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.replace('$', "")) {
43 Some(v) => v,
44 None => ctx.resolve_ref(&crate::parser::refs::Ref::classify(name)),
45 },
46 Expr::Reference(r, _) => match ctx.ctx.lookup(&r.relative_display()) {
52 Some(v) => v,
53 None => ctx.resolve_ref(r),
54 },
55
56 Expr::UnaryOp { op, operand, .. } => {
58 let val = evaluate_expr(operand, ctx);
59 match to_number(val) {
60 Err(e) => e,
61 Ok(n) => match op {
62 UnaryOp::Neg => Value::Number(-n),
63 UnaryOp::Percent => Value::Number(n / 100.0),
64 },
65 }
66 }
67
68 Expr::BinaryOp { op, left, right, .. } => {
70 let lv = evaluate_expr(left, ctx);
71 let rv = evaluate_expr(right, ctx);
72 eval_binary(op, lv, rv)
73 }
74
75 Expr::Array(elems, _) => {
77 let mut values = Vec::with_capacity(elems.len());
78 for elem in elems {
79 let v = evaluate_expr(elem, ctx);
80 values.push(v);
81 }
82 Value::Array(values)
83 }
84
85 Expr::Apply { func, call_args, .. } => {
87 eval_apply(func, call_args, ctx)
88 }
89
90 Expr::FunctionCall { name, args, .. } => {
92 match ctx.registry.get(name) {
93 None => Value::Error(ErrorKind::Name),
94 Some(FunctionKind::Lazy(f)) => {
95 let f: functions::LazyFn = *f;
98 f(args, ctx)
99 }
100 Some(FunctionKind::Eager(f)) => {
101 let f: functions::EagerFn = *f;
102 let mut evaluated = Vec::with_capacity(args.len());
104 for arg in args {
105 let v = evaluate_expr(arg, ctx);
106 if matches!(v, Value::Error(_)) {
107 return v;
108 }
109 evaluated.push(v);
110 }
111 f(&evaluated)
112 }
113 }
114 }
115
116 }
117}
118
119fn eval_apply(func: &Expr, call_args: &[Expr], ctx: &mut EvalCtx<'_>) -> Value {
121 let (lambda_params, body) = match func {
122 Expr::FunctionCall { name, args: lambda_args, .. } if name == "LAMBDA" => {
123 if lambda_args.is_empty() {
124 return Value::Error(ErrorKind::NA);
125 }
126 let param_count = lambda_args.len() - 1;
127 let mut params: Vec<String> = Vec::with_capacity(param_count);
128 for param_expr in &lambda_args[..param_count] {
129 match param_expr {
130 Expr::Variable(n, _) => params.push(n.to_uppercase().replace('$', "")),
134 _ => return Value::Error(ErrorKind::Name),
135 }
136 }
137 let body = &lambda_args[lambda_args.len() - 1];
138 (params, body)
139 }
140 _ => return Value::Error(ErrorKind::Value),
141 };
142
143 if call_args.len() != lambda_params.len() {
144 return Value::Error(ErrorKind::NA);
145 }
146
147 let mut evaluated_args: Vec<Value> = Vec::with_capacity(call_args.len());
148 for arg in call_args {
149 let v = evaluate_expr(arg, ctx);
150 if matches!(v, Value::Error(_)) {
151 return v;
152 }
153 evaluated_args.push(v);
154 }
155
156 let mut saved: Vec<(String, Option<Value>)> = Vec::with_capacity(lambda_params.len());
157 for (param, val) in lambda_params.iter().zip(evaluated_args) {
158 let old = ctx.ctx.set(param.clone(), val);
159 saved.push((param.clone(), old));
160 }
161
162 let result = evaluate_expr(body, ctx);
163
164 for (name, old_val) in saved.into_iter().rev() {
165 match old_val {
166 Some(v) => { ctx.ctx.set(name, v); }
167 None => { ctx.ctx.remove(&name); }
168 }
169 }
170
171 result
172}
173
174fn type_rank(v: &Value) -> u8 {
177 match v {
178 Value::Number(_) | Value::Date(_) | Value::Empty | Value::Zoned(_) => 0,
179 Value::Text(_) => 1,
180 Value::Bool(_) => 2,
181 Value::Error(_) | Value::Array(_) => 3,
184 }
185}
186
187fn eval_binary(op: &BinaryOp, lv: Value, rv: Value) -> Value {
188 match (&lv, &rv) {
190 (Value::Array(lelems), Value::Array(relems)) => {
191 if lelems.len() != relems.len() {
193 return Value::Error(ErrorKind::Value);
194 }
195 let result: Vec<Value> = lelems
196 .iter()
197 .zip(relems.iter())
198 .map(|(l, r)| eval_binary(op, l.clone(), r.clone()))
199 .collect();
200 return Value::Array(result);
201 }
202 (Value::Array(elems), _) => {
203 let result: Vec<Value> = elems
204 .iter()
205 .map(|e| eval_binary(op, e.clone(), rv.clone()))
206 .collect();
207 return Value::Array(result);
208 }
209 (_, Value::Array(elems)) => {
210 let result: Vec<Value> = elems
211 .iter()
212 .map(|e| eval_binary(op, lv.clone(), e.clone()))
213 .collect();
214 return Value::Array(result);
215 }
216 _ => {}
217 }
218 match op {
219 BinaryOp::Add | BinaryOp::Sub | BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow => {
221 let date_typed = match op {
232 BinaryOp::Add => {
233 matches!(lv, Value::Date(_)) != matches!(rv, Value::Date(_))
234 }
235 BinaryOp::Sub => {
236 matches!(lv, Value::Date(_)) && !matches!(rv, Value::Date(_))
237 }
238 _ => false,
239 };
240 let ln = match to_number(lv) { Ok(n) => n, Err(e) => return e };
241 let rn = match to_number(rv) { Ok(n) => n, Err(e) => return e };
242 let result = match op {
243 BinaryOp::Add => ln + rn,
244 BinaryOp::Sub => ln - rn,
245 BinaryOp::Mul => ln * rn,
246 BinaryOp::Div => {
247 if rn == 0.0 {
248 return Value::Error(ErrorKind::DivByZero);
249 }
250 ln / rn
251 }
252 BinaryOp::Pow => libm::pow(ln, rn),
253 _ => unreachable!(),
255 };
256 if !result.is_finite() {
257 return Value::Error(ErrorKind::Num);
258 }
259 if date_typed {
260 Value::Date(result)
261 } else {
262 Value::Number(result)
263 }
264 }
265
266 BinaryOp::Concat => {
268 let ls = match to_string_val(lv) { Ok(s) => s, Err(e) => return e };
269 let rs = match to_string_val(rv) { Ok(s) => s, Err(e) => return e };
270 Value::Text(ls + &rs)
271 }
272
273 BinaryOp::Eq | BinaryOp::Ne
275 | BinaryOp::Lt | BinaryOp::Gt
276 | BinaryOp::Le | BinaryOp::Ge => {
277 if let Value::Error(_) = &lv { return lv; }
279 if let Value::Error(_) = &rv { return rv; }
280 if matches!(&lv, Value::Zoned(_)) ^ matches!(&rv, Value::Zoned(_)) {
283 return Value::Error(ErrorKind::Value);
284 }
285
286 let result = compare_values(op, &lv, &rv);
287 Value::Bool(result)
288 }
289 }
290}
291
292fn compare_values(op: &BinaryOp, lv: &Value, rv: &Value) -> bool {
294 match (lv, rv) {
295 (Value::Number(a), Value::Number(b)) => apply_cmp(op, a.partial_cmp(b)),
296 (Value::Date(a), Value::Date(b)) => apply_cmp(op, a.partial_cmp(b)),
297 (Value::Date(a), Value::Number(b)) => apply_cmp(op, a.partial_cmp(b)),
298 (Value::Number(a), Value::Date(b)) => apply_cmp(op, a.partial_cmp(b)),
299 (Value::Zoned(a), Value::Zoned(b)) => apply_cmp(op, Some(a.utc_nanos.cmp(&b.utc_nanos))),
302 (Value::Text(a), Value::Text(b)) => apply_cmp(op, Some(a.cmp(b))),
303 (Value::Bool(a), Value::Bool(b)) => apply_cmp(op, Some(a.cmp(b))),
304 (Value::Empty, Value::Empty) => apply_cmp(op, Some(std::cmp::Ordering::Equal)),
305 (Value::Empty, Value::Number(b)) => apply_cmp(op, 0.0f64.partial_cmp(b)),
307 (Value::Number(a), Value::Empty) => apply_cmp(op, a.partial_cmp(&0.0f64)),
308 _ => {
310 let lr = type_rank(lv);
311 let rr = type_rank(rv);
312 match op {
313 BinaryOp::Eq => false,
314 BinaryOp::Ne => true,
315 BinaryOp::Lt => lr < rr,
316 BinaryOp::Gt => lr > rr,
317 BinaryOp::Le => lr <= rr,
318 BinaryOp::Ge => lr >= rr,
319 _ => unreachable!(),
321 }
322 }
323 }
324}
325
326fn apply_cmp(op: &BinaryOp, ord: Option<std::cmp::Ordering>) -> bool {
327 match ord {
328 None => false,
331 Some(o) => match op {
332 BinaryOp::Eq => o.is_eq(),
333 BinaryOp::Ne => o.is_ne(),
334 BinaryOp::Lt => o.is_lt(),
335 BinaryOp::Gt => o.is_gt(),
336 BinaryOp::Le => o.is_le(),
337 BinaryOp::Ge => o.is_ge(),
338 _ => unreachable!(),
340 },
341 }
342}
343
344#[cfg(test)]
346mod tests;