changeset 20013:bf377a9ffccb v8.2.0562

patch 8.2.0562: Vim9: cannot split an expression into multiple lines Commit: https://github.com/vim/vim/commit/9c7e6dd653b62f54324f3c00d69cb348d8611a9f Author: Bram Moolenaar <Bram@vim.org> Date: Sun Apr 12 20:55:20 2020 +0200 patch 8.2.0562: Vim9: cannot split an expression into multiple lines Problem: Vim9: cannot split an expression into multiple lines. Solution: Continue in next line after an operator.
author Bram Moolenaar <Bram@vim.org>
date Sun, 12 Apr 2020 21:00:06 +0200
parents 19a396bfe96c
children 1609b2b2733d
files runtime/doc/vim9.txt src/macros.h src/testdir/test_vim9_expr.vim src/version.c src/vim9compile.c
diffstat 5 files changed, 120 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/vim9.txt
+++ b/runtime/doc/vim9.txt
@@ -195,6 +195,18 @@ Function call: >
 			arg2
 			)
 
+For binary operators iin expressions not in [], {} or () a line break is
+possible AFTER the operators.  For example: >
+	let text = lead ..
+		   middle ..
+		   end
+	let total = start +
+	            end -
+		    correction
+	let result = positive ?
+			PosFunc(arg) :
+			NegFunc(arg)
+
 Note that "enddef" cannot be used at the start of a continuation line, it ends
 the current function.
 
--- a/src/macros.h
+++ b/src/macros.h
@@ -37,10 +37,11 @@
 #define LTOREQ_POS(a, b) (LT_POS(a, b) || EQUAL_POS(a, b))
 
 /*
- * VIM_ISWHITE() is used for "^" and the like. It differs from isspace()
- * because it doesn't include <CR> and <LF> and the like.
+ * VIM_ISWHITE() differs from isspace() because it doesn't include <CR> and
+ * <LF> and the like.
  */
