Several changes, see commit msg

* clean up all tests
* bugfix for zero value functions, and test
* removed expand function, put in snippets
* added doc strings to Symbol type
* added doc strings to symbol declarations
* implemented display for Args type
* wrote a help function
* wrote docstrings for all builtins and config vars
This commit is contained in:
Ava Hahn 2023-03-05 22:18:49 -08:00
parent 4b587f11ab
commit dc6342bc74
Signed by untrusted user who does not match committer: affine
GPG key ID: 3A4645B8CF806069
16 changed files with 575 additions and 677 deletions

View file

@ -6,46 +6,19 @@ mod eval_tests {
fn eval_simple() {
let test_doc = "(1 2)".to_string();
let mut syms = SymTable::new();
match lex(&test_doc) {
Err(e) => {
println!("Lexing error: {}\n", e);
assert!(false)
}
Ok(initial_ast) => match eval(&initial_ast, &mut syms) {
Err(e) => {
println!("Evaluation error: {}\n", e);
assert!(false)
}
Ok(reduced) => {
assert_eq!(reduced.to_string(), test_doc)
}
},
}
let doc_tree = lex(&test_doc).unwrap();
let reduced = *eval(&doc_tree, &mut syms).unwrap();
assert_eq!(reduced.to_string(), test_doc);
}
#[test]
fn eval_embedded_lists_no_funcs() {
let test_doc = "(1 (1 2 3 4 5) 5)".to_string();
let mut syms = SymTable::new();
match lex(&test_doc) {
Err(e) => {
println!("Lexing error: {}\n", e);
assert!(false)
}
let doc_tree = lex(&test_doc).unwrap();
let reduced = *eval(&doc_tree, &mut syms).unwrap();
assert_eq!(reduced.to_string(), test_doc);
Ok(initial_ast) => match eval(&initial_ast, &mut syms) {
Err(e) => {
println!("Evaluation error: {}\n", e);
assert!(false)
}
Ok(reduced) => {
assert_eq!(reduced.to_string(), test_doc)
}
},
}
}
#[test]
@ -58,6 +31,7 @@ mod eval_tests {
name: String::from("echo"),
args: Args::Lazy(1),
conditional_branches: false,
docs: String::new(),
value: ValueType::FuncForm(UserFn {
arg_syms: vec!["input".to_string()],
ast: Box::new(Seg::from(
@ -68,24 +42,9 @@ mod eval_tests {
};
syms.insert(String::from("echo"), test_external_func);
match lex(&test_doc) {
Err(e) => {
println!("Lexing error: {}\n", e);
assert!(false)
}
Ok(initial_ast) => match eval(&initial_ast, &mut syms) {
Err(e) => {
println!("Evaluation error: {}\n", e);
assert!(false)
}
Ok(reduced) => {
assert_eq!(reduced.to_string(), output)
}
},
}
let doc_tree = lex(&test_doc).unwrap();
let reduced = *eval(&doc_tree, &mut syms).unwrap();
assert_eq!(reduced.to_string(), output);
}
#[test]
@ -98,6 +57,7 @@ mod eval_tests {
name: String::from("echo"),
args: Args::Lazy(1),
conditional_branches: false,
docs: String::new(),
value: ValueType::FuncForm(UserFn {
arg_syms: vec!["input".to_string()],
ast: Box::new(Seg::from(
@ -108,46 +68,26 @@ mod eval_tests {
};
syms.insert(String::from("echo"), test_external_func);
match lex(&test_doc) {
Err(e) => {
println!("Lexing error: {}\n", e);
assert!(false)
}
Ok(initial_ast) => match eval(&initial_ast, &mut syms) {
Err(e) => {
println!("Evaluation error: {}\n", e);
assert!(false)
}
Ok(reduced) => {
assert_eq!(reduced.to_string(), output)
}
},
}
let doc_tree = lex(&test_doc).unwrap();
let reduced = *eval(&doc_tree, &mut syms).unwrap();
assert_eq!(reduced.to_string(), output);
}
#[test]
fn eval_bad_syms() {
let test_doc = "(undefined)".to_string();
let mut syms = SymTable::new();
match lex(&test_doc) {
let doc_tree = lex(&test_doc).unwrap();
match eval(&doc_tree, &mut syms) {
Err(e) => {
println!("Lexing error: {}\n", e);
assert!(false)
assert_eq!(e, "error in call to undefined: undefined symbol: undefined")
}
Ok(initial_ast) => match eval(&initial_ast, &mut syms) {
Err(e) => {
assert_eq!(e, "error in call to undefined: undefined symbol: undefined")
}
Ok(reduced) => {
println!("Eval succeeded when it shouldnt have");
println!("see: {}", reduced);
assert!(false)
}
},
Ok(reduced) => {
println!("Eval succeeded when it shouldnt have");
println!("see: {}", reduced);
assert!(false)
}
}
}
}

View file

@ -10,6 +10,7 @@ mod func_tests {
let test_internal_func: Symbol = Symbol {
name: String::from("test_func_in"),
conditional_branches: false,
docs: String::new(),
args: Args::Strict(vec![Type::Bool]),
value: ValueType::Internal(Rc::new(
|a: &Seg, _: &mut SymTable| -> Result<Ctr, String> {
@ -23,95 +24,63 @@ mod func_tests {
)),
};
let args = Seg::from(Box::new(Ctr::Bool(true)), Box::new(Ctr::None));
syms.insert(String::from("test_func_in"), test_internal_func);
if let Ok(ret) = syms.call_symbol(&"test_func_in".to_string(), &args, true) {
match *ret {
Ctr::Bool(b) => assert!(b),
_ => {
print!("invalid return from func!");
assert!(false);
}
}
} else {
print!("call to function failed!");
assert!(false);
if let Ctr::Bool(b) = *syms.call_symbol(&"test_func_in".to_string(), &args, true).unwrap() {
assert!(b)
}
}
#[test]
fn decl_and_call_external_func_singlet() {
let mut syms = SymTable::new();
match lex(&"input".to_string()) {
Err(e) => panic!("{}", e),
Ok(finner) => {
let test_external_func: Symbol = Symbol {
name: String::from("echo"),
conditional_branches: false,
args: Args::Lazy(1),
value: ValueType::FuncForm(UserFn {
arg_syms: vec!["input".to_string()],
ast: finner,
}),
};
let finner = lex(&"input".to_string()).unwrap();
let test_external_func: Symbol = Symbol {
name: String::from("echo"),
conditional_branches: false,
args: Args::Lazy(1),
docs: String::new(),
value: ValueType::FuncForm(UserFn {
arg_syms: vec!["input".to_string()],
ast: finner,
}),
};
let args = Seg::from(
Box::new(Ctr::String("test".to_string())),
Box::new(Ctr::None),
);
let args = Seg::from(
Box::new(Ctr::String("test".to_string())),
Box::new(Ctr::None),
);
syms.insert(String::from("test_func_in"), test_external_func);
match syms.call_symbol(&"test_func_in".to_string(), &args, true) {
Ok(ret) => match *ret {
Ctr::String(b) => assert!(b == "test"),
_ => {
print!("Invalid return from func. Got {:?}\n", ret);
assert!(false);
}
},
Err(e) => {
print!("Call to function failed: {}\n", e);
assert!(false);
}
}
}
syms.insert(String::from("test_func_in"), test_external_func);
if let Ctr::Bool(b) = *syms.call_symbol(&"test_func_in".to_string(), &args, true).unwrap() {
assert!(b)
}
}
#[test]
fn decl_and_call_external_func_multi_body() {
let mut syms = SymTable::new();
match lex(&"(input input)".to_string()) {
Err(e) => panic!("{}", e),
Ok(finner) => {
let test_external_func: Symbol = Symbol {
name: String::from("echo_2"),
conditional_branches: false,
args: Args::Lazy(1),
value: ValueType::FuncForm(UserFn {
arg_syms: vec!["input".to_string()],
ast: finner,
}),
};
let finner = lex(&"input".to_string()).unwrap();
let test_external_func: Symbol = Symbol {
name: String::from("echo_2"),
conditional_branches: false,
args: Args::Lazy(1),
docs: String::new(),
value: ValueType::FuncForm(UserFn {
arg_syms: vec!["input".to_string()],
ast: finner,
}),
};
let args = Seg::from(
Box::new(Ctr::String("test".to_string())),
Box::new(Ctr::None),
);
let args = Seg::from(
Box::new(Ctr::String("test".to_string())),
Box::new(Ctr::None),
);
syms.insert(String::from("echo_2"), test_external_func);
match syms.call_symbol(&"echo_2".to_string(), &args, true) {
Ok(ret) => assert_eq!(ret.to_string(), "'test'"),
Err(e) => {
print!("Call to function failed: {}\n", e);
assert!(false);
}
}
}
}
syms.insert(String::from("echo_2"), test_external_func);
assert_eq!(*syms.call_symbol(&"echo_2".to_string(), &args, true)
.unwrap()
.to_string(),
"'test'".to_string());
}
#[test]
@ -121,6 +90,7 @@ mod func_tests {
name: String::from("test_inner"),
conditional_branches: false,
args: Args::Strict(vec![Type::Bool]),
docs: String::new(),
value: ValueType::Internal(Rc::new(
|a: &Seg, _: &mut SymTable| -> Result<Ctr, String> {
let inner = a;
@ -137,39 +107,25 @@ mod func_tests {
)),
};
match lex(&"((test_inner true))".to_string()) {
Err(e) => panic!("{}", e),
Ok(finner) => {
let outer_func: Symbol = Symbol {
name: String::from("test_outer"),
conditional_branches: false,
args: Args::Lazy(1),
value: ValueType::FuncForm(UserFn {
arg_syms: vec!["input".to_string()],
ast: finner,
}),
};
let finner = lex(&"((test_inner true))".to_string()).unwrap();
let outer_func: Symbol = Symbol {
name: String::from("test_outer"),
conditional_branches: false,
args: Args::Lazy(1),
docs: String::new(),
value: ValueType::FuncForm(UserFn {
arg_syms: vec!["input".to_string()],
ast: finner,
}),
};
let args = Seg::from(Box::new(Ctr::Bool(true)), Box::new(Ctr::None));
syms.insert(String::from("test_inner"), inner_func);
syms.insert(String::from("test_outer"), outer_func);
match syms.call_symbol(&"test_outer".to_string(), &args, true) {
Ok(ret) => match *ret {
Ctr::String(b) => assert!(b == "test"),
_ => {
print!("Invalid return from func. Got {:?}\n", ret);
assert!(false);
}
},
Err(e) => {
print!("Call to function failed: {}\n", e);
assert!(false);
}
}
}
}
let args = Seg::from(Box::new(Ctr::Bool(true)), Box::new(Ctr::None));
syms.insert(String::from("test_inner"), inner_func);
syms.insert(String::from("test_outer"), outer_func);
assert_eq!(syms.call_symbol(&"test_outer".to_string(), &args, true)
.unwrap()
.to_string(),
"'test'".to_string());
}
#[test]
@ -179,6 +135,7 @@ mod func_tests {
name: String::from("test_func_in"),
conditional_branches: false,
args: Args::Strict(vec![Type::Bool]),
docs: String::new(),
value: ValueType::Internal(Rc::new(
|a: &Seg, _: &mut SymTable| -> Result<Ctr, String> {
let inner = a;
@ -193,75 +150,66 @@ mod func_tests {
let args = Seg::from(Box::new(Ctr::Integer(1)), Box::new(Ctr::None));
syms.insert(String::from("test_func_in"), test_internal_func);
if let Err(s) = syms.call_symbol(&"test_func_in".to_string(), &args, true) {
assert_eq!(s, "failure to call test_func_in: arg 1 expected to be bool");
} else {
print!("call to function succeeded (shouldnt have)");
assert!(false);
}
assert_eq!(
syms.call_symbol(&"test_func_in".to_string(), &args, true)
.err()
.unwrap(),
"arg 1 expected to be bool".to_string(),
);
}
#[test]
fn too_many_args() {
let mut syms = SymTable::new();
match lex(&"(input)".to_string()) {
Err(e) => panic!("{}", e),
Ok(finner) => {
let test_external_func: Symbol = Symbol {
name: String::from("echo"),
conditional_branches: false,
args: Args::Lazy(1),
value: ValueType::FuncForm(UserFn {
arg_syms: vec!["input".to_string()],
ast: finner,
}),
};
let finner = lex(&"(input)".to_string()).unwrap();
let test_external_func: Symbol = Symbol {
name: String::from("echo"),
conditional_branches: false,
args: Args::Lazy(1),
docs: String::new(),
value: ValueType::FuncForm(UserFn {
arg_syms: vec!["input".to_string()],
ast: finner,
}),
};
let args = Seg::from(
Box::new(Ctr::String("test".to_string())),
Box::new(Ctr::Seg(Seg::from_mono(Box::new(Ctr::Integer(1))))),
);
let args = Seg::from(
Box::new(Ctr::String("test".to_string())),
Box::new(Ctr::Seg(Seg::from_mono(Box::new(Ctr::Integer(1))))),
);
syms.insert(String::from("test_func_in"), test_external_func);
if let Err(s) = syms.call_symbol(&"test_func_in".to_string(), &args, true) {
assert_eq!(s, "failure to call echo: expected 1 args. Got 2.");
} else {
print!("call to function succeeded (shouldnt have)");
assert!(false);
}
}
}
syms.insert(String::from("test_func_in"), test_external_func);
assert_eq!(
syms.call_symbol(&"test_func_in".to_string(), &args, true)
.err()
.unwrap(),
"expected 1 args. Got 2.".to_string(),
);
}
#[test]
fn too_few_args() {
let mut syms = SymTable::new();
match lex(&"(input)".to_string()) {
Err(e) => panic!("{}", e),
Ok(finner) => {
let test_external_func: Symbol = Symbol {
name: String::from("echo"),
conditional_branches: false,
args: Args::Lazy(1),
value: ValueType::FuncForm(UserFn {
arg_syms: vec!["input".to_string()],
ast: finner,
}),
};
let finner = lex(&"(input)".to_string()).unwrap();
let test_external_func: Symbol = Symbol {
name: String::from("echo"),
conditional_branches: false,
args: Args::Lazy(1),
docs: String::new(),
value: ValueType::FuncForm(UserFn {
arg_syms: vec!["input".to_string()],
ast: finner,
}),
};
let args = Seg::new();
syms.insert(String::from("test_func_in"), test_external_func);
if let Err(s) = syms.call_symbol(&"test_func_in".to_string(), &args, true) {
assert_eq!(s, "failure to call echo: expected 1 args. Got 0.");
} else {
print!("call to function succeeded (shouldnt have)");
assert!(false);
}
}
}
let args = Seg::new();
syms.insert(String::from("test_func_in"), test_external_func);
assert_eq!(
syms.call_symbol(&"test_func_in".to_string(), &args, true)
.err()
.unwrap(),
"expected 1 args. Got 0.".to_string(),
);
}
#[test]
@ -271,6 +219,7 @@ mod func_tests {
name: String::from("test_func_in"),
conditional_branches: false,
args: Args::Strict(vec![Type::Bool]),
docs: String::new(),
value: ValueType::Internal(Rc::new(
|a: &Seg, _: &mut SymTable| -> Result<Ctr, String> {
let inner = a;
@ -288,15 +237,12 @@ mod func_tests {
);
syms.insert(String::from("test_func_in"), test_internal_func);
if let Err(s) = syms.call_symbol(&"test_func_in".to_string(), &args, true) {
assert_eq!(
s,
"error in call to undefined-symbol: undefined symbol: undefined-symbol"
);
} else {
print!("call to function succeeded (shouldnt have)");
assert!(false);
}
assert_eq!(
syms.call_symbol(&"test_func_in".to_string(), &args, true)
.err()
.unwrap(),
"error in call to undefined-symbol: undefined symbol: undefined-symbol"
.to_string(),
);
}
}

View file

@ -4,131 +4,86 @@ mod lex_tests {
#[test]
fn test_lex_basic_pair() {
let document = String::from("(hello 'world')");
match lex(&document) {
Ok(tree) => {
assert_eq!(tree.to_string(), document);
}
Err(s) => {
print!("{}\n", s);
assert!(false);
}
}
assert_eq!(
lex(&document).unwrap().to_string(),
document
);
}
#[test]
fn test_lex_basic_list() {
let document = String::from("(hello 'world' 1 2 3)");
match lex(&document) {
Ok(tree) => {
assert_eq!(tree.to_string(), document);
}
Err(s) => {
print!("{}\n", s);
assert!(false);
}
}
assert_eq!(
lex(&document).unwrap().to_string(),
document
);
}
#[test]
fn test_lex_complex_list() {
let document = String::from("(hello 'world' (1 2 (1 2 3)) 1 2 3)");
match lex(&document) {
Ok(tree) => {
assert_eq!(tree.to_string(), document);
}
Err(s) => {
print!("{}\n", s);
assert!(false);
}
}
assert_eq!(
lex(&document).unwrap().to_string(),
document
);
}
#[test]
fn test_bad_symbol() {
let document = String::from("(as;dd)");
let output: &str = "Problem lexing document: \"Unparsable token: as;dd\"";
match lex(&document) {
Ok(tree) => {
print!("Bad token yielded: {}\n", tree.to_string());
assert!(false);
}
Err(s) => {
assert_eq!(s, output);
}
}
assert_eq!(
lex(&document).err().unwrap(),
output.to_string(),
);
}
#[test]
fn test_list_delim_in_str() {
let document = String::from("('(')");
match lex(&document) {
Ok(tree) => {
assert_eq!(tree.to_string(), document);
}
Err(s) => {
print!("{}\n", s);
assert!(false);
}
}
assert_eq!(
lex(&document).unwrap().to_string(),
document
);
}
#[test]
fn test_empty_string() {
let document = String::from("('')");
match lex(&document) {
Ok(tree) => {
assert_eq!(tree.to_string(), document);
}
Err(s) => {
print!("{}\n", s);
assert!(false);
}
}
assert_eq!(
lex(&document).unwrap().to_string(),
document
);
}
#[test]
fn test_unmatched_list_delim_flat() {
let document = String::from("(one two");
let output: &str = "Problem lexing document: \"Unmatched list delimiter in input\"";
match lex(&document) {
Ok(tree) => {
print!("Bad token yielded: {}\n", tree.to_string());
assert!(false);
}
Err(s) => {
assert_eq!(s, output);
}
}
assert_eq!(
lex(&document).err().unwrap(),
output.to_string(),
);
}
#[test]
fn test_unmatched_list_delim_complex() {
let document = String::from("(one two (three)");
let output: &str = "Problem lexing document: \"Unmatched list delimiter in input\"";
match lex(&document) {
Ok(tree) => {
print!("Bad token yielded: {}\n", tree);
assert!(false);
}
Err(s) => {
assert_eq!(s, output);
}
}
assert_eq!(
lex(&document).err().unwrap(),
output.to_string(),
);
}
#[test]
fn test_comment() {
let document = String::from("#!/bin/relish\n(one two)");
let output: &str = "(one two)";
match lex(&document) {
Ok(tree) => {
assert_eq!(tree.to_string(), output);
}
Err(s) => {
print!("{}\n", s);
assert!(false);
}
}
assert_eq!(
lex(&document).unwrap().to_string(),
output.to_string(),
);
}
#[test]
@ -136,44 +91,30 @@ mod lex_tests {
let document =
String::from("#!/bin/relish\n((one two)# another doc comment\n(three four))");
let output: &str = "((one two) (three four))";
match lex(&document) {
Ok(tree) => {
assert_eq!(tree.to_string(), output.to_string());
}
Err(s) => {
print!("{}\n", s);
assert!(false);
}
}
assert_eq!(
lex(&document).unwrap().to_string(),
output.to_string(),
);
}
#[test]
fn test_inline_comment() {
let document = String::from("#!/bin/relish\n((one two)\n# another doc comment\nthree)");
let output: &str = "((one two) three)";
match lex(&document) {
Ok(tree) => {
assert_eq!(tree.to_string(), output.to_string());
}
Err(s) => {
print!("{}\n", s);
assert!(false);
}
}
assert_eq!(
lex(&document).unwrap().to_string(),
output.to_string(),
);
}
#[test]
fn test_bad_token_list() {
let document = String::from("(one t(wo)");
let output: &str = "Problem lexing document: \"list started in middle of another token\"";
match lex(&document) {
Ok(tree) => {
print!("Bad token yielded: {}\n", tree);
assert!(false);
}
Err(s) => {
assert_eq!(s, output);
}
}
assert_eq!(
lex(&document).err().unwrap(),
output.to_string(),
);
}
}

View file

@ -1,5 +1,5 @@
mod append_lib_tests {
use relish::ast::{eval, lex, Ctr, SymTable};
use relish::ast::{eval, lex, SymTable};
use relish::stdlib::{dynamic_stdlib, static_stdlib};
#[test]
@ -10,14 +10,10 @@ mod append_lib_tests {
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Seg(ref s) = *eval(&tree, &mut syms).unwrap() {
assert_eq!(s.to_string(), result);
}
} else {
assert!(false)
}
assert_eq!(
*eval(&lex(&document.to_string()).unwrap(), &mut syms).unwrap().to_string(),
result.to_string(),
);
}
#[test]
@ -29,13 +25,10 @@ mod append_lib_tests {
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Seg(ref s) = *eval(&tree, &mut syms).unwrap() {
assert_eq!(s.to_string(), result);
}
} else {
assert!(false)
}
assert_eq!(
*eval(&lex(&document.to_string()).unwrap(), &mut syms).unwrap().to_string(),
result.to_string(),
);
}
#[test]
@ -47,13 +40,10 @@ mod append_lib_tests {
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Seg(ref s) = *eval(&tree, &mut syms).unwrap() {
assert_eq!(s.to_string(), result);
}
} else {
assert!(false);
}
assert_eq!(
*eval(&lex(&document.to_string()).unwrap(), &mut syms).unwrap().to_string(),
result.to_string(),
);
}
#[test]
@ -65,13 +55,10 @@ mod append_lib_tests {
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Seg(ref s) = *eval(&tree, &mut syms).unwrap() {
assert_eq!(s.to_string(), result);
}
} else {
assert!(false);
}
assert_eq!(
*eval(&lex(&document.to_string()).unwrap(), &mut syms).unwrap().to_string(),
result.to_string(),
);
}
#[test]
@ -83,12 +70,9 @@ mod append_lib_tests {
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Seg(ref s) = *eval(&tree, &mut syms).unwrap() {
assert_eq!(s.to_string(), result);
}
} else {
assert!(false);
}
assert_eq!(
*eval(&lex(&document.to_string()).unwrap(), &mut syms).unwrap().to_string(),
result.to_string(),
);
}
}

View file

@ -5,146 +5,99 @@ mod bool_lib_tests {
#[test]
fn test_and_true_chain() {
let document = "(and true true true true true)";
let result = true;
let result = "true";
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Bool(b) = *eval(&tree, &mut syms).unwrap() {
assert_eq!(b, result);
} else {
assert!(false);
}
} else {
assert!(false);
}
assert_eq!(
*eval(&lex(&document.to_string()).unwrap(), &mut syms).unwrap().to_string(),
result.to_string(),
);
}
#[test]
fn test_and_true_chain_with_false() {
let document = "(and true true false true true)";
let result = false;
let result = "false";
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Bool(i) = *eval(&tree, &mut syms).unwrap() {
assert_eq!(i, result);
} else {
assert!(false);
}
} else {
assert!(false);
}
assert_eq!(
*eval(&lex(&document.to_string()).unwrap(), &mut syms).unwrap().to_string(),
result.to_string(),
);
}
#[test]
fn test_and_false_chain() {
let document = "(and false false false false false)";
let result = false;
let result = "false";
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Bool(i) = *eval(&tree, &mut syms).unwrap() {
assert_eq!(i, result);
} else {
assert!(false);
}
} else {
assert!(false);
}
assert_eq!(
*eval(&lex(&document.to_string()).unwrap(), &mut syms).unwrap().to_string(),
result.to_string(),
);
}
#[test]
fn test_or_true_chain() {
let document = "(or true true true true true)";
let result = true;
let result = "true";
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
assert_eq!(
*eval(&lex(&document.to_string()).unwrap(), &mut syms).unwrap().to_string(),
result.to_string(),
);
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Bool(b) = *eval(&tree, &mut syms).unwrap() {
assert_eq!(b, result);
} else {
assert!(false);
}
} else {
assert!(false);
}
}
#[test]
fn test_or_true_chain_with_false() {
let document = "(or true true false true true)";
let result = true;
let result = "true";
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
assert_eq!(
*eval(&lex(&document.to_string()).unwrap(), &mut syms).unwrap().to_string(),
result.to_string(),
);
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Bool(i) = *eval(&tree, &mut syms).unwrap() {
assert_eq!(i, result);
} else {
assert!(false);
}
} else {
assert!(false);
}
}
#[test]
fn test_or_false_chain() {
let document = "(or false false false false)";
let result = false;
let document = "(or false false false false false)";
let result = "false";
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Bool(i) = *eval(&tree, &mut syms).unwrap() {
assert_eq!(i, result);
} else {
assert!(false);
}
} else {
assert!(false);
}
assert_eq!(
*eval(&lex(&document.to_string()).unwrap(), &mut syms).unwrap().to_string(),
result.to_string(),
);
}
#[test]
fn test_not() {
let document = "(not true)";
let result = false;
let result = "false";
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Bool(i) = *eval(&tree, &mut syms).unwrap() {
assert_eq!(i, result);
} else {
assert!(false);
}
} else {
assert!(false);
}
assert_eq!(
*eval(&lex(&document.to_string()).unwrap(), &mut syms).unwrap().to_string(),
result.to_string(),
);
}
#[test]
fn test_toggle_a_bool() {
let document = "(def tester true)";
let document = "(def tester '' true)";
let change = "(toggle tester)";
let check = "(tester)";
@ -183,7 +136,7 @@ mod bool_lib_tests {
#[test]
fn test_toggle_errors_dont_lose_vars() {
let document = "(def tester 'oops')";
let document = "(def tester '' 'oops')";
let change = "(toggle tester)";
let check = "(tester)";
@ -216,7 +169,7 @@ mod bool_lib_tests {
#[test]
fn test_toggle_errors_dont_lose_funcs() {
let document = "(def tester (oops) oops)";
let document = "(def tester '' (oops) oops)";
let change = "(toggle tester)";
let check = "(tester '1')";

View file

@ -1,66 +1,44 @@
mod control_lib_tests {
use relish::ast::{eval, lex, Ctr, SymTable};
use relish::ast::{eval, lex, SymTable};
use relish::stdlib::{dynamic_stdlib, static_stdlib};
#[test]
fn test_if_first_case_singlet() {
let document = "(if true 1 2)";
let result = 1;
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Integer(i) = *eval(&tree, &mut syms).unwrap() {
assert_eq!(i, result);
} else {
assert!(false);
}
} else {
assert!(false);
}
assert_eq!(
*eval(&lex(&document.to_string()).unwrap(), &mut syms).unwrap().to_string(),
result.to_string(),
);
}
#[test]
fn test_if_second_case_singlet() {
let document = "(if false 1 2)";
let result = 2;
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Integer(i) = *eval(&tree, &mut syms).unwrap() {
assert_eq!(i, result);
} else {
eprintln!("{}", *eval(&tree, &mut syms).unwrap());
assert!(false);
}
} else {
assert!(false);
}
assert_eq!(
*eval(&lex(&document.to_string()).unwrap(), &mut syms).unwrap().to_string(),
result.to_string(),
);
}
#[test]
fn test_complex_case_call() {
let document = "(if true (append () 1) 2)";
let result = "(1)";
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Seg(ref i) = *eval(&tree, &mut syms).unwrap() {
assert_eq!(i.to_string(), result);
} else {
assert!(false);
}
} else {
assert!(false);
}
assert_eq!(
*eval(&lex(&document.to_string()).unwrap(), &mut syms).unwrap().to_string(),
result.to_string(),
);
}
#[test]
@ -70,45 +48,30 @@ mod control_lib_tests {
(temp (append () temp '2')))
temp)";
let result = "('1' '2')";
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Seg(ref i) = *eval(&tree, &mut syms).unwrap() {
assert_eq!(i.to_string(), result);
} else {
assert!(false);
}
} else {
assert!(false);
}
assert_eq!(
*eval(&lex(&document.to_string()).unwrap(), &mut syms).unwrap().to_string(),
result.to_string(),
);
}
#[test]
fn test_let_multibody_evals() {
let document = "(let ((temp '1')) temp (append () temp '2'))";
let result = "('1' '2')";
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Seg(ref i) = *eval(&tree, &mut syms).unwrap() {
assert_eq!(i.to_string(), result);
} else {
assert!(false);
}
} else {
assert!(false);
}
assert_eq!(
*eval(&lex(&document.to_string()).unwrap(), &mut syms).unwrap().to_string(),
result.to_string(),
);
}
#[test]
fn test_let_multiphase_local_multibody_evals() {
// prints 'first body' and then returns ('1' '2' '3')
let document = "(let (
(temp '1')
(temp (append () temp '2')))
@ -116,33 +79,26 @@ mod control_lib_tests {
(append temp '3'))";
let result = "('1' '2' '3')";
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Seg(ref i) = *eval(&tree, &mut syms).unwrap() {
assert_eq!(i.to_string(), result);
} else {
assert!(false);
}
} else {
assert!(false);
}
assert_eq!(
*eval(&lex(&document.to_string()).unwrap(), &mut syms).unwrap().to_string(),
result.to_string(),
);
}
#[test]
fn test_while_basic() {
let switch_dec = "(def switch true)";
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)
(def prev '' switch)
(toggle switch)
(if switch
(def prev)
(def '' prev)
()))";
let test_check = "prev";
@ -161,15 +117,15 @@ mod control_lib_tests {
#[test]
fn test_while_eval_cond() {
let switch_dec = "(def switch true)";
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)
(def prev '' switch)
(toggle switch)
(if switch
(def prev)
(def '' prev)
()))";
let test_check = "prev";
@ -188,15 +144,15 @@ mod control_lib_tests {
#[test]
fn test_while_2_iter() {
let additional = "(def sw1 true)";
let switch_dec = "(def sw2 true)";
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')))";
(def sw1 '' false)
(def result '' 'yay')))";
let test_check = "result";
let another_tree = lex(&additional.to_string()).unwrap();
@ -216,7 +172,7 @@ mod control_lib_tests {
#[test]
fn test_circuit_basic() {
let document = "(if (circuit true (and true true) true) (def result 'passed') ())";
let document = "(if (circuit true (and true true) true) (def result '' 'passed') ())";
let test = "result";
let doc_tree = lex(&document.to_string()).unwrap();
@ -228,13 +184,12 @@ mod control_lib_tests {
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 document = "(if (circuit true (and false true) true) (def result '' 'passed') ())";
let test = "result";
let doc_tree = lex(&document.to_string()).unwrap();
@ -245,13 +200,9 @@ mod control_lib_tests {
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!();
}
assert_eq!(
eval(&test_tree, &mut syms).err().unwrap(),
"error in call to result: undefined symbol: result".to_string()
);
}
}

View file

@ -4,7 +4,7 @@ mod var_lib_tests {
#[test]
fn test_variable_def_and_lookup() {
let doc1 = "(def test 1)";
let doc1 = "(def test 'my test var' 1)";
let doc2 = "(test)";
let result = "(1)";
@ -42,7 +42,7 @@ mod var_lib_tests {
#[test]
fn test_func_def_and_lookup() {
let doc1 = "(def test (hello) hello)";
let doc1 = "(def test 'my test func' (hello) hello)";
let doc2 = "(test '1')";
let result = "1";
@ -79,8 +79,8 @@ mod var_lib_tests {
#[test]
fn test_variable_def_redef_and_lookup() {
let doc1 = "(def test 1)";
let doc2 = "(def test '2')";
let doc1 = "(def test 'my test var' 1)";
let doc2 = "(def test 'my test var' '2')";
let doc3 = "(test)";
let result = "('2')";
@ -132,7 +132,7 @@ mod var_lib_tests {
#[test]
fn test_variable_def_undef_and_lookup_fail() {
let doc1 = "(def test 1)";
let doc1 = "(def test 'my test var' 1)";
let doc2 = "(def test)";
let doc3 = "(test)";
@ -185,4 +185,41 @@ mod var_lib_tests {
assert!(false);
}
}
#[test]
fn test_func_def_no_args() {
let doc1 = "(def test 'my test func' () '1')";
let doc2 = "(test)";
let result = "1";
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&doc1.to_string()) {
let eval_result = *eval(&tree, &mut syms).unwrap();
if let Ctr::None = eval_result {
// pass
} else {
eprintln!("bad: {eval_result}");
assert!(false);
}
} else {
eprintln!("couldn't lex doc1");
assert!(false);
}
if let Ok(tree) = lex(&doc2.to_string()) {
let eval_result = *eval(&tree, &mut syms).unwrap();
if let Ctr::String(ref i) = eval_result {
assert_eq!(i.to_string(), result);
} else {
eprintln!("bad: {eval_result}");
assert!(false);
}
} else {
eprintln!("couldn't lex doc2");
assert!(false);
}
}
}