@@ -949,28 +949,25 @@ def parse_Call(self):
949949 return external_call .make_external_call (self .expr , self .context )
950950
951951 def parse_List (self ):
952- if not len (self .expr .elements ):
953- return
954-
955- def get_out_type (lll_node ):
956- if isinstance (lll_node , ListType ):
957- return get_out_type (lll_node .subtype )
958- return lll_node .typ
952+ call_lll , multi_lll = parse_sequence (self .expr , self .expr .elements , self .context )
953+ out_type = next ((i .typ for i in multi_lll if not i .typ .is_literal ), multi_lll [0 ].typ )
954+ typ = ListType (out_type , len (self .expr .elements ), is_literal = True )
955+ multi_lll = LLLnode .from_list (["multi" ] + multi_lll , typ = typ , pos = getpos (self .expr ))
956+ if not call_lll :
957+ return multi_lll
959958
960- lll_node = []
961- out_type = None
959+ lll_node = ["seq_unchecked" ] + call_lll + [ multi_lll ]
960+ return LLLnode . from_list ( lll_node , typ = typ , pos = getpos ( self . expr ))
962961
963- for elt in self .expr .elements :
964- current_lll_node = Expr (elt , self .context ).lll_node
965- if not out_type or not current_lll_node .typ .is_literal :
966- # prefer to use a non-literal type here, because literals can be ambiguous
967- # this should be removed altogether as we refactor types out of parser
968- out_type = current_lll_node .typ
969- lll_node .append (current_lll_node )
962+ def parse_Tuple (self ):
963+ call_lll , multi_lll = parse_sequence (self .expr , self .expr .elements , self .context )
964+ typ = TupleType ([x .typ for x in multi_lll ], is_literal = True )
965+ multi_lll = LLLnode .from_list (["multi" ] + multi_lll , typ = typ , pos = getpos (self .expr ))
966+ if not call_lll :
967+ return multi_lll
970968
971- return LLLnode .from_list (
972- ["multi" ] + lll_node , typ = ListType (out_type , len (lll_node )), pos = getpos (self .expr ),
973- )
969+ lll_node = ["seq_unchecked" ] + call_lll + [multi_lll ]
970+ return LLLnode .from_list (lll_node , typ = typ , pos = getpos (self .expr ))
974971
975972 @staticmethod
976973 def struct_literals (expr , name , context ):
@@ -990,39 +987,6 @@ def struct_literals(expr, name, context):
990987 pos = getpos (expr ),
991988 )
992989
993- def parse_Tuple (self ):
994- if not len (self .expr .elements ):
995- return
996- call_lll = []
997- multi_lll = []
998- for node in self .expr .elements :
999- if isinstance (node , vy_ast .Call ):
1000- # for calls inside the tuple, we perform the call prior to building the tuple and
1001- # assign it's result to memory - otherwise there is potential for memory corruption
1002- lll_node = Expr (node , self .context ).lll_node
1003- target = LLLnode .from_list (
1004- self .context .new_internal_variable (lll_node .typ ),
1005- typ = lll_node .typ ,
1006- location = "memory" ,
1007- pos = getpos (self .expr ),
1008- )
1009- call_lll .append (make_setter (target , lll_node , "memory" , pos = getpos (self .expr )))
1010- multi_lll .append (
1011- LLLnode .from_list (
1012- target , typ = lll_node .typ , pos = getpos (self .expr ), location = "memory"
1013- ),
1014- )
1015- else :
1016- multi_lll .append (Expr (node , self .context ).lll_node )
1017-
1018- typ = TupleType ([x .typ for x in multi_lll ], is_literal = True )
1019- multi_lll = LLLnode .from_list (["multi" ] + multi_lll , typ = typ , pos = getpos (self .expr ))
1020- if not call_lll :
1021- return multi_lll
1022-
1023- lll_node = ["seq_unchecked" ] + call_lll + [multi_lll ]
1024- return LLLnode .from_list (lll_node , typ = typ , pos = getpos (self .expr ))
1025-
1026990 # Parse an expression that results in a value
1027991 @classmethod
1028992 def parse_value_expr (cls , expr , context ):
@@ -1035,3 +999,63 @@ def parse_variable_location(cls, expr, context):
1035999 if not o .location :
10361000 raise StructureException ("Looking for a variable location, instead got a value" , expr )
10371001 return o
1002+
1003+
1004+ def parse_sequence (base_node , elements , context ):
1005+ """
1006+ Generate an LLL node from a sequence of Vyper AST nodes, such as values inside a
1007+ list/tuple or arguments inside a call.
1008+
1009+ Arguments
1010+ ---------
1011+ base_node : VyperNode
1012+ Parent node which contains the sequence being parsed.
1013+ elements : List[VyperNode]
1014+ A list of nodes within the sequence.
1015+ context : Context
1016+ Currently active local context.
1017+
1018+ Returns
1019+ -------
1020+ List[LLLNode]
1021+ LLL nodes that must execute prior to generating the actual sequence in order to
1022+ avoid memory corruption issues. This list may be empty, depending on the values
1023+ within `elements`.
1024+ List[LLLNode]
1025+ LLL nodes which collectively represent `elements`.
1026+ """
1027+ init_lll = []
1028+ sequence_lll = []
1029+ for node in elements :
1030+ if isinstance (node , vy_ast .List ):
1031+ # for nested lists, ensure the init LLL is also processed before the values
1032+ init , seq = parse_sequence (node , node .elements , context )
1033+ init_lll .extend (init )
1034+ out_type = next ((i .typ for i in seq if not i .typ .is_literal ), seq [0 ].typ )
1035+ typ = ListType (out_type , len (node .elements ), is_literal = True )
1036+ multi_lll = LLLnode .from_list (["multi" ] + seq , typ = typ , pos = getpos (node ))
1037+ sequence_lll .append (multi_lll )
1038+ continue
1039+
1040+ lll_node = Expr (node , context ).lll_node
1041+ if isinstance (node , vy_ast .Call ) or (
1042+ isinstance (node , vy_ast .Subscript ) and isinstance (node .value , vy_ast .Call )
1043+ ):
1044+ # nodes which potentially create their own internal memory variables, and so must
1045+ # be parsed prior to generating the final sequence to avoid memory corruption
1046+ target = LLLnode .from_list (
1047+ context .new_internal_variable (lll_node .typ ),
1048+ typ = lll_node .typ ,
1049+ location = "memory" ,
1050+ pos = getpos (base_node ),
1051+ )
1052+ init_lll .append (make_setter (target , lll_node , "memory" , pos = getpos (base_node )))
1053+ sequence_lll .append (
1054+ LLLnode .from_list (
1055+ target , typ = lll_node .typ , pos = getpos (base_node ), location = "memory"
1056+ ),
1057+ )
1058+ else :
1059+ sequence_lll .append (lll_node )
1060+
1061+ return init_lll , sequence_lll
0 commit comments