Skip to main content

zen_expression/
expression.rs

1use crate::compiler::Opcode;
2use crate::vm::VM;
3use crate::{IsolateError, Variable};
4use std::marker::PhantomData;
5use std::sync::Arc;
6
7#[derive(Debug, Clone)]
8pub struct Standard;
9
10#[derive(Debug, Clone)]
11pub struct Unary;
12
13#[derive(Debug, Clone, Eq, PartialEq, Hash)]
14pub enum ExpressionKind {
15    Standard,
16    Unary,
17}
18
19#[derive(Clone, Debug, Eq, PartialEq)]
20pub struct OpcodeCache {
21    pub standard: ahash::HashMap<Arc<str>, Arc<[Opcode]>>,
22    pub unary: ahash::HashMap<Arc<str>, Arc<[Opcode]>>,
23}
24
25impl OpcodeCache {
26    pub fn new() -> Self {
27        Self {
28            standard: Default::default(),
29            unary: Default::default(),
30        }
31    }
32}
33
34/// Compiled expression
35#[derive(Debug, Clone)]
36pub struct Expression<Kind> {
37    bytecode: Arc<[Opcode]>,
38    _marker: PhantomData<Kind>,
39}
40
41impl<Kind> Expression<Kind> {
42    pub fn bytecode(&self) -> &Arc<[Opcode]> {
43        &self.bytecode
44    }
45}
46
47impl Expression<Standard> {
48    pub fn new_standard(bytecode: Arc<[Opcode]>) -> Self {
49        Expression {
50            bytecode,
51            _marker: PhantomData,
52        }
53    }
54
55    pub fn kind(&self) -> ExpressionKind {
56        ExpressionKind::Standard
57    }
58
59    pub fn evaluate(&self, context: Variable) -> Result<Variable, IsolateError> {
60        let mut vm = VM::new();
61        self.evaluate_with(context, &mut vm)
62    }
63
64    pub fn evaluate_with(&self, context: Variable, vm: &mut VM) -> Result<Variable, IsolateError> {
65        let output = vm.run(self.bytecode.as_ref(), context)?;
66        Ok(output)
67    }
68}
69
70impl Expression<Unary> {
71    pub fn new_unary(bytecode: Arc<[Opcode]>) -> Self {
72        Expression {
73            bytecode,
74            _marker: PhantomData,
75        }
76    }
77
78    pub fn kind(&self) -> ExpressionKind {
79        ExpressionKind::Unary
80    }
81
82    pub fn evaluate(&self, context: Variable) -> Result<bool, IsolateError> {
83        let mut vm = VM::new();
84        self.evaluate_with(context, &mut vm)
85    }
86
87    pub fn evaluate_with(&self, context: Variable, vm: &mut VM) -> Result<bool, IsolateError> {
88        let Some(context_object_ref) = context.as_object() else {
89            return Err(IsolateError::MissingContextReference);
90        };
91
92        let context_object = context_object_ref.borrow();
93        if !context_object.contains_key("$") {
94            return Err(IsolateError::MissingContextReference);
95        }
96
97        let output = vm
98            .run(self.bytecode.as_ref(), context)?
99            .as_bool()
100            .ok_or_else(|| IsolateError::ValueCastError)?;
101        Ok(output)
102    }
103}