# HG changeset patch # User Bram Moolenaar # Date 1567601104 -7200 # Node ID 6d4d3bce365df4ad88cac33daab3dffd5c634eb2 # Parent 5de9b5831cd44e520b82f981971a112e875ffa43 patch 8.1.1978: the eval.c file is too big Commit: https://github.com/vim/vim/commit/1e1d30048e722906a13665bd6c3c24c87eb2fe25 Author: Bram Moolenaar Date: Wed Sep 4 14:41:14 2019 +0200 patch 8.1.1978: the eval.c file is too big Problem: The eval.c file is too big. Solution: Move filter() and map() to list.c. diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -7135,199 +7135,4 @@ do_string_sub( return ret; } - static int -filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp) -{ - typval_T rettv; - typval_T argv[3]; - int retval = FAIL; - - copy_tv(tv, get_vim_var_tv(VV_VAL)); - argv[0] = *get_vim_var_tv(VV_KEY); - argv[1] = *get_vim_var_tv(VV_VAL); - if (eval_expr_typval(expr, argv, 2, &rettv) == FAIL) - goto theend; - if (map) - { - /* map(): replace the list item value */ - clear_tv(tv); - rettv.v_lock = 0; - *tv = rettv; - } - else - { - int error = FALSE; - - /* filter(): when expr is zero remove the item */ - *remp = (tv_get_number_chk(&rettv, &error) == 0); - clear_tv(&rettv); - /* On type error, nothing has been removed; return FAIL to stop the - * loop. The error message was given by tv_get_number_chk(). */ - if (error) - goto theend; - } - retval = OK; -theend: - clear_tv(get_vim_var_tv(VV_VAL)); - return retval; -} - -/* - * Implementation of map() and filter(). - */ - void -filter_map(typval_T *argvars, typval_T *rettv, int map) -{ - typval_T *expr; - listitem_T *li, *nli; - list_T *l = NULL; - dictitem_T *di; - hashtab_T *ht; - hashitem_T *hi; - dict_T *d = NULL; - blob_T *b = NULL; - int rem; - int todo; - char_u *ermsg = (char_u *)(map ? "map()" : "filter()"); - char_u *arg_errmsg = (char_u *)(map ? N_("map() argument") - : N_("filter() argument")); - int save_did_emsg; - int idx = 0; - - if (argvars[0].v_type == VAR_BLOB) - { - if ((b = argvars[0].vval.v_blob) == NULL) - return; - } - else if (argvars[0].v_type == VAR_LIST) - { - if ((l = argvars[0].vval.v_list) == NULL - || (!map && var_check_lock(l->lv_lock, arg_errmsg, TRUE))) - return; - } - else if (argvars[0].v_type == VAR_DICT) - { - if ((d = argvars[0].vval.v_dict) == NULL - || (!map && var_check_lock(d->dv_lock, arg_errmsg, TRUE))) - return; - } - else - { - semsg(_(e_listdictarg), ermsg); - return; - } - - expr = &argvars[1]; - /* On type errors, the preceding call has already displayed an error - * message. Avoid a misleading error message for an empty string that - * was not passed as argument. */ - if (expr->v_type != VAR_UNKNOWN) - { - typval_T save_val; - typval_T save_key; - - prepare_vimvar(VV_VAL, &save_val); - prepare_vimvar(VV_KEY, &save_key); - - // We reset "did_emsg" to be able to detect whether an error - // occurred during evaluation of the expression. - save_did_emsg = did_emsg; - did_emsg = FALSE; - - if (argvars[0].v_type == VAR_DICT) - { - ht = &d->dv_hashtab; - hash_lock(ht); - todo = (int)ht->ht_used; - for (hi = ht->ht_array; todo > 0; ++hi) - { - if (!HASHITEM_EMPTY(hi)) - { - int r; - - --todo; - di = HI2DI(hi); - if (map && (var_check_lock(di->di_tv.v_lock, - arg_errmsg, TRUE) - || var_check_ro(di->di_flags, - arg_errmsg, TRUE))) - break; - set_vim_var_string(VV_KEY, di->di_key, -1); - r = filter_map_one(&di->di_tv, expr, map, &rem); - clear_tv(get_vim_var_tv(VV_KEY)); - if (r == FAIL || did_emsg) - break; - if (!map && rem) - { - if (var_check_fixed(di->di_flags, arg_errmsg, TRUE) - || var_check_ro(di->di_flags, arg_errmsg, TRUE)) - break; - dictitem_remove(d, di); - } - } - } - hash_unlock(ht); - } - else if (argvars[0].v_type == VAR_BLOB) - { - int i; - typval_T tv; - - // set_vim_var_nr() doesn't set the type - set_vim_var_type(VV_KEY, VAR_NUMBER); - - for (i = 0; i < b->bv_ga.ga_len; i++) - { - tv.v_type = VAR_NUMBER; - tv.vval.v_number = blob_get(b, i); - set_vim_var_nr(VV_KEY, idx); - if (filter_map_one(&tv, expr, map, &rem) == FAIL || did_emsg) - break; - if (tv.v_type != VAR_NUMBER) - { - emsg(_(e_invalblob)); - break; - } - tv.v_type = VAR_NUMBER; - blob_set(b, i, tv.vval.v_number); - if (!map && rem) - { - char_u *p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data; - - mch_memmove(p + idx, p + i + 1, - (size_t)b->bv_ga.ga_len - i - 1); - --b->bv_ga.ga_len; - --i; - } - } - } - else // argvars[0].v_type == VAR_LIST - { - // set_vim_var_nr() doesn't set the type - set_vim_var_type(VV_KEY, VAR_NUMBER); - - for (li = l->lv_first; li != NULL; li = nli) - { - if (map && var_check_lock(li->li_tv.v_lock, arg_errmsg, TRUE)) - break; - nli = li->li_next; - set_vim_var_nr(VV_KEY, idx); - if (filter_map_one(&li->li_tv, expr, map, &rem) == FAIL - || did_emsg) - break; - if (!map && rem) - listitem_remove(l, li); - ++idx; - } - } - - restore_vimvar(VV_KEY, &save_key); - restore_vimvar(VV_VAL, &save_val); - - did_emsg |= save_did_emsg; - } - - copy_tv(&argvars[0], rettv); -} - #endif /* defined(FEAT_MODIFY_FNAME) || defined(FEAT_EVAL) */ diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -106,7 +106,6 @@ static void f_extend(typval_T *argvars, static void f_feedkeys(typval_T *argvars, typval_T *rettv); static void f_filereadable(typval_T *argvars, typval_T *rettv); static void f_filewritable(typval_T *argvars, typval_T *rettv); -static void f_filter(typval_T *argvars, typval_T *rettv); static void f_finddir(typval_T *argvars, typval_T *rettv); static void f_findfile(typval_T *argvars, typval_T *rettv); #ifdef FEAT_FLOAT @@ -192,7 +191,6 @@ static void f_log10(typval_T *argvars, t #ifdef FEAT_LUA static void f_luaeval(typval_T *argvars, typval_T *rettv); #endif -static void f_map(typval_T *argvars, typval_T *rettv); static void f_maparg(typval_T *argvars, typval_T *rettv); static void f_mapcheck(typval_T *argvars, typval_T *rettv); static void f_match(typval_T *argvars, typval_T *rettv); @@ -3511,15 +3509,6 @@ findfilendir( } /* - * "filter()" function - */ - static void -f_filter(typval_T *argvars, typval_T *rettv) -{ - filter_map(argvars, rettv, FALSE); -} - -/* * "finddir({fname}[, {path}[, {count}]])" function */ static void @@ -6801,15 +6790,6 @@ f_luaeval(typval_T *argvars, typval_T *r #endif /* - * "map()" function - */ - static void -f_map(typval_T *argvars, typval_T *rettv) -{ - filter_map(argvars, rettv, TRUE); -} - -/* * "maparg()" function */ static void diff --git a/src/list.c b/src/list.c --- a/src/list.c +++ b/src/list.c @@ -1547,4 +1547,220 @@ f_uniq(typval_T *argvars, typval_T *rett do_sort_uniq(argvars, rettv, FALSE); } -#endif /* defined(FEAT_EVAL) */ +/* + * Handle one item for map() and filter(). + */ + static int +filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp) +{ + typval_T rettv; + typval_T argv[3]; + int retval = FAIL; + + copy_tv(tv, get_vim_var_tv(VV_VAL)); + argv[0] = *get_vim_var_tv(VV_KEY); + argv[1] = *get_vim_var_tv(VV_VAL); + if (eval_expr_typval(expr, argv, 2, &rettv) == FAIL) + goto theend; + if (map) + { + // map(): replace the list item value + clear_tv(tv); + rettv.v_lock = 0; + *tv = rettv; + } + else + { + int error = FALSE; + + // filter(): when expr is zero remove the item + *remp = (tv_get_number_chk(&rettv, &error) == 0); + clear_tv(&rettv); + // On type error, nothing has been removed; return FAIL to stop the + // loop. The error message was given by tv_get_number_chk(). + if (error) + goto theend; + } + retval = OK; +theend: + clear_tv(get_vim_var_tv(VV_VAL)); + return retval; +} + +/* + * Implementation of map() and filter(). + */ + static void +filter_map(typval_T *argvars, typval_T *rettv, int map) +{ + typval_T *expr; + listitem_T *li, *nli; + list_T *l = NULL; + dictitem_T *di; + hashtab_T *ht; + hashitem_T *hi; + dict_T *d = NULL; + blob_T *b = NULL; + int rem; + int todo; + char_u *ermsg = (char_u *)(map ? "map()" : "filter()"); + char_u *arg_errmsg = (char_u *)(map ? N_("map() argument") + : N_("filter() argument")); + int save_did_emsg; + int idx = 0; + + if (argvars[0].v_type == VAR_BLOB) + { + if ((b = argvars[0].vval.v_blob) == NULL) + return; + } + else if (argvars[0].v_type == VAR_LIST) + { + if ((l = argvars[0].vval.v_list) == NULL + || (!map && var_check_lock(l->lv_lock, arg_errmsg, TRUE))) + return; + } + else if (argvars[0].v_type == VAR_DICT) + { + if ((d = argvars[0].vval.v_dict) == NULL + || (!map && var_check_lock(d->dv_lock, arg_errmsg, TRUE))) + return; + } + else + { + semsg(_(e_listdictarg), ermsg); + return; + } + + expr = &argvars[1]; + // On type errors, the preceding call has already displayed an error + // message. Avoid a misleading error message for an empty string that + // was not passed as argument. + if (expr->v_type != VAR_UNKNOWN) + { + typval_T save_val; + typval_T save_key; + + prepare_vimvar(VV_VAL, &save_val); + prepare_vimvar(VV_KEY, &save_key); + + // We reset "did_emsg" to be able to detect whether an error + // occurred during evaluation of the expression. + save_did_emsg = did_emsg; + did_emsg = FALSE; + + if (argvars[0].v_type == VAR_DICT) + { + ht = &d->dv_hashtab; + hash_lock(ht); + todo = (int)ht->ht_used; + for (hi = ht->ht_array; todo > 0; ++hi) + { + if (!HASHITEM_EMPTY(hi)) + { + int r; + + --todo; + di = HI2DI(hi); + if (map && (var_check_lock(di->di_tv.v_lock, + arg_errmsg, TRUE) + || var_check_ro(di->di_flags, + arg_errmsg, TRUE))) + break; + set_vim_var_string(VV_KEY, di->di_key, -1); + r = filter_map_one(&di->di_tv, expr, map, &rem); + clear_tv(get_vim_var_tv(VV_KEY)); + if (r == FAIL || did_emsg) + break; + if (!map && rem) + { + if (var_check_fixed(di->di_flags, arg_errmsg, TRUE) + || var_check_ro(di->di_flags, arg_errmsg, TRUE)) + break; + dictitem_remove(d, di); + } + } + } + hash_unlock(ht); + } + else if (argvars[0].v_type == VAR_BLOB) + { + int i; + typval_T tv; + + // set_vim_var_nr() doesn't set the type + set_vim_var_type(VV_KEY, VAR_NUMBER); + + for (i = 0; i < b->bv_ga.ga_len; i++) + { + tv.v_type = VAR_NUMBER; + tv.vval.v_number = blob_get(b, i); + set_vim_var_nr(VV_KEY, idx); + if (filter_map_one(&tv, expr, map, &rem) == FAIL || did_emsg) + break; + if (tv.v_type != VAR_NUMBER) + { + emsg(_(e_invalblob)); + break; + } + tv.v_type = VAR_NUMBER; + blob_set(b, i, tv.vval.v_number); + if (!map && rem) + { + char_u *p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data; + + mch_memmove(p + idx, p + i + 1, + (size_t)b->bv_ga.ga_len - i - 1); + --b->bv_ga.ga_len; + --i; + } + } + } + else // argvars[0].v_type == VAR_LIST + { + // set_vim_var_nr() doesn't set the type + set_vim_var_type(VV_KEY, VAR_NUMBER); + + for (li = l->lv_first; li != NULL; li = nli) + { + if (map && var_check_lock(li->li_tv.v_lock, arg_errmsg, TRUE)) + break; + nli = li->li_next; + set_vim_var_nr(VV_KEY, idx); + if (filter_map_one(&li->li_tv, expr, map, &rem) == FAIL + || did_emsg) + break; + if (!map && rem) + listitem_remove(l, li); + ++idx; + } + } + + restore_vimvar(VV_KEY, &save_key); + restore_vimvar(VV_VAL, &save_val); + + did_emsg |= save_did_emsg; + } + + copy_tv(&argvars[0], rettv); +} + +/* + * "filter()" function + */ + void +f_filter(typval_T *argvars, typval_T *rettv) +{ + filter_map(argvars, rettv, FALSE); +} + +/* + * "map()" function + */ + void +f_map(typval_T *argvars, typval_T *rettv) +{ + filter_map(argvars, rettv, TRUE); +} + +#endif // defined(FEAT_EVAL) diff --git a/src/proto/eval.pro b/src/proto/eval.pro --- a/src/proto/eval.pro +++ b/src/proto/eval.pro @@ -11,8 +11,6 @@ int skip_expr(char_u **pp); char_u *eval_to_string(char_u *arg, char_u **nextcmd, int convert); char_u *eval_to_string_safe(char_u *arg, char_u **nextcmd, int use_sandbox); varnumber_T eval_to_number(char_u *expr); -list_T *eval_spell_expr(char_u *badword, char_u *expr); -int get_spellword(list_T *list, char_u **pp); typval_T *eval_expr(char_u *arg, char_u **nextcmd); int call_vim_function(char_u *func, int argc, typval_T *argv, typval_T *rettv); varnumber_T call_func_retnr(char_u *func, int argc, typval_T *argv); @@ -78,5 +76,4 @@ int typval_compare(typval_T *typ1, typva char_u *typval_tostring(typval_T *arg); int modify_fname(char_u *src, int tilde_file, int *usedlen, char_u **fnamep, char_u **bufp, int *fnamelen); char_u *do_string_sub(char_u *str, char_u *pat, char_u *sub, typval_T *expr, char_u *flags); -void filter_map(typval_T *argvars, typval_T *rettv, int map); /* vim: set ft=c : */ diff --git a/src/proto/list.pro b/src/proto/list.pro --- a/src/proto/list.pro +++ b/src/proto/list.pro @@ -41,4 +41,6 @@ void f_list2str(typval_T *argvars, typva void list_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg); void f_sort(typval_T *argvars, typval_T *rettv); void f_uniq(typval_T *argvars, typval_T *rettv); +void f_filter(typval_T *argvars, typval_T *rettv); +void f_map(typval_T *argvars, typval_T *rettv); /* vim: set ft=c : */ diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -762,6 +762,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1978, +/**/ 1977, /**/ 1976,