diff options
author | Vincent Ambo <mail@tazj.in> | 2021-01-11T17·29+0300 |
---|---|---|
committer | tazjin <mail@tazj.in> | 2021-01-13T17·03+0000 |
commit | f3c60865a3bf8c90afa58df477779bad72e6945d (patch) | |
tree | 7cf3b96f4a5f333a75bbd67d6990045104136e32 | |
parent | 2253617e0b5d093a73048d3630d5f1092fe273fd (diff) |
feat(tazjin/rlox): Parse function calls r/2092
Change-Id: I1836c73dbfd5fc4ca30c2d22bbffee2fb222d566 Reviewed-on: https://cl.tvl.fyi/c/depot/+/2366 Reviewed-by: tazjin <mail@tazj.in> Tested-by: BuildkiteCI
-rw-r--r-- | users/tazjin/rlox/src/interpreter.rs | 1 | ||||
-rw-r--r-- | users/tazjin/rlox/src/parser.rs | 56 |
2 files changed, 53 insertions, 4 deletions
diff --git a/users/tazjin/rlox/src/interpreter.rs b/users/tazjin/rlox/src/interpreter.rs index 28eb23f9948c..b3fc3d1900a8 100644 --- a/users/tazjin/rlox/src/interpreter.rs +++ b/users/tazjin/rlox/src/interpreter.rs @@ -190,6 +190,7 @@ impl Interpreter { Expr::Binary(binary) => self.eval_binary(binary), Expr::Variable(var) => self.get_var(var), Expr::Logical(log) => self.eval_logical(log), + Expr::Call(_) => unimplemented!(), } } diff --git a/users/tazjin/rlox/src/parser.rs b/users/tazjin/rlox/src/parser.rs index fd1f7c9ea825..4d72eed539bd 100644 --- a/users/tazjin/rlox/src/parser.rs +++ b/users/tazjin/rlox/src/parser.rs @@ -47,6 +47,13 @@ pub struct Unary<'a> { pub right: Box<Expr<'a>>, } +#[derive(Debug)] +pub struct Call<'a> { + pub callee: Box<Expr<'a>>, + pub paren: Token<'a>, + pub args: Vec<Expr<'a>>, +} + // Not to be confused with `Var`, which is for assignment. #[derive(Debug)] pub struct Variable<'a>(pub Token<'a>); @@ -58,6 +65,7 @@ pub enum Expr<'a> { Grouping(Grouping<'a>), Literal(Literal), Unary(Unary<'a>), + Call(Call<'a>), Variable(Variable<'a>), Logical(Logical<'a>), } @@ -132,8 +140,9 @@ equality → comparison ( ( "!=" | "==" ) comparison )* ; comparison → term ( ( ">" | ">=" | "<" | "<=" ) term )* ; term → factor ( ( "-" | "+" ) factor )* ; factor → unary ( ( "/" | "*" ) unary )* ; -unary → ( "!" | "-" ) unary - | primary ; +unary → ( "!" | "-" ) unary | call ; +call → primary ( "(" arguments? ")" )* ; +arguments → expression ( "," expression )* ; primary → NUMBER | STRING | "true" | "false" | "nil" | "(" expression ")" ; */ @@ -410,7 +419,46 @@ impl<'a> Parser<'a> { })); } - return self.primary(); + return self.call(); + } + + fn call(&mut self) -> ExprResult<'a> { + let mut expr = self.primary()?; + + loop { + if self.match_token(&[TokenKind::LeftParen]) { + expr = self.finish_call(expr)?; + } else { + break; + } + } + + Ok(expr) + } + + fn finish_call(&mut self, callee: Expr<'a>) -> ExprResult<'a> { + let mut args = vec![]; + + if !self.check_token(&TokenKind::RightParen) { + loop { + // TODO(tazjin): Check for max args count + args.push(self.expression()?); + if !self.match_token(&[TokenKind::Comma]) { + break; + } + } + } + + let paren = self.consume( + &TokenKind::RightParen, + ErrorKind::ExpectedToken("Expect ')' after arguments."), + )?; + + Ok(Expr::Call(Call { + args, + callee: Box::new(callee), + paren, + })) } fn primary(&mut self) -> ExprResult<'a> { @@ -482,7 +530,7 @@ impl<'a> Parser<'a> { &self.tokens[self.current - 1] } - fn consume(&mut self, kind: &TokenKind, err: ErrorKind) -> Result<Token, Error> { + fn consume(&mut self, kind: &TokenKind, err: ErrorKind) -> Result<Token<'a>, Error> { if self.check_token(kind) { return Ok(self.advance()); } |