def generate_vtable(entries: VTableEntries, vtable_name: str, emitter: Emitter,
                    subtables: List[Tuple[ClassIR,
                                          str]], shadow: bool) -> None:
    emitter.emit_line('CPyVTableItem {}_scratch[] = {{'.format(vtable_name))
    if subtables:
        emitter.emit_line('/* Array of trait vtables */')
        for trait, table in subtables:
            emitter.emit_line('(CPyVTableItem){}, (CPyVTableItem){},'.format(
                emitter.type_struct_name(trait), table))
        emitter.emit_line('/* Start of real vtable */')

    for entry in entries:
        if isinstance(entry, VTableMethod):
            method = entry.shadow_method if shadow and entry.shadow_method else entry.method
            emitter.emit_line('(CPyVTableItem){}{}{},'.format(
                emitter.get_group_prefix(entry.method.decl), NATIVE_PREFIX,
                method.cname(emitter.names)))
        else:
            cl, attr, is_setter = entry
            namer = native_setter_name if is_setter else native_getter_name
            emitter.emit_line('(CPyVTableItem){}{},'.format(
                emitter.get_group_prefix(cl), namer(cl, attr, emitter.names)))
    # msvc doesn't allow empty arrays; maybe allowing them at all is an extension?
    if not entries:
        emitter.emit_line('NULL')
    emitter.emit_line('};')
    emitter.emit_line('memcpy({name}, {name}_scratch, sizeof({name}));'.format(
        name=vtable_name))
Beispiel #2
0
def generate_constructor_for_class(cl: ClassIR, fn: FuncDecl,
                                   init_fn: Optional[FuncIR], setup_name: str,
                                   vtable_name: str, emitter: Emitter) -> None:
    """Generate a native function that allocates and initializes an instance of a class."""
    emitter.emit_line('{}'.format(native_function_header(fn, emitter)))
    emitter.emit_line('{')
    emitter.emit_line('PyObject *self = {}({});'.format(
        setup_name, emitter.type_struct_name(cl)))
    emitter.emit_line('if (self == NULL)')
    emitter.emit_line('    return NULL;')
    args = ', '.join(['self'] + [REG_PREFIX + arg.name for arg in fn.sig.args])
    if init_fn is not None:
        emitter.emit_line('char res = {}{}{}({});'.format(
            emitter.get_group_prefix(init_fn.decl), NATIVE_PREFIX,
            init_fn.cname(emitter.names), args))
        emitter.emit_line('if (res == 2) {')
        emitter.emit_line('Py_DECREF(self);')
        emitter.emit_line('return NULL;')
        emitter.emit_line('}')

    # If there is a nontrivial ctor that we didn't define, invoke it via tp_init
    elif len(fn.sig.args) > 1:
        emitter.emit_line('int res = {}->tp_init({});'.format(
            emitter.type_struct_name(cl), args))

        emitter.emit_line('if (res < 0) {')
        emitter.emit_line('Py_DECREF(self);')
        emitter.emit_line('return NULL;')
        emitter.emit_line('}')

    emitter.emit_line('return self;')
    emitter.emit_line('}')
def generate_len_wrapper(cl: ClassIR, fn: FuncIR, emitter: Emitter) -> str:
    """Generates a wrapper for native __len__ 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), emitter.get_group_prefix(fn.decl),
        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_AsSsize_t(retval);')
    else:
        emitter.emit_line('Py_ssize_t val = PyLong_AsSsize_t(retval);')
    emitter.emit_dec_ref('retval', fn.ret_type)
    emitter.emit_line('if (PyErr_Occurred()) return -1;')
    emitter.emit_line('return val;')
    emitter.emit_line('}')

    return name