Added the env and evaluation for addition and subtraction functions

This commit is contained in:
Chris Cochrun 2024-11-06 13:24:25 -06:00
parent 7f7aae2f63
commit ba5b02074d
4 changed files with 101 additions and 26 deletions

30
src/env.rs Normal file
View file

@ -0,0 +1,30 @@
use std::collections::HashMap;
use crate::{Symbol, Value};
#[derive(Default, Debug, Clone)]
pub struct Environment {
symbols: HashMap<Symbol, Value>,
outer: Box<Option<Environment>>,
}
impl Environment {
pub fn new() -> Self {
Self {
outer: Box::new(None),
..Default::default()
}
}
pub fn insert_symbol(&mut self, symbol: Symbol, value: Value) {
self.symbols.insert(symbol, value);
}
pub fn get_symbol(&self, symbol: &Symbol) -> &Value {
if let Some(value) = self.symbols.get(symbol) {
value
} else {
&Value::Nil
}
}
}

8
src/macros.rs Normal file
View file

@ -0,0 +1,8 @@
macro_rules! insert_symbol {
// Takes the env and a symbol in &str form, then it takes a variable list,
// of arg types and then a fn to run over them.
(&env:expr, &symbol:expr) => {
// The macro will expand into the contents of this block.
println!("Hello!")
};
}

View file

@ -4,11 +4,14 @@ use color_eyre::{
eyre::{eyre, ContextCompat}, eyre::{eyre, ContextCompat},
Result, Result,
}; };
use env::Environment;
use printer::print; use printer::print;
use reader::read; use reader::read;
use regex::Regex; use regex::Regex;
use rustyline::{config::Configurer, error::ReadlineError, Editor}; use rustyline::{config::Configurer, error::ReadlineError, Editor};
pub mod env;
pub mod macros;
pub mod printer; pub mod printer;
pub mod reader; pub mod reader;
pub mod types; pub mod types;
@ -19,28 +22,55 @@ fn main() -> Result<()> {
if rl.load_history(".mal-history").is_err() { if rl.load_history(".mal-history").is_err() {
eprintln!("No previous history."); eprintln!("No previous history.");
} }
rl.set_edit_mode(rustyline::EditMode::Vi); rl.set_edit_mode(rustyline::EditMode::Vi);
let mut env = Environment::default();
env.symbols.insert( let mut env = Environment::new();
env.insert_symbol(
Symbol::from("+"), Symbol::from("+"),
Value::func(|args| { Value::func(|args| {
let total = args let nums: Vec<i64> = args
.iter() .iter()
.map(|a| match a { .map(|a| match a {
Value::Number(a) => Ok(*a), Value::Number(a) => Ok(*a),
_ => Err(eyre!("Should be a number")), _ => Err(eyre!("Should be a number")),
}) })
.sum(); .flatten()
total .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<i64> = 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 { loop {
let entry = rl.readline(">> "); let entry = rl.readline(">> ");
match entry { match entry {
Ok(line) => { Ok(line) => {
rl.add_history_entry(line.as_str())?; rl.add_history_entry(line.as_str())?;
read_eval_print(line.as_str(), &env)?; match read_eval_print(line.as_str(), &env) {
Ok(s) => println!("{s}"),
Err(e) => eprintln!("{e}"),
}
} }
Err(ReadlineError::Interrupted) => { Err(ReadlineError::Interrupted) => {
println!("CTRL-C"); println!("CTRL-C");
@ -59,35 +89,30 @@ fn main() -> Result<()> {
Ok(()) Ok(())
} }
#[derive(Default, Debug, Clone)] fn read_eval_print(str: &str, env: &Environment) -> Result<String> {
pub struct Environment { Ok(print(&eval(&read(str), env)?))
symbols: HashMap<Symbol, Value>,
outer: Box<Environment>,
}
fn read_eval_print(str: &str, env: &Environment) -> Result<()> {
print(&eval(&read(str), env).unwrap());
Ok(())
} }
fn eval(expr: &Value, env: &Environment) -> Result<Value> { fn eval(expr: &Value, env: &Environment) -> Result<Value> {
match expr { match expr {
Value::Symbol(s) => { Value::Symbol(s) => {
if let Some(symbol) = env.symbols.get(&s) { let symbol = env.get_symbol(s).to_owned();
Ok(symbol.clone()) Ok(symbol)
} else {
Err(eyre!("No symbol here"))
}
} }
Value::List(list) => { Value::List(list) => {
let mut args = vec![]; let mut args = vec![];
let func = &list[0]; let first = &list[0];
for value in 1..list.len() { if let Value::List(_) = first {
if let Ok(return_value) = eval(&list[value], env) { eval(first, env)
args.push(return_value) } 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)
} }
func.apply(args)
} }
value => Ok(value.to_owned()), value => Ok(value.to_owned()),
} }

View file

@ -88,6 +88,18 @@ impl From<&String> for Value {
} }
} }
impl From<i64> for Value {
fn from(num: i64) -> Self {
Self::Number(num)
}
}
impl From<&i64> for Value {
fn from(num: &i64) -> Self {
Self::Number(*num)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Symbol(pub String); pub struct Symbol(pub String);