示例#1
0
    def binary_op(self,
                  lreg: Value,
                  rreg: Value,
                  expr_op: str,
                  line: int) -> Value:
        # Special case == and != when we can resolve the method call statically.
        value = None
        if expr_op in ('==', '!='):
            value = self.translate_eq_cmp(lreg, rreg, expr_op, line)
        if value is not None:
            return value

        # generate fast binary logic ops on short ints
        if (is_short_int_rprimitive(lreg.type) and is_short_int_rprimitive(rreg.type)
                and expr_op in int_logical_op_mapping.keys()):
            return self.binary_int_op(bool_rprimitive, lreg, rreg,
                                      int_logical_op_mapping[expr_op][0], line)

        call_c_ops_candidates = c_binary_ops.get(expr_op, [])
        target = self.matching_call_c(call_c_ops_candidates, [lreg, rreg], line)
        if target:
            return target
        ops = binary_ops.get(expr_op, [])
        target = self.matching_primitive_op(ops, [lreg, rreg], line)
        assert target, 'Unsupported binary operation: %s' % expr_op
        return target
示例#2
0
def convert_expr(builder: IRBuilder, format_ops: List[FormatOp],
                 exprs: List[Expression], line: int) -> Optional[List[Value]]:
    """Convert expressions into string literals with the guidance
    of FormatOps."""
    if len(format_ops) != len(exprs):
        return None

    converted = []
    for x, format_op in zip(exprs, format_ops):
        node_type = builder.node_type(x)
        if format_op == FormatOp.STR:
            if is_str_rprimitive(node_type):
                var_str = builder.accept(x)
            elif is_int_rprimitive(node_type) or is_short_int_rprimitive(
                    node_type):
                var_str = builder.call_c(int_to_str_op, [builder.accept(x)],
                                         line)
            else:
                var_str = builder.call_c(str_op, [builder.accept(x)], line)
        elif format_op == FormatOp.INT:
            if is_int_rprimitive(node_type) or is_short_int_rprimitive(
                    node_type):
                var_str = builder.call_c(int_to_str_op, [builder.accept(x)],
                                         line)
            else:
                return None
        else:
            return None
        converted.append(var_str)
    return converted
示例#3
0
 def __init__(self, value: int, line: int = -1, rtype: RType = short_int_rprimitive) -> None:
     super().__init__(line)
     if is_short_int_rprimitive(rtype) or is_int_rprimitive(rtype):
         self.value = value * 2
     else:
         self.value = value
     self.type = rtype
示例#4
0
文件: emit.py 项目: JoeCare/mypy-1
    def emit_box(self,
                 src: str,
                 dest: str,
                 typ: RType,
                 declare_dest: bool = False,
                 can_borrow: bool = False) -> None:
        """Emit code for boxing a value of given type.

        Generate a simple assignment if no boxing is needed.

        The source reference count is stolen for the result (no need to decref afterwards).
        """
        # TODO: Always generate a new reference (if a reference type)
        if declare_dest:
            declaration = 'PyObject *'
        else:
            declaration = ''
        if is_int_rprimitive(typ) or is_short_int_rprimitive(typ):
            # Steal the existing reference if it exists.
            self.emit_line('{}{} = CPyTagged_StealAsObject({});'.format(
                declaration, dest, src))
        elif is_bool_rprimitive(typ):
            # N.B: bool is special cased to produce a borrowed value
            # after boxing, so we don't need to increment the refcount
            # when this comes directly from a Box op.
            self.emit_lines('{}{} = {} ? Py_True : Py_False;'.format(
                declaration, dest, src))
            if not can_borrow:
                self.emit_inc_ref(dest, object_rprimitive)
        elif is_none_rprimitive(typ):
            # N.B: None is special cased to produce a borrowed value
            # after boxing, so we don't need to increment the refcount
            # when this comes directly from a Box op.
            self.emit_lines('{}{} = Py_None;'.format(declaration, dest))
            if not can_borrow:
                self.emit_inc_ref(dest, object_rprimitive)
        elif isinstance(typ, RTuple):
            self.declare_tuple_struct(typ)
            self.emit_line('{}{} = PyTuple_New({});'.format(
                declaration, dest, len(typ.types)))
            self.emit_line('if (unlikely({} == NULL))'.format(dest))
            self.emit_line('    CPyError_OutOfMemory();')
            # TODO: Fail if dest is None
            for i in range(0, len(typ.types)):
                if not typ.is_unboxed:
                    self.emit_line('PyTuple_SET_ITEM({}, {}, {}.f{}'.format(
                        dest, i, src, i))
                else:
                    inner_name = self.temp_name()
                    self.emit_box('{}.f{}'.format(src, i),
                                  inner_name,
                                  typ.types[i],
                                  declare_dest=True)
                    self.emit_line('PyTuple_SET_ITEM({}, {}, {});'.format(
                        dest, i, inner_name))
        else:
            assert not typ.is_unboxed
            # Type is boxed -- trivially just assign.
            self.emit_line('{}{} = {};'.format(declaration, dest, src))
