From 1ed34443d832fcfd7b683ecdcb58b0c445443def Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Thu, 14 Jan 2021 05:02:50 +0300 Subject: feat(tazjin/rlox): Parse function declarations Change-Id: I1db4316563827976e5233dc7a626968f80b992ef Reviewed-on: https://cl.tvl.fyi/c/depot/+/2390 Reviewed-by: tazjin Tested-by: BuildkiteCI --- users/tazjin/rlox/src/interpreter.rs | 1 + users/tazjin/rlox/src/parser.rs | 70 +++++++++++++++++++++++++++++++++--- 2 files changed, 67 insertions(+), 4 deletions(-) (limited to 'users/tazjin/rlox') diff --git a/users/tazjin/rlox/src/interpreter.rs b/users/tazjin/rlox/src/interpreter.rs index cccc381b3258..6aab389369ea 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 74c2f448ede9..626eda641c03 100644 --- a/users/tazjin/rlox/src/parser.rs +++ b/users/tazjin/rlox/src/parser.rs @@ -93,6 +93,13 @@ pub struct While<'a> { pub type Block<'a> = Vec>; +#[derive(Debug)] +pub struct Function<'a> { + pub name: Token<'a>, + pub params: Vec>, + pub body: Block<'a>, +} + #[derive(Debug)] pub enum Statement<'a> { Expr(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, 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> { -- cgit 1.4.1