finished circuit form
Signed-off-by: Ava Hahn <ava@aidanis.online>
This commit is contained in:
parent
c235f9727f
commit
4b587f11ab
7 changed files with 144 additions and 53 deletions
|
|
@ -136,11 +136,6 @@ This contains any executable target of this project. Notably the main shell file
|
|||
Note: this section will not show the status of each item unless you are viewing it with a proper orgmode viewer.
|
||||
Note: this section only tracks the state of incomplete TODO items. Having everything on here would be cluttered.
|
||||
|
||||
*** TODO Control Flow
|
||||
**** DONE if form
|
||||
**** DONE let 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
|
||||
*** TODO Custom ast pretty print
|
||||
|
|
|
|||
|
|
@ -59,8 +59,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| {
|
||||
let mut config_document = fs::read_to_string(filename).unwrap_or_else(|err: io::Error| {
|
||||
eprintln!("{}", err);
|
||||
"".to_string()
|
||||
}) + ")";
|
||||
|
|
|
|||
12
src/stl.rs
12
src/stl.rs
|
|
@ -22,8 +22,8 @@ use std::env;
|
|||
use std::rc::Rc;
|
||||
|
||||
pub mod append;
|
||||
pub mod control;
|
||||
pub mod boolean;
|
||||
pub mod control;
|
||||
//pub mod str;
|
||||
|
||||
/// static_stdlib
|
||||
|
|
@ -107,7 +107,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> {
|
|||
args: Args::Infinite,
|
||||
conditional_branches: false,
|
||||
value: ValueType::Internal(Rc::new(boolean::bool_and_callback)),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
|
|
@ -117,7 +117,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> {
|
|||
args: Args::Infinite,
|
||||
conditional_branches: false,
|
||||
value: ValueType::Internal(Rc::new(boolean::bool_or_callback)),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
|
|
@ -127,7 +127,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> {
|
|||
args: Args::Strict(vec![Type::Bool]),
|
||||
conditional_branches: false,
|
||||
value: ValueType::Internal(Rc::new(boolean::bool_not_callback)),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
|
|
@ -137,7 +137,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> {
|
|||
args: Args::Infinite,
|
||||
conditional_branches: false,
|
||||
value: ValueType::Internal(Rc::new(boolean::bool_iseq_callback)),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
|
|
@ -147,7 +147,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> {
|
|||
args: Args::Lazy(1),
|
||||
conditional_branches: true,
|
||||
value: ValueType::Internal(Rc::new(boolean::bool_toggle_callback)),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -65,7 +65,9 @@ pub fn bool_not_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String>
|
|||
|
||||
pub fn bool_iseq_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> {
|
||||
let head_ctr_ref = &*ast.car;
|
||||
Ok(Ctr::Bool(ast.circuit(&mut |arg: &Ctr| -> bool {arg == head_ctr_ref})))
|
||||
Ok(Ctr::Bool(
|
||||
ast.circuit(&mut |arg: &Ctr| -> bool { arg == head_ctr_ref }),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn bool_toggle_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
|
||||
|
|
@ -73,20 +75,22 @@ pub fn bool_toggle_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Strin
|
|||
if let Ctr::Symbol(ref s) = *ast.car {
|
||||
var_name = s.clone();
|
||||
} else {
|
||||
return Err("argument to toggle should be a symbol".to_string())
|
||||
return Err("argument to toggle should be a symbol".to_string());
|
||||
}
|
||||
|
||||
let mut sym = syms.remove(&var_name).expect(&format!("symbol {var_name} is not defined"));
|
||||
let mut sym = syms
|
||||
.remove(&var_name)
|
||||
.expect(&format!("symbol {var_name} is not defined"));
|
||||
if let ValueType::VarForm(ref var) = sym.value {
|
||||
if let Ctr::Bool(ref b) = **var {
|
||||
sym.value = ValueType::VarForm(Box::new(Ctr::Bool(!b)));
|
||||
} else {
|
||||
syms.insert(var_name, sym);
|
||||
return Err("can only toggle a boolean".to_string())
|
||||
return Err("can only toggle a boolean".to_string());
|
||||
}
|
||||
} else {
|
||||
syms.insert(var_name, sym);
|
||||
return Err("cannot toggle a function".to_string())
|
||||
return Err("cannot toggle a function".to_string());
|
||||
}
|
||||
|
||||
syms.insert(var_name, sym);
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
use crate::eval::eval;
|
||||
use crate::segment::{Ctr, Seg};
|
||||
use crate::sym::{SymTable, Symbol, ValueType, Args};
|
||||
use crate::sym::{Args, SymTable, Symbol, ValueType};
|
||||
|
||||
pub fn if_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
|
||||
let cond: bool;
|
||||
|
|
@ -32,10 +32,7 @@ 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
|
||||
)? {
|
||||
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());
|
||||
|
|
@ -95,13 +92,13 @@ pub fn let_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
|
|||
if let Ctr::Seg(ref locals_form_list) = *ast.car {
|
||||
locals_form = locals_form_list;
|
||||
} else {
|
||||
return Err("first element of let form must contain local variables".to_string())
|
||||
return Err("first element of let form must contain local variables".to_string());
|
||||
}
|
||||
|
||||
if let Ctr::Seg(ref eval_forms_head) = *ast.cdr {
|
||||
eval_forms = eval_forms_head;
|
||||
} else {
|
||||
return Err("let form should contain one or more elements to evaluate".to_string())
|
||||
return Err("let form should contain one or more elements to evaluate".to_string());
|
||||
}
|
||||
|
||||
// process locals forms
|
||||
|
|
@ -125,27 +122,30 @@ pub fn let_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
|
|||
}
|
||||
if let Err(e) = var_val_res {
|
||||
eprintln!("failed to evaluate definition of {}: {}", name, e);
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
|
||||
localsyms.insert(name.clone(), Symbol {
|
||||
localsyms.insert(
|
||||
name.clone(),
|
||||
Symbol {
|
||||
name: name.clone(),
|
||||
args: Args::None,
|
||||
conditional_branches: false,
|
||||
value: ValueType::VarForm(Box::new(*var_val_res.unwrap().clone())),
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
} else {
|
||||
eprintln!("improper declaration of {}: not a list", var_decl);
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
eprintln!("improper declaration form: {}", var_decl);
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}) {
|
||||
return Err("local variable declaration failure".to_string())
|
||||
return Err("local variable declaration failure".to_string());
|
||||
}
|
||||
|
||||
let mut result: Box<Ctr> = Box::new(Ctr::None);
|
||||
|
|
@ -167,13 +167,13 @@ pub fn let_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
|
|||
|
||||
if let Err(e) = res {
|
||||
eprintln!("error evaluating let form: {}", e);
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
|
||||
result = res.unwrap().clone();
|
||||
true
|
||||
}) {
|
||||
return Err("evaluation failure".to_string())
|
||||
return Err("evaluation failure".to_string());
|
||||
}
|
||||
|
||||
Ok((*result).clone())
|
||||
|
|
@ -200,7 +200,7 @@ pub fn while_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
|
|||
if let Ctr::Seg(ref eval) = *ast.cdr {
|
||||
eval_bodies_head = eval;
|
||||
} else {
|
||||
return Err("expected N more bodies in while form".to_string())
|
||||
return Err("expected N more bodies in while form".to_string());
|
||||
}
|
||||
|
||||
loop {
|
||||
|
|
@ -208,15 +208,19 @@ pub fn while_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
|
|||
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}
|
||||
if !b {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
panic!()
|
||||
}
|
||||
} else if let Ctr::Bool(b) = cond_res {
|
||||
if !b {break}
|
||||
if !b {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
return Err("first body of while form should evaluate to a bool".to_string())
|
||||
return Err("first body of while form should evaluate to a bool".to_string());
|
||||
}
|
||||
|
||||
if !eval_bodies_head.circuit(&mut |body: &Ctr| -> bool {
|
||||
|
|
@ -242,7 +246,49 @@ pub fn while_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
|
|||
/*
|
||||
(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!()
|
||||
pub fn circuit_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
|
||||
let mut cursor = 0;
|
||||
let mut error: String = String::new();
|
||||
let result = ast.circuit(&mut |form: &Ctr| -> bool {
|
||||
cursor += 1;
|
||||
let operand: &Seg;
|
||||
let mut expand_eval_res = false;
|
||||
let outer_scope_seg: Seg;
|
||||
if let Ctr::Seg(ref s) = form {
|
||||
operand = s;
|
||||
} else {
|
||||
outer_scope_seg = Seg::from_mono(Box::new(form.clone()));
|
||||
operand = &outer_scope_seg;
|
||||
expand_eval_res = true;
|
||||
}
|
||||
|
||||
let eval_result = eval(operand, syms);
|
||||
match eval_result {
|
||||
Err(s) => error = format!("eval failed at form {cursor}: {s}"),
|
||||
Ok(s) => match *s {
|
||||
Ctr::Bool(b) => return b,
|
||||
|
||||
Ctr::Seg(s) if expand_eval_res => {
|
||||
if let Ctr::Bool(b) = *s.car {
|
||||
return b;
|
||||
} else {
|
||||
error = "impossible condition in circuit form".to_string();
|
||||
}
|
||||
}
|
||||
|
||||
_ => error = format!("{cursor} form did not evaluate to a boolean"),
|
||||
},
|
||||
}
|
||||
|
||||
false
|
||||
});
|
||||
|
||||
if !result && !error.is_empty() {
|
||||
Err(format!("circuit stopped at form {cursor}: {error}"))
|
||||
} else {
|
||||
if !result {
|
||||
eprintln!("circuit stopped at form {cursor}");
|
||||
}
|
||||
Ok(Ctr::Bool(result))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -197,7 +197,10 @@ mod bool_lib_tests {
|
|||
|
||||
eval(&doc_tree, &mut syms).unwrap();
|
||||
if let Err(s) = eval(&change_tree, &mut syms) {
|
||||
assert_eq!(s, "error in call to toggle: can only toggle a boolean".to_string());
|
||||
assert_eq!(
|
||||
s,
|
||||
"error in call to toggle: can only toggle a boolean".to_string()
|
||||
);
|
||||
let intermediate = *eval(&check_tree, &mut syms).unwrap();
|
||||
if let Ctr::Seg(ref s) = intermediate {
|
||||
assert_eq!(s.to_string(), "('oops')".to_string());
|
||||
|
|
@ -227,7 +230,10 @@ mod bool_lib_tests {
|
|||
|
||||
eval(&doc_tree, &mut syms).unwrap();
|
||||
if let Err(s) = eval(&change_tree, &mut syms) {
|
||||
assert_eq!(s, "error in call to toggle: cannot toggle a function".to_string());
|
||||
assert_eq!(
|
||||
s,
|
||||
"error in call to toggle: cannot toggle a function".to_string()
|
||||
);
|
||||
if let Ctr::String(ref s) = *eval(&check_tree, &mut syms).unwrap() {
|
||||
assert_eq!(*s, "1".to_string());
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -213,4 +213,45 @@ mod control_lib_tests {
|
|||
eval(&while_tree, &mut syms).unwrap();
|
||||
eval(&check_tree, &mut syms).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_circuit_basic() {
|
||||
let document = "(if (circuit true (and true true) true) (def result 'passed') ())";
|
||||
let test = "result";
|
||||
|
||||
let doc_tree = lex(&document.to_string()).unwrap();
|
||||
let test_tree = lex(&test.to_string()).unwrap();
|
||||
|
||||
let mut syms = SymTable::new();
|
||||
static_stdlib(&mut syms).unwrap();
|
||||
dynamic_stdlib(&mut syms).unwrap();
|
||||
|
||||
eval(&doc_tree, &mut syms).unwrap();
|
||||
let res = eval(&test_tree, &mut syms);
|
||||
println!("{:#?}", res);
|
||||
res.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_circuit_fail() {
|
||||
let document = "(if (circuit true (and false true) true) (def result 'passed') ())";
|
||||
let test = "result";
|
||||
|
||||
let doc_tree = lex(&document.to_string()).unwrap();
|
||||
let test_tree = lex(&test.to_string()).unwrap();
|
||||
|
||||
let mut syms = SymTable::new();
|
||||
static_stdlib(&mut syms).unwrap();
|
||||
dynamic_stdlib(&mut syms).unwrap();
|
||||
|
||||
eval(&doc_tree, &mut syms).unwrap();
|
||||
if let Err(s) = eval(&test_tree, &mut syms) {
|
||||
assert_eq!(
|
||||
s,
|
||||
"error in call to result: undefined symbol: result".to_string()
|
||||
);
|
||||
} else {
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue