# HG changeset patch # User Bram Moolenaar # Date 1586718006 -7200 # Node ID bf377a9ffccb2cab3e671b39a19815944663406f # Parent 19a396bfe96cce8737f0102703cc296008bad6ff patch 8.2.0562: Vim9: cannot split an expression into multiple lines Commit: https://github.com/vim/vim/commit/9c7e6dd653b62f54324f3c00d69cb348d8611a9f Author: Bram Moolenaar 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. diff --git a/runtime/doc/vim9.txt b/runtime/doc/vim9.txt --- 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. diff --git a/src/macros.h b/src/macros.h --- 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 and and the like. + * VIM_ISWHITE() differs from isspace() because it doesn't include and + * 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 diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim --- 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) diff --git a/src/version.c b/src/version.c --- 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, diff --git a/src/vim9compile.c b/src/vim9compile.c --- 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;