diff options
author | zeertzjq <zeertzjq@outlook.com> | 2023-05-02 16:25:47 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2023-05-02 16:25:47 +0100 |
commit | a93d9cdc74f70ca2c85781496ffae4ca738fcd88 (patch) | |
tree | 25c7b84548c6fccafd119edb84807db998351f1f | |
parent | 17b695190d63b2de745499cb40a383c2672e275e (diff) | |
download | vim-git-9.0.1505.tar.gz |
patch 9.0.1505: error when heredoc content looks like heredocv9.0.1505
Problem: Error when heredoc content looks like heredoc.
Solution: Handle curly expressions. (closes #12325)
-rw-r--r-- | src/eval.c | 8 | ||||
-rw-r--r-- | src/testdir/test_let.vim | 64 | ||||
-rw-r--r-- | src/testdir/test_vim9_assign.vim | 71 | ||||
-rw-r--r-- | src/userfunc.c | 31 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/vim.h | 1 |
6 files changed, 145 insertions, 32 deletions
diff --git a/src/eval.c b/src/eval.c index 0163ccc85..c31b0be07 100644 --- a/src/eval.c +++ b/src/eval.c @@ -6581,7 +6581,7 @@ find_name_end( int br_nest = 0; char_u *p; int len; - int vim9script = in_vim9script(); + int allow_curly = (flags & FNE_ALLOW_CURLY) || !in_vim9script(); if (expr_start != NULL) { @@ -6591,12 +6591,12 @@ find_name_end( // Quick check for valid starting character. if ((flags & FNE_CHECK_START) && !eval_isnamec1(*arg) - && (*arg != '{' || vim9script)) + && (*arg != '{' || !allow_curly)) return arg; for (p = arg; *p != NUL && (eval_isnamec(*p) - || (*p == '{' && !vim9script) + || (*p == '{' && allow_curly) || ((flags & FNE_INCL_BR) && (*p == '[' || (*p == '.' && eval_isdictc(p[1])))) || mb_nest != 0 @@ -6637,7 +6637,7 @@ find_name_end( --br_nest; } - if (br_nest == 0 && !vim9script) + if (br_nest == 0 && allow_curly) { if (*p == '{') { diff --git a/src/testdir/test_let.vim b/src/testdir/test_let.vim index 4e4a386df..680572f76 100644 --- a/src/testdir/test_let.vim +++ b/src/testdir/test_let.vim @@ -337,7 +337,43 @@ func Test_let_heredoc_fails() call assert_report('No exception thrown') catch /E488:/ catch - call assert_report("Caught exception: " .. v:exception) + call assert_report('Caught exception: ' .. v:exception) + endtry + + try + let &commentstring =<< trim TEXT + change + insert + append + TEXT + call assert_report('No exception thrown') + catch /E730:/ + catch + call assert_report('Caught exception: ' .. v:exception) + endtry + + try + let $SOME_ENV_VAR =<< trim TEXT + change + insert + append + TEXT + call assert_report('No exception thrown') + catch /E730:/ + catch + call assert_report('Caught exception: ' .. v:exception) + endtry + + try + let @r =<< trim TEXT + change + insert + append + TEXT + call assert_report('No exception thrown') + catch /E730:/ + catch + call assert_report('Caught exception: ' .. v:exception) endtry let text =<< trim END @@ -506,6 +542,32 @@ E z END call assert_equal([' x', ' \y', ' z'], [a, b, c]) + + " unpack assignment without whitespace + let[a,b,c]=<<END +change +insert +append +END + call assert_equal(['change', 'insert', 'append'], [a, b, c]) + + " curly braces name and list slice assignment + let foo_3_bar = ['', '', ''] + let foo_{1 + 2}_bar[ : ] =<< END +change +insert +append +END + call assert_equal(['change', 'insert', 'append'], foo_3_bar) + + " dictionary key containing brackets and spaces + let d = {'abc] 123': 'baz'} + let d[d['abc] 123'] .. '{'] =<< END +change +insert +append +END + call assert_equal(['change', 'insert', 'append'], d['baz{']) endfunc " Test for evaluating Vim expressions in a heredoc using {expr} diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim index 4f4e58e06..6db2718da 100644 --- a/src/testdir/test_vim9_assign.vim +++ b/src/testdir/test_vim9_assign.vim @@ -1848,30 +1848,81 @@ enddef def Test_heredoc() # simple heredoc var lines =<< trim END - var text =<< trim TEXT # comment - abc - TEXT - assert_equal(['abc'], text) + var text =<< trim TEXT # comment + abc + TEXT + assert_equal(['abc'], text) END v9.CheckDefAndScriptSuccess(lines) # empty heredoc lines =<< trim END - var text =<< trim TEXT - TEXT - assert_equal([], text) + var text =<< trim TEXT + TEXT + assert_equal([], text) END v9.CheckDefAndScriptSuccess(lines) # heredoc with a single empty line lines =<< trim END - var text =<< trim TEXT + var text =<< trim TEXT - TEXT - assert_equal([''], text) + TEXT + assert_equal([''], text) END v9.CheckDefAndScriptSuccess(lines) + # assign heredoc to variable with type + lines =<< trim END + var text: list<string> =<< trim TEXT + var foo =<< trim FOO + TEXT + assert_equal(['var foo =<< trim FOO'], text) + END + v9.CheckDefAndScriptSuccess(lines) + + # extra whitespace before type is allowed + lines =<< trim END + var text: list<string> =<< trim TEXT + var foo =<< trim FOO + TEXT + assert_equal(['var foo =<< trim FOO'], text) + END + v9.CheckDefAndScriptSuccess(lines) + + # missing whitespace before type is an error + lines =<< trim END + var text:list<string> =<< trim TEXT + var foo =<< trim FOO + TEXT + assert_equal(['var foo =<< trim FOO'], text) + END + v9.CheckDefAndScriptFailure(lines, 'E1069:') + + # assign heredoc to list slice + lines =<< trim END + var text = [''] + text[ : ] =<< trim TEXT + var foo =<< trim FOO + TEXT + assert_equal(['var foo =<< trim FOO'], text) + END + v9.CheckDefAndScriptSuccess(lines) + + # assign heredoc to curly braces name in legacy function in Vim9 script + lines =<< trim END + vim9script + func Func() + let foo_3_bar = [''] + let foo_{1 + 2}_bar[ : ] =<< trim TEXT + var foo =<< trim FOO + TEXT + call assert_equal(['var foo =<< trim FOO'], foo_3_bar) + endfunc + Func() + END + v9.CheckScriptSuccess(lines) + v9.CheckDefFailure(['var lines =<< trim END X', 'END'], 'E488:') v9.CheckDefFailure(['var lines =<< trim END " comment', 'END'], 'E488:') diff --git a/src/userfunc.c b/src/userfunc.c index fbde6edd0..e63caf9fe 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -1143,7 +1143,7 @@ get_function_body( skip_until = vim_strnsave(p, skiptowhite(p) - p); getline_options = GETLINE_NONE; is_heredoc = TRUE; - if (eap->cmdidx == CMD_def && nesting == 0) + if (vim9_function && nesting == 0) heredoc_concat_len = newlines->ga_len + 1; } @@ -1153,23 +1153,20 @@ get_function_body( // and ":cmd [a, b] =<< [trim] EOF" // and "lines =<< [trim] EOF" for Vim9 // Where "cmd" can be "let", "var", "final" or "const". - arg = skipwhite(skiptowhite(p)); - if (*arg == '[') - arg = vim_strchr(arg, ']'); - if (arg != NULL) + arg = p; + if (checkforcmd(&arg, "let", 2) + || checkforcmd(&arg, "var", 3) + || checkforcmd(&arg, "final", 5) + || checkforcmd(&arg, "const", 5) + || vim9_function) { - int found = (eap->cmdidx == CMD_def && arg[0] == '=' - && arg[1] == '<' && arg[2] =='<'); - - if (!found) - // skip over the argument after "cmd" - arg = skipwhite(skiptowhite(arg)); - if (found || (arg[0] == '=' && arg[1] == '<' - && arg[2] =='<' - && (checkforcmd(&p, "let", 2) - || checkforcmd(&p, "var", 3) - || checkforcmd(&p, "final", 5) - || checkforcmd(&p, "const", 5)))) + while (vim_strchr((char_u *)"$@&", *arg) != NULL) + ++arg; + arg = skipwhite(find_name_end(arg, NULL, NULL, + FNE_INCL_BR | FNE_ALLOW_CURLY)); + if (vim9_function && *arg == ':') + arg = skipwhite(skip_type(skipwhite(arg + 1), FALSE)); + if (arg[0] == '=' && arg[1] == '<' && arg[2] =='<') { p = skipwhite(arg + 3); while (TRUE) diff --git a/src/version.c b/src/version.c index 2a99c3b3c..d01d7f26b 100644 --- a/src/version.c +++ b/src/version.c @@ -696,6 +696,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1505, +/**/ 1504, /**/ 1503, @@ -2758,6 +2758,7 @@ typedef char *(*opt_did_set_cb_T)(optset_T *args); // flags for find_name_end() #define FNE_INCL_BR 1 // include [] in name #define FNE_CHECK_START 2 // check name starts with valid character +#define FNE_ALLOW_CURLY 4 // always allow curly braces name // BSD is supposed to cover FreeBSD and similar systems. #if (defined(SUN_SYSTEM) || defined(BSD) || defined(__FreeBSD_kernel__)) \ |