1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
|
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
|