core: allow debug tracing of parse for visualisations

This commit is contained in:
Shiz 2021-07-04 23:40:46 +02:00
parent ea61dbf1e3
commit 8bf9b77505
1 changed files with 44 additions and 6 deletions

View File

@ -11,16 +11,40 @@ from .util import seeking
from .io import Segment, Stream, Pos
class Params:
__slots__ = ('segments', 'default_segment', 'user')
T = TypeVar('T')
def __init__(self, segments: Sequence[Segment] = None, user: Mapping[str, Any] = {}):
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', 'debug_path', 'debug_root')
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)