Exemplo n.º 1
0
    def parse_AnnAssign(self):
        typ = parse_type(
            self.stmt.annotation,
            sigs=self.context.sigs,
            custom_structs=self.context.structs,
        )
        varname = self.stmt.target.id
        pos = self.context.new_variable(varname, typ)
        if self.stmt.value is None:
            return

        sub = Expr(self.stmt.value, self.context).ir_node

        is_literal_bytes32_assign = (isinstance(sub.typ, ByteArrayType)
                                     and sub.typ.maxlen == 32
                                     and isinstance(typ, BaseType)
                                     and typ.typ == "bytes32"
                                     and sub.typ.is_literal)

        # If bytes[32] to bytes32 assignment rewrite sub as bytes32.
        if is_literal_bytes32_assign:
            sub = IRnode(
                util.bytes_to_int(self.stmt.value.s),
                typ=BaseType("bytes32"),
            )

        variable_loc = IRnode.from_list(pos, typ=typ, location=MEMORY)

        ir_node = make_setter(variable_loc, sub)

        return ir_node
Exemplo n.º 2
0
    def _assert_reason(self, test_expr, msg):
        if isinstance(msg, vy_ast.Name) and msg.id == "UNREACHABLE":
            return IRnode.from_list(["assert_unreachable", test_expr],
                                    error_msg="assert unreachable")

        # set constant so that revert reason str is well behaved
        try:
            tmp = self.context.constancy
            self.context.constancy = Constancy.Constant
            msg_ir = Expr(msg, self.context).ir_node
        finally:
            self.context.constancy = tmp

        # TODO this is probably useful in codegen.core
        # compare with eval_seq.
        def _get_last(ir):
            if len(ir.args) == 0:
                return ir.value
            return _get_last(ir.args[-1])

        # TODO maybe use ensure_in_memory
        if msg_ir.location != MEMORY:
            buf = self.context.new_internal_variable(msg_ir.typ)
            instantiate_msg = make_byte_array_copier(buf, msg_ir)
        else:
            buf = _get_last(msg_ir)
            if not isinstance(buf, int):
                raise CompilerPanic(f"invalid bytestring {buf}\n{self}")
            instantiate_msg = msg_ir

        # offset of bytes in (bytes,)
        method_id = util.abi_method_id("Error(string)")

        # abi encode method_id + bytestring
        assert buf >= 36, "invalid buffer"
        # we don't mind overwriting other memory because we are
        # getting out of here anyway.
        _runtime_length = ["mload", buf]
        revert_seq = [
            "seq",
            instantiate_msg,
            zero_pad(buf),
            ["mstore", buf - 64, method_id],
            ["mstore", buf - 32, 0x20],
            [
                "revert", buf - 36,
                ["add", 4 + 32 + 32, ["ceil32", _runtime_length]]
            ],
        ]

        if test_expr is not None:
            ir_node = ["if", ["iszero", test_expr], revert_seq]
        else:
            ir_node = revert_seq

        return IRnode.from_list(ir_node, error_msg="user revert with reason")
Exemplo n.º 3
0
    def _parse_For_range(self):
        # attempt to use the type specified by type checking, fall back to `int256`
        # this is a stopgap solution to allow uint256 - it will be properly solved
        # once we refactor type system
        iter_typ = "int256"
        if "type" in self.stmt.target._metadata:
            iter_typ = self.stmt.target._metadata["type"]._id

        # Get arg0
        arg0 = self.stmt.iter.args[0]
        num_of_args = len(self.stmt.iter.args)

        # Type 1 for, e.g. for i in range(10): ...
        if num_of_args == 1:
            arg0_val = self._get_range_const_value(arg0)
            start = IRnode.from_list(0, typ=iter_typ)
            rounds = arg0_val

        # Type 2 for, e.g. for i in range(100, 110): ...
        elif self._check_valid_range_constant(self.stmt.iter.args[1],
                                              raise_exception=False)[0]:
            arg0_val = self._get_range_const_value(arg0)
            arg1_val = self._get_range_const_value(self.stmt.iter.args[1])
            start = IRnode.from_list(arg0_val, typ=iter_typ)
            rounds = IRnode.from_list(arg1_val - arg0_val, typ=iter_typ)

        # Type 3 for, e.g. for i in range(x, x + 10): ...
        else:
            arg1 = self.stmt.iter.args[1]
            rounds = self._get_range_const_value(arg1.right)
            start = Expr.parse_value_expr(arg0, self.context)

        r = rounds if isinstance(rounds, int) else rounds.value
        if r < 1:
            return

        varname = self.stmt.target.id
        i = IRnode.from_list(self.context.fresh_varname("range_ix"),
                             typ="uint256")
        iptr = self.context.new_variable(varname, BaseType(iter_typ))

        self.context.forvars[varname] = True

        loop_body = ["seq"]
        # store the current value of i so it is accessible to userland
        loop_body.append(["mstore", iptr, i])
        loop_body.append(parse_body(self.stmt.body, self.context))

        ir_node = IRnode.from_list(
            ["repeat", i, start, rounds, rounds, loop_body])
        del self.context.forvars[varname]

        return ir_node
