• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import re
2
3from ._regexes import (
4    _ind,
5    STRING_LITERAL,
6    VAR_DECL as _VAR_DECL,
7)
8
9
10def log_match(group, m):
11    from . import _logger
12    _logger.debug(f'matched <{group}> ({m.group(0)})')
13
14
15#############################
16# regex utils
17
18def set_capture_group(pattern, group, *, strict=True):
19    old = f'(?:  # <{group}>'
20    if strict and f'(?:  # <{group}>' not in pattern:
21        raise ValueError(f'{old!r} not found in pattern')
22    return pattern.replace(old, f'(  # <{group}>', 1)
23
24
25def set_capture_groups(pattern, groups, *, strict=True):
26    for group in groups:
27        pattern = set_capture_group(pattern, group, strict=strict)
28    return pattern
29
30
31#############################
32# syntax-related utils
33
34_PAREN_RE = re.compile(rf'''
35    (?:
36        (?:
37            [^'"()]*
38            {_ind(STRING_LITERAL, 3)}
39         )*
40        [^'"()]*
41        (?:
42            ( [(] )
43            |
44            ( [)] )
45         )
46     )
47    ''', re.VERBOSE)
48
49
50def match_paren(text, depth=0):
51    pos = 0
52    while (m := _PAREN_RE.match(text, pos)):
53        pos = m.end()
54        _open, _close = m.groups()
55        if _open:
56            depth += 1
57        else:  # _close
58            depth -= 1
59            if depth == 0:
60                return pos
61    else:
62        raise ValueError(f'could not find matching parens for {text!r}')
63
64
65VAR_DECL = set_capture_groups(_VAR_DECL, (
66    'STORAGE',
67    'TYPE_QUAL',
68    'TYPE_SPEC',
69    'DECLARATOR',
70    'IDENTIFIER',
71    'WRAPPED_IDENTIFIER',
72    'FUNC_IDENTIFIER',
73))
74
75
76def parse_var_decl(decl):
77    m = re.match(VAR_DECL, decl, re.VERBOSE)
78    (storage, typequal, typespec, declarator,
79     name,
80     wrappedname,
81     funcptrname,
82     ) = m.groups()
83    if name:
84        kind = 'simple'
85    elif wrappedname:
86        kind = 'wrapped'
87        name = wrappedname
88    elif funcptrname:
89        kind = 'funcptr'
90        name = funcptrname
91    else:
92        raise NotImplementedError
93    abstract = declarator.replace(name, '')
94    vartype = {
95        'storage': storage,
96        'typequal': typequal,
97        'typespec': typespec,
98        'abstract': abstract,
99    }
100    return (kind, name, vartype)
101
102
103#############################
104# parser state utils
105
106# XXX Drop this or use it!
107def iter_results(results):
108    if not results:
109        return
110    if callable(results):
111        results = results()
112
113    for result, text in results():
114        if result:
115            yield result, text
116