To: vim_dev@googlegroups.com Subject: Patch 8.0.0360 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.0.0360 Problem: Sometimes VimL is used, which is confusing. Solution: Consistently use "Vim script". (Hirohito Higashi) Files: runtime/doc/if_mzsch.txt, runtime/doc/if_pyth.txt, runtime/doc/syntax.txt, runtime/doc/usr_02.txt, runtime/doc/version7.txt, src/Makefile, src/eval.c, src/ex_getln.c, src/if_py_both.h, src/if_xcmdsrv.c, src/testdir/Make_all.mak, src/testdir/runtest.vim, src/testdir/test49.vim, src/testdir/test_vimscript.vim, src/testdir/test_viml.vim *** ../vim-8.0.0359/runtime/doc/if_mzsch.txt 2016-09-12 12:45:25.000000000 +0200 --- runtime/doc/if_mzsch.txt 2017-02-23 18:49:31.945088705 +0100 *************** *** 249,255 **** 5. mzeval() Vim function *mzscheme-mzeval* To facilitate bi-directional interface, you can use |mzeval()| function to ! evaluate MzScheme expressions and pass their values to VimL. ============================================================================== 6. Using Function references *mzscheme-funcref* --- 249,255 ---- 5. mzeval() Vim function *mzscheme-mzeval* To facilitate bi-directional interface, you can use |mzeval()| function to ! evaluate MzScheme expressions and pass their values to Vim script. ============================================================================== 6. Using Function references *mzscheme-funcref* *** ../vim-8.0.0359/runtime/doc/if_pyth.txt 2017-01-28 15:58:45.336197327 +0100 --- runtime/doc/if_pyth.txt 2017-02-23 18:49:31.945088705 +0100 *************** *** 676,686 **** dictionary. Note that explicit `self` keyword used when calling resulting object overrides this attribute. auto_rebind Boolean. True if partial created from this Python object ! and stored in the VimL dictionary should be automatically ! rebound to the dictionary it is stored in when this ! dictionary is indexed. Exposes Vim internal difference ! between `dict.func` (auto_rebind=True) and ! `function(dict.func,dict)` (auto_rebind=False). This attribute makes no sense if `self` attribute is `None`. Constructor additionally accepts `args`, `self` and `auto_rebind` --- 676,686 ---- dictionary. Note that explicit `self` keyword used when calling resulting object overrides this attribute. auto_rebind Boolean. True if partial created from this Python object ! and stored in the Vim script dictionary should be ! automatically rebound to the dictionary it is stored in ! when this dictionary is indexed. Exposes Vim internal ! difference between `dict.func` (auto_rebind=True) and ! `function(dict.func,dict)` (auto_rebind=False). This attribute makes no sense if `self` attribute is `None`. Constructor additionally accepts `args`, `self` and `auto_rebind` *************** *** 711,717 **** 8. pyeval() and py3eval() Vim functions *python-pyeval* To facilitate bi-directional interface, you can use |pyeval()| and |py3eval()| ! functions to evaluate Python expressions and pass their values to VimL. |pyxeval()| is also available. ============================================================================== --- 711,717 ---- 8. pyeval() and py3eval() Vim functions *python-pyeval* To facilitate bi-directional interface, you can use |pyeval()| and |py3eval()| ! functions to evaluate Python expressions and pass their values to Vim script. |pyxeval()| is also available. ============================================================================== *** ../vim-8.0.0359/runtime/doc/syntax.txt 2016-09-12 13:39:47.000000000 +0200 --- runtime/doc/syntax.txt 2017-02-23 18:49:31.949088680 +0100 *************** *** 3322,3329 **** g:vimsyn_folding =~ 't' : fold tcl script < *g:vimsyn_noerror* ! Not all error highlighting that syntax/vim.vim does may be correct; VimL is a ! difficult language to highlight correctly. A way to suppress error highlighting is to put the following line in your |vimrc|: > let g:vimsyn_noerror = 1 --- 3327,3334 ---- g:vimsyn_folding =~ 't' : fold tcl script < *g:vimsyn_noerror* ! Not all error highlighting that syntax/vim.vim does may be correct; Vim script ! is a difficult language to highlight correctly. A way to suppress error highlighting is to put the following line in your |vimrc|: > let g:vimsyn_noerror = 1 *** ../vim-8.0.0359/runtime/doc/usr_02.txt 2016-09-12 12:45:48.000000000 +0200 --- runtime/doc/usr_02.txt 2017-02-23 18:49:31.949088680 +0100 *************** *** 589,595 **** register: > :help quote: ! 13) Vim Script (VimL) is available at > :help eval.txt < Certain aspects of the language are available at :h expr-X where "X" is a single letter. E.g. > --- 589,595 ---- register: > :help quote: ! 13) Vim script is available at > :help eval.txt < Certain aspects of the language are available at :h expr-X where "X" is a single letter. E.g. > *************** *** 599,608 **** Also important is > :help function-list < to find a short description of all functions available. Help topics for ! VimL functions always include the "()", so: > :help append() ! < talks about the append VimL function rather than how to append text in the ! current buffer. 14) Mappings are talked about in the help page :h |map.txt|. Use > :help mapmode-i --- 599,608 ---- Also important is > :help function-list < to find a short description of all functions available. Help topics for ! Vim script functions always include the "()", so: > :help append() ! < talks about the append Vim script function rather than how to append text ! in the current buffer. 14) Mappings are talked about in the help page :h |map.txt|. Use > :help mapmode-i *** ../vim-8.0.0359/runtime/doc/version7.txt 2016-09-12 12:45:49.000000000 +0200 --- runtime/doc/version7.txt 2017-02-23 18:49:31.949088680 +0100 *************** *** 10202,10208 **** interfaces to some extent. Extent will be improved in the future. Added special |python-vars| objects also available for |python-buffer| and ! |python-window|. They ease access to VimL variables from Python. Now you no longer need to alter `sys.path` to import your module: special hooks are responsible for importing from {rtp}/python2, {rtp}/python3 and --- 10202,10208 ---- interfaces to some extent. Extent will be improved in the future. Added special |python-vars| objects also available for |python-buffer| and ! |python-window|. They ease access to Vim script variables from Python. Now you no longer need to alter `sys.path` to import your module: special hooks are responsible for importing from {rtp}/python2, {rtp}/python3 and *** ../vim-8.0.0359/src/Makefile 2017-02-23 18:46:24.462288941 +0100 --- src/Makefile 2017-02-23 18:49:31.953088654 +0100 *************** *** 2213,2219 **** test_usercommands \ test_utf8 \ test_viminfo \ ! test_viml \ test_visual \ test_window_cmd \ test_window_id \ --- 2213,2219 ---- test_usercommands \ test_utf8 \ test_viminfo \ ! test_vimscript \ test_visual \ test_window_cmd \ test_window_id \ *** ../vim-8.0.0359/src/eval.c 2017-02-23 14:25:13.210370073 +0100 --- src/eval.c 2017-02-23 18:49:31.953088654 +0100 *************** *** 950,956 **** /* ! * Call some vimL function and return the result in "*rettv". * Uses argv[argc] for the function arguments. Only Number and String * arguments are currently supported. * Returns OK or FAIL. --- 950,956 ---- /* ! * Call some Vim script function and return the result in "*rettv". * Uses argv[argc] for the function arguments. Only Number and String * arguments are currently supported. * Returns OK or FAIL. *************** *** 1027,1033 **** } /* ! * Call vimL function "func" and return the result as a number. * Returns -1 when calling the function fails. * Uses argv[argc] for the function arguments. */ --- 1027,1033 ---- } /* ! * Call Vim script function "func" and return the result as a number. * Returns -1 when calling the function fails. * Uses argv[argc] for the function arguments. */ *************** *** 1055,1061 **** # if (defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL)) || defined(PROTO) /* ! * Call vimL function "func" and return the result as a string. * Returns NULL when calling the function fails. * Uses argv[argc] for the function arguments. */ --- 1055,1061 ---- # if (defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL)) || defined(PROTO) /* ! * Call Vim script function "func" and return the result as a string. * Returns NULL when calling the function fails. * Uses argv[argc] for the function arguments. */ *************** *** 1080,1086 **** # endif /* ! * Call vimL function "func" and return the result as a List. * Uses argv[argc] for the function arguments. * Returns NULL when there is something wrong. */ --- 1080,1086 ---- # endif /* ! * Call Vim script function "func" and return the result as a List. * Uses argv[argc] for the function arguments. * Returns NULL when there is something wrong. */ *** ../vim-8.0.0359/src/ex_getln.c 2017-02-09 18:25:09.151838714 +0100 --- src/ex_getln.c 2017-02-23 18:49:31.953088654 +0100 *************** *** 5140,5147 **** static void * call_user_expand_func(void *(*user_expand_func)(char_u *, int, char_u **, int), expand_T *xp, int *num_file, char_u ***file); /* ! * Call "user_expand_func()" to invoke a user defined VimL function and return ! * the result (either a string or a List). */ static void * call_user_expand_func( --- 5140,5147 ---- static void * call_user_expand_func(void *(*user_expand_func)(char_u *, int, char_u **, int), expand_T *xp, int *num_file, char_u ***file); /* ! * Call "user_expand_func()" to invoke a user defined Vim script function and ! * return the result (either a string or a List). */ static void * call_user_expand_func( *** ../vim-8.0.0359/src/if_py_both.h 2017-01-29 21:30:48.332627641 +0100 --- src/if_py_both.h 2017-02-23 18:49:31.953088654 +0100 *************** *** 582,590 **** VimTryEnd(void) { --trylevel; ! /* Without this it stops processing all subsequent VimL commands and ! * generates strange error messages if I e.g. try calling Test() in a ! * cycle */ did_emsg = FALSE; /* Keyboard interrupt should be preferred over anything else */ if (got_int) --- 582,590 ---- VimTryEnd(void) { --trylevel; ! /* Without this it stops processing all subsequent Vim script commands and ! * generates strange error messages if I e.g. try calling Test() in a cycle ! */ did_emsg = FALSE; /* Keyboard interrupt should be preferred over anything else */ if (got_int) *************** *** 625,631 **** discard_current_exception(); return -1; } ! /* Finally transform VimL exception to python one */ else { PyErr_SetVim((char *)current_exception->value); --- 625,631 ---- discard_current_exception(); return -1; } ! /* Finally transform Vim script exception to python one */ else { PyErr_SetVim((char *)current_exception->value); *** ../vim-8.0.0359/src/if_xcmdsrv.c 2016-08-29 22:42:20.000000000 +0200 --- src/if_xcmdsrv.c 2017-02-23 18:49:31.953088654 +0100 *************** *** 1449,1456 **** char_u *enc; /* ! * This is a (n)otification. Sent with serverreply_send in VimL. ! * Execute any autocommand and save it for later retrieval */ p += 2; gotWindow = 0; --- 1449,1456 ---- char_u *enc; /* ! * This is a (n)otification. Sent with serverreply_send in Vim ! * script. Execute any autocommand and save it for later retrieval */ p += 2; gotWindow = 0; *** ../vim-8.0.0359/src/testdir/Make_all.mak 2017-02-23 18:46:24.462288941 +0100 --- src/testdir/Make_all.mak 2017-02-23 18:49:31.953088654 +0100 *************** *** 199,205 **** test_undo.res \ test_usercommands.res \ test_viminfo.res \ ! test_viml.res \ test_visual.res \ test_window_id.res \ test_writefile.res \ --- 199,205 ---- test_undo.res \ test_usercommands.res \ test_viminfo.res \ ! test_vimscript.res \ test_visual.res \ test_window_id.res \ test_writefile.res \ *** ../vim-8.0.0359/src/testdir/runtest.vim 2017-02-01 23:17:30.909975952 +0100 --- src/testdir/runtest.vim 2017-02-23 18:49:31.953088654 +0100 *************** *** 147,153 **** let s:errors = [] let s:messages = [] let s:skipped = [] ! if expand('%') =~ 'test_viml.vim' " this test has intentional s:errors, don't use try/catch. source % else --- 147,153 ---- let s:errors = [] let s:messages = [] let s:skipped = [] ! if expand('%') =~ 'test_vimscript.vim' " this test has intentional s:errors, don't use try/catch. source % else *** ../vim-8.0.0359/src/testdir/test49.vim 2016-02-07 20:24:49.000000000 +0100 --- src/testdir/test49.vim 2017-02-23 18:49:31.957088629 +0100 *************** *** 608,614 **** " END_OF_TEST_ENVIRONMENT - do not change or remove this line. ! " Tests 1 to 15 were moved to test_viml.vim let Xtest = 16 "------------------------------------------------------------------------------- --- 608,614 ---- " END_OF_TEST_ENVIRONMENT - do not change or remove this line. ! " Tests 1 to 15 were moved to test_vimscript.vim let Xtest = 16 "------------------------------------------------------------------------------- *** ../vim-8.0.0359/src/testdir/test_vimscript.vim 2017-02-23 18:57:49.325919004 +0100 --- src/testdir/test_vimscript.vim 2017-02-23 18:49:31.957088629 +0100 *************** *** 0 **** --- 1,1316 ---- + " Test various aspects of the Vim script language. + " Most of this was formerly in test49. + + "------------------------------------------------------------------------------- + " Test environment {{{1 + "------------------------------------------------------------------------------- + + com! XpathINIT let g:Xpath = '' + com! -nargs=1 -bar Xpath let g:Xpath = g:Xpath . + + " Append a message to the "messages" file + func! Xout(text) + split messages + $put =a:text + wq + endfunc + + com! -nargs=1 Xout call Xout() + + " MakeScript() - Make a script file from a function. {{{2 + " + " Create a script that consists of the body of the function a:funcname. + " Replace any ":return" by a ":finish", any argument variable by a global + " variable, and and every ":call" by a ":source" for the next following argument + " in the variable argument list. This function is useful if similar tests are + " to be made for a ":return" from a function call or a ":finish" in a script + " file. + function! MakeScript(funcname, ...) + let script = tempname() + execute "redir! >" . script + execute "function" a:funcname + redir END + execute "edit" script + " Delete the "function" and the "endfunction" lines. Do not include the + " word "function" in the pattern since it might be translated if LANG is + " set. When MakeScript() is being debugged, this deletes also the debugging + " output of its line 3 and 4. + exec '1,/.*' . a:funcname . '(.*)/d' + /^\d*\s*endfunction\>/,$d + %s/^\d*//e + %s/return/finish/e + %s/\ 0 + let cnt = cnt + 1 + s/\) + + + "------------------------------------------------------------------------------- + " Test 1: :endwhile in function {{{1 + " + " Detect if a broken loop is (incorrectly) reactivated by the + " :endwhile. Use a :return to prevent an endless loop, and make + " this test first to get a meaningful result on an error before other + " tests will hang. + "------------------------------------------------------------------------------- + + function! T1_F() + Xpath 'a' + let first = 1 + while 1 + Xpath 'b' + if first + Xpath 'c' + let first = 0 + break + else + Xpath 'd' + return + endif + endwhile + endfunction + + function! T1_G() + Xpath 'h' + let first = 1 + while 1 + Xpath 'i' + if first + Xpath 'j' + let first = 0 + break + else + Xpath 'k' + return + endif + if 1 " unmatched :if + endwhile + endfunction + + func Test_endwhile_function() + XpathINIT + call T1_F() + Xpath 'F' + + try + call T1_G() + catch + " Catch missing :endif + call assert_true(v:exception =~ 'E171') + Xpath 'x' + endtry + Xpath 'G' + + call assert_equal('abcFhijxG', g:Xpath) + endfunc + + "------------------------------------------------------------------------------- + " Test 2: :endwhile in script {{{1 + " + " Detect if a broken loop is (incorrectly) reactivated by the + " :endwhile. Use a :finish to prevent an endless loop, and place + " this test before others that might hang to get a meaningful result + " on an error. + " + " This test executes the bodies of the functions T1_F and T1_G from + " the previous test as script files (:return replaced by :finish). + "------------------------------------------------------------------------------- + + func Test_endwhile_script() + XpathINIT + ExecAsScript T1_F + Xpath 'F' + call DeleteTheScript() + + try + ExecAsScript T1_G + catch + " Catch missing :endif + call assert_true(v:exception =~ 'E171') + Xpath 'x' + endtry + Xpath 'G' + call DeleteTheScript() + + call assert_equal('abcFhijxG', g:Xpath) + endfunc + + "------------------------------------------------------------------------------- + " Test 3: :if, :elseif, :while, :continue, :break {{{1 + "------------------------------------------------------------------------------- + + function Test_if_while() + XpathINIT + if 1 + Xpath 'a' + let loops = 3 + while loops > -1 " main loop: loops == 3, 2, 1 (which breaks) + if loops <= 0 + let break_err = 1 + let loops = -1 + else + Xpath 'b' . loops + endif + if (loops == 2) + while loops == 2 " dummy loop + Xpath 'c' . loops + let loops = loops - 1 + continue " stop dummy loop + Xpath 'd' . loops + endwhile + continue " continue main loop + Xpath 'e' . loops + elseif (loops == 1) + let p = 1 + while p " dummy loop + Xpath 'f' . loops + let p = 0 + break " break dummy loop + Xpath 'g' . loops + endwhile + Xpath 'h' . loops + unlet p + break " break main loop + Xpath 'i' . loops + endif + if (loops > 0) + Xpath 'j' . loops + endif + while loops == 3 " dummy loop + let loops = loops - 1 + endwhile " end dummy loop + endwhile " end main loop + Xpath 'k' + else + Xpath 'l' + endif + Xpath 'm' + if exists("break_err") + Xpath 'm' + unlet break_err + endif + + unlet loops + + call assert_equal('ab3j3b2c2b1f1h1km', g:Xpath) + endfunc + + "------------------------------------------------------------------------------- + " Test 4: :return {{{1 + "------------------------------------------------------------------------------- + + function! T4_F() + if 1 + Xpath 'a' + let loops = 3 + while loops > 0 " 3: 2: 1: + Xpath 'b' . loops + if (loops == 2) + Xpath 'c' . loops + return + Xpath 'd' . loops + endif + Xpath 'e' . loops + let loops = loops - 1 + endwhile + Xpath 'f' + else + Xpath 'g' + endif + endfunction + + function Test_return() + XpathINIT + call T4_F() + Xpath '4' + + call assert_equal('ab3e3b2c24', g:Xpath) + endfunction + + + "------------------------------------------------------------------------------- + " Test 5: :finish {{{1 + " + " This test executes the body of the function T4_F from the previous + " test as a script file (:return replaced by :finish). + "------------------------------------------------------------------------------- + + function Test_finish() + XpathINIT + ExecAsScript T4_F + Xpath '5' + call DeleteTheScript() + + call assert_equal('ab3e3b2c25', g:Xpath) + endfunction + + + + "------------------------------------------------------------------------------- + " Test 6: Defining functions in :while loops {{{1 + " + " Functions can be defined inside other functions. An inner function + " gets defined when the outer function is executed. Functions may + " also be defined inside while loops. Expressions in braces for + " defining the function name are allowed. + " + " The functions are defined when sourcing the script, only the + " resulting path is checked in the test function. + "------------------------------------------------------------------------------- + + XpathINIT + + " The command CALL collects the argument of all its invocations in "calls" + " when used from a function (that is, when the global variable "calls" needs + " the "g:" prefix). This is to check that the function code is skipped when + " the function is defined. For inner functions, do so only if the outer + " function is not being executed. + " + let calls = "" + com! -nargs=1 CALL + \ if !exists("calls") && !exists("outer") | + \ let g:calls = g:calls . | + \ endif + + let i = 0 + while i < 3 + let i = i + 1 + if i == 1 + Xpath 'a' + function! F1(arg) + CALL a:arg + let outer = 1 + + let j = 0 + while j < 1 + Xpath 'b' + let j = j + 1 + function! G1(arg) + CALL a:arg + endfunction + Xpath 'c' + endwhile + endfunction + Xpath 'd' + + continue + endif + + Xpath 'e' . i + function! F{i}(i, arg) + CALL a:arg + let outer = 1 + + if a:i == 3 + Xpath 'f' + endif + let k = 0 + while k < 3 + Xpath 'g' . k + let k = k + 1 + function! G{a:i}{k}(arg) + CALL a:arg + endfunction + Xpath 'h' . k + endwhile + endfunction + Xpath 'i' + + endwhile + + if exists("*G1") + Xpath 'j' + endif + if exists("*F1") + call F1("F1") + if exists("*G1") + call G1("G1") + endif + endif + + if exists("G21") || exists("G22") || exists("G23") + Xpath 'k' + endif + if exists("*F2") + call F2(2, "F2") + if exists("*G21") + call G21("G21") + endif + if exists("*G22") + call G22("G22") + endif + if exists("*G23") + call G23("G23") + endif + endif + + if exists("G31") || exists("G32") || exists("G33") + Xpath 'l' + endif + if exists("*F3") + call F3(3, "F3") + if exists("*G31") + call G31("G31") + endif + if exists("*G32") + call G32("G32") + endif + if exists("*G33") + call G33("G33") + endif + endif + + Xpath 'm' + + let g:test6_result = g:Xpath + let g:test6_calls = calls + + unlet calls + delfunction F1 + delfunction G1 + delfunction F2 + delfunction G21 + delfunction G22 + delfunction G23 + delfunction G31 + delfunction G32 + delfunction G33 + + function Test_defining_functions() + call assert_equal('ade2ie3ibcg0h1g1h2g2h3fg0h1g1h2g2h3m', g:test6_result) + call assert_equal('F1G1F2G21G22G23F3G31G32G33', g:test6_calls) + endfunc + + "------------------------------------------------------------------------------- + " Test 7: Continuing on errors outside functions {{{1 + " + " On an error outside a function, the script processing continues + " at the line following the outermost :endif or :endwhile. When not + " inside an :if or :while, the script processing continues at the next + " line. + "------------------------------------------------------------------------------- + + XpathINIT + + if 1 + Xpath 'a' + while 1 + Xpath 'b' + asdf + Xpath 'c' + break + endwhile | Xpath 'd' + Xpath 'e' + endif | Xpath 'f' + Xpath 'g' + + while 1 + Xpath 'h' + if 1 + Xpath 'i' + asdf + Xpath 'j' + endif | Xpath 'k' + Xpath 'l' + break + endwhile | Xpath 'm' + Xpath 'n' + + asdf + Xpath 'o' + + asdf | Xpath 'p' + Xpath 'q' + + let g:test7_result = g:Xpath + + func Test_error_in_script() + call assert_equal('abghinoq', g:test7_result) + endfunc + + "------------------------------------------------------------------------------- + " Test 8: Aborting and continuing on errors inside functions {{{1 + " + " On an error inside a function without the "abort" attribute, the + " script processing continues at the next line (unless the error was + " in a :return command). On an error inside a function with the + " "abort" attribute, the function is aborted and the script processing + " continues after the function call; the value -1 is returned then. + "------------------------------------------------------------------------------- + + XpathINIT + + function! T8_F() + if 1 + Xpath 'a' + while 1 + Xpath 'b' + asdf + Xpath 'c' + asdf | Xpath 'd' + Xpath 'e' + break + endwhile + Xpath 'f' + endif | Xpath 'g' + Xpath 'h' + + while 1 + Xpath 'i' + if 1 + Xpath 'j' + asdf + Xpath 'k' + asdf | Xpath 'l' + Xpath 'm' + endif + Xpath 'n' + break + endwhile | Xpath 'o' + Xpath 'p' + + return novar " returns (default return value 0) + Xpath 'q' + return 1 " not reached + endfunction + + function! T8_G() abort + if 1 + Xpath 'r' + while 1 + Xpath 's' + asdf " returns -1 + Xpath 't' + break + endwhile + Xpath 'v' + endif | Xpath 'w' + Xpath 'x' + + return -4 " not reached + endfunction + + function! T8_H() abort + while 1 + Xpath 'A' + if 1 + Xpath 'B' + asdf " returns -1 + Xpath 'C' + endif + Xpath 'D' + break + endwhile | Xpath 'E' + Xpath 'F' + + return -4 " not reached + endfunction + + " Aborted functions (T8_G and T8_H) return -1. + let g:test8_sum = (T8_F() + 1) - 4 * T8_G() - 8 * T8_H() + Xpath 'X' + let g:test8_result = g:Xpath + + func Test_error_in_function() + call assert_equal(13, g:test8_sum) + call assert_equal('abcefghijkmnoprsABX', g:test8_result) + + delfunction T8_F + delfunction T8_G + delfunction T8_H + endfunc + + + "------------------------------------------------------------------------------- + " Test 9: Continuing after aborted functions {{{1 + " + " When a function with the "abort" attribute is aborted due to an + " error, the next function back in the call hierarchy without an + " "abort" attribute continues; the value -1 is returned then. + "------------------------------------------------------------------------------- + + XpathINIT + + function! F() abort + Xpath 'a' + let result = G() " not aborted + Xpath 'b' + if result != 2 + Xpath 'c' + endif + return 1 + endfunction + + function! G() " no abort attribute + Xpath 'd' + if H() != -1 " aborted + Xpath 'e' + endif + Xpath 'f' + return 2 + endfunction + + function! H() abort + Xpath 'g' + call I() " aborted + Xpath 'h' + return 4 + endfunction + + function! I() abort + Xpath 'i' + asdf " error + Xpath 'j' + return 8 + endfunction + + if F() != 1 + Xpath 'k' + endif + + let g:test9_result = g:Xpath + + delfunction F + delfunction G + delfunction H + delfunction I + + func Test_func_abort() + call assert_equal('adgifb', g:test9_result) + endfunc + + + "------------------------------------------------------------------------------- + " Test 10: :if, :elseif, :while argument parsing {{{1 + " + " A '"' or '|' in an argument expression must not be mixed up with + " a comment or a next command after a bar. Parsing errors should + " be recognized. + "------------------------------------------------------------------------------- + + XpathINIT + + function! MSG(enr, emsg) + let english = v:lang == "C" || v:lang =~ '^[Ee]n' + if a:enr == "" + Xout "TODO: Add message number for:" a:emsg + let v:errmsg = ":" . v:errmsg + endif + let match = 1 + if v:errmsg !~ '^'.a:enr.':' || (english && v:errmsg !~ a:emsg) + let match = 0 + if v:errmsg == "" + Xout "Message missing." + else + let v:errmsg = escape(v:errmsg, '"') + Xout "Unexpected message:" v:errmsg + endif + endif + return match + endfunction + + if 1 || strlen("\"") | Xpath 'a' + Xpath 'b' + endif + Xpath 'c' + + if 0 + elseif 1 || strlen("\"") | Xpath 'd' + Xpath 'e' + endif + Xpath 'f' + + while 1 || strlen("\"") | Xpath 'g' + Xpath 'h' + break + endwhile + Xpath 'i' + + let v:errmsg = "" + if 1 ||| strlen("\"") | Xpath 'j' + Xpath 'k' + endif + Xpath 'l' + if !MSG('E15', "Invalid expression") + Xpath 'm' + endif + + let v:errmsg = "" + if 0 + elseif 1 ||| strlen("\"") | Xpath 'n' + Xpath 'o' + endif + Xpath 'p' + if !MSG('E15', "Invalid expression") + Xpath 'q' + endif + + let v:errmsg = "" + while 1 ||| strlen("\"") | Xpath 'r' + Xpath 's' + break + endwhile + Xpath 't' + if !MSG('E15', "Invalid expression") + Xpath 'u' + endif + + let g:test10_result = g:Xpath + delfunction MSG + + func Test_expr_parsing() + call assert_equal('abcdefghilpt', g:test10_result) + endfunc + + + "------------------------------------------------------------------------------- + " Test 11: :if, :elseif, :while argument evaluation after abort {{{1 + " + " When code is skipped over due to an error, the boolean argument to + " an :if, :elseif, or :while must not be evaluated. + "------------------------------------------------------------------------------- + + XpathINIT + + let calls = 0 + + function! P(num) + let g:calls = g:calls + a:num " side effect on call + return 0 + endfunction + + if 1 + Xpath 'a' + asdf " error + Xpath 'b' + if P(1) " should not be called + Xpath 'c' + elseif !P(2) " should not be called + Xpath 'd' + else + Xpath 'e' + endif + Xpath 'f' + while P(4) " should not be called + Xpath 'g' + endwhile + Xpath 'h' + endif + Xpath 'x' + + let g:test11_calls = calls + let g:test11_result = g:Xpath + + unlet calls + delfunction P + + func Test_arg_abort() + call assert_equal(0, g:test11_calls) + call assert_equal('ax', g:test11_result) + endfunc + + + "------------------------------------------------------------------------------- + " Test 12: Expressions in braces in skipped code {{{1 + " + " In code skipped over due to an error or inactive conditional, + " an expression in braces as part of a variable or function name + " should not be evaluated. + "------------------------------------------------------------------------------- + + XpathINIT + + function! NULL() + Xpath 'a' + return 0 + endfunction + + function! ZERO() + Xpath 'b' + return 0 + endfunction + + function! F0() + Xpath 'c' + endfunction + + function! F1(arg) + Xpath 'e' + endfunction + + let V0 = 1 + + Xpath 'f' + echo 0 ? F{NULL() + V{ZERO()}}() : 1 + + Xpath 'g' + if 0 + Xpath 'h' + call F{NULL() + V{ZERO()}}() + endif + + Xpath 'i' + if 1 + asdf " error + Xpath 'j' + call F1(F{NULL() + V{ZERO()}}()) + endif + + Xpath 'k' + if 1 + asdf " error + Xpath 'l' + call F{NULL() + V{ZERO()}}() + endif + + let g:test12_result = g:Xpath + + func Test_braces_skipped() + call assert_equal('fgik', g:test12_result) + endfunc + + + "------------------------------------------------------------------------------- + " Test 13: Failure in argument evaluation for :while {{{1 + " + " A failure in the expression evaluation for the condition of a :while + " causes the whole :while loop until the matching :endwhile being + " ignored. Continuation is at the next following line. + "------------------------------------------------------------------------------- + + XpathINIT + + Xpath 'a' + while asdf + Xpath 'b' + while 1 + Xpath 'c' + break + endwhile + Xpath 'd' + break + endwhile + Xpath 'e' + + while asdf | Xpath 'f' | endwhile | Xpath 'g' + Xpath 'h' + let g:test13_result = g:Xpath + + func Test_while_fail() + call assert_equal('aeh', g:test13_result) + endfunc + + + "------------------------------------------------------------------------------- + " Test 14: Failure in argument evaluation for :if {{{1 + " + " A failure in the expression evaluation for the condition of an :if + " does not cause the corresponding :else or :endif being matched to + " a previous :if/:elseif. Neither of both branches of the failed :if + " are executed. + "------------------------------------------------------------------------------- + + XpathINIT + + function! F() + Xpath 'a' + let x = 0 + if x " false + Xpath 'b' + elseif !x " always true + Xpath 'c' + let x = 1 + if g:boolvar " possibly undefined + Xpath 'd' + else + Xpath 'e' + endif + Xpath 'f' + elseif x " never executed + Xpath 'g' + endif + Xpath 'h' + endfunction + + let boolvar = 1 + call F() + Xpath '-' + + unlet boolvar + call F() + let g:test14_result = g:Xpath + + delfunction F + + func Test_if_fail() + call assert_equal('acdfh-acfh', g:test14_result) + endfunc + + + "------------------------------------------------------------------------------- + " Test 15: Failure in argument evaluation for :if (bar) {{{1 + " + " Like previous test, except that the failing :if ... | ... | :endif + " is in a single line. + "------------------------------------------------------------------------------- + + XpathINIT + + function! F() + Xpath 'a' + let x = 0 + if x " false + Xpath 'b' + elseif !x " always true + Xpath 'c' + let x = 1 + if g:boolvar | Xpath 'd' | else | Xpath 'e' | endif + Xpath 'f' + elseif x " never executed + Xpath 'g' + endif + Xpath 'h' + endfunction + + let boolvar = 1 + call F() + Xpath '-' + + unlet boolvar + call F() + let g:test15_result = g:Xpath + + delfunction F + + func Test_if_bar_fail() + call assert_equal('acdfh-acfh', g:test15_result) + endfunc + + "------------------------------------------------------------------------------- + " Test 90: Recognizing {} in variable name. {{{1 + "------------------------------------------------------------------------------- + + func Test_curlies() + let s:var = 66 + let ns = 's' + call assert_equal(66, {ns}:var) + + let g:a = {} + let g:b = 't' + let g:a[g:b] = 77 + call assert_equal(77, g:a['t']) + endfunc + + "------------------------------------------------------------------------------- + " Test 91: using type(). {{{1 + "------------------------------------------------------------------------------- + + func Test_type() + call assert_equal(0, type(0)) + call assert_equal(1, type("")) + call assert_equal(2, type(function("tr"))) + call assert_equal(2, type(function("tr", [8]))) + call assert_equal(3, type([])) + call assert_equal(4, type({})) + call assert_equal(5, type(0.0)) + call assert_equal(6, type(v:false)) + call assert_equal(6, type(v:true)) + call assert_equal(7, type(v:none)) + call assert_equal(7, type(v:null)) + call assert_equal(8, v:t_job) + call assert_equal(9, v:t_channel) + call assert_equal(v:t_number, type(0)) + call assert_equal(v:t_string, type("")) + call assert_equal(v:t_func, type(function("tr"))) + call assert_equal(v:t_func, type(function("tr", [8]))) + call assert_equal(v:t_list, type([])) + call assert_equal(v:t_dict, type({})) + call assert_equal(v:t_float, type(0.0)) + call assert_equal(v:t_bool, type(v:false)) + call assert_equal(v:t_bool, type(v:true)) + call assert_equal(v:t_none, type(v:none)) + call assert_equal(v:t_none, type(v:null)) + + + call assert_equal(0, 0 + v:false) + call assert_equal(1, 0 + v:true) + call assert_equal(0, 0 + v:none) + call assert_equal(0, 0 + v:null) + + call assert_equal('v:false', '' . v:false) + call assert_equal('v:true', '' . v:true) + call assert_equal('v:none', '' . v:none) + call assert_equal('v:null', '' . v:null) + + call assert_true(v:false == 0) + call assert_false(v:false != 0) + call assert_true(v:true == 1) + call assert_false(v:true != 1) + call assert_false(v:true == v:false) + call assert_true(v:true != v:false) + + call assert_true(v:null == 0) + call assert_false(v:null != 0) + call assert_true(v:none == 0) + call assert_false(v:none != 0) + + call assert_true(v:false is v:false) + call assert_true(v:true is v:true) + call assert_true(v:none is v:none) + call assert_true(v:null is v:null) + + call assert_false(v:false isnot v:false) + call assert_false(v:true isnot v:true) + call assert_false(v:none isnot v:none) + call assert_false(v:null isnot v:null) + + call assert_false(v:false is 0) + call assert_false(v:true is 1) + call assert_false(v:true is v:false) + call assert_false(v:none is 0) + call assert_false(v:null is 0) + call assert_false(v:null is v:none) + + call assert_true(v:false isnot 0) + call assert_true(v:true isnot 1) + call assert_true(v:true isnot v:false) + call assert_true(v:none isnot 0) + call assert_true(v:null isnot 0) + call assert_true(v:null isnot v:none) + + call assert_equal(v:false, eval(string(v:false))) + call assert_equal(v:true, eval(string(v:true))) + call assert_equal(v:none, eval(string(v:none))) + call assert_equal(v:null, eval(string(v:null))) + + call assert_equal(v:false, copy(v:false)) + call assert_equal(v:true, copy(v:true)) + call assert_equal(v:none, copy(v:none)) + call assert_equal(v:null, copy(v:null)) + + call assert_equal([v:false], deepcopy([v:false])) + call assert_equal([v:true], deepcopy([v:true])) + call assert_equal([v:none], deepcopy([v:none])) + call assert_equal([v:null], deepcopy([v:null])) + + call assert_true(empty(v:false)) + call assert_false(empty(v:true)) + call assert_true(empty(v:null)) + call assert_true(empty(v:none)) + + func ChangeYourMind() + try + return v:true + finally + return 'something else' + endtry + endfunc + + call ChangeYourMind() + endfunc + + "------------------------------------------------------------------------------- + " Test 92: skipping code {{{1 + "------------------------------------------------------------------------------- + + func Test_skip() + let Fn = function('Test_type') + call assert_false(0 && Fn[1]) + call assert_false(0 && string(Fn)) + call assert_false(0 && len(Fn)) + let l = [] + call assert_false(0 && l[1]) + call assert_false(0 && string(l)) + call assert_false(0 && len(l)) + let f = 1.0 + call assert_false(0 && f[1]) + call assert_false(0 && string(f)) + call assert_false(0 && len(f)) + let sp = v:null + call assert_false(0 && sp[1]) + call assert_false(0 && string(sp)) + call assert_false(0 && len(sp)) + + endfunc + + "------------------------------------------------------------------------------- + " Test 93: :echo and string() {{{1 + "------------------------------------------------------------------------------- + + func Test_echo_and_string() + " String + let a = 'foo bar' + redir => result + echo a + echo string(a) + redir END + let l = split(result, "\n") + call assert_equal(["foo bar", + \ "'foo bar'"], l) + + " Float + if has('float') + let a = -1.2e0 + redir => result + echo a + echo string(a) + redir END + let l = split(result, "\n") + call assert_equal(["-1.2", + \ "-1.2"], l) + endif + + " Funcref + redir => result + echo function('string') + echo string(function('string')) + redir END + let l = split(result, "\n") + call assert_equal(["string", + \ "function('string')"], l) + + " Recursive dictionary + let a = {} + let a["a"] = a + redir => result + echo a + echo string(a) + redir END + let l = split(result, "\n") + call assert_equal(["{'a': {...}}", + \ "{'a': {...}}"], l) + + " Recursive list + let a = [0] + let a[0] = a + redir => result + echo a + echo string(a) + redir END + let l = split(result, "\n") + call assert_equal(["[[...]]", + \ "[[...]]"], l) + + " Empty dictionaries in a list + let a = {} + redir => result + echo [a, a, a] + echo string([a, a, a]) + redir END + let l = split(result, "\n") + call assert_equal(["[{}, {}, {}]", + \ "[{}, {}, {}]"], l) + + " Empty dictionaries in a dictionary + let a = {} + let b = {"a": a, "b": a} + redir => result + echo b + echo string(b) + redir END + let l = split(result, "\n") + call assert_equal(["{'a': {}, 'b': {}}", + \ "{'a': {}, 'b': {}}"], l) + + " Empty lists in a list + let a = [] + redir => result + echo [a, a, a] + echo string([a, a, a]) + redir END + let l = split(result, "\n") + call assert_equal(["[[], [], []]", + \ "[[], [], []]"], l) + + " Empty lists in a dictionary + let a = [] + let b = {"a": a, "b": a} + redir => result + echo b + echo string(b) + redir END + let l = split(result, "\n") + call assert_equal(["{'a': [], 'b': []}", + \ "{'a': [], 'b': []}"], l) + + " Dictionaries in a list + let a = {"one": "yes", "two": "yes", "three": "yes"} + redir => result + echo [a, a, a] + echo string([a, a, a]) + redir END + let l = split(result, "\n") + call assert_equal(["[{'one': 'yes', 'two': 'yes', 'three': 'yes'}, {...}, {...}]", + \ "[{'one': 'yes', 'two': 'yes', 'three': 'yes'}, {'one': 'yes', 'two': 'yes', 'three': 'yes'}, {'one': 'yes', 'two': 'yes', 'three': 'yes'}]"], l) + + " Dictionaries in a dictionary + let a = {"one": "yes", "two": "yes", "three": "yes"} + let b = {"a": a, "b": a} + redir => result + echo b + echo string(b) + redir END + let l = split(result, "\n") + call assert_equal(["{'a': {'one': 'yes', 'two': 'yes', 'three': 'yes'}, 'b': {...}}", + \ "{'a': {'one': 'yes', 'two': 'yes', 'three': 'yes'}, 'b': {'one': 'yes', 'two': 'yes', 'three': 'yes'}}"], l) + + " Lists in a list + let a = [1, 2, 3] + redir => result + echo [a, a, a] + echo string([a, a, a]) + redir END + let l = split(result, "\n") + call assert_equal(["[[1, 2, 3], [...], [...]]", + \ "[[1, 2, 3], [1, 2, 3], [1, 2, 3]]"], l) + + " Lists in a dictionary + let a = [1, 2, 3] + let b = {"a": a, "b": a} + redir => result + echo b + echo string(b) + redir END + let l = split(result, "\n") + call assert_equal(["{'a': [1, 2, 3], 'b': [...]}", + \ "{'a': [1, 2, 3], 'b': [1, 2, 3]}"], l) + + endfunc + + "------------------------------------------------------------------------------- + " Test 94: 64-bit Numbers {{{1 + "------------------------------------------------------------------------------- + + func Test_num64() + if !has('num64') + return + endif + + call assert_notequal( 4294967296, 0) + call assert_notequal(-4294967296, 0) + call assert_equal( 4294967296, 0xFFFFffff + 1) + call assert_equal(-4294967296, -0xFFFFffff - 1) + + call assert_equal( 9223372036854775807, 1 / 0) + call assert_equal(-9223372036854775807, -1 / 0) + call assert_equal(-9223372036854775807 - 1, 0 / 0) + + call assert_equal( 0x7FFFffffFFFFffff, float2nr( 1.0e150)) + call assert_equal(-0x7FFFffffFFFFffff, float2nr(-1.0e150)) + + let rng = range(0xFFFFffff, 0x100000001) + call assert_equal([0xFFFFffff, 0x100000000, 0x100000001], rng) + call assert_equal(0x100000001, max(rng)) + call assert_equal(0xFFFFffff, min(rng)) + call assert_equal(rng, sort(range(0x100000001, 0xFFFFffff, -1), 'N')) + endfunc + + "------------------------------------------------------------------------------- + " Test 95: lines of :append, :change, :insert {{{1 + "------------------------------------------------------------------------------- + + function! DefineFunction(name, body) + let func = join(['function! ' . a:name . '()'] + a:body + ['endfunction'], "\n") + exec func + endfunction + + func Test_script_lines() + " :append + try + call DefineFunction('T_Append', [ + \ 'append', + \ 'py < - - " Append a message to the "messages" file - func! Xout(text) - split messages - $put =a:text - wq - endfunc - - com! -nargs=1 Xout call Xout() - - " MakeScript() - Make a script file from a function. {{{2 - " - " Create a script that consists of the body of the function a:funcname. - " Replace any ":return" by a ":finish", any argument variable by a global - " variable, and and every ":call" by a ":source" for the next following argument - " in the variable argument list. This function is useful if similar tests are - " to be made for a ":return" from a function call or a ":finish" in a script - " file. - function! MakeScript(funcname, ...) - let script = tempname() - execute "redir! >" . script - execute "function" a:funcname - redir END - execute "edit" script - " Delete the "function" and the "endfunction" lines. Do not include the - " word "function" in the pattern since it might be translated if LANG is - " set. When MakeScript() is being debugged, this deletes also the debugging - " output of its line 3 and 4. - exec '1,/.*' . a:funcname . '(.*)/d' - /^\d*\s*endfunction\>/,$d - %s/^\d*//e - %s/return/finish/e - %s/\ 0 - let cnt = cnt + 1 - s/\) - - - "------------------------------------------------------------------------------- - " Test 1: :endwhile in function {{{1 - " - " Detect if a broken loop is (incorrectly) reactivated by the - " :endwhile. Use a :return to prevent an endless loop, and make - " this test first to get a meaningful result on an error before other - " tests will hang. - "------------------------------------------------------------------------------- - - function! T1_F() - Xpath 'a' - let first = 1 - while 1 - Xpath 'b' - if first - Xpath 'c' - let first = 0 - break - else - Xpath 'd' - return - endif - endwhile - endfunction - - function! T1_G() - Xpath 'h' - let first = 1 - while 1 - Xpath 'i' - if first - Xpath 'j' - let first = 0 - break - else - Xpath 'k' - return - endif - if 1 " unmatched :if - endwhile - endfunction - - func Test_endwhile_function() - XpathINIT - call T1_F() - Xpath 'F' - - try - call T1_G() - catch - " Catch missing :endif - call assert_true(v:exception =~ 'E171') - Xpath 'x' - endtry - Xpath 'G' - - call assert_equal('abcFhijxG', g:Xpath) - endfunc - - "------------------------------------------------------------------------------- - " Test 2: :endwhile in script {{{1 - " - " Detect if a broken loop is (incorrectly) reactivated by the - " :endwhile. Use a :finish to prevent an endless loop, and place - " this test before others that might hang to get a meaningful result - " on an error. - " - " This test executes the bodies of the functions T1_F and T1_G from - " the previous test as script files (:return replaced by :finish). - "------------------------------------------------------------------------------- - - func Test_endwhile_script() - XpathINIT - ExecAsScript T1_F - Xpath 'F' - call DeleteTheScript() - - try - ExecAsScript T1_G - catch - " Catch missing :endif - call assert_true(v:exception =~ 'E171') - Xpath 'x' - endtry - Xpath 'G' - call DeleteTheScript() - - call assert_equal('abcFhijxG', g:Xpath) - endfunc - - "------------------------------------------------------------------------------- - " Test 3: :if, :elseif, :while, :continue, :break {{{1 - "------------------------------------------------------------------------------- - - function Test_if_while() - XpathINIT - if 1 - Xpath 'a' - let loops = 3 - while loops > -1 " main loop: loops == 3, 2, 1 (which breaks) - if loops <= 0 - let break_err = 1 - let loops = -1 - else - Xpath 'b' . loops - endif - if (loops == 2) - while loops == 2 " dummy loop - Xpath 'c' . loops - let loops = loops - 1 - continue " stop dummy loop - Xpath 'd' . loops - endwhile - continue " continue main loop - Xpath 'e' . loops - elseif (loops == 1) - let p = 1 - while p " dummy loop - Xpath 'f' . loops - let p = 0 - break " break dummy loop - Xpath 'g' . loops - endwhile - Xpath 'h' . loops - unlet p - break " break main loop - Xpath 'i' . loops - endif - if (loops > 0) - Xpath 'j' . loops - endif - while loops == 3 " dummy loop - let loops = loops - 1 - endwhile " end dummy loop - endwhile " end main loop - Xpath 'k' - else - Xpath 'l' - endif - Xpath 'm' - if exists("break_err") - Xpath 'm' - unlet break_err - endif - - unlet loops - - call assert_equal('ab3j3b2c2b1f1h1km', g:Xpath) - endfunc - - "------------------------------------------------------------------------------- - " Test 4: :return {{{1 - "------------------------------------------------------------------------------- - - function! T4_F() - if 1 - Xpath 'a' - let loops = 3 - while loops > 0 " 3: 2: 1: - Xpath 'b' . loops - if (loops == 2) - Xpath 'c' . loops - return - Xpath 'd' . loops - endif - Xpath 'e' . loops - let loops = loops - 1 - endwhile - Xpath 'f' - else - Xpath 'g' - endif - endfunction - - function Test_return() - XpathINIT - call T4_F() - Xpath '4' - - call assert_equal('ab3e3b2c24', g:Xpath) - endfunction - - - "------------------------------------------------------------------------------- - " Test 5: :finish {{{1 - " - " This test executes the body of the function T4_F from the previous - " test as a script file (:return replaced by :finish). - "------------------------------------------------------------------------------- - - function Test_finish() - XpathINIT - ExecAsScript T4_F - Xpath '5' - call DeleteTheScript() - - call assert_equal('ab3e3b2c25', g:Xpath) - endfunction - - - - "------------------------------------------------------------------------------- - " Test 6: Defining functions in :while loops {{{1 - " - " Functions can be defined inside other functions. An inner function - " gets defined when the outer function is executed. Functions may - " also be defined inside while loops. Expressions in braces for - " defining the function name are allowed. - " - " The functions are defined when sourcing the script, only the - " resulting path is checked in the test function. - "------------------------------------------------------------------------------- - - XpathINIT - - " The command CALL collects the argument of all its invocations in "calls" - " when used from a function (that is, when the global variable "calls" needs - " the "g:" prefix). This is to check that the function code is skipped when - " the function is defined. For inner functions, do so only if the outer - " function is not being executed. - " - let calls = "" - com! -nargs=1 CALL - \ if !exists("calls") && !exists("outer") | - \ let g:calls = g:calls . | - \ endif - - let i = 0 - while i < 3 - let i = i + 1 - if i == 1 - Xpath 'a' - function! F1(arg) - CALL a:arg - let outer = 1 - - let j = 0 - while j < 1 - Xpath 'b' - let j = j + 1 - function! G1(arg) - CALL a:arg - endfunction - Xpath 'c' - endwhile - endfunction - Xpath 'd' - - continue - endif - - Xpath 'e' . i - function! F{i}(i, arg) - CALL a:arg - let outer = 1 - - if a:i == 3 - Xpath 'f' - endif - let k = 0 - while k < 3 - Xpath 'g' . k - let k = k + 1 - function! G{a:i}{k}(arg) - CALL a:arg - endfunction - Xpath 'h' . k - endwhile - endfunction - Xpath 'i' - - endwhile - - if exists("*G1") - Xpath 'j' - endif - if exists("*F1") - call F1("F1") - if exists("*G1") - call G1("G1") - endif - endif - - if exists("G21") || exists("G22") || exists("G23") - Xpath 'k' - endif - if exists("*F2") - call F2(2, "F2") - if exists("*G21") - call G21("G21") - endif - if exists("*G22") - call G22("G22") - endif - if exists("*G23") - call G23("G23") - endif - endif - - if exists("G31") || exists("G32") || exists("G33") - Xpath 'l' - endif - if exists("*F3") - call F3(3, "F3") - if exists("*G31") - call G31("G31") - endif - if exists("*G32") - call G32("G32") - endif - if exists("*G33") - call G33("G33") - endif - endif - - Xpath 'm' - - let g:test6_result = g:Xpath - let g:test6_calls = calls - - unlet calls - delfunction F1 - delfunction G1 - delfunction F2 - delfunction G21 - delfunction G22 - delfunction G23 - delfunction G31 - delfunction G32 - delfunction G33 - - function Test_defining_functions() - call assert_equal('ade2ie3ibcg0h1g1h2g2h3fg0h1g1h2g2h3m', g:test6_result) - call assert_equal('F1G1F2G21G22G23F3G31G32G33', g:test6_calls) - endfunc - - "------------------------------------------------------------------------------- - " Test 7: Continuing on errors outside functions {{{1 - " - " On an error outside a function, the script processing continues - " at the line following the outermost :endif or :endwhile. When not - " inside an :if or :while, the script processing continues at the next - " line. - "------------------------------------------------------------------------------- - - XpathINIT - - if 1 - Xpath 'a' - while 1 - Xpath 'b' - asdf - Xpath 'c' - break - endwhile | Xpath 'd' - Xpath 'e' - endif | Xpath 'f' - Xpath 'g' - - while 1 - Xpath 'h' - if 1 - Xpath 'i' - asdf - Xpath 'j' - endif | Xpath 'k' - Xpath 'l' - break - endwhile | Xpath 'm' - Xpath 'n' - - asdf - Xpath 'o' - - asdf | Xpath 'p' - Xpath 'q' - - let g:test7_result = g:Xpath - - func Test_error_in_script() - call assert_equal('abghinoq', g:test7_result) - endfunc - - "------------------------------------------------------------------------------- - " Test 8: Aborting and continuing on errors inside functions {{{1 - " - " On an error inside a function without the "abort" attribute, the - " script processing continues at the next line (unless the error was - " in a :return command). On an error inside a function with the - " "abort" attribute, the function is aborted and the script processing - " continues after the function call; the value -1 is returned then. - "------------------------------------------------------------------------------- - - XpathINIT - - function! T8_F() - if 1 - Xpath 'a' - while 1 - Xpath 'b' - asdf - Xpath 'c' - asdf | Xpath 'd' - Xpath 'e' - break - endwhile - Xpath 'f' - endif | Xpath 'g' - Xpath 'h' - - while 1 - Xpath 'i' - if 1 - Xpath 'j' - asdf - Xpath 'k' - asdf | Xpath 'l' - Xpath 'm' - endif - Xpath 'n' - break - endwhile | Xpath 'o' - Xpath 'p' - - return novar " returns (default return value 0) - Xpath 'q' - return 1 " not reached - endfunction - - function! T8_G() abort - if 1 - Xpath 'r' - while 1 - Xpath 's' - asdf " returns -1 - Xpath 't' - break - endwhile - Xpath 'v' - endif | Xpath 'w' - Xpath 'x' - - return -4 " not reached - endfunction - - function! T8_H() abort - while 1 - Xpath 'A' - if 1 - Xpath 'B' - asdf " returns -1 - Xpath 'C' - endif - Xpath 'D' - break - endwhile | Xpath 'E' - Xpath 'F' - - return -4 " not reached - endfunction - - " Aborted functions (T8_G and T8_H) return -1. - let g:test8_sum = (T8_F() + 1) - 4 * T8_G() - 8 * T8_H() - Xpath 'X' - let g:test8_result = g:Xpath - - func Test_error_in_function() - call assert_equal(13, g:test8_sum) - call assert_equal('abcefghijkmnoprsABX', g:test8_result) - - delfunction T8_F - delfunction T8_G - delfunction T8_H - endfunc - - - "------------------------------------------------------------------------------- - " Test 9: Continuing after aborted functions {{{1 - " - " When a function with the "abort" attribute is aborted due to an - " error, the next function back in the call hierarchy without an - " "abort" attribute continues; the value -1 is returned then. - "------------------------------------------------------------------------------- - - XpathINIT - - function! F() abort - Xpath 'a' - let result = G() " not aborted - Xpath 'b' - if result != 2 - Xpath 'c' - endif - return 1 - endfunction - - function! G() " no abort attribute - Xpath 'd' - if H() != -1 " aborted - Xpath 'e' - endif - Xpath 'f' - return 2 - endfunction - - function! H() abort - Xpath 'g' - call I() " aborted - Xpath 'h' - return 4 - endfunction - - function! I() abort - Xpath 'i' - asdf " error - Xpath 'j' - return 8 - endfunction - - if F() != 1 - Xpath 'k' - endif - - let g:test9_result = g:Xpath - - delfunction F - delfunction G - delfunction H - delfunction I - - func Test_func_abort() - call assert_equal('adgifb', g:test9_result) - endfunc - - - "------------------------------------------------------------------------------- - " Test 10: :if, :elseif, :while argument parsing {{{1 - " - " A '"' or '|' in an argument expression must not be mixed up with - " a comment or a next command after a bar. Parsing errors should - " be recognized. - "------------------------------------------------------------------------------- - - XpathINIT - - function! MSG(enr, emsg) - let english = v:lang == "C" || v:lang =~ '^[Ee]n' - if a:enr == "" - Xout "TODO: Add message number for:" a:emsg - let v:errmsg = ":" . v:errmsg - endif - let match = 1 - if v:errmsg !~ '^'.a:enr.':' || (english && v:errmsg !~ a:emsg) - let match = 0 - if v:errmsg == "" - Xout "Message missing." - else - let v:errmsg = escape(v:errmsg, '"') - Xout "Unexpected message:" v:errmsg - endif - endif - return match - endfunction - - if 1 || strlen("\"") | Xpath 'a' - Xpath 'b' - endif - Xpath 'c' - - if 0 - elseif 1 || strlen("\"") | Xpath 'd' - Xpath 'e' - endif - Xpath 'f' - - while 1 || strlen("\"") | Xpath 'g' - Xpath 'h' - break - endwhile - Xpath 'i' - - let v:errmsg = "" - if 1 ||| strlen("\"") | Xpath 'j' - Xpath 'k' - endif - Xpath 'l' - if !MSG('E15', "Invalid expression") - Xpath 'm' - endif - - let v:errmsg = "" - if 0 - elseif 1 ||| strlen("\"") | Xpath 'n' - Xpath 'o' - endif - Xpath 'p' - if !MSG('E15', "Invalid expression") - Xpath 'q' - endif - - let v:errmsg = "" - while 1 ||| strlen("\"") | Xpath 'r' - Xpath 's' - break - endwhile - Xpath 't' - if !MSG('E15', "Invalid expression") - Xpath 'u' - endif - - let g:test10_result = g:Xpath - delfunction MSG - - func Test_expr_parsing() - call assert_equal('abcdefghilpt', g:test10_result) - endfunc - - - "------------------------------------------------------------------------------- - " Test 11: :if, :elseif, :while argument evaluation after abort {{{1 - " - " When code is skipped over due to an error, the boolean argument to - " an :if, :elseif, or :while must not be evaluated. - "------------------------------------------------------------------------------- - - XpathINIT - - let calls = 0 - - function! P(num) - let g:calls = g:calls + a:num " side effect on call - return 0 - endfunction - - if 1 - Xpath 'a' - asdf " error - Xpath 'b' - if P(1) " should not be called - Xpath 'c' - elseif !P(2) " should not be called - Xpath 'd' - else - Xpath 'e' - endif - Xpath 'f' - while P(4) " should not be called - Xpath 'g' - endwhile - Xpath 'h' - endif - Xpath 'x' - - let g:test11_calls = calls - let g:test11_result = g:Xpath - - unlet calls - delfunction P - - func Test_arg_abort() - call assert_equal(0, g:test11_calls) - call assert_equal('ax', g:test11_result) - endfunc - - - "------------------------------------------------------------------------------- - " Test 12: Expressions in braces in skipped code {{{1 - " - " In code skipped over due to an error or inactive conditional, - " an expression in braces as part of a variable or function name - " should not be evaluated. - "------------------------------------------------------------------------------- - - XpathINIT - - function! NULL() - Xpath 'a' - return 0 - endfunction - - function! ZERO() - Xpath 'b' - return 0 - endfunction - - function! F0() - Xpath 'c' - endfunction - - function! F1(arg) - Xpath 'e' - endfunction - - let V0 = 1 - - Xpath 'f' - echo 0 ? F{NULL() + V{ZERO()}}() : 1 - - Xpath 'g' - if 0 - Xpath 'h' - call F{NULL() + V{ZERO()}}() - endif - - Xpath 'i' - if 1 - asdf " error - Xpath 'j' - call F1(F{NULL() + V{ZERO()}}()) - endif - - Xpath 'k' - if 1 - asdf " error - Xpath 'l' - call F{NULL() + V{ZERO()}}() - endif - - let g:test12_result = g:Xpath - - func Test_braces_skipped() - call assert_equal('fgik', g:test12_result) - endfunc - - - "------------------------------------------------------------------------------- - " Test 13: Failure in argument evaluation for :while {{{1 - " - " A failure in the expression evaluation for the condition of a :while - " causes the whole :while loop until the matching :endwhile being - " ignored. Continuation is at the next following line. - "------------------------------------------------------------------------------- - - XpathINIT - - Xpath 'a' - while asdf - Xpath 'b' - while 1 - Xpath 'c' - break - endwhile - Xpath 'd' - break - endwhile - Xpath 'e' - - while asdf | Xpath 'f' | endwhile | Xpath 'g' - Xpath 'h' - let g:test13_result = g:Xpath - - func Test_while_fail() - call assert_equal('aeh', g:test13_result) - endfunc - - - "------------------------------------------------------------------------------- - " Test 14: Failure in argument evaluation for :if {{{1 - " - " A failure in the expression evaluation for the condition of an :if - " does not cause the corresponding :else or :endif being matched to - " a previous :if/:elseif. Neither of both branches of the failed :if - " are executed. - "------------------------------------------------------------------------------- - - XpathINIT - - function! F() - Xpath 'a' - let x = 0 - if x " false - Xpath 'b' - elseif !x " always true - Xpath 'c' - let x = 1 - if g:boolvar " possibly undefined - Xpath 'd' - else - Xpath 'e' - endif - Xpath 'f' - elseif x " never executed - Xpath 'g' - endif - Xpath 'h' - endfunction - - let boolvar = 1 - call F() - Xpath '-' - - unlet boolvar - call F() - let g:test14_result = g:Xpath - - delfunction F - - func Test_if_fail() - call assert_equal('acdfh-acfh', g:test14_result) - endfunc - - - "------------------------------------------------------------------------------- - " Test 15: Failure in argument evaluation for :if (bar) {{{1 - " - " Like previous test, except that the failing :if ... | ... | :endif - " is in a single line. - "------------------------------------------------------------------------------- - - XpathINIT - - function! F() - Xpath 'a' - let x = 0 - if x " false - Xpath 'b' - elseif !x " always true - Xpath 'c' - let x = 1 - if g:boolvar | Xpath 'd' | else | Xpath 'e' | endif - Xpath 'f' - elseif x " never executed - Xpath 'g' - endif - Xpath 'h' - endfunction - - let boolvar = 1 - call F() - Xpath '-' - - unlet boolvar - call F() - let g:test15_result = g:Xpath - - delfunction F - - func Test_if_bar_fail() - call assert_equal('acdfh-acfh', g:test15_result) - endfunc - - "------------------------------------------------------------------------------- - " Test 90: Recognizing {} in variable name. {{{1 - "------------------------------------------------------------------------------- - - func Test_curlies() - let s:var = 66 - let ns = 's' - call assert_equal(66, {ns}:var) - - let g:a = {} - let g:b = 't' - let g:a[g:b] = 77 - call assert_equal(77, g:a['t']) - endfunc - - "------------------------------------------------------------------------------- - " Test 91: using type(). {{{1 - "------------------------------------------------------------------------------- - - func Test_type() - call assert_equal(0, type(0)) - call assert_equal(1, type("")) - call assert_equal(2, type(function("tr"))) - call assert_equal(2, type(function("tr", [8]))) - call assert_equal(3, type([])) - call assert_equal(4, type({})) - call assert_equal(5, type(0.0)) - call assert_equal(6, type(v:false)) - call assert_equal(6, type(v:true)) - call assert_equal(7, type(v:none)) - call assert_equal(7, type(v:null)) - call assert_equal(8, v:t_job) - call assert_equal(9, v:t_channel) - call assert_equal(v:t_number, type(0)) - call assert_equal(v:t_string, type("")) - call assert_equal(v:t_func, type(function("tr"))) - call assert_equal(v:t_func, type(function("tr", [8]))) - call assert_equal(v:t_list, type([])) - call assert_equal(v:t_dict, type({})) - call assert_equal(v:t_float, type(0.0)) - call assert_equal(v:t_bool, type(v:false)) - call assert_equal(v:t_bool, type(v:true)) - call assert_equal(v:t_none, type(v:none)) - call assert_equal(v:t_none, type(v:null)) - - - call assert_equal(0, 0 + v:false) - call assert_equal(1, 0 + v:true) - call assert_equal(0, 0 + v:none) - call assert_equal(0, 0 + v:null) - - call assert_equal('v:false', '' . v:false) - call assert_equal('v:true', '' . v:true) - call assert_equal('v:none', '' . v:none) - call assert_equal('v:null', '' . v:null) - - call assert_true(v:false == 0) - call assert_false(v:false != 0) - call assert_true(v:true == 1) - call assert_false(v:true != 1) - call assert_false(v:true == v:false) - call assert_true(v:true != v:false) - - call assert_true(v:null == 0) - call assert_false(v:null != 0) - call assert_true(v:none == 0) - call assert_false(v:none != 0) - - call assert_true(v:false is v:false) - call assert_true(v:true is v:true) - call assert_true(v:none is v:none) - call assert_true(v:null is v:null) - - call assert_false(v:false isnot v:false) - call assert_false(v:true isnot v:true) - call assert_false(v:none isnot v:none) - call assert_false(v:null isnot v:null) - - call assert_false(v:false is 0) - call assert_false(v:true is 1) - call assert_false(v:true is v:false) - call assert_false(v:none is 0) - call assert_false(v:null is 0) - call assert_false(v:null is v:none) - - call assert_true(v:false isnot 0) - call assert_true(v:true isnot 1) - call assert_true(v:true isnot v:false) - call assert_true(v:none isnot 0) - call assert_true(v:null isnot 0) - call assert_true(v:null isnot v:none) - - call assert_equal(v:false, eval(string(v:false))) - call assert_equal(v:true, eval(string(v:true))) - call assert_equal(v:none, eval(string(v:none))) - call assert_equal(v:null, eval(string(v:null))) - - call assert_equal(v:false, copy(v:false)) - call assert_equal(v:true, copy(v:true)) - call assert_equal(v:none, copy(v:none)) - call assert_equal(v:null, copy(v:null)) - - call assert_equal([v:false], deepcopy([v:false])) - call assert_equal([v:true], deepcopy([v:true])) - call assert_equal([v:none], deepcopy([v:none])) - call assert_equal([v:null], deepcopy([v:null])) - - call assert_true(empty(v:false)) - call assert_false(empty(v:true)) - call assert_true(empty(v:null)) - call assert_true(empty(v:none)) - - func ChangeYourMind() - try - return v:true - finally - return 'something else' - endtry - endfunc - - call ChangeYourMind() - endfunc - - "------------------------------------------------------------------------------- - " Test 92: skipping code {{{1 - "------------------------------------------------------------------------------- - - func Test_skip() - let Fn = function('Test_type') - call assert_false(0 && Fn[1]) - call assert_false(0 && string(Fn)) - call assert_false(0 && len(Fn)) - let l = [] - call assert_false(0 && l[1]) - call assert_false(0 && string(l)) - call assert_false(0 && len(l)) - let f = 1.0 - call assert_false(0 && f[1]) - call assert_false(0 && string(f)) - call assert_false(0 && len(f)) - let sp = v:null - call assert_false(0 && sp[1]) - call assert_false(0 && string(sp)) - call assert_false(0 && len(sp)) - - endfunc - - "------------------------------------------------------------------------------- - " Test 93: :echo and string() {{{1 - "------------------------------------------------------------------------------- - - func Test_echo_and_string() - " String - let a = 'foo bar' - redir => result - echo a - echo string(a) - redir END - let l = split(result, "\n") - call assert_equal(["foo bar", - \ "'foo bar'"], l) - - " Float - if has('float') - let a = -1.2e0 - redir => result - echo a - echo string(a) - redir END - let l = split(result, "\n") - call assert_equal(["-1.2", - \ "-1.2"], l) - endif - - " Funcref - redir => result - echo function('string') - echo string(function('string')) - redir END - let l = split(result, "\n") - call assert_equal(["string", - \ "function('string')"], l) - - " Recursive dictionary - let a = {} - let a["a"] = a - redir => result - echo a - echo string(a) - redir END - let l = split(result, "\n") - call assert_equal(["{'a': {...}}", - \ "{'a': {...}}"], l) - - " Recursive list - let a = [0] - let a[0] = a - redir => result - echo a - echo string(a) - redir END - let l = split(result, "\n") - call assert_equal(["[[...]]", - \ "[[...]]"], l) - - " Empty dictionaries in a list - let a = {} - redir => result - echo [a, a, a] - echo string([a, a, a]) - redir END - let l = split(result, "\n") - call assert_equal(["[{}, {}, {}]", - \ "[{}, {}, {}]"], l) - - " Empty dictionaries in a dictionary - let a = {} - let b = {"a": a, "b": a} - redir => result - echo b - echo string(b) - redir END - let l = split(result, "\n") - call assert_equal(["{'a': {}, 'b': {}}", - \ "{'a': {}, 'b': {}}"], l) - - " Empty lists in a list - let a = [] - redir => result - echo [a, a, a] - echo string([a, a, a]) - redir END - let l = split(result, "\n") - call assert_equal(["[[], [], []]", - \ "[[], [], []]"], l) - - " Empty lists in a dictionary - let a = [] - let b = {"a": a, "b": a} - redir => result - echo b - echo string(b) - redir END - let l = split(result, "\n") - call assert_equal(["{'a': [], 'b': []}", - \ "{'a': [], 'b': []}"], l) - - " Dictionaries in a list - let a = {"one": "yes", "two": "yes", "three": "yes"} - redir => result - echo [a, a, a] - echo string([a, a, a]) - redir END - let l = split(result, "\n") - call assert_equal(["[{'one': 'yes', 'two': 'yes', 'three': 'yes'}, {...}, {...}]", - \ "[{'one': 'yes', 'two': 'yes', 'three': 'yes'}, {'one': 'yes', 'two': 'yes', 'three': 'yes'}, {'one': 'yes', 'two': 'yes', 'three': 'yes'}]"], l) - - " Dictionaries in a dictionary - let a = {"one": "yes", "two": "yes", "three": "yes"} - let b = {"a": a, "b": a} - redir => result - echo b - echo string(b) - redir END - let l = split(result, "\n") - call assert_equal(["{'a': {'one': 'yes', 'two': 'yes', 'three': 'yes'}, 'b': {...}}", - \ "{'a': {'one': 'yes', 'two': 'yes', 'three': 'yes'}, 'b': {'one': 'yes', 'two': 'yes', 'three': 'yes'}}"], l) - - " Lists in a list - let a = [1, 2, 3] - redir => result - echo [a, a, a] - echo string([a, a, a]) - redir END - let l = split(result, "\n") - call assert_equal(["[[1, 2, 3], [...], [...]]", - \ "[[1, 2, 3], [1, 2, 3], [1, 2, 3]]"], l) - - " Lists in a dictionary - let a = [1, 2, 3] - let b = {"a": a, "b": a} - redir => result - echo b - echo string(b) - redir END - let l = split(result, "\n") - call assert_equal(["{'a': [1, 2, 3], 'b': [...]}", - \ "{'a': [1, 2, 3], 'b': [1, 2, 3]}"], l) - - endfunc - - "------------------------------------------------------------------------------- - " Test 94: 64-bit Numbers {{{1 - "------------------------------------------------------------------------------- - - func Test_num64() - if !has('num64') - return - endif - - call assert_notequal( 4294967296, 0) - call assert_notequal(-4294967296, 0) - call assert_equal( 4294967296, 0xFFFFffff + 1) - call assert_equal(-4294967296, -0xFFFFffff - 1) - - call assert_equal( 9223372036854775807, 1 / 0) - call assert_equal(-9223372036854775807, -1 / 0) - call assert_equal(-9223372036854775807 - 1, 0 / 0) - - call assert_equal( 0x7FFFffffFFFFffff, float2nr( 1.0e150)) - call assert_equal(-0x7FFFffffFFFFffff, float2nr(-1.0e150)) - - let rng = range(0xFFFFffff, 0x100000001) - call assert_equal([0xFFFFffff, 0x100000000, 0x100000001], rng) - call assert_equal(0x100000001, max(rng)) - call assert_equal(0xFFFFffff, min(rng)) - call assert_equal(rng, sort(range(0x100000001, 0xFFFFffff, -1), 'N')) - endfunc - - "------------------------------------------------------------------------------- - " Test 95: lines of :append, :change, :insert {{{1 - "------------------------------------------------------------------------------- - - function! DefineFunction(name, body) - let func = join(['function! ' . a:name . '()'] + a:body + ['endfunction'], "\n") - exec func - endfunction - - func Test_script_lines() - " :append - try - call DefineFunction('T_Append', [ - \ 'append', - \ 'py <