Esempio n. 1
0
def instantiate_callable_class(builder: IRBuilder, fn_info: FuncInfo) -> Value:
    """Create an instance of a callable class for a function.

    Calls to the function will actually call this instance.

    Note that fn_info refers to the function being assigned, whereas
    builder.fn_info refers to the function encapsulating the function
    being turned into a callable class.
    """
    fitem = fn_info.fitem
    func_reg = builder.add(Call(fn_info.callable_class.ir.ctor, [], fitem.line))

    # Set the environment attribute of the callable class to point at
    # the environment class defined in the callable class' immediate
    # outer scope. Note that there are three possible environment
    # class registers we may use. This depends on what the encapsulating
    # (parent) function is:
    #
    # - A nested function: the callable class is instantiated
    #   from the current callable class' '__call__' function, and hence
    #   the callable class' environment register is used.
    # - A generator function: the callable class is instantiated
    #   from the '__next__' method of the generator class, and hence the
    #   environment of the generator class is used.
    # - Regular function: we use the environment of the original function.
    curr_env_reg = None
    if builder.fn_info.is_generator:
        curr_env_reg = builder.fn_info.generator_class.curr_env_reg
    elif builder.fn_info.is_nested:
        curr_env_reg = builder.fn_info.callable_class.curr_env_reg
    elif builder.fn_info.contains_nested:
        curr_env_reg = builder.fn_info.curr_env_reg
    if curr_env_reg:
        builder.add(SetAttr(func_reg, ENV_ATTR_NAME, curr_env_reg, fitem.line))
    return func_reg
Esempio n. 2
0
 def call(self, decl: FuncDecl, args: Sequence[Value], arg_kinds: List[int],
          arg_names: Sequence[Optional[str]], line: int) -> Value:
     """Call a native function."""
     # Normalize args to positionals.
     args = self.native_args_to_positional(args, arg_kinds, arg_names,
                                           decl.sig, line)
     return self.add(Call(decl, args, line))
Esempio n. 3
0
 def test_call_two_args(self) -> None:
     decl = FuncDecl('myfn', None, 'mod',
                     FuncSignature([RuntimeArg('m', int_rprimitive),
                                    RuntimeArg('n', int_rprimitive)],
                                   int_rprimitive))
     self.assert_emit(Call(decl, [self.m, self.k], 55),
                      "cpy_r_r0 = CPyDef_myfn(cpy_r_m, cpy_r_k);")
Esempio n. 4
0
def add_throw_to_generator_class(builder: IRBuilder, fn_info: FuncInfo,
                                 fn_decl: FuncDecl,
                                 sig: FuncSignature) -> None:
    """Generates the 'throw' method for a generator class."""
    with builder.enter_method(fn_info.generator_class.ir, 'throw',
                              object_rprimitive, fn_info):
        typ = builder.add_argument('type', object_rprimitive)
        val = builder.add_argument('value', object_rprimitive, ARG_OPT)
        tb = builder.add_argument('traceback', object_rprimitive, ARG_OPT)

        # Because the value and traceback arguments are optional and hence
        # can be NULL if not passed in, we have to assign them Py_None if
        # they are not passed in.
        none_reg = builder.none_object()
        builder.assign_if_null(val, lambda: none_reg,
                               builder.fn_info.fitem.line)
        builder.assign_if_null(tb, lambda: none_reg,
                               builder.fn_info.fitem.line)

        # Call the helper function using the arguments passed in, and return that result.
        result = builder.add(
            Call(fn_decl, [
                builder.self(),
                builder.read(typ),
                builder.read(val),
                builder.read(tb), none_reg
            ], fn_info.fitem.line))
        builder.add(Return(result))
Esempio n. 5
0
def add_next_to_generator_class(builder: IRBuilder, fn_info: FuncInfo,
                                fn_decl: FuncDecl, sig: FuncSignature) -> None:
    """Generates the '__next__' method for a generator class."""
    builder.enter_method(fn_info.generator_class.ir, '__next__',
                         object_rprimitive, fn_info)
    none_reg = builder.none_object()
    # Call the helper function with error flags set to Py_None, and return that result.
    result = builder.add(
        Call(fn_decl, [builder.self(), none_reg, none_reg, none_reg, none_reg],
             fn_info.fitem.line))
    builder.add(Return(result))
    builder.leave_method()
