use std::cell::{RefCell, UnsafeCell};
use std::collections::HashMap;
use std::hash::BuildHasherDefault;
use std::mem::ManuallyDrop;
use std::ops::DerefMut;
use std::rc::Rc;
use ahash::AHasher;
use bumpalo::Bump;
use serde_json::Value;
use thiserror::Error;
use zen_parser::lexer::error::LexerError;
use zen_parser::lexer::Lexer;
use zen_parser::parser::error::ParserError;
use zen_parser::parser::{StandardParser, UnaryParser};
use crate::compiler::{Compiler, CompilerError};
use crate::opcodes::{ExecResult, Opcode, Variable};
use crate::vm::{Scope, VMError, VM};
type ADefHasher = BuildHasherDefault<AHasher>;
#[derive(Debug, Error)]
pub enum IsolateError {
#[error("Lexer error")]
LexerError { source: LexerError },
#[error("Parser error")]
ParserError { source: ParserError },
#[error("Compiler error")]
CompilerError { source: CompilerError },
#[error("VM error")]
VMError { source: VMError },
#[error("Value cast error")]
ValueCastError,
#[error("Failed to compute reference")]
ReferenceError,
}
#[derive(Debug)]
pub struct Isolate<'a> {
lexer: Lexer<'a>,
bump: RefCell<Bump>,
reference_bump: Bump,
bytecode: Rc<UnsafeCell<Vec<&'a Opcode<'a>>>>,
stack: UnsafeCell<Vec<&'a Variable<'a>>>,
scopes: UnsafeCell<Vec<Scope<'a>>>,
environment: UnsafeCell<ManuallyDrop<Variable<'a>>>,
references: RefCell<HashMap<&'a str, &'a Variable<'a>, ADefHasher>>,
}
impl<'a> Default for Isolate<'a> {
fn default() -> Self {
Self {
lexer: Lexer::new(),
bump: Default::default(),
reference_bump: Default::default(),
bytecode: Default::default(),
stack: Default::default(),
scopes: Default::default(),
environment: UnsafeCell::new(ManuallyDrop::new(Variable::Null)),
references: Default::default(),
}
}
}
impl<'a> Isolate<'a> {
pub fn inject_env(&self, value: &Value) {
let new_env = Variable::from_serde(value, self.get_reference_bump());
let env = unsafe { &mut (*self.environment.get()) };
*env = ManuallyDrop::new(new_env);
}
pub fn run(&self, source: &'a str) -> Result<ExecResult, IsolateError> {
if self.contains_ref(source) {
self.run_standard(source)
} else {
self.run_unary(source)
}
}
fn get_bump(&self) -> &'a Bump {
unsafe { std::mem::transmute::<&Bump, &'a Bump>(&self.bump.borrow()) }
}
fn get_reference_bump(&self) -> &'a Bump {
unsafe { std::mem::transmute(&self.reference_bump) }
}
pub fn set_reference(&self, reference: &'a str) -> Result<(), IsolateError> {
let mut references = self.references.borrow_mut();
let bump = self.get_reference_bump();
if !references.contains_key(reference) {
let result = self.run_standard(reference)?;
let value = result
.to_variable(bump)
.map_err(|_| IsolateError::ValueCastError)?;
references.insert(reference, value);
}
let value = references
.get(reference)
.ok_or(IsolateError::ReferenceError)?;
let env_w = unsafe { &mut (*self.environment.get()) };
let env = env_w.deref_mut();
match env {
Variable::Object(..) => {
}
_ => {
*env = Variable::empty_object_in(bump);
}
}
if let Variable::Object(obj) = env {
obj.insert("$", value);
}
Ok(())
}
pub fn run_standard(&self, source: &'a str) -> Result<ExecResult, IsolateError> {
self.clear();
let tokens = self
.lexer
.tokenize(source)
.map_err(|source| IsolateError::LexerError { source })?;
let tkn = tokens.borrow();
let bump = self.get_bump();
let parser = StandardParser::try_new(tkn.as_ref(), bump)
.map_err(|source| IsolateError::ParserError { source })?;
let ast = parser
.parse()
.map_err(|source| IsolateError::ParserError { source })?;
let compiler = Compiler::new(ast, self.bytecode.clone(), bump);
compiler
.compile()
.map_err(|source| IsolateError::CompilerError { source })?;
let mut vm = unsafe {
VM::new(
&*self.bytecode.get(),
&mut *self.stack.get(),
&mut *self.scopes.get(),
bump,
)
};
let res = vm
.run(unsafe { &*self.environment.get() })
.map_err(|source| IsolateError::VMError { source })?;
ExecResult::try_from(res).map_err(|_| IsolateError::ValueCastError)
}
pub fn run_unary(&self, source: &'a str) -> Result<ExecResult, IsolateError> {
self.clear();
let tokens = self
.lexer
.tokenize(source)
.map_err(|source| IsolateError::LexerError { source })?;
let tkn = tokens.borrow();
let bump = self.get_bump();
let parser = UnaryParser::try_new(tkn.as_ref(), bump)
.map_err(|source| IsolateError::ParserError { source })?;
let ast = parser
.parse()
.map_err(|source| IsolateError::ParserError { source })?;
let compiler = Compiler::new(ast, self.bytecode.clone(), bump);
compiler
.compile()
.map_err(|source| IsolateError::CompilerError { source })?;
let mut vm = unsafe {
VM::new(
&*self.bytecode.get(),
&mut *self.stack.get(),
&mut *self.scopes.get(),
bump,
)
};
let res = vm
.run(unsafe { &*self.environment.get() })
.map_err(|source| IsolateError::VMError { source })?;
ExecResult::try_from(res).map_err(|_| IsolateError::ValueCastError)
}
fn clear(&self) {
self.bump.borrow_mut().reset();
unsafe {
(*self.bytecode.get()).clear();
(*self.stack.get()).clear();
(*self.scopes.get()).clear();
}
}
fn contains_ref(&self, source: &str) -> bool {
source.chars().any(|c| c == '$')
}
}