1
0
forked from aniani/vim

patch 8.2.2449: Vim9: flatten() always changes the list type

Problem:    Vim9: flatten() always changes the list type.
Solution:   Disallow using flatten() and add flattennew().
This commit is contained in:
Bram Moolenaar 2021-02-01 20:14:51 +01:00
parent 9d20daffc2
commit 3b69006973
10 changed files with 98 additions and 14 deletions

View File

@ -2549,6 +2549,8 @@ finddir({name} [, {path} [, {count}]])
findfile({name} [, {path} [, {count}]])
String find file {name} in {path}
flatten({list} [, {maxdepth}]) List flatten {list} up to {maxdepth} levels
flattennew({list} [, {maxdepth}])
List flatten a copy of {list}
float2nr({expr}) Number convert Float {expr} to a Number
floor({expr}) Float round {expr} down
fmod({expr1}, {expr2}) Float remainder of {expr1} / {expr2}
@ -4712,8 +4714,10 @@ flatten({list} [, {maxdepth}]) *flatten()*
Flatten {list} up to {maxdepth} levels. Without {maxdepth}
the result is a |List| without nesting, as if {maxdepth} is
a very large number.
The {list} is changed in place, make a copy first if you do
The {list} is changed in place, use |flattennew()| if you do
not want that.
In Vim9 script flatten() cannot be used, you must always use
|flattennew()|.
*E900*
{maxdepth} means how deep in nested lists changes are made.
{list} is not modified when {maxdepth} is 0.
@ -4727,6 +4731,10 @@ flatten({list} [, {maxdepth}]) *flatten()*
:echo flatten([1, [2, [3, 4]], 5], 1)
< [1, 2, [3, 4], 5]
flattennew({list} [, {maxdepth}]) *flattennew()*
Like |flatten()| but first make a copy of {list}.
float2nr({expr}) *float2nr()*
Convert {expr} to a Number by omitting the part after the
decimal point.

View File

@ -665,6 +665,7 @@ List manipulation: *list-functions*
count() count number of times a value appears in a List
repeat() repeat a List multiple times
flatten() flatten a List
flattennew() flatten a copy of a List
Dictionary manipulation: *dict-functions*
get() get an entry without an error for a wrong key

View File

@ -351,3 +351,5 @@ EXTERN char e_cannot_change_arglist_recursively[]
INIT(= N_("E1156: Cannot change the argument list recursively"));
EXTERN char e_missing_return_type[]
INIT(= N_("E1157: Missing return type"));
EXTERN char e_cannot_use_flatten_in_vim9_script[]
INIT(= N_("E1158: Cannot use flatten() in Vim9 script"));

View File

