From 37af7ff0ef5925635774451d709e76825b0645a2 Mon Sep 17 00:00:00 2001 From: Chris Cochrun Date: Tue, 19 Nov 2024 06:17:07 -0600 Subject: [PATCH] making this work as a library --- Cargo.toml | 4 ++ src/env.rs | 6 ++- src/lib.rs | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 13 +++++ 4 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 930ad9c..ca5cfed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,10 @@ name = "crisp" version = "0.1.0" edition = "2021" +[lib] +crate-type = ["staticlib"] +path = "src/lib.rs" + [dependencies] color-eyre = "0.6.3" lazy_static = "1.5.0" diff --git a/src/env.rs b/src/env.rs index 46ec888..ef2f0e9 100644 --- a/src/env.rs +++ b/src/env.rs @@ -24,7 +24,11 @@ impl Environment { if let Some(value) = self.symbols.get(symbol) { value } else { - &Value::Nil + if let Some(env) = &*self.outer { + env.get_symbol(symbol) + } else { + &Value::Nil + } } } } diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..64ae787 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,138 @@ +use std::collections::HashMap; + +use color_eyre::{ + eyre::{eyre, ContextCompat}, + Result, +}; +use env::Environment; +use printer::print; +use reader::read; +use regex::Regex; +use rustyline::{config::Configurer, error::ReadlineError, Editor}; + +pub mod env; +pub mod macros; +pub mod printer; +pub mod reader; +pub mod types; +use types::*; + +pub fn main() -> Result<()> { + let mut rl = Editor::<(), rustyline::history::DefaultHistory>::new().unwrap(); + if rl.load_history(".mal-history").is_err() { + eprintln!("No previous history."); + } + rl.set_edit_mode(rustyline::EditMode::Vi); + + let mut env = Environment::new(); + env.insert_symbol( + Symbol::from("+"), + Value::func(|args| { + let nums: Vec = args + .iter() + .map(|a| match a { + Value::Number(a) => Ok(*a), + _ => Err(eyre!("Should be a number")), + }) + .flatten() + .collect(); + let total = nums + .into_iter() + .reduce(|acc, e| acc + e) + .expect("shouldn't fail"); + Ok(Value::from(total)) + }), + ); + env.insert_symbol( + Symbol::from("-"), + Value::func(|args| { + let nums: Vec = args + .iter() + .map(|a| match a { + Value::Number(a) => Ok(*a), + _ => Err(eyre!("Should be a number")), + }) + .flatten() + .collect(); + let total = nums + .into_iter() + .reduce(|acc, n| acc - n) + .expect("shouldn't fail"); + Ok(Value::from(total)) + }), + ); + + loop { + let entry = rl.readline(">> "); + match entry { + Ok(line) => { + rl.add_history_entry(line.as_str())?; + match read_eval_print(line.as_str(), &mut env) { + Ok(s) => println!("{s}"), + Err(e) => eprintln!("{e}"), + } + } + Err(ReadlineError::Interrupted) => { + println!("CTRL-C"); + break; + } + Err(ReadlineError::Eof) => { + println!("CTRL-D"); + break; + } + Err(err) => { + println!("Error: {:?}", err); + break; + } + } + } + Ok(()) +} + +pub fn read_eval_print(str: &str, env: &mut Environment) -> Result { + Ok(print(&eval(&read(str), env)?)) +} + +pub fn eval(expr: &Value, env: &mut Environment) -> Result { + match expr { + Value::Symbol(s) => { + let symbol = env.get_symbol(s).to_owned(); + Ok(symbol) + } + Value::List(list) => { + let mut args = vec![]; + let first = &list[0]; + if let Value::List(_) = first { + eval(first, env) + } else if let Value::Symbol(s) = first { + if s == &Symbol("defvar".to_string()) { + let second = &list[1]; + if let Value::Symbol(s) = second { + Ok(Value::Symbol(s.clone())) + } else { + todo!() + } + } else if s == &Symbol("let*".to_string()) { + todo!() + } else { + let first = eval(first, env)?; + for value in list.iter().skip(1) { + if let Ok(return_value) = eval(value, env) { + args.push(return_value) + } + } + first.apply(args) + } + } else { + let first = eval(first, env)?; + for value in list.iter().skip(1) { + if let Ok(return_value) = eval(value, env) { + args.push(return_value) + } + } + first.apply(args) + } + } + value => Ok(value.to_owned()), + } +} diff --git a/src/main.rs b/src/main.rs index e8a0469..e1e3f80 100644 --- a/src/main.rs +++ b/src/main.rs @@ -104,6 +104,19 @@ fn eval(expr: &Value, env: &Environment) -> Result { let first = &list[0]; if let Value::List(_) = first { eval(first, env) + } else if let Value::Symbol(s) = first { + if s == &Symbol("defvar".to_string()) { + let second = &list[1]; + if let Value::Symbol(s) = second { + Ok(Value::Symbol(s.clone())) + } else { + todo!() + } + } else if s == &Symbol("let*".to_string()) { + todo!() + } else { + todo!() + } } else { let first = eval(first, env)?; for value in list.iter().skip(1) {