locals.lua 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203
  1. -- $Id: testes/locals.lua $
  2. -- See Copyright Notice in file lua.h
  3. print('testing local variables and environments')
  4. local debug = require"debug"
  5. local tracegc = require"tracegc"
  6. -- bug in 5.1:
  7. local function f(x) x = nil; return x end
  8. assert(f(10) == nil)
  9. local function f() local x; return x end
  10. assert(f(10) == nil)
  11. local function f(x) x = nil; local y; return x, y end
  12. assert(f(10) == nil and select(2, f(20)) == nil)
  13. do
  14. local i = 10
  15. do local i = 100; assert(i==100) end
  16. do local i = 1000; assert(i==1000) end
  17. assert(i == 10)
  18. if i ~= 10 then
  19. local i = 20
  20. else
  21. local i = 30
  22. assert(i == 30)
  23. end
  24. end
  25. f = nil
  26. local f
  27. local x = 1
  28. a = nil
  29. load('local a = {}')()
  30. assert(a == nil)
  31. function f (a)
  32. local _1, _2, _3, _4, _5
  33. local _6, _7, _8, _9, _10
  34. local x = 3
  35. local b = a
  36. local c,d = a,b
  37. if (d == b) then
  38. local x = 'q'
  39. x = b
  40. assert(x == 2)
  41. else
  42. assert(nil)
  43. end
  44. assert(x == 3)
  45. local f = 10
  46. end
  47. local b=10
  48. local a; repeat local b; a,b=1,2; assert(a+1==b); until a+b==3
  49. assert(x == 1)
  50. f(2)
  51. assert(type(f) == 'function')
  52. local function getenv (f)
  53. local a,b = debug.getupvalue(f, 1)
  54. assert(a == '_ENV')
  55. return b
  56. end
  57. -- test for global table of loaded chunks
  58. assert(getenv(load"a=3") == _G)
  59. local c = {}; local f = load("a = 3", nil, nil, c)
  60. assert(getenv(f) == c)
  61. assert(c.a == nil)
  62. f()
  63. assert(c.a == 3)
  64. -- old test for limits for special instructions
  65. do
  66. local i = 2
  67. local p = 4 -- p == 2^i
  68. repeat
  69. for j=-3,3 do
  70. assert(load(string.format([[local a=%s;
  71. a=a+%s;
  72. assert(a ==2^%s)]], j, p-j, i), '')) ()
  73. assert(load(string.format([[local a=%s;
  74. a=a-%s;
  75. assert(a==-2^%s)]], -j, p-j, i), '')) ()
  76. assert(load(string.format([[local a,b=0,%s;
  77. a=b-%s;
  78. assert(a==-2^%s)]], -j, p-j, i), '')) ()
  79. end
  80. p = 2 * p; i = i + 1
  81. until p <= 0
  82. end
  83. print'+'
  84. if rawget(_G, "T") then
  85. -- testing clearing of dead elements from tables
  86. collectgarbage("stop") -- stop GC
  87. local a = {[{}] = 4, [3] = 0, alo = 1,
  88. a1234567890123456789012345678901234567890 = 10}
  89. local t = T.querytab(a)
  90. for k,_ in pairs(a) do a[k] = undef end
  91. collectgarbage() -- restore GC and collect dead fields in 'a'
  92. for i=0,t-1 do
  93. local k = querytab(a, i)
  94. assert(k == nil or type(k) == 'number' or k == 'alo')
  95. end
  96. -- testing allocation errors during table insertions
  97. local a = {}
  98. local function additems ()
  99. a.x = true; a.y = true; a.z = true
  100. a[1] = true
  101. a[2] = true
  102. end
  103. for i = 1, math.huge do
  104. T.alloccount(i)
  105. local st, msg = pcall(additems)
  106. T.alloccount()
  107. local count = 0
  108. for k, v in pairs(a) do
  109. assert(a[k] == v)
  110. count = count + 1
  111. end
  112. if st then assert(count == 5); break end
  113. end
  114. end
  115. -- testing lexical environments
  116. assert(_ENV == _G)
  117. do
  118. local dummy
  119. local _ENV = (function (...) return ... end)(_G, dummy) -- {
  120. do local _ENV = {assert=assert}; assert(true) end
  121. local mt = {_G = _G}
  122. local foo,x
  123. A = false -- "declare" A
  124. do local _ENV = mt
  125. function foo (x)
  126. A = x
  127. do local _ENV = _G; A = 1000 end
  128. return function (x) return A .. x end
  129. end
  130. end
  131. assert(getenv(foo) == mt)
  132. x = foo('hi'); assert(mt.A == 'hi' and A == 1000)
  133. assert(x('*') == mt.A .. '*')
  134. do local _ENV = {assert=assert, A=10};
  135. do local _ENV = {assert=assert, A=20};
  136. assert(A==20);x=A
  137. end
  138. assert(A==10 and x==20)
  139. end
  140. assert(x==20)
  141. A = nil
  142. do -- constants
  143. local a<const>, b, c<const> = 10, 20, 30
  144. b = a + c + b -- 'b' is not constant
  145. assert(a == 10 and b == 60 and c == 30)
  146. local function checkro (name, code)
  147. local st, msg = load(code)
  148. local gab = string.format("attempt to assign to const variable '%s'", name)
  149. assert(not st and string.find(msg, gab))
  150. end
  151. checkro("y", "local x, y <const>, z = 10, 20, 30; x = 11; y = 12")
  152. checkro("x", "local x <const>, y, z <const> = 10, 20, 30; x = 11")
  153. checkro("z", "local x <const>, y, z <const> = 10, 20, 30; y = 10; z = 11")
  154. checkro("foo", "local foo <const> = 10; function foo() end")
  155. checkro("foo", "local foo <const> = {}; function foo() end")
  156. checkro("z", [[
  157. local a, z <const>, b = 10;
  158. function foo() a = 20; z = 32; end
  159. ]])
  160. checkro("var1", [[
  161. local a, var1 <const> = 10;
  162. function foo() a = 20; z = function () var1 = 12; end end
  163. ]])
  164. end
  165. print"testing to-be-closed variables"
  166. local function stack(n) n = ((n == 0) or stack(n - 1)) end
  167. local function func2close (f, x, y)
  168. local obj = setmetatable({}, {__close = f})
  169. if x then
  170. return x, obj, y
  171. else
  172. return obj
  173. end
  174. end
  175. do
  176. local a = {}
  177. do
  178. local b <close> = false -- not to be closed
  179. local x <close> = setmetatable({"x"}, {__close = function (self)
  180. a[#a + 1] = self[1] end})
  181. local w, y <close>, z = func2close(function (self, err)
  182. assert(err == nil); a[#a + 1] = "y"
  183. end, 10, 20)
  184. local c <close> = nil -- not to be closed
  185. a[#a + 1] = "in"
  186. assert(w == 10 and z == 20)
  187. end
  188. a[#a + 1] = "out"
  189. assert(a[1] == "in" and a[2] == "y" and a[3] == "x" and a[4] == "out")
  190. end
  191. do
  192. local X = false
  193. local x, closescope = func2close(function (_, msg)
  194. stack(10);
  195. assert(msg == nil)
  196. X = true
  197. end, 100)
  198. assert(x == 100); x = 101; -- 'x' is not read-only
  199. -- closing functions do not corrupt returning values
  200. local function foo (x)
  201. local _ <close> = closescope
  202. return x, X, 23
  203. end
  204. local a, b, c = foo(1.5)
  205. assert(a == 1.5 and b == false and c == 23 and X == true)
  206. X = false
  207. foo = function (x)
  208. local _<close> = func2close(function (_, msg)
  209. -- without errors, enclosing function should be still active when
  210. -- __close is called
  211. assert(debug.getinfo(2).name == "foo")
  212. assert(msg == nil)
  213. end)
  214. local _<close> = closescope
  215. local y = 15
  216. return y
  217. end
  218. assert(foo() == 15 and X == true)
  219. X = false
  220. foo = function ()
  221. local x <close> = closescope
  222. return x
  223. end
  224. assert(foo() == closescope and X == true)
  225. end
  226. do -- testing presence of second argument
  227. local function foo (howtoclose, obj, n)
  228. local ca -- copy of 'a' visible inside its close metamethod
  229. do
  230. local a <close> = func2close(function (...)
  231. local t = table.pack(...)
  232. assert(select("#", ...) == n)
  233. assert(t.n == n and t[1] == ca and (t.n < 2 or t[2] == obj))
  234. ca = 15 -- final value to be returned if howtoclose=="scope"
  235. end)
  236. ca = a
  237. if howtoclose == "ret" then return obj -- 'a' closed by return
  238. elseif howtoclose == "err" then error(obj) -- 'a' closed by error
  239. end
  240. end -- 'a' closed by end of scope
  241. return ca -- ca now should be 15
  242. end
  243. -- with no errors, closing methods receive no extra argument
  244. assert(foo("scope", nil, 1) == 15) -- close by end of scope
  245. assert(foo("ret", 32, 1) == 32) -- close by return
  246. -- with errors, they do
  247. local st, msg = pcall(foo, "err", 23, 2) -- close by error
  248. assert(not st and msg == 23)
  249. end
  250. -- testing to-be-closed x compile-time constants
  251. -- (there were some bugs here in Lua 5.4-rc3, due to a confusion
  252. -- between compile levels and stack levels of variables)
  253. do
  254. local flag = false
  255. local x = setmetatable({},
  256. {__close = function() assert(flag == false); flag = true end})
  257. local y <const> = nil
  258. local z <const> = nil
  259. do
  260. local a <close> = x
  261. end
  262. assert(flag) -- 'x' must be closed here
  263. end
  264. do
  265. -- similar problem, but with implicit close in for loops
  266. local flag = false
  267. local x = setmetatable({},
  268. {__close = function () assert(flag == false); flag = true end})
  269. -- return an empty iterator, nil, nil, and 'x' to be closed
  270. local function a ()
  271. return (function () return nil end), nil, nil, x
  272. end
  273. local v <const> = 1
  274. local w <const> = 1
  275. local x <const> = 1
  276. local y <const> = 1
  277. local z <const> = 1
  278. for k in a() do
  279. a = k
  280. end -- ending the loop must close 'x'
  281. assert(flag) -- 'x' must be closed here
  282. end
  283. do
  284. -- calls cannot be tail in the scope of to-be-closed variables
  285. local X, Y
  286. local function foo ()
  287. local _ <close> = func2close(function () Y = 10 end)
  288. assert(X == true and Y == nil) -- 'X' not closed yet
  289. return 1,2,3
  290. end
  291. local function bar ()
  292. local _ <close> = func2close(function () X = false end)
  293. X = true
  294. do
  295. return foo() -- not a tail call!
  296. end
  297. end
  298. local a, b, c, d = bar()
  299. assert(a == 1 and b == 2 and c == 3 and X == false and Y == 10 and d == nil)
  300. end
  301. do
  302. -- bug in 5.4.3: previous condition (calls cannot be tail in the
  303. -- scope of to-be-closed variables) must be valid for tbc variables
  304. -- created by 'for' loops.
  305. local closed = false
  306. local function foo ()
  307. return function () return true end, 0, 0,
  308. func2close(function () closed = true end)
  309. end
  310. local function tail() return closed end
  311. local function foo1 ()
  312. for k in foo() do return tail() end
  313. end
  314. assert(foo1() == false)
  315. assert(closed == true)
  316. end
  317. do
  318. -- bug in 5.4.4: 'break' may generate wrong 'close' instruction when
  319. -- leaving a loop block.
  320. local closed = false
  321. local o1 = setmetatable({}, {__close=function() closed = true end})
  322. local function test()
  323. for k, v in next, {}, nil, o1 do
  324. local function f() return k end -- create an upvalue
  325. break
  326. end
  327. assert(closed)
  328. end
  329. test()
  330. end
  331. do print("testing errors in __close")
  332. -- original error is in __close
  333. local function foo ()
  334. local x <close> =
  335. func2close(function (self, msg)
  336. assert(string.find(msg, "@y"))
  337. error("@x")
  338. end)
  339. local x1 <close> =
  340. func2close(function (self, msg)
  341. assert(string.find(msg, "@y"))
  342. end)
  343. local gc <close> = func2close(function () collectgarbage() end)
  344. local y <close> =
  345. func2close(function (self, msg)
  346. assert(string.find(msg, "@z")) -- error in 'z'
  347. error("@y")
  348. end)
  349. local z <close> =
  350. func2close(function (self, msg)
  351. assert(msg == nil)
  352. error("@z")
  353. end)
  354. return 200
  355. end
  356. local stat, msg = pcall(foo, false)
  357. assert(string.find(msg, "@x"))
  358. -- original error not in __close
  359. local function foo ()
  360. local x <close> =
  361. func2close(function (self, msg)
  362. -- after error, 'foo' was discarded, so caller now
  363. -- must be 'pcall'
  364. assert(debug.getinfo(2).name == "pcall")
  365. assert(string.find(msg, "@x1"))
  366. end)
  367. local x1 <close> =
  368. func2close(function (self, msg)
  369. assert(debug.getinfo(2).name == "pcall")
  370. assert(string.find(msg, "@y"))
  371. error("@x1")
  372. end)
  373. local gc <close> = func2close(function () collectgarbage() end)
  374. local y <close> =
  375. func2close(function (self, msg)
  376. assert(debug.getinfo(2).name == "pcall")
  377. assert(string.find(msg, "@z"))
  378. error("@y")
  379. end)
  380. local first = true
  381. local z <close> =
  382. func2close(function (self, msg)
  383. assert(debug.getinfo(2).name == "pcall")
  384. -- 'z' close is called once
  385. assert(first and msg == 4)
  386. first = false
  387. error("@z")
  388. end)
  389. error(4) -- original error
  390. end
  391. local stat, msg = pcall(foo, true)
  392. assert(string.find(msg, "@x1"))
  393. -- error leaving a block
  394. local function foo (...)
  395. do
  396. local x1 <close> =
  397. func2close(function (self, msg)
  398. assert(string.find(msg, "@X"))
  399. error("@Y")
  400. end)
  401. local x123 <close> =
  402. func2close(function (_, msg)
  403. assert(msg == nil)
  404. error("@X")
  405. end)
  406. end
  407. os.exit(false) -- should not run
  408. end
  409. local st, msg = xpcall(foo, debug.traceback)
  410. assert(string.match(msg, "^[^ ]* @Y"))
  411. -- error in toclose in vararg function
  412. local function foo (...)
  413. local x123 <close> = func2close(function () error("@x123") end)
  414. end
  415. local st, msg = xpcall(foo, debug.traceback)
  416. assert(string.match(msg, "^[^ ]* @x123"))
  417. assert(string.find(msg, "in metamethod 'close'"))
  418. end
  419. do -- errors due to non-closable values
  420. local function foo ()
  421. local x <close> = {}
  422. os.exit(false) -- should not run
  423. end
  424. local stat, msg = pcall(foo)
  425. assert(not stat and
  426. string.find(msg, "variable 'x' got a non%-closable value"))
  427. local function foo ()
  428. local xyz <close> = setmetatable({}, {__close = print})
  429. getmetatable(xyz).__close = nil -- remove metamethod
  430. end
  431. local stat, msg = pcall(foo)
  432. assert(not stat and string.find(msg, "metamethod 'close'"))
  433. local function foo ()
  434. local a1 <close> = func2close(function (_, msg)
  435. assert(string.find(msg, "number value"))
  436. error(12)
  437. end)
  438. local a2 <close> = setmetatable({}, {__close = print})
  439. local a3 <close> = func2close(function (_, msg)
  440. assert(msg == nil)
  441. error(123)
  442. end)
  443. getmetatable(a2).__close = 4 -- invalidate metamethod
  444. end
  445. local stat, msg = pcall(foo)
  446. assert(not stat and msg == 12)
  447. end
  448. do -- tbc inside close methods
  449. local track = {}
  450. local function foo ()
  451. local x <close> = func2close(function ()
  452. local xx <close> = func2close(function (_, msg)
  453. assert(msg == nil)
  454. track[#track + 1] = "xx"
  455. end)
  456. track[#track + 1] = "x"
  457. end)
  458. track[#track + 1] = "foo"
  459. return 20, 30, 40
  460. end
  461. local a, b, c, d = foo()
  462. assert(a == 20 and b == 30 and c == 40 and d == nil)
  463. assert(track[1] == "foo" and track[2] == "x" and track[3] == "xx")
  464. -- again, with errors
  465. local track = {}
  466. local function foo ()
  467. local x0 <close> = func2close(function (_, msg)
  468. assert(msg == 202)
  469. track[#track + 1] = "x0"
  470. end)
  471. local x <close> = func2close(function ()
  472. local xx <close> = func2close(function (_, msg)
  473. assert(msg == 101)
  474. track[#track + 1] = "xx"
  475. error(202)
  476. end)
  477. track[#track + 1] = "x"
  478. error(101)
  479. end)
  480. track[#track + 1] = "foo"
  481. return 20, 30, 40
  482. end
  483. local st, msg = pcall(foo)
  484. assert(not st and msg == 202)
  485. assert(track[1] == "foo" and track[2] == "x" and track[3] == "xx" and
  486. track[4] == "x0")
  487. end
  488. local function checktable (t1, t2)
  489. assert(#t1 == #t2)
  490. for i = 1, #t1 do
  491. assert(t1[i] == t2[i])
  492. end
  493. end
  494. do -- test for tbc variable high in the stack
  495. -- function to force a stack overflow
  496. local function overflow (n)
  497. overflow(n + 1)
  498. end
  499. -- error handler will create tbc variable handling a stack overflow,
  500. -- high in the stack
  501. local function errorh (m)
  502. assert(string.find(m, "stack overflow"))
  503. local x <close> = func2close(function (o) o[1] = 10 end)
  504. return x
  505. end
  506. local flag
  507. local st, obj
  508. -- run test in a coroutine so as not to swell the main stack
  509. local co = coroutine.wrap(function ()
  510. -- tbc variable down the stack
  511. local y <close> = func2close(function (obj, msg)
  512. assert(msg == nil)
  513. obj[1] = 100
  514. flag = obj
  515. end)
  516. tracegc.stop()
  517. st, obj = xpcall(overflow, errorh, 0)
  518. tracegc.start()
  519. end)
  520. co()
  521. assert(not st and obj[1] == 10 and flag[1] == 100)
  522. end
  523. if rawget(_G, "T") then
  524. do
  525. -- bug in 5.4.3
  526. -- 'lua_settop' may use a pointer to stack invalidated by 'luaF_close'
  527. -- reduce stack size
  528. collectgarbage(); collectgarbage(); collectgarbage()
  529. -- force a stack reallocation
  530. local function loop (n)
  531. if n < 400 then loop(n + 1) end
  532. end
  533. -- close metamethod will reallocate the stack
  534. local o = setmetatable({}, {__close = function () loop(0) end})
  535. local script = [[toclose 2; settop 1; return 1]]
  536. assert(T.testC(script, o) == script)
  537. end
  538. -- memory error inside closing function
  539. local function foo ()
  540. local y <close> = func2close(function () T.alloccount() end)
  541. local x <close> = setmetatable({}, {__close = function ()
  542. T.alloccount(0); local x = {} -- force a memory error
  543. end})
  544. error(1000) -- common error inside the function's body
  545. end
  546. stack(5) -- ensure a minimal number of CI structures
  547. -- despite memory error, 'y' will be executed and
  548. -- memory limit will be lifted
  549. local _, msg = pcall(foo)
  550. assert(msg == "not enough memory")
  551. local closemsg
  552. local close = func2close(function (self, msg)
  553. T.alloccount()
  554. closemsg = msg
  555. end)
  556. -- set a memory limit and return a closing object to remove the limit
  557. local function enter (count)
  558. stack(10) -- reserve some stack space
  559. T.alloccount(count)
  560. closemsg = nil
  561. return close
  562. end
  563. local function test ()
  564. local x <close> = enter(0) -- set a memory limit
  565. local y = {} -- raise a memory error
  566. end
  567. local _, msg = pcall(test)
  568. assert(msg == "not enough memory" and closemsg == "not enough memory")
  569. -- repeat test with extra closing upvalues
  570. local function test ()
  571. local xxx <close> = func2close(function (self, msg)
  572. assert(msg == "not enough memory");
  573. error(1000) -- raise another error
  574. end)
  575. local xx <close> = func2close(function (self, msg)
  576. assert(msg == "not enough memory");
  577. end)
  578. local x <close> = enter(0) -- set a memory limit
  579. local y = {} -- raise a memory error
  580. end
  581. local _, msg = pcall(test)
  582. assert(msg == 1000 and closemsg == "not enough memory")
  583. do -- testing 'toclose' in C string buffer
  584. collectgarbage()
  585. local s = string.rep('a', 10000) -- large string
  586. local m = T.totalmem()
  587. collectgarbage("stop")
  588. s = string.upper(s) -- allocate buffer + new string (10K each)
  589. -- ensure buffer was deallocated
  590. assert(T.totalmem() - m <= 11000)
  591. collectgarbage("restart")
  592. end
  593. do -- now some tests for freeing buffer in case of errors
  594. local lim = 10000 -- some size larger than the static buffer
  595. local extra = 2000 -- some extra memory (for callinfo, etc.)
  596. local s = string.rep("a", lim)
  597. -- concat this table needs two buffer resizes (one for each 's')
  598. local a = {s, s}
  599. collectgarbage(); collectgarbage()
  600. local m = T.totalmem()
  601. collectgarbage("stop")
  602. -- error in the first buffer allocation
  603. T. totalmem(m + extra)
  604. assert(not pcall(table.concat, a))
  605. -- first buffer was not even allocated
  606. assert(T.totalmem() - m <= extra)
  607. -- error in the second buffer allocation
  608. T. totalmem(m + lim + extra)
  609. assert(not pcall(table.concat, a))
  610. -- first buffer was released by 'toclose'
  611. assert(T.totalmem() - m <= extra)
  612. -- userdata, buffer, final string
  613. T.totalmem(m + 2*lim + extra)
  614. assert(#table.concat(a) == 2*lim)
  615. T.totalmem(0) -- remove memory limit
  616. collectgarbage("restart")
  617. print'+'
  618. end
  619. do
  620. -- '__close' vs. return hooks in C functions
  621. local trace = {}
  622. local function hook (event)
  623. trace[#trace + 1] = event .. " " .. (debug.getinfo(2).name or "?")
  624. end
  625. -- create tbc variables to be used by C function
  626. local x = func2close(function (_,msg)
  627. trace[#trace + 1] = "x"
  628. end)
  629. local y = func2close(function (_,msg)
  630. trace[#trace + 1] = "y"
  631. end)
  632. debug.sethook(hook, "r")
  633. local t = {T.testC([[
  634. toclose 2 # x
  635. pushnum 10
  636. pushint 20
  637. toclose 3 # y
  638. return 2
  639. ]], x, y)}
  640. debug.sethook()
  641. -- hooks ran before return hook from 'testC'
  642. checktable(trace,
  643. {"return sethook", "y", "return ?", "x", "return ?", "return testC"})
  644. -- results are correct
  645. checktable(t, {10, 20})
  646. end
  647. end
  648. do -- '__close' vs. return hooks in Lua functions
  649. local trace = {}
  650. local function hook (event)
  651. trace[#trace + 1] = event .. " " .. debug.getinfo(2).name
  652. end
  653. local function foo (...)
  654. local x <close> = func2close(function (_,msg)
  655. trace[#trace + 1] = "x"
  656. end)
  657. local y <close> = func2close(function (_,msg)
  658. debug.sethook(hook, "r")
  659. end)
  660. return ...
  661. end
  662. local t = {foo(10,20,30)}
  663. debug.sethook()
  664. checktable(t, {10, 20, 30})
  665. checktable(trace,
  666. {"return sethook", "return close", "x", "return close", "return foo"})
  667. end
  668. print "to-be-closed variables in coroutines"
  669. do
  670. -- yielding inside closing metamethods
  671. local trace = {}
  672. local co = coroutine.wrap(function ()
  673. trace[#trace + 1] = "nowX"
  674. -- will be closed after 'y'
  675. local x <close> = func2close(function (_, msg)
  676. assert(msg == nil)
  677. trace[#trace + 1] = "x1"
  678. coroutine.yield("x")
  679. trace[#trace + 1] = "x2"
  680. end)
  681. return pcall(function ()
  682. do -- 'z' will be closed first
  683. local z <close> = func2close(function (_, msg)
  684. assert(msg == nil)
  685. trace[#trace + 1] = "z1"
  686. coroutine.yield("z")
  687. trace[#trace + 1] = "z2"
  688. end)
  689. end
  690. trace[#trace + 1] = "nowY"
  691. -- will be closed after 'z'
  692. local y <close> = func2close(function(_, msg)
  693. assert(msg == nil)
  694. trace[#trace + 1] = "y1"
  695. coroutine.yield("y")
  696. trace[#trace + 1] = "y2"
  697. end)
  698. return 10, 20, 30
  699. end)
  700. end)
  701. assert(co() == "z")
  702. assert(co() == "y")
  703. assert(co() == "x")
  704. checktable({co()}, {true, 10, 20, 30})
  705. checktable(trace, {"nowX", "z1", "z2", "nowY", "y1", "y2", "x1", "x2"})
  706. end
  707. do
  708. -- yielding inside closing metamethods while returning
  709. -- (bug in 5.4.3)
  710. local extrares -- result from extra yield (if any)
  711. local function check (body, extra, ...)
  712. local t = table.pack(...) -- expected returns
  713. local co = coroutine.wrap(body)
  714. if extra then
  715. extrares = co() -- runs until first (extra) yield
  716. end
  717. local res = table.pack(co()) -- runs until "regular" yield
  718. -- regular yield will yield all values passed to the close function;
  719. -- without errors, that is only the object being closed.
  720. assert(res.n == 1 and type(res[1]) == "table")
  721. local res2 = table.pack(co()) -- runs until end of function
  722. assert(res2.n == t.n)
  723. for i = 1, #t do
  724. if t[i] == "x" then
  725. assert(res2[i] == res[1]) -- value that was closed
  726. else
  727. assert(res2[i] == t[i])
  728. end
  729. end
  730. end
  731. local function foo ()
  732. local x <close> = func2close(coroutine.yield) -- "regular" yield
  733. local extra <close> = func2close(function (self)
  734. assert(self == extrares)
  735. coroutine.yield(100) -- first (extra) yield
  736. end)
  737. extrares = extra
  738. return table.unpack{10, x, 30}
  739. end
  740. check(foo, true, 10, "x", 30)
  741. assert(extrares == 100)
  742. local function foo ()
  743. local x <close> = func2close(coroutine.yield) -- "regular" yield
  744. return
  745. end
  746. check(foo, false)
  747. local function foo ()
  748. local x <close> = func2close(coroutine.yield) -- "regular" yield
  749. local y, z = 20, 30
  750. return x
  751. end
  752. check(foo, false, "x")
  753. local function foo ()
  754. local x <close> = func2close(coroutine.yield) -- "regular" yield
  755. local extra <close> = func2close(coroutine.yield) -- extra yield
  756. return table.unpack({}, 1, 100) -- 100 nils
  757. end
  758. check(foo, true, table.unpack({}, 1, 100))
  759. end
  760. do
  761. -- yielding inside closing metamethods after an error
  762. local co = coroutine.wrap(function ()
  763. local function foo (err)
  764. local z <close> = func2close(function(_, msg)
  765. assert(msg == nil or msg == err + 20)
  766. coroutine.yield("z")
  767. return 100, 200
  768. end)
  769. local y <close> = func2close(function(_, msg)
  770. -- still gets the original error (if any)
  771. assert(msg == err or (msg == nil and err == 1))
  772. coroutine.yield("y")
  773. if err then error(err + 20) end -- creates or changes the error
  774. end)
  775. local x <close> = func2close(function(_, msg)
  776. assert(msg == err or (msg == nil and err == 1))
  777. coroutine.yield("x")
  778. return 100, 200
  779. end)
  780. if err == 10 then error(err) else return 10, 20 end
  781. end
  782. coroutine.yield(pcall(foo, nil)) -- no error
  783. coroutine.yield(pcall(foo, 1)) -- error in __close
  784. return pcall(foo, 10) -- 'foo' will raise an error
  785. end)
  786. local a, b = co() -- first foo: no error
  787. assert(a == "x" and b == nil) -- yields inside 'x'; Ok
  788. a, b = co()
  789. assert(a == "y" and b == nil) -- yields inside 'y'; Ok
  790. a, b = co()
  791. assert(a == "z" and b == nil) -- yields inside 'z'; Ok
  792. local a, b, c = co()
  793. assert(a and b == 10 and c == 20) -- returns from 'pcall(foo, nil)'
  794. local a, b = co() -- second foo: error in __close
  795. assert(a == "x" and b == nil) -- yields inside 'x'; Ok
  796. a, b = co()
  797. assert(a == "y" and b == nil) -- yields inside 'y'; Ok
  798. a, b = co()
  799. assert(a == "z" and b == nil) -- yields inside 'z'; Ok
  800. local st, msg = co() -- reports the error in 'y'
  801. assert(not st and msg == 21)
  802. local a, b = co() -- third foo: error in function body
  803. assert(a == "x" and b == nil) -- yields inside 'x'; Ok
  804. a, b = co()
  805. assert(a == "y" and b == nil) -- yields inside 'y'; Ok
  806. a, b = co()
  807. assert(a == "z" and b == nil) -- yields inside 'z'; Ok
  808. local st, msg = co() -- gets final error
  809. assert(not st and msg == 10 + 20)
  810. end
  811. do
  812. -- an error in a wrapped coroutine closes variables
  813. local x = false
  814. local y = false
  815. local co = coroutine.wrap(function ()
  816. local xv <close> = func2close(function () x = true end)
  817. do
  818. local yv <close> = func2close(function () y = true end)
  819. coroutine.yield(100) -- yield doesn't close variable
  820. end
  821. coroutine.yield(200) -- yield doesn't close variable
  822. error(23) -- error does
  823. end)
  824. local b = co()
  825. assert(b == 100 and not x and not y)
  826. b = co()
  827. assert(b == 200 and not x and y)
  828. local a, b = pcall(co)
  829. assert(not a and b == 23 and x and y)
  830. end
  831. do
  832. -- error in a wrapped coroutine raising errors when closing a variable
  833. local x = 0
  834. local co = coroutine.wrap(function ()
  835. local xx <close> = func2close(function (_, msg)
  836. x = x + 1;
  837. assert(string.find(msg, "@XXX"))
  838. error("@YYY")
  839. end)
  840. local xv <close> = func2close(function () x = x + 1; error("@XXX") end)
  841. coroutine.yield(100)
  842. error(200)
  843. end)
  844. assert(co() == 100); assert(x == 0)
  845. local st, msg = pcall(co); assert(x == 2)
  846. assert(not st and string.find(msg, "@YYY")) -- should get error raised
  847. local x = 0
  848. local y = 0
  849. co = coroutine.wrap(function ()
  850. local xx <close> = func2close(function (_, err)
  851. y = y + 1;
  852. assert(string.find(err, "XXX"))
  853. error("YYY")
  854. end)
  855. local xv <close> = func2close(function ()
  856. x = x + 1; error("XXX")
  857. end)
  858. coroutine.yield(100)
  859. return 200
  860. end)
  861. assert(co() == 100); assert(x == 0)
  862. local st, msg = pcall(co)
  863. assert(x == 1 and y == 1)
  864. -- should get first error raised
  865. assert(not st and string.find(msg, "%w+%.%w+:%d+: YYY"))
  866. end
  867. -- a suspended coroutine should not close its variables when collected
  868. local co
  869. co = coroutine.wrap(function()
  870. -- should not run
  871. local x <close> = func2close(function () os.exit(false) end)
  872. co = nil
  873. coroutine.yield()
  874. end)
  875. co() -- start coroutine
  876. assert(co == nil) -- eventually it will be collected
  877. collectgarbage()
  878. if rawget(_G, "T") then
  879. print("to-be-closed variables x coroutines in C")
  880. do
  881. local token = 0
  882. local count = 0
  883. local f = T.makeCfunc[[
  884. toclose 1
  885. toclose 2
  886. return .
  887. ]]
  888. local obj = func2close(function (_, msg)
  889. count = count + 1
  890. token = coroutine.yield(count, token)
  891. end)
  892. local co = coroutine.wrap(f)
  893. local ct, res = co(obj, obj, 10, 20, 30, 3) -- will return 10, 20, 30
  894. -- initial token value, after closing 2nd obj
  895. assert(ct == 1 and res == 0)
  896. -- run until yield when closing 1st obj
  897. ct, res = co(100)
  898. assert(ct == 2 and res == 100)
  899. res = {co(200)} -- run until end
  900. assert(res[1] == 10 and res[2] == 20 and res[3] == 30 and res[4] == nil)
  901. assert(token == 200)
  902. end
  903. do
  904. local f = T.makeCfunc[[
  905. toclose 1
  906. return .
  907. ]]
  908. local obj = func2close(function ()
  909. local temp
  910. local x <close> = func2close(function ()
  911. coroutine.yield(temp)
  912. return 1,2,3 -- to be ignored
  913. end)
  914. temp = coroutine.yield("closing obj")
  915. return 1,2,3 -- to be ignored
  916. end)
  917. local co = coroutine.wrap(f)
  918. local res = co(obj, 10, 30, 1) -- will return only 30
  919. assert(res == "closing obj")
  920. res = co("closing x")
  921. assert(res == "closing x")
  922. res = {co()}
  923. assert(res[1] == 30 and res[2] == nil)
  924. end
  925. do
  926. -- still cannot yield inside 'closeslot'
  927. local f = T.makeCfunc[[
  928. toclose 1
  929. closeslot 1
  930. ]]
  931. local obj = func2close(coroutine.yield)
  932. local co = coroutine.create(f)
  933. local st, msg = coroutine.resume(co, obj)
  934. assert(not st and string.find(msg, "attempt to yield across"))
  935. -- nor outside a coroutine
  936. local f = T.makeCfunc[[
  937. toclose 1
  938. ]]
  939. local st, msg = pcall(f, obj)
  940. assert(not st and string.find(msg, "attempt to yield from outside"))
  941. end
  942. end
  943. -- to-be-closed variables in generic for loops
  944. do
  945. local numopen = 0
  946. local function open (x)
  947. numopen = numopen + 1
  948. return
  949. function () -- iteraction function
  950. x = x - 1
  951. if x > 0 then return x end
  952. end,
  953. nil, -- state
  954. nil, -- control variable
  955. func2close(function () numopen = numopen - 1 end) -- closing function
  956. end
  957. local s = 0
  958. for i in open(10) do
  959. s = s + i
  960. end
  961. assert(s == 45 and numopen == 0)
  962. local s = 0
  963. for i in open(10) do
  964. if i < 5 then break end
  965. s = s + i
  966. end
  967. assert(s == 35 and numopen == 0)
  968. local s = 0
  969. for i in open(10) do
  970. for j in open(10) do
  971. if i + j < 5 then goto endloop end
  972. s = s + i
  973. end
  974. end
  975. ::endloop::
  976. assert(s == 375 and numopen == 0)
  977. end
  978. print('OK')
  979. return 5,f
  980. end -- }