Skip to content

Commit 1fa8ef8

Browse files
committed
feat: add support for traits
Signed-off-by: azjezz <azjezz@protonmail.com>
1 parent 8649d08 commit 1fa8ef8

File tree

6 files changed

+316
-1
lines changed

6 files changed

+316
-1
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ Generate PHP code from Rust using a fluent API 🐘 🦀
2626
- [x] Code generation for function/method bodies
2727
- [x] Code generation for interfaces
2828
- [ ] Code generation for enums
29-
- [ ] Code generation for traits
29+
- [x] Code generation for traits
3030
- [x] Code generation for trait use statements
3131
- [x] Code generation for variadic parameters
3232

examples/complete.php

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,73 @@ public final function helloWorld(): void {
134134
}
135135
}
136136

137+
/**
138+
* This is an example trait.
139+
*/
140+
trait ExampleTrait
141+
{
142+
use A;
143+
144+
use B, C;
145+
146+
use D, E, F, G {
147+
E::bar as baz;
148+
D::foo as public bar;
149+
E::qux as public;
150+
D::format as protected;
151+
D::d as private;
152+
D::drop insteadof E;
153+
G::something insteadof E, F, D;
154+
E::e as protected;
155+
}
156+
157+
private string $foo;
158+
159+
protected string $bar;
160+
161+
public string|int $baz = "Hello World!";
162+
163+
/**
164+
* This is a simple hello function.
165+
*
166+
* @param non-empty-string $firstname
167+
*
168+
* @return string
169+
*
170+
* @pure
171+
*/
172+
#[Qux(foo: 1, bar: 2), Qux(foo: 1, bar: 2)]
173+
function hello(
174+
string $firstname,
175+
string $lastname = Qux::Foo,
176+
): string {
177+
return 'Hello ' . $firstname . ' ' . $lastname . '!';
178+
}
179+
180+
/**
181+
* This is a simple x function.
182+
*
183+
* @pure
184+
*/
185+
#[Foo(foo: 1, bar: 2), Bar(foo: 1, bar: 2)]
186+
#[Baz, Qux]
187+
public function x(): mixed {
188+
return 'Hello!';
189+
}
190+
191+
/**
192+
* This is a simple poop function.
193+
*/
194+
public abstract function poop(): void;
195+
196+
/**
197+
* This is a simple echo function.
198+
*/
199+
public final function helloWorld(): void {
200+
echo 'Hello World!';
201+
}
202+
}
203+
137204
/**
138205
* This is a simple formatter interface.
139206
*

examples/complete.rs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use php_codegen::modifiers::Modifier;
1313
use php_codegen::modifiers::VisibilityModifier;
1414
use php_codegen::parameter::Parameter;
1515
use php_codegen::property::Property;
16+
use php_codegen::r#trait::Trait;
1617
use php_codegen::usage::Usage;
1718
use php_codegen::Indentation;
1819

@@ -196,6 +197,97 @@ fn main() {
196197
}),
197198
),
198199
)
200+
.r#trait(
201+
Trait::new("ExampleTrait")
202+
.document(Document::new().text("This is an example trait."))
203+
.using("A")
204+
.using(vec!["B", "C"])
205+
.using(
206+
Usage::new(vec![
207+
"D".to_string(),
208+
"E".to_string(),
209+
"F".to_string(),
210+
"G".to_string(),
211+
])
212+
.rename("E::bar", "baz")
213+
.alias("D::foo", "bar", VisibilityModifier::Public)
214+
.public("E::qux")
215+
.protected("D::format")
216+
.private("D::d")
217+
.precede("D::drop", vec!["E"])
218+
.precede("G::something", vec!["E", "F", "D"])
219+
.visibility("E::e", VisibilityModifier::Protected),
220+
)
221+
.property(Property::new("foo").typed(DataType::String).private())
222+
.property(Property::new("bar").typed(DataType::String).protected())
223+
.property(
224+
Property::new("baz")
225+
.typed(DataType::Union(vec![DataType::String, DataType::Integer]))
226+
.public()
227+
.default("Hello World!"),
228+
)
229+
.method(
230+
Method::new("hello")
231+
.returns(DataType::String)
232+
.parameter(Parameter::new("firstname").typed(DataType::String))
233+
.parameter(
234+
Parameter::new("lastname")
235+
.typed(DataType::String)
236+
.default(Value::Literal("Qux::Foo".to_string())),
237+
)
238+
.body("return 'Hello ' . $firstname . ' ' . $lastname . '!';")
239+
.attributes(
240+
AttributeGroup::new()
241+
.add("Qux", Some("foo: 1, bar: 2"))
242+
.add("Qux", Some("foo: 1, bar: 2")),
243+
)
244+
.document(
245+
Document::new()
246+
.text("This is a simple hello function.")
247+
.empty_line()
248+
.tag("param", "non-empty-string $firstname")
249+
.empty_line()
250+
.tag("return", "string")
251+
.empty_line()
252+
.simple_tag("pure"),
253+
),
254+
)
255+
.method(
256+
Method::new("x")
257+
.public()
258+
.returns(DataType::Mixed)
259+
.body("return 'Hello!';")
260+
.attributes(
261+
AttributeGroup::new()
262+
.add("Foo", Some("foo: 1, bar: 2"))
263+
.add("Bar", Some("foo: 1, bar: 2")),
264+
)
265+
.attributes(AttributeGroup::new().add("Baz", None).add("Qux", None))
266+
.document(
267+
Document::new()
268+
.text("This is a simple x function.")
269+
.empty_line()
270+
.simple_tag("pure"),
271+
),
272+
)
273+
.method(
274+
Method::new("poop")
275+
.public()
276+
.modifier(Modifier::Abstract)
277+
.returns(DataType::Void)
278+
.document(Document::new().text("This is a simple poop function.")),
279+
)
280+
.method(
281+
Method::new("helloWorld")
282+
.public()
283+
.modifier(Modifier::Final)
284+
.returns(DataType::Void)
285+
.document(Document::new().text("This is a simple echo function."))
286+
.body(|indentation: Indentation, level| {
287+
indentation.indent("echo 'Hello World!';", level)
288+
}),
289+
),
290+
)
199291
.interface(
200292
Interface::new("Formatter")
201293
.document(

src/file.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::constant::Constant;
55
use crate::function::Function;
66
use crate::interface::Interface;
77
use crate::literal::Value;
8+
use crate::r#trait::Trait;
89
use crate::Generator;
910
use crate::Indentation;
1011

@@ -18,6 +19,7 @@ pub struct File {
1819
pub functions: Vec<Function>,
1920
pub constants: Vec<Constant>,
2021
pub classes: Vec<Class>,
22+
pub traits: Vec<Trait>,
2123
pub interfaces: Vec<Interface>,
2224
}
2325

@@ -32,6 +34,7 @@ impl File {
3234
constants: vec![],
3335
functions: vec![],
3436
classes: vec![],
37+
traits: vec![],
3538
interfaces: vec![],
3639
}
3740
}
@@ -84,6 +87,12 @@ impl File {
8487
self
8588
}
8689

90+
pub fn r#trait(mut self, r#trait: Trait) -> Self {
91+
self.traits.push(r#trait);
92+
93+
self
94+
}
95+
8796
pub fn interface(mut self, interface: Interface) -> Self {
8897
self.interfaces.push(interface);
8998

@@ -159,6 +168,11 @@ impl Generator for File {
159168
code.push('\n');
160169
}
161170

171+
for r#trait in &self.traits {
172+
code.push_str(&r#trait.generate(indentation, level));
173+
code.push('\n');
174+
}
175+
162176
for interface in &self.interfaces {
163177
code.push_str(&interface.generate(indentation, level));
164178
code.push('\n');

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pub mod method;
1212
pub mod modifiers;
1313
pub mod parameter;
1414
pub mod property;
15+
pub mod r#trait;
1516
pub mod usage;
1617

1718
#[derive(Debug, PartialEq, Eq, PartialOrd, Clone, Copy)]

src/trait.rs

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
use crate::attribute::AttributeGroup;
2+
use crate::comment::Document;
3+
use crate::constant::ClassConstant;
4+
use crate::method::Method;
5+
use crate::property::Property;
6+
use crate::usage::Usage;
7+
use crate::Generator;
8+
use crate::Indentation;
9+
10+
#[derive(Debug)]
11+
pub struct Trait {
12+
pub documentation: Option<Document>,
13+
pub attributes: Vec<AttributeGroup>,
14+
pub name: String,
15+
pub usages: Vec<Usage>,
16+
pub constants: Vec<ClassConstant>,
17+
pub properties: Vec<Property>,
18+
pub methods: Vec<Method>,
19+
}
20+
21+
impl Trait {
22+
pub fn new<T: ToString>(name: T) -> Self {
23+
Self {
24+
documentation: None,
25+
attributes: vec![],
26+
name: name.to_string(),
27+
usages: vec![],
28+
constants: vec![],
29+
properties: vec![],
30+
methods: vec![],
31+
}
32+
}
33+
34+
pub fn document(mut self, documentation: Document) -> Self {
35+
self.documentation = Some(documentation);
36+
37+
self
38+
}
39+
40+
pub fn attributes(mut self, attributes: AttributeGroup) -> Self {
41+
self.attributes.push(attributes);
42+
43+
self
44+
}
45+
46+
pub fn using<T: Into<Usage>>(mut self, usage: T) -> Self {
47+
self.usages.push(usage.into());
48+
49+
self
50+
}
51+
52+
pub fn constant<T: Into<ClassConstant>>(mut self, constant: T) -> Self {
53+
self.constants.push(constant.into());
54+
55+
self
56+
}
57+
58+
pub fn property(mut self, property: Property) -> Self {
59+
self.properties.push(property);
60+
61+
self
62+
}
63+
64+
pub fn method(mut self, method: Method) -> Self {
65+
self.methods.push(method);
66+
67+
self
68+
}
69+
}
70+
71+
impl Generator for Trait {
72+
fn generate(&self, indentation: Indentation, level: usize) -> String {
73+
let mut code = String::new();
74+
75+
if let Some(documentation) = &self.documentation {
76+
code.push_str(&documentation.generate(indentation, level));
77+
}
78+
79+
for attribute in &self.attributes {
80+
code.push_str(&attribute.generate(indentation, level));
81+
}
82+
83+
code.push_str(&format!("trait {}", self.name));
84+
85+
code.push_str("\n{\n");
86+
87+
if !self.usages.is_empty() {
88+
code.push_str(
89+
&self
90+
.usages
91+
.iter()
92+
.map(|usage| usage.generate(indentation, level + 1))
93+
.collect::<Vec<String>>()
94+
.join("\n"),
95+
);
96+
97+
code.push('\n');
98+
}
99+
100+
if !self.constants.is_empty() {
101+
code.push_str(
102+
&self
103+
.constants
104+
.iter()
105+
.map(|constant| constant.generate(indentation, level + 1))
106+
.collect::<Vec<String>>()
107+
.join("\n"),
108+
);
109+
110+
code.push('\n');
111+
}
112+
113+
if !self.properties.is_empty() {
114+
code.push_str(
115+
&self
116+
.properties
117+
.iter()
118+
.map(|property| property.generate(indentation, level + 1))
119+
.collect::<Vec<String>>()
120+
.join("\n"),
121+
);
122+
123+
code.push('\n');
124+
}
125+
126+
if !self.methods.is_empty() {
127+
code.push_str(
128+
&self
129+
.methods
130+
.iter()
131+
.map(|method| method.generate(indentation, level + 1))
132+
.collect::<Vec<String>>()
133+
.join("\n"),
134+
);
135+
}
136+
137+
code.push_str("}\n");
138+
139+
code
140+
}
141+
}

0 commit comments

Comments
 (0)