wayver's git archive


an obsidian renderer
git clone https://git.wayver.dev/sable

sable-bases/src/eval.rs@337ba67f65eaa17b44e371af7c0f0c761d6aa914

raw
Date Commit Message Author Files + -
2026-02-23 01:55 initial mvp wayverd 139 17808 0
...

1#![allow(
2    clippy::todo,
3    clippy::cast_precision_loss,
4    clippy::unnecessary_cast,
5    trivial_casts
6)]
7
8use std::{borrow::Cow, collections::BTreeMap};
9
10use camino::Utf8Path;
11use chumsky::span::SimpleSpan;
12use jiff::{SignedDuration, civil::DateTime};
13
14use crate::filter::ast::{BinOp, Expr, UnOp};
15
16macro_rules! bast {
17    ($name:ident: f64 ) => {
18        if $name { 1.0 } else { 0.0 }
19    };
20    ($name:ident: i64 ) => {
21        if $name { 1 } else { 0 }
22    };
23}
24
25#[derive(Debug, PartialEq)]
26struct TypeError {
27    kind: ErrorKind,
28    pos: SimpleSpan,
29}
30
31#[derive(Debug, PartialEq)]
32enum ErrorKind {}
33
34#[derive(Debug, PartialEq)]
35struct Array<'r> {
36    scope: Vec<ScopeEntry<'r>>,
37}
38
39impl<'r> Array<'r> {
40    fn push<E: Into<ScopeEntry<'r>>>(&mut self, entry: E) {
41        self.scope.push(entry.into());
42    }
43}
44
45impl<'r> From<Array<'r>> for ScopeEntry<'r> {
46    fn from(value: Array<'r>) -> Self {
47        Self::Array(value)
48    }
49}
50
51#[derive(Debug, PartialEq)]
52struct Object<'r> {
53    scope: BTreeMap<&'r str, ScopeEntry<'r>>,
54}
55
56impl<'r> Object<'r> {
57    fn insert<E: Into<ScopeEntry<'r>>>(&mut self, ident: &'r str, entry: E) {
58        self.scope.insert(ident, entry.into());
59    }
60}
61
62impl<'r> From<Object<'r>> for ScopeEntry<'r> {
63    fn from(value: Object<'r>) -> Self {
64        Self::Object(value)
65    }
66}
67
68type Date = DateTime;
69type Duration = SignedDuration;
70
71#[derive(Debug, PartialEq)]
72struct File<'r> {
73    path: &'r Utf8Path,
74    creation_time: DateTime,
75    mondified_time: DateTime,
76}
77
78#[derive(Debug, PartialEq)]
79enum Value<'r, 'vm> {
80    Null,
81    Bool(bool),
82    Integer(i64),
83    Decimal(f64),
84    String(Cow<'r, str>),
85    Array(&'vm Array<'r>),
86    Object(&'vm Object<'r>),
87    Date(Date),
88    Duration(Duration),
89    Link(),
90    File(),
91}
92
93impl<'r, 'vm> Value<'r, 'vm> {
94    #[must_use]
95    const fn is_bool(&self) -> bool {
96        matches!(self, Self::Bool(..))
97    }
98
99    #[must_use]
100    const fn is_integer(&self) -> bool {
101        matches!(self, Self::Integer(..))
102    }
103
104    #[must_use]
105    const fn is_decimal(&self) -> bool {
106        matches!(self, Self::Decimal(..))
107    }
108
109    fn as_string(&self) -> Result<Cow<'r, str>, TypeError> {
110        if let Value::String(str) = self {
111            return Ok(str.clone());
112        }
113
114        todo!()
115    }
116
117    fn into_bool(self) -> Result<Self, TypeError> {
118        match self {
119            Value::Null => todo!(),
120            Value::Bool(value) => Ok(Value::Bool(value)),
121            Value::Integer(value) => Ok(Value::Bool(value != 0)),
122            Value::Decimal(value) => Ok(Value::Bool(value != 0.0)),
123            _ => todo!(),
124        }
125    }
126
127    fn into_integer(self) -> Result<Self, TypeError> {
128        match self {
129            Value::Null => todo!(),
130            Value::Bool(value) => Ok(Value::Integer(bast!(value: i64))),
131            Value::Integer(value) => Ok(Value::Integer(value)),
132            Value::Decimal(value) => Ok(Value::Integer(value.round() as i64)),
133            _ => todo!(),
134        }
135    }
136
137    fn into_decimal(self) -> Result<Self, TypeError> {
138        match self {
139            Value::Null => todo!(),
140            Value::Bool(value) => Ok(Value::Decimal(bast!(value: f64))),
141            Value::Integer(value) => Ok(Value::Decimal(value as f64)),
142            Value::Decimal(value) => Ok(Value::Decimal(value)),
143            _ => todo!(),
144        }
145    }
146
147    fn into_string(self) -> Result<Self, TypeError> {
148        match self {
149            Value::Null => todo!(),
150            Value::Bool(value) => Ok(Value::Bool(value)),
151            Value::Integer(value) => Ok(Value::String(Cow::from(format!("{value}")))),
152            Value::Decimal(value) => Ok(Value::String(Cow::from(format!("{value}")))),
153            Value::String(value) => Ok(Value::String(value)),
154            _ => todo!(),
155        }
156    }
157}
158
159#[derive(Debug, PartialEq)]
160enum ScopeEntry<'r> {
161    Bool(bool),
162    Integer(i64),
163    Decimal(f64),
164    String(&'r str),
165    Array(Array<'r>),
166    Object(Object<'r>),
167    Function(),
168}
169
170struct Vm<'r> {
171    scope: BTreeMap<&'r str, ScopeEntry<'r>>,
172    fallback: Option<&'r str>,
173}
174
175impl<'r> Vm<'r> {
176    const fn new() -> Self {
177        Self {
178            scope: BTreeMap::new(),
179            fallback: None,
180        }
181    }
182
183    fn add_scope<E: Into<ScopeEntry<'r>>>(&mut self, ident: &'r str, entry: E) {
184        self.scope.insert(ident, entry.into());
185    }
186
187    const fn set_fallback(&mut self, ident: &'r str) {
188        self.fallback = Some(ident);
189    }
190
191    fn eval<'vm, 'src: 'r>(&'vm self, expr: &Expr<'src>) -> Result<Value<'r, 'vm>, TypeError> {
192        match expr {
193            Expr::Ident(ident) => {
194                let entry = match (self.scope.get(ident.0.as_ref()), self.fallback.as_ref()) {
195                    (Some(entry), _) => Some(entry),
196                    (None, Some(fallback)) => self.scope.get(fallback),
197                    (None, None) => return Ok(Value::Null),
198                };
199
200                if let Some(entry) = entry {
201                    return match entry {
202                        ScopeEntry::Bool(value) => Ok(Value::Bool(*value)),
203                        ScopeEntry::Integer(value) => Ok(Value::Integer(*value)),
204                        ScopeEntry::Decimal(value) => Ok(Value::Decimal(*value)),
205                        ScopeEntry::String(value) => Ok(Value::String(Cow::from(*value))),
206                        ScopeEntry::Array(value) => Ok(Value::Array(value)),
207                        ScopeEntry::Object(value) => Ok(Value::Object(value)),
208                        ScopeEntry::Function() => todo!(),
209                    };
210                }
211
212                Ok(Value::Null)
213            }
214            Expr::Bool(value) => Ok(Value::Bool(*value)),
215            Expr::Integer(value) => Ok(Value::Integer(*value)),
216            Expr::Decimal(value) => Ok(Value::Decimal(*value)),
217            Expr::String(value) => Ok(Value::String(value.clone())),
218            Expr::Function(ident, params) => {
219                let ident = self.eval(&ident.inner)?;
220                let params = params
221                    .inner
222                    .iter()
223                    .map(|param| self.eval(&param.inner))
224                    .collect::<Result<Vec<_>, _>>()?;
225
226                todo!()
227            }
228            Expr::Method(object, ident, params) => {
229                let object = self.eval(&object.inner)?;
230                let params = params
231                    .inner
232                    .iter()
233                    .map(|param| self.eval(&param.inner))
234                    .collect::<Result<Vec<_>, _>>()?;
235
236                match object {
237                    Value::Array(object) => todo!(),
238                    Value::Object(object) => todo!(),
239                    _ => todo!(),
240                }
241            }
242            Expr::Member(object, ident) => {
243                let object = self.eval(&object.inner)?;
244
245                match object {
246                    Value::Array(object) => todo!(),
247                    Value::Object(object) => todo!(),
248                    _ => todo!(),
249                }
250            }
251            Expr::Index(ident, index) => {
252                let ident = self.eval(&ident.inner)?;
253
254                match ident {
255                    Value::Array(object) => todo!(),
256                    Value::Object(object) => todo!(),
257                    _ => todo!(),
258                }
259            }
260            // TODO: this is the worst way to do this, use the cast methods on Value to clean this up
261            Expr::BinOp(op, lhs, rhs) => {
262                let lhs = self.eval(&lhs.inner)?;
263                let rhs = self.eval(&rhs.inner)?;
264
265                match op.inner {
266                    BinOp::Add => match lhs {
267                        Value::Bool(lhs) => match rhs {
268                            Value::Bool(rhs) => {
269                                Ok(Value::Integer(bast!(lhs: i64) + bast!(rhs: i64)))
270                            }
271                            Value::Integer(rhs) => Ok(Value::Integer(bast!(lhs: i64) + rhs)),
272                            Value::Decimal(rhs) => Ok(Value::Decimal(bast!(lhs: f64) + rhs)),
273                            _ => todo!(),
274                        },
275                        Value::Integer(lhs) => match rhs {
276                            Value::Bool(rhs) => Ok(Value::Integer(lhs + bast!(rhs: i64))),
277                            Value::Integer(rhs) => Ok(Value::Integer(lhs + rhs)),
278                            Value::Decimal(rhs) => Ok(Value::Decimal(lhs as f64 + rhs)),
279                            _ => todo!(),
280                        },
281                        Value::Decimal(lhs) => match rhs {
282                            Value::Bool(rhs) => Ok(Value::Decimal(lhs + bast!(rhs: f64))),
283                            Value::Integer(rhs) => Ok(Value::Decimal(lhs + rhs as f64)),
284                            Value::Decimal(rhs) => Ok(Value::Decimal(lhs + rhs)),
285                            _ => todo!(),
286                        },
287                        Value::String(lhs) => match rhs {
288                            Value::Bool(rhs) => Ok(Value::String(Cow::from(format!("{lhs}{rhs}")))),
289                            Value::Integer(rhs) => {
290                                Ok(Value::String(Cow::from(format!("{lhs}{rhs}"))))
291                            }
292                            Value::Decimal(rhs) => {
293                                Ok(Value::String(Cow::from(format!("{lhs}{rhs}"))))
294                            }
295                            Value::String(rhs) => {
296                                Ok(Value::String(Cow::from(format!("{lhs}{rhs}"))))
297                            }
298                            _ => todo!(),
299                        },
300                        _ => todo!(),
301                    },
302                    BinOp::Sub => match lhs {
303                        Value::Bool(lhs) => match rhs {
304                            Value::Bool(rhs) => {
305                                Ok(Value::Integer(bast!(lhs: i64) - bast!(rhs: i64)))
306                            }
307                            Value::Integer(rhs) => Ok(Value::Integer(bast!(lhs: i64) - rhs)),
308                            Value::Decimal(rhs) => Ok(Value::Decimal(bast!(lhs: f64) - rhs)),
309                            _ => todo!(),
310                        },
311                        Value::Integer(lhs) => match rhs {
312                            Value::Bool(rhs) => Ok(Value::Integer(lhs - bast!(rhs: i64))),
313                            Value::Integer(rhs) => Ok(Value::Integer(lhs - rhs)),
314                            Value::Decimal(rhs) => Ok(Value::Decimal(lhs as f64 - rhs)),
315                            _ => todo!(),
316                        },
317                        Value::Decimal(lhs) => match rhs {
318                            Value::Bool(rhs) => Ok(Value::Decimal(lhs - bast!(rhs: f64))),
319                            Value::Integer(rhs) => Ok(Value::Decimal(lhs - rhs as f64)),
320                            Value::Decimal(rhs) => Ok(Value::Decimal(lhs - rhs)),
321                            _ => todo!(),
322                        },
323                        _ => todo!(),
324                    },
325                    BinOp::Mul => match lhs {
326                        Value::Bool(lhs) => match rhs {
327                            Value::Bool(rhs) => {
328                                Ok(Value::Integer(bast!(lhs: i64) * bast!(rhs: i64)))
329                            }
330                            Value::Integer(rhs) => Ok(Value::Integer(bast!(lhs: i64) * rhs)),
331                            Value::Decimal(rhs) => Ok(Value::Decimal(bast!(lhs: f64) * rhs)),
332                            _ => todo!(),
333                        },
334                        Value::Integer(lhs) => match rhs {
335                            Value::Bool(rhs) => Ok(Value::Integer(lhs * bast!(rhs: i64))),
336                            Value::Integer(rhs) => Ok(Value::Integer(lhs * rhs)),
337                            Value::Decimal(rhs) => Ok(Value::Decimal(lhs as f64 * rhs)),
338                            _ => todo!(),
339                        },
340                        Value::Decimal(lhs) => match rhs {
341                            Value::Bool(rhs) => Ok(Value::Decimal(lhs * bast!(rhs: f64))),
342                            Value::Integer(rhs) => Ok(Value::Decimal(lhs * rhs as f64)),
343                            Value::Decimal(rhs) => Ok(Value::Decimal(lhs * rhs)),
344                            _ => todo!(),
345                        },
346                        _ => todo!(),
347                    },
348                    BinOp::Div => match lhs {
349                        Value::Bool(lhs) => match rhs {
350                            Value::Bool(rhs) => {
351                                Ok(Value::Integer(bast!(lhs: i64) / bast!(rhs: i64)))
352                            }
353                            Value::Integer(rhs) => Ok(Value::Integer(bast!(lhs: i64) / rhs)),
354                            Value::Decimal(rhs) => Ok(Value::Decimal(bast!(lhs: f64) / rhs)),
355                            _ => todo!(),
356                        },
357                        Value::Integer(lhs) => match rhs {
358                            Value::Bool(rhs) => Ok(Value::Integer(lhs / bast!(rhs: i64))),
359                            Value::Integer(rhs) => Ok(Value::Integer(lhs / rhs)),
360                            Value::Decimal(rhs) => Ok(Value::Decimal(lhs as f64 / rhs)),
361                            _ => todo!(),
362                        },
363                        Value::Decimal(lhs) => match rhs {
364                            Value::Bool(rhs) => Ok(Value::Decimal(lhs / bast!(rhs: f64))),
365                            Value::Integer(rhs) => Ok(Value::Decimal(lhs / rhs as f64)),
366                            Value::Decimal(rhs) => Ok(Value::Decimal(lhs / rhs)),
367                            _ => todo!(),
368                        },
369                        _ => todo!(),
370                    },
371                    BinOp::Mod => match lhs {
372                        Value::Bool(lhs) => match rhs {
373                            Value::Bool(rhs) => {
374                                Ok(Value::Integer(bast!(lhs: i64) % bast!(rhs: i64)))
375                            }
376                            Value::Integer(rhs) => Ok(Value::Integer(bast!(lhs: i64) % rhs)),
377                            Value::Decimal(rhs) => Ok(Value::Decimal(bast!(lhs: f64) % rhs)),
378                            _ => todo!(),
379                        },
380                        Value::Integer(lhs) => match rhs {
381                            Value::Bool(rhs) => Ok(Value::Integer(lhs % bast!(rhs: i64))),
382                            Value::Integer(rhs) => Ok(Value::Integer(lhs % rhs)),
383                            Value::Decimal(rhs) => Ok(Value::Decimal(lhs as f64 % rhs)),
384                            _ => todo!(),
385                        },
386                        Value::Decimal(lhs) => match rhs {
387                            Value::Bool(rhs) => Ok(Value::Decimal(lhs % bast!(rhs: f64))),
388                            Value::Integer(rhs) => Ok(Value::Decimal(lhs % rhs as f64)),
389                            Value::Decimal(rhs) => Ok(Value::Decimal(lhs % rhs)),
390                            _ => todo!(),
391                        },
392                        _ => todo!(),
393                    },
394                    BinOp::Equal => match lhs {
395                        Value::Bool(lhs) => match rhs {
396                            Value::Bool(rhs) => Ok(Value::Bool(lhs == rhs)),
397                            Value::Integer(rhs) => Ok(Value::Bool(bast!(lhs: i64) == rhs)),
398                            Value::Decimal(rhs) => Ok(Value::Bool(bast!(lhs: f64) == rhs)),
399                            _ => todo!(),
400                        },
401                        Value::Integer(lhs) => match rhs {
402                            Value::Bool(rhs) => Ok(Value::Bool(lhs == bast!(rhs: i64))),
403                            Value::Integer(rhs) => Ok(Value::Bool(lhs == rhs)),
404                            Value::Decimal(rhs) => Ok(Value::Bool(lhs as f64 == rhs)),
405                            _ => todo!(),
406                        },
407                        Value::Decimal(lhs) => match rhs {
408                            Value::Bool(rhs) => Ok(Value::Bool(lhs == bast!(rhs: f64))),
409                            Value::Integer(rhs) => Ok(Value::Bool(lhs == rhs as f64)),
410                            Value::Decimal(rhs) => Ok(Value::Bool(lhs == rhs)),
411                            _ => todo!(),
412                        },
413                        _ => todo!(),
414                    },
415                    BinOp::NotEqual => match lhs {
416                        Value::Bool(lhs) => match rhs {
417                            Value::Bool(rhs) => Ok(Value::Bool(lhs != rhs)),
418                            Value::Integer(rhs) => Ok(Value::Bool(bast!(lhs: i64) != rhs)),
419                            Value::Decimal(rhs) => Ok(Value::Bool(bast!(lhs: f64) != rhs)),
420                            _ => todo!(),
421                        },
422                        Value::Integer(lhs) => match rhs {
423                            Value::Bool(rhs) => Ok(Value::Bool(lhs != bast!(rhs: i64))),
424                            Value::Integer(rhs) => Ok(Value::Bool(lhs != rhs)),
425                            Value::Decimal(rhs) => Ok(Value::Bool(lhs as f64 != rhs)),
426                            _ => todo!(),
427                        },
428                        Value::Decimal(lhs) => match rhs {
429                            Value::Bool(rhs) => Ok(Value::Bool(lhs != bast!(rhs: f64))),
430                            Value::Integer(rhs) => Ok(Value::Bool(lhs != rhs as f64)),
431                            Value::Decimal(rhs) => Ok(Value::Bool(lhs != rhs)),
432                            _ => todo!(),
433                        },
434                        _ => todo!(),
435                    },
436                    BinOp::GreaterThan => match lhs {
437                        Value::Bool(lhs) => match rhs {
438                            Value::Bool(rhs) => Ok(Value::Bool(lhs > rhs)),
439                            Value::Integer(rhs) => Ok(Value::Bool(bast!(lhs: i64) > rhs)),
440                            Value::Decimal(rhs) => Ok(Value::Bool(bast!(lhs: f64) > rhs)),
441                            _ => todo!(),
442                        },
443                        Value::Integer(lhs) => match rhs {
444                            Value::Bool(rhs) => Ok(Value::Bool(lhs > bast!(rhs: i64))),
445                            Value::Integer(rhs) => Ok(Value::Bool(lhs > rhs)),
446                            Value::Decimal(rhs) => Ok(Value::Bool((lhs as f64) > rhs)),
447                            _ => todo!(),
448                        },
449                        Value::Decimal(lhs) => match rhs {
450                            Value::Bool(rhs) => Ok(Value::Bool(lhs > bast!(rhs: f64))),
451                            Value::Integer(rhs) => Ok(Value::Bool(lhs > rhs as f64)),
452                            Value::Decimal(rhs) => Ok(Value::Bool(lhs > rhs)),
453                            _ => todo!(),
454                        },
455                        _ => todo!(),
456                    },
457                    BinOp::LessThan => match lhs {
458                        Value::Bool(lhs) => match rhs {
459                            Value::Bool(rhs) => Ok(Value::Bool(lhs < rhs)),
460                            Value::Integer(rhs) => Ok(Value::Bool(bast!(lhs: i64) < rhs)),
461                            Value::Decimal(rhs) => Ok(Value::Bool(bast!(lhs: f64) < rhs)),
462                            _ => todo!(),
463                        },
464                        Value::Integer(lhs) => match rhs {
465                            Value::Bool(rhs) => Ok(Value::Bool(lhs < bast!(rhs: i64))),
466                            Value::Integer(rhs) => Ok(Value::Bool(lhs < rhs)),
467                            Value::Decimal(rhs) => Ok(Value::Bool((lhs as f64) < rhs)),
468                            _ => todo!(),
469                        },
470                        Value::Decimal(lhs) => match rhs {
471                            Value::Bool(rhs) => Ok(Value::Bool(lhs < bast!(rhs: f64))),
472                            Value::Integer(rhs) => Ok(Value::Bool(lhs < rhs as f64)),
473                            Value::Decimal(rhs) => Ok(Value::Bool(lhs < rhs)),
474                            _ => todo!(),
475                        },
476                        _ => todo!(),
477                    },
478                    BinOp::GreaterEqual => match lhs {
479                        Value::Bool(lhs) => match rhs {
480                            Value::Bool(rhs) => Ok(Value::Bool(lhs >= rhs)),
481                            Value::Integer(rhs) => Ok(Value::Bool(bast!(lhs: i64) >= rhs)),
482                            Value::Decimal(rhs) => Ok(Value::Bool(bast!(lhs: f64) >= rhs)),
483                            _ => todo!(),
484                        },
485                        Value::Integer(lhs) => match rhs {
486                            Value::Bool(rhs) => Ok(Value::Bool(lhs >= bast!(rhs: i64))),
487                            Value::Integer(rhs) => Ok(Value::Bool(lhs >= rhs)),
488                            Value::Decimal(rhs) => Ok(Value::Bool((lhs as f64) >= rhs)),
489                            _ => todo!(),
490                        },
491                        Value::Decimal(lhs) => match rhs {
492                            Value::Bool(rhs) => Ok(Value::Bool(lhs >= bast!(rhs: f64))),
493                            Value::Integer(rhs) => Ok(Value::Bool(lhs >= rhs as f64)),
494                            Value::Decimal(rhs) => Ok(Value::Bool(lhs >= rhs)),
495                            _ => todo!(),
496                        },
497                        _ => todo!(),
498                    },
499                    BinOp::LessEqual => match lhs {
500                        Value::Bool(lhs) => match rhs {
501                            Value::Bool(rhs) => Ok(Value::Bool(lhs <= rhs)),
502                            Value::Integer(rhs) => Ok(Value::Bool(bast!(lhs: i64) <= rhs)),
503                            Value::Decimal(rhs) => Ok(Value::Bool(bast!(lhs: f64) <= rhs)),
504                            _ => todo!(),
505                        },
506                        Value::Integer(lhs) => match rhs {
507                            Value::Bool(rhs) => Ok(Value::Bool(lhs <= bast!(rhs: i64))),
508                            Value::Integer(rhs) => Ok(Value::Bool(lhs <= rhs)),
509                            Value::Decimal(rhs) => Ok(Value::Bool(lhs as f64 <= rhs)),
510                            _ => todo!(),
511                        },
512                        Value::Decimal(lhs) => match rhs {
513                            Value::Bool(rhs) => Ok(Value::Bool(lhs <= bast!(rhs: f64))),
514                            Value::Integer(rhs) => Ok(Value::Bool(lhs <= rhs as f64)),
515                            Value::Decimal(rhs) => Ok(Value::Bool(lhs <= rhs)),
516                            _ => todo!(),
517                        },
518                        _ => todo!(),
519                    },
520                    BinOp::And => match lhs {
521                        Value::Bool(lhs) => match rhs {
522                            Value::Bool(rhs) => {
523                                Ok(Value::Integer(bast!(lhs: i64) & bast!(rhs: i64)))
524                            }
525                            Value::Integer(rhs) => Ok(Value::Integer(bast!(lhs: i64) & rhs)),
526                            _ => todo!(),
527                        },
528                        Value::Integer(lhs) => match rhs {
529                            Value::Bool(rhs) => Ok(Value::Integer(lhs & bast!(rhs: i64))),
530                            Value::Integer(rhs) => Ok(Value::Integer(lhs & rhs)),
531                            _ => todo!(),
532                        },
533                        _ => todo!(),
534                    },
535                    BinOp::Or => match lhs {
536                        Value::Bool(lhs) => match rhs {
537                            Value::Bool(rhs) => {
538                                Ok(Value::Integer(bast!(lhs: i64) | bast!(rhs: i64)))
539                            }
540                            Value::Integer(rhs) => Ok(Value::Integer(bast!(lhs: i64) | rhs)),
541                            _ => todo!(),
542                        },
543                        Value::Integer(lhs) => match rhs {
544                            Value::Bool(rhs) => Ok(Value::Integer(lhs | bast!(rhs: i64))),
545                            Value::Integer(rhs) => Ok(Value::Integer(lhs | rhs)),
546                            _ => todo!(),
547                        },
548                        _ => todo!(),
549                    },
550                }
551            }
552            Expr::UnOp(op, expr) => {
553                let value = self.eval(&expr.inner)?;
554
555                match op.inner {
556                    UnOp::Not => match value {
557                        Value::Bool(value) => Ok(Value::Bool(!value)),
558                        Value::Integer(value) => Ok(Value::Bool(value == 0)),
559                        Value::Decimal(value) => Ok(Value::Bool(value == 0.0)),
560                        _ => todo!(),
561                    },
562                    UnOp::Plus => todo!(),
563                    UnOp::Neg => match value {
564                        Value::Bool(value) => Ok(Value::Integer(-bast!(value: i64))),
565                        Value::Integer(value) => Ok(Value::Integer(-value)),
566                        Value::Decimal(value) => Ok(Value::Decimal(-value)),
567                        _ => todo!(),
568                    },
569                }
570            }
571            Expr::Group(expr) => self.eval(&expr.inner),
572        }
573    }
574}
575
576#[cfg(test)]
577mod tests {
578    use chumsky::span::WrappingSpan as _;
579
580    use crate::filter::ast::Ident;
581
582    use super::*;
583
584    fn binop<'src>(op: BinOp, lhs: Expr<'src>, rhs: Expr<'src>) -> Expr<'src> {
585        Expr::BinOp(
586            SimpleSpan::from(0..1).make_wrapped(op),
587            Box::new(SimpleSpan::from(0..1).make_wrapped(lhs)),
588            Box::new(SimpleSpan::from(0..1).make_wrapped(rhs)),
589        )
590    }
591
592    fn unop(op: UnOp, lhs: Expr<'_>) -> Expr<'_> {
593        Expr::UnOp(
594            SimpleSpan::from(0..1).make_wrapped(op),
595            Box::new(SimpleSpan::from(0..1).make_wrapped(lhs)),
596        )
597    }
598
599    #[test]
600    fn bool() {
601        let mut vm = Vm::new();
602
603        vm.add_scope("bool_false", ScopeEntry::Bool(false));
604        vm.add_scope("bool_true", ScopeEntry::Bool(true));
605
606        assert_eq!(Ok(Value::Bool(false)), vm.eval(&Expr::Bool(false)));
607        assert_eq!(Ok(Value::Bool(true)), vm.eval(&Expr::Bool(true)));
608
609        assert_eq!(
610            Ok(Value::Bool(true)),
611            vm.eval(&unop(UnOp::Not, Expr::Bool(false)))
612        );
613        assert_eq!(
614            Ok(Value::Bool(false)),
615            vm.eval(&unop(UnOp::Not, Expr::Bool(true)))
616        );
617
618        assert_eq!(
619            Ok(Value::Bool(false)),
620            vm.eval(&Expr::Ident(Ident("bool_false".into())))
621        );
622        assert_eq!(
623            Ok(Value::Bool(true)),
624            vm.eval(&Expr::Ident(Ident("bool_true".into())))
625        );
626
627        assert_eq!(
628            Ok(Value::Bool(true)),
629            vm.eval(&unop(UnOp::Not, Expr::Ident(Ident("bool_false".into()))))
630        );
631        assert_eq!(
632            Ok(Value::Bool(false)),
633            vm.eval(&unop(UnOp::Not, Expr::Ident(Ident("bool_true".into()))))
634        );
635    }
636
637    #[test]
638    fn integer() {
639        let mut vm = Vm::new();
640
641        vm.add_scope("integer_zero", ScopeEntry::Integer(0));
642        vm.add_scope("integer_one", ScopeEntry::Integer(1));
643
644        assert_eq!(Ok(Value::Integer(0)), vm.eval(&Expr::Integer(0)));
645        assert_eq!(Ok(Value::Integer(1)), vm.eval(&Expr::Integer(1)));
646
647        assert_eq!(
648            Ok(Value::Integer(2)),
649            vm.eval(&binop(BinOp::Add, Expr::Integer(1), Expr::Integer(1)))
650        );
651        assert_eq!(
652            Ok(Value::Integer(0)),
653            vm.eval(&binop(BinOp::Sub, Expr::Integer(1), Expr::Integer(1)))
654        );
655
656        assert_eq!(
657            Ok(Value::Integer(2)),
658            vm.eval(&binop(
659                BinOp::Add,
660                Expr::Ident(Ident("integer_one".into())),
661                Expr::Ident(Ident("integer_one".into()))
662            ))
663        );
664        assert_eq!(
665            Ok(Value::Integer(0)),
666            vm.eval(&binop(
667                BinOp::Sub,
668                Expr::Ident(Ident("integer_one".into())),
669                Expr::Ident(Ident("integer_one".into()))
670            ))
671        );
672    }
673
674    #[test]
675    fn decimal() {
676        let mut vm = Vm::new();
677
678        vm.add_scope("decimal_zero", ScopeEntry::Decimal(0.0));
679        vm.add_scope("decimal_one", ScopeEntry::Decimal(1.0));
680
681        assert_eq!(Ok(Value::Decimal(0.0)), vm.eval(&Expr::Decimal(0.0)));
682        assert_eq!(Ok(Value::Decimal(1.0)), vm.eval(&Expr::Decimal(1.0)));
683
684        assert_eq!(
685            Ok(Value::Decimal(2.0)),
686            vm.eval(&binop(BinOp::Add, Expr::Decimal(1.0), Expr::Decimal(1.0)))
687        );
688        assert_eq!(
689            Ok(Value::Decimal(0.0)),
690            vm.eval(&binop(BinOp::Sub, Expr::Decimal(1.0), Expr::Decimal(1.0)))
691        );
692
693        assert_eq!(
694            Ok(Value::Decimal(2.0)),
695            vm.eval(&binop(
696                BinOp::Add,
697                Expr::Ident(Ident("decimal_one".into())),
698                Expr::Ident(Ident("decimal_one".into()))
699            ))
700        );
701        assert_eq!(
702            Ok(Value::Decimal(0.0)),
703            vm.eval(&binop(
704                BinOp::Sub,
705                Expr::Ident(Ident("decimal_one".into())),
706                Expr::Ident(Ident("decimal_one".into()))
707            ))
708        );
709    }
710}
711