@@ -949,28 +949,25 @@ def parse_Call(self):
949
949
return external_call .make_external_call (self .expr , self .context )
950
950
951
951
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
959
958
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 ))
962
961
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
970
968
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 ))
974
971
975
972
@staticmethod
976
973
def struct_literals (expr , name , context ):
@@ -990,39 +987,6 @@ def struct_literals(expr, name, context):
990
987
pos = getpos (expr ),
991
988
)
992
989
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
-
1026
990
# Parse an expression that results in a value
1027
991
@classmethod
1028
992
def parse_value_expr (cls , expr , context ):
@@ -1035,3 +999,63 @@ def parse_variable_location(cls, expr, context):
1035
999
if not o .location :
1036
1000
raise StructureException ("Looking for a variable location, instead got a value" , expr )
1037
1001
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