forked from aniani/vim
patch 8.2.2179: Vim9: crash when indexing a dict with a number
Problem: Vim9: crash when indexing a dict with a number. Solution: Add ISN_STOREINDEX. (closes #7513)
This commit is contained in:
@@ -323,3 +323,7 @@ EXTERN char e_missing_heredoc_end_marker_str[]
|
|||||||
INIT(= N_("E1145: Missing heredoc end marker: %s"));
|
INIT(= N_("E1145: Missing heredoc end marker: %s"));
|
||||||
EXTERN char e_command_not_recognized_str[]
|
EXTERN char e_command_not_recognized_str[]
|
||||||
INIT(= N_("E1146: Command not recognized: %s"));
|
INIT(= N_("E1146: Command not recognized: %s"));
|
||||||
|
EXTERN char e_list_not_set[]
|
||||||
|
INIT(= N_("E1147: List not set"));
|
||||||
|
EXTERN char e_cannot_index_str[]
|
||||||
|
INIT(= N_("E1148: Cannot index a %s"));
|
||||||
|
@@ -533,6 +533,12 @@ def Test_assignment_list()
|
|||||||
|
|
||||||
# type becomes list<any>
|
# type becomes list<any>
|
||||||
var somelist = rand() > 0 ? [1, 2, 3] : ['a', 'b', 'c']
|
var somelist = rand() > 0 ? [1, 2, 3] : ['a', 'b', 'c']
|
||||||
|
|
||||||
|
var lines =<< trim END
|
||||||
|
var d = {dd: test_null_list()}
|
||||||
|
d.dd[0] = 0
|
||||||
|
END
|
||||||
|
CheckDefExecFailure(lines, 'E1147:', 2)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
def Test_assignment_list_vim9script()
|
def Test_assignment_list_vim9script()
|
||||||
@@ -567,12 +573,20 @@ def Test_assignment_dict()
|
|||||||
assert_equal({nest: {this: 123, that: 456}, nr: 0}, anydict)
|
assert_equal({nest: {this: 123, that: 456}, nr: 0}, anydict)
|
||||||
|
|
||||||
var lines =<< trim END
|
var lines =<< trim END
|
||||||
vim9script
|
|
||||||
var dd = {}
|
var dd = {}
|
||||||
dd.two = 2
|
dd.two = 2
|
||||||
assert_equal({two: 2}, dd)
|
assert_equal({two: 2}, dd)
|
||||||
END
|
END
|
||||||
CheckScriptSuccess(lines)
|
CheckDefAndScriptSuccess(lines)
|
||||||
|
|
||||||
|
lines =<< trim END
|
||||||
|
var d = {dd: {}}
|
||||||
|
d.dd[0] = 2
|
||||||
|
d.dd['x'] = 3
|
||||||
|
d.dd.y = 4
|
||||||
|
assert_equal({dd: {0: 2, x: 3, y: 4}}, d)
|
||||||
|
END
|
||||||
|
CheckDefAndScriptSuccess(lines)
|
||||||
|
|
||||||
lines =<< trim END
|
lines =<< trim END
|
||||||
var dd = {one: 1}
|
var dd = {one: 1}
|
||||||
@@ -641,6 +655,18 @@ def Test_assignment_dict()
|
|||||||
assert_equal({a: 43}, FillDict())
|
assert_equal({a: 43}, FillDict())
|
||||||
END
|
END
|
||||||
CheckScriptSuccess(lines)
|
CheckScriptSuccess(lines)
|
||||||
|
|
||||||
|
lines =<< trim END
|
||||||
|
var d = {dd: test_null_dict()}
|
||||||
|
d.dd[0] = 0
|
||||||
|
END
|
||||||
|
CheckDefExecFailure(lines, 'E1103:', 2)
|
||||||
|
|
||||||
|
lines =<< trim END
|
||||||
|
var d = {dd: 'string'}
|
||||||
|
d.dd[0] = 0
|
||||||
|
END
|
||||||
|
CheckDefExecFailure(lines, 'E1148:', 2)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
def Test_assignment_local()
|
def Test_assignment_local()
|
||||||
|
@@ -276,6 +276,30 @@ def Test_disassemble_store_member()
|
|||||||
res)
|
res)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
def s:ScriptFuncStoreIndex()
|
||||||
|
var d = {dd: {}}
|
||||||
|
d.dd[0] = 0
|
||||||
|
enddef
|
||||||
|
|
||||||
|
def Test_disassemble_store_index()
|
||||||
|
var res = execute('disass s:ScriptFuncStoreIndex')
|
||||||
|
assert_match('<SNR>\d*_ScriptFuncStoreIndex\_s*' ..
|
||||||
|
'var d = {dd: {}}\_s*' ..
|
||||||
|
'\d PUSHS "dd"\_s*' ..
|
||||||
|
'\d NEWDICT size 0\_s*' ..
|
||||||
|
'\d NEWDICT size 1\_s*' ..
|
||||||
|
'\d STORE $0\_s*' ..
|
||||||
|
'd.dd\[0\] = 0\_s*' ..
|
||||||
|
'\d PUSHNR 0\_s*' ..
|
||||||
|
'\d PUSHNR 0\_s*' ..
|
||||||
|
'\d LOAD $0\_s*' ..
|
||||||
|
'\d MEMBER dd\_s*' ..
|
||||||
|
'\d STOREINDEX\_s*' ..
|
||||||
|
'\d\+ PUSHNR 0\_s*' ..
|
||||||
|
'\d\+ RETURN',
|
||||||
|
res)
|
||||||
|
enddef
|
||||||
|
|
||||||
def s:ListAssign()
|
def s:ListAssign()
|
||||||
var x: string
|
var x: string
|
||||||
var y: string
|
var y: string
|
||||||
|
@@ -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 */
|
||||||
|
/**/
|
||||||
|
2179,
|
||||||
/**/
|
/**/
|
||||||
2178,
|
2178,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -55,8 +55,8 @@ typedef enum {
|
|||||||
// ISN_STOREOTHER, // pop into other script variable isn_arg.other.
|
// ISN_STOREOTHER, // pop into other script variable isn_arg.other.
|
||||||
|
|
||||||
ISN_STORENR, // store number into local variable isn_arg.storenr.stnr_idx
|
ISN_STORENR, // store number into local variable isn_arg.storenr.stnr_idx
|
||||||
ISN_STORELIST, // store into list, value/index/variable on stack
|
ISN_STOREINDEX, // store into list or dictionary, type isn_arg.vartype,
|
||||||
ISN_STOREDICT, // store into dictionary, value/index/variable on stack
|
// value/index/variable on stack
|
||||||
|
|
||||||
ISN_UNLET, // unlet variable isn_arg.unlet.ul_name
|
ISN_UNLET, // unlet variable isn_arg.unlet.ul_name
|
||||||
ISN_UNLETENV, // unlet environment variable isn_arg.unlet.ul_name
|
ISN_UNLETENV, // unlet environment variable isn_arg.unlet.ul_name
|
||||||
@@ -304,6 +304,7 @@ struct isn_S {
|
|||||||
char_u *string;
|
char_u *string;
|
||||||
varnumber_T number;
|
varnumber_T number;
|
||||||
blob_T *blob;
|
blob_T *blob;
|
||||||
|
vartype_T vartype;
|
||||||
#ifdef FEAT_FLOAT
|
#ifdef FEAT_FLOAT
|
||||||
float_T fnumber;
|
float_T fnumber;
|
||||||
#endif
|
#endif
|
||||||
|
@@ -5904,26 +5904,22 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|||||||
|
|
||||||
if (type == &t_any)
|
if (type == &t_any)
|
||||||
{
|
{
|
||||||
type_T *idx_type = ((type_T **)stack->ga_data)[
|
// Index on variable of unknown type: check at runtime.
|
||||||
stack->ga_len - 1];
|
dest_type = VAR_ANY;
|
||||||
// Index on variable of unknown type: guess the type from the
|
|
||||||
// index type: number is dict, otherwise dict.
|
|
||||||
// TODO: should do the assignment at runtime
|
|
||||||
if (idx_type->tt_type == VAR_NUMBER)
|
|
||||||
type = &t_list_any;
|
|
||||||
else
|
|
||||||
type = &t_dict_any;
|
|
||||||
}
|
}
|
||||||
dest_type = type->tt_type;
|
else
|
||||||
if (dest_type == VAR_DICT
|
|
||||||
&& may_generate_2STRING(-1, cctx) == FAIL)
|
|
||||||
goto theend;
|
|
||||||
if (dest_type == VAR_LIST
|
|
||||||
&& ((type_T **)stack->ga_data)[stack->ga_len - 1]->tt_type
|
|
||||||
!= VAR_NUMBER)
|
|
||||||
{
|
{
|
||||||
emsg(_(e_number_exp));
|
dest_type = type->tt_type;
|
||||||
goto theend;
|
if (dest_type == VAR_DICT
|
||||||
|
&& may_generate_2STRING(-1, cctx) == FAIL)
|
||||||
|
goto theend;
|
||||||
|
if (dest_type == VAR_LIST
|
||||||
|
&& ((type_T **)stack->ga_data)[stack->ga_len - 1]->tt_type
|
||||||
|
!= VAR_NUMBER)
|
||||||
|
{
|
||||||
|
emsg(_(e_number_exp));
|
||||||
|
goto theend;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the dict or list. On the stack we then have:
|
// Load the dict or list. On the stack we then have:
|
||||||
@@ -5956,15 +5952,14 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|||||||
else
|
else
|
||||||
generate_loadvar(cctx, dest, name, lvar, type);
|
generate_loadvar(cctx, dest, name, lvar, type);
|
||||||
|
|
||||||
if (dest_type == VAR_LIST)
|
if (dest_type == VAR_LIST || dest_type == VAR_DICT
|
||||||
|
|| dest_type == VAR_ANY)
|
||||||
{
|
{
|
||||||
if (generate_instr_drop(cctx, ISN_STORELIST, 3) == FAIL)
|
isn_T *isn = generate_instr_drop(cctx, ISN_STOREINDEX, 3);
|
||||||
goto theend;
|
|
||||||
}
|
if (isn == NULL)
|
||||||
else if (dest_type == VAR_DICT)
|
|
||||||
{
|
|
||||||
if (generate_instr_drop(cctx, ISN_STOREDICT, 3) == FAIL)
|
|
||||||
goto theend;
|
goto theend;
|
||||||
|
isn->isn_arg.vartype = dest_type;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -8194,8 +8189,7 @@ delete_instr(isn_T *isn)
|
|||||||
case ISN_SHUFFLE:
|
case ISN_SHUFFLE:
|
||||||
case ISN_SLICE:
|
case ISN_SLICE:
|
||||||
case ISN_STORE:
|
case ISN_STORE:
|
||||||
case ISN_STOREDICT:
|
case ISN_STOREINDEX:
|
||||||
case ISN_STORELIST:
|
|
||||||
case ISN_STORENR:
|
case ISN_STORENR:
|
||||||
case ISN_STOREOUTER:
|
case ISN_STOREOUTER:
|
||||||
case ISN_STOREREG:
|
case ISN_STOREREG:
|
||||||
|
@@ -801,6 +801,38 @@ store_var(char_u *name, typval_T *tv)
|
|||||||
restore_funccal();
|
restore_funccal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert "tv" to a string.
|
||||||
|
* Return FAIL if not allowed.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
do_2string(typval_T *tv, int is_2string_any)
|
||||||
|
{
|
||||||
|
if (tv->v_type != VAR_STRING)
|
||||||
|
{
|
||||||
|
char_u *str;
|
||||||
|
|
||||||
|
if (is_2string_any)
|
||||||
|
{
|
||||||
|
switch (tv->v_type)
|
||||||
|
{
|
||||||
|
case VAR_SPECIAL:
|
||||||
|
case VAR_BOOL:
|
||||||
|
case VAR_NUMBER:
|
||||||
|
case VAR_FLOAT:
|
||||||
|
case VAR_BLOB: break;
|
||||||
|
default: to_string_error(tv->v_type);
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
str = typval_tostring(tv);
|
||||||
|
clear_tv(tv);
|
||||||
|
tv->v_type = VAR_STRING;
|
||||||
|
tv->vval.v_string = str;
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When the value of "sv" is a null list of dict, allocate it.
|
* When the value of "sv" is a null list of dict, allocate it.
|
||||||
*/
|
*/
|
||||||
@@ -1700,92 +1732,126 @@ call_def_function(
|
|||||||
tv->vval.v_number = iptr->isn_arg.storenr.stnr_val;
|
tv->vval.v_number = iptr->isn_arg.storenr.stnr_val;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// store value in list variable
|
// store value in list or dict variable
|
||||||
case ISN_STORELIST:
|
case ISN_STOREINDEX:
|
||||||
{
|
{
|
||||||
|
vartype_T dest_type = iptr->isn_arg.vartype;
|
||||||
typval_T *tv_idx = STACK_TV_BOT(-2);
|
typval_T *tv_idx = STACK_TV_BOT(-2);
|
||||||
varnumber_T lidx = tv_idx->vval.v_number;
|
typval_T *tv_dest = STACK_TV_BOT(-1);
|
||||||
typval_T *tv_list = STACK_TV_BOT(-1);
|
int status = OK;
|
||||||
list_T *list = tv_list->vval.v_list;
|
|
||||||
|
|
||||||
SOURCING_LNUM = iptr->isn_lnum;
|
|
||||||
if (lidx < 0 && list->lv_len + lidx >= 0)
|
|
||||||
// negative index is relative to the end
|
|
||||||
lidx = list->lv_len + lidx;
|
|
||||||
if (lidx < 0 || lidx > list->lv_len)
|
|
||||||
{
|
|
||||||
semsg(_(e_listidx), lidx);
|
|
||||||
goto on_error;
|
|
||||||
}
|
|
||||||
tv = STACK_TV_BOT(-3);
|
tv = STACK_TV_BOT(-3);
|
||||||
if (lidx < list->lv_len)
|
SOURCING_LNUM = iptr->isn_lnum;
|
||||||
|
if (dest_type == VAR_ANY)
|
||||||
{
|
{
|
||||||
listitem_T *li = list_find(list, lidx);
|
dest_type = tv_dest->v_type;
|
||||||
|
if (dest_type == VAR_DICT)
|
||||||
|
status = do_2string(tv_idx, TRUE);
|
||||||
|
else if (dest_type == VAR_LIST
|
||||||
|
&& tv_idx->v_type != VAR_NUMBER)
|
||||||
|
{
|
||||||
|
emsg(_(e_number_exp));
|
||||||
|
status = FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (dest_type != tv_dest->v_type)
|
||||||
|
{
|
||||||
|
// just in case, should be OK
|
||||||
|
semsg(_(e_expected_str_but_got_str),
|
||||||
|
vartype_name(dest_type),
|
||||||
|
vartype_name(tv_dest->v_type));
|
||||||
|
status = FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
if (error_if_locked(li->li_tv.v_lock,
|
if (status == OK && dest_type == VAR_LIST)
|
||||||
|
{
|
||||||
|
varnumber_T lidx = tv_idx->vval.v_number;
|
||||||
|
list_T *list = tv_dest->vval.v_list;
|
||||||
|
|
||||||
|
if (list == NULL)
|
||||||
|
{
|
||||||
|
emsg(_(e_list_not_set));
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
|
if (lidx < 0 && list->lv_len + lidx >= 0)
|
||||||
|
// negative index is relative to the end
|
||||||
|
lidx = list->lv_len + lidx;
|
||||||
|
if (lidx < 0 || lidx > list->lv_len)
|
||||||
|
{
|
||||||
|
semsg(_(e_listidx), lidx);
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
|
if (lidx < list->lv_len)
|
||||||
|
{
|
||||||
|
listitem_T *li = list_find(list, lidx);
|
||||||
|
|
||||||
|
if (error_if_locked(li->li_tv.v_lock,
|
||||||
e_cannot_change_list_item))
|
e_cannot_change_list_item))
|
||||||
goto failed;
|
goto on_error;
|
||||||
// overwrite existing list item
|
// overwrite existing list item
|
||||||
clear_tv(&li->li_tv);
|
clear_tv(&li->li_tv);
|
||||||
li->li_tv = *tv;
|
li->li_tv = *tv;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (error_if_locked(list->lv_lock,
|
||||||
|
e_cannot_change_list))
|
||||||
|
goto on_error;
|
||||||
|
// append to list, only fails when out of memory
|
||||||
|
if (list_append_tv(list, tv) == FAIL)
|
||||||
|
goto failed;
|
||||||
|
clear_tv(tv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (status == OK && dest_type == VAR_DICT)
|
||||||
|
{
|
||||||
|
char_u *key = tv_idx->vval.v_string;
|
||||||
|
dict_T *dict = tv_dest->vval.v_dict;
|
||||||
|
dictitem_T *di;
|
||||||
|
|
||||||
|
SOURCING_LNUM = iptr->isn_lnum;
|
||||||
|
if (dict == NULL)
|
||||||
|
{
|
||||||
|
emsg(_(e_dictionary_not_set));
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
|
if (key == NULL)
|
||||||
|
key = (char_u *)"";
|
||||||
|
di = dict_find(dict, key, -1);
|
||||||
|
if (di != NULL)
|
||||||
|
{
|
||||||
|
if (error_if_locked(di->di_tv.v_lock,
|
||||||
|
e_cannot_change_dict_item))
|
||||||
|
goto on_error;
|
||||||
|
// overwrite existing value
|
||||||
|
clear_tv(&di->di_tv);
|
||||||
|
di->di_tv = *tv;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (error_if_locked(dict->dv_lock,
|
||||||
|
e_cannot_change_dict))
|
||||||
|
goto on_error;
|
||||||
|
// add to dict, only fails when out of memory
|
||||||
|
if (dict_add_tv(dict, (char *)key, tv) == FAIL)
|
||||||
|
goto failed;
|
||||||
|
clear_tv(tv);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (error_if_locked(list->lv_lock,
|
status = FAIL;
|
||||||
e_cannot_change_list))
|
semsg(_(e_cannot_index_str), vartype_name(dest_type));
|
||||||
goto failed;
|
|
||||||
// append to list, only fails when out of memory
|
|
||||||
if (list_append_tv(list, tv) == FAIL)
|
|
||||||
goto failed;
|
|
||||||
clear_tv(tv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_tv(tv_idx);
|
clear_tv(tv_idx);
|
||||||
clear_tv(tv_list);
|
clear_tv(tv_dest);
|
||||||
ectx.ec_stack.ga_len -= 3;
|
ectx.ec_stack.ga_len -= 3;
|
||||||
}
|
if (status == FAIL)
|
||||||
break;
|
|
||||||
|
|
||||||
// store value in dict variable
|
|
||||||
case ISN_STOREDICT:
|
|
||||||
{
|
|
||||||
typval_T *tv_key = STACK_TV_BOT(-2);
|
|
||||||
char_u *key = tv_key->vval.v_string;
|
|
||||||
typval_T *tv_dict = STACK_TV_BOT(-1);
|
|
||||||
dict_T *dict = tv_dict->vval.v_dict;
|
|
||||||
dictitem_T *di;
|
|
||||||
|
|
||||||
SOURCING_LNUM = iptr->isn_lnum;
|
|
||||||
if (dict == NULL)
|
|
||||||
{
|
{
|
||||||
emsg(_(e_dictionary_not_set));
|
clear_tv(tv);
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
if (key == NULL)
|
|
||||||
key = (char_u *)"";
|
|
||||||
tv = STACK_TV_BOT(-3);
|
|
||||||
di = dict_find(dict, key, -1);
|
|
||||||
if (di != NULL)
|
|
||||||
{
|
|
||||||
if (error_if_locked(di->di_tv.v_lock,
|
|
||||||
e_cannot_change_dict_item))
|
|
||||||
goto failed;
|
|
||||||
// overwrite existing value
|
|
||||||
clear_tv(&di->di_tv);
|
|
||||||
di->di_tv = *tv;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (error_if_locked(dict->dv_lock,
|
|
||||||
e_cannot_change_dict))
|
|
||||||
goto failed;
|
|
||||||
// add to dict, only fails when out of memory
|
|
||||||
if (dict_add_tv(dict, (char *)key, tv) == FAIL)
|
|
||||||
goto failed;
|
|
||||||
clear_tv(tv);
|
|
||||||
}
|
|
||||||
clear_tv(tv_key);
|
|
||||||
clear_tv(tv_dict);
|
|
||||||
ectx.ec_stack.ga_len -= 3;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -2921,31 +2987,9 @@ call_def_function(
|
|||||||
|
|
||||||
case ISN_2STRING:
|
case ISN_2STRING:
|
||||||
case ISN_2STRING_ANY:
|
case ISN_2STRING_ANY:
|
||||||
{
|
if (do_2string(STACK_TV_BOT(iptr->isn_arg.number),
|
||||||
char_u *str;
|
iptr->isn_type == ISN_2STRING_ANY) == FAIL)
|
||||||
|
goto on_error;
|
||||||
tv = STACK_TV_BOT(iptr->isn_arg.number);
|
|
||||||
if (tv->v_type != VAR_STRING)
|
|
||||||
{
|
|
||||||
if (iptr->isn_type == ISN_2STRING_ANY)
|
|
||||||
{
|
|
||||||
switch (tv->v_type)
|
|
||||||
{
|
|
||||||
case VAR_SPECIAL:
|
|
||||||
case VAR_BOOL:
|
|
||||||
case VAR_NUMBER:
|
|
||||||
case VAR_FLOAT:
|
|
||||||
case VAR_BLOB: break;
|
|
||||||
default: to_string_error(tv->v_type);
|
|
||||||
goto on_error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
str = typval_tostring(tv);
|
|
||||||
clear_tv(tv);
|
|
||||||
tv->v_type = VAR_STRING;
|
|
||||||
tv->vval.v_string = str;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ISN_RANGE:
|
case ISN_RANGE:
|
||||||
@@ -3462,12 +3506,20 @@ ex_disassemble(exarg_T *eap)
|
|||||||
iptr->isn_arg.storenr.stnr_idx);
|
iptr->isn_arg.storenr.stnr_idx);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ISN_STORELIST:
|
case ISN_STOREINDEX:
|
||||||
smsg("%4d STORELIST", current);
|
switch (iptr->isn_arg.vartype)
|
||||||
break;
|
{
|
||||||
|
case VAR_LIST:
|
||||||
case ISN_STOREDICT:
|
smsg("%4d STORELIST", current);
|
||||||
smsg("%4d STOREDICT", current);
|
break;
|
||||||
|
case VAR_DICT:
|
||||||
|
smsg("%4d STOREDICT", current);
|
||||||
|
break;
|
||||||
|
case VAR_ANY:
|
||||||
|
smsg("%4d STOREINDEX", current);
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// constants
|
// constants
|
||||||
|
Reference in New Issue
Block a user