From 54912b7087922aae4876db6d5cd900c8fa0b3738 Mon Sep 17 00:00:00 2001 From: Seymur Bagirov Date: Thu, 16 Jan 2025 23:44:09 +0400 Subject: [PATCH] feat: finish chapter 9 --- src/ast.rs | 14 ++++++ src/interpreter.rs | 31 +++++++++++- src/parser.rs | 122 ++++++++++++++++++++++++++++++++++++++++++++- src/printer.rs | 1 + 4 files changed, 166 insertions(+), 2 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index fb03341..ad8aca3 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -29,6 +29,11 @@ pub enum Expr { name: Token, value: Box, }, + Logical { + left: Box, + op: Token, + right: Box, + }, } pub enum Stmt { @@ -38,6 +43,11 @@ pub enum Stmt { Expression { expression: Expr, }, + If { + condition: Expr, + then_branch: Box, + else_branch: Option>, + }, Print { expression: Expr, }, @@ -45,4 +55,8 @@ pub enum Stmt { name: Token, initializer: Option, }, + While { + condition: Expr, + body: Box, + }, } diff --git a/src/interpreter.rs b/src/interpreter.rs index bf313f8..71629f2 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -2,7 +2,7 @@ use std::{cell::RefCell, rc::Rc}; use crate::{ ast::{Expr, Stmt}, - environment::Environment, + environment::{self, Environment}, token::{LiteralType, Token, TokenType}, }; @@ -52,6 +52,22 @@ fn execute(statement: &Stmt, environment: &Rc>) -> Result<( Stmt::Block { statements } => { execute_block(statements, environment)?; } + Stmt::If { + condition, + then_branch, + else_branch, + } => { + if is_truthy(&evaluate(condition, &mut environment.borrow_mut())?) { + execute(then_branch, environment)?; + } else if let Some(else_branch) = else_branch { + execute(else_branch, environment)?; + } + } + Stmt::While { condition, body } => { + while is_truthy(&evaluate(condition, &mut environment.borrow_mut())?) { + execute(body, environment)?; + } + } } Ok(()) @@ -108,6 +124,19 @@ fn evaluate(expr: &Expr, environment: &mut Environment) -> Result { + let left = evaluate(left, environment)?; + + if op.t_type == TokenType::OR { + if is_truthy(&left) { + return Ok(left); + } + } else if !is_truthy(&left) { + return Ok(left); + } + + evaluate(right, environment) + } } } diff --git a/src/parser.rs b/src/parser.rs index 4940ab0..84288b2 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -71,9 +71,18 @@ impl Parser<'_> { } fn statement(&mut self) -> Result { + if self.match_token(&[TokenType::For]) { + return self.for_statement(); + } + if self.match_token(&[TokenType::If]) { + return self.if_statement(); + } if self.match_token(&[TokenType::Print]) { return self.print_statement(); } + if self.match_token(&[TokenType::While]) { + return self.while_statement(); + } if self.match_token(&[TokenType::LeftBrace]) { return Ok(Stmt::Block { @@ -96,6 +105,86 @@ impl Parser<'_> { Ok(statements) } + fn if_statement(&mut self) -> Result { + self.consume(TokenType::LeftParen, "Expect '(' after 'if'.")?; + let condition = self.expression()?; + self.consume(TokenType::RightParen, "Expect ')' after if condition.")?; + + let then_branch = Box::new(self.statement()?); + let else_branch = if self.match_token(&[TokenType::Else]) { + Some(Box::new(self.statement()?)) + } else { + None + }; + + Ok(Stmt::If { + condition, + then_branch, + else_branch, + }) + } + + fn while_statement(&mut self) -> Result { + self.consume(TokenType::LeftParen, "Expect '(' after 'while'.")?; + let condition = self.expression()?; + self.consume(TokenType::RightParen, "Expect ')' after while condition.")?; + let body = Box::new(self.statement()?); + + Ok(Stmt::While { condition, body }) + } + + fn for_statement(&mut self) -> Result { + self.consume(TokenType::LeftParen, "Expect '(' after 'for'.")?; + let initializer = if self.match_token(&[TokenType::Semicolon]) { + None + } else if self.match_token(&[TokenType::Var]) { + Some(self.var_declaration()?) + } else { + Some(self.expression_statement()?) + }; + + let condition = if !self.match_token(&[TokenType::Semicolon]) { + Some(self.expression()?) + } else { + None + }; + + self.consume(TokenType::Semicolon, "Expect ';' after loop condition")?; + + let increment = if !self.match_token(&[TokenType::RightParen]) { + Some(self.expression()?) + } else { + None + }; + + self.consume(TokenType::RightParen, "Expect ')' after for clauses.")?; + + let body = match increment { + Some(inc) => Stmt::Block { + statements: vec![self.statement()?, Stmt::Expression { expression: inc }], + }, + None => self.statement()?, + }; + + let condition = condition.unwrap_or(Expr::Literal { + value: LiteralType::Bool(true), + }); + + let body = Stmt::While { + condition, + body: Box::new(body), + }; + + let body = match initializer { + Some(init) => Stmt::Block { + statements: vec![init, body], + }, + None => body, + }; + + Ok(body) + } + fn print_statement(&mut self) -> Result { let expression = self.expression()?; self.consume(TokenType::Semicolon, "Expect ';' after value.")?; @@ -146,7 +235,7 @@ impl Parser<'_> { // ternary -> equality ("?" expression : ternary)? // expression grammar fn ternary(&mut self) -> Result { use TokenType::*; - let expr = self.equality()?; + let expr = self.or()?; if self.match_token(&[Question]) { let second = self.expression()?; @@ -162,6 +251,37 @@ impl Parser<'_> { Ok(expr) } + fn or(&mut self) -> Result { + let mut expr = self.and()?; + + while self.match_token(&[TokenType::OR]) { + let op = self.previous().clone(); + let right = self.and()?; + expr = Expr::Logical { + left: Box::new(expr), + op, + right: Box::new(right), + }; + } + + Ok(expr) + } + + fn and(&mut self) -> Result { + let mut expr = self.equality()?; + while self.match_token(&[TokenType::And]) { + let op = self.previous().clone(); + let right = self.equality()?; + expr = Expr::Logical { + left: Box::new(expr), + op, + right: Box::new(right), + }; + } + + Ok(expr) + } + fn equality(&mut self) -> Result { use TokenType::*; self.left_association_binary(&[BangEqual, EqualEqual], Self::comparison) diff --git a/src/printer.rs b/src/printer.rs index b20ab5e..9c9117b 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -18,6 +18,7 @@ pub fn pretty_print(expr: &Expr) -> String { } => parenthesize("?:", &[first, second, third]), Expr::Variable { name } => name.lexeme.clone(), Expr::Assign { name, value } => parenthesize(&name.lexeme, &[value]), + Expr::Logical { left, op, right } => parenthesize(&op.lexeme, &[left, right]), } }