Browse Source

first implementation of coroutines

Roberto Ierusalimschy 23 năm trước cách đây
mục cha
commit
f083812c02
11 tập tin đã thay đổi với 229 bổ sung137 xóa
  1. 46 35
      lbaselib.c
  2. 1 2
      lcode.c
  3. 8 7
      ldebug.c
  4. 110 16
      ldo.c
  5. 14 5
      lopcodes.h
  6. 5 5
      lparser.c
  7. 1 0
      lstate.c
  8. 5 1
      lstate.h
  9. 9 8
      lua.h
  10. 29 57
      lvm.c
  11. 1 1
      lvm.h

+ 46 - 35
lbaselib.c

@@ -148,30 +148,6 @@ static int luaB_eventtable (lua_State *L) {
 }
 }
 
 
 
 
-static int luaB_weakmode (lua_State *L) {
-  const char *mode = luaL_check_string(L, 2);
-  luaL_check_type(L, 1, LUA_TTABLE);
-  if (*mode == '?') {
-    char buff[3];
-    char *s = buff;
-    int imode = lua_getweakmode(L, 1);
-    if (imode & LUA_WEAK_KEY) *s++ = 'k';
-    if (imode & LUA_WEAK_VALUE) *s++ = 'v';
-    *s = '\0';
-    lua_pushstring(L, buff);
-    return 1;
-  }
-  else {
-    int imode = 0;
-    if (strchr(mode, 'k')) imode |= LUA_WEAK_KEY;
-    if (strchr(mode, 'v')) imode |= LUA_WEAK_VALUE;
-    lua_pushvalue(L, 1);  /* push table */
-    lua_setweakmode(L, imode);
-    return 1;  /* return the table */
-  }
-}
-
-
 static int luaB_globals (lua_State *L) {
 static int luaB_globals (lua_State *L) {
   lua_getglobals(L);  /* value to be returned */
   lua_getglobals(L);  /* value to be returned */
   if (!lua_isnone(L, 1)) {
   if (!lua_isnone(L, 1)) {
@@ -287,6 +263,14 @@ static int luaB_loadfile (lua_State *L) {
 }
 }
 
 
 
 
+static int luaB_assert (lua_State *L) {
+  luaL_check_any(L, 1);
+  if (!lua_istrue(L, 1))
+    luaL_verror(L, "assertion failed!  %.90s", luaL_opt_string(L, 2, ""));
+  lua_settop(L, 1);
+  return 1;
+}
+
 
 
 #define LUA_PATH	"LUA_PATH"
 #define LUA_PATH	"LUA_PATH"
 
 
@@ -428,6 +412,40 @@ static int luaB_tostring (lua_State *L) {
 }
 }
 
 
 
 
+static int luaB_resume (lua_State *L) {
+  lua_State *co = (lua_State *)lua_touserdata(L, lua_upvalueindex(1));
+  lua_resume(L, co);
+  return 0;
+}
+
+
+static int luaB_coroutine (lua_State *L) {
+  lua_State *NL;
+  int ref;
+  luaL_check_type(L, 1, LUA_TFUNCTION);
+  NL = lua_newthread(L, 0);
+  if (NL == NULL) lua_error(L, "unable to create new thread");
+  /* move function from L to NL */
+  ref = lua_ref(L, 1);
+  lua_getref(NL, ref);
+  lua_unref(L, ref);
+  lua_cobegin(NL, 0);
+  lua_newuserdatabox(L, NL);
+  lua_pushcclosure(L, luaB_resume, 1);
+  return 1;
+}
+
+
+static int luaB_yield (lua_State *L) {
+  return lua_yield(L, 0);
+}
+
+
+/*
+** {======================================================
+** Auxiliar table-related functions
+*/
+
 static int luaB_foreachi (lua_State *L) {
 static int luaB_foreachi (lua_State *L) {
   int n, i;
   int n, i;
   luaL_check_type(L, 1, LUA_TTABLE);
   luaL_check_type(L, 1, LUA_TTABLE);
@@ -464,15 +482,6 @@ static int luaB_foreach (lua_State *L) {
 }
 }
 
 
 
 
-static int luaB_assert (lua_State *L) {
-  luaL_check_any(L, 1);
-  if (!lua_istrue(L, 1))
-    luaL_verror(L, "assertion failed!  %.90s", luaL_opt_string(L, 2, ""));
-  lua_settop(L, 1);
-  return 1;
-}
-
-
 static int luaB_getn (lua_State *L) {
 static int luaB_getn (lua_State *L) {
   luaL_check_type(L, 1, LUA_TTABLE);
   luaL_check_type(L, 1, LUA_TTABLE);
   lua_pushnumber(L, lua_getn(L, 1));
   lua_pushnumber(L, lua_getn(L, 1));
@@ -521,7 +530,6 @@ static int luaB_tremove (lua_State *L) {
 
 
 
 
 
 
-
 /*
 /*
 ** {======================================================
 ** {======================================================
 ** Quicksort
 ** Quicksort
@@ -627,6 +635,8 @@ static int luaB_sort (lua_State *L) {
 
 
 /* }====================================================== */
 /* }====================================================== */
 
 
+/* }====================================================== */
+
 
 
 
 
 static const luaL_reg base_funcs[] = {
 static const luaL_reg base_funcs[] = {
@@ -634,6 +644,7 @@ static const luaL_reg base_funcs[] = {
   {LUA_ERRORMESSAGE, luaB__ERRORMESSAGE},
   {LUA_ERRORMESSAGE, luaB__ERRORMESSAGE},
   {"call", luaB_call},
   {"call", luaB_call},
   {"collectgarbage", luaB_collectgarbage},
   {"collectgarbage", luaB_collectgarbage},
+  {"coroutine", luaB_coroutine},
   {"dofile", luaB_dofile},
   {"dofile", luaB_dofile},
   {"dostring", luaB_dostring},
   {"dostring", luaB_dostring},
   {"error", luaB_error},
   {"error", luaB_error},
@@ -659,7 +670,7 @@ static const luaL_reg base_funcs[] = {
   {"tinsert", luaB_tinsert},
   {"tinsert", luaB_tinsert},
   {"tremove", luaB_tremove},
   {"tremove", luaB_tremove},
   {"unpack", luaB_unpack},
   {"unpack", luaB_unpack},
-  {"weakmode", luaB_weakmode}
+  {"yield", luaB_yield}
 };
 };
 
 
 
 

+ 1 - 2
lcode.c

@@ -264,8 +264,7 @@ static int nil_constant (FuncState *fs) {
 
 
 void luaK_setcallreturns (FuncState *fs, expdesc *e, int nresults) {
 void luaK_setcallreturns (FuncState *fs, expdesc *e, int nresults) {
   if (e->k == VCALL) {  /* expression is an open function call? */
   if (e->k == VCALL) {  /* expression is an open function call? */
-    if (nresults == LUA_MULTRET) nresults = NO_REG;
-    SETARG_C(getcode(fs, e), nresults);
+    SETARG_C(getcode(fs, e), nresults+1);
     if (nresults == 1) {  /* `regular' expression? */
     if (nresults == 1) {  /* `regular' expression? */
       e->k = VNONRELOC;
       e->k = VNONRELOC;
       e->u.i.info = GETARG_A(getcode(fs, e));
       e->u.i.info = GETARG_A(getcode(fs, e));

+ 8 - 7
ldebug.c

@@ -1,5 +1,5 @@
 /*
 /*
-** $Id: ldebug.c,v 1.1 2001/11/29 22:14:34 rieru Exp rieru $
+** $Id: ldebug.c,v 1.96 2001/12/18 20:52:30 roberto Exp $
 ** Debug Interface
 ** Debug Interface
 ** See Copyright Notice in lua.h
 ** See Copyright Notice in lua.h
 */
 */
@@ -303,7 +303,7 @@ static int checkopenop (const Proto *pt, int pc) {
   switch (GET_OPCODE(i)) {
   switch (GET_OPCODE(i)) {
     case OP_CALL:
     case OP_CALL:
     case OP_RETURN: {
     case OP_RETURN: {
-      check(GETARG_B(i) == NO_REG);
+      check(GETARG_B(i) == 0);
       return 1;
       return 1;
     }
     }
     case OP_SETLISTO: return 1;
     case OP_SETLISTO: return 1;
@@ -391,10 +391,11 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) {
         break;
         break;
       }
       }
       case OP_CALL: {
       case OP_CALL: {
-        if (b != NO_REG) {
-          checkreg(pt, a+b);
+        if (b != 0) {
+          checkreg(pt, a+b-1);
         }
         }
-        if (c == NO_REG) {
+        c--;  /* c = num. returns */
+        if (c == LUA_MULTRET) {
           check(checkopenop(pt, pc));
           check(checkopenop(pt, pc));
         }
         }
         else if (c != 0)
         else if (c != 0)
@@ -403,8 +404,8 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) {
         break;
         break;
       }
       }
       case OP_RETURN: {
       case OP_RETURN: {
-        if (b != NO_REG && b != 0)
-          checkreg(pt, a+b-1);
+        b--;  /* b = num. returns */
+        if (b > 0) checkreg(pt, a+b-1);
         break;
         break;
       }
       }
       case OP_FORPREP:
       case OP_FORPREP:

+ 110 - 16
ldo.c

@@ -18,6 +18,7 @@
 #include "lgc.h"
 #include "lgc.h"
 #include "lmem.h"
 #include "lmem.h"
 #include "lobject.h"
 #include "lobject.h"
+#include "lopcodes.h"
 #include "lparser.h"
 #include "lparser.h"
 #include "lstate.h"
 #include "lstate.h"
 #include "lstring.h"
 #include "lstring.h"
@@ -112,8 +113,6 @@ void luaD_callHook (lua_State *L, lua_Hook callhook, const char *event) {
 }
 }
 
 
 
 
-#define newci(L)	((++L->ci == L->end_ci) ? growci(L) : L->ci)
-
 static CallInfo *growci (lua_State *L) {
 static CallInfo *growci (lua_State *L) {
   lua_assert(L->ci == L->end_ci);
   lua_assert(L->ci == L->end_ci);
   luaM_reallocvector(L, L->base_ci, L->size_ci, 2*L->size_ci, CallInfo);
   luaM_reallocvector(L, L->base_ci, L->size_ci, 2*L->size_ci, CallInfo);
@@ -124,9 +123,32 @@ static CallInfo *growci (lua_State *L) {
 }
 }
 
 
 
 
+static void adjust_varargs (lua_State *L, StkId base, int nfixargs) {
+  int i;
+  Table *htab;
+  TObject n, nname;
+  StkId firstvar = base + nfixargs;  /* position of first vararg */
+  if (L->top < firstvar) {
+    luaD_checkstack(L, firstvar - L->top);
+    while (L->top < firstvar)
+      setnilvalue(L->top++);
+  }
+  htab = luaH_new(L, 0, 0);
+  for (i=0; firstvar+i<L->top; i++)
+    luaH_setnum(L, htab, i+1, firstvar+i);
+  /* store counter in field `n' */
+  setnvalue(&n, i);
+  setsvalue(&nname, luaS_newliteral(L, "n"));
+  luaH_set(L, htab, &nname, &n);
+  L->top = firstvar;  /* remove elements from the stack */
+  sethvalue(L->top, htab);
+  incr_top;
+}
+
+
 StkId luaD_precall (lua_State *L, StkId func) {
 StkId luaD_precall (lua_State *L, StkId func) {
   CallInfo *ci;
   CallInfo *ci;
-  int n;
+  LClosure *cl;
   if (ttype(func) != LUA_TFUNCTION) {
   if (ttype(func) != LUA_TFUNCTION) {
     /* `func' is not a function; check the `function' tag method */
     /* `func' is not a function; check the `function' tag method */
     const TObject *tm = luaT_gettmbyobj(L, func, TM_CALL);
     const TObject *tm = luaT_gettmbyobj(L, func, TM_CALL);
@@ -135,21 +157,39 @@ StkId luaD_precall (lua_State *L, StkId func) {
     luaD_openstack(L, func);
     luaD_openstack(L, func);
     setobj(func, tm);  /* tag method is the new function to be called */
     setobj(func, tm);  /* tag method is the new function to be called */
   }
   }
-  ci = newci(L);
+  ci = ++L->ci;
+  if (L->ci == L->end_ci) ci = growci(L);
   ci->base = func+1;
   ci->base = func+1;
-  ci->savedpc = NULL;
   if (L->callhook)
   if (L->callhook)
     luaD_callHook(L, L->callhook, "call");
     luaD_callHook(L, L->callhook, "call");
-  if (!clvalue(func)->c.isC) return NULL;
-  /* if is a C function, call it */
-  luaD_checkstack(L, LUA_MINSTACK);  /* ensure minimum stack size */
-  lua_unlock(L);
+  cl = &clvalue(func)->l;
+  if (!cl->isC) {  /* Lua function? prepare its call */
+    StkId base = func+1;
+    Proto *p = cl->p;
+    ci->linehook = L->linehook;
+    ci->savedpc = p->code;  /* starting point */
+    if (p->is_vararg)  /* varargs? */
+      adjust_varargs(L, base, p->numparams);
+    if (base > L->stack_last - p->maxstacksize)
+      luaD_stackerror(L);
+    ci->top = base + p->maxstacksize;
+    while (L->top < ci->top)
+      setnilvalue(L->top++);
+    L->top = ci->top;
+    return NULL;
+  }
+  else {  /* if is a C function, call it */
+    int n;
+    ci->savedpc = NULL;
+    luaD_checkstack(L, LUA_MINSTACK);  /* ensure minimum stack size */
+    lua_unlock(L);
 #if LUA_COMPATUPVALUES
 #if LUA_COMPATUPVALUES
-  lua_pushupvalues(L);
+    lua_pushupvalues(L);
 #endif
 #endif
-  n = (*clvalue(func)->c.f)(L);  /* do the actual call */
-  lua_lock(L);
-  return L->top - n;
+    n = (*clvalue(func)->c.f)(L);  /* do the actual call */
+    lua_lock(L);
+    return L->top - n;
+  }
 }
 }
 
 
 
 
@@ -179,12 +219,60 @@ void luaD_poscall (lua_State *L, int wanted, StkId firstResult) {
 */ 
 */ 
 void luaD_call (lua_State *L, StkId func, int nResults) {
 void luaD_call (lua_State *L, StkId func, int nResults) {
   StkId firstResult = luaD_precall(L, func);
   StkId firstResult = luaD_precall(L, func);
-  if (firstResult == NULL)  /* is a Lua function? */
-    firstResult = luaV_execute(L, &clvalue(func)->l, func+1);  /* call it */
+  if (firstResult == NULL) {  /* is a Lua function? */
+    firstResult = luaV_execute(L);  /* call it */
+    if (firstResult == NULL) {
+      luaD_poscall(L, 0, L->top);
+      luaD_error(L, "attempt to `yield' across tag-method/C-call boundary");
+    }
+  }
   luaD_poscall(L, nResults, firstResult);
   luaD_poscall(L, nResults, firstResult);
 }
 }
 
 
 
 
+LUA_API void lua_cobegin (lua_State *L, int nargs) {
+  StkId func;
+  lua_lock(L);
+  func = L->top - (nargs+1);  /* coroutine main function */
+  if (luaD_precall(L, func) != NULL)
+    luaD_error(L, "coroutine started with a C function");
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_resume (lua_State *L, lua_State *co) {
+  StkId firstResult;
+  lua_lock(L);
+  if (co->ci->savedpc == NULL)  /* no activation record? */
+    luaD_error(L, "thread is dead - cannot be resumed");
+  lua_assert(co->errorJmp == NULL);
+  co->errorJmp = L->errorJmp;
+  firstResult = luaV_execute(co);
+  if (firstResult != NULL)  /* `return'? */
+    luaD_poscall(co, LUA_MULTRET, firstResult);  /* ends this coroutine */
+  else {  /* `yield' */
+    int nresults = GETARG_C(*((co->ci-1)->savedpc - 1)) - 1;
+    luaD_poscall(co, nresults, co->top);  /* complete it */
+    if (nresults >= 0) co->top = co->ci->top;
+  }
+  co->errorJmp = NULL;
+  lua_unlock(L);
+}
+
+
+LUA_API int lua_yield (lua_State *L, int nresults) {
+  CallInfo *ci;
+  int ibase;
+  lua_lock(L);
+  ci = L->ci - 1;  /* call info of calling function */
+  if (ci->pc == NULL)
+    luaD_error(L, "cannot `yield' a C function");
+  ibase = L->top - ci->base;
+  lua_unlock(L);
+  return ibase;
+}
+
+
 /*
 /*
 ** Execute a protected call.
 ** Execute a protected call.
 */
 */
@@ -330,7 +418,13 @@ static void message (lua_State *L, const char *s) {
 ** Reports an error, and jumps up to the available recovery label
 ** Reports an error, and jumps up to the available recovery label
 */
 */
 void luaD_error (lua_State *L, const char *s) {
 void luaD_error (lua_State *L, const char *s) {
-  if (s) message(L, s);
+  if (s) {
+    if (L->ci->savedpc) {  /* error in Lua function preamble? */
+      L->ci->savedpc = NULL;  /* pretend function was already running */
+      L->ci->pc = NULL;
+    }
+    message(L, s);
+  }
   luaD_breakrun(L, LUA_ERRRUN);
   luaD_breakrun(L, LUA_ERRRUN);
 }
 }
 
 

+ 14 - 5
lopcodes.h

@@ -168,8 +168,8 @@ OP_TESTGE,/*	A C	test := (R(A) >= R/K(C))			*/
 OP_TESTT,/*	A B	test := R(B); if (test) R(A) := R(B)		*/
 OP_TESTT,/*	A B	test := R(B); if (test) R(A) := R(B)		*/
 OP_TESTF,/*	A B	test := not R(B); if (test) R(A) := R(B)	*/
 OP_TESTF,/*	A B	test := not R(B); if (test) R(A) := R(B)	*/
 
 
-OP_CALL,/*	A B C	R(A), ... ,R(A+C-1) := R(A)(R(A+1), ... ,R(A+B))*/
-OP_RETURN,/*	A B	return R(A), ... ,R(A+B-1)	(see (3))	*/
+OP_CALL,/*	A B C	R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1))*/
+OP_RETURN,/*	A B	return R(A), ... ,R(A+B-2)	(see (3))	*/
 
 
 OP_FORPREP,/*	A sBc							*/
 OP_FORPREP,/*	A sBc							*/
 OP_FORLOOP,/*	A sBc							*/
 OP_FORLOOP,/*	A sBc							*/
@@ -182,6 +182,9 @@ OP_SETLISTO,/*	A Bc							*/
 
 
 OP_CLOSE,/*	A 	close all variables in the stack up to (>=) R(A)*/
 OP_CLOSE,/*	A 	close all variables in the stack up to (>=) R(A)*/
 OP_CLOSURE /*	A Bc	R(A) := closure(KPROTO[Bc], R(A), ... ,R(A+n))	*/
 OP_CLOSURE /*	A Bc	R(A) := closure(KPROTO[Bc], R(A), ... ,R(A+n))	*/
+/*----------------------------------------------------------------------
+pseudo-instructions (interruptions): cannot occur in regular code
+------------------------------------------------------------------------*/
 } OpCode;
 } OpCode;
 
 
 
 
@@ -194,11 +197,11 @@ OP_CLOSURE /*	A Bc	R(A) := closure(KPROTO[Bc], R(A), ... ,R(A+n))	*/
   (1) In the current implementation there is no `test' variable;
   (1) In the current implementation there is no `test' variable;
       instructions OP_TEST* and OP_CJMP must always occur together.
       instructions OP_TEST* and OP_CJMP must always occur together.
 
 
-  (2) In OP_CALL, if (B == NO_REG) then B = top. C is the number of returns,
-      and can be NO_REG. OP_CALL can set `top' to last_result+1, so
+  (2) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1,
+      and can be 0: OP_CALL then sets `top' to last_result+1, so
       next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use `top'.
       next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use `top'.
 
 
-  (3) In OP_RETURN, if (B == NO_REG) then return up to `top'
+  (3) In OP_RETURN, if (B == 0) then return up to `top'
 ===========================================================================*/
 ===========================================================================*/
 
 
 
 
@@ -220,6 +223,12 @@ extern const lu_byte luaP_opmodes[NUM_OPCODES];
 #define testOpMode(m, b)        (luaP_opmodes[m] & (1 << (b)))
 #define testOpMode(m, b)        (luaP_opmodes[m] & (1 << (b)))
 
 
 
 
+/*
+** constant instructions
+*/
+
+extern const Instruction luaP_yieldop;
+
 /*
 /*
 ** opcode names (only included when compiled with LUA_OPNAMES)
 ** opcode names (only included when compiled with LUA_OPNAMES)
 */
 */

+ 5 - 5
lparser.c

@@ -335,7 +335,7 @@ static void close_func (LexState *ls) {
   FuncState *fs = ls->fs;
   FuncState *fs = ls->fs;
   Proto *f = fs->f;
   Proto *f = fs->f;
   removelocalvars(ls, fs->nactloc, 0);
   removelocalvars(ls, fs->nactloc, 0);
-  luaK_codeABC(fs, OP_RETURN, 0, 0, 0);  /* final return */
+  luaK_codeABC(fs, OP_RETURN, 0, 1, 0);  /* final return */
   luaK_getlabel(fs);  /* close eventual list of pending jumps */
   luaK_getlabel(fs);  /* close eventual list of pending jumps */
   lua_assert(G(L)->roottable == fs->h);
   lua_assert(G(L)->roottable == fs->h);
   G(L)->roottable = fs->h->next;
   G(L)->roottable = fs->h->next;
@@ -449,13 +449,13 @@ static void funcargs (LexState *ls, expdesc *f) {
   lua_assert(f->k == VNONRELOC);
   lua_assert(f->k == VNONRELOC);
   base = f->u.i.info;  /* base register for call */
   base = f->u.i.info;  /* base register for call */
   if (args.k == VCALL)
   if (args.k == VCALL)
-    nparams = NO_REG;  /* open call */
+    nparams = LUA_MULTRET;  /* open call */
   else {
   else {
     if (args.k != VVOID)
     if (args.k != VVOID)
       luaK_exp2nextreg(fs, &args);  /* close last argument */
       luaK_exp2nextreg(fs, &args);  /* close last argument */
     nparams = fs->freereg - (base+1);
     nparams = fs->freereg - (base+1);
   }
   }
-  init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams, 1));
+  init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2));
   fs->freereg = base+1;  /* call remove function and arguments and leaves
   fs->freereg = base+1;  /* call remove function and arguments and leaves
                             (unless changed) one result */
                             (unless changed) one result */
 }
 }
@@ -1136,7 +1136,7 @@ static void retstat (LexState *ls) {
     if (e.k == VCALL) {
     if (e.k == VCALL) {
       luaK_setcallreturns(fs, &e, LUA_MULTRET);
       luaK_setcallreturns(fs, &e, LUA_MULTRET);
       first = fs->nactloc;
       first = fs->nactloc;
-      nret = NO_REG;  /* return all values */
+      nret = LUA_MULTRET;  /* return all values */
     }
     }
     else {
     else {
       luaK_exp2nextreg(fs, &e);  /* values must go to the `stack' */
       luaK_exp2nextreg(fs, &e);  /* values must go to the `stack' */
@@ -1144,7 +1144,7 @@ static void retstat (LexState *ls) {
       nret = fs->freereg - first;  /* return all `active' values */
       nret = fs->freereg - first;  /* return all `active' values */
     }
     }
   }
   }
-  luaK_codeABC(fs, OP_RETURN, first, nret, 0);
+  luaK_codeABC(fs, OP_RETURN, first, nret+1, 0);
   fs->freereg = fs->nactloc;  /* removes all temp values */
   fs->freereg = fs->nactloc;  /* removes all temp values */
 }
 }
 
 

+ 1 - 0
lstate.c

@@ -104,6 +104,7 @@ LUA_API lua_State *lua_newthread (lua_State *OL, int stacksize) {
     }
     }
   }
   }
   if (OL) lua_unlock(OL);
   if (OL) lua_unlock(OL);
+  lua_userstateopen(L);
   return L;
   return L;
 }
 }
 
 

+ 5 - 1
lstate.h

@@ -39,6 +39,10 @@
 #define LUA_USERSTATE
 #define LUA_USERSTATE
 #endif
 #endif
 
 
+#ifndef lua_userstateopen
+#define lua_userstateopen(l)
+#endif
+
 
 
 
 
 struct lua_longjmp;  /* defined in ldo.c */
 struct lua_longjmp;  /* defined in ldo.c */
@@ -77,8 +81,8 @@ typedef struct CallInfo {
   const Instruction *savedpc;
   const Instruction *savedpc;
   lua_Hook linehook;
   lua_Hook linehook;
   StkId	top;  /* top for this function (when it's a Lua function) */
   StkId	top;  /* top for this function (when it's a Lua function) */
-  /* extra information for debugging */
   const Instruction **pc;
   const Instruction **pc;
+  /* extra information for line tracing */
   int lastpc;  /* last pc traced */
   int lastpc;  /* last pc traced */
   int line;  /* current line */
   int line;  /* current line */
   int refi;  /* current index in `lineinfo' */
   int refi;  /* current index in `lineinfo' */

+ 9 - 8
lua.h

@@ -45,10 +45,6 @@
 #define LUA_ERRMEM	4
 #define LUA_ERRMEM	4
 #define LUA_ERRERR	5
 #define LUA_ERRERR	5
 
 
-/* weak-table modes */
-#define LUA_WEAK_KEY	1
-#define LUA_WEAK_VALUE	2
-
 
 
 typedef struct lua_State lua_State;
 typedef struct lua_State lua_State;
 
 
@@ -182,6 +178,14 @@ LUA_API int   lua_loadbuffer (lua_State *L, const char *buff, size_t size,
 LUA_API int   lua_dobuffer (lua_State *L, const char *buff, size_t size,
 LUA_API int   lua_dobuffer (lua_State *L, const char *buff, size_t size,
                             const char *name);
                             const char *name);
 
 
+
+/*
+** coroutine functions
+*/
+LUA_API void lua_cobegin (lua_State *L, int nargs);
+LUA_API int  lua_yield (lua_State *L, int nresults);
+LUA_API void lua_resume (lua_State *L, lua_State *co);
+
 /*
 /*
 ** Garbage-collection functions
 ** Garbage-collection functions
 */
 */
@@ -203,9 +207,6 @@ LUA_API void  lua_concat (lua_State *L, int n);
 LUA_API void *lua_newuserdata (lua_State *L, size_t size);
 LUA_API void *lua_newuserdata (lua_State *L, size_t size);
 LUA_API void  lua_newuserdatabox (lua_State *L, void *u);
 LUA_API void  lua_newuserdatabox (lua_State *L, void *u);
 
 
-LUA_API void  lua_setweakmode (lua_State *L, int mode);
-LUA_API int   lua_getweakmode (lua_State *L, int index);
-
 
 
 
 
 /* 
 /* 
@@ -242,7 +243,7 @@ LUA_API int   lua_getweakmode (lua_State *L, int index);
 ** compatibility macros and functions
 ** compatibility macros and functions
 */
 */
 
 
-LUA_API void lua_pushupvalues (lua_State *L);
+LUA_API int lua_pushupvalues (lua_State *L);
 
 
 #define lua_isnull	lua_isnone
 #define lua_isnull	lua_isnone
 
 

+ 29 - 57
lvm.c

@@ -254,29 +254,6 @@ void luaV_strconc (lua_State *L, int total, StkId top) {
 }
 }
 
 
 
 
-static void adjust_varargs (lua_State *L, StkId base, int nfixargs) {
-  int i;
-  Table *htab;
-  TObject n, nname;
-  StkId firstvar = base + nfixargs;  /* position of first vararg */
-  if (L->top < firstvar) {
-    luaD_checkstack(L, firstvar - L->top);
-    while (L->top < firstvar)
-      setnilvalue(L->top++);
-  }
-  htab = luaH_new(L, 0, 0);
-  for (i=0; firstvar+i<L->top; i++)
-    luaH_setnum(L, htab, i+1, firstvar+i);
-  /* store counter in field `n' */
-  setnvalue(&n, i);
-  setsvalue(&nname, luaS_newliteral(L, "n"));
-  luaH_set(L, htab, &nname, &n);
-  L->top = firstvar;  /* remove elements from the stack */
-  sethvalue(L->top, htab);
-  incr_top;
-}
-
-
 static void powOp (lua_State *L, StkId ra, StkId rb, StkId rc) {
 static void powOp (lua_State *L, StkId ra, StkId rb, StkId rc) {
   const TObject *b = rb;
   const TObject *b = rb;
   const TObject *c = rc;
   const TObject *c = rc;
@@ -307,8 +284,8 @@ static void powOp (lua_State *L, StkId ra, StkId rb, StkId rc) {
 #define RC(i)	(base+GETARG_C(i))
 #define RC(i)	(base+GETARG_C(i))
 #define RKC(i)	((GETARG_C(i) < MAXSTACK) ? \
 #define RKC(i)	((GETARG_C(i) < MAXSTACK) ? \
 			base+GETARG_C(i) : \
 			base+GETARG_C(i) : \
-			cl->p->k+GETARG_C(i)-MAXSTACK)
-#define KBc(i)	(cl->p->k+GETARG_Bc(i))
+			k+GETARG_C(i)-MAXSTACK)
+#define KBc(i)	(k+GETARG_Bc(i))
 
 
 #define Arith(op, optm)	{ \
 #define Arith(op, optm)	{ \
   const TObject *b = RB(i); const TObject *c = RKC(i);		\
   const TObject *b = RB(i); const TObject *c = RKC(i);		\
@@ -321,38 +298,26 @@ static void powOp (lua_State *L, StkId ra, StkId rb, StkId rc) {
 }
 }
 
 
 
 
-#define luaV_poscall(L,c,f,ci) \
-  if (c != NO_REG) { \
-    luaD_poscall(L, c, f); \
-    L->top = ci->top; \
-  } \
-  else { \
-    luaD_poscall(L, LUA_MULTRET, f); \
-  }
-
-
 #define dojump(pc, i)	((pc) += GETARG_sBc(i))
 #define dojump(pc, i)	((pc) += GETARG_sBc(i))
 
 
 /*
 /*
-** Executes the given Lua function. Parameters are between [base,top).
+** Executes current Lua function. Parameters are between [base,top).
 ** Returns n such that the results are between [n,top).
 ** Returns n such that the results are between [n,top).
 */
 */
-StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base) {
+StkId luaV_execute (lua_State *L) {
+  StkId base;
+  LClosure *cl;
+  TObject *k;
   const Instruction *pc;
   const Instruction *pc;
   lua_Hook linehook;
   lua_Hook linehook;
  reinit:
  reinit:
-  lua_assert(L->ci->savedpc == NULL);
+  base = L->ci->base;
+  cl = &clvalue(base - 1)->l;
+  k = cl->p->k;
+  linehook = L->ci->linehook;
   L->ci->pc = &pc;
   L->ci->pc = &pc;
-  L->ci->top = base + cl->p->maxstacksize;
-  if (cl->p->is_vararg)  /* varargs? */
-    adjust_varargs(L, base, cl->p->numparams);
-  if (base > L->stack_last - cl->p->maxstacksize)
-    luaD_stackerror(L);
-  while (L->top < L->ci->top)
-    setnilvalue(L->top++);
-  L->top = L->ci->top;
-  linehook = L->ci->linehook = L->linehook;
-  pc = cl->p->code;
+  pc = L->ci->savedpc;
+  L->ci->savedpc = NULL;
   /* main loop of interpreter */
   /* main loop of interpreter */
   for (;;) {
   for (;;) {
     const Instruction i = *pc++;
     const Instruction i = *pc++;
@@ -535,18 +500,21 @@ StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base) {
       case OP_CALL: {
       case OP_CALL: {
         StkId firstResult;
         StkId firstResult;
         int b = GETARG_B(i);
         int b = GETARG_B(i);
-        if (b != NO_REG) L->top = ra+b+1;
-        /* else previous instruction set top */
+        int nresults;
+        if (b != 0) L->top = ra+b;  /* else previous instruction set top */
+        nresults = GETARG_C(i) - 1;
         firstResult = luaD_precall(L, ra);
         firstResult = luaD_precall(L, ra);
         if (firstResult) {
         if (firstResult) {
+          if (firstResult == base) {  /* yield?? */
+            (L->ci-1)->savedpc = pc;
+            return NULL;
+          }
           /* it was a C function (`precall' called it); adjust results */
           /* it was a C function (`precall' called it); adjust results */
-          luaV_poscall(L, GETARG_C(i), firstResult, L->ci);
+          luaD_poscall(L, nresults, firstResult);
+          if (nresults >= 0) L->top = L->ci->top;
         }
         }
         else {  /* it is a Lua function: `call' it */
         else {  /* it is a Lua function: `call' it */
-          CallInfo *ci = L->ci;
-          (ci-1)->savedpc = pc;
-          base = ci->base;
-          cl = &clvalue(base - 1)->l;
+          (L->ci-1)->savedpc = pc;
           goto reinit;
           goto reinit;
         }
         }
         break;
         break;
@@ -556,19 +524,23 @@ StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base) {
         int b;
         int b;
         if (L->openupval) luaF_close(L, base);
         if (L->openupval) luaF_close(L, base);
         b = GETARG_B(i);
         b = GETARG_B(i);
-        if (b != NO_REG) L->top = ra+b;
+        if (b != 0) L->top = ra+b-1;
         ci = L->ci - 1;
         ci = L->ci - 1;
         if (ci->savedpc == NULL)
         if (ci->savedpc == NULL)
           return ra;
           return ra;
         else {  /* previous function is Lua: continue its execution */
         else {  /* previous function is Lua: continue its execution */
+          int nresults;
           lua_assert(ttype(ci->base-1) == LUA_TFUNCTION);
           lua_assert(ttype(ci->base-1) == LUA_TFUNCTION);
           base = ci->base;  /* restore previous values */
           base = ci->base;  /* restore previous values */
           linehook = ci->linehook;
           linehook = ci->linehook;
           cl = &clvalue(base - 1)->l;
           cl = &clvalue(base - 1)->l;
+          k = cl->p->k;
           pc = ci->savedpc;
           pc = ci->savedpc;
           ci->savedpc = NULL;
           ci->savedpc = NULL;
           lua_assert(GET_OPCODE(*(pc-1)) == OP_CALL);
           lua_assert(GET_OPCODE(*(pc-1)) == OP_CALL);
-          luaV_poscall(L, GETARG_C(*(pc-1)), ra, ci);
+          nresults = GETARG_C(*(pc-1)) - 1;
+          luaD_poscall(L, nresults, ra);
+          if (nresults >= 0) L->top = L->ci->top;
         }
         }
         break;
         break;
       }
       }

+ 1 - 1
lvm.h

@@ -20,7 +20,7 @@ const TObject *luaV_tonumber (const TObject *obj, TObject *n);
 int luaV_tostring (lua_State *L, TObject *obj);
 int luaV_tostring (lua_State *L, TObject *obj);
 void luaV_gettable (lua_State *L, StkId t, TObject *key, StkId res);
 void luaV_gettable (lua_State *L, StkId t, TObject *key, StkId res);
 void luaV_settable (lua_State *L, StkId t, TObject *key, StkId val);
 void luaV_settable (lua_State *L, StkId t, TObject *key, StkId val);
-StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base);
+StkId luaV_execute (lua_State *L);
 int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r);
 int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r);
 void luaV_strconc (lua_State *L, int total, StkId top);
 void luaV_strconc (lua_State *L, int total, StkId top);