from typing import TYPE_CHECKING, Any if TYPE_CHECKING: from .terms import ExecutorTerm class ExecContext: """ Base context class that carries the instantiation state. This is passed to all CommandTerms upon execution. """ def __init__(self, *, alias: str, args: list[str], content: str, initial_globals: dict[str, Any] = {}, **kwargs): self.alias = alias self.args = args self.content = content # Stack of scopes # Initialising globals this way to avoid modifying default arg globals = {} | initial_globals self.scopes: list[dict[str, Any]] = [globals] # Stack of terms that are *currently* executing with this context. self.termstack: list['ExecutorTerm'] = [] def enter_scope(self, *args, **kwargs): new_scope = dict(*args, **kwargs) self.scopes.append(new_scope) def leave_scope(self): if len(self.scopes) > 1: self.scopes.pop() else: raise ValueError("Cannot leave global scope") @property def scope(self): # TODO: Move this to a more efficient ExecScope mapping type at some point fullscope = {} for scope in self.scopes: fullscope |= scope return fullscope @property def this_scope(self): return self.scopes[-1]