17db96d56Sopenharmony_ciimport os.path 27db96d56Sopenharmony_ciimport re 37db96d56Sopenharmony_ci 47db96d56Sopenharmony_cifrom c_common.clsutil import classonly 57db96d56Sopenharmony_cifrom c_parser.info import ( 67db96d56Sopenharmony_ci KIND, 77db96d56Sopenharmony_ci DeclID, 87db96d56Sopenharmony_ci Declaration, 97db96d56Sopenharmony_ci TypeDeclaration, 107db96d56Sopenharmony_ci TypeDef, 117db96d56Sopenharmony_ci Struct, 127db96d56Sopenharmony_ci Member, 137db96d56Sopenharmony_ci FIXED_TYPE, 147db96d56Sopenharmony_ci) 157db96d56Sopenharmony_cifrom c_parser.match import ( 167db96d56Sopenharmony_ci is_type_decl, 177db96d56Sopenharmony_ci is_pots, 187db96d56Sopenharmony_ci is_funcptr, 197db96d56Sopenharmony_ci) 207db96d56Sopenharmony_cifrom c_analyzer.match import ( 217db96d56Sopenharmony_ci is_system_type, 227db96d56Sopenharmony_ci is_process_global, 237db96d56Sopenharmony_ci is_fixed_type, 247db96d56Sopenharmony_ci is_immutable, 257db96d56Sopenharmony_ci) 267db96d56Sopenharmony_ciimport c_analyzer as _c_analyzer 277db96d56Sopenharmony_ciimport c_analyzer.info as _info 287db96d56Sopenharmony_ciimport c_analyzer.datafiles as _datafiles 297db96d56Sopenharmony_cifrom . import _parser, REPO_ROOT 307db96d56Sopenharmony_ci 317db96d56Sopenharmony_ci 327db96d56Sopenharmony_ci_DATA_DIR = os.path.dirname(__file__) 337db96d56Sopenharmony_ciKNOWN_FILE = os.path.join(_DATA_DIR, 'known.tsv') 347db96d56Sopenharmony_ciIGNORED_FILE = os.path.join(_DATA_DIR, 'ignored.tsv') 357db96d56Sopenharmony_ciNEED_FIX_FILE = os.path.join(_DATA_DIR, 'globals-to-fix.tsv') 367db96d56Sopenharmony_ciKNOWN_IN_DOT_C = { 377db96d56Sopenharmony_ci 'struct _odictobject': False, 387db96d56Sopenharmony_ci 'PyTupleObject': False, 397db96d56Sopenharmony_ci 'struct _typeobject': False, 407db96d56Sopenharmony_ci 'struct _arena': True, # ??? 417db96d56Sopenharmony_ci 'struct _frame': False, 427db96d56Sopenharmony_ci 'struct _ts': True, # ??? 437db96d56Sopenharmony_ci 'struct PyCodeObject': False, 447db96d56Sopenharmony_ci 'struct _is': True, # ??? 457db96d56Sopenharmony_ci 'PyWideStringList': True, # ??? 467db96d56Sopenharmony_ci # recursive 477db96d56Sopenharmony_ci 'struct _dictkeysobject': False, 487db96d56Sopenharmony_ci} 497db96d56Sopenharmony_ci# These are loaded from the respective .tsv files upon first use. 507db96d56Sopenharmony_ci_KNOWN = { 517db96d56Sopenharmony_ci # {(file, ID) | ID => info | bool} 527db96d56Sopenharmony_ci #'PyWideStringList': True, 537db96d56Sopenharmony_ci} 547db96d56Sopenharmony_ci#_KNOWN = {(Struct(None, typeid.partition(' ')[-1], None) 557db96d56Sopenharmony_ci# if typeid.startswith('struct ') 567db96d56Sopenharmony_ci# else TypeDef(None, typeid, None) 577db96d56Sopenharmony_ci# ): ([], {'unsupported': None if supported else True}) 587db96d56Sopenharmony_ci# for typeid, supported in _KNOWN_IN_DOT_C.items()} 597db96d56Sopenharmony_ci_IGNORED = { 607db96d56Sopenharmony_ci # {ID => reason} 617db96d56Sopenharmony_ci} 627db96d56Sopenharmony_ci 637db96d56Sopenharmony_ciKINDS = frozenset((*KIND.TYPES, KIND.VARIABLE)) 647db96d56Sopenharmony_ci 657db96d56Sopenharmony_ci 667db96d56Sopenharmony_cidef read_known(): 677db96d56Sopenharmony_ci if not _KNOWN: 687db96d56Sopenharmony_ci # Cache a copy the first time. 697db96d56Sopenharmony_ci extracols = None # XXX 707db96d56Sopenharmony_ci #extracols = ['unsupported'] 717db96d56Sopenharmony_ci known = _datafiles.read_known(KNOWN_FILE, extracols, REPO_ROOT) 727db96d56Sopenharmony_ci # For now we ignore known.values() (i.e. "extra"). 737db96d56Sopenharmony_ci types, _ = _datafiles.analyze_known( 747db96d56Sopenharmony_ci known, 757db96d56Sopenharmony_ci analyze_resolved=analyze_resolved, 767db96d56Sopenharmony_ci ) 777db96d56Sopenharmony_ci _KNOWN.update(types) 787db96d56Sopenharmony_ci return _KNOWN.copy() 797db96d56Sopenharmony_ci 807db96d56Sopenharmony_ci 817db96d56Sopenharmony_cidef write_known(): 827db96d56Sopenharmony_ci raise NotImplementedError 837db96d56Sopenharmony_ci datafiles.write_known(decls, IGNORED_FILE, ['unsupported'], relroot=REPO_ROOT) 847db96d56Sopenharmony_ci 857db96d56Sopenharmony_ci 867db96d56Sopenharmony_cidef read_ignored(): 877db96d56Sopenharmony_ci if not _IGNORED: 887db96d56Sopenharmony_ci _IGNORED.update(_datafiles.read_ignored(IGNORED_FILE, relroot=REPO_ROOT)) 897db96d56Sopenharmony_ci _IGNORED.update(_datafiles.read_ignored(NEED_FIX_FILE, relroot=REPO_ROOT)) 907db96d56Sopenharmony_ci return dict(_IGNORED) 917db96d56Sopenharmony_ci 927db96d56Sopenharmony_ci 937db96d56Sopenharmony_cidef write_ignored(): 947db96d56Sopenharmony_ci raise NotImplementedError 957db96d56Sopenharmony_ci _datafiles.write_ignored(variables, IGNORED_FILE, relroot=REPO_ROOT) 967db96d56Sopenharmony_ci 977db96d56Sopenharmony_ci 987db96d56Sopenharmony_cidef analyze(filenames, *, 997db96d56Sopenharmony_ci skip_objects=False, 1007db96d56Sopenharmony_ci **kwargs 1017db96d56Sopenharmony_ci ): 1027db96d56Sopenharmony_ci if skip_objects: 1037db96d56Sopenharmony_ci # XXX Set up a filter. 1047db96d56Sopenharmony_ci raise NotImplementedError 1057db96d56Sopenharmony_ci 1067db96d56Sopenharmony_ci known = read_known() 1077db96d56Sopenharmony_ci 1087db96d56Sopenharmony_ci decls = iter_decls(filenames) 1097db96d56Sopenharmony_ci results = _c_analyzer.analyze_decls( 1107db96d56Sopenharmony_ci decls, 1117db96d56Sopenharmony_ci known, 1127db96d56Sopenharmony_ci analyze_resolved=analyze_resolved, 1137db96d56Sopenharmony_ci ) 1147db96d56Sopenharmony_ci analysis = Analysis.from_results(results) 1157db96d56Sopenharmony_ci 1167db96d56Sopenharmony_ci return analysis 1177db96d56Sopenharmony_ci 1187db96d56Sopenharmony_ci 1197db96d56Sopenharmony_cidef iter_decls(filenames, **kwargs): 1207db96d56Sopenharmony_ci decls = _c_analyzer.iter_decls( 1217db96d56Sopenharmony_ci filenames, 1227db96d56Sopenharmony_ci # We ignore functions (and statements). 1237db96d56Sopenharmony_ci kinds=KINDS, 1247db96d56Sopenharmony_ci parse_files=_parser.parse_files, 1257db96d56Sopenharmony_ci **kwargs 1267db96d56Sopenharmony_ci ) 1277db96d56Sopenharmony_ci for decl in decls: 1287db96d56Sopenharmony_ci if not decl.data: 1297db96d56Sopenharmony_ci # Ignore forward declarations. 1307db96d56Sopenharmony_ci continue 1317db96d56Sopenharmony_ci yield decl 1327db96d56Sopenharmony_ci 1337db96d56Sopenharmony_ci 1347db96d56Sopenharmony_cidef analyze_resolved(resolved, decl, types, knowntypes, extra=None): 1357db96d56Sopenharmony_ci if decl.kind not in KINDS: 1367db96d56Sopenharmony_ci # Skip it! 1377db96d56Sopenharmony_ci return None 1387db96d56Sopenharmony_ci 1397db96d56Sopenharmony_ci typedeps = resolved 1407db96d56Sopenharmony_ci if typedeps is _info.UNKNOWN: 1417db96d56Sopenharmony_ci if decl.kind in (KIND.STRUCT, KIND.UNION): 1427db96d56Sopenharmony_ci typedeps = [typedeps] * len(decl.members) 1437db96d56Sopenharmony_ci else: 1447db96d56Sopenharmony_ci typedeps = [typedeps] 1457db96d56Sopenharmony_ci #assert isinstance(typedeps, (list, TypeDeclaration)), typedeps 1467db96d56Sopenharmony_ci 1477db96d56Sopenharmony_ci if extra is None: 1487db96d56Sopenharmony_ci extra = {} 1497db96d56Sopenharmony_ci elif 'unsupported' in extra: 1507db96d56Sopenharmony_ci raise NotImplementedError((decl, extra)) 1517db96d56Sopenharmony_ci 1527db96d56Sopenharmony_ci unsupported = _check_unsupported(decl, typedeps, types, knowntypes) 1537db96d56Sopenharmony_ci extra['unsupported'] = unsupported 1547db96d56Sopenharmony_ci 1557db96d56Sopenharmony_ci return typedeps, extra 1567db96d56Sopenharmony_ci 1577db96d56Sopenharmony_ci 1587db96d56Sopenharmony_cidef _check_unsupported(decl, typedeps, types, knowntypes): 1597db96d56Sopenharmony_ci if typedeps is None: 1607db96d56Sopenharmony_ci raise NotImplementedError(decl) 1617db96d56Sopenharmony_ci 1627db96d56Sopenharmony_ci if decl.kind in (KIND.STRUCT, KIND.UNION): 1637db96d56Sopenharmony_ci return _check_members(decl, typedeps, types, knowntypes) 1647db96d56Sopenharmony_ci elif decl.kind is KIND.ENUM: 1657db96d56Sopenharmony_ci if typedeps: 1667db96d56Sopenharmony_ci raise NotImplementedError((decl, typedeps)) 1677db96d56Sopenharmony_ci return None 1687db96d56Sopenharmony_ci else: 1697db96d56Sopenharmony_ci return _check_typedep(decl, typedeps, types, knowntypes) 1707db96d56Sopenharmony_ci 1717db96d56Sopenharmony_ci 1727db96d56Sopenharmony_cidef _check_members(decl, typedeps, types, knowntypes): 1737db96d56Sopenharmony_ci if isinstance(typedeps, TypeDeclaration): 1747db96d56Sopenharmony_ci raise NotImplementedError((decl, typedeps)) 1757db96d56Sopenharmony_ci 1767db96d56Sopenharmony_ci #members = decl.members or () # A forward decl has no members. 1777db96d56Sopenharmony_ci members = decl.members 1787db96d56Sopenharmony_ci if not members: 1797db96d56Sopenharmony_ci # A forward decl has no members, but that shouldn't surface here.. 1807db96d56Sopenharmony_ci raise NotImplementedError(decl) 1817db96d56Sopenharmony_ci if len(members) != len(typedeps): 1827db96d56Sopenharmony_ci raise NotImplementedError((decl, typedeps)) 1837db96d56Sopenharmony_ci 1847db96d56Sopenharmony_ci unsupported = [] 1857db96d56Sopenharmony_ci for member, typedecl in zip(members, typedeps): 1867db96d56Sopenharmony_ci checked = _check_typedep(member, typedecl, types, knowntypes) 1877db96d56Sopenharmony_ci unsupported.append(checked) 1887db96d56Sopenharmony_ci if any(None if v is FIXED_TYPE else v for v in unsupported): 1897db96d56Sopenharmony_ci return unsupported 1907db96d56Sopenharmony_ci elif FIXED_TYPE in unsupported: 1917db96d56Sopenharmony_ci return FIXED_TYPE 1927db96d56Sopenharmony_ci else: 1937db96d56Sopenharmony_ci return None 1947db96d56Sopenharmony_ci 1957db96d56Sopenharmony_ci 1967db96d56Sopenharmony_cidef _check_typedep(decl, typedecl, types, knowntypes): 1977db96d56Sopenharmony_ci if not isinstance(typedecl, TypeDeclaration): 1987db96d56Sopenharmony_ci if hasattr(type(typedecl), '__len__'): 1997db96d56Sopenharmony_ci if len(typedecl) == 1: 2007db96d56Sopenharmony_ci typedecl, = typedecl 2017db96d56Sopenharmony_ci if typedecl is None: 2027db96d56Sopenharmony_ci # XXX Fail? 2037db96d56Sopenharmony_ci return 'typespec (missing)' 2047db96d56Sopenharmony_ci elif typedecl is _info.UNKNOWN: 2057db96d56Sopenharmony_ci # XXX Is this right? 2067db96d56Sopenharmony_ci return 'typespec (unknown)' 2077db96d56Sopenharmony_ci elif not isinstance(typedecl, TypeDeclaration): 2087db96d56Sopenharmony_ci raise NotImplementedError((decl, typedecl)) 2097db96d56Sopenharmony_ci 2107db96d56Sopenharmony_ci if isinstance(decl, Member): 2117db96d56Sopenharmony_ci return _check_vartype(decl, typedecl, types, knowntypes) 2127db96d56Sopenharmony_ci elif not isinstance(decl, Declaration): 2137db96d56Sopenharmony_ci raise NotImplementedError(decl) 2147db96d56Sopenharmony_ci elif decl.kind is KIND.TYPEDEF: 2157db96d56Sopenharmony_ci return _check_vartype(decl, typedecl, types, knowntypes) 2167db96d56Sopenharmony_ci elif decl.kind is KIND.VARIABLE: 2177db96d56Sopenharmony_ci if not is_process_global(decl): 2187db96d56Sopenharmony_ci return None 2197db96d56Sopenharmony_ci checked = _check_vartype(decl, typedecl, types, knowntypes) 2207db96d56Sopenharmony_ci return 'mutable' if checked is FIXED_TYPE else checked 2217db96d56Sopenharmony_ci else: 2227db96d56Sopenharmony_ci raise NotImplementedError(decl) 2237db96d56Sopenharmony_ci 2247db96d56Sopenharmony_ci 2257db96d56Sopenharmony_cidef _check_vartype(decl, typedecl, types, knowntypes): 2267db96d56Sopenharmony_ci """Return failure reason.""" 2277db96d56Sopenharmony_ci checked = _check_typespec(decl, typedecl, types, knowntypes) 2287db96d56Sopenharmony_ci if checked: 2297db96d56Sopenharmony_ci return checked 2307db96d56Sopenharmony_ci if is_immutable(decl.vartype): 2317db96d56Sopenharmony_ci return None 2327db96d56Sopenharmony_ci if is_fixed_type(decl.vartype): 2337db96d56Sopenharmony_ci return FIXED_TYPE 2347db96d56Sopenharmony_ci return 'mutable' 2357db96d56Sopenharmony_ci 2367db96d56Sopenharmony_ci 2377db96d56Sopenharmony_cidef _check_typespec(decl, typedecl, types, knowntypes): 2387db96d56Sopenharmony_ci typespec = decl.vartype.typespec 2397db96d56Sopenharmony_ci if typedecl is not None: 2407db96d56Sopenharmony_ci found = types.get(typedecl) 2417db96d56Sopenharmony_ci if found is None: 2427db96d56Sopenharmony_ci found = knowntypes.get(typedecl) 2437db96d56Sopenharmony_ci 2447db96d56Sopenharmony_ci if found is not None: 2457db96d56Sopenharmony_ci _, extra = found 2467db96d56Sopenharmony_ci if extra is None: 2477db96d56Sopenharmony_ci # XXX Under what circumstances does this happen? 2487db96d56Sopenharmony_ci extra = {} 2497db96d56Sopenharmony_ci unsupported = extra.get('unsupported') 2507db96d56Sopenharmony_ci if unsupported is FIXED_TYPE: 2517db96d56Sopenharmony_ci unsupported = None 2527db96d56Sopenharmony_ci return 'typespec' if unsupported else None 2537db96d56Sopenharmony_ci # Fall back to default known types. 2547db96d56Sopenharmony_ci if is_pots(typespec): 2557db96d56Sopenharmony_ci return None 2567db96d56Sopenharmony_ci elif is_system_type(typespec): 2577db96d56Sopenharmony_ci return None 2587db96d56Sopenharmony_ci elif is_funcptr(decl.vartype): 2597db96d56Sopenharmony_ci return None 2607db96d56Sopenharmony_ci return 'typespec' 2617db96d56Sopenharmony_ci 2627db96d56Sopenharmony_ci 2637db96d56Sopenharmony_ciclass Analyzed(_info.Analyzed): 2647db96d56Sopenharmony_ci 2657db96d56Sopenharmony_ci @classonly 2667db96d56Sopenharmony_ci def is_target(cls, raw): 2677db96d56Sopenharmony_ci if not super().is_target(raw): 2687db96d56Sopenharmony_ci return False 2697db96d56Sopenharmony_ci if raw.kind not in KINDS: 2707db96d56Sopenharmony_ci return False 2717db96d56Sopenharmony_ci return True 2727db96d56Sopenharmony_ci 2737db96d56Sopenharmony_ci #@classonly 2747db96d56Sopenharmony_ci #def _parse_raw_result(cls, result, extra): 2757db96d56Sopenharmony_ci # typedecl, extra = super()._parse_raw_result(result, extra) 2767db96d56Sopenharmony_ci # if typedecl is None: 2777db96d56Sopenharmony_ci # return None, extra 2787db96d56Sopenharmony_ci # raise NotImplementedError 2797db96d56Sopenharmony_ci 2807db96d56Sopenharmony_ci def __init__(self, item, typedecl=None, *, unsupported=None, **extra): 2817db96d56Sopenharmony_ci if 'unsupported' in extra: 2827db96d56Sopenharmony_ci raise NotImplementedError((item, typedecl, unsupported, extra)) 2837db96d56Sopenharmony_ci if not unsupported: 2847db96d56Sopenharmony_ci unsupported = None 2857db96d56Sopenharmony_ci elif isinstance(unsupported, (str, TypeDeclaration)): 2867db96d56Sopenharmony_ci unsupported = (unsupported,) 2877db96d56Sopenharmony_ci elif unsupported is not FIXED_TYPE: 2887db96d56Sopenharmony_ci unsupported = tuple(unsupported) 2897db96d56Sopenharmony_ci self.unsupported = unsupported 2907db96d56Sopenharmony_ci extra['unsupported'] = self.unsupported # ...for __repr__(), etc. 2917db96d56Sopenharmony_ci if self.unsupported is None: 2927db96d56Sopenharmony_ci #self.supported = None 2937db96d56Sopenharmony_ci self.supported = True 2947db96d56Sopenharmony_ci elif self.unsupported is FIXED_TYPE: 2957db96d56Sopenharmony_ci if item.kind is KIND.VARIABLE: 2967db96d56Sopenharmony_ci raise NotImplementedError(item, typedecl, unsupported) 2977db96d56Sopenharmony_ci self.supported = True 2987db96d56Sopenharmony_ci else: 2997db96d56Sopenharmony_ci self.supported = not self.unsupported 3007db96d56Sopenharmony_ci super().__init__(item, typedecl, **extra) 3017db96d56Sopenharmony_ci 3027db96d56Sopenharmony_ci def render(self, fmt='line', *, itemonly=False): 3037db96d56Sopenharmony_ci if fmt == 'raw': 3047db96d56Sopenharmony_ci yield repr(self) 3057db96d56Sopenharmony_ci return 3067db96d56Sopenharmony_ci rendered = super().render(fmt, itemonly=itemonly) 3077db96d56Sopenharmony_ci # XXX ??? 3087db96d56Sopenharmony_ci #if itemonly: 3097db96d56Sopenharmony_ci # yield from rendered 3107db96d56Sopenharmony_ci supported = self.supported 3117db96d56Sopenharmony_ci if fmt in ('line', 'brief'): 3127db96d56Sopenharmony_ci rendered, = rendered 3137db96d56Sopenharmony_ci parts = [ 3147db96d56Sopenharmony_ci '+' if supported else '-' if supported is False else '', 3157db96d56Sopenharmony_ci rendered, 3167db96d56Sopenharmony_ci ] 3177db96d56Sopenharmony_ci yield '\t'.join(parts) 3187db96d56Sopenharmony_ci elif fmt == 'summary': 3197db96d56Sopenharmony_ci raise NotImplementedError(fmt) 3207db96d56Sopenharmony_ci elif fmt == 'full': 3217db96d56Sopenharmony_ci yield from rendered 3227db96d56Sopenharmony_ci if supported: 3237db96d56Sopenharmony_ci yield f'\tsupported:\t{supported}' 3247db96d56Sopenharmony_ci else: 3257db96d56Sopenharmony_ci raise NotImplementedError(fmt) 3267db96d56Sopenharmony_ci 3277db96d56Sopenharmony_ci 3287db96d56Sopenharmony_ciclass Analysis(_info.Analysis): 3297db96d56Sopenharmony_ci _item_class = Analyzed 3307db96d56Sopenharmony_ci 3317db96d56Sopenharmony_ci @classonly 3327db96d56Sopenharmony_ci def build_item(cls, info, result=None): 3337db96d56Sopenharmony_ci if not isinstance(info, Declaration) or info.kind not in KINDS: 3347db96d56Sopenharmony_ci raise NotImplementedError((info, result)) 3357db96d56Sopenharmony_ci return super().build_item(info, result) 3367db96d56Sopenharmony_ci 3377db96d56Sopenharmony_ci 3387db96d56Sopenharmony_cidef check_globals(analysis): 3397db96d56Sopenharmony_ci # yield (data, failure) 3407db96d56Sopenharmony_ci ignored = read_ignored() 3417db96d56Sopenharmony_ci for item in analysis: 3427db96d56Sopenharmony_ci if item.kind != KIND.VARIABLE: 3437db96d56Sopenharmony_ci continue 3447db96d56Sopenharmony_ci if item.supported: 3457db96d56Sopenharmony_ci continue 3467db96d56Sopenharmony_ci if item.id in ignored: 3477db96d56Sopenharmony_ci continue 3487db96d56Sopenharmony_ci reason = item.unsupported 3497db96d56Sopenharmony_ci if not reason: 3507db96d56Sopenharmony_ci reason = '???' 3517db96d56Sopenharmony_ci elif not isinstance(reason, str): 3527db96d56Sopenharmony_ci if len(reason) == 1: 3537db96d56Sopenharmony_ci reason, = reason 3547db96d56Sopenharmony_ci reason = f'({reason})' 3557db96d56Sopenharmony_ci yield item, f'not supported {reason:20}\t{item.storage or ""} {item.vartype}' 356