~cdv/crafting-interpreters-sox

758f856aabeaf47796a3411fb9dc2cffdc129bbd — Chris Vittal 6 months ago eb6bf9f
Add for an while loops
2 files changed, 60 insertions(+), 9 deletions(-)

M src/parser.rs
M src/stmt.rs
M src/parser.rs => src/parser.rs +56 -9
@@ 41,21 41,59 @@ impl<'s> Parser<'s> {
    }

    fn statement(&mut self) -> Result<St<'s>, Error> {
        if self.matches(&[TokenType::If]) {
            return self.if_stmt();
        if self.matches(&[TokenType::For]) {
            self.for_stmt()
        } else if self.matches(&[TokenType::If]) {
            self.if_stmt()
        } else if self.matches(&[TokenType::Print]) {
            self.print_stmt()
        } else if self.matches(&[TokenType::While]) {
            self.while_stmt()
        } else if self.matches(&[TokenType::LeftBrace]) {
            Ok(St::new(Stmt::Block { stmts: self.block()?, }))
        } else {
            self.expr_stmt()
        }
    }

    fn for_stmt(&mut self) -> Result<St<'s>, Error> {
        self.consume(TokenType::LeftParen, "Expect '(' after 'for'.")?;

        let init = if self.matches(&[TokenType::Semicolon]) {
            None
        } else if self.matches(&[TokenType::Var]) {
            Some(self.var_decl()?)
        } else {
            Some(self.expr_stmt()?)
        };

        let cond = if !self.check(TokenType::Semicolon) {
            self.expression()?
        } else {
            Ex::new(Expr::Literal { val: Literal::Bool(true) })
        };
        self.consume(TokenType::Semicolon, "Expect ';' after loop condition.")?;

        if self.matches(&[TokenType::Print]) {
            return self.print_stmt();
        let incr = if !self.check(TokenType::RightParen) {
            Some(Stmt::Expr { expr: self.expression()? }.into())
        } else {
            None
        };
        self.consume(TokenType::RightParen, "Expect ')' after for clauses.")?;

        let mut body = self.statement()?;

        if let Some(incr) = incr {
            body = Stmt::Block { stmts: vec![body, incr], }.into();
        }

        if self.matches(&[TokenType::LeftBrace]) {
            return Ok(St::new(Stmt::Block {
                stmts: self.block()?,
            }));
        body = Stmt::While { cond, body }.into();

        if let Some(init) = init {
            body = Stmt::Block { stmts: vec![init, body] }.into();
        }

        self.expr_stmt()
        Ok(body)
    }

    fn if_stmt(&mut self) -> Result<St<'s>, Error> {


@@ 93,6 131,15 @@ impl<'s> Parser<'s> {
        Ok(St::new(Stmt::Var { name, init }))
    }

    fn while_stmt(&mut self) -> Result<St<'s>, Error> {
        self.consume(TokenType::LeftParen, "Expect '(' after 'while'.")?;
        let cond = self.expression()?;
        self.consume(TokenType::RightParen, "Expect ')' after condition.")?;
        let body = self.statement()?;

        Ok(St::new(Stmt::While { cond, body }))
    }

    fn expr_stmt(&mut self) -> Result<St<'s>, Error> {
        let expr = self.expression()?;
        self.consume(TokenType::Semicolon, "Expect ';' after value.")?;

M src/stmt.rs => src/stmt.rs +4 -0
@@ 22,4 22,8 @@ pub enum Stmt<'s> {
        name: Token<'s>,
        init: Option<Ex<'s>>,
    },
    While {
        cond: Ex<'s>,
        body: St<'s>,
    },
}