示例#5
0
    def gen_step(self) -> None:
        builder = self.builder
        line = self.line

        # Increment curr_index register. If the range is known to fit in short ints, use
        # short ints.
        if (is_short_int_rprimitive(self.start_reg.type)
                and is_short_int_rprimitive(self.end_reg.type)):
            new_val = builder.binary_int_op(short_int_rprimitive,
                            builder.read(self.index_reg, line),
                            builder.add(LoadInt(self.step)), BinaryIntOp.ADD, line)

        else:
            new_val = builder.binary_op(
                builder.read(self.index_reg, line), builder.add(LoadInt(self.step)), '+', line)
        builder.assign(self.index_reg, new_val, line)
        builder.assign(self.index_target, new_val, line)
 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)
示例#7
0
文件: ops.py 项目: pranavrajpal/mypy
 def __init__(self,
              value: int,
              rtype: RType = short_int_rprimitive,
              line: int = -1) -> None:
     if is_short_int_rprimitive(rtype) or is_int_rprimitive(rtype):
         self.value = value * 2
     else:
         self.value = value
     self.type = rtype
     self.line = line
示例#8
0
 def __init__(self, items: List[Value], line: int) -> None:
     super().__init__(line)
     self.items = items
     # Don't keep track of the fact that an int is short after it
     # is put into a tuple, since we don't properly implement
     # runtime subtyping for tuples.
     self.tuple_type = RTuple(
         [arg.type if not is_short_int_rprimitive(arg.type) else int_rprimitive
          for arg in items])
     self.type = self.tuple_type
示例#9
0
 def compare_tagged(self, lhs: Value, rhs: Value, op: str,
                    line: int) -> Value:
     """Compare two tagged integers using given op"""
     # generate fast binary logic ops on short ints
     if is_short_int_rprimitive(lhs.type) and is_short_int_rprimitive(
             rhs.type):
         return self.comparison_op(lhs, rhs,
                                   int_comparison_op_mapping[op][0], line)
     op_type, c_func_desc, negate_result, swap_op = int_comparison_op_mapping[
         op]
     result = self.alloc_temp(bool_rprimitive)
     short_int_block, int_block, out = BasicBlock(), BasicBlock(
     ), BasicBlock()
     check_lhs = self.check_tagged_short_int(lhs, line)
     if op in ("==", "!="):
         check = check_lhs
     else:
         # for non-equal logical ops(less than, greater than, etc.), need to check both side
         check_rhs = self.check_tagged_short_int(rhs, line)
         check = self.binary_int_op(bool_rprimitive, check_lhs, check_rhs,
                                    BinaryIntOp.AND, line)
     branch = Branch(check, short_int_block, int_block, Branch.BOOL_EXPR)
     branch.negated = False
     self.add(branch)
     self.activate_block(short_int_block)
     eq = self.comparison_op(lhs, rhs, op_type, line)
     self.add(Assign(result, eq, line))
     self.goto(out)
     self.activate_block(int_block)
     if swap_op:
         args = [rhs, lhs]
     else:
         args = [lhs, rhs]
     call = self.call_c(c_func_desc, args, line)
     if negate_result:
         # TODO: introduce UnaryIntOp?
         call_result = self.unary_op(call, "not", line)
     else:
         call_result = call
     self.add(Assign(result, call_result, line))
     self.goto_and_activate(out)
     return result
示例#10
0
 def visit_rprimitive(self, left: RPrimitive) -> bool:
     right = self.right
     if is_bool_rprimitive(left):
         if is_int_rprimitive(right):
             return True
     elif is_bit_rprimitive(left):
         if is_bool_rprimitive(right) or is_int_rprimitive(right):
             return True
     elif is_short_int_rprimitive(left):
         if is_int_rprimitive(right):
             return True
     return left is right
示例#11
0
 def visit_rprimitive(self, left: RPrimitive) -> bool:
     if is_bool_rprimitive(left) and is_int_rprimitive(self.right):
         return True
     if is_short_int_rprimitive(left) and is_int_rprimitive(self.right):
         return True
     return left is self.right
