110ce39a0SBram Moolenaar" Test for lambda and closure 210ce39a0SBram Moolenaar 31e115360SBram Moolenaarfunc Test_lambda_feature() 49532fe7fSBram Moolenaar call assert_equal(1, has('lambda')) 51e115360SBram Moolenaarendfunc 69532fe7fSBram Moolenaar 71e115360SBram Moolenaarfunc Test_lambda_with_filter() 8069c1e7fSBram Moolenaar let s:x = 2 9069c1e7fSBram Moolenaar call assert_equal([2, 3], filter([1, 2, 3], {i, v -> v >= s:x})) 101e115360SBram Moolenaarendfunc 11069c1e7fSBram Moolenaar 121e115360SBram Moolenaarfunc Test_lambda_with_map() 13069c1e7fSBram Moolenaar let s:x = 1 14069c1e7fSBram Moolenaar call assert_equal([2, 3, 4], map([1, 2, 3], {i, v -> v + s:x})) 151e115360SBram Moolenaarendfunc 16069c1e7fSBram Moolenaar 171e115360SBram Moolenaarfunc Test_lambda_with_sort() 18069c1e7fSBram Moolenaar call assert_equal([1, 2, 3, 4, 7], sort([3,7,2,1,4], {a, b -> a - b})) 191e115360SBram Moolenaarendfunc 20069c1e7fSBram Moolenaar 211e115360SBram Moolenaarfunc Test_lambda_with_timer() 22069c1e7fSBram Moolenaar if !has('timers') 23069c1e7fSBram Moolenaar return 24069c1e7fSBram Moolenaar endif 25069c1e7fSBram Moolenaar 26069c1e7fSBram Moolenaar let s:n = 0 27069c1e7fSBram Moolenaar let s:timer_id = 0 281e115360SBram Moolenaar func! s:Foo() 29*9bc4dde4SBram 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() 33*9bc4dde4SBram Moolenaar " check timer works 34*9bc4dde4SBram Moolenaar for i in range(0, 10) 35*9bc4dde4SBram Moolenaar if s:n > 0 36*9bc4dde4SBram Moolenaar break 37*9bc4dde4SBram Moolenaar endif 38*9bc4dde4SBram Moolenaar sleep 10m 39*9bc4dde4SBram Moolenaar endfor 40*9bc4dde4SBram Moolenaar 41069c1e7fSBram Moolenaar " do not collect lambda 42069c1e7fSBram Moolenaar call test_garbagecollect_now() 43*9bc4dde4SBram Moolenaar 44*9bc4dde4SBram Moolenaar " check timer still works 45069c1e7fSBram Moolenaar let m = s:n 46*9bc4dde4SBram Moolenaar for i in range(0, 10) 47*9bc4dde4SBram Moolenaar if s:n > m 48*9bc4dde4SBram Moolenaar break 49*9bc4dde4SBram Moolenaar endif 50*9bc4dde4SBram Moolenaar sleep 10m 51*9bc4dde4SBram Moolenaar endfor 52*9bc4dde4SBram Moolenaar 53069c1e7fSBram Moolenaar call timer_stop(s:timer_id) 54*9bc4dde4SBram 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:') 65069c1e7fSBram Moolenaar call assert_fails('echo {a, b -> a + b)}(1, 2)', 'E15:') 66069c1e7fSBram Moolenaarendfunc 674f0383bcSBram Moolenaar 684f0383bcSBram Moolenaarfunc Test_not_lamda() 694f0383bcSBram Moolenaar let x = {'>' : 'foo'} 704f0383bcSBram Moolenaar call assert_equal('foo', x['>']) 714f0383bcSBram Moolenaarendfunc 721e96d9bfSBram Moolenaar 731e115360SBram Moolenaarfunc Test_lambda_capture_by_reference() 741e96d9bfSBram Moolenaar let v = 1 751e96d9bfSBram Moolenaar let l:F = {x -> x + v} 761e96d9bfSBram Moolenaar let v = 2 771e96d9bfSBram Moolenaar call assert_equal(12, l:F(10)) 781e115360SBram Moolenaarendfunc 791e96d9bfSBram Moolenaar 801e115360SBram Moolenaarfunc Test_lambda_side_effect() 811e115360SBram Moolenaar func! s:update_and_return(arr) 821e96d9bfSBram Moolenaar let a:arr[1] = 5 831e96d9bfSBram Moolenaar return a:arr 841e115360SBram Moolenaar endfunc 851e96d9bfSBram Moolenaar 861e115360SBram Moolenaar func! s:foo(arr) 871e96d9bfSBram Moolenaar return {-> s:update_and_return(a:arr)} 881e115360SBram Moolenaar endfunc 891e96d9bfSBram Moolenaar 901e96d9bfSBram Moolenaar let arr = [3,2,1] 911e96d9bfSBram Moolenaar call assert_equal([3, 5, 1], s:foo(arr)()) 921e115360SBram Moolenaarendfunc 931e96d9bfSBram Moolenaar 941e115360SBram Moolenaarfunc Test_lambda_refer_local_variable_from_other_scope() 951e115360SBram Moolenaar func! s:foo(X) 961e96d9bfSBram Moolenaar return a:X() " refer l:x in s:bar() 971e115360SBram Moolenaar endfunc 981e96d9bfSBram Moolenaar 991e115360SBram Moolenaar func! s:bar() 1001e96d9bfSBram Moolenaar let x = 123 1011e96d9bfSBram Moolenaar return s:foo({-> x}) 1021e115360SBram Moolenaar endfunc 1031e96d9bfSBram Moolenaar 1041e96d9bfSBram Moolenaar call assert_equal(123, s:bar()) 1051e115360SBram Moolenaarendfunc 1061e96d9bfSBram Moolenaar 1071e115360SBram Moolenaarfunc Test_lambda_do_not_share_local_variable() 1081e115360SBram Moolenaar func! s:define_funcs() 1091e96d9bfSBram Moolenaar let l:One = {-> split(execute("let a = 'abc' | echo a"))[0]} 1101e96d9bfSBram Moolenaar let l:Two = {-> exists("a") ? a : "no"} 1111e96d9bfSBram Moolenaar return [l:One, l:Two] 1121e115360SBram Moolenaar endfunc 1131e96d9bfSBram Moolenaar 1141e96d9bfSBram Moolenaar let l:F = s:define_funcs() 1151e96d9bfSBram Moolenaar 1161e96d9bfSBram Moolenaar call assert_equal('no', l:F[1]()) 1171e96d9bfSBram Moolenaar call assert_equal('abc', l:F[0]()) 1181e96d9bfSBram Moolenaar call assert_equal('no', l:F[1]()) 1191e115360SBram Moolenaarendfunc 1201e96d9bfSBram Moolenaar 1211e115360SBram Moolenaarfunc Test_lambda_closure_counter() 1221e115360SBram Moolenaar func! s:foo() 1231e96d9bfSBram Moolenaar let x = 0 1241e96d9bfSBram Moolenaar return {-> [execute("let x += 1"), x][-1]} 1251e115360SBram Moolenaar endfunc 1261e96d9bfSBram Moolenaar 1271e96d9bfSBram Moolenaar let l:F = s:foo() 1281e96d9bfSBram Moolenaar call test_garbagecollect_now() 1291e96d9bfSBram Moolenaar call assert_equal(1, l:F()) 1301e96d9bfSBram Moolenaar call assert_equal(2, l:F()) 1311e96d9bfSBram Moolenaar call assert_equal(3, l:F()) 1321e96d9bfSBram Moolenaar call assert_equal(4, l:F()) 1331e115360SBram Moolenaarendfunc 1341e96d9bfSBram Moolenaar 1351e115360SBram Moolenaarfunc Test_lambda_with_a_var() 1361e115360SBram Moolenaar func! s:foo() 1371e96d9bfSBram Moolenaar let x = 2 1381e96d9bfSBram Moolenaar return {... -> a:000 + [x]} 1391e115360SBram Moolenaar endfunc 1401e115360SBram Moolenaar func! s:bar() 1411e96d9bfSBram Moolenaar return s:foo()(1) 1421e115360SBram Moolenaar endfunc 1431e96d9bfSBram Moolenaar 1441e96d9bfSBram Moolenaar call assert_equal([1, 2], s:bar()) 1451e115360SBram Moolenaarendfunc 1461e96d9bfSBram Moolenaar 1471e115360SBram Moolenaarfunc Test_lambda_call_lambda_from_lambda() 1481e115360SBram Moolenaar func! s:foo(x) 1491e96d9bfSBram Moolenaar let l:F1 = {-> {-> a:x}} 1501e96d9bfSBram Moolenaar return {-> l:F1()} 1511e115360SBram Moolenaar endfunc 1521e96d9bfSBram Moolenaar 1531e96d9bfSBram Moolenaar let l:F = s:foo(1) 1541e96d9bfSBram Moolenaar call assert_equal(1, l:F()()) 1551e115360SBram Moolenaarendfunc 1561e96d9bfSBram Moolenaar 1571e115360SBram Moolenaarfunc Test_lambda_delfunc() 1581e115360SBram Moolenaar func! s:gen() 1591e96d9bfSBram Moolenaar let pl = l: 1601e96d9bfSBram Moolenaar let l:Foo = {-> get(pl, "Foo", get(pl, "Bar", {-> 0}))} 1611e96d9bfSBram Moolenaar let l:Bar = l:Foo 1621e96d9bfSBram Moolenaar delfunction l:Foo 1631e96d9bfSBram Moolenaar return l:Bar 1641e115360SBram Moolenaar endfunc 1651e96d9bfSBram Moolenaar 1661e96d9bfSBram Moolenaar let l:F = s:gen() 167437bafe4SBram Moolenaar call assert_fails(':call l:F()', 'E933:') 1681e115360SBram Moolenaarendfunc 1691e96d9bfSBram Moolenaar 1701e115360SBram Moolenaarfunc Test_lambda_scope() 1711e115360SBram Moolenaar func! s:NewCounter() 1721e96d9bfSBram Moolenaar let c = 0 1731e96d9bfSBram Moolenaar return {-> [execute('let c += 1'), c][-1]} 1741e115360SBram Moolenaar endfunc 1751e96d9bfSBram Moolenaar 1761e115360SBram Moolenaar func! s:NewCounter2() 1771e96d9bfSBram Moolenaar return {-> [execute('let c += 100'), c][-1]} 1781e115360SBram Moolenaar endfunc 1791e96d9bfSBram Moolenaar 1801e96d9bfSBram Moolenaar let l:C = s:NewCounter() 1811e96d9bfSBram Moolenaar let l:D = s:NewCounter2() 1821e96d9bfSBram Moolenaar 1831e96d9bfSBram Moolenaar call assert_equal(1, l:C()) 184c0f5a78cSBram Moolenaar call assert_fails(':call l:D()', 'E121:') 1851e96d9bfSBram Moolenaar call assert_equal(2, l:C()) 1861e115360SBram Moolenaarendfunc 1871e96d9bfSBram Moolenaar 1881e115360SBram Moolenaarfunc Test_lambda_share_scope() 1891e115360SBram Moolenaar func! s:New() 1901e96d9bfSBram Moolenaar let c = 0 1911e96d9bfSBram Moolenaar let l:Inc0 = {-> [execute('let c += 1'), c][-1]} 1921e96d9bfSBram Moolenaar let l:Dec0 = {-> [execute('let c -= 1'), c][-1]} 1931e96d9bfSBram Moolenaar return [l:Inc0, l:Dec0] 1941e115360SBram Moolenaar endfunc 1951e96d9bfSBram Moolenaar 1961e96d9bfSBram Moolenaar let [l:Inc, l:Dec] = s:New() 1971e96d9bfSBram Moolenaar 1981e96d9bfSBram Moolenaar call assert_equal(1, l:Inc()) 1991e96d9bfSBram Moolenaar call assert_equal(2, l:Inc()) 2001e96d9bfSBram Moolenaar call assert_equal(1, l:Dec()) 2011e115360SBram Moolenaarendfunc 2021e96d9bfSBram Moolenaar 2031e115360SBram Moolenaarfunc Test_lambda_circular_reference() 2041e115360SBram Moolenaar func! s:Foo() 2051e96d9bfSBram Moolenaar let d = {} 2061e96d9bfSBram Moolenaar let d.f = {-> d} 2071e96d9bfSBram Moolenaar return d.f 2081e115360SBram Moolenaar endfunc 2091e96d9bfSBram Moolenaar 2101e96d9bfSBram Moolenaar call s:Foo() 2111e96d9bfSBram Moolenaar call test_garbagecollect_now() 2121e96d9bfSBram Moolenaar let i = 0 | while i < 10000 | call s:Foo() | let i+= 1 | endwhile 2131e96d9bfSBram Moolenaar call test_garbagecollect_now() 2141e115360SBram Moolenaarendfunc 2151e96d9bfSBram Moolenaar 2161e115360SBram Moolenaarfunc Test_lambda_combination() 2171e96d9bfSBram Moolenaar call assert_equal(2, {x -> {x -> x}}(1)(2)) 2181e96d9bfSBram Moolenaar call assert_equal(10, {y -> {x -> x(y)(10)}({y -> y})}({z -> z})) 2191e96d9bfSBram Moolenaar call assert_equal(5.0, {x -> {y -> x / y}}(10)(2.0)) 2201e96d9bfSBram Moolenaar call assert_equal(6, {x -> {y -> {z -> x + y + z}}}(1)(2)(3)) 2211e96d9bfSBram Moolenaar 2221e96d9bfSBram Moolenaar call assert_equal(6, {x -> {f -> f(x)}}(3)({x -> x * 2})) 2231e96d9bfSBram Moolenaar call assert_equal(6, {f -> {x -> f(x)}}({x -> x * 2})(3)) 2241e96d9bfSBram Moolenaar 2251e96d9bfSBram Moolenaar " Z combinator 2261e96d9bfSBram Moolenaar let Z = {f -> {x -> f({y -> x(x)(y)})}({x -> f({y -> x(x)(y)})})} 2271e96d9bfSBram Moolenaar let Fact = {f -> {x -> x == 0 ? 1 : x * f(x - 1)}} 2281e96d9bfSBram Moolenaar call assert_equal(120, Z(Fact)(5)) 2291e115360SBram Moolenaarendfunc 23010ce39a0SBram Moolenaar 2311e115360SBram Moolenaarfunc Test_closure_counter() 2321e115360SBram Moolenaar func! s:foo() 23310ce39a0SBram Moolenaar let x = 0 2341e115360SBram Moolenaar func! s:bar() closure 23510ce39a0SBram Moolenaar let x += 1 23610ce39a0SBram Moolenaar return x 2371e115360SBram Moolenaar endfunc 23810ce39a0SBram Moolenaar return function('s:bar') 2391e115360SBram Moolenaar endfunc 24010ce39a0SBram Moolenaar 24110ce39a0SBram Moolenaar let l:F = s:foo() 24210ce39a0SBram Moolenaar call test_garbagecollect_now() 24310ce39a0SBram Moolenaar call assert_equal(1, l:F()) 24410ce39a0SBram Moolenaar call assert_equal(2, l:F()) 24510ce39a0SBram Moolenaar call assert_equal(3, l:F()) 24610ce39a0SBram Moolenaar call assert_equal(4, l:F()) 2471e115360SBram Moolenaarendfunc 24810ce39a0SBram Moolenaar 2491e115360SBram Moolenaarfunc Test_closure_unlet() 2501e115360SBram Moolenaar func! s:foo() 25110ce39a0SBram Moolenaar let x = 1 2521e115360SBram Moolenaar func! s:bar() closure 25310ce39a0SBram Moolenaar unlet x 2541e115360SBram Moolenaar endfunc 25510ce39a0SBram Moolenaar call s:bar() 25610ce39a0SBram Moolenaar return l: 2571e115360SBram Moolenaar endfunc 25810ce39a0SBram Moolenaar 25910ce39a0SBram Moolenaar call assert_false(has_key(s:foo(), 'x')) 26010ce39a0SBram Moolenaar call test_garbagecollect_now() 2611e115360SBram Moolenaarendfunc 26258016448SBram Moolenaar 2631e115360SBram Moolenaarfunc LambdaFoo() 26458016448SBram Moolenaar let x = 0 2651e115360SBram Moolenaar func! LambdaBar() closure 26658016448SBram Moolenaar let x += 1 26758016448SBram Moolenaar return x 2681e115360SBram Moolenaar endfunc 26958016448SBram Moolenaar return function('LambdaBar') 2701e115360SBram Moolenaarendfunc 27158016448SBram Moolenaar 27258016448SBram Moolenaarfunc Test_closure_refcount() 27358016448SBram Moolenaar let g:Count = LambdaFoo() 27458016448SBram Moolenaar call test_garbagecollect_now() 27558016448SBram Moolenaar call assert_equal(1, g:Count()) 27658016448SBram Moolenaar let g:Count2 = LambdaFoo() 27758016448SBram Moolenaar call test_garbagecollect_now() 27858016448SBram Moolenaar call assert_equal(1, g:Count2()) 27958016448SBram Moolenaar call assert_equal(2, g:Count()) 28058016448SBram Moolenaar call assert_equal(3, g:Count2()) 28158016448SBram Moolenaar 2820588d4f9SBram Moolenaar delfunc LambdaFoo 2830588d4f9SBram Moolenaar delfunc LambdaBar 28458016448SBram Moolenaarendfunc 285bc7ce675SBram Moolenaar 286bc7ce675SBram Moolenaarfunc Test_named_function_closure() 287bc7ce675SBram Moolenaar func! Afoo() 288bc7ce675SBram Moolenaar let x = 14 289bc7ce675SBram Moolenaar func! s:Abar() closure 290bc7ce675SBram Moolenaar return x 291bc7ce675SBram Moolenaar endfunc 292bc7ce675SBram Moolenaar call assert_equal(14, s:Abar()) 293bc7ce675SBram Moolenaar endfunc 294bc7ce675SBram Moolenaar call Afoo() 295bc7ce675SBram Moolenaar call assert_equal(14, s:Abar()) 296bc7ce675SBram Moolenaar call test_garbagecollect_now() 297bc7ce675SBram Moolenaar call assert_equal(14, s:Abar()) 298bc7ce675SBram Moolenaarendfunc 299b4518563SBram Moolenaar 300b4518563SBram Moolenaarfunc Test_lambda_with_index() 301b4518563SBram Moolenaar let List = {x -> [x]} 302b4518563SBram Moolenaar let Extract = {-> function(List, ['foobar'])()[0]} 303b4518563SBram Moolenaar call assert_equal('foobar', Extract()) 304b4518563SBram Moolenaarendfunc 305