def base_type_conversion(orig, frm, to, pos=None): orig = unwrap_location(orig) 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, 'num') 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 is_base_type(frm, 'num256') and is_base_type( to, 'num') and are_units_compatible(frm, to): return LLLnode.from_list( ['uclample', orig, ['mload', MemoryPositions.MAXNUM]], typ=BaseType("num")) elif isinstance(frm, NullType): if to.typ not in ('num', 'bool', 'num256', 'address', 'bytes32', 'decimal'): raise TypeMismatchException( "Cannot convert null-type object to type %r" % to, pos) return LLLnode.from_list(0, typ=to) else: raise TypeMismatchException( "Typecasting from base type %r to %r unavailable" % (frm, to), pos)
def compare(self): left = Expr.parse_value_expr(self.expr.left, self.context) right = Expr.parse_value_expr(self.expr.comparators[0], self.context) if isinstance(self.expr.ops[0], ast.In) and \ isinstance(right.typ, ListType): if not are_units_compatible( left.typ, right.typ.subtype) and not are_units_compatible( right.typ.subtype, left.typ): raise TypeMismatchException( "Can't use IN comparison with different types!", self.expr) return self.build_in_comparator() else: if not are_units_compatible( left.typ, right.typ) and not are_units_compatible( right.typ, left.typ): raise TypeMismatchException( "Can't compare values with different units!", self.expr) if len(self.expr.ops) != 1: raise StructureException( "Cannot have a comparison with more than two elements", self.expr) if isinstance(self.expr.ops[0], ast.Gt): op = 'sgt' elif isinstance(self.expr.ops[0], ast.GtE): op = 'sge' elif isinstance(self.expr.ops[0], ast.LtE): op = 'sle' elif isinstance(self.expr.ops[0], ast.Lt): op = 'slt' elif isinstance(self.expr.ops[0], ast.Eq): op = 'eq' elif isinstance(self.expr.ops[0], ast.NotEq): op = 'ne' else: raise Exception("Unsupported comparison operator") if not is_numeric_type(left.typ) or not is_numeric_type(right.typ): if op not in ('eq', 'ne'): raise TypeMismatchException("Invalid type for comparison op", self.expr) ltyp, rtyp = left.typ.typ, right.typ.typ if ltyp == rtyp: return LLLnode.from_list([op, left, right], typ='bool', pos=getpos(self.expr)) elif ltyp == 'decimal' and rtyp == 'num': return LLLnode.from_list( [op, left, ['mul', right, DECIMAL_DIVISOR]], typ='bool', pos=getpos(self.expr)) elif ltyp == 'num' and rtyp == 'decimal': return LLLnode.from_list( [op, ['mul', left, DECIMAL_DIVISOR], right], typ='bool', pos=getpos(self.expr)) else: raise TypeMismatchException( "Unsupported types for comparison: %r %r" % (ltyp, rtyp), self.expr)
def parse_return(self): from .parser import (make_setter) if self.context.return_type is None: if self.stmt.value: raise TypeMismatchException("Not expecting to return a value", self.stmt) return LLLnode.from_list(['return', 0, 0], typ=None, pos=getpos(self.stmt)) if not self.stmt.value: raise TypeMismatchException("Expecting to return a value", self.stmt) sub = Expr(self.stmt.value, self.context).lll_node self.context.increment_return_counter() # Returning a value (most common case) if isinstance(sub.typ, BaseType): if not isinstance(self.context.return_type, BaseType): raise TypeMismatchException( "Trying to return base type %r, output expecting %r" % (sub.typ, self.context.return_type), self.stmt.value) sub = unwrap_location(sub) if not are_units_compatible(sub.typ, self.context.return_type): raise TypeMismatchException( "Return type units mismatch %r %r" % (sub.typ, self.context.return_type), self.stmt.value) elif is_base_type(sub.typ, self.context.return_type.typ) or \ (is_base_type(sub.typ, 'num') and is_base_type(self.context.return_type, 'signed256')): return LLLnode.from_list( ['seq', ['mstore', 0, sub], ['return', 0, 32]], typ=None, pos=getpos(self.stmt)) else: raise TypeMismatchException( "Unsupported type conversion: %r to %r" % (sub.typ, self.context.return_type), self.stmt.value) # Returning a byte array elif isinstance(sub.typ, ByteArrayType): if not isinstance(self.context.return_type, ByteArrayType): raise TypeMismatchException( "Trying to return base type %r, output expecting %r" % (sub.typ, self.context.return_type), self.stmt.value) if sub.typ.maxlen > self.context.return_type.maxlen: raise TypeMismatchException( "Cannot cast from greater max-length %d to shorter max-length %d" % (sub.typ.maxlen, self.context.return_type.maxlen), self.stmt.value) # Returning something already in memory if sub.location == 'memory': return LLLnode.from_list([ 'with', '_loc', sub, [ 'seq', ['mstore', ['sub', '_loc', 32], 32], [ 'return', ['sub', '_loc', 32], ['ceil32', ['add', ['mload', '_loc'], 64]] ] ] ], typ=None, pos=getpos(self.stmt)) # Copying from storage elif sub.location == 'storage': # Instantiate a byte array at some index fake_byte_array = LLLnode(self.context.get_next_mem() + 32, typ=sub.typ, location='memory', pos=getpos(self.stmt)) o = [ 'seq', # Copy the data to this byte array make_byte_array_copier(fake_byte_array, sub), # Store the number 32 before it for ABI formatting purposes ['mstore', self.context.get_next_mem(), 32], # Return it [ 'return', self.context.get_next_mem(), [ 'add', [ 'ceil32', ['mload', self.context.get_next_mem() + 32] ], 64 ] ] ] return LLLnode.from_list(o, typ=None, pos=getpos(self.stmt)) else: raise Exception("Invalid location: %s" % sub.location) elif isinstance(sub.typ, ListType): sub_base_type = re.split(r'\(|\[', str(sub.typ.subtype))[0] ret_base_type = re.split(r'\(|\[', str(self.context.return_type.subtype))[0] if sub_base_type != ret_base_type and sub.value != 'multi': raise TypeMismatchException( "List return type %r does not match specified return type, expecting %r" % (sub_base_type, ret_base_type), self.stmt) if sub.location == "memory" and sub.value != "multi": return LLLnode.from_list([ 'return', sub, get_size_of_type(self.context.return_type) * 32 ], typ=None, pos=getpos(self.stmt)) else: new_sub = LLLnode.from_list(self.context.new_placeholder( self.context.return_type), typ=self.context.return_type, location='memory') setter = make_setter(new_sub, sub, 'memory', pos=getpos(self.stmt)) return LLLnode.from_list([ 'seq', setter, [ 'return', new_sub, get_size_of_type(self.context.return_type) * 32 ] ], typ=None, pos=getpos(self.stmt)) # Returning a tuple. elif isinstance(sub.typ, TupleType): if len(self.context.return_type.members) != len(sub.typ.members): raise StructureException("Tuple lengths don't match!") subs = [] dynamic_offset_counter = LLLnode( self.context.get_next_mem(), typ=None, annotation="dynamic_offset_counter" ) # dynamic offset position counter. new_sub = LLLnode.from_list(self.context.get_next_mem() + 32, typ=self.context.return_type, location='memory', annotation='new_sub') keyz = list(range(len(sub.typ.members))) dynamic_offset_start = 32 * len( sub.args) # The static list of args end. 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] ] ] for i, typ in enumerate(keyz): arg = sub.args[i] variable_offset = LLLnode.from_list( ['add', 32 * i, left_token], typ=arg.typ, annotation='variable_offset') if isinstance(arg.typ, ByteArrayType): # 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=arg.typ, annotation='dynamic_spot') subs.append( make_setter(dynamic_spot, arg, location="memory", pos=getpos(self.stmt))) subs.append(increment_dynamic_offset(dynamic_spot)) elif isinstance(arg.typ, BaseType): subs.append( make_setter(variable_offset, arg, "memory", pos=getpos(self.stmt))) else: raise Exception("Can't return type %s as part of tuple", type(arg.typ)) 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, ['return', new_sub, get_dynamic_offset_value()] ], typ=None, pos=getpos(self.stmt)) else: raise TypeMismatchException("Can only return base type!", self.stmt)
def parse_return(self): from .parser import (parse_expr, make_setter) if self.context.return_type is None: if self.stmt.value: raise TypeMismatchException("Not expecting to return a value", self.stmt) return LLLnode.from_list(['return', 0, 0], typ=None, pos=getpos(self.stmt)) if not self.stmt.value: raise TypeMismatchException("Expecting to return a value", self.stmt) sub = parse_expr(self.stmt.value, self.context) # Returning a value (most common case) if isinstance(sub.typ, BaseType): if not isinstance(self.context.return_type, BaseType): raise TypeMismatchException( "Trying to return base type %r, output expecting %r" % (sub.typ, self.context.return_type), self.stmt.value) sub = unwrap_location(sub) if not are_units_compatible(sub.typ, self.context.return_type): raise TypeMismatchException( "Return type units mismatch %r %r" % (sub.typ, self.context.return_type), self.stmt.value) elif is_base_type(sub.typ, self.context.return_type.typ) or \ (is_base_type(sub.typ, 'num') and is_base_type(self.context.return_type, 'signed256')): return LLLnode.from_list( ['seq', ['mstore', 0, sub], ['return', 0, 32]], typ=None, pos=getpos(self.stmt)) else: raise TypeMismatchException( "Unsupported type conversion: %r to %r" % (sub.typ, self.context.return_type), self.stmt.value) # Returning a byte array elif isinstance(sub.typ, ByteArrayType): if not isinstance(self.context.return_type, ByteArrayType): raise TypeMismatchException( "Trying to return base type %r, output expecting %r" % (sub.typ, self.context.return_type), self.stmt.value) if sub.typ.maxlen > self.context.return_type.maxlen: raise TypeMismatchException( "Cannot cast from greater max-length %d to shorter max-length %d" % (sub.typ.maxlen, self.context.return_type.maxlen), self.stmt.value) # Returning something already in memory if sub.location == 'memory': return LLLnode.from_list([ 'with', '_loc', sub, [ 'seq', ['mstore', ['sub', '_loc', 32], 32], [ 'return', ['sub', '_loc', 32], ['ceil32', ['add', ['mload', '_loc'], 64]] ] ] ], typ=None, pos=getpos(self.stmt)) # Copying from storage elif sub.location == 'storage': # Instantiate a byte array at some index fake_byte_array = LLLnode(self.context.get_next_mem() + 32, typ=sub.typ, location='memory', pos=getpos(self.stmt)) o = [ 'seq', # Copy the data to this byte array make_byte_array_copier(fake_byte_array, sub), # Store the number 32 before it for ABI formatting purposes ['mstore', self.context.get_next_mem(), 32], # Return it [ 'return', self.context.get_next_mem(), [ 'add', [ 'ceil32', ['mload', self.context.get_next_mem() + 32] ], 64 ] ] ] return LLLnode.from_list(o, typ=None, pos=getpos(self.stmt)) else: raise Exception("Invalid location: %s" % sub.location) # Returning a list elif isinstance(sub.typ, ListType): if sub.location == "memory" and sub.value != "multi": return LLLnode.from_list([ 'return', sub, get_size_of_type(self.context.return_type) * 32 ], typ=None, pos=getpos(self.stmt)) else: new_sub = LLLnode.from_list(self.context.new_placeholder( self.context.return_type), typ=self.context.return_type, location='memory') setter = make_setter(new_sub, sub, 'memory') return LLLnode.from_list([ 'seq', setter, [ 'return', new_sub, get_size_of_type(self.context.return_type) * 32 ] ], typ=None, pos=getpos(self.stmt)) else: raise TypeMismatchException("Can only return base type!", self.stmt)