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 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
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
}) + ")";
|
}) + ")";
|
||||||
|
|
||||||
|
|
|
||||||
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(
|
syms.insert(
|
||||||
"and".to_string(),
|
"and".to_string(),
|
||||||
Symbol {
|
Symbol {
|
||||||
|
|
|
||||||
|
|
@ -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!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue