mudgangster

Tiny, scriptable MUD client
Log | Files | Refs | README

lcorolib.cc (3768B)


      1 /*
      2 ** $Id: lcorolib.c,v 1.10.1.1 2017/04/19 17:20:42 roberto Exp $
      3 ** Coroutine Library
      4 ** See Copyright Notice in lua.h
      5 */
      6 
      7 #define lcorolib_c
      8 #define LUA_LIB
      9 
     10 #include "lprefix.h"
     11 
     12 
     13 #include <stdlib.h>
     14 
     15 #include "lua.h"
     16 
     17 #include "lauxlib.h"
     18 #include "lualib.h"
     19 
     20 
     21 static lua_State *getco (lua_State *L) {
     22   lua_State *co = lua_tothread(L, 1);
     23   luaL_argcheck(L, co, 1, "thread expected");
     24   return co;
     25 }
     26 
     27 
     28 static int auxresume (lua_State *L, lua_State *co, int narg) {
     29   int status;
     30   if (!lua_checkstack(co, narg)) {
     31     lua_pushliteral(L, "too many arguments to resume");
     32     return -1;  /* error flag */
     33   }
     34   if (lua_status(co) == LUA_OK && lua_gettop(co) == 0) {
     35     lua_pushliteral(L, "cannot resume dead coroutine");
     36     return -1;  /* error flag */
     37   }
     38   lua_xmove(L, co, narg);
     39   status = lua_resume(co, L, narg);
     40   if (status == LUA_OK || status == LUA_YIELD) {
     41     int nres = lua_gettop(co);
     42     if (!lua_checkstack(L, nres + 1)) {
     43       lua_pop(co, nres);  /* remove results anyway */
     44       lua_pushliteral(L, "too many results to resume");
     45       return -1;  /* error flag */
     46     }
     47     lua_xmove(co, L, nres);  /* move yielded values */
     48     return nres;
     49   }
     50   else {
     51     lua_xmove(co, L, 1);  /* move error message */
     52     return -1;  /* error flag */
     53   }
     54 }
     55 
     56 
     57 static int luaB_coresume (lua_State *L) {
     58   lua_State *co = getco(L);
     59   int r;
     60   r = auxresume(L, co, lua_gettop(L) - 1);
     61   if (r < 0) {
     62     lua_pushboolean(L, 0);
     63     lua_insert(L, -2);
     64     return 2;  /* return false + error message */
     65   }
     66   else {
     67     lua_pushboolean(L, 1);
     68     lua_insert(L, -(r + 1));
     69     return r + 1;  /* return true + 'resume' returns */
     70   }
     71 }
     72 
     73 
     74 static int luaB_auxwrap (lua_State *L) {
     75   lua_State *co = lua_tothread(L, lua_upvalueindex(1));
     76   int r = auxresume(L, co, lua_gettop(L));
     77   if (r < 0) {
     78     if (lua_type(L, -1) == LUA_TSTRING) {  /* error object is a string? */
     79       luaL_where(L, 1);  /* add extra info */
     80       lua_insert(L, -2);
     81       lua_concat(L, 2);
     82     }
     83     return lua_error(L);  /* propagate error */
     84   }
     85   return r;
     86 }
     87 
     88 
     89 static int luaB_cocreate (lua_State *L) {
     90   lua_State *NL;
     91   luaL_checktype(L, 1, LUA_TFUNCTION);
     92   NL = lua_newthread(L);
     93   lua_pushvalue(L, 1);  /* move function to top */
     94   lua_xmove(L, NL, 1);  /* move function from L to NL */
     95   return 1;
     96 }
     97 
     98 
     99 static int luaB_cowrap (lua_State *L) {
    100   luaB_cocreate(L);
    101   lua_pushcclosure(L, luaB_auxwrap, 1);
    102   return 1;
    103 }
    104 
    105 
    106 static int luaB_yield (lua_State *L) {
    107   return lua_yield(L, lua_gettop(L));
    108 }
    109 
    110 
    111 static int luaB_costatus (lua_State *L) {
    112   lua_State *co = getco(L);
    113   if (L == co) lua_pushliteral(L, "running");
    114   else {
    115     switch (lua_status(co)) {
    116       case LUA_YIELD:
    117         lua_pushliteral(L, "suspended");
    118         break;
    119       case LUA_OK: {
    120         lua_Debug ar;
    121         if (lua_getstack(co, 0, &ar) > 0)  /* does it have frames? */
    122           lua_pushliteral(L, "normal");  /* it is running */
    123         else if (lua_gettop(co) == 0)
    124             lua_pushliteral(L, "dead");
    125         else
    126           lua_pushliteral(L, "suspended");  /* initial state */
    127         break;
    128       }
    129       default:  /* some error occurred */
    130         lua_pushliteral(L, "dead");
    131         break;
    132     }
    133   }
    134   return 1;
    135 }
    136 
    137 
    138 static int luaB_yieldable (lua_State *L) {
    139   lua_pushboolean(L, lua_isyieldable(L));
    140   return 1;
    141 }
    142 
    143 
    144 static int luaB_corunning (lua_State *L) {
    145   int ismain = lua_pushthread(L);
    146   lua_pushboolean(L, ismain);
    147   return 2;
    148 }
    149 
    150 
    151 static const luaL_Reg co_funcs[] = {
    152   {"create", luaB_cocreate},
    153   {"resume", luaB_coresume},
    154   {"running", luaB_corunning},
    155   {"status", luaB_costatus},
    156   {"wrap", luaB_cowrap},
    157   {"yield", luaB_yield},
    158   {"isyieldable", luaB_yieldable},
    159   {NULL, NULL}
    160 };
    161 
    162 
    163 
    164 LUAMOD_API int luaopen_coroutine (lua_State *L) {
    165   luaL_newlib(L, co_funcs);
    166   return 1;
    167 }
    168