1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
|
import re
from . import info as _info
from .parser._regexes import SIMPLE_TYPE
_KIND = _info.KIND
def match_storage(decl, expected):
default = _info.get_default_storage(decl)
#assert default
if expected is None:
expected = {default}
elif isinstance(expected, str):
expected = {expected or default}
elif not expected:
expected = _info.STORAGE
else:
expected = {v or default for v in expected}
storage = _info.get_effective_storage(decl, default=default)
return storage in expected
##################################
# decl matchers
def is_type_decl(item):
return _KIND.is_type_decl(item.kind)
def is_decl(item):
return _KIND.is_decl(item.kind)
def is_pots(typespec, *,
_regex=re.compile(rf'^{SIMPLE_TYPE}$', re.VERBOSE),
):
if not typespec:
return None
if type(typespec) is not str:
_, _, _, typespec, _ = _info.get_parsed_vartype(typespec)
return _regex.match(typespec) is not None
def is_funcptr(vartype):
if not vartype:
return None
_, _, _, _, abstract = _info.get_parsed_vartype(vartype)
return _is_funcptr(abstract)
def _is_funcptr(declstr):
if not declstr:
return None
# XXX Support "(<name>*)(".
return '(*)(' in declstr.replace(' ', '')
def is_forward_decl(decl):
if decl.kind is _KIND.TYPEDEF:
return False
elif is_type_decl(decl):
return not decl.data
elif decl.kind is _KIND.FUNCTION:
# XXX This doesn't work with ParsedItem.
return decl.signature.isforward
elif decl.kind is _KIND.VARIABLE:
# No var decls are considered forward (or all are...).
return False
else:
raise NotImplementedError(decl)
def can_have_symbol(decl):
return decl.kind in (_KIND.VARIABLE, _KIND.FUNCTION)
def has_external_symbol(decl):
if not can_have_symbol(decl):
return False
if _info.get_effective_storage(decl) != 'extern':
return False
if decl.kind is _KIND.FUNCTION:
return not decl.signature.isforward
else:
# It must be a variable, which can only be implicitly extern here.
return decl.storage != 'extern'
def has_internal_symbol(decl):
if not can_have_symbol(decl):
return False
return _info.get_actual_storage(decl) == 'static'
def is_external_reference(decl):
if not can_have_symbol(decl):
return False
# We have to check the declared storage rather tnan the effective.
if decl.storage != 'extern':
return False
if decl.kind is _KIND.FUNCTION:
return decl.signature.isforward
# Otherwise it's a variable.
return True
def is_local_var(decl):
if not decl.kind is _KIND.VARIABLE:
return False
return True if decl.parent else False
def is_global_var(decl):
if not decl.kind is _KIND.VARIABLE:
return False
return False if decl.parent else True
##################################
# filtering with matchers
def filter_by_kind(items, kind):
if kind == 'type':
kinds = _KIND._TYPE_DECLS
elif kind == 'decl':
kinds = _KIND._TYPE_DECLS
try:
okay = kind in _KIND
except TypeError:
kinds = set(kind)
else:
kinds = {kind} if okay else set(kind)
for item in items:
if item.kind in kinds:
yield item
##################################
# grouping with matchers
def group_by_category(decls, categories, *, ignore_non_match=True):
collated = {}
for decl in decls:
# Matchers should be mutually exclusive. (First match wins.)
for category, match in categories.items():
if match(decl):
if category not in collated:
collated[category] = [decl]
else:
collated[category].append(decl)
break
else:
if not ignore_non_match:
raise Exception(f'no match for {decl!r}')
return collated
def group_by_kind(items):
collated = {kind: [] for kind in _KIND}
for item in items:
try:
collated[item.kind].append(item)
except KeyError:
raise ValueError(f'unsupported kind in {item!r}')
return collated
def group_by_kinds(items):
# Collate into kind groups (decl, type, etc.).
collated = {_KIND.get_group(k): [] for k in _KIND}
for item in items:
group = _KIND.get_group(item.kind)
collated[group].append(item)
return collated
|