view src/testdir/test_vimscript.vim @ 21632:792398a9fe39 v8.2.1366

patch 8.2.1366: test 49 is old style Commit: https://github.com/vim/vim/commit/a6296200bd5191bab7efcdcc16c9e79eb498e8e0 Author: Bram Moolenaar <Bram@vim.org> Date: Wed Aug 5 11:23:13 2020 +0200 patch 8.2.1366: test 49 is old style Problem: Test 49 is old style. Solution: Convert several tests to new style. (Yegappan Lakshmanan, closes #6629)
author Bram Moolenaar <Bram@vim.org>
date Wed, 05 Aug 2020 11:30:03 +0200
parents 8fb0e507491d
children 97b887aecd4a
line wrap: on
line source

" Test various aspects of the Vim script language.
" Most of this was formerly in test49.

source check.vim
source shared.vim
source script_util.vim

"-------------------------------------------------------------------------------
" Test environment							    {{{1
"-------------------------------------------------------------------------------

" Append a message to the "messages" file
func Xout(text)
    split messages
    $put =a:text
    wq
endfunc

com! -nargs=1	     Xout     call Xout(<args>)

" Create a new instance of Vim and run the commands in 'test' and then 'verify'
" The commands in 'test' are expected to store the test results in the Xtest.out
" file. If the test passes successfully, then Xtest.out should be empty.
func RunInNewVim(test, verify)
  let init =<< trim END
    source script_util.vim
    XpathINIT
    XloopINIT
  END
  let cleanup =<< trim END
    call writefile(v:errors, 'Xtest.out')
    qall
  END
  call writefile(init, 'Xtest.vim')
  call writefile(a:test, 'Xtest.vim', 'a')
  call writefile(a:verify, 'Xverify.vim')
  call writefile(cleanup, 'Xverify.vim', 'a')
  call RunVim([], [], "-S Xtest.vim -S Xverify.vim")
  call assert_equal([], readfile('Xtest.out'))
  call delete('Xtest.out')
  call delete('Xtest.vim')
  call delete('Xverify.vim')
endfunc

"-------------------------------------------------------------------------------
" Test 1:   :endwhile in function					    {{{1
"
"	    Detect if a broken loop is (incorrectly) reactivated by the
"	    :endwhile.  Use a :return to prevent an endless loop, and make
"	    this test first to get a meaningful result on an error before other
"	    tests will hang.
"-------------------------------------------------------------------------------

func T1_F()
    Xpath 'a'
    let first = 1
    while 1
	Xpath 'b'
	if first
	    Xpath 'c'
	    let first = 0
	    break
	else
	    Xpath 'd'
	    return
	endif
    endwhile
endfunc

func T1_G()
    Xpath 'h'
    let first = 1
    while 1
	Xpath 'i'
	if first
	    Xpath 'j'
	    let first = 0
	    break
	else
	    Xpath 'k'
	    return
	endif
	if 1	" unmatched :if
    endwhile
endfunc

func Test_endwhile_function()
  XpathINIT
  call T1_F()
  Xpath 'F'

  try
    call T1_G()
  catch
    " Catch missing :endif
    call assert_true(v:exception =~ 'E171')
    Xpath 'x'
  endtry
  Xpath 'G'

  call assert_equal('abcFhijxG', g:Xpath)
endfunc

"-------------------------------------------------------------------------------
" Test 2:   :endwhile in script						    {{{1
"
"	    Detect if a broken loop is (incorrectly) reactivated by the
"	    :endwhile.  Use a :finish to prevent an endless loop, and place
"	    this test before others that might hang to get a meaningful result
"	    on an error.
"
"	    This test executes the bodies of the functions T1_F and T1_G from
"	    the previous test as script files (:return replaced by :finish).
"-------------------------------------------------------------------------------

func Test_endwhile_script()
  XpathINIT
  ExecAsScript T1_F
  Xpath 'F'
  call DeleteTheScript()

  try
    ExecAsScript T1_G
  catch
    " Catch missing :endif
    call assert_true(v:exception =~ 'E171')
    Xpath 'x'
  endtry
  Xpath 'G'
  call DeleteTheScript()

  call assert_equal('abcFhijxG', g:Xpath)
endfunc

"-------------------------------------------------------------------------------
" Test 3:   :if, :elseif, :while, :continue, :break			    {{{1
"-------------------------------------------------------------------------------

func Test_if_while()
    XpathINIT
    if 1
	Xpath 'a'
	let loops = 3
	while loops > -1	    " main loop: loops == 3, 2, 1 (which breaks)
	    if loops <= 0
		let break_err = 1
		let loops = -1
	    else
		Xpath 'b' . loops
	    endif
	    if (loops == 2)
		while loops == 2 " dummy loop
		    Xpath 'c' . loops
		    let loops = loops - 1
		    continue    " stop dummy loop
		    Xpath 'd' . loops
		endwhile
		continue	    " continue main loop
		Xpath 'e' . loops
	    elseif (loops == 1)
		let p = 1
		while p	    " dummy loop
		    Xpath 'f' . loops
		    let p = 0
		    break	    " break dummy loop
		    Xpath 'g' . loops
		endwhile
		Xpath 'h' . loops
		unlet p
		break	    " break main loop
		Xpath 'i' . loops
	    endif
	    if (loops > 0)
		Xpath 'j' . loops
	    endif
	    while loops == 3    " dummy loop
		let loops = loops - 1
	    endwhile	    " end dummy loop
	endwhile		    " end main loop
	Xpath 'k'
    else
	Xpath 'l'
    endif
    Xpath 'm'
    if exists("break_err")
	Xpath 'm'
	unlet break_err
    endif

    unlet loops

    call assert_equal('ab3j3b2c2b1f1h1km', g:Xpath)
endfunc

"-------------------------------------------------------------------------------
" Test 4:   :return							    {{{1
"-------------------------------------------------------------------------------

func T4_F()
    if 1
	Xpath 'a'
	let loops = 3
	while loops > 0				"    3:  2:     1:
	    Xpath 'b' . loops
	    if (loops == 2)
		Xpath 'c' . loops
		return
		Xpath 'd' . loops
	    endif
	    Xpath 'e' . loops
	    let loops = loops - 1
	endwhile
	Xpath 'f'
    else
	Xpath 'g'
    endif
endfunc

func Test_return()
    XpathINIT
    call T4_F()
    Xpath '4'

    call assert_equal('ab3e3b2c24', g:Xpath)
endfunc


"-------------------------------------------------------------------------------
" Test 5:   :finish							    {{{1
"
"	    This test executes the body of the function T4_F from the previous
"	    test as a script file (:return replaced by :finish).
"-------------------------------------------------------------------------------

func Test_finish()
    XpathINIT
    ExecAsScript T4_F
    Xpath '5'
    call DeleteTheScript()

    call assert_equal('ab3e3b2c25', g:Xpath)
endfunc



"-------------------------------------------------------------------------------
" Test 6:   Defining functions in :while loops				    {{{1
"
"	     Functions can be defined inside other functions.  An inner function
"	     gets defined when the outer function is executed.  Functions may
"	     also be defined inside while loops.  Expressions in braces for
"	     defining the function name are allowed.
"
"	     The functions are defined when sourcing the script, only the
"	     resulting path is checked in the test function.
"-------------------------------------------------------------------------------

XpathINIT

" The command CALL collects the argument of all its invocations in "calls"
" when used from a function (that is, when the global variable "calls" needs
" the "g:" prefix).  This is to check that the function code is skipped when
" the function is defined.  For inner functions, do so only if the outer
" function is not being executed.
"
let calls = ""
com! -nargs=1 CALL
	    \ if !exists("calls") && !exists("outer") |
	    \ let g:calls = g:calls . <args> |
	    \ endif

let i = 0
while i < 3
    let i = i + 1
    if i == 1
	Xpath 'a'
	function! F1(arg)
	    CALL a:arg
	    let outer = 1

	    let j = 0
	    while j < 1
		Xpath 'b'
		let j = j + 1
		function! G1(arg)
		    CALL a:arg
		endfunction
		Xpath 'c'
	    endwhile
	endfunction
	Xpath 'd'

	continue
    endif

    Xpath 'e' . i
    function! F{i}(i, arg)
	CALL a:arg
	let outer = 1

	if a:i == 3
	    Xpath 'f'
	endif
	let k = 0
	while k < 3
	    Xpath 'g' . k
	    let k = k + 1
	    function! G{a:i}{k}(arg)
		CALL a:arg
	    endfunction
	    Xpath 'h' . k
	endwhile
    endfunction
    Xpath 'i'

endwhile

if exists("*G1")
    Xpath 'j'
endif
if exists("*F1")
    call F1("F1")
    if exists("*G1")
       call G1("G1")
    endif
endif

if exists("G21") || exists("G22") || exists("G23")
    Xpath 'k'
endif
if exists("*F2")
    call F2(2, "F2")
    if exists("*G21")
       call G21("G21")
    endif
    if exists("*G22")
       call G22("G22")
    endif
    if exists("*G23")
       call G23("G23")
    endif
endif

if exists("G31") || exists("G32") || exists("G33")
    Xpath 'l'
endif
if exists("*F3")
    call F3(3, "F3")
    if exists("*G31")
       call G31("G31")
    endif
    if exists("*G32")
       call G32("G32")
    endif
    if exists("*G33")
       call G33("G33")
    endif
endif

Xpath 'm'

let g:test6_result = g:Xpath
let g:test6_calls = calls

unlet calls
delfunction F1
delfunction G1
delfunction F2
delfunction G21
delfunction G22
delfunction G23
delfunction G31
delfunction G32
delfunction G33

func Test_defining_functions()
    call assert_equal('ade2ie3ibcg0h1g1h2g2h3fg0h1g1h2g2h3m', g:test6_result)
    call assert_equal('F1G1F2G21G22G23F3G31G32G33', g:test6_calls)
endfunc

"-------------------------------------------------------------------------------
" Test 7:   Continuing on errors outside functions			    {{{1
"
"	    On an error outside a function, the script processing continues
"	    at the line following the outermost :endif or :endwhile.  When not
"	    inside an :if or :while, the script processing continues at the next
"	    line.
"-------------------------------------------------------------------------------

XpathINIT

if 1
    Xpath 'a'
    while 1
	Xpath 'b'
	asdf
	Xpath 'c'
	break
    endwhile | Xpath 'd'
    Xpath 'e'
endif | Xpath 'f'
Xpath 'g'

while 1
    Xpath 'h'
    if 1
	Xpath 'i'
	asdf
	Xpath 'j'
    endif | Xpath 'k'
    Xpath 'l'
    break
endwhile | Xpath 'm'
Xpath 'n'

asdf
Xpath 'o'

asdf | Xpath 'p'
Xpath 'q'

let g:test7_result = g:Xpath

func Test_error_in_script()
    call assert_equal('abghinoq', g:test7_result)
endfunc

"-------------------------------------------------------------------------------
" Test 8:   Aborting and continuing on errors inside functions		    {{{1
"
"	    On an error inside a function without the "abort" attribute, the
"	    script processing continues at the next line (unless the error was
"	    in a :return command).  On an error inside a function with the
"	    "abort" attribute, the function is aborted and the script processing
"	    continues after the function call; the value -1 is returned then.
"-------------------------------------------------------------------------------

XpathINIT

