Example #1
0
def generate_methods_table(cl: ClassIR, name: str, emitter: Emitter) -> None:
    emitter.emit_line('static PyMethodDef {}[] = {{'.format(name))
    for fn in cl.methods.values():
        if fn.decl.is_prop_setter or fn.decl.is_prop_getter:
            continue
        emitter.emit_line('{{"{}",'.format(fn.name))
        emitter.emit_line(' (PyCFunction){}{},'.format(PREFIX,
                                                       fn.cname(
                                                           emitter.names)))
        flags = ['METH_VARARGS', 'METH_KEYWORDS']
        if fn.decl.kind == FUNC_STATICMETHOD:
            flags.append('METH_STATIC')
        elif fn.decl.kind == FUNC_CLASSMETHOD:
            flags.append('METH_CLASS')

        emitter.emit_line(' {}, NULL}},'.format(' | '.join(flags)))

    # Provide a default __getstate__ and __setstate__
    if not cl.has_method('__setstate__') and not cl.has_method('__getstate__'):
        emitter.emit_lines(
            '{"__setstate__", (PyCFunction)CPyPickle_SetState, METH_O, NULL},',
            '{"__getstate__", (PyCFunction)CPyPickle_GetState, METH_NOARGS, NULL},',
        )

    emitter.emit_line('{NULL}  /* Sentinel */')
    emitter.emit_line('};')
Example #2
0
def generate_richcompare_wrapper(cl: ClassIR,
                                 emitter: Emitter) -> Optional[str]:
    """Generates a wrapper for richcompare dunder methods."""
    matches = [name for name in RICHCOMPARE_OPS if cl.has_method(name)]
    if not matches:
        return None

    name = '{}_RichCompare_{}'.format(DUNDER_PREFIX,
                                      cl.name_prefix(emitter.names))
    emitter.emit_line(
        'static PyObject *{name}(PyObject *obj_lhs, PyObject *obj_rhs, int op) {{'
        .format(name=name))
    emitter.emit_line('switch (op) {')
    for func in matches:
        emitter.emit_line('case {}: {{'.format(RICHCOMPARE_OPS[func]))
        method = cl.get_method(func)
        assert method is not None
        generate_wrapper_core(method, emitter, arg_names=['lhs', 'rhs'])
        emitter.emit_line('}')
    emitter.emit_line('}')

    emitter.emit_line('Py_INCREF(Py_NotImplemented);')
    emitter.emit_line('return Py_NotImplemented;')

    emitter.emit_line('}')

    return name
Example #3
0
def generate_getseter_declarations(cl: ClassIR, emitter: Emitter) -> None:
    if not cl.is_trait:
        for attr in cl.attributes:
            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('static int')
            emitter.emit_line(
                '{}({} *self, PyObject *value, void *closure);'.format(
                    setter_name(cl, attr, emitter.names),
                    cl.struct_name(emitter.names)))

    for prop in cl.properties:
        # Generate getter declaration
        emitter.emit_line('static PyObject *')
        emitter.emit_line('{}({} *self, void *closure);'.format(
            getter_name(cl, prop, emitter.names),
            cl.struct_name(emitter.names)))

        # Generate property setter declaration if a setter exists
        if cl.properties[prop][1]:
            emitter.emit_line('static int')
            emitter.emit_line(
                '{}({} *self, PyObject *value, void *closure);'.format(
                    setter_name(cl, prop, emitter.names),
                    cl.struct_name(emitter.names)))
Example #4
0
def generate_native_getters_and_setters(cl: ClassIR, emitter: Emitter) -> None:
    for attr, rtype in cl.attributes.items():
        # 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, '==')
            emitter.emit_lines(
                'PyErr_SetString(PyExc_AttributeError, "attribute {} of {} undefined");'
                .format(repr(attr), repr(cl.name)), '} else {')
            emitter.emit_inc_ref('self->{}'.format(attr), rtype)
            emitter.emit_line('}')
        emitter.emit_line('return self->{};'.format(attr))
        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, '!=')
            emitter.emit_dec_ref('self->{}'.format(attr), 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), 'return 1;', '}')
        emitter.emit_line()
