coroutine.lua 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874
  1. -- $Id: coroutine.lua,v 1.42 2016/11/07 13:03:20 roberto Exp $
  2. -- See Copyright Notice in file all.lua
  3. print "testing coroutines"
  4. local debug = require'debug'
  5. local f
  6. local main, ismain = coroutine.running()
  7. assert(type(main) == "thread" and ismain)
  8. assert(not coroutine.resume(main))
  9. assert(not coroutine.isyieldable())
  10. assert(not pcall(coroutine.yield))
  11. -- trivial errors
  12. assert(not pcall(coroutine.resume, 0))
  13. assert(not pcall(coroutine.status, 0))
  14. -- tests for multiple yield/resume arguments
  15. local function eqtab (t1, t2)
  16. assert(#t1 == #t2)
  17. for i = 1, #t1 do
  18. local v = t1[i]
  19. assert(t2[i] == v)
  20. end
  21. end
  22. _G.x = nil -- declare x
  23. function foo (a, ...)
  24. local x, y = coroutine.running()
  25. assert(x == f and y == false)
  26. -- next call should not corrupt coroutine (but must fail,
  27. -- as it attempts to resume the running coroutine)
  28. assert(coroutine.resume(f) == false)
  29. assert(coroutine.status(f) == "running")
  30. local arg = {...}
  31. assert(coroutine.isyieldable())
  32. for i=1,#arg do
  33. _G.x = {coroutine.yield(table.unpack(arg[i]))}
  34. end
  35. return table.unpack(a)
  36. end
  37. f = coroutine.create(foo)
  38. assert(type(f) == "thread" and coroutine.status(f) == "suspended")
  39. assert(string.find(tostring(f), "thread"))
  40. local s,a,b,c,d
  41. s,a,b,c,d = coroutine.resume(f, {1,2,3}, {}, {1}, {'a', 'b', 'c'})
  42. assert(s and a == nil and coroutine.status(f) == "suspended")
  43. s,a,b,c,d = coroutine.resume(f)
  44. eqtab(_G.x, {})
  45. assert(s and a == 1 and b == nil)
  46. s,a,b,c,d = coroutine.resume(f, 1, 2, 3)
  47. eqtab(_G.x, {1, 2, 3})
  48. assert(s and a == 'a' and b == 'b' and c == 'c' and d == nil)
  49. s,a,b,c,d = coroutine.resume(f, "xuxu")
  50. eqtab(_G.x, {"xuxu"})
  51. assert(s and a == 1 and b == 2 and c == 3 and d == nil)
  52. assert(coroutine.status(f) == "dead")
  53. s, a = coroutine.resume(f, "xuxu")
  54. assert(not s and string.find(a, "dead") and coroutine.status(f) == "dead")
  55. -- yields in tail calls
  56. local function foo (i) return coroutine.yield(i) end
  57. f = coroutine.wrap(function ()
  58. for i=1,10 do
  59. assert(foo(i) == _G.x)
  60. end
  61. return 'a'
  62. end)
  63. for i=1,10 do _G.x = i; assert(f(i) == i) end
  64. _G.x = 'xuxu'; assert(f('xuxu') == 'a')
  65. -- recursive
  66. function pf (n, i)
  67. coroutine.yield(n)
  68. pf(n*i, i+1)
  69. end
  70. f = coroutine.wrap(pf)
  71. local s=1
  72. for i=1,10 do
  73. assert(f(1, 1) == s)
  74. s = s*i
  75. end
  76. -- sieve
  77. function gen (n)
  78. return coroutine.wrap(function ()
  79. for i=2,n do coroutine.yield(i) end
  80. end)
  81. end
  82. function filter (p, g)
  83. return coroutine.wrap(function ()
  84. while 1 do
  85. local n = g()
  86. if n == nil then return end
  87. if math.fmod(n, p) ~= 0 then coroutine.yield(n) end
  88. end
  89. end)
  90. end
  91. local x = gen(100)
  92. local a = {}
  93. while 1 do
  94. local n = x()
  95. if n == nil then break end
  96. table.insert(a, n)
  97. x = filter(n, x)
  98. end
  99. assert(#a == 25 and a[#a] == 97)
  100. x, a = nil
  101. -- yielding across C boundaries
  102. co = coroutine.wrap(function()
  103. assert(not pcall(table.sort,{1,2,3}, coroutine.yield))
  104. assert(coroutine.isyieldable())
  105. coroutine.yield(20)
  106. return 30
  107. end)
  108. assert(co() == 20)
  109. assert(co() == 30)
  110. local f = function (s, i) return coroutine.yield(i) end
  111. local f1 = coroutine.wrap(function ()
  112. return xpcall(pcall, function (...) return ... end,
  113. function ()
  114. local s = 0
  115. for i in f, nil, 1 do pcall(function () s = s + i end) end
  116. error({s})
  117. end)
  118. end)
  119. f1()
  120. for i = 1, 10 do assert(f1(i) == i) end
  121. local r1, r2, v = f1(nil)
  122. assert(r1 and not r2 and v[1] == (10 + 1)*10/2)
  123. function f (a, b) a = coroutine.yield(a); error{a + b} end
  124. function g(x) return x[1]*2 end
  125. co = coroutine.wrap(function ()
  126. coroutine.yield(xpcall(f, g, 10, 20))
  127. end)
  128. assert(co() == 10)
  129. r, msg = co(100)
  130. assert(not r and msg == 240)
  131. -- unyieldable C call
  132. do
  133. local function f (c)
  134. assert(not coroutine.isyieldable())
  135. return c .. c
  136. end
  137. local co = coroutine.wrap(function (c)
  138. assert(coroutine.isyieldable())
  139. local s = string.gsub("a", ".", f)
  140. return s
  141. end)
  142. assert(co() == "aa")
  143. end
  144. -- errors in coroutines
  145. function foo ()
  146. assert(debug.getinfo(1).currentline == debug.getinfo(foo).linedefined + 1)
  147. assert(debug.getinfo(2).currentline == debug.getinfo(goo).linedefined)
  148. coroutine.yield(3)
  149. error(foo)
  150. end
  151. function goo() foo() end
  152. x = coroutine.wrap(goo)
  153. assert(x() == 3)
  154. local a,b = pcall(x)
  155. assert(not a and b == foo)
  156. x = coroutine.create(goo)
  157. a,b = coroutine.resume(x)
  158. assert(a and b == 3)
  159. a,b = coroutine.resume(x)
  160. assert(not a and b == foo and coroutine.status(x) == "dead")
  161. a,b = coroutine.resume(x)
  162. assert(not a and string.find(b, "dead") and coroutine.status(x) == "dead")
  163. -- co-routines x for loop
  164. function all (a, n, k)
  165. if k == 0 then coroutine.yield(a)
  166. else
  167. for i=1,n do
  168. a[k] = i
  169. all(a, n, k-1)
  170. end
  171. end
  172. end
  173. local a = 0
  174. for t in coroutine.wrap(function () all({}, 5, 4) end) do
  175. a = a+1
  176. end
  177. assert(a == 5^4)
  178. -- access to locals of collected corroutines
  179. local C = {}; setmetatable(C, {__mode = "kv"})
  180. local x = coroutine.wrap (function ()
  181. local a = 10
  182. local function f () a = a+10; return a end
  183. while true do
  184. a = a+1
  185. coroutine.yield(f)
  186. end
  187. end)
  188. C[1] = x;
  189. local f = x()
  190. assert(f() == 21 and x()() == 32 and x() == f)
  191. x = nil
  192. collectgarbage()
  193. assert(C[1] == nil)
  194. assert(f() == 43 and f() == 53)
  195. -- old bug: attempt to resume itself
  196. function co_func (current_co)
  197. assert(coroutine.running() == current_co)
  198. assert(coroutine.resume(current_co) == false)
  199. coroutine.yield(10, 20)
  200. assert(coroutine.resume(current_co) == false)
  201. coroutine.yield(23)
  202. return 10
  203. end
  204. local co = coroutine.create(co_func)
  205. local a,b,c = coroutine.resume(co, co)
  206. assert(a == true and b == 10 and c == 20)
  207. a,b = coroutine.resume(co, co)
  208. assert(a == true and b == 23)
  209. a,b = coroutine.resume(co, co)
  210. assert(a == true and b == 10)
  211. assert(coroutine.resume(co, co) == false)
  212. assert(coroutine.resume(co, co) == false)
  213. -- other old bug when attempting to resume itself
  214. -- (trigger C-code assertions)
  215. do
  216. local A = coroutine.running()
  217. local B = coroutine.create(function() return coroutine.resume(A) end)
  218. local st, res = coroutine.resume(B)
  219. assert(st == true and res == false)
  220. A = coroutine.wrap(function() return pcall(A, 1) end)
  221. st, res = A()
  222. assert(not st and string.find(res, "non%-suspended"))
  223. end
  224. -- attempt to resume 'normal' coroutine
  225. local co1, co2
  226. co1 = coroutine.create(function () return co2() end)
  227. co2 = coroutine.wrap(function ()
  228. assert(coroutine.status(co1) == 'normal')
  229. assert(not coroutine.resume(co1))
  230. coroutine.yield(3)
  231. end)
  232. a,b = coroutine.resume(co1)
  233. assert(a and b == 3)
  234. assert(coroutine.status(co1) == 'dead')
  235. -- infinite recursion of coroutines
  236. a = function(a) coroutine.wrap(a)(a) end
  237. assert(not pcall(a, a))
  238. a = nil
  239. -- access to locals of erroneous coroutines
  240. local x = coroutine.create (function ()
  241. local a = 10
  242. _G.f = function () a=a+1; return a end
  243. error('x')
  244. end)
  245. assert(not coroutine.resume(x))
  246. -- overwrite previous position of local `a'
  247. assert(not coroutine.resume(x, 1, 1, 1, 1, 1, 1, 1))
  248. assert(_G.f() == 11)
  249. assert(_G.f() == 12)
  250. if not T then
  251. (Message or print)('\n >>> testC not active: skipping yield/hook tests <<<\n')
  252. else
  253. print "testing yields inside hooks"
  254. local turn
  255. function fact (t, x)
  256. assert(turn == t)
  257. if x == 0 then return 1
  258. else return x*fact(t, x-1)
  259. end
  260. end
  261. local A, B = 0, 0
  262. local x = coroutine.create(function ()
  263. T.sethook("yield 0", "", 2)
  264. A = fact("A", 6)
  265. end)
  266. local y = coroutine.create(function ()
  267. T.sethook("yield 0", "", 3)
  268. B = fact("B", 7)
  269. end)
  270. while A==0 or B==0 do -- A ~= 0 when 'x' finishes (similar for 'B','y')
  271. if A==0 then turn = "A"; assert(T.resume(x)) end
  272. if B==0 then turn = "B"; assert(T.resume(y)) end
  273. end
  274. assert(B // A == 7) -- fact(7) // fact(6)
  275. local line = debug.getinfo(1, "l").currentline + 2 -- get line number
  276. local function foo ()
  277. local x = 10 --<< this line is 'line'
  278. x = x + 10
  279. _G.XX = x
  280. end
  281. -- testing yields in line hook
  282. local co = coroutine.wrap(function ()
  283. T.sethook("setglobal X; yield 0", "l", 0); foo(); return 10 end)
  284. _G.XX = nil;
  285. _G.X = nil; co(); assert(_G.X == line)
  286. _G.X = nil; co(); assert(_G.X == line + 1)
  287. _G.X = nil; co(); assert(_G.X == line + 2 and _G.XX == nil)
  288. _G.X = nil; co(); assert(_G.X == line + 3 and _G.XX == 20)
  289. assert(co() == 10)
  290. -- testing yields in count hook
  291. co = coroutine.wrap(function ()
  292. T.sethook("yield 0", "", 1); foo(); return 10 end)
  293. _G.XX = nil;
  294. local c = 0
  295. repeat c = c + 1; local a = co() until a == 10
  296. assert(_G.XX == 20 and c >= 5)
  297. co = coroutine.wrap(function ()
  298. T.sethook("yield 0", "", 2); foo(); return 10 end)
  299. _G.XX = nil;
  300. local c = 0
  301. repeat c = c + 1; local a = co() until a == 10
  302. assert(_G.XX == 20 and c >= 5)
  303. _G.X = nil; _G.XX = nil
  304. do
  305. -- testing debug library on a coroutine suspended inside a hook
  306. -- (bug in 5.2/5.3)
  307. c = coroutine.create(function (a, ...)
  308. T.sethook("yield 0", "l") -- will yield on next two lines
  309. assert(a == 10)
  310. return ...
  311. end)
  312. assert(coroutine.resume(c, 1, 2, 3)) -- start coroutine
  313. local n,v = debug.getlocal(c, 0, 1) -- check its local
  314. assert(n == "a" and v == 1)
  315. n,v = debug.getlocal(c, 0, -1) -- check varargs
  316. assert(v == 2)
  317. n,v = debug.getlocal(c, 0, -2)
  318. assert(v == 3)
  319. assert(debug.setlocal(c, 0, 1, 10)) -- test 'setlocal'
  320. assert(debug.setlocal(c, 0, -2, 20))
  321. local t = debug.getinfo(c, 0) -- test 'getinfo'
  322. assert(t.currentline == t.linedefined + 1)
  323. assert(not debug.getinfo(c, 1)) -- no other level
  324. assert(coroutine.resume(c)) -- run next line
  325. v = {coroutine.resume(c)} -- finish coroutine
  326. assert(v[1] == true and v[2] == 2 and v[3] == 20 and v[4] == nil)
  327. assert(not coroutine.resume(c))
  328. end
  329. do
  330. -- testing debug library on last function in a suspended coroutine
  331. -- (bug in 5.2/5.3)
  332. local c = coroutine.create(function () T.testC("yield 1", 10, 20) end)
  333. local a, b = coroutine.resume(c)
  334. assert(a and b == 20)
  335. assert(debug.getinfo(c, 0).linedefined == -1)
  336. a, b = debug.getlocal(c, 0, 2)
  337. assert(b == 10)
  338. end
  339. print "testing coroutine API"
  340. -- reusing a thread
  341. assert(T.testC([[
  342. newthread # create thread
  343. pushvalue 2 # push body
  344. pushstring 'a a a' # push argument
  345. xmove 0 3 2 # move values to new thread
  346. resume -1, 1 # call it first time
  347. pushstatus
  348. xmove 3 0 0 # move results back to stack
  349. setglobal X # result
  350. setglobal Y # status
  351. pushvalue 2 # push body (to call it again)
  352. pushstring 'b b b'
  353. xmove 0 3 2
  354. resume -1, 1 # call it again
  355. pushstatus
  356. xmove 3 0 0
  357. return 1 # return result
  358. ]], function (...) return ... end) == 'b b b')
  359. assert(X == 'a a a' and Y == 'OK')
  360. -- resuming running coroutine
  361. C = coroutine.create(function ()
  362. return T.testC([[
  363. pushnum 10;
  364. pushnum 20;
  365. resume -3 2;
  366. pushstatus
  367. gettop;
  368. return 3]], C)
  369. end)
  370. local a, b, c, d = coroutine.resume(C)
  371. assert(a == true and string.find(b, "non%-suspended") and
  372. c == "ERRRUN" and d == 4)
  373. a, b, c, d = T.testC([[
  374. rawgeti R 1 # get main thread
  375. pushnum 10;
  376. pushnum 20;
  377. resume -3 2;
  378. pushstatus
  379. gettop;
  380. return 4]])
  381. assert(a == coroutine.running() and string.find(b, "non%-suspended") and
  382. c == "ERRRUN" and d == 4)
  383. -- using a main thread as a coroutine
  384. local state = T.newstate()
  385. T.loadlib(state)
  386. assert(T.doremote(state, [[
  387. coroutine = require'coroutine';
  388. X = function (x) coroutine.yield(x, 'BB'); return 'CC' end;
  389. return 'ok']]))
  390. t = table.pack(T.testC(state, [[
  391. rawgeti R 1 # get main thread
  392. pushstring 'XX'
  393. getglobal X # get function for body
  394. pushstring AA # arg
  395. resume 1 1 # 'resume' shadows previous stack!
  396. gettop
  397. setglobal T # top
  398. setglobal B # second yielded value
  399. setglobal A # fist yielded value
  400. rawgeti R 1 # get main thread
  401. pushnum 5 # arg (noise)
  402. resume 1 1 # after coroutine ends, previous stack is back
  403. pushstatus
  404. return *
  405. ]]))
  406. assert(t.n == 4 and t[2] == 'XX' and t[3] == 'CC' and t[4] == 'OK')
  407. assert(T.doremote(state, "return T") == '2')
  408. assert(T.doremote(state, "return A") == 'AA')
  409. assert(T.doremote(state, "return B") == 'BB')
  410. T.closestate(state)
  411. print'+'
  412. end
  413. -- leaving a pending coroutine open
  414. _X = coroutine.wrap(function ()
  415. local a = 10
  416. local x = function () a = a+1 end
  417. coroutine.yield()
  418. end)
  419. _X()
  420. if not _soft then
  421. -- bug (stack overflow)
  422. local j = 2^9
  423. local lim = 1000000 -- (C stack limit; assume 32-bit machine)
  424. local t = {lim - 10, lim - 5, lim - 1, lim, lim + 1}
  425. for i = 1, #t do
  426. local j = t[i]
  427. co = coroutine.create(function()
  428. local t = {}
  429. for i = 1, j do t[i] = i end
  430. return table.unpack(t)
  431. end)
  432. local r, msg = coroutine.resume(co)
  433. assert(not r)
  434. end
  435. co = nil
  436. end
  437. assert(coroutine.running() == main)
  438. print"+"
  439. print"testing yields inside metamethods"
  440. local mt = {
  441. __eq = function(a,b) coroutine.yield(nil, "eq"); return a.x == b.x end,
  442. __lt = function(a,b) coroutine.yield(nil, "lt"); return a.x < b.x end,
  443. __le = function(a,b) coroutine.yield(nil, "le"); return a - b <= 0 end,
  444. __add = function(a,b) coroutine.yield(nil, "add"); return a.x + b.x end,
  445. __sub = function(a,b) coroutine.yield(nil, "sub"); return a.x - b.x end,
  446. __mod = function(a,b) coroutine.yield(nil, "mod"); return a.x % b.x end,
  447. __unm = function(a,b) coroutine.yield(nil, "unm"); return -a.x end,
  448. __bnot = function(a,b) coroutine.yield(nil, "bnot"); return ~a.x end,
  449. __shl = function(a,b) coroutine.yield(nil, "shl"); return a.x << b.x end,
  450. __shr = function(a,b) coroutine.yield(nil, "shr"); return a.x >> b.x end,
  451. __band = function(a,b)
  452. a = type(a) == "table" and a.x or a
  453. b = type(b) == "table" and b.x or b
  454. coroutine.yield(nil, "band")
  455. return a & b
  456. end,
  457. __bor = function(a,b) coroutine.yield(nil, "bor"); return a.x | b.x end,
  458. __bxor = function(a,b) coroutine.yield(nil, "bxor"); return a.x ~ b.x end,
  459. __concat = function(a,b)
  460. coroutine.yield(nil, "concat");
  461. a = type(a) == "table" and a.x or a
  462. b = type(b) == "table" and b.x or b
  463. return a .. b
  464. end,
  465. __index = function (t,k) coroutine.yield(nil, "idx"); return t.k[k] end,
  466. __newindex = function (t,k,v) coroutine.yield(nil, "nidx"); t.k[k] = v end,
  467. }
  468. local function new (x)
  469. return setmetatable({x = x, k = {}}, mt)
  470. end
  471. local a = new(10)
  472. local b = new(12)
  473. local c = new"hello"
  474. local function run (f, t)
  475. local i = 1
  476. local c = coroutine.wrap(f)
  477. while true do
  478. local res, stat = c()
  479. if res then assert(t[i] == nil); return res, t end
  480. assert(stat == t[i])
  481. i = i + 1
  482. end
  483. end
  484. assert(run(function () if (a>=b) then return '>=' else return '<' end end,
  485. {"le", "sub"}) == "<")
  486. -- '<=' using '<'
  487. mt.__le = nil
  488. assert(run(function () if (a<=b) then return '<=' else return '>' end end,
  489. {"lt"}) == "<=")
  490. assert(run(function () if (a==b) then return '==' else return '~=' end end,
  491. {"eq"}) == "~=")
  492. assert(run(function () return a & b + a end, {"add", "band"}) == 2)
  493. assert(run(function () return a % b end, {"mod"}) == 10)
  494. assert(run(function () return ~a & b end, {"bnot", "band"}) == ~10 & 12)
  495. assert(run(function () return a | b end, {"bor"}) == 10 | 12)
  496. assert(run(function () return a ~ b end, {"bxor"}) == 10 ~ 12)
  497. assert(run(function () return a << b end, {"shl"}) == 10 << 12)
  498. assert(run(function () return a >> b end, {"shr"}) == 10 >> 12)
  499. assert(run(function () return a..b end, {"concat"}) == "1012")
  500. assert(run(function() return a .. b .. c .. a end,
  501. {"concat", "concat", "concat"}) == "1012hello10")
  502. assert(run(function() return "a" .. "b" .. a .. "c" .. c .. b .. "x" end,
  503. {"concat", "concat", "concat"}) == "ab10chello12x")
  504. do -- a few more tests for comparsion operators
  505. local mt1 = {
  506. __le = function (a,b)
  507. coroutine.yield(10)
  508. return
  509. (type(a) == "table" and a.x or a) <= (type(b) == "table" and b.x or b)
  510. end,
  511. __lt = function (a,b)
  512. coroutine.yield(10)
  513. return
  514. (type(a) == "table" and a.x or a) < (type(b) == "table" and b.x or b)
  515. end,
  516. }
  517. local mt2 = { __lt = mt1.__lt } -- no __le
  518. local function run (f)
  519. local co = coroutine.wrap(f)
  520. local res
  521. repeat
  522. res = co()
  523. until res ~= 10
  524. return res
  525. end
  526. local function test ()
  527. local a1 = setmetatable({x=1}, mt1)
  528. local a2 = setmetatable({x=2}, mt2)
  529. assert(a1 < a2)
  530. assert(a1 <= a2)
  531. assert(1 < a2)
  532. assert(1 <= a2)
  533. assert(2 > a1)
  534. assert(2 >= a2)
  535. return true
  536. end
  537. run(test)
  538. end
  539. assert(run(function ()
  540. a.BB = print
  541. return a.BB
  542. end, {"nidx", "idx"}) == print)
  543. -- getuptable & setuptable
  544. do local _ENV = _ENV
  545. f = function () AAA = BBB + 1; return AAA end
  546. end
  547. g = new(10); g.k.BBB = 10;
  548. debug.setupvalue(f, 1, g)
  549. assert(run(f, {"idx", "nidx", "idx"}) == 11)
  550. assert(g.k.AAA == 11)
  551. print"+"
  552. print"testing yields inside 'for' iterators"
  553. local f = function (s, i)
  554. if i%2 == 0 then coroutine.yield(nil, "for") end
  555. if i < s then return i + 1 end
  556. end
  557. assert(run(function ()
  558. local s = 0
  559. for i in f, 4, 0 do s = s + i end
  560. return s
  561. end, {"for", "for", "for"}) == 10)
  562. -- tests for coroutine API
  563. if T==nil then
  564. (Message or print)('\n >>> testC not active: skipping coroutine API tests <<<\n')
  565. return
  566. end
  567. print('testing coroutine API')
  568. local function apico (...)
  569. local x = {...}
  570. return coroutine.wrap(function ()
  571. return T.testC(table.unpack(x))
  572. end)
  573. end
  574. local a = {apico(
  575. [[
  576. pushstring errorcode
  577. pcallk 1 0 2;
  578. invalid command (should not arrive here)
  579. ]],
  580. [[return *]],
  581. "stackmark",
  582. error
  583. )()}
  584. assert(#a == 4 and
  585. a[3] == "stackmark" and
  586. a[4] == "errorcode" and
  587. _G.status == "ERRRUN" and
  588. _G.ctx == 2) -- 'ctx' to pcallk
  589. local co = apico(
  590. "pushvalue 2; pushnum 10; pcallk 1 2 3; invalid command;",
  591. coroutine.yield,
  592. "getglobal status; getglobal ctx; pushvalue 2; pushstring a; pcallk 1 0 4; invalid command",
  593. "getglobal status; getglobal ctx; return *")
  594. assert(co() == 10)
  595. assert(co(20, 30) == 'a')
  596. a = {co()}
  597. assert(#a == 10 and
  598. a[2] == coroutine.yield and
  599. a[5] == 20 and a[6] == 30 and
  600. a[7] == "YIELD" and a[8] == 3 and
  601. a[9] == "YIELD" and a[10] == 4)
  602. assert(not pcall(co)) -- coroutine is dead now
  603. f = T.makeCfunc("pushnum 3; pushnum 5; yield 1;")
  604. co = coroutine.wrap(function ()
  605. assert(f() == 23); assert(f() == 23); return 10
  606. end)
  607. assert(co(23,16) == 5)
  608. assert(co(23,16) == 5)
  609. assert(co(23,16) == 10)
  610. -- testing coroutines with C bodies
  611. f = T.makeCfunc([[
  612. pushnum 102
  613. yieldk 1 U2
  614. cannot be here!
  615. ]],
  616. [[ # continuation
  617. pushvalue U3 # accessing upvalues inside a continuation
  618. pushvalue U4
  619. return *
  620. ]], 23, "huu")
  621. x = coroutine.wrap(f)
  622. assert(x() == 102)
  623. eqtab({x()}, {23, "huu"})
  624. f = T.makeCfunc[[pushstring 'a'; pushnum 102; yield 2; ]]
  625. a, b, c, d = T.testC([[newthread; pushvalue 2; xmove 0 3 1; resume 3 0;
  626. pushstatus; xmove 3 0 0; resume 3 0; pushstatus;
  627. return 4; ]], f)
  628. assert(a == 'YIELD' and b == 'a' and c == 102 and d == 'OK')
  629. -- testing chain of suspendable C calls
  630. local count = 3 -- number of levels
  631. f = T.makeCfunc([[
  632. remove 1; # remove argument
  633. pushvalue U3; # get selection function
  634. call 0 1; # call it (result is 'f' or 'yield')
  635. pushstring hello # single argument for selected function
  636. pushupvalueindex 2; # index of continuation program
  637. callk 1 -1 .; # call selected function
  638. errorerror # should never arrive here
  639. ]],
  640. [[
  641. # continuation program
  642. pushnum 34 # return value
  643. return * # return all results
  644. ]],
  645. function () -- selection function
  646. count = count - 1
  647. if count == 0 then return coroutine.yield
  648. else return f
  649. end
  650. end
  651. )
  652. co = coroutine.wrap(function () return f(nil) end)
  653. assert(co() == "hello") -- argument to 'yield'
  654. a = {co()}
  655. -- three '34's (one from each pending C call)
  656. assert(#a == 3 and a[1] == a[2] and a[2] == a[3] and a[3] == 34)
  657. -- testing yields with continuations
  658. co = coroutine.wrap(function (...) return
  659. T.testC([[ # initial function
  660. yieldk 1 2
  661. cannot be here!
  662. ]],
  663. [[ # 1st continuation
  664. yieldk 0 3
  665. cannot be here!
  666. ]],
  667. [[ # 2nd continuation
  668. yieldk 0 4
  669. cannot be here!
  670. ]],
  671. [[ # 3th continuation
  672. pushvalue 6 # function which is last arg. to 'testC' here
  673. pushnum 10; pushnum 20;
  674. pcall 2 0 0 # call should throw an error and return to next line
  675. pop 1 # remove error message
  676. pushvalue 6
  677. getglobal status; getglobal ctx
  678. pcallk 2 2 5 # call should throw an error and jump to continuation
  679. cannot be here!
  680. ]],
  681. [[ # 4th (and last) continuation
  682. return *
  683. ]],
  684. -- function called by 3th continuation
  685. function (a,b) x=a; y=b; error("errmsg") end,
  686. ...
  687. )
  688. end)
  689. local a = {co(3,4,6)}
  690. assert(a[1] == 6 and a[2] == nil)
  691. a = {co()}; assert(a[1] == nil and _G.status == "YIELD" and _G.ctx == 2)
  692. a = {co()}; assert(a[1] == nil and _G.status == "YIELD" and _G.ctx == 3)
  693. a = {co(7,8)};
  694. -- original arguments
  695. assert(type(a[1]) == 'string' and type(a[2]) == 'string' and
  696. type(a[3]) == 'string' and type(a[4]) == 'string' and
  697. type(a[5]) == 'string' and type(a[6]) == 'function')
  698. -- arguments left from fist resume
  699. assert(a[7] == 3 and a[8] == 4)
  700. -- arguments to last resume
  701. assert(a[9] == 7 and a[10] == 8)
  702. -- error message and nothing more
  703. assert(a[11]:find("errmsg") and #a == 11)
  704. -- check arguments to pcallk
  705. assert(x == "YIELD" and y == 4)
  706. assert(not pcall(co)) -- coroutine should be dead
  707. -- bug in nCcalls
  708. local co = coroutine.wrap(function ()
  709. local a = {pcall(pcall,pcall,pcall,pcall,pcall,pcall,pcall,error,"hi")}
  710. return pcall(assert, table.unpack(a))
  711. end)
  712. local a = {co()}
  713. assert(a[10] == "hi")
  714. print'OK'