summaryrefslogtreecommitdiff
path: root/src/list.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-06-01 18:39:20 +0200
committerBram Moolenaar <Bram@vim.org>2020-06-01 18:39:20 +0200
commit85629985b71035608a37ba3bde86968481490d46 (patch)
tree5970b7cc5eb33369ad8ee0337884e781fba1dfea /src/list.c
parente8f5ec0d30b629d7166f0ad03434065d8bc822df (diff)
downloadvim-git-85629985b71035608a37ba3bde86968481490d46.tar.gz
patch 8.2.0878: no reduce() functionv8.2.0878
Problem: No reduce() function. Solution: Add a reduce() function. (closes #5481)
Diffstat (limited to 'src/list.c')
-rw-r--r--src/list.c105
1 files changed, 105 insertions, 0 deletions
diff --git a/src/list.c b/src/list.c
index 7c06cfce5..40a910b1e 100644
--- a/src/list.c
+++ b/src/list.c
@@ -2305,4 +2305,109 @@ f_reverse(typval_T *argvars, typval_T *rettv)
}
}
+/*
+ * "reduce(list, { accumlator, element -> value } [, initial])" function
+ */
+ void
+f_reduce(typval_T *argvars, typval_T *rettv)
+{
+ typval_T accum;
+ char_u *func_name;
+ partial_T *partial = NULL;
+ funcexe_T funcexe;
+ typval_T argv[3];
+
+ if (argvars[0].v_type != VAR_LIST && argvars[0].v_type != VAR_BLOB)
+ {
+ emsg(_(e_listblobreq));
+ return;
+ }
+
+ if (argvars[1].v_type == VAR_FUNC)
+ func_name = argvars[1].vval.v_string;
+ else if (argvars[1].v_type == VAR_PARTIAL)
+ {
+ partial = argvars[1].vval.v_partial;
+ func_name = partial_name(partial);
+ }
+ else
+ func_name = tv_get_string(&argvars[1]);
+ if (*func_name == NUL)
+ return; // type error or empty name
+
+ vim_memset(&funcexe, 0, sizeof(funcexe));
+ funcexe.evaluate = TRUE;
+ funcexe.partial = partial;
+
+ if (argvars[0].v_type == VAR_LIST)
+ {
+ list_T *l = argvars[0].vval.v_list;
+ listitem_T *li = NULL;
+
+ CHECK_LIST_MATERIALIZE(l);
+ if (argvars[2].v_type == VAR_UNKNOWN)
+ {
+ if (l == NULL || l->lv_first == NULL)
+ {
+ semsg(_(e_reduceempty), "List");
+ return;
+ }
+ accum = l->lv_first->li_tv;
+ li = l->lv_first->li_next;
+ }
+ else
+ {
+ accum = argvars[2];
+ if (l != NULL)
+ li = l->lv_first;
+ }
+
+ copy_tv(&accum, rettv);
+ for ( ; li != NULL; li = li->li_next)
+ {
+ argv[0] = accum;
+ argv[1] = li->li_tv;
+ if (call_func(func_name, -1, rettv, 2, argv, &funcexe) == FAIL)
+ return;
+ accum = *rettv;
+ }
+ }
+ else
+ {
+ blob_T *b = argvars[0].vval.v_blob;
+ int i;
+
+ if (argvars[2].v_type == VAR_UNKNOWN)
+ {
+ if (b == NULL || b->bv_ga.ga_len == 0)
+ {
+ semsg(_(e_reduceempty), "Blob");
+ return;
+ }
+ accum.v_type = VAR_NUMBER;
+ accum.vval.v_number = blob_get(b, 0);
+ i = 1;
+ }
+ else
+ {
+ accum = argvars[2];
+ i = 0;
+ }
+
+ copy_tv(&accum, rettv);
+ if (b != NULL)
+ {
+ for ( ; i < b->bv_ga.ga_len; i++)
+ {
+ argv[0] = accum;
+ argv[1].v_type = VAR_NUMBER;
+ argv[1].vval.v_number = blob_get(b, i);
+ if (call_func(func_name, -1, rettv, 2, argv, &funcexe) == FAIL)
+ return;
+ accum = *rettv;
+ }
+ }
+ }
+}
+
#endif // defined(FEAT_EVAL)