changeset 17763:117c7795a979 v8.1.1878

patch 8.1.1878: negative float before method not parsed correctly commit https://github.com/vim/vim/commit/9cfe8f6e68de4bfb5942d84f4465de914a747b3f Author: Bram Moolenaar <Bram@vim.org> Date: Sat Aug 17 21:04:16 2019 +0200 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 ->.
author Bram Moolenaar <Bram@vim.org>
date Sat, 17 Aug 2019 21:15:03 +0200
parents 87d3311b3401
children 3a5933d7d4a4
files src/eval.c src/proto/eval.pro src/testdir/test_method.vim src/userfunc.c src/version.c
diffstat 5 files changed, 94 insertions(+), 63 deletions(-) [+]
line wrap: on
line diff
--- a/src/eval.c
+++ b/src/eval.c
@@ -241,6 +241,7 @@ static int eval4(char_u **arg, typval_T 
 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,
 		{
 		    /* 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
+#endif
+	val = tv_get_number_chk(rettv, &error);
+    if (error)
+    {
+	clear_tv(rettv);
+	ret = FAIL;
+    }
+    else
+    {
+	while (end_leader > start_leader)
+	{
+	    --end_leader;
+	    if (*end_leader == '!')
+	    {
+#ifdef FEAT_FLOAT
+		if (rettv->v_type == VAR_FLOAT)
+		    f = !f;
+		else
+#endif
+		    val = !val;
+	    }
+	    else if (*end_leader == '-')
+	    {
+#ifdef FEAT_FLOAT
+		if (rettv->v_type == VAR_FLOAT)
+		    f = -f;
+		else
+#endif
+		    val = -val;
+	    }
+	}
+#ifdef FEAT_FLOAT
 	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;
+	    rettv->vval.v_float = f;
 	}
 	else
-	{
-	    while (end_leader > start_leader)
-	    {
-		--end_leader;
-		if (*end_leader == '!')
-		{
-#ifdef FEAT_FLOAT
-		    if (rettv->v_type == VAR_FLOAT)
-			f = !f;
-		    else
 #endif
-			val = !val;
-		}
-		else if (*end_leader == '-')
-		{
-#ifdef FEAT_FLOAT
-		    if (rettv->v_type == VAR_FLOAT)
-			f = -f;
-		    else
-#endif
-			val = -val;
-		}
-	    }
-#ifdef FEAT_FLOAT
-	    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);
 	}
--- 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);
--- 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]  
--- 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;
--- a/src/version.c
+++ b/src/version.c
@@ -770,6 +770,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1878,
+/**/
     1877,
 /**/
     1876,