aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/parser.rs
diff options
context:
space:
mode:
authorJohannes Stoelp <johannes.stoelp@gmail.com>2021-10-04 22:51:42 +0200
committerJohannes Stoelp <johannes.stoelp@gmail.com>2021-10-04 22:51:42 +0200
commit4f6dd49df3f19204694fcea55f38efd9c5118bf2 (patch)
tree119d4fa88f6f744ecdb1eb9a833c316f5932b0c1 /src/parser.rs
parenta3dee93989b9fdd99b8a22a2da7f72bcd2ba50c2 (diff)
downloadllvm-kaleidoscope-rs-4f6dd49df3f19204694fcea55f38efd9c5118bf2.tar.gz
llvm-kaleidoscope-rs-4f6dd49df3f19204694fcea55f38efd9c5118bf2.zip
ch5: added if/then/else
Diffstat (limited to 'src/parser.rs')
-rw-r--r--src/parser.rs77
1 files changed, 74 insertions, 3 deletions
diff --git a/src/parser.rs b/src/parser.rs
index b3a26cb..39e69ce 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -13,6 +13,13 @@ pub enum ExprAST {
/// Call - Expression class for function calls.
Call(String, Vec<ExprAST>),
+
+ /// If - Expression class for if/then/else.
+ If {
+ cond: Box<ExprAST>,
+ then: Box<ExprAST>,
+ else_: Box<ExprAST>,
+ },
}
/// PrototypeAST - This class represents the "prototype" for a function,
@@ -137,8 +144,6 @@ where
args.push(arg);
if *self.cur_tok() == Token::Char(')') {
- // Eat ')' token.
- self.get_next_token();
break;
}
@@ -150,10 +155,47 @@ where
}
}
+ assert_eq!(*self.cur_tok(), Token::Char(')'));
+ // Eat ')' token.
+ self.get_next_token();
+
Ok(ExprAST::Call(id_name, args))
}
}
+ /// ifexpr ::= 'if' expression 'then' expression 'else' expression
+ ///
+ /// Implement `std::unique_ptr<ExprAST> ParseIfExpr();` from the tutorial.
+ fn parse_if_expr(&mut self) -> ParseResult<ExprAST> {
+ // Consume 'if' token.
+ assert_eq!(*self.cur_tok(), Token::If);
+ self.get_next_token();
+
+ let cond = self.parse_expression()?;
+
+ if *dbg!(self.cur_tok()) != Token::Then {
+ return Err("Expected 'then'".into());
+ }
+ // Consume 'then' token.
+ self.get_next_token();
+
+ let then = self.parse_expression()?;
+
+ if *self.cur_tok() != Token::Else {
+ return Err("Expected 'else'".into());
+ }
+ // Consume 'else' token.
+ self.get_next_token();
+
+ let else_ = self.parse_expression()?;
+
+ Ok(ExprAST::If {
+ cond: Box::new(cond),
+ then: Box::new(then),
+ else_: Box::new(else_),
+ })
+ }
+
/// primary
/// ::= identifierexpr
/// ::= numberexpr
@@ -165,6 +207,7 @@ where
Token::Identifier(_) => self.parse_identifier_expr(),
Token::Number(_) => self.parse_num_expr(),
Token::Char('(') => self.parse_paren_expr(),
+ Token::If => self.parse_if_expr(),
_ => Err("unknown token when expecting an expression".into()),
}
}
@@ -358,8 +401,27 @@ mod test {
}
#[test]
+ fn parse_if() {
+ let mut p = parser("if 1 then 2 else 3");
+
+ let cond = Box::new(ExprAST::Number(1f64));
+ let then = Box::new(ExprAST::Number(2f64));
+ let else_ = Box::new(ExprAST::Number(3f64));
+
+ assert_eq!(p.parse_if_expr(), Ok(ExprAST::If { cond, then, else_ }));
+
+ let mut p = parser("if foo() then bar(2) else baz(3)");
+
+ let cond = Box::new(ExprAST::Call("foo".into(), vec![]));
+ let then = Box::new(ExprAST::Call("bar".into(), vec![ExprAST::Number(2f64)]));
+ let else_ = Box::new(ExprAST::Call("baz".into(), vec![ExprAST::Number(3f64)]));
+
+ assert_eq!(p.parse_if_expr(), Ok(ExprAST::If { cond, then, else_ }));
+ }
+
+ #[test]
fn parse_primary() {
- let mut p = parser("1337 foop \n bla(123)");
+ let mut p = parser("1337 foop \n bla(123) \n if a then b else c");
assert_eq!(p.parse_primary(), Ok(ExprAST::Number(1337f64)));
@@ -369,6 +431,15 @@ mod test {
p.parse_primary(),
Ok(ExprAST::Call("bla".into(), vec![ExprAST::Number(123f64)]))
);
+
+ assert_eq!(
+ p.parse_primary(),
+ Ok(ExprAST::If {
+ cond: Box::new(ExprAST::Variable("a".into())),
+ then: Box::new(ExprAST::Variable("b".into())),
+ else_: Box::new(ExprAST::Variable("c".into())),
+ })
+ );
}
#[test]