aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval/funcs.c
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2023-08-17 14:12:24 +0800
committerzeertzjq <zeertzjq@outlook.com>2023-08-17 15:37:32 +0800
commitb193674b4a1dce1b348489fa13dd42254b9a3ebb (patch)
tree0f2ba228c173892c16b082236f0eb124ad02fab8 /src/nvim/eval/funcs.c
parentc5576fcc8003280489c0aa0323a966e6de33e31f (diff)
downloadrneovim-b193674b4a1dce1b348489fa13dd42254b9a3ebb.tar.gz
rneovim-b193674b4a1dce1b348489fa13dd42254b9a3ebb.tar.bz2
rneovim-b193674b4a1dce1b348489fa13dd42254b9a3ebb.zip
vim-patch:partial:8.2.3849: functions implementing reduce and map are too long
Problem: Functions implementing reduce and map are too long. Solution: Use a function for each type of value. Add a few more test cases and add to the help. (Yegappan Lakshmanan, closes vim/vim#9370) https://github.com/vim/vim/commit/389b72196e6aaeafe3f907c73d271f2c6b931140 Partial port as this doesn't include handling for non-materialized List. Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Diffstat (limited to 'src/nvim/eval/funcs.c')
-rw-r--r--src/nvim/eval/funcs.c241
1 files changed, 138 insertions, 103 deletions
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index bf11fdf029..d5d9726397 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -6171,17 +6171,150 @@ static void f_reverse(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
}
+/// reduce() on a List
+static void reduce_list(typval_T *argvars, const char *func_name, funcexe_T *funcexe,
+ typval_T *rettv)
+{
+ list_T *const l = argvars[0].vval.v_list;
+ const int called_emsg_start = called_emsg;
+
+ typval_T initial;
+ const listitem_T *li = NULL;
+ if (argvars[2].v_type == VAR_UNKNOWN) {
+ if (tv_list_len(l) == 0) {
+ semsg(_(e_reduceempty), "List");
+ return;
+ }
+ const listitem_T *const first = tv_list_first(l);
+ initial = *TV_LIST_ITEM_TV(first);
+ li = TV_LIST_ITEM_NEXT(l, first);
+ } else {
+ initial = argvars[2];
+ li = tv_list_first(l);
+ }
+
+ tv_copy(&initial, rettv);
+
+ if (l == NULL) {
+ return;
+ }
+
+ const VarLockStatus prev_locked = tv_list_locked(l);
+
+ tv_list_set_lock(l, VAR_FIXED); // disallow the list changing here
+ for (; li != NULL; li = TV_LIST_ITEM_NEXT(l, li)) {
+ typval_T argv[3];
+ argv[0] = *rettv;
+ argv[1] = *TV_LIST_ITEM_TV(li);
+ rettv->v_type = VAR_UNKNOWN;
+ const int r = call_func(func_name, -1, rettv, 2, argv, funcexe);
+ tv_clear(&argv[0]);
+ if (r == FAIL || called_emsg != called_emsg_start) {
+ break;
+ }
+ }
+ tv_list_set_lock(l, prev_locked);
+}
+
+/// reduce() on a String
+static void reduce_string(typval_T *argvars, const char *func_name, funcexe_T *funcexe,
+ typval_T *rettv)
+{
+ const char *p = tv_get_string(&argvars[0]);
+ int len;
+ const int called_emsg_start = called_emsg;
+
+ if (argvars[2].v_type == VAR_UNKNOWN) {
+ if (*p == NUL) {
+ semsg(_(e_reduceempty), "String");
+ return;
+ }
+ len = utfc_ptr2len(p);
+ *rettv = (typval_T){
+ .v_type = VAR_STRING,
+ .v_lock = VAR_UNLOCKED,
+ .vval.v_string = xstrnsave(p, (size_t)len),
+ };
+ p += len;
+ } else if (argvars[2].v_type != VAR_STRING) {
+ semsg(_(e_string_expected_for_argument_nr), 3);
+ return;
+ } else {
+ tv_copy(&argvars[2], rettv);
+ }
+
+ for (; *p != NUL; p += len) {
+ typval_T argv[3];
+ argv[0] = *rettv;
+ len = utfc_ptr2len(p);
+ argv[1] = (typval_T){
+ .v_type = VAR_STRING,
+ .v_lock = VAR_UNLOCKED,
+ .vval.v_string = xstrnsave(p, (size_t)len),
+ };
+ const int r = call_func(func_name, -1, rettv, 2, argv, funcexe);
+ tv_clear(&argv[0]);
+ tv_clear(&argv[1]);
+ if (r == FAIL || called_emsg != called_emsg_start) {
+ break;
+ }
+ }
+}
+
+/// reduce() on a Blob
+static void reduce_blob(typval_T *argvars, const char *func_name, funcexe_T *funcexe,
+ typval_T *rettv)
+{
+ const blob_T *const b = argvars[0].vval.v_blob;
+ const int called_emsg_start = called_emsg;
+
+ typval_T initial;
+ int i;
+ if (argvars[2].v_type == VAR_UNKNOWN) {
+ if (tv_blob_len(b) == 0) {
+ semsg(_(e_reduceempty), "Blob");
+ return;
+ }
+ initial = (typval_T){
+ .v_type = VAR_NUMBER,
+ .v_lock = VAR_UNLOCKED,
+ .vval.v_number = tv_blob_get(b, 0),
+ };
+ i = 1;
+ } else if (argvars[2].v_type != VAR_NUMBER) {
+ emsg(_(e_number_exp));
+ return;
+ } else {
+ initial = argvars[2];
+ i = 0;
+ }
+
+ tv_copy(&initial, rettv);
+ for (; i < tv_blob_len(b); i++) {
+ typval_T argv[3];
+ argv[0] = *rettv;
+ argv[1] = (typval_T){
+ .v_type = VAR_NUMBER,
+ .v_lock = VAR_UNLOCKED,
+ .vval.v_number = tv_blob_get(b, i),
+ };
+ const int r = call_func(func_name, -1, rettv, 2, argv, funcexe);
+ if (r == FAIL || called_emsg != called_emsg_start) {
+ return;
+ }
+ }
+}
+
/// "reduce(list, { accumulator, element -> value } [, initial])" function
/// "reduce(blob, { accumulator, element -> value } [, initial])" function
/// "reduce(string, { accumulator, element -> value } [, initial])" function
static void f_reduce(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
- const int called_emsg_start = called_emsg;
-
if (argvars[0].v_type != VAR_STRING
&& argvars[0].v_type != VAR_LIST
&& argvars[0].v_type != VAR_BLOB) {
emsg(_(e_string_list_or_blob_required));
+ return;
}
const char *func_name;
@@ -6203,110 +6336,12 @@ static void f_reduce(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
funcexe.fe_evaluate = true;
funcexe.fe_partial = partial;
- typval_T initial;
- typval_T argv[3];
if (argvars[0].v_type == VAR_LIST) {
- list_T *const l = argvars[0].vval.v_list;
- const listitem_T *li;
-
- if (argvars[2].v_type == VAR_UNKNOWN) {
- if (tv_list_len(l) == 0) {
- semsg(_(e_reduceempty), "List");
- return;
- }
- const listitem_T *const first = tv_list_first(l);
- initial = *TV_LIST_ITEM_TV(first);
- li = TV_LIST_ITEM_NEXT(l, first);
- } else {
- initial = argvars[2];
- li = tv_list_first(l);
- }
-
- tv_copy(&initial, rettv);
-
- if (l != NULL) {
- const VarLockStatus prev_locked = tv_list_locked(l);
-
- tv_list_set_lock(l, VAR_FIXED); // disallow the list changing here
- for (; li != NULL; li = TV_LIST_ITEM_NEXT(l, li)) {
- argv[0] = *rettv;
- argv[1] = *TV_LIST_ITEM_TV(li);
- rettv->v_type = VAR_UNKNOWN;
- const int r = call_func(func_name, -1, rettv, 2, argv, &funcexe);
- tv_clear(&argv[0]);
- if (r == FAIL || called_emsg != called_emsg_start) {
- break;
- }
- }
- tv_list_set_lock(l, prev_locked);
- }
+ reduce_list(argvars, func_name, &funcexe, rettv);
} else if (argvars[0].v_type == VAR_STRING) {
- const char *p = tv_get_string(&argvars[0]);
- int len;
-
- if (argvars[2].v_type == VAR_UNKNOWN) {
- if (*p == NUL) {
- semsg(_(e_reduceempty), "String");
- return;
- }
- len = utfc_ptr2len(p);
- *rettv = (typval_T){
- .v_type = VAR_STRING,
- .v_lock = VAR_UNLOCKED,
- .vval.v_string = xstrnsave(p, (size_t)len),
- };
- p += len;
- } else if (argvars[2].v_type != VAR_STRING) {
- semsg(_(e_string_expected_for_argument_nr), 3);
- return;
- } else {
- tv_copy(&argvars[2], rettv);
- }
-
- for (; *p != NUL; p += len) {
- argv[0] = *rettv;
- len = utfc_ptr2len(p);
- argv[1] = (typval_T){
- .v_type = VAR_STRING,
- .v_lock = VAR_UNLOCKED,
- .vval.v_string = xstrnsave(p, (size_t)len),
- };
- const int r = call_func(func_name, -1, rettv, 2, argv, &funcexe);
- tv_clear(&argv[0]);
- tv_clear(&argv[1]);
- if (r == FAIL || called_emsg != called_emsg_start) {
- break;
- }
- }
+ reduce_string(argvars, func_name, &funcexe, rettv);
} else {
- const blob_T *const b = argvars[0].vval.v_blob;
- int i;
-
- if (argvars[2].v_type == VAR_UNKNOWN) {
- if (tv_blob_len(b) == 0) {
- semsg(_(e_reduceempty), "Blob");
- return;
- }
- initial.v_type = VAR_NUMBER;
- initial.vval.v_number = tv_blob_get(b, 0);
- i = 1;
- } else if (argvars[2].v_type != VAR_NUMBER) {
- emsg(_(e_number_exp));
- return;
- } else {
- initial = argvars[2];
- i = 0;
- }
-
- tv_copy(&initial, rettv);
- for (; i < tv_blob_len(b); i++) {
- argv[0] = *rettv;
- argv[1].v_type = VAR_NUMBER;
- argv[1].vval.v_number = tv_blob_get(b, i);
- if (call_func(func_name, -1, rettv, 2, argv, &funcexe) == FAIL) {
- return;
- }
- }
+ reduce_blob(argvars, func_name, &funcexe, rettv);
}
}