symoxide/mappers/
walk.rs

1// Copyright (c) 2022 Kaushik Kulkarni
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21use crate::mappers::CachedMapper;
22use crate::primitives::{BinaryOpType, Expression, LiteralT, SmallVecExprT, UnaryOpType};
23use crate::utils::ExpressionRawPointer;
24use std::rc::Rc;
25
26// {{{ WalkMapper
27
28pub trait UncachedWalkMapper {
29    fn should_walk(&self, _expr: &Expression) -> bool {
30        true
31    }
32
33    fn post_walk(&self, _expr: &Expression) {}
34
35    fn visit(&self, expr: &Expression) {
36        if self.should_walk(expr) {
37            match expr {
38                Expression::Scalar(s) => self.map_scalar(&s),
39                Expression::Variable(name) => self.map_variable(name.to_string()),
40                Expression::UnaryOp(op, x) => self.map_unary_op(op.clone(), &x),
41                Expression::BinaryOp(l, op, r) => self.map_binary_op(&l, op.clone(), &r),
42                Expression::Call(call, params) => self.map_call(&call, &params),
43                Expression::Subscript(agg, indices) => self.map_subscript(&agg, &indices),
44                Expression::If(cond, then, else_) => self.map_if(&cond, &then, &else_),
45            };
46            self.post_walk(expr);
47        }
48    }
49
50    fn map_scalar(&self, _value: &LiteralT) {}
51
52    fn map_variable(&self, _name: String) {}
53
54    fn map_unary_op(&self, _op: UnaryOpType, x: &Expression) {
55        self.visit(x);
56    }
57
58    fn map_binary_op(&self, left: &Expression, _op: BinaryOpType, right: &Expression) {
59        self.visit(left);
60        self.visit(right);
61    }
62
63    fn map_call(&self, call: &Expression, params: &SmallVecExprT) {
64        self.visit(call);
65        for param in params {
66            self.visit(param);
67        }
68    }
69
70    fn map_subscript(&self, agg: &Expression, indices: &SmallVecExprT) {
71        self.visit(agg);
72        for idx in indices {
73            self.visit(idx);
74        }
75    }
76
77    fn map_if(&self, cond: &Expression, then: &Expression, else_: &Expression) {
78        self.visit(cond);
79        self.visit(then);
80        self.visit(else_);
81    }
82}
83
84// }}}
85
86// {{{ WalkMapperWithContext
87
88pub trait WalkMapperWithContext {
89    type Context;
90
91    fn should_walk(&self, _expr: &Expression, _context: &Self::Context) -> bool {
92        true
93    }
94
95    fn post_walk(&self, _expr: &Expression, _context: &Self::Context) {}
96
97    fn visit(&self, expr: &Expression, context: &Self::Context) {
98        if self.should_walk(expr, context) {
99            match expr {
100                Expression::Scalar(s) => self.map_scalar(&s, context),
101                Expression::Variable(name) => self.map_variable(name.to_string(), context),
102                Expression::UnaryOp(op, x) => self.map_unary_op(op.clone(), &x, context),
103                Expression::BinaryOp(l, op, r) => self.map_binary_op(&l, op.clone(), &r, context),
104                Expression::Call(call, params) => self.map_call(&call, &params, context),
105                Expression::Subscript(agg, indices) => self.map_subscript(&agg, &indices, context),
106                Expression::If(cond, then, else_) => self.map_if(&cond, &then, &else_, context),
107            };
108            self.post_walk(expr, context);
109        }
110    }
111
112    fn map_scalar(&self, _value: &LiteralT, _context: &Self::Context) {}
113
114    fn map_variable(&self, _name: String, _context: &Self::Context) {}
115
116    fn map_unary_op(&self, _op: UnaryOpType, x: &Expression, context: &Self::Context) {
117        self.visit(x, context);
118    }
119
120    fn map_binary_op(&self, left: &Expression, _op: BinaryOpType, right: &Expression,
121                     context: &Self::Context) {
122        self.visit(left, context);
123        self.visit(right, context);
124    }
125
126    fn map_call(&self, call: &Expression, params: &SmallVecExprT, context: &Self::Context) {
127        self.visit(call, context);
128        for param in params {
129            self.visit(param, context);
130        }
131    }
132
133    fn map_subscript(&self, agg: &Expression, indices: &SmallVecExprT, context: &Self::Context) {
134        self.visit(agg, context);
135        for idx in indices {
136            self.visit(idx, context);
137        }
138    }
139
140    fn map_if(&self, cond: &Expression, then: &Expression, else_: &Expression,
141              context: &Self::Context) {
142        self.visit(cond, context);
143        self.visit(then, context);
144        self.visit(else_, context);
145    }
146}
147
148// }}}
149
150// {{{ WalkMapper
151
152pub trait WalkMapper: CachedMapper<ExpressionRawPointer, bool> {
153    fn should_walk(&self, _expr: &Expression) -> bool {
154        true
155    }
156
157    fn post_walk(&mut self, _expr: &Expression) {}
158
159    fn visit(&mut self, expr: &Rc<Expression>) {
160        let cache_key = ExpressionRawPointer(expr.clone());
161
162        match self.query_cache(&cache_key) {
163            Some(true) => {}
164            None => {
165                if self.should_walk(&expr) {
166                    match &*expr.clone() {
167                        Expression::Scalar(s) => self.map_scalar(&s),
168                        Expression::Variable(name) => self.map_variable(name.to_string()),
169                        Expression::UnaryOp(op, x) => self.map_unary_op(op.clone(), x),
170                        Expression::BinaryOp(l, op, r) => self.map_binary_op(l, op.clone(), r),
171                        Expression::Call(call, params) => self.map_call(call, &params),
172                        Expression::Subscript(agg, indices) => self.map_subscript(agg, &indices),
173                        Expression::If(cond, then, else_) => self.map_if(cond, then, else_),
174                    };
175                    self.post_walk(&expr);
176                };
177                self.add_to_cache(cache_key, true);
178            }
179            _ => unreachable!(),
180        }
181    }
182
183    fn map_scalar(&mut self, _value: &LiteralT) {}
184
185    fn map_variable(&mut self, _name: String) {}
186
187    fn map_unary_op(&mut self, _op: UnaryOpType, x: &Rc<Expression>) {
188        self.visit(x);
189    }
190
191    fn map_binary_op(&mut self, left: &Rc<Expression>, _op: BinaryOpType, right: &Rc<Expression>) {
192        self.visit(left);
193        self.visit(right);
194    }
195
196    fn map_call(&mut self, call: &Rc<Expression>, params: &SmallVecExprT) {
197        self.visit(call);
198        for param in params {
199            self.visit(param);
200        }
201    }
202
203    fn map_subscript(&mut self, agg: &Rc<Expression>, indices: &SmallVecExprT) {
204        self.visit(agg);
205        for idx in indices {
206            self.visit(idx);
207        }
208    }
209
210    fn map_if(&mut self, cond: &Rc<Expression>, then: &Rc<Expression>, else_: &Rc<Expression>) {
211        self.visit(cond);
212        self.visit(then);
213        self.visit(else_);
214    }
215}
216
217// }}}
218
219// vim: fdm=marker