Skip to content

Commit 8649d08

Browse files
committed
feat: add support for trait use statements
Signed-off-by: azjezz <azjezz@protonmail.com>
1 parent 837c328 commit 8649d08

File tree

6 files changed

+239
-1
lines changed

6 files changed

+239
-1
lines changed

README.md

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

3333
## License

examples/complete.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,21 @@ function format(
6464
*/
6565
abstract class Example extends Foo\Bar\Baz implements Foo\Bar\BazInterface
6666
{
67+
use A;
68+
69+
use B, C;
70+
71+
use D, E, F, G {
72+
E::bar as baz;
73+
D::foo as public bar;
74+
E::qux as public;
75+
D::format as protected;
76+
D::d as private;
77+
D::drop insteadof E;
78+
G::something insteadof E, F, D;
79+
E::e as protected;
80+
}
81+
6782
final const A = "Hello World!";
6883

6984
protected const B = null;

examples/complete.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ use php_codegen::interface::Interface;
1010
use php_codegen::literal::Value;
1111
use php_codegen::method::Method;
1212
use php_codegen::modifiers::Modifier;
13+
use php_codegen::modifiers::VisibilityModifier;
1314
use php_codegen::parameter::Parameter;
1415
use php_codegen::property::Property;
16+
use php_codegen::usage::Usage;
1517
use php_codegen::Indentation;
1618

1719
fn main() {
@@ -98,6 +100,24 @@ fn main() {
98100
.simple_tag("immutable"),
99101
)
100102
.modifier(Modifier::Abstract)
103+
.using("A")
104+
.using(vec!["B", "C"])
105+
.using(
106+
Usage::new(vec![
107+
"D".to_string(),
108+
"E".to_string(),
109+
"F".to_string(),
110+
"G".to_string(),
111+
])
112+
.rename("E::bar", "baz")
113+
.alias("D::foo", "bar", VisibilityModifier::Public)
114+
.public("E::qux")
115+
.protected("D::format")
116+
.private("D::d")
117+
.precede("D::drop", vec!["E"])
118+
.precede("G::something", vec!["E", "F", "D"])
119+
.visibility("E::e", VisibilityModifier::Protected),
120+
)
101121
.constant(
102122
ClassConstant::new("A")
103123
.valued("Hello World!")

src/class.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::constant::ClassConstant;
44
use crate::method::Method;
55
use crate::modifiers::Modifier;
66
use crate::property::Property;
7+
use crate::usage::Usage;
78
use crate::Generator;
89
use crate::Indentation;
910

@@ -15,6 +16,7 @@ pub struct Class {
1516
pub name: String,
1617
pub extends: Option<String>,
1718
pub implements: Vec<String>,
19+
pub usages: Vec<Usage>,
1820
pub constants: Vec<ClassConstant>,
1921
pub properties: Vec<Property>,
2022
pub methods: Vec<Method>,
@@ -29,6 +31,7 @@ impl Class {
2931
name: name.to_string(),
3032
extends: None,
3133
implements: vec![],
34+
usages: vec![],
3235
constants: vec![],
3336
properties: vec![],
3437
methods: vec![],
@@ -65,6 +68,12 @@ impl Class {
6568
self
6669
}
6770

71+
pub fn using<T: Into<Usage>>(mut self, usage: T) -> Self {
72+
self.usages.push(usage.into());
73+
74+
self
75+
}
76+
6877
pub fn constant<T: Into<ClassConstant>>(mut self, constant: T) -> Self {
6978
self.constants.push(constant.into());
7079

@@ -119,6 +128,19 @@ impl Generator for Class {
119128

120129
code.push_str("\n{\n");
121130

131+
if !self.usages.is_empty() {
132+
code.push_str(
133+
&self
134+
.usages
135+
.iter()
136+
.map(|usage| usage.generate(indentation, level + 1))
137+
.collect::<Vec<String>>()
138+
.join("\n"),
139+
);
140+
141+
code.push('\n');
142+
}
143+
122144
if !self.constants.is_empty() {
123145
code.push_str(
124146
&self

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 usage;
1516

1617
#[derive(Debug, PartialEq, Eq, PartialOrd, Clone, Copy)]
1718
pub enum Indentation {

src/usage.rs

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
use crate::modifiers::VisibilityModifier;
2+
use crate::Generator;
3+
use crate::Indentation;
4+
5+
#[derive(Debug)]
6+
pub struct Usage {
7+
pub traits: Vec<String>,
8+
pub adaptations: Vec<UsageAdaptation>,
9+
}
10+
11+
#[derive(Debug)]
12+
pub enum UsageAdaptation {
13+
Alias {
14+
method: String,
15+
alias: String,
16+
visibility: Option<VisibilityModifier>,
17+
},
18+
Visibility {
19+
method: String,
20+
visibility: VisibilityModifier,
21+
},
22+
Precedence {
23+
method: String,
24+
insteadof: Vec<String>,
25+
},
26+
}
27+
28+
impl Usage {
29+
pub fn new(traits: Vec<String>) -> Self {
30+
Self {
31+
traits,
32+
adaptations: vec![],
33+
}
34+
}
35+
36+
pub fn with<T: ToString>(mut self, r#trait: T) -> Self {
37+
self.traits.push(r#trait.to_string());
38+
39+
self
40+
}
41+
42+
pub fn alias<T: ToString>(
43+
mut self,
44+
method: T,
45+
alias: T,
46+
visibility: VisibilityModifier,
47+
) -> Self {
48+
self.adaptations.push(UsageAdaptation::Alias {
49+
method: method.to_string(),
50+
alias: alias.to_string(),
51+
visibility: Some(visibility),
52+
});
53+
54+
self
55+
}
56+
57+
pub fn rename<T: ToString>(mut self, method: T, alias: T) -> Self {
58+
self.adaptations.push(UsageAdaptation::Alias {
59+
method: method.to_string(),
60+
alias: alias.to_string(),
61+
visibility: None,
62+
});
63+
64+
self
65+
}
66+
67+
pub fn public<T: ToString>(mut self, method: T) -> Self {
68+
self.adaptations.push(UsageAdaptation::Visibility {
69+
method: method.to_string(),
70+
visibility: VisibilityModifier::Public,
71+
});
72+
73+
self
74+
}
75+
76+
pub fn protected<T: ToString>(mut self, method: T) -> Self {
77+
self.adaptations.push(UsageAdaptation::Visibility {
78+
method: method.to_string(),
79+
visibility: VisibilityModifier::Protected,
80+
});
81+
82+
self
83+
}
84+
85+
pub fn private<T: ToString>(mut self, method: T) -> Self {
86+
self.adaptations.push(UsageAdaptation::Visibility {
87+
method: method.to_string(),
88+
visibility: VisibilityModifier::Private,
89+
});
90+
91+
self
92+
}
93+
94+
pub fn visibility<T: ToString>(mut self, method: T, visibility: VisibilityModifier) -> Self {
95+
self.adaptations.push(UsageAdaptation::Visibility {
96+
method: method.to_string(),
97+
visibility,
98+
});
99+
100+
self
101+
}
102+
103+
pub fn precede<T: ToString>(mut self, method: T, insteadof: Vec<T>) -> Self {
104+
self.adaptations.push(UsageAdaptation::Precedence {
105+
method: method.to_string(),
106+
insteadof: insteadof
107+
.into_iter()
108+
.map(|insteadof| insteadof.to_string())
109+
.collect(),
110+
});
111+
112+
self
113+
}
114+
}
115+
116+
impl Generator for Usage {
117+
fn generate(&self, indentation: Indentation, level: usize) -> String {
118+
let mut code = indentation.indent("use", level);
119+
120+
code.push(' ');
121+
code.push_str(&self.traits.join(", "));
122+
123+
if !self.adaptations.is_empty() {
124+
code.push_str(" {\n");
125+
for adaptation in &self.adaptations {
126+
let adaptation = match adaptation {
127+
UsageAdaptation::Alias {
128+
method,
129+
alias,
130+
visibility,
131+
} => {
132+
let alias = if let Some(visibility) = visibility {
133+
format!("{} {}", visibility.generate(indentation, level), alias)
134+
} else {
135+
alias.to_string()
136+
};
137+
138+
indentation.indent(format!("{} as {}", method, alias), level + 1)
139+
}
140+
UsageAdaptation::Visibility { method, visibility } => indentation.indent(
141+
format!("{} as {}", method, visibility.generate(indentation, level)),
142+
level + 1,
143+
),
144+
UsageAdaptation::Precedence { method, insteadof } => indentation.indent(
145+
format!("{} insteadof {}", method, insteadof.join(", ")),
146+
level + 1,
147+
),
148+
};
149+
150+
code.push_str(&format!("{};\n", adaptation));
151+
}
152+
153+
code.push_str(&format!("{}}}\n", indentation.value(level)));
154+
} else {
155+
code.push_str(";\n");
156+
}
157+
158+
code
159+
}
160+
}
161+
162+
impl From<String> for Usage {
163+
fn from(r#trait: String) -> Self {
164+
Self::new(vec![r#trait])
165+
}
166+
}
167+
168+
impl From<&str> for Usage {
169+
fn from(r#trait: &str) -> Self {
170+
Self::new(vec![r#trait.to_string()])
171+
}
172+
}
173+
174+
impl<T: ToString> From<Vec<T>> for Usage {
175+
fn from(traits: Vec<T>) -> Self {
176+
traits
177+
.into_iter()
178+
.fold(Self::new(vec![]), |usage, r#trait| usage.with(r#trait))
179+
}
180+
}

0 commit comments

Comments
 (0)