def parseImpl(self, string, loc, doActions=True): maxExcLoc = -1 maxException = None matches = [] for e in self.exprs: try: loc2 = e.tryParse(string, loc) except ParseException as err: err.__traceback__ = None if err.loc > maxExcLoc: maxException = err maxExcLoc = err.loc except IndexError: if len(string) > maxExcLoc: maxException = ParseException(string, len(string), self) maxExcLoc = len(string) else: # save match among all matches, to retry longest to shortest matches.append((loc2, e)) if matches: # re-evaluate all matches in descending order of length of match, in case attached actions # might change whether or how much they match of the input. matches.sort(key=itemgetter(0), reverse=True) if not doActions: # no further conditions or parse actions to change the selection of # alternative, so the first match will be the best match _, best_expr = matches[0] loc, best_results = best_expr._parse(string, loc, doActions) return loc, ParseResults(self, [best_results]) longest = -1, None for loc1, expr1 in matches: if loc1 <= longest[0]: # already have a longer match than this one will deliver, we are done return longest try: loc2, toks = expr1._parse(string, loc, doActions) except ParseException as err: err.__traceback__ = None if err.loc > maxExcLoc: maxException = err maxExcLoc = err.loc else: if loc2 >= loc1: return loc2, ParseResults(self, [toks]) # didn't match as much as before elif loc2 > longest[0]: longest = loc2, ParseResults(self, [toks]) if longest != (-1, None): return longest if maxException is not None: maxException.msg = "Expecting " + text(self) raise maxException else: raise ParseException(string, loc, "no defined alternatives to match", self)
def parseImpl(self, string, start, doActions=True): try: results = self.expr._parse(string, start, doActions) return ParseResults(self, results.start, results.end, [results]) except ParseException: return ParseResults(self, start, start, self.parser_config.defaultValue)
def parseImpl(self, string, loc, doActions=True): if self.re.match(string, loc): end = loc + len(self.match) try: if string[end] not in self.identChars: return end, ParseResults(self, [self.match]) except IndexError: return end, ParseResults(self, [self.match]) raise ParseException(self, loc, string)
def parseImpl(self, string, loc, doActions=True): try: loc, tokens = self.expr._parse(string, loc, doActions) except (ParseException, IndexError): if self.defaultValue is None: return loc, ParseResults(self, []) else: tokens = self.defaultValue return loc, ParseResults(self, [tokens])
def parseImpl(self, string, loc, doActions=True): if loc < len(string): if string[loc] == "\n": return loc + 1, ParseResults(self, ["\n"]) else: raise ParseException(self, loc, string) elif loc == len(string): return loc + 1, ParseResults(self, []) else: raise ParseException(self, loc, string)
def parseImpl(self, string, start, doActions=True): acc = [] end = start max = self.parser_config.max_match stopper = self.parser_config.end count = 0 try: while end < len(string) and count < max: if stopper: end = self.engine.skip(string, end) if stopper.match(string, end): if self.parser_config.min_match <= count: break else: raise ParseException(self, end, string, msg="found stopper too soon") result = self.expr._parse(string, end, doActions) end = result.end if result: acc.append(result) count += 1 except ParseException: if self.parser_config.min_match <= count <= max: pass else: ParseException(self, start, string, msg="Not correct amount of matches") if count: if (count < self.parser_config.min_match or self.parser_config.max_match < count): raise ParseException( self, acc[0].start, string, msg=( f"Expecting between {self.parser_config.min_match} and" f" {self.parser_config.max_match} of {self.expr}"), ) else: return ParseResults(self, acc[0].start, acc[-1].end, acc) else: if not self.parser_config.min_match: return ParseResults(self, start, start, []) else: raise ParseException( self, start, string, msg= f"Expecting at least {self.parser_config.min_match} of {self}", )
def parseImpl(self, string, start, doActions=True): if self.regex: found = self.regex.match(string, start) if found: return ParseResults(self, start, start, []) raise ParseException(self, start, string) else: try: self.expr.parse(string, start, doActions=True) raise ParseException(self, start, string) except: return ParseResults(self, start, start, [])
def parseImpl(self, string, start, doActions=True): causes = [] matches = [] for e in self.exprs: try: end = e.tryParse(string, start) matches.append((end, e)) except ParseException as err: causes.append(err) if matches: # re-evaluate all matches in descending order of length of match, in case attached actions # might change whether or how much they match of the input. matches.sort(key=itemgetter(0), reverse=True) if not doActions: # no further conditions or parse actions to change the selection of # alternative, so the first match will be the best match _, best_expr = matches[0] best_results = best_expr._parse(string, start, doActions) return ParseResults(self, best_results.start, best_results.end, [best_results]) longest = -1, None for loc, expr1 in matches: if loc <= longest[0]: # already have a longer match than this one will deliver, we are done return longest try: toks = expr1._parse(string, start, doActions) except ParseException as err: causes.append(err) else: if toks.end >= loc: return ParseResults(self, toks.start, toks.end, [toks]) # didn't match as much as before elif toks.end > longest[0]: longest = ( toks.end, ParseResults(self, toks.start, toks.end, [toks]), ) if longest != (-1, None): return longest raise ParseException(self, start, string, msg="no defined alternatives to match", cause=causes)
def parseImpl(self, string, end, doActions=True): start = end instrlen = len(string) end_parse = self.expr._parse self_failOn_canParseNext = (self.failOn.canParseNext if self.failOn is not None else None) self_ignoreExpr_tryParse = (self.ignoreExpr.tryParse if self.ignoreExpr is not None else None) tmploc = end while tmploc <= instrlen: if self_failOn_canParseNext is not None: # break if failOn expression matches if self_failOn_canParseNext(string, tmploc): before_end = tmploc break if self_ignoreExpr_tryParse is not None: # advance past ignore expressions while 1: try: tmploc = self_ignoreExpr_tryParse(string, tmploc) except ParseBaseException: break try: before_end = tmploc tmploc, _ = end_parse(string, tmploc, doActions=False) except (ParseException, IndexError): # no match, advance loc in string tmploc += 1 else: # matched skipto expr, done break else: # ran off the end of the input string without matching skipto expr, fail raise ParseException(self, end, string) # build up return values end = tmploc skiptext = string[start:before_end] skip_result = [] if skiptext: skip_result.append(skiptext) if self.includeMatch: _, end_result = end_parse(string, before_end, doActions) skip_result.append(end_result) return end, ParseResults(self, skip_result) else: return before_end, ParseResults(self, skip_result)
def parseImpl(self, string, start, doActions=True): instrlen = len(string) fail = self.parser_config.fail ignore = self.parser_config.ignore loc = start while loc <= instrlen: if fail: # break if failOn expression matches if fail.canParseNext(string, loc): before_end = loc break if ignore: # advance past ignore expressions while 1: try: loc = ignore.tryParse(string, loc) if loc == None: Log.error("") except ParseException: break try: before_end = loc loc = self.expr._parse(string, loc, doActions=False).end if loc == None: Log.error("") except ParseException: # no match, advance loc in string loc += 1 else: # matched skipto expr, done break else: # ran off the end of the input string without matching skipto expr, fail raise ParseException(self, start, string) # build up return values end = loc skiptext = string[start:before_end] skip_result = [] if skiptext: skip_result.append(skiptext) if self.parser_config.include: end_result = self.expr._parse(string, before_end, doActions) skip_result.append(end_result) return ParseResults(self, start, end, skip_result) else: return ParseResults(self, start, before_end, skip_result)
def parseImpl(self, string, loc, doActions=True): start = loc instrlen = len(string) maxloc = start + len(self.match_string) if maxloc <= instrlen: match_string = self.match_string match_stringloc = 0 mismatches = [] maxMismatches = self.maxMismatches for match_stringloc, (src, mat) in enumerate( zip(string[loc:maxloc], match_string)): if src != mat: mismatches.append(match_stringloc) if len(mismatches) > maxMismatches: break else: loc = match_stringloc + 1 results = ParseResults(self, [string[start:loc]]) results["original"] = match_string results["mismatches"] = mismatches return loc, results raise ParseException(self, loc, string)
def parseImpl(self, string, loc, doActions=True): # pass False as last arg to _parse for first element, since we already # pre-parsed the string as part of our And pre-parsing encountered_error_stop = False acc = [] for expr in self.exprs: if isinstance(expr, And._ErrorStop): encountered_error_stop = True continue try: loc, exprtokens = expr._parse(string, loc, doActions) acc.append(exprtokens) except ParseSyntaxException as cause: raise cause except ParseBaseException as pe: if encountered_error_stop: raise ParseSyntaxException(pe.parserElement, pe.loc, pe.pstr) else: raise pe except IndexError as ie: if encountered_error_stop: raise ParseSyntaxException(string, len(string), self) else: raise ie return loc, ParseResults(self, acc)
def parseImpl(self, string, loc, doActions=True): result = (string[loc] == self.firstQuoteChar and self.re_match(string, loc) or None) if not result: raise ParseException(self, loc, string) loc = result.end() ret = result.group() if self.unquoteResults: # strip off quotes ret = ret[self.quoteCharLen:-self.endQuoteCharLen] if isinstance(ret, text): # replace escaped whitespace if "\\" in ret and self.convertWhitespaceEscapes: ws_map = { r"\t": "\t", r"\n": "\n", r"\f": "\f", r"\r": "\r", } for wslit, wschar in ws_map.items(): ret = ret.replace(wslit, wschar) # replace escaped characters if self.escChar: ret = re.sub(self.escCharReplacePattern, r"\g<1>", ret) # replace escaped quotes if self.escQuote: ret = ret.replace(self.escQuote, self.endQuoteChar) return loc, ParseResults(self, [ret])
def parseImpl(self, string, loc, doActions=True): if loc != 0: if string[ loc - 1] in self.wordChars or string[loc] not in self.wordChars: raise ParseException(self, loc, string) return loc, ParseResults(self, [])
def _searchString(self, string, maxMatches=MAX_INT): if isinstance(self, Group): g = self scanned = [t for t, s, e in self._scanString(string, maxMatches)] else: g = Group(self) scanned = [ ParseResults(g, s, e, [t]) for t, s, e in self._scanString(string, maxMatches) ] if not scanned: return ParseResults(ZeroOrMore(g), -1, 0, []) else: return ParseResults(ZeroOrMore(g), scanned[0].start, scanned[-1].end, scanned)
def parseImpl(self, string, start=0, doActions=True): if self.parser_config.exact: loc = start - self.parser_config.retreat if loc < 0: raise ParseException(self, start, string) ret = self.expr._parse(string, loc) else: # retreat specified a maximum lookbehind window, iterate test_expr = self.expr + StringEnd() instring_slice = string[:start] last_cause = ParseException(self, start, string) with self.engine.backup(): for offset in range(self.parser_config.retreat, start + 1): try: ret = test_expr._parse(instring_slice, start - offset) break except ParseException as cause: last_cause = cause else: raise last_cause # return empty list of tokens, but preserve any defined results names ret.__class__ = Annotation return ParseResults(self, start, start, [ret])
def parseImpl(self, string, loc, doActions=True): if string[loc] not in self.initChars: raise ParseException(self, loc, string) start = loc loc += 1 instrlen = len(string) bodychars = self.bodyChars maxloc = start + self.maxLen maxloc = min(maxloc, instrlen) while loc < maxloc and string[loc] in bodychars: loc += 1 throwException = False if loc - start < self.minLen: throwException = True elif self.maxSpecified and loc < instrlen and string[loc] in bodychars: throwException = True elif self.asKeyword: if (start > 0 and string[start - 1] in bodychars or loc < instrlen and string[loc] in bodychars): throwException = True if throwException: raise ParseException(self, loc, string) return loc, ParseResults(self, [string[start:loc]])
def parseImpl(self, string, start, doActions=True): end = start instrlen = len(string) maxloc = start + len(self.parser_config.match) if maxloc <= instrlen: match = self.parser_config.match match_stringloc = 0 mismatches = [] maxMismatches = self.parser_config.maxMismatches for match_stringloc, (src, mat) in enumerate( zip(string[end:maxloc], match)): if src != mat: mismatches.append(match_stringloc) if len(mismatches) > maxMismatches: break else: end = match_stringloc + 1 results = ParseResults(self, start, end, [string[start:end]]) results["original"] = match results["mismatches"] = mismatches return results raise ParseException(self, start, string)
def parseImpl(self, string, loc, doActions=True): instrlen = len(string) if instrlen > 0 and loc < instrlen: if string[loc] in self.wordChars or string[ loc - 1] not in self.wordChars: raise ParseException(self, loc, string) return loc, ParseResults(self, [])
def parseImpl(self, string, start, doActions=True): # by using self._expr.parse and deleting the contents of the returned ParseResults list # we keep any named results that were defined in the FollowedBy expression result = self.expr._parse(string, start, doActions=doActions) result.__class__ = Annotation return ParseResults(self, start, start, [result])
def post_parse(tokens): ret = tokens[0] if unquote_results: # strip off quotes ret = ret[len(quote_char) : -len(end_quote_char)] if isinstance(ret, text): # replace escaped whitespace if "\\" in ret and convert_whitespace_escape: ws_map = { r"\t": "\t", r"\n": "\n", r"\f": "\f", r"\r": "\r", } for wslit, wschar in ws_map.items(): ret = ret.replace(wslit, wschar) # replace escaped characters if esc_char: ret = re.sub(esc_char_replace_pattern, r"\g<1>", ret) # replace escaped quotes if esc_quote: ret = ret.replace(esc_quote, end_quote_char) return ParseResults(tokens.type, tokens.start, tokens.end, [ret])
def extractText(tokens, loc, string): start, d, end = tokens content = string[start:end] annotations = [ Annotation(k, v[0].start, v[-1].end, v) for k, v in d.items() ] return ParseResults(d.type, start, end, [content] + annotations)
def parseImpl(self, string, start, doActions=True): word_chars = self.parser_config.word_chars instrlen = len(string) if instrlen > 0 and start < instrlen: if string[start] in word_chars or string[start - 1] not in word_chars: raise ParseException(self, start, string) return ParseResults(self, start, start, [])
def parseImpl(self, string, loc, doActions=True): result = self.re.match(string, loc) if not result: raise ParseException(self, loc, string) loc = result.end() return loc, ParseResults(self, [result.group()])
def parseImpl(self, string, loc, doActions=True): end_loc = loc matchOrder = [] todo = list(zip( self.exprs, self.parser_config.min_match, self.parser_config.max_match )) count = [0] * len(self.exprs) while todo: for i, (c, (e, mi, ma)) in enumerate(zip(count, todo)): try: temp_loc = e.tryParse(string, end_loc) if temp_loc == end_loc: continue end_loc = temp_loc c2 = count[i] = c + 1 if c2 >= ma: del todo[i] del count[i] matchOrder.append(e) break except ParseException as pe: continue else: break for c, (e, mi, ma) in zip(count, todo): if c < mi: raise ParseException( string, loc, "Missing minimum (%i) more required elements (%s)" % (mi, e), ) found = set(id(m) for m in matchOrder) missing = [ e for e, mi in zip(self.exprs, self.parser_config.min_matches) if id(e) not in found and not e.parser_config.mayReturnEmpty and mi > 0 ] if missing: missing = ", ".join(text(e) for e in missing) raise ParseException( string, loc, "Missing one or more required elements (%s)" % missing ) # add any unmatched Optionals, in case they have default values defined matchOrder += [ e for e in self.exprs if id(e) not in found and e.parser_config.mayReturnEmpty ] results = [] for e in matchOrder: loc, result = e._parse(string, loc, doActions) results.append(result) return loc, ParseResults(self, results)
def parseImpl(self, string, start, doActions=True): try: if string[start] == self.parser_config.match: return ParseResults(self, start, start + 1, [self.parser_config.match]) except IndexError: pass raise ParseException(self, start, string)
def _combine(tokens, start, string): output = ParseResults( tokens.type, tokens.start, tokens.end, [tokens.asString(sep=tokens.type.parser_config.separator)], ) return output
def parseImpl(self, string, start, doActions=True): result = self.expr.parseImpl(string, start, doActions=doActions) output = ParseResults( self, start, result.end, [result.asString(sep=self.parser_config.separator)], ) return output
def parseImpl(self, string, start, doActions=True): found = self.parser_config.regex.match(string, start) if found: return ParseResults( self, start, found.end(), [self.parser_config.match], ) raise ParseException(self, start, string)
def parseImpl(self, string, loc, doActions=True): try: result = self.expr._parse(string, loc, doActions) return ParseResults(self, result.start, result.end, [result]) except Exception as cause: if is_null(self.expr): Log.warning( "Ensure you have assigned a ParserElement (<<) to this Forward", cause=cause, ) raise cause