Ejemplo n.º 1
0
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('{')
    attr_expr = f'self->{attr_field}'

    # 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 not always_defined:
        emitter.emit_undefined_attr_check(rtype, attr_expr, '==', unlikely=True)
        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(f'self->{attr_field}', rtype)
    emitter.emit_box(f'self->{attr_field}', 'retval', rtype, declare_dest=True)
    emitter.emit_line('return retval;')
    emitter.emit_line('}')
Ejemplo n.º 2
0
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('}')