diff options
Diffstat (limited to 'abdl')
-rw-r--r-- | abdl/__init__.py | 10 | ||||
-rw-r--r-- | abdl/_vm.py | 7 |
2 files changed, 13 insertions, 4 deletions
diff --git a/abdl/__init__.py b/abdl/__init__.py index efcd3df..7208e44 100644 --- a/abdl/__init__.py +++ b/abdl/__init__.py @@ -14,7 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <https://www.gnu.org/licenses/>. -"""A Boneless Datastructure Language, version 2.1. +"""A Boneless Datastructure Language, version 2.2. ABDL expressions are regex-like constructs for matching and validating object structures. They can be used with JSON and similar formats, and even @@ -76,7 +76,11 @@ Language Reference: the enclosed ABDL expression to the value (or index) being processed. A subvalue enables the ability to match multiple values on the same object, and accepts a value if and only the enclosed expression - matches the value. + matches the value. A subvalue can be made optional by the presence of + a ``?`` after the subvalue - in case of no match, it will just omit + the relevant keys in the result. Optional subvalues are unrelated to + non-validating syntax elements (see below), they just use the same + syntax. Some syntax elements can be validating or non-validating. Validating syntax elements will raise a :py:exc:`abdl.exceptions.ValidationError` @@ -100,7 +104,7 @@ Language Reference: arrow ::= '->' keymatch ::= '[' {predicate} abdlexpression ']' - subvalue ::= '(' {predicate} abdlexpression ')' + subvalue ::= '(' {predicate} abdlexpression ')' ['?'] For a description of the terminals "parameter", "literal", "regex" and "predicate", see "Syntax Elements of ABDL Expressions" above. diff --git a/abdl/_vm.py b/abdl/_vm.py index 2f76586..c6cd7be 100644 --- a/abdl/_vm.py +++ b/abdl/_vm.py @@ -162,7 +162,7 @@ class ValueSubtree(PatternElement): def __init__(self, toks): self.key = toks[0] - self.skippable = toks[1] == '?' + self.optional = toks[1] == '?' def on_not_in_key(self, frame, path, defs): assert not path[-1].empty @@ -171,8 +171,13 @@ class ValueSubtree(PatternElement): return True def _filter(self, parent, defs): + has_results = False for pair in match_helper(self.key, defs, parent): + has_results = True yield (pair, parent) + # support for optional subtrees + if self.optional and not has_results: + yield ({}, parent) def collect_params(self, res: list): for sub in self.key: |