summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Milton <ttmigueltt@gmail.com>2020-06-09 15:09:21 +1000
committerGitHub <noreply@github.com>2020-06-09 00:09:21 -0500
commit17aaf616a752990327ec51f41d2ac4c4a0871215 (patch)
tree8a96779b8b238c8eb1c80783a1cd4574c1e14a06
parent1181390886f39240a98977348bd5b9030986f98d (diff)
downloadpyparsing-git-17aaf616a752990327ec51f41d2ac4c4a0871215.tar.gz
Additional configuration for `skipWhitespace` and `leaveWhitespace` (#219)
* Add .ignoreWhitespace() method * Add recursive arg to leave- and ignoreWhitespace(), with tests * Add tests and implementation of the recursive flag
-rw-r--r--pyparsing/core.py71
-rw-r--r--tests/test_simple_unit.py91
2 files changed, 148 insertions, 14 deletions
diff --git a/pyparsing/core.py b/pyparsing/core.py
index 431e656..8f2979e 100644
--- a/pyparsing/core.py
+++ b/pyparsing/core.py
@@ -1343,11 +1343,23 @@ class ParserElement:
"""
return Suppress(self)
- def leaveWhitespace(self):
+ def ignoreWhitespace(self, recursive=True):
+ """
+ Enables the skipping of whitespace before matching the characters in the
+ :class:`ParserElement`'s defined pattern.
+
+ :param recursive: If true (the default), also enable whitespace skipping in child elements (if any)
+ """
+ self.skipWhitespace = True
+ return self
+
+ def leaveWhitespace(self, recursive=True):
"""
Disables the skipping of whitespace before matching the characters in the
:class:`ParserElement`'s defined pattern. This is normally only used internally by
the pyparsing module, but may be needed in some whitespace-sensitive grammars.
+
+ :param recursive: If true (the default), also disable whitespace skipping in child elements (if any)
"""
self.skipWhitespace = False
return self
@@ -2995,13 +3007,29 @@ class ParseExpression(ParserElement):
self.strRepr = None
return self
- def leaveWhitespace(self):
- """Extends ``leaveWhitespace`` defined in base class, and also invokes ``leaveWhitespace`` on
- all contained expressions."""
- self.skipWhitespace = False
- self.exprs = [e.copy() for e in self.exprs]
- for e in self.exprs:
- e.leaveWhitespace()
+ def leaveWhitespace(self, recursive=True):
+ """
+ Extends ``leaveWhitespace`` defined in base class, and also invokes ``leaveWhitespace`` on
+ all contained expressions.
+ """
+ super().leaveWhitespace(recursive)
+
+ if recursive:
+ self.exprs = [e.copy() for e in self.exprs]
+ for e in self.exprs:
+ e.leaveWhitespace(recursive)
+ return self
+
+ def ignoreWhitespace(self, recursive=True):
+ """
+ Extends ``ignoreWhitespace`` defined in base class, and also invokes ``leaveWhitespace`` on
+ all contained expressions.
+ """
+ super().ignoreWhitespace(recursive)
+ if recursive:
+ self.exprs = [e.copy() for e in self.exprs]
+ for e in self.exprs:
+ e.ignoreWhitespace(recursive)
return self
def ignore(self, other):
@@ -3672,11 +3700,22 @@ class ParseElementEnhance(ParserElement):
else:
raise ParseException("", loc, self.errmsg, self)
- def leaveWhitespace(self):
- self.skipWhitespace = False
- self.expr = self.expr.copy()
- if self.expr is not None:
- self.expr.leaveWhitespace()
+ def leaveWhitespace(self, recursive=True):
+ super().leaveWhitespace(recursive)
+
+ if recursive:
+ self.expr = self.expr.copy()
+ if self.expr is not None:
+ self.expr.leaveWhitespace(recursive)
+ return self
+
+ def ignoreWhitespace(self, recursive=True):
+ super().ignoreWhitespace(recursive)
+
+ if recursive:
+ self.expr = self.expr.copy()
+ if self.expr is not None:
+ self.expr.ignoreWhitespace(recursive)
return self
def ignore(self, other):
@@ -4283,10 +4322,14 @@ class Forward(ParseElementEnhance):
ret = super().__or__(other)
return ret
- def leaveWhitespace(self):
+ def leaveWhitespace(self, recursive=True):
self.skipWhitespace = False
return self
+ def ignoreWhitespace(self, recursive=True):
+ self.skipWhitespace = True
+ return self
+
def streamline(self):
if not self.streamlined:
self.streamlined = True
diff --git a/tests/test_simple_unit.py b/tests/test_simple_unit.py
index 15edc33..8682f0f 100644
--- a/tests/test_simple_unit.py
+++ b/tests/test_simple_unit.py
@@ -568,6 +568,97 @@ class TestCommonHelperExpressions(PyparsingExpressionTestCase):
]
+class TestWhitespaceMethods(PyparsingExpressionTestCase):
+ tests = [
+ # These test the single-element versions
+ PpTestSpec(
+ desc="The word foo",
+ expr=pp.Literal("foo").ignoreWhitespace(),
+ text=" foo ",
+ expected_list=["foo"],
+ ),
+ PpTestSpec(
+ desc="The word foo",
+ expr=pp.Literal("foo").leaveWhitespace(),
+ text=" foo ",
+ expected_fail_locn=0,
+ ),
+ PpTestSpec(
+ desc="The word foo",
+ expr=pp.Literal("foo").ignoreWhitespace(),
+ text="foo",
+ expected_list=["foo"],
+ ),
+ PpTestSpec(
+ desc="The word foo",
+ expr=pp.Literal("foo").leaveWhitespace(),
+ text="foo",
+ expected_list=["foo"],
+ ),
+ # These test the composite elements
+ PpTestSpec(
+ desc="If we recursively leave whitespace on the parent, this whitespace-dependent grammar will succeed, even if the children themselves skip whitespace",
+ expr=pp.And(
+ [
+ pp.Literal(" foo").ignoreWhitespace(),
+ pp.Literal(" bar").ignoreWhitespace(),
+ ]
+ ).leaveWhitespace(recursive=True),
+ text=" foo bar",
+ expected_list=[" foo", " bar"],
+ ),
+ #
+ PpTestSpec(
+ desc="If we recursively ignore whitespace in our parsing, this whitespace-dependent grammar will fail, even if the children themselves keep whitespace",
+ expr=pp.And(
+ [
+ pp.Literal(" foo").leaveWhitespace(),
+ pp.Literal(" bar").leaveWhitespace(),
+ ]
+ ).ignoreWhitespace(recursive=True),
+ text=" foo bar",
+ expected_fail_locn=1,
+ ),
+ PpTestSpec(
+ desc="If we leave whitespace on the parent, but it isn't recursive, this whitespace-dependent grammar will fail",
+ expr=pp.And(
+ [
+ pp.Literal(" foo").ignoreWhitespace(),
+ pp.Literal(" bar").ignoreWhitespace(),
+ ]
+ ).leaveWhitespace(recursive=False),
+ text=" foo bar",
+ expected_fail_locn=5,
+ ),
+ # These test the Enhance classes
+ PpTestSpec(
+ desc="If we recursively leave whitespace on the parent, this whitespace-dependent grammar will succeed, even if the children themselves skip whitespace",
+ expr=pp.Optional(pp.Literal(" foo").ignoreWhitespace()).leaveWhitespace(
+ recursive=True
+ ),
+ text=" foo",
+ expected_list=[" foo"],
+ ),
+ #
+ PpTestSpec(
+ desc="If we ignore whitespace on the parent, but it isn't recursive, parsing will fail because we skip to the first character 'f' before the internal expr can see it",
+ expr=pp.Optional(pp.Literal(" foo").leaveWhitespace()).ignoreWhitespace(
+ recursive=True
+ ),
+ text=" foo",
+ expected_list=[],
+ ),
+ # PpTestSpec(
+ # desc="If we leave whitespace on the parent, this whitespace-dependent grammar will succeed, even if the children themselves skip whitespace",
+ # expr=pp.Optional(pp.Literal(" foo").ignoreWhitespace()).leaveWhitespace(
+ # recursive=False
+ # ),
+ # text=" foo",
+ # expected_list=[]
+ # ),
+ ]
+
+
def _get_decl_line_no(cls):
import inspect