662 lines · 19.7 KB · Python
RawDownload
    """      def __init__(self, regex, delim="("):        self.regex = KernRe("^" + regex + r"\b")        self.start_delim = delim     def _search(self, tokenizer):        """        Finds paired blocks for a regex that ends with a delimiter.         The suggestion of using finditer to match pairs came from:        https://stackoverflow.com/questions/5454322/python-how-to-match-nested-parentheses-with-regex        but I ended using a different implementation to align all three types        of delimiters and seek for an initial regular expression.         The algorithm seeks for open/close paired delimiters and places them        into a stack, yielding a start/stop position of each match when the        stack is zeroed.         The algorithm should work fine for properly paired lines, but will        silently ignore end delimiters that precede a start delimiter.        This should be OK for kernel-doc parser, as unaligned delimiters        would cause compilation errors. So, we don't need to raise exceptions        to cover such issues.        """         start = None        started = False         import sys         stack = []         for i, tok in enumerate(tokenizer.tokens):            if start is None:                if tok.kind == CToken.NAME and self.regex.match(tok.value):                    start = i                    stack.append((start, tok.level))                    started = False                 continue             if not started:                if tok.kind == CToken.SPACE:                    continue                 if tok.kind == CToken.BEGIN and tok.value == self.start_delim:                    started = True                    continue                 # Name only token without BEGIN/END                if i > start:                    i -= 1                yield start, i                start = None             if tok.kind == CToken.END and tok.level == stack[-1][1]:                start, level = stack.pop()                 yield start, i                start = None         #        # If an END zeroing levels is not there, return remaining stuff        # This is meant to solve cases where the caller logic might be        # picking an incomplete block.        #        if start and stack:            if started:                s = str(tokenizer)                log.warning(f"can't find a final end at {s}")             yield start, len(tokenizer.tokens)     def search(self, source):        """        This is similar to re.search:         It matches a regex that it is followed by a delimiter,        returning occurrences only if all delimiters are paired.        """         if isinstance(source, CTokenizer):            tokenizer = source            is_token = True        else:            tokenizer = CTokenizer(source)            is_token = False         for start, end in self._search(tokenizer):            new_tokenizer = CTokenizer(tokenizer.tokens[start:end + 1])             if is_token:                yield new_tokenizer            else:                yield str(new_tokenizer)     def sub(self, sub_str, source, count=0):        """        This is similar to re.sub:         It matches a regex that it is followed by a delimiter,        replacing occurrences only if all delimiters are paired.         if the sub argument contains::             r'\0'         it will work just like re: it places there the matched paired data        with the delimiter stripped.         If count is different than zero, it will replace at most count        items.        """        if isinstance(source, CTokenizer):            is_token = True            tokenizer = source        else:            is_token = False            tokenizer = CTokenizer(source)         # Detect if sub_str contains sub arguments         args_match = CTokenArgs(sub_str)         new_tokenizer = CTokenizer()        pos = 0        n = 0         #        # NOTE: the code below doesn't consider overlays at sub.        # We may need to add some extra unit tests to check if those        # would cause problems. When replacing by "", this should not        # be a problem, but other transformations could be problematic        #        for start, end in self._search(tokenizer):            new_tokenizer.tokens += tokenizer.tokens[pos:start]             new = CTokenizer(tokenizer.tokens[start:end + 1])             new_tokenizer.tokens += args_match.tokens(new)             pos = end + 1             n += 1            if count and n >= count:                break         new_tokenizer.tokens += tokenizer.tokens[pos:]         if not is_token:            return str(new_tokenizer)         return new_tokenizer     def __repr__(self):        """        Returns a displayable version of the class init.        """         return f'CMatch("{self.regex.regex.pattern}")'

Lines 501–662 of 662. Previous lines