|
|
@@ -4,284 +4,18 @@ import csv
|
|
|
import operator
|
|
|
|
|
|
from enum import Enum, auto
|
|
|
-from typing import List, Set, ClassVar, Any
|
|
|
-from dataclasses import dataclass, field
|
|
|
+from typing import Set, ClassVar, Any
|
|
|
+from dataclasses import dataclass
|
|
|
|
|
|
from ansi.color import fg
|
|
|
|
|
|
-from cxxheaderparser.parser import CxxParser
|
|
|
-
|
|
|
-
|
|
|
-# 'Fixing' complaints about typedefs
|
|
|
-CxxParser._fundamentals.discard("wchar_t")
|
|
|
-
|
|
|
-from cxxheaderparser.types import (
|
|
|
- EnumDecl,
|
|
|
- Field,
|
|
|
- ForwardDecl,
|
|
|
- FriendDecl,
|
|
|
- Function,
|
|
|
- Method,
|
|
|
- Typedef,
|
|
|
- UsingAlias,
|
|
|
- UsingDecl,
|
|
|
- Variable,
|
|
|
- Pointer,
|
|
|
- Type,
|
|
|
- PQName,
|
|
|
- NameSpecifier,
|
|
|
- FundamentalSpecifier,
|
|
|
- Parameter,
|
|
|
- Array,
|
|
|
- Value,
|
|
|
- Token,
|
|
|
- FunctionType,
|
|
|
+from . import (
|
|
|
+ ApiEntries,
|
|
|
+ ApiEntryFunction,
|
|
|
+ ApiEntryVariable,
|
|
|
+ ApiHeader,
|
|
|
)
|
|
|
|
|
|
-from cxxheaderparser.parserstate import (
|
|
|
- State,
|
|
|
- EmptyBlockState,
|
|
|
- ClassBlockState,
|
|
|
- ExternBlockState,
|
|
|
- NamespaceBlockState,
|
|
|
-)
|
|
|
-
|
|
|
-
|
|
|
-@dataclass(frozen=True)
|
|
|
-class ApiEntryFunction:
|
|
|
- name: str
|
|
|
- returns: str
|
|
|
- params: str
|
|
|
-
|
|
|
- csv_type: ClassVar[str] = "Function"
|
|
|
-
|
|
|
- def dictify(self):
|
|
|
- return dict(name=self.name, type=self.returns, params=self.params)
|
|
|
-
|
|
|
-
|
|
|
-@dataclass(frozen=True)
|
|
|
-class ApiEntryVariable:
|
|
|
- name: str
|
|
|
- var_type: str
|
|
|
-
|
|
|
- csv_type: ClassVar[str] = "Variable"
|
|
|
-
|
|
|
- def dictify(self):
|
|
|
- return dict(name=self.name, type=self.var_type, params=None)
|
|
|
-
|
|
|
-
|
|
|
-@dataclass(frozen=True)
|
|
|
-class ApiHeader:
|
|
|
- name: str
|
|
|
-
|
|
|
- csv_type: ClassVar[str] = "Header"
|
|
|
-
|
|
|
- def dictify(self):
|
|
|
- return dict(name=self.name, type=None, params=None)
|
|
|
-
|
|
|
-
|
|
|
-@dataclass
|
|
|
-class ApiEntries:
|
|
|
- # These are sets, to avoid creating duplicates when we have multiple
|
|
|
- # declarations with same signature
|
|
|
- functions: Set[ApiEntryFunction] = field(default_factory=set)
|
|
|
- variables: Set[ApiEntryVariable] = field(default_factory=set)
|
|
|
- headers: Set[ApiHeader] = field(default_factory=set)
|
|
|
-
|
|
|
-
|
|
|
-class SymbolManager:
|
|
|
- def __init__(self):
|
|
|
- self.api = ApiEntries()
|
|
|
- self.name_hashes = set()
|
|
|
-
|
|
|
- # Calculate hash of name and raise exception if it already is in the set
|
|
|
- def _name_check(self, name: str):
|
|
|
- name_hash = gnu_sym_hash(name)
|
|
|
- if name_hash in self.name_hashes:
|
|
|
- raise Exception(f"Hash collision on {name}")
|
|
|
- self.name_hashes.add(name_hash)
|
|
|
-
|
|
|
- def add_function(self, function_def: ApiEntryFunction):
|
|
|
- if function_def in self.api.functions:
|
|
|
- return
|
|
|
- self._name_check(function_def.name)
|
|
|
- self.api.functions.add(function_def)
|
|
|
-
|
|
|
- def add_variable(self, variable_def: ApiEntryVariable):
|
|
|
- if variable_def in self.api.variables:
|
|
|
- return
|
|
|
- self._name_check(variable_def.name)
|
|
|
- self.api.variables.add(variable_def)
|
|
|
-
|
|
|
- def add_header(self, header: str):
|
|
|
- self.api.headers.add(ApiHeader(header))
|
|
|
-
|
|
|
-
|
|
|
-def gnu_sym_hash(name: str):
|
|
|
- h = 0x1505
|
|
|
- for c in name:
|
|
|
- h = (h << 5) + h + ord(c)
|
|
|
- return str(hex(h))[-8:]
|
|
|
-
|
|
|
-
|
|
|
-class SdkCollector:
|
|
|
- def __init__(self):
|
|
|
- self.symbol_manager = SymbolManager()
|
|
|
-
|
|
|
- def add_header_to_sdk(self, header: str):
|
|
|
- self.symbol_manager.add_header(header)
|
|
|
-
|
|
|
- def process_source_file_for_sdk(self, file_path: str):
|
|
|
- visitor = SdkCxxVisitor(self.symbol_manager)
|
|
|
- with open(file_path, "rt") as f:
|
|
|
- content = f.read()
|
|
|
- parser = CxxParser(file_path, content, visitor, None)
|
|
|
- parser.parse()
|
|
|
-
|
|
|
- def get_api(self):
|
|
|
- return self.symbol_manager.api
|
|
|
-
|
|
|
-
|
|
|
-def stringify_array_dimension(size_descr):
|
|
|
- if not size_descr:
|
|
|
- return ""
|
|
|
- return stringify_descr(size_descr)
|
|
|
-
|
|
|
-
|
|
|
-def stringify_array_descr(type_descr):
|
|
|
- assert isinstance(type_descr, Array)
|
|
|
- return (
|
|
|
- stringify_descr(type_descr.array_of),
|
|
|
- stringify_array_dimension(type_descr.size),
|
|
|
- )
|
|
|
-
|
|
|
-
|
|
|
-def stringify_descr(type_descr):
|
|
|
- if isinstance(type_descr, (NameSpecifier, FundamentalSpecifier)):
|
|
|
- return type_descr.name
|
|
|
- elif isinstance(type_descr, PQName):
|
|
|
- return "::".join(map(stringify_descr, type_descr.segments))
|
|
|
- elif isinstance(type_descr, Pointer):
|
|
|
- # Hack
|
|
|
- if isinstance(type_descr.ptr_to, FunctionType):
|
|
|
- return stringify_descr(type_descr.ptr_to)
|
|
|
- return f"{stringify_descr(type_descr.ptr_to)}*"
|
|
|
- elif isinstance(type_descr, Type):
|
|
|
- return (
|
|
|
- f"{'const ' if type_descr.const else ''}"
|
|
|
- f"{'volatile ' if type_descr.volatile else ''}"
|
|
|
- f"{stringify_descr(type_descr.typename)}"
|
|
|
- )
|
|
|
- elif isinstance(type_descr, Parameter):
|
|
|
- return stringify_descr(type_descr.type)
|
|
|
- elif isinstance(type_descr, Array):
|
|
|
- # Hack for 2d arrays
|
|
|
- if isinstance(type_descr.array_of, Array):
|
|
|
- argtype, dimension = stringify_array_descr(type_descr.array_of)
|
|
|
- return (
|
|
|
- f"{argtype}[{stringify_array_dimension(type_descr.size)}][{dimension}]"
|
|
|
- )
|
|
|
- return f"{stringify_descr(type_descr.array_of)}[{stringify_array_dimension(type_descr.size)}]"
|
|
|
- elif isinstance(type_descr, Value):
|
|
|
- return " ".join(map(stringify_descr, type_descr.tokens))
|
|
|
- elif isinstance(type_descr, FunctionType):
|
|
|
- return f"{stringify_descr(type_descr.return_type)} (*)({', '.join(map(stringify_descr, type_descr.parameters))})"
|
|
|
- elif isinstance(type_descr, Token):
|
|
|
- return type_descr.value
|
|
|
- elif type_descr is None:
|
|
|
- return ""
|
|
|
- else:
|
|
|
- raise Exception("unsupported type_descr: %s" % type_descr)
|
|
|
-
|
|
|
-
|
|
|
-class SdkCxxVisitor:
|
|
|
- def __init__(self, symbol_manager: SymbolManager):
|
|
|
- self.api = symbol_manager
|
|
|
-
|
|
|
- def on_variable(self, state: State, v: Variable) -> None:
|
|
|
- if not v.extern:
|
|
|
- return
|
|
|
-
|
|
|
- self.api.add_variable(
|
|
|
- ApiEntryVariable(
|
|
|
- stringify_descr(v.name),
|
|
|
- stringify_descr(v.type),
|
|
|
- )
|
|
|
- )
|
|
|
-
|
|
|
- def on_function(self, state: State, fn: Function) -> None:
|
|
|
- if fn.inline or fn.has_body:
|
|
|
- return
|
|
|
-
|
|
|
- self.api.add_function(
|
|
|
- ApiEntryFunction(
|
|
|
- stringify_descr(fn.name),
|
|
|
- stringify_descr(fn.return_type),
|
|
|
- ", ".join(map(stringify_descr, fn.parameters))
|
|
|
- + (", ..." if fn.vararg else ""),
|
|
|
- )
|
|
|
- )
|
|
|
-
|
|
|
- def on_define(self, state: State, content: str) -> None:
|
|
|
- pass
|
|
|
-
|
|
|
- def on_pragma(self, state: State, content: str) -> None:
|
|
|
- pass
|
|
|
-
|
|
|
- def on_include(self, state: State, filename: str) -> None:
|
|
|
- pass
|
|
|
-
|
|
|
- def on_empty_block_start(self, state: EmptyBlockState) -> None:
|
|
|
- pass
|
|
|
-
|
|
|
- def on_empty_block_end(self, state: EmptyBlockState) -> None:
|
|
|
- pass
|
|
|
-
|
|
|
- def on_extern_block_start(self, state: ExternBlockState) -> None:
|
|
|
- pass
|
|
|
-
|
|
|
- def on_extern_block_end(self, state: ExternBlockState) -> None:
|
|
|
- pass
|
|
|
-
|
|
|
- def on_namespace_start(self, state: NamespaceBlockState) -> None:
|
|
|
- pass
|
|
|
-
|
|
|
- def on_namespace_end(self, state: NamespaceBlockState) -> None:
|
|
|
- pass
|
|
|
-
|
|
|
- def on_forward_decl(self, state: State, fdecl: ForwardDecl) -> None:
|
|
|
- pass
|
|
|
-
|
|
|
- def on_typedef(self, state: State, typedef: Typedef) -> None:
|
|
|
- pass
|
|
|
-
|
|
|
- def on_using_namespace(self, state: State, namespace: List[str]) -> None:
|
|
|
- pass
|
|
|
-
|
|
|
- def on_using_alias(self, state: State, using: UsingAlias) -> None:
|
|
|
- pass
|
|
|
-
|
|
|
- def on_using_declaration(self, state: State, using: UsingDecl) -> None:
|
|
|
- pass
|
|
|
-
|
|
|
- def on_enum(self, state: State, enum: EnumDecl) -> None:
|
|
|
- pass
|
|
|
-
|
|
|
- def on_class_start(self, state: ClassBlockState) -> None:
|
|
|
- pass
|
|
|
-
|
|
|
- def on_class_field(self, state: State, f: Field) -> None:
|
|
|
- pass
|
|
|
-
|
|
|
- def on_class_method(self, state: ClassBlockState, method: Method) -> None:
|
|
|
- pass
|
|
|
-
|
|
|
- def on_class_friend(self, state: ClassBlockState, friend: FriendDecl) -> None:
|
|
|
- pass
|
|
|
-
|
|
|
- def on_class_end(self, state: ClassBlockState) -> None:
|
|
|
- pass
|
|
|
-
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
|
class SdkVersion:
|