closure.lua 5.7 KB

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