feat(tazjin/rlox): Parse function declarations

Change-Id: I1db4316563827976e5233dc7a626968f80b992ef
Reviewed-on: https://cl.tvl.fyi/c/depot/+/2390
Reviewed-by: tazjin <mail@tazj.in>
Tested-by: BuildkiteCI
This commit is contained in:
Vincent Ambo 2021-01-14 05:02:50 +03:00 committed by tazjin
parent 8bcbb04160
commit 1ed34443d8
2 changed files with 67 additions and 4 deletions

View file

@ -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)

View file

@ -93,6 +93,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>),
@ -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> {