summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul McGuire <ptmcg@austin.rr.com>2019-08-09 06:46:56 -0500
committerPaul McGuire <ptmcg@austin.rr.com>2019-08-09 06:46:56 -0500
commit7c1db54c6b4de188d7bebcc7372b926a13fd3da4 (patch)
treee224eaeef31b55a4bcf6a672733ec13dc95d7836
parentc02db7427de3197d607e30ba42031884802a6f94 (diff)
downloadpyparsing-git-7c1db54c6b4de188d7bebcc7372b926a13fd3da4.tar.gz
Fixed bug in indentedBlock with a parser using two different types of nested indented blocks with different indent values, but sharing the same indent stack. Raised in comments on #87.
-rw-r--r--pyparsing.py13
-rw-r--r--unitTests.py39
2 files changed, 45 insertions, 7 deletions
diff --git a/pyparsing.py b/pyparsing.py
index 23b36dc..aa49a06 100644
--- a/pyparsing.py
+++ b/pyparsing.py
@@ -96,7 +96,7 @@ classes inherit from. Use the docstrings for examples of how to:
"""
__version__ = "2.5.0a1"
-__versionTime__ = "06 Aug 2019 04:55 UTC"
+__versionTime__ = "09 Aug 2019 11:27 UTC"
__author__ = "Paul McGuire <ptmcg@users.sourceforge.net>"
import string
@@ -6015,7 +6015,7 @@ def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString.cop
ret.setName('nested %s%s expression' % (opener, closer))
return ret
-def indentedBlock(blockStatementExpr, indentStack, indent=True):
+def indentedBlock(blockStatementExpr, indentStack, indent=True, backup_stacks=[]):
"""Helper method for defining space-delimited indentation blocks,
such as those used to define block statements in Python source code.
@@ -6096,10 +6096,10 @@ def indentedBlock(blockStatementExpr, indentStack, indent=True):
':',
[[['def', 'eggs', ['(', 'z', ')'], ':', [['pass']]]]]]]
"""
- backup_stack = indentStack[:]
+ backup_stacks.append(indentStack[:])
def reset_stack():
- indentStack[:] = backup_stack
+ indentStack[:] = backup_stacks[-1]
def checkPeerIndent(s, l, t):
if l >= len(s): return
@@ -6136,7 +6136,10 @@ def indentedBlock(blockStatementExpr, indentStack, indent=True):
else:
smExpr = Group(Optional(NL)
+ OneOrMore(PEER + Group(blockStatementExpr) + Optional(NL))
- + UNDENT)
+ + Optional(UNDENT))
+
+ # add a parse action to remove backup_stack from list of backups
+ smExpr.addParseAction(lambda: backup_stacks.pop(-1) and None if backup_stacks else None)
smExpr.setFailAction(lambda a, b, c, d: reset_stack())
blockStatementExpr.ignore(_bslash + LineEnd())
return smExpr.setName('indented block')
diff --git a/unitTests.py b/unitTests.py
index 9fe246e..8601be1 100644
--- a/unitTests.py
+++ b/unitTests.py
@@ -4217,12 +4217,12 @@ class IndentedBlockTest2(ParseTestCase):
key.setParseAction(key_parse_action)
header = Suppress("[") + Literal("test") + Suppress("]")
- content = (header + OneOrMore(indentedBlock(body, indent_stack, False)))
+ content = (header - OneOrMore(indentedBlock(body, indent_stack, False)))
contents = Forward()
suites = indentedBlock(content, indent_stack)
- extra = Literal("extra") + Suppress(":") + suites
+ extra = Literal("extra") + Suppress(":") - suites
contents << (content | extra)
parser = OneOrMore(contents)
@@ -4245,6 +4245,41 @@ class IndentedBlockTest2(ParseTestCase):
success, _ = parser.runTests([sample])
self.assertTrue(success, "Failed indentedBlock test for issue #87")
+ sample2 = dedent("""
+ extra:
+ [test]
+ one:
+ two (three)
+ four:
+ five (seven)
+ extra:
+ [test]
+ one:
+ two (three)
+ four:
+ five (seven)
+
+ [test]
+ one:
+ two (three)
+ four:
+ five (seven)
+
+ [test]
+ eight:
+ nine (ten)
+ eleven:
+ twelve (thirteen)
+
+ fourteen:
+ fifteen (sixteen)
+ seventeen:
+ eighteen (nineteen)
+ """)
+
+ del indent_stack[1:]
+ success, _ = parser.runTests([sample2])
+ self.assertTrue(success, "Failed indentedBlock multi-block test for issue #87")
class IndentedBlockScanTest(ParseTestCase):
def get_parser(self):