neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

test_trycatch.vim (52802B)


      1 " Test try-catch-finally exception handling
      2 " Most of this was formerly in test49.
      3 
      4 source check.vim
      5 source shared.vim
      6 source vim9.vim
      7 
      8 "-------------------------------------------------------------------------------
      9 " Test environment							    {{{1
     10 "-------------------------------------------------------------------------------
     11 
     12 com!		   XpathINIT  let g:Xpath = ''
     13 com! -nargs=1 -bar Xpath      let g:Xpath = g:Xpath . <args>
     14 
     15 " Test 25:  Executing :finally clauses on normal control flow		    {{{1
     16 "
     17 "	    Control flow in a :try conditional should always fall through to its
     18 "	    :finally clause.  A :finally clause of a :try conditional inside an
     19 "	    inactive conditional should never be executed.
     20 "-------------------------------------------------------------------------------
     21 
     22 func T25_F()
     23  let loops = 3
     24  while loops > 0
     25    Xpath 'a' . loops
     26    if loops >= 2
     27      try
     28        Xpath 'b' . loops
     29        if loops == 2
     30          try
     31            Xpath 'c' . loops
     32          finally
     33            Xpath 'd' . loops
     34          endtry
     35        endif
     36      finally
     37        Xpath 'e' . loops
     38        if loops == 2
     39          try
     40            Xpath 'f' . loops
     41          final
     42            Xpath 'g' . loops
     43          endtry
     44        endif
     45      endtry
     46    endif
     47    Xpath 'h' . loops
     48    let loops = loops - 1
     49  endwhile
     50  Xpath 'i'
     51 endfunc
     52 
     53 " Also try using "fina" and "final" and "finall" as abbreviations.
     54 func T25_G()
     55  if 1
     56    try
     57      Xpath 'A'
     58      call T25_F()
     59      Xpath 'B'
     60    fina
     61      Xpath 'C'
     62    endtry
     63  else
     64    try
     65      Xpath 'D'
     66    finall
     67      Xpath 'E'
     68    endtry
     69  endif
     70 endfunc
     71 
     72 func Test_finally()
     73  XpathINIT
     74  call T25_G()
     75  call assert_equal('Aa3b3e3h3a2b2c2d2e2f2g2h2a1h1iBC', g:Xpath)
     76 endfunc
     77 
     78 
     79 "-------------------------------------------------------------------------------
     80 " Test 26:  Executing :finally clauses after :continue or :break	    {{{1
     81 "
     82 "	    For a :continue or :break dynamically enclosed in a :try/:endtry
     83 "	    region inside the next surrounding :while/:endwhile, if the
     84 "	    :continue/:break is before the :finally, the :finally clause is
     85 "	    executed first.  If the :continue/:break is after the :finally, the
     86 "	    :finally clause is broken (like an :if/:endif region).
     87 "-------------------------------------------------------------------------------
     88 
     89 func T26_F()
     90  try
     91    let loops = 3
     92    while loops > 0
     93      try
     94        try
     95          if loops == 2
     96            Xpath 'a' . loops
     97            let loops = loops - 1
     98            continue
     99          elseif loops == 1
    100            Xpath 'b' . loops
    101            break
    102            finish
    103          endif
    104          Xpath 'c' . loops
    105        endtry
    106      finally
    107        Xpath 'd' . loops
    108      endtry
    109      Xpath 'e' . loops
    110      let loops = loops - 1
    111    endwhile
    112    Xpath 'f'
    113  finally
    114    Xpath 'g'
    115    let loops = 3
    116    while loops > 0
    117      try
    118      finally
    119        try
    120          if loops == 2
    121            Xpath 'h' . loops
    122            let loops = loops - 1
    123            continue
    124          elseif loops == 1
    125            Xpath 'i' . loops
    126            break
    127            finish
    128          endif
    129        endtry
    130        Xpath 'j' . loops
    131      endtry
    132      Xpath 'k' . loops
    133      let loops = loops - 1
    134    endwhile
    135    Xpath 'l'
    136  endtry
    137  Xpath 'm'
    138 endfunc
    139 
    140 func Test_finally_after_continue()
    141  XpathINIT
    142  call T26_F()
    143  call assert_equal('c3d3e3a2d1b1d1fgj3k3h2i1lm', g:Xpath)
    144 endfunc
    145 
    146 
    147 "-------------------------------------------------------------------------------
    148 " Test 32:  Remembering the :return value on :finally			    {{{1
    149 "
    150 "	    If a :finally clause is executed due to a :return specifying
    151 "	    a value, this is the value visible to the caller if not overwritten
    152 "	    by a new :return in the :finally clause.  A :return without a value
    153 "	    in the :finally clause overwrites with value 0.
    154 "-------------------------------------------------------------------------------
    155 
    156 func T32_F()
    157  try
    158    Xpath 'a'
    159    try
    160      Xpath 'b'
    161      return "ABCD"
    162      Xpath 'c'
    163    finally
    164      Xpath 'd'
    165    endtry
    166    Xpath 'e'
    167  finally
    168    Xpath 'f'
    169  endtry
    170  Xpath 'g'
    171 endfunc
    172 
    173 func T32_G()
    174  try
    175    Xpath 'h'
    176    return 8
    177    Xpath 'i'
    178  finally
    179    Xpath 'j'
    180    return 16 + strlen(T32_F())
    181    Xpath 'k'
    182  endtry
    183  Xpath 'l'
    184 endfunc
    185 
    186 func T32_H()
    187  try
    188    Xpath 'm'
    189    return 32
    190    Xpath 'n'
    191  finally
    192    Xpath 'o'
    193    return
    194    Xpath 'p'
    195  endtry
    196  Xpath 'q'
    197 endfunc
    198 
    199 func T32_I()
    200  try
    201    Xpath 'r'
    202  finally
    203    Xpath 's'
    204    return T32_G() + T32_H() + 64
    205    Xpath 't'
    206  endtry
    207  Xpath 'u'
    208 endfunc
    209 
    210 func Test_finally_return()
    211  XpathINIT
    212  call assert_equal(84, T32_I())
    213  call assert_equal('rshjabdfmo', g:Xpath)
    214 endfunc
    215 
    216 "-------------------------------------------------------------------------------
    217 " Test 33:  :return under :execute or user command and :finally		    {{{1
    218 "
    219 "	    A :return command may be executed under an ":execute" or from
    220 "	    a user command.  Executing of :finally clauses and passing through
    221 "	    the return code works also then.
    222 "-------------------------------------------------------------------------------
    223 
    224 func T33_F()
    225  try
    226    RETURN 10
    227    Xpath 'a'
    228  finally
    229    Xpath 'b'
    230  endtry
    231  Xpath 'c'
    232 endfunc
    233 
    234 func T33_G()
    235  try
    236    RETURN 20
    237    Xpath 'd'
    238  finally
    239    Xpath 'e'
    240    RETURN 30
    241    Xpath 'f'
    242  endtry
    243  Xpath 'g'
    244 endfunc
    245 
    246 func T33_H()
    247  try
    248    execute "try | return 40 | finally | return 50 | endtry"
    249    Xpath 'h'
    250  finally
    251    Xpath 'i'
    252  endtry
    253  Xpath 'j'
    254 endfunc
    255 
    256 func T33_I()
    257  try
    258    execute "try | return 60 | finally | return 70 | endtry"
    259    Xpath 'k'
    260  finally
    261    Xpath 'l'
    262    execute "try | return 80 | finally | return 90 | endtry"
    263    Xpath 'm'
    264  endtry
    265  Xpath 'n'
    266 endfunc
    267 
    268 func T33_J()
    269  try
    270    RETURN 100
    271    Xpath 'o'
    272  finally
    273    Xpath 'p'
    274    return
    275    Xpath 'q'
    276  endtry
    277  Xpath 'r'
    278 endfunc
    279 
    280 func T33_K()
    281  try
    282    execute "try | return 110 | finally | return 120 | endtry"
    283    Xpath 's'
    284  finally
    285    Xpath 't'
    286    execute "try | return 130 | finally | return | endtry"
    287    Xpath 'u'
    288  endtry
    289  Xpath 'v'
    290 endfunc
    291 
    292 func T33_L()
    293  try
    294    return
    295    Xpath 'w'
    296  finally
    297    Xpath 'x'
    298    RETURN 140
    299    Xpath 'y'
    300  endtry
    301  Xpath 'z'
    302 endfunc
    303 
    304 func T33_M()
    305  try
    306    return
    307    Xpath 'A'
    308  finally
    309    Xpath 'B'
    310    execute "try | return 150 | finally | return 160 | endtry"
    311    Xpath 'C'
    312  endtry
    313  Xpath 'D'
    314 endfunc
    315 
    316 func T33_N()
    317  RETURN 170
    318 endfunc
    319 
    320 func T33_O()
    321  execute "try | return 180 | finally | return 190 | endtry"
    322 endfunc
    323 
    324 func Test_finally_cmd_return()
    325  command! -nargs=? RETURN
    326        \ try | return <args> | finally | return <args> * 2 | endtry
    327  XpathINIT
    328  call assert_equal(20, T33_F())
    329  call assert_equal(60, T33_G())
    330  call assert_equal(50, T33_H())
    331  call assert_equal(90, T33_I())
    332  call assert_equal(0, T33_J())
    333  call assert_equal(0, T33_K())
    334  call assert_equal(280, T33_L())
    335  call assert_equal(160, T33_M())
    336  call assert_equal(340, T33_N())
    337  call assert_equal(190, T33_O())
    338  call assert_equal('beilptxB', g:Xpath)
    339  delcommand RETURN
    340 endfunc
    341 
    342 
    343 "-------------------------------------------------------------------------------
    344 " Test 41:  Skipped :throw finding next command				    {{{1
    345 "
    346 "	    A :throw in an inactive conditional must not hide a following
    347 "	    command.
    348 "-------------------------------------------------------------------------------
    349 
    350 func T41_F()
    351  Xpath 'a'
    352  if 0 | throw 'never' | endif | Xpath 'b'
    353  Xpath 'c'
    354 endfunc
    355 
    356 func T41_G()
    357  Xpath 'd'
    358  while 0 | throw 'never' | endwhile | Xpath 'e'
    359  Xpath 'f'
    360 endfunc
    361 
    362 func T41_H()
    363  Xpath 'g'
    364  if 0 | try | throw 'never' | endtry | endif | Xpath 'h'
    365  Xpath 'i'
    366 endfunc
    367 
    368 func Test_throw_inactive_cond()
    369  XpathINIT
    370  try
    371    Xpath 'j'
    372    call T41_F()
    373    Xpath 'k'
    374  catch /.*/
    375    Xpath 'l'
    376    call assert_report('Caught ' . v:exception . ' in ' . v:throwpoint)
    377  endtry
    378 
    379  try
    380    Xpath 'm'
    381    call T41_G()
    382    Xpath 'n'
    383  catch /.*/
    384    Xpath 'o'
    385    call assert_report('Caught ' . v:exception . ' in ' . v:throwpoint)
    386  endtry
    387 
    388  try
    389    Xpath 'p'
    390    call T41_H()
    391    Xpath 'q'
    392  catch /.*/
    393    Xpath 'r'
    394    call assert_report('Caught ' . v:exception . ' in ' . v:throwpoint)
    395  endtry
    396 
    397  call assert_equal('jabckmdefnpghiq', g:Xpath)
    398 endfunc
    399 
    400 
    401 "-------------------------------------------------------------------------------
    402 " Test 42:  Catching number and string exceptions			    {{{1
    403 "
    404 "	    When a number is thrown, it is converted to a string exception.
    405 "	    Numbers and strings may be caught by specifying a regular exception
    406 "	    as argument to the :catch command.
    407 "-------------------------------------------------------------------------------
    408 
    409 
    410 func T42_F()
    411  try
    412 
    413    try
    414      Xpath 'a'
    415      throw 4711
    416      Xpath 'b'
    417    catch /4711/
    418      Xpath 'c'
    419    endtry
    420 
    421    try
    422      Xpath 'd'
    423      throw 4711
    424      Xpath 'e'
    425    catch /^4711$/
    426      Xpath 'f'
    427    endtry
    428 
    429    try
    430      Xpath 'g'
    431      throw 4711
    432      Xpath 'h'
    433    catch /\d/
    434      Xpath 'i'
    435    endtry
    436 
    437    try
    438      Xpath 'j'
    439      throw 4711
    440      Xpath 'k'
    441    catch /^\d\+$/
    442      Xpath 'l'
    443    endtry
    444 
    445    try
    446      Xpath 'm'
    447      throw "arrgh"
    448      Xpath 'n'
    449    catch /arrgh/
    450      Xpath 'o'
    451    endtry
    452 
    453    try
    454      Xpath 'p'
    455      throw "arrgh"
    456      Xpath 'q'
    457    catch /^arrgh$/
    458      Xpath 'r'
    459    endtry
    460 
    461    try
    462      Xpath 's'
    463      throw "arrgh"
    464      Xpath 't'
    465    catch /\l/
    466      Xpath 'u'
    467    endtry
    468 
    469    try
    470      Xpath 'v'
    471      throw "arrgh"
    472      Xpath 'w'
    473    catch /^\l\+$/
    474      Xpath 'x'
    475    endtry
    476 
    477    try
    478      try
    479        Xpath 'y'
    480        throw "ARRGH"
    481        Xpath 'z'
    482      catch /^arrgh$/
    483        Xpath 'A'
    484      endtry
    485    catch /^\carrgh$/
    486      Xpath 'B'
    487    endtry
    488 
    489    try
    490      Xpath 'C'
    491      throw ""
    492      Xpath 'D'
    493    catch /^$/
    494      Xpath 'E'
    495    endtry
    496 
    497  catch /.*/
    498    Xpath 'F'
    499    call assert_report('Caught ' . v:exception . ' in ' . v:throwpoint)
    500  endtry
    501 endfunc
    502 
    503 func Test_catch_number_string()
    504  XpathINIT
    505  call T42_F()
    506  call assert_equal('acdfgijlmoprsuvxyBCE', g:Xpath)
    507 endfunc
    508 
    509 
    510 "-------------------------------------------------------------------------------
    511 " Test 43:  Selecting the correct :catch clause				    {{{1
    512 "
    513 "	    When an exception is thrown and there are multiple :catch clauses,
    514 "	    the first matching one is taken.
    515 "-------------------------------------------------------------------------------
    516 
    517 func T43_F()
    518  let loops = 3
    519  while loops > 0
    520    try
    521      if loops == 3
    522        Xpath 'a' . loops
    523        throw "a"
    524        Xpath 'b' . loops
    525      elseif loops == 2
    526        Xpath 'c' . loops
    527        throw "ab"
    528        Xpath 'd' . loops
    529      elseif loops == 1
    530        Xpath 'e' . loops
    531        throw "abc"
    532        Xpath 'f' . loops
    533      endif
    534    catch /abc/
    535      Xpath 'g' . loops
    536    catch /ab/
    537      Xpath 'h' . loops
    538    catch /.*/
    539      Xpath 'i' . loops
    540    catch /a/
    541      Xpath 'j' . loops
    542    endtry
    543 
    544    let loops = loops - 1
    545  endwhile
    546  Xpath 'k'
    547 endfunc
    548 
    549 func Test_multi_catch()
    550  XpathINIT
    551  call T43_F()
    552  call assert_equal('a3i3c2h2e1g1k', g:Xpath)
    553 endfunc
    554 
    555 
    556 "-------------------------------------------------------------------------------
    557 " Test 44:  Missing or empty :catch patterns				    {{{1
    558 "
    559 "	    A missing or empty :catch pattern means the same as /.*/, that is,
    560 "	    catches everything.  To catch only empty exceptions, /^$/ must be
    561 "	    used.  A :catch with missing, empty, or /.*/ argument also works
    562 "	    when followed by another command separated by a bar on the same
    563 "	    line.  :catch patterns cannot be specified between ||.  But other
    564 "	    pattern separators can be used instead of //.
    565 "-------------------------------------------------------------------------------
    566 
    567 func T44_F()
    568  try
    569    try
    570      Xpath 'a'
    571      throw ""
    572    catch /^$/
    573      Xpath 'b'
    574    endtry
    575 
    576    try
    577      Xpath 'c'
    578      throw ""
    579    catch /.*/
    580      Xpath 'd'
    581    endtry
    582 
    583    try
    584      Xpath 'e'
    585      throw ""
    586    catch //
    587      Xpath 'f'
    588    endtry
    589 
    590    try
    591      Xpath 'g'
    592      throw ""
    593    catch
    594      Xpath 'h'
    595    endtry
    596 
    597    try
    598      Xpath 'i'
    599      throw "oops"
    600    catch /^$/
    601      Xpath 'j'
    602    catch /.*/
    603      Xpath 'k'
    604    endtry
    605 
    606    try
    607      Xpath 'l'
    608      throw "arrgh"
    609    catch /^$/
    610      Xpath 'm'
    611    catch //
    612      Xpath 'n'
    613    endtry
    614 
    615    try
    616      Xpath 'o'
    617      throw "brrr"
    618    catch /^$/
    619      Xpath 'p'
    620    catch
    621      Xpath 'q'
    622    endtry
    623 
    624    try | Xpath 'r' | throw "x" | catch /.*/ | Xpath 's' | endtry
    625 
    626    try | Xpath 't' | throw "y" | catch // | Xpath 'u' | endtry
    627 
    628    while 1
    629      try
    630        let caught = 0
    631        let v:errmsg = ""
    632        " Extra try level:  if ":catch" without arguments below raises
    633        " a syntax error because it misinterprets the "Xpath" as a pattern,
    634        " let it be caught by the ":catch /.*/" below.
    635        try
    636          try | Xpath 'v' | throw "z" | catch | Xpath 'w' | :
    637          endtry
    638        endtry
    639      catch /.*/
    640        let caught = 1
    641        call assert_report('Caught ' . v:exception . ' in ' . v:throwpoint)
    642      finally
    643        if $VIMNOERRTHROW && v:errmsg != ""
    644          call assert_report(v:errmsg)
    645        endif
    646        if caught || $VIMNOERRTHROW && v:errmsg != ""
    647          Xpath 'x'
    648        endif
    649        break		" discard error for $VIMNOERRTHROW
    650      endtry
    651    endwhile
    652 
    653    let cologne = 4711
    654    try
    655      try
    656        Xpath 'y'
    657        throw "throw cologne"
    658        " Next lines catches all and throws 4711:
    659      catch |throw cologne|
    660        Xpath 'z'
    661      endtry
    662    catch /4711/
    663      Xpath 'A'
    664    endtry
    665 
    666    try
    667      Xpath 'B'
    668      throw "plus"
    669    catch +plus+
    670      Xpath 'C'
    671    endtry
    672 
    673    Xpath 'D'
    674  catch /.*/
    675    Xpath 'E'
    676    call assert_report('Caught ' . v:exception . ' in ' . v:throwpoint)
    677  endtry
    678 endfunc
    679 
    680 func Test_empty_catch()
    681  XpathINIT
    682  call T44_F()
    683  call assert_equal('abcdefghiklnoqrstuvwyABCD', g:Xpath)
    684 endfunc
    685 
    686 
    687 "-------------------------------------------------------------------------------
    688 " Test 45:  Catching exceptions from nested :try blocks			    {{{1
    689 "
    690 "	    When :try blocks are nested, an exception is caught by the innermost
    691 "	    try conditional that has a matching :catch clause.
    692 "-------------------------------------------------------------------------------
    693 
    694 func T45_F()
    695  let loops = 3
    696  while loops > 0
    697    try
    698      try
    699        try
    700          try
    701            if loops == 3
    702              Xpath 'a' . loops
    703              throw "a"
    704              Xpath 'b' . loops
    705            elseif loops == 2
    706              Xpath 'c' . loops
    707              throw "ab"
    708              Xpath 'd' . loops
    709            elseif loops == 1
    710              Xpath 'e' . loops
    711              throw "abc"
    712              Xpath 'f' . loops
    713            endif
    714          catch /abc/
    715            Xpath 'g' . loops
    716          endtry
    717        catch /ab/
    718          Xpath 'h' . loops
    719        endtry
    720      catch /.*/
    721        Xpath 'i' . loops
    722      endtry
    723    catch /a/
    724      Xpath 'j' . loops
    725    endtry
    726 
    727    let loops = loops - 1
    728  endwhile
    729  Xpath 'k'
    730 endfunc
    731 
    732 func Test_catch_from_nested_try()
    733  XpathINIT
    734  call T45_F()
    735  call assert_equal('a3i3c2h2e1g1k', g:Xpath)
    736 endfunc
    737 
    738 
    739 "-------------------------------------------------------------------------------
    740 " Test 46:  Executing :finally after a :throw in nested :try		    {{{1
    741 "
    742 "	    When an exception is thrown from within nested :try blocks, the
    743 "	    :finally clauses of the non-catching try conditionals should be
    744 "	    executed before the matching :catch of the next surrounding :try
    745 "	    gets the control.  If this also has a :finally clause, it is
    746 "	    executed afterwards.
    747 "-------------------------------------------------------------------------------
    748 
    749 func T46_F()
    750  let sum = 0
    751 
    752  try
    753    Xpath 'a'
    754    try
    755      Xpath 'b'
    756      try
    757        Xpath 'c'
    758        try
    759          Xpath 'd'
    760          throw "ABC"
    761          Xpath 'e'
    762        catch /xyz/
    763          Xpath 'f'
    764        finally
    765          Xpath 'g'
    766          if sum != 0
    767            Xpath 'h'
    768          endif
    769          let sum = sum + 1
    770        endtry
    771        Xpath 'i'
    772      catch /123/
    773        Xpath 'j'
    774      catch /321/
    775        Xpath 'k'
    776      finally
    777        Xpath 'l'
    778        if sum != 1
    779          Xpath 'm'
    780        endif
    781        let sum = sum + 2
    782      endtry
    783      Xpath 'n'
    784    finally
    785      Xpath 'o'
    786      if sum != 3
    787        Xpath 'p'
    788      endif
    789      let sum = sum + 4
    790    endtry
    791    Xpath 'q'
    792  catch /ABC/
    793    Xpath 'r'
    794    if sum != 7
    795      Xpath 's'
    796    endif
    797    let sum = sum + 8
    798  finally
    799    Xpath 't'
    800    if sum != 15
    801      Xpath 'u'
    802    endif
    803    let sum = sum + 16
    804  endtry
    805  Xpath 'v'
    806  if sum != 31
    807    Xpath 'w'
    808  endif
    809 endfunc
    810 
    811 func Test_finally_after_throw()
    812  XpathINIT
    813  call T46_F()
    814  call assert_equal('abcdglortv', g:Xpath)
    815 endfunc
    816 
    817 
    818 "-------------------------------------------------------------------------------
    819 " Test 47:  Throwing exceptions from a :catch clause			    {{{1
    820 "
    821 "	    When an exception is thrown from a :catch clause, it should not be
    822 "	    caught by a :catch of the same :try conditional.  After executing
    823 "	    the :finally clause (if present), surrounding try conditionals
    824 "	    should be checked for a matching :catch.
    825 "-------------------------------------------------------------------------------
    826 
    827 func T47_F()
    828  Xpath 'a'
    829  try
    830    Xpath 'b'
    831    try
    832      Xpath 'c'
    833      try
    834        Xpath 'd'
    835        throw "x1"
    836        Xpath 'e'
    837      catch /x1/
    838        Xpath 'f'
    839        try
    840          Xpath 'g'
    841          throw "x2"
    842          Xpath 'h'
    843        catch /x1/
    844          Xpath 'i'
    845        catch /x2/
    846          Xpath 'j'
    847          try
    848            Xpath 'k'
    849            throw "x3"
    850            Xpath 'l'
    851          catch /x1/
    852            Xpath 'm'
    853          catch /x2/
    854            Xpath 'n'
    855          finally
    856            Xpath 'o'
    857          endtry
    858          Xpath 'p'
    859        catch /x3/
    860          Xpath 'q'
    861        endtry
    862        Xpath 'r'
    863      catch /x1/
    864        Xpath 's'
    865      catch /x2/
    866        Xpath 't'
    867      catch /x3/
    868        Xpath 'u'
    869      finally
    870        Xpath 'v'
    871      endtry
    872      Xpath 'w'
    873    catch /x1/
    874      Xpath 'x'
    875    catch /x2/
    876      Xpath 'y'
    877    catch /x3/
    878      Xpath 'z'
    879    endtry
    880    Xpath 'A'
    881  catch /.*/
    882    Xpath 'B'
    883    call assert_report('Caught ' . v:exception . ' in ' . v:throwpoint)
    884  endtry
    885  Xpath 'C'
    886 endfunc
    887 
    888 func Test_throw_from_catch()
    889  XpathINIT
    890  call T47_F()
    891  call assert_equal('abcdfgjkovzAC', g:Xpath)
    892 endfunc
    893 
    894 
    895 "-------------------------------------------------------------------------------
    896 " Test 48:  Throwing exceptions from a :finally clause			    {{{1
    897 "
    898 "	    When an exception is thrown from a :finally clause, it should not be
    899 "	    caught by a :catch of the same :try conditional.  Surrounding try
    900 "	    conditionals should be checked for a matching :catch.  A previously
    901 "	    thrown exception is discarded.
    902 "-------------------------------------------------------------------------------
    903 
    904 func T48_F()
    905  try
    906 
    907    try
    908      try
    909        Xpath 'a'
    910      catch /x1/
    911        Xpath 'b'
    912      finally
    913        Xpath 'c'
    914        throw "x1"
    915        Xpath 'd'
    916      endtry
    917      Xpath 'e'
    918    catch /x1/
    919      Xpath 'f'
    920    endtry
    921    Xpath 'g'
    922 
    923    try
    924      try
    925        Xpath 'h'
    926        throw "x2"
    927        Xpath 'i'
    928      catch /x2/
    929        Xpath 'j'
    930      catch /x3/
    931        Xpath 'k'
    932      finally
    933        Xpath 'l'
    934        throw "x3"
    935        Xpath 'm'
    936      endtry
    937      Xpath 'n'
    938    catch /x2/
    939      Xpath 'o'
    940    catch /x3/
    941      Xpath 'p'
    942    endtry
    943    Xpath 'q'
    944 
    945    try
    946      try
    947        try
    948          Xpath 'r'
    949          throw "x4"
    950          Xpath 's'
    951        catch /x5/
    952          Xpath 't'
    953        finally
    954          Xpath 'u'
    955          throw "x5"	" discards 'x4'
    956          Xpath 'v'
    957        endtry
    958        Xpath 'w'
    959      catch /x4/
    960        Xpath 'x'
    961      finally
    962        Xpath 'y'
    963      endtry
    964      Xpath 'z'
    965    catch /x5/
    966      Xpath 'A'
    967    endtry
    968    Xpath 'B'
    969 
    970  catch /.*/
    971    Xpath 'C'
    972    call assert_report('Caught ' . v:exception . ' in ' . v:throwpoint)
    973  endtry
    974  Xpath 'D'
    975 endfunc
    976 
    977 func Test_throw_from_finally()
    978  XpathINIT
    979  call T48_F()
    980  call assert_equal('acfghjlpqruyABD', g:Xpath)
    981 endfunc
    982 
    983 
    984 "-------------------------------------------------------------------------------
    985 " Test 51:  Throwing exceptions across :execute and user commands	    {{{1
    986 "
    987 "	    A :throw command may be executed under an ":execute" or from
    988 "	    a user command.
    989 "-------------------------------------------------------------------------------
    990 
    991 func T51_F()
    992  command! -nargs=? THROW1    throw <args> | throw 1
    993  command! -nargs=? THROW2    try | throw <args> | endtry | throw 2
    994  command! -nargs=? THROW3    try | throw 3 | catch /3/ | throw <args> | endtry
    995  command! -nargs=? THROW4    try | throw 4 | finally   | throw <args> | endtry
    996 
    997  try
    998 
    999    try
   1000      try
   1001        Xpath 'a'
   1002        THROW1 "A"
   1003      catch /A/
   1004        Xpath 'b'
   1005      endtry
   1006    catch /1/
   1007      Xpath 'c'
   1008    endtry
   1009 
   1010    try
   1011      try
   1012        Xpath 'd'
   1013        THROW2 "B"
   1014      catch /B/
   1015        Xpath 'e'
   1016      endtry
   1017    catch /2/
   1018      Xpath 'f'
   1019    endtry
   1020 
   1021    try
   1022      try
   1023        Xpath 'g'
   1024        THROW3 "C"
   1025      catch /C/
   1026        Xpath 'h'
   1027      endtry
   1028    catch /3/
   1029      Xpath 'i'
   1030    endtry
   1031 
   1032    try
   1033      try
   1034        Xpath 'j'
   1035        THROW4 "D"
   1036      catch /D/
   1037        Xpath 'k'
   1038      endtry
   1039    catch /4/
   1040      Xpath 'l'
   1041    endtry
   1042 
   1043    try
   1044      try
   1045        Xpath 'm'
   1046        execute 'throw "E" | throw 5'
   1047      catch /E/
   1048        Xpath 'n'
   1049      endtry
   1050    catch /5/
   1051      Xpath 'o'
   1052    endtry
   1053 
   1054    try
   1055      try
   1056        Xpath 'p'
   1057        execute 'try | throw "F" | endtry | throw 6'
   1058      catch /F/
   1059        Xpath 'q'
   1060      endtry
   1061    catch /6/
   1062      Xpath 'r'
   1063    endtry
   1064 
   1065    try
   1066      try
   1067        Xpath 's'
   1068        execute'try | throw 7 | catch /7/ | throw "G" | endtry'
   1069      catch /G/
   1070        Xpath 't'
   1071      endtry
   1072    catch /7/
   1073      Xpath 'u'
   1074    endtry
   1075 
   1076    try
   1077      try
   1078        Xpath 'v'
   1079        execute 'try | throw 8 | finally   | throw "H" | endtry'
   1080      catch /H/
   1081        Xpath 'w'
   1082      endtry
   1083    catch /8/
   1084      Xpath 'x'
   1085    endtry
   1086 
   1087  catch /.*/
   1088    Xpath 'y'
   1089    call assert_report('Caught ' . v:exception . ' in ' . v:throwpoint)
   1090  endtry
   1091 
   1092  Xpath 'z'
   1093 
   1094  delcommand THROW1
   1095  delcommand THROW2
   1096  delcommand THROW3
   1097  delcommand THROW4
   1098 endfunc
   1099 
   1100 func Test_throw_across_commands()
   1101  XpathINIT
   1102  call T51_F()
   1103  call assert_equal('abdeghjkmnpqstvwz', g:Xpath)
   1104 endfunc
   1105 
   1106 
   1107 
   1108 "-------------------------------------------------------------------------------
   1109 " Test 69:  :throw across :if, :elseif, :while				    {{{1
   1110 "
   1111 "	    On an :if, :elseif, or :while command, an exception might be thrown
   1112 "	    during evaluation of the expression to test.  The exception can be
   1113 "	    caught by the script.
   1114 "-------------------------------------------------------------------------------
   1115 
   1116 func T69_throw(x)
   1117  Xpath 'x'
   1118  throw a:x
   1119 endfunc
   1120 
   1121 func Test_throw_ifelsewhile()
   1122  XpathINIT
   1123 
   1124  try
   1125    try
   1126      Xpath 'a'
   1127      if 111 == T69_throw("if") + 111
   1128        Xpath 'b'
   1129      else
   1130        Xpath 'c'
   1131      endif
   1132      Xpath 'd'
   1133    catch /^if$/
   1134      Xpath 'e'
   1135    catch /.*/
   1136      Xpath 'f'
   1137      call assert_report("if: " . v:exception . " in " . v:throwpoint)
   1138    endtry
   1139 
   1140    try
   1141      Xpath 'g'
   1142      if v:false
   1143        Xpath 'h'
   1144      elseif 222 == T69_throw("elseif") + 222
   1145        Xpath 'i'
   1146      else
   1147        Xpath 'j'
   1148      endif
   1149      Xpath 'k'
   1150    catch /^elseif$/
   1151      Xpath 'l'
   1152    catch /.*/
   1153      Xpath 'm'
   1154      call assert_report("elseif: " . v:exception . " in " . v:throwpoint)
   1155    endtry
   1156 
   1157    try
   1158      Xpath 'n'
   1159      while 333 == T69_throw("while") + 333
   1160        Xpath 'o'
   1161        break
   1162      endwhile
   1163      Xpath 'p'
   1164    catch /^while$/
   1165      Xpath 'q'
   1166    catch /.*/
   1167      Xpath 'r'
   1168      call assert_report("while: " .. v:exception .. " in " .. v:throwpoint)
   1169    endtry
   1170  catch /^0$/	    " default return value
   1171    Xpath 's'
   1172    call assert_report(v:throwpoint)
   1173  catch /.*/
   1174    call assert_report(v:exception .. " in " .. v:throwpoint)
   1175    Xpath 't'
   1176  endtry
   1177 
   1178  call assert_equal('axegxlnxq', g:Xpath)
   1179 endfunc
   1180 
   1181 
   1182 "-------------------------------------------------------------------------------
   1183 " Test 70:  :throw across :return or :throw				    {{{1
   1184 "
   1185 "	    On a :return or :throw command, an exception might be thrown during
   1186 "	    evaluation of the expression to return or throw, respectively.  The
   1187 "	    exception can be caught by the script.
   1188 "-------------------------------------------------------------------------------
   1189 
   1190 let T70_taken = ""
   1191 
   1192 func T70_throw(x, n)
   1193    let g:T70_taken = g:T70_taken . "T" . a:n
   1194    throw a:x
   1195 endfunc
   1196 
   1197 func T70_F(x, y, n)
   1198    let g:T70_taken = g:T70_taken . "F" . a:n
   1199    return a:x + T70_throw(a:y, a:n)
   1200 endfunc
   1201 
   1202 func T70_G(x, y, n)
   1203    let g:T70_taken = g:T70_taken . "G" . a:n
   1204    throw a:x . T70_throw(a:y, a:n)
   1205    return a:x
   1206 endfunc
   1207 
   1208 func Test_throwreturn()
   1209  XpathINIT
   1210 
   1211  try
   1212    try
   1213      Xpath 'a'
   1214      call T70_F(4711, "return", 1)
   1215      Xpath 'b'
   1216    catch /^return$/
   1217      Xpath 'c'
   1218    catch /.*/
   1219      Xpath 'd'
   1220      call assert_report("return: " .. v:exception .. " in " .. v:throwpoint)
   1221    endtry
   1222 
   1223    try
   1224      Xpath 'e'
   1225      let var = T70_F(4712, "return-var", 2)
   1226      Xpath 'f'
   1227    catch /^return-var$/
   1228      Xpath 'g'
   1229    catch /.*/
   1230      Xpath 'h'
   1231      call assert_report("return-var: " . v:exception . " in " . v:throwpoint)
   1232    finally
   1233      unlet! var
   1234    endtry
   1235 
   1236    try
   1237      Xpath 'i'
   1238      throw "except1" . T70_throw("throw1", 3)
   1239      Xpath 'j'
   1240    catch /^except1/
   1241      Xpath 'k'
   1242    catch /^throw1$/
   1243      Xpath 'l'
   1244    catch /.*/
   1245      Xpath 'm'
   1246      call assert_report("throw1: " .. v:exception .. " in " .. v:throwpoint)
   1247    endtry
   1248 
   1249    try
   1250      Xpath 'n'
   1251      call T70_G("except2", "throw2", 4)
   1252      Xpath 'o'
   1253    catch /^except2/
   1254      Xpath 'p'
   1255    catch /^throw2$/
   1256      Xpath 'q'
   1257    catch /.*/
   1258      Xpath 'r'
   1259      call assert_report("throw2: " .. v:exception .. " in " .. v:throwpoint)
   1260    endtry
   1261 
   1262    try
   1263      Xpath 's'
   1264      let var = T70_G("except3", "throw3", 5)
   1265      Xpath 't'
   1266    catch /^except3/
   1267      Xpath 'u'
   1268    catch /^throw3$/
   1269      Xpath 'v'
   1270    catch /.*/
   1271      Xpath 'w'
   1272      call assert_report("throw3: " .. v:exception .. " in " .. v:throwpoint)
   1273    finally
   1274      unlet! var
   1275    endtry
   1276 
   1277    call assert_equal('F1T1F2T2T3G4T4G5T5', g:T70_taken)
   1278    Xpath 'x'
   1279  catch /^0$/	    " default return value
   1280    Xpath 'y'
   1281    call assert_report(v:throwpoint)
   1282  catch /.*/
   1283    Xpath 'z'
   1284    call assert_report('Caught' .. v:exception .. ' in ' .. v:throwpoint)
   1285  endtry
   1286 
   1287  call assert_equal('acegilnqsvx', g:Xpath)
   1288 endfunc
   1289 
   1290 "-------------------------------------------------------------------------------
   1291 " Test 71:  :throw across :echo variants and :execute			    {{{1
   1292 "
   1293 "	    On an :echo, :echon, :echomsg, :echoerr, or :execute command, an
   1294 "	    exception might be thrown during evaluation of the arguments to
   1295 "	    be displayed or executed as a command, respectively.  Any following
   1296 "	    arguments are not evaluated, then.  The exception can be caught by
   1297 "	    the script.
   1298 "-------------------------------------------------------------------------------
   1299 
   1300 let T71_taken = ""
   1301 
   1302 func T71_throw(x, n)
   1303    let g:T71_taken = g:T71_taken . "T" . a:n
   1304    throw a:x
   1305 endfunc
   1306 
   1307 func T71_F(n)
   1308    let g:T71_taken = g:T71_taken . "F" . a:n
   1309    return "F" . a:n
   1310 endfunc
   1311 
   1312 func Test_throw_echo()
   1313  XpathINIT
   1314 
   1315  try
   1316    try
   1317      Xpath 'a'
   1318      echo 'echo ' . T71_throw("echo-except", 1) . T71_F(1)
   1319      Xpath 'b'
   1320    catch /^echo-except$/
   1321      Xpath 'c'
   1322    catch /.*/
   1323      Xpath 'd'
   1324      call assert_report("echo: " .. v:exception .. " in " .. v:throwpoint)
   1325    endtry
   1326 
   1327    try
   1328      Xpath 'e'
   1329      echon "echon " . T71_throw("echon-except", 2) . T71_F(2)
   1330      Xpath 'f'
   1331    catch /^echon-except$/
   1332      Xpath 'g'
   1333    catch /.*/
   1334      Xpath 'h'
   1335      call assert_report('echon: ' . v:exception . ' in ' . v:throwpoint)
   1336    endtry
   1337 
   1338    try
   1339      Xpath 'i'
   1340      echomsg "echomsg " . T71_throw("echomsg-except", 3) . T71_F(3)
   1341      Xpath 'j'
   1342    catch /^echomsg-except$/
   1343      Xpath 'k'
   1344    catch /.*/
   1345      Xpath 'l'
   1346      call assert_report('echomsg: ' . v:exception . ' in ' . v:throwpoint)
   1347    endtry
   1348 
   1349    try
   1350      Xpath 'm'
   1351      echoerr "echoerr " . T71_throw("echoerr-except", 4) . T71_F(4)
   1352      Xpath 'n'
   1353    catch /^echoerr-except$/
   1354      Xpath 'o'
   1355    catch /Vim/
   1356      Xpath 'p'
   1357    catch /echoerr/
   1358      Xpath 'q'
   1359    catch /.*/
   1360      Xpath 'r'
   1361      call assert_report('echoerr: ' . v:exception . ' in ' . v:throwpoint)
   1362    endtry
   1363 
   1364    try
   1365      Xpath 's'
   1366      execute "echo 'execute " . T71_throw("execute-except", 5) . T71_F(5) "'"
   1367      Xpath 't'
   1368    catch /^execute-except$/
   1369      Xpath 'u'
   1370    catch /.*/
   1371      Xpath 'v'
   1372      call assert_report('execute: ' . v:exception . ' in ' . v:throwpoint)
   1373    endtry
   1374 
   1375    call assert_equal('T1T2T3T4T5', g:T71_taken)
   1376    Xpath 'w'
   1377  catch /^0$/	    " default return value
   1378    Xpath 'x'
   1379    call assert_report(v:throwpoint)
   1380  catch /.*/
   1381    Xpath 'y'
   1382    call assert_report('Caught ' . v:exception . ' in ' . v:throwpoint)
   1383  endtry
   1384 
   1385  call assert_equal('acegikmosuw', g:Xpath)
   1386 endfunc
   1387 
   1388 
   1389 "-------------------------------------------------------------------------------
   1390 " Test 72:  :throw across :let or :unlet				    {{{1
   1391 "
   1392 "	    On a :let command, an exception might be thrown during evaluation
   1393 "	    of the expression to assign.  On an :let or :unlet command, the
   1394 "	    evaluation of the name of the variable to be assigned or list or
   1395 "	    deleted, respectively, may throw an exception.  Any following
   1396 "	    arguments are not evaluated, then.  The exception can be caught by
   1397 "	    the script.
   1398 "-------------------------------------------------------------------------------
   1399 
   1400 let throwcount = 0
   1401 
   1402 func T72_throw(x)
   1403  let g:throwcount = g:throwcount + 1
   1404  throw a:x
   1405 endfunc
   1406 
   1407 let T72_addpath = ''
   1408 
   1409 func T72_addpath(p)
   1410  let g:T72_addpath = g:T72_addpath . a:p
   1411 endfunc
   1412 
   1413 func Test_throw_let()
   1414  XpathINIT
   1415 
   1416  try
   1417    try
   1418      let $VAR = 'old_value'
   1419      Xpath 'a'
   1420      let $VAR = 'let(' . T72_throw('var') . ')'
   1421      Xpath 'b'
   1422    catch /^var$/
   1423      Xpath 'c'
   1424    finally
   1425      call assert_equal('old_value', $VAR)
   1426    endtry
   1427 
   1428    try
   1429      let @a = 'old_value'
   1430      Xpath 'd'
   1431      let @a = 'let(' . T72_throw('reg') . ')'
   1432      Xpath 'e'
   1433    catch /^reg$/
   1434      try
   1435        Xpath 'f'
   1436        let @A = 'let(' . T72_throw('REG') . ')'
   1437        Xpath 'g'
   1438      catch /^REG$/
   1439        Xpath 'h'
   1440      endtry
   1441    finally
   1442      call assert_equal('old_value', @a)
   1443      call assert_equal('old_value', @A)
   1444    endtry
   1445 
   1446    try
   1447      let saved_gpath = &g:path
   1448      let saved_lpath = &l:path
   1449      Xpath 'i'
   1450      let &path = 'let(' . T72_throw('opt') . ')'
   1451      Xpath 'j'
   1452    catch /^opt$/
   1453      try
   1454        Xpath 'k'
   1455        let &g:path = 'let(' . T72_throw('gopt') . ')'
   1456        Xpath 'l'
   1457      catch /^gopt$/
   1458        try
   1459          Xpath 'm'
   1460          let &l:path = 'let(' . T72_throw('lopt') . ')'
   1461          Xpath 'n'
   1462        catch /^lopt$/
   1463          Xpath 'o'
   1464        endtry
   1465      endtry
   1466    finally
   1467      call assert_equal(saved_gpath, &g:path)
   1468      call assert_equal(saved_lpath, &l:path)
   1469      let &g:path = saved_gpath
   1470      let &l:path = saved_lpath
   1471    endtry
   1472 
   1473    unlet! var1 var2 var3
   1474 
   1475    try
   1476      Xpath 'p'
   1477      let var1 = 'let(' . T72_throw('var1') . ')'
   1478      Xpath 'q'
   1479    catch /^var1$/
   1480      Xpath 'r'
   1481    finally
   1482      call assert_true(!exists('var1'))
   1483    endtry
   1484 
   1485    try
   1486      let var2 = 'old_value'
   1487      Xpath 's'
   1488      let var2 = 'let(' . T72_throw('var2'). ')'
   1489      Xpath 't'
   1490    catch /^var2$/
   1491      Xpath 'u'
   1492    finally
   1493      call assert_equal('old_value', var2)
   1494    endtry
   1495 
   1496    try
   1497      Xpath 'v'
   1498      let var{T72_throw('var3')} = 4711
   1499      Xpath 'w'
   1500    catch /^var3$/
   1501      Xpath 'x'
   1502    endtry
   1503 
   1504    try
   1505      call T72_addpath('T1')
   1506      let var{T72_throw('var4')} var{T72_addpath('T2')} | call T72_addpath('T3')
   1507      call T72_addpath('T4')
   1508    catch /^var4$/
   1509      call T72_addpath('T5')
   1510    endtry
   1511 
   1512    try
   1513      call T72_addpath('T6')
   1514      unlet var{T72_throw('var5')} var{T72_addpath('T7')}
   1515            \ | call T72_addpath('T8')
   1516      call T72_addpath('T9')
   1517    catch /^var5$/
   1518      call T72_addpath('T10')
   1519    endtry
   1520 
   1521    call assert_equal('T1T5T6T10', g:T72_addpath)
   1522    call assert_equal(11, g:throwcount)
   1523  catch /.*/
   1524    call assert_report('Caught ' . v:exception . ' in ' . v:throwpoint)
   1525  endtry
   1526 
   1527  call assert_equal('acdfhikmoprsuvx', g:Xpath)
   1528 endfunc
   1529 
   1530 
   1531 "-------------------------------------------------------------------------------
   1532 " Test 73:  :throw across :function, :delfunction			    {{{1
   1533 "
   1534 "	    The :function and :delfunction commands may cause an expression
   1535 "	    specified in braces to be evaluated.  During evaluation, an
   1536 "	    exception might be thrown.  The exception can be caught by the
   1537 "	    script.
   1538 "-------------------------------------------------------------------------------
   1539 
   1540 let T73_taken = ''
   1541 
   1542 func T73_throw(x, n)
   1543  let g:T73_taken = g:T73_taken . 'T' . a:n
   1544  throw a:x
   1545 endfunc
   1546 
   1547 func T73_expr(x, n)
   1548  let g:T73_taken = g:T73_taken . 'E' . a:n
   1549  if a:n % 2 == 0
   1550    call T73_throw(a:x, a:n)
   1551  endif
   1552  return 2 - a:n % 2
   1553 endfunc
   1554 
   1555 func Test_throw_func()
   1556  XpathINIT
   1557 
   1558  try
   1559    try
   1560      " Define function.
   1561      Xpath 'a'
   1562      function! F0()
   1563      endfunction
   1564      Xpath 'b'
   1565      function! F{T73_expr('function-def-ok', 1)}()
   1566      endfunction
   1567      Xpath 'c'
   1568      function! F{T73_expr('function-def', 2)}()
   1569      endfunction
   1570      Xpath 'd'
   1571    catch /^function-def-ok$/
   1572      Xpath 'e'
   1573    catch /^function-def$/
   1574      Xpath 'f'
   1575    catch /.*/
   1576      call assert_report('def: ' . v:exception . ' in ' . v:throwpoint)
   1577    endtry
   1578 
   1579    try
   1580      " List function.
   1581      Xpath 'g'
   1582      function F0
   1583      Xpath 'h'
   1584      function F{T73_expr('function-lst-ok', 3)}
   1585      Xpath 'i'
   1586      function F{T73_expr('function-lst', 4)}
   1587      Xpath 'j'
   1588    catch /^function-lst-ok$/
   1589      Xpath 'k'
   1590    catch /^function-lst$/
   1591      Xpath 'l'
   1592    catch /.*/
   1593      call assert_report('lst: ' . v:exception . ' in ' . v:throwpoint)
   1594    endtry
   1595 
   1596    try
   1597      " Delete function
   1598      Xpath 'm'
   1599      delfunction F0
   1600      Xpath 'n'
   1601      delfunction F{T73_expr('function-del-ok', 5)}
   1602      Xpath 'o'
   1603      delfunction F{T73_expr('function-del', 6)}
   1604      Xpath 'p'
   1605    catch /^function-del-ok$/
   1606      Xpath 'q'
   1607    catch /^function-del$/
   1608      Xpath 'r'
   1609    catch /.*/
   1610      call assert_report('del: ' . v:exception . ' in ' . v:throwpoint)
   1611    endtry
   1612    call assert_equal('E1E2T2E3E4T4E5E6T6', g:T73_taken)
   1613  catch /.*/
   1614    call assert_report('Caught ' . v:exception . ' in ' . v:throwpoint)
   1615  endtry
   1616 
   1617  call assert_equal('abcfghilmnor', g:Xpath)
   1618 endfunc
   1619 
   1620 
   1621 "-------------------------------------------------------------------------------
   1622 " Test 74:  :throw across builtin functions and commands		    {{{1
   1623 "
   1624 "	    Some functions like exists(), searchpair() take expression
   1625 "	    arguments, other functions or commands like substitute() or
   1626 "	    :substitute cause an expression (specified in the regular
   1627 "	    expression) to be evaluated.  During evaluation an exception
   1628 "	    might be thrown.  The exception can be caught by the script.
   1629 "-------------------------------------------------------------------------------
   1630 
   1631 let T74_taken = ""
   1632 
   1633 func T74_throw(x, n)
   1634  let g:T74_taken = g:T74_taken . "T" . a:n
   1635  throw a:x
   1636 endfunc
   1637 
   1638 func T74_expr(x, n)
   1639  let g:T74_taken = g:T74_taken . "E" . a:n
   1640  call T74_throw(a:x . a:n, a:n)
   1641  return "EXPR"
   1642 endfunc
   1643 
   1644 func T74_skip(x, n)
   1645  let g:T74_taken = g:T74_taken . "S" . a:n . "(" . line(".")
   1646  let theline = getline(".")
   1647  if theline =~ "skip"
   1648    let g:T74_taken = g:T74_taken . "s)"
   1649    return 1
   1650  elseif theline =~ "throw"
   1651    let g:T74_taken = g:T74_taken . "t)"
   1652    call T74_throw(a:x . a:n, a:n)
   1653  else
   1654    let g:T74_taken = g:T74_taken . ")"
   1655    return 0
   1656  endif
   1657 endfunc
   1658 
   1659 func T74_subst(x, n)
   1660  let g:T74_taken = g:T74_taken . "U" . a:n . "(" . line(".")
   1661  let theline = getline(".")
   1662  if theline =~ "not"       " T74_subst() should not be called for this line
   1663    let g:T74_taken = g:T74_taken . "n)"
   1664    call T74_throw(a:x . a:n, a:n)
   1665  elseif theline =~ "throw"
   1666    let g:T74_taken = g:T74_taken . "t)"
   1667    call T74_throw(a:x . a:n, a:n)
   1668  else
   1669    let g:T74_taken = g:T74_taken . ")"
   1670    return "replaced"
   1671  endif
   1672 endfunc
   1673 
   1674 func Test_throw_builtin_func()
   1675  XpathINIT
   1676 
   1677  try
   1678    try
   1679      Xpath 'a'
   1680      let result = exists('*{T74_expr("exists", 1)}')
   1681      Xpath 'b'
   1682    catch /^exists1$/
   1683      Xpath 'c'
   1684      try
   1685        let result = exists('{T74_expr("exists", 2)}')
   1686        Xpath 'd'
   1687      catch /^exists2$/
   1688        Xpath 'e'
   1689      catch /.*/
   1690        call assert_report('exists2: ' . v:exception . ' in ' . v:throwpoint)
   1691      endtry
   1692    catch /.*/
   1693      call assert_report('exists1: ' . v:exception . ' in ' . v:throwpoint)
   1694    endtry
   1695 
   1696    try
   1697      let file = tempname()
   1698      exec "edit" file
   1699      call append(0, [
   1700            \ 'begin',
   1701            \ 'xx',
   1702            \ 'middle 3',
   1703            \ 'xx',
   1704            \ 'middle 5 skip',
   1705            \ 'xx',
   1706            \ 'middle 7 throw',
   1707            \ 'xx',
   1708            \ 'end'])
   1709      normal! gg
   1710      Xpath 'f'
   1711      let result = searchpair("begin", "middle", "end", '',
   1712            \ 'T74_skip("searchpair", 3)')
   1713      Xpath 'g'
   1714      let result = searchpair("begin", "middle", "end", '',
   1715            \ 'T74_skip("searchpair", 4)')
   1716      Xpath 'h'
   1717      let result = searchpair("begin", "middle", "end", '',
   1718            \ 'T74_skip("searchpair", 5)')
   1719      Xpath 'i'
   1720    catch /^searchpair[35]$/
   1721      Xpath 'j'
   1722    catch /^searchpair4$/
   1723      Xpath 'k'
   1724    catch /.*/
   1725      call assert_report('searchpair: ' . v:exception . ' in ' . v:throwpoint)
   1726    finally
   1727      bwipeout!
   1728      call delete(file)
   1729    endtry
   1730 
   1731    try
   1732      let file = tempname()
   1733      exec "edit" file
   1734      call append(0, [
   1735            \ 'subst 1',
   1736            \ 'subst 2',
   1737            \ 'not',
   1738            \ 'subst 4',
   1739            \ 'subst throw',
   1740            \ 'subst 6'])
   1741      normal! gg
   1742      Xpath 'l'
   1743      1,2substitute/subst/\=T74_subst("substitute", 6)/
   1744      try
   1745        Xpath 'm'
   1746        try
   1747          let v:errmsg = ""
   1748          3substitute/subst/\=T74_subst("substitute", 7)/
   1749        finally
   1750          if v:errmsg != ""
   1751            " If exceptions are not thrown on errors, fake the error
   1752            " exception in order to get the same execution path.
   1753            throw "faked Vim(substitute)"
   1754          endif
   1755        endtry
   1756      catch /Vim(substitute)/	    " Pattern not found ('e' flag missing)
   1757        Xpath 'n'
   1758        3substitute/subst/\=T74_subst("substitute", 8)/e
   1759        Xpath 'o'
   1760      endtry
   1761      Xpath 'p'
   1762      4,6substitute/subst/\=T74_subst("substitute", 9)/
   1763      Xpath 'q'
   1764    catch /^substitute[678]/
   1765      Xpath 'r'
   1766    catch /^substitute9/
   1767      Xpath 's'
   1768    finally
   1769      bwipeout!
   1770      call delete(file)
   1771    endtry
   1772 
   1773    try
   1774      Xpath 't'
   1775      let var = substitute("sub", "sub", '\=T74_throw("substitute()y", 10)', '')
   1776      Xpath 'u'
   1777    catch /substitute()y/
   1778      Xpath 'v'
   1779    catch /.*/
   1780      call assert_report('substitute()y: ' . v:exception . ' in '
   1781            \ . v:throwpoint)
   1782    endtry
   1783 
   1784    try
   1785      Xpath 'w'
   1786      let var = substitute("not", "sub", '\=T74_throw("substitute()n", 11)', '')
   1787      Xpath 'x'
   1788    catch /substitute()n/
   1789      Xpath 'y'
   1790    catch /.*/
   1791      call assert_report('substitute()n: ' . v:exception . ' in '
   1792            \ . v:throwpoint)
   1793    endtry
   1794 
   1795    call assert_equal('E1T1E2T2S3(3)S4(5s)S4(7t)T4U6(1)U6(2)U9(4)U9(5t)T9T10',
   1796          \ g:T74_taken)
   1797 
   1798  catch /.*/
   1799    call assert_report('Caught ' . v:exception . ' in ' . v:throwpoint)
   1800  endtry
   1801 
   1802  call assert_equal('acefgklmnopstvwx', g:Xpath)
   1803 endfunc
   1804 
   1805 
   1806 "-------------------------------------------------------------------------------
   1807 " Test 75:  Errors in builtin functions.				    {{{1
   1808 "
   1809 "	    On an error in a builtin function called inside a :try/:endtry
   1810 "	    region, the evaluation of the expression calling that function and
   1811 "	    the command containing that expression are abandoned.  The error can
   1812 "	    be caught as an exception.
   1813 "
   1814 "	    A simple :call of the builtin function is a trivial case.  If the
   1815 "	    builtin function is called in the argument list of another function,
   1816 "	    no further arguments are evaluated, and the other function is not
   1817 "	    executed.  If the builtin function is called from the argument of
   1818 "	    a :return command, the :return command is not executed.  If the
   1819 "	    builtin function is called from the argument of a :throw command,
   1820 "	    the :throw command is not executed.  The evaluation of the
   1821 "	    expression calling the builtin function is abandoned.
   1822 "-------------------------------------------------------------------------------
   1823 
   1824 func T75_F1(arg1)
   1825  Xpath 'a'
   1826 endfunc
   1827 
   1828 func T75_F2(arg1, arg2)
   1829  Xpath 'b'
   1830 endfunc
   1831 
   1832 func T75_G()
   1833  Xpath 'c'
   1834 endfunc
   1835 
   1836 func T75_H()
   1837  Xpath 'd'
   1838 endfunc
   1839 
   1840 func T75_R()
   1841  while 1
   1842    try
   1843      let caught = 0
   1844      let v:errmsg = ""
   1845      Xpath 'e'
   1846      return append(1, "s")
   1847    catch /E21/
   1848      let caught = 1
   1849    catch /.*/
   1850      Xpath 'f'
   1851    finally
   1852      Xpath 'g'
   1853      if caught || $VIMNOERRTHROW && v:errmsg =~ 'E21:'
   1854        Xpath 'h'
   1855      endif
   1856      break		" discard error for $VIMNOERRTHROW
   1857    endtry
   1858  endwhile
   1859  Xpath 'i'
   1860 endfunc
   1861 
   1862 func Test_builtin_func_error()
   1863  XpathINIT
   1864 
   1865  try
   1866    set noma	" let append() fail with "E21"
   1867 
   1868    while 1
   1869      try
   1870        let caught = 0
   1871        let v:errmsg = ""
   1872        Xpath 'j'
   1873        call append(1, "s")
   1874      catch /E21/
   1875        let caught = 1
   1876      catch /.*/
   1877        Xpath 'k'
   1878      finally
   1879        Xpath 'l'
   1880        if caught || $VIMNOERRTHROW && v:errmsg =~ 'E21:'
   1881          Xpath 'm'
   1882        endif
   1883        break		" discard error for $VIMNOERRTHROW
   1884      endtry
   1885    endwhile
   1886 
   1887    while 1
   1888      try
   1889        let caught = 0
   1890        let v:errmsg = ""
   1891        Xpath 'n'
   1892        call T75_F1('x' . append(1, "s"))
   1893      catch /E21/
   1894        let caught = 1
   1895      catch /.*/
   1896        Xpath 'o'
   1897      finally
   1898        Xpath 'p'
   1899        if caught || $VIMNOERRTHROW && v:errmsg =~ 'E21:'
   1900          Xpath 'q'
   1901        endif
   1902        break		" discard error for $VIMNOERRTHROW
   1903      endtry
   1904    endwhile
   1905 
   1906    while 1
   1907      try
   1908        let caught = 0
   1909        let v:errmsg = ""
   1910        Xpath 'r'
   1911        call T75_F2('x' . append(1, "s"), T75_G())
   1912      catch /E21/
   1913        let caught = 1
   1914      catch /.*/
   1915        Xpath 's'
   1916      finally
   1917        Xpath 't'
   1918        if caught || $VIMNOERRTHROW && v:errmsg =~ 'E21:'
   1919          Xpath 'u'
   1920        endif
   1921        break		" discard error for $VIMNOERRTHROW
   1922      endtry
   1923    endwhile
   1924 
   1925    call T75_R()
   1926 
   1927    while 1
   1928      try
   1929        let caught = 0
   1930        let v:errmsg = ""
   1931        Xpath 'v'
   1932        throw "T" . append(1, "s")
   1933      catch /E21/
   1934        let caught = 1
   1935      catch /^T.*/
   1936        Xpath 'w'
   1937      catch /.*/
   1938        Xpath 'x'
   1939      finally
   1940        Xpath 'y'
   1941        if caught || $VIMNOERRTHROW && v:errmsg =~ 'E21:'
   1942          Xpath 'z'
   1943        endif
   1944        break		" discard error for $VIMNOERRTHROW
   1945      endtry
   1946    endwhile
   1947 
   1948    while 1
   1949      try
   1950        let caught = 0
   1951        let v:errmsg = ""
   1952        Xpath 'A'
   1953        let x = "a"
   1954        let x = x . "b" . append(1, "s") . T75_H()
   1955      catch /E21/
   1956        let caught = 1
   1957      catch /.*/
   1958        Xpath 'B'
   1959      finally
   1960        Xpath 'C'
   1961        if caught || $VIMNOERRTHROW && v:errmsg =~ 'E21:'
   1962          Xpath 'D'
   1963        endif
   1964        call assert_equal('a', x)
   1965        break		" discard error for $VIMNOERRTHROW
   1966      endtry
   1967    endwhile
   1968  catch /.*/
   1969    call assert_report('Caught ' . v:exception . ' in ' . v:throwpoint)
   1970  finally
   1971    set ma&
   1972  endtry
   1973 
   1974  call assert_equal('jlmnpqrtueghivyzACD', g:Xpath)
   1975 endfunc
   1976 
   1977 func Test_reload_in_try_catch()
   1978  call writefile(['x'], 'Xreload')
   1979  set autoread
   1980  edit Xreload
   1981  tabnew
   1982  call writefile(['xx'], 'Xreload')
   1983  augroup ReLoad
   1984    au FileReadPost Xreload let x = doesnotexist
   1985    au BufReadPost Xreload let x = doesnotexist
   1986  augroup END
   1987  try
   1988    edit Xreload
   1989  catch
   1990  endtry
   1991  tabnew
   1992 
   1993  tabclose
   1994  tabclose
   1995  autocmd! ReLoad
   1996  set noautoread
   1997  bwipe! Xreload
   1998  call delete('Xreload')
   1999 endfunc
   2000 
   2001 " Test for errors with :catch, :throw, :finally                            {{{1
   2002 func Test_try_catch_errors()
   2003  call assert_fails('throw |', 'E471:')
   2004  call assert_fails("throw \n ", 'E471:')
   2005  call assert_fails('catch abc', 'E654:')
   2006  call assert_fails('try | let i = 1| finally | catch | endtry', 'E604:')
   2007  call assert_fails('finally', 'E606:')
   2008  call assert_fails('try | finally | finally | endtry', 'E607:')
   2009  call assert_fails('try | for i in range(5) | endif | endtry', 'E580:')
   2010  call assert_fails('try | while v:true | endtry', 'E170:')
   2011  call assert_fails('try | if v:true | endtry', 'E171:')
   2012 
   2013  " this was using a negative index in cstack[]
   2014  let lines =<< trim END
   2015      try
   2016      for
   2017      if
   2018      endwhile
   2019      if
   2020      finally
   2021  END
   2022  call CheckScriptFailure(lines, 'E690:')
   2023 
   2024  let lines =<< trim END
   2025      try
   2026      for
   2027      if
   2028      endwhile
   2029      if
   2030      endtry
   2031  END
   2032  call CheckScriptFailure(lines, 'E690:')
   2033 endfunc
   2034 
   2035 " Test for verbose messages with :try :catch, and :finally                 {{{1
   2036 func Test_try_catch_verbose()
   2037  " This test works only when the language is English
   2038  CheckEnglish
   2039 
   2040  set verbose=14
   2041 
   2042  " Test for verbose messages displayed when an exception is caught
   2043  redir => msg
   2044  try
   2045    echo i
   2046  catch /E121:/
   2047  finally
   2048  endtry
   2049  redir END
   2050  let expected = [
   2051        \ 'Exception thrown: Vim(echo):E121: Undefined variable: i', '',
   2052        \ 'Exception caught: Vim(echo):E121: Undefined variable: i', '',
   2053        \ 'Exception finished: Vim(echo):E121: Undefined variable: i']
   2054  call assert_equal(expected, split(msg, "\n"))
   2055 
   2056  " Test for verbose messages displayed when an exception is discarded
   2057  redir => msg
   2058  try
   2059    try
   2060      throw 'abc'
   2061    finally
   2062      throw 'xyz'
   2063    endtry
   2064  catch
   2065  endtry
   2066  redir END
   2067  let expected = [
   2068        \ 'Exception thrown: abc', '',
   2069        \ 'Exception made pending: abc', '',
   2070        \ 'Exception thrown: xyz', '',
   2071        \ 'Exception discarded: abc', '',
   2072        \ 'Exception caught: xyz', '',
   2073        \ 'Exception finished: xyz']
   2074  call assert_equal(expected, split(msg, "\n"))
   2075 
   2076  " Test for messages displayed when :throw is resumed after :finally
   2077  redir => msg
   2078  try
   2079    try
   2080      throw 'abc'
   2081    finally
   2082    endtry
   2083  catch
   2084  endtry
   2085  redir END
   2086  let expected = [
   2087        \ 'Exception thrown: abc', '',
   2088        \ 'Exception made pending: abc', '',
   2089        \ 'Exception resumed: abc', '',
   2090        \ 'Exception caught: abc', '',
   2091        \ 'Exception finished: abc']
   2092  call assert_equal(expected, split(msg, "\n"))
   2093 
   2094  " Test for messages displayed when :break is resumed after :finally
   2095  redir => msg
   2096  for i in range(1)
   2097    try
   2098      break
   2099    finally
   2100    endtry
   2101  endfor
   2102  redir END
   2103  let expected = [':break made pending', '', ':break resumed']
   2104  call assert_equal(expected, split(msg, "\n"))
   2105 
   2106  " Test for messages displayed when :continue is resumed after :finally
   2107  redir => msg
   2108  for i in range(1)
   2109    try
   2110      continue
   2111    finally
   2112    endtry
   2113  endfor
   2114  redir END
   2115  let expected = [':continue made pending', '', ':continue resumed']
   2116  call assert_equal(expected, split(msg, "\n"))
   2117 
   2118  " Test for messages displayed when :return is resumed after :finally
   2119  func Xtest()
   2120    try
   2121      return 'vim'
   2122    finally
   2123    endtry
   2124  endfunc
   2125  redir => msg
   2126  call Xtest()
   2127  redir END
   2128  let expected = [
   2129        \ 'calling Xtest()', '',
   2130        \ ':return vim made pending', '',
   2131        \ ':return vim resumed', '',
   2132        \ 'Xtest returning ''vim''', '',
   2133        \ 'continuing in Test_try_catch_verbose']
   2134  call assert_equal(expected, split(msg, "\n"))
   2135  delfunc Xtest
   2136 
   2137  " Test for messages displayed when :finish is resumed after :finally
   2138  call writefile(['try', 'finish', 'finally', 'endtry'], 'Xscript')
   2139  redir => msg
   2140  source Xscript
   2141  redir END
   2142  let expected = [
   2143        \ ':finish made pending', '',
   2144        \ ':finish resumed', '',
   2145        \ 'finished sourcing Xscript',
   2146        \ 'continuing in Test_try_catch_verbose']
   2147  call assert_equal(expected, split(msg, "\n")[1:])
   2148  call delete('Xscript')
   2149 
   2150  " Test for messages displayed when a pending :continue is discarded by an
   2151  " exception in a finally handler
   2152  redir => msg
   2153  try
   2154    for i in range(1)
   2155      try
   2156        continue
   2157      finally
   2158        throw 'abc'
   2159      endtry
   2160    endfor
   2161  catch
   2162  endtry
   2163  redir END
   2164  let expected = [
   2165        \ ':continue made pending', '',
   2166        \ 'Exception thrown: abc', '',
   2167        \ ':continue discarded', '',
   2168        \ 'Exception caught: abc', '',
   2169        \ 'Exception finished: abc']
   2170  call assert_equal(expected, split(msg, "\n"))
   2171 
   2172  set verbose&
   2173 endfunc
   2174 
   2175 " Test for throwing an exception from a BufEnter autocmd                   {{{1
   2176 func Test_BufEnter_exception()
   2177  augroup bufenter_exception
   2178    au!
   2179    autocmd BufEnter Xfile1 throw 'abc'
   2180  augroup END
   2181 
   2182  let caught_abc = 0
   2183  try
   2184    sp Xfile1
   2185  catch /^abc/
   2186    let caught_abc = 1
   2187  endtry
   2188  call assert_equal(1, caught_abc)
   2189  call assert_equal(1, winnr('$'))
   2190 
   2191  augroup bufenter_exception
   2192    au!
   2193  augroup END
   2194  augroup! bufenter_exception
   2195  %bwipe!
   2196 
   2197  " Test for recursively throwing exceptions in autocmds
   2198  augroup bufenter_exception
   2199    au!
   2200    autocmd BufEnter Xfile1 throw 'bufenter'
   2201    autocmd BufLeave Xfile1 throw 'bufleave'
   2202  augroup END
   2203 
   2204  let ex_count = 0
   2205  try
   2206    try
   2207      sp Xfile1
   2208    catch /^bufenter/
   2209      let ex_count += 1
   2210    endtry
   2211  catch /^bufleave/
   2212      let ex_count += 10
   2213  endtry
   2214  call assert_equal(10, ex_count)
   2215  call assert_equal(2, winnr('$'))
   2216 
   2217  augroup bufenter_exception
   2218    au!
   2219  augroup END
   2220  augroup! bufenter_exception
   2221  %bwipe!
   2222 endfunc
   2223 
   2224 " Test for using try/catch when lines are joined by "|" or "\n"           {{{1
   2225 func Test_try_catch_nextcmd()
   2226  func Throw()
   2227    throw "Failure"
   2228  endfunc
   2229 
   2230  let lines =<< trim END
   2231    try
   2232      let s:x = Throw()
   2233    catch
   2234      let g:caught = 1
   2235    endtry
   2236  END
   2237 
   2238  let g:caught = 0
   2239  call execute(lines)
   2240  call assert_equal(1, g:caught)
   2241 
   2242  let g:caught = 0
   2243  call execute(join(lines, '|'))
   2244  call assert_equal(1, g:caught)
   2245 
   2246  let g:caught = 0
   2247  call execute(join(lines, "\n"))
   2248  call assert_equal(1, g:caught)
   2249 
   2250  unlet g:caught
   2251  delfunc Throw
   2252 endfunc
   2253 
   2254 " Test for using try/catch in a user command with a failing expression    {{{1
   2255 func Test_user_command_try_catch()
   2256  let lines =<< trim END
   2257      function s:throw() abort
   2258        throw 'error'
   2259      endfunction
   2260 
   2261      command! Execute
   2262      \   try
   2263      \ |   let s:x = s:throw()
   2264      \ | catch
   2265      \ |   let g:caught = 'caught'
   2266      \ | endtry
   2267 
   2268      let g:caught = 'no'
   2269      Execute
   2270      call assert_equal('caught', g:caught)
   2271  END
   2272  call writefile(lines, 'XtestTryCatch')
   2273  source XtestTryCatch
   2274 
   2275  call delete('XtestTryCatch')
   2276  unlet g:caught
   2277 endfunc
   2278 
   2279 " Test for using throw in a called function with following error    {{{1
   2280 func Test_user_command_throw_in_function_call()
   2281  let lines =<< trim END
   2282      function s:get_dict() abort
   2283        throw 'my_error'
   2284      endfunction
   2285 
   2286      try
   2287        call s:get_dict().foo()
   2288      catch /my_error/
   2289        let caught = 'yes'
   2290      catch
   2291        let caught = v:exception
   2292      endtry
   2293      call assert_equal('yes', caught)
   2294  END
   2295  call writefile(lines, 'XtestThrow')
   2296  source XtestThrow
   2297 
   2298  call delete('XtestThrow')
   2299  unlet g:caught
   2300 endfunc
   2301 
   2302 " Test that after reporting an uncaught exception there is no error for a
   2303 " missing :endif
   2304 func Test_after_exception_no_endif_error()
   2305  function Throw()
   2306    throw "Failure"
   2307  endfunction
   2308 
   2309  function Foo()
   2310    if 1
   2311      call Throw()
   2312    endif
   2313  endfunction
   2314  call assert_fails('call Foo()', ['E605:', 'E605:'])
   2315  delfunc Throw
   2316  delfunc Foo
   2317 endfunc
   2318 
   2319 " Test for using throw in a called function with following endtry    {{{1
   2320 func Test_user_command_function_call_with_endtry()
   2321  let lines =<< trim END
   2322      funct s:throw(msg) abort
   2323        throw a:msg
   2324      endfunc
   2325      func s:main() abort
   2326        try
   2327          try
   2328            throw 'err1'
   2329          catch
   2330            call s:throw('err2') | endtry
   2331          catch
   2332            let s:caught = 'yes'
   2333        endtry
   2334      endfunc
   2335 
   2336      call s:main()
   2337      call assert_equal('yes', s:caught)
   2338  END
   2339  call writefile(lines, 'XtestThrow')
   2340  source XtestThrow
   2341 
   2342  call delete('XtestThrow')
   2343 endfunc
   2344 
   2345 func ThisWillFail()
   2346 
   2347 endfunc
   2348 
   2349 " This was crashing prior to the fix in 8.2.3478.
   2350 func Test_error_in_catch_and_finally()
   2351  let lines =<< trim END
   2352    try
   2353      echo x
   2354    catch
   2355      for l in []
   2356    finally
   2357  END
   2358  call writefile(lines, 'XtestCatchAndFinally')
   2359  try
   2360    source XtestCatchAndFinally
   2361  catch /E600:/
   2362  endtry
   2363 
   2364  call delete('XtestCatchAndFinally')
   2365 endfunc
   2366 
   2367 " This was causing an illegal memory access
   2368 func Test_leave_block_in_endtry_not_called()
   2369  let lines =<< trim END
   2370      " vim9script
   2371      " try #
   2372      try "
   2373      for x in []
   2374      if
   2375      endwhile
   2376      if
   2377      endtry
   2378  END
   2379  call writefile(lines, 'XtestEndtry')
   2380  try
   2381    source XtestEndtry
   2382  catch /E171:/
   2383  endtry
   2384 
   2385  call delete('XtestEndtry')
   2386 endfunc
   2387 
   2388 " Modeline								    {{{1
   2389 " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker