1pub mod context;
2pub mod coercion;
3pub mod functions;
4pub mod resolver;
5
6pub use context::Context;
7pub use functions::{EvalCtx, FunctionMeta, Registry};
8pub use resolver::{extract_refs, Resolver};
9
10use crate::parser::ast::{BinaryOp, Expr, UnaryOp};
11use crate::types::{ErrorKind, Value};
12
13use coercion::{to_number, to_string_val};
14use functions::FunctionKind;
15
16pub fn evaluate_expr(expr: &Expr, ctx: &mut EvalCtx<'_>) -> Value {
23 match expr {
24 Expr::Number(n, _) => {
26 if n.is_finite() {
27 Value::Number(*n)
28 } else {
29 Value::Error(ErrorKind::Num)
30 }
31 }
32 Expr::Text(s, _) => Value::Text(s.clone()),
33 Expr::Bool(b, _) => Value::Bool(*b),
34 Expr::Variable(name, _) => match ctx.ctx.lookup(name) {
38 Some(v) => v,
39 None => ctx.resolve_ref(&crate::parser::refs::Ref::classify(name)),
40 },
41 Expr::Reference(r, _) => match ctx.ctx.lookup(&r.to_string()) {
45 Some(v) => v,
46 None => ctx.resolve_ref(r),
47 },
48
49 Expr::UnaryOp { op, operand, .. } => {
51 let val = evaluate_expr(operand, ctx);
52 match to_number(val) {
53 Err(e) => e,
54 Ok(n) => match op {
55 UnaryOp::Neg => Value::Number(-n),
56 UnaryOp::Percent => Value::Number(n / 100.0),
57 },
58 }
59 }
60
61 Expr::BinaryOp { op, left, right, .. } => {
63 let lv = evaluate_expr(left, ctx);
64 let rv = evaluate_expr(right, ctx);
65 eval_binary(op, lv, rv)
66 }
67
68 Expr::Array(elems, _) => {
70 let mut values = Vec::with_capacity(elems.len());
71 for elem in elems {
72 let v = evaluate_expr(elem, ctx);
73 values.push(v);
74 }
75 Value::Array(values)
76 }
77
78 Expr::Apply { func, call_args, .. } => {
80 eval_apply(func, call_args, ctx)
81 }
82
83 Expr::FunctionCall { name, args, .. } => {
85 match ctx.registry.get(name) {
86 None => Value::Error(ErrorKind::Name),
87 Some(FunctionKind::Lazy(f)) => {
88 let f: functions::LazyFn = *f;
91 f(args, ctx)
92 }
93 Some(FunctionKind::Eager(f)) => {
94 let f: functions::EagerFn = *f;
95 let mut evaluated = Vec::with_capacity(args.len());
97 for arg in args {
98 let v = evaluate_expr(arg, ctx);
99 if matches!(v, Value::Error(_)) {
100 return v;
101 }
102 evaluated.push(v);
103 }
104 f(&evaluated)
105 }
106 }
107 }
108
109 }
110}
111
112fn eval_apply(func: &Expr, call_args: &[Expr], ctx: &mut EvalCtx<'_>) -> Value {
114 let (lambda_params, body) = match func {
115 Expr::FunctionCall { name, args: lambda_args, .. } if name == "LAMBDA" => {
116 if lambda_args.is_empty() {
117 return Value::Error(ErrorKind::NA);
118 }
119 let param_count = lambda_args.len() - 1;
120 let mut params: Vec<String> = Vec::with_capacity(param_count);
121 for param_expr in &lambda_args[..param_count] {
122 match param_expr {
123 Expr::Variable(n, _) => params.push(n.to_uppercase()),
124 _ => return Value::Error(ErrorKind::Name),
125 }
126 }
127 let body = &lambda_args[lambda_args.len() - 1];
128 (params, body)
129 }
130 _ => return Value::Error(ErrorKind::Value),
131 };
132
133 if call_args.len() != lambda_params.len() {
134 return Value::Error(ErrorKind::NA);
135 }
136
137 let mut evaluated_args: Vec<Value> = Vec::with_capacity(call_args.len());
138 for arg in call_args {
139 let v = evaluate_expr(arg, ctx);
140 if matches!(v, Value::Error(_)) {
141 return v;
142 }
143 evaluated_args.push(v);
144 }
145
146 let mut saved: Vec<(String, Option<Value>)> = Vec::with_capacity(lambda_params.len());
147 for (param, val) in lambda_params.iter().zip(evaluated_args) {
148 let old = ctx.ctx.set(param.clone(), val);
149 saved.push((param.clone(), old));
150 }
151
152 let result = evaluate_expr(body, ctx);
153
154 for (name, old_val) in saved.into_iter().rev() {
155 match old_val {
156 Some(v) => { ctx.ctx.set(name, v); }
157 None => { ctx.ctx.remove(&name); }
158 }
159 }
160
161 result
162}
163
164fn type_rank(v: &Value) -> u8 {
167 match v {
168 Value::Number(_) | Value::Date(_) | Value::Empty | Value::Zoned(_) => 0,
169 Value::Text(_) => 1,
170 Value::Bool(_) => 2,
171 Value::Error(_) | Value::Array(_) => 3,
174 }
175}
176
177fn eval_binary(op: &BinaryOp, lv: Value, rv: Value) -> Value {
178 match (&lv, &rv) {
180 (Value::Array(lelems), Value::Array(relems)) => {
181 if lelems.len() != relems.len() {
183 return Value::Error(ErrorKind::Value);
184 }
185 let result: Vec<Value> = lelems
186 .iter()
187 .zip(relems.iter())
188 .map(|(l, r)| eval_binary(op, l.clone(), r.clone()))
189 .collect();
190 return Value::Array(result);
191 }
192 (Value::Array(elems), _) => {
193 let result: Vec<Value> = elems
194 .iter()
195 .map(|e| eval_binary(op, e.clone(), rv.clone()))
196 .collect();
197 return Value::Array(result);
198 }
199 (_, Value::Array(elems)) => {
200 let result: Vec<Value> = elems
201 .iter()
202 .map(|e| eval_binary(op, lv.clone(), e.clone()))
203 .collect();
204 return Value::Array(result);
205 }
206 _ => {}
207 }
208 match op {
209 BinaryOp::Add | BinaryOp::Sub | BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow => {
211 let date_typed_add = matches!(op, BinaryOp::Add)
219 && matches!(lv, Value::Date(_)) != matches!(rv, Value::Date(_));
220 let ln = match to_number(lv) { Ok(n) => n, Err(e) => return e };
221 let rn = match to_number(rv) { Ok(n) => n, Err(e) => return e };
222 let result = match op {
223 BinaryOp::Add => ln + rn,
224 BinaryOp::Sub => ln - rn,
225 BinaryOp::Mul => ln * rn,
226 BinaryOp::Div => {
227 if rn == 0.0 {
228 return Value::Error(ErrorKind::DivByZero);
229 }
230 ln / rn
231 }
232 BinaryOp::Pow => libm::pow(ln, rn),
233 _ => unreachable!(),
235 };
236 if !result.is_finite() {
237 return Value::Error(ErrorKind::Num);
238 }
239 if date_typed_add {
240 Value::Date(result)
241 } else {
242 Value::Number(result)
243 }
244 }
245
246 BinaryOp::Concat => {
248 let ls = match to_string_val(lv) { Ok(s) => s, Err(e) => return e };
249 let rs = match to_string_val(rv) { Ok(s) => s, Err(e) => return e };
250 Value::Text(ls + &rs)
251 }
252
253 BinaryOp::Eq | BinaryOp::Ne
255 | BinaryOp::Lt | BinaryOp::Gt
256 | BinaryOp::Le | BinaryOp::Ge => {
257 if let Value::Error(_) = &lv { return lv; }
259 if let Value::Error(_) = &rv { return rv; }
260 if matches!(&lv, Value::Zoned(_)) ^ matches!(&rv, Value::Zoned(_)) {
263 return Value::Error(ErrorKind::Value);
264 }
265
266 let result = compare_values(op, &lv, &rv);
267 Value::Bool(result)
268 }
269 }
270}
271
272fn compare_values(op: &BinaryOp, lv: &Value, rv: &Value) -> bool {
274 match (lv, rv) {
275 (Value::Number(a), Value::Number(b)) => apply_cmp(op, a.partial_cmp(b)),
276 (Value::Date(a), Value::Date(b)) => apply_cmp(op, a.partial_cmp(b)),
277 (Value::Date(a), Value::Number(b)) => apply_cmp(op, a.partial_cmp(b)),
278 (Value::Number(a), Value::Date(b)) => apply_cmp(op, a.partial_cmp(b)),
279 (Value::Zoned(a), Value::Zoned(b)) => apply_cmp(op, Some(a.utc_nanos.cmp(&b.utc_nanos))),
282 (Value::Text(a), Value::Text(b)) => apply_cmp(op, Some(a.cmp(b))),
283 (Value::Bool(a), Value::Bool(b)) => apply_cmp(op, Some(a.cmp(b))),
284 (Value::Empty, Value::Empty) => apply_cmp(op, Some(std::cmp::Ordering::Equal)),
285 (Value::Empty, Value::Number(b)) => apply_cmp(op, 0.0f64.partial_cmp(b)),
287 (Value::Number(a), Value::Empty) => apply_cmp(op, a.partial_cmp(&0.0f64)),
288 _ => {
290 let lr = type_rank(lv);
291 let rr = type_rank(rv);
292 match op {
293 BinaryOp::Eq => false,
294 BinaryOp::Ne => true,
295 BinaryOp::Lt => lr < rr,
296 BinaryOp::Gt => lr > rr,
297 BinaryOp::Le => lr <= rr,
298 BinaryOp::Ge => lr >= rr,
299 _ => unreachable!(),
301 }
302 }
303 }
304}
305
306fn apply_cmp(op: &BinaryOp, ord: Option<std::cmp::Ordering>) -> bool {
307 match ord {
308 None => false,
311 Some(o) => match op {
312 BinaryOp::Eq => o.is_eq(),
313 BinaryOp::Ne => o.is_ne(),
314 BinaryOp::Lt => o.is_lt(),
315 BinaryOp::Gt => o.is_gt(),
316 BinaryOp::Le => o.is_le(),
317 BinaryOp::Ge => o.is_ge(),
318 _ => unreachable!(),
320 },
321 }
322}
323
324#[cfg(test)]
326mod tests;