diff --git a/Readme.org b/Readme.org index 8164e0f..81cddc5 100644 --- a/Readme.org +++ b/Readme.org @@ -107,7 +107,7 @@ Note: this section will not show the status of each item unless you are viewing **** DONE Function table **** DONE Variable table *** DONE Echo function -*** TODO Redo segment.rs +*** DONE Redo segment.rs **** DONE Clone impl for Ctr (derived) **** DONE Derive Clone for Seg @@ -119,14 +119,21 @@ Note: this section will not show the status of each item unless you are viewing **** DONE Derive Default for Seg **** WONTDO From/Into for Ctr **** DONE Iterator for Seg -**** TODO YEET AST EVERYWHERE. PASS AROUND A FUCKING SEG REF DAMNIT -In string lib +**** TODO Consider RefCell for tables, or using 'static lifetime +one of these may fix borrow checker insanity +all you have to do is actually learn this shit +just pay attention +**** DONE YEET AST EVERYWHERE. PASS AROUND A SEG REF. +*** TODO refactor code into more digestible, better organized pieces +Just need to get core compiling at this point. +Refactors made include splitting func_call into reasonable segments +Reorganizing eval *** TODO Rudimentary Control Flow **** TODO if clause **** TODO loop clause **** TODO while clause **** TODO circuit clause -*** TODO Configuration +*** DONE Configuration **** DONE Function to load configuration into Variable and Function tables **** DONE Configure in main shell **** DONE manual verification of config settings @@ -140,15 +147,15 @@ Pull/Refactor the logic out of the configure functions. Optionally return a list of new variables and/or functions? Will need a concatenate function for func tables *** TODO Main shell calls Load function on arg and exits +*** TODO Custom error printing +*** TODO Custom ast pretty print +*** DONE Implement Ctr, Ast to_string / Display trait +*** TODO get_stdlibphase1 -> configuration -> get_stdlibphase2 +*** TODO STDLIB *** TODO Shell module **** TODO Process launching with environment variables **** TODO Foreground process TTY **** TODO Background processes -*** TODO Custom error printing -*** TODO Custom ast pretty print -*** TODO Implement Ctr, Ast to_string / Display trait -*** TODO get_stdlibphase1 -> configuration -> get_stdlibphase2 -*** TODO STDLIB **** DONE append **** TODO string operations ***** DONE concatenate diff --git a/the_rewrite/src/eval.rs b/the_rewrite/src/eval.rs index e6d4f1f..1cd953c 100644 --- a/the_rewrite/src/eval.rs +++ b/the_rewrite/src/eval.rs @@ -23,86 +23,98 @@ use crate::vars::VTable; * returns a NEW LIST of values * representing the simplest possible form of the input */ -pub fn eval<'a>( - ast: &'a Seg<'a>, + +/* Regarding 'a and 'b + * 'a intends to live beyond the call to eval + * 'b (input seg) only needs to live until this call to seg + */ + +pub fn eval<'a, 'b>( + ast: &'b Seg<'b>, vars: &'a mut VTable<'a>, funcs: &'a mut FTable<'a>, sym_loose: bool, -) -> Result>, String> { - let mut ret = Box::new(Ctr::Seg(Seg::new())); - let mut iter: &mut Seg; - if let Ctr::Seg(ref mut s) = *ret { - iter = s; - } else { - return Err("Critfail: no fuckin clue whats up here".to_string()) - } + call_lazy: bool, +) -> Result>, String> { + // data to return + let mut ret = Box::from(Ctr::None); - let mut car = &ast.car; + // to be assigned from cloned/evaled data + let mut car; + let mut cdr = Box::from(Ctr::None); + + // lets me redirect the input + let mut arg_car = &ast.car; + let mut arg_cdr = &ast.cdr; + + // theres probably a better way to do this + let mut binding_for_vtable_get; // doing an initial variable check here allows us // to find functions passed in as variables - if let Ctr::Symbol(tok) = **car { - if let Some(val) = vars.get(tok.clone()) { - car = &(val.clone()); + if let Ctr::Symbol(tok) = &**arg_car { + binding_for_vtable_get = vars.get(tok.clone()); + if let Some(ref val) = binding_for_vtable_get { + arg_car = &val; } } - // another check to detect if we may have a function call - if let Ctr::Symbol(ref tok) = **car { - match *ast.cdr { - Ctr::Seg(ref ast) => { - if let Some(func) = funcs.get(tok.clone()) { - return func.func_call(ast, vars, funcs); - } else if !sym_loose { - return Err(format!("Couldnt find definition of {}.", tok)); + // Is ast a function call? + if !call_lazy { + if let Ctr::Symbol(ref tok) = &**arg_car { + match *ast.cdr { + Ctr::Seg(ref ast) => { + if let Some(ref func) = funcs.get(tok.clone()) { + return func.func_call(ast, vars, funcs); + } else if !sym_loose { + return Err(format!("Couldnt find definition of {}.", tok)); + } } - } - Ctr::None => { - if let Some(func) = funcs.get(tok.clone()) { - return func.func_call(&Seg::new(), vars, funcs); - } else if !sym_loose { - return Err(format!("Couldnt find definition of {}.", tok.clone())); + Ctr::None => { + if let Some(ref func) = funcs.get(tok.clone()) { + return func.func_call(&Seg::new(), vars, funcs); + } else if !sym_loose { + return Err(format!("Couldnt find definition of {}.", tok.clone())); + } } + _ => return Err(format!("Arguments to function not a list!")), } - _ => return Err(format!("Arguments to function not a list!")), } } + // iterate over ast and build out ret let mut none = false; while !none { - match **car { - // if LIST: call eval inner on it with first_item=true + match &**arg_car { Ctr::Seg(ref inner) => { - match eval(inner, vars, funcs, sym_loose) { - Ok(res) => (*iter).car = res, + match eval(inner, vars, funcs, sym_loose, call_lazy) { + Ok(res) => car = res, Err(e) => return Err(format!("Evaluation error: {}", e)), } } - // if SYMBOL: unwrap naively Ctr::Symbol(ref tok) => { - if let Some(val) = vars.get(tok.clone()) { - iter.car = val.clone(); + binding_for_vtable_get = vars.get(tok.clone()); + if let Some(ref val) = binding_for_vtable_get { + car = val.clone(); } else if sym_loose { - iter.car = car.clone() + car = arg_car.clone() } else { return Err(format!("Undefined variable: {}", tok.clone())); } } - // if OTHER: clone and set _ => { - iter.car = car.clone(); + car = arg_car.clone(); } } - match *ast.cdr { - // if SYMBOL: unwrap naively, then end + match &**arg_cdr { Ctr::Symbol(ref tok) => { if let Some(val) = vars.get(tok.clone()) { - iter.cdr = val.clone(); + cdr = val.clone(); } else if sym_loose { - iter.cdr = ast.cdr.clone() + cdr = ast.cdr.clone() } else { return Err(format!("Undefined variable: {}", tok.clone())); } @@ -110,26 +122,25 @@ pub fn eval<'a>( none = true; } - // if LIST: - // - iter.cdr = new_ast(None, None) - // - iter = iter.cdr - // - car = cdr.car - // - cdr = cdr.cdr - // - LOOP - Ctr::Seg(next) => { - iter.cdr = Box::new(Ctr::Seg(Seg::new())); - ast = &next; + Ctr::Seg(ref next) => { + if let Ctr::None = *ret { + *ret = Ctr::Seg(Seg::from(car, cdr.clone())) + } else if let Ctr::Seg(ref mut s) = *ret { + s.append(Box::from(Ctr::Seg(Seg::from(car, cdr.clone())))) + } + arg_car = &next.car; + arg_cdr = &next.cdr } // if OTHER: clone and set, and then end _ => { - iter.cdr = ast.cdr.clone(); + cdr = ast.cdr.clone(); none = true; } } - if let Ctr::None = **car { - if let Ctr::None = *ast.cdr { + if let Ctr::None = **arg_car { + if let Ctr::None = **arg_cdr { none = true; } } diff --git a/the_rewrite/src/func.rs b/the_rewrite/src/func.rs index e6c253d..38811b7 100644 --- a/the_rewrite/src/func.rs +++ b/the_rewrite/src/func.rs @@ -46,7 +46,7 @@ impl<'a> FTable<'a> { self.0.get(&id) } - pub fn remove(&self, id: String) { + pub fn remove(&mut self, id: String) { self.0.remove(&id); } @@ -57,7 +57,7 @@ impl<'a> FTable<'a> { // Standardized function signature for stdlib functions -//pub type InternalOperation = impl Fn(Box, Box, Box) -> Box; +//pub type InternalOperation = impl Fn(&Seg, &mut VTable, &mut FTable) -> Ctr; #[derive(Debug)] pub struct ExternalOperation<'a> { @@ -88,70 +88,28 @@ pub enum Args { Strict(Vec), } -pub struct Function<'a> { - pub function: Operation<'a>, - pub name: String, - pub args: Args, - - // dont fail on undefined symbol (passed to eval) - pub loose_syms: bool, - - // dont evaluate args at all. leave that to the function - pub eval_lazy: bool, -} - -impl<'a> Function<'a> { - /* call - * routine is called by eval when a function call is detected - */ - pub fn func_call( - &self, - args: &'a Seg<'a>, - vars: &'a mut VTable<'a>, - funcs: &'a mut FTable<'a>, - ) -> Result>, String> { - let mut evaluated_args = args; - if !self.eval_lazy { - match eval(args, vars, funcs, self.loose_syms) { - Ok(arg_data) => { - if let Ctr::Seg(ast) = *arg_data { - evaluated_args = * - } else { - return Err("Panicking: eval returned not a list for function args.".to_string()); - } - } - Err(s) => { - return Err(format!( - "error evaluating args to {}: {}", - self.name, s - )) - } - } - } - - match self.args { +impl Args { + fn validate_inputs(&self, args: &Seg) -> Result<(), String> { + match self { Args::Lazy(ref num) => { - let called_arg_count = evaluated_args.len() as i128; + let called_arg_count = args.len() as i128; if *num == 0 { - if let Ctr::None = *evaluated_args.car { + if let Ctr::None = *args.car { //pass } else { - return Err(format!( - "expected 0 args in call to {}. Got one or more.", - self.name, - )); + return Err("Expected 0 args. Got one or more.".to_string()); } } else if *num > -1 && (*num != called_arg_count) { return Err(format!( - "expected {} args in call to {}. Got {}.", - num, self.name, called_arg_count + "Expected {} args. Got {}.", + num, called_arg_count )); } } Args::Strict(ref arg_types) => { let mut idx: usize = 0; - let passes = evaluated_args.circuit(&mut |c: &Ctr| -> bool { + let passes = args.circuit(&mut |c: &Ctr| -> bool { if idx >= arg_types.len() { return false; } @@ -169,32 +127,75 @@ impl<'a> Function<'a> { if passes && idx < (arg_types.len() - 1) { return Err(format!( - "{} too little arguments in call to {}", - arg_types.len() - (idx + 1), - self.name + "{} too few arguments", + arg_types.len() - (idx + 1) )); } if !passes { if idx < (arg_types.len() - 1) { return Err(format!( - "argument {} in call to {} is of wrong type (expected {})", + "argument {} is of wrong type (expected {})", idx + 1, - self.name, arg_types[idx].to_string() )); } if idx == (arg_types.len() - 1) { - return Err(format!( - "too many arguments in call to {}", - self.name - )); + return Err("too many arguments".to_string()); } } } } + Ok(()) + } +} + +pub struct Function<'a> { + pub function: Operation<'a>, + pub name: String, + pub args: Args, + + // dont fail on undefined symbol (passed to eval) + pub loose_syms: bool, + + // dont evaluate args at all. leave that to the function + pub eval_lazy: bool, +} + +impl<'a, 'b, 'c> Function<'a> { + /* call + * routine is called by eval when a function call is detected + */ + pub fn func_call( + &self, + args: &'b Seg<'b>, + vars: &'a mut VTable<'a>, + funcs: &'a mut FTable<'a>, + ) -> Result>, String> { + // put args in simplest desired form + let evaluated_args; + match eval(args, vars, funcs, self.loose_syms, self.eval_lazy) { + Ok(arg_data) => { + if let Ctr::Seg(ast) = *arg_data { + evaluated_args = * + } else { + return Err("Panicking: eval returned not a list for function args.".to_string()); + } + } + Err(s) => { + return Err(format!( + "error evaluating args to {}: {}", + self.name, s + )) + } + } + + if let Err(msg) = self.args.validate_inputs(evaluated_args) { + return Err(format!("failure to call {}: {}", self.name, msg)); + } + /* corecursive with eval. * essentially calls eval on each body in the function. * result of the final body is returned. @@ -211,7 +212,7 @@ impl<'a> Function<'a> { let iterate = &*(f.ast); loop { if let Ctr::Seg(ref data) = *iterate.car { - match eval(data, vars, funcs, self.loose_syms) { + match eval(data, vars, funcs, self.loose_syms, true) { Ok(ctr) => result = ctr, Err(e) => return Err(e), } diff --git a/the_rewrite/src/lib.rs b/the_rewrite/src/lib.rs index 6520d89..534f3e5 100644 --- a/the_rewrite/src/lib.rs +++ b/the_rewrite/src/lib.rs @@ -15,9 +15,6 @@ * along with this program. If not, see . */ -#![feature(derive_default_enum)] -#![feature(box_into_inner)] - /*mod append; mod config; */ diff --git a/the_rewrite/src/segment.rs b/the_rewrite/src/segment.rs index d369275..1b463ae 100644 --- a/the_rewrite/src/segment.rs +++ b/the_rewrite/src/segment.rs @@ -105,7 +105,7 @@ impl<'a> Seg<'a> { } if let Ctr::None = &mut *(self.cdr) { - self.cdr = Box::new(Ctr::Seg(Seg::from(obj))); + self.cdr = Box::new(Ctr::Seg(Seg::from_mono(obj))); // pray for memory lost to the void } } @@ -127,7 +127,7 @@ impl<'a> Seg<'a> { } } - pub fn from(arg: Box>) -> Seg<'a> { + pub fn from_mono(arg: Box>) -> Seg<'a> { return Seg{ car: arg, cdr: Box::new(Ctr::None), @@ -135,6 +135,14 @@ impl<'a> Seg<'a> { } } + pub fn from(car: Box>, cdr: Box>) -> Seg<'a> { + return Seg{ + car, + cdr, + _lifetime_variance_determinant: PhantomData, + } + } + /* recurs over ast assumed to be list in standard form * returns length */ diff --git a/the_rewrite/src/vars.rs b/the_rewrite/src/vars.rs index 81a2509..f143566 100644 --- a/the_rewrite/src/vars.rs +++ b/the_rewrite/src/vars.rs @@ -26,7 +26,7 @@ use std::env; */ pub struct VTable<'a>(HashMap>>); -impl<'a> VTable<'a> { +impl<'a, 'b> VTable<'a> { // WARNING: make sure var_tree is properly evaluated before storing pub fn insert(&'a mut self, identifier: String, data: Box>) { if let Some(datum) = self.0.insert(identifier, data) { @@ -34,14 +34,14 @@ impl<'a> VTable<'a> { } } - pub fn get(&'a self, id: String) -> Option>> { + pub fn get(&'a self, id: String) -> Option>> { match self.0.get(&id) { Some(s) => Some(s.clone()), None => None, } } - pub fn remove(&self, id: String) { + pub fn remove(&mut self, id: String) { self.0.remove(&id); } @@ -66,10 +66,10 @@ pub fn get_export<'a>(env_cfg: bool) -> Function<'a>{ } -fn _export_callback<'a> (ast: &'a Seg, vars: &'a mut VTable, funcs: &'a mut FTable, env_cfg: bool) -> Ctr<'a> { +fn _export_callback<'a> (ast: &Seg, vars: &mut VTable, funcs: &mut FTable, env_cfg: bool) -> Ctr<'a> { if let Ctr::Symbol(ref identifier) = *ast.car { - match *ast.cdr { - Ctr::Seg(data_tree) => match eval(&Box::new(data_tree), vars, funcs, false) { + match &*ast.cdr { + Ctr::Seg(data_tree) => match eval(&Box::new(data_tree), vars, funcs, false, true) { Ok(seg) => match *seg { Ctr::Seg(val) => { vars.insert(identifier.clone(), val.car);