def generate_wrapper_core(fn: FuncIR, emitter: Emitter, optional_args: List[RuntimeArg] = [], arg_names: Optional[List[str]] = None) -> None: """Generates the core part of a wrapper function for a native function. This expects each argument as a PyObject * named obj_{arg} as a precondition. It converts the PyObject *s to the necessary types, checking and unboxing if necessary, makes the call, then boxes the result if necessary and returns it. """ arg_names = arg_names or [arg.name for arg in fn.args] for arg_name, arg in zip(arg_names, fn.args): generate_arg_check(arg_name, arg.type, emitter, arg in optional_args) native_args = ', '.join('arg_{}'.format(arg) for arg in arg_names) if fn.ret_type.is_unboxed: # TODO: The Py_RETURN macros return the correct PyObject * with reference count handling. # Are they relevant? emitter.emit_line('{}retval = {}{}({});'.format( emitter.ctype_spaced(fn.ret_type), NATIVE_PREFIX, fn.cname(emitter.names), native_args)) emitter.emit_error_check('retval', fn.ret_type, 'return NULL;') emitter.emit_box('retval', 'retbox', fn.ret_type, declare_dest=True) emitter.emit_line('return retbox;') else: emitter.emit_line('return {}{}({});'.format(NATIVE_PREFIX, fn.cname(emitter.names), native_args))
def generate_wrapper_core(fn: FuncIR, emitter: Emitter, optional_args: Optional[List[RuntimeArg]] = None, arg_names: Optional[List[str]] = None, cleanups: Optional[List[str]] = None, traceback_code: Optional[str] = None) -> None: """Generates the core part of a wrapper function for a native function. This expects each argument as a PyObject * named obj_{arg} as a precondition. It converts the PyObject *s to the necessary types, checking and unboxing if necessary, makes the call, then boxes the result if necessary and returns it. """ optional_args = optional_args or [] cleanups = cleanups or [] use_goto = bool(cleanups or traceback_code) error_code = 'return NULL;' if not use_goto else 'goto fail;' arg_names = arg_names or [arg.name for arg in fn.args] for arg_name, arg in zip(arg_names, fn.args): # Suppress the argument check for *args/**kwargs, since we know it must be right. typ = arg.type if arg.kind not in (ARG_STAR, ARG_STAR2) else object_rprimitive generate_arg_check(arg_name, typ, emitter, error_code, arg in optional_args) native_args = ', '.join('arg_{}'.format(arg) for arg in arg_names) if fn.ret_type.is_unboxed or use_goto: # TODO: The Py_RETURN macros return the correct PyObject * with reference count handling. # Are they relevant? emitter.emit_line('{}retval = {}{}({});'.format( emitter.ctype_spaced(fn.ret_type), NATIVE_PREFIX, fn.cname(emitter.names), native_args)) emitter.emit_lines(*cleanups) if fn.ret_type.is_unboxed: emitter.emit_error_check('retval', fn.ret_type, 'return NULL;') emitter.emit_box('retval', 'retbox', fn.ret_type, declare_dest=True) emitter.emit_line('return {};'.format( 'retbox' if fn.ret_type.is_unboxed else 'retval')) else: emitter.emit_line('return {}{}({});'.format(NATIVE_PREFIX, fn.cname(emitter.names), native_args)) # TODO: Tracebacks? if use_goto: emitter.emit_label('fail') emitter.emit_lines(*cleanups) if traceback_code: emitter.emit_lines(traceback_code) emitter.emit_lines('return NULL;')
def generate_function_declaration(fn: FuncIR, emitter: Emitter) -> None: emitter.context.declarations[emitter.native_function_name(fn.decl)] = HeaderDeclaration( '{};'.format(native_function_header(fn.decl, emitter)), needs_export=True) if fn.name != TOP_LEVEL_NAME: emitter.context.declarations[PREFIX + fn.cname(emitter.names)] = HeaderDeclaration( '{};'.format(wrapper_function_header(fn, emitter.names)))
def generate_readonly_getter(cl: ClassIR, attr: str, rtype: RType, func_ir: FuncIR, emitter: Emitter) -> None: emitter.emit_line('static PyObject *') emitter.emit_line('{}({} *self, void *closure)'.format( getter_name(cl, attr, emitter.names), cl.struct_name(emitter.names))) emitter.emit_line('{') if rtype.is_unboxed: emitter.emit_line('{}retval = {}{}((PyObject *) self);'.format( emitter.ctype_spaced(rtype), NATIVE_PREFIX, func_ir.cname(emitter.names))) emitter.emit_box('retval', 'retbox', rtype, declare_dest=True) emitter.emit_line('return retbox;') else: emitter.emit_line('return {}{}((PyObject *) self);'.format( NATIVE_PREFIX, func_ir.cname(emitter.names))) emitter.emit_line('}')
def generate_wrapper_function(fn: FuncIR, emitter: Emitter) -> None: """Generates a CPython-compatible wrapper function for a native function. In particular, this handles unboxing the arguments, calling the native function, and then boxing the return value. """ emitter.emit_line('{} {{'.format(wrapper_function_header(fn, emitter.names))) # If fn is a method, then the first argument is a self param real_args = list(fn.args) if fn.class_name: arg = real_args.pop(0) emitter.emit_line('PyObject *obj_{} = self;'.format(arg.name)) arg_names = ''.join('"{}", '.format(arg.name) for arg in real_args) emitter.emit_line('static char *kwlist[] = {{{}0}};'.format(arg_names)) for arg in real_args: emitter.emit_line('PyObject *obj_{};'.format(arg.name)) arg_spec = 'O' * len(real_args) arg_ptrs = ''.join(', &obj_{}'.format(arg.name) for arg in real_args) emitter.emit_lines( 'if (!PyArg_ParseTupleAndKeywords(args, kw, "{}:f", kwlist{})) {{'.format( arg_spec, arg_ptrs), 'return NULL;', '}') for arg in fn.args: generate_arg_check(arg.name, arg.type, emitter) native_args = ', '.join('arg_{}'.format(arg.name) for arg in fn.args) if fn.ret_type.is_unboxed: # TODO: The Py_RETURN macros return the correct PyObject * with reference count handling. # Are they relevant? ret_type = fn.ret_type emitter.emit_line('{}retval = {}{}({});'.format(emitter.ctype_spaced(ret_type), NATIVE_PREFIX, fn.cname(emitter.names), native_args)) emitter.emit_error_check('retval', ret_type, 'return NULL;') emitter.emit_box('retval', 'retbox', ret_type, declare_dest=True) emitter.emit_lines('return retbox;') else: emitter.emit_line('return {}{}({});'.format(NATIVE_PREFIX, fn.cname(emitter.names), native_args)) # TODO: Tracebacks? emitter.emit_line('}')
def generate_property_setter(cl: ClassIR, attr: str, arg_type: RType, func_ir: FuncIR, emitter: Emitter) -> None: emitter.emit_line('static int') emitter.emit_line('{}({} *self, PyObject *value, void *closure)'.format( setter_name(cl, attr, emitter.names), cl.struct_name(emitter.names))) emitter.emit_line('{') if arg_type.is_unboxed: emitter.emit_unbox('value', 'tmp', arg_type, custom_failure='return -1;', declare_dest=True) emitter.emit_line('{}{}((PyObject *) self, tmp);'.format( NATIVE_PREFIX, func_ir.cname(emitter.names))) else: emitter.emit_line('{}{}((PyObject *) self, value);'.format( NATIVE_PREFIX, func_ir.cname(emitter.names))) emitter.emit_line('return 0;') emitter.emit_line('}')
def insert_uninit_checks(ir: FuncIR) -> None: # Remove dead blocks from the CFG, which helps avoid spurious # checks due to unused error handling blocks. cleanup_cfg(ir.blocks) cfg = get_cfg(ir.blocks) args = set(reg for reg in ir.env.regs() if ir.env.indexes[reg] < len(ir.args)) must_defined = analyze_must_defined_regs(ir.blocks, cfg, args, ir.env.regs()) ir.blocks = split_blocks_at_uninits(ir.env, ir.blocks, must_defined.before)
def insert_exception_handling(ir: FuncIR) -> None: # Generate error block if any ops may raise an exception. If an op # fails without its own error handler, we'll branch to this # block. The block just returns an error value. error_label = None for block in ir.blocks: can_raise = any(op.can_raise() for op in block.ops) if can_raise: error_label = add_handler_block(ir) break if error_label: ir.blocks = split_blocks_at_errors(ir.blocks, error_label, ir.name)
def generate_get_wrapper(cl: ClassIR, fn: FuncIR, emitter: Emitter) -> str: """Generates a wrapper for native __get__ methods.""" name = '{}{}{}'.format(DUNDER_PREFIX, fn.name, cl.name_prefix(emitter.names)) emitter.emit_line( 'static PyObject *{name}(PyObject *self, PyObject *instance, PyObject *owner) {{' .format(name=name)) emitter.emit_line('instance = instance ? instance : Py_None;') emitter.emit_line('return {}{}(self, instance, owner);'.format( NATIVE_PREFIX, fn.cname(emitter.names))) emitter.emit_line('}') return name
def test_simple(self) -> None: self.block.ops.append(Return(self.reg)) fn = FuncIR('myfunc', [self.arg], IntRType(), [self.block], self.env) emitter = Emitter(EmitterContext()) generate_native_function(fn, emitter) result = emitter.fragments assert_string_arrays_equal([ 'static CPyTagged CPyDef_myfunc(CPyTagged cpy_r_arg) {\n', 'CPyL0: ;\n', ' return cpy_r_arg;\n', '}\n', ], result, msg='Generated code invalid')
def test_simple(self) -> None: self.block.ops.append(Return(self.reg)) fn = FuncIR('myfunc', None, 'mod', FuncSignature([self.arg], int_rprimitive), [self.block], self.env) emitter = Emitter(EmitterContext(['mod'])) generate_native_function(fn, emitter, 'prog.py', 'prog') result = emitter.fragments assert_string_arrays_equal( [ 'static CPyTagged CPyDef_myfunc(CPyTagged cpy_r_arg) {\n', 'CPyL0: ;\n', ' return cpy_r_arg;\n', '}\n', ], result, msg='Generated code invalid')
def test_register(self) -> None: self.temp = self.env.add_temp(IntRType()) self.block.ops.append(LoadInt(self.temp, 5)) fn = FuncIR('myfunc', [self.arg], ListRType(), [self.block], self.env) emitter = Emitter(EmitterContext()) generate_native_function(fn, emitter) result = emitter.fragments assert_string_arrays_equal([ 'static PyObject *CPyDef_myfunc(CPyTagged cpy_r_arg) {\n', ' CPyTagged cpy_r_r0;\n', 'CPyL0: ;\n', ' cpy_r_r0 = 10;\n', '}\n', ], result, msg='Generated code invalid')
def generate_init_for_class(cl: ClassIR, func_name: str, init_fn: FuncIR, emitter: Emitter) -> None: """Generate an init function suitable for use as tp_init. tp_init needs to be a function that returns an int, and our __init__ methods return a PyObject. Translate NULL to -1, everything else to 0. """ emitter.emit_line('static int') emitter.emit_line( '{}(PyObject *self, PyObject *args, PyObject *kwds)'.format(func_name)) emitter.emit_line('{') emitter.emit_line('return {}{}(self, args, kwds) != NULL ? 0 : -1;'.format( PREFIX, init_fn.cname(emitter.names))) emitter.emit_line('}')
def generate_bool_wrapper(cl: ClassIR, fn: FuncIR, emitter: Emitter) -> str: """Generates a wrapper for native __bool__ methods.""" name = '{}{}{}'.format(DUNDER_PREFIX, fn.name, cl.name_prefix(emitter.names)) emitter.emit_line('static int {name}(PyObject *self) {{'.format(name=name)) emitter.emit_line('{}val = {}{}(self);'.format( emitter.ctype_spaced(fn.ret_type), NATIVE_PREFIX, fn.cname(emitter.names))) emitter.emit_error_check('val', fn.ret_type, 'return -1;') # This wouldn't be that hard to fix but it seems unimportant and # getting error handling and unboxing right would be fiddly. (And # way easier to do in IR!) assert is_bool_rprimitive( fn.ret_type), "Only bool return supported for __bool__" emitter.emit_line('return val;') emitter.emit_line('}') return name
def visit_func_def(self, fdef: FuncDef) -> Register: self.enter() for arg in fdef.arguments: self.environment.add_local(arg.variable, self.type_to_rtype(arg.variable.type)) fdef.body.accept(self) ret_type = self.convert_return_type(fdef) if ret_type.name == 'None': self.add_implicit_return() else: self.add_implicit_unreachable() blocks, env = self.leave() args = self.convert_args(fdef) func = FuncIR(fdef.name(), args, ret_type, blocks, env) self.functions.append(func) return INVALID_REGISTER
def gen_glue_ne_method(self, cls: ClassIR, line: int) -> FuncIR: """Generate a __ne__ method from a __eq__ method. """ self.builder.enter() rt_args = (RuntimeArg("self", RInstance(cls)), RuntimeArg("rhs", object_rprimitive)) # The environment operates on Vars, so we make some up fake_vars = [(Var(arg.name), arg.type) for arg in rt_args] args = [ self.builder.read( self.builder.environment.add_local_reg( var, type, is_arg=True ), line ) for var, type in fake_vars ] # type: List[Value] self.builder.ret_types[-1] = object_rprimitive # If __eq__ returns NotImplemented, then __ne__ should also not_implemented_block, regular_block = BasicBlock(), BasicBlock() eqval = self.add(MethodCall(args[0], '__eq__', [args[1]], line)) not_implemented = self.primitive_op(not_implemented_op, [], line) self.add(Branch( self.builder.binary_op(eqval, not_implemented, 'is', line), not_implemented_block, regular_block, Branch.BOOL_EXPR)) self.builder.activate_block(regular_block) retval = self.builder.coerce( self.builder.unary_op(eqval, 'not', line), object_rprimitive, line ) self.add(Return(retval)) self.builder.activate_block(not_implemented_block) self.add(Return(not_implemented)) blocks, env, ret_type, _ = self.builder.leave() return FuncIR( FuncDecl('__ne__', cls.name, self.module_name, FuncSignature(rt_args, ret_type)), blocks, env)
def test_register(self) -> None: self.env.temp_index = 0 op = LoadInt(5) self.block.ops.append(op) self.env.add_op(op) fn = FuncIR('myfunc', None, 'mod', FuncSignature([self.arg], list_rprimitive), [self.block], self.env) emitter = Emitter(EmitterContext(['mod'])) generate_native_function(fn, emitter, 'prog.py', 'prog') result = emitter.fragments assert_string_arrays_equal( [ 'static PyObject *CPyDef_myfunc(CPyTagged cpy_r_arg) {\n', ' CPyTagged cpy_r_r0;\n', 'CPyL0: ;\n', ' cpy_r_r0 = 10;\n', '}\n', ], result, msg='Generated code invalid')
def generate_hash_wrapper(cl: ClassIR, fn: FuncIR, emitter: Emitter) -> str: """Generates a wrapper for native __hash__ methods.""" name = '{}{}{}'.format(DUNDER_PREFIX, fn.name, cl.name_prefix(emitter.names)) emitter.emit_line( 'static Py_ssize_t {name}(PyObject *self) {{'.format(name=name)) emitter.emit_line('{}retval = {}{}(self);'.format( emitter.ctype_spaced(fn.ret_type), NATIVE_PREFIX, fn.cname(emitter.names))) emitter.emit_error_check('retval', fn.ret_type, 'return -1;') if is_int_rprimitive(fn.ret_type): emitter.emit_line('Py_ssize_t val = CPyTagged_AsLongLong(retval);') else: emitter.emit_line('Py_ssize_t val = PyLong_AsLongLong(retval);') emitter.emit_line('if (PyErr_Occurred()) return -1;') # We can't return -1 from a hash function.. emitter.emit_line('if (val == -1) return -2;') emitter.emit_line('return val;') emitter.emit_line('}') return name
def generate_class(cl: ClassIR, module: str, emitter: Emitter) -> None: """Generate C code for a class. This is the main entry point to the module. """ name = cl.name fullname = '{}.{}'.format(module, name) new_name = '{}_new'.format(name) traverse_name = '{}_traverse'.format(name) clear_name = '{}_clear'.format(name) dealloc_name = '{}_dealloc'.format(name) getseters_name = '{}_getseters'.format(name) vtable_name = '{}_vtable'.format(name) def emit_line() -> None: emitter.emit_line() # Use dummy empty __init__ for now. # TODO: Use UserRType init = FuncIR(cl.name, [], ObjectRType(), [], Environment()) emitter.emit_line(native_function_header(init) + ';') emit_line() generate_object_struct(cl, emitter) emit_line() generate_new_for_class(cl, new_name, vtable_name, emitter) emit_line() generate_traverse_for_class(cl, traverse_name, emitter) emit_line() generate_clear_for_class(cl, clear_name, emitter) emit_line() generate_dealloc_for_class(cl, dealloc_name, clear_name, emitter) emit_line() generate_native_getters_and_setters(cl, emitter) generate_vtable(cl, vtable_name, emitter) emit_line() generate_getseter_declarations(cl, emitter) emit_line() generate_getseters_table(cl, getseters_name, emitter) emit_line() emitter.emit_line(textwrap.dedent("""\ static PyTypeObject {type_struct} = {{ PyVarObject_HEAD_INIT(NULL, 0) "{fullname}", /* tp_name */ sizeof({struct_name}), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor){dealloc_name}, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 0, /* tp_doc */ (traverseproc){traverse_name}, /* tp_traverse */ (inquiry){clear_name}, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ 0, /* tp_methods */ 0, /* tp_members */ {getseters_name}, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ {new_name}, /* tp_new */ }};\ """).format(type_struct=type_struct_name(cl.name), struct_name=cl.struct_name, fullname=fullname, traverse_name=traverse_name, clear_name=clear_name, dealloc_name=dealloc_name, new_name=new_name, getseters_name=getseters_name)) emitter.emit_line() generate_constructor_for_class(cl, new_name, vtable_name, emitter) emitter.emit_line() generate_getseters(cl, emitter)
def wrapper_slot(cl: ClassIR, fn: FuncIR, emitter: Emitter) -> str: return '{}{}'.format(PREFIX, fn.cname(emitter.names))
def native_slot(cl: ClassIR, fn: FuncIR, emitter: Emitter) -> str: return '{}{}'.format(NATIVE_PREFIX, fn.cname(emitter.names))
def wrapper_function_header(fn: FuncIR, names: NameGenerator) -> str: return 'static PyObject *{prefix}{name}(PyObject *self, PyObject *args, PyObject *kw)'.format( prefix=PREFIX, name=fn.cname(names))
def generate_attr_defaults(self, cdef: ClassDef) -> None: """Generate an initialization method for default attr values (from class vars)""" cls = self.mapper.type_to_ir[cdef.info] if cls.builtin_base: return # Pull out all assignments in classes in the mro so we can initialize them # TODO: Support nested statements default_assignments = [] for info in reversed(cdef.info.mro): if info not in self.mapper.type_to_ir: continue for stmt in info.defn.defs.body: if (isinstance(stmt, AssignmentStmt) and isinstance(stmt.lvalues[0], NameExpr) and not is_class_var(stmt.lvalues[0]) and not isinstance(stmt.rvalue, TempNode)): if stmt.lvalues[0].name == '__slots__': continue # Skip type annotated assignments in dataclasses if is_dataclass(cdef) and stmt.type: continue default_assignments.append(stmt) if not default_assignments: return self.builder.enter() self.builder.ret_types[-1] = bool_rprimitive rt_args = (RuntimeArg(SELF_NAME, RInstance(cls)),) self_var = self.builder.read(add_self_to_env(self.builder.environment, cls), -1) for stmt in default_assignments: lvalue = stmt.lvalues[0] assert isinstance(lvalue, NameExpr) if not stmt.is_final_def and not is_constant(stmt.rvalue): self.builder.warning('Unsupported default attribute value', stmt.rvalue.line) # If the attribute is initialized to None and type isn't optional, # don't initialize it to anything. attr_type = cls.attr_type(lvalue.name) if isinstance(stmt.rvalue, RefExpr) and stmt.rvalue.fullname == 'builtins.None': if (not is_optional_type(attr_type) and not is_object_rprimitive(attr_type) and not is_none_rprimitive(attr_type)): continue val = self.builder.coerce(self.accept(stmt.rvalue), attr_type, stmt.line) self.add(SetAttr(self_var, lvalue.name, val, -1)) self.add(Return(self.primitive_op(true_op, [], -1))) blocks, env, ret_type, _ = self.builder.leave() ir = FuncIR( FuncDecl('__mypyc_defaults_setup', cls.name, self.module_name, FuncSignature(rt_args, ret_type)), blocks, env) self.builder.functions.append(ir) cls.methods[ir.name] = ir
def native_function_name(self, fn: FuncIR) -> str: return '{}{}'.format(NATIVE_PREFIX, fn.cname(self.names))
def generate_class(cl: ClassIR, module: str, emitter: Emitter) -> None: """Generate C code for a class. This is the main entry point to the module. """ name = cl.name name_prefix = cl.name_prefix(emitter.names) fullname = '{}.{}'.format(module, name) setup_name = new_name = clear_name = dealloc_name = '0' traverse_name = getseters_name = vtable_name = '0' if not cl.is_trait: setup_name = '{}_setup'.format(name_prefix) new_name = '{}_new'.format(name_prefix) traverse_name = '{}_traverse'.format(name_prefix) clear_name = '{}_clear'.format(name_prefix) dealloc_name = '{}_dealloc'.format(name_prefix) getseters_name = '{}_getseters'.format(name_prefix) vtable_name = '{}_vtable'.format(name_prefix) methods_name = '{}_methods'.format(name_prefix) base_arg = "&{}".format( emitter.type_struct_name(cl.base)) if cl.base and not cl.traits else "0" def emit_line() -> None: emitter.emit_line() emit_line() generate_object_struct(cl, emitter) emit_line() # If there is a __init__ method, generate a function for tp_init and # extract the args (which we'll use for the native constructor) init_fn = cl.get_method('__init__') if init_fn: init_name = '{}_init'.format(name_prefix) init_args = init_fn.args[1:] generate_init_for_class(cl, init_name, init_fn, emitter) else: init_name = '0' init_args = [] call_fn = cl.get_method('__call__') call_name = '{}{}'.format(PREFIX, call_fn.cname(emitter.names)) if call_fn else '0' if not cl.is_trait: emitter.emit_line('static PyObject *{}(void);'.format(setup_name)) # TODO: Use RInstance ctor = FuncIR(cl.name, None, module, FuncSignature(init_args, object_rprimitive), [], Environment()) emitter.emit_line(native_function_header(ctor, emitter) + ';') emit_line() generate_new_for_class(cl, new_name, vtable_name, setup_name, emitter) emit_line() generate_traverse_for_class(cl, traverse_name, emitter) emit_line() generate_clear_for_class(cl, clear_name, emitter) emit_line() generate_dealloc_for_class(cl, dealloc_name, clear_name, emitter) emit_line() generate_native_getters_and_setters(cl, emitter) vtable_name = generate_vtables(cl, vtable_name, emitter) emit_line() generate_getseter_declarations(cl, emitter) emit_line() generate_getseters_table(cl, getseters_name, emitter) emit_line() generate_methods_table(cl, methods_name, emitter) emit_line() emitter.emit_line(textwrap.dedent("""\ static PyTypeObject {type_struct} = {{ PyVarObject_HEAD_INIT(NULL, 0) "{fullname}", /* tp_name */ sizeof({struct_name}), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor){dealloc_name}, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ {tp_call}, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 0, /* tp_doc */ (traverseproc){traverse_name}, /* tp_traverse */ (inquiry){clear_name}, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ {methods_name}, /* tp_methods */ 0, /* tp_members */ {getseters_name}, /* tp_getset */ {base_arg}, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ {init_name}, /* tp_init */ 0, /* tp_alloc */ {new_name}, /* tp_new */ }};\ """).format(type_struct=emitter.type_struct_name(cl), struct_name=cl.struct_name(emitter.names), fullname=fullname, traverse_name=traverse_name, clear_name=clear_name, dealloc_name=dealloc_name, tp_call=call_name, new_name=new_name, methods_name=methods_name, getseters_name=getseters_name, init_name=init_name, base_arg=base_arg, )) emitter.emit_line() if not cl.is_trait: generate_setup_for_class(cl, setup_name, vtable_name, emitter) emitter.emit_line() generate_constructor_for_class(cl, ctor, init_fn, setup_name, vtable_name, emitter) emitter.emit_line() generate_getseters(cl, emitter)