Conditionals

This commit is contained in:
Dane Johnson 2022-02-14 10:42:49 -06:00
parent 96d446dde3
commit 51531b806f

View File

@ -1,10 +1,11 @@
#[derive(Debug,PartialEq)]
#[derive(Debug,PartialEq,Clone)]
pub enum Stmt {
Assignment(String, Expr),
Funcall(Expr),
Conditional(Vec<Expr>, Option<Expr>),
}
#[derive(Debug,PartialEq)]
#[derive(Debug,PartialEq,Clone)]
pub enum Expr {
Id(String),
Num(f64),
@ -15,6 +16,13 @@ pub enum Expr {
Mult(Box<Expr>, Box<Expr>),
Div(Box<Expr>, Box<Expr>),
Block(Vec<Stmt>),
GuardedBlock(Box<GuardedBlock>),
}
#[derive(Debug,PartialEq,Clone)]
pub struct GuardedBlock {
pub guard: Expr,
pub block: Vec<Stmt>,
}
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<Stmt>
= 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() {