Problem: Vim9: can use command modifier without an effect.
Solution: Give an error for a misplaced command modifier. Fix error message
number.
return OK;
}
+/*
+ * Return TRUE if "cmod" has anything set.
+ */
+ int
+has_cmdmod(cmdmod_T *cmod)
+{
+ return cmod->cmod_flags != 0
+ || cmod->cmod_split != 0
+ || cmod->cmod_verbose != 0
+ || cmod->cmod_tab != 0
+ || cmod->cmod_filter_regmatch.regprog != NULL;
+}
+
+/*
+ * If Vim9 script and "cmdmod" has anything set give an error and return TRUE.
+ */
+ int
+cmdmod_error(void)
+{
+ if (in_vim9script() && has_cmdmod(&cmdmod))
+ {
+ emsg(_(e_misplaced_command_modifier));
+ return TRUE;
+ }
+ return FALSE;
+}
+
/*
* Apply the command modifiers. Saves current state in "cmdmod", call
* undo_cmdmod() later.
{
cstack_T *cstack = eap->cstack;
+ if (cmdmod_error())
+ return;
did_endif = TRUE;
if (cstack->cs_idx < 0
|| (cstack->cs_flags[cstack->cs_idx]
int csf;
int fl;
+ if (cmdmod_error())
+ return;
+
if (eap->cmdidx == CMD_endwhile)
{
err = e_while;
int skip;
cstack_T *cstack = eap->cstack;
+ if (cmdmod_error())
+ return;
+
if (cstack->cs_idx == CSTACK_LEN - 1)
eap->errmsg = _("E601: :try nesting too deep");
else
cstack_T *cstack = eap->cstack;
char_u *pat;
+ if (cmdmod_error())
+ return;
+
if (cstack->cs_trylevel <= 0 || cstack->cs_idx < 0)
{
eap->errmsg = _(e_catch);
int pending = CSTP_NONE;
cstack_T *cstack = eap->cstack;
+ if (cmdmod_error())
+ return;
+
if (cstack->cs_trylevel <= 0 || cstack->cs_idx < 0)
eap->errmsg = _(e_finally);
else
void *rettv = NULL;
cstack_T *cstack = eap->cstack;
+ if (cmdmod_error())
+ return;
+
if (cstack->cs_trylevel <= 0 || cstack->cs_idx < 0)
eap->errmsg = _(e_no_endtry);
else
char_u *getline_peek(char_u *(*fgetline)(int, void *, int, getline_opt_T), void *cookie);
char *ex_errmsg(char *msg, char_u *arg);
int parse_command_modifiers(exarg_T *eap, char **errormsg, cmdmod_T *cmod, int skip_only);
+int has_cmdmod(cmdmod_T *cmod);
+int cmdmod_error(void);
void apply_cmdmod(cmdmod_T *cmod);
void undo_cmdmod(cmdmod_T *cmod);
int parse_cmd_address(exarg_T *eap, char **errormsg, int silent);
def Test_exepath()
CheckDefExecFailure(['echo exepath(true)'], 'E1174:')
CheckDefExecFailure(['echo exepath(v:null)'], 'E1174:')
- CheckDefExecFailure(['echo exepath("")'], 'E1142:')
+ CheckDefExecFailure(['echo exepath("")'], 'E1175:')
enddef
def Test_expand()
def Test_finddir()
CheckDefExecFailure(['echo finddir(true)'], 'E1174:')
CheckDefExecFailure(['echo finddir(v:null)'], 'E1174:')
- CheckDefExecFailure(['echo finddir("")'], 'E1142:')
+ CheckDefExecFailure(['echo finddir("")'], 'E1175:')
enddef
def Test_findfile()
CheckDefExecFailure(['echo findfile(true)'], 'E1174:')
CheckDefExecFailure(['echo findfile(v:null)'], 'E1174:')
- CheckDefExecFailure(['echo findfile("")'], 'E1142:')
+ CheckDefExecFailure(['echo findfile("")'], 'E1175:')
enddef
def Test_flattennew()
bwipe!
enddef
+def Test_useless_command_modifier()
+ g:maybe = true
+ var lines =<< trim END
+ if g:maybe
+ silent endif
+ END
+ CheckDefAndScriptFailure(lines, 'E1176:', 2)
+
+ lines =<< trim END
+ for i in [0]
+ silent endfor
+ END
+ CheckDefAndScriptFailure(lines, 'E1176:', 2)
+
+ lines =<< trim END
+ while g:maybe
+ silent endwhile
+ END
+ CheckDefAndScriptFailure(lines, 'E1176:', 2)
+
+ lines =<< trim END
+ silent try
+ finally
+ endtry
+ END
+ CheckDefAndScriptFailure(lines, 'E1176:', 1)
+
+ lines =<< trim END
+ try
+ silent catch
+ endtry
+ END
+ CheckDefAndScriptFailure(lines, 'E1176:', 2)
+
+ lines =<< trim END
+ try
+ silent finally
+ endtry
+ END
+ CheckDefAndScriptFailure(lines, 'E1176:', 2)
+
+ lines =<< trim END
+ try
+ finally
+ silent endtry
+ END
+ CheckDefAndScriptFailure(lines, 'E1176:', 3)
+enddef
+
def Test_eval_command()
var from = 3
var to = 5
def s:SilentIf()
silent if 4 == g:five
silent elseif 4 == g:five
- silent endif
+ endif
enddef
def Test_silent_if()
'\d\+ COMPAREANY ==\_s*' ..
'\d\+ CMDMOD_REV\_s*' ..
'\d\+ JUMP_IF_FALSE -> \d\+\_s*' ..
- 'silent endif\_s*' ..
+ 'endif\_s*' ..
'\d\+ RETURN 0',
res)
enddef
def s:SilentFor()
silent for i in [0]
- silent endfor
+ endfor
enddef
def Test_silent_for()
'\d CMDMOD_REV\_s*' ..
'5 FOR $0 -> 8\_s*' ..
'\d STORE $1\_s*' ..
- 'silent endfor\_s*' ..
+ 'endfor\_s*' ..
'\d JUMP -> 5\_s*' ..
'8 DROP\_s*' ..
'\d RETURN 0\_s*',
def s:SilentWhile()
silent while g:not
- silent endwhile
+ endwhile
enddef
def Test_silent_while()
'\d CMDMOD_REV\_s*' ..
'\d JUMP_IF_FALSE -> 6\_s*' ..
- 'silent endwhile\_s*' ..
+ 'endwhile\_s*' ..
'\d JUMP -> 0\_s*' ..
'6 RETURN 0\_s*',
res)
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 2652,
/**/
2651,
/**/
{
isn_T *isn;
- if (cmod->cmod_flags != 0
- || cmod->cmod_split != 0
- || cmod->cmod_verbose != 0
- || cmod->cmod_tab != 0
- || cmod->cmod_filter_regmatch.regprog != NULL)
+ if (has_cmdmod(cmod))
{
cctx->ctx_has_cmdmod = TRUE;
return OK;
}
-/*
- * If an ISN_CMDMOD was just generated drop it.
- */
- static void
-drop_cmdmod(cctx_T *cctx)
+ static int
+misplaced_cmdmod(cctx_T *cctx)
{
garray_T *instr = &cctx->ctx_instr;
- // Drop any CMDMOD instruction
if (cctx->ctx_has_cmdmod
&& ((isn_T *)instr->ga_data)[instr->ga_len - 1].isn_type
== ISN_CMDMOD)
{
- --instr->ga_len;
- cctx->ctx_has_cmdmod = FALSE;
+ emsg(_(e_misplaced_command_modifier));
+ return TRUE;
}
+ return FALSE;
}
/*
garray_T *instr = &cctx->ctx_instr;
isn_T *isn;
- drop_cmdmod(cctx);
+ if (misplaced_cmdmod(cctx))
+ return NULL;
+
if (scope == NULL || scope->se_type != IF_SCOPE)
{
emsg(_(e_endif_without_if));
forscope_T *forscope;
isn_T *isn;
- drop_cmdmod(cctx);
+ if (misplaced_cmdmod(cctx))
+ return NULL;
if (scope == NULL || scope->se_type != FOR_SCOPE)
{
scope_T *scope = cctx->ctx_scope;
garray_T *instr = &cctx->ctx_instr;
- drop_cmdmod(cctx);
+ if (misplaced_cmdmod(cctx))
+ return NULL;
if (scope == NULL || scope->se_type != WHILE_SCOPE)
{
emsg(_(e_while));
scope_T *try_scope;
scope_T *scope;
+ if (misplaced_cmdmod(cctx))
+ return NULL;
+
// scope that holds the jumps that go to catch/finally/endtry
try_scope = new_scope(cctx, TRY_SCOPE);
if (try_scope == NULL)
char_u *p;
isn_T *isn;
+ if (misplaced_cmdmod(cctx))
+ return NULL;
+
// end block scope from :try or :catch
if (scope != NULL && scope->se_type == BLOCK_SCOPE)
compile_endblock(cctx);
isn_T *isn;
int this_instr;
+ if (misplaced_cmdmod(cctx))
+ return NULL;
+
// end block scope from :try or :catch
if (scope != NULL && scope->se_type == BLOCK_SCOPE)
compile_endblock(cctx);
garray_T *instr = &cctx->ctx_instr;
isn_T *try_isn;
+ if (misplaced_cmdmod(cctx))
+ return NULL;
+
// end block scope from :catch or :finally
if (scope != NULL && scope->se_type == BLOCK_SCOPE)
compile_endblock(cctx);