lua

A copy of the Lua development repository
Log | Files | Refs | README

closure.lua (5768B)


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