xref: /vim-8.2.3635/src/testdir/test_lambda.vim (revision 10ce39a0)
1*10ce39a0SBram Moolenaar" Test for lambda and closure
2*10ce39a0SBram Moolenaar
3069c1e7fSBram Moolenaarfunction! Test_lambda_with_filter()
4069c1e7fSBram Moolenaar  let s:x = 2
5069c1e7fSBram Moolenaar  call assert_equal([2, 3], filter([1, 2, 3], {i, v -> v >= s:x}))
6069c1e7fSBram Moolenaarendfunction
7069c1e7fSBram Moolenaar
8069c1e7fSBram Moolenaarfunction! Test_lambda_with_map()
9069c1e7fSBram Moolenaar  let s:x = 1
10069c1e7fSBram Moolenaar  call assert_equal([2, 3, 4], map([1, 2, 3], {i, v -> v + s:x}))
11069c1e7fSBram Moolenaarendfunction
12069c1e7fSBram Moolenaar
13069c1e7fSBram Moolenaarfunction! Test_lambda_with_sort()
14069c1e7fSBram Moolenaar  call assert_equal([1, 2, 3, 4, 7], sort([3,7,2,1,4], {a, b -> a - b}))
15069c1e7fSBram Moolenaarendfunction
16069c1e7fSBram Moolenaar
17069c1e7fSBram Moolenaarfunction! Test_lambda_with_timer()
18069c1e7fSBram Moolenaar  if !has('timers')
19069c1e7fSBram Moolenaar    return
20069c1e7fSBram Moolenaar  endif
21069c1e7fSBram Moolenaar
22069c1e7fSBram Moolenaar  let s:n = 0
23069c1e7fSBram Moolenaar  let s:timer_id = 0
24069c1e7fSBram Moolenaar  function! s:Foo()
25069c1e7fSBram Moolenaar    "let n = 0
261e96d9bfSBram Moolenaar    let s:timer_id = timer_start(50, {-> execute("let s:n += 1 | echo s:n", "")}, {"repeat": -1})
27069c1e7fSBram Moolenaar  endfunction
28069c1e7fSBram Moolenaar
29069c1e7fSBram Moolenaar  call s:Foo()
30069c1e7fSBram Moolenaar  sleep 200ms
31069c1e7fSBram Moolenaar  " do not collect lambda
32069c1e7fSBram Moolenaar  call test_garbagecollect_now()
33069c1e7fSBram Moolenaar  let m = s:n
34069c1e7fSBram Moolenaar  sleep 200ms
35069c1e7fSBram Moolenaar  call timer_stop(s:timer_id)
36069c1e7fSBram Moolenaar  call assert_true(m > 1)
37069c1e7fSBram Moolenaar  call assert_true(s:n > m + 1)
38069c1e7fSBram Moolenaar  call assert_true(s:n < 9)
39069c1e7fSBram Moolenaarendfunction
40069c1e7fSBram Moolenaar
41069c1e7fSBram Moolenaarfunction! Test_lambda_with_partial()
42069c1e7fSBram Moolenaar  let l:Cb = function({... -> ['zero', a:1, a:2, a:3]}, ['one', 'two'])
43069c1e7fSBram Moolenaar  call assert_equal(['zero', 'one', 'two', 'three'], l:Cb('three'))
44069c1e7fSBram Moolenaarendfunction
45069c1e7fSBram Moolenaar
46069c1e7fSBram Moolenaarfunction Test_lambda_fails()
47069c1e7fSBram Moolenaar  call assert_equal(3, {a, b -> a + b}(1, 2))
48069c1e7fSBram Moolenaar  call assert_fails('echo {a, a -> a + a}(1, 2)', 'E15:')
49069c1e7fSBram Moolenaar  call assert_fails('echo {a, b -> a + b)}(1, 2)', 'E15:')
50069c1e7fSBram Moolenaarendfunc
514f0383bcSBram Moolenaar
524f0383bcSBram Moolenaarfunc Test_not_lamda()
534f0383bcSBram Moolenaar  let x = {'>' : 'foo'}
544f0383bcSBram Moolenaar  call assert_equal('foo', x['>'])
554f0383bcSBram Moolenaarendfunc
561e96d9bfSBram Moolenaar
571e96d9bfSBram Moolenaarfunction! Test_lambda_capture_by_reference()
581e96d9bfSBram Moolenaar  let v = 1
591e96d9bfSBram Moolenaar  let l:F = {x -> x + v}
601e96d9bfSBram Moolenaar  let v = 2
611e96d9bfSBram Moolenaar  call assert_equal(12, l:F(10))
621e96d9bfSBram Moolenaarendfunction
631e96d9bfSBram Moolenaar
641e96d9bfSBram Moolenaarfunction! Test_lambda_side_effect()
651e96d9bfSBram Moolenaar  function! s:update_and_return(arr)
661e96d9bfSBram Moolenaar    let a:arr[1] = 5
671e96d9bfSBram Moolenaar    return a:arr
681e96d9bfSBram Moolenaar  endfunction
691e96d9bfSBram Moolenaar
701e96d9bfSBram Moolenaar  function! s:foo(arr)
711e96d9bfSBram Moolenaar    return {-> s:update_and_return(a:arr)}
721e96d9bfSBram Moolenaar  endfunction
731e96d9bfSBram Moolenaar
741e96d9bfSBram Moolenaar  let arr = [3,2,1]
751e96d9bfSBram Moolenaar  call assert_equal([3, 5, 1], s:foo(arr)())
761e96d9bfSBram Moolenaarendfunction
771e96d9bfSBram Moolenaar
781e96d9bfSBram Moolenaarfunction! Test_lambda_refer_local_variable_from_other_scope()
791e96d9bfSBram Moolenaar  function! s:foo(X)
801e96d9bfSBram Moolenaar    return a:X() " refer l:x in s:bar()
811e96d9bfSBram Moolenaar  endfunction
821e96d9bfSBram Moolenaar
831e96d9bfSBram Moolenaar  function! s:bar()
841e96d9bfSBram Moolenaar    let x = 123
851e96d9bfSBram Moolenaar    return s:foo({-> x})
861e96d9bfSBram Moolenaar  endfunction
871e96d9bfSBram Moolenaar
881e96d9bfSBram Moolenaar  call assert_equal(123, s:bar())
891e96d9bfSBram Moolenaarendfunction
901e96d9bfSBram Moolenaar
911e96d9bfSBram Moolenaarfunction! Test_lambda_do_not_share_local_variable()
921e96d9bfSBram Moolenaar  function! s:define_funcs()
931e96d9bfSBram Moolenaar    let l:One = {-> split(execute("let a = 'abc' | echo a"))[0]}
941e96d9bfSBram Moolenaar    let l:Two = {-> exists("a") ? a : "no"}
951e96d9bfSBram Moolenaar    return [l:One, l:Two]
961e96d9bfSBram Moolenaar  endfunction
971e96d9bfSBram Moolenaar
981e96d9bfSBram Moolenaar  let l:F = s:define_funcs()
991e96d9bfSBram Moolenaar
1001e96d9bfSBram Moolenaar  call assert_equal('no', l:F[1]())
1011e96d9bfSBram Moolenaar  call assert_equal('abc', l:F[0]())
1021e96d9bfSBram Moolenaar  call assert_equal('no', l:F[1]())
1031e96d9bfSBram Moolenaarendfunction
1041e96d9bfSBram Moolenaar
105*10ce39a0SBram Moolenaarfunction! Test_lambda_closure_counter()
1061e96d9bfSBram Moolenaar  function! s:foo()
1071e96d9bfSBram Moolenaar    let x = 0
1081e96d9bfSBram Moolenaar    return {-> [execute("let x += 1"), x][-1]}
1091e96d9bfSBram Moolenaar  endfunction
1101e96d9bfSBram Moolenaar
1111e96d9bfSBram Moolenaar  let l:F = s:foo()
1121e96d9bfSBram Moolenaar  call test_garbagecollect_now()
1131e96d9bfSBram Moolenaar  call assert_equal(1, l:F())
1141e96d9bfSBram Moolenaar  call assert_equal(2, l:F())
1151e96d9bfSBram Moolenaar  call assert_equal(3, l:F())
1161e96d9bfSBram Moolenaar  call assert_equal(4, l:F())
1171e96d9bfSBram Moolenaarendfunction
1181e96d9bfSBram Moolenaar
1191e96d9bfSBram Moolenaarfunction! Test_lambda_with_a_var()
1201e96d9bfSBram Moolenaar  function! s:foo()
1211e96d9bfSBram Moolenaar    let x = 2
1221e96d9bfSBram Moolenaar    return {... -> a:000 + [x]}
1231e96d9bfSBram Moolenaar  endfunction
1241e96d9bfSBram Moolenaar  function! s:bar()
1251e96d9bfSBram Moolenaar    return s:foo()(1)
1261e96d9bfSBram Moolenaar  endfunction
1271e96d9bfSBram Moolenaar
1281e96d9bfSBram Moolenaar  call assert_equal([1, 2], s:bar())
1291e96d9bfSBram Moolenaarendfunction
1301e96d9bfSBram Moolenaar
1311e96d9bfSBram Moolenaarfunction! Test_lambda_call_lambda_from_lambda()
1321e96d9bfSBram Moolenaar  function! s:foo(x)
1331e96d9bfSBram Moolenaar    let l:F1 = {-> {-> a:x}}
1341e96d9bfSBram Moolenaar    return {-> l:F1()}
1351e96d9bfSBram Moolenaar  endfunction
1361e96d9bfSBram Moolenaar
1371e96d9bfSBram Moolenaar  let l:F = s:foo(1)
1381e96d9bfSBram Moolenaar  call assert_equal(1, l:F()())
1391e96d9bfSBram Moolenaarendfunction
1401e96d9bfSBram Moolenaar
1411e96d9bfSBram Moolenaarfunction! Test_lambda_delfunc()
1421e96d9bfSBram Moolenaar  function! s:gen()
1431e96d9bfSBram Moolenaar    let pl = l:
1441e96d9bfSBram Moolenaar    let l:Foo = {-> get(pl, "Foo", get(pl, "Bar", {-> 0}))}
1451e96d9bfSBram Moolenaar    let l:Bar = l:Foo
1461e96d9bfSBram Moolenaar    delfunction l:Foo
1471e96d9bfSBram Moolenaar    return l:Bar
1481e96d9bfSBram Moolenaar  endfunction
1491e96d9bfSBram Moolenaar
1501e96d9bfSBram Moolenaar  let l:F = s:gen()
1511e96d9bfSBram Moolenaar  call assert_fails(':call l:F()', 'E117:')
1521e96d9bfSBram Moolenaarendfunction
1531e96d9bfSBram Moolenaar
1541e96d9bfSBram Moolenaarfunction! Test_lambda_scope()
1551e96d9bfSBram Moolenaar  function! s:NewCounter()
1561e96d9bfSBram Moolenaar    let c = 0
1571e96d9bfSBram Moolenaar    return {-> [execute('let c += 1'), c][-1]}
1581e96d9bfSBram Moolenaar  endfunction
1591e96d9bfSBram Moolenaar
1601e96d9bfSBram Moolenaar  function! s:NewCounter2()
1611e96d9bfSBram Moolenaar    return {-> [execute('let c += 100'), c][-1]}
1621e96d9bfSBram Moolenaar  endfunction
1631e96d9bfSBram Moolenaar
1641e96d9bfSBram Moolenaar  let l:C = s:NewCounter()
1651e96d9bfSBram Moolenaar  let l:D = s:NewCounter2()
1661e96d9bfSBram Moolenaar
1671e96d9bfSBram Moolenaar  call assert_equal(1, l:C())
1681e96d9bfSBram Moolenaar  call assert_fails(':call l:D()', 'E15:') " E121: then E15:
1691e96d9bfSBram Moolenaar  call assert_equal(2, l:C())
1701e96d9bfSBram Moolenaarendfunction
1711e96d9bfSBram Moolenaar
1721e96d9bfSBram Moolenaarfunction! Test_lambda_share_scope()
1731e96d9bfSBram Moolenaar  function! s:New()
1741e96d9bfSBram Moolenaar    let c = 0
1751e96d9bfSBram Moolenaar    let l:Inc0 = {-> [execute('let c += 1'), c][-1]}
1761e96d9bfSBram Moolenaar    let l:Dec0 = {-> [execute('let c -= 1'), c][-1]}
1771e96d9bfSBram Moolenaar    return [l:Inc0, l:Dec0]
1781e96d9bfSBram Moolenaar  endfunction
1791e96d9bfSBram Moolenaar
1801e96d9bfSBram Moolenaar  let [l:Inc, l:Dec] = s:New()
1811e96d9bfSBram Moolenaar
1821e96d9bfSBram Moolenaar  call assert_equal(1, l:Inc())
1831e96d9bfSBram Moolenaar  call assert_equal(2, l:Inc())
1841e96d9bfSBram Moolenaar  call assert_equal(1, l:Dec())
1851e96d9bfSBram Moolenaarendfunction
1861e96d9bfSBram Moolenaar
1871e96d9bfSBram Moolenaarfunction! Test_lambda_circular_reference()
1881e96d9bfSBram Moolenaar  function! s:Foo()
1891e96d9bfSBram Moolenaar    let d = {}
1901e96d9bfSBram Moolenaar    let d.f = {-> d}
1911e96d9bfSBram Moolenaar    return d.f
1921e96d9bfSBram Moolenaar  endfunction
1931e96d9bfSBram Moolenaar
1941e96d9bfSBram Moolenaar  call s:Foo()
1951e96d9bfSBram Moolenaar  call test_garbagecollect_now()
1961e96d9bfSBram Moolenaar  let i = 0 | while i < 10000 | call s:Foo() | let i+= 1 | endwhile
1971e96d9bfSBram Moolenaar  call test_garbagecollect_now()
1981e96d9bfSBram Moolenaarendfunction
1991e96d9bfSBram Moolenaar
2001e96d9bfSBram Moolenaarfunction! Test_lambda_combination()
2011e96d9bfSBram Moolenaar  call assert_equal(2, {x -> {x -> x}}(1)(2))
2021e96d9bfSBram Moolenaar  call assert_equal(10, {y -> {x -> x(y)(10)}({y -> y})}({z -> z}))
2031e96d9bfSBram Moolenaar  call assert_equal(5.0, {x -> {y -> x / y}}(10)(2.0))
2041e96d9bfSBram Moolenaar  call assert_equal(6, {x -> {y -> {z -> x + y + z}}}(1)(2)(3))
2051e96d9bfSBram Moolenaar
2061e96d9bfSBram Moolenaar  call assert_equal(6, {x -> {f -> f(x)}}(3)({x -> x * 2}))
2071e96d9bfSBram Moolenaar  call assert_equal(6, {f -> {x -> f(x)}}({x -> x * 2})(3))
2081e96d9bfSBram Moolenaar
2091e96d9bfSBram Moolenaar  " Z combinator
2101e96d9bfSBram Moolenaar  let Z = {f -> {x -> f({y -> x(x)(y)})}({x -> f({y -> x(x)(y)})})}
2111e96d9bfSBram Moolenaar  let Fact = {f -> {x -> x == 0 ? 1 : x * f(x - 1)}}
2121e96d9bfSBram Moolenaar  call assert_equal(120, Z(Fact)(5))
2131e96d9bfSBram Moolenaarendfunction
214*10ce39a0SBram Moolenaar
215*10ce39a0SBram Moolenaarfunction! Test_closure_counter()
216*10ce39a0SBram Moolenaar  function! s:foo()
217*10ce39a0SBram Moolenaar    let x = 0
218*10ce39a0SBram Moolenaar    function! s:bar() closure
219*10ce39a0SBram Moolenaar      let x += 1
220*10ce39a0SBram Moolenaar      return x
221*10ce39a0SBram Moolenaar    endfunction
222*10ce39a0SBram Moolenaar    return function('s:bar')
223*10ce39a0SBram Moolenaar  endfunction
224*10ce39a0SBram Moolenaar
225*10ce39a0SBram Moolenaar  let l:F = s:foo()
226*10ce39a0SBram Moolenaar  call test_garbagecollect_now()
227*10ce39a0SBram Moolenaar  call assert_equal(1, l:F())
228*10ce39a0SBram Moolenaar  call assert_equal(2, l:F())
229*10ce39a0SBram Moolenaar  call assert_equal(3, l:F())
230*10ce39a0SBram Moolenaar  call assert_equal(4, l:F())
231*10ce39a0SBram Moolenaarendfunction
232*10ce39a0SBram Moolenaar
233*10ce39a0SBram Moolenaarfunction! Test_closure_unlet()
234*10ce39a0SBram Moolenaar  function! s:foo()
235*10ce39a0SBram Moolenaar    let x = 1
236*10ce39a0SBram Moolenaar    function! s:bar() closure
237*10ce39a0SBram Moolenaar      unlet x
238*10ce39a0SBram Moolenaar    endfunction
239*10ce39a0SBram Moolenaar    call s:bar()
240*10ce39a0SBram Moolenaar    return l:
241*10ce39a0SBram Moolenaar  endfunction
242*10ce39a0SBram Moolenaar
243*10ce39a0SBram Moolenaar  call assert_false(has_key(s:foo(), 'x'))
244*10ce39a0SBram Moolenaar  call test_garbagecollect_now()
245*10ce39a0SBram Moolenaarendfunction
246