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 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)),
|
||||||
|
_ => (),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user