feat: add while loops

This commit is contained in:
2026-02-06 02:06:06 +01:00
parent 57eecb8a65
commit be1b03bb1f
5 changed files with 41 additions and 3 deletions

13
examples/10_while.peb Normal file
View File

@@ -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
}

View File

@@ -13,7 +13,7 @@ def main():
123 123
"This is "This is
another string" """ another string" """
path: str = "examples/09_logical.peb" path: str = "examples/10_while.peb"
with open(path, "r") as f: with open(path, "r") as f:
source = f.read() source = f.read()
lexer: Lexer = Lexer() lexer: Lexer = Lexer()

View File

@@ -37,6 +37,10 @@ class Stmt(ABC):
def visit_let_stmt(self, stmt: LetStmt) -> T: def visit_let_stmt(self, stmt: LetStmt) -> T:
... ...
@abstractmethod
def visit_while_stmt(self, stmt: WhileStmt) -> T:
...
@dataclass(frozen=True) @dataclass(frozen=True)
class BlockStmt(Stmt): class BlockStmt(Stmt):
@@ -79,3 +83,13 @@ class LetStmt(Stmt):
def accept(self, visitor: Stmt.Visitor[T]) -> T: def accept(self, visitor: Stmt.Visitor[T]) -> T:
return visitor.visit_let_stmt(self) 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)

View File

@@ -1,7 +1,7 @@
from typing import Any from typing import Any
from src.ast.expr import LiteralExpr, GroupingExpr, UnaryExpr, BinaryExpr, Expr, VariableExpr, AssignExpr, LogicalExpr 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.environment import Environment
from src.interpreter.error import PebbleRuntimeError from src.interpreter.error import PebbleRuntimeError
from src.pebble import Pebble from src.pebble import Pebble
@@ -133,6 +133,10 @@ class Interpreter(Expr.Visitor[Any], Stmt.Visitor[None]):
value: Any = self.evaluate(stmt.expression) value: Any = self.evaluate(stmt.expression)
print(value) 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: def visit_let_stmt(self, stmt: LetStmt) -> None:
value: Any = None value: Any = None
if stmt.initializer is not None: if stmt.initializer is not None:

View File

@@ -1,7 +1,7 @@
from typing import Optional from typing import Optional
from src.ast.expr import Expr, BinaryExpr, UnaryExpr, LiteralExpr, GroupingExpr, VariableExpr, AssignExpr, LogicalExpr 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.parser.error import ParsingError
from src.pebble import Pebble from src.pebble import Pebble
from src.token import Token, TokenType from src.token import Token, TokenType
@@ -111,6 +111,8 @@ class Parser:
return self.if_stmt() return self.if_stmt()
if self.match(TokenType.PRINT): if self.match(TokenType.PRINT):
return self.print_stmt() return self.print_stmt()
if self.match(TokenType.WHILE):
return self.while_stmt()
if self.match(TokenType.LEFT_BRACE): if self.match(TokenType.LEFT_BRACE):
return self.block_stmt() return self.block_stmt()
return self.expression_stmt() return self.expression_stmt()
@@ -130,6 +132,11 @@ class Parser:
self.expect_eol("Expected end of line after statement") self.expect_eol("Expected end of line after statement")
return PrintStmt(value) 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: def block_stmt(self) -> Stmt:
statements: list[Stmt] = [] statements: list[Stmt] = []
self.skip_newlines() self.skip_newlines()