1use proc_macro2::Span;
5use syn::Ident;
6
7#[derive(Clone, Debug)]
9pub struct TrEntry {
10 pub language: String,
11 pub text: String,
12 pub span: Span,
13}
14
15#[derive(Clone, Debug)]
17pub struct TrArg {
18 pub name: Ident,
19 pub value: Expr,
20}
21
22#[derive(Clone, Debug)]
24pub struct Tr {
25 pub entries: Vec<TrEntry>,
26 pub args: Vec<TrArg>,
27 pub span: Span,
28}
29
30#[derive(Clone, Debug, PartialEq)]
31pub enum Literal {
32 Text(String),
33 Int(i64),
34 Float(f64),
35 Bool(bool),
36}
37
38#[derive(Clone, Copy, Debug, PartialEq, Eq)]
39pub enum UnaryOp {
40 Not,
41 Neg,
42}
43
44#[derive(Clone, Copy, Debug, PartialEq, Eq)]
45pub enum BinaryOp {
46 Eq,
47 Ne,
48 Lt,
49 Le,
50 Gt,
51 Ge,
52 And,
53 Or,
54}
55
56impl BinaryOp {
57 pub fn symbol(self) -> &'static str {
58 match self {
59 BinaryOp::Eq => "==",
60 BinaryOp::Ne => "!=",
61 BinaryOp::Lt => "<",
62 BinaryOp::Le => "<=",
63 BinaryOp::Gt => ">",
64 BinaryOp::Ge => ">=",
65 BinaryOp::And => "&&",
66 BinaryOp::Or => "||",
67 }
68 }
69}
70
71#[derive(Clone, Debug)]
74pub struct PathExpr {
75 pub segments: Vec<Ident>,
76}
77
78impl PathExpr {
79 pub fn span(&self) -> Span {
80 self.segments[0].span()
81 }
82
83 pub fn dotted(&self) -> String {
84 self.segments
85 .iter()
86 .map(Ident::to_string)
87 .collect::<Vec<_>>()
88 .join(".")
89 }
90
91 pub fn single(&self) -> Option<&Ident> {
92 (self.segments.len() == 1).then(|| &self.segments[0])
93 }
94}
95
96#[derive(Clone, Debug)]
98pub struct VariantExpr {
99 pub ty: Ident,
100 pub variant: Ident,
101 pub fields: Vec<(Ident, Expr)>,
102 pub has_braces: bool,
103}
104
105#[derive(Clone, Debug)]
109pub enum Expr {
110 Literal {
111 value: Literal,
112 span: Span,
113 },
114 Tr(Tr),
115 Path(PathExpr),
116 Variant(VariantExpr),
117 Unary {
118 op: UnaryOp,
119 expr: Box<Expr>,
120 span: Span,
121 },
122 Binary {
123 op: BinaryOp,
124 lhs: Box<Expr>,
125 rhs: Box<Expr>,
126 span: Span,
127 },
128 Query(Action),
131 If {
133 cond: Box<Expr>,
134 then: Box<Expr>,
135 otherwise: Box<Expr>,
136 span: Span,
137 },
138}
139
140impl Expr {
141 pub fn span(&self) -> Span {
142 match self {
143 Expr::Literal { span, .. }
144 | Expr::Unary { span, .. }
145 | Expr::Binary { span, .. }
146 | Expr::If { span, .. } => *span,
147 Expr::Tr(tr) => tr.span,
148 Expr::Path(path) => path.span(),
149 Expr::Variant(variant) => variant.ty.span(),
150 Expr::Query(call) => call.span,
151 }
152 }
153}
154
155#[derive(Clone, Debug)]
156pub struct Prop {
157 pub attrs: Vec<syn::Attribute>,
158 pub name: Ident,
159 pub value: Expr,
160}
161
162impl Prop {
163 pub fn keyword(&self) -> Option<String> {
165 match &self.value {
166 Expr::Path(path) => path.single().map(Ident::to_string),
167 _ => None,
168 }
169 }
170}
171
172#[derive(Clone, Debug)]
175pub struct Action {
176 pub receiver: Vec<Ident>,
177 pub method: Ident,
178 pub args: Vec<Expr>,
179 pub span: Span,
180}
181
182impl Action {
183 pub fn receiver_path(&self) -> String {
184 self.receiver
185 .iter()
186 .map(Ident::to_string)
187 .collect::<Vec<_>>()
188 .join(".")
189 }
190}
191
192#[derive(Clone, Debug)]
194pub struct Element {
195 pub name: Ident,
196 pub props: Vec<Prop>,
197 pub template: Option<Ident>,
199 pub children: Option<Vec<Node>>,
200 pub action: Option<Action>,
201 pub span: Span,
202}
203
204impl Element {
205 pub fn prop(&self, name: &str) -> Option<&Prop> {
206 self.props.iter().find(|prop| prop.name == name)
207 }
208}
209
210#[derive(Clone, Debug)]
212pub struct ComponentCall {
213 pub path: Vec<Ident>,
214 pub args: Vec<Prop>,
215 pub span: Span,
216}
217
218impl ComponentCall {
219 pub fn name(&self) -> &Ident {
220 self.path.last().expect("non-empty path")
221 }
222
223 pub fn path_string(&self) -> String {
224 self.path
225 .iter()
226 .map(Ident::to_string)
227 .collect::<Vec<_>>()
228 .join("::")
229 }
230}
231
232#[derive(Clone, Debug)]
233pub struct IfNode {
234 pub branches: Vec<(Expr, Vec<Node>)>,
235 pub otherwise: Option<Vec<Node>>,
236 pub span: Span,
237}
238
239#[derive(Clone, Debug)]
241pub struct IfLetNode {
242 pub binding: Ident,
243 pub value: Expr,
244 pub then: Vec<Node>,
245 pub otherwise: Option<Vec<Node>>,
246 pub span: Span,
247}
248
249#[derive(Clone, Debug)]
250pub enum Pattern {
251 Variant {
252 ty: Ident,
253 variant: Ident,
254 bindings: Vec<Ident>,
255 },
256 Wildcard(Span),
257}
258
259#[derive(Clone, Debug)]
260pub struct MatchArm {
261 pub attrs: Vec<syn::Attribute>,
262 pub pattern: Pattern,
263 pub body: Vec<Node>,
264 pub span: Span,
265}
266
267#[derive(Clone, Debug)]
268pub struct MatchNode {
269 pub value: Expr,
270 pub arms: Vec<MatchArm>,
271 pub span: Span,
272}
273
274#[derive(Clone, Debug)]
275pub enum Node {
276 Element(Element),
277 Component(ComponentCall),
278 If(IfNode),
279 IfLet(IfLetNode),
280 Match(MatchNode),
281}
282
283pub fn child_names(children: &[Node], items: bool) -> Vec<Option<String>> {
287 fn flatten(nodes: &[Node], out: &mut Vec<Option<String>>) {
288 for node in nodes {
289 match node {
290 Node::Element(child) if child.name == "ForEach" => {
291 flatten(child.children.as_deref().unwrap_or(&[]), out)
292 }
293 Node::Element(child) => out.push(Some(child.name.to_string())),
294 Node::If(node) => {
295 for (_, body) in &node.branches {
296 flatten(body, out);
297 }
298 flatten(node.otherwise.as_deref().unwrap_or(&[]), out);
299 }
300 Node::IfLet(node) => {
301 flatten(&node.then, out);
302 flatten(node.otherwise.as_deref().unwrap_or(&[]), out);
303 }
304 Node::Match(node) => {
305 for arm in &node.arms {
306 flatten(&arm.body, out);
307 }
308 }
309 Node::Component(_) => out.push(None),
310 }
311 }
312 }
313 if items {
314 let mut out = Vec::new();
315 flatten(children, &mut out);
316 return out;
317 }
318 children
319 .iter()
320 .map(|child| match child {
321 Node::Element(child) => Some(child.name.to_string()),
322 _ => None,
323 })
324 .collect()
325}
326
327impl Node {
328 pub fn span(&self) -> Span {
329 match self {
330 Node::Element(element) => element.span,
331 Node::Component(call) => call.span,
332 Node::If(node) => node.span,
333 Node::IfLet(node) => node.span,
334 Node::Match(node) => node.span,
335 }
336 }
337}
338
339#[derive(Clone, Debug)]
341pub struct UiBody {
342 pub nodes: Vec<Node>,
343}
344
345#[derive(Clone, Debug, PartialEq, Eq)]
347pub enum TypeRef {
348 Unit,
349 Bool,
350 Int,
351 Float,
352 Text,
353 Named(Vec<String>),
356 Optional(Box<TypeRef>),
357 List(Box<TypeRef>),
358}
359
360impl TypeRef {
361 pub fn name(&self) -> Option<&str> {
362 match self {
363 TypeRef::Named(path) => path.last().map(String::as_str),
364 _ => None,
365 }
366 }
367}