locals.lua 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. -- $Id: testes/locals.lua $
  2. -- See Copyright Notice in file all.lua
  3. print('testing local variables and environments')
  4. local debug = require"debug"
  5. -- bug in 5.1:
  6. local function f(x) x = nil; return x end
  7. assert(f(10) == nil)
  8. local function f() local x; return x end
  9. assert(f(10) == nil)
  10. local function f(x) x = nil; local y; return x, y end
  11. assert(f(10) == nil and select(2, f(20)) == nil)
  12. do
  13. local i = 10
  14. do local i = 100; assert(i==100) end
  15. do local i = 1000; assert(i==1000) end
  16. assert(i == 10)
  17. if i ~= 10 then
  18. local i = 20
  19. else
  20. local i = 30
  21. assert(i == 30)
  22. end
  23. end
  24. f = nil
  25. local f
  26. x = 1
  27. a = nil
  28. load('local a = {}')()
  29. assert(a == nil)
  30. function f (a)
  31. local _1, _2, _3, _4, _5
  32. local _6, _7, _8, _9, _10
  33. local x = 3
  34. local b = a
  35. local c,d = a,b
  36. if (d == b) then
  37. local x = 'q'
  38. x = b
  39. assert(x == 2)
  40. else
  41. assert(nil)
  42. end
  43. assert(x == 3)
  44. local f = 10
  45. end
  46. local b=10
  47. local a; repeat local b; a,b=1,2; assert(a+1==b); until a+b==3
  48. assert(x == 1)
  49. f(2)
  50. assert(type(f) == 'function')
  51. local function getenv (f)
  52. local a,b = debug.getupvalue(f, 1)
  53. assert(a == '_ENV')
  54. return b
  55. end
  56. -- test for global table of loaded chunks
  57. assert(getenv(load"a=3") == _G)
  58. local c = {}; local f = load("a = 3", nil, nil, c)
  59. assert(getenv(f) == c)
  60. assert(c.a == nil)
  61. f()
  62. assert(c.a == 3)
  63. -- old test for limits for special instructions (now just a generic test)
  64. do
  65. local i = 2
  66. local p = 4 -- p == 2^i
  67. repeat
  68. for j=-3,3 do
  69. assert(load(string.format([[local a=%s;
  70. a=a+%s;
  71. assert(a ==2^%s)]], j, p-j, i), '')) ()
  72. assert(load(string.format([[local a=%s;
  73. a=a-%s;
  74. assert(a==-2^%s)]], -j, p-j, i), '')) ()
  75. assert(load(string.format([[local a,b=0,%s;
  76. a=b-%s;
  77. assert(a==-2^%s)]], -j, p-j, i), '')) ()
  78. end
  79. p = 2 * p; i = i + 1
  80. until p <= 0
  81. end
  82. print'+'
  83. if rawget(_G, "T") then
  84. -- testing clearing of dead elements from tables
  85. collectgarbage("stop") -- stop GC
  86. local a = {[{}] = 4, [3] = 0, alo = 1,
  87. a1234567890123456789012345678901234567890 = 10}
  88. local t = T.querytab(a)
  89. for k,_ in pairs(a) do a[k] = undef end
  90. collectgarbage() -- restore GC and collect dead fiels in `a'
  91. for i=0,t-1 do
  92. local k = querytab(a, i)
  93. assert(k == nil or type(k) == 'number' or k == 'alo')
  94. end
  95. -- testing allocation errors during table insertions
  96. local a = {}
  97. local function additems ()
  98. a.x = true; a.y = true; a.z = true
  99. a[1] = true
  100. a[2] = true
  101. end
  102. for i = 1, math.huge do
  103. T.alloccount(i)
  104. local st, msg = pcall(additems)
  105. T.alloccount()
  106. local count = 0
  107. for k, v in pairs(a) do
  108. assert(a[k] == v)
  109. count = count + 1
  110. end
  111. if st then assert(count == 5); break end
  112. end
  113. end
  114. -- testing lexical environments
  115. assert(_ENV == _G)
  116. do
  117. local dummy
  118. local _ENV = (function (...) return ... end)(_G, dummy) -- {
  119. do local _ENV = {assert=assert}; assert(true) end
  120. mt = {_G = _G}
  121. local foo,x
  122. A = false -- "declare" A
  123. do local _ENV = mt
  124. function foo (x)
  125. A = x
  126. do local _ENV = _G; A = 1000 end
  127. return function (x) return A .. x end
  128. end
  129. end
  130. assert(getenv(foo) == mt)
  131. x = foo('hi'); assert(mt.A == 'hi' and A == 1000)
  132. assert(x('*') == mt.A .. '*')
  133. do local _ENV = {assert=assert, A=10};
  134. do local _ENV = {assert=assert, A=20};
  135. assert(A==20);x=A
  136. end
  137. assert(A==10 and x==20)
  138. end
  139. assert(x==20)
  140. print"testing to-be-closed variables"
  141. local function stack(n) n = ((n == 0) or stack(n - 1)) end
  142. local function func2close (f)
  143. return setmetatable({}, {__close = f})
  144. end
  145. do
  146. local a = {}
  147. do
  148. local <toclose> x = setmetatable({"x"}, {__close = function (self)
  149. a[#a + 1] = self[1] end})
  150. local <toclose> y = func2close(function (self, err)
  151. assert(err == nil); a[#a + 1] = "y"
  152. end)
  153. a[#a + 1] = "in"
  154. end
  155. a[#a + 1] = "out"
  156. assert(a[1] == "in" and a[2] == "y" and a[3] == "x" and a[4] == "out")
  157. end
  158. do
  159. local X = false
  160. local closescope = func2close(function () stack(10); X = true end)
  161. -- closing functions do not corrupt returning values
  162. local function foo (x)
  163. local <toclose> _ = closescope
  164. return x, X, 23
  165. end
  166. local a, b, c = foo(1.5)
  167. assert(a == 1.5 and b == false and c == 23 and X == true)
  168. X = false
  169. foo = function (x)
  170. local <toclose> _ = closescope
  171. local y = 15
  172. return y
  173. end
  174. assert(foo() == 15 and X == true)
  175. X = false
  176. foo = function ()
  177. local <toclose> x = closescope
  178. return x
  179. end
  180. assert(foo() == closescope and X == true)
  181. end
  182. do
  183. -- calls cannot be tail in the scope of to-be-closed variables
  184. local X, Y
  185. local function foo ()
  186. local <toclose> _ = func2close(function () Y = 10 end)
  187. assert(X == true and Y == nil) -- 'X' not closed yet
  188. return 1,2,3
  189. end
  190. local function bar ()
  191. local <toclose> _ = func2close(function () X = false end)
  192. X = true
  193. do
  194. return foo() -- not a tail call!
  195. end
  196. end
  197. local a, b, c, d = bar()
  198. assert(a == 1 and b == 2 and c == 3 and X == false and Y == 10 and d == nil)
  199. end
  200. do -- errors in __close
  201. local log = {}
  202. local function foo (err)
  203. local <toclose> x =
  204. func2close(function (self, msg) log[#log + 1] = msg; error(1) end)
  205. local <toclose> x1 =
  206. func2close(function (self, msg) log[#log + 1] = msg; end)
  207. local <toclose> gc = func2close(function () collectgarbage() end)
  208. local <toclose> y =
  209. func2close(function (self, msg) log[#log + 1] = msg; error(2) end)
  210. local <toclose> z =
  211. func2close(function (self, msg) log[#log + 1] = msg or 10; error(3) end)
  212. if err then error(4) end
  213. end
  214. local stat, msg = pcall(foo, false)
  215. assert(msg == 3)
  216. assert(log[1] == 10 and log[2] == 3 and log[3] == 3 and log[4] == 3
  217. and #log == 4)
  218. log = {}
  219. local stat, msg = pcall(foo, true)
  220. assert(msg == 4)
  221. assert(log[1] == 4 and log[2] == 4 and log[3] == 4 and log[4] == 4
  222. and #log == 4)
  223. -- error in toclose in vararg function
  224. function foo (...)
  225. local <toclose> x123 = 10
  226. end
  227. local st, msg = pcall(foo)
  228. assert(string.find(msg, "'x123'"))
  229. end
  230. do
  231. -- errors due to non-closable values
  232. local function foo ()
  233. local <toclose> x = 34
  234. end
  235. local stat, msg = pcall(foo)
  236. assert(not stat and string.find(msg, "variable 'x'"))
  237. -- with other errors, non-closable values are ignored
  238. local function foo ()
  239. local <toclose> x = 34
  240. local <toclose> y = func2close(function () error(32) end)
  241. end
  242. local stat, msg = pcall(foo)
  243. assert(not stat and msg == 32)
  244. end
  245. if rawget(_G, "T") then
  246. -- memory error inside closing function
  247. local function foo ()
  248. local <toclose> y = func2close(function () T.alloccount() end)
  249. local <toclose> x = setmetatable({}, {__close = function ()
  250. T.alloccount(0); local x = {} -- force a memory error
  251. end})
  252. error(1000) -- common error inside the function's body
  253. end
  254. stack(5) -- ensure a minimal number of CI structures
  255. -- despite memory error, 'y' will be executed and
  256. -- memory limit will be lifted
  257. local _, msg = pcall(foo)
  258. assert(msg == 1000)
  259. local close = func2close(function (self, msg)
  260. T.alloccount()
  261. assert(msg == "not enough memory")
  262. end)
  263. -- set a memory limit and return a closing object to remove the limit
  264. local function enter (count)
  265. stack(10) -- reserve some stack space
  266. T.alloccount(count)
  267. return close
  268. end
  269. local function test ()
  270. local <toclose> x = enter(0) -- set a memory limit
  271. -- creation of previous upvalue will raise a memory error
  272. assert(false) -- should not run
  273. end
  274. local _, msg = pcall(test)
  275. assert(msg == "not enough memory")
  276. -- now use metamethod for closing
  277. close = setmetatable({}, {__close = function ()
  278. T.alloccount()
  279. end})
  280. -- repeat test with extra closing upvalues
  281. local function test ()
  282. local <toclose> xxx = func2close(function (self, msg)
  283. assert(msg == "not enough memory");
  284. error(1000) -- raise another error
  285. end)
  286. local <toclose> xx = func2close(function (self, msg)
  287. assert(msg == "not enough memory");
  288. end)
  289. local <toclose> x = enter(0) -- set a memory limit
  290. -- creation of previous upvalue will raise a memory error
  291. os.exit(false) -- should not run
  292. end
  293. local _, msg = pcall(test)
  294. assert(msg == "not enough memory") -- reported error is the first one
  295. do -- testing 'toclose' in C string buffer
  296. collectgarbage()
  297. local s = string.rep('a', 10000) -- large string
  298. local m = T.totalmem()
  299. collectgarbage("stop")
  300. s = string.upper(s) -- allocate buffer + new string (10K each)
  301. -- ensure buffer was deallocated
  302. assert(T.totalmem() - m <= 11000)
  303. collectgarbage("restart")
  304. end
  305. do -- now some tests for freeing buffer in case of errors
  306. local lim = 10000 -- some size larger than the static buffer
  307. local extra = 2000 -- some extra memory (for callinfo, etc.)
  308. local s = string.rep("a", lim)
  309. -- concat this table needs two buffer resizes (one for each 's')
  310. local a = {s, s}
  311. collectgarbage()
  312. m = T.totalmem()
  313. collectgarbage("stop")
  314. -- error in the first buffer allocation
  315. T. totalmem(m + extra)
  316. assert(not pcall(table.concat, a))
  317. -- first buffer was not even allocated
  318. assert(T.totalmem() - m <= extra)
  319. -- error in the second buffer allocation
  320. T. totalmem(m + lim + extra)
  321. assert(not pcall(table.concat, a))
  322. -- first buffer was released by 'toclose'
  323. assert(T.totalmem() - m <= extra)
  324. -- error in creation of final string
  325. T.totalmem(m + 2 * lim + extra)
  326. assert(not pcall(table.concat, a))
  327. -- second buffer was released by 'toclose'
  328. assert(T.totalmem() - m <= extra)
  329. -- userdata, upvalue, buffer, buffer, final string
  330. T.totalmem(m + 4*lim + extra)
  331. assert(#table.concat(a) == 2*lim)
  332. T.totalmem(0) -- remove memory limit
  333. collectgarbage("restart")
  334. print'+'
  335. end
  336. end
  337. print "to-be-closed variables in coroutines"
  338. do
  339. -- an error in a wrapped coroutine closes variables
  340. local x = false
  341. local y = false
  342. local co = coroutine.wrap(function ()
  343. local <toclose> xv = func2close(function () x = true end)
  344. do
  345. local <toclose> yv = func2close(function () y = true end)
  346. coroutine.yield(100) -- yield doesn't close variable
  347. end
  348. coroutine.yield(200) -- yield doesn't close variable
  349. error(23) -- error does
  350. end)
  351. local b = co()
  352. assert(b == 100 and not x and not y)
  353. b = co()
  354. assert(b == 200 and not x and y)
  355. local a, b = pcall(co)
  356. assert(not a and b == 23 and x and y)
  357. end
  358. do
  359. -- error in a wrapped coroutine raising errors when closing a variable
  360. local x = 0
  361. local co = coroutine.wrap(function ()
  362. local <toclose> xx = func2close(function () x = x + 1; error("YYY") end)
  363. local <toclose> xv = func2close(function () x = x + 1; error("XXX") end)
  364. coroutine.yield(100)
  365. error(200)
  366. end)
  367. assert(co() == 100); assert(x == 0)
  368. local st, msg = pcall(co); assert(x == 2)
  369. assert(not st and msg == 200) -- should get first error raised
  370. x = 0
  371. co = coroutine.wrap(function ()
  372. local <toclose> xx = func2close(function () x = x + 1; error("YYY") end)
  373. local <toclose> xv = func2close(function () x = x + 1; error("XXX") end)
  374. coroutine.yield(100)
  375. return 200
  376. end)
  377. assert(co() == 100); assert(x == 0)
  378. local st, msg = pcall(co); assert(x == 2)
  379. -- should get first error raised
  380. assert(not st and string.find(msg, "%w+%.%w+:%d+: XXX"))
  381. end
  382. -- a suspended coroutine should not close its variables when collected
  383. local co
  384. co = coroutine.wrap(function()
  385. local <toclose> x = function () os.exit(false) end -- should not run
  386. co = nil
  387. coroutine.yield()
  388. end)
  389. co() -- start coroutine
  390. assert(co == nil) -- eventually it will be collected
  391. collectgarbage()
  392. -- to-be-closed variables in generic for loops
  393. do
  394. local numopen = 0
  395. local function open (x)
  396. numopen = numopen + 1
  397. return
  398. function () -- iteraction function
  399. x = x - 1
  400. if x > 0 then return x end
  401. end,
  402. nil, -- state
  403. nil, -- control variable
  404. func2close(function () numopen = numopen - 1 end) -- closing function
  405. end
  406. local s = 0
  407. for i in open(10) do
  408. s = s + i
  409. end
  410. assert(s == 45 and numopen == 0)
  411. local s = 0
  412. for i in open(10) do
  413. if i < 5 then break end
  414. s = s + i
  415. end
  416. assert(s == 35 and numopen == 0)
  417. -- repeat test with '__open' metamethod instead of a function
  418. local function open (x)
  419. numopen = numopen + 1
  420. local state = setmetatable({x},
  421. {__close = function () numopen = numopen - 1 end})
  422. return
  423. function (t) -- iteraction function
  424. t[1] = t[1] - 1
  425. if t[1] > 0 then return t[1] end
  426. end,
  427. state,
  428. nil,
  429. state -- to-be-closed
  430. end
  431. local s = 0
  432. for i in open(10) do
  433. if (i < 5) then break end
  434. s = s + i
  435. end
  436. assert(s == 35 and numopen == 0)
  437. end
  438. print('OK')
  439. return 5,f
  440. end -- }