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