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)]
14pub enum ExpressionKind {
15    Standard,
16    Unary,
17}
18
19/// Compiled expression
20#[derive(Debug, Clone)]
21pub struct Expression<Kind> {
22    bytecode: Arc<Vec<Opcode>>,
23    _marker: PhantomData<Kind>,
24}
25
26impl<Kind> Expression<Kind> {
27    pub fn bytecode(&self) -> &Arc<Vec<Opcode>> {
28        &self.bytecode
29    }
30}
31
32impl Expression<Standard> {
33    pub fn new_standard(bytecode: Arc<Vec<Opcode>>) -> Self {
34        Expression {
35            bytecode,
36            _marker: PhantomData,
37        }
38    }
39
40    pub fn kind(&self) -> ExpressionKind {
41        ExpressionKind::Standard
42    }
43
44    pub fn evaluate(&self, context: Variable) -> Result<Variable, IsolateError> {
45        let mut vm = VM::new();
46        self.evaluate_with(context, &mut vm)
47    }
48
49    pub fn evaluate_with(&self, context: Variable, vm: &mut VM) -> Result<Variable, IsolateError> {
50        let output = vm.run(self.bytecode.as_slice(), context)?;
51        Ok(output)
52    }
53}
54
55impl Expression<Unary> {
56    pub fn new_unary(bytecode: Arc<Vec<Opcode>>) -> Self {
57        Expression {
58            bytecode,
59            _marker: PhantomData,
60        }
61    }
62
63    pub fn kind(&self) -> ExpressionKind {
64        ExpressionKind::Unary
65    }
66
67    pub fn evaluate(&self, context: Variable) -> Result<bool, IsolateError> {
68        let mut vm = VM::new();
69        self.evaluate_with(context, &mut vm)
70    }
71
72    pub fn evaluate_with(&self, context: Variable, vm: &mut VM) -> Result<bool, IsolateError> {
73        let Some(context_object_ref) = context.as_object() else {
74            return Err(IsolateError::MissingContextReference);
75        };
76
77        let context_object = context_object_ref.borrow();
78        if !context_object.contains_key("$") {
79            return Err(IsolateError::MissingContextReference);
80        }
81
82        let output = vm
83            .run(self.bytecode.as_slice(), context)?
84            .as_bool()
85            .ok_or_else(|| IsolateError::ValueCastError)?;
86        Ok(output)
87    }
88}