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