diff options
Diffstat (limited to 'pyparsing/helpers.py')
-rw-r--r-- | pyparsing/helpers.py | 37 |
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" |