# HG changeset patch # User Bram Moolenaar # Date 1593256503 -7200 # Node ID f80e822a310df2c0bbbd6d2e7f6c2d4f775ff591 # Parent d49456e1977eab0063c7b41119d5430ff852d6f7 patch 8.2.1067: expression "!expr->func()" does not work Commit: https://github.com/vim/vim/commit/0b1cd52ff6bf690388f892be686a91721a082e55 Author: Bram Moolenaar Date: Sat Jun 27 13:11:50 2020 +0200 patch 8.2.1067: expression "!expr->func()" does not work Problem: Expression "!expr->func()" does not work. Solution: Apply plus and minus earlier. (closes https://github.com/vim/vim/issues/6348) diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -51,7 +51,7 @@ static int eval4(char_u **arg, typval_T static int eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg); static int eval6(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int want_string); static int eval7(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int want_string); -static int eval7_leader(typval_T *rettv, char_u *start_leader, char_u **end_leaderp); +static int eval7_leader(typval_T *rettv, int numeric_only, char_u *start_leader, char_u **end_leaderp); static int free_unref_items(int copyID); static char_u *make_expanded_name(char_u *in_start, char_u *expr_start, char_u *expr_end, char_u *in_end); @@ -2756,6 +2756,11 @@ eval7( case '8': case '9': case '.': ret = get_number_tv(arg, rettv, evaluate, want_string); + + // Apply prefixed "-" and "+" now. Matters especially when + // "->" follows. + if (ret == OK && evaluate && end_leader > start_leader) + ret = eval7_leader(rettv, TRUE, start_leader, &end_leader); break; /* @@ -2879,23 +2884,27 @@ eval7( // Handle following '[', '(' and '.' for expr[expr], expr.name, // expr(expr), expr->name(expr) if (ret == OK) - ret = handle_subscript(arg, rettv, flags, TRUE, - start_leader, &end_leader); + ret = handle_subscript(arg, rettv, flags, TRUE); /* * Apply logical NOT and unary '-', from right to left, ignore '+'. */ if (ret == OK && evaluate && end_leader > start_leader) - ret = eval7_leader(rettv, start_leader, &end_leader); + ret = eval7_leader(rettv, FALSE, start_leader, &end_leader); return ret; } /* * Apply the leading "!" and "-" before an eval7 expression to "rettv". + * When "numeric_only" is TRUE only handle "+" and "-". * Adjusts "end_leaderp" until it is at "start_leader". */ static int -eval7_leader(typval_T *rettv, char_u *start_leader, char_u **end_leaderp) +eval7_leader( + typval_T *rettv, + int numeric_only, + char_u *start_leader, + char_u **end_leaderp) { char_u *end_leader = *end_leaderp; int ret = OK; @@ -2921,6 +2930,11 @@ eval7_leader(typval_T *rettv, char_u *st --end_leader; if (*end_leader == '!') { + if (numeric_only) + { + ++end_leader; + break; + } #ifdef FEAT_FLOAT if (rettv->v_type == VAR_FLOAT) f = !f; @@ -4871,9 +4885,7 @@ handle_subscript( char_u **arg, typval_T *rettv, int flags, // do more than finding the end - int verbose, // give error messages - char_u *start_leader, // start of '!' and '-' prefixes - char_u **end_leaderp) // end of '!' and '-' prefixes + int verbose) // give error messages { int evaluate = flags & EVAL_EVALUATE; int ret = OK; @@ -4910,10 +4922,6 @@ handle_subscript( } else if (**arg == '-') { - // Expression "-1.0->method()" applies the leader "-" before - // applying ->. - if (evaluate && *end_leaderp > start_leader) - ret = eval7_leader(rettv, start_leader, end_leaderp); if (ret == OK) { if ((*arg)[2] == '{') diff --git a/src/evalvars.c b/src/evalvars.c --- a/src/evalvars.c +++ b/src/evalvars.c @@ -1125,8 +1125,8 @@ list_arg_vars(exarg_T *eap, char_u *arg, { // handle d.key, l[idx], f(expr) arg_subsc = arg; - if (handle_subscript(&arg, &tv, EVAL_EVALUATE, TRUE, - name, &name) == FAIL) + if (handle_subscript(&arg, &tv, EVAL_EVALUATE, TRUE) + == FAIL) error = TRUE; else { @@ -3341,8 +3341,7 @@ var_exists(char_u *var) if (n) { // handle d.key, l[idx], f(expr) - n = (handle_subscript(&var, &tv, EVAL_EVALUATE, - FALSE, name, &name) == OK); + n = (handle_subscript(&var, &tv, EVAL_EVALUATE, FALSE) == OK); if (n) clear_tv(&tv); } diff --git a/src/proto/eval.pro b/src/proto/eval.pro --- a/src/proto/eval.pro +++ b/src/proto/eval.pro @@ -53,7 +53,7 @@ int get_name_len(char_u **arg, char_u ** char_u *find_name_end(char_u *arg, char_u **expr_start, char_u **expr_end, int flags); int eval_isnamec(int c); int eval_isnamec1(int c); -int handle_subscript(char_u **arg, typval_T *rettv, int flags, int verbose, char_u *start_leader, char_u **end_leaderp); +int handle_subscript(char_u **arg, typval_T *rettv, int flags, int verbose); int item_copy(typval_T *from, typval_T *to, int deep, int copyID); void echo_one(typval_T *rettv, int with_space, int *atstart, int *needclr); void ex_echo(exarg_T *eap); diff --git a/src/testdir/test_expr.vim b/src/testdir/test_expr.vim --- a/src/testdir/test_expr.vim +++ b/src/testdir/test_expr.vim @@ -110,6 +110,13 @@ func Test_special_char() call assert_fails('echo "\') endfunc +func Test_method_with_prefix() + call assert_equal(1, !range(5)->empty()) + call assert_equal([0, 1, 2], --3->range()) + call assert_equal(0, !-3) + call assert_equal(1, !+-+0) +endfunc + func Test_option_value() " boolean set bri diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -1081,6 +1081,8 @@ def Test_expr7_parens() assert_equal(6, --6) assert_equal(6, -+-6) assert_equal(-6, ---6) + assert_equal(false, !-3) + assert_equal(true, !+-+0) enddef def Test_expr7_negate() @@ -1102,6 +1104,8 @@ enddef def Test_expr7_call() assert_equal('yes', 'yes'->Echo()) assert_equal('yes', 'yes'->s:EchoArg()) + assert_equal(1, !range(5)->empty()) + assert_equal([0, 1, 2], --3->range()) call CheckDefFailure(["let x = 'yes'->Echo"], 'E107:') enddef diff --git a/src/userfunc.c b/src/userfunc.c --- a/src/userfunc.c +++ b/src/userfunc.c @@ -3926,7 +3926,7 @@ ex_call(exarg_T *eap) // Handle a function returning a Funcref, Dictionary or List. if (handle_subscript(&arg, &rettv, eap->skip ? 0 : EVAL_EVALUATE, - TRUE, name, &name) == FAIL) + TRUE) == FAIL) { failed = TRUE; break; diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1067, +/**/ 1066, /**/ 1065,