1
0
forked from aniani/vim

patch 8.2.1067: expression "!expr->func()" does not work

Problem:    Expression "!expr->func()" does not work.
Solution:   Apply plus and minus earlier. (closes #6348)
This commit is contained in:
Bram Moolenaar
2020-06-27 13:11:50 +02:00
parent bd84617d1a
commit 0b1cd52ff6
7 changed files with 38 additions and 18 deletions

View File

@@ -51,7 +51,7 @@ static int eval4(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
static int eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg); 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 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(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 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); 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 '8':
case '9': case '9':
case '.': ret = get_number_tv(arg, rettv, evaluate, want_string); 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; break;
/* /*
@@ -2879,23 +2884,27 @@ eval7(
// Handle following '[', '(' and '.' for expr[expr], expr.name, // Handle following '[', '(' and '.' for expr[expr], expr.name,
// expr(expr), expr->name(expr) // expr(expr), expr->name(expr)
if (ret == OK) if (ret == OK)
ret = handle_subscript(arg, rettv, flags, TRUE, ret = handle_subscript(arg, rettv, flags, TRUE);
start_leader, &end_leader);
/* /*
* Apply logical NOT and unary '-', from right to left, ignore '+'. * Apply logical NOT and unary '-', from right to left, ignore '+'.
*/ */
if (ret == OK && evaluate && end_leader > start_leader) 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; return ret;
} }
/* /*
* Apply the leading "!" and "-" before an eval7 expression to "rettv". * 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". * Adjusts "end_leaderp" until it is at "start_leader".
*/ */
static int 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; char_u *end_leader = *end_leaderp;
int ret = OK; int ret = OK;
@@ -2921,6 +2930,11 @@ eval7_leader(typval_T *rettv, char_u *start_leader, char_u **end_leaderp)
--end_leader; --end_leader;
if (*end_leader == '!') if (*end_leader == '!')
{ {
if (numeric_only)
{
++end_leader;
break;
}
#ifdef FEAT_FLOAT #ifdef FEAT_FLOAT
if (rettv->v_type == VAR_FLOAT) if (rettv->v_type == VAR_FLOAT)
f = !f; f = !f;
@@ -4871,9 +4885,7 @@ handle_subscript(
char_u **arg, char_u **arg,
typval_T *rettv, typval_T *rettv,
int flags, // do more than finding the end int flags, // do more than finding the end
int verbose, // give error messages int verbose) // give error messages
char_u *start_leader, // start of '!' and '-' prefixes
char_u **end_leaderp) // end of '!' and '-' prefixes
{ {
int evaluate = flags & EVAL_EVALUATE; int evaluate = flags & EVAL_EVALUATE;
int ret = OK; int ret = OK;
@@ -4910,10 +4922,6 @@ handle_subscript(
} }
else if (**arg == '-') 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 (ret == OK)
{ {
if ((*arg)[2] == '{') if ((*arg)[2] == '{')

View File

@@ -1125,8 +1125,8 @@ list_arg_vars(exarg_T *eap, char_u *arg, int *first)
{ {
// handle d.key, l[idx], f(expr) // handle d.key, l[idx], f(expr)
arg_subsc = arg; arg_subsc = arg;
if (handle_subscript(&arg, &tv, EVAL_EVALUATE, TRUE, if (handle_subscript(&arg, &tv, EVAL_EVALUATE, TRUE)
name, &name) == FAIL) == FAIL)
error = TRUE; error = TRUE;
else else
{ {
@@ -3341,8 +3341,7 @@ var_exists(char_u *var)
if (n) if (n)
{ {
// handle d.key, l[idx], f(expr) // handle d.key, l[idx], f(expr)
n = (handle_subscript(&var, &tv, EVAL_EVALUATE, n = (handle_subscript(&var, &tv, EVAL_EVALUATE, FALSE) == OK);
FALSE, name, &name) == OK);
if (n) if (n)
clear_tv(&tv); clear_tv(&tv);
} }

View File

@@ -53,7 +53,7 @@ int get_name_len(char_u **arg, char_u **alias, int evaluate, int verbose);
char_u *find_name_end(char_u *arg, char_u **expr_start, char_u **expr_end, int flags); 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_isnamec(int c);
int eval_isnamec1(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); 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 echo_one(typval_T *rettv, int with_space, int *atstart, int *needclr);
void ex_echo(exarg_T *eap); void ex_echo(exarg_T *eap);

View File

@@ -110,6 +110,13 @@ func Test_special_char()
call assert_fails('echo "\<C-">') call assert_fails('echo "\<C-">')
endfunc 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() func Test_option_value()
" boolean " boolean
set bri set bri

View File

@@ -1081,6 +1081,8 @@ def Test_expr7_parens()
assert_equal(6, --6) assert_equal(6, --6)
assert_equal(6, -+-6) assert_equal(6, -+-6)
assert_equal(-6, ---6) assert_equal(-6, ---6)
assert_equal(false, !-3)
assert_equal(true, !+-+0)
enddef enddef
def Test_expr7_negate() def Test_expr7_negate()
@@ -1102,6 +1104,8 @@ enddef
def Test_expr7_call() def Test_expr7_call()
assert_equal('yes', 'yes'->Echo()) assert_equal('yes', 'yes'->Echo())
assert_equal('yes', 'yes'->s:EchoArg()) 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:') call CheckDefFailure(["let x = 'yes'->Echo"], 'E107:')
enddef enddef

View File

@@ -3926,7 +3926,7 @@ ex_call(exarg_T *eap)
// Handle a function returning a Funcref, Dictionary or List. // Handle a function returning a Funcref, Dictionary or List.
if (handle_subscript(&arg, &rettv, eap->skip ? 0 : EVAL_EVALUATE, if (handle_subscript(&arg, &rettv, eap->skip ? 0 : EVAL_EVALUATE,
TRUE, name, &name) == FAIL) TRUE) == FAIL)
{ {
failed = TRUE; failed = TRUE;
break; break;

View File

@@ -754,6 +754,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1067,
/**/ /**/
1066, 1066,
/**/ /**/