diff options
author | SoniEx2 <endermoneymod@gmail.com> | 2020-04-17 14:25:21 -0300 |
---|---|---|
committer | SoniEx2 <endermoneymod@gmail.com> | 2020-04-17 14:26:01 -0300 |
commit | b259b179f5ceba60a1d04fef07559c0b01720c31 (patch) | |
tree | a0315c67fddc7919e6d6892e8d1eb15f328057a6 /abdl | |
parent | 3f9f66712aaa071bd3bb32c46e1e4dc1fed13378 (diff) |
Fix bugs with empty and predicate-only matches
Also clarified the behaviour of empty matches, which match anything, but only once. This behaviour is required for consistency with the rest of the matching rules.
Diffstat (limited to 'abdl')
-rw-r--r-- | abdl/__init__.py | 2 | ||||
-rw-r--r-- | abdl/_vm.py | 16 |
2 files changed, 14 insertions, 4 deletions
diff --git a/abdl/__init__.py b/abdl/__init__.py index 547bb68..efcd3df 100644 --- a/abdl/__init__.py +++ b/abdl/__init__.py @@ -88,6 +88,8 @@ Language Reference: needs to be careful when writing code where such behaviour could result in a security vulnerability. + The empty pattern matches anything, but only does so once. + Syntax of ABDL Expressions: ABDL Expressions follow the given syntax, in (pseudo-)extended BNF:: diff --git a/abdl/_vm.py b/abdl/_vm.py index 5ab7efb..2f76586 100644 --- a/abdl/_vm.py +++ b/abdl/_vm.py @@ -255,7 +255,15 @@ class ApplyPredicate(PatternElement): def on_end(self, frame, path, defs, in_key): assert not in_key - raise NotImplementedError + 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) + path.clear() + return (False, res) class End(PatternElement): """Pseudo-token, used to advance iteration.""" @@ -282,7 +290,8 @@ class End(PatternElement): elif holder.name is not None: res[holder.name] = (holder.match, holder.value) if not frame.prev(): - return (None, res) + # this should never happen + assert False return (True, res) @classmethod @@ -382,6 +391,7 @@ def match_helper(ops, defs, tree): frame = _Frame(ops) if not len(frame.ops): # no ops? + yield {} return # do nothing path = [Holder(value=tree, parent=None, iterator=iter(()))] @@ -390,8 +400,6 @@ def match_helper(ops, defs, tree): if not frame.next(): in_key, res = frame.current_op.on_end(frame, path, defs, in_key) yield res - if in_key is None: - return else: if in_key: in_key = frame.current_op.on_in_key(frame, path, defs) |