WIP commit:

- Big organizational updates
- Class of errors brought down to borrow checker level
This commit is contained in:
Ava Hahn 2023-02-15 20:05:48 -08:00
parent 6dcb804d34
commit b680e3ca9a
Signed by untrusted user who does not match committer: affine
GPG key ID: 3A4645B8CF806069
6 changed files with 162 additions and 138 deletions

View file

@ -107,7 +107,7 @@ Note: this section will not show the status of each item unless you are viewing
**** DONE Function table **** DONE Function table
**** DONE Variable table **** DONE Variable table
*** DONE Echo function *** DONE Echo function
*** TODO Redo segment.rs *** DONE Redo segment.rs
**** DONE Clone impl for Ctr **** DONE Clone impl for Ctr
(derived) (derived)
**** DONE Derive Clone for Seg **** 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 **** DONE Derive Default for Seg
**** WONTDO From/Into for Ctr **** WONTDO From/Into for Ctr
**** DONE Iterator for Seg **** DONE Iterator for Seg
**** TODO YEET AST EVERYWHERE. PASS AROUND A FUCKING SEG REF DAMNIT **** TODO Consider RefCell for tables, or using 'static lifetime
In string lib 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 Rudimentary Control Flow
**** TODO if clause **** TODO if clause
**** TODO loop clause **** TODO loop clause
**** TODO while clause **** TODO while clause
**** TODO circuit clause **** TODO circuit clause
*** TODO Configuration *** DONE Configuration
**** DONE Function to load configuration into Variable and Function tables **** DONE Function to load configuration into Variable and Function tables
**** DONE Configure in main shell **** DONE Configure in main shell
**** DONE manual verification of config settings **** 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? Optionally return a list of new variables and/or functions?
Will need a concatenate function for func tables Will need a concatenate function for func tables
*** TODO Main shell calls Load function on arg and exits *** 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 Shell module
**** TODO Process launching with environment variables **** TODO Process launching with environment variables
**** TODO Foreground process TTY **** TODO Foreground process TTY
**** TODO Background processes **** 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 **** DONE append
**** TODO string operations **** TODO string operations
***** DONE concatenate ***** DONE concatenate

View file

