diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2002-01-09 20:02:47 -0200 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2002-01-09 20:02:47 -0200 |
| commit | f083812c020186d0d919833100c1a0b6eda8c2c0 (patch) | |
| tree | 29c2e1d25f05af62277aab03e8e070aaa1a0d664 | |
| parent | 3533382a1ed7ba21f0233057c886be2dd8a71d92 (diff) | |
| download | lua-f083812c020186d0d919833100c1a0b6eda8c2c0.tar.gz lua-f083812c020186d0d919833100c1a0b6eda8c2c0.tar.bz2 lua-f083812c020186d0d919833100c1a0b6eda8c2c0.zip | |
first implementation of coroutines
| -rw-r--r-- | lbaselib.c | 81 | ||||
| -rw-r--r-- | lcode.c | 3 | ||||
| -rw-r--r-- | ldebug.c | 15 | ||||
| -rw-r--r-- | ldo.c | 126 | ||||
| -rw-r--r-- | lopcodes.h | 19 | ||||
| -rw-r--r-- | lparser.c | 10 | ||||
| -rw-r--r-- | lstate.c | 1 | ||||
| -rw-r--r-- | lstate.h | 6 | ||||
| -rw-r--r-- | lua.h | 17 | ||||
| -rw-r--r-- | lvm.c | 86 | ||||
| -rw-r--r-- | lvm.h | 2 |
11 files changed, 229 insertions, 137 deletions
| @@ -148,30 +148,6 @@ static int luaB_eventtable (lua_State *L) { | |||
| 148 | } | 148 | } |
| 149 | 149 | ||
| 150 | 150 | ||
| 151 | static int luaB_weakmode (lua_State *L) { | ||
| 152 | const char *mode = luaL_check_string(L, 2); | ||
| 153 | luaL_check_type(L, 1, LUA_TTABLE); | ||
| 154 | if (*mode == '?') { | ||
| 155 | char buff[3]; | ||
| 156 | char *s = buff; | ||
| 157 | int imode = lua_getweakmode(L, 1); | ||
| 158 | if (imode & LUA_WEAK_KEY) *s++ = 'k'; | ||
| 159 | if (imode & LUA_WEAK_VALUE) *s++ = 'v'; | ||
| 160 | *s = '\0'; | ||
| 161 | lua_pushstring(L, buff); | ||
| 162 | return 1; | ||
| 163 | } | ||
| 164 | else { | ||
| 165 | int imode = 0; | ||
| 166 | if (strchr(mode, 'k')) imode |= LUA_WEAK_KEY; | ||
| 167 | if (strchr(mode, 'v')) imode |= LUA_WEAK_VALUE; | ||
| 168 | lua_pushvalue(L, 1); /* push table */ | ||
| 169 | lua_setweakmode(L, imode); | ||
| 170 | return 1; /* return the table */ | ||
| 171 | } | ||
| 172 | } | ||
| 173 | |||
| 174 | |||
| 175 | static int luaB_globals (lua_State *L) { | 151 | static int luaB_globals (lua_State *L) { |
| 176 | lua_getglobals(L); /* value to be returned */ | 152 | lua_getglobals(L); /* value to be returned */ |
| 177 | if (!lua_isnone(L, 1)) { | 153 | if (!lua_isnone(L, 1)) { |
| @@ -287,6 +263,14 @@ static int luaB_loadfile (lua_State *L) { | |||
| 287 | } | 263 | } |
| 288 | 264 | ||
| 289 | 265 | ||
| 266 | static int luaB_assert (lua_State *L) { | ||
| 267 | luaL_check_any(L, 1); | ||
| 268 | if (!lua_istrue(L, 1)) | ||
| 269 | luaL_verror(L, "assertion failed! %.90s", luaL_opt_string(L, 2, "")); | ||
| 270 | lua_settop(L, 1); | ||
| 271 | return 1; | ||
| 272 | } | ||
| 273 | |||
| 290 | 274 | ||
| 291 | #define LUA_PATH "LUA_PATH" | 275 | #define LUA_PATH "LUA_PATH" |
| 292 | 276 | ||
| @@ -428,6 +412,40 @@ static int luaB_tostring (lua_State *L) { | |||
| 428 | } | 412 | } |
| 429 | 413 | ||
| 430 | 414 | ||
| 415 | static int luaB_resume (lua_State *L) { | ||
| 416 | lua_State *co = (lua_State *)lua_touserdata(L, lua_upvalueindex(1)); | ||
| 417 | lua_resume(L, co); | ||
| 418 | return 0; | ||
| 419 | } | ||
| 420 | |||
| 421 | |||
| 422 | static int luaB_coroutine (lua_State *L) { | ||
| 423 | lua_State *NL; | ||
| 424 | int ref; | ||
| 425 | luaL_check_type(L, 1, LUA_TFUNCTION); | ||
| 426 | NL = lua_newthread(L, 0); | ||
| 427 | if (NL == NULL) lua_error(L, "unable to create new thread"); | ||
| 428 | /* move function from L to NL */ | ||
| 429 | ref = lua_ref(L, 1); | ||
| 430 | lua_getref(NL, ref); | ||
| 431 | lua_unref(L, ref); | ||
| 432 | lua_cobegin(NL, 0); | ||
| 433 | lua_newuserdatabox(L, NL); | ||
| 434 | lua_pushcclosure(L, luaB_resume, 1); | ||
| 435 | return 1; | ||
| 436 | } | ||
| 437 | |||
| 438 | |||
| 439 | static int luaB_yield (lua_State *L) { | ||
| 440 | return lua_yield(L, 0); | ||
| 441 | } | ||
| 442 | |||
| 443 | |||
| 444 | /* | ||
| 445 | ** {====================================================== | ||
| 446 | ** Auxiliar table-related functions | ||
| 447 | */ | ||
| 448 | |||
| 431 | static int luaB_foreachi (lua_State *L) { | 449 | static int luaB_foreachi (lua_State *L) { |
| 432 | int n, i; | 450 | int n, i; |
| 433 | luaL_check_type(L, 1, LUA_TTABLE); | 451 | luaL_check_type(L, 1, LUA_TTABLE); |
| @@ -464,15 +482,6 @@ static int luaB_foreach (lua_State *L) { | |||
| 464 | } | 482 | } |
| 465 | 483 | ||
| 466 | 484 | ||
| 467 | static int luaB_assert (lua_State *L) { | ||
| 468 | luaL_check_any(L, 1); | ||
| 469 | if (!lua_istrue(L, 1)) | ||
| 470 | luaL_verror(L, "assertion failed! %.90s", luaL_opt_string(L, 2, "")); | ||
| 471 | lua_settop(L, 1); | ||
| 472 | return 1; | ||
| 473 | } | ||
| 474 | |||
| 475 | |||
| 476 | static int luaB_getn (lua_State *L) { | 485 | static int luaB_getn (lua_State *L) { |
| 477 | luaL_check_type(L, 1, LUA_TTABLE); | 486 | luaL_check_type(L, 1, LUA_TTABLE); |
| 478 | lua_pushnumber(L, lua_getn(L, 1)); | 487 | lua_pushnumber(L, lua_getn(L, 1)); |
| @@ -521,7 +530,6 @@ static int luaB_tremove (lua_State *L) { | |||
| 521 | 530 | ||
| 522 | 531 | ||
| 523 | 532 | ||
| 524 | |||
| 525 | /* | 533 | /* |
| 526 | ** {====================================================== | 534 | ** {====================================================== |
| 527 | ** Quicksort | 535 | ** Quicksort |
| @@ -627,6 +635,8 @@ static int luaB_sort (lua_State *L) { | |||
| 627 | 635 | ||
| 628 | /* }====================================================== */ | 636 | /* }====================================================== */ |
| 629 | 637 | ||
| 638 | /* }====================================================== */ | ||
| 639 | |||
| 630 | 640 | ||
| 631 | 641 | ||
| 632 | static const luaL_reg base_funcs[] = { | 642 | static const luaL_reg base_funcs[] = { |
| @@ -634,6 +644,7 @@ static const luaL_reg base_funcs[] = { | |||
| 634 | {LUA_ERRORMESSAGE, luaB__ERRORMESSAGE}, | 644 | {LUA_ERRORMESSAGE, luaB__ERRORMESSAGE}, |
| 635 | {"call", luaB_call}, | 645 | {"call", luaB_call}, |
| 636 | {"collectgarbage", luaB_collectgarbage}, | 646 | {"collectgarbage", luaB_collectgarbage}, |
| 647 | {"coroutine", luaB_coroutine}, | ||
| 637 | {"dofile", luaB_dofile}, | 648 | {"dofile", luaB_dofile}, |
| 638 | {"dostring", luaB_dostring}, | 649 | {"dostring", luaB_dostring}, |
| 639 | {"error", luaB_error}, | 650 | {"error", luaB_error}, |
| @@ -659,7 +670,7 @@ static const luaL_reg base_funcs[] = { | |||
| 659 | {"tinsert", luaB_tinsert}, | 670 | {"tinsert", luaB_tinsert}, |
| 660 | {"tremove", luaB_tremove}, | 671 | {"tremove", luaB_tremove}, |
| 661 | {"unpack", luaB_unpack}, | 672 | {"unpack", luaB_unpack}, |
| 662 | {"weakmode", luaB_weakmode} | 673 | {"yield", luaB_yield} |
| 663 | }; | 674 | }; |
| 664 | 675 | ||
| 665 | 676 | ||
| @@ -264,8 +264,7 @@ static int nil_constant (FuncState *fs) { | |||
| 264 | 264 | ||
| 265 | void luaK_setcallreturns (FuncState *fs, expdesc *e, int nresults) { | 265 | void luaK_setcallreturns (FuncState *fs, expdesc *e, int nresults) { |
| 266 | if (e->k == VCALL) { /* expression is an open function call? */ | 266 | if (e->k == VCALL) { /* expression is an open function call? */ |
| 267 | if (nresults == LUA_MULTRET) nresults = NO_REG; | 267 | SETARG_C(getcode(fs, e), nresults+1); |
| 268 | SETARG_C(getcode(fs, e), nresults); | ||
| 269 | if (nresults == 1) { /* `regular' expression? */ | 268 | if (nresults == 1) { /* `regular' expression? */ |
| 270 | e->k = VNONRELOC; | 269 | e->k = VNONRELOC; |
| 271 | e->u.i.info = GETARG_A(getcode(fs, e)); | 270 | e->u.i.info = GETARG_A(getcode(fs, e)); |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ldebug.c,v 1.1 2001/11/29 22:14:34 rieru Exp rieru $ | 2 | ** $Id: ldebug.c,v 1.96 2001/12/18 20:52:30 roberto Exp $ |
| 3 | ** Debug Interface | 3 | ** Debug Interface |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -303,7 +303,7 @@ static int checkopenop (const Proto *pt, int pc) { | |||
| 303 | switch (GET_OPCODE(i)) { | 303 | switch (GET_OPCODE(i)) { |
| 304 | case OP_CALL: | 304 | case OP_CALL: |
| 305 | case OP_RETURN: { | 305 | case OP_RETURN: { |
| 306 | check(GETARG_B(i) == NO_REG); | 306 | check(GETARG_B(i) == 0); |
| 307 | return 1; | 307 | return 1; |
| 308 | } | 308 | } |
| 309 | case OP_SETLISTO: return 1; | 309 | case OP_SETLISTO: return 1; |
| @@ -391,10 +391,11 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { | |||
| 391 | break; | 391 | break; |
| 392 | } | 392 | } |
| 393 | case OP_CALL: { | 393 | case OP_CALL: { |
| 394 | if (b != NO_REG) { | 394 | if (b != 0) { |
| 395 | checkreg(pt, a+b); | 395 | checkreg(pt, a+b-1); |
| 396 | } | 396 | } |
| 397 | if (c == NO_REG) { | 397 | c--; /* c = num. returns */ |
| 398 | if (c == LUA_MULTRET) { | ||
| 398 | check(checkopenop(pt, pc)); | 399 | check(checkopenop(pt, pc)); |
| 399 | } | 400 | } |
| 400 | else if (c != 0) | 401 | else if (c != 0) |
| @@ -403,8 +404,8 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { | |||
| 403 | break; | 404 | break; |
| 404 | } | 405 | } |
| 405 | case OP_RETURN: { | 406 | case OP_RETURN: { |
| 406 | if (b != NO_REG && b != 0) | 407 | b--; /* b = num. returns */ |
| 407 | checkreg(pt, a+b-1); | 408 | if (b > 0) checkreg(pt, a+b-1); |
| 408 | break; | 409 | break; |
| 409 | } | 410 | } |
| 410 | case OP_FORPREP: | 411 | case OP_FORPREP: |
| @@ -18,6 +18,7 @@ | |||
| 18 | #include "lgc.h" | 18 | #include "lgc.h" |
| 19 | #include "lmem.h" | 19 | #include "lmem.h" |
| 20 | #include "lobject.h" | 20 | #include "lobject.h" |
| 21 | #include "lopcodes.h" | ||
| 21 | #include "lparser.h" | 22 | #include "lparser.h" |
| 22 | #include "lstate.h" | 23 | #include "lstate.h" |
| 23 | #include "lstring.h" | 24 | #include "lstring.h" |
| @@ -112,8 +113,6 @@ void luaD_callHook (lua_State *L, lua_Hook callhook, const char *event) { | |||
| 112 | } | 113 | } |
| 113 | 114 | ||
| 114 | 115 | ||
| 115 | #define newci(L) ((++L->ci == L->end_ci) ? growci(L) : L->ci) | ||
| 116 | |||
| 117 | static CallInfo *growci (lua_State *L) { | 116 | static CallInfo *growci (lua_State *L) { |
| 118 | lua_assert(L->ci == L->end_ci); | 117 | lua_assert(L->ci == L->end_ci); |
| 119 | luaM_reallocvector(L, L->base_ci, L->size_ci, 2*L->size_ci, CallInfo); | 118 | luaM_reallocvector(L, L->base_ci, L->size_ci, 2*L->size_ci, CallInfo); |
| @@ -124,9 +123,32 @@ static CallInfo *growci (lua_State *L) { | |||
| 124 | } | 123 | } |
| 125 | 124 | ||
| 126 | 125 | ||
| 126 | static void adjust_varargs (lua_State *L, StkId base, int nfixargs) { | ||
| 127 | int i; | ||
| 128 | Table *htab; | ||
| 129 | TObject n, nname; | ||
| 130 | StkId firstvar = base + nfixargs; /* position of first vararg */ | ||
| 131 | if (L->top < firstvar) { | ||
| 132 | luaD_checkstack(L, firstvar - L->top); | ||
| 133 | while (L->top < firstvar) | ||
| 134 | setnilvalue(L->top++); | ||
| 135 | } | ||
| 136 | htab = luaH_new(L, 0, 0); | ||
| 137 | for (i=0; firstvar+i<L->top; i++) | ||
| 138 | luaH_setnum(L, htab, i+1, firstvar+i); | ||
| 139 | /* store counter in field `n' */ | ||
| 140 | setnvalue(&n, i); | ||
| 141 | setsvalue(&nname, luaS_newliteral(L, "n")); | ||
| 142 | luaH_set(L, htab, &nname, &n); | ||
| 143 | L->top = firstvar; /* remove elements from the stack */ | ||
| 144 | sethvalue(L->top, htab); | ||
| 145 | incr_top; | ||
| 146 | } | ||
| 147 | |||
| 148 | |||
| 127 | StkId luaD_precall (lua_State *L, StkId func) { | 149 | StkId luaD_precall (lua_State *L, StkId func) { |
| 128 | CallInfo *ci; | 150 | CallInfo *ci; |
| 129 | int n; | 151 | LClosure *cl; |
| 130 | if (ttype(func) != LUA_TFUNCTION) { | 152 | if (ttype(func) != LUA_TFUNCTION) { |
| 131 | /* `func' is not a function; check the `function' tag method */ | 153 | /* `func' is not a function; check the `function' tag method */ |
| 132 | const TObject *tm = luaT_gettmbyobj(L, func, TM_CALL); | 154 | const TObject *tm = luaT_gettmbyobj(L, func, TM_CALL); |
| @@ -135,21 +157,39 @@ StkId luaD_precall (lua_State *L, StkId func) { | |||
| 135 | luaD_openstack(L, func); | 157 | luaD_openstack(L, func); |
| 136 | setobj(func, tm); /* tag method is the new function to be called */ | 158 | setobj(func, tm); /* tag method is the new function to be called */ |
| 137 | } | 159 | } |
| 138 | ci = newci(L); | 160 | ci = ++L->ci; |
| 161 | if (L->ci == L->end_ci) ci = growci(L); | ||
| 139 | ci->base = func+1; | 162 | ci->base = func+1; |
| 140 | ci->savedpc = NULL; | ||
| 141 | if (L->callhook) | 163 | if (L->callhook) |
| 142 | luaD_callHook(L, L->callhook, "call"); | 164 | luaD_callHook(L, L->callhook, "call"); |
| 143 | if (!clvalue(func)->c.isC) return NULL; | 165 | cl = &clvalue(func)->l; |
| 144 | /* if is a C function, call it */ | 166 | if (!cl->isC) { /* Lua function? prepare its call */ |
| 145 | luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ | 167 | StkId base = func+1; |
| 146 | lua_unlock(L); | 168 | Proto *p = cl->p; |
| 169 | ci->linehook = L->linehook; | ||
| 170 | ci->savedpc = p->code; /* starting point */ | ||
| 171 | if (p->is_vararg) /* varargs? */ | ||
| 172 | adjust_varargs(L, base, p->numparams); | ||
| 173 | if (base > L->stack_last - p->maxstacksize) | ||
| 174 | luaD_stackerror(L); | ||
| 175 | ci->top = base + p->maxstacksize; | ||
| 176 | while (L->top < ci->top) | ||
| 177 | setnilvalue(L->top++); | ||
| 178 | L->top = ci->top; | ||
| 179 | return NULL; | ||
| 180 | } | ||
| 181 | else { /* if is a C function, call it */ | ||
| 182 | int n; | ||
| 183 | ci->savedpc = NULL; | ||
| 184 | luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ | ||
| 185 | lua_unlock(L); | ||
| 147 | #if LUA_COMPATUPVALUES | 186 | #if LUA_COMPATUPVALUES |
| 148 | lua_pushupvalues(L); | 187 | lua_pushupvalues(L); |
| 149 | #endif | 188 | #endif |
| 150 | n = (*clvalue(func)->c.f)(L); /* do the actual call */ | 189 | n = (*clvalue(func)->c.f)(L); /* do the actual call */ |
| 151 | lua_lock(L); | 190 | lua_lock(L); |
| 152 | return L->top - n; | 191 | return L->top - n; |
| 192 | } | ||
| 153 | } | 193 | } |
| 154 | 194 | ||
| 155 | 195 | ||
| @@ -179,12 +219,60 @@ void luaD_poscall (lua_State *L, int wanted, StkId firstResult) { | |||
| 179 | */ | 219 | */ |
| 180 | void luaD_call (lua_State *L, StkId func, int nResults) { | 220 | void luaD_call (lua_State *L, StkId func, int nResults) { |
| 181 | StkId firstResult = luaD_precall(L, func); | 221 | StkId firstResult = luaD_precall(L, func); |
| 182 | if (firstResult == NULL) /* is a Lua function? */ | 222 | if (firstResult == NULL) { /* is a Lua function? */ |
| 183 | firstResult = luaV_execute(L, &clvalue(func)->l, func+1); /* call it */ | 223 | firstResult = luaV_execute(L); /* call it */ |
| 224 | if (firstResult == NULL) { | ||
| 225 | luaD_poscall(L, 0, L->top); | ||
| 226 | luaD_error(L, "attempt to `yield' across tag-method/C-call boundary"); | ||
| 227 | } | ||
| 228 | } | ||
| 184 | luaD_poscall(L, nResults, firstResult); | 229 | luaD_poscall(L, nResults, firstResult); |
| 185 | } | 230 | } |
| 186 | 231 | ||
| 187 | 232 | ||
| 233 | LUA_API void lua_cobegin (lua_State *L, int nargs) { | ||
| 234 | StkId func; | ||
| 235 | lua_lock(L); | ||
| 236 | func = L->top - (nargs+1); /* coroutine main function */ | ||
| 237 | if (luaD_precall(L, func) != NULL) | ||
| 238 | luaD_error(L, "coroutine started with a C function"); | ||
| 239 | lua_unlock(L); | ||
| 240 | } | ||
| 241 | |||
| 242 | |||
| 243 | LUA_API void lua_resume (lua_State *L, lua_State *co) { | ||
| 244 | StkId firstResult; | ||
| 245 | lua_lock(L); | ||
| 246 | if (co->ci->savedpc == NULL) /* no activation record? */ | ||
| 247 | luaD_error(L, "thread is dead - cannot be resumed"); | ||
| 248 | lua_assert(co->errorJmp == NULL); | ||
| 249 | co->errorJmp = L->errorJmp; | ||
| 250 | firstResult = luaV_execute(co); | ||
| 251 | if (firstResult != NULL) /* `return'? */ | ||
| 252 | luaD_poscall(co, LUA_MULTRET, firstResult); /* ends this coroutine */ | ||
| 253 | else { /* `yield' */ | ||
| 254 | int nresults = GETARG_C(*((co->ci-1)->savedpc - 1)) - 1; | ||
| 255 | luaD_poscall(co, nresults, co->top); /* complete it */ | ||
| 256 | if (nresults >= 0) co->top = co->ci->top; | ||
| 257 | } | ||
| 258 | co->errorJmp = NULL; | ||
| 259 | lua_unlock(L); | ||
| 260 | } | ||
| 261 | |||
| 262 | |||
| 263 | LUA_API int lua_yield (lua_State *L, int nresults) { | ||
| 264 | CallInfo *ci; | ||
| 265 | int ibase; | ||
| 266 | lua_lock(L); | ||
| 267 | ci = L->ci - 1; /* call info of calling function */ | ||
| 268 | if (ci->pc == NULL) | ||
| 269 | luaD_error(L, "cannot `yield' a C function"); | ||
| 270 | ibase = L->top - ci->base; | ||
| 271 | lua_unlock(L); | ||
| 272 | return ibase; | ||
| 273 | } | ||
| 274 | |||
| 275 | |||
| 188 | /* | 276 | /* |
| 189 | ** Execute a protected call. | 277 | ** Execute a protected call. |
| 190 | */ | 278 | */ |
| @@ -330,7 +418,13 @@ static void message (lua_State *L, const char *s) { | |||
| 330 | ** Reports an error, and jumps up to the available recovery label | 418 | ** Reports an error, and jumps up to the available recovery label |
| 331 | */ | 419 | */ |
| 332 | void luaD_error (lua_State *L, const char *s) { | 420 | void luaD_error (lua_State *L, const char *s) { |
| 333 | if (s) message(L, s); | 421 | if (s) { |
| 422 | if (L->ci->savedpc) { /* error in Lua function preamble? */ | ||
| 423 | L->ci->savedpc = NULL; /* pretend function was already running */ | ||
| 424 | L->ci->pc = NULL; | ||
| 425 | } | ||
| 426 | message(L, s); | ||
| 427 | } | ||
| 334 | luaD_breakrun(L, LUA_ERRRUN); | 428 | luaD_breakrun(L, LUA_ERRRUN); |
| 335 | } | 429 | } |
| 336 | 430 | ||
| @@ -168,8 +168,8 @@ OP_TESTGE,/* A C test := (R(A) >= R/K(C)) */ | |||
| 168 | OP_TESTT,/* A B test := R(B); if (test) R(A) := R(B) */ | 168 | OP_TESTT,/* A B test := R(B); if (test) R(A) := R(B) */ |
| 169 | OP_TESTF,/* A B test := not R(B); if (test) R(A) := R(B) */ | 169 | OP_TESTF,/* A B test := not R(B); if (test) R(A) := R(B) */ |
| 170 | 170 | ||
| 171 | OP_CALL,/* A B C R(A), ... ,R(A+C-1) := R(A)(R(A+1), ... ,R(A+B))*/ | 171 | OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1))*/ |
| 172 | OP_RETURN,/* A B return R(A), ... ,R(A+B-1) (see (3)) */ | 172 | OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see (3)) */ |
| 173 | 173 | ||
| 174 | OP_FORPREP,/* A sBc */ | 174 | OP_FORPREP,/* A sBc */ |
| 175 | OP_FORLOOP,/* A sBc */ | 175 | OP_FORLOOP,/* A sBc */ |
| @@ -182,6 +182,9 @@ OP_SETLISTO,/* A Bc */ | |||
| 182 | 182 | ||
| 183 | OP_CLOSE,/* A close all variables in the stack up to (>=) R(A)*/ | 183 | OP_CLOSE,/* A close all variables in the stack up to (>=) R(A)*/ |
| 184 | OP_CLOSURE /* A Bc R(A) := closure(KPROTO[Bc], R(A), ... ,R(A+n)) */ | 184 | OP_CLOSURE /* A Bc R(A) := closure(KPROTO[Bc], R(A), ... ,R(A+n)) */ |
| 185 | /*---------------------------------------------------------------------- | ||
| 186 | pseudo-instructions (interruptions): cannot occur in regular code | ||
| 187 | ------------------------------------------------------------------------*/ | ||
| 185 | } OpCode; | 188 | } OpCode; |
| 186 | 189 | ||
| 187 | 190 | ||
| @@ -194,11 +197,11 @@ OP_CLOSURE /* A Bc R(A) := closure(KPROTO[Bc], R(A), ... ,R(A+n)) */ | |||
| 194 | (1) In the current implementation there is no `test' variable; | 197 | (1) In the current implementation there is no `test' variable; |
| 195 | instructions OP_TEST* and OP_CJMP must always occur together. | 198 | instructions OP_TEST* and OP_CJMP must always occur together. |
| 196 | 199 | ||
| 197 | (2) In OP_CALL, if (B == NO_REG) then B = top. C is the number of returns, | 200 | (2) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1, |
| 198 | and can be NO_REG. OP_CALL can set `top' to last_result+1, so | 201 | and can be 0: OP_CALL then sets `top' to last_result+1, so |
| 199 | next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use `top'. | 202 | next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use `top'. |
| 200 | 203 | ||
| 201 | (3) In OP_RETURN, if (B == NO_REG) then return up to `top' | 204 | (3) In OP_RETURN, if (B == 0) then return up to `top' |
| 202 | ===========================================================================*/ | 205 | ===========================================================================*/ |
| 203 | 206 | ||
| 204 | 207 | ||
| @@ -221,6 +224,12 @@ extern const lu_byte luaP_opmodes[NUM_OPCODES]; | |||
| 221 | 224 | ||
| 222 | 225 | ||
| 223 | /* | 226 | /* |
| 227 | ** constant instructions | ||
| 228 | */ | ||
| 229 | |||
| 230 | extern const Instruction luaP_yieldop; | ||
| 231 | |||
| 232 | /* | ||
| 224 | ** opcode names (only included when compiled with LUA_OPNAMES) | 233 | ** opcode names (only included when compiled with LUA_OPNAMES) |
| 225 | */ | 234 | */ |
| 226 | extern const char *const luaP_opnames[]; | 235 | extern const char *const luaP_opnames[]; |
| @@ -335,7 +335,7 @@ static void close_func (LexState *ls) { | |||
| 335 | FuncState *fs = ls->fs; | 335 | FuncState *fs = ls->fs; |
| 336 | Proto *f = fs->f; | 336 | Proto *f = fs->f; |
| 337 | removelocalvars(ls, fs->nactloc, 0); | 337 | removelocalvars(ls, fs->nactloc, 0); |
| 338 | luaK_codeABC(fs, OP_RETURN, 0, 0, 0); /* final return */ | 338 | luaK_codeABC(fs, OP_RETURN, 0, 1, 0); /* final return */ |
| 339 | luaK_getlabel(fs); /* close eventual list of pending jumps */ | 339 | luaK_getlabel(fs); /* close eventual list of pending jumps */ |
| 340 | lua_assert(G(L)->roottable == fs->h); | 340 | lua_assert(G(L)->roottable == fs->h); |
| 341 | G(L)->roottable = fs->h->next; | 341 | G(L)->roottable = fs->h->next; |
| @@ -449,13 +449,13 @@ static void funcargs (LexState *ls, expdesc *f) { | |||
| 449 | lua_assert(f->k == VNONRELOC); | 449 | lua_assert(f->k == VNONRELOC); |
| 450 | base = f->u.i.info; /* base register for call */ | 450 | base = f->u.i.info; /* base register for call */ |
| 451 | if (args.k == VCALL) | 451 | if (args.k == VCALL) |
| 452 | nparams = NO_REG; /* open call */ | 452 | nparams = LUA_MULTRET; /* open call */ |
| 453 | else { | 453 | else { |
| 454 | if (args.k != VVOID) | 454 | if (args.k != VVOID) |
| 455 | luaK_exp2nextreg(fs, &args); /* close last argument */ | 455 | luaK_exp2nextreg(fs, &args); /* close last argument */ |
| 456 | nparams = fs->freereg - (base+1); | 456 | nparams = fs->freereg - (base+1); |
| 457 | } | 457 | } |
| 458 | init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams, 1)); | 458 | init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2)); |
| 459 | fs->freereg = base+1; /* call remove function and arguments and leaves | 459 | fs->freereg = base+1; /* call remove function and arguments and leaves |
| 460 | (unless changed) one result */ | 460 | (unless changed) one result */ |
| 461 | } | 461 | } |
| @@ -1136,7 +1136,7 @@ static void retstat (LexState *ls) { | |||
| 1136 | if (e.k == VCALL) { | 1136 | if (e.k == VCALL) { |
| 1137 | luaK_setcallreturns(fs, &e, LUA_MULTRET); | 1137 | luaK_setcallreturns(fs, &e, LUA_MULTRET); |
| 1138 | first = fs->nactloc; | 1138 | first = fs->nactloc; |
| 1139 | nret = NO_REG; /* return all values */ | 1139 | nret = LUA_MULTRET; /* return all values */ |
| 1140 | } | 1140 | } |
| 1141 | else { | 1141 | else { |
| 1142 | luaK_exp2nextreg(fs, &e); /* values must go to the `stack' */ | 1142 | luaK_exp2nextreg(fs, &e); /* values must go to the `stack' */ |
| @@ -1144,7 +1144,7 @@ static void retstat (LexState *ls) { | |||
| 1144 | nret = fs->freereg - first; /* return all `active' values */ | 1144 | nret = fs->freereg - first; /* return all `active' values */ |
| 1145 | } | 1145 | } |
| 1146 | } | 1146 | } |
| 1147 | luaK_codeABC(fs, OP_RETURN, first, nret, 0); | 1147 | luaK_codeABC(fs, OP_RETURN, first, nret+1, 0); |
| 1148 | fs->freereg = fs->nactloc; /* removes all temp values */ | 1148 | fs->freereg = fs->nactloc; /* removes all temp values */ |
| 1149 | } | 1149 | } |
| 1150 | 1150 | ||
| @@ -104,6 +104,7 @@ LUA_API lua_State *lua_newthread (lua_State *OL, int stacksize) { | |||
| 104 | } | 104 | } |
| 105 | } | 105 | } |
| 106 | if (OL) lua_unlock(OL); | 106 | if (OL) lua_unlock(OL); |
| 107 | lua_userstateopen(L); | ||
| 107 | return L; | 108 | return L; |
| 108 | } | 109 | } |
| 109 | 110 | ||
| @@ -39,6 +39,10 @@ | |||
| 39 | #define LUA_USERSTATE | 39 | #define LUA_USERSTATE |
| 40 | #endif | 40 | #endif |
| 41 | 41 | ||
| 42 | #ifndef lua_userstateopen | ||
| 43 | #define lua_userstateopen(l) | ||
| 44 | #endif | ||
| 45 | |||
| 42 | 46 | ||
| 43 | 47 | ||
| 44 | struct lua_longjmp; /* defined in ldo.c */ | 48 | struct lua_longjmp; /* defined in ldo.c */ |
| @@ -77,8 +81,8 @@ typedef struct CallInfo { | |||
| 77 | const Instruction *savedpc; | 81 | const Instruction *savedpc; |
| 78 | lua_Hook linehook; | 82 | lua_Hook linehook; |
| 79 | StkId top; /* top for this function (when it's a Lua function) */ | 83 | StkId top; /* top for this function (when it's a Lua function) */ |
| 80 | /* extra information for debugging */ | ||
| 81 | const Instruction **pc; | 84 | const Instruction **pc; |
| 85 | /* extra information for line tracing */ | ||
| 82 | int lastpc; /* last pc traced */ | 86 | int lastpc; /* last pc traced */ |
| 83 | int line; /* current line */ | 87 | int line; /* current line */ |
| 84 | int refi; /* current index in `lineinfo' */ | 88 | int refi; /* current index in `lineinfo' */ |
| @@ -45,10 +45,6 @@ | |||
| 45 | #define LUA_ERRMEM 4 | 45 | #define LUA_ERRMEM 4 |
| 46 | #define LUA_ERRERR 5 | 46 | #define LUA_ERRERR 5 |
| 47 | 47 | ||
| 48 | /* weak-table modes */ | ||
| 49 | #define LUA_WEAK_KEY 1 | ||
| 50 | #define LUA_WEAK_VALUE 2 | ||
| 51 | |||
| 52 | 48 | ||
| 53 | typedef struct lua_State lua_State; | 49 | typedef struct lua_State lua_State; |
| 54 | 50 | ||
| @@ -182,6 +178,14 @@ LUA_API int lua_loadbuffer (lua_State *L, const char *buff, size_t size, | |||
| 182 | LUA_API int lua_dobuffer (lua_State *L, const char *buff, size_t size, | 178 | LUA_API int lua_dobuffer (lua_State *L, const char *buff, size_t size, |
| 183 | const char *name); | 179 | const char *name); |
| 184 | 180 | ||
| 181 | |||
| 182 | /* | ||
| 183 | ** coroutine functions | ||
| 184 | */ | ||
| 185 | LUA_API void lua_cobegin (lua_State *L, int nargs); | ||
| 186 | LUA_API int lua_yield (lua_State *L, int nresults); | ||
| 187 | LUA_API void lua_resume (lua_State *L, lua_State *co); | ||
| 188 | |||
| 185 | /* | 189 | /* |
| 186 | ** Garbage-collection functions | 190 | ** Garbage-collection functions |
| 187 | */ | 191 | */ |
| @@ -203,9 +207,6 @@ LUA_API void lua_concat (lua_State *L, int n); | |||
| 203 | LUA_API void *lua_newuserdata (lua_State *L, size_t size); | 207 | LUA_API void *lua_newuserdata (lua_State *L, size_t size); |
| 204 | LUA_API void lua_newuserdatabox (lua_State *L, void *u); | 208 | LUA_API void lua_newuserdatabox (lua_State *L, void *u); |
| 205 | 209 | ||
| 206 | LUA_API void lua_setweakmode (lua_State *L, int mode); | ||
| 207 | LUA_API int lua_getweakmode (lua_State *L, int index); | ||
| 208 | |||
| 209 | 210 | ||
| 210 | 211 | ||
| 211 | /* | 212 | /* |
| @@ -242,7 +243,7 @@ LUA_API int lua_getweakmode (lua_State *L, int index); | |||
| 242 | ** compatibility macros and functions | 243 | ** compatibility macros and functions |
| 243 | */ | 244 | */ |
| 244 | 245 | ||
| 245 | LUA_API void lua_pushupvalues (lua_State *L); | 246 | LUA_API int lua_pushupvalues (lua_State *L); |
| 246 | 247 | ||
| 247 | #define lua_isnull lua_isnone | 248 | #define lua_isnull lua_isnone |
| 248 | 249 | ||
| @@ -254,29 +254,6 @@ void luaV_strconc (lua_State *L, int total, StkId top) { | |||
| 254 | } | 254 | } |
| 255 | 255 | ||
| 256 | 256 | ||
| 257 | static void adjust_varargs (lua_State *L, StkId base, int nfixargs) { | ||
| 258 | int i; | ||
| 259 | Table *htab; | ||
| 260 | TObject n, nname; | ||
| 261 | StkId firstvar = base + nfixargs; /* position of first vararg */ | ||
| 262 | if (L->top < firstvar) { | ||
| 263 | luaD_checkstack(L, firstvar - L->top); | ||
| 264 | while (L->top < firstvar) | ||
| 265 | setnilvalue(L->top++); | ||
| 266 | } | ||
| 267 | htab = luaH_new(L, 0, 0); | ||
| 268 | for (i=0; firstvar+i<L->top; i++) | ||
| 269 | luaH_setnum(L, htab, i+1, firstvar+i); | ||
| 270 | /* store counter in field `n' */ | ||
| 271 | setnvalue(&n, i); | ||
| 272 | setsvalue(&nname, luaS_newliteral(L, "n")); | ||
| 273 | luaH_set(L, htab, &nname, &n); | ||
| 274 | L->top = firstvar; /* remove elements from the stack */ | ||
| 275 | sethvalue(L->top, htab); | ||
| 276 | incr_top; | ||
| 277 | } | ||
| 278 | |||
| 279 | |||
| 280 | static void powOp (lua_State *L, StkId ra, StkId rb, StkId rc) { | 257 | static void powOp (lua_State *L, StkId ra, StkId rb, StkId rc) { |
| 281 | const TObject *b = rb; | 258 | const TObject *b = rb; |
| 282 | const TObject *c = rc; | 259 | const TObject *c = rc; |
| @@ -307,8 +284,8 @@ static void powOp (lua_State *L, StkId ra, StkId rb, StkId rc) { | |||
| 307 | #define RC(i) (base+GETARG_C(i)) | 284 | #define RC(i) (base+GETARG_C(i)) |
| 308 | #define RKC(i) ((GETARG_C(i) < MAXSTACK) ? \ | 285 | #define RKC(i) ((GETARG_C(i) < MAXSTACK) ? \ |
| 309 | base+GETARG_C(i) : \ | 286 | base+GETARG_C(i) : \ |
| 310 | cl->p->k+GETARG_C(i)-MAXSTACK) | 287 | k+GETARG_C(i)-MAXSTACK) |
| 311 | #define KBc(i) (cl->p->k+GETARG_Bc(i)) | 288 | #define KBc(i) (k+GETARG_Bc(i)) |
| 312 | 289 | ||
| 313 | #define Arith(op, optm) { \ | 290 | #define Arith(op, optm) { \ |
| 314 | const TObject *b = RB(i); const TObject *c = RKC(i); \ | 291 | 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) { | |||
| 321 | } | 298 | } |
| 322 | 299 | ||
| 323 | 300 | ||
| 324 | #define luaV_poscall(L,c,f,ci) \ | ||
| 325 | if (c != NO_REG) { \ | ||
| 326 | luaD_poscall(L, c, f); \ | ||
| 327 | L->top = ci->top; \ | ||
| 328 | } \ | ||
| 329 | else { \ | ||
| 330 | luaD_poscall(L, LUA_MULTRET, f); \ | ||
| 331 | } | ||
| 332 | |||
| 333 | |||
| 334 | #define dojump(pc, i) ((pc) += GETARG_sBc(i)) | 301 | #define dojump(pc, i) ((pc) += GETARG_sBc(i)) |
| 335 | 302 | ||
| 336 | /* | 303 | /* |
| 337 | ** Executes the given Lua function. Parameters are between [base,top). | 304 | ** Executes current Lua function. Parameters are between [base,top). |
| 338 | ** Returns n such that the results are between [n,top). | 305 | ** Returns n such that the results are between [n,top). |
| 339 | */ | 306 | */ |
| 340 | StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base) { | 307 | StkId luaV_execute (lua_State *L) { |
| 308 | StkId base; | ||
| 309 | LClosure *cl; | ||
| 310 | TObject *k; | ||
| 341 | const Instruction *pc; | 311 | const Instruction *pc; |
| 342 | lua_Hook linehook; | 312 | lua_Hook linehook; |
| 343 | reinit: | 313 | reinit: |
| 344 | lua_assert(L->ci->savedpc == NULL); | 314 | base = L->ci->base; |
| 315 | cl = &clvalue(base - 1)->l; | ||
| 316 | k = cl->p->k; | ||
| 317 | linehook = L->ci->linehook; | ||
| 345 | L->ci->pc = &pc; | 318 | L->ci->pc = &pc; |
| 346 | L->ci->top = base + cl->p->maxstacksize; | 319 | pc = L->ci->savedpc; |
| 347 | if (cl->p->is_vararg) /* varargs? */ | 320 | L->ci->savedpc = NULL; |
| 348 | adjust_varargs(L, base, cl->p->numparams); | ||
| 349 | if (base > L->stack_last - cl->p->maxstacksize) | ||
| 350 | luaD_stackerror(L); | ||
| 351 | while (L->top < L->ci->top) | ||
| 352 | setnilvalue(L->top++); | ||
| 353 | L->top = L->ci->top; | ||
| 354 | linehook = L->ci->linehook = L->linehook; | ||
| 355 | pc = cl->p->code; | ||
| 356 | /* main loop of interpreter */ | 321 | /* main loop of interpreter */ |
| 357 | for (;;) { | 322 | for (;;) { |
| 358 | const Instruction i = *pc++; | 323 | const Instruction i = *pc++; |
| @@ -535,18 +500,21 @@ StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base) { | |||
| 535 | case OP_CALL: { | 500 | case OP_CALL: { |
| 536 | StkId firstResult; | 501 | StkId firstResult; |
| 537 | int b = GETARG_B(i); | 502 | int b = GETARG_B(i); |
| 538 | if (b != NO_REG) L->top = ra+b+1; | 503 | int nresults; |
| 539 | /* else previous instruction set top */ | 504 | if (b != 0) L->top = ra+b; /* else previous instruction set top */ |
| 505 | nresults = GETARG_C(i) - 1; | ||
| 540 | firstResult = luaD_precall(L, ra); | 506 | firstResult = luaD_precall(L, ra); |
| 541 | if (firstResult) { | 507 | if (firstResult) { |
| 508 | if (firstResult == base) { /* yield?? */ | ||
| 509 | (L->ci-1)->savedpc = pc; | ||
| 510 | return NULL; | ||
| 511 | } | ||
| 542 | /* it was a C function (`precall' called it); adjust results */ | 512 | /* it was a C function (`precall' called it); adjust results */ |
| 543 | luaV_poscall(L, GETARG_C(i), firstResult, L->ci); | 513 | luaD_poscall(L, nresults, firstResult); |
| 514 | if (nresults >= 0) L->top = L->ci->top; | ||
| 544 | } | 515 | } |
| 545 | else { /* it is a Lua function: `call' it */ | 516 | else { /* it is a Lua function: `call' it */ |
| 546 | CallInfo *ci = L->ci; | 517 | (L->ci-1)->savedpc = pc; |
| 547 | (ci-1)->savedpc = pc; | ||
| 548 | base = ci->base; | ||
| 549 | cl = &clvalue(base - 1)->l; | ||
| 550 | goto reinit; | 518 | goto reinit; |
| 551 | } | 519 | } |
| 552 | break; | 520 | break; |
| @@ -556,19 +524,23 @@ StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base) { | |||
| 556 | int b; | 524 | int b; |
| 557 | if (L->openupval) luaF_close(L, base); | 525 | if (L->openupval) luaF_close(L, base); |
| 558 | b = GETARG_B(i); | 526 | b = GETARG_B(i); |
| 559 | if (b != NO_REG) L->top = ra+b; | 527 | if (b != 0) L->top = ra+b-1; |
| 560 | ci = L->ci - 1; | 528 | ci = L->ci - 1; |
| 561 | if (ci->savedpc == NULL) | 529 | if (ci->savedpc == NULL) |
| 562 | return ra; | 530 | return ra; |
| 563 | else { /* previous function is Lua: continue its execution */ | 531 | else { /* previous function is Lua: continue its execution */ |
| 532 | int nresults; | ||
| 564 | lua_assert(ttype(ci->base-1) == LUA_TFUNCTION); | 533 | lua_assert(ttype(ci->base-1) == LUA_TFUNCTION); |
| 565 | base = ci->base; /* restore previous values */ | 534 | base = ci->base; /* restore previous values */ |
| 566 | linehook = ci->linehook; | 535 | linehook = ci->linehook; |
| 567 | cl = &clvalue(base - 1)->l; | 536 | cl = &clvalue(base - 1)->l; |
| 537 | k = cl->p->k; | ||
| 568 | pc = ci->savedpc; | 538 | pc = ci->savedpc; |
| 569 | ci->savedpc = NULL; | 539 | ci->savedpc = NULL; |
| 570 | lua_assert(GET_OPCODE(*(pc-1)) == OP_CALL); | 540 | lua_assert(GET_OPCODE(*(pc-1)) == OP_CALL); |
| 571 | luaV_poscall(L, GETARG_C(*(pc-1)), ra, ci); | 541 | nresults = GETARG_C(*(pc-1)) - 1; |
| 542 | luaD_poscall(L, nresults, ra); | ||
| 543 | if (nresults >= 0) L->top = L->ci->top; | ||
| 572 | } | 544 | } |
| 573 | break; | 545 | break; |
| 574 | } | 546 | } |
| @@ -20,7 +20,7 @@ const TObject *luaV_tonumber (const TObject *obj, TObject *n); | |||
| 20 | int luaV_tostring (lua_State *L, TObject *obj); | 20 | int luaV_tostring (lua_State *L, TObject *obj); |
| 21 | void luaV_gettable (lua_State *L, StkId t, TObject *key, StkId res); | 21 | void luaV_gettable (lua_State *L, StkId t, TObject *key, StkId res); |
| 22 | void luaV_settable (lua_State *L, StkId t, TObject *key, StkId val); | 22 | void luaV_settable (lua_State *L, StkId t, TObject *key, StkId val); |
| 23 | StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base); | 23 | StkId luaV_execute (lua_State *L); |
| 24 | int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r); | 24 | int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r); |
| 25 | void luaV_strconc (lua_State *L, int total, StkId top); | 25 | void luaV_strconc (lua_State *L, int total, StkId top); |
| 26 | 26 | ||
