feat: add block statements and scoped environment

This commit is contained in:
HEL
2026-02-05 23:39:07 +01:00
parent 90d9f89bce
commit bf25dc81f0
5 changed files with 58 additions and 3 deletions
+19
View File
@@ -0,0 +1,19 @@
let a = "global a"
let b = "global b"
let c = "global c"
{
let a = "outer a"
let b = "outer b"
{
let a = "inner a"
print(a)
print(b)
print(c)
}
print(a)
print(b)
print(c)
}
print(a)
print(b)
print(c)
+1 -1
View File
@@ -13,7 +13,7 @@ def main():
123
"This is
another string" """
path: str = "examples/01_variables.peb"
path: str = "examples/08_scopes.peb"
with open(path, "r") as f:
source = f.read()
lexer: Lexer = Lexer()
+12
View File
@@ -17,6 +17,10 @@ class Stmt(ABC):
...
class Visitor(ABC, Generic[T]):
@abstractmethod
def visit_block_stmt(self, stmt: BlockStmt) -> T:
...
@abstractmethod
def visit_expression_stmt(self, stmt: ExpressionStmt) -> T:
...
@@ -30,6 +34,14 @@ class Stmt(ABC):
...
@dataclass(frozen=True)
class BlockStmt(Stmt):
statements: list[Stmt]
def accept(self, visitor: Stmt.Visitor[T]) -> T:
return visitor.visit_block_stmt(self)
@dataclass(frozen=True)
class ExpressionStmt(Stmt):
expression: Expr
+13 -1
View File
@@ -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
from src.ast.stmt import Stmt, PrintStmt, ExpressionStmt, LetStmt, BlockStmt
from src.interpreter.environment import Environment
from src.interpreter.error import PebbleRuntimeError
from src.pebble import Pebble
@@ -26,6 +26,15 @@ class Interpreter(Expr.Visitor[Any], Stmt.Visitor[None]):
def execute(self, stmt: Stmt) -> None:
stmt.accept(self)
def execute_block(self, statements: list[Stmt], env: Environment) -> None:
previous_env: Environment = self.env
try:
self.env = env
for stmt in statements:
self.execute(stmt)
finally:
self.env = previous_env
def visit_assign_expr(self, expr: AssignExpr) -> Any:
value: Any = self.evaluate(expr.value)
self.env.assign(expr.name, value)
@@ -93,6 +102,9 @@ class Interpreter(Expr.Visitor[Any], Stmt.Visitor[None]):
def visit_variable_expr(self, expr: VariableExpr) -> Any:
return self.env.get(expr.name)
def visit_block_stmt(self, stmt: BlockStmt) -> None:
self.execute_block(stmt.statements, Environment(self.env))
def visit_expression_stmt(self, stmt: ExpressionStmt) -> None:
self.evaluate(stmt.expression)
+13 -1
View File
@@ -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
from src.ast.stmt import Stmt, PrintStmt, ExpressionStmt, LetStmt, BlockStmt
from src.parser.error import ParsingError
from src.pebble import Pebble
from src.token import Token, TokenType
@@ -109,6 +109,8 @@ class Parser:
def statement(self) -> 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 print_stmt(self) -> Stmt:
@@ -118,6 +120,16 @@ class Parser:
self.expect_eol("Expected end of line after statement")
return PrintStmt(value)
def block_stmt(self) -> Stmt:
statements: list[Stmt] = []
self.skip_newlines()
while not self.check(TokenType.RIGHT_BRACE) and not self.is_at_end():
self.skip_newlines()
statements.append(self.declaration())
self.consume(TokenType.RIGHT_BRACE, "Expected '}' after block.")
return BlockStmt(statements)
def expression_stmt(self) -> Stmt:
value: Expr = self.expression()
self.expect_eol("Expected end of line after expression")