xxx use known tsv for these osspecific libspecific decl matchers xxx what about if there it can only be const or volatile see filterforward about ispublic filtering with matchers nonpublic duplicate xxx grouping with matchers this is covered by isstaticmoduleglobal def islocaldecl if not match islocalvardecl return false return info geteffectivestoragedecl static extern isextern xxx use known tsv for these os specific lib specific curses decl matchers xxx what about if there it can only be const or volatile see filter_forward about is_public filtering with matchers non public duplicate xxx grouping with matchers this is covered by is_static_module_global def is_local decl if not _match is_local_var decl return false return _info get_effective_storage decl static extern is_extern
import os.path

from c_parser import (
    info as _info,
    match as _match,
)


_KIND = _info.KIND



SYSTEM_TYPES = {
    'int8_t',
    'uint8_t',
    'int16_t',
    'uint16_t',
    'int32_t',
    'uint32_t',
    'int64_t',
    'uint64_t',
    'size_t',
    'ssize_t',
    'intptr_t',
    'uintptr_t',
    'wchar_t',
    '',
    
    'pthread_cond_t',
    'pthread_mutex_t',
    'pthread_key_t',
    'atomic_int',
    'atomic_uintptr_t',
    '',
    
    'WINDOW',  
    'XML_LChar',
    'XML_Size',
    'XML_Parser',
    'enum XML_Error',
    'enum XML_Status',
    '',
}


def is_system_type(typespec):
    return typespec in SYSTEM_TYPES





def is_public(decl):
    if not decl.filename.endswith('.h'):
        return False
    if 'Include' not in decl.filename.split(os.path.sep):
        return False
    return True


def is_process_global(vardecl):
    kind, storage, _, _, _ = _info.get_parsed_vartype(vardecl)
    if kind is not _KIND.VARIABLE:
        raise NotImplementedError(vardecl)
    if 'static' in (storage or ''):
        return True

    if hasattr(vardecl, 'parent'):
        parent = vardecl.parent
    else:
        parent = vardecl.get('parent')
    return not parent


def is_fixed_type(vardecl):
    if not vardecl:
        return None
    _, _, _, typespec, abstract = _info.get_parsed_vartype(vardecl)
    if 'typeof' in typespec:
        raise NotImplementedError(vardecl)
    elif not abstract:
        return True

    if '*' not in abstract:
        
        return True
    elif _match._is_funcptr(abstract):
        return True
    else:
        for after in abstract.split('*')[1:]:
            if not after.lstrip().startswith('const'):
                return False
        else:
            return True


def is_immutable(vardecl):
    if not vardecl:
        return None
    if not is_fixed_type(vardecl):
        return False
    _, _, typequal, _, _ = _info.get_parsed_vartype(vardecl)
    
    return typequal == 'const'


def is_public_api(decl):
    if not is_public(decl):
        return False
    if decl.kind is _KIND.TYPEDEF:
        return True
    elif _match.is_type_decl(decl):
        return not _match.is_forward_decl(decl)
    else:
        return _match.is_external_reference(decl)


def is_public_declaration(decl):
    if not is_public(decl):
        return False
    if decl.kind is _KIND.TYPEDEF:
        return True
    elif _match.is_type_decl(decl):
        return _match.is_forward_decl(decl)
    else:
        return _match.is_external_reference(decl)


def is_public_definition(decl):
    if not is_public(decl):
        return False
    if decl.kind is _KIND.TYPEDEF:
        return True
    elif _match.is_type_decl(decl):
        return not _match.is_forward_decl(decl)
    else:
        return not _match.is_external_reference(decl)


def is_public_impl(decl):
    if not _KIND.is_decl(decl.kind):
        return False
    
    return getattr(decl, 'is_public', False)


def is_module_global_decl(decl):
    if is_public_impl(decl):
        return False
    if _match.is_forward_decl(decl):
        return False
    return not _match.is_local_var(decl)





def filter_forward(items, *, markpublic=False):
    if markpublic:
        public = set()
        actual = []
        for item in items:
            if is_public_api(item):
                public.add(item.id)
            elif not _match.is_forward_decl(item):
                actual.append(item)
            else:
                
                
                raise Exception(item)
        for item in actual:
            _info.set_flag(item, 'is_public', item.id in public)
            yield item
    else:
        for item in items:
            if _match.is_forward_decl(item):
                continue
            yield item





def group_by_storage(decls, **kwargs):
    def is_module_global(decl):
        if not is_module_global_decl(decl):
            return False
        if decl.kind == _KIND.VARIABLE:
            if _info.get_effective_storage(decl) == 'static':
                
                return False
        return True
    def is_static_module_global(decl):
        if not _match.is_global_var(decl):
            return False
        return _info.get_effective_storage(decl) == 'static'
    def is_static_local(decl):
        if not _match.is_local_var(decl):
            return False
        return _info.get_effective_storage(decl) == 'static'
    
    
    
    
    categories = {
        
        'published': is_public_impl,
        'module-global': is_module_global,
        'static-module-global': is_static_module_global,
        'static-local': is_static_local,
    }
    return _match.group_by_category(decls, categories, **kwargs)