From 381852b3bded942e4dbd0ede55ab5074584f7854 Mon Sep 17 00:00:00 2001 From: Ava Hahn Date: Mon, 20 Mar 2023 17:16:44 -0700 Subject: [PATCH] Implemented SymTable optimization for efficient variable updates --- Readme.org | 1 - snippets/userlib-tests.rls | 4 +-- snippets/userlib.rls | 2 +- src/config.rs | 3 ++ src/stl.rs | 47 ++++++++++++++++++++++++++++++ src/stl/control.rs | 18 ++---------- src/sym.rs | 59 +++++++++++++++++++++++++++++++++++--- tests/test_eval.rs | 2 ++ tests/test_func.rs | 9 ++++++ 9 files changed, 122 insertions(+), 23 deletions(-) diff --git a/Readme.org b/Readme.org index 89d3a5c..2f2526b 100644 --- a/Readme.org +++ b/Readme.org @@ -477,7 +477,6 @@ Note: this section will not show the status of each item unless you are viewing Note: this section only tracks the state of incomplete TODO items. Having everything on here would be cluttered. ** TODO Pre-alpha tasks -- SYMTABLE-LET OPTIMIZATION COUNTERS - Load (load a script) function - Pull/Refactor the logic out of the configure functions. - Optionally return a list of new variables and/or functions? diff --git a/snippets/userlib-tests.rls b/snippets/userlib-tests.rls index bc06634..ab46c66 100644 --- a/snippets/userlib-tests.rls +++ b/snippets/userlib-tests.rls @@ -28,7 +28,7 @@ 'prints if a test has failed' (test) (echo (concat "FAILED: " test))) - + (def test-cases 'all test cases' (('set updates var' (quote @@ -61,4 +61,4 @@ (if (eval test-body) (passed test-name) (failed test-name)) - (set (q test-iter) (pop remaining))))) \ No newline at end of file + (set (q test-iter) (pop remaining))))) diff --git a/snippets/userlib.rls b/snippets/userlib.rls index 783034c..41f9d79 100644 --- a/snippets/userlib.rls +++ b/snippets/userlib.rls @@ -50,7 +50,7 @@ WARNING: abandon hope all ye who declare and then modify global variables! (let ((doc (get-doc var))) (def (eval var) doc val))) -(def map +(def map 'Takes two arguments: a function and a list. for each element in the list, the function is applied and the result is added to a new list. Returns the new list.' diff --git a/src/config.rs b/src/config.rs index 16ccc9f..23ad8dd 100644 --- a/src/config.rs +++ b/src/config.rs @@ -40,6 +40,7 @@ pub fn configure(filename: String, syms: &mut SymTable) -> Result<(), String> { default value: false".to_string(), value: ValueType::VarForm(Box::new(Ctr::Bool(false))), + ..Default::default() }, ); @@ -56,6 +57,7 @@ checked at shell startup by configuration daemon. not used afterwards. default value: 1 (set) ".to_string(), value: ValueType::VarForm(Box::new(Ctr::Bool(true))), + ..Default::default() }, ); @@ -69,6 +71,7 @@ default value: 1 (set) default value ()" .to_string(), value: ValueType::Internal(Rc::new(prompt_default_callback)), + ..Default::default() }, ); diff --git a/src/stl.rs b/src/stl.rs index 8b71b1b..b4cd122 100644 --- a/src/stl.rs +++ b/src/stl.rs @@ -38,6 +38,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: append::CONS_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(append::cons_callback)), + ..Default::default() }, ); @@ -49,6 +50,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: strings::ECHO_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(strings::echo_callback)), + ..Default::default() }, ); @@ -60,6 +62,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: strings::CONCAT_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(strings::concat_callback)), + ..Default::default() }, ); @@ -71,6 +74,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: strings::CONTAINS_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(strings::contains_callback)), + ..Default::default() }, ); @@ -82,6 +86,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: strings::SPLIT_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(strings::split_callback)), + ..Default::default() }, ); @@ -93,6 +98,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: strings::STRLEN_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(strings::strlen_callback)), + ..Default::default() }, ); @@ -104,6 +110,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: strings::STRCAST_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(strings::strcast_callback)), + ..Default::default() }, ); @@ -115,6 +122,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: true, docs: control::IF_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(control::if_callback)), + ..Default::default() }, ); @@ -126,6 +134,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: true, docs: control::LET_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(control::let_callback)), + ..Default::default() }, ); @@ -137,6 +146,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: true, docs: control::WHILE_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(control::while_callback)), + ..Default::default() }, ); @@ -148,6 +158,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: true, docs: control::CIRCUIT_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(control::circuit_callback)), + ..Default::default() }, ); @@ -159,6 +170,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: boolean::AND_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(boolean::and_callback)), + ..Default::default() }, ); @@ -170,6 +182,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: boolean::BOOLCAST_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(boolean::boolcast_callback)), + ..Default::default() }, ); @@ -181,6 +194,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: boolean::OR_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(boolean::or_callback)), + ..Default::default() }, ); @@ -192,6 +206,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: boolean::NOT_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(boolean::not_callback)), + ..Default::default() }, ); @@ -203,6 +218,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: boolean::ISEQ_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(boolean::iseq_callback)), + ..Default::default() }, ); @@ -214,6 +230,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: true, docs: boolean::TOGGLE_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(boolean::toggle_callback)), + ..Default::default() }, ); @@ -225,6 +242,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: true, docs: decl::HELP_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(decl::help_callback)), + ..Default::default() }, ); @@ -236,6 +254,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: true, docs: decl::ISSET_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(decl::isset_callback)), + ..Default::default() }, ); @@ -247,6 +266,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: decl::ENV_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(decl::env_callback)), + ..Default::default() }, ); @@ -258,6 +278,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: math::ADD_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(math::add_callback)), + ..Default::default() }, ); @@ -269,6 +290,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: math::SUB_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(math::sub_callback)), + ..Default::default() }, ); @@ -280,6 +302,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: math::DIV_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(math::div_callback)), + ..Default::default() }, ); @@ -291,6 +314,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: math::MUL_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(math::mul_callback)), + ..Default::default() }, ); @@ -302,6 +326,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: math::INTCAST_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(math::intcast_callback)), + ..Default::default() }, ); @@ -313,6 +338,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: math::FLOATCAST_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(math::floatcast_callback)), + ..Default::default() }, ); @@ -324,6 +350,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: append::LEN_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(append::len_callback)), + ..Default::default() }, ); @@ -335,6 +362,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: append::CAR_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(append::car_callback)), + ..Default::default() }, ); @@ -346,6 +374,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: append::CDR_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(append::cdr_callback)), + ..Default::default() }, ); @@ -357,6 +386,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: append::POP_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(append::pop_callback)), + ..Default::default() }, ); @@ -368,6 +398,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: append::DEQUEUE_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(append::dequeue_callback)), + ..Default::default() }, ); @@ -379,6 +410,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: append::REVERSE_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(append::reverse_callback)), + ..Default::default() }, ); @@ -390,6 +422,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: math::EXP_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(math::exp_callback)), + ..Default::default() }, ); @@ -401,6 +434,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: math::MOD_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(math::mod_callback)), + ..Default::default() }, ); @@ -412,6 +446,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: math::ISGT_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(math::isgt_callback)), + ..Default::default() }, ); @@ -423,6 +458,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: math::ISLT_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(math::islt_callback)), + ..Default::default() }, ); @@ -434,6 +470,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: math::ISGTE_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(math::isgte_callback)), + ..Default::default() }, ); @@ -445,6 +482,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: math::ISLTE_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(math::islte_callback)), + ..Default::default() }, ); @@ -456,6 +494,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: true, docs: math::INC_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(math::inc_callback)), + ..Default::default() }, ); @@ -467,6 +506,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: true, docs: math::DEC_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(math::dec_callback)), + ..Default::default() }, ); @@ -478,6 +518,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: true, docs: decl::QUOTE_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(decl::quote_callback)), + ..Default::default() }, ); @@ -489,6 +530,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: true, docs: decl::QUOTE_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(decl::quote_callback)), + ..Default::default() }, ); @@ -500,6 +542,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: true, docs: decl::EVAL_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(decl::eval_callback)), + ..Default::default() }, ); @@ -511,6 +554,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: true, docs: decl::LAMBDA_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(decl::lambda_callback)), + ..Default::default() } ); @@ -522,6 +566,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: decl::GETDOC_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(decl::getdoc_callback)), + ..Default::default() } ); @@ -533,6 +578,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: decl::SETDOC_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(decl::setdoc_callback)), + ..Default::default() } ); @@ -562,6 +608,7 @@ pub fn dynamic_stdlib(syms: &mut SymTable) -> Result<(), String> { decl::store_callback(ast, syms, env_cfg_user_form) }, )), + ..Default::default() }, ); diff --git a/src/stl/control.rs b/src/stl/control.rs index 2bcef89..df0e510 100644 --- a/src/stl/control.rs +++ b/src/stl/control.rs @@ -202,22 +202,10 @@ pub fn let_callback(ast: &Seg, syms: &mut SymTable) -> Result { return Err("evaluation failure".to_string()); } - // we need to get any var declared from within the let eval forms - // those need to exist in the outside context - // TODO: make this more optimal - // How can we skip iterations? - // implement a counter for number of calls to def - // store it inside the SymTable and Symbol - // only re-insert into global scope what is most recent - for i in localsyms.iter() { - if !locals.contains(i.0) { - syms.insert( - i.0.clone(), - i.1.clone(), - ); - } + for i in locals { + localsyms.remove(&i); } - + syms.update(&mut localsyms); Ok((*result).clone()) } diff --git a/src/sym.rs b/src/sym.rs index 5db9239..a96d845 100644 --- a/src/sym.rs +++ b/src/sym.rs @@ -22,7 +22,7 @@ use std::fmt; use std::rc::Rc; #[derive(Clone)] -pub struct SymTable(HashMap); +pub struct SymTable(HashMap, usize); #[derive(Debug, Clone)] pub struct UserFn { @@ -68,11 +68,14 @@ pub struct Symbol { // eval() will not eval the args pub conditional_branches: bool, pub docs: String, + // see SymTable::Insert + // (only pub begrudgingly + pub __generation: usize, } impl SymTable { pub fn new() -> SymTable { - SymTable(HashMap::::new()) + SymTable(HashMap::::new(), 0) } pub fn get(&self, arg: &String) -> Option<&Symbol> { @@ -83,7 +86,9 @@ impl SymTable { self.0.contains_key(arg) } - pub fn insert(&mut self, k: String, v: Symbol) -> Option { + pub fn insert(&mut self, k: String, mut v: Symbol) -> Option { + self.1 += 1; + v.__generation = self.1; self.0.insert(k, v) } @@ -95,16 +100,40 @@ impl SymTable { self.0.iter() } + pub fn update(&mut self, other: &mut SymTable) { + /* updates self with all syms in other that match the following cases: + * * sym is not in self + * * sym has a newer generation than the entry in self + */ + for i in other.iter() { + self.0.entry(i.0.to_string()) + .and_modify(|inner: &mut Symbol| { + if inner.__generation < i.1.__generation { + inner.__generation = i.1.__generation; + inner.value = i.1.value.clone(); + inner.args = i.1.args.clone(); + inner.docs = i.1.docs.clone(); + inner.conditional_branches = i.1.conditional_branches; + inner.name = i.1.name.clone(); + } + }) + .or_insert(i.1.clone()); + } + } + pub fn call_symbol( &mut self, name: &String, args: &Seg, call_func: bool, ) -> Result, String> { - let symbol = match self.remove(name) { + let mut symbol = match self.remove(name) { Some(s) => s, None => return Err(format!("undefined symbol: {}", name)), }; + // will re-increment when inserted + // but we dont want to increment it + symbol.__generation -= 1; self.insert(name.to_string(), symbol.clone()); let cond_args: &Seg; @@ -338,6 +367,7 @@ impl Symbol { args: Args::None, docs: format!("local argument to {}", f.arg_syms[n].clone()), conditional_branches: false, + ..Default::default() }, ) { holding_table.insert(f.arg_syms[n].clone(), old); @@ -412,6 +442,26 @@ impl Symbol { docs: doc.clone(), conditional_branches: false, args, value, + ..Default::default() + } + } +} + +impl Default for Symbol { + fn default() -> Symbol { + Symbol { + value: ValueType::Internal( + Rc::new( + |_: &Seg, _: &mut SymTable| -> Result { + unimplemented!() + } + ) + ), + name: String::new(), + docs: String::new(), + args: Args::None, + conditional_branches: false, + __generation: 0, } } } @@ -427,6 +477,7 @@ pub fn call_lambda( docs: String::from("user defined lambda"), args: Args::Lazy(lam.arg_syms.len() as u128), value: ValueType::FuncForm(lam.clone()), + ..Default::default() }; let args: &Seg; diff --git a/tests/test_eval.rs b/tests/test_eval.rs index 0f147cd..a987669 100644 --- a/tests/test_eval.rs +++ b/tests/test_eval.rs @@ -38,6 +38,7 @@ mod eval_tests { Box::from(Ctr::None), )), }), + ..Default::default() }; syms.insert(String::from("echo"), test_external_func); @@ -64,6 +65,7 @@ mod eval_tests { Box::from(Ctr::None), )), }), + ..Default::default() }; syms.insert(String::from("echo"), test_external_func); diff --git a/tests/test_func.rs b/tests/test_func.rs index 0be6722..3f66d86 100644 --- a/tests/test_func.rs +++ b/tests/test_func.rs @@ -22,6 +22,7 @@ mod func_tests { Ok(Ctr::Bool(is_bool)) }, )), + ..Default::default() }; let args = Seg::from(Box::new(Ctr::Bool(true)), Box::new(Ctr::None)); syms.insert(String::from("test_func_in"), test_internal_func); @@ -46,6 +47,7 @@ mod func_tests { arg_syms: vec!["input".to_string()], ast: finner, }), + ..Default::default() }; let args = Seg::from( @@ -75,6 +77,7 @@ mod func_tests { arg_syms: vec!["input".to_string()], ast: finner, }), + ..Default::default() }; let args = Seg::from( @@ -114,6 +117,7 @@ mod func_tests { } }, )), + ..Default::default() }; let finner = lex(&"((test_inner true))".to_string()).unwrap(); @@ -126,6 +130,7 @@ mod func_tests { arg_syms: vec!["input".to_string()], ast: finner, }), + ..Default::default() }; let args = Seg::from(Box::new(Ctr::Bool(true)), Box::new(Ctr::None)); @@ -157,6 +162,7 @@ mod func_tests { Ok(Ctr::Bool(is_bool)) }, )), + ..Default::default() }; let args = Seg::from(Box::new(Ctr::Integer(1)), Box::new(Ctr::None)); @@ -182,6 +188,7 @@ mod func_tests { arg_syms: vec!["input".to_string()], ast: finner, }), + ..Default::default() }; let args = Seg::from( @@ -211,6 +218,7 @@ mod func_tests { arg_syms: vec!["input".to_string()], ast: finner, }), + ..Default::default() }; let args = Seg::new(); @@ -241,6 +249,7 @@ mod func_tests { Ok(Ctr::Bool(is_bool)) }, )), + ..Default::default() }; let args = Seg::from( Box::new(Ctr::Symbol("undefined-symbol".to_string())),