Exemple #1
0
    def parse_Call(self):
        is_self_function = ((isinstance(self.stmt.func, vy_ast.Attribute))
                            and isinstance(self.stmt.func.value, vy_ast.Name)
                            and self.stmt.func.value.id == "self")

        if isinstance(self.stmt.func, vy_ast.Name):
            funcname = self.stmt.func.id
            return STMT_DISPATCH_TABLE[funcname].build_LLL(
                self.stmt, self.context)

        elif isinstance(self.stmt.func,
                        vy_ast.Attribute) and self.stmt.func.attr in (
                            "append",
                            "pop",
                        ):
            darray = Expr(self.stmt.func.value, self.context).lll_node
            args = [Expr(x, self.context).lll_node for x in self.stmt.args]
            if self.stmt.func.attr == "append":
                assert len(args) == 1
                arg = args[0]
                assert isinstance(darray.typ, DArrayType)
                assert arg.typ == darray.typ.subtype
                return append_dyn_array(darray, arg, pos=getpos(self.stmt))
            else:
                assert len(args) == 0
                return pop_dyn_array(darray,
                                     return_popped_item=False,
                                     pos=getpos(self.stmt))

        elif is_self_function:
            return self_call.lll_for_self_call(self.stmt, self.context)
        else:
            return external_call.lll_for_external_call(self.stmt, self.context)
Exemple #2
0
    def parse_Subscript(self):
        sub = Expr(self.expr.value, self.context).lll_node
        if sub.value == "multi":
            # force literal to memory, e.g.
            # MY_LIST: constant(decimal[6])
            # ...
            # return MY_LIST[ix]
            sub = ensure_in_memory(sub, self.context, pos=getpos(self.expr))

        if isinstance(sub.typ, MappingType):
            # TODO sanity check we are in a self.my_map[i] situation
            index = Expr.parse_value_expr(self.expr.slice.value, self.context)
            if isinstance(index.typ, ByteArrayLike):
                # we have to hash the key to get a storage location
                assert len(index.args) == 1
                index = keccak256_helper(self.expr.slice.value, index.args[0],
                                         self.context)

        elif isinstance(sub.typ, ArrayLike):
            index = Expr.parse_value_expr(self.expr.slice.value, self.context)

        elif isinstance(sub.typ, TupleType):
            index = self.expr.slice.value.n
            # note: this check should also happen in get_element_ptr
            if not 0 <= index < len(sub.typ.members):
                return
        else:
            return

        lll_node = get_element_ptr(sub, index, pos=getpos(self.expr))
        lll_node.mutable = sub.mutable
        return lll_node
Exemple #3
0
    def parse_Name(self):

        if self.expr.id == "self":
            return LLLnode.from_list(["address"],
                                     typ="address",
                                     pos=getpos(self.expr))
        elif self.expr.id in self.context.vars:
            var = self.context.vars[self.expr.id]
            return LLLnode.from_list(
                var.pos,
                typ=var.typ,
                location=var.
                location,  # either 'memory' or 'calldata' storage is handled above.
                encoding=var.encoding,
                pos=getpos(self.expr),
                annotation=self.expr.id,
                mutable=var.mutable,
            )

        elif self.expr.id in BUILTIN_CONSTANTS:
            obj, typ = BUILTIN_CONSTANTS[self.expr.id]
            return LLLnode.from_list([obj],
                                     typ=BaseType(typ, is_literal=True),
                                     pos=getpos(self.expr))
        elif self.expr._metadata["type"].is_immutable:
            # immutable variable
            # need to handle constructor and outside constructor
            var = self.context.globals[self.expr.id]
            is_constructor = self.expr.get_ancestor(
                vy_ast.FunctionDef).get("name") == "__init__"
            if is_constructor:
                # store memory position for later access in module.py in the variable record
                memory_loc = self.context.new_variable(self.expr.id, var.typ)
                self.context.global_ctx._globals[self.expr.id].pos = memory_loc
                # store the data offset in the variable record as well for accessing
                data_offset = self.expr._metadata["type"].position.offset
                self.context.global_ctx._globals[
                    self.expr.id].data_offset = data_offset

                return LLLnode.from_list(
                    memory_loc,
                    typ=var.typ,
                    location="memory",
                    pos=getpos(self.expr),
                    annotation=self.expr.id,
                    mutable=True,
                )
            else:
                immutable_section_size = self.context.global_ctx.immutable_section_size
                offset = self.expr._metadata["type"].position.offset
                # TODO: resolve code offsets for immutables at compile time
                return LLLnode.from_list(
                    ["sub", "codesize", immutable_section_size - offset],
                    typ=var.typ,
                    location="code",
                    pos=getpos(self.expr),
                    annotation=self.expr.id,
                    mutable=False,
                )
