ucglib/ast/
walk.rs

1use crate::ast::*;
2
3pub trait Walker {
4    fn walk_statement_list(&mut self, stmts: Vec<&mut Statement>) {
5        for v in stmts {
6            self.walk_statement(v);
7        }
8    }
9
10    fn walk_statement(&mut self, stmt: &mut Statement) {
11        self.visit_statement(stmt);
12        match stmt {
13            Statement::Let(ref mut def) => {
14                self.walk_expression(&mut def.value);
15            }
16            Statement::Expression(ref mut expr) => {
17                self.walk_expression(expr);
18            }
19            Statement::Assert(_, ref mut expr) => {
20                self.walk_expression(expr);
21            }
22            Statement::Output(_, _, ref mut expr) => {
23                self.walk_expression(expr);
24            }
25            Statement::Print(_, _, ref mut expr) => {
26                self.walk_expression(expr);
27            }
28        }
29    }
30
31    fn walk_fieldset(&mut self, fs: &mut FieldList) {
32        for &mut (_, ref mut expr) in fs.iter_mut() {
33            self.walk_expression(expr);
34        }
35    }
36
37    fn walk_expression(&mut self, expr: &mut Expression) {
38        self.visit_expression(expr);
39        match expr {
40            Expression::Call(ref mut def) => {
41                for expr in def.arglist.iter_mut() {
42                    self.walk_expression(expr);
43                }
44            }
45            Expression::Cast(ref mut def) => {
46                self.walk_expression(&mut def.target);
47            }
48            Expression::Copy(ref mut def) => {
49                self.walk_fieldset(&mut def.fields);
50            }
51            Expression::Format(ref mut def) => match def.args {
52                FormatArgs::List(ref mut args) => {
53                    for expr in args.iter_mut() {
54                        self.walk_expression(expr);
55                    }
56                }
57                FormatArgs::Single(ref mut expr) => {
58                    self.walk_expression(expr);
59                }
60            },
61            Expression::FuncOp(ref mut def) => match def {
62                FuncOpDef::Reduce(ref mut def) => {
63                    self.walk_expression(def.target.as_mut());
64                    self.walk_expression(def.acc.as_mut())
65                }
66                FuncOpDef::Map(ref mut def) => {
67                    self.walk_expression(def.target.as_mut());
68                }
69                FuncOpDef::Filter(ref mut def) => {
70                    self.walk_expression(def.target.as_mut());
71                }
72            },
73            Expression::Binary(ref mut def) => {
74                self.walk_expression(def.left.as_mut());
75                self.walk_expression(def.right.as_mut());
76            }
77            Expression::Grouped(ref mut expr, _) => {
78                self.walk_expression(expr);
79            }
80            Expression::Func(ref mut def) => self.walk_expression(def.fields.as_mut()),
81            Expression::Module(ref mut def) => {
82                self.walk_fieldset(&mut def.arg_set);
83                for stmt in def.statements.iter_mut() {
84                    self.walk_statement(stmt);
85                }
86            }
87            Expression::Range(ref mut def) => {
88                self.walk_expression(def.start.as_mut());
89                self.walk_expression(def.end.as_mut());
90                if let Some(ref mut expr) = def.step {
91                    self.walk_expression(expr.as_mut());
92                }
93            }
94            Expression::Select(ref mut def) => {
95                match def.default {
96                    Some(ref mut e) => {
97                        self.walk_expression(e.as_mut());
98                    }
99                    None => {
100                        // noop;
101                    }
102                };
103                self.walk_expression(def.val.as_mut());
104                self.walk_fieldset(&mut def.tuple);
105            }
106            Expression::Simple(ref mut val) => {
107                self.walk_value(val);
108            }
109
110            Expression::Import(i) => {
111                self.visit_import(i);
112            }
113            Expression::Include(i) => {
114                self.visit_include(i);
115            }
116            Expression::Fail(f) => {
117                self.visit_fail(f);
118            }
119            Expression::Not(ref mut def) => {
120                self.walk_expression(def.expr.as_mut());
121            }
122            Expression::Debug(ref mut def) => {
123                self.walk_expression(&mut def.expr);
124            }
125        }
126    }
127
128    fn walk_value(&mut self, val: &mut Value) {
129        match val {
130            Value::Empty(_)
131            | Value::Symbol(_)
132            | Value::Boolean(_)
133            | Value::Int(_)
134            | Value::Float(_)
135            | Value::Str(_) => self.visit_value(val),
136            Value::Tuple(fs) => self.walk_fieldset(&mut fs.val),
137            Value::List(vs) => {
138                for e in &mut vs.elems {
139                    self.walk_expression(e);
140                }
141            }
142        }
143    }
144
145    // TODO(jwall): Should this have exit versions as well?
146    fn visit_import(&mut self, _i: &mut ImportDef) {
147        // noop by default;
148    }
149
150    fn visit_include(&mut self, _i: &mut IncludeDef) {
151        // noop by default;
152    }
153
154    fn visit_fail(&mut self, _f: &mut FailDef) {
155        // noop by default;
156    }
157
158    fn visit_value(&mut self, _val: &mut Value) {
159        // noop by default
160    }
161
162    fn visit_expression(&mut self, _expr: &mut Expression) {
163        // noop by default
164    }
165
166    fn visit_statement(&mut self, _stmt: &mut Statement) {
167        // noop by default
168    }
169}
170
171// TODO this would be better implemented as a Trait I think.
172pub struct AstWalker<'a> {
173    handle_value: Option<&'a dyn Fn(&mut Value)>,
174    handle_expression: Option<&'a dyn Fn(&mut Expression)>,
175    handle_statment: Option<&'a dyn Fn(&mut Statement)>,
176}
177
178impl<'a> AstWalker<'a> {
179    pub fn new() -> Self {
180        AstWalker {
181            handle_value: None,
182            handle_expression: None,
183            handle_statment: None,
184        }
185    }
186
187    pub fn with_value_handler(mut self, h: &'a dyn Fn(&mut Value)) -> Self {
188        self.handle_value = Some(h);
189        self
190    }
191
192    pub fn with_expr_handler(mut self, h: &'a dyn Fn(&mut Expression)) -> Self {
193        self.handle_expression = Some(h);
194        self
195    }
196
197    pub fn with_stmt_handler(mut self, h: &'a dyn Fn(&mut Statement)) -> Self {
198        self.handle_statment = Some(h);
199        self
200    }
201}
202
203impl<'a> Walker for AstWalker<'a> {
204    fn visit_value(&mut self, val: &mut Value) {
205        if let Some(h) = self.handle_value {
206            h(val);
207        }
208    }
209
210    fn visit_expression(&mut self, expr: &mut Expression) {
211        if let Some(h) = self.handle_expression {
212            h(expr);
213        }
214    }
215
216    fn visit_statement(&mut self, stmt: &mut Statement) {
217        if let Some(h) = self.handle_statment {
218            h(stmt);
219        }
220    }
221}