def _parse_kwargs(call_expr, context): from vyper.codegen.expr import Expr # TODO rethink this circular import def _bool(x): assert x.value in (0, 1), "type checker missed this" return bool(x.value) # note: codegen for kwarg values in AST order call_kwargs = { kw.arg: Expr(kw.value, context).ir_node for kw in call_expr.keywords } ret = _CallKwargs( value=unwrap_location(call_kwargs.pop("value", IRnode(0))), gas=unwrap_location(call_kwargs.pop("gas", IRnode("gas"))), skip_contract_check=_bool( call_kwargs.pop("skip_contract_check", IRnode(0))), default_return_value=call_kwargs.pop("default_return_value", None), ) if len(call_kwargs) != 0: raise TypeCheckFailure(f"Unexpected keyword arguments: {call_kwargs}") return ret
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), )
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)
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
def _encode_log_topics(expr, event_id, arg_nodes, context): topics = [event_id] for arg in arg_nodes: if isinstance(arg.typ, BaseType): value = unwrap_location(arg) elif isinstance(arg.typ, ByteArrayLike): value = keccak256_helper(expr, arg, context=context) else: # TODO block at higher level raise TypeMismatch("Event indexes may only be value types", expr) topics.append(value) return topics
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))
def build_in_comparator(self): left = Expr(self.expr.left, self.context).lll_node right = Expr(self.expr.right, self.context).lll_node # temporary kludge to block #2637 bug # TODO actually fix the bug if not isinstance(left.typ, BaseType): raise TypeMismatch( "`in` not allowed for arrays of non-base types, tracked in issue #2637", self.expr) if isinstance(self.expr.op, vy_ast.In): found, not_found = 1, 0 elif isinstance(self.expr.op, vy_ast.NotIn): found, not_found = 0, 1 else: return # pragma: notest i = LLLnode.from_list(self.context.fresh_varname("in_ix"), typ="uint256") found_ptr = self.context.new_internal_variable(BaseType("bool")) ret = ["seq"] left = unwrap_location(left) with left.cache_when_complex("needle") as ( b1, left), right.cache_when_complex("haystack") as (b2, right): if right.value == "multi": # Copy literal to memory to be compared. tmp_list = LLLnode.from_list( self.context.new_internal_variable(right.typ), typ=right.typ, location="memory", ) ret.append(make_setter(tmp_list, right, pos=getpos(self.expr))) right = tmp_list # location of i'th item from list pos = getpos(self.expr) ith_element_ptr = get_element_ptr(right, i, array_bounds_check=False, pos=pos) ith_element = unwrap_location(ith_element_ptr) if isinstance(right.typ, SArrayType): len_ = right.typ.count else: len_ = get_dyn_array_count(right) # Condition repeat loop has to break on. # TODO maybe put result on the stack loop_body = [ "if", ["eq", left, ith_element], ["seq", ["mstore", found_ptr, found], "break"], # store true. ] loop = ["repeat", i, 0, len_, right.typ.count, loop_body] ret.append([ "seq", ["mstore", found_ptr, not_found], loop, ["mload", found_ptr], ]) return LLLnode.from_list(b1.resolve(b2.resolve(ret)), typ="bool")
def parse_value_expr(cls, expr, context): return unwrap_location(cls(expr, context).lll_node)