diff --git a/.rustfmt.toml b/.rustfmt.toml index 82c4323b..79bf0b74 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -1,3 +1,3 @@ -max_width = 120 +max_width = 136 tab_spaces = 2 diff --git a/Cargo.lock b/Cargo.lock index 4600c0b0..382d9451 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,7 +39,7 @@ dependencies = [ [[package]] name = "calcit_runner" -version = "0.5.0-a5" +version = "0.5.0-a6" dependencies = [ "cirru_edn", "cirru_parser", @@ -66,9 +66,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cirru_edn" -version = "0.2.0-a1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d330ef840d99262797910f774aa2d210987464cc3f29849f63d214d274fe44" +checksum = "2c7cac61b1f862d248bb55df7f5120e122d6394498f96fa40d60afeaa1cab45b" dependencies = [ "cirru_parser", ] diff --git a/Cargo.toml b/Cargo.toml index 2b0d5dd1..115a58d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "calcit_runner" -version = "0.5.0-a5" +version = "0.5.0-a6" authors = ["jiyinyiyong "] edition = "2018" license = "MIT" @@ -20,7 +20,7 @@ exclude = [ # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -cirru_edn = "0.2.0-a1" +cirru_edn = "0.2.0" cirru_parser = "0.1.8" clap = "2.33.3" dirs = "4.0.0" diff --git a/calcit/calcit.cirru b/calcit/calcit.cirru index 6255bd78..2cb2f679 100644 --- a/calcit/calcit.cirru +++ b/calcit/calcit.cirru @@ -1010,7 +1010,7 @@ :by |u0 |yT $ {} :data $ {} - |T $ {} (:text |echo-values) (:type :leaf) (:at 1618659589617) (:by |u0) + |T $ {} (:text |print-values) (:type :leaf) (:at 1633952520593) (:by |u0) |j $ {} (:text |1) (:type :leaf) (:at 1618659590535) (:by |u0) |r $ {} (:text "|\"1") (:type :leaf) (:at 1618659591512) (:by |u0) |v $ {} (:text |:a) (:type :leaf) (:at 1618659595541) (:by |u0) @@ -1130,7 +1130,7 @@ :by |u0 |yj $ {} :data $ {} - |D $ {} (:type :leaf) (:by |u0) (:at 1633873455342) (:text |;) + |D $ {} (:text |;) (:type :leaf) (:at 1633873455342) (:by |u0) |T $ {} (:text |show-data) (:type :leaf) (:at 1633872991931) (:by |u0) :type :expr :at 1633872988484 diff --git a/calcit/compact.cirru b/calcit/compact.cirru index 77562f3c..9cc8ee43 100644 --- a/calcit/compact.cirru +++ b/calcit/compact.cirru @@ -61,7 +61,7 @@ defn demos () (echo "\"demo") echo $ &+ 2 2 echo "\"f1" $ f1 - echo-values 1 "\"1" :a $ [] 1 2 + print-values 1 "\"1" :a $ [] 1 2 echo $ &{} :a 1 :b 2 echo $ #{} 1 2 3 |four lib/f2 diff --git a/package.json b/package.json index 3d34d02b..c1e86ef6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@calcit/procs", - "version": "0.5.0-a5", + "version": "0.5.0-a6", "main": "./lib/calcit.procs.js", "devDependencies": { "@types/node": "^16.9.6", diff --git a/src/bin/cr.rs b/src/bin/cr.rs index aa53bd46..11efa03e 100644 --- a/src/bin/cr.rs +++ b/src/bin/cr.rs @@ -27,7 +27,7 @@ fn main() -> Result<(), String> { // get dirty functions injected #[cfg(not(target_arch = "wasm32"))] - builtins::register_import_proc("&call-dylib-edn", injection::call_dylib_edn); + injection::inject_platform_apis(); let cli_matches = cli_args::parse_cli(); let settings = ProgramSettings { @@ -79,14 +79,8 @@ fn main() -> Result<(), String> { } } } - let init_fn = cli_matches - .value_of("init-fn") - .or(Some(&snapshot.configs.init_fn)) - .unwrap(); - let reload_fn = cli_matches - .value_of("reload-fn") - .or(Some(&snapshot.configs.reload_fn)) - .unwrap(); + let init_fn = cli_matches.value_of("init-fn").or(Some(&snapshot.configs.init_fn)).unwrap(); + let reload_fn = cli_matches.value_of("reload-fn").or(Some(&snapshot.configs.reload_fn)).unwrap(); // attach core for (k, v) in core_snapshot.files { @@ -104,7 +98,8 @@ fn main() -> Result<(), String> { calcit_runner::primes::BUILTIN_CLASSES_ENTRY, None, check_warnings, - )?; + ) + .map_err(|e| e.msg)?; let task = if settings.emit_js { run_codegen(init_fn, reload_fn, &program_code, &settings.emit_path, false) @@ -113,7 +108,12 @@ fn main() -> Result<(), String> { } else { let started_time = Instant::now(); - let v = calcit_runner::run_program(init_fn, im::vector![], &program_code)?; + let v = calcit_runner::run_program(init_fn, im::vector![], &program_code).map_err(|e| { + for w in e.warnings { + println!("{}", w); + } + e.msg + })?; let duration = Instant::now().duration_since(started_time); println!("took {}ms: {}", duration.as_micros() as f64 / 1000.0, v); @@ -215,7 +215,12 @@ fn recall_program( } else { // run from `reload_fn` after reload let started_time = Instant::now(); - let v = calcit_runner::run_program(reload_fn, im::vector![], &new_code)?; + let v = calcit_runner::run_program(reload_fn, im::vector![], &new_code).map_err(|e| { + for w in e.warnings { + println!("{}", w); + } + e.msg + })?; let duration = Instant::now().duration_since(started_time); println!("took {}ms: {}", duration.as_micros() as f64 / 1000.0, v); Ok(()) @@ -266,17 +271,16 @@ fn run_codegen( Ok(_) => (), Err(failure) => { println!("\nfailed preprocessing, {}", failure); - call_stack::display_stack(&failure)?; + call_stack::display_stack(&failure.msg)?; let _ = fs::write( &js_file_path, format!( "export default \"Preprocessing failed:\\n{}\";", - failure.trim().escape_default() + failure.msg.trim().escape_default() ), ); - - return Err(failure); + return Err(failure.msg); } } @@ -285,8 +289,8 @@ fn run_codegen( Ok(_) => (), Err(failure) => { println!("\nfailed preprocessing, {}", failure); - call_stack::display_stack(&failure)?; - return Err(failure); + call_stack::display_stack(&failure.msg)?; + return Err(failure.msg); } } let warnings = check_warnings.to_owned().into_inner(); @@ -297,10 +301,7 @@ fn run_codegen( content = format!("{}\n{}", content, message); } - let _ = fs::write( - &js_file_path, - format!("export default \"{}\";", content.trim().escape_default()), - ); + let _ = fs::write(&js_file_path, format!("export default \"{}\";", content.trim().escape_default())); return Err(format!( "Found {} warnings, codegen blocked. errors in {}.js", warnings.len(), diff --git a/src/bin/injection/mod.rs b/src/bin/injection/mod.rs index 108c7ce8..b3ea94bc 100644 --- a/src/bin/injection/mod.rs +++ b/src/bin/injection/mod.rs @@ -1,43 +1,65 @@ use cirru_edn::Edn; use calcit_runner::{ + builtins, data::edn::{calcit_to_edn, edn_to_calcit}, - primes::{Calcit, CalcitItems, CrListWrap}, + primes::{Calcit, CalcitErr, CalcitItems, CrListWrap}, }; /// FFI protocol types type EdnFfi = fn(args: Vec) -> Result; +pub fn inject_platform_apis() { + builtins::register_import_proc("&call-dylib-edn", call_dylib_edn); + builtins::register_import_proc("echo", echo); + builtins::register_import_proc("println", echo); +} + // &call-dylib-edn -pub fn call_dylib_edn(xs: &CalcitItems) -> Result { +pub fn call_dylib_edn(xs: &CalcitItems) -> Result { if xs.is_empty() { - return Err(format!( + return Err(CalcitErr::use_string(format!( "&call-dylib-edn expected >2 arguments, got {}", CrListWrap(xs.to_owned()) - )); + ))); } let lib_name = if let Calcit::Str(s) = &xs[0] { s.to_owned() } else { - return Err(format!("&call-dylib-edn expected a lib_name, got {}", xs[0])); + return Err(CalcitErr::use_string(format!("&call-dylib-edn expected a lib_name, got {}", xs[0]))); }; let method: String = if let Calcit::Str(s) = &xs[1] { s.to_owned() } else { - return Err(format!("&call-dylib-edn expected a method name, got {}", xs[1])); + return Err(CalcitErr::use_string(format!( + "&call-dylib-edn expected a method name, got {}", + xs[1] + ))); }; let mut ys: Vec = vec![]; for (idx, v) in xs.iter().enumerate() { if idx > 1 { - ys.push(calcit_to_edn(v)?); + ys.push(calcit_to_edn(v).map_err(CalcitErr::use_string)?); } } unsafe { let lib = libloading::Library::new(&lib_name).expect("dylib not found"); let func: libloading::Symbol = lib.get(method.as_bytes()).expect("dy function not found"); - let ret = func(ys.to_owned())?; + let ret = func(ys.to_owned()).map_err(CalcitErr::use_string)?; Ok(edn_to_calcit(&ret)) } } + +pub fn echo(xs: &CalcitItems) -> Result { + let mut s = String::from(""); + for (idx, x) in xs.iter().enumerate() { + if idx > 0 { + s.push(' '); + } + s.push_str(&x.turn_string()); + } + println!("{}", s); + Ok(Calcit::Nil) +} diff --git a/src/builtins.rs b/src/builtins.rs index 95129a1d..a13e2151 100644 --- a/src/builtins.rs +++ b/src/builtins.rs @@ -14,10 +14,10 @@ mod syntax; use std::collections::HashMap; use std::sync::RwLock; -use crate::primes::{Calcit, CalcitItems, CalcitScope, CalcitSyntax}; +use crate::primes::{Calcit, CalcitErr, CalcitItems, CalcitScope, CalcitSyntax}; use crate::program::ProgramCodeData; -pub type FnType = fn(xs: &CalcitItems) -> Result; +pub type FnType = fn(xs: &CalcitItems) -> Result; lazy_static! { static ref IMPORTED_PROCS: RwLock> = RwLock::new(HashMap::new()); @@ -45,9 +45,6 @@ pub fn is_proc_name(s: &str) -> bool { | "&tuple:assoc" // effects | "&display-stack" - | "echo" - | "println" // alias for echo - | "echo-values" | "raise" | "quit!" | "get-env" @@ -193,7 +190,7 @@ pub fn is_proc_name(s: &str) -> bool { } } -pub fn handle_proc(name: &str, args: &CalcitItems) -> Result { +pub fn handle_proc(name: &str, args: &CalcitItems) -> Result { match name { // meta "type-of" => meta::type_of(args), @@ -214,9 +211,6 @@ pub fn handle_proc(name: &str, args: &CalcitItems) -> Result { "&tuple:assoc" => meta::assoc(args), // effects "&display-stack" => meta::display_stack(args), - "echo" => effects::echo(args), - "println" => effects::echo(args), // alias - "echo-values" => effects::echo_values(args), "raise" => effects::raise(args), "quit!" => effects::quit(args), "get-env" => effects::get_env(args), @@ -359,7 +353,7 @@ pub fn handle_proc(name: &str, args: &CalcitItems) -> Result { let f = ps[name]; f(args) } else { - Err(format!("No such proc: {}", a)) + Err(CalcitErr::use_string(format!("No such proc: {}", a))) } } } @@ -377,7 +371,7 @@ pub fn handle_syntax( scope: &CalcitScope, file_ns: &str, program: &ProgramCodeData, -) -> Result { +) -> Result { match name { CalcitSyntax::Defn => syntax::defn(nodes, scope, file_ns, program), CalcitSyntax::Eval => syntax::eval(nodes, scope, file_ns, program), diff --git a/src/builtins/effects.rs b/src/builtins/effects.rs index 80134970..6ce08ef2 100644 --- a/src/builtins/effects.rs +++ b/src/builtins/effects.rs @@ -5,7 +5,7 @@ use std::sync::RwLock; use std::time::Instant; use crate::{ - primes::{load_kwd, Calcit, CalcitItems}, + primes::{load_kwd, Calcit, CalcitErr, CalcitItems}, util::number::f64_to_i32, }; @@ -21,7 +21,7 @@ lazy_static! { static ref CLI_RUNNING_MODE: RwLock = RwLock::new(CliRunningMode::Eval); } -pub fn echo(xs: &CalcitItems) -> Result { +pub fn raise(xs: &CalcitItems) -> Result { let mut s = String::from(""); for (idx, x) in xs.iter().enumerate() { if idx > 0 { @@ -29,31 +29,7 @@ pub fn echo(xs: &CalcitItems) -> Result { } s.push_str(&x.turn_string()); } - println!("{}", s); - Ok(Calcit::Nil) -} - -pub fn echo_values(xs: &CalcitItems) -> Result { - let mut s = String::from(""); - for (idx, x) in xs.iter().enumerate() { - if idx > 0 { - s.push(' '); - } - s.push_str(&format!("{}", x)); - } - println!("{}", s); - Ok(Calcit::Nil) -} - -pub fn raise(xs: &CalcitItems) -> Result { - let mut s = String::from(""); - for (idx, x) in xs.iter().enumerate() { - if idx > 0 { - s.push(' '); - } - s.push_str(&x.turn_string()); - } - Err(s) + Err(CalcitErr::use_string(s)) } pub fn init_effects_states() { @@ -61,7 +37,7 @@ pub fn init_effects_states() { let _eff = STARTED_INSTANT.read().unwrap(); } -pub fn cpu_time(_xs: &CalcitItems) -> Result { +pub fn cpu_time(_xs: &CalcitItems) -> Result { let now = Instant::now(); let started = STARTED_INSTANT.read().unwrap().to_owned(); @@ -82,7 +58,7 @@ pub fn modify_cli_running_mode(mode: CliRunningMode) -> Result<(), String> { Ok(()) } -pub fn calcit_running_mode(_xs: &CalcitItems) -> Result { +pub fn calcit_running_mode(_xs: &CalcitItems) -> Result { let mode = CLI_RUNNING_MODE.read().unwrap().to_owned(); match mode { CliRunningMode::Eval => Ok(load_kwd("eval")), @@ -92,22 +68,22 @@ pub fn calcit_running_mode(_xs: &CalcitItems) -> Result { } // TODO -pub fn call_get_calcit_backend(_xs: &CalcitItems) -> Result { +pub fn call_get_calcit_backend(_xs: &CalcitItems) -> Result { Ok(load_kwd("rust")) } -pub fn quit(xs: &CalcitItems) -> Result { +pub fn quit(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Number(n)) => match f64_to_i32(*n) { Ok(code) => exit(code), Err(e) => unreachable!("quit failed to get code from f64, {}", e), }, - Some(a) => Err(format!("quit expected i32 value, got: {}", a)), - None => Err(String::from("quit expected a code, got nothing")), + Some(a) => Err(CalcitErr::use_string(format!("quit expected i32 value, got: {}", a))), + None => Err(CalcitErr::use_str("quit expected a code, got nothing")), } } -pub fn get_env(xs: &CalcitItems) -> Result { +pub fn get_env(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Str(s)) => match env::var(s) { Ok(v) => Ok(Calcit::Str(v)), @@ -116,29 +92,32 @@ pub fn get_env(xs: &CalcitItems) -> Result { Ok(Calcit::Nil) } }, - Some(a) => Err(format!("get-env expected a string, got {}", a)), - None => Err(String::from("get-env expected an argument, got nothing")), + Some(a) => Err(CalcitErr::use_string(format!("get-env expected a string, got {}", a))), + None => Err(CalcitErr::use_str("get-env expected an argument, got nothing")), } } -pub fn read_file(xs: &CalcitItems) -> Result { +pub fn read_file(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Str(s)) => match fs::read_to_string(s) { Ok(content) => Ok(Calcit::Str(content)), - Err(e) => Err(format!("read-file failed: {}", e)), + Err(e) => Err(CalcitErr::use_string(format!("read-file failed: {}", e))), }, - Some(a) => Err(format!("read-file expected a string, got: {}", a)), - None => Err(String::from("read-file expected a filename, got nothing")), + Some(a) => Err(CalcitErr::use_string(format!("read-file expected a string, got: {}", a))), + None => Err(CalcitErr::use_str("read-file expected a filename, got nothing")), } } -pub fn write_file(xs: &CalcitItems) -> Result { +pub fn write_file(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Str(path)), Some(Calcit::Str(content))) => match fs::write(path, content) { Ok(_) => Ok(Calcit::Nil), - Err(e) => Err(format!("write-file failed, {}", e)), + Err(e) => Err(CalcitErr::use_string(format!("write-file failed, {}", e))), }, - (Some(a), Some(b)) => Err(format!("write-file expected 3 strings, got: {} {}", a, b)), - (a, b) => Err(format!("write-file expected 2 strings, got: {:?} {:?}", a, b)), + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!("write-file expected 3 strings, got: {} {}", a, b))), + (a, b) => Err(CalcitErr::use_string(format!( + "write-file expected 2 strings, got: {:?} {:?}", + a, b + ))), } } diff --git a/src/builtins/ffi.rs b/src/builtins/ffi.rs index 00b85ae9..a1e1dfe2 100644 --- a/src/builtins/ffi.rs +++ b/src/builtins/ffi.rs @@ -1,9 +1,9 @@ use crate::{ - primes::{Calcit, CalcitItems}, + primes::{Calcit, CalcitErr, CalcitItems}, program, }; -pub fn ffi_message(xs: &CalcitItems) -> Result { +pub fn ffi_message(xs: &CalcitItems) -> Result { if !xs.is_empty() { match &xs[0] { Calcit::Str(s) | Calcit::Symbol(s, ..) => { @@ -11,9 +11,9 @@ pub fn ffi_message(xs: &CalcitItems) -> Result { program::send_ffi_message(s.to_owned(), items); Ok(Calcit::Nil) } - a => Err(format!("&ffi-message expected string, got {}", a)), + a => Err(CalcitErr::use_string(format!("&ffi-message expected string, got {}", a))), } } else { - Err(String::from("&ffi-message expected arguments but got empty")) + Err(CalcitErr::use_str("&ffi-message expected arguments but got empty")) } } diff --git a/src/builtins/lists.rs b/src/builtins/lists.rs index 82cc6a31..6a312da2 100644 --- a/src/builtins/lists.rs +++ b/src/builtins/lists.rs @@ -1,40 +1,49 @@ use core::cmp::Ordering; -use crate::primes::{Calcit, CalcitItems, CalcitScope, CrListWrap}; +use crate::primes::{Calcit, CalcitErr, CalcitItems, CalcitScope, CrListWrap}; use crate::util::number::f64_to_usize; use crate::builtins; use crate::program::ProgramCodeData; use crate::runner; -pub fn new_list(xs: &CalcitItems) -> Result { +pub fn new_list(xs: &CalcitItems) -> Result { Ok(Calcit::List(xs.to_owned())) } -pub fn count(xs: &CalcitItems) -> Result { +pub fn count(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::List(ys)) => Ok(Calcit::Number(ys.len() as f64)), - Some(a) => Err(format!("list count expected a list, got: {}", a)), - None => Err(String::from("list count expected 1 argument")), + Some(a) => Err(CalcitErr::use_string(format!("list count expected a list, got: {}", a))), + None => Err(CalcitErr::use_str("list count expected 1 argument")), } } -pub fn nth(xs: &CalcitItems) -> Result { +pub fn nth(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::List(ys)), Some(Calcit::Number(n))) => match f64_to_usize(*n) { Ok(idx) => match ys.get(idx) { Some(v) => Ok(v.to_owned()), None => Ok(Calcit::Nil), }, - Err(e) => Err(format!("nth expect usize, {}", e)), + Err(e) => Err(CalcitErr::use_string(format!("nth expect usize, {}", e))), }, - (Some(_), None) => Err(format!("string nth expected a list and index, got: {:?}", xs)), - (None, Some(_)) => Err(format!("string nth expected a list and index, got: {:?}", xs)), - (_, _) => Err(format!("nth expected 2 argument, got: {}", CrListWrap(xs.to_owned()))), + (Some(_), None) => Err(CalcitErr::use_string(format!( + "string nth expected a list and index, got: {:?}", + xs + ))), + (None, Some(_)) => Err(CalcitErr::use_string(format!( + "string nth expected a list and index, got: {:?}", + xs + ))), + (_, _) => Err(CalcitErr::use_string(format!( + "nth expected 2 argument, got: {}", + CrListWrap(xs.to_owned()) + ))), } } -pub fn slice(xs: &CalcitItems) -> Result { +pub fn slice(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::List(ys)), Some(Calcit::Number(from))) => { let to_idx = match xs.get(2) { @@ -42,43 +51,43 @@ pub fn slice(xs: &CalcitItems) -> Result { let idx: usize = unsafe { to.to_int_unchecked() }; idx } - Some(a) => return Err(format!("slice expected number index, got: {}", a)), + Some(a) => return Err(CalcitErr::use_string(format!("slice expected number index, got: {}", a))), None => ys.len(), }; let from_idx: usize = unsafe { from.to_int_unchecked() }; Ok(Calcit::List(ys.to_owned().slice(from_idx..to_idx))) } - (Some(Calcit::List(_)), Some(a)) => Err(format!("slice expected index number, got: {}", a)), - (Some(Calcit::List(_)), None) => Err(String::from("slice expected index numbers")), - (_, _) => Err(String::from("slice expected 2~3 arguments")), + (Some(Calcit::List(_)), Some(a)) => Err(CalcitErr::use_string(format!("slice expected index number, got: {}", a))), + (Some(Calcit::List(_)), None) => Err(CalcitErr::use_str("slice expected index numbers")), + (_, _) => Err(CalcitErr::use_str("slice expected 2~3 arguments")), } } -pub fn append(xs: &CalcitItems) -> Result { +pub fn append(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::List(ys)), Some(a)) => { let mut zs = ys.to_owned(); zs.push_back(a.to_owned()); Ok(Calcit::List(zs)) } - (Some(a), _) => Err(format!("append expected list, got: {}", a)), - (None, _) => Err(String::from("append expected 2 arguments, got nothing")), + (Some(a), _) => Err(CalcitErr::use_string(format!("append expected list, got: {}", a))), + (None, _) => Err(CalcitErr::use_str("append expected 2 arguments, got nothing")), } } -pub fn prepend(xs: &CalcitItems) -> Result { +pub fn prepend(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::List(ys)), Some(a)) => { let mut zs = ys.to_owned(); zs.push_front(a.to_owned()); Ok(Calcit::List(zs)) } - (Some(a), _) => Err(format!("prepend expected list, got: {}", a)), - (None, _) => Err(String::from("prepend expected 2 arguments, got nothing")), + (Some(a), _) => Err(CalcitErr::use_string(format!("prepend expected list, got: {}", a))), + (None, _) => Err(CalcitErr::use_str("prepend expected 2 arguments, got nothing")), } } -pub fn rest(xs: &CalcitItems) -> Result { +pub fn rest(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::List(ys)) => { if ys.is_empty() { @@ -89,12 +98,12 @@ pub fn rest(xs: &CalcitItems) -> Result { Ok(Calcit::List(zs)) } } - Some(a) => Err(format!("list:rest expected a list, got: {}", a)), - None => Err(String::from("list:rest expected 1 argument")), + Some(a) => Err(CalcitErr::use_string(format!("list:rest expected a list, got: {}", a))), + None => Err(CalcitErr::use_str("list:rest expected 1 argument")), } } -pub fn butlast(xs: &CalcitItems) -> Result { +pub fn butlast(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Nil) => Ok(Calcit::Nil), Some(Calcit::List(ys)) => { @@ -106,12 +115,12 @@ pub fn butlast(xs: &CalcitItems) -> Result { Ok(Calcit::List(zs)) } } - Some(a) => Err(format!("butlast expected a list, got: {}", a)), - None => Err(String::from("butlast expected 1 argument")), + Some(a) => Err(CalcitErr::use_string(format!("butlast expected a list, got: {}", a))), + None => Err(CalcitErr::use_str("butlast expected 1 argument")), } } -pub fn concat(xs: &CalcitItems) -> Result { +pub fn concat(xs: &CalcitItems) -> Result { let mut ys: CalcitItems = im::vector![]; for x in xs { if let Calcit::List(zs) = x { @@ -119,23 +128,23 @@ pub fn concat(xs: &CalcitItems) -> Result { ys.push_back(z.to_owned()); } } else { - return Err(format!("concat expects list arguments, got: {}", x)); + return Err(CalcitErr::use_string(format!("concat expects list arguments, got: {}", x))); } } Ok(Calcit::List(ys)) } -pub fn range(xs: &CalcitItems) -> Result { +pub fn range(xs: &CalcitItems) -> Result { let (base, bound) = match (xs.get(0), xs.get(1)) { (Some(Calcit::Number(bound)), None) => (0.0, *bound), (Some(Calcit::Number(base)), Some(Calcit::Number(bound))) => (*base, *bound), - (Some(a), Some(b)) => return Err(format!("range expected 2 numbers, but got: {} {}", a, b)), - (_, _) => return Err(format!("invalid arguments for range: {:?}", xs)), + (Some(a), Some(b)) => return Err(CalcitErr::use_string(format!("range expected 2 numbers, but got: {} {}", a, b))), + (_, _) => return Err(CalcitErr::use_string(format!("invalid arguments for range: {:?}", xs))), }; let step = match xs.get(2) { Some(Calcit::Number(n)) => *n, - Some(a) => return Err(format!("range expected numbers, but got: {}", a)), + Some(a) => return Err(CalcitErr::use_string(format!("range expected numbers, but got: {}", a))), None => 1.0, }; @@ -144,7 +153,7 @@ pub fn range(xs: &CalcitItems) -> Result { } if step == 0.0 || (bound > base && step < 0.0) || (bound < base && step > 0.0) { - return Err(String::from("range cannot construct list with step 0")); + return Err(CalcitErr::use_str("range cannot construct list with step 0")); } let mut ys: CalcitItems = im::vector![]; @@ -163,7 +172,7 @@ pub fn range(xs: &CalcitItems) -> Result { Ok(Calcit::List(ys)) } -pub fn reverse(xs: &CalcitItems) -> Result { +pub fn reverse(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Nil) => Ok(Calcit::Nil), Some(Calcit::List(ys)) => { @@ -173,18 +182,13 @@ pub fn reverse(xs: &CalcitItems) -> Result { } Ok(Calcit::List(zs)) } - Some(a) => Err(format!("butlast expected a list, got: {}", a)), - None => Err(String::from("butlast expected 1 argument")), + Some(a) => Err(CalcitErr::use_string(format!("butlast expected a list, got: {}", a))), + None => Err(CalcitErr::use_str("butlast expected 1 argument")), } } /// foldl using syntax for performance, it's supposed to be a function -pub fn foldl( - expr: &CalcitItems, - scope: &CalcitScope, - file_ns: &str, - program_code: &ProgramCodeData, -) -> Result { +pub fn foldl(expr: &CalcitItems, scope: &CalcitScope, file_ns: &str, program_code: &ProgramCodeData) -> Result { if expr.len() == 3 { let xs = runner::evaluate_expr(&expr[0], scope, file_ns, program_code)?; let acc = runner::evaluate_expr(&expr[1], scope, file_ns, program_code)?; @@ -237,18 +241,18 @@ pub fn foldl( let mut ret = acc; for (k, x) in xs { // println!("foldl args, {} {}", ret, x.to_owned()); - ret = builtins::handle_proc( - proc, - &im::vector![ret, Calcit::List(im::vector![k.to_owned(), x.to_owned()])], - )?; + ret = builtins::handle_proc(proc, &im::vector![ret, Calcit::List(im::vector![k.to_owned(), x.to_owned()])])?; } Ok(ret) } - (_, _) => Err(format!("foldl expected list and function, got: {} {}", xs, f)), + (_, _) => Err(CalcitErr::use_string(format!( + "foldl expected list and function, got: {} {}", + xs, f + ))), } } else { - Err(format!("foldl expected 3 arguments, got: {:?}", expr)) + Err(CalcitErr::use_string(format!("foldl expected 3 arguments, got: {:?}", expr))) } } @@ -259,7 +263,7 @@ pub fn foldl_shortcut( scope: &CalcitScope, file_ns: &str, program_code: &ProgramCodeData, -) -> Result { +) -> Result { if expr.len() == 4 { let xs = runner::evaluate_expr(&expr[0], scope, file_ns, program_code)?; let acc = runner::evaluate_expr(&expr[1], scope, file_ns, program_code)?; @@ -281,13 +285,18 @@ pub fn foldl_shortcut( state = *x1.to_owned() } } - a => return Err(format!("return value in foldl-shortcut should be a bool, got: {}", a)), + a => { + return Err(CalcitErr::use_string(format!( + "return value in foldl-shortcut should be a bool, got: {}", + a + ))) + } }, _ => { - return Err(format!( + return Err(CalcitErr::use_string(format!( "return value for foldl-shortcut should be `:: bool acc`, got: {}", pair - )) + ))) } } } @@ -308,13 +317,18 @@ pub fn foldl_shortcut( state = *x1.to_owned() } } - a => return Err(format!("return value in foldl-shortcut should be a bool, got: {}", a)), + a => { + return Err(CalcitErr::use_string(format!( + "return value in foldl-shortcut should be a bool, got: {}", + a + ))) + } }, _ => { - return Err(format!( + return Err(CalcitErr::use_string(format!( "return value for foldl-shortcut should be `:: bool acc`, got: {}", pair - )) + ))) } } } @@ -335,26 +349,34 @@ pub fn foldl_shortcut( state = *x1.to_owned() } } - a => return Err(format!("return value in foldl-shortcut should be a bool, got: {}", a)), + a => { + return Err(CalcitErr::use_string(format!( + "return value in foldl-shortcut should be a bool, got: {}", + a + ))) + } }, _ => { - return Err(format!( + return Err(CalcitErr::use_string(format!( "return value for foldl-shortcut should be `:: bool acc`, got: {}", pair - )) + ))) } } } Ok(default_value) } - (_, _) => Err(format!("foldl-shortcut expected list... and fn, got: {} {}", xs, f)), + (_, _) => Err(CalcitErr::use_string(format!( + "foldl-shortcut expected list... and fn, got: {} {}", + xs, f + ))), } } else { - Err(format!( + Err(CalcitErr::use_string(format!( "foldl-shortcut expected 4 arguments list,state,default,fn, got: {:?}", expr - )) + ))) } } @@ -363,7 +385,7 @@ pub fn foldr_shortcut( scope: &CalcitScope, file_ns: &str, program_code: &ProgramCodeData, -) -> Result { +) -> Result { if expr.len() == 4 { let xs = runner::evaluate_expr(&expr[0], scope, file_ns, program_code)?; let acc = runner::evaluate_expr(&expr[1], scope, file_ns, program_code)?; @@ -387,36 +409,39 @@ pub fn foldr_shortcut( state = *x1.to_owned() } } - a => return Err(format!("return value in foldr-shortcut should be a bool, got: {}", a)), + a => { + return Err(CalcitErr::use_string(format!( + "return value in foldr-shortcut should be a bool, got: {}", + a + ))) + } }, _ => { - return Err(format!( + return Err(CalcitErr::use_string(format!( "return value for foldr-shortcut should be `:: bool acc`, got: {}", pair - )) + ))) } } } Ok(default_value) } - (_, _) => Err(format!("foldr-shortcut expected list... and fn, got: {} {}", xs, f)), + (_, _) => Err(CalcitErr::use_string(format!( + "foldr-shortcut expected list... and fn, got: {} {}", + xs, f + ))), } } else { - Err(format!( + Err(CalcitErr::use_string(format!( "foldr-shortcut expected 4 arguments list,state,default,fn, got: {:?}", expr - )) + ))) } } // TODO as SYNTAX at current, not supposed to be a syntax -pub fn sort( - expr: &CalcitItems, - scope: &CalcitScope, - file_ns: &str, - program_code: &ProgramCodeData, -) -> Result { +pub fn sort(expr: &CalcitItems, scope: &CalcitScope, file_ns: &str, program_code: &ProgramCodeData) -> Result { if expr.len() == 2 { let xs = runner::evaluate_expr(&expr[0], scope, file_ns, program_code)?; let f = runner::evaluate_expr(&expr[1], scope, file_ns, program_code)?; @@ -465,14 +490,14 @@ pub fn sort( Ok(Calcit::List(ret)) } - (_, _) => Err(format!("sort expected list and function, got: {} {}", xs, f)), + (_, _) => Err(CalcitErr::use_string(format!("sort expected list and function, got: {} {}", xs, f))), } } else { - Err(format!("sort expected 2 arguments, got: {:?}", expr)) + Err(CalcitErr::use_string(format!("sort expected 2 arguments, got: {:?}", expr))) } } -pub fn first(xs: &CalcitItems) -> Result { +pub fn first(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::List(ys)) => { if ys.is_empty() { @@ -481,13 +506,13 @@ pub fn first(xs: &CalcitItems) -> Result { Ok(ys[0].to_owned()) } } - Some(a) => Err(format!("list:first expected a list, got: {}", a)), - None => Err(String::from("list:first expected 1 argument")), + Some(a) => Err(CalcitErr::use_string(format!("list:first expected a list, got: {}", a))), + None => Err(CalcitErr::use_str("list:first expected 1 argument")), } } // real implementation relies of ternary-tree -pub fn assoc_before(xs: &CalcitItems) -> Result { +pub fn assoc_before(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1), xs.get(2)) { (Some(Calcit::List(xs)), Some(Calcit::Number(n)), Some(a)) => match f64_to_usize(*n) { Ok(idx) => { @@ -495,14 +520,20 @@ pub fn assoc_before(xs: &CalcitItems) -> Result { ys.insert(idx, a.to_owned()); Ok(Calcit::List(ys)) } - Err(e) => Err(format!("assoc-before expect usize, {}", e)), + Err(e) => Err(CalcitErr::use_string(format!("assoc-before expect usize, {}", e))), }, - (Some(a), Some(b), Some(c)) => Err(format!("assoc-before expected list and index, got: {} {} {}", a, b, c)), - (a, b, c) => Err(format!("invalid arguments to assoc-before: {:?} {:?} {:?}", a, b, c)), + (Some(a), Some(b), Some(c)) => Err(CalcitErr::use_string(format!( + "assoc-before expected list and index, got: {} {} {}", + a, b, c + ))), + (a, b, c) => Err(CalcitErr::use_string(format!( + "invalid arguments to assoc-before: {:?} {:?} {:?}", + a, b, c + ))), } } -pub fn assoc_after(xs: &CalcitItems) -> Result { +pub fn assoc_after(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1), xs.get(2)) { (Some(Calcit::List(xs)), Some(Calcit::Number(n)), Some(a)) => match f64_to_usize(*n) { Ok(idx) => { @@ -510,41 +541,50 @@ pub fn assoc_after(xs: &CalcitItems) -> Result { ys.insert(idx + 1, a.to_owned()); Ok(Calcit::List(ys)) } - Err(e) => Err(format!("assoc-after expect usize, {}", e)), + Err(e) => Err(CalcitErr::use_string(format!("assoc-after expect usize, {}", e))), }, - (Some(a), Some(b), Some(c)) => Err(format!("assoc-after expected list and index, got: {} {} {}", a, b, c)), - (a, b, c) => Err(format!("invalid arguments to assoc-after: {:?} {:?} {:?}", a, b, c)), + (Some(a), Some(b), Some(c)) => Err(CalcitErr::use_string(format!( + "assoc-after expected list and index, got: {} {} {}", + a, b, c + ))), + (a, b, c) => Err(CalcitErr::use_string(format!( + "invalid arguments to assoc-after: {:?} {:?} {:?}", + a, b, c + ))), } } -pub fn empty_ques(xs: &CalcitItems) -> Result { +pub fn empty_ques(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::List(ys)) => Ok(Calcit::Bool(ys.is_empty())), - Some(a) => Err(format!("list empty? expected a list, got: {}", a)), - None => Err(String::from("list empty? expected 1 argument")), + Some(a) => Err(CalcitErr::use_string(format!("list empty? expected a list, got: {}", a))), + None => Err(CalcitErr::use_str("list empty? expected 1 argument")), } } -pub fn contains_ques(xs: &CalcitItems) -> Result { +pub fn contains_ques(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::List(xs)), Some(Calcit::Number(n))) => match f64_to_usize(*n) { Ok(idx) => Ok(Calcit::Bool(idx < xs.len())), Err(_) => Ok(Calcit::Bool(false)), }, - (Some(a), ..) => Err(format!("list contains? expected list, got: {}", a)), - (None, ..) => Err(format!("list contains? expected 2 arguments, got: {:?}", xs)), + (Some(a), ..) => Err(CalcitErr::use_string(format!("list contains? expected list, got: {}", a))), + (None, ..) => Err(CalcitErr::use_string(format!("list contains? expected 2 arguments, got: {:?}", xs))), } } -pub fn includes_ques(xs: &CalcitItems) -> Result { +pub fn includes_ques(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::List(xs)), Some(a)) => Ok(Calcit::Bool(xs.contains(a))), - (Some(a), ..) => Err(format!("list `includes?` expected list, list, got: {}", a)), - (None, ..) => Err(format!("list `includes?` expected 2 arguments, got: {:?}", xs)), + (Some(a), ..) => Err(CalcitErr::use_string(format!("list `includes?` expected list, list, got: {}", a))), + (None, ..) => Err(CalcitErr::use_string(format!( + "list `includes?` expected 2 arguments, got: {:?}", + xs + ))), } } -pub fn assoc(xs: &CalcitItems) -> Result { +pub fn assoc(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1), xs.get(2)) { (Some(Calcit::List(xs)), Some(Calcit::Number(n)), Some(a)) => match f64_to_usize(*n) { Ok(idx) => { @@ -556,14 +596,14 @@ pub fn assoc(xs: &CalcitItems) -> Result { Ok(Calcit::Nil) } } - Err(e) => Err(e), + Err(e) => Err(CalcitErr::use_string(e)), }, - (Some(a), ..) => Err(format!("list:assoc expected list, got: {}", a)), - (None, ..) => Err(format!("list:assoc expected 3 arguments, got: {:?}", xs)), + (Some(a), ..) => Err(CalcitErr::use_string(format!("list:assoc expected list, got: {}", a))), + (None, ..) => Err(CalcitErr::use_string(format!("list:assoc expected 3 arguments, got: {:?}", xs))), } } -pub fn dissoc(xs: &CalcitItems) -> Result { +pub fn dissoc(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::List(xs)), Some(Calcit::Number(n))) => match f64_to_usize(*n) { Ok(idx) => { @@ -571,16 +611,19 @@ pub fn dissoc(xs: &CalcitItems) -> Result { ys.remove(idx); Ok(Calcit::List(ys.to_owned())) } - Err(e) => Err(format!("dissoc expected number, {}", e)), + Err(e) => Err(CalcitErr::use_string(format!("dissoc expected number, {}", e))), }, - (Some(a), ..) => Err(format!("list dissoc expected a list, got: {}", a)), - (_, _) => Err(format!("list dissoc expected 2 arguments, got: {:?}", xs)), + (Some(a), ..) => Err(CalcitErr::use_string(format!("list dissoc expected a list, got: {}", a))), + (_, _) => Err(CalcitErr::use_string(format!("list dissoc expected 2 arguments, got: {:?}", xs))), } } -pub fn list_to_set(xs: &CalcitItems) -> Result { +pub fn list_to_set(xs: &CalcitItems) -> Result { if xs.len() != 1 { - return Err(format!("&list:to-set expected a single argument in list, got {:?}", xs)); + return Err(CalcitErr::use_string(format!( + "&list:to-set expected a single argument in list, got {:?}", + xs + ))); } match &xs[0] { Calcit::List(ys) => { @@ -590,16 +633,16 @@ pub fn list_to_set(xs: &CalcitItems) -> Result { } Ok(Calcit::Set(zs)) } - a => Err(format!("&list:to-set expected a list, got {}", a)), + a => Err(CalcitErr::use_string(format!("&list:to-set expected a list, got {}", a))), } } -pub fn distinct(xs: &CalcitItems) -> Result { +pub fn distinct(xs: &CalcitItems) -> Result { if xs.len() != 1 { - return Err(format!( + return Err(CalcitErr::use_string(format!( "&list:distinct expected a single argument in list, got {:?}", xs - )); + ))); } match &xs[0] { Calcit::List(ys) => { @@ -611,6 +654,6 @@ pub fn distinct(xs: &CalcitItems) -> Result { } Ok(Calcit::List(zs)) } - a => Err(format!("&list:distinct expected a list, got {}", a)), + a => Err(CalcitErr::use_string(format!("&list:distinct expected a list, got {}", a))), } } diff --git a/src/builtins/logics.rs b/src/builtins/logics.rs index 8b37418b..25c89333 100644 --- a/src/builtins/logics.rs +++ b/src/builtins/logics.rs @@ -1,31 +1,31 @@ -use crate::primes::{Calcit, CalcitItems}; +use crate::primes::{Calcit, CalcitErr, CalcitItems}; -pub fn binary_equal(xs: &CalcitItems) -> Result { +pub fn binary_equal(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(a), Some(b)) => Ok(Calcit::Bool(a == b)), - (_, _) => Err(format!("&= expected 2 arguments, got: {:?}", xs)), + (_, _) => Err(CalcitErr::use_string(format!("&= expected 2 arguments, got: {:?}", xs))), } } -pub fn binary_less(xs: &CalcitItems) -> Result { +pub fn binary_less(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(a), Some(b)) => Ok(Calcit::Bool(a < b)), - (_, _) => Err(format!("&< expected 2 arguments, got: {:?}", xs)), + (_, _) => Err(CalcitErr::use_string(format!("&< expected 2 arguments, got: {:?}", xs))), } } -pub fn binary_greater(xs: &CalcitItems) -> Result { +pub fn binary_greater(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(a), Some(b)) => Ok(Calcit::Bool(a > b)), - (_, _) => Err(format!("&> expected 2 arguments, got: {:?}", xs)), + (_, _) => Err(CalcitErr::use_string(format!("&> expected 2 arguments, got: {:?}", xs))), } } -pub fn not(xs: &CalcitItems) -> Result { +pub fn not(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Nil) => Ok(Calcit::Bool(true)), Some(Calcit::Bool(b)) => Ok(Calcit::Bool(!b)), - Some(a) => Err(format!("not expected bool or nil, got: {}", a)), - None => Err(String::from("not expected 1 argument, got nothing")), + Some(a) => Err(CalcitErr::use_string(format!("not expected bool or nil, got: {}", a))), + None => Err(CalcitErr::use_str("not expected 1 argument, got nothing")), } } diff --git a/src/builtins/maps.rs b/src/builtins/maps.rs index 9a3d1cee..088be3c2 100644 --- a/src/builtins/maps.rs +++ b/src/builtins/maps.rs @@ -1,9 +1,9 @@ use crate::builtins::records::find_in_fields; -use crate::primes::{keyword::load_order_key, Calcit, CalcitItems, CrListWrap}; +use crate::primes::{keyword::load_order_key, Calcit, CalcitErr, CalcitItems, CrListWrap}; use crate::util::number::is_even; -pub fn call_new_map(xs: &CalcitItems) -> Result { +pub fn call_new_map(xs: &CalcitItems) -> Result { if is_even(xs.len()) { let n = xs.len() >> 1; let mut ys = im::HashMap::new(); @@ -12,16 +12,16 @@ pub fn call_new_map(xs: &CalcitItems) -> Result { } Ok(Calcit::Map(ys)) } else { - Err(format!( + Err(CalcitErr::use_string(format!( "&{{}} expected even number of arguments, got {}", CrListWrap(xs.to_owned()) - )) + ))) } } -pub fn dissoc(xs: &CalcitItems) -> Result { +pub fn dissoc(xs: &CalcitItems) -> Result { if xs.len() < 2 { - return Err(format!("map dissoc expected at least 2 arguments: {:?}", xs)); + return Err(CalcitErr::use_string(format!("map dissoc expected at least 2 arguments: {:?}", xs))); } match xs.get(0) { Some(Calcit::Map(base)) => { @@ -36,12 +36,12 @@ pub fn dissoc(xs: &CalcitItems) -> Result { } Ok(Calcit::Map(ys.to_owned())) } - Some(a) => Err(format!("map dissoc expected a map, got: {}", a)), - _ => Err(format!("map dissoc expected 2 arguments, got: {:?}", xs)), + Some(a) => Err(CalcitErr::use_string(format!("map dissoc expected a map, got: {}", a))), + _ => Err(CalcitErr::use_string(format!("map dissoc expected 2 arguments, got: {:?}", xs))), } } -pub fn get(xs: &CalcitItems) -> Result { +pub fn get(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Map(xs)), Some(a)) => { let ys = &mut xs.to_owned(); @@ -50,12 +50,12 @@ pub fn get(xs: &CalcitItems) -> Result { None => Ok(Calcit::Nil), } } - (Some(a), ..) => Err(format!("map &get expected map, got: {}", a)), - (None, ..) => Err(format!("map &get expected 2 arguments, got: {:?}", xs)), + (Some(a), ..) => Err(CalcitErr::use_string(format!("map &get expected map, got: {}", a))), + (None, ..) => Err(CalcitErr::use_string(format!("map &get expected 2 arguments, got: {:?}", xs))), } } -pub fn call_merge(xs: &CalcitItems) -> Result { +pub fn call_merge(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Map(xs)), Some(Calcit::Map(ys))) => { let mut zs: im::HashMap = xs.to_owned(); @@ -70,24 +70,24 @@ pub fn call_merge(xs: &CalcitItems) -> Result { match k { Calcit::Str(s) | Calcit::Symbol(s, ..) => match find_in_fields(fields, load_order_key(s)) { Some(pos) => new_values[pos] = v.to_owned(), - None => return Err(format!("invalid field `{}` for {:?}", s, fields)), + None => return Err(CalcitErr::use_string(format!("invalid field `{}` for {:?}", s, fields))), }, Calcit::Keyword(s) => match find_in_fields(fields, s.to_owned()) { Some(pos) => new_values[pos] = v.to_owned(), - None => return Err(format!("invalid field `{}` for {:?}", s, fields)), + None => return Err(CalcitErr::use_string(format!("invalid field `{}` for {:?}", s, fields))), }, - a => return Err(format!("invalid field key: {}", a)), + a => return Err(CalcitErr::use_string(format!("invalid field key: {}", a))), } } Ok(Calcit::Record(name.to_owned(), fields.to_owned(), new_values)) } - (Some(a), Some(b)) => Err(format!("expected 2 maps, got: {} {}", a, b)), - (_, _) => Err(format!("expected 2 arguments, got: {:?}", xs)), + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!("expected 2 maps, got: {} {}", a, b))), + (_, _) => Err(CalcitErr::use_string(format!("expected 2 arguments, got: {:?}", xs))), } } /// to set -pub fn to_pairs(xs: &CalcitItems) -> Result { +pub fn to_pairs(xs: &CalcitItems) -> Result { match xs.get(0) { // get a random order from internals Some(Calcit::Map(ys)) => { @@ -107,12 +107,12 @@ pub fn to_pairs(xs: &CalcitItems) -> Result { } Ok(Calcit::Set(zs)) } - Some(a) => Err(format!("to-pairs expected a map, got {}", a)), - None => Err(String::from("to-pairs expected 1 argument, got nothing")), + Some(a) => Err(CalcitErr::use_string(format!("to-pairs expected a map, got {}", a))), + None => Err(CalcitErr::use_str("to-pairs expected 1 argument, got nothing")), } } -pub fn call_merge_non_nil(xs: &CalcitItems) -> Result { +pub fn call_merge_non_nil(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Map(xs)), Some(Calcit::Map(ys))) => { let mut zs: im::HashMap = xs.to_owned(); @@ -123,13 +123,13 @@ pub fn call_merge_non_nil(xs: &CalcitItems) -> Result { } Ok(Calcit::Map(zs)) } - (Some(a), Some(b)) => Err(format!("expected 2 maps, got: {} {}", a, b)), - (_, _) => Err(format!("expected 2 arguments, got: {:?}", xs)), + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!("expected 2 maps, got: {} {}", a, b))), + (_, _) => Err(CalcitErr::use_string(format!("expected 2 arguments, got: {:?}", xs))), } } /// out to list, but with a arbitrary order -pub fn to_list(xs: &CalcitItems) -> Result { +pub fn to_list(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Map(m)) => { let mut ys: im::Vector = im::vector![]; @@ -139,36 +139,36 @@ pub fn to_list(xs: &CalcitItems) -> Result { } Ok(Calcit::List(ys)) } - Some(a) => Err(format!("&map:to-list expected a map, got: {}", a)), - None => Err(String::from("&map:to-list expected a map, got nothing")), + Some(a) => Err(CalcitErr::use_string(format!("&map:to-list expected a map, got: {}", a))), + None => Err(CalcitErr::use_str("&map:to-list expected a map, got nothing")), } } -pub fn count(xs: &CalcitItems) -> Result { +pub fn count(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Map(ys)) => Ok(Calcit::Number(ys.len() as f64)), - Some(a) => Err(format!("map count expected a map, got: {}", a)), - None => Err(String::from("map count expected 1 argument")), + Some(a) => Err(CalcitErr::use_string(format!("map count expected a map, got: {}", a))), + None => Err(CalcitErr::use_str("map count expected 1 argument")), } } -pub fn empty_ques(xs: &CalcitItems) -> Result { +pub fn empty_ques(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Map(ys)) => Ok(Calcit::Bool(ys.is_empty())), - Some(a) => Err(format!("map empty? expected some map, got: {}", a)), - None => Err(String::from("map empty? expected 1 argument")), + Some(a) => Err(CalcitErr::use_string(format!("map empty? expected some map, got: {}", a))), + None => Err(CalcitErr::use_str("map empty? expected 1 argument")), } } -pub fn contains_ques(xs: &CalcitItems) -> Result { +pub fn contains_ques(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Map(xs)), Some(a)) => Ok(Calcit::Bool(xs.contains_key(a))), - (Some(a), ..) => Err(format!("map contains? expected a map, got: {}", a)), - (None, ..) => Err(format!("map contains? expected 2 arguments, got: {:?}", xs)), + (Some(a), ..) => Err(CalcitErr::use_string(format!("map contains? expected a map, got: {}", a))), + (None, ..) => Err(CalcitErr::use_string(format!("map contains? expected 2 arguments, got: {:?}", xs))), } } -pub fn includes_ques(xs: &CalcitItems) -> Result { +pub fn includes_ques(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Map(ys)), Some(a)) => { for (_k, v) in ys { @@ -178,25 +178,28 @@ pub fn includes_ques(xs: &CalcitItems) -> Result { } Ok(Calcit::Bool(false)) } - (Some(a), ..) => Err(format!("map `includes?` expected a map, got: {}", a)), - (None, ..) => Err(format!("map `includes?` expected 2 arguments, got: {:?}", xs)), + (Some(a), ..) => Err(CalcitErr::use_string(format!("map `includes?` expected a map, got: {}", a))), + (None, ..) => Err(CalcitErr::use_string(format!( + "map `includes?` expected 2 arguments, got: {:?}", + xs + ))), } } /// use builtin function since maps need to be handled specifically -pub fn first(xs: &CalcitItems) -> Result { +pub fn first(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Map(ys)) => match ys.iter().next() { // TODO order may not be stable enough Some((k, v)) => Ok(Calcit::List(im::vector![k.to_owned(), v.to_owned()])), None => Ok(Calcit::Nil), }, - Some(a) => Err(format!("map:first expected a map, got: {}", a)), - None => Err(String::from("map:first expected 1 argument")), + Some(a) => Err(CalcitErr::use_string(format!("map:first expected a map, got: {}", a))), + None => Err(CalcitErr::use_str("map:first expected 1 argument")), } } -pub fn rest(xs: &CalcitItems) -> Result { +pub fn rest(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Map(ys)) => match ys.keys().next() { Some(k0) => { @@ -206,16 +209,19 @@ pub fn rest(xs: &CalcitItems) -> Result { } None => Ok(Calcit::Nil), }, - Some(a) => Err(format!("map:rest expected a map, got: {}", a)), - None => Err(String::from("map:rest expected 1 argument")), + Some(a) => Err(CalcitErr::use_string(format!("map:rest expected a map, got: {}", a))), + None => Err(CalcitErr::use_str("map:rest expected 1 argument")), } } -pub fn assoc(xs: &CalcitItems) -> Result { +pub fn assoc(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Map(base)) => { if xs.len() % 2 != 1 { - Err(format!("map:assoc expected odd number of arguments, got {:?}", xs)) + Err(CalcitErr::use_string(format!( + "map:assoc expected odd number of arguments, got {:?}", + xs + ))) } else { let size = (xs.len() - 1) / 2; let mut ys = base.to_owned(); @@ -225,12 +231,12 @@ pub fn assoc(xs: &CalcitItems) -> Result { Ok(Calcit::Map(ys)) } } - Some(a) => Err(format!("map:assoc expected a map, got: {}", a)), - None => Err(format!("map:assoc expected 3 arguments, got: {:?}", xs)), + Some(a) => Err(CalcitErr::use_string(format!("map:assoc expected a map, got: {}", a))), + None => Err(CalcitErr::use_string(format!("map:assoc expected 3 arguments, got: {:?}", xs))), } } -pub fn diff_new(xs: &CalcitItems) -> Result { +pub fn diff_new(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Map(xs)), Some(Calcit::Map(ys))) => { let zs = &mut xs.to_owned(); @@ -241,12 +247,15 @@ pub fn diff_new(xs: &CalcitItems) -> Result { } Ok(Calcit::Map(zs.to_owned())) } - (Some(a), Some(b)) => Err(format!("map:new_entries expected 2 maps, got: {} {}", a, b)), - (..) => Err(format!("map:new_entries expected 2 arguments, got: {:?}", xs)), + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!("map:new_entries expected 2 maps, got: {} {}", a, b))), + (..) => Err(CalcitErr::use_string(format!( + "map:new_entries expected 2 arguments, got: {:?}", + xs + ))), } } -pub fn diff_keys(xs: &CalcitItems) -> Result { +pub fn diff_keys(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Map(xs)), Some(Calcit::Map(ys))) => { let mut ks: im::HashSet = im::HashSet::new(); @@ -257,12 +266,12 @@ pub fn diff_keys(xs: &CalcitItems) -> Result { } Ok(Calcit::Set(ks)) } - (Some(a), Some(b)) => Err(format!("map:diff-keys expected 2 maps, got: {} {}", a, b)), - (..) => Err(format!("map:diff-keys expected 2 arguments, got: {:?}", xs)), + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!("map:diff-keys expected 2 maps, got: {} {}", a, b))), + (..) => Err(CalcitErr::use_string(format!("map:diff-keys expected 2 arguments, got: {:?}", xs))), } } -pub fn common_keys(xs: &CalcitItems) -> Result { +pub fn common_keys(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Map(xs)), Some(Calcit::Map(ys))) => { let mut ks: im::HashSet = im::HashSet::new(); @@ -273,7 +282,7 @@ pub fn common_keys(xs: &CalcitItems) -> Result { } Ok(Calcit::Set(ks)) } - (Some(a), Some(b)) => Err(format!("map:diff-keys expected 2 maps, got: {} {}", a, b)), - (..) => Err(format!("map:diff-keys expected 2 arguments, got: {:?}", xs)), + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!("map:diff-keys expected 2 maps, got: {} {}", a, b))), + (..) => Err(CalcitErr::use_string(format!("map:diff-keys expected 2 arguments, got: {:?}", xs))), } } diff --git a/src/builtins/math.rs b/src/builtins/math.rs index de3e8720..cbeac07c 100644 --- a/src/builtins/math.rs +++ b/src/builtins/math.rs @@ -1,143 +1,143 @@ -use crate::primes::{Calcit, CalcitItems}; +use crate::primes::{Calcit, CalcitErr, CalcitItems}; use crate::util::number::{f64_to_i32, is_integer}; -pub fn binary_add(xs: &CalcitItems) -> Result { +pub fn binary_add(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Number(a)), Some(Calcit::Number(b))) => Ok(Calcit::Number(a + b)), - (Some(a), Some(b)) => Err(format!("invalid types for &+: {} {}", a, b)), - (_, _) if xs.len() != 2 => Err(String::from("&+ expected 2 arguments")), - _ => Err(String::from("invalid arguments")), + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!("invalid types for &+: {} {}", a, b))), + (_, _) if xs.len() != 2 => Err(CalcitErr::use_str("&+ expected 2 arguments")), + _ => Err(CalcitErr::use_str("invalid arguments")), } } -pub fn binary_minus(xs: &CalcitItems) -> Result { +pub fn binary_minus(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Number(a)), Some(Calcit::Number(b))) => Ok(Calcit::Number(a - b)), - (Some(a), Some(b)) => Err(format!("invalid types for &-: {} {}", a, b)), - (_, _) if xs.len() != 2 => Err(String::from("&- expected 2 arguments")), - _ => Err(String::from("invalid arguments")), + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!("invalid types for &-: {} {}", a, b))), + (_, _) if xs.len() != 2 => Err(CalcitErr::use_str("&- expected 2 arguments")), + _ => Err(CalcitErr::use_str("invalid arguments")), } } -pub fn binary_multiply(xs: &CalcitItems) -> Result { +pub fn binary_multiply(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Number(a)), Some(Calcit::Number(b))) => Ok(Calcit::Number(a * b)), - (Some(a), Some(b)) => Err(format!("invalid types for &*: {} {}", a, b)), - (_, _) if xs.len() != 2 => Err(String::from("&* expected 2 arguments")), - _ => Err(String::from("invalid arguments")), + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!("invalid types for &*: {} {}", a, b))), + (_, _) if xs.len() != 2 => Err(CalcitErr::use_str("&* expected 2 arguments")), + _ => Err(CalcitErr::use_str("invalid arguments")), } } -pub fn binary_divide(xs: &CalcitItems) -> Result { +pub fn binary_divide(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Number(a)), Some(Calcit::Number(b))) => Ok(Calcit::Number(a / b)), - (Some(a), Some(b)) => Err(format!("invalid types for &/: {} {}", a, b)), - (_, _) if xs.len() != 2 => Err(String::from("&/ expected 2 arguments")), - _ => Err(String::from("invalid arguments")), + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!("invalid types for &/: {} {}", a, b))), + (_, _) if xs.len() != 2 => Err(CalcitErr::use_str("&/ expected 2 arguments")), + _ => Err(CalcitErr::use_str("invalid arguments")), } } -pub fn round_ques(xs: &CalcitItems) -> Result { +pub fn round_ques(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Number(n)) => Ok(Calcit::Bool(is_integer(*n))), - Some(a) => Err(format!("round? expected a number: {}", a)), - a => Err(format!("round? expected 1 number: {:?}", a)), + Some(a) => Err(CalcitErr::use_string(format!("round? expected a number: {}", a))), + a => Err(CalcitErr::use_string(format!("round? expected 1 number: {:?}", a))), } } -pub fn floor(xs: &CalcitItems) -> Result { +pub fn floor(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Number(n)) => Ok(Calcit::Number(n.floor())), - Some(a) => Err(format!("rand expected a number: {}", a)), - a => Err(format!("rand expected 1 number: {:?}", a)), + Some(a) => Err(CalcitErr::use_string(format!("rand expected a number: {}", a))), + a => Err(CalcitErr::use_string(format!("rand expected 1 number: {:?}", a))), } } // TODO semantics of Rust and JavaScript are different -pub fn fractional(xs: &CalcitItems) -> Result { +pub fn fractional(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Number(n)) => Ok(Calcit::Number(n - n.floor())), - Some(a) => Err(format!("fractional expected a number: {}", a)), - a => Err(format!("fractional expected 1 number: {:?}", a)), + Some(a) => Err(CalcitErr::use_string(format!("fractional expected a number: {}", a))), + a => Err(CalcitErr::use_string(format!("fractional expected 1 number: {:?}", a))), } } -pub fn rem(xs: &CalcitItems) -> Result { +pub fn rem(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Number(base)), Some(Calcit::Number(step))) => match (f64_to_i32(*base), f64_to_i32(*step)) { (Ok(a), Ok(b)) => Ok(Calcit::Number((a % b) as f64)), - (Err(a), _) => Err(a), - (_, Err(a)) => Err(a), + (Err(a), _) => Err(CalcitErr::use_string(a)), + (_, Err(a)) => Err(CalcitErr::use_string(a)), }, - (Some(a), Some(b)) => Err(format!("mod expected 2 numbers, got: {:?} {:?}", a, b)), - (a, b) => Err(format!("mod expected 2 numbers, got: {:?} {:?}", a, b)), + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!("mod expected 2 numbers, got: {:?} {:?}", a, b))), + (a, b) => Err(CalcitErr::use_string(format!("mod expected 2 numbers, got: {:?} {:?}", a, b))), } } -pub fn round(xs: &CalcitItems) -> Result { +pub fn round(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Number(n)) => Ok(Calcit::Number(n.round())), - Some(a) => Err(format!("round expected a number: {}", a)), - a => Err(format!("round expected 1 number: {:?}", a)), + Some(a) => Err(CalcitErr::use_string(format!("round expected a number: {}", a))), + a => Err(CalcitErr::use_string(format!("round expected 1 number: {:?}", a))), } } -pub fn sin(xs: &CalcitItems) -> Result { +pub fn sin(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Number(n)) => Ok(Calcit::Number(n.sin())), - Some(a) => Err(format!("sin expected a number: {}", a)), - a => Err(format!("sin expected 1 number: {:?}", a)), + Some(a) => Err(CalcitErr::use_string(format!("sin expected a number: {}", a))), + a => Err(CalcitErr::use_string(format!("sin expected 1 number: {:?}", a))), } } -pub fn cos(xs: &CalcitItems) -> Result { +pub fn cos(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Number(n)) => Ok(Calcit::Number(n.cos())), - Some(a) => Err(format!("cos expected a number: {}", a)), - a => Err(format!("cos expected 1 number: {:?}", a)), + Some(a) => Err(CalcitErr::use_string(format!("cos expected a number: {}", a))), + a => Err(CalcitErr::use_string(format!("cos expected 1 number: {:?}", a))), } } -pub fn pow(xs: &CalcitItems) -> Result { +pub fn pow(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Number(base)), Some(Calcit::Number(step))) => Ok(Calcit::Number(base.powf(*step))), - (Some(a), Some(b)) => Err(format!("pow expected 2 numbers, got: {:?} {:?}", a, b)), - (a, b) => Err(format!("pow expected 2 numbers, got: {:?} {:?}", a, b)), + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!("pow expected 2 numbers, got: {:?} {:?}", a, b))), + (a, b) => Err(CalcitErr::use_string(format!("pow expected 2 numbers, got: {:?} {:?}", a, b))), } } -pub fn ceil(xs: &CalcitItems) -> Result { +pub fn ceil(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Number(n)) => Ok(Calcit::Number(n.ceil())), - Some(a) => Err(format!("ceil expected a number: {}", a)), - a => Err(format!("ceil expected 1 number: {:?}", a)), + Some(a) => Err(CalcitErr::use_string(format!("ceil expected a number: {}", a))), + a => Err(CalcitErr::use_string(format!("ceil expected 1 number: {:?}", a))), } } -pub fn sqrt(xs: &CalcitItems) -> Result { +pub fn sqrt(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Number(n)) => Ok(Calcit::Number(n.sqrt())), - Some(a) => Err(format!("sqrt expected a number: {}", a)), - a => Err(format!("sqrt expected 1 number: {:?}", a)), + Some(a) => Err(CalcitErr::use_string(format!("sqrt expected a number: {}", a))), + a => Err(CalcitErr::use_string(format!("sqrt expected 1 number: {:?}", a))), } } -pub fn bit_shr(xs: &CalcitItems) -> Result { +pub fn bit_shr(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Number(n)), Some(Calcit::Number(m))) => match (f64_to_i32(*n), f64_to_i32(*m)) { (Ok(value), Ok(step)) => Ok(Calcit::Number((value >> step) as f64)), - (Err(e), _) => Err(format!("bit-shr expect int as initial value: {}", e)), - (_, Err(e)) => Err(format!("bit-shr expect int as step: {}", e)), + (Err(e), _) => Err(CalcitErr::use_string(format!("bit-shr expect int as initial value: {}", e))), + (_, Err(e)) => Err(CalcitErr::use_string(format!("bit-shr expect int as step: {}", e))), }, - (Some(a), Some(b)) => Err(format!("bit-shr expected 2 numbers, got: {} {}", a, b)), - (a, b) => Err(format!("bit-shr expected 2 number: {:?} {:?}", a, b)), + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!("bit-shr expected 2 numbers, got: {} {}", a, b))), + (a, b) => Err(CalcitErr::use_string(format!("bit-shr expected 2 number: {:?} {:?}", a, b))), } } -pub fn bit_shl(xs: &CalcitItems) -> Result { +pub fn bit_shl(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Number(n)), Some(Calcit::Number(m))) => match (f64_to_i32(*n), f64_to_i32(*m)) { (Ok(value), Ok(step)) => Ok(Calcit::Number((value << step) as f64)), - (Err(e), _) => Err(format!("bit-shl expect int as initial value: {}", e)), - (_, Err(e)) => Err(format!("bit-shl expect int as step: {}", e)), + (Err(e), _) => Err(CalcitErr::use_string(format!("bit-shl expect int as initial value: {}", e))), + (_, Err(e)) => Err(CalcitErr::use_string(format!("bit-shl expect int as step: {}", e))), }, - (Some(a), Some(b)) => Err(format!("bit-shl expected 2 numbers, got: {} {}", a, b)), - (a, b) => Err(format!("bit-shl expected 2 number: {:?} {:?}", a, b)), + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!("bit-shl expected 2 numbers, got: {} {}", a, b))), + (a, b) => Err(CalcitErr::use_string(format!("bit-shl expected 2 number: {:?} {:?}", a, b))), } } diff --git a/src/builtins/meta.rs b/src/builtins/meta.rs index f448516e..a142aa54 100644 --- a/src/builtins/meta.rs +++ b/src/builtins/meta.rs @@ -4,9 +4,7 @@ use crate::call_stack; use crate::data::cirru; use crate::data::edn; use crate::primes; -use crate::primes::{ - gen_core_id, keyword::load_order_key, load_kwd, lookup_order_kwd_str, Calcit, CalcitItems, CrListWrap, -}; +use crate::primes::{gen_core_id, keyword::load_order_key, load_kwd, lookup_order_kwd_str, Calcit, CalcitErr, CalcitItems, CrListWrap}; use crate::program; use crate::runner; use crate::util::number::f64_to_usize; @@ -20,7 +18,7 @@ use std::sync::atomic::AtomicUsize; static SYMBOL_INDEX: AtomicUsize = AtomicUsize::new(0); static JS_SYMBOL_INDEX: AtomicUsize = AtomicUsize::new(0); -pub fn type_of(xs: &CalcitItems) -> Result { +pub fn type_of(xs: &CalcitItems) -> Result { match xs.get(0) { Some(a) => match a { Calcit::Nil => Ok(load_kwd("nil")), @@ -44,27 +42,27 @@ pub fn type_of(xs: &CalcitItems) -> Result { Calcit::Fn(..) => Ok(load_kwd("fn")), Calcit::Syntax(..) => Ok(load_kwd("synta")), }, - None => Err(String::from("type-of expected 1 argument")), + None => Err(CalcitErr::use_str("type-of expected 1 argument")), } } -pub fn recur(xs: &CalcitItems) -> Result { +pub fn recur(xs: &CalcitItems) -> Result { Ok(Calcit::Recur(xs.to_owned())) } -pub fn format_to_lisp(xs: &CalcitItems) -> Result { +pub fn format_to_lisp(xs: &CalcitItems) -> Result { match xs.get(0) { Some(v) => Ok(Calcit::Str(v.lisp_str())), - None => Err(String::from("format-to-lisp expected 1 argument")), + None => Err(CalcitErr::use_str("format-to-lisp expected 1 argument")), } } -pub fn format_to_cirru(xs: &CalcitItems) -> Result { +pub fn format_to_cirru(xs: &CalcitItems) -> Result { match xs.get(0) { - Some(v) => { - cirru_parser::format(&[transform_code_to_cirru(v)], CirruWriterOptions { use_inline: false }).map(Calcit::Str) - } - None => Err(String::from("format-to-cirru expected 1 argument")), + Some(v) => cirru_parser::format(&[transform_code_to_cirru(v)], CirruWriterOptions { use_inline: false }) + .map(Calcit::Str) + .map_err(CalcitErr::use_string), + None => Err(CalcitErr::use_str("format-to-cirru expected 1 argument")), } } @@ -84,7 +82,7 @@ fn transform_code_to_cirru(x: &Calcit) -> Cirru { } } -pub fn gensym(xs: &CalcitItems) -> Result { +pub fn gensym(xs: &CalcitItems) -> Result { let idx = SYMBOL_INDEX.fetch_add(1, atomic::Ordering::SeqCst); let n = idx + 1; // use 1 as first value since previous implementation did this @@ -103,7 +101,7 @@ pub fn gensym(xs: &CalcitItems) -> Result { chunk.push_str(&n.to_string()); chunk } - Some(a) => return Err(format!("gensym expected a string, but got: {}", a)), + Some(a) => return Err(CalcitErr::use_string(format!("gensym expected a string, but got: {}", a))), None => { let mut chunk = String::from("G__"); chunk.push_str(&n.to_string()); @@ -118,7 +116,7 @@ pub fn gensym(xs: &CalcitItems) -> Result { )) } -pub fn reset_gensym_index(_xs: &CalcitItems) -> Result { +pub fn reset_gensym_index(_xs: &CalcitItems) -> Result { let _ = SYMBOL_INDEX.swap(0, atomic::Ordering::SeqCst); Ok(Calcit::Nil) } @@ -144,13 +142,13 @@ pub fn js_gensym(name: &str) -> String { } /// TODO, move out to calcit -pub fn generate_id(xs: &CalcitItems) -> Result { +pub fn generate_id(xs: &CalcitItems) -> Result { let size = match xs.get(0) { Some(Calcit::Number(n)) => match f64_to_usize(*n) { Ok(size) => Some(size), - Err(e) => return Err(e), + Err(e) => return Err(CalcitErr::use_string(e)), }, - Some(a) => return Err(format!("expected usize, got: {}", a)), + Some(a) => return Err(CalcitErr::use_string(format!("expected usize, got: {}", a))), None => None, // nanoid defaults to 21 }; @@ -164,64 +162,69 @@ pub fn generate_id(xs: &CalcitItems) -> Result { } Ok(Calcit::Str(gen_core_id())) } - (a, b) => Err(format!("generate-id! expected size or charset, got: {:?} {:?}", a, b)), + (a, b) => Err(CalcitErr::use_string(format!( + "generate-id! expected size or charset, got: {:?} {:?}", + a, b + ))), } } -pub fn display_stack(_xs: &CalcitItems) -> Result { +pub fn display_stack(_xs: &CalcitItems) -> Result { call_stack::show_stack(); Ok(Calcit::Nil) } -pub fn parse_cirru(xs: &CalcitItems) -> Result { +pub fn parse_cirru(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Str(s)) => match cirru_parser::parse(s) { Ok(nodes) => Ok(cirru::cirru_to_calcit(&Cirru::List(nodes))), - Err(e) => Err(format!("parse-cirru failed, {}", e)), + Err(e) => Err(CalcitErr::use_string(format!("parse-cirru failed, {}", e))), }, - Some(a) => Err(format!("parse-cirru expected a string, got: {}", a)), - None => Err(String::from("parse-cirru expected 1 argument")), + Some(a) => Err(CalcitErr::use_string(format!("parse-cirru expected a string, got: {}", a))), + None => Err(CalcitErr::use_str("parse-cirru expected 1 argument")), } } -pub fn format_cirru(xs: &CalcitItems) -> Result { +pub fn format_cirru(xs: &CalcitItems) -> Result { match xs.get(0) { Some(a) => { let options = cirru_parser::CirruWriterOptions { use_inline: false }; match cirru::calcit_data_to_cirru(a) { Ok(v) => { if let Cirru::List(ys) = v { - Ok(Calcit::Str(cirru_parser::format(&ys, options)?)) + Ok(Calcit::Str(cirru_parser::format(&ys, options).map_err(CalcitErr::use_string)?)) } else { - Err(format!("expected vector for Cirru formatting: {}", v)) + Err(CalcitErr::use_string(format!("expected vector for Cirru formatting: {}", v))) } } - Err(e) => Err(format!("format-cirru failed, {}", e)), + Err(e) => Err(CalcitErr::use_string(format!("format-cirru failed, {}", e))), } } - None => Err(String::from("parse-cirru expected 1 argument")), + None => Err(CalcitErr::use_str("parse-cirru expected 1 argument")), } } -pub fn parse_cirru_edn(xs: &CalcitItems) -> Result { +pub fn parse_cirru_edn(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Str(s)) => match cirru_edn::parse(s) { Ok(nodes) => Ok(edn::edn_to_calcit(&nodes)), - Err(e) => Err(format!("parse-cirru-edn failed, {}", e)), + Err(e) => Err(CalcitErr::use_string(format!("parse-cirru-edn failed, {}", e))), }, - Some(a) => Err(format!("parse-cirru-edn expected a string, got: {}", a)), - None => Err(String::from("parse-cirru-edn expected 1 argument")), + Some(a) => Err(CalcitErr::use_string(format!("parse-cirru-edn expected a string, got: {}", a))), + None => Err(CalcitErr::use_str("parse-cirru-edn expected 1 argument")), } } -pub fn format_cirru_edn(xs: &CalcitItems) -> Result { +pub fn format_cirru_edn(xs: &CalcitItems) -> Result { match xs.get(0) { - Some(a) => Ok(Calcit::Str(cirru_edn::format(&edn::calcit_to_edn(a)?, true)?)), - None => Err(String::from("format-cirru-edn expected 1 argument")), + Some(a) => Ok(Calcit::Str( + cirru_edn::format(&edn::calcit_to_edn(a).map_err(CalcitErr::use_string)?, true).map_err(CalcitErr::use_string)?, + )), + None => Err(CalcitErr::use_str("format-cirru-edn expected 1 argument")), } } -pub fn turn_symbol(xs: &CalcitItems) -> Result { +pub fn turn_symbol(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Str(s)) => Ok(Calcit::Symbol( s.to_owned(), @@ -235,40 +238,34 @@ pub fn turn_symbol(xs: &CalcitItems) -> Result { String::from(primes::GENERATED_DEF), None, )), - Some(Calcit::Symbol(s, ns, def, resolved)) => Ok(Calcit::Symbol( - s.to_owned(), - ns.to_owned(), - def.to_owned(), - resolved.to_owned(), - )), - Some(a) => Err(format!("turn-symbol cannot turn this to symbol: {}", a)), - None => Err(String::from("turn-symbol expected 1 argument, got nothing")), + Some(Calcit::Symbol(s, ns, def, resolved)) => Ok(Calcit::Symbol(s.to_owned(), ns.to_owned(), def.to_owned(), resolved.to_owned())), + Some(a) => Err(CalcitErr::use_string(format!("turn-symbol cannot turn this to symbol: {}", a))), + None => Err(CalcitErr::use_str("turn-symbol expected 1 argument, got nothing")), } } -pub fn turn_keyword(xs: &CalcitItems) -> Result { +pub fn turn_keyword(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Str(s)) => Ok(load_kwd(s)), Some(Calcit::Keyword(s)) => Ok(Calcit::Keyword(s.to_owned())), Some(Calcit::Symbol(s, ..)) => Ok(load_kwd(s)), - Some(a) => Err(format!("turn-keyword cannot turn this to keyword: {}", a)), - None => Err(String::from("turn-keyword expected 1 argument, got nothing")), + Some(a) => Err(CalcitErr::use_string(format!("turn-keyword cannot turn this to keyword: {}", a))), + None => Err(CalcitErr::use_str("turn-keyword expected 1 argument, got nothing")), } } -pub fn new_tuple(xs: &CalcitItems) -> Result { +pub fn new_tuple(xs: &CalcitItems) -> Result { if xs.len() != 2 { - Err(format!("tuple expected 2 arguments, got {}", CrListWrap(xs.to_owned()))) + Err(CalcitErr::use_string(format!( + "tuple expected 2 arguments, got {}", + CrListWrap(xs.to_owned()) + ))) } else { Ok(Calcit::Tuple(Box::new(xs[0].to_owned()), Box::new(xs[1].to_owned()))) } } -pub fn invoke_method( - name: &str, - invoke_args: &CalcitItems, - program_code: &program::ProgramCodeData, -) -> Result { +pub fn invoke_method(name: &str, invoke_args: &CalcitItems, program_code: &program::ProgramCodeData) -> Result { let (class, value) = match invoke_args.get(0) { Some(Calcit::Tuple(a, _b)) => ((**a).to_owned(), invoke_args.get(0).unwrap().to_owned()), Some(Calcit::Number(..)) => { @@ -312,7 +309,7 @@ pub fn invoke_method( let class = runner::evaluate_expr(&code, &im::HashMap::new(), primes::CORE_NS, program_code)?; (class, invoke_args[0].to_owned()) } - x => return Err(format!("cannot decide a class from: {:?}", x)), + x => return Err(CalcitErr::use_string(format!("cannot decide a class from: {:?}", x))), }; match &class { Calcit::Record(_, fields, values) => { @@ -335,11 +332,11 @@ pub fn invoke_method( runner::run_fn(&method_args, def_scope, args, body, def_ns, program_code) } Calcit::Proc(proc) => builtins::handle_proc(proc, &method_args), - Calcit::Syntax(syn, _ns) => Err(format!( + Calcit::Syntax(syn, _ns) => Err(CalcitErr::use_string(format!( "cannot get syntax here since instance is always evaluated, got: {}", syn - )), - y => Err(format!("expected a function to invoke, got: {}", y)), + ))), + y => Err(CalcitErr::use_string(format!("expected a function to invoke, got: {}", y))), } } None => { @@ -347,11 +344,14 @@ pub fn invoke_method( for k in fields { content = format!("{},{}", content, lookup_order_kwd_str(k)) } - Err(format!("missing field `{}` in {}", name, content)) + Err(CalcitErr::use_string(format!("missing field `{}` in {}", name, content))) } } } - x => Err(format!("method invoking expected a record as class, got: {}", x)), + x => Err(CalcitErr::use_string(format!( + "method invoking expected a record as class, got: {}", + x + ))), } } @@ -368,35 +368,44 @@ fn gen_sym(sym: &str) -> Calcit { ) } -pub fn native_compare(xs: &CalcitItems) -> Result { +pub fn native_compare(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(a), Some(b)) => match a.cmp(b) { Ordering::Less => Ok(Calcit::Number(-1.0)), Ordering::Greater => Ok(Calcit::Number(1.0)), Ordering::Equal => Ok(Calcit::Number(0.0)), }, - (a, b) => Err(format!("&compare expected 2 values, got {:?} {:?}", a, b)), + (a, b) => Err(CalcitErr::use_string(format!("&compare expected 2 values, got {:?} {:?}", a, b))), } } -pub fn tuple_nth(xs: &CalcitItems) -> Result { +pub fn tuple_nth(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Tuple(a, b)), Some(Calcit::Number(n))) => match f64_to_usize(*n) { Ok(0) => Ok((**a).to_owned()), Ok(1) => Ok((**b).to_owned()), - Ok(m) => Err(format!("Tuple only got 2 elements, trying to index with {}", m)), - Err(e) => Err(format!("&tuple:nth expect usize, {}", e)), + Ok(m) => Err(CalcitErr::use_string(format!( + "Tuple only got 2 elements, trying to index with {}", + m + ))), + Err(e) => Err(CalcitErr::use_string(format!("&tuple:nth expect usize, {}", e))), }, - (Some(_), None) => Err(format!("&tuple:nth expected a tuple and an index, got: {:?}", xs)), - (None, Some(_)) => Err(format!("&tuple:nth expected a tuple and an index, got: {:?}", xs)), - (_, _) => Err(format!( + (Some(_), None) => Err(CalcitErr::use_string(format!( + "&tuple:nth expected a tuple and an index, got: {:?}", + xs + ))), + (None, Some(_)) => Err(CalcitErr::use_string(format!( + "&tuple:nth expected a tuple and an index, got: {:?}", + xs + ))), + (_, _) => Err(CalcitErr::use_string(format!( "&tuple:nth expected 2 argument, got: {}", CrListWrap(xs.to_owned()) - )), + ))), } } -pub fn assoc(xs: &CalcitItems) -> Result { +pub fn assoc(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1), xs.get(2)) { (Some(Calcit::Tuple(a0, a1)), Some(Calcit::Number(n)), Some(a)) => match f64_to_usize(*n) { Ok(idx) => { @@ -405,21 +414,24 @@ pub fn assoc(xs: &CalcitItems) -> Result { } else if idx == 1 { Ok(Calcit::Tuple(a0.to_owned(), Box::new(a.to_owned()))) } else { - Err(format!("Tuple only has fields of 0,1 , unknown index: {}", idx)) + Err(CalcitErr::use_string(format!( + "Tuple only has fields of 0,1 , unknown index: {}", + idx + ))) } } - Err(e) => Err(e), + Err(e) => Err(CalcitErr::use_string(e)), }, - (Some(a), ..) => Err(format!("tuplu:assoc expected a tuple, got: {}", a)), - (None, ..) => Err(format!("tuplu:assoc expected 3 arguments, got: {:?}", xs)), + (Some(a), ..) => Err(CalcitErr::use_string(format!("tuplu:assoc expected a tuple, got: {}", a))), + (None, ..) => Err(CalcitErr::use_string(format!("tuplu:assoc expected 3 arguments, got: {:?}", xs))), } } -pub fn no_op() -> Result { +pub fn no_op() -> Result { Ok(Calcit::Nil) } -pub fn get_os(_xs: &CalcitItems) -> Result { +pub fn get_os(_xs: &CalcitItems) -> Result { // https://doc.rust-lang.org/std/env/consts/constant.OS.html Ok(load_kwd(&std::env::consts::OS.to_owned())) } diff --git a/src/builtins/records.rs b/src/builtins/records.rs index 2fce7617..b82d437b 100644 --- a/src/builtins/records.rs +++ b/src/builtins/records.rs @@ -1,14 +1,14 @@ use std::cmp::Ordering; use std::ops::Rem; -use crate::primes::{keyword::load_order_key, lookup_order_kwd_str, Calcit, CalcitItems}; +use crate::primes::{keyword::load_order_key, lookup_order_kwd_str, Calcit, CalcitErr, CalcitItems}; -pub fn new_record(xs: &CalcitItems) -> Result { +pub fn new_record(xs: &CalcitItems) -> Result { let name_id: usize = match xs.get(0) { Some(Calcit::Symbol(s, ..)) => load_order_key(s), Some(Calcit::Keyword(k)) => k.to_owned(), - Some(a) => return Err(format!("new-record expected a name, got {}", a)), - None => return Err(format!("new-record expected arguments, got {:?}", xs)), + Some(a) => return Err(CalcitErr::use_string(format!("new-record expected a name, got {}", a))), + None => return Err(CalcitErr::use_string(format!("new-record expected arguments, got {:?}", xs))), }; let mut fields: Vec = vec![]; @@ -23,7 +23,12 @@ pub fn new_record(xs: &CalcitItems) -> Result { Calcit::Keyword(s) => { fields.push(s.to_owned()); } - a => return Err(format!("new-record fields accepets keyword/string, got a {}", a)), + a => { + return Err(CalcitErr::use_string(format!( + "new-record fields accepets keyword/string, got a {}", + a + ))) + } } values.push(Calcit::Nil); } @@ -35,7 +40,10 @@ pub fn new_record(xs: &CalcitItems) -> Result { for (idx, x) in fields.iter().enumerate() { if idx > 0 { if x == &prev { - return Err(format!("duplicated field for record: {}", Calcit::Keyword(*x))); + return Err(CalcitErr::use_string(format!( + "duplicated field for record: {}", + Calcit::Keyword(*x) + ))); } else { prev = x.to_owned(); // checked ok @@ -46,17 +54,24 @@ pub fn new_record(xs: &CalcitItems) -> Result { } Ok(Calcit::Record(name_id.to_owned(), fields, values)) } -pub fn call_record(xs: &CalcitItems) -> Result { +pub fn call_record(xs: &CalcitItems) -> Result { let args_size = xs.len(); if args_size < 2 { - return Err(format!("&%{{}} expected at least 2 arguments, got {:?}", xs)); + return Err(CalcitErr::use_string(format!( + "&%{{}} expected at least 2 arguments, got {:?}", + xs + ))); } match &xs[0] { Calcit::Record(name, def_fields, v0) => { if (args_size - 1).rem(2) == 0 { let size = (args_size - 1) / 2; if size != def_fields.len() { - return Err(format!("unexpected size in &%{{}}, {} .. {}", size, def_fields.len())); + return Err(CalcitErr::use_string(format!( + "unexpected size in &%{{}}, {} .. {}", + size, + def_fields.len() + ))); } let mut fields: Vec = def_fields.to_owned(); let mut values: Vec = v0.to_owned(); @@ -70,29 +85,29 @@ pub fn call_record(xs: &CalcitItems) -> Result { fields[pos] = s.to_owned(); values[pos] = xs[v_idx].to_owned(); } - None => return Err(format!("unexpected field {} for {:?}", s, def_fields)), + None => return Err(CalcitErr::use_string(format!("unexpected field {} for {:?}", s, def_fields))), }, Calcit::Symbol(s, ..) | Calcit::Str(s) => match find_in_fields(def_fields, load_order_key(s)) { Some(pos) => { fields[pos] = load_order_key(s); values[pos] = xs[v_idx].to_owned(); } - None => return Err(format!("unexpected field {} for {:?}", s, def_fields)), + None => return Err(CalcitErr::use_string(format!("unexpected field {} for {:?}", s, def_fields))), }, - a => return Err(format!("expected field in string/keyword, got: {}", a)), + a => return Err(CalcitErr::use_string(format!("expected field in string/keyword, got: {}", a))), } } Ok(Calcit::Record(name.to_owned(), fields, values)) } else { - Err(format!("&%{{}} expected pairs, got: {:?}", xs)) + Err(CalcitErr::use_string(format!("&%{{}} expected pairs, got: {:?}", xs))) } } - a => Err(format!("&%{{}} expected a record as prototype, got {}", a)), + a => Err(CalcitErr::use_string(format!("&%{{}} expected a record as prototype, got {}", a))), } } -pub fn record_from_map(xs: &CalcitItems) -> Result { +pub fn record_from_map(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Record(name, fields, _values)), Some(Calcit::Map(ys))) => { let mut pairs: Vec<(String, Calcit)> = vec![]; @@ -104,11 +119,14 @@ pub fn record_from_map(xs: &CalcitItems) -> Result { Calcit::Keyword(s) => { pairs.push((lookup_order_kwd_str(s), v.to_owned())); } - a => return Err(format!("unknown field {}", a)), + a => return Err(CalcitErr::use_string(format!("unknown field {}", a))), } } if fields.len() != pairs.len() { - return Err(format!("invalid fields {:?} for record {:?}", pairs, fields)); + return Err(CalcitErr::use_string(format!( + "invalid fields {:?} for record {:?}", + pairs, fields + ))); } pairs.sort_by(|(a, _), (b, _)| load_order_key(a).cmp(&load_order_key(b))); let mut values: Vec = vec![]; @@ -117,30 +135,36 @@ pub fn record_from_map(xs: &CalcitItems) -> Result { if fields[idx] == load_order_key(k) { values.push(v.to_owned()); } else { - return Err(format!( + return Err(CalcitErr::use_string(format!( "field mismatch: {} {} in {:?} {:?}", load_order_key(k), fields[idx], fields, pairs - )); + ))); } } Ok(Calcit::Record(name.to_owned(), fields.to_owned(), values)) } - (Some(a), Some(b)) => Err(format!("&record:from-map expected a record and a map, got {} {}", a, b)), - (_, _) => Err(format!("&record:from-map expected 2 arguments, got {:?}", xs)), + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!( + "&record:from-map expected a record and a map, got {} {}", + a, b + ))), + (_, _) => Err(CalcitErr::use_string(format!( + "&record:from-map expected 2 arguments, got {:?}", + xs + ))), } } -pub fn get_record_name(xs: &CalcitItems) -> Result { +pub fn get_record_name(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Record(name, ..)) => Ok(Calcit::Keyword(*name)), - Some(a) => Err(format!("&record:get-name expected record, got: {}", a)), - None => Err(String::from("&record:get-name expected record, got nothing")), + Some(a) => Err(CalcitErr::use_string(format!("&record:get-name expected record, got: {}", a))), + None => Err(CalcitErr::use_str("&record:get-name expected record, got nothing")), } } -pub fn turn_map(xs: &CalcitItems) -> Result { +pub fn turn_map(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Record(_name, fields, values)) => { let mut ys: im::HashMap = im::HashMap::new(); @@ -149,17 +173,23 @@ pub fn turn_map(xs: &CalcitItems) -> Result { } Ok(Calcit::Map(ys)) } - Some(a) => Err(format!("&record:to-map expected a record, got {}", a)), - None => Err(String::from("&record:to-map expected 1 argument, got nothing")), + Some(a) => Err(CalcitErr::use_string(format!("&record:to-map expected a record, got {}", a))), + None => Err(CalcitErr::use_str("&record:to-map expected 1 argument, got nothing")), } } -pub fn matches(xs: &CalcitItems) -> Result { +pub fn matches(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Record(left, left_fields, ..)), Some(Calcit::Record(right, right_fields, ..))) => { Ok(Calcit::Bool(left == right && left_fields == right_fields)) } - (Some(a), Some(b)) => Err(format!("&record:matches? expected 2 records, got {} {}", a, b)), - (_, _) => Err(format!("&record:matches? expected 2 arguments, got {:?}", xs)), + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!( + "&record:matches? expected 2 records, got {} {}", + a, b + ))), + (_, _) => Err(CalcitErr::use_string(format!( + "&record:matches? expected 2 arguments, got {:?}", + xs + ))), } } @@ -187,27 +217,30 @@ pub fn find_in_fields(xs: &[usize], y: usize) -> Option { } } -pub fn count(xs: &CalcitItems) -> Result { +pub fn count(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Record(_name, fields, _)) => Ok(Calcit::Number(fields.len() as f64)), - Some(a) => Err(format!("record count expected a record, got: {}", a)), - None => Err(String::from("record count expected 1 argument")), + Some(a) => Err(CalcitErr::use_string(format!("record count expected a record, got: {}", a))), + None => Err(CalcitErr::use_str("record count expected 1 argument")), } } -pub fn contains_ques(xs: &CalcitItems) -> Result { +pub fn contains_ques(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Record(_name, fields, _)), Some(a)) => match a { Calcit::Str(k) | Calcit::Symbol(k, ..) => Ok(Calcit::Bool(find_in_fields(fields, load_order_key(k)).is_some())), Calcit::Keyword(k) => Ok(Calcit::Bool(find_in_fields(fields, k.to_owned()).is_some())), - a => Err(format!("contains? got invalid field for record: {}", a)), + a => Err(CalcitErr::use_string(format!("contains? got invalid field for record: {}", a))), }, - (Some(a), ..) => Err(format!("record contains? expected a record, got: {}", a)), - (None, ..) => Err(format!("record contains? expected 2 arguments, got: {:?}", xs)), + (Some(a), ..) => Err(CalcitErr::use_string(format!("record contains? expected a record, got: {}", a))), + (None, ..) => Err(CalcitErr::use_string(format!( + "record contains? expected 2 arguments, got: {:?}", + xs + ))), } } -pub fn get(xs: &CalcitItems) -> Result { +pub fn get(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Record(_name, fields, values)), Some(a)) => match a { Calcit::Str(k) | Calcit::Symbol(k, ..) => match find_in_fields(fields, load_order_key(k)) { @@ -218,14 +251,17 @@ pub fn get(xs: &CalcitItems) -> Result { Some(idx) => Ok(values[idx].to_owned()), None => Ok(Calcit::Nil), }, - a => Err(format!("record field expected to be string/keyword, got {}", a)), + a => Err(CalcitErr::use_string(format!( + "record field expected to be string/keyword, got {}", + a + ))), }, - (Some(a), ..) => Err(format!("record &get expected record, got: {}", a)), - (None, ..) => Err(format!("record &get expected 2 arguments, got: {:?}", xs)), + (Some(a), ..) => Err(CalcitErr::use_string(format!("record &get expected record, got: {}", a))), + (None, ..) => Err(CalcitErr::use_string(format!("record &get expected 2 arguments, got: {:?}", xs))), } } -pub fn assoc(xs: &CalcitItems) -> Result { +pub fn assoc(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1), xs.get(2)) { (Some(Calcit::Record(name, fields, values)), Some(a), Some(b)) => match a { Calcit::Str(s) | Calcit::Symbol(s, ..) => match find_in_fields(fields, load_order_key(s)) { @@ -234,7 +270,7 @@ pub fn assoc(xs: &CalcitItems) -> Result { new_values[pos] = b.to_owned(); Ok(Calcit::Record(name.to_owned(), fields.to_owned(), new_values)) } - None => Err(format!("invalid field `{}` for {:?}", s, fields)), + None => Err(CalcitErr::use_string(format!("invalid field `{}` for {:?}", s, fields))), }, Calcit::Keyword(s) => match find_in_fields(fields, s.to_owned()) { Some(pos) => { @@ -242,43 +278,45 @@ pub fn assoc(xs: &CalcitItems) -> Result { new_values[pos] = b.to_owned(); Ok(Calcit::Record(name.to_owned(), fields.to_owned(), new_values)) } - None => Err(format!("invalid field `{}` for {:?}", s, fields)), + None => Err(CalcitErr::use_string(format!("invalid field `{}` for {:?}", s, fields))), }, - a => Err(format!("invalid field `{}` for {:?}", a, fields)), + a => Err(CalcitErr::use_string(format!("invalid field `{}` for {:?}", a, fields))), }, - (Some(a), ..) => Err(format!("record:assoc expected a record, got: {}", a)), - (None, ..) => Err(format!("record:assoc expected 3 arguments, got: {:?}", xs)), + (Some(a), ..) => Err(CalcitErr::use_string(format!("record:assoc expected a record, got: {}", a))), + (None, ..) => Err(CalcitErr::use_string(format!("record:assoc expected 3 arguments, got: {:?}", xs))), } } -pub fn extend_as(xs: &CalcitItems) -> Result { +pub fn extend_as(xs: &CalcitItems) -> Result { if xs.len() != 4 { - return Err(format!("record:extend-as expected 4 arguments, got: {:?}", xs)); + return Err(CalcitErr::use_string(format!( + "record:extend-as expected 4 arguments, got: {:?}", + xs + ))); } match (xs.get(0), xs.get(1), xs.get(2), xs.get(3)) { (Some(Calcit::Record(_name, fields, values)), Some(n), Some(a), Some(new_value)) => match a { Calcit::Str(s) | Calcit::Symbol(s, ..) => match find_in_fields(fields, load_order_key(s)) { - Some(_pos) => Err(format!("field `{}` already existed", s)), + Some(_pos) => Err(CalcitErr::use_string(format!("field `{}` already existed", s))), None => extend_record_field(s, n, fields, values, new_value), }, Calcit::Keyword(s) => match find_in_fields(fields, s.to_owned()) { - Some(_pos) => Err(format!("field `{}` already existed", s)), + Some(_pos) => Err(CalcitErr::use_string(format!("field `{}` already existed", s))), None => extend_record_field(&lookup_order_kwd_str(s), n, fields, values, new_value), }, - a => return Err(format!("invalid field `{}` for {:?}", a, fields)), + a => return Err(CalcitErr::use_string(format!("invalid field `{}` for {:?}", a, fields))), }, - (Some(a), ..) => return Err(format!("record:extend-as expected a record, got: {}", a)), - (None, ..) => return Err(format!("record:extend-as expected 4 arguments, got: {:?}", xs)), + (Some(a), ..) => return Err(CalcitErr::use_string(format!("record:extend-as expected a record, got: {}", a))), + (None, ..) => { + return Err(CalcitErr::use_string(format!( + "record:extend-as expected 4 arguments, got: {:?}", + xs + ))) + } } } -fn extend_record_field( - s: &str, - n: &Calcit, - fields: &[usize], - values: &[Calcit], - new_value: &Calcit, -) -> Result { +fn extend_record_field(s: &str, n: &Calcit, fields: &[usize], values: &[Calcit], new_value: &Calcit) -> Result { let mut next_fields: Vec = vec![]; let mut next_values: Vec = vec![]; let mut inserted: bool = false; @@ -313,11 +351,11 @@ fn extend_record_field( next_values.push(new_value.to_owned()); } - let new_name_id: Result = match n { - Calcit::Str(s) | Calcit::Symbol(s, ..) => Ok(load_order_key(s)), - Calcit::Keyword(s) => Ok(s.to_owned()), - _ => Err(String::from("expected record name")), + let new_name_id: usize = match n { + Calcit::Str(s) | Calcit::Symbol(s, ..) => load_order_key(s), + Calcit::Keyword(s) => s.to_owned(), + _ => return Err(CalcitErr::use_str("expected record name")), }; - Ok(Calcit::Record(new_name_id?, next_fields, next_values)) + Ok(Calcit::Record(new_name_id, next_fields, next_values)) } diff --git a/src/builtins/refs.rs b/src/builtins/refs.rs index 94db5009..0817837b 100644 --- a/src/builtins/refs.rs +++ b/src/builtins/refs.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use std::sync::RwLock; -use crate::primes::{lookup_order_kwd_str, Calcit, CalcitItems, CalcitScope}; +use crate::primes::{lookup_order_kwd_str, Calcit, CalcitErr, CalcitItems, CalcitScope}; use crate::program::ProgramCodeData; use crate::runner; @@ -24,7 +24,7 @@ fn write_to_ref(path: String, v: Calcit, listeners: HashMap) { let _ = (*dict).insert(path, (v, listeners)); } -fn modify_ref(path: String, v: Calcit, program_code: &ProgramCodeData) -> Result<(), String> { +fn modify_ref(path: String, v: Calcit, program_code: &ProgramCodeData) -> Result<(), CalcitErr> { let (prev, listeners) = read_ref(&path).unwrap(); write_to_ref(path, v.to_owned(), listeners.to_owned()); @@ -34,19 +34,14 @@ fn modify_ref(path: String, v: Calcit, program_code: &ProgramCodeData) -> Result let values = im::vector![v.to_owned(), prev.to_owned()]; runner::run_fn(&values, def_scope, args, body, def_ns, program_code)?; } - a => return Err(format!("expected fn to trigger after `reset!`, got {}", a)), + a => return Err(CalcitErr::use_string(format!("expected fn to trigger after `reset!`, got {}", a))), } } Ok(()) } /// syntax to prevent expr re-evaluating -pub fn defatom( - expr: &CalcitItems, - scope: &CalcitScope, - file_ns: &str, - program_code: &ProgramCodeData, -) -> Result { +pub fn defatom(expr: &CalcitItems, scope: &CalcitScope, file_ns: &str, program_code: &ProgramCodeData) -> Result { match (expr.get(0), expr.get(1)) { (Some(Calcit::Symbol(s, ns, _def, _)), Some(code)) => { let mut path = ns.to_owned(); @@ -59,19 +54,22 @@ pub fn defatom( } Ok(Calcit::Ref(path)) } - (Some(a), Some(b)) => Err(format!("defref expected a symbol and an expression: {} , {}", a, b)), - _ => Err(String::from("defref expected 2 nodes")), + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!( + "defref expected a symbol and an expression: {} , {}", + a, b + ))), + _ => Err(CalcitErr::use_str("defref expected 2 nodes")), } } -pub fn deref(xs: &CalcitItems) -> Result { +pub fn deref(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Ref(path)) => match read_ref(path) { Some((v, _)) => Ok(v), - None => Err(format!("found nothing after refer &{}", path)), + None => Err(CalcitErr::use_string(format!("found nothing after refer &{}", path))), }, - Some(a) => Err(format!("deref expected a ref, got: {}", a)), - _ => Err(String::from("deref expected 1 argument, got nothing")), + Some(a) => Err(CalcitErr::use_string(format!("deref expected a ref, got: {}", a))), + _ => Err(CalcitErr::use_str("deref expected 1 argument, got nothing")), } } @@ -81,9 +79,9 @@ pub fn reset_bang( scope: &CalcitScope, file_ns: &str, program_code: &ProgramCodeData, -) -> Result { +) -> Result { if expr.len() < 2 { - return Err(format!("reset! excepted 2 arguments, got: {:?}", expr)); + return Err(CalcitErr::use_string(format!("reset! excepted 2 arguments, got: {:?}", expr))); } // println!("reset! {:?}", expr[0]); let target = runner::evaluate_expr(&expr[0], scope, file_ns, program_code)?; @@ -91,22 +89,28 @@ pub fn reset_bang( match (target, new_value) { (Calcit::Ref(path), v) => { if read_ref(&path).is_none() { - return Err(format!("missing pre-exisiting data for path &{}", path)); + return Err(CalcitErr::use_string(format!("missing pre-exisiting data for path &{}", path))); } modify_ref(path, v, program_code)?; Ok(Calcit::Nil) } - (a, b) => Err(format!("reset! expected a ref and a value, got: {} {}", a, b)), + (a, b) => Err(CalcitErr::use_string(format!( + "reset! expected a ref and a value, got: {} {}", + a, b + ))), } } -pub fn add_watch(xs: &CalcitItems) -> Result { +pub fn add_watch(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1), xs.get(2)) { (Some(Calcit::Ref(path)), Some(Calcit::Keyword(k)), Some(Calcit::Fn(..))) => { let mut dict = REFS_DICT.write().unwrap(); let (prev, listeners) = &(*dict).get(path).unwrap().to_owned(); if listeners.contains_key(&lookup_order_kwd_str(k)) { - Err(format!("add-watch failed, listener with key `{}` existed", k)) + Err(CalcitErr::use_string(format!( + "add-watch failed, listener with key `{}` existed", + k + ))) } else { let mut new_listeners = listeners.to_owned(); new_listeners.insert(lookup_order_kwd_str(k), xs.get(2).unwrap().to_owned()); @@ -115,18 +119,18 @@ pub fn add_watch(xs: &CalcitItems) -> Result { } } (Some(Calcit::Ref(_)), Some(Calcit::Keyword(_)), Some(a)) => { - Err(format!("add-watch expected fn instead of proc, got {}", a)) + Err(CalcitErr::use_string(format!("add-watch expected fn instead of proc, got {}", a))) } - (Some(Calcit::Ref(_)), Some(a), Some(_)) => Err(format!("add-watch expected a keyword, but got: {}", a)), - (Some(a), _, _) => Err(format!("add-watch expected ref, got: {}", a)), - (a, b, c) => Err(format!( + (Some(Calcit::Ref(_)), Some(a), Some(_)) => Err(CalcitErr::use_string(format!("add-watch expected a keyword, but got: {}", a))), + (Some(a), _, _) => Err(CalcitErr::use_string(format!("add-watch expected ref, got: {}", a))), + (a, b, c) => Err(CalcitErr::use_string(format!( "add-watch expected ref, keyword, function, got {:?} {:?} {:?}", a, b, c - )), + ))), } } -pub fn remove_watch(xs: &CalcitItems) -> Result { +pub fn remove_watch(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Ref(path)), Some(Calcit::Keyword(k))) => { let mut dict = REFS_DICT.write().unwrap(); @@ -137,10 +141,19 @@ pub fn remove_watch(xs: &CalcitItems) -> Result { let _ = (*dict).insert(path.to_owned(), (prev.to_owned(), new_listeners)); Ok(Calcit::Nil) } else { - Err(format!("remove-watch failed, listener with key `{}` missing", k)) + Err(CalcitErr::use_string(format!( + "remove-watch failed, listener with key `{}` missing", + k + ))) } } - (Some(a), Some(b)) => Err(format!("remove-watch expected ref and keyword, got: {} {}", a, b)), - (a, b) => Err(format!("remove-watch expected 2 arguments, got {:?} {:?}", a, b)), + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!( + "remove-watch expected ref and keyword, got: {} {}", + a, b + ))), + (a, b) => Err(CalcitErr::use_string(format!( + "remove-watch expected 2 arguments, got {:?} {:?}", + a, b + ))), } } diff --git a/src/builtins/sets.rs b/src/builtins/sets.rs index 6075a94e..f39cc1c8 100644 --- a/src/builtins/sets.rs +++ b/src/builtins/sets.rs @@ -1,6 +1,6 @@ -use crate::primes::{Calcit, CalcitItems}; +use crate::primes::{Calcit, CalcitErr, CalcitItems}; -pub fn new_set(xs: &CalcitItems) -> Result { +pub fn new_set(xs: &CalcitItems) -> Result { let mut ys = im::HashSet::new(); for x in xs { ys.insert(x.to_owned()); @@ -8,30 +8,30 @@ pub fn new_set(xs: &CalcitItems) -> Result { Ok(Calcit::Set(ys)) } -pub fn call_include(xs: &CalcitItems) -> Result { +pub fn call_include(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Set(xs)), Some(a)) => { let mut ys = xs.to_owned(); ys.insert(a.to_owned()); Ok(Calcit::Set(ys)) } - (Some(a), _) => Err(format!("&include expect a set, but got: {}", a)), - (a, b) => Err(format!("invalid arguments for &include: {:?} {:?}", a, b)), + (Some(a), _) => Err(CalcitErr::use_string(format!("&include expect a set, but got: {}", a))), + (a, b) => Err(CalcitErr::use_string(format!("invalid arguments for &include: {:?} {:?}", a, b))), } } -pub fn call_exclude(xs: &CalcitItems) -> Result { +pub fn call_exclude(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Set(xs)), Some(a)) => { let mut ys = xs.to_owned(); ys.remove(a); Ok(Calcit::Set(ys)) } - (Some(a), _) => Err(format!("&exclude expect a set, but got: {}", a)), - (a, b) => Err(format!("invalid arguments for &exclude: {:?} {:?}", a, b)), + (Some(a), _) => Err(CalcitErr::use_string(format!("&exclude expect a set, but got: {}", a))), + (a, b) => Err(CalcitErr::use_string(format!("invalid arguments for &exclude: {:?} {:?}", a, b))), } } -pub fn call_difference(xs: &CalcitItems) -> Result { +pub fn call_difference(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Set(a)), Some(Calcit::Set(b))) => { // im::HashSet::difference has different semantics @@ -42,27 +42,30 @@ pub fn call_difference(xs: &CalcitItems) -> Result { } Ok(Calcit::Set(ys)) } - (Some(a), Some(b)) => Err(format!("&difference expected 2 sets: {} {}", a, b)), - (a, b) => Err(format!("&difference expected 2 arguments: {:?} {:?}", a, b)), + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!("&difference expected 2 sets: {} {}", a, b))), + (a, b) => Err(CalcitErr::use_string(format!("&difference expected 2 arguments: {:?} {:?}", a, b))), } } -pub fn call_union(xs: &CalcitItems) -> Result { +pub fn call_union(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Set(a)), Some(Calcit::Set(b))) => Ok(Calcit::Set(a.to_owned().union(b.to_owned()))), - (Some(a), Some(b)) => Err(format!("&union expected 2 sets: {} {}", a, b)), - (a, b) => Err(format!("&union expected 2 arguments: {:?} {:?}", a, b)), + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!("&union expected 2 sets: {} {}", a, b))), + (a, b) => Err(CalcitErr::use_string(format!("&union expected 2 arguments: {:?} {:?}", a, b))), } } -pub fn call_intersection(xs: &CalcitItems) -> Result { +pub fn call_intersection(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Set(a)), Some(Calcit::Set(b))) => Ok(Calcit::Set(a.to_owned().intersection(b.to_owned()))), - (Some(a), Some(b)) => Err(format!("&set:intersection expected 2 sets: {} {}", a, b)), - (a, b) => Err(format!("&set:intersection expected 2 arguments: {:?} {:?}", a, b)), + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!("&set:intersection expected 2 sets: {} {}", a, b))), + (a, b) => Err(CalcitErr::use_string(format!( + "&set:intersection expected 2 arguments: {:?} {:?}", + a, b + ))), } } /// turn hashset into list with a random order from internals -pub fn set_to_list(xs: &CalcitItems) -> Result { +pub fn set_to_list(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Set(xs)) => { let mut ys: CalcitItems = im::vector![]; @@ -71,49 +74,52 @@ pub fn set_to_list(xs: &CalcitItems) -> Result { } Ok(Calcit::List(ys)) } - Some(a) => Err(format!("&set:to-list expected a set: {}", a)), - None => Err(String::from("&set:to-list expected 1 argument, got none")), + Some(a) => Err(CalcitErr::use_string(format!("&set:to-list expected a set: {}", a))), + None => Err(CalcitErr::use_str("&set:to-list expected 1 argument, got none")), } } -pub fn count(xs: &CalcitItems) -> Result { +pub fn count(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Set(ys)) => Ok(Calcit::Number(ys.len() as f64)), - Some(a) => Err(format!("set count expected a set, got: {}", a)), - None => Err(String::from("set count expected 1 argument")), + Some(a) => Err(CalcitErr::use_string(format!("set count expected a set, got: {}", a))), + None => Err(CalcitErr::use_str("set count expected 1 argument")), } } -pub fn empty_ques(xs: &CalcitItems) -> Result { +pub fn empty_ques(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Set(ys)) => Ok(Calcit::Bool(ys.is_empty())), - Some(a) => Err(format!("set empty? expected some set, got: {}", a)), - None => Err(String::from("set empty? expected 1 argument")), + Some(a) => Err(CalcitErr::use_string(format!("set empty? expected some set, got: {}", a))), + None => Err(CalcitErr::use_str("set empty? expected 1 argument")), } } -pub fn includes_ques(xs: &CalcitItems) -> Result { +pub fn includes_ques(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Set(xs)), Some(a)) => Ok(Calcit::Bool(xs.contains(a))), - (Some(a), ..) => Err(format!("sets `includes?` expected set, got: {}", a)), - (None, ..) => Err(format!("sets `includes?` expected 2 arguments, got: {:?}", xs)), + (Some(a), ..) => Err(CalcitErr::use_string(format!("sets `includes?` expected set, got: {}", a))), + (None, ..) => Err(CalcitErr::use_string(format!( + "sets `includes?` expected 2 arguments, got: {:?}", + xs + ))), } } /// use builtin function since sets need to be handled specifically -pub fn first(xs: &CalcitItems) -> Result { +pub fn first(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Set(ys)) => match ys.iter().next() { // TODO first element of a set.. need to be more sure... Some(v) => Ok(v.to_owned()), None => Ok(Calcit::Nil), }, - Some(a) => Err(format!("set:first expected a set, got: {}", a)), - None => Err(String::from("set:first expected 1 argument")), + Some(a) => Err(CalcitErr::use_string(format!("set:first expected a set, got: {}", a))), + None => Err(CalcitErr::use_str("set:first expected 1 argument")), } } -pub fn rest(xs: &CalcitItems) -> Result { +pub fn rest(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Set(ys)) => match ys.iter().next() { Some(y0) => { @@ -123,7 +129,7 @@ pub fn rest(xs: &CalcitItems) -> Result { } None => Ok(Calcit::Nil), }, - Some(a) => Err(format!("set:rest expected a set, got: {}", a)), - None => Err(String::from("set:rest expected 1 argument")), + Some(a) => Err(CalcitErr::use_string(format!("set:rest expected a set, got: {}", a))), + None => Err(CalcitErr::use_str("set:rest expected 1 argument")), } } diff --git a/src/builtins/strings.rs b/src/builtins/strings.rs index 9c79334f..895084ca 100644 --- a/src/builtins/strings.rs +++ b/src/builtins/strings.rs @@ -2,10 +2,10 @@ use std::char; use std::cmp::Ordering; use crate::primes; -use crate::primes::{lookup_order_kwd_str, Calcit, CalcitItems, CrListWrap}; +use crate::primes::{lookup_order_kwd_str, Calcit, CalcitErr, CalcitItems, CrListWrap}; use crate::util::number::f64_to_usize; -pub fn binary_str_concat(xs: &CalcitItems) -> Result { +pub fn binary_str_concat(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Nil), Some(Calcit::Nil)) => Ok(Calcit::Str(String::from(""))), (Some(Calcit::Nil), Some(b)) => Ok(Calcit::Str(b.turn_string())), @@ -15,14 +15,14 @@ pub fn binary_str_concat(xs: &CalcitItems) -> Result { s.push_str(&b.turn_string()); Ok(Calcit::Str(s)) } - (_, _) => Err(format!( + (_, _) => Err(CalcitErr::use_string(format!( "expected 2 arguments, got: {}", primes::CrListWrap(xs.to_owned()) - )), + ))), } } -pub fn trim(xs: &CalcitItems) -> Result { +pub fn trim(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Str(s)), None) => Ok(Calcit::Str(s.trim().to_owned())), (Some(Calcit::Str(s)), Some(Calcit::Str(p))) => { @@ -30,26 +30,26 @@ pub fn trim(xs: &CalcitItems) -> Result { let c: char = p.chars().next().unwrap(); Ok(Calcit::Str(s.trim_matches(c).to_owned())) } else { - Err(format!("trim expected pattern in a char, got {}", p)) + Err(CalcitErr::use_string(format!("trim expected pattern in a char, got {}", p))) } } - (Some(a), Some(b)) => Err(format!("trim expected 2 strings, but got: {} {}", a, b)), - (_, _) => Err(format!( + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!("trim expected 2 strings, but got: {} {}", a, b))), + (_, _) => Err(CalcitErr::use_string(format!( "expected 2 arguments, got: {}", primes::CrListWrap(xs.to_owned()) - )), + ))), } } /// just format value to string -pub fn call_str(xs: &CalcitItems) -> Result { +pub fn call_str(xs: &CalcitItems) -> Result { match xs.get(0) { Some(a) => Ok(Calcit::Str(a.turn_string())), - None => Err(String::from("&str expected 1 argument, got nothing")), + None => Err(CalcitErr::use_string(String::from("&str expected 1 argument, got nothing"))), } } -pub fn turn_string(xs: &CalcitItems) -> Result { +pub fn turn_string(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Nil) => Ok(Calcit::Str(String::from(""))), Some(Calcit::Bool(b)) => Ok(Calcit::Str(b.to_string())), @@ -57,12 +57,12 @@ pub fn turn_string(xs: &CalcitItems) -> Result { Some(Calcit::Keyword(s)) => Ok(Calcit::Str(lookup_order_kwd_str(s))), Some(Calcit::Symbol(s, ..)) => Ok(Calcit::Str(s.to_owned())), Some(Calcit::Number(n)) => Ok(Calcit::Str(n.to_string())), - Some(a) => Err(format!("turn-string cannot turn this to string: {}", a)), - None => Err(String::from("turn-string expected 1 argument, got nothing")), + Some(a) => Err(CalcitErr::use_string(format!("turn-string cannot turn this to string: {}", a))), + None => Err(CalcitErr::use_str("turn-string expected 1 argument, got nothing")), } } -pub fn split(xs: &CalcitItems) -> Result { +pub fn split(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Str(s)), Some(Calcit::Str(pattern))) => { let pieces = s.split(pattern); @@ -74,33 +74,36 @@ pub fn split(xs: &CalcitItems) -> Result { } Ok(Calcit::List(ys)) } - (Some(a), Some(b)) => Err(format!("split expected 2 strings, got: {} {}", a, b)), - (_, _) => Err(String::from("split expected 2 arguments, got nothing")), + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!("split expected 2 strings, got: {} {}", a, b))), + (_, _) => Err(CalcitErr::use_str("split expected 2 arguments, got nothing")), } } -pub fn format_number(xs: &CalcitItems) -> Result { +pub fn format_number(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Number(n)), Some(Calcit::Number(x))) => { - let size = f64_to_usize(*x)?; + let size = f64_to_usize(*x).map_err(CalcitErr::use_string)?; Ok(Calcit::Str(format!("{n:.*}", size, n = n))) } - (Some(a), Some(b)) => Err(format!("&number:format expected numbers, got: {} {}", a, b)), - (_, _) => Err(String::from("&number:format expected 2 arguments")), + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!("&number:format expected numbers, got: {} {}", a, b))), + (_, _) => Err(CalcitErr::use_str("&number:format expected 2 arguments")), } } -pub fn replace(xs: &CalcitItems) -> Result { +pub fn replace(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1), xs.get(2)) { (Some(Calcit::Str(s)), Some(Calcit::Str(p)), Some(Calcit::Str(r))) => Ok(Calcit::Str(s.replace(p, r))), - (Some(a), Some(b), Some(c)) => Err(format!("str:replace expected 3 strings, got: {} {} {}", a, b, c)), - (_, _, _) => Err(format!( + (Some(a), Some(b), Some(c)) => Err(CalcitErr::use_string(format!( + "str:replace expected 3 strings, got: {} {} {}", + a, b, c + ))), + (_, _, _) => Err(CalcitErr::use_string(format!( "str:replace expected 3 arguments, got: {}", primes::CrListWrap(xs.to_owned()) - )), + ))), } } -pub fn split_lines(xs: &CalcitItems) -> Result { +pub fn split_lines(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Str(s)) => { let lines = s.split('\n'); @@ -110,20 +113,20 @@ pub fn split_lines(xs: &CalcitItems) -> Result { } Ok(Calcit::List(ys)) } - Some(a) => Err(format!("split-lines expected 1 string, got: {}", a)), - _ => Err(String::from("split-lines expected 1 argument, got nothing")), + Some(a) => Err(CalcitErr::use_string(format!("split-lines expected 1 string, got: {}", a))), + _ => Err(CalcitErr::use_str("split-lines expected 1 argument, got nothing")), } } -pub fn str_slice(xs: &CalcitItems) -> Result { +pub fn str_slice(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Str(s)), Some(Calcit::Number(n))) => match f64_to_usize(*n) { Ok(from) => { let to: usize = match xs.get(2) { Some(Calcit::Number(n2)) => match f64_to_usize(*n2) { Ok(idx2) => idx2, - Err(e) => return Err(format!("&str:slice expected number, got: {}", e)), + Err(e) => return Err(CalcitErr::use_string(format!("&str:slice expected number, got: {}", e))), }, - Some(a) => return Err(format!("&str:slice expected number, got: {}", a)), + Some(a) => return Err(CalcitErr::use_string(format!("&str:slice expected number, got: {}", a))), None => s.chars().count(), }; if from >= to { @@ -134,14 +137,20 @@ pub fn str_slice(xs: &CalcitItems) -> Result { Ok(Calcit::Str(s_vec[from..to].iter().cloned().collect::())) } } - Err(e) => Err(e), + Err(e) => Err(CalcitErr::use_string(e)), }, - (Some(a), Some(b)) => Err(format!("&str:slice expected string and number, got: {} {}", a, b)), - (_, _) => Err(format!("&str:slice expected string and numbers, got: {:?}", xs)), + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!( + "&str:slice expected string and number, got: {} {}", + a, b + ))), + (_, _) => Err(CalcitErr::use_string(format!( + "&str:slice expected string and numbers, got: {:?}", + xs + ))), } } -pub fn compare_string(xs: &CalcitItems) -> Result { +pub fn compare_string(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Str(a)), Some(Calcit::Str(b))) => { let v = match a.cmp(b) { @@ -151,36 +160,39 @@ pub fn compare_string(xs: &CalcitItems) -> Result { }; Ok(Calcit::Number(v as f64)) } - (Some(a), Some(b)) => Err(format!("&str:compare expected 2 strings, got: {}, {}", a, b)), - (_, _) => Err(format!("&str:compare expected 2 string, got: {:?}", xs)), + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!("&str:compare expected 2 strings, got: {}, {}", a, b))), + (_, _) => Err(CalcitErr::use_string(format!("&str:compare expected 2 string, got: {:?}", xs))), } } -pub fn find_index(xs: &CalcitItems) -> Result { +pub fn find_index(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Str(s)), Some(Calcit::Str(pattern))) => match s.find(pattern) { Some(idx) => Ok(Calcit::Number(idx as f64)), None => Ok(Calcit::Number(-1.0)), // TODO maybe nil? }, - (Some(a), Some(b)) => Err(format!("str:find-index expected 2 strings, got: {} {}", a, b)), - (_, _) => Err(String::from("str:find-index expected 2 arguments, got nothing")), + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!( + "str:find-index expected 2 strings, got: {} {}", + a, b + ))), + (_, _) => Err(CalcitErr::use_str("str:find-index expected 2 arguments, got nothing")), } } -pub fn starts_with_ques(xs: &CalcitItems) -> Result { +pub fn starts_with_ques(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Str(s)), Some(Calcit::Str(pattern))) => Ok(Calcit::Bool(s.starts_with(pattern))), - (Some(a), Some(b)) => Err(format!("starts-with? expected 2 strings, got: {} {}", a, b)), - (_, _) => Err(String::from("starts-with? expected 2 arguments, got nothing")), + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!("starts-with? expected 2 strings, got: {} {}", a, b))), + (_, _) => Err(CalcitErr::use_str("starts-with? expected 2 arguments, got nothing")), } } -pub fn ends_with_ques(xs: &CalcitItems) -> Result { +pub fn ends_with_ques(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Str(s)), Some(Calcit::Str(pattern))) => Ok(Calcit::Bool(s.ends_with(pattern))), - (Some(a), Some(b)) => Err(format!("ends-with? expected 2 strings, got: {} {}", a, b)), - (_, _) => Err(String::from("ends-with? expected 2 arguments, got nothing")), + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!("ends-with? expected 2 strings, got: {} {}", a, b))), + (_, _) => Err(CalcitErr::use_str("ends-with? expected 2 arguments, got nothing")), } } -pub fn get_char_code(xs: &CalcitItems) -> Result { +pub fn get_char_code(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Str(s)) => { if s.chars().count() == 1 { @@ -189,49 +201,49 @@ pub fn get_char_code(xs: &CalcitItems) -> Result { None => unreachable!("expected a character"), } } else { - Err(format!("get-char-code expected a character, got: {}", s)) + Err(CalcitErr::use_string(format!("get-char-code expected a character, got: {}", s))) } } - Some(a) => Err(format!("get-char-code expected a charactor, got: {}", a)), - _ => Err(String::from("get-char-code expected 1 argument, got nothing")), + Some(a) => Err(CalcitErr::use_string(format!("get-char-code expected a charactor, got: {}", a))), + _ => Err(CalcitErr::use_str("get-char-code expected 1 argument, got nothing")), } } -pub fn char_from_code(xs: &CalcitItems) -> Result { +pub fn char_from_code(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Number(x)) => match f64_to_usize(*x) { Ok(n) => Ok(Calcit::Str((char::from_u32(n as u32).unwrap()).to_string())), - Err(e) => return Err(format!("char_from_code expected number, got: {}", e)), + Err(e) => return Err(CalcitErr::use_string(format!("char_from_code expected number, got: {}", e))), }, - Some(a) => Err(format!("char_from_code expected 1 number, got: {}", a)), - _ => Err(String::from("char_from_code expected 1 arguments, got nothing")), + Some(a) => Err(CalcitErr::use_string(format!("char_from_code expected 1 number, got: {}", a))), + _ => Err(CalcitErr::use_str("char_from_code expected 1 arguments, got nothing")), } } -pub fn parse_float(xs: &CalcitItems) -> Result { +pub fn parse_float(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Str(s)) => match s.parse::() { Ok(n) => Ok(Calcit::Number(n)), - Err(e) => Err(format!("parse-float failed, {}", e)), + Err(e) => Err(CalcitErr::use_string(format!("parse-float failed, {}", e))), }, - Some(a) => Err(format!("starts-with? expected 1 string, got: {}", a)), - _ => Err(String::from("starts-with? expected 1 argument, got nothing")), + Some(a) => Err(CalcitErr::use_string(format!("starts-with? expected 1 string, got: {}", a))), + _ => Err(CalcitErr::use_str("starts-with? expected 1 argument, got nothing")), } } -pub fn pr_str(xs: &CalcitItems) -> Result { +pub fn pr_str(xs: &CalcitItems) -> Result { match xs.get(0) { Some(a) => Ok(Calcit::Str(a.to_string())), - None => Err(String::from("pr-str expected 1 argument, got nothing")), + None => Err(CalcitErr::use_str("pr-str expected 1 argument, got nothing")), } } -pub fn blank_ques(xs: &CalcitItems) -> Result { +pub fn blank_ques(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Str(s)) => Ok(Calcit::Bool(s.trim().is_empty())), - Some(a) => Err(format!("blank? expected 1 string, got: {}", a)), - None => Err(String::from("blank? expected 1 argument, got nothing")), + Some(a) => Err(CalcitErr::use_string(format!("blank? expected 1 string, got: {}", a))), + None => Err(CalcitErr::use_str("blank? expected 1 argument, got nothing")), } } -pub fn escape(xs: &CalcitItems) -> Result { +pub fn escape(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Str(s)) => { let mut chunk = String::from("\""); @@ -239,76 +251,88 @@ pub fn escape(xs: &CalcitItems) -> Result { chunk.push('"'); Ok(Calcit::Str(chunk)) } - Some(a) => Err(format!("escape expected 1 string, got {}", a)), - None => Err(String::from("escape expected 1 argument, got nothing")), + Some(a) => Err(CalcitErr::use_string(format!("escape expected 1 string, got {}", a))), + None => Err(CalcitErr::use_str("escape expected 1 argument, got nothing")), } } -pub fn count(xs: &CalcitItems) -> Result { +pub fn count(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Str(s)) => Ok(Calcit::Number(s.chars().count() as f64)), - Some(a) => Err(format!("string count expected a string, got: {}", a)), - None => Err(String::from("string count expected 1 argument")), + Some(a) => Err(CalcitErr::use_string(format!("string count expected a string, got: {}", a))), + None => Err(CalcitErr::use_str("string count expected 1 argument")), } } -pub fn empty_ques(xs: &CalcitItems) -> Result { +pub fn empty_ques(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Str(s)) => Ok(Calcit::Bool(s.is_empty())), - Some(a) => Err(format!("string empty? expected a string, got: {}", a)), - None => Err(String::from("string empty? expected 1 argument")), + Some(a) => Err(CalcitErr::use_string(format!("string empty? expected a string, got: {}", a))), + None => Err(CalcitErr::use_str("string empty? expected 1 argument")), } } -pub fn contains_ques(xs: &CalcitItems) -> Result { +pub fn contains_ques(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Str(s)), Some(Calcit::Number(n))) => match f64_to_usize(*n) { Ok(idx) => Ok(Calcit::Bool(idx < s.chars().count())), - Err(e) => Err(e), + Err(e) => Err(CalcitErr::use_string(e)), }, - (Some(a), ..) => Err(format!("strings contains? expected a string, got: {}", a)), - (None, ..) => Err(format!("strings contains? expected 2 arguments, got: {:?}", xs)), + (Some(a), ..) => Err(CalcitErr::use_string(format!("strings contains? expected a string, got: {}", a))), + (None, ..) => Err(CalcitErr::use_string(format!( + "strings contains? expected 2 arguments, got: {:?}", + xs + ))), } } -pub fn includes_ques(xs: &CalcitItems) -> Result { +pub fn includes_ques(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Str(xs)), Some(Calcit::Str(a))) => Ok(Calcit::Bool(xs.contains(a))), - (Some(Calcit::Str(_)), Some(a)) => Err(format!("string `includes?` expected a string, got: {}", a)), - (Some(a), ..) => Err(format!("string `includes?` expected string, got: {}", a)), - (None, ..) => Err(format!("string `includes?` expected 2 arguments, got: {:?}", xs)), + (Some(Calcit::Str(_)), Some(a)) => Err(CalcitErr::use_string(format!("string `includes?` expected a string, got: {}", a))), + (Some(a), ..) => Err(CalcitErr::use_string(format!("string `includes?` expected string, got: {}", a))), + (None, ..) => Err(CalcitErr::use_string(format!( + "string `includes?` expected 2 arguments, got: {:?}", + xs + ))), } } -pub fn nth(xs: &CalcitItems) -> Result { +pub fn nth(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Str(s)), Some(Calcit::Number(n))) => match f64_to_usize(*n) { Ok(idx) => match s.chars().nth(idx) { Some(v) => Ok(Calcit::Str(v.to_string())), None => Ok(Calcit::Nil), }, - Err(e) => Err(format!("string nth expect usize, {}", e)), + Err(e) => Err(CalcitErr::use_string(format!("string nth expect usize, {}", e))), }, - (Some(_), None) => Err(format!("string nth expected a string and index, got: {:?}", xs)), - (None, Some(_)) => Err(format!("string nth expected a string and index, got: {:?}", xs)), - (_, _) => Err(format!( + (Some(_), None) => Err(CalcitErr::use_string(format!( + "string nth expected a string and index, got: {:?}", + xs + ))), + (None, Some(_)) => Err(CalcitErr::use_string(format!( + "string nth expected a string and index, got: {:?}", + xs + ))), + (_, _) => Err(CalcitErr::use_string(format!( "string nth expected 2 argument, got: {}", CrListWrap(xs.to_owned()) - )), + ))), } } -pub fn first(xs: &CalcitItems) -> Result { +pub fn first(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Str(s)) => match s.chars().next() { Some(c) => Ok(Calcit::Str(c.to_string())), None => Ok(Calcit::Nil), }, - Some(a) => Err(format!("str:first expected a string, got: {}", a)), - None => Err(String::from("str:first expected 1 argument")), + Some(a) => Err(CalcitErr::use_string(format!("str:first expected a string, got: {}", a))), + None => Err(CalcitErr::use_str("str:first expected 1 argument")), } } -pub fn rest(xs: &CalcitItems) -> Result { +pub fn rest(xs: &CalcitItems) -> Result { match xs.get(0) { Some(Calcit::Str(s)) => { let mut buffer = String::from(""); @@ -322,7 +346,7 @@ pub fn rest(xs: &CalcitItems) -> Result { } Ok(Calcit::Str(buffer)) } - Some(a) => Err(format!("str:rest expected a string, got: {}", a)), - None => Err(String::from("str:rest expected 1 argument")), + Some(a) => Err(CalcitErr::use_string(format!("str:rest expected a string, got: {}", a))), + None => Err(CalcitErr::use_str("str:rest expected 1 argument")), } } diff --git a/src/builtins/syntax.rs b/src/builtins/syntax.rs index f7a67340..d4bdfda7 100644 --- a/src/builtins/syntax.rs +++ b/src/builtins/syntax.rs @@ -6,16 +6,11 @@ use std::cell::RefCell; use std::collections::HashSet; use crate::builtins; -use crate::primes::{gen_core_id, Calcit, CalcitItems, CalcitScope}; +use crate::primes::{gen_core_id, Calcit, CalcitErr, CalcitItems, CalcitScope}; use crate::program::ProgramCodeData; use crate::runner; -pub fn defn( - expr: &CalcitItems, - scope: &CalcitScope, - file_ns: &str, - _program: &ProgramCodeData, -) -> Result { +pub fn defn(expr: &CalcitItems, scope: &CalcitScope, file_ns: &str, _program: &ProgramCodeData) -> Result { match (expr.get(0), expr.get(1)) { (Some(Calcit::Symbol(s, ..)), Some(Calcit::List(xs))) => Ok(Calcit::Fn( s.to_owned(), @@ -25,17 +20,12 @@ pub fn defn( Box::new(xs.to_owned()), Box::new(expr.skip(2)), )), - (Some(a), Some(b)) => Err(format!("invalid args type for defn: {} , {}", a, b)), - _ => Err(String::from("inefficient arguments for defn")), + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!("invalid args type for defn: {} , {}", a, b))), + _ => Err(CalcitErr::use_str("inefficient arguments for defn")), } } -pub fn defmacro( - expr: &CalcitItems, - _scope: &CalcitScope, - def_ns: &str, - _program: &ProgramCodeData, -) -> Result { +pub fn defmacro(expr: &CalcitItems, _scope: &CalcitScope, def_ns: &str, _program: &ProgramCodeData) -> Result { match (expr.get(0), expr.get(1)) { (Some(Calcit::Symbol(s, ..)), Some(Calcit::List(xs))) => Ok(Calcit::Macro( s.to_owned(), @@ -44,35 +34,25 @@ pub fn defmacro( Box::new(xs.to_owned()), Box::new(expr.skip(2)), )), - (Some(a), Some(b)) => Err(format!("invalid structure for defmacro: {} {}", a, b)), - _ => Err(format!( + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!("invalid structure for defmacro: {} {}", a, b))), + _ => Err(CalcitErr::use_string(format!( "invalid structure for defmacro: {}", Calcit::List(expr.to_owned()) - )), + ))), } } -pub fn quote( - expr: &CalcitItems, - _scope: &CalcitScope, - _file_ns: &str, - _program: &ProgramCodeData, -) -> Result { +pub fn quote(expr: &CalcitItems, _scope: &CalcitScope, _file_ns: &str, _program: &ProgramCodeData) -> Result { if expr.len() == 1 { Ok(expr[0].to_owned()) } else { - Err(format!("unexpected data for quote: {:?}", expr)) + Err(CalcitErr::use_string(format!("unexpected data for quote: {:?}", expr))) } } -pub fn syntax_if( - expr: &CalcitItems, - scope: &CalcitScope, - file_ns: &str, - program_code: &ProgramCodeData, -) -> Result { +pub fn syntax_if(expr: &CalcitItems, scope: &CalcitScope, file_ns: &str, program_code: &ProgramCodeData) -> Result { match (expr.get(0), expr.get(1)) { - _ if expr.len() > 3 => Err(format!("too many nodes for if: {:?}", expr)), + _ if expr.len() > 3 => Err(CalcitErr::use_string(format!("too many nodes for if: {:?}", expr))), (Some(cond), Some(true_branch)) => { let cond_value = runner::evaluate_expr(cond, scope, file_ns, program_code)?; match cond_value { @@ -83,31 +63,21 @@ pub fn syntax_if( _ => runner::evaluate_expr(true_branch, scope, file_ns, program_code), } } - (None, _) => Err(format!("insufficient nodes for if: {:?}", expr)), - _ => Err(format!("invalid if form: {:?}", expr)), + (None, _) => Err(CalcitErr::use_string(format!("insufficient nodes for if: {:?}", expr))), + _ => Err(CalcitErr::use_string(format!("invalid if form: {:?}", expr))), } } -pub fn eval( - expr: &CalcitItems, - scope: &CalcitScope, - file_ns: &str, - program_code: &ProgramCodeData, -) -> Result { +pub fn eval(expr: &CalcitItems, scope: &CalcitScope, file_ns: &str, program_code: &ProgramCodeData) -> Result { if expr.len() == 1 { let v = runner::evaluate_expr(&expr[0], scope, file_ns, program_code)?; runner::evaluate_expr(&v, scope, file_ns, program_code) } else { - Err(format!("unexpected data for evaling: {:?}", expr)) + Err(CalcitErr::use_string(format!("unexpected data for evaling: {:?}", expr))) } } -pub fn syntax_let( - expr: &CalcitItems, - scope: &CalcitScope, - file_ns: &str, - program_code: &ProgramCodeData, -) -> Result { +pub fn syntax_let(expr: &CalcitItems, scope: &CalcitScope, file_ns: &str, program_code: &ProgramCodeData) -> Result { match expr.get(0) { Some(Calcit::Nil) => runner::evaluate_lines(&expr.skip(1), scope, file_ns, program_code), Some(Calcit::List(xs)) if xs.len() == 2 => { @@ -117,13 +87,13 @@ pub fn syntax_let( let value = runner::evaluate_expr(ys, scope, file_ns, program_code)?; body_scope.insert(s.to_owned(), value); } - (a, _) => return Err(format!("invalid binding name: {}", a)), + (a, _) => return Err(CalcitErr::use_string(format!("invalid binding name: {}", a))), } runner::evaluate_lines(&expr.skip(1), &body_scope, file_ns, program_code) } - Some(Calcit::List(xs)) => Err(format!("invalid length: {:?}", xs)), - Some(_) => Err(format!("invalid node for &let: {:?}", expr)), - None => Err(String::from("&let expected a pair or a nil")), + Some(Calcit::List(xs)) => Err(CalcitErr::use_string(format!("invalid length: {:?}", xs))), + Some(_) => Err(CalcitErr::use_string(format!("invalid node for &let: {:?}", expr))), + None => Err(CalcitErr::use_str("&let expected a pair or a nil")), } } @@ -134,32 +104,25 @@ enum SpanResult { Range(CalcitItems), } -pub fn quasiquote( - expr: &CalcitItems, - scope: &CalcitScope, - file_ns: &str, - program_code: &ProgramCodeData, -) -> Result { +pub fn quasiquote(expr: &CalcitItems, scope: &CalcitScope, file_ns: &str, program_code: &ProgramCodeData) -> Result { match expr.get(0) { - None => Err(String::from("quasiquote expected a node")), + None => Err(CalcitErr::use_str("quasiquote expected a node")), Some(code) => { match replace_code(code, scope, file_ns, program_code)? { SpanResult::Single(v) => { // println!("replace result: {:?}", v); Ok(v) } - SpanResult::Range(xs) => Err(format!("expected single result from quasiquote, got {:?}", xs)), + SpanResult::Range(xs) => Err(CalcitErr::use_string(format!( + "expected single result from quasiquote, got {:?}", + xs + ))), } } } } -fn replace_code( - c: &Calcit, - scope: &CalcitScope, - file_ns: &str, - program_code: &ProgramCodeData, -) -> Result { +fn replace_code(c: &Calcit, scope: &CalcitScope, file_ns: &str, program_code: &ProgramCodeData) -> Result { if !has_unquote(c) { return Ok(SpanResult::Single(c.to_owned())); } @@ -173,7 +136,7 @@ fn replace_code( let ret = runner::evaluate_expr(expr, scope, file_ns, program_code)?; match ret { Calcit::List(zs) => Ok(SpanResult::Range(zs)), - _ => Err(format!("unknown result from unquote-slice: {}", ret)), + _ => Err(CalcitErr::use_string(format!("unknown result from unquote-slice: {}", ret))), } } (_, _) => { @@ -215,7 +178,7 @@ pub fn macroexpand( scope: &CalcitScope, file_ns: &str, program_code: &ProgramCodeData, -) -> Result { +) -> Result { if expr.len() == 1 { let quoted_code = runner::evaluate_expr(&expr[0], scope, file_ns, program_code)?; @@ -249,7 +212,10 @@ pub fn macroexpand( a => Ok(a), } } else { - Err(format!("macroexpand expected excaclty 1 argument, got: {:?}", expr)) + Err(CalcitErr::use_string(format!( + "macroexpand expected excaclty 1 argument, got: {:?}", + expr + ))) } } @@ -258,7 +224,7 @@ pub fn macroexpand_1( scope: &CalcitScope, file_ns: &str, program_code: &ProgramCodeData, -) -> Result { +) -> Result { if expr.len() == 1 { let quoted_code = runner::evaluate_expr(&expr[0], scope, file_ns, program_code)?; // println!("quoted: {}", quoted_code); @@ -280,7 +246,10 @@ pub fn macroexpand_1( a => Ok(a), } } else { - Err(format!("macroexpand expected excaclty 1 argument, got: {:?}", expr)) + Err(CalcitErr::use_string(format!( + "macroexpand expected excaclty 1 argument, got: {:?}", + expr + ))) } } @@ -289,7 +258,7 @@ pub fn macroexpand_all( scope: &CalcitScope, file_ns: &str, program_code: &ProgramCodeData, -) -> Result { +) -> Result { if expr.len() == 1 { let quoted_code = runner::evaluate_expr(&expr[0], scope, file_ns, program_code)?; @@ -315,8 +284,7 @@ pub fn macroexpand_all( rest_nodes = rest_code; } _ => { - let (resolved, _v) = - runner::preprocess::preprocess_expr(&v, &HashSet::new(), file_ns, program_code, check_warnings)?; + let (resolved, _v) = runner::preprocess::preprocess_expr(&v, &HashSet::new(), file_ns, program_code, check_warnings)?; let warnings = check_warnings.to_owned().into_inner(); if !warnings.is_empty() { for message in &warnings { @@ -331,13 +299,8 @@ pub fn macroexpand_all( } _ => { let check_warnings: &RefCell> = &RefCell::new(vec![]); - let (resolved, _v) = runner::preprocess::preprocess_expr( - "ed_code, - &HashSet::new(), - file_ns, - program_code, - check_warnings, - )?; + let (resolved, _v) = + runner::preprocess::preprocess_expr("ed_code, &HashSet::new(), file_ns, program_code, check_warnings)?; let warnings = check_warnings.to_owned().into_inner(); if !warnings.is_empty() { for message in &warnings { @@ -351,16 +314,14 @@ pub fn macroexpand_all( a => Ok(a), } } else { - Err(format!("macroexpand expected excaclty 1 argument, got: {:?}", expr)) + Err(CalcitErr::use_string(format!( + "macroexpand expected excaclty 1 argument, got: {:?}", + expr + ))) } } -pub fn call_try( - expr: &CalcitItems, - scope: &CalcitScope, - file_ns: &str, - program_code: &ProgramCodeData, -) -> Result { +pub fn call_try(expr: &CalcitItems, scope: &CalcitScope, file_ns: &str, program_code: &ProgramCodeData) -> Result { if expr.len() == 2 { let xs = runner::evaluate_expr(&expr[0], scope, file_ns, program_code); @@ -369,18 +330,18 @@ pub fn call_try( Ok(v) => Ok(v.to_owned()), Err(failure) => { let f = runner::evaluate_expr(&expr[1], scope, file_ns, program_code)?; - let err_data = Calcit::Str(failure.to_owned()); + let err_data = Calcit::Str(failure.msg.to_owned()); match f { Calcit::Fn(_, def_ns, _, def_scope, args, body) => { let values = im::vector![err_data]; runner::run_fn(&values, &def_scope, &args, &body, &def_ns, program_code) } Calcit::Proc(proc) => builtins::handle_proc(&proc, &im::vector![err_data]), - a => Err(format!("try expected a function handler, got: {}", a)), + a => Err(CalcitErr::use_string(format!("try expected a function handler, got: {}", a))), } } } } else { - Err(format!("try expected 2 arguments, got: {:?}", expr)) + Err(CalcitErr::use_string(format!("try expected 2 arguments, got: {:?}", expr))) } } diff --git a/src/cirru/calcit-core.cirru b/src/cirru/calcit-core.cirru index be3a6a3d..8b8f4154 100644 --- a/src/cirru/calcit-core.cirru +++ b/src/cirru/calcit-core.cirru @@ -1586,3 +1586,7 @@ if (string? k) (turn-keyword k) k keywordize-edn v , data + + |print-values $ quote + defn print-values (& args) + println & $ &list:map args pr-str diff --git a/src/codegen/emit_js.rs b/src/codegen/emit_js.rs index 5f2e9622..997ae63b 100644 --- a/src/codegen/emit_js.rs +++ b/src/codegen/emit_js.rs @@ -300,10 +300,7 @@ fn gen_call_code( let cond_code = to_js_code(condition, ns, local_defs, file_imports, keywords, &None)?; let true_code = to_js_code(true_branch, ns, local_defs, file_imports, keywords, &None)?; call_stack::pop_call_stack(); - Ok(format!( - "{}( {} ? {} : {} )", - return_code, cond_code, true_code, false_code - )) + Ok(format!("{}( {} ? {} : {} )", return_code, cond_code, true_code, false_code)) } (_, _) => Err(format!("if expected 2~3 nodes, got: {:?}", body)), }; @@ -637,21 +634,14 @@ fn gen_symbol_code( } // track but compare first, return Err if a different one existed -fn track_ns_import( - sym: String, - import_rule: ImportedTarget, - file_imports: &RefCell, -) -> Result<(), String> { +fn track_ns_import(sym: String, import_rule: ImportedTarget, file_imports: &RefCell) -> Result<(), String> { let mut dict = file_imports.borrow_mut(); match dict.get(&sym) { Some(v) => { if *v == import_rule { Ok(()) } else { - Err(format!( - "conflicted import rule, previous {:?}, now {:?}", - v, import_rule - )) + Err(format!("conflicted import rule, previous {:?}, now {:?}", v, import_rule)) } } None => { @@ -743,15 +733,13 @@ fn gen_let_code( if content.len() == 1 { match &content[0] { Calcit::List(ys) if ys.len() > 2 => match (&ys[0], &ys[1]) { - (Calcit::Syntax(sym, _ns), Calcit::List(zs)) if sym == &CalcitSyntax::CoreLet && zs.len() == 2 => { - match &zs[0] { - Calcit::Symbol(s2, ..) if !scoped_defs.contains(s2) => { - let_def_body = ys.skip(1); - continue; - } - _ => (), + (Calcit::Syntax(sym, _ns), Calcit::List(zs)) if sym == &CalcitSyntax::CoreLet && zs.len() == 2 => match &zs[0] { + Calcit::Symbol(s2, ..) if !scoped_defs.contains(s2) => { + let_def_body = ys.skip(1); + continue; } - } + _ => (), + }, _ => (), }, _ => (), @@ -896,14 +884,7 @@ fn list_to_js_code( for (idx, x) in xs.iter().enumerate() { // result = result & "// " & $x & "\n" if idx == xs.len() - 1 { - let line = to_js_code( - x, - ns, - &local_defs, - file_imports, - keywords, - &Some(return_label.to_owned()), - )?; + let line = to_js_code(x, ns, &local_defs, file_imports, keywords, &Some(return_label.to_owned()))?; result.push_str(&line); result.push('\n'); } else { @@ -1026,14 +1007,7 @@ fn gen_js_func( if !body.is_empty() && uses_recur(&body[body.len() - 1]) { let return_var = js_gensym("return_mark"); - let body = list_to_js_code( - &body, - ns, - local_defs, - &format!("%%{}%% =", return_var), - file_imports, - keywords, - )?; + let body = list_to_js_code(&body, ns, local_defs, &format!("%%{}%% =", return_var), file_imports, keywords)?; let fn_def = snippets::tmpl_tail_recursion( /* name = */ escape_var(name), /* args_code = */ args_code, @@ -1232,11 +1206,7 @@ pub fn emit_js(entry_ns: &str, emit_path: &str) -> Result<(), String> { continue; } if is_preferred_js_proc(&def) { - defs_code.push_str(&format!( - "\nvar {} = $calcit_procs.{};\n", - escape_var(&def), - escape_var(&def) - )); + defs_code.push_str(&format!("\nvar {} = $calcit_procs.{};\n", escape_var(&def), escape_var(&def))); continue; } } @@ -1246,24 +1216,11 @@ pub fn emit_js(entry_ns: &str, emit_path: &str) -> Result<(), String> { match &f { // probably not work here Calcit::Proc(..) => { - defs_code.push_str(&format!( - "\nvar {} = $calcit_procs.{};\n", - escape_var(&def), - escape_var(&def) - )); + defs_code.push_str(&format!("\nvar {} = $calcit_procs.{};\n", escape_var(&def), escape_var(&def))); } Calcit::Fn(name, def_ns, _, _, args, code) => { call_stack::push_call_stack(def_ns, name, StackKind::Codegen, f.to_owned(), &im::vector![]); - defs_code.push_str(&gen_js_func( - &def, - args, - code, - &ns, - true, - &def_names, - &file_imports, - &keywords, - )?); + defs_code.push_str(&gen_js_func(&def, args, code, &ns, true, &def_names, &file_imports, &keywords)?); call_stack::pop_call_stack(); } Calcit::Thunk(code, _) => { @@ -1310,11 +1267,7 @@ pub fn emit_js(entry_ns: &str, emit_path: &str) -> Result<(), String> { import_code.push_str(&format!("\nimport * as {} from {};", escape_ns(&def), import_target)); } else { let import_target = to_js_import_name(&target_ns, false); // TODO js_mode - import_code.push_str(&format!( - "\nimport * as {} from {};", - escape_ns(&target_ns), - import_target - )); + import_code.push_str(&format!("\nimport * as {} from {};", escape_ns(&target_ns), import_target)); } } ImportedTarget::DefaultNs(target_ns) => { @@ -1355,10 +1308,7 @@ pub fn emit_js(entry_ns: &str, emit_path: &str) -> Result<(), String> { let js_file_path = code_emit_path.join(to_js_file_name(&ns, false)); // TODO mjs_mode let wrote_new = write_file_if_changed( &js_file_path, - &format!( - "{}\n{}{}\n\n{}\n{}", - import_code, keywords_code, defs_code, vals_code, direct_code - ), + &format!("{}\n{}{}\n\n{}\n{}", import_code, keywords_code, defs_code, vals_code, direct_code), ); if wrote_new { println!("Emitted js file: {}", js_file_path.to_str().unwrap()); diff --git a/src/lib.rs b/src/lib.rs index 913b479a..8c383e87 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,7 @@ use std::cell::RefCell; use std::fs; use std::path::Path; -pub use primes::{Calcit, CalcitItems}; +pub use primes::{Calcit, CalcitErr, CalcitItems}; pub fn load_core_snapshot() -> Result { // load core libs @@ -28,12 +28,8 @@ pub fn load_core_snapshot() -> Result { snapshot::load_snapshot_data(core_data, "calcit-internal://calcit-core.cirru") } -pub fn run_program( - init_fn: &str, - params: CalcitItems, - program_code: &program::ProgramCodeData, -) -> Result { - let (init_ns, init_def) = util::string::extract_ns_def(init_fn)?; +pub fn run_program(init_fn: &str, params: CalcitItems, program_code: &program::ProgramCodeData) -> Result { + let (init_ns, init_def) = util::string::extract_ns_def(init_fn).map_err(CalcitErr::use_string)?; let check_warnings: &RefCell> = &RefCell::new(vec![]); @@ -42,20 +38,20 @@ pub fn run_program( Ok(_) => (), Err(failure) => { println!("\nfailed preprocessing, {}", failure); - call_stack::display_stack(&failure)?; - return Err(failure); + call_stack::display_stack(&failure.msg).map_err(CalcitErr::use_string)?; + return Err(CalcitErr::use_string(failure.msg)); } } let warnings = check_warnings.to_owned().into_inner(); if !warnings.is_empty() { - for message in &warnings { - println!("{}", message); - } - return Err(format!("Found {} warnings, runner blocked", warnings.len())); + return Err(CalcitErr { + msg: format!("Found {} warnings, runner blocked", warnings.len()), + warnings: warnings.to_owned(), + }); } match program::lookup_evaled_def(&init_ns, &init_def) { - None => Err(format!("entry not initialized: {}/{}", init_ns, init_def)), + None => Err(CalcitErr::use_string(format!("entry not initialized: {}/{}", init_ns, init_def))), Some(entry) => match entry { Calcit::Fn(_, f_ns, _, def_scope, args, body) => { let result = runner::run_fn(¶ms, &def_scope, &args, &body, &f_ns, program_code); @@ -63,12 +59,12 @@ pub fn run_program( Ok(v) => Ok(v), Err(failure) => { println!("\nfailed, {}", failure); - call_stack::display_stack(&failure)?; + call_stack::display_stack(&failure.msg).map_err(CalcitErr::use_string)?; Err(failure) } } } - _ => Err(format!("expected function entry, got: {}", entry)), + _ => Err(CalcitErr::use_string(format!("expected function entry, got: {}", entry))), }, } } diff --git a/src/primes.rs b/src/primes.rs index 2ae72fd8..6a11d145 100644 --- a/src/primes.rs +++ b/src/primes.rs @@ -132,11 +132,7 @@ impl fmt::Display for Calcit { Calcit::Record(name, fields, values) => { f.write_str(&format!("(%{{}} {}", Calcit::Keyword(*name)))?; for idx in 0..fields.len() { - f.write_str(&format!( - " ({} {})", - Calcit::Keyword(fields[idx].to_owned()), - values[idx] - ))?; + f.write_str(&format!(" ({} {})", Calcit::Keyword(fields[idx].to_owned()), values[idx]))?; } f.write_str(")") } @@ -507,3 +503,37 @@ pub fn gen_core_id() -> String { let c = ID_GEN.fetch_add(1, SeqCst); format!("gen_id_{}", c) } + +pub struct CalcitErr { + pub msg: String, + // stack: im::Vector, + pub warnings: Vec, +} + +impl fmt::Display for CalcitErr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(&self.msg)?; + if !self.warnings.is_empty() { + f.write_str("\n")?; + for w in &self.warnings { + writeln!(f, "{}", w)?; + } + } + Ok(()) + } +} + +impl CalcitErr { + pub fn use_str(msg: &str) -> Self { + CalcitErr { + msg: msg.to_owned(), + warnings: vec![], + } + } + pub fn use_string(msg: String) -> Self { + CalcitErr { + msg: msg.to_owned(), + warnings: vec![], + } + } +} diff --git a/src/runner.rs b/src/runner.rs index 0d7b574c..cd81d015 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -4,7 +4,7 @@ use crate::builtins; use crate::builtins::is_proc_name; use crate::call_stack; use crate::call_stack::{push_call_stack, StackKind}; -use crate::primes::{Calcit, CalcitItems, CalcitScope, CalcitSyntax, CrListWrap, SymbolResolved::*, CORE_NS}; +use crate::primes::{Calcit, CalcitErr, CalcitItems, CalcitScope, CalcitSyntax, CrListWrap, SymbolResolved::*, CORE_NS}; use crate::program; pub fn evaluate_expr( @@ -12,7 +12,7 @@ pub fn evaluate_expr( scope: &CalcitScope, file_ns: &str, program_code: &program::ProgramCodeData, -) -> Result { +) -> Result { // println!("eval code: {}", expr.lisp_str()); match expr { @@ -32,7 +32,8 @@ pub fn evaluate_expr( let evaled_v = evaluate_expr(&code, scope, file_ns, program_code)?; // and write back to program state to fix duplicated evalution // still using thunk since js and IR requires bare code - program::write_evaled_def(r_ns, r_def, Calcit::Thunk(code, Some(Box::new(evaled_v.to_owned()))))?; + program::write_evaled_def(r_ns, r_def, Calcit::Thunk(code, Some(Box::new(evaled_v.to_owned())))) + .map_err(CalcitErr::use_string)?; Ok(evaled_v) } _ => Ok(v), @@ -54,7 +55,7 @@ pub fn evaluate_expr( Calcit::Buffer(..) => Ok(expr.to_owned()), Calcit::Recur(_) => unreachable!("recur not expected to be from symbol"), Calcit::List(xs) => match xs.get(0) { - None => Err(format!("cannot evaluate empty expr: {}", expr)), + None => Err(CalcitErr::use_string(format!("cannot evaluate empty expr: {}", expr))), Some(x) => { // println!("eval expr: {}", expr.lisp_str()); // println!("eval expr: {}", x); @@ -125,24 +126,24 @@ pub fn evaluate_expr( None => Ok(Calcit::Nil), } } else { - Err(format!("expected a hashmap, got {}", v)) + Err(CalcitErr::use_string(format!("expected a hashmap, got {}", v))) } } else { - Err(format!( + Err(CalcitErr::use_string(format!( "keyword only takes 1 argument, got: {}", CrListWrap(rest_nodes) - )) + ))) } } - Calcit::Symbol(s, ns, at_def, resolved) => Err(format!( + Calcit::Symbol(s, ns, at_def, resolved) => Err(CalcitErr::use_string(format!( "cannot evaluate symbol directly: {}/{} in {}, {:?}", ns, s, at_def, resolved - )), - a => Err(format!( + ))), + a => Err(CalcitErr::use_string(format!( "cannot be used as operator: {} in {}", a, CrListWrap(xs.to_owned()) - )), + ))), }; if added_stack && ret.is_ok() { @@ -152,9 +153,9 @@ pub fn evaluate_expr( ret } }, - Calcit::Set(_) => Err(String::from("unexpected set for expr")), - Calcit::Map(_) => Err(String::from("unexpected map for expr")), - Calcit::Record(..) => Err(String::from("unexpected record for expr")), + Calcit::Set(_) => Err(CalcitErr::use_str("unexpected set for expr")), + Calcit::Map(_) => Err(CalcitErr::use_str("unexpected map for expr")), + Calcit::Record(..) => Err(CalcitErr::use_str("unexpected record for expr")), Calcit::Proc(_) => Ok(expr.to_owned()), Calcit::Macro(..) => Ok(expr.to_owned()), Calcit::Fn(..) => Ok(expr.to_owned()), @@ -167,18 +168,21 @@ pub fn evaluate_symbol( scope: &CalcitScope, file_ns: &str, program_code: &program::ProgramCodeData, -) -> Result { +) -> Result { match parse_ns_def(sym) { Some((ns_part, def_part)) => match program::lookup_ns_target_in_import(file_ns, &ns_part, program_code) { Some(target_ns) => match eval_symbol_from_program(&def_part, &target_ns, program_code) { Ok(v) => Ok(v), Err(e) => Err(e), }, - None => Err(format!("unknown ns target: {}/{}", ns_part, def_part)), + None => Err(CalcitErr::use_string(format!("unknown ns target: {}/{}", ns_part, def_part))), }, None => { if CalcitSyntax::is_core_syntax(sym) { - return Ok(Calcit::Syntax(CalcitSyntax::from(sym)?, file_ns.to_owned())); + return Ok(Calcit::Syntax( + CalcitSyntax::from(sym).map_err(CalcitErr::use_string)?, + file_ns.to_owned(), + )); } if scope.contains_key(sym) { // although scope is detected first, it would trigger warning during preprocess @@ -197,7 +201,7 @@ pub fn evaluate_symbol( Some(target_ns) => eval_symbol_from_program(sym, &target_ns, program_code), None => { let vars: Vec<&String> = scope.keys().collect(); - Err(format!("unknown symbol `{}` in {:?}", sym, vars)) + Err(CalcitErr::use_string(format!("unknown symbol `{}` in {:?}", sym, vars))) } } } @@ -217,16 +221,16 @@ pub fn parse_ns_def(s: &str) -> Option<(String, String)> { } } -fn eval_symbol_from_program(sym: &str, ns: &str, program_code: &program::ProgramCodeData) -> Result { +fn eval_symbol_from_program(sym: &str, ns: &str, program_code: &program::ProgramCodeData) -> Result { match program::lookup_evaled_def(ns, sym) { Some(v) => Ok(v), None => match program::lookup_def_code(ns, sym, program_code) { Some(code) => { let v = evaluate_expr(&code, &im::HashMap::new(), ns, program_code)?; - program::write_evaled_def(ns, sym, v.to_owned())?; + program::write_evaled_def(ns, sym, v.to_owned()).map_err(CalcitErr::use_string)?; Ok(v) } - None => Err(format!("cannot find code for def: {}/{}", ns, sym)), + None => Err(CalcitErr::use_string(format!("cannot find code for def: {}/{}", ns, sym))), }, } } @@ -238,7 +242,7 @@ pub fn run_fn( body: &CalcitItems, file_ns: &str, program_code: &program::ProgramCodeData, -) -> Result { +) -> Result { let mut current_values = values.to_owned(); loop { let body_scope = bind_args(args, ¤t_values, scope)?; @@ -254,14 +258,14 @@ pub fn run_fn( /// create new scope by wrting new args /// notice that `&` is a mark for spreading, `?` for optional arguments -pub fn bind_args(args: &CalcitItems, values: &CalcitItems, base_scope: &CalcitScope) -> Result { +pub fn bind_args(args: &CalcitItems, values: &CalcitItems, base_scope: &CalcitScope) -> Result { // TODO arguments spreading syntax // if values.len() != args.len() { - // return Err(format!( + // return Err(CalcitErr::use_string(format!( // "arguments length mismatch: {} ... {}", // Calcit::List(values.to_owned()), // Calcit::List(args.to_owned()), - // )); + // ))); // } let mut scope = base_scope.to_owned(); let mut spreading = false; @@ -271,8 +275,8 @@ pub fn bind_args(args: &CalcitItems, values: &CalcitItems, base_scope: &CalcitSc while let Some(a) = collected_args.pop_front() { if spreading { match a { - Calcit::Symbol(s, ..) if s == "&" => return Err(format!("invalid & in args: {:?}", args)), - Calcit::Symbol(s, ..) if s == "?" => return Err(format!("invalid ? in args: {:?}", args)), + Calcit::Symbol(s, ..) if s == "&" => return Err(CalcitErr::use_string(format!("invalid & in args: {:?}", args))), + Calcit::Symbol(s, ..) if s == "?" => return Err(CalcitErr::use_string(format!("invalid ? in args: {:?}", args))), Calcit::Symbol(s, ..) => { let mut chunk: CalcitItems = im::vector![]; while let Some(v) = collected_values.pop_front() { @@ -280,14 +284,14 @@ pub fn bind_args(args: &CalcitItems, values: &CalcitItems, base_scope: &CalcitSc } scope.insert(s, Calcit::List(chunk)); if !collected_args.is_empty() { - return Err(format!( + return Err(CalcitErr::use_string(format!( "extra args `{}` after spreading in `{}`", CrListWrap(collected_args), CrListWrap(args.to_owned()), - )); + ))); } } - b => return Err(format!("invalid argument name: {}", b)), + b => return Err(CalcitErr::use_string(format!("invalid argument name: {}", b))), } } else { match a { @@ -301,27 +305,27 @@ pub fn bind_args(args: &CalcitItems, values: &CalcitItems, base_scope: &CalcitSc if optional { scope.insert(s.to_owned(), Calcit::Nil); } else { - return Err(format!( + return Err(CalcitErr::use_string(format!( "too few values `{}` passed to args `{}`", CrListWrap(values.to_owned()), CrListWrap(args.to_owned()) - )); + ))); } } }, - b => return Err(format!("invalid argument name: {}", b)), + b => return Err(CalcitErr::use_string(format!("invalid argument name: {}", b))), } } } if collected_values.is_empty() { Ok(scope) } else { - Err(format!( + Err(CalcitErr::use_string(format!( "extra args `{}` not handled while passing values `{}` to args `{}`", CrListWrap(collected_values), CrListWrap(values.to_owned()), CrListWrap(args.to_owned()), - )) + ))) } } @@ -330,7 +334,7 @@ pub fn evaluate_lines( scope: &CalcitScope, file_ns: &str, program_code: &program::ProgramCodeData, -) -> Result { +) -> Result { let mut ret: Calcit = Calcit::Nil; for line in lines { match evaluate_expr(line, scope, file_ns, program_code) { @@ -348,7 +352,7 @@ pub fn evaluate_args( scope: &CalcitScope, file_ns: &str, program_code: &program::ProgramCodeData, -) -> Result { +) -> Result { let mut ret: CalcitItems = im::vector![]; let mut spreading = false; for item in items { @@ -356,40 +360,39 @@ pub fn evaluate_args( Calcit::Symbol(s, ..) if s == "&" => { spreading = true; } - _ => match &evaluate_expr(item, scope, file_ns, program_code) { - Ok(v) => { - if spreading { - match v { - Calcit::List(xs) => { - for x in xs { - // extract thunk before calling functions - let y = match x { - Calcit::Thunk(code, v) => match v { - None => evaluate_expr(code, scope, file_ns, program_code)?, - Some(data) => *data.to_owned(), - }, - _ => x.to_owned(), - }; - ret.push_back(y.to_owned()); - } - spreading = false + _ => { + let v = evaluate_expr(item, scope, file_ns, program_code)?; + + if spreading { + match v { + Calcit::List(xs) => { + for x in xs { + // extract thunk before calling functions + let y = match x { + Calcit::Thunk(code, v) => match v { + None => evaluate_expr(&*code, scope, file_ns, program_code)?, + Some(data) => *data.to_owned(), + }, + _ => x.to_owned(), + }; + ret.push_back(y.to_owned()); } - a => return Err(format!("expected list for spreading, got: {}", a)), + spreading = false } - } else { - // extract thunk before calling functions - let y = match v { - Calcit::Thunk(code, value) => match value { - None => evaluate_expr(code, scope, file_ns, program_code)?, - Some(data) => *data.to_owned(), - }, - _ => v.to_owned(), - }; - ret.push_back(y) + a => return Err(CalcitErr::use_string(format!("expected list for spreading, got: {}", a))), } + } else { + // extract thunk before calling functions + let y = match v { + Calcit::Thunk(code, value) => match value { + None => evaluate_expr(&*code, scope, file_ns, program_code)?, + Some(data) => *data.to_owned(), + }, + _ => v.to_owned(), + }; + ret.push_back(y) } - Err(e) => return Err(e.to_owned()), - }, + } } } Ok(ret) diff --git a/src/runner/preprocess.rs b/src/runner/preprocess.rs index d96acc51..4603d91c 100644 --- a/src/runner/preprocess.rs +++ b/src/runner/preprocess.rs @@ -1,7 +1,7 @@ use crate::builtins::{is_js_syntax_procs, is_proc_name}; use crate::call_stack::{pop_call_stack, push_call_stack, StackKind}; use crate::primes; -use crate::primes::{Calcit, CalcitItems, CalcitSyntax, ImportRule, SymbolResolved::*}; +use crate::primes::{Calcit, CalcitErr, CalcitItems, CalcitSyntax, ImportRule, SymbolResolved::*}; use crate::program; use crate::runner; @@ -18,7 +18,7 @@ pub fn preprocess_ns_def( original_sym: &str, import_rule: Option, // returns form and possible value check_warnings: &RefCell>, -) -> Result<(Calcit, Option), String> { +) -> Result<(Calcit, Option), CalcitErr> { // println!("preprocessing def: {}/{}", ns, def); match program::lookup_evaled_def(ns, def) { Some(v) => { @@ -38,12 +38,11 @@ pub fn preprocess_ns_def( match program::lookup_def_code(ns, def, program_code) { Some(code) => { // write a nil value first to prevent dead loop - program::write_evaled_def(ns, def, Calcit::Nil)?; + program::write_evaled_def(ns, def, Calcit::Nil).map_err(CalcitErr::use_string)?; push_call_stack(ns, def, StackKind::Fn, code.to_owned(), &im::vector![]); - let (resolved_code, _resolve_value) = - preprocess_expr(&code, &HashSet::new(), ns, program_code, check_warnings)?; + let (resolved_code, _resolve_value) = preprocess_expr(&code, &HashSet::new(), ns, program_code, check_warnings)?; // println!("\n resolve code to run: {:?}", resolved_code); let v = if is_fn_or_macro(&resolved_code) { match runner::evaluate_expr(&resolved_code, &im::HashMap::new(), ns, program_code) { @@ -54,7 +53,7 @@ pub fn preprocess_ns_def( Calcit::Thunk(Box::new(resolved_code), None) }; // println!("\nwriting value to: {}/{} {:?}", ns, def, v); - program::write_evaled_def(ns, def, v.to_owned())?; + program::write_evaled_def(ns, def, v.to_owned()).map_err(CalcitErr::use_string)?; pop_call_stack(); Ok(( Calcit::Symbol( @@ -79,7 +78,7 @@ pub fn preprocess_ns_def( ), None, )), - None => Err(format!("unknown ns/def in program: {}/{}", ns, def)), + None => Err(CalcitErr::use_string(format!("unknown ns/def in program: {}/{}", ns, def))), } } } @@ -102,7 +101,7 @@ pub fn preprocess_expr( file_ns: &str, program_code: &program::ProgramCodeData, check_warnings: &RefCell>, -) -> Result<(Calcit, Option), String> { +) -> Result<(Calcit, Option), CalcitErr> { // println!("preprocessing @{} {}", file_ns, expr); match expr { Calcit::Symbol(def, def_ns, at_def, _) => match runner::parse_ns_def(def) { @@ -121,32 +120,25 @@ pub fn preprocess_expr( ), None, )), // js code - None => Err(format!("unknown ns target: {}", def)), + None => Err(CalcitErr::use_string(format!("unknown ns target: {}", def))), } } None => { if def == "~" || def == "~@" || def == "&" || def == "?" { Ok(( - Calcit::Symbol( - def.to_owned(), - def_ns.to_owned(), - at_def.to_owned(), - Some(Box::new(ResolvedRaw)), - ), + Calcit::Symbol(def.to_owned(), def_ns.to_owned(), at_def.to_owned(), Some(Box::new(ResolvedRaw))), None, )) } else if scope_defs.contains(def) { Ok(( - Calcit::Symbol( - def.to_owned(), - def_ns.to_owned(), - at_def.to_owned(), - Some(Box::new(ResolvedLocal)), - ), + Calcit::Symbol(def.to_owned(), def_ns.to_owned(), at_def.to_owned(), Some(Box::new(ResolvedLocal))), None, )) } else if CalcitSyntax::is_core_syntax(def) { - Ok((Calcit::Syntax(CalcitSyntax::from(def)?, def_ns.to_owned()), None)) + Ok(( + Calcit::Syntax(CalcitSyntax::from(def).map_err(CalcitErr::use_string)?, def_ns.to_owned()), + None, + )) } else if is_proc_name(def) { Ok((Calcit::Proc(def.to_owned()), None)) } else if program::has_def_code(primes::CORE_NS, def, program_code) { @@ -171,10 +163,7 @@ pub fn preprocess_expr( def.to_owned(), Some(ImportRule::NsDefault(target_ns)), ))); - Ok(( - Calcit::Symbol(def.to_owned(), def_ns.to_owned(), at_def.to_owned(), target), - None, - )) + Ok((Calcit::Symbol(def.to_owned(), def_ns.to_owned(), at_def.to_owned(), target), None)) } else { let mut names: Vec = vec![]; for def in scope_defs { @@ -226,7 +215,7 @@ fn process_list_call( file_ns: &str, program_code: &program::ProgramCodeData, check_warnings: &RefCell>, -) -> Result<(Calcit, Option), String> { +) -> Result<(Calcit, Option), CalcitErr> { let head = &xs[0]; let (head_form, head_evaled) = preprocess_expr(head, scope_defs, file_ns, program_code, check_warnings)?; let args = xs.skip(1); @@ -251,18 +240,14 @@ fn process_list_call( String::from("get"), String::from(primes::CORE_NS), String::from(primes::GENERATED_DEF), - Some(Box::new(ResolvedDef( - String::from(primes::CORE_NS), - String::from("get"), - None - ))) + Some(Box::new(ResolvedDef(String::from(primes::CORE_NS), String::from("get"), None))) ), args[0].to_owned(), head.to_owned() ]); preprocess_expr(&code, scope_defs, file_ns, program_code, check_warnings) } else { - Err(format!("{} expected single argument", head)) + Err(CalcitErr::use_string(format!("{} expected single argument", head))) } } (Calcit::Macro(name, def_ns, _, def_args, body), _) @@ -295,39 +280,15 @@ fn process_list_call( } (Calcit::Syntax(name, name_ns), _) => match name { CalcitSyntax::Quasiquote => Ok(( - preprocess_quasiquote( - &name, - &name_ns, - &args, - scope_defs, - file_ns, - program_code, - check_warnings, - )?, + preprocess_quasiquote(&name, &name_ns, &args, scope_defs, file_ns, program_code, check_warnings)?, None, )), CalcitSyntax::Defn | CalcitSyntax::Defmacro => Ok(( - preprocess_defn( - &name, - &name_ns, - &args, - scope_defs, - file_ns, - program_code, - check_warnings, - )?, + preprocess_defn(&name, &name_ns, &args, scope_defs, file_ns, program_code, check_warnings)?, None, )), CalcitSyntax::CoreLet => Ok(( - preprocess_call_let( - &name, - &name_ns, - &args, - scope_defs, - file_ns, - program_code, - check_warnings, - )?, + preprocess_call_let(&name, &name_ns, &args, scope_defs, file_ns, program_code, check_warnings)?, None, )), CalcitSyntax::If @@ -340,35 +301,18 @@ fn process_list_call( | CalcitSyntax::FoldrShortcut | CalcitSyntax::Sort | CalcitSyntax::Reset => Ok(( - preprocess_each_items( - &name, - &name_ns, - &args, - scope_defs, - file_ns, - program_code, - check_warnings, - )?, - None, - )), - CalcitSyntax::Quote | CalcitSyntax::Eval | CalcitSyntax::HintFn => Ok(( - preprocess_quote(&name, &name_ns, &args, scope_defs, file_ns, program_code)?, + preprocess_each_items(&name, &name_ns, &args, scope_defs, file_ns, program_code, check_warnings)?, None, )), + CalcitSyntax::Quote | CalcitSyntax::Eval | CalcitSyntax::HintFn => { + Ok((preprocess_quote(&name, &name_ns, &args, scope_defs, file_ns, program_code)?, None)) + } CalcitSyntax::Defatom => Ok(( - preprocess_defatom( - &name, - &name_ns, - &args, - scope_defs, - file_ns, - program_code, - check_warnings, - )?, + preprocess_defatom(&name, &name_ns, &args, scope_defs, file_ns, program_code, check_warnings)?, None, )), }, - (Calcit::Thunk(..), _) => Err(format!("does not know how to preprocess a thunk: {}", head)), + (Calcit::Thunk(..), _) => Err(CalcitErr::use_string(format!("does not know how to preprocess a thunk: {}", head))), (_, Some(Calcit::Fn(f_name, _name_ns, _id, _scope, f_args, _f_body))) => { check_fn_args(&f_args, &args, file_ns, &f_name, &def_name, check_warnings); @@ -479,7 +423,7 @@ pub fn preprocess_each_items( file_ns: &str, program_code: &program::ProgramCodeData, check_warnings: &RefCell>, -) -> Result { +) -> Result { let mut xs: CalcitItems = im::vector![Calcit::Syntax(head.to_owned(), head_ns.to_owned())]; for a in args { let (form, _v) = preprocess_expr(a, scope_defs, file_ns, program_code, check_warnings)?; @@ -496,7 +440,7 @@ pub fn preprocess_defn( file_ns: &str, program_code: &program::ProgramCodeData, check_warnings: &RefCell>, -) -> Result { +) -> Result { // println!("defn args: {}", primes::CrListWrap(args.to_owned())); let mut xs: CalcitItems = im::vector![Calcit::Syntax(head.to_owned(), head_ns.to_owned())]; match (args.get(0), args.get(1)) { @@ -525,7 +469,7 @@ pub fn preprocess_defn( body_defs.insert(sym.to_owned()); } } - _ => return Err(format!("expected defn args to be symbols, got: {}", y)), + _ => return Err(CalcitErr::use_string(format!("expected defn args to be symbols, got: {}", y))), } } xs.push_back(Calcit::List(zs)); @@ -538,20 +482,17 @@ pub fn preprocess_defn( } Ok(Calcit::List(xs)) } - (Some(a), Some(b)) => Err(format!("defn/defmacro expected name and args: {} {}", a, b)), - (a, b) => Err(format!("defn or defmacro expected name and args, got {:?} {:?}", a, b,)), + (Some(a), Some(b)) => Err(CalcitErr::use_string(format!("defn/defmacro expected name and args: {} {}", a, b))), + (a, b) => Err(CalcitErr::use_string(format!( + "defn or defmacro expected name and args, got {:?} {:?}", + a, b, + ))), } } // warn if this symbol is used -fn check_symbol( - sym: &str, - program_code: &program::ProgramCodeData, - args: &CalcitItems, - check_warnings: &RefCell>, -) { - if is_proc_name(sym) || CalcitSyntax::is_core_syntax(sym) || program::has_def_code(primes::CORE_NS, sym, program_code) - { +fn check_symbol(sym: &str, program_code: &program::ProgramCodeData, args: &CalcitItems, check_warnings: &RefCell>) { + if is_proc_name(sym) || CalcitSyntax::is_core_syntax(sym) || program::has_def_code(primes::CORE_NS, sym, program_code) { let mut warnings = check_warnings.borrow_mut(); warnings.push(format!( "[Warn] local binding `{}` shadowed `calcit.core/{}`, with {}", @@ -570,7 +511,7 @@ pub fn preprocess_call_let( file_ns: &str, program_code: &program::ProgramCodeData, check_warnings: &RefCell>, -) -> Result { +) -> Result { let mut xs: CalcitItems = im::vector![Calcit::Syntax(head.to_owned(), head_ns.to_owned())]; let mut body_defs: HashSet = scope_defs.to_owned(); let binding = match args.get(0) { @@ -582,11 +523,11 @@ pub fn preprocess_call_let( let (form, _v) = preprocess_expr(a, &body_defs, file_ns, program_code, check_warnings)?; Calcit::List(im::vector![ys[0].to_owned(), form]) } - (a, b) => return Err(format!("invalid pair for &let binding: {} {}", a, b)), + (a, b) => return Err(CalcitErr::use_string(format!("invalid pair for &let binding: {} {}", a, b))), }, - Some(Calcit::List(ys)) => return Err(format!("expected binding of a pair, got {:?}", ys)), - Some(a) => return Err(format!("expected binding of a pair, got {}", a)), - None => return Err(String::from("expected binding of a pair, got nothing")), + Some(Calcit::List(ys)) => return Err(CalcitErr::use_string(format!("expected binding of a pair, got {:?}", ys))), + Some(a) => return Err(CalcitErr::use_string(format!("expected binding of a pair, got {}", a))), + None => return Err(CalcitErr::use_str("expected binding of a pair, got nothing")), }; xs.push_back(binding); for (idx, a) in args.iter().enumerate() { @@ -605,7 +546,7 @@ pub fn preprocess_quote( _scope_defs: &HashSet, _file_ns: &str, _program_code: &program::ProgramCodeData, -) -> Result { +) -> Result { let mut xs: CalcitItems = im::vector![Calcit::Syntax(head.to_owned(), head_ns.to_owned())]; for a in args { xs.push_back(a.to_owned()); @@ -621,7 +562,7 @@ pub fn preprocess_defatom( file_ns: &str, program_code: &program::ProgramCodeData, check_warnings: &RefCell>, -) -> Result { +) -> Result { let mut xs: CalcitItems = im::vector![Calcit::Syntax(head.to_owned(), head_ns.to_owned())]; for a in args { // TODO @@ -640,7 +581,7 @@ pub fn preprocess_quasiquote( file_ns: &str, program_code: &program::ProgramCodeData, check_warnings: &RefCell>, -) -> Result { +) -> Result { let mut xs: CalcitItems = im::vector![Calcit::Syntax(head.to_owned(), head_ns.to_owned())]; for a in args { xs.push_back(preprocess_quasiquote_internal( @@ -660,7 +601,7 @@ pub fn preprocess_quasiquote_internal( file_ns: &str, program_code: &program::ProgramCodeData, check_warnings: &RefCell>, -) -> Result { +) -> Result { match x { Calcit::List(ys) if ys.is_empty() => Ok(x.to_owned()), Calcit::List(ys) => match &ys[0] { @@ -675,9 +616,7 @@ pub fn preprocess_quasiquote_internal( _ => { let mut xs: CalcitItems = im::vector![]; for y in ys { - xs.push_back( - preprocess_quasiquote_internal(y, scope_defs, file_ns, program_code, check_warnings)?.to_owned(), - ); + xs.push_back(preprocess_quasiquote_internal(y, scope_defs, file_ns, program_code, check_warnings)?.to_owned()); } Ok(Calcit::List(xs)) } diff --git a/ts-src/calcit.procs.ts b/ts-src/calcit.procs.ts index 27046df3..1220a090 100644 --- a/ts-src/calcit.procs.ts +++ b/ts-src/calcit.procs.ts @@ -1,5 +1,5 @@ // CALCIT VERSION -export const calcit_version = "0.5.0-a5"; +export const calcit_version = "0.5.0-a6"; import { overwriteComparator, initTernaryTreeMap } from "@calcit/ternary-tree"; import { parse, ICirruNode } from "@cirru/parser.ts";