summaryrefslogtreecommitdiffstats
path: root/src/list.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/list.c')
-rw-r--r--src/list.c81
1 files changed, 55 insertions, 26 deletions
diff --git a/src/list.c b/src/list.c
index b50cb03c98..e9f1ae3206 100644
--- a/src/list.c
+++ b/src/list.c
@@ -2325,7 +2325,7 @@ f_uniq(typval_T *argvars, typval_T *rettv)
}
/*
- * Handle one item for map() and filter().
+ * Handle one item for map(), filter(), foreach().
* Sets v:val to "tv". Caller must set v:key.
*/
int
@@ -2341,6 +2341,17 @@ filter_map_one(
int retval = FAIL;
copy_tv(tv, get_vim_var_tv(VV_VAL));
+
+ newtv->v_type = VAR_UNKNOWN;
+ if (filtermap == FILTERMAP_FOREACH && expr->v_type == VAR_STRING)
+ {
+ // foreach() is not limited to an expression
+ do_cmdline_cmd(expr->vval.v_string);
+ if (!did_emsg)
+ retval = OK;
+ goto theend;
+ }
+
argv[0] = *get_vim_var_tv(VV_KEY);
argv[1] = *get_vim_var_tv(VV_VAL);
if (eval_expr_typval(expr, FALSE, argv, 2, fc, newtv) == FAIL)
@@ -2360,6 +2371,8 @@ filter_map_one(
if (error)
goto theend;
}
+ else if (filtermap == FILTERMAP_FOREACH)
+ clear_tv(newtv);
retval = OK;
theend:
clear_tv(get_vim_var_tv(VV_VAL));
@@ -2367,8 +2380,8 @@ theend:
}
/*
- * Implementation of map() and filter() for a List. Apply "expr" to every item
- * in List "l" and return the result in "rettv".
+ * Implementation of map(), filter(), foreach() for a List. Apply "expr" to
+ * every item in List "l" and return the result in "rettv".
*/
static void
list_filter_map(
@@ -2421,7 +2434,8 @@ list_filter_map(
int stride = l->lv_u.nonmat.lv_stride;
// List from range(): loop over the numbers
- if (filtermap != FILTERMAP_MAPNEW)
+ // NOTE: foreach() returns the range_list_item
+ if (filtermap != FILTERMAP_MAPNEW && filtermap != FILTERMAP_FOREACH)
{
l->lv_first = NULL;
l->lv_u.mat.lv_last = NULL;
@@ -2444,27 +2458,30 @@ list_filter_map(
clear_tv(&newtv);
break;
}
- if (filtermap != FILTERMAP_FILTER)
+ if (filtermap != FILTERMAP_FOREACH)
{
- if (filtermap == FILTERMAP_MAP && argtype != NULL
+ if (filtermap != FILTERMAP_FILTER)
+ {
+ if (filtermap == FILTERMAP_MAP && argtype != NULL
&& check_typval_arg_type(
- argtype->tt_member, &newtv,
- func_name, 0) == FAIL)
+ argtype->tt_member, &newtv,
+ func_name, 0) == FAIL)
+ {
+ clear_tv(&newtv);
+ break;
+ }
+ // map(), mapnew(): always append the new value to the
+ // list
+ if (list_append_tv_move(filtermap == FILTERMAP_MAP
+ ? l : l_ret, &newtv) == FAIL)
+ break;
+ }
+ else if (!rem)
{
- clear_tv(&newtv);
- break;
+ // filter(): append the list item value when not rem
+ if (list_append_tv_move(l, &tv) == FAIL)
+ break;
}
- // map(), mapnew(): always append the new value to the
- // list
- if (list_append_tv_move(filtermap == FILTERMAP_MAP
- ? l : l_ret, &newtv) == FAIL)
- break;
- }
- else if (!rem)
- {
- // filter(): append the list item value when not rem
- if (list_append_tv_move(l, &tv) == FAIL)
- break;
}
val += stride;
@@ -2508,7 +2525,7 @@ list_filter_map(
break;
}
else if (filtermap == FILTERMAP_FILTER && rem)
- listitem_remove(l, li);
+ listitem_remove(l, li);
++idx;
}
}
@@ -2519,7 +2536,7 @@ list_filter_map(
}
/*
- * Implementation of map() and filter().
+ * Implementation of map(), filter() and foreach().
*/
static void
filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap)
@@ -2527,16 +2544,19 @@ filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap)
typval_T *expr;
char *func_name = filtermap == FILTERMAP_MAP ? "map()"
: filtermap == FILTERMAP_MAPNEW ? "mapnew()"
- : "filter()";
+ : filtermap == FILTERMAP_FILTER ? "filter()"
+ : "foreach()";
char_u *arg_errmsg = (char_u *)(filtermap == FILTERMAP_MAP
? N_("map() argument")
: filtermap == FILTERMAP_MAPNEW
? N_("mapnew() argument")
- : N_("filter() argument"));
+ : filtermap == FILTERMAP_FILTER
+ ? N_("filter() argument")
+ : N_("foreach() argument"));
int save_did_emsg;
type_T *type = NULL;
- // map() and filter() return the first argument, also on failure.
+ // map(), filter(), foreach() return the first argument, also on failure.
if (filtermap != FILTERMAP_MAPNEW && argvars[0].v_type != VAR_STRING)
copy_tv(&argvars[0], rettv);
@@ -2630,6 +2650,15 @@ f_mapnew(typval_T *argvars, typval_T *rettv)
}
/*
+ * "foreach()" function
+ */
+ void
+f_foreach(typval_T *argvars, typval_T *rettv)
+{
+ filter_map(argvars, rettv, FILTERMAP_FOREACH);
+}
+
+/*
* "add(list, item)" function
*/
static void