Mercurial > vim
changeset 32347:edea3992cb01 v9.0.1505
patch 9.0.1505: error when heredoc content looks like heredoc
Commit: https://github.com/vim/vim/commit/a93d9cdc74f70ca2c85781496ffae4ca738fcd88
Author: zeertzjq <zeertzjq@outlook.com>
Date: Tue May 2 16:25:47 2023 +0100
patch 9.0.1505: error when heredoc content looks like heredoc
Problem: Error when heredoc content looks like heredoc.
Solution: Handle curly expressions. (closes https://github.com/vim/vim/issues/12325)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Tue, 02 May 2023 17:30:05 +0200 |
parents | 0e2ba4c8b1c1 |
children | 73c473159a74 |
files | src/eval.c src/testdir/test_let.vim src/testdir/test_vim9_assign.vim src/userfunc.c src/version.c src/vim.h |
diffstat | 6 files changed, 146 insertions(+), 33 deletions(-) [+] |
line wrap: on
line diff
--- 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 == '{') {
--- 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}
--- 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 - - TEXT - assert_equal([''], text) + var text =<< trim 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:')
--- 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)
--- 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,
--- a/src/vim.h +++ b/src/vim.h @@ -2758,6 +2758,7 @@ typedef char *(*opt_did_set_cb_T)(optset // 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__)) \