func T8_F()
    if 1
	Xpath 'a'
	while 1
	    Xpath 'b'
	    asdf
	    Xpath 'c'
	    asdf | Xpath 'd'
	    Xpath 'e'
	    break
	endwhile
	Xpath 'f'
    endif | Xpath 'g'
    Xpath 'h'

    while 1
	Xpath 'i'
	if 1
	    Xpath 'j'
	    asdf
	    Xpath 'k'
	    asdf | Xpath 'l'
	    Xpath 'm'
	endif
	Xpath 'n'
	break
    endwhile | Xpath 'o'
    Xpath 'p'

    return novar		" returns (default return value 0)
    Xpath 'q'
    return 1			" not reached
endfunc

func T8_G() abort
    if 1
	Xpath 'r'
	while 1
	    Xpath 's'
	    asdf		" returns -1
	    Xpath 't'
	    break
	endwhile
	Xpath 'v'
    endif | Xpath 'w'
    Xpath 'x'

    return -4			" not reached
endfunc

func T8_H() abort
    while 1
	Xpath 'A'
	if 1
	    Xpath 'B'
	    asdf		" returns -1
	    Xpath 'C'
	endif
	Xpath 'D'
	break
    endwhile | Xpath 'E'
    Xpath 'F'

    return -4			" not reached
endfunc

" Aborted functions (T8_G and T8_H) return -1.
let g:test8_sum = (T8_F() + 1) - 4 * T8_G() - 8 * T8_H()
Xpath 'X'
let g:test8_result = g:Xpath

func Test_error_in_function()
    call assert_equal(13, g:test8_sum)
    call assert_equal('abcefghijkmnoprsABX', g:test8_result)

    delfunction T8_F
    delfunction T8_G
    delfunction T8_H
endfunc


"-------------------------------------------------------------------------------
" Test 9:   Continuing after aborted functions				    {{{1
"
"	    When a function with the "abort" attribute is aborted due to an
"	    error, the next function back in the call hierarchy without an
"	    "abort" attribute continues; the value -1 is returned then.
"-------------------------------------------------------------------------------

XpathINIT

func F() abort
    Xpath 'a'
    let result = G()	" not aborted
    Xpath 'b'
    if result != 2
	Xpath 'c'
    endif
    return 1
endfunc

func G()		" no abort attribute
    Xpath 'd'
    if H() != -1	" aborted
	Xpath 'e'
    endif
    Xpath 'f'
    return 2
endfunc

func H() abort
    Xpath 'g'
    call I()		" aborted
    Xpath 'h'
    return 4
endfunc

func I() abort
    Xpath 'i'
    asdf		" error
    Xpath 'j'
    return 8
endfunc

if F() != 1
    Xpath 'k'
endif

let g:test9_result = g:Xpath

delfunction F
delfunction G
delfunction H
delfunction I

func Test_func_abort()
    call assert_equal('adgifb', g:test9_result)
endfunc


"-------------------------------------------------------------------------------
" Test 10:  :if, :elseif, :while argument parsing			    {{{1
"
"	    A '"' or '|' in an argument expression must not be mixed up with
"	    a comment or a next command after a bar.  Parsing errors should
"	    be recognized.
"-------------------------------------------------------------------------------

XpathINIT

func MSG(enr, emsg)
    let english = v:lang == "C" || v:lang =~ '^[Ee]n'
    if a:enr == ""
	Xout "TODO: Add message number for:" a:emsg
	let v:errmsg = ":" . v:errmsg
    endif
    let match = 1
    if v:errmsg !~ '^'.a:enr.':' || (english && v:errmsg !~ a:emsg)
	let match = 0
	if v:errmsg == ""
	    Xout "Message missing."
	else
	    let v:errmsg = v:errmsg->escape('"')
	    Xout "Unexpected message:" v:errmsg
	endif
    endif
    return match
endfunc

if 1 || strlen("\"") | Xpath 'a'
    Xpath 'b'
endif
Xpath 'c'

if 0
elseif 1 || strlen("\"") | Xpath 'd'
    Xpath 'e'
endif
Xpath 'f'

while 1 || strlen("\"") | Xpath 'g'
    Xpath 'h'
    break
endwhile
Xpath 'i'

let v:errmsg = ""
if 1 ||| strlen("\"") | Xpath 'j'
    Xpath 'k'
endif
Xpath 'l'
if !MSG('E15', "Invalid expression")
    Xpath 'm'
endif

let v:errmsg = ""
if 0
elseif 1 ||| strlen("\"") | Xpath 'n'
    Xpath 'o'
endif
Xpath 'p'
if !MSG('E15', "Invalid expression")
    Xpath 'q'
endif

let v:errmsg = ""
while 1 ||| strlen("\"") | Xpath 'r'
    Xpath 's'
    break
endwhile
Xpath 't'
if !MSG('E15', "Invalid expression")
    Xpath 'u'
endif

let g:test10_result = g:Xpath
delfunction MSG

func Test_expr_parsing()
    call assert_equal('abcdefghilpt', g:test10_result)
endfunc


"-------------------------------------------------------------------------------
" Test 11:  :if, :elseif, :while argument evaluation after abort	    {{{1
"
"	    When code is skipped over due to an error, the boolean argument to
"	    an :if, :elseif, or :while must not be evaluated.
"-------------------------------------------------------------------------------

XpathINIT

let calls = 0

func P(num)
    let g:calls = g:calls + a:num   " side effect on call
    return 0
endfunc

if 1
    Xpath 'a'
    asdf		" error
    Xpath 'b'
    if P(1)		" should not be called
	Xpath 'c'
    elseif !P(2)	" should not be called
	Xpath 'd'
    else
	Xpath 'e'
    endif
    Xpath 'f'
    while P(4)		" should not be called
	Xpath 'g'
    endwhile
    Xpath 'h'
endif
Xpath 'x'

let g:test11_calls = calls
let g:test11_result = g:Xpath

unlet calls
delfunction P

func Test_arg_abort()
    call assert_equal(0, g:test11_calls)
    call assert_equal('ax', g:test11_result)
endfunc


"-------------------------------------------------------------------------------
" Test 12:  Expressions in braces in skipped code			    {{{1
"
"	    In code skipped over due to an error or inactive conditional,
"	    an expression in braces as part of a variable or function name
"	    should not be evaluated.
"-------------------------------------------------------------------------------

XpathINIT

function! NULL()
    Xpath 'a'
    return 0
endfunction

function! ZERO()
    Xpath 'b'
    return 0
endfunction

function! F0()
    Xpath 'c'
endfunction

function! F1(arg)
    Xpath 'e'
endfunction

let V0 = 1

Xpath 'f'
echo 0 ? F{NULL() + V{ZERO()}}() : 1

Xpath 'g'
if 0
    Xpath 'h'
    call F{NULL() + V{ZERO()}}()
endif

Xpath 'i'
if 1
    asdf		" error
    Xpath 'j'
    call F1(F{NULL() + V{ZERO()}}())
endif

Xpath 'k'
if 1
    asdf		" error
    Xpath 'l'
    call F{NULL() + V{ZERO()}}()
endif

let g:test12_result = g:Xpath

func Test_braces_skipped()
    call assert_equal('fgik', g:test12_result)
endfunc


"-------------------------------------------------------------------------------
" Test 13:  Failure in argument evaluation for :while			    {{{1
"
"	    A failure in the expression evaluation for the condition of a :while
"	    causes the whole :while loop until the matching :endwhile being
"	    ignored.  Continuation is at the next following line.
"-------------------------------------------------------------------------------

XpathINIT

Xpath 'a'
while asdf
    Xpath 'b'
    while 1
	Xpath 'c'
	break
    endwhile
    Xpath 'd'
    break
endwhile
Xpath 'e'

while asdf | Xpath 'f' | endwhile | Xpath 'g'
Xpath 'h'
let g:test13_result = g:Xpath

func Test_while_fail()
    call assert_equal('aeh', g:test13_result)
endfunc


"-------------------------------------------------------------------------------
" Test 14:  Failure in argument evaluation for :if			    {{{1
"
"	    A failure in the expression evaluation for the condition of an :if
"	    does not cause the corresponding :else or :endif being matched to
"	    a previous :if/:elseif.  Neither of both branches of the failed :if
"	    are executed.
"-------------------------------------------------------------------------------

XpathINIT

function! F()
    Xpath 'a'
    let x = 0
    if x		" false
	Xpath 'b'
    elseif !x		" always true
	Xpath 'c'
	let x = 1
	if g:boolvar	" possibly undefined
	    Xpath 'd'
	else
	    Xpath 'e'
	endif
	Xpath 'f'
    elseif x		" never executed
	Xpath 'g'
    endif
    Xpath 'h'
endfunction

let boolvar = 1
call F()
Xpath '-'

unlet boolvar
call F()
let g:test14_result = g:Xpath

delfunction F

func Test_if_fail()
    call assert_equal('acdfh-acfh', g:test14_result)
endfunc


"-------------------------------------------------------------------------------
" Test 15:  Failure in argument evaluation for :if (bar)		    {{{1
"
"	    Like previous test, except that the failing :if ... | ... | :endif
"	    is in a single line.
"-------------------------------------------------------------------------------

XpathINIT

function! F()
    Xpath 'a'
    let x = 0
    if x		" false
	Xpath 'b'
    elseif !x		" always true
	Xpath 'c'
	let x = 1
	if g:boolvar | Xpath 'd' | else | Xpath 'e' | endif
	Xpath 'f'
    elseif x		" never executed
	Xpath 'g'
    endif
    Xpath 'h'
endfunction

let boolvar = 1
call F()
Xpath '-'

unlet boolvar
call F()
let g:test15_result = g:Xpath

delfunction F

func Test_if_bar_fail()
    call assert_equal('acdfh-acfh', g:test15_result)
endfunc

"-------------------------------------------------------------------------------
" Test 16:  Double :else or :elseif after :else				    {{{1
"
"	    Multiple :elses or an :elseif after an :else are forbidden.
"-------------------------------------------------------------------------------

func T16_F() abort
  if 0
    Xpath 'a'
  else
    Xpath 'b'
  else		" aborts function
    Xpath 'c'
  endif
  Xpath 'd'
endfunc

func T16_G() abort
  if 0
    Xpath 'a'
  else
    Xpath 'b'
  elseif 1		" aborts function
    Xpath 'c'
  else
    Xpath 'd'
  endif
  Xpath 'e'
endfunc

func T16_H() abort
  if 0
    Xpath 'a'
  elseif 0
    Xpath 'b'
  else
    Xpath 'c'
  else		" aborts function
    Xpath 'd'
  endif
  Xpath 'e'
endfunc

func T16_I() abort
  if 0
    Xpath 'a'
  elseif 0
    Xpath 'b'
  else
    Xpath 'c'
  elseif 1		" aborts function
    Xpath 'd'
  else
    Xpath 'e'
  endif
  Xpath 'f'
endfunc

func Test_Multi_Else()
  XpathINIT
  try
    call T16_F()
  catch /E583:/
    Xpath 'e'
  endtry
  call assert_equal('be', g:Xpath)

  XpathINIT
  try
    call T16_G()
  catch /E584:/
    Xpath 'f'
  endtry
  call assert_equal('bf', g:Xpath)

  XpathINIT
  try
    call T16_H()
  catch /E583:/
    Xpath 'f'
  endtry
  call assert_equal('cf', g:Xpath)

  XpathINIT
  try
    call T16_I()
  catch /E584:/
    Xpath 'g'
  endtry
  call assert_equal('cg', g:Xpath)
endfunc

"-------------------------------------------------------------------------------
" Test 17:  Nesting of unmatched :if or :endif inside a :while		    {{{1
"
"	    The :while/:endwhile takes precedence in nesting over an unclosed
"	    :if or an unopened :endif.
"-------------------------------------------------------------------------------