示例#12
0
    def emit_unbox(self,
                   src: str,
                   dest: str,
                   typ: RType,
                   custom_failure: Optional[str] = None,
                   declare_dest: bool = False,
                   borrow: bool = False,
                   optional: bool = False) -> None:
        """Emit code for unboxing a value of given type (from PyObject *).

        Evaluate C code in 'failure' if the value has an incompatible type.

        Always generate a new reference.

        Args:
            src: Name of source C variable
            dest: Name of target C variable
            typ: Type of value
            failure: What happens on error
            declare_dest: If True, also declare the variable 'dest'
            borrow: If True, create a borrowed reference
        """
        # TODO: Verify refcount handling.
        raise_exc = 'CPy_TypeError("{}", {});'.format(self.pretty_name(typ),
                                                      src)
        if custom_failure is not None:
            failure = [raise_exc, custom_failure]
        else:
            failure = [raise_exc, '%s = %s;' % (dest, self.c_error_value(typ))]
        if is_int_rprimitive(typ) or is_short_int_rprimitive(typ):
            if declare_dest:
                self.emit_line('CPyTagged {};'.format(dest))
            self.emit_arg_check(src, dest, typ,
                                '(likely(PyLong_Check({})))'.format(src),
                                optional)
            if borrow:
                self.emit_line(
                    '    {} = CPyTagged_BorrowFromObject({});'.format(
                        dest, src))
            else:
                self.emit_line('    {} = CPyTagged_FromObject({});'.format(
                    dest, src))
            self.emit_line('else {')
            self.emit_lines(*failure)
            self.emit_line('}')
        elif is_bool_rprimitive(typ) or is_bit_rprimitive(typ):
            # Whether we are borrowing or not makes no difference.
            if declare_dest:
                self.emit_line('char {};'.format(dest))
            self.emit_arg_check(src, dest, typ,
                                '(unlikely(!PyBool_Check({}))) {{'.format(src),
                                optional)
            self.emit_lines(*failure)
            self.emit_line('} else')
            conversion = '{} == Py_True'.format(src)
            self.emit_line('    {} = {};'.format(dest, conversion))
        elif is_none_rprimitive(typ):
            # Whether we are borrowing or not makes no difference.
            if declare_dest:
                self.emit_line('char {};'.format(dest))
            self.emit_arg_check(src, dest, typ,
                                '(unlikely({} != Py_None)) {{'.format(src),
                                optional)
            self.emit_lines(*failure)
            self.emit_line('} else')
            self.emit_line('    {} = 1;'.format(dest))
        elif isinstance(typ, RTuple):
            self.declare_tuple_struct(typ)
            if declare_dest:
                self.emit_line('{} {};'.format(self.ctype(typ), dest))
            # HACK: The error handling for unboxing tuples is busted
            # and instead of fixing it I am just wrapping it in the
            # cast code which I think is right. This is not good.
            if optional:
                self.emit_line('if ({} == NULL) {{'.format(src))
                self.emit_line('{} = {};'.format(dest,
                                                 self.c_error_value(typ)))
                self.emit_line('} else {')

            cast_temp = self.temp_name()
            self.emit_tuple_cast(src,
                                 cast_temp,
                                 typ,
                                 declare_dest=True,
                                 err='',
                                 src_type=None)
            self.emit_line('if (unlikely({} == NULL)) {{'.format(cast_temp))

            # self.emit_arg_check(src, dest, typ,
            #     '(!PyTuple_Check({}) || PyTuple_Size({}) != {}) {{'.format(
            #         src, src, len(typ.types)), optional)
            self.emit_lines(*failure)  # TODO: Decrease refcount?
            self.emit_line('} else {')
            if not typ.types:
                self.emit_line('{}.empty_struct_error_flag = 0;'.format(dest))
            for i, item_type in enumerate(typ.types):
                temp = self.temp_name()
                # emit_tuple_cast above checks the size, so this should not fail
                self.emit_line(
                    'PyObject *{} = PyTuple_GET_ITEM({}, {});'.format(
                        temp, src, i))
                temp2 = self.temp_name()
                # Unbox or check the item.
                if item_type.is_unboxed:
                    self.emit_unbox(temp,
                                    temp2,
                                    item_type,
                                    custom_failure,
                                    declare_dest=True,
                                    borrow=borrow)
                else:
                    if not borrow:
                        self.emit_inc_ref(temp, object_rprimitive)
                    self.emit_cast(temp, temp2, item_type, declare_dest=True)
                self.emit_line('{}.f{} = {};'.format(dest, i, temp2))
            self.emit_line('}')
            if optional:
                self.emit_line('}')

        else:
            assert False, 'Unboxing not implemented: %s' % typ
