mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 07:31:38 +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
							 |