Exemple #4
0
    def parse_Assign(self):
        # Assignment (e.g. x[4] = y)
        sub = Expr(self.stmt.value, self.context).lll_node
        target = self._get_target(self.stmt.target)

        lll_node = make_setter(target, sub, pos=getpos(self.stmt))
        lll_node.pos = getpos(self.stmt)
        return lll_node
Exemple #5
0
    def handler_for(calldata_kwargs, default_kwargs):
        calldata_args = sig.base_args + calldata_kwargs
        # create a fake type so that get_element_ptr works
        calldata_args_t = TupleType(list(arg.typ for arg in calldata_args))

        abi_sig = sig.abi_signature_for_kwargs(calldata_kwargs)
        method_id = _annotated_method_id(abi_sig)

        calldata_kwargs_ofst = IRnode(
            4, location=CALLDATA, typ=calldata_args_t, encoding=Encoding.ABI
        )

        # a sequence of statements to strictify kwargs into memory
        ret = ["seq"]

        # ensure calldata is at least of minimum length
        args_abi_t = calldata_args_t.abi_type
        calldata_min_size = args_abi_t.min_size() + 4
        if args_abi_t.is_dynamic():
            ret.append(["assert", ["ge", "calldatasize", calldata_min_size]])
        else:
            # stricter for static data
            ret.append(["assert", ["eq", "calldatasize", calldata_min_size]])

        # TODO optimize make_setter by using
        # TupleType(list(arg.typ for arg in calldata_kwargs + default_kwargs))
        # (must ensure memory area is contiguous)

        n_base_args = len(sig.base_args)

        for i, arg_meta in enumerate(calldata_kwargs):
            k = n_base_args + i

            dst = context.lookup_var(arg_meta.name).pos

            lhs = IRnode(dst, location=MEMORY, typ=arg_meta.typ)

            rhs = get_element_ptr(calldata_kwargs_ofst, k, array_bounds_check=False)

            copy_arg = make_setter(lhs, rhs)
            copy_arg.source_pos = getpos(arg_meta.ast_source)
            ret.append(copy_arg)

        for x in default_kwargs:
            dst = context.lookup_var(x.name).pos
            lhs = IRnode(dst, location=MEMORY, typ=x.typ)
            lhs.source_pos = getpos(x.ast_source)
            kw_ast_val = sig.default_values[x.name]  # e.g. `3` in x: int = 3
            rhs = Expr(kw_ast_val, context).ir_node

            copy_arg = make_setter(lhs, rhs)
            copy_arg.source_pos = getpos(x.ast_source)
            ret.append(copy_arg)

        ret.append(["goto", sig.external_function_base_entry_label])

        ret = ["if", ["eq", "_calldata_method_id", method_id], ret]
        return ret
