def gen_typedef(self): """ Generates an internal typedef definition for this function. :param typedef_name: Overrides automatic type name generation w/ value. """ _tmp, tmp = None, None # Fix for an insiduous bug with string identifiers (e.g. int_fast32_t) _tmp = self.func_decl.type.type.type\ if isinstance(self.func_decl.type.type, TypeDecl) else\ IdentifierType(names=self.func_decl.type.type.names) # Use TypeDecl/PtrDecl depending on whether return value is a pointer tmp = PtrDecl([], TypeDecl(self.typedef_name, [], _tmp))\ if self.ret_var.ptr else TypeDecl(self.typedef_name, [], _tmp) _tmp_fdecl = PtrDecl([], FuncDecl(self.param_list, tmp)) # Update base type so its registered a MyriadCType subclass self.base_type = type(self.typedef_name, (MyriadCType, ), {'mtype': IdentifierType([self.typedef_name])})() # Create typedef so its registered by the pycparser AST self.fun_typedef = Typedef(name=self.typedef_name, quals=[], storage=['typedef'], type=_tmp_fdecl, coord=None)
def pointer_decay(type: Type, typemap: TypeMap) -> SimpleType: real_type = resolve_typedefs(type, typemap) if isinstance(real_type, ArrayDecl): return PtrDecl(quals=[], type=real_type.type) if isinstance(real_type, FuncDecl): return PtrDecl(quals=[], type=type) if isinstance(real_type, TypeDecl) and isinstance(real_type.type, c_ast.Enum): return basic_type("int") assert not isinstance( type, (ArrayDecl, FuncDecl) ), "resolve_typedefs can't hide arrays/functions" return type
def void_ptr_ptr(cls, ident: str): """ Special method for generating a void** (corner case)""" obj = cls(ident, MVoid, True) obj.ptr_decl = PtrDecl(quals=[], type=obj.ptr_decl) obj.decl = Decl(name=obj.ident, quals=obj.quals, storage=obj.storage, funcspec=[], type=obj.ptr_decl, init=obj.init, bitsize=None) return obj
def pointer(type: Type) -> Type: return PtrDecl(quals=[], type=type)
def print_header(message): generator = CGenerator() parser = CParser() def del_spaces(name): if name.startswith('(extension in '): idx = name.index('):') name = '_extension_in_' + name[14:idx] + "__" + name[idx + 2:] # file private types if ' in _' in name: idx = name.index(' in _') end = name.index(')', idx) start = name.rindex('(', None, idx) namespace = name[:start] if '>' in namespace: namespace = mangle_name(namespace[:-1]) + '.' name = namespace + name[start + 1:idx] + name[end + 1:] return name def mangle_name(human): if human in ('void*', 'voidp', 'Metadata*'): return human if human == '()': return 'void' info = types[human] if 'getGenericParams' in info and info['getGenericParams']: name = remove_generic(human) else: name = human if name.startswith('?Unknown type of'): name = name.replace('?Unknown type of ', 'XXX_unknown_type_of_') if name.startswith("Static #"): spl = name.split(' ', 4) return "_static_no" + spl[1][1:] + "_in_" + spl[ 3] + "__func" + str(hash(spl[4]))[1:] name = del_spaces(name) outp = f'swift_{info["kind"]}__' if info['kind'] == "Tuple": elems = [] for e in info['tupleElements']: name = mangle_name(e['type']) if e['label']: name += "__as_" + e['label'] elems.append(name) outp += "with__" + "__and__".join(elems) elif info['kind'] == "Existential": protos = [] for p in info['protocols']: protos.append( del_spaces(script.exports.demangle(p)).replace(".", "__")) if info['isClassBounded']: protos.append("Swift__AnyObject") if protos: outp += "conforming_to__" + "__and__".join(protos) else: outp += "Any" if info.get('getSuperclassConstraint'): outp += "__inheriting_from_" + mangle_name( info['getSuperclassConstraint']) elif info['kind'] == 'Function': return "func_" + str(hash(name))[1:] else: outp += name.replace(".", "_") if 'getGenericParams' in info and info['getGenericParams']: gen_params = [ mangle_name(param) for param in info['getGenericParams'] ] outp += "__of__" + "__and__".join(gen_params) return outp def make_decl(name, offset, type_name): nonlocal decls, pad_count, parser, prev_end if isinstance(offset, str): assert offset[:2] == '0x' offset = int(offset, 16) if prev_end < offset: pad_str = f"char _padding{pad_count}[{offset - prev_end}];" decls.append(parser.parse(pad_str).ext[0]) pad_count += 1 type_decl = TypeDecl(name.replace(".", "__"), None, IdentifierType([mangle_name(type_name)])) decls.append(Decl(None, None, None, None, type_decl, None, None)) req_graph.setdefault(type_name, set()).add(parent_name) if offset != -1: size = pointer_size if type_name.endswith('*') else int( types[type_name]['size'], 16) prev_end = offset + size #print("#include <stdint.h>") print("#pragma pack(1)") print("typedef void *voidp;") print("typedef struct Metadata_s Metadata;") types = json.loads(message) req_graph = {} ptr_types = {'void*', 'voidp', 'Metadata*'} ctypes = {} for name, info in types.items(): pad_count = 0 decls = [] prev_end = 0 ctype = None parent_name = name if info['kind'] == "Tuple": for i, elem in enumerate(info['tupleElements']): make_decl(elem['label'] or f'_{i}', elem['offset'], elem['type']) ctype = Struct(mangle_name(name) + "_s", decls) elif info['kind'] == "ObjCClassWrapper": print( f'typedef struct {mangle_name(name)}_s *{mangle_name(name)};') elif info['kind'] in ("Struct", "Class"): if info['kind'] == 'Class': make_decl('_isa', '0x0', 'Metadata*') #make_decl('_refCounts', hex(pointer_size), 'size_t') for i, field in enumerate(info['fields']): make_decl(field['name'], field['offset'], field['type']) ctype = Struct(mangle_name(name) + "_s", decls) if info['kind'] == 'Class': ctype = PtrDecl(None, ctype) elif info['kind'] == "Existential": if info['isClassBounded'] or info.get( 'getSuperclassConstraint'): # class existential container make_decl(f'heap_object', -1, 'void*') else: # opaque existential container decls.append( parser.parse("void *heapObjectOrInlineData0;").ext[0]) for i in range(1, 3): decls.append( parser.parse( "void *nothingOrInlineData{};".format(i)).ext[0]) make_decl("dynamicType", -1, "Metadata*") for i in range(info['witnessTableCount']): make_decl(f'_witnessTable{i + 1}', -1, 'void*') ctype = Struct(mangle_name(name) + "_s", decls) elif info['kind'] in ("Enum", "Optional"): if info['enumCases'] and info['enumCases'][0]['name'] is None: # C-like enum # we don't have case names or values, so just generate a typedef to an int type print( f"typedef uint{int(info['size'], 16) * 8}_t {mangle_name(name)};" ) elif len(info['enumCases']) == 0: ctype = Struct(mangle_name(name) + "_s", decls) elif len(info['enumCases']) == 1 and info['enumCases'][0]['type']: make_decl(info['enumCases'][0]['name'], 0, info['enumCases'][0]['type']) ctype = Struct(mangle_name(name) + "_s", decls) else: print( f'typedef struct {mangle_name(name)}_s {{ char _data[{info["size"]}]; }} {mangle_name(name)};' ) elif info['kind'] == 'Opaque': if 'getCType' in info: ctype_names = { 'pointer': 'void*', 'int8': 'int8_t', 'int16': 'int16_t', 'int32': 'int32_t', 'int64': 'int64_t', 'int64': 'int64_t', } print( f'typedef {ctype_names[info["getCType"]]} {mangle_name(name)};' ) elif name == 'Builtin.NativeObject': print(f'typedef void *{mangle_name(name)};') else: print(f'typedef char {mangle_name(name)}[{info["size"]}];') elif info['kind'] == 'Function': print(f"typedef void *func_{str(hash(name))[1:]};" ) # TODO: proper names else: print(f'typedef char {mangle_name(name)}[{info["size"]}];') if ctype: type_decl = TypeDecl(mangle_name(name), None, ctype) ctypes[name] = type_decl type_decl_forward = Struct(mangle_name(name) + "_s", []) if isinstance(type_decl, PtrDecl): ptr_types.add(name) type_decl_forward = PtrDecl(None, type_decl_forward) print( generator.visit( Typedef(mangle_name(name), None, ['typedef'], type_decl_forward)) + ";") for name in ptr_types: req_graph.pop(name, None) for name in top_sort(req_graph): if name in ctypes: print(f"\n// {name}") print( generator.visit( Typedef(mangle_name(name), None, ['typedef'], ctypes[name])) + ";")
def __init__(self, ident: str, base_type: MyriadCType, ptr: bool = False, quals: list = None, storage: list = None, arr_id: str = None, init=None): """ Initializes a scalar variable, i.e. a base type, a pointer type, or an array type containing the base scalar type (variable/fixed length). :param str ident: Name of the scalar variable to be created. :param MyriadCType base_type: Underlying C AST base type (e.g. MInt). :param bool ptr: Indicates whether this is a pointer. :param list quals: C AST scope qualifiers (e.g. "static") :param list storage: C AST storage qualifiers (e.g. "const") :param str arr_id: Array length ID specifier (None if this isn't one) :param init: Initial value given to this scalar # TODO: NOT IMPLEMENTED """ # Always call super first super().__init__(ident, quals=quals, storage=storage) #: Represents the underlying C type via a MyriadCType subclass. self.base_type = base_type #: Indicates if this is a pointer (or an array of pointers). self.ptr = ptr #: Indicates whether this is actually an array of this scalar type self.arr_id = arr_id #: Underlying C AST type declaration, used for C generation. self.type_decl = TypeDecl(declname=self.ident, quals=self.quals, type=self.base_type.mtype) #: Optional pointer declaration, used for scalar pointers. self.ptr_decl = PtrDecl(quals=[], type=self.type_decl) #: Optional array declaration, used for scalar arrays self.arr_decl = None if self.arr_id is not None: # Array of scalars or array of pointers (first arg is base type) self.arr_decl = ArrayDecl(self.ptr_decl if ptr else self.type_decl, dim=ID(name=self.arr_id), dim_quals=[]) # TODO: Process init in some way #: Initial value of this scalar at the C level. self.init = init if init is not None: warn("Setting init is deprecated", DeprecationWarning) # Override superclass and re-initialize internal top-level declaration # Order of choosing declaration: # 1. If it's an array declaration (aka arr_id isn't None), use that # 2. Otherwise: # a) If ptr is true, use the ptr declaration # b) Otherwise, use the regular type declaration if self.arr_id is None: self.decl = Decl(name=self.ident, quals=self.quals, storage=self.storage, funcspec=[], type=self.ptr_decl if ptr else self.type_decl, init=self.init, bitsize=None) else: self.decl = Decl(name=self.ident, quals=self.quals, storage=self.storage, funcspec=[], type=self.arr_decl, init=None, bitsize=None)