github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/testdata/lua-5.3.3-tests/closure.lua (about)

     1  -- $Id: closure.lua,v 1.58 2014/12/26 17:20:53 roberto Exp $
     2  
     3  print "testing closures"
     4  
     5  local A,B = 0,{g=10}
     6  function f(x)
     7    local a = {}
     8    for i=1,1000 do
     9      local y = 0
    10      do
    11        a[i] = function () B.g = B.g+1; y = y+x; return y+A end
    12      end
    13    end
    14    local dummy = function () return a[A] end
    15    collectgarbage()
    16    A = 1; assert(dummy() == a[1]); A = 0;
    17    assert(a[1]() == x)
    18    assert(a[3]() == x)
    19    collectgarbage()
    20    assert(B.g == 12)
    21    return a
    22  end
    23  
    24  local a = f(10)
    25  -- TODO or spec: weak tables are not supported
    26  -- force a GC in this level
    27  -- local x = {[1] = {}}   -- to detect a GC
    28  -- setmetatable(x, {__mode = 'kv'})
    29  -- while x[1] do   -- repeat until GC
    30    -- local a = A..A..A..A  -- create garbage
    31    -- A = A+1
    32  -- end
    33  -- assert(a[1]() == 20+A)
    34  -- assert(a[1]() == 30+A)
    35  -- assert(a[2]() == 10+A)
    36  -- collectgarbage()
    37  -- assert(a[2]() == 20+A)
    38  -- assert(a[2]() == 30+A)
    39  -- assert(a[3]() == 20+A)
    40  -- assert(a[8]() == 10+A)
    41  -- assert(getmetatable(x).__mode == 'kv')
    42  -- assert(B.g == 19)
    43  
    44  
    45  -- testing equality
    46  a = {}
    47  for i = 1, 5 do  a[i] = function (x) return x + a + _ENV end  end
    48  assert(a[3] == a[4] and a[4] == a[5])
    49  
    50  for i = 1, 5 do  a[i] = function (x) return i + a + _ENV end  end
    51  assert(a[3] ~= a[4] and a[4] ~= a[5])
    52  
    53  local function f()
    54    return function (x)  return math.sin(_ENV[x])  end
    55  end
    56  assert(f() == f())
    57  
    58  
    59  -- testing closures with 'for' control variable
    60  a = {}
    61  for i=1,10 do
    62    a[i] = {set = function(x) i=x end, get = function () return i end}
    63    if i == 3 then break end
    64  end
    65  assert(a[4] == nil)
    66  a[1].set(10)
    67  assert(a[2].get() == 2)
    68  a[2].set('a')
    69  assert(a[3].get() == 3)
    70  assert(a[2].get() == 'a')
    71  
    72  a = {}
    73  local t = {"a", "b"}
    74  for i = 1, #t do
    75    local k = t[i]
    76    a[i] = {set = function(x, y) i=x; k=y end,
    77            get = function () return i, k end}
    78    if i == 2 then break end
    79  end
    80  a[1].set(10, 20)
    81  local r,s = a[2].get()
    82  assert(r == 2 and s == 'b')
    83  r,s = a[1].get()
    84  assert(r == 10 and s == 20)
    85  a[2].set('a', 'b')
    86  r,s = a[2].get()
    87  assert(r == "a" and s == "b")
    88  
    89  
    90  -- testing closures with 'for' control variable x break
    91  for i=1,3 do
    92    f = function () return i end
    93    break
    94  end
    95  assert(f() == 1)
    96  
    97  for k = 1, #t do
    98    local v = t[k]
    99    f = function () return k, v end
   100    break
   101  end
   102  assert(({f()})[1] == 1)
   103  assert(({f()})[2] == "a")
   104  
   105  
   106  -- testing closure x break x return x errors
   107  
   108  local b
   109  function f(x)
   110    local first = 1
   111    while 1 do
   112      if x == 3 and not first then return end
   113      local a = 'xuxu'
   114      b = function (op, y)
   115            if op == 'set' then
   116              a = x+y
   117            else
   118              return a
   119            end
   120          end
   121      if x == 1 then do break end
   122      elseif x == 2 then return
   123      else if x ~= 3 then error() end
   124      end
   125      first = nil
   126    end
   127  end
   128  
   129  for i=1,3 do
   130    f(i)
   131    assert(b('get') == 'xuxu')
   132    b('set', 10); assert(b('get') == 10+i)
   133    b = nil
   134  end
   135  
   136  pcall(f, 4);
   137  assert(b('get') == 'xuxu')
   138  b('set', 10); assert(b('get') == 14)
   139  
   140  
   141  local w
   142  -- testing multi-level closure
   143  function f(x)
   144    return function (y)
   145      return function (z) return w+x+y+z end
   146    end
   147  end
   148  
   149  y = f(10)
   150  w = 1.345
   151  assert(y(20)(30) == 60+w)
   152  
   153  -- testing closures x repeat-until
   154  
   155  local a = {}
   156  local i = 1
   157  repeat
   158    local x = i
   159    a[i] = function () i = x+1; return x end
   160  until i > 10 or a[i]() ~= x
   161  assert(i == 11 and a[1]() == 1 and a[3]() == 3 and i == 4)
   162  
   163  
   164  -- testing closures created in 'then' and 'else' parts of 'if's
   165  a = {}
   166  for i = 1, 10 do
   167    if i % 3 == 0 then
   168  	local y = 0
   169  	a[i] = function (x) local t = y; y = x; return t end
   170    elseif i % 3 == 1 then
   171  	goto L1
   172  	error'not here'
   173    ::L1::
   174  	local y = 1
   175  	a[i] = function (x) local t = y; y = x; return t end
   176    elseif i % 3 == 2 then
   177  	local t
   178  	goto l4
   179  	::l4a:: a[i] = t; goto l4b
   180  	error("should never be here!")
   181  	::l4::
   182  	local y = 2
   183  	t = function (x) local t = y; y = x; return t end
   184  	goto l4a
   185  	error("should never be here!")
   186  	::l4b::
   187    end
   188  end
   189  
   190  for i = 1, 10 do
   191    assert(a[i](i * 10) == i % 3 and a[i]() == i * 10)
   192  end
   193  
   194  print'+'
   195  
   196  
   197  -- test for correctly closing upvalues in tail calls of vararg functions
   198  local function t ()
   199    local function c(a,b) assert(a=="test" and b=="OK") end
   200    local function v(f, ...) c("test", f() ~= 1 and "FAILED" or "OK") end
   201    local x = 1
   202    return v(function() return x end)
   203  end
   204  t()
   205  
   206  
   207  -- test for debug manipulation of upvalues
   208  local debug = require'debug'
   209  
   210  do
   211    local a , b, c = 3, 5, 7
   212    foo1 = function () return a+b end;
   213    foo2 = function () return b+a end;
   214    do
   215      local a = 10
   216      foo3 = function () return a+b end;
   217    end
   218  end
   219  
   220  assert(debug.upvalueid(foo1, 1))
   221  assert(debug.upvalueid(foo1, 2))
   222  assert(not pcall(debug.upvalueid, foo1, 3))
   223  assert(debug.upvalueid(foo1, 1) == debug.upvalueid(foo2, 2))
   224  assert(debug.upvalueid(foo1, 2) == debug.upvalueid(foo2, 1))
   225  assert(debug.upvalueid(foo3, 1))
   226  assert(debug.upvalueid(foo1, 1) ~= debug.upvalueid(foo3, 1))
   227  assert(debug.upvalueid(foo1, 2) == debug.upvalueid(foo3, 2))
   228  
   229  -- TODO or spec: no plan to support upvalues for GoFunction
   230  -- assert(debug.upvalueid(string.gmatch("x", "x"), 1) ~= nil)
   231  
   232  assert(foo1() == 3 + 5 and foo2() == 5 + 3)
   233  debug.upvaluejoin(foo1, 2, foo2, 2)
   234  assert(foo1() == 3 + 3 and foo2() == 5 + 3)
   235  assert(foo3() == 10 + 5)
   236  debug.upvaluejoin(foo3, 2, foo2, 1)
   237  assert(foo3() == 10 + 5)
   238  debug.upvaluejoin(foo3, 2, foo2, 2)
   239  assert(foo3() == 10 + 3)
   240  
   241  assert(not pcall(debug.upvaluejoin, foo1, 3, foo2, 1))
   242  assert(not pcall(debug.upvaluejoin, foo1, 1, foo2, 3))
   243  assert(not pcall(debug.upvaluejoin, foo1, 0, foo2, 1))
   244  assert(not pcall(debug.upvaluejoin, print, 1, foo2, 1))
   245  assert(not pcall(debug.upvaluejoin, {}, 1, foo2, 1))
   246  assert(not pcall(debug.upvaluejoin, foo1, 1, print, 1))
   247  
   248  print'OK'