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