# HG changeset patch # User Bram Moolenaar # Date 1554385504 -7200 # Node ID bd49e1656c729ca852a1057ae845c72e62609512 # Parent 0874f5cbaaa60c6f20c6b42d219c711a47a280e9 patch 8.1.1114: confusing overloaded operator "." for string concatenation commit https://github.com/vim/vim/commit/0f248b006c2574abc00c9aa7886d8f33620eb822 Author: Bram Moolenaar Date: Thu Apr 4 15:36:05 2019 +0200 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". diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -786,10 +786,10 @@ Expression syntax summary, from least to expr2 ? expr1 : expr1 if-then-else |expr2| expr3 - expr3 || expr3 .. logical OR + expr3 || expr3 ... logical OR |expr3| expr4 - expr4 && expr4 .. logical AND + expr4 && expr4 ... logical AND |expr4| expr5 expr5 == expr5 equal @@ -811,14 +811,15 @@ Expression syntax summary, from least to instance |expr5| expr6 - expr6 + expr6 .. number addition, list or blob concatenation - expr6 - expr6 .. number subtraction - expr6 . expr6 .. string concatenation + expr6 + expr6 ... number addition, list or blob concatenation + expr6 - expr6 ... number subtraction + expr6 . expr6 ... string concatenation + expr6 .. expr6 ... string concatenation |expr6| expr7 - expr7 * expr7 .. number multiplication - expr7 / expr7 .. number division - expr7 % expr7 .. number modulo + expr7 * expr7 ... number multiplication + expr7 / expr7 ... number division + expr7 % expr7 ... number modulo |expr7| expr8 ! expr7 logical NOT @@ -847,7 +848,7 @@ Expression syntax summary, from least to {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: > &nu || &list && &shell == "csh" @@ -1026,13 +1027,17 @@ can be matched like an ordinary characte expr5 and expr6 *expr5* *expr6* --------------- -expr6 + expr6 Number addition, |List| or |Blob| concatenation *expr-+* -expr6 - expr6 Number subtraction *expr--* -expr6 . expr6 String concatenation *expr-.* +expr6 + expr6 Number addition, |List| or |Blob| concatenation *expr-+* +expr6 - expr6 Number subtraction *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 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 division *expr-/* expr7 % expr7 Number modulo *expr-%* @@ -5800,7 +5805,7 @@ islocked({expr}) *islocked()* *E786* isnan({expr}) *isnan()* Return |TRUE| if {expr} is a float with value NaN. > echo isnan(0.0 / 0.0) -< 1 ~ +< 1 {only available when compiled with the |+float| feature} diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -1234,6 +1234,7 @@ 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 [var1, var2] = expr" unpack list. */ void @@ -1255,8 +1256,8 @@ ex_let(exarg_T *eap) if (argend > arg && argend[-1] == '.') // for var.='str' --argend; expr = skipwhite(argend); - if (*expr != '=' && !(vim_strchr((char_u *)"+-*/%.", *expr) != NULL - && expr[1] == '=')) + if (*expr != '=' && !((vim_strchr((char_u *)"+-*/%.", *expr) != NULL + && expr[1] == '=') || STRNCMP(expr, "..=", 3) == 0)) { /* * ":let" without "=": list variables @@ -1286,7 +1287,11 @@ ex_let(exarg_T *eap) if (*expr != '=') { if (vim_strchr((char_u *)"+-*/%.", *expr) != NULL) + { op[0] = *expr; // +=, -=, *=, /=, %= or .= + if (expr[0] == '.' && expr[1] == '.') // ..= + ++expr; + } expr = skipwhite(expr + 2); } else @@ -3813,6 +3818,7 @@ eval4(char_u **arg, typval_T *rettv, int * + number addition * - number subtraction * . string concatenation + * .. string concatenation * * "arg" must point to the first non-white of the expression. * "arg" is advanced to the next non-white after the recognized expression. @@ -3872,6 +3878,8 @@ eval5(char_u **arg, typval_T *rettv, int /* * Get the second variable. */ + if (op == '.' && *(*arg + 1) == '.') // .. string concatenation + ++*arg; *arg = skipwhite(*arg + 1); if (eval6(arg, &var2, evaluate, op == '.') == FAIL) { diff --git a/src/testdir/test_eval_stuff.vim b/src/testdir/test_eval_stuff.vim --- a/src/testdir/test_eval_stuff.vim +++ b/src/testdir/test_eval_stuff.vim @@ -94,3 +94,32 @@ func Test_let_errmsg() call assert_fails('let v:errmsg = []', 'E730:') let v:errmsg = '' 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 diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -772,6 +772,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1114, +/**/ 1113, /**/ 1112,