mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	
		
			
	
	
		
			178 lines
		
	
	
	
		
			4.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			178 lines
		
	
	
	
		
			4.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
|   | 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 |