17db96d56Sopenharmony_cifrom c_parser.info import (
27db96d56Sopenharmony_ci    KIND,
37db96d56Sopenharmony_ci    TypeDeclaration,
47db96d56Sopenharmony_ci    POTSType,
57db96d56Sopenharmony_ci    FuncPtr,
67db96d56Sopenharmony_ci)
77db96d56Sopenharmony_cifrom c_parser.match import (
87db96d56Sopenharmony_ci    is_pots,
97db96d56Sopenharmony_ci    is_funcptr,
107db96d56Sopenharmony_ci)
117db96d56Sopenharmony_cifrom .info import (
127db96d56Sopenharmony_ci    IGNORED,
137db96d56Sopenharmony_ci    UNKNOWN,
147db96d56Sopenharmony_ci    SystemType,
157db96d56Sopenharmony_ci)
167db96d56Sopenharmony_cifrom .match import (
177db96d56Sopenharmony_ci    is_system_type,
187db96d56Sopenharmony_ci)
197db96d56Sopenharmony_ci
207db96d56Sopenharmony_ci
217db96d56Sopenharmony_cidef get_typespecs(typedecls):
227db96d56Sopenharmony_ci    typespecs = {}
237db96d56Sopenharmony_ci    for decl in typedecls:
247db96d56Sopenharmony_ci        if decl.shortkey not in typespecs:
257db96d56Sopenharmony_ci            typespecs[decl.shortkey] = [decl]
267db96d56Sopenharmony_ci        else:
277db96d56Sopenharmony_ci            typespecs[decl.shortkey].append(decl)
287db96d56Sopenharmony_ci    return typespecs
297db96d56Sopenharmony_ci
307db96d56Sopenharmony_ci
317db96d56Sopenharmony_cidef analyze_decl(decl, typespecs, knowntypespecs, types, knowntypes, *,
327db96d56Sopenharmony_ci                 analyze_resolved=None):
337db96d56Sopenharmony_ci    resolved = resolve_decl(decl, typespecs, knowntypespecs, types)
347db96d56Sopenharmony_ci    if resolved is None:
357db96d56Sopenharmony_ci        # The decl is supposed to be skipped or ignored.
367db96d56Sopenharmony_ci        return None
377db96d56Sopenharmony_ci    if analyze_resolved is None:
387db96d56Sopenharmony_ci        return resolved, None
397db96d56Sopenharmony_ci    return analyze_resolved(resolved, decl, types, knowntypes)
407db96d56Sopenharmony_ci
417db96d56Sopenharmony_ci# This alias helps us avoid name collisions.
427db96d56Sopenharmony_ci_analyze_decl = analyze_decl
437db96d56Sopenharmony_ci
447db96d56Sopenharmony_ci
457db96d56Sopenharmony_cidef analyze_type_decls(types, analyze_decl, handle_unresolved=True):
467db96d56Sopenharmony_ci    unresolved = set(types)
477db96d56Sopenharmony_ci    while unresolved:
487db96d56Sopenharmony_ci        updated = []
497db96d56Sopenharmony_ci        for decl in unresolved:
507db96d56Sopenharmony_ci            resolved = analyze_decl(decl)
517db96d56Sopenharmony_ci            if resolved is None:
527db96d56Sopenharmony_ci                # The decl should be skipped or ignored.
537db96d56Sopenharmony_ci                types[decl] = IGNORED
547db96d56Sopenharmony_ci                updated.append(decl)
557db96d56Sopenharmony_ci                continue
567db96d56Sopenharmony_ci            typedeps, _ = resolved
577db96d56Sopenharmony_ci            if typedeps is None:
587db96d56Sopenharmony_ci                raise NotImplementedError(decl)
597db96d56Sopenharmony_ci            if UNKNOWN in typedeps:
607db96d56Sopenharmony_ci                # At least one dependency is unknown, so this decl
617db96d56Sopenharmony_ci                # is not resolvable.
627db96d56Sopenharmony_ci                types[decl] = UNKNOWN
637db96d56Sopenharmony_ci                updated.append(decl)
647db96d56Sopenharmony_ci                continue
657db96d56Sopenharmony_ci            if None in typedeps:
667db96d56Sopenharmony_ci                # XXX
677db96d56Sopenharmony_ci                # Handle direct recursive types first.
687db96d56Sopenharmony_ci                nonrecursive = 1
697db96d56Sopenharmony_ci                if decl.kind is KIND.STRUCT or decl.kind is KIND.UNION:
707db96d56Sopenharmony_ci                    nonrecursive = 0
717db96d56Sopenharmony_ci                    i = 0
727db96d56Sopenharmony_ci                    for member, dep in zip(decl.members, typedeps):
737db96d56Sopenharmony_ci                        if dep is None:
747db96d56Sopenharmony_ci                            if member.vartype.typespec != decl.shortkey:
757db96d56Sopenharmony_ci                                nonrecursive += 1
767db96d56Sopenharmony_ci                            else:
777db96d56Sopenharmony_ci                                typedeps[i] = decl
787db96d56Sopenharmony_ci                        i += 1
797db96d56Sopenharmony_ci                if nonrecursive:
807db96d56Sopenharmony_ci                    # We don't have all dependencies resolved yet.
817db96d56Sopenharmony_ci                    continue
827db96d56Sopenharmony_ci            types[decl] = resolved
837db96d56Sopenharmony_ci            updated.append(decl)
847db96d56Sopenharmony_ci        if updated:
857db96d56Sopenharmony_ci            for decl in updated:
867db96d56Sopenharmony_ci                unresolved.remove(decl)
877db96d56Sopenharmony_ci        else:
887db96d56Sopenharmony_ci            # XXX
897db96d56Sopenharmony_ci            # Handle indirect recursive types.
907db96d56Sopenharmony_ci            ...
917db96d56Sopenharmony_ci            # We couldn't resolve the rest.
927db96d56Sopenharmony_ci            # Let the caller deal with it!
937db96d56Sopenharmony_ci            break
947db96d56Sopenharmony_ci    if unresolved and handle_unresolved:
957db96d56Sopenharmony_ci        if handle_unresolved is True:
967db96d56Sopenharmony_ci            handle_unresolved = _handle_unresolved
977db96d56Sopenharmony_ci        handle_unresolved(unresolved, types, analyze_decl)
987db96d56Sopenharmony_ci
997db96d56Sopenharmony_ci
1007db96d56Sopenharmony_cidef resolve_decl(decl, typespecs, knowntypespecs, types):
1017db96d56Sopenharmony_ci    if decl.kind is KIND.ENUM:
1027db96d56Sopenharmony_ci        typedeps = []
1037db96d56Sopenharmony_ci    else:
1047db96d56Sopenharmony_ci        if decl.kind is KIND.VARIABLE:
1057db96d56Sopenharmony_ci            vartypes = [decl.vartype]
1067db96d56Sopenharmony_ci        elif decl.kind is KIND.FUNCTION:
1077db96d56Sopenharmony_ci            vartypes = [decl.signature.returntype]
1087db96d56Sopenharmony_ci        elif decl.kind is KIND.TYPEDEF:
1097db96d56Sopenharmony_ci            vartypes = [decl.vartype]
1107db96d56Sopenharmony_ci        elif decl.kind is KIND.STRUCT or decl.kind is KIND.UNION:
1117db96d56Sopenharmony_ci            vartypes = [m.vartype for m in decl.members]
1127db96d56Sopenharmony_ci        else:
1137db96d56Sopenharmony_ci            # Skip this one!
1147db96d56Sopenharmony_ci            return None
1157db96d56Sopenharmony_ci
1167db96d56Sopenharmony_ci        typedeps = []
1177db96d56Sopenharmony_ci        for vartype in vartypes:
1187db96d56Sopenharmony_ci            typespec = vartype.typespec
1197db96d56Sopenharmony_ci            if is_pots(typespec):
1207db96d56Sopenharmony_ci                typedecl = POTSType(typespec)
1217db96d56Sopenharmony_ci            elif is_system_type(typespec):
1227db96d56Sopenharmony_ci                typedecl = SystemType(typespec)
1237db96d56Sopenharmony_ci            elif is_funcptr(vartype):
1247db96d56Sopenharmony_ci                typedecl = FuncPtr(vartype)
1257db96d56Sopenharmony_ci            else:
1267db96d56Sopenharmony_ci                typedecl = find_typedecl(decl, typespec, typespecs)
1277db96d56Sopenharmony_ci                if typedecl is None:
1287db96d56Sopenharmony_ci                    typedecl = find_typedecl(decl, typespec, knowntypespecs)
1297db96d56Sopenharmony_ci                elif not isinstance(typedecl, TypeDeclaration):
1307db96d56Sopenharmony_ci                    raise NotImplementedError(repr(typedecl))
1317db96d56Sopenharmony_ci                if typedecl is None:
1327db96d56Sopenharmony_ci                    # We couldn't find it!
1337db96d56Sopenharmony_ci                    typedecl = UNKNOWN
1347db96d56Sopenharmony_ci                elif typedecl not in types:
1357db96d56Sopenharmony_ci                    # XXX How can this happen?
1367db96d56Sopenharmony_ci                    typedecl = UNKNOWN
1377db96d56Sopenharmony_ci                elif types[typedecl] is UNKNOWN:
1387db96d56Sopenharmony_ci                    typedecl = UNKNOWN
1397db96d56Sopenharmony_ci                elif types[typedecl] is IGNORED:
1407db96d56Sopenharmony_ci                    # We don't care if it didn't resolve.
1417db96d56Sopenharmony_ci                    pass
1427db96d56Sopenharmony_ci                elif types[typedecl] is None:
1437db96d56Sopenharmony_ci                    # The typedecl for the typespec hasn't been resolved yet.
1447db96d56Sopenharmony_ci                    typedecl = None
1457db96d56Sopenharmony_ci            typedeps.append(typedecl)
1467db96d56Sopenharmony_ci    return typedeps
1477db96d56Sopenharmony_ci
1487db96d56Sopenharmony_ci
1497db96d56Sopenharmony_cidef find_typedecl(decl, typespec, typespecs):
1507db96d56Sopenharmony_ci    specdecls = typespecs.get(typespec)
1517db96d56Sopenharmony_ci    if not specdecls:
1527db96d56Sopenharmony_ci        return None
1537db96d56Sopenharmony_ci
1547db96d56Sopenharmony_ci    filename = decl.filename
1557db96d56Sopenharmony_ci
1567db96d56Sopenharmony_ci    if len(specdecls) == 1:
1577db96d56Sopenharmony_ci        typedecl, = specdecls
1587db96d56Sopenharmony_ci        if '-' in typespec and typedecl.filename != filename:
1597db96d56Sopenharmony_ci            # Inlined types are always in the same file.
1607db96d56Sopenharmony_ci            return None
1617db96d56Sopenharmony_ci        return typedecl
1627db96d56Sopenharmony_ci
1637db96d56Sopenharmony_ci    # Decide which one to return.
1647db96d56Sopenharmony_ci    candidates = []
1657db96d56Sopenharmony_ci    samefile = None
1667db96d56Sopenharmony_ci    for typedecl in specdecls:
1677db96d56Sopenharmony_ci        type_filename = typedecl.filename
1687db96d56Sopenharmony_ci        if type_filename == filename:
1697db96d56Sopenharmony_ci            if samefile is not None:
1707db96d56Sopenharmony_ci                # We expect type names to be unique in a file.
1717db96d56Sopenharmony_ci                raise NotImplementedError((decl, samefile, typedecl))
1727db96d56Sopenharmony_ci            samefile = typedecl
1737db96d56Sopenharmony_ci        elif filename.endswith('.c') and not type_filename.endswith('.h'):
1747db96d56Sopenharmony_ci            # If the decl is in a source file then we expect the
1757db96d56Sopenharmony_ci            # type to be in the same file or in a header file.
1767db96d56Sopenharmony_ci            continue
1777db96d56Sopenharmony_ci        candidates.append(typedecl)
1787db96d56Sopenharmony_ci    if not candidates:
1797db96d56Sopenharmony_ci        return None
1807db96d56Sopenharmony_ci    elif len(candidates) == 1:
1817db96d56Sopenharmony_ci        winner, = candidates
1827db96d56Sopenharmony_ci        # XXX Check for inline?
1837db96d56Sopenharmony_ci    elif '-' in typespec:
1847db96d56Sopenharmony_ci        # Inlined types are always in the same file.
1857db96d56Sopenharmony_ci        winner = samefile
1867db96d56Sopenharmony_ci    elif samefile is not None:
1877db96d56Sopenharmony_ci        # Favor types in the same file.
1887db96d56Sopenharmony_ci        winner = samefile
1897db96d56Sopenharmony_ci    else:
1907db96d56Sopenharmony_ci        # We don't know which to return.
1917db96d56Sopenharmony_ci        raise NotImplementedError((decl, candidates))
1927db96d56Sopenharmony_ci
1937db96d56Sopenharmony_ci    return winner
1947db96d56Sopenharmony_ci
1957db96d56Sopenharmony_ci
1967db96d56Sopenharmony_ci#############################
1977db96d56Sopenharmony_ci# handling unresolved decls
1987db96d56Sopenharmony_ci
1997db96d56Sopenharmony_ciclass Skipped(TypeDeclaration):
2007db96d56Sopenharmony_ci    def __init__(self):
2017db96d56Sopenharmony_ci        _file = _name = _data = _parent = None
2027db96d56Sopenharmony_ci        super().__init__(_file, _name, _data, _parent, _shortkey='<skipped>')
2037db96d56Sopenharmony_ci_SKIPPED = Skipped()
2047db96d56Sopenharmony_cidel Skipped
2057db96d56Sopenharmony_ci
2067db96d56Sopenharmony_ci
2077db96d56Sopenharmony_cidef _handle_unresolved(unresolved, types, analyze_decl):
2087db96d56Sopenharmony_ci    #raise NotImplementedError(unresolved)
2097db96d56Sopenharmony_ci
2107db96d56Sopenharmony_ci    dump = True
2117db96d56Sopenharmony_ci    dump = False
2127db96d56Sopenharmony_ci    if dump:
2137db96d56Sopenharmony_ci        print()
2147db96d56Sopenharmony_ci    for decl in types:  # Preserve the original order.
2157db96d56Sopenharmony_ci        if decl not in unresolved:
2167db96d56Sopenharmony_ci            assert types[decl] is not None, decl
2177db96d56Sopenharmony_ci            if types[decl] in (UNKNOWN, IGNORED):
2187db96d56Sopenharmony_ci                unresolved.add(decl)
2197db96d56Sopenharmony_ci                if dump:
2207db96d56Sopenharmony_ci                    _dump_unresolved(decl, types, analyze_decl)
2217db96d56Sopenharmony_ci                    print()
2227db96d56Sopenharmony_ci            else:
2237db96d56Sopenharmony_ci                assert types[decl][0] is not None, (decl, types[decl])
2247db96d56Sopenharmony_ci                assert None not in types[decl][0], (decl, types[decl])
2257db96d56Sopenharmony_ci        else:
2267db96d56Sopenharmony_ci            assert types[decl] is None
2277db96d56Sopenharmony_ci            if dump:
2287db96d56Sopenharmony_ci                _dump_unresolved(decl, types, analyze_decl)
2297db96d56Sopenharmony_ci                print()
2307db96d56Sopenharmony_ci    #raise NotImplementedError
2317db96d56Sopenharmony_ci
2327db96d56Sopenharmony_ci    for decl in unresolved:
2337db96d56Sopenharmony_ci        types[decl] = ([_SKIPPED], None)
2347db96d56Sopenharmony_ci
2357db96d56Sopenharmony_ci    for decl in types:
2367db96d56Sopenharmony_ci        assert types[decl]
2377db96d56Sopenharmony_ci
2387db96d56Sopenharmony_ci
2397db96d56Sopenharmony_cidef _dump_unresolved(decl, types, analyze_decl):
2407db96d56Sopenharmony_ci    if isinstance(decl, str):
2417db96d56Sopenharmony_ci        typespec = decl
2427db96d56Sopenharmony_ci        decl, = (d for d in types if d.shortkey == typespec)
2437db96d56Sopenharmony_ci    elif type(decl) is tuple:
2447db96d56Sopenharmony_ci        filename, typespec = decl
2457db96d56Sopenharmony_ci        if '-' in typespec:
2467db96d56Sopenharmony_ci            found = [d for d in types
2477db96d56Sopenharmony_ci                     if d.shortkey == typespec and d.filename == filename]
2487db96d56Sopenharmony_ci            #if not found:
2497db96d56Sopenharmony_ci            #    raise NotImplementedError(decl)
2507db96d56Sopenharmony_ci            decl, = found
2517db96d56Sopenharmony_ci        else:
2527db96d56Sopenharmony_ci            found = [d for d in types if d.shortkey == typespec]
2537db96d56Sopenharmony_ci            if not found:
2547db96d56Sopenharmony_ci                print(f'*** {typespec} ???')
2557db96d56Sopenharmony_ci                return
2567db96d56Sopenharmony_ci                #raise NotImplementedError(decl)
2577db96d56Sopenharmony_ci            else:
2587db96d56Sopenharmony_ci                decl, = found
2597db96d56Sopenharmony_ci    resolved = analyze_decl(decl)
2607db96d56Sopenharmony_ci    if resolved:
2617db96d56Sopenharmony_ci        typedeps, _ = resolved or (None, None)
2627db96d56Sopenharmony_ci
2637db96d56Sopenharmony_ci    if decl.kind is KIND.STRUCT or decl.kind is KIND.UNION:
2647db96d56Sopenharmony_ci        print(f'*** {decl.shortkey} {decl.filename}')
2657db96d56Sopenharmony_ci        for member, mtype in zip(decl.members, typedeps):
2667db96d56Sopenharmony_ci            typespec = member.vartype.typespec
2677db96d56Sopenharmony_ci            if typespec == decl.shortkey:
2687db96d56Sopenharmony_ci                print(f'     ~~~~: {typespec:20} - {member!r}')
2697db96d56Sopenharmony_ci                continue
2707db96d56Sopenharmony_ci            status = None
2717db96d56Sopenharmony_ci            if is_pots(typespec):
2727db96d56Sopenharmony_ci                mtype = typespec
2737db96d56Sopenharmony_ci                status = 'okay'
2747db96d56Sopenharmony_ci            elif is_system_type(typespec):
2757db96d56Sopenharmony_ci                mtype = typespec
2767db96d56Sopenharmony_ci                status = 'okay'
2777db96d56Sopenharmony_ci            elif mtype is None:
2787db96d56Sopenharmony_ci                if '-' in member.vartype.typespec:
2797db96d56Sopenharmony_ci                    mtype, = [d for d in types
2807db96d56Sopenharmony_ci                              if d.shortkey == member.vartype.typespec
2817db96d56Sopenharmony_ci                              and d.filename == decl.filename]
2827db96d56Sopenharmony_ci                else:
2837db96d56Sopenharmony_ci                    found = [d for d in types
2847db96d56Sopenharmony_ci                             if d.shortkey == typespec]
2857db96d56Sopenharmony_ci                    if not found:
2867db96d56Sopenharmony_ci                        print(f' ???: {typespec:20}')
2877db96d56Sopenharmony_ci                        continue
2887db96d56Sopenharmony_ci                    mtype, = found
2897db96d56Sopenharmony_ci            if status is None:
2907db96d56Sopenharmony_ci                status = 'okay' if types.get(mtype) else 'oops'
2917db96d56Sopenharmony_ci            if mtype is _SKIPPED:
2927db96d56Sopenharmony_ci                status = 'okay'
2937db96d56Sopenharmony_ci                mtype = '<skipped>'
2947db96d56Sopenharmony_ci            elif isinstance(mtype, FuncPtr):
2957db96d56Sopenharmony_ci                status = 'okay'
2967db96d56Sopenharmony_ci                mtype = str(mtype.vartype)
2977db96d56Sopenharmony_ci            elif not isinstance(mtype, str):
2987db96d56Sopenharmony_ci                if hasattr(mtype, 'vartype'):
2997db96d56Sopenharmony_ci                    if is_funcptr(mtype.vartype):
3007db96d56Sopenharmony_ci                        status = 'okay'
3017db96d56Sopenharmony_ci                mtype = str(mtype).rpartition('(')[0].rstrip()
3027db96d56Sopenharmony_ci            status = '    okay' if status == 'okay' else f'--> {status}'
3037db96d56Sopenharmony_ci            print(f' {status}: {typespec:20} - {member!r} ({mtype})')
3047db96d56Sopenharmony_ci    else:
3057db96d56Sopenharmony_ci        print(f'*** {decl} ({decl.vartype!r})')
3067db96d56Sopenharmony_ci        if decl.vartype.typespec.startswith('struct ') or is_funcptr(decl):
3077db96d56Sopenharmony_ci            _dump_unresolved(
3087db96d56Sopenharmony_ci                (decl.filename, decl.vartype.typespec),
3097db96d56Sopenharmony_ci                types,
3107db96d56Sopenharmony_ci                analyze_decl,
3117db96d56Sopenharmony_ci            )
312