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))
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_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), 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;') # 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