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