From d86bd7f7ae734916a54b39bd28d0dcf54b28f943 Mon Sep 17 00:00:00 2001 From: teo3300 Date: Mon, 24 Jun 2024 00:42:49 +0900 Subject: [PATCH] EPrintlns and libs - Moving all repl prints to stderr - Adding small functions to module string --- core/core.mal | 10 ++++++++-- libs/string.mal | 8 ++++++++ src/core.rs | 2 +- src/eval.rs | 2 +- src/main.rs | 7 +++++-- src/mal_tests/mod.rs | 2 ++ src/parse_tools.rs | 7 +++++-- src/reader.rs | 6 ++++-- src/types.rs | 4 ++++ 9 files changed, 38 insertions(+), 10 deletions(-) diff --git a/core/core.mal b/core/core.mal index 530213d..23c699e 100644 --- a/core/core.mal +++ b/core/core.mal @@ -71,6 +71,10 @@ "open a mal file and evaluate its content" (eval (read-string (str "(do " (slurp f) "\nnil)"))))) +(def! module (fn* [f] + "load a file from the library path" + (load-file (str MAL_HOME "/libs/" f ".mal")))) + (def! conf-reload (fn* [] "reload mal config file" (load-file (str MAL_HOME "/" "config.mal")))) @@ -139,8 +143,8 @@ (def! BANNER (str "; rust-mal: a toy lisp interpreter written in rust\n" - "; $ mal [filename ...] : load specified modules at start\n" - "; (load-file ) : load specified module while mal is running\n" + "; $ mal [filename ...] : load specified files at start\n" + "; (load-file ) : load specified file while mal is running\n" "; (find [pattern...]) : list symbols matching all patterns\n" "; (help ) : print information about a symbol\n" ";\n" @@ -186,3 +190,5 @@ c (collect-r (f c (car l)) (cdr l))))) (collect-r i l))) + +(conf-reload) diff --git a/libs/string.mal b/libs/string.mal index 0430629..64af407 100644 --- a/libs/string.mal +++ b/libs/string.mal @@ -1,12 +1,18 @@ (def! char (fn* [l] (car (boom l)))) +(def! #n (char "\n")) +(def! #s (char " ")) +(def! #t (char "\t")) + (def! char? (fn* [a] (= (type a) :char))) (def! string? (fn* [a] (= (type a) :string))) +(def! strlen (fn* [s] (count (boom s)))) + (def! strc (fn* [l] (def! strc-r (fn* [l s] (if (empty? l) @@ -38,3 +44,5 @@ (def! chsub (fn* [s c1 c2] (strc (map-if (fn* [x] (= x c1)) (fn* [x] c2) (boom s))))) + + diff --git a/src/core.rs b/src/core.rs index 886cc52..1026106 100644 --- a/src/core.rs +++ b/src/core.rs @@ -76,7 +76,7 @@ pub fn ns_init() -> Env { "car" => Fun(|a| mal_car(car(a)?), "Returns the first element of the list, NIL if its empty"), "cdr" => Fun(|a| mal_cdr(car(a)?), "Returns all the list but the first element"), // A tribute to PHP's explode (PHP, a language I never used) - "boom" => Fun(mal_boom, "Split a string into a list of string\n; BE CAREFUL WHEN USING"), + "boom" => Fun(mal_boom, "Split a string into a list of characters\n; BE CAREFUL WHEN USING"), "read-string" => Fun(|a| read_str(Reader::new().push(car(a)?.if_string()?)).map_err(MalErr::severe), "Tokenize and read the first argument"), "slurp" => Fun(|a| Ok(Str(read_file(car(a)?.if_string()?)?)), "Read a file and return the content as a string"), "atom" => Fun(|a| Ok(Atom(Rc::new(RefCell::new(car(a).unwrap_or_default().clone())))), "Return an atom pointing to the given arg"), diff --git a/src/eval.rs b/src/eval.rs index b1feba5..0780f16 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -129,7 +129,7 @@ pub fn help_form(list: &[MalType], env: Env) -> MalRet { let (sym, _) = car_cdr(list)?; let sym_str = sym.if_symbol()?; match eval(sym, env.clone())? { - M::Fun(_, desc) => println!("{}\t[builtin]: {}\n", sym_str, desc), + M::Fun(_, desc) => eprintln!("{}\t[builtin]: {}\n", sym_str, desc), M::MalFun { params, ast, .. } => print_malfun(sym_str, params, ast), _ => eprintln!("{}\t[symbol]: {}\n", sym_str, prt(&env_get(&env, sym_str)?)), } diff --git a/src/main.rs b/src/main.rs index 93cce8b..ac7ac9a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,12 +24,15 @@ fn main() { load_home_file("core.mal", &reply_env, true); // Load config files ($MAL_HOME/config.mal, or default $HOME/.config/mal/config.mal) // [warn: false] since this file is optional - load_home_file("config.mal", &reply_env, false); + // replaced by (ok? '(reload-config)) at the end of core.mal + // - I used this to overwrite BANNER to prevent it from displaying + // based on conf + //load_home_file("config.mal", &reply_env, false); // load all files passed as arguments args().collect::>()[1..].iter().for_each(|f| { if let Err(e) = load_file(f, &reply_env) { - println!("{}", e.message()) + eprintln!("{}", e.message()) } }); diff --git a/src/mal_tests/mod.rs b/src/mal_tests/mod.rs index a9a04bc..7892638 100644 --- a/src/mal_tests/mod.rs +++ b/src/mal_tests/mod.rs @@ -15,6 +15,8 @@ mod functional { )); }}; } + // TODO: modify to accept more parameters for test/libraries + // TODO: text 'boom' from within rust #[test] fn assert() { diff --git a/src/parse_tools.rs b/src/parse_tools.rs index ea0cc78..c50841a 100644 --- a/src/parse_tools.rs +++ b/src/parse_tools.rs @@ -109,16 +109,19 @@ pub fn interactive(env: Env) { // Perform rep on whole available input match rep(&parser, &env) { - Ok(output) => output.iter().for_each(|el| println!("; [{}]> {}", num, el)), + Ok(output) => output.iter().for_each(|el| { + eprintln!("; [{}]> {}", num, el); + num += 1; + }), Err(error) => { if error.is_recoverable() { // && line != "\n" { continue; } eprintln!("; [{}]> Error @ {}", num, error.message()); + num += 1 } } - num += 1; break; } Err(ReadlineError::Interrupted) => { diff --git a/src/reader.rs b/src/reader.rs index c19bfd7..fb99b3a 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -98,14 +98,16 @@ impl Reader { tk => { if Regex::new(r"^-?[0-9]+$").unwrap().is_match(tk) { return Ok(Int(tk.parse::().unwrap())); - } else if tk.starts_with('\"') { + } + if tk.starts_with('\"') { if tk.len() > 1 && tk.ends_with('\"') { return Ok(Str(unescape_str(tk).into())); } return Err(MalErr::unrecoverable( "End of line reached without closing string", )); - } else if tk.starts_with(':') { + } + if tk.starts_with(':') { return Ok(Key(format!("ʞ{}", tk).into())); } Ok(Sym(tk.into())) diff --git a/src/types.rs b/src/types.rs index 26022e4..98818c5 100644 --- a/src/types.rs +++ b/src/types.rs @@ -220,6 +220,8 @@ pub fn escape_str(s: &str) -> String { String::from(s) .replace('\\', "\\\\") .replace('\n', "\\n") + .replace('\u{000D}', "\\r") + .replace('\t', "\\t") .replace('\"', "\\\"") ) } @@ -228,6 +230,8 @@ pub fn unescape_str(s: &str) -> String { String::from(&s[1..s.len() - 1]) .replace("\\\\", "\\") .replace("\\n", "\n") + .replace("\\r", "\r") + .replace("\\t", "\t") .replace("\\\"", "\"") }