Exemplo n.º 4
0
    def _parse_For_list(self):
        with self.context.range_scope():
            iter_list = Expr(self.stmt.iter, self.context).ir_node

        # override with type inferred at typechecking time
        # TODO investigate why stmt.target.type != stmt.iter.type.subtype
        target_type = new_type_to_old_type(self.stmt.target._metadata["type"])
        iter_list.typ.subtype = target_type

        # user-supplied name for loop variable
        varname = self.stmt.target.id
        loop_var = IRnode.from_list(self.context.new_variable(
            varname, target_type),
                                    typ=target_type,
                                    location=MEMORY)

        i = IRnode.from_list(self.context.fresh_varname("for_list_ix"),
                             typ="uint256")

        self.context.forvars[varname] = True

        ret = ["seq"]

        # list literal, force it to memory first
        if isinstance(self.stmt.iter, vy_ast.List):
            tmp_list = IRnode.from_list(
                self.context.new_internal_variable(iter_list.typ),
                typ=iter_list.typ,
                location=MEMORY,
            )
            ret.append(make_setter(tmp_list, iter_list))
            iter_list = tmp_list

        # set up the loop variable
        e = get_element_ptr(iter_list, i, array_bounds_check=False)
        body = [
            "seq",
            make_setter(loop_var, e),
            parse_body(self.stmt.body, self.context),
        ]

        repeat_bound = iter_list.typ.count
        if isinstance(iter_list.typ, DArrayType):
            array_len = get_dyn_array_count(iter_list)
        else:
            array_len = repeat_bound

        ret.append(["repeat", i, 0, array_len, repeat_bound, body])

        del self.context.forvars[varname]
        return IRnode.from_list(ret)
Exemplo n.º 5
0
    def parse_Assert(self):
        test_expr = Expr.parse_value_expr(self.stmt.test, self.context)
        if test_expr.typ.is_literal:
            if test_expr.value == 1:
                # skip literal assertions that always pass
                # TODO move this to optimizer
                return IRnode.from_list(["pass"])
            else:
                test_expr = test_expr.value

        if self.stmt.msg:
            return self._assert_reason(test_expr, self.stmt.msg)
        else:
            return IRnode.from_list(["assert", test_expr])
Exemplo n.º 6
0
def convert(expr, context):
    if len(expr.args) != 2:
        raise StructureException(
            "The convert function expects two parameters.", expr)

    arg_ast = expr.args[0]
    arg = Expr(arg_ast, context).ir_node
    out_typ = context.parse_type(expr.args[1])

    if isinstance(arg.typ, BaseType):
        arg = unwrap_location(arg)
    with arg.cache_when_complex("arg") as (b, arg):
        if is_base_type(out_typ, "bool"):
            ret = to_bool(arg_ast, arg, out_typ)
        elif is_base_type(out_typ, "address"):
            ret = to_address(arg_ast, arg, out_typ)
        elif is_integer_type(out_typ):
            ret = to_int(arg_ast, arg, out_typ)
        elif is_bytes_m_type(out_typ):
            ret = to_bytes_m(arg_ast, arg, out_typ)
        elif is_decimal_type(out_typ):
            ret = to_decimal(arg_ast, arg, out_typ)
        elif isinstance(out_typ, ByteArrayType):
            ret = to_bytes(arg_ast, arg, out_typ)
        elif isinstance(out_typ, StringType):
            ret = to_string(arg_ast, arg, out_typ)
        else:
            raise StructureException(f"Conversion to {out_typ} is invalid.",
                                     arg_ast)

        ret = b.resolve(ret)

    return IRnode.from_list(ret)
