示例#1
0
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))
示例#2
0
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;')
示例#3
0
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)))
示例#4
0
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('}')
示例#5
0
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('}')
示例#6
0
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('}')
示例#7
0
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)
示例#8
0
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)
示例#9
0
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
示例#10
0
 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')
示例#11
0
 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')
示例#12
0
 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')
示例#13
0
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('}')
示例#14
0
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
示例#15
0
    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
示例#16
0
    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)
示例#17
0
 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')
示例#18
0
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
示例#19
0
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)
示例#20
0
def wrapper_slot(cl: ClassIR, fn: FuncIR, emitter: Emitter) -> str:
    return '{}{}'.format(PREFIX, fn.cname(emitter.names))
示例#21
0
def native_slot(cl: ClassIR, fn: FuncIR, emitter: Emitter) -> str:
    return '{}{}'.format(NATIVE_PREFIX, fn.cname(emitter.names))
示例#22
0
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))
示例#23
0
    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
示例#24
0
文件: emit.py 项目: kxing/mypyc
 def native_function_name(self, fn: FuncIR) -> str:
     return '{}{}'.format(NATIVE_PREFIX, fn.cname(self.names))
示例#25
0
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)