changeset 21739:caf0286cf02b v8.2.1419

patch 8.2.1419: Vim9: not operator applied too early Commit: https://github.com/vim/vim/commit/59eccb92e3c68f65525e08d2113213ff7d7ed00a Author: Bram Moolenaar <Bram@vim.org> Date: Mon Aug 10 23:09:37 2020 +0200 patch 8.2.1419: Vim9: not operator applied too early Problem: Vim9: not operator applied too early. Solution: Implement the "numeric_only" argument. (closes https://github.com/vim/vim/issues/6680)
author Bram Moolenaar <Bram@vim.org>
date Mon, 10 Aug 2020 23:15:03 +0200
parents c7693230fb82
children 54928f1c0d20
files src/testdir/test_vim9_expr.vim src/version.c src/vim9compile.c
diffstat 3 files changed, 37 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/src/testdir/test_vim9_expr.vim
+++ b/src/testdir/test_vim9_expr.vim
@@ -1744,7 +1744,7 @@ def Test_expr7_call()
   assert_equal('yes', 'yes'->Echo())
   assert_equal('yes', 'yes'
   			->s:Echo4Arg())
-  assert_equal(1, !range(5)->empty())
+  assert_equal(true, !range(5)->empty())
   assert_equal([0, 1, 2], --3->range())
 
   call CheckDefFailure(["let x = 'yes'->Echo"], 'E107:')
@@ -1782,6 +1782,9 @@ def Test_expr7_not()
 
       assert_equal(true, !test_void())
       assert_equal(true, !test_unknown())
+
+      assert_equal(false, ![1, 2, 3]->reverse())
+      assert_equal(true, ![]->reverse())
   END
   CheckDefSuccess(lines)
   CheckScriptSuccess(['vim9script'] + lines)
--- a/src/version.c
+++ b/src/version.c
@@ -755,6 +755,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1419,
+/**/
     1418,
 /**/
     1417,
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -2723,11 +2723,12 @@ compile_get_register(char_u **arg, cctx_
 
 /*
  * Apply leading '!', '-' and '+' to constant "rettv".
+ * When "numeric_only" is TRUE do not apply '!'.
  */
     static int
-apply_leader(typval_T *rettv, char_u *start, char_u *end)
-{
-    char_u *p = end;
+apply_leader(typval_T *rettv, int numeric_only, char_u *start, char_u **end)
+{
+    char_u *p = *end;
 
     // this works from end to start
     while (p > start)
@@ -2762,6 +2763,11 @@ apply_leader(typval_T *rettv, char_u *st
 		rettv->vval.v_number = val;
 	    }
 	}
+	else if (numeric_only)
+	{
+	    ++p;
+	    break;
+	}
 	else
 	{
 	    int v = tv2bool(rettv);
@@ -2772,6 +2778,7 @@ apply_leader(typval_T *rettv, char_u *st
 	    rettv->vval.v_number = v ? VVAL_FALSE : VVAL_TRUE;
 	}
     }
+    *end = p;
     return OK;
 }
 
@@ -2860,11 +2867,12 @@ get_compare_type(char_u *p, int *len, in
 
 /*
  * Compile code to apply '-', '+' and '!'.
+ * When "numeric_only" is TRUE do not apply '!'.
  */
     static int
-compile_leader(cctx_T *cctx, char_u *start, char_u *end)
-{
-    char_u	*p = end;
+compile_leader(cctx_T *cctx, int numeric_only, char_u *start, char_u **end)
+{
+    char_u	*p = *end;
 
     // this works from end to start
     while (p > start)
@@ -2890,6 +2898,11 @@ compile_leader(cctx_T *cctx, char_u *sta
 	    if (isn == NULL)
 		return FAIL;
 	}
+	else if (numeric_only)
+	{
+	    ++p;
+	    break;
+	}
 	else
 	{
 	    int  invert = TRUE;
@@ -2903,6 +2916,7 @@ compile_leader(cctx_T *cctx, char_u *sta
 		return FAIL;
 	}
     }
+    *end = p;
     return OK;
 }
 
@@ -2914,10 +2928,12 @@ compile_leader(cctx_T *cctx, char_u *sta
 compile_subscript(
 	char_u **arg,
 	cctx_T *cctx,
-	char_u **start_leader,
-	char_u *end_leader,
+	char_u *start_leader,
+	char_u **end_leader,
 	ppconst_T *ppconst)
 {
+    char_u	*name_start = *end_leader;
+
     for (;;)
     {
 	char_u *p = skipwhite(*arg);
@@ -2959,7 +2975,7 @@ compile_subscript(
 	    *arg = skipwhite(p + 1);
 	    if (compile_arguments(arg, cctx, &argcount) == FAIL)
 		return FAIL;
-	    if (generate_PCALL(cctx, argcount, end_leader, type, TRUE) == FAIL)
+	    if (generate_PCALL(cctx, argcount, name_start, type, TRUE) == FAIL)
 		return FAIL;
 	}
 	else if (*p == '-' && p[1] == '>')
@@ -2972,9 +2988,8 @@ compile_subscript(
 	    // something->method()
 	    // Apply the '!', '-' and '+' first:
 	    //   -1.0->func() works like (-1.0)->func()
-	    if (compile_leader(cctx, *start_leader, end_leader) == FAIL)
+	    if (compile_leader(cctx, TRUE, start_leader, end_leader) == FAIL)
 		return FAIL;
-	    *start_leader = end_leader;   // don't apply again later
 
 	    p += 2;
 	    *arg = skipwhite(p);
@@ -3329,13 +3344,12 @@ compile_expr7(
 
     if (rettv->v_type != VAR_UNKNOWN && used_before == ppconst->pp_used)
     {
-	// apply the '!', '-' and '+' before the constant
-	if (apply_leader(rettv, start_leader, end_leader) == FAIL)
+	// apply the '-' and '+' before the constant, but not '!'
+	if (apply_leader(rettv, TRUE, start_leader, &end_leader) == FAIL)
 	{
 	    clear_tv(rettv);
 	    return FAIL;
 	}
-	start_leader = end_leader;   // don't apply again below
 
 	if (cctx->ctx_skip == SKIP_YES)
 	    clear_tv(rettv);
@@ -3373,18 +3387,18 @@ compile_expr7(
 
     // Handle following "[]", ".member", etc.
     // Then deal with prefixed '-', '+' and '!', if not done already.
-    if (compile_subscript(arg, cctx, &start_leader, end_leader,
+    if (compile_subscript(arg, cctx, start_leader, &end_leader,
 							     ppconst) == FAIL)
 	return FAIL;
     if (ppconst->pp_used > 0)
     {
 	// apply the '!', '-' and '+' before the constant
 	rettv = &ppconst->pp_tv[ppconst->pp_used - 1];
-	if (apply_leader(rettv, start_leader, end_leader) == FAIL)
+	if (apply_leader(rettv, FALSE, start_leader, &end_leader) == FAIL)
 	    return FAIL;
 	return OK;
     }
-    if (compile_leader(cctx, start_leader, end_leader) == FAIL)
+    if (compile_leader(cctx, FALSE, start_leader, &end_leader) == FAIL)
 	return FAIL;
     return OK;
 }