" While loops inside a function are continued on error.
func T17_F()
  let loops = 3
  while loops > 0
    let loops -= 1
    Xpath 'a' . loops
    if (loops == 1)
      Xpath 'b' . loops
      continue
    elseif (loops == 0)
      Xpath 'c' . loops
      break
    elseif 1
      Xpath 'd' . loops
    " endif missing!
  endwhile	" :endwhile after :if 1
  Xpath 'e'
endfunc

func T17_G()
  let loops = 2
  while loops > 0
    let loops -= 1
    Xpath 'a' . loops
    if 0
      Xpath 'b' . loops
    " endif missing
  endwhile	" :endwhile after :if 0
endfunc

func T17_H()
  let loops = 2
  while loops > 0
    let loops -= 1
    Xpath 'a' . loops
    " if missing!
    endif	" :endif without :if in while
    Xpath 'b' . loops
  endwhile
endfunc

" Error continuation outside a function is at the outermost :endwhile or :endif.
XpathINIT
let v:errmsg = ''
let loops = 2
while loops > 0
    let loops -= 1
    Xpath 'a' . loops
    if 0
	Xpath 'b' . loops
    " endif missing! Following :endwhile fails.
endwhile | Xpath 'c'
Xpath 'd'
call assert_match('E171:', v:errmsg)
call assert_equal('a1d', g:Xpath)

func Test_unmatched_if_in_while()
  XpathINIT
  call assert_fails('call T17_F()', 'E171:')
  call assert_equal('a2d2a1b1a0c0e', g:Xpath)

  XpathINIT
  call assert_fails('call T17_G()', 'E171:')
  call assert_equal('a1a0', g:Xpath)

  XpathINIT
  call assert_fails('call T17_H()', 'E580:')
  call assert_equal('a1b1a0b0', g:Xpath)
endfunc

"-------------------------------------------------------------------------------
" Test 18:  Interrupt (Ctrl-C pressed)					    {{{1
"
"	    On an interrupt, the script processing is terminated immediately.
"-------------------------------------------------------------------------------

