# HG changeset patch # User Bram Moolenaar # Date 1592944204 -7200 # Node ID ae4b1d497a063ab4b0459aa055f50668191c3e43 # Parent bccc75504b67a0f42ff5ddb96f5dfe23d3fb6a31 patch 8.2.1045: Vim9: line break before operator does not work Commit: https://github.com/vim/vim/commit/67fbdfefd26a237831c3838f799d3e6198c8a34a Author: Bram Moolenaar Date: Tue Jun 23 22:26:05 2020 +0200 patch 8.2.1045: Vim9: line break before operator does not work Problem: Vim9: line break before operator does not work. Solution: Peek the next line for an operator. 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 @@ -13,6 +13,9 @@ def Test_expr1() assert_equal('one', 0.1 ? 'one' : 'two') endif assert_equal('one', 'x' ? 'one' : 'two') + assert_equal('one', 'x' + ? 'one' + : 'two') assert_equal('one', 0z1234 ? 'one' : 'two') assert_equal('one', [0] ? 'one' : 'two') assert_equal('one', #{x: 0} ? 'one' : 'two') @@ -70,6 +73,8 @@ def Test_expr2() 0 || 7) assert_equal(0, 0 || 0) + assert_equal(0, 0 + || 0) assert_equal('', 0 || '') g:vals = [] @@ -81,7 +86,9 @@ def Test_expr2() assert_equal([0, 5], g:vals) g:vals = [] - assert_equal(4, Record(0) || Record(4) || Record(0)) + assert_equal(4, Record(0) + || Record(4) + || Record(0)) assert_equal([0, 4], g:vals) g:vals = [] @@ -104,7 +111,9 @@ def Test_expr3() assert_equal(0, 0 && 0 && 7) - assert_equal(7, 2 && 3 && 7) + assert_equal(7, 2 + && 3 + && 7) assert_equal(0, 0 && 0) assert_equal(0, 0 && '') assert_equal('', 8 && '') @@ -158,7 +167,8 @@ def Test_expr4_equal() assert_equal(true, true == true) assert_equal(false, true == false) - assert_equal(true, true == trueVar) + assert_equal(true, true + == trueVar) assert_equal(false, true == falseVar) assert_equal(true, true == g:atrue) assert_equal(false, g:atrue == false) @@ -250,7 +260,8 @@ def Test_expr4_notequal() assert_equal(false, true != true) assert_equal(true, true != false) - assert_equal(false, true != trueVar) + assert_equal(false, true + != trueVar) assert_equal(true, true != falseVar) assert_equal(false, true != g:atrue) assert_equal(true, g:atrue != false) @@ -334,7 +345,8 @@ def Test_expr4_greater() assert_true(nr2 > 1) assert_false(nr2 > 2) - assert_false(nr2 > 3) + assert_false(nr2 + > 3) if has('float') let ff = 2.0 assert_true(ff > 0.0) @@ -367,7 +379,8 @@ def Test_expr4_smaller() assert_false(2 < 0) assert_false(2 < 2) - assert_true(2 < 3) + assert_true(2 + < 3) let nr2 = 2 assert_false(nr2 < 0) assert_false(nr2 < 2) @@ -385,7 +398,8 @@ def Test_expr4_smallerequal() assert_false(2 <= 0) assert_false(2 <= 1) - assert_true(2 <= 2) + assert_true(2 + <= 2) assert_true(2 <= 3) let nr2 = 2 assert_false(nr2 <= 0) @@ -404,6 +418,8 @@ enddef " test =~ comperator def Test_expr4_match() assert_equal(false, '2' =~ '0') + assert_equal(false, '' + =~ '0') assert_equal(true, '2' =~ '[0-9]') enddef @@ -411,6 +427,8 @@ enddef " test !~ comperator def Test_expr4_nomatch() assert_equal(true, '2' !~ '0') + assert_equal(true, '' + !~ '0') assert_equal(false, '2' !~ '[0-9]') enddef @@ -424,7 +442,8 @@ def Test_expr4_is() other) let myblob = 0z1234 - assert_false(myblob is 0z1234) + assert_false(myblob + is 0z1234) let otherblob = myblob assert_true(myblob is otherblob) enddef @@ -439,7 +458,8 @@ def Test_expr4_isnot() other) let myblob = 0z1234 - assert_true(myblob isnot 0z1234) + assert_true(myblob + isnot 0z1234) let otherblob = myblob assert_false(myblob isnot otherblob) enddef @@ -522,26 +542,30 @@ def Test_expr5() assert_equal(66, 60 + 6) assert_equal(70, 60 + g:anint) - assert_equal(9, g:alsoint + 5) + assert_equal(9, g:alsoint + + 5) assert_equal(14, g:alsoint + g:anint) assert_equal([1, 2, 3, 4], [1] + g:alist) assert_equal(54, 60 - 6) assert_equal(50, 60 - g:anint) - assert_equal(-1, g:alsoint - 5) + 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('hello 123', 'hello ' + .. 123) assert_equal('123 hello', 123 .. ' hello') assert_equal('123456', 123 .. 456) assert_equal([1, 2, 3, 4], [1, 2] + [3, 4]) assert_equal(0z11223344, 0z1122 + 0z3344) - assert_equal(0z112201ab, 0z1122 + g:ablob) + assert_equal(0z112201ab, 0z1122 + + g:ablob) assert_equal(0z01ab3344, g:ablob + 0z3344) assert_equal(0z01ab01ab, g:ablob + g:ablob) enddef @@ -554,13 +578,15 @@ def Test_expr5_float() assert_equal(66.0, 60.0 + 6) assert_equal(66.0, 60 + 6.0) - assert_equal(5.1, g:afloat + 5) + assert_equal(5.1, g:afloat + + 5) assert_equal(8.1, 8 + g:afloat) assert_equal(10.1, g:anint + g:afloat) assert_equal(10.1, g:afloat + g:anint) assert_equal(54.0, 60.0 - 6.0) - assert_equal(54.0, 60.0 - 6) + assert_equal(54.0, 60.0 + - 6) assert_equal(54.0, 60 - 6.0) assert_equal(-4.9, g:afloat - 5) assert_equal(7.9, 8 - g:afloat) @@ -599,20 +625,23 @@ def Test_expr6() assert_equal(36, 6 * 6) assert_equal(24, 6 * g:alsoint) - assert_equal(24, g:alsoint * 6) + 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(1, g:anint / 6) - assert_equal(2, g:anint / g:alsoint) + 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(2, g:anint % g:alsoint) + assert_equal(2, g:anint + % g:alsoint) assert_equal(4, 6 * 4 / 6) @@ -623,8 +652,10 @@ def Test_expr6() if has('float') let xf = [2.0] let yf = [3.0] - assert_equal(5.0, xf[0] + yf[0]) - assert_equal(6.0, xf[0] * yf[0]) + assert_equal(5.0, xf[0] + + yf[0]) + assert_equal(6.0, xf[0] + * yf[0]) endif call CheckDefFailure(["let x = 6 * xxx"], 'E1001') diff --git a/src/version.c b/src/version.c --- 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 */ /**/ + 1045, +/**/ 1044, /**/ 1043, diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -2414,6 +2414,27 @@ peek_next_line(cctx_T *cctx) } /* + * Called when checking for a following operator at "arg". When the rest of + * the line is empty or only a comment, peek the next line. If there is a next + * line return a pointer to it and set "nextp". + * Otherwise skip over white space. + */ + static char_u * +may_peek_next_line(cctx_T *cctx, char_u *arg, char_u **nextp) +{ + char_u *p = skipwhite(arg); + + *nextp = NULL; + if (*p == NUL || (VIM_ISWHITE(*arg) && comment_start(p))) + { + *nextp = peek_next_line(cctx); + if (*nextp != NULL) + return *nextp; + } + return p; +} + +/* * Get the next line of the function from "cctx". * Skips over empty lines. Skips over comment lines if "skip_comment" is TRUE. * Returns NULL when at the end. @@ -3947,6 +3968,7 @@ compile_expr7( compile_expr6(char_u **arg, cctx_T *cctx, ppconst_T *ppconst) { char_u *op; + char_u *next; int ppconst_used = ppconst->pp_used; // get the first expression @@ -3958,9 +3980,14 @@ compile_expr6(char_u **arg, cctx_T *cctx */ for (;;) { - op = skipwhite(*arg); + op = may_peek_next_line(cctx, *arg, &next); if (*op != '*' && *op != '/' && *op != '%') break; + if (next != NULL) + { + *arg = next_line_from_context(cctx, TRUE); + op = skipwhite(*arg); + } if (!IS_WHITE_OR_NUL(**arg) || !IS_WHITE_OR_NUL(op[1])) { @@ -4018,6 +4045,7 @@ compile_expr6(char_u **arg, cctx_T *cctx compile_expr5(char_u **arg, cctx_T *cctx, ppconst_T *ppconst) { char_u *op; + char_u *next; int oplen; int ppconst_used = ppconst->pp_used; @@ -4030,10 +4058,15 @@ compile_expr5(char_u **arg, cctx_T *cctx */ for (;;) { - op = skipwhite(*arg); - if (*op != '+' && *op != '-' && !(*op == '.' && (*(*arg + 1) == '.'))) + op = may_peek_next_line(cctx, *arg, &next); + if (*op != '+' && *op != '-' && !(*op == '.' && *(op + 1) == '.')) break; oplen = (*op == '.' ? 2 : 1); + if (next != NULL) + { + *arg = next_line_from_context(cctx, TRUE); + op = skipwhite(*arg); + } if (!IS_WHITE_OR_NUL(**arg) || !IS_WHITE_OR_NUL(op[oplen])) { @@ -4127,6 +4160,7 @@ compile_expr4(char_u **arg, cctx_T *cctx { exptype_T type = EXPR_UNKNOWN; char_u *p; + char_u *next; int len = 2; int type_is = FALSE; int ppconst_used = ppconst->pp_used; @@ -4135,7 +4169,7 @@ compile_expr4(char_u **arg, cctx_T *cctx if (compile_expr5(arg, cctx, ppconst) == FAIL) return FAIL; - p = skipwhite(*arg); + p = may_peek_next_line(cctx, *arg, &next); type = get_compare_type(p, &len, &type_is); /* @@ -4145,6 +4179,11 @@ compile_expr4(char_u **arg, cctx_T *cctx { int ic = FALSE; // Default: do not ignore case + if (next != NULL) + { + *arg = next_line_from_context(cctx, TRUE); + p = skipwhite(*arg); + } if (type_is && (p[len] == '?' || p[len] == '#')) { semsg(_(e_invexpr2), *arg); @@ -4221,7 +4260,8 @@ compile_and_or( ppconst_T *ppconst, int ppconst_used UNUSED) { - char_u *p = skipwhite(*arg); + char_u *next; + char_u *p = may_peek_next_line(cctx, *arg, &next); int opchar = *op; if (p[0] == opchar && p[1] == opchar) @@ -4235,6 +4275,12 @@ compile_and_or( ga_init2(&end_ga, sizeof(int), 10); while (p[0] == opchar && p[1] == opchar) { + if (next != NULL) + { + *arg = next_line_from_context(cctx, TRUE); + p = skipwhite(*arg); + } + if (!IS_WHITE_OR_NUL(**arg) || !IS_WHITE_OR_NUL(p[2])) { semsg(_(e_white_both), op); @@ -4265,7 +4311,8 @@ compile_and_or( ga_clear(&end_ga); return FAIL; } - p = skipwhite(*arg); + + p = may_peek_next_line(cctx, *arg, &next); } generate_ppconst(cctx, ppconst); @@ -4349,12 +4396,13 @@ compile_expr1(char_u **arg, cctx_T *cct { char_u *p; int ppconst_used = ppconst->pp_used; + char_u *next; // Evaluate the first expression. if (compile_expr2(arg, cctx, ppconst) == FAIL) return FAIL; - p = skipwhite(*arg); + p = may_peek_next_line(cctx, *arg, &next); if (*p == '?') { garray_T *instr = &cctx->ctx_instr; @@ -4368,6 +4416,12 @@ compile_expr1(char_u **arg, cctx_T *cct int const_value = FALSE; int save_skip = cctx->ctx_skip; + if (next != NULL) + { + *arg = next_line_from_context(cctx, TRUE); + p = skipwhite(*arg); + } + if (!IS_WHITE_OR_NUL(**arg) || !IS_WHITE_OR_NUL(p[1])) { semsg(_(e_white_both), "?"); @@ -4415,12 +4469,18 @@ compile_expr1(char_u **arg, cctx_T *cct } // Check for the ":". - p = skipwhite(*arg); + p = may_peek_next_line(cctx, *arg, &next); if (*p != ':') { emsg(_(e_missing_colon)); return FAIL; } + if (next != NULL) + { + *arg = next_line_from_context(cctx, TRUE); + p = skipwhite(*arg); + } + if (!IS_WHITE_OR_NUL(**arg) || !IS_WHITE_OR_NUL(p[1])) { semsg(_(e_white_both), ":");