locals.lua 25 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051
  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
  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 fields 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. do -- constants
  141. local a<const>, b, c<const> = 10, 20, 30
  142. b = a + c + b -- 'b' is not constant
  143. assert(a == 10 and b == 60 and c == 30)
  144. local function checkro (name, code)
  145. local st, msg = load(code)
  146. local gab = string.format("attempt to assign to const variable '%s'", name)
  147. assert(not st and string.find(msg, gab))
  148. end
  149. checkro("y", "local x, y <const>, z = 10, 20, 30; x = 11; y = 12")
  150. checkro("x", "local x <const>, y, z <const> = 10, 20, 30; x = 11")
  151. checkro("z", "local x <const>, y, z <const> = 10, 20, 30; y = 10; z = 11")
  152. checkro("z", [[
  153. local a, z <const>, b = 10;
  154. function foo() a = 20; z = 32; end
  155. ]])
  156. checkro("var1", [[
  157. local a, var1 <const> = 10;
  158. function foo() a = 20; z = function () var1 = 12; end end
  159. ]])
  160. end
  161. print"testing to-be-closed variables"
  162. local function stack(n) n = ((n == 0) or stack(n - 1)) end
  163. local function func2close (f, x, y)
  164. local obj = setmetatable({}, {__close = f})
  165. if x then
  166. return x, obj, y
  167. else
  168. return obj
  169. end
  170. end
  171. do
  172. local a = {}
  173. do
  174. local b <close> = false -- not to be closed
  175. local x <close> = setmetatable({"x"}, {__close = function (self)
  176. a[#a + 1] = self[1] end})
  177. local w, y <close>, z = func2close(function (self, err)
  178. assert(err == nil); a[#a + 1] = "y"
  179. end, 10, 20)
  180. local c <close> = nil -- not to be closed
  181. a[#a + 1] = "in"
  182. assert(w == 10 and z == 20)
  183. end
  184. a[#a + 1] = "out"
  185. assert(a[1] == "in" and a[2] == "y" and a[3] == "x" and a[4] == "out")
  186. end
  187. do
  188. local X = false
  189. local x, closescope = func2close(function (_, msg)
  190. stack(10);
  191. assert(msg == nil)
  192. X = true
  193. end, 100)
  194. assert(x == 100); x = 101; -- 'x' is not read-only
  195. -- closing functions do not corrupt returning values
  196. local function foo (x)
  197. local _ <close> = closescope
  198. return x, X, 23
  199. end
  200. local a, b, c = foo(1.5)
  201. assert(a == 1.5 and b == false and c == 23 and X == true)
  202. X = false
  203. foo = function (x)
  204. local _<close> = func2close(function (_, msg)
  205. -- without errors, enclosing function should be still active when
  206. -- __close is called
  207. assert(debug.getinfo(2).name == "foo")
  208. assert(msg == nil)
  209. end)
  210. local _<close> = closescope
  211. local y = 15
  212. return y
  213. end
  214. assert(foo() == 15 and X == true)
  215. X = false
  216. foo = function ()
  217. local x <close> = closescope
  218. return x
  219. end
  220. assert(foo() == closescope and X == true)
  221. end
  222. -- testing to-be-closed x compile-time constants
  223. -- (there were some bugs here in Lua 5.4-rc3, due to a confusion
  224. -- between compile levels and stack levels of variables)
  225. do
  226. local flag = false
  227. local x = setmetatable({},
  228. {__close = function() assert(flag == false); flag = true end})
  229. local y <const> = nil
  230. local z <const> = nil
  231. do
  232. local a <close> = x
  233. end
  234. assert(flag) -- 'x' must be closed here
  235. end
  236. do
  237. -- similar problem, but with implicit close in for loops
  238. local flag = false
  239. local x = setmetatable({},
  240. {__close = function () assert(flag == false); flag = true end})
  241. -- return an empty iterator, nil, nil, and 'x' to be closed
  242. local function a ()
  243. return (function () return nil end), nil, nil, x
  244. end
  245. local v <const> = 1
  246. local w <const> = 1
  247. local x <const> = 1
  248. local y <const> = 1
  249. local z <const> = 1
  250. for k in a() do
  251. a = k
  252. end -- ending the loop must close 'x'
  253. assert(flag) -- 'x' must be closed here
  254. end
  255. do
  256. -- calls cannot be tail in the scope of to-be-closed variables
  257. local X, Y
  258. local function foo ()
  259. local _ <close> = func2close(function () Y = 10 end)
  260. assert(X == true and Y == nil) -- 'X' not closed yet
  261. return 1,2,3
  262. end
  263. local function bar ()
  264. local _ <close> = func2close(function () X = false end)
  265. X = true
  266. do
  267. return foo() -- not a tail call!
  268. end
  269. end
  270. local a, b, c, d = bar()
  271. assert(a == 1 and b == 2 and c == 3 and X == false and Y == 10 and d == nil)
  272. end
  273. do print("testing errors in __close")
  274. -- original error is in __close
  275. local function foo ()
  276. local x <close> =
  277. func2close(function (self, msg)
  278. assert(string.find(msg, "@y"))
  279. error("@x")
  280. end)
  281. local x1 <close> =
  282. func2close(function (self, msg)
  283. assert(string.find(msg, "@y"))
  284. end)
  285. local gc <close> = func2close(function () collectgarbage() end)
  286. local y <close> =
  287. func2close(function (self, msg)
  288. assert(string.find(msg, "@z")) -- error in 'z'
  289. error("@y")
  290. end)
  291. local z <close> =
  292. func2close(function (self, msg)
  293. assert(msg == nil)
  294. error("@z")
  295. end)
  296. return 200
  297. end
  298. local stat, msg = pcall(foo, false)
  299. assert(string.find(msg, "@x"))
  300. -- original error not in __close
  301. local function foo ()
  302. local x <close> =
  303. func2close(function (self, msg)
  304. -- after error, 'foo' was discarded, so caller now
  305. -- must be 'pcall'
  306. assert(debug.getinfo(2).name == "pcall")
  307. assert(string.find(msg, "@x1"))
  308. end)
  309. local x1 <close> =
  310. func2close(function (self, msg)
  311. assert(debug.getinfo(2).name == "pcall")
  312. assert(string.find(msg, "@y"))
  313. error("@x1")
  314. end)
  315. local gc <close> = func2close(function () collectgarbage() end)
  316. local y <close> =
  317. func2close(function (self, msg)
  318. assert(debug.getinfo(2).name == "pcall")
  319. assert(string.find(msg, "@z"))
  320. error("@y")
  321. end)
  322. local first = true
  323. local z <close> =
  324. func2close(function (self, msg)
  325. assert(debug.getinfo(2).name == "pcall")
  326. -- 'z' close is called once
  327. assert(first and msg == 4)
  328. first = false
  329. error("@z")
  330. end)
  331. error(4) -- original error
  332. end
  333. local stat, msg = pcall(foo, true)
  334. assert(string.find(msg, "@x1"))
  335. -- error leaving a block
  336. local function foo (...)
  337. do
  338. local x1 <close> =
  339. func2close(function (self, msg)
  340. assert(string.find(msg, "@X"))
  341. error("@Y")
  342. end)
  343. local x123 <close> =
  344. func2close(function (_, msg)
  345. assert(msg == nil)
  346. error("@X")
  347. end)
  348. end
  349. os.exit(false) -- should not run
  350. end
  351. local st, msg = xpcall(foo, debug.traceback)
  352. assert(string.match(msg, "^[^ ]* @Y"))
  353. -- error in toclose in vararg function
  354. local function foo (...)
  355. local x123 <close> = func2close(function () error("@x123") end)
  356. end
  357. local st, msg = xpcall(foo, debug.traceback)
  358. assert(string.match(msg, "^[^ ]* @x123"))
  359. assert(string.find(msg, "in metamethod 'close'"))
  360. end
  361. do -- errors due to non-closable values
  362. local function foo ()
  363. local x <close> = {}
  364. os.exit(false) -- should not run
  365. end
  366. local stat, msg = pcall(foo)
  367. assert(not stat and
  368. string.find(msg, "variable 'x' got a non%-closable value"))
  369. local function foo ()
  370. local xyz <close> = setmetatable({}, {__close = print})
  371. getmetatable(xyz).__close = nil -- remove metamethod
  372. end
  373. local stat, msg = pcall(foo)
  374. assert(not stat and string.find(msg, "metamethod 'close'"))
  375. local function foo ()
  376. local a1 <close> = func2close(function (_, msg)
  377. assert(string.find(msg, "number value"))
  378. error(12)
  379. end)
  380. local a2 <close> = setmetatable({}, {__close = print})
  381. local a3 <close> = func2close(function (_, msg)
  382. assert(msg == nil)
  383. error(123)
  384. end)
  385. getmetatable(a2).__close = 4 -- invalidate metamethod
  386. end
  387. local stat, msg = pcall(foo)
  388. assert(not stat and msg == 12)
  389. end
  390. do -- tbc inside close methods
  391. local track = {}
  392. local function foo ()
  393. local x <close> = func2close(function ()
  394. local xx <close> = func2close(function (_, msg)
  395. assert(msg == nil)
  396. track[#track + 1] = "xx"
  397. end)
  398. track[#track + 1] = "x"
  399. end)
  400. track[#track + 1] = "foo"
  401. return 20, 30, 40
  402. end
  403. local a, b, c, d = foo()
  404. assert(a == 20 and b == 30 and c == 40 and d == nil)
  405. assert(track[1] == "foo" and track[2] == "x" and track[3] == "xx")
  406. -- again, with errors
  407. local track = {}
  408. local function foo ()
  409. local x0 <close> = func2close(function (_, msg)
  410. assert(msg == 202)
  411. track[#track + 1] = "x0"
  412. end)
  413. local x <close> = func2close(function ()
  414. local xx <close> = func2close(function (_, msg)
  415. assert(msg == 101)
  416. track[#track + 1] = "xx"
  417. error(202)
  418. end)
  419. track[#track + 1] = "x"
  420. error(101)
  421. end)
  422. track[#track + 1] = "foo"
  423. return 20, 30, 40
  424. end
  425. local st, msg = pcall(foo)
  426. assert(not st and msg == 202)
  427. assert(track[1] == "foo" and track[2] == "x" and track[3] == "xx" and
  428. track[4] == "x0")
  429. end
  430. local function checktable (t1, t2)
  431. assert(#t1 == #t2)
  432. for i = 1, #t1 do
  433. assert(t1[i] == t2[i])
  434. end
  435. end
  436. do -- test for tbc variable high in the stack
  437. -- function to force a stack overflow
  438. local function overflow (n)
  439. overflow(n + 1)
  440. end
  441. -- error handler will create tbc variable handling a stack overflow,
  442. -- high in the stack
  443. local function errorh (m)
  444. assert(string.find(m, "stack overflow"))
  445. local x <close> = func2close(function (o) o[1] = 10 end)
  446. return x
  447. end
  448. local flag
  449. local st, obj
  450. -- run test in a coroutine so as not to swell the main stack
  451. local co = coroutine.wrap(function ()
  452. -- tbc variable down the stack
  453. local y <close> = func2close(function (obj, msg)
  454. assert(msg == nil)
  455. obj[1] = 100
  456. flag = obj
  457. end)
  458. collectgarbage("stop")
  459. st, obj = xpcall(overflow, errorh, 0)
  460. collectgarbage("restart")
  461. end)
  462. co()
  463. assert(not st and obj[1] == 10 and flag[1] == 100)
  464. end
  465. if rawget(_G, "T") then
  466. -- memory error inside closing function
  467. local function foo ()
  468. local y <close> = func2close(function () T.alloccount() end)
  469. local x <close> = setmetatable({}, {__close = function ()
  470. T.alloccount(0); local x = {} -- force a memory error
  471. end})
  472. error(1000) -- common error inside the function's body
  473. end
  474. stack(5) -- ensure a minimal number of CI structures
  475. -- despite memory error, 'y' will be executed and
  476. -- memory limit will be lifted
  477. local _, msg = pcall(foo)
  478. assert(msg == "not enough memory")
  479. local closemsg
  480. local close = func2close(function (self, msg)
  481. T.alloccount()
  482. closemsg = msg
  483. end)
  484. -- set a memory limit and return a closing object to remove the limit
  485. local function enter (count)
  486. stack(10) -- reserve some stack space
  487. T.alloccount(count)
  488. closemsg = nil
  489. return close
  490. end
  491. local function test ()
  492. local x <close> = enter(0) -- set a memory limit
  493. local y = {} -- raise a memory error
  494. end
  495. local _, msg = pcall(test)
  496. assert(msg == "not enough memory" and closemsg == "not enough memory")
  497. -- repeat test with extra closing upvalues
  498. local function test ()
  499. local xxx <close> = func2close(function (self, msg)
  500. assert(msg == "not enough memory");
  501. error(1000) -- raise another error
  502. end)
  503. local xx <close> = func2close(function (self, msg)
  504. assert(msg == "not enough memory");
  505. end)
  506. local x <close> = enter(0) -- set a memory limit
  507. local y = {} -- raise a memory error
  508. end
  509. local _, msg = pcall(test)
  510. assert(msg == 1000 and closemsg == "not enough memory")
  511. do -- testing 'toclose' in C string buffer
  512. collectgarbage()
  513. local s = string.rep('a', 10000) -- large string
  514. local m = T.totalmem()
  515. collectgarbage("stop")
  516. s = string.upper(s) -- allocate buffer + new string (10K each)
  517. -- ensure buffer was deallocated
  518. assert(T.totalmem() - m <= 11000)
  519. collectgarbage("restart")
  520. end
  521. do -- now some tests for freeing buffer in case of errors
  522. local lim = 10000 -- some size larger than the static buffer
  523. local extra = 2000 -- some extra memory (for callinfo, etc.)
  524. local s = string.rep("a", lim)
  525. -- concat this table needs two buffer resizes (one for each 's')
  526. local a = {s, s}
  527. collectgarbage(); collectgarbage()
  528. m = T.totalmem()
  529. collectgarbage("stop")
  530. -- error in the first buffer allocation
  531. T. totalmem(m + extra)
  532. assert(not pcall(table.concat, a))
  533. -- first buffer was not even allocated
  534. assert(T.totalmem() - m <= extra)
  535. -- error in the second buffer allocation
  536. T. totalmem(m + lim + extra)
  537. assert(not pcall(table.concat, a))
  538. -- first buffer was released by 'toclose'
  539. assert(T.totalmem() - m <= extra)
  540. -- error in creation of final string
  541. T.totalmem(m + 2 * lim + extra)
  542. assert(not pcall(table.concat, a))
  543. -- second buffer was released by 'toclose'
  544. assert(T.totalmem() - m <= extra)
  545. -- userdata, buffer, buffer, final string
  546. T.totalmem(m + 4*lim + extra)
  547. assert(#table.concat(a) == 2*lim)
  548. T.totalmem(0) -- remove memory limit
  549. collectgarbage("restart")
  550. print'+'
  551. end
  552. do
  553. -- '__close' vs. return hooks in C functions
  554. local trace = {}
  555. local function hook (event)
  556. trace[#trace + 1] = event .. " " .. (debug.getinfo(2).name or "?")
  557. end
  558. -- create tbc variables to be used by C function
  559. local x = func2close(function (_,msg)
  560. trace[#trace + 1] = "x"
  561. end)
  562. local y = func2close(function (_,msg)
  563. trace[#trace + 1] = "y"
  564. end)
  565. debug.sethook(hook, "r")
  566. local t = {T.testC([[
  567. toclose 2 # x
  568. pushnum 10
  569. pushint 20
  570. toclose 3 # y
  571. return 2
  572. ]], x, y)}
  573. debug.sethook()
  574. -- hooks ran before return hook from 'testC'
  575. checktable(trace,
  576. {"return sethook", "y", "return ?", "x", "return ?", "return testC"})
  577. -- results are correct
  578. checktable(t, {10, 20})
  579. end
  580. end
  581. do -- '__close' vs. return hooks in Lua functions
  582. local trace = {}
  583. local function hook (event)
  584. trace[#trace + 1] = event .. " " .. debug.getinfo(2).name
  585. end
  586. local function foo (...)
  587. local x <close> = func2close(function (_,msg)
  588. trace[#trace + 1] = "x"
  589. end)
  590. local y <close> = func2close(function (_,msg)
  591. debug.sethook(hook, "r")
  592. end)
  593. return ...
  594. end
  595. local t = {foo(10,20,30)}
  596. debug.sethook()
  597. checktable(t, {10, 20, 30})
  598. checktable(trace,
  599. {"return sethook", "return close", "x", "return close", "return foo"})
  600. end
  601. print "to-be-closed variables in coroutines"
  602. do
  603. -- yielding inside closing metamethods
  604. local trace = {}
  605. local co = coroutine.wrap(function ()
  606. trace[#trace + 1] = "nowX"
  607. -- will be closed after 'y'
  608. local x <close> = func2close(function (_, msg)
  609. assert(msg == nil)
  610. trace[#trace + 1] = "x1"
  611. coroutine.yield("x")
  612. trace[#trace + 1] = "x2"
  613. end)
  614. return pcall(function ()
  615. do -- 'z' will be closed first
  616. local z <close> = func2close(function (_, msg)
  617. assert(msg == nil)
  618. trace[#trace + 1] = "z1"
  619. coroutine.yield("z")
  620. trace[#trace + 1] = "z2"
  621. end)
  622. end
  623. trace[#trace + 1] = "nowY"
  624. -- will be closed after 'z'
  625. local y <close> = func2close(function(_, msg)
  626. assert(msg == nil)
  627. trace[#trace + 1] = "y1"
  628. coroutine.yield("y")
  629. trace[#trace + 1] = "y2"
  630. end)
  631. return 10, 20, 30
  632. end)
  633. end)
  634. assert(co() == "z")
  635. assert(co() == "y")
  636. assert(co() == "x")
  637. checktable({co()}, {true, 10, 20, 30})
  638. checktable(trace, {"nowX", "z1", "z2", "nowY", "y1", "y2", "x1", "x2"})
  639. end
  640. do
  641. -- yielding inside closing metamethods after an error
  642. local co = coroutine.wrap(function ()
  643. local function foo (err)
  644. local z <close> = func2close(function(_, msg)
  645. assert(msg == nil or msg == err + 20)
  646. coroutine.yield("z")
  647. return 100, 200
  648. end)
  649. local y <close> = func2close(function(_, msg)
  650. -- still gets the original error (if any)
  651. assert(msg == err or (msg == nil and err == 1))
  652. coroutine.yield("y")
  653. if err then error(err + 20) end -- creates or changes the error
  654. end)
  655. local x <close> = func2close(function(_, msg)
  656. assert(msg == err or (msg == nil and err == 1))
  657. coroutine.yield("x")
  658. return 100, 200
  659. end)
  660. if err == 10 then error(err) else return 10, 20 end
  661. end
  662. coroutine.yield(pcall(foo, nil)) -- no error
  663. coroutine.yield(pcall(foo, 1)) -- error in __close
  664. return pcall(foo, 10) -- 'foo' will raise an error
  665. end)
  666. local a, b = co() -- first foo: no error
  667. assert(a == "x" and b == nil) -- yields inside 'x'; Ok
  668. a, b = co()
  669. assert(a == "y" and b == nil) -- yields inside 'y'; Ok
  670. a, b = co()
  671. assert(a == "z" and b == nil) -- yields inside 'z'; Ok
  672. local a, b, c = co()
  673. assert(a and b == 10 and c == 20) -- returns from 'pcall(foo, nil)'
  674. local a, b = co() -- second foo: error in __close
  675. assert(a == "x" and b == nil) -- yields inside 'x'; Ok
  676. a, b = co()
  677. assert(a == "y" and b == nil) -- yields inside 'y'; Ok
  678. a, b = co()
  679. assert(a == "z" and b == nil) -- yields inside 'z'; Ok
  680. local st, msg = co() -- reports the error in 'y'
  681. assert(not st and msg == 21)
  682. local a, b = co() -- third foo: error in function body
  683. assert(a == "x" and b == nil) -- yields inside 'x'; Ok
  684. a, b = co()
  685. assert(a == "y" and b == nil) -- yields inside 'y'; Ok
  686. a, b = co()
  687. assert(a == "z" and b == nil) -- yields inside 'z'; Ok
  688. local st, msg = co() -- gets final error
  689. assert(not st and msg == 10 + 20)
  690. end
  691. do
  692. -- an error in a wrapped coroutine closes variables
  693. local x = false
  694. local y = false
  695. local co = coroutine.wrap(function ()
  696. local xv <close> = func2close(function () x = true end)
  697. do
  698. local yv <close> = func2close(function () y = true end)
  699. coroutine.yield(100) -- yield doesn't close variable
  700. end
  701. coroutine.yield(200) -- yield doesn't close variable
  702. error(23) -- error does
  703. end)
  704. local b = co()
  705. assert(b == 100 and not x and not y)
  706. b = co()
  707. assert(b == 200 and not x and y)
  708. local a, b = pcall(co)
  709. assert(not a and b == 23 and x and y)
  710. end
  711. do
  712. -- error in a wrapped coroutine raising errors when closing a variable
  713. local x = 0
  714. local co = coroutine.wrap(function ()
  715. local xx <close> = func2close(function (_, msg)
  716. x = x + 1;
  717. assert(string.find(msg, "@XXX"))
  718. error("@YYY")
  719. end)
  720. local xv <close> = func2close(function () x = x + 1; error("@XXX") end)
  721. coroutine.yield(100)
  722. error(200)
  723. end)
  724. assert(co() == 100); assert(x == 0)
  725. local st, msg = pcall(co); assert(x == 2)
  726. assert(not st and string.find(msg, "@YYY")) -- should get error raised
  727. local x = 0
  728. local y = 0
  729. co = coroutine.wrap(function ()
  730. local xx <close> = func2close(function (_, err)
  731. y = y + 1;
  732. assert(string.find(err, "XXX"))
  733. error("YYY")
  734. end)
  735. local xv <close> = func2close(function ()
  736. x = x + 1; error("XXX")
  737. end)
  738. coroutine.yield(100)
  739. return 200
  740. end)
  741. assert(co() == 100); assert(x == 0)
  742. local st, msg = pcall(co)
  743. assert(x == 1 and y == 1)
  744. -- should get first error raised
  745. assert(not st and string.find(msg, "%w+%.%w+:%d+: YYY"))
  746. end
  747. -- a suspended coroutine should not close its variables when collected
  748. local co
  749. co = coroutine.wrap(function()
  750. -- should not run
  751. local x <close> = func2close(function () os.exit(false) end)
  752. co = nil
  753. coroutine.yield()
  754. end)
  755. co() -- start coroutine
  756. assert(co == nil) -- eventually it will be collected
  757. collectgarbage()
  758. if rawget(_G, "T") then
  759. print("to-be-closed variables x coroutines in C")
  760. do
  761. local token = 0
  762. local count = 0
  763. local f = T.makeCfunc[[
  764. toclose 1
  765. toclose 2
  766. return .
  767. ]]
  768. local obj = func2close(function (_, msg)
  769. count = count + 1
  770. token = coroutine.yield(count, token)
  771. end)
  772. local co = coroutine.wrap(f)
  773. local ct, res = co(obj, obj, 10, 20, 30, 3) -- will return 10, 20, 30
  774. -- initial token value, after closing 2nd obj
  775. assert(ct == 1 and res == 0)
  776. -- run until yield when closing 1st obj
  777. ct, res = co(100)
  778. assert(ct == 2 and res == 100)
  779. res = {co(200)} -- run until end
  780. assert(res[1] == 10 and res[2] == 20 and res[3] == 30 and res[4] == nil)
  781. assert(token == 200)
  782. end
  783. do
  784. local f = T.makeCfunc[[
  785. toclose 1
  786. return .
  787. ]]
  788. local obj = func2close(function ()
  789. local temp
  790. local x <close> = func2close(function ()
  791. coroutine.yield(temp)
  792. return 1,2,3 -- to be ignored
  793. end)
  794. temp = coroutine.yield("closing obj")
  795. return 1,2,3 -- to be ignored
  796. end)
  797. local co = coroutine.wrap(f)
  798. local res = co(obj, 10, 30, 1) -- will return only 30
  799. assert(res == "closing obj")
  800. res = co("closing x")
  801. assert(res == "closing x")
  802. res = {co()}
  803. assert(res[1] == 30 and res[2] == nil)
  804. end
  805. do
  806. -- still cannot yield inside 'closeslot'
  807. local f = T.makeCfunc[[
  808. toclose 1
  809. closeslot 1
  810. ]]
  811. local obj = func2close(coroutine.yield)
  812. local co = coroutine.create(f)
  813. local st, msg = coroutine.resume(co, obj)
  814. assert(not st and string.find(msg, "attempt to yield across"))
  815. -- nor outside a coroutine
  816. local f = T.makeCfunc[[
  817. toclose 1
  818. ]]
  819. local st, msg = pcall(f, obj)
  820. assert(not st and string.find(msg, "attempt to yield from outside"))
  821. end
  822. end
  823. -- to-be-closed variables in generic for loops
  824. do
  825. local numopen = 0
  826. local function open (x)
  827. numopen = numopen + 1
  828. return
  829. function () -- iteraction function
  830. x = x - 1
  831. if x > 0 then return x end
  832. end,
  833. nil, -- state
  834. nil, -- control variable
  835. func2close(function () numopen = numopen - 1 end) -- closing function
  836. end
  837. local s = 0
  838. for i in open(10) do
  839. s = s + i
  840. end
  841. assert(s == 45 and numopen == 0)
  842. local s = 0
  843. for i in open(10) do
  844. if i < 5 then break end
  845. s = s + i
  846. end
  847. assert(s == 35 and numopen == 0)
  848. local s = 0
  849. for i in open(10) do
  850. for j in open(10) do
  851. if i + j < 5 then goto endloop end
  852. s = s + i
  853. end
  854. end
  855. ::endloop::
  856. assert(s == 375 and numopen == 0)
  857. end
  858. print('OK')
  859. return 5,f
  860. end -- }