Пример #1
0
def to_address(expr, arg, out_typ):
    # question: should this be allowed?
    if is_integer_type(arg.typ):
        if arg.typ._int_info.is_signed:
            _FAIL(arg.typ, out_typ, expr)

    # TODO once we introduce uint160, we can just check that arg
    # is unsigned, and then call to_int(expr, arg, uint160) because
    # the logic is equivalent.

    # disallow casting from Bytes[N>20]
    _check_bytes(expr, arg, out_typ, 32)

    if isinstance(arg.typ, ByteArrayType):
        arg_typ = arg.typ
        arg = _bytes_to_num(arg, out_typ, signed=False)
        # clamp after shift
        if arg_typ.maxlen > 20:
            arg = int_clamp(arg, 160, signed=False)

    if is_bytes_m_type(arg.typ):
        info = arg.typ._bytes_info
        arg = _bytes_to_num(arg, out_typ, signed=False)

        # clamp after shift
        if info.m > 20:
            arg = int_clamp(arg, 160, signed=False)

    elif is_integer_type(arg.typ):
        arg_info = arg.typ._int_info
        if arg_info.bits > 160 or arg_info.is_signed:
            arg = int_clamp(arg, 160, signed=False)

    return IRnode.from_list(arg, typ=out_typ)
Пример #2
0
def to_int(expr, arg, out_typ):
    int_info = out_typ._int_info

    assert int_info.bits % 8 == 0
    _check_bytes(expr, arg, out_typ, 32)

    if isinstance(expr, vy_ast.Constant):
        return _literal_int(expr, arg.typ, out_typ)

    elif isinstance(arg.typ, ByteArrayType):
        arg_typ = arg.typ
        arg = _bytes_to_num(arg, out_typ, signed=int_info.is_signed)
        if arg_typ.maxlen * 8 > int_info.bits:
            arg = int_clamp(arg, int_info.bits, signed=int_info.is_signed)

    elif is_bytes_m_type(arg.typ):
        arg_info = arg.typ._bytes_info
        arg = _bytes_to_num(arg, out_typ, signed=int_info.is_signed)
        if arg_info.m_bits > int_info.bits:
            arg = int_clamp(arg, int_info.bits, signed=int_info.is_signed)

    elif is_decimal_type(arg.typ):
        arg = _fixed_to_int(arg, out_typ)

    elif is_integer_type(arg.typ):
        arg = _int_to_int(arg, out_typ)

    elif is_base_type(arg.typ, "address"):
        if int_info.is_signed:
            # TODO if possible, refactor to move this validation close to the entry of the function
            _FAIL(arg.typ, out_typ, expr)
        if int_info.bits < 160:
            arg = int_clamp(arg, int_info.bits, signed=False)

    return IRnode.from_list(arg, typ=out_typ)
Пример #3
0
def to_enum(expr, arg, out_typ):
    if not is_base_type(arg.typ, "uint256"):
        _FAIL(arg.typ, out_typ, expr)

    if len(out_typ.members) < 256:
        arg = int_clamp(arg, bits=len(out_typ.members), signed=False)

    return IRnode.from_list(arg, typ=out_typ)
Пример #4
0
def _int_to_int(arg, out_typ):
    arg_info = arg.typ._int_info
    out_info = out_typ._int_info

    # do the same thing as
    # _clamp_numeric_convert(arg, arg_info.bounds, out_info.bounds, arg_info.is_signed)
    # but with better code size and gas.
    if arg_info.is_signed and not out_info.is_signed:

        # e.g. (clample (clampge arg 0) (2**128 - 1))

        # note that when out_info.bits == 256,
        # (clample arg 2**256 - 1) does not make sense.
        # see similar assertion in _clamp_numeric_convert.

        if out_info.bits < arg_info.bits:

            assert out_info.bits < 256, "unreachable"
            # note: because of the usage of signed=False, and the fact
            # that out_bits < 256 in this branch, below implies
            # not only (clample arg 2**128 - 1) but also (clampge arg 0).
            arg = int_clamp(arg, out_info.bits, signed=False)

        else:
            # note: this also works for out_bits == 256.
            arg = clamp("sge", arg, 0)

    elif not arg_info.is_signed and out_info.is_signed:
        # e.g. (uclample (uclampge arg 0) (2**127 - 1))
        # (note that (uclampge arg 0) always evaluates to true.)
        arg = int_clamp(arg, out_info.bits - 1, signed=False)

    elif out_info.bits < arg_info.bits:
        assert out_info.bits < 256, "unreachable"
        # narrowing conversion, signs are the same.
        # we can just use regular int clampers.
        arg = int_clamp(arg, out_info.bits, out_info.is_signed)

    else:
        # widening conversion, signs are the same.
        # we do not have to do any clamps.
        assert arg_info.is_signed == out_info.is_signed and out_info.bits >= arg_info.bits

    return IRnode.from_list(arg, typ=out_typ)