Esempio n. 6
0
def add_send_to_generator_class(builder: IRBuilder, fn_info: FuncInfo,
                                fn_decl: FuncDecl, sig: FuncSignature) -> None:
    """Generates the 'send' method for a generator class."""
    with builder.enter_method(fn_info.generator_class.ir, 'send',
                              object_rprimitive, fn_info):
        arg = builder.add_argument('arg', object_rprimitive)
        none_reg = builder.none_object()
        # Call the helper function with error flags set to Py_None, and return that result.
        result = builder.add(
            Call(fn_decl, [
                builder.self(), none_reg, none_reg, none_reg,
                builder.read(arg)
            ], fn_info.fitem.line))
        builder.add(Return(result))
Esempio n. 7
0
def instantiate_env_class(builder: IRBuilder) -> Value:
    """Assign an environment class to a register named after the given function definition."""
    curr_env_reg = builder.add(
        Call(builder.fn_info.env_class.ctor, [], builder.fn_info.fitem.line))

    if builder.fn_info.is_nested:
        builder.fn_info.callable_class._curr_env_reg = curr_env_reg
        builder.add(
            SetAttr(curr_env_reg, ENV_ATTR_NAME,
                    builder.fn_info.callable_class.prev_env_reg,
                    builder.fn_info.fitem.line))
    else:
        builder.fn_info._curr_env_reg = curr_env_reg

    return curr_env_reg
Esempio n. 8
0
def add_throw_to_generator_class(builder: IRBuilder, fn_info: FuncInfo,
                                 fn_decl: FuncDecl,
                                 sig: FuncSignature) -> None:
    """Generates the 'throw' method for a generator class."""
    builder.enter(fn_info)
    self_reg = builder.read(
        add_self_to_env(builder.environment, fn_info.generator_class.ir))

    # Add the type, value, and traceback variables to the environment.
    typ = builder.environment.add_local_reg(Var('type'), object_rprimitive,
                                            True)
    val = builder.environment.add_local_reg(Var('value'), object_rprimitive,
                                            True)
    tb = builder.environment.add_local_reg(Var('traceback'), object_rprimitive,
                                           True)

    # Because the value and traceback arguments are optional and hence
    # can be NULL if not passed in, we have to assign them Py_None if
    # they are not passed in.
    none_reg = builder.none_object()
    builder.assign_if_null(val, lambda: none_reg, builder.fn_info.fitem.line)
    builder.assign_if_null(tb, lambda: none_reg, builder.fn_info.fitem.line)

    # Call the helper function using the arguments passed in, and return that result.
    result = builder.add(
        Call(fn_decl, [
            self_reg,
            builder.read(typ),
            builder.read(val),
            builder.read(tb), none_reg
        ], fn_info.fitem.line))
    builder.add(Return(result))
    blocks, env, _, fn_info = builder.leave()

    # Create the FuncSignature for the throw function. Note that the
    # value and traceback fields are optional, and are assigned to if
    # they are not passed in inside the body of the throw function.
    sig = FuncSignature((RuntimeArg(
        SELF_NAME, object_rprimitive), RuntimeArg('type', object_rprimitive),
                         RuntimeArg('value', object_rprimitive, ARG_OPT),
                         RuntimeArg('traceback', object_rprimitive, ARG_OPT)),
                        sig.ret_type)

    throw_fn_decl = FuncDecl('throw', fn_info.generator_class.ir.name,
                             builder.module_name, sig)
    throw_fn_ir = FuncIR(throw_fn_decl, blocks, env)
    fn_info.generator_class.ir.methods['throw'] = throw_fn_ir
    builder.functions.append(throw_fn_ir)
