示例#1
0
def setup_non_ext_dict(builder: IRBuilder,
                       cdef: ClassDef,
                       metaclass: Value,
                       bases: Value) -> Value:
    """Initialize the class dictionary for a non-extension class.

    This class dictionary is passed to the metaclass constructor.
    """
    # Check if the metaclass defines a __prepare__ method, and if so, call it.
    has_prepare = builder.call_c(py_hasattr_op,
                                [metaclass,
                                builder.load_str('__prepare__')], cdef.line)

    non_ext_dict = Register(dict_rprimitive)

    true_block, false_block, exit_block, = BasicBlock(), BasicBlock(), BasicBlock()
    builder.add_bool_branch(has_prepare, true_block, false_block)

    builder.activate_block(true_block)
    cls_name = builder.load_str(cdef.name)
    prepare_meth = builder.py_get_attr(metaclass, '__prepare__', cdef.line)
    prepare_dict = builder.py_call(prepare_meth, [cls_name, bases], cdef.line)
    builder.assign(non_ext_dict, prepare_dict, cdef.line)
    builder.goto(exit_block)

    builder.activate_block(false_block)
    builder.assign(non_ext_dict, builder.call_c(dict_new_op, [], cdef.line), cdef.line)
    builder.goto(exit_block)
    builder.activate_block(exit_block)

    return non_ext_dict
示例#2
0
def faster_min_max(builder: IRBuilder, expr: CallExpr,
                   callee: RefExpr) -> Optional[Value]:
    if expr.arg_kinds == [ARG_POS, ARG_POS]:
        x, y = builder.accept(expr.args[0]), builder.accept(expr.args[1])
        result = Register(builder.node_type(expr))
        # CPython evaluates arguments reversely when calling min(...) or max(...)
        if callee.fullname == 'builtins.min':
            comparison = builder.binary_op(y, x, '<', expr.line)
        else:
            comparison = builder.binary_op(y, x, '>', expr.line)

        true_block, false_block, next_block = BasicBlock(), BasicBlock(
        ), BasicBlock()
        builder.add_bool_branch(comparison, true_block, false_block)

        builder.activate_block(true_block)
        builder.assign(result, builder.coerce(y, result.type, expr.line),
                       expr.line)
        builder.goto(next_block)

        builder.activate_block(false_block)
        builder.assign(result, builder.coerce(x, result.type, expr.line),
                       expr.line)
        builder.goto(next_block)

        builder.activate_block(next_block)
        return result
    return None
示例#3
0
文件: statement.py 项目: sthagen/mypy
def try_finally_entry_blocks(builder: IRBuilder, err_handler: BasicBlock,
                             return_entry: BasicBlock, main_entry: BasicBlock,
                             finally_block: BasicBlock,
                             ret_reg: Optional[Register]) -> Value:
    old_exc = Register(exc_rtuple)

    # Entry block for non-exceptional flow
    builder.activate_block(main_entry)
    if ret_reg:
        builder.add(
            Assign(ret_reg,
                   builder.add(LoadErrorValue(builder.ret_types[-1]))))
    builder.goto(return_entry)

    builder.activate_block(return_entry)
    builder.add(Assign(old_exc, builder.add(LoadErrorValue(exc_rtuple))))
    builder.goto(finally_block)

    # Entry block for errors
    builder.activate_block(err_handler)
    if ret_reg:
        builder.add(
            Assign(ret_reg,
                   builder.add(LoadErrorValue(builder.ret_types[-1]))))
    builder.add(Assign(old_exc, builder.call_c(error_catch_op, [], -1)))
    builder.goto(finally_block)

    return old_exc
示例#4
0
    def gen_return(self, builder: 'IRBuilder', value: Value,
                   line: int) -> None:
        if self.ret_reg is None:
            self.ret_reg = Register(builder.ret_types[-1])

        builder.add(Assign(self.ret_reg, value))
        builder.add(Goto(self.target))