Пример #5
0
def _num_clamp(arg, dst_info, arg_info):
    if dst_info.is_signed != arg_info.is_signed:
        arg = _signedness_clamp(arg, arg_info.bits)

    # if, not elif (could be two clamps!)
    # TODO is it possible to make this more efficient?
    if dst_info.bits < arg_info.bits:
        arg = int_clamp(arg, dst_info.bits, dst_info.is_signed)

    return arg
Пример #6
0
def to_int128(expr, args, kwargs, context):
    in_arg = args[0]
    input_type, _ = get_type(in_arg)

    if input_type == "num_literal":
        if isinstance(in_arg, int):
            if not SizeLimits.in_bounds("int128", in_arg):
                raise InvalidLiteral(f"Number out of range: {in_arg}")
            return LLLnode.from_list(in_arg,
                                     typ=BaseType("int128"),
                                     pos=getpos(expr))
        elif isinstance(in_arg, Decimal):
            if not SizeLimits.in_bounds("int128", math.trunc(in_arg)):
                raise InvalidLiteral(
                    f"Number out of range: {math.trunc(in_arg)}")
            return LLLnode.from_list(math.trunc(in_arg),
                                     typ=BaseType("int128"),
                                     pos=getpos(expr))
        else:
            raise InvalidLiteral(f"Unknown numeric literal type: {in_arg}")

    elif input_type in ("bytes32", "int256"):
        if in_arg.typ.is_literal:
            if not SizeLimits.in_bounds("int128", in_arg.value):
                raise InvalidLiteral(f"Number out of range: {in_arg.value}",
                                     expr)
            else:
                return LLLnode.from_list(in_arg,
                                         typ=BaseType("int128"),
                                         pos=getpos(expr))
        else:
            # cast to output type so clamp_basetype works
            in_arg = LLLnode.from_list(in_arg, typ="int128")
            return LLLnode.from_list(
                clamp_basetype(in_arg),
                typ=BaseType("int128"),
                pos=getpos(expr),
            )

    # CMC 20211020: what is the purpose of this .. it lops off 32 bits
    elif input_type == "address":
        return LLLnode.from_list(
            ["signextend", 15, ["and", in_arg, (SizeLimits.ADDRSIZE - 1)]],
            typ=BaseType("int128"),
            pos=getpos(expr),
        )

    elif input_type in ("String", "Bytes"):
        if in_arg.typ.maxlen > 32:
            raise TypeMismatch(
                f"Cannot convert bytes array of max length {in_arg.typ.maxlen} to int128",
                expr,
            )
        return byte_array_to_num(in_arg, "int128")

    elif input_type == "uint256":
        if in_arg.typ.is_literal:
            if not SizeLimits.in_bounds("int128", in_arg.value):
                raise InvalidLiteral(f"Number out of range: {in_arg.value}",
                                     expr)
            else:
                return LLLnode.from_list(in_arg,
                                         typ=BaseType("int128"),
                                         pos=getpos(expr))

        # !! do not use clamp_basetype. check that 0 <= input <= MAX_INT128.
        res = int_clamp(in_arg, 127, signed=False)
        return LLLnode.from_list(
            res,
            typ="int128",
            pos=getpos(expr),
        )

    elif input_type == "decimal":
        # cast to int128 so clamp_basetype works
        res = LLLnode.from_list(["sdiv", in_arg, DECIMAL_DIVISOR],
                                typ="int128")
        return LLLnode.from_list(clamp_basetype(res),
                                 typ="int128",
                                 pos=getpos(expr))

    elif input_type in ("bool", "uint8"):
        # note: for int8, would need signextend
        return LLLnode.from_list(in_arg,
                                 typ=BaseType("int128"),
                                 pos=getpos(expr))

    else:
        raise InvalidLiteral(f"Invalid input for int128: {in_arg}", expr)
Пример #7
0
def _signedness_clamp(arg, bits):
    return int_clamp(arg, bits=bits - 1, signed=False)