summaryrefslogtreecommitdiffstats
path: root/src/testdir/test49.vim
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2004-06-13 20:20:40 +0000
committerBram Moolenaar <Bram@vim.org>2004-06-13 20:20:40 +0000
commit071d4279d6ab81b7187b48f3a0fc61e587b6db6c (patch)
tree221cbe3c40e043163c06f61c52a7ba2eb41e12ce /src/testdir/test49.vim
parentb4210b3bc14e2918f153a7307530fbe6eba659e1 (diff)
updated for version 7.0001v7.0001
Diffstat (limited to 'src/testdir/test49.vim')
-rw-r--r--src/testdir/test49.vim9666
1 files changed, 9666 insertions, 0 deletions
diff --git a/src/testdir/test49.vim b/src/testdir/test49.vim
new file mode 100644
index 0000000000..e742a96222
--- /dev/null
+++ b/src/testdir/test49.vim
@@ -0,0 +1,9666 @@
+" Vim script language tests
+" Author: Servatius Brandt <Servatius.Brandt@fujitsu-siemens.com>
+" Last Change: 2004 Apr 03
+
+"-------------------------------------------------------------------------------
+" Test environment {{{1
+"-------------------------------------------------------------------------------
+
+
+" Adding new tests easily. {{{2
+"
+" Writing new tests is eased considerably with the following functions and
+" abbreviations (see "Commands for recording the execution path", "Automatic
+" argument generation").
+"
+" To get the abbreviations, execute the command
+"
+" :let test49_set_env = 1 | source test49.vim
+"
+" To get them always (from src/testdir), put a line
+"
+" au! BufRead test49.vim let test49_set_env = 1 | source test49.vim
+"
+" into the local .vimrc file in the src/testdir directory.
+"
+if exists("test49_set_env") && test49_set_env
+
+ " Automatic argument generation for the test environment commands.
+
+ function! Xsum()
+ let addend = substitute(getline("."), '^.*"\s*X:\s*\|^.*', '', "")
+ " Evaluate arithmetic expression.
+ if addend != ""
+ exec "let g:Xsum = g:Xsum + " . addend
+ endif
+ endfunction
+
+ function! Xcheck()
+ let g:Xsum=0
+ ?XpathINIT?,.call Xsum()
+ exec "norm A "
+ return g:Xsum
+ endfunction
+
+ iab Xcheck Xcheck<Space><C-R>=Xcheck()<CR><C-O>x
+
+ function! Xcomment(num)
+ let str = ""
+ let tabwidth = &sts ? &sts : &ts
+ let tabs = (48+tabwidth - a:num - virtcol(".")) / tabwidth
+ while tabs > 0
+ let str = str . "\t"
+ let tabs = tabs - 1
+ endwhile
+ let str = str . '" X:'
+ return str
+ endfunction
+
+ function! Xloop()
+ let back = line(".") . "|norm" . virtcol(".") . "|"
+ norm 0
+ let last = search('X\(loop\|path\)INIT\|Xloop\>', "bW")
+ exec back
+ let theline = getline(last)
+ if theline =~ 'X\(loop\|path\)INIT'
+ let num = 1
+ else
+ let num = 2 * substitute(theline, '.*Xloop\s*\(\d\+\).*', '\1', "")
+ endif
+ ?X\(loop\|path\)INIT?
+ \s/\(XloopINIT!\=\s*\d\+\s\+\)\@<=\(\d\+\)/\=2*submatch(2)/
+ exec back
+ exec "norm a "
+ return num . Xcomment(strlen(num))
+ endfunction
+
+ iab Xloop Xloop<Space><C-R>=Xloop()<CR><C-O>x
+
+ function! Xpath(loopinit)
+ let back = line(".") . "|norm" . virtcol(".") . "|"
+ norm 0
+ let last = search('XpathINIT\|Xpath\>\|XloopINIT', "bW")
+ exec back
+ let theline = getline(last)
+ if theline =~ 'XpathINIT'
+ let num = 1
+ elseif theline =~ 'Xpath\>'
+ let num = 2 * substitute(theline, '.*Xpath\s*\(\d\+\).*', '\1', "")
+ else
+ let pattern = '.*XloopINIT!\=\s*\(\d\+\)\s*\(\d\+\).*'
+ let num = substitute(theline, pattern, '\1', "")
+ let factor = substitute(theline, pattern, '\2', "")
+ " The "<C-O>x" from the "Xpath" iab and the character triggering its
+ " expansion are in the input buffer. Save and clear typeahead so
+ " that it is not read away by the call to "input()" below. Restore
+ " afterwards.
+ call inputsave()
+ let loops = input("Number of iterations in previous loop? ")
+ call inputrestore()
+ while (loops > 0)
+ let num = num * factor
+ let loops = loops - 1
+ endwhile
+ endif
+ exec "norm a "
+ if a:loopinit
+ return num . " 1"
+ endif
+ return num . Xcomment(strlen(num))
+ endfunction
+
+ iab Xpath Xpath<Space><C-R>=Xpath(0)<CR><C-O>x
+ iab XloopINIT XloopINIT<Space><C-R>=Xpath(1)<CR><C-O>x
+
+ " Also useful (see ExtraVim below):
+ aug ExtraVim
+ au!
+ au BufEnter <sfile> syn region ExtraVim
+ \ start=+^if\s\+ExtraVim(.*)+ end=+^endif+
+ \ transparent keepend
+ au BufEnter <sfile> syn match ExtraComment /^"/
+ \ contained containedin=ExtraVim
+ au BufEnter <sfile> hi link ExtraComment vimComment
+ aug END
+
+ aug Xpath
+ au BufEnter <sfile> syn keyword Xpath
+ \ XpathINIT Xpath XloopINIT Xloop XloopNEXT Xcheck Xout
+ au BufEnter <sfile> hi link Xpath Special
+ aug END
+
+ do BufEnter <sfile>
+
+ " Do not execute the tests when sourcing this file for getting the functions
+ " and abbreviations above, which are intended for easily adding new test
+ " cases; they are not needed for test execution. Unlet the variable
+ " controlling this so that an explicit ":source" command for this file will
+ " execute the tests.
+ unlet test49_set_env
+ finish
+
+endif
+
+
+" Commands for recording the execution path. {{{2
+"
+" The Xpath/Xloop commands can be used for computing the eXecution path by
+" adding (different) powers of 2 from those script lines, for which the
+" execution should be checked. Xloop provides different addends for each
+" execution of a loop. Permittable values are 2^0 to 2^30, so that 31 execution
+" points (multiply counted inside loops) can be tested.
+"
+" Note that the arguments of the following commands can be generated
+" automatically, see below.
+"
+" Usage: {{{3
+"
+" - Use XpathINIT at the beginning of the test.
+"
+" - Use Xpath to check if a line is executed.
+" Argument: power of 2 (decimal).
+"
+" - To check multiple execution of loops use Xloop for automatically
+" computing Xpath values:
+"
+" - Use XloopINIT before the loop.
+" Two arguments:
+" - the first Xpath value (power of 2) to be used (Xnext),
+" - factor for computing a new Xnext value when reexecuting a loop
+" (by a ":continue" or ":endwhile"); this should be 2^n where
+" n is the number of Xloop commands inside the loop.
+" If XloopINIT! is used, the first execution of XloopNEXT is
+" a no-operation.
+"
+" - Use Xloop inside the loop:
+" One argument:
+" The argument and the Xnext value are multiplied to build the
+" next Xpath value. No new Xnext value is prepared. The argument
+" should be 2^(n-1) for the nth Xloop command inside the loop.
+" If the loop has only one Xloop command, the argument can be
+" ommitted (default: 1).
+"
+" - Use XloopNEXT before ":continue" and ":endwhile". This computes a new
+" Xnext value for the next execution of the loop by multiplying the old
+" one with the factor specified in the XloopINIT command. No Argument.
+" Alternatively, when XloopINIT! is used, a single XloopNEXT at the
+" beginning of the loop can be used.
+"
+" Nested loops are not supported.
+"
+" - Use Xcheck at end of each test. It prints the test number, the expected
+" execution path value, the test result ("OK" or "FAIL"), and, if the tests
+" fails, the actual execution path.
+" One argument:
+" Expected Xpath/Xloop sum for the correct execution path.
+" In order that this value can be computed automatically, do the
+" following: For each line in the test with an Xpath and Xloop
+" command, add a comment starting with "X:" and specifying an
+" expression that evaluates to the value contributed by this line to
+" the correct execution path. (For copying an Xpath argument of at
+" least two digits into the comment, press <C-P>.) At the end of the
+" test, just type "Xcheck" and press <Esc>.
+"
+" - In order to add additional information to the test output file, use the
+" Xout command. Argument(s) like ":echo".
+"
+" Automatic argument generation: {{{3
+"
+" The arguments of the Xpath, XloopINIT, Xloop, and Xcheck commands can be
+" generated automatically, so that new tests can easily be written without
+" mental arithmetic. The Xcheck argument is computed from the "X:" comments
+" of the preceding Xpath and Xloop commands. See the commands and
+" abbreviations at the beginning of this file.
+"
+" Implementation: {{{3
+" XpathINIT, Xpath, XloopINIT, Xloop, XloopNEXT, Xcheck, Xout.
+"
+" The variants for existing g:ExtraVimResult are needed when executing a script
+" in an extra Vim process, see ExtraVim below.
+
+" EXTRA_VIM_START - do not change or remove this line.
+
+com! XpathINIT let g:Xpath = 0
+
+if exists("g:ExtraVimResult")
+ com! -count -bar Xpath exec "!echo <count> >>" . g:ExtraVimResult
+else
+ com! -count -bar Xpath let g:Xpath = g:Xpath + <count>
+endif
+
+com! -count -nargs=1 -bang
+ \ XloopINIT let g:Xnext = <count> |
+ \ let g:Xfactor = <args> |
+ \ let g:Xskip = strlen("<bang>")
+
+if exists("g:ExtraVimResult")
+ com! -count=1 -bar Xloop exec "!echo " . (g:Xnext * <count>) . " >>" .
+ \ g:ExtraVimResult
+else
+ com! -count=1 -bar Xloop let g:Xpath = g:Xpath + g:Xnext * <count>
+endif
+
+com! XloopNEXT let g:Xnext = g:Xnext *
+ \ (g:Xskip ? 1 : g:Xfactor) |
+ \ let g:Xskip = 0
+
+let @r = ""
+let Xtest = 1
+com! -count Xcheck let Xresult = "*** Test " .
+ \ (Xtest<10?" ":Xtest<100?" ":"") .
+ \ Xtest . ": " . (
+ \ (Xpath==<count>) ? "OK (".Xpath.")" :
+ \ "FAIL (".Xpath." instead of <count>)"
+ \ ) |
+ \ let @R = Xresult . "\n" |
+ \ echo Xresult |
+ \ let Xtest = Xtest + 1
+
+if exists("g:ExtraVimResult")
+ com! -nargs=+ Xout exec "exec \"!echo @R:'\" ."
+ \ 'substitute(substitute("' . <args> .
+ \ '", "' . "'" . '", ' . "'" . '&\\&&' . "'"
+ \ . ', "g"), "\n", "@NL@", "g")'
+ \ ". \"' >>\" . g:ExtraVimResult"
+else
+ com! -nargs=+ Xout exec 'let @R = "--- Test ' .
+ \ (g:Xtest<10?" ":g:Xtest<100?" ":"") .
+ \ g:Xtest . ": " .
+ \ '" . substitute("' . <args> .
+ \ '", "\n", "&\t ", "g") . "\n"'
+endif
+
+" Switch off storing of lines for undoing changes. Speeds things up a little.
+set undolevels=-1
+
+" EXTRA_VIM_STOP - do not change or remove this line.
+
+
+" ExtraVim() - Run a script file in an extra Vim process. {{{2
+"
+" This is useful for testing immediate abortion of the script processing due to
+" an error in a command dynamically enclosed by a :try/:tryend region or when an
+" exception is thrown but not caught or when an interrupt occurs. It can also
+" be used for testing :finish.
+"
+" An interrupt location can be specified by an "INTERRUPT" comment. A number
+" telling how often this location is reached (in a loop or in several function
+" calls) should be specified as argument. When missing, once per script
+" invocation or function call is assumed. INTERRUPT locations are tested by
+" setting a breakpoint in that line and using the ">quit" debug command when
+" the breakpoint is reached. A function for which an INTERRUPT location is
+" specified must be defined before calling it (or executing it as a script by
+" using ExecAsScript below).
+"
+" This function is only called in normal modus ("g:ExtraVimResult" undefined).
+"
+" Tests to be executed as an extra script should be written as follows:
+"
+" column 1 column 1
+" | |
+" v v
+"
+" XpathINIT XpathINIT
+" if ExtraVim() if ExtraVim()
+" ... " ...
+" ... " ...
+" endif endif
+" Xcheck <number> Xcheck <number>
+"
+" Double quotes in column 1 are removed before the script is executed.
+" They should be used if the test has unbalanced conditionals (:if/:endif,
+" :while:/endwhile, :try/:endtry) or for a line with a syntax error. The
+" extra script may use Xpath, XloopINIT, Xloop, XloopNEXT, and Xout as usual.
+"
+" A file name may be specified as argument. All messages of the extra Vim
+" process are then redirected to the file. An existing file is overwritten.
+"
+let ExtraVimCount = 0
+let ExtraVimBase = expand("<sfile>")
+let ExtraVimTestEnv = ""
+"
+function! ExtraVim(...)
+ " Count how often this function is called.
+ let g:ExtraVimCount = g:ExtraVimCount + 1
+
+ " Disable folds to prevent that the ranges in the ":write" commands below
+ " are extended up to the end of a closed fold. This also speeds things up
+ " considerably.
+ set nofoldenable
+
+ " Open a buffer for this test script and copy the test environment to
+ " a temporary file. Take account of parts relevant for the extra script
+ " execution only.
+ let current_buffnr = bufnr("%")
+ execute "view +1" g:ExtraVimBase
+ if g:ExtraVimCount == 1
+ let g:ExtraVimTestEnv = tempname()
+ execute "/E" . "XTRA_VIM_START/+,/E" . "XTRA_VIM_STOP/-w"
+ \ g:ExtraVimTestEnv "|']+"
+ execute "/E" . "XTRA_VIM_START/+,/E" . "XTRA_VIM_STOP/-w >>"
+ \ g:ExtraVimTestEnv "|']+"
+ execute "/E" . "XTRA_VIM_START/+,/E" . "XTRA_VIM_STOP/-w >>"
+ \ g:ExtraVimTestEnv "|']+"
+ execute "/E" . "XTRA_VIM_START/+,/E" . "XTRA_VIM_STOP/-w >>"
+ \ g:ExtraVimTestEnv "|']+"
+ endif
+
+ " Start the extra Vim script with a ":source" command for the test
+ " environment. The source line number where the extra script will be
+ " appended, needs to be passed as variable "ExtraVimBegin" to the script.
+ let extra_script = tempname()
+ exec "!echo 'source " . g:ExtraVimTestEnv . "' >" . extra_script
+ let extra_begin = 1
+
+ " Starting behind the test environment, skip over the first g:ExtraVimCount
+ " occurrences of "if ExtraVim()" and copy the following lines up to the
+ " matching "endif" to the extra Vim script.
+ execute "/E" . "ND_OF_TEST_ENVIRONMENT/"
+ exec 'norm ' . g:ExtraVimCount . '/^\s*if\s\+ExtraVim(.*)/+' . "\n"
+ execute ".,/^endif/-write >>" . extra_script
+
+ " Open a buffer for the extra Vim script, delete all ^", and write the
+ " script if was actually modified.
+ execute "edit +" . (extra_begin + 1) extra_script
+ ,$s/^"//e
+ update
+
+ " Count the INTERRUPTs and build the breakpoint and quit commands.
+ let breakpoints = ""
+ let debug_quits = ""
+ let in_func = 0
+ exec extra_begin
+ while search(
+ \ '"\s*INTERRUPT\h\@!\|^\s*fu\%[nction]\>!\=\s*\%(\u\|s:\)\w*\s*(\|'
+ \ . '^\s*\\\|^\s*endf\%[unction]\>\|'
+ \ . '\%(^\s*fu\%[nction]!\=\s*\)\@<!\%(\u\|s:\)\w*\s*(\|'
+ \ . 'ExecAsScript\s\+\%(\u\|s:\)\w*',
+ \ "W") > 0
+ let theline = getline(".")
+ if theline =~ '^\s*fu'
+ " Function definition.
+ let in_func = 1
+ let func_start = line(".")
+ let func_name = substitute(theline,
+ \ '^\s*fu\%[nction]!\=\s*\(\%(\u\|s:\)\w*\).*', '\1', "")
+ let func_conts = 0
+ elseif theline =~ '^\s*\\'
+ if in_func
+ let func_conts = func_conts + 1
+ endif
+ elseif theline =~ '^\s*endf'
+ " End of function definition.
+ let in_func = 0
+ else
+ let finding = substitute(theline, '.*\(\%' . col(".") . 'c.*\)',
+ \ '\1', "")
+ if finding =~ '^"\s*INTERRUPT\h\@!'
+ " Interrupt comment. Compose as many quit commands as
+ " specified.
+ let cnt = substitute(finding,
+ \ '^"\s*INTERRUPT\s*\(\d*\).*$', '\1', "")
+ let quits = ""
+ while cnt > 0
+ " Use "\r" rather than "\n" to separate the quit commands.
+ " "\r" is not interpreted as command separator by the ":!"
+ " command below but works to separate commands in the
+ " external vim.
+ let quits = quits . "q\r"
+ let cnt = cnt - 1
+ endwhile
+ if in_func
+ " Add the function breakpoint and note the number of quits
+ " to be used, if specified, or one for every call else.
+ let breakpoints = breakpoints . " -c 'breakadd func " .
+ \ (line(".") - func_start - func_conts) . " " .
+ \ func_name . "'"
+ if quits != ""
+ let debug_quits = debug_quits . quits
+ elseif !exists("quits{func_name}")
+ let quits{func_name} = "q\r"
+ else
+ let quits{func_name} = quits{func_name} . "q\r"
+ endif
+ else
+ " Add the file breakpoint and the quits to be used for it.
+ let breakpoints = breakpoints . " -c 'breakadd file " .
+ \ line(".") . " " . extra_script . "'"
+ if quits == ""
+ let quits = "q\r"
+ endif
+ let debug_quits = debug_quits . quits
+ endif
+ else
+ " Add the quits to be used for calling the function or executing
+ " it as script file.
+ if finding =~ '^ExecAsScript'
+ " Sourcing function as script.
+ let finding = substitute(finding,
+ \ '^ExecAsScript\s\+\(\%(\u\|s:\)\w*\).*', '\1', "")
+ else
+ " Function call.
+ let finding = substitute(finding,
+ \ '^\(\%(\u\|s:\)\w*\).*', '\1', "")
+ endif
+ if exists("quits{finding}")
+ let debug_quits = debug_quits . quits{finding}
+ endif
+ endif
+ endif
+ endwhile
+
+ " Close the buffer for the script and create an (empty) resultfile.
+ bwipeout
+ let resultfile = tempname()
+ exec "!>" . resultfile
+
+ " Run the script in an extra vim. Switch to extra modus by passing the
+ " resultfile in ExtraVimResult. Redirect messages to the file specified as
+ " argument if any. Use ":debuggreedy" so that the commands provided on the
+ " pipe are consumed at the debug prompt. Use "-N" to enable command-line
+ " contiunation ("C" in 'cpo'). Add "nviminfo" to 'viminfo' to avoid
+ " messing up the user's viminfo file.
+ let redirect = a:0 ?
+ \ " -c 'au VimLeave * redir END' -c 'redir\\! >" . a:1 . "'" : ""
+ exec "!echo '" . debug_quits . "q' | ../vim -u NONE -N -Xes" . redirect .
+ \ " -c 'debuggreedy|set viminfo+=nviminfo'" .
+ \ " -c 'let ExtraVimBegin = " . extra_begin . "'" .
+ \ " -c 'let ExtraVimResult = \"" . resultfile . "\"'" . breakpoints .
+ \ " -S " . extra_script
+
+ " Build the resulting sum for resultfile and add it to g:Xpath. Add Xout
+ " information provided by the extra Vim process to the test output.
+ let sum = 0
+ exec "edit" resultfile
+ let line = 1
+ while line <= line("$")
+ let theline = getline(line)
+ if theline =~ '^@R:'
+ exec 'Xout "' . substitute(substitute(
+ \ escape(escape(theline, '"'), '\"'),
+ \ '^@R:', '', ""), '@NL@', "\n", "g") . '"'
+ else
+ let sum = sum + getline(line)
+ endif
+ let line = line + 1
+ endwhile
+ bwipeout
+ let g:Xpath = g:Xpath + sum
+
+ " Delete the extra script and the resultfile.
+ call delete(extra_script)
+ call delete(resultfile)
+
+ " Switch back to the buffer that was active when this function was entered.
+ exec "buffer" current_buffnr
+
+ " Return 0. This protects extra scripts from being run in the main Vim
+ " process.
+ return 0
+endfunction
+
+
+" ExtraVimThrowpoint() - Relative throwpoint in ExtraVim script {{{2
+"
+" Evaluates v:throwpoint and returns the throwpoint relativ to the beginning of
+" an ExtraVim script as passed by ExtraVim() in ExtraVimBegin.
+"
+" EXTRA_VIM_START - do not change or remove this line.
+function! ExtraVimThrowpoint()
+ if !exists("g:ExtraVimBegin")
+ Xout "ExtraVimThrowpoint() used outside ExtraVim() script."
+ return v:throwpoint
+ endif
+
+ if v:throwpoint =~ '^function\>'
+ return v:throwpoint
+ endif
+
+ return "line " .
+ \ (substitute(v:throwpoint, '.*, line ', '', "") - g:ExtraVimBegin) .
+ \ " of ExtraVim() script"
+endfunction
+" EXTRA_VIM_STOP - do not change or remove this line.
+
+
+" MakeScript() - Make a script file from a function. {{{2
+"
+" Create a script that consists of the body of the function a:funcname.
+" Replace any ":return" by a ":finish", any argument variable by a global
+" variable, and and every ":call" by a ":source" for the next following argument
+" in the variable argument list. This function is useful if similar tests are
+" to be made for a ":return" from a function call or a ":finish" in a script
+" file.
+"
+" In order to execute a function specifying an INTERRUPT location (see ExtraVim)
+" as a script file, use ExecAsScript below.
+"
+" EXTRA_VIM_START - do not change or remove this line.
+function! MakeScript(funcname, ...)
+ let script = tempname()
+ execute "redir! >" . script
+ execute "function" a:funcname
+ redir END
+ execute "edit" script
+ " Delete the "function" and the "endfunction" lines. Do not include the
+ " word "function" in the pattern since it might be translated if LANG is
+ " set. When MakeScript() is being debugged, this deletes also the debugging
+ " output of its line 3 and 4.
+ exec '1,/.*' . a:funcname . '(.*)/d'
+ /^\d*\s*endfunction\>/,$d
+ %s/^\d*//e
+ %s/return/finish/e
+ %s/\<a:\(\h\w*\)/g:\1/ge
+ normal gg0
+ let cnt = 0
+ while search('\<call\s*\%(\u\|s:\)\w*\s*(.*)', 'W') > 0
+ let cnt = cnt + 1
+ s/\<call\s*\%(\u\|s:\)\w*\s*(.*)/\='source ' . a:{cnt}/
+ endwhile
+ g/^\s*$/d
+ write
+ bwipeout
+ return script
+endfunction
+" EXTRA_VIM_STOP - do not change or remove this line.
+
+
+" ExecAsScript - Source a temporary script made from a function. {{{2
+"
+" Make a temporary script file from the function a:funcname, ":source" it, and
+" delete it afterwards.
+"
+" When inside ":if ExtraVim()", add a file breakpoint for each INTERRUPT
+" location specified in the function.
+"
+" EXTRA_VIM_START - do not change or remove this line.
+function! ExecAsScript(funcname)
+ " Make a script from the function passed as argument.
+ let script = MakeScript(a:funcname)
+
+ " When running in an extra Vim process, add a file breakpoint for each
+ " function breakpoint set when the extra Vim process was invoked by
+ " ExtraVim().
+ if exists("g:ExtraVimResult")
+ let bplist = tempname()
+ execute "redir! >" . bplist
+ breaklist
+ redir END
+ execute "edit" bplist
+ " Get the line number from the function breakpoint. Works also when
+ " LANG is set.
+ execute 'v/^\s*\d\+\s\+func\s\+' . a:funcname . '\s.*/d'
+ %s/^\s*\d\+\s\+func\s\+\%(\u\|s:\)\w*\s\D*\(\d*\).*/\1/e
+ let cnt = 0
+ while cnt < line("$")
+ let cnt = cnt + 1
+ if getline(cnt) != ""
+ execute "breakadd file" getline(cnt) script
+ endif
+ endwhile
+ bwipeout!
+ call delete(bplist)
+ endif
+
+ " Source and delete the script.
+ exec "source" script
+ call delete(script)
+endfunction
+
+com! -nargs=1 -bar ExecAsScript call ExecAsScript(<f-args>)
+" EXTRA_VIM_STOP - do not change or remove this line.
+
+
+" END_OF_TEST_ENVIRONMENT - do not change or remove this line.
+
+
+"-------------------------------------------------------------------------------
+" 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.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+function! F()
+ Xpath 1 " X: 1
+ let first = 1
+ XloopINIT 2 8
+ while 1
+ Xloop 1 " X: 2 + 0 * 16
+ if first
+ Xloop 2 " X: 4 + 0 * 32
+ let first = 0
+ XloopNEXT
+ break
+ else
+ Xloop 4 " X: 0 + 0 * 64
+ return
+ endif
+ endwhile
+endfunction
+
+call F()
+Xpath 128 " X: 128
+
+function! G()
+ Xpath 256 " X: 256 + 0 * 2048
+ let first = 1
+ XloopINIT 512 8
+ while 1
+ Xloop 1 " X: 512 + 0 * 4096
+ if first
+ Xloop 2 " X: 1024 + 0 * 8192
+ let first = 0
+ XloopNEXT
+ break
+ else
+ Xloop 4 " X: 0 + 0 * 16384
+ return
+ endif
+ if 1 " unmatched :if
+ endwhile
+endfunction
+
+call G()
+Xpath 32768 " X: 32768
+
+Xcheck 34695
+
+" Leave F and G for execution as scripts in the next test.
+
+
+"-------------------------------------------------------------------------------
+" 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 F and G from the
+" previous test as script files (:return replaced by :finish).
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+ExecAsScript F " X: 1 + 2 + 4
+Xpath 128 " X: 128
+
+ExecAsScript G " X: 256 + 512 + 1024
+Xpath 32768 " X: 32768
+
+unlet first
+delfunction F
+delfunction G
+
+Xcheck 34695
+
+
+"-------------------------------------------------------------------------------
+" Test 3: :if, :elseif, :while, :continue, :break {{{1
+"-------------------------------------------------------------------------------
+
+XpathINIT
+if 1
+ Xpath 1 " X: 1
+ let loops = 3
+ XloopINIT 2 512
+ while loops > -1 " main loop: loops == 3, 2, 1 (which breaks)
+ if loops <= 0
+ let break_err = 1
+ let loops = -1
+ else " 3: 2: 1:
+ Xloop 1 " X: 2 + 2*512 + 2*512*512
+ endif
+ if (loops == 2)
+ while loops == 2 " dummy loop
+ Xloop 2 " X: 4*512
+ let loops = loops - 1
+ continue " stop dummy loop
+ Xloop 4 " X: 0
+ endwhile
+ XloopNEXT
+ continue " continue main loop
+ Xloop 8 " X: 0
+ elseif (loops == 1)
+ let p = 1
+ while p " dummy loop
+ Xloop 16 " X: 32*512*512
+ let p = 0
+ break " break dummy loop
+ Xloop 32 " X: 0
+ endwhile
+ Xloop 64 " X: 128*512*512
+ unlet p
+ break " break main loop
+ Xloop 128 " X: 0
+ endif
+ if (loops > 0)
+ Xloop 256 " X: 512
+ endif
+ while loops == 3 " dummy loop
+ let loops = loops - 1
+ endwhile " end dummy loop
+ XloopNEXT
+ endwhile " end main loop
+ Xpath 268435456 " X: 1024*512*512
+else
+ Xpath 536870912 " X: 0
+endif
+Xpath 1073741824 " X: 4096*512*512
+if exists("break_err")
+ " The Xpath command does not accept 2^31 (negative); add explicitly:
+ let Xpath = Xpath + 2147483648 " X: 0
+ unlet break_err
+endif
+
+unlet loops
+
+Xcheck 1384648195
+
+
+"-------------------------------------------------------------------------------
+" Test 4: :return {{{1
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+function! F()
+ if 1
+ Xpath 1 " X: 1
+ let loops = 3
+ XloopINIT 2 16
+ while loops > 0 " 3: 2: 1:
+ Xloop 1 " X: 2 + 2*16 + 0*16*16
+ if (loops == 2)
+ Xloop 2 " X: 4*16
+ return
+ Xloop 4 " X: 0
+ endif
+ Xloop 8 " X: 16
+ let loops = loops - 1
+ XloopNEXT
+ endwhile
+ Xpath 8192 " X: 0
+ else
+ Xpath 16384 " X: 0
+ endif
+endfunction
+
+call F()
+Xpath 32768 " X: 8*16*16*16
+
+Xcheck 32883
+
+" Leave F for execution as a script in the next test.
+
+
+"-------------------------------------------------------------------------------
+" Test 5: :finish {{{1
+"
+" This test executes the body of the function F from the previous test
+" as a script file (:return replaced by :finish).
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+ExecAsScript F " X: 1 + 2 + 2*16 + 4*16 + 16
+Xpath 32768 " X: 32768
+
+unlet loops
+delfunction F
+
+Xcheck 32883
+
+
+"-------------------------------------------------------------------------------
+" 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.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+if ExtraVim()
+
+ " 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
+
+
+ XloopINIT! 1 16
+
+ let i = 0
+ while i < 3
+
+ XloopNEXT
+ let i = i + 1
+
+ if i == 1
+ Xloop 1 " X: 1
+ function! F1(arg)
+ CALL a:arg
+ let outer = 1
+
+ XloopINIT! 4096 4
+ let j = 0
+ while j < 1
+ XloopNEXT
+ Xloop 1 " X: 4096
+ let j = j + 1
+ function! G1(arg)
+ CALL a:arg
+ endfunction
+ Xloop 2 " X: 8192
+ endwhile
+ endfunction
+ Xloop 2 " X: 2
+
+ continue
+ endif
+
+ Xloop 4 " X: 4 * (16 + 256)
+ function! F{i}(i, arg)
+ CALL a:arg
+ let outer = 1
+
+ XloopINIT! 16384 4
+ if a:i == 3
+ XloopNEXT
+ XloopNEXT
+ XloopNEXT
+ endif
+ let k = 0
+ while k < 3
+ XloopNEXT
+ Xloop 1 " X: 16384*(1+4+16+64+256+1024)
+ let k = k + 1
+ function! G{a:i}{k}(arg)
+ CALL a:arg
+ endfunction
+ Xloop 2 " X: 32768*(1+4+16+64+256+1024)
+ endwhile
+ endfunction
+ Xloop 8 " X: 8 * (16 + 256)
+
+ endwhile
+
+ if exists("*G1")
+ Xpath 67108864 " X: 0
+ endif
+ if exists("*F1")
+ call F1("F1")
+ if exists("*G1")
+ call G1("G1")
+ endif
+ endif
+
+ if exists("G21") || exists("G21") || exists("G21")
+ Xpath 134217728 " X: 0
+ 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("G31") || exists("G31")
+ Xpath 268435456 " X: 0
+ 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 536870912 " X: 536870912
+
+ if calls != "F1G1F2G21G22G23F3G31G32G33"
+ Xpath 1073741824 " X: 0
+ Xout "calls is" calls
+ endif
+
+ delfunction F1
+ delfunction G1
+ delfunction F2
+ delfunction G21
+ delfunction G22
+ delfunction G23
+ delfunction G31
+ delfunction G32
+ delfunction G33
+
+endif
+
+Xcheck 603978947
+
+
+"-------------------------------------------------------------------------------
+" 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 1 " X: 1
+ while 1
+ Xpath 2 " X: 2
+ asdf
+ Xpath 4 " X: 0
+ break
+ endwhile | Xpath 8 " X: 0
+ Xpath 16 " X: 0
+endif | Xpath 32 " X: 0
+Xpath 64 " X: 64
+
+while 1
+ Xpath 128 " X: 128
+ if 1
+ Xpath 256 " X: 256
+ asdf
+ Xpath 512 " X: 0
+ endif | Xpath 1024 " X: 0
+ Xpath 2048 " X: 0
+ break
+endwhile | Xpath 4096 " X: 0
+Xpath 8192 " X: 8192
+
+asdf
+Xpath 16384 " X: 16384
+
+asdf | Xpath 32768 " X: 0
+Xpath 65536 " X: 65536
+
+Xcheck 90563
+
+
+"-------------------------------------------------------------------------------
+" 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
+
+function! F()
+ if 1
+ Xpath 1 " X: 1
+ while 1
+ Xpath 2 " X: 2
+ asdf
+ Xpath 4 " X: 4
+ asdf | Xpath 8 " X: 0
+ Xpath 16 " X: 16
+ break
+ endwhile
+ Xpath 32 " X: 32
+ endif | Xpath 64 " X: 64
+ Xpath 128 " X: 128
+
+ while 1
+ Xpath 256 " X: 256
+ if 1
+ Xpath 512 " X: 512
+ asdf
+ Xpath 1024 " X: 1024
+ asdf | Xpath 2048 " X: 0
+ Xpath 4096 " X: 4096
+ endif
+ Xpath 8192 " X: 8192
+ break
+ endwhile | Xpath 16384 " X: 16384
+ Xpath 32768 " X: 32768
+
+ return novar " returns (default return value 0)
+ Xpath 65536 " X: 0
+ return 1 " not reached
+endfunction
+
+function! G() abort
+ if 1
+ Xpath 131072 " X: 131072
+ while 1
+ Xpath 262144 " X: 262144
+ asdf " returns -1
+ Xpath 524288 " X: 0
+ break
+ endwhile
+ Xpath 1048576 " X: 0
+ endif | Xpath 2097152 " X: 0
+ Xpath Xpath 4194304 " X: 0
+
+ return -4 " not reached
+endfunction
+
+function! H() abort
+ while 1
+ Xpath 8388608 " X: 8388608
+ if 1
+ Xpath 16777216 " X: 16777216
+ asdf " returns -1
+ Xpath 33554432 " X: 0
+ endif
+ Xpath 67108864 " X: 0
+ break
+ endwhile | Xpath 134217728 " X: 0
+ Xpath 268435456 " X: 0
+
+ return -4 " not reached
+endfunction
+
+" Aborted functions (G and H) return -1.
+let sum = (F() + 1) - 4*G() - 8*H()
+Xpath 536870912 " X: 536870912
+if sum != 13
+ Xpath 1073741824 " X: 0
+ Xout "sum is" sum
+endif
+
+unlet sum
+delfunction F
+delfunction G
+delfunction H
+
+Xcheck 562493431
+
+
+"-------------------------------------------------------------------------------
+" 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
+