From 51531b806f4a52a415ad938d9055d3609ba4479f Mon Sep 17 00:00:00 2001 From: Dane Johnson Date: Mon, 14 Feb 2022 10:42:49 -0600 Subject: [PATCH] Conditionals --- rust/src/parser.rs | 65 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 5 deletions(-) diff --git a/rust/src/parser.rs b/rust/src/parser.rs index 8e2fa46..15d3e20 100644 --- a/rust/src/parser.rs +++ b/rust/src/parser.rs @@ -1,10 +1,11 @@ -#[derive(Debug,PartialEq)] +#[derive(Debug,PartialEq,Clone)] pub enum Stmt { Assignment(String, Expr), Funcall(Expr), + Conditional(Vec, Option), } -#[derive(Debug,PartialEq)] +#[derive(Debug,PartialEq,Clone)] pub enum Expr { Id(String), Num(f64), @@ -15,6 +16,13 @@ pub enum Expr { Mult(Box, Box), Div(Box, Box), Block(Vec), + GuardedBlock(Box), +} + +#[derive(Debug,PartialEq,Clone)] +pub struct GuardedBlock { + pub guard: Expr, + pub block: Vec, } peg::parser! { @@ -23,7 +31,8 @@ peg::parser! { = __* s:stmt()* { s } pub rule stmt() -> Stmt = i:id() "<-" _ e:expr() stop() { Stmt::Assignment(i, e) } / - f:funcall() stop() { Stmt::Funcall(f) } + f:funcall() stop() { Stmt::Funcall(f) } / + c:conditional() { c } rule expr() -> Expr = precedence! { e1:(@) "+" _ e2:@ { Expr::Plus(Box::new(e1), Box::new(e2)) } e1:(@) "-" _ e2:@ { Expr::Minus(Box::new(e1), Box::new(e2)) } @@ -37,8 +46,6 @@ peg::parser! { i:id() _ { Expr::Id(i) } n:num() _ { Expr::Num(n) } } - rule block() -> Expr - = stop() indent() __* s:stmt()+ dedent() { Expr::Block(s) } rule id() -> String = i:$(letter() (letter() / digit() / ['?'|'.'|'-'])*) _ { i.to_string() } @@ -48,6 +55,28 @@ peg::parser! { = i:id() "(" _ e:(expr() ** ("," _)) ")" _ { Expr::Funcall(i, e) } rule funcdef() -> Expr = i:id()? "->" _ e:(expr() / block()) { Expr::Funcdef(i, Box::new(e)) } + rule conditional() -> Stmt + = i:_if() __* ei:elif()* __* e:_else()? __* { Stmt::Conditional([vec![i], ei].concat(), e) } + rule _if() -> Expr + = "if" _ g:expr() b:indented_block() { + Expr::GuardedBlock(Box::new(GuardedBlock { + guard: g, + block: b, + })) + } + rule elif() -> Expr + = "elif" _ g:expr() b:indented_block() { + Expr::GuardedBlock(Box::new(GuardedBlock { + guard: g, + block: b + })) + } + rule _else() -> Expr + = "else" _ b:block() { b } + rule block() -> Expr + = i:indented_block() { Expr::Block(i) } + rule indented_block() -> Vec + = stop() indent() __* s:stmt()+ dedent() { s } rule letter() = ['A'..='Z'] / ['a'..='z'] @@ -250,6 +279,32 @@ foo <- x -> y -> x * y"; ]; assert_eq!(deelang_parser::program(prgm).unwrap(), expected); } + #[test] + fn test_conditional() { + let prgm = r"if foo +>>>bar() +<<< +elif baz +>>>foobar() +<<< +else +>>>quux() +<<<"; + let expected = vec![Stmt::Conditional( + vec![ + Expr::GuardedBlock(Box::new(GuardedBlock { + guard: Expr::Id("foo".to_string()), + block: vec![Stmt::Funcall(Expr::Funcall("bar".to_string(), vec![]))] + })), + Expr::GuardedBlock(Box::new(GuardedBlock { + guard: Expr::Id("baz".to_string()), + block: vec![Stmt::Funcall(Expr::Funcall("foobar".to_string(), vec![]))] + })), + ], + Some(Expr::Block(vec![Stmt::Funcall(Expr::Funcall("quux".to_string(), vec![]))])), + )]; + assert_eq!(deelang_parser::program(prgm).unwrap(), expected); + } #[test] fn test_preprocess() {