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
def build_in_comparator(self): from vyper.parser.parser import make_setter left = Expr(self.expr.left, self.context).lll_node right = Expr(self.expr.comparators[0], self.context).lll_node if left.typ.typ != right.typ.subtype.typ: raise TypeMismatchException("%s cannot be in a list of %s" % (left.typ.typ, right.typ.subtype.typ)) 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', pos=getpos(self.expr)) 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 parse_for_list(self): with self.context.range_scope(): 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, unit=iter_list_node.typ.subtype.unit), ) i_pos_raw_name = '_index_for_' + varname i_pos = self.context.new_internal_variable( i_pos_raw_name, BaseType(subtype), ) self.context.forvars[varname] = True # Is a list that is already allocated to memory. if iter_var_type: list_name = self.stmt.iter.id # make sure list cannot be altered whilst iterating. with self.context.in_for_loop_scope(list_name): iter_var = self.context.vars.get(self.stmt.iter.id) if iter_var.location == 'calldata': fetcher = 'calldataload' elif iter_var.location == 'memory': fetcher = 'mload' else: raise CompilerPanic( f'List iteration only supported on in-memory types {self.expr}', ) body = [ 'seq', [ 'mstore', value_pos, [ fetcher, [ '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)) # List gets defined in the for statement. elif isinstance(self.stmt.iter, ast.List): # 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', pos=getpos(self.stmt)) 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)) # List contained in storage. elif isinstance(self.stmt.iter, ast.Attribute): count = iter_list_node.typ.count list_name = iter_list_node.annotation # make sure list cannot be altered whilst iterating. with self.context.in_for_loop_scope(list_name): 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)) del self.context.vars[varname] # this kind of open access to the vars dict should be disallowed. # we should use member functions to provide an API for these kinds # of operations. del self.context.vars[self.context._mangle(i_pos_raw_name)] del self.context.forvars[varname] return o