feat: add block statements and scoped environment
This commit is contained in:
19
examples/08_scopes.peb
Normal file
19
examples/08_scopes.peb
Normal 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)
|
||||
2
main.py
2
main.py
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user