summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--abdl/__init__.py3
-rw-r--r--abdl/_parser.py31
-rw-r--r--testing/test_abdl.py2
-rw-r--r--testing/test_ops_abdl.py34
4 files changed, 39 insertions, 31 deletions
diff --git a/abdl/__init__.py b/abdl/__init__.py
index d751187..2c6b26a 100644
--- a/abdl/__init__.py
+++ b/abdl/__init__.py
@@ -137,6 +137,9 @@ from abdl import _parser
 from abdl import _vm
 from abdl import exceptions
 
+# backwards compatibility TODO: remove in 3.0.0
+from abdl.exceptions import ValidationError, DeprecationError, PatternError
+
 class Pattern:
     """A compiled pattern object.
 
diff --git a/abdl/_parser.py b/abdl/_parser.py
index c39a45e..3e179a2 100644
--- a/abdl/_parser.py
+++ b/abdl/_parser.py
@@ -16,7 +16,7 @@
 
 import pyparsing
 
-import abdl.exceptions
+from abdl import exceptions
 from abdl import _vm
 
 def _build_syntax():
@@ -27,14 +27,21 @@ def _build_syntax():
 
     skippable = Optional("?", default="")
 
-    str_literal = (Combine(Suppress("'")
-            + (Suppress("%") + ("'" | "%") | Literal("%") + (CharsNotIn("") | StringEnd()).setParseAction(abdl.exceptions.PatternError._str_escape) | CharsNotIn("%'"))[...]
-            + (Suppress("'") | StringEnd().setParseAction(abdl.exceptions.PatternError._str_end))) + skippable)
+    escape_char = Literal("%")
+    str_token = Literal("'")
+    re_token = Literal("/")
+
+    unexpected_token = CharsNotIn("", exact=1).setParseAction(exceptions.PatternError._unexpected_tok)
+    unexpected_end = StringEnd().setParseAction(exceptions.PatternError._unexpected_tok)
+
+    str_literal = (Combine(Suppress(str_token)
+            + (Suppress(escape_char) + (str_token | escape_char) | escape_char + CharsNotIn("", exact=1).setParseAction(exceptions.PatternError._str_escape) | CharsNotIn("%'"))[...]
+            + (Suppress(str_token) | StringEnd().setParseAction(exceptions.PatternError._str_end))) + skippable)
     str_literal.setParseAction(lambda toks: [_vm.StringKey(toks)])
 
-    re_literal = (Combine(Suppress("/")
-            + (Suppress("%") + ("/" | "%") | Literal("%") + (CharsNotIn("") | StringEnd()).setParseAction(abdl.exceptions.PatternError._re_escape) | CharsNotIn("%/"))[...]
-            + (Suppress("/") | StringEnd().setParseAction(abdl.exceptions.PatternError._re_end))) + skippable)
+    re_literal = (Combine(Suppress(re_token)
+            + (Suppress(escape_char) + (re_token | escape_char) | escape_char + CharsNotIn("", exact=1).setParseAction(exceptions.PatternError._re_escape) | CharsNotIn("%/"))[...]
+            + (Suppress(re_token) | StringEnd().setParseAction(exceptions.PatternError._re_end))) + skippable)
     re_literal.setParseAction(lambda toks: [_vm.RegexKey(toks)])
 
     arrow = Literal("->")
@@ -46,25 +53,23 @@ def _build_syntax():
     parameter = (Suppress("$") + skippable + identifier)
     parameter.setParseAction(lambda toks: [_vm.Param(toks)])
 
-    type_ = (Suppress(":") + skippable + Optional(Suppress("$")) + identifier)
+    type_ = (Suppress(":") + skippable + Suppress("$") + identifier)
     type_.setParseAction(lambda toks: [_vm.ApplyPredicate(toks)])
 
     # support for objects-as-keys
-    keysubtree = (Suppress("[")
-            + Group(type_[...] + subtree)
-            + (Suppress("]") | (CharsNotIn("") | StringEnd()).setParseAction(abdl.exceptions.PatternError._unexpected_tok)) + skippable)
+    keysubtree = (Suppress("[") + Group(type_[...] + subtree) + (Suppress("]") | unexpected_token | unexpected_end) + skippable)
     keysubtree.setParseAction(lambda toks: [_vm.KeySubtree(toks)])
 
     # represents key matching - switches from "key" to "value"
     tag = (identifier + Optional(parameter | str_literal | re_literal | keysubtree) | parameter | str_literal | re_literal | keysubtree) + type_[...] + Empty().setParseAction(lambda: [_vm.End()])
 
     # multiple value matching
-    valuesubtree = (Suppress("(") + Group(subtree) + (Suppress(")") | CharsNotIn("").setParseAction(abdl.exceptions.PatternError._unexpected_tok) | StringEnd().setParseAction(abdl.exceptions.PatternError._unexpected_tok)) + Optional("?", default=""))
+    valuesubtree = (Suppress("(") + Group(subtree) + (Suppress(")") | unexpected_token | unexpected_end) + Optional("?", default=""))
     valuesubtree.setParseAction(lambda toks: [_vm.ValueSubtree(toks)])
 
     # arrow and tag, value subtree
     subtree <<= (arrow + tag)[...] + (valuesubtree + Empty().setParseAction(lambda: [_vm.End()]))[...]
 
-    return ((subtree | CharsNotIn("").setParseAction(abdl.exceptions.PatternError._unexpected_tok)) + StringEnd()).parseWithTabs()
+    return ((subtree | unexpected_token) + StringEnd()).parseWithTabs()
 
 BUILT_SYNTAX = _build_syntax()
diff --git a/testing/test_abdl.py b/testing/test_abdl.py
index f9eedcc..2cea90d 100644
--- a/testing/test_abdl.py
+++ b/testing/test_abdl.py
@@ -15,7 +15,7 @@ import traceback
 abdl.DeprecationError.enable_key_match_compat = False
 
 # use abdl's _pairs for consistency.
-pairs = abdl._pairs
+pairs = abdl._vm._pairs
 
 # do not put integers, floats, etc here
 # do not put bytes, they iterate as integers
diff --git a/testing/test_ops_abdl.py b/testing/test_ops_abdl.py
index 0695e3f..3fba731 100644
--- a/testing/test_ops_abdl.py
+++ b/testing/test_ops_abdl.py
@@ -19,10 +19,10 @@ class OpHelper:
     def __enter__(self):
         self.pos += 1
         first = self.pos
-        assert not isinstance(self.ops[first], abdl._End)
-        while not isinstance(self.ops[self.pos], abdl._End):
+        assert not isinstance(self.ops[first], abdl._vm.End)
+        while not isinstance(self.ops[self.pos], abdl._vm.End):
             self.pos += 1
-        assert isinstance(self.ops[self.pos], abdl._End)
+        assert isinstance(self.ops[self.pos], abdl._vm.End)
         return self.ops[first:self.pos]
 
     def __exit__(self, exc_type, exc_value, traceback):
@@ -35,7 +35,7 @@ def expect_types(seq, *tys):
 def expect_idents(oph, *idents):
     for ident in idents:
         with oph as ops:
-            expect_types(ops, abdl._Arrow, abdl._Ident)
+            expect_types(ops, abdl._vm.Arrow, abdl._vm.Ident)
             assert ops[1].key == ident
 
 def test_empty_iterator_pattern():
@@ -50,7 +50,7 @@ def test_four_depths_pattern():
 def test_regex_pattern():
     oph = OpHelper(abdl.compile("->/.../"))
     with oph as ops:
-        expect_types(ops, abdl._Arrow, abdl._RegexKey)
+        expect_types(ops, abdl._vm.Arrow, abdl._vm.RegexKey)
         assert ops[1].key == '...'
         assert ops[1].compiled == re.compile('...')
         assert ops[1].skippable == False
@@ -59,7 +59,7 @@ def test_regex_pattern():
 def test_regex_skippable_pattern():
     oph = OpHelper(abdl.compile("->/.../?"))
     with oph as ops:
-        expect_types(ops, abdl._Arrow, abdl._RegexKey)
+        expect_types(ops, abdl._vm.Arrow, abdl._vm.RegexKey)
         assert ops[1].key == '...'
         assert ops[1].compiled == re.compile('...')
         assert ops[1].skippable == True
@@ -68,7 +68,7 @@ def test_regex_skippable_pattern():
 def test_regex_and_bind_pattern():
     oph = OpHelper(abdl.compile("->/.../->Y"))
     with oph as ops:
-        expect_types(ops, abdl._Arrow, abdl._RegexKey)
+        expect_types(ops, abdl._vm.Arrow, abdl._vm.RegexKey)
         assert ops[1].key == '...'
         assert ops[1].compiled == re.compile('...')
         assert ops[1].skippable == False
@@ -78,7 +78,7 @@ def test_regex_and_bind_pattern():
 def test_empty_literal_skippable_and_bind_pattern():
     oph = OpHelper(abdl.compile("->''?->Y"))
     with oph as ops:
-        expect_types(ops, abdl._Arrow, abdl._StringKey)
+        expect_types(ops, abdl._vm.Arrow, abdl._vm.StringKey)
         assert ops[1].key == ''
         assert ops[1].skippable == True
     expect_idents(oph, "Y")
@@ -88,7 +88,7 @@ def test_type_pattern():
     oph = OpHelper(abdl.compile("->X:?$a->Y", defs={'a': (dict, list, set)}))
     assert oph.pat._defs['a'] == (dict, list, set)
     with oph as ops:
-        expect_types(ops, abdl._Arrow, abdl._Ident, abdl._ApplyPredicate)
+        expect_types(ops, abdl._vm.Arrow, abdl._vm.Ident, abdl._vm.ApplyPredicate)
         assert ops[1].key == 'X'
         assert ops[2].key == 'a'
         assert ops[2].skippable == True
@@ -101,7 +101,7 @@ def test_multi_type_pattern():
     assert oph.pat._defs['b'] == (dict, set)
     assert oph.pat._defs['c'] == dict
     with oph as ops:
-        expect_types(ops, abdl._Arrow, abdl._Ident, abdl._ApplyPredicate, abdl._ApplyPredicate, abdl._ApplyPredicate)
+        expect_types(ops, abdl._vm.Arrow, abdl._vm.Ident, abdl._vm.ApplyPredicate, abdl._vm.ApplyPredicate, abdl._vm.ApplyPredicate)
         assert ops[1].key == 'X'
         assert ops[2].key == 'a'
         assert ops[2].skippable == False
@@ -116,10 +116,10 @@ def test_key_subtree_pattern():
     oph = OpHelper(abdl.compile("->[:?$set->A]->D", defs={'set': set}))
     assert oph.pat._defs['set'] == set
     with oph as ops:
-        expect_types(ops, abdl._Arrow, abdl._KeySubtree)
+        expect_types(ops, abdl._vm.Arrow, abdl._vm.KeySubtree)
         oph2 = OpHelper(None, ops=ops[1].key)
         with oph2 as ops2:
-            expect_types(ops2, abdl._ApplyPredicate, abdl._Arrow, abdl._Ident)
+            expect_types(ops2, abdl._vm.ApplyPredicate, abdl._vm.Arrow, abdl._vm.Ident)
             assert ops2[0].key == 'set'
             assert ops2[0].skippable == True
             assert ops2[2].key == 'A'
@@ -132,7 +132,7 @@ def test_param_pattern():
     assert oph.pat._defs['a'] == '0'
     expect_idents(oph, "X")
     with oph as ops:
-        expect_types(ops, abdl._Arrow, abdl._Param)
+        expect_types(ops, abdl._vm.Arrow, abdl._vm.Param)
         assert ops[1].key == 'a'
         assert ops[1].skippable == False
     expect_idents(oph, "Z")
@@ -141,19 +141,19 @@ def test_param_pattern():
 def test_value_subtree_pattern():
     oph = OpHelper(abdl.compile("(->foo'foo')(->bar'bar')"))
     with oph as ops:
-        expect_types(ops, abdl._ValueSubtree)
+        expect_types(ops, abdl._vm.ValueSubtree)
         oph2 = OpHelper(None, ops=ops[0].key)
         with oph2 as ops2:
-            expect_types(ops2, abdl._Arrow, abdl._Ident, abdl._StringKey)
+            expect_types(ops2, abdl._vm.Arrow, abdl._vm.Ident, abdl._vm.StringKey)
             assert ops2[1].key == 'foo'
             assert ops2[2].key == 'foo'
             assert ops2[2].skippable == False
         oph2.done()
     with oph as ops:
-        expect_types(ops, abdl._ValueSubtree)
+        expect_types(ops, abdl._vm.ValueSubtree)
         oph2 = OpHelper(None, ops=ops[0].key)
         with oph2 as ops2:
-            expect_types(ops2, abdl._Arrow, abdl._Ident, abdl._StringKey)
+            expect_types(ops2, abdl._vm.Arrow, abdl._vm.Ident, abdl._vm.StringKey)
             assert ops2[1].key == 'bar'
             assert ops2[2].key == 'bar'
             assert ops2[2].skippable == False