diff options
author | Paul McGuire <ptmcg@austin.rr.com> | 2019-08-04 23:11:07 -0500 |
---|---|---|
committer | Paul McGuire <ptmcg@austin.rr.com> | 2019-08-04 23:11:07 -0500 |
commit | 897e536d2131c6d07cbc355edb0ed744213c6997 (patch) | |
tree | 4454dd53ac5b874779605b1b2f82a144913215e7 /pyparsing.py | |
parent | b0f76d82a134d2ea2324b384ac9eba6c50a516d3 (diff) | |
download | pyparsing-git-897e536d2131c6d07cbc355edb0ed744213c6997.tar.gz |
Improved handling of '-' ErrorStop's when used within Each
Diffstat (limited to 'pyparsing.py')
-rw-r--r-- | pyparsing.py | 82 |
1 files changed, 65 insertions, 17 deletions
diff --git a/pyparsing.py b/pyparsing.py index 6715edf..0871fa8 100644 --- a/pyparsing.py +++ b/pyparsing.py @@ -95,8 +95,8 @@ classes inherit from. Use the docstrings for examples of how to: namespace class """ -__version__ = "2.4.2" -__versionTime__ = "29 Jul 2019 02:58 UTC" +__version__ = "2.5.0a1" +__versionTime__ = "05 Aug 2019 00:46 UTC" __author__ = "Paul McGuire <ptmcg@users.sourceforge.net>" import string @@ -111,7 +111,7 @@ import pprint import traceback import types from datetime import datetime -from operator import itemgetter +from operator import itemgetter, attrgetter import itertools from functools import wraps @@ -1717,10 +1717,12 @@ class ParserElement(object): return loc, retTokens - def tryParse(self, instring, loc): + def tryParse(self, instring, loc, raise_fatal=False): try: return self._parse(instring, loc, doActions=False)[0] except ParseFatalException: + if raise_fatal: + raise raise ParseException(instring, loc, self.errmsg, self) def canParseNext(self, instring, loc): @@ -4104,14 +4106,22 @@ class Or(ParseExpression): maxExcLoc = -1 maxException = None matches = [] + fatals = [] for e in self.exprs: try: - loc2 = e.tryParse(instring, loc) + loc2 = e.tryParse(instring, loc, raise_fatal=True) + except ParseFatalException as pfe: + pfe.__traceback__ = None + pfe.parserElement = e + fatals.append(pfe) + maxException = None + maxExcLoc = -1 except ParseException as err: - err.__traceback__ = None - if err.loc > maxExcLoc: - maxException = err - maxExcLoc = err.loc + if not fatals: + err.__traceback__ = None + if err.loc > maxExcLoc: + maxException = err + maxExcLoc = err.loc except IndexError: if len(instring) > maxExcLoc: maxException = ParseException(instring, len(instring), e.errmsg, self) @@ -4154,6 +4164,14 @@ class Or(ParseExpression): if longest != (-1, None): return longest + if fatals: + if len(fatals) > 1: + fatals.sort(key=lambda e: -e.loc) + if fatals[0].loc == fatals[1].loc: + fatals.sort(key=lambda e: (-e.loc, -len(str(e.parserElement)))) + max_fatal = fatals[0] + raise max_fatal + if maxException is not None: maxException.msg = self.errmsg raise maxException @@ -4226,12 +4244,18 @@ class MatchFirst(ParseExpression): def parseImpl(self, instring, loc, doActions=True): maxExcLoc = -1 maxException = None + fatals = [] for e in self.exprs: try: ret = e._parse(instring, loc, doActions) return ret + except ParseFatalException as pfe: + pfe.__traceback__ = None + pfe.parserElement = e + fatals.append(pfe) + maxException = None except ParseException as err: - if err.loc > maxExcLoc: + if not fatals and err.loc > maxExcLoc: maxException = err maxExcLoc = err.loc except IndexError: @@ -4240,12 +4264,19 @@ class MatchFirst(ParseExpression): maxExcLoc = len(instring) # only got here if no expression matched, raise exception for match that made it the furthest + if fatals: + if len(fatals) > 1: + fatals.sort(key=lambda e: -e.loc) + if fatals[0].loc == fatals[1].loc: + fatals.sort(key=lambda e: (-e.loc, -len(str(e.parserElement)))) + max_fatal = fatals[0] + raise max_fatal + + if maxException is not None: + maxException.msg = self.errmsg + raise maxException else: - if maxException is not None: - maxException.msg = self.errmsg - raise maxException - else: - raise ParseException(instring, loc, "no defined alternatives to match", self) + raise ParseException(instring, loc, "no defined alternatives to match", self) def __ior__(self, other): if isinstance(other, basestring): @@ -4365,12 +4396,20 @@ class Each(ParseExpression): matchOrder = [] keepMatching = True + failed = [] + fatals = [] while keepMatching: tmpExprs = tmpReqd + tmpOpt + self.multioptionals + self.multirequired - failed = [] + failed.clear() + fatals.clear() for e in tmpExprs: try: - tmpLoc = e.tryParse(instring, tmpLoc) + tmpLoc = e.tryParse(instring, tmpLoc, raise_fatal=True) + except ParseFatalException as pfe: + pfe.__traceback__ = None + pfe.parserElement = e + fatals.append(pfe) + failed.append(e) except ParseException: failed.append(e) else: @@ -4382,6 +4421,15 @@ class Each(ParseExpression): if len(failed) == len(tmpExprs): keepMatching = False + # look for any ParseFatalExceptions + if fatals: + if len(fatals) > 1: + fatals.sort(key=lambda e: -e.loc) + if fatals[0].loc == fatals[1].loc: + fatals.sort(key=lambda e: (-e.loc, -len(str(e.parserElement)))) + max_fatal = fatals[0] + raise max_fatal + if tmpReqd: missing = ", ".join(_ustr(e) for e in tmpReqd) raise ParseException(instring, loc, "Missing one or more required elements (%s)" % missing) |