From e5feeb76984ae05aa74b810a77e6caafb0adc625 Mon Sep 17 00:00:00 2001 From: Vedat Can Keklik Date: Sun, 15 Dec 2024 01:05:29 +0300 Subject: [PATCH 01/14] feat: String interning in env --- lykiadb-server/Cargo.toml | 3 +- lykiadb-server/src/engine/interpreter.rs | 105 +++++++++++++---------- lykiadb-server/src/value/callable.rs | 7 +- lykiadb-server/src/value/environment.rs | 54 +++++++----- 4 files changed, 97 insertions(+), 72 deletions(-) diff --git a/lykiadb-server/Cargo.toml b/lykiadb-server/Cargo.toml index e40f3279..ac47f86e 100644 --- a/lykiadb-server/Cargo.toml +++ b/lykiadb-server/Cargo.toml @@ -28,6 +28,7 @@ tokio-stream = { version = "~0.1.6", features = ["net"] } tracing = "0.1" tracing-subscriber = "0.3" pretty_assertions = "1.4.1" +string-interner = "0.18.0" [dev-dependencies] criterion = { version = "0.4", features = ["html_reports"] } @@ -35,4 +36,4 @@ test_each_file = "0.3.4" [[bench]] name = "interpreter" -harness = false +harness = false \ No newline at end of file diff --git a/lykiadb-server/src/engine/interpreter.rs b/lykiadb-server/src/engine/interpreter.rs index f7c9f1ac..7460bf71 100644 --- a/lykiadb-server/src/engine/interpreter.rs +++ b/lykiadb-server/src/engine/interpreter.rs @@ -11,6 +11,9 @@ use lykiadb_lang::{Literal, Locals, Scopes}; use pretty_assertions::assert_eq; use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; +use string_interner::backend::StringBackend; +use string_interner::symbol::SymbolU32; +use string_interner::StringInterner; use super::error::ExecutionError; use super::stdlib::stdlib; @@ -179,17 +182,20 @@ pub struct Interpreter { loop_stack: LoopStack, source_processor: SourceProcessor, output: Option>, + // + interner: StringInterner>, } impl Interpreter { pub fn new(out: Option>, with_stdlib: bool) -> Interpreter { let mut env_man = Environment::new(); + 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, name.to_string(), value); + env_man.declare(env, interner.get_or_intern(name), value); } } let env = EnvId(0); @@ -201,6 +207,7 @@ impl Interpreter { source_processor: SourceProcessor::new(), current_program: None, output: out, + interner } } @@ -246,15 +253,15 @@ impl Interpreter { Ok(eval_binary(left_eval, right_eval, operation)) } - fn look_up_variable(&self, name: &str, expr: &Expr) -> Result { + fn look_up_variable(&mut self, name: &str, expr: &Expr) -> Result { let distance = self.current_program.clone().unwrap().get_distance(expr); if let Some(unwrapped) = distance { self.env_man .read() .unwrap() - .read_at(self.env, unwrapped, name) + .read_at(self.env, unwrapped, &self.interner.get_or_intern(name)) } else { - self.env_man.read().unwrap().read(self.root_env, name) + self.env_man.read().unwrap().read(self.root_env, &self.interner.get_or_intern(name)) } } @@ -262,20 +269,23 @@ impl Interpreter { &mut self, statements: &Vec, closure: EnvId, - parameters: &[String], + parameters: &[SymbolU32], arguments: &[RV], ) -> Result { - let fn_env = self.env_man.write().unwrap().push(Some(closure)); + let mut write_guard = self.env_man.write().unwrap(); + let fn_env = write_guard.push(Some(closure)); for (i, param) in parameters.iter().enumerate() { // TODO: Remove clone here - self.env_man.write().unwrap().declare( + write_guard.declare( fn_env, - param.to_string(), + param.clone(), arguments.get(i).unwrap().clone(), ); } + drop(write_guard); + self.execute_block(statements, Some(fn_env)) } @@ -334,21 +344,8 @@ impl Interpreter { impl VisitorMut for Interpreter { fn visit_expr(&mut self, e: &Expr) -> Result { match e { - Expr::Select { .. } - | Expr::Insert { .. } - | Expr::Update { .. } - | Expr::Delete { .. } => { - let mut planner = Planner::new(self); - let plan = planner.build(e)?; - if let Some(out) = &self.output { - out.write() - .unwrap() - .push(RV::Str(Arc::new(plan.to_string().trim().to_string()))); - } - Ok(RV::Undefined) - } Expr::Literal { value, .. } => Ok(self.literal_to_rv(value)), - Expr::Grouping { expr, .. } => self.visit_expr(expr), + Expr::Variable { name, .. } => self.look_up_variable(&name.name, e), Expr::Unary { operation, expr, .. } => self.eval_unary(operation, expr), @@ -358,7 +355,23 @@ impl VisitorMut for Interpreter { right, .. } => self.eval_binary(left, right, *operation), - Expr::Variable { name, .. } => self.look_up_variable(&name.name, e), + Expr::Grouping { expr, .. } => self.visit_expr(expr), + Expr::Logical { + left, + operation, + right, + .. + } => { + let is_true = self.visit_expr(left)?.as_bool(); + + if (*operation == Operation::Or && is_true) + || (*operation == Operation::And && !is_true) + { + return Ok(RV::Bool(is_true)); + } + + Ok(RV::Bool(self.visit_expr(right)?.as_bool())) + } Expr::Assignment { dst, expr, .. } => { let distance = self.current_program.clone().unwrap().get_distance(e); let evaluated = self.visit_expr(expr)?; @@ -366,13 +379,13 @@ impl VisitorMut for Interpreter { self.env_man.write().unwrap().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, - dst.name.clone(), + self.interner.get_or_intern(&dst.name), evaluated.clone(), ) }; @@ -381,22 +394,6 @@ impl VisitorMut for Interpreter { } Ok(evaluated) } - Expr::Logical { - left, - operation, - right, - .. - } => { - let is_true = self.visit_expr(left)?.as_bool(); - - if (*operation == Operation::Or && is_true) - || (*operation == Operation::And && !is_true) - { - return Ok(RV::Bool(is_true)); - } - - Ok(RV::Bool(self.visit_expr(right)?.as_bool())) - } Expr::Call { callee, args, span, .. } => { @@ -419,11 +416,12 @@ impl VisitorMut for Interpreter { for arg in args.iter() { args_evaluated.push(self.visit_expr(arg)?); } - self.loop_stack.push_fn(); + // self.loop_stack.push_fn(); let val = callable.call(self, args_evaluated.as_slice()); - self.loop_stack.pop_fn(); + // self.loop_stack.pop_fn(); + match val { Err(HaltReason::Return(ret_val)) => Ok(ret_val), Ok(unpacked_val) => Ok(unpacked_val), @@ -450,9 +448,9 @@ impl VisitorMut for Interpreter { "" }; let fun = Function::UserDefined { - name: fn_name.to_string(), + name: self.interner.get_or_intern(fn_name), body: Arc::clone(body), - parameters: parameters.iter().map(|x| x.name.to_string()).collect(), + parameters: parameters.iter().map(|x| self.interner.get_or_intern(&x.name)).collect(), closure: self.env, }; @@ -466,7 +464,7 @@ impl VisitorMut for Interpreter { // TODO(vck): Callable shouldn't be cloned here self.env_man.write().unwrap().declare( self.env, - name.as_ref().unwrap().name.to_string(), + self.interner.get_or_intern(&name.as_ref().unwrap().name), callable.clone(), ); } @@ -572,6 +570,19 @@ impl VisitorMut for Interpreter { )) } } + Expr::Select { .. } + | Expr::Insert { .. } + | Expr::Update { .. } + | Expr::Delete { .. } => { + let mut planner = Planner::new(self); + let plan = planner.build(e)?; + if let Some(out) = &self.output { + out.write() + .unwrap() + .push(RV::Str(Arc::new(plan.to_string().trim().to_string()))); + } + Ok(RV::Undefined) + } } } @@ -593,7 +604,7 @@ impl VisitorMut for Interpreter { let evaluated = self.visit_expr(expr)?; self.env_man.write().unwrap().declare( self.env, - dst.name.to_string(), + self.interner.get_or_intern(&dst.name), evaluated.clone(), ); } diff --git a/lykiadb-server/src/value/callable.rs b/lykiadb-server/src/value/callable.rs index d4999d5c..81e0f332 100644 --- a/lykiadb-server/src/value/callable.rs +++ b/lykiadb-server/src/value/callable.rs @@ -5,6 +5,7 @@ use crate::{ util::Shared, }; use lykiadb_lang::ast::stmt::Stmt; +use string_interner::symbol::SymbolU32; use std::fmt::{Debug, Display, Formatter}; use std::sync::Arc; @@ -55,8 +56,8 @@ pub enum Function { }, Stateful(Shared), UserDefined { - name: String, - parameters: Vec, + name: SymbolU32, + parameters: Vec, closure: EnvId, body: Arc>, }, @@ -66,7 +67,7 @@ impl Function { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { Function::Stateful(_) | Function::Lambda { .. } => write!(f, ""), - Function::UserDefined { name, .. } => write!(f, "{}", name), + Function::UserDefined { name, .. } => write!(f, "{}", ""), } } } diff --git a/lykiadb-server/src/value/environment.rs b/lykiadb-server/src/value/environment.rs index fea828fa..584520f4 100644 --- a/lykiadb-server/src/value/environment.rs +++ b/lykiadb-server/src/value/environment.rs @@ -3,6 +3,7 @@ use core::panic; use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; use std::borrow::{Borrow, BorrowMut}; +use string_interner::{symbol::SymbolU32, StringInterner, Symbol}; use super::RV; @@ -12,7 +13,7 @@ pub struct EnvId(pub usize); #[derive(Debug)] struct EnvironmentFrame { - map: FxHashMap, + map: FxHashMap, pub parent: Option, } @@ -69,11 +70,11 @@ impl Environment { EnvId(self.envs.len() - 1) } - pub fn declare(&mut self, env_id: EnvId, name: String, value: RV) { + pub fn declare(&mut self, env_id: EnvId, name: SymbolU32, value: RV) { self.envs[env_id.0].map.insert(name, value); } - pub fn assign(&mut self, env_id: EnvId, name: String, value: RV) -> Result { + pub fn assign(&mut self, env_id: EnvId, name: SymbolU32, value: RV) -> Result { let env = self.envs[env_id.0].borrow(); if env.map.contains_key(&name) { self.envs[env_id.0].borrow_mut().map.insert(name, value); @@ -85,7 +86,7 @@ impl Environment { } Err(HaltReason::Error( EnvironmentError::Other { - message: format!("Assignment to an undefined variable '{}'", &name), + message: format!("Assignment to an undefined variable '{}'", "TODO Fix"), } .into(), )) @@ -95,7 +96,7 @@ impl Environment { &mut self, env_id: EnvId, distance: usize, - name: &str, + name: SymbolU32, value: RV, ) -> Result { let ancestor = self.ancestor(env_id, distance); @@ -104,18 +105,18 @@ impl Environment { self.envs[unwrapped.0] .borrow_mut() .map - .insert(name.to_string(), value); + .insert(name, value); } else { self.envs[env_id.0] .borrow_mut() .map - .insert(name.to_string(), value); + .insert(name, value); } Ok(true) } - pub fn read(&self, env_id: EnvId, name: &str) -> Result { + pub fn read(&self, env_id: EnvId, name: &SymbolU32) -> Result { if self.envs[env_id.0].map.contains_key(name) { // TODO(vck): Remove clone return Ok(self.envs[env_id.0].map.get(name).unwrap().clone()); @@ -127,13 +128,13 @@ impl Environment { Err(HaltReason::Error( EnvironmentError::Other { - message: format!("Variable '{}' was not found", &name), + message: format!("Variable '{}' was not found", "TODO Fix"), } .into(), )) } - pub fn read_at(&self, env_id: EnvId, distance: usize, name: &str) -> Result { + pub fn read_at(&self, env_id: EnvId, distance: usize, name: &SymbolU32) -> Result { let ancestor = self.ancestor(env_id, distance); if let Some(unwrapped) = ancestor { @@ -146,7 +147,7 @@ impl Environment { Err(HaltReason::Error( EnvironmentError::Other { - message: format!("Variable '{}' was not found", &name), + message: format!("Variable '{}' was not found", "TODO Fix"), } .into(), )) @@ -169,51 +170,62 @@ impl Environment { #[cfg(test)] mod test { + use string_interner::{backend::StringBackend, symbol::SymbolU32, StringInterner}; + use crate::value::RV; + fn get_interner() -> StringInterner::> { + StringInterner::>::new() + } + #[test] fn test_read_basic() { let mut env_man = super::Environment::new(); + let mut interner = get_interner(); let env = env_man.top(); - env_man.declare(env, "five".to_string(), RV::Num(5.0)); - assert_eq!(env_man.read(env, "five").unwrap(), RV::Num(5.0)); + env_man.declare(env, interner.get_or_intern("five"), RV::Num(5.0)); + assert_eq!(env_man.read(env, &interner.get_or_intern("five")).unwrap(), RV::Num(5.0)); } #[test] fn test_read_from_parent() { let mut env_man = super::Environment::new(); + let mut interner = get_interner(); let parent = env_man.top(); - env_man.declare(parent, "five".to_string(), RV::Num(5.0)); + env_man.declare(parent, interner.get_or_intern("five"), RV::Num(5.0)); let child = env_man.push(Some(parent)); - assert_eq!(env_man.read(child, "five").unwrap(), RV::Num(5.0)); + assert_eq!(env_man.read(child, &interner.get_or_intern("five")).unwrap(), RV::Num(5.0)); } #[test] fn test_write_to_parent() { let mut env_man = super::Environment::new(); + let mut interner = get_interner(); let parent = env_man.top(); - env_man.declare(parent, "five".to_string(), RV::Num(5.0)); + 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".to_string(), RV::Num(5.1)) + .assign(child, interner.get_or_intern("five"), RV::Num(5.1)) .unwrap(); - assert_eq!(env_man.read(parent, "five").unwrap(), RV::Num(5.1)); - assert_eq!(env_man.read(child, "five").unwrap(), RV::Num(5.1)); + assert_eq!(env_man.read(parent, &interner.get_or_intern("five")).unwrap(), RV::Num(5.1)); + assert_eq!(env_man.read(child, &interner.get_or_intern("five")).unwrap(), RV::Num(5.1)); } #[test] fn test_read_undefined_variable() { let env_man = super::Environment::new(); + let mut interner = get_interner(); let env = env_man.top(); - assert!(env_man.read(env, "five").is_err()); + assert!(env_man.read(env, &interner.get_or_intern("five")).is_err()); } #[test] fn test_assign_to_undefined_variable() { let mut env_man = super::Environment::new(); + let mut interner = get_interner(); let env = env_man.top(); assert!(env_man - .assign(env, "five".to_string(), RV::Num(5.0)) + .assign(env, interner.get_or_intern("five"), RV::Num(5.0)) .is_err()); } } From 79fb12ca0d1f9228c621115d893741e34bae3abb Mon Sep 17 00:00:00 2001 From: Vedat Can Keklik Date: Sun, 15 Dec 2024 01:09:46 +0300 Subject: [PATCH 02/14] fix: Bug --- lykiadb-server/src/engine/interpreter.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lykiadb-server/src/engine/interpreter.rs b/lykiadb-server/src/engine/interpreter.rs index 7460bf71..ef18efc2 100644 --- a/lykiadb-server/src/engine/interpreter.rs +++ b/lykiadb-server/src/engine/interpreter.rs @@ -416,11 +416,11 @@ impl VisitorMut for Interpreter { for arg in args.iter() { args_evaluated.push(self.visit_expr(arg)?); } - // self.loop_stack.push_fn(); + self.loop_stack.push_fn(); let val = callable.call(self, args_evaluated.as_slice()); - // self.loop_stack.pop_fn(); + self.loop_stack.pop_fn(); match val { Err(HaltReason::Return(ret_val)) => Ok(ret_val), From 18aeaa406a973aa703616e0ca6bbcec713984d35 Mon Sep 17 00:00:00 2001 From: Vedat Can Keklik Date: Sun, 15 Dec 2024 17:53:10 +0300 Subject: [PATCH 03/14] fix: Tests --- lykiadb-server/src/engine/interpreter.rs | 5 +-- lykiadb-server/src/value/environment.rs | 46 ++++++++++++------------ 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/lykiadb-server/src/engine/interpreter.rs b/lykiadb-server/src/engine/interpreter.rs index ef18efc2..f7ad63fb 100644 --- a/lykiadb-server/src/engine/interpreter.rs +++ b/lykiadb-server/src/engine/interpreter.rs @@ -259,9 +259,9 @@ impl Interpreter { self.env_man .read() .unwrap() - .read_at(self.env, unwrapped, &self.interner.get_or_intern(name)) + .read_at(self.env, unwrapped, &name, &self.interner.get_or_intern(name)) } else { - self.env_man.read().unwrap().read(self.root_env, &self.interner.get_or_intern(name)) + self.env_man.read().unwrap().read(self.root_env, &name, &self.interner.get_or_intern(name)) } } @@ -385,6 +385,7 @@ impl VisitorMut for Interpreter { } else { self.env_man.write().unwrap().assign( self.env, + &dst.name, self.interner.get_or_intern(&dst.name), evaluated.clone(), ) diff --git a/lykiadb-server/src/value/environment.rs b/lykiadb-server/src/value/environment.rs index 584520f4..f8ba0eee 100644 --- a/lykiadb-server/src/value/environment.rs +++ b/lykiadb-server/src/value/environment.rs @@ -53,8 +53,10 @@ impl Environment { } 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: FxHashMap::default(), + map, parent, }); EnvId(self.envs.len() - 1) @@ -74,19 +76,19 @@ impl Environment { self.envs[env_id.0].map.insert(name, value); } - pub fn assign(&mut self, env_id: EnvId, name: SymbolU32, value: RV) -> Result { + 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(&name) { - self.envs[env_id.0].borrow_mut().map.insert(name, value); + if env.map.contains_key(&key_sym) { + self.envs[env_id.0].borrow_mut().map.insert(key_sym, value); return Ok(true); } if env.parent.is_some() { - return self.assign(env.parent.unwrap(), name, value); + return self.assign(env.parent.unwrap(), key, key_sym, value); } Err(HaltReason::Error( EnvironmentError::Other { - message: format!("Assignment to an undefined variable '{}'", "TODO Fix"), + message: format!("Assignment to an undefined variable '{}'", key), } .into(), )) @@ -116,38 +118,38 @@ impl Environment { Ok(true) } - pub fn read(&self, env_id: EnvId, name: &SymbolU32) -> Result { - if self.envs[env_id.0].map.contains_key(name) { + pub fn read(&self, env_id: EnvId, key: &str, key_sym: &SymbolU32) -> Result { + if self.envs[env_id.0].map.contains_key(key_sym) { // TODO(vck): Remove clone - return Ok(self.envs[env_id.0].map.get(name).unwrap().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(), name); + return self.read(self.envs[env_id.0].parent.unwrap(), key, key_sym); } Err(HaltReason::Error( EnvironmentError::Other { - message: format!("Variable '{}' was not found", "TODO Fix"), + message: format!("Variable '{}' was not found", key), } .into(), )) } - pub fn read_at(&self, env_id: EnvId, distance: usize, name: &SymbolU32) -> Result { + pub fn read_at(&self, env_id: EnvId, 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(name).unwrap().clone()); + return Ok(self.envs[unwrapped.0].map.get(key_sym).unwrap().clone()); } - if let Some(val) = self.envs[env_id.0].map.get(name) { + 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", "TODO Fix"), + message: format!("Variable '{}' was not found", key), } .into(), )) @@ -184,7 +186,7 @@ mod test { let mut interner = get_interner(); let env = env_man.top(); env_man.declare(env, interner.get_or_intern("five"), RV::Num(5.0)); - assert_eq!(env_man.read(env, &interner.get_or_intern("five")).unwrap(), RV::Num(5.0)); + assert_eq!(env_man.read(env, &"five", &interner.get_or_intern("five")).unwrap(), RV::Num(5.0)); } #[test] @@ -194,7 +196,7 @@ mod test { 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)); - assert_eq!(env_man.read(child, &interner.get_or_intern("five")).unwrap(), RV::Num(5.0)); + assert_eq!(env_man.read(child, &"five", &interner.get_or_intern("five")).unwrap(), RV::Num(5.0)); } #[test] @@ -205,10 +207,10 @@ mod test { env_man.declare(parent, interner.get_or_intern("five"), RV::Num(5.0)); let child = env_man.push(Some(parent)); env_man - .assign(child, interner.get_or_intern("five"), RV::Num(5.1)) + .assign(child, &"five", interner.get_or_intern("five"), RV::Num(5.1)) .unwrap(); - assert_eq!(env_man.read(parent, &interner.get_or_intern("five")).unwrap(), RV::Num(5.1)); - assert_eq!(env_man.read(child, &interner.get_or_intern("five")).unwrap(), RV::Num(5.1)); + assert_eq!(env_man.read(parent, &"five", &interner.get_or_intern("five")).unwrap(), RV::Num(5.1)); + assert_eq!(env_man.read(child, &"five", &interner.get_or_intern("five")).unwrap(), RV::Num(5.1)); } #[test] @@ -216,7 +218,7 @@ mod test { let env_man = super::Environment::new(); let mut interner = get_interner(); let env = env_man.top(); - assert!(env_man.read(env, &interner.get_or_intern("five")).is_err()); + assert!(env_man.read(env, &"five", &interner.get_or_intern("five")).is_err()); } #[test] @@ -225,7 +227,7 @@ mod test { let mut interner = get_interner(); let env = env_man.top(); assert!(env_man - .assign(env, interner.get_or_intern("five"), RV::Num(5.0)) + .assign(env, &"five", interner.get_or_intern("five"), RV::Num(5.0)) .is_err()); } } From 0ea41c4bb6d1c1ae33a0bff6f5ac135bbf5f213a Mon Sep 17 00:00:00 2001 From: Vedat Can Keklik Date: Sun, 15 Dec 2024 17:53:47 +0300 Subject: [PATCH 04/14] fix: fmt --- lykiadb-lang/benches/parsing.rs | 14 ++--- lykiadb-lang/src/ast/expr.rs | 9 +--- lykiadb-server/src/engine/error.rs | 25 +++++---- lykiadb-server/src/engine/interpreter.rs | 29 +++++----- lykiadb-server/src/value/callable.rs | 2 +- lykiadb-server/src/value/environment.rs | 67 ++++++++++++++++-------- 6 files changed, 88 insertions(+), 58 deletions(-) diff --git a/lykiadb-lang/benches/parsing.rs b/lykiadb-lang/benches/parsing.rs index 9b7c861c..273b736b 100644 --- a/lykiadb-lang/benches/parsing.rs +++ b/lykiadb-lang/benches/parsing.rs @@ -1,5 +1,9 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use lykiadb_lang::{parser::{program::Program, resolver::Resolver, Parser}, tokenizer::scanner::Scanner, Locals, Scopes}; +use lykiadb_lang::{ + parser::{program::Program, resolver::Resolver, Parser}, + tokenizer::scanner::Scanner, + Locals, Scopes, +}; use rustc_hash::FxHashMap; pub struct ParserBenchmark { @@ -7,7 +11,6 @@ pub struct ParserBenchmark { locals: Locals, } - impl ParserBenchmark { pub fn new() -> ParserBenchmark { ParserBenchmark { @@ -49,16 +52,15 @@ fn runtime() { EXCEPT SELECT * FROM books; - ".to_string(); + " + .to_string(); let mut parser = black_box(ParserBenchmark::new()); black_box(parser.process(black_box(&content))); } fn bench(c: &mut Criterion) { let mut group = c.benchmark_group("sample-size-example"); - group.bench_function("2-way join", |b| { - b.iter(|| runtime()) - }); + group.bench_function("2-way join", |b| b.iter(|| runtime())); group.finish(); } diff --git a/lykiadb-lang/src/ast/expr.rs b/lykiadb-lang/src/ast/expr.rs index 8532830d..29d647d1 100644 --- a/lykiadb-lang/src/ast/expr.rs +++ b/lykiadb-lang/src/ast/expr.rs @@ -703,12 +703,10 @@ pub mod test { }); assert_eq!(visited, vec![3, 1, 2]); } - } #[test] fn test_expr_get_id() { - // Test Variable let var_expr = Expr::Variable { name: Identifier::new("test_var", false), @@ -822,7 +820,6 @@ pub mod test { fn test_expr_get_span() { let test_span = Span::default(); - // Test Variable let var_expr = Expr::Variable { name: Identifier::new("test_var", false), @@ -1073,10 +1070,7 @@ pub mod test { fn test_function_display() { let func = Expr::Function { name: Some(Identifier::new("test_func", false)), - parameters: vec![ - Identifier::new("a", false), - Identifier::new("b", false), - ], + parameters: vec![Identifier::new("a", false), Identifier::new("b", false)], body: Arc::new(vec![]), span: Span::default(), id: 1, @@ -1139,7 +1133,6 @@ pub mod test { assert_eq!(call.to_string(), "test_func(Num(1.0), Num(2.0))"); } - pub fn create_simple_add_expr(id: usize, left: f64, right: f64) -> Expr { Expr::Binary { left: Box::new(Expr::Literal { diff --git a/lykiadb-server/src/engine/error.rs b/lykiadb-server/src/engine/error.rs index 28f4a967..c0276c72 100644 --- a/lykiadb-server/src/engine/error.rs +++ b/lykiadb-server/src/engine/error.rs @@ -38,7 +38,12 @@ impl From for ExecutionError { } } -pub fn report_error(source_name: &str, source: &str, error: ExecutionError, mut writer: impl std::io::Write) { +pub fn report_error( + source_name: &str, + source: &str, + error: ExecutionError, + mut writer: impl std::io::Write, +) { use ariadne::{Color, Label, Report, ReportKind, Source}; // Generate & choose some colours for each of our elements @@ -54,7 +59,8 @@ pub fn report_error(source_name: &str, source: &str, error: ExecutionError, mut .with_color(out), ) .finish() - .write((source_name, Source::from(&source)), &mut writer).unwrap(); + .write((source_name, Source::from(&source)), &mut writer) + .unwrap(); }; match error { @@ -87,11 +93,7 @@ pub fn report_error(source_name: &str, source: &str, error: ExecutionError, mut ); } ExecutionError::Parse(ParseError::NoTokens) => { - print( - "There is nothing to parse", - "", - Span::default(), - ); + print("There is nothing to parse", "", Span::default()); } ExecutionError::Parse(ParseError::InvalidAssignmentTarget { left }) => { print( @@ -170,7 +172,11 @@ mod tests { use core::panic; use super::*; - use lykiadb_lang::{kw, sym, tokenizer::token::{Keyword, Symbol, Token, TokenType}, Identifier, Literal}; + use lykiadb_lang::{ + kw, sym, + tokenizer::token::{Keyword, Symbol, Token, TokenType}, + Identifier, Literal, + }; fn capture_error_output(filename: &str, source: &str, error: ExecutionError) -> String { let mut output = Vec::new(); @@ -178,7 +184,6 @@ mod tests { String::from_utf8(output).unwrap() } - // Scanner Error Tests #[test] fn test_scanner_unterminated_string() { @@ -230,7 +235,7 @@ mod tests { }, literal: None, }, - expected: TokenType::Identifier { dollar: true } + expected: TokenType::Identifier { dollar: true }, }); let output = capture_error_output("test.txt", source, error); diff --git a/lykiadb-server/src/engine/interpreter.rs b/lykiadb-server/src/engine/interpreter.rs index f7ad63fb..09105520 100644 --- a/lykiadb-server/src/engine/interpreter.rs +++ b/lykiadb-server/src/engine/interpreter.rs @@ -207,7 +207,7 @@ impl Interpreter { source_processor: SourceProcessor::new(), current_program: None, output: out, - interner + interner, } } @@ -256,12 +256,18 @@ impl Interpreter { fn look_up_variable(&mut self, name: &str, expr: &Expr) -> Result { let distance = self.current_program.clone().unwrap().get_distance(expr); if let Some(unwrapped) = distance { - self.env_man - .read() - .unwrap() - .read_at(self.env, unwrapped, &name, &self.interner.get_or_intern(name)) + self.env_man.read().unwrap().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.env_man.read().unwrap().read( + self.root_env, + &name, + &self.interner.get_or_intern(name), + ) } } @@ -277,11 +283,7 @@ impl Interpreter { for (i, param) in parameters.iter().enumerate() { // TODO: Remove clone here - write_guard.declare( - fn_env, - param.clone(), - arguments.get(i).unwrap().clone(), - ); + write_guard.declare(fn_env, param.clone(), arguments.get(i).unwrap().clone()); } drop(write_guard); @@ -451,7 +453,10 @@ impl VisitorMut for Interpreter { let fun = Function::UserDefined { name: self.interner.get_or_intern(fn_name), body: Arc::clone(body), - parameters: parameters.iter().map(|x| self.interner.get_or_intern(&x.name)).collect(), + parameters: parameters + .iter() + .map(|x| self.interner.get_or_intern(&x.name)) + .collect(), closure: self.env, }; diff --git a/lykiadb-server/src/value/callable.rs b/lykiadb-server/src/value/callable.rs index 81e0f332..13c66c05 100644 --- a/lykiadb-server/src/value/callable.rs +++ b/lykiadb-server/src/value/callable.rs @@ -5,9 +5,9 @@ use crate::{ util::Shared, }; use lykiadb_lang::ast::stmt::Stmt; -use string_interner::symbol::SymbolU32; use std::fmt::{Debug, Display, Formatter}; use std::sync::Arc; +use string_interner::symbol::SymbolU32; #[derive(Debug, Clone)] pub enum CallableKind { diff --git a/lykiadb-server/src/value/environment.rs b/lykiadb-server/src/value/environment.rs index f8ba0eee..18fa1887 100644 --- a/lykiadb-server/src/value/environment.rs +++ b/lykiadb-server/src/value/environment.rs @@ -55,10 +55,7 @@ impl Environment { 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, - }); + self.envs.push(EnvironmentFrame { map, parent }); EnvId(self.envs.len() - 1) } @@ -76,7 +73,13 @@ impl Environment { self.envs[env_id.0].map.insert(name, value); } - pub fn assign(&mut self, env_id: EnvId, key: &str, key_sym: SymbolU32, value: RV) -> Result { + 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); @@ -104,15 +107,9 @@ impl Environment { let ancestor = self.ancestor(env_id, distance); if let Some(unwrapped) = ancestor { - self.envs[unwrapped.0] - .borrow_mut() - .map - .insert(name, value); + self.envs[unwrapped.0].borrow_mut().map.insert(name, value); } else { - self.envs[env_id.0] - .borrow_mut() - .map - .insert(name, value); + self.envs[env_id.0].borrow_mut().map.insert(name, value); } Ok(true) @@ -125,7 +122,7 @@ impl Environment { } if self.envs[env_id.0].parent.is_some() { - return self.read(self.envs[env_id.0].parent.unwrap(), key, key_sym); + return self.read(self.envs[env_id.0].parent.unwrap(), key, key_sym); } Err(HaltReason::Error( @@ -136,7 +133,13 @@ impl Environment { )) } - pub fn read_at(&self, env_id: EnvId, distance: usize, key: &str, key_sym: &SymbolU32) -> Result { + pub fn read_at( + &self, + env_id: EnvId, + distance: usize, + key: &str, + key_sym: &SymbolU32, + ) -> Result { let ancestor = self.ancestor(env_id, distance); if let Some(unwrapped) = ancestor { @@ -176,7 +179,7 @@ mod test { use crate::value::RV; - fn get_interner() -> StringInterner::> { + fn get_interner() -> StringInterner> { StringInterner::>::new() } @@ -186,7 +189,12 @@ mod test { let mut interner = get_interner(); let env = env_man.top(); env_man.declare(env, interner.get_or_intern("five"), RV::Num(5.0)); - assert_eq!(env_man.read(env, &"five", &interner.get_or_intern("five")).unwrap(), RV::Num(5.0)); + assert_eq!( + env_man + .read(env, &"five", &interner.get_or_intern("five")) + .unwrap(), + RV::Num(5.0) + ); } #[test] @@ -196,7 +204,12 @@ mod test { 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)); - assert_eq!(env_man.read(child, &"five", &interner.get_or_intern("five")).unwrap(), RV::Num(5.0)); + assert_eq!( + env_man + .read(child, &"five", &interner.get_or_intern("five")) + .unwrap(), + RV::Num(5.0) + ); } #[test] @@ -209,8 +222,18 @@ mod test { env_man .assign(child, &"five", interner.get_or_intern("five"), RV::Num(5.1)) .unwrap(); - assert_eq!(env_man.read(parent, &"five", &interner.get_or_intern("five")).unwrap(), RV::Num(5.1)); - assert_eq!(env_man.read(child, &"five", &interner.get_or_intern("five")).unwrap(), RV::Num(5.1)); + assert_eq!( + env_man + .read(parent, &"five", &interner.get_or_intern("five")) + .unwrap(), + RV::Num(5.1) + ); + assert_eq!( + env_man + .read(child, &"five", &interner.get_or_intern("five")) + .unwrap(), + RV::Num(5.1) + ); } #[test] @@ -218,7 +241,9 @@ mod test { let env_man = super::Environment::new(); 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_man + .read(env, &"five", &interner.get_or_intern("five")) + .is_err()); } #[test] From e7454f5c8513193600235e8a43befc3575539c87 Mon Sep 17 00:00:00 2001 From: Vedat Can Keklik Date: Sun, 15 Dec 2024 17:54:38 +0300 Subject: [PATCH 05/14] fix: clippy --- lykiadb-lang/benches/parsing.rs | 8 +++++++- lykiadb-lang/src/parser/mod.rs | 2 +- lykiadb-lang/src/parser/resolver.rs | 8 ++------ lykiadb-lang/src/tokenizer/scanner.rs | 2 +- lykiadb-server/src/engine/error.rs | 2 +- lykiadb-server/src/engine/interpreter.rs | 8 ++++---- lykiadb-server/src/engine/mod.rs | 2 +- lykiadb-server/src/value/callable.rs | 2 +- lykiadb-server/src/value/environment.rs | 16 ++++++++-------- 9 files changed, 26 insertions(+), 24 deletions(-) diff --git a/lykiadb-lang/benches/parsing.rs b/lykiadb-lang/benches/parsing.rs index 273b736b..db27a9fc 100644 --- a/lykiadb-lang/benches/parsing.rs +++ b/lykiadb-lang/benches/parsing.rs @@ -11,6 +11,12 @@ pub struct ParserBenchmark { locals: Locals, } +impl Default for ParserBenchmark { + fn default() -> Self { + Self::new() + } +} + impl ParserBenchmark { pub fn new() -> ParserBenchmark { ParserBenchmark { @@ -60,7 +66,7 @@ fn runtime() { fn bench(c: &mut Criterion) { let mut group = c.benchmark_group("sample-size-example"); - group.bench_function("2-way join", |b| b.iter(|| runtime())); + group.bench_function("2-way join", |b| b.iter(runtime)); group.finish(); } diff --git a/lykiadb-lang/src/parser/mod.rs b/lykiadb-lang/src/parser/mod.rs index 08b65db9..6f742479 100644 --- a/lykiadb-lang/src/parser/mod.rs +++ b/lykiadb-lang/src/parser/mod.rs @@ -912,7 +912,7 @@ macro_rules! optional_with_expected { }; } -impl<'a> Parser<'a> { +impl Parser<'_> { fn sql_insert(&mut self) -> ParseResult> { if !self.match_next(&skw!(Insert)) { return self.sql_update(); diff --git a/lykiadb-lang/src/parser/resolver.rs b/lykiadb-lang/src/parser/resolver.rs index 04eeaafe..e7dd2ef1 100644 --- a/lykiadb-lang/src/parser/resolver.rs +++ b/lykiadb-lang/src/parser/resolver.rs @@ -34,11 +34,7 @@ impl<'a> Resolver<'a> { ) -> Resolver<'a> { Resolver { scopes, - locals: if let Some(previous_locals) = previous_locals { - previous_locals - } else { - FxHashMap::default() - }, + locals: previous_locals.unwrap_or_default(), program, } } @@ -91,7 +87,7 @@ impl<'a> Resolver<'a> { } } -impl<'a> VisitorMut<(), ResolveError> for Resolver<'a> { +impl VisitorMut<(), ResolveError> for Resolver<'_> { fn visit_expr(&mut self, e: &Expr) -> Result<(), ResolveError> { match e { Expr::Literal { value, .. } => match value { diff --git a/lykiadb-lang/src/tokenizer/scanner.rs b/lykiadb-lang/src/tokenizer/scanner.rs index 83d2c9b6..9b019870 100644 --- a/lykiadb-lang/src/tokenizer/scanner.rs +++ b/lykiadb-lang/src/tokenizer/scanner.rs @@ -21,7 +21,7 @@ pub enum ScanError { MalformedNumberLiteral { span: Span }, } -impl<'a> Scanner<'a> { +impl Scanner<'_> { pub fn scan(source: &str) -> Result, ScanError> { let mut scanner = Scanner { chars: source.chars().enumerate().peekable(), diff --git a/lykiadb-server/src/engine/error.rs b/lykiadb-server/src/engine/error.rs index c0276c72..909e9b2a 100644 --- a/lykiadb-server/src/engine/error.rs +++ b/lykiadb-server/src/engine/error.rs @@ -169,7 +169,7 @@ pub fn report_error( } #[cfg(test)] mod tests { - use core::panic; + use super::*; use lykiadb_lang::{ diff --git a/lykiadb-server/src/engine/interpreter.rs b/lykiadb-server/src/engine/interpreter.rs index 09105520..39824f32 100644 --- a/lykiadb-server/src/engine/interpreter.rs +++ b/lykiadb-server/src/engine/interpreter.rs @@ -142,7 +142,7 @@ impl LoopStack { if self.is_loops_empty() { return None; } - return self.ongoing_loops.last(); + self.ongoing_loops.last() } pub fn set_last_loop(&mut self, to: LoopState) { @@ -259,13 +259,13 @@ impl Interpreter { self.env_man.read().unwrap().read_at( self.env, unwrapped, - &name, + name, &self.interner.get_or_intern(name), ) } else { self.env_man.read().unwrap().read( self.root_env, - &name, + name, &self.interner.get_or_intern(name), ) } @@ -283,7 +283,7 @@ impl Interpreter { for (i, param) in parameters.iter().enumerate() { // TODO: Remove clone here - write_guard.declare(fn_env, param.clone(), arguments.get(i).unwrap().clone()); + write_guard.declare(fn_env, *param, arguments.get(i).unwrap().clone()); } drop(write_guard); diff --git a/lykiadb-server/src/engine/mod.rs b/lykiadb-server/src/engine/mod.rs index e502fb9d..98f594c2 100644 --- a/lykiadb-server/src/engine/mod.rs +++ b/lykiadb-server/src/engine/mod.rs @@ -97,7 +97,7 @@ pub mod test_helpers { .split(',') .map(|flag| { let kv: Vec<&str> = flag.split('=').collect(); - return (kv[0].trim(), kv[1].trim()); + (kv[0].trim(), kv[1].trim()) }) .fold(std::collections::HashMap::new(), |mut acc, (k, v)| { acc.insert(k, v); diff --git a/lykiadb-server/src/value/callable.rs b/lykiadb-server/src/value/callable.rs index 13c66c05..646dced0 100644 --- a/lykiadb-server/src/value/callable.rs +++ b/lykiadb-server/src/value/callable.rs @@ -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 { name, .. } => write!(f, "{}", ""), + Function::UserDefined { .. } => write!(f, ""), } } } diff --git a/lykiadb-server/src/value/environment.rs b/lykiadb-server/src/value/environment.rs index 18fa1887..fa010b7f 100644 --- a/lykiadb-server/src/value/environment.rs +++ b/lykiadb-server/src/value/environment.rs @@ -3,7 +3,7 @@ use core::panic; use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; use std::borrow::{Borrow, BorrowMut}; -use string_interner::{symbol::SymbolU32, StringInterner, Symbol}; +use string_interner::symbol::SymbolU32; use super::RV; @@ -191,7 +191,7 @@ mod test { env_man.declare(env, interner.get_or_intern("five"), RV::Num(5.0)); assert_eq!( env_man - .read(env, &"five", &interner.get_or_intern("five")) + .read(env, "five", &interner.get_or_intern("five")) .unwrap(), RV::Num(5.0) ); @@ -206,7 +206,7 @@ mod test { let child = env_man.push(Some(parent)); assert_eq!( env_man - .read(child, &"five", &interner.get_or_intern("five")) + .read(child, "five", &interner.get_or_intern("five")) .unwrap(), RV::Num(5.0) ); @@ -220,17 +220,17 @@ mod test { 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)) + .assign(child, "five", interner.get_or_intern("five"), RV::Num(5.1)) .unwrap(); assert_eq!( env_man - .read(parent, &"five", &interner.get_or_intern("five")) + .read(parent, "five", &interner.get_or_intern("five")) .unwrap(), RV::Num(5.1) ); assert_eq!( env_man - .read(child, &"five", &interner.get_or_intern("five")) + .read(child, "five", &interner.get_or_intern("five")) .unwrap(), RV::Num(5.1) ); @@ -242,7 +242,7 @@ mod test { let mut interner = get_interner(); let env = env_man.top(); assert!(env_man - .read(env, &"five", &interner.get_or_intern("five")) + .read(env, "five", &interner.get_or_intern("five")) .is_err()); } @@ -252,7 +252,7 @@ mod test { 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)) + .assign(env, "five", interner.get_or_intern("five"), RV::Num(5.0)) .is_err()); } } From 6e6f238f85f13a53e4405c18344d56f558774e17 Mon Sep 17 00:00:00 2001 From: Vedat Can Keklik Date: Mon, 16 Dec 2024 14:10:08 +0300 Subject: [PATCH 06/14] fix: Removed array-like environments --- lykiadb-server/src/engine/interpreter.rs | 78 +++----- lykiadb-server/src/value/callable.rs | 6 +- lykiadb-server/src/value/environment.rs | 229 +++++++++-------------- 3 files changed, 116 insertions(+), 197 deletions(-) diff --git a/lykiadb-server/src/engine/interpreter.rs b/lykiadb-server/src/engine/interpreter.rs index 39824f32..95fe8c5e 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: root_env, loop_stack: LoopStack::new(), source_processor: SourceProcessor::new(), current_program: None, @@ -256,15 +252,14 @@ impl Interpreter { fn look_up_variable(&mut self, name: &str, expr: &Expr) -> Result { let distance = self.current_program.clone().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, + self.root_env.read( name, &self.interner.get_or_intern(name), ) @@ -274,36 +269,27 @@ impl Interpreter { 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.clone()); - 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 +298,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 } @@ -378,19 +362,15 @@ impl VisitorMut for Interpreter { let distance = self.current_program.clone().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, - self.interner.get_or_intern(&dst.name), - evaluated.clone(), - ) - } else { - self.env_man.write().unwrap().assign( - self.env, &dst.name, self.interner.get_or_intern(&dst.name), evaluated.clone(), ) + } else { + self.root_env.assign( &dst.name, self.interner.get_or_intern(&dst.name), evaluated.clone(),) }; if result.is_err() { return Err(result.err().unwrap()); @@ -457,7 +437,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 +448,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 +580,20 @@ 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.env.define( self.interner.get_or_intern(&dst.name), evaluated.clone(), ); } 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..da9cee5a 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>, }, } diff --git a/lykiadb-server/src/value/environment.rs b/lykiadb-server/src/value/environment.rs index fa010b7f..54723140 100644 --- a/lykiadb-server/src/value/environment.rs +++ b/lykiadb-server/src/value/environment.rs @@ -1,32 +1,16 @@ 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, +pub struct EnvironmentFrame { + map: RwLock>, + pub parent: Option>, } -#[derive(Debug)] -pub struct Environment { - envs: Vec, -} - -impl Default for Environment { - fn default() -> Self { - Self::new() - } -} #[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)] pub enum EnvironmentError { @@ -39,142 +23,102 @@ pub enum EnvironmentError { Other { message: String }, } +macro_rules! env_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 +impl EnvironmentFrame { + pub fn new(parent: Option>) -> EnvironmentFrame { + EnvironmentFrame { parent, map: RwLock::new(FxHashMap::default()) } } - 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) - } - - 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, + &self, 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); + 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); - } - - Ok(true) + env_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 { + if self.map.read().unwrap().contains_key(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(self.map.read().unwrap().get(key_sym).unwrap().clone()); } - - Err(HaltReason::Error( - EnvironmentError::Other { - message: format!("Variable '{}' was not found", key), - } - .into(), - )) + return 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()); - } - if self.envs[env_id.0].parent.is_some() { - let pref = self.envs[env_id.0].parent.unwrap(); - return self.ancestor(pref, distance - 1); - } - panic!("Invalid variable distance."); + env_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 +129,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,14 +142,13 @@ 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")) + child + .read("five", &interner.get_or_intern("five")) .unwrap(), RV::Num(5.0) ); @@ -214,23 +156,24 @@ mod test { #[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")) + 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")) + child.read("five", &interner.get_or_intern("five")) .unwrap(), RV::Num(5.1) ); @@ -238,21 +181,19 @@ mod test { #[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")) + 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()); } } From 02bbe70aeb189edb860ba7450727ba6854866837 Mon Sep 17 00:00:00 2001 From: Vedat Can Keklik Date: Mon, 16 Dec 2024 14:10:24 +0300 Subject: [PATCH 07/14] fix: fmt --- lykiadb-server/src/engine/error.rs | 1 - lykiadb-server/src/engine/interpreter.rs | 22 +++++---- lykiadb-server/src/value/callable.rs | 2 +- lykiadb-server/src/value/environment.rs | 60 +++++++++++------------- 4 files changed, 41 insertions(+), 44 deletions(-) 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 95fe8c5e..625a26dd 100644 --- a/lykiadb-server/src/engine/interpreter.rs +++ b/lykiadb-server/src/engine/interpreter.rs @@ -259,10 +259,7 @@ impl Interpreter { &self.interner.get_or_intern(name), ) } else { - self.root_env.read( - name, - &self.interner.get_or_intern(name), - ) + self.root_env.read(name, &self.interner.get_or_intern(name)) } } @@ -370,7 +367,11 @@ impl VisitorMut for Interpreter { evaluated.clone(), ) } else { - self.root_env.assign( &dst.name, self.interner.get_or_intern(&dst.name), evaluated.clone(),) + self.root_env.assign( + &dst.name, + self.interner.get_or_intern(&dst.name), + evaluated.clone(), + ) }; if result.is_err() { return Err(result.err().unwrap()); @@ -587,13 +588,14 @@ impl VisitorMut for Interpreter { } Stmt::Declaration { dst, expr, .. } => { let evaluated = self.visit_expr(expr)?; - self.env.define( - self.interner.get_or_intern(&dst.name), - evaluated.clone(), - ); + self.env + .define(self.interner.get_or_intern(&dst.name), evaluated.clone()); } Stmt::Block { body: stmts, .. } => { - return self.execute_block(stmts, Arc::new(EnvironmentFrame::new(Some(Arc::clone(&self.env))))); + 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 da9cee5a..f2c8e61c 100644 --- a/lykiadb-server/src/value/callable.rs +++ b/lykiadb-server/src/value/callable.rs @@ -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 54723140..0460a21e 100644 --- a/lykiadb-server/src/value/environment.rs +++ b/lykiadb-server/src/value/environment.rs @@ -11,7 +11,6 @@ pub struct EnvironmentFrame { pub parent: Option>, } - #[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)] pub enum EnvironmentError { /*AssignmentToUndefined { @@ -33,7 +32,6 @@ macro_rules! env_ancestor { }}; } - impl From for ExecutionError { fn from(err: EnvironmentError) -> Self { ExecutionError::Environment(err) @@ -42,19 +40,17 @@ impl From for ExecutionError { impl EnvironmentFrame { pub fn new(parent: Option>) -> EnvironmentFrame { - EnvironmentFrame { parent, map: RwLock::new(FxHashMap::default()) } + EnvironmentFrame { + parent, + map: RwLock::new(FxHashMap::default()), + } } pub fn define(&self, name: SymbolU32, value: RV) { self.map.write().unwrap().insert(name, value); } - pub fn assign( - &self, - key: &str, - key_sym: SymbolU32, - value: RV, - ) -> Result { + 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); @@ -67,7 +63,7 @@ impl EnvironmentFrame { } .into(), )), - |parent| parent.as_ref().assign(key, key_sym, value) + |parent| parent.as_ref().assign(key, key_sym, value), ) } @@ -94,7 +90,7 @@ impl EnvironmentFrame { .into(), )), |parent| parent.read(key, key_sym), - ) + ); } pub fn read_at( @@ -105,13 +101,18 @@ impl EnvironmentFrame { ) -> Result { env_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())) + .read() + .unwrap() + .get(&key_sym) + .map_or( + Err(HaltReason::Error( + EnvironmentError::Other { + message: format!("Variable '{}' was not found", key), + } + .into(), + )), + |v| Ok(v.clone()), + ) } } @@ -147,9 +148,7 @@ mod test { root.define(interner.get_or_intern("five"), RV::Num(5.0)); let child = super::EnvironmentFrame::new(Some(Arc::new(root))); assert_eq!( - child - .read("five", &interner.get_or_intern("five")) - .unwrap(), + child.read("five", &interner.get_or_intern("five")).unwrap(), RV::Num(5.0) ); } @@ -158,23 +157,22 @@ mod test { fn test_write_to_parent() { let root = Arc::new(super::EnvironmentFrame::new(None)); let mut interner = get_interner(); - + 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)) + + child + .assign("five", interner.get_or_intern("five"), RV::Num(5.1)) .unwrap(); assert_eq!( - root.read("five", &interner.get_or_intern("five")) - .unwrap(), + root.read("five", &interner.get_or_intern("five")).unwrap(), RV::Num(5.1) ); assert_eq!( - child.read("five", &interner.get_or_intern("five")) - .unwrap(), + child.read("five", &interner.get_or_intern("five")).unwrap(), RV::Num(5.1) ); } @@ -183,9 +181,7 @@ mod test { fn test_read_undefined_variable() { let env = super::EnvironmentFrame::new(None); let mut interner = get_interner(); - assert!(env - .read("five", &interner.get_or_intern("five")) - .is_err()); + assert!(env.read("five", &interner.get_or_intern("five")).is_err()); } #[test] From 32548b6e33abd4537c627116ecb71edb4ba8d946 Mon Sep 17 00:00:00 2001 From: Vedat Can Keklik Date: Mon, 16 Dec 2024 14:10:48 +0300 Subject: [PATCH 08/14] fix: clippy --- lykiadb-server/src/engine/interpreter.rs | 2 +- lykiadb-server/src/value/environment.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lykiadb-server/src/engine/interpreter.rs b/lykiadb-server/src/engine/interpreter.rs index 625a26dd..dadf2fa7 100644 --- a/lykiadb-server/src/engine/interpreter.rs +++ b/lykiadb-server/src/engine/interpreter.rs @@ -198,7 +198,7 @@ impl Interpreter { } Interpreter { env: root_env.clone(), - root_env: root_env, + root_env, loop_stack: LoopStack::new(), source_processor: SourceProcessor::new(), current_program: None, diff --git a/lykiadb-server/src/value/environment.rs b/lykiadb-server/src/value/environment.rs index 0460a21e..f43bae27 100644 --- a/lykiadb-server/src/value/environment.rs +++ b/lykiadb-server/src/value/environment.rs @@ -82,7 +82,7 @@ impl EnvironmentFrame { // TODO(vck): Remove clone return Ok(self.map.read().unwrap().get(key_sym).unwrap().clone()); } - return self.parent.as_ref().map_or( + self.parent.as_ref().map_or( Err(HaltReason::Error( EnvironmentError::Other { message: format!("Variable '{}' was not found", key), @@ -90,7 +90,7 @@ impl EnvironmentFrame { .into(), )), |parent| parent.read(key, key_sym), - ); + ) } pub fn read_at( @@ -103,7 +103,7 @@ impl EnvironmentFrame { .map .read() .unwrap() - .get(&key_sym) + .get(key_sym) .map_or( Err(HaltReason::Error( EnvironmentError::Other { From 75e36891285c934650af420edee4402c351bbfe4 Mon Sep 17 00:00:00 2001 From: Vedat Can Keklik Date: Mon, 16 Dec 2024 14:49:09 +0300 Subject: [PATCH 09/14] fix: Minor tweak for surprising boost --- lykiadb-server/src/engine/interpreter.rs | 8 ++++---- lykiadb-server/src/value/environment.rs | 18 +++++++++++++++--- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/lykiadb-server/src/engine/interpreter.rs b/lykiadb-server/src/engine/interpreter.rs index dadf2fa7..a4dc46a9 100644 --- a/lykiadb-server/src/engine/interpreter.rs +++ b/lykiadb-server/src/engine/interpreter.rs @@ -250,7 +250,7 @@ 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 { EnvironmentFrame::read_at( &self.env, @@ -285,7 +285,7 @@ impl Interpreter { statements: &Vec, env_opt: Arc, ) -> Result { - let previous = std::mem::replace(&mut self.env, env_opt.clone()); + let previous = std::mem::replace(&mut self.env, env_opt); let mut ret = Ok(RV::Undefined); @@ -356,7 +356,7 @@ 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 { EnvironmentFrame::assign_at( @@ -589,7 +589,7 @@ impl VisitorMut for Interpreter { Stmt::Declaration { dst, expr, .. } => { let evaluated = self.visit_expr(expr)?; self.env - .define(self.interner.get_or_intern(&dst.name), evaluated.clone()); + .define(self.interner.get_or_intern(&dst.name), evaluated); } Stmt::Block { body: stmts, .. } => { return self.execute_block( diff --git a/lykiadb-server/src/value/environment.rs b/lykiadb-server/src/value/environment.rs index f43bae27..3f78af82 100644 --- a/lykiadb-server/src/value/environment.rs +++ b/lykiadb-server/src/value/environment.rs @@ -22,7 +22,7 @@ pub enum EnvironmentError { Other { message: String }, } -macro_rules! env_ancestor { +macro_rules! to_ancestor { ($init:expr, $distance:expr) => {{ let mut env = $init; for _ in 0..$distance { @@ -74,7 +74,13 @@ impl EnvironmentFrame { key_sym: SymbolU32, value: RV, ) -> Result { - env_ancestor!(env, distance).assign(key, key_sym, value) + if distance == 0 { + return env.assign(key, key_sym, value); + } + 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, key: &str, key_sym: &SymbolU32) -> Result { @@ -99,7 +105,13 @@ impl EnvironmentFrame { key: &str, key_sym: &SymbolU32, ) -> Result { - env_ancestor!(env, distance) + if distance == 0 { + return env.read(key, key_sym); + } + if distance == 1 && env.parent.is_some() { + return env.parent.as_ref().unwrap().read(key, key_sym); + } + to_ancestor!(env, distance) .map .read() .unwrap() From 568c9814c176bce25f60ec60fe67884c444caf1e Mon Sep 17 00:00:00 2001 From: Vedat Can Keklik Date: Mon, 16 Dec 2024 15:39:37 +0300 Subject: [PATCH 10/14] fix: Simpler read --- lykiadb-server/src/value/environment.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lykiadb-server/src/value/environment.rs b/lykiadb-server/src/value/environment.rs index 3f78af82..e8934c90 100644 --- a/lykiadb-server/src/value/environment.rs +++ b/lykiadb-server/src/value/environment.rs @@ -84,9 +84,10 @@ impl EnvironmentFrame { } pub fn read(&self, key: &str, key_sym: &SymbolU32) -> Result { - if self.map.read().unwrap().contains_key(key_sym) { + let guard = self.map.read().unwrap(); + if let Some(value) = guard.get(key_sym) { // TODO(vck): Remove clone - return Ok(self.map.read().unwrap().get(key_sym).unwrap().clone()); + return Ok(value.clone()); } self.parent.as_ref().map_or( Err(HaltReason::Error( From ac899af5cb6717541c0e513c3cf6d7322695b763 Mon Sep 17 00:00:00 2001 From: Vedat Can Keklik Date: Mon, 16 Dec 2024 19:24:20 +0300 Subject: [PATCH 11/14] fix: Moved source processing code to lang --- lykiadb-lang/src/lib.rs | 65 +++++++++++++++++++++++- lykiadb-server/src/comm/mod.rs | 8 --- lykiadb-server/src/engine/error.rs | 60 ++++++++-------------- lykiadb-server/src/engine/interpreter.rs | 46 +++-------------- lykiadb-server/src/engine/mod.rs | 7 --- lykiadb-shell/src/main.rs | 12 +---- 6 files changed, 95 insertions(+), 103 deletions(-) diff --git a/lykiadb-lang/src/lib.rs b/lykiadb-lang/src/lib.rs index 978af0b0..041fd223 100644 --- a/lykiadb-lang/src/lib.rs +++ b/lykiadb-lang/src/lib.rs @@ -1,13 +1,15 @@ use std::{ - fmt::{Display, Formatter, Result}, + fmt::{Display, Formatter}, hash::Hash, sync::Arc, }; use ast::expr::Expr; use derivative::Derivative; +use parser::{program::Program, resolver::{ResolveError, Resolver}, ParseError, Parser}; use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; +use tokenizer::scanner::{ScanError, Scanner}; pub mod ast; pub mod parser; @@ -107,7 +109,66 @@ impl Identifier { } impl Display for Identifier { - fn fmt(&self, f: &mut Formatter) -> Result { + fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { write!(f, "{}", self.name) } } + + +#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)] +pub enum LangError { + Parse(ParseError), + Scan(ScanError), + Resolve(ResolveError) +} + +impl From for LangError { + fn from(err: ParseError) -> Self { + LangError::Parse(err) + } +} + +impl From for LangError { + fn from(err: ScanError) -> Self { + LangError::Scan(err) + } +} + +impl From for LangError { + fn from(err: ResolveError) -> Self { + LangError::Resolve(err) + } +} + +pub struct SourceProcessor { + scopes: Scopes, + locals: Locals, +} + +impl Default for SourceProcessor { + fn default() -> Self { + Self::new() + } +} + +impl SourceProcessor { + pub fn new() -> SourceProcessor { + SourceProcessor { + scopes: vec![], + locals: FxHashMap::default(), + } + } + + pub fn process(&mut self, source: &str) -> Result { + let tokens = Scanner::scan(source)?; + let mut program = Parser::parse(&tokens)?; + let mut resolver = Resolver::new(self.scopes.clone(), &program, Some(self.locals.clone())); + let (scopes, locals) = resolver.resolve()?; + + self.scopes = scopes; + self.locals.clone_from(&locals); + program.set_locals(self.locals.clone()); + + Ok(program) + } +} \ No newline at end of file diff --git a/lykiadb-server/src/comm/mod.rs b/lykiadb-server/src/comm/mod.rs index 512a2f99..1adf5db0 100644 --- a/lykiadb-server/src/comm/mod.rs +++ b/lykiadb-server/src/comm/mod.rs @@ -16,7 +16,6 @@ use crate::engine::error::ExecutionError; #[derive(Debug, Clone, Serialize, Deserialize)] pub enum Request { Run(String), - Ast(String), } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -70,13 +69,6 @@ impl ServerSession { let start = Instant::now(); match &message { Message::Request(req) => match req { - Request::Ast(source) => { - let ast = self.runtime.ast(source); - self.conn - .write(Message::Response(Response::Program(ast.unwrap()))) - .await - .unwrap(); - } Request::Run(command) => { let execution = self.runtime.interpret(command); let response = if execution.is_ok() { diff --git a/lykiadb-server/src/engine/error.rs b/lykiadb-server/src/engine/error.rs index c61fc7e2..1fdfdd4b 100644 --- a/lykiadb-server/src/engine/error.rs +++ b/lykiadb-server/src/engine/error.rs @@ -4,17 +4,13 @@ use crate::{plan::PlannerError, value::environment::EnvironmentError}; use super::interpreter::InterpretError; use lykiadb_lang::{ - parser::{resolver::ResolveError, ParseError}, - tokenizer::scanner::ScanError, - Span, + parser::ParseError, tokenizer::scanner::ScanError, LangError, Span }; use serde::{Deserialize, Serialize}; #[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)] pub enum ExecutionError { - Scan(ScanError), - Parse(ParseError), - Resolve(ResolveError), + Lang(LangError), Interpret(InterpretError), Environment(EnvironmentError), Plan(PlannerError), @@ -26,18 +22,6 @@ impl Display for ExecutionError { } } -impl From for ExecutionError { - fn from(err: ParseError) -> Self { - ExecutionError::Parse(err) - } -} - -impl From for ExecutionError { - fn from(err: ScanError) -> Self { - ExecutionError::Scan(err) - } -} - pub fn report_error( source_name: &str, source: &str, @@ -64,24 +48,24 @@ pub fn report_error( }; match error { - ExecutionError::Scan(ScanError::UnexpectedCharacter { span }) => { + ExecutionError::Lang(LangError::Scan(ScanError::UnexpectedCharacter { span })) => { print("Unexpected character", "Remove this character", span); } - ExecutionError::Scan(ScanError::UnterminatedString { span }) => { + ExecutionError::Lang(LangError::Scan(ScanError::UnterminatedString { span })) => { print( "Unterminated string", "Terminate the string with a double quote (\").", span, ); } - ExecutionError::Scan(ScanError::MalformedNumberLiteral { span }) => { + ExecutionError::Lang(LangError::Scan(ScanError::MalformedNumberLiteral { span })) => { print( "Malformed number literal", "Make sure that number literal is up to spec.", span, ); } - ExecutionError::Parse(ParseError::MissingToken { token, expected }) => { + ExecutionError::Lang(LangError::Parse(ParseError::MissingToken { token, expected })) => { print( "Missing token", &format!( @@ -92,17 +76,17 @@ pub fn report_error( token.span, ); } - ExecutionError::Parse(ParseError::NoTokens) => { + ExecutionError::Lang(LangError::Parse(ParseError::NoTokens)) => { print("There is nothing to parse", "", Span::default()); } - ExecutionError::Parse(ParseError::InvalidAssignmentTarget { left }) => { + ExecutionError::Lang(LangError::Parse(ParseError::InvalidAssignmentTarget { left })) => { print( "Invalid assignment target", &format!("No values can be assigned to {}", left.lexeme.unwrap()), left.span, ); } - ExecutionError::Parse(ParseError::UnexpectedToken { token }) => { + ExecutionError::Lang(LangError::Parse(ParseError::UnexpectedToken { token })) => { print( "Unexpected token", &format!( @@ -187,14 +171,14 @@ mod tests { #[test] fn test_scanner_unterminated_string() { let source = r#"let x = "unterminated"#; - let error = ExecutionError::Scan(ScanError::UnterminatedString { + let error = ExecutionError::Lang(LangError::Scan(ScanError::UnterminatedString { span: Span { start: 8, end: 21, line: 0, line_end: 0, }, - }); + })); let output = capture_error_output("test.txt", source, error); assert!(output.contains("Unterminated string")); @@ -204,14 +188,14 @@ mod tests { #[test] fn test_scanner_malformed_number() { let source = "let x = 123.456.789"; - let error = ExecutionError::Scan(ScanError::MalformedNumberLiteral { + let error = ExecutionError::Lang(LangError::Scan(ScanError::MalformedNumberLiteral { span: Span { start: 8, end: 19, line: 0, line_end: 0, }, - }); + })); let output = capture_error_output("test.txt", source, error); assert!(output.contains("Malformed number literal")); @@ -222,7 +206,7 @@ mod tests { #[test] fn test_parser_missing_token() { let source = "var x = "; - let error = ExecutionError::Parse(ParseError::MissingToken { + let error = ExecutionError::Lang(LangError::Parse(ParseError::MissingToken { token: Token { tok_type: kw!(Keyword::Var), lexeme: Some("var".to_string()), @@ -235,7 +219,7 @@ mod tests { literal: None, }, expected: TokenType::Identifier { dollar: true }, - }); + })); let output = capture_error_output("test.txt", source, error); assert!(output.contains("Missing token")); @@ -245,7 +229,7 @@ mod tests { #[test] fn test_parser_no_tokens() { let source = ""; - let error = ExecutionError::Parse(ParseError::NoTokens); + let error = ExecutionError::Lang(LangError::Parse(ParseError::NoTokens)); let output = capture_error_output("test.txt", source, error); @@ -255,7 +239,7 @@ mod tests { #[test] fn test_parser_unexpected_token() { let source = "let x = ;"; - let error = ExecutionError::Parse(ParseError::UnexpectedToken { + let error = ExecutionError::Lang(LangError::Parse(ParseError::UnexpectedToken { token: Token { tok_type: sym!(Symbol::Semicolon), lexeme: Some(";".to_string()), @@ -267,7 +251,7 @@ mod tests { }, literal: None, }, - }); + })); let output = capture_error_output("test.txt", source, error); assert!(output.contains("Unexpected token")); @@ -294,7 +278,7 @@ mod tests { #[test] fn test_parser_invalid_assignment() { let source = "5 = 10"; - let error = ExecutionError::Parse(ParseError::InvalidAssignmentTarget { + let error = ExecutionError::Lang(LangError::Parse(ParseError::InvalidAssignmentTarget { left: Token { tok_type: TokenType::Num, lexeme: Some("5".to_string()), @@ -306,7 +290,7 @@ mod tests { }, literal: Some(Literal::Num(5.0)), }, - }); + })); let output = capture_error_output("test.txt", source, error); assert!(output.contains("Invalid assignment target")); @@ -394,14 +378,14 @@ mod tests { #[test] fn test_scan_error_reporting() { let source = "let x = @"; - let error = ExecutionError::Scan(ScanError::UnexpectedCharacter { + let error = ExecutionError::Lang(LangError::Scan(ScanError::UnexpectedCharacter { span: Span { start: 8, end: 9, line: 0, line_end: 0, }, - }); + })); let output = capture_error_output("test.txt", source, error); assert!(output.contains("Unexpected character")); diff --git a/lykiadb-server/src/engine/interpreter.rs b/lykiadb-server/src/engine/interpreter.rs index a4dc46a9..560e3a8c 100644 --- a/lykiadb-server/src/engine/interpreter.rs +++ b/lykiadb-server/src/engine/interpreter.rs @@ -2,12 +2,9 @@ use lykiadb_lang::ast::expr::{Expr, Operation, RangeKind}; use lykiadb_lang::ast::stmt::Stmt; use lykiadb_lang::ast::visitor::VisitorMut; use lykiadb_lang::parser::program::Program; -use lykiadb_lang::parser::resolver::Resolver; -use lykiadb_lang::parser::Parser; -use lykiadb_lang::tokenizer::scanner::Scanner; -use lykiadb_lang::Span; +use lykiadb_lang::{LangError, SourceProcessor, Span}; use lykiadb_lang::Spanned; -use lykiadb_lang::{Literal, Locals, Scopes}; +use lykiadb_lang::Literal; use pretty_assertions::assert_eq; use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; @@ -27,39 +24,6 @@ use crate::value::{eval::eval_binary, RV}; use std::sync::Arc; use std::vec; -pub struct SourceProcessor { - scopes: Scopes, - locals: Locals, -} - -impl Default for SourceProcessor { - fn default() -> Self { - Self::new() - } -} - -impl SourceProcessor { - pub fn new() -> SourceProcessor { - SourceProcessor { - scopes: vec![], - locals: FxHashMap::default(), - } - } - - pub fn process(&mut self, source: &str) -> Result { - let tokens = Scanner::scan(source)?; - let mut program = Parser::parse(&tokens)?; - let mut resolver = Resolver::new(self.scopes.clone(), &program, Some(self.locals.clone())); - let (scopes, locals) = resolver.resolve().unwrap(); - - self.scopes = scopes; - self.locals.clone_from(&locals); - program.set_locals(self.locals.clone()); - - Ok(program) - } -} - #[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)] pub enum InterpretError { NotCallable { @@ -88,6 +52,12 @@ impl From for ExecutionError { } } +impl From for ExecutionError { + fn from(err: LangError) -> Self { + ExecutionError::Lang(err) + } +} + #[derive(Debug)] pub enum HaltReason { Error(ExecutionError), diff --git a/lykiadb-server/src/engine/mod.rs b/lykiadb-server/src/engine/mod.rs index 98f594c2..87228ea8 100644 --- a/lykiadb-server/src/engine/mod.rs +++ b/lykiadb-server/src/engine/mod.rs @@ -26,13 +26,6 @@ impl Runtime { Runtime { mode, interpreter } } - pub fn ast(&mut self, source: &str) -> Result { - let tokens = Scanner::scan(source)?; - let program = Parser::parse(&tokens)?; - let json = program.to_json(); - Ok(json) - } - pub fn interpret(&mut self, source: &str) -> Result { let out = self.interpreter.interpret(source); diff --git a/lykiadb-shell/src/main.rs b/lykiadb-shell/src/main.rs index 1decb2f0..65fa92e5 100644 --- a/lykiadb-shell/src/main.rs +++ b/lykiadb-shell/src/main.rs @@ -12,9 +12,6 @@ use lykiadb_connect::{get_session, report_error, Message, Protocol, Request, Res struct Args { /// Path to the script to be executed filename: Option, - - #[clap(short, long, default_value = "false")] - print_ast: bool, } struct Shell; @@ -45,7 +42,6 @@ impl Shell { &mut self, session: &mut impl ClientSession, filename: &str, - print_ast: bool, ) { let file = File::open(filename).expect("File couldn't be opened."); @@ -55,11 +51,7 @@ impl Shell { .read_to_string(&mut content) .expect("File couldn't be read."); - let msg = if print_ast { - Message::Request(Request::Ast(content.to_string())) - } else { - Message::Request(Request::Run(content.to_string())) - }; + let msg = Message::Request(Request::Run(content.to_string())); let response = session.send_receive(msg).await.unwrap(); self.handle_response(filename, &content, response); @@ -87,7 +79,7 @@ async fn main() { match args.filename { Some(filename) => { shell - .run_file(&mut session, &filename, args.print_ast) + .run_file(&mut session, &filename) .await } None => shell.run_repl(&mut session).await, From 5218a7d12c4b716f8c12d11fd0a4b4e63465d2ef Mon Sep 17 00:00:00 2001 From: Vedat Can Keklik Date: Mon, 16 Dec 2024 19:38:48 +0300 Subject: [PATCH 12/14] fix: Organization fix --- lykiadb-lang/src/ast/expr.rs | 10 +-- lykiadb-lang/src/ast/mod.rs | 107 ++++++++++++++++++++++- lykiadb-lang/src/ast/sql.rs | 3 +- lykiadb-lang/src/ast/stmt.rs | 13 +-- lykiadb-lang/src/lib.rs | 105 ---------------------- lykiadb-lang/src/parser/mod.rs | 4 +- lykiadb-lang/src/parser/resolver.rs | 5 +- lykiadb-lang/src/tokenizer/scanner.rs | 2 +- lykiadb-lang/src/tokenizer/token.rs | 3 +- lykiadb-server/src/engine/error.rs | 7 +- lykiadb-server/src/engine/interpreter.rs | 5 +- lykiadb-server/src/plan/mod.rs | 9 +- lykiadb-server/src/plan/planner.rs | 9 +- lykiadb-server/src/plan/scope.rs | 2 +- 14 files changed, 133 insertions(+), 151 deletions(-) diff --git a/lykiadb-lang/src/ast/expr.rs b/lykiadb-lang/src/ast/expr.rs index 29d647d1..0b04f932 100644 --- a/lykiadb-lang/src/ast/expr.rs +++ b/lykiadb-lang/src/ast/expr.rs @@ -3,16 +3,10 @@ use serde::{Deserialize, Serialize}; use std::{fmt::Display, sync::Arc}; -use crate::{Identifier, Span, Spanned}; - use super::{ - sql::{SqlDelete, SqlInsert, SqlSelect, SqlUpdate}, - stmt::Stmt, - AstNode, + sql::{SqlDelete, SqlInsert, SqlSelect, SqlUpdate}, stmt::Stmt, AstNode, Identifier, Literal, Span, Spanned }; -use crate::Literal; - #[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)] #[serde(tag = "@type")] pub enum Operation { @@ -497,7 +491,7 @@ impl Expr { pub mod test { use std::collections::HashSet; - use crate::{ast::expr::Expr, Literal, Span}; + use crate::ast::expr::Expr; use super::*; diff --git a/lykiadb-lang/src/ast/mod.rs b/lykiadb-lang/src/ast/mod.rs index b7962967..2848b130 100644 --- a/lykiadb-lang/src/ast/mod.rs +++ b/lykiadb-lang/src/ast/mod.rs @@ -1,4 +1,13 @@ -use crate::Spanned; +use std::{ + fmt::{Display, Formatter}, + hash::Hash, + sync::Arc, +}; + +use derivative::Derivative; +use expr::Expr; +use rustc_hash::FxHashMap; +use serde::{Deserialize, Serialize}; pub mod expr; pub mod sql; @@ -8,3 +17,99 @@ pub mod visitor; pub trait AstNode: Spanned { fn get_id(&self) -> usize; } + +#[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, Hash)] +pub struct Span { + pub start: usize, + pub end: usize, + pub line: u32, + pub line_end: u32, +} + +pub trait Spanned { + fn get_span(&self) -> Span; +} + +impl Spanned for Span { + fn get_span(&self) -> Span { + *self + } +} + +impl Span { + pub fn merge(&self, other: &Span) -> Span { + Span { + start: self.start.min(other.start), + end: self.end.max(other.end), + line: self.line.min(other.line), + line_end: self.line_end.min(other.line_end), + } + } +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub enum Literal { + Str(Arc), + Num(f64), + Bool(bool), + Undefined, + Object(FxHashMap>), + Array(Vec), + NaN, + Null, +} + +impl Literal { + pub fn as_str(&self) -> Option<&str> { + match self { + Literal::Str(s) => Some(s), + _ => None, + } + } +} + +impl Hash for Literal { + fn hash(&self, state: &mut H) { + match self { + Literal::Str(s) => s.hash(state), + Literal::Num(n) => n.to_bits().hash(state), + Literal::Bool(b) => b.hash(state), + Literal::Object(o) => (o as *const _ as usize).hash(state), + Literal::Array(a) => a.hash(state), + // + Literal::Undefined => "undefined".hash(state), + Literal::NaN => "NaN".hash(state), + Literal::Null => "null".hash(state), + } + } +} + +impl Eq for Literal {} + +#[derive(Debug, Clone, Serialize, Deserialize, Derivative)] +#[serde(tag = "@type")] +#[derivative(Eq, PartialEq, Hash)] +pub struct Identifier { + pub name: String, + pub dollar: bool, + #[serde(skip)] + #[derivative(PartialEq = "ignore")] + #[derivative(Hash = "ignore")] + pub span: Span, +} + +impl Identifier { + pub fn new(name: &str, dollar: bool) -> Self { + Identifier { + name: name.to_string(), + dollar, + span: Span::default(), + } + } +} + +impl Display for Identifier { + fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { + write!(f, "{}", self.name) + } +} \ No newline at end of file diff --git a/lykiadb-lang/src/ast/sql.rs b/lykiadb-lang/src/ast/sql.rs index 9082cece..9ad69b74 100644 --- a/lykiadb-lang/src/ast/sql.rs +++ b/lykiadb-lang/src/ast/sql.rs @@ -1,7 +1,6 @@ -use crate::Identifier; use serde::{Deserialize, Serialize}; -use super::expr::Expr; +use super::{expr::Expr, Identifier}; // Enums diff --git a/lykiadb-lang/src/ast/stmt.rs b/lykiadb-lang/src/ast/stmt.rs index 73bc5b03..37b5beea 100644 --- a/lykiadb-lang/src/ast/stmt.rs +++ b/lykiadb-lang/src/ast/stmt.rs @@ -1,9 +1,7 @@ use derivative::Derivative; use serde::{Deserialize, Serialize}; -use crate::{Identifier, Span, Spanned}; - -use super::expr::Expr; +use super::{expr::Expr, Identifier, Span, Spanned}; #[derive(Debug, Serialize, Deserialize, Clone, Derivative)] #[serde(tag = "@type")] @@ -106,13 +104,10 @@ impl Spanned for Stmt { mod test { use std::collections::HashSet; - use crate::{ - ast::{ + use crate::ast::{ expr::{test::create_simple_add_expr, Expr}, - stmt::Stmt, - }, - Span, - }; + stmt::Stmt, Span, + }; pub fn create_simple_block_stmt(a: Expr, b: Expr) -> Stmt { Stmt::Block { diff --git a/lykiadb-lang/src/lib.rs b/lykiadb-lang/src/lib.rs index 041fd223..48fa4b81 100644 --- a/lykiadb-lang/src/lib.rs +++ b/lykiadb-lang/src/lib.rs @@ -1,11 +1,3 @@ -use std::{ - fmt::{Display, Formatter}, - hash::Hash, - sync::Arc, -}; - -use ast::expr::Expr; -use derivative::Derivative; use parser::{program::Program, resolver::{ResolveError, Resolver}, ParseError, Parser}; use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; @@ -18,103 +10,6 @@ pub mod tokenizer; pub type Scopes = Vec>; pub type Locals = FxHashMap; -#[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, Hash)] -pub struct Span { - pub start: usize, - pub end: usize, - pub line: u32, - pub line_end: u32, -} - -pub trait Spanned { - fn get_span(&self) -> Span; -} - -impl Spanned for Span { - fn get_span(&self) -> Span { - *self - } -} - -impl Span { - pub fn merge(&self, other: &Span) -> Span { - Span { - start: self.start.min(other.start), - end: self.end.max(other.end), - line: self.line.min(other.line), - line_end: self.line_end.min(other.line_end), - } - } -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub enum Literal { - Str(Arc), - Num(f64), - Bool(bool), - Undefined, - Object(FxHashMap>), - Array(Vec), - NaN, - Null, -} - -impl Literal { - pub fn as_str(&self) -> Option<&str> { - match self { - Literal::Str(s) => Some(s), - _ => None, - } - } -} - -impl Hash for Literal { - fn hash(&self, state: &mut H) { - match self { - Literal::Str(s) => s.hash(state), - Literal::Num(n) => n.to_bits().hash(state), - Literal::Bool(b) => b.hash(state), - Literal::Object(o) => (o as *const _ as usize).hash(state), - Literal::Array(a) => a.hash(state), - // - Literal::Undefined => "undefined".hash(state), - Literal::NaN => "NaN".hash(state), - Literal::Null => "null".hash(state), - } - } -} - -impl Eq for Literal {} - -#[derive(Debug, Clone, Serialize, Deserialize, Derivative)] -#[serde(tag = "@type")] -#[derivative(Eq, PartialEq, Hash)] -pub struct Identifier { - pub name: String, - pub dollar: bool, - #[serde(skip)] - #[derivative(PartialEq = "ignore")] - #[derivative(Hash = "ignore")] - pub span: Span, -} - -impl Identifier { - pub fn new(name: &str, dollar: bool) -> Self { - Identifier { - name: name.to_string(), - dollar, - span: Span::default(), - } - } -} - -impl Display for Identifier { - fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { - write!(f, "{}", self.name) - } -} - - #[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)] pub enum LangError { Parse(ParseError), diff --git a/lykiadb-lang/src/parser/mod.rs b/lykiadb-lang/src/parser/mod.rs index 6f742479..8289eb9b 100644 --- a/lykiadb-lang/src/parser/mod.rs +++ b/lykiadb-lang/src/parser/mod.rs @@ -3,11 +3,11 @@ use self::program::Program; use super::ast::expr::{Expr, Operation}; use super::ast::stmt::Stmt; use crate::ast::expr::RangeKind; +use crate::ast::{Literal, Span, Spanned}; use crate::tokenizer::token::{ Keyword::*, SqlKeyword, SqlKeyword::*, Symbol::*, Token, TokenType, TokenType::*, }; use crate::{kw, skw, sym}; -use crate::{Literal, Span, Spanned}; use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; use std::sync::Arc; @@ -616,7 +616,7 @@ impl<'a> Parser<'a> { && self.in_select_depth > 0 { let head = name.clone(); - let mut tail: Vec = vec![]; + let mut tail: Vec = vec![]; while self.match_next(&sym!(Dot)) { let identifier = self.expected(&Identifier { dollar: false })?.clone(); tail.push(identifier.extract_identifier().unwrap()); diff --git a/lykiadb-lang/src/parser/resolver.rs b/lykiadb-lang/src/parser/resolver.rs index e7dd2ef1..8d53e569 100644 --- a/lykiadb-lang/src/parser/resolver.rs +++ b/lykiadb-lang/src/parser/resolver.rs @@ -1,8 +1,9 @@ use crate::ast::expr::Expr; use crate::ast::stmt::Stmt; use crate::ast::visitor::VisitorMut; -use crate::{Identifier, Literal}; -use crate::{Locals, Scopes, Span}; +use crate::ast::Span; +use crate::ast::{Identifier, Literal}; +use crate::{Locals, Scopes}; use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; diff --git a/lykiadb-lang/src/tokenizer/scanner.rs b/lykiadb-lang/src/tokenizer/scanner.rs index 9b019870..9909f05a 100644 --- a/lykiadb-lang/src/tokenizer/scanner.rs +++ b/lykiadb-lang/src/tokenizer/scanner.rs @@ -1,10 +1,10 @@ use serde::{Deserialize, Serialize}; +use crate::ast::{Span, Literal::*}; use crate::sym; use crate::tokenizer::token::Symbol::*; use crate::tokenizer::token::TokenType::{Eof, Identifier}; use crate::tokenizer::token::*; -use crate::{Literal::*, Span}; use std::iter::{Enumerate, Peekable}; use std::str::Chars; use std::sync::Arc; diff --git a/lykiadb-lang/src/tokenizer/token.rs b/lykiadb-lang/src/tokenizer/token.rs index 3bfc33df..317aec14 100644 --- a/lykiadb-lang/src/tokenizer/token.rs +++ b/lykiadb-lang/src/tokenizer/token.rs @@ -1,7 +1,8 @@ -use crate::{Identifier, Literal, Span}; use phf::phf_map; use serde::{Deserialize, Serialize}; +use crate::ast::{Identifier, Literal, Span}; + #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] pub enum Symbol { Comma, diff --git a/lykiadb-server/src/engine/error.rs b/lykiadb-server/src/engine/error.rs index 1fdfdd4b..a46cdbd6 100644 --- a/lykiadb-server/src/engine/error.rs +++ b/lykiadb-server/src/engine/error.rs @@ -4,7 +4,7 @@ use crate::{plan::PlannerError, value::environment::EnvironmentError}; use super::interpreter::InterpretError; use lykiadb_lang::{ - parser::ParseError, tokenizer::scanner::ScanError, LangError, Span + ast::Span, parser::ParseError, tokenizer::scanner::ScanError, LangError }; use serde::{Deserialize, Serialize}; @@ -156,9 +156,8 @@ mod tests { use super::*; use lykiadb_lang::{ - kw, sym, - tokenizer::token::{Keyword, Symbol, Token, TokenType}, - Identifier, Literal, + ast::{Identifier, Literal}, kw, sym, tokenizer::token::{Keyword, Symbol, Token, TokenType} + }; fn capture_error_output(filename: &str, source: &str, error: ExecutionError) -> String { diff --git a/lykiadb-server/src/engine/interpreter.rs b/lykiadb-server/src/engine/interpreter.rs index 560e3a8c..e0a72afe 100644 --- a/lykiadb-server/src/engine/interpreter.rs +++ b/lykiadb-server/src/engine/interpreter.rs @@ -1,10 +1,9 @@ use lykiadb_lang::ast::expr::{Expr, Operation, RangeKind}; use lykiadb_lang::ast::stmt::Stmt; use lykiadb_lang::ast::visitor::VisitorMut; +use lykiadb_lang::ast::{Literal, Span, Spanned}; use lykiadb_lang::parser::program::Program; -use lykiadb_lang::{LangError, SourceProcessor, Span}; -use lykiadb_lang::Spanned; -use lykiadb_lang::Literal; +use lykiadb_lang::{LangError, SourceProcessor}; use pretty_assertions::assert_eq; use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; diff --git a/lykiadb-server/src/plan/mod.rs b/lykiadb-server/src/plan/mod.rs index 4c9fed8f..b8fb9032 100644 --- a/lykiadb-server/src/plan/mod.rs +++ b/lykiadb-server/src/plan/mod.rs @@ -1,15 +1,12 @@ use std::fmt::Display; -use lykiadb_lang::{ - ast::{ +use lykiadb_lang::ast::{ expr::Expr, sql::{ SqlCollectionIdentifier, SqlCompoundOperator, SqlExpressionSource, SqlJoinType, SqlOrdering, SqlProjection, - }, - }, - Identifier, Span, -}; + }, Identifier, Span, + }; use serde::{Deserialize, Serialize}; use crate::value::RV; diff --git a/lykiadb-server/src/plan/planner.rs b/lykiadb-server/src/plan/planner.rs index c42311ce..b65abcc6 100644 --- a/lykiadb-server/src/plan/planner.rs +++ b/lykiadb-server/src/plan/planner.rs @@ -6,14 +6,11 @@ use crate::{ value::RV, }; -use lykiadb_lang::{ - ast::{ +use lykiadb_lang::ast::{ expr::Expr, sql::{SqlFrom, SqlJoinType, SqlProjection, SqlSelect, SqlSelectCore, SqlSource}, - visitor::VisitorMut, - }, - Spanned, -}; + visitor::VisitorMut, Spanned, + }; use super::{scope::Scope, IntermediateExpr, Node, Plan, PlannerError}; diff --git a/lykiadb-server/src/plan/scope.rs b/lykiadb-server/src/plan/scope.rs index 42669803..675c83c1 100644 --- a/lykiadb-server/src/plan/scope.rs +++ b/lykiadb-server/src/plan/scope.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use lykiadb_lang::{ast::sql::SqlSource, Identifier}; +use lykiadb_lang::ast::{sql::SqlSource, Identifier}; use super::PlannerError; From 1fe8110a1adf1d9e0fb639a0d0dc68cffa2fd127 Mon Sep 17 00:00:00 2001 From: Vedat Can Keklik Date: Mon, 16 Dec 2024 19:39:37 +0300 Subject: [PATCH 13/14] fix: fmt --- lykiadb-lang/src/ast/expr.rs | 4 +++- lykiadb-lang/src/ast/mod.rs | 2 +- lykiadb-lang/src/ast/stmt.rs | 7 ++++--- lykiadb-lang/src/lib.rs | 10 +++++++--- lykiadb-lang/src/tokenizer/scanner.rs | 2 +- lykiadb-server/src/engine/error.rs | 9 ++++----- lykiadb-server/src/plan/mod.rs | 13 +++++++------ lykiadb-server/src/plan/planner.rs | 9 +++++---- lykiadb-shell/src/main.rs | 12 ++---------- 9 files changed, 34 insertions(+), 34 deletions(-) diff --git a/lykiadb-lang/src/ast/expr.rs b/lykiadb-lang/src/ast/expr.rs index 0b04f932..258e9ab9 100644 --- a/lykiadb-lang/src/ast/expr.rs +++ b/lykiadb-lang/src/ast/expr.rs @@ -4,7 +4,9 @@ use serde::{Deserialize, Serialize}; use std::{fmt::Display, sync::Arc}; use super::{ - sql::{SqlDelete, SqlInsert, SqlSelect, SqlUpdate}, stmt::Stmt, AstNode, Identifier, Literal, Span, Spanned + sql::{SqlDelete, SqlInsert, SqlSelect, SqlUpdate}, + stmt::Stmt, + AstNode, Identifier, Literal, Span, Spanned, }; #[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)] diff --git a/lykiadb-lang/src/ast/mod.rs b/lykiadb-lang/src/ast/mod.rs index 2848b130..eccc5d78 100644 --- a/lykiadb-lang/src/ast/mod.rs +++ b/lykiadb-lang/src/ast/mod.rs @@ -112,4 +112,4 @@ impl Display for Identifier { fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { write!(f, "{}", self.name) } -} \ No newline at end of file +} diff --git a/lykiadb-lang/src/ast/stmt.rs b/lykiadb-lang/src/ast/stmt.rs index 37b5beea..0d77532a 100644 --- a/lykiadb-lang/src/ast/stmt.rs +++ b/lykiadb-lang/src/ast/stmt.rs @@ -105,9 +105,10 @@ mod test { use std::collections::HashSet; use crate::ast::{ - expr::{test::create_simple_add_expr, Expr}, - stmt::Stmt, Span, - }; + expr::{test::create_simple_add_expr, Expr}, + stmt::Stmt, + Span, + }; pub fn create_simple_block_stmt(a: Expr, b: Expr) -> Stmt { Stmt::Block { diff --git a/lykiadb-lang/src/lib.rs b/lykiadb-lang/src/lib.rs index 48fa4b81..fdd2ab4e 100644 --- a/lykiadb-lang/src/lib.rs +++ b/lykiadb-lang/src/lib.rs @@ -1,4 +1,8 @@ -use parser::{program::Program, resolver::{ResolveError, Resolver}, ParseError, Parser}; +use parser::{ + program::Program, + resolver::{ResolveError, Resolver}, + ParseError, Parser, +}; use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; use tokenizer::scanner::{ScanError, Scanner}; @@ -14,7 +18,7 @@ pub type Locals = FxHashMap; pub enum LangError { Parse(ParseError), Scan(ScanError), - Resolve(ResolveError) + Resolve(ResolveError), } impl From for LangError { @@ -66,4 +70,4 @@ impl SourceProcessor { Ok(program) } -} \ No newline at end of file +} diff --git a/lykiadb-lang/src/tokenizer/scanner.rs b/lykiadb-lang/src/tokenizer/scanner.rs index 9909f05a..72ec97d6 100644 --- a/lykiadb-lang/src/tokenizer/scanner.rs +++ b/lykiadb-lang/src/tokenizer/scanner.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; -use crate::ast::{Span, Literal::*}; +use crate::ast::{Literal::*, Span}; use crate::sym; use crate::tokenizer::token::Symbol::*; use crate::tokenizer::token::TokenType::{Eof, Identifier}; diff --git a/lykiadb-server/src/engine/error.rs b/lykiadb-server/src/engine/error.rs index a46cdbd6..c8776c15 100644 --- a/lykiadb-server/src/engine/error.rs +++ b/lykiadb-server/src/engine/error.rs @@ -3,9 +3,7 @@ use std::fmt::{Display, Formatter, Result}; use crate::{plan::PlannerError, value::environment::EnvironmentError}; use super::interpreter::InterpretError; -use lykiadb_lang::{ - ast::Span, parser::ParseError, tokenizer::scanner::ScanError, LangError -}; +use lykiadb_lang::{ast::Span, parser::ParseError, tokenizer::scanner::ScanError, LangError}; use serde::{Deserialize, Serialize}; #[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)] @@ -156,8 +154,9 @@ mod tests { use super::*; use lykiadb_lang::{ - ast::{Identifier, Literal}, kw, sym, tokenizer::token::{Keyword, Symbol, Token, TokenType} - + ast::{Identifier, Literal}, + kw, sym, + tokenizer::token::{Keyword, Symbol, Token, TokenType}, }; fn capture_error_output(filename: &str, source: &str, error: ExecutionError) -> String { diff --git a/lykiadb-server/src/plan/mod.rs b/lykiadb-server/src/plan/mod.rs index b8fb9032..839e0f81 100644 --- a/lykiadb-server/src/plan/mod.rs +++ b/lykiadb-server/src/plan/mod.rs @@ -1,12 +1,13 @@ use std::fmt::Display; use lykiadb_lang::ast::{ - expr::Expr, - sql::{ - SqlCollectionIdentifier, SqlCompoundOperator, SqlExpressionSource, SqlJoinType, - SqlOrdering, SqlProjection, - }, Identifier, Span, - }; + expr::Expr, + sql::{ + SqlCollectionIdentifier, SqlCompoundOperator, SqlExpressionSource, SqlJoinType, + SqlOrdering, SqlProjection, + }, + Identifier, Span, +}; use serde::{Deserialize, Serialize}; use crate::value::RV; diff --git a/lykiadb-server/src/plan/planner.rs b/lykiadb-server/src/plan/planner.rs index b65abcc6..f9bdcc15 100644 --- a/lykiadb-server/src/plan/planner.rs +++ b/lykiadb-server/src/plan/planner.rs @@ -7,10 +7,11 @@ use crate::{ }; use lykiadb_lang::ast::{ - expr::Expr, - sql::{SqlFrom, SqlJoinType, SqlProjection, SqlSelect, SqlSelectCore, SqlSource}, - visitor::VisitorMut, Spanned, - }; + expr::Expr, + sql::{SqlFrom, SqlJoinType, SqlProjection, SqlSelect, SqlSelectCore, SqlSource}, + visitor::VisitorMut, + Spanned, +}; use super::{scope::Scope, IntermediateExpr, Node, Plan, PlannerError}; diff --git a/lykiadb-shell/src/main.rs b/lykiadb-shell/src/main.rs index 65fa92e5..cc1302ae 100644 --- a/lykiadb-shell/src/main.rs +++ b/lykiadb-shell/src/main.rs @@ -38,11 +38,7 @@ impl Shell { } } - async fn run_file( - &mut self, - session: &mut impl ClientSession, - filename: &str, - ) { + async fn run_file(&mut self, session: &mut impl ClientSession, filename: &str) { let file = File::open(filename).expect("File couldn't be opened."); let mut content: String = String::new(); @@ -77,11 +73,7 @@ async fn main() { let mut session = get_session("localhost:19191", Protocol::Tcp).await; let mut shell = Shell; match args.filename { - Some(filename) => { - shell - .run_file(&mut session, &filename) - .await - } + Some(filename) => shell.run_file(&mut session, &filename).await, None => shell.run_repl(&mut session).await, }; } From 337c29c9bb95617cbb4e647e0122540155909857 Mon Sep 17 00:00:00 2001 From: Vedat Can Keklik Date: Mon, 16 Dec 2024 19:40:34 +0300 Subject: [PATCH 14/14] fix: clippy --- lykiadb-server/src/engine/mod.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/lykiadb-server/src/engine/mod.rs b/lykiadb-server/src/engine/mod.rs index 87228ea8..6ee728dd 100644 --- a/lykiadb-server/src/engine/mod.rs +++ b/lykiadb-server/src/engine/mod.rs @@ -1,9 +1,6 @@ use self::error::ExecutionError; use crate::value::RV; use interpreter::Interpreter; -use lykiadb_lang::parser::Parser; -use lykiadb_lang::tokenizer::scanner::Scanner; -use serde_json::Value; use tracing::info; pub mod error;