From 9b252d9a6a932d80acfeffc873167f4e8cef733d Mon Sep 17 00:00:00 2001 From: Chris Cochrun Date: Wed, 6 Nov 2024 10:45:33 -0600 Subject: [PATCH] starting to add an env so symbols can be found and functions run --- src/main.rs | 80 ++++++++++++++++++++++++++++++++------------------ src/printer.rs | 2 +- src/types.rs | 22 ++++++++++---- 3 files changed, 69 insertions(+), 35 deletions(-) diff --git a/src/main.rs b/src/main.rs index d770e83..269ffb7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,13 @@ -use color_eyre::Result; +use std::collections::HashMap; + +use color_eyre::{ + eyre::{eyre, ContextCompat}, + Result, +}; use printer::print; use reader::read; use regex::Regex; -use rustyline::{config::Configurer, error::ReadlineError}; +use rustyline::{config::Configurer, error::ReadlineError, Editor}; pub mod printer; pub mod reader; @@ -10,15 +15,32 @@ pub mod types; use types::*; fn main() -> Result<()> { - let mut rl = rustyline::DefaultEditor::new()?; + 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 env = Environment::default(); + let mut env = Environment::default(); + env.symbols.insert( + Symbol::from("+"), + Value::func(|args| { + let total = args + .iter() + .map(|a| match a { + Value::Number(a) => Ok(*a), + _ => Err(eyre!("Should be a number")), + }) + .sum(); + total + }), + ); loop { let entry = rl.readline(">> "); match entry { Ok(line) => { rl.add_history_entry(line.as_str())?; - eval(line.as_str(), env.clone())?; + read_eval_print(line.as_str(), &env)?; } Err(ReadlineError::Interrupted) => { println!("CTRL-C"); @@ -39,32 +61,34 @@ fn main() -> Result<()> { #[derive(Default, Debug, Clone)] pub struct Environment { - symbols: Vec, - functions: Vec, - keywords: Vec, + symbols: HashMap, + outer: Box, } -fn read_eval_print(str: &str) -> Result<()> { - // print(eval(read(str))); +fn read_eval_print(str: &str, env: &Environment) -> Result<()> { + print(&eval(&read(str), env).unwrap()); Ok(()) } -fn eval(expr: &str, env: Environment) -> Result<()> { - let ast = read(expr); - let expr = print(&ast); - // let regex = Regex::new(r"^\(([[:ascii:]] .*)\)$").unwrap(); - // let exp = regex.captures_iter(&expr.expr); - // for expr in exp { - // // let regex = Regex::new(r#"^(\w)$"#).unwrap(); - // // let mut atom = regex.captures_iter(atom?.get(0).unwrap().as_str()); - // // for atom in atom { - // // } - // for atom in expr.iter() { - // if let Some(atom) = atom { - // println!("{:?}", atom); - // }; - // } - // } - println!("{}", expr); - Ok(()) +fn eval(expr: &Value, env: &Environment) -> Result { + match expr { + Value::Symbol(s) => { + if let Some(symbol) = env.symbols.get(&s) { + Ok(symbol.clone()) + } else { + Err(eyre!("No symbol here")) + } + } + Value::List(list) => { + let mut args = vec![]; + let func = &list[0]; + for value in 1..list.len() { + if let Ok(return_value) = eval(&list[value], env) { + args.push(return_value) + } + } + func.apply(args) + } + value => Ok(value.to_owned()), + } } diff --git a/src/printer.rs b/src/printer.rs index b5d8cff..ccec9f5 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -23,7 +23,6 @@ pub fn print(value: &Value) -> String { } Value::Number(n) => n.to_string(), Value::Nil => "nil".to_string(), - Value::Function => "fn".to_string(), Value::True => "t".to_string(), Value::Symbol(s) => s.0.clone(), Value::Keyword(k) => { @@ -31,6 +30,7 @@ pub fn print(value: &Value) -> String { string.insert_str(0, ":"); string } + _ => "fn".to_string(), } } diff --git a/src/types.rs b/src/types.rs index 00f3029..202be28 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,4 +1,5 @@ -use std::num::ParseIntError; +use color_eyre::{eyre::eyre, Result}; +use std::{num::ParseIntError, rc::Rc}; #[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct Expression { @@ -15,6 +16,8 @@ impl From<&str> for Expression { } } +pub type LispArgs = Vec; + #[derive(Default, Debug, Clone, Eq, PartialEq, PartialOrd, Ord)] pub enum Value { List(Vec), @@ -22,7 +25,7 @@ pub enum Value { Number(i64), #[default] Nil, - Function, + Function(fn(LispArgs) -> Result, Rc), True, Symbol(Symbol), Keyword(Keyword), @@ -35,6 +38,17 @@ impl Value { _ => Self::Nil, } } + + pub fn func(f: fn(LispArgs) -> Result) -> Self { + Self::Function(f, Rc::new(Self::Nil)) + } + + pub fn apply(&self, args: LispArgs) -> Result { + match self { + Self::Function(f, _) => f(args), + _ => Err(eyre!("No function here, shouldn't call apply")), + } + } } impl From> for Value { @@ -54,10 +68,6 @@ impl From<&str> for Value { Value::True } else if s.starts_with(r#"""#) { Value::String(s.replace('"', "")) - } else if s == "fn".to_owned() { - Value::Function - } else if s == "defun".to_owned() { - Value::Function } else if s == "nil".to_owned() { Value::Nil } else {