Mercurial > vim
comparison src/vim9compile.c @ 22975:a943b175586a v8.2.2034
patch 8.2.2034: Vim9: list unpack in for statement not compiled yet
Commit: https://github.com/vim/vim/commit/792f786aad8409ca9ab895392742643a5b6aed8f
Author: Bram Moolenaar <Bram@vim.org>
Date: Mon Nov 23 08:31:18 2020 +0100
patch 8.2.2034: Vim9: list unpack in for statement not compiled yet
Problem: Vim9: list unpack in for statement not compiled yet.
Solution: Compile list unpack. (closes https://github.com/vim/vim/issues/7345)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Mon, 23 Nov 2020 08:45:04 +0100 |
parents | 4c97c0747017 |
children | b98003d73150 |
comparison
equal
deleted
inserted
replaced
22974:3f8025537dd9 | 22975:a943b175586a |
---|---|
1883 isn_T *isn; | 1883 isn_T *isn; |
1884 | 1884 |
1885 if ((isn = generate_instr_drop(cctx, ISN_EXECCONCAT, count)) == NULL) | 1885 if ((isn = generate_instr_drop(cctx, ISN_EXECCONCAT, count)) == NULL) |
1886 return FAIL; | 1886 return FAIL; |
1887 isn->isn_arg.number = count; | 1887 isn->isn_arg.number = count; |
1888 return OK; | |
1889 } | |
1890 | |
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; | |
1888 return OK; | 1901 return OK; |
1889 } | 1902 } |
1890 | 1903 |
1891 /* | 1904 /* |
1892 * Generate an instruction for any command modifiers. | 1905 * Generate an instruction for any command modifiers. |
6321 drop_scope(cctx); | 6334 drop_scope(cctx); |
6322 return arg; | 6335 return arg; |
6323 } | 6336 } |
6324 | 6337 |
6325 /* | 6338 /* |
6326 * compile "for var in expr" | 6339 * Compile "for var in expr": |
6327 * | 6340 * |
6328 * Produces instructions: | 6341 * Produces instructions: |
6329 * PUSHNR -1 | 6342 * PUSHNR -1 |
6330 * STORE loop-idx Set index to -1 | 6343 * STORE loop-idx Set index to -1 |
6331 * EVAL expr Push result of "expr" | 6344 * EVAL expr result of "expr" on top of stack |
6332 * top: FOR loop-idx, end Increment index, use list on bottom of stack | 6345 * top: FOR loop-idx, end Increment index, use list on bottom of stack |
6333 * - if beyond end, jump to "end" | 6346 * - if beyond end, jump to "end" |
6334 * - otherwise get item from list and push it | 6347 * - otherwise get item from list and push it |
6335 * STORE var Store item in "var" | 6348 * STORE var Store item in "var" |
6336 * ... body ... | 6349 * ... body ... |
6337 * JUMP top Jump back to repeat | 6350 * JUMP top Jump back to repeat |
6338 * end: DROP Drop the result of "expr" | 6351 * end: DROP Drop the result of "expr" |
6339 * | 6352 * |
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" | |
6340 */ | 6357 */ |
6341 static char_u * | 6358 static char_u * |
6342 compile_for(char_u *arg, cctx_T *cctx) | 6359 compile_for(char_u *arg_start, cctx_T *cctx) |
6343 { | 6360 { |
6361 char_u *arg; | |
6362 char_u *arg_end; | |
6344 char_u *p; | 6363 char_u *p; |
6364 int var_count = 0; | |
6365 int semicolon = FALSE; | |
6345 size_t varlen; | 6366 size_t varlen; |
6346 garray_T *instr = &cctx->ctx_instr; | 6367 garray_T *instr = &cctx->ctx_instr; |
6347 garray_T *stack = &cctx->ctx_type_stack; | 6368 garray_T *stack = &cctx->ctx_type_stack; |
6348 scope_T *scope; | 6369 scope_T *scope; |
6349 lvar_T *loop_lvar; // loop iteration variable | 6370 lvar_T *loop_lvar; // loop iteration variable |
6350 lvar_T *var_lvar; // variable for "var" | 6371 lvar_T *var_lvar; // variable for "var" |
6351 type_T *vartype; | 6372 type_T *vartype; |
6352 | 6373 type_T *item_type = &t_any; |
6353 // TODO: list of variables: "for [key, value] in dict" | 6374 int idx; |
6354 // parse "var" | 6375 |
6355 for (p = arg; eval_isnamec1(*p); ++p) | 6376 p = skip_var_list(arg_start, TRUE, &var_count, &semicolon, FALSE); |
6356 ; | 6377 if (var_count == 0) |
6357 varlen = p - arg; | 6378 var_count = 1; |
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 } | |
6364 | 6379 |
6365 // consume "in" | 6380 // consume "in" |
6366 p = skipwhite(p); | 6381 p = skipwhite(p); |
6367 if (STRNCMP(p, "in", 2) != 0 || !VIM_ISWHITE(p[2])) | 6382 if (STRNCMP(p, "in", 2) != 0 || !VIM_ISWHITE(p[2])) |
6368 { | 6383 { |
6369 emsg(_(e_missing_in)); | 6384 emsg(_(e_missing_in)); |
6370 return NULL; | 6385 return NULL; |
6371 } | 6386 } |
6372 p = skipwhite(p + 2); | 6387 p = skipwhite(p + 2); |
6373 | 6388 |
6374 | |
6375 scope = new_scope(cctx, FOR_SCOPE); | 6389 scope = new_scope(cctx, FOR_SCOPE); |
6376 if (scope == NULL) | 6390 if (scope == NULL) |
6377 return NULL; | 6391 return NULL; |
6378 | 6392 |
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. | |
6380 loop_lvar = reserve_local(cctx, (char_u *)"", 0, FALSE, &t_number); | 6395 loop_lvar = reserve_local(cctx, (char_u *)"", 0, FALSE, &t_number); |
6381 if (loop_lvar == NULL) | 6396 if (loop_lvar == NULL) |
6382 { | 6397 { |
6383 // out of memory | 6398 // out of memory |
6384 drop_scope(cctx); | 6399 drop_scope(cctx); |
6385 return NULL; | 6400 return NULL; |
6386 } | 6401 } |
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 | |
6397 generate_STORENR(cctx, loop_lvar->lv_idx, -1); | 6402 generate_STORENR(cctx, loop_lvar->lv_idx, -1); |
6398 | 6403 |
6399 // compile "expr", it remains on the stack until "endfor" | 6404 // compile "expr", it remains on the stack until "endfor" |
6400 arg = p; | 6405 arg = p; |
6401 if (compile_expr0(&arg, cctx) == FAIL) | 6406 if (compile_expr0(&arg, cctx) == FAIL) |
6402 { | 6407 { |
6403 drop_scope(cctx); | 6408 drop_scope(cctx); |
6404 return NULL; | 6409 return NULL; |
6405 } | 6410 } |
6411 arg_end = arg; | |
6406 | 6412 |
6407 // Now that we know the type of "var", check that it is a list, now or at | 6413 // Now that we know the type of "var", check that it is a list, now or at |
6408 // runtime. | 6414 // runtime. |
6409 vartype = ((type_T **)stack->ga_data)[stack->ga_len - 1]; | 6415 vartype = ((type_T **)stack->ga_data)[stack->ga_len - 1]; |
6410 if (need_type(vartype, &t_list_any, -1, cctx, FALSE, FALSE) == FAIL) | 6416 if (need_type(vartype, &t_list_any, -1, cctx, FALSE, FALSE) == FAIL) |
6411 { | 6417 { |
6412 drop_scope(cctx); | 6418 drop_scope(cctx); |
6413 return NULL; | 6419 return NULL; |
6414 } | 6420 } |
6421 | |
6415 if (vartype->tt_type == VAR_LIST && vartype->tt_member->tt_type != VAR_ANY) | 6422 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 } | |
6417 | 6430 |
6418 // "for_end" is set when ":endfor" is found | 6431 // "for_end" is set when ":endfor" is found |
6419 scope->se_u.se_for.fs_top_label = instr->ga_len; | 6432 scope->se_u.se_for.fs_top_label = instr->ga_len; |
6420 | |
6421 generate_FOR(cctx, loop_lvar->lv_idx); | 6433 generate_FOR(cctx, loop_lvar->lv_idx); |
6422 generate_STORE(cctx, ISN_STORE, var_lvar->lv_idx, NULL); | 6434 |
6423 | 6435 arg = arg_start; |
6424 return arg; | 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; | |
6425 } | 6493 } |
6426 | 6494 |
6427 /* | 6495 /* |
6428 * compile "endfor" | 6496 * compile "endfor" |
6429 */ | 6497 */ |
7955 case ISN_STOREV: | 8023 case ISN_STOREV: |
7956 case ISN_STRINDEX: | 8024 case ISN_STRINDEX: |
7957 case ISN_STRSLICE: | 8025 case ISN_STRSLICE: |
7958 case ISN_THROW: | 8026 case ISN_THROW: |
7959 case ISN_TRY: | 8027 case ISN_TRY: |
8028 case ISN_UNPACK: | |
7960 // nothing allocated | 8029 // nothing allocated |
7961 break; | 8030 break; |
7962 } | 8031 } |
7963 } | 8032 } |
7964 | 8033 |