comparison src/vim9compile.c @ 24220:a7a9176bb542 v8.2.2651

patch 8.2.2651: Vim9: restoring command modifiers happens after jump Commit: https://github.com/vim/vim/commit/a91a71322dc2e6a1640e73b6da1f1a2f94f39a54 Author: Bram Moolenaar <Bram@vim.org> Date: Thu Mar 25 21:12:15 2021 +0100 patch 8.2.2651: Vim9: restoring command modifiers happens after jump Problem: Vim9: restoring command modifiers happens after jump. Solution: Move the restore instruction to before the jump. (closes https://github.com/vim/vim/issues/8006) Also handle for and while.
author Bram Moolenaar <Bram@vim.org>
date Thu, 25 Mar 2021 21:15:04 +0100
parents 5f3a2d31c48d
children a2e6029d354e
comparison
equal deleted inserted replaced
24219:529521098193 24220:a7a9176bb542
2168 { 2168 {
2169 if (cctx->ctx_has_cmdmod && generate_instr(cctx, ISN_CMDMOD_REV) == NULL) 2169 if (cctx->ctx_has_cmdmod && generate_instr(cctx, ISN_CMDMOD_REV) == NULL)
2170 return FAIL; 2170 return FAIL;
2171 cctx->ctx_has_cmdmod = FALSE; 2171 cctx->ctx_has_cmdmod = FALSE;
2172 return OK; 2172 return OK;
2173 }
2174
2175 /*
2176 * If an ISN_CMDMOD was just generated drop it.
2177 */
2178 static void
2179 drop_cmdmod(cctx_T *cctx)
2180 {
2181 garray_T *instr = &cctx->ctx_instr;
2182
2183 // Drop any CMDMOD instruction
2184 if (cctx->ctx_has_cmdmod
2185 && ((isn_T *)instr->ga_data)[instr->ga_len - 1].isn_type
2186 == ISN_CMDMOD)
2187 {
2188 --instr->ga_len;
2189 cctx->ctx_has_cmdmod = FALSE;
2190 }
2191 }
2192
2193 /*
2194 * Get the index of the current instruction.
2195 * This compenstates for a preceding ISN_CMDMOD and ISN_PROF_START.
2196 */
2197 static int
2198 current_instr_idx(cctx_T *cctx)
2199 {
2200 garray_T *instr = &cctx->ctx_instr;
2201 int idx = instr->ga_len;
2202
2203 if (cctx->ctx_has_cmdmod && ((isn_T *)instr->ga_data)[idx - 1]
2204 .isn_type == ISN_CMDMOD)
2205 --idx;
2206 #ifdef FEAT_PROFILE
2207 if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[idx - 1]
2208 .isn_type == ISN_PROF_START)
2209 --idx;
2210 #endif
2211 return idx;
2173 } 2212 }
2174 2213
2175 #ifdef FEAT_PROFILE 2214 #ifdef FEAT_PROFILE
2176 static void 2215 static void
2177 may_generate_prof_end(cctx_T *cctx, int prof_lnum) 2216 may_generate_prof_end(cctx_T *cctx, int prof_lnum)
6875 return NULL; 6914 return NULL;
6876 if (bool_on_stack(cctx) == FAIL) 6915 if (bool_on_stack(cctx) == FAIL)
6877 return NULL; 6916 return NULL;
6878 } 6917 }
6879 6918
6919 // CMDMOD_REV must come before the jump
6920 generate_undo_cmdmods(cctx);
6921
6880 scope = new_scope(cctx, IF_SCOPE); 6922 scope = new_scope(cctx, IF_SCOPE);
6881 if (scope == NULL) 6923 if (scope == NULL)
6882 return NULL; 6924 return NULL;
6883 scope->se_skip_save = skip_save; 6925 scope->se_skip_save = skip_save;
6884 // "is_had_return" will be reset if any block does not end in :return 6926 // "is_had_return" will be reset if any block does not end in :return
6935 scope->se_u.se_if.is_seen_skip_not = TRUE; 6977 scope->se_u.se_if.is_seen_skip_not = TRUE;
6936 } 6978 }
6937 if (scope->se_u.se_if.is_seen_skip_not) 6979 if (scope->se_u.se_if.is_seen_skip_not)
6938 { 6980 {
6939 // A previous block was executed, skip over expression and bail out. 6981 // A previous block was executed, skip over expression and bail out.
6940 // Do not count the "elseif" for profiling. 6982 // Do not count the "elseif" for profiling and cmdmod
6941 #ifdef FEAT_PROFILE 6983 instr->ga_len = current_instr_idx(cctx);
6942 if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[instr->ga_len - 1] 6984
6943 .isn_type == ISN_PROF_START)
6944 --instr->ga_len;
6945 #endif
6946 skip_expr_cctx(&p, cctx); 6985 skip_expr_cctx(&p, cctx);
6947 return p; 6986 return p;
6948 } 6987 }
6949 6988
6950 if (cctx->ctx_skip == SKIP_UNKNOWN) 6989 if (cctx->ctx_skip == SKIP_UNKNOWN)
6951 { 6990 {
6991 int moved_cmdmod = FALSE;
6992
6993 // Move any CMDMOD instruction to after the jump
6994 if (((isn_T *)instr->ga_data)[instr->ga_len - 1].isn_type == ISN_CMDMOD)
6995 {
6996 if (ga_grow(instr, 1) == FAIL)
6997 return NULL;
6998 ((isn_T *)instr->ga_data)[instr->ga_len] =
6999 ((isn_T *)instr->ga_data)[instr->ga_len - 1];
7000 --instr->ga_len;
7001 moved_cmdmod = TRUE;
7002 }
7003
6952 if (compile_jump_to_end(&scope->se_u.se_if.is_end_label, 7004 if (compile_jump_to_end(&scope->se_u.se_if.is_end_label,
6953 JUMP_ALWAYS, cctx) == FAIL) 7005 JUMP_ALWAYS, cctx) == FAIL)
6954 return NULL; 7006 return NULL;
6955 // previous "if" or "elseif" jumps here 7007 // previous "if" or "elseif" jumps here
6956 isn = ((isn_T *)instr->ga_data) + scope->se_u.se_if.is_if_label; 7008 isn = ((isn_T *)instr->ga_data) + scope->se_u.se_if.is_if_label;
6957 isn->isn_arg.jump.jump_where = instr->ga_len; 7009 isn->isn_arg.jump.jump_where = instr->ga_len;
7010 if (moved_cmdmod)
7011 ++instr->ga_len;
6958 } 7012 }
6959 7013
6960 // compile "expr"; if we know it evaluates to FALSE skip the block 7014 // compile "expr"; if we know it evaluates to FALSE skip the block
6961 CLEAR_FIELD(ppconst); 7015 CLEAR_FIELD(ppconst);
6962 if (cctx->ctx_skip == SKIP_YES) 7016 if (cctx->ctx_skip == SKIP_YES)
7005 if (generate_ppconst(cctx, &ppconst) == FAIL) 7059 if (generate_ppconst(cctx, &ppconst) == FAIL)
7006 return NULL; 7060 return NULL;
7007 if (bool_on_stack(cctx) == FAIL) 7061 if (bool_on_stack(cctx) == FAIL)
7008 return NULL; 7062 return NULL;
7009 7063
7064 // CMDMOD_REV must come before the jump
7065 generate_undo_cmdmods(cctx);
7066
7010 // "where" is set when ":elseif", "else" or ":endif" is found 7067 // "where" is set when ":elseif", "else" or ":endif" is found
7011 scope->se_u.se_if.is_if_label = instr->ga_len; 7068 scope->se_u.se_if.is_if_label = instr->ga_len;
7012 generate_JUMP(cctx, JUMP_IF_FALSE, 0); 7069 generate_JUMP(cctx, JUMP_IF_FALSE, 0);
7013 } 7070 }
7014 7071
7088 scope_T *scope = cctx->ctx_scope; 7145 scope_T *scope = cctx->ctx_scope;
7089 ifscope_T *ifscope; 7146 ifscope_T *ifscope;
7090 garray_T *instr = &cctx->ctx_instr; 7147 garray_T *instr = &cctx->ctx_instr;
7091 isn_T *isn; 7148 isn_T *isn;
7092 7149
7150 drop_cmdmod(cctx);
7093 if (scope == NULL || scope->se_type != IF_SCOPE) 7151 if (scope == NULL || scope->se_type != IF_SCOPE)
7094 { 7152 {
7095 emsg(_(e_endif_without_if)); 7153 emsg(_(e_endif_without_if));
7096 return NULL; 7154 return NULL;
7097 } 7155 }
7158 char_u *p; 7216 char_u *p;
7159 char_u *wp; 7217 char_u *wp;
7160 int var_count = 0; 7218 int var_count = 0;
7161 int semicolon = FALSE; 7219 int semicolon = FALSE;
7162 size_t varlen; 7220 size_t varlen;
7163 garray_T *instr = &cctx->ctx_instr;
7164 garray_T *stack = &cctx->ctx_type_stack; 7221 garray_T *stack = &cctx->ctx_type_stack;
7165 scope_T *scope; 7222 scope_T *scope;
7166 lvar_T *loop_lvar; // loop iteration variable 7223 lvar_T *loop_lvar; // loop iteration variable
7167 lvar_T *var_lvar; // variable for "var" 7224 lvar_T *var_lvar; // variable for "var"
7168 type_T *vartype; 7225 type_T *vartype;
7228 else if (vartype->tt_member->tt_type == VAR_LIST 7285 else if (vartype->tt_member->tt_type == VAR_LIST
7229 && vartype->tt_member->tt_member->tt_type != VAR_ANY) 7286 && vartype->tt_member->tt_member->tt_type != VAR_ANY)
7230 item_type = vartype->tt_member->tt_member; 7287 item_type = vartype->tt_member->tt_member;
7231 } 7288 }
7232 7289
7290 // CMDMOD_REV must come before the FOR instruction
7291 generate_undo_cmdmods(cctx);
7292
7233 // "for_end" is set when ":endfor" is found 7293 // "for_end" is set when ":endfor" is found
7234 scope->se_u.se_for.fs_top_label = instr->ga_len; 7294 scope->se_u.se_for.fs_top_label = current_instr_idx(cctx);
7235 generate_FOR(cctx, loop_lvar->lv_idx); 7295 generate_FOR(cctx, loop_lvar->lv_idx);
7236 7296
7237 arg = arg_start; 7297 arg = arg_start;
7238 if (var_count > 1) 7298 if (var_count > 1)
7239 { 7299 {
7330 { 7390 {
7331 garray_T *instr = &cctx->ctx_instr; 7391 garray_T *instr = &cctx->ctx_instr;
7332 scope_T *scope = cctx->ctx_scope; 7392 scope_T *scope = cctx->ctx_scope;
7333 forscope_T *forscope; 7393 forscope_T *forscope;
7334 isn_T *isn; 7394 isn_T *isn;
7395
7396 drop_cmdmod(cctx);
7335 7397
7336 if (scope == NULL || scope->se_type != FOR_SCOPE) 7398 if (scope == NULL || scope->se_type != FOR_SCOPE)
7337 { 7399 {
7338 emsg(_(e_for)); 7400 emsg(_(e_for));
7339 return NULL; 7401 return NULL;
7374 */ 7436 */
7375 static char_u * 7437 static char_u *
7376 compile_while(char_u *arg, cctx_T *cctx) 7438 compile_while(char_u *arg, cctx_T *cctx)
7377 { 7439 {
7378 char_u *p = arg; 7440 char_u *p = arg;
7379 garray_T *instr = &cctx->ctx_instr;
7380 scope_T *scope; 7441 scope_T *scope;
7381 7442
7382 scope = new_scope(cctx, WHILE_SCOPE); 7443 scope = new_scope(cctx, WHILE_SCOPE);
7383 if (scope == NULL) 7444 if (scope == NULL)
7384 return NULL; 7445 return NULL;
7385 7446
7386 // "endwhile" jumps back here, one before when profiling 7447 // "endwhile" jumps back here, one before when profiling or using cmdmods
7387 scope->se_u.se_while.ws_top_label = instr->ga_len; 7448 scope->se_u.se_while.ws_top_label = current_instr_idx(cctx);
7388 #ifdef FEAT_PROFILE
7389 if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
7390 .isn_type == ISN_PROF_START)
7391 --scope->se_u.se_while.ws_top_label;
7392 #endif
7393 7449
7394 // compile "expr" 7450 // compile "expr"
7395 if (compile_expr0(&p, cctx) == FAIL) 7451 if (compile_expr0(&p, cctx) == FAIL)
7396 return NULL; 7452 return NULL;
7397 if (!ends_excmd2(arg, skipwhite(p))) 7453 if (!ends_excmd2(arg, skipwhite(p)))
7401 } 7457 }
7402 7458
7403 if (bool_on_stack(cctx) == FAIL) 7459 if (bool_on_stack(cctx) == FAIL)
7404 return FAIL; 7460 return FAIL;
7405 7461
7462 // CMDMOD_REV must come before the jump
7463 generate_undo_cmdmods(cctx);
7464
7406 // "while_end" is set when ":endwhile" is found 7465 // "while_end" is set when ":endwhile" is found
7407 if (compile_jump_to_end(&scope->se_u.se_while.ws_end_label, 7466 if (compile_jump_to_end(&scope->se_u.se_while.ws_end_label,
7408 JUMP_IF_FALSE, cctx) == FAIL) 7467 JUMP_IF_FALSE, cctx) == FAIL)
7409 return FAIL; 7468 return FAIL;
7410 7469
7418 compile_endwhile(char_u *arg, cctx_T *cctx) 7477 compile_endwhile(char_u *arg, cctx_T *cctx)
7419 { 7478 {
7420 scope_T *scope = cctx->ctx_scope; 7479 scope_T *scope = cctx->ctx_scope;
7421 garray_T *instr = &cctx->ctx_instr; 7480 garray_T *instr = &cctx->ctx_instr;
7422 7481
7482 drop_cmdmod(cctx);
7423 if (scope == NULL || scope->se_type != WHILE_SCOPE) 7483 if (scope == NULL || scope->se_type != WHILE_SCOPE)
7424 { 7484 {
7425 emsg(_(e_while)); 7485 emsg(_(e_while));
7426 return NULL; 7486 return NULL;
7427 } 7487 }