• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import os.path
2
3from 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?
13SYSTEM_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
46def is_system_type(typespec):
47    return typespec in SYSTEM_TYPES
48
49
50##################################
51# decl matchers
52
53def 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
61def 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
75def 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
97def 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
107def 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
118def 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
129def 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
140def 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
147def 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
158def 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
184def 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)
213