1use crate::ast::AstNode;
4use crate::errors::Result;
5use crate::values::Value;
6use std::collections::HashMap;
7
8pub type IndexKey = u8;
10
11pub type IndexedValues = HashMap<IndexKey, Value>;
13
14pub type Evaluator = Box<dyn Fn(&IndexedValues) -> Value>;
16
17pub fn build_evaluator(node: &AstNode) -> Result<Evaluator> {
19 match node {
20 AstNode::And(lhs, rhs) => build_and(lhs, rhs),
21 AstNode::Eq(lhs, rhs) => build_eq(lhs, rhs),
22 AstNode::Ge(lhs, rhs) => build_ge(lhs, rhs),
23 AstNode::Gt(lhs, rhs) => build_gt(lhs, rhs),
24 AstNode::If(mhs, lhs, rhs) => build_if(mhs, lhs, rhs),
25 AstNode::Le(lhs, rhs) => build_le(lhs, rhs),
26 AstNode::Lt(lhs, rhs) => build_lt(lhs, rhs),
27 AstNode::Nq(lhs, rhs) => build_nq(lhs, rhs),
28 AstNode::Null => build_null(),
29 AstNode::Number(mhs) => build_number(*mhs),
30 AstNode::Or(lhs, rhs) => build_or(lhs, rhs),
31 }
32}
33
34fn build_and(lhs: &AstNode, rhs: &AstNode) -> Result<Evaluator> {
36 let lhe = build_evaluator(lhs)?;
37 let rhe = build_evaluator(rhs)?;
38 Ok(Box::new(move |iv: &IndexedValues| {
39 if let Value::Bool(lhv) = lhe(iv) {
40 if let Value::Bool(rhv) = rhe(iv) {
41 return Value::Bool(lhv && rhv);
42 }
43 }
44 Value::Null
45 }))
46}
47
48fn build_eq(lhs: &AstNode, rhs: &AstNode) -> Result<Evaluator> {
50 let lhe = build_evaluator(lhs)?;
51 let rhe = build_evaluator(rhs)?;
52 Ok(Box::new(move |iv: &IndexedValues| match lhe(iv) {
53 Value::Number(lhv) => match rhe(iv) {
54 Value::Number(rhv) => Value::Bool(lhv == rhv),
55 Value::Null => Value::Bool(false),
56 _ => Value::Null,
57 },
58 Value::Null => match rhe(iv) {
59 Value::Number(_) => Value::Bool(false),
60 Value::Null => Value::Bool(true),
61 _ => Value::Null,
62 },
63 _ => Value::Null,
64 }))
65}
66
67fn build_ge(lhs: &AstNode, rhs: &AstNode) -> Result<Evaluator> {
69 let lhe = build_evaluator(lhs)?;
70 let rhe = build_evaluator(rhs)?;
71 Ok(Box::new(move |iv: &IndexedValues| {
72 if let Value::Number(lhv) = lhe(iv) {
73 if let Value::Number(rhv) = rhe(iv) {
74 return Value::Bool(lhv >= rhv);
75 }
76 }
77 Value::Null
78 }))
79}
80
81fn build_gt(lhs: &AstNode, rhs: &AstNode) -> Result<Evaluator> {
83 let lhe = build_evaluator(lhs)?;
84 let rhe = build_evaluator(rhs)?;
85 Ok(Box::new(move |iv: &IndexedValues| {
86 if let Value::Number(lhv) = lhe(iv) {
87 if let Value::Number(rhv) = rhe(iv) {
88 return Value::Bool(lhv > rhv);
89 }
90 }
91 Value::Null
92 }))
93}
94
95fn build_if(mhs: &AstNode, lhs: &AstNode, rhs: &AstNode) -> Result<Evaluator> {
97 let mhe = build_evaluator(mhs)?;
98 let lhe = build_evaluator(lhs)?;
99 let rhe = build_evaluator(rhs)?;
100 Ok(Box::new(move |iv: &IndexedValues| {
101 if let Value::Bool(mhv) = mhe(iv) {
102 return if mhv { lhe(iv) } else { rhe(iv) };
103 }
104 Value::Null
105 }))
106}
107
108fn build_le(lhs: &AstNode, rhs: &AstNode) -> Result<Evaluator> {
110 let lhe = build_evaluator(lhs)?;
111 let rhe = build_evaluator(rhs)?;
112 Ok(Box::new(move |iv: &IndexedValues| {
113 if let Value::Number(lhv) = lhe(iv) {
114 if let Value::Number(rhv) = rhe(iv) {
115 return Value::Bool(lhv <= rhv);
116 }
117 }
118 Value::Null
119 }))
120}
121
122fn build_lt(lhs: &AstNode, rhs: &AstNode) -> Result<Evaluator> {
124 let lhe = build_evaluator(lhs)?;
125 let rhe = build_evaluator(rhs)?;
126 Ok(Box::new(move |iv: &IndexedValues| {
127 if let Value::Number(lhv) = lhe(iv) {
128 if let Value::Number(rhv) = rhe(iv) {
129 return Value::Bool(lhv < rhv);
130 }
131 }
132 Value::Null
133 }))
134}
135
136fn build_nq(lhs: &AstNode, rhs: &AstNode) -> Result<Evaluator> {
138 let lhe = build_evaluator(lhs)?;
139 let rhe = build_evaluator(rhs)?;
140 Ok(Box::new(move |iv: &IndexedValues| match lhe(iv) {
141 Value::Number(lhv) => match rhe(iv) {
142 Value::Number(rhv) => Value::Bool(lhv != rhv),
143 Value::Null => Value::Bool(true),
144 _ => Value::Null,
145 },
146 Value::Null => match rhe(iv) {
147 Value::Number(_) => Value::Bool(true),
148 Value::Null => Value::Bool(false),
149 _ => Value::Null,
150 },
151 _ => Value::Null,
152 }))
153}
154
155fn build_or(lhs: &AstNode, rhs: &AstNode) -> Result<Evaluator> {
157 let lhe = build_evaluator(lhs)?;
158 let rhe = build_evaluator(rhs)?;
159 Ok(Box::new(move |iv: &IndexedValues| {
160 if let Value::Bool(lhv) = lhe(iv) {
161 if let Value::Bool(rhv) = rhe(iv) {
162 return Value::Bool(lhv || rhv);
163 }
164 }
165 Value::Null
166 }))
167}
168
169fn build_null() -> Result<Evaluator> {
171 Ok(Box::new(move |_: &IndexedValues| Value::Null))
172}
173
174fn build_number(key: IndexKey) -> Result<Evaluator> {
176 Ok(Box::new(
177 move |iv: &IndexedValues| if let Some(value) = iv.get(&key) { *value } else { Value::Null },
178 ))
179}
180
181#[cfg(test)]
182mod tests {
183 use super::*;
184 use crate::IndexedValues;
185 use rust_decimal::Decimal;
186
187 #[test]
188 fn test_build_if() {
189 let mut m = IndexedValues::new();
190 m.insert(1, Value::Bool(true));
191 m.insert(2, Value::Bool(true));
192 let b = build_if(&AstNode::Number(255), &AstNode::Number(1), &AstNode::Number(2)).unwrap();
193 assert_eq!(Value::Null, b(&m));
194 }
195
196 #[test]
197 fn test_build_ge() {
198 let mut r = IndexedValues::new();
199 r.insert(1, Value::Bool(true));
200 r.insert(2, Value::Bool(false));
201 let b = build_ge(&AstNode::Number(1), &AstNode::Number(1)).unwrap();
202 assert_eq!(Value::Null, b(&r));
203 }
204
205 #[test]
206 fn test_build_gt() {
207 let mut r = IndexedValues::new();
208 r.insert(1, Value::Bool(true));
209 r.insert(2, Value::Bool(false));
210 let b = build_gt(&AstNode::Number(1), &AstNode::Number(1)).unwrap();
211 assert_eq!(Value::Null, b(&r));
212 }
213
214 #[test]
215 fn test_build_le() {
216 let mut r = IndexedValues::new();
217 r.insert(1, Value::Bool(true));
218 r.insert(2, Value::Bool(false));
219 let b = build_le(&AstNode::Number(1), &AstNode::Number(1)).unwrap();
220 assert_eq!(Value::Null, b(&r));
221 }
222
223 #[test]
224 fn test_build_lt() {
225 let mut r = IndexedValues::new();
226 r.insert(1, Value::Bool(true));
227 r.insert(2, Value::Bool(false));
228 let b = build_lt(&AstNode::Number(1), &AstNode::Number(1)).unwrap();
229 assert_eq!(Value::Null, b(&r));
230 }
231
232 #[test]
233 fn test_build_eq() {
234 let mut r = IndexedValues::new();
235 r.insert(1, Value::Bool(true));
236 r.insert(2, Value::Number(Decimal::new(123, 2)));
237 let b = build_eq(&AstNode::Null, &AstNode::Number(1)).unwrap();
238 assert_eq!(Value::Null, b(&r));
239 let b = build_eq(&AstNode::Number(2), &AstNode::Number(1)).unwrap();
240 assert_eq!(Value::Null, b(&r));
241 let b = build_eq(&AstNode::Number(1), &AstNode::Number(2)).unwrap();
242 assert_eq!(Value::Null, b(&r));
243 }
244
245 #[test]
246 fn test_build_nq() {
247 let mut r = IndexedValues::new();
248 r.insert(1, Value::Bool(true));
249 r.insert(2, Value::Number(Decimal::new(123, 2)));
250 let b = build_nq(&AstNode::Null, &AstNode::Number(1)).unwrap();
251 assert_eq!(Value::Null, b(&r));
252 let b = build_nq(&AstNode::Number(2), &AstNode::Number(1)).unwrap();
253 assert_eq!(Value::Null, b(&r));
254 let b = build_nq(&AstNode::Number(1), &AstNode::Number(2)).unwrap();
255 assert_eq!(Value::Null, b(&r));
256 }
257
258 #[test]
259 fn test_build_and() {
260 let r = IndexedValues::new();
261 let b = build_and(&AstNode::Null, &AstNode::Null).unwrap();
262 assert_eq!(Value::Null, b(&r));
263 }
264
265 #[test]
266 fn test_build_or() {
267 let r = IndexedValues::new();
268 let b = build_or(&AstNode::Null, &AstNode::Null).unwrap();
269 assert_eq!(Value::Null, b(&r));
270 }
271
272 #[test]
273 fn test_build_null() {
274 let r = IndexedValues::new();
275 let b = build_null().unwrap();
276 assert_eq!(Value::Null, b(&r));
277 }
278
279 #[test]
280 fn test_build_number() {
281 let mut r = IndexedValues::new();
282 let b = build_number(1).unwrap();
283 assert_eq!(Value::Null, b(&r));
284 r.insert(1, Value::Number(Decimal::new(123, 2)));
285 assert_eq!(Value::Number(Decimal::new(123, 2)), b(&r));
286 }
287}