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: attr_expr = 'self->{}'.format(attr_field) emitter.emit_undefined_attr_check(rtype, attr_expr, '!=') 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_arg_check(name: str, typ: RType, emitter: Emitter, error_code: str, optional: bool = False) -> None: """Insert a runtime check for argument and unbox if necessary. The object is named PyObject *obj_{}. This is expected to generate a value of name arg_{} (unboxed if necessary). For each primitive a runtime check ensures the correct type. """ if typ.is_unboxed: # Borrow when unboxing to avoid reference count manipulation. emitter.emit_unbox('obj_{}'.format(name), 'arg_{}'.format(name), typ, error_code, declare_dest=True, borrow=True, optional=optional) elif is_object_rprimitive(typ): # Object is trivial since any object is valid if optional: emitter.emit_line('PyObject *arg_{};'.format(name)) emitter.emit_line('if (obj_{} == NULL) {{'.format(name)) emitter.emit_line('arg_{} = {};'.format(name, emitter.c_error_value(typ))) emitter.emit_lines('} else {', 'arg_{} = obj_{}; '.format(name, name), '}') else: emitter.emit_line('PyObject *arg_{} = obj_{};'.format(name, name)) else: emitter.emit_cast('obj_{}'.format(name), 'arg_{}'.format(name), typ, declare_dest=True, optional=optional) if optional: emitter.emit_line('if (obj_{} != NULL && arg_{} == NULL) {}'.format( name, name, error_code)) else: emitter.emit_line('if (arg_{} == NULL) {}'.format(name, error_code))
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('{') deletable = cl.is_deletable(attr) if not deletable: emitter.emit_line('if (value == NULL) {') emitter.emit_line('PyErr_SetString(PyExc_AttributeError,') emitter.emit_line(' "{} object attribute {} cannot be deleted");'.format(repr(cl.name), repr(attr))) emitter.emit_line('return -1;') emitter.emit_line('}') # HACK: Don't consider refcounted values as always defined, since it's possible to # access uninitialized values via 'gc.get_objects()'. Accessing non-refcounted # values is benign. always_defined = cl.is_always_defined(attr) and not rtype.is_refcounted if rtype.is_refcounted: attr_expr = f'self->{attr_field}' if not always_defined: emitter.emit_undefined_attr_check(rtype, attr_expr, '!=') emitter.emit_dec_ref('self->{}'.format(attr_field), rtype) if not always_defined: emitter.emit_line('}') if deletable: emitter.emit_line('if (value != NULL) {') if rtype.is_unboxed: emitter.emit_unbox('value', 'tmp', rtype, error=ReturnHandler('-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(f'self->{attr_field} = tmp;') if deletable: 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_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('{') deletable = cl.is_deletable(attr) if not deletable: emitter.emit_line('if (value == NULL) {') emitter.emit_line('PyErr_SetString(PyExc_AttributeError,') emitter.emit_line( ' "{} object attribute {} cannot be deleted");'.format( repr(cl.name), repr(attr))) emitter.emit_line('return -1;') emitter.emit_line('}') if rtype.is_refcounted: attr_expr = 'self->{}'.format(attr_field) emitter.emit_undefined_attr_check(rtype, attr_expr, '!=') emitter.emit_dec_ref('self->{}'.format(attr_field), rtype) emitter.emit_line('}') if deletable: emitter.emit_line('if (value != NULL) {') if rtype.is_unboxed: emitter.emit_unbox('value', 'tmp', rtype, error=ReturnHandler('-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)) if deletable: 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_arg_check(name: str, typ: RType, emitter: Emitter, error: Optional[ErrorHandler] = None, *, optional: bool = False, raise_exception: bool = True) -> None: """Insert a runtime check for argument and unbox if necessary. The object is named PyObject *obj_{}. This is expected to generate a value of name arg_{} (unboxed if necessary). For each primitive a runtime check ensures the correct type. """ error = error or AssignHandler() if typ.is_unboxed: # Borrow when unboxing to avoid reference count manipulation. emitter.emit_unbox(f'obj_{name}', f'arg_{name}', typ, declare_dest=True, raise_exception=raise_exception, error=error, borrow=True, optional=optional) elif is_object_rprimitive(typ): # Object is trivial since any object is valid if optional: emitter.emit_line(f'PyObject *arg_{name};') emitter.emit_line(f'if (obj_{name} == NULL) {{') emitter.emit_line(f'arg_{name} = {emitter.c_error_value(typ)};') emitter.emit_lines('} else {', f'arg_{name} = obj_{name}; ', '}') else: emitter.emit_line(f'PyObject *arg_{name} = obj_{name};') else: emitter.emit_cast(f'obj_{name}', f'arg_{name}', typ, declare_dest=True, raise_exception=raise_exception, error=error, optional=optional)