|
|
|
@ -11,16 +11,40 @@ from .util import seeking |
|
|
|
|
from .io import Segment, Stream, Pos |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
T = TypeVar('T') |
|
|
|
|
|
|
|
|
|
class DebugTreeNode(Generic[T]): |
|
|
|
|
__slots__ = ('type', 'pos', 'end', 'value', 'children') |
|
|
|
|
|
|
|
|
|
def __init__(self, type: 'Type[T]', pos: Pos = None) -> None: |
|
|
|
|
self.type = type |
|
|
|
|
self.pos = pos |
|
|
|
|
self.value = None |
|
|
|
|
self.end = None |
|
|
|
|
self.children = [] |
|
|
|
|
|
|
|
|
|
def finalize(self, value: T, end: Pos) -> None: |
|
|
|
|
self.value = value |
|
|
|
|
self.end = end |
|
|
|
|
|
|
|
|
|
def add_child(self, ident, node: 'DebugTreeNode') -> None: |
|
|
|
|
self.children.append((ident, node)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Params: |
|
|
|
|
__slots__ = ('segments', 'default_segment', 'user') |
|
|
|
|
__slots__ = ('segments', 'default_segment', 'user', 'debug_path', 'debug_root') |
|
|
|
|
|
|
|
|
|
def __init__(self, segments: Sequence[Segment] = None, user: Mapping[str, Any] = {}): |
|
|
|
|
def __init__(self, segments: Sequence[Segment] = None, user: Mapping[str, Any] = {}, debug: bool = False): |
|
|
|
|
default = segments[0] if segments else Segment('default') |
|
|
|
|
self.segments = {s.name: s for s in (segments or [default, Segment('refs', [default])])} |
|
|
|
|
self.default_segment = default |
|
|
|
|
self.user = SimpleNamespace(**user) |
|
|
|
|
self.debug_path: O[List[DebugTreeNode]] = [] if debug else None |
|
|
|
|
self.debug_root: O[DebugTreeNode] = None |
|
|
|
|
|
|
|
|
|
def reset(self): |
|
|
|
|
self.debug_root = None |
|
|
|
|
self.debug_path = [] if self.debug_path is not None else None |
|
|
|
|
for s in self.segments.values(): |
|
|
|
|
s.reset() |
|
|
|
|
|
|
|
|
@ -45,10 +69,8 @@ def format_path(path: Iterable[PathElement]) -> str: |
|
|
|
|
return s |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
T = TypeVar('T') |
|
|
|
|
PT = TypeVar('PT') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PossibleDynamic(Generic[T]): |
|
|
|
|
pass |
|
|
|
|
|
|
|
|
@ -62,6 +84,8 @@ class Context: |
|
|
|
|
self.path: List[PathEntry] = [] |
|
|
|
|
self.segment_path: List[Segment] = [] |
|
|
|
|
|
|
|
|
|
self.params.reset() |
|
|
|
|
|
|
|
|
|
def copy(self) -> 'Context': |
|
|
|
|
c = self.__class__(root=self.root, value=self.value, params=self.params) |
|
|
|
|
c.path = self.path.copy() |
|
|
|
@ -144,7 +168,21 @@ class Context: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def parse(self, type: 'Type[PT]', stream: Stream) -> PT: |
|
|
|
|
return type.parse(self, stream) |
|
|
|
|
if self.params.debug_path is not None: |
|
|
|
|
node = DebugTreeNode(type, stream.root.tell()) |
|
|
|
|
if self.params.debug_path: |
|
|
|
|
self.params.debug_path[-1].add_child(self.path[-1][0], node) |
|
|
|
|
else: |
|
|
|
|
self.params.debug_root = node |
|
|
|
|
self.params.debug_path.append(node) |
|
|
|
|
value = None |
|
|
|
|
try: |
|
|
|
|
value = type.parse(self, stream) |
|
|
|
|
return value |
|
|
|
|
finally: |
|
|
|
|
if self.params.debug_path is not None: |
|
|
|
|
node.finalize(value, stream.root.tell()) |
|
|
|
|
self.params.debug_path.pop() |
|
|
|
|
|
|
|
|
|
def dump(self, type: 'Type[PT]', stream: Stream, value: PT) -> None: |
|
|
|
|
return type.dump(self, stream, value) |
|
|
|
|