Exemple #1
0
def gen_glue_ne_method(builder: IRBuilder, cls: ClassIR, line: int) -> None:
    """Generate a "__ne__" method from a "__eq__" method. """
    builder.enter_method(cls, '__ne__', object_rprimitive)
    rhs_arg = builder.add_argument('rhs', object_rprimitive)

    # If __eq__ returns NotImplemented, then __ne__ should also
    not_implemented_block, regular_block = BasicBlock(), BasicBlock()
    eqval = builder.add(MethodCall(builder.self(), '__eq__', [rhs_arg], line))
    not_implemented = builder.add(LoadAddress(not_implemented_op.type,
                                              not_implemented_op.src, line))
    builder.add(Branch(
        builder.translate_is_op(eqval, not_implemented, 'is', line),
        not_implemented_block,
        regular_block,
        Branch.BOOL))

    builder.activate_block(regular_block)
    retval = builder.coerce(
        builder.unary_op(eqval, 'not', line), object_rprimitive, line
    )
    builder.add(Return(retval))

    builder.activate_block(not_implemented_block)
    builder.add(Return(not_implemented))

    builder.leave_method()
Exemple #2
0
    def gen_method_call(
            self,
            base: Value,
            name: str,
            arg_values: List[Value],
            result_type: Optional[RType],
            line: int,
            arg_kinds: Optional[List[int]] = None,
            arg_names: Optional[List[Optional[str]]] = None) -> Value:
        """Generate either a native or Python method call."""
        # If arg_kinds contains values other than arg_pos and arg_named, then fallback to
        # Python method call.
        if (arg_kinds is not None and not all(kind in (ARG_POS, ARG_NAMED)
                                              for kind in arg_kinds)):
            return self.py_method_call(base, name, arg_values, base.line,
                                       arg_kinds, arg_names)

        # If the base type is one of ours, do a MethodCall
        if (isinstance(base.type, RInstance)
                and base.type.class_ir.is_ext_class
                and not base.type.class_ir.builtin_base):
            if base.type.class_ir.has_method(name):
                decl = base.type.class_ir.method_decl(name)
                if arg_kinds is None:
                    assert arg_names is None, "arg_kinds not present but arg_names is"
                    arg_kinds = [ARG_POS for _ in arg_values]
                    arg_names = [None for _ in arg_values]
                else:
                    assert arg_names is not None, "arg_kinds present but arg_names is not"

                # Normalize args to positionals.
                assert decl.bound_sig
                arg_values = self.native_args_to_positional(
                    arg_values, arg_kinds, arg_names, decl.bound_sig, line)
                return self.add(MethodCall(base, name, arg_values, line))
            elif base.type.class_ir.has_attr(name):
                function = self.add(GetAttr(base, name, line))
                return self.py_call(function,
                                    arg_values,
                                    line,
                                    arg_kinds=arg_kinds,
                                    arg_names=arg_names)

        elif isinstance(base.type, RUnion):
            return self.union_method_call(base, base.type, name, arg_values,
                                          result_type, line, arg_kinds,
                                          arg_names)

        # Try to do a special-cased method call
        if not arg_kinds or arg_kinds == [ARG_POS] * len(arg_values):
            target = self.translate_special_method_call(
                base, name, arg_values, result_type, line)
            if target:
                return target

        # Fall back to Python method call
        return self.py_method_call(base, name, arg_values, line, arg_kinds,
                                   arg_names)
Exemple #3
0
def add_close_to_generator_class(builder: IRBuilder,
                                 fn_info: FuncInfo) -> None:
    """Generates the '__close__' method for a generator class."""
    with builder.enter_method(fn_info.generator_class.ir, 'close',
                              object_rprimitive, fn_info):
        except_block, else_block = BasicBlock(), BasicBlock()
        builder.builder.push_error_handler(except_block)
        builder.goto_and_activate(BasicBlock())
        generator_exit = builder.load_module_attr_by_fullname(
            'builtins.GeneratorExit', fn_info.fitem.line)
        builder.add(
            MethodCall(
                builder.self(), 'throw',
                [generator_exit,
                 builder.none_object(),
                 builder.none_object()]))
        builder.goto(else_block)
        builder.builder.pop_error_handler()

        builder.activate_block(except_block)
        old_exc = builder.call_c(error_catch_op, [], fn_info.fitem.line)
        builder.nonlocal_control.append(
            ExceptNonlocalControl(builder.nonlocal_control[-1], old_exc))
        stop_iteration = builder.load_module_attr_by_fullname(
            'builtins.StopIteration', fn_info.fitem.line)
        exceptions = builder.add(
            TupleSet([generator_exit, stop_iteration], fn_info.fitem.line))
        matches = builder.call_c(exc_matches_op, [exceptions],
                                 fn_info.fitem.line)

        match_block, non_match_block = BasicBlock(), BasicBlock()
        builder.add(Branch(matches, match_block, non_match_block, Branch.BOOL))

        builder.activate_block(match_block)
        builder.call_c(restore_exc_info_op, [builder.read(old_exc)],
                       fn_info.fitem.line)
        builder.add(Return(builder.none_object()))

        builder.activate_block(non_match_block)
        builder.call_c(reraise_exception_op, [], NO_TRACEBACK_LINE_NO)
        builder.add(Unreachable())

        builder.nonlocal_control.pop()

        builder.activate_block(else_block)
        builder.add(
            RaiseStandardError(RaiseStandardError.RUNTIME_ERROR,
                               'generator ignored GeneratorExit',
                               fn_info.fitem.line))
        builder.add(Unreachable())
Exemple #4
0
def gen_glue_ne_method(builder: IRBuilder, cls: ClassIR, line: int) -> FuncIR:
    """Generate a "__ne__" method from a "__eq__" method. """
    builder.enter()

    rt_args = (RuntimeArg("self", RInstance(cls)), RuntimeArg("rhs", object_rprimitive))

    # The environment operates on Vars, so we make some up
    fake_vars = [(Var(arg.name), arg.type) for arg in rt_args]
    args = [
        builder.read(
            builder.environment.add_local_reg(
                var, type, is_arg=True
            ),
            line
        )
        for var, type in fake_vars
    ]  # type: List[Value]
    builder.ret_types[-1] = object_rprimitive

    # If __eq__ returns NotImplemented, then __ne__ should also
    not_implemented_block, regular_block = BasicBlock(), BasicBlock()
    eqval = builder.add(MethodCall(args[0], '__eq__', [args[1]], line))
    not_implemented = builder.add(LoadAddress(not_implemented_op.type,
                                              not_implemented_op.src, line))
    builder.add(Branch(
        builder.translate_is_op(eqval, not_implemented, 'is', line),
        not_implemented_block,
        regular_block,
        Branch.BOOL_EXPR))

    builder.activate_block(regular_block)
    retval = builder.coerce(
        builder.unary_op(eqval, 'not', line), object_rprimitive, line
    )
    builder.add(Return(retval))

    builder.activate_block(not_implemented_block)
    builder.add(Return(not_implemented))

    blocks, env, ret_type, _ = builder.leave()
    return FuncIR(
        FuncDecl('__ne__', cls.name, builder.module_name,
                 FuncSignature(rt_args, ret_type)),
        blocks, env)