From a1e19a19d9e7b5a670fda272cc954bd318e76ca2 Mon Sep 17 00:00:00 2001 From: Ava Hahn Date: Thu, 23 Feb 2023 23:01:47 -0800 Subject: [PATCH] simplify eval, add member function to symtable to call a symbol --- Cargo.toml | 2 +- src/eval.rs | 95 +++++++++++++---------------------------------------- src/lib.rs | 4 +-- src/stl.rs | 17 +++++----- src/sym.rs | 93 +++++++++++++++++++++++++++++++++++++++------------ 5 files changed, 104 insertions(+), 107 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index db0c100..ab899d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,5 +8,5 @@ edition = "2018" [dependencies] dirs = "3.0" -lazy_static = "1.4.0" rustyline = "8.2.0" +once_cell = "1.17.1" \ No newline at end of file diff --git a/src/eval.rs b/src/eval.rs index d7bc949..52e93c6 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -use crate::sym::{SYM_TABLE, Symbol, ValueType}; +use crate::sym::SymTable; use crate::segment::{Seg, Ctr}; /* iterates over a syntax tree @@ -24,8 +24,7 @@ use crate::segment::{Seg, Ctr}; */ pub fn eval ( ast: &Seg, - expect_all_symbols_defined: bool, - simplify_function_branches: bool, + syms: &mut SymTable, ) -> Result, String> { // data to return let mut ret = Box::from(Ctr::None); @@ -36,70 +35,33 @@ pub fn eval ( let mut cdr = Box::from(Ctr::None); // lets me redirect the input - let table_handle = SYM_TABLE.read().unwrap(); let mut arg_car = &ast.car; let mut arg_cdr = &ast.cdr; // iterate over ast and build out ret let mut none = false; while !none { - let mut prefetched_function: Option<&Symbol> = None; - while let Ctr::Symbol(ref tok) = **arg_car { - prefetched_function = table_handle.get(tok); - if let Some(sym_ref) = prefetched_function { - if let ValueType::VarForm(ref value) = sym_ref.value { - arg_car = value; - } else { - break; - } - } else if !expect_all_symbols_defined { - return Err(format!("evaluation error: undefined symbol {}", tok)) - } else { - break - } - } - - match **arg_car { + match &**arg_car { Ctr::Seg(ref inner) => { - match eval(inner, expect_all_symbols_defined, simplify_function_branches) { + match eval(inner, syms) { Ok(res) => car = res, Err(e) => return Err(format!("evaluation error: {}", e)), } } - Ctr::Symbol(_) => { - if simplify_function_branches && first { - if let Some(func) = prefetched_function { - if let Ctr::Seg(ref candidates) = **arg_cdr { - let fc: Result, String>; - match eval(candidates, expect_all_symbols_defined, false) { - Ok(res) => { - match *res { - Ctr::Seg(ref args) => { - fc = func.call(args); - }, - _ => { - fc = func.call(&Seg::from_mono(res.clone())) - } - } - match fc { - Ok(datum) => car = datum, - Err(e) => return Err(format!("call to {} failed: {}", func.name, e)) - } - } - Err(e) => return Err(format!("evaluation error: {}", e)) - } - } else { - match func.call(&Seg::new()) { - Ok(res) => car = res, - Err(e) => return Err(format!("call to {} failed: {}", func.name, e)) - } - } - } else { - car = arg_car.clone(); - } + Ctr::Symbol(ref tok) => { + let outer_scope_seg_holder: Seg; + let args: &Seg; + if let Ctr::Seg(ref candidate_args) = **arg_cdr { + args = candidate_args; } else { - car = arg_car.clone(); + outer_scope_seg_holder = Seg::from_mono(arg_cdr.clone()); + args = &outer_scope_seg_holder; + } + + match syms.call_symbol(tok, args, first) { + Ok(s) => car = s, + Err(s) => return Err(format!("error in call to {}: {}", tok, s)), } } @@ -108,25 +70,13 @@ pub fn eval ( } } - // weird tree but okay - while let Ctr::Symbol(ref tok) = **arg_cdr { - prefetched_function = table_handle.get(tok); - if let Some(sym_ref) = prefetched_function { - if let ValueType::VarForm(ref value) = sym_ref.value { - arg_cdr = value; - } else { - break; - } - } else if !expect_all_symbols_defined { - return Err(format!("evaluation error: undefined symbol {}", tok)) - } else { - break - } - } - match **arg_cdr { - Ctr::Symbol(_) => { - cdr = arg_cdr.clone(); + Ctr::Symbol(ref tok) => { + let blank = Seg::new(); + match syms.call_symbol(tok, &blank, false) { + Ok(res) => cdr = res, + Err(s) => return Err(format!("error fetching {}: {}", tok, s)), + } none = true; } @@ -157,4 +107,3 @@ pub fn eval ( Ok(ret) } - diff --git a/src/lib.rs b/src/lib.rs index 76213de..1a34393 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,14 +26,12 @@ mod stl; /*mod stl; mod str;*/ -extern crate lazy_static; - pub mod ast { pub use crate::eval::eval; pub use crate::lex::lex; pub use crate::segment::{Ctr, Seg, Type}; pub use crate::sym::{ - SYM_TABLE, SymTable, Symbol, + SymTable, Symbol, UserFn, ValueType, Args }; } diff --git a/src/stl.rs b/src/stl.rs index b1abf79..293a3e2 100644 --- a/src/stl.rs +++ b/src/stl.rs @@ -17,7 +17,7 @@ use crate::segment::{Ctr, Seg, Type}; use crate::eval::eval; -use crate::sym::{SYM_TABLE, Symbol, ValueType, Args, UserFn}; +use crate::sym::{SymTable, Symbol, ValueType, Args, UserFn}; use std::env; /* @@ -44,18 +44,17 @@ pub static LIB_STORE_NO_ENV: Symbol = Symbol { };*/ // TODO : declare function if arg list is long enough -fn _store_callback (ast: &Seg, env_cfg: bool) -> Ctr { - let mut table_handle = SYM_TABLE.write().unwrap(); +fn _store_callback (ast: &Seg, syms: &mut SymTable, env_cfg: bool) -> Ctr { let is_var = ast.len() == 2; if let Ctr::Symbol(ref identifier) = *ast.car { match &*ast.cdr { - Ctr::Seg(data_tree) if is_var => match eval(&Box::new(data_tree), true, true) { + Ctr::Seg(data_tree) if is_var => match eval(&Box::new(data_tree), syms) { Ok(seg) => if let Ctr::Seg(ref val) = *seg { - table_handle.insert(identifier.clone(), Symbol{ + syms.insert(identifier.clone(), Symbol{ value: ValueType::VarForm(val.car.clone()), name: identifier.clone(), args: Args::None, - has_undefined_symbols: false, + conditional_branches: false, }); if env_cfg { env::set_var(identifier.clone(), val.car.to_string()); @@ -81,7 +80,7 @@ fn _store_callback (ast: &Seg, env_cfg: bool) -> Ctr { }; if let Ctr::Seg(ref bodies) = *data_tree.cdr { - table_handle.insert(identifier.clone(), Symbol{ + syms.insert(identifier.clone(), Symbol{ value: ValueType::FuncForm(UserFn{ ast: Box::new(bodies.clone()), arg_syms: arg_list.clone(), @@ -91,7 +90,7 @@ fn _store_callback (ast: &Seg, env_cfg: bool) -> Ctr { .into_iter() .map(Type::from) .collect()), - has_undefined_symbols: false, + conditional_branches: false, }); } else { eprintln!("expected one or more function bodies in function definition"); @@ -103,7 +102,7 @@ fn _store_callback (ast: &Seg, env_cfg: bool) -> Ctr { } } Ctr::None => { - table_handle.remove(&identifier.to_string()); + syms.remove(&identifier.to_string()); if env_cfg { env::remove_var(identifier); } diff --git a/src/sym.rs b/src/sym.rs index b8bca9b..e29ffac 100644 --- a/src/sym.rs +++ b/src/sym.rs @@ -18,16 +18,8 @@ use crate::eval::eval; use crate::segment::{Seg, Ctr, Type}; use std::collections::HashMap; -use std::sync::RwLock; -use lazy_static::lazy_static; -pub type SymTable = HashMap; - -lazy_static! { - pub static ref SYM_TABLE: RwLock = { - RwLock::new(SymTable::new()) - }; -} +pub struct SymTable(HashMap); #[derive(Debug, Clone)] pub struct UserFn { @@ -47,7 +39,7 @@ pub struct UserFn { */ #[derive(Clone)] pub enum ValueType { - Internal(Box Ctr>), + Internal(Box Ctr>), FuncForm(UserFn), VarForm(Box) } @@ -69,7 +61,47 @@ pub struct Symbol { pub value: ValueType, pub name: String, pub args: Args, - pub has_undefined_symbols: bool, + // for internal control flow constructs + // eval() will not eval the args + pub conditional_branches: bool, +} + +impl SymTable { + pub fn new() -> SymTable { + SymTable{0: HashMap::::new()} + } + + pub fn get(&self, arg: &String) -> Option<&Symbol> { + self.0.get(arg) + } + + pub fn insert(&mut self, k: String, v: Symbol) -> Option { + self.0.insert(k, v) + } + + pub fn remove(&mut self, arg: &String) -> Option { + self.0.remove(arg) + } + + pub fn call_symbol(&mut self, name: &String, args: &Seg, call_func: bool) -> Result, String> { + let symbol = match self.get(name) { + Some(s) => s, + None => return Err(format!("undefined symbol: {}", name)), + }; + + let cond_args: &Seg; + let outer_scope_seg_holder: Seg; + if let ValueType::VarForm(ref val) = symbol.value { + return Ok(val.clone()); + } else if call_func { + cond_args = args + } else { + outer_scope_seg_holder = Seg::new(); + cond_args = &outer_scope_seg_holder; + } + + symbol.call(cond_args, self) + } } impl Args { @@ -155,14 +187,35 @@ impl Symbol { pub fn call( &self, args: &Seg, + syms: &mut SymTable ) -> Result, String> { - if let Err(msg) = self.args.validate_inputs(args) { + let evaluated_args: &Seg; + let outer_scope_seg_storage: Seg; + let outer_scope_eval: Box; + if self.conditional_branches { + let outer_scope_eval_result = eval(args, syms); + if let Err(s) = outer_scope_eval_result { + return Err(s); + } + outer_scope_eval = outer_scope_eval_result.unwrap(); + match *outer_scope_eval { + Ctr::Seg(ref segment) => evaluated_args = segment, + _ => { + outer_scope_seg_storage = Seg::from_mono(outer_scope_eval); + evaluated_args = &outer_scope_seg_storage; + } + } + } else { + evaluated_args = args; + } + + if let Err(msg) = self.args.validate_inputs(evaluated_args) { return Err(format!("failure to call {}: {}", self.name, msg)); } match &self.value { ValueType::VarForm(ref f) => Ok(Box::new(*f.clone())), - ValueType::Internal(ref f) => Ok(Box::new(f(args))), + ValueType::Internal(ref f) => Ok(Box::new(f(evaluated_args, syms))), ValueType::FuncForm(ref f) => { // stores any value overwritten by local state // If this ever becomes ASYNC this will need to @@ -172,12 +225,11 @@ impl Symbol { // Prep var table for function execution for n in 0..f.arg_syms.len() { - if let Some(old) = SYM_TABLE.write().unwrap() - .insert(f.arg_syms[n].clone(), Symbol{ + if let Some(old) = syms.insert(f.arg_syms[n].clone(), Symbol{ name: f.arg_syms[n].clone(), - value: ValueType::VarForm(Box::new(args[n].clone())), + value: ValueType::VarForm(Box::new(evaluated_args[n].clone())), args: Args::None, - has_undefined_symbols: false, + conditional_branches: false, }) { holding_table.insert(f.arg_syms[n].clone(), old); @@ -189,7 +241,7 @@ impl Symbol { let mut iterate = &*(f.ast); loop { if let Ctr::Seg(ref data) = *iterate.car { - match eval(data, !self.has_undefined_symbols, true) { + match eval(data, syms) { Ok(ctr) => result = ctr, Err(e) => return Err(e), } @@ -206,9 +258,9 @@ impl Symbol { // clear local vars and restore previous values for n in 0..f.arg_syms.len() { - SYM_TABLE.write().unwrap().remove(&f.arg_syms[n]); + syms.remove(&f.arg_syms[n]); if let Some(val) = holding_table.remove(&f.arg_syms[n]) { - SYM_TABLE.write().unwrap().insert(f.arg_syms[n].clone(), val); + syms.insert(f.arg_syms[n].clone(), val); } } @@ -217,4 +269,3 @@ impl Symbol { } } } -