aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval.c
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2024-08-01 10:41:08 +0800
committerzeertzjq <zeertzjq@outlook.com>2024-08-02 11:56:51 +0800
commit582bf4f1e15988565da53a91395e2d0131628fbb (patch)
tree320f48a9beb4271a9ffd32eca0db526d3276de7c /src/nvim/eval.c
parentf7fde0173af95925e7324b7d3c09776173dab8a7 (diff)
downloadrneovim-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.c120
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);