xref: /vim-8.2.3635/src/testdir/test_lambda.vim (revision 6c72fd51)
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