1import re 2 3from . import info as _info 4from .parser._regexes import SIMPLE_TYPE 5 6 7_KIND = _info.KIND 8 9 10def match_storage(decl, expected): 11 default = _info.get_default_storage(decl) 12 #assert default 13 if expected is None: 14 expected = {default} 15 elif isinstance(expected, str): 16 expected = {expected or default} 17 elif not expected: 18 expected = _info.STORAGE 19 else: 20 expected = {v or default for v in expected} 21 storage = _info.get_effective_storage(decl, default=default) 22 return storage in expected 23 24 25################################## 26# decl matchers 27 28def is_type_decl(item): 29 return _KIND.is_type_decl(item.kind) 30 31 32def is_decl(item): 33 return _KIND.is_decl(item.kind) 34 35 36def is_pots(typespec, *, 37 _regex=re.compile(rf'^{SIMPLE_TYPE}$', re.VERBOSE), 38 ): 39 40 if not typespec: 41 return None 42 if type(typespec) is not str: 43 _, _, _, typespec, _ = _info.get_parsed_vartype(typespec) 44 return _regex.match(typespec) is not None 45 46 47def is_funcptr(vartype): 48 if not vartype: 49 return None 50 _, _, _, _, abstract = _info.get_parsed_vartype(vartype) 51 return _is_funcptr(abstract) 52 53 54def _is_funcptr(declstr): 55 if not declstr: 56 return None 57 # XXX Support "(<name>*)(". 58 return '(*)(' in declstr.replace(' ', '') 59 60 61def is_forward_decl(decl): 62 if decl.kind is _KIND.TYPEDEF: 63 return False 64 elif is_type_decl(decl): 65 return not decl.data 66 elif decl.kind is _KIND.FUNCTION: 67 # XXX This doesn't work with ParsedItem. 68 return decl.signature.isforward 69 elif decl.kind is _KIND.VARIABLE: 70 # No var decls are considered forward (or all are...). 71 return False 72 else: 73 raise NotImplementedError(decl) 74 75 76def can_have_symbol(decl): 77 return decl.kind in (_KIND.VARIABLE, _KIND.FUNCTION) 78 79 80def has_external_symbol(decl): 81 if not can_have_symbol(decl): 82 return False 83 if _info.get_effective_storage(decl) != 'extern': 84 return False 85 if decl.kind is _KIND.FUNCTION: 86 return not decl.signature.isforward 87 else: 88 # It must be a variable, which can only be implicitly extern here. 89 return decl.storage != 'extern' 90 91 92def has_internal_symbol(decl): 93 if not can_have_symbol(decl): 94 return False 95 return _info.get_actual_storage(decl) == 'static' 96 97 98def is_external_reference(decl): 99 if not can_have_symbol(decl): 100 return False 101 # We have to check the declared storage rather tnan the effective. 102 if decl.storage != 'extern': 103 return False 104 if decl.kind is _KIND.FUNCTION: 105 return decl.signature.isforward 106 # Otherwise it's a variable. 107 return True 108 109 110def is_local_var(decl): 111 if not decl.kind is _KIND.VARIABLE: 112 return False 113 return True if decl.parent else False 114 115 116def is_global_var(decl): 117 if not decl.kind is _KIND.VARIABLE: 118 return False 119 return False if decl.parent else True 120 121 122################################## 123# filtering with matchers 124 125def filter_by_kind(items, kind): 126 if kind == 'type': 127 kinds = _KIND._TYPE_DECLS 128 elif kind == 'decl': 129 kinds = _KIND._TYPE_DECLS 130 try: 131 okay = kind in _KIND 132 except TypeError: 133 kinds = set(kind) 134 else: 135 kinds = {kind} if okay else set(kind) 136 for item in items: 137 if item.kind in kinds: 138 yield item 139 140 141################################## 142# grouping with matchers 143 144def group_by_category(decls, categories, *, ignore_non_match=True): 145 collated = {} 146 for decl in decls: 147 # Matchers should be mutually exclusive. (First match wins.) 148 for category, match in categories.items(): 149 if match(decl): 150 if category not in collated: 151 collated[category] = [decl] 152 else: 153 collated[category].append(decl) 154 break 155 else: 156 if not ignore_non_match: 157 raise Exception(f'no match for {decl!r}') 158 return collated 159 160 161def group_by_kind(items): 162 collated = {kind: [] for kind in _KIND} 163 for item in items: 164 try: 165 collated[item.kind].append(item) 166 except KeyError: 167 raise ValueError(f'unsupported kind in {item!r}') 168 return collated 169 170 171def group_by_kinds(items): 172 # Collate into kind groups (decl, type, etc.). 173 collated = {_KIND.get_group(k): [] for k in _KIND} 174 for item in items: 175 group = _KIND.get_group(item.kind) 176 collated[group].append(item) 177 return collated 178