xref: /vim-8.2.3635/src/testdir/test_lambda.vim (revision c0f5a78c)
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()
29069c1e7fSBram Moolenaar    "let n = 0
301e96d9bfSBram Moolenaar    let s:timer_id = timer_start(50, {-> execute("let s:n += 1 | echo s:n", "")}, {"repeat": -1})
311e115360SBram Moolenaar  endfunc
32069c1e7fSBram Moolenaar
33069c1e7fSBram Moolenaar  call s:Foo()
34069c1e7fSBram Moolenaar  sleep 200ms
35069c1e7fSBram Moolenaar  " do not collect lambda
36069c1e7fSBram Moolenaar  call test_garbagecollect_now()
37069c1e7fSBram Moolenaar  let m = s:n
38069c1e7fSBram Moolenaar  sleep 200ms
39069c1e7fSBram Moolenaar  call timer_stop(s:timer_id)
40069c1e7fSBram Moolenaar  call assert_true(m > 1)
41069c1e7fSBram Moolenaar  call assert_true(s:n > m + 1)
42069c1e7fSBram Moolenaar  call assert_true(s:n < 9)
431e115360SBram Moolenaarendfunc
44069c1e7fSBram Moolenaar
451e115360SBram Moolenaarfunc Test_lambda_with_partial()
46069c1e7fSBram Moolenaar  let l:Cb = function({... -> ['zero', a:1, a:2, a:3]}, ['one', 'two'])
47069c1e7fSBram Moolenaar  call assert_equal(['zero', 'one', 'two', 'three'], l:Cb('three'))
481e115360SBram Moolenaarendfunc
49069c1e7fSBram Moolenaar
50069c1e7fSBram Moolenaarfunction Test_lambda_fails()
51069c1e7fSBram Moolenaar  call assert_equal(3, {a, b -> a + b}(1, 2))
52*c0f5a78cSBram Moolenaar  call assert_fails('echo {a, a -> a + a}(1, 2)', 'E853:')
53069c1e7fSBram Moolenaar  call assert_fails('echo {a, b -> a + b)}(1, 2)', 'E15:')
54069c1e7fSBram Moolenaarendfunc
554f0383bcSBram Moolenaar
564f0383bcSBram Moolenaarfunc Test_not_lamda()
574f0383bcSBram Moolenaar  let x = {'>' : 'foo'}
584f0383bcSBram Moolenaar  call assert_equal('foo', x['>'])
594f0383bcSBram Moolenaarendfunc
601e96d9bfSBram Moolenaar
611e115360SBram Moolenaarfunc Test_lambda_capture_by_reference()
621e96d9bfSBram Moolenaar  let v = 1
631e96d9bfSBram Moolenaar  let l:F = {x -> x + v}
641e96d9bfSBram Moolenaar  let v = 2
651e96d9bfSBram Moolenaar  call assert_equal(12, l:F(10))
661e115360SBram Moolenaarendfunc
671e96d9bfSBram Moolenaar
681e115360SBram Moolenaarfunc Test_lambda_side_effect()
691e115360SBram Moolenaar  func! s:update_and_return(arr)
701e96d9bfSBram Moolenaar    let a:arr[1] = 5
711e96d9bfSBram Moolenaar    return a:arr
721e115360SBram Moolenaar  endfunc
731e96d9bfSBram Moolenaar
741e115360SBram Moolenaar  func! s:foo(arr)
751e96d9bfSBram Moolenaar    return {-> s:update_and_return(a:arr)}
761e115360SBram Moolenaar  endfunc
771e96d9bfSBram Moolenaar
781e96d9bfSBram Moolenaar  let arr = [3,2,1]
791e96d9bfSBram Moolenaar  call assert_equal([3, 5, 1], s:foo(arr)())
801e115360SBram Moolenaarendfunc
811e96d9bfSBram Moolenaar
821e115360SBram Moolenaarfunc Test_lambda_refer_local_variable_from_other_scope()
831e115360SBram Moolenaar  func! s:foo(X)
841e96d9bfSBram Moolenaar    return a:X() " refer l:x in s:bar()
851e115360SBram Moolenaar  endfunc
861e96d9bfSBram Moolenaar
871e115360SBram Moolenaar  func! s:bar()
881e96d9bfSBram Moolenaar    let x = 123
891e96d9bfSBram Moolenaar    return s:foo({-> x})
901e115360SBram Moolenaar  endfunc
911e96d9bfSBram Moolenaar
921e96d9bfSBram Moolenaar  call assert_equal(123, s:bar())
931e115360SBram Moolenaarendfunc
941e96d9bfSBram Moolenaar
951e115360SBram Moolenaarfunc Test_lambda_do_not_share_local_variable()
961e115360SBram Moolenaar  func! s:define_funcs()
971e96d9bfSBram Moolenaar    let l:One = {-> split(execute("let a = 'abc' | echo a"))[0]}
981e96d9bfSBram Moolenaar    let l:Two = {-> exists("a") ? a : "no"}
991e96d9bfSBram Moolenaar    return [l:One, l:Two]
1001e115360SBram Moolenaar  endfunc
1011e96d9bfSBram Moolenaar
1021e96d9bfSBram Moolenaar  let l:F = s:define_funcs()
1031e96d9bfSBram Moolenaar
1041e96d9bfSBram Moolenaar  call assert_equal('no', l:F[1]())
1051e96d9bfSBram Moolenaar  call assert_equal('abc', l:F[0]())
1061e96d9bfSBram Moolenaar  call assert_equal('no', l:F[1]())
1071e115360SBram Moolenaarendfunc
1081e96d9bfSBram Moolenaar
1091e115360SBram Moolenaarfunc Test_lambda_closure_counter()
1101e115360SBram Moolenaar  func! s:foo()
1111e96d9bfSBram Moolenaar    let x = 0
1121e96d9bfSBram Moolenaar    return {-> [execute("let x += 1"), x][-1]}
1131e115360SBram Moolenaar  endfunc
1141e96d9bfSBram Moolenaar
1151e96d9bfSBram Moolenaar  let l:F = s:foo()
1161e96d9bfSBram Moolenaar  call test_garbagecollect_now()
1171e96d9bfSBram Moolenaar  call assert_equal(1, l:F())
1181e96d9bfSBram Moolenaar  call assert_equal(2, l:F())
1191e96d9bfSBram Moolenaar  call assert_equal(3, l:F())
1201e96d9bfSBram Moolenaar  call assert_equal(4, l:F())
1211e115360SBram Moolenaarendfunc
1221e96d9bfSBram Moolenaar
1231e115360SBram Moolenaarfunc Test_lambda_with_a_var()
1241e115360SBram Moolenaar  func! s:foo()
1251e96d9bfSBram Moolenaar    let x = 2
1261e96d9bfSBram Moolenaar    return {... -> a:000 + [x]}
1271e115360SBram Moolenaar  endfunc
1281e115360SBram Moolenaar  func! s:bar()
1291e96d9bfSBram Moolenaar    return s:foo()(1)
1301e115360SBram Moolenaar  endfunc
1311e96d9bfSBram Moolenaar
1321e96d9bfSBram Moolenaar  call assert_equal([1, 2], s:bar())
1331e115360SBram Moolenaarendfunc
1341e96d9bfSBram Moolenaar
1351e115360SBram Moolenaarfunc Test_lambda_call_lambda_from_lambda()
1361e115360SBram Moolenaar  func! s:foo(x)
1371e96d9bfSBram Moolenaar    let l:F1 = {-> {-> a:x}}
1381e96d9bfSBram Moolenaar    return {-> l:F1()}
1391e115360SBram Moolenaar  endfunc
1401e96d9bfSBram Moolenaar
1411e96d9bfSBram Moolenaar  let l:F = s:foo(1)
1421e96d9bfSBram Moolenaar  call assert_equal(1, l:F()())
1431e115360SBram Moolenaarendfunc
1441e96d9bfSBram Moolenaar
1451e115360SBram Moolenaarfunc Test_lambda_delfunc()
1461e115360SBram Moolenaar  func! s:gen()
1471e96d9bfSBram Moolenaar    let pl = l:
1481e96d9bfSBram Moolenaar    let l:Foo = {-> get(pl, "Foo", get(pl, "Bar", {-> 0}))}
1491e96d9bfSBram Moolenaar    let l:Bar = l:Foo
1501e96d9bfSBram Moolenaar    delfunction l:Foo
1511e96d9bfSBram Moolenaar    return l:Bar
1521e115360SBram Moolenaar  endfunc
1531e96d9bfSBram Moolenaar
1541e96d9bfSBram Moolenaar  let l:F = s:gen()
155437bafe4SBram Moolenaar  call assert_fails(':call l:F()', 'E933:')
1561e115360SBram Moolenaarendfunc
1571e96d9bfSBram Moolenaar
1581e115360SBram Moolenaarfunc Test_lambda_scope()
1591e115360SBram Moolenaar  func! s:NewCounter()
1601e96d9bfSBram Moolenaar    let c = 0
1611e96d9bfSBram Moolenaar    return {-> [execute('let c += 1'), c][-1]}
1621e115360SBram Moolenaar  endfunc
1631e96d9bfSBram Moolenaar
1641e115360SBram Moolenaar  func! s:NewCounter2()
1651e96d9bfSBram Moolenaar    return {-> [execute('let c += 100'), c][-1]}
1661e115360SBram Moolenaar  endfunc
1671e96d9bfSBram Moolenaar
1681e96d9bfSBram Moolenaar  let l:C = s:NewCounter()
1691e96d9bfSBram Moolenaar  let l:D = s:NewCounter2()
1701e96d9bfSBram Moolenaar
1711e96d9bfSBram Moolenaar  call assert_equal(1, l:C())
172*c0f5a78cSBram Moolenaar  call assert_fails(':call l:D()', 'E121:')
1731e96d9bfSBram Moolenaar  call assert_equal(2, l:C())
1741e115360SBram Moolenaarendfunc
1751e96d9bfSBram Moolenaar
1761e115360SBram Moolenaarfunc Test_lambda_share_scope()
1771e115360SBram Moolenaar  func! s:New()
1781e96d9bfSBram Moolenaar    let c = 0
1791e96d9bfSBram Moolenaar    let l:Inc0 = {-> [execute('let c += 1'), c][-1]}
1801e96d9bfSBram Moolenaar    let l:Dec0 = {-> [execute('let c -= 1'), c][-1]}
1811e96d9bfSBram Moolenaar    return [l:Inc0, l:Dec0]
1821e115360SBram Moolenaar  endfunc
1831e96d9bfSBram Moolenaar
1841e96d9bfSBram Moolenaar  let [l:Inc, l:Dec] = s:New()
1851e96d9bfSBram Moolenaar
1861e96d9bfSBram Moolenaar  call assert_equal(1, l:Inc())
1871e96d9bfSBram Moolenaar  call assert_equal(2, l:Inc())
1881e96d9bfSBram Moolenaar  call assert_equal(1, l:Dec())
1891e115360SBram Moolenaarendfunc
1901e96d9bfSBram Moolenaar
1911e115360SBram Moolenaarfunc Test_lambda_circular_reference()
1921e115360SBram Moolenaar  func! s:Foo()
1931e96d9bfSBram Moolenaar    let d = {}
1941e96d9bfSBram Moolenaar    let d.f = {-> d}
1951e96d9bfSBram Moolenaar    return d.f
1961e115360SBram Moolenaar  endfunc
1971e96d9bfSBram Moolenaar
1981e96d9bfSBram Moolenaar  call s:Foo()
1991e96d9bfSBram Moolenaar  call test_garbagecollect_now()
2001e96d9bfSBram Moolenaar  let i = 0 | while i < 10000 | call s:Foo() | let i+= 1 | endwhile
2011e96d9bfSBram Moolenaar  call test_garbagecollect_now()
2021e115360SBram Moolenaarendfunc
2031e96d9bfSBram Moolenaar
2041e115360SBram Moolenaarfunc Test_lambda_combination()
2051e96d9bfSBram Moolenaar  call assert_equal(2, {x -> {x -> x}}(1)(2))
2061e96d9bfSBram Moolenaar  call assert_equal(10, {y -> {x -> x(y)(10)}({y -> y})}({z -> z}))
2071e96d9bfSBram Moolenaar  call assert_equal(5.0, {x -> {y -> x / y}}(10)(2.0))
2081e96d9bfSBram Moolenaar  call assert_equal(6, {x -> {y -> {z -> x + y + z}}}(1)(2)(3))
2091e96d9bfSBram Moolenaar
2101e96d9bfSBram Moolenaar  call assert_equal(6, {x -> {f -> f(x)}}(3)({x -> x * 2}))
2111e96d9bfSBram Moolenaar  call assert_equal(6, {f -> {x -> f(x)}}({x -> x * 2})(3))
2121e96d9bfSBram Moolenaar
2131e96d9bfSBram Moolenaar  " Z combinator
2141e96d9bfSBram Moolenaar  let Z = {f -> {x -> f({y -> x(x)(y)})}({x -> f({y -> x(x)(y)})})}
2151e96d9bfSBram Moolenaar  let Fact = {f -> {x -> x == 0 ? 1 : x * f(x - 1)}}
2161e96d9bfSBram Moolenaar  call assert_equal(120, Z(Fact)(5))
2171e115360SBram Moolenaarendfunc
21810ce39a0SBram Moolenaar
2191e115360SBram Moolenaarfunc Test_closure_counter()
2201e115360SBram Moolenaar  func! s:foo()
22110ce39a0SBram Moolenaar    let x = 0
2221e115360SBram Moolenaar    func! s:bar() closure
22310ce39a0SBram Moolenaar      let x += 1
22410ce39a0SBram Moolenaar      return x
2251e115360SBram Moolenaar    endfunc
22610ce39a0SBram Moolenaar    return function('s:bar')
2271e115360SBram Moolenaar  endfunc
22810ce39a0SBram Moolenaar
22910ce39a0SBram Moolenaar  let l:F = s:foo()
23010ce39a0SBram Moolenaar  call test_garbagecollect_now()
23110ce39a0SBram Moolenaar  call assert_equal(1, l:F())
23210ce39a0SBram Moolenaar  call assert_equal(2, l:F())
23310ce39a0SBram Moolenaar  call assert_equal(3, l:F())
23410ce39a0SBram Moolenaar  call assert_equal(4, l:F())
2351e115360SBram Moolenaarendfunc
23610ce39a0SBram Moolenaar
2371e115360SBram Moolenaarfunc Test_closure_unlet()
2381e115360SBram Moolenaar  func! s:foo()
23910ce39a0SBram Moolenaar    let x = 1
2401e115360SBram Moolenaar    func! s:bar() closure
24110ce39a0SBram Moolenaar      unlet x
2421e115360SBram Moolenaar    endfunc
24310ce39a0SBram Moolenaar    call s:bar()
24410ce39a0SBram Moolenaar    return l:
2451e115360SBram Moolenaar  endfunc
24610ce39a0SBram Moolenaar
24710ce39a0SBram Moolenaar  call assert_false(has_key(s:foo(), 'x'))
24810ce39a0SBram Moolenaar  call test_garbagecollect_now()
2491e115360SBram Moolenaarendfunc
25058016448SBram Moolenaar
2511e115360SBram Moolenaarfunc LambdaFoo()
25258016448SBram Moolenaar  let x = 0
2531e115360SBram Moolenaar  func! LambdaBar() closure
25458016448SBram Moolenaar    let x += 1
25558016448SBram Moolenaar    return x
2561e115360SBram Moolenaar  endfunc
25758016448SBram Moolenaar  return function('LambdaBar')
2581e115360SBram Moolenaarendfunc
25958016448SBram Moolenaar
26058016448SBram Moolenaarfunc Test_closure_refcount()
26158016448SBram Moolenaar  let g:Count = LambdaFoo()
26258016448SBram Moolenaar  call test_garbagecollect_now()
26358016448SBram Moolenaar  call assert_equal(1, g:Count())
26458016448SBram Moolenaar  let g:Count2 = LambdaFoo()
26558016448SBram Moolenaar  call test_garbagecollect_now()
26658016448SBram Moolenaar  call assert_equal(1, g:Count2())
26758016448SBram Moolenaar  call assert_equal(2, g:Count())
26858016448SBram Moolenaar  call assert_equal(3, g:Count2())
26958016448SBram Moolenaar
2700588d4f9SBram Moolenaar  delfunc LambdaFoo
2710588d4f9SBram Moolenaar  delfunc LambdaBar
27258016448SBram Moolenaarendfunc
273bc7ce675SBram Moolenaar
274bc7ce675SBram Moolenaarfunc Test_named_function_closure()
275bc7ce675SBram Moolenaar  func! Afoo()
276bc7ce675SBram Moolenaar    let x = 14
277bc7ce675SBram Moolenaar    func! s:Abar() closure
278bc7ce675SBram Moolenaar      return x
279bc7ce675SBram Moolenaar    endfunc
280bc7ce675SBram Moolenaar    call assert_equal(14, s:Abar())
281bc7ce675SBram Moolenaar  endfunc
282bc7ce675SBram Moolenaar  call Afoo()
283bc7ce675SBram Moolenaar  call assert_equal(14, s:Abar())
284bc7ce675SBram Moolenaar  call test_garbagecollect_now()
285bc7ce675SBram Moolenaar  call assert_equal(14, s:Abar())
286bc7ce675SBram Moolenaarendfunc
287b4518563SBram Moolenaar
288b4518563SBram Moolenaarfunc Test_lambda_with_index()
289b4518563SBram Moolenaar  let List = {x -> [x]}
290b4518563SBram Moolenaar  let Extract = {-> function(List, ['foobar'])()[0]}
291b4518563SBram Moolenaar  call assert_equal('foobar', Extract())
292b4518563SBram Moolenaarendfunc
293