Exemplo n.º 7
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)
Exemplo n.º 8
0
def to_bytes(expr, arg, out_typ):
    _check_bytes(expr, arg, out_typ, out_typ.maxlen)

    # TODO: more casts

    # NOTE: this is a pointer cast
    return IRnode.from_list(arg, typ=out_typ)
Exemplo n.º 9
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)
Exemplo n.º 10
0
    def parse_Assert(self):
        test_expr = Expr.parse_value_expr(self.stmt.test, self.context)

        if self.stmt.msg:
            return self._assert_reason(test_expr, self.stmt.msg)
        else:
            return IRnode.from_list(["assert", test_expr])
Exemplo n.º 11
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)
Exemplo n.º 12
0
def to_bytes_m(expr, arg, out_typ):
    out_info = out_typ._bytes_info

    _check_bytes(expr, arg, out_typ, max_bytes_allowed=out_info.m)

    if isinstance(arg.typ, ByteArrayType):
        bytes_val = LOAD(bytes_data_ptr(arg))

        # zero out any dirty bytes (which can happen in the last
        # word of a bytearray)
        len_ = get_bytearray_length(arg)
        num_zero_bits = IRnode.from_list(["mul", ["sub", 32, len_], 8])
        with num_zero_bits.cache_when_complex("bits") as (b, num_zero_bits):
            arg = shl(num_zero_bits, shr(num_zero_bits, bytes_val))
            arg = b.resolve(arg)

    elif is_bytes_m_type(arg.typ):
        arg_info = arg.typ._bytes_info
        # clamp if it's a downcast
        if arg_info.m > out_info.m:
            arg = bytes_clamp(arg, out_info.m)

    elif is_integer_type(arg.typ) or is_base_type(arg.typ, "address"):
        int_bits = arg.typ._int_info.bits

        if out_info.m_bits < int_bits:
            # question: allow with runtime clamp?
            # arg = int_clamp(m_bits, signed=int_info.signed)
            _FAIL(arg.typ, out_typ, expr)

        # note: neg numbers not OOB. keep sign bit
        arg = shl(256 - out_info.m_bits, arg)

    elif is_decimal_type(arg.typ):
        if out_info.m_bits < arg.typ._decimal_info.bits:
            _FAIL(arg.typ, out_typ, expr)

        # note: neg numbers not OOB. keep sign bit
        arg = shl(256 - out_info.m_bits, arg)

    else:
        # bool
        arg = shl(256 - out_info.m_bits, arg)

    return IRnode.from_list(arg, typ=out_typ)
Exemplo n.º 13
0
def convert(expr, context):
    if len(expr.args) != 2:
        raise StructureException(
            "The convert function expects two parameters.", expr)

    arg_ast = expr.args[0]
    arg = Expr(arg_ast, context).ir_node
    original_arg = arg
    out_typ = context.parse_type(expr.args[1])

    if isinstance(arg.typ, BaseType):
        arg = unwrap_location(arg)
    with arg.cache_when_complex("arg") as (b, arg):
        if is_base_type(out_typ, "bool"):
            ret = to_bool(arg_ast, arg, out_typ)
        elif is_base_type(out_typ, "address"):
            ret = to_address(arg_ast, arg, out_typ)
        elif isinstance(out_typ, EnumType):
            ret = to_enum(arg_ast, arg, out_typ)
        elif is_integer_type(out_typ):
            ret = to_int(arg_ast, arg, out_typ)
        elif is_bytes_m_type(out_typ):
            ret = to_bytes_m(arg_ast, arg, out_typ)
        elif is_decimal_type(out_typ):
            ret = to_decimal(arg_ast, arg, out_typ)
        elif isinstance(out_typ, ByteArrayType):
            ret = to_bytes(arg_ast, arg, out_typ)
        elif isinstance(out_typ, StringType):
            ret = to_string(arg_ast, arg, out_typ)
        else:
            raise StructureException(f"Conversion to {out_typ} is invalid.",
                                     arg_ast)

        # test if arg actually changed. if not, we do not need to use
        # unwrap_location (this can reduce memory traffic for downstream
        # operations which are in-place, like the returndata routine)
        test_arg = IRnode.from_list(arg, typ=out_typ)
        if test_arg == ret:
            original_arg.typ = out_typ
            return original_arg

        return IRnode.from_list(b.resolve(ret))