示例#13
0
文件: emit.py 项目: pranavrajpal/mypy
    def emit_unbox(self,
                   src: str,
                   dest: str,
                   typ: RType,
                   *,
                   declare_dest: bool = False,
                   error: Optional[ErrorHandler] = None,
                   raise_exception: bool = True,
                   optional: bool = False,
                   borrow: bool = False) -> None:
        """Emit code for unboxing a value of given type (from PyObject *).

        By default, assign error value to dest if the value has an
        incompatible type and raise TypeError. These can be customized
        using 'error' and 'raise_exception'.

        Generate a new reference unless 'borrow' is True.

        Args:
            src: Name of source C variable
            dest: Name of target C variable
            typ: Type of value
            declare_dest: If True, also declare the variable 'dest'
            error: What happens on error
            raise_exception: If True, also raise TypeError on failure
            borrow: If True, create a borrowed reference

        """
        error = error or AssignHandler()
        # TODO: Verify refcount handling.
        if isinstance(error, AssignHandler):
            failure = f'{dest} = {self.c_error_value(typ)};'
        elif isinstance(error, GotoHandler):
            failure = 'goto %s;' % error.label
        else:
            assert isinstance(error, ReturnHandler)
            failure = 'return %s;' % error.value
        if raise_exception:
            raise_exc = f'CPy_TypeError("{self.pretty_name(typ)}", {src}); '
            failure = raise_exc + failure
        if is_int_rprimitive(typ) or is_short_int_rprimitive(typ):
            if declare_dest:
                self.emit_line(f'CPyTagged {dest};')
            self.emit_arg_check(src, dest, typ, f'(likely(PyLong_Check({src})))',
                                optional)
            if borrow:
                self.emit_line(f'    {dest} = CPyTagged_BorrowFromObject({src});')
            else:
                self.emit_line(f'    {dest} = CPyTagged_FromObject({src});')
            self.emit_line('else {')
            self.emit_line(failure)
            self.emit_line('}')
        elif is_bool_rprimitive(typ) or is_bit_rprimitive(typ):
            # Whether we are borrowing or not makes no difference.
            if declare_dest:
                self.emit_line(f'char {dest};')
            self.emit_arg_check(src, dest, typ, f'(unlikely(!PyBool_Check({src}))) {{',
                                optional)
            self.emit_line(failure)
            self.emit_line('} else')
            conversion = f'{src} == Py_True'
            self.emit_line(f'    {dest} = {conversion};')
        elif is_none_rprimitive(typ):
            # Whether we are borrowing or not makes no difference.
            if declare_dest:
                self.emit_line(f'char {dest};')
            self.emit_arg_check(src, dest, typ, f'(unlikely({src} != Py_None)) {{',
                                optional)
            self.emit_line(failure)
            self.emit_line('} else')
            self.emit_line(f'    {dest} = 1;')
        elif isinstance(typ, RTuple):
            self.declare_tuple_struct(typ)
            if declare_dest:
                self.emit_line(f'{self.ctype(typ)} {dest};')
            # HACK: The error handling for unboxing tuples is busted
            # and instead of fixing it I am just wrapping it in the
            # cast code which I think is right. This is not good.
            if optional:
                self.emit_line(f'if ({src} == NULL) {{')
                self.emit_line(f'{dest} = {self.c_error_value(typ)};')
                self.emit_line('} else {')

            cast_temp = self.temp_name()
            self.emit_tuple_cast(src, cast_temp, typ, declare_dest=True, err='', src_type=None)
            self.emit_line(f'if (unlikely({cast_temp} == NULL)) {{')

            # self.emit_arg_check(src, dest, typ,
            #     '(!PyTuple_Check({}) || PyTuple_Size({}) != {}) {{'.format(
            #         src, src, len(typ.types)), optional)
            self.emit_line(failure)  # TODO: Decrease refcount?
            self.emit_line('} else {')
            if not typ.types:
                self.emit_line(f'{dest}.empty_struct_error_flag = 0;')
            for i, item_type in enumerate(typ.types):
                temp = self.temp_name()
                # emit_tuple_cast above checks the size, so this should not fail
                self.emit_line(f'PyObject *{temp} = PyTuple_GET_ITEM({src}, {i});')
                temp2 = self.temp_name()
                # Unbox or check the item.
                if item_type.is_unboxed:
                    self.emit_unbox(temp,
                                    temp2,
                                    item_type,
                                    raise_exception=raise_exception,
                                    error=error,
                                    declare_dest=True,
                                    borrow=borrow)
                else:
                    if not borrow:
                        self.emit_inc_ref(temp, object_rprimitive)
                    self.emit_cast(temp, temp2, item_type, declare_dest=True)
                self.emit_line(f'{dest}.f{i} = {temp2};')
            self.emit_line('}')
            if optional:
                self.emit_line('}')

        else:
            assert False, 'Unboxing not implemented: %s' % typ