diff --git a/lykiadb-server/src/engine/error.rs b/lykiadb-server/src/engine/error.rs index 909e9b2a..c61fc7e2 100644 --- a/lykiadb-server/src/engine/error.rs +++ b/lykiadb-server/src/engine/error.rs @@ -169,7 +169,6 @@ pub fn report_error( } #[cfg(test)] mod tests { - use super::*; use lykiadb_lang::{ diff --git a/lykiadb-server/src/engine/interpreter.rs b/lykiadb-server/src/engine/interpreter.rs index 39824f32..a4dc46a9 100644 --- a/lykiadb-server/src/engine/interpreter.rs +++ b/lykiadb-server/src/engine/interpreter.rs @@ -21,7 +21,7 @@ use super::stdlib::stdlib; use crate::plan::planner::Planner; use crate::util::{alloc_shared, Shared}; use crate::value::callable::{Callable, CallableKind, Function, Stateful}; -use crate::value::environment::{EnvId, Environment}; +use crate::value::environment::EnvironmentFrame; use crate::value::{eval::eval_binary, RV}; use std::sync::Arc; @@ -174,9 +174,8 @@ impl LoopStack { } pub struct Interpreter { - env: EnvId, - root_env: EnvId, - env_man: Shared, + env: Arc, + root_env: Arc, current_program: Option>, // loop_stack: LoopStack, @@ -188,21 +187,18 @@ pub struct Interpreter { impl Interpreter { pub fn new(out: Option>, with_stdlib: bool) -> Interpreter { - let mut env_man = Environment::new(); + let root_env = Arc::new(EnvironmentFrame::new(None)); let mut interner = StringInterner::>::new(); if with_stdlib { let native_fns = stdlib(out.clone()); - let env = env_man.top(); for (name, value) in native_fns { - env_man.declare(env, interner.get_or_intern(name), value); + root_env.define(interner.get_or_intern(name), value); } } - let env = EnvId(0); Interpreter { - env_man: alloc_shared(env_man), - env, - root_env: env, + env: root_env.clone(), + root_env, loop_stack: LoopStack::new(), source_processor: SourceProcessor::new(), current_program: None, @@ -254,56 +250,43 @@ impl Interpreter { } fn look_up_variable(&mut self, name: &str, expr: &Expr) -> Result { - let distance = self.current_program.clone().unwrap().get_distance(expr); + let distance = self.current_program.as_ref().unwrap().get_distance(expr); if let Some(unwrapped) = distance { - self.env_man.read().unwrap().read_at( - self.env, + EnvironmentFrame::read_at( + &self.env, unwrapped, name, &self.interner.get_or_intern(name), ) } else { - self.env_man.read().unwrap().read( - self.root_env, - name, - &self.interner.get_or_intern(name), - ) + self.root_env.read(name, &self.interner.get_or_intern(name)) } } pub fn user_fn_call( &mut self, statements: &Vec, - closure: EnvId, + closure: Arc, parameters: &[SymbolU32], arguments: &[RV], ) -> Result { - let mut write_guard = self.env_man.write().unwrap(); - let fn_env = write_guard.push(Some(closure)); + let fn_env = EnvironmentFrame::new(Some(Arc::clone(&closure))); for (i, param) in parameters.iter().enumerate() { // TODO: Remove clone here - write_guard.declare(fn_env, *param, arguments.get(i).unwrap().clone()); + fn_env.define(*param, arguments.get(i).unwrap().clone()); } - drop(write_guard); - - self.execute_block(statements, Some(fn_env)) + self.execute_block(statements, Arc::new(fn_env)) } fn execute_block( &mut self, statements: &Vec, - env_opt: Option, + env_opt: Arc, ) -> Result { - let mut env_tmp: Option = None; + let previous = std::mem::replace(&mut self.env, env_opt); - if let Some(env_opt_unwrapped) = env_opt { - env_tmp = Some(self.env); - self.env = env_opt_unwrapped; - } else { - self.env = self.env_man.write().unwrap().push(Some(self.env)); - } let mut ret = Ok(RV::Undefined); for statement in statements { @@ -312,11 +295,9 @@ impl Interpreter { break; } } - if let Some(env_tmp_unwrapped) = env_tmp { - self.env = env_tmp_unwrapped; - } else { - self.env = self.env_man.write().unwrap().remove(self.env); - } + + self.env = previous; + ret } @@ -375,18 +356,18 @@ impl VisitorMut for Interpreter { Ok(RV::Bool(self.visit_expr(right)?.as_bool())) } Expr::Assignment { dst, expr, .. } => { - let distance = self.current_program.clone().unwrap().get_distance(e); + let distance = self.current_program.as_ref().unwrap().get_distance(e); let evaluated = self.visit_expr(expr)?; let result = if let Some(distance_unv) = distance { - self.env_man.write().unwrap().assign_at( - self.env, + EnvironmentFrame::assign_at( + &self.env, distance_unv, + &dst.name, self.interner.get_or_intern(&dst.name), evaluated.clone(), ) } else { - self.env_man.write().unwrap().assign( - self.env, + self.root_env.assign( &dst.name, self.interner.get_or_intern(&dst.name), evaluated.clone(), @@ -457,7 +438,7 @@ impl VisitorMut for Interpreter { .iter() .map(|x| self.interner.get_or_intern(&x.name)) .collect(), - closure: self.env, + closure: self.env.clone(), }; let callable = RV::Callable(Callable::new( @@ -468,8 +449,7 @@ impl VisitorMut for Interpreter { if name.is_some() { // TODO(vck): Callable shouldn't be cloned here - self.env_man.write().unwrap().declare( - self.env, + self.env.define( self.interner.get_or_intern(&name.as_ref().unwrap().name), callable.clone(), ); @@ -601,21 +581,21 @@ impl VisitorMut for Interpreter { match s { Stmt::Program { body: stmts, .. } => { - return self.execute_block(stmts, Some(self.env)); + return self.execute_block(stmts, self.env.clone()); } Stmt::Expression { expr, .. } => { return self.visit_expr(expr); } Stmt::Declaration { dst, expr, .. } => { let evaluated = self.visit_expr(expr)?; - self.env_man.write().unwrap().declare( - self.env, - self.interner.get_or_intern(&dst.name), - evaluated.clone(), - ); + self.env + .define(self.interner.get_or_intern(&dst.name), evaluated); } Stmt::Block { body: stmts, .. } => { - return self.execute_block(stmts, None); + return self.execute_block( + stmts, + Arc::new(EnvironmentFrame::new(Some(Arc::clone(&self.env)))), + ); } Stmt::If { condition, diff --git a/lykiadb-server/src/value/callable.rs b/lykiadb-server/src/value/callable.rs index 646dced0..f2c8e61c 100644 --- a/lykiadb-server/src/value/callable.rs +++ b/lykiadb-server/src/value/callable.rs @@ -1,4 +1,4 @@ -use super::environment::EnvId; +use super::environment::EnvironmentFrame; use super::RV; use crate::{ engine::interpreter::{HaltReason, Interpreter}, @@ -40,7 +40,7 @@ impl Callable { closure, body, .. - } => interpreter.user_fn_call(body, *closure, parameters, arguments), + } => interpreter.user_fn_call(body, closure.clone(), parameters, arguments), } } } @@ -58,7 +58,7 @@ pub enum Function { UserDefined { name: SymbolU32, parameters: Vec, - closure: EnvId, + closure: Arc, body: Arc>, }, } @@ -67,7 +67,7 @@ impl Function { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { Function::Stateful(_) | Function::Lambda { .. } => write!(f, ""), - Function::UserDefined { .. } => write!(f, ""), + Function::UserDefined { .. } => write!(f, ""), } } } diff --git a/lykiadb-server/src/value/environment.rs b/lykiadb-server/src/value/environment.rs index fa010b7f..e8934c90 100644 --- a/lykiadb-server/src/value/environment.rs +++ b/lykiadb-server/src/value/environment.rs @@ -1,31 +1,14 @@ use crate::engine::{error::ExecutionError, interpreter::HaltReason}; -use core::panic; use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; -use std::borrow::{Borrow, BorrowMut}; +use std::sync::{Arc, RwLock}; use string_interner::symbol::SymbolU32; use super::RV; - -#[repr(transparent)] -#[derive(Debug, Eq, PartialEq, Clone, Copy)] -pub struct EnvId(pub usize); - #[derive(Debug)] -struct EnvironmentFrame { - map: FxHashMap, - pub parent: Option, -} - -#[derive(Debug)] -pub struct Environment { - envs: Vec, -} - -impl Default for Environment { - fn default() -> Self { - Self::new() - } +pub struct EnvironmentFrame { + map: RwLock>, + pub parent: Option>, } #[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)] @@ -39,142 +22,117 @@ pub enum EnvironmentError { Other { message: String }, } +macro_rules! to_ancestor { + ($init:expr, $distance:expr) => {{ + let mut env = $init; + for _ in 0..$distance { + env = env.parent.as_ref().unwrap(); + } + env + }}; +} + impl From for ExecutionError { fn from(err: EnvironmentError) -> Self { ExecutionError::Environment(err) } } -impl Environment { - pub fn new() -> Self { - let mut instance = Environment { envs: vec![] }; - instance.push(None); - instance - } - - pub fn push(&mut self, parent: Option) -> EnvId { - let map: FxHashMap = FxHashMap::default(); - // map.try_reserve(4).unwrap(); // speeds up sudo execution, don't know why - self.envs.push(EnvironmentFrame { map, parent }); - EnvId(self.envs.len() - 1) - } - - pub fn remove(&mut self, env_id: EnvId) -> EnvId { - let parent = self.envs[env_id.0].parent.unwrap(); - self.envs.remove(env_id.0); - parent - } - - pub fn top(&self) -> EnvId { - EnvId(self.envs.len() - 1) +impl EnvironmentFrame { + pub fn new(parent: Option>) -> EnvironmentFrame { + EnvironmentFrame { + parent, + map: RwLock::new(FxHashMap::default()), + } } - pub fn declare(&mut self, env_id: EnvId, name: SymbolU32, value: RV) { - self.envs[env_id.0].map.insert(name, value); + pub fn define(&self, name: SymbolU32, value: RV) { + self.map.write().unwrap().insert(name, value); } - pub fn assign( - &mut self, - env_id: EnvId, - key: &str, - key_sym: SymbolU32, - value: RV, - ) -> Result { - let env = self.envs[env_id.0].borrow(); - if env.map.contains_key(&key_sym) { - self.envs[env_id.0].borrow_mut().map.insert(key_sym, value); + pub fn assign(&self, key: &str, key_sym: SymbolU32, value: RV) -> Result { + if self.map.read().unwrap().contains_key(&key_sym) { + self.map.write().unwrap().insert(key_sym, value); return Ok(true); } - if env.parent.is_some() { - return self.assign(env.parent.unwrap(), key, key_sym, value); - } - Err(HaltReason::Error( - EnvironmentError::Other { - message: format!("Assignment to an undefined variable '{}'", key), - } - .into(), - )) + self.parent.as_ref().map_or( + Err(HaltReason::Error( + EnvironmentError::Other { + message: format!("Assignment to an undefined variable '{}'", key), + } + .into(), + )), + |parent| parent.as_ref().assign(key, key_sym, value), + ) } pub fn assign_at( - &mut self, - env_id: EnvId, + env: &Arc, distance: usize, - name: SymbolU32, + key: &str, + key_sym: SymbolU32, value: RV, ) -> Result { - let ancestor = self.ancestor(env_id, distance); - - if let Some(unwrapped) = ancestor { - self.envs[unwrapped.0].borrow_mut().map.insert(name, value); - } else { - self.envs[env_id.0].borrow_mut().map.insert(name, value); + if distance == 0 { + return env.assign(key, key_sym, value); } - - Ok(true) + if distance == 1 && env.parent.is_some() { + return env.parent.as_ref().unwrap().assign(key, key_sym, value); + } + to_ancestor!(env, distance).assign(key, key_sym, value) } - pub fn read(&self, env_id: EnvId, key: &str, key_sym: &SymbolU32) -> Result { - if self.envs[env_id.0].map.contains_key(key_sym) { + pub fn read(&self, key: &str, key_sym: &SymbolU32) -> Result { + let guard = self.map.read().unwrap(); + if let Some(value) = guard.get(key_sym) { // TODO(vck): Remove clone - return Ok(self.envs[env_id.0].map.get(key_sym).unwrap().clone()); - } - - if self.envs[env_id.0].parent.is_some() { - return self.read(self.envs[env_id.0].parent.unwrap(), key, key_sym); + return Ok(value.clone()); } - - Err(HaltReason::Error( - EnvironmentError::Other { - message: format!("Variable '{}' was not found", key), - } - .into(), - )) + self.parent.as_ref().map_or( + Err(HaltReason::Error( + EnvironmentError::Other { + message: format!("Variable '{}' was not found", key), + } + .into(), + )), + |parent| parent.read(key, key_sym), + ) } pub fn read_at( - &self, - env_id: EnvId, + env: &Arc, distance: usize, key: &str, key_sym: &SymbolU32, ) -> Result { - let ancestor = self.ancestor(env_id, distance); - - if let Some(unwrapped) = ancestor { - // TODO(vck): Remove clone - return Ok(self.envs[unwrapped.0].map.get(key_sym).unwrap().clone()); - } - if let Some(val) = self.envs[env_id.0].map.get(key_sym) { - return Ok(val.clone()); - } - - Err(HaltReason::Error( - EnvironmentError::Other { - message: format!("Variable '{}' was not found", key), - } - .into(), - )) - } - - pub fn ancestor(&self, env_id: EnvId, distance: usize) -> Option { if distance == 0 { - return None; - } - if distance == 1 { - return Some(self.envs[env_id.0].parent.unwrap()); + return env.read(key, key_sym); } - if self.envs[env_id.0].parent.is_some() { - let pref = self.envs[env_id.0].parent.unwrap(); - return self.ancestor(pref, distance - 1); + if distance == 1 && env.parent.is_some() { + return env.parent.as_ref().unwrap().read(key, key_sym); } - panic!("Invalid variable distance."); + to_ancestor!(env, distance) + .map + .read() + .unwrap() + .get(key_sym) + .map_or( + Err(HaltReason::Error( + EnvironmentError::Other { + message: format!("Variable '{}' was not found", key), + } + .into(), + )), + |v| Ok(v.clone()), + ) } } #[cfg(test)] mod test { + use std::sync::Arc; + use string_interner::{backend::StringBackend, symbol::SymbolU32, StringInterner}; use crate::value::RV; @@ -185,13 +143,12 @@ mod test { #[test] fn test_read_basic() { - let mut env_man = super::Environment::new(); + let env_man = super::EnvironmentFrame::new(None); let mut interner = get_interner(); - let env = env_man.top(); - env_man.declare(env, interner.get_or_intern("five"), RV::Num(5.0)); + env_man.define(interner.get_or_intern("five"), RV::Num(5.0)); assert_eq!( env_man - .read(env, "five", &interner.get_or_intern("five")) + .read("five", &interner.get_or_intern("five")) .unwrap(), RV::Num(5.0) ); @@ -199,60 +156,53 @@ mod test { #[test] fn test_read_from_parent() { - let mut env_man = super::Environment::new(); + let root = super::EnvironmentFrame::new(None); let mut interner = get_interner(); - let parent = env_man.top(); - env_man.declare(parent, interner.get_or_intern("five"), RV::Num(5.0)); - let child = env_man.push(Some(parent)); + root.define(interner.get_or_intern("five"), RV::Num(5.0)); + let child = super::EnvironmentFrame::new(Some(Arc::new(root))); assert_eq!( - env_man - .read(child, "five", &interner.get_or_intern("five")) - .unwrap(), + child.read("five", &interner.get_or_intern("five")).unwrap(), RV::Num(5.0) ); } #[test] fn test_write_to_parent() { - let mut env_man = super::Environment::new(); + let root = Arc::new(super::EnvironmentFrame::new(None)); let mut interner = get_interner(); - let parent = env_man.top(); - env_man.declare(parent, interner.get_or_intern("five"), RV::Num(5.0)); - let child = env_man.push(Some(parent)); - env_man - .assign(child, "five", interner.get_or_intern("five"), RV::Num(5.1)) + + root.define(interner.get_or_intern("five"), RV::Num(5.0)); + + let child = super::EnvironmentFrame::new(Some(root.clone())); + + child + .assign("five", interner.get_or_intern("five"), RV::Num(5.1)) .unwrap(); + assert_eq!( - env_man - .read(parent, "five", &interner.get_or_intern("five")) - .unwrap(), + root.read("five", &interner.get_or_intern("five")).unwrap(), RV::Num(5.1) ); + assert_eq!( - env_man - .read(child, "five", &interner.get_or_intern("five")) - .unwrap(), + child.read("five", &interner.get_or_intern("five")).unwrap(), RV::Num(5.1) ); } #[test] fn test_read_undefined_variable() { - let env_man = super::Environment::new(); + let env = super::EnvironmentFrame::new(None); let mut interner = get_interner(); - let env = env_man.top(); - assert!(env_man - .read(env, "five", &interner.get_or_intern("five")) - .is_err()); + assert!(env.read("five", &interner.get_or_intern("five")).is_err()); } #[test] fn test_assign_to_undefined_variable() { - let mut env_man = super::Environment::new(); + let env = super::EnvironmentFrame::new(None); let mut interner = get_interner(); - let env = env_man.top(); - assert!(env_man - .assign(env, "five", interner.get_or_intern("five"), RV::Num(5.0)) + assert!(env + .assign("five", interner.get_or_intern("five"), RV::Num(5.0)) .is_err()); } }