vim-patch:8.1.1114: confusing overloaded operator "." for string concatenation

Problem:    Confusing overloaded operator "." for string concatenation.
Solution:   Add ".." for string concatenation.  Also "let a ..= b".
0f248b006c
This commit is contained in:
erw7 2019-05-29 12:06:39 +09:00
parent d46aaa0746
commit bfc44a91ac
3 changed files with 50 additions and 8 deletions

View File

@ -610,10 +610,10 @@ Expression syntax summary, from least to most significant:
expr2 ? expr1 : expr1 if-then-else expr2 ? expr1 : expr1 if-then-else
|expr2| expr3 |expr2| expr3
expr3 || expr3 .. logical OR expr3 || expr3 ... logical OR
|expr3| expr4 |expr3| expr4
expr4 && expr4 .. logical AND expr4 && expr4 ... logical AND
|expr4| expr5 |expr4| expr5
expr5 == expr5 equal expr5 == expr5 equal
@ -634,9 +634,10 @@ Expression syntax summary, from least to most significant:
expr5 isnot expr5 different |List| instance expr5 isnot expr5 different |List| instance
|expr5| expr6 |expr5| expr6
expr6 + expr6 .. number addition or list concatenation expr6 + expr6 .. number addition or list concatenation
expr6 - expr6 .. number subtraction expr6 - expr6 .. number subtraction
expr6 . expr6 .. string concatenation expr6 . expr6 .. string concatenation
expr6 .. expr6 .. string concatenation
|expr6| expr7 |expr6| expr7
expr7 * expr7 .. number multiplication expr7 * expr7 .. number multiplication
@ -670,7 +671,7 @@ Expression syntax summary, from least to most significant:
{args -> expr1} lambda expression {args -> expr1} lambda expression
".." indicates that the operations in this level can be concatenated. "..." indicates that the operations in this level can be concatenated.
Example: > Example: >
&nu || &list && &shell == "csh" &nu || &list && &shell == "csh"
@ -850,10 +851,14 @@ expr5 and expr6 *expr5* *expr6*
expr6 + expr6 .. Number addition or |List| concatenation *expr-+* expr6 + expr6 .. Number addition or |List| concatenation *expr-+*
expr6 - expr6 .. Number subtraction *expr--* expr6 - expr6 .. Number subtraction *expr--*
expr6 . expr6 .. String concatenation *expr-.* expr6 . expr6 .. String concatenation *expr-.*
expr6 .. expr6 .. String concatenation *expr-..*
For |Lists| only "+" is possible and then both expr6 must be a list. The For |Lists| only "+" is possible and then both expr6 must be a list. The
result is a new list with the two lists Concatenated. result is a new list with the two lists Concatenated.
For String concatenation ".." is preferred, since "." is ambiguous, it is also
used for |Dict| member access and floating point numbers.
expr7 * expr7 .. Number multiplication *expr-star* expr7 * expr7 .. Number multiplication *expr-star*
expr7 / expr7 .. Number division *expr-/* expr7 / expr7 .. Number division *expr-/*
expr7 % expr7 .. Number modulo *expr-%* expr7 % expr7 .. Number modulo *expr-%*

View File

@ -1446,6 +1446,7 @@ int eval_foldexpr(char_u *arg, int *cp)
* ":let var /= expr" assignment command. * ":let var /= expr" assignment command.
* ":let var %= expr" assignment command. * ":let var %= expr" assignment command.
* ":let var .= expr" assignment command. * ":let var .= expr" assignment command.
* ":let var ..= expr" assignment command.
* ":let [var1, var2] = expr" unpack list. * ":let [var1, var2] = expr" unpack list.
*/ */
void ex_let(exarg_T *eap) void ex_let(exarg_T *eap)
@ -1468,8 +1469,8 @@ void ex_let(exarg_T *eap)
argend--; argend--;
} }
expr = skipwhite(argend); expr = skipwhite(argend);
if (*expr != '=' && !(vim_strchr((char_u *)"+-*/%.", *expr) != NULL if (*expr != '=' && !((vim_strchr((char_u *)"+-*/%.", *expr) != NULL
&& expr[1] == '=')) { && expr[1] == '=') || STRNCMP(expr, "..=", 3) == 0)) {
// ":let" without "=": list variables // ":let" without "=": list variables
if (*arg == '[') { if (*arg == '[') {
EMSG(_(e_invarg)); EMSG(_(e_invarg));
@ -1493,6 +1494,9 @@ void ex_let(exarg_T *eap)
if (*expr != '=') { if (*expr != '=') {
if (vim_strchr((char_u *)"+-*/%.", *expr) != NULL) { if (vim_strchr((char_u *)"+-*/%.", *expr) != NULL) {
op[0] = *expr; // +=, -=, *=, /=, %= or .= op[0] = *expr; // +=, -=, *=, /=, %= or .=
if (expr[0] == '.' && expr[1] == '.') { // ..=
expr++;
}
} }
expr = skipwhite(expr + 2); expr = skipwhite(expr + 2);
} else { } else {
@ -3789,6 +3793,7 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate)
* + number addition * + number addition
* - number subtraction * - number subtraction
* . string concatenation * . string concatenation
* .. string concatenation
* *
* "arg" must point to the first non-white of the expression. * "arg" must point to the first non-white of the expression.
* "arg" is advanced to the next non-white after the recognized expression. * "arg" is advanced to the next non-white after the recognized expression.
@ -3836,6 +3841,9 @@ static int eval5(char_u **arg, typval_T *rettv, int evaluate)
/* /*
* Get the second variable. * Get the second variable.
*/ */
if (op == '.' && *(*arg + 1) == '.') { // ..string concatenation
(*arg)++;
}
*arg = skipwhite(*arg + 1); *arg = skipwhite(*arg + 1);
if (eval6(arg, &var2, evaluate, op == '.') == FAIL) { if (eval6(arg, &var2, evaluate, op == '.') == FAIL) {
tv_clear(rettv); tv_clear(rettv);

View File

@ -49,3 +49,32 @@ func Test_line_continuation()
"\ and some more "\ and some more
call assert_equal([5, 6], array) call assert_equal([5, 6], array)
endfunc endfunc
func Test_string_concatenation()
call assert_equal('ab', 'a'.'b')
call assert_equal('ab', 'a' .'b')
call assert_equal('ab', 'a'. 'b')
call assert_equal('ab', 'a' . 'b')
call assert_equal('ab', 'a'..'b')
call assert_equal('ab', 'a' ..'b')
call assert_equal('ab', 'a'.. 'b')
call assert_equal('ab', 'a' .. 'b')
let a = 'a'
let b = 'b'
let a .= b
call assert_equal('ab', a)
let a = 'a'
let a.=b
call assert_equal('ab', a)
let a = 'a'
let a ..= b
call assert_equal('ab', a)
let a = 'a'
let a..=b
call assert_equal('ab', a)
endfunc