def _call_make_placeholder(stmt_expr, context, sig): if sig.output_type is None: return 0, 0, 0 output_placeholder = context.new_placeholder(typ=sig.output_type) output_size = get_size_of_type(sig.output_type) * 32 if isinstance(sig.output_type, BaseType): returner = output_placeholder elif isinstance(sig.output_type, ByteArrayLike): returner = output_placeholder elif isinstance(sig.output_type, TupleLike): # incase of struct we need to decode the output and then return it returner = ["seq"] decoded_placeholder = context.new_placeholder(typ=sig.output_type) decoded_node = LLLnode(decoded_placeholder, typ=sig.output_type, location="memory") output_node = LLLnode(output_placeholder, typ=sig.output_type, location="memory") returner.append(abi_decode(decoded_node, output_node)) returner.extend([decoded_placeholder]) elif isinstance(sig.output_type, ListType): returner = output_placeholder else: raise TypeCheckFailure(f"Invalid output type: {sig.output_type}") return output_placeholder, returner, output_size
def get_external_call_output(sig, context): if not sig.output_type: return 0, 0, [] output_placeholder = context.new_internal_variable(typ=sig.output_type) output_size = get_size_of_type(sig.output_type) * 32 if isinstance(sig.output_type, BaseType): returner = [0, output_placeholder] elif isinstance(sig.output_type, ByteArrayLike): returner = [0, output_placeholder + 32] elif isinstance(sig.output_type, TupleLike): # incase of struct we need to decode the output and then return it returner = ["seq"] decoded_placeholder = context.new_internal_variable( typ=sig.output_type) decoded_node = LLLnode(decoded_placeholder, typ=sig.output_type, location="memory") output_node = LLLnode(output_placeholder, typ=sig.output_type, location="memory") returner.append(abi_decode(decoded_node, output_node)) returner.extend([0, decoded_placeholder]) elif isinstance(sig.output_type, ListType): returner = [0, output_placeholder] else: raise TypeCheckFailure(f"Invalid output type: {sig.output_type}") return output_placeholder, output_size, returner
def base_type_conversion(orig, frm, to, pos): orig = unwrap_location(orig) if getattr(frm, 'is_literal', False) and frm.typ in ('int128', 'uint256') and not SizeLimits.in_bounds(frm.typ, orig.value): raise InvalidLiteralException("Number out of range: " + str(orig.value), pos) # # Valid bytes[32] to bytes32 assignment. # if isinstance(to, BaseType) and to.typ = 'bytes32' and isinstance(frm, ByteArrayType) and frm.maxlen == 32: # return LLLnode(orig.value, orig.args, typ=to, add_gas_estimate=orig.add_gas_estimate) if not isinstance(frm, (BaseType, NullType)) or not isinstance(to, BaseType): raise TypeMismatchException("Base type conversion from or to non-base type: %r %r" % (frm, to), pos) elif is_base_type(frm, to.typ) and are_units_compatible(frm, to): return LLLnode(orig.value, orig.args, typ=to, add_gas_estimate=orig.add_gas_estimate) elif is_base_type(frm, 'int128') and is_base_type(to, 'decimal') and are_units_compatible(frm, to): return LLLnode.from_list(['mul', orig, DECIMAL_DIVISOR], typ=BaseType('decimal', to.unit, to.positional)) elif isinstance(frm, NullType): if to.typ not in ('int128', 'bool', 'uint256', 'address', 'bytes32', 'decimal'): # This is only to future proof the use of base_type_conversion. raise TypeMismatchException("Cannot convert null-type object to type %r" % to, pos) # pragma: no cover return LLLnode.from_list(0, typ=to) elif isinstance(to, ContractType) and frm.typ == 'address': return LLLnode(orig.value, orig.args, typ=to, add_gas_estimate=orig.add_gas_estimate) # Integer literal conversion. elif (frm.typ, to.typ, frm.is_literal) == ('int128', 'uint256', True): return LLLnode(orig.value, orig.args, typ=to, add_gas_estimate=orig.add_gas_estimate) else: raise TypeMismatchException("Typecasting from base type %r to %r unavailable" % (frm, to), pos)
def base_type_conversion(orig, frm, to, pos, in_function_call=False): orig = unwrap_location(orig) if getattr(frm, 'is_literal', False) and frm.typ in ('int128', 'uint256'): if not SizeLimits.in_bounds(frm.typ, orig.value): raise InvalidLiteralException("Number out of range: " + str(orig.value), pos) # Special Case: Literals in function calls should always convey unit type as well. if in_function_call and not (frm.unit == to.unit and frm.positional == to.positional): raise InvalidLiteralException("Function calls require explicit unit definitions on calls, expected %r" % to, pos) if not isinstance(frm, (BaseType, NullType)) or not isinstance(to, BaseType): raise TypeMismatchException("Base type conversion from or to non-base type: %r %r" % (frm, to), pos) elif is_base_type(frm, to.typ) and are_units_compatible(frm, to): return LLLnode(orig.value, orig.args, typ=to, add_gas_estimate=orig.add_gas_estimate) elif is_base_type(frm, 'int128') and is_base_type(to, 'decimal') and are_units_compatible(frm, to): return LLLnode.from_list(['mul', orig, DECIMAL_DIVISOR], typ=BaseType('decimal', to.unit, to.positional)) elif isinstance(frm, NullType): if to.typ not in ('int128', 'bool', 'uint256', 'address', 'bytes32', 'decimal'): # This is only to future proof the use of base_type_conversion. raise TypeMismatchException("Cannot convert null-type object to type %r" % to, pos) # pragma: no cover return LLLnode.from_list(0, typ=to) elif isinstance(to, ContractType) and frm.typ == 'address': return LLLnode(orig.value, orig.args, typ=to, add_gas_estimate=orig.add_gas_estimate) # Integer literal conversion. elif (frm.typ, to.typ, frm.is_literal) == ('int128', 'uint256', True): return LLLnode(orig.value, orig.args, typ=to, add_gas_estimate=orig.add_gas_estimate) else: raise TypeMismatchException("Typecasting from base type %r to %r unavailable" % (frm, to), pos)
def gen_tuple_return(stmt, context, sub): abi_typ = abi_type_of(context.return_type) # according to the ABI, return types are ALWAYS tuples even if # only one element is being returned. # https://solidity.readthedocs.io/en/latest/abi-spec.html#function-selector-and-argument-encoding # "and the return values v_1, ..., v_k of f are encoded as # # enc((v_1, ..., v_k)) # i.e. the values are combined into a tuple and encoded. # " # therefore, wrap it in a tuple if it's not already a tuple. # (big difference between returning `(bytes,)` and `bytes`. abi_typ = ensure_tuple(abi_typ) abi_bytes_needed = abi_typ.static_size() + abi_typ.dynamic_size_bound() dst, _ = context.memory_allocator.increase_memory(abi_bytes_needed) return_buffer = LLLnode(dst, location="memory", annotation="return_buffer", typ=context.return_type) check_assign(return_buffer, sub, pos=getpos(stmt)) # in case of multi we can't create a variable to store location of the return expression # as multi can have data from multiple location like store, calldata etc if sub.value == "multi": encode_out = abi_encode(return_buffer, sub, pos=getpos(stmt), returns=True) load_return_len = ["mload", MemoryPositions.FREE_VAR_SPACE] os = [ "seq", ["mstore", MemoryPositions.FREE_VAR_SPACE, encode_out], make_return_stmt(stmt, context, return_buffer, load_return_len), ] return LLLnode.from_list(os, typ=None, pos=getpos(stmt), valency=0) # for all othe cases we are creating a stack variable named sub_loc to store the location # of the return expression. This is done so that the return expression does not get evaluated # abi-encode uses a function named o_list which evaluate the expression multiple times sub_loc = LLLnode("sub_loc", typ=sub.typ, location=sub.location) encode_out = abi_encode(return_buffer, sub_loc, pos=getpos(stmt), returns=True) load_return_len = ["mload", MemoryPositions.FREE_VAR_SPACE] os = [ "with", "sub_loc", sub, [ "seq", ["mstore", MemoryPositions.FREE_VAR_SPACE, encode_out], make_return_stmt(stmt, context, return_buffer, load_return_len), ], ] return LLLnode.from_list(os, typ=None, pos=getpos(stmt), valency=0)
def abi_decode(lll_node, src, pos=None): os = o_list(lll_node, pos=pos) lll_ret = ["seq"] parent_abi_t = abi_type_of(lll_node.typ) for i, o in enumerate(os): abi_t = abi_type_of(o.typ) src_loc = LLLnode("src_loc", typ=o.typ, location=src.location) if parent_abi_t.is_tuple(): if abi_t.is_dynamic(): child_loc = ["add", "src", unwrap_location(src_loc)] child_loc = LLLnode.from_list(child_loc, typ=o.typ, location=src.location) else: child_loc = src_loc # descend into the child tuple lll_ret.append(abi_decode(o, child_loc, pos=pos)) else: lll_ret.append( make_setter(o, src_loc, location=o.location, pos=pos)) if i + 1 == len(os): pass # optimize out the last pointer increment else: sz = abi_t.embedded_static_size() lll_ret.append(["set", "src_loc", ["add", "src_loc", sz]]) lll_ret = ["with", "src", src, ["with", "src_loc", "src", lll_ret]] return lll_ret
def abi_decode(lll_node, src, pos=None): os = o_list(lll_node, pos=pos) lll_ret = [] src_ptr = 'src' # pointer to beginning of buffer src_loc = 'src_loc' # pointer to read location in static section parent_abi_t = abi_type_of(src.typ) for i, o in enumerate(os): abi_t = abi_type_of(o.typ) src_loc = LLLnode('src_loc', typ=o.typ, location=src.location) if parent_abi_t.is_tuple(): if abi_t.is_dynamic(): child_loc = ['add', src_ptr, unwrap_location(src_loc)] else: child_loc = src_loc # descend into the child tuple lll_ret.append(abi_decode(o, child_loc, pos=pos)) else: lll_ret.append(make_setter(o, src_loc)) if i + 1 == len(os): pass # optimize out the last pointer increment else: sz = abi_t.embedded_static_size() lll_ret.append(['set', src_loc, ['add', src_loc, sz]]) lll_ret = [ 'with', 'src', src, ['with', 'src_loc', 'src', ['seq', lll_ret]] ] return lll_ret
def base_type_conversion(orig, frm, to, pos, in_function_call=False): orig = unwrap_location(orig) # do the base type check so we can use BaseType attributes if not isinstance(frm, BaseType) or not isinstance(to, BaseType): return if getattr(frm, "is_literal", False): for typ in (frm.typ, to.typ): if typ in ("int128", "uint256") and not SizeLimits.in_bounds(typ, orig.value): return is_decimal_int128_conversion = frm.typ == "int128" and to.typ == "decimal" is_same_type = frm.typ == to.typ is_literal_conversion = frm.is_literal and (frm.typ, to.typ) == ("int128", "uint256") is_address_conversion = isinstance(frm, InterfaceType) and to.typ == "address" if not ( is_same_type or is_literal_conversion or is_address_conversion or is_decimal_int128_conversion ): return # handle None value inserted by `empty()` if orig.value is None: return LLLnode.from_list(0, typ=to) if is_decimal_int128_conversion: return LLLnode.from_list(["mul", orig, DECIMAL_DIVISOR], typ=BaseType("decimal"),) return LLLnode(orig.value, orig.args, typ=to, add_gas_estimate=orig.add_gas_estimate)
def gen_tuple_return(stmt, context, sub): # Is from a call expression. if sub.args and len(sub.args[0].args) > 0 and ( sub.args[0].args[0].value == "call" or sub.args[0].args[0].value == "staticcall"): # self-call to external. mem_pos = sub mem_size = get_size_of_type(sub.typ) * 32 return LLLnode.from_list(["return", mem_pos, mem_size], typ=sub.typ) elif sub.annotation and "Internal Call" in sub.annotation: mem_pos = sub.args[ -1].value if sub.value == "seq_unchecked" else sub.args[0].args[-1] mem_size = get_size_of_type(sub.typ) * 32 # Add zero padder if bytes are present in output. zero_padder = ["pass"] byte_arrays = [(i, x) for i, x in enumerate(sub.typ.tuple_members()) if isinstance(x, ByteArrayLike)] if byte_arrays: i, x = byte_arrays[-1] zero_padder = zero_pad(bytez_placeholder=[ "add", mem_pos, ["mload", mem_pos + i * 32] ]) return LLLnode.from_list( ["seq"] + [sub] + [zero_padder] + [make_return_stmt(stmt, context, mem_pos, mem_size)], typ=sub.typ, pos=getpos(stmt), valency=0, ) abi_typ = abi_type_of(context.return_type) # according to the ABI, return types are ALWAYS tuples even if # only one element is being returned. # https://solidity.readthedocs.io/en/latest/abi-spec.html#function-selector-and-argument-encoding # "and the return values v_1, ..., v_k of f are encoded as # # enc((v_1, ..., v_k)) # i.e. the values are combined into a tuple and encoded. # " # therefore, wrap it in a tuple if it's not already a tuple. # (big difference between returning `(bytes,)` and `bytes`. abi_typ = ensure_tuple(abi_typ) abi_bytes_needed = abi_typ.static_size() + abi_typ.dynamic_size_bound() dst, _ = context.memory_allocator.increase_memory(abi_bytes_needed) return_buffer = LLLnode(dst, location="memory", annotation="return_buffer", typ=context.return_type) check_assign(return_buffer, sub, pos=getpos(stmt)) encode_out = abi_encode(return_buffer, sub, pos=getpos(stmt), returns=True) load_return_len = ["mload", MemoryPositions.FREE_VAR_SPACE] os = [ "seq", ["mstore", MemoryPositions.FREE_VAR_SPACE, encode_out], make_return_stmt(stmt, context, return_buffer, load_return_len), ] return LLLnode.from_list(os, typ=None, pos=getpos(stmt), valency=0)
def base_type_conversion(orig, frm, to, pos, in_function_call=False): orig = unwrap_location(orig) # do the base type check so we can use BaseType attributes if not isinstance(frm, BaseType) or not isinstance(to, BaseType): raise TypeMismatch( f"Base type conversion from or to non-base type: {frm} {to}", pos) if getattr(frm, 'is_literal', False): if frm.typ in ('int128', 'uint256'): if not SizeLimits.in_bounds(frm.typ, orig.value): raise InvalidLiteral(f"Number out of range: {orig.value}", pos) if to.typ in ('int128', 'uint256'): if not SizeLimits.in_bounds(to.typ, orig.value): raise InvalidLiteral(f"Number out of range: {orig.value}", pos) is_decimal_int128_conversion = frm.typ == 'int128' and to.typ == 'decimal' is_same_type = frm.typ == to.typ is_literal_conversion = frm.is_literal and (frm.typ, to.typ) == ('int128', 'uint256') is_address_conversion = isinstance(frm, ContractType) and to.typ == 'address' if not (is_same_type or is_literal_conversion or is_address_conversion or is_decimal_int128_conversion): raise TypeMismatch( f"Typecasting from base type {frm} to {to} unavailable", pos) # handle None value inserted by `empty()` if orig.value is None: return LLLnode.from_list(0, typ=to) if is_decimal_int128_conversion: return LLLnode.from_list( ['mul', orig, DECIMAL_DIVISOR], typ=BaseType('decimal'), ) return LLLnode(orig.value, orig.args, typ=to, add_gas_estimate=orig.add_gas_estimate)
def gen_tuple_return(stmt, context, sub): abi_typ = abi_type_of(context.return_type) # according to the ABI, return types are ALWAYS tuples even if # only one element is being returned. # https://solidity.readthedocs.io/en/latest/abi-spec.html#function-selector-and-argument-encoding # "and the return values v_1, ..., v_k of f are encoded as # # enc((v_1, ..., v_k)) # i.e. the values are combined into a tuple and encoded. # " # therefore, wrap it in a tuple if it's not already a tuple. # (big difference between returning `(bytes,)` and `bytes`. abi_typ = ensure_tuple(abi_typ) abi_bytes_needed = abi_typ.static_size() + abi_typ.dynamic_size_bound() dst = context.memory_allocator.expand_memory(abi_bytes_needed) return_buffer = LLLnode(dst, location="memory", annotation="return_buffer", typ=context.return_type) check_assign(return_buffer, sub, pos=getpos(stmt)) if sub.value == "multi": if isinstance(context.return_type, TupleType) and not abi_typ.dynamic_size_bound(): # for tuples where every value is of the same type and a fixed length, # we can simplify the encoding by treating it as though it were an array base_types = set() for typ in context.return_type.members: while isinstance(typ, ListType): typ = typ.subtype base_types.add(typ.typ) if len(base_types) == 1: new_sub = LLLnode.from_list( context.new_internal_variable(context.return_type), typ=context.return_type, location="memory", ) setter = make_setter(new_sub, sub, "memory", pos=getpos(stmt)) return LLLnode.from_list( [ "seq", setter, make_return_stmt( stmt, context, new_sub, get_size_of_type(context.return_type) * 32, ), ], typ=None, pos=getpos(stmt), ) # in case of multi we can't create a variable to store location of the return expression # as multi can have data from multiple location like store, calldata etc encode_out = abi_encode(return_buffer, sub, pos=getpos(stmt), returns=True) load_return_len = ["mload", MemoryPositions.FREE_VAR_SPACE] os = [ "seq", ["mstore", MemoryPositions.FREE_VAR_SPACE, encode_out], make_return_stmt(stmt, context, return_buffer, load_return_len), ] return LLLnode.from_list(os, typ=None, pos=getpos(stmt), valency=0) # for tuple return types where a function is called inside the tuple, we # process the calls prior to encoding the return data if sub.value == "seq_unchecked" and sub.args[-1].value == "multi": encode_out = abi_encode(return_buffer, sub.args[-1], pos=getpos(stmt), returns=True) load_return_len = ["mload", MemoryPositions.FREE_VAR_SPACE] os = (["seq"] + sub.args[:-1] + [ ["mstore", MemoryPositions.FREE_VAR_SPACE, encode_out], make_return_stmt(stmt, context, return_buffer, load_return_len), ]) return LLLnode.from_list(os, typ=None, pos=getpos(stmt), valency=0) # for all othe cases we are creating a stack variable named sub_loc to store the location # of the return expression. This is done so that the return expression does not get evaluated # abi-encode uses a function named o_list which evaluate the expression multiple times sub_loc = LLLnode("sub_loc", typ=sub.typ, location=sub.location) encode_out = abi_encode(return_buffer, sub_loc, pos=getpos(stmt), returns=True) load_return_len = ["mload", MemoryPositions.FREE_VAR_SPACE] os = [ "with", "sub_loc", sub, [ "seq", ["mstore", MemoryPositions.FREE_VAR_SPACE, encode_out], make_return_stmt(stmt, context, return_buffer, load_return_len), ], ] return LLLnode.from_list(os, typ=None, pos=getpos(stmt), valency=0)
def gen_tuple_return(stmt, context, sub): # Is from a call expression. if sub.args and len( sub.args[0].args) > 0 and sub.args[0].args[0].value == 'call': # self-call to public. mem_pos = sub.args[0].args[-1] mem_size = get_size_of_type(sub.typ) * 32 return LLLnode.from_list(['return', mem_pos, mem_size], typ=sub.typ) elif (sub.annotation and 'Internal Call' in sub.annotation): mem_pos = sub.args[ -1].value if sub.value == 'seq_unchecked' else sub.args[0].args[-1] mem_size = get_size_of_type(sub.typ) * 32 # Add zero padder if bytes are present in output. zero_padder = ['pass'] byte_arrays = [(i, x) for i, x in enumerate(sub.typ.tuple_members()) if isinstance(x, ByteArrayLike)] if byte_arrays: i, x = byte_arrays[-1] zero_padder = zero_pad(bytez_placeholder=[ 'add', mem_pos, ['mload', mem_pos + i * 32] ], maxlen=x.maxlen, context=context) return LLLnode.from_list( ['seq'] + [sub] + [zero_padder] + [make_return_stmt(stmt, context, mem_pos, mem_size)], typ=sub.typ, pos=getpos(stmt), valency=0) subs = [] # Pre-allocate loop_memory_position if required for private function returning. loop_memory_position = (context.new_placeholder( typ=BaseType('uint256')) if context.is_private else None) # Allocate dynamic off set counter, to keep track of the total packed dynamic data size. dynamic_offset_counter_placeholder = context.new_placeholder( typ=BaseType('uint256')) dynamic_offset_counter = LLLnode( dynamic_offset_counter_placeholder, typ=None, annotation="dynamic_offset_counter" # dynamic offset position counter. ) new_sub = LLLnode.from_list( context.new_placeholder(typ=BaseType('uint256')), typ=context.return_type, location='memory', annotation='new_sub', ) left_token = LLLnode.from_list('_loc', typ=new_sub.typ, location="memory") def get_dynamic_offset_value(): # Get value of dynamic offset counter. return ['mload', dynamic_offset_counter] def increment_dynamic_offset(dynamic_spot): # Increment dyanmic offset counter in memory. return [ 'mstore', dynamic_offset_counter, [ 'add', ['add', ['ceil32', ['mload', dynamic_spot]], 32], ['mload', dynamic_offset_counter] ] ] if not isinstance(context.return_type, TupleLike): raise TypeMismatchException( 'Trying to return %r when expecting %r' % (sub.typ, context.return_type), getpos(stmt)) items = context.return_type.tuple_items() dynamic_offset_start = 32 * len(items) # The static list of args end. for i, (key, typ) in enumerate(items): variable_offset = LLLnode.from_list( ['add', 32 * i, left_token], typ=typ, annotation='variable_offset', ) # variable offset of destination if sub.typ.is_literal: arg = sub.args[i] else: arg = add_variable_offset(parent=sub, key=key, pos=getpos(stmt)) if isinstance(typ, ByteArrayLike): # Store offset pointer value. subs.append( ['mstore', variable_offset, get_dynamic_offset_value()]) # Store dynamic data, from offset pointer onwards. dynamic_spot = LLLnode.from_list( ['add', left_token, get_dynamic_offset_value()], location="memory", typ=typ, annotation='dynamic_spot', ) subs.append( make_setter(dynamic_spot, arg, location="memory", pos=getpos(stmt))) subs.append(increment_dynamic_offset(dynamic_spot)) elif isinstance(typ, BaseType): subs.append( make_setter(variable_offset, arg, "memory", pos=getpos(stmt))) elif isinstance(typ, TupleLike): subs.append(gen_tuple_return(stmt, context, arg)) else: # Maybe this should panic because the type error should be # caught at an earlier type-checking stage. raise TypeMismatchException( "Can't return type %s as part of tuple" % arg.typ, stmt) setter = LLLnode.from_list([ 'seq', ['mstore', dynamic_offset_counter, dynamic_offset_start], ['with', '_loc', new_sub, ['seq'] + subs] ], typ=None) return LLLnode.from_list([ 'seq', setter, make_return_stmt(stmt, context, new_sub, get_dynamic_offset_value(), loop_memory_position) ], typ=None, pos=getpos(stmt), valency=0)
def _add_ofst(loc, ofst): if isinstance(loc.value, int): return LLLnode(loc.value + ofst) return ["add", loc, ofst]
def abi_encode(dst, lll_node, pos=None, bufsz=None, returns=False): parent_abi_t = abi_type_of(lll_node.typ) size_bound = parent_abi_t.static_size() + parent_abi_t.dynamic_size_bound() if bufsz is not None and bufsz < 32 * size_bound: raise CompilerPanic("buffer provided to abi_encode not large enough") lll_ret = ["seq"] dyn_ofst = "dyn_ofst" # current offset in the dynamic section dst_begin = "dst" # pointer to beginning of buffer dst_loc = "dst_loc" # pointer to write location in static section os = o_list(lll_node, pos=pos) for i, o in enumerate(os): abi_t = abi_type_of(o.typ) if parent_abi_t.is_tuple(): if abi_t.is_dynamic(): lll_ret.append(["mstore", dst_loc, dyn_ofst]) # recurse child_dst = ["add", dst_begin, dyn_ofst] child = abi_encode(child_dst, o, pos=pos, returns=True) # increment dyn ofst for the return # (optimization note: # if non-returning and this is the last dyn member in # the tuple, this set can be elided.) lll_ret.append(["set", dyn_ofst, ["add", dyn_ofst, child]]) else: # recurse lll_ret.append(abi_encode(dst_loc, o, pos=pos, returns=False)) elif isinstance(o.typ, BaseType): d = LLLnode(dst_loc, typ=o.typ, location="memory") lll_ret.append(make_setter(d, o, location=d.location, pos=pos)) elif isinstance(o.typ, ByteArrayLike): d = LLLnode.from_list(dst_loc, typ=o.typ, location="memory") lll_ret.append([ "seq", make_setter(d, o, location=d.location, pos=pos), zero_pad(d) ]) else: raise CompilerPanic(f"unreachable type: {o.typ}") if i + 1 == len(os): pass # optimize out the last increment to dst_loc else: # note: always false for non-tuple types sz = abi_t.embedded_static_size() lll_ret.append(["set", dst_loc, ["add", dst_loc, sz]]) # declare LLL variables. if returns: if not parent_abi_t.is_dynamic(): lll_ret.append(parent_abi_t.embedded_static_size()) elif parent_abi_t.is_tuple(): lll_ret.append("dyn_ofst") elif isinstance(lll_node.typ, ByteArrayLike): # for abi purposes, return zero-padded length calc_len = ["ceil32", ["add", 32, ["mload", dst_loc]]] lll_ret.append(calc_len) else: raise CompilerPanic("unknown type {lll_node.typ}") if not (parent_abi_t.is_dynamic() and parent_abi_t.is_tuple()): pass # optimize out dyn_ofst allocation if we don't need it else: dyn_section_start = parent_abi_t.static_size() lll_ret = ["with", "dyn_ofst", dyn_section_start, lll_ret] lll_ret = ["with", dst_begin, dst, ["with", dst_loc, dst_begin, lll_ret]] return LLLnode.from_list(lll_ret)
def call(self): from vyper.functions import ( dispatch_table, ) if isinstance(self.expr.func, ast.Name): function_name = self.expr.func.id if function_name in dispatch_table: return dispatch_table[function_name](self.expr, self.context) # Struct constructors do not need `self` prefix. elif function_name in self.context.structs: if not self.context.in_assignment: raise StructureException( "Struct constructor must be called in RHS of assignment.", self.expr) args = self.expr.args if len(args) != 1: raise StructureException( "Struct constructor is called with one argument only", self.expr) arg = args[0] if not isinstance(arg, ast.Dict): raise TypeMismatchException( "Struct can only be constructed with a dict", self.expr) sub = Expr.struct_literals(arg, self.context) if sub.typ.name is not None: raise TypeMismatchException( "Struct can only be constructed with a dict", self.expr) typ = StructType(sub.typ.members, function_name) # OR: # sub.typ = typ # return sub return LLLnode(sub.value, typ=typ, args=sub.args, location=sub.location, pos=getpos(self.expr), add_gas_estimate=sub.add_gas_estimate, valency=sub.valency, annotation=function_name) else: err_msg = "Not a top-level function: {}".format(function_name) if function_name in [ x.split('(')[0] for x, _ in self.context.sigs['self'].items() ]: err_msg += ". Did you mean self.{}?".format(function_name) raise StructureException(err_msg, self.expr) elif isinstance(self.expr.func, ast.Attribute) and isinstance( self.expr.func.value, ast.Name) and self.expr.func.value.id == "self": return self_call.make_call(self.expr, self.context) else: return external_call.make_external_call(self.expr, self.context)