Esempio n. 9
0
def allocate_class(builder: IRBuilder, cdef: ClassDef) -> Value:
    # OK AND NOW THE FUN PART
    base_exprs = cdef.base_type_exprs + cdef.removed_base_type_exprs
    if base_exprs:
        bases = [builder.accept(x) for x in base_exprs]
        tp_bases = builder.new_tuple(bases, cdef.line)
    else:
        tp_bases = builder.add(
            LoadErrorValue(object_rprimitive, is_borrowed=True))
    modname = builder.load_static_unicode(builder.module_name)
    template = builder.add(
        LoadStatic(object_rprimitive, cdef.name + "_template",
                   builder.module_name, NAMESPACE_TYPE))
    # Create the class
    tp = builder.call_c(pytype_from_template_op, [template, tp_bases, modname],
                        cdef.line)
    # Immediately fix up the trait vtables, before doing anything with the class.
    ir = builder.mapper.type_to_ir[cdef.info]
    if not ir.is_trait and not ir.builtin_base:
        builder.add(
            Call(
                FuncDecl(cdef.name + '_trait_vtable_setup',
                         None, builder.module_name,
                         FuncSignature([], bool_rprimitive)), [], -1))
    # Populate a '__mypyc_attrs__' field containing the list of attrs
    builder.call_c(py_setattr_op, [
        tp,
        builder.load_static_unicode('__mypyc_attrs__'),
        create_mypyc_attrs_tuple(builder, builder.mapper.type_to_ir[cdef.info],
                                 cdef.line)
    ], cdef.line)

    # Save the class
    builder.add(InitStatic(tp, cdef.name, builder.module_name, NAMESPACE_TYPE))

    # Add it to the dict
    builder.call_c(dict_set_item_op, [
        builder.load_globals_dict(),
        builder.load_static_unicode(cdef.name),
        tp,
    ], cdef.line)

    return tp
Esempio n. 10
0
def instantiate_generator_class(builder: IRBuilder) -> Value:
    fitem = builder.fn_info.fitem
    generator_reg = builder.add(Call(builder.fn_info.generator_class.ir.ctor, [], fitem.line))

    # Get the current environment register. If the current function is nested, then the
    # generator class gets instantiated from the callable class' '__call__' method, and hence
    # we use the callable class' environment register. Otherwise, we use the original
    # function's environment register.
    if builder.fn_info.is_nested:
        curr_env_reg = builder.fn_info.callable_class.curr_env_reg
    else:
        curr_env_reg = builder.fn_info.curr_env_reg

    # Set the generator class' environment attribute to point at the environment class
    # defined in the current scope.
    builder.add(SetAttr(generator_reg, ENV_ATTR_NAME, curr_env_reg, fitem.line))

    # Set the generator class' environment class' NEXT_LABEL_ATTR_NAME attribute to 0.
    zero = Integer(0)
    builder.add(SetAttr(curr_env_reg, NEXT_LABEL_ATTR_NAME, zero, fitem.line))
    return generator_reg
Esempio n. 11
0
def add_next_to_generator_class(builder: IRBuilder, fn_info: FuncInfo,
                                fn_decl: FuncDecl, sig: FuncSignature) -> None:
    """Generates the '__next__' method for a generator class."""
    builder.enter(fn_info)
    self_reg = builder.read(
        add_self_to_env(builder.environment, fn_info.generator_class.ir))
    none_reg = builder.none_object()

    # Call the helper function with error flags set to Py_None, and return that result.
    result = builder.add(
        Call(fn_decl, [self_reg, none_reg, none_reg, none_reg, none_reg],
             fn_info.fitem.line))
    builder.add(Return(result))
    blocks, env, _, fn_info = builder.leave()

    sig = FuncSignature((RuntimeArg(SELF_NAME, object_rprimitive), ),
                        sig.ret_type)
    next_fn_decl = FuncDecl('__next__', fn_info.generator_class.ir.name,
                            builder.module_name, sig)
    next_fn_ir = FuncIR(next_fn_decl, blocks, env)
    fn_info.generator_class.ir.methods['__next__'] = next_fn_ir
    builder.functions.append(next_fn_ir)