finished while form
Signed-off-by: Ava Hahn <ava@aidanis.online>
This commit is contained in:
parent
6ef467db94
commit
c235f9727f
5 changed files with 185 additions and 5 deletions
10
Readme.org
10
Readme.org
|
|
@ -31,10 +31,16 @@ https://matrix.to/#/#vomitorium:matrix.sunnypup.io
|
|||
**** TODO circuit
|
||||
*** TODO Defining variables and functions
|
||||
**** TODO Anatomy
|
||||
**** TODO Naming conventions
|
||||
**** TODO Undefining variables and functions
|
||||
*** TODO Easy patterns
|
||||
**** TODO while-let combo
|
||||
**** TODO main loop application
|
||||
*** TODO Builtin functions
|
||||
*** TODO Documentation
|
||||
(help function
|
||||
**** TODO Tests
|
||||
**** TODO Help function
|
||||
**** TODO Snippets directory
|
||||
|
||||
** 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.
|
||||
|
|
@ -133,7 +139,7 @@ Note: this section only tracks the state of incomplete TODO items. Having everyt
|
|||
*** TODO Control Flow
|
||||
**** DONE if form
|
||||
**** DONE let form
|
||||
**** TODO while form
|
||||
**** DONE while form
|
||||
**** TODO circuit form
|
||||
*** 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
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ pub fn configure(filename: String, syms: &mut SymTable) -> Result<(), String> {
|
|||
|
||||
let mut config_document = fs::read_to_string(filename)
|
||||
.unwrap_or_else(|err: io::Error| {
|
||||
eprintln!("{}", err.to_string());
|
||||
eprintln!("{}", err);
|
||||
"".to_string()
|
||||
}) + ")";
|
||||
|
||||
|
|
|
|||
20
src/stl.rs
20
src/stl.rs
|
|
@ -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(
|
||||
"and".to_string(),
|
||||
Symbol {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ use crate::sym::{SymTable, Symbol, ValueType, Args};
|
|||
|
||||
pub fn if_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
|
||||
let cond: bool;
|
||||
println!("Y: {}", *ast.car);
|
||||
match *ast.car {
|
||||
Ctr::Seg(ref cond_form) => {
|
||||
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,
|
||||
_ => 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())
|
||||
}
|
||||
|
||||
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> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -131,4 +131,86 @@ mod control_lib_tests {
|
|||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue