# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. ========= # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ========= Copyright 2026 @ Strukto.AI All Rights Reserved. ========= from dataclasses import dataclass, field @dataclass class CallFrame: positional: list[str] = field(default_factory=list) locals: dict[str, str] = field(default_factory=dict) function_name: str = "" loop_level: int = 0 class CallStack: def __init__(self) -> None: self._frames: list[CallFrame] = [CallFrame()] @property def current(self) -> CallFrame: return self._frames[-1] def push(self, positional: list[str] | None = None, function_name: str = "") -> None: self._frames.append( CallFrame( positional=positional or [], function_name=function_name, )) def pop(self) -> CallFrame: if len(self._frames) <= 1: return self._frames[0] return self._frames.pop() @property def depth(self) -> int: return len(self._frames) def get_positional(self, index: int) -> str: pos = self.current.positional if 0 < index <= len(pos): return pos[index - 1] return "" def get_all_positional(self) -> list[str]: return self.current.positional def get_positional_count(self) -> int: return len(self.current.positional) def shift(self, n: int = 1) -> None: self.current.positional = self.current.positional[n:] def set_positional(self, values: list[str]) -> None: self.current.positional = values def set_local(self, name: str, value: str) -> None: self.current.locals[name] = value def get_local(self, name: str) -> str | None: for frame in reversed(self._frames): if name in frame.locals: return frame.locals[name] return None