simplify eval, add member function to symtable to call a symbol

This commit is contained in:
Ava Hahn 2023-02-23 23:01:47 -08:00
parent e055f26e90
commit a1e19a19d9
Signed by untrusted user who does not match committer: affine
GPG key ID: 3A4645B8CF806069
5 changed files with 104 additions and 107 deletions

View file

@ -8,5 +8,5 @@ edition = "2018"
[dependencies] [dependencies]
dirs = "3.0" dirs = "3.0"
lazy_static = "1.4.0"
rustyline = "8.2.0" rustyline = "8.2.0"
once_cell = "1.17.1"

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
use crate::sym::{SYM_TABLE, Symbol, ValueType}; use crate::sym::SymTable;
use crate::segment::{Seg, Ctr}; use crate::segment::{Seg, Ctr};
/* iterates over a syntax tree /* iterates over a syntax tree
@ -24,8 +24,7 @@ use crate::segment::{Seg, Ctr};
*/ */
pub fn eval ( pub fn eval (
ast: &Seg, ast: &Seg,
expect_all_symbols_defined: bool, syms: &mut SymTable,
simplify_function_branches: bool,
) -> Result<Box<Ctr>, String> { ) -> Result<Box<Ctr>, String> {
// data to return // data to return
let mut ret = Box::from(Ctr::None); let mut ret = Box::from(Ctr::None);
@ -36,70 +35,33 @@ pub fn eval (
let mut cdr = Box::from(Ctr::None); let mut cdr = Box::from(Ctr::None);
// lets me redirect the input // lets me redirect the input
let table_handle = SYM_TABLE.read().unwrap();
let mut arg_car = &ast.car; let mut arg_car = &ast.car;
let mut arg_cdr = &ast.cdr; let mut arg_cdr = &ast.cdr;
// iterate over ast and build out ret // iterate over ast and build out ret
let mut none = false; let mut none = false;
while !none { while !none {
let mut prefetched_function: Option<&Symbol> = None; match &**arg_car {
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 {
Ctr::Seg(ref inner) => { Ctr::Seg(ref inner) => {
match eval(inner, expect_all_symbols_defined, simplify_function_branches) { match eval(inner, syms) {
Ok(res) => car = res, Ok(res) => car = res,
Err(e) => return Err(format!("evaluation error: {}", e)), Err(e) => return Err(format!("evaluation error: {}", e)),
} }
} }
Ctr::Symbol(_) => { Ctr::Symbol(ref tok) => {
if simplify_function_branches && first { let outer_scope_seg_holder: Seg;
if let Some(func) = prefetched_function { let args: &Seg;
if let Ctr::Seg(ref candidates) = **arg_cdr { if let Ctr::Seg(ref candidate_args) = **arg_cdr {
let fc: Result<Box<Ctr>, String>; args = candidate_args;
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 { } else {
match func.call(&Seg::new()) { outer_scope_seg_holder = Seg::from_mono(arg_cdr.clone());
Ok(res) => car = res, args = &outer_scope_seg_holder;
Err(e) => return Err(format!("call to {} failed: {}", func.name, e))
} }
}
} else { match syms.call_symbol(tok, args, first) {
car = arg_car.clone(); Ok(s) => car = s,
} Err(s) => return Err(format!("error in call to {}: {}", tok, s)),
} else {
car = arg_car.clone();
} }
} }
@ -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 { match **arg_cdr {
Ctr::Symbol(_) => { Ctr::Symbol(ref tok) => {
cdr = arg_cdr.clone(); 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; none = true;
} }
@ -157,4 +107,3 @@ pub fn eval (
Ok(ret) Ok(ret)
} }

View file

@ -26,14 +26,12 @@ mod stl;
/*mod stl; /*mod stl;
mod str;*/ mod str;*/
extern crate lazy_static;
pub mod ast { pub mod ast {
pub use crate::eval::eval; pub use crate::eval::eval;
pub use crate::lex::lex; pub use crate::lex::lex;
pub use crate::segment::{Ctr, Seg, Type}; pub use crate::segment::{Ctr, Seg, Type};
pub use crate::sym::{ pub use crate::sym::{
SYM_TABLE, SymTable, Symbol, SymTable, Symbol,
UserFn, ValueType, Args UserFn, ValueType, Args
}; };
} }

View file

@ -17,7 +17,7 @@
use crate::segment::{Ctr, Seg, Type}; use crate::segment::{Ctr, Seg, Type};
use crate::eval::eval; use crate::eval::eval;
use crate::sym::{SYM_TABLE, Symbol, ValueType, Args, UserFn}; use crate::sym::{SymTable, Symbol, ValueType, Args, UserFn};
use std::env; use std::env;
/* /*
@ -44,18 +44,17 @@ pub static LIB_STORE_NO_ENV: Symbol = Symbol {
};*/ };*/
// TODO : declare function if arg list is long enough // TODO : declare function if arg list is long enough
fn _store_callback (ast: &Seg, env_cfg: bool) -> Ctr { fn _store_callback (ast: &Seg, syms: &mut SymTable, env_cfg: bool) -> Ctr {
let mut table_handle = SYM_TABLE.write().unwrap();
let is_var = ast.len() == 2; let is_var = ast.len() == 2;
if let Ctr::Symbol(ref identifier) = *ast.car { if let Ctr::Symbol(ref identifier) = *ast.car {
match &*ast.cdr { 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 { 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()), value: ValueType::VarForm(val.car.clone()),
name: identifier.clone(), name: identifier.clone(),
args: Args::None, args: Args::None,
has_undefined_symbols: false, conditional_branches: false,
}); });
if env_cfg { if env_cfg {
env::set_var(identifier.clone(), val.car.to_string()); 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 { if let Ctr::Seg(ref bodies) = *data_tree.cdr {
table_handle.insert(identifier.clone(), Symbol{ syms.insert(identifier.clone(), Symbol{
value: ValueType::FuncForm(UserFn{ value: ValueType::FuncForm(UserFn{
ast: Box::new(bodies.clone()), ast: Box::new(bodies.clone()),
arg_syms: arg_list.clone(), arg_syms: arg_list.clone(),
@ -91,7 +90,7 @@ fn _store_callback (ast: &Seg, env_cfg: bool) -> Ctr {
.into_iter() .into_iter()
.map(Type::from) .map(Type::from)
.collect()), .collect()),
has_undefined_symbols: false, conditional_branches: false,
}); });
} else { } else {
eprintln!("expected one or more function bodies in function definition"); 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 => { Ctr::None => {
table_handle.remove(&identifier.to_string()); syms.remove(&identifier.to_string());
if env_cfg { if env_cfg {
env::remove_var(identifier); env::remove_var(identifier);
} }

View file

@ -18,16 +18,8 @@
use crate::eval::eval; use crate::eval::eval;
use crate::segment::{Seg, Ctr, Type}; use crate::segment::{Seg, Ctr, Type};
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::RwLock;
use lazy_static::lazy_static;
pub type SymTable = HashMap<String, Symbol>; pub struct SymTable(HashMap<String, Symbol>);
lazy_static! {
pub static ref SYM_TABLE: RwLock<SymTable> = {
RwLock::new(SymTable::new())
};
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct UserFn { pub struct UserFn {
@ -47,7 +39,7 @@ pub struct UserFn {
*/ */
#[derive(Clone)] #[derive(Clone)]
pub enum ValueType { pub enum ValueType {
Internal(Box<fn(&Seg) -> Ctr>), Internal(Box<fn(&Seg, &mut SymTable) -> Ctr>),
FuncForm(UserFn), FuncForm(UserFn),
VarForm(Box<Ctr>) VarForm(Box<Ctr>)
} }
@ -69,7 +61,47 @@ pub struct Symbol {
pub value: ValueType, pub value: ValueType,
pub name: String, pub name: String,
pub args: Args, 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::<String, Symbol>::new()}
}
pub fn get(&self, arg: &String) -> Option<&Symbol> {
self.0.get(arg)
}
pub fn insert(&mut self, k: String, v: Symbol) -> Option<Symbol> {
self.0.insert(k, v)
}
pub fn remove(&mut self, arg: &String) -> Option<Symbol> {
self.0.remove(arg)
}
pub fn call_symbol(&mut self, name: &String, args: &Seg, call_func: bool) -> Result<Box<Ctr>, 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 { impl Args {
@ -155,14 +187,35 @@ impl Symbol {
pub fn call( pub fn call(
&self, &self,
args: &Seg, args: &Seg,
syms: &mut SymTable
) -> Result<Box<Ctr>, String> { ) -> Result<Box<Ctr>, 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<Ctr>;
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)); return Err(format!("failure to call {}: {}", self.name, msg));
} }
match &self.value { match &self.value {
ValueType::VarForm(ref f) => Ok(Box::new(*f.clone())), 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) => { ValueType::FuncForm(ref f) => {
// stores any value overwritten by local state // stores any value overwritten by local state
// If this ever becomes ASYNC this will need to // If this ever becomes ASYNC this will need to
@ -172,12 +225,11 @@ impl Symbol {
// Prep var table for function execution // Prep var table for function execution
for n in 0..f.arg_syms.len() { for n in 0..f.arg_syms.len() {
if let Some(old) = SYM_TABLE.write().unwrap() if let Some(old) = syms.insert(f.arg_syms[n].clone(), Symbol{
.insert(f.arg_syms[n].clone(), Symbol{
name: f.arg_syms[n].clone(), 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, args: Args::None,
has_undefined_symbols: false, conditional_branches: false,
}) })
{ {
holding_table.insert(f.arg_syms[n].clone(), old); holding_table.insert(f.arg_syms[n].clone(), old);
@ -189,7 +241,7 @@ impl Symbol {
let mut iterate = &*(f.ast); let mut iterate = &*(f.ast);
loop { loop {
if let Ctr::Seg(ref data) = *iterate.car { if let Ctr::Seg(ref data) = *iterate.car {
match eval(data, !self.has_undefined_symbols, true) { match eval(data, syms) {
Ok(ctr) => result = ctr, Ok(ctr) => result = ctr,
Err(e) => return Err(e), Err(e) => return Err(e),
} }
@ -206,9 +258,9 @@ impl Symbol {
// clear local vars and restore previous values // clear local vars and restore previous values
for n in 0..f.arg_syms.len() { 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]) { 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 {
} }
} }
} }