123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475 |
- from typing import *
- from dataclasses import *
- from sccd.util.bitmap import *
- from sccd.util.debug import *
- from sccd.action_lang.static.scope import *
- from sccd.common.exceptions import *
- from sccd.action_lang.static.expression import *
- @dataclass(frozen=True)
- class StackFrame:
- __slots__ = ["storage", "parent", "context", "scope"]
- # Values of variables in the frame.
- storage: List[Any]
- # The previous stack frame, forming a linked list of stack frames representing the "call stack".
- # The parent frame will become the "current frame" when this stack frame is popped.
- parent: Optional['StackFrame']
- # The sequence of 'context' values forms another linked list, often but not always identical to the linked list of 'parent's, for accessing nonlocal variables.
- # The 'context' is the stack frame in which the frame of the currently called function was declared.
- # This could be a stack frame that no longer exists on "the stack", like with a function closure, or some ancestor, for a recursive function.
- # If the current scope is not a function, this value is equal to the 'parent' field.
- context: Optional['StackFrame']
- # We need this to know where the offsets of this scope start relative to the offsets of the parent scope, and to print variable names in error messages.
- scope: Scope
- def __str__(self):
- def short_descr(frame):
- return "StackFrame(%s, len=%d, ...)" % (frame.scope.name, len(frame.storage)) if frame else "None"
- return "StackFrame(%s, len=%d, parent=%s, context=%s)" % (self.scope.name, len(self.storage), short_descr(self.parent), "parent" if self.context is self.parent else short_descr(self.context))
- class Memory(MemoryInterface):
- __slots__ = ["_current_frame"]
- def __init__(self):
- self._current_frame = None
- def current_frame(self) -> StackFrame:
- return self._current_frame
- # For function calls: context MAY differ from _current_frame if the function was
- # called from a different context from where it was created.
- # This enables function closures.
- def push_frame_w_context(self, scope: Scope, context: StackFrame):
- self._current_frame = StackFrame(
- storage=[None]*scope.size(),
- parent=self._current_frame,
- context=context,
- scope=scope)
- def push_frame(self, scope: Scope):
- self.push_frame_w_context(scope, self._current_frame)
- def pop_frame(self):
- self._current_frame = self._current_frame.parent
- def _get_frame(self, offset: int) -> Tuple[StackFrame, int]:
- frame = self._current_frame
- while offset < 0:
- offset += frame.scope.parent_offset
- frame = frame.context
- return (frame, offset)
- def load(self, offset: int) -> Any:
- frame, offset = self._get_frame(offset)
- return frame.storage[offset]
- def store(self, offset: int, value: Any):
- frame, offset = self._get_frame(offset)
- frame.storage[offset] = value
|