diff options
author | zeertzjq <zeertzjq@outlook.com> | 2024-08-01 10:41:08 +0800 |
---|---|---|
committer | zeertzjq <zeertzjq@outlook.com> | 2024-08-02 11:56:51 +0800 |
commit | 582bf4f1e15988565da53a91395e2d0131628fbb (patch) | |
tree | 320f48a9beb4271a9ffd32eca0db526d3276de7c /src/nvim/eval.c | |
parent | f7fde0173af95925e7324b7d3c09776173dab8a7 (diff) | |
download | rneovim-582bf4f1e15988565da53a91395e2d0131628fbb.tar.gz rneovim-582bf4f1e15988565da53a91395e2d0131628fbb.tar.bz2 rneovim-582bf4f1e15988565da53a91395e2d0131628fbb.zip |
vim-patch:9.0.0634: evaluating "expr" options has more overhead than needed
Problem: Evaluating "expr" options has more overhead than needed.
Solution: Use call_simple_func() for 'foldtext', 'includeexpr', 'printexpr',
"expr" of 'spellsuggest', 'diffexpr', 'patchexpr', 'balloonexpr',
'formatexpr', 'indentexpr' and 'charconvert'.
https://github.com/vim/vim/commit/a4e0b9785e409e9e660171cea76dfcc5fdafad9b
vim-patch:9.0.0635: build error and compiler warnings
Problem: Build error and compiler warnings.
Solution: Add missing change. Add type casts.
https://github.com/vim/vim/commit/3292a229402c9892f5ab90645fbfe2b1db342f5b
Co-authored-by: Bram Moolenaar <Bram@vim.org>
Diffstat (limited to 'src/nvim/eval.c')
-rw-r--r-- | src/nvim/eval.c | 120 |
1 files changed, 84 insertions, 36 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index c8451b7a28..6b4f49b6cb 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -703,7 +703,7 @@ int eval_charconvert(const char *const enc_from, const char *const enc_to, } bool err = false; - if (eval_to_bool(p_ccv, &err, NULL, false)) { + if (eval_to_bool(p_ccv, &err, NULL, false, true)) { err = true; } @@ -732,7 +732,7 @@ void eval_diff(const char *const origfile, const char *const newfile, const char } // errors are ignored - typval_T *tv = eval_expr(p_dex, NULL); + typval_T *tv = eval_expr_ext(p_dex, NULL, true); tv_free(tv); set_vim_var_string(VV_FNAME_IN, NULL, -1); @@ -754,7 +754,7 @@ void eval_patch(const char *const origfile, const char *const difffile, const ch } // errors are ignored - typval_T *tv = eval_expr(p_pex, NULL); + typval_T *tv = eval_expr_ext(p_pex, NULL, true); tv_free(tv); set_vim_var_string(VV_FNAME_IN, NULL, -1); @@ -783,7 +783,8 @@ void fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, bool skip) /// @param skip only parse, don't execute /// /// @return true or false. -bool eval_to_bool(char *arg, bool *error, exarg_T *eap, bool skip) +bool eval_to_bool(char *arg, bool *error, exarg_T *eap, const bool skip, + const bool use_simple_function) { typval_T tv; bool retval = false; @@ -794,7 +795,9 @@ bool eval_to_bool(char *arg, bool *error, exarg_T *eap, bool skip) if (skip) { emsg_skip++; } - if (eval0(arg, &tv, eap, &evalarg) == FAIL) { + int r = use_simple_function ? eval0_simple_funccal(arg, &tv, eap, &evalarg) + : eval0(arg, &tv, eap, &evalarg); + if (r == FAIL) { *error = true; } else { *error = false; @@ -1042,14 +1045,17 @@ static char *typval2string(typval_T *tv, bool join_list) /// @param join_list when true convert a List into a sequence of lines. /// /// @return pointer to allocated memory, or NULL for failure. -char *eval_to_string_eap(char *arg, bool join_list, exarg_T *eap) +char *eval_to_string_eap(char *arg, const bool join_list, exarg_T *eap, + const bool use_simple_function) { typval_T tv; char *retval; evalarg_T evalarg; fill_evalarg_from_eap(&evalarg, eap, eap != NULL && eap->skip); - if (eval0(arg, &tv, NULL, &evalarg) == FAIL) { + int r = use_simple_function ? eval0_simple_funccal(arg, &tv, NULL, &evalarg) + : eval0(arg, &tv, NULL, &evalarg); + if (r == FAIL) { retval = NULL; } else { retval = typval2string(&tv, join_list); @@ -1060,16 +1066,16 @@ char *eval_to_string_eap(char *arg, bool join_list, exarg_T *eap) return retval; } -char *eval_to_string(char *arg, bool join_list) +char *eval_to_string(char *arg, const bool join_list, const bool use_simple_function) { - return eval_to_string_eap(arg, join_list, NULL); + return eval_to_string_eap(arg, join_list, NULL, use_simple_function); } /// Call eval_to_string() without using current local variables and using /// textlock. /// /// @param use_sandbox when true, use the sandbox. -char *eval_to_string_safe(char *arg, const bool use_sandbox) +char *eval_to_string_safe(char *arg, const bool use_sandbox, const bool use_simple_function) { char *retval; funccal_entry_T funccal_entry; @@ -1079,7 +1085,7 @@ char *eval_to_string_safe(char *arg, const bool use_sandbox) sandbox++; } textlock++; - retval = eval_to_string(arg, false); + retval = eval_to_string(arg, false, use_simple_function); if (use_sandbox) { sandbox--; } @@ -1092,15 +1098,22 @@ char *eval_to_string_safe(char *arg, const bool use_sandbox) /// Evaluates "expr" silently. /// /// @return -1 for an error. -varnumber_T eval_to_number(char *expr) +varnumber_T eval_to_number(char *expr, const bool use_simple_function) { typval_T rettv; varnumber_T retval; char *p = skipwhite(expr); + int r = NOTDONE; emsg_off++; - if (eval1(&p, &rettv, &EVALARG_EVALUATE) == FAIL) { + if (use_simple_function) { + r = may_call_simple_func(expr, &rettv); + } + if (r == NOTDONE) { + r = eval1(&p, &rettv, &EVALARG_EVALUATE); + } + if (r == FAIL) { retval = -1; } else { retval = tv_get_number_chk(&rettv, NULL); @@ -1117,12 +1130,26 @@ varnumber_T eval_to_number(char *expr) /// NULL when there is an error. typval_T *eval_expr(char *arg, exarg_T *eap) { + return eval_expr_ext(arg, eap, false); +} + +static typval_T *eval_expr_ext(char *arg, exarg_T *eap, const bool use_simple_function) +{ typval_T *tv = xmalloc(sizeof(*tv)); evalarg_T evalarg; fill_evalarg_from_eap(&evalarg, eap, eap != NULL && eap->skip); - if (eval0(arg, tv, eap, &evalarg) == FAIL) { + int r = NOTDONE; + + if (use_simple_function) { + r = eval0_simple_funccal(arg, tv, eap, &evalarg); + } + if (r == NOTDONE) { + r = eval0(arg, tv, eap, &evalarg); + } + + if (r == FAIL) { XFREE_CLEAR(tv); } @@ -1208,7 +1235,11 @@ list_T *eval_spell_expr(char *badword, char *expr) current_sctx = *ctx; } - if (eval1(&p, &rettv, &EVALARG_EVALUATE) == OK) { + int r = may_call_simple_func(p, &rettv); + if (r == NOTDONE) { + r = eval1(&p, &rettv, &EVALARG_EVALUATE); + } + if (r == OK) { if (rettv.v_type != VAR_LIST) { tv_clear(&rettv); } else { @@ -1360,23 +1391,10 @@ int eval_foldexpr(win_T *wp, int *cp) *cp = NUL; typval_T tv; - int r = NOTDONE; - - // If the expression is "FuncName()" then we can skip a lot of overhead. - char *parens = strstr(arg, "()"); - if (parens != NULL && *skipwhite(parens + 2) == NUL) { - char *p = strncmp(arg, "<SNR>", 5) == 0 ? skipdigits(arg + 5) : arg; - if (to_name_end(p, true) == parens) { - r = call_simple_func(arg, (int)(parens - arg), &tv); - } - } - - if (r == NOTDONE) { - r = eval0(arg, &tv, NULL, &EVALARG_EVALUATE); - } - varnumber_T retval; - if (r == FAIL) { + // Evaluate the expression. If the expression is "FuncName()" call the + // function directly. + if (eval0_simple_funccal(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL) { retval = 0; } else { // If the result is a number, just return the number. @@ -1422,7 +1440,7 @@ Object eval_foldtext(win_T *wp) typval_T tv; Object retval; - if (eval0(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL) { + if (eval0_simple_funccal(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL) { retval = STRING_OBJ(NULL_STRING); } else { if (tv.v_type == VAR_LIST) { @@ -2539,9 +2557,10 @@ void clear_evalarg(evalarg_T *evalarg, exarg_T *eap) } } -/// The "evaluate" argument: When false, the argument is only parsed but not -/// executed. The function may return OK, but the rettv will be of type -/// VAR_UNKNOWN. The function still returns FAIL for a syntax error. +/// The "eval" functions have an "evalarg" argument: When NULL or +/// "evalarg->eval_flags" does not have EVAL_EVALUATE, then the argument is only +/// parsed but not executed. The functions may return OK, but the rettv will be +/// of type VAR_UNKNOWN. The functions still returns FAIL for a syntax error. /// Handle zero level expression. /// This calls eval1() and handles error message and nextcmd. @@ -2600,6 +2619,35 @@ int eval0(char *arg, typval_T *rettv, exarg_T *eap, evalarg_T *const evalarg) return ret; } +/// If "arg" is a simple function call without arguments then call it and return +/// the result. Otherwise return NOTDONE. +static int may_call_simple_func(char *arg, typval_T *rettv) +{ + char *parens = strstr(arg, "()"); + int r = NOTDONE; + + // If the expression is "FuncName()" then we can skip a lot of overhead. + if (parens != NULL && *skipwhite(parens + 2) == NUL) { + char *p = strncmp(arg, "<SNR>", 5) == 0 ? skipdigits(arg + 5) : arg; + if (to_name_end(p, true) == parens) { + r = call_simple_func(arg, (int)(parens - arg), rettv); + } + } + return r; +} + +/// Handle zero level expression with optimization for a simple function call. +/// Same arguments and return value as eval0(). +static int eval0_simple_funccal(char *arg, typval_T *rettv, exarg_T *eap, evalarg_T *const evalarg) +{ + int r = may_call_simple_func(arg, rettv); + + if (r == NOTDONE) { + r = eval0(arg, rettv, eap, evalarg); + } + return r; +} + /// Handle top level expression: /// expr2 ? expr1 : expr1 /// expr2 ?? expr1 @@ -7412,7 +7460,7 @@ static char *make_expanded_name(const char *in_start, char *expr_start, char *ex char c1 = *in_end; *in_end = NUL; - char *temp_result = eval_to_string(expr_start + 1, false); + char *temp_result = eval_to_string(expr_start + 1, false, false); if (temp_result != NULL) { retval = xmalloc(strlen(temp_result) + (size_t)(expr_start - in_start) + (size_t)(in_end - expr_end) + 1); |