feat(tazjin/rlox): Parse & interpret while statements

Change-Id: Iee772274de95dfd6a6d4af973402859aeda17b1d
Reviewed-on: https://cl.tvl.fyi/c/depot/+/2325
Reviewed-by: tazjin <mail@tazj.in>
Tested-by: BuildkiteCI
This commit is contained in:
Vincent Ambo 2021-01-06 20:49:20 +03:00 committed by tazjin
parent 0a0335ae6c
commit d47e55ba4d
2 changed files with 40 additions and 0 deletions

View file

@ -128,6 +128,7 @@ impl Interpreter {
Statement::Var(var) => return self.interpret_var(var), Statement::Var(var) => return self.interpret_var(var),
Statement::Block(block) => return self.interpret_block(block), Statement::Block(block) => return self.interpret_block(block),
Statement::If(if_stmt) => return self.interpret_if(if_stmt), Statement::If(if_stmt) => return self.interpret_if(if_stmt),
Statement::While(while_stmt) => return self.interpret_while(while_stmt),
} }
Ok(()) Ok(())
@ -172,6 +173,14 @@ impl Interpreter {
} }
} }
fn interpret_while<'a>(&mut self, stmt: &parser::While<'a>) -> Result<(), Error> {
while eval_truthy(&self.eval(&stmt.condition)?) {
self.interpret_stmt(&stmt.body)?;
}
Ok(())
}
fn eval<'a>(&mut self, expr: &Expr<'a>) -> Result<Literal, Error> { fn eval<'a>(&mut self, expr: &Expr<'a>) -> Result<Literal, Error> {
match expr { match expr {
Expr::Assign(assign) => self.eval_assign(assign), Expr::Assign(assign) => self.eval_assign(assign),

View file

@ -77,6 +77,12 @@ pub struct If<'a> {
pub else_branch: Option<Box<Statement<'a>>>, pub else_branch: Option<Box<Statement<'a>>>,
} }
#[derive(Debug)]
pub struct While<'a> {
pub condition: Expr<'a>,
pub body: Box<Statement<'a>>,
}
pub type Block<'a> = Vec<Statement<'a>>; pub type Block<'a> = Vec<Statement<'a>>;
#[derive(Debug)] #[derive(Debug)]
@ -86,6 +92,7 @@ pub enum Statement<'a> {
Var(Var<'a>), Var(Var<'a>),
Block(Block<'a>), Block(Block<'a>),
If(If<'a>), If(If<'a>),
While(While<'a>),
} }
// Parser // Parser
@ -99,8 +106,11 @@ declaration → varDecl
statement exprStmt statement exprStmt
| ifStmt | ifStmt
| printStmt | printStmt
| whileStmt
| block ; | block ;
whileStmt "while" "(" expression ")" statement ;
exprStmt expression ";" ; exprStmt expression ";" ;
ifStmt "if" "(" expression ")" statement ifStmt "if" "(" expression ")" statement
@ -172,6 +182,8 @@ impl<'a> Parser<'a> {
self.block_statement() self.block_statement()
} else if self.match_token(&[TokenKind::If]) { } else if self.match_token(&[TokenKind::If]) {
self.if_statement() self.if_statement()
} else if self.match_token(&[TokenKind::While]) {
self.while_statement()
} else { } else {
self.expr_statement() self.expr_statement()
} }
@ -221,6 +233,25 @@ impl<'a> Parser<'a> {
Ok(Statement::If(stmt)) Ok(Statement::If(stmt))
} }
fn while_statement(&mut self) -> StmtResult<'a> {
self.consume(
&TokenKind::LeftParen,
ErrorKind::ExpectedToken("Expected '(' after 'while'"),
)?;
let condition = self.expression()?;
self.consume(
&TokenKind::RightParen,
ErrorKind::ExpectedToken("Expected ')' after 'while'"),
)?;
Ok(Statement::While(While {
condition,
body: Box::new(self.statement()?),
}))
}
fn expr_statement(&mut self) -> StmtResult<'a> { fn expr_statement(&mut self) -> StmtResult<'a> {
let expr = self.expression()?; let expr = self.expression()?;
self.consume(&TokenKind::Semicolon, ErrorKind::ExpectedSemicolon)?; self.consume(&TokenKind::Semicolon, ErrorKind::ExpectedSemicolon)?;