1
0
forked from aniani/vim

patch 8.2.2842: Vim9: skip argument to searchpair() is not compiled

Problem:    Vim9: skip argument to searchpair() is not compiled.
Solution:   Add VAR_INSTR.
This commit is contained in:
Bram Moolenaar
2021-05-07 17:55:55 +02:00
parent e08795e1ec
commit f18332fb9e
18 changed files with 235 additions and 17 deletions

View File

@@ -615,6 +615,7 @@ may_generate_2STRING(int offset, cctx_T *cctx)
case VAR_DICT:
case VAR_JOB:
case VAR_CHANNEL:
case VAR_INSTR:
to_string_error((*type)->tt_type);
return FAIL;
}
@@ -3097,16 +3098,72 @@ theend:
return res;
}
static void
clear_instr_ga(garray_T *gap)
{
int idx;
for (idx = 0; idx < gap->ga_len; ++idx)
delete_instr(((isn_T *)gap->ga_data) + idx);
ga_clear(gap);
}
/*
* Compile a string in a ISN_PUSHS instruction into an ISN_INSTR.
* Returns FAIL if compilation fails.
*/
static int
compile_string(isn_T *isn, cctx_T *cctx)
{
char_u *s = isn->isn_arg.string;
garray_T save_ga = cctx->ctx_instr;
int expr_res;
int trailing_error;
int instr_count;
isn_T *instr = NULL;
// Temporarily reset the list of instructions so that the jump labels are
// correct.
cctx->ctx_instr.ga_len = 0;
cctx->ctx_instr.ga_maxlen = 0;
cctx->ctx_instr.ga_data = NULL;
expr_res = compile_expr0(&s, cctx);
s = skipwhite(s);
trailing_error = *s != NUL;
if (expr_res == FAIL || trailing_error)
{
if (trailing_error)
semsg(_(e_trailing_arg), s);
clear_instr_ga(&cctx->ctx_instr);
cctx->ctx_instr = save_ga;
return FAIL;
}
// Move the generated instructions into the ISN_INSTR instruction, then
// restore the list of instructions.
instr_count = cctx->ctx_instr.ga_len;
instr = cctx->ctx_instr.ga_data;
instr[instr_count].isn_type = ISN_FINISH;
cctx->ctx_instr = save_ga;
vim_free(isn->isn_arg.string);
isn->isn_type = ISN_INSTR;
isn->isn_arg.instr = instr;
return OK;
}
/*
* Compile the argument expressions.
* "arg" points to just after the "(" and is advanced to after the ")"
*/
static int
compile_arguments(char_u **arg, cctx_T *cctx, int *argcount)
compile_arguments(char_u **arg, cctx_T *cctx, int *argcount, int is_searchpair)
{
char_u *p = *arg;
char_u *whitep = *arg;
int must_end = FALSE;
int instr_count;
for (;;)
{
@@ -3123,10 +3180,21 @@ compile_arguments(char_u **arg, cctx_T *cctx, int *argcount)
return FAIL;
}
instr_count = cctx->ctx_instr.ga_len;
if (compile_expr0(&p, cctx) == FAIL)
return FAIL;
++*argcount;
if (is_searchpair && *argcount == 5
&& cctx->ctx_instr.ga_len == instr_count + 1)
{
isn_T *isn = ((isn_T *)cctx->ctx_instr.ga_data) + instr_count;
// {skip} argument of searchpair() can be compiled if not empty
if (isn->isn_type == ISN_PUSHS && *isn->isn_arg.string != NUL)
compile_string(isn, cctx);
}
if (*p != ',' && *skipwhite(p) == ',')
{
semsg(_(e_no_white_space_allowed_before_str_str), ",", p);
@@ -3175,6 +3243,7 @@ compile_call(
ufunc_T *ufunc = NULL;
int res = FAIL;
int is_autoload;
int is_searchpair;
// we can evaluate "has('name')" at compile time
if (varlen == 3 && STRNCMP(*arg, "has", 3) == 0)
@@ -3216,8 +3285,11 @@ compile_call(
vim_strncpy(namebuf, *arg, varlen);
name = fname_trans_sid(namebuf, fname_buf, &tofree, &error);
// we handle the "skip" argument of searchpair() differently
is_searchpair = (varlen == 10 && STRNCMP(*arg, "searchpair", 10) == 0);
*arg = skipwhite(*arg + varlen + 1);
if (compile_arguments(arg, cctx, &argcount) == FAIL)
if (compile_arguments(arg, cctx, &argcount, is_searchpair) == FAIL)
goto theend;
is_autoload = vim_strchr(name, AUTOLOAD_CHAR) != NULL;
@@ -4027,7 +4099,7 @@ compile_subscript(
type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
*arg = skipwhite(p + 1);
if (compile_arguments(arg, cctx, &argcount) == FAIL)
if (compile_arguments(arg, cctx, &argcount, FALSE) == FAIL)
return FAIL;
if (generate_PCALL(cctx, argcount, name_start, type, TRUE) == FAIL)
return FAIL;
@@ -4080,7 +4152,7 @@ compile_subscript(
return FAIL;
}
*arg = skipwhite(*arg + 1);
if (compile_arguments(arg, cctx, &argcount) == FAIL)
if (compile_arguments(arg, cctx, &argcount, FALSE) == FAIL)
return FAIL;
// Move the instructions for the arguments to before the
@@ -6728,6 +6800,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
case VAR_ANY:
case VAR_PARTIAL:
case VAR_VOID:
case VAR_INSTR:
case VAR_SPECIAL: // cannot happen
generate_PUSHNR(cctx, 0);
break;
@@ -8536,16 +8609,6 @@ theend:
}
static void
clear_instr_ga(garray_T *gap)
{
int idx;
for (idx = 0; idx < gap->ga_len; ++idx)
delete_instr(((isn_T *)gap->ga_data) + idx);
ga_clear(gap);
}
/*
* :s/pat/repl/
*/
@@ -8568,13 +8631,13 @@ compile_substitute(char_u *arg, exarg_T *eap, cctx_T *cctx)
int expr_res;
int trailing_error;
int instr_count;
isn_T *instr = NULL;
isn_T *instr;
isn_T *isn;
cmd += 3;
end = skip_substitute(cmd, delimiter);
// Temporarily reset the list of instructions so that the jumps
// Temporarily reset the list of instructions so that the jump
// labels are correct.
cctx->ctx_instr.ga_len = 0;
cctx->ctx_instr.ga_maxlen = 0;
@@ -8592,7 +8655,6 @@ compile_substitute(char_u *arg, exarg_T *eap, cctx_T *cctx)
semsg(_(e_trailing_arg), cmd);
clear_instr_ga(&cctx->ctx_instr);
cctx->ctx_instr = save_ga;
vim_free(instr);
return NULL;
}
@@ -9555,6 +9617,17 @@ delete_instr(isn_T *isn)
}
break;
case ISN_INSTR:
{
int idx;
isn_T *list = isn->isn_arg.instr;
for (idx = 0; list[idx].isn_type != ISN_FINISH; ++idx)
delete_instr(list + idx);
vim_free(list);
}
break;
case ISN_LOADS:
case ISN_STORES:
vim_free(isn->isn_arg.loadstore.ls_name);