1
0
forked from aniani/vim

patch 8.2.3716: Vim9: range without a command is not compiled

Problem:    Vim9: range without a command is not compiled.
Solution:   Add the ISN_EXECRANGE byte code.
This commit is contained in:
Bram Moolenaar
2021-12-01 15:22:56 +00:00
parent f0e496a85a
commit e4eed8c6db
7 changed files with 136 additions and 45 deletions

View File

@@ -1977,43 +1977,7 @@ do_one_cmd(
*/
if (ea.skip) // skip this if inside :if
goto doend;
if ((*ea.cmd == '|' || (exmode_active && ea.line1 != ea.line2))
#ifdef FEAT_EVAL
&& !vim9script
#endif
)
{
ea.cmdidx = CMD_print;
ea.argt = EX_RANGE+EX_COUNT+EX_TRLBAR;
if ((errormsg = invalid_range(&ea)) == NULL)
{
correct_range(&ea);
ex_print(&ea);
}
}
else if (ea.addr_count != 0)
{
if (ea.line2 > curbuf->b_ml.ml_line_count)
{
// With '-' in 'cpoptions' a line number past the file is an
// error, otherwise put it at the end of the file.
if (vim_strchr(p_cpo, CPO_MINUS) != NULL)
ea.line2 = -1;
else
ea.line2 = curbuf->b_ml.ml_line_count;
}
if (ea.line2 < 0)
errormsg = _(e_invalid_range);
else
{
if (ea.line2 == 0)
curwin->w_cursor.lnum = 1;
else
curwin->w_cursor.lnum = ea.line2;
beginline(BL_SOL | BL_FIX);
}
}
errormsg = ex_range_without_command(&ea);
goto doend;
}
@@ -2707,6 +2671,55 @@ ex_errmsg(char *msg, char_u *arg)
return ex_error_buf;
}
/*
* Handle a range without a command.
* Returns an error message on failure.
*/
char *
ex_range_without_command(exarg_T *eap)
{
char *errormsg = NULL;
if ((*eap->cmd == '|' || (exmode_active && eap->line1 != eap->line2))
#ifdef FEAT_EVAL
&& !in_vim9script()
#endif
)
{
eap->cmdidx = CMD_print;
eap->argt = EX_RANGE+EX_COUNT+EX_TRLBAR;
if ((errormsg = invalid_range(eap)) == NULL)
{
correct_range(eap);
ex_print(eap);
}
}
else if (eap->addr_count != 0)
{
if (eap->line2 > curbuf->b_ml.ml_line_count)
{
// With '-' in 'cpoptions' a line number past the file is an
// error, otherwise put it at the end of the file.
if (vim_strchr(p_cpo, CPO_MINUS) != NULL)
eap->line2 = -1;
else
eap->line2 = curbuf->b_ml.ml_line_count;
}
if (eap->line2 < 0)
errormsg = _(e_invalid_range);
else
{
if (eap->line2 == 0)
curwin->w_cursor.lnum = 1;
else
curwin->w_cursor.lnum = eap->line2;
beginline(BL_SOL | BL_FIX);
}
}
return errormsg;
}
/*
* Check for an Ex command with optional tail.
* If there is a match advance "pp" to the argument and return TRUE.

View File

@@ -7,6 +7,7 @@ int getline_equal(char_u *(*fgetline)(int, void *, int, getline_opt_T), void *co
void *getline_cookie(char_u *(*fgetline)(int, void *, int, getline_opt_T), void *cookie);
char_u *getline_peek(char_u *(*fgetline)(int, void *, int, getline_opt_T), void *cookie);
char *ex_errmsg(char *msg, char_u *arg);
char *ex_range_without_command(exarg_T *eap);
int checkforcmd(char_u **pp, char *cmd, int len);
int checkforcmd_noparen(char_u **pp, char *cmd, int len);
int parse_command_modifiers(exarg_T *eap, char **errormsg, cmdmod_T *cmod, int skip_only);
@@ -22,7 +23,7 @@ int cmd_exists(char_u *name);
void f_fullcommand(typval_T *argvars, typval_T *rettv);
cmdidx_T excmd_get_cmdidx(char_u *cmd, int len);
long excmd_get_argt(cmdidx_T idx);
char_u *skip_range(char_u *cmd, int skip_star, int *ctx);
char_u *skip_range(char_u *cmd_start, int skip_star, int *ctx);
void ex_ni(exarg_T *eap);
int expand_filename(exarg_T *eap, char_u **cmdlinep, char **errormsgp);
void separate_nextcmd(exarg_T *eap);

View File

@@ -1999,6 +1999,25 @@ def Test_disassemble_execute()
res)
enddef
def s:OnlyRange()
:$
:123
:'m
enddef
def Test_disassemble_range_only()
var res = execute('disass s:OnlyRange')
assert_match('\<SNR>\d*_OnlyRange\_s*' ..
':$\_s*' ..
'\d EXECRANGE $\_s*' ..
':123\_s*' ..
'\d EXECRANGE 123\_s*' ..
':''m\_s*' ..
'\d EXECRANGE ''m\_s*' ..
'\d\+ RETURN void',
res)
enddef
def s:Echomsg()
echomsg 'some' 'message'
echoconsole 'nothing'

View File

@@ -753,6 +753,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
3716,
/**/
3715,
/**/

