From 0b398062710dc00b952636bcf7b7933f74f125da Mon Sep 17 00:00:00 2001 From: Paul McGuire Date: Mon, 18 Nov 2019 22:41:40 -0600 Subject: Break up pyparsing.py monolith into sub-modules in a pyparsing package (#162) * Break up pyparsing.py monolith into sub-modules in a pyparsing package * Convert relative imports to absolutes * Reference submodule pyparsing in setup.py modules * Remove recursive import of pyparsing from setup.py * Black updates * setup.py updates - packages vs. modules. use .dev1 for the version --- pyparsing/util.py | 171 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 pyparsing/util.py (limited to 'pyparsing/util.py') diff --git a/pyparsing/util.py b/pyparsing/util.py new file mode 100644 index 0000000..376b9ae --- /dev/null +++ b/pyparsing/util.py @@ -0,0 +1,171 @@ +# util.py +import warnings +import types +import collections +import itertools + + +_bslash = chr(92) + + +class __config_flags: + """Internal class for defining compatibility and debugging flags""" + + _all_names = [] + _fixed_names = [] + _type_desc = "configuration" + + @classmethod + def _set(cls, dname, value): + if dname in cls._fixed_names: + warnings.warn( + "{}.{} {} is {} and cannot be overridden".format( + cls.__name__, + dname, + cls._type_desc, + str(getattr(cls, dname)).upper(), + ) + ) + return + if dname in cls._all_names: + setattr(cls, dname, value) + else: + raise ValueError("no such {} {!r}".format(cls._type_desc, dname)) + + enable = classmethod(lambda cls, name: cls._set(name, True)) + disable = classmethod(lambda cls, name: cls._set(name, False)) + + +def col(loc, strg): + """Returns current column within a string, counting newlines as line separators. + The first column is number 1. + + Note: the default parsing behavior is to expand tabs in the input string + before starting the parsing process. See + :class:`ParserElement.parseString` for more + information on parsing strings containing ```` s, and suggested + methods to maintain a consistent view of the parsed string, the parse + location, and line and column positions within the parsed string. + """ + s = strg + return 1 if 0 < loc < len(s) and s[loc - 1] == "\n" else loc - s.rfind("\n", 0, loc) + + +def lineno(loc, strg): + """Returns current line number within a string, counting newlines as line separators. + The first line is number 1. + + Note - the default parsing behavior is to expand tabs in the input string + before starting the parsing process. See :class:`ParserElement.parseString` + for more information on parsing strings containing ```` s, and + suggested methods to maintain a consistent view of the parsed string, the + parse location, and line and column positions within the parsed string. + """ + return strg.count("\n", 0, loc) + 1 + + +def line(loc, strg): + """Returns the line of text containing loc within a string, counting newlines as line separators. + """ + lastCR = strg.rfind("\n", 0, loc) + nextCR = strg.find("\n", loc) + return strg[lastCR + 1 : nextCR] if nextCR >= 0 else strg[lastCR + 1 :] + + +class _UnboundedCache: + def __init__(self): + cache = {} + self.not_in_cache = not_in_cache = object() + + def get(self, key): + return cache.get(key, not_in_cache) + + def set(self, key, value): + cache[key] = value + + def clear(self): + cache.clear() + + def cache_len(self): + return len(cache) + + self.get = types.MethodType(get, self) + self.set = types.MethodType(set, self) + self.clear = types.MethodType(clear, self) + self.__len__ = types.MethodType(cache_len, self) + + +class _FifoCache: + def __init__(self, size): + self.not_in_cache = not_in_cache = object() + cache = collections.OrderedDict() + + def get(self, key): + return cache.get(key, not_in_cache) + + def set(self, key, value): + cache[key] = value + try: + while len(cache) > size: + cache.popitem(False) + except KeyError: + pass + + def clear(self): + cache.clear() + + def cache_len(self): + return len(cache) + + self.get = types.MethodType(get, self) + self.set = types.MethodType(set, self) + self.clear = types.MethodType(clear, self) + self.__len__ = types.MethodType(cache_len, self) + + +def _escapeRegexRangeChars(s): + # ~ escape these chars: ^-] + for c in r"\^-]": + s = s.replace(c, _bslash + c) + s = s.replace("\n", r"\n") + s = s.replace("\t", r"\t") + return str(s) + + +def _collapseAndEscapeRegexRangeChars(s): + def is_consecutive(c): + c_int = ord(c) + is_consecutive.prev, prev = c_int, is_consecutive.prev + if c_int - prev > 1: + is_consecutive.value = next(is_consecutive.counter) + return is_consecutive.value + + is_consecutive.prev = 0 + is_consecutive.counter = itertools.count() + is_consecutive.value = -1 + + def escape_re_range_char(c): + return "\\" + c if c in r"\^-]" else c + + ret = [] + for _, chars in itertools.groupby(sorted(s), key=is_consecutive): + first = last = next(chars) + for c in chars: + last = c + if first == last: + ret.append(escape_re_range_char(first)) + else: + ret.append( + "{}-{}".format(escape_re_range_char(first), escape_re_range_char(last)) + ) + return "".join(ret) + + +def _flatten(L): + ret = [] + for i in L: + if isinstance(i, list): + ret.extend(_flatten(i)) + else: + ret.append(i) + return ret -- cgit v1.2.1