17db96d56Sopenharmony_cifrom collections import namedtuple 27db96d56Sopenharmony_ciimport os.path 37db96d56Sopenharmony_ci 47db96d56Sopenharmony_cifrom c_common import fsutil 57db96d56Sopenharmony_cifrom c_common.clsutil import classonly 67db96d56Sopenharmony_ciimport c_common.misc as _misc 77db96d56Sopenharmony_cifrom c_parser.info import ( 87db96d56Sopenharmony_ci KIND, 97db96d56Sopenharmony_ci HighlevelParsedItem, 107db96d56Sopenharmony_ci Declaration, 117db96d56Sopenharmony_ci TypeDeclaration, 127db96d56Sopenharmony_ci) 137db96d56Sopenharmony_cifrom c_parser.match import ( 147db96d56Sopenharmony_ci is_type_decl, 157db96d56Sopenharmony_ci) 167db96d56Sopenharmony_cifrom .match import ( 177db96d56Sopenharmony_ci is_process_global, 187db96d56Sopenharmony_ci) 197db96d56Sopenharmony_ci 207db96d56Sopenharmony_ci 217db96d56Sopenharmony_ciIGNORED = _misc.Labeled('IGNORED') 227db96d56Sopenharmony_ciUNKNOWN = _misc.Labeled('UNKNOWN') 237db96d56Sopenharmony_ci 247db96d56Sopenharmony_ci 257db96d56Sopenharmony_ciclass SystemType(TypeDeclaration): 267db96d56Sopenharmony_ci 277db96d56Sopenharmony_ci def __init__(self, name): 287db96d56Sopenharmony_ci super().__init__(None, name, None, None, _shortkey=name) 297db96d56Sopenharmony_ci 307db96d56Sopenharmony_ci 317db96d56Sopenharmony_ciclass Analyzed: 327db96d56Sopenharmony_ci _locked = False 337db96d56Sopenharmony_ci 347db96d56Sopenharmony_ci @classonly 357db96d56Sopenharmony_ci def is_target(cls, raw): 367db96d56Sopenharmony_ci if isinstance(raw, HighlevelParsedItem): 377db96d56Sopenharmony_ci return True 387db96d56Sopenharmony_ci else: 397db96d56Sopenharmony_ci return False 407db96d56Sopenharmony_ci 417db96d56Sopenharmony_ci @classonly 427db96d56Sopenharmony_ci def from_raw(cls, raw, **extra): 437db96d56Sopenharmony_ci if isinstance(raw, cls): 447db96d56Sopenharmony_ci if extra: 457db96d56Sopenharmony_ci # XXX ? 467db96d56Sopenharmony_ci raise NotImplementedError((raw, extra)) 477db96d56Sopenharmony_ci #return cls(raw.item, raw.typedecl, **raw._extra, **extra) 487db96d56Sopenharmony_ci else: 497db96d56Sopenharmony_ci return info 507db96d56Sopenharmony_ci elif cls.is_target(raw): 517db96d56Sopenharmony_ci return cls(raw, **extra) 527db96d56Sopenharmony_ci else: 537db96d56Sopenharmony_ci raise NotImplementedError((raw, extra)) 547db96d56Sopenharmony_ci 557db96d56Sopenharmony_ci @classonly 567db96d56Sopenharmony_ci def from_resolved(cls, item, resolved, **extra): 577db96d56Sopenharmony_ci if isinstance(resolved, TypeDeclaration): 587db96d56Sopenharmony_ci return cls(item, typedecl=resolved, **extra) 597db96d56Sopenharmony_ci else: 607db96d56Sopenharmony_ci typedeps, extra = cls._parse_raw_resolved(item, resolved, extra) 617db96d56Sopenharmony_ci if item.kind is KIND.ENUM: 627db96d56Sopenharmony_ci if typedeps: 637db96d56Sopenharmony_ci raise NotImplementedError((item, resolved, extra)) 647db96d56Sopenharmony_ci elif not typedeps: 657db96d56Sopenharmony_ci raise NotImplementedError((item, resolved, extra)) 667db96d56Sopenharmony_ci return cls(item, typedeps, **extra or {}) 677db96d56Sopenharmony_ci 687db96d56Sopenharmony_ci @classonly 697db96d56Sopenharmony_ci def _parse_raw_resolved(cls, item, resolved, extra_extra): 707db96d56Sopenharmony_ci if resolved in (UNKNOWN, IGNORED): 717db96d56Sopenharmony_ci return resolved, None 727db96d56Sopenharmony_ci try: 737db96d56Sopenharmony_ci typedeps, extra = resolved 747db96d56Sopenharmony_ci except (TypeError, ValueError): 757db96d56Sopenharmony_ci typedeps = extra = None 767db96d56Sopenharmony_ci if extra: 777db96d56Sopenharmony_ci # The resolved data takes precedence. 787db96d56Sopenharmony_ci extra = dict(extra_extra, **extra) 797db96d56Sopenharmony_ci if isinstance(typedeps, TypeDeclaration): 807db96d56Sopenharmony_ci return typedeps, extra 817db96d56Sopenharmony_ci elif typedeps in (None, UNKNOWN): 827db96d56Sopenharmony_ci # It is still effectively unresolved. 837db96d56Sopenharmony_ci return UNKNOWN, extra 847db96d56Sopenharmony_ci elif None in typedeps or UNKNOWN in typedeps: 857db96d56Sopenharmony_ci # It is still effectively unresolved. 867db96d56Sopenharmony_ci return typedeps, extra 877db96d56Sopenharmony_ci elif any(not isinstance(td, TypeDeclaration) for td in typedeps): 887db96d56Sopenharmony_ci raise NotImplementedError((item, typedeps, extra)) 897db96d56Sopenharmony_ci return typedeps, extra 907db96d56Sopenharmony_ci 917db96d56Sopenharmony_ci def __init__(self, item, typedecl=None, **extra): 927db96d56Sopenharmony_ci assert item is not None 937db96d56Sopenharmony_ci self.item = item 947db96d56Sopenharmony_ci if typedecl in (UNKNOWN, IGNORED): 957db96d56Sopenharmony_ci pass 967db96d56Sopenharmony_ci elif item.kind is KIND.STRUCT or item.kind is KIND.UNION: 977db96d56Sopenharmony_ci if isinstance(typedecl, TypeDeclaration): 987db96d56Sopenharmony_ci raise NotImplementedError(item, typedecl) 997db96d56Sopenharmony_ci elif typedecl is None: 1007db96d56Sopenharmony_ci typedecl = UNKNOWN 1017db96d56Sopenharmony_ci else: 1027db96d56Sopenharmony_ci typedecl = [UNKNOWN if d is None else d for d in typedecl] 1037db96d56Sopenharmony_ci elif typedecl is None: 1047db96d56Sopenharmony_ci typedecl = UNKNOWN 1057db96d56Sopenharmony_ci elif typedecl and not isinstance(typedecl, TypeDeclaration): 1067db96d56Sopenharmony_ci # All the other decls have a single type decl. 1077db96d56Sopenharmony_ci typedecl, = typedecl 1087db96d56Sopenharmony_ci if typedecl is None: 1097db96d56Sopenharmony_ci typedecl = UNKNOWN 1107db96d56Sopenharmony_ci self.typedecl = typedecl 1117db96d56Sopenharmony_ci self._extra = extra 1127db96d56Sopenharmony_ci self._locked = True 1137db96d56Sopenharmony_ci 1147db96d56Sopenharmony_ci self._validate() 1157db96d56Sopenharmony_ci 1167db96d56Sopenharmony_ci def _validate(self): 1177db96d56Sopenharmony_ci item = self.item 1187db96d56Sopenharmony_ci extra = self._extra 1197db96d56Sopenharmony_ci # Check item. 1207db96d56Sopenharmony_ci if not isinstance(item, HighlevelParsedItem): 1217db96d56Sopenharmony_ci raise ValueError(f'"item" must be a high-level parsed item, got {item!r}') 1227db96d56Sopenharmony_ci # Check extra. 1237db96d56Sopenharmony_ci for key, value in extra.items(): 1247db96d56Sopenharmony_ci if key.startswith('_'): 1257db96d56Sopenharmony_ci raise ValueError(f'extra items starting with {"_"!r} not allowed, got {extra!r}') 1267db96d56Sopenharmony_ci if hasattr(item, key) and not callable(getattr(item, key)): 1277db96d56Sopenharmony_ci raise ValueError(f'extra cannot override item, got {value!r} for key {key!r}') 1287db96d56Sopenharmony_ci 1297db96d56Sopenharmony_ci def __repr__(self): 1307db96d56Sopenharmony_ci kwargs = [ 1317db96d56Sopenharmony_ci f'item={self.item!r}', 1327db96d56Sopenharmony_ci f'typedecl={self.typedecl!r}', 1337db96d56Sopenharmony_ci *(f'{k}={v!r}' for k, v in self._extra.items()) 1347db96d56Sopenharmony_ci ] 1357db96d56Sopenharmony_ci return f'{type(self).__name__}({", ".join(kwargs)})' 1367db96d56Sopenharmony_ci 1377db96d56Sopenharmony_ci def __str__(self): 1387db96d56Sopenharmony_ci try: 1397db96d56Sopenharmony_ci return self._str 1407db96d56Sopenharmony_ci except AttributeError: 1417db96d56Sopenharmony_ci self._str, = self.render('line') 1427db96d56Sopenharmony_ci return self._str 1437db96d56Sopenharmony_ci 1447db96d56Sopenharmony_ci def __hash__(self): 1457db96d56Sopenharmony_ci return hash(self.item) 1467db96d56Sopenharmony_ci 1477db96d56Sopenharmony_ci def __eq__(self, other): 1487db96d56Sopenharmony_ci if isinstance(other, Analyzed): 1497db96d56Sopenharmony_ci return self.item == other.item 1507db96d56Sopenharmony_ci elif isinstance(other, HighlevelParsedItem): 1517db96d56Sopenharmony_ci return self.item == other 1527db96d56Sopenharmony_ci elif type(other) is tuple: 1537db96d56Sopenharmony_ci return self.item == other 1547db96d56Sopenharmony_ci else: 1557db96d56Sopenharmony_ci return NotImplemented 1567db96d56Sopenharmony_ci 1577db96d56Sopenharmony_ci def __gt__(self, other): 1587db96d56Sopenharmony_ci if isinstance(other, Analyzed): 1597db96d56Sopenharmony_ci return self.item > other.item 1607db96d56Sopenharmony_ci elif isinstance(other, HighlevelParsedItem): 1617db96d56Sopenharmony_ci return self.item > other 1627db96d56Sopenharmony_ci elif type(other) is tuple: 1637db96d56Sopenharmony_ci return self.item > other 1647db96d56Sopenharmony_ci else: 1657db96d56Sopenharmony_ci return NotImplemented 1667db96d56Sopenharmony_ci 1677db96d56Sopenharmony_ci def __dir__(self): 1687db96d56Sopenharmony_ci names = set(super().__dir__()) 1697db96d56Sopenharmony_ci names.update(self._extra) 1707db96d56Sopenharmony_ci names.remove('_locked') 1717db96d56Sopenharmony_ci return sorted(names) 1727db96d56Sopenharmony_ci 1737db96d56Sopenharmony_ci def __getattr__(self, name): 1747db96d56Sopenharmony_ci if name.startswith('_'): 1757db96d56Sopenharmony_ci raise AttributeError(name) 1767db96d56Sopenharmony_ci # The item takes precedence over the extra data (except if callable). 1777db96d56Sopenharmony_ci try: 1787db96d56Sopenharmony_ci value = getattr(self.item, name) 1797db96d56Sopenharmony_ci if callable(value): 1807db96d56Sopenharmony_ci raise AttributeError(name) 1817db96d56Sopenharmony_ci except AttributeError: 1827db96d56Sopenharmony_ci try: 1837db96d56Sopenharmony_ci value = self._extra[name] 1847db96d56Sopenharmony_ci except KeyError: 1857db96d56Sopenharmony_ci pass 1867db96d56Sopenharmony_ci else: 1877db96d56Sopenharmony_ci # Speed things up the next time. 1887db96d56Sopenharmony_ci self.__dict__[name] = value 1897db96d56Sopenharmony_ci return value 1907db96d56Sopenharmony_ci raise # re-raise 1917db96d56Sopenharmony_ci else: 1927db96d56Sopenharmony_ci return value 1937db96d56Sopenharmony_ci 1947db96d56Sopenharmony_ci def __setattr__(self, name, value): 1957db96d56Sopenharmony_ci if self._locked and name != '_str': 1967db96d56Sopenharmony_ci raise AttributeError(f'readonly ({name})') 1977db96d56Sopenharmony_ci super().__setattr__(name, value) 1987db96d56Sopenharmony_ci 1997db96d56Sopenharmony_ci def __delattr__(self, name): 2007db96d56Sopenharmony_ci if self._locked: 2017db96d56Sopenharmony_ci raise AttributeError(f'readonly ({name})') 2027db96d56Sopenharmony_ci super().__delattr__(name) 2037db96d56Sopenharmony_ci 2047db96d56Sopenharmony_ci @property 2057db96d56Sopenharmony_ci def decl(self): 2067db96d56Sopenharmony_ci if not isinstance(self.item, Declaration): 2077db96d56Sopenharmony_ci raise AttributeError('decl') 2087db96d56Sopenharmony_ci return self.item 2097db96d56Sopenharmony_ci 2107db96d56Sopenharmony_ci @property 2117db96d56Sopenharmony_ci def signature(self): 2127db96d56Sopenharmony_ci # XXX vartype... 2137db96d56Sopenharmony_ci ... 2147db96d56Sopenharmony_ci 2157db96d56Sopenharmony_ci @property 2167db96d56Sopenharmony_ci def istype(self): 2177db96d56Sopenharmony_ci return is_type_decl(self.item.kind) 2187db96d56Sopenharmony_ci 2197db96d56Sopenharmony_ci @property 2207db96d56Sopenharmony_ci def is_known(self): 2217db96d56Sopenharmony_ci if self.typedecl in (UNKNOWN, IGNORED): 2227db96d56Sopenharmony_ci return False 2237db96d56Sopenharmony_ci elif isinstance(self.typedecl, TypeDeclaration): 2247db96d56Sopenharmony_ci return True 2257db96d56Sopenharmony_ci else: 2267db96d56Sopenharmony_ci return UNKNOWN not in self.typedecl 2277db96d56Sopenharmony_ci 2287db96d56Sopenharmony_ci def fix_filename(self, relroot=fsutil.USE_CWD, **kwargs): 2297db96d56Sopenharmony_ci self.item.fix_filename(relroot, **kwargs) 2307db96d56Sopenharmony_ci return self 2317db96d56Sopenharmony_ci 2327db96d56Sopenharmony_ci def as_rowdata(self, columns=None): 2337db96d56Sopenharmony_ci # XXX finish! 2347db96d56Sopenharmony_ci return self.item.as_rowdata(columns) 2357db96d56Sopenharmony_ci 2367db96d56Sopenharmony_ci def render_rowdata(self, columns=None): 2377db96d56Sopenharmony_ci # XXX finish! 2387db96d56Sopenharmony_ci return self.item.render_rowdata(columns) 2397db96d56Sopenharmony_ci 2407db96d56Sopenharmony_ci def render(self, fmt='line', *, itemonly=False): 2417db96d56Sopenharmony_ci if fmt == 'raw': 2427db96d56Sopenharmony_ci yield repr(self) 2437db96d56Sopenharmony_ci return 2447db96d56Sopenharmony_ci rendered = self.item.render(fmt) 2457db96d56Sopenharmony_ci if itemonly or not self._extra: 2467db96d56Sopenharmony_ci yield from rendered 2477db96d56Sopenharmony_ci return 2487db96d56Sopenharmony_ci extra = self._render_extra(fmt) 2497db96d56Sopenharmony_ci if not extra: 2507db96d56Sopenharmony_ci yield from rendered 2517db96d56Sopenharmony_ci elif fmt in ('brief', 'line'): 2527db96d56Sopenharmony_ci rendered, = rendered 2537db96d56Sopenharmony_ci extra, = extra 2547db96d56Sopenharmony_ci yield f'{rendered}\t{extra}' 2557db96d56Sopenharmony_ci elif fmt == 'summary': 2567db96d56Sopenharmony_ci raise NotImplementedError(fmt) 2577db96d56Sopenharmony_ci elif fmt == 'full': 2587db96d56Sopenharmony_ci yield from rendered 2597db96d56Sopenharmony_ci for line in extra: 2607db96d56Sopenharmony_ci yield f'\t{line}' 2617db96d56Sopenharmony_ci else: 2627db96d56Sopenharmony_ci raise NotImplementedError(fmt) 2637db96d56Sopenharmony_ci 2647db96d56Sopenharmony_ci def _render_extra(self, fmt): 2657db96d56Sopenharmony_ci if fmt in ('brief', 'line'): 2667db96d56Sopenharmony_ci yield str(self._extra) 2677db96d56Sopenharmony_ci else: 2687db96d56Sopenharmony_ci raise NotImplementedError(fmt) 2697db96d56Sopenharmony_ci 2707db96d56Sopenharmony_ci 2717db96d56Sopenharmony_ciclass Analysis: 2727db96d56Sopenharmony_ci 2737db96d56Sopenharmony_ci _item_class = Analyzed 2747db96d56Sopenharmony_ci 2757db96d56Sopenharmony_ci @classonly 2767db96d56Sopenharmony_ci def build_item(cls, info, resolved=None, **extra): 2777db96d56Sopenharmony_ci if resolved is None: 2787db96d56Sopenharmony_ci return cls._item_class.from_raw(info, **extra) 2797db96d56Sopenharmony_ci else: 2807db96d56Sopenharmony_ci return cls._item_class.from_resolved(info, resolved, **extra) 2817db96d56Sopenharmony_ci 2827db96d56Sopenharmony_ci @classmethod 2837db96d56Sopenharmony_ci def from_results(cls, results): 2847db96d56Sopenharmony_ci self = cls() 2857db96d56Sopenharmony_ci for info, resolved in results: 2867db96d56Sopenharmony_ci self._add_result(info, resolved) 2877db96d56Sopenharmony_ci return self 2887db96d56Sopenharmony_ci 2897db96d56Sopenharmony_ci def __init__(self, items=None): 2907db96d56Sopenharmony_ci self._analyzed = {type(self).build_item(item): None 2917db96d56Sopenharmony_ci for item in items or ()} 2927db96d56Sopenharmony_ci 2937db96d56Sopenharmony_ci def __repr__(self): 2947db96d56Sopenharmony_ci return f'{type(self).__name__}({list(self._analyzed.keys())})' 2957db96d56Sopenharmony_ci 2967db96d56Sopenharmony_ci def __iter__(self): 2977db96d56Sopenharmony_ci #yield from self.types 2987db96d56Sopenharmony_ci #yield from self.functions 2997db96d56Sopenharmony_ci #yield from self.variables 3007db96d56Sopenharmony_ci yield from self._analyzed 3017db96d56Sopenharmony_ci 3027db96d56Sopenharmony_ci def __len__(self): 3037db96d56Sopenharmony_ci return len(self._analyzed) 3047db96d56Sopenharmony_ci 3057db96d56Sopenharmony_ci def __getitem__(self, key): 3067db96d56Sopenharmony_ci if type(key) is int: 3077db96d56Sopenharmony_ci for i, val in enumerate(self._analyzed): 3087db96d56Sopenharmony_ci if i == key: 3097db96d56Sopenharmony_ci return val 3107db96d56Sopenharmony_ci else: 3117db96d56Sopenharmony_ci raise IndexError(key) 3127db96d56Sopenharmony_ci else: 3137db96d56Sopenharmony_ci return self._analyzed[key] 3147db96d56Sopenharmony_ci 3157db96d56Sopenharmony_ci def fix_filenames(self, relroot=fsutil.USE_CWD, **kwargs): 3167db96d56Sopenharmony_ci if relroot and relroot is not fsutil.USE_CWD: 3177db96d56Sopenharmony_ci relroot = os.path.abspath(relroot) 3187db96d56Sopenharmony_ci for item in self._analyzed: 3197db96d56Sopenharmony_ci item.fix_filename(relroot, fixroot=False, **kwargs) 3207db96d56Sopenharmony_ci 3217db96d56Sopenharmony_ci def _add_result(self, info, resolved): 3227db96d56Sopenharmony_ci analyzed = type(self).build_item(info, resolved) 3237db96d56Sopenharmony_ci self._analyzed[analyzed] = None 3247db96d56Sopenharmony_ci return analyzed 325