示例#5
0
 def test_duplicate_op(self) -> None:
     arg_reg = Register(type=int32_rprimitive, name="r1")
     assign = Assign(dest=arg_reg,
                     src=Integer(value=5, rtype=int32_rprimitive))
     block = self.basic_block([assign, assign, Return(value=NONE_VALUE)])
     fn = FuncIR(
         decl=self.func_decl(name="func_1"),
         arg_regs=[],
         blocks=[block],
     )
     assert_has_error(
         fn, FnError(source=assign, desc="Func has a duplicate op"))
示例#6
0
    def add_local(self, symbol: SymbolNode, typ: RType, is_arg: bool = False) -> 'Register':
        """Add register that represents a symbol to the symbol table.

        Args:
            is_arg: is this a function argument
        """
        assert isinstance(symbol, SymbolNode)
        reg = Register(typ, symbol.name, is_arg=is_arg, line=symbol.line)
        self.symtables[-1][symbol] = AssignmentTargetRegister(reg)
        if is_arg:
            self.builder.args.append(reg)
        return reg
示例#7
0
 def test_invalid_register_source(self) -> None:
     ret = Return(value=Register(
         type=none_rprimitive,
         name="r1",
     ))
     block = self.basic_block([ret])
     fn = FuncIR(
         decl=self.func_decl(name="func_1"),
         arg_regs=[],
         blocks=[block],
     )
     assert_has_error(
         fn, FnError(source=ret,
                     desc="Invalid op reference to register r1"))
示例#8
0
 def test_invalid_assign(self) -> None:
     arg_reg = Register(type=int64_rprimitive, name="r1")
     assign = Assign(dest=arg_reg,
                     src=Integer(value=5, rtype=int32_rprimitive))
     ret = Return(value=NONE_VALUE)
     fn = FuncIR(
         decl=self.func_decl(name="func_1"),
         arg_regs=[arg_reg],
         blocks=[self.basic_block([assign, ret])],
     )
     assert_has_error(
         fn,
         FnError(source=assign,
                 desc="Cannot coerce source type int32 to dest type int64"),
     )
示例#9
0
def translate_next_call(builder: IRBuilder, expr: CallExpr,
                        callee: RefExpr) -> Optional[Value]:
    """Special case for calling next() on a generator expression, an
    idiom that shows up some in mypy.

    For example, next(x for x in l if x.id == 12, None) will
    generate code that searches l for an element where x.id == 12
    and produce the first such object, or None if no such element
    exists.
    """
    if not (expr.arg_kinds in ([ARG_POS], [ARG_POS, ARG_POS])
            and isinstance(expr.args[0], GeneratorExpr)):
        return None

    gen = expr.args[0]

    retval = Register(builder.node_type(expr))
    default_val = None
    if len(expr.args) > 1:
        default_val = builder.accept(expr.args[1])

    exit_block = BasicBlock()

    def gen_inner_stmts() -> None:
        # next takes the first element of the generator, so if
        # something gets produced, we are done.
        builder.assign(retval, builder.accept(gen.left_expr),
                       gen.left_expr.line)
        builder.goto(exit_block)

    loop_params = list(zip(gen.indices, gen.sequences, gen.condlists))
    comprehension_helper(builder, loop_params, gen_inner_stmts, gen.line)

    # Now we need the case for when nothing got hit. If there was
    # a default value, we produce it, and otherwise we raise
    # StopIteration.
    if default_val:
        builder.assign(retval, default_val, gen.left_expr.line)
        builder.goto(exit_block)
    else:
        builder.add(
            RaiseStandardError(RaiseStandardError.STOP_ITERATION, None,
                               expr.line))
        builder.add(Unreachable())

    builder.activate_block(exit_block)
    return retval
 def init(self, start_reg: Value, end_reg: Value, step: int) -> None:
     builder = self.builder
     self.start_reg = start_reg
     self.end_reg = end_reg
     self.step = step
     self.end_target = builder.maybe_spill(end_reg)
     if is_short_int_rprimitive(start_reg.type) and is_short_int_rprimitive(end_reg.type):
         index_type = short_int_rprimitive
     else:
         index_type = int_rprimitive
     index_reg = Register(index_type)
     builder.assign(index_reg, start_reg, -1)
     self.index_reg = builder.maybe_spill_assignable(index_reg)
     # Initialize loop index to 0. Assert that the index target is assignable.
     self.index_target = builder.get_assignment_target(
         self.index)  # type: Union[Register, AssignmentTarget]
     builder.assign(self.index_target, builder.read(self.index_reg, self.line), self.line)
