@@ -1888,6 +1888,19 @@ generate_EXECCONCAT(cctx_T *cctx, int count)
18881888 return OK ;
18891889}
18901890
1891+ static int
1892+ generate_UNPACK (cctx_T * cctx , int var_count , int semicolon )
1893+ {
1894+ isn_T * isn ;
1895+
1896+ RETURN_OK_IF_SKIP (cctx );
1897+ if ((isn = generate_instr (cctx , ISN_UNPACK )) == NULL )
1898+ return FAIL ;
1899+ isn -> isn_arg .unpack .unp_count = var_count ;
1900+ isn -> isn_arg .unpack .unp_semicolon = semicolon ;
1901+ return OK ;
1902+ }
1903+
18911904/*
18921905 * Generate an instruction for any command modifiers.
18931906 */
@@ -6323,12 +6336,12 @@ compile_endif(char_u *arg, cctx_T *cctx)
63236336}
63246337
63256338/*
6326- * compile "for var in expr"
6339+ * Compile "for var in expr":
63276340 *
63286341 * Produces instructions:
63296342 * PUSHNR -1
63306343 * STORE loop-idx Set index to -1
6331- * EVAL expr Push result of "expr"
6344+ * EVAL expr result of "expr" on top of stack
63326345 * top: FOR loop-idx, end Increment index, use list on bottom of stack
63336346 * - if beyond end, jump to "end"
63346347 * - otherwise get item from list and push it
@@ -6337,30 +6350,32 @@ compile_endif(char_u *arg, cctx_T *cctx)
63376350 * JUMP top Jump back to repeat
63386351 * end: DROP Drop the result of "expr"
63396352 *
6353+ * Compile "for [var1, var2] in expr" - as above, but instead of "STORE var":
6354+ * UNPACK 2 Split item in 2
6355+ * STORE var1 Store item in "var1"
6356+ * STORE var2 Store item in "var2"
63406357 */
63416358 static char_u *
6342- compile_for (char_u * arg , cctx_T * cctx )
6359+ compile_for (char_u * arg_start , cctx_T * cctx )
63436360{
6361+ char_u * arg ;
6362+ char_u * arg_end ;
63446363 char_u * p ;
6364+ int var_count = 0 ;
6365+ int semicolon = FALSE;
63456366 size_t varlen ;
63466367 garray_T * instr = & cctx -> ctx_instr ;
63476368 garray_T * stack = & cctx -> ctx_type_stack ;
63486369 scope_T * scope ;
63496370 lvar_T * loop_lvar ; // loop iteration variable
63506371 lvar_T * var_lvar ; // variable for "var"
63516372 type_T * vartype ;
6373+ type_T * item_type = & t_any ;
6374+ int idx ;
63526375
6353- // TODO: list of variables: "for [key, value] in dict"
6354- // parse "var"
6355- for (p = arg ; eval_isnamec1 (* p ); ++ p )
6356- ;
6357- varlen = p - arg ;
6358- var_lvar = lookup_local (arg , varlen , cctx );
6359- if (var_lvar != NULL )
6360- {
6361- semsg (_ (e_variable_already_declared ), arg );
6362- return NULL ;
6363- }
6376+ p = skip_var_list (arg_start , TRUE, & var_count , & semicolon , FALSE);
6377+ if (var_count == 0 )
6378+ var_count = 1 ;
63646379
63656380 // consume "in"
63666381 p = skipwhite (p );
@@ -6371,29 +6386,19 @@ compile_for(char_u *arg, cctx_T *cctx)
63716386 }
63726387 p = skipwhite (p + 2 );
63736388
6374-
63756389 scope = new_scope (cctx , FOR_SCOPE );
63766390 if (scope == NULL )
63776391 return NULL ;
63786392
6379- // Reserve a variable to store the loop iteration counter.
6393+ // Reserve a variable to store the loop iteration counter and initialize it
6394+ // to -1.
63806395 loop_lvar = reserve_local (cctx , (char_u * )"" , 0 , FALSE, & t_number );
63816396 if (loop_lvar == NULL )
63826397 {
63836398 // out of memory
63846399 drop_scope (cctx );
63856400 return NULL ;
63866401 }
6387-
6388- // Reserve a variable to store "var"
6389- var_lvar = reserve_local (cctx , arg , varlen , FALSE, & t_any );
6390- if (var_lvar == NULL )
6391- {
6392- // out of memory or used as an argument
6393- drop_scope (cctx );
6394- return NULL ;
6395- }
6396-
63976402 generate_STORENR (cctx , loop_lvar -> lv_idx , -1 );
63986403
63996404 // compile "expr", it remains on the stack until "endfor"
@@ -6403,6 +6408,7 @@ compile_for(char_u *arg, cctx_T *cctx)
64036408 drop_scope (cctx );
64046409 return NULL ;
64056410 }
6411+ arg_end = arg ;
64066412
64076413 // Now that we know the type of "var", check that it is a list, now or at
64086414 // runtime.
@@ -6412,16 +6418,78 @@ compile_for(char_u *arg, cctx_T *cctx)
64126418 drop_scope (cctx );
64136419 return NULL ;
64146420 }
6421+
64156422 if (vartype -> tt_type == VAR_LIST && vartype -> tt_member -> tt_type != VAR_ANY )
6416- var_lvar -> lv_type = vartype -> tt_member ;
6423+ {
6424+ if (var_count == 1 )
6425+ item_type = vartype -> tt_member ;
6426+ else if (vartype -> tt_member -> tt_type == VAR_LIST
6427+ && vartype -> tt_member -> tt_member -> tt_type != VAR_ANY )
6428+ item_type = vartype -> tt_member -> tt_member ;
6429+ }
64176430
64186431 // "for_end" is set when ":endfor" is found
64196432 scope -> se_u .se_for .fs_top_label = instr -> ga_len ;
6420-
64216433 generate_FOR (cctx , loop_lvar -> lv_idx );
6422- generate_STORE (cctx , ISN_STORE , var_lvar -> lv_idx , NULL );
64236434
6424- return arg ;
6435+ arg = arg_start ;
6436+ if (var_count > 1 )
6437+ {
6438+ generate_UNPACK (cctx , var_count , semicolon );
6439+ arg = skipwhite (arg + 1 ); // skip white after '['
6440+
6441+ // the list item is replaced by a number of items
6442+ if (ga_grow (stack , var_count - 1 ) == FAIL )
6443+ {
6444+ drop_scope (cctx );
6445+ return NULL ;
6446+ }
6447+ -- stack -> ga_len ;
6448+ for (idx = 0 ; idx < var_count ; ++ idx )
6449+ {
6450+ ((type_T * * )stack -> ga_data )[stack -> ga_len ] =
6451+ (semicolon && idx == 0 ) ? vartype : item_type ;
6452+ ++ stack -> ga_len ;
6453+ }
6454+ }
6455+
6456+ for (idx = 0 ; idx < var_count ; ++ idx )
6457+ {
6458+ // TODO: use skip_var_one, also assign to @r, $VAR, etc.
6459+ p = arg ;
6460+ while (eval_isnamec (* p ))
6461+ ++ p ;
6462+ varlen = p - arg ;
6463+ var_lvar = lookup_local (arg , varlen , cctx );
6464+ if (var_lvar != NULL )
6465+ {
6466+ semsg (_ (e_variable_already_declared ), arg );
6467+ drop_scope (cctx );
6468+ return NULL ;
6469+ }
6470+
6471+ // Reserve a variable to store "var".
6472+ // TODO: check for type
6473+ var_lvar = reserve_local (cctx , arg , varlen , FALSE, & t_any );
6474+ if (var_lvar == NULL )
6475+ {
6476+ // out of memory or used as an argument
6477+ drop_scope (cctx );
6478+ return NULL ;
6479+ }
6480+
6481+ if (semicolon && idx == var_count - 1 )
6482+ var_lvar -> lv_type = vartype ;
6483+ else
6484+ var_lvar -> lv_type = item_type ;
6485+ generate_STORE (cctx , ISN_STORE , var_lvar -> lv_idx , NULL );
6486+
6487+ if (* p == ',' || * p == ';' )
6488+ ++ p ;
6489+ arg = skipwhite (p );
6490+ }
6491+
6492+ return arg_end ;
64256493}
64266494
64276495/*
@@ -7957,6 +8025,7 @@ delete_instr(isn_T *isn)
79578025 case ISN_STRSLICE :
79588026 case ISN_THROW :
79598027 case ISN_TRY :
8028+ case ISN_UNPACK :
79608029 // nothing allocated
79618030 break ;
79628031 }
0 commit comments