mirror of
https://github.com/zoriya/vim.git
synced 2025-12-20 14:15:18 +00:00
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:
13
src/eval.c
13
src/eval.c
@@ -309,6 +309,10 @@ eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv)
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (expr->v_type == VAR_INSTR)
|
||||||
|
{
|
||||||
|
return exe_typval_instr(expr, rettv);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
s = tv_get_string_buf_chk(expr, buf);
|
s = tv_get_string_buf_chk(expr, buf);
|
||||||
@@ -1510,6 +1514,7 @@ tv_op(typval_T *tv1, typval_T *tv2, char_u *op)
|
|||||||
case VAR_SPECIAL:
|
case VAR_SPECIAL:
|
||||||
case VAR_JOB:
|
case VAR_JOB:
|
||||||
case VAR_CHANNEL:
|
case VAR_CHANNEL:
|
||||||
|
case VAR_INSTR:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VAR_BLOB:
|
case VAR_BLOB:
|
||||||
@@ -4084,6 +4089,7 @@ check_can_index(typval_T *rettv, int evaluate, int verbose)
|
|||||||
case VAR_SPECIAL:
|
case VAR_SPECIAL:
|
||||||
case VAR_JOB:
|
case VAR_JOB:
|
||||||
case VAR_CHANNEL:
|
case VAR_CHANNEL:
|
||||||
|
case VAR_INSTR:
|
||||||
if (verbose)
|
if (verbose)
|
||||||
emsg(_(e_cannot_index_special_variable));
|
emsg(_(e_cannot_index_special_variable));
|
||||||
return FAIL;
|
return FAIL;
|
||||||
@@ -4177,6 +4183,7 @@ eval_index_inner(
|
|||||||
case VAR_SPECIAL:
|
case VAR_SPECIAL:
|
||||||
case VAR_JOB:
|
case VAR_JOB:
|
||||||
case VAR_CHANNEL:
|
case VAR_CHANNEL:
|
||||||
|
case VAR_INSTR:
|
||||||
break; // not evaluating, skipping over subscript
|
break; // not evaluating, skipping over subscript
|
||||||
|
|
||||||
case VAR_NUMBER:
|
case VAR_NUMBER:
|
||||||
@@ -5067,6 +5074,11 @@ echo_string_core(
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case VAR_INSTR:
|
||||||
|
*tofree = NULL;
|
||||||
|
r = (char_u *)"instructions";
|
||||||
|
break;
|
||||||
|
|
||||||
case VAR_FLOAT:
|
case VAR_FLOAT:
|
||||||
#ifdef FEAT_FLOAT
|
#ifdef FEAT_FLOAT
|
||||||
*tofree = NULL;
|
*tofree = NULL;
|
||||||
@@ -5987,6 +5999,7 @@ item_copy(
|
|||||||
case VAR_SPECIAL:
|
case VAR_SPECIAL:
|
||||||
case VAR_JOB:
|
case VAR_JOB:
|
||||||
case VAR_CHANNEL:
|
case VAR_CHANNEL:
|
||||||
|
case VAR_INSTR:
|
||||||
copy_tv(from, to);
|
copy_tv(from, to);
|
||||||
break;
|
break;
|
||||||
case VAR_LIST:
|
case VAR_LIST:
|
||||||
|
|||||||
@@ -2989,6 +2989,7 @@ f_empty(typval_T *argvars, typval_T *rettv)
|
|||||||
case VAR_UNKNOWN:
|
case VAR_UNKNOWN:
|
||||||
case VAR_ANY:
|
case VAR_ANY:
|
||||||
case VAR_VOID:
|
case VAR_VOID:
|
||||||
|
case VAR_INSTR:
|
||||||
internal_error_no_abort("f_empty(UNKNOWN)");
|
internal_error_no_abort("f_empty(UNKNOWN)");
|
||||||
n = TRUE;
|
n = TRUE;
|
||||||
break;
|
break;
|
||||||
@@ -6303,6 +6304,7 @@ f_len(typval_T *argvars, typval_T *rettv)
|
|||||||
case VAR_PARTIAL:
|
case VAR_PARTIAL:
|
||||||
case VAR_JOB:
|
case VAR_JOB:
|
||||||
case VAR_CHANNEL:
|
case VAR_CHANNEL:
|
||||||
|
case VAR_INSTR:
|
||||||
emsg(_("E701: Invalid type for len()"));
|
emsg(_("E701: Invalid type for len()"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -10215,6 +10217,7 @@ f_type(typval_T *argvars, typval_T *rettv)
|
|||||||
case VAR_JOB: n = VAR_TYPE_JOB; break;
|
case VAR_JOB: n = VAR_TYPE_JOB; break;
|
||||||
case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
|
case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
|
||||||
case VAR_BLOB: n = VAR_TYPE_BLOB; break;
|
case VAR_BLOB: n = VAR_TYPE_BLOB; break;
|
||||||
|
case VAR_INSTR: n = VAR_TYPE_INSTR; break;
|
||||||
case VAR_UNKNOWN:
|
case VAR_UNKNOWN:
|
||||||
case VAR_ANY:
|
case VAR_ANY:
|
||||||
case VAR_VOID:
|
case VAR_VOID:
|
||||||
|
|||||||
@@ -1912,6 +1912,7 @@ item_lock(typval_T *tv, int deep, int lock, int check_refcount)
|
|||||||
case VAR_SPECIAL:
|
case VAR_SPECIAL:
|
||||||
case VAR_JOB:
|
case VAR_JOB:
|
||||||
case VAR_CHANNEL:
|
case VAR_CHANNEL:
|
||||||
|
case VAR_INSTR:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VAR_BLOB:
|
case VAR_BLOB:
|
||||||
|
|||||||
@@ -6425,6 +6425,7 @@ ConvertToPyObject(typval_T *tv)
|
|||||||
case VAR_VOID:
|
case VAR_VOID:
|
||||||
case VAR_CHANNEL:
|
case VAR_CHANNEL:
|
||||||
case VAR_JOB:
|
case VAR_JOB:
|
||||||
|
case VAR_INSTR:
|
||||||
Py_INCREF(Py_None);
|
Py_INCREF(Py_None);
|
||||||
return Py_None;
|
return Py_None;
|
||||||
case VAR_BOOL:
|
case VAR_BOOL:
|
||||||
|
|||||||
@@ -230,6 +230,7 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID, int options)
|
|||||||
case VAR_PARTIAL:
|
case VAR_PARTIAL:
|
||||||
case VAR_JOB:
|
case VAR_JOB:
|
||||||
case VAR_CHANNEL:
|
case VAR_CHANNEL:
|
||||||
|
case VAR_INSTR:
|
||||||
semsg(_(e_cannot_json_encode_str), vartype_name(val->v_type));
|
semsg(_(e_cannot_json_encode_str), vartype_name(val->v_type));
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ void funcstack_check_refcount(funcstack_T *funcstack);
|
|||||||
char_u *char_from_string(char_u *str, varnumber_T index);
|
char_u *char_from_string(char_u *str, varnumber_T index);
|
||||||
char_u *string_slice(char_u *str, varnumber_T first, varnumber_T last, int exclusive);
|
char_u *string_slice(char_u *str, varnumber_T first, varnumber_T last, int exclusive);
|
||||||
int fill_partial_and_closure(partial_T *pt, ufunc_T *ufunc, ectx_T *ectx);
|
int fill_partial_and_closure(partial_T *pt, ufunc_T *ufunc, ectx_T *ectx);
|
||||||
|
int exe_typval_instr(typval_T *tv, typval_T *rettv);
|
||||||
char_u *exe_substitute_instr(void);
|
char_u *exe_substitute_instr(void);
|
||||||
int call_def_function(ufunc_T *ufunc, int argc_arg, typval_T *argv, partial_T *partial, typval_T *rettv);
|
int call_def_function(ufunc_T *ufunc, int argc_arg, typval_T *argv, partial_T *partial, typval_T *rettv);
|
||||||
void ex_disassemble(exarg_T *eap);
|
void ex_disassemble(exarg_T *eap);
|
||||||
|
|||||||
@@ -1371,6 +1371,7 @@ typedef struct cbq_S cbq_T;
|
|||||||
typedef struct channel_S channel_T;
|
typedef struct channel_S channel_T;
|
||||||
typedef struct cctx_S cctx_T;
|
typedef struct cctx_S cctx_T;
|
||||||
typedef struct ectx_S ectx_T;
|
typedef struct ectx_S ectx_T;
|
||||||
|
typedef struct instr_S instr_T;
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
@@ -1389,6 +1390,7 @@ typedef enum
|
|||||||
VAR_DICT, // "v_dict" is used
|
VAR_DICT, // "v_dict" is used
|
||||||
VAR_JOB, // "v_job" is used
|
VAR_JOB, // "v_job" is used
|
||||||
VAR_CHANNEL, // "v_channel" is used
|
VAR_CHANNEL, // "v_channel" is used
|
||||||
|
VAR_INSTR, // "v_instr" is used
|
||||||
} vartype_T;
|
} vartype_T;
|
||||||
|
|
||||||
// A type specification.
|
// A type specification.
|
||||||
@@ -1429,6 +1431,7 @@ typedef struct
|
|||||||
channel_T *v_channel; // channel value (can be NULL!)
|
channel_T *v_channel; // channel value (can be NULL!)
|
||||||
#endif
|
#endif
|
||||||
blob_T *v_blob; // blob value (can be NULL!)
|
blob_T *v_blob; // blob value (can be NULL!)
|
||||||
|
instr_T *v_instr; // instructions to execute
|
||||||
} vval;
|
} vval;
|
||||||
} typval_T;
|
} typval_T;
|
||||||
|
|
||||||
|
|||||||
@@ -974,6 +974,20 @@ def Test_searchcount()
|
|||||||
bwipe!
|
bwipe!
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
def Test_searchpair()
|
||||||
|
new
|
||||||
|
setline(1, "here { and } there")
|
||||||
|
normal f{
|
||||||
|
var col = 15
|
||||||
|
assert_equal(1, searchpair('{', '', '}', '', 'col(".") > col'))
|
||||||
|
assert_equal(12, col('.'))
|
||||||
|
col = 8
|
||||||
|
normal 0f{
|
||||||
|
assert_equal(0, searchpair('{', '', '}', '', 'col(".") > col'))
|
||||||
|
assert_equal(6, col('.'))
|
||||||
|
bwipe!
|
||||||
|
enddef
|
||||||
|
|
||||||
def Test_set_get_bufline()
|
def Test_set_get_bufline()
|
||||||
# similar to Test_setbufline_getbufline()
|
# similar to Test_setbufline_getbufline()
|
||||||
var lines =<< trim END
|
var lines =<< trim END
|
||||||
|
|||||||
@@ -140,6 +140,35 @@ def Test_disassemble_substitute()
|
|||||||
res)
|
res)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
|
||||||
|
def s:SearchPair()
|
||||||
|
var col = 8
|
||||||
|
searchpair("{", "", "}", "", "col('.') > col")
|
||||||
|
enddef
|
||||||
|
|
||||||
|
def Test_disassemble_seachpair()
|
||||||
|
var res = execute('disass s:SearchPair')
|
||||||
|
assert_match('<SNR>\d*_SearchPair.*' ..
|
||||||
|
' var col = 8\_s*' ..
|
||||||
|
'\d STORE 8 in $0\_s*' ..
|
||||||
|
' searchpair("{", "", "}", "", "col(''.'') > col")\_s*' ..
|
||||||
|
'\d PUSHS "{"\_s*' ..
|
||||||
|
'\d PUSHS ""\_s*' ..
|
||||||
|
'\d PUSHS "}"\_s*' ..
|
||||||
|
'\d PUSHS ""\_s*' ..
|
||||||
|
'\d INSTR\_s*' ..
|
||||||
|
' 0 PUSHS "."\_s*' ..
|
||||||
|
' 1 BCALL col(argc 1)\_s*' ..
|
||||||
|
' 2 LOAD $0\_s*' ..
|
||||||
|
' 3 COMPARENR >\_s*' ..
|
||||||
|
' -------------\_s*' ..
|
||||||
|
'\d BCALL searchpair(argc 5)\_s*' ..
|
||||||
|
'\d DROP\_s*' ..
|
||||||
|
'\d RETURN 0',
|
||||||
|
res)
|
||||||
|
enddef
|
||||||
|
|
||||||
|
|
||||||
def s:RedirVar()
|
def s:RedirVar()
|
||||||
var result: string
|
var result: string
|
||||||
redir =>> result
|
redir =>> result
|
||||||
|
|||||||
@@ -1023,6 +1023,7 @@ f_test_refcount(typval_T *argvars, typval_T *rettv)
|
|||||||
case VAR_FLOAT:
|
case VAR_FLOAT:
|
||||||
case VAR_SPECIAL:
|
case VAR_SPECIAL:
|
||||||
case VAR_STRING:
|
case VAR_STRING:
|
||||||
|
case VAR_INSTR:
|
||||||
break;
|
break;
|
||||||
case VAR_JOB:
|
case VAR_JOB:
|
||||||
#ifdef FEAT_JOB_CHANNEL
|
#ifdef FEAT_JOB_CHANNEL
|
||||||
|
|||||||
11
src/typval.c
11
src/typval.c
@@ -91,6 +91,7 @@ free_tv(typval_T *varp)
|
|||||||
case VAR_VOID:
|
case VAR_VOID:
|
||||||
case VAR_BOOL:
|
case VAR_BOOL:
|
||||||
case VAR_SPECIAL:
|
case VAR_SPECIAL:
|
||||||
|
case VAR_INSTR:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
vim_free(varp);
|
vim_free(varp);
|
||||||
@@ -153,6 +154,7 @@ clear_tv(typval_T *varp)
|
|||||||
case VAR_UNKNOWN:
|
case VAR_UNKNOWN:
|
||||||
case VAR_ANY:
|
case VAR_ANY:
|
||||||
case VAR_VOID:
|
case VAR_VOID:
|
||||||
|
case VAR_INSTR:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
varp->v_lock = 0;
|
varp->v_lock = 0;
|
||||||
@@ -236,6 +238,7 @@ tv_get_bool_or_number_chk(typval_T *varp, int *denote, int want_bool)
|
|||||||
case VAR_UNKNOWN:
|
case VAR_UNKNOWN:
|
||||||
case VAR_ANY:
|
case VAR_ANY:
|
||||||
case VAR_VOID:
|
case VAR_VOID:
|
||||||
|
case VAR_INSTR:
|
||||||
internal_error_no_abort("tv_get_number(UNKNOWN)");
|
internal_error_no_abort("tv_get_number(UNKNOWN)");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -333,6 +336,7 @@ tv_get_float(typval_T *varp)
|
|||||||
case VAR_UNKNOWN:
|
case VAR_UNKNOWN:
|
||||||
case VAR_ANY:
|
case VAR_ANY:
|
||||||
case VAR_VOID:
|
case VAR_VOID:
|
||||||
|
case VAR_INSTR:
|
||||||
internal_error_no_abort("tv_get_float(UNKNOWN)");
|
internal_error_no_abort("tv_get_float(UNKNOWN)");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -514,6 +518,7 @@ tv_get_string_buf_chk_strict(typval_T *varp, char_u *buf, int strict)
|
|||||||
case VAR_UNKNOWN:
|
case VAR_UNKNOWN:
|
||||||
case VAR_ANY:
|
case VAR_ANY:
|
||||||
case VAR_VOID:
|
case VAR_VOID:
|
||||||
|
case VAR_INSTR:
|
||||||
emsg(_(e_inval_string));
|
emsg(_(e_inval_string));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -614,6 +619,10 @@ copy_tv(typval_T *from, typval_T *to)
|
|||||||
++to->vval.v_channel->ch_refcount;
|
++to->vval.v_channel->ch_refcount;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
case VAR_INSTR:
|
||||||
|
to->vval.v_instr = from->vval.v_instr;
|
||||||
|
break;
|
||||||
|
|
||||||
case VAR_STRING:
|
case VAR_STRING:
|
||||||
case VAR_FUNC:
|
case VAR_FUNC:
|
||||||
if (from->vval.v_string == NULL)
|
if (from->vval.v_string == NULL)
|
||||||
@@ -1116,6 +1125,8 @@ tv_equal(
|
|||||||
#ifdef FEAT_JOB_CHANNEL
|
#ifdef FEAT_JOB_CHANNEL
|
||||||
return tv1->vval.v_channel == tv2->vval.v_channel;
|
return tv1->vval.v_channel == tv2->vval.v_channel;
|
||||||
#endif
|
#endif
|
||||||
|
case VAR_INSTR:
|
||||||
|
return tv1->vval.v_instr == tv2->vval.v_instr;
|
||||||
|
|
||||||
case VAR_PARTIAL:
|
case VAR_PARTIAL:
|
||||||
return tv1->vval.v_partial == tv2->vval.v_partial;
|
return tv1->vval.v_partial == tv2->vval.v_partial;
|
||||||
|
|||||||
@@ -750,6 +750,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
2842,
|
||||||
/**/
|
/**/
|
||||||
2841,
|
2841,
|
||||||
/**/
|
/**/
|
||||||
|
|||||||
@@ -2030,6 +2030,7 @@ typedef int sock_T;
|
|||||||
#define VAR_TYPE_JOB 8
|
#define VAR_TYPE_JOB 8
|
||||||
#define VAR_TYPE_CHANNEL 9
|
#define VAR_TYPE_CHANNEL 9
|
||||||
#define VAR_TYPE_BLOB 10
|
#define VAR_TYPE_BLOB 10
|
||||||
|
#define VAR_TYPE_INSTR 11
|
||||||
|
|
||||||
#define DICT_MAXNEST 100 // maximum nesting of lists and dicts
|
#define DICT_MAXNEST 100 // maximum nesting of lists and dicts
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ typedef enum {
|
|||||||
ISN_ECHOERR, // echo Ex commands isn_arg.number items on top of stack
|
ISN_ECHOERR, // echo Ex commands isn_arg.number items on top of stack
|
||||||
ISN_RANGE, // compute range from isn_arg.string, push to stack
|
ISN_RANGE, // compute range from isn_arg.string, push to stack
|
||||||
ISN_SUBSTITUTE, // :s command with expression
|
ISN_SUBSTITUTE, // :s command with expression
|
||||||
|
ISN_INSTR, // instructions compiled from expression
|
||||||
|
|
||||||
// get and set variables
|
// get and set variables
|
||||||
ISN_LOAD, // push local variable isn_arg.number
|
ISN_LOAD, // push local variable isn_arg.number
|
||||||
@@ -411,6 +412,7 @@ struct isn_S {
|
|||||||
isn_outer_T outer;
|
isn_outer_T outer;
|
||||||
subs_T subs;
|
subs_T subs;
|
||||||
cexpr_T cexpr;
|
cexpr_T cexpr;
|
||||||
|
isn_T *instr;
|
||||||
} isn_arg;
|
} isn_arg;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -615,6 +615,7 @@ may_generate_2STRING(int offset, cctx_T *cctx)
|
|||||||
case VAR_DICT:
|
case VAR_DICT:
|
||||||
case VAR_JOB:
|
case VAR_JOB:
|
||||||
case VAR_CHANNEL:
|
case VAR_CHANNEL:
|
||||||
|
case VAR_INSTR:
|
||||||
to_string_error((*type)->tt_type);
|
to_string_error((*type)->tt_type);
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
@@ -3097,16 +3098,72 @@ theend:
|
|||||||
return res;
|
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.
|
* Compile the argument expressions.
|
||||||
* "arg" points to just after the "(" and is advanced to after the ")"
|
* "arg" points to just after the "(" and is advanced to after the ")"
|
||||||
*/
|
*/
|
||||||
static int
|
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 *p = *arg;
|
||||||
char_u *whitep = *arg;
|
char_u *whitep = *arg;
|
||||||
int must_end = FALSE;
|
int must_end = FALSE;
|
||||||
|
int instr_count;
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@@ -3123,10 +3180,21 @@ compile_arguments(char_u **arg, cctx_T *cctx, int *argcount)
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
instr_count = cctx->ctx_instr.ga_len;
|
||||||
if (compile_expr0(&p, cctx) == FAIL)
|
if (compile_expr0(&p, cctx) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
++*argcount;
|
++*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) == ',')
|
if (*p != ',' && *skipwhite(p) == ',')
|
||||||
{
|
{
|
||||||
semsg(_(e_no_white_space_allowed_before_str_str), ",", p);
|
semsg(_(e_no_white_space_allowed_before_str_str), ",", p);
|
||||||
@@ -3175,6 +3243,7 @@ compile_call(
|
|||||||
ufunc_T *ufunc = NULL;
|
ufunc_T *ufunc = NULL;
|
||||||
int res = FAIL;
|
int res = FAIL;
|
||||||
int is_autoload;
|
int is_autoload;
|
||||||
|
int is_searchpair;
|
||||||
|
|
||||||
// we can evaluate "has('name')" at compile time
|
// we can evaluate "has('name')" at compile time
|
||||||
if (varlen == 3 && STRNCMP(*arg, "has", 3) == 0)
|
if (varlen == 3 && STRNCMP(*arg, "has", 3) == 0)
|
||||||
@@ -3216,8 +3285,11 @@ compile_call(
|
|||||||
vim_strncpy(namebuf, *arg, varlen);
|
vim_strncpy(namebuf, *arg, varlen);
|
||||||
name = fname_trans_sid(namebuf, fname_buf, &tofree, &error);
|
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);
|
*arg = skipwhite(*arg + varlen + 1);
|
||||||
if (compile_arguments(arg, cctx, &argcount) == FAIL)
|
if (compile_arguments(arg, cctx, &argcount, is_searchpair) == FAIL)
|
||||||
goto theend;
|
goto theend;
|
||||||
|
|
||||||
is_autoload = vim_strchr(name, AUTOLOAD_CHAR) != NULL;
|
is_autoload = vim_strchr(name, AUTOLOAD_CHAR) != NULL;
|
||||||
@@ -4027,7 +4099,7 @@ compile_subscript(
|
|||||||
type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
||||||
|
|
||||||
*arg = skipwhite(p + 1);
|
*arg = skipwhite(p + 1);
|
||||||
if (compile_arguments(arg, cctx, &argcount) == FAIL)
|
if (compile_arguments(arg, cctx, &argcount, FALSE) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
if (generate_PCALL(cctx, argcount, name_start, type, TRUE) == FAIL)
|
if (generate_PCALL(cctx, argcount, name_start, type, TRUE) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
@@ -4080,7 +4152,7 @@ compile_subscript(
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
*arg = skipwhite(*arg + 1);
|
*arg = skipwhite(*arg + 1);
|
||||||
if (compile_arguments(arg, cctx, &argcount) == FAIL)
|
if (compile_arguments(arg, cctx, &argcount, FALSE) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
|
||||||
// Move the instructions for the arguments to before the
|
// 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_ANY:
|
||||||
case VAR_PARTIAL:
|
case VAR_PARTIAL:
|
||||||
case VAR_VOID:
|
case VAR_VOID:
|
||||||
|
case VAR_INSTR:
|
||||||
case VAR_SPECIAL: // cannot happen
|
case VAR_SPECIAL: // cannot happen
|
||||||
generate_PUSHNR(cctx, 0);
|
generate_PUSHNR(cctx, 0);
|
||||||
break;
|
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/
|
* :s/pat/repl/
|
||||||
*/
|
*/
|
||||||
@@ -8568,13 +8631,13 @@ compile_substitute(char_u *arg, exarg_T *eap, cctx_T *cctx)
|
|||||||
int expr_res;
|
int expr_res;
|
||||||
int trailing_error;
|
int trailing_error;
|
||||||
int instr_count;
|
int instr_count;
|
||||||
isn_T *instr = NULL;
|
isn_T *instr;
|
||||||
isn_T *isn;
|
isn_T *isn;
|
||||||
|
|
||||||
cmd += 3;
|
cmd += 3;
|
||||||
end = skip_substitute(cmd, delimiter);
|
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.
|
// labels are correct.
|
||||||
cctx->ctx_instr.ga_len = 0;
|
cctx->ctx_instr.ga_len = 0;
|
||||||
cctx->ctx_instr.ga_maxlen = 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);
|
semsg(_(e_trailing_arg), cmd);
|
||||||
clear_instr_ga(&cctx->ctx_instr);
|
clear_instr_ga(&cctx->ctx_instr);
|
||||||
cctx->ctx_instr = save_ga;
|
cctx->ctx_instr = save_ga;
|
||||||
vim_free(instr);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -9555,6 +9617,17 @@ delete_instr(isn_T *isn)
|
|||||||
}
|
}
|
||||||
break;
|
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_LOADS:
|
||||||
case ISN_STORES:
|
case ISN_STORES:
|
||||||
vim_free(isn->isn_arg.loadstore.ls_name);
|
vim_free(isn->isn_arg.loadstore.ls_name);
|
||||||
|
|||||||
@@ -1259,6 +1259,12 @@ fill_partial_and_closure(partial_T *pt, ufunc_T *ufunc, ectx_T *ectx)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// used for v_instr of typval of VAR_INSTR
|
||||||
|
struct instr_S {
|
||||||
|
ectx_T *instr_ectx;
|
||||||
|
isn_T *instr_instr;
|
||||||
|
};
|
||||||
|
|
||||||
// used for substitute_instr
|
// used for substitute_instr
|
||||||
typedef struct subs_expr_S {
|
typedef struct subs_expr_S {
|
||||||
ectx_T *subs_ectx;
|
ectx_T *subs_ectx;
|
||||||
@@ -1379,6 +1385,23 @@ exec_instructions(ectx_T *ectx)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// push typeval VAR_INSTR with instructions to be executed
|
||||||
|
case ISN_INSTR:
|
||||||
|
{
|
||||||
|
if (GA_GROW(&ectx->ec_stack, 1) == FAIL)
|
||||||
|
return FAIL;
|
||||||
|
tv = STACK_TV_BOT(0);
|
||||||
|
tv->vval.v_instr = ALLOC_ONE(instr_T);
|
||||||
|
if (tv->vval.v_instr == NULL)
|
||||||
|
goto on_error;
|
||||||
|
++ectx->ec_stack.ga_len;
|
||||||
|
|
||||||
|
tv->v_type = VAR_INSTR;
|
||||||
|
tv->vval.v_instr->instr_ectx = ectx;
|
||||||
|
tv->vval.v_instr->instr_instr = iptr->isn_arg.instr;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
// execute :substitute with an expression
|
// execute :substitute with an expression
|
||||||
case ISN_SUBSTITUTE:
|
case ISN_SUBSTITUTE:
|
||||||
{
|
{
|
||||||
@@ -3996,6 +4019,33 @@ done:
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Execute the instructions from a VAR_INSTR typeval and put the result in
|
||||||
|
* "rettv".
|
||||||
|
* Return OK or FAIL.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
exe_typval_instr(typval_T *tv, typval_T *rettv)
|
||||||
|
{
|
||||||
|
ectx_T *ectx = tv->vval.v_instr->instr_ectx;
|
||||||
|
isn_T *save_instr = ectx->ec_instr;
|
||||||
|
int save_iidx = ectx->ec_iidx;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
ectx->ec_instr = tv->vval.v_instr->instr_instr;
|
||||||
|
res = exec_instructions(ectx);
|
||||||
|
if (res == OK)
|
||||||
|
{
|
||||||
|
*rettv = *STACK_TV_BOT(-1);
|
||||||
|
--ectx->ec_stack.ga_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
ectx->ec_instr = save_instr;
|
||||||
|
ectx->ec_iidx = save_iidx;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Execute the instructions from an ISN_SUBSTITUTE command, which are in
|
* Execute the instructions from an ISN_SUBSTITUTE command, which are in
|
||||||
* "substitute_instr".
|
* "substitute_instr".
|
||||||
@@ -4436,6 +4486,14 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
case ISN_INSTR:
|
||||||
|
{
|
||||||
|
smsg("%s%4d INSTR", pfx, current);
|
||||||
|
list_instructions(" ", iptr->isn_arg.instr,
|
||||||
|
INT_MAX, NULL);
|
||||||
|
msg(" -------------");
|
||||||
|
}
|
||||||
|
break;
|
||||||
case ISN_SUBSTITUTE:
|
case ISN_SUBSTITUTE:
|
||||||
{
|
{
|
||||||
subs_T *subs = &iptr->isn_arg.subs;
|
subs_T *subs = &iptr->isn_arg.subs;
|
||||||
@@ -5225,6 +5283,7 @@ tv2bool(typval_T *tv)
|
|||||||
case VAR_UNKNOWN:
|
case VAR_UNKNOWN:
|
||||||
case VAR_ANY:
|
case VAR_ANY:
|
||||||
case VAR_VOID:
|
case VAR_VOID:
|
||||||
|
case VAR_INSTR:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|||||||
@@ -950,6 +950,7 @@ equal_type(type_T *type1, type_T *type2)
|
|||||||
case VAR_BLOB:
|
case VAR_BLOB:
|
||||||
case VAR_JOB:
|
case VAR_JOB:
|
||||||
case VAR_CHANNEL:
|
case VAR_CHANNEL:
|
||||||
|
case VAR_INSTR:
|
||||||
break; // not composite is always OK
|
break; // not composite is always OK
|
||||||
case VAR_LIST:
|
case VAR_LIST:
|
||||||
case VAR_DICT:
|
case VAR_DICT:
|
||||||
@@ -1097,6 +1098,7 @@ vartype_name(vartype_T type)
|
|||||||
case VAR_CHANNEL: return "channel";
|
case VAR_CHANNEL: return "channel";
|
||||||
case VAR_LIST: return "list";
|
case VAR_LIST: return "list";
|
||||||
case VAR_DICT: return "dict";
|
case VAR_DICT: return "dict";
|
||||||
|
case VAR_INSTR: return "instr";
|
||||||
|
|
||||||
case VAR_FUNC:
|
case VAR_FUNC:
|
||||||
case VAR_PARTIAL: return "func";
|
case VAR_PARTIAL: return "func";
|
||||||
|
|||||||
@@ -1376,6 +1376,7 @@ write_viminfo_varlist(FILE *fp)
|
|||||||
case VAR_PARTIAL:
|
case VAR_PARTIAL:
|
||||||
case VAR_JOB:
|
case VAR_JOB:
|
||||||
case VAR_CHANNEL:
|
case VAR_CHANNEL:
|
||||||
|
case VAR_INSTR:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
fprintf(fp, "!%s\t%s\t", this_var->di_key, s);
|
fprintf(fp, "!%s\t%s\t", this_var->di_key, s);
|
||||||
|
|||||||
Reference in New Issue
Block a user