github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/testdata/lua-5.3.3-tests/coroutine.lua (about)

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