示例#11
0
    def maybe_spill_assignable(self, value: Value) -> Union[Register, AssignmentTarget]:
        """
        Moves a given Value instance into the environment class for generator functions. For
        non-generator functions, allocate a temporary Register.

        Returns an AssignmentTarget associated with the Value for generator functions and an
        assignable Register for non-generator functions.
        """
        if self.fn_info.is_generator:
            return self.spill(value)

        if isinstance(value, Register):
            return value

        # Allocate a temporary register for the assignable value.
        reg = Register(value.type)
        self.assign(reg, value, -1)
        return reg
示例#12
0
 def accept(self, node: Union[Statement, Expression]) -> Optional[Value]:
     """Transform an expression or a statement."""
     with self.catch_errors(node.line):
         if isinstance(node, Expression):
             try:
                 res = node.accept(self.visitor)
                 res = self.coerce(res, self.node_type(node), node.line)
             # If we hit an error during compilation, we want to
             # keep trying, so we can produce more error
             # messages. Generate a temp of the right type to keep
             # from causing more downstream trouble.
             except UnsupportedException:
                 res = Register(self.node_type(node))
             return res
         else:
             try:
                 node.accept(self.visitor)
             except UnsupportedException:
                 pass
             return None
示例#13
0
    def except_body() -> None:
        # The body of the except is all implemented in a C function to
        # reduce how much code we need to generate. It returns a value
        # indicating whether to break or yield (or raise an exception).
        val = Register(object_rprimitive)
        val_address = builder.add(LoadAddress(object_pointer_rprimitive, val))
        to_stop = builder.call_c(yield_from_except_op,
                                 [builder.read(iter_reg), val_address], o.line)

        ok, stop = BasicBlock(), BasicBlock()
        builder.add(Branch(to_stop, stop, ok, Branch.BOOL))

        # The exception got swallowed. Continue, yielding the returned value
        builder.activate_block(ok)
        builder.assign(to_yield_reg, val, o.line)
        builder.nonlocal_control[-1].gen_continue(builder, o.line)

        # The exception was a StopIteration. Stop iterating.
        builder.activate_block(stop)
        builder.assign(result, val, o.line)
        builder.nonlocal_control[-1].gen_break(builder, o.line)
示例#14
0
def generate_singledispatch_dispatch_function(
    builder: IRBuilder,
    main_singledispatch_function_name: str,
    fitem: FuncDef,
) -> None:
    line = fitem.line
    current_func_decl = builder.mapper.func_to_decl[fitem]
    arg_info = get_args(builder, current_func_decl.sig.args, line)

    dispatch_func_obj = builder.self()

    arg_type = builder.builder.get_type_of_obj(arg_info.args[0], line)
    dispatch_cache = builder.builder.get_attr(dispatch_func_obj,
                                              'dispatch_cache',
                                              dict_rprimitive, line)
    call_find_impl, use_cache, call_func = BasicBlock(), BasicBlock(
    ), BasicBlock()
    get_result = builder.call_c(dict_get_method_with_none,
                                [dispatch_cache, arg_type], line)
    is_not_none = builder.translate_is_op(get_result, builder.none_object(),
                                          'is not', line)
    impl_to_use = Register(object_rprimitive)
    builder.add_bool_branch(is_not_none, use_cache, call_find_impl)

    builder.activate_block(use_cache)
    builder.assign(impl_to_use, get_result, line)
    builder.goto(call_func)

    builder.activate_block(call_find_impl)
    find_impl = builder.load_module_attr_by_fullname('functools._find_impl',
                                                     line)
    registry = load_singledispatch_registry(builder, dispatch_func_obj, line)
    uncached_impl = builder.py_call(find_impl, [arg_type, registry], line)
    builder.call_c(dict_set_item_op, [dispatch_cache, arg_type, uncached_impl],
                   line)
    builder.assign(impl_to_use, uncached_impl, line)
    builder.goto(call_func)

    builder.activate_block(call_func)
    gen_calls_to_correct_impl(builder, impl_to_use, arg_info, fitem, line)
