1 import os.path
2
3 from c_parser import (
4 info as _info,
5 match as _match,
6 )
7
8
9 _KIND = _info.KIND
10
11
12 # XXX Use known.tsv for these?
13 SYSTEM_TYPES = {
14 'int8_t',
15 'uint8_t',
16 'int16_t',
17 'uint16_t',
18 'int32_t',
19 'uint32_t',
20 'int64_t',
21 'uint64_t',
22 'size_t',
23 'ssize_t',
24 'intptr_t',
25 'uintptr_t',
26 'wchar_t',
27 '',
28 # OS-specific
29 'pthread_cond_t',
30 'pthread_mutex_t',
31 'pthread_key_t',
32 'atomic_int',
33 'atomic_uintptr_t',
34 '',
35 # lib-specific
36 'WINDOW', # curses
37 'XML_LChar',
38 'XML_Size',
39 'XML_Parser',
40 'enum XML_Error',
41 'enum XML_Status',
42 '',
43 }
44
45
46 def is_system_type(typespec):
47 return typespec in SYSTEM_TYPES
48
49
50 ##################################
51 # decl matchers
52
53 def is_public(decl):
54 if not decl.filename.endswith('.h'):
55 return False
56 if 'Include' not in decl.filename.split(os.path.sep):
57 return False
58 return True
59
60
61 def is_process_global(vardecl):
62 kind, storage, _, _, _ = _info.get_parsed_vartype(vardecl)
63 if kind is not _KIND.VARIABLE:
64 raise NotImplementedError(vardecl)
65 if 'static' in (storage or ''):
66 return True
67
68 if hasattr(vardecl, 'parent'):
69 parent = vardecl.parent
70 else:
71 parent = vardecl.get('parent')
72 return not parent
73
74
75 def is_fixed_type(vardecl):
76 if not vardecl:
77 return None
78 _, _, _, typespec, abstract = _info.get_parsed_vartype(vardecl)
79 if 'typeof' in typespec:
80 raise NotImplementedError(vardecl)
81 elif not abstract:
82 return True
83
84 if '*' not in abstract:
85 # XXX What about []?
86 return True
87 elif _match._is_funcptr(abstract):
88 return True
89 else:
90 for after in abstract.split('*')[1:]:
91 if not after.lstrip().startswith('const'):
92 return False
93 else:
94 return True
95
96
97 def is_immutable(vardecl):
98 if not vardecl:
99 return None
100 if not is_fixed_type(vardecl):
101 return False
102 _, _, typequal, _, _ = _info.get_parsed_vartype(vardecl)
103 # If there, it can only be "const" or "volatile".
104 return typequal == 'const'
105
106
107 def is_public_api(decl):
108 if not is_public(decl):
109 return False
110 if decl.kind is _KIND.TYPEDEF:
111 return True
112 elif _match.is_type_decl(decl):
113 return not _match.is_forward_decl(decl)
114 else:
115 return _match.is_external_reference(decl)
116
117
118 def is_public_declaration(decl):
119 if not is_public(decl):
120 return False
121 if decl.kind is _KIND.TYPEDEF:
122 return True
123 elif _match.is_type_decl(decl):
124 return _match.is_forward_decl(decl)
125 else:
126 return _match.is_external_reference(decl)
127
128
129 def is_public_definition(decl):
130 if not is_public(decl):
131 return False
132 if decl.kind is _KIND.TYPEDEF:
133 return True
134 elif _match.is_type_decl(decl):
135 return not _match.is_forward_decl(decl)
136 else:
137 return not _match.is_external_reference(decl)
138
139
140 def is_public_impl(decl):
141 if not _KIND.is_decl(decl.kind):
142 return False
143 # See filter_forward() about "is_public".
144 return getattr(decl, 'is_public', False)
145
146
147 def is_module_global_decl(decl):
148 if is_public_impl(decl):
149 return False
150 if _match.is_forward_decl(decl):
151 return False
152 return not _match.is_local_var(decl)
153
154
155 ##################################
156 # filtering with matchers
157
158 def filter_forward(items, *, markpublic=False):
159 if markpublic:
160 public = set()
161 actual = []
162 for item in items:
163 if is_public_api(item):
164 public.add(item.id)
165 elif not _match.is_forward_decl(item):
166 actual.append(item)
167 else:
168 # non-public duplicate!
169 # XXX
170 raise Exception(item)
171 for item in actual:
172 _info.set_flag(item, 'is_public', item.id in public)
173 yield item
174 else:
175 for item in items:
176 if _match.is_forward_decl(item):
177 continue
178 yield item
179
180
181 ##################################
182 # grouping with matchers
183
184 def group_by_storage(decls, **kwargs):
185 def is_module_global(decl):
186 if not is_module_global_decl(decl):
187 return False
188 if decl.kind == _KIND.VARIABLE:
189 if _info.get_effective_storage(decl) == 'static':
190 # This is covered by is_static_module_global().
191 return False
192 return True
193 def is_static_module_global(decl):
194 if not _match.is_global_var(decl):
195 return False
196 return _info.get_effective_storage(decl) == 'static'
197 def is_static_local(decl):
198 if not _match.is_local_var(decl):
199 return False
200 return _info.get_effective_storage(decl) == 'static'
201 #def is_local(decl):
202 # if not _match.is_local_var(decl):
203 # return False
204 # return _info.get_effective_storage(decl) != 'static'
205 categories = {
206 #'extern': is_extern,
207 'published': is_public_impl,
208 'module-global': is_module_global,
209 'static-module-global': is_static_module_global,
210 'static-local': is_static_local,
211 }
212 return _match.group_by_category(decls, categories, **kwargs)