mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 23:21:29 +00:00 
			
		
		
		
	This is a little bit of clean-up, small fixes, and additional helpers prior to building an updated & accurate list of globals to eliminate.
		
			
				
	
	
		
			177 lines
		
	
	
	
		
			4.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			177 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
 |