@ -954,6 +954,8 @@ static funcentry_T global_functions[] =
ret_string, f_findfile},
{"flatten", 1, 2, FEARG_1, NULL,
ret_list_any, f_flatten},
{"flattennew", 1, 2, FEARG_1, NULL,
ret_list_any, f_flattennew},
{"float2nr", 1, 1, FEARG_1, NULL,
ret_number, FLOAT_FUNC(f_float2nr)},
{"floor", 1, 1, FEARG_1, NULL,

View File

@ -740,7 +740,7 @@ list_insert(list_T *l, listitem_T *ni, listitem_T *item)
* It does nothing if "maxdepth" is 0.
* Returns FAIL when out of memory.
*/
static int
static void
list_flatten(list_T *list, long maxdepth)
{
listitem_T *item;
@ -748,7 +748,7 @@ list_flatten(list_T *list, long maxdepth)
int n;
if (maxdepth == 0)
return OK;
return;
CHECK_LIST_MATERIALIZE(list);
n = 0;
@ -757,7 +757,7 @@ list_flatten(list_T *list, long maxdepth)
{
fast_breakcheck();
if (got_int)
return FAIL;
return;
if (item->li_tv.v_type == VAR_LIST)
{
@ -765,7 +765,7 @@ list_flatten(list_T *list, long maxdepth)
vimlist_remove(list, item, item);
if (list_extend(list, item->li_tv.vval.v_list, next) == FAIL)
return FAIL;
return;
clear_tv(&item->li_tv);
tofree = item;
@ -787,15 +787,13 @@ list_flatten(list_T *list, long maxdepth)
item = item->li_next;
}
}
return OK;
}
/*
* "flatten(list[, {maxdepth}])" function
* "flatten()" and "flattennew()" functions
*/
void
f_flatten(typval_T *argvars, typval_T *rettv)
static void
flatten_common(typval_T *argvars, typval_T *rettv, int make_copy)
{
list_T *l;
long maxdepth;
@ -822,10 +820,48 @@ f_flatten(typval_T *argvars, typval_T *rettv)
}
l = argvars[0].vval.v_list;
if (l != NULL && !value_check_lock(l->lv_lock,
(char_u *)N_("flatten() argument"), TRUE)
&& list_flatten(l, maxdepth) == OK)
copy_tv(&argvars[0], rettv);
rettv->v_type = VAR_LIST;
rettv->vval.v_list = l;
if (l == NULL)
return;
if (make_copy)
{
l = list_copy(l, TRUE, get_copyID());
rettv->vval.v_list = l;
if (l == NULL)
return;
}
else
{
if (value_check_lock(l->lv_lock,
(char_u *)N_("flatten() argument"), TRUE))
return;
++l->lv_refcount;
}
list_flatten(l, maxdepth);
}
/*
* "flatten(list[, {maxdepth}])" function
*/
void
f_flatten(typval_T *argvars, typval_T *rettv)
{
if (in_vim9script())
emsg(_(e_cannot_use_flatten_in_vim9_script));
else
flatten_common(argvars, rettv, FALSE);
}
/*
* "flattennew(list[, {maxdepth}])" function
*/
void
f_flattennew(typval_T *argvars, typval_T *rettv)
{
flatten_common(argvars, rettv, TRUE);
}
/*

View File

@ -31,6 +31,7 @@ int list_append_number(list_T *l, varnumber_T n);
int list_insert_tv(list_T *l, typval_T *tv, listitem_T *item);
void list_insert(list_T *l, listitem_T *ni, listitem_T *item);
void f_flatten(typval_T *argvars, typval_T *rettv);
void f_flattennew(typval_T *argvars, typval_T *rettv);
int list_extend(list_T *l1, list_T *l2, listitem_T *bef);
int list_concat(list_T *l1, list_T *l2, typval_T *tv);
list_T *list_slice(list_T *ol, long n1, long n2);

View File

@ -81,4 +81,13 @@ func Test_flatten()
call assert_equal([2, l:x], l:y)
endfunc
func Test_flattennew()
let l = [1, [2, [3, 4]], 5]
call assert_equal([1, 2, 3, 4, 5], flattennew(l))
call assert_equal([1, [2, [3, 4]], 5], l)
call assert_equal([1, 2, [3, 4], 5], flattennew(l, 1))
call assert_equal([1, [2, [3, 4]], 5], l)
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@ -382,6 +382,23 @@ def Test_findfile()
CheckDefExecFailure(['echo findfile("")'], 'E1142:')
enddef
def Test_flattennew()
var lines =<< trim END
var l = [1, [2, [3, 4]], 5]
call assert_equal([1, 2, 3, 4, 5], flattennew(l))
call assert_equal([1, [2, [3, 4]], 5], l)
call assert_equal([1, 2, [3, 4], 5], flattennew(l, 1))
call assert_equal([1, [2, [3, 4]], 5], l)
END
CheckDefAndScriptSuccess(lines)
lines =<< trim END
echo flatten([1, 2, 3])
END
CheckDefAndScriptFailure(lines, 'E1158:')
enddef
def Test_fnamemodify()
CheckDefSuccess(['echo fnamemodify(test_null_string(), ":p")'])
CheckDefSuccess(['echo fnamemodify("", ":p")'])

View File

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

View File

@ -2900,6 +2900,12 @@ compile_call(
idx = find_internal_func(name);
if (idx >= 0)
{
if (STRCMP(name, "flatten") == 0)
{
emsg(_(e_cannot_use_flatten_in_vim9_script));
goto theend;
}
if (STRCMP(name, "add") == 0 && argcount == 2)
{
garray_T *stack = &cctx->ctx_type_stack;