def build_in_comparator(self): from viper.parser.parser import make_setter left = Expr(self.expr.left, self.context).lll_node right = Expr(self.expr.comparators[0], self.context).lll_node result_placeholder = self.context.new_placeholder(BaseType('bool')) setter = [] # Load nth item from list in memory. if right.value == 'multi': # Copy literal to memory to be compared. tmp_list = LLLnode.from_list( obj=self.context.new_placeholder(ListType(right.typ.subtype, right.typ.count)), typ=ListType(right.typ.subtype, right.typ.count), location='memory' ) setter = make_setter(tmp_list, right, 'memory') load_i_from_list = ['mload', ['add', tmp_list, ['mul', 32, ['mload', MemoryPositions.FREE_LOOP_INDEX]]]] elif right.location == "storage": load_i_from_list = ['sload', ['add', ['sha3_32', right], ['mload', MemoryPositions.FREE_LOOP_INDEX]]] else: load_i_from_list = ['mload', ['add', right, ['mul', 32, ['mload', MemoryPositions.FREE_LOOP_INDEX]]]] # Condition repeat loop has to break on. break_loop_condition = [ 'if', ['eq', unwrap_location(left), load_i_from_list], ['seq', ['mstore', '_result', 1], # store true. 'break'] ] # Repeat loop to loop-compare each item in the list. for_loop_sequence = [ ['mstore', result_placeholder, 0], ['with', '_result', result_placeholder, ['repeat', MemoryPositions.FREE_LOOP_INDEX, 0, right.typ.count, break_loop_condition]], ['mload', result_placeholder] ] # Save list to memory, so one can iterate over it, # used when literal was created with tmp_list. if setter: compare_sequence = ['seq', setter] + for_loop_sequence else: compare_sequence = ['seq'] + for_loop_sequence # Compare the result of the repeat loop to 1, to know if a match was found. o = LLLnode.from_list([ 'eq', 1, compare_sequence], typ='bool', annotation="in comporator" ) return o
def list_literals(self): if not len(self.expr.elts): raise StructureException("List must have elements", self.expr) o = [] out_type = None for elt in self.expr.elts: o.append(Expr(elt, self.context).lll_node) if not out_type: out_type = o[-1].typ elif len(o) > 1 and o[-1].typ != out_type: out_type = MixedType() return LLLnode.from_list(["multi"] + o, typ=ListType(out_type, len(o)), pos=getpos(self.expr))
def list_literals(self): if not len(self.expr.elts): raise StructureException("List must have elements", self.expr) o = [] out_type = None for elt in self.expr.elts: o.append(Expr(elt, self.context).lll_node) if not out_type: out_type = o[-1].typ previous_type = o[-1].typ.subtype.typ if hasattr( o[-1].typ, 'subtype') else o[-1].typ current_type = out_type.subtype.typ if hasattr( out_type, 'subtype') else out_type if len(o) > 1 and previous_type != current_type: raise TypeMismatchException("Lists may only contain one type", self.expr) return LLLnode.from_list(["multi"] + o, typ=ListType(out_type, len(o)), pos=getpos(self.expr))
def parse_for_list(self): from .parser import (parse_body, make_setter) iter_list_node = Expr(self.stmt.iter, self.context).lll_node if not isinstance(iter_list_node.typ.subtype, BaseType): # Sanity check on list subtype. raise StructureException( 'For loops allowed only on basetype lists.', self.stmt.iter) iter_var_type = self.context.vars.get( self.stmt.iter.id).typ if isinstance(self.stmt.iter, ast.Name) else None subtype = iter_list_node.typ.subtype.typ varname = self.stmt.target.id value_pos = self.context.new_variable(varname, BaseType(subtype)) i_pos = self.context.new_variable('_index_for_' + varname, BaseType(subtype)) self.context.forvars[varname] = True if iter_var_type: # Is a list that is already allocated to memory. self.context.set_in_for_loop( self.stmt.iter.id ) # make sure list cannot be altered whilst iterating. iter_var = self.context.vars.get(self.stmt.iter.id) body = [ 'seq', [ 'mstore', value_pos, [ 'mload', ['add', iter_var.pos, ['mul', ['mload', i_pos], 32]] ] ], parse_body(self.stmt.body, self.context) ] o = LLLnode.from_list(['repeat', i_pos, 0, iter_var.size, body], typ=None, pos=getpos(self.stmt)) self.context.remove_in_for_loop(self.stmt.iter.id) elif isinstance(self.stmt.iter, ast.List): # List gets defined in the for statement. # Allocate list to memory. count = iter_list_node.typ.count tmp_list = LLLnode.from_list(obj=self.context.new_placeholder( ListType(iter_list_node.typ.subtype, count)), typ=ListType( iter_list_node.typ.subtype, count), location='memory') setter = make_setter(tmp_list, iter_list_node, 'memory') body = [ 'seq', [ 'mstore', value_pos, [ 'mload', ['add', tmp_list, ['mul', ['mload', i_pos], 32]] ] ], parse_body(self.stmt.body, self.context) ] o = LLLnode.from_list( ['seq', setter, ['repeat', i_pos, 0, count, body]], typ=None, pos=getpos(self.stmt)) elif isinstance(self.stmt.iter, ast.Attribute): # List is contained in storage. count = iter_list_node.typ.count self.context.set_in_for_loop( iter_list_node.annotation ) # make sure list cannot be altered whilst iterating. body = [ 'seq', [ 'mstore', value_pos, [ 'sload', ['add', ['sha3_32', iter_list_node], ['mload', i_pos]] ] ], parse_body(self.stmt.body, self.context), ] o = LLLnode.from_list(['seq', ['repeat', i_pos, 0, count, body]], typ=None, pos=getpos(self.stmt)) self.context.remove_in_for_loop(iter_list_node.annotation) del self.context.vars[varname] del self.context.vars['_index_for_' + varname] del self.context.forvars[varname] return o