Exemple #6
0
def generate_lll_for_external_function(code, sig, context, check_nonpayable):
    # TODO type hints:
    # def generate_lll_for_external_function(
    #    code: vy_ast.FunctionDef, sig: FunctionSignature, context: Context, check_nonpayable: bool,
    # ) -> LLLnode:
    """Return the LLL for an external function. Includes code to inspect the method_id,
    enter the function (nonpayable and reentrancy checks), handle kwargs and exit
    the function (clean up reentrancy storage variables)
    """
    func_type = code._metadata["type"]
    pos = getpos(code)

    nonreentrant_pre, nonreentrant_post = get_nonreentrant_lock(func_type)

    # generate handlers for base args and register the variable records
    handle_base_args = _register_function_args(context, sig)

    # generate handlers for kwargs and register the variable records
    kwarg_handlers = _generate_kwarg_handlers(context, sig, pos)

    # once optional args have been handled,
    # generate the main body of the function
    entrance = [["label", sig.external_function_base_entry_label]]

    entrance += handle_base_args

    if check_nonpayable and sig.mutability != "payable":
        # if the contract contains payable functions, but this is not one of them
        # add an assertion that the value of the call is zero
        entrance += [["assert", ["iszero", "callvalue"]]]

    entrance += nonreentrant_pre

    body = [parse_body(c, context) for c in code.body]

    exit = [["label", sig.exit_sequence_label]] + nonreentrant_post
    if sig.is_init_func:
        pass  # init func has special exit sequence generated by module.py
    elif context.return_type is None:
        exit += [["stop"]]
    else:
        # ret_ofst and ret_len stack items passed by function body; consume using 'pass'
        exit += [["return", "pass", "pass"]]

    # the lll which comprises the main body of the function,
    # besides any kwarg handling
    func_common_lll = ["seq"] + entrance + body + exit

    if sig.is_default_func or sig.is_init_func:
        # default and init funcs have special entries generated by module.py
        ret = func_common_lll
    else:
        ret = kwarg_handlers
        # sneak the base code into the kwarg handler
        # TODO rethink this / make it clearer
        ret[-1][-1].append(func_common_lll)

    return LLLnode.from_list(ret, pos=getpos(code))
Exemple #7
0
    def _assert_reason(self, test_expr, msg):
        if isinstance(msg, vy_ast.Name) and msg.id == "UNREACHABLE":
            return LLLnode.from_list(["assert_unreachable", test_expr],
                                     typ=None,
                                     pos=getpos(msg))

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

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

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

        # 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:
            lll_node = ["if", ["iszero", test_expr], revert_seq]
        else:
            lll_node = revert_seq

        return LLLnode.from_list(lll_node, typ=None, pos=getpos(self.stmt))
