about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2021-01-14T02·02+0300
committertazjin <mail@tazj.in>2021-01-14T02·05+0000
commit1ed34443d832fcfd7b683ecdcb58b0c445443def (patch)
treeeb69960be2b3c8f3b8236b2dc10878bf048e87e0
parent8bcbb041606b0fd15459415a3e5531a753c8bfd8 (diff)
feat(tazjin/rlox): Parse function declarations r/2103
Change-Id: I1db4316563827976e5233dc7a626968f80b992ef
Reviewed-on: https://cl.tvl.fyi/c/depot/+/2390
Reviewed-by: tazjin <mail@tazj.in>
Tested-by: BuildkiteCI
-rw-r--r--users/tazjin/rlox/src/interpreter.rs1
-rw-r--r--users/tazjin/rlox/src/parser.rs70
2 files changed, 67 insertions, 4 deletions
diff --git a/users/tazjin/rlox/src/interpreter.rs b/users/tazjin/rlox/src/interpreter.rs
index cccc381b32..6aab389369 100644
--- a/users/tazjin/rlox/src/interpreter.rs
+++ b/users/tazjin/rlox/src/interpreter.rs
@@ -208,6 +208,7 @@ impl Interpreter {
             Statement::Block(block) => return self.interpret_block(block),
             Statement::If(if_stmt) => return self.interpret_if(if_stmt),
             Statement::While(while_stmt) => return self.interpret_while(while_stmt),
+            Statement::Function(_) => unimplemented!(),
         };
 
         Ok(value)
diff --git a/users/tazjin/rlox/src/parser.rs b/users/tazjin/rlox/src/parser.rs
index 74c2f448ed..626eda641c 100644
--- a/users/tazjin/rlox/src/parser.rs
+++ b/users/tazjin/rlox/src/parser.rs
@@ -94,6 +94,13 @@ pub struct While<'a> {
 pub type Block<'a> = Vec<Statement<'a>>;
 
 #[derive(Debug)]
+pub struct Function<'a> {
+    pub name: Token<'a>,
+    pub params: Vec<Token<'a>>,
+    pub body: Block<'a>,
+}
+
+#[derive(Debug)]
 pub enum Statement<'a> {
     Expr(Expr<'a>),
     Print(Expr<'a>),
@@ -101,6 +108,7 @@ pub enum Statement<'a> {
     Block(Block<'a>),
     If(If<'a>),
     While(While<'a>),
+    Function(Function<'a>),
 }
 
 // Parser
@@ -108,9 +116,15 @@ pub enum Statement<'a> {
 /*
 program        → declaration* EOF ;
 
-declaration    → varDecl
+declaration    → funDecl
+               | varDecl
                | statement ;
 
+funDecl        → "fun" function ;
+function       → IDENTIFIER "(" parameters? ")" block ;
+parameters     → IDENTIFIER ( "," IDENTIFIER )* ;
+
+
 statement      → exprStmt
                | forStmt
                | ifStmt
@@ -159,6 +173,10 @@ impl<'a> Parser<'a> {
     // recursive-descent parser functions
 
     fn declaration(&mut self) -> StmtResult<'a> {
+        if self.match_token(&TokenKind::Fun) {
+            return self.function();
+        }
+
         if self.match_token(&TokenKind::Var) {
             return self.var_declaration();
         }
@@ -166,6 +184,50 @@ impl<'a> Parser<'a> {
         self.statement()
     }
 
+    fn function(&mut self) -> StmtResult<'a> {
+        let name = self.identifier("Expected function name.")?;
+
+        self.consume(
+            &TokenKind::LeftParen,
+            ErrorKind::ExpectedToken("Expect '(' after function name."),
+        )?;
+
+        let mut params = vec![];
+
+        if !self.check_token(&TokenKind::RightParen) {
+            loop {
+                if params.len() >= 255 {
+                    return Err(Error {
+                        line: self.peek().line,
+                        kind: ErrorKind::InternalError("255 parameter limit exceeded.".into()),
+                    });
+                }
+
+                params.push(self.identifier("Expected parameter name.")?);
+
+                if !self.match_token(&TokenKind::Comma) {
+                    break;
+                }
+            }
+        }
+
+        self.consume(
+            &TokenKind::RightParen,
+            ErrorKind::ExpectedToken("Expect ')' after parameters."),
+        )?;
+
+        self.consume(
+            &TokenKind::LeftBrace,
+            ErrorKind::ExpectedToken("Expect '{' before function body."),
+        )?;
+
+        Ok(Statement::Function(Function {
+            name,
+            params,
+            body: self.block_statement()?,
+        }))
+    }
+
     fn var_declaration(&mut self) -> StmtResult<'a> {
         // Since `TokenKind::Identifier` carries data, we can't use
         // `consume`.
@@ -186,7 +248,7 @@ impl<'a> Parser<'a> {
         if self.match_token(&TokenKind::Print) {
             self.print_statement()
         } else if self.match_token(&TokenKind::LeftBrace) {
-            self.block_statement()
+            Ok(Statement::Block(self.block_statement()?))
         } else if self.match_token(&TokenKind::If) {
             self.if_statement()
         } else if self.match_token(&TokenKind::While) {
@@ -204,7 +266,7 @@ impl<'a> Parser<'a> {
         Ok(Statement::Print(expr))
     }
 
-    fn block_statement(&mut self) -> StmtResult<'a> {
+    fn block_statement(&mut self) -> Result<Block<'a>, Error> {
         let mut block: Block<'a> = vec![];
 
         while !self.check_token(&TokenKind::RightBrace) && !self.is_at_end() {
@@ -213,7 +275,7 @@ impl<'a> Parser<'a> {
 
         self.consume(&TokenKind::RightBrace, ErrorKind::ExpectedClosingBrace)?;
 
-        Ok(Statement::Block(block))
+        Ok(block)
     }
 
     fn if_statement(&mut self) -> StmtResult<'a> {