func Test_interrupt_while_if()
  let test =<< trim [CODE]
    try
      if 1
        Xpath 'a'
        while 1
          Xpath 'b'
          if 1
            Xpath 'c'
            call interrupt()
            call assert_report('should not get here')
            break
            finish
          endif | call assert_report('should not get here')
          call assert_report('should not get here')
        endwhile | call assert_report('should not get here')
        call assert_report('should not get here')
      endif | call assert_report('should not get here')
      call assert_report('should not get here')
    catch /^Vim:Interrupt$/
      Xpath 'd'
    endtry | Xpath 'e'
    Xpath 'f'
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('abcdef', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

func Test_interrupt_try()
  let test =<< trim [CODE]
    try
      try
        Xpath 'a'
        call interrupt()
        call assert_report('should not get here')
      endtry | call assert_report('should not get here')
      call assert_report('should not get here')
    catch /^Vim:Interrupt$/
      Xpath 'b'
    endtry | Xpath 'c'
    Xpath 'd'
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('abcd', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

func Test_interrupt_func_while_if()
  let test =<< trim [CODE]
    func F()
      if 1
        Xpath 'a'
        while 1
          Xpath 'b'
          if 1
            Xpath 'c'
            call interrupt()
            call assert_report('should not get here')
            break
            return
          endif | call assert_report('should not get here')
          call assert_report('should not get here')
        endwhile | call assert_report('should not get here')
        call assert_report('should not get here')
      endif | call assert_report('should not get here')
      call assert_report('should not get here')
    endfunc

    Xpath 'd'
    try
      call F() | call assert_report('should not get here')
    catch /^Vim:Interrupt$/
      Xpath 'e'
    endtry | Xpath 'f'
    Xpath 'g'
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('dabcefg', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

func Test_interrupt_func_try()
  let test =<< trim [CODE]
    func G()
      try
        Xpath 'a'
        call interrupt()
        call assert_report('should not get here')
      endtry | call assert_report('should not get here')
      call assert_report('should not get here')
    endfunc

    Xpath 'b'
    try
      call G() | call assert_report('should not get here')
    catch /^Vim:Interrupt$/
      Xpath 'c'
    endtry | Xpath 'd'
    Xpath 'e'
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('bacde', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

"-------------------------------------------------------------------------------
" Test 19:  Aborting on errors inside :try/:endtry			    {{{1
"
"	    An error in a command dynamically enclosed in a :try/:endtry region
"	    aborts script processing immediately.  It does not matter whether
"	    the failing command is outside or inside a function and whether a
"	    function has an "abort" attribute.
"-------------------------------------------------------------------------------

func Test_try_error_abort_1()
  let test =<< trim [CODE]
    func F() abort
      Xpath 'a'
      asdf
      call assert_report('should not get here')
    endfunc

    try
      Xpath 'b'
      call F()
      call assert_report('should not get here')
    endtry | call assert_report('should not get here')
    call assert_report('should not get here')
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('ba', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

func Test_try_error_abort_2()
  let test =<< trim [CODE]
    func G()
      Xpath 'a'
      asdf
      call assert_report('should not get here')
    endfunc

    try
      Xpath 'b'
      call G()
      call assert_report('should not get here')
    endtry | call assert_report('should not get here')
    call assert_report('should not get here')
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('ba', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

func Test_try_error_abort_3()
  let test =<< trim [CODE]
    try
      Xpath 'a'
      asdf
      call assert_report('should not get here')
    endtry | call assert_report('should not get here')
    call assert_report('should not get here')
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('a', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

func Test_try_error_abort_4()
  let test =<< trim [CODE]
    if 1
      try
        Xpath 'a'
        asdf
        call assert_report('should not get here')
      endtry | call assert_report('should not get here')
    endif | call assert_report('should not get here')
    call assert_report('should not get here')
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('a', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

func Test_try_error_abort_5()
  let test =<< trim [CODE]
    let p = 1
    while p
      let p = 0
      try
        Xpath 'a'
        asdf
        call assert_report('should not get here')
      endtry | call assert_report('should not get here')
    endwhile | call assert_report('should not get here')
    call assert_report('should not get here')
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('a', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

func Test_try_error_abort_6()
  let test =<< trim [CODE]
    let p = 1
    Xpath 'a'
    while p
      Xpath 'b'
      let p = 0
      try
        Xpath 'c'
    endwhile | call assert_report('should not get here')
    call assert_report('should not get here')
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('abc', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

"-------------------------------------------------------------------------------
" Test 20:  Aborting on errors after :try/:endtry			    {{{1
"
"	    When an error occurs after the last active :try/:endtry region has
"	    been left, termination behavior is as if no :try/:endtry has been
"	    seen.
"-------------------------------------------------------------------------------

func Test_error_after_try_1()
  let test =<< trim [CODE]
    let p = 1
    while p
      let p = 0
      Xpath 'a'
      try
        Xpath 'b'
      endtry
      asdf
      call assert_report('should not get here')
    endwhile | call assert_report('should not get here')
    Xpath 'c'
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('abc', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

func Test_error_after_try_2()
  let test =<< trim [CODE]
    while 1
      try
        Xpath 'a'
        break
        call assert_report('should not get here')
      endtry
    endwhile
    Xpath 'b'
    asdf
    Xpath 'c'
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('abc', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

func Test_error_after_try_3()
  let test =<< trim [CODE]
    while 1
      try
        Xpath 'a'
        break
        call assert_report('should not get here')
      finally
        Xpath 'b'
      endtry
    endwhile
    Xpath 'c'
    asdf
    Xpath 'd'
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('abcd', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

func Test_error_after_try_4()
  let test =<< trim [CODE]
    while 1
      try
        Xpath 'a'
      finally
        Xpath 'b'
        break
        call assert_report('should not get here')
      endtry
    endwhile
    Xpath 'c'
    asdf
    Xpath 'd'
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('abcd', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

func Test_error_after_try_5()
  let test =<< trim [CODE]
    let p = 1
    while p
      let p = 0
      try
        Xpath 'a'
        continue
        call assert_report('should not get here')
      endtry
    endwhile
    Xpath 'b'
    asdf
    Xpath 'c'
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('abc', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

func Test_error_after_try_6()
  let test =<< trim [CODE]
    let p = 1
    while p
      let p = 0
      try
        Xpath 'a'
        continue
        call assert_report('should not get here')
      finally
        Xpath 'b'
      endtry
    endwhile
    Xpath 'c'
    asdf
    Xpath 'd'
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('abcd', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

func Test_error_after_try_7()
  let test =<< trim [CODE]
    let p = 1
    while p
      let p = 0
      try
        Xpath 'a'
      finally
        Xpath 'b'
        continue
        call assert_report('should not get here')
      endtry
    endwhile
    Xpath 'c'
    asdf
    Xpath 'd'
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('abcd', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

"-------------------------------------------------------------------------------
" Test 21:  :finally for :try after :continue/:break/:return/:finish	    {{{1
"
"	    If a :try conditional stays inactive due to a preceding :continue,
"	    :break, :return, or :finish, its :finally clause should not be
"	    executed.
"-------------------------------------------------------------------------------

func Test_finally_after_loop_ctrl_statement()
  let test =<< trim [CODE]
    func F()
      let loops = 2
      while loops > 0
        XloopNEXT
        let loops = loops - 1
        try
          if loops == 1
            Xloop 'a'
            continue
            call assert_report('should not get here')
          elseif loops == 0
            Xloop 'b'
            break
            call assert_report('should not get here')
          endif

          try		" inactive
            call assert_report('should not get here')
          finally
            call assert_report('should not get here')
          endtry
        finally
          Xloop 'c'
        endtry
        call assert_report('should not get here')
      endwhile

      try
        Xpath 'd'
        return
        call assert_report('should not get here')
        try		    " inactive
          call assert_report('should not get here')
        finally
          call assert_report('should not get here')
        endtry
      finally
        Xpath 'e'
      endtry
      call assert_report('should not get here')
    endfunc

    try
      Xpath 'f'
      call F()
      Xpath 'g'
      finish
      call assert_report('should not get here')
      try		" inactive
        call assert_report('should not get here')
      finally
        call assert_report('should not get here')
      endtry
    finally
      Xpath 'h'
    endtry
    call assert_report('should not get here')
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('fa2c2b3c3degh', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

"-------------------------------------------------------------------------------
" Test 22:  :finally for a :try after an error/interrupt/:throw		    {{{1
"
"	    If a :try conditional stays inactive due to a preceding error or
"	    interrupt or :throw, its :finally clause should not be executed.
"-------------------------------------------------------------------------------

func Test_finally_after_error_in_func()
  let test =<< trim [CODE]
    func Error()
      try
        Xpath 'b'
        asdf    " aborting error, triggering error exception
        call assert_report('should not get here')
      endtry
      call assert_report('should not get here')
    endfunc

    Xpath 'a'
    call Error()
    call assert_report('should not get here')

    if 1	" not active due to error
      try	" not active since :if inactive
        call assert_report('should not get here')
      finally
        call assert_report('should not get here')
      endtry
    endif

    try		" not active due to error
      call assert_report('should not get here')
    finally
      call assert_report('should not get here')
    endtry
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('ab', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

func Test_finally_after_interrupt()
  let test =<< trim [CODE]
    func Interrupt()
      try
        Xpath 'a'
        call interrupt()            " triggering interrupt exception
        call assert_report('should not get here')
      endtry
    endfunc

    Xpath 'b'
    try
      call Interrupt()
    catch /^Vim:Interrupt$/
      Xpath 'c'
      finish
    endtry
    call assert_report('should not get here')

    if 1	" not active due to interrupt
      try	" not active since :if inactive
        call assert_report('should not get here')
      finally
        call assert_report('should not get here')
      endtry
    endif

    try		" not active due to interrupt
      call assert_report('should not get here')
    finally
      call assert_report('should not get here')
    endtry
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('bac', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

func Test_finally_after_throw()
  let test =<< trim [CODE]
    func Throw()
      Xpath 'a'
      throw 'xyz'
    endfunc

    Xpath 'b'
    call Throw()
    call assert_report('should not get here')

    if 1	" not active due to :throw
      try	" not active since :if inactive
        call assert_report('should not get here')
      finally
        call assert_report('should not get here')
      endtry
    endif

    try		" not active due to :throw
      call assert_report('should not get here')
    finally
      call assert_report('should not get here')
    endtry
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('ba', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

"-------------------------------------------------------------------------------
" Test 23:  :catch clauses for a :try after a :throw			    {{{1
"
"	    If a :try conditional stays inactive due to a preceding :throw,
"	    none of its :catch clauses should be executed.
"-------------------------------------------------------------------------------

func Test_catch_after_throw()
  let test =<< trim [CODE]
    try
      Xpath 'a'
      throw "xyz"
      call assert_report('should not get here')

      if 1	" not active due to :throw
        try	" not active since :if inactive
          call assert_report('should not get here')
        catch /xyz/
          call assert_report('should not get here')
        endtry
      endif
    catch /xyz/
      Xpath 'b'
    endtry

    Xpath 'c'
    throw "abc"
    call assert_report('should not get here')

    try		" not active due to :throw
      call assert_report('should not get here')
    catch /abc/
      call assert_report('should not get here')
    endtry
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('abc', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

"-------------------------------------------------------------------------------
" Test 24:  :endtry for a :try after a :throw				    {{{1
"
"	    If a :try conditional stays inactive due to a preceding :throw,
"	    its :endtry should not rethrow the exception to the next surrounding
"	    active :try conditional.
"-------------------------------------------------------------------------------

func Test_endtry_after_throw()
  let test =<< trim [CODE]
    try			" try 1
      try		" try 2
        Xpath 'a'
        throw "xyz"	" makes try 2 inactive
        call assert_report('should not get here')

        try		" try 3
          call assert_report('should not get here')
        endtry	" no rethrow to try 1
      catch /xyz/	" should catch although try 2 inactive
        Xpath 'b'
      endtry
    catch /xyz/		" try 1 active, but exception already caught
      call assert_report('should not get here')
    endtry
    Xpath 'c'
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('abc', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

"-------------------------------------------------------------------------------
" Test 27:  Executing :finally clauses after :return			    {{{1
"
"	    For a :return command dynamically enclosed in a :try/:endtry region,
"	    :finally clauses are executed and the called function is ended.
"-------------------------------------------------------------------------------

func T27_F()
  try
    Xpath 'a'
    try
      Xpath 'b'
      return
      call assert_report('should not get here')
    finally
      Xpath 'c'
    endtry
    Xpath 'd'
  finally
    Xpath 'e'
  endtry
  call assert_report('should not get here')
endfunc

func T27_G()
  try
    Xpath 'f'
    return
    call assert_report('should not get here')
  finally
    Xpath 'g'
    call T27_F()
    Xpath 'h'
  endtry
  call assert_report('should not get here')
endfunc

func T27_H()
  try
    Xpath 'i'
    call T27_G()
    Xpath 'j'
  finally
    Xpath 'k'
    return
    call assert_report('should not get here')
  endtry
  call assert_report('should not get here')
endfunction

func Test_finally_after_return()
  XpathINIT
  try
      Xpath 'l'
      call T27_H()
      Xpath 'm'
  finally
      Xpath 'n'
  endtry
  call assert_equal('lifgabcehjkmn', g:Xpath)
endfunc

"-------------------------------------------------------------------------------
" Test 28:  Executing :finally clauses after :finish			    {{{1
"
"	    For a :finish command dynamically enclosed in a :try/:endtry region,
"	    :finally clauses are executed and the sourced file is finished.
"
"	    This test executes the bodies of the functions F, G, and H from the
"	    previous test as script files (:return replaced by :finish).
"-------------------------------------------------------------------------------

func Test_finally_after_finish()
  XpathINIT

  let scriptF = MakeScript("T27_F")
  let scriptG = MakeScript("T27_G", scriptF)
  let scriptH = MakeScript("T27_H", scriptG)

  try
    Xpath 'A'
    exec "source" scriptH
    Xpath 'B'
  finally
    Xpath 'C'
  endtry
  Xpath 'D'
  call assert_equal('AifgabcehjkBCD', g:Xpath)
  call delete(scriptF)
  call delete(scriptG)
  call delete(scriptH)
endfunc

"-------------------------------------------------------------------------------
" Test 29:  Executing :finally clauses on errors			    {{{1
"
"	    After an error in a command dynamically enclosed in a :try/:endtry
"	    region, :finally clauses are executed and the script processing is
"	    terminated.
"-------------------------------------------------------------------------------

func Test_finally_after_error_1()
  let test =<< trim [CODE]
    func F()
      while 1
        try
          Xpath 'a'
          while 1
            try
              Xpath 'b'
              asdf	    " error
              call assert_report('should not get here')
            finally
              Xpath 'c'
            endtry | call assert_report('should not get here')
            call assert_report('should not get here')
            break
          endwhile
          call assert_report('should not get here')
        finally
          Xpath 'd'
        endtry | call assert_report('should not get here')
        call assert_report('should not get here')
        break
      endwhile
      call assert_report('should not get here')
    endfunc

    while 1
      try
        Xpath 'e'
        while 1
          call F()
          call assert_report('should not get here')
          break
        endwhile  | call assert_report('should not get here')
        call assert_report('should not get here')
      finally
        Xpath 'f'
      endtry | call assert_report('should not get here')
    endwhile | call assert_report('should not get here')
    call assert_report('should not get here')
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('eabcdf', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

func Test_finally_after_error_2()
  let test =<< trim [CODE]
    func G() abort
      if 1
        try
          Xpath 'a'
          asdf	    " error
          call assert_report('should not get here')
        finally
          Xpath 'b'
        endtry | Xpath 'c'
      endif | Xpath 'd'
      call assert_report('should not get here')
    endfunc

    if 1
      try
        Xpath 'e'
        call G()
        call assert_report('should not get here')
      finally
        Xpath 'f'
      endtry | call assert_report('should not get here')
    endif | call assert_report('should not get here')
    call assert_report('should not get here')
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('eabf', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

"-------------------------------------------------------------------------------
" Test 30:  Executing :finally clauses on interrupt			    {{{1
"
"	    After an interrupt in a command dynamically enclosed in
"	    a :try/:endtry region, :finally clauses are executed and the
"	    script processing is terminated.
"-------------------------------------------------------------------------------

func Test_finally_on_interrupt()
  let test =<< trim [CODE]
    func F()
      try
        Xloop 'a'
        call interrupt()
        call assert_report('should not get here')
      finally
        Xloop 'b'
      endtry
      call assert_report('should not get here')
    endfunc

    try
      try
        Xpath 'c'
        try
          Xpath 'd'
          call interrupt()
          call assert_report('should not get here')
        finally
          Xpath 'e'
          try
            Xpath 'f'
            try
              Xpath 'g'
            finally
              Xpath 'h'
              try
                Xpath 'i'
                call interrupt()
                call assert_report('should not get here')
              endtry
              call assert_report('should not get here')
            endtry
            call assert_report('should not get here')
          endtry
          call assert_report('should not get here')
        endtry
        call assert_report('should not get here')
      finally
        Xpath 'j'
        try
          Xpath 'k'
          call F()
          call assert_report('should not get here')
        finally
          Xpath 'l'
          try
            Xpath 'm'
            XloopNEXT
            ExecAsScript F
            call assert_report('should not get here')
          finally
            Xpath 'n'
          endtry
          call assert_report('should not get here')
        endtry
        call assert_report('should not get here')
      endtry
      call assert_report('should not get here')
    catch /^Vim:Interrupt$/
      Xpath 'o'
    endtry
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('cdefghijka1b1lma2b2no', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

"-------------------------------------------------------------------------------
" Test 31:  Executing :finally clauses after :throw			    {{{1
"
"	    After a :throw dynamically enclosed in a :try/:endtry region,
"	    :finally clauses are executed and the script processing is
"	    terminated.
"-------------------------------------------------------------------------------

func Test_finally_after_throw_2()
  let test =<< trim [CODE]
    func F()
      try
        Xloop 'a'
        throw "exception"
        call assert_report('should not get here')
      finally
        Xloop 'b'
      endtry
      call assert_report('should not get here')
    endfunc

    try
      Xpath 'c'
      try
        Xpath 'd'
        throw "exception"
        call assert_report('should not get here')
      finally
        Xpath 'e'
        try
          Xpath 'f'
          try
            Xpath 'g'
          finally
            Xpath 'h'
            try
              Xpath 'i'
              throw "exception"
              call assert_report('should not get here')
            endtry
            call assert_report('should not get here')
          endtry
          call assert_report('should not get here')
        endtry
        call assert_report('should not get here')
      endtry
      call assert_report('should not get here')
    finally
      Xpath 'j'
      try
        Xpath 'k'
        call F()
        call assert_report('should not get here')
      finally
        Xpath 'l'
        try
          Xpath 'm'
          XloopNEXT
          ExecAsScript F
          call assert_report('should not get here')
        finally
          Xpath 'n'
        endtry
        call assert_report('should not get here')
      endtry
      call assert_report('should not get here')
    endtry
    call assert_report('should not get here')
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('cdefghijka1b1lma2b2n', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

"-------------------------------------------------------------------------------
" Test 34:  :finally reason discarded by :continue			    {{{1
"
"	    When a :finally clause is executed due to a :continue, :break,
"	    :return, :finish, error, interrupt or :throw, the jump reason is
"	    discarded by a :continue in the finally clause.
"-------------------------------------------------------------------------------

func Test_finally_after_continue()
  let test =<< trim [CODE]
    func C(jump)
      XloopNEXT
      let loop = 0
      while loop < 2
        let loop = loop + 1
        if loop == 1
          try
            if a:jump == "continue"
              continue
            elseif a:jump == "break"
              break
            elseif a:jump == "return" || a:jump == "finish"
              return
            elseif a:jump == "error"
              asdf
            elseif a:jump == "interrupt"
              call interrupt()
              let dummy = 0
            elseif a:jump == "throw"
              throw "abc"
            endif
          finally
            continue	" discards jump that caused the :finally
            call assert_report('should not get here')
          endtry
          call assert_report('should not get here')
        elseif loop == 2
          Xloop 'a'
        endif
      endwhile
    endfunc

    call C("continue")
    Xpath 'b'
    call C("break")
    Xpath 'c'
    call C("return")
    Xpath 'd'
    let g:jump = "finish"
    ExecAsScript C
    unlet g:jump
    Xpath 'e'
    try
      call C("error")
      Xpath 'f'
    finally
      Xpath 'g'
      try
        call C("interrupt")
        Xpath 'h'
      finally
        Xpath 'i'
        call C("throw")
        Xpath 'j'
      endtry
    endtry
    Xpath 'k'
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('a2ba3ca4da5ea6fga7hia8jk', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

"-------------------------------------------------------------------------------
" Test 35:  :finally reason discarded by :break				    {{{1
"
"	    When a :finally clause is executed due to a :continue, :break,
"	    :return, :finish, error, interrupt or :throw, the jump reason is
"	    discarded by a :break in the finally clause.
"-------------------------------------------------------------------------------

func Test_finally_discard_by_break()
  let test =<< trim [CODE]
    func B(jump)
      XloopNEXT
      let loop = 0
      while loop < 2
        let loop = loop + 1
        if loop == 1
          try
            if a:jump == "continue"
              continue
            elseif a:jump == "break"
              break
            elseif a:jump == "return" || a:jump == "finish"
              return
            elseif a:jump == "error"
              asdf
            elseif a:jump == "interrupt"
              call interrupt()
              let dummy = 0
            elseif a:jump == "throw"
              throw "abc"
            endif
          finally
            break	" discards jump that caused the :finally
            call assert_report('should not get here')
          endtry
        elseif loop == 2
          call assert_report('should not get here')
        endif
      endwhile
      Xloop 'a'
    endfunc

    call B("continue")
    Xpath 'b'
    call B("break")
    Xpath 'c'
    call B("return")
    Xpath 'd'
    let g:jump = "finish"
    ExecAsScript B
    unlet g:jump
    Xpath 'e'
    try
      call B("error")
      Xpath 'f'
    finally
      Xpath 'g'
      try
        call B("interrupt")
        Xpath 'h'
      finally
        Xpath 'i'
        call B("throw")
        Xpath 'j'
      endtry
    endtry
    Xpath 'k'
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('a2ba3ca4da5ea6fga7hia8jk', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

"-------------------------------------------------------------------------------
" Test 36:  :finally reason discarded by :return			    {{{1
"
"	    When a :finally clause is executed due to a :continue, :break,
"	    :return, :finish, error, interrupt or :throw, the jump reason is
"	    discarded by a :return in the finally clause.
"-------------------------------------------------------------------------------

func Test_finally_discard_by_return()
  let test =<< trim [CODE]
    func R(jump, retval) abort
      let loop = 0
      while loop < 2
        let loop = loop + 1
        if loop == 1
          try
            if a:jump == "continue"
              continue
            elseif a:jump == "break"
              break
            elseif a:jump == "return"
              return
            elseif a:jump == "error"
              asdf
            elseif a:jump == "interrupt"
              call interrupt()
              let dummy = 0
            elseif a:jump == "throw"
              throw "abc"
            endif
          finally
            return a:retval	" discards jump that caused the :finally
            call assert_report('should not get here')
          endtry
        elseif loop == 2
          call assert_report('should not get here')
        endif
      endwhile
      call assert_report('should not get here')
    endfunc

    let sum =  -R("continue", -8)
    Xpath 'a'
    let sum = sum - R("break", -16)
    Xpath 'b'
    let sum = sum - R("return", -32)
    Xpath 'c'
    try
      let sum = sum - R("error", -64)
      Xpath 'd'
    finally
      Xpath 'e'
      try
        let sum = sum - R("interrupt", -128)
        Xpath 'f'
      finally
        Xpath 'g'
        let sum = sum - R("throw", -256)
        Xpath 'h'
      endtry
    endtry
    Xpath 'i'

    let expected = 8 + 16 + 32 + 64 + 128 + 256
    call assert_equal(sum, expected)
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('abcdefghi', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

"-------------------------------------------------------------------------------
" Test 37:  :finally reason discarded by :finish			    {{{1
"
"	    When a :finally clause is executed due to a :continue, :break,
"	    :return, :finish, error, interrupt or :throw, the jump reason is
"	    discarded by a :finish in the finally clause.
"-------------------------------------------------------------------------------

func Test_finally_discard_by_finish()
  let test =<< trim [CODE]
    func F(jump)	" not executed as function, transformed to a script
      let loop = 0
      while loop < 2
        let loop = loop + 1
        if loop == 1
          try
            if a:jump == "continue"
              continue
            elseif a:jump == "break"
              break
            elseif a:jump == "finish"
              finish
            elseif a:jump == "error"
              asdf
            elseif a:jump == "interrupt"
              call interrupt()
              let dummy = 0
            elseif a:jump == "throw"
              throw "abc"
            endif
          finally
            finish	" discards jump that caused the :finally
            call assert_report('should not get here')
          endtry
        elseif loop == 2
          call assert_report('should not get here')
        endif
      endwhile
      call assert_report('should not get here')
    endfunc

    let scriptF = MakeScript("F")
    delfunction F

    let g:jump = "continue"
    exec "source" scriptF
    Xpath 'a'
    let g:jump = "break"
    exec "source" scriptF
    Xpath 'b'
    let g:jump = "finish"
    exec "source" scriptF
    Xpath 'c'
    try
      let g:jump = "error"
      exec "source" scriptF
      Xpath 'd'
    finally
      Xpath 'e'
      try
        let g:jump = "interrupt"
        exec "source" scriptF
        Xpath 'f'
      finally
        Xpath 'g'
        try
          let g:jump = "throw"
          exec "source" scriptF
          Xpath 'h'
        finally
          Xpath 'i'
        endtry
      endtry
    endtry
    unlet g:jump
    call delete(scriptF)
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('abcdefghi', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

"-------------------------------------------------------------------------------
" Test 38:  :finally reason discarded by an error			    {{{1
"
"	    When a :finally clause is executed due to a :continue, :break,
"	    :return, :finish, error, interrupt or :throw, the jump reason is
"	    discarded by an error in the finally clause.
"-------------------------------------------------------------------------------

func Test_finally_discard_by_error()
  let test =<< trim [CODE]
    func E(jump)
      let loop = 0
      while loop < 2
        let loop = loop + 1
        if loop == 1
          try
            if a:jump == "continue"
              continue
            elseif a:jump == "break"
              break
            elseif a:jump == "return" || a:jump == "finish"
              return
            elseif a:jump == "error"
              asdf
            elseif a:jump == "interrupt"
              call interrupt()
              let dummy = 0
            elseif a:jump == "throw"
              throw "abc"
            endif
          finally
            asdf	" error; discards jump that caused the :finally
          endtry
        elseif loop == 2
          call assert_report('should not get here')
        endif
      endwhile
      call assert_report('should not get here')
    endfunc

    try
      Xpath 'a'
      call E("continue")
      call assert_report('should not get here')
    finally
      try
        Xpath 'b'
        call E("break")
        call assert_report('should not get here')
      finally
        try
          Xpath 'c'
          call E("return")
          call assert_report('should not get here')
        finally
          try
            Xpath 'd'
            let g:jump = "finish"
            ExecAsScript E
            call assert_report('should not get here')
          finally
            unlet g:jump
            try
              Xpath 'e'
              call E("error")
              call assert_report('should not get here')
            finally
              try
                Xpath 'f'
                call E("interrupt")
                call assert_report('should not get here')
              finally
                try
                  Xpath 'g'
                  call E("throw")
                  call assert_report('should not get here')
                finally
                  Xpath 'h'
                  delfunction E
                endtry
              endtry
            endtry
          endtry
        endtry
      endtry
    endtry
    call assert_report('should not get here')
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('abcdefgh', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

"-------------------------------------------------------------------------------
" Test 39:  :finally reason discarded by an interrupt			    {{{1
"
"	    When a :finally clause is executed due to a :continue, :break,
"	    :return, :finish, error, interrupt or :throw, the jump reason is
"	    discarded by an interrupt in the finally clause.
"-------------------------------------------------------------------------------

func Test_finally_discarded_by_interrupt()
  let test =<< trim [CODE]
    func I(jump)
      let loop = 0
      while loop < 2
        let loop = loop + 1
        if loop == 1
          try
            if a:jump == "continue"
              continue
            elseif a:jump == "break"
              break
            elseif a:jump == "return" || a:jump == "finish"
              return
            elseif a:jump == "error"
              asdf
            elseif a:jump == "interrupt"
              call interrupt()
              let dummy = 0
            elseif a:jump == "throw"
              throw "abc"
            endif
          finally
            call interrupt()
            let dummy = 0
          endtry
        elseif loop == 2
          call assert_report('should not get here')
        endif
      endwhile
      call assert_report('should not get here')
    endfunc

    try
      try
        Xpath 'a'
        call I("continue")
        call assert_report('should not get here')
      finally
        try
          Xpath 'b'
          call I("break")
          call assert_report('should not get here')
        finally
          try
            Xpath 'c'
            call I("return")
            call assert_report('should not get here')
          finally
            try
              Xpath 'd'
              let g:jump = "finish"
              ExecAsScript I
              call assert_report('should not get here')
            finally
              unlet g:jump
              try
                Xpath 'e'
                call I("error")
                call assert_report('should not get here')
              finally
                try
                  Xpath 'f'
                  call I("interrupt")
                  call assert_report('should not get here')
                finally
                  try
                    Xpath 'g'
                    call I("throw")
                    call assert_report('should not get here')
                  finally
                    Xpath 'h'
                    delfunction I
                  endtry
                endtry
              endtry
            endtry
          endtry
        endtry
      endtry
      call assert_report('should not get here')
    catch /^Vim:Interrupt$/
      Xpath 'A'
    endtry
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('abcdefghA', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

"-------------------------------------------------------------------------------
" Test 40:  :finally reason discarded by :throw				    {{{1
"
"	    When a :finally clause is executed due to a :continue, :break,
"	    :return, :finish, error, interrupt or :throw, the jump reason is
"	    discarded by a :throw in the finally clause.
"-------------------------------------------------------------------------------

func Test_finally_discard_by_throw()
  let test =<< trim [CODE]
    func T(jump)
      let loop = 0
      while loop < 2
        let loop = loop + 1
        if loop == 1
          try
            if a:jump == "continue"
              continue
            elseif a:jump == "break"
              break
            elseif a:jump == "return" || a:jump == "finish"
              return
            elseif a:jump == "error"
              asdf
            elseif a:jump == "interrupt"
              call interrupt()
              let dummy = 0
            elseif a:jump == "throw"
              throw "abc"
            endif
          finally
            throw "xyz"	" discards jump that caused the :finally
          endtry
        elseif loop == 2
          call assert_report('should not get here')
        endif
      endwhile
      call assert_report('should not get here')
    endfunc

    try
      Xpath 'a'
      call T("continue")
      call assert_report('should not get here')
    finally
      try
        Xpath 'b'
        call T("break")
        call assert_report('should not get here')
      finally
        try
          Xpath 'c'
          call T("return")
          call assert_report('should not get here')
        finally
          try
            Xpath 'd'
            let g:jump = "finish"
            ExecAsScript T
            call assert_report('should not get here')
          finally
            unlet g:jump
            try
              Xpath 'e'
              call T("error")
              call assert_report('should not get here')
            finally
              try
                Xpath 'f'
                call T("interrupt")
                call assert_report('should not get here')
              finally
                try
                  Xpath 'g'
                  call T("throw")
                  call assert_report('should not get here')
                finally
                  Xpath 'h'
                  delfunction T
                endtry
              endtry
            endtry
          endtry
        endtry
      endtry
    endtry
    call assert_report('should not get here')
  [CODE]
  let verify =<< trim [CODE]
    call assert_equal('abcdefgh', g:Xpath)
  [CODE]
  call RunInNewVim(test, verify)
endfunc

"-------------------------------------------------------------------------------
" Test 49:  Throwing exceptions across functions			    {{{1
"
"	    When an exception is thrown but not caught inside a function, the
"	    caller is checked for a matching :catch clause.
"-------------------------------------------------------------------------------

func T49_C()
  try
    Xpath 'a'
    throw "arrgh"
    call assert_report('should not get here')
  catch /arrgh/
    Xpath 'b'
  endtry
  Xpath 'c'
endfunc

func T49_T1()
  XloopNEXT
  try
    Xloop 'd'
    throw "arrgh"
    call assert_report('should not get here')
  finally
    Xloop 'e'
  endtry
  Xloop 'f'
endfunc

func T49_T2()
  try
    Xpath 'g'
    call T49_T1()
    call assert_report('should not get here')
  finally
    Xpath 'h'
  endtry
  call assert_report('should not get here')
endfunc

func Test_throw_exception_across_funcs()
  XpathINIT
  XloopINIT
  try
    Xpath 'i'
    call T49_C()            " throw and catch
    Xpath 'j'
  catch /.*/
    call assert_report('should not get here')
  endtry

  try
    Xpath 'k'
    call T49_T1()  " throw, one level
    call assert_report('should not get here')
  catch /arrgh/
    Xpath 'l'
  catch /.*/
    call assert_report('should not get here')
  endtry

  try
    Xpath 'm'
    call T49_T2()	" throw, two levels
    call assert_report('should not get here')
  catch /arrgh/
    Xpath 'n'
  catch /.*/
    call assert_report('should not get here')
  endtry
  Xpath 'o'

  call assert_equal('iabcjkd2e2lmgd3e3hno', g:Xpath)
endfunc

"-------------------------------------------------------------------------------
" Test 50:  Throwing exceptions across script files			    {{{1
"
"	    When an exception is thrown but not caught inside a script file,
"	    the sourcing script or function is checked for a matching :catch
"	    clause.
"
"	    This test executes the bodies of the functions C, T1, and T2 from
"	    the previous test as script files (:return replaced by :finish).
"-------------------------------------------------------------------------------

func T50_F()
  try
    Xpath 'A'
    exec "source" g:scriptC
    Xpath 'B'
  catch /.*/
    call assert_report('should not get here')
  endtry

  try
    Xpath 'C'
    exec "source" g:scriptT1
    call assert_report('should not get here')
  catch /arrgh/
    Xpath 'D'
  catch /.*/
    call assert_report('should not get here')
  endtry
endfunc

func Test_throw_across_script()
  XpathINIT
  XloopINIT
  let g:scriptC = MakeScript("T49_C")
  let g:scriptT1 = MakeScript("T49_T1")
  let scriptT2 = MakeScript("T49_T2", g:scriptT1)

  try
    Xpath 'E'
    call T50_F()
    Xpath 'F'
    exec "source" scriptT2
    call assert_report('should not get here')
  catch /arrgh/
    Xpath 'G'
  catch /.*/
    call assert_report('should not get here')
  endtry
  Xpath 'H'
  call assert_equal('EAabcBCd2e2DFgd3e3hGH', g:Xpath)

  call delete(g:scriptC)
  call delete(g:scriptT1)
  call delete(scriptT2)
  unlet g:scriptC g:scriptT1 scriptT2
endfunc

"-------------------------------------------------------------------------------
" Test 87   using (expr) ? funcref : funcref				    {{{1
"
"	    Vim needs to correctly parse the funcref and even when it does
"	    not execute the funcref, it needs to consume the trailing ()
"-------------------------------------------------------------------------------

func Add2(x1, x2)
  return a:x1 + a:x2
endfu

func GetStr()
  return "abcdefghijklmnopqrstuvwxyp"
endfu

func Test_funcref_with_condexpr()
  call assert_equal(5, function('Add2')(2,3))

  call assert_equal(3, 1 ? function('Add2')(1,2) : function('Add2')(2,3))
  call assert_equal(5, 0 ? function('Add2')(1,2) : function('Add2')(2,3))
  " Make sure, GetStr() still works.
  call assert_equal('abcdefghijk', GetStr()[0:10])
endfunc

" Test 90:  Recognizing {} in variable name.			    {{{1
"-------------------------------------------------------------------------------

func Test_curlies()
    let s:var = 66
    let ns = 's'
    call assert_equal(66, {ns}:var)

    let g:a = {}
    let g:b = 't'
    let g:a[g:b] = 77
    call assert_equal(77, g:a['t'])
endfunc

"-------------------------------------------------------------------------------
" Test 91:  using type().					    {{{1
"-------------------------------------------------------------------------------

func Test_type()
    call assert_equal(0, type(0))
    call assert_equal(1, type(""))
    call assert_equal(2, type(function("tr")))
    call assert_equal(2, type(function("tr", [8])))
    call assert_equal(3, type([]))
    call assert_equal(4, type({}))
    if has('float')
      call assert_equal(5, type(0.0))
    endif
    call assert_equal(6, type(v:false))
    call assert_equal(6, type(v:true))
    call assert_equal(7, type(v:none))
    call assert_equal(7, type(v:null))
    call assert_equal(8, v:t_job)
    call assert_equal(9, v:t_channel)
    call assert_equal(v:t_number, type(0))
    call assert_equal(v:t_string, type(""))
    call assert_equal(v:t_func, type(function("tr")))
    call assert_equal(v:t_func, type(function("tr", [8])))
    call assert_equal(v:t_list, type([]))
    call assert_equal(v:t_dict, type({}))
    if has('float')
      call assert_equal(v:t_float, type(0.0))
    endif
    call assert_equal(v:t_bool, type(v:false))
    call assert_equal(v:t_bool, type(v:true))
    call assert_equal(v:t_none, type(v:none))
    call assert_equal(v:t_none, type(v:null))
    call assert_equal(v:t_string, type(test_null_string()))
    call assert_equal(v:t_func, type(test_null_function()))
    call assert_equal(v:t_func, type(test_null_partial()))
    call assert_equal(v:t_list, type(test_null_list()))
    call assert_equal(v:t_dict, type(test_null_dict()))
    if has('job')
      call assert_equal(v:t_job, type(test_null_job()))
    endif
    if has('channel')
      call assert_equal(v:t_channel, type(test_null_channel()))
    endif
    call assert_equal(v:t_blob, type(test_null_blob()))

    call assert_fails("call type(test_void())", 'E685:')
    call assert_fails("call type(test_unknown())", 'E685:')

    call assert_equal(0, 0 + v:false)
    call assert_equal(1, 0 + v:true)
    call assert_equal(0, 0 + v:none)
    call assert_equal(0, 0 + v:null)

    call assert_equal('v:false', '' . v:false)
    call assert_equal('v:true', '' . v:true)
    call assert_equal('v:none', '' . v:none)
    call assert_equal('v:null', '' . v:null)

    call assert_true(v:false == 0)
    call assert_false(v:false != 0)
    call assert_true(v:true == 1)
    call assert_false(v:true != 1)
    call assert_false(v:true == v:false)
    call assert_true(v:true != v:false)

    call assert_true(v:null == 0)
    call assert_false(v:null != 0)
    call assert_true(v:none == 0)
    call assert_false(v:none != 0)

    call assert_true(v:false is v:false)
    call assert_true(v:true is v:true)
    call assert_true(v:none is v:none)
    call assert_true(v:null is v:null)

    call assert_false(v:false isnot v:false)
    call assert_false(v:true isnot v:true)
    call assert_false(v:none isnot v:none)
    call assert_false(v:null isnot v:null)

    call assert_false(v:false is 0)
    call assert_false(v:true is 1)
    call assert_false(v:true is v:false)
    call assert_false(v:none is 0)
    call assert_false(v:null is 0)
    call assert_false(v:null is v:none)

    call assert_true(v:false isnot 0)
    call assert_true(v:true isnot 1)
    call assert_true(v:true isnot v:false)
    call assert_true(v:none isnot 0)
    call assert_true(v:null isnot 0)
    call assert_true(v:null isnot v:none)

    call assert_equal(v:false, eval(string(v:false)))
    call assert_equal(v:true, eval(string(v:true)))
    call assert_equal(v:none, eval(string(v:none)))
    call assert_equal(v:null, eval(string(v:null)))

    call assert_equal(v:false, copy(v:false))
    call assert_equal(v:true, copy(v:true))
    call assert_equal(v:none, copy(v:none))
    call assert_equal(v:null, copy(v:null))

    call assert_equal([v:false], deepcopy([v:false]))
    call assert_equal([v:true], deepcopy([v:true]))
    call assert_equal([v:none], deepcopy([v:none]))
    call assert_equal([v:null], deepcopy([v:null]))

    call assert_true(empty(v:false))
    call assert_false(empty(v:true))
    call assert_true(empty(v:null))
    call assert_true(empty(v:none))

    func ChangeYourMind()
	try
	    return v:true
	finally
	    return 'something else'
	endtry
    endfunc

    call ChangeYourMind()
endfunc

"-------------------------------------------------------------------------------
" Test 92:  skipping code					    {{{1
"-------------------------------------------------------------------------------

func Test_skip()
    let Fn = function('Test_type')
    call assert_false(0 && Fn[1])
    call assert_false(0 && string(Fn))
    call assert_false(0 && len(Fn))
    let l = []
    call assert_false(0 && l[1])
    call assert_false(0 && string(l))
    call assert_false(0 && len(l))
    let f = 1.0
    call assert_false(0 && f[1])
    call assert_false(0 && string(f))
    call assert_false(0 && len(f))
    let sp = v:null
    call assert_false(0 && sp[1])
    call assert_false(0 && string(sp))
    call assert_false(0 && len(sp))

endfunc

"-------------------------------------------------------------------------------
" Test 93:  :echo and string()					    {{{1
"-------------------------------------------------------------------------------

func Test_echo_and_string()
    " String
    let a = 'foo bar'
    redir => result
    echo a
    echo string(a)
    redir END
    let l = split(result, "\n")
    call assert_equal(["foo bar",
		     \ "'foo bar'"], l)

    " Float
    if has('float')
	let a = -1.2e0
	redir => result
	echo a
	echo string(a)
	redir END
	let l = split(result, "\n")
	call assert_equal(["-1.2",
			 \ "-1.2"], l)
    endif

    " Funcref
    redir => result
    echo function('string')
    echo string(function('string'))
    redir END
    let l = split(result, "\n")
    call assert_equal(["string",
		     \ "function('string')"], l)

    " Recursive dictionary
    let a = {}
    let a["a"] = a
    redir => result
    echo a
    echo string(a)
    redir END
    let l = split(result, "\n")
    call assert_equal(["{'a': {...}}",
		     \ "{'a': {...}}"], l)

    " Recursive list
    let a = [0]
    let a[0] = a
    redir => result
    echo a
    echo string(a)
    redir END
    let l = split(result, "\n")
    call assert_equal(["[[...]]",
		     \ "[[...]]"], l)

    " Empty dictionaries in a list
    let a = {}
    redir => result
    echo [a, a, a]
    echo string([a, a, a])
    redir END
    let l = split(result, "\n")
    call assert_equal(["[{}, {}, {}]",
		     \ "[{}, {}, {}]"], l)

    " Empty dictionaries in a dictionary
    let a = {}
    let b = {"a": a, "b": a}
    redir => result
    echo b
    echo string(b)
    redir END
    let l = split(result, "\n")
    call assert_equal(["{'a': {}, 'b': {}}",
		     \ "{'a': {}, 'b': {}}"], l)

    " Empty lists in a list
    let a = []
    redir => result
    echo [a, a, a]
    echo string([a, a, a])
    redir END
    let l = split(result, "\n")
    call assert_equal(["[[], [], []]",
		     \ "[[], [], []]"], l)

    " Empty lists in a dictionary
    let a = []
    let b = {"a": a, "b": a}
    redir => result
    echo b
    echo string(b)
    redir END
    let l = split(result, "\n")
    call assert_equal(["{'a': [], 'b': []}",
		     \ "{'a': [], 'b': []}"], l)

    " Dictionaries in a list
    let a = {"one": "yes", "two": "yes", "three": "yes"}
    redir => result
    echo [a, a, a]
    echo string([a, a, a])
    redir END
    let l = split(result, "\n")
    call assert_equal(["[{'one': 'yes', 'two': 'yes', 'three': 'yes'}, {...}, {...}]",
		     \ "[{'one': 'yes', 'two': 'yes', 'three': 'yes'}, {'one': 'yes', 'two': 'yes', 'three': 'yes'}, {'one': 'yes', 'two': 'yes', 'three': 'yes'}]"], l)

    " Dictionaries in a dictionary
    let a = {"one": "yes", "two": "yes", "three": "yes"}
    let b = {"a": a, "b": a}
    redir => result
    echo b
    echo string(b)
    redir END
    let l = split(result, "\n")
    call assert_equal(["{'a': {'one': 'yes', 'two': 'yes', 'three': 'yes'}, 'b': {...}}",
		     \ "{'a': {'one': 'yes', 'two': 'yes', 'three': 'yes'}, 'b': {'one': 'yes', 'two': 'yes', 'three': 'yes'}}"], l)

    " Lists in a list
    let a = [1, 2, 3]
    redir => result
    echo [a, a, a]
    echo string([a, a, a])
    redir END
    let l = split(result, "\n")
    call assert_equal(["[[1, 2, 3], [...], [...]]",
		     \ "[[1, 2, 3], [1, 2, 3], [1, 2, 3]]"], l)

    " Lists in a dictionary
    let a = [1, 2, 3]
    let b = {"a": a, "b": a}
    redir => result
    echo b
    echo string(b)
    redir END
    let l = split(result, "\n")
    call assert_equal(["{'a': [1, 2, 3], 'b': [...]}",
		     \ "{'a': [1, 2, 3], 'b': [1, 2, 3]}"], l)

    call assert_fails('echo &:', 'E112:')
    call assert_fails('echo &g:', 'E112:')
    call assert_fails('echo &l:', 'E112:')

endfunc

"-------------------------------------------------------------------------------
" Test 94:  64-bit Numbers					    {{{1
"-------------------------------------------------------------------------------

func Test_num64()
    call assert_notequal( 4294967296, 0)
    call assert_notequal(-4294967296, 0)
    call assert_equal( 4294967296,  0xFFFFffff + 1)
    call assert_equal(-4294967296, -0xFFFFffff - 1)

    call assert_equal( 9223372036854775807,  1 / 0)
    call assert_equal(-9223372036854775807, -1 / 0)
    call assert_equal(-9223372036854775807 - 1,  0 / 0)

    if has('float')
      call assert_equal( 0x7FFFffffFFFFffff, float2nr( 1.0e150))
      call assert_equal(-0x7FFFffffFFFFffff, float2nr(-1.0e150))
    endif

    let rng = range(0xFFFFffff, 0x100000001)
    call assert_equal([0xFFFFffff, 0x100000000, 0x100000001], rng)
    call assert_equal(0x100000001, max(rng))
    call assert_equal(0xFFFFffff, min(rng))
    call assert_equal(rng, sort(range(0x100000001, 0xFFFFffff, -1), 'N'))
endfunc

"-------------------------------------------------------------------------------
" Test 95:  lines of :append, :change, :insert			    {{{1
"-------------------------------------------------------------------------------

function! DefineFunction(name, body)
    let func = join(['function! ' . a:name . '()'] + a:body + ['endfunction'], "\n")
    exec func
endfunction

func Test_script_lines()
    " :append
    try
	call DefineFunction('T_Append', [
		    \ 'append',
		    \ 'py <<EOS',
		    \ '.',
		    \ ])
    catch
	call assert_report("Can't define function")
    endtry
    try
	call DefineFunction('T_Append', [
		    \ 'append',
		    \ 'abc',
		    \ ])
	call assert_report("Shouldn't be able to define function")
    catch
	call assert_exception('Vim(function):E126: Missing :endfunction')
    endtry

    " :change
    try
	call DefineFunction('T_Change', [
		    \ 'change',
		    \ 'py <<EOS',
		    \ '.',
		    \ ])
    catch
	call assert_report("Can't define function")
    endtry
    try
	call DefineFunction('T_Change', [
		    \ 'change',
		    \ 'abc',
		    \ ])
	call assert_report("Shouldn't be able to define function")
    catch
	call assert_exception('Vim(function):E126: Missing :endfunction')
    endtry

    " :insert
    try
	call DefineFunction('T_Insert', [
		    \ 'insert',
		    \ 'py <<EOS',
		    \ '.',
		    \ ])
    catch
	call assert_report("Can't define function")
    endtry
    try
	call DefineFunction('T_Insert', [
		    \ 'insert',
		    \ 'abc',
		    \ ])
	call assert_report("Shouldn't be able to define function")
    catch
	call assert_exception('Vim(function):E126: Missing :endfunction')
    endtry
endfunc

"-------------------------------------------------------------------------------
" Test 96:  line continuation						    {{{1
"
"	    Undefined behavior was detected by ubsan with line continuation
"	    after an empty line.
"-------------------------------------------------------------------------------
func Test_script_emty_line_continuation()

    \
endfunc

"-------------------------------------------------------------------------------
" Test 97:  bitwise functions						    {{{1
"-------------------------------------------------------------------------------
func Test_bitwise_functions()
    " and
    call assert_equal(127, and(127, 127))
    call assert_equal(16, and(127, 16))
    eval 127->and(16)->assert_equal(16)
    call assert_equal(0, and(127, 128))
    call assert_fails("call and([], 1)", 'E745:')
    call assert_fails("call and({}, 1)", 'E728:')
    if has('float')
      call assert_fails("call and(1.0, 1)", 'E805:')
      call assert_fails("call and(1, 1.0)", 'E805:')
    endif
    call assert_fails("call and(1, [])", 'E745:')
    call assert_fails("call and(1, {})", 'E728:')
    " or
    call assert_equal(23, or(16, 7))
    call assert_equal(15, or(8, 7))
    eval 8->or(7)->assert_equal(15)
    call assert_equal(123, or(0, 123))
    call assert_fails("call or([], 1)", 'E745:')
    call assert_fails("call or({}, 1)", 'E728:')
    if has('float')
      call assert_fails("call or(1.0, 1)", 'E805:')
      call assert_fails("call or(1, 1.0)", 'E805:')
    endif
    call assert_fails("call or(1, [])", 'E745:')
    call assert_fails("call or(1, {})", 'E728:')
    " xor
    call assert_equal(0, xor(127, 127))
    call assert_equal(111, xor(127, 16))
    eval 127->xor(16)->assert_equal(111)
    call assert_equal(255, xor(127, 128))
    if has('float')
      call assert_fails("call xor(1.0, 1)", 'E805:')
      call assert_fails("call xor(1, 1.0)", 'E805:')
    endif
    call assert_fails("call xor([], 1)", 'E745:')
    call assert_fails("call xor({}, 1)", 'E728:')
    call assert_fails("call xor(1, [])", 'E745:')
    call assert_fails("call xor(1, {})", 'E728:')
    " invert
    call assert_equal(65408, and(invert(127), 65535))
    eval 127->invert()->and(65535)->assert_equal(65408)
    call assert_equal(65519, and(invert(16), 65535))
    call assert_equal(65407, and(invert(128), 65535))
    if has('float')
      call assert_fails("call invert(1.0)", 'E805:')
    endif
    call assert_fails("call invert([])", 'E745:')
    call assert_fails("call invert({})", 'E728:')
endfunc

" Test using bang after user command				    {{{1
func Test_user_command_with_bang()
    command -bang Nieuw let nieuw = 1
    Ni!
    call assert_equal(1, nieuw)
    unlet nieuw
    delcommand Nieuw
endfunc

func Test_script_expand_sfile()
  let lines =<< trim END
    func s:snr()
      return expand('<sfile>')
    endfunc
    let g:result = s:snr()
  END
  call writefile(lines, 'Xexpand')
  source Xexpand
  call assert_match('<SNR>\d\+_snr', g:result)
  source Xexpand
  call assert_match('<SNR>\d\+_snr', g:result)

  call delete('Xexpand')
  unlet g:result
endfunc

func Test_compound_assignment_operators()
    " Test for number
    let x = 1
    let x += 10
    call assert_equal(11, x)
    let x -= 5
    call assert_equal(6, x)
    let x *= 4
    call assert_equal(24, x)
    let x /= 3
    call assert_equal(8, x)
    let x %= 3
    call assert_equal(2, x)
    let x .= 'n'
    call assert_equal('2n', x)

    " Test special cases: division or modulus with 0.
    let x = 1
    let x /= 0
    call assert_equal(0x7FFFFFFFFFFFFFFF, x)

    let x = -1
    let x /= 0
    call assert_equal(-0x7FFFFFFFFFFFFFFF, x)

    let x = 0
    let x /= 0
    call assert_equal(-0x7FFFFFFFFFFFFFFF - 1, x)

    let x = 1
    let x %= 0
    call assert_equal(0, x)

    let x = -1
    let x %= 0
    call assert_equal(0, x)

    let x = 0
    let x %= 0
    call assert_equal(0, x)

    " Test for string
    let x = 'str'
    let x .= 'ing'
    call assert_equal('string', x)
    let x += 1
    call assert_equal(1, x)

    if has('float')
      " Test for float
      let x -= 1.5
      call assert_equal(-0.5, x)
      let x = 0.5
      let x += 4.5
      call assert_equal(5.0, x)
      let x -= 1.5
      call assert_equal(3.5, x)
      let x *= 3.0
      call assert_equal(10.5, x)
      let x /= 2.5
      call assert_equal(4.2, x)
      call assert_fails('let x %= 0.5', 'E734')
      call assert_fails('let x .= "f"', 'E734')
      let x = !3.14
      call assert_equal(0.0, x)

      " integer and float operations
      let x = 1
      let x *= 2.1
      call assert_equal(2.1, x)
      let x = 1
      let x /= 0.25
      call assert_equal(4.0, x)
      let x = 1
      call assert_fails('let x %= 0.25', 'E734:')
      let x = 1
      call assert_fails('let x .= 0.25', 'E734:')
      let x = 1.0
      call assert_fails('let x += [1.1]', 'E734:')
    endif

    " Test for environment variable
    let $FOO = 1
    call assert_fails('let $FOO += 1', 'E734')
    call assert_fails('let $FOO -= 1', 'E734')
    call assert_fails('let $FOO *= 1', 'E734')
    call assert_fails('let $FOO /= 1', 'E734')
    call assert_fails('let $FOO %= 1', 'E734')
    let $FOO .= 's'
    call assert_equal('1s', $FOO)
    unlet $FOO

    " Test for option variable (type: number)
    let &scrolljump = 1
    let &scrolljump += 5
    call assert_equal(6, &scrolljump)
    let &scrolljump -= 2
    call assert_equal(4, &scrolljump)
    let &scrolljump *= 3
    call assert_equal(12, &scrolljump)
    let &scrolljump /= 2
    call assert_equal(6, &scrolljump)
    let &scrolljump %= 5
    call assert_equal(1, &scrolljump)
    call assert_fails('let &scrolljump .= "j"', 'E734')
    set scrolljump&vim

    " Test for register
    let @/ = 1
    call assert_fails('let @/ += 1', 'E734')
    call assert_fails('let @/ -= 1', 'E734')
    call assert_fails('let @/ *= 1', 'E734')
    call assert_fails('let @/ /= 1', 'E734')
    call assert_fails('let @/ %= 1', 'E734')
    let @/ .= 's'
    call assert_equal('1s', @/)
    let @/ = ''
endfunc

func Test_unlet_env()
  let $TESTVAR = 'yes'
  call assert_equal('yes', $TESTVAR)
  call assert_fails('lockvar $TESTVAR', 'E940')
  call assert_fails('unlockvar $TESTVAR', 'E940')
  call assert_equal('yes', $TESTVAR)
  if 0
    unlet $TESTVAR
  endif
  call assert_equal('yes', $TESTVAR)
  unlet $TESTVAR
  call assert_equal('', $TESTVAR)
endfunc

func Test_refcount()
    " Immediate values
    call assert_equal(-1, test_refcount(1))
    call assert_equal(-1, test_refcount('s'))
    call assert_equal(-1, test_refcount(v:true))
    call assert_equal(0, test_refcount([]))
    call assert_equal(0, test_refcount({}))
    call assert_equal(0, test_refcount(0zff))
    call assert_equal(0, test_refcount({-> line('.')}))
    if has('float')
        call assert_equal(-1, test_refcount(0.1))
    endif
    if has('job')
        call assert_equal(0, test_refcount(job_start([&shell, &shellcmdflag, 'echo .'])))
    endif

    " No refcount types
    let x = 1
    call assert_equal(-1, test_refcount(x))
    let x = 's'
    call assert_equal(-1, test_refcount(x))
    let x = v:true
    call assert_equal(-1, test_refcount(x))
    if has('float')
        let x = 0.1
        call assert_equal(-1, test_refcount(x))
    endif

    " Check refcount
    let x = []
    call assert_equal(1, test_refcount(x))

    let x = {}
    call assert_equal(1, x->test_refcount())

    let x = 0zff
    call assert_equal(1, test_refcount(x))

    let X = {-> line('.')}
    call assert_equal(1, test_refcount(X))
    let Y = X
    call assert_equal(2, test_refcount(X))

    if has('job')
        let job = job_start([&shell, &shellcmdflag, 'echo .'])
        call assert_equal(1, test_refcount(job))
        call assert_equal(1, test_refcount(job_getchannel(job)))
        call assert_equal(1, test_refcount(job))
    endif

    " Function arguments, copying and unassigning
    func ExprCheck(x, i)
        let i = a:i + 1
        call assert_equal(i, test_refcount(a:x))
        let Y = a:x
        call assert_equal(i + 1, test_refcount(a:x))
        call assert_equal(test_refcount(a:x), test_refcount(Y))
        let Y = 0
        call assert_equal(i, test_refcount(a:x))
    endfunc
    call ExprCheck([], 0)
    call ExprCheck({}, 0)
    call ExprCheck(0zff, 0)
    call ExprCheck({-> line('.')}, 0)
    if has('job')
	call ExprCheck(job, 1)
	call ExprCheck(job_getchannel(job), 1)
	call job_stop(job)
    endif
    delfunc ExprCheck

    " Regarding function
    func Func(x) abort
        call assert_equal(2, test_refcount(function('Func')))
        call assert_equal(0, test_refcount(funcref('Func')))
    endfunc
    call assert_equal(1, test_refcount(function('Func')))
    call assert_equal(0, test_refcount(function('Func', [1])))
    call assert_equal(0, test_refcount(funcref('Func')))
    call assert_equal(0, test_refcount(funcref('Func', [1])))
    let X = function('Func')
    let Y = X
    call assert_equal(1, test_refcount(X))
    let X = function('Func', [1])
    let Y = X
    call assert_equal(2, test_refcount(X))
    let X = funcref('Func')
    let Y = X
    call assert_equal(2, test_refcount(X))
    let X = funcref('Func', [1])
    let Y = X
    call assert_equal(2, test_refcount(X))
    unlet X
    unlet Y
    call Func(1)
    delfunc Func

    " Function with dict
    func DictFunc() dict
        call assert_equal(3, test_refcount(self))
    endfunc
    let d = {'Func': function('DictFunc')}
    call assert_equal(1, test_refcount(d))
    call assert_equal(0, test_refcount(d.Func))
    call d.Func()
    unlet d
    delfunc DictFunc
endfunc

" Test for missing :endif, :endfor, :endwhile and :endtry           {{{1
func Test_missing_end()
  call writefile(['if 2 > 1', 'echo ">"'], 'Xscript')
  call assert_fails('source Xscript', 'E171:')
  call writefile(['for i in range(5)', 'echo i'], 'Xscript')
  call assert_fails('source Xscript', 'E170:')
  call writefile(['while v:true', 'echo "."'], 'Xscript')
  call assert_fails('source Xscript', 'E170:')
  call writefile(['try', 'echo "."'], 'Xscript')
  call assert_fails('source Xscript', 'E600:')
  call delete('Xscript')

  " Using endfor with :while
  let caught_e732 = 0
  try
    while v:true
    endfor
  catch /E732:/
    let caught_e732 = 1
  endtry
  call assert_equal(1, caught_e732)

  " Using endwhile with :for
  let caught_e733 = 0
  try
    for i in range(1)
    endwhile
  catch /E733:/
    let caught_e733 = 1
  endtry
  call assert_equal(1, caught_e733)

  " Using endfunc with :if
  call assert_fails('exe "if 1 | endfunc | endif"', 'E193:')

  " Missing 'in' in a :for statement
  call assert_fails('for i range(1) | endfor', 'E690:')

  " Incorrect number of variables in for
  call assert_fails('for [i,] in range(3) | endfor', 'E475:')
endfunc

" Test for deep nesting of if/for/while/try statements              {{{1
func Test_deep_nest()
  CheckRunVimInTerminal

  let lines =<< trim [SCRIPT]
    " Deep nesting of if ... endif
    func Test1()
      let @a = join(repeat(['if v:true'], 51), "\n")
      let @a ..= "\n"
      let @a ..= join(repeat(['endif'], 51), "\n")
      @a
      let @a = ''
    endfunc

    " Deep nesting of for ... endfor
    func Test2()
      let @a = join(repeat(['for i in [1]'], 51), "\n")
      let @a ..= "\n"
      let @a ..= join(repeat(['endfor'], 51), "\n")
      @a
      let @a = ''
    endfunc

    " Deep nesting of while ... endwhile
    func Test3()
      let @a = join(repeat(['while v:true'], 51), "\n")
      let @a ..= "\n"
      let @a ..= join(repeat(['endwhile'], 51), "\n")
      @a
      let @a = ''
    endfunc

    " Deep nesting of try ... endtry
    func Test4()
      let @a = join(repeat(['try'], 51), "\n")
      let @a ..= "\necho v:true\n"
      let @a ..= join(repeat(['endtry'], 51), "\n")
      @a
      let @a = ''
    endfunc

    " Deep nesting of function ... endfunction
    func Test5()
      let @a = join(repeat(['function X()'], 51), "\n")
      let @a ..= "\necho v:true\n"
      let @a ..= join(repeat(['endfunction'], 51), "\n")
      @a
      let @a = ''
    endfunc
  [SCRIPT]
  call writefile(lines, 'Xscript')

  let buf = RunVimInTerminal('-S Xscript', {'rows': 6})

  " Deep nesting of if ... endif
  call term_sendkeys(buf, ":call Test1()\n")
  call TermWait(buf)
  call WaitForAssert({-> assert_match('^E579:', term_getline(buf, 5))})

  " Deep nesting of for ... endfor
  call term_sendkeys(buf, ":call Test2()\n")
  call TermWait(buf)
  call WaitForAssert({-> assert_match('^E585:', term_getline(buf, 5))})

  " Deep nesting of while ... endwhile
  call term_sendkeys(buf, ":call Test3()\n")
  call TermWait(buf)
  call WaitForAssert({-> assert_match('^E585:', term_getline(buf, 5))})

  " Deep nesting of try ... endtry
  call term_sendkeys(buf, ":call Test4()\n")
  call TermWait(buf)
  call WaitForAssert({-> assert_match('^E601:', term_getline(buf, 5))})

  " Deep nesting of function ... endfunction
  call term_sendkeys(buf, ":call Test5()\n")
  call TermWait(buf)
  call WaitForAssert({-> assert_match('^E1058:', term_getline(buf, 4))})
  call term_sendkeys(buf, "\<C-C>\n")
  call TermWait(buf)

  "let l = ''
  "for i in range(1, 6)
  "  let l ..= term_getline(buf, i) . "\n"
  "endfor
  "call assert_report(l)

  call StopVimInTerminal(buf)
  call delete('Xscript')
endfunc

" Test for errors in converting to float from various types         {{{1
func Test_float_conversion_errors()
  if has('float')
    call assert_fails('let x = 4.0 % 2.0', 'E804')
    call assert_fails('echo 1.1[0]', 'E806')
    call assert_fails('echo sort([function("min"), 1], "f")', 'E891:')
    call assert_fails('echo 3.2 == "vim"', 'E892:')
    call assert_fails('echo sort([[], 1], "f")', 'E893:')
    call assert_fails('echo sort([{}, 1], "f")', 'E894:')
    call assert_fails('echo 3.2 == v:true', 'E362:')
    call assert_fails('echo 3.2 == v:none', 'E907:')
  endif
endfunc

" invalid function names               {{{1
func Test_invalid_function_names()
  " function name not starting with capital
  let caught_e128 = 0
  try
    func! g:test()
      echo "test"
    endfunc
  catch /E128:/
    let caught_e128 = 1
  endtry
  call assert_equal(1, caught_e128)

  " function name includes a colon
  let caught_e884 = 0
  try
    func! b:test()
      echo "test"
    endfunc
  catch /E884:/
    let caught_e884 = 1
  endtry
  call assert_equal(1, caught_e884)

  " function name folowed by #
  let caught_e128 = 0
  try
    func! test2() "#
      echo "test2"
    endfunc
  catch /E128:/
    let caught_e128 = 1
  endtry
  call assert_equal(1, caught_e128)

  " function name starting with/without "g:", buffer-local funcref.
  function! g:Foo(n)
    return 'called Foo(' . a:n . ')'
  endfunction
  let b:my_func = function('Foo')
  call assert_equal('called Foo(1)', b:my_func(1))
  call assert_equal('called Foo(2)', g:Foo(2))
  call assert_equal('called Foo(3)', Foo(3))
  delfunc g:Foo

  " script-local function used in Funcref must exist.
  let lines =<< trim END
    func s:Testje()
      return "foo"
    endfunc
    let Bar = function('s:Testje')
    call assert_equal(0, exists('s:Testje'))
    call assert_equal(1, exists('*s:Testje'))
    call assert_equal(1, exists('Bar'))
    call assert_equal(1, exists('*Bar'))
  END
  call writefile(lines, 'Xscript')
  source Xscript
  call delete('Xscript')
endfunc

" substring and variable name              {{{1
func Test_substring_var()
  let str = 'abcdef'
  let n = 3
  call assert_equal('def', str[n:])
  call assert_equal('abcd', str[:n])
  call assert_equal('d', str[n:n])
  unlet n
  let nn = 3
  call assert_equal('def', str[nn:])
  call assert_equal('abcd', str[:nn])
  call assert_equal('d', str[nn:nn])
  unlet nn
  let b:nn = 4
  call assert_equal('ef', str[b:nn:])
  call assert_equal('abcde', str[:b:nn])
  call assert_equal('e', str[b:nn:b:nn])
  unlet b:nn
endfunc

" Test using s: with a typed command              {{{1
func Test_typed_script_var()
  CheckRunVimInTerminal

  let buf = RunVimInTerminal('', {'rows': 6})

  " Deep nesting of if ... endif
  call term_sendkeys(buf, ":echo get(s:, 'foo', 'x')\n")
  call TermWait(buf)
  call WaitForAssert({-> assert_match('^E116:', term_getline(buf, 5))})

  call StopVimInTerminal(buf)
endfunc

"-------------------------------------------------------------------------------
" Modelines								    {{{1
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
"-------------------------------------------------------------------------------