diff -urN lua-5.0.2/include/lauxlib.h lua-5.0.2-thread/include/lauxlib.h --- lua-5.0.2/include/lauxlib.h Thu Apr 3 08:35:34 2003 +++ lua-5.0.2-thread/include/lauxlib.h Mon Mar 22 08:00:30 2004 @@ -62,7 +62,7 @@ LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t sz, const char *name); - +LUALIB_API int luaL_traceback (lua_State *L); /* ** =============================================================== diff -urN lua-5.0.2/include/lua.h lua-5.0.2-thread/include/lua.h --- lua-5.0.2/include/lua.h Thu Mar 11 20:44:52 2004 +++ lua-5.0.2-thread/include/lua.h Mon Mar 22 08:00:54 2004 @@ -14,7 +14,7 @@ #include -#define LUA_VERSION "Lua 5.0.2" +#define LUA_VERSION "Lua 5.0.2-forpatch" #define LUA_COPYRIGHT "Copyright (C) 1994-2004 Tecgraf, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" diff -urN lua-5.0.2/src/ldebug.c lua-5.0.2-thread/src/ldebug.c --- lua-5.0.2/src/ldebug.c Wed Mar 19 16:24:04 2003 +++ lua-5.0.2-thread/src/ldebug.c Mon Mar 22 08:00:30 2004 @@ -373,12 +373,9 @@ check(c < MAXSTACK && b < c); break; } - case OP_TFORLOOP: - checkreg(pt, a+c+5); - if (reg >= a) last = pc; /* affect all registers above base */ - /* go through */ case OP_FORLOOP: - checkreg(pt, a+2); + checkreg(pt, a+3); + if (reg == a+3) last = pc; /* go through */ case OP_JMP: { int dest = pc+1+b; @@ -389,10 +386,12 @@ break; } case OP_CALL: - case OP_TAILCALL: { + case OP_TAILCALL: if (b != 0) { checkreg(pt, a+b-1); } + /* go through */ + case OP_TFORLOOP: { c--; /* c = num. returns */ if (c == LUA_MULTRET) { check(checkopenop(pt, pc)); @@ -496,7 +495,9 @@ return NULL; /* calling function is not Lua (or is unknown) */ ci--; /* calling function */ i = ci_func(ci)->l.p->code[currentpc(ci)]; - if (GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL) + if (GET_OPCODE(i) == OP_CALL || + GET_OPCODE(i) == OP_TAILCALL || + GET_OPCODE(i) == OP_TFORLOOP) return getobjname(ci, GETARG_A(i), name); else return NULL; /* no useful name can be found */ @@ -562,12 +563,16 @@ } -void luaG_errormsg (lua_State *L) { - if (L->errfunc != 0) { /* is there an error handling function? */ - StkId errfunc = restorestack(L, L->errfunc); - if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR); + void luaG_errormsg (lua_State *L) { + const TObject *errfunc; + if (L->errfunc != 0) { /* is there an error handling function? */ + errfunc = restorestack(L, L->errfunc); + } else { + errfunc = luaH_getstr(hvalue(gt(L)), luaS_new(L, "_TRACEBACK")); + } + if (ttisfunction(errfunc)) { setobjs2s(L->top, L->top - 1); /* move argument */ - setobjs2s(L->top - 1, errfunc); /* push function */ + setobj2s(L->top - 1, errfunc); /* push function */ incr_top(L); luaD_call(L, L->top - 2, 1); /* call it */ } diff -urN lua-5.0.2/src/ldo.c lua-5.0.2-thread/src/ldo.c --- lua-5.0.2/src/ldo.c Tue Oct 7 08:25:42 2003 +++ lua-5.0.2-thread/src/ldo.c Mon Mar 22 08:00:30 2004 @@ -332,7 +332,8 @@ int nresults; lua_assert((ci-1)->state & CI_SAVEDPC); lua_assert(GET_OPCODE(*((ci-1)->u.l.savedpc - 1)) == OP_CALL || - GET_OPCODE(*((ci-1)->u.l.savedpc - 1)) == OP_TAILCALL); + GET_OPCODE(*((ci-1)->u.l.savedpc - 1)) == OP_TAILCALL || + GET_OPCODE(*((ci-1)->u.l.savedpc - 1)) == OP_TFORLOOP); nresults = GETARG_C(*((ci-1)->u.l.savedpc - 1)) - 1; luaD_poscall(L, nresults, L->top - nargs); /* complete it */ if (nresults >= 0) L->top = L->ci->top; diff -urN lua-5.0.2/src/lib/lauxlib.c lua-5.0.2-thread/src/lib/lauxlib.c --- lua-5.0.2/src/lib/lauxlib.c Mon Apr 7 09:35:00 2003 +++ lua-5.0.2-thread/src/lib/lauxlib.c Mon Mar 22 08:00:30 2004 @@ -589,3 +589,57 @@ } /* }====================================================== */ + +#define LEVELS1 12 /* size of the first part of the stack */ +#define LEVELS2 10 /* size of the second part of the stack */ + +LUALIB_API int luaL_traceback (lua_State *L) { + int level = 1; /* skip level 0 (it's this function) */ + int firstpart = 1; /* still before eventual `...' */ + lua_Debug ar; + if (lua_gettop(L) == 0) + lua_pushliteral(L, ""); + else if (!lua_isstring(L, 1)) return 1; /* no string message */ + else lua_pushliteral(L, "\n"); + lua_pushliteral(L, "stack traceback:"); + while (lua_getstack(L, level++, &ar)) { + if (level > LEVELS1 && firstpart) { + /* no more than `LEVELS2' more levels? */ + if (!lua_getstack(L, level+LEVELS2, &ar)) + level--; /* keep going */ + else { + lua_pushliteral(L, "\n\t..."); /* too many levels */ + while (lua_getstack(L, level+LEVELS2, &ar)) /* find last levels */ + level++; + } + firstpart = 0; + continue; + } + lua_pushliteral(L, "\n\t"); + lua_getinfo(L, "Snl", &ar); + lua_pushfstring(L, "%s:", ar.short_src); + if (ar.currentline > 0) + lua_pushfstring(L, "%d:", ar.currentline); + switch (*ar.namewhat) { + case 'g': /* global */ + case 'l': /* local */ + case 'f': /* field */ + case 'm': /* method */ + lua_pushfstring(L, " in function `%s'", ar.name); + break; + default: { + if (*ar.what == 'm') /* main? */ + lua_pushfstring(L, " in main chunk"); + else if (*ar.what == 'C' || *ar.what == 't') + lua_pushliteral(L, " ?"); /* C function or tail call */ + else + lua_pushfstring(L, " in function <%s:%d>", + ar.short_src, ar.linedefined); + } + } + lua_concat(L, lua_gettop(L)); + } + lua_concat(L, lua_gettop(L)); + return 1; +} + diff -urN lua-5.0.2/src/lib/ldblib.c lua-5.0.2-thread/src/lib/ldblib.c --- lua-5.0.2/src/lib/ldblib.c Thu Apr 3 08:35:34 2003 +++ lua-5.0.2-thread/src/lib/ldblib.c Mon Mar 22 08:00:30 2004 @@ -220,61 +220,6 @@ } } - -#define LEVELS1 12 /* size of the first part of the stack */ -#define LEVELS2 10 /* size of the second part of the stack */ - -static int errorfb (lua_State *L) { - int level = 1; /* skip level 0 (it's this function) */ - int firstpart = 1; /* still before eventual `...' */ - lua_Debug ar; - if (lua_gettop(L) == 0) - lua_pushliteral(L, ""); - else if (!lua_isstring(L, 1)) return 1; /* no string message */ - else lua_pushliteral(L, "\n"); - lua_pushliteral(L, "stack traceback:"); - while (lua_getstack(L, level++, &ar)) { - if (level > LEVELS1 && firstpart) { - /* no more than `LEVELS2' more levels? */ - if (!lua_getstack(L, level+LEVELS2, &ar)) - level--; /* keep going */ - else { - lua_pushliteral(L, "\n\t..."); /* too many levels */ - while (lua_getstack(L, level+LEVELS2, &ar)) /* find last levels */ - level++; - } - firstpart = 0; - continue; - } - lua_pushliteral(L, "\n\t"); - lua_getinfo(L, "Snl", &ar); - lua_pushfstring(L, "%s:", ar.short_src); - if (ar.currentline > 0) - lua_pushfstring(L, "%d:", ar.currentline); - switch (*ar.namewhat) { - case 'g': /* global */ - case 'l': /* local */ - case 'f': /* field */ - case 'm': /* method */ - lua_pushfstring(L, " in function `%s'", ar.name); - break; - default: { - if (*ar.what == 'm') /* main? */ - lua_pushfstring(L, " in main chunk"); - else if (*ar.what == 'C' || *ar.what == 't') - lua_pushliteral(L, " ?"); /* C function or tail call */ - else - lua_pushfstring(L, " in function <%s:%d>", - ar.short_src, ar.linedefined); - } - } - lua_concat(L, lua_gettop(L)); - } - lua_concat(L, lua_gettop(L)); - return 1; -} - - static const luaL_reg dblib[] = { {"getlocal", getlocal}, {"getinfo", getinfo}, @@ -284,7 +229,7 @@ {"setlocal", setlocal}, {"setupvalue", setupvalue}, {"debug", debug}, - {"traceback", errorfb}, + {"traceback", luaL_traceback}, {NULL, NULL} }; @@ -292,7 +237,7 @@ LUALIB_API int luaopen_debug (lua_State *L) { luaL_openlib(L, LUA_DBLIBNAME, dblib, 0); lua_pushliteral(L, "_TRACEBACK"); - lua_pushcfunction(L, errorfb); + lua_pushcfunction(L, luaL_traceback); lua_settable(L, LUA_GLOBALSINDEX); return 1; } diff -urN lua-5.0.2/src/lopcodes.c lua-5.0.2-thread/src/lopcodes.c --- lua-5.0.2/src/lopcodes.c Wed Dec 4 12:38:31 2002 +++ lua-5.0.2-thread/src/lopcodes.c Mon Mar 22 08:00:30 2004 @@ -42,6 +42,7 @@ "LT", "LE", "TEST", + "TESTNIL", "CALL", "TAILCALL", "RETURN", @@ -88,11 +89,12 @@ ,opmode(1, 0, 1, 1, 0, 0, iABC) /* OP_LT */ ,opmode(1, 0, 1, 1, 0, 0, iABC) /* OP_LE */ ,opmode(1, 1, 0, 0, 1, 0, iABC) /* OP_TEST */ + ,opmode(1, 1, 0, 0, 1, 0, iABC) /* OP_TESTNIL */ ,opmode(0, 0, 0, 0, 0, 0, iABC) /* OP_CALL */ ,opmode(0, 0, 0, 0, 0, 0, iABC) /* OP_TAILCALL */ ,opmode(0, 0, 0, 0, 0, 0, iABC) /* OP_RETURN */ ,opmode(0, 0, 0, 0, 0, 0, iAsBx) /* OP_FORLOOP */ - ,opmode(1, 0, 0, 0, 0, 0, iABC) /* OP_TFORLOOP */ + ,opmode(0, 1, 0, 0, 0, 0, iABC) /* OP_TFORLOOP */ ,opmode(0, 0, 0, 0, 0, 0, iAsBx) /* OP_TFORPREP */ ,opmode(0, 0, 0, 0, 0, 0, iABx) /* OP_SETLIST */ ,opmode(0, 0, 0, 0, 0, 0, iABx) /* OP_SETLISTO */ diff -urN lua-5.0.2/src/lopcodes.h lua-5.0.2-thread/src/lopcodes.h --- lua-5.0.2/src/lopcodes.h Wed Aug 21 13:56:09 2002 +++ lua-5.0.2-thread/src/lopcodes.h Mon Mar 22 08:00:30 2004 @@ -166,6 +166,7 @@ OP_LE,/* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */ OP_TEST,/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ +OP_TESTNIL,/* A B C if (R(B) is nil <=> C) then R(A) := R(B) else pc++ */ OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ @@ -173,8 +174,7 @@ OP_FORLOOP,/* A sBx R(A)+=R(A+2); if R(A) upval = 0; bl->previous = fs->bl; fs->bl = bl; - lua_assert(fs->freereg == fs->nactvar); + /* lua_assert(fs->freereg == fs->nactvar); */ } @@ -849,11 +849,12 @@ } -static void block (LexState *ls) { +static void block (LexState *ls, int nvars) { /* block -> chunk */ FuncState *fs = ls->fs; BlockCnt bl; enterblock(fs, &bl, 0); + if (nvars) adjustlocalvars(ls, nvars); chunk(ls); lua_assert(bl.breaklist == NO_JUMP); leaveblock(fs); @@ -986,7 +987,7 @@ enterblock(fs, &bl, 1); check(ls, TK_DO); blockinit = luaK_getlabel(fs); - block(ls); + block(ls, 0); luaK_patchtohere(fs, whileinit); /* initial jump jumps to here */ /* move `exp' back to code */ if (v.t != NO_JUMP) v.t += fs->pc - expinit; @@ -1008,7 +1009,7 @@ BlockCnt bl; enterblock(fs, &bl, 1); next(ls); - block(ls); + block(ls, 0); check_match(ls, TK_UNTIL, TK_REPEAT, line); cond(ls, &v); luaK_patchlist(fs, v.f, repeat_init); @@ -1030,16 +1031,22 @@ BlockCnt bl; FuncState *fs = ls->fs; int prep, endfor; - adjustlocalvars(ls, nvars); /* scope for all variables */ check(ls, TK_DO); enterblock(fs, &bl, 1); /* loop block */ + adjustlocalvars(ls, 3); /* scope for control variables */ prep = luaK_getlabel(fs); - block(ls); + block(ls, nvars - 3); luaK_patchtohere(fs, prep-1); - endfor = (isnum) ? luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP) : - luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars - 3); - luaK_fixline(fs, line); /* pretend that `OP_FOR' starts the loop */ - luaK_patchlist(fs, (isnum) ? endfor : luaK_jump(fs), prep); + if (isnum) { + endfor = luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP); + luaK_fixline(fs, line); /* pretend that `OP_FOR' starts the loop */ + luaK_patchlist(fs, endfor, prep); + } else { + endfor = luaK_codeABC(fs, OP_TFORLOOP, base + 3, base, nvars - 2); + luaK_fixline(fs, line); + luaK_codeABC(fs, OP_TESTNIL, base + 2, base + 3, 1); + luaK_patchlist(fs, luaK_jump(fs), prep); + } leaveblock(fs); } @@ -1048,22 +1055,25 @@ /* fornum -> NAME = exp1,exp1[,exp1] DO body */ FuncState *fs = ls->fs; int base = fs->freereg; - new_localvar(ls, varname, 0); + new_localvarstr(ls, "(for value)", 0); new_localvarstr(ls, "(for limit)", 1); new_localvarstr(ls, "(for step)", 2); + new_localvar(ls, varname, 3); check(ls, '='); exp1(ls); /* initial value */ check(ls, ','); exp1(ls); /* limit */ - if (testnext(ls, ',')) + if (testnext(ls, ',')) { exp1(ls); /* optional step */ + luaK_reserveregs(fs, 1); + } else { /* default step = 1 */ luaK_codeABx(fs, OP_LOADK, fs->freereg, luaK_numberK(fs, 1)); - luaK_reserveregs(fs, 1); + luaK_reserveregs(fs, 2); } - luaK_codeABC(fs, OP_SUB, fs->freereg - 3, fs->freereg - 3, fs->freereg - 1); + luaK_codeABC(fs, OP_SUB, fs->freereg - 4, fs->freereg - 4, fs->freereg - 2); luaK_jump(fs); - forbody(ls, base, line, 3, 1); + forbody(ls, base, line, 4, 1); } @@ -1076,13 +1086,15 @@ int base = fs->freereg; new_localvarstr(ls, "(for generator)", nvars++); new_localvarstr(ls, "(for state)", nvars++); + new_localvarstr(ls, "(for key)", nvars++); new_localvar(ls, indexname, nvars++); while (testnext(ls, ',')) new_localvar(ls, str_checkname(ls), nvars++); check(ls, TK_IN); line = ls->linenumber; adjust_assign(ls, nvars, explist1(ls, &e), &e); - luaK_checkstack(fs, 3); /* extra space to call generator */ + if (nvars < 6) + luaK_checkstack(fs, nvars - 3); /* extra space to call generator */ luaK_codeAsBx(fs, OP_TFORPREP, base, NO_JUMP); forbody(ls, base, line, nvars, 0); } @@ -1090,10 +1102,7 @@ static void forstat (LexState *ls, int line) { /* forstat -> fornum | forlist */ - FuncState *fs = ls->fs; TString *varname; - BlockCnt bl; - enterblock(fs, &bl, 0); /* block to control variable scope */ next(ls); /* skip `for' */ varname = str_checkname(ls); /* first variable name */ switch (ls->t.token) { @@ -1102,7 +1111,6 @@ default: luaX_syntaxerror(ls, "`=' or `in' expected"); } check_match(ls, TK_END, TK_FOR, line); - leaveblock(fs); } @@ -1111,7 +1119,7 @@ next(ls); /* skip IF or ELSEIF */ cond(ls, v); check(ls, TK_THEN); - block(ls); /* `then' part */ + block(ls, 0); /* `then' part */ } @@ -1130,7 +1138,7 @@ luaK_concat(fs, &escapelist, luaK_jump(fs)); luaK_patchtohere(fs, v.f); next(ls); /* skip ELSE (after patch, for correct line info) */ - block(ls); /* `else' part */ + block(ls, 0); /* `else' part */ } else luaK_concat(fs, &escapelist, v.f); @@ -1277,7 +1285,7 @@ } case TK_DO: { /* stat -> DO block END */ next(ls); /* skip DO */ - block(ls); + block(ls, 0); check_match(ls, TK_END, TK_DO, line); return 0; } diff -urN lua-5.0.2/src/lvm.c lua-5.0.2-thread/src/lvm.c --- lua-5.0.2/src/lvm.c Wed Mar 3 19:50:13 2004 +++ lua-5.0.2-thread/src/lvm.c Mon Mar 22 08:00:30 2004 @@ -432,7 +432,8 @@ lua_assert(L->top <= L->stack + L->stacksize && L->top >= base); lua_assert(L->top == L->ci->top || GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL || - GET_OPCODE(i) == OP_RETURN || GET_OPCODE(i) == OP_SETLISTO); + GET_OPCODE(i) == OP_RETURN || GET_OPCODE(i) == OP_SETLISTO || + GET_OPCODE(i) == OP_TFORLOOP); switch (GET_OPCODE(i)) { case OP_MOVE: { setobjs2s(ra, RB(i)); @@ -617,12 +618,33 @@ } break; } + case OP_TESTNIL: { + TObject *rb = RB(i); + if (ttisnil(rb) == GETARG_C(i)) pc++; + else { + setobjs2s(ra, rb); + dojump(pc, GETARG_sBx(*pc) + 1); + } + break; + } + case OP_TFORLOOP: { + TObject *rb = RB(i); + setobjs2s(ra, rb); /* copy function + 2 args */ + setobjs2s(ra+1, rb+1); + setobjs2s(ra+2, rb+2); + L->top = ra + 3; + } + + goto do_the_call; + case OP_CALL: case OP_TAILCALL: { - StkId firstResult; int b = GETARG_B(i); - int nresults; if (b != 0) L->top = ra+b; /* else previous instruction set top */ + } + do_the_call: { + StkId firstResult; + int nresults; nresults = GETARG_C(i) - 1; firstResult = luaD_precall(L, ra); if (firstResult) { @@ -637,7 +659,7 @@ if (nresults >= 0) L->top = L->ci->top; } else { /* it is a Lua function */ - if (GET_OPCODE(i) == OP_CALL) { /* regular call? */ + if (GET_OPCODE(i) != OP_TAILCALL) { /* regular call? */ (L->ci-1)->u.l.savedpc = pc; /* save `pc' to return later */ (L->ci-1)->state = (CI_SAVEDPC | CI_CALLING); } @@ -676,7 +698,8 @@ else { /* yes: continue its execution */ int nresults; lua_assert(ttisfunction(ci->base - 1) && (ci->state & CI_SAVEDPC)); - lua_assert(GET_OPCODE(*(ci->u.l.savedpc - 1)) == OP_CALL); + lua_assert(GET_OPCODE(*(ci->u.l.savedpc - 1)) == OP_CALL || + GET_OPCODE(*(ci->u.l.savedpc - 1)) == OP_TFORLOOP); nresults = GETARG_C(*(ci->u.l.savedpc - 1)) - 1; luaD_poscall(L, nresults, ra); if (nresults >= 0) L->top = L->ci->top; @@ -699,28 +722,8 @@ if (step > 0 ? idx <= limit : idx >= limit) { dojump(pc, GETARG_sBx(i)); /* jump back */ chgnvalue(ra, idx); /* update index */ + setobjs2s(ra+3, ra); /* copy for for loop */ } - break; - } - case OP_TFORLOOP: { - int nvar = GETARG_C(i) + 1; - StkId cb = ra + nvar + 2; /* call base */ - setobjs2s(cb, ra); - setobjs2s(cb+1, ra+1); - setobjs2s(cb+2, ra+2); - L->top = cb+3; /* func. + 2 args (state and index) */ - luaD_call(L, cb, nvar); - L->top = L->ci->top; - ra = XRA(i) + 2; /* final position of first result */ - cb = ra + nvar; - do { /* move results to proper positions */ - nvar--; - setobjs2s(ra+nvar, cb+nvar); - } while (nvar > 0); - if (ttisnil(ra)) /* break loop? */ - pc++; /* skip jump (break loop) */ - else - dojump(pc, GETARG_sBx(*pc) + 1); /* jump back */ break; } case OP_TFORPREP: { /* for compatibility only */