Skip to main content

yog_script_analyze/ast/
walk.rs

1//! Walking the tree: an expression's direct sub-expressions, a
2//! declaration's members — for passes that look at every one.
3
4use super::{Decl, DeclKind, Element, Expr, ExprKind, Name, Pattern, StrSeg};
5
6impl Expr {
7    /// Each expression directly inside this one, in reading order; a
8    /// lambda's body is not (its code runs later, on its own).
9    pub fn each_child<'e>(&'e self, mut f: impl FnMut(&'e Expr)) {
10        match &self.kind {
11            ExprKind::Str(segs) => segs.iter().for_each(|s| {
12                if let StrSeg::Expr(e) = s {
13                    f(e);
14                }
15            }),
16            ExprKind::Tuple(items) | ExprKind::Macro { args: items, .. } => {
17                items.iter().for_each(f)
18            }
19            ExprKind::Collection(items) => items.iter().for_each(|i| match i {
20                Element::Item(e) | Element::Spread(e) => f(e),
21                Element::Entry(k, v) => {
22                    f(k);
23                    f(v);
24                }
25            }),
26            ExprKind::New { args, init, .. } => {
27                args.iter().flatten().for_each(|a| f(&a.value));
28                init.iter().for_each(|(_, v)| f(v));
29            }
30            ExprKind::Call { callee, args } => {
31                f(callee);
32                args.iter().for_each(|a| f(&a.value));
33            }
34            ExprKind::Binary { left, right, .. } => {
35                f(left);
36                f(right);
37            }
38            ExprKind::Range { from, to, .. } => {
39                f(from);
40                f(to);
41            }
42            ExprKind::Index { expr, index } => {
43                f(expr);
44                f(index);
45            }
46            ExprKind::Conditional {
47                cond,
48                then,
49                otherwise,
50            } => {
51                f(cond);
52                f(then);
53                f(otherwise);
54            }
55            ExprKind::Switch { expr, arms } => {
56                f(expr);
57                for arm in arms {
58                    arm.guard.iter().for_each(&mut f);
59                    f(&arm.value);
60                }
61            }
62            _ => self.each_wrapped(f),
63        }
64    }
65
66    /// The one expression a wrapping form holds (`-x`, `x.Y`, `move x`, …).
67    fn each_wrapped<'e>(&'e self, mut f: impl FnMut(&'e Expr)) {
68        match &self.kind {
69            ExprKind::NameOf(e)
70            | ExprKind::NotNull(e)
71            | ExprKind::Move(e)
72            | ExprKind::Unary { expr: e, .. }
73            | ExprKind::Cast { expr: e, .. }
74            | ExprKind::Is { expr: e, .. }
75            | ExprKind::As { expr: e, .. }
76            | ExprKind::Has { expr: e, .. }
77            | ExprKind::TypeArgs { expr: e, .. }
78            | ExprKind::Member { expr: e, .. } => f(e),
79            _ => {}
80        }
81    }
82}
83
84impl DeclKind {
85    /// The declarations inside this one: a type's, a mod's, a namespace's
86    /// members.
87    pub fn members(&self) -> &[Decl] {
88        match self {
89            DeclKind::Namespace {
90                body: Some(body), ..
91            }
92            | DeclKind::Mod { body, .. }
93            | DeclKind::Type { body, .. }
94            | DeclKind::Enum { body, .. }
95            | DeclKind::Content { body, .. }
96            | DeclKind::Component { body, .. }
97            | DeclKind::Extend { body, .. }
98            | DeclKind::Screen { body, .. }
99            | DeclKind::Command { body, .. } => body,
100            _ => &[],
101        }
102    }
103}
104
105impl Pattern {
106    /// The names the pattern binds (`let e`, `Monster m`), in order.
107    pub fn each_binding<'p>(&'p self, f: &mut impl FnMut(&'p Name)) {
108        match self {
109            Pattern::Let(n) | Pattern::Type { bind: Some(n), .. } => f(n),
110            Pattern::Variant { args: all, .. } | Pattern::Tuple(all) => {
111                all.iter().for_each(|p| p.each_binding(f));
112            }
113            Pattern::Property { fields, .. } => fields.iter().for_each(|(_, p)| p.each_binding(f)),
114            Pattern::Or(a, b) | Pattern::And(a, b) => {
115                a.each_binding(f);
116                b.each_binding(f);
117            }
118            Pattern::Not(p) => p.each_binding(f),
119            _ => {}
120        }
121    }
122}