View File

@@ -15,6 +15,7 @@ typedef enum {
ISN_EXEC, // execute Ex command line isn_arg.string
ISN_EXECCONCAT, // execute Ex command from isn_arg.number items on stack
ISN_EXEC_SPLIT, // execute Ex command from isn_arg.string split at NL
ISN_EXECRANGE, // execute EX command that is only a range
ISN_LEGACY_EVAL, // evaluate expression isn_arg.string with legacy syntax.
ISN_ECHO, // :echo with isn_arg.echo.echo_count items on top of stack
ISN_EXECUTE, // :execute with isn_arg.number items on top of stack

View File

@@ -2275,8 +2275,12 @@ generate_PUT(cctx_T *cctx, int regname, linenr_T lnum)
return OK;
}
/*
* Generate an EXEC instruction that takes a string argument.
* A copy is made of "line".
*/
static int
generate_EXEC(cctx_T *cctx, isntype_T isntype, char_u *line)
generate_EXEC_copy(cctx_T *cctx, isntype_T isntype, char_u *line)
{
isn_T *isn;
@@ -2287,6 +2291,29 @@ generate_EXEC(cctx_T *cctx, isntype_T isntype, char_u *line)
return OK;
}
/*
* Generate an EXEC instruction that takes a string argument.
* "str" must be allocated, it is consumed.
*/
static int
generate_EXEC(cctx_T *cctx, isntype_T isntype, char_u *str)
{
isn_T *isn;
if (cctx->ctx_skip == SKIP_YES)
{
vim_free(str);
return OK;
}
if ((isn = generate_instr(cctx, isntype)) == NULL)
{
vim_free(str);
return FAIL;
}
isn->isn_arg.string = str;
return OK;
}
static int
generate_LEGACY_EVAL(cctx_T *cctx, char_u *line)
{
@@ -7552,7 +7579,7 @@ compile_lock_unlock(
vim_snprintf((char *)buf, len, "%s %s",
eap->cmdidx == CMD_lockvar ? "lockvar" : "unlockvar",
p);
ret = generate_EXEC(cctx, isn, buf);
ret = generate_EXEC_copy(cctx, isn, buf);
vim_free(buf);
*name_end = cc;
@@ -9248,7 +9275,7 @@ compile_exec(char_u *line_arg, exarg_T *eap, cctx_T *cctx)
generate_EXECCONCAT(cctx, count);
}
else
generate_EXEC(cctx, ISN_EXEC, line);
generate_EXEC_copy(cctx, ISN_EXEC, line);
theend:
if (*nextcmd != NUL)
@@ -9874,10 +9901,12 @@ compile_def_function(
if (ends_excmd2(line, ea.cmd))
{
// A range without a command: jump to the line.
// TODO: compile to a more efficient command, possibly
// calling parse_cmd_address().
ea.cmdidx = CMD_SIZE;
line = compile_exec(line, &ea, &cctx);
line = skipwhite(line);
while (*line == ':')
++line;
generate_EXEC(&cctx, ISN_EXECRANGE,
vim_strnsave(line, ea.cmd - line));
line = ea.cmd;
goto nextline;
}
}
@@ -10350,6 +10379,7 @@ delete_instr(isn_T *isn)
{
case ISN_DEF:
case ISN_EXEC:
case ISN_EXECRANGE:
case ISN_EXEC_SPLIT:
case ISN_LEGACY_EVAL:
case ISN_LOADAUTO:

View File

@@ -1774,6 +1774,28 @@ exec_instructions(ectx_T *ectx)
}
break;
// execute Ex command line that is only a range
case ISN_EXECRANGE:
{
exarg_T ea;
char *error = NULL;
CLEAR_FIELD(ea);
ea.cmdidx = CMD_SIZE;
ea.addr_type = ADDR_LINES;
ea.cmd = iptr->isn_arg.string;
parse_cmd_address(&ea, &error, FALSE);
if (error == NULL)
error = ex_range_without_command(&ea);
if (error != NULL)
{
SOURCING_LNUM = iptr->isn_lnum;
emsg(error);
goto on_error;
}
}
break;
// Evaluate an expression with legacy syntax, push it onto the
// stack.
case ISN_LEGACY_EVAL:
@@ -5068,6 +5090,9 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
case ISN_EXEC_SPLIT:
smsg("%s%4d EXEC_SPLIT %s", pfx, current, iptr->isn_arg.string);
break;
case ISN_EXECRANGE:
smsg("%s%4d EXECRANGE %s", pfx, current, iptr->isn_arg.string);
break;
case ISN_LEGACY_EVAL:
smsg("%s%4d EVAL legacy %s", pfx, current,
iptr->isn_arg.string);