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