Exemple #8
0
    def _parse_For_list(self):
        with self.context.range_scope():
            iter_list = Expr(self.stmt.iter, self.context).lll_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 = LLLnode.from_list(
            self.context.new_variable(varname, target_type),
            typ=target_type,
            location="memory",
        )

        i = LLLnode.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 = LLLnode.from_list(
                self.context.new_internal_variable(iter_list.typ),
                typ=iter_list.typ,
                location="memory",
            )
            ret.append(make_setter(tmp_list, iter_list, pos=getpos(self.stmt)))
            iter_list = tmp_list

        # set up the loop variable
        loop_var_ast = getpos(self.stmt.target)
        e = get_element_ptr(iter_list,
                            i,
                            array_bounds_check=False,
                            pos=loop_var_ast)
        body = [
            "seq",
            make_setter(loop_var, e, pos=loop_var_ast),
            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 LLLnode.from_list(ret, pos=getpos(self.stmt))
Exemple #9
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
     if target.location == "storage":
         lll_node = Expr.parse_value_expr(
             vy_ast.BinOp(
                 left=LLLnode.from_list(["sload", "_stloc"],
                                        typ=target.typ,
                                        pos=target.pos),
                 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 LLLnode.from_list(
             [
                 "with", "_stloc", target,
                 ["sstore", "_stloc",
                  unwrap_location(lll_node)]
             ],
             typ=None,
             pos=getpos(self.stmt),
         )
     elif target.location == "memory":
         lll_node = Expr.parse_value_expr(
             vy_ast.BinOp(
                 left=LLLnode.from_list(["mload", "_mloc"],
                                        typ=target.typ,
                                        pos=target.pos),
                 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 LLLnode.from_list(
             [
                 "with", "_mloc", target,
                 ["mstore", "_mloc",
                  unwrap_location(lll_node)]
             ],
             typ=None,
             pos=getpos(self.stmt),
         )
Exemple #10
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 = LLLnode.from_list(0, typ=iter_typ, pos=getpos(self.stmt))
            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 = LLLnode.from_list(arg0_val, typ=iter_typ, pos=getpos(self.stmt))
            rounds = LLLnode.from_list(arg1_val - arg0_val, typ=iter_typ, pos=getpos(self.stmt))

        # 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 = LLLnode.from_list(self.context.fresh_varname("range_ix"), typ="uint256")
        iptr = self.context.new_variable(varname, BaseType(iter_typ), pos=getpos(self.stmt))

        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))

        lll_node = LLLnode.from_list(
            ["repeat", i, start, rounds, rounds, loop_body],
            pos=getpos(self.stmt),
        )
        del self.context.forvars[varname]

        return lll_node
Exemple #11
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
                return LLLnode.from_list(["pass"], typ=None, pos=getpos(self.stmt))
            else:
                test_expr = test_expr.value

        if self.stmt.msg:
            return self._assert_reason(test_expr, self.stmt.msg)
        else:
            return LLLnode.from_list(["assert", test_expr], typ=None, pos=getpos(self.stmt))
Exemple #12
0
 def parse_NameConstant(self):
     if self.expr.value is True:
         return LLLnode.from_list(
             1,
             typ=BaseType("bool", is_literal=True),
             pos=getpos(self.expr),
         )
     elif self.expr.value is False:
         return LLLnode.from_list(
             0,
             typ=BaseType("bool", is_literal=True),
             pos=getpos(self.expr),
         )
Exemple #13
0
 def parse_Hex(self):
     orignum = self.expr.value
     if len(orignum) == 42 and checksum_encode(orignum) == orignum:
         return LLLnode.from_list(
             int(self.expr.value, 16),
             typ=BaseType("address", is_literal=True),
             pos=getpos(self.expr),
         )
     elif len(orignum) == 66:
         return LLLnode.from_list(
             int(self.expr.value, 16),
             typ=BaseType("bytes32", is_literal=True),
             pos=getpos(self.expr),
         )
Exemple #14
0
 def parse_Int(self):
     # Literal (mostly likely) becomes int256
     if self.expr.n < 0:
         return LLLnode.from_list(
             self.expr.n,
             typ=BaseType("int256", is_literal=True),
             pos=getpos(self.expr),
         )
     # Literal is large enough (mostly likely) becomes uint256.
     else:
         return LLLnode.from_list(
             self.expr.n,
             typ=BaseType("uint256", is_literal=True),
             pos=getpos(self.expr),
         )
Exemple #15
0
def generate_lll_for_internal_function(code: vy_ast.FunctionDef,
                                       sig: FunctionSignature,
                                       context: Context) -> LLLnode:
    """
    Parse a internal function (FuncDef), and produce full function body.

    :param sig: the FuntionSignature
    :param code: ast of function
    :param context: current calling context
    :return: function body in LLL
    """

    # The calling convention is:
    #   Caller fills in argument buffer
    #   Caller provides return address, return buffer on the stack
    #   Callee runs its code, fills in return buffer provided by caller
    #   Callee jumps back to caller

    # The reason caller fills argument buffer is so there is less
    # complication with passing args on the stack; the caller is better
    # suited to optimize the copy operation. Also it avoids the callee
    # having to handle default args; that is easier left to the caller
    # as well. Meanwhile, the reason the callee fills the return buffer
    # is first, similarly, the callee is more suited to optimize the copy
    # operation. Second, it allows the caller to allocate the return
    # buffer in a way which reduces the number of copies. Third, it
    # reduces the potential for bugs since it forces the caller to have
    # the return data copied into a preallocated location. Otherwise, a
    # situation like the following is easy to bork:
    #   x: T[2] = [self.generate_T(), self.generate_T()]

    func_type = code._metadata["type"]

    # Get nonreentrant lock

    for arg in sig.args:
        # allocate a variable for every arg, setting mutability
        # to False to comply with vyper semantics, function arguments are immutable
        context.new_variable(arg.name, arg.typ, is_mutable=False)

    nonreentrant_pre, nonreentrant_post = get_nonreentrant_lock(func_type)

    function_entry_label = sig.internal_function_label
    cleanup_label = sig.exit_sequence_label

    # jump to the label which was passed in via stack
    stop_func = LLLnode.from_list(["jump", "pass"],
                                  annotation="jump to return address")

    enter = [["label", function_entry_label]] + nonreentrant_pre

    body = [parse_body(c, context) for c in code.body]

    exit = [["label", cleanup_label]] + nonreentrant_post + [stop_func]

    return LLLnode.from_list(
        ["seq"] + enter + body + exit,
        typ=None,
        pos=getpos(code),
    )
Exemple #16
0
 def parse_Raise(self):
     if self.stmt.exc:
         return self._assert_reason(None, self.stmt.exc)
     else:
         return LLLnode.from_list(["revert", 0, 0],
                                  typ=None,
                                  pos=getpos(self.stmt))
Exemple #17
0
def to_bytes32(expr, args, kwargs, context):
    in_arg = args[0]
    input_type, _len = get_type(in_arg)

    if input_type == "Bytes":
        if _len > 32:
            raise TypeMismatch(
                f"Unable to convert bytes[{_len}] to bytes32, max length is too "
                "large.")

        with in_arg.cache_when_complex("bytes") as (b1, in_arg):
            op = load_op(in_arg.location)
            ofst = wordsize(in_arg.location) * DYNAMIC_ARRAY_OVERHEAD
            bytes_val = [op, ["add", in_arg, ofst]]

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

    else:
        # literal
        ret = in_arg

    return LLLnode.from_list(ret, typ="bytes32", pos=getpos(expr))
Exemple #18
0
def lll_for_external_call(stmt_expr, context):
    from vyper.codegen.expr import Expr  # TODO rethink this circular import

    pos = getpos(stmt_expr)

    contract_address = Expr.parse_value_expr(stmt_expr.func.value, context)
    value, gas, skip_contract_check = _get_special_kwargs(stmt_expr, context)
    args_lll = [Expr(x, context).lll_node for x in stmt_expr.args]

    assert isinstance(contract_address.typ, InterfaceType)
    contract_name = contract_address.typ.name
    method_name = stmt_expr.func.attr
    contract_sig = context.sigs[contract_name][method_name]

    ret = _external_call_helper(
        contract_address,
        contract_sig,
        args_lll,
        context,
        pos,
        value=value,
        gas=gas,
        skip_contract_check=skip_contract_check,
    )
    ret.annotation = stmt_expr.get("node_source_code")

    return ret
Exemple #19
0
    def _run_pass(memory_allocator=None):
        # Create a local (per function) context.
        if memory_allocator is None:
            memory_allocator = MemoryAllocator()
        nonlocal sig
        sig = copy.deepcopy(sig)  # just in case
        context = Context(
            vars_=None,
            global_ctx=global_ctx,
            sigs=sigs,
            memory_allocator=memory_allocator,
            return_type=sig.return_type,
            constancy=Constancy.Constant
            if sig.mutability in ("view", "pure") else Constancy.Mutable,
            is_payable=sig.mutability == "payable",
            is_internal=sig.internal,
            sig=sig,
        )

        if sig.internal:
            o = generate_ir_for_internal_function(code, sig, context)
        else:
            o = generate_ir_for_external_function(code, sig, context,
                                                  check_nonpayable)

        o.source_pos = getpos(code)

        return o, context
Exemple #20
0
 def parse_UnaryOp(self):
     operand = Expr.parse_value_expr(self.expr.operand, self.context)
     if isinstance(self.expr.op, vy_ast.Not):
         if isinstance(operand.typ, BaseType) and operand.typ.typ == "bool":
             return LLLnode.from_list(["iszero", operand],
                                      typ="bool",
                                      pos=getpos(self.expr))
     elif isinstance(self.expr.op, vy_ast.USub) and is_numeric_type(
             operand.typ):
         # Clamp on minimum integer value as we cannot negate that value
         # (all other integer values are fine)
         min_int_val = get_min_val_for_type(operand.typ.typ)
         return LLLnode.from_list(
             ["sub", 0, ["clampgt", operand, min_int_val]],
             typ=operand.typ,
             pos=getpos(self.expr),
         )
Exemple #21
0
def lll_for_external_call(stmt_expr, context):
    from vyper.codegen.expr import Expr  # TODO rethink this circular import

    pos = getpos(stmt_expr)
    value, gas, skip_contract_check = _get_special_kwargs(stmt_expr, context)
    args_lll = [Expr(x, context).lll_node for x in stmt_expr.args]

    if isinstance(stmt_expr.func, vy_ast.Attribute) and isinstance(
            stmt_expr.func.value, vy_ast.Call):
        # e.g. `Foo(address).bar()`

        # sanity check
        assert len(stmt_expr.func.value.args) == 1
        contract_name = stmt_expr.func.value.func.id
        contract_address = Expr.parse_value_expr(stmt_expr.func.value.args[0],
                                                 context)

    elif (isinstance(stmt_expr.func.value, vy_ast.Attribute)
          and stmt_expr.func.value.attr in context.globals
          # TODO check for self?
          and hasattr(context.globals[stmt_expr.func.value.attr].typ, "name")):
        # e.g. `self.foo.bar()`

        # sanity check
        assert stmt_expr.func.value.value.id == "self", stmt_expr

        contract_name = context.globals[stmt_expr.func.value.attr].typ.name
        type_ = stmt_expr.func.value._metadata["type"]
        var = context.globals[stmt_expr.func.value.attr]
        contract_address = unwrap_location(
            LLLnode.from_list(
                type_.position.position,
                typ=var.typ,
                location="storage",
                pos=pos,
                annotation="self." + stmt_expr.func.value.attr,
            ))
    else:
        # TODO catch this during type checking
        raise StructureException("Unsupported operator.", stmt_expr)

    method_name = stmt_expr.func.attr
    contract_sig = context.sigs[contract_name][method_name]

    ret = _external_call_helper(
        contract_address,
        contract_sig,
        args_lll,
        context,
        pos,
        value=value,
        gas=gas,
        skip_contract_check=skip_contract_check,
    )
    ret.annotation = stmt_expr.get("node_source_code")

    return ret
Exemple #22
0
 def parse_Tuple(self):
     tuple_elements = [
         Expr(x, self.context).lll_node for x in self.expr.elements
     ]
     typ = TupleType([x.typ for x in tuple_elements], is_literal=True)
     multi_lll = LLLnode.from_list(["multi"] + tuple_elements,
                                   typ=typ,
                                   pos=getpos(self.expr))
     return multi_lll
Exemple #23
0
    def parse_Name(self):

        if self.expr.id == "self":
            return LLLnode.from_list(["address"],
                                     typ="address",
                                     pos=getpos(self.expr))
        elif self.expr.id in self.context.vars:
            var = self.context.vars[self.expr.id]
            return LLLnode.from_list(
                var.pos,
                typ=var.typ,
                location=var.
                location,  # either 'memory' or 'calldata' storage is handled above.
                encoding=var.encoding,
                pos=getpos(self.expr),
                annotation=self.expr.id,
                mutable=var.mutable,
            )

        elif self.expr.id in BUILTIN_CONSTANTS:
            obj, typ = BUILTIN_CONSTANTS[self.expr.id]
            return LLLnode.from_list([obj],
                                     typ=BaseType(typ, is_literal=True),
                                     pos=getpos(self.expr))

        elif self.expr._metadata["type"].is_immutable:
            var = self.context.globals[self.expr.id]
            ofst = self.expr._metadata["type"].position.offset

            if self.context.sig.is_init_func:
                mutable = True
                location = "immutables"
            else:
                mutable = False
                location = "data"

            return LLLnode.from_list(
                ofst,
                typ=var.typ,
                location=location,
                pos=getpos(self.expr),
                annotation=self.expr.id,
                mutable=mutable,
            )
Exemple #24
0
def parse_body(code, context):
    if not isinstance(code, list):
        return parse_stmt(code, context)

    lll_node = ["seq"]
    for stmt in code:
        lll = parse_stmt(stmt, context)
        lll_node.append(lll)
    lll_node.append("pass")  # force zerovalent, even last statement
    return LLLnode.from_list(lll_node, pos=getpos(code[0]) if code else None)
Exemple #25
0
def to_bool(expr, args, kwargs, context):
    in_arg = args[0]
    input_type, _ = get_type(in_arg)

    if input_type == "Bytes":
        if in_arg.typ.maxlen > 32:
            raise TypeMismatch(
                f"Cannot convert bytes array of max length {in_arg.typ.maxlen} to bool",
                expr,
            )
        else:
            num = byte_array_to_num(in_arg, "uint256")
            return LLLnode.from_list(["iszero", ["iszero", num]],
                                     typ=BaseType("bool"),
                                     pos=getpos(expr))

    else:
        return LLLnode.from_list(["iszero", ["iszero", in_arg]],
                                 typ=BaseType("bool"),
                                 pos=getpos(expr))
Exemple #26
0
    def parse_List(self):
        pos = getpos(self.expr)
        typ = new_type_to_old_type(self.expr._metadata["type"])
        if len(self.expr.elements) == 0:
            return LLLnode.from_list("~empty", typ=typ, pos=pos)

        multi_lll = [
            Expr(x, self.context).lll_node for x in self.expr.elements
        ]

        return LLLnode.from_list(["multi"] + multi_lll, typ=typ, pos=pos)
Exemple #27
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
            lll_node = LLLnode.from_list(body, typ=None, pos=getpos(self.stmt))
        return lll_node
Exemple #28
0
 def parse_Decimal(self):
     numstring, num, den = get_number_as_fraction(self.expr, self.context)
     if not (SizeLimits.MIN_INT128 * den <= num <=
             SizeLimits.MAX_INT128 * den):
         return
     if DECIMAL_DIVISOR % den:
         return
     return LLLnode.from_list(
         num * DECIMAL_DIVISOR // den,
         typ=BaseType("decimal", is_literal=True),
         pos=getpos(self.expr),
     )
Exemple #29
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, pos=self.stmt)
        if self.stmt.value is None:
            return

        sub = Expr(self.stmt.value, self.context).lll_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 = LLLnode(
                util.bytes_to_int(self.stmt.value.s),
                typ=BaseType("bytes32"),
                pos=getpos(self.stmt),
            )

        variable_loc = LLLnode.from_list(
            pos,
            typ=typ,
            location="memory",
            pos=getpos(self.stmt),
        )

        lll_node = make_setter(variable_loc, sub, pos=getpos(self.stmt))

        return lll_node
def keccak256_helper(expr, lll_arg, context):
    sub = lll_arg  # TODO get rid of useless variable
    _check_byteslike(sub.typ, expr)

    # Can hash literals
    # TODO this is dead code.
    if isinstance(sub, bytes):
        return LLLnode.from_list(bytes_to_int(keccak256(sub)),
                                 typ=BaseType("bytes32"),
                                 pos=getpos(expr))

    # Can hash bytes32 objects
    if is_base_type(sub.typ, "bytes32"):
        return LLLnode.from_list(
            [
                "seq",
                ["mstore", MemoryPositions.FREE_VAR_SPACE, sub],
                ["sha3", MemoryPositions.FREE_VAR_SPACE, 32],
            ],
            typ=BaseType("bytes32"),
            pos=getpos(expr),
            add_gas_estimate=_gas_bound(1),
        )

    sub = ensure_in_memory(sub, context, pos=getpos(expr))

    return LLLnode.from_list(
        [
            "with",
            "_buf",
            sub,
            ["sha3", ["add", "_buf", 32], ["mload", "_buf"]],
        ],
        typ=BaseType("bytes32"),
        pos=getpos(expr),
        annotation="keccak256",
        add_gas_estimate=_gas_bound(ceil(sub.typ.maxlen / 32)),
    )