finished while form

Signed-off-by: Ava Hahn <ava@aidanis.online>
This commit is contained in:
Ava Hahn 2023-03-02 15:29:50 -08:00
parent 6ef467db94
commit c235f9727f
Signed by untrusted user who does not match committer: affine
GPG key ID: 3A4645B8CF806069
5 changed files with 185 additions and 5 deletions

View file

@ -31,10 +31,16 @@ https://matrix.to/#/#vomitorium:matrix.sunnypup.io
**** TODO circuit **** TODO circuit
*** TODO Defining variables and functions *** TODO Defining variables and functions
**** TODO Anatomy **** TODO Anatomy
**** TODO Naming conventions
**** TODO Undefining variables and functions **** TODO Undefining variables and functions
*** TODO Easy patterns
**** TODO while-let combo
**** TODO main loop application
*** TODO Builtin functions *** TODO Builtin functions
*** TODO Documentation *** TODO Documentation
(help function **** TODO Tests
**** TODO Help function
**** TODO Snippets directory
** Configuration ** Configuration
By default Relish will read from ~/.relishrc for configuration, but the default shell will also accept a filename from the RELISH_CFG_FILE environment variable. By default Relish will read from ~/.relishrc for configuration, but the default shell will also accept a filename from the RELISH_CFG_FILE environment variable.
@ -133,7 +139,7 @@ Note: this section only tracks the state of incomplete TODO items. Having everyt
*** TODO Control Flow *** TODO Control Flow
**** DONE if form **** DONE if form
**** DONE let form **** DONE let form
**** TODO while form **** DONE while form
**** TODO circuit form **** TODO circuit form
*** TODO Clean up tests, simplify, convert some to unit tests, mention tests in Readme as docs *** TODO Clean up tests, simplify, convert some to unit tests, mention tests in Readme as docs
*** TODO Document all internal/builtin functions in the rustiest way possible *** TODO Document all internal/builtin functions in the rustiest way possible

View file

@ -61,7 +61,7 @@ pub fn configure(filename: String, syms: &mut SymTable) -> Result<(), String> {
let mut config_document = fs::read_to_string(filename) let mut config_document = fs::read_to_string(filename)
.unwrap_or_else(|err: io::Error| { .unwrap_or_else(|err: io::Error| {
eprintln!("{}", err.to_string()); eprintln!("{}", err);
"".to_string() "".to_string()
}) + ")"; }) + ")";

View file

@ -80,6 +80,26 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> {
}, },
); );
syms.insert(
"while".to_string(),
Symbol {
name: String::from("while"),
args: Args::Infinite,
conditional_branches: true,
value: ValueType::Internal(Rc::new(control::while_callback)),
},
);
syms.insert(
"circuit".to_string(),
Symbol {
name: String::from("circuit"),
args: Args::Infinite,
conditional_branches: true,
value: ValueType::Internal(Rc::new(control::circuit_callback)),
},
);
syms.insert( syms.insert(
"and".to_string(), "and".to_string(),
Symbol { Symbol {

View file

@ -21,6 +21,7 @@ use crate::sym::{SymTable, Symbol, ValueType, Args};
pub fn if_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> { pub fn if_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
let cond: bool; let cond: bool;
println!("Y: {}", *ast.car);
match *ast.car { match *ast.car {
Ctr::Seg(ref cond_form) => { Ctr::Seg(ref cond_form) => {
if let Ctr::Bool(cond_from_eval) = *eval(cond_form, syms)? { if let Ctr::Bool(cond_from_eval) = *eval(cond_form, syms)? {
@ -30,6 +31,17 @@ pub fn if_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
} }
} }
Ctr::Symbol(ref cond_name) => {
if let Ctr::Bool(cond_from_eval) = *syms.call_symbol(
cond_name,
&Seg::new(), false
)? {
cond = cond_from_eval;
} else {
return Err("first argument to if must evaluate to be a boolean".to_string());
}
}
Ctr::Bool(cond_from_car) => cond = cond_from_car, Ctr::Bool(cond_from_car) => cond = cond_from_car,
_ => return Err("first argument to if must evaluate to be a boolean".to_string()), _ => return Err("first argument to if must evaluate to be a boolean".to_string()),
} }
@ -167,10 +179,70 @@ pub fn let_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
Ok((*result).clone()) Ok((*result).clone())
} }
pub fn while_callback(_ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> { /*
todo!() (while (cond) evalme evalme evalme evalme ... )
*/
pub fn while_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
let eval_cond: &Seg;
let outer_maybe: Seg;
let eval_bodies_head: &Seg;
let mut unwrap = false;
let mut result: Result<Box<Ctr>, String> = Ok(Box::new(Ctr::None));
if let Ctr::Seg(ref cond) = *ast.car {
eval_cond = cond;
} else {
outer_maybe = Seg::from_mono(ast.car.clone());
eval_cond = &outer_maybe;
unwrap = true;
} }
if let Ctr::Seg(ref eval) = *ast.cdr {
eval_bodies_head = eval;
} else {
return Err("expected N more bodies in while form".to_string())
}
loop {
let cond_res = *eval(eval_cond, syms)?;
if unwrap {
if let Ctr::Seg(ref cond_res_inner) = cond_res {
if let Ctr::Bool(ref b) = *cond_res_inner.car {
if !b {break}
}
} else {
panic!()
}
} else if let Ctr::Bool(b) = cond_res {
if !b {break}
} else {
return Err("first body of while form should evaluate to a bool".to_string())
}
if !eval_bodies_head.circuit(&mut |body: &Ctr| -> bool {
let outer_scope_seg: Seg;
let eval_arg: &Seg;
if let Ctr::Seg(ref eval_body) = *body {
eval_arg = eval_body;
} else {
outer_scope_seg = Seg::from_mono(Box::new(body.clone()));
eval_arg = &outer_scope_seg;
}
result = eval(eval_arg, syms);
result.is_ok()
}) {
return Err(result.err().unwrap());
}
}
Ok(*(result.unwrap()).clone())
}
/*
(circuit makes_a_bool makes_a_bool makes_a_bool makes_a_bool ... )
*/
pub fn circuit_callback(_ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> { pub fn circuit_callback(_ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> {
todo!() todo!()
} }

View file

@ -131,4 +131,86 @@ mod control_lib_tests {
assert!(false); assert!(false);
} }
} }
#[test]
fn test_while_basic() {
let switch_dec = "(def switch true)";
// if prev is true, switch looped once and only once
// else prev will have a problematic type
let while_loop = "
(while switch
(def prev switch)
(toggle switch)
(if switch
(def prev)
()))";
let test_check = "prev";
let switch_tree = lex(&switch_dec.to_string()).unwrap();
let while_tree = lex(&while_loop.to_string()).unwrap();
let check_tree = lex(&test_check.to_string()).unwrap();
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
eval(&switch_tree, &mut syms).unwrap();
eval(&while_tree, &mut syms).unwrap();
eval(&check_tree, &mut syms).unwrap();
}
#[test]
fn test_while_eval_cond() {
let switch_dec = "(def switch true)";
// if prev is true, switch looped once and only once
// else prev will have a problematic type
let while_loop = "
(while (or switch switch)
(def prev switch)
(toggle switch)
(if switch
(def prev)
()))";
let test_check = "prev";
let switch_tree = lex(&switch_dec.to_string()).unwrap();
let while_tree = lex(&while_loop.to_string()).unwrap();
let check_tree = lex(&test_check.to_string()).unwrap();
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
eval(&switch_tree, &mut syms).unwrap();
eval(&while_tree, &mut syms).unwrap();
eval(&check_tree, &mut syms).unwrap();
}
#[test]
fn test_while_2_iter() {
let additional = "(def sw1 true)";
let switch_dec = "(def sw2 true)";
// while should loop twice and define result
let while_loop = "
(while sw1
(toggle sw2)
(if (and sw1 sw2)
(def sw1 false)
(def result 'yay')))";
let test_check = "result";
let another_tree = lex(&additional.to_string()).unwrap();
let switch_tree = lex(&switch_dec.to_string()).unwrap();
let while_tree = lex(&while_loop.to_string()).unwrap();
let check_tree = lex(&test_check.to_string()).unwrap();
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
eval(&another_tree, &mut syms).unwrap();
eval(&switch_tree, &mut syms).unwrap();
eval(&while_tree, &mut syms).unwrap();
eval(&check_tree, &mut syms).unwrap();
}
} }