def generate_native_getters_and_setters(cl: ClassIR, emitter: Emitter) -> None: for attr, rtype in cl.attributes.items(): attr_field = emitter.attr(attr) # Native getter emitter.emit_line('{}{}({} *self)'.format( emitter.ctype_spaced(rtype), native_getter_name(cl, attr, emitter.names), cl.struct_name(emitter.names))) emitter.emit_line('{') if rtype.is_refcounted: emit_undefined_check(rtype, emitter, attr_field, '==') emitter.emit_lines( 'PyErr_SetString(PyExc_AttributeError, "attribute {} of {} undefined");' .format(repr(attr), repr(cl.name)), '} else {') emitter.emit_inc_ref('self->{}'.format(attr_field), rtype) emitter.emit_line('}') emitter.emit_line('return self->{};'.format(attr_field)) emitter.emit_line('}') emitter.emit_line() # Native setter emitter.emit_line('bool {}({} *self, {}value)'.format( native_setter_name(cl, attr, emitter.names), cl.struct_name(emitter.names), emitter.ctype_spaced(rtype))) emitter.emit_line('{') if rtype.is_refcounted: emit_undefined_check(rtype, emitter, attr_field, '!=') emitter.emit_dec_ref('self->{}'.format(attr_field), rtype) emitter.emit_line('}') # This steal the reference to src, so we don't need to increment the arg emitter.emit_lines('self->{} = value;'.format(attr_field), 'return 1;', '}') emitter.emit_line()
def generate_setter(cl: ClassIR, attr: str, rtype: RType, emitter: Emitter) -> None: attr_field = emitter.attr(attr) 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 rtype.is_refcounted: emit_undefined_check(rtype, emitter, attr_field, '!=') emitter.emit_dec_ref('self->{}'.format(attr_field), rtype) emitter.emit_line('}') emitter.emit_line('if (value != NULL) {') if rtype.is_unboxed: emitter.emit_unbox('value', 'tmp', rtype, custom_failure='return -1;', declare_dest=True) elif is_same_type(rtype, object_rprimitive): emitter.emit_line('PyObject *tmp = value;') else: emitter.emit_cast('value', 'tmp', rtype, declare_dest=True) emitter.emit_lines('if (!tmp)', ' return -1;') emitter.emit_inc_ref('tmp', rtype) emitter.emit_line('self->{} = tmp;'.format(attr_field)) emitter.emit_line('} else') emitter.emit_line(' self->{} = {};'.format( attr_field, emitter.c_undefined_value(rtype))) emitter.emit_line('return 0;') emitter.emit_line('}')
def generate_setup_for_class(cl: ClassIR, func_name: str, defaults_fn: Optional[FuncIR], vtable_name: str, emitter: Emitter) -> None: """Generate a native function that allocates an instance of a class.""" emitter.emit_line('static PyObject *') emitter.emit_line('{}(void)'.format(func_name)) emitter.emit_line('{') emitter.emit_line('{} *self;'.format(cl.struct_name(emitter.names))) emitter.emit_line('self = ({struct} *){type_struct}->tp_alloc({type_struct}, 0);'.format( struct=cl.struct_name(emitter.names), type_struct=emitter.type_struct_name(cl))) emitter.emit_line('if (self == NULL)') emitter.emit_line(' return NULL;') emitter.emit_line('self->vtable = {};'.format(vtable_name)) for base in reversed(cl.base_mro): for attr, rtype in base.attributes.items(): emitter.emit_line('self->{} = {};'.format( emitter.attr(attr), emitter.c_undefined_value(rtype))) # Initialize attributes to default values, if necessary if defaults_fn is not None: emitter.emit_lines( 'if ({}{}((PyObject *)self) == 0) {{'.format( NATIVE_PREFIX, defaults_fn.cname(emitter.names)), 'Py_DECREF(self);', 'return NULL;', '}') emitter.emit_line('return (PyObject *)self;') emitter.emit_line('}')
def generate_object_struct(cl: ClassIR, emitter: Emitter) -> None: emitter.emit_lines('typedef struct {', 'PyObject_HEAD', 'CPyVTableItem *vtable;') for base in reversed(cl.base_mro): if not base.is_trait: for attr, rtype in base.attributes.items(): emitter.emit_line('{}{};'.format(emitter.ctype_spaced(rtype), emitter.attr(attr))) emitter.emit_line('}} {};'.format(cl.struct_name(emitter.names)))
def generate_clear_for_class(cl: ClassIR, func_name: str, emitter: Emitter) -> None: emitter.emit_line('static int') emitter.emit_line('{}({} *self)'.format(func_name, cl.struct_name(emitter.names))) emitter.emit_line('{') for base in reversed(cl.base_mro): for attr, rtype in base.attributes.items(): emitter.emit_gc_clear('self->{}'.format(emitter.attr(attr)), rtype) emitter.emit_line('return 0;') emitter.emit_line('}')
def generate_object_struct(cl: ClassIR, emitter: Emitter) -> None: emitter.emit_lines('typedef struct {', 'PyObject_HEAD', 'CPyVTableItem *vtable;') seen_attrs = set() # type: Set[Tuple[str, RType]] for base in reversed(cl.base_mro): if not base.is_trait: for attr, rtype in base.attributes.items(): if (attr, rtype) not in seen_attrs: emitter.emit_line('{}{};'.format( emitter.ctype_spaced(rtype), emitter.attr(attr))) seen_attrs.add((attr, rtype)) emitter.emit_line('}} {};'.format(cl.struct_name(emitter.names)))
def generate_traverse_for_class(cl: ClassIR, func_name: str, emitter: Emitter) -> None: """Emit function that performs cycle GC traversal of an instance.""" emitter.emit_line('static int') emitter.emit_line('{}({} *self, visitproc visit, void *arg)'.format( func_name, cl.struct_name(emitter.names))) emitter.emit_line('{') for base in reversed(cl.base_mro): for attr, rtype in base.attributes.items(): emitter.emit_gc_visit('self->{}'.format(emitter.attr(attr)), rtype) emitter.emit_line('return 0;') emitter.emit_line('}')
def generate_object_struct(cl: ClassIR, emitter: Emitter) -> None: seen_attrs = set() # type: Set[Tuple[str, RType]] lines = [] # type: List[str] lines += ['typedef struct {', 'PyObject_HEAD', 'CPyVTableItem *vtable;'] for base in reversed(cl.base_mro): if not base.is_trait: for attr, rtype in base.attributes.items(): if (attr, rtype) not in seen_attrs: lines.append('{}{};'.format(emitter.ctype_spaced(rtype), emitter.attr(attr))) seen_attrs.add((attr, rtype)) lines.append('}} {};'.format(cl.struct_name(emitter.names))) lines.append('') emitter.context.declarations[cl.struct_name( emitter.names)] = HeaderDeclaration(lines, is_type=True)
def generate_getter(cl: ClassIR, attr: str, rtype: RType, emitter: Emitter) -> None: attr_field = emitter.attr(attr) 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('{') emit_undefined_check(rtype, emitter, attr_field, '==') emitter.emit_line('PyErr_SetString(PyExc_AttributeError,') emitter.emit_line(' "attribute {} of {} undefined");'.format(repr(attr), repr(cl.name))) emitter.emit_line('return NULL;') emitter.emit_line('}') emitter.emit_inc_ref('self->{}'.format(attr_field), rtype) emitter.emit_box('self->{}'.format(attr_field), 'retval', rtype, declare_dest=True) emitter.emit_line('return retval;') emitter.emit_line('}')
def generate_clear_for_class(cl: ClassIR, func_name: str, emitter: Emitter) -> None: emitter.emit_line('static int') emitter.emit_line('{}({} *self)'.format(func_name, cl.struct_name(emitter.names))) emitter.emit_line('{') for base in reversed(cl.base_mro): for attr, rtype in base.attributes.items(): emitter.emit_gc_clear('self->{}'.format(emitter.attr(attr)), rtype) if cl.has_dict: struct_name = cl.struct_name(emitter.names) # __dict__ lives right after the struct and __weakref__ lives right after that emitter.emit_gc_clear( '*((PyObject **)((char *)self + sizeof({})))'.format(struct_name), object_rprimitive) emitter.emit_gc_clear( '*((PyObject **)((char *)self + sizeof(PyObject *) + sizeof({})))'. format(struct_name), object_rprimitive) emitter.emit_line('return 0;') emitter.emit_line('}')
def generate_traverse_for_class(cl: ClassIR, func_name: str, emitter: Emitter) -> None: """Emit function that performs cycle GC traversal of an instance.""" emitter.emit_line('static int') emitter.emit_line('{}({} *self, visitproc visit, void *arg)'.format( func_name, cl.struct_name(emitter.names))) emitter.emit_line('{') for base in reversed(cl.base_mro): for attr, rtype in base.attributes.items(): emitter.emit_gc_visit('self->{}'.format(emitter.attr(attr)), rtype) if cl.has_dict: struct_name = cl.struct_name(emitter.names) # __dict__ lives right after the struct and __weakref__ lives right after that emitter.emit_gc_visit( '*((PyObject **)((char *)self + sizeof({})))'.format(struct_name), object_rprimitive) emitter.emit_gc_visit( '*((PyObject **)((char *)self + sizeof(PyObject *) + sizeof({})))'. format(struct_name), object_rprimitive) emitter.emit_line('return 0;') emitter.emit_line('}')