patch 9.1.1232: Vim script is missing the tuple data type
Problem: Vim script is missing the tuple data type
Solution: Add support for the tuple data type
(Yegappan Lakshmanan)
closes: #16776
Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 5592471..21ed15e 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -361,6 +361,15 @@
}
/*
+ * Check "type" is a tuple of 'any'.
+ */
+ static int
+arg_tuple_any(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
+{
+ return check_arg_type(&t_tuple_any, type, context);
+}
+
+/*
* Check "type" is a string.
*/
static int
@@ -430,6 +439,42 @@
}
/*
+ * Check "type" is a list of 'any' or a tuple.
+ */
+ static int
+arg_list_or_tuple(
+ type_T *type,
+ type_T *decl_type UNUSED,
+ argcontext_T *context)
+{
+ if (type->tt_type == VAR_LIST
+ || type->tt_type == VAR_TUPLE
+ || type_any_or_unknown(type))
+ return OK;
+ arg_type_mismatch(&t_list_any, type, context->arg_idx + 1);
+ return FAIL;
+}
+
+
+/*
+ * Check "type" is a list of 'any', a tuple or a blob.
+ */
+ static int
+arg_list_or_tuple_or_blob(
+ type_T *type,
+ type_T *decl_type UNUSED,
+ argcontext_T *context)
+{
+ if (type->tt_type == VAR_LIST
+ || type->tt_type == VAR_TUPLE
+ || type->tt_type == VAR_BLOB
+ || type_any_or_unknown(type))
+ return OK;
+ arg_type_mismatch(&t_list_any, type, context->arg_idx + 1);
+ return FAIL;
+}
+
+/*
* Check "type" is a string or a number
*/
static int
@@ -461,7 +506,10 @@
* Check "type" is a buffer or a dict of any
*/
static int
-arg_buffer_or_dict_any(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
+arg_buffer_or_dict_any(
+ type_T *type,
+ type_T *decl_type UNUSED,
+ argcontext_T *context)
{
if (type->tt_type == VAR_STRING
|| type->tt_type == VAR_NUMBER
@@ -490,7 +538,10 @@
* Check "type" is a string or a list of strings.
*/
static int
-arg_string_or_list_string(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
+arg_string_or_list_string(
+ type_T *type,
+ type_T *decl_type UNUSED,
+ argcontext_T *context)
{
if (type->tt_type == VAR_STRING
|| type_any_or_unknown(type))
@@ -512,7 +563,10 @@
* Check "type" is a string or a list of 'any'
*/
static int
-arg_string_or_list_any(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
+arg_string_or_list_any(
+ type_T *type,
+ type_T *decl_type UNUSED,
+ argcontext_T *context)
{
if (type->tt_type == VAR_STRING
|| type->tt_type == VAR_LIST
@@ -526,7 +580,10 @@
* Check "type" is a string or a dict of 'any'
*/
static int
-arg_string_or_dict_any(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
+arg_string_or_dict_any(
+ type_T *type,
+ type_T *decl_type UNUSED,
+ argcontext_T *context)
{
if (type->tt_type == VAR_STRING
|| type->tt_type == VAR_DICT
@@ -540,7 +597,10 @@
* Check "type" is a string or a blob
*/
static int
-arg_string_or_blob(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
+arg_string_or_blob(
+ type_T *type,
+ type_T *decl_type UNUSED,
+ argcontext_T *context)
{
if (type->tt_type == VAR_STRING
|| type->tt_type == VAR_BLOB
@@ -579,7 +639,25 @@
}
/*
- * Check "type" is a list of 'any' or a dict of 'any' or a blob.
+ * Check "type" is a list of 'any', a tuple of 'any' or dict of 'any'.
+ */
+ static int
+arg_list_or_tuple_or_dict(
+ type_T *type,
+ type_T *decl_type UNUSED,
+ argcontext_T *context)
+{
+ if (type->tt_type == VAR_LIST
+ || type->tt_type == VAR_TUPLE
+ || type->tt_type == VAR_DICT
+ || type_any_or_unknown(type))
+ return OK;
+ arg_type_mismatch(&t_list_any, type, context->arg_idx + 1);
+ return FAIL;
+}
+
+/*
+ * Check "type" is a list of 'any', a dict of 'any' or a blob.
* Also check if "type" is modifiable.
*/
static int
@@ -601,7 +679,10 @@
* Check "type" is a list of 'any' or a dict of 'any' or a blob or a string.
*/
static int
-arg_list_or_dict_or_blob_or_string(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
+arg_list_or_dict_or_blob_or_string(
+ type_T *type,
+ type_T *decl_type UNUSED,
+ argcontext_T *context)
{
if (type->tt_type == VAR_LIST
|| type->tt_type == VAR_DICT
@@ -629,11 +710,35 @@
}
/*
+ * Check "type" is a list of 'any', a tuple of 'any', a dict of 'any', a blob
+ * or a string.
+ */
+ static int
+arg_list_tuple_dict_blob_or_string(
+ type_T *type,
+ type_T *decl_type UNUSED,
+ argcontext_T *context)
+{
+ if (type->tt_type == VAR_LIST
+ || type->tt_type == VAR_TUPLE
+ || type->tt_type == VAR_DICT
+ || type->tt_type == VAR_BLOB
+ || type->tt_type == VAR_STRING
+ || type_any_or_unknown(type))
+ return OK;
+ arg_type_mismatch(&t_list_any, type, context->arg_idx + 1);
+ return FAIL;
+}
+
+
+/*
* Check second argument of map(), filter(), foreach().
*/
static int
-check_map_filter_arg2(type_T *type, argcontext_T *context,
- filtermap_T filtermap)
+check_map_filter_arg2(
+ type_T *type,
+ argcontext_T *context,
+ filtermap_T filtermap)
{
type_T *expected_member = NULL;
type_T *(args[2]);
@@ -801,7 +906,10 @@
* Also accept a number, one and zero are accepted.
*/
static int
-arg_string_or_func(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
+arg_string_or_func(
+ type_T *type,
+ type_T *decl_type UNUSED,
+ argcontext_T *context)
{
if (type->tt_type == VAR_STRING
|| type->tt_type == VAR_PARTIAL
@@ -835,12 +943,16 @@
}
/*
- * Check "type" is a list of 'any' or a blob or a string.
+ * Check "type" is a list of 'any', a tuple, a blob or a string.
*/
static int
-arg_string_list_or_blob(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
+arg_string_list_tuple_or_blob(
+ type_T *type,
+ type_T *decl_type UNUSED,
+ argcontext_T *context)
{
if (type->tt_type == VAR_LIST
+ || type->tt_type == VAR_TUPLE
|| type->tt_type == VAR_BLOB
|| type->tt_type == VAR_STRING
|| type_any_or_unknown(type))
@@ -850,12 +962,12 @@
}
/*
- * Check "type" is a modifiable list of 'any' or a blob or a string.
+ * Check "type" is a tuple or a modifiable list of 'any' or a blob or a string.
*/
static int
-arg_string_list_or_blob_mod(type_T *type, type_T *decl_type, argcontext_T *context)
+arg_reverse(type_T *type, type_T *decl_type, argcontext_T *context)
{
- if (arg_string_list_or_blob(type, decl_type, context) == FAIL)
+ if (arg_string_list_tuple_or_blob(type, decl_type, context) == FAIL)
return FAIL;
return arg_type_modifiable(type, context->arg_idx + 1);
}
@@ -901,7 +1013,10 @@
* Must not be used for the first argcheck_T entry.
*/
static int
-arg_same_struct_as_prev(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
+arg_same_struct_as_prev(
+ type_T *type,
+ type_T *decl_type UNUSED,
+ argcontext_T *context)
{
type_T *prev_type = context->arg_types[context->arg_idx - 1].type_curr;
@@ -935,7 +1050,10 @@
* Check "type" is a string or a number or a list
*/
static int
-arg_str_or_nr_or_list(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
+arg_str_or_nr_or_list(
+ type_T *type,
+ type_T *decl_type UNUSED,
+ argcontext_T *context)
{
if (type->tt_type == VAR_STRING
|| type->tt_type == VAR_NUMBER
@@ -950,7 +1068,10 @@
* Check "type" is a dict of 'any' or a string
*/
static int
-arg_dict_any_or_string(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
+arg_dict_any_or_string(
+ type_T *type,
+ type_T *decl_type UNUSED,
+ argcontext_T *context)
{
if (type->tt_type == VAR_DICT
|| type->tt_type == VAR_STRING
@@ -977,14 +1098,15 @@
}
/*
- * Check "type" which is the first argument of get() (blob or list or dict or
- * funcref)
+ * Check "type" which is the first argument of get() (a blob, a list, a tuple,
+ * a dict or a funcref)
*/
static int
arg_get1(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
if (type->tt_type == VAR_BLOB
|| type->tt_type == VAR_LIST
+ || type->tt_type == VAR_TUPLE
|| type->tt_type == VAR_DICT
|| type->tt_type == VAR_FUNC
|| type->tt_type == VAR_PARTIAL
@@ -996,8 +1118,8 @@
}
/*
- * Check "type" which is the first argument of len() (number or string or
- * blob or list or dict)
+ * Check "type" which is the first argument of len() (a string, a number, a
+ * blob, a list, a tuple, a dict or an object)
*/
static int
arg_len1(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
@@ -1006,6 +1128,7 @@
|| type->tt_type == VAR_NUMBER
|| type->tt_type == VAR_BLOB
|| type->tt_type == VAR_LIST
+ || type->tt_type == VAR_TUPLE
|| type->tt_type == VAR_DICT
|| type->tt_type == VAR_OBJECT
|| type_any_or_unknown(type))
@@ -1032,8 +1155,8 @@
}
/*
- * Check "type" which is the first argument of repeat() (string or number or
- * list or any)
+ * Check "type" which is the first argument of repeat() (a string, a number, a
+ * blob, a list, a tuple or any)
*/
static int
arg_repeat1(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
@@ -1042,6 +1165,7 @@
|| type->tt_type == VAR_NUMBER
|| type->tt_type == VAR_BLOB
|| type->tt_type == VAR_LIST
+ || type->tt_type == VAR_TUPLE
|| type_any_or_unknown(type))
return OK;
@@ -1050,13 +1174,14 @@
}
/*
- * Check "type" which is the first argument of slice() (list or blob or string
- * or any)
+ * Check "type" which is the first argument of slice() (a list, a tuple, a
+ * blob, a string or any)
*/
static int
arg_slice1(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
if (type->tt_type == VAR_LIST
+ || type->tt_type == VAR_TUPLE
|| type->tt_type == VAR_BLOB
|| type->tt_type == VAR_STRING
|| type_any_or_unknown(type))
@@ -1067,19 +1192,23 @@
}
/*
- * Check "type" which is the first argument of count() (string or list or dict
- * or any)
+ * Check "type" which is the first argument of count() (a string, a list, a
+ * tuple, a dict or any)
*/
static int
-arg_string_or_list_or_dict(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
+arg_string_list_tuple_or_dict(
+ type_T *type,
+ type_T *decl_type UNUSED,
+ argcontext_T *context)
{
if (type->tt_type == VAR_STRING
|| type->tt_type == VAR_LIST
+ || type->tt_type == VAR_TUPLE
|| type->tt_type == VAR_DICT
|| type_any_or_unknown(type))
return OK;
- semsg(_(e_string_list_or_dict_required_for_argument_nr),
+ semsg(_(e_string_list_tuple_or_dict_required_for_argument_nr),
context->arg_idx + 1);
return FAIL;
}
@@ -1114,11 +1243,12 @@
static argcheck_T arg1_float_or_nr[] = {arg_float_or_nr};
static argcheck_T arg1_job[] = {arg_job};
static argcheck_T arg1_list_any[] = {arg_list_any};
+static argcheck_T arg1_tuple_any[] = {arg_tuple_any};
static argcheck_T arg1_list_number[] = {arg_list_number};
-static argcheck_T arg1_string_or_list_or_blob_mod[] = {arg_string_list_or_blob_mod};
-static argcheck_T arg1_list_or_dict[] = {arg_list_or_dict};
+static argcheck_T arg1_reverse[] = {arg_reverse};
+static argcheck_T arg1_list_or_tuple_or_dict[] = {arg_list_or_tuple_or_dict};
static argcheck_T arg1_list_string[] = {arg_list_string};
-static argcheck_T arg1_string_or_list_or_dict[] = {arg_string_or_list_or_dict};
+static argcheck_T arg1_string_list_tuple_or_dict[] = {arg_string_list_tuple_or_dict};
static argcheck_T arg1_lnum[] = {arg_lnum};
static argcheck_T arg1_number[] = {arg_number};
static argcheck_T arg1_string[] = {arg_string};
@@ -1141,7 +1271,6 @@
static argcheck_T arg2_job_dict[] = {arg_job, arg_dict_any};
static argcheck_T arg2_job_string_or_number[] = {arg_job, arg_string_or_nr};
static argcheck_T arg2_list_any_number[] = {arg_list_any, arg_number};
-static argcheck_T arg2_list_any_string[] = {arg_list_any, arg_string};
static argcheck_T arg2_list_number[] = {arg_list_number, arg_list_number};
static argcheck_T arg2_list_number_bool[] = {arg_list_number, arg_bool};
static argcheck_T arg2_list_string_dict[] = {arg_list_string, arg_dict_any};
@@ -1168,6 +1297,7 @@
static argcheck_T arg2_string_or_list_number[] = {arg_string_or_list_any, arg_number};
static argcheck_T arg2_string_string_or_number[] = {arg_string, arg_string_or_nr};
static argcheck_T arg2_blob_dict[] = {arg_blob, arg_dict_any};
+static argcheck_T arg2_list_or_tuple_string[] = {arg_list_or_tuple, arg_string};
static argcheck_T arg3_any_list_dict[] = {arg_any, arg_list_any, arg_dict_any};
static argcheck_T arg3_buffer_lnum_lnum[] = {arg_buffer, arg_lnum, arg_lnum};
static argcheck_T arg3_buffer_number_number[] = {arg_buffer, arg_number, arg_number};
@@ -1205,7 +1335,7 @@
static argcheck_T arg4_browse[] = {arg_bool, arg_string, arg_string, arg_string};
static argcheck_T arg23_chanexpr[] = {arg_chan_or_job, arg_any, arg_dict_any};
static argcheck_T arg23_chanraw[] = {arg_chan_or_job, arg_string_or_blob, arg_dict_any};
-static argcheck_T arg24_count[] = {arg_string_or_list_or_dict, arg_any, arg_bool, arg_number};
+static argcheck_T arg24_count[] = {arg_string_list_tuple_or_dict, arg_any, arg_bool, arg_number};
static argcheck_T arg13_cursor[] = {arg_cursor1, arg_number, arg_number};
static argcheck_T arg12_deepcopy[] = {arg_any, arg_bool};
static argcheck_T arg12_execute[] = {arg_string_or_list_string, arg_string};
@@ -1215,14 +1345,14 @@
static argcheck_T arg23_get[] = {arg_get1, arg_string_or_nr, arg_any};
static argcheck_T arg14_glob[] = {arg_string, arg_bool, arg_bool, arg_bool};
static argcheck_T arg25_globpath[] = {arg_string, arg_string, arg_bool, arg_bool, arg_bool};
-static argcheck_T arg24_index[] = {arg_list_or_blob, arg_item_of_prev, arg_number, arg_bool};
-static argcheck_T arg23_index[] = {arg_list_or_blob, arg_filter_func, arg_dict_any};
+static argcheck_T arg24_index[] = {arg_list_or_tuple_or_blob, arg_item_of_prev, arg_number, arg_bool};
+static argcheck_T arg23_index[] = {arg_list_or_tuple_or_blob, arg_filter_func, arg_dict_any};
static argcheck_T arg23_insert[] = {arg_list_or_blob, arg_item_of_prev, arg_number};
static argcheck_T arg1_len[] = {arg_len1};
static argcheck_T arg3_libcall[] = {arg_string, arg_string, arg_string_or_nr};
static argcheck_T arg14_maparg[] = {arg_string, arg_string, arg_bool, arg_bool};
static argcheck_T arg2_filter[] = {arg_list_or_dict_or_blob_or_string_mod, arg_filter_func};
-static argcheck_T arg2_foreach[] = {arg_list_or_dict_or_blob_or_string, arg_foreach_func};
+static argcheck_T arg2_foreach[] = {arg_list_tuple_dict_blob_or_string, arg_foreach_func};
static argcheck_T arg2_instanceof[] = {arg_object, varargs_class, NULL };
static argcheck_T arg2_map[] = {arg_list_or_dict_or_blob_or_string_mod, arg_map_func};
static argcheck_T arg2_mapnew[] = {arg_list_or_dict_or_blob_or_string, arg_any};
@@ -1231,7 +1361,7 @@
static argcheck_T arg23_matchstrlist[] = {arg_list_string, arg_string, arg_dict_any};
static argcheck_T arg45_matchbufline[] = {arg_buffer, arg_string, arg_lnum, arg_lnum, arg_dict_any};
static argcheck_T arg119_printf[] = {arg_string_or_nr, arg_any, arg_any, arg_any, arg_any, arg_any, arg_any, arg_any, arg_any, arg_any, arg_any, arg_any, arg_any, arg_any, arg_any, arg_any, arg_any, arg_any, arg_any};
-static argcheck_T arg23_reduce[] = {arg_string_list_or_blob, arg_any, arg_any};
+static argcheck_T arg23_reduce[] = {arg_string_list_tuple_or_blob, arg_any, arg_any};
static argcheck_T arg24_remote_expr[] = {arg_string, arg_string, arg_string, arg_number};
static argcheck_T arg23_remove[] = {arg_list_or_dict_or_blob_mod, arg_remove2, arg_number};
static argcheck_T arg2_repeat[] = {arg_repeat1, arg_number};
@@ -1364,6 +1494,13 @@
return &t_list_list_list_number;
}
static type_T *
+ret_tuple_any(int argcount UNUSED,
+ type2_T *argtypes UNUSED,
+ type_T **decl_type UNUSED)
+{
+ return &t_tuple_any;
+}
+ static type_T *
ret_dict_any(int argcount UNUSED,
type2_T *argtypes UNUSED,
type_T **decl_type UNUSED)
@@ -1457,6 +1594,7 @@
case VAR_STRING: *decl_type = &t_string; break;
case VAR_BLOB: *decl_type = &t_blob; break;
case VAR_LIST: *decl_type = &t_list_any; break;
+ case VAR_TUPLE: *decl_type = &t_tuple_any; break;
default: break;
}
}
@@ -2288,7 +2426,7 @@
ret_number_bool, f_islocked},
{"isnan", 1, 1, FEARG_1, arg1_float_or_nr,
ret_number_bool, MATH_FUNC(f_isnan)},
- {"items", 1, 1, FEARG_1, arg1_string_or_list_or_dict,
+ {"items", 1, 1, FEARG_1, arg1_string_list_tuple_or_dict,
ret_list_items, f_items},
{"job_getchannel", 1, 1, FEARG_1, arg1_job,
ret_channel, JOB_FUNC(f_job_getchannel)},
@@ -2302,7 +2440,7 @@
ret_string, JOB_FUNC(f_job_status)},
{"job_stop", 1, 2, FEARG_1, arg2_job_string_or_number,
ret_number_bool, JOB_FUNC(f_job_stop)},
- {"join", 1, 2, FEARG_1, arg2_list_any_string,
+ {"join", 1, 2, FEARG_1, arg2_list_or_tuple_string,
ret_string, f_join},
{"js_decode", 1, 1, FEARG_1, arg1_string,
ret_any, f_js_decode},
@@ -2334,6 +2472,8 @@
ret_blob, f_list2blob},
{"list2str", 1, 2, FEARG_1, arg2_list_number_bool,
ret_string, f_list2str},
+ {"list2tuple", 1, 1, FEARG_1, arg1_list_any,
+ ret_tuple_any, f_list2tuple},
{"listener_add", 1, 2, FEARG_2, arg2_any_buffer,
ret_number, f_listener_add},
{"listener_flush", 0, 1, FEARG_1, arg1_buffer,
@@ -2392,7 +2532,7 @@
ret_list_any, f_matchstrlist},
{"matchstrpos", 2, 4, FEARG_1, arg24_match_func,
ret_list_any, f_matchstrpos},
- {"max", 1, 1, FEARG_1, arg1_list_or_dict,
+ {"max", 1, 1, FEARG_1, arg1_list_or_tuple_or_dict,
ret_number, f_max},
{"menu_info", 1, 2, FEARG_1, arg2_string,
ret_dict_any,
@@ -2402,7 +2542,7 @@
NULL
#endif
},
- {"min", 1, 1, FEARG_1, arg1_list_or_dict,
+ {"min", 1, 1, FEARG_1, arg1_list_or_tuple_or_dict,
ret_number, f_min},
{"mkdir", 1, 3, FEARG_1, arg3_string_string_number,
ret_number_bool, f_mkdir},
@@ -2588,7 +2728,7 @@
ret_repeat, f_repeat},
{"resolve", 1, 1, FEARG_1, arg1_string,
ret_string, f_resolve},
- {"reverse", 1, 1, FEARG_1, arg1_string_or_list_or_blob_mod,
+ {"reverse", 1, 1, FEARG_1, arg1_reverse,
ret_first_arg, f_reverse},
{"round", 1, 1, FEARG_1, arg1_float_or_nr,
ret_float, f_round},
@@ -2918,6 +3058,8 @@
ret_func_any, f_test_null_partial},
{"test_null_string", 0, 0, 0, NULL,
ret_string, f_test_null_string},
+ {"test_null_tuple", 0, 0, 0, NULL,
+ ret_tuple_any, f_test_null_tuple},
{"test_option_not_set", 1, 1, FEARG_1, arg1_string,
ret_void, f_test_option_not_set},
{"test_override", 2, 2, FEARG_2, arg2_string_number,
@@ -2954,6 +3096,8 @@
ret_string, f_trim},
{"trunc", 1, 1, FEARG_1, arg1_float_or_nr,
ret_float, f_trunc},
+ {"tuple2list", 1, 1, FEARG_1, arg1_tuple_any,
+ ret_list_any, f_tuple2list},
{"type", 1, 1, FEARG_1|FE_X, NULL,
ret_number, f_type},
{"typename", 1, 1, FEARG_1|FE_X, NULL,
@@ -4226,6 +4370,9 @@
n = argvars[0].vval.v_list == NULL
|| argvars[0].vval.v_list->lv_len == 0;
break;
+ case VAR_TUPLE:
+ n = tuple_len(argvars[0].vval.v_tuple) == 0;
+ break;
case VAR_DICT:
n = argvars[0].vval.v_dict == NULL
|| argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
@@ -5263,6 +5410,7 @@
{
listitem_T *li;
list_T *l;
+ tuple_T *tuple;
dictitem_T *di;
dict_T *d;
typval_T *tv = NULL;
@@ -5298,6 +5446,18 @@
tv = &li->li_tv;
}
}
+ else if (argvars[0].v_type == VAR_TUPLE)
+ {
+ if ((tuple = argvars[0].vval.v_tuple) != NULL)
+ {
+ int error = FALSE;
+ long idx;
+
+ idx = (long)tv_get_number_chk(&argvars[1], &error);
+ if (!error)
+ tv = tuple_find(tuple, idx);
+ }
+ }
else if (argvars[0].v_type == VAR_DICT)
{
if ((d = argvars[0].vval.v_dict) != NULL)
@@ -5400,7 +5560,7 @@
}
}
else
- semsg(_(e_argument_of_str_must_be_list_dictionary_or_blob), "get()");
+ semsg(_(e_argument_of_str_must_be_list_tuple_dictionary_or_blob), "get()");
if (tv == NULL)
{
@@ -7811,6 +7971,7 @@
switch (argvars[0].v_type)
{
case VAR_LIST:
+ case VAR_TUPLE:
case VAR_DICT:
case VAR_OBJECT:
case VAR_JOB:
@@ -7837,67 +7998,84 @@
}
/*
- * "index()" function
+ * index() function for a blob
*/
static void
-f_index(typval_T *argvars, typval_T *rettv)
+index_func_blob(typval_T *argvars, typval_T *rettv)
{
- list_T *l;
- listitem_T *item;
+ typval_T tv;
blob_T *b;
- long idx = 0;
+ int start = 0;
+ int error = FALSE;
+ int ic = FALSE;
+
+ b = argvars[0].vval.v_blob;
+ if (b == NULL)
+ return;
+
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ start = tv_get_number_chk(&argvars[2], &error);
+ if (error)
+ return;
+ }
+
+ if (start < 0)
+ {
+ start = blob_len(b) + start;
+ if (start < 0)
+ start = 0;
+ }
+
+ for (int idx = start; idx < blob_len(b); ++idx)
+ {
+ tv.v_type = VAR_NUMBER;
+ tv.vval.v_number = blob_get(b, idx);
+ if (tv_equal(&tv, &argvars[1], ic))
+ {
+ rettv->vval.v_number = idx;
+ return;
+ }
+ }
+}
+
+/*
+ * index() function for a tuple
+ */
+ static void
+index_func_tuple(typval_T *argvars, typval_T *rettv)
+{
+ tuple_T *tuple = argvars[0].vval.v_tuple;
int ic = FALSE;
int error = FALSE;
- rettv->vval.v_number = -1;
-
- if (in_vim9script()
- && (check_for_list_or_blob_arg(argvars, 0) == FAIL
- || (argvars[0].v_type == VAR_BLOB
- && check_for_number_arg(argvars, 1) == FAIL)
- || check_for_opt_number_arg(argvars, 2) == FAIL
- || (argvars[2].v_type != VAR_UNKNOWN
- && check_for_opt_bool_arg(argvars, 3) == FAIL)))
+ if (tuple == NULL)
return;
- if (argvars[0].v_type == VAR_BLOB)
+ int start_idx = 0;
+ if (argvars[2].v_type != VAR_UNKNOWN)
{
- typval_T tv;
- int start = 0;
-
- if (argvars[2].v_type != VAR_UNKNOWN)
- {
- start = tv_get_number_chk(&argvars[2], &error);
- if (error)
- return;
- }
- b = argvars[0].vval.v_blob;
- if (b == NULL)
+ start_idx = tv_get_number_chk(&argvars[2], &error);
+ if (!error && argvars[3].v_type != VAR_UNKNOWN)
+ ic = (int)tv_get_bool_chk(&argvars[3], &error);
+ if (error)
return;
- if (start < 0)
- {
- start = blob_len(b) + start;
- if (start < 0)
- start = 0;
- }
+ }
- for (idx = start; idx < blob_len(b); ++idx)
- {
- tv.v_type = VAR_NUMBER;
- tv.vval.v_number = blob_get(b, idx);
- if (tv_equal(&tv, &argvars[1], ic))
- {
- rettv->vval.v_number = idx;
- return;
- }
- }
- return;
- }
- else if (argvars[0].v_type != VAR_LIST)
- {
- emsg(_(e_list_or_blob_required));
- return;
- }
+ rettv->vval.v_number = index_tuple(tuple, &argvars[1], start_idx, ic);
+}
+
+/*
+ * index() function for a list
+ */
+ static void
+index_func_list(typval_T *argvars, typval_T *rettv)
+{
+ list_T *l;
+ listitem_T *item;
+ long idx = 0;
+ int ic = FALSE;
+ int error = FALSE;
l = argvars[0].vval.v_list;
if (l == NULL)
@@ -7926,11 +8104,38 @@
}
/*
+ * "index()" function
+ */
+ static void
+f_index(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = -1;
+
+ if (in_vim9script()
+ && (check_for_list_or_tuple_or_blob_arg(argvars, 0) == FAIL
+ || (argvars[0].v_type == VAR_BLOB
+ && check_for_number_arg(argvars, 1) == FAIL)
+ || check_for_opt_number_arg(argvars, 2) == FAIL
+ || (argvars[2].v_type != VAR_UNKNOWN
+ && check_for_opt_bool_arg(argvars, 3) == FAIL)))
+ return;
+
+ if (argvars[0].v_type == VAR_BLOB)
+ index_func_blob(argvars, rettv);
+ else if (argvars[0].v_type == VAR_TUPLE)
+ index_func_tuple(argvars, rettv);
+ else if (argvars[0].v_type == VAR_LIST)
+ index_func_list(argvars, rettv);
+ else
+ emsg(_(e_list_or_blob_required));
+}
+
+/*
* Evaluate 'expr' with the v:key and v:val arguments and return the result.
* The expression is expected to return a boolean value. The caller should set
* the VV_KEY and VV_VAL vim variables before calling this function.
*/
- static int
+ int
indexof_eval_expr(typval_T *expr)
{
typval_T argv[3];
@@ -8053,7 +8258,7 @@
rettv->vval.v_number = -1;
- if (check_for_list_or_blob_arg(argvars, 0) == FAIL
+ if (check_for_list_or_tuple_or_blob_arg(argvars, 0) == FAIL
|| check_for_string_or_func_arg(argvars, 1) == FAIL
|| check_for_opt_dict_arg(argvars, 2) == FAIL)
return;
@@ -8079,6 +8284,9 @@
if (argvars[0].v_type == VAR_BLOB)
rettv->vval.v_number = indexof_blob(argvars[0].vval.v_blob, startidx,
&argvars[1]);
+ else if (argvars[0].v_type == VAR_TUPLE)
+ rettv->vval.v_number = indexof_tuple(argvars[0].vval.v_tuple, startidx,
+ &argvars[1]);
else
rettv->vval.v_number = indexof_list(argvars[0].vval.v_list, startidx,
&argvars[1]);
@@ -8488,6 +8696,9 @@
case VAR_LIST:
rettv->vval.v_number = list_len(argvars[0].vval.v_list);
break;
+ case VAR_TUPLE:
+ rettv->vval.v_number = tuple_len(argvars[0].vval.v_tuple);
+ break;
case VAR_DICT:
rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
break;
@@ -9229,7 +9440,8 @@
varnumber_T i;
int error = FALSE;
- if (in_vim9script() && check_for_list_or_dict_arg(argvars, 0) == FAIL)
+ if (in_vim9script() &&
+ check_for_list_or_tuple_or_dict_arg(argvars, 0) == FAIL)
return;
if (argvars[0].v_type == VAR_LIST)
@@ -9271,6 +9483,12 @@
}
}
}
+ else if (argvars[0].v_type == VAR_TUPLE)
+ {
+ n = tuple_max_min(argvars[0].vval.v_tuple, domax, &error);
+ if (error)
+ return;
+ }
else if (argvars[0].v_type == VAR_DICT)
{
dict_T *d;
@@ -10076,83 +10294,114 @@
}
/*
- * "repeat()" function
+ * Repeat the list "l" "n" times and set "rettv" to the new list.
*/
static void
-f_repeat(typval_T *argvars, typval_T *rettv)
+repeat_list(list_T *l, int n, typval_T *rettv)
+{
+ if (rettv_list_alloc(rettv) == FAIL
+ || l == NULL
+ || n <= 0)
+ return;
+
+ while (n-- > 0)
+ if (list_extend(rettv->vval.v_list, l, NULL) == FAIL)
+ break;
+}
+
+/*
+ * Repeat the blob "b" "n" times and set "rettv" to the new blob.
+ */
+ static void
+repeat_blob(typval_T *blob_tv, int n, typval_T *rettv)
+{
+ int slen;
+ int len;
+ int i;
+ blob_T *blob = blob_tv->vval.v_blob;
+
+ if (rettv_blob_alloc(rettv) == FAIL
+ || blob == NULL
+ || n <= 0)
+ return;
+
+ slen = blob->bv_ga.ga_len;
+ len = (int)slen * n;
+ if (len <= 0)
+ return;
+
+ if (ga_grow(&rettv->vval.v_blob->bv_ga, len) == FAIL)
+ return;
+
+ rettv->vval.v_blob->bv_ga.ga_len = len;
+
+ for (i = 0; i < slen; ++i)
+ if (blob_get(blob, i) != 0)
+ break;
+
+ if (i == slen)
+ // No need to copy since all bytes are already zero
+ return;
+
+ for (i = 0; i < n; ++i)
+ blob_set_range(rettv->vval.v_blob,
+ (long)i * slen, ((long)i + 1) * slen - 1, blob_tv);
+}
+
+/*
+ * Repeat the string "str" "n" times and set "rettv" to the new string.
+ */
+ static void
+repeat_string(typval_T *str_tv, int n, typval_T *rettv)
{
char_u *p;
- varnumber_T n;
int slen;
int len;
char_u *r;
int i;
+ p = tv_get_string(str_tv);
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+
+ slen = (int)STRLEN(p);
+ len = slen * n;
+ if (len <= 0)
+ return;
+
+ r = alloc(len + 1);
+ if (r == NULL)
+ return;
+
+ for (i = 0; i < n; i++)
+ mch_memmove(r + i * slen, p, (size_t)slen);
+ r[len] = NUL;
+
+ rettv->vval.v_string = r;
+}
+
+/*
+ * "repeat()" function
+ */
+ static void
+f_repeat(typval_T *argvars, typval_T *rettv)
+{
+ varnumber_T n;
+
if (in_vim9script()
- && (check_for_string_or_number_or_list_or_blob_arg(argvars, 0)
- == FAIL
+ && (check_for_repeat_func_arg(argvars, 0) == FAIL
|| check_for_number_arg(argvars, 1) == FAIL))
return;
n = tv_get_number(&argvars[1]);
if (argvars[0].v_type == VAR_LIST)
- {
- if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
- while (n-- > 0)
- if (list_extend(rettv->vval.v_list,
- argvars[0].vval.v_list, NULL) == FAIL)
- break;
- }
+ repeat_list(argvars[0].vval.v_list, n, rettv);
+ else if (argvars[0].v_type == VAR_TUPLE)
+ tuple_repeat(argvars[0].vval.v_tuple, n, rettv);
else if (argvars[0].v_type == VAR_BLOB)
- {
- if (rettv_blob_alloc(rettv) == FAIL
- || argvars[0].vval.v_blob == NULL
- || n <= 0)
- return;
-
- slen = argvars[0].vval.v_blob->bv_ga.ga_len;
- len = (int)slen * n;
- if (len <= 0)
- return;
-
- if (ga_grow(&rettv->vval.v_blob->bv_ga, len) == FAIL)
- return;
-
- rettv->vval.v_blob->bv_ga.ga_len = len;
-
- for (i = 0; i < slen; ++i)
- if (blob_get(argvars[0].vval.v_blob, i) != 0)
- break;
-
- if (i == slen)
- // No need to copy since all bytes are already zero
- return;
-
- for (i = 0; i < n; ++i)
- blob_set_range(rettv->vval.v_blob,
- (long)i * slen, ((long)i + 1) * slen - 1, argvars);
- }
+ repeat_blob(&argvars[0], n, rettv);
else
- {
- p = tv_get_string(&argvars[0]);
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = NULL;
-
- slen = (int)STRLEN(p);
- len = slen * n;
- if (len <= 0)
- return;
-
- r = alloc(len + 1);
- if (r != NULL)
- {
- for (i = 0; i < n; i++)
- mch_memmove(r + i * slen, p, (size_t)slen);
- r[len] = NUL;
- }
-
- rettv->vval.v_string = r;
- }
+ repeat_string(&argvars[0], n, rettv);
}
#define SP_NOMOVE 0x01 // don't move cursor
@@ -12191,6 +12440,7 @@
case VAR_PARTIAL:
case VAR_FUNC: n = VAR_TYPE_FUNC; break;
case VAR_LIST: n = VAR_TYPE_LIST; break;
+ case VAR_TUPLE: n = VAR_TYPE_TUPLE; break;
case VAR_DICT: n = VAR_TYPE_DICT; break;
case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
case VAR_BOOL: n = VAR_TYPE_BOOL; break;