1
0
forked from aniani/vim

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.
This commit is contained in:
Bram Moolenaar 2020-04-12 20:55:20 +02:00
parent e6085c5350
commit 9c7e6dd653
5 changed files with 120 additions and 32 deletions

View File

@ -195,6 +195,18 @@ Function call: >
arg2 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 Note that "enddef" cannot be used at the start of a continuation line, it ends
the current function. the current function.

View File

@ -37,10 +37,11 @@
#define LTOREQ_POS(a, b) (LT_POS(a, b) || EQUAL_POS(a, b)) #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() * VIM_ISWHITE() differs from isspace() because it doesn't include <CR> and
* because it doesn't include <CR> and <LF> and the like. * <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 * LINEEMPTY() - return TRUE if the line is empty

View File

@ -32,7 +32,9 @@ endfunc
" test cond ? expr : expr " test cond ? expr : expr
def Test_expr1() def Test_expr1()
assert_equal('one', true ? 'one' : 'two') assert_equal('one', true ? 'one' : 'two')
assert_equal('one', 1 ? 'one' : 'two') assert_equal('one', 1 ?
'one' :
'two')
if has('float') if has('float')
assert_equal('one', 0.1 ? 'one' : 'two') assert_equal('one', 0.1 ? 'one' : 'two')
endif endif
@ -80,7 +82,9 @@ enddef
" test || " test ||
def Test_expr2() def Test_expr2()
assert_equal(2, 2 || 0) 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, 0 || 0)
assert_equal('', 0 || '') assert_equal('', 0 || '')
@ -113,7 +117,9 @@ endfunc
" test && " test &&
def Test_expr3() def Test_expr3()
assert_equal(0, 2 && 0) 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(7, 2 && 3 && 7)
assert_equal(0, 0 && 0) assert_equal(0, 0 && 0)
assert_equal(0, 0 && '') assert_equal(0, 0 && '')
@ -164,7 +170,8 @@ let adict = #{aaa: 2, bbb: 8}
" test == comperator " test == comperator
def Test_expr4_equal() def Test_expr4_equal()
assert_equal(true, true == true) assert_equal(true, true == true)
assert_equal(false, true == false) assert_equal(false, true ==
false)
assert_equal(true, true == g:atrue) assert_equal(true, true == g:atrue)
assert_equal(false, g:atrue == false) assert_equal(false, g:atrue == false)
@ -237,7 +244,8 @@ enddef
" test != comperator " test != comperator
def Test_expr4_notequal() def Test_expr4_notequal()
assert_equal(false, true != true) assert_equal(false, true != true)
assert_equal(true, true != false) assert_equal(true, true !=
false)
assert_equal(false, true != g:atrue) assert_equal(false, true != g:atrue)
assert_equal(true, g:atrue != false) assert_equal(true, g:atrue != false)
@ -303,7 +311,8 @@ enddef
" test > comperator " test > comperator
def Test_expr4_greater() def Test_expr4_greater()
assert_true(2 > 0) assert_true(2 > 0)
assert_true(2 > 1) assert_true(2 >
1)
assert_false(2 > 2) assert_false(2 > 2)
assert_false(2 > 3) assert_false(2 > 3)
if has('float') if has('float')
@ -317,7 +326,8 @@ enddef
" test >= comperator " test >= comperator
def Test_expr4_greaterequal() def Test_expr4_greaterequal()
assert_true(2 >= 0) assert_true(2 >= 0)
assert_true(2 >= 2) assert_true(2 >=
2)
assert_false(2 >= 3) assert_false(2 >= 3)
if has('float') if has('float')
assert_true(2.0 >= 0.0) assert_true(2.0 >= 0.0)
@ -329,7 +339,8 @@ enddef
" test < comperator " test < comperator
def Test_expr4_smaller() def Test_expr4_smaller()
assert_false(2 < 0) assert_false(2 < 0)
assert_false(2 < 2) assert_false(2 <
2)
assert_true(2 < 3) assert_true(2 < 3)
if has('float') if has('float')
assert_false(2.0 < 0.0) assert_false(2.0 < 0.0)
@ -341,7 +352,8 @@ enddef
" test <= comperator " test <= comperator
def Test_expr4_smallerequal() def Test_expr4_smallerequal()
assert_false(2 <= 0) assert_false(2 <= 0)
assert_false(2 <= 1) assert_false(2 <=
1)
assert_true(2 <= 2) assert_true(2 <= 2)
assert_true(2 <= 3) assert_true(2 <= 3)
if has('float') if has('float')
@ -355,13 +367,15 @@ enddef
" test =~ comperator " test =~ comperator
def Test_expr4_match() def Test_expr4_match()
assert_equal(false, '2' =~ '0') assert_equal(false, '2' =~ '0')
assert_equal(true, '2' =~ '[0-9]') assert_equal(true, '2' =~
'[0-9]')
enddef enddef
" test !~ comperator " test !~ comperator
def Test_expr4_nomatch() def Test_expr4_nomatch()
assert_equal(true, '2' !~ '0') assert_equal(true, '2' !~ '0')
assert_equal(false, '2' !~ '[0-9]') assert_equal(false, '2' !~
'[0-9]')
enddef enddef
" test is comperator " test is comperator
@ -369,7 +383,8 @@ def Test_expr4_is()
let mylist = [2] let mylist = [2]
assert_false(mylist is [2]) assert_false(mylist is [2])
let other = mylist let other = mylist
assert_true(mylist is other) assert_true(mylist is
other)
let myblob = 0z1234 let myblob = 0z1234
assert_false(myblob is 0z1234) assert_false(myblob is 0z1234)
@ -383,7 +398,8 @@ def Test_expr4_isnot()
assert_true('2' isnot '0') assert_true('2' isnot '0')
assert_true(mylist isnot [2]) assert_true(mylist isnot [2])
let other = mylist let other = mylist
assert_false(mylist isnot other) assert_false(mylist isnot
other)
let myblob = 0z1234 let myblob = 0z1234
assert_true(myblob isnot 0z1234) assert_true(myblob isnot 0z1234)
@ -467,17 +483,20 @@ endfunc
" test addition, subtraction, concatenation " test addition, subtraction, concatenation
def Test_expr5() def Test_expr5()
assert_equal(66, 60 + 6) 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(9, g:alsoint + 5)
assert_equal(14, g:alsoint + g:anint) assert_equal(14, g:alsoint + g:anint)
assert_equal(54, 60 - 6) 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(-1, g:alsoint - 5)
assert_equal(-6, g:alsoint - g:anint) assert_equal(-6, g:alsoint - g:anint)
assert_equal('hello', 'hel' .. 'lo') 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('123 hello', 123 .. ' hello')
assert_equal('123456', 123 .. 456) assert_equal('123456', 123 .. 456)
@ -494,7 +513,8 @@ def Test_expr5_float()
else else
assert_equal(66.0, 60.0 + 6.0) assert_equal(66.0, 60.0 + 6.0)
assert_equal(66.0, 60.0 + 6) 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(5.1, g:afloat + 5)
assert_equal(8.1, 8 + g:afloat) assert_equal(8.1, 8 + g:afloat)
assert_equal(10.1, g:anint + g:afloat) assert_equal(10.1, g:anint + g:afloat)
@ -538,18 +558,21 @@ endfunc
" test multiply, divide, modulo " test multiply, divide, modulo
def Test_expr6() def Test_expr6()
assert_equal(36, 6 * 6) 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(24, g:alsoint * 6)
assert_equal(40, g:anint * g:alsoint) assert_equal(40, g:anint * g:alsoint)
assert_equal(10, 60 / 6) 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(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(5, 11 % 6)
assert_equal(4, g:anint % 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(2, g:anint % g:alsoint)
assert_equal(4, 6 * 4 / 6) assert_equal(4, 6 * 4 / 6)
@ -573,17 +596,21 @@ def Test_expr6_float()
MissingFeature 'float' MissingFeature 'float'
else else
assert_equal(36.0, 6.0 * 6) 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(36.0, 6.0 * 6.0)
assert_equal(1.0, g:afloat * g:anint) assert_equal(1.0, g:afloat * g:anint)
assert_equal(10.0, 60 / 6.0) 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(10.0, 60.0 / 6.0)
assert_equal(0.01, g:afloat / g:anint) assert_equal(0.01, g:afloat / g:anint)
assert_equal(4.0, 6.0 * 4 / 6) 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 * 4 / 6.0)
assert_equal(4.0, 6.0 * 4.0 / 6) assert_equal(4.0, 6.0 * 4.0 / 6)
assert_equal(4.0, 6 * 4.0 / 6.0) assert_equal(4.0, 6 * 4.0 / 6.0)

View File

@ -738,6 +738,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
562,
/**/ /**/
561, 561,
/**/ /**/

View File

@ -2069,6 +2069,24 @@ next_line_from_context(cctx_T *cctx)
return line; return line;
} }
/*
* 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 * Generate an instruction to load script-local variable "name", without the
* leading "s:". * leading "s:".
@ -3394,14 +3412,17 @@ compile_expr6(char_u **arg, cctx_T *cctx)
op = skipwhite(*arg); op = skipwhite(*arg);
if (*op != '*' && *op != '/' && *op != '%') if (*op != '*' && *op != '/' && *op != '%')
break; 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]; char_u buf[3];
vim_strncpy(buf, op, 1); vim_strncpy(buf, op, 1);
semsg(_(e_white_both), buf); semsg(_(e_white_both), buf);
return FAIL;
} }
*arg = skipwhite(op + 1); *arg = skipwhite(op + 1);
if (may_get_next_line(arg, cctx) == FAIL)
return FAIL;
// get the second variable // get the second variable
if (compile_expr7(arg, cctx) == FAIL) if (compile_expr7(arg, cctx) == FAIL)
@ -3438,15 +3459,18 @@ compile_expr5(char_u **arg, cctx_T *cctx)
break; break;
oplen = (*op == '.' ? 2 : 1); 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]; char_u buf[3];
vim_strncpy(buf, op, oplen); vim_strncpy(buf, op, oplen);
semsg(_(e_white_both), buf); semsg(_(e_white_both), buf);
return FAIL;
} }
*arg = skipwhite(op + oplen); *arg = skipwhite(op + oplen);
if (may_get_next_line(arg, cctx) == FAIL)
return FAIL;
// get the second variable // get the second variable
if (compile_expr6(arg, cctx) == FAIL) if (compile_expr6(arg, cctx) == FAIL)
@ -3572,16 +3596,20 @@ compile_expr4(char_u **arg, cctx_T *cctx)
++len; ++len;
// nothing appended: match case // 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]; char_u buf[7];
vim_strncpy(buf, p, len); vim_strncpy(buf, p, len);
semsg(_(e_white_both), buf); semsg(_(e_white_both), buf);
return FAIL;
} }
// get the second variable // get the second variable
*arg = skipwhite(p + len); *arg = skipwhite(p + len);
if (may_get_next_line(arg, cctx) == FAIL)
return FAIL;
if (compile_expr5(arg, cctx) == FAIL) if (compile_expr5(arg, cctx) == FAIL)
return FAIL; return FAIL;
@ -3611,8 +3639,11 @@ compile_and_or(char_u **arg, cctx_T *cctx, char *op)
ga_init2(&end_ga, sizeof(int), 10); ga_init2(&end_ga, sizeof(int), 10);
while (p[0] == opchar && p[1] == opchar) 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); semsg(_(e_white_both), op);
return FAIL;
}
if (ga_grow(&end_ga, 1) == FAIL) if (ga_grow(&end_ga, 1) == FAIL)
{ {
@ -3626,6 +3657,9 @@ compile_and_or(char_u **arg, cctx_T *cctx, char *op)
// eval the next expression // eval the next expression
*arg = skipwhite(p + 2); *arg = skipwhite(p + 2);
if (may_get_next_line(arg, cctx) == FAIL)
return FAIL;
if ((opchar == '|' ? compile_expr3(arg, cctx) if ((opchar == '|' ? compile_expr3(arg, cctx)
: compile_expr4(arg, cctx)) == FAIL) : compile_expr4(arg, cctx)) == FAIL)
{ {
@ -3726,13 +3760,19 @@ compile_expr1(char_u **arg, cctx_T *cctx)
type_T *type1; type_T *type1;
type_T *type2; 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), "?"); semsg(_(e_white_both), "?");
return FAIL;
}
generate_JUMP(cctx, JUMP_IF_FALSE, 0); generate_JUMP(cctx, JUMP_IF_FALSE, 0);
// evaluate the second expression; any type is accepted // evaluate the second expression; any type is accepted
*arg = skipwhite(p + 1); *arg = skipwhite(p + 1);
if (may_get_next_line(arg, cctx) == FAIL)
return FAIL;
if (compile_expr1(arg, cctx) == FAIL) if (compile_expr1(arg, cctx) == FAIL)
return FAIL; return FAIL;
@ -3754,11 +3794,17 @@ compile_expr1(char_u **arg, cctx_T *cctx)
emsg(_(e_missing_colon)); emsg(_(e_missing_colon));
return FAIL; 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), ":"); semsg(_(e_white_both), ":");
return FAIL;
}
// evaluate the third expression // evaluate the third expression
*arg = skipwhite(p + 1); *arg = skipwhite(p + 1);
if (may_get_next_line(arg, cctx) == FAIL)
return FAIL;
if (compile_expr1(arg, cctx) == FAIL) if (compile_expr1(arg, cctx) == FAIL)
return FAIL; return FAIL;