diff options
Diffstat (limited to 'abdl/_vm.py')
-rw-r--r-- | abdl/_vm.py | 40 |
1 files changed, 29 insertions, 11 deletions
diff --git a/abdl/_vm.py b/abdl/_vm.py index 0ec1018..5ab7efb 100644 --- a/abdl/_vm.py +++ b/abdl/_vm.py @@ -41,6 +41,14 @@ class PatternElement: """ raise RuntimeError(self) + def on_end(self, frame, path, defs, in_key): + """Called when the pattern has reached the end. + + Returns the new value of in_key and a dict to be yielded, or + None and a dict to be yielded. + """ + raise RuntimeError(self) + def collect_params(self, res: list): """Appends parameter names used in this pattern to ``res``. """ @@ -245,6 +253,10 @@ class ApplyPredicate(PatternElement): def collect_params(self, res: list): res.append(self.key) + def on_end(self, frame, path, defs, in_key): + assert not in_key + raise NotImplementedError + class End(PatternElement): """Pseudo-token, used to advance iteration.""" @@ -260,6 +272,19 @@ class End(PatternElement): path.clear() return True + def on_end(self, frame, path, defs, in_key): + assert not path[-1].empty + res = {} + for holder in path: + if holder.subtree: + for name, pair in holder.match.items(): + res[name] = pair + elif holder.name is not None: + res[holder.name] = (holder.match, holder.value) + if not frame.prev(): + return (None, res) + return (True, res) + @classmethod def action(cls, toks): return [cls()] @@ -356,24 +381,17 @@ def match_helper(ops, defs, tree): """ frame = _Frame(ops) + if not len(frame.ops): # no ops? + return # do nothing path = [Holder(value=tree, parent=None, iterator=iter(()))] in_key = False while path: if not frame.next(): - assert not path[-1].empty - res = {} - for holder in path: - if holder.subtree: - for name, pair in holder.match.items(): - res[name] = pair - elif holder.name is not None: - res[holder.name] = (holder.match, holder.value) + in_key, res = frame.current_op.on_end(frame, path, defs, in_key) yield res - assert len(path) == 1 or isinstance(frame.current_op, End) - if not frame.prev(): + if in_key is None: return - in_key = True else: if in_key: in_key = frame.current_op.on_in_key(frame, path, defs) |