From 330486fb816be5dc5728cf24ce01886c7d24afa5 Mon Sep 17 00:00:00 2001 From: LordBaryhobal Date: Fri, 6 Feb 2026 01:12:12 +0100 Subject: [PATCH] feat: add if statements --- examples/04_if_else.peb | 2 +- main.py | 2 +- src/ast/stmt.py | 14 ++++++++++++++ src/interpreter/interpreter.py | 8 +++++++- src/parser/parser.py | 12 +++++++++++- 5 files changed, 34 insertions(+), 4 deletions(-) diff --git a/examples/04_if_else.peb b/examples/04_if_else.peb index 7552429..f01f7f5 100644 --- a/examples/04_if_else.peb +++ b/examples/04_if_else.peb @@ -3,7 +3,7 @@ let age = 14 if age >= 18 { print("You are an adult") } else { - print("You are a child) + print("You are a child") } let guess = 12 diff --git a/main.py b/main.py index f412fe2..2ea2368 100644 --- a/main.py +++ b/main.py @@ -13,7 +13,7 @@ def main(): 123 "This is another string" """ - path: str = "examples/08_scopes.peb" + path: str = "examples/04_if_else.peb" with open(path, "r") as f: source = f.read() lexer: Lexer = Lexer() diff --git a/src/ast/stmt.py b/src/ast/stmt.py index 778d3ce..6441733 100644 --- a/src/ast/stmt.py +++ b/src/ast/stmt.py @@ -25,6 +25,10 @@ class Stmt(ABC): def visit_expression_stmt(self, stmt: ExpressionStmt) -> T: ... + @abstractmethod + def visit_if_stmt(self, stmt: IfStmt) -> T: + ... + @abstractmethod def visit_print_stmt(self, stmt: PrintStmt) -> T: ... @@ -50,6 +54,16 @@ class ExpressionStmt(Stmt): return visitor.visit_expression_stmt(self) +@dataclass(frozen=True) +class IfStmt(Stmt): + condition: Expr + then_branch: Stmt + else_branch: Optional[Stmt] + + def accept(self, visitor: Stmt.Visitor[T]) -> T: + return visitor.visit_if_stmt(self) + + @dataclass(frozen=True) class PrintStmt(Stmt): expression: Expr diff --git a/src/interpreter/interpreter.py b/src/interpreter/interpreter.py index fce0c3e..c4c9a35 100644 --- a/src/interpreter/interpreter.py +++ b/src/interpreter/interpreter.py @@ -1,7 +1,7 @@ from typing import Any from src.ast.expr import LiteralExpr, GroupingExpr, UnaryExpr, BinaryExpr, Expr, VariableExpr, AssignExpr -from src.ast.stmt import Stmt, PrintStmt, ExpressionStmt, LetStmt, BlockStmt +from src.ast.stmt import Stmt, PrintStmt, ExpressionStmt, LetStmt, BlockStmt, IfStmt from src.interpreter.environment import Environment from src.interpreter.error import PebbleRuntimeError from src.pebble import Pebble @@ -108,6 +108,12 @@ class Interpreter(Expr.Visitor[Any], Stmt.Visitor[None]): def visit_expression_stmt(self, stmt: ExpressionStmt) -> None: self.evaluate(stmt.expression) + def visit_if_stmt(self, stmt: IfStmt) -> None: + if self.is_truthy(self.evaluate(stmt.condition)): + self.execute(stmt.then_branch) + elif stmt.else_branch is not None: + self.execute(stmt.else_branch) + def visit_print_stmt(self, stmt: PrintStmt) -> None: value: Any = self.evaluate(stmt.expression) print(value) diff --git a/src/parser/parser.py b/src/parser/parser.py index dce12fa..788d61a 100644 --- a/src/parser/parser.py +++ b/src/parser/parser.py @@ -1,7 +1,7 @@ from typing import Optional from src.ast.expr import Expr, BinaryExpr, UnaryExpr, LiteralExpr, GroupingExpr, VariableExpr, AssignExpr -from src.ast.stmt import Stmt, PrintStmt, ExpressionStmt, LetStmt, BlockStmt +from src.ast.stmt import Stmt, PrintStmt, ExpressionStmt, LetStmt, BlockStmt, IfStmt from src.parser.error import ParsingError from src.pebble import Pebble from src.token import Token, TokenType @@ -107,12 +107,22 @@ class Parser: return LetStmt(name, initializer) def statement(self) -> Stmt: + if self.match(TokenType.IF): + return self.if_stmt() if self.match(TokenType.PRINT): return self.print_stmt() if self.match(TokenType.LEFT_BRACE): return self.block_stmt() return self.expression_stmt() + def if_stmt(self) -> Stmt: + condition: Expr = self.expression() + then_branch: Stmt = self.statement() + else_branch: Optional[Stmt] = None + if self.match(TokenType.ELSE): + else_branch = self.statement() + return IfStmt(condition, then_branch, else_branch) + def print_stmt(self) -> Stmt: self.consume(TokenType.LEFT_PAREN, "Missing parentheses") value: Expr = self.expression()