-#define VIM_ISWHITE(x)	((x) == ' ' || (x) == '\t')
+#define VIM_ISWHITE(x)		((x) == ' ' || (x) == '\t')
+#define IS_WHITE_OR_NUL(x)	((x) == ' ' || (x) == '\t' || (x) == NUL)
 
 /*
  * LINEEMPTY() - return TRUE if the line is empty
--- a/src/testdir/test_vim9_expr.vim
+++ b/src/testdir/test_vim9_expr.vim
@@ -32,7 +32,9 @@ endfunc
 " test cond ? expr : expr
 def Test_expr1()
   assert_equal('one', true ? 'one' : 'two')
-  assert_equal('one', 1 ? 'one' : 'two')
+  assert_equal('one', 1 ?
+			'one' :
+			'two')
   if has('float')
     assert_equal('one', 0.1 ? 'one' : 'two')
   endif
@@ -80,7 +82,9 @@ enddef
 " test ||
 def Test_expr2()
   assert_equal(2, 2 || 0)
-  assert_equal(7, 0 || 0 || 7)
+  assert_equal(7, 0 ||
+		    0 ||
+		    7)
   assert_equal(0, 0 || 0)
   assert_equal('', 0 || '')
 
@@ -113,7 +117,9 @@ endfunc
 " test &&
 def Test_expr3()
   assert_equal(0, 2 && 0)
-  assert_equal(0, 0 && 0 && 7)
+  assert_equal(0, 0 &&
+		0 &&
+		7)
   assert_equal(7, 2 && 3 && 7)
   assert_equal(0, 0 && 0)
   assert_equal(0, 0 && '')
@@ -164,7 +170,8 @@ let adict = #{aaa: 2, bbb: 8}
 " test == comperator
 def Test_expr4_equal()
   assert_equal(true, true == true)
-  assert_equal(false, true == false)
+  assert_equal(false, true ==
+			false)
   assert_equal(true, true == g:atrue)
   assert_equal(false, g:atrue == false)
 
@@ -237,7 +244,8 @@ enddef
 " test != comperator
 def Test_expr4_notequal()
   assert_equal(false, true != true)
-  assert_equal(true, true != false)
+  assert_equal(true, true !=
+			false)
   assert_equal(false, true != g:atrue)
   assert_equal(true, g:atrue != false)
 
@@ -303,7 +311,8 @@ enddef
 " test > comperator
 def Test_expr4_greater()
   assert_true(2 > 0)
-  assert_true(2 > 1)
+  assert_true(2 >
+		1)
   assert_false(2 > 2)
   assert_false(2 > 3)
   if has('float')
@@ -317,7 +326,8 @@ enddef
 " test >= comperator
 def Test_expr4_greaterequal()
   assert_true(2 >= 0)
-  assert_true(2 >= 2)
+  assert_true(2 >=
+			2)
   assert_false(2 >= 3)
   if has('float')
     assert_true(2.0 >= 0.0)
@@ -329,7 +339,8 @@ enddef
 " test < comperator
 def Test_expr4_smaller()
   assert_false(2 < 0)
-  assert_false(2 < 2)
+  assert_false(2 <
+			2)
   assert_true(2 < 3)
   if has('float')
     assert_false(2.0 < 0.0)
@@ -341,7 +352,8 @@ enddef
 " test <= comperator
 def Test_expr4_smallerequal()
   assert_false(2 <= 0)
-  assert_false(2 <= 1)
+  assert_false(2 <=
+			1)
   assert_true(2 <= 2)
   assert_true(2 <= 3)
   if has('float')
@@ -355,13 +367,15 @@ enddef
 " test =~ comperator
 def Test_expr4_match()
   assert_equal(false, '2' =~ '0')
-  assert_equal(true, '2' =~ '[0-9]')
+  assert_equal(true, '2' =~
+			'[0-9]')
 enddef
 
 " test !~ comperator
 def Test_expr4_nomatch()
   assert_equal(true, '2' !~ '0')
-  assert_equal(false, '2' !~ '[0-9]')
+  assert_equal(false, '2' !~
+			'[0-9]')
 enddef
 
 " test is comperator
@@ -369,7 +383,8 @@ def Test_expr4_is()
   let mylist = [2]
   assert_false(mylist is [2])
   let other = mylist
-  assert_true(mylist is other)
+  assert_true(mylist is
+		other)
 
   let myblob = 0z1234
   assert_false(myblob is 0z1234)
@@ -383,7 +398,8 @@ def Test_expr4_isnot()
   assert_true('2' isnot '0')
   assert_true(mylist isnot [2])
   let other = mylist
-  assert_false(mylist isnot other)
+  assert_false(mylist isnot
+			other)
 
   let myblob = 0z1234
   assert_true(myblob isnot 0z1234)
@@ -467,17 +483,20 @@ endfunc
 " test addition, subtraction, concatenation
 def Test_expr5()
   assert_equal(66, 60 + 6)
-  assert_equal(70, 60 + g:anint)
+  assert_equal(70, 60 +
+			g:anint)
   assert_equal(9, g:alsoint + 5)
   assert_equal(14, g:alsoint + g:anint)
 
   assert_equal(54, 60 - 6)
-  assert_equal(50, 60 - g:anint)
+  assert_equal(50, 60 -
+		    g:anint)
   assert_equal(-1, g:alsoint - 5)
   assert_equal(-6, g:alsoint - g:anint)
 
   assert_equal('hello', 'hel' .. 'lo')
-  assert_equal('hello 123', 'hello ' .. 123)
+  assert_equal('hello 123', 'hello ' ..
+					123)
   assert_equal('123 hello', 123 .. ' hello')
   assert_equal('123456', 123 .. 456)
 
@@ -494,7 +513,8 @@ def Test_expr5_float()
   else
     assert_equal(66.0, 60.0 + 6.0)
     assert_equal(66.0, 60.0 + 6)
-    assert_equal(66.0, 60 + 6.0)
+    assert_equal(66.0, 60 +
+			 6.0)
     assert_equal(5.1, g:afloat + 5)
     assert_equal(8.1, 8 + g:afloat)
     assert_equal(10.1, g:anint + g:afloat)
@@ -538,18 +558,21 @@ endfunc
 " test multiply, divide, modulo
 def Test_expr6()
   assert_equal(36, 6 * 6)
-  assert_equal(24, 6 * g:alsoint)
+  assert_equal(24, 6 *
+			g:alsoint)
   assert_equal(24, g:alsoint * 6)
   assert_equal(40, g:anint * g:alsoint)
 
   assert_equal(10, 60 / 6)
-  assert_equal(6, 60 / g:anint)
+  assert_equal(6, 60 /
+			g:anint)
   assert_equal(1, g:anint / 6)
   assert_equal(2, g:anint / g:alsoint)
 
   assert_equal(5, 11 % 6)
   assert_equal(4, g:anint % 6)
-  assert_equal(3, 13 % g:anint)
+  assert_equal(3, 13 %
+			g:anint)
   assert_equal(2, g:anint % g:alsoint)
 
   assert_equal(4, 6 * 4 / 6)
@@ -573,17 +596,21 @@ def Test_expr6_float()
     MissingFeature 'float'
   else
     assert_equal(36.0, 6.0 * 6)
-    assert_equal(36.0, 6 * 6.0)
+    assert_equal(36.0, 6 *
+			   6.0)
     assert_equal(36.0, 6.0 * 6.0)
     assert_equal(1.0, g:afloat * g:anint)
 
     assert_equal(10.0, 60 / 6.0)
-    assert_equal(10.0, 60.0 / 6)
+    assert_equal(10.0, 60.0 /
+			6)
     assert_equal(10.0, 60.0 / 6.0)
     assert_equal(0.01, g:afloat / g:anint)
 
     assert_equal(4.0, 6.0 * 4 / 6)
-    assert_equal(4.0, 6 * 4.0 / 6)
+    assert_equal(4.0, 6 *
+			4.0 /
+			6)
     assert_equal(4.0, 6 * 4 / 6.0)
     assert_equal(4.0, 6.0 * 4.0 / 6)
     assert_equal(4.0, 6 * 4.0 / 6.0)
--- a/src/version.c
+++ b/src/version.c
@@ -739,6 +739,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    562,
+/**/
     561,
 /**/
     560,
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -2070,6 +2070,24 @@ next_line_from_context(cctx_T *cctx)
 }
 
 /*
+ * If "*arg" is at the end of the line, advance to the next line.
+ * Return FAIL if beyond the last line, "*arg" is unmodified then.
+ */
+    static int
+may_get_next_line(char_u **arg, cctx_T *cctx)
+{
+    if (**arg == NUL)
+    {
+	char_u *next = next_line_from_context(cctx);
+
+	if (next == NULL)
+	    return FAIL;
+	*arg = skipwhite(next);
+    }
+    return OK;
+}
+
+/*
  * Generate an instruction to load script-local variable "name", without the
  * leading "s:".
  * Also finds imported variables.
@@ -3394,14 +3412,17 @@ compile_expr6(char_u **arg, cctx_T *cctx
 	op = skipwhite(*arg);
 	if (*op != '*' && *op != '/' && *op != '%')
 	    break;
-	if (!VIM_ISWHITE(**arg) || !VIM_ISWHITE(op[1]))
+	if (!IS_WHITE_OR_NUL(**arg) || !IS_WHITE_OR_NUL(op[1]))
 	{
 	    char_u buf[3];
 
 	    vim_strncpy(buf, op, 1);
 	    semsg(_(e_white_both), buf);
+	    return FAIL;
 	}
 	*arg = skipwhite(op + 1);
+	if (may_get_next_line(arg, cctx) == FAIL)
+	    return FAIL;
 
 	// get the second variable
 	if (compile_expr7(arg, cctx) == FAIL)
@@ -3438,15 +3459,18 @@ compile_expr5(char_u **arg, cctx_T *cctx
 	    break;
 	oplen = (*op == '.' ? 2 : 1);
 
-	if (!VIM_ISWHITE(**arg) || !VIM_ISWHITE(op[oplen]))
+	if (!IS_WHITE_OR_NUL(**arg) || !IS_WHITE_OR_NUL(op[oplen]))
 	{
 	    char_u buf[3];
 
 	    vim_strncpy(buf, op, oplen);
 	    semsg(_(e_white_both), buf);
+	    return FAIL;
 	}
 
 	*arg = skipwhite(op + oplen);
+	if (may_get_next_line(arg, cctx) == FAIL)
+	    return FAIL;
 
 	// get the second variable
 	if (compile_expr6(arg, cctx) == FAIL)
@@ -3572,16 +3596,20 @@ compile_expr4(char_u **arg, cctx_T *cctx
 	    ++len;
 	// nothing appended: match case
 
-	if (!VIM_ISWHITE(**arg) || !VIM_ISWHITE(p[len]))
+	if (!IS_WHITE_OR_NUL(**arg) || !IS_WHITE_OR_NUL(p[len]))
 	{
 	    char_u buf[7];
 
 	    vim_strncpy(buf, p, len);
 	    semsg(_(e_white_both), buf);
+	    return FAIL;
 	}
 
 	// get the second variable
 	*arg = skipwhite(p + len);
+	if (may_get_next_line(arg, cctx) == FAIL)
+	    return FAIL;
+
 	if (compile_expr5(arg, cctx) == FAIL)
 	    return FAIL;
 
@@ -3611,8 +3639,11 @@ compile_and_or(char_u **arg, cctx_T *cct
 	ga_init2(&end_ga, sizeof(int), 10);
 	while (p[0] == opchar && p[1] == opchar)
 	{
-	    if (!VIM_ISWHITE(**arg) || !VIM_ISWHITE(p[2]))
+	    if (!IS_WHITE_OR_NUL(**arg) || !IS_WHITE_OR_NUL(p[2]))
+	    {
 		semsg(_(e_white_both), op);
+		return FAIL;
+	    }
 
 	    if (ga_grow(&end_ga, 1) == FAIL)
 	    {
@@ -3626,6 +3657,9 @@ compile_and_or(char_u **arg, cctx_T *cct
 
 	    // eval the next expression
 	    *arg = skipwhite(p + 2);
+	    if (may_get_next_line(arg, cctx) == FAIL)
+		return FAIL;
+
 	    if ((opchar == '|' ? compile_expr3(arg, cctx)
 					   : compile_expr4(arg, cctx)) == FAIL)
 	    {
@@ -3726,13 +3760,19 @@ compile_expr1(char_u **arg,  cctx_T *cct
 	type_T		*type1;
 	type_T		*type2;
 
-	if (!VIM_ISWHITE(**arg) || !VIM_ISWHITE(p[1]))
+	if (!IS_WHITE_OR_NUL(**arg) || !IS_WHITE_OR_NUL(p[1]))
+	{
 	    semsg(_(e_white_both), "?");
+	    return FAIL;
+	}
 
 	generate_JUMP(cctx, JUMP_IF_FALSE, 0);
 
 	// evaluate the second expression; any type is accepted
 	*arg = skipwhite(p + 1);
+	if (may_get_next_line(arg, cctx) == FAIL)
+	    return FAIL;
+
 	if (compile_expr1(arg, cctx) == FAIL)
 	    return FAIL;
 
@@ -3754,11 +3794,17 @@ compile_expr1(char_u **arg,  cctx_T *cct
 	    emsg(_(e_missing_colon));
 	    return FAIL;
 	}
-	if (!VIM_ISWHITE(**arg) || !VIM_ISWHITE(p[1]))
+	if (!IS_WHITE_OR_NUL(**arg) || !IS_WHITE_OR_NUL(p[1]))
+	{
 	    semsg(_(e_white_both), ":");
+	    return FAIL;
+	}
 
 	// evaluate the third expression
 	*arg = skipwhite(p + 1);
+	if (may_get_next_line(arg, cctx) == FAIL)
+	    return FAIL;
+
 	if (compile_expr1(arg, cctx) == FAIL)
 	    return FAIL;