about summary refs log tree commit diff
path: root/users/tazjin/rlox
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2021-01-11T17·29+0300
committertazjin <mail@tazj.in>2021-01-13T17·03+0000
commitf3c60865a3bf8c90afa58df477779bad72e6945d (patch)
tree7cf3b96f4a5f333a75bbd67d6990045104136e32 /users/tazjin/rlox
parent2253617e0b5d093a73048d3630d5f1092fe273fd (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
Diffstat (limited to 'users/tazjin/rlox')
-rw-r--r--users/tazjin/rlox/src/interpreter.rs1
-rw-r--r--users/tazjin/rlox/src/parser.rs56
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());
         }