• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import re
2
3from ._regexes import (
4    STRUCT_MEMBER_DECL as _STRUCT_MEMBER_DECL,
5    ENUM_MEMBER_DECL as _ENUM_MEMBER_DECL,
6)
7from ._common import (
8    log_match,
9    parse_var_decl,
10    set_capture_groups,
11)
12
13
14#############################
15# struct / union
16
17STRUCT_MEMBER_DECL = set_capture_groups(_STRUCT_MEMBER_DECL, (
18    'COMPOUND_TYPE_KIND',
19    'COMPOUND_TYPE_NAME',
20    'SPECIFIER_QUALIFIER',
21    'DECLARATOR',
22    'SIZE',
23    'ENDING',
24    'CLOSE',
25))
26STRUCT_MEMBER_RE = re.compile(rf'^ \s* {STRUCT_MEMBER_DECL}', re.VERBOSE)
27
28
29def parse_struct_body(source, anon_name, parent):
30    done = False
31    while not done:
32        done = True
33        for srcinfo in source:
34            m = STRUCT_MEMBER_RE.match(srcinfo.text)
35            if m:
36                break
37        else:
38            # We ran out of lines.
39            if srcinfo is not None:
40                srcinfo.done()
41            return
42        for item in _parse_struct_next(m, srcinfo, anon_name, parent):
43            if callable(item):
44                parse_body = item
45                yield from parse_body(source)
46            else:
47                yield item
48            done = False
49
50
51def _parse_struct_next(m, srcinfo, anon_name, parent):
52    (inline_kind, inline_name,
53     qualspec, declarator,
54     size,
55     ending,
56     close,
57     ) = m.groups()
58    remainder = srcinfo.text[m.end():]
59
60    if close:
61        log_match('compound close', m)
62        srcinfo.advance(remainder)
63
64    elif inline_kind:
65        log_match('compound inline', m)
66        kind = inline_kind
67        name = inline_name or anon_name('inline-')
68        # Immediately emit a forward declaration.
69        yield srcinfo.resolve(kind, name=name, data=None)
70
71        # un-inline the decl.  Note that it might not actually be inline.
72        # We handle the case in the "maybe_inline_actual" branch.
73        srcinfo.nest(
74            remainder,
75            f'{kind} {name}',
76        )
77        def parse_body(source):
78            _parse_body = DECL_BODY_PARSERS[kind]
79
80            data = []  # members
81            ident = f'{kind} {name}'
82            for item in _parse_body(source, anon_name, ident):
83                if item.kind == 'field':
84                    data.append(item)
85                else:
86                    yield item
87            # XXX Should "parent" really be None for inline type decls?
88            yield srcinfo.resolve(kind, data, name, parent=None)
89
90            srcinfo.resume()
91        yield parse_body
92
93    else:
94        # not inline (member)
95        log_match('compound member', m)
96        if qualspec:
97            _, name, data = parse_var_decl(f'{qualspec} {declarator}')
98            if not name:
99                name = anon_name('struct-field-')
100            if size:
101#                data = (data, size)
102                data['size'] = int(size)
103        else:
104            # This shouldn't happen (we expect each field to have a name).
105            raise NotImplementedError
106            name = sized_name or anon_name('struct-field-')
107            data = int(size)
108
109        yield srcinfo.resolve('field', data, name, parent)  # XXX Restart?
110        if ending == ',':
111            remainder = rf'{qualspec} {remainder}'
112        srcinfo.advance(remainder)
113
114
115#############################
116# enum
117
118ENUM_MEMBER_DECL = set_capture_groups(_ENUM_MEMBER_DECL, (
119    'CLOSE',
120    'NAME',
121    'INIT',
122    'ENDING',
123))
124ENUM_MEMBER_RE = re.compile(rf'{ENUM_MEMBER_DECL}', re.VERBOSE)
125
126
127def parse_enum_body(source, _anon_name, _parent):
128    ending = None
129    while ending != '}':
130        for srcinfo in source:
131            m = ENUM_MEMBER_RE.match(srcinfo.text)
132            if m:
133                break
134        else:
135            # We ran out of lines.
136            if srcinfo is not None:
137                srcinfo.done()
138            return
139        remainder = srcinfo.text[m.end():]
140
141        (close,
142         name, init, ending,
143         ) = m.groups()
144        if close:
145            ending = '}'
146        else:
147            data = init
148            yield srcinfo.resolve('field', data, name, _parent)
149        srcinfo.advance(remainder)
150
151
152#############################
153
154DECL_BODY_PARSERS = {
155    'struct': parse_struct_body,
156    'union': parse_struct_body,
157    'enum': parse_enum_body,
158}
159