Exemplo n.º 14
0
def _int_to_fixed(x, out_typ):
    info = out_typ._decimal_info

    lo, hi = info.bounds
    decimals = info.decimals

    clamp_op = "clamp" if info.is_signed else "uclamp"

    # TODO is this clamp redundant with later num clamps?
    return IRnode.from_list(["mul", [clamp_op, lo, x, hi], 10**decimals],
                            typ=out_typ)
Exemplo n.º 15
0
def to_bool(expr, arg, out_typ):
    _check_bytes(expr, arg, out_typ, 32)  # should we restrict to Bytes[1]?

    if isinstance(arg.typ, ByteArrayType):
        # no clamp. checks for any nonzero bytes.
        arg = _bytes_to_num(arg, out_typ, signed=False)

    # NOTE: for decimal, the behavior is x != 0.0,
    # (we do not issue an `sdiv DECIMAL_DIVISOR`)

    return IRnode.from_list(["iszero", ["iszero", arg]], typ=out_typ)
Exemplo n.º 16
0
    def parse_If(self):
        if self.stmt.orelse:
            with self.context.block_scope():
                add_on = [parse_body(self.stmt.orelse, self.context)]
        else:
            add_on = []

        with self.context.block_scope():
            test_expr = Expr.parse_value_expr(self.stmt.test, self.context)
            body = ["if", test_expr,
                    parse_body(self.stmt.body, self.context)] + add_on
            ir_node = IRnode.from_list(body)
        return ir_node
Exemplo n.º 17
0
def _int_to_fixed(arg, out_typ):
    arg_info = arg.typ._int_info
    out_info = out_typ._decimal_info

    DIVISOR = out_info.divisor

    # block inputs which are out of bounds before promotion
    out_lo, out_hi = out_info.bounds
    out_lo = round_towards_zero(out_lo / decimal.Decimal(DIVISOR))
    out_hi = round_towards_zero(out_hi / decimal.Decimal(DIVISOR))

    clamped_arg = _clamp_numeric_convert(arg, arg_info.bounds, (out_lo, out_hi), arg_info.is_signed)

    return IRnode.from_list(["mul", clamped_arg, DIVISOR], typ=out_typ)
Exemplo n.º 18
0
def _literal_int(expr, out_typ):
    # TODO: possible to reuse machinery from expr.py?
    int_info = out_typ._int_info
    if isinstance(expr, vy_ast.Hex):
        val = int(expr.value, 16)
    elif isinstance(expr, vy_ast.Bytes):
        val = int.from_bytes(expr.value, "big")
    else:
        # Int, Decimal
        val = int(expr.value)
    (lo, hi) = int_info.bounds
    if not (lo <= val <= hi):
        raise InvalidLiteral("Number out of range", expr)
    return IRnode.from_list(val, typ=out_typ)
Exemplo n.º 19
0
def _literal_decimal(expr, out_typ):
    # TODO: possible to reuse machinery from expr.py?
    if isinstance(expr, vy_ast.Hex):
        val = decimal.Decimal(int(expr.value, 16))
    else:
        val = decimal.Decimal(expr.value)  # should work for Int, Decimal

    val = val * DECIMAL_DIVISOR

    if not SizeLimits.in_bounds("decimal", val):
        raise InvalidLiteral("Number out of range", expr)

    # sanity check type checker did its job
    assert math.ceil(val) == math.floor(val)

    return IRnode.from_list(int(val), typ=out_typ)
Exemplo n.º 20
0
def _fixed_to_int(arg, out_typ):
    arg_info = arg.typ._decimal_info
    out_info = out_typ._int_info

    DIVISOR = arg_info.divisor

    # block inputs which are out of bounds before truncation.
    # e.g., convert(255.1, uint8) should revert or fail to compile.
    out_lo, out_hi = out_info.bounds
    out_lo = out_lo * DIVISOR
    out_hi = out_hi * DIVISOR

    clamped_arg = _clamp_numeric_convert(arg, arg_info.bounds, (out_lo, out_hi), arg_info.is_signed)

    assert arg_info.is_signed, "should use unsigned div"  # stub in case we ever add ufixed
    return IRnode.from_list(["sdiv", clamped_arg, DIVISOR], typ=out_typ)
