From 9cfe8f6e68de4bfb5942d84f4465de914a747b3f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 17 Aug 2019 21:04:16 +0200 Subject: patch 8.1.1878: negative float before method not parsed correctly Problem: Negative float before method not parsed correctly. Solution: Apply "!" and "-" in front of expression before using ->. --- src/eval.c | 129 ++++++++++++++++++++++++++------------------ src/proto/eval.pro | 2 +- src/testdir/test_method.vim | 5 ++ src/userfunc.c | 5 +- src/version.c | 2 + 5 files changed, 87 insertions(+), 56 deletions(-) diff --git a/src/eval.c b/src/eval.c index 1967f9401c..b30f40490e 100644 --- a/src/eval.c +++ b/src/eval.c @@ -241,6 +241,7 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate); static int eval5(char_u **arg, typval_T *rettv, int evaluate); static int eval6(char_u **arg, typval_T *rettv, int evaluate, int want_string); static int eval7(char_u **arg, typval_T *rettv, int evaluate, int want_string); +static int eval7_leader(typval_T *rettv, char_u *start_leader, char_u **end_leaderp); static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate); static int get_lit_string_tv(char_u **arg, typval_T *rettv, int evaluate); @@ -1810,7 +1811,8 @@ list_arg_vars(exarg_T *eap, char_u *arg, int *first) { /* handle d.key, l[idx], f(expr) */ arg_subsc = arg; - if (handle_subscript(&arg, &tv, TRUE, TRUE) == FAIL) + if (handle_subscript(&arg, &tv, TRUE, TRUE, + name, &name) == FAIL) error = TRUE; else { @@ -4756,68 +4758,80 @@ eval7( /* Handle following '[', '(' and '.' for expr[expr], expr.name, * expr(expr), expr->name(expr) */ if (ret == OK) - ret = handle_subscript(arg, rettv, evaluate, TRUE); + ret = handle_subscript(arg, rettv, evaluate, TRUE, + start_leader, &end_leader); /* * Apply logical NOT and unary '-', from right to left, ignore '+'. */ if (ret == OK && evaluate && end_leader > start_leader) - { - int error = FALSE; - varnumber_T val = 0; + ret = eval7_leader(rettv, start_leader, &end_leader); + return ret; +} + +/* + * Apply the leading "!" and "-" before an eval7 expression to "rettv". + * Adjusts "end_leaderp" until it is at "start_leader". + */ + static int +eval7_leader(typval_T *rettv, char_u *start_leader, char_u **end_leaderp) +{ + char_u *end_leader = *end_leaderp; + int ret = OK; + int error = FALSE; + varnumber_T val = 0; #ifdef FEAT_FLOAT - float_T f = 0.0; + float_T f = 0.0; - if (rettv->v_type == VAR_FLOAT) - f = rettv->vval.v_float; - else + if (rettv->v_type == VAR_FLOAT) + f = rettv->vval.v_float; + else #endif - val = tv_get_number_chk(rettv, &error); - if (error) - { - clear_tv(rettv); - ret = FAIL; - } - else + val = tv_get_number_chk(rettv, &error); + if (error) + { + clear_tv(rettv); + ret = FAIL; + } + else + { + while (end_leader > start_leader) { - while (end_leader > start_leader) + --end_leader; + if (*end_leader == '!') { - --end_leader; - if (*end_leader == '!') - { #ifdef FEAT_FLOAT - if (rettv->v_type == VAR_FLOAT) - f = !f; - else + if (rettv->v_type == VAR_FLOAT) + f = !f; + else #endif - val = !val; - } - else if (*end_leader == '-') - { + val = !val; + } + else if (*end_leader == '-') + { #ifdef FEAT_FLOAT - if (rettv->v_type == VAR_FLOAT) - f = -f; - else + if (rettv->v_type == VAR_FLOAT) + f = -f; + else #endif - val = -val; - } + val = -val; } + } #ifdef FEAT_FLOAT - if (rettv->v_type == VAR_FLOAT) - { - clear_tv(rettv); - rettv->vval.v_float = f; - } - else + if (rettv->v_type == VAR_FLOAT) + { + clear_tv(rettv); + rettv->vval.v_float = f; + } + else #endif - { - clear_tv(rettv); - rettv->v_type = VAR_NUMBER; - rettv->vval.v_number = val; - } + { + clear_tv(rettv); + rettv->v_type = VAR_NUMBER; + rettv->vval.v_number = val; } } - + *end_leaderp = end_leader; return ret; } @@ -7539,8 +7553,10 @@ check_vars(char_u *name, int len) handle_subscript( char_u **arg, typval_T *rettv, - int evaluate, /* do more than finding the end */ - int verbose) /* give error messages */ + int evaluate, // 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 ret = OK; dict_T *selfdict = NULL; @@ -7576,12 +7592,19 @@ handle_subscript( } else if (**arg == '-') { - if ((*arg)[2] == '{') - // expr->{lambda}() - ret = eval_lambda(arg, rettv, evaluate, verbose); - else - // expr->name() - ret = eval_method(arg, rettv, evaluate, verbose); + // 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] == '{') + // expr->{lambda}() + ret = eval_lambda(arg, rettv, evaluate, verbose); + else + // expr->name() + ret = eval_method(arg, rettv, evaluate, verbose); + } } else /* **arg == '[' || **arg == '.' */ { @@ -9803,7 +9826,7 @@ var_exists(char_u *var) if (n) { /* handle d.key, l[idx], f(expr) */ - n = (handle_subscript(&var, &tv, TRUE, FALSE) == OK); + n = (handle_subscript(&var, &tv, TRUE, FALSE, name, &name) == OK); if (n) clear_tv(&tv); } diff --git a/src/proto/eval.pro b/src/proto/eval.pro index 6074c4ee2f..680b131841 100644 --- a/src/proto/eval.pro +++ b/src/proto/eval.pro @@ -85,7 +85,7 @@ char_u *v_exception(char_u *oldval); char_u *v_throwpoint(char_u *oldval); char_u *set_cmdarg(exarg_T *eap, char_u *oldarg); int get_var_tv(char_u *name, int len, typval_T *rettv, dictitem_T **dip, int verbose, int no_autoload); -int handle_subscript(char_u **arg, typval_T *rettv, int evaluate, int verbose); +int handle_subscript(char_u **arg, typval_T *rettv, int evaluate, int verbose, char_u *start_leader, char_u **end_leaderp); typval_T *alloc_tv(void); void free_tv(typval_T *varp); void clear_tv(typval_T *varp); diff --git a/src/testdir/test_method.vim b/src/testdir/test_method.vim index ba13bb4973..8c5f35b5ce 100644 --- a/src/testdir/test_method.vim +++ b/src/testdir/test_method.vim @@ -115,6 +115,11 @@ func Test_method_funcref() delfunc Concat endfunc +func Test_method_float() + eval 1.234->string()->assert_equal('1.234') + eval -1.234->string()->assert_equal('-1.234') +endfunc + func Test_method_syntax() eval [1, 2, 3] ->sort( ) eval [1, 2, 3] diff --git a/src/userfunc.c b/src/userfunc.c index fd25090118..bdd5c370d8 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -3165,8 +3165,9 @@ ex_call(exarg_T *eap) if (has_watchexpr()) dbg_check_breakpoint(eap); - /* Handle a function returning a Funcref, Dictionary or List. */ - if (handle_subscript(&arg, &rettv, !eap->skip, TRUE) == FAIL) + // Handle a function returning a Funcref, Dictionary or List. + if (handle_subscript(&arg, &rettv, !eap->skip, TRUE, + name, &name) == FAIL) { failed = TRUE; break; diff --git a/src/version.c b/src/version.c index b7d09aae6c..7242368f96 100644 --- a/src/version.c +++ b/src/version.c @@ -769,6 +769,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1878, /**/ 1877, /**/ -- cgit v1.2.3