Added the env and evaluation for addition and subtraction functions
This commit is contained in:
parent
7f7aae2f63
commit
ba5b02074d
4 changed files with 101 additions and 26 deletions
30
src/env.rs
Normal file
30
src/env.rs
Normal 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
8
src/macros.rs
Normal 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!")
|
||||||
|
};
|
||||||
|
}
|
77
src/main.rs
77
src/main.rs
|
@ -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()),
|
||||||
}
|
}
|
||||||
|
|
12
src/types.rs
12
src/types.rs
|
@ -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);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue