Skip to main content

zen_expression/
isolate.rs

1use ahash::HashMap;
2use serde::ser::SerializeMap;
3use serde::{Serialize, Serializer};
4use std::sync::Arc;
5use thiserror::Error;
6
7use crate::compiler::{Compiler, CompilerError, Opcode};
8use crate::expression::{OpcodeCache, Standard, Unary};
9use crate::lexer::{Lexer, LexerError};
10use crate::parser::{Parser, ParserError};
11use crate::scope::Scope;
12use crate::variable::Variable;
13use crate::vm::{VMError, VM};
14use crate::{Expression, ExpressionKind};
15use bumpalo::Bump;
16use zen_types::symbol::Symbol;
17
18/// Isolate is a component that encapsulates an isolated environment for executing expressions.
19///
20/// Rerunning the Isolate allows for efficient memory reuse through an arena allocator.
21/// The arena allocator optimizes memory management by reusing memory blocks for subsequent evaluations,
22/// contributing to improved performance and resource utilization in scenarios where the Isolate is reused multiple times.
23#[derive(Debug)]
24pub struct Isolate {
25    lexer: Lexer,
26    compiler: Compiler,
27    vm: VM,
28
29    bump: Bump,
30
31    scope: Scope,
32    references: HashMap<String, Variable>,
33    cache: Option<Arc<OpcodeCache>>,
34}
35
36impl Isolate {
37    pub fn new() -> Self {
38        Self {
39            lexer: Lexer::new(),
40            compiler: Compiler::new(),
41            vm: VM::new(),
42
43            bump: Bump::new(),
44
45            scope: Scope::default(),
46            references: Default::default(),
47            cache: None,
48        }
49    }
50
51    pub fn with_environment(variable: Variable) -> Self {
52        let mut isolate = Isolate::new();
53        isolate.set_environment(variable);
54
55        isolate
56    }
57
58    pub fn with_cache(mut self, cache: Option<Arc<OpcodeCache>>) -> Self {
59        self.cache = cache;
60        self
61    }
62
63    pub fn set_environment(&mut self, variable: Variable) {
64        self.scope.set_base(variable);
65        self.references.clear();
66    }
67
68    pub fn set_cache(&mut self, cache: Arc<OpcodeCache>) {
69        self.cache = Some(cache);
70    }
71
72    pub fn scope(&self) -> &Scope {
73        &self.scope
74    }
75
76    pub fn set_local(&mut self, name: Symbol, value: Variable) {
77        self.scope.set_local(name, value);
78    }
79
80    pub fn insert_dollar(&mut self, path: &str, value: Variable) {
81        let dollar = match self.scope.local(&Variable::dollar_key()) {
82            Some(existing @ Variable::Object(_)) => existing.shallow_clone(),
83            _ => {
84                let created = Variable::empty_object();
85                self.scope
86                    .set_local(Variable::dollar_key(), created.clone());
87                created
88            }
89        };
90
91        let _ = dollar.dot_insert(path, value);
92    }
93
94    pub fn set_reference(&mut self, reference: &str) -> Result<(), IsolateError> {
95        let reference_value = match self.references.get(reference) {
96            Some(value) => value.clone(),
97            None => {
98                let result = self.run_standard(reference)?;
99                self.references
100                    .insert(reference.to_string(), result.clone());
101                result
102            }
103        };
104
105        self.set_reference_value(reference_value)
106    }
107
108    pub fn set_reference_value(&mut self, value: Variable) -> Result<(), IsolateError> {
109        self.scope.set_local(Variable::dollar_key(), value);
110
111        Ok(())
112    }
113
114    pub fn get_reference(&self, reference: &str) -> Option<Variable> {
115        self.references.get(reference).cloned()
116    }
117
118    fn run_internal(&mut self, source: &str, kind: ExpressionKind) -> Result<(), IsolateError> {
119        self.bump.reset();
120        let bump = &self.bump;
121
122        let tokens = self.lexer.tokenize(bump, source)?;
123
124        let base_parser = Parser::try_new(&tokens, bump)?;
125        let parser_result = match kind {
126            ExpressionKind::Unary => base_parser.unary().parse(),
127            ExpressionKind::Standard => base_parser.standard().parse(),
128        };
129
130        parser_result.error()?;
131
132        self.compiler.compile(parser_result.root)?;
133
134        Ok(())
135    }
136
137    pub fn compile_standard(&mut self, source: &str) -> Result<Expression<Standard>, IsolateError> {
138        self.run_internal(source, ExpressionKind::Standard)?;
139        let bytecode = self.compiler.get_bytecode().to_vec();
140
141        Ok(Expression::new_standard(Arc::from(bytecode)))
142    }
143
144    pub fn run_standard(&mut self, source: &str) -> Result<Variable, IsolateError> {
145        let cached = self
146            .cache
147            .as_ref()
148            .and_then(|c| c.standard.get(source).cloned());
149        if let Some(codes) = cached {
150            return self.run_compiled(codes.as_ref());
151        }
152
153        self.run_internal(source, ExpressionKind::Standard)?;
154
155        let bytecode = self.compiler.get_bytecode();
156        let result = self.vm.run(bytecode, &self.scope)?;
157
158        Ok(result)
159    }
160    pub fn run_compiled(&mut self, source: &[Opcode]) -> Result<Variable, IsolateError> {
161        let result = self.vm.run(source, &self.scope)?;
162
163        Ok(result)
164    }
165
166    pub fn compile_unary(&mut self, source: &str) -> Result<Expression<Unary>, IsolateError> {
167        self.run_internal(source, ExpressionKind::Unary)?;
168        let bytecode = self.compiler.get_bytecode().to_vec();
169
170        Ok(Expression::new_unary(Arc::from(bytecode)))
171    }
172
173    pub fn run_unary(&mut self, source: &str) -> Result<bool, IsolateError> {
174        let cached = self
175            .cache
176            .as_ref()
177            .and_then(|c| c.unary.get(source).cloned());
178        if let Some(codes) = cached {
179            return self.run_unary_compiled(codes.as_ref());
180        }
181
182        self.run_internal(source, ExpressionKind::Unary)?;
183
184        let bytecode = self.compiler.get_bytecode();
185        let result = self.vm.run(bytecode, &self.scope)?;
186
187        result.as_bool().ok_or_else(|| IsolateError::ValueCastError)
188    }
189
190    pub fn run_unary_compiled(&mut self, code: &[Opcode]) -> Result<bool, IsolateError> {
191        let result = self.vm.run(code, &self.scope)?;
192
193        result.as_bool().ok_or_else(|| IsolateError::ValueCastError)
194    }
195}
196
197/// Errors which happen within isolate or during evaluation
198#[derive(Debug, Error)]
199pub enum IsolateError {
200    #[error("Lexer error: {source}")]
201    LexerError { source: LexerError },
202
203    #[error("Parser error: {source}")]
204    ParserError { source: ParserError },
205
206    #[error("Compiler error: {source}")]
207    CompilerError { source: CompilerError },
208
209    #[error("VM error: {source}")]
210    VMError { source: VMError },
211
212    #[error("Value cast error")]
213    ValueCastError,
214
215    #[error("Failed to compute reference")]
216    ReferenceError,
217
218    #[error("Missing context reference")]
219    MissingContextReference,
220}
221
222impl Serialize for IsolateError {
223    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
224    where
225        S: Serializer,
226    {
227        let mut map = serializer.serialize_map(None)?;
228
229        match &self {
230            IsolateError::ReferenceError => {
231                map.serialize_entry("type", "referenceError")?;
232            }
233            IsolateError::MissingContextReference => {
234                map.serialize_entry("type", "missingContextReference")?;
235            }
236            IsolateError::ValueCastError => {
237                map.serialize_entry("type", "valueCastError")?;
238            }
239            IsolateError::LexerError { source } => {
240                map.serialize_entry("type", "lexerError")?;
241                map.serialize_entry("source", source.to_string().as_str())?;
242            }
243            IsolateError::ParserError { source } => {
244                map.serialize_entry("type", "parserError")?;
245                map.serialize_entry("source", source.to_string().as_str())?;
246            }
247            IsolateError::CompilerError { source } => {
248                map.serialize_entry("type", "compilerError")?;
249                map.serialize_entry("source", source.to_string().as_str())?;
250            }
251            IsolateError::VMError { source } => {
252                map.serialize_entry("type", "vmError")?;
253                map.serialize_entry("source", source.to_string().as_str())?;
254            }
255        }
256
257        map.end()
258    }
259}
260
261impl From<LexerError> for IsolateError {
262    fn from(source: LexerError) -> Self {
263        IsolateError::LexerError { source }
264    }
265}
266
267impl From<ParserError> for IsolateError {
268    fn from(source: ParserError) -> Self {
269        IsolateError::ParserError { source }
270    }
271}
272
273impl From<VMError> for IsolateError {
274    fn from(source: VMError) -> Self {
275        IsolateError::VMError { source }
276    }
277}
278
279impl From<CompilerError> for IsolateError {
280    fn from(source: CompilerError) -> Self {
281        IsolateError::CompilerError { source }
282    }
283}