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'