示例#15
0
def any_all_helper(builder: IRBuilder,
                   gen: GeneratorExpr,
                   initial_value: Callable[[], Value],
                   modify: Callable[[Value], Value],
                   new_value: Callable[[], Value]) -> Value:
    retval = Register(bool_rprimitive)
    builder.assign(retval, initial_value(), -1)
    loop_params = list(zip(gen.indices, gen.sequences, gen.condlists))
    true_block, false_block, exit_block = BasicBlock(), BasicBlock(), BasicBlock()

    def gen_inner_stmts() -> None:
        comparison = modify(builder.accept(gen.left_expr))
        builder.add_bool_branch(comparison, true_block, false_block)
        builder.activate_block(true_block)
        builder.assign(retval, new_value(), -1)
        builder.goto(exit_block)
        builder.activate_block(false_block)

    comprehension_helper(builder, loop_params, gen_inner_stmts, gen.line)
    builder.goto_and_activate(exit_block)

    return retval
示例#16
0
 def test_register(self) -> None:
     reg = Register(int_rprimitive)
     op = Assign(reg, Integer(5))
     self.block.ops.append(op)
     fn = FuncIR(
         FuncDecl('myfunc', None, 'mod',
                  FuncSignature([self.arg], list_rprimitive)), [self.reg],
         [self.block])
     value_names = generate_names_for_ir(fn.arg_regs, fn.blocks)
     emitter = Emitter(EmitterContext(NameGenerator([['mod']])),
                       value_names)
     generate_native_function(fn, emitter, 'prog.py', 'prog')
     result = emitter.fragments
     assert_string_arrays_equal([
         'PyObject *CPyDef_myfunc(CPyTagged cpy_r_arg) {\n',
         '    CPyTagged cpy_r_r0;\n',
         'CPyL0: ;\n',
         '    cpy_r_r0 = 10;\n',
         '}\n',
     ],
                                result,
                                msg='Generated code invalid')
示例#17
0
def transform_conditional_expr(builder: IRBuilder, expr: ConditionalExpr) -> Value:
    if_body, else_body, next_block = BasicBlock(), BasicBlock(), BasicBlock()

    builder.process_conditional(expr.cond, if_body, else_body)
    expr_type = builder.node_type(expr)
    # Having actual Phi nodes would be really nice here!
    target = Register(expr_type)

    builder.activate_block(if_body)
    true_value = builder.accept(expr.if_expr)
    true_value = builder.coerce(true_value, expr_type, expr.line)
    builder.add(Assign(target, true_value))
    builder.goto(next_block)

    builder.activate_block(else_body)
    false_value = builder.accept(expr.else_expr)
    false_value = builder.coerce(false_value, expr_type, expr.line)
    builder.add(Assign(target, false_value))
    builder.goto(next_block)

    builder.activate_block(next_block)

    return target