Example #5
0
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(
                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('}')
Example #6
0
def specialize_parent_vtable(cls: ClassIR, parent: ClassIR) -> VTableEntries:
    """Generate the part of a vtable corresponding to a parent class or trait"""
    updated = []
    for entry in parent.vtable_entries:
        if isinstance(entry, VTableMethod):
            # Find the original method corresponding to this vtable entry.
            # (This may not be the method in the entry, if it was overridden.)
            orig_parent_method = entry.cls.get_method(entry.name)
            assert orig_parent_method
            method_cls = cls.get_method_and_class(entry.name)
            if method_cls:
                child_method, defining_cls = method_cls
                # TODO: emit a wrapper for __init__ that raises or something
                if (is_same_method_signature(orig_parent_method.sig,
                                             child_method.sig)
                        or orig_parent_method.name == '__init__'):
                    entry = VTableMethod(entry.cls, entry.name, child_method,
                                         entry.shadow_method)
                else:
                    entry = VTableMethod(
                        entry.cls, entry.name,
                        defining_cls.glue_methods[(entry.cls, entry.name)],
                        entry.shadow_method)
        else:
            # If it is an attribute from a trait, we need to find out
            # the real class it got mixed in at and point to that.
            if parent.is_trait:
                _, origin_cls = cls.attr_details(entry.name)
                entry = VTableAttr(origin_cls, entry.name, entry.is_setter)
        updated.append(entry)
    return updated
Example #7
0
    def setUp(self) -> None:
        self.env = Environment()
        self.n = self.env.add_local(Var('n'), int_rprimitive)
        self.m = self.env.add_local(Var('m'), int_rprimitive)
        self.k = self.env.add_local(Var('k'), int_rprimitive)
        self.l = self.env.add_local(Var('l'), list_rprimitive)  # noqa
        self.ll = self.env.add_local(Var('ll'), list_rprimitive)
        self.o = self.env.add_local(Var('o'), object_rprimitive)
        self.o2 = self.env.add_local(Var('o2'), object_rprimitive)
        self.d = self.env.add_local(Var('d'), dict_rprimitive)
        self.b = self.env.add_local(Var('b'), bool_rprimitive)
        self.t = self.env.add_local(Var('t'),
                                    RTuple([int_rprimitive, bool_rprimitive]))
        self.tt = self.env.add_local(
            Var('tt'),
            RTuple(
                [RTuple([int_rprimitive, bool_rprimitive]), bool_rprimitive]))
        ir = ClassIR('A', 'mod')
        ir.attributes = OrderedDict([('x', bool_rprimitive),
                                     ('y', int_rprimitive)])
        compute_vtable(ir)
        ir.mro = [ir]
        self.r = self.env.add_local(Var('r'), RInstance(ir))

        self.context = EmitterContext(NameGenerator([['mod']]))
        self.emitter = Emitter(self.context, self.env)
        self.declarations = Emitter(self.context, self.env)
        self.visitor = FunctionEmitterVisitor(self.emitter, self.declarations,
                                              'prog.py', 'prog')
Example #8
0
def declare_native_getters_and_setters(cl: ClassIR, emitter: Emitter) -> None:
    for attr, rtype in cl.attributes.items():
        emitter.emit_line('{}{}({} *self);'.format(
            emitter.ctype_spaced(rtype),
            native_getter_name(cl, attr, emitter.names),
            cl.struct_name(emitter.names)))
        emitter.emit_line('bool {}({} *self, {}value);'.format(
            native_setter_name(cl, attr, emitter.names),
            cl.struct_name(emitter.names), emitter.ctype_spaced(rtype)))
Example #9
0
def generate_getseter_declarations(cl: ClassIR, emitter: Emitter) -> None:
    for attr in cl.attributes:
        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('static int')
        emitter.emit_line('{}({} *self, PyObject *value, void *closure);'.format(
            setter_name(cl, attr, emitter.names),
            cl.struct_name(emitter.names)))
Example #10
0
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)
Example #11
0
def declare_native_getters_and_setters(cl: ClassIR, emitter: Emitter) -> None:
    decls = emitter.context.declarations
    for attr, rtype in cl.attributes.items():
        getter_name = native_getter_name(cl, attr, emitter.names)
        setter_name = native_setter_name(cl, attr, emitter.names)
        decls[getter_name] = HeaderDeclaration(
            '{}{}({} *self);'.format(emitter.ctype_spaced(rtype), getter_name,
                                     cl.struct_name(emitter.names)),
            needs_export=True,
        )
        decls[setter_name] = HeaderDeclaration(
            'bool {}({} *self, {}value);'.format(
                native_setter_name(cl, attr, emitter.names),
                cl.struct_name(emitter.names), emitter.ctype_spaced(rtype)),
            needs_export=True,
        )
