summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES4
-rw-r--r--pyparsing.py10
-rw-r--r--unitTests.py15
3 files changed, 23 insertions, 6 deletions
diff --git a/CHANGES b/CHANGES
index 22e2a30..1c1be35 100644
--- a/CHANGES
+++ b/CHANGES
@@ -8,7 +8,9 @@ Version 2.4.3 - September, 2019
create a recursion error at parser definition time. Thanks to
Michael Clerx for the assist. (Addresses issue #123)
-- Backport from pyparsing 3.0.0 of __diag__.enable_all_warnings().
+- Backports from pyparsing 3.0.0:
+ . __diag__.enable_all_warnings().
+ . Fixed bug in PrecededBy which caused infinite recursion, issue #127
Version 2.4.2 - July, 2019
diff --git a/pyparsing.py b/pyparsing.py
index ffbe78b..17e0bdf 100644
--- a/pyparsing.py
+++ b/pyparsing.py
@@ -4570,6 +4570,7 @@ class PrecededBy(ParseElementEnhance):
self.retreat = retreat
self.errmsg = "not preceded by " + str(expr)
self.skipWhitespace = False
+ self.parseAction.append(lambda s, l, t: t.__delitem__(slice(None, None)))
def parseImpl(self, instring, loc=0, doActions=True):
if self.exact:
@@ -4580,19 +4581,18 @@ class PrecededBy(ParseElementEnhance):
else:
# retreat specified a maximum lookbehind window, iterate
test_expr = self.expr + StringEnd()
- instring_slice = instring[:loc]
+ instring_slice = instring[max(0, loc - self.retreat):loc]
last_expr = ParseException(instring, loc, self.errmsg)
- for offset in range(1, min(loc, self.retreat + 1)):
+ for offset in range(1, min(loc, self.retreat + 1)+1):
try:
- _, ret = test_expr._parse(instring_slice, loc - offset)
+ # print('trying', offset, instring_slice, repr(instring_slice[loc - offset:]))
+ _, ret = test_expr._parse(instring_slice, len(instring_slice) - offset)
except ParseBaseException as pbe:
last_expr = pbe
else:
break
else:
raise last_expr
- # return empty list of tokens, but preserve any defined results names
- del ret[:]
return loc, ret
diff --git a/unitTests.py b/unitTests.py
index 40dd58b..cfc4e90 100644
--- a/unitTests.py
+++ b/unitTests.py
@@ -2046,6 +2046,21 @@ class PrecededByTest(ParseTestCase):
"Erroneous named results for {0}: expected {1}, got {2}".format(expr,
expected_dict,
result.asDict()))
+ # infinite loop test - from Issue #127
+ string_test = 'notworking'
+ # negs = pp.Or(['not', 'un'])('negs')
+ negs_pb = pp.PrecededBy('not', retreat=100)('negs_lb')
+ # negs_pb = pp.PrecededBy(negs, retreat=100)('negs_lb')
+ pattern = pp.Group(negs_pb + pp.Literal('working'))('main')
+
+ results = pattern.searchString(string_test)
+ try:
+ print_(results.dump())
+ except RecursionError:
+ self.assertTrue(False, "got maximum excursion limit exception")
+ else:
+ self.assertTrue(True, "got maximum excursion limit exception")
+
class CountedArrayTest(ParseTestCase):
def runTest(self):