mirror of
https://github.com/lua/lua
synced 2025-01-11 11:59:18 +03:00
first implementation of coroutines
This commit is contained in:
parent
3533382a1e
commit
f083812c02
81
lbaselib.c
81
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) {
|
||||
lua_getglobals(L); /* value to be returned */
|
||||
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"
|
||||
|
||||
@ -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) {
|
||||
int n, i;
|
||||
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) {
|
||||
luaL_check_type(L, 1, LUA_TTABLE);
|
||||
lua_pushnumber(L, lua_getn(L, 1));
|
||||
@ -521,7 +530,6 @@ static int luaB_tremove (lua_State *L) {
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** Quicksort
|
||||
@ -627,6 +635,8 @@ static int luaB_sort (lua_State *L) {
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
|
||||
static const luaL_reg base_funcs[] = {
|
||||
@ -634,6 +644,7 @@ static const luaL_reg base_funcs[] = {
|
||||
{LUA_ERRORMESSAGE, luaB__ERRORMESSAGE},
|
||||
{"call", luaB_call},
|
||||
{"collectgarbage", luaB_collectgarbage},
|
||||
{"coroutine", luaB_coroutine},
|
||||
{"dofile", luaB_dofile},
|
||||
{"dostring", luaB_dostring},
|
||||
{"error", luaB_error},
|
||||
@ -659,7 +670,7 @@ static const luaL_reg base_funcs[] = {
|
||||
{"tinsert", luaB_tinsert},
|
||||
{"tremove", luaB_tremove},
|
||||
{"unpack", luaB_unpack},
|
||||
{"weakmode", luaB_weakmode}
|
||||
{"yield", luaB_yield}
|
||||
};
|
||||
|
||||
|
||||
|
3
lcode.c
3
lcode.c
@ -264,8 +264,7 @@ static int nil_constant (FuncState *fs) {
|
||||
|
||||
void luaK_setcallreturns (FuncState *fs, expdesc *e, int nresults) {
|
||||
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? */
|
||||
e->k = VNONRELOC;
|
||||
e->u.i.info = GETARG_A(getcode(fs, e));
|
||||
|
15
ldebug.c
15
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
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@ -303,7 +303,7 @@ static int checkopenop (const Proto *pt, int pc) {
|
||||
switch (GET_OPCODE(i)) {
|
||||
case OP_CALL:
|
||||
case OP_RETURN: {
|
||||
check(GETARG_B(i) == NO_REG);
|
||||
check(GETARG_B(i) == 0);
|
||||
return 1;
|
||||
}
|
||||
case OP_SETLISTO: return 1;
|
||||
@ -391,10 +391,11 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) {
|
||||
break;
|
||||
}
|
||||
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));
|
||||
}
|
||||
else if (c != 0)
|
||||
@ -403,8 +404,8 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) {
|
||||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
case OP_FORPREP:
|
||||
|
126
ldo.c
126
ldo.c
@ -18,6 +18,7 @@
|
||||
#include "lgc.h"
|
||||
#include "lmem.h"
|
||||
#include "lobject.h"
|
||||
#include "lopcodes.h"
|
||||
#include "lparser.h"
|
||||
#include "lstate.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) {
|
||||
lua_assert(L->ci == L->end_ci);
|
||||
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) {
|
||||
CallInfo *ci;
|
||||
int n;
|
||||
LClosure *cl;
|
||||
if (ttype(func) != LUA_TFUNCTION) {
|
||||
/* `func' is not a function; check the `function' tag method */
|
||||
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);
|
||||
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->savedpc = NULL;
|
||||
if (L->callhook)
|
||||
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
|
||||
lua_pushupvalues(L);
|
||||
lua_pushupvalues(L);
|
||||
#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) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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.
|
||||
*/
|
||||
@ -330,7 +418,13 @@ static void message (lua_State *L, const char *s) {
|
||||
** Reports an error, and jumps up to the available recovery label
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
|
19
lopcodes.h
19
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_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_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_CLOSURE /* A Bc R(A) := closure(KPROTO[Bc], R(A), ... ,R(A+n)) */
|
||||
/*----------------------------------------------------------------------
|
||||
pseudo-instructions (interruptions): cannot occur in regular code
|
||||
------------------------------------------------------------------------*/
|
||||
} 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;
|
||||
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'.
|
||||
|
||||
(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)))
|
||||
|
||||
|
||||
/*
|
||||
** constant instructions
|
||||
*/
|
||||
|
||||
extern const Instruction luaP_yieldop;
|
||||
|
||||
/*
|
||||
** opcode names (only included when compiled with LUA_OPNAMES)
|
||||
*/
|
||||
|
10
lparser.c
10
lparser.c
@ -335,7 +335,7 @@ static void close_func (LexState *ls) {
|
||||
FuncState *fs = ls->fs;
|
||||
Proto *f = fs->f;
|
||||
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 */
|
||||
lua_assert(G(L)->roottable == fs->h);
|
||||
G(L)->roottable = fs->h->next;
|
||||
@ -449,13 +449,13 @@ static void funcargs (LexState *ls, expdesc *f) {
|
||||
lua_assert(f->k == VNONRELOC);
|
||||
base = f->u.i.info; /* base register for call */
|
||||
if (args.k == VCALL)
|
||||
nparams = NO_REG; /* open call */
|
||||
nparams = LUA_MULTRET; /* open call */
|
||||
else {
|
||||
if (args.k != VVOID)
|
||||
luaK_exp2nextreg(fs, &args); /* close last argument */
|
||||
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
|
||||
(unless changed) one result */
|
||||
}
|
||||
@ -1136,7 +1136,7 @@ static void retstat (LexState *ls) {
|
||||
if (e.k == VCALL) {
|
||||
luaK_setcallreturns(fs, &e, LUA_MULTRET);
|
||||
first = fs->nactloc;
|
||||
nret = NO_REG; /* return all values */
|
||||
nret = LUA_MULTRET; /* return all values */
|
||||
}
|
||||
else {
|
||||
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 */
|
||||
}
|
||||
}
|
||||
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 */
|
||||
}
|
||||
|
||||
|
1
lstate.c
1
lstate.c
@ -104,6 +104,7 @@ LUA_API lua_State *lua_newthread (lua_State *OL, int stacksize) {
|
||||
}
|
||||
}
|
||||
if (OL) lua_unlock(OL);
|
||||
lua_userstateopen(L);
|
||||
return L;
|
||||
}
|
||||
|
||||
|
6
lstate.h
6
lstate.h
@ -39,6 +39,10 @@
|
||||
#define LUA_USERSTATE
|
||||
#endif
|
||||
|
||||
#ifndef lua_userstateopen
|
||||
#define lua_userstateopen(l)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
struct lua_longjmp; /* defined in ldo.c */
|
||||
@ -77,8 +81,8 @@ typedef struct CallInfo {
|
||||
const Instruction *savedpc;
|
||||
lua_Hook linehook;
|
||||
StkId top; /* top for this function (when it's a Lua function) */
|
||||
/* extra information for debugging */
|
||||
const Instruction **pc;
|
||||
/* extra information for line tracing */
|
||||
int lastpc; /* last pc traced */
|
||||
int line; /* current line */
|
||||
int refi; /* current index in `lineinfo' */
|
||||
|
17
lua.h
17
lua.h
@ -45,10 +45,6 @@
|
||||
#define LUA_ERRMEM 4
|
||||
#define LUA_ERRERR 5
|
||||
|
||||
/* weak-table modes */
|
||||
#define LUA_WEAK_KEY 1
|
||||
#define LUA_WEAK_VALUE 2
|
||||
|
||||
|
||||
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,
|
||||
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
|
||||
*/
|
||||
@ -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_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
|
||||
*/
|
||||
|
||||
LUA_API void lua_pushupvalues (lua_State *L);
|
||||
LUA_API int lua_pushupvalues (lua_State *L);
|
||||
|
||||
#define lua_isnull lua_isnone
|
||||
|
||||
|
86
lvm.c
86
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) {
|
||||
const TObject *b = rb;
|
||||
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 RKC(i) ((GETARG_C(i) < MAXSTACK) ? \
|
||||
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) { \
|
||||
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))
|
||||
|
||||
/*
|
||||
** 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).
|
||||
*/
|
||||
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;
|
||||
lua_Hook linehook;
|
||||
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->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 */
|
||||
for (;;) {
|
||||
const Instruction i = *pc++;
|
||||
@ -535,18 +500,21 @@ StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base) {
|
||||
case OP_CALL: {
|
||||
StkId firstResult;
|
||||
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);
|
||||
if (firstResult) {
|
||||
if (firstResult == base) { /* yield?? */
|
||||
(L->ci-1)->savedpc = pc;
|
||||
return NULL;
|
||||
}
|
||||
/* 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 */
|
||||
CallInfo *ci = L->ci;
|
||||
(ci-1)->savedpc = pc;
|
||||
base = ci->base;
|
||||
cl = &clvalue(base - 1)->l;
|
||||
(L->ci-1)->savedpc = pc;
|
||||
goto reinit;
|
||||
}
|
||||
break;
|
||||
@ -556,19 +524,23 @@ StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base) {
|
||||
int b;
|
||||
if (L->openupval) luaF_close(L, base);
|
||||
b = GETARG_B(i);
|
||||
if (b != NO_REG) L->top = ra+b;
|
||||
if (b != 0) L->top = ra+b-1;
|
||||
ci = L->ci - 1;
|
||||
if (ci->savedpc == NULL)
|
||||
return ra;
|
||||
else { /* previous function is Lua: continue its execution */
|
||||
int nresults;
|
||||
lua_assert(ttype(ci->base-1) == LUA_TFUNCTION);
|
||||
base = ci->base; /* restore previous values */
|
||||
linehook = ci->linehook;
|
||||
cl = &clvalue(base - 1)->l;
|
||||
k = cl->p->k;
|
||||
pc = ci->savedpc;
|
||||
ci->savedpc = NULL;
|
||||
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;
|
||||
}
|
||||
|
2
lvm.h
2
lvm.h
@ -20,7 +20,7 @@ const TObject *luaV_tonumber (const TObject *obj, TObject *n);
|
||||
int luaV_tostring (lua_State *L, TObject *obj);
|
||||
void luaV_gettable (lua_State *L, StkId t, TObject *key, StkId res);
|
||||
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);
|
||||
void luaV_strconc (lua_State *L, int total, StkId top);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user