示例#18
0
文件: statement.py 项目: sthagen/mypy
def transform_assignment_stmt(builder: IRBuilder,
                              stmt: AssignmentStmt) -> None:
    lvalues = stmt.lvalues
    assert len(lvalues) >= 1
    builder.disallow_class_assignments(lvalues, stmt.line)
    first_lvalue = lvalues[0]
    if stmt.type and isinstance(stmt.rvalue, TempNode):
        # This is actually a variable annotation without initializer. Don't generate
        # an assignment but we need to call get_assignment_target since it adds a
        # name binding as a side effect.
        builder.get_assignment_target(first_lvalue, stmt.line)
        return

    # Special case multiple assignments like 'x, y = e1, e2'.
    if (isinstance(first_lvalue, (TupleExpr, ListExpr))
            and isinstance(stmt.rvalue, (TupleExpr, ListExpr))
            and len(first_lvalue.items) == len(stmt.rvalue.items)
            and all(is_simple_lvalue(item)
                    for item in first_lvalue.items) and len(lvalues) == 1):
        temps = []
        for right in stmt.rvalue.items:
            rvalue_reg = builder.accept(right)
            temp = Register(rvalue_reg.type)
            builder.assign(temp, rvalue_reg, stmt.line)
            temps.append(temp)
        for (left, temp) in zip(first_lvalue.items, temps):
            assignment_target = builder.get_assignment_target(left)
            builder.assign(assignment_target, temp, stmt.line)
        return

    line = stmt.rvalue.line
    rvalue_reg = builder.accept(stmt.rvalue)
    if builder.non_function_scope() and stmt.is_final_def:
        builder.init_final_static(first_lvalue, rvalue_reg)
    for lvalue in lvalues:
        target = builder.get_assignment_target(lvalue)
        builder.assign(target, rvalue_reg, line)
示例#19
0
def translate_sum_call(builder: IRBuilder, expr: CallExpr,
                       callee: RefExpr) -> Optional[Value]:
    # specialized implementation is used if:
    # - only one or two arguments given (if not, sum() has been given invalid arguments)
    # - first argument is a Generator (there is no benefit to optimizing the performance of eg.
    #   sum([1, 2, 3]), so non-Generator Iterables are not handled)
    if not (len(expr.args) in (1, 2) and expr.arg_kinds[0] == ARG_POS
            and isinstance(expr.args[0], GeneratorExpr)):
        return None

    # handle 'start' argument, if given
    if len(expr.args) == 2:
        # ensure call to sum() was properly constructed
        if not expr.arg_kinds[1] in (ARG_POS, ARG_NAMED):
            return None
        start_expr = expr.args[1]
    else:
        start_expr = IntExpr(0)

    gen_expr = expr.args[0]
    target_type = builder.node_type(expr)
    retval = Register(target_type)
    builder.assign(retval,
                   builder.coerce(builder.accept(start_expr), target_type, -1),
                   -1)

    def gen_inner_stmts() -> None:
        call_expr = builder.accept(gen_expr.left_expr)
        builder.assign(retval, builder.binary_op(retval, call_expr, '+', -1),
                       -1)

    loop_params = list(
        zip(gen_expr.indices, gen_expr.sequences, gen_expr.condlists))
    comprehension_helper(builder, loop_params, gen_inner_stmts, gen_expr.line)

    return retval
示例#20
0
def register(name: str) -> Register:
    return Register(int_rprimitive, 'foo', is_arg=True)
示例#21
0
 def add_local(name: str, rtype: RType) -> Register:
     reg = Register(rtype, name)
     self.registers.append(reg)
     return reg
示例#22
0
 def setUp(self) -> None:
     self.arg = RuntimeArg('arg', int_rprimitive)
     self.reg = Register(int_rprimitive, 'arg')
     self.block = BasicBlock(0)
示例#23
0
 def setUp(self) -> None:
     self.n = Register(int_rprimitive, 'n')
     self.context = EmitterContext(NameGenerator([['mod']]))
示例#24
0
 def test_long_unsigned(self) -> None:
     a = Register(int64_rprimitive, 'a')
     self.assert_emit(Assign(a, Integer(1 << 31, int64_rprimitive)),
                      """cpy_r_a = 2147483648U;""")
     self.assert_emit(Assign(a, Integer((1 << 31) - 1, int64_rprimitive)),
                      """cpy_r_a = 2147483647;""")