@ -23,42 +23,55 @@ use crate::vars::VTable;
* returns a NEW LIST of values * returns a NEW LIST of values
* representing the simplest possible form of the input * 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>, vars: &'a mut VTable<'a>,
funcs: &'a mut FTable<'a>, funcs: &'a mut FTable<'a>,
sym_loose: bool, sym_loose: bool,
) -> Result<Box<Ctr<'a>>, String> { call_lazy: bool,
let mut ret = Box::new(Ctr::Seg(Seg::new())); ) -> Result<Box<Ctr<'b>>, String> {
let mut iter: &mut Seg; // data to return
if let Ctr::Seg(ref mut s) = *ret { let mut ret = Box::from(Ctr::None);
iter = s;
} else {
return Err("Critfail: no fuckin clue whats up here".to_string())
}
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 // doing an initial variable check here allows us
// to find functions passed in as variables // to find functions passed in as variables
if let Ctr::Symbol(tok) = **car { if let Ctr::Symbol(tok) = &**arg_car {
if let Some(val) = vars.get(tok.clone()) { binding_for_vtable_get = vars.get(tok.clone());
car = &(val.clone()); if let Some(ref val) = binding_for_vtable_get {
arg_car = &val;
} }
} }
// another check to detect if we may have a function call // Is ast a function call?
if let Ctr::Symbol(ref tok) = **car { if !call_lazy {
if let Ctr::Symbol(ref tok) = &**arg_car {
match *ast.cdr { match *ast.cdr {
Ctr::Seg(ref ast) => { Ctr::Seg(ref ast) => {
if let Some(func) = funcs.get(tok.clone()) { if let Some(ref func) = funcs.get(tok.clone()) {
return func.func_call(ast, vars, funcs); return func.func_call(ast, vars, funcs);
} else if !sym_loose { } else if !sym_loose {
return Err(format!("Couldnt find definition of {}.", tok)); return Err(format!("Couldnt find definition of {}.", tok));
} }
} }
Ctr::None => { Ctr::None => {
if let Some(func) = funcs.get(tok.clone()) { if let Some(ref func) = funcs.get(tok.clone()) {
return func.func_call(&Seg::new(), vars, funcs); return func.func_call(&Seg::new(), vars, funcs);
} else if !sym_loose { } else if !sym_loose {
return Err(format!("Couldnt find definition of {}.", tok.clone())); return Err(format!("Couldnt find definition of {}.", tok.clone()));
@ -67,42 +80,41 @@ pub fn eval<'a>(
_ => 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; let mut none = false;
while !none { while !none {
match **car { match &**arg_car {
// if LIST: call eval inner on it with first_item=true
Ctr::Seg(ref inner) => { Ctr::Seg(ref inner) => {
match eval(inner, vars, funcs, sym_loose) { match eval(inner, vars, funcs, sym_loose, call_lazy) {
Ok(res) => (*iter).car = res, Ok(res) => car = res,
Err(e) => return Err(format!("Evaluation error: {}", e)), Err(e) => return Err(format!("Evaluation error: {}", e)),
} }
} }
// if SYMBOL: unwrap naively
Ctr::Symbol(ref tok) => { Ctr::Symbol(ref tok) => {
if let Some(val) = vars.get(tok.clone()) { binding_for_vtable_get = vars.get(tok.clone());
iter.car = val.clone(); if let Some(ref val) = binding_for_vtable_get {
car = val.clone();
} else if sym_loose { } else if sym_loose {
iter.car = car.clone() car = arg_car.clone()
} else { } else {
return Err(format!("Undefined variable: {}", tok.clone())); return Err(format!("Undefined variable: {}", tok.clone()));
} }
} }
// if OTHER: clone and set
_ => { _ => {
iter.car = car.clone(); car = arg_car.clone();
} }
} }
match *ast.cdr { match &**arg_cdr {
// if SYMBOL: unwrap naively, then end
Ctr::Symbol(ref tok) => { Ctr::Symbol(ref tok) => {
if let Some(val) = vars.get(tok.clone()) { if let Some(val) = vars.get(tok.clone()) {
iter.cdr = val.clone(); cdr = val.clone();
} else if sym_loose { } else if sym_loose {
iter.cdr = ast.cdr.clone() cdr = ast.cdr.clone()
} else { } else {
return Err(format!("Undefined variable: {}", tok.clone())); return Err(format!("Undefined variable: {}", tok.clone()));
} }
@ -110,26 +122,25 @@ pub fn eval<'a>(
none = true; none = true;
} }
// if LIST: Ctr::Seg(ref next) => {
// - iter.cdr = new_ast(None, None) if let Ctr::None = *ret {
// - iter = iter.cdr *ret = Ctr::Seg(Seg::from(car, cdr.clone()))
// - car = cdr.car } else if let Ctr::Seg(ref mut s) = *ret {
// - cdr = cdr.cdr s.append(Box::from(Ctr::Seg(Seg::from(car, cdr.clone()))))
// - LOOP }
Ctr::Seg(next) => { arg_car = &next.car;
iter.cdr = Box::new(Ctr::Seg(Seg::new())); arg_cdr = &next.cdr
ast = &next;
} }
// if OTHER: clone and set, and then end // if OTHER: clone and set, and then end
_ => { _ => {
iter.cdr = ast.cdr.clone(); cdr = ast.cdr.clone();
none = true; none = true;
} }
} }
if let Ctr::None = **car { if let Ctr::None = **arg_car {
if let Ctr::None = *ast.cdr { if let Ctr::None = **arg_cdr {
none = true; none = true;
} }
} }

View file

@ -46,7 +46,7 @@ impl<'a> FTable<'a> {
self.0.get(&id) self.0.get(&id)
} }
pub fn remove(&self, id: String) { pub fn remove(&mut self, id: String) {
self.0.remove(&id); self.0.remove(&id);
} }
@ -57,7 +57,7 @@ impl<'a> FTable<'a> {
// Standardized function signature for stdlib functions // Standardized function signature for stdlib functions
//pub type InternalOperation = impl Fn(Box<Seg>, Box<VTable>, Box<FTable>) -> Box<Ctr>; //pub type InternalOperation = impl Fn(&Seg, &mut VTable, &mut FTable) -> Ctr;
#[derive(Debug)] #[derive(Debug)]
pub struct ExternalOperation<'a> { pub struct ExternalOperation<'a> {
@ -88,70 +88,28 @@ pub enum Args {
Strict(Vec<Type>), Strict(Vec<Type>),
} }
pub struct Function<'a> { impl Args {
pub function: Operation<'a>, fn validate_inputs(&self, args: &Seg) -> Result<(), String> {
pub name: String, match self {
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<Box<Ctr<'a>>, 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 = &ast;
} 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 {
Args::Lazy(ref num) => { 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 *num == 0 {
if let Ctr::None = *evaluated_args.car { if let Ctr::None = *args.car {
//pass //pass
} else { } else {
return Err(format!( return Err("Expected 0 args. Got one or more.".to_string());
"expected 0 args in call to {}. Got one or more.",
self.name,
));
} }
} else if *num > -1 && (*num != called_arg_count) { } else if *num > -1 && (*num != called_arg_count) {
return Err(format!( return Err(format!(
"expected {} args in call to {}. Got {}.", "Expected {} args. Got {}.",
num, self.name, called_arg_count num, called_arg_count
)); ));
} }
} }
Args::Strict(ref arg_types) => { Args::Strict(ref arg_types) => {
let mut idx: usize = 0; 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() { if idx >= arg_types.len() {
return false; return false;
} }
@ -169,30 +127,73 @@ impl<'a> Function<'a> {
if passes && idx < (arg_types.len() - 1) { if passes && idx < (arg_types.len() - 1) {
return Err(format!( return Err(format!(
"{} too little arguments in call to {}", "{} too few arguments",
arg_types.len() - (idx + 1), arg_types.len() - (idx + 1)
self.name
)); ));
} }
if !passes { if !passes {
if idx < (arg_types.len() - 1) { if idx < (arg_types.len() - 1) {
return Err(format!( return Err(format!(
"argument {} in call to {} is of wrong type (expected {})", "argument {} is of wrong type (expected {})",
idx + 1, idx + 1,
self.name,
arg_types[idx].to_string() arg_types[idx].to_string()
)); ));
} }
if idx == (arg_types.len() - 1) { if idx == (arg_types.len() - 1) {
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<Box<Ctr<'c>>, 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 = &ast;
} else {
return Err("Panicking: eval returned not a list for function args.".to_string());
}
}
Err(s) => {
return Err(format!( return Err(format!(
"too many arguments in call to {}", "error evaluating args to {}: {}",
self.name 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. /* corecursive with eval.
@ -211,7 +212,7 @@ impl<'a> Function<'a> {
let iterate = &*(f.ast); let iterate = &*(f.ast);
loop { loop {
if let Ctr::Seg(ref data) = *iterate.car { 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, Ok(ctr) => result = ctr,
Err(e) => return Err(e), Err(e) => return Err(e),
} }

View file

@ -15,9 +15,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#![feature(derive_default_enum)]
#![feature(box_into_inner)]
/*mod append; /*mod append;
mod config; mod config;
*/ */

View file

@ -105,7 +105,7 @@ impl<'a> Seg<'a> {
} }
if let Ctr::None = &mut *(self.cdr) { 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 // pray for memory lost to the void
} }
} }
@ -127,7 +127,7 @@ impl<'a> Seg<'a> {
} }
} }
pub fn from(arg: Box<Ctr<'a>>) -> Seg<'a> { pub fn from_mono(arg: Box<Ctr<'a>>) -> Seg<'a> {
return Seg{ return Seg{
car: arg, car: arg,
cdr: Box::new(Ctr::None), cdr: Box::new(Ctr::None),
@ -135,6 +135,14 @@ impl<'a> Seg<'a> {
} }
} }
pub fn from(car: Box<Ctr<'a>>, cdr: Box<Ctr<'a>>) -> Seg<'a> {
return Seg{
car,
cdr,
_lifetime_variance_determinant: PhantomData,
}
}
/* recurs over ast assumed to be list in standard form /* recurs over ast assumed to be list in standard form
* returns length * returns length
*/ */

View file

@ -26,7 +26,7 @@ use std::env;
*/ */
pub struct VTable<'a>(HashMap<String, Box<Ctr<'a>>>); pub struct VTable<'a>(HashMap<String, Box<Ctr<'a>>>);
impl<'a> VTable<'a> { impl<'a, 'b> VTable<'a> {
// WARNING: make sure var_tree is properly evaluated before storing // WARNING: make sure var_tree is properly evaluated before storing
pub fn insert(&'a mut self, identifier: String, data: Box<Ctr<'a>>) { pub fn insert(&'a mut self, identifier: String, data: Box<Ctr<'a>>) {
if let Some(datum) = self.0.insert(identifier, data) { 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<Box<Ctr<'a>>> { pub fn get(&'a self, id: String) -> Option<Box<Ctr<'b>>> {
match self.0.get(&id) { match self.0.get(&id) {
Some(s) => Some(s.clone()), Some(s) => Some(s.clone()),
None => None, None => None,
} }
} }
pub fn remove(&self, id: String) { pub fn remove(&mut self, id: String) {
self.0.remove(&id); 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 { if let Ctr::Symbol(ref identifier) = *ast.car {
match *ast.cdr { match &*ast.cdr {
Ctr::Seg(data_tree) => match eval(&Box::new(data_tree), vars, funcs, false) { Ctr::Seg(data_tree) => match eval(&Box::new(data_tree), vars, funcs, false, true) {
Ok(seg) => match *seg { Ok(seg) => match *seg {
Ctr::Seg(val) => { Ctr::Seg(val) => {
vars.insert(identifier.clone(), val.car); vars.insert(identifier.clone(), val.car);