From f2e996aaa91bc6e1dab5e773b0b9869d0a3f302a Mon Sep 17 00:00:00 2001 From: LordBaryhobal Date: Thu, 5 Feb 2026 23:29:20 +0100 Subject: [PATCH] feat(interpreter): add enclosing environment parameter --- src/interpreter/environment.py | 34 ++++++++++++++++++++++++++++++++++ src/interpreter/interpreter.py | 26 +++----------------------- 2 files changed, 37 insertions(+), 23 deletions(-) create mode 100644 src/interpreter/environment.py diff --git a/src/interpreter/environment.py b/src/interpreter/environment.py new file mode 100644 index 0000000..9fbc51d --- /dev/null +++ b/src/interpreter/environment.py @@ -0,0 +1,34 @@ +from __future__ import annotations + +from typing import Any, Optional + +from src.interpreter.error import PebbleRuntimeError +from src.token import Token + + +class Environment: + def __init__(self, enclosing: Optional[Environment] = None): + self.enclosing: Optional[Environment] = enclosing + self.values: dict[str, Any] = {} + + def define(self, name: str, value: Any): + self.values[name] = value + + def get(self, name: Token) -> Any: + try: + return self.values[name.lexeme] + except IndexError: + if self.enclosing is not None: + return self.enclosing.get(name) + raise PebbleRuntimeError(name, f"Undefined variable '{name.lexeme}'.") + + def assign(self, name: Token, value: Any): + if name.lexeme not in self.values: + if self.enclosing is not None: + self.enclosing.assign(name, value) + return + raise PebbleRuntimeError(name, f"Undefined variable '{name.lexeme}'.") + self.values[name.lexeme] = value + + def clear(self): + self.values = {} diff --git a/src/interpreter/interpreter.py b/src/interpreter/interpreter.py index 3c24fa5..2d6c67e 100644 --- a/src/interpreter/interpreter.py +++ b/src/interpreter/interpreter.py @@ -1,36 +1,16 @@ from typing import Any from src.ast.expr import LiteralExpr, GroupingExpr, UnaryExpr, BinaryExpr, Expr, VariableExpr, AssignExpr -from src.ast.stmt import Stmt, PrintStmt, T, ExpressionStmt, LetStmt +from src.ast.stmt import Stmt, PrintStmt, ExpressionStmt, LetStmt +from src.interpreter.environment import Environment from src.interpreter.error import PebbleRuntimeError from src.pebble import Pebble from src.token import TokenType, Token class Interpreter(Expr.Visitor[Any], Stmt.Visitor[None]): - class Environment: - def __init__(self): - self.values: dict[str, Any] = {} - - def define(self, name: str, value: Any): - self.values[name] = value - - def get(self, name: Token) -> Any: - try: - return self.values[name.lexeme] - except IndexError: - raise PebbleRuntimeError(name, f"Undefined variable '{name.lexeme}'.") - - def assign(self, name: Token, value: Any): - if name.lexeme not in self.values: - raise PebbleRuntimeError(name, f"Undefined variable '{name.lexeme}'.") - self.values[name.lexeme] = value - - def clear(self): - self.values = {} - def __init__(self): - self.env: Interpreter.Environment = Interpreter.Environment() + self.env: Environment = Environment() def interpret(self, statements: list[Stmt]) -> None: self.env.clear()