| 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) |