示例#25
0
def handle_yield_from_and_await(builder: IRBuilder,
                                o: Union[YieldFromExpr, AwaitExpr]) -> Value:
    # This is basically an implementation of the code in PEP 380.

    # TODO: do we want to use the right types here?
    result = Register(object_rprimitive)
    to_yield_reg = Register(object_rprimitive)
    received_reg = Register(object_rprimitive)

    if isinstance(o, YieldFromExpr):
        iter_val = builder.call_c(iter_op, [builder.accept(o.expr)], o.line)
    else:
        iter_val = builder.call_c(coro_op, [builder.accept(o.expr)], o.line)

    iter_reg = builder.maybe_spill_assignable(iter_val)

    stop_block, main_block, done_block = BasicBlock(), BasicBlock(
    ), BasicBlock()
    _y_init = builder.call_c(next_raw_op, [builder.read(iter_reg)], o.line)
    builder.add(Branch(_y_init, stop_block, main_block, Branch.IS_ERROR))

    # Try extracting a return value from a StopIteration and return it.
    # If it wasn't, this reraises the exception.
    builder.activate_block(stop_block)
    builder.assign(result, builder.call_c(check_stop_op, [], o.line), o.line)
    builder.goto(done_block)

    builder.activate_block(main_block)
    builder.assign(to_yield_reg, _y_init, o.line)

    # OK Now the main loop!
    loop_block = BasicBlock()
    builder.goto_and_activate(loop_block)

    def try_body() -> None:
        builder.assign(received_reg,
                       emit_yield(builder, builder.read(to_yield_reg), o.line),
                       o.line)

    def except_body() -> None:
        # The body of the except is all implemented in a C function to
        # reduce how much code we need to generate. It returns a value
        # indicating whether to break or yield (or raise an exception).
        val = Register(object_rprimitive)
        val_address = builder.add(LoadAddress(object_pointer_rprimitive, val))
        to_stop = builder.call_c(yield_from_except_op,
                                 [builder.read(iter_reg), val_address], o.line)

        ok, stop = BasicBlock(), BasicBlock()
        builder.add(Branch(to_stop, stop, ok, Branch.BOOL))

        # The exception got swallowed. Continue, yielding the returned value
        builder.activate_block(ok)
        builder.assign(to_yield_reg, val, o.line)
        builder.nonlocal_control[-1].gen_continue(builder, o.line)

        # The exception was a StopIteration. Stop iterating.
        builder.activate_block(stop)
        builder.assign(result, val, o.line)
        builder.nonlocal_control[-1].gen_break(builder, o.line)

    def else_body() -> None:
        # Do a next() or a .send(). It will return NULL on exception
        # but it won't automatically propagate.
        _y = builder.call_c(
            send_op, [builder.read(iter_reg),
                      builder.read(received_reg)], o.line)
        ok, stop = BasicBlock(), BasicBlock()
        builder.add(Branch(_y, stop, ok, Branch.IS_ERROR))

        # Everything's fine. Yield it.
        builder.activate_block(ok)
        builder.assign(to_yield_reg, _y, o.line)
        builder.nonlocal_control[-1].gen_continue(builder, o.line)

        # Try extracting a return value from a StopIteration and return it.
        # If it wasn't, this rereaises the exception.
        builder.activate_block(stop)
        builder.assign(result, builder.call_c(check_stop_op, [], o.line),
                       o.line)
        builder.nonlocal_control[-1].gen_break(builder, o.line)

    builder.push_loop_stack(loop_block, done_block)
    transform_try_except(builder, try_body, [(None, None, except_body)],
                         else_body, o.line)
    builder.pop_loop_stack()

    builder.goto_and_activate(done_block)
    return builder.read(result)
示例#26
0
 def test_assign_multi(self) -> None:
     t = RArray(object_rprimitive, 2)
     a = Register(t, 'a')
     self.registers.append(a)
     self.assert_emit(AssignMulti(a, [self.o, self.o2]),
                      """PyObject *cpy_r_a[2] = {cpy_r_o, cpy_r_o2};""")
示例#27
0
 def test_long_signed(self) -> None:
     a = Register(int64_rprimitive, 'a')
     self.assert_emit(Assign(a, Integer(-(1 << 31) + 1, int64_rprimitive)),
                      """cpy_r_a = -2147483647;""")
     self.assert_emit(Assign(a, Integer(-(1 << 31), int64_rprimitive)),
                      """cpy_r_a = -2147483648LL;""")