xref: /vim-8.2.3635/src/testdir/test_lambda.vim (revision 437bafe4)
110ce39a0SBram Moolenaar" Test for lambda and closure
210ce39a0SBram Moolenaar
39532fe7fSBram Moolenaarfunction! Test_lambda_feature()
49532fe7fSBram Moolenaar  call assert_equal(1, has('lambda'))
59532fe7fSBram Moolenaarendfunction
69532fe7fSBram Moolenaar
7069c1e7fSBram Moolenaarfunction! 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}))
10069c1e7fSBram Moolenaarendfunction
11069c1e7fSBram Moolenaar
12069c1e7fSBram Moolenaarfunction! 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}))
15069c1e7fSBram Moolenaarendfunction
16069c1e7fSBram Moolenaar
17069c1e7fSBram Moolenaarfunction! Test_lambda_with_sort()
18069c1e7fSBram Moolenaar  call assert_equal([1, 2, 3, 4, 7], sort([3,7,2,1,4], {a, b -> a - b}))
19069c1e7fSBram Moolenaarendfunction
20069c1e7fSBram Moolenaar
21069c1e7fSBram Moolenaarfunction! 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
28069c1e7fSBram Moolenaar  function! 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})
31069c1e7fSBram Moolenaar  endfunction
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)
43069c1e7fSBram Moolenaarendfunction
44069c1e7fSBram Moolenaar
45069c1e7fSBram Moolenaarfunction! 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'))
48069c1e7fSBram Moolenaarendfunction
49069c1e7fSBram Moolenaar
50069c1e7fSBram Moolenaarfunction Test_lambda_fails()
51069c1e7fSBram Moolenaar  call assert_equal(3, {a, b -> a + b}(1, 2))
52069c1e7fSBram Moolenaar  call assert_fails('echo {a, a -> a + a}(1, 2)', 'E15:')
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
611e96d9bfSBram Moolenaarfunction! 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))
661e96d9bfSBram Moolenaarendfunction
671e96d9bfSBram Moolenaar
681e96d9bfSBram Moolenaarfunction! Test_lambda_side_effect()
691e96d9bfSBram Moolenaar  function! s:update_and_return(arr)
701e96d9bfSBram Moolenaar    let a:arr[1] = 5
711e96d9bfSBram Moolenaar    return a:arr
721e96d9bfSBram Moolenaar  endfunction
731e96d9bfSBram Moolenaar
741e96d9bfSBram Moolenaar  function! s:foo(arr)
751e96d9bfSBram Moolenaar    return {-> s:update_and_return(a:arr)}
761e96d9bfSBram Moolenaar  endfunction
771e96d9bfSBram Moolenaar
781e96d9bfSBram Moolenaar  let arr = [3,2,1]
791e96d9bfSBram Moolenaar  call assert_equal([3, 5, 1], s:foo(arr)())
801e96d9bfSBram Moolenaarendfunction
811e96d9bfSBram Moolenaar
821e96d9bfSBram Moolenaarfunction! Test_lambda_refer_local_variable_from_other_scope()
831e96d9bfSBram Moolenaar  function! s:foo(X)
841e96d9bfSBram Moolenaar    return a:X() " refer l:x in s:bar()
851e96d9bfSBram Moolenaar  endfunction
861e96d9bfSBram Moolenaar
871e96d9bfSBram Moolenaar  function! s:bar()
881e96d9bfSBram Moolenaar    let x = 123
891e96d9bfSBram Moolenaar    return s:foo({-> x})
901e96d9bfSBram Moolenaar  endfunction
911e96d9bfSBram Moolenaar
921e96d9bfSBram Moolenaar  call assert_equal(123, s:bar())
931e96d9bfSBram Moolenaarendfunction
941e96d9bfSBram Moolenaar
951e96d9bfSBram Moolenaarfunction! Test_lambda_do_not_share_local_variable()
961e96d9bfSBram Moolenaar  function! 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]
1001e96d9bfSBram Moolenaar  endfunction
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]())
1071e96d9bfSBram Moolenaarendfunction
1081e96d9bfSBram Moolenaar
10910ce39a0SBram Moolenaarfunction! Test_lambda_closure_counter()
1101e96d9bfSBram Moolenaar  function! s:foo()
1111e96d9bfSBram Moolenaar    let x = 0
1121e96d9bfSBram Moolenaar    return {-> [execute("let x += 1"), x][-1]}
1131e96d9bfSBram Moolenaar  endfunction
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())
1211e96d9bfSBram Moolenaarendfunction
1221e96d9bfSBram Moolenaar
1231e96d9bfSBram Moolenaarfunction! Test_lambda_with_a_var()
1241e96d9bfSBram Moolenaar  function! s:foo()
1251e96d9bfSBram Moolenaar    let x = 2
1261e96d9bfSBram Moolenaar    return {... -> a:000 + [x]}
1271e96d9bfSBram Moolenaar  endfunction
1281e96d9bfSBram Moolenaar  function! s:bar()
1291e96d9bfSBram Moolenaar    return s:foo()(1)
1301e96d9bfSBram Moolenaar  endfunction
1311e96d9bfSBram Moolenaar
1321e96d9bfSBram Moolenaar  call assert_equal([1, 2], s:bar())
1331e96d9bfSBram Moolenaarendfunction
1341e96d9bfSBram Moolenaar
1351e96d9bfSBram Moolenaarfunction! Test_lambda_call_lambda_from_lambda()
1361e96d9bfSBram Moolenaar  function! s:foo(x)
1371e96d9bfSBram Moolenaar    let l:F1 = {-> {-> a:x}}
1381e96d9bfSBram Moolenaar    return {-> l:F1()}
1391e96d9bfSBram Moolenaar  endfunction
1401e96d9bfSBram Moolenaar
1411e96d9bfSBram Moolenaar  let l:F = s:foo(1)
1421e96d9bfSBram Moolenaar  call assert_equal(1, l:F()())
1431e96d9bfSBram Moolenaarendfunction
1441e96d9bfSBram Moolenaar
1451e96d9bfSBram Moolenaarfunction! Test_lambda_delfunc()
1461e96d9bfSBram Moolenaar  function! 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
1521e96d9bfSBram Moolenaar  endfunction
1531e96d9bfSBram Moolenaar
1541e96d9bfSBram Moolenaar  let l:F = s:gen()
155*437bafe4SBram Moolenaar  call assert_fails(':call l:F()', 'E933:')
1561e96d9bfSBram Moolenaarendfunction
1571e96d9bfSBram Moolenaar
1581e96d9bfSBram Moolenaarfunction! Test_lambda_scope()
1591e96d9bfSBram Moolenaar  function! s:NewCounter()
1601e96d9bfSBram Moolenaar    let c = 0
1611e96d9bfSBram Moolenaar    return {-> [execute('let c += 1'), c][-1]}
1621e96d9bfSBram Moolenaar  endfunction
1631e96d9bfSBram Moolenaar
1641e96d9bfSBram Moolenaar  function! s:NewCounter2()
1651e96d9bfSBram Moolenaar    return {-> [execute('let c += 100'), c][-1]}
1661e96d9bfSBram Moolenaar  endfunction
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())
1721e96d9bfSBram Moolenaar  call assert_fails(':call l:D()', 'E15:') " E121: then E15:
1731e96d9bfSBram Moolenaar  call assert_equal(2, l:C())
1741e96d9bfSBram Moolenaarendfunction
1751e96d9bfSBram Moolenaar
1761e96d9bfSBram Moolenaarfunction! Test_lambda_share_scope()
1771e96d9bfSBram Moolenaar  function! 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]
1821e96d9bfSBram Moolenaar  endfunction
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())
1891e96d9bfSBram Moolenaarendfunction
1901e96d9bfSBram Moolenaar
1911e96d9bfSBram Moolenaarfunction! Test_lambda_circular_reference()
1921e96d9bfSBram Moolenaar  function! s:Foo()
1931e96d9bfSBram Moolenaar    let d = {}
1941e96d9bfSBram Moolenaar    let d.f = {-> d}
1951e96d9bfSBram Moolenaar    return d.f
1961e96d9bfSBram Moolenaar  endfunction
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()
2021e96d9bfSBram Moolenaarendfunction
2031e96d9bfSBram Moolenaar
2041e96d9bfSBram Moolenaarfunction! 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))
2171e96d9bfSBram Moolenaarendfunction
21810ce39a0SBram Moolenaar
21910ce39a0SBram Moolenaarfunction! Test_closure_counter()
22010ce39a0SBram Moolenaar  function! s:foo()
22110ce39a0SBram Moolenaar    let x = 0
22210ce39a0SBram Moolenaar    function! s:bar() closure
22310ce39a0SBram Moolenaar      let x += 1
22410ce39a0SBram Moolenaar      return x
22510ce39a0SBram Moolenaar    endfunction
22610ce39a0SBram Moolenaar    return function('s:bar')
22710ce39a0SBram Moolenaar  endfunction
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())
23510ce39a0SBram Moolenaarendfunction
23610ce39a0SBram Moolenaar
23710ce39a0SBram Moolenaarfunction! Test_closure_unlet()
23810ce39a0SBram Moolenaar  function! s:foo()
23910ce39a0SBram Moolenaar    let x = 1
24010ce39a0SBram Moolenaar    function! s:bar() closure
24110ce39a0SBram Moolenaar      unlet x
24210ce39a0SBram Moolenaar    endfunction
24310ce39a0SBram Moolenaar    call s:bar()
24410ce39a0SBram Moolenaar    return l:
24510ce39a0SBram Moolenaar  endfunction
24610ce39a0SBram Moolenaar
24710ce39a0SBram Moolenaar  call assert_false(has_key(s:foo(), 'x'))
24810ce39a0SBram Moolenaar  call test_garbagecollect_now()
24910ce39a0SBram Moolenaarendfunction
25058016448SBram Moolenaar
25158016448SBram Moolenaarfunction! LambdaFoo()
25258016448SBram Moolenaar  let x = 0
25358016448SBram Moolenaar  function! LambdaBar() closure
25458016448SBram Moolenaar    let x += 1
25558016448SBram Moolenaar    return x
25658016448SBram Moolenaar  endfunction
25758016448SBram Moolenaar  return function('LambdaBar')
25858016448SBram Moolenaarendfunction
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
27058016448SBram Moolenaar  " This causes memory access errors.
27158016448SBram Moolenaar  " delfunc LambdaFoo
27258016448SBram Moolenaar  " delfunc LambdaBar
27358016448SBram Moolenaarendfunc
274