]> granicus.if.org Git - vim/commitdiff
patch 8.1.1878: negative float before method not parsed correctly v8.1.1878
authorBram Moolenaar <Bram@vim.org>
Sat, 17 Aug 2019 19:04:16 +0000 (21:04 +0200)
committerBram Moolenaar <Bram@vim.org>
Sat, 17 Aug 2019 19:04:16 +0000 (21:04 +0200)
Problem:    Negative float before method not parsed correctly.
Solution:   Apply "!" and "-" in front of expression before using ->.

src/eval.c
src/proto/eval.pro
src/testdir/test_method.vim
src/userfunc.c
src/version.c

index 1967f9401c8cac86164c47894e298c661bf6ea7a..b30f40490e34f24346340bc99ba46ddd860ebebd 100644 (file)
@@ -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);
        }
index 6074c4ee2f7d517f02377f4fae8bdb885a0d5358..680b131841087a381889f02ec41deecca49fd41a 100644 (file)
@@ -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);
index ba13bb49730d6b2bd6f2db3ea2c636306f7ba33c..8c5f35b5ce4af049b09beba602d52bb3d2ea6216 100644 (file)
@@ -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]  
index fd25090118cca46761c7689757dd792a56374374..bdd5c370d8a9b33348e4c0e3d8d75ba965bde6f2 100644 (file)
@@ -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;
index b7d09aae6c8db3e6e73df87494aac00a2271c27d..7242368f9633bc5b5fb86acc179f6bb51bb682f2 100644 (file)
@@ -769,6 +769,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1878,
 /**/
     1877,
 /**/