Exemplo n.º 21
0
def parse_body(code, context, ensure_terminated=False):
    if not isinstance(code, list):
        return parse_stmt(code, context)

    ir_node = ["seq"]
    for stmt in code:
        ir = parse_stmt(stmt, context)
        ir_node.append(ir)

    # force using the return routine / exit_to cleanup for end of function
    if ensure_terminated and context.return_type is None and not _is_terminated(
            code):
        ir_node.append(parse_stmt(vy_ast.Return(value=None), context))

    # force zerovalent, even last statement
    ir_node.append("pass")  # CMC 2022-01-16 is this necessary?
    return IRnode.from_list(ir_node)
Exemplo n.º 22
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)
Exemplo n.º 23
0
    def parse_AugAssign(self):
        target = self._get_target(self.stmt.target)
        sub = Expr.parse_value_expr(self.stmt.value, self.context)
        if not isinstance(target.typ, BaseType):
            return

        with target.cache_when_complex("_loc") as (b, target):
            rhs = Expr.parse_value_expr(
                vy_ast.BinOp(
                    left=IRnode.from_list(LOAD(target), typ=target.typ),
                    right=sub,
                    op=self.stmt.op,
                    lineno=self.stmt.lineno,
                    col_offset=self.stmt.col_offset,
                    end_lineno=self.stmt.end_lineno,
                    end_col_offset=self.stmt.end_col_offset,
                    node_source_code=self.stmt.get("node_source_code"),
                ),
                self.context,
            )
            return b.resolve(STORE(target, rhs))
Exemplo n.º 24
0
def _literal_decimal(expr, arg_typ, out_typ):
    if isinstance(expr, vy_ast.Hex):
        val = decimal.Decimal(int(expr.value, 16))
    else:
        val = decimal.Decimal(expr.value)  # should work for Int, Decimal
        val *= DECIMAL_DIVISOR

    # sanity check type checker did its job
    assert math.ceil(val) == math.floor(val)

    val = int(val)

    # apply sign extension, if expected
    out_info = out_typ._decimal_info
    if isinstance(expr, (vy_ast.Hex, vy_ast.Bytes)) and out_info.is_signed:
        val = _signextend(expr, val, arg_typ)

    if not SizeLimits.in_bounds("decimal", val):
        raise InvalidLiteral("Number out of range", expr)

    return IRnode.from_list(val, typ=out_typ)
Exemplo n.º 25
0
def to_decimal(expr, arg, out_typ):
    # question: is converting from Bytes to decimal allowed?
    _check_bytes(expr, arg, out_typ, max_bytes_allowed=16)

    if isinstance(expr, vy_ast.Constant):
        return _literal_decimal(expr, out_typ)

    if isinstance(arg.typ, ByteArrayType):
        arg_typ = arg.typ
        arg = _bytes_to_num(arg, out_typ, signed=True)
        # TODO revisit this condition once we have more decimal types
        # and decimal bounds expand
        # will be something like: if info.m_bits > 168
        if arg_typ.maxlen * 8 > 128:
            arg = IRnode.from_list(arg, typ=out_typ)
            arg = clamp_basetype(arg)

        return IRnode.from_list(arg, typ=out_typ)

    elif is_bytes_m_type(arg.typ):
        info = arg.typ._bytes_info
        arg = _bytes_to_num(arg, out_typ, signed=True)
        # TODO revisit this condition once we have more decimal types
        # and decimal bounds expand
        # will be something like: if info.m_bits > 168
        if info.m_bits > 128:
            arg = IRnode.from_list(arg, typ=out_typ)
            arg = clamp_basetype(arg)

        return IRnode.from_list(arg, typ=out_typ)

    elif is_integer_type(arg.typ):
        int_info = arg.typ._int_info
        arg = _int_to_fixed(arg, out_typ)
        out_info = out_typ._decimal_info
        if int_info.bits > out_info.bits:
            # TODO: _num_clamp probably not necessary bc already
            # clamped in _int_to_fixed
            arg = _num_clamp(arg, out_info, int_info)
        return IRnode.from_list(arg, typ=out_typ)

    elif is_base_type(arg.typ, "bool"):
        arg = _int_to_fixed(arg, out_typ)
        return IRnode.from_list(arg, typ=out_typ)
    else:
        raise CompilerPanic("unreachable")  # pragma: notest
