• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import re
2
3from ._regexes import (
4    GLOBAL as _GLOBAL,
5)
6from ._common import (
7    log_match,
8    parse_var_decl,
9    set_capture_groups,
10)
11from ._compound_decl_body import DECL_BODY_PARSERS
12from ._func_body import parse_function_statics as parse_function_body
13
14
15GLOBAL = set_capture_groups(_GLOBAL, (
16    'EMPTY',
17    'COMPOUND_LEADING',
18    'COMPOUND_KIND',
19    'COMPOUND_NAME',
20    'FORWARD_KIND',
21    'FORWARD_NAME',
22    'MAYBE_INLINE_ACTUAL',
23    'TYPEDEF_DECL',
24    'TYPEDEF_FUNC_PARAMS',
25    'VAR_STORAGE',
26    'FUNC_INLINE',
27    'VAR_DECL',
28    'FUNC_PARAMS',
29    'FUNC_DELIM',
30    'FUNC_LEGACY_PARAMS',
31    'VAR_INIT',
32    'VAR_ENDING',
33))
34GLOBAL_RE = re.compile(rf'^ \s* {GLOBAL}', re.VERBOSE)
35
36
37def parse_globals(source, anon_name):
38    for srcinfo in source:
39        m = GLOBAL_RE.match(srcinfo.text)
40        if not m:
41            # We need more text.
42            continue
43        for item in _parse_next(m, srcinfo, anon_name):
44            if callable(item):
45                parse_body = item
46                yield from parse_body(source)
47            else:
48                yield item
49    else:
50        # We ran out of lines.
51        if srcinfo is not None:
52            srcinfo.done()
53        return
54
55
56def _parse_next(m, srcinfo, anon_name):
57    (
58     empty,
59     # compound type decl (maybe inline)
60     compound_leading, compound_kind, compound_name,
61     forward_kind, forward_name, maybe_inline_actual,
62     # typedef
63     typedef_decl, typedef_func_params,
64     # vars and funcs
65     storage, func_inline, decl,
66     func_params, func_delim, func_legacy_params,
67     var_init, var_ending,
68     ) = m.groups()
69    remainder = srcinfo.text[m.end():]
70
71    if empty:
72        log_match('global empty', m)
73        srcinfo.advance(remainder)
74
75    elif maybe_inline_actual:
76        log_match('maybe_inline_actual', m)
77        # Ignore forward declarations.
78        # XXX Maybe return them too (with an "isforward" flag)?
79        if not maybe_inline_actual.strip().endswith(';'):
80            remainder = maybe_inline_actual + remainder
81        yield srcinfo.resolve(forward_kind, None, forward_name)
82        if maybe_inline_actual.strip().endswith('='):
83            # We use a dummy prefix for a fake typedef.
84            # XXX Ideally this case would not be caught by MAYBE_INLINE_ACTUAL.
85            _, name, data = parse_var_decl(f'{forward_kind} {forward_name} fake_typedef_{forward_name}')
86            yield srcinfo.resolve('typedef', data, name, parent=None)
87            remainder = f'{name} {remainder}'
88        srcinfo.advance(remainder)
89
90    elif compound_kind:
91        kind = compound_kind
92        name = compound_name or anon_name('inline-')
93        # Immediately emit a forward declaration.
94        yield srcinfo.resolve(kind, name=name, data=None)
95
96        # un-inline the decl.  Note that it might not actually be inline.
97        # We handle the case in the "maybe_inline_actual" branch.
98        srcinfo.nest(
99            remainder,
100            f'{compound_leading or ""} {compound_kind} {name}',
101        )
102        def parse_body(source):
103            _parse_body = DECL_BODY_PARSERS[compound_kind]
104
105            data = []  # members
106            ident = f'{kind} {name}'
107            for item in _parse_body(source, anon_name, ident):
108                if item.kind == 'field':
109                    data.append(item)
110                else:
111                    yield item
112            # XXX Should "parent" really be None for inline type decls?
113            yield srcinfo.resolve(kind, data, name, parent=None)
114
115            srcinfo.resume()
116        yield parse_body
117
118    elif typedef_decl:
119        log_match('typedef', m)
120        kind = 'typedef'
121        _, name, data = parse_var_decl(typedef_decl)
122        if typedef_func_params:
123            return_type = data
124            # This matches the data for func declarations.
125            data = {
126                'storage': None,
127                'inline': None,
128                'params': f'({typedef_func_params})',
129                'returntype': return_type,
130                'isforward': True,
131            }
132        yield srcinfo.resolve(kind, data, name, parent=None)
133        srcinfo.advance(remainder)
134
135    elif func_delim or func_legacy_params:
136        log_match('function', m)
137        kind = 'function'
138        _, name, return_type = parse_var_decl(decl)
139        func_params = func_params or func_legacy_params
140        data = {
141            'storage': storage,
142            'inline': func_inline,
143            'params': f'({func_params})',
144            'returntype': return_type,
145            'isforward': func_delim == ';',
146        }
147
148        yield srcinfo.resolve(kind, data, name, parent=None)
149        srcinfo.advance(remainder)
150
151        if func_delim == '{' or func_legacy_params:
152            def parse_body(source):
153                yield from parse_function_body(source, name, anon_name)
154            yield parse_body
155
156    elif var_ending:
157        log_match('global variable', m)
158        kind = 'variable'
159        _, name, vartype = parse_var_decl(decl)
160        data = {
161            'storage': storage,
162            'vartype': vartype,
163        }
164        yield srcinfo.resolve(kind, data, name, parent=None)
165
166        if var_ending == ',':
167            # It was a multi-declaration, so queue up the next one.
168            _, qual, typespec, _ = vartype.values()
169            remainder = f'{storage or ""} {qual or ""} {typespec} {remainder}'
170        srcinfo.advance(remainder)
171
172        if var_init:
173            _data = f'{name} = {var_init.strip()}'
174            yield srcinfo.resolve('statement', _data, name=None)
175
176    else:
177        # This should be unreachable.
178        raise NotImplementedError
179