diff --git a/examples/10_while.peb b/examples/10_while.peb new file mode 100644 index 0000000..461db20 --- /dev/null +++ b/examples/10_while.peb @@ -0,0 +1,13 @@ +let i = 0 +let a = 1 +let b = 1 + +print("Fibonacci") + +while i < 10 { + print(a) + let c = a + b + a = b + b = c + i += 1 +} \ No newline at end of file diff --git a/main.py b/main.py index a048745..0a4cb36 100644 --- a/main.py +++ b/main.py @@ -13,7 +13,7 @@ def main(): 123 "This is another string" """ - path: str = "examples/09_logical.peb" + path: str = "examples/10_while.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 6441733..1cb5be6 100644 --- a/src/ast/stmt.py +++ b/src/ast/stmt.py @@ -37,6 +37,10 @@ class Stmt(ABC): def visit_let_stmt(self, stmt: LetStmt) -> T: ... + @abstractmethod + def visit_while_stmt(self, stmt: WhileStmt) -> T: + ... + @dataclass(frozen=True) class BlockStmt(Stmt): @@ -79,3 +83,13 @@ class LetStmt(Stmt): def accept(self, visitor: Stmt.Visitor[T]) -> T: return visitor.visit_let_stmt(self) + + + +@dataclass(frozen=True) +class WhileStmt(Stmt): + condition: Expr + body: Stmt + + def accept(self, visitor: Stmt.Visitor[T]) -> T: + return visitor.visit_while_stmt(self) diff --git a/src/interpreter/interpreter.py b/src/interpreter/interpreter.py index 00bc85d..6f99d24 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, LogicalExpr -from src.ast.stmt import Stmt, PrintStmt, ExpressionStmt, LetStmt, BlockStmt, IfStmt +from src.ast.stmt import Stmt, PrintStmt, ExpressionStmt, LetStmt, BlockStmt, IfStmt, WhileStmt from src.interpreter.environment import Environment from src.interpreter.error import PebbleRuntimeError from src.pebble import Pebble @@ -133,6 +133,10 @@ class Interpreter(Expr.Visitor[Any], Stmt.Visitor[None]): value: Any = self.evaluate(stmt.expression) print(value) + def visit_while_stmt(self, stmt: WhileStmt) -> None: + while self.is_truthy(self.evaluate(stmt.condition)): + self.execute(stmt.body) + def visit_let_stmt(self, stmt: LetStmt) -> None: value: Any = None if stmt.initializer is not None: diff --git a/src/parser/parser.py b/src/parser/parser.py index 613e0a3..21d8638 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, LogicalExpr -from src.ast.stmt import Stmt, PrintStmt, ExpressionStmt, LetStmt, BlockStmt, IfStmt +from src.ast.stmt import Stmt, PrintStmt, ExpressionStmt, LetStmt, BlockStmt, IfStmt, WhileStmt from src.parser.error import ParsingError from src.pebble import Pebble from src.token import Token, TokenType @@ -111,6 +111,8 @@ class Parser: return self.if_stmt() if self.match(TokenType.PRINT): return self.print_stmt() + if self.match(TokenType.WHILE): + return self.while_stmt() if self.match(TokenType.LEFT_BRACE): return self.block_stmt() return self.expression_stmt() @@ -130,6 +132,11 @@ class Parser: self.expect_eol("Expected end of line after statement") return PrintStmt(value) + def while_stmt(self) -> Stmt: + condition: Expr = self.expression() + body: Stmt = self.statement() + return WhileStmt(condition, body) + def block_stmt(self) -> Stmt: statements: list[Stmt] = [] self.skip_newlines()