| import os.path | |
| from c_parser import ( | |
| info as _info, | |
| match as _match, | |
| ) | |
| _KIND = _info.KIND | |
| # XXX Use known.tsv for these? | |
| SYSTEM_TYPES = { | |
| 'int8_t', | |
| 'uint8_t', | |
| 'int16_t', | |
| 'uint16_t', | |
| 'int32_t', | |
| 'uint32_t', | |
| 'int64_t', | |
| 'uint64_t', | |
| 'size_t', | |
| 'ssize_t', | |
| 'intptr_t', | |
| 'uintptr_t', | |
| 'wchar_t', | |
| '', | |
| # OS-specific | |
| 'pthread_cond_t', | |
| 'pthread_mutex_t', | |
| 'pthread_key_t', | |
| 'atomic_int', | |
| 'atomic_uintptr_t', | |
| '', | |
| # lib-specific | |
| 'WINDOW', # curses | |
| 'XML_LChar', | |
| 'XML_Size', | |
| 'XML_Parser', | |
| 'enum XML_Error', | |
| 'enum XML_Status', | |
| '', | |
| } | |
| def is_system_type(typespec): | |
| return typespec in SYSTEM_TYPES | |
| ################################## | |
| # decl matchers | |
| def is_public(decl): | |
| if not decl.filename.endswith('.h'): | |
| return False | |
| if 'Include' not in decl.filename.split(os.path.sep): | |
| return False | |
| return True | |
| def is_process_global(vardecl): | |
| kind, storage, _, _, _ = _info.get_parsed_vartype(vardecl) | |
| if kind is not _KIND.VARIABLE: | |
| raise NotImplementedError(vardecl) | |
| if 'static' in (storage or ''): | |
| return True | |
| if hasattr(vardecl, 'parent'): | |
| parent = vardecl.parent | |
| else: | |
| parent = vardecl.get('parent') | |
| return not parent | |
| def is_fixed_type(vardecl): | |
| if not vardecl: | |
| return None | |
| _, _, _, typespec, abstract = _info.get_parsed_vartype(vardecl) | |
| if 'typeof' in typespec: | |
| raise NotImplementedError(vardecl) | |
| elif not abstract: | |
| return True | |
| if '*' not in abstract: | |
| # XXX What about []? | |
| return True | |
| elif _match._is_funcptr(abstract): | |
| return True | |
| else: | |
| for after in abstract.split('*')[1:]: | |
| if not after.lstrip().startswith('const'): | |
| return False | |
| else: | |
| return True | |
| def is_immutable(vardecl): | |
| if not vardecl: | |
| return None | |
| if not is_fixed_type(vardecl): | |
| return False | |
| _, _, typequal, _, _ = _info.get_parsed_vartype(vardecl) | |
| # If there, it can only be "const" or "volatile". | |
| return typequal == 'const' | |
| def is_public_api(decl): | |
| if not is_public(decl): | |
| return False | |
| if decl.kind is _KIND.TYPEDEF: | |
| return True | |
| elif _match.is_type_decl(decl): | |
| return not _match.is_forward_decl(decl) | |
| else: | |
| return _match.is_external_reference(decl) | |
| def is_public_declaration(decl): | |
| if not is_public(decl): | |
| return False | |
| if decl.kind is _KIND.TYPEDEF: | |
| return True | |
| elif _match.is_type_decl(decl): | |
| return _match.is_forward_decl(decl) | |
| else: | |
| return _match.is_external_reference(decl) | |
| def is_public_definition(decl): | |
| if not is_public(decl): | |
| return False | |
| if decl.kind is _KIND.TYPEDEF: | |
| return True | |
| elif _match.is_type_decl(decl): | |
| return not _match.is_forward_decl(decl) | |
| else: | |
| return not _match.is_external_reference(decl) | |
| def is_public_impl(decl): | |
| if not _KIND.is_decl(decl.kind): | |
| return False | |
| # See filter_forward() about "is_public". | |
| return getattr(decl, 'is_public', False) | |
| def is_module_global_decl(decl): | |
| if is_public_impl(decl): | |
| return False | |
| if _match.is_forward_decl(decl): | |
| return False | |
| return not _match.is_local_var(decl) | |
| ################################## | |
| # filtering with matchers | |
| def filter_forward(items, *, markpublic=False): | |
| if markpublic: | |
| public = set() | |
| actual = [] | |
| for item in items: | |
| if is_public_api(item): | |
| public.add(item.id) | |
| elif not _match.is_forward_decl(item): | |
| actual.append(item) | |
| else: | |
| # non-public duplicate! | |
| # XXX | |
| raise Exception(item) | |
| for item in actual: | |
| _info.set_flag(item, 'is_public', item.id in public) | |
| yield item | |
| else: | |
| for item in items: | |
| if _match.is_forward_decl(item): | |
| continue | |
| yield item | |
| ################################## | |
| # grouping with matchers | |
| def group_by_storage(decls, **kwargs): | |
| def is_module_global(decl): | |
| if not is_module_global_decl(decl): | |
| return False | |
| if decl.kind == _KIND.VARIABLE: | |
| if _info.get_effective_storage(decl) == 'static': | |
| # This is covered by is_static_module_global(). | |
| return False | |
| return True | |
| def is_static_module_global(decl): | |
| if not _match.is_global_var(decl): | |
| return False | |
| return _info.get_effective_storage(decl) == 'static' | |
| def is_static_local(decl): | |
| if not _match.is_local_var(decl): | |
| return False | |
| return _info.get_effective_storage(decl) == 'static' | |
| #def is_local(decl): | |
| # if not _match.is_local_var(decl): | |
| # return False | |
| # return _info.get_effective_storage(decl) != 'static' | |
| categories = { | |
| #'extern': is_extern, | |
| 'published': is_public_impl, | |
| 'module-global': is_module_global, | |
| 'static-module-global': is_static_module_global, | |
| 'static-local': is_static_local, | |
| } | |
| return _match.group_by_category(decls, categories, **kwargs) |