Fully fledged lambdas, along with efficiency tweaks across the ast

This commit is contained in:
Ava Apples Affine 2023-03-13 15:02:19 -07:00
parent b0bd369c1d
commit 8efa1dbaad
Signed by: affine
GPG key ID: 3A4645B8CF806069
10 changed files with 264 additions and 70 deletions

View file

@ -17,7 +17,7 @@
use crate::eval::eval;
use crate::segment::{Ctr, Seg};
use crate::sym::{Args, SymTable, Symbol, UserFn, ValueType};
use crate::sym::{SymTable, Symbol, UserFn, ValueType};
use std::env;
pub const QUOTE_DOCSTRING: &str = "takes a single unevaluated tree and returns it as it is: unevaluated.";
@ -101,6 +101,7 @@ pub const STORE_DOCSTRING: &str = "allows user to define functions and variables
(def useless-var)";
pub fn store_callback(ast: &Seg, syms: &mut SymTable, env_cfg: bool) -> Result<Ctr, String> {
println!("def: {}", ast);
let is_var = ast.len() == 3;
if let Ctr::Symbol(ref identifier) = *ast.car {
match &*ast.cdr {
@ -109,27 +110,40 @@ pub fn store_callback(ast: &Seg, syms: &mut SymTable, env_cfg: bool) -> Result<C
if let Ctr::String(ref doc) = *doc_tree.car {
match &*doc_tree.cdr {
// define a variable
Ctr::Seg(data_tree) if is_var => match eval(&Box::new(data_tree), syms) {
Ok(seg) => {
if let Ctr::Seg(ref val) = *seg {
Ctr::Seg(data_tree) if is_var => {
let eval_arg: &Seg;
let outer_maybe_eval_seg: Seg;
let mut expand = false;
if let Ctr::Seg(ref eval_me) = *data_tree.car {
eval_arg = eval_me;
} else {
outer_maybe_eval_seg = Seg::from_mono(data_tree.car.clone());
eval_arg = &outer_maybe_eval_seg;
expand = true;
}
match eval(eval_arg, syms) {
Ok(ctr) => {
let mut body = ctr;
if expand {
if let Ctr::Seg(ref s) = *body {
body = s.car.clone();
} else {
return Err("impossible expansion".to_string())
}
}
syms.insert(
identifier.clone(),
Symbol {
value: ValueType::VarForm(val.car.clone()),
name: identifier.clone(),
args: Args::None,
docs: doc.to_owned(),
conditional_branches: false,
},
Symbol::from_ast(
identifier, doc,
&Seg::from_mono(body.clone()), None
),
);
if env_cfg {
env::set_var(identifier.clone(), val.car.to_string());
env::set_var(identifier.clone(), body.to_string());
}
} else {
return Err("impossible args to export".to_string());
}
Err(e) => return Err(format!("couldnt eval symbol: {}", e)),
}
Err(e) => return Err(format!("couldnt eval symbol: {}", e)),
},
// define a function
@ -157,16 +171,10 @@ pub fn store_callback(ast: &Seg, syms: &mut SymTable, env_cfg: bool) -> Result<C
if let Ctr::Seg(ref bodies) = *data_tree.cdr {
syms.insert(
identifier.clone(),
Symbol {
value: ValueType::FuncForm(UserFn {
ast: Box::new(bodies.clone()),
arg_syms: arg_list.clone(),
}),
name: identifier.clone(),
args: Args::Lazy(arg_list.len() as u128),
docs: doc.to_owned(),
conditional_branches: false,
},
Symbol::from_ast(
identifier, doc, bodies,
Some(arg_list),
),
);
} else {
return Err(
@ -266,6 +274,9 @@ pub fn lambda_callback(
if let Ctr::Symbol(ref s) = *arg {
args.push(s.clone());
true
} else if let Ctr::None = *arg {
// no args case
true
} else {
false
}
@ -273,10 +284,14 @@ pub fn lambda_callback(
Err("all elements of first argumnets must be symbols".to_string())
} else {
if let Ctr::Seg(ref eval_head) = *ast.cdr {
Ok(Ctr::Lambda(UserFn{
ast: Box::new(eval_head.clone()),
arg_syms: args,
}))
if let Ctr::Seg(_) = *eval_head.car {
Ok(Ctr::Lambda(UserFn{
ast: Box::new(eval_head.clone()),
arg_syms: args,
}))
} else {
Err("function body must be in list form".to_string())
}
} else {
Err("not enough args".to_string())
}