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 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)),
_ => (),
};
}
}

View File

@ -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<Expr>),
Funcdef(Option<String>, Box<Expr>),
UnaryMinus(Box<Expr>),
Plus(Box<Expr>, Box<Expr>),
Minus(Box<Expr>, Box<Expr>),
Mult(Box<Expr>, Box<Expr>),
@ -22,6 +24,21 @@ pub enum Expr {
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)]
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);