Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
allendowney
GitHub Repository: allendowney/cpython
Path: blob/main/Tools/c-analyzer/c_parser/parser/_compound_decl_body.py
12 views
1
import re
2
3
from ._regexes import (
4
STRUCT_MEMBER_DECL as _STRUCT_MEMBER_DECL,
5
ENUM_MEMBER_DECL as _ENUM_MEMBER_DECL,
6
)
7
from ._common import (
8
log_match,
9
parse_var_decl,
10
set_capture_groups,
11
)
12
13
14
#############################
15
# struct / union
16
17
STRUCT_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
))
26
STRUCT_MEMBER_RE = re.compile(rf'^ \s* {STRUCT_MEMBER_DECL}', re.VERBOSE)
27
28
29
def 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
51
def _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) if size.isdigit() else 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
118
ENUM_MEMBER_DECL = set_capture_groups(_ENUM_MEMBER_DECL, (
119
'CLOSE',
120
'NAME',
121
'INIT',
122
'ENDING',
123
))
124
ENUM_MEMBER_RE = re.compile(rf'{ENUM_MEMBER_DECL}', re.VERBOSE)
125
126
127
def 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
154
DECL_BODY_PARSERS = {
155
'struct': parse_struct_body,
156
'union': parse_struct_body,
157
'enum': parse_enum_body,
158
}
159
160