瀏覽代碼

first implementation of 'lua_yieldk' (yield with continuation)

Roberto Ierusalimschy 16 年之前
父節點
當前提交
0e45ffb8e4
共有 3 個文件被更改,包括 39 次插入9 次删除
  1. 23 5
      ldo.c
  2. 12 2
      ltests.c
  3. 4 2
      lua.h

+ 23 - 5
ldo.c

@@ -1,5 +1,5 @@
 /*
 /*
-** $Id: ldo.c,v 2.65 2009/06/01 19:09:26 roberto Exp roberto $
+** $Id: ldo.c,v 2.66 2009/07/15 17:26:14 roberto Exp roberto $
 ** Stack and Call structure of Lua
 ** Stack and Call structure of Lua
 ** See Copyright Notice in lua.h
 ** See Copyright Notice in lua.h
 */
 */
@@ -418,6 +418,16 @@ static void resume (lua_State *L, void *ud) {
     if (isLua(ci))  /* yielded inside a hook? */
     if (isLua(ci))  /* yielded inside a hook? */
       luaV_execute(L);
       luaV_execute(L);
     else {  /* 'common' yield */
     else {  /* 'common' yield */
+      if (ci->u.c.k != NULL) {  /* does it have a continuation? */
+        int n;
+        ci->u.c.status = LUA_YIELD;  /* 'default' status */
+        ci->callstatus |= CIST_YIELDED;
+        ci->func = restorestack(L, ci->u.c.oldtop);
+        lua_unlock(L);
+        n = (*ci->u.c.k)(L);  /* call continuation */
+        lua_lock(L);
+        firstArg = L->top - n;
+      }
       G(L)->nCcalls--;  /* finish 'luaD_call' */
       G(L)->nCcalls--;  /* finish 'luaD_call' */
       luaD_poscall(L, firstArg);  /* finish 'luaD_precall' */
       luaD_poscall(L, firstArg);  /* finish 'luaD_precall' */
     }
     }
@@ -499,17 +509,25 @@ LUA_API int lua_resume (lua_State *L, int nargs) {
   return status;
   return status;
 }
 }
 
 
-LUA_API int lua_yield (lua_State *L, int nresults) {
+LUA_API int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k) {
+  CallInfo *ci = L->ci;
   luai_userstateyield(L, nresults);
   luai_userstateyield(L, nresults);
   lua_lock(L);
   lua_lock(L);
   if (L->nny > 0)
   if (L->nny > 0)
     luaG_runerror(L, "attempt to yield across metamethod/C-call boundary");
     luaG_runerror(L, "attempt to yield across metamethod/C-call boundary");
   L->status = LUA_YIELD;
   L->status = LUA_YIELD;
-  if (!isLua(L->ci)) {  /* not inside a hook? */
-    L->ci->func = L->top - nresults - 1;  /* protect stack slots below ??? */
+  if (isLua(ci)) {  /* inside a hook? */
+    api_check(L, k == NULL, "hooks cannot continue after yielding");
+  }
+  else {
+    if ((ci->u.c.k = k) != NULL) {  /* is there a continuation? */
+      ci->u.c.ctx = ctx;  /* save context */
+      ci->u.c.oldtop = savestack(L, ci->func);  /* save current 'func' */
+    }
+    ci->func = L->top - nresults - 1;  /* protect stack slots below */
     luaD_throw(L, LUA_YIELD);
     luaD_throw(L, LUA_YIELD);
   }
   }
-  lua_assert(L->ci->callstatus & CIST_HOOKED);  /* must be inside a hook */
+  lua_assert(ci->callstatus & CIST_HOOKED);  /* must be inside a hook */
   lua_unlock(L);
   lua_unlock(L);
   return 0;  /* otherwise, return to 'luaD_callhook' */
   return 0;  /* otherwise, return to 'luaD_callhook' */
 }
 }

+ 12 - 2
ltests.c

@@ -1,5 +1,5 @@
 /*
 /*
-** $Id: ltests.c,v 2.69 2009/08/26 17:41:26 roberto Exp roberto $
+** $Id: ltests.c,v 2.70 2009/09/09 20:44:10 roberto Exp roberto $
 ** Internal Module for Debugging of the Lua Implementation
 ** Internal Module for Debugging of the Lua Implementation
 ** See Copyright Notice in lua.h
 ** See Copyright Notice in lua.h
 */
 */
@@ -836,6 +836,8 @@ static int getnum_aux (lua_State *L, const char **pc) {
     sig = -1;
     sig = -1;
     (*pc)++;
     (*pc)++;
   }
   }
+  if (!lisdigit(cast(unsigned char, **pc)))
+    luaL_error(L, "number expected (%s)", *pc);
   while (lisdigit(cast(unsigned char, **pc))) res = res*10 + (*(*pc)++) - '0';
   while (lisdigit(cast(unsigned char, **pc))) res = res*10 + (*(*pc)++) - '0';
   return sig*res;
   return sig*res;
 }
 }
@@ -1033,6 +1035,11 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
     else if EQ("yield") {
     else if EQ("yield") {
       return lua_yield(L1, getnum);
       return lua_yield(L1, getnum);
     }
     }
+    else if EQ("yieldk") {
+      int nres = getnum;
+      int i = getnum;
+      return lua_yieldk(L1, nres, i, Cfunck);
+    }
     else if EQ("loadstring") {
     else if EQ("loadstring") {
       size_t sl;
       size_t sl;
       const char *s = luaL_checklstring(L1, getnum, &sl);
       const char *s = luaL_checklstring(L1, getnum, &sl);
@@ -1056,9 +1063,12 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
       lua_pushinteger(L1, lua_objlen(L1, i));
       lua_pushinteger(L1, lua_objlen(L1, i));
     }
     }
     else if EQ("getctx") {
     else if EQ("getctx") {
+      static const char *const codes[] = {"OK", "YIELD", "ERRRUN",
+         "ERRSYNTAX", "ERRMEM", "ERRGCMM", "ERRERR"};
+
       int i = 0;
       int i = 0;
       int s = lua_getctx(L1, &i);
       int s = lua_getctx(L1, &i);
-      lua_pushinteger(L1, s);
+      lua_pushstring(L1, codes[s]);
       lua_pushinteger(L1, i);
       lua_pushinteger(L1, i);
     }
     }
     else if EQ("checkstack") {
     else if EQ("checkstack") {

+ 4 - 2
lua.h

@@ -1,5 +1,5 @@
 /*
 /*
-** $Id: lua.h,v 1.240 2009/06/18 18:59:18 roberto Exp roberto $
+** $Id: lua.h,v 1.241 2009/07/15 17:26:14 roberto Exp roberto $
 ** Lua - An Extensible Extension Language
 ** Lua - An Extensible Extension Language
 ** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
 ** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
 ** See Copyright Notice at the end of this file
 ** See Copyright Notice at the end of this file
@@ -243,7 +243,9 @@ LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data);
 /*
 /*
 ** coroutine functions
 ** coroutine functions
 */
 */
-LUA_API int  (lua_yield) (lua_State *L, int nresults);
+LUA_API int  (lua_yieldk) (lua_State *L, int nresults, int ctx,
+                           lua_CFunction k);
+#define lua_yield(L,n)		lua_yieldk(L, (n), 0, NULL)
 LUA_API int  (lua_resume) (lua_State *L, int narg);
 LUA_API int  (lua_resume) (lua_State *L, int narg);
 LUA_API int  (lua_status) (lua_State *L);
 LUA_API int  (lua_status) (lua_State *L);