Skip to main content

dry4rust/rust/normalizer/
expr.rs

1// Copyright (c) 2026 Matjaz Domen Pecan
2// Copyright 2026 Umberto Gotti <umberto.gotti@umbertogotti.dev>
3// Licensed under the MIT License
4// SPDX-License-Identifier: MIT
5
6use crate::node::{NodeKind, NormalizedNode, PlaceholderKind};
7use crate::normalization_context::NormalizationContext;
8
9use super::helpers::{member_to_string, normalize_bin_op, normalize_lit, normalize_un_op};
10use syn::Block;
11use syn::Expr;
12use syn::Stmt;
13
14impl NormalizationContext {
15    #[allow(clippy::too_many_lines)]
16    pub fn normalize_expr(&mut self, expr: &Expr) -> NormalizedNode {
17        match expr {
18            Expr::Lit(el) => normalize_lit(&el.lit),
19            Expr::Path(ep) => {
20                if ep.path.segments.len() == 1 {
21                    let seg = &ep.path.segments[0];
22                    let ident = seg.ident.to_string();
23                    let kind = if ident.chars().next().is_some_and(char::is_uppercase) {
24                        PlaceholderKind::Type
25                    } else {
26                        PlaceholderKind::Variable
27                    };
28                    let idx = self.placeholder(&ident, kind);
29                    NormalizedNode::leaf(NodeKind::Placeholder(kind, idx))
30                } else {
31                    let segments: Vec<NormalizedNode> = ep
32                        .path
33                        .segments
34                        .iter()
35                        .map(|seg| {
36                            let ident = seg.ident.to_string();
37                            let kind = if ident.chars().next().is_some_and(char::is_uppercase) {
38                                PlaceholderKind::Type
39                            } else {
40                                PlaceholderKind::Variable
41                            };
42                            let idx = self.placeholder(&ident, kind);
43                            NormalizedNode::leaf(NodeKind::Placeholder(kind, idx))
44                        })
45                        .collect();
46                    NormalizedNode::with_children(NodeKind::Path, segments)
47                }
48            }
49            // BinaryOp -> [left, right]
50            Expr::Binary(eb) => NormalizedNode::with_children(
51                NodeKind::BinaryOp(normalize_bin_op(&eb.op)),
52                vec![
53                    self.normalize_expr(&eb.left),
54                    self.normalize_expr(&eb.right),
55                ],
56            ),
57            // UnaryOp -> [operand]
58            Expr::Unary(eu) => NormalizedNode::with_children(
59                NodeKind::UnaryOp(normalize_un_op(&eu.op)),
60                vec![self.normalize_expr(&eu.expr)],
61            ),
62            // Call -> [func, arg0, arg1, ...]
63            Expr::Call(ec) => {
64                let mut children = vec![self.normalize_expr(&ec.func)];
65                children.extend(ec.args.iter().map(|a| self.normalize_expr(a)));
66                NormalizedNode::with_children(NodeKind::Call, children)
67            }
68            // MethodCall -> [receiver, method, arg0, ...]
69            Expr::MethodCall(emc) => {
70                let method_idx =
71                    self.placeholder(&emc.method.to_string(), PlaceholderKind::Function);
72                let mut children = vec![
73                    self.normalize_expr(&emc.receiver),
74                    NormalizedNode::leaf(NodeKind::Placeholder(
75                        PlaceholderKind::Function,
76                        method_idx,
77                    )),
78                ];
79                children.extend(emc.args.iter().map(|a| self.normalize_expr(a)));
80                NormalizedNode::with_children(NodeKind::MethodCall, children)
81            }
82            // FieldAccess -> [base, field]
83            Expr::Field(ef) => {
84                let field_idx =
85                    self.placeholder(&member_to_string(&ef.member), PlaceholderKind::Variable);
86                NormalizedNode::with_children(
87                    NodeKind::FieldAccess,
88                    vec![
89                        self.normalize_expr(&ef.base),
90                        NormalizedNode::leaf(NodeKind::Placeholder(
91                            PlaceholderKind::Variable,
92                            field_idx,
93                        )),
94                    ],
95                )
96            }
97            // Index -> [base, index]
98            Expr::Index(ei) => NormalizedNode::with_children(
99                NodeKind::Index,
100                vec![
101                    self.normalize_expr(&ei.expr),
102                    self.normalize_expr(&ei.index),
103                ],
104            ),
105            // Closure -> [body, param0, param1, ...]
106            Expr::Closure(ec) => {
107                let mut children = vec![self.normalize_expr(&ec.body)];
108                children.extend(ec.inputs.iter().map(|p| self.normalize_pat(p)));
109                NormalizedNode::with_children(NodeKind::Closure, children)
110            }
111            // Return -> [] or [value]
112            Expr::Return(er) => {
113                let children: Vec<_> = er
114                    .expr
115                    .as_ref()
116                    .map(|e| vec![self.normalize_expr(e)])
117                    .unwrap_or_default();
118                NormalizedNode::with_children(NodeKind::Return, children)
119            }
120            // Break -> [] or [value]
121            Expr::Break(eb) => {
122                let children: Vec<_> = eb
123                    .expr
124                    .as_ref()
125                    .map(|e| vec![self.normalize_expr(e)])
126                    .unwrap_or_default();
127                NormalizedNode::with_children(NodeKind::Break, children)
128            }
129            Expr::Continue(_) => NormalizedNode::leaf(NodeKind::Continue),
130            // Assign -> [left, right]
131            Expr::Assign(ea) => NormalizedNode::with_children(
132                NodeKind::Assign,
133                vec![
134                    self.normalize_expr(&ea.left),
135                    self.normalize_expr(&ea.right),
136                ],
137            ),
138            // Reference -> [expr]
139            Expr::Reference(er) => NormalizedNode::with_children(
140                NodeKind::Reference {
141                    mutable: er.mutability.is_some(),
142                },
143                vec![self.normalize_expr(&er.expr)],
144            ),
145            Expr::Tuple(et) => NormalizedNode::with_children(
146                NodeKind::Tuple,
147                et.elems.iter().map(|e| self.normalize_expr(e)).collect(),
148            ),
149            Expr::Array(ea) => NormalizedNode::with_children(
150                NodeKind::Array,
151                ea.elems.iter().map(|e| self.normalize_expr(e)).collect(),
152            ),
153            // Repeat -> [elem, len]
154            Expr::Repeat(er) => NormalizedNode::with_children(
155                NodeKind::Repeat,
156                vec![self.normalize_expr(&er.expr), self.normalize_expr(&er.len)],
157            ),
158            // Cast -> [expr, ty]
159            Expr::Cast(ec) => NormalizedNode::with_children(
160                NodeKind::Cast,
161                vec![self.normalize_expr(&ec.expr), self.normalize_type(&ec.ty)],
162            ),
163            // StructInit -> [rest_or_None, field0, field1, ...]
164            Expr::Struct(es) => {
165                let mut children = vec![NormalizedNode::opt(
166                    es.rest.as_ref().map(|e| self.normalize_expr(e)),
167                )];
168                children.extend(es.fields.iter().map(|f| {
169                    let field_idx =
170                        self.placeholder(&member_to_string(&f.member), PlaceholderKind::Variable);
171                    NormalizedNode::with_children(
172                        NodeKind::FieldValue,
173                        vec![
174                            NormalizedNode::leaf(NodeKind::Placeholder(
175                                PlaceholderKind::Variable,
176                                field_idx,
177                            )),
178                            self.normalize_expr(&f.expr),
179                        ],
180                    )
181                }));
182                NormalizedNode::with_children(NodeKind::StructInit, children)
183            }
184            // Await -> [expr]
185            Expr::Await(ea) => {
186                NormalizedNode::with_children(NodeKind::Await, vec![self.normalize_expr(&ea.base)])
187            }
188            // Try -> [expr]
189            Expr::Try(et) => {
190                NormalizedNode::with_children(NodeKind::Try, vec![self.normalize_expr(&et.expr)])
191            }
192            // If -> [condition, then_branch, else_or_None]
193            Expr::If(ei) => NormalizedNode::with_children(
194                NodeKind::If,
195                vec![
196                    self.normalize_expr(&ei.cond),
197                    self.normalize_block(&ei.then_branch),
198                    NormalizedNode::opt(
199                        ei.else_branch.as_ref().map(|(_, e)| self.normalize_expr(e)),
200                    ),
201                ],
202            ),
203            // Match -> [expr, arm0, arm1, ...]
204            // Each arm is MatchArm -> [pattern, guard_or_None, body]
205            Expr::Match(em) => {
206                let mut children = vec![self.normalize_expr(&em.expr)];
207                children.extend(em.arms.iter().map(|arm| {
208                    NormalizedNode::with_children(
209                        NodeKind::MatchArm,
210                        vec![
211                            self.normalize_pat(&arm.pat),
212                            NormalizedNode::opt(
213                                arm.guard.as_ref().map(|(_, g)| self.normalize_expr(g)),
214                            ),
215                            self.normalize_expr(&arm.body),
216                        ],
217                    )
218                }));
219                NormalizedNode::with_children(NodeKind::Match, children)
220            }
221            // Loop -> [body]
222            Expr::Loop(el) => {
223                NormalizedNode::with_children(NodeKind::Loop, vec![self.normalize_block(&el.body)])
224            }
225            // While -> [condition, body]
226            Expr::While(ew) => NormalizedNode::with_children(
227                NodeKind::While,
228                vec![
229                    self.normalize_expr(&ew.cond),
230                    self.normalize_block(&ew.body),
231                ],
232            ),
233            // ForLoop -> [pat, iter, body]
234            Expr::ForLoop(ef) => NormalizedNode::with_children(
235                NodeKind::ForLoop,
236                vec![
237                    self.normalize_pat(&ef.pat),
238                    self.normalize_expr(&ef.expr),
239                    self.normalize_block(&ef.body),
240                ],
241            ),
242            Expr::Block(eb) => self.normalize_block(&eb.block),
243            // Paren -> [expr]
244            Expr::Paren(ep) => {
245                NormalizedNode::with_children(NodeKind::Paren, vec![self.normalize_expr(&ep.expr)])
246            }
247            // Range -> [from_or_None, to_or_None]
248            Expr::Range(er) => NormalizedNode::with_children(
249                NodeKind::Range,
250                vec![
251                    NormalizedNode::opt(er.start.as_ref().map(|e| self.normalize_expr(e))),
252                    NormalizedNode::opt(er.end.as_ref().map(|e| self.normalize_expr(e))),
253                ],
254            ),
255            // LetExpr -> [pat, expr]
256            Expr::Let(el) => NormalizedNode::with_children(
257                NodeKind::LetExpr,
258                vec![self.normalize_pat(&el.pat), self.normalize_expr(&el.expr)],
259            ),
260            Expr::Macro(em) => self.normalize_macro(&em.mac),
261            Expr::Group(eg) => self.normalize_expr(&eg.expr),
262            Expr::Unsafe(eu) => self.normalize_block(&eu.block),
263            Expr::Const(ec) => self.normalize_block(&ec.block),
264            _ => NormalizedNode::leaf(NodeKind::Opaque),
265        }
266    }
267
268    pub fn normalize_stmt(&mut self, stmt: &Stmt) -> NormalizedNode {
269        match stmt {
270            // LetBinding -> [pattern, type_or_None, init_or_None, diverge_or_None]
271            Stmt::Local(local) => NormalizedNode::with_children(
272                NodeKind::LetBinding,
273                vec![
274                    self.normalize_pat(&local.pat),
275                    NormalizedNode::none(), // type annotations on let bindings are part of the pattern in syn
276                    NormalizedNode::opt(
277                        local
278                            .init
279                            .as_ref()
280                            .map(|init| self.normalize_expr(&init.expr)),
281                    ),
282                    NormalizedNode::opt(
283                        local
284                            .init
285                            .as_ref()
286                            .and_then(|init| init.diverge.as_ref())
287                            .map(|(_, expr)| self.normalize_expr(expr)),
288                    ),
289                ],
290            ),
291            Stmt::Expr(expr, semi) => {
292                let normalized = self.normalize_expr(expr);
293                if semi.is_some() {
294                    NormalizedNode::with_children(NodeKind::Semi, vec![normalized])
295                } else {
296                    normalized
297                }
298            }
299            Stmt::Item(_) => NormalizedNode::leaf(NodeKind::Opaque),
300            Stmt::Macro(sm) => {
301                let normalized = self.normalize_macro(&sm.mac);
302                if sm.semi_token.is_some() {
303                    NormalizedNode::with_children(NodeKind::Semi, vec![normalized])
304                } else {
305                    normalized
306                }
307            }
308        }
309    }
310
311    pub fn normalize_block(&mut self, block: &Block) -> NormalizedNode {
312        NormalizedNode::with_children(
313            NodeKind::Block,
314            block.stmts.iter().map(|s| self.normalize_stmt(s)).collect(),
315        )
316    }
317}