diff --git a/rust/src/evaluator.rs b/rust/src/evaluator.rs new file mode 100644 index 0000000..8060170 --- /dev/null +++ b/rust/src/evaluator.rs @@ -0,0 +1,71 @@ +use std::ops; + +use crate::parser; +use parser::Atom; + +pub fn eval(ast: &parser::Expr) -> parser::Atom { + match ast { + parser::Expr::Atom(a) => a.clone(), + parser::Expr::UnaryMinus(a) => -eval(&a), + parser::Expr::Plus(a, b) => eval(&a) + eval(&b), + parser::Expr::Minus(a, b) => eval(&a) - eval(&b), + parser::Expr::Mult(a, b) => eval(&a) * eval(&b), + parser::Expr::Div(a, b) => eval(&a) / eval(&b), + _ => panic!("Couldn't evalute expression {{ {:?} }}", ast), + } +} + +impl ops::Neg for Atom { + type Output = Self; + + fn neg(self) -> Self { + match self { + Atom::Num(a) => Atom::Num(-a), + _ => panic!("Can't negate non-numeral type!"), + } + } +} + +impl ops::Add for Atom { + type Output = Self; + + fn add(self, other: Self) -> Self { + match (self, other) { + (Atom::Num(a), Atom::Num(b)) => Atom::Num(a + b), + _ => panic!("Can't add non-numeral types!"), + } + } +} + +impl ops::Sub for Atom { + type Output = Self; + + fn sub(self, other: Self) -> Self { + match (self, other) { + (Atom::Num(a), Atom::Num(b)) => Atom::Num(a - b), + _ => panic!("Can't subtract non-numeral types!"), + } + } +} + +impl ops::Mul for Atom { + type Output = Self; + + fn mul(self, other: Self) -> Self { + match (self, other) { + (Atom::Num(a), Atom::Num(b)) => Atom::Num(a * b), + _ => panic!("Can't multiply non-numeral types!"), + } + } +} + +impl ops::Div for Atom { + type Output = Self; + + fn div(self, other: Self) -> Self { + match (self, other) { + (Atom::Num(a), Atom::Num(b)) => Atom::Num(a / b), + _ => panic!("Can't divide non-numeral types!"), + } + } +} diff --git a/rust/src/main.rs b/rust/src/main.rs index 807d781..3779ffc 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -1,4 +1,5 @@ mod parser; +mod evaluator; use std::io; use std::io::prelude::*; @@ -10,7 +11,10 @@ fn repl() { let mut line = String::new(); io::stdin().read_line(&mut line).unwrap(); let tree = parser::parse_stmt(&line); - println!("{:#?}", tree); + match &tree { + parser::Stmt::ReplPrint(expr) => println!("{}", evaluator::eval(expr)), + _ => (), + }; } } diff --git a/rust/src/parser.rs b/rust/src/parser.rs index e3414c3..8674b9d 100644 --- a/rust/src/parser.rs +++ b/rust/src/parser.rs @@ -1,3 +1,5 @@ +use std::fmt; + #[derive(Debug,PartialEq,Clone)] pub enum Stmt { Assignment(String, Expr), @@ -9,10 +11,10 @@ pub enum Stmt { #[derive(Debug,PartialEq,Clone)] pub enum Expr { Id(String), - String(String), - Num(f64), + Atom(Atom), Funcall(String, Vec), Funcdef(Option, Box), + UnaryMinus(Box), Plus(Box, Box), Minus(Box, Box), Mult(Box, Box), @@ -22,6 +24,21 @@ pub enum Expr { Object(Vec), } +#[derive(Debug,PartialEq,Clone)] +pub enum Atom { + String(String), + Num(f64), +} + +impl fmt::Display for Atom { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Atom::String(a) => write!(f, "{}", a), + Atom::Num(a) => write!(f, "{}", a), + } + } +} + #[derive(Debug,PartialEq,Clone)] pub struct GuardedBlock { pub guard: Expr, @@ -38,6 +55,8 @@ peg::parser! { c:conditional() { c } / e:expr() stop() { Stmt::ReplPrint(e) } rule expr() -> Expr = precedence! { + "-" _ e1:@ { Expr::UnaryMinus(Box::new(e1)) } + -- e1:(@) "+" _ e2:@ { Expr::Plus(Box::new(e1), Box::new(e2)) } e1:(@) "-" _ e2:@ { Expr::Minus(Box::new(e1), Box::new(e2)) } -- @@ -45,12 +64,12 @@ peg::parser! { e1:(@) "/" _ e2:@ { Expr::Div(Box::new(e1), Box::new(e2)) } -- "(" _ e:expr() ")" _ { e } - ['"'] s:$((!['"'] [_] / r#"\""#)*) ['"'] { Expr::String(s.to_string()) } + ['"'] s:$((!['"'] [_] / r#"\""#)*) ['"'] { Expr::Atom(Atom::String(s.to_string())) } f:funcall() { f } f:funcdef() { f } o:object() { o } i:id() _ { Expr::Id(i) } - n:num() _ { Expr::Num(n) } + n:num() _ { Expr::Atom(Atom::Num(n)) } } @@ -165,7 +184,7 @@ mod test { let prgm = r"## This is a comment apple <- 1 ## This is too ## This comment ends the file"; - let expected = vec![Stmt::Assignment("apple".to_string(), Expr::Num(1.0))]; + let expected = vec![Stmt::Assignment("apple".to_string(), Expr::Atom(Atom::Num(1.0)))]; assert_eq!(deelang_parser::program(prgm).unwrap(), expected); } @@ -188,7 +207,7 @@ pear(x, y)"; apple <- pear(x, y)"; let expected = vec![ Stmt::Assignment("apple".to_string(), - Expr::Num(1.0)), + Expr::Atom(Atom::Num(1.0))), Stmt::Assignment("apple".to_string(), Expr::Funcall("pear".to_string(), vec![ @@ -207,21 +226,21 @@ four <- (3 - 1) * 2"; let expected = vec![ Stmt::Assignment("three".to_string(), Expr::Plus( - Box::new(Expr::Num(1.0)), - Box::new(Expr::Num(2.0)) + Box::new(Expr::Atom(Atom::Num(1.0))), + Box::new(Expr::Atom(Atom::Num(2.0))), )), Stmt::Assignment("one".to_string(), Expr::Minus( - Box::new(Expr::Num(3.0)), - Box::new(Expr::Num(2.0)) + Box::new(Expr::Atom(Atom::Num(3.0))), + Box::new(Expr::Atom(Atom::Num(2.0))), )), Stmt::Assignment("four".to_string(), Expr::Mult( Box::new(Expr::Minus( - Box::new(Expr::Num(3.0)), - Box::new(Expr::Num(1.0)), + Box::new(Expr::Atom(Atom::Num(3.0))), + Box::new(Expr::Atom(Atom::Num(1.0))), )), - Box::new(Expr::Num(2.0)), + Box::new(Expr::Atom(Atom::Num (2.0))), )) ]; assert_eq!(deelang_parser::program(prgm).unwrap(), expected); @@ -327,8 +346,8 @@ pear <- 2 let expected = vec![Stmt::Assignment( "fruit".to_string(), Expr::Object(vec![ - Stmt::Assignment("apple".to_string(), Expr::Num(1.0)), - Stmt::Assignment("pear".to_string(), Expr::Num(2.0)), + Stmt::Assignment("apple".to_string(), Expr::Atom(Atom::Num(1.0))), + Stmt::Assignment("pear".to_string(), Expr::Atom(Atom::Num(2.0))), ]), )]; assert_eq!(deelang_parser::program(prgm).unwrap(), expected);