xref: /vim-8.2.3635/src/testdir/test_lambda.vim (revision 0ff822d2)
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()
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:')
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*0ff822d2SBram Moolenaar
306*0ff822d2SBram Moolenaarfunc Test_lambda_error()
307*0ff822d2SBram Moolenaar  " This was causing a crash
308*0ff822d2SBram Moolenaar  call assert_fails('ec{@{->{d->()()', 'E15')
309*0ff822d2SBram Moolenaarendfunc
310