summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lib/eval/arith.rs83
-rw-r--r--src/lib/eval/mod.rs62
-rw-r--r--src/lib/mod.rs6
-rw-r--r--src/lib/parse.rs12
-rw-r--r--src/lib/sexpr.rs42
-rw-r--r--src/lib/types.rs43
-rw-r--r--src/main.rs7
7 files changed, 158 insertions, 97 deletions
diff --git a/src/lib/eval/arith.rs b/src/lib/eval/arith.rs
index fae69de..fe3a06b 100644
--- a/src/lib/eval/arith.rs
+++ b/src/lib/eval/arith.rs
@@ -1,34 +1,67 @@
-use std::ops::Add;
+use std::ops::{Add, Sub, Mul, Div};
use super::super::types::Type;
-use super::super::types::Type::*;
use super::super::types::Number;
+fn apply_arithmetic(
+ func_i: fn(isize, isize) -> isize,
+ func_f: fn(f32, f32) -> f32,
+ operand_a: &Type,
+ operand_b: &Type) -> Result<Type, String> {
+
+ match (operand_a, operand_b) {
+ (Type::Bool(_), _) | (_, Type::Bool(_)) |
+ (Type::Str(_), _) | (_, Type::Str(_)) |
+ (Type::Operator(_), _) | (_, Type::Operator(_)) => {
+ Err("Incompatible types".to_string())
+ },
+
+ (Type::Number(Number::Int(i)), Type::Number(Number::Float(f))) |
+ (Type::Number(Number::Float(f)), Type::Number(Number::Int(i))) => {
+ Ok(Type::Number(Number::Float(func_f(*f, *i as f32))))
+ },
+
+ (Type::Number(Number::Int(a)), Type::Number(Number::Int(b))) => {
+ Ok(Type::Number(Number::Int(func_i(*a, *b))))
+ },
+
+ (Type::Number(Number::Float(a)), Type::Number(Number::Float(b))) => {
+ Ok(Type::Number(Number::Float(func_f(*a, *b))))
+ },
+
+ (Type::Symbol(_), Type::Number(_)) |
+ (Type::Number(_), Type::Symbol(_)) |
+ (Type::Symbol(_), Type::Symbol(_)) => Err("Not yet implemented".to_string())
+ }
+}
+
impl Add for Type {
type Output = Result<Type, String>;
fn add(self, other: Type) -> Result<Type, String> {
- match (self, other) {
- (Bool(_), _) | (_, Bool(_)) |
- (Str(_), _) | (_, Str(_)) |
- (Operator(_), _) | (_, Operator(_)) => {
- Err("Cannot add these types".to_string())
- },
- (Number(Number::Int(i)), Number(Number::Float(f))) |
- (Number(Number::Float(f)), Number(Number::Int(i))) => {
- Ok(Number(Number::Float(f + i as f32)))
- },
-
- (Number(Number::Int(a)), Number(Number::Int(b))) => {
- Ok(Number(Number::Int(a + b)))
- },
-
- (Number(Number::Float(a)), Number(Number::Float(b))) => {
- Ok(Number(Number::Float(a + b)))
- },
-
- (Symbol(_), Number(_)) |
- (Number(_), Symbol(_)) |
- (Symbol(_), Symbol(_)) => Err("Not yet implemented".to_string())
- }
+ apply_arithmetic(|a, b| a + b, |a, b| a + b, &self, &other)
+ }
+}
+
+impl Sub for Type {
+ type Output = Result<Type, String>;
+
+ fn sub(self, other: Type) -> Result<Type, String> {
+ apply_arithmetic(|a, b| a - b, |a, b| a - b, &self, &other)
+ }
+}
+
+impl Mul for Type {
+ type Output = Result<Type, String>;
+
+ fn mul(self, other: Type) -> Result<Type, String> {
+ apply_arithmetic(|a, b| a * b, |a, b| a * b, &self, &other)
+ }
+}
+
+impl Div for Type {
+ type Output = Result<Type, String>;
+
+ fn div(self, other: Type) -> Result<Type, String> {
+ apply_arithmetic(|a, b| a / b, |a, b| a / b, &self, &other)
}
}
diff --git a/src/lib/eval/mod.rs b/src/lib/eval/mod.rs
index b582397..adee0e5 100644
--- a/src/lib/eval/mod.rs
+++ b/src/lib/eval/mod.rs
@@ -1,54 +1,84 @@
-use std::collections::HashMap;
use super::types::Op;
use super::types::Op::*;
-use super::types::SEXP;
-use super::types::SEXP::*;
-use super::types::Type::*;
+use super::sexpr::SExpr;
+use super::sexpr::SExpr::*;
+use super::types::Type;
use super::types::Number;
+use super::environment::Environment;
pub mod arith;
-pub type Env = HashMap<String, SEXP>;
-
-pub fn eval(expr: &SEXP, env: &mut Env) -> Result<SEXP, String> {
+pub fn eval(expr: &SExpr, env: &mut Environment) -> Result<SExpr, String> {
match expr {
Atom(ref x) => Ok(Atom((*x).clone())),
Sexpr(ref s) => seval(s, env)
}
}
-fn seval(sexpr: &[SEXP], env: &mut Env) -> Result<SEXP, String> {
+fn seval(sexpr: &[SExpr], env: &mut Environment) -> Result<SExpr, String> {
if sexpr.is_empty() {
return Err("Empty S Expression".to_string())
}
let op = match &sexpr[0] {
- Atom(Operator(x)) => *x,
- Atom(Symbol(_s)) => return Err("Not yet implemented".to_string()),
+ Atom(Type::Operator(x)) => *x,
+ Atom(Type::Symbol(_s)) => return Err("Not yet implemented".to_string()),
x => return Err(format!("{:?} is not a procedure", x))
};
op_eval(op, &sexpr[1..], env)
}
-fn op_eval(op: Op, expr: &[SEXP], env: &mut Env) -> Result<SEXP, String> {
+fn op_eval(op: Op, expr: &[SExpr], env: &mut Environment) -> Result<SExpr, String> {
match op {
Add => op_add(expr, env),
+ Sub => op_sub(expr, env),
+ Mul => op_mul(expr, env),
+ Div => op_div(expr, env),
//Define => define(expr, env),
_ => Err("Not yet implemented".to_string())
}
}
-fn op_add(expr: &[SEXP], env: &mut Env) -> Result<SEXP, String> {
- let mut acc = Number(Number::Int(0));
+fn arith_op(
+ expr: &[SExpr],
+ env: &mut Environment,
+ identity: Number,
+ f: fn(Type, Type) -> Result<Type, String>) -> Result<SExpr, String>{
+
+ let mut acc = Type::Number(identity);
let mut i = 0;
+ if expr.len() > 1 {
+ let b = match eval(&expr[i], env)? {
+ Atom(x) => x,
+ Sexpr(_) => panic!("This should have evaluated to an atom")
+ };
+ acc = b;
+ i = 1;
+ }
while i < expr.len() {
let b = match eval(&expr[i], env)? {
Atom(x) => x,
Sexpr(_) => panic!("This should have evaluated to an atom")
};
- acc = (acc + b)?;
- i += 1;
+ acc = (f(acc, b))?;
+ i += 1
}
- Ok(SEXP::Atom(acc))
+ Ok(SExpr::Atom(acc))
+}
+
+fn op_add(expr: &[SExpr], env: &mut Environment) -> Result<SExpr, String> {
+ arith_op(expr, env, Number::Int(0), |a, b| a + b)
+}
+
+fn op_sub(expr: &[SExpr], env: &mut Environment) -> Result<SExpr, String> {
+ arith_op(expr, env, Number::Int(0), |a, b| a - b)
+}
+
+fn op_mul(expr: &[SExpr], env: &mut Environment) -> Result<SExpr, String> {
+ arith_op(expr, env, Number::Int(1), |a, b| a * b)
+}
+
+fn op_div(expr: &[SExpr], env: &mut Environment) -> Result<SExpr, String> {
+ arith_op(expr, env, Number::Float(1.0), |a, b| a / b)
}
diff --git a/src/lib/mod.rs b/src/lib/mod.rs
index a547a2d..bf4584c 100644
--- a/src/lib/mod.rs
+++ b/src/lib/mod.rs
@@ -1,3 +1,5 @@
-pub mod types;
-pub mod parse;
+pub mod environment;
pub mod eval;
+pub mod parse;
+pub mod sexpr;
+pub mod types;
diff --git a/src/lib/parse.rs b/src/lib/parse.rs
index 8e9c785..047b374 100644
--- a/src/lib/parse.rs
+++ b/src/lib/parse.rs
@@ -1,7 +1,7 @@
use super::types::Type;
use super::types::Number;
use super::types::Op;
-use super::types::SEXP;
+use super::sexpr::SExpr;
pub type MaybeToken = (Option<Result<Token, String>>, usize);
@@ -250,7 +250,7 @@ pub fn is_float(word: &str) -> MaybeToken {
}
}
-pub fn parse(expr: &str) -> Result<SEXP, String> {
+pub fn parse(expr: &str) -> Result<SExpr, String> {
let mut tokenstream = TokenStream::default(expr);
match tokenstream.peek() {
Some(Ok(Token::LParen)) => {
@@ -258,13 +258,13 @@ pub fn parse(expr: &str) -> Result<SEXP, String> {
descend(&mut tokenstream)
},
Some(Ok(Token::RParen)) => Err("Malformed expression".to_string()),
- Some(Ok(Token::Value(x))) => Ok(SEXP::Atom(x)),
+ Some(Ok(Token::Value(x))) => Ok(SExpr::Atom(x)),
Some(Err(f)) => Err(f),
None => Err("Empty expression".to_string())
}
}
-pub fn descend(tokenstream: &mut TokenStream) -> Result<SEXP, String> {
+pub fn descend(tokenstream: &mut TokenStream) -> Result<SExpr, String> {
let mut sexp = Vec::new();
loop {
let token = match tokenstream.next() {
@@ -286,11 +286,11 @@ pub fn descend(tokenstream: &mut TokenStream) -> Result<SEXP, String> {
break;
},
Token::Value(atom) => {
- sexp.push(SEXP::Atom(atom));
+ sexp.push(SExpr::Atom(atom));
continue;
}
}
}
- Ok(SEXP::Sexpr(sexp))
+ Ok(SExpr::Sexpr(sexp))
}
diff --git a/src/lib/sexpr.rs b/src/lib/sexpr.rs
index 0d37332..a6fbe49 100644
--- a/src/lib/sexpr.rs
+++ b/src/lib/sexpr.rs
@@ -1,7 +1,45 @@
use super::types::Type;
-pub enum SEXP {
+#[derive(PartialEq, Debug)]
+pub enum SExpr {
Atom(Type),
- List(Vec<SEXP>)
+ Sexpr(Vec<SExpr>)
}
+#[test]
+fn construct() {
+ let atom1 = SExpr::Atom(Type::Number(Number::Int(1)));
+ let atom2 = SExpr::Atom(Type::Number(Number::Int(2)));
+ let atom3 = SExpr::Atom(Type::Number(Number::Int(3)));
+ let atom4 = SExpr::Atom(Type::Number(Number::Int(4)));
+ let sexp = SExpr::Sexpr(vec!(atom1, atom2, atom3, atom4));
+ match sexp {
+ SExpr::Sexpr(ref x) => {
+ assert_eq!(x[0], SExpr::Atom(Type::Number(Number::Int(1))));
+ },
+ _ => panic!("What")
+ }
+}
+
+#[test]
+fn mutability() {
+ let atom1 = SExpr::Atom(Type::Number(Number::Int(1)));
+ let atom2 = SExpr::Atom(Type::Number(Number::Int(2)));
+ let atom3 = SExpr::Atom(Type::Number(Number::Int(3)));
+ let atom4 = SExpr::Atom(Type::Number(Number::Int(4)));
+ let mut sexp = SExpr::Sexpr(vec!(atom1, atom2, atom3, atom4));
+ match sexp {
+ SExpr::Sexpr(ref mut x) => match x[0] {
+ SExpr::Atom(Type::Number(Number::Int(ref mut x))) => *x += 7,
+ _ => panic!("What")
+ },
+ _ => panic!("What")
+ }
+
+ match sexp {
+ SExpr::Sexpr(ref x) => {
+ assert_eq!(x[0], SExpr::Atom(Type::Number(Number::Int(8))));
+ },
+ _ => panic!("What")
+ }
+}
diff --git a/src/lib/types.rs b/src/lib/types.rs
index 4c2900a..7755c04 100644
--- a/src/lib/types.rs
+++ b/src/lib/types.rs
@@ -51,47 +51,4 @@ pub enum Type {
Operator(Op),
}
-#[derive(PartialEq, Debug)]
-pub enum SEXP {
- Atom(Type),
- Sexpr(Vec<SEXP>)
-}
-
-#[test]
-fn construct() {
- let atom1 = SEXP::Atom(Type::Number(Number::Int(1)));
- let atom2 = SEXP::Atom(Type::Number(Number::Int(2)));
- let atom3 = SEXP::Atom(Type::Number(Number::Int(3)));
- let atom4 = SEXP::Atom(Type::Number(Number::Int(4)));
- let sexp = SEXP::Sexpr(vec!(atom1, atom2, atom3, atom4));
- match sexp {
- SEXP::Sexpr(ref x) => {
- assert_eq!(x[0], SEXP::Atom(Type::Number(Number::Int(1))));
- },
- _ => panic!("What")
- }
-}
-
-#[test]
-fn mutability() {
- let atom1 = SEXP::Atom(Type::Number(Number::Int(1)));
- let atom2 = SEXP::Atom(Type::Number(Number::Int(2)));
- let atom3 = SEXP::Atom(Type::Number(Number::Int(3)));
- let atom4 = SEXP::Atom(Type::Number(Number::Int(4)));
- let mut sexp = SEXP::Sexpr(vec!(atom1, atom2, atom3, atom4));
- match sexp {
- SEXP::Sexpr(ref mut x) => match x[0] {
- SEXP::Atom(Type::Number(Number::Int(ref mut x))) => *x += 7,
- _ => panic!("What")
- },
- _ => panic!("What")
- }
-
- match sexp {
- SEXP::Sexpr(ref x) => {
- assert_eq!(x[0], SEXP::Atom(Type::Number(Number::Int(8))));
- },
- _ => panic!("What")
- }
-}
diff --git a/src/main.rs b/src/main.rs
index 15cf60b..49c916a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -6,6 +6,8 @@ pub mod lib;
use rustyline::error::ReadlineError;
use rustyline::Editor;
+use lib::environment::Environment;
+
fn read<T: rustyline::Helper>(rl: &mut Editor<T>) -> Option<String> {
let readline = rl.readline(">> ");
match readline {
@@ -35,13 +37,12 @@ fn means_exit(input: &str) -> bool {
}
}
-fn eval(env: &mut lib::eval::Env, input: &str) -> String {
+fn eval(env: &mut Environment, input: &str) -> String {
let sexp = match lib::parse::parse(input) {
Ok(x) => x,
Err(f) => return f
};
- println!("{:?}", sexp);
let res = lib::eval::eval(&sexp, env);
match res {
Ok(x) => format!("{:?}", x),
@@ -50,7 +51,7 @@ fn eval(env: &mut lib::eval::Env, input: &str) -> String {
}
fn main() {
- let mut env = lib::eval::Env::new();
+ let mut env = Environment::new();
let hist_file = "history.txt";
// `()` can be used when no completer is required