110ce39a0SBram Moolenaar" Test for lambda and closure 210ce39a0SBram Moolenaar 36d91bcb4SBram Moolenaarsource check.vim 46d91bcb4SBram Moolenaar 51e115360SBram Moolenaarfunc Test_lambda_feature() 69532fe7fSBram Moolenaar call assert_equal(1, has('lambda')) 71e115360SBram Moolenaarendfunc 89532fe7fSBram Moolenaar 91e115360SBram Moolenaarfunc Test_lambda_with_filter() 10069c1e7fSBram Moolenaar let s:x = 2 11069c1e7fSBram Moolenaar call assert_equal([2, 3], filter([1, 2, 3], {i, v -> v >= s:x})) 121e115360SBram Moolenaarendfunc 13069c1e7fSBram Moolenaar 141e115360SBram Moolenaarfunc Test_lambda_with_map() 15069c1e7fSBram Moolenaar let s:x = 1 16069c1e7fSBram Moolenaar call assert_equal([2, 3, 4], map([1, 2, 3], {i, v -> v + s:x})) 171e115360SBram Moolenaarendfunc 18069c1e7fSBram Moolenaar 191e115360SBram Moolenaarfunc Test_lambda_with_sort() 20069c1e7fSBram Moolenaar call assert_equal([1, 2, 3, 4, 7], sort([3,7,2,1,4], {a, b -> a - b})) 211e115360SBram Moolenaarendfunc 22069c1e7fSBram Moolenaar 231e115360SBram Moolenaarfunc Test_lambda_with_timer() 246d91bcb4SBram Moolenaar CheckFeature timers 25069c1e7fSBram Moolenaar 26069c1e7fSBram Moolenaar let s:n = 0 27069c1e7fSBram Moolenaar let s:timer_id = 0 281e115360SBram Moolenaar func! s:Foo() 299bc4dde4SBram Moolenaar let s:timer_id = timer_start(10, {-> execute("let s:n += 1 | echo s:n", "")}, {"repeat": -1}) 301e115360SBram Moolenaar endfunc 31069c1e7fSBram Moolenaar 32069c1e7fSBram Moolenaar call s:Foo() 339bc4dde4SBram Moolenaar " check timer works 349bc4dde4SBram Moolenaar for i in range(0, 10) 359bc4dde4SBram Moolenaar if s:n > 0 369bc4dde4SBram Moolenaar break 379bc4dde4SBram Moolenaar endif 389bc4dde4SBram Moolenaar sleep 10m 399bc4dde4SBram Moolenaar endfor 409bc4dde4SBram Moolenaar 41069c1e7fSBram Moolenaar " do not collect lambda 42069c1e7fSBram Moolenaar call test_garbagecollect_now() 439bc4dde4SBram Moolenaar 449bc4dde4SBram Moolenaar " check timer still works 45069c1e7fSBram Moolenaar let m = s:n 469bc4dde4SBram Moolenaar for i in range(0, 10) 479bc4dde4SBram Moolenaar if s:n > m 489bc4dde4SBram Moolenaar break 499bc4dde4SBram Moolenaar endif 509bc4dde4SBram Moolenaar sleep 10m 519bc4dde4SBram Moolenaar endfor 529bc4dde4SBram Moolenaar 53069c1e7fSBram Moolenaar call timer_stop(s:timer_id) 549bc4dde4SBram Moolenaar call assert_true(s:n > m) 551e115360SBram Moolenaarendfunc 56069c1e7fSBram Moolenaar 571e115360SBram Moolenaarfunc Test_lambda_with_partial() 58069c1e7fSBram Moolenaar let l:Cb = function({... -> ['zero', a:1, a:2, a:3]}, ['one', 'two']) 59069c1e7fSBram Moolenaar call assert_equal(['zero', 'one', 'two', 'three'], l:Cb('three')) 601e115360SBram Moolenaarendfunc 61069c1e7fSBram Moolenaar 62069c1e7fSBram Moolenaarfunction Test_lambda_fails() 63069c1e7fSBram Moolenaar call assert_equal(3, {a, b -> a + b}(1, 2)) 64c0f5a78cSBram Moolenaar call assert_fails('echo {a, a -> a + a}(1, 2)', 'E853:') 65ee619e5bSBram Moolenaar call assert_fails('echo {a, b -> a + b)}(1, 2)', 'E451:') 668b633135SBram Moolenaar echo assert_fails('echo 10->{a -> a + 2}', 'E107:') 67069c1e7fSBram Moolenaarendfunc 684f0383bcSBram Moolenaar 694f0383bcSBram Moolenaarfunc Test_not_lamda() 704f0383bcSBram Moolenaar let x = {'>' : 'foo'} 714f0383bcSBram Moolenaar call assert_equal('foo', x['>']) 724f0383bcSBram Moolenaarendfunc 731e96d9bfSBram Moolenaar 741e115360SBram Moolenaarfunc Test_lambda_capture_by_reference() 751e96d9bfSBram Moolenaar let v = 1 761e96d9bfSBram Moolenaar let l:F = {x -> x + v} 771e96d9bfSBram Moolenaar let v = 2 781e96d9bfSBram Moolenaar call assert_equal(12, l:F(10)) 791e115360SBram Moolenaarendfunc 801e96d9bfSBram Moolenaar 811e115360SBram Moolenaarfunc Test_lambda_side_effect() 821e115360SBram Moolenaar func! s:update_and_return(arr) 831e96d9bfSBram Moolenaar let a:arr[1] = 5 841e96d9bfSBram Moolenaar return a:arr 851e115360SBram Moolenaar endfunc 861e96d9bfSBram Moolenaar 871e115360SBram Moolenaar func! s:foo(arr) 881e96d9bfSBram Moolenaar return {-> s:update_and_return(a:arr)} 891e115360SBram Moolenaar endfunc 901e96d9bfSBram Moolenaar 911e96d9bfSBram Moolenaar let arr = [3,2,1] 921e96d9bfSBram Moolenaar call assert_equal([3, 5, 1], s:foo(arr)()) 931e115360SBram Moolenaarendfunc 941e96d9bfSBram Moolenaar 951e115360SBram Moolenaarfunc Test_lambda_refer_local_variable_from_other_scope() 961e115360SBram Moolenaar func! s:foo(X) 971e96d9bfSBram Moolenaar return a:X() " refer l:x in s:bar() 981e115360SBram Moolenaar endfunc 991e96d9bfSBram Moolenaar 1001e115360SBram Moolenaar func! s:bar() 1011e96d9bfSBram Moolenaar let x = 123 1021e96d9bfSBram Moolenaar return s:foo({-> x}) 1031e115360SBram Moolenaar endfunc 1041e96d9bfSBram Moolenaar 1051e96d9bfSBram Moolenaar call assert_equal(123, s:bar()) 1061e115360SBram Moolenaarendfunc 1071e96d9bfSBram Moolenaar 1081e115360SBram Moolenaarfunc Test_lambda_do_not_share_local_variable() 1091e115360SBram Moolenaar func! s:define_funcs() 1101e96d9bfSBram Moolenaar let l:One = {-> split(execute("let a = 'abc' | echo a"))[0]} 1111e96d9bfSBram Moolenaar let l:Two = {-> exists("a") ? a : "no"} 1121e96d9bfSBram Moolenaar return [l:One, l:Two] 1131e115360SBram Moolenaar endfunc 1141e96d9bfSBram Moolenaar 1151e96d9bfSBram Moolenaar let l:F = s:define_funcs() 1161e96d9bfSBram Moolenaar 1171e96d9bfSBram Moolenaar call assert_equal('no', l:F[1]()) 1181e96d9bfSBram Moolenaar call assert_equal('abc', l:F[0]()) 1191e96d9bfSBram Moolenaar call assert_equal('no', l:F[1]()) 1201e115360SBram Moolenaarendfunc 1211e96d9bfSBram Moolenaar 1221e115360SBram Moolenaarfunc Test_lambda_closure_counter() 1231e115360SBram Moolenaar func! s:foo() 1241e96d9bfSBram Moolenaar let x = 0 1251e96d9bfSBram Moolenaar return {-> [execute("let x += 1"), x][-1]} 1261e115360SBram Moolenaar endfunc 1271e96d9bfSBram Moolenaar 1281e96d9bfSBram Moolenaar let l:F = s:foo() 1291e96d9bfSBram Moolenaar call test_garbagecollect_now() 1301e96d9bfSBram Moolenaar call assert_equal(1, l:F()) 1311e96d9bfSBram Moolenaar call assert_equal(2, l:F()) 1321e96d9bfSBram Moolenaar call assert_equal(3, l:F()) 1331e96d9bfSBram Moolenaar call assert_equal(4, l:F()) 1341e115360SBram Moolenaarendfunc 1351e96d9bfSBram Moolenaar 1361e115360SBram Moolenaarfunc Test_lambda_with_a_var() 1371e115360SBram Moolenaar func! s:foo() 1381e96d9bfSBram Moolenaar let x = 2 1391e96d9bfSBram Moolenaar return {... -> a:000 + [x]} 1401e115360SBram Moolenaar endfunc 1411e115360SBram Moolenaar func! s:bar() 1421e96d9bfSBram Moolenaar return s:foo()(1) 1431e115360SBram Moolenaar endfunc 1441e96d9bfSBram Moolenaar 1451e96d9bfSBram Moolenaar call assert_equal([1, 2], s:bar()) 1461e115360SBram Moolenaarendfunc 1471e96d9bfSBram Moolenaar 1481e115360SBram Moolenaarfunc Test_lambda_call_lambda_from_lambda() 1491e115360SBram Moolenaar func! s:foo(x) 1501e96d9bfSBram Moolenaar let l:F1 = {-> {-> a:x}} 1511e96d9bfSBram Moolenaar return {-> l:F1()} 1521e115360SBram Moolenaar endfunc 1531e96d9bfSBram Moolenaar 1541e96d9bfSBram Moolenaar let l:F = s:foo(1) 1551e96d9bfSBram Moolenaar call assert_equal(1, l:F()()) 1561e115360SBram Moolenaarendfunc 1571e96d9bfSBram Moolenaar 1581e115360SBram Moolenaarfunc Test_lambda_delfunc() 1591e115360SBram Moolenaar func! s:gen() 1601e96d9bfSBram Moolenaar let pl = l: 1611e96d9bfSBram Moolenaar let l:Foo = {-> get(pl, "Foo", get(pl, "Bar", {-> 0}))} 1621e96d9bfSBram Moolenaar let l:Bar = l:Foo 1631e96d9bfSBram Moolenaar delfunction l:Foo 1641e96d9bfSBram Moolenaar return l:Bar 1651e115360SBram Moolenaar endfunc 1661e96d9bfSBram Moolenaar 1671e96d9bfSBram Moolenaar let l:F = s:gen() 168437bafe4SBram Moolenaar call assert_fails(':call l:F()', 'E933:') 1691e115360SBram Moolenaarendfunc 1701e96d9bfSBram Moolenaar 1711e115360SBram Moolenaarfunc Test_lambda_scope() 1721e115360SBram Moolenaar func! s:NewCounter() 1731e96d9bfSBram Moolenaar let c = 0 1741e96d9bfSBram Moolenaar return {-> [execute('let c += 1'), c][-1]} 1751e115360SBram Moolenaar endfunc 1761e96d9bfSBram Moolenaar 1771e115360SBram Moolenaar func! s:NewCounter2() 1781e96d9bfSBram Moolenaar return {-> [execute('let c += 100'), c][-1]} 1791e115360SBram Moolenaar endfunc 1801e96d9bfSBram Moolenaar 1811e96d9bfSBram Moolenaar let l:C = s:NewCounter() 1821e96d9bfSBram Moolenaar let l:D = s:NewCounter2() 1831e96d9bfSBram Moolenaar 1841e96d9bfSBram Moolenaar call assert_equal(1, l:C()) 185c0f5a78cSBram Moolenaar call assert_fails(':call l:D()', 'E121:') 1861e96d9bfSBram Moolenaar call assert_equal(2, l:C()) 1871e115360SBram Moolenaarendfunc 1881e96d9bfSBram Moolenaar 1891e115360SBram Moolenaarfunc Test_lambda_share_scope() 1901e115360SBram Moolenaar func! s:New() 1911e96d9bfSBram Moolenaar let c = 0 1921e96d9bfSBram Moolenaar let l:Inc0 = {-> [execute('let c += 1'), c][-1]} 1931e96d9bfSBram Moolenaar let l:Dec0 = {-> [execute('let c -= 1'), c][-1]} 1941e96d9bfSBram Moolenaar return [l:Inc0, l:Dec0] 1951e115360SBram Moolenaar endfunc 1961e96d9bfSBram Moolenaar 1971e96d9bfSBram Moolenaar let [l:Inc, l:Dec] = s:New() 1981e96d9bfSBram Moolenaar 1991e96d9bfSBram Moolenaar call assert_equal(1, l:Inc()) 2001e96d9bfSBram Moolenaar call assert_equal(2, l:Inc()) 2011e96d9bfSBram Moolenaar call assert_equal(1, l:Dec()) 2021e115360SBram Moolenaarendfunc 2031e96d9bfSBram Moolenaar 2041e115360SBram Moolenaarfunc Test_lambda_circular_reference() 2051e115360SBram Moolenaar func! s:Foo() 2061e96d9bfSBram Moolenaar let d = {} 2071e96d9bfSBram Moolenaar let d.f = {-> d} 2081e96d9bfSBram Moolenaar return d.f 2091e115360SBram Moolenaar endfunc 2101e96d9bfSBram Moolenaar 2111e96d9bfSBram Moolenaar call s:Foo() 2121e96d9bfSBram Moolenaar call test_garbagecollect_now() 2131e96d9bfSBram Moolenaar let i = 0 | while i < 10000 | call s:Foo() | let i+= 1 | endwhile 2141e96d9bfSBram Moolenaar call test_garbagecollect_now() 2151e115360SBram Moolenaarendfunc 2161e96d9bfSBram Moolenaar 2171e115360SBram Moolenaarfunc Test_lambda_combination() 2181e96d9bfSBram Moolenaar call assert_equal(2, {x -> {x -> x}}(1)(2)) 2191e96d9bfSBram Moolenaar call assert_equal(10, {y -> {x -> x(y)(10)}({y -> y})}({z -> z})) 2205feabe00SBram Moolenaar if has('float') 2211e96d9bfSBram Moolenaar call assert_equal(5.0, {x -> {y -> x / y}}(10)(2.0)) 2225feabe00SBram Moolenaar endif 2231e96d9bfSBram Moolenaar call assert_equal(6, {x -> {y -> {z -> x + y + z}}}(1)(2)(3)) 2241e96d9bfSBram Moolenaar 2251e96d9bfSBram Moolenaar call assert_equal(6, {x -> {f -> f(x)}}(3)({x -> x * 2})) 2261e96d9bfSBram Moolenaar call assert_equal(6, {f -> {x -> f(x)}}({x -> x * 2})(3)) 2271e96d9bfSBram Moolenaar 2281e96d9bfSBram Moolenaar " Z combinator 2291e96d9bfSBram Moolenaar let Z = {f -> {x -> f({y -> x(x)(y)})}({x -> f({y -> x(x)(y)})})} 2301e96d9bfSBram Moolenaar let Fact = {f -> {x -> x == 0 ? 1 : x * f(x - 1)}} 2311e96d9bfSBram Moolenaar call assert_equal(120, Z(Fact)(5)) 2321e115360SBram Moolenaarendfunc 23310ce39a0SBram Moolenaar 2341e115360SBram Moolenaarfunc Test_closure_counter() 2351e115360SBram Moolenaar func! s:foo() 23610ce39a0SBram Moolenaar let x = 0 2371e115360SBram Moolenaar func! s:bar() closure 23810ce39a0SBram Moolenaar let x += 1 23910ce39a0SBram Moolenaar return x 2401e115360SBram Moolenaar endfunc 24110ce39a0SBram Moolenaar return function('s:bar') 2421e115360SBram Moolenaar endfunc 24310ce39a0SBram Moolenaar 24410ce39a0SBram Moolenaar let l:F = s:foo() 24510ce39a0SBram Moolenaar call test_garbagecollect_now() 24610ce39a0SBram Moolenaar call assert_equal(1, l:F()) 24710ce39a0SBram Moolenaar call assert_equal(2, l:F()) 24810ce39a0SBram Moolenaar call assert_equal(3, l:F()) 24910ce39a0SBram Moolenaar call assert_equal(4, l:F()) 25067322bf7SBram Moolenaar 25167322bf7SBram Moolenaar call assert_match("^\n function <SNR>\\d\\+_bar() closure" 25267322bf7SBram Moolenaar \ .. "\n1 let x += 1" 25367322bf7SBram Moolenaar \ .. "\n2 return x" 25467322bf7SBram Moolenaar \ .. "\n endfunction$", execute('func s:bar')) 2551e115360SBram Moolenaarendfunc 25610ce39a0SBram Moolenaar 2571e115360SBram Moolenaarfunc Test_closure_unlet() 2581e115360SBram Moolenaar func! s:foo() 25910ce39a0SBram Moolenaar let x = 1 2601e115360SBram Moolenaar func! s:bar() closure 26110ce39a0SBram Moolenaar unlet x 2621e115360SBram Moolenaar endfunc 26310ce39a0SBram Moolenaar call s:bar() 26410ce39a0SBram Moolenaar return l: 2651e115360SBram Moolenaar endfunc 26610ce39a0SBram Moolenaar 26710ce39a0SBram Moolenaar call assert_false(has_key(s:foo(), 'x')) 26810ce39a0SBram Moolenaar call test_garbagecollect_now() 2691e115360SBram Moolenaarendfunc 27058016448SBram Moolenaar 2711e115360SBram Moolenaarfunc LambdaFoo() 27258016448SBram Moolenaar let x = 0 2731e115360SBram Moolenaar func! LambdaBar() closure 27458016448SBram Moolenaar let x += 1 27558016448SBram Moolenaar return x 2761e115360SBram Moolenaar endfunc 27758016448SBram Moolenaar return function('LambdaBar') 2781e115360SBram Moolenaarendfunc 27958016448SBram Moolenaar 28058016448SBram Moolenaarfunc Test_closure_refcount() 28158016448SBram Moolenaar let g:Count = LambdaFoo() 28258016448SBram Moolenaar call test_garbagecollect_now() 28358016448SBram Moolenaar call assert_equal(1, g:Count()) 28458016448SBram Moolenaar let g:Count2 = LambdaFoo() 28558016448SBram Moolenaar call test_garbagecollect_now() 28658016448SBram Moolenaar call assert_equal(1, g:Count2()) 28758016448SBram Moolenaar call assert_equal(2, g:Count()) 28858016448SBram Moolenaar call assert_equal(3, g:Count2()) 28958016448SBram Moolenaar 2900588d4f9SBram Moolenaar delfunc LambdaFoo 2910588d4f9SBram Moolenaar delfunc LambdaBar 29258016448SBram Moolenaarendfunc 293bc7ce675SBram Moolenaar 294bc7ce675SBram Moolenaarfunc Test_named_function_closure() 295bc7ce675SBram Moolenaar func! Afoo() 296bc7ce675SBram Moolenaar let x = 14 297bc7ce675SBram Moolenaar func! s:Abar() closure 298bc7ce675SBram Moolenaar return x 299bc7ce675SBram Moolenaar endfunc 300bc7ce675SBram Moolenaar call assert_equal(14, s:Abar()) 301bc7ce675SBram Moolenaar endfunc 302bc7ce675SBram Moolenaar call Afoo() 303bc7ce675SBram Moolenaar call assert_equal(14, s:Abar()) 304bc7ce675SBram Moolenaar call test_garbagecollect_now() 305bc7ce675SBram Moolenaar call assert_equal(14, s:Abar()) 306bc7ce675SBram Moolenaarendfunc 307b4518563SBram Moolenaar 308b4518563SBram Moolenaarfunc Test_lambda_with_index() 309b4518563SBram Moolenaar let List = {x -> [x]} 310b4518563SBram Moolenaar let Extract = {-> function(List, ['foobar'])()[0]} 311b4518563SBram Moolenaar call assert_equal('foobar', Extract()) 312b4518563SBram Moolenaarendfunc 3130ff822d2SBram Moolenaar 3140ff822d2SBram Moolenaarfunc Test_lambda_error() 3150ff822d2SBram Moolenaar " This was causing a crash 316e2e4075fSBram Moolenaar call assert_fails('ec{@{->{d->()()', 'E15:') 3170ff822d2SBram Moolenaarendfunc 3188b633135SBram Moolenaar 319ee4e0c1eSBram Moolenaarfunc Test_closure_error() 320ee4e0c1eSBram Moolenaar let l =<< trim END 321ee4e0c1eSBram Moolenaar func F1() closure 322ee4e0c1eSBram Moolenaar return 1 323ee4e0c1eSBram Moolenaar endfunc 324ee4e0c1eSBram Moolenaar END 325ee4e0c1eSBram Moolenaar call writefile(l, 'Xscript') 326ee4e0c1eSBram Moolenaar let caught_932 = 0 327ee4e0c1eSBram Moolenaar try 328ee4e0c1eSBram Moolenaar source Xscript 329ee4e0c1eSBram Moolenaar catch /E932:/ 330ee4e0c1eSBram Moolenaar let caught_932 = 1 331ee4e0c1eSBram Moolenaar endtry 332ee4e0c1eSBram Moolenaar call assert_equal(1, caught_932) 333*6c72fd51SDominique Pelle call delete('Xscript') 334ee4e0c1eSBram Moolenaarendfunc 335ee4e0c1eSBram Moolenaar 3368b633135SBram Moolenaar" vim: shiftwidth=2 sts=2 expandtab 337