Begin evaluator, calculator with batteries
This commit is contained in:
parent
688b48ef42
commit
03cf0974de
71
rust/src/evaluator.rs
Normal file
71
rust/src/evaluator.rs
Normal 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!"),
|
||||
}
|
||||
}
|
||||
}
|
@ -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)),
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user