Commit c52f02b8 authored by capresti@gmail.com's avatar capresti@gmail.com
Browse files

- Applied patch-lua-5.1.4-3 from lua.org

git-svn-id: http://luainterface.googlecode.com/svn/trunk@26 63eb109e-e254-0410-a61e-ed0b8f8614f5
parent ff873f0f
/* /*
** $Id: lcode.c,v 2.25.1.3 2007/12/28 15:32:23 roberto Exp $ ** $Id: lcode.c,v 2.25.1.5 2011/01/31 14:53:16 roberto Exp $
** Code generator for Lua ** Code generator for Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
#include <stdlib.h> #include <stdlib.h>
#define lcode_c #define lcode_c
#define LUA_CORE #define LUA_CORE
#include "lua.h" #include "lua.h"
#include "lcode.h" #include "lcode.h"
#include "ldebug.h" #include "ldebug.h"
#include "ldo.h" #include "ldo.h"
#include "lgc.h" #include "lgc.h"
#include "llex.h" #include "llex.h"
#include "lmem.h" #include "lmem.h"
#include "lobject.h" #include "lobject.h"
#include "lopcodes.h" #include "lopcodes.h"
#include "lparser.h" #include "lparser.h"
#include "ltable.h" #include "ltable.h"
#define hasjumps(e) ((e)->t != (e)->f) #define hasjumps(e) ((e)->t != (e)->f)
static int isnumeral(expdesc *e) { static int isnumeral(expdesc *e) {
return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP); return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP);
} }
void luaK_nil (FuncState *fs, int from, int n) { void luaK_nil (FuncState *fs, int from, int n) {
Instruction *previous; Instruction *previous;
if (fs->pc > fs->lasttarget) { /* no jumps to current position? */ if (fs->pc > fs->lasttarget) { /* no jumps to current position? */
if (fs->pc == 0) { /* function start? */ if (fs->pc == 0) { /* function start? */
if (from >= fs->nactvar) if (from >= fs->nactvar)
return; /* positions are already clean */ return; /* positions are already clean */
} }
else { else {
previous = &fs->f->code[fs->pc-1]; previous = &fs->f->code[fs->pc-1];
if (GET_OPCODE(*previous) == OP_LOADNIL) { if (GET_OPCODE(*previous) == OP_LOADNIL) {
int pfrom = GETARG_A(*previous); int pfrom = GETARG_A(*previous);
int pto = GETARG_B(*previous); int pto = GETARG_B(*previous);
if (pfrom <= from && from <= pto+1) { /* can connect both? */ if (pfrom <= from && from <= pto+1) { /* can connect both? */
if (from+n-1 > pto) if (from+n-1 > pto)
SETARG_B(*previous, from+n-1); SETARG_B(*previous, from+n-1);
return; return;
} }
} }
} }
} }
luaK_codeABC(fs, OP_LOADNIL, from, from+n-1, 0); /* else no optimization */ luaK_codeABC(fs, OP_LOADNIL, from, from+n-1, 0); /* else no optimization */
} }
int luaK_jump (FuncState *fs) { int luaK_jump (FuncState *fs) {
int jpc = fs->jpc; /* save list of jumps to here */ int jpc = fs->jpc; /* save list of jumps to here */
int j; int j;
fs->jpc = NO_JUMP; fs->jpc = NO_JUMP;
j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP); j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP);
luaK_concat(fs, &j, jpc); /* keep them on hold */ luaK_concat(fs, &j, jpc); /* keep them on hold */
return j; return j;
} }
void luaK_ret (FuncState *fs, int first, int nret) { void luaK_ret (FuncState *fs, int first, int nret) {
luaK_codeABC(fs, OP_RETURN, first, nret+1, 0); luaK_codeABC(fs, OP_RETURN, first, nret+1, 0);
} }
static int condjump (FuncState *fs, OpCode op, int A, int B, int C) { static int condjump (FuncState *fs, OpCode op, int A, int B, int C) {
luaK_codeABC(fs, op, A, B, C); luaK_codeABC(fs, op, A, B, C);
return luaK_jump(fs); return luaK_jump(fs);
} }
static void fixjump (FuncState *fs, int pc, int dest) { static void fixjump (FuncState *fs, int pc, int dest) {
Instruction *jmp = &fs->f->code[pc]; Instruction *jmp = &fs->f->code[pc];
int offset = dest-(pc+1); int offset = dest-(pc+1);
lua_assert(dest != NO_JUMP); lua_assert(dest != NO_JUMP);
if (abs(offset) > MAXARG_sBx) if (abs(offset) > MAXARG_sBx)
luaX_syntaxerror(fs->ls, "control structure too long"); luaX_syntaxerror(fs->ls, "control structure too long");
SETARG_sBx(*jmp, offset); SETARG_sBx(*jmp, offset);
} }
/* /*
** returns current `pc' and marks it as a jump target (to avoid wrong ** returns current `pc' and marks it as a jump target (to avoid wrong
** optimizations with consecutive instructions not in the same basic block). ** optimizations with consecutive instructions not in the same basic block).
*/ */
int luaK_getlabel (FuncState *fs) { int luaK_getlabel (FuncState *fs) {
fs->lasttarget = fs->pc; fs->lasttarget = fs->pc;
return fs->pc; return fs->pc;
} }
static int getjump (FuncState *fs, int pc) { static int getjump (FuncState *fs, int pc) {
int offset = GETARG_sBx(fs->f->code[pc]); int offset = GETARG_sBx(fs->f->code[pc]);
if (offset == NO_JUMP) /* point to itself represents end of list */ if (offset == NO_JUMP) /* point to itself represents end of list */
return NO_JUMP; /* end of list */ return NO_JUMP; /* end of list */
else else
return (pc+1)+offset; /* turn offset into absolute position */ return (pc+1)+offset; /* turn offset into absolute position */
} }
static Instruction *getjumpcontrol (FuncState *fs, int pc) { static Instruction *getjumpcontrol (FuncState *fs, int pc) {
Instruction *pi = &fs->f->code[pc]; Instruction *pi = &fs->f->code[pc];
if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1)))) if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1))))
return pi-1; return pi-1;
else else
return pi; return pi;
} }
/* /*
** check whether list has any jump that do not produce a value ** check whether list has any jump that do not produce a value
** (or produce an inverted value) ** (or produce an inverted value)
*/ */
static int need_value (FuncState *fs, int list) { static int need_value (FuncState *fs, int list) {
for (; list != NO_JUMP; list = getjump(fs, list)) { for (; list != NO_JUMP; list = getjump(fs, list)) {
Instruction i = *getjumpcontrol(fs, list); Instruction i = *getjumpcontrol(fs, list);
if (GET_OPCODE(i) != OP_TESTSET) return 1; if (GET_OPCODE(i) != OP_TESTSET) return 1;
} }
return 0; /* not found */ return 0; /* not found */
} }
static int patchtestreg (FuncState *fs, int node, int reg) { static int patchtestreg (FuncState *fs, int node, int reg) {
Instruction *i = getjumpcontrol(fs, node); Instruction *i = getjumpcontrol(fs, node);
if (GET_OPCODE(*i) != OP_TESTSET) if (GET_OPCODE(*i) != OP_TESTSET)
return 0; /* cannot patch other instructions */ return 0; /* cannot patch other instructions */
if (reg != NO_REG && reg != GETARG_B(*i)) if (reg != NO_REG && reg != GETARG_B(*i))
SETARG_A(*i, reg); SETARG_A(*i, reg);
else /* no register to put value or register already has the value */ else /* no register to put value or register already has the value */
*i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i)); *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i));
return 1; return 1;
} }
static void removevalues (FuncState *fs, int list) { static void removevalues (FuncState *fs, int list) {
for (; list != NO_JUMP; list = getjump(fs, list)) for (; list != NO_JUMP; list = getjump(fs, list))
patchtestreg(fs, list, NO_REG); patchtestreg(fs, list, NO_REG);
} }
static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, static void patchlistaux (FuncState *fs, int list, int vtarget, int reg,
int dtarget) { int dtarget) {
while (list != NO_JUMP) { while (list != NO_JUMP) {
int next = getjump(fs, list); int next = getjump(fs, list);
if (patchtestreg(fs, list, reg)) if (patchtestreg(fs, list, reg))
fixjump(fs, list, vtarget); fixjump(fs, list, vtarget);
else else
fixjump(fs, list, dtarget); /* jump to default target */ fixjump(fs, list, dtarget); /* jump to default target */
list = next; list = next;
} }
} }
static void dischargejpc (FuncState *fs) { static void dischargejpc (FuncState *fs) {
patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc); patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc);
fs->jpc = NO_JUMP; fs->jpc = NO_JUMP;
} }
void luaK_patchlist (FuncState *fs, int list, int target) { void luaK_patchlist (FuncState *fs, int list, int target) {
if (target == fs->pc) if (target == fs->pc)
luaK_patchtohere(fs, list); luaK_patchtohere(fs, list);
else { else {
lua_assert(target < fs->pc); lua_assert(target < fs->pc);
patchlistaux(fs, list, target, NO_REG, target); patchlistaux(fs, list, target, NO_REG, target);
} }
} }
void luaK_patchtohere (FuncState *fs, int list) { void luaK_patchtohere (FuncState *fs, int list) {
luaK_getlabel(fs); luaK_getlabel(fs);
luaK_concat(fs, &fs->jpc, list); luaK_concat(fs, &fs->jpc, list);
} }
void luaK_concat (FuncState *fs, int *l1, int l2) { void luaK_concat (FuncState *fs, int *l1, int l2) {
if (l2 == NO_JUMP) return; if (l2 == NO_JUMP) return;
else if (*l1 == NO_JUMP) else if (*l1 == NO_JUMP)
*l1 = l2; *l1 = l2;
else { else {
int list = *l1; int list = *l1;
int next; int next;
while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */ while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */
list = next; list = next;
fixjump(fs, list, l2); fixjump(fs, list, l2);
} }
} }
void luaK_checkstack (FuncState *fs, int n) { void luaK_checkstack (FuncState *fs, int n) {
int newstack = fs->freereg + n; int newstack = fs->freereg + n;
if (newstack > fs->f->maxstacksize) { if (newstack > fs->f->maxstacksize) {
if (newstack >= MAXSTACK) if (newstack >= MAXSTACK)
luaX_syntaxerror(fs->ls, "function or expression too complex"); luaX_syntaxerror(fs->ls, "function or expression too complex");
fs->f->maxstacksize = cast_byte(newstack); fs->f->maxstacksize = cast_byte(newstack);
} }
} }
void luaK_reserveregs (FuncState *fs, int n) { void luaK_reserveregs (FuncState *fs, int n) {
luaK_checkstack(fs, n); luaK_checkstack(fs, n);
fs->freereg += n; fs->freereg += n;
} }
static void freereg (FuncState *fs, int reg) { static void freereg (FuncState *fs, int reg) {
if (!ISK(reg) && reg >= fs->nactvar) { if (!ISK(reg) && reg >= fs->nactvar) {
fs->freereg--; fs->freereg--;
lua_assert(reg == fs->freereg); lua_assert(reg == fs->freereg);
} }
} }
static void freeexp (FuncState *fs, expdesc *e) { static void freeexp (FuncState *fs, expdesc *e) {
if (e->k == VNONRELOC) if (e->k == VNONRELOC)
freereg(fs, e->u.s.info); freereg(fs, e->u.s.info);
} }
static int addk (FuncState *fs, TValue *k, TValue *v) { static int addk (FuncState *fs, TValue *k, TValue *v) {
lua_State *L = fs->L; lua_State *L = fs->L;
TValue *idx = luaH_set(L, fs->h, k); TValue *idx = luaH_set(L, fs->h, k);
Proto *f = fs->f; Proto *f = fs->f;
int oldsize = f->sizek; int oldsize = f->sizek;
if (ttisnumber(idx)) { if (ttisnumber(idx)) {
lua_assert(luaO_rawequalObj(&fs->f->k[cast_int(nvalue(idx))], v)); lua_assert(luaO_rawequalObj(&fs->f->k[cast_int(nvalue(idx))], v));
return cast_int(nvalue(idx)); return cast_int(nvalue(idx));
} }
else { /* constant not found; create a new entry */ else { /* constant not found; create a new entry */
setnvalue(idx, cast_num(fs->nk)); setnvalue(idx, cast_num(fs->nk));
luaM_growvector(L, f->k, fs->nk, f->sizek, TValue, luaM_growvector(L, f->k, fs->nk, f->sizek, TValue,
MAXARG_Bx, "constant table overflow"); MAXARG_Bx, "constant table overflow");
while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]);
setobj(L, &f->k[fs->nk], v); setobj(L, &f->k[fs->nk], v);
luaC_barrier(L, f, v); luaC_barrier(L, f, v);
return fs->nk++; return fs->nk++;
} }
} }
int luaK_stringK (FuncState *fs, TString *s) { int luaK_stringK (FuncState *fs, TString *s) {
TValue o; TValue o;
setsvalue(fs->L, &o, s); setsvalue(fs->L, &o, s);
return addk(fs, &o, &o); return addk(fs, &o, &o);
} }
int luaK_numberK (FuncState *fs, lua_Number r) { int luaK_numberK (FuncState *fs, lua_Number r) {
TValue o; TValue o;
setnvalue(&o, r); setnvalue(&o, r);
return addk(fs, &o, &o); return addk(fs, &o, &o);
} }
static int boolK (FuncState *fs, int b) { static int boolK (FuncState *fs, int b) {
TValue o; TValue o;
setbvalue(&o, b); setbvalue(&o, b);
return addk(fs, &o, &o); return addk(fs, &o, &o);
} }
static int nilK (FuncState *fs) { static int nilK (FuncState *fs) {
TValue k, v; TValue k, v;
setnilvalue(&v); setnilvalue(&v);
/* cannot use nil as key; instead use table itself to represent nil */ /* cannot use nil as key; instead use table itself to represent nil */
sethvalue(fs->L, &k, fs->h); sethvalue(fs->L, &k, fs->h);
return addk(fs, &k, &v); return addk(fs, &k, &v);
} }
void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) { void luaK_setreturns (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? */
SETARG_C(getcode(fs, e), nresults+1); SETARG_C(getcode(fs, e), nresults+1);
} }
else if (e->k == VVARARG) { else if (e->k == VVARARG) {
SETARG_B(getcode(fs, e), nresults+1); SETARG_B(getcode(fs, e), nresults+1);
SETARG_A(getcode(fs, e), fs->freereg); SETARG_A(getcode(fs, e), fs->freereg);
luaK_reserveregs(fs, 1); luaK_reserveregs(fs, 1);
} }
} }
void luaK_setoneret (FuncState *fs, expdesc *e) { void luaK_setoneret (FuncState *fs, expdesc *e) {
if (e->k == VCALL) { /* expression is an open function call? */ if (e->k == VCALL) { /* expression is an open function call? */
e->k = VNONRELOC; e->k = VNONRELOC;
e->u.s.info = GETARG_A(getcode(fs, e)); e->u.s.info = GETARG_A(getcode(fs, e));
} }
else if (e->k == VVARARG) { else if (e->k == VVARARG) {
SETARG_B(getcode(fs, e), 2); SETARG_B(getcode(fs, e), 2);
e->k = VRELOCABLE; /* can relocate its simple result */ e->k = VRELOCABLE; /* can relocate its simple result */
} }
} }
void luaK_dischargevars (FuncState *fs, expdesc *e) { void luaK_dischargevars (FuncState *fs, expdesc *e) {
switch (e->k) { switch (e->k) {
case VLOCAL: { case VLOCAL: {
e->k = VNONRELOC; e->k = VNONRELOC;
break; break;
} }
case VUPVAL: { case VUPVAL: {
e->u.s.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.s.info, 0); e->u.s.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.s.info, 0);
e->k = VRELOCABLE; e->k = VRELOCABLE;
break; break;
} }
case VGLOBAL: { case VGLOBAL: {
e->u.s.info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->u.s.info); e->u.s.info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->u.s.info);
e->k = VRELOCABLE; e->k = VRELOCABLE;
break; break;
} }
case VINDEXED: { case VINDEXED: {
freereg(fs, e->u.s.aux); freereg(fs, e->u.s.aux);
freereg(fs, e->u.s.info); freereg(fs, e->u.s.info);
e->u.s.info = luaK_codeABC(fs, OP_GETTABLE, 0, e->u.s.info, e->u.s.aux); e->u.s.info = luaK_codeABC(fs, OP_GETTABLE, 0, e->u.s.info, e->u.s.aux);
e->k = VRELOCABLE; e->k = VRELOCABLE;
break; break;
} }
case VVARARG: case VVARARG:
case VCALL: { case VCALL: {
luaK_setoneret(fs, e); luaK_setoneret(fs, e);
break; break;
} }
default: break; /* there is one value available (somewhere) */ default: break; /* there is one value available (somewhere) */
} }
} }
static int code_label (FuncState *fs, int A, int b, int jump) { static int code_label (FuncState *fs, int A, int b, int jump) {
luaK_getlabel(fs); /* those instructions may be jump targets */ luaK_getlabel(fs); /* those instructions may be jump targets */
return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump); return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump);
} }
static void discharge2reg (FuncState *fs, expdesc *e, int reg) { static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
luaK_dischargevars(fs, e); luaK_dischargevars(fs, e);
switch (e->k) { switch (e->k) {
case VNIL: { case VNIL: {
luaK_nil(fs, reg, 1); luaK_nil(fs, reg, 1);
break; break;
} }
case VFALSE: case VTRUE: { case VFALSE: case VTRUE: {
luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0); luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);
break; break;
} }
case VK: { case VK: {
luaK_codeABx(fs, OP_LOADK, reg, e->u.s.info); luaK_codeABx(fs, OP_LOADK, reg, e->u.s.info);
break; break;
} }
case VKNUM: { case VKNUM: {
luaK_codeABx(fs, OP_LOADK, reg, luaK_numberK(fs, e->u.nval)); luaK_codeABx(fs, OP_LOADK, reg, luaK_numberK(fs, e->u.nval));
break; break;
} }
case VRELOCABLE: { case VRELOCABLE: {
Instruction *pc = &getcode(fs, e); Instruction *pc = &getcode(fs, e);
SETARG_A(*pc, reg); SETARG_A(*pc, reg);
break; break;
} }
case VNONRELOC: { case VNONRELOC: {
if (reg != e->u.s.info) if (reg != e->u.s.info)
luaK_codeABC(fs, OP_MOVE, reg, e->u.s.info, 0); luaK_codeABC(fs, OP_MOVE, reg, e->u.s.info, 0);
break; break;
} }
default: { default: {
lua_assert(e->k == VVOID || e->k == VJMP); lua_assert(e->k == VVOID || e->k == VJMP);
return; /* nothing to do... */ return; /* nothing to do... */
} }
} }
e->u.s.info = reg; e->u.s.info = reg;
e->k = VNONRELOC; e->k = VNONRELOC;
} }
static void discharge2anyreg (FuncState *fs, expdesc *e) { static void discharge2anyreg (FuncState *fs, expdesc *e) {
if (e->k != VNONRELOC) { if (e->k != VNONRELOC) {
luaK_reserveregs(fs, 1); luaK_reserveregs(fs, 1);
discharge2reg(fs, e, fs->freereg-1); discharge2reg(fs, e, fs->freereg-1);
} }
} }
static void exp2reg (FuncState *fs, expdesc *e, int reg) { static void exp2reg (FuncState *fs, expdesc *e, int reg) {
discharge2reg(fs, e, reg); discharge2reg(fs, e, reg);
if (e->k == VJMP) if (e->k == VJMP)
luaK_concat(fs, &e->t, e->u.s.info); /* put this jump in `t' list */ luaK_concat(fs, &e->t, e->u.s.info); /* put this jump in `t' list */
if (hasjumps(e)) { if (hasjumps(e)) {
int final; /* position after whole expression */ int final; /* position after whole expression */
int p_f = NO_JUMP; /* position of an eventual LOAD false */ int p_f = NO_JUMP; /* position of an eventual LOAD false */
int p_t = NO_JUMP; /* position of an eventual LOAD true */ int p_t = NO_JUMP; /* position of an eventual LOAD true */
if (need_value(fs, e->t) || need_value(fs, e->f)) { if (need_value(fs, e->t) || need_value(fs, e->f)) {
int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs); int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs);
p_f = code_label(fs, reg, 0, 1); p_f = code_label(fs, reg, 0, 1);
p_t = code_label(fs, reg, 1, 0); p_t = code_label(fs, reg, 1, 0);
luaK_patchtohere(fs, fj); luaK_patchtohere(fs, fj);
} }
final = luaK_getlabel(fs); final = luaK_getlabel(fs);
patchlistaux(fs, e->f, final, reg, p_f); patchlistaux(fs, e->f, final, reg, p_f);
patchlistaux(fs, e->t, final, reg, p_t); patchlistaux(fs, e->t, final, reg, p_t);
} }
e->f = e->t = NO_JUMP; e->f = e->t = NO_JUMP;
e->u.s.info = reg; e->u.s.info = reg;
e->k = VNONRELOC; e->k = VNONRELOC;
} }
void luaK_exp2nextreg (FuncState *fs, expdesc *e) { void luaK_exp2nextreg (FuncState *fs, expdesc *e) {
luaK_dischargevars(fs, e); luaK_dischargevars(fs, e);
freeexp(fs, e); freeexp(fs, e);
luaK_reserveregs(fs, 1); luaK_reserveregs(fs, 1);
exp2reg(fs, e, fs->freereg - 1); exp2reg(fs, e, fs->freereg - 1);
} }
int luaK_exp2anyreg (FuncState *fs, expdesc *e) { int luaK_exp2anyreg (FuncState *fs, expdesc *e) {
luaK_dischargevars(fs, e); luaK_dischargevars(fs, e);
if (e->k == VNONRELOC) { if (e->k == VNONRELOC) {
if (!hasjumps(e)) return e->u.s.info; /* exp is already in a register */ if (!hasjumps(e)) return e->u.s.info; /* exp is already in a register */
if (e->u.s.info >= fs->nactvar) { /* reg. is not a local? */ if (e->u.s.info >= fs->nactvar) { /* reg. is not a local? */
exp2reg(fs, e, e->u.s.info); /* put value on it */ exp2reg(fs, e, e->u.s.info); /* put value on it */
return e->u.s.info; return e->u.s.info;
} }
} }
luaK_exp2nextreg(fs, e); /* default */ luaK_exp2nextreg(fs, e); /* default */
return e->u.s.info; return e->u.s.info;
} }
void luaK_exp2val (FuncState *fs, expdesc *e) { void luaK_exp2val (FuncState *fs, expdesc *e) {
if (hasjumps(e)) if (hasjumps(e))
luaK_exp2anyreg(fs, e); luaK_exp2anyreg(fs, e);
else else
luaK_dischargevars(fs, e); luaK_dischargevars(fs, e);
} }
int luaK_exp2RK (FuncState *fs, expdesc *e) { int luaK_exp2RK (FuncState *fs, expdesc *e) {
luaK_exp2val(fs, e); luaK_exp2val(fs, e);
switch (e->k) { switch (e->k) {
case VKNUM: case VKNUM:
case VTRUE: case VTRUE:
case VFALSE: case VFALSE:
case VNIL: { case VNIL: {
if (fs->nk <= MAXINDEXRK) { /* constant fit in RK operand? */ if (fs->nk <= MAXINDEXRK) { /* constant fit in RK operand? */
e->u.s.info = (e->k == VNIL) ? nilK(fs) : e->u.s.info = (e->k == VNIL) ? nilK(fs) :
(e->k == VKNUM) ? luaK_numberK(fs, e->u.nval) : (e->k == VKNUM) ? luaK_numberK(fs, e->u.nval) :
boolK(fs, (e->k == VTRUE)); boolK(fs, (e->k == VTRUE));
e->k = VK; e->k = VK;
return RKASK(e->u.s.info); return RKASK(e->u.s.info);
} }
else break; else break;
} }
case VK: { case VK: {
if (e->u.s.info <= MAXINDEXRK) /* constant fit in argC? */ if (e->u.s.info <= MAXINDEXRK) /* constant fit in argC? */
return RKASK(e->u.s.info); return RKASK(e->u.s.info);
else break; else break;
} }
default: break; default: break;
} }
/* not a constant in the right range: put it in a register */ /* not a constant in the right range: put it in a register */
return luaK_exp2anyreg(fs, e); return luaK_exp2anyreg(fs, e);
} }
void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
switch (var->k) { switch (var->k) {
case VLOCAL: { case VLOCAL: {
freeexp(fs, ex); freeexp(fs, ex);
exp2reg(fs, ex, var->u.s.info); exp2reg(fs, ex, var->u.s.info);
return; return;
} }
case VUPVAL: { case VUPVAL: {
int e = luaK_exp2anyreg(fs, ex); int e = luaK_exp2anyreg(fs, ex);
luaK_codeABC(fs, OP_SETUPVAL, e, var->u.s.info, 0); luaK_codeABC(fs, OP_SETUPVAL, e, var->u.s.info, 0);
break; break;
} }
case VGLOBAL: { case VGLOBAL: {
int e = luaK_exp2anyreg(fs, ex); int e = luaK_exp2anyreg(fs, ex);
luaK_codeABx(fs, OP_SETGLOBAL, e, var->u.s.info); luaK_codeABx(fs, OP_SETGLOBAL, e, var->u.s.info);
break; break;
} }
case VINDEXED: { case VINDEXED: {
int e = luaK_exp2RK(fs, ex); int e = luaK_exp2RK(fs, ex);
luaK_codeABC(fs, OP_SETTABLE, var->u.s.info, var->u.s.aux, e); luaK_codeABC(fs, OP_SETTABLE, var->u.s.info, var->u.s.aux, e);
break; break;
} }
default: { default: {
lua_assert(0); /* invalid var kind to store */ lua_assert(0); /* invalid var kind to store */
break; break;
} }
} }
freeexp(fs, ex); freeexp(fs, ex);
} }
void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
int func; int func;
luaK_exp2anyreg(fs, e); luaK_exp2anyreg(fs, e);
freeexp(fs, e); freeexp(fs, e);
func = fs->freereg; func = fs->freereg;
luaK_reserveregs(fs, 2); luaK_reserveregs(fs, 2);
luaK_codeABC(fs, OP_SELF, func, e->u.s.info, luaK_exp2RK(fs, key)); luaK_codeABC(fs, OP_SELF, func, e->u.s.info, luaK_exp2RK(fs, key));
freeexp(fs, key); freeexp(fs, key);
e->u.s.info = func; e->u.s.info = func;
e->k = VNONRELOC; e->k = VNONRELOC;
} }
static void invertjump (FuncState *fs, expdesc *e) { static void invertjump (FuncState *fs, expdesc *e) {
Instruction *pc = getjumpcontrol(fs, e->u.s.info); Instruction *pc = getjumpcontrol(fs, e->u.s.info);
lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET && lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET &&
GET_OPCODE(*pc) != OP_TEST); GET_OPCODE(*pc) != OP_TEST);
SETARG_A(*pc, !(GETARG_A(*pc))); SETARG_A(*pc, !(GETARG_A(*pc)));
} }
static int jumponcond (FuncState *fs, expdesc *e, int cond) { static int jumponcond (FuncState *fs, expdesc *e, int cond) {
if (e->k == VRELOCABLE) { if (e->k == VRELOCABLE) {
Instruction ie = getcode(fs, e); Instruction ie = getcode(fs, e);
if (GET_OPCODE(ie) == OP_NOT) { if (GET_OPCODE(ie) == OP_NOT) {
fs->pc--; /* remove previous OP_NOT */ fs->pc--; /* remove previous OP_NOT */
return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond); return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond);
} }
/* else go through */ /* else go through */
} }
discharge2anyreg(fs, e); discharge2anyreg(fs, e);
freeexp(fs, e); freeexp(fs, e);
return condjump(fs, OP_TESTSET, NO_REG, e->u.s.info, cond); return condjump(fs, OP_TESTSET, NO_REG, e->u.s.info, cond);
} }
void luaK_goiftrue (FuncState *fs, expdesc *e) { void luaK_goiftrue (FuncState *fs, expdesc *e) {
int pc; /* pc of last jump */ int pc; /* pc of last jump */
luaK_dischargevars(fs, e); luaK_dischargevars(fs, e);
switch (e->k) { switch (e->k) {
case VK: case VKNUM: case VTRUE: { case VK: case VKNUM: case VTRUE: {
pc = NO_JUMP; /* always true; do nothing */ pc = NO_JUMP; /* always true; do nothing */
break; break;
} }
case VFALSE: { case VJMP: {
pc = luaK_jump(fs); /* always jump */ invertjump(fs, e);
break; pc = e->u.s.info;
} break;
case VJMP: { }
invertjump(fs, e); default: {
pc = e->u.s.info; pc = jumponcond(fs, e, 0);
break; break;
} }
default: { }
pc = jumponcond(fs, e, 0); luaK_concat(fs, &e->f, pc); /* insert last jump in `f' list */
break; luaK_patchtohere(fs, e->t);
} e->t = NO_JUMP;
} }
luaK_concat(fs, &e->f, pc); /* insert last jump in `f' list */
luaK_patchtohere(fs, e->t);
e->t = NO_JUMP; static void luaK_goiffalse (FuncState *fs, expdesc *e) {
} int pc; /* pc of last jump */
luaK_dischargevars(fs, e);
switch (e->k) {
static void luaK_goiffalse (FuncState *fs, expdesc *e) { case VNIL: case VFALSE: {
int pc; /* pc of last jump */ pc = NO_JUMP; /* always false; do nothing */
luaK_dischargevars(fs, e); break;
switch (e->k) { }
case VNIL: case VFALSE: { case VJMP: {
pc = NO_JUMP; /* always false; do nothing */ pc = e->u.s.info;
break; break;
} }
case VTRUE: { default: {
pc = luaK_jump(fs); /* always jump */ pc = jumponcond(fs, e, 1);
break; break;
} }
case VJMP: { }
pc = e->u.s.info; luaK_concat(fs, &e->t, pc); /* insert last jump in `t' list */
break; luaK_patchtohere(fs, e->f);
} e->f = NO_JUMP;
default: { }
pc = jumponcond(fs, e, 1);
break;
} static void codenot (FuncState *fs, expdesc *e) {
} luaK_dischargevars(fs, e);
luaK_concat(fs, &e->t, pc); /* insert last jump in `t' list */ switch (e->k) {
luaK_patchtohere(fs, e->f); case VNIL: case VFALSE: {
e->f = NO_JUMP; e->k = VTRUE;
} break;
}
case VK: case VKNUM: case VTRUE: {
static void codenot (FuncState *fs, expdesc *e) { e->k = VFALSE;
luaK_dischargevars(fs, e); break;
switch (e->k) { }
case VNIL: case VFALSE: { case VJMP: {
e->k = VTRUE; invertjump(fs, e);
break; break;
} }
case VK: case VKNUM: case VTRUE: { case VRELOCABLE:
e->k = VFALSE; case VNONRELOC: {
break; discharge2anyreg(fs, e);
} freeexp(fs, e);
case VJMP: { e->u.s.info = luaK_codeABC(fs, OP_NOT, 0, e->u.s.info, 0);
invertjump(fs, e); e->k = VRELOCABLE;
break; break;
} }
case VRELOCABLE: default: {
case VNONRELOC: { lua_assert(0); /* cannot happen */
discharge2anyreg(fs, e); break;
freeexp(fs, e); }
e->u.s.info = luaK_codeABC(fs, OP_NOT, 0, e->u.s.info, 0); }
e->k = VRELOCABLE; /* interchange true and false lists */
break; { int temp = e->f; e->f = e->t; e->t = temp; }
} removevalues(fs, e->f);
default: { removevalues(fs, e->t);
lua_assert(0); /* cannot happen */ }
break;
}
} void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
/* interchange true and false lists */ t->u.s.aux = luaK_exp2RK(fs, k);
{ int temp = e->f; e->f = e->t; e->t = temp; } t->k = VINDEXED;
removevalues(fs, e->f); }
removevalues(fs, e->t);
}
static int constfolding (OpCode op, expdesc *e1, expdesc *e2) {
lua_Number v1, v2, r;
void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { if (!isnumeral(e1) || !isnumeral(e2)) return 0;
t->u.s.aux = luaK_exp2RK(fs, k); v1 = e1->u.nval;
t->k = VINDEXED; v2 = e2->u.nval;
} switch (op) {
case OP_ADD: r = luai_numadd(v1, v2); break;
case OP_SUB: r = luai_numsub(v1, v2); break;
static int constfolding (OpCode op, expdesc *e1, expdesc *e2) { case OP_MUL: r = luai_nummul(v1, v2); break;
lua_Number v1, v2, r; case OP_DIV:
if (!isnumeral(e1) || !isnumeral(e2)) return 0; if (v2 == 0) return 0; /* do not attempt to divide by 0 */
v1 = e1->u.nval; r = luai_numdiv(v1, v2); break;
v2 = e2->u.nval; case OP_MOD:
switch (op) { if (v2 == 0) return 0; /* do not attempt to divide by 0 */
case OP_ADD: r = luai_numadd(v1, v2); break; r = luai_nummod(v1, v2); break;
case OP_SUB: r = luai_numsub(v1, v2); break; case OP_POW: r = luai_numpow(v1, v2); break;
case OP_MUL: r = luai_nummul(v1, v2); break; case OP_UNM: r = luai_numunm(v1); break;
case OP_DIV: case OP_LEN: return 0; /* no constant folding for 'len' */
if (v2 == 0) return 0; /* do not attempt to divide by 0 */ default: lua_assert(0); r = 0; break;
r = luai_numdiv(v1, v2); break; }
case OP_MOD: if (luai_numisnan(r)) return 0; /* do not attempt to produce NaN */
if (v2 == 0) return 0; /* do not attempt to divide by 0 */ e1->u.nval = r;
r = luai_nummod(v1, v2); break; return 1;
case OP_POW: r = luai_numpow(v1, v2); break; }
case OP_UNM: r = luai_numunm(v1); break;
case OP_LEN: return 0; /* no constant folding for 'len' */
default: lua_assert(0); r = 0; break; static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) {
} if (constfolding(op, e1, e2))
if (luai_numisnan(r)) return 0; /* do not attempt to produce NaN */ return;
e1->u.nval = r; else {
return 1; int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0;
} int o1 = luaK_exp2RK(fs, e1);
if (o1 > o2) {
freeexp(fs, e1);
static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) { freeexp(fs, e2);
if (constfolding(op, e1, e2)) }
return; else {
else { freeexp(fs, e2);
int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0; freeexp(fs, e1);
int o1 = luaK_exp2RK(fs, e1); }
if (o1 > o2) { e1->u.s.info = luaK_codeABC(fs, op, 0, o1, o2);
freeexp(fs, e1); e1->k = VRELOCABLE;
freeexp(fs, e2); }
} }
else {
freeexp(fs, e2);
freeexp(fs, e1); static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1,
} expdesc *e2) {
e1->u.s.info = luaK_codeABC(fs, op, 0, o1, o2); int o1 = luaK_exp2RK(fs, e1);
e1->k = VRELOCABLE; int o2 = luaK_exp2RK(fs, e2);
} freeexp(fs, e2);
} freeexp(fs, e1);
if (cond == 0 && op != OP_EQ) {
int temp; /* exchange args to replace by `<' or `<=' */
static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1, temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */
expdesc *e2) { cond = 1;
int o1 = luaK_exp2RK(fs, e1); }
int o2 = luaK_exp2RK(fs, e2); e1->u.s.info = condjump(fs, op, cond, o1, o2);
freeexp(fs, e2); e1->k = VJMP;
freeexp(fs, e1); }
if (cond == 0 && op != OP_EQ) {
int temp; /* exchange args to replace by `<' or `<=' */
temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */ void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) {
cond = 1; expdesc e2;
} e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0;
e1->u.s.info = condjump(fs, op, cond, o1, o2); switch (op) {
e1->k = VJMP; case OPR_MINUS: {
} if (!isnumeral(e))
luaK_exp2anyreg(fs, e); /* cannot operate on non-numeric constants */
codearith(fs, OP_UNM, e, &e2);
void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) { break;
expdesc e2; }
e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0; case OPR_NOT: codenot(fs, e); break;
switch (op) { case OPR_LEN: {
case OPR_MINUS: { luaK_exp2anyreg(fs, e); /* cannot operate on constants */
if (!isnumeral(e)) codearith(fs, OP_LEN, e, &e2);
luaK_exp2anyreg(fs, e); /* cannot operate on non-numeric constants */ break;
codearith(fs, OP_UNM, e, &e2); }
break; default: lua_assert(0);
} }
case OPR_NOT: codenot(fs, e); break; }
case OPR_LEN: {
luaK_exp2anyreg(fs, e); /* cannot operate on constants */
codearith(fs, OP_LEN, e, &e2); void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
break; switch (op) {
} case OPR_AND: {
default: lua_assert(0); luaK_goiftrue(fs, v);
} break;
} }
case OPR_OR: {
luaK_goiffalse(fs, v);
void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { break;
switch (op) { }
case OPR_AND: { case OPR_CONCAT: {
luaK_goiftrue(fs, v); luaK_exp2nextreg(fs, v); /* operand must be on the `stack' */
break; break;
} }
case OPR_OR: { case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV:
luaK_goiffalse(fs, v); case OPR_MOD: case OPR_POW: {
break; if (!isnumeral(v)) luaK_exp2RK(fs, v);
} break;
case OPR_CONCAT: { }
luaK_exp2nextreg(fs, v); /* operand must be on the `stack' */ default: {
break; luaK_exp2RK(fs, v);
} break;
case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: }
case OPR_MOD: case OPR_POW: { }
if (!isnumeral(v)) luaK_exp2RK(fs, v); }
break;
}
default: { void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) {
luaK_exp2RK(fs, v); switch (op) {
break; case OPR_AND: {
} lua_assert(e1->t == NO_JUMP); /* list must be closed */
} luaK_dischargevars(fs, e2);
} luaK_concat(fs, &e2->f, e1->f);
*e1 = *e2;
break;
void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) { }
switch (op) { case OPR_OR: {
case OPR_AND: { lua_assert(e1->f == NO_JUMP); /* list must be closed */
lua_assert(e1->t == NO_JUMP); /* list must be closed */ luaK_dischargevars(fs, e2);
luaK_dischargevars(fs, e2); luaK_concat(fs, &e2->t, e1->t);
luaK_concat(fs, &e2->f, e1->f); *e1 = *e2;
*e1 = *e2; break;
break; }
} case OPR_CONCAT: {
case OPR_OR: { luaK_exp2val(fs, e2);
lua_assert(e1->f == NO_JUMP); /* list must be closed */ if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) {
luaK_dischargevars(fs, e2); lua_assert(e1->u.s.info == GETARG_B(getcode(fs, e2))-1);
luaK_concat(fs, &e2->t, e1->t); freeexp(fs, e1);
*e1 = *e2; SETARG_B(getcode(fs, e2), e1->u.s.info);
break; e1->k = VRELOCABLE; e1->u.s.info = e2->u.s.info;
} }
case OPR_CONCAT: { else {
luaK_exp2val(fs, e2); luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */
if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) { codearith(fs, OP_CONCAT, e1, e2);
lua_assert(e1->u.s.info == GETARG_B(getcode(fs, e2))-1); }
freeexp(fs, e1); break;
SETARG_B(getcode(fs, e2), e1->u.s.info); }
e1->k = VRELOCABLE; e1->u.s.info = e2->u.s.info; case OPR_ADD: codearith(fs, OP_ADD, e1, e2); break;
} case OPR_SUB: codearith(fs, OP_SUB, e1, e2); break;
else { case OPR_MUL: codearith(fs, OP_MUL, e1, e2); break;
luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ case OPR_DIV: codearith(fs, OP_DIV, e1, e2); break;
codearith(fs, OP_CONCAT, e1, e2); case OPR_MOD: codearith(fs, OP_MOD, e1, e2); break;
} case OPR_POW: codearith(fs, OP_POW, e1, e2); break;
break; case OPR_EQ: codecomp(fs, OP_EQ, 1, e1, e2); break;
} case OPR_NE: codecomp(fs, OP_EQ, 0, e1, e2); break;
case OPR_ADD: codearith(fs, OP_ADD, e1, e2); break; case OPR_LT: codecomp(fs, OP_LT, 1, e1, e2); break;
case OPR_SUB: codearith(fs, OP_SUB, e1, e2); break; case OPR_LE: codecomp(fs, OP_LE, 1, e1, e2); break;
case OPR_MUL: codearith(fs, OP_MUL, e1, e2); break; case OPR_GT: codecomp(fs, OP_LT, 0, e1, e2); break;
case OPR_DIV: codearith(fs, OP_DIV, e1, e2); break; case OPR_GE: codecomp(fs, OP_LE, 0, e1, e2); break;
case OPR_MOD: codearith(fs, OP_MOD, e1, e2); break; default: lua_assert(0);
case OPR_POW: codearith(fs, OP_POW, e1, e2); break; }
case OPR_EQ: codecomp(fs, OP_EQ, 1, e1, e2); break; }
case OPR_NE: codecomp(fs, OP_EQ, 0, e1, e2); break;
case OPR_LT: codecomp(fs, OP_LT, 1, e1, e2); break;
case OPR_LE: codecomp(fs, OP_LE, 1, e1, e2); break; void luaK_fixline (FuncState *fs, int line) {
case OPR_GT: codecomp(fs, OP_LT, 0, e1, e2); break; fs->f->lineinfo[fs->pc - 1] = line;
case OPR_GE: codecomp(fs, OP_LE, 0, e1, e2); break; }
default: lua_assert(0);
}
} static int luaK_code (FuncState *fs, Instruction i, int line) {
Proto *f = fs->f;
dischargejpc(fs); /* `pc' will change */
void luaK_fixline (FuncState *fs, int line) { /* put new instruction in code array */
fs->f->lineinfo[fs->pc - 1] = line; luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction,
} MAX_INT, "code size overflow");
f->code[fs->pc] = i;
/* save corresponding line information */
static int luaK_code (FuncState *fs, Instruction i, int line) { luaM_growvector(fs->L, f->lineinfo, fs->pc, f->sizelineinfo, int,
Proto *f = fs->f; MAX_INT, "code size overflow");
dischargejpc(fs); /* `pc' will change */ f->lineinfo[fs->pc] = line;
/* put new instruction in code array */ return fs->pc++;
luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction, }
MAX_INT, "code size overflow");
f->code[fs->pc] = i;
/* save corresponding line information */ int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) {
luaM_growvector(fs->L, f->lineinfo, fs->pc, f->sizelineinfo, int, lua_assert(getOpMode(o) == iABC);
MAX_INT, "code size overflow"); lua_assert(getBMode(o) != OpArgN || b == 0);
f->lineinfo[fs->pc] = line; lua_assert(getCMode(o) != OpArgN || c == 0);
return fs->pc++; return luaK_code(fs, CREATE_ABC(o, a, b, c), fs->ls->lastline);
} }
int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) { int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) {
lua_assert(getOpMode(o) == iABC); lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx);
lua_assert(getBMode(o) != OpArgN || b == 0); lua_assert(getCMode(o) == OpArgN);
lua_assert(getCMode(o) != OpArgN || c == 0); return luaK_code(fs, CREATE_ABx(o, a, bc), fs->ls->lastline);
return luaK_code(fs, CREATE_ABC(o, a, b, c), fs->ls->lastline); }
}
void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) {
int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1;
lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); int b = (tostore == LUA_MULTRET) ? 0 : tostore;
lua_assert(getCMode(o) == OpArgN); lua_assert(tostore != 0);
return luaK_code(fs, CREATE_ABx(o, a, bc), fs->ls->lastline); if (c <= MAXARG_C)
} luaK_codeABC(fs, OP_SETLIST, base, b, c);
else {
luaK_codeABC(fs, OP_SETLIST, base, b, 0);
void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { luaK_code(fs, cast(Instruction, c), fs->ls->lastline);
int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1; }
int b = (tostore == LUA_MULTRET) ? 0 : tostore; fs->freereg = base + 1; /* free registers with list values */
lua_assert(tostore != 0); }
if (c <= MAXARG_C)
luaK_codeABC(fs, OP_SETLIST, base, b, c);
else {
luaK_codeABC(fs, OP_SETLIST, base, b, 0);
luaK_code(fs, cast(Instruction, c), fs->ls->lastline);
}
fs->freereg = base + 1; /* free registers with list values */
}
/* /*
** $Id: ldblib.c,v 1.104.1.3 2008/01/21 13:11:21 roberto Exp $ ** $Id: ldblib.c,v 1.104.1.4 2009/08/04 18:50:18 roberto Exp $
** Interface from Lua to its debug API ** Interface from Lua to its debug API
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#define ldblib_c #define ldblib_c
#define LUA_LIB #define LUA_LIB
#include "lua.h" #include "lua.h"
#include "lauxlib.h" #include "lauxlib.h"
#include "lualib.h" #include "lualib.h"
static int db_getregistry (lua_State *L) { static int db_getregistry (lua_State *L) {
lua_pushvalue(L, LUA_REGISTRYINDEX); lua_pushvalue(L, LUA_REGISTRYINDEX);
return 1; return 1;
} }
static int db_getmetatable (lua_State *L) { static int db_getmetatable (lua_State *L) {
luaL_checkany(L, 1); luaL_checkany(L, 1);
if (!lua_getmetatable(L, 1)) { if (!lua_getmetatable(L, 1)) {
lua_pushnil(L); /* no metatable */ lua_pushnil(L); /* no metatable */
} }
return 1; return 1;
} }
static int db_setmetatable (lua_State *L) { static int db_setmetatable (lua_State *L) {
int t = lua_type(L, 2); int t = lua_type(L, 2);
luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
"nil or table expected"); "nil or table expected");
lua_settop(L, 2); lua_settop(L, 2);
lua_pushboolean(L, lua_setmetatable(L, 1)); lua_pushboolean(L, lua_setmetatable(L, 1));
return 1; return 1;
} }
static int db_getfenv (lua_State *L) { static int db_getfenv (lua_State *L) {
lua_getfenv(L, 1); luaL_checkany(L, 1);
return 1; lua_getfenv(L, 1);
} return 1;
}
static int db_setfenv (lua_State *L) {
luaL_checktype(L, 2, LUA_TTABLE); static int db_setfenv (lua_State *L) {
lua_settop(L, 2); luaL_checktype(L, 2, LUA_TTABLE);
if (lua_setfenv(L, 1) == 0) lua_settop(L, 2);
luaL_error(L, LUA_QL("setfenv") if (lua_setfenv(L, 1) == 0)
" cannot change environment of given object"); luaL_error(L, LUA_QL("setfenv")
return 1; " cannot change environment of given object");
} return 1;
}
static void settabss (lua_State *L, const char *i, const char *v) {
lua_pushstring(L, v); static void settabss (lua_State *L, const char *i, const char *v) {
lua_setfield(L, -2, i); lua_pushstring(L, v);
} lua_setfield(L, -2, i);
}
static void settabsi (lua_State *L, const char *i, int v) {
lua_pushinteger(L, v); static void settabsi (lua_State *L, const char *i, int v) {
lua_setfield(L, -2, i); lua_pushinteger(L, v);
} lua_setfield(L, -2, i);
}
static lua_State *getthread (lua_State *L, int *arg) {
if (lua_isthread(L, 1)) { static lua_State *getthread (lua_State *L, int *arg) {
*arg = 1; if (lua_isthread(L, 1)) {
return lua_tothread(L, 1); *arg = 1;
} return lua_tothread(L, 1);
else { }
*arg = 0; else {
return L; *arg = 0;
} return L;
} }
}
static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) {
if (L == L1) { static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) {
lua_pushvalue(L, -2); if (L == L1) {
lua_remove(L, -3); lua_pushvalue(L, -2);
} lua_remove(L, -3);
else }
lua_xmove(L1, L, 1); else
lua_setfield(L, -2, fname); lua_xmove(L1, L, 1);
} lua_setfield(L, -2, fname);
}
static int db_getinfo (lua_State *L) {
lua_Debug ar; static int db_getinfo (lua_State *L) {
int arg; lua_Debug ar;
lua_State *L1 = getthread(L, &arg); int arg;
const char *options = luaL_optstring(L, arg+2, "flnSu"); lua_State *L1 = getthread(L, &arg);
if (lua_isnumber(L, arg+1)) { const char *options = luaL_optstring(L, arg+2, "flnSu");
if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) { if (lua_isnumber(L, arg+1)) {
lua_pushnil(L); /* level out of range */ if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) {
return 1; lua_pushnil(L); /* level out of range */
} return 1;
} }
else if (lua_isfunction(L, arg+1)) { }
lua_pushfstring(L, ">%s", options); else if (lua_isfunction(L, arg+1)) {
options = lua_tostring(L, -1); lua_pushfstring(L, ">%s", options);
lua_pushvalue(L, arg+1); options = lua_tostring(L, -1);
lua_xmove(L, L1, 1); lua_pushvalue(L, arg+1);
} lua_xmove(L, L1, 1);
else }
return luaL_argerror(L, arg+1, "function or level expected"); else
if (!lua_getinfo(L1, options, &ar)) return luaL_argerror(L, arg+1, "function or level expected");
return luaL_argerror(L, arg+2, "invalid option"); if (!lua_getinfo(L1, options, &ar))
lua_createtable(L, 0, 2); return luaL_argerror(L, arg+2, "invalid option");
if (strchr(options, 'S')) { lua_createtable(L, 0, 2);
settabss(L, "source", ar.source); if (strchr(options, 'S')) {
settabss(L, "short_src", ar.short_src); settabss(L, "source", ar.source);
settabsi(L, "linedefined", ar.linedefined); settabss(L, "short_src", ar.short_src);
settabsi(L, "lastlinedefined", ar.lastlinedefined); settabsi(L, "linedefined", ar.linedefined);
settabss(L, "what", ar.what); settabsi(L, "lastlinedefined", ar.lastlinedefined);
} settabss(L, "what", ar.what);
if (strchr(options, 'l')) }
settabsi(L, "currentline", ar.currentline); if (strchr(options, 'l'))
if (strchr(options, 'u')) settabsi(L, "currentline", ar.currentline);
settabsi(L, "nups", ar.nups); if (strchr(options, 'u'))
if (strchr(options, 'n')) { settabsi(L, "nups", ar.nups);
settabss(L, "name", ar.name); if (strchr(options, 'n')) {
settabss(L, "namewhat", ar.namewhat); settabss(L, "name", ar.name);
} settabss(L, "namewhat", ar.namewhat);
if (strchr(options, 'L')) }
treatstackoption(L, L1, "activelines"); if (strchr(options, 'L'))
if (strchr(options, 'f')) treatstackoption(L, L1, "activelines");
treatstackoption(L, L1, "func"); if (strchr(options, 'f'))
return 1; /* return table */ treatstackoption(L, L1, "func");
} return 1; /* return table */
}
static int db_getlocal (lua_State *L) {
int arg; static int db_getlocal (lua_State *L) {
lua_State *L1 = getthread(L, &arg); int arg;
lua_Debug ar; lua_State *L1 = getthread(L, &arg);
const char *name; lua_Debug ar;
if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ const char *name;
return luaL_argerror(L, arg+1, "level out of range"); if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */
name = lua_getlocal(L1, &ar, luaL_checkint(L, arg+2)); return luaL_argerror(L, arg+1, "level out of range");
if (name) { name = lua_getlocal(L1, &ar, luaL_checkint(L, arg+2));
lua_xmove(L1, L, 1); if (name) {
lua_pushstring(L, name); lua_xmove(L1, L, 1);
lua_pushvalue(L, -2); lua_pushstring(L, name);
return 2; lua_pushvalue(L, -2);
} return 2;
else { }
lua_pushnil(L); else {
return 1; lua_pushnil(L);
} return 1;
} }
}
static int db_setlocal (lua_State *L) {
int arg; static int db_setlocal (lua_State *L) {
lua_State *L1 = getthread(L, &arg); int arg;
lua_Debug ar; lua_State *L1 = getthread(L, &arg);
if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ lua_Debug ar;
return luaL_argerror(L, arg+1, "level out of range"); if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */
luaL_checkany(L, arg+3); return luaL_argerror(L, arg+1, "level out of range");
lua_settop(L, arg+3); luaL_checkany(L, arg+3);
lua_xmove(L, L1, 1); lua_settop(L, arg+3);
lua_pushstring(L, lua_setlocal(L1, &ar, luaL_checkint(L, arg+2))); lua_xmove(L, L1, 1);
return 1; lua_pushstring(L, lua_setlocal(L1, &ar, luaL_checkint(L, arg+2)));
} return 1;
}
static int auxupvalue (lua_State *L, int get) {
const char *name; static int auxupvalue (lua_State *L, int get) {
int n = luaL_checkint(L, 2); const char *name;
luaL_checktype(L, 1, LUA_TFUNCTION); int n = luaL_checkint(L, 2);
if (lua_iscfunction(L, 1)) return 0; /* cannot touch C upvalues from Lua */ luaL_checktype(L, 1, LUA_TFUNCTION);
name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); if (lua_iscfunction(L, 1)) return 0; /* cannot touch C upvalues from Lua */
if (name == NULL) return 0; name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n);
lua_pushstring(L, name); if (name == NULL) return 0;
lua_insert(L, -(get+1)); lua_pushstring(L, name);
return get + 1; lua_insert(L, -(get+1));
} return get + 1;
}
static int db_getupvalue (lua_State *L) {
return auxupvalue(L, 1); static int db_getupvalue (lua_State *L) {
} return auxupvalue(L, 1);
}
static int db_setupvalue (lua_State *L) {
luaL_checkany(L, 3); static int db_setupvalue (lua_State *L) {
return auxupvalue(L, 0); luaL_checkany(L, 3);
} return auxupvalue(L, 0);
}
static const char KEY_HOOK = 'h';
static const char KEY_HOOK = 'h';
static void hookf (lua_State *L, lua_Debug *ar) {
static const char *const hooknames[] = static void hookf (lua_State *L, lua_Debug *ar) {
{"call", "return", "line", "count", "tail return"}; static const char *const hooknames[] =
lua_pushlightuserdata(L, (void *)&KEY_HOOK); {"call", "return", "line", "count", "tail return"};
lua_rawget(L, LUA_REGISTRYINDEX); lua_pushlightuserdata(L, (void *)&KEY_HOOK);
lua_pushlightuserdata(L, L); lua_rawget(L, LUA_REGISTRYINDEX);
lua_rawget(L, -2); lua_pushlightuserdata(L, L);
if (lua_isfunction(L, -1)) { lua_rawget(L, -2);
lua_pushstring(L, hooknames[(int)ar->event]); if (lua_isfunction(L, -1)) {
if (ar->currentline >= 0) lua_pushstring(L, hooknames[(int)ar->event]);
lua_pushinteger(L, ar->currentline); if (ar->currentline >= 0)
else lua_pushnil(L); lua_pushinteger(L, ar->currentline);
lua_assert(lua_getinfo(L, "lS", ar)); else lua_pushnil(L);
lua_call(L, 2, 0); lua_assert(lua_getinfo(L, "lS", ar));
} lua_call(L, 2, 0);
} }
}
static int makemask (const char *smask, int count) {
int mask = 0; static int makemask (const char *smask, int count) {
if (strchr(smask, 'c')) mask |= LUA_MASKCALL; int mask = 0;
if (strchr(smask, 'r')) mask |= LUA_MASKRET; if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
if (strchr(smask, 'l')) mask |= LUA_MASKLINE; if (strchr(smask, 'r')) mask |= LUA_MASKRET;
if (count > 0) mask |= LUA_MASKCOUNT; if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
return mask; if (count > 0) mask |= LUA_MASKCOUNT;
} return mask;
}
static char *unmakemask (int mask, char *smask) {
int i = 0; static char *unmakemask (int mask, char *smask) {
if (mask & LUA_MASKCALL) smask[i++] = 'c'; int i = 0;
if (mask & LUA_MASKRET) smask[i++] = 'r'; if (mask & LUA_MASKCALL) smask[i++] = 'c';
if (mask & LUA_MASKLINE) smask[i++] = 'l'; if (mask & LUA_MASKRET) smask[i++] = 'r';
smask[i] = '\0'; if (mask & LUA_MASKLINE) smask[i++] = 'l';
return smask; smask[i] = '\0';
} return smask;
}
static void gethooktable (lua_State *L) {
lua_pushlightuserdata(L, (void *)&KEY_HOOK); static void gethooktable (lua_State *L) {
lua_rawget(L, LUA_REGISTRYINDEX); lua_pushlightuserdata(L, (void *)&KEY_HOOK);
if (!lua_istable(L, -1)) { lua_rawget(L, LUA_REGISTRYINDEX);
lua_pop(L, 1); if (!lua_istable(L, -1)) {
lua_createtable(L, 0, 1); lua_pop(L, 1);
lua_pushlightuserdata(L, (void *)&KEY_HOOK); lua_createtable(L, 0, 1);
lua_pushvalue(L, -2); lua_pushlightuserdata(L, (void *)&KEY_HOOK);
lua_rawset(L, LUA_REGISTRYINDEX); lua_pushvalue(L, -2);
} lua_rawset(L, LUA_REGISTRYINDEX);
} }
}
static int db_sethook (lua_State *L) {
int arg, mask, count; static int db_sethook (lua_State *L) {
lua_Hook func; int arg, mask, count;
lua_State *L1 = getthread(L, &arg); lua_Hook func;
if (lua_isnoneornil(L, arg+1)) { lua_State *L1 = getthread(L, &arg);
lua_settop(L, arg+1); if (lua_isnoneornil(L, arg+1)) {
func = NULL; mask = 0; count = 0; /* turn off hooks */ lua_settop(L, arg+1);
} func = NULL; mask = 0; count = 0; /* turn off hooks */
else { }
const char *smask = luaL_checkstring(L, arg+2); else {
luaL_checktype(L, arg+1, LUA_TFUNCTION); const char *smask = luaL_checkstring(L, arg+2);
count = luaL_optint(L, arg+3, 0); luaL_checktype(L, arg+1, LUA_TFUNCTION);
func = hookf; mask = makemask(smask, count); count = luaL_optint(L, arg+3, 0);
} func = hookf; mask = makemask(smask, count);
gethooktable(L); }
lua_pushlightuserdata(L, L1); gethooktable(L);
lua_pushvalue(L, arg+1); lua_pushlightuserdata(L, L1);
lua_rawset(L, -3); /* set new hook */ lua_pushvalue(L, arg+1);
lua_pop(L, 1); /* remove hook table */ lua_rawset(L, -3); /* set new hook */
lua_sethook(L1, func, mask, count); /* set hooks */ lua_pop(L, 1); /* remove hook table */
return 0; lua_sethook(L1, func, mask, count); /* set hooks */
} return 0;
}
static int db_gethook (lua_State *L) {
int arg; static int db_gethook (lua_State *L) {
lua_State *L1 = getthread(L, &arg); int arg;
char buff[5]; lua_State *L1 = getthread(L, &arg);
int mask = lua_gethookmask(L1); char buff[5];
lua_Hook hook = lua_gethook(L1); int mask = lua_gethookmask(L1);
if (hook != NULL && hook != hookf) /* external hook? */ lua_Hook hook = lua_gethook(L1);
lua_pushliteral(L, "external hook"); if (hook != NULL && hook != hookf) /* external hook? */
else { lua_pushliteral(L, "external hook");
gethooktable(L); else {
lua_pushlightuserdata(L, L1); gethooktable(L);
lua_rawget(L, -2); /* get hook */ lua_pushlightuserdata(L, L1);
lua_remove(L, -2); /* remove hook table */ lua_rawget(L, -2); /* get hook */
} lua_remove(L, -2); /* remove hook table */
lua_pushstring(L, unmakemask(mask, buff)); }
lua_pushinteger(L, lua_gethookcount(L1)); lua_pushstring(L, unmakemask(mask, buff));
return 3; lua_pushinteger(L, lua_gethookcount(L1));
} return 3;
}
static int db_debug (lua_State *L) {
for (;;) { static int db_debug (lua_State *L) {
char buffer[250]; for (;;) {
fputs("lua_debug> ", stderr); char buffer[250];
if (fgets(buffer, sizeof(buffer), stdin) == 0 || fputs("lua_debug> ", stderr);
strcmp(buffer, "cont\n") == 0) if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
return 0; strcmp(buffer, "cont\n") == 0)
if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") || return 0;
lua_pcall(L, 0, 0, 0)) { if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
fputs(lua_tostring(L, -1), stderr); lua_pcall(L, 0, 0, 0)) {
fputs("\n", stderr); fputs(lua_tostring(L, -1), stderr);
} fputs("\n", stderr);
lua_settop(L, 0); /* remove eventual returns */ }
} lua_settop(L, 0); /* remove eventual returns */
} }
}
#define LEVELS1 12 /* size of the first part of the stack */
#define LEVELS2 10 /* size of the second part of the stack */ #define LEVELS1 12 /* size of the first part of the stack */
#define LEVELS2 10 /* size of the second part of the stack */
static int db_errorfb (lua_State *L) {
int level; static int db_errorfb (lua_State *L) {
int firstpart = 1; /* still before eventual `...' */ int level;
int arg; int firstpart = 1; /* still before eventual `...' */
lua_State *L1 = getthread(L, &arg); int arg;
lua_Debug ar; lua_State *L1 = getthread(L, &arg);
if (lua_isnumber(L, arg+2)) { lua_Debug ar;
level = (int)lua_tointeger(L, arg+2); if (lua_isnumber(L, arg+2)) {
lua_pop(L, 1); level = (int)lua_tointeger(L, arg+2);
} lua_pop(L, 1);
else }
level = (L == L1) ? 1 : 0; /* level 0 may be this own function */ else
if (lua_gettop(L) == arg) level = (L == L1) ? 1 : 0; /* level 0 may be this own function */
lua_pushliteral(L, ""); if (lua_gettop(L) == arg)
else if (!lua_isstring(L, arg+1)) return 1; /* message is not a string */ lua_pushliteral(L, "");
else lua_pushliteral(L, "\n"); else if (!lua_isstring(L, arg+1)) return 1; /* message is not a string */
lua_pushliteral(L, "stack traceback:"); else lua_pushliteral(L, "\n");
while (lua_getstack(L1, level++, &ar)) { lua_pushliteral(L, "stack traceback:");
if (level > LEVELS1 && firstpart) { while (lua_getstack(L1, level++, &ar)) {
/* no more than `LEVELS2' more levels? */ if (level > LEVELS1 && firstpart) {
if (!lua_getstack(L1, level+LEVELS2, &ar)) /* no more than `LEVELS2' more levels? */
level--; /* keep going */ if (!lua_getstack(L1, level+LEVELS2, &ar))
else { level--; /* keep going */
lua_pushliteral(L, "\n\t..."); /* too many levels */ else {
while (lua_getstack(L1, level+LEVELS2, &ar)) /* find last levels */ lua_pushliteral(L, "\n\t..."); /* too many levels */
level++; while (lua_getstack(L1, level+LEVELS2, &ar)) /* find last levels */
} level++;
firstpart = 0; }
continue; firstpart = 0;
} continue;
lua_pushliteral(L, "\n\t"); }
lua_getinfo(L1, "Snl", &ar); lua_pushliteral(L, "\n\t");
lua_pushfstring(L, "%s:", ar.short_src); lua_getinfo(L1, "Snl", &ar);
if (ar.currentline > 0) lua_pushfstring(L, "%s:", ar.short_src);
lua_pushfstring(L, "%d:", ar.currentline); if (ar.currentline > 0)
if (*ar.namewhat != '\0') /* is there a name? */ lua_pushfstring(L, "%d:", ar.currentline);
lua_pushfstring(L, " in function " LUA_QS, ar.name); if (*ar.namewhat != '\0') /* is there a name? */
else { lua_pushfstring(L, " in function " LUA_QS, ar.name);
if (*ar.what == 'm') /* main? */ else {
lua_pushfstring(L, " in main chunk"); if (*ar.what == 'm') /* main? */
else if (*ar.what == 'C' || *ar.what == 't') lua_pushfstring(L, " in main chunk");
lua_pushliteral(L, " ?"); /* C function or tail call */ else if (*ar.what == 'C' || *ar.what == 't')
else lua_pushliteral(L, " ?"); /* C function or tail call */
lua_pushfstring(L, " in function <%s:%d>", else
ar.short_src, ar.linedefined); lua_pushfstring(L, " in function <%s:%d>",
} ar.short_src, ar.linedefined);
lua_concat(L, lua_gettop(L) - arg); }
} lua_concat(L, lua_gettop(L) - arg);
lua_concat(L, lua_gettop(L) - arg); }
return 1; lua_concat(L, lua_gettop(L) - arg);
} return 1;
}
static const luaL_Reg dblib[] = {
{"debug", db_debug}, static const luaL_Reg dblib[] = {
{"getfenv", db_getfenv}, {"debug", db_debug},
{"gethook", db_gethook}, {"getfenv", db_getfenv},
{"getinfo", db_getinfo}, {"gethook", db_gethook},
{"getlocal", db_getlocal}, {"getinfo", db_getinfo},
{"getregistry", db_getregistry}, {"getlocal", db_getlocal},
{"getmetatable", db_getmetatable}, {"getregistry", db_getregistry},
{"getupvalue", db_getupvalue}, {"getmetatable", db_getmetatable},
{"setfenv", db_setfenv}, {"getupvalue", db_getupvalue},
{"sethook", db_sethook}, {"setfenv", db_setfenv},
{"setlocal", db_setlocal}, {"sethook", db_sethook},
{"setmetatable", db_setmetatable}, {"setlocal", db_setlocal},
{"setupvalue", db_setupvalue}, {"setmetatable", db_setmetatable},
{"traceback", db_errorfb}, {"setupvalue", db_setupvalue},
{NULL, NULL} {"traceback", db_errorfb},
}; {NULL, NULL}
};
LUALIB_API int luaopen_debug (lua_State *L) {
luaL_register(L, LUA_DBLIBNAME, dblib); LUALIB_API int luaopen_debug (lua_State *L) {
return 1; luaL_register(L, LUA_DBLIBNAME, dblib);
} return 1;
}
/* /*
** $Id: liolib.c,v 2.73.1.3 2008/01/18 17:47:43 roberto Exp $ ** $Id: liolib.c,v 2.73.1.4 2010/05/14 15:33:51 roberto Exp $
** Standard I/O (and system) library ** Standard I/O (and system) library
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#define liolib_c #define liolib_c
#define LUA_LIB #define LUA_LIB
#include "lua.h" #include "lua.h"
#include "lauxlib.h" #include "lauxlib.h"
#include "lualib.h" #include "lualib.h"
#define IO_INPUT 1 #define IO_INPUT 1
#define IO_OUTPUT 2 #define IO_OUTPUT 2
static const char *const fnames[] = {"input", "output"}; static const char *const fnames[] = {"input", "output"};
static int pushresult (lua_State *L, int i, const char *filename) { static int pushresult (lua_State *L, int i, const char *filename) {
int en = errno; /* calls to Lua API may change this value */ int en = errno; /* calls to Lua API may change this value */
if (i) { if (i) {
lua_pushboolean(L, 1); lua_pushboolean(L, 1);
return 1; return 1;
} }
else { else {
lua_pushnil(L); lua_pushnil(L);
if (filename) if (filename)
lua_pushfstring(L, "%s: %s", filename, strerror(en)); lua_pushfstring(L, "%s: %s", filename, strerror(en));
else else
lua_pushfstring(L, "%s", strerror(en)); lua_pushfstring(L, "%s", strerror(en));
lua_pushinteger(L, en); lua_pushinteger(L, en);
return 3; return 3;
} }
} }
static void fileerror (lua_State *L, int arg, const char *filename) { static void fileerror (lua_State *L, int arg, const char *filename) {
lua_pushfstring(L, "%s: %s", filename, strerror(errno)); lua_pushfstring(L, "%s: %s", filename, strerror(errno));
luaL_argerror(L, arg, lua_tostring(L, -1)); luaL_argerror(L, arg, lua_tostring(L, -1));
} }
#define tofilep(L) ((FILE **)luaL_checkudata(L, 1, LUA_FILEHANDLE)) #define tofilep(L) ((FILE **)luaL_checkudata(L, 1, LUA_FILEHANDLE))
static int io_type (lua_State *L) { static int io_type (lua_State *L) {
void *ud; void *ud;
luaL_checkany(L, 1); luaL_checkany(L, 1);
ud = lua_touserdata(L, 1); ud = lua_touserdata(L, 1);
lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE); lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE);
if (ud == NULL || !lua_getmetatable(L, 1) || !lua_rawequal(L, -2, -1)) if (ud == NULL || !lua_getmetatable(L, 1) || !lua_rawequal(L, -2, -1))
lua_pushnil(L); /* not a file */ lua_pushnil(L); /* not a file */
else if (*((FILE **)ud) == NULL) else if (*((FILE **)ud) == NULL)
lua_pushliteral(L, "closed file"); lua_pushliteral(L, "closed file");
else else
lua_pushliteral(L, "file"); lua_pushliteral(L, "file");
return 1; return 1;
} }
static FILE *tofile (lua_State *L) { static FILE *tofile (lua_State *L) {
FILE **f = tofilep(L); FILE **f = tofilep(L);
if (*f == NULL) if (*f == NULL)
luaL_error(L, "attempt to use a closed file"); luaL_error(L, "attempt to use a closed file");
return *f; return *f;
} }
/* /*
** When creating file handles, always creates a `closed' file handle ** When creating file handles, always creates a `closed' file handle
** before opening the actual file; so, if there is a memory error, the ** before opening the actual file; so, if there is a memory error, the
** file is not left opened. ** file is not left opened.
*/ */
static FILE **newfile (lua_State *L) { static FILE **newfile (lua_State *L) {
FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *)); FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *));
*pf = NULL; /* file handle is currently `closed' */ *pf = NULL; /* file handle is currently `closed' */
luaL_getmetatable(L, LUA_FILEHANDLE); luaL_getmetatable(L, LUA_FILEHANDLE);
lua_setmetatable(L, -2); lua_setmetatable(L, -2);
return pf; return pf;
} }
/* /*
** function to (not) close the standard files stdin, stdout, and stderr ** function to (not) close the standard files stdin, stdout, and stderr
*/ */
static int io_noclose (lua_State *L) { static int io_noclose (lua_State *L) {
lua_pushnil(L); lua_pushnil(L);
lua_pushliteral(L, "cannot close standard file"); lua_pushliteral(L, "cannot close standard file");
return 2; return 2;
} }
/* /*
** function to close 'popen' files ** function to close 'popen' files
*/ */
static int io_pclose (lua_State *L) { static int io_pclose (lua_State *L) {
FILE **p = tofilep(L); FILE **p = tofilep(L);
int ok = lua_pclose(L, *p); int ok = lua_pclose(L, *p);
*p = NULL; *p = NULL;
return pushresult(L, ok, NULL); return pushresult(L, ok, NULL);
} }
/* /*
** function to close regular files ** function to close regular files
*/ */
static int io_fclose (lua_State *L) { static int io_fclose (lua_State *L) {
FILE **p = tofilep(L); FILE **p = tofilep(L);
int ok = (fclose(*p) == 0); int ok = (fclose(*p) == 0);
*p = NULL; *p = NULL;
return pushresult(L, ok, NULL); return pushresult(L, ok, NULL);
} }
static int aux_close (lua_State *L) { static int aux_close (lua_State *L) {
lua_getfenv(L, 1); lua_getfenv(L, 1);
lua_getfield(L, -1, "__close"); lua_getfield(L, -1, "__close");
return (lua_tocfunction(L, -1))(L); return (lua_tocfunction(L, -1))(L);
} }
static int io_close (lua_State *L) { static int io_close (lua_State *L) {
if (lua_isnone(L, 1)) if (lua_isnone(L, 1))
lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT); lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT);
tofile(L); /* make sure argument is a file */ tofile(L); /* make sure argument is a file */
return aux_close(L); return aux_close(L);
} }
static int io_gc (lua_State *L) { static int io_gc (lua_State *L) {
FILE *f = *tofilep(L); FILE *f = *tofilep(L);
/* ignore closed files */ /* ignore closed files */
if (f != NULL) if (f != NULL)
aux_close(L); aux_close(L);
return 0; return 0;
} }
static int io_tostring (lua_State *L) { static int io_tostring (lua_State *L) {
FILE *f = *tofilep(L); FILE *f = *tofilep(L);
if (f == NULL) if (f == NULL)
lua_pushliteral(L, "file (closed)"); lua_pushliteral(L, "file (closed)");
else else
lua_pushfstring(L, "file (%p)", f); lua_pushfstring(L, "file (%p)", f);
return 1; return 1;
} }
static int io_open (lua_State *L) { static int io_open (lua_State *L) {
const char *filename = luaL_checkstring(L, 1); const char *filename = luaL_checkstring(L, 1);
const char *mode = luaL_optstring(L, 2, "r"); const char *mode = luaL_optstring(L, 2, "r");
FILE **pf = newfile(L); FILE **pf = newfile(L);
*pf = fopen(filename, mode); *pf = fopen(filename, mode);
return (*pf == NULL) ? pushresult(L, 0, filename) : 1; return (*pf == NULL) ? pushresult(L, 0, filename) : 1;
} }
/* /*
** this function has a separated environment, which defines the ** this function has a separated environment, which defines the
** correct __close for 'popen' files ** correct __close for 'popen' files
*/ */
static int io_popen (lua_State *L) { static int io_popen (lua_State *L) {
const char *filename = luaL_checkstring(L, 1); const char *filename = luaL_checkstring(L, 1);
const char *mode = luaL_optstring(L, 2, "r"); const char *mode = luaL_optstring(L, 2, "r");
FILE **pf = newfile(L); FILE **pf = newfile(L);
*pf = lua_popen(L, filename, mode); *pf = lua_popen(L, filename, mode);
return (*pf == NULL) ? pushresult(L, 0, filename) : 1; return (*pf == NULL) ? pushresult(L, 0, filename) : 1;
} }
static int io_tmpfile (lua_State *L) { static int io_tmpfile (lua_State *L) {
FILE **pf = newfile(L); FILE **pf = newfile(L);
*pf = tmpfile(); *pf = tmpfile();
return (*pf == NULL) ? pushresult(L, 0, NULL) : 1; return (*pf == NULL) ? pushresult(L, 0, NULL) : 1;
} }
static FILE *getiofile (lua_State *L, int findex) { static FILE *getiofile (lua_State *L, int findex) {
FILE *f; FILE *f;
lua_rawgeti(L, LUA_ENVIRONINDEX, findex); lua_rawgeti(L, LUA_ENVIRONINDEX, findex);
f = *(FILE **)lua_touserdata(L, -1); f = *(FILE **)lua_touserdata(L, -1);
if (f == NULL) if (f == NULL)
luaL_error(L, "standard %s file is closed", fnames[findex - 1]); luaL_error(L, "standard %s file is closed", fnames[findex - 1]);
return f; return f;
} }
static int g_iofile (lua_State *L, int f, const char *mode) { static int g_iofile (lua_State *L, int f, const char *mode) {
if (!lua_isnoneornil(L, 1)) { if (!lua_isnoneornil(L, 1)) {
const char *filename = lua_tostring(L, 1); const char *filename = lua_tostring(L, 1);
if (filename) { if (filename) {
FILE **pf = newfile(L); FILE **pf = newfile(L);
*pf = fopen(filename, mode); *pf = fopen(filename, mode);
if (*pf == NULL) if (*pf == NULL)
fileerror(L, 1, filename); fileerror(L, 1, filename);
} }
else { else {
tofile(L); /* check that it's a valid file handle */ tofile(L); /* check that it's a valid file handle */
lua_pushvalue(L, 1); lua_pushvalue(L, 1);
} }
lua_rawseti(L, LUA_ENVIRONINDEX, f); lua_rawseti(L, LUA_ENVIRONINDEX, f);
} }
/* return current value */ /* return current value */
lua_rawgeti(L, LUA_ENVIRONINDEX, f); lua_rawgeti(L, LUA_ENVIRONINDEX, f);
return 1; return 1;
} }
static int io_input (lua_State *L) { static int io_input (lua_State *L) {
return g_iofile(L, IO_INPUT, "r"); return g_iofile(L, IO_INPUT, "r");
} }
static int io_output (lua_State *L) { static int io_output (lua_State *L) {
return g_iofile(L, IO_OUTPUT, "w"); return g_iofile(L, IO_OUTPUT, "w");
} }
static int io_readline (lua_State *L); static int io_readline (lua_State *L);
static void aux_lines (lua_State *L, int idx, int toclose) { static void aux_lines (lua_State *L, int idx, int toclose) {
lua_pushvalue(L, idx); lua_pushvalue(L, idx);
lua_pushboolean(L, toclose); /* close/not close file when finished */ lua_pushboolean(L, toclose); /* close/not close file when finished */
lua_pushcclosure(L, io_readline, 2); lua_pushcclosure(L, io_readline, 2);
} }
static int f_lines (lua_State *L) { static int f_lines (lua_State *L) {
tofile(L); /* check that it's a valid file handle */ tofile(L); /* check that it's a valid file handle */
aux_lines(L, 1, 0); aux_lines(L, 1, 0);
return 1; return 1;
} }
static int io_lines (lua_State *L) { static int io_lines (lua_State *L) {
if (lua_isnoneornil(L, 1)) { /* no arguments? */ if (lua_isnoneornil(L, 1)) { /* no arguments? */
/* will iterate over default input */ /* will iterate over default input */
lua_rawgeti(L, LUA_ENVIRONINDEX, IO_INPUT); lua_rawgeti(L, LUA_ENVIRONINDEX, IO_INPUT);
return f_lines(L); return f_lines(L);
} }
else { else {
const char *filename = luaL_checkstring(L, 1); const char *filename = luaL_checkstring(L, 1);
FILE **pf = newfile(L); FILE **pf = newfile(L);
*pf = fopen(filename, "r"); *pf = fopen(filename, "r");
if (*pf == NULL) if (*pf == NULL)
fileerror(L, 1, filename); fileerror(L, 1, filename);
aux_lines(L, lua_gettop(L), 1); aux_lines(L, lua_gettop(L), 1);
return 1; return 1;
} }
} }
/* /*
** {====================================================== ** {======================================================
** READ ** READ
** ======================================================= ** =======================================================
*/ */
static int read_number (lua_State *L, FILE *f) { static int read_number (lua_State *L, FILE *f) {
lua_Number d; lua_Number d;
if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) { if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) {
lua_pushnumber(L, d); lua_pushnumber(L, d);
return 1; return 1;
} }
else return 0; /* read fails */ else {
} lua_pushnil(L); /* "result" to be removed */
return 0; /* read fails */
}
static int test_eof (lua_State *L, FILE *f) { }
int c = getc(f);
ungetc(c, f);
lua_pushlstring(L, NULL, 0); static int test_eof (lua_State *L, FILE *f) {
return (c != EOF); int c = getc(f);
} ungetc(c, f);
lua_pushlstring(L, NULL, 0);
return (c != EOF);
static int read_line (lua_State *L, FILE *f) { }
luaL_Buffer b;
luaL_buffinit(L, &b);
for (;;) { static int read_line (lua_State *L, FILE *f) {
size_t l; luaL_Buffer b;
char *p = luaL_prepbuffer(&b); luaL_buffinit(L, &b);
if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */ for (;;) {
luaL_pushresult(&b); /* close buffer */ size_t l;
return (lua_objlen(L, -1) > 0); /* check whether read something */ char *p = luaL_prepbuffer(&b);
} if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */
l = strlen(p); luaL_pushresult(&b); /* close buffer */
if (l == 0 || p[l-1] != '\n') return (lua_objlen(L, -1) > 0); /* check whether read something */
luaL_addsize(&b, l); }
else { l = strlen(p);
luaL_addsize(&b, l - 1); /* do not include `eol' */ if (l == 0 || p[l-1] != '\n')
luaL_pushresult(&b); /* close buffer */ luaL_addsize(&b, l);
return 1; /* read at least an `eol' */ else {
} luaL_addsize(&b, l - 1); /* do not include `eol' */
} luaL_pushresult(&b); /* close buffer */
} return 1; /* read at least an `eol' */
}
}
static int read_chars (lua_State *L, FILE *f, size_t n) { }
size_t rlen; /* how much to read */
size_t nr; /* number of chars actually read */
luaL_Buffer b; static int read_chars (lua_State *L, FILE *f, size_t n) {
luaL_buffinit(L, &b); size_t rlen; /* how much to read */
rlen = LUAL_BUFFERSIZE; /* try to read that much each time */ size_t nr; /* number of chars actually read */
do { luaL_Buffer b;
char *p = luaL_prepbuffer(&b); luaL_buffinit(L, &b);
if (rlen > n) rlen = n; /* cannot read more than asked */ rlen = LUAL_BUFFERSIZE; /* try to read that much each time */
nr = fread(p, sizeof(char), rlen, f); do {
luaL_addsize(&b, nr); char *p = luaL_prepbuffer(&b);
n -= nr; /* still have to read `n' chars */ if (rlen > n) rlen = n; /* cannot read more than asked */
} while (n > 0 && nr == rlen); /* until end of count or eof */ nr = fread(p, sizeof(char), rlen, f);
luaL_pushresult(&b); /* close buffer */ luaL_addsize(&b, nr);
return (n == 0 || lua_objlen(L, -1) > 0); n -= nr; /* still have to read `n' chars */
} } while (n > 0 && nr == rlen); /* until end of count or eof */
luaL_pushresult(&b); /* close buffer */
return (n == 0 || lua_objlen(L, -1) > 0);
static int g_read (lua_State *L, FILE *f, int first) { }
int nargs = lua_gettop(L) - 1;
int success;
int n; static int g_read (lua_State *L, FILE *f, int first) {
clearerr(f); int nargs = lua_gettop(L) - 1;
if (nargs == 0) { /* no arguments? */ int success;
success = read_line(L, f); int n;
n = first+1; /* to return 1 result */ clearerr(f);
} if (nargs == 0) { /* no arguments? */
else { /* ensure stack space for all results and for auxlib's buffer */ success = read_line(L, f);
luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments"); n = first+1; /* to return 1 result */
success = 1; }
for (n = first; nargs-- && success; n++) { else { /* ensure stack space for all results and for auxlib's buffer */
if (lua_type(L, n) == LUA_TNUMBER) { luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments");
size_t l = (size_t)lua_tointeger(L, n); success = 1;
success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); for (n = first; nargs-- && success; n++) {
} if (lua_type(L, n) == LUA_TNUMBER) {
else { size_t l = (size_t)lua_tointeger(L, n);
const char *p = lua_tostring(L, n); success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l);
luaL_argcheck(L, p && p[0] == '*', n, "invalid option"); }
switch (p[1]) { else {
case 'n': /* number */ const char *p = lua_tostring(L, n);
success = read_number(L, f); luaL_argcheck(L, p && p[0] == '*', n, "invalid option");
break; switch (p[1]) {
case 'l': /* line */ case 'n': /* number */
success = read_line(L, f); success = read_number(L, f);
break; break;
case 'a': /* file */ case 'l': /* line */
read_chars(L, f, ~((size_t)0)); /* read MAX_SIZE_T chars */ success = read_line(L, f);
success = 1; /* always success */ break;
break; case 'a': /* file */
default: read_chars(L, f, ~((size_t)0)); /* read MAX_SIZE_T chars */
return luaL_argerror(L, n, "invalid format"); success = 1; /* always success */
} break;
} default:
} return luaL_argerror(L, n, "invalid format");
} }
if (ferror(f)) }
return pushresult(L, 0, NULL); }
if (!success) { }
lua_pop(L, 1); /* remove last result */ if (ferror(f))
lua_pushnil(L); /* push nil instead */ return pushresult(L, 0, NULL);
} if (!success) {
return n - first; lua_pop(L, 1); /* remove last result */
} lua_pushnil(L); /* push nil instead */
}
return n - first;
static int io_read (lua_State *L) { }
return g_read(L, getiofile(L, IO_INPUT), 1);
}
static int io_read (lua_State *L) {
return g_read(L, getiofile(L, IO_INPUT), 1);
static int f_read (lua_State *L) { }
return g_read(L, tofile(L), 2);
}
static int f_read (lua_State *L) {
return g_read(L, tofile(L), 2);
static int io_readline (lua_State *L) { }
FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(1));
int sucess;
if (f == NULL) /* file is already closed? */ static int io_readline (lua_State *L) {
luaL_error(L, "file is already closed"); FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(1));
sucess = read_line(L, f); int sucess;
if (ferror(f)) if (f == NULL) /* file is already closed? */
return luaL_error(L, "%s", strerror(errno)); luaL_error(L, "file is already closed");
if (sucess) return 1; sucess = read_line(L, f);
else { /* EOF */ if (ferror(f))
if (lua_toboolean(L, lua_upvalueindex(2))) { /* generator created file? */ return luaL_error(L, "%s", strerror(errno));
lua_settop(L, 0); if (sucess) return 1;
lua_pushvalue(L, lua_upvalueindex(1)); else { /* EOF */
aux_close(L); /* close it */ if (lua_toboolean(L, lua_upvalueindex(2))) { /* generator created file? */
} lua_settop(L, 0);
return 0; lua_pushvalue(L, lua_upvalueindex(1));
} aux_close(L); /* close it */
} }
return 0;
/* }====================================================== */ }
}
static int g_write (lua_State *L, FILE *f, int arg) { /* }====================================================== */
int nargs = lua_gettop(L) - 1;
int status = 1;
for (; nargs--; arg++) { static int g_write (lua_State *L, FILE *f, int arg) {
if (lua_type(L, arg) == LUA_TNUMBER) { int nargs = lua_gettop(L) - 1;
/* optimization: could be done exactly as for strings */ int status = 1;
status = status && for (; nargs--; arg++) {
fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0; if (lua_type(L, arg) == LUA_TNUMBER) {
} /* optimization: could be done exactly as for strings */
else { status = status &&
size_t l; fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0;
const char *s = luaL_checklstring(L, arg, &l); }
status = status && (fwrite(s, sizeof(char), l, f) == l); else {
} size_t l;
} const char *s = luaL_checklstring(L, arg, &l);
return pushresult(L, status, NULL); status = status && (fwrite(s, sizeof(char), l, f) == l);
} }
}
return pushresult(L, status, NULL);
static int io_write (lua_State *L) { }
return g_write(L, getiofile(L, IO_OUTPUT), 1);
}
static int io_write (lua_State *L) {
return g_write(L, getiofile(L, IO_OUTPUT), 1);
static int f_write (lua_State *L) { }
return g_write(L, tofile(L), 2);
}
static int f_write (lua_State *L) {
return g_write(L, tofile(L), 2);
static int f_seek (lua_State *L) { }
static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END};
static const char *const modenames[] = {"set", "cur", "end", NULL};
FILE *f = tofile(L); static int f_seek (lua_State *L) {
int op = luaL_checkoption(L, 2, "cur", modenames); static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END};
long offset = luaL_optlong(L, 3, 0); static const char *const modenames[] = {"set", "cur", "end", NULL};
op = fseek(f, offset, mode[op]); FILE *f = tofile(L);
if (op) int op = luaL_checkoption(L, 2, "cur", modenames);
return pushresult(L, 0, NULL); /* error */ long offset = luaL_optlong(L, 3, 0);
else { op = fseek(f, offset, mode[op]);
lua_pushinteger(L, ftell(f)); if (op)
return 1; return pushresult(L, 0, NULL); /* error */
} else {
} lua_pushinteger(L, ftell(f));
return 1;
}
static int f_setvbuf (lua_State *L) { }
static const int mode[] = {_IONBF, _IOFBF, _IOLBF};
static const char *const modenames[] = {"no", "full", "line", NULL};
FILE *f = tofile(L); static int f_setvbuf (lua_State *L) {
int op = luaL_checkoption(L, 2, NULL, modenames); static const int mode[] = {_IONBF, _IOFBF, _IOLBF};
lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); static const char *const modenames[] = {"no", "full", "line", NULL};
int res = setvbuf(f, NULL, mode[op], sz); FILE *f = tofile(L);
return pushresult(L, res == 0, NULL); int op = luaL_checkoption(L, 2, NULL, modenames);
} lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE);
int res = setvbuf(f, NULL, mode[op], sz);
return pushresult(L, res == 0, NULL);
}
static int io_flush (lua_State *L) {
return pushresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL);
}
static int io_flush (lua_State *L) {
return pushresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL);
static int f_flush (lua_State *L) { }
return pushresult(L, fflush(tofile(L)) == 0, NULL);
}
static int f_flush (lua_State *L) {
return pushresult(L, fflush(tofile(L)) == 0, NULL);
static const luaL_Reg iolib[] = { }
{"close", io_close},
{"flush", io_flush},
{"input", io_input}, static const luaL_Reg iolib[] = {
{"lines", io_lines}, {"close", io_close},
{"open", io_open}, {"flush", io_flush},
{"output", io_output}, {"input", io_input},
{"popen", io_popen}, {"lines", io_lines},
{"read", io_read}, {"open", io_open},
{"tmpfile", io_tmpfile}, {"output", io_output},
{"type", io_type}, {"popen", io_popen},
{"write", io_write}, {"read", io_read},
{NULL, NULL} {"tmpfile", io_tmpfile},
}; {"type", io_type},
{"write", io_write},
{NULL, NULL}
static const luaL_Reg flib[] = { };
{"close", io_close},
{"flush", f_flush},
{"lines", f_lines}, static const luaL_Reg flib[] = {
{"read", f_read}, {"close", io_close},
{"seek", f_seek}, {"flush", f_flush},
{"setvbuf", f_setvbuf}, {"lines", f_lines},
{"write", f_write}, {"read", f_read},
{"__gc", io_gc}, {"seek", f_seek},
{"__tostring", io_tostring}, {"setvbuf", f_setvbuf},
{NULL, NULL} {"write", f_write},
}; {"__gc", io_gc},
{"__tostring", io_tostring},
{NULL, NULL}
static void createmeta (lua_State *L) { };
luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */
lua_pushvalue(L, -1); /* push metatable */
lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ static void createmeta (lua_State *L) {
luaL_register(L, NULL, flib); /* file methods */ luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */
} lua_pushvalue(L, -1); /* push metatable */
lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
luaL_register(L, NULL, flib); /* file methods */
static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) { }
*newfile(L) = f;
if (k > 0) {
lua_pushvalue(L, -1); static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) {
lua_rawseti(L, LUA_ENVIRONINDEX, k); *newfile(L) = f;
} if (k > 0) {
lua_pushvalue(L, -2); /* copy environment */ lua_pushvalue(L, -1);
lua_setfenv(L, -2); /* set it */ lua_rawseti(L, LUA_ENVIRONINDEX, k);
lua_setfield(L, -3, fname); }
} lua_pushvalue(L, -2); /* copy environment */
lua_setfenv(L, -2); /* set it */
lua_setfield(L, -3, fname);
static void newfenv (lua_State *L, lua_CFunction cls) { }
lua_createtable(L, 0, 1);
lua_pushcfunction(L, cls);
lua_setfield(L, -2, "__close"); static void newfenv (lua_State *L, lua_CFunction cls) {
} lua_createtable(L, 0, 1);
lua_pushcfunction(L, cls);
lua_setfield(L, -2, "__close");
LUALIB_API int luaopen_io (lua_State *L) { }
createmeta(L);
/* create (private) environment (with fields IO_INPUT, IO_OUTPUT, __close) */
newfenv(L, io_fclose); LUALIB_API int luaopen_io (lua_State *L) {
lua_replace(L, LUA_ENVIRONINDEX); createmeta(L);
/* open library */ /* create (private) environment (with fields IO_INPUT, IO_OUTPUT, __close) */
luaL_register(L, LUA_IOLIBNAME, iolib); newfenv(L, io_fclose);
/* create (and set) default files */ lua_replace(L, LUA_ENVIRONINDEX);
newfenv(L, io_noclose); /* close function for default files */ /* open library */
createstdfile(L, stdin, IO_INPUT, "stdin"); luaL_register(L, LUA_IOLIBNAME, iolib);
createstdfile(L, stdout, IO_OUTPUT, "stdout"); /* create (and set) default files */
createstdfile(L, stderr, 0, "stderr"); newfenv(L, io_noclose); /* close function for default files */
lua_pop(L, 1); /* pop environment for default files */ createstdfile(L, stdin, IO_INPUT, "stdin");
lua_getfield(L, -1, "popen"); createstdfile(L, stdout, IO_OUTPUT, "stdout");
newfenv(L, io_pclose); /* create environment for 'popen' */ createstdfile(L, stderr, 0, "stderr");
lua_setfenv(L, -2); /* set fenv for 'popen' */ lua_pop(L, 1); /* pop environment for default files */
lua_pop(L, 1); /* pop 'popen' */ lua_getfield(L, -1, "popen");
return 1; newfenv(L, io_pclose); /* create environment for 'popen' */
} lua_setfenv(L, -2); /* set fenv for 'popen' */
lua_pop(L, 1); /* pop 'popen' */
return 1;
}
/* /*
** $Id: llex.c,v 2.20.1.1 2007/12/27 13:02:25 roberto Exp $ ** $Id: llex.c,v 2.20.1.2 2009/11/23 14:58:22 roberto Exp $
** Lexical Analyzer ** Lexical Analyzer
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
#include <ctype.h> #include <ctype.h>
#include <locale.h> #include <locale.h>
#include <string.h> #include <string.h>
#define llex_c #define llex_c
#define LUA_CORE #define LUA_CORE
#include "lua.h" #include "lua.h"
#include "ldo.h" #include "ldo.h"
#include "llex.h" #include "llex.h"
#include "lobject.h" #include "lobject.h"
#include "lparser.h" #include "lparser.h"
#include "lstate.h" #include "lstate.h"
#include "lstring.h" #include "lstring.h"
#include "ltable.h" #include "ltable.h"
#include "lzio.h" #include "lzio.h"
#define next(ls) (ls->current = zgetc(ls->z)) #define next(ls) (ls->current = zgetc(ls->z))
#define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r') #define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r')
/* ORDER RESERVED */ /* ORDER RESERVED */
const char *const luaX_tokens [] = { const char *const luaX_tokens [] = {
"and", "break", "do", "else", "elseif", "and", "break", "do", "else", "elseif",
"end", "false", "for", "function", "if", "end", "false", "for", "function", "if",
"in", "local", "nil", "not", "or", "repeat", "in", "local", "nil", "not", "or", "repeat",
"return", "then", "true", "until", "while", "return", "then", "true", "until", "while",
"..", "...", "==", ">=", "<=", "~=", "..", "...", "==", ">=", "<=", "~=",
"<number>", "<name>", "<string>", "<eof>", "<number>", "<name>", "<string>", "<eof>",
NULL NULL
}; };
#define save_and_next(ls) (save(ls, ls->current), next(ls)) #define save_and_next(ls) (save(ls, ls->current), next(ls))
static void save (LexState *ls, int c) { static void save (LexState *ls, int c) {
Mbuffer *b = ls->buff; Mbuffer *b = ls->buff;
if (b->n + 1 > b->buffsize) { if (b->n + 1 > b->buffsize) {
size_t newsize; size_t newsize;
if (b->buffsize >= MAX_SIZET/2) if (b->buffsize >= MAX_SIZET/2)
luaX_lexerror(ls, "lexical element too long", 0); luaX_lexerror(ls, "lexical element too long", 0);
newsize = b->buffsize * 2; newsize = b->buffsize * 2;
luaZ_resizebuffer(ls->L, b, newsize); luaZ_resizebuffer(ls->L, b, newsize);
} }
b->buffer[b->n++] = cast(char, c); b->buffer[b->n++] = cast(char, c);
} }
void luaX_init (lua_State *L) { void luaX_init (lua_State *L) {
int i; int i;
for (i=0; i<NUM_RESERVED; i++) { for (i=0; i<NUM_RESERVED; i++) {
TString *ts = luaS_new(L, luaX_tokens[i]); TString *ts = luaS_new(L, luaX_tokens[i]);
luaS_fix(ts); /* reserved words are never collected */ luaS_fix(ts); /* reserved words are never collected */
lua_assert(strlen(luaX_tokens[i])+1 <= TOKEN_LEN); lua_assert(strlen(luaX_tokens[i])+1 <= TOKEN_LEN);
ts->tsv.reserved = cast_byte(i+1); /* reserved word */ ts->tsv.reserved = cast_byte(i+1); /* reserved word */
} }
} }
#define MAXSRC 80 #define MAXSRC 80
const char *luaX_token2str (LexState *ls, int token) { const char *luaX_token2str (LexState *ls, int token) {
if (token < FIRST_RESERVED) { if (token < FIRST_RESERVED) {
lua_assert(token == cast(unsigned char, token)); lua_assert(token == cast(unsigned char, token));
return (iscntrl(token)) ? luaO_pushfstring(ls->L, "char(%d)", token) : return (iscntrl(token)) ? luaO_pushfstring(ls->L, "char(%d)", token) :
luaO_pushfstring(ls->L, "%c", token); luaO_pushfstring(ls->L, "%c", token);
} }
else else
return luaX_tokens[token-FIRST_RESERVED]; return luaX_tokens[token-FIRST_RESERVED];
} }
static const char *txtToken (LexState *ls, int token) { static const char *txtToken (LexState *ls, int token) {
switch (token) { switch (token) {
case TK_NAME: case TK_NAME:
case TK_STRING: case TK_STRING:
case TK_NUMBER: case TK_NUMBER:
save(ls, '\0'); save(ls, '\0');
return luaZ_buffer(ls->buff); return luaZ_buffer(ls->buff);
default: default:
return luaX_token2str(ls, token); return luaX_token2str(ls, token);
} }
} }
void luaX_lexerror (LexState *ls, const char *msg, int token) { void luaX_lexerror (LexState *ls, const char *msg, int token) {
char buff[MAXSRC]; char buff[MAXSRC];
luaO_chunkid(buff, getstr(ls->source), MAXSRC); luaO_chunkid(buff, getstr(ls->source), MAXSRC);
msg = luaO_pushfstring(ls->L, "%s:%d: %s", buff, ls->linenumber, msg); msg = luaO_pushfstring(ls->L, "%s:%d: %s", buff, ls->linenumber, msg);
if (token) if (token)
luaO_pushfstring(ls->L, "%s near " LUA_QS, msg, txtToken(ls, token)); luaO_pushfstring(ls->L, "%s near " LUA_QS, msg, txtToken(ls, token));
luaD_throw(ls->L, LUA_ERRSYNTAX); luaD_throw(ls->L, LUA_ERRSYNTAX);
} }
void luaX_syntaxerror (LexState *ls, const char *msg) { void luaX_syntaxerror (LexState *ls, const char *msg) {
luaX_lexerror(ls, msg, ls->t.token); luaX_lexerror(ls, msg, ls->t.token);
} }
TString *luaX_newstring (LexState *ls, const char *str, size_t l) { TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
lua_State *L = ls->L; lua_State *L = ls->L;
TString *ts = luaS_newlstr(L, str, l); TString *ts = luaS_newlstr(L, str, l);
TValue *o = luaH_setstr(L, ls->fs->h, ts); /* entry for `str' */ TValue *o = luaH_setstr(L, ls->fs->h, ts); /* entry for `str' */
if (ttisnil(o)) if (ttisnil(o)) {
setbvalue(o, 1); /* make sure `str' will not be collected */ setbvalue(o, 1); /* make sure `str' will not be collected */
return ts; luaC_checkGC(L);
} }
return ts;
}
static void inclinenumber (LexState *ls) {
int old = ls->current;
lua_assert(currIsNewline(ls)); static void inclinenumber (LexState *ls) {
next(ls); /* skip `\n' or `\r' */ int old = ls->current;
if (currIsNewline(ls) && ls->current != old) lua_assert(currIsNewline(ls));
next(ls); /* skip `\n\r' or `\r\n' */ next(ls); /* skip `\n' or `\r' */
if (++ls->linenumber >= MAX_INT) if (currIsNewline(ls) && ls->current != old)
luaX_syntaxerror(ls, "chunk has too many lines"); next(ls); /* skip `\n\r' or `\r\n' */
} if (++ls->linenumber >= MAX_INT)
luaX_syntaxerror(ls, "chunk has too many lines");
}
void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) {
ls->decpoint = '.';
ls->L = L; void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) {
ls->lookahead.token = TK_EOS; /* no look-ahead token */ ls->decpoint = '.';
ls->z = z; ls->L = L;
ls->fs = NULL; ls->lookahead.token = TK_EOS; /* no look-ahead token */
ls->linenumber = 1; ls->z = z;
ls->lastline = 1; ls->fs = NULL;
ls->source = source; ls->linenumber = 1;
luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */ ls->lastline = 1;
next(ls); /* read first char */ ls->source = source;
} luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */
next(ls); /* read first char */
}
/*
** =======================================================
** LEXICAL ANALYZER /*
** ======================================================= ** =======================================================
*/ ** LEXICAL ANALYZER
** =======================================================
*/
static int check_next (LexState *ls, const char *set) {
if (!strchr(set, ls->current))
return 0; static int check_next (LexState *ls, const char *set) {
save_and_next(ls); if (!strchr(set, ls->current))
return 1; return 0;
} save_and_next(ls);
return 1;
}
static void buffreplace (LexState *ls, char from, char to) {
size_t n = luaZ_bufflen(ls->buff);
char *p = luaZ_buffer(ls->buff); static void buffreplace (LexState *ls, char from, char to) {
while (n--) size_t n = luaZ_bufflen(ls->buff);
if (p[n] == from) p[n] = to; char *p = luaZ_buffer(ls->buff);
} while (n--)
if (p[n] == from) p[n] = to;
}
static void trydecpoint (LexState *ls, SemInfo *seminfo) {
/* format error: try to update decimal point separator */
struct lconv *cv = localeconv(); static void trydecpoint (LexState *ls, SemInfo *seminfo) {
char old = ls->decpoint; /* format error: try to update decimal point separator */
ls->decpoint = (cv ? cv->decimal_point[0] : '.'); struct lconv *cv = localeconv();
buffreplace(ls, old, ls->decpoint); /* try updated decimal separator */ char old = ls->decpoint;
if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) { ls->decpoint = (cv ? cv->decimal_point[0] : '.');
/* format error with correct decimal point: no more options */ buffreplace(ls, old, ls->decpoint); /* try updated decimal separator */
buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */ if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) {
luaX_lexerror(ls, "malformed number", TK_NUMBER); /* format error with correct decimal point: no more options */
} buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */
} luaX_lexerror(ls, "malformed number", TK_NUMBER);
}
}
/* LUA_NUMBER */
static void read_numeral (LexState *ls, SemInfo *seminfo) {
lua_assert(isdigit(ls->current)); /* LUA_NUMBER */
do { static void read_numeral (LexState *ls, SemInfo *seminfo) {
save_and_next(ls); lua_assert(isdigit(ls->current));
} while (isdigit(ls->current) || ls->current == '.'); do {
if (check_next(ls, "Ee")) /* `E'? */ save_and_next(ls);
check_next(ls, "+-"); /* optional exponent sign */ } while (isdigit(ls->current) || ls->current == '.');
while (isalnum(ls->current) || ls->current == '_') if (check_next(ls, "Ee")) /* `E'? */
save_and_next(ls); check_next(ls, "+-"); /* optional exponent sign */
save(ls, '\0'); while (isalnum(ls->current) || ls->current == '_')
buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */ save_and_next(ls);
if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) /* format error? */ save(ls, '\0');
trydecpoint(ls, seminfo); /* try to update decimal point separator */ buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */
} if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) /* format error? */
trydecpoint(ls, seminfo); /* try to update decimal point separator */
}
static int skip_sep (LexState *ls) {
int count = 0;
int s = ls->current; static int skip_sep (LexState *ls) {
lua_assert(s == '[' || s == ']'); int count = 0;
save_and_next(ls); int s = ls->current;
while (ls->current == '=') { lua_assert(s == '[' || s == ']');
save_and_next(ls); save_and_next(ls);
count++; while (ls->current == '=') {
} save_and_next(ls);
return (ls->current == s) ? count : (-count) - 1; count++;
} }
return (ls->current == s) ? count : (-count) - 1;
}
static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) {
int cont = 0;
(void)(cont); /* avoid warnings when `cont' is not used */ static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) {
save_and_next(ls); /* skip 2nd `[' */ int cont = 0;
if (currIsNewline(ls)) /* string starts with a newline? */ (void)(cont); /* avoid warnings when `cont' is not used */
inclinenumber(ls); /* skip it */ save_and_next(ls); /* skip 2nd `[' */
for (;;) { if (currIsNewline(ls)) /* string starts with a newline? */
switch (ls->current) { inclinenumber(ls); /* skip it */
case EOZ: for (;;) {
luaX_lexerror(ls, (seminfo) ? "unfinished long string" : switch (ls->current) {
"unfinished long comment", TK_EOS); case EOZ:
break; /* to avoid warnings */ luaX_lexerror(ls, (seminfo) ? "unfinished long string" :
#if defined(LUA_COMPAT_LSTR) "unfinished long comment", TK_EOS);
case '[': { break; /* to avoid warnings */
if (skip_sep(ls) == sep) { #if defined(LUA_COMPAT_LSTR)
save_and_next(ls); /* skip 2nd `[' */ case '[': {
cont++; if (skip_sep(ls) == sep) {
#if LUA_COMPAT_LSTR == 1 save_and_next(ls); /* skip 2nd `[' */
if (sep == 0) cont++;
luaX_lexerror(ls, "nesting of [[...]] is deprecated", '['); #if LUA_COMPAT_LSTR == 1
#endif if (sep == 0)
} luaX_lexerror(ls, "nesting of [[...]] is deprecated", '[');
break; #endif
} }
#endif break;
case ']': { }
if (skip_sep(ls) == sep) { #endif
save_and_next(ls); /* skip 2nd `]' */ case ']': {
#if defined(LUA_COMPAT_LSTR) && LUA_COMPAT_LSTR == 2 if (skip_sep(ls) == sep) {
cont--; save_and_next(ls); /* skip 2nd `]' */
if (sep == 0 && cont >= 0) break; #if defined(LUA_COMPAT_LSTR) && LUA_COMPAT_LSTR == 2
#endif cont--;
goto endloop; if (sep == 0 && cont >= 0) break;
} #endif
break; goto endloop;
} }
case '\n': break;
case '\r': { }
save(ls, '\n'); case '\n':
inclinenumber(ls); case '\r': {
if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */ save(ls, '\n');
break; inclinenumber(ls);
} if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */
default: { break;
if (seminfo) save_and_next(ls); }
else next(ls); default: {
} if (seminfo) save_and_next(ls);
} else next(ls);
} endloop: }
if (seminfo) }
seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep), } endloop:
luaZ_bufflen(ls->buff) - 2*(2 + sep)); if (seminfo)
} seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep),
luaZ_bufflen(ls->buff) - 2*(2 + sep));
}
static void read_string (LexState *ls, int del, SemInfo *seminfo) {
save_and_next(ls);
while (ls->current != del) { static void read_string (LexState *ls, int del, SemInfo *seminfo) {
switch (ls->current) { save_and_next(ls);
case EOZ: while (ls->current != del) {
luaX_lexerror(ls, "unfinished string", TK_EOS); switch (ls->current) {
continue; /* to avoid warnings */ case EOZ:
case '\n': luaX_lexerror(ls, "unfinished string", TK_EOS);
case '\r': continue; /* to avoid warnings */
luaX_lexerror(ls, "unfinished string", TK_STRING); case '\n':
continue; /* to avoid warnings */ case '\r':
case '\\': { luaX_lexerror(ls, "unfinished string", TK_STRING);
int c; continue; /* to avoid warnings */
next(ls); /* do not save the `\' */ case '\\': {
switch (ls->current) { int c;
case 'a': c = '\a'; break; next(ls); /* do not save the `\' */
case 'b': c = '\b'; break; switch (ls->current) {
case 'f': c = '\f'; break; case 'a': c = '\a'; break;
case 'n': c = '\n'; break; case 'b': c = '\b'; break;
case 'r': c = '\r'; break; case 'f': c = '\f'; break;
case 't': c = '\t'; break; case 'n': c = '\n'; break;
case 'v': c = '\v'; break; case 'r': c = '\r'; break;
case '\n': /* go through */ case 't': c = '\t'; break;
case '\r': save(ls, '\n'); inclinenumber(ls); continue; case 'v': c = '\v'; break;
case EOZ: continue; /* will raise an error next loop */ case '\n': /* go through */
default: { case '\r': save(ls, '\n'); inclinenumber(ls); continue;
if (!isdigit(ls->current)) case EOZ: continue; /* will raise an error next loop */
save_and_next(ls); /* handles \\, \", \', and \? */ default: {
else { /* \xxx */ if (!isdigit(ls->current))
int i = 0; save_and_next(ls); /* handles \\, \", \', and \? */
c = 0; else { /* \xxx */
do { int i = 0;
c = 10*c + (ls->current-'0'); c = 0;
next(ls); do {
} while (++i<3 && isdigit(ls->current)); c = 10*c + (ls->current-'0');
if (c > UCHAR_MAX) next(ls);
luaX_lexerror(ls, "escape sequence too large", TK_STRING); } while (++i<3 && isdigit(ls->current));
save(ls, c); if (c > UCHAR_MAX)
} luaX_lexerror(ls, "escape sequence too large", TK_STRING);
continue; save(ls, c);
} }
} continue;
save(ls, c); }
next(ls); }
continue; save(ls, c);
} next(ls);
default: continue;
save_and_next(ls); }
} default:
} save_and_next(ls);
save_and_next(ls); /* skip delimiter */ }
seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1, }
luaZ_bufflen(ls->buff) - 2); save_and_next(ls); /* skip delimiter */
} seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1,
luaZ_bufflen(ls->buff) - 2);
}
static int llex (LexState *ls, SemInfo *seminfo) {
luaZ_resetbuffer(ls->buff);
for (;;) { static int llex (LexState *ls, SemInfo *seminfo) {
switch (ls->current) { luaZ_resetbuffer(ls->buff);
case '\n': for (;;) {
case '\r': { switch (ls->current) {
inclinenumber(ls); case '\n':
continue; case '\r': {
} inclinenumber(ls);
case '-': { continue;
next(ls); }
if (ls->current != '-') return '-'; case '-': {
/* else is a comment */ next(ls);
next(ls); if (ls->current != '-') return '-';
if (ls->current == '[') { /* else is a comment */
int sep = skip_sep(ls); next(ls);
luaZ_resetbuffer(ls->buff); /* `skip_sep' may dirty the buffer */ if (ls->current == '[') {
if (sep >= 0) { int sep = skip_sep(ls);
read_long_string(ls, NULL, sep); /* long comment */ luaZ_resetbuffer(ls->buff); /* `skip_sep' may dirty the buffer */
luaZ_resetbuffer(ls->buff); if (sep >= 0) {
continue; read_long_string(ls, NULL, sep); /* long comment */
} luaZ_resetbuffer(ls->buff);
} continue;
/* else short comment */ }
while (!currIsNewline(ls) && ls->current != EOZ) }
next(ls); /* else short comment */
continue; while (!currIsNewline(ls) && ls->current != EOZ)
} next(ls);
case '[': { continue;
int sep = skip_sep(ls); }
if (sep >= 0) { case '[': {
read_long_string(ls, seminfo, sep); int sep = skip_sep(ls);
return TK_STRING; if (sep >= 0) {
} read_long_string(ls, seminfo, sep);
else if (sep == -1) return '['; return TK_STRING;
else luaX_lexerror(ls, "invalid long string delimiter", TK_STRING); }
} else if (sep == -1) return '[';
case '=': { else luaX_lexerror(ls, "invalid long string delimiter", TK_STRING);
next(ls); }
if (ls->current != '=') return '='; case '=': {
else { next(ls); return TK_EQ; } next(ls);
} if (ls->current != '=') return '=';
case '<': { else { next(ls); return TK_EQ; }
next(ls); }
if (ls->current != '=') return '<'; case '<': {
else { next(ls); return TK_LE; } next(ls);
} if (ls->current != '=') return '<';
case '>': { else { next(ls); return TK_LE; }
next(ls); }
if (ls->current != '=') return '>'; case '>': {
else { next(ls); return TK_GE; } next(ls);
} if (ls->current != '=') return '>';
case '~': { else { next(ls); return TK_GE; }
next(ls); }
if (ls->current != '=') return '~'; case '~': {
else { next(ls); return TK_NE; } next(ls);
} if (ls->current != '=') return '~';
case '"': else { next(ls); return TK_NE; }
case '\'': { }
read_string(ls, ls->current, seminfo); case '"':
return TK_STRING; case '\'': {
} read_string(ls, ls->current, seminfo);
case '.': { return TK_STRING;
save_and_next(ls); }
if (check_next(ls, ".")) { case '.': {
if (check_next(ls, ".")) save_and_next(ls);
return TK_DOTS; /* ... */ if (check_next(ls, ".")) {
else return TK_CONCAT; /* .. */ if (check_next(ls, "."))
} return TK_DOTS; /* ... */
else if (!isdigit(ls->current)) return '.'; else return TK_CONCAT; /* .. */
else { }
read_numeral(ls, seminfo); else if (!isdigit(ls->current)) return '.';
return TK_NUMBER; else {
} read_numeral(ls, seminfo);
} return TK_NUMBER;
case EOZ: { }
return TK_EOS; }
} case EOZ: {
default: { return TK_EOS;
if (isspace(ls->current)) { }
lua_assert(!currIsNewline(ls)); default: {
next(ls); if (isspace(ls->current)) {
continue; lua_assert(!currIsNewline(ls));
} next(ls);
else if (isdigit(ls->current)) { continue;
read_numeral(ls, seminfo); }
return TK_NUMBER; else if (isdigit(ls->current)) {
} read_numeral(ls, seminfo);
else if (isalpha(ls->current) || ls->current == '_') { return TK_NUMBER;
/* identifier or reserved word */ }
TString *ts; else if (isalpha(ls->current) || ls->current == '_') {
do { /* identifier or reserved word */
save_and_next(ls); TString *ts;
} while (isalnum(ls->current) || ls->current == '_'); do {
ts = luaX_newstring(ls, luaZ_buffer(ls->buff), save_and_next(ls);
luaZ_bufflen(ls->buff)); } while (isalnum(ls->current) || ls->current == '_');
if (ts->tsv.reserved > 0) /* reserved word? */ ts = luaX_newstring(ls, luaZ_buffer(ls->buff),
return ts->tsv.reserved - 1 + FIRST_RESERVED; luaZ_bufflen(ls->buff));
else { if (ts->tsv.reserved > 0) /* reserved word? */
seminfo->ts = ts; return ts->tsv.reserved - 1 + FIRST_RESERVED;
return TK_NAME; else {
} seminfo->ts = ts;
} return TK_NAME;
else { }
int c = ls->current; }
next(ls); else {
return c; /* single-char tokens (+ - / ...) */ int c = ls->current;
} next(ls);
} return c; /* single-char tokens (+ - / ...) */
} }
} }
} }
}
}
void luaX_next (LexState *ls) {
ls->lastline = ls->linenumber;
if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */ void luaX_next (LexState *ls) {
ls->t = ls->lookahead; /* use this one */ ls->lastline = ls->linenumber;
ls->lookahead.token = TK_EOS; /* and discharge it */ if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */
} ls->t = ls->lookahead; /* use this one */
else ls->lookahead.token = TK_EOS; /* and discharge it */
ls->t.token = llex(ls, &ls->t.seminfo); /* read next token */ }
} else
ls->t.token = llex(ls, &ls->t.seminfo); /* read next token */
}
void luaX_lookahead (LexState *ls) {
lua_assert(ls->lookahead.token == TK_EOS);
ls->lookahead.token = llex(ls, &ls->lookahead.seminfo); void luaX_lookahead (LexState *ls) {
} lua_assert(ls->lookahead.token == TK_EOS);
ls->lookahead.token = llex(ls, &ls->lookahead.seminfo);
}
/* /*
** $Id: loadlib.c,v 1.52.1.3 2008/08/06 13:29:28 roberto Exp $ ** $Id: loadlib.c,v 1.52.1.4 2009/09/09 13:17:16 roberto Exp $
** Dynamic library loader for Lua ** Dynamic library loader for Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
** **
** This module contains an implementation of loadlib for Unix systems ** This module contains an implementation of loadlib for Unix systems
** that have dlfcn, an implementation for Darwin (Mac OS X), an ** that have dlfcn, an implementation for Darwin (Mac OS X), an
** implementation for Windows, and a stub for other systems. ** implementation for Windows, and a stub for other systems.
*/ */
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#define loadlib_c #define loadlib_c
#define LUA_LIB #define LUA_LIB
#include "lua.h" #include "lua.h"
#include "lauxlib.h" #include "lauxlib.h"
#include "lualib.h" #include "lualib.h"
/* prefix for open functions in C libraries */ /* prefix for open functions in C libraries */
#define LUA_POF "luaopen_" #define LUA_POF "luaopen_"
/* separator for open functions in C libraries */ /* separator for open functions in C libraries */
#define LUA_OFSEP "_" #define LUA_OFSEP "_"
#define LIBPREFIX "LOADLIB: " #define LIBPREFIX "LOADLIB: "
#define POF LUA_POF #define POF LUA_POF
#define LIB_FAIL "open" #define LIB_FAIL "open"
/* error codes for ll_loadfunc */ /* error codes for ll_loadfunc */
#define ERRLIB 1 #define ERRLIB 1
#define ERRFUNC 2 #define ERRFUNC 2
#define setprogdir(L) ((void)0) #define setprogdir(L) ((void)0)
static void ll_unloadlib (void *lib); static void ll_unloadlib (void *lib);
static void *ll_load (lua_State *L, const char *path); static void *ll_load (lua_State *L, const char *path);
static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym); static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym);
#if defined(LUA_DL_DLOPEN) #if defined(LUA_DL_DLOPEN)
/* /*
** {======================================================================== ** {========================================================================
** This is an implementation of loadlib based on the dlfcn interface. ** This is an implementation of loadlib based on the dlfcn interface.
** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, ** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD,
** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least ** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least
** as an emulation layer on top of native functions. ** as an emulation layer on top of native functions.
** ========================================================================= ** =========================================================================
*/ */
#include <dlfcn.h> #include <dlfcn.h>
static void ll_unloadlib (void *lib) { static void ll_unloadlib (void *lib) {
dlclose(lib); dlclose(lib);
} }
static void *ll_load (lua_State *L, const char *path) { static void *ll_load (lua_State *L, const char *path) {
void *lib = dlopen(path, RTLD_NOW); void *lib = dlopen(path, RTLD_NOW);
if (lib == NULL) lua_pushstring(L, dlerror()); if (lib == NULL) lua_pushstring(L, dlerror());
return lib; return lib;
} }
static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {
lua_CFunction f = (lua_CFunction)dlsym(lib, sym); lua_CFunction f = (lua_CFunction)dlsym(lib, sym);
if (f == NULL) lua_pushstring(L, dlerror()); if (f == NULL) lua_pushstring(L, dlerror());
return f; return f;
} }
/* }====================================================== */ /* }====================================================== */
#elif defined(LUA_DL_DLL) #elif defined(LUA_DL_DLL)
/* /*
** {====================================================================== ** {======================================================================
** This is an implementation of loadlib for Windows using native functions. ** This is an implementation of loadlib for Windows using native functions.
** ======================================================================= ** =======================================================================
*/ */
#include <windows.h> #include <windows.h>
#undef setprogdir #undef setprogdir
static void setprogdir (lua_State *L) { static void setprogdir (lua_State *L) {
char buff[MAX_PATH + 1]; char buff[MAX_PATH + 1];
char *lb; char *lb;
DWORD nsize = sizeof(buff)/sizeof(char); DWORD nsize = sizeof(buff)/sizeof(char);
DWORD n = GetModuleFileNameA(NULL, buff, nsize); DWORD n = GetModuleFileNameA(NULL, buff, nsize);
if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL)
luaL_error(L, "unable to get ModuleFileName"); luaL_error(L, "unable to get ModuleFileName");
else { else {
*lb = '\0'; *lb = '\0';
luaL_gsub(L, lua_tostring(L, -1), LUA_EXECDIR, buff); luaL_gsub(L, lua_tostring(L, -1), LUA_EXECDIR, buff);
lua_remove(L, -2); /* remove original string */ lua_remove(L, -2); /* remove original string */
} }
} }
static void pusherror (lua_State *L) { static void pusherror (lua_State *L) {
int error = GetLastError(); int error = GetLastError();
char buffer[128]; char buffer[128];
if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, error, 0, buffer, sizeof(buffer), NULL)) NULL, error, 0, buffer, sizeof(buffer), NULL))
lua_pushstring(L, buffer); lua_pushstring(L, buffer);
else else
lua_pushfstring(L, "system error %d\n", error); lua_pushfstring(L, "system error %d\n", error);
} }
static void ll_unloadlib (void *lib) { static void ll_unloadlib (void *lib) {
FreeLibrary((HINSTANCE)lib); FreeLibrary((HINSTANCE)lib);
} }
static void *ll_load (lua_State *L, const char *path) { static void *ll_load (lua_State *L, const char *path) {
HINSTANCE lib = LoadLibraryA(path); HINSTANCE lib = LoadLibraryA(path);
if (lib == NULL) pusherror(L); if (lib == NULL) pusherror(L);
return lib; return lib;
} }
static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {
lua_CFunction f = (lua_CFunction)GetProcAddress((HINSTANCE)lib, sym); lua_CFunction f = (lua_CFunction)GetProcAddress((HINSTANCE)lib, sym);
if (f == NULL) pusherror(L); if (f == NULL) pusherror(L);
return f; return f;
} }
/* }====================================================== */ /* }====================================================== */
#elif defined(LUA_DL_DYLD) #elif defined(LUA_DL_DYLD)
/* /*
** {====================================================================== ** {======================================================================
** Native Mac OS X / Darwin Implementation ** Native Mac OS X / Darwin Implementation
** ======================================================================= ** =======================================================================
*/ */
#include <mach-o/dyld.h> #include <mach-o/dyld.h>
/* Mac appends a `_' before C function names */ /* Mac appends a `_' before C function names */
#undef POF #undef POF
#define POF "_" LUA_POF #define POF "_" LUA_POF
static void pusherror (lua_State *L) { static void pusherror (lua_State *L) {
const char *err_str; const char *err_str;
const char *err_file; const char *err_file;
NSLinkEditErrors err; NSLinkEditErrors err;
int err_num; int err_num;
NSLinkEditError(&err, &err_num, &err_file, &err_str); NSLinkEditError(&err, &err_num, &err_file, &err_str);
lua_pushstring(L, err_str); lua_pushstring(L, err_str);
} }
static const char *errorfromcode (NSObjectFileImageReturnCode ret) { static const char *errorfromcode (NSObjectFileImageReturnCode ret) {
switch (ret) { switch (ret) {
case NSObjectFileImageInappropriateFile: case NSObjectFileImageInappropriateFile:
return "file is not a bundle"; return "file is not a bundle";
case NSObjectFileImageArch: case NSObjectFileImageArch:
return "library is for wrong CPU type"; return "library is for wrong CPU type";
case NSObjectFileImageFormat: case NSObjectFileImageFormat:
return "bad format"; return "bad format";
case NSObjectFileImageAccess: case NSObjectFileImageAccess:
return "cannot access file"; return "cannot access file";
case NSObjectFileImageFailure: case NSObjectFileImageFailure:
default: default:
return "unable to load library"; return "unable to load library";
} }
} }
static void ll_unloadlib (void *lib) { static void ll_unloadlib (void *lib) {
NSUnLinkModule((NSModule)lib, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES); NSUnLinkModule((NSModule)lib, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES);
} }
static void *ll_load (lua_State *L, const char *path) { static void *ll_load (lua_State *L, const char *path) {
NSObjectFileImage img; NSObjectFileImage img;
NSObjectFileImageReturnCode ret; NSObjectFileImageReturnCode ret;
/* this would be a rare case, but prevents crashing if it happens */ /* this would be a rare case, but prevents crashing if it happens */
if(!_dyld_present()) { if(!_dyld_present()) {
lua_pushliteral(L, "dyld not present"); lua_pushliteral(L, "dyld not present");
return NULL; return NULL;
} }
ret = NSCreateObjectFileImageFromFile(path, &img); ret = NSCreateObjectFileImageFromFile(path, &img);
if (ret == NSObjectFileImageSuccess) { if (ret == NSObjectFileImageSuccess) {
NSModule mod = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE | NSModule mod = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE |
NSLINKMODULE_OPTION_RETURN_ON_ERROR); NSLINKMODULE_OPTION_RETURN_ON_ERROR);
NSDestroyObjectFileImage(img); NSDestroyObjectFileImage(img);
if (mod == NULL) pusherror(L); if (mod == NULL) pusherror(L);
return mod; return mod;
} }
lua_pushstring(L, errorfromcode(ret)); lua_pushstring(L, errorfromcode(ret));
return NULL; return NULL;
} }
static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {
NSSymbol nss = NSLookupSymbolInModule((NSModule)lib, sym); NSSymbol nss = NSLookupSymbolInModule((NSModule)lib, sym);
if (nss == NULL) { if (nss == NULL) {
lua_pushfstring(L, "symbol " LUA_QS " not found", sym); lua_pushfstring(L, "symbol " LUA_QS " not found", sym);
return NULL; return NULL;
} }
return (lua_CFunction)NSAddressOfSymbol(nss); return (lua_CFunction)NSAddressOfSymbol(nss);
} }
/* }====================================================== */ /* }====================================================== */
#else #else
/* /*
** {====================================================== ** {======================================================
** Fallback for other systems ** Fallback for other systems
** ======================================================= ** =======================================================
*/ */
#undef LIB_FAIL #undef LIB_FAIL
#define LIB_FAIL "absent" #define LIB_FAIL "absent"
#define DLMSG "dynamic libraries not enabled; check your Lua installation" #define DLMSG "dynamic libraries not enabled; check your Lua installation"
static void ll_unloadlib (void *lib) { static void ll_unloadlib (void *lib) {
(void)lib; /* to avoid warnings */ (void)lib; /* to avoid warnings */
} }
static void *ll_load (lua_State *L, const char *path) { static void *ll_load (lua_State *L, const char *path) {
(void)path; /* to avoid warnings */ (void)path; /* to avoid warnings */
lua_pushliteral(L, DLMSG); lua_pushliteral(L, DLMSG);
return NULL; return NULL;
} }
static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {
(void)lib; (void)sym; /* to avoid warnings */ (void)lib; (void)sym; /* to avoid warnings */
lua_pushliteral(L, DLMSG); lua_pushliteral(L, DLMSG);
return NULL; return NULL;
} }
/* }====================================================== */ /* }====================================================== */
#endif #endif
static void **ll_register (lua_State *L, const char *path) { static void **ll_register (lua_State *L, const char *path) {
void **plib; void **plib;
lua_pushfstring(L, "%s%s", LIBPREFIX, path); lua_pushfstring(L, "%s%s", LIBPREFIX, path);
lua_gettable(L, LUA_REGISTRYINDEX); /* check library in registry? */ lua_gettable(L, LUA_REGISTRYINDEX); /* check library in registry? */
if (!lua_isnil(L, -1)) /* is there an entry? */ if (!lua_isnil(L, -1)) /* is there an entry? */
plib = (void **)lua_touserdata(L, -1); plib = (void **)lua_touserdata(L, -1);
else { /* no entry yet; create one */ else { /* no entry yet; create one */
lua_pop(L, 1); lua_pop(L, 1);
plib = (void **)lua_newuserdata(L, sizeof(const void *)); plib = (void **)lua_newuserdata(L, sizeof(const void *));
*plib = NULL; *plib = NULL;
luaL_getmetatable(L, "_LOADLIB"); luaL_getmetatable(L, "_LOADLIB");
lua_setmetatable(L, -2); lua_setmetatable(L, -2);
lua_pushfstring(L, "%s%s", LIBPREFIX, path); lua_pushfstring(L, "%s%s", LIBPREFIX, path);
lua_pushvalue(L, -2); lua_pushvalue(L, -2);
lua_settable(L, LUA_REGISTRYINDEX); lua_settable(L, LUA_REGISTRYINDEX);
} }
return plib; return plib;
} }
/* /*
** __gc tag method: calls library's `ll_unloadlib' function with the lib ** __gc tag method: calls library's `ll_unloadlib' function with the lib
** handle ** handle
*/ */
static int gctm (lua_State *L) { static int gctm (lua_State *L) {
void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB"); void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB");
if (*lib) ll_unloadlib(*lib); if (*lib) ll_unloadlib(*lib);
*lib = NULL; /* mark library as closed */ *lib = NULL; /* mark library as closed */
return 0; return 0;
} }
static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { static int ll_loadfunc (lua_State *L, const char *path, const char *sym) {
void **reg = ll_register(L, path); void **reg = ll_register(L, path);
if (*reg == NULL) *reg = ll_load(L, path); if (*reg == NULL) *reg = ll_load(L, path);
if (*reg == NULL) if (*reg == NULL)
return ERRLIB; /* unable to load library */ return ERRLIB; /* unable to load library */
else { else {
lua_CFunction f = ll_sym(L, *reg, sym); lua_CFunction f = ll_sym(L, *reg, sym);
if (f == NULL) if (f == NULL)
return ERRFUNC; /* unable to find function */ return ERRFUNC; /* unable to find function */
lua_pushcfunction(L, f); lua_pushcfunction(L, f);
return 0; /* return function */ return 0; /* return function */
} }
} }
static int ll_loadlib (lua_State *L) { static int ll_loadlib (lua_State *L) {
const char *path = luaL_checkstring(L, 1); const char *path = luaL_checkstring(L, 1);
const char *init = luaL_checkstring(L, 2); const char *init = luaL_checkstring(L, 2);
int stat = ll_loadfunc(L, path, init); int stat = ll_loadfunc(L, path, init);
if (stat == 0) /* no errors? */ if (stat == 0) /* no errors? */
return 1; /* return the loaded function */ return 1; /* return the loaded function */
else { /* error; error message is on stack top */ else { /* error; error message is on stack top */
lua_pushnil(L); lua_pushnil(L);
lua_insert(L, -2); lua_insert(L, -2);
lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init"); lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init");
return 3; /* return nil, error message, and where */ return 3; /* return nil, error message, and where */
} }
} }
/* /*
** {====================================================== ** {======================================================
** 'require' function ** 'require' function
** ======================================================= ** =======================================================
*/ */
static int readable (const char *filename) { static int readable (const char *filename) {
FILE *f = fopen(filename, "r"); /* try to open file */ FILE *f = fopen(filename, "r"); /* try to open file */
if (f == NULL) return 0; /* open failed */ if (f == NULL) return 0; /* open failed */
fclose(f); fclose(f);
return 1; return 1;
} }
static const char *pushnexttemplate (lua_State *L, const char *path) { static const char *pushnexttemplate (lua_State *L, const char *path) {
const char *l; const char *l;
while (*path == *LUA_PATHSEP) path++; /* skip separators */ while (*path == *LUA_PATHSEP) path++; /* skip separators */
if (*path == '\0') return NULL; /* no more templates */ if (*path == '\0') return NULL; /* no more templates */
l = strchr(path, *LUA_PATHSEP); /* find next separator */ l = strchr(path, *LUA_PATHSEP); /* find next separator */
if (l == NULL) l = path + strlen(path); if (l == NULL) l = path + strlen(path);
lua_pushlstring(L, path, l - path); /* template */ lua_pushlstring(L, path, l - path); /* template */
return l; return l;
} }
static const char *findfile (lua_State *L, const char *name, static const char *findfile (lua_State *L, const char *name,
const char *pname) { const char *pname) {
const char *path; const char *path;
name = luaL_gsub(L, name, ".", LUA_DIRSEP); name = luaL_gsub(L, name, ".", LUA_DIRSEP);
lua_getfield(L, LUA_ENVIRONINDEX, pname); lua_getfield(L, LUA_ENVIRONINDEX, pname);
path = lua_tostring(L, -1); path = lua_tostring(L, -1);
if (path == NULL) if (path == NULL)
luaL_error(L, LUA_QL("package.%s") " must be a string", pname); luaL_error(L, LUA_QL("package.%s") " must be a string", pname);
lua_pushliteral(L, ""); /* error accumulator */ lua_pushliteral(L, ""); /* error accumulator */
while ((path = pushnexttemplate(L, path)) != NULL) { while ((path = pushnexttemplate(L, path)) != NULL) {
const char *filename; const char *filename;
filename = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name); filename = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name);
lua_remove(L, -2); /* remove path template */ lua_remove(L, -2); /* remove path template */
if (readable(filename)) /* does file exist and is readable? */ if (readable(filename)) /* does file exist and is readable? */
return filename; /* return that file name */ return filename; /* return that file name */
lua_pushfstring(L, "\n\tno file " LUA_QS, filename); lua_pushfstring(L, "\n\tno file " LUA_QS, filename);
lua_remove(L, -2); /* remove file name */ lua_remove(L, -2); /* remove file name */
lua_concat(L, 2); /* add entry to possible error message */ lua_concat(L, 2); /* add entry to possible error message */
} }
return NULL; /* not found */ return NULL; /* not found */
} }
static void loaderror (lua_State *L, const char *filename) { static void loaderror (lua_State *L, const char *filename) {
luaL_error(L, "error loading module " LUA_QS " from file " LUA_QS ":\n\t%s", luaL_error(L, "error loading module " LUA_QS " from file " LUA_QS ":\n\t%s",
lua_tostring(L, 1), filename, lua_tostring(L, -1)); lua_tostring(L, 1), filename, lua_tostring(L, -1));
} }
static int loader_Lua (lua_State *L) { static int loader_Lua (lua_State *L) {
const char *filename; const char *filename;
const char *name = luaL_checkstring(L, 1); const char *name = luaL_checkstring(L, 1);
filename = findfile(L, name, "path"); filename = findfile(L, name, "path");
if (filename == NULL) return 1; /* library not found in this path */ if (filename == NULL) return 1; /* library not found in this path */
if (luaL_loadfile(L, filename) != 0) if (luaL_loadfile(L, filename) != 0)
loaderror(L, filename); loaderror(L, filename);
return 1; /* library loaded successfully */ return 1; /* library loaded successfully */
} }
static const char *mkfuncname (lua_State *L, const char *modname) { static const char *mkfuncname (lua_State *L, const char *modname) {
const char *funcname; const char *funcname;
const char *mark = strchr(modname, *LUA_IGMARK); const char *mark = strchr(modname, *LUA_IGMARK);
if (mark) modname = mark + 1; if (mark) modname = mark + 1;
funcname = luaL_gsub(L, modname, ".", LUA_OFSEP); funcname = luaL_gsub(L, modname, ".", LUA_OFSEP);
funcname = lua_pushfstring(L, POF"%s", funcname); funcname = lua_pushfstring(L, POF"%s", funcname);
lua_remove(L, -2); /* remove 'gsub' result */ lua_remove(L, -2); /* remove 'gsub' result */
return funcname; return funcname;
} }
static int loader_C (lua_State *L) { static int loader_C (lua_State *L) {
const char *funcname; const char *funcname;
const char *name = luaL_checkstring(L, 1); const char *name = luaL_checkstring(L, 1);
const char *filename = findfile(L, name, "cpath"); const char *filename = findfile(L, name, "cpath");
if (filename == NULL) return 1; /* library not found in this path */ if (filename == NULL) return 1; /* library not found in this path */
funcname = mkfuncname(L, name); funcname = mkfuncname(L, name);
if (ll_loadfunc(L, filename, funcname) != 0) if (ll_loadfunc(L, filename, funcname) != 0)
loaderror(L, filename); loaderror(L, filename);
return 1; /* library loaded successfully */ return 1; /* library loaded successfully */
} }
static int loader_Croot (lua_State *L) { static int loader_Croot (lua_State *L) {
const char *funcname; const char *funcname;
const char *filename; const char *filename;
const char *name = luaL_checkstring(L, 1); const char *name = luaL_checkstring(L, 1);
const char *p = strchr(name, '.'); const char *p = strchr(name, '.');
int stat; int stat;
if (p == NULL) return 0; /* is root */ if (p == NULL) return 0; /* is root */
lua_pushlstring(L, name, p - name); lua_pushlstring(L, name, p - name);
filename = findfile(L, lua_tostring(L, -1), "cpath"); filename = findfile(L, lua_tostring(L, -1), "cpath");
if (filename == NULL) return 1; /* root not found */ if (filename == NULL) return 1; /* root not found */
funcname = mkfuncname(L, name); funcname = mkfuncname(L, name);
if ((stat = ll_loadfunc(L, filename, funcname)) != 0) { if ((stat = ll_loadfunc(L, filename, funcname)) != 0) {
if (stat != ERRFUNC) loaderror(L, filename); /* real error */ if (stat != ERRFUNC) loaderror(L, filename); /* real error */
lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS, lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS,
name, filename); name, filename);
return 1; /* function not found */ return 1; /* function not found */
} }
return 1; return 1;
} }
static int loader_preload (lua_State *L) { static int loader_preload (lua_State *L) {
const char *name = luaL_checkstring(L, 1); const char *name = luaL_checkstring(L, 1);
lua_getfield(L, LUA_ENVIRONINDEX, "preload"); lua_getfield(L, LUA_ENVIRONINDEX, "preload");
if (!lua_istable(L, -1)) if (!lua_istable(L, -1))
luaL_error(L, LUA_QL("package.preload") " must be a table"); luaL_error(L, LUA_QL("package.preload") " must be a table");
lua_getfield(L, -1, name); lua_getfield(L, -1, name);
if (lua_isnil(L, -1)) /* not found? */ if (lua_isnil(L, -1)) /* not found? */
lua_pushfstring(L, "\n\tno field package.preload['%s']", name); lua_pushfstring(L, "\n\tno field package.preload['%s']", name);
return 1; return 1;
} }
static const int sentinel_ = 0; static const int sentinel_ = 0;
#define sentinel ((void *)&sentinel_) #define sentinel ((void *)&sentinel_)
static int ll_require (lua_State *L) { static int ll_require (lua_State *L) {
const char *name = luaL_checkstring(L, 1); const char *name = luaL_checkstring(L, 1);
int i; int i;
lua_settop(L, 1); /* _LOADED table will be at index 2 */ lua_settop(L, 1); /* _LOADED table will be at index 2 */
lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
lua_getfield(L, 2, name); lua_getfield(L, 2, name);
if (lua_toboolean(L, -1)) { /* is it there? */ if (lua_toboolean(L, -1)) { /* is it there? */
if (lua_touserdata(L, -1) == sentinel) /* check loops */ if (lua_touserdata(L, -1) == sentinel) /* check loops */
luaL_error(L, "loop or previous error loading module " LUA_QS, name); luaL_error(L, "loop or previous error loading module " LUA_QS, name);
return 1; /* package is already loaded */ return 1; /* package is already loaded */
} }
/* else must load it; iterate over available loaders */ /* else must load it; iterate over available loaders */
lua_getfield(L, LUA_ENVIRONINDEX, "loaders"); lua_getfield(L, LUA_ENVIRONINDEX, "loaders");
if (!lua_istable(L, -1)) if (!lua_istable(L, -1))
luaL_error(L, LUA_QL("package.loaders") " must be a table"); luaL_error(L, LUA_QL("package.loaders") " must be a table");
lua_pushliteral(L, ""); /* error message accumulator */ lua_pushliteral(L, ""); /* error message accumulator */
for (i=1; ; i++) { for (i=1; ; i++) {
lua_rawgeti(L, -2, i); /* get a loader */ lua_rawgeti(L, -2, i); /* get a loader */
if (lua_isnil(L, -1)) if (lua_isnil(L, -1))
luaL_error(L, "module " LUA_QS " not found:%s", luaL_error(L, "module " LUA_QS " not found:%s",
name, lua_tostring(L, -2)); name, lua_tostring(L, -2));
lua_pushstring(L, name); lua_pushstring(L, name);
lua_call(L, 1, 1); /* call it */ lua_call(L, 1, 1); /* call it */
if (lua_isfunction(L, -1)) /* did it find module? */ if (lua_isfunction(L, -1)) /* did it find module? */
break; /* module loaded successfully */ break; /* module loaded successfully */
else if (lua_isstring(L, -1)) /* loader returned error message? */ else if (lua_isstring(L, -1)) /* loader returned error message? */
lua_concat(L, 2); /* accumulate it */ lua_concat(L, 2); /* accumulate it */
else else
lua_pop(L, 1); lua_pop(L, 1);
} }
lua_pushlightuserdata(L, sentinel); lua_pushlightuserdata(L, sentinel);
lua_setfield(L, 2, name); /* _LOADED[name] = sentinel */ lua_setfield(L, 2, name); /* _LOADED[name] = sentinel */
lua_pushstring(L, name); /* pass name as argument to module */ lua_pushstring(L, name); /* pass name as argument to module */
lua_call(L, 1, 1); /* run loaded module */ lua_call(L, 1, 1); /* run loaded module */
if (!lua_isnil(L, -1)) /* non-nil return? */ if (!lua_isnil(L, -1)) /* non-nil return? */
lua_setfield(L, 2, name); /* _LOADED[name] = returned value */ lua_setfield(L, 2, name); /* _LOADED[name] = returned value */
lua_getfield(L, 2, name); lua_getfield(L, 2, name);
if (lua_touserdata(L, -1) == sentinel) { /* module did not set a value? */ if (lua_touserdata(L, -1) == sentinel) { /* module did not set a value? */
lua_pushboolean(L, 1); /* use true as result */ lua_pushboolean(L, 1); /* use true as result */
lua_pushvalue(L, -1); /* extra copy to be returned */ lua_pushvalue(L, -1); /* extra copy to be returned */
lua_setfield(L, 2, name); /* _LOADED[name] = true */ lua_setfield(L, 2, name); /* _LOADED[name] = true */
} }
return 1; return 1;
} }
/* }====================================================== */ /* }====================================================== */
/* /*
** {====================================================== ** {======================================================
** 'module' function ** 'module' function
** ======================================================= ** =======================================================
*/ */
static void setfenv (lua_State *L) { static void setfenv (lua_State *L) {
lua_Debug ar; lua_Debug ar;
if (lua_getstack(L, 1, &ar) == 0 || if (lua_getstack(L, 1, &ar) == 0 ||
lua_getinfo(L, "f", &ar) == 0 || /* get calling function */ lua_getinfo(L, "f", &ar) == 0 || /* get calling function */
lua_iscfunction(L, -1)) lua_iscfunction(L, -1))
luaL_error(L, LUA_QL("module") " not called from a Lua function"); luaL_error(L, LUA_QL("module") " not called from a Lua function");
lua_pushvalue(L, -2); lua_pushvalue(L, -2);
lua_setfenv(L, -2); lua_setfenv(L, -2);
lua_pop(L, 1); lua_pop(L, 1);
} }
static void dooptions (lua_State *L, int n) { static void dooptions (lua_State *L, int n) {
int i; int i;
for (i = 2; i <= n; i++) { for (i = 2; i <= n; i++) {
lua_pushvalue(L, i); /* get option (a function) */ lua_pushvalue(L, i); /* get option (a function) */
lua_pushvalue(L, -2); /* module */ lua_pushvalue(L, -2); /* module */
lua_call(L, 1, 0); lua_call(L, 1, 0);
} }
} }
static void modinit (lua_State *L, const char *modname) { static void modinit (lua_State *L, const char *modname) {
const char *dot; const char *dot;
lua_pushvalue(L, -1); lua_pushvalue(L, -1);
lua_setfield(L, -2, "_M"); /* module._M = module */ lua_setfield(L, -2, "_M"); /* module._M = module */
lua_pushstring(L, modname); lua_pushstring(L, modname);
lua_setfield(L, -2, "_NAME"); lua_setfield(L, -2, "_NAME");
dot = strrchr(modname, '.'); /* look for last dot in module name */ dot = strrchr(modname, '.'); /* look for last dot in module name */
if (dot == NULL) dot = modname; if (dot == NULL) dot = modname;
else dot++; else dot++;
/* set _PACKAGE as package name (full module name minus last part) */ /* set _PACKAGE as package name (full module name minus last part) */
lua_pushlstring(L, modname, dot - modname); lua_pushlstring(L, modname, dot - modname);
lua_setfield(L, -2, "_PACKAGE"); lua_setfield(L, -2, "_PACKAGE");
} }
static int ll_module (lua_State *L) { static int ll_module (lua_State *L) {
const char *modname = luaL_checkstring(L, 1); const char *modname = luaL_checkstring(L, 1);
int loaded = lua_gettop(L) + 1; /* index of _LOADED table */ int loaded = lua_gettop(L) + 1; /* index of _LOADED table */
lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
lua_getfield(L, loaded, modname); /* get _LOADED[modname] */ lua_getfield(L, loaded, modname); /* get _LOADED[modname] */
if (!lua_istable(L, -1)) { /* not found? */ if (!lua_istable(L, -1)) { /* not found? */
lua_pop(L, 1); /* remove previous result */ lua_pop(L, 1); /* remove previous result */
/* try global variable (and create one if it does not exist) */ /* try global variable (and create one if it does not exist) */
if (luaL_findtable(L, LUA_GLOBALSINDEX, modname, 1) != NULL) if (luaL_findtable(L, LUA_GLOBALSINDEX, modname, 1) != NULL)
return luaL_error(L, "name conflict for module " LUA_QS, modname); return luaL_error(L, "name conflict for module " LUA_QS, modname);
lua_pushvalue(L, -1); lua_pushvalue(L, -1);
lua_setfield(L, loaded, modname); /* _LOADED[modname] = new table */ lua_setfield(L, loaded, modname); /* _LOADED[modname] = new table */
} }
/* check whether table already has a _NAME field */ /* check whether table already has a _NAME field */
lua_getfield(L, -1, "_NAME"); lua_getfield(L, -1, "_NAME");
if (!lua_isnil(L, -1)) /* is table an initialized module? */ if (!lua_isnil(L, -1)) /* is table an initialized module? */
lua_pop(L, 1); lua_pop(L, 1);
else { /* no; initialize it */ else { /* no; initialize it */
lua_pop(L, 1); lua_pop(L, 1);
modinit(L, modname); modinit(L, modname);
} }
lua_pushvalue(L, -1); lua_pushvalue(L, -1);
setfenv(L); setfenv(L);
dooptions(L, loaded - 1); dooptions(L, loaded - 1);
return 0; return 0;
} }
static int ll_seeall (lua_State *L) { static int ll_seeall (lua_State *L) {
luaL_checktype(L, 1, LUA_TTABLE); luaL_checktype(L, 1, LUA_TTABLE);
if (!lua_getmetatable(L, 1)) { if (!lua_getmetatable(L, 1)) {
lua_createtable(L, 0, 1); /* create new metatable */ lua_createtable(L, 0, 1); /* create new metatable */
lua_pushvalue(L, -1); lua_pushvalue(L, -1);
lua_setmetatable(L, 1); lua_setmetatable(L, 1);
} }
lua_pushvalue(L, LUA_GLOBALSINDEX); lua_pushvalue(L, LUA_GLOBALSINDEX);
lua_setfield(L, -2, "__index"); /* mt.__index = _G */ lua_setfield(L, -2, "__index"); /* mt.__index = _G */
return 0; return 0;
} }
/* }====================================================== */ /* }====================================================== */
/* auxiliary mark (for internal use) */ /* auxiliary mark (for internal use) */
#define AUXMARK "\1" #define AUXMARK "\1"
static void setpath (lua_State *L, const char *fieldname, const char *envname, static void setpath (lua_State *L, const char *fieldname, const char *envname,
const char *def) { const char *def) {
const char *path = getenv(envname); const char *path = getenv(envname);
if (path == NULL) /* no environment variable? */ if (path == NULL) /* no environment variable? */
lua_pushstring(L, def); /* use default */ lua_pushstring(L, def); /* use default */
else { else {
/* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */ /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */
path = luaL_gsub(L, path, LUA_PATHSEP LUA_PATHSEP, path = luaL_gsub(L, path, LUA_PATHSEP LUA_PATHSEP,
LUA_PATHSEP AUXMARK LUA_PATHSEP); LUA_PATHSEP AUXMARK LUA_PATHSEP);
luaL_gsub(L, path, AUXMARK, def); luaL_gsub(L, path, AUXMARK, def);
lua_remove(L, -2); lua_remove(L, -2);
} }
setprogdir(L); setprogdir(L);
lua_setfield(L, -2, fieldname); lua_setfield(L, -2, fieldname);
} }
static const luaL_Reg pk_funcs[] = { static const luaL_Reg pk_funcs[] = {
{"loadlib", ll_loadlib}, {"loadlib", ll_loadlib},
{"seeall", ll_seeall}, {"seeall", ll_seeall},
{NULL, NULL} {NULL, NULL}
}; };
static const luaL_Reg ll_funcs[] = { static const luaL_Reg ll_funcs[] = {
{"module", ll_module}, {"module", ll_module},
{"require", ll_require}, {"require", ll_require},
{NULL, NULL} {NULL, NULL}
}; };
static const lua_CFunction loaders[] = static const lua_CFunction loaders[] =
{loader_preload, loader_Lua, loader_C, loader_Croot, NULL}; {loader_preload, loader_Lua, loader_C, loader_Croot, NULL};
LUALIB_API int luaopen_package (lua_State *L) { LUALIB_API int luaopen_package (lua_State *L) {
int i; int i;
/* create new type _LOADLIB */ /* create new type _LOADLIB */
luaL_newmetatable(L, "_LOADLIB"); luaL_newmetatable(L, "_LOADLIB");
lua_pushcfunction(L, gctm); lua_pushcfunction(L, gctm);
lua_setfield(L, -2, "__gc"); lua_setfield(L, -2, "__gc");
/* create `package' table */ /* create `package' table */
luaL_register(L, LUA_LOADLIBNAME, pk_funcs); luaL_register(L, LUA_LOADLIBNAME, pk_funcs);
#if defined(LUA_COMPAT_LOADLIB) #if defined(LUA_COMPAT_LOADLIB)
lua_getfield(L, -1, "loadlib"); lua_getfield(L, -1, "loadlib");
lua_setfield(L, LUA_GLOBALSINDEX, "loadlib"); lua_setfield(L, LUA_GLOBALSINDEX, "loadlib");
#endif #endif
lua_pushvalue(L, -1); lua_pushvalue(L, -1);
lua_replace(L, LUA_ENVIRONINDEX); lua_replace(L, LUA_ENVIRONINDEX);
/* create `loaders' table */ /* create `loaders' table */
lua_createtable(L, 0, sizeof(loaders)/sizeof(loaders[0]) - 1); lua_createtable(L, sizeof(loaders)/sizeof(loaders[0]) - 1, 0);
/* fill it with pre-defined loaders */ /* fill it with pre-defined loaders */
for (i=0; loaders[i] != NULL; i++) { for (i=0; loaders[i] != NULL; i++) {
lua_pushcfunction(L, loaders[i]); lua_pushcfunction(L, loaders[i]);
lua_rawseti(L, -2, i+1); lua_rawseti(L, -2, i+1);
} }
lua_setfield(L, -2, "loaders"); /* put it in field `loaders' */ lua_setfield(L, -2, "loaders"); /* put it in field `loaders' */
setpath(L, "path", LUA_PATH, LUA_PATH_DEFAULT); /* set field `path' */ setpath(L, "path", LUA_PATH, LUA_PATH_DEFAULT); /* set field `path' */
setpath(L, "cpath", LUA_CPATH, LUA_CPATH_DEFAULT); /* set field `cpath' */ setpath(L, "cpath", LUA_CPATH, LUA_CPATH_DEFAULT); /* set field `cpath' */
/* store config information */ /* store config information */
lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATHSEP "\n" LUA_PATH_MARK "\n" lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATHSEP "\n" LUA_PATH_MARK "\n"
LUA_EXECDIR "\n" LUA_IGMARK); LUA_EXECDIR "\n" LUA_IGMARK);
lua_setfield(L, -2, "config"); lua_setfield(L, -2, "config");
/* set field `loaded' */ /* set field `loaded' */
luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 2); luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 2);
lua_setfield(L, -2, "loaded"); lua_setfield(L, -2, "loaded");
/* set field `preload' */ /* set field `preload' */
lua_newtable(L); lua_newtable(L);
lua_setfield(L, -2, "preload"); lua_setfield(L, -2, "preload");
lua_pushvalue(L, LUA_GLOBALSINDEX); lua_pushvalue(L, LUA_GLOBALSINDEX);
luaL_register(L, NULL, ll_funcs); /* open lib into global table */ luaL_register(L, NULL, ll_funcs); /* open lib into global table */
lua_pop(L, 1); lua_pop(L, 1);
return 1; /* return 'package' table */ return 1; /* return 'package' table */
} }
/* /*
** $Id: lstrlib.c,v 1.132.1.4 2008/07/11 17:27:21 roberto Exp $ ** $Id: lstrlib.c,v 1.132.1.5 2010/05/14 15:34:19 roberto Exp $
** Standard library for string operations and pattern-matching ** Standard library for string operations and pattern-matching
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
#include <ctype.h> #include <ctype.h>
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#define lstrlib_c #define lstrlib_c
#define LUA_LIB #define LUA_LIB
#include "lua.h" #include "lua.h"
#include "lauxlib.h" #include "lauxlib.h"
#include "lualib.h" #include "lualib.h"
/* macro to `unsign' a character */ /* macro to `unsign' a character */
#define uchar(c) ((unsigned char)(c)) #define uchar(c) ((unsigned char)(c))
static int str_len (lua_State *L) { static int str_len (lua_State *L) {
size_t l; size_t l;
luaL_checklstring(L, 1, &l); luaL_checklstring(L, 1, &l);
lua_pushinteger(L, l); lua_pushinteger(L, l);
return 1; return 1;
} }
static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) { static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) {
/* relative string position: negative means back from end */ /* relative string position: negative means back from end */
if (pos < 0) pos += (ptrdiff_t)len + 1; if (pos < 0) pos += (ptrdiff_t)len + 1;
return (pos >= 0) ? pos : 0; return (pos >= 0) ? pos : 0;
} }
static int str_sub (lua_State *L) { static int str_sub (lua_State *L) {
size_t l; size_t l;
const char *s = luaL_checklstring(L, 1, &l); const char *s = luaL_checklstring(L, 1, &l);
ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l); ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l);
ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l); ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l);
if (start < 1) start = 1; if (start < 1) start = 1;
if (end > (ptrdiff_t)l) end = (ptrdiff_t)l; if (end > (ptrdiff_t)l) end = (ptrdiff_t)l;
if (start <= end) if (start <= end)
lua_pushlstring(L, s+start-1, end-start+1); lua_pushlstring(L, s+start-1, end-start+1);
else lua_pushliteral(L, ""); else lua_pushliteral(L, "");
return 1; return 1;
} }
static int str_reverse (lua_State *L) { static int str_reverse (lua_State *L) {
size_t l; size_t l;
luaL_Buffer b; luaL_Buffer b;
const char *s = luaL_checklstring(L, 1, &l); const char *s = luaL_checklstring(L, 1, &l);
luaL_buffinit(L, &b); luaL_buffinit(L, &b);
while (l--) luaL_addchar(&b, s[l]); while (l--) luaL_addchar(&b, s[l]);
luaL_pushresult(&b); luaL_pushresult(&b);
return 1; return 1;
} }
static int str_lower (lua_State *L) { static int str_lower (lua_State *L) {
size_t l; size_t l;
size_t i; size_t i;
luaL_Buffer b; luaL_Buffer b;
const char *s = luaL_checklstring(L, 1, &l); const char *s = luaL_checklstring(L, 1, &l);
luaL_buffinit(L, &b); luaL_buffinit(L, &b);
for (i=0; i<l; i++) for (i=0; i<l; i++)
luaL_addchar(&b, tolower(uchar(s[i]))); luaL_addchar(&b, tolower(uchar(s[i])));
luaL_pushresult(&b); luaL_pushresult(&b);
return 1; return 1;
} }
static int str_upper (lua_State *L) { static int str_upper (lua_State *L) {
size_t l; size_t l;
size_t i; size_t i;
luaL_Buffer b; luaL_Buffer b;
const char *s = luaL_checklstring(L, 1, &l); const char *s = luaL_checklstring(L, 1, &l);
luaL_buffinit(L, &b); luaL_buffinit(L, &b);
for (i=0; i<l; i++) for (i=0; i<l; i++)
luaL_addchar(&b, toupper(uchar(s[i]))); luaL_addchar(&b, toupper(uchar(s[i])));
luaL_pushresult(&b); luaL_pushresult(&b);
return 1; return 1;
} }
static int str_rep (lua_State *L) { static int str_rep (lua_State *L) {
size_t l; size_t l;
luaL_Buffer b; luaL_Buffer b;
const char *s = luaL_checklstring(L, 1, &l); const char *s = luaL_checklstring(L, 1, &l);
int n = luaL_checkint(L, 2); int n = luaL_checkint(L, 2);
luaL_buffinit(L, &b); luaL_buffinit(L, &b);
while (n-- > 0) while (n-- > 0)
luaL_addlstring(&b, s, l); luaL_addlstring(&b, s, l);
luaL_pushresult(&b); luaL_pushresult(&b);
return 1; return 1;
} }
static int str_byte (lua_State *L) { static int str_byte (lua_State *L) {
size_t l; size_t l;
const char *s = luaL_checklstring(L, 1, &l); const char *s = luaL_checklstring(L, 1, &l);
ptrdiff_t posi = posrelat(luaL_optinteger(L, 2, 1), l); ptrdiff_t posi = posrelat(luaL_optinteger(L, 2, 1), l);
ptrdiff_t pose = posrelat(luaL_optinteger(L, 3, posi), l); ptrdiff_t pose = posrelat(luaL_optinteger(L, 3, posi), l);
int n, i; int n, i;
if (posi <= 0) posi = 1; if (posi <= 0) posi = 1;
if ((size_t)pose > l) pose = l; if ((size_t)pose > l) pose = l;
if (posi > pose) return 0; /* empty interval; return no values */ if (posi > pose) return 0; /* empty interval; return no values */
n = (int)(pose - posi + 1); n = (int)(pose - posi + 1);
if (posi + n <= pose) /* overflow? */ if (posi + n <= pose) /* overflow? */
luaL_error(L, "string slice too long"); luaL_error(L, "string slice too long");
luaL_checkstack(L, n, "string slice too long"); luaL_checkstack(L, n, "string slice too long");
for (i=0; i<n; i++) for (i=0; i<n; i++)
lua_pushinteger(L, uchar(s[posi+i-1])); lua_pushinteger(L, uchar(s[posi+i-1]));
return n; return n;
} }
static int str_char (lua_State *L) { static int str_char (lua_State *L) {
int n = lua_gettop(L); /* number of arguments */ int n = lua_gettop(L); /* number of arguments */
int i; int i;
luaL_Buffer b; luaL_Buffer b;
luaL_buffinit(L, &b); luaL_buffinit(L, &b);
for (i=1; i<=n; i++) { for (i=1; i<=n; i++) {
int c = luaL_checkint(L, i); int c = luaL_checkint(L, i);
luaL_argcheck(L, uchar(c) == c, i, "invalid value"); luaL_argcheck(L, uchar(c) == c, i, "invalid value");
luaL_addchar(&b, uchar(c)); luaL_addchar(&b, uchar(c));
} }
luaL_pushresult(&b); luaL_pushresult(&b);
return 1; return 1;
} }
static int writer (lua_State *L, const void* b, size_t size, void* B) { static int writer (lua_State *L, const void* b, size_t size, void* B) {
(void)L; (void)L;
luaL_addlstring((luaL_Buffer*) B, (const char *)b, size); luaL_addlstring((luaL_Buffer*) B, (const char *)b, size);
return 0; return 0;
} }
static int str_dump (lua_State *L) { static int str_dump (lua_State *L) {
luaL_Buffer b; luaL_Buffer b;
luaL_checktype(L, 1, LUA_TFUNCTION); luaL_checktype(L, 1, LUA_TFUNCTION);
lua_settop(L, 1); lua_settop(L, 1);
luaL_buffinit(L,&b); luaL_buffinit(L,&b);
if (lua_dump(L, writer, &b) != 0) if (lua_dump(L, writer, &b) != 0)
luaL_error(L, "unable to dump given function"); luaL_error(L, "unable to dump given function");
luaL_pushresult(&b); luaL_pushresult(&b);
return 1; return 1;
} }
/* /*
** {====================================================== ** {======================================================
** PATTERN MATCHING ** PATTERN MATCHING
** ======================================================= ** =======================================================
*/ */
#define CAP_UNFINISHED (-1) #define CAP_UNFINISHED (-1)
#define CAP_POSITION (-2) #define CAP_POSITION (-2)
typedef struct MatchState { typedef struct MatchState {
const char *src_init; /* init of source string */ const char *src_init; /* init of source string */
const char *src_end; /* end (`\0') of source string */ const char *src_end; /* end (`\0') of source string */
lua_State *L; lua_State *L;
int level; /* total number of captures (finished or unfinished) */ int level; /* total number of captures (finished or unfinished) */
struct { struct {
const char *init; const char *init;
ptrdiff_t len; ptrdiff_t len;
} capture[LUA_MAXCAPTURES]; } capture[LUA_MAXCAPTURES];
} MatchState; } MatchState;
#define L_ESC '%' #define L_ESC '%'
#define SPECIALS "^$*+?.([%-" #define SPECIALS "^$*+?.([%-"
static int check_capture (MatchState *ms, int l) { static int check_capture (MatchState *ms, int l) {
l -= '1'; l -= '1';
if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED) if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED)
return luaL_error(ms->L, "invalid capture index"); return luaL_error(ms->L, "invalid capture index");
return l; return l;
} }
static int capture_to_close (MatchState *ms) { static int capture_to_close (MatchState *ms) {
int level = ms->level; int level = ms->level;
for (level--; level>=0; level--) for (level--; level>=0; level--)
if (ms->capture[level].len == CAP_UNFINISHED) return level; if (ms->capture[level].len == CAP_UNFINISHED) return level;
return luaL_error(ms->L, "invalid pattern capture"); return luaL_error(ms->L, "invalid pattern capture");
} }
static const char *classend (MatchState *ms, const char *p) { static const char *classend (MatchState *ms, const char *p) {
switch (*p++) { switch (*p++) {
case L_ESC: { case L_ESC: {
if (*p == '\0') if (*p == '\0')
luaL_error(ms->L, "malformed pattern (ends with " LUA_QL("%%") ")"); luaL_error(ms->L, "malformed pattern (ends with " LUA_QL("%%") ")");
return p+1; return p+1;
} }
case '[': { case '[': {
if (*p == '^') p++; if (*p == '^') p++;
do { /* look for a `]' */ do { /* look for a `]' */
if (*p == '\0') if (*p == '\0')
luaL_error(ms->L, "malformed pattern (missing " LUA_QL("]") ")"); luaL_error(ms->L, "malformed pattern (missing " LUA_QL("]") ")");
if (*(p++) == L_ESC && *p != '\0') if (*(p++) == L_ESC && *p != '\0')
p++; /* skip escapes (e.g. `%]') */ p++; /* skip escapes (e.g. `%]') */
} while (*p != ']'); } while (*p != ']');
return p+1; return p+1;
} }
default: { default: {
return p; return p;
} }
} }
} }
static int match_class (int c, int cl) { static int match_class (int c, int cl) {
int res; int res;
switch (tolower(cl)) { switch (tolower(cl)) {
case 'a' : res = isalpha(c); break; case 'a' : res = isalpha(c); break;
case 'c' : res = iscntrl(c); break; case 'c' : res = iscntrl(c); break;
case 'd' : res = isdigit(c); break; case 'd' : res = isdigit(c); break;
case 'l' : res = islower(c); break; case 'l' : res = islower(c); break;
case 'p' : res = ispunct(c); break; case 'p' : res = ispunct(c); break;
case 's' : res = isspace(c); break; case 's' : res = isspace(c); break;
case 'u' : res = isupper(c); break; case 'u' : res = isupper(c); break;
case 'w' : res = isalnum(c); break; case 'w' : res = isalnum(c); break;
case 'x' : res = isxdigit(c); break; case 'x' : res = isxdigit(c); break;
case 'z' : res = (c == 0); break; case 'z' : res = (c == 0); break;
default: return (cl == c); default: return (cl == c);
} }
return (islower(cl) ? res : !res); return (islower(cl) ? res : !res);
} }
static int matchbracketclass (int c, const char *p, const char *ec) { static int matchbracketclass (int c, const char *p, const char *ec) {
int sig = 1; int sig = 1;
if (*(p+1) == '^') { if (*(p+1) == '^') {
sig = 0; sig = 0;
p++; /* skip the `^' */ p++; /* skip the `^' */
} }
while (++p < ec) { while (++p < ec) {
if (*p == L_ESC) { if (*p == L_ESC) {
p++; p++;
if (match_class(c, uchar(*p))) if (match_class(c, uchar(*p)))
return sig; return sig;
} }
else if ((*(p+1) == '-') && (p+2 < ec)) { else if ((*(p+1) == '-') && (p+2 < ec)) {
p+=2; p+=2;
if (uchar(*(p-2)) <= c && c <= uchar(*p)) if (uchar(*(p-2)) <= c && c <= uchar(*p))
return sig; return sig;
} }
else if (uchar(*p) == c) return sig; else if (uchar(*p) == c) return sig;
} }
return !sig; return !sig;
} }
static int singlematch (int c, const char *p, const char *ep) { static int singlematch (int c, const char *p, const char *ep) {
switch (*p) { switch (*p) {
case '.': return 1; /* matches any char */ case '.': return 1; /* matches any char */
case L_ESC: return match_class(c, uchar(*(p+1))); case L_ESC: return match_class(c, uchar(*(p+1)));
case '[': return matchbracketclass(c, p, ep-1); case '[': return matchbracketclass(c, p, ep-1);
default: return (uchar(*p) == c); default: return (uchar(*p) == c);
} }
} }
static const char *match (MatchState *ms, const char *s, const char *p); static const char *match (MatchState *ms, const char *s, const char *p);
static const char *matchbalance (MatchState *ms, const char *s, static const char *matchbalance (MatchState *ms, const char *s,
const char *p) { const char *p) {
if (*p == 0 || *(p+1) == 0) if (*p == 0 || *(p+1) == 0)
luaL_error(ms->L, "unbalanced pattern"); luaL_error(ms->L, "unbalanced pattern");
if (*s != *p) return NULL; if (*s != *p) return NULL;
else { else {
int b = *p; int b = *p;
int e = *(p+1); int e = *(p+1);
int cont = 1; int cont = 1;
while (++s < ms->src_end) { while (++s < ms->src_end) {
if (*s == e) { if (*s == e) {
if (--cont == 0) return s+1; if (--cont == 0) return s+1;
} }
else if (*s == b) cont++; else if (*s == b) cont++;
} }
} }
return NULL; /* string ends out of balance */ return NULL; /* string ends out of balance */
} }
static const char *max_expand (MatchState *ms, const char *s, static const char *max_expand (MatchState *ms, const char *s,
const char *p, const char *ep) { const char *p, const char *ep) {
ptrdiff_t i = 0; /* counts maximum expand for item */ ptrdiff_t i = 0; /* counts maximum expand for item */
while ((s+i)<ms->src_end && singlematch(uchar(*(s+i)), p, ep)) while ((s+i)<ms->src_end && singlematch(uchar(*(s+i)), p, ep))
i++; i++;
/* keeps trying to match with the maximum repetitions */ /* keeps trying to match with the maximum repetitions */
while (i>=0) { while (i>=0) {
const char *res = match(ms, (s+i), ep+1); const char *res = match(ms, (s+i), ep+1);
if (res) return res; if (res) return res;
i--; /* else didn't match; reduce 1 repetition to try again */ i--; /* else didn't match; reduce 1 repetition to try again */
} }
return NULL; return NULL;
} }
static const char *min_expand (MatchState *ms, const char *s, static const char *min_expand (MatchState *ms, const char *s,
const char *p, const char *ep) { const char *p, const char *ep) {
for (;;) { for (;;) {
const char *res = match(ms, s, ep+1); const char *res = match(ms, s, ep+1);
if (res != NULL) if (res != NULL)
return res; return res;
else if (s<ms->src_end && singlematch(uchar(*s), p, ep)) else if (s<ms->src_end && singlematch(uchar(*s), p, ep))
s++; /* try with one more repetition */ s++; /* try with one more repetition */
else return NULL; else return NULL;
} }
} }
static const char *start_capture (MatchState *ms, const char *s, static const char *start_capture (MatchState *ms, const char *s,
const char *p, int what) { const char *p, int what) {
const char *res; const char *res;
int level = ms->level; int level = ms->level;
if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures"); if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures");
ms->capture[level].init = s; ms->capture[level].init = s;
ms->capture[level].len = what; ms->capture[level].len = what;
ms->level = level+1; ms->level = level+1;
if ((res=match(ms, s, p)) == NULL) /* match failed? */ if ((res=match(ms, s, p)) == NULL) /* match failed? */
ms->level--; /* undo capture */ ms->level--; /* undo capture */
return res; return res;
} }
static const char *end_capture (MatchState *ms, const char *s, static const char *end_capture (MatchState *ms, const char *s,
const char *p) { const char *p) {
int l = capture_to_close(ms); int l = capture_to_close(ms);
const char *res; const char *res;
ms->capture[l].len = s - ms->capture[l].init; /* close capture */ ms->capture[l].len = s - ms->capture[l].init; /* close capture */
if ((res = match(ms, s, p)) == NULL) /* match failed? */ if ((res = match(ms, s, p)) == NULL) /* match failed? */
ms->capture[l].len = CAP_UNFINISHED; /* undo capture */ ms->capture[l].len = CAP_UNFINISHED; /* undo capture */
return res; return res;
} }
static const char *match_capture (MatchState *ms, const char *s, int l) { static const char *match_capture (MatchState *ms, const char *s, int l) {
size_t len; size_t len;
l = check_capture(ms, l); l = check_capture(ms, l);
len = ms->capture[l].len; len = ms->capture[l].len;
if ((size_t)(ms->src_end-s) >= len && if ((size_t)(ms->src_end-s) >= len &&
memcmp(ms->capture[l].init, s, len) == 0) memcmp(ms->capture[l].init, s, len) == 0)
return s+len; return s+len;
else return NULL; else return NULL;
} }
static const char *match (MatchState *ms, const char *s, const char *p) { static const char *match (MatchState *ms, const char *s, const char *p) {
init: /* using goto's to optimize tail recursion */ init: /* using goto's to optimize tail recursion */
switch (*p) { switch (*p) {
case '(': { /* start capture */ case '(': { /* start capture */
if (*(p+1) == ')') /* position capture? */ if (*(p+1) == ')') /* position capture? */
return start_capture(ms, s, p+2, CAP_POSITION); return start_capture(ms, s, p+2, CAP_POSITION);
else else
return start_capture(ms, s, p+1, CAP_UNFINISHED); return start_capture(ms, s, p+1, CAP_UNFINISHED);
} }
case ')': { /* end capture */ case ')': { /* end capture */
return end_capture(ms, s, p+1); return end_capture(ms, s, p+1);
} }
case L_ESC: { case L_ESC: {
switch (*(p+1)) { switch (*(p+1)) {
case 'b': { /* balanced string? */ case 'b': { /* balanced string? */
s = matchbalance(ms, s, p+2); s = matchbalance(ms, s, p+2);
if (s == NULL) return NULL; if (s == NULL) return NULL;
p+=4; goto init; /* else return match(ms, s, p+4); */ p+=4; goto init; /* else return match(ms, s, p+4); */
} }
case 'f': { /* frontier? */ case 'f': { /* frontier? */
const char *ep; char previous; const char *ep; char previous;
p += 2; p += 2;
if (*p != '[') if (*p != '[')
luaL_error(ms->L, "missing " LUA_QL("[") " after " luaL_error(ms->L, "missing " LUA_QL("[") " after "
LUA_QL("%%f") " in pattern"); LUA_QL("%%f") " in pattern");
ep = classend(ms, p); /* points to what is next */ ep = classend(ms, p); /* points to what is next */
previous = (s == ms->src_init) ? '\0' : *(s-1); previous = (s == ms->src_init) ? '\0' : *(s-1);
if (matchbracketclass(uchar(previous), p, ep-1) || if (matchbracketclass(uchar(previous), p, ep-1) ||
!matchbracketclass(uchar(*s), p, ep-1)) return NULL; !matchbracketclass(uchar(*s), p, ep-1)) return NULL;
p=ep; goto init; /* else return match(ms, s, ep); */ p=ep; goto init; /* else return match(ms, s, ep); */
} }
default: { default: {
if (isdigit(uchar(*(p+1)))) { /* capture results (%0-%9)? */ if (isdigit(uchar(*(p+1)))) { /* capture results (%0-%9)? */
s = match_capture(ms, s, uchar(*(p+1))); s = match_capture(ms, s, uchar(*(p+1)));
if (s == NULL) return NULL; if (s == NULL) return NULL;
p+=2; goto init; /* else return match(ms, s, p+2) */ p+=2; goto init; /* else return match(ms, s, p+2) */
} }
goto dflt; /* case default */ goto dflt; /* case default */
} }
} }
} }
case '\0': { /* end of pattern */ case '\0': { /* end of pattern */
return s; /* match succeeded */ return s; /* match succeeded */
} }
case '$': { case '$': {
if (*(p+1) == '\0') /* is the `$' the last char in pattern? */ if (*(p+1) == '\0') /* is the `$' the last char in pattern? */
return (s == ms->src_end) ? s : NULL; /* check end of string */ return (s == ms->src_end) ? s : NULL; /* check end of string */
else goto dflt; else goto dflt;
} }
default: dflt: { /* it is a pattern item */ default: dflt: { /* it is a pattern item */
const char *ep = classend(ms, p); /* points to what is next */ const char *ep = classend(ms, p); /* points to what is next */
int m = s<ms->src_end && singlematch(uchar(*s), p, ep); int m = s<ms->src_end && singlematch(uchar(*s), p, ep);
switch (*ep) { switch (*ep) {
case '?': { /* optional */ case '?': { /* optional */
const char *res; const char *res;
if (m && ((res=match(ms, s+1, ep+1)) != NULL)) if (m && ((res=match(ms, s+1, ep+1)) != NULL))
return res; return res;
p=ep+1; goto init; /* else return match(ms, s, ep+1); */ p=ep+1; goto init; /* else return match(ms, s, ep+1); */
} }
case '*': { /* 0 or more repetitions */ case '*': { /* 0 or more repetitions */
return max_expand(ms, s, p, ep); return max_expand(ms, s, p, ep);
} }
case '+': { /* 1 or more repetitions */ case '+': { /* 1 or more repetitions */
return (m ? max_expand(ms, s+1, p, ep) : NULL); return (m ? max_expand(ms, s+1, p, ep) : NULL);
} }
case '-': { /* 0 or more repetitions (minimum) */ case '-': { /* 0 or more repetitions (minimum) */
return min_expand(ms, s, p, ep); return min_expand(ms, s, p, ep);
} }
default: { default: {
if (!m) return NULL; if (!m) return NULL;
s++; p=ep; goto init; /* else return match(ms, s+1, ep); */ s++; p=ep; goto init; /* else return match(ms, s+1, ep); */
} }
} }
} }
} }
} }
static const char *lmemfind (const char *s1, size_t l1, static const char *lmemfind (const char *s1, size_t l1,
const char *s2, size_t l2) { const char *s2, size_t l2) {
if (l2 == 0) return s1; /* empty strings are everywhere */ if (l2 == 0) return s1; /* empty strings are everywhere */
else if (l2 > l1) return NULL; /* avoids a negative `l1' */ else if (l2 > l1) return NULL; /* avoids a negative `l1' */
else { else {
const char *init; /* to search for a `*s2' inside `s1' */ const char *init; /* to search for a `*s2' inside `s1' */
l2--; /* 1st char will be checked by `memchr' */ l2--; /* 1st char will be checked by `memchr' */
l1 = l1-l2; /* `s2' cannot be found after that */ l1 = l1-l2; /* `s2' cannot be found after that */
while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) { while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) {
init++; /* 1st char is already checked */ init++; /* 1st char is already checked */
if (memcmp(init, s2+1, l2) == 0) if (memcmp(init, s2+1, l2) == 0)
return init-1; return init-1;
else { /* correct `l1' and `s1' to try again */ else { /* correct `l1' and `s1' to try again */
l1 -= init-s1; l1 -= init-s1;
s1 = init; s1 = init;
} }
} }
return NULL; /* not found */ return NULL; /* not found */
} }
} }
static void push_onecapture (MatchState *ms, int i, const char *s, static void push_onecapture (MatchState *ms, int i, const char *s,
const char *e) { const char *e) {
if (i >= ms->level) { if (i >= ms->level) {
if (i == 0) /* ms->level == 0, too */ if (i == 0) /* ms->level == 0, too */
lua_pushlstring(ms->L, s, e - s); /* add whole match */ lua_pushlstring(ms->L, s, e - s); /* add whole match */
else else
luaL_error(ms->L, "invalid capture index"); luaL_error(ms->L, "invalid capture index");
} }
else { else {
ptrdiff_t l = ms->capture[i].len; ptrdiff_t l = ms->capture[i].len;
if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture");
if (l == CAP_POSITION) if (l == CAP_POSITION)
lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1); lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1);
else else
lua_pushlstring(ms->L, ms->capture[i].init, l); lua_pushlstring(ms->L, ms->capture[i].init, l);
} }
} }
static int push_captures (MatchState *ms, const char *s, const char *e) { static int push_captures (MatchState *ms, const char *s, const char *e) {
int i; int i;
int nlevels = (ms->level == 0 && s) ? 1 : ms->level; int nlevels = (ms->level == 0 && s) ? 1 : ms->level;
luaL_checkstack(ms->L, nlevels, "too many captures"); luaL_checkstack(ms->L, nlevels, "too many captures");
for (i = 0; i < nlevels; i++) for (i = 0; i < nlevels; i++)
push_onecapture(ms, i, s, e); push_onecapture(ms, i, s, e);
return nlevels; /* number of strings pushed */ return nlevels; /* number of strings pushed */
} }
static int str_find_aux (lua_State *L, int find) { static int str_find_aux (lua_State *L, int find) {
size_t l1, l2; size_t l1, l2;
const char *s = luaL_checklstring(L, 1, &l1); const char *s = luaL_checklstring(L, 1, &l1);
const char *p = luaL_checklstring(L, 2, &l2); const char *p = luaL_checklstring(L, 2, &l2);
ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1; ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1;
if (init < 0) init = 0; if (init < 0) init = 0;
else if ((size_t)(init) > l1) init = (ptrdiff_t)l1; else if ((size_t)(init) > l1) init = (ptrdiff_t)l1;
if (find && (lua_toboolean(L, 4) || /* explicit request? */ if (find && (lua_toboolean(L, 4) || /* explicit request? */
strpbrk(p, SPECIALS) == NULL)) { /* or no special characters? */ strpbrk(p, SPECIALS) == NULL)) { /* or no special characters? */
/* do a plain search */ /* do a plain search */
const char *s2 = lmemfind(s+init, l1-init, p, l2); const char *s2 = lmemfind(s+init, l1-init, p, l2);
if (s2) { if (s2) {
lua_pushinteger(L, s2-s+1); lua_pushinteger(L, s2-s+1);
lua_pushinteger(L, s2-s+l2); lua_pushinteger(L, s2-s+l2);
return 2; return 2;
} }
} }
else { else {
MatchState ms; MatchState ms;
int anchor = (*p == '^') ? (p++, 1) : 0; int anchor = (*p == '^') ? (p++, 1) : 0;
const char *s1=s+init; const char *s1=s+init;
ms.L = L; ms.L = L;
ms.src_init = s; ms.src_init = s;
ms.src_end = s+l1; ms.src_end = s+l1;
do { do {
const char *res; const char *res;
ms.level = 0; ms.level = 0;
if ((res=match(&ms, s1, p)) != NULL) { if ((res=match(&ms, s1, p)) != NULL) {
if (find) { if (find) {
lua_pushinteger(L, s1-s+1); /* start */ lua_pushinteger(L, s1-s+1); /* start */
lua_pushinteger(L, res-s); /* end */ lua_pushinteger(L, res-s); /* end */
return push_captures(&ms, NULL, 0) + 2; return push_captures(&ms, NULL, 0) + 2;
} }
else else
return push_captures(&ms, s1, res); return push_captures(&ms, s1, res);
} }
} while (s1++ < ms.src_end && !anchor); } while (s1++ < ms.src_end && !anchor);
} }
lua_pushnil(L); /* not found */ lua_pushnil(L); /* not found */
return 1; return 1;
} }
static int str_find (lua_State *L) { static int str_find (lua_State *L) {
return str_find_aux(L, 1); return str_find_aux(L, 1);
} }
static int str_match (lua_State *L) { static int str_match (lua_State *L) {
return str_find_aux(L, 0); return str_find_aux(L, 0);
} }
static int gmatch_aux (lua_State *L) { static int gmatch_aux (lua_State *L) {
MatchState ms; MatchState ms;
size_t ls; size_t ls;
const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls); const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls);
const char *p = lua_tostring(L, lua_upvalueindex(2)); const char *p = lua_tostring(L, lua_upvalueindex(2));
const char *src; const char *src;
ms.L = L; ms.L = L;
ms.src_init = s; ms.src_init = s;
ms.src_end = s+ls; ms.src_end = s+ls;
for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3)); for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3));
src <= ms.src_end; src <= ms.src_end;
src++) { src++) {
const char *e; const char *e;
ms.level = 0; ms.level = 0;
if ((e = match(&ms, src, p)) != NULL) { if ((e = match(&ms, src, p)) != NULL) {
lua_Integer newstart = e-s; lua_Integer newstart = e-s;
if (e == src) newstart++; /* empty match? go at least one position */ if (e == src) newstart++; /* empty match? go at least one position */
lua_pushinteger(L, newstart); lua_pushinteger(L, newstart);
lua_replace(L, lua_upvalueindex(3)); lua_replace(L, lua_upvalueindex(3));
return push_captures(&ms, src, e); return push_captures(&ms, src, e);
} }
} }
return 0; /* not found */ return 0; /* not found */
} }
static int gmatch (lua_State *L) { static int gmatch (lua_State *L) {
luaL_checkstring(L, 1); luaL_checkstring(L, 1);
luaL_checkstring(L, 2); luaL_checkstring(L, 2);
lua_settop(L, 2); lua_settop(L, 2);
lua_pushinteger(L, 0); lua_pushinteger(L, 0);
lua_pushcclosure(L, gmatch_aux, 3); lua_pushcclosure(L, gmatch_aux, 3);
return 1; return 1;
} }
static int gfind_nodef (lua_State *L) { static int gfind_nodef (lua_State *L) {
return luaL_error(L, LUA_QL("string.gfind") " was renamed to " return luaL_error(L, LUA_QL("string.gfind") " was renamed to "
LUA_QL("string.gmatch")); LUA_QL("string.gmatch"));
} }
static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, static void add_s (MatchState *ms, luaL_Buffer *b, const char *s,
const char *e) { const char *e) {
size_t l, i; size_t l, i;
const char *news = lua_tolstring(ms->L, 3, &l); const char *news = lua_tolstring(ms->L, 3, &l);
for (i = 0; i < l; i++) { for (i = 0; i < l; i++) {
if (news[i] != L_ESC) if (news[i] != L_ESC)
luaL_addchar(b, news[i]); luaL_addchar(b, news[i]);
else { else {
i++; /* skip ESC */ i++; /* skip ESC */
if (!isdigit(uchar(news[i]))) if (!isdigit(uchar(news[i])))
luaL_addchar(b, news[i]); luaL_addchar(b, news[i]);
else if (news[i] == '0') else if (news[i] == '0')
luaL_addlstring(b, s, e - s); luaL_addlstring(b, s, e - s);
else { else {
push_onecapture(ms, news[i] - '1', s, e); push_onecapture(ms, news[i] - '1', s, e);
luaL_addvalue(b); /* add capture to accumulated result */ luaL_addvalue(b); /* add capture to accumulated result */
} }
} }
} }
} }
static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, static void add_value (MatchState *ms, luaL_Buffer *b, const char *s,
const char *e) { const char *e) {
lua_State *L = ms->L; lua_State *L = ms->L;
switch (lua_type(L, 3)) { switch (lua_type(L, 3)) {
case LUA_TNUMBER: case LUA_TNUMBER:
case LUA_TSTRING: { case LUA_TSTRING: {
add_s(ms, b, s, e); add_s(ms, b, s, e);
return; return;
} }
case LUA_TFUNCTION: { case LUA_TFUNCTION: {
int n; int n;
lua_pushvalue(L, 3); lua_pushvalue(L, 3);
n = push_captures(ms, s, e); n = push_captures(ms, s, e);
lua_call(L, n, 1); lua_call(L, n, 1);
break; break;
} }
case LUA_TTABLE: { case LUA_TTABLE: {
push_onecapture(ms, 0, s, e); push_onecapture(ms, 0, s, e);
lua_gettable(L, 3); lua_gettable(L, 3);
break; break;
} }
} }
if (!lua_toboolean(L, -1)) { /* nil or false? */ if (!lua_toboolean(L, -1)) { /* nil or false? */
lua_pop(L, 1); lua_pop(L, 1);
lua_pushlstring(L, s, e - s); /* keep original text */ lua_pushlstring(L, s, e - s); /* keep original text */
} }
else if (!lua_isstring(L, -1)) else if (!lua_isstring(L, -1))
luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1));
luaL_addvalue(b); /* add result to accumulator */ luaL_addvalue(b); /* add result to accumulator */
} }
static int str_gsub (lua_State *L) { static int str_gsub (lua_State *L) {
size_t srcl; size_t srcl;
const char *src = luaL_checklstring(L, 1, &srcl); const char *src = luaL_checklstring(L, 1, &srcl);
const char *p = luaL_checkstring(L, 2); const char *p = luaL_checkstring(L, 2);
int tr = lua_type(L, 3); int tr = lua_type(L, 3);
int max_s = luaL_optint(L, 4, srcl+1); int max_s = luaL_optint(L, 4, srcl+1);
int anchor = (*p == '^') ? (p++, 1) : 0; int anchor = (*p == '^') ? (p++, 1) : 0;
int n = 0; int n = 0;
MatchState ms; MatchState ms;
luaL_Buffer b; luaL_Buffer b;
luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING ||
tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3, tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3,
"string/function/table expected"); "string/function/table expected");
luaL_buffinit(L, &b); luaL_buffinit(L, &b);
ms.L = L; ms.L = L;
ms.src_init = src; ms.src_init = src;
ms.src_end = src+srcl; ms.src_end = src+srcl;
while (n < max_s) { while (n < max_s) {
const char *e; const char *e;
ms.level = 0; ms.level = 0;
e = match(&ms, src, p); e = match(&ms, src, p);
if (e) { if (e) {
n++; n++;
add_value(&ms, &b, src, e); add_value(&ms, &b, src, e);
} }
if (e && e>src) /* non empty match? */ if (e && e>src) /* non empty match? */
src = e; /* skip it */ src = e; /* skip it */
else if (src < ms.src_end) else if (src < ms.src_end)
luaL_addchar(&b, *src++); luaL_addchar(&b, *src++);
else break; else break;
if (anchor) break; if (anchor) break;
} }
luaL_addlstring(&b, src, ms.src_end-src); luaL_addlstring(&b, src, ms.src_end-src);
luaL_pushresult(&b); luaL_pushresult(&b);
lua_pushinteger(L, n); /* number of substitutions */ lua_pushinteger(L, n); /* number of substitutions */
return 2; return 2;
} }
/* }====================================================== */ /* }====================================================== */
/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ /* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */
#define MAX_ITEM 512 #define MAX_ITEM 512
/* valid flags in a format specification */ /* valid flags in a format specification */
#define FLAGS "-+ #0" #define FLAGS "-+ #0"
/* /*
** maximum size of each format specification (such as '%-099.99d') ** maximum size of each format specification (such as '%-099.99d')
** (+10 accounts for %99.99x plus margin of error) ** (+10 accounts for %99.99x plus margin of error)
*/ */
#define MAX_FORMAT (sizeof(FLAGS) + sizeof(LUA_INTFRMLEN) + 10) #define MAX_FORMAT (sizeof(FLAGS) + sizeof(LUA_INTFRMLEN) + 10)
static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
size_t l; size_t l;
const char *s = luaL_checklstring(L, arg, &l); const char *s = luaL_checklstring(L, arg, &l);
luaL_addchar(b, '"'); luaL_addchar(b, '"');
while (l--) { while (l--) {
switch (*s) { switch (*s) {
case '"': case '\\': case '\n': { case '"': case '\\': case '\n': {
luaL_addchar(b, '\\'); luaL_addchar(b, '\\');
luaL_addchar(b, *s); luaL_addchar(b, *s);
break; break;
} }
case '\r': { case '\r': {
luaL_addlstring(b, "\\r", 2); luaL_addlstring(b, "\\r", 2);
break; break;
} }
case '\0': { case '\0': {
luaL_addlstring(b, "\\000", 4); luaL_addlstring(b, "\\000", 4);
break; break;
} }
default: { default: {
luaL_addchar(b, *s); luaL_addchar(b, *s);
break; break;
} }
} }
s++; s++;
} }
luaL_addchar(b, '"'); luaL_addchar(b, '"');
} }
static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
const char *p = strfrmt; const char *p = strfrmt;
while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */
if ((size_t)(p - strfrmt) >= sizeof(FLAGS)) if ((size_t)(p - strfrmt) >= sizeof(FLAGS))
luaL_error(L, "invalid format (repeated flags)"); luaL_error(L, "invalid format (repeated flags)");
if (isdigit(uchar(*p))) p++; /* skip width */ if (isdigit(uchar(*p))) p++; /* skip width */
if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
if (*p == '.') { if (*p == '.') {
p++; p++;
if (isdigit(uchar(*p))) p++; /* skip precision */ if (isdigit(uchar(*p))) p++; /* skip precision */
if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
} }
if (isdigit(uchar(*p))) if (isdigit(uchar(*p)))
luaL_error(L, "invalid format (width or precision too long)"); luaL_error(L, "invalid format (width or precision too long)");
*(form++) = '%'; *(form++) = '%';
strncpy(form, strfrmt, p - strfrmt + 1); strncpy(form, strfrmt, p - strfrmt + 1);
form += p - strfrmt + 1; form += p - strfrmt + 1;
*form = '\0'; *form = '\0';
return p; return p;
} }
static void addintlen (char *form) { static void addintlen (char *form) {
size_t l = strlen(form); size_t l = strlen(form);
char spec = form[l - 1]; char spec = form[l - 1];
strcpy(form + l - 1, LUA_INTFRMLEN); strcpy(form + l - 1, LUA_INTFRMLEN);
form[l + sizeof(LUA_INTFRMLEN) - 2] = spec; form[l + sizeof(LUA_INTFRMLEN) - 2] = spec;
form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0'; form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0';
} }
static int str_format (lua_State *L) { static int str_format (lua_State *L) {
int arg = 1; int top = lua_gettop(L);
size_t sfl; int arg = 1;
const char *strfrmt = luaL_checklstring(L, arg, &sfl); size_t sfl;
const char *strfrmt_end = strfrmt+sfl; const char *strfrmt = luaL_checklstring(L, arg, &sfl);
luaL_Buffer b; const char *strfrmt_end = strfrmt+sfl;
luaL_buffinit(L, &b); luaL_Buffer b;
while (strfrmt < strfrmt_end) { luaL_buffinit(L, &b);
if (*strfrmt != L_ESC) while (strfrmt < strfrmt_end) {
luaL_addchar(&b, *strfrmt++); if (*strfrmt != L_ESC)
else if (*++strfrmt == L_ESC) luaL_addchar(&b, *strfrmt++);
luaL_addchar(&b, *strfrmt++); /* %% */ else if (*++strfrmt == L_ESC)
else { /* format item */ luaL_addchar(&b, *strfrmt++); /* %% */
char form[MAX_FORMAT]; /* to store the format (`%...') */ else { /* format item */
char buff[MAX_ITEM]; /* to store the formatted item */ char form[MAX_FORMAT]; /* to store the format (`%...') */
arg++; char buff[MAX_ITEM]; /* to store the formatted item */
strfrmt = scanformat(L, strfrmt, form); if (++arg > top)
switch (*strfrmt++) { luaL_argerror(L, arg, "no value");
case 'c': { strfrmt = scanformat(L, strfrmt, form);
sprintf(buff, form, (int)luaL_checknumber(L, arg)); switch (*strfrmt++) {
break; case 'c': {
} sprintf(buff, form, (int)luaL_checknumber(L, arg));
case 'd': case 'i': { break;
addintlen(form); }
sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg)); case 'd': case 'i': {
break; addintlen(form);
} sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg));
case 'o': case 'u': case 'x': case 'X': { break;
addintlen(form); }
sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg)); case 'o': case 'u': case 'x': case 'X': {
break; addintlen(form);
} sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg));
case 'e': case 'E': case 'f': break;
case 'g': case 'G': { }
sprintf(buff, form, (double)luaL_checknumber(L, arg)); case 'e': case 'E': case 'f':
break; case 'g': case 'G': {
} sprintf(buff, form, (double)luaL_checknumber(L, arg));
case 'q': { break;
addquoted(L, &b, arg); }
continue; /* skip the 'addsize' at the end */ case 'q': {
} addquoted(L, &b, arg);
case 's': { continue; /* skip the 'addsize' at the end */
size_t l; }
const char *s = luaL_checklstring(L, arg, &l); case 's': {
if (!strchr(form, '.') && l >= 100) { size_t l;
/* no precision and string is too long to be formatted; const char *s = luaL_checklstring(L, arg, &l);
keep original string */ if (!strchr(form, '.') && l >= 100) {
lua_pushvalue(L, arg); /* no precision and string is too long to be formatted;
luaL_addvalue(&b); keep original string */
continue; /* skip the `addsize' at the end */ lua_pushvalue(L, arg);
} luaL_addvalue(&b);
else { continue; /* skip the `addsize' at the end */
sprintf(buff, form, s); }
break; else {
} sprintf(buff, form, s);
} break;
default: { /* also treat cases `pnLlh' */ }
return luaL_error(L, "invalid option " LUA_QL("%%%c") " to " }
LUA_QL("format"), *(strfrmt - 1)); default: { /* also treat cases `pnLlh' */
} return luaL_error(L, "invalid option " LUA_QL("%%%c") " to "
} LUA_QL("format"), *(strfrmt - 1));
luaL_addlstring(&b, buff, strlen(buff)); }
} }
} luaL_addlstring(&b, buff, strlen(buff));
luaL_pushresult(&b); }
return 1; }
} luaL_pushresult(&b);
return 1;
}
static const luaL_Reg strlib[] = {
{"byte", str_byte},
{"char", str_char}, static const luaL_Reg strlib[] = {
{"dump", str_dump}, {"byte", str_byte},
{"find", str_find}, {"char", str_char},
{"format", str_format}, {"dump", str_dump},
{"gfind", gfind_nodef}, {"find", str_find},
{"gmatch", gmatch}, {"format", str_format},
{"gsub", str_gsub}, {"gfind", gfind_nodef},
{"len", str_len}, {"gmatch", gmatch},
{"lower", str_lower}, {"gsub", str_gsub},
{"match", str_match}, {"len", str_len},
{"rep", str_rep}, {"lower", str_lower},
{"reverse", str_reverse}, {"match", str_match},
{"sub", str_sub}, {"rep", str_rep},
{"upper", str_upper}, {"reverse", str_reverse},
{NULL, NULL} {"sub", str_sub},
}; {"upper", str_upper},
{NULL, NULL}
};
static void createmetatable (lua_State *L) {
lua_createtable(L, 0, 1); /* create metatable for strings */
lua_pushliteral(L, ""); /* dummy string */ static void createmetatable (lua_State *L) {
lua_pushvalue(L, -2); lua_createtable(L, 0, 1); /* create metatable for strings */
lua_setmetatable(L, -2); /* set string metatable */ lua_pushliteral(L, ""); /* dummy string */
lua_pop(L, 1); /* pop dummy string */ lua_pushvalue(L, -2);
lua_pushvalue(L, -2); /* string library... */ lua_setmetatable(L, -2); /* set string metatable */
lua_setfield(L, -2, "__index"); /* ...is the __index metamethod */ lua_pop(L, 1); /* pop dummy string */
lua_pop(L, 1); /* pop metatable */ lua_pushvalue(L, -2); /* string library... */
} lua_setfield(L, -2, "__index"); /* ...is the __index metamethod */
lua_pop(L, 1); /* pop metatable */
}
/*
** Open string library
*/ /*
LUALIB_API int luaopen_string (lua_State *L) { ** Open string library
luaL_register(L, LUA_STRLIBNAME, strlib); */
#if defined(LUA_COMPAT_GFIND) LUALIB_API int luaopen_string (lua_State *L) {
lua_getfield(L, -1, "gmatch"); luaL_register(L, LUA_STRLIBNAME, strlib);
lua_setfield(L, -2, "gfind"); #if defined(LUA_COMPAT_GFIND)
#endif lua_getfield(L, -1, "gmatch");
createmetatable(L); lua_setfield(L, -2, "gfind");
return 1; #endif
} createmetatable(L);
return 1;
}
/* /*
** $Id: lvm.c,v 2.63.1.3 2007/12/28 15:32:23 roberto Exp $ ** $Id: lvm.c,v 2.63.1.4 2009/07/01 21:10:33 roberto Exp $
** Lua virtual machine ** Lua virtual machine
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#define lvm_c #define lvm_c
#define LUA_CORE #define LUA_CORE
#include "lua.h" #include "lua.h"
#include "ldebug.h" #include "ldebug.h"
#include "ldo.h" #include "ldo.h"
#include "lfunc.h" #include "lfunc.h"
#include "lgc.h" #include "lgc.h"
#include "lobject.h" #include "lobject.h"
#include "lopcodes.h" #include "lopcodes.h"
#include "lstate.h" #include "lstate.h"
#include "lstring.h" #include "lstring.h"
#include "ltable.h" #include "ltable.h"
#include "ltm.h" #include "ltm.h"
#include "lvm.h" #include "lvm.h"
/* limit for table tag-method chains (to avoid loops) */ /* limit for table tag-method chains (to avoid loops) */
#define MAXTAGLOOP 100 #define MAXTAGLOOP 100
const TValue *luaV_tonumber (const TValue *obj, TValue *n) { const TValue *luaV_tonumber (const TValue *obj, TValue *n) {
lua_Number num; lua_Number num;
if (ttisnumber(obj)) return obj; if (ttisnumber(obj)) return obj;
if (ttisstring(obj) && luaO_str2d(svalue(obj), &num)) { if (ttisstring(obj) && luaO_str2d(svalue(obj), &num)) {
setnvalue(n, num); setnvalue(n, num);
return n; return n;
} }
else else
return NULL; return NULL;
} }
int luaV_tostring (lua_State *L, StkId obj) { int luaV_tostring (lua_State *L, StkId obj) {
if (!ttisnumber(obj)) if (!ttisnumber(obj))
return 0; return 0;
else { else {
char s[LUAI_MAXNUMBER2STR]; char s[LUAI_MAXNUMBER2STR];
lua_Number n = nvalue(obj); lua_Number n = nvalue(obj);
lua_number2str(s, n); lua_number2str(s, n);
setsvalue2s(L, obj, luaS_new(L, s)); setsvalue2s(L, obj, luaS_new(L, s));
return 1; return 1;
} }
} }
static void traceexec (lua_State *L, const Instruction *pc) { static void traceexec (lua_State *L, const Instruction *pc) {
lu_byte mask = L->hookmask; lu_byte mask = L->hookmask;
const Instruction *oldpc = L->savedpc; const Instruction *oldpc = L->savedpc;
L->savedpc = pc; L->savedpc = pc;
if ((mask & LUA_MASKCOUNT) && L->hookcount == 0) { if ((mask & LUA_MASKCOUNT) && L->hookcount == 0) {
resethookcount(L); resethookcount(L);
luaD_callhook(L, LUA_HOOKCOUNT, -1); luaD_callhook(L, LUA_HOOKCOUNT, -1);
} }
if (mask & LUA_MASKLINE) { if (mask & LUA_MASKLINE) {
Proto *p = ci_func(L->ci)->l.p; Proto *p = ci_func(L->ci)->l.p;
int npc = pcRel(pc, p); int npc = pcRel(pc, p);
int newline = getline(p, npc); int newline = getline(p, npc);
/* call linehook when enter a new function, when jump back (loop), /* call linehook when enter a new function, when jump back (loop),
or when enter a new line */ or when enter a new line */
if (npc == 0 || pc <= oldpc || newline != getline(p, pcRel(oldpc, p))) if (npc == 0 || pc <= oldpc || newline != getline(p, pcRel(oldpc, p)))
luaD_callhook(L, LUA_HOOKLINE, newline); luaD_callhook(L, LUA_HOOKLINE, newline);
} }
} }
static void callTMres (lua_State *L, StkId res, const TValue *f, static void callTMres (lua_State *L, StkId res, const TValue *f,
const TValue *p1, const TValue *p2) { const TValue *p1, const TValue *p2) {
ptrdiff_t result = savestack(L, res); ptrdiff_t result = savestack(L, res);
setobj2s(L, L->top, f); /* push function */ setobj2s(L, L->top, f); /* push function */
setobj2s(L, L->top+1, p1); /* 1st argument */ setobj2s(L, L->top+1, p1); /* 1st argument */
setobj2s(L, L->top+2, p2); /* 2nd argument */ setobj2s(L, L->top+2, p2); /* 2nd argument */
luaD_checkstack(L, 3); luaD_checkstack(L, 3);
L->top += 3; L->top += 3;
luaD_call(L, L->top - 3, 1); luaD_call(L, L->top - 3, 1);
res = restorestack(L, result); res = restorestack(L, result);
L->top--; L->top--;
setobjs2s(L, res, L->top); setobjs2s(L, res, L->top);
} }
static void callTM (lua_State *L, const TValue *f, const TValue *p1, static void callTM (lua_State *L, const TValue *f, const TValue *p1,
const TValue *p2, const TValue *p3) { const TValue *p2, const TValue *p3) {
setobj2s(L, L->top, f); /* push function */ setobj2s(L, L->top, f); /* push function */
setobj2s(L, L->top+1, p1); /* 1st argument */ setobj2s(L, L->top+1, p1); /* 1st argument */
setobj2s(L, L->top+2, p2); /* 2nd argument */ setobj2s(L, L->top+2, p2); /* 2nd argument */
setobj2s(L, L->top+3, p3); /* 3th argument */ setobj2s(L, L->top+3, p3); /* 3th argument */
luaD_checkstack(L, 4); luaD_checkstack(L, 4);
L->top += 4; L->top += 4;
luaD_call(L, L->top - 4, 0); luaD_call(L, L->top - 4, 0);
} }
void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) {
int loop; int loop;
for (loop = 0; loop < MAXTAGLOOP; loop++) { for (loop = 0; loop < MAXTAGLOOP; loop++) {
const TValue *tm; const TValue *tm;
if (ttistable(t)) { /* `t' is a table? */ if (ttistable(t)) { /* `t' is a table? */
Table *h = hvalue(t); Table *h = hvalue(t);
const TValue *res = luaH_get(h, key); /* do a primitive get */ const TValue *res = luaH_get(h, key); /* do a primitive get */
if (!ttisnil(res) || /* result is no nil? */ if (!ttisnil(res) || /* result is no nil? */
(tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */
setobj2s(L, val, res); setobj2s(L, val, res);
return; return;
} }
/* else will try the tag method */ /* else will try the tag method */
} }
else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX)))
luaG_typeerror(L, t, "index"); luaG_typeerror(L, t, "index");
if (ttisfunction(tm)) { if (ttisfunction(tm)) {
callTMres(L, val, tm, t, key); callTMres(L, val, tm, t, key);
return; return;
} }
t = tm; /* else repeat with `tm' */ t = tm; /* else repeat with `tm' */
} }
luaG_runerror(L, "loop in gettable"); luaG_runerror(L, "loop in gettable");
} }
void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
int loop; int loop;
for (loop = 0; loop < MAXTAGLOOP; loop++) { TValue temp;
const TValue *tm; for (loop = 0; loop < MAXTAGLOOP; loop++) {
if (ttistable(t)) { /* `t' is a table? */ const TValue *tm;
Table *h = hvalue(t); if (ttistable(t)) { /* `t' is a table? */
TValue *oldval = luaH_set(L, h, key); /* do a primitive set */ Table *h = hvalue(t);
if (!ttisnil(oldval) || /* result is no nil? */ TValue *oldval = luaH_set(L, h, key); /* do a primitive set */
(tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ if (!ttisnil(oldval) || /* result is no nil? */
setobj2t(L, oldval, val); (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */
luaC_barriert(L, h, val); setobj2t(L, oldval, val);
return; luaC_barriert(L, h, val);
} return;
/* else will try the tag method */ }
} /* else will try the tag method */
else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) }
luaG_typeerror(L, t, "index"); else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX)))
if (ttisfunction(tm)) { luaG_typeerror(L, t, "index");
callTM(L, tm, t, key, val); if (ttisfunction(tm)) {
return; callTM(L, tm, t, key, val);
} return;
t = tm; /* else repeat with `tm' */ }
} /* else repeat with `tm' */
luaG_runerror(L, "loop in settable"); setobj(L, &temp, tm); /* avoid pointing inside table (may rehash) */
} t = &temp;
}
luaG_runerror(L, "loop in settable");
static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2, }
StkId res, TMS event) {
const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */
if (ttisnil(tm)) static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2,
tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ StkId res, TMS event) {
if (ttisnil(tm)) return 0; const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */
callTMres(L, res, tm, p1, p2); if (ttisnil(tm))
return 1; tm = luaT_gettmbyobj(L, p2, event); /* try second operand */
} if (ttisnil(tm)) return 0;
callTMres(L, res, tm, p1, p2);
return 1;
static const TValue *get_compTM (lua_State *L, Table *mt1, Table *mt2, }
TMS event) {
const TValue *tm1 = fasttm(L, mt1, event);
const TValue *tm2; static const TValue *get_compTM (lua_State *L, Table *mt1, Table *mt2,
if (tm1 == NULL) return NULL; /* no metamethod */ TMS event) {
if (mt1 == mt2) return tm1; /* same metatables => same metamethods */ const TValue *tm1 = fasttm(L, mt1, event);
tm2 = fasttm(L, mt2, event); const TValue *tm2;
if (tm2 == NULL) return NULL; /* no metamethod */ if (tm1 == NULL) return NULL; /* no metamethod */
if (luaO_rawequalObj(tm1, tm2)) /* same metamethods? */ if (mt1 == mt2) return tm1; /* same metatables => same metamethods */
return tm1; tm2 = fasttm(L, mt2, event);
return NULL; if (tm2 == NULL) return NULL; /* no metamethod */
} if (luaO_rawequalObj(tm1, tm2)) /* same metamethods? */
return tm1;
return NULL;
static int call_orderTM (lua_State *L, const TValue *p1, const TValue *p2, }
TMS event) {
const TValue *tm1 = luaT_gettmbyobj(L, p1, event);
const TValue *tm2; static int call_orderTM (lua_State *L, const TValue *p1, const TValue *p2,
if (ttisnil(tm1)) return -1; /* no metamethod? */ TMS event) {
tm2 = luaT_gettmbyobj(L, p2, event); const TValue *tm1 = luaT_gettmbyobj(L, p1, event);
if (!luaO_rawequalObj(tm1, tm2)) /* different metamethods? */ const TValue *tm2;
return -1; if (ttisnil(tm1)) return -1; /* no metamethod? */
callTMres(L, L->top, tm1, p1, p2); tm2 = luaT_gettmbyobj(L, p2, event);
return !l_isfalse(L->top); if (!luaO_rawequalObj(tm1, tm2)) /* different metamethods? */
} return -1;
callTMres(L, L->top, tm1, p1, p2);
return !l_isfalse(L->top);
static int l_strcmp (const TString *ls, const TString *rs) { }
const char *l = getstr(ls);
size_t ll = ls->tsv.len;
const char *r = getstr(rs); static int l_strcmp (const TString *ls, const TString *rs) {
size_t lr = rs->tsv.len; const char *l = getstr(ls);
for (;;) { size_t ll = ls->tsv.len;
int temp = strcoll(l, r); const char *r = getstr(rs);
if (temp != 0) return temp; size_t lr = rs->tsv.len;
else { /* strings are equal up to a `\0' */ for (;;) {
size_t len = strlen(l); /* index of first `\0' in both strings */ int temp = strcoll(l, r);
if (len == lr) /* r is finished? */ if (temp != 0) return temp;
return (len == ll) ? 0 : 1; else { /* strings are equal up to a `\0' */
else if (len == ll) /* l is finished? */ size_t len = strlen(l); /* index of first `\0' in both strings */
return -1; /* l is smaller than r (because r is not finished) */ if (len == lr) /* r is finished? */
/* both strings longer than `len'; go on comparing (after the `\0') */ return (len == ll) ? 0 : 1;
len++; else if (len == ll) /* l is finished? */
l += len; ll -= len; r += len; lr -= len; return -1; /* l is smaller than r (because r is not finished) */
} /* both strings longer than `len'; go on comparing (after the `\0') */
} len++;
} l += len; ll -= len; r += len; lr -= len;
}
}
int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { }
int res;
if (ttype(l) != ttype(r))
return luaG_ordererror(L, l, r); int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
else if (ttisnumber(l)) int res;
return luai_numlt(nvalue(l), nvalue(r)); if (ttype(l) != ttype(r))
else if (ttisstring(l)) return luaG_ordererror(L, l, r);
return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0; else if (ttisnumber(l))
else if ((res = call_orderTM(L, l, r, TM_LT)) != -1) return luai_numlt(nvalue(l), nvalue(r));
return res; else if (ttisstring(l))
return luaG_ordererror(L, l, r); return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0;
} else if ((res = call_orderTM(L, l, r, TM_LT)) != -1)
return res;
return luaG_ordererror(L, l, r);
static int lessequal (lua_State *L, const TValue *l, const TValue *r) { }
int res;
if (ttype(l) != ttype(r))
return luaG_ordererror(L, l, r); static int lessequal (lua_State *L, const TValue *l, const TValue *r) {
else if (ttisnumber(l)) int res;
return luai_numle(nvalue(l), nvalue(r)); if (ttype(l) != ttype(r))
else if (ttisstring(l)) return luaG_ordererror(L, l, r);
return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0; else if (ttisnumber(l))
else if ((res = call_orderTM(L, l, r, TM_LE)) != -1) /* first try `le' */ return luai_numle(nvalue(l), nvalue(r));
return res; else if (ttisstring(l))
else if ((res = call_orderTM(L, r, l, TM_LT)) != -1) /* else try `lt' */ return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0;
return !res; else if ((res = call_orderTM(L, l, r, TM_LE)) != -1) /* first try `le' */
return luaG_ordererror(L, l, r); return res;
} else if ((res = call_orderTM(L, r, l, TM_LT)) != -1) /* else try `lt' */
return !res;
return luaG_ordererror(L, l, r);
int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) { }
const TValue *tm;
lua_assert(ttype(t1) == ttype(t2));
switch (ttype(t1)) { int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) {
case LUA_TNIL: return 1; const TValue *tm;
case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2)); lua_assert(ttype(t1) == ttype(t2));
case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ switch (ttype(t1)) {
case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); case LUA_TNIL: return 1;
case LUA_TUSERDATA: { case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2));
if (uvalue(t1) == uvalue(t2)) return 1; case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */
tm = get_compTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable, case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2);
TM_EQ); case LUA_TUSERDATA: {
break; /* will try TM */ if (uvalue(t1) == uvalue(t2)) return 1;
} tm = get_compTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable,
case LUA_TTABLE: { TM_EQ);
if (hvalue(t1) == hvalue(t2)) return 1; break; /* will try TM */
tm = get_compTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ); }
break; /* will try TM */ case LUA_TTABLE: {
} if (hvalue(t1) == hvalue(t2)) return 1;
default: return gcvalue(t1) == gcvalue(t2); tm = get_compTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ);
} break; /* will try TM */
if (tm == NULL) return 0; /* no TM? */ }
callTMres(L, L->top, tm, t1, t2); /* call TM */ default: return gcvalue(t1) == gcvalue(t2);
return !l_isfalse(L->top); }
} if (tm == NULL) return 0; /* no TM? */
callTMres(L, L->top, tm, t1, t2); /* call TM */
return !l_isfalse(L->top);
void luaV_concat (lua_State *L, int total, int last) { }
do {
StkId top = L->base + last + 1;
int n = 2; /* number of elements handled in this pass (at least 2) */ void luaV_concat (lua_State *L, int total, int last) {
if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) { do {
if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) StkId top = L->base + last + 1;
luaG_concaterror(L, top-2, top-1); int n = 2; /* number of elements handled in this pass (at least 2) */
} else if (tsvalue(top-1)->len == 0) /* second op is empty? */ if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) {
(void)tostring(L, top - 2); /* result is first op (as string) */ if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT))
else { luaG_concaterror(L, top-2, top-1);
/* at least two string values; get as many as possible */ } else if (tsvalue(top-1)->len == 0) /* second op is empty? */
size_t tl = tsvalue(top-1)->len; (void)tostring(L, top - 2); /* result is first op (as string) */
char *buffer; else {
int i; /* at least two string values; get as many as possible */
/* collect total length */ size_t tl = tsvalue(top-1)->len;
for (n = 1; n < total && tostring(L, top-n-1); n++) { char *buffer;
size_t l = tsvalue(top-n-1)->len; int i;
if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow"); /* collect total length */
tl += l; for (n = 1; n < total && tostring(L, top-n-1); n++) {
} size_t l = tsvalue(top-n-1)->len;
buffer = luaZ_openspace(L, &G(L)->buff, tl); if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow");
tl = 0; tl += l;
for (i=n; i>0; i--) { /* concat all strings */ }
size_t l = tsvalue(top-i)->len; buffer = luaZ_openspace(L, &G(L)->buff, tl);
memcpy(buffer+tl, svalue(top-i), l); tl = 0;
tl += l; for (i=n; i>0; i--) { /* concat all strings */
} size_t l = tsvalue(top-i)->len;
setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); memcpy(buffer+tl, svalue(top-i), l);
} tl += l;
total -= n-1; /* got `n' strings to create 1 new */ }
last -= n-1; setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl));
} while (total > 1); /* repeat until only 1 result left */ }
} total -= n-1; /* got `n' strings to create 1 new */
last -= n-1;
} while (total > 1); /* repeat until only 1 result left */
static void Arith (lua_State *L, StkId ra, const TValue *rb, }
const TValue *rc, TMS op) {
TValue tempb, tempc;
const TValue *b, *c; static void Arith (lua_State *L, StkId ra, const TValue *rb,
if ((b = luaV_tonumber(rb, &tempb)) != NULL && const TValue *rc, TMS op) {
(c = luaV_tonumber(rc, &tempc)) != NULL) { TValue tempb, tempc;
lua_Number nb = nvalue(b), nc = nvalue(c); const TValue *b, *c;
switch (op) { if ((b = luaV_tonumber(rb, &tempb)) != NULL &&
case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break; (c = luaV_tonumber(rc, &tempc)) != NULL) {
case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break; lua_Number nb = nvalue(b), nc = nvalue(c);
case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break; switch (op) {
case TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); break; case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break;
case TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); break; case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break;
case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break; case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break;
case TM_UNM: setnvalue(ra, luai_numunm(nb)); break; case TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); break;
default: lua_assert(0); break; case TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); break;
} case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break;
} case TM_UNM: setnvalue(ra, luai_numunm(nb)); break;
else if (!call_binTM(L, rb, rc, ra, op)) default: lua_assert(0); break;
luaG_aritherror(L, rb, rc); }
} }
else if (!call_binTM(L, rb, rc, ra, op))
luaG_aritherror(L, rb, rc);
}
/*
** some macros for common tasks in `luaV_execute'
*/
/*
#define runtime_check(L, c) { if (!(c)) break; } ** some macros for common tasks in `luaV_execute'
*/
#define RA(i) (base+GETARG_A(i))
/* to be used after possible stack reallocation */ #define runtime_check(L, c) { if (!(c)) break; }
#define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i))
#define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i)) #define RA(i) (base+GETARG_A(i))
#define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \ /* to be used after possible stack reallocation */
ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i)) #define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i))
#define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \ #define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i))
ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i)) #define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \
#define KBx(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, k+GETARG_Bx(i)) ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i))
#define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \
ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i))
#define dojump(L,pc,i) {(pc) += (i); luai_threadyield(L);} #define KBx(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, k+GETARG_Bx(i))
#define Protect(x) { L->savedpc = pc; {x;}; base = L->base; } #define dojump(L,pc,i) {(pc) += (i); luai_threadyield(L);}
#define arith_op(op,tm) { \ #define Protect(x) { L->savedpc = pc; {x;}; base = L->base; }
TValue *rb = RKB(i); \
TValue *rc = RKC(i); \
if (ttisnumber(rb) && ttisnumber(rc)) { \ #define arith_op(op,tm) { \
lua_Number nb = nvalue(rb), nc = nvalue(rc); \ TValue *rb = RKB(i); \
setnvalue(ra, op(nb, nc)); \ TValue *rc = RKC(i); \
} \ if (ttisnumber(rb) && ttisnumber(rc)) { \
else \ lua_Number nb = nvalue(rb), nc = nvalue(rc); \
Protect(Arith(L, ra, rb, rc, tm)); \ setnvalue(ra, op(nb, nc)); \
} } \
else \
Protect(Arith(L, ra, rb, rc, tm)); \
}
void luaV_execute (lua_State *L, int nexeccalls) {
LClosure *cl;
StkId base;
TValue *k; void luaV_execute (lua_State *L, int nexeccalls) {
const Instruction *pc; LClosure *cl;
reentry: /* entry point */ StkId base;
lua_assert(isLua(L->ci)); TValue *k;
pc = L->savedpc; const Instruction *pc;
cl = &clvalue(L->ci->func)->l; reentry: /* entry point */
base = L->base; lua_assert(isLua(L->ci));
k = cl->p->k; pc = L->savedpc;
/* main loop of interpreter */ cl = &clvalue(L->ci->func)->l;
for (;;) { base = L->base;
const Instruction i = *pc++; k = cl->p->k;
StkId ra; /* main loop of interpreter */
if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && for (;;) {
(--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { const Instruction i = *pc++;
traceexec(L, pc); StkId ra;
if (L->status == LUA_YIELD) { /* did hook yield? */ if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) &&
L->savedpc = pc - 1; (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) {
return; traceexec(L, pc);
} if (L->status == LUA_YIELD) { /* did hook yield? */
base = L->base; L->savedpc = pc - 1;
} return;
/* warning!! several calls may realloc the stack and invalidate `ra' */ }
ra = RA(i); base = L->base;
lua_assert(base == L->base && L->base == L->ci->base); }
lua_assert(base <= L->top && L->top <= L->stack + L->stacksize); /* warning!! several calls may realloc the stack and invalidate `ra' */
lua_assert(L->top == L->ci->top || luaG_checkopenop(i)); ra = RA(i);
switch (GET_OPCODE(i)) { lua_assert(base == L->base && L->base == L->ci->base);
case OP_MOVE: { lua_assert(base <= L->top && L->top <= L->stack + L->stacksize);
setobjs2s(L, ra, RB(i)); lua_assert(L->top == L->ci->top || luaG_checkopenop(i));
continue; switch (GET_OPCODE(i)) {
} case OP_MOVE: {
case OP_LOADK: { setobjs2s(L, ra, RB(i));
setobj2s(L, ra, KBx(i)); continue;
continue; }
} case OP_LOADK: {
case OP_LOADBOOL: { setobj2s(L, ra, KBx(i));
setbvalue(ra, GETARG_B(i)); continue;
if (GETARG_C(i)) pc++; /* skip next instruction (if C) */ }
continue; case OP_LOADBOOL: {
} setbvalue(ra, GETARG_B(i));
case OP_LOADNIL: { if (GETARG_C(i)) pc++; /* skip next instruction (if C) */
TValue *rb = RB(i); continue;
do { }
setnilvalue(rb--); case OP_LOADNIL: {
} while (rb >= ra); TValue *rb = RB(i);
continue; do {
} setnilvalue(rb--);
case OP_GETUPVAL: { } while (rb >= ra);
int b = GETARG_B(i); continue;
setobj2s(L, ra, cl->upvals[b]->v); }
continue; case OP_GETUPVAL: {
} int b = GETARG_B(i);
case OP_GETGLOBAL: { setobj2s(L, ra, cl->upvals[b]->v);
TValue g; continue;
TValue *rb = KBx(i); }
sethvalue(L, &g, cl->env); case OP_GETGLOBAL: {
lua_assert(ttisstring(rb)); TValue g;
Protect(luaV_gettable(L, &g, rb, ra)); TValue *rb = KBx(i);
continue; sethvalue(L, &g, cl->env);
} lua_assert(ttisstring(rb));
case OP_GETTABLE: { Protect(luaV_gettable(L, &g, rb, ra));
Protect(luaV_gettable(L, RB(i), RKC(i), ra)); continue;
continue; }
} case OP_GETTABLE: {
case OP_SETGLOBAL: { Protect(luaV_gettable(L, RB(i), RKC(i), ra));
TValue g; continue;
sethvalue(L, &g, cl->env); }
lua_assert(ttisstring(KBx(i))); case OP_SETGLOBAL: {
Protect(luaV_settable(L, &g, KBx(i), ra)); TValue g;
continue; sethvalue(L, &g, cl->env);
} lua_assert(ttisstring(KBx(i)));
case OP_SETUPVAL: { Protect(luaV_settable(L, &g, KBx(i), ra));
UpVal *uv = cl->upvals[GETARG_B(i)]; continue;
setobj(L, uv->v, ra); }
luaC_barrier(L, uv, ra); case OP_SETUPVAL: {
continue; UpVal *uv = cl->upvals[GETARG_B(i)];
} setobj(L, uv->v, ra);
case OP_SETTABLE: { luaC_barrier(L, uv, ra);
Protect(luaV_settable(L, ra, RKB(i), RKC(i))); continue;
continue; }
} case OP_SETTABLE: {
case OP_NEWTABLE: { Protect(luaV_settable(L, ra, RKB(i), RKC(i)));
int b = GETARG_B(i); continue;
int c = GETARG_C(i); }
sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c))); case OP_NEWTABLE: {
Protect(luaC_checkGC(L)); int b = GETARG_B(i);
continue; int c = GETARG_C(i);
} sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c)));
case OP_SELF: { Protect(luaC_checkGC(L));
StkId rb = RB(i); continue;
setobjs2s(L, ra+1, rb); }
Protect(luaV_gettable(L, rb, RKC(i), ra)); case OP_SELF: {
continue; StkId rb = RB(i);
} setobjs2s(L, ra+1, rb);
case OP_ADD: { Protect(luaV_gettable(L, rb, RKC(i), ra));
arith_op(luai_numadd, TM_ADD); continue;
continue; }
} case OP_ADD: {
case OP_SUB: { arith_op(luai_numadd, TM_ADD);
arith_op(luai_numsub, TM_SUB); continue;
continue; }
} case OP_SUB: {
case OP_MUL: { arith_op(luai_numsub, TM_SUB);
arith_op(luai_nummul, TM_MUL); continue;
continue; }
} case OP_MUL: {
case OP_DIV: { arith_op(luai_nummul, TM_MUL);
arith_op(luai_numdiv, TM_DIV); continue;
continue; }
} case OP_DIV: {
case OP_MOD: { arith_op(luai_numdiv, TM_DIV);
arith_op(luai_nummod, TM_MOD); continue;
continue; }
} case OP_MOD: {
case OP_POW: { arith_op(luai_nummod, TM_MOD);
arith_op(luai_numpow, TM_POW); continue;
continue; }
} case OP_POW: {
case OP_UNM: { arith_op(luai_numpow, TM_POW);
TValue *rb = RB(i); continue;
if (ttisnumber(rb)) { }
lua_Number nb = nvalue(rb); case OP_UNM: {
setnvalue(ra, luai_numunm(nb)); TValue *rb = RB(i);
} if (ttisnumber(rb)) {
else { lua_Number nb = nvalue(rb);
Protect(Arith(L, ra, rb, rb, TM_UNM)); setnvalue(ra, luai_numunm(nb));
} }
continue; else {
} Protect(Arith(L, ra, rb, rb, TM_UNM));
case OP_NOT: { }
int res = l_isfalse(RB(i)); /* next assignment may change this value */ continue;
setbvalue(ra, res); }
continue; case OP_NOT: {
} int res = l_isfalse(RB(i)); /* next assignment may change this value */
case OP_LEN: { setbvalue(ra, res);
const TValue *rb = RB(i); continue;
switch (ttype(rb)) { }
case LUA_TTABLE: { case OP_LEN: {
setnvalue(ra, cast_num(luaH_getn(hvalue(rb)))); const TValue *rb = RB(i);
break; switch (ttype(rb)) {
} case LUA_TTABLE: {
case LUA_TSTRING: { setnvalue(ra, cast_num(luaH_getn(hvalue(rb))));
setnvalue(ra, cast_num(tsvalue(rb)->len)); break;
break; }
} case LUA_TSTRING: {
default: { /* try metamethod */ setnvalue(ra, cast_num(tsvalue(rb)->len));
Protect( break;
if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN)) }
luaG_typeerror(L, rb, "get length of"); default: { /* try metamethod */
) Protect(
} if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN))
} luaG_typeerror(L, rb, "get length of");
continue; )
} }
case OP_CONCAT: { }
int b = GETARG_B(i); continue;
int c = GETARG_C(i); }
Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L)); case OP_CONCAT: {
setobjs2s(L, RA(i), base+b); int b = GETARG_B(i);
continue; int c = GETARG_C(i);
} Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L));
case OP_JMP: { setobjs2s(L, RA(i), base+b);
dojump(L, pc, GETARG_sBx(i)); continue;
continue; }
} case OP_JMP: {
case OP_EQ: { dojump(L, pc, GETARG_sBx(i));
TValue *rb = RKB(i); continue;
TValue *rc = RKC(i); }
Protect( case OP_EQ: {
if (equalobj(L, rb, rc) == GETARG_A(i)) TValue *rb = RKB(i);
dojump(L, pc, GETARG_sBx(*pc)); TValue *rc = RKC(i);
) Protect(
pc++; if (equalobj(L, rb, rc) == GETARG_A(i))
continue; dojump(L, pc, GETARG_sBx(*pc));
} )
case OP_LT: { pc++;
Protect( continue;
if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i)) }
dojump(L, pc, GETARG_sBx(*pc)); case OP_LT: {
) Protect(
pc++; if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i))
continue; dojump(L, pc, GETARG_sBx(*pc));
} )
case OP_LE: { pc++;
Protect( continue;
if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i)) }
dojump(L, pc, GETARG_sBx(*pc)); case OP_LE: {
) Protect(
pc++; if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i))
continue; dojump(L, pc, GETARG_sBx(*pc));
} )
case OP_TEST: { pc++;
if (l_isfalse(ra) != GETARG_C(i)) continue;
dojump(L, pc, GETARG_sBx(*pc)); }
pc++; case OP_TEST: {
continue; if (l_isfalse(ra) != GETARG_C(i))
} dojump(L, pc, GETARG_sBx(*pc));
case OP_TESTSET: { pc++;
TValue *rb = RB(i); continue;
if (l_isfalse(rb) != GETARG_C(i)) { }
setobjs2s(L, ra, rb); case OP_TESTSET: {
dojump(L, pc, GETARG_sBx(*pc)); TValue *rb = RB(i);
} if (l_isfalse(rb) != GETARG_C(i)) {
pc++; setobjs2s(L, ra, rb);
continue; dojump(L, pc, GETARG_sBx(*pc));
} }
case OP_CALL: { pc++;
int b = GETARG_B(i); continue;
int nresults = GETARG_C(i) - 1; }
if (b != 0) L->top = ra+b; /* else previous instruction set top */ case OP_CALL: {
L->savedpc = pc; int b = GETARG_B(i);
switch (luaD_precall(L, ra, nresults)) { int nresults = GETARG_C(i) - 1;
case PCRLUA: { if (b != 0) L->top = ra+b; /* else previous instruction set top */
nexeccalls++; L->savedpc = pc;
goto reentry; /* restart luaV_execute over new Lua function */ switch (luaD_precall(L, ra, nresults)) {
} case PCRLUA: {
case PCRC: { nexeccalls++;
/* it was a C function (`precall' called it); adjust results */ goto reentry; /* restart luaV_execute over new Lua function */
if (nresults >= 0) L->top = L->ci->top; }
base = L->base; case PCRC: {
continue; /* it was a C function (`precall' called it); adjust results */
} if (nresults >= 0) L->top = L->ci->top;
default: { base = L->base;
return; /* yield */ continue;
} }
} default: {
} return; /* yield */
case OP_TAILCALL: { }
int b = GETARG_B(i); }
if (b != 0) L->top = ra+b; /* else previous instruction set top */ }
L->savedpc = pc; case OP_TAILCALL: {
lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); int b = GETARG_B(i);
switch (luaD_precall(L, ra, LUA_MULTRET)) { if (b != 0) L->top = ra+b; /* else previous instruction set top */
case PCRLUA: { L->savedpc = pc;
/* tail call: put new frame in place of previous one */ lua_assert(GETARG_C(i) - 1 == LUA_MULTRET);
CallInfo *ci = L->ci - 1; /* previous frame */ switch (luaD_precall(L, ra, LUA_MULTRET)) {
int aux; case PCRLUA: {
StkId func = ci->func; /* tail call: put new frame in place of previous one */
StkId pfunc = (ci+1)->func; /* previous function index */ CallInfo *ci = L->ci - 1; /* previous frame */
if (L->openupval) luaF_close(L, ci->base); int aux;
L->base = ci->base = ci->func + ((ci+1)->base - pfunc); StkId func = ci->func;
for (aux = 0; pfunc+aux < L->top; aux++) /* move frame down */ StkId pfunc = (ci+1)->func; /* previous function index */
setobjs2s(L, func+aux, pfunc+aux); if (L->openupval) luaF_close(L, ci->base);
ci->top = L->top = func+aux; /* correct top */ L->base = ci->base = ci->func + ((ci+1)->base - pfunc);
lua_assert(L->top == L->base + clvalue(func)->l.p->maxstacksize); for (aux = 0; pfunc+aux < L->top; aux++) /* move frame down */
ci->savedpc = L->savedpc; setobjs2s(L, func+aux, pfunc+aux);
ci->tailcalls++; /* one more call lost */ ci->top = L->top = func+aux; /* correct top */
L->ci--; /* remove new frame */ lua_assert(L->top == L->base + clvalue(func)->l.p->maxstacksize);
goto reentry; ci->savedpc = L->savedpc;
} ci->tailcalls++; /* one more call lost */
case PCRC: { /* it was a C function (`precall' called it) */ L->ci--; /* remove new frame */
base = L->base; goto reentry;
continue; }
} case PCRC: { /* it was a C function (`precall' called it) */
default: { base = L->base;
return; /* yield */ continue;
} }
} default: {
} return; /* yield */
case OP_RETURN: { }
int b = GETARG_B(i); }
if (b != 0) L->top = ra+b-1; }
if (L->openupval) luaF_close(L, base); case OP_RETURN: {
L->savedpc = pc; int b = GETARG_B(i);
b = luaD_poscall(L, ra); if (b != 0) L->top = ra+b-1;
if (--nexeccalls == 0) /* was previous function running `here'? */ if (L->openupval) luaF_close(L, base);
return; /* no: return */ L->savedpc = pc;
else { /* yes: continue its execution */ b = luaD_poscall(L, ra);
if (b) L->top = L->ci->top; if (--nexeccalls == 0) /* was previous function running `here'? */
lua_assert(isLua(L->ci)); return; /* no: return */
lua_assert(GET_OPCODE(*((L->ci)->savedpc - 1)) == OP_CALL); else { /* yes: continue its execution */
goto reentry; if (b) L->top = L->ci->top;
} lua_assert(isLua(L->ci));
} lua_assert(GET_OPCODE(*((L->ci)->savedpc - 1)) == OP_CALL);
case OP_FORLOOP: { goto reentry;
lua_Number step = nvalue(ra+2); }
lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */ }
lua_Number limit = nvalue(ra+1); case OP_FORLOOP: {
if (luai_numlt(0, step) ? luai_numle(idx, limit) lua_Number step = nvalue(ra+2);
: luai_numle(limit, idx)) { lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */
dojump(L, pc, GETARG_sBx(i)); /* jump back */ lua_Number limit = nvalue(ra+1);
setnvalue(ra, idx); /* update internal index... */ if (luai_numlt(0, step) ? luai_numle(idx, limit)
setnvalue(ra+3, idx); /* ...and external index */ : luai_numle(limit, idx)) {
} dojump(L, pc, GETARG_sBx(i)); /* jump back */
continue; setnvalue(ra, idx); /* update internal index... */
} setnvalue(ra+3, idx); /* ...and external index */
case OP_FORPREP: { }
const TValue *init = ra; continue;
const TValue *plimit = ra+1; }
const TValue *pstep = ra+2; case OP_FORPREP: {
L->savedpc = pc; /* next steps may throw errors */ const TValue *init = ra;
if (!tonumber(init, ra)) const TValue *plimit = ra+1;
luaG_runerror(L, LUA_QL("for") " initial value must be a number"); const TValue *pstep = ra+2;
else if (!tonumber(plimit, ra+1)) L->savedpc = pc; /* next steps may throw errors */
luaG_runerror(L, LUA_QL("for") " limit must be a number"); if (!tonumber(init, ra))
else if (!tonumber(pstep, ra+2)) luaG_runerror(L, LUA_QL("for") " initial value must be a number");
luaG_runerror(L, LUA_QL("for") " step must be a number"); else if (!tonumber(plimit, ra+1))
setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep))); luaG_runerror(L, LUA_QL("for") " limit must be a number");
dojump(L, pc, GETARG_sBx(i)); else if (!tonumber(pstep, ra+2))
continue; luaG_runerror(L, LUA_QL("for") " step must be a number");
} setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep)));
case OP_TFORLOOP: { dojump(L, pc, GETARG_sBx(i));
StkId cb = ra + 3; /* call base */ continue;
setobjs2s(L, cb+2, ra+2); }
setobjs2s(L, cb+1, ra+1); case OP_TFORLOOP: {
setobjs2s(L, cb, ra); StkId cb = ra + 3; /* call base */
L->top = cb+3; /* func. + 2 args (state and index) */ setobjs2s(L, cb+2, ra+2);
Protect(luaD_call(L, cb, GETARG_C(i))); setobjs2s(L, cb+1, ra+1);
L->top = L->ci->top; setobjs2s(L, cb, ra);
cb = RA(i) + 3; /* previous call may change the stack */ L->top = cb+3; /* func. + 2 args (state and index) */
if (!ttisnil(cb)) { /* continue loop? */ Protect(luaD_call(L, cb, GETARG_C(i)));
setobjs2s(L, cb-1, cb); /* save control variable */ L->top = L->ci->top;
dojump(L, pc, GETARG_sBx(*pc)); /* jump back */ cb = RA(i) + 3; /* previous call may change the stack */
} if (!ttisnil(cb)) { /* continue loop? */
pc++; setobjs2s(L, cb-1, cb); /* save control variable */
continue; dojump(L, pc, GETARG_sBx(*pc)); /* jump back */
} }
case OP_SETLIST: { pc++;
int n = GETARG_B(i); continue;
int c = GETARG_C(i); }
int last; case OP_SETLIST: {
Table *h; int n = GETARG_B(i);
if (n == 0) { int c = GETARG_C(i);
n = cast_int(L->top - ra) - 1; int last;
L->top = L->ci->top; Table *h;
} if (n == 0) {
if (c == 0) c = cast_int(*pc++); n = cast_int(L->top - ra) - 1;
runtime_check(L, ttistable(ra)); L->top = L->ci->top;
h = hvalue(ra); }
last = ((c-1)*LFIELDS_PER_FLUSH) + n; if (c == 0) c = cast_int(*pc++);
if (last > h->sizearray) /* needs more space? */ runtime_check(L, ttistable(ra));
luaH_resizearray(L, h, last); /* pre-alloc it at once */ h = hvalue(ra);
for (; n > 0; n--) { last = ((c-1)*LFIELDS_PER_FLUSH) + n;
TValue *val = ra+n; if (last > h->sizearray) /* needs more space? */
setobj2t(L, luaH_setnum(L, h, last--), val); luaH_resizearray(L, h, last); /* pre-alloc it at once */
luaC_barriert(L, h, val); for (; n > 0; n--) {
} TValue *val = ra+n;
continue; setobj2t(L, luaH_setnum(L, h, last--), val);
} luaC_barriert(L, h, val);
case OP_CLOSE: { }
luaF_close(L, ra); continue;
continue; }
} case OP_CLOSE: {
case OP_CLOSURE: { luaF_close(L, ra);
Proto *p; continue;
Closure *ncl; }
int nup, j; case OP_CLOSURE: {
p = cl->p->p[GETARG_Bx(i)]; Proto *p;
nup = p->nups; Closure *ncl;
ncl = luaF_newLclosure(L, nup, cl->env); int nup, j;
ncl->l.p = p; p = cl->p->p[GETARG_Bx(i)];
for (j=0; j<nup; j++, pc++) { nup = p->nups;
if (GET_OPCODE(*pc) == OP_GETUPVAL) ncl = luaF_newLclosure(L, nup, cl->env);
ncl->l.upvals[j] = cl->upvals[GETARG_B(*pc)]; ncl->l.p = p;
else { for (j=0; j<nup; j++, pc++) {
lua_assert(GET_OPCODE(*pc) == OP_MOVE); if (GET_OPCODE(*pc) == OP_GETUPVAL)
ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc)); ncl->l.upvals[j] = cl->upvals[GETARG_B(*pc)];
} else {
} lua_assert(GET_OPCODE(*pc) == OP_MOVE);
setclvalue(L, ra, ncl); ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc));
Protect(luaC_checkGC(L)); }
continue; }
} setclvalue(L, ra, ncl);
case OP_VARARG: { Protect(luaC_checkGC(L));
int b = GETARG_B(i) - 1; continue;
int j; }
CallInfo *ci = L->ci; case OP_VARARG: {
int n = cast_int(ci->base - ci->func) - cl->p->numparams - 1; int b = GETARG_B(i) - 1;
if (b == LUA_MULTRET) { int j;
Protect(luaD_checkstack(L, n)); CallInfo *ci = L->ci;
ra = RA(i); /* previous call may change the stack */ int n = cast_int(ci->base - ci->func) - cl->p->numparams - 1;
b = n; if (b == LUA_MULTRET) {
L->top = ra + n; Protect(luaD_checkstack(L, n));
} ra = RA(i); /* previous call may change the stack */
for (j = 0; j < b; j++) { b = n;
if (j < n) { L->top = ra + n;
setobjs2s(L, ra + j, ci->base - n + j); }
} for (j = 0; j < b; j++) {
else { if (j < n) {
setnilvalue(ra + j); setobjs2s(L, ra + j, ci->base - n + j);
} }
} else {
continue; setnilvalue(ra + j);
} }
} }
} continue;
} }
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment