from __future__ import annotations from typing import Any, Callable, Optional from string import whitespace from core.primitives.symbol import symbolKey, isSymbol from core.printer import Representation from core.primitives.list import NIL class Environment: """Environment for variable bindings with lexical scoping.""" frame: dict[str, Any] parent: Environment | None def __init__(self, parent: Environment | None) -> None: self.frame: dict[str, Any] = {} self.parent: Environment | None = parent def add(self, symbol_key: Any, value: Any) -> None: """Add a new binding to the current environment frame.""" self.frame[symbolKey(symbol_key)] = value def set(self, symbol_key: Any, value: Any) -> None: """Set a binding in the environment chain.""" key: str = symbolKey(symbol_key) currentEnvironment: Environment = self while currentEnvironment is not None: if key in currentEnvironment.frame: currentEnvironment.frame[key] = value return assert currentEnvironment is Environment currentEnvironment = currentEnvironment.parent raise SyntaxError(f"no such symbol: {key}") def get(self, symbol_key: Any) -> Any: """Get a binding from the environment chain.""" key: str = symbolKey(symbol_key) currentEnvironment: Environment | None = self while currentEnvironment is not None: if key in currentEnvironment.frame: return currentEnvironment.frame[key] currentEnvironment = currentEnvironment.parent return symbol_key EVAL_NIL: Callable[[], Any] = lambda: NIL ENV: Environment = Environment(None) MEANINGFUL: str = "\"();'" IGNORE: str = whitespace + "," RepresentateAST: Callable[[Any], str] = lambda value: ( value if type(value) is str and not isSymbol(value) else Representation(value) ) TCO: bool = True