To: vim_dev@googlegroups.com Subject: Patch 8.2.1417 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.1417 Problem: Test 49 is old style. Solution: Convert more parts to new style test. (Yegappan Lakshmanan, closes #6682) Files: src/testdir/test49.ok, src/testdir/test49.vim, src/testdir/test_vimscript.vim *** ../vim-8.2.1416/src/testdir/test49.ok 2020-08-07 16:49:06.425905234 +0200 --- src/testdir/test49.ok 2020-08-10 22:13:55.867239536 +0200 *************** *** 1,18 **** Results of test49.vim: - *** Test 59: OK (2038431743) - *** Test 60: OK (311511339) - *** Test 62: OK (286331153) - *** Test 63: OK (236978127) - *** Test 64: OK (1499645335) - *** Test 66: OK (5464) - *** Test 67: OK (212514423) - *** Test 68: OK (212514423) - *** Test 76: OK (1610087935) - *** Test 77: OK (1388671) - *** Test 78: OK (134217728) - *** Test 79: OK (70288929) - *** Test 80: OK (17895765) - *** Test 81: OK (387) *** Test 82: OK (8454401) *** Test 83: OK (2835) *** Test 84: OK (934782101) --- 1,4 ---- *** ../vim-8.2.1416/src/testdir/test49.vim 2020-08-07 16:49:06.425905234 +0200 --- src/testdir/test49.vim 2020-08-10 22:13:55.871239529 +0200 *************** *** 648,3115 **** return match endfunction ! " Leave MESSAGES() for the next tests. ! ! " Tests 1 to 50, 52 to 57, 87 were moved to test_vimscript.vim ! " Tests 25, 26, 32, 33, 41-48, 51, 69-75 were moved to test_trycatch.vim ! let Xtest = 59 ! ! "------------------------------------------------------------------------------- ! " ! " Test 59: v:exception and v:throwpoint when discarding exceptions {{{1 ! " ! " When a :catch clause is left by a ":break" etc or an error or ! " interrupt exception, v:exception and v:throwpoint are reset. They ! " are not affected by an exception that is discarded before being ! " caught. ! "------------------------------------------------------------------------------- ! ! XpathINIT ! ! if ExtraVim() ! ! XloopINIT! 1 2 ! ! let sfile = expand("") ! ! function! LineNumber() ! return substitute(substitute(v:throwpoint, g:sfile, '', ""), ! \ '\D*\(\d*\).*', '\1', "") ! endfunction ! ! command! -nargs=1 SetLineNumber ! \ try | throw "line" | catch /.*/ | let = LineNumber() | endtry ! ! " Check v:exception/v:throwpoint against second/fourth parameter if ! " specified, check for being empty else. ! function! CHECK(n, ...) ! XloopNEXT ! let exception = a:0 != 0 ? a:1 : "" " second parameter (optional) ! let emsg = a:0 != 0 ? a:2 : "" " third parameter (optional) ! let line = a:0 != 0 ? a:3 : 0 " fourth parameter (optional) ! let error = 0 ! if emsg != "" ! " exception is the error number, emsg the English error message text ! if exception !~ '^E\d\+$' ! Xout "TODO: Add message number for:" emsg ! elseif v:lang == "C" || v:lang =~ '^[Ee]n' ! if exception == "E492" && emsg == "Not an editor command" ! let exception = '^Vim:' . exception . ': ' . emsg ! else ! let exception = '^Vim(\a\+):' . exception . ': ' . emsg ! endif ! else ! if exception == "E492" ! let exception = '^Vim:' . exception ! else ! let exception = '^Vim(\a\+):' . exception ! endif ! endif ! endif ! if exception == "" && v:exception != "" ! Xout a:n.": v:exception is set:" v:exception ! let error = 1 ! elseif exception != "" && v:exception !~ exception ! Xout a:n.": v:exception (".v:exception.") does not match" exception ! let error = 1 ! endif ! if line == 0 && v:throwpoint != "" ! Xout a:n.": v:throwpoint is set:" v:throwpoint ! let error = 1 ! elseif line != 0 && v:throwpoint !~ '\<' . line . '\>' ! Xout a:n.": v:throwpoint (".v:throwpoint.") does not match" line ! let error = 1 ! endif ! if !error ! Xloop 1 " X: 2097151 ! endif ! endfunction ! ! while 1 ! try ! throw "x1" ! catch /.*/ ! break ! endtry ! endwhile ! call CHECK(1) ! ! while 1 ! try ! throw "x2" ! catch /.*/ ! break ! finally ! call CHECK(2) ! endtry ! break ! endwhile ! call CHECK(3) ! ! while 1 ! try ! let errcaught = 0 ! try ! try ! throw "x3" ! catch /.*/ ! SetLineNumber line_before_error ! asdf ! endtry ! catch /.*/ ! let errcaught = 1 ! call CHECK(4, 'E492', "Not an editor command", ! \ line_before_error + 1) ! endtry ! finally ! if !errcaught && $VIMNOERRTHROW ! call CHECK(4) ! endif ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! call CHECK(5) ! ! Xpath 2097152 " X: 2097152 ! ! while 1 ! try ! let intcaught = 0 ! try ! try ! throw "x4" ! catch /.*/ ! SetLineNumber two_lines_before_interrupt ! "INTERRUPT ! let dummy = 0 ! endtry ! catch /.*/ ! let intcaught = 1 ! call CHECK(6, "Vim:Interrupt", '', ! \ two_lines_before_interrupt + 2) ! endtry ! finally ! if !intcaught && $VIMNOINTTHROW ! call CHECK(6) ! endif ! break " discard interrupt for $VIMNOINTTHROW ! endtry ! endwhile ! call CHECK(7) ! ! Xpath 4194304 " X: 4194304 ! ! while 1 ! try ! let errcaught = 0 ! try ! try ! " if 1 ! SetLineNumber line_before_throw ! throw "x5" ! " missing endif ! catch /.*/ ! Xpath 8388608 " X: 0 ! endtry ! catch /.*/ ! let errcaught = 1 ! call CHECK(8, 'E171', "Missing :endif", line_before_throw + 3) ! endtry ! finally ! if !errcaught && $VIMNOERRTHROW ! call CHECK(8) ! endif ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! call CHECK(9) ! ! Xpath 16777216 " X: 16777216 ! ! try ! while 1 ! try ! throw "x6" ! finally ! break ! endtry ! break ! endwhile ! catch /.*/ ! Xpath 33554432 " X: 0 ! endtry ! call CHECK(10) ! ! try ! while 1 ! try ! throw "x7" ! finally ! break ! endtry ! break ! endwhile ! catch /.*/ ! Xpath 67108864 " X: 0 ! finally ! call CHECK(11) ! endtry ! call CHECK(12) ! ! while 1 ! try ! let errcaught = 0 ! try ! try ! throw "x8" ! finally ! SetLineNumber line_before_error ! asdf ! endtry ! catch /.*/ ! let errcaught = 1 ! call CHECK(13, 'E492', "Not an editor command", ! \ line_before_error + 1) ! endtry ! finally ! if !errcaught && $VIMNOERRTHROW ! call CHECK(13) ! endif ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! call CHECK(14) ! ! Xpath 134217728 " X: 134217728 ! ! while 1 ! try ! let intcaught = 0 ! try ! try ! throw "x9" ! finally ! SetLineNumber two_lines_before_interrupt ! "INTERRUPT ! endtry ! catch /.*/ ! let intcaught = 1 ! call CHECK(15, "Vim:Interrupt", '', ! \ two_lines_before_interrupt + 2) ! endtry ! finally ! if !intcaught && $VIMNOINTTHROW ! call CHECK(15) ! endif ! break " discard interrupt for $VIMNOINTTHROW ! endtry ! endwhile ! call CHECK(16) ! ! Xpath 268435456 " X: 268435456 ! ! while 1 ! try ! let errcaught = 0 ! try ! try ! " if 1 ! SetLineNumber line_before_throw ! throw "x10" ! " missing endif ! finally ! call CHECK(17) ! endtry ! catch /.*/ ! let errcaught = 1 ! call CHECK(18, 'E171', "Missing :endif", line_before_throw + 3) ! endtry ! finally ! if !errcaught && $VIMNOERRTHROW ! call CHECK(18) ! endif ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! call CHECK(19) ! ! Xpath 536870912 " X: 536870912 ! ! while 1 ! try ! let errcaught = 0 ! try ! try ! " if 1 ! SetLineNumber line_before_throw ! throw "x11" ! " missing endif ! endtry ! catch /.*/ ! let errcaught = 1 ! call CHECK(20, 'E171', "Missing :endif", line_before_throw + 3) ! endtry ! finally ! if !errcaught && $VIMNOERRTHROW ! call CHECK(20) ! endif ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! call CHECK(21) ! ! Xpath 1073741824 " X: 1073741824 ! ! endif ! ! Xcheck 2038431743 ! ! ! "------------------------------------------------------------------------------- ! " ! " Test 60: (Re)throwing v:exception; :echoerr. {{{1 ! " ! " A user exception can be rethrown after catching by throwing ! " v:exception. An error or interrupt exception cannot be rethrown ! " because Vim exceptions cannot be faked. A Vim exception using the ! " value of v:exception can, however, be triggered by the :echoerr ! " command. ! "------------------------------------------------------------------------------- ! ! XpathINIT ! ! try ! try ! Xpath 1 " X: 1 ! throw "oops" ! catch /oops/ ! Xpath 2 " X: 2 ! throw v:exception " rethrow user exception ! catch /.*/ ! Xpath 4 " X: 0 ! endtry ! catch /^oops$/ " catches rethrown user exception ! Xpath 8 " X: 8 ! catch /.*/ ! Xpath 16 " X: 0 ! endtry ! ! function! F() ! try ! let caught = 0 ! try ! Xpath 32 " X: 32 ! write /n/o/n/w/r/i/t/a/b/l/e/_/f/i/l/e ! Xpath 64 " X: 0 ! Xout "did_emsg was reset before executing " . ! \ "BufWritePost autocommands." ! catch /^Vim(write):/ ! let caught = 1 ! throw v:exception " throw error: cannot fake Vim exception ! catch /.*/ ! Xpath 128 " X: 0 ! finally ! Xpath 256 " X: 256 ! if !caught && !$VIMNOERRTHROW ! Xpath 512 " X: 0 ! endif ! endtry ! catch /^Vim(throw):/ " catches throw error ! let caught = caught + 1 ! catch /.*/ ! Xpath 1024 " X: 0 ! finally ! Xpath 2048 " X: 2048 ! if caught != 2 ! if !caught && !$VIMNOERRTHROW ! Xpath 4096 " X: 0 ! elseif caught ! Xpath 8192 " X: 0 ! endif ! return | " discard error for $VIMNOERRTHROW ! endif ! endtry ! endfunction ! ! call F() ! delfunction F ! ! function! G() ! try ! let caught = 0 ! try ! Xpath 16384 " X: 16384 ! asdf ! catch /^Vim/ " catch error exception ! let caught = 1 ! " Trigger Vim error exception with value specified after :echoerr ! let value = substitute(v:exception, '^Vim\((.*)\)\=:', '', "") ! echoerr value ! catch /.*/ ! Xpath 32768 " X: 0 ! finally ! Xpath 65536 " X: 65536 ! if !caught ! if !$VIMNOERRTHROW ! Xpath 131072 " X: 0 ! else ! let value = "Error" ! echoerr value ! endif ! endif ! endtry ! catch /^Vim(echoerr):/ ! let caught = caught + 1 ! if v:exception !~ value ! Xpath 262144 " X: 0 ! endif ! catch /.*/ ! Xpath 524288 " X: 0 ! finally ! Xpath 1048576 " X: 1048576 ! if caught != 2 ! if !caught && !$VIMNOERRTHROW ! Xpath 2097152 " X: 0 ! elseif caught ! Xpath 4194304 " X: 0 ! endif ! return | " discard error for $VIMNOERRTHROW ! endif ! endtry ! endfunction ! ! call G() ! delfunction G ! ! unlet! value caught ! ! if ExtraVim() ! try ! let errcaught = 0 ! try ! Xpath 8388608 " X: 8388608 ! let intcaught = 0 ! "INTERRUPT ! catch /^Vim:/ " catch interrupt exception ! let intcaught = 1 ! " Trigger Vim error exception with value specified after :echoerr ! echoerr substitute(v:exception, '^Vim\((.*)\)\=:', '', "") ! catch /.*/ ! Xpath 16777216 " X: 0 ! finally ! Xpath 33554432 " X: 33554432 ! if !intcaught ! if !$VIMNOINTTHROW ! Xpath 67108864 " X: 0 ! else ! echoerr "Interrupt" ! endif ! endif ! endtry ! catch /^Vim(echoerr):/ ! let errcaught = 1 ! if v:exception !~ "Interrupt" ! Xpath 134217728 " X: 0 ! endif ! finally ! Xpath 268435456 " X: 268435456 ! if !errcaught && !$VIMNOERRTHROW ! Xpath 536870912 " X: 0 ! endif ! endtry ! endif ! ! Xcheck 311511339 ! ! " Test 61 was moved to test_vimscript.vim ! let Xtest = 62 ! ! "------------------------------------------------------------------------------- ! " Test 62: Catching error exceptions {{{1 ! " ! " An error inside a :try/:endtry region is converted to an exception ! " and can be caught. The error exception has a "Vim(cmdname):" prefix ! " where cmdname is the name of the failing command, or a "Vim:" prefix ! " if no command name is known. The "Vim" prefixes cannot be faked. ! "------------------------------------------------------------------------------- ! ! XpathINIT ! ! function! 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 = escape(v:errmsg, '"') ! Xout "Unexpected message:" v:errmsg ! endif ! endif ! return match ! endfunction ! ! while 1 ! try ! try ! let caught = 0 ! unlet novar ! catch /^Vim(unlet):/ ! let caught = 1 ! let v:errmsg = substitute(v:exception, '^Vim(unlet):', '', "") ! finally ! Xpath 1 " X: 1 ! if !caught && !$VIMNOERRTHROW ! Xpath 2 " X: 0 ! endif ! if !MSG('E108', "No such variable") ! Xpath 4 " X: 0 ! endif ! endtry ! catch /.*/ ! Xpath 8 " X: 0 ! Xout v:exception "in" v:throwpoint ! finally ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! ! while 1 ! try ! try ! let caught = 0 ! throw novar " error in :throw ! catch /^Vim(throw):/ ! let caught = 1 ! let v:errmsg = substitute(v:exception, '^Vim(throw):', '', "") ! finally ! Xpath 16 " X: 16 ! if !caught && !$VIMNOERRTHROW ! Xpath 32 " X: 0 ! endif ! if caught ? !MSG('E121', "Undefined variable") ! \ : !MSG('E15', "Invalid expression") ! Xpath 64 " X: 0 ! endif ! endtry ! catch /.*/ ! Xpath 128 " X: 0 ! Xout v:exception "in" v:throwpoint ! finally ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! ! while 1 ! try ! try ! let caught = 0 ! throw "Vim:faked" " error: cannot fake Vim exception ! catch /^Vim(throw):/ ! let caught = 1 ! let v:errmsg = substitute(v:exception, '^Vim(throw):', '', "") ! finally ! Xpath 256 " X: 256 ! if !caught && !$VIMNOERRTHROW ! Xpath 512 " X: 0 ! endif ! if !MSG('E608', "Cannot :throw exceptions with 'Vim' prefix") ! Xpath 1024 " X: 0 ! endif ! endtry ! catch /.*/ ! Xpath 2048 " X: 0 ! Xout v:exception "in" v:throwpoint ! finally ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! ! function! F() ! while 1 ! " Missing :endwhile ! endfunction ! ! while 1 ! try ! try ! let caught = 0 ! call F() ! catch /^Vim(endfunction):/ ! let caught = 1 ! let v:errmsg = substitute(v:exception, '^Vim(endfunction):', '', "") ! finally ! Xpath 4096 " X: 4096 ! if !caught && !$VIMNOERRTHROW ! Xpath 8192 " X: 0 ! endif ! if !MSG('E170', "Missing :endwhile") ! Xpath 16384 " X: 0 ! endif ! endtry ! catch /.*/ ! Xpath 32768 " X: 0 ! Xout v:exception "in" v:throwpoint ! finally ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! ! while 1 ! try ! try ! let caught = 0 ! ExecAsScript F ! catch /^Vim:/ ! let caught = 1 ! let v:errmsg = substitute(v:exception, '^Vim:', '', "") ! finally ! Xpath 65536 " X: 65536 ! if !caught && !$VIMNOERRTHROW ! Xpath 131072 " X: 0 ! endif ! if !MSG('E170', "Missing :endwhile") ! Xpath 262144 " X: 0 ! endif ! endtry ! catch /.*/ ! Xpath 524288 " X: 0 ! Xout v:exception "in" v:throwpoint ! finally ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! ! function! G() ! call G() ! endfunction ! ! while 1 ! try ! let mfd_save = &mfd ! set mfd=3 ! try ! let caught = 0 ! call G() ! catch /^Vim(call):/ ! let caught = 1 ! let v:errmsg = substitute(v:exception, '^Vim(call):', '', "") ! finally ! Xpath 1048576 " X: 1048576 ! if !caught && !$VIMNOERRTHROW ! Xpath 2097152 " X: 0 ! endif ! if !MSG('E132', "Function call depth is higher than 'maxfuncdepth'") ! Xpath 4194304 " X: 0 ! endif ! endtry ! catch /.*/ ! Xpath 8388608 " X: 0 ! Xout v:exception "in" v:throwpoint ! finally ! let &mfd = mfd_save ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! ! function! H() ! return H() ! endfunction ! ! while 1 ! try ! let mfd_save = &mfd ! set mfd=3 ! try ! let caught = 0 ! call H() ! catch /^Vim(return):/ ! let caught = 1 ! let v:errmsg = substitute(v:exception, '^Vim(return):', '', "") ! finally ! Xpath 16777216 " X: 16777216 ! if !caught && !$VIMNOERRTHROW ! Xpath 33554432 " X: 0 ! endif ! if !MSG('E132', "Function call depth is higher than 'maxfuncdepth'") ! Xpath 67108864 " X: 0 ! endif ! endtry ! catch /.*/ ! Xpath 134217728 " X: 0 ! Xout v:exception "in" v:throwpoint ! finally ! let &mfd = mfd_save ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! ! unlet! caught mfd_save ! delfunction F ! delfunction G ! delfunction H ! Xpath 268435456 " X: 268435456 ! ! Xcheck 286331153 ! ! " Leave MSG() for the next test. ! ! ! "------------------------------------------------------------------------------- ! " Test 63: Suppressing error exceptions by :silent!. {{{1 ! " ! " A :silent! command inside a :try/:endtry region suppresses the ! " conversion of errors to an exception and the immediate abortion on ! " error. When the commands executed by the :silent! themselves open ! " a new :try/:endtry region, conversion of errors to exception and ! " immediate abortion is switched on again - until the next :silent! ! " etc. The :silent! has the effect of setting v:errmsg to the error ! " message text (without displaying it) and continuing with the next ! " script line. ! " ! " When a command triggering autocommands is executed by :silent! ! " inside a :try/:endtry, the autocommand execution is not suppressed ! " on error. ! " ! " This test reuses the function MSG() from the previous test. ! "------------------------------------------------------------------------------- ! ! XpathINIT ! ! XloopINIT! 1 4 ! ! let taken = "" ! ! function! S(n) abort ! XloopNEXT ! let g:taken = g:taken . "E" . a:n ! let v:errmsg = "" ! exec "asdf" . a:n ! ! " Check that ":silent!" continues: ! Xloop 1 ! ! " Check that ":silent!" sets "v:errmsg": ! if MSG('E492', "Not an editor command") ! Xloop 2 ! endif ! endfunction ! ! function! Foo() ! while 1 ! try ! try ! let caught = 0 ! " This is not silent: ! call S(3) " X: 0 * 16 ! catch /^Vim:/ ! let caught = 1 ! let errmsg3 = substitute(v:exception, '^Vim:', '', "") ! silent! call S(4) " X: 3 * 64 ! finally ! if !caught ! let errmsg3 = v:errmsg ! " Do call S(4) here if not executed in :catch. ! silent! call S(4) ! endif ! Xpath 1048576 " X: 1048576 ! if !caught && !$VIMNOERRTHROW ! Xpath 2097152 " X: 0 ! endif ! let v:errmsg = errmsg3 ! if !MSG('E492', "Not an editor command") ! Xpath 4194304 " X: 0 ! endif ! silent! call S(5) " X: 3 * 256 ! " Break out of try conditionals that cover ":silent!". This also ! " discards the aborting error when $VIMNOERRTHROW is non-zero. ! break ! endtry ! catch /.*/ ! Xpath 8388608 " X: 0 ! Xout v:exception "in" v:throwpoint ! endtry ! endwhile ! " This is a double ":silent!" (see caller). ! silent! call S(6) " X: 3 * 1024 ! endfunction ! ! function! Bar() ! try ! silent! call S(2) " X: 3 * 4 ! " X: 3 * 4096 ! silent! execute "call Foo() | call S(7)" ! silent! call S(8) " X: 3 * 16384 ! endtry " normal end of try cond that covers ":silent!" ! " This has a ":silent!" from the caller: ! call S(9) " X: 3 * 65536 ! endfunction ! ! silent! call S(1) " X: 3 * 1 ! silent! call Bar() ! silent! call S(10) " X: 3 * 262144 ! ! let expected = "E1E2E3E4E5E6E7E8E9E10" ! if taken != expected ! Xpath 16777216 " X: 0 ! Xout "'taken' is" taken "instead of" expected ! endif ! ! augroup TMP ! autocmd BufWritePost * Xpath 33554432 " X: 33554432 ! augroup END ! ! Xpath 67108864 " X: 67108864 ! write /i/m/p/o/s/s/i/b/l/e ! Xpath 134217728 " X: 134217728 ! ! autocmd! TMP ! unlet! caught errmsg3 taken expected ! delfunction S ! delfunction Foo ! delfunction Bar ! delfunction MSG ! ! Xcheck 236978127 ! ! ! "------------------------------------------------------------------------------- ! " Test 64: Error exceptions after error, interrupt or :throw {{{1 ! " ! " When an error occurs after an interrupt or a :throw but before ! " a matching :catch is reached, all following :catches of that try ! " block are ignored, but the error exception can be caught by the next ! " surrounding try conditional. Any previous error exception is ! " discarded. An error is ignored when there is a previous error that ! " has not been caught. ! "------------------------------------------------------------------------------- ! ! XpathINIT ! ! if ExtraVim() ! ! while 1 ! try ! try ! Xpath 1 " X: 1 ! let caught = 0 ! while 1 ! " if 1 ! " Missing :endif ! endwhile " throw error exception ! catch /^Vim(/ ! let caught = 1 ! finally ! Xpath 2 " X: 2 ! if caught || $VIMNOERRTHROW ! Xpath 4 " X: 4 ! endif ! endtry ! catch /.*/ ! Xpath 8 " X: 0 ! Xout v:exception "in" v:throwpoint ! finally ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! ! while 1 ! try ! try ! Xpath 16 " X: 16 ! let caught = 0 ! try ! " if 1 ! " Missing :endif ! catch /.*/ " throw error exception ! Xpath 32 " X: 0 ! catch /.*/ ! Xpath 64 " X: 0 ! endtry ! catch /^Vim(/ ! let caught = 1 ! finally ! Xpath 128 " X: 128 ! if caught || $VIMNOERRTHROW ! Xpath 256 " X: 256 ! endif ! endtry ! catch /.*/ ! Xpath 512 " X: 0 ! Xout v:exception "in" v:throwpoint ! finally ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! ! while 1 ! try ! try ! let caught = 0 ! try ! Xpath 1024 " X: 1024 ! "INTERRUPT ! catch /do_not_catch/ ! Xpath 2048 " X: 0 ! " if 1 ! " Missing :endif ! catch /.*/ " throw error exception ! Xpath 4096 " X: 0 ! catch /.*/ ! Xpath 8192 " X: 0 ! endtry ! catch /^Vim(/ ! let caught = 1 ! finally ! Xpath 16384 " X: 16384 ! if caught || $VIMNOERRTHROW ! Xpath 32768 " X: 32768 ! endif ! endtry ! catch /.*/ ! Xpath 65536 " X: 0 ! Xout v:exception "in" v:throwpoint ! finally ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! ! while 1 ! try ! try ! let caught = 0 ! try ! Xpath 131072 " X: 131072 ! throw "x" ! catch /do_not_catch/ ! Xpath 262144 " X: 0 ! " if 1 ! " Missing :endif ! catch /x/ " throw error exception ! Xpath 524288 " X: 0 ! catch /.*/ ! Xpath 1048576 " X: 0 ! endtry ! catch /^Vim(/ ! let caught = 1 ! finally ! Xpath 2097152 " X: 2097152 ! if caught || $VIMNOERRTHROW ! Xpath 4194304 " X: 4194304 ! endif ! endtry ! catch /.*/ ! Xpath 8388608 " X: 0 ! Xout v:exception "in" v:throwpoint ! finally ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! ! while 1 ! try ! try ! let caught = 0 ! Xpath 16777216 " X: 16777216 ! " endif " :endif without :if; throw error exception ! " if 1 ! " Missing :endif ! catch /do_not_catch/ " ignore new error ! Xpath 33554432 " X: 0 ! catch /^Vim(endif):/ ! let caught = 1 ! catch /^Vim(/ ! Xpath 67108864 " X: 0 ! finally ! Xpath 134217728 " X: 134217728 ! if caught || $VIMNOERRTHROW ! Xpath 268435456 " X: 268435456 ! endif ! endtry ! catch /.*/ ! Xpath 536870912 " X: 0 ! Xout v:exception "in" v:throwpoint ! finally ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! ! Xpath 1073741824 " X: 1073741824 ! ! endif ! ! Xcheck 1499645335 ! ! " Test 65 was moved to test_vimscript.vim ! let Xtest = 66 ! ! "------------------------------------------------------------------------------- ! " Test 66: Stop range :call on error, interrupt, or :throw {{{1 ! " ! " When a function which is multiply called for a range since it ! " doesn't handle the range itself has an error in a command ! " dynamically enclosed by :try/:endtry or gets an interrupt or ! " executes a :throw, no more calls for the remaining lines in the ! " range are made. On an error in a command not dynamically enclosed ! " by :try/:endtry, the function is executed again for the remaining ! " lines in the range. ! "------------------------------------------------------------------------------- ! ! XpathINIT ! ! if ExtraVim() ! ! let file = tempname() ! exec "edit" file ! ! insert ! line 1 ! line 2 ! line 3 ! . ! ! XloopINIT! 1 2 ! ! let taken = "" ! let expected = "G1EF1E(1)F1E(2)F1E(3)G2EF2E(1)G3IF3I(1)G4TF4T(1)G5AF5A(1)" ! ! function! F(reason, n) abort ! let g:taken = g:taken . "F" . a:n . ! \ substitute(a:reason, '\(\l\).*', '\u\1', "") . ! \ "(" . line(".") . ")" ! ! if a:reason == "error" ! asdf ! elseif a:reason == "interrupt" ! "INTERRUPT ! let dummy = 0 ! elseif a:reason == "throw" ! throw "xyz" ! elseif a:reason == "aborting error" ! XloopNEXT ! if g:taken != g:expected ! Xloop 1 " X: 0 ! Xout "'taken' is" g:taken "instead of" g:expected ! endif ! try ! bwipeout! ! call delete(file) ! asdf ! endtry ! endif ! endfunction ! ! function! G(reason, n) ! let g:taken = g:taken . "G" . a:n . ! \ substitute(a:reason, '\(\l\).*', '\u\1', "") ! 1,3call F(a:reason, a:n) ! endfunction ! ! Xpath 8 " X: 8 ! call G("error", 1) ! try ! Xpath 16 " X: 16 ! try ! call G("error", 2) ! Xpath 32 " X: 0 ! finally ! Xpath 64 " X: 64 ! try ! call G("interrupt", 3) ! Xpath 128 " X: 0 ! finally ! Xpath 256 " X: 256 ! try ! call G("throw", 4) ! Xpath 512 " X: 0 ! endtry ! endtry ! endtry ! catch /xyz/ ! Xpath 1024 " X: 1024 ! catch /.*/ ! Xpath 2048 " X: 0 ! Xout v:exception "in" ExtraVimThrowpoint() ! endtry ! Xpath 4096 " X: 4096 ! call G("aborting error", 5) ! Xpath 8192 " X: 0 ! Xout "'taken' is" taken "instead of" expected ! ! endif ! ! Xcheck 5464 ! ! ! "------------------------------------------------------------------------------- ! " Test 67: :throw across :call command {{{1 ! " ! " On a call command, an exception might be thrown when evaluating the ! " function name, during evaluation of the arguments, or when the ! " function is being executed. The exception can be caught by the ! " caller. ! "------------------------------------------------------------------------------- ! ! XpathINIT ! ! function! THROW(x, n) ! if a:n == 1 ! Xpath 1 " X: 1 ! elseif a:n == 2 ! Xpath 2 " X: 2 ! elseif a:n == 3 ! Xpath 4 " X: 4 ! endif ! throw a:x ! endfunction ! ! function! NAME(x, n) ! if a:n == 1 ! Xpath 8 " X: 0 ! elseif a:n == 2 ! Xpath 16 " X: 16 ! elseif a:n == 3 ! Xpath 32 " X: 32 ! elseif a:n == 4 ! Xpath 64 " X: 64 ! endif ! return a:x ! endfunction ! ! function! ARG(x, n) ! if a:n == 1 ! Xpath 128 " X: 0 ! elseif a:n == 2 ! Xpath 256 " X: 0 ! elseif a:n == 3 ! Xpath 512 " X: 512 ! elseif a:n == 4 ! Xpath 1024 " X: 1024 ! endif ! return a:x ! endfunction ! ! function! F(x, n) ! if a:n == 2 ! Xpath 2048 " X: 0 ! elseif a:n == 4 ! Xpath 4096 " X: 4096 ! endif ! endfunction ! ! while 1 ! try ! let error = 0 ! let v:errmsg = "" ! ! while 1 ! try ! Xpath 8192 " X: 8192 ! call {NAME(THROW("name", 1), 1)}(ARG(4711, 1), 1) ! Xpath 16384 " X: 0 ! catch /^name$/ ! Xpath 32768 " X: 32768 ! catch /.*/ ! let error = 1 ! Xout "1:" v:exception "in" v:throwpoint ! finally ! if !error && $VIMNOERRTHROW && v:errmsg != "" ! let error = 1 ! Xout "1:" v:errmsg ! endif ! if error ! Xpath 65536 " X: 0 ! endif ! let error = 0 ! let v:errmsg = "" ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! ! while 1 ! try ! Xpath 131072 " X: 131072 ! call {NAME("F", 2)}(ARG(THROW("arg", 2), 2), 2) ! Xpath 262144 " X: 0 ! catch /^arg$/ ! Xpath 524288 " X: 524288 ! catch /.*/ ! let error = 1 ! Xout "2:" v:exception "in" v:throwpoint ! finally ! if !error && $VIMNOERRTHROW && v:errmsg != "" ! let error = 1 ! Xout "2:" v:errmsg ! endif ! if error ! Xpath 1048576 " X: 0 ! endif ! let error = 0 ! let v:errmsg = "" ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! ! while 1 ! try ! Xpath 2097152 " X: 2097152 ! call {NAME("THROW", 3)}(ARG("call", 3), 3) ! Xpath 4194304 " X: 0 ! catch /^call$/ ! Xpath 8388608 " X: 8388608 ! catch /^0$/ " default return value ! Xpath 16777216 " X: 0 ! Xout "3:" v:throwpoint ! catch /.*/ ! let error = 1 ! Xout "3:" v:exception "in" v:throwpoint ! finally ! if !error && $VIMNOERRTHROW && v:errmsg != "" ! let error = 1 ! Xout "3:" v:errmsg ! endif ! if error ! Xpath 33554432 " X: 0 ! endif ! let error = 0 ! let v:errmsg = "" ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! ! while 1 ! try ! Xpath 67108864 " X: 67108864 ! call {NAME("F", 4)}(ARG(4711, 4), 4) ! Xpath 134217728 " X: 134217728 ! catch /.*/ ! let error = 1 ! Xout "4:" v:exception "in" v:throwpoint ! finally ! if !error && $VIMNOERRTHROW && v:errmsg != "" ! let error = 1 ! Xout "4:" v:errmsg ! endif ! if error ! Xpath 268435456 " X: 0 ! endif ! let error = 0 ! let v:errmsg = "" ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! ! catch /^0$/ " default return value ! Xpath 536870912 " X: 0 ! Xout v:throwpoint ! catch /.*/ ! let error = 1 ! Xout v:exception "in" v:throwpoint ! finally ! if !error && $VIMNOERRTHROW && v:errmsg != "" ! let error = 1 ! Xout v:errmsg ! endif ! if error ! Xpath 1073741824 " X: 0 ! endif ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! ! unlet error ! delfunction F ! ! Xcheck 212514423 ! ! " Leave THROW(), NAME(), and ARG() for the next test. ! ! ! "------------------------------------------------------------------------------- ! " Test 68: :throw across function calls in expressions {{{1 ! " ! " On a function call within an expression, an exception might be ! " thrown when evaluating the function name, during evaluation of the ! " arguments, or when the function is being executed. The exception ! " can be caught by the caller. ! " ! " This test reuses the functions THROW(), NAME(), and ARG() from the ! " previous test. ! "------------------------------------------------------------------------------- ! ! XpathINIT ! ! function! F(x, n) ! if a:n == 2 ! Xpath 2048 " X: 0 ! elseif a:n == 4 ! Xpath 4096 " X: 4096 ! endif ! return a:x ! endfunction ! ! unlet! var1 var2 var3 var4 ! ! while 1 ! try ! let error = 0 ! let v:errmsg = "" ! ! while 1 ! try ! Xpath 8192 " X: 8192 ! let var1 = {NAME(THROW("name", 1), 1)}(ARG(4711, 1), 1) ! Xpath 16384 " X: 0 ! catch /^name$/ ! Xpath 32768 " X: 32768 ! catch /.*/ ! let error = 1 ! Xout "1:" v:exception "in" v:throwpoint ! finally ! if !error && $VIMNOERRTHROW && v:errmsg != "" ! let error = 1 ! Xout "1:" v:errmsg ! endif ! if error ! Xpath 65536 " X: 0 ! endif ! let error = 0 ! let v:errmsg = "" ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! ! while 1 ! try ! Xpath 131072 " X: 131072 ! let var2 = {NAME("F", 2)}(ARG(THROW("arg", 2), 2), 2) ! Xpath 262144 " X: 0 ! catch /^arg$/ ! Xpath 524288 " X: 524288 ! catch /.*/ ! let error = 1 ! Xout "2:" v:exception "in" v:throwpoint ! finally ! if !error && $VIMNOERRTHROW && v:errmsg != "" ! let error = 1 ! Xout "2:" v:errmsg ! endif ! if error ! Xpath 1048576 " X: 0 ! endif ! let error = 0 ! let v:errmsg = "" ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! ! while 1 ! try ! Xpath 2097152 " X: 2097152 ! let var3 = {NAME("THROW", 3)}(ARG("call", 3), 3) ! Xpath 4194304 " X: 0 ! catch /^call$/ ! Xpath 8388608 " X: 8388608 ! catch /^0$/ " default return value ! Xpath 16777216 " X: 0 ! Xout "3:" v:throwpoint ! catch /.*/ ! let error = 1 ! Xout "3:" v:exception "in" v:throwpoint ! finally ! if !error && $VIMNOERRTHROW && v:errmsg != "" ! let error = 1 ! Xout "3:" v:errmsg ! endif ! if error ! Xpath 33554432 " X: 0 ! endif ! let error = 0 ! let v:errmsg = "" ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! ! while 1 ! try ! Xpath 67108864 " X: 67108864 ! let var4 = {NAME("F", 4)}(ARG(4711, 4), 4) ! Xpath 134217728 " X: 134217728 ! catch /.*/ ! let error = 1 ! Xout "4:" v:exception "in" v:throwpoint ! finally ! if !error && $VIMNOERRTHROW && v:errmsg != "" ! let error = 1 ! Xout "4:" v:errmsg ! endif ! if error ! Xpath 268435456 " X: 0 ! endif ! let error = 0 ! let v:errmsg = "" ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! ! catch /^0$/ " default return value ! Xpath 536870912 " X: 0 ! Xout v:throwpoint ! catch /.*/ ! let error = 1 ! Xout v:exception "in" v:throwpoint ! finally ! if !error && $VIMNOERRTHROW && v:errmsg != "" ! let error = 1 ! Xout v:errmsg ! endif ! if error ! Xpath 1073741824 " X: 0 ! endif ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! ! if exists("var1") || exists("var2") || exists("var3") || ! \ !exists("var4") || var4 != 4711 ! " The Xpath command does not accept 2^31 (negative); add explicitly: ! let Xpath = Xpath + 2147483648 " X: 0 ! if exists("var1") ! Xout "var1 =" var1 ! endif ! if exists("var2") ! Xout "var2 =" var2 ! endif ! if exists("var3") ! Xout "var3 =" var3 ! endif ! if !exists("var4") ! Xout "var4 unset" ! elseif var4 != 4711 ! Xout "var4 =" var4 ! endif ! endif ! ! unlet! error var1 var2 var3 var4 ! delfunction THROW ! delfunction NAME ! delfunction ARG ! delfunction F ! ! Xcheck 212514423 ! ! " Tests 69 to 75 were moved to test_trycatch.vim ! let Xtest = 76 ! ! ! "------------------------------------------------------------------------------- ! " Test 76: Errors, interrupts, :throw during expression evaluation {{{1 ! " ! " When a function call made during expression evaluation is aborted ! " due to an error inside a :try/:endtry region or due to an interrupt ! " or a :throw, the expression evaluation is aborted as well. No ! " message is displayed for the cancelled expression evaluation. On an ! " error not inside :try/:endtry, the expression evaluation continues. ! "------------------------------------------------------------------------------- ! ! XpathINIT ! ! if ExtraVim() ! ! let taken = "" ! ! function! ERR(n) ! let g:taken = g:taken . "E" . a:n ! asdf ! endfunction ! ! function! ERRabort(n) abort ! let g:taken = g:taken . "A" . a:n ! asdf ! endfunction " returns -1; may cause follow-up msg for illegal var/func name ! ! function! WRAP(n, arg) ! let g:taken = g:taken . "W" . a:n ! let g:saved_errmsg = v:errmsg ! return arg ! endfunction ! ! function! INT(n) ! let g:taken = g:taken . "I" . a:n ! "INTERRUPT9 ! let dummy = 0 ! endfunction ! ! function! THR(n) ! let g:taken = g:taken . "T" . a:n ! throw "should not be caught" ! endfunction ! ! function! CONT(n) ! let g:taken = g:taken . "C" . a:n ! endfunction ! ! function! MSG(n) ! let g:taken = g:taken . "M" . a:n ! let errmsg = (a:n >= 37 && a:n <= 44) ? g:saved_errmsg : v:errmsg ! let msgptn = (a:n >= 10 && a:n <= 27) ? "^$" : "asdf" ! if errmsg !~ msgptn ! let g:taken = g:taken . "x" ! Xout "Expr" a:n.": Unexpected message:" v:errmsg ! endif ! let v:errmsg = "" ! let g:saved_errmsg = "" ! endfunction ! ! let v:errmsg = "" ! ! try ! let t = 1 ! XloopINIT 1 2 ! while t <= 9 ! Xloop 1 " X: 511 ! try ! if t == 1 ! let v{ERR(t) + CONT(t)} = 0 ! elseif t == 2 ! let v{ERR(t) + CONT(t)} ! elseif t == 3 ! let var = exists('v{ERR(t) + CONT(t)}') ! elseif t == 4 ! unlet v{ERR(t) + CONT(t)} ! elseif t == 5 ! function F{ERR(t) + CONT(t)}() ! endfunction ! elseif t == 6 ! function F{ERR(t) + CONT(t)} ! elseif t == 7 ! let var = exists('*F{ERR(t) + CONT(t)}') ! elseif t == 8 ! delfunction F{ERR(t) + CONT(t)} ! elseif t == 9 ! let var = ERR(t) + CONT(t) ! endif ! catch /asdf/ ! " v:errmsg is not set when the error message is converted to an ! " exception. Set it to the original error message. ! let v:errmsg = substitute(v:exception, '^Vim:', '', "") ! catch /^Vim\((\a\+)\)\=:/ ! " An error exception has been thrown after the original error. ! let v:errmsg = "" ! finally ! call MSG(t) ! let t = t + 1 ! XloopNEXT ! continue " discard an aborting error ! endtry ! endwhile ! catch /.*/ ! Xpath 512 " X: 0 ! Xout v:exception "in" ExtraVimThrowpoint() ! endtry ! ! try ! let t = 10 ! XloopINIT 1024 2 ! while t <= 18 ! Xloop 1 " X: 1024 * 511 ! try ! if t == 10 ! let v{INT(t) + CONT(t)} = 0 ! elseif t == 11 ! let v{INT(t) + CONT(t)} ! elseif t == 12 ! let var = exists('v{INT(t) + CONT(t)}') ! elseif t == 13 ! unlet v{INT(t) + CONT(t)} ! elseif t == 14 ! function F{INT(t) + CONT(t)}() ! endfunction ! elseif t == 15 ! function F{INT(t) + CONT(t)} ! elseif t == 16 ! let var = exists('*F{INT(t) + CONT(t)}') ! elseif t == 17 ! delfunction F{INT(t) + CONT(t)} ! elseif t == 18 ! let var = INT(t) + CONT(t) ! endif ! catch /^Vim\((\a\+)\)\=:\(Interrupt\)\@!/ ! " An error exception has been triggered after the interrupt. ! let v:errmsg = substitute(v:exception, ! \ '^Vim\((\a\+)\)\=:', '', "") ! finally ! call MSG(t) ! let t = t + 1 ! XloopNEXT ! continue " discard interrupt ! endtry ! endwhile ! catch /.*/ ! Xpath 524288 " X: 0 ! Xout v:exception "in" ExtraVimThrowpoint() ! endtry ! ! try ! let t = 19 ! XloopINIT 1048576 2 ! while t <= 27 ! Xloop 1 " X: 1048576 * 511 ! try ! if t == 19 ! let v{THR(t) + CONT(t)} = 0 ! elseif t == 20 ! let v{THR(t) + CONT(t)} ! elseif t == 21 ! let var = exists('v{THR(t) + CONT(t)}') ! elseif t == 22 ! unlet v{THR(t) + CONT(t)} ! elseif t == 23 ! function F{THR(t) + CONT(t)}() ! endfunction ! elseif t == 24 ! function F{THR(t) + CONT(t)} ! elseif t == 25 ! let var = exists('*F{THR(t) + CONT(t)}') ! elseif t == 26 ! delfunction F{THR(t) + CONT(t)} ! elseif t == 27 ! let var = THR(t) + CONT(t) ! endif ! catch /^Vim\((\a\+)\)\=:/ ! " An error exception has been triggered after the :throw. ! let v:errmsg = substitute(v:exception, ! \ '^Vim\((\a\+)\)\=:', '', "") ! finally ! call MSG(t) ! let t = t + 1 ! XloopNEXT ! continue " discard exception ! endtry ! endwhile ! catch /.*/ ! Xpath 536870912 " X: 0 ! Xout v:exception "in" ExtraVimThrowpoint() ! endtry ! ! let v{ERR(28) + CONT(28)} = 0 ! call MSG(28) ! let v{ERR(29) + CONT(29)} ! call MSG(29) ! let var = exists('v{ERR(30) + CONT(30)}') ! call MSG(30) ! unlet v{ERR(31) + CONT(31)} ! call MSG(31) ! function F{ERR(32) + CONT(32)}() ! endfunction ! call MSG(32) ! function F{ERR(33) + CONT(33)} ! call MSG(33) ! let var = exists('*F{ERR(34) + CONT(34)}') ! call MSG(34) ! delfunction F{ERR(35) + CONT(35)} ! call MSG(35) ! let var = ERR(36) + CONT(36) ! call MSG(36) ! ! let saved_errmsg = "" ! ! let v{WRAP(37, ERRabort(37)) + CONT(37)} = 0 ! call MSG(37) ! let v{WRAP(38, ERRabort(38)) + CONT(38)} ! call MSG(38) ! let var = exists('v{WRAP(39, ERRabort(39)) + CONT(39)}') ! call MSG(39) ! unlet v{WRAP(40, ERRabort(40)) + CONT(40)} ! call MSG(40) ! function F{WRAP(41, ERRabort(41)) + CONT(41)}() ! endfunction ! call MSG(41) ! function F{WRAP(42, ERRabort(42)) + CONT(42)} ! call MSG(42) ! let var = exists('*F{WRAP(43, ERRabort(43)) + CONT(43)}') ! call MSG(43) ! delfunction F{WRAP(44, ERRabort(44)) + CONT(44)} ! call MSG(44) ! let var = ERRabort(45) + CONT(45) ! call MSG(45) ! ! Xpath 1073741824 " X: 1073741824 ! ! let expected = "" ! \ . "E1M1E2M2E3M3E4M4E5M5E6M6E7M7E8M8E9M9" ! \ . "I10M10I11M11I12M12I13M13I14M14I15M15I16M16I17M17I18M18" ! \ . "T19M19T20M20T21M21T22M22T23M23T24M24T25M25T26M26T27M27" ! \ . "E28C28M28E29C29M29E30C30M30E31C31M31E32C32M32E33C33M33" ! \ . "E34C34M34E35C35M35E36C36M36" ! \ . "A37W37C37M37A38W38C38M38A39W39C39M39A40W40C40M40A41W41C41M41" ! \ . "A42W42C42M42A43W43C43M43A44W44C44M44A45C45M45" ! ! if taken != expected ! " The Xpath command does not accept 2^31 (negative); display explicitly: ! exec "!echo 2147483648 >>" . g:ExtraVimResult ! " X: 0 ! Xout "'taken' is" taken "instead of" expected ! if substitute(taken, ! \ '\(.*\)E3C3M3x\(.*\)E30C30M30x\(.*\)A39C39M39x\(.*\)', ! \ '\1E3M3\2E30C30M30\3A39C39M39\4', ! \ "") == expected ! Xout "Is ++emsg_skip for var with expr_start non-NULL" ! \ "in f_exists ok?" ! endif ! endif ! ! unlet! v var saved_errmsg taken expected ! call delete(WA_t5) ! call delete(WA_t14) ! call delete(WA_t23) ! unlet! WA_t5 WA_t14 WA_t23 ! delfunction WA_t5 ! delfunction WA_t14 ! delfunction WA_t23 ! ! endif ! ! Xcheck 1610087935 ! ! ! "------------------------------------------------------------------------------- ! " Test 77: Errors, interrupts, :throw in name{brace-expression} {{{1 ! " ! " When a function call made during evaluation of an expression in ! " braces as part of a function name after ":function" is aborted due ! " to an error inside a :try/:endtry region or due to an interrupt or ! " a :throw, the expression evaluation is aborted as well, and the ! " function definition is ignored, skipping all commands to the ! " ":endfunction". On an error not inside :try/:endtry, the expression ! " evaluation continues and the function gets defined, and can be ! " called and deleted. ! "------------------------------------------------------------------------------- ! ! XpathINIT ! ! XloopINIT 1 4 ! ! function! ERR() abort ! Xloop 1 " X: 1 + 4 + 16 + 64 ! asdf ! endfunction " returns -1 ! ! function! OK() ! Xloop 2 " X: 2 * (1 + 4 + 16) ! let v:errmsg = "" ! return 0 ! endfunction ! ! let v:errmsg = "" ! ! Xpath 4096 " X: 4096 ! function! F{1 + ERR() + OK()}(arg) ! " F0 should be defined. ! if exists("a:arg") && a:arg == "calling" ! Xpath 8192 " X: 8192 ! else ! Xpath 16384 " X: 0 ! endif ! endfunction ! if v:errmsg != "" ! Xpath 32768 " X: 0 ! endif ! XloopNEXT ! ! Xpath 65536 " X: 65536 ! call F{1 + ERR() + OK()}("calling") ! if v:errmsg != "" ! Xpath 131072 " X: 0 ! endif ! XloopNEXT ! ! Xpath 262144 " X: 262144 ! delfunction F{1 + ERR() + OK()} ! if v:errmsg != "" ! Xpath 524288 " X: 0 ! endif ! XloopNEXT ! ! try ! while 1 ! let caught = 0 ! try ! Xpath 1048576 " X: 1048576 ! function! G{1 + ERR() + OK()}(arg) ! " G0 should not be defined, and the function body should be ! " skipped. ! if exists("a:arg") && a:arg == "calling" ! Xpath 2097152 " X: 0 ! else ! Xpath 4194304 " X: 0 ! endif ! " Use an unmatched ":finally" to check whether the body is ! " skipped when an error occurs in ERR(). This works whether or ! " not the exception is converted to an exception. ! finally ! Xpath 8388608 " X: 0 ! Xout "Body of G{1 + ERR() + OK()}() not skipped" ! " Discard the aborting error or exception, and break the ! " while loop. ! break ! " End the try conditional and start a new one to avoid ! " ":catch after :finally" errors. ! endtry ! try ! Xpath 16777216 " X: 0 ! endfunction ! ! " When the function was not defined, this won't be reached - whether ! " the body was skipped or not. When the function was defined, it ! " can be called and deleted here. ! Xpath 33554432 " X: 0 ! Xout "G0() has been defined" ! XloopNEXT ! try ! call G{1 + ERR() + OK()}("calling") ! catch /.*/ ! Xpath 67108864 " X: 0 ! endtry ! Xpath 134217728 " X: 0 ! XloopNEXT ! try ! delfunction G{1 + ERR() + OK()} ! catch /.*/ ! Xpath 268435456 " X: 0 ! endtry ! catch /asdf/ ! " Jumped to when the function is not defined and the body is ! " skipped. ! let caught = 1 ! catch /.*/ ! Xpath 536870912 " X: 0 ! finally ! if !caught && !$VIMNOERRTHROW ! Xpath 1073741824 " X: 0 ! endif ! break " discard error for $VIMNOERRTHROW ! endtry " jumped to when the body is not skipped ! endwhile ! catch /.*/ ! " The Xpath command does not accept 2^31 (negative); add explicitly: ! let Xpath = Xpath + 2147483648 " X: 0 ! Xout "Body of G{1 + ERR() + OK()}() not skipped, exception caught" ! Xout v:exception "in" v:throwpoint ! endtry ! ! Xcheck 1388671 ! ! ! "------------------------------------------------------------------------------- ! " Test 78: Messages on parsing errors in expression evaluation {{{1 ! " ! " When an expression evaluation detects a parsing error, an error ! " message is given and converted to an exception, and the expression ! " evaluation is aborted. ! "------------------------------------------------------------------------------- ! ! XpathINIT ! ! if ExtraVim() ! ! let taken = "" ! ! function! F(n) ! let g:taken = g:taken . "F" . a:n ! endfunction ! ! function! MSG(n, enr, emsg) ! let g:taken = g:taken . "M" . a:n ! 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 ! if v:errmsg !~ '^'.a:enr.':' || (english && v:errmsg !~ a:emsg) ! if v:errmsg == "" ! Xout "Expr" a:n.": Message missing." ! let g:taken = g:taken . "x" ! else ! let v:errmsg = escape(v:errmsg, '"') ! Xout "Expr" a:n.": Unexpected message:" v:errmsg ! Xout "Expected: " . a:enr . ': ' . a:emsg ! let g:taken = g:taken . "X" ! endif ! endif ! endfunction ! ! function! CONT(n) ! let g:taken = g:taken . "C" . a:n ! endfunction ! ! let v:errmsg = "" ! XloopINIT 1 2 ! ! try ! let t = 1 ! while t <= 14 ! let g:taken = g:taken . "T" . t ! let v:errmsg = "" ! try ! let caught = 0 ! if t == 1 ! let v{novar + CONT(t)} = 0 ! elseif t == 2 ! let v{novar + CONT(t)} ! elseif t == 3 ! let var = exists('v{novar + CONT(t)}') ! elseif t == 4 ! unlet v{novar + CONT(t)} ! elseif t == 5 ! function F{novar + CONT(t)}() ! endfunction ! elseif t == 6 ! function F{novar + CONT(t)} ! elseif t == 7 ! let var = exists('*F{novar + CONT(t)}') ! elseif t == 8 ! delfunction F{novar + CONT(t)} ! elseif t == 9 ! echo novar + CONT(t) ! elseif t == 10 ! echo v{novar + CONT(t)} ! elseif t == 11 ! echo F{novar + CONT(t)} ! elseif t == 12 ! let var = novar + CONT(t) ! elseif t == 13 ! let var = v{novar + CONT(t)} ! elseif t == 14 ! let var = F{novar + CONT(t)}() ! endif ! catch /^Vim\((\a\+)\)\=:/ ! " v:errmsg is not set when the error message is converted to an ! " exception. Set it to the original error message. ! let v:errmsg = substitute(v:exception, ! \ '^Vim\((\a\+)\)\=:', '', "") ! let caught = 1 ! finally ! if t <= 8 && t != 3 && t != 7 ! call MSG(t, 'E475', 'Invalid argument\>') ! else ! if !caught " no error exceptions ($VIMNOERRTHROW set) ! call MSG(t, 'E15', "Invalid expression") ! else ! call MSG(t, 'E121', "Undefined variable") ! endif ! endif ! let t = t + 1 ! XloopNEXT ! continue " discard an aborting error ! endtry ! endwhile ! catch /.*/ ! Xloop 1 " X: 0 ! Xout t.":" v:exception "in" ExtraVimThrowpoint() ! endtry ! ! function! T(n, expr, enr, emsg) ! try ! let g:taken = g:taken . "T" . a:n ! let v:errmsg = "" ! try ! let caught = 0 ! execute "let var = " . a:expr ! catch /^Vim\((\a\+)\)\=:/ ! " v:errmsg is not set when the error message is converted to an ! " exception. Set it to the original error message. ! let v:errmsg = substitute(v:exception, ! \ '^Vim\((\a\+)\)\=:', '', "") ! let caught = 1 ! finally ! if !caught " no error exceptions ($VIMNOERRTHROW set) ! call MSG(a:n, 'E15', "Invalid expression") ! else ! call MSG(a:n, a:enr, a:emsg) ! endif ! XloopNEXT ! " Discard an aborting error: ! return ! endtry ! catch /.*/ ! Xloop 1 " X: 0 ! Xout a:n.":" v:exception "in" ExtraVimThrowpoint() ! endtry ! endfunction ! ! call T(15, 'Nofunc() + CONT(15)', 'E117', "Unknown function") ! call T(16, 'F(1 2 + CONT(16))', 'E116', "Invalid arguments") ! call T(17, 'F(1, 2) + CONT(17)', 'E118', "Too many arguments") ! call T(18, 'F() + CONT(18)', 'E119', "Not enough arguments") ! call T(19, '{(1} + CONT(19)', 'E110', "Missing ')'") ! call T(20, '("abc"[1) + CONT(20)', 'E111', "Missing ']'") ! call T(21, '(1 +) + CONT(21)', 'E15', "Invalid expression") ! call T(22, '1 2 + CONT(22)', 'E15', "Invalid expression") ! call T(23, '(1 ? 2) + CONT(23)', 'E109', "Missing ':' after '?'") ! call T(24, '("abc) + CONT(24)', 'E114', "Missing quote") ! call T(25, "('abc) + CONT(25)", 'E115', "Missing quote") ! call T(26, '& + CONT(26)', 'E112', "Option name missing") ! call T(27, '&asdf + CONT(27)', 'E113', "Unknown option") ! ! Xpath 134217728 " X: 134217728 ! ! let expected = "" ! \ . "T1M1T2M2T3M3T4M4T5M5T6M6T7M7T8M8T9M9T10M10T11M11T12M12T13M13T14M14" ! \ . "T15M15T16M16T17M17T18M18T19M19T20M20T21M21T22M22T23M23T24M24T25M25" ! \ . "T26M26T27M27" ! ! if taken != expected ! Xpath 268435456 " X: 0 ! Xout "'taken' is" taken "instead of" expected ! if substitute(taken, '\(.*\)T3M3x\(.*\)', '\1T3M3\2', "") == expected ! Xout "Is ++emsg_skip for var with expr_start non-NULL" ! \ "in f_exists ok?" ! endif ! endif ! ! unlet! var caught taken expected ! call delete(WA_t5) ! unlet! WA_t5 ! delfunction WA_t5 ! ! endif ! ! Xcheck 134217728 ! ! ! "------------------------------------------------------------------------------- ! " Test 79: Throwing one of several errors for the same command {{{1 ! " ! " When several errors appear in a row (for instance during expression ! " evaluation), the first as the most specific one is used when ! " throwing an error exception. If, however, a syntax error is ! " detected afterwards, this one is used for the error exception. ! " On a syntax error, the next command is not executed, on a normal ! " error, however, it is (relevant only in a function without the ! " "abort" flag). v:errmsg is not set. ! " ! " If throwing error exceptions is configured off, v:errmsg is always ! " set to the latest error message, that is, to the more general ! " message or the syntax error, respectively. ! "------------------------------------------------------------------------------- ! ! XpathINIT ! ! XloopINIT 1 2 ! ! function! NEXT(cmd) ! exec a:cmd . " | Xloop 1" ! endfunction ! ! call NEXT('echo novar') " X: 1 * 1 (checks nextcmd) ! XloopNEXT ! call NEXT('let novar #') " X: 0 * 2 (skips nextcmd) ! XloopNEXT ! call NEXT('unlet novar #') " X: 0 * 4 (skips nextcmd) ! XloopNEXT ! call NEXT('let {novar}') " X: 0 * 8 (skips nextcmd) ! XloopNEXT ! call NEXT('unlet{ novar}') " X: 0 * 16 (skips nextcmd) ! ! function! EXEC(cmd) ! exec a:cmd ! endfunction ! ! function! MATCH(expected, msg, enr, emsg) ! let msg = a:msg ! if a:enr == "" ! Xout "TODO: Add message number for:" a:emsg ! let msg = ":" . msg ! endif ! let english = v:lang == "C" || v:lang =~ '^[Ee]n' ! if msg !~ '^'.a:enr.':' || (english && msg !~ a:emsg) ! let match = 0 ! if a:expected " no match although expected ! if a:msg == "" ! Xout "Message missing." ! else ! let msg = escape(msg, '"') ! Xout "Unexpected message:" msg ! Xout "Expected:" a:enr . ": " . a:emsg ! endif ! endif ! else ! let match = 1 ! if !a:expected " match although not expected ! let msg = escape(msg, '"') ! Xout "Unexpected message:" msg ! Xout "Expected none." ! endif ! endif ! return match ! endfunction ! ! try ! ! while 1 " dummy loop ! try ! let v:errmsg = "" ! let caught = 0 ! let thrmsg = "" ! call EXEC('echo novar') " normal error ! catch /^Vim\((\a\+)\)\=:/ ! let caught = 1 ! let thrmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "") ! finally ! Xpath 32 " X: 32 ! if !caught ! if !$VIMNOERRTHROW ! Xpath 64 " X: 0 ! endif ! elseif !MATCH(1, thrmsg, 'E121', "Undefined variable") ! \ || v:errmsg != "" ! Xpath 128 " X: 0 ! endif ! if !caught && !MATCH(1, v:errmsg, 'E15', "Invalid expression") ! Xpath 256 " X: 0 ! endif ! break " discard error if $VIMNOERRTHROW == 1 ! endtry ! endwhile ! ! Xpath 512 " X: 512 ! let cmd = "let" ! XloopINIT 1024 32 ! while cmd != "" ! try ! let v:errmsg = "" ! let caught = 0 ! let thrmsg = "" ! call EXEC(cmd . ' novar #') " normal plus syntax error ! catch /^Vim\((\a\+)\)\=:/ ! let caught = 1 ! let thrmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "") ! finally ! Xloop 1 " X: 1024 * (1 + 32) ! if !caught ! if !$VIMNOERRTHROW ! Xloop 2 " X: 0 ! endif ! else ! if cmd == "let" ! let match = MATCH(0, thrmsg, 'E121', "Undefined variable") ! elseif cmd == "unlet" ! let match = MATCH(0, thrmsg, 'E108', "No such variable") ! endif ! if match " normal error ! Xloop 4 " X: 0 ! endif ! if !MATCH(1, thrmsg, 'E488', "Trailing characters") ! \|| v:errmsg != "" ! " syntax error ! Xloop 8 " X: 0 ! endif ! endif ! if !caught && !MATCH(1, v:errmsg, 'E488', "Trailing characters") ! " last error ! Xloop 16 " X: 0 ! endif ! if cmd == "let" ! let cmd = "unlet" ! else ! let cmd = "" ! endif ! XloopNEXT ! continue " discard error if $VIMNOERRTHROW == 1 ! endtry ! endwhile ! ! Xpath 1048576 " X: 1048576 ! let cmd = "let" ! XloopINIT 2097152 32 ! while cmd != "" ! try ! let v:errmsg = "" ! let caught = 0 ! let thrmsg = "" ! call EXEC(cmd . ' {novar}') " normal plus syntax error ! catch /^Vim\((\a\+)\)\=:/ ! let caught = 1 ! let thrmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "") ! finally ! Xloop 1 " X: 2097152 * (1 + 32) ! if !caught ! if !$VIMNOERRTHROW ! Xloop 2 " X: 0 ! endif ! else ! if MATCH(0, thrmsg, 'E121', "Undefined variable") " normal error ! Xloop 4 " X: 0 ! endif ! if !MATCH(1, thrmsg, 'E475', 'Invalid argument\>') ! \ || v:errmsg != "" " syntax error ! Xloop 8 " X: 0 ! endif ! endif ! if !caught && !MATCH(1, v:errmsg, 'E475', 'Invalid argument\>') ! " last error ! Xloop 16 " X: 0 ! endif ! if cmd == "let" ! let cmd = "unlet" ! else ! let cmd = "" ! endif ! XloopNEXT ! continue " discard error if $VIMNOERRTHROW == 1 ! endtry ! endwhile ! ! catch /.*/ ! " The Xpath command does not accept 2^31 (negative); add explicitly: ! let Xpath = Xpath + 2147483648 " X: 0 ! Xout v:exception "in" v:throwpoint ! endtry ! ! unlet! next_command thrmsg match ! delfunction NEXT ! delfunction EXEC ! delfunction MATCH ! ! Xcheck 70288929 ! ! ! "------------------------------------------------------------------------------- ! " Test 80: Syntax error in expression for illegal :elseif {{{1 ! " ! " If there is a syntax error in the expression after an illegal ! " :elseif, an error message is given (or an error exception thrown) ! " for the illegal :elseif rather than the expression error. ! "------------------------------------------------------------------------------- ! ! XpathINIT ! ! function! 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 = escape(v:errmsg, '"') ! Xout "Unexpected message:" v:errmsg ! endif ! endif ! return match ! endfunction ! ! let v:errmsg = "" ! if 0 ! else ! elseif 1 ||| 2 ! endif ! Xpath 1 " X: 1 ! if !MSG('E584', ":elseif after :else") ! Xpath 2 " X: 0 ! endif ! ! let v:errmsg = "" ! if 1 ! else ! elseif 1 ||| 2 ! endif ! Xpath 4 " X: 4 ! if !MSG('E584', ":elseif after :else") ! Xpath 8 " X: 0 ! endif ! ! let v:errmsg = "" ! elseif 1 ||| 2 ! Xpath 16 " X: 16 ! if !MSG('E582', ":elseif without :if") ! Xpath 32 " X: 0 ! endif ! ! let v:errmsg = "" ! while 1 ! elseif 1 ||| 2 ! endwhile ! Xpath 64 " X: 64 ! if !MSG('E582', ":elseif without :if") ! Xpath 128 " X: 0 ! endif ! ! while 1 ! try ! try ! let v:errmsg = "" ! let caught = 0 ! if 0 ! else ! elseif 1 ||| 2 ! endif ! catch /^Vim\((\a\+)\)\=:/ ! let caught = 1 ! let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "") ! finally ! Xpath 256 " X: 256 ! if !caught && !$VIMNOERRTHROW ! Xpath 512 " X: 0 ! endif ! if !MSG('E584', ":elseif after :else") ! Xpath 1024 " X: 0 ! endif ! endtry ! catch /.*/ ! Xpath 2048 " X: 0 ! Xout v:exception "in" v:throwpoint ! finally ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! ! while 1 ! try ! try ! let v:errmsg = "" ! let caught = 0 ! if 1 ! else ! elseif 1 ||| 2 ! endif ! catch /^Vim\((\a\+)\)\=:/ ! let caught = 1 ! let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "") ! finally ! Xpath 4096 " X: 4096 ! if !caught && !$VIMNOERRTHROW ! Xpath 8192 " X: 0 ! endif ! if !MSG('E584', ":elseif after :else") ! Xpath 16384 " X: 0 ! endif ! endtry ! catch /.*/ ! Xpath 32768 " X: 0 ! Xout v:exception "in" v:throwpoint ! finally ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! ! while 1 ! try ! try ! let v:errmsg = "" ! let caught = 0 ! elseif 1 ||| 2 ! catch /^Vim\((\a\+)\)\=:/ ! let caught = 1 ! let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "") ! finally ! Xpath 65536 " X: 65536 ! if !caught && !$VIMNOERRTHROW ! Xpath 131072 " X: 0 ! endif ! if !MSG('E582', ":elseif without :if") ! Xpath 262144 " X: 0 ! endif ! endtry ! catch /.*/ ! Xpath 524288 " X: 0 ! Xout v:exception "in" v:throwpoint ! finally ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! ! while 1 ! try ! try ! let v:errmsg = "" ! let caught = 0 ! while 1 ! elseif 1 ||| 2 ! endwhile ! catch /^Vim\((\a\+)\)\=:/ ! let caught = 1 ! let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "") ! finally ! Xpath 1048576 " X: 1048576 ! if !caught && !$VIMNOERRTHROW ! Xpath 2097152 " X: 0 ! endif ! if !MSG('E582', ":elseif without :if") ! Xpath 4194304 " X: 0 ! endif ! endtry ! catch /.*/ ! Xpath 8388608 " X: 0 ! Xout v:exception "in" v:throwpoint ! finally ! break " discard error for $VIMNOERRTHROW ! endtry ! endwhile ! ! Xpath 16777216 " X: 16777216 ! ! unlet! caught ! delfunction MSG ! ! Xcheck 17895765 ! ! ! "------------------------------------------------------------------------------- ! " Test 81: Discarding exceptions after an error or interrupt {{{1 ! " ! " When an exception is thrown from inside a :try conditional without ! " :catch and :finally clauses and an error or interrupt occurs before ! " the :endtry is reached, the exception is discarded. ! "------------------------------------------------------------------------------- ! ! XpathINIT ! ! if ExtraVim() ! try ! Xpath 1 " X: 1 ! try ! Xpath 2 " X: 2 ! throw "arrgh" ! Xpath 4 " X: 0 ! " if 1 ! Xpath 8 " X: 0 ! " error after :throw: missing :endif ! endtry ! Xpath 16 " X: 0 ! catch /arrgh/ ! Xpath 32 " X: 0 ! endtry ! Xpath 64 " X: 0 ! endif ! ! if ExtraVim() ! try ! Xpath 128 " X: 128 ! try ! Xpath 256 " X: 256 ! throw "arrgh" ! Xpath 512 " X: 0 ! endtry " INTERRUPT ! Xpath 1024 " X: 0 ! catch /arrgh/ ! Xpath 2048 " X: 0 ! endtry ! Xpath 4096 " X: 0 ! endif ! ! Xcheck 387 ! "------------------------------------------------------------------------------- " Test 82: Ignoring :catch clauses after an error or interrupt {{{1 --- 648,658 ---- return match endfunction ! " Following tests were moved to test_vimscript.vim: ! " 1-24, 27-31, 34-40, 49-50, 52-68, 76-81, 87 ! " Following tests were moved to test_trycatch.vim: ! " 25-26, 32-33, 41-48, 51, 69-75 ! let Xtest = 82 "------------------------------------------------------------------------------- " Test 82: Ignoring :catch clauses after an error or interrupt {{{1 *** ../vim-8.2.1416/src/testdir/test_vimscript.vim 2020-08-07 16:49:06.425905234 +0200 --- src/testdir/test_vimscript.vim 2020-08-10 22:13:55.871239529 +0200 *************** *** 23,28 **** --- 23,29 ---- " file. If the test passes successfully, then Xtest.out should be empty. func RunInNewVim(test, verify) let init =<< trim END + set cpo-=C " support line-continuation in sourced script source script_util.vim XpathINIT XloopINIT *************** *** 3720,3725 **** --- 3721,4101 ---- endfunc "------------------------------------------------------------------------------- + " + " Test 59: v:exception and v:throwpoint when discarding exceptions {{{1 + " + " When a :catch clause is left by a ":break" etc or an error or + " interrupt exception, v:exception and v:throwpoint are reset. They + " are not affected by an exception that is discarded before being + " caught. + "------------------------------------------------------------------------------- + func Test_exception_info_on_discard() + CheckEnglish + + let test =<< trim [CODE] + let sfile = expand("") + + while 1 + try + throw "x1" + catch /.*/ + break + endtry + endwhile + call assert_equal('', v:exception) + call assert_equal('', v:throwpoint) + + while 1 + try + throw "x2" + catch /.*/ + break + finally + call assert_equal('', v:exception) + call assert_equal('', v:throwpoint) + endtry + break + endwhile + call assert_equal('', v:exception) + call assert_equal('', v:throwpoint) + + while 1 + try + let errcaught = 0 + try + try + throw "x3" + catch /.*/ + let lnum = expand("") + asdf + endtry + catch /.*/ + let errcaught = 1 + call assert_match('Vim:E492: Not an editor command:', v:exception) + call assert_match('line ' .. (lnum + 1), v:throwpoint) + endtry + finally + call assert_equal(1, errcaught) + break + endtry + endwhile + call assert_equal('', v:exception) + call assert_equal('', v:throwpoint) + + Xpath 'a' + + while 1 + try + let intcaught = 0 + try + try + throw "x4" + catch /.*/ + let lnum = expand("") + call interrupt() + endtry + catch /.*/ + let intcaught = 1 + call assert_match('Vim:Interrupt', v:exception) + call assert_match('line ' .. (lnum + 1), v:throwpoint) + endtry + finally + call assert_equal(1, intcaught) + break + endtry + endwhile + call assert_equal('', v:exception) + call assert_equal('', v:throwpoint) + + Xpath 'b' + + while 1 + try + let errcaught = 0 + try + try + if 1 + let lnum = expand("") + throw "x5" + " missing endif + catch /.*/ + call assert_report('should not get here') + endtry + catch /.*/ + let errcaught = 1 + call assert_match('Vim(catch):E171: Missing :endif:', v:exception) + call assert_match('line ' .. (lnum + 3), v:throwpoint) + endtry + finally + call assert_equal(1, errcaught) + break + endtry + endwhile + call assert_equal('', v:exception) + call assert_equal('', v:throwpoint) + + Xpath 'c' + + try + while 1 + try + throw "x6" + finally + break + endtry + break + endwhile + catch /.*/ + call assert_report('should not get here') + endtry + call assert_equal('', v:exception) + call assert_equal('', v:throwpoint) + + try + while 1 + try + throw "x7" + finally + break + endtry + break + endwhile + catch /.*/ + call assert_report('should not get here') + finally + call assert_equal('', v:exception) + call assert_equal('', v:throwpoint) + endtry + call assert_equal('', v:exception) + call assert_equal('', v:throwpoint) + + while 1 + try + let errcaught = 0 + try + try + throw "x8" + finally + let lnum = expand("") + asdf + endtry + catch /.*/ + let errcaught = 1 + call assert_match('Vim:E492: Not an editor command:', v:exception) + call assert_match('line ' .. (lnum + 1), v:throwpoint) + endtry + finally + call assert_equal(1, errcaught) + break + endtry + endwhile + call assert_equal('', v:exception) + call assert_equal('', v:throwpoint) + + Xpath 'd' + + while 1 + try + let intcaught = 0 + try + try + throw "x9" + finally + let lnum = expand("") + call interrupt() + endtry + catch /.*/ + let intcaught = 1 + call assert_match('Vim:Interrupt', v:exception) + call assert_match('line ' .. (lnum + 1), v:throwpoint) + endtry + finally + call assert_equal(1, intcaught) + break + endtry + endwhile + call assert_equal('', v:exception) + call assert_equal('', v:throwpoint) + + Xpath 'e' + + while 1 + try + let errcaught = 0 + try + try + if 1 + let lnum = expand("") + throw "x10" + " missing endif + finally + call assert_equal('', v:exception) + call assert_equal('', v:throwpoint) + endtry + catch /.*/ + let errcaught = 1 + call assert_match('Vim(finally):E171: Missing :endif:', v:exception) + call assert_match('line ' .. (lnum + 3), v:throwpoint) + endtry + finally + call assert_equal(1, errcaught) + break + endtry + endwhile + call assert_equal('', v:exception) + call assert_equal('', v:throwpoint) + + Xpath 'f' + + while 1 + try + let errcaught = 0 + try + try + if 1 + let lnum = expand("") + throw "x11" + " missing endif + endtry + catch /.*/ + let errcaught = 1 + call assert_match('Vim(endtry):E171: Missing :endif:', v:exception) + call assert_match('line ' .. (lnum + 3), v:throwpoint) + endtry + finally + call assert_equal(1, errcaught) + break + endtry + endwhile + call assert_equal('', v:exception) + call assert_equal('', v:throwpoint) + + Xpath 'g' + [CODE] + let verify =<< trim [CODE] + call assert_equal('abcdefg', g:Xpath) + [CODE] + call RunInNewVim(test, verify) + endfunc + + "------------------------------------------------------------------------------- + " + " Test 60: (Re)throwing v:exception; :echoerr. {{{1 + " + " A user exception can be rethrown after catching by throwing + " v:exception. An error or interrupt exception cannot be rethrown + " because Vim exceptions cannot be faked. A Vim exception using the + " value of v:exception can, however, be triggered by the :echoerr + " command. + "------------------------------------------------------------------------------- + + func Test_rethrow_exception_1() + XpathINIT + try + try + Xpath 'a' + throw "oops" + catch /oops/ + Xpath 'b' + throw v:exception " rethrow user exception + catch /.*/ + call assert_report('should not get here') + endtry + catch /^oops$/ " catches rethrown user exception + Xpath 'c' + catch /.*/ + call assert_report('should not get here') + endtry + call assert_equal('abc', g:Xpath) + endfunc + + func Test_rethrow_exception_2() + XpathINIT + try + let caught = 0 + try + Xpath 'a' + write /n/o/n/w/r/i/t/a/b/l/e/_/f/i/l/e + call assert_report('should not get here') + catch /^Vim(write):/ + let caught = 1 + throw v:exception " throw error: cannot fake Vim exception + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'b' + call assert_equal(1, caught) + endtry + catch /^Vim(throw):/ " catches throw error + let caught = caught + 1 + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'c' + call assert_equal(2, caught) + endtry + call assert_equal('abc', g:Xpath) + endfunc + + func Test_rethrow_exception_3() + XpathINIT + try + let caught = 0 + try + Xpath 'a' + asdf + catch /^Vim/ " catch error exception + let caught = 1 + " Trigger Vim error exception with value specified after :echoerr + let value = substitute(v:exception, '^Vim\((.*)\)\=:', '', "") + echoerr value + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'b' + call assert_equal(1, caught) + endtry + catch /^Vim(echoerr):/ + let caught = caught + 1 + call assert_match(value, v:exception) + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'c' + call assert_equal(2, caught) + endtry + call assert_equal('abc', g:Xpath) + endfunc + + func Test_rethrow_exception_3() + XpathINIT + try + let errcaught = 0 + try + Xpath 'a' + let intcaught = 0 + call interrupt() + catch /^Vim:/ " catch interrupt exception + let intcaught = 1 + " Trigger Vim error exception with value specified after :echoerr + echoerr substitute(v:exception, '^Vim\((.*)\)\=:', '', "") + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'b' + call assert_equal(1, intcaught) + endtry + catch /^Vim(echoerr):/ + let errcaught = 1 + call assert_match('Interrupt', v:exception) + finally + Xpath 'c' + call assert_equal(1, errcaught) + endtry + call assert_equal('abc', g:Xpath) + endfunc + + "------------------------------------------------------------------------------- " Test 61: Catching interrupt exceptions {{{1 " " When an interrupt occurs inside a :try/:endtry region, an *************** *** 3846,3851 **** --- 4222,4734 ---- endfunc "------------------------------------------------------------------------------- + " Test 62: Catching error exceptions {{{1 + " + " An error inside a :try/:endtry region is converted to an exception + " and can be caught. The error exception has a "Vim(cmdname):" prefix + " where cmdname is the name of the failing command, or a "Vim:" prefix + " if no command name is known. The "Vim" prefixes cannot be faked. + "------------------------------------------------------------------------------- + + func Test_catch_err_exception_1() + XpathINIT + while 1 + try + try + let caught = 0 + unlet novar + catch /^Vim(unlet):/ + Xpath 'a' + let caught = 1 + let v:errmsg = substitute(v:exception, '^Vim(unlet):', '', "") + finally + Xpath 'b' + call assert_equal(1, caught) + call assert_match('E108: No such variable: "novar"', v:errmsg) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'c' + break + endtry + call assert_report('should not get here') + endwhile + call assert_equal('abc', g:Xpath) + endfunc + + func Test_catch_err_exception_2() + XpathINIT + while 1 + try + try + let caught = 0 + throw novar " error in :throw + catch /^Vim(throw):/ + Xpath 'a' + let caught = 1 + let v:errmsg = substitute(v:exception, '^Vim(throw):', '', "") + finally + Xpath 'b' + call assert_equal(1, caught) + call assert_match('E121: Undefined variable: novar', v:errmsg) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'c' + break + endtry + call assert_report('should not get here') + endwhile + call assert_equal('abc', g:Xpath) + endfunc + + func Test_catch_err_exception_3() + XpathINIT + while 1 + try + try + let caught = 0 + throw "Vim:faked" " error: cannot fake Vim exception + catch /^Vim(throw):/ + Xpath 'a' + let caught = 1 + let v:errmsg = substitute(v:exception, '^Vim(throw):', '', "") + finally + Xpath 'b' + call assert_equal(1, caught) + call assert_match("E608: Cannot :throw exceptions with 'Vim' prefix", + \ v:errmsg) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'c' + break + endtry + call assert_report('should not get here') + endwhile + call assert_equal('abc', g:Xpath) + endfunc + + func Test_catch_err_exception_4() + XpathINIT + func F() + while 1 + " Missing :endwhile + endfunc + + while 1 + try + try + let caught = 0 + call F() + catch /^Vim(endfunction):/ + Xpath 'a' + let caught = 1 + let v:errmsg = substitute(v:exception, '^Vim(endfunction):', '', "") + finally + Xpath 'b' + call assert_equal(1, caught) + call assert_match("E170: Missing :endwhile", v:errmsg) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'c' + break + endtry + call assert_report('should not get here') + endwhile + call assert_equal('abc', g:Xpath) + delfunc F + endfunc + + func Test_catch_err_exception_5() + XpathINIT + func F() + while 1 + " Missing :endwhile + endfunc + + while 1 + try + try + let caught = 0 + ExecAsScript F + catch /^Vim:/ + Xpath 'a' + let caught = 1 + let v:errmsg = substitute(v:exception, '^Vim:', '', "") + finally + Xpath 'b' + call assert_equal(1, caught) + call assert_match("E170: Missing :endwhile", v:errmsg) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'c' + break + endtry + call assert_report('should not get here') + endwhile + call assert_equal('abc', g:Xpath) + delfunc F + endfunc + + func Test_catch_err_exception_6() + XpathINIT + func G() + call G() + endfunc + + while 1 + try + let mfd_save = &mfd + set mfd=3 + try + let caught = 0 + call G() + catch /^Vim(call):/ + Xpath 'a' + let caught = 1 + let v:errmsg = substitute(v:exception, '^Vim(call):', '', "") + finally + Xpath 'b' + call assert_equal(1, caught) + call assert_match("E132: Function call depth is higher than 'maxfuncdepth'", v:errmsg) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'c' + let &mfd = mfd_save + break + endtry + call assert_report('should not get here') + endwhile + call assert_equal('abc', g:Xpath) + delfunc G + endfunc + + func Test_catch_err_exception_7() + XpathINIT + func H() + return H() + endfunc + + while 1 + try + let mfd_save = &mfd + set mfd=3 + try + let caught = 0 + call H() + catch /^Vim(return):/ + Xpath 'a' + let caught = 1 + let v:errmsg = substitute(v:exception, '^Vim(return):', '', "") + finally + Xpath 'b' + call assert_equal(1, caught) + call assert_match("E132: Function call depth is higher than 'maxfuncdepth'", v:errmsg) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'c' + let &mfd = mfd_save + break " discard error for $VIMNOERRTHROW + endtry + call assert_report('should not get here') + endwhile + + call assert_equal('abc', g:Xpath) + delfunc H + endfunc + + "------------------------------------------------------------------------------- + " Test 63: Suppressing error exceptions by :silent!. {{{1 + " + " A :silent! command inside a :try/:endtry region suppresses the + " conversion of errors to an exception and the immediate abortion on + " error. When the commands executed by the :silent! themselves open + " a new :try/:endtry region, conversion of errors to exception and + " immediate abortion is switched on again - until the next :silent! + " etc. The :silent! has the effect of setting v:errmsg to the error + " message text (without displaying it) and continuing with the next + " script line. + " + " When a command triggering autocommands is executed by :silent! + " inside a :try/:endtry, the autocommand execution is not suppressed + " on error. + " + " This test reuses the function MSG() from the previous test. + "------------------------------------------------------------------------------- + + func Test_silent_exception() + XpathINIT + XloopINIT + let g:taken = "" + + func S(n) abort + XloopNEXT + let g:taken = g:taken . "E" . a:n + let v:errmsg = "" + exec "asdf" . a:n + + " Check that ":silent!" continues: + Xloop 'a' + + " Check that ":silent!" sets "v:errmsg": + call assert_match("E492: Not an editor command", v:errmsg) + endfunc + + func Foo() + while 1 + try + try + let caught = 0 + " This is not silent: + call S(3) + catch /^Vim:/ + Xpath 'b' + let caught = 1 + let errmsg3 = substitute(v:exception, '^Vim:', '', "") + silent! call S(4) + finally + call assert_equal(1, caught) + Xpath 'c' + call assert_match("E492: Not an editor command", errmsg3) + silent! call S(5) + " Break out of try conditionals that cover ":silent!". This also + " discards the aborting error when $VIMNOERRTHROW is non-zero. + break + endtry + catch /.*/ + call assert_report('should not get here') + endtry + endwhile + " This is a double ":silent!" (see caller). + silent! call S(6) + endfunc + + func Bar() + try + silent! call S(2) + silent! execute "call Foo() | call S(7)" + silent! call S(8) + endtry " normal end of try cond that covers ":silent!" + " This has a ":silent!" from the caller: + call S(9) + endfunc + + silent! call S(1) + silent! call Bar() + silent! call S(10) + + call assert_equal("E1E2E3E4E5E6E7E8E9E10", g:taken) + + augroup TMP + au! + autocmd BufWritePost * Xpath 'd' + augroup END + + Xpath 'e' + silent! write /i/m/p/o/s/s/i/b/l/e + Xpath 'f' + + call assert_equal('a2a3ba5ca6a7a8a9a10a11edf', g:Xpath) + + augroup TMP + au! + augroup END + augroup! TMP + delfunction S + delfunction Foo + delfunction Bar + endfunc + + "------------------------------------------------------------------------------- + " Test 64: Error exceptions after error, interrupt or :throw {{{1 + " + " When an error occurs after an interrupt or a :throw but before + " a matching :catch is reached, all following :catches of that try + " block are ignored, but the error exception can be caught by the next + " surrounding try conditional. Any previous error exception is + " discarded. An error is ignored when there is a previous error that + " has not been caught. + "------------------------------------------------------------------------------- + + func Test_exception_after_error_1() + XpathINIT + while 1 + try + try + Xpath 'a' + let caught = 0 + while 1 + if 1 + " Missing :endif + endwhile " throw error exception + catch /^Vim(/ + Xpath 'b' + let caught = 1 + finally + Xpath 'c' + call assert_equal(1, caught) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'd' + break + endtry + call assert_report('should not get here') + endwhile + call assert_equal('abcd', g:Xpath) + endfunc + + func Test_exception_after_error_2() + XpathINIT + while 1 + try + try + Xpath 'a' + let caught = 0 + try + if 1 + " Missing :endif + catch /.*/ " throw error exception + call assert_report('should not get here') + catch /.*/ + call assert_report('should not get here') + endtry + catch /^Vim(/ + Xpath 'b' + let caught = 1 + finally + Xpath 'c' + call assert_equal(1, caught) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'd' + break + endtry + call assert_report('should not get here') + endwhile + call assert_equal('abcd', g:Xpath) + endfunc + + func Test_exception_after_error_3() + XpathINIT + while 1 + try + try + let caught = 0 + try + Xpath 'a' + call interrupt() + catch /do_not_catch/ + call assert_report('should not get here') + if 1 + " Missing :endif + catch /.*/ " throw error exception + call assert_report('should not get here') + catch /.*/ + call assert_report('should not get here') + endtry + catch /^Vim(/ + Xpath 'b' + let caught = 1 + finally + Xpath 'c' + call assert_equal(1, caught) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'd' + break + endtry + call assert_report('should not get here') + endwhile + call assert_equal('abcd', g:Xpath) + endfunc + + func Test_exception_after_error_4() + XpathINIT + while 1 + try + try + let caught = 0 + try + Xpath 'a' + throw "x" + catch /do_not_catch/ + call assert_report('should not get here') + if 1 + " Missing :endif + catch /x/ " throw error exception + call assert_report('should not get here') + catch /.*/ + call assert_report('should not get here') + endtry + catch /^Vim(/ + Xpath 'b' + let caught = 1 + finally + Xpath 'c' + call assert_equal(1, caught) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'd' + break + endtry + call assert_report('should not get here') + endwhile + call assert_equal('abcd', g:Xpath) + endfunc + + func Test_exception_after_error_5() + XpathINIT + while 1 + try + try + let caught = 0 + Xpath 'a' + endif " :endif without :if; throw error exception + if 1 + " Missing :endif + catch /do_not_catch/ " ignore new error + call assert_report('should not get here') + catch /^Vim(endif):/ + Xpath 'b' + let caught = 1 + catch /^Vim(/ + call assert_report('should not get here') + finally + Xpath 'c' + call assert_equal(1, caught) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'd' + break + endtry + call assert_report('should not get here') + endwhile + call assert_equal('abcd', g:Xpath) + endfunc + + "------------------------------------------------------------------------------- " Test 65: Errors in the /pattern/ argument of a :catch {{{1 " " On an error in the /pattern/ argument of a :catch, the :catch does *************** *** 3911,3916 **** --- 4794,5897 ---- endfunc "------------------------------------------------------------------------------- + " Test 66: Stop range :call on error, interrupt, or :throw {{{1 + " + " When a function which is multiply called for a range since it + " doesn't handle the range itself has an error in a command + " dynamically enclosed by :try/:endtry or gets an interrupt or + " executes a :throw, no more calls for the remaining lines in the + " range are made. On an error in a command not dynamically enclosed + " by :try/:endtry, the function is executed again for the remaining + " lines in the range. + "------------------------------------------------------------------------------- + + func Test_stop_range_on_error() + let test =<< trim [CODE] + let file = tempname() + exec "edit" file + call setline(1, ['line 1', 'line 2', 'line 3']) + let taken = "" + let expected = "G1EF1E(1)F1E(2)F1E(3)G2EF2E(1)G3IF3I(1)G4TF4T(1)G5AF5A(1)" + + func F(reason, n) abort + let g:taken = g:taken .. "F" .. a:n .. + \ substitute(a:reason, '\(\l\).*', '\u\1', "") .. + \ "(" .. line(".") .. ")" + + if a:reason == "error" + asdf + elseif a:reason == "interrupt" + call interrupt() + elseif a:reason == "throw" + throw "xyz" + elseif a:reason == "aborting error" + XloopNEXT + call assert_equal(g:taken, g:expected) + try + bwipeout! + call delete(g:file) + asdf + endtry + endif + endfunc + + func G(reason, n) + let g:taken = g:taken .. "G" .. a:n .. + \ substitute(a:reason, '\(\l\).*', '\u\1', "") + 1,3call F(a:reason, a:n) + endfunc + + Xpath 'a' + call G("error", 1) + try + Xpath 'b' + try + call G("error", 2) + call assert_report('should not get here') + finally + Xpath 'c' + try + call G("interrupt", 3) + call assert_report('should not get here') + finally + Xpath 'd' + try + call G("throw", 4) + call assert_report('should not get here') + endtry + endtry + endtry + catch /xyz/ + Xpath 'e' + catch /.*/ + call assert_report('should not get here') + endtry + Xpath 'f' + call G("aborting error", 5) + call assert_report('should not get here') + [CODE] + let verify =<< trim [CODE] + call assert_equal('abcdef', g:Xpath) + [CODE] + call RunInNewVim(test, verify) + endfunc + + "------------------------------------------------------------------------------- + " Test 67: :throw across :call command {{{1 + " + " On a call command, an exception might be thrown when evaluating the + " function name, during evaluation of the arguments, or when the + " function is being executed. The exception can be caught by the + " caller. + "------------------------------------------------------------------------------- + + func THROW(x, n) + if a:n == 1 + Xpath 'A' + elseif a:n == 2 + Xpath 'B' + elseif a:n == 3 + Xpath 'C' + endif + throw a:x + endfunc + + func NAME(x, n) + if a:n == 1 + call assert_report('should not get here') + elseif a:n == 2 + Xpath 'D' + elseif a:n == 3 + Xpath 'E' + elseif a:n == 4 + Xpath 'F' + endif + return a:x + endfunc + + func ARG(x, n) + if a:n == 1 + call assert_report('should not get here') + elseif a:n == 2 + call assert_report('should not get here') + elseif a:n == 3 + Xpath 'G' + elseif a:n == 4 + Xpath 'I' + endif + return a:x + endfunc + + func Test_throw_across_call_cmd() + XpathINIT + + func F(x, n) + if a:n == 2 + call assert_report('should not get here') + elseif a:n == 4 + Xpath 'a' + endif + endfunc + + while 1 + try + let v:errmsg = "" + + while 1 + try + Xpath 'b' + call {NAME(THROW("name", 1), 1)}(ARG(4711, 1), 1) + call assert_report('should not get here') + catch /^name$/ + Xpath 'c' + catch /.*/ + call assert_report('should not get here') + finally + call assert_equal("", v:errmsg) + let v:errmsg = "" + break + endtry + endwhile + + while 1 + try + Xpath 'd' + call {NAME("F", 2)}(ARG(THROW("arg", 2), 2), 2) + call assert_report('should not get here') + catch /^arg$/ + Xpath 'e' + catch /.*/ + call assert_report('should not get here') + finally + call assert_equal("", v:errmsg) + let v:errmsg = "" + break + endtry + endwhile + + while 1 + try + Xpath 'f' + call {NAME("THROW", 3)}(ARG("call", 3), 3) + call assert_report('should not get here') + catch /^call$/ + Xpath 'g' + catch /^0$/ " default return value + call assert_report('should not get here') + catch /.*/ + call assert_report('should not get here') + finally + call assert_equal("", v:errmsg) + let v:errmsg = "" + break + endtry + endwhile + + while 1 + try + Xpath 'h' + call {NAME("F", 4)}(ARG(4711, 4), 4) + Xpath 'i' + catch /.*/ + call assert_report('should not get here') + finally + call assert_equal("", v:errmsg) + let v:errmsg = "" + break + endtry + endwhile + + catch /^0$/ " default return value + call assert_report('should not get here') + catch /.*/ + call assert_report('should not get here') + finally + call assert_equal("", v:errmsg) + let v:errmsg = "" + break + endtry + endwhile + + call assert_equal('bAcdDBefEGCghFIai', g:Xpath) + delfunction F + endfunc + + "------------------------------------------------------------------------------- + " Test 68: :throw across function calls in expressions {{{1 + " + " On a function call within an expression, an exception might be + " thrown when evaluating the function name, during evaluation of the + " arguments, or when the function is being executed. The exception + " can be caught by the caller. + " + " This test reuses the functions THROW(), NAME(), and ARG() from the + " previous test. + "------------------------------------------------------------------------------- + + func Test_throw_across_call_expr() + XpathINIT + + func F(x, n) + if a:n == 2 + call assert_report('should not get here') + elseif a:n == 4 + Xpath 'a' + endif + return a:x + endfunction + + while 1 + try + let error = 0 + let v:errmsg = "" + + while 1 + try + Xpath 'b' + let var1 = {NAME(THROW("name", 1), 1)}(ARG(4711, 1), 1) + call assert_report('should not get here') + catch /^name$/ + Xpath 'c' + catch /.*/ + call assert_report('should not get here') + finally + call assert_equal("", v:errmsg) + let v:errmsg = "" + break + endtry + endwhile + call assert_true(!exists('var1')) + + while 1 + try + Xpath 'd' + let var2 = {NAME("F", 2)}(ARG(THROW("arg", 2), 2), 2) + call assert_report('should not get here') + catch /^arg$/ + Xpath 'e' + catch /.*/ + call assert_report('should not get here') + finally + call assert_equal("", v:errmsg) + let v:errmsg = "" + break + endtry + endwhile + call assert_true(!exists('var2')) + + while 1 + try + Xpath 'f' + let var3 = {NAME("THROW", 3)}(ARG("call", 3), 3) + call assert_report('should not get here') + catch /^call$/ + Xpath 'g' + catch /^0$/ " default return value + call assert_report('should not get here') + catch /.*/ + call assert_report('should not get here') + finally + call assert_equal("", v:errmsg) + let v:errmsg = "" + break + endtry + endwhile + call assert_true(!exists('var3')) + + while 1 + try + Xpath 'h' + let var4 = {NAME("F", 4)}(ARG(4711, 4), 4) + Xpath 'i' + catch /.*/ + call assert_report('should not get here') + finally + call assert_equal("", v:errmsg) + let v:errmsg = "" + break + endtry + endwhile + call assert_true(exists('var4') && var4 == 4711) + + catch /^0$/ " default return value + call assert_report('should not get here') + catch /.*/ + call assert_report('should not get here') + finally + call assert_equal("", v:errmsg) + break + endtry + endwhile + + call assert_equal('bAcdDBefEGCghFIai', g:Xpath) + delfunc F + endfunc + + "------------------------------------------------------------------------------- + " Test 76: Errors, interrupts, :throw during expression evaluation {{{1 + " + " When a function call made during expression evaluation is aborted + " due to an error inside a :try/:endtry region or due to an interrupt + " or a :throw, the expression evaluation is aborted as well. No + " message is displayed for the cancelled expression evaluation. On an + " error not inside :try/:endtry, the expression evaluation continues. + "------------------------------------------------------------------------------- + + func Test_expr_eval_error() + let test =<< trim [CODE] + let taken = "" + + func ERR(n) + let g:taken = g:taken .. "E" .. a:n + asdf + endfunc + + func ERRabort(n) abort + let g:taken = g:taken .. "A" .. a:n + asdf + endfunc " returns -1; may cause follow-up msg for illegal var/func name + + func WRAP(n, arg) + let g:taken = g:taken .. "W" .. a:n + let g:saved_errmsg = v:errmsg + return arg + endfunc + + func INT(n) + let g:taken = g:taken .. "I" .. a:n + call interrupt() + endfunc + + func THR(n) + let g:taken = g:taken .. "T" .. a:n + throw "should not be caught" + endfunc + + func CONT(n) + let g:taken = g:taken .. "C" .. a:n + endfunc + + func MSG(n) + let g:taken = g:taken .. "M" .. a:n + let errmsg = (a:n >= 37 && a:n <= 44) ? g:saved_errmsg : v:errmsg + let msgptn = (a:n >= 10 && a:n <= 27) ? "^$" : "asdf" + call assert_match(msgptn, errmsg) + let v:errmsg = "" + let g:saved_errmsg = "" + endfunc + + let v:errmsg = "" + + try + let t = 1 + while t <= 9 + Xloop 'a' + try + if t == 1 + let v{ERR(t) + CONT(t)} = 0 + elseif t == 2 + let v{ERR(t) + CONT(t)} + elseif t == 3 + let var = exists('v{ERR(t) + CONT(t)}') + elseif t == 4 + unlet v{ERR(t) + CONT(t)} + elseif t == 5 + function F{ERR(t) + CONT(t)}() + endfunction + elseif t == 6 + function F{ERR(t) + CONT(t)} + elseif t == 7 + let var = exists('*F{ERR(t) + CONT(t)}') + elseif t == 8 + delfunction F{ERR(t) + CONT(t)} + elseif t == 9 + let var = ERR(t) + CONT(t) + endif + catch /asdf/ + " v:errmsg is not set when the error message is converted to an + " exception. Set it to the original error message. + let v:errmsg = substitute(v:exception, '^Vim:', '', "") + catch /^Vim\((\a\+)\)\=:/ + " An error exception has been thrown after the original error. + let v:errmsg = "" + finally + call MSG(t) + let t = t + 1 + XloopNEXT + continue " discard an aborting error + endtry + endwhile + catch /.*/ + call assert_report('should not get here') + endtry + + try + let t = 10 + while t <= 18 + Xloop 'b' + try + if t == 10 + let v{INT(t) + CONT(t)} = 0 + elseif t == 11 + let v{INT(t) + CONT(t)} + elseif t == 12 + let var = exists('v{INT(t) + CONT(t)}') + elseif t == 13 + unlet v{INT(t) + CONT(t)} + elseif t == 14 + function F{INT(t) + CONT(t)}() + endfunction + elseif t == 15 + function F{INT(t) + CONT(t)} + elseif t == 16 + let var = exists('*F{INT(t) + CONT(t)}') + elseif t == 17 + delfunction F{INT(t) + CONT(t)} + elseif t == 18 + let var = INT(t) + CONT(t) + endif + catch /^Vim\((\a\+)\)\=:\(Interrupt\)\@!/ + " An error exception has been triggered after the interrupt. + let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "") + finally + call MSG(t) + let t = t + 1 + XloopNEXT + continue " discard interrupt + endtry + endwhile + catch /.*/ + call assert_report('should not get here') + endtry + + try + let t = 19 + while t <= 27 + Xloop 'c' + try + if t == 19 + let v{THR(t) + CONT(t)} = 0 + elseif t == 20 + let v{THR(t) + CONT(t)} + elseif t == 21 + let var = exists('v{THR(t) + CONT(t)}') + elseif t == 22 + unlet v{THR(t) + CONT(t)} + elseif t == 23 + function F{THR(t) + CONT(t)}() + endfunction + elseif t == 24 + function F{THR(t) + CONT(t)} + elseif t == 25 + let var = exists('*F{THR(t) + CONT(t)}') + elseif t == 26 + delfunction F{THR(t) + CONT(t)} + elseif t == 27 + let var = THR(t) + CONT(t) + endif + catch /^Vim\((\a\+)\)\=:/ + " An error exception has been triggered after the :throw. + let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "") + finally + call MSG(t) + let t = t + 1 + XloopNEXT + continue " discard exception + endtry + endwhile + catch /.*/ + call assert_report('should not get here') + endtry + + let v{ERR(28) + CONT(28)} = 0 + call MSG(28) + let v{ERR(29) + CONT(29)} + call MSG(29) + let var = exists('v{ERR(30) + CONT(30)}') + call MSG(30) + unlet v{ERR(31) + CONT(31)} + call MSG(31) + function F{ERR(32) + CONT(32)}() + endfunction + call MSG(32) + function F{ERR(33) + CONT(33)} + call MSG(33) + let var = exists('*F{ERR(34) + CONT(34)}') + call MSG(34) + delfunction F{ERR(35) + CONT(35)} + call MSG(35) + let var = ERR(36) + CONT(36) + call MSG(36) + + let saved_errmsg = "" + + let v{WRAP(37, ERRabort(37)) + CONT(37)} = 0 + call MSG(37) + let v{WRAP(38, ERRabort(38)) + CONT(38)} + call MSG(38) + let var = exists('v{WRAP(39, ERRabort(39)) + CONT(39)}') + call MSG(39) + unlet v{WRAP(40, ERRabort(40)) + CONT(40)} + call MSG(40) + function F{WRAP(41, ERRabort(41)) + CONT(41)}() + endfunction + call MSG(41) + function F{WRAP(42, ERRabort(42)) + CONT(42)} + call MSG(42) + let var = exists('*F{WRAP(43, ERRabort(43)) + CONT(43)}') + call MSG(43) + delfunction F{WRAP(44, ERRabort(44)) + CONT(44)} + call MSG(44) + let var = ERRabort(45) + CONT(45) + call MSG(45) + Xpath 'd' + + let expected = "" + \ .. "E1M1E2M2E3M3E4M4E5M5E6M6E7M7E8M8E9M9" + \ .. "I10M10I11M11I12M12I13M13I14M14I15M15I16M16I17M17I18M18" + \ .. "T19M19T20M20T21M21T22M22T23M23T24M24T25M25T26M26T27M27" + \ .. "E28C28M28E29C29M29E30C30M30E31C31M31E32C32M32E33C33M33" + \ .. "E34C34M34E35C35M35E36C36M36" + \ .. "A37W37C37M37A38W38C38M38A39W39C39M39A40W40C40M40A41W41C41M41" + \ .. "A42W42C42M42A43W43C43M43A44W44C44M44A45C45M45" + call assert_equal(expected, taken) + [CODE] + let verify =<< trim [CODE] + let expected = "a1a2a3a4a5a6a7a8a9" + \ .. "b10b11b12b13b14b15b16b17b18" + \ .. "c19c20c21c22c23c24c25c26c27d" + call assert_equal(expected, g:Xpath) + [CODE] + call RunInNewVim(test, verify) + endfunc + + "------------------------------------------------------------------------------- + " Test 77: Errors, interrupts, :throw in name{brace-expression} {{{1 + " + " When a function call made during evaluation of an expression in + " braces as part of a function name after ":function" is aborted due + " to an error inside a :try/:endtry region or due to an interrupt or + " a :throw, the expression evaluation is aborted as well, and the + " function definition is ignored, skipping all commands to the + " ":endfunction". On an error not inside :try/:endtry, the expression + " evaluation continues and the function gets defined, and can be + " called and deleted. + "------------------------------------------------------------------------------- + func Test_brace_expr_error() + let test =<< trim [CODE] + func ERR() abort + Xloop 'a' + asdf + endfunc " returns -1 + + func OK() + Xloop 'b' + let v:errmsg = "" + return 0 + endfunc + + let v:errmsg = "" + + Xpath 'c' + func F{1 + ERR() + OK()}(arg) + " F0 should be defined. + if exists("a:arg") && a:arg == "calling" + Xpath 'd' + else + call assert_report('should not get here') + endif + endfunction + call assert_equal("", v:errmsg) + XloopNEXT + + Xpath 'e' + call F{1 + ERR() + OK()}("calling") + call assert_equal("", v:errmsg) + XloopNEXT + + Xpath 'f' + delfunction F{1 + ERR() + OK()} + call assert_equal("", v:errmsg) + XloopNEXT + + try + while 1 + try + Xpath 'g' + func G{1 + ERR() + OK()}(arg) + " G0 should not be defined, and the function body should be + " skipped. + call assert_report('should not get here') + " Use an unmatched ":finally" to check whether the body is + " skipped when an error occurs in ERR(). This works whether or + " not the exception is converted to an exception. + finally + call assert_report('should not get here') + endtry + try + call assert_report('should not get here') + endfunction + + call assert_report('should not get here') + catch /asdf/ + " Jumped to when the function is not defined and the body is + " skipped. + Xpath 'h' + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'i' + break + endtry " jumped to when the body is not skipped + endwhile + catch /.*/ + call assert_report('should not get here') + endtry + [CODE] + let verify =<< trim [CODE] + call assert_equal('ca1b1ea2b2dfa3b3ga4hi', g:Xpath) + [CODE] + call RunInNewVim(test, verify) + endfunc + + "------------------------------------------------------------------------------- + " Test 78: Messages on parsing errors in expression evaluation {{{1 + " + " When an expression evaluation detects a parsing error, an error + " message is given and converted to an exception, and the expression + " evaluation is aborted. + "------------------------------------------------------------------------------- + func Test_expr_eval_error_msg() + CheckEnglish + + let test =<< trim [CODE] + let taken = "" + + func F(n) + let g:taken = g:taken . "F" . a:n + endfunc + + func MSG(n, enr, emsg) + let g:taken = g:taken . "M" . a:n + call assert_match('^' .. a:enr .. ':', v:errmsg) + call assert_match(a:emsg, v:errmsg) + endfunc + + func CONT(n) + let g:taken = g:taken . "C" . a:n + endfunc + + let v:errmsg = "" + try + let t = 1 + while t <= 14 + let g:taken = g:taken . "T" . t + let v:errmsg = "" + try + if t == 1 + let v{novar + CONT(t)} = 0 + elseif t == 2 + let v{novar + CONT(t)} + elseif t == 3 + let var = exists('v{novar + CONT(t)}') + elseif t == 4 + unlet v{novar + CONT(t)} + elseif t == 5 + function F{novar + CONT(t)}() + endfunction + elseif t == 6 + function F{novar + CONT(t)} + elseif t == 7 + let var = exists('*F{novar + CONT(t)}') + elseif t == 8 + delfunction F{novar + CONT(t)} + elseif t == 9 + echo novar + CONT(t) + elseif t == 10 + echo v{novar + CONT(t)} + elseif t == 11 + echo F{novar + CONT(t)} + elseif t == 12 + let var = novar + CONT(t) + elseif t == 13 + let var = v{novar + CONT(t)} + elseif t == 14 + let var = F{novar + CONT(t)}() + endif + catch /^Vim\((\a\+)\)\=:/ + Xloop 'a' + " v:errmsg is not set when the error message is converted to an + " exception. Set it to the original error message. + let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "") + finally + Xloop 'b' + if t <= 8 && t != 3 && t != 7 + call MSG(t, 'E475', 'Invalid argument\>') + else + call MSG(t, 'E121', "Undefined variable") + endif + let t = t + 1 + XloopNEXT + continue " discard an aborting error + endtry + endwhile + catch /.*/ + call assert_report('should not get here') + endtry + + func T(n, expr, enr, emsg) + try + let g:taken = g:taken . "T" . a:n + let v:errmsg = "" + try + execute "let var = " . a:expr + catch /^Vim\((\a\+)\)\=:/ + Xloop 'c' + " v:errmsg is not set when the error message is converted to an + " exception. Set it to the original error message. + let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "") + finally + Xloop 'd' + call MSG(a:n, a:enr, a:emsg) + XloopNEXT + " Discard an aborting error: + return + endtry + catch /.*/ + call assert_report('should not get here') + endtry + endfunc + + call T(15, 'Nofunc() + CONT(15)', 'E117', "Unknown function") + call T(16, 'F(1 2 + CONT(16))', 'E116', "Invalid arguments") + call T(17, 'F(1, 2) + CONT(17)', 'E118', "Too many arguments") + call T(18, 'F() + CONT(18)', 'E119', "Not enough arguments") + call T(19, '{(1} + CONT(19)', 'E110', "Missing ')'") + call T(20, '("abc"[1) + CONT(20)', 'E111', "Missing ']'") + call T(21, '(1 +) + CONT(21)', 'E15', "Invalid expression") + call T(22, '1 2 + CONT(22)', 'E15', "Invalid expression") + call T(23, '(1 ? 2) + CONT(23)', 'E109', "Missing ':' after '?'") + call T(24, '("abc) + CONT(24)', 'E114', "Missing quote") + call T(25, "('abc) + CONT(25)", 'E115', "Missing quote") + call T(26, '& + CONT(26)', 'E112', "Option name missing") + call T(27, '&asdf + CONT(27)', 'E113', "Unknown option") + + let expected = "" + \ .. "T1M1T2M2T3M3T4M4T5M5T6M6T7M7T8M8T9M9T10M10T11M11T12M12T13M13T14M14" + \ .. "T15M15T16M16T17M17T18M18T19M19T20M20T21M21T22M22T23M23T24M24T25M25" + \ .. "T26M26T27M27" + + call assert_equal(expected, taken) + [CODE] + let verify =<< trim [CODE] + let expected = "a1b1a2b2a3b3a4b4a5b5a6b6a7b7a8b8a9b9a10b10a11b11a12b12" + \ .. "a13b13a14b14c15d15c16d16c17d17c18d18c19d19c20d20" + \ .. "c21d21c22d22c23d23c24d24c25d25c26d26c27d27" + call assert_equal(expected, g:Xpath) + [CODE] + call RunInNewVim(test, verify) + endfunc + + "------------------------------------------------------------------------------- + " Test 79: Throwing one of several errors for the same command {{{1 + " + " When several errors appear in a row (for instance during expression + " evaluation), the first as the most specific one is used when + " throwing an error exception. If, however, a syntax error is + " detected afterwards, this one is used for the error exception. + " On a syntax error, the next command is not executed, on a normal + " error, however, it is (relevant only in a function without the + " "abort" flag). v:errmsg is not set. + " + " If throwing error exceptions is configured off, v:errmsg is always + " set to the latest error message, that is, to the more general + " message or the syntax error, respectively. + "------------------------------------------------------------------------------- + func Test_throw_multi_error() + CheckEnglish + + let test =<< trim [CODE] + func NEXT(cmd) + exec a:cmd . " | Xloop 'a'" + endfun + + call NEXT('echo novar') " (checks nextcmd) + XloopNEXT + call NEXT('let novar #') " (skips nextcmd) + XloopNEXT + call NEXT('unlet novar #') " (skips nextcmd) + XloopNEXT + call NEXT('let {novar}') " (skips nextcmd) + XloopNEXT + call NEXT('unlet{ novar}') " (skips nextcmd) + + call assert_equal('a1', g:Xpath) + XpathINIT + XloopINIT + + func EXEC(cmd) + exec a:cmd + endfunc + + try + while 1 " dummy loop + try + let v:errmsg = "" + call EXEC('echo novar') " normal error + catch /^Vim\((\a\+)\)\=:/ + Xpath 'b' + call assert_match('E121: Undefined variable: novar', v:exception) + finally + Xpath 'c' + call assert_equal("", v:errmsg) + break + endtry + endwhile + + Xpath 'd' + let cmd = "let" + while cmd != "" + try + let v:errmsg = "" + call EXEC(cmd . ' novar #') " normal plus syntax error + catch /^Vim\((\a\+)\)\=:/ + Xloop 'e' + call assert_match('E488: Trailing characters', v:exception) + finally + Xloop 'f' + call assert_equal("", v:errmsg) + if cmd == "let" + let cmd = "unlet" + else + let cmd = "" + endif + XloopNEXT + continue + endtry + endwhile + + Xpath 'g' + let cmd = "let" + while cmd != "" + try + let v:errmsg = "" + call EXEC(cmd . ' {novar}') " normal plus syntax error + catch /^Vim\((\a\+)\)\=:/ + Xloop 'h' + call assert_match('E475: Invalid argument: {novar}', v:exception) + finally + Xloop 'i' + call assert_equal("", v:errmsg) + if cmd == "let" + let cmd = "unlet" + else + let cmd = "" + endif + XloopNEXT + continue + endtry + endwhile + catch /.*/ + call assert_report('should not get here') + endtry + Xpath 'j' + [CODE] + let verify =<< trim [CODE] + call assert_equal('bcde1f1e2f2gh3i3h4i4j', g:Xpath) + [CODE] + call RunInNewVim(test, verify) + endfunc + + "------------------------------------------------------------------------------- + " Test 80: Syntax error in expression for illegal :elseif {{{1 + " + " If there is a syntax error in the expression after an illegal + " :elseif, an error message is given (or an error exception thrown) + " for the illegal :elseif rather than the expression error. + "------------------------------------------------------------------------------- + func Test_if_syntax_error() + CheckEnglish + + let test =<< trim [CODE] + let v:errmsg = "" + if 0 + else + elseif 1 ||| 2 + endif + Xpath 'a' + call assert_match('E584: :elseif after :else', v:errmsg) + + let v:errmsg = "" + if 1 + else + elseif 1 ||| 2 + endif + Xpath 'b' + call assert_match('E584: :elseif after :else', v:errmsg) + + let v:errmsg = "" + elseif 1 ||| 2 + Xpath 'c' + call assert_match('E582: :elseif without :if', v:errmsg) + + let v:errmsg = "" + while 1 + elseif 1 ||| 2 + endwhile + Xpath 'd' + call assert_match('E582: :elseif without :if', v:errmsg) + + while 1 + try + try + let v:errmsg = "" + if 0 + else + elseif 1 ||| 2 + endif + catch /^Vim\((\a\+)\)\=:/ + Xpath 'e' + call assert_match('E584: :elseif after :else', v:exception) + finally + Xpath 'f' + call assert_equal("", v:errmsg) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'g' + break + endtry + endwhile + + while 1 + try + try + let v:errmsg = "" + if 1 + else + elseif 1 ||| 2 + endif + catch /^Vim\((\a\+)\)\=:/ + Xpath 'h' + call assert_match('E584: :elseif after :else', v:exception) + finally + Xpath 'i' + call assert_equal("", v:errmsg) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'j' + break + endtry + endwhile + + while 1 + try + try + let v:errmsg = "" + elseif 1 ||| 2 + catch /^Vim\((\a\+)\)\=:/ + Xpath 'k' + call assert_match('E582: :elseif without :if', v:exception) + finally + Xpath 'l' + call assert_equal("", v:errmsg) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'm' + break + endtry + endwhile + + while 1 + try + try + let v:errmsg = "" + while 1 + elseif 1 ||| 2 + endwhile + catch /^Vim\((\a\+)\)\=:/ + Xpath 'n' + call assert_match('E582: :elseif without :if', v:exception) + finally + Xpath 'o' + call assert_equal("", v:errmsg) + endtry + catch /.*/ + call assert_report('should not get here') + finally + Xpath 'p' + break + endtry + endwhile + Xpath 'q' + [CODE] + let verify =<< trim [CODE] + call assert_equal('abcdefghijklmnopq', g:Xpath) + [CODE] + call RunInNewVim(test, verify) + endfunc + + "------------------------------------------------------------------------------- + " Test 81: Discarding exceptions after an error or interrupt {{{1 + " + " When an exception is thrown from inside a :try conditional without + " :catch and :finally clauses and an error or interrupt occurs before + " the :endtry is reached, the exception is discarded. + "------------------------------------------------------------------------------- + + func Test_discard_exception_after_error_1() + let test =<< trim [CODE] + try + Xpath 'a' + try + Xpath 'b' + throw "arrgh" + call assert_report('should not get here') + if 1 + call assert_report('should not get here') + " error after :throw: missing :endif + endtry + call assert_report('should not get here') + catch /arrgh/ + call assert_report('should not get here') + endtry + call assert_report('should not get here') + [CODE] + let verify =<< trim [CODE] + call assert_equal('ab', g:Xpath) + [CODE] + call RunInNewVim(test, verify) + endfunc + + " TODO: Not able inject an interrupt after throwing an exception + func Disable_Test_discard_exception_after_error_2() + let test =<< trim [CODE] + try + Xpath 'a' + try + Xpath 'b' + throw "arrgh" + call interrupt() " FIXME: throw is not interrupted here + call assert_report('should not get here') + endtry + call assert_report('should not get here') + catch /arrgh/ + call assert_report('should not get here') + endtry + call assert_report('should not get here') + [CODE] + let verify =<< trim [CODE] + call assert_equal('ab', g:Xpath) + [CODE] + call RunInNewVim(test, verify) + endfunc + + "------------------------------------------------------------------------------- " Test 87 using (expr) ? funcref : funcref {{{1 " " Vim needs to correctly parse the funcref and even when it does *** ../vim-8.2.1416/src/version.c 2020-08-10 21:57:49.039237480 +0200 --- src/version.c 2020-08-10 22:15:06.295095449 +0200 *************** *** 756,757 **** --- 756,759 ---- { /* Add new patch number below this line */ + /**/ + 1417, /**/ -- hundred-and-one symptoms of being an internet addict: 169. You hire a housekeeper for your home page. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///