Patch 9.0.1505

4 views
Skip to first unread message

Bram Moolenaar

unread,
May 2, 2023, 11:26:22 AM5/2/23
to vim...@googlegroups.com

Patch 9.0.1505
Problem: Error when heredoc content looks like heredoc.
Solution: Handle curly expressions. (closes #12325)
Files: src/eval.c, src/userfunc.c, src/vim.h, src/testdir/test_let.vim,
src/testdir/test_vim9_assign.vim


*** ../vim-9.0.1504/src/eval.c 2023-04-13 22:12:46.300718943 +0100
--- src/eval.c 2023-05-02 16:19:44.051000651 +0100
***************
*** 6581,6587 ****
int br_nest = 0;
char_u *p;
int len;
! int vim9script = in_vim9script();

if (expr_start != NULL)
{
--- 6581,6587 ----
int br_nest = 0;
char_u *p;
int len;
! int allow_curly = (flags & FNE_ALLOW_CURLY) || !in_vim9script();

if (expr_start != NULL)
{
***************
*** 6591,6602 ****

// Quick check for valid starting character.
if ((flags & FNE_CHECK_START) && !eval_isnamec1(*arg)
! && (*arg != '{' || vim9script))
return arg;

for (p = arg; *p != NUL
&& (eval_isnamec(*p)
! || (*p == '{' && !vim9script)
|| ((flags & FNE_INCL_BR) && (*p == '['
|| (*p == '.' && eval_isdictc(p[1]))))
|| mb_nest != 0
--- 6591,6602 ----

// Quick check for valid starting character.
if ((flags & FNE_CHECK_START) && !eval_isnamec1(*arg)
! && (*arg != '{' || !allow_curly))
return arg;

for (p = arg; *p != NUL
&& (eval_isnamec(*p)
! || (*p == '{' && allow_curly)
|| ((flags & FNE_INCL_BR) && (*p == '['
|| (*p == '.' && eval_isdictc(p[1]))))
|| mb_nest != 0
***************
*** 6637,6643 ****
--br_nest;
}

! if (br_nest == 0 && !vim9script)
{
if (*p == '{')
{
--- 6637,6643 ----
--br_nest;
}

! if (br_nest == 0 && allow_curly)
{
if (*p == '{')
{
*** ../vim-9.0.1504/src/userfunc.c 2023-04-19 14:21:19.078048657 +0100
--- src/userfunc.c 2023-05-02 16:18:35.495061306 +0100
***************
*** 1143,1149 ****
skip_until = vim_strnsave(p, skiptowhite(p) - p);
getline_options = GETLINE_NONE;
is_heredoc = TRUE;
! if (eap->cmdidx == CMD_def && nesting == 0)
heredoc_concat_len = newlines->ga_len + 1;
}

--- 1143,1149 ----
skip_until = vim_strnsave(p, skiptowhite(p) - p);
getline_options = GETLINE_NONE;
is_heredoc = TRUE;
! if (vim9_function && nesting == 0)
heredoc_concat_len = newlines->ga_len + 1;
}

***************
*** 1153,1175 ****
// 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)
{
! 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))))
{
p = skipwhite(arg + 3);
while (TRUE)
--- 1153,1172 ----
// and ":cmd [a, b] =<< [trim] EOF"
// and "lines =<< [trim] EOF" for Vim9
// Where "cmd" can be "let", "var", "final" or "const".
! arg = p;
! if (checkforcmd(&arg, "let", 2)
! || checkforcmd(&arg, "var", 3)
! || checkforcmd(&arg, "final", 5)
! || checkforcmd(&arg, "const", 5)
! || vim9_function)
{
! 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)
*** ../vim-9.0.1504/src/vim.h 2023-04-13 19:15:50.023391985 +0100
--- src/vim.h 2023-05-02 16:18:35.495061306 +0100
***************
*** 2758,2763 ****
--- 2758,2764 ----
// 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__)) \
*** ../vim-9.0.1504/src/testdir/test_let.vim 2022-11-05 20:21:50.601151478 +0000
--- src/testdir/test_let.vim 2023-05-02 16:18:35.491061310 +0100
***************
*** 337,343 ****
call assert_report('No exception thrown')
catch /E488:/
catch
! call assert_report("Caught exception: " .. v:exception)
endtry

let text =<< trim END
--- 337,379 ----
call assert_report('No exception thrown')
catch /E488:/
catch
! 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,511 ****
--- 542,573 ----
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}
*** ../vim-9.0.1504/src/testdir/test_vim9_assign.vim 2023-01-30 21:12:30.547422897 +0000
--- src/testdir/test_vim9_assign.vim 2023-05-02 16:18:35.491061310 +0100
***************
*** 1848,1877 ****
def Test_heredoc()
# simple heredoc
var lines =<< trim END
! 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)
END
v9.CheckDefAndScriptSuccess(lines)

# heredoc with a single empty line
lines =<< trim END
! var text =<< trim TEXT

! TEXT
! assert_equal([''], text)
END
v9.CheckDefAndScriptSuccess(lines)

v9.CheckDefFailure(['var lines =<< trim END X', 'END'], 'E488:')
v9.CheckDefFailure(['var lines =<< trim END " comment', 'END'], 'E488:')

--- 1848,1928 ----
def Test_heredoc()
# simple heredoc
var lines =<< trim END
! 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)
END
v9.CheckDefAndScriptSuccess(lines)

# heredoc with a single empty line
lines =<< trim END
! 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:')

*** ../vim-9.0.1504/src/version.c 2023-05-01 22:36:52.870894672 +0100
--- src/version.c 2023-05-02 16:20:42.170957010 +0100
***************
*** 697,698 ****
--- 697,700 ----
{ /* Add new patch number below this line */
+ /**/
+ 1505,
/**/

--
Are leaders born or made? And if they're made, can we return them under
warranty?
(Scott Adams - The Dilbert principle)

/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
Reply all
Reply to author
Forward
0 new messages