Exemplo n.º 26
0
def _literal_int(expr, arg_typ, out_typ):
    # TODO: possible to reuse machinery from expr.py?
    int_info = out_typ._int_info
    if isinstance(expr, vy_ast.Hex):
        val = int(expr.value, 16)
    elif isinstance(expr, vy_ast.Bytes):
        val = int.from_bytes(expr.value, "big")
    elif isinstance(expr, (vy_ast.Int, vy_ast.Decimal, vy_ast.NameConstant)):
        val = expr.value
    else:  # pragma: no cover
        raise CompilerPanic("unreachable")

    if isinstance(expr, (vy_ast.Hex, vy_ast.Bytes)) and int_info.is_signed:
        val = _signextend(expr, val, arg_typ)

    (lo, hi) = int_info.bounds
    if not (lo <= val <= hi):
        raise InvalidLiteral("Number out of range", expr)

    # cast to int AFTER bounds check (ensures decimal is in bounds before truncation)
    val = int(val)

    return IRnode.from_list(val, typ=out_typ)
Exemplo n.º 27
0
def _bytes_to_num(arg, out_typ, signed):
    # converting a bytestring to a number:
    # bytestring and bytes_m are right-padded with zeroes, int is left-padded.
    # convert by shr or sar the number of zero bytes (converted to bits)
    # e.g. "abcd000000000000" -> bitcast(000000000000abcd, output_type)

    if isinstance(arg.typ, ByteArrayLike):
        _len = get_bytearray_length(arg)
        arg = LOAD(bytes_data_ptr(arg))
        num_zero_bits = ["mul", 8, ["sub", 32, _len]]
    elif is_bytes_m_type(arg.typ):
        info = arg.typ._bytes_info
        num_zero_bits = 8 * (32 - info.m)
    else:
        raise CompilerPanic("unreachable")  # pragma: notest

    if signed:
        ret = sar(num_zero_bits, arg)
    else:
        ret = shr(num_zero_bits, arg)

    annotation = (f"__intrinsic__byte_array_to_num({out_typ})", )
    return IRnode.from_list(ret, annotation=annotation)
Exemplo n.º 28
0
def to_decimal(expr, arg, out_typ):
    _check_bytes(expr, arg, out_typ, 32)

    out_info = out_typ._decimal_info

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

    if isinstance(arg.typ, ByteArrayType):
        arg_typ = arg.typ
        arg = _bytes_to_num(arg, out_typ, signed=True)
        if arg_typ.maxlen * 8 > 168:
            arg = IRnode.from_list(arg, typ=out_typ)
            arg = clamp_basetype(arg)

        return IRnode.from_list(arg, typ=out_typ)

    elif is_bytes_m_type(arg.typ):
        info = arg.typ._bytes_info
        arg = _bytes_to_num(arg, out_typ, signed=True)
        if info.m_bits > 168:
            arg = IRnode.from_list(arg, typ=out_typ)
            arg = clamp_basetype(arg)

        return IRnode.from_list(arg, typ=out_typ)

    elif is_integer_type(arg.typ):
        arg = _int_to_fixed(arg, out_typ)
        return IRnode.from_list(arg, typ=out_typ)

    elif is_base_type(arg.typ, "bool"):
        # TODO: consider adding _int_info to bool so we can use _int_to_fixed
        arg = ["mul", arg, 10**out_info.decimals]
        return IRnode.from_list(arg, typ=out_typ)
    else:
        raise CompilerPanic("unreachable")  # pragma: notest
Exemplo n.º 29
0
 def parse_Name(self):
     if self.stmt.id == "vdb":
         return IRnode("debugger")
     else:
         raise StructureException(
             f"Unsupported statement type: {type(self.stmt)}", self.stmt)
Exemplo n.º 30
0
 def parse_Pass(self):
     return IRnode.from_list("pass")