summaryrefslogtreecommitdiff
path: root/pyparsing/helpers.py
diff options
context:
space:
mode:
authorptmcg <ptmcg@austin.rr.com>2020-11-02 18:14:56 -0600
committerptmcg <ptmcg@austin.rr.com>2020-11-02 18:14:56 -0600
commit2dd2e2bb70407eea91f18de2caea5ba4527eb7dc (patch)
treec0a8824908983d6b4b81a6081af629e6ba8064b0 /pyparsing/helpers.py
parent96e0fab07788fca87e1473b0ae755335d6988895 (diff)
downloadpyparsing-git-2dd2e2bb70407eea91f18de2caea5ba4527eb7dc.tar.gz
Add IndentedBlock class; made vertical keyword arg more visible when creating railroad diags; changed create_diagram from monkeypatch to included method on ParserElement; better debug exception if Dict is constructed with non-Group expressionpyparsing_3.0.0b1
Diffstat (limited to 'pyparsing/helpers.py')
-rw-r--r--pyparsing/helpers.py37
1 files changed, 36 insertions, 1 deletions
diff --git a/pyparsing/helpers.py b/pyparsing/helpers.py
index d2325c9..cf59107 100644
--- a/pyparsing/helpers.py
+++ b/pyparsing/helpers.py
@@ -699,7 +699,9 @@ def infixNotation(baseExpr, opList, lpar=Suppress("("), rpar=Suppress(")")):
thisExpr = Forward().setName(termName)
if rightLeftAssoc is opAssoc.LEFT:
if arity == 1:
- matchExpr = _FB(lastExpr + opExpr) + Group(lastExpr + opExpr + opExpr[...])
+ matchExpr = _FB(lastExpr + opExpr) + Group(
+ lastExpr + opExpr + opExpr[...]
+ )
elif arity == 2:
if opExpr is not None:
matchExpr = _FB(lastExpr + opExpr + lastExpr) + Group(
@@ -760,6 +762,9 @@ def indentedBlock(blockStatementExpr, indentStack, indent=True, backup_stacks=[]
A valid block must contain at least one ``blockStatement``.
+ (Note that indentedBlock uses internal parse actions which make it
+ incompatible with packrat parsing.)
+
Example::
data = '''
@@ -881,6 +886,36 @@ def indentedBlock(blockStatementExpr, indentStack, indent=True, backup_stacks=[]
return smExpr.setName("indented block")
+class IndentedBlock(ParseElementEnhance):
+ """
+ Expression to match one or more expressions at a given indentation level.
+ Useful for parsing text where structure is implied by indentation (like Python source code).
+ """
+
+ def __init__(self, expr, recursive=True):
+ super().__init__(expr, savelist=True)
+ self._recursive = recursive
+
+ def parseImpl(self, instring, loc, doActions=True):
+ # see if self.expr matches at the current location - if not it will raise an exception
+ # and no further work is necessary
+ self.expr.parseImpl(instring, loc, doActions)
+
+ indent_col = col(loc, instring)
+ peer_parse_action = matchOnlyAtCol(indent_col)
+ peer_expr = FollowedBy(self.expr).addParseAction(peer_parse_action)
+ inner_expr = Empty() + peer_expr.suppress() + self.expr
+
+ if self._recursive:
+ indent_parse_action = conditionAsParseAction(
+ lambda s, l, t, relative_to_col=indent_col: col(l, s) > relative_to_col
+ )
+ indent_expr = FollowedBy(self.expr).addParseAction(indent_parse_action)
+ inner_expr += Optional(indent_expr + self)
+
+ return OneOrMore(inner_expr).parseImpl(instring, loc, doActions)
+
+
# it's easy to get these comment structures wrong - they're very common, so may as well make them available
cStyleComment = Combine(Regex(r"/\*(?:[^*]|\*(?!/))*") + "*/").setName(
"C style comment"