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

Problem:    Expression "!expr->func()" does not work.
Solution:   Apply plus and minus earlier. (closes vim/vim#6348)

0b1cd52ff6

Co-authored-by: Bram Moolenaar <Bram@vim.org>
This commit is contained in:
zeertzjq 2023-03-09 13:47:01 +08:00 committed by GitHub
parent 89a525de9f
commit 3ad8458824
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 27 additions and 16 deletions

View File

@ -2906,6 +2906,12 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string)
case '8':
case '9':
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;
// String constant: "string".
@ -3011,13 +3017,12 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string)
// Handle following '[', '(' and '.' for expr[expr], expr.name,
// expr(expr), expr->name(expr)
if (ret == OK) {
ret = handle_subscript((const char **)arg, rettv, evaluate, true,
(char *)start_leader, &end_leader);
ret = handle_subscript((const char **)arg, rettv, evaluate, true);
}
// Apply logical NOT and unary '-', from right to left, ignore '+'.
if (ret == OK && evaluate && end_leader > start_leader) {
ret = eval7_leader(rettv, (char *)start_leader, &end_leader);
ret = eval7_leader(rettv, false, start_leader, &end_leader);
}
recurse--;
@ -3027,9 +3032,11 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string)
/// Apply the leading "!" and "-" before an eval7 expression to "rettv".
/// Adjusts "end_leaderp" until it is at "start_leader".
///
/// @param numeric_only if true only handle "+" and "-".
///
/// @return OK on success, FAIL on failure.
static int eval7_leader(typval_T *const rettv, const char *const start_leader,
const char **const end_leaderp)
static int eval7_leader(typval_T *const rettv, const bool numeric_only,
const char *const start_leader, const char **const end_leaderp)
FUNC_ATTR_NONNULL_ALL
{
const char *end_leader = (char *)(*end_leaderp);
@ -3050,6 +3057,10 @@ static int eval7_leader(typval_T *const rettv, const char *const start_leader,
while (end_leader > start_leader) {
end_leader--;
if (*end_leader == '!') {
if (numeric_only) {
end_leader++;
break;
}
if (rettv->v_type == VAR_FLOAT) {
f = !(bool)f;
} else {
@ -6899,8 +6910,7 @@ int check_luafunc_name(const char *const str, const bool paren)
/// @param verbose give error messages
/// @param start_leader start of '!' and '-' prefixes
/// @param end_leaderp end of '!' and '-' prefixes
int handle_subscript(const char **const arg, typval_T *rettv, int evaluate, int verbose,
const char *const start_leader, const char **const end_leaderp)
int handle_subscript(const char **const arg, typval_T *rettv, int evaluate, int verbose)
{
int ret = OK;
dict_T *selfdict = NULL;
@ -6944,11 +6954,6 @@ int handle_subscript(const char **const arg, typval_T *rettv, int evaluate, int
tv_dict_unref(selfdict);
selfdict = NULL;
} else if (**arg == '-') {
// Expression "-1.0->method()" applies the leader "-" before
// applying ->.
if (evaluate && *end_leaderp > start_leader) {
ret = eval7_leader(rettv, (char *)start_leader, end_leaderp);
}
if (ret == OK) {
if ((*arg)[2] == '{') {
// expr->{lambda}()

View File

@ -3075,8 +3075,7 @@ void ex_call(exarg_T *eap)
}
// Handle a function returning a Funcref, Dictionary or List.
if (handle_subscript((const char **)&arg, &rettv, true, true,
(const char *)name, (const char **)&name)
if (handle_subscript((const char **)&arg, &rettv, true, true)
== FAIL) {
failed = true;
break;

View File

@ -508,7 +508,7 @@ static const char *list_arg_vars(exarg_T *eap, const char *arg, int *first)
} else {
// handle d.key, l[idx], f(expr)
const char *const arg_subsc = arg;
if (handle_subscript(&arg, &tv, true, true, name, &name) == FAIL) {
if (handle_subscript(&arg, &tv, true, true) == FAIL) {
error = true;
} else {
if (arg == arg_subsc && len == 2 && name[1] == ':') {
@ -1715,7 +1715,7 @@ bool var_exists(const char *var)
n = get_var_tv(name, len, &tv, NULL, false, true) == OK;
if (n) {
// Handle d.key, l[idx], f(expr).
n = handle_subscript(&var, &tv, true, false, name, &name) == OK;
n = handle_subscript(&var, &tv, true, false) == OK;
if (n) {
tv_clear(&tv);
}

View File

@ -111,6 +111,13 @@ func Test_special_char()
call assert_fails('echo "\<C-">')
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