diff --git a/rust/src/evaluator.rs b/rust/src/evaluator.rs index 8e670e9..6db0598 100644 --- a/rust/src/evaluator.rs +++ b/rust/src/evaluator.rs @@ -1,7 +1,7 @@ use std::ops; use std::collections::HashMap; -use crate::parser; +use crate::parser::{self, GuardedBlock}; use parser::Atom; pub struct Env<'a> { @@ -42,6 +42,30 @@ pub fn eval(ast: &parser::Stmt, env: &mut Env) { println!("{}", eval_expr(expr, env)), parser::Stmt::Assignment(id, expr) => env.set(id.clone(), eval_expr(expr, env)), + parser::Stmt::Conditional(guarded_blocks, default_block) => { + let mut matched = false; + for GuardedBlock { guard, block } in guarded_blocks { + let res = eval_expr(&guard, env); + match res { + Atom::Bool(true) => { + matched = true; + for stmt in block { + eval(stmt, env); + } + break; + } + Atom::Bool(false) => continue, + _ => panic!("Conditional expression does not evaluate to a bool"), + } + } + if !matched { + if let Some(block) = default_block { + for expr in default_block { + eval_expr(expr, env); + } + } + } + } _ => todo!(), } } diff --git a/rust/src/parser.rs b/rust/src/parser.rs index 2a40e90..5c9173e 100644 --- a/rust/src/parser.rs +++ b/rust/src/parser.rs @@ -4,7 +4,7 @@ use std::fmt; pub enum Stmt { Assignment(String, Expr), Funcall(Expr), - Conditional(Vec, Option), + Conditional(Vec, Option), ReplPrint(Expr), } @@ -20,7 +20,6 @@ pub enum Expr { Mult(Box, Box), Div(Box, Box), Block(Vec), - GuardedBlock(Box), Object(Vec), } @@ -28,6 +27,7 @@ pub enum Expr { pub enum Atom { String(String), Num(f64), + Bool(bool), } impl fmt::Display for Atom { @@ -35,6 +35,7 @@ impl fmt::Display for Atom { match self { Atom::String(a) => write!(f, "\"{}\"", a), Atom::Num(a) => write!(f, "{}", a), + Atom::Bool(a) => write!(f, "{}", a), } } } @@ -68,7 +69,8 @@ peg::parser! { f:funcall() { f } f:funcdef() { f } o:object() { o } - i:id() _ { Expr::Id(i) } + b:_bool() _ { Expr::Atom(Atom::Bool(b)) } + i:id() { Expr::Id(i) } n:num() _ { Expr::Atom(Atom::Num(n)) } } @@ -79,6 +81,8 @@ peg::parser! { = i:id() "<-" _ e:expr() stop() { Stmt::Assignment(i, e) } rule num() -> f64 = n:$(digit()+ "."? digit()* / "." digit()+) _ { n.parse().unwrap() } + rule _bool() -> bool + = "true" _ { true } / "false" _ { false } rule funcall() -> Expr = i:id() "(" _ e:(expr() ** ("," _)) ")" _ { Expr::Funcall(i, e) } rule funcdef() -> Expr @@ -88,19 +92,19 @@ peg::parser! { rule object() -> Expr = "{" _ stop() indent() __* a:assignment()+ dedent() __* "}" _ { Expr::Object(a) } - rule _if() -> Expr + rule _if() -> GuardedBlock = "if" _ g:expr() b:indented_block() { - Expr::GuardedBlock(Box::new(GuardedBlock { + GuardedBlock { guard: g, block: b, - })) + } } - rule elif() -> Expr + rule elif() -> GuardedBlock = "elif" _ g:expr() b:indented_block() { - Expr::GuardedBlock(Box::new(GuardedBlock { + GuardedBlock { guard: g, block: b - })) + } } rule _else() -> Expr = "else" _ b:block() { b }