def __iter__(self): if is_forward(self.type): if len(self.tokens) != 1: Log.error("not expected") output = list(self.tokens[0]) for i in output: yield i return for r in self.tokens: if isinstance(r, Annotation): continue elif isinstance(r, ParseResults): if isinstance(r, Annotation): return elif isinstance(r.type, Group): yield r elif is_forward(r.type) and isinstance(forward_type(r), Group): yield r elif not isinstance(r.type, Group): for mm in r: yield mm else: yield r
def __init__(self, result_type, start, end, tokens): if end == -1: Log.error("not allowed") self.type = result_type self.start = start self.end = end self.tokens = tokens
def __init__(self, pattern, flags=0, asGroupList=False, asMatch=False): """The parameters ``pattern`` and ``flags`` are passed to the ``regex_compile()`` function as-is. See the Python `re module <https://docs.python.org/3/library/re.html>`_ module for an explanation of the acceptable patterns and flags. """ Token.__init__(self) if isinstance(pattern, text): if not pattern: warnings.warn( "null string passed to Regex; use Empty() instead", SyntaxWarning, stacklevel=2, ) try: self.set_config(flags=flags, regex=re.compile(pattern, flags)) except sre_constants.error as cause: Log.error( "invalid pattern {{pattern}} passed to Regex", pattern=pattern, cause=cause, ) elif isinstance(pattern, regex_type): self.set_config(flags=flags, regex=pattern) else: Log.error( "Regex may only be constructed with a string or a compiled RE object" ) self.parser_name = text(self)
def _parse(self, string, start, doActions=True): lookup = (self, string, start, doActions) value = packrat_cache.get(lookup) if value is not None: if isinstance(value, Exception): raise value return value try: index = self.engine.skip(string, start) try: result = self.parseImpl(string, index, doActions) except Exception as cause: self.parser_config.failAction and self.parser_config.failAction( self, start, string, cause ) raise if self.parseAction and (doActions or self.parser_config.callDuringTry): for fn in self.parseAction: next_result = fn(result, index, string) if next_result.end < result.end: fn(result, index, string) Log.error("parse action not allowed to roll back the end of parsing") result = next_result except ParseException as cause: packrat_cache.set(lookup, cause) raise packrat_cache.set(lookup, result) return result
def __init__(self, tokens, loc, string): if not isinstance(string, str): Log.error("expecting string") self.pstr = string self.loc = loc self.parserElement = tokens self._msg = ""
def repeat(tokens): if tokens.length() == 1: return tokens.value() try: operand, operator = tokens except Exception as cause: Log.error("not expected", cause=cause) mode = operator["mode"] if not mode: if operator["exact"]: return Many(operand, PLAIN_ENGINE, exact=int(operator["exact"])) else: return Many(operand, PLAIN_ENGINE, min_match=int(operator["min"]), max_match=int(operator["max"])) elif mode in "*?": return ZeroOrMore(operand, PLAIN_ENGINE) elif mode in "+?": return OneOrMore(operand, PLAIN_ENGINE) elif mode == "?": return Optional(operand, PLAIN_ENGINE) else: Log.error("not expected")
def __setitem__(self, k, v): if isinstance(k, (slice, int)): Log.error("not supported") if v is None: v = NO_RESULTS if is_forward(self): self.tokens[0][k] = v return for i, tok in enumerate(self.tokens): if isinstance(tok, ParseResults): if tok.name == k: self.tokens[i] = v v = NO_RESULTS # ERASE ALL OTHERS elif isinstance(tok.type, Group): continue elif is_forward(tok.type) and isinstance( tok.tokens[0].type, Group): continue elif tok.name: continue tok.__setitem__(k, NO_RESULTS) # ERASE ALL CHILDREN if v is not NO_RESULTS: self.tokens.append(Annotation(k, [v]))
def __new__(cls, matchString, identChars=None, caseless=None): if len(matchString) == 0: Log.error("Expecting more than one character in keyword") if caseless: return object.__new__(CaselessKeyword) else: return object.__new__(cls)
def __init__(self, match): Token.__init__(self) self.set_config(match=match) if len(match) == 0: Log.error("Literal must be at least one character") elif len(match) == 1: self.__class__ = SingleCharLiteral
def min_length(self): if not hasattr(self, "min_cache"): Log.error("should not happen") if self.min_cache >= 0: return self.min_cache min_ = self._min_length() if self.streamlined: self.min_cache = min_ return min_
def __init__(self, expr, start, string, msg="", cause=None): if not isinstance(string, str): Log.error("expecting string") self.expr = expr self.start = start self.string = string self._msg = msg self.unsorted_cause = cause self._causes = None
def output(*args, **kwargs): with locker: for a in _reset_actions: try: a() except Exception as e: Log.error("reset action failed", cause=e) return func(*args, **kwargs)
def add(obj, key, value): if not isinstance(value, list): Log.error("not allowed") if value and isinstance(value[0], list): Log.error("not expected") old_v = obj.get(key) if old_v is None: obj[key] = value else: old_v.extend(value)
def __init__(self, matchString): Token.__init__(self) self.match = matchString self.parser_config.mayReturnEmpty = False self.parser_config.mayIndexError = False if len(matchString) == 0: Log.error("Literal must be at least one character") if len(matchString) == 1: self.__class__ = _SingleCharLiteral
def __lshift__(self, other): self.strRepr = "" if other == None: Log.error("can not set to None") if is_forward(self.expr): return self.expr << other while is_forward(other): other = other.expr self.expr = engine.CURRENT.normalize(other) return self
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
def __exit__(self, exc_type, exc_val, exc_tb): """ ENSURE self IS NOT CURRENT :return: """ global CURRENT if not self.previous: Log.error("expecting engine to be released just once") CURRENT = self.previous self.previous = None
def __call__(self, name): if not name: return self for e in [self.expr]: if isinstance(e, ParserElement) and e.token_name == name: Log.error( "can not set token name, already set in one of the other" " expressions") return ParseEnhancement.__call__(self, name)
def clear(self): if DEBUG and self.hit + self.miss > 100: Log.note( "Hit Rate: {{rate|round(places=2)|percent}} (hits={{hits}}," " misses={{misses}})", rate=self.hit / (self.hit + self.miss), hits=self.hit, misses=self.miss, ) self.hit = 0 self.miss = 0 self.cache.clear()
def drill(e): if isinstance(e, Literal): chars.add(e.parser_config.match) elif isinstance(e, Char): chars.update(c for c in e.parser_config.include) elif isinstance(e, MatchFirst): for ee in e.exprs: drill(ee) elif isinstance(e, And): drill(e.exprs[0].expr) else: Log.error("logic error")
def to_bracket(tokens): acc = [] for e in listwrap(tokens["body"].value()): if isinstance(e, SingleCharLiteral): acc.append(e.parser_config.match) elif isinstance(e, Char): acc.extend(e.parser_config.include) else: Log.error("programmer error") if tokens["negate"]: return Char(exclude=acc) else: return Char(acc)
def parseImpl(self, string, loc, doActions=True): try: temp = self.expr result = self.expr._parse(string, loc, doActions) loc, output = result return loc, ParseResults(self, [output]) except Exception as cause: if self.expr == None: Log.warning( "Ensure you have assigned a ParserElement (<<) to this Forward", cause=cause, ) raise cause
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 cond(token, index, string): result = fn(token, index, string) if not bool(result.tokens[0]): if fatal: Log.error("fatal error", casue=ParseException(token.type, index, string, msg=message)) raise ParseException(token.type, index, string, msg=message) return token
def normalize(self, expr): if expr == None: return None if is_text(expr): if issubclass(self.literal, Token): return self.literal(expr) else: return self.literal(Literal(expr)) if isinstance(expr, type) and issubclass(expr, ParserElement): return expr() # ALLOW Empty WHEN Empty() WAS INTENDED if not isinstance(expr, ParserElement): Log.error("expecting string, or ParserElemenet") return expr
def __getattr__(self, item): """ IF THERE IS ONLY ONE VALUE, THEN DEFER TO IT """ iter = self.__iter__() try: v1 = iter.__next__() try: iter.__next__() raise Log.error("No attribute {{item}} for mutiple tokens", item=item) except Exception: return getattr(v1, item) except Exception: raise Log.error("No attribute {{item}}", item=item)
def output(*args, **kwargs): with locker: for a in _reset_actions: try: a() except Exception as e: Log.error("reset action failed", cause=e) self = args[0] if not self.streamlined and ( not is_forward(self) or not self.expr.streamlined ): Log.alert("Expecting expression to be streamlined before use") self = self.streamline() return func(self, *args[1:], **kwargs)
def normalize(self, expr): if expr == None: return Null if is_text(expr): if issubclass(self.literal, Token): return self.literal(expr) else: return self.literal(Literal(expr)) if not isinstance(expr, ParserElement): Log.error("expecting string, or ParserElemenet") # curr_engine = expr.engine # if curr_engine != self and not expr.parser_config.lock_engine: # # UPDATE ENGINE IF NOT LOCKED # expr = expr.copy() return expr
def __eq__(self, other): if other == None: return not self.__bool__() elif is_text(other): try: return "".join(self) == other except Exception as e: return False elif is_many(other): return all(s == o for s, o in zip_longest(self, other)) elif self.length() == 1: return self[0] == other elif not self: return False else: Log.error("do not know how to handle")
def _parse(self, string, start, doActions=True): try: result = self.parseImpl(string, start, doActions) except Exception as cause: self.parser_config.failAction and self.parser_config.failAction( self, start, string, cause) raise if doActions or self.parser_config.callDuringTry: for fn in self.parseAction: next_result = fn(result, result.start, string) if next_result.end < result.end: Log.error( "parse action not allowed to roll back the end of parsing" ) result = next_result return result