Begin evaluator, calculator with batteries

This commit is contained in:
Dane Johnson 2022-02-14 16:32:07 -06:00
parent 688b48ef42
commit 03cf0974de
3 changed files with 110 additions and 16 deletions

71
rust/src/evaluator.rs Normal file
View File

@ -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!"),
}
}
}

View File

@ -1,4 +1,5 @@
mod parser; mod parser;
mod evaluator;
use std::io; use std::io;
use std::io::prelude::*; use std::io::prelude::*;
@ -10,7 +11,10 @@ fn repl() {
let mut line = String::new(); let mut line = String::new();
io::stdin().read_line(&mut line).unwrap(); io::stdin().read_line(&mut line).unwrap();
let tree = parser::parse_stmt(&line); let tree = parser::parse_stmt(&line);
println!("{:#?}", tree); match &tree {
parser::Stmt::ReplPrint(expr) => println!("{}", evaluator::eval(expr)),
_ => (),
};
} }
} }

View File

@ -1,3 +1,5 @@
use std::fmt;
#[derive(Debug,PartialEq,Clone)] #[derive(Debug,PartialEq,Clone)]
pub enum Stmt { pub enum Stmt {
Assignment(String, Expr), Assignment(String, Expr),
@ -9,10 +11,10 @@ pub enum Stmt {
#[derive(Debug,PartialEq,Clone)] #[derive(Debug,PartialEq,Clone)]
pub enum Expr { pub enum Expr {
Id(String), Id(String),
String(String), Atom(Atom),
Num(f64),
Funcall(String, Vec<Expr>), Funcall(String, Vec<Expr>),
Funcdef(Option<String>, Box<Expr>), Funcdef(Option<String>, Box<Expr>),
UnaryMinus(Box<Expr>),
Plus(Box<Expr>, Box<Expr>), Plus(Box<Expr>, Box<Expr>),
Minus(Box<Expr>, Box<Expr>), Minus(Box<Expr>, Box<Expr>),
Mult(Box<Expr>, Box<Expr>), Mult(Box<Expr>, Box<Expr>),
@ -22,6 +24,21 @@ pub enum Expr {
Object(Vec<Stmt>), Object(Vec<Stmt>),
} }
#[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)] #[derive(Debug,PartialEq,Clone)]
pub struct GuardedBlock { pub struct GuardedBlock {
pub guard: Expr, pub guard: Expr,
@ -38,6 +55,8 @@ peg::parser! {
c:conditional() { c } / c:conditional() { c } /
e:expr() stop() { Stmt::ReplPrint(e) } e:expr() stop() { Stmt::ReplPrint(e) }
rule expr() -> Expr = precedence! { rule expr() -> Expr = precedence! {
"-" _ e1:@ { Expr::UnaryMinus(Box::new(e1)) }
--
e1:(@) "+" _ e2:@ { Expr::Plus(Box::new(e1), Box::new(e2)) } e1:(@) "+" _ e2:@ { Expr::Plus(Box::new(e1), Box::new(e2)) }
e1:(@) "-" _ e2:@ { Expr::Minus(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)) } e1:(@) "/" _ e2:@ { Expr::Div(Box::new(e1), Box::new(e2)) }
-- --
"(" _ e:expr() ")" _ { e } "(" _ e:expr() ")" _ { e }
['"'] s:$((!['"'] [_] / r#"\""#)*) ['"'] { Expr::String(s.to_string()) } ['"'] s:$((!['"'] [_] / r#"\""#)*) ['"'] { Expr::Atom(Atom::String(s.to_string())) }
f:funcall() { f } f:funcall() { f }
f:funcdef() { f } f:funcdef() { f }
o:object() { o } o:object() { o }
i:id() _ { Expr::Id(i) } 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 let prgm = r"## This is a comment
apple <- 1 ## This is too apple <- 1 ## This is too
## This comment ends the file"; ## 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); assert_eq!(deelang_parser::program(prgm).unwrap(), expected);
} }
@ -188,7 +207,7 @@ pear(x, y)";
apple <- pear(x, y)"; apple <- pear(x, y)";
let expected = vec![ let expected = vec![
Stmt::Assignment("apple".to_string(), Stmt::Assignment("apple".to_string(),
Expr::Num(1.0)), Expr::Atom(Atom::Num(1.0))),
Stmt::Assignment("apple".to_string(), Stmt::Assignment("apple".to_string(),
Expr::Funcall("pear".to_string(), Expr::Funcall("pear".to_string(),
vec![ vec![
@ -207,21 +226,21 @@ four <- (3 - 1) * 2";
let expected = vec![ let expected = vec![
Stmt::Assignment("three".to_string(), Stmt::Assignment("three".to_string(),
Expr::Plus( Expr::Plus(
Box::new(Expr::Num(1.0)), Box::new(Expr::Atom(Atom::Num(1.0))),
Box::new(Expr::Num(2.0)) Box::new(Expr::Atom(Atom::Num(2.0))),
)), )),
Stmt::Assignment("one".to_string(), Stmt::Assignment("one".to_string(),
Expr::Minus( Expr::Minus(
Box::new(Expr::Num(3.0)), Box::new(Expr::Atom(Atom::Num(3.0))),
Box::new(Expr::Num(2.0)) Box::new(Expr::Atom(Atom::Num(2.0))),
)), )),
Stmt::Assignment("four".to_string(), Stmt::Assignment("four".to_string(),
Expr::Mult( Expr::Mult(
Box::new(Expr::Minus( Box::new(Expr::Minus(
Box::new(Expr::Num(3.0)), Box::new(Expr::Atom(Atom::Num(3.0))),
Box::new(Expr::Num(1.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); assert_eq!(deelang_parser::program(prgm).unwrap(), expected);
@ -327,8 +346,8 @@ pear <- 2
let expected = vec![Stmt::Assignment( let expected = vec![Stmt::Assignment(
"fruit".to_string(), "fruit".to_string(),
Expr::Object(vec![ Expr::Object(vec![
Stmt::Assignment("apple".to_string(), Expr::Num(1.0)), Stmt::Assignment("apple".to_string(), Expr::Atom(Atom::Num(1.0))),
Stmt::Assignment("pear".to_string(), Expr::Num(2.0)), Stmt::Assignment("pear".to_string(), Expr::Atom(Atom::Num(2.0))),
]), ]),
)]; )];
assert_eq!(deelang_parser::program(prgm).unwrap(), expected); assert_eq!(deelang_parser::program(prgm).unwrap(), expected);