forked from aniani/vim
patch 8.2.3435: Vim9: dict is not passed to dict function
Problem: Vim9: dict is not passed to dict function. Solution: Keep the dict used until a function call.
This commit is contained in:
@@ -412,7 +412,8 @@ def Test_disassemble_store_index()
|
|||||||
'\d PUSHNR 0\_s*' ..
|
'\d PUSHNR 0\_s*' ..
|
||||||
'\d LOAD $0\_s*' ..
|
'\d LOAD $0\_s*' ..
|
||||||
'\d MEMBER dd\_s*' ..
|
'\d MEMBER dd\_s*' ..
|
||||||
'\d STOREINDEX any\_s*' ..
|
'\d\+ USEDICT\_s*' ..
|
||||||
|
'\d\+ STOREINDEX any\_s*' ..
|
||||||
'\d\+ RETURN void',
|
'\d\+ RETURN void',
|
||||||
res)
|
res)
|
||||||
enddef
|
enddef
|
||||||
@@ -1625,11 +1626,13 @@ def Test_disassemble_dict_member()
|
|||||||
'var res = d.item\_s*' ..
|
'var res = d.item\_s*' ..
|
||||||
'\d\+ LOAD $0\_s*' ..
|
'\d\+ LOAD $0\_s*' ..
|
||||||
'\d\+ MEMBER item\_s*' ..
|
'\d\+ MEMBER item\_s*' ..
|
||||||
|
'\d\+ USEDICT\_s*' ..
|
||||||
'\d\+ STORE $1\_s*' ..
|
'\d\+ STORE $1\_s*' ..
|
||||||
'res = d\["item"\]\_s*' ..
|
'res = d\["item"\]\_s*' ..
|
||||||
'\d\+ LOAD $0\_s*' ..
|
'\d\+ LOAD $0\_s*' ..
|
||||||
'\d\+ PUSHS "item"\_s*' ..
|
'\d\+ PUSHS "item"\_s*' ..
|
||||||
'\d\+ MEMBER\_s*' ..
|
'\d\+ MEMBER\_s*' ..
|
||||||
|
'\d\+ USEDICT\_s*' ..
|
||||||
'\d\+ STORE $1\_s*',
|
'\d\+ STORE $1\_s*',
|
||||||
instr)
|
instr)
|
||||||
assert_equal(1, DictMember())
|
assert_equal(1, DictMember())
|
||||||
@@ -2302,6 +2305,35 @@ def Test_debug_elseif()
|
|||||||
res)
|
res)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
func Legacy() dict
|
||||||
|
echo 'legacy'
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
def s:UseMember()
|
||||||
|
var d = {func: Legacy}
|
||||||
|
var v = d.func()
|
||||||
|
enddef
|
||||||
|
|
||||||
|
def Test_disassemble_dict_stack()
|
||||||
|
var res = execute('disass s:UseMember')
|
||||||
|
assert_match('<SNR>\d*_UseMember\_s*' ..
|
||||||
|
'var d = {func: Legacy}\_s*' ..
|
||||||
|
'\d PUSHS "func"\_s*' ..
|
||||||
|
'\d PUSHFUNC "Legacy"\_s*' ..
|
||||||
|
'\d NEWDICT size 1\_s*' ..
|
||||||
|
'\d STORE $0\_s*' ..
|
||||||
|
|
||||||
|
'var v = d.func()\_s*' ..
|
||||||
|
'\d LOAD $0\_s*' ..
|
||||||
|
'\d MEMBER func\_s*' ..
|
||||||
|
'\d PCALL top (argc 0)\_s*' ..
|
||||||
|
'\d PCALL end\_s*' ..
|
||||||
|
'\d CLEARDICT\_s*' ..
|
||||||
|
'\d\+ STORE $1\_s*' ..
|
||||||
|
'\d\+ RETURN void*',
|
||||||
|
res)
|
||||||
|
enddef
|
||||||
|
|
||||||
def s:EchoMessages()
|
def s:EchoMessages()
|
||||||
echohl ErrorMsg | echom v:exception | echohl NONE
|
echohl ErrorMsg | echom v:exception | echohl NONE
|
||||||
enddef
|
enddef
|
||||||
@@ -2363,4 +2395,5 @@ def Test_disassemble_after_reload()
|
|||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
||||||
|
|||||||
@@ -2557,6 +2557,37 @@ def Test_legacy_errors()
|
|||||||
endfor
|
endfor
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
def Test_call_legacy_with_dict()
|
||||||
|
var lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
func Legacy() dict
|
||||||
|
let g:result = self.value
|
||||||
|
endfunc
|
||||||
|
def TestDirect()
|
||||||
|
var d = {value: 'yes', func: Legacy}
|
||||||
|
d.func()
|
||||||
|
enddef
|
||||||
|
TestDirect()
|
||||||
|
assert_equal('yes', g:result)
|
||||||
|
unlet g:result
|
||||||
|
|
||||||
|
def TestIndirect()
|
||||||
|
var d = {value: 'foo', func: Legacy}
|
||||||
|
var Fi = d.func
|
||||||
|
Fi()
|
||||||
|
enddef
|
||||||
|
TestIndirect()
|
||||||
|
assert_equal('foo', g:result)
|
||||||
|
unlet g:result
|
||||||
|
|
||||||
|
var d = {value: 'bar', func: Legacy}
|
||||||
|
d.func()
|
||||||
|
assert_equal('bar', g:result)
|
||||||
|
unlet g:result
|
||||||
|
END
|
||||||
|
CheckScriptSuccess(lines)
|
||||||
|
enddef
|
||||||
|
|
||||||
def DoFilterThis(a: string): list<string>
|
def DoFilterThis(a: string): list<string>
|
||||||
# closure nested inside another closure using argument
|
# closure nested inside another closure using argument
|
||||||
var Filter = (l) => filter(l, (_, v) => stridx(v, a) == 0)
|
var Filter = (l) => filter(l, (_, v) => stridx(v, a) == 0)
|
||||||
|
|||||||
@@ -755,6 +755,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 */
|
||||||
|
/**/
|
||||||
|
3435,
|
||||||
/**/
|
/**/
|
||||||
3434,
|
3434,
|
||||||
/**/
|
/**/
|
||||||
|
|||||||
@@ -162,6 +162,9 @@ typedef enum {
|
|||||||
ISN_CHECKLEN, // check list length is isn_arg.checklen.cl_min_len
|
ISN_CHECKLEN, // check list length is isn_arg.checklen.cl_min_len
|
||||||
ISN_SETTYPE, // set dict type to isn_arg.type.ct_type
|
ISN_SETTYPE, // set dict type to isn_arg.type.ct_type
|
||||||
|
|
||||||
|
ISN_CLEARDICT, // clear dict saved by ISN_MEMBER/ISN_STRINGMEMBER
|
||||||
|
ISN_USEDICT, // use or clear dict saved by ISN_MEMBER/ISN_STRINGMEMBER
|
||||||
|
|
||||||
ISN_PUT, // ":put", uses isn_arg.put
|
ISN_PUT, // ":put", uses isn_arg.put
|
||||||
|
|
||||||
ISN_CMDMOD, // set cmdmod
|
ISN_CMDMOD, // set cmdmod
|
||||||
|
|||||||
@@ -2878,9 +2878,10 @@ clear_ppconst(ppconst_T *ppconst)
|
|||||||
/*
|
/*
|
||||||
* Compile getting a member from a list/dict/string/blob. Stack has the
|
* Compile getting a member from a list/dict/string/blob. Stack has the
|
||||||
* indexable value and the index or the two indexes of a slice.
|
* indexable value and the index or the two indexes of a slice.
|
||||||
|
* "keeping_dict" is used for dict[func](arg) to pass dict to func.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
compile_member(int is_slice, cctx_T *cctx)
|
compile_member(int is_slice, int *keeping_dict, cctx_T *cctx)
|
||||||
{
|
{
|
||||||
type_T **typep;
|
type_T **typep;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
garray_T *stack = &cctx->ctx_type_stack;
|
||||||
@@ -2935,6 +2936,8 @@ compile_member(int is_slice, cctx_T *cctx)
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
if (generate_instr_drop(cctx, ISN_MEMBER, 1) == FAIL)
|
if (generate_instr_drop(cctx, ISN_MEMBER, 1) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
if (keeping_dict != NULL)
|
||||||
|
*keeping_dict = TRUE;
|
||||||
}
|
}
|
||||||
else if (vartype == VAR_STRING)
|
else if (vartype == VAR_STRING)
|
||||||
{
|
{
|
||||||
@@ -4314,6 +4317,7 @@ compile_subscript(
|
|||||||
ppconst_T *ppconst)
|
ppconst_T *ppconst)
|
||||||
{
|
{
|
||||||
char_u *name_start = *end_leader;
|
char_u *name_start = *end_leader;
|
||||||
|
int keeping_dict = FALSE;
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@@ -4360,6 +4364,12 @@ compile_subscript(
|
|||||||
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;
|
||||||
|
if (keeping_dict)
|
||||||
|
{
|
||||||
|
keeping_dict = FALSE;
|
||||||
|
if (generate_instr(cctx, ISN_CLEARDICT) == NULL)
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (*p == '-' && p[1] == '>')
|
else if (*p == '-' && p[1] == '>')
|
||||||
{
|
{
|
||||||
@@ -4470,6 +4480,12 @@ compile_subscript(
|
|||||||
if (compile_call(arg, p - *arg, cctx, ppconst, 1) == FAIL)
|
if (compile_call(arg, p - *arg, cctx, ppconst, 1) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
if (keeping_dict)
|
||||||
|
{
|
||||||
|
keeping_dict = FALSE;
|
||||||
|
if (generate_instr(cctx, ISN_CLEARDICT) == NULL)
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (**arg == '[')
|
else if (**arg == '[')
|
||||||
{
|
{
|
||||||
@@ -4537,7 +4553,13 @@ compile_subscript(
|
|||||||
}
|
}
|
||||||
*arg = *arg + 1;
|
*arg = *arg + 1;
|
||||||
|
|
||||||
if (compile_member(is_slice, cctx) == FAIL)
|
if (keeping_dict)
|
||||||
|
{
|
||||||
|
keeping_dict = FALSE;
|
||||||
|
if (generate_instr(cctx, ISN_CLEARDICT) == NULL)
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
if (compile_member(is_slice, &keeping_dict, cctx) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
else if (*p == '.' && p[1] != '.')
|
else if (*p == '.' && p[1] != '.')
|
||||||
@@ -4562,18 +4584,21 @@ compile_subscript(
|
|||||||
semsg(_(e_syntax_error_at_str), *arg);
|
semsg(_(e_syntax_error_at_str), *arg);
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
if (keeping_dict && generate_instr(cctx, ISN_CLEARDICT) == NULL)
|
||||||
|
return FAIL;
|
||||||
if (generate_STRINGMEMBER(cctx, *arg, p - *arg) == FAIL)
|
if (generate_STRINGMEMBER(cctx, *arg, p - *arg) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
keeping_dict = TRUE;
|
||||||
*arg = p;
|
*arg = p;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO - see handle_subscript():
|
|
||||||
// Turn "dict.Func" into a partial for "Func" bound to "dict".
|
// Turn "dict.Func" into a partial for "Func" bound to "dict".
|
||||||
// Don't do this when "Func" is already a partial that was bound
|
// This needs to be done at runtime to be able to check the type.
|
||||||
// explicitly (pt_auto is FALSE).
|
if (keeping_dict && generate_instr(cctx, ISN_USEDICT) == NULL)
|
||||||
|
return FAIL;
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@@ -6661,7 +6686,7 @@ compile_load_lhs_with_index(lhs_T *lhs, char_u *var_start, cctx_T *cctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the member.
|
// Get the member.
|
||||||
if (compile_member(FALSE, cctx) == FAIL)
|
if (compile_member(FALSE, NULL, cctx) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
return OK;
|
return OK;
|
||||||
@@ -10406,6 +10431,7 @@ delete_instr(isn_T *isn)
|
|||||||
case ISN_CEXPR_AUCMD:
|
case ISN_CEXPR_AUCMD:
|
||||||
case ISN_CHECKLEN:
|
case ISN_CHECKLEN:
|
||||||
case ISN_CHECKNR:
|
case ISN_CHECKNR:
|
||||||
|
case ISN_CLEARDICT:
|
||||||
case ISN_CMDMOD_REV:
|
case ISN_CMDMOD_REV:
|
||||||
case ISN_COMPAREANY:
|
case ISN_COMPAREANY:
|
||||||
case ISN_COMPAREBLOB:
|
case ISN_COMPAREBLOB:
|
||||||
@@ -10482,6 +10508,7 @@ delete_instr(isn_T *isn)
|
|||||||
case ISN_UNLETINDEX:
|
case ISN_UNLETINDEX:
|
||||||
case ISN_UNLETRANGE:
|
case ISN_UNLETRANGE:
|
||||||
case ISN_UNPACK:
|
case ISN_UNPACK:
|
||||||
|
case ISN_USEDICT:
|
||||||
// nothing allocated
|
// nothing allocated
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -165,6 +165,75 @@ update_has_breakpoint(ufunc_T *ufunc)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static garray_T dict_stack = GA_EMPTY;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Put a value on the dict stack. This consumes "tv".
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
dict_stack_save(typval_T *tv)
|
||||||
|
{
|
||||||
|
if (dict_stack.ga_growsize == 0)
|
||||||
|
ga_init2(&dict_stack, (int)sizeof(typval_T), 10);
|
||||||
|
if (ga_grow(&dict_stack, 1) == FAIL)
|
||||||
|
return FAIL;
|
||||||
|
((typval_T *)dict_stack.ga_data)[dict_stack.ga_len] = *tv;
|
||||||
|
++dict_stack.ga_len;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the typval at top of the dict stack.
|
||||||
|
*/
|
||||||
|
static typval_T *
|
||||||
|
dict_stack_get_tv(void)
|
||||||
|
{
|
||||||
|
if (dict_stack.ga_len == 0)
|
||||||
|
return NULL;
|
||||||
|
return ((typval_T *)dict_stack.ga_data) + dict_stack.ga_len - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the dict at top of the dict stack.
|
||||||
|
*/
|
||||||
|
static dict_T *
|
||||||
|
dict_stack_get_dict(void)
|
||||||
|
{
|
||||||
|
typval_T *tv;
|
||||||
|
|
||||||
|
if (dict_stack.ga_len == 0)
|
||||||
|
return NULL;
|
||||||
|
tv = ((typval_T *)dict_stack.ga_data) + dict_stack.ga_len - 1;
|
||||||
|
if (tv->v_type == VAR_DICT)
|
||||||
|
return tv->vval.v_dict;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Drop an item from the dict stack.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
dict_stack_drop(void)
|
||||||
|
{
|
||||||
|
if (dict_stack.ga_len == 0)
|
||||||
|
{
|
||||||
|
iemsg("Dict stack underflow");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
--dict_stack.ga_len;
|
||||||
|
clear_tv(((typval_T *)dict_stack.ga_data) + dict_stack.ga_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Drop items from the dict stack until the length is equal to "len".
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
dict_stack_clear(int len)
|
||||||
|
{
|
||||||
|
while (dict_stack.ga_len > len)
|
||||||
|
dict_stack_drop();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Call compiled function "cdf_idx" from compiled code.
|
* Call compiled function "cdf_idx" from compiled code.
|
||||||
* This adds a stack frame and sets the instruction pointer to the start of the
|
* This adds a stack frame and sets the instruction pointer to the start of the
|
||||||
@@ -765,7 +834,8 @@ call_ufunc(
|
|||||||
partial_T *pt,
|
partial_T *pt,
|
||||||
int argcount,
|
int argcount,
|
||||||
ectx_T *ectx,
|
ectx_T *ectx,
|
||||||
isn_T *iptr)
|
isn_T *iptr,
|
||||||
|
dict_T *selfdict)
|
||||||
{
|
{
|
||||||
typval_T argvars[MAX_FUNC_ARGS];
|
typval_T argvars[MAX_FUNC_ARGS];
|
||||||
funcexe_T funcexe;
|
funcexe_T funcexe;
|
||||||
@@ -807,11 +877,12 @@ call_ufunc(
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
CLEAR_FIELD(funcexe);
|
CLEAR_FIELD(funcexe);
|
||||||
funcexe.evaluate = TRUE;
|
funcexe.evaluate = TRUE;
|
||||||
|
funcexe.selfdict = selfdict != NULL ? selfdict : dict_stack_get_dict();
|
||||||
|
|
||||||
// Call the user function. Result goes in last position on the stack.
|
// Call the user function. Result goes in last position on the stack.
|
||||||
// TODO: add selfdict if there is one
|
// TODO: add selfdict if there is one
|
||||||
error = call_user_func_check(ufunc, argcount, argvars,
|
error = call_user_func_check(ufunc, argcount, argvars,
|
||||||
STACK_TV_BOT(-1), &funcexe, NULL);
|
STACK_TV_BOT(-1), &funcexe, funcexe.selfdict);
|
||||||
|
|
||||||
// Clear the arguments.
|
// Clear the arguments.
|
||||||
for (idx = 0; idx < argcount; ++idx)
|
for (idx = 0; idx < argcount; ++idx)
|
||||||
@@ -864,7 +935,8 @@ call_by_name(
|
|||||||
char_u *name,
|
char_u *name,
|
||||||
int argcount,
|
int argcount,
|
||||||
ectx_T *ectx,
|
ectx_T *ectx,
|
||||||
isn_T *iptr)
|
isn_T *iptr,
|
||||||
|
dict_T *selfdict)
|
||||||
{
|
{
|
||||||
ufunc_T *ufunc;
|
ufunc_T *ufunc;
|
||||||
|
|
||||||
@@ -916,7 +988,7 @@ call_by_name(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return call_ufunc(ufunc, NULL, argcount, ectx, iptr);
|
return call_ufunc(ufunc, NULL, argcount, ectx, iptr, selfdict);
|
||||||
}
|
}
|
||||||
|
|
||||||
return FAIL;
|
return FAIL;
|
||||||
@@ -932,6 +1004,7 @@ call_partial(
|
|||||||
char_u *name = NULL;
|
char_u *name = NULL;
|
||||||
int called_emsg_before = called_emsg;
|
int called_emsg_before = called_emsg;
|
||||||
int res = FAIL;
|
int res = FAIL;
|
||||||
|
dict_T *selfdict = NULL;
|
||||||
|
|
||||||
if (tv->v_type == VAR_PARTIAL)
|
if (tv->v_type == VAR_PARTIAL)
|
||||||
{
|
{
|
||||||
@@ -953,9 +1026,10 @@ call_partial(
|
|||||||
for (i = 0; i < pt->pt_argc; ++i)
|
for (i = 0; i < pt->pt_argc; ++i)
|
||||||
copy_tv(&pt->pt_argv[i], STACK_TV_BOT(-argcount + i));
|
copy_tv(&pt->pt_argv[i], STACK_TV_BOT(-argcount + i));
|
||||||
}
|
}
|
||||||
|
selfdict = pt->pt_dict;
|
||||||
|
|
||||||
if (pt->pt_func != NULL)
|
if (pt->pt_func != NULL)
|
||||||
return call_ufunc(pt->pt_func, pt, argcount, ectx, NULL);
|
return call_ufunc(pt->pt_func, pt, argcount, ectx, NULL, selfdict);
|
||||||
|
|
||||||
name = pt->pt_name;
|
name = pt->pt_name;
|
||||||
}
|
}
|
||||||
@@ -973,7 +1047,7 @@ call_partial(
|
|||||||
if (error != FCERR_NONE)
|
if (error != FCERR_NONE)
|
||||||
res = FAIL;
|
res = FAIL;
|
||||||
else
|
else
|
||||||
res = call_by_name(fname, argcount, ectx, NULL);
|
res = call_by_name(fname, argcount, ectx, NULL, selfdict);
|
||||||
vim_free(tofree);
|
vim_free(tofree);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1325,7 +1399,7 @@ call_eval_func(
|
|||||||
int called_emsg_before = called_emsg;
|
int called_emsg_before = called_emsg;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
res = call_by_name(name, argcount, ectx, iptr);
|
res = call_by_name(name, argcount, ectx, iptr, NULL);
|
||||||
if (res == FAIL && called_emsg == called_emsg_before)
|
if (res == FAIL && called_emsg == called_emsg_before)
|
||||||
{
|
{
|
||||||
dictitem_T *v;
|
dictitem_T *v;
|
||||||
@@ -1570,6 +1644,7 @@ exec_instructions(ectx_T *ectx)
|
|||||||
{
|
{
|
||||||
int ret = FAIL;
|
int ret = FAIL;
|
||||||
int save_trylevel_at_start = ectx->ec_trylevel_at_start;
|
int save_trylevel_at_start = ectx->ec_trylevel_at_start;
|
||||||
|
int dict_stack_len_at_start = dict_stack.ga_len;
|
||||||
|
|
||||||
// Start execution at the first instruction.
|
// Start execution at the first instruction.
|
||||||
ectx->ec_iidx = 0;
|
ectx->ec_iidx = 0;
|
||||||
@@ -4022,7 +4097,6 @@ exec_instructions(ectx_T *ectx)
|
|||||||
dict_T *dict;
|
dict_T *dict;
|
||||||
char_u *key;
|
char_u *key;
|
||||||
dictitem_T *di;
|
dictitem_T *di;
|
||||||
typval_T temp_tv;
|
|
||||||
|
|
||||||
// dict member: dict is at stack-2, key at stack-1
|
// dict member: dict is at stack-2, key at stack-1
|
||||||
tv = STACK_TV_BOT(-2);
|
tv = STACK_TV_BOT(-2);
|
||||||
@@ -4041,23 +4115,24 @@ exec_instructions(ectx_T *ectx)
|
|||||||
semsg(_(e_dictkey), key);
|
semsg(_(e_dictkey), key);
|
||||||
|
|
||||||
// If :silent! is used we will continue, make sure the
|
// If :silent! is used we will continue, make sure the
|
||||||
// stack contents makes sense.
|
// stack contents makes sense and the dict stack is
|
||||||
|
// updated.
|
||||||
clear_tv(tv);
|
clear_tv(tv);
|
||||||
--ectx->ec_stack.ga_len;
|
--ectx->ec_stack.ga_len;
|
||||||
tv = STACK_TV_BOT(-1);
|
tv = STACK_TV_BOT(-1);
|
||||||
clear_tv(tv);
|
(void) dict_stack_save(tv);
|
||||||
tv->v_type = VAR_NUMBER;
|
tv->v_type = VAR_NUMBER;
|
||||||
tv->vval.v_number = 0;
|
tv->vval.v_number = 0;
|
||||||
goto on_fatal_error;
|
goto on_fatal_error;
|
||||||
}
|
}
|
||||||
clear_tv(tv);
|
clear_tv(tv);
|
||||||
--ectx->ec_stack.ga_len;
|
--ectx->ec_stack.ga_len;
|
||||||
// Clear the dict only after getting the item, to avoid
|
// Put the dict used on the dict stack, it might be used by
|
||||||
// that it makes the item invalid.
|
// a dict function later.
|
||||||
tv = STACK_TV_BOT(-1);
|
tv = STACK_TV_BOT(-1);
|
||||||
temp_tv = *tv;
|
if (dict_stack_save(tv) == FAIL)
|
||||||
|
goto on_fatal_error;
|
||||||
copy_tv(&di->di_tv, tv);
|
copy_tv(&di->di_tv, tv);
|
||||||
clear_tv(&temp_tv);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -4066,7 +4141,6 @@ exec_instructions(ectx_T *ectx)
|
|||||||
{
|
{
|
||||||
dict_T *dict;
|
dict_T *dict;
|
||||||
dictitem_T *di;
|
dictitem_T *di;
|
||||||
typval_T temp_tv;
|
|
||||||
|
|
||||||
tv = STACK_TV_BOT(-1);
|
tv = STACK_TV_BOT(-1);
|
||||||
if (tv->v_type != VAR_DICT || tv->vval.v_dict == NULL)
|
if (tv->v_type != VAR_DICT || tv->vval.v_dict == NULL)
|
||||||
@@ -4084,11 +4158,37 @@ exec_instructions(ectx_T *ectx)
|
|||||||
semsg(_(e_dictkey), iptr->isn_arg.string);
|
semsg(_(e_dictkey), iptr->isn_arg.string);
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
// Clear the dict after getting the item, to avoid that it
|
// Put the dict used on the dict stack, it might be used by
|
||||||
// make the item invalid.
|
// a dict function later.
|
||||||
temp_tv = *tv;
|
if (dict_stack_save(tv) == FAIL)
|
||||||
|
goto on_fatal_error;
|
||||||
|
|
||||||
copy_tv(&di->di_tv, tv);
|
copy_tv(&di->di_tv, tv);
|
||||||
clear_tv(&temp_tv);
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ISN_CLEARDICT:
|
||||||
|
dict_stack_drop();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ISN_USEDICT:
|
||||||
|
{
|
||||||
|
typval_T *dict_tv = dict_stack_get_tv();
|
||||||
|
|
||||||
|
// Turn "dict.Func" into a partial for "Func" bound to
|
||||||
|
// "dict". Don't do this when "Func" is already a partial
|
||||||
|
// that was bound explicitly (pt_auto is FALSE).
|
||||||
|
tv = STACK_TV_BOT(-1);
|
||||||
|
if (dict_tv != NULL
|
||||||
|
&& dict_tv->v_type == VAR_DICT
|
||||||
|
&& dict_tv->vval.v_dict != NULL
|
||||||
|
&& (tv->v_type == VAR_FUNC
|
||||||
|
|| (tv->v_type == VAR_PARTIAL
|
||||||
|
&& (tv->vval.v_partial->pt_auto
|
||||||
|
|| tv->vval.v_partial->pt_dict == NULL))))
|
||||||
|
dict_tv->vval.v_dict =
|
||||||
|
make_partial(dict_tv->vval.v_dict, tv);
|
||||||
|
dict_stack_drop();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -4478,6 +4578,7 @@ on_fatal_error:
|
|||||||
done:
|
done:
|
||||||
ret = OK;
|
ret = OK;
|
||||||
theend:
|
theend:
|
||||||
|
dict_stack_clear(dict_stack_len_at_start);
|
||||||
ectx->ec_trylevel_at_start = save_trylevel_at_start;
|
ectx->ec_trylevel_at_start = save_trylevel_at_start;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -5568,6 +5669,9 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
|
|||||||
case ISN_MEMBER: smsg("%s%4d MEMBER", pfx, current); break;
|
case ISN_MEMBER: smsg("%s%4d MEMBER", pfx, current); break;
|
||||||
case ISN_STRINGMEMBER: smsg("%s%4d MEMBER %s", pfx, current,
|
case ISN_STRINGMEMBER: smsg("%s%4d MEMBER %s", pfx, current,
|
||||||
iptr->isn_arg.string); break;
|
iptr->isn_arg.string); break;
|
||||||
|
case ISN_CLEARDICT: smsg("%s%4d CLEARDICT", pfx, current); break;
|
||||||
|
case ISN_USEDICT: smsg("%s%4d USEDICT", pfx, current); break;
|
||||||
|
|
||||||
case ISN_NEGATENR: smsg("%s%4d NEGATENR", pfx, current); break;
|
case ISN_NEGATENR: smsg("%s%4d NEGATENR", pfx, current); break;
|
||||||
|
|
||||||
case ISN_CHECKNR: smsg("%s%4d CHECKNR", pfx, current); break;
|
case ISN_CHECKNR: smsg("%s%4d CHECKNR", pfx, current); break;
|
||||||
|
|||||||
Reference in New Issue
Block a user