diff options
author | Vincent Ambo <mail@tazj.in> | 2020-12-20T22·55+0100 |
---|---|---|
committer | tazjin <mail@tazj.in> | 2020-12-22T10·13+0000 |
commit | 75ae25daa9e7686bca60b518d9cf442bcfba3bf7 (patch) | |
tree | ad9fa978d10be144010fd41b26b272f3e0ad0fd5 /users/tazjin/rlox/src/parser.rs | |
parent | c3bbb861b8a97f7ea0df51f56bacf14145350a42 (diff) |
feat(tazjin/rlox): Add support for statements r/2024
First part of https://craftinginterpreters.com/statements-and-state.html Supports print statements, as well as evaluation for the sake of it (i.e. future side-effects). Change-Id: Ic6653b568f98d6cfe3f297615b7113c0ba1d9a70 Reviewed-on: https://cl.tvl.fyi/c/depot/+/2287 Reviewed-by: tazjin <mail@tazj.in> Tested-by: BuildkiteCI
Diffstat (limited to 'users/tazjin/rlox/src/parser.rs')
-rw-r--r-- | users/tazjin/rlox/src/parser.rs | 65 |
1 files changed, 47 insertions, 18 deletions
diff --git a/users/tazjin/rlox/src/parser.rs b/users/tazjin/rlox/src/parser.rs index 611a99f01c22..d7155fff10a7 100644 --- a/users/tazjin/rlox/src/parser.rs +++ b/users/tazjin/rlox/src/parser.rs @@ -42,9 +42,25 @@ pub enum Expr<'a> { Unary(Unary<'a>), } +#[derive(Debug)] +pub enum Statement<'a> { + Expr(Expr<'a>), + Print(Expr<'a>), +} + +pub type Program<'a> = Vec<Statement<'a>>; + // Parser /* +program → statement* EOF ; + +statement → exprStmt + | printStmt ; + +exprStmt → expression ";" ; +printStmt → "print" expression ";" ; + expression → equality ; equality → comparison ( ( "!=" | "==" ) comparison )* ; comparison → term ( ( ">" | ">=" | "<" | "<=" ) term )* ; @@ -62,10 +78,31 @@ struct Parser<'a> { } type ExprResult<'a> = Result<Expr<'a>, Error>; +type StmtResult<'a> = Result<Statement<'a>, Error>; impl<'a> Parser<'a> { // recursive-descent parser functions + fn statement(&mut self) -> StmtResult<'a> { + if self.match_token(&[TokenKind::Print]) { + self.print_statement() + } else { + self.expr_statement() + } + } + + fn print_statement(&mut self) -> StmtResult<'a> { + let expr = self.expression()?; + self.consume(&TokenKind::Semicolon, ErrorKind::ExpectedSemicolon)?; + Ok(Statement::Print(expr)) + } + + fn expr_statement(&mut self) -> StmtResult<'a> { + let expr = self.expression()?; + self.consume(&TokenKind::Semicolon, ErrorKind::ExpectedSemicolon)?; + Ok(Statement::Expr(expr)) + } + fn expression(&mut self) -> ExprResult<'a> { self.equality() } @@ -231,34 +268,26 @@ impl<'a> Parser<'a> { } } -pub fn parse<'a>(tokens: Vec<Token<'a>>) -> Result<Expr<'a>, Vec<Error>> { +pub fn parse<'a>(tokens: Vec<Token<'a>>) -> Result<Program<'a>, Vec<Error>> { let mut parser = Parser { tokens, current: 0 }; + let mut program: Program<'a> = vec![]; let mut errors: Vec<Error> = vec![]; while !parser.is_at_end() { - match parser.expression() { + match parser.statement() { Err(err) => { errors.push(err); parser.synchronise(); } - Ok(expr) => { - if !parser.is_at_end() { - // TODO(tazjin): This isn't a functional language - // - multiple statements should be allowed, at - // some point. - let current = &parser.tokens[parser.current]; - errors.push(Error { - line: current.line, - kind: ErrorKind::UnexpectedChar(current.lexeme[0]), - }); - } - - if errors.is_empty() { - return Ok(expr); - } + Ok(stmt) => { + program.push(stmt); } } } - return Err(errors); + if errors.is_empty() { + Ok(program) + } else { + Err(errors) + } } |