Example #12
0
def generate_setter(cl: ClassIR, attr: str, rtype: RType,
                    emitter: Emitter) -> None:
    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, '!=')
        emitter.emit_dec_ref('self->{}'.format(attr), 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))
    emitter.emit_line('} else')
    emitter.emit_line('    self->{} = {};'.format(
        attr, emitter.c_undefined_value(rtype)))
    emitter.emit_line('return 0;')
    emitter.emit_line('}')
Example #13
0
def generate_slots(cl: ClassIR, table: SlotTable, emitter: Emitter) -> Dict[str, str]:
    fields = OrderedDict()  # type: Dict[str, str]
    for name, (slot, generator) in table.items():
        method = cl.get_method(name)
        if method:
            fields[slot] = generator(cl, method, emitter)

    return fields
Example #14
0
def generate_slots(cl: ClassIR, table: SlotTable, emitter: Emitter) -> Dict[str, str]:
    fields = OrderedDict()  # type: Dict[str, str]
    # Sort for determinism on Python 3.5
    for name, (slot, generator) in sorted(table.items()):
        method = cl.get_method(name)
        if method:
            fields[slot] = generator(cl, method, emitter)

    return fields
Example #15
0
def generate_slots(cl: ClassIR, table: SlotTable, emitter: Emitter) -> Dict[str, str]:
    fields = OrderedDict()  # type: Dict[str, str]
    # Sort for determinism on Python 3.5
    for name, (slot, generator) in sorted(table.items()):
        method_cls = cl.get_method_and_class(name)
        if method_cls and (method_cls[1] == cl or name in ALWAYS_FILL):
            fields[slot] = generator(cl, method_cls[0], emitter)

    return fields
Example #16
0
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),
                                                 attr))
    emitter.emit_line('}} {};'.format(cl.struct_name(emitter.names)))
Example #17
0
def generate_side_table_for_class(cl: ClassIR, name: str, type: str,
                                  slots: Dict[str, str],
                                  emitter: Emitter) -> Optional[str]:
    name = '{}_{}'.format(cl.name_prefix(emitter.names), name)
    emitter.emit_line('static {} {} = {{'.format(type, name))
    for field, value in slots.items():
        emitter.emit_line(".{} = {},".format(field, value))
    emitter.emit_line("};")
    return name
Example #18
0
def compute_vtable(cls: ClassIR) -> None:
    """Compute the vtable structure for a class."""
    if cls.vtable is not None: return

    if not cls.is_generated:
        cls.has_dict = any(x.inherits_python for x in cls.mro)

    for t in cls.mro[1:]:
        # Make sure all ancestors are processed first
        compute_vtable(t)
        # Merge attributes from traits into the class
        if not t.is_trait:
            continue
        for name, typ in t.attributes.items():
            if not cls.is_trait and not any(name in b.attributes
                                            for b in cls.base_mro):
                cls.attributes[name] = typ

    cls.vtable = {}
    if cls.base:
        assert cls.base.vtable is not None
        cls.vtable.update(cls.base.vtable)
        cls.vtable_entries = specialize_parent_vtable(cls, cls.base)

    # Include the vtable from the parent classes, but handle method overrides.
    entries = cls.vtable_entries

    # Traits need to have attributes in the vtable, since the
    # attributes can be at different places in different classes, but
    # regular classes can just directly get them.
    if cls.is_trait:
        # Traits also need to pull in vtable entries for non-trait
        # parent classes explicitly.
        for t in cls.mro:
            for attr in t.attributes:
                if attr in cls.vtable:
                    continue
                cls.vtable[attr] = len(entries)
                entries.append(VTableAttr(t, attr, is_setter=False))
                entries.append(VTableAttr(t, attr, is_setter=True))

    all_traits = [t for t in cls.mro if t.is_trait]

    for t in [cls] + cls.traits:
        for fn in itertools.chain(t.methods.values()):
            # TODO: don't generate a new entry when we overload without changing the type
            if fn == cls.get_method(fn.name):
                cls.vtable[fn.name] = len(entries)
                # If the class contains a glue method referring to itself, that is a
                # shadow glue method to support interpreted subclasses.
                shadow = cls.glue_methods.get((cls, fn.name))
                entries.append(VTableMethod(t, fn.name, fn, shadow))

    # Compute vtables for all of the traits that the class implements
    if not cls.is_trait:
        for trait in all_traits:
            compute_vtable(trait)
            cls.trait_vtables[trait] = specialize_parent_vtable(cls, trait)
Example #19
0
def generate_dealloc_for_class(cl: ClassIR, dealloc_func_name: str,
                               clear_func_name: str, emitter: Emitter) -> None:
    emitter.emit_line('static void')
    emitter.emit_line('{}({} *self)'.format(dealloc_func_name,
                                            cl.struct_name(emitter.names)))
    emitter.emit_line('{')
    emitter.emit_line('PyObject_GC_UnTrack(self);')
    emitter.emit_line('{}(self);'.format(clear_func_name))
    emitter.emit_line('Py_TYPE(self)->tp_free((PyObject *)self);')
    emitter.emit_line('}')
Example #20
0
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(attr), rtype)
    emitter.emit_line('return 0;')
    emitter.emit_line('}')
Example #21
0
def generate_setup_for_class(cl: ClassIR,
                             func_name: str,
                             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(attr, emitter.c_undefined_value(rtype)))
    emitter.emit_line('return (PyObject *)self;')
    emitter.emit_line('}')
Example #22
0
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('}')
Example #23
0
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(attr), rtype)
    emitter.emit_line('return 0;')
    emitter.emit_line('}')
Example #24
0
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)))
Example #25
0
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('}')
Example #26
0
def build_type_map(mapper: Mapper, modules: List[MypyFile], graph: Graph,
                   types: Dict[Expression, Type], options: CompilerOptions,
                   errors: Errors) -> None:
    # Collect all classes defined in everything we are compiling
    classes = []
    for module in modules:
        module_classes = [
            node for node in module.defs if isinstance(node, ClassDef)
        ]
        classes.extend([(module, cdef) for cdef in module_classes])

    # Collect all class mappings so that we can bind arbitrary class name
    # references even if there are import cycles.
    for module, cdef in classes:
        class_ir = ClassIR(cdef.name,
                           module.fullname,
                           is_trait(cdef),
                           is_abstract=cdef.info.is_abstract)
        class_ir.is_ext_class = is_extension_class(cdef)
        # If global optimizations are disabled, turn of tracking of class children
        if not options.global_opts:
            class_ir.children = None
        mapper.type_to_ir[cdef.info] = class_ir

    # Populate structural information in class IR for extension classes.
    for module, cdef in classes:
        with catch_errors(module.path, cdef.line):
            if mapper.type_to_ir[cdef.info].is_ext_class:
                prepare_class_def(module.path, module.fullname, cdef, errors,
                                  mapper)
            else:
                prepare_non_ext_class_def(module.path, module.fullname, cdef,
                                          errors, mapper)

    # Collect all the functions also. We collect from the symbol table
    # so that we can easily pick out the right copy of a function that
    # is conditionally defined.
    for module in modules:
        for func in get_module_func_defs(module):
            prepare_func_def(module.fullname, None, func, mapper)
Example #27
0
def generate_get_wrapper(cl: ClassIR, fn: FuncIR, emitter: Emitter) -> str:
    """Generates a wrapper for native __get__ methods."""
    name = '{}{}{}'.format(DUNDER_PREFIX, fn.name,
                           cl.name_prefix(emitter.names))
    emitter.emit_line(
        'static PyObject *{name}(PyObject *self, PyObject *instance, PyObject *owner) {{'
        .format(name=name))
    emitter.emit_line('instance = instance ? instance : Py_None;')
    emitter.emit_line('return {}{}(self, instance, owner);'.format(
        NATIVE_PREFIX, fn.cname(emitter.names)))
    emitter.emit_line('}')

    return name
Example #28
0
def generate_trait_vtable_setup(cl: ClassIR, vtable_setup_name: str,
                                vtable_name: str, emitter: Emitter) -> None:
    """Generate a native function that fixes up the trait vtables of a class.

    This needs to be called before a class is used.
    """
    emitter.emit_line('static bool')
    emitter.emit_line('{}{}(void)'.format(NATIVE_PREFIX, vtable_setup_name))
    emitter.emit_line('{')
    if cl.trait_vtables and not cl.is_trait:
        emitter.emit_lines('CPy_FixupTraitVtable({}_vtable, {});'.format(
            cl.name_prefix(emitter.names), len(cl.trait_vtables)))
    emitter.emit_line('return 1;')
    emitter.emit_line('}')
Example #29
0
def generate_native_getters_and_setters(cl: ClassIR,
                                        emitter: Emitter) -> None:
    for attr, rtype in cl.attributes.items():
        # 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:
            emitter.emit_lines(
                'if (self->{} == {}) {{'.format(attr, emitter.c_undefined_value(rtype)),
                'PyErr_SetString(PyExc_AttributeError, "attribute {} of {} undefined");'.format(
                    repr(attr), repr(cl.name)),
                '} else {')
            emitter.emit_inc_ref('self->{}'.format(attr), rtype)
            emitter.emit_line('}')
        emitter.emit_line('return self->{};'.format(attr))
        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:
            emitter.emit_line('if (self->{} != {}) {{'.format(attr,
                                                              emitter.c_undefined_value(rtype)))
            emitter.emit_dec_ref('self->{}'.format(attr), rtype)
            emitter.emit_line('}')
        emitter.emit_inc_ref('value'.format(attr), rtype)
        emitter.emit_lines('self->{} = value;'.format(attr),
                           'return 1;',
                           '}')
        emitter.emit_line()
Example #30
0
def generate_dunder_wrapper(cl: ClassIR, fn: FuncIR, emitter: Emitter) -> str:
    """Generates a wrapper for native __dunder__ methods to be able to fit into the mapping
    protocol slot. This specifically means that the arguments are taken as *PyObjects and returned
    as *PyObjects.
    """
    input_args = ', '.join('PyObject *obj_{}'.format(arg.name) for arg in fn.args)
    name = '{}{}{}'.format(DUNDER_PREFIX, fn.name, cl.name_prefix(emitter.names))
    emitter.emit_line('static PyObject *{name}({input_args}) {{'.format(
        name=name,
        input_args=input_args,
    ))
    generate_wrapper_core(fn, emitter)
    emitter.emit_line('}')

    return name