First cut at updating compiler and runtime to handle lua 5.2 bytecodes. Able to compile and execute "hello, world" lua script.
This commit is contained in:
@@ -141,6 +141,7 @@ public class LoadState {
|
||||
private static final Prototype[] NOPROTOS = {};
|
||||
private static final LocVars[] NOLOCVARS = {};
|
||||
private static final LuaString[] NOSTRVALUES = {};
|
||||
private static final Upvaldesc[] NOUPVALDESCS = {};
|
||||
private static final int[] NOINTS = {};
|
||||
|
||||
/** Read buffer */
|
||||
@@ -282,12 +283,24 @@ public class LoadState {
|
||||
f.p = protos;
|
||||
}
|
||||
|
||||
|
||||
void loadUpvalues(Prototype f) throws IOException {
|
||||
int n = loadInt();
|
||||
f.upvalues = n>0? new Upvaldesc[n]: NOUPVALDESCS;
|
||||
for (int i=0; i<n; i++) {
|
||||
boolean instack = is.readByte() != 0;
|
||||
int idx = ((int) is.readByte()) & 0xff;
|
||||
f.upvalues[i] = new Upvaldesc(null, instack, idx);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the debug infor for a function prototype
|
||||
* Load the debug info for a function prototype
|
||||
* @param f the function Prototype
|
||||
* @throws IOException if there is an i/o exception
|
||||
*/
|
||||
void loadDebug( Prototype f ) throws IOException {
|
||||
f.source = loadString();
|
||||
f.lineinfo = loadIntArray();
|
||||
int n = loadInt();
|
||||
f.locvars = n>0? new LocVars[n]: NOLOCVARS;
|
||||
@@ -299,10 +312,9 @@ public class LoadState {
|
||||
}
|
||||
|
||||
n = loadInt();
|
||||
f.upvalues = n>0? new LuaString[n]: NOSTRVALUES;
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
f.upvalues[i] = loadString();
|
||||
}
|
||||
f.upvalues = n>0? new Upvaldesc[n]: NOUPVALDESCS;
|
||||
for ( int i=0; i<n; i++ )
|
||||
f.upvalues[i] = new Upvaldesc(loadString(), false, i);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -319,12 +331,12 @@ public class LoadState {
|
||||
f.source = p;
|
||||
f.linedefined = loadInt();
|
||||
f.lastlinedefined = loadInt();
|
||||
f.nups = is.readUnsignedByte();
|
||||
f.numparams = is.readUnsignedByte();
|
||||
f.is_vararg = is.readUnsignedByte();
|
||||
f.maxstacksize = is.readUnsignedByte();
|
||||
f.code = loadIntArray();
|
||||
loadConstants(f);
|
||||
loadUpvalues(f);
|
||||
loadDebug(f);
|
||||
|
||||
// TODO: add check here, for debugging purposes, I believe
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
package org.luaj.vm2;
|
||||
|
||||
/**
|
||||
* Data class to hold debug information relatign to local variables for a {@link Prototype}
|
||||
* Data class to hold debug information relating to local variables for a {@link Prototype}
|
||||
*/
|
||||
public class LocVars {
|
||||
/** The local variable name */
|
||||
|
||||
@@ -31,7 +31,7 @@ package org.luaj.vm2;
|
||||
public class Lua {
|
||||
/** version is supplied by ant build task */
|
||||
public static final String _VERSION = "Luaj 0.0";
|
||||
|
||||
|
||||
/** use return values from previous op */
|
||||
public static final int LUA_MULTRET = -1;
|
||||
|
||||
@@ -64,6 +64,7 @@ public class Lua {
|
||||
public static final int iABC = 0;
|
||||
public static final int iABx = 1;
|
||||
public static final int iAsBx = 2;
|
||||
public static final int iAx = 3;
|
||||
|
||||
|
||||
/*
|
||||
@@ -73,6 +74,7 @@ public class Lua {
|
||||
public static final int SIZE_B = 9;
|
||||
public static final int SIZE_Bx = (SIZE_C + SIZE_B);
|
||||
public static final int SIZE_A = 8;
|
||||
public static final int SIZE_Ax = (SIZE_C + SIZE_B + SIZE_A);
|
||||
|
||||
public static final int SIZE_OP = 6;
|
||||
|
||||
@@ -81,6 +83,7 @@ public class Lua {
|
||||
public static final int POS_C = (POS_A + SIZE_A);
|
||||
public static final int POS_B = (POS_C + SIZE_C);
|
||||
public static final int POS_Bx = POS_C;
|
||||
public static final int POS_Ax = POS_A;
|
||||
|
||||
|
||||
public static final int MAX_OP = ((1<<SIZE_OP)-1);
|
||||
@@ -89,6 +92,7 @@ public class Lua {
|
||||
public static final int MAXARG_C = ((1<<SIZE_C)-1);
|
||||
public static final int MAXARG_Bx = ((1<<SIZE_Bx)-1);
|
||||
public static final int MAXARG_sBx = (MAXARG_Bx>>1); /* `sBx' is signed */
|
||||
public static final int MAXARG_Ax = ((1<<SIZE_Ax)-1);
|
||||
|
||||
public static final int MASK_OP = ((1<<SIZE_OP)-1)<<POS_OP;
|
||||
public static final int MASK_A = ((1<<SIZE_A)-1)<<POS_A;
|
||||
@@ -113,6 +117,10 @@ public class Lua {
|
||||
return (i >> POS_A) & MAXARG_A;
|
||||
}
|
||||
|
||||
public static int GETARG_Ax(int i) {
|
||||
return (i >> POS_Ax) & MAXARG_Ax;
|
||||
}
|
||||
|
||||
public static int GETARG_B(int i) {
|
||||
return (i >> POS_B) & MAXARG_B;
|
||||
}
|
||||
@@ -177,59 +185,62 @@ public class Lua {
|
||||
------------------------------------------------------------------------*/
|
||||
public static final int OP_MOVE = 0;/* A B R(A) := R(B) */
|
||||
public static final int OP_LOADK = 1;/* A Bx R(A) := Kst(Bx) */
|
||||
public static final int OP_LOADBOOL = 2;/* A B C R(A) := (Bool)B; if (C) pc++ */
|
||||
public static final int OP_LOADNIL = 3; /* A B R(A) := ... := R(B) := nil */
|
||||
public static final int OP_GETUPVAL = 4; /* A B R(A) := UpValue[B] */
|
||||
public static final int OP_LOADKX = 2;/* A R(A) := Kst(extra arg) */
|
||||
public static final int OP_LOADBOOL = 3;/* A B C R(A) := (Bool)B; if (C) pc++ */
|
||||
public static final int OP_LOADNIL = 4; /* A B R(A) := ... := R(B) := nil */
|
||||
public static final int OP_GETUPVAL = 5; /* A B R(A) := UpValue[B] */
|
||||
|
||||
public static final int OP_GETGLOBAL = 5; /* A Bx R(A) := Gbl[Kst(Bx)] */
|
||||
public static final int OP_GETTABLE = 6; /* A B C R(A) := R(B)[RK(C)] */
|
||||
public static final int OP_GETTABUP = 6; /* A B C R(A) := UpValue[B][RK(C)] */
|
||||
public static final int OP_GETTABLE = 7; /* A B C R(A) := R(B)[RK(C)] */
|
||||
|
||||
public static final int OP_SETGLOBAL = 7; /* A Bx Gbl[Kst(Bx)] := R(A) */
|
||||
public static final int OP_SETUPVAL = 8; /* A B UpValue[B] := R(A) */
|
||||
public static final int OP_SETTABLE = 9; /* A B C R(A)[RK(B)] := RK(C) */
|
||||
public static final int OP_SETTABUP = 8; /* A B C UpValue[A][RK(B)] := RK(C) */
|
||||
public static final int OP_SETUPVAL = 9; /* A B UpValue[B] := R(A) */
|
||||
public static final int OP_SETTABLE = 10; /* A B C R(A)[RK(B)] := RK(C) */
|
||||
|
||||
public static final int OP_NEWTABLE = 10; /* A B C R(A) := {} (size = B,C) */
|
||||
public static final int OP_NEWTABLE = 11; /* A B C R(A) := {} (size = B,C) */
|
||||
|
||||
public static final int OP_SELF = 11; /* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */
|
||||
public static final int OP_SELF = 12; /* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */
|
||||
|
||||
public static final int OP_ADD = 12; /* A B C R(A) := RK(B) + RK(C) */
|
||||
public static final int OP_SUB = 13; /* A B C R(A) := RK(B) - RK(C) */
|
||||
public static final int OP_MUL = 14; /* A B C R(A) := RK(B) * RK(C) */
|
||||
public static final int OP_DIV = 15; /* A B C R(A) := RK(B) / RK(C) */
|
||||
public static final int OP_MOD = 16; /* A B C R(A) := RK(B) % RK(C) */
|
||||
public static final int OP_POW = 17; /* A B C R(A) := RK(B) ^ RK(C) */
|
||||
public static final int OP_UNM = 18; /* A B R(A) := -R(B) */
|
||||
public static final int OP_NOT = 19; /* A B R(A) := not R(B) */
|
||||
public static final int OP_LEN = 20; /* A B R(A) := length of R(B) */
|
||||
public static final int OP_ADD = 13; /* A B C R(A) := RK(B) + RK(C) */
|
||||
public static final int OP_SUB = 14; /* A B C R(A) := RK(B) - RK(C) */
|
||||
public static final int OP_MUL = 15; /* A B C R(A) := RK(B) * RK(C) */
|
||||
public static final int OP_DIV = 16; /* A B C R(A) := RK(B) / RK(C) */
|
||||
public static final int OP_MOD = 17; /* A B C R(A) := RK(B) % RK(C) */
|
||||
public static final int OP_POW = 18; /* A B C R(A) := RK(B) ^ RK(C) */
|
||||
public static final int OP_UNM = 19; /* A B R(A) := -R(B) */
|
||||
public static final int OP_NOT = 20; /* A B R(A) := not R(B) */
|
||||
public static final int OP_LEN = 21; /* A B R(A) := length of R(B) */
|
||||
|
||||
public static final int OP_CONCAT = 21; /* A B C R(A) := R(B).. ... ..R(C) */
|
||||
public static final int OP_CONCAT = 22; /* A B C R(A) := R(B).. ... ..R(C) */
|
||||
|
||||
public static final int OP_JMP = 22; /* sBx pc+=sBx */
|
||||
public static final int OP_JMP = 23; /* sBx pc+=sBx */
|
||||
public static final int OP_EQ = 24; /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
|
||||
public static final int OP_LT = 25; /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
|
||||
public static final int OP_LE = 26; /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
|
||||
|
||||
public static final int OP_EQ = 23; /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
|
||||
public static final int OP_LT = 24; /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
|
||||
public static final int OP_LE = 25; /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
|
||||
public static final int OP_TEST = 27; /* A C if not (R(A) <=> C) then pc++ */
|
||||
public static final int OP_TESTSET = 28; /* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */
|
||||
|
||||
public static final int OP_TEST = 26; /* A C if not (R(A) <=> C) then pc++ */
|
||||
public static final int OP_TESTSET = 27; /* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */
|
||||
public static final int OP_CALL = 29; /* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
|
||||
public static final int OP_TAILCALL = 30; /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
|
||||
public static final int OP_RETURN = 31; /* A B return R(A), ... ,R(A+B-2) (see note) */
|
||||
|
||||
public static final int OP_CALL = 28; /* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
|
||||
public static final int OP_TAILCALL = 29; /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
|
||||
public static final int OP_RETURN = 30; /* A B return R(A), ... ,R(A+B-2) (see note) */
|
||||
|
||||
public static final int OP_FORLOOP = 31; /* A sBx R(A)+=R(A+2);
|
||||
public static final int OP_FORLOOP = 32; /* A sBx R(A)+=R(A+2);
|
||||
if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/
|
||||
public static final int OP_FORPREP = 32; /* A sBx R(A)-=R(A+2); pc+=sBx */
|
||||
public static final int OP_FORPREP = 33; /* A sBx R(A)-=R(A+2); pc+=sBx */
|
||||
|
||||
public static final int OP_TFORLOOP = 33; /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));
|
||||
public static final int OP_TFORCALL = 34; /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */
|
||||
public static final int OP_TFORLOOP = 35; /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));
|
||||
if R(A+3) ~= nil then R(A+2)=R(A+3) else pc++ */
|
||||
public static final int OP_SETLIST = 34; /* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */
|
||||
public static final int OP_SETLIST = 36; /* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */
|
||||
|
||||
public static final int OP_CLOSE = 35; /* A close all variables in the stack up to (>=) R(A)*/
|
||||
public static final int OP_CLOSURE = 36; /* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */
|
||||
public static final int OP_VARARG = 37; /* A B R(A), R(A+1), ..., R(A+B-1) = vararg */
|
||||
|
||||
public static final int NUM_OPCODES = OP_VARARG + 1;
|
||||
public static final int OP_CLOSURE = 37; /* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */
|
||||
|
||||
public static final int OP_VARARG = 38; /* A B R(A), R(A+1), ..., R(A+B-1) = vararg */
|
||||
|
||||
public static final int OP_EXTRAARG = 39; /* Ax extra (larger) argument for previous opcode */
|
||||
|
||||
public static final int NUM_OPCODES = OP_EXTRAARG + 1;
|
||||
|
||||
/* pseudo-opcodes used in parsing only. */
|
||||
public static final int OP_GT = 63; // >
|
||||
@@ -277,12 +288,13 @@ public class Lua {
|
||||
/* T A B C mode opcode */
|
||||
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iABC), /* OP_MOVE */
|
||||
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgN<<2) | (iABx), /* OP_LOADK */
|
||||
(0<<7) | (1<<6) | (OpArgN<<4) | (OpArgN<<2) | (iABx), /* OP_LOADKX */
|
||||
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgU<<2) | (iABC), /* OP_LOADBOOL */
|
||||
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iABC), /* OP_LOADNIL */
|
||||
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABC), /* OP_LOADNIL */
|
||||
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABC), /* OP_GETUPVAL */
|
||||
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgN<<2) | (iABx), /* OP_GETGLOBAL */
|
||||
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgK<<2) | (iABC), /* OP_GETTABUP */
|
||||
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgK<<2) | (iABC), /* OP_GETTABLE */
|
||||
(0<<7) | (0<<6) | (OpArgK<<4) | (OpArgN<<2) | (iABx), /* OP_SETGLOBAL */
|
||||
(0<<7) | (0<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_SETTABUP */
|
||||
(0<<7) | (0<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABC), /* OP_SETUPVAL */
|
||||
(0<<7) | (0<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_SETTABLE */
|
||||
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgU<<2) | (iABC), /* OP_NEWTABLE */
|
||||
@@ -301,18 +313,19 @@ public class Lua {
|
||||
(1<<7) | (0<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_EQ */
|
||||
(1<<7) | (0<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_LT */
|
||||
(1<<7) | (0<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_LE */
|
||||
(1<<7) | (1<<6) | (OpArgR<<4) | (OpArgU<<2) | (iABC), /* OP_TEST */
|
||||
(1<<7) | (0<<6) | (OpArgN<<4) | (OpArgU<<2) | (iABC), /* OP_TEST */
|
||||
(1<<7) | (1<<6) | (OpArgR<<4) | (OpArgU<<2) | (iABC), /* OP_TESTSET */
|
||||
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgU<<2) | (iABC), /* OP_CALL */
|
||||
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgU<<2) | (iABC), /* OP_TAILCALL */
|
||||
(0<<7) | (0<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABC), /* OP_RETURN */
|
||||
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iAsBx), /* OP_FORLOOP */
|
||||
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iAsBx), /* OP_FORPREP */
|
||||
(1<<7) | (0<<6) | (OpArgN<<4) | (OpArgU<<2) | (iABC), /* OP_TFORLOOP */
|
||||
(0<<7) | (0<<6) | (OpArgN<<4) | (OpArgU<<2) | (iABC), /* OP_TFORCALL */
|
||||
(1<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iAsBx), /* OP_TFORLOOP */
|
||||
(0<<7) | (0<<6) | (OpArgU<<4) | (OpArgU<<2) | (iABC), /* OP_SETLIST */
|
||||
(0<<7) | (0<<6) | (OpArgN<<4) | (OpArgN<<2) | (iABC), /* OP_CLOSE */
|
||||
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABx), /* OP_CLOSURE */
|
||||
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABC), /* OP_VARARG */
|
||||
(0<<7) | (0<<6) | (OpArgU<<4) | (OpArgU<<2) | (iAx), /* OP_EXTRAARG */
|
||||
};
|
||||
|
||||
public static int getOpMode(int m) {
|
||||
|
||||
@@ -21,9 +21,6 @@
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.luaj.vm2.LoadState.LuaCompiler;
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
import org.luaj.vm2.lib.DebugLib;
|
||||
@@ -101,15 +98,17 @@ public class LuaClosure extends LuaFunction {
|
||||
}
|
||||
/** Supply the initial environment */
|
||||
public LuaClosure(Prototype p, LuaValue env) {
|
||||
super( env );
|
||||
this.p = p;
|
||||
this.upValues = p.nups>0? new UpValue[p.nups]: NOUPVALUES;
|
||||
this(p, p.upvalues.length, env);
|
||||
}
|
||||
|
||||
protected LuaClosure(int nupvalues, LuaValue env) {
|
||||
protected LuaClosure(Prototype p, int nupvalues, LuaValue env) {
|
||||
super( env );
|
||||
this.p = null;
|
||||
this.upValues = nupvalues>0? new UpValue[nupvalues]: NOUPVALUES;
|
||||
this.p = p;
|
||||
switch (nupvalues) {
|
||||
case 0: this.upValues = NOUPVALUES; break;
|
||||
case 1: this.upValues = new UpValue[] { new UpValue(new LuaValue[1], 0) }; this.upValues[0].setValue(env); break;
|
||||
default: this.upValues = new UpValue[nupvalues]; break;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isclosure() {
|
||||
@@ -233,16 +232,16 @@ public class LuaClosure extends LuaFunction {
|
||||
stack[a] = upValues[i>>>23].getValue();
|
||||
continue;
|
||||
|
||||
case Lua.OP_GETGLOBAL: /* A Bx R(A):= Gbl[Kst(Bx)] */
|
||||
stack[a] = env.get(k[i>>>14]);
|
||||
case Lua.OP_GETTABUP: /* A B C R(A) := UpValue[B][RK(C)] */
|
||||
stack[a] = upValues[i>>>23].getValue().get((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
|
||||
continue;
|
||||
|
||||
|
||||
case Lua.OP_GETTABLE: /* A B C R(A):= R(B)[RK(C)] */
|
||||
stack[a] = stack[i>>>23].get((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
|
||||
continue;
|
||||
|
||||
case Lua.OP_SETGLOBAL: /* A Bx Gbl[Kst(Bx)]:= R(A) */
|
||||
env.set(k[i>>>14], stack[a]);
|
||||
case Lua.OP_SETTABUP: /* A B C UpValue[A][RK(B)] := RK(C) */
|
||||
upValues[a].getValue().set(((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]), (c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
|
||||
continue;
|
||||
|
||||
case Lua.OP_SETUPVAL: /* A B UpValue[B]:= R(A) */
|
||||
@@ -422,7 +421,11 @@ public class LuaClosure extends LuaFunction {
|
||||
pc += (i>>>14)-0x1ffff;
|
||||
}
|
||||
continue;
|
||||
|
||||
|
||||
case Lua.OP_TFORCALL: /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */
|
||||
v = stack[a].invoke(varargsOf(stack[a+1],stack[a+2]));
|
||||
continue;
|
||||
|
||||
case Lua.OP_TFORLOOP: /*
|
||||
* A C R(A+3), ... ,R(A+2+C):= R(A)(R(A+1),
|
||||
* R(A+2)): if R(A+3) ~= nil then R(A+2)=R(A+3)
|
||||
@@ -462,21 +465,12 @@ public class LuaClosure extends LuaFunction {
|
||||
}
|
||||
continue;
|
||||
|
||||
case Lua.OP_CLOSE: /* A close all variables in the stack up to (>=) R(A)*/
|
||||
for ( b=openups.length; --b>=a; )
|
||||
if ( openups[b]!=null ) {
|
||||
openups[b].close();
|
||||
openups[b] = null;
|
||||
}
|
||||
continue;
|
||||
|
||||
case Lua.OP_CLOSURE: /* A Bx R(A):= closure(KPROTO[Bx], R(A), ... ,R(A+n)) */
|
||||
{
|
||||
Prototype newp = p.p[i>>>14];
|
||||
LuaClosure newcl = new LuaClosure(newp, env);
|
||||
for ( int j=0, nup=newp.nups; j<nup; ++j ) {
|
||||
for ( int j=0, nup=newp.upvalues.length; j<nup; ++j ) {
|
||||
i = code[pc++];
|
||||
//b = B(i);
|
||||
b = i>>>23;
|
||||
newcl.upValues[j] = (i&4) != 0?
|
||||
upValues[b]:
|
||||
@@ -496,6 +490,12 @@ public class LuaClosure extends LuaFunction {
|
||||
stack[a+j-1] = varargs.arg(j);
|
||||
}
|
||||
continue;
|
||||
|
||||
case Lua.OP_EXTRAARG:
|
||||
throw new java.lang.IllegalArgumentException("Uexecutable opcode: OP_EXTRAARG");
|
||||
|
||||
default:
|
||||
throw new java.lang.IllegalArgumentException("Illegal opcode: " + (i & 0x3f));
|
||||
}
|
||||
}
|
||||
} catch ( LuaError le ) {
|
||||
|
||||
@@ -187,7 +187,9 @@ public class LuaValue extends Varargs {
|
||||
|
||||
/** LuaValue array constant with no values */
|
||||
public static final LuaValue[] NOVALS = {};
|
||||
|
||||
|
||||
/** The variable name of the environment. */
|
||||
public static LuaString ENV = valueOf("_ENV");
|
||||
|
||||
/** LuaString constant with value "__index" for use as metatag */
|
||||
public static final LuaString INDEX = valueOf("__index");
|
||||
|
||||
@@ -136,6 +136,11 @@ public class Print extends Lua {
|
||||
printValue( ps, f.k[i] );
|
||||
}
|
||||
|
||||
static void printUpvalue(PrintStream ps, Upvaldesc u) {
|
||||
ps.print( u.idx + " " );
|
||||
printValue( ps, u.name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the code in a prototype
|
||||
* @param f the {@link Prototype}
|
||||
@@ -211,12 +216,12 @@ public class Print extends Lua {
|
||||
case OP_SETUPVAL:
|
||||
ps.print(" ; ");
|
||||
if ( f.upvalues.length > b )
|
||||
printValue(ps, f.upvalues[b]);
|
||||
printUpvalue(ps, f.upvalues[b]);
|
||||
else
|
||||
ps.print( "-" );
|
||||
break;
|
||||
case OP_GETGLOBAL:
|
||||
case OP_SETGLOBAL:
|
||||
case OP_GETTABUP:
|
||||
case OP_SETTABUP:
|
||||
ps.print(" ; ");
|
||||
printConstant( ps, f, bx );
|
||||
break;
|
||||
|
||||
@@ -42,10 +42,9 @@ public class Prototype {
|
||||
public int[] lineinfo;
|
||||
/* information about local variables */
|
||||
public LocVars[] locvars;
|
||||
/* upvalue names */
|
||||
public LuaString[] upvalues;
|
||||
/* upvalue information */
|
||||
public Upvaldesc[] upvalues;
|
||||
public LuaString source;
|
||||
public int nups;
|
||||
public int linedefined;
|
||||
public int lastlinedefined;
|
||||
public int numparams;
|
||||
|
||||
40
src/core/org/luaj/vm2/Upvaldesc.java
Normal file
40
src/core/org/luaj/vm2/Upvaldesc.java
Normal file
@@ -0,0 +1,40 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
public class Upvaldesc {
|
||||
|
||||
/* upvalue name (for debug information) */
|
||||
public final LuaString name;
|
||||
|
||||
/* whether it is in stack */
|
||||
public final boolean instack;
|
||||
|
||||
/* index of upvalue (in stack or in outer function's list) */
|
||||
public final short idx;
|
||||
|
||||
public Upvaldesc(LuaString name, boolean instack, int idx) {
|
||||
this.name = name;
|
||||
this.instack = instack;
|
||||
this.idx = (short) idx;
|
||||
}
|
||||
}
|
||||
@@ -177,14 +177,24 @@ public class DumpState {
|
||||
for (i = 0; i < n; i++)
|
||||
dumpFunction(f.p[i], f.source);
|
||||
}
|
||||
|
||||
|
||||
void dumpUpvalues(final Prototype f) throws IOException {
|
||||
int n = f.upvalues.length;
|
||||
dumpInt(n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
writer.writeByte(f.upvalues[i].instack ? 1 : 0);
|
||||
writer.writeByte(f.upvalues[i].idx);
|
||||
}
|
||||
}
|
||||
|
||||
void dumpDebug(final Prototype f) throws IOException {
|
||||
int i, n;
|
||||
n = (strip) ? 0 : f.lineinfo.length;
|
||||
dumpString(strip ? null: f.source);
|
||||
n = strip ? 0 : f.lineinfo.length;
|
||||
dumpInt(n);
|
||||
for (i = 0; i < n; i++)
|
||||
dumpInt(f.lineinfo[i]);
|
||||
n = (strip) ? 0 : f.locvars.length;
|
||||
n = strip ? 0 : f.locvars.length;
|
||||
dumpInt(n);
|
||||
for (i = 0; i < n; i++) {
|
||||
LocVars lvi = f.locvars[i];
|
||||
@@ -192,10 +202,10 @@ public class DumpState {
|
||||
dumpInt(lvi.startpc);
|
||||
dumpInt(lvi.endpc);
|
||||
}
|
||||
n = (strip) ? 0 : f.upvalues.length;
|
||||
n = strip ? 0 : f.upvalues.length;
|
||||
dumpInt(n);
|
||||
for (i = 0; i < n; i++)
|
||||
dumpString(f.upvalues[i]);
|
||||
dumpString(f.upvalues[i].name);
|
||||
}
|
||||
|
||||
void dumpFunction(final Prototype f, final LuaString string) throws IOException {
|
||||
@@ -205,12 +215,12 @@ public class DumpState {
|
||||
dumpString(f.source);
|
||||
dumpInt(f.linedefined);
|
||||
dumpInt(f.lastlinedefined);
|
||||
dumpChar(f.nups);
|
||||
dumpChar(f.numparams);
|
||||
dumpChar(f.is_vararg);
|
||||
dumpChar(f.maxstacksize);
|
||||
dumpCode(f);
|
||||
dumpConstants(f);
|
||||
dumpUpvalues(f);
|
||||
dumpDebug(f);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,15 +21,15 @@
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.compiler;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
import org.luaj.vm2.LuaBoolean;
|
||||
import org.luaj.vm2.LuaDouble;
|
||||
import org.luaj.vm2.LuaInteger;
|
||||
import org.luaj.vm2.LocVars;
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.LuaNil;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.Upvaldesc;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.compiler.LexState.ConsControl;
|
||||
@@ -37,22 +37,18 @@ import org.luaj.vm2.compiler.LexState.expdesc;
|
||||
|
||||
|
||||
public class FuncState extends LuaC {
|
||||
class upvaldesc {
|
||||
short k;
|
||||
short info;
|
||||
};
|
||||
|
||||
static class BlockCnt {
|
||||
BlockCnt previous; /* chain */
|
||||
IntPtr breaklist = new IntPtr(); /* list of jumps out of this loop */
|
||||
short nactvar; /* # active locals outside the breakable structure */
|
||||
boolean upval; /* true if some variable in the block is an upvalue */
|
||||
boolean isbreakable; /* true if `block' is a loop */
|
||||
};
|
||||
BlockCnt previous; /* chain */
|
||||
short firstlabel; /* index of first label in this block */
|
||||
short firstgoto; /* index of first pending goto in this block */
|
||||
short nactvar; /* # active locals outside the breakable structure */
|
||||
boolean upval; /* true if some variable in the block is an upvalue */
|
||||
boolean isloop; /* true if `block' is a loop */
|
||||
};
|
||||
|
||||
Prototype f; /* current function header */
|
||||
// LTable h; /* table to find (and reuse) elements in `k' */
|
||||
Hashtable htable; /* table to find (and reuse) elements in `k' */
|
||||
LuaTable h; /* table to find (and reuse) elements in `k' */
|
||||
FuncState prev; /* enclosing function */
|
||||
LexState ls; /* lexical state */
|
||||
LuaC L; /* compiler being invoked */
|
||||
@@ -60,14 +56,14 @@ public class FuncState extends LuaC {
|
||||
int pc; /* next position to code (equivalent to `ncode') */
|
||||
int lasttarget; /* `pc' of last `jump target' */
|
||||
IntPtr jpc; /* list of pending jumps to `pc' */
|
||||
int freereg; /* first free register */
|
||||
int nk; /* number of elements in `k' */
|
||||
int np; /* number of elements in `p' */
|
||||
int firstlocal; /* index of first local var (in Dyndata array) */
|
||||
short nlocvars; /* number of elements in `locvars' */
|
||||
short nactvar; /* number of active local variables */
|
||||
upvaldesc upvalues[] = new upvaldesc[LUAI_MAXUPVALUES]; /* upvalues */
|
||||
short actvar[] = new short[LUAI_MAXVARS]; /* declared-variable stack */
|
||||
|
||||
short nups; /* number of upvalues */
|
||||
short freereg; /* first free register */
|
||||
|
||||
FuncState() {
|
||||
}
|
||||
|
||||
@@ -77,11 +73,11 @@ public class FuncState extends LuaC {
|
||||
// =============================================================
|
||||
|
||||
InstructionPtr getcodePtr(expdesc e) {
|
||||
return new InstructionPtr( f.code, e.u.s.info );
|
||||
return new InstructionPtr( f.code, e.u.info );
|
||||
}
|
||||
|
||||
int getcode(expdesc e) {
|
||||
return f.code[e.u.s.info];
|
||||
return f.code[e.u.info];
|
||||
}
|
||||
|
||||
int codeAsBx(int o, int A, int sBx) {
|
||||
@@ -97,47 +93,66 @@ public class FuncState extends LuaC {
|
||||
// from lparser.c
|
||||
// =============================================================
|
||||
|
||||
LocVars getlocvar(int i) {
|
||||
return f.locvars[actvar[i]];
|
||||
/* check for repeated labels on the same block */
|
||||
void checkrepeated (LexState.Labeldesc[] ll, int ll_n, LuaString label) {
|
||||
int i;
|
||||
for (i = bl.firstlabel; i < ll_n; i++) {
|
||||
if (label.eq_b(ll[i].name)) {
|
||||
String msg = ls.L.pushfstring(
|
||||
"label '" + label + " already defined on line " + ll[i].line);
|
||||
ls.semerror(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void checklimit(int v, int l, String msg) {
|
||||
if ( v > l )
|
||||
errorlimit( l, msg );
|
||||
}
|
||||
|
||||
void errorlimit (int limit, String what) {
|
||||
// TODO: report message logic.
|
||||
String msg = (f.linedefined == 0) ?
|
||||
L.pushfstring("main function has more than "+limit+" "+what) :
|
||||
L.pushfstring("function at line "+f.linedefined+" has more than "+limit+" "+what);
|
||||
ls.lexerror(msg, 0);
|
||||
}
|
||||
|
||||
LocVars getlocvar(int i) {
|
||||
int idx = ls.dyd.actvar[firstlocal + i].idx;
|
||||
_assert(idx < nlocvars);
|
||||
return f.locvars[idx];
|
||||
}
|
||||
|
||||
int indexupvalue(LuaString name, expdesc v) {
|
||||
int i;
|
||||
for (i = 0; i < f.nups; i++) {
|
||||
if (upvalues[i].k == v.k && upvalues[i].info == v.u.s.info) {
|
||||
_assert(f.upvalues[i] == name);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
/* new one */
|
||||
checklimit(f.nups + 1, LUAI_MAXUPVALUES, "upvalues");
|
||||
if ( f.upvalues == null || f.nups + 1 > f.upvalues.length)
|
||||
f.upvalues = realloc( f.upvalues, f.nups*2+1 );
|
||||
f.upvalues[f.nups] = name;
|
||||
_assert (v.k == LexState.VLOCAL || v.k == LexState.VUPVAL);
|
||||
upvalues[f.nups] = new upvaldesc();
|
||||
upvalues[f.nups].k = (short) (v.k);
|
||||
upvalues[f.nups].info = (short) (v.u.s.info);
|
||||
return f.nups++;
|
||||
void removevars (int tolevel) {
|
||||
ls.dyd.n_actvar -= (nactvar - tolevel);
|
||||
while (nactvar > tolevel)
|
||||
getlocvar(--nactvar).endpc = pc;
|
||||
}
|
||||
|
||||
|
||||
int searchupvalue (LuaString name) {
|
||||
int i;
|
||||
Upvaldesc[] up = f.upvalues;
|
||||
for (i = 0; i < nups; i++)
|
||||
if (up[i].name.eq_b(name))
|
||||
return i;
|
||||
return -1; /* not found */
|
||||
}
|
||||
|
||||
int newupvalue (LuaString name, expdesc v) {
|
||||
checklimit(nups + 1, LUAI_MAXUPVAL, "upvalues");
|
||||
if (f.upvalues == null || nups + 1 > f.upvalues.length)
|
||||
f.upvalues = realloc( f.upvalues, nups > 0 ? nups*2 : 1 );
|
||||
f.upvalues[nups] = new Upvaldesc(name, v.k == LexState.VLOCAL, v.u.info);
|
||||
return nups++;
|
||||
}
|
||||
|
||||
int searchvar(LuaString n) {
|
||||
int i;
|
||||
for (i = nactvar - 1; i >= 0; i--) {
|
||||
if (n == getlocvar(i).varname)
|
||||
if (n.eq_b(getlocvar(i).varname))
|
||||
return i;
|
||||
}
|
||||
return -1; /* not found */
|
||||
@@ -145,68 +160,89 @@ public class FuncState extends LuaC {
|
||||
|
||||
void markupval(int level) {
|
||||
BlockCnt bl = this.bl;
|
||||
while (bl != null && bl.nactvar > level)
|
||||
while (bl.nactvar > level)
|
||||
bl = bl.previous;
|
||||
if (bl != null)
|
||||
bl.upval = true;
|
||||
bl.upval = true;
|
||||
}
|
||||
|
||||
int singlevaraux(LuaString n, expdesc var, int base) {
|
||||
int v = searchvar(n); /* look up at current level */
|
||||
static int singlevaraux(FuncState fs, LuaString n, expdesc var, int base) {
|
||||
if (fs == null) /* no more levels? */
|
||||
return LexState.VVOID; /* default is global */
|
||||
int v = fs.searchvar(n); /* look up at current level */
|
||||
if (v >= 0) {
|
||||
var.init(LexState.VLOCAL, v);
|
||||
if (base == 0)
|
||||
markupval(v); /* local will be used as an upval */
|
||||
fs.markupval(v); /* local will be used as an upval */
|
||||
return LexState.VLOCAL;
|
||||
} else { /* not found at current level; try upper one */
|
||||
if (prev == null) { /* no more levels? */
|
||||
/* default is global variable */
|
||||
var.init(LexState.VGLOBAL, NO_REG);
|
||||
return LexState.VGLOBAL;
|
||||
} else { /* not found at current level; try upvalues */
|
||||
int idx = fs.searchupvalue(n); /* try existing upvalues */
|
||||
if (idx < 0) { /* not found? */
|
||||
if (singlevaraux(fs.prev, n, var, 0) == LexState.VVOID) /* try upper levels */
|
||||
return LexState.VVOID; /* not found; is a global */
|
||||
/* else was LOCAL or UPVAL */
|
||||
idx = fs.newupvalue(n, var); /* will be a new upvalue */
|
||||
}
|
||||
var.init(LexState.VUPVAL, idx);
|
||||
return LexState.VUPVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** "export" pending gotos to outer level, to check them against
|
||||
** outer labels; if the block being exited has upvalues, and
|
||||
** the goto exits the scope of any variable (which can be the
|
||||
** upvalue), close those variables being exited.
|
||||
*/
|
||||
void movegotosout(BlockCnt bl) {
|
||||
int i = bl.firstgoto;
|
||||
final LexState.Labeldesc[] gl = ls.dyd.gt;
|
||||
final int n_gt = ls.dyd.n_gt;
|
||||
/* correct pending gotos to current block and try to close it
|
||||
with visible labels */
|
||||
while (i < n_gt) {
|
||||
LexState.Labeldesc gt = gl[i];
|
||||
if (gt.nactvar > bl.nactvar) {
|
||||
if (bl.upval)
|
||||
patchclose(gt.pc, bl.nactvar);
|
||||
gt.nactvar = bl.nactvar;
|
||||
}
|
||||
if (prev.singlevaraux(n, var, 0) == LexState.VGLOBAL)
|
||||
return LexState.VGLOBAL;
|
||||
var.u.s.info = indexupvalue(n, var); /* else was LOCAL or UPVAL */
|
||||
var.k = LexState.VUPVAL; /* upvalue in this level */
|
||||
return LexState.VUPVAL;
|
||||
if (!ls.findlabel(i))
|
||||
i++; /* move to next one */
|
||||
}
|
||||
}
|
||||
|
||||
void enterblock (BlockCnt bl, boolean isbreakable) {
|
||||
bl.breaklist.i = LexState.NO_JUMP;
|
||||
bl.isbreakable = isbreakable;
|
||||
bl.nactvar = this.nactvar;
|
||||
void enterblock (BlockCnt bl, boolean isloop) {
|
||||
bl.isloop = isloop;
|
||||
bl.nactvar = nactvar;
|
||||
if (ls.dyd == null)
|
||||
ls.dyd = new LexState.Dyndata();
|
||||
bl.firstlabel = (short) ls.dyd.n_label;
|
||||
bl.firstgoto = (short) ls.dyd.n_gt;
|
||||
bl.upval = false;
|
||||
bl.previous = this.bl;
|
||||
this.bl = bl;
|
||||
_assert(this.freereg == this.nactvar);
|
||||
}
|
||||
|
||||
//
|
||||
// void leaveblock (FuncState *fs) {
|
||||
// BlockCnt *bl = this.bl;
|
||||
// this.bl = bl.previous;
|
||||
// removevars(this.ls, bl.nactvar);
|
||||
// if (bl.upval)
|
||||
// this.codeABC(OP_CLOSE, bl.nactvar, 0, 0);
|
||||
// /* a block either controls scope or breaks (never both) */
|
||||
// assert(!bl.isbreakable || !bl.upval);
|
||||
// assert(bl.nactvar == this.nactvar);
|
||||
// this.freereg = this.nactvar; /* free registers */
|
||||
// this.patchtohere(bl.breaklist);
|
||||
// }
|
||||
|
||||
void leaveblock() {
|
||||
BlockCnt bl = this.bl;
|
||||
if (bl.previous != null && bl.upval) {
|
||||
/* create a 'jump to here' to close upvalues */
|
||||
int j = this.jump();
|
||||
this.patchclose(j, bl.nactvar);
|
||||
this.patchtohere(j);
|
||||
}
|
||||
if (bl.isloop)
|
||||
ls.breaklabel(); /* close pending breaks */
|
||||
this.bl = bl.previous;
|
||||
ls.removevars(bl.nactvar);
|
||||
if (bl.upval)
|
||||
this.codeABC(OP_CLOSE, bl.nactvar, 0, 0);
|
||||
/* a block either controls scope or breaks (never both) */
|
||||
_assert (!bl.isbreakable || !bl.upval);
|
||||
_assert (bl.nactvar == this.nactvar);
|
||||
this.freereg = this.nactvar; /* free registers */
|
||||
this.patchtohere(bl.breaklist.i);
|
||||
this.removevars(bl.nactvar);
|
||||
_assert(bl.nactvar == this.nactvar);
|
||||
this.freereg = this.nactvar; /* free registers */
|
||||
ls.dyd.n_label = bl.firstlabel; /* remove local labels */
|
||||
if (bl.previous != null) /* inner block? */
|
||||
this.movegotosout(bl); /* update pending gotos to outer block */
|
||||
else if (bl.firstgoto < ls.dyd.n_gt) /* pending gotos in outer block? */
|
||||
ls.undefgoto(ls.dyd.gt[bl.firstgoto]); /* error */
|
||||
}
|
||||
|
||||
void closelistfield(ConsControl cc) {
|
||||
@@ -215,7 +251,7 @@ public class FuncState extends LuaC {
|
||||
this.exp2nextreg(cc.v);
|
||||
cc.v.k = LexState.VVOID;
|
||||
if (cc.tostore == LFIELDS_PER_FLUSH) {
|
||||
this.setlist(cc.t.u.s.info, cc.na, cc.tostore); /* flush */
|
||||
this.setlist(cc.t.u.info, cc.na, cc.tostore); /* flush */
|
||||
cc.tostore = 0; /* no more items pending */
|
||||
}
|
||||
}
|
||||
@@ -228,13 +264,13 @@ public class FuncState extends LuaC {
|
||||
if (cc.tostore == 0) return;
|
||||
if (hasmultret(cc.v.k)) {
|
||||
this.setmultret(cc.v);
|
||||
this.setlist(cc.t.u.s.info, cc.na, LUA_MULTRET);
|
||||
this.setlist(cc.t.u.info, cc.na, LUA_MULTRET);
|
||||
cc.na--; /** do not count last expression (unknown number of elements) */
|
||||
}
|
||||
else {
|
||||
if (cc.v.k != LexState.VVOID)
|
||||
this.exp2nextreg(cc.v);
|
||||
this.setlist(cc.t.u.s.info, cc.na, cc.tostore);
|
||||
this.setlist(cc.t.u.info, cc.na, cc.tostore);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,6 +421,17 @@ public class FuncState extends LuaC {
|
||||
}
|
||||
}
|
||||
|
||||
void patchclose(int list, int level) {
|
||||
level++; /* argument is +1 to reserve 0 as non-op */
|
||||
while (list != LexState.NO_JUMP) {
|
||||
int next = getjump(list);
|
||||
_assert(GET_OPCODE(f.code[list]) == OP_JMP
|
||||
&& (GETARG_A(f.code[list]) == 0 || GETARG_A(f.code[list]) >= level));
|
||||
SETARG_A(f.code, list, level);
|
||||
list = next;
|
||||
}
|
||||
}
|
||||
|
||||
void patchtohere(int list) {
|
||||
this.getlabel();
|
||||
this.concat(this.jpc, list);
|
||||
@@ -428,21 +475,23 @@ public class FuncState extends LuaC {
|
||||
|
||||
void freeexp(expdesc e) {
|
||||
if (e.k == LexState.VNONRELOC)
|
||||
this.freereg(e.u.s.info);
|
||||
this.freereg(e.u.info);
|
||||
}
|
||||
|
||||
int addk(LuaValue v) {
|
||||
int idx;
|
||||
if (this.htable.containsKey(v)) {
|
||||
idx = ((Integer) htable.get(v)).intValue();
|
||||
if (this.h == null) {
|
||||
this.h = new LuaTable();
|
||||
} else {
|
||||
idx = this.nk;
|
||||
this.htable.put(v, new Integer(idx));
|
||||
final Prototype f = this.f;
|
||||
if (f.k == null || nk + 1 >= f.k.length)
|
||||
f.k = realloc( f.k, nk*2 + 1 );
|
||||
f.k[this.nk++] = v;
|
||||
LuaValue idx = this.h.get(v);
|
||||
if (idx.isnumber())
|
||||
return idx.toint();
|
||||
}
|
||||
int idx = this.nk;
|
||||
this.h.set(v, LuaValue.valueOf(idx));
|
||||
final Prototype f = this.f;
|
||||
if (f.k == null || nk + 1 >= f.k.length)
|
||||
f.k = realloc( f.k, nk*2 + 1 );
|
||||
f.k[this.nk++] = v;
|
||||
return idx;
|
||||
}
|
||||
|
||||
@@ -481,7 +530,7 @@ public class FuncState extends LuaC {
|
||||
void setoneret(expdesc e) {
|
||||
if (e.k == LexState.VCALL) { /* expression is an open function call? */
|
||||
e.k = LexState.VNONRELOC;
|
||||
e.u.s.info = GETARG_A(this.getcode(e));
|
||||
e.u.info = GETARG_A(this.getcode(e));
|
||||
} else if (e.k == LexState.VVARARG) {
|
||||
SETARG_B(this.getcodePtr(e), 2);
|
||||
e.k = LexState.VRELOCABLE; /* can relocate its simple result */
|
||||
@@ -495,20 +544,18 @@ public class FuncState extends LuaC {
|
||||
break;
|
||||
}
|
||||
case LexState.VUPVAL: {
|
||||
e.u.s.info = this.codeABC(OP_GETUPVAL, 0, e.u.s.info, 0);
|
||||
e.k = LexState.VRELOCABLE;
|
||||
break;
|
||||
}
|
||||
case LexState.VGLOBAL: {
|
||||
e.u.s.info = this.codeABx(OP_GETGLOBAL, 0, e.u.s.info);
|
||||
e.u.info = this.codeABC(OP_GETUPVAL, 0, e.u.info, 0);
|
||||
e.k = LexState.VRELOCABLE;
|
||||
break;
|
||||
}
|
||||
case LexState.VINDEXED: {
|
||||
this.freereg(e.u.s.aux);
|
||||
this.freereg(e.u.s.info);
|
||||
e.u.s.info = this
|
||||
.codeABC(OP_GETTABLE, 0, e.u.s.info, e.u.s.aux);
|
||||
int op = OP_GETTABUP; /* assume 't' is in an upvalue */
|
||||
this.freereg(e.u.ind_idx);
|
||||
if (e.u.ind_vt == LexState.VLOCAL) { /* 't' is in a register? */
|
||||
this.freereg(e.u.ind_t);
|
||||
op = OP_GETTABLE;
|
||||
}
|
||||
e.u.info = this.codeABC(op, 0, e.u.ind_t, e.u.ind_idx);
|
||||
e.k = LexState.VRELOCABLE;
|
||||
break;
|
||||
}
|
||||
@@ -541,7 +588,7 @@ public class FuncState extends LuaC {
|
||||
break;
|
||||
}
|
||||
case LexState.VK: {
|
||||
this.codeABx(OP_LOADK, reg, e.u.s.info);
|
||||
this.codeABx(OP_LOADK, reg, e.u.info);
|
||||
break;
|
||||
}
|
||||
case LexState.VKNUM: {
|
||||
@@ -554,8 +601,8 @@ public class FuncState extends LuaC {
|
||||
break;
|
||||
}
|
||||
case LexState.VNONRELOC: {
|
||||
if (reg != e.u.s.info)
|
||||
this.codeABC(OP_MOVE, reg, e.u.s.info, 0);
|
||||
if (reg != e.u.info)
|
||||
this.codeABC(OP_MOVE, reg, e.u.info, 0);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -563,7 +610,7 @@ public class FuncState extends LuaC {
|
||||
return; /* nothing to do... */
|
||||
}
|
||||
}
|
||||
e.u.s.info = reg;
|
||||
e.u.info = reg;
|
||||
e.k = LexState.VNONRELOC;
|
||||
}
|
||||
|
||||
@@ -577,7 +624,7 @@ public class FuncState extends LuaC {
|
||||
void exp2reg(expdesc e, int reg) {
|
||||
this.discharge2reg(e, reg);
|
||||
if (e.k == LexState.VJMP)
|
||||
this.concat(e.t, e.u.s.info); /* put this jump in `t' list */
|
||||
this.concat(e.t, e.u.info); /* put this jump in `t' list */
|
||||
if (e.hasjumps()) {
|
||||
int _final; /* position after whole expression */
|
||||
int p_f = LexState.NO_JUMP; /* position of an eventual LOAD false */
|
||||
@@ -594,7 +641,7 @@ public class FuncState extends LuaC {
|
||||
this.patchlistaux(e.t.i, _final, reg, p_t);
|
||||
}
|
||||
e.f.i = e.t.i = LexState.NO_JUMP;
|
||||
e.u.s.info = reg;
|
||||
e.u.info = reg;
|
||||
e.k = LexState.VNONRELOC;
|
||||
}
|
||||
|
||||
@@ -609,14 +656,14 @@ public class FuncState extends LuaC {
|
||||
this.dischargevars(e);
|
||||
if (e.k == LexState.VNONRELOC) {
|
||||
if (!e.hasjumps())
|
||||
return e.u.s.info; /* exp is already in a register */
|
||||
if (e.u.s.info >= this.nactvar) { /* reg. is not a local? */
|
||||
this.exp2reg(e, e.u.s.info); /* put value on it */
|
||||
return e.u.s.info;
|
||||
return e.u.info; /* exp is already in a register */
|
||||
if (e.u.info >= this.nactvar) { /* reg. is not a local? */
|
||||
this.exp2reg(e, e.u.info); /* put value on it */
|
||||
return e.u.info;
|
||||
}
|
||||
}
|
||||
this.exp2nextreg(e); /* default */
|
||||
return e.u.s.info;
|
||||
return e.u.info;
|
||||
}
|
||||
|
||||
void exp2val(expdesc e) {
|
||||
@@ -634,17 +681,17 @@ public class FuncState extends LuaC {
|
||||
case LexState.VFALSE:
|
||||
case LexState.VNIL: {
|
||||
if (this.nk <= MAXINDEXRK) { /* constant fit in RK operand? */
|
||||
e.u.s.info = (e.k == LexState.VNIL) ? this.nilK()
|
||||
e.u.info = (e.k == LexState.VNIL) ? this.nilK()
|
||||
: (e.k == LexState.VKNUM) ? this.numberK(e.u.nval())
|
||||
: this.boolK((e.k == LexState.VTRUE));
|
||||
e.k = LexState.VK;
|
||||
return RKASK(e.u.s.info);
|
||||
return RKASK(e.u.info);
|
||||
} else
|
||||
break;
|
||||
}
|
||||
case LexState.VK: {
|
||||
if (e.u.s.info <= MAXINDEXRK) /* constant fit in argC? */
|
||||
return RKASK(e.u.s.info);
|
||||
if (e.u.info <= MAXINDEXRK) /* constant fit in argC? */
|
||||
return RKASK(e.u.info);
|
||||
else
|
||||
break;
|
||||
}
|
||||
@@ -659,22 +706,18 @@ public class FuncState extends LuaC {
|
||||
switch (var.k) {
|
||||
case LexState.VLOCAL: {
|
||||
this.freeexp(ex);
|
||||
this.exp2reg(ex, var.u.s.info);
|
||||
this.exp2reg(ex, var.u.info);
|
||||
return;
|
||||
}
|
||||
case LexState.VUPVAL: {
|
||||
int e = this.exp2anyreg(ex);
|
||||
this.codeABC(OP_SETUPVAL, e, var.u.s.info, 0);
|
||||
break;
|
||||
}
|
||||
case LexState.VGLOBAL: {
|
||||
int e = this.exp2anyreg(ex);
|
||||
this.codeABx(OP_SETGLOBAL, e, var.u.s.info);
|
||||
this.codeABC(OP_SETUPVAL, e, var.u.info, 0);
|
||||
break;
|
||||
}
|
||||
case LexState.VINDEXED: {
|
||||
int op = (var.u.ind_vt == LexState.VLOCAL) ? OP_SETTABLE : OP_SETTABUP;
|
||||
int e = this.exp2RK(ex);
|
||||
this.codeABC(OP_SETTABLE, var.u.s.info, var.u.s.aux, e);
|
||||
this.codeABC(op, var.u.ind_t, var.u.ind_idx, e);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -691,14 +734,14 @@ public class FuncState extends LuaC {
|
||||
this.freeexp(e);
|
||||
func = this.freereg;
|
||||
this.reserveregs(2);
|
||||
this.codeABC(OP_SELF, func, e.u.s.info, this.exp2RK(key));
|
||||
this.codeABC(OP_SELF, func, e.u.info, this.exp2RK(key));
|
||||
this.freeexp(key);
|
||||
e.u.s.info = func;
|
||||
e.u.info = func;
|
||||
e.k = LexState.VNONRELOC;
|
||||
}
|
||||
|
||||
void invertjump(expdesc e) {
|
||||
InstructionPtr pc = this.getjumpcontrol(e.u.s.info);
|
||||
InstructionPtr pc = this.getjumpcontrol(e.u.info);
|
||||
_assert (testTMode(GET_OPCODE(pc.get()))
|
||||
&& GET_OPCODE(pc.get()) != OP_TESTSET && Lua
|
||||
.GET_OPCODE(pc.get()) != OP_TEST);
|
||||
@@ -719,7 +762,7 @@ public class FuncState extends LuaC {
|
||||
}
|
||||
this.discharge2anyreg(e);
|
||||
this.freeexp(e);
|
||||
return this.condjump(OP_TESTSET, NO_REG, e.u.s.info, cond);
|
||||
return this.condjump(OP_TESTSET, NO_REG, e.u.info, cond);
|
||||
}
|
||||
|
||||
void goiftrue(expdesc e) {
|
||||
@@ -738,7 +781,7 @@ public class FuncState extends LuaC {
|
||||
}
|
||||
case LexState.VJMP: {
|
||||
this.invertjump(e);
|
||||
pc = e.u.s.info;
|
||||
pc = e.u.info;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -765,7 +808,7 @@ public class FuncState extends LuaC {
|
||||
break;
|
||||
}
|
||||
case LexState.VJMP: {
|
||||
pc = e.u.s.info;
|
||||
pc = e.u.info;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -800,7 +843,7 @@ public class FuncState extends LuaC {
|
||||
case LexState.VNONRELOC: {
|
||||
this.discharge2anyreg(e);
|
||||
this.freeexp(e);
|
||||
e.u.s.info = this.codeABC(OP_NOT, 0, e.u.s.info, 0);
|
||||
e.u.info = this.codeABC(OP_NOT, 0, e.u.info, 0);
|
||||
e.k = LexState.VRELOCABLE;
|
||||
break;
|
||||
}
|
||||
@@ -820,7 +863,9 @@ public class FuncState extends LuaC {
|
||||
}
|
||||
|
||||
void indexed(expdesc t, expdesc k) {
|
||||
t.u.s.aux = this.exp2RK(k);
|
||||
t.u.ind_t = (short) t.u.info;
|
||||
t.u.ind_idx = (short) this.exp2RK(k);
|
||||
t.u.ind_vt = (short) ((t.k == LexState.VUPVAL) ? LexState.VUPVAL : LexState.VLOCAL);
|
||||
t.k = LexState.VINDEXED;
|
||||
}
|
||||
|
||||
@@ -881,7 +926,7 @@ public class FuncState extends LuaC {
|
||||
this.freeexp(e2);
|
||||
this.freeexp(e1);
|
||||
}
|
||||
e1.u.s.info = this.codeABC(op, 0, o1, o2);
|
||||
e1.u.info = this.codeABC(op, 0, o1, o2);
|
||||
e1.k = LexState.VRELOCABLE;
|
||||
}
|
||||
}
|
||||
@@ -898,7 +943,7 @@ public class FuncState extends LuaC {
|
||||
o2 = temp; /* o1 <==> o2 */
|
||||
cond = 1;
|
||||
}
|
||||
e1.u.s.info = this.condjump(op, cond, o1, o2);
|
||||
e1.u.info = this.condjump(op, cond, o1, o2);
|
||||
e1.k = LexState.VJMP;
|
||||
}
|
||||
|
||||
@@ -979,11 +1024,11 @@ public class FuncState extends LuaC {
|
||||
this.exp2val(e2);
|
||||
if (e2.k == LexState.VRELOCABLE
|
||||
&& GET_OPCODE(this.getcode(e2)) == OP_CONCAT) {
|
||||
_assert (e1.u.s.info == GETARG_B(this.getcode(e2)) - 1);
|
||||
_assert (e1.u.info == GETARG_B(this.getcode(e2)) - 1);
|
||||
this.freeexp(e1);
|
||||
SETARG_B(this.getcodePtr(e2), e1.u.s.info);
|
||||
SETARG_B(this.getcodePtr(e2), e1.u.info);
|
||||
e1.k = LexState.VRELOCABLE;
|
||||
e1.u.s.info = e2.u.s.info;
|
||||
e1.u.info = e2.u.info;
|
||||
} else {
|
||||
this.exp2nextreg(e2); /* operand must be on the 'stack' */
|
||||
this.codearith(OP_CONCAT, e1, e2);
|
||||
@@ -1078,7 +1123,7 @@ public class FuncState extends LuaC {
|
||||
this.codeABC(OP_SETLIST, base, b, 0);
|
||||
this.code(c, this.ls.lastline);
|
||||
}
|
||||
this.freereg = base + 1; /* free registers with list values */
|
||||
this.freereg = (short) (base + 1); /* free registers with list values */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -105,13 +105,12 @@ public class LexState {
|
||||
VKNUM = 5, /* nval = numerical value */
|
||||
VLOCAL = 6, /* info = local register */
|
||||
VUPVAL = 7, /* info = index of upvalue in `upvalues' */
|
||||
VGLOBAL = 8, /* info = index of table, aux = index of global name in `k' */
|
||||
VINDEXED = 9, /* info = table register, aux = index register (or `k') */
|
||||
VJMP = 10, /* info = instruction pc */
|
||||
VRELOCABLE = 11, /* info = instruction pc */
|
||||
VNONRELOC = 12, /* info = result register */
|
||||
VCALL = 13, /* info = instruction pc */
|
||||
VVARARG = 14; /* info = instruction pc */
|
||||
VINDEXED = 8, /* info = table register, aux = index register (or `k') */
|
||||
VJMP = 9, /* info = instruction pc */
|
||||
VRELOCABLE = 10, /* info = instruction pc */
|
||||
VNONRELOC = 11, /* info = result register */
|
||||
VCALL = 12, /* info = instruction pc */
|
||||
VVARARG = 13; /* info = instruction pc */
|
||||
|
||||
/* semantics information */
|
||||
private static class SemInfo {
|
||||
@@ -139,7 +138,9 @@ public class LexState {
|
||||
InputStream z; /* input stream */
|
||||
byte[] buff; /* buffer for tokens */
|
||||
int nbuff; /* length of buffer */
|
||||
Dyndata dyd; /* dynamic structures used by the parser */
|
||||
LuaString source; /* current source name */
|
||||
LuaString envn; /* environment variable name */
|
||||
byte decpoint; /* locale decimal point */
|
||||
|
||||
/* ORDER RESERVED */
|
||||
@@ -155,13 +156,13 @@ public class LexState {
|
||||
final static int
|
||||
/* terminal symbols denoted by reserved words */
|
||||
TK_AND=257, TK_BREAK=258, TK_DO=259, TK_ELSE=260, TK_ELSEIF=261,
|
||||
TK_END=262, TK_FALSE=263, TK_FOR=264, TK_FUNCTION=265, TK_IF=266,
|
||||
TK_IN=267, TK_LOCAL=268, TK_NIL=269, TK_NOT=270, TK_OR=271, TK_REPEAT=272,
|
||||
TK_RETURN=273, TK_THEN=274, TK_TRUE=275, TK_UNTIL=276, TK_WHILE=277,
|
||||
TK_END=262, TK_FALSE=263, TK_FOR=264, TK_FUNCTION=265, TK_GOTO=266, TK_IF=267,
|
||||
TK_IN=268, TK_LOCAL=269, TK_NIL=270, TK_NOT=271, TK_OR=272, TK_REPEAT=273,
|
||||
TK_RETURN=274, TK_THEN=275, TK_TRUE=276, TK_UNTIL=277, TK_WHILE=278,
|
||||
/* other terminal symbols */
|
||||
TK_CONCAT=278, TK_DOTS=279, TK_EQ=280, TK_GE=281, TK_LE=282, TK_NE=283,
|
||||
TK_NUMBER=284, TK_NAME=285, TK_STRING=286, TK_EOS=287;
|
||||
|
||||
TK_CONCAT=279, TK_DOTS=280, TK_EQ=281, TK_GE=282, TK_LE=283, TK_NE=284,
|
||||
TK_DBCOLON=285, TK_EOS=286, TK_NUMBER=287, TK_NAME=288, TK_STRING=289;
|
||||
|
||||
final static int FIRST_RESERVED = TK_AND;
|
||||
final static int NUM_RESERVED = TK_WHILE+1-FIRST_RESERVED;
|
||||
|
||||
@@ -308,6 +309,7 @@ public class LexState {
|
||||
this.linenumber = 1;
|
||||
this.lastline = 1;
|
||||
this.source = source;
|
||||
this.envn = LuaValue.ENV; /* environment variable name */
|
||||
this.nbuff = 0; /* initialize buffer */
|
||||
this.current = firstByte; /* read first char */
|
||||
this.skipShebang();
|
||||
@@ -690,19 +692,27 @@ public class LexState {
|
||||
// from lparser.c
|
||||
// =============================================================
|
||||
|
||||
static final boolean vkisvar(final int k) {
|
||||
return (VLOCAL <= (k) && (k) <= VINDEXED);
|
||||
}
|
||||
|
||||
static final boolean vkisinreg(final int k) {
|
||||
return ((k) == VNONRELOC || (k) == VLOCAL);
|
||||
}
|
||||
|
||||
static class expdesc {
|
||||
int k; // expkind, from enumerated list, above
|
||||
static class U { // originally a union
|
||||
static class S {
|
||||
int info, aux;
|
||||
}
|
||||
final S s = new S();
|
||||
short ind_idx; // index (R/K)
|
||||
short ind_t; // table(register or upvalue)
|
||||
short ind_vt; // whether 't' is register (VLOCAL) or (UPVALUE)
|
||||
private LuaValue _nval;
|
||||
int info;
|
||||
public void setNval(LuaValue r) {
|
||||
_nval = r;
|
||||
}
|
||||
public LuaValue nval() {
|
||||
return (_nval == null? LuaInteger.valueOf(s.info): _nval);
|
||||
return (_nval == null? LuaInteger.valueOf(info): _nval);
|
||||
}
|
||||
};
|
||||
final U u = new U();
|
||||
@@ -712,7 +722,7 @@ public class LexState {
|
||||
this.f.i = NO_JUMP;
|
||||
this.t.i = NO_JUMP;
|
||||
this.k = k;
|
||||
this.u.s.info = i;
|
||||
this.u.info = i;
|
||||
}
|
||||
|
||||
boolean hasjumps() {
|
||||
@@ -725,14 +735,51 @@ public class LexState {
|
||||
|
||||
public void setvalue(expdesc other) {
|
||||
this.k = other.k;
|
||||
this.u._nval = other.u._nval;
|
||||
this.u.s.info = other.u.s.info;
|
||||
this.u.s.aux = other.u.s.aux;
|
||||
this.u.info = other.u.info;
|
||||
this.u.ind_idx = other.u.ind_idx;
|
||||
this.u.ind_t = other.u.ind_t;
|
||||
this.u.ind_vt = other.u.ind_vt;
|
||||
this.t.i = other.t.i;
|
||||
this.f.i = other.f.i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* description of active local variable */
|
||||
static class Vardesc {
|
||||
final short idx; /* variable index in stack */
|
||||
Vardesc(int idx) {
|
||||
this.idx = (short) idx;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* description of pending goto statements and label statements */
|
||||
static class Labeldesc {
|
||||
LuaString name; /* label identifier */
|
||||
int pc; /* position in code */
|
||||
int line; /* line where it appeared */
|
||||
short nactvar; /* local level where it appears in current block */
|
||||
public Labeldesc(LuaString name, int pc, int line, short nactvar) {
|
||||
this.name = name;
|
||||
this.pc = pc;
|
||||
this.line = line;
|
||||
this.nactvar = nactvar;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* dynamic structures used by the parser */
|
||||
static class Dyndata {
|
||||
Vardesc[] actvar; /* list of active local variables */
|
||||
int n_actvar = 0;
|
||||
Labeldesc[] gt; /* list of pending gotos */
|
||||
int n_gt = 0;
|
||||
Labeldesc[] label; /* list of active labels */
|
||||
int n_label = 0;
|
||||
};
|
||||
|
||||
|
||||
boolean hasmultret(int k) {
|
||||
return ((k) == VCALL || (k) == VVARARG);
|
||||
}
|
||||
@@ -741,9 +788,21 @@ public class LexState {
|
||||
name args description
|
||||
------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* * prototypes for recursive non-terminal functions
|
||||
*/
|
||||
void anchor_token () {
|
||||
/* last token from outer function must be EOS */
|
||||
LuaC._assert(fs != null || t.token == TK_EOS);
|
||||
if (t.token == TK_NAME || t.token == TK_STRING) {
|
||||
LuaString ts = t.seminfo.ts;
|
||||
// TODO: is this necessary?
|
||||
newstring(ts.m_bytes, 0, ts.m_length);
|
||||
}
|
||||
}
|
||||
|
||||
/* semantic error */
|
||||
void semerror (String msg) {
|
||||
t.token = 0; /* remove 'near to' from final message */
|
||||
syntaxerror(msg);
|
||||
}
|
||||
|
||||
void error_expected(int token) {
|
||||
syntaxerror(L.pushfstring(LUA_QS(token2str(token)) + " expected"));
|
||||
@@ -822,9 +881,11 @@ public class LexState {
|
||||
}
|
||||
|
||||
void new_localvar(LuaString name, int n) {
|
||||
FuncState fs = this.fs;
|
||||
int reg = registerlocalvar(name);
|
||||
fs.checklimit(fs.nactvar + n + 1, FuncState.LUAI_MAXVARS, "local variables");
|
||||
fs.actvar[fs.nactvar + n] = (short) registerlocalvar(name);
|
||||
if (dyd.actvar == null || dyd.n_actvar + 1 > dyd.actvar.length)
|
||||
dyd.actvar = LuaC.realloc(dyd.actvar, Math.max(1, dyd.n_actvar * 2));
|
||||
dyd.actvar[dyd.n_actvar] = new Vardesc(reg);
|
||||
}
|
||||
|
||||
void adjustlocalvars(int nvars) {
|
||||
@@ -844,8 +905,13 @@ public class LexState {
|
||||
void singlevar(expdesc var) {
|
||||
LuaString varname = this.str_checkname();
|
||||
FuncState fs = this.fs;
|
||||
if (fs.singlevaraux(varname, var, 1) == VGLOBAL)
|
||||
var.u.s.info = fs.stringK(varname); /* info points to global name */
|
||||
if (FuncState.singlevaraux(fs, varname, var, 1) == VVOID) { /* global name? */
|
||||
expdesc key = new expdesc();
|
||||
FuncState.singlevaraux(fs, this.envn, var, 1); /* get environment variable */
|
||||
LuaC._assert(var.k == VLOCAL || var.k == VUPVAL);
|
||||
this.codestring(key, varname); /* key is variable name */
|
||||
fs.indexed(var, key); /* env[varname] */
|
||||
}
|
||||
}
|
||||
|
||||
void adjust_assign(int nvars, int nexps, expdesc e) {
|
||||
@@ -880,22 +946,91 @@ public class LexState {
|
||||
void leavelevel() {
|
||||
L.nCcalls--;
|
||||
}
|
||||
|
||||
void pushclosure(FuncState func, expdesc v) {
|
||||
|
||||
void closegoto(int g, Labeldesc label) {
|
||||
int i;
|
||||
FuncState fs = this.fs;
|
||||
Prototype f = fs.f;
|
||||
if (f.p == null || fs.np + 1 > f.p.length)
|
||||
f.p = LuaC.realloc( f.p, fs.np*2 + 1 );
|
||||
f.p[fs.np++] = func.f;
|
||||
v.init(VRELOCABLE, fs.codeABx(Lua.OP_CLOSURE, 0, fs.np - 1));
|
||||
for (int i = 0; i < func.f.nups; i++) {
|
||||
int o = (func.upvalues[i].k == VLOCAL) ? Lua.OP_MOVE
|
||||
: Lua.OP_GETUPVAL;
|
||||
fs.codeABC(o, 0, func.upvalues[i].info, 0);
|
||||
Labeldesc[] gl = this.dyd.gt;
|
||||
Labeldesc gt = gl[g];
|
||||
LuaC._assert(gt.name.eq_b(label.name));
|
||||
if (gt.nactvar < label.nactvar) {
|
||||
LuaString vname = fs.getlocvar(gt.nactvar).varname;
|
||||
String msg = L.pushfstring("<goto " + gt.name + "> at line "
|
||||
+ gt.line + " jumps into the scope of local '"
|
||||
+ vname.tojstring() + "'");
|
||||
semerror(msg);
|
||||
}
|
||||
fs.patchlist(gt.pc, label.pc);
|
||||
/* remove goto from pending list */
|
||||
System.arraycopy(gl, g + 1, gl, g, this.dyd.n_gt - g - 1);
|
||||
gl[--this.dyd.n_gt] = null;
|
||||
}
|
||||
|
||||
/*
|
||||
** try to close a goto with existing labels; this solves backward jumps
|
||||
*/
|
||||
boolean findlabel (int g) {
|
||||
int i;
|
||||
BlockCnt bl = fs.bl;
|
||||
Dyndata dyd = this.dyd;
|
||||
Labeldesc gt = dyd.gt[g];
|
||||
/* check labels in current block for a match */
|
||||
for (i = bl.firstlabel; i < dyd.n_label; i++) {
|
||||
Labeldesc lb = dyd.label[i];
|
||||
if (lb.name.eq_b(gt.name)) { /* correct label? */
|
||||
if (gt.nactvar > lb.nactvar &&
|
||||
(bl.upval || dyd.n_label > bl.firstlabel))
|
||||
fs.patchclose(gt.pc, lb.nactvar);
|
||||
closegoto(g, lb); /* close it */
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false; /* label not found; cannot close goto */
|
||||
}
|
||||
|
||||
/* Caller must LuaC.grow() the vector before calling this. */
|
||||
int newlabelentry(Labeldesc[] l, int index, LuaString name, int line, int pc) {
|
||||
l[index] = new Labeldesc(name, pc, line, fs.nactvar);
|
||||
return index;
|
||||
}
|
||||
|
||||
/*
|
||||
** check whether new label 'lb' matches any pending gotos in current
|
||||
** block; solves forward jumps
|
||||
*/
|
||||
void findgotos (Labeldesc lb) {
|
||||
Labeldesc[] gl = dyd.gt;
|
||||
int i = fs.bl.firstgoto;
|
||||
while (i < dyd.n_gt) {
|
||||
if (gl[i].name.eq_b(lb.name))
|
||||
closegoto(i, lb);
|
||||
else
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void open_func (FuncState fs) {
|
||||
|
||||
/*
|
||||
** create a label named "break" to resolve break statements
|
||||
*/
|
||||
void breaklabel () {
|
||||
LuaString n = LuaString.valueOf("break");
|
||||
int l = newlabelentry(LuaC.grow(dyd.label, dyd.n_label+1), dyd.n_label++, n, 0, fs.pc);
|
||||
findgotos(dyd.label[l]);
|
||||
}
|
||||
|
||||
/*
|
||||
** generates an error for an undefined 'goto'; choose appropriate
|
||||
** message when label name is a reserved word (which can only be 'break')
|
||||
*/
|
||||
void undefgoto (Labeldesc gt) {
|
||||
String msg = L.pushfstring(isReservedKeyword(gt.name.tojstring())
|
||||
? "<"+gt.name+"> at line "+gt.line+" not inside a loop"
|
||||
: "no visible label '"+gt.name+"' for <goto> at line "+gt.line);
|
||||
semerror(msg);
|
||||
}
|
||||
|
||||
void open_func (FuncState fs, BlockCnt bl) {
|
||||
LuaC L = this.L;
|
||||
Prototype f = new Prototype();
|
||||
if ( this.fs!=null )
|
||||
@@ -915,14 +1050,14 @@ public class LexState {
|
||||
fs.nactvar = 0;
|
||||
fs.bl = null;
|
||||
f.maxstacksize = 2; /* registers 0/1 are always valid */
|
||||
//fs.h = new LTable();
|
||||
fs.htable = new Hashtable();
|
||||
fs.enterblock(bl, false);
|
||||
}
|
||||
|
||||
void close_func() {
|
||||
FuncState fs = this.fs;
|
||||
Prototype f = fs.f;
|
||||
this.removevars(0);
|
||||
fs.ret(0, 0);
|
||||
fs.leaveblock();
|
||||
fs.ret(0, 0); /* final return */
|
||||
f.code = LuaC.realloc(f.code, fs.pc);
|
||||
f.lineinfo = LuaC.realloc(f.lineinfo, fs.pc);
|
||||
@@ -931,7 +1066,7 @@ public class LexState {
|
||||
f.p = LuaC.realloc(f.p, fs.np);
|
||||
f.locvars = LuaC.realloc(f.locvars, fs.nlocvars);
|
||||
// f.sizelocvars = fs.nlocvars;
|
||||
f.upvalues = LuaC.realloc(f.upvalues, f.nups);
|
||||
f.upvalues = LuaC.realloc(f.upvalues, fs.nups);
|
||||
// LuaC._assert (CheckCode.checkcode(f));
|
||||
LuaC._assert (fs.bl == null);
|
||||
this.fs = fs.prev;
|
||||
@@ -997,8 +1132,8 @@ public class LexState {
|
||||
this.checknext('=');
|
||||
rkkey = fs.exp2RK(key);
|
||||
this.expr(val);
|
||||
fs.codeABC(Lua.OP_SETTABLE, cc.t.u.s.info, rkkey, fs.exp2RK(val));
|
||||
fs.freereg = reg; /* free registers */
|
||||
fs.codeABC(Lua.OP_SETTABLE, cc.t.u.info, rkkey, fs.exp2RK(val));
|
||||
fs.freereg = (short)reg; /* free registers */
|
||||
}
|
||||
|
||||
void listfield (ConsControl cc) {
|
||||
@@ -1106,7 +1241,8 @@ public class LexState {
|
||||
void body(expdesc e, boolean needself, int line) {
|
||||
/* body -> `(' parlist `)' chunk END */
|
||||
FuncState new_fs = new FuncState();
|
||||
open_func(new_fs);
|
||||
BlockCnt bl = new BlockCnt();
|
||||
open_func(new_fs, bl);
|
||||
new_fs.f.linedefined = line;
|
||||
this.checknext('(');
|
||||
if (needself) {
|
||||
@@ -1115,11 +1251,10 @@ public class LexState {
|
||||
}
|
||||
this.parlist();
|
||||
this.checknext(')');
|
||||
this.chunk();
|
||||
this.statlist();
|
||||
new_fs.f.lastlinedefined = this.linenumber;
|
||||
this.check_match(TK_END, TK_FUNCTION, line);
|
||||
this.close_func();
|
||||
this.pushclosure(new_fs, e);
|
||||
}
|
||||
|
||||
int explist1(expdesc v) {
|
||||
@@ -1169,7 +1304,7 @@ public class LexState {
|
||||
}
|
||||
}
|
||||
LuaC._assert (f.k == VNONRELOC);
|
||||
base = f.u.s.info; /* base register for call */
|
||||
base = f.u.info; /* base register for call */
|
||||
if (hasmultret(args.k))
|
||||
nparams = Lua.LUA_MULTRET; /* open call */
|
||||
else {
|
||||
@@ -1179,7 +1314,7 @@ public class LexState {
|
||||
}
|
||||
f.init(VCALL, fs.codeABC(Lua.OP_CALL, base, nparams + 1, 2));
|
||||
fs.fixline(line);
|
||||
fs.freereg = base+1; /* call remove function and arguments and leaves
|
||||
fs.freereg = (short)(base+1); /* call remove function and arguments and leaves
|
||||
* (unless changed) one result */
|
||||
}
|
||||
|
||||
@@ -1427,11 +1562,12 @@ public class LexState {
|
||||
*/
|
||||
|
||||
|
||||
boolean block_follow (int token) {
|
||||
switch (token) {
|
||||
case TK_ELSE: case TK_ELSEIF: case TK_END:
|
||||
case TK_UNTIL: case TK_EOS:
|
||||
boolean block_follow (boolean withuntil) {
|
||||
switch (t.token) {
|
||||
case TK_ELSE: case TK_ELSEIF: case TK_END: case TK_EOS:
|
||||
return true;
|
||||
case TK_UNTIL:
|
||||
return withuntil;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
@@ -1442,8 +1578,7 @@ public class LexState {
|
||||
FuncState fs = this.fs;
|
||||
BlockCnt bl = new BlockCnt();
|
||||
fs.enterblock(bl, false);
|
||||
this.chunk();
|
||||
LuaC._assert(bl.breaklist.i == NO_JUMP);
|
||||
this.statlist();
|
||||
fs.leaveblock();
|
||||
}
|
||||
|
||||
@@ -1467,22 +1602,25 @@ public class LexState {
|
||||
*/
|
||||
void check_conflict (LHS_assign lh, expdesc v) {
|
||||
FuncState fs = this.fs;
|
||||
int extra = fs.freereg; /* eventual position to save local variable */
|
||||
short extra = (short) fs.freereg; /* eventual position to save local variable */
|
||||
boolean conflict = false;
|
||||
for (; lh!=null; lh = lh.prev) {
|
||||
if (lh.v.k == VINDEXED) {
|
||||
if (lh.v.u.s.info == v.u.s.info) { /* conflict? */
|
||||
/* table is the upvalue/local being assigned now? */
|
||||
if (lh.v.u.ind_vt == v.k && lh.v.u.ind_t == v.u.info) {
|
||||
conflict = true;
|
||||
lh.v.u.s.info = extra; /* previous assignment will use safe copy */
|
||||
lh.v.u.ind_vt = VLOCAL;
|
||||
lh.v.u.ind_t = extra; /* previous assignment will use safe copy */
|
||||
}
|
||||
if (lh.v.u.s.aux == v.u.s.info) { /* conflict? */
|
||||
/* index is the local being assigned? (index cannot be upvalue) */
|
||||
if (v.k == VLOCAL && lh.v.u.ind_idx == v.u.info) {
|
||||
conflict = true;
|
||||
lh.v.u.s.aux = extra; /* previous assignment will use safe copy */
|
||||
lh.v.u.ind_idx = extra; /* previous assignment will use safe copy */
|
||||
}
|
||||
}
|
||||
}
|
||||
if (conflict) {
|
||||
fs.codeABC(Lua.OP_MOVE, fs.freereg, v.u.s.info, 0); /* make copy */
|
||||
fs.codeABC(Lua.OP_MOVE, fs.freereg, v.u.info, 0); /* make copy */
|
||||
fs.reserveregs(1);
|
||||
}
|
||||
}
|
||||
@@ -1532,23 +1670,46 @@ public class LexState {
|
||||
return v.f.i;
|
||||
}
|
||||
|
||||
|
||||
void breakstat() {
|
||||
FuncState fs = this.fs;
|
||||
BlockCnt bl = fs.bl;
|
||||
boolean upval = false;
|
||||
while (bl != null && !bl.isbreakable) {
|
||||
upval |= bl.upval;
|
||||
bl = bl.previous;
|
||||
void gotostat(int pc) {
|
||||
int line = linenumber;
|
||||
LuaString label;
|
||||
int g;
|
||||
if (testnext(TK_GOTO))
|
||||
label = str_checkname();
|
||||
else {
|
||||
next(); /* skip break */
|
||||
label = LuaString.valueOf("break");
|
||||
}
|
||||
if (bl == null)
|
||||
this.syntaxerror("no loop to break");
|
||||
if (upval)
|
||||
fs.codeABC(Lua.OP_CLOSE, bl.nactvar, 0, 0);
|
||||
fs.concat(bl.breaklist, fs.jump());
|
||||
g = newlabelentry(LuaC.grow(dyd.gt, dyd.n_gt+1), dyd.n_gt++, label, line, pc);
|
||||
findlabel(g); /* close it if label already defined */
|
||||
}
|
||||
|
||||
|
||||
/* skip no-op statements */
|
||||
void skipnoopstat () {
|
||||
while (t.token == ';' || t.token == TK_DBCOLON)
|
||||
statement();
|
||||
}
|
||||
|
||||
|
||||
void labelstat (LuaString label, int line) {
|
||||
/* label -> '::' NAME '::' */
|
||||
FuncState fs = this.fs;
|
||||
Labeldesc[] ll = dyd.label;
|
||||
int l; /* index of new label being created */
|
||||
fs.checkrepeated(ll, dyd.n_label, label); /* check for repeated labels */
|
||||
checknext(TK_DBCOLON); /* skip double colon */
|
||||
/* create new entry for this label */
|
||||
l = newlabelentry(LuaC.grow(ll, dyd.n_label+1), dyd.n_label++, label, line, fs.pc);
|
||||
skipnoopstat(); /* skip other no-op statements */
|
||||
if (block_follow(false)) { /* label is last no-op statement in the block? */
|
||||
/* assume that locals are already out of scope */
|
||||
ll[l].nactvar = fs.bl.nactvar;
|
||||
}
|
||||
findgotos(ll[l]);
|
||||
}
|
||||
|
||||
|
||||
void whilestat (int line) {
|
||||
/* whilestat -> WHILE cond DO block END */
|
||||
FuncState fs = this.fs;
|
||||
@@ -1577,18 +1738,14 @@ public class LexState {
|
||||
fs.enterblock(bl1, true); /* loop block */
|
||||
fs.enterblock(bl2, false); /* scope block */
|
||||
this.next(); /* skip REPEAT */
|
||||
this.chunk();
|
||||
this.statlist();
|
||||
this.check_match(TK_UNTIL, TK_REPEAT, line);
|
||||
condexit = this.cond(); /* read condition (inside scope block) */
|
||||
if (!bl2.upval) { /* no upvalues? */
|
||||
fs.leaveblock(); /* finish scope */
|
||||
fs.patchlist(condexit, repeat_init); /* close the loop */
|
||||
} else { /* complete semantics when there are upvalues */
|
||||
this.breakstat(); /* if condition then break */
|
||||
fs.patchtohere(condexit); /* else... */
|
||||
fs.leaveblock(); /* finish scope... */
|
||||
fs.patchlist(fs.jump(), repeat_init); /* and repeat */
|
||||
if (bl2.upval) { /* upvalues? */
|
||||
fs.patchclose(condexit, bl2.nactvar);
|
||||
}
|
||||
fs.leaveblock(); /* finish scope */
|
||||
fs.patchlist(condexit, repeat_init); /* close the loop */
|
||||
fs.leaveblock(); /* finish loop */
|
||||
}
|
||||
|
||||
@@ -1807,7 +1964,7 @@ public class LexState {
|
||||
expdesc e = new expdesc();
|
||||
int first, nret; /* registers with returned values */
|
||||
this.next(); /* skip RETURN */
|
||||
if (block_follow(this.t.token) || this.t.token == ';')
|
||||
if (block_follow(true) || this.t.token == ';')
|
||||
first = nret = 0; /* return no values */
|
||||
else {
|
||||
nret = this.explist1(e); /* optional return values */
|
||||
@@ -1874,9 +2031,10 @@ public class LexState {
|
||||
this.retstat();
|
||||
return true; /* must be last statement */
|
||||
}
|
||||
case TK_BREAK: { /* stat -> breakstat */
|
||||
case TK_BREAK:
|
||||
case TK_GOTO: { /* stat -> breakstat */
|
||||
this.next(); /* skip BREAK */
|
||||
this.breakstat();
|
||||
this.gotostat(fs.jump());
|
||||
return true; /* must be last statement */
|
||||
}
|
||||
default: {
|
||||
@@ -1886,20 +2044,34 @@ public class LexState {
|
||||
}
|
||||
}
|
||||
|
||||
void chunk() {
|
||||
/* chunk -> { stat [`;'] } */
|
||||
boolean islast = false;
|
||||
this.enterlevel();
|
||||
while (!islast && !block_follow(this.t.token)) {
|
||||
islast = this.statement();
|
||||
this.testnext(';');
|
||||
LuaC._assert (this.fs.f.maxstacksize >= this.fs.freereg
|
||||
&& this.fs.freereg >= this.fs.nactvar);
|
||||
this.fs.freereg = this.fs.nactvar; /* free registers */
|
||||
void statlist() {
|
||||
/* statlist -> { stat [`;'] } */
|
||||
while (!block_follow(true)) {
|
||||
if (t.token == TK_RETURN) {
|
||||
statement();
|
||||
return; /* 'return' must be last statement */
|
||||
}
|
||||
statement();
|
||||
}
|
||||
this.leavelevel();
|
||||
}
|
||||
|
||||
/*
|
||||
** compiles the main function, which is a regular vararg function with an
|
||||
** upvalue named LUA_ENV
|
||||
*/
|
||||
public void mainfunc(FuncState funcstate) {
|
||||
BlockCnt bl = new BlockCnt();
|
||||
open_func(funcstate, bl);
|
||||
fs.f.is_vararg = 1; /* main function is always vararg */
|
||||
expdesc v = new expdesc();
|
||||
v.init(VLOCAL, 0); /* create and... */
|
||||
fs.newupvalue(envn, v); /* ...set environment upvalue */
|
||||
next(); /* read first token */
|
||||
statlist(); /* parse main body */
|
||||
check(TK_EOS);
|
||||
close_func();
|
||||
}
|
||||
|
||||
/* }====================================================================== */
|
||||
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.luaj.vm2.LuaFunction;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.Upvaldesc;
|
||||
import org.luaj.vm2.LoadState.LuaCompiler;
|
||||
|
||||
/**
|
||||
@@ -83,7 +84,7 @@ public class LuaC extends Lua implements LuaCompiler {
|
||||
}
|
||||
|
||||
public static final int MAXSTACK = 250;
|
||||
static final int LUAI_MAXUPVALUES = 60;
|
||||
static final int LUAI_MAXUPVAL = 0xff;
|
||||
static final int LUAI_MAXVARS = 200;
|
||||
static final int NO_REG = MAXARG_A;
|
||||
|
||||
@@ -106,6 +107,10 @@ public class LuaC extends Lua implements LuaCompiler {
|
||||
i.set( ( i.get() & (MASK_NOT_OP)) | ((o << POS_OP) & MASK_OP) );
|
||||
}
|
||||
|
||||
static void SETARG_A(int[] code, int index, int u) {
|
||||
code[index] = (code[index] & (MASK_NOT_A)) | ((u << POS_A) & MASK_A);
|
||||
}
|
||||
|
||||
static void SETARG_A(InstructionPtr i,int u) {
|
||||
i.set( ( i.get() & (MASK_NOT_A)) | ((u << POS_A) & MASK_A) );
|
||||
}
|
||||
@@ -169,6 +174,31 @@ public class LuaC extends Lua implements LuaCompiler {
|
||||
return a;
|
||||
}
|
||||
|
||||
static Upvaldesc[] realloc(Upvaldesc[] v, int n) {
|
||||
Upvaldesc[] a = new Upvaldesc[n];
|
||||
if ( v != null )
|
||||
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
|
||||
return a;
|
||||
}
|
||||
|
||||
static LexState.Vardesc[] realloc(LexState.Vardesc[] v, int n) {
|
||||
LexState.Vardesc[] a = new LexState.Vardesc[n];
|
||||
if ( v != null )
|
||||
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
|
||||
return a;
|
||||
}
|
||||
|
||||
static LexState.Labeldesc[] grow(LexState.Labeldesc[] v, int min_n) {
|
||||
return v == null ? new LexState.Labeldesc[2] : v.length <= min_n ? v : realloc(v, v.length*2);
|
||||
}
|
||||
|
||||
static LexState.Labeldesc[] realloc(LexState.Labeldesc[] v, int n) {
|
||||
LexState.Labeldesc[] a = new LexState.Labeldesc[n];
|
||||
if ( v != null )
|
||||
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
|
||||
return a;
|
||||
}
|
||||
|
||||
static int[] realloc(int[] v, int n) {
|
||||
int[] a = new int[n];
|
||||
if ( v != null )
|
||||
@@ -206,23 +236,22 @@ public class LuaC extends Lua implements LuaCompiler {
|
||||
(new LuaC(new Hashtable())).luaY_parser(firstByte, stream, name);
|
||||
}
|
||||
|
||||
|
||||
/** Parse the input */
|
||||
private Prototype luaY_parser(int firstByte, InputStream z, String name) {
|
||||
LexState lexstate = new LexState(this, z);
|
||||
FuncState funcstate = new FuncState();
|
||||
// lexstate.buff = buff;
|
||||
lexstate.fs = funcstate;
|
||||
lexstate.setinput( this, firstByte, z, (LuaString) LuaValue.valueOf(name) );
|
||||
lexstate.open_func(funcstate);
|
||||
/* main func. is always vararg */
|
||||
funcstate.f.is_vararg = LuaC.VARARG_ISVARARG;
|
||||
funcstate.f = new Prototype();
|
||||
funcstate.f.source = (LuaString) LuaValue.valueOf(name);
|
||||
lexstate.next(); /* read first token */
|
||||
lexstate.chunk();
|
||||
lexstate.check(LexState.TK_EOS);
|
||||
lexstate.close_func();
|
||||
lexstate.mainfunc(funcstate);
|
||||
LuaC._assert (funcstate.prev == null);
|
||||
LuaC._assert (funcstate.f.nups == 0);
|
||||
LuaC._assert (lexstate.fs == null);
|
||||
/* all scopes should be correctly finished */
|
||||
LuaC._assert (lexstate.dyd == null
|
||||
|| (lexstate.dyd.n_actvar == 0 && lexstate.dyd.n_gt == 0 && lexstate.dyd.n_label == 0));
|
||||
return funcstate.f;
|
||||
}
|
||||
|
||||
|
||||
@@ -123,6 +123,7 @@ public class DebugLib extends VarArgFunction {
|
||||
private static final LuaString COUNT = valueOf("count");
|
||||
private static final LuaString RETURN = valueOf("return");
|
||||
private static final LuaString TAILRETURN = valueOf("tail return");
|
||||
private static final LuaString CONSTANT = valueOf("constant");
|
||||
|
||||
private static final LuaString FUNC = valueOf("func");
|
||||
private static final LuaString NUPS = valueOf("nups");
|
||||
@@ -219,7 +220,7 @@ public class DebugLib extends VarArgFunction {
|
||||
public LuaString[] getfunckind() {
|
||||
if ( closure == null || pc<0 ) return null;
|
||||
int stackpos = (closure.p.code[pc] >> 6) & 0xff;
|
||||
return getobjname(this, stackpos);
|
||||
return getobjname(this, pc, stackpos);
|
||||
}
|
||||
public String sourceline() {
|
||||
if ( closure == null ) return func.tojstring();
|
||||
@@ -500,7 +501,7 @@ public class DebugLib extends VarArgFunction {
|
||||
break;
|
||||
}
|
||||
case 'u': {
|
||||
info.set(NUPS, valueOf(c!=null? c.p.nups: 0));
|
||||
info.set(NUPS, valueOf(c!=null? c.p.upvalues.length: 0));
|
||||
break;
|
||||
}
|
||||
case 'n': {
|
||||
@@ -604,7 +605,7 @@ public class DebugLib extends VarArgFunction {
|
||||
static LuaString findupvalue(LuaClosure c, int up) {
|
||||
if ( c.upValues != null && up > 0 && up <= c.upValues.length ) {
|
||||
if ( c.p.upvalues != null && up <= c.p.upvalues.length )
|
||||
return c.p.upvalues[up-1];
|
||||
return c.p.upvalues[up-1].name;
|
||||
else
|
||||
return LuaString.valueOf( "."+up );
|
||||
}
|
||||
@@ -720,40 +721,53 @@ public class DebugLib extends VarArgFunction {
|
||||
|
||||
|
||||
// return StrValue[] { name, namewhat } if found, null if not
|
||||
static LuaString[] getobjname(DebugInfo di, int stackpos) {
|
||||
LuaString name;
|
||||
if (di.closure != null) { /* a Lua function? */
|
||||
Prototype p = di.closure.p;
|
||||
int pc = di.pc; // currentpc(L, ci);
|
||||
int i;// Instruction i;
|
||||
name = p.getlocalname(stackpos + 1, pc);
|
||||
if (name != null) /* is a local? */
|
||||
return new LuaString[] { name, LOCAL };
|
||||
i = symbexec(p, pc, stackpos); /* try symbolic execution */
|
||||
lua_assert(pc != -1);
|
||||
static LuaString[] getobjname(DebugInfo di, int lastpc, int reg) {
|
||||
if (di.closure == null)
|
||||
return null; /* Not a Lua function? */
|
||||
|
||||
Prototype p = di.closure.p;
|
||||
int pc = di.pc; // currentpc(L, ci);
|
||||
LuaString name = p.getlocalname(reg + 1, pc);
|
||||
if (name != null) /* is a local? */
|
||||
return new LuaString[] { name, LOCAL };
|
||||
|
||||
/* else try symbolic execution */
|
||||
pc = findsetreg(p, lastpc, reg);
|
||||
if (pc != -1) { /* could find instruction? */
|
||||
int i = p.code[pc];
|
||||
switch (Lua.GET_OPCODE(i)) {
|
||||
case Lua.OP_GETGLOBAL: {
|
||||
int g = Lua.GETARG_Bx(i); /* global index */
|
||||
// lua_assert(p.k[g].isString());
|
||||
return new LuaString[] { p.k[g].strvalue(), GLOBAL };
|
||||
}
|
||||
case Lua.OP_MOVE: {
|
||||
int a = Lua.GETARG_A(i);
|
||||
int b = Lua.GETARG_B(i); /* move from `b' to `a' */
|
||||
if (b < a)
|
||||
return getobjname(di, b); /* get name for `b' */
|
||||
return getobjname(di, pc, b); /* get name for `b' */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_GETTABUP:
|
||||
case Lua.OP_GETTABLE: {
|
||||
int k = Lua.GETARG_C(i); /* key index */
|
||||
int t = Lua.GETARG_Bx(i); /* table index */
|
||||
LuaString vn = (Lua.GET_OPCODE(i) == Lua.OP_GETTABLE) /* name of indexed variable */
|
||||
? p.getlocalname(t + 1, pc)
|
||||
: (t < p.upvalues.length ? p.upvalues[t].name : QMARK);
|
||||
name = kname(p, k);
|
||||
return new LuaString[] { name, FIELD };
|
||||
return new LuaString[] { name, vn.eq_b(ENV)? GLOBAL: FIELD };
|
||||
}
|
||||
case Lua.OP_GETUPVAL: {
|
||||
int u = Lua.GETARG_B(i); /* upvalue index */
|
||||
name = u < p.upvalues.length ? p.upvalues[u] : QMARK;
|
||||
name = u < p.upvalues.length ? p.upvalues[u].name : QMARK;
|
||||
return new LuaString[] { name, UPVALUE };
|
||||
}
|
||||
case Lua.OP_LOADK:
|
||||
case Lua.OP_LOADKX: {
|
||||
int b = (Lua.GET_OPCODE(i) == Lua.OP_LOADK) ? Lua.GETARG_Bx(i)
|
||||
: Lua.GETARG_Ax(p.code[pc + 1]);
|
||||
if (p.k[b].isstring()) {
|
||||
name = p.k[b].strvalue();
|
||||
return new LuaString[] { name, CONSTANT };
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Lua.OP_SELF: {
|
||||
int k = Lua.GETARG_C(i); /* key index */
|
||||
name = kname(p, k);
|
||||
@@ -782,7 +796,7 @@ public class DebugLib extends VarArgFunction {
|
||||
lua_assert(pt.numparams + (pt.is_vararg & Lua.VARARG_HASARG) <= pt.maxstacksize);
|
||||
lua_assert((pt.is_vararg & Lua.VARARG_NEEDSARG) == 0
|
||||
|| (pt.is_vararg & Lua.VARARG_HASARG) != 0);
|
||||
if (!(pt.upvalues.length <= pt.nups)) return false;
|
||||
// if (!(pt.upvalues.length <= pt.nups)) return false;
|
||||
if (!(pt.lineinfo.length == pt.code.length || pt.lineinfo.length == 0)) return false;
|
||||
if (!(Lua.GET_OPCODE(pt.code[pt.code.length - 1]) == Lua.OP_RETURN)) return false;
|
||||
return true;
|
||||
@@ -816,162 +830,51 @@ public class DebugLib extends VarArgFunction {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// return last instruction, or 0 if error
|
||||
static int symbexec(Prototype pt, int lastpc, int reg) {
|
||||
int pc;
|
||||
int last; /* stores position of last instruction that changed `reg' */
|
||||
last = pt.code.length - 1; /*
|
||||
* points to final return (a `neutral'
|
||||
* instruction)
|
||||
*/
|
||||
if (!(precheck(pt))) return 0;
|
||||
for (pc = 0; pc < lastpc; pc++) {
|
||||
int i = pt.code[pc];
|
||||
int op = Lua.GET_OPCODE(i);
|
||||
int a = Lua.GETARG_A(i);
|
||||
int b = 0;
|
||||
int c = 0;
|
||||
if (!(op < Lua.NUM_OPCODES)) return 0;
|
||||
if (!checkreg(pt, a)) return 0;
|
||||
switch (Lua.getOpMode(op)) {
|
||||
case Lua.iABC: {
|
||||
b = Lua.GETARG_B(i);
|
||||
c = Lua.GETARG_C(i);
|
||||
if (!(checkArgMode(pt, b, Lua.getBMode(op)))) return 0;
|
||||
if (!(checkArgMode(pt, c, Lua.getCMode(op)))) return 0;
|
||||
break;
|
||||
}
|
||||
case Lua.iABx: {
|
||||
b = Lua.GETARG_Bx(i);
|
||||
if (Lua.getBMode(op) == Lua.OpArgK)
|
||||
if (!(b < pt.k.length)) return 0;
|
||||
break;
|
||||
}
|
||||
case Lua.iAsBx: {
|
||||
b = Lua.GETARG_sBx(i);
|
||||
if (Lua.getBMode(op) == Lua.OpArgR) {
|
||||
int dest = pc + 1 + b;
|
||||
if (!(0 <= dest && dest < pt.code.length)) return 0;
|
||||
if (dest > 0) {
|
||||
/* cannot jump to a setlist count */
|
||||
int d = pt.code[dest - 1];
|
||||
if ((Lua.GET_OPCODE(d) == Lua.OP_SETLIST && Lua.GETARG_C(d) == 0)) return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (Lua.testAMode(op)) {
|
||||
if (a == reg)
|
||||
last = pc; /* change register `a' */
|
||||
}
|
||||
if (Lua.testTMode(op)) {
|
||||
if (!(pc + 2 < pt.code.length)) return 0; /* check skip */
|
||||
if (!(Lua.GET_OPCODE(pt.code[pc + 1]) == Lua.OP_JMP)) return 0;
|
||||
}
|
||||
switch (op) {
|
||||
case Lua.OP_LOADBOOL: {
|
||||
if (!(c == 0 || pc + 2 < pt.code.length)) return 0; /* check its jump */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_LOADNIL: {
|
||||
if (a <= reg && reg <= b)
|
||||
last = pc; /* set registers from `a' to `b' */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_GETUPVAL:
|
||||
case Lua.OP_SETUPVAL: {
|
||||
if (!(b < pt.nups)) return 0;
|
||||
break;
|
||||
}
|
||||
case Lua.OP_GETGLOBAL:
|
||||
case Lua.OP_SETGLOBAL: {
|
||||
if (!(pt.k[b].isstring())) return 0;
|
||||
break;
|
||||
}
|
||||
case Lua.OP_SELF: {
|
||||
if (!checkreg(pt, a + 1)) return 0;
|
||||
if (reg == a + 1)
|
||||
last = pc;
|
||||
break;
|
||||
}
|
||||
case Lua.OP_CONCAT: {
|
||||
if (!(b < c)) return 0; /* at least two operands */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_TFORLOOP: {
|
||||
if (!(c >= 1)) return 0; /* at least one result (control variable) */
|
||||
if (!checkreg(pt, a + 2 + c)) return 0; /* space for results */
|
||||
if (reg >= a + 2)
|
||||
last = pc; /* affect all regs above its base */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_FORLOOP:
|
||||
case Lua.OP_FORPREP:
|
||||
if (!checkreg(pt, a + 3)) return 0;
|
||||
/* go through */
|
||||
case Lua.OP_JMP: {
|
||||
int dest = pc + 1 + b;
|
||||
/* not full check and jump is forward and do not skip `lastpc'? */
|
||||
if (reg != Lua.NO_REG && pc < dest && dest <= lastpc)
|
||||
pc += b; /* do the jump */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_CALL:
|
||||
case Lua.OP_TAILCALL: {
|
||||
if (b != 0) {
|
||||
if (!checkreg(pt, a + b - 1)) return 0;
|
||||
}
|
||||
c--; /* c = num. returns */
|
||||
if (c == Lua.LUA_MULTRET) {
|
||||
if (!(checkopenop(pt, pc))) return 0;
|
||||
} else if (c != 0)
|
||||
if (!checkreg(pt, a + c - 1)) return 0;
|
||||
if (reg >= a)
|
||||
last = pc; /* affect all registers above base */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_RETURN: {
|
||||
b--; /* b = num. returns */
|
||||
if (b > 0)
|
||||
if (!checkreg(pt, a + b - 1)) return 0;
|
||||
break;
|
||||
}
|
||||
case Lua.OP_SETLIST: {
|
||||
if (b > 0)
|
||||
if (!checkreg(pt, a + b)) return 0;
|
||||
if (c == 0)
|
||||
pc++;
|
||||
break;
|
||||
}
|
||||
case Lua.OP_CLOSURE: {
|
||||
int nup, j;
|
||||
if (!(b < pt.p.length)) return 0;
|
||||
nup = pt.p[b].nups;
|
||||
if (!(pc + nup < pt.code.length)) return 0;
|
||||
for (j = 1; j <= nup; j++) {
|
||||
int op1 = Lua.GET_OPCODE(pt.code[pc + j]);
|
||||
if (!(op1 == Lua.OP_GETUPVAL || op1 == Lua.OP_MOVE)) return 0;
|
||||
}
|
||||
if (reg != Lua.NO_REG) /* tracing? */
|
||||
pc += nup; /* do not 'execute' these pseudo-instructions */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_VARARG: {
|
||||
if (!((pt.is_vararg & Lua.VARARG_ISVARARG) != 0
|
||||
&& (pt.is_vararg & Lua.VARARG_NEEDSARG) == 0)) return 0;
|
||||
b--;
|
||||
if (b == Lua.LUA_MULTRET)
|
||||
if (!(checkopenop(pt, pc))) return 0;
|
||||
if (!checkreg(pt, a + b - 1)) return 0;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return pt.code[last];
|
||||
/*
|
||||
** try to find last instruction before 'lastpc' that modified register 'reg'
|
||||
*/
|
||||
static int findsetreg (Prototype p, int lastpc, int reg) {
|
||||
int pc;
|
||||
int setreg = -1; /* keep last instruction that changed 'reg' */
|
||||
for (pc = 0; pc < lastpc; pc++) {
|
||||
int i = p.code[pc];
|
||||
int op = Lua.GET_OPCODE(i);
|
||||
int a = Lua.GETARG_A(i);
|
||||
switch (op) {
|
||||
case Lua.OP_LOADNIL: {
|
||||
int b = Lua.GETARG_B(i);
|
||||
if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */
|
||||
setreg = pc;
|
||||
break;
|
||||
}
|
||||
case Lua.OP_TFORCALL: {
|
||||
if (reg >= a + 2) setreg = pc; /* affect all regs above its base */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_CALL:
|
||||
case Lua.OP_TAILCALL: {
|
||||
if (reg >= a) setreg = pc; /* affect all registers above base */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_JMP: {
|
||||
int b = Lua.GETARG_sBx(i);
|
||||
int dest = pc + 1 + b;
|
||||
/* jump is forward and do not skip `lastpc'? */
|
||||
if (pc < dest && dest <= lastpc)
|
||||
pc += b; /* do the jump */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_TEST: {
|
||||
if (reg == a) setreg = pc; /* jumped code can change 'a' */
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (Lua.testAMode(op) && reg == a) /* any instruction that set A */
|
||||
setreg = pc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return setreg;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -196,7 +196,7 @@ public class JavaBuilder {
|
||||
main = new InstructionList();
|
||||
|
||||
// create the fields
|
||||
for ( int i=0; i<p.nups; i++ ) {
|
||||
for ( int i=0; i<p.upvalues.length; i++ ) {
|
||||
boolean isrw = pi.isReadWriteUpvalue( pi.upvals[i] );
|
||||
Type uptype = isrw? (Type) TYPE_LOCALUPVALUE: (Type) TYPE_LUAVALUE;
|
||||
FieldGen fg = new FieldGen(0, uptype, upvalueName(i), cp);
|
||||
|
||||
@@ -122,20 +122,6 @@ public class JavaGen {
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_GETGLOBAL: /* A Bx R(A):= Gbl[Kst(Bx)] */
|
||||
builder.loadEnv();
|
||||
builder.loadConstant( p.k[bx] );
|
||||
builder.getTable();
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_SETGLOBAL: /* A Bx Gbl[Kst(Bx)]:= R(A) */
|
||||
builder.loadEnv();
|
||||
builder.loadConstant( p.k[bx] );
|
||||
builder.loadLocal( pc, a );
|
||||
builder.setTable();
|
||||
break;
|
||||
|
||||
case Lua.OP_LOADNIL: /* A B R(A):= ...:= R(B):= nil */
|
||||
builder.loadNil();
|
||||
for ( ; a<=b; a++ ) {
|
||||
@@ -145,6 +131,13 @@ public class JavaGen {
|
||||
}
|
||||
break;
|
||||
|
||||
case Lua.OP_GETTABUP: /* A B C R(A) := UpValue[B][RK(C)] */
|
||||
builder.loadUpvalue( b );
|
||||
loadLocalOrConstant( p, builder, pc, c );
|
||||
builder.getTable();
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_GETTABLE: /* A B C R(A):= R(B)[RK(C)] */
|
||||
builder.loadLocal( pc, b );
|
||||
loadLocalOrConstant( p, builder, pc, c );
|
||||
@@ -152,6 +145,13 @@ public class JavaGen {
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_SETTABUP: /* A B C UpValue[A][RK(B)] := RK(C) */
|
||||
builder.loadUpvalue( a );
|
||||
loadLocalOrConstant( p, builder, pc, b );
|
||||
loadLocalOrConstant( p, builder, pc, c );
|
||||
builder.setTable();
|
||||
break;
|
||||
|
||||
case Lua.OP_SETTABLE: /* A B C R(A)[RK(B)]:= RK(C) */
|
||||
builder.loadLocal( pc, a );
|
||||
loadLocalOrConstant( p, builder, pc, b );
|
||||
@@ -342,6 +342,9 @@ public class JavaGen {
|
||||
builder.addBranch(pc, JavaBuilder.BRANCH_IFNE, pc+1+sbx);
|
||||
break;
|
||||
|
||||
case Lua.OP_TFORCALL: /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */
|
||||
throw new RuntimeException("Unimplemented OP_TFORCALL");
|
||||
|
||||
case Lua.OP_TFORLOOP: /*
|
||||
* A C R(A+3), ... ,R(A+2+C):= R(A)(R(A+1),
|
||||
* R(A+2)): if R(A+3) ~= nil then R(A+2)=R(A+3)
|
||||
@@ -395,14 +398,11 @@ public class JavaGen {
|
||||
}
|
||||
break;
|
||||
|
||||
case Lua.OP_CLOSE: /* A close all variables in the stack up to (>=) R(A)*/
|
||||
break;
|
||||
|
||||
case Lua.OP_CLOSURE: /* A Bx R(A):= closure(KPROTO[Bx], R(A), ... ,R(A+n)) */
|
||||
{
|
||||
Prototype newp = p.p[bx];
|
||||
String protoname = closureName(classname, bx);
|
||||
int nup = newp.nups;
|
||||
int nup = newp.upvalues.length;
|
||||
builder.closureCreate( protoname );
|
||||
if ( nup > 0 )
|
||||
builder.dup();
|
||||
|
||||
@@ -164,7 +164,7 @@ public class ProtoInfo {
|
||||
case Lua.OP_LOADK:/* A Bx R(A) := Kst(Bx) */
|
||||
case Lua.OP_LOADBOOL:/* A B C R(A) := (Bool)B; if (C) pc++ */
|
||||
case Lua.OP_GETUPVAL: /* A B R(A) := UpValue[B] */
|
||||
case Lua.OP_GETGLOBAL: /* A Bx R(A) := Gbl[Kst(Bx)] */
|
||||
case Lua.OP_GETTABUP: /* A B C R(A) := UpValue[B][RK(C)] */
|
||||
case Lua.OP_NEWTABLE: /* A B C R(A) := {} (size = B,C) */
|
||||
a = Lua.GETARG_A( ins );
|
||||
v[a][pc] = new VarInfo(a,pc);
|
||||
@@ -203,6 +203,13 @@ public class ProtoInfo {
|
||||
if (!Lua.ISK(b)) v[b][pc].isreferenced = true;
|
||||
if (!Lua.ISK(c)) v[c][pc].isreferenced = true;
|
||||
break;
|
||||
|
||||
case Lua.OP_SETTABUP: /* A B C UpValue[A][RK(B)] := RK(C) */
|
||||
b = Lua.GETARG_B( ins );
|
||||
c = Lua.GETARG_C( ins );
|
||||
if (!Lua.ISK(b)) v[b][pc].isreferenced = true;
|
||||
if (!Lua.ISK(c)) v[c][pc].isreferenced = true;
|
||||
break;
|
||||
|
||||
case Lua.OP_CONCAT: /* A B C R(A) := R(B).. ... ..R(C) */
|
||||
a = Lua.GETARG_A( ins );
|
||||
@@ -295,6 +302,7 @@ public class ProtoInfo {
|
||||
v[a+i][pc].isreferenced = true;
|
||||
break;
|
||||
|
||||
case Lua.OP_TFORCALL: /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */
|
||||
case Lua.OP_TFORLOOP: /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));
|
||||
if R(A+3) ~= nil then R(A+2)=R(A+3) else pc++ */
|
||||
a = Lua.GETARG_A( ins );
|
||||
@@ -311,7 +319,7 @@ public class ProtoInfo {
|
||||
case Lua.OP_CLOSURE: /* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */
|
||||
a = Lua.GETARG_A( ins );
|
||||
b = Lua.GETARG_Bx( ins );
|
||||
nups = prototype.p[b].nups;
|
||||
nups = prototype.p[b].upvalues.length;
|
||||
for ( int k=1; k<=nups; ++k ) {
|
||||
int i = prototype.code[pc+k];
|
||||
if ( (i&4) == 0 ) {
|
||||
@@ -324,12 +332,7 @@ public class ProtoInfo {
|
||||
propogateVars( v, pc, pc+k );
|
||||
pc += nups;
|
||||
break;
|
||||
case Lua.OP_CLOSE: /* A close all variables in the stack up to (>=) R(A)*/
|
||||
a = Lua.GETARG_A( ins );
|
||||
for ( ; a<m; a++ )
|
||||
v[a][pc] = VarInfo.INVALID;
|
||||
break;
|
||||
|
||||
|
||||
case Lua.OP_SETLIST: /* A B C R(A)[(C-1)*FPF+i]:= R(A+i), 1 <= i <= B */
|
||||
a = Lua.GETARG_A( ins );
|
||||
b = Lua.GETARG_B( ins );
|
||||
@@ -338,7 +341,6 @@ public class ProtoInfo {
|
||||
v[a+i][pc].isreferenced = true;
|
||||
break;
|
||||
|
||||
case Lua.OP_SETGLOBAL: /* A Bx Gbl[Kst(Bx)]:= R(A) */
|
||||
case Lua.OP_SETUPVAL: /* A B UpValue[B]:= R(A) */
|
||||
case Lua.OP_TEST: /* A C if not (R(A) <=> C) then pc++ */
|
||||
a = Lua.GETARG_A( ins );
|
||||
@@ -402,9 +404,9 @@ public class ProtoInfo {
|
||||
if ( Lua.GET_OPCODE(code[pc]) == Lua.OP_CLOSURE ) {
|
||||
int bx = Lua.GETARG_Bx(code[pc]);
|
||||
Prototype newp = prototype.p[bx];
|
||||
UpvalInfo[] newu = newp.nups>0? new UpvalInfo[newp.nups]: null;
|
||||
UpvalInfo[] newu = new UpvalInfo[newp.upvalues.length];
|
||||
String newname = name + "$" + bx;
|
||||
for ( int j=0; j<newp.nups; ++j ) {
|
||||
for ( int j=0; j<newp.upvalues.length; ++j ) {
|
||||
int i = code[++pc];
|
||||
int b = Lua.GETARG_B(i);
|
||||
newu[j] = (i&4) != 0? upvals[b]: findOpenUp(pc,b);
|
||||
|
||||
@@ -5,23 +5,26 @@ package org.luaj.vm2.compiler;
|
||||
public class CompilerUnitTests extends AbstractUnitTests {
|
||||
|
||||
public CompilerUnitTests() {
|
||||
super("lua5.1-tests.zip", "lua5.1-tests");
|
||||
super("lua5.2.1-tests.zip", "lua5.2.1-tests");
|
||||
}
|
||||
|
||||
public void testAll() { doTest("all.lua"); }
|
||||
public void testAll() { doTest("all.lua"); }
|
||||
public void testApi() { doTest("api.lua"); }
|
||||
public void testAttrib() { doTest("attrib.lua"); }
|
||||
public void testBig() { doTest("big.lua"); }
|
||||
public void testBitwise() { doTest("bitwise.lua"); }
|
||||
public void testCalls() { doTest("calls.lua"); }
|
||||
public void testChecktable() { doTest("checktable.lua"); }
|
||||
public void testClosure() { doTest("closure.lua"); }
|
||||
public void testCode() { doTest("code.lua"); }
|
||||
public void testConstruct() { doTest("constructs.lua"); }
|
||||
public void testCoroutine() { doTest("coroutine.lua"); }
|
||||
public void testDb() { doTest("db.lua"); }
|
||||
public void testErrors() { doTest("errors.lua"); }
|
||||
public void testEvents() { doTest("events.lua"); }
|
||||
public void testFiles() { doTest("files.lua"); }
|
||||
public void testGc() { doTest("gc.lua"); }
|
||||
public void testGoto() { doTest("goto.lua"); }
|
||||
public void testLiterals() { doTest("literals.lua"); }
|
||||
public void testLocals() { doTest("locals.lua"); }
|
||||
public void testMain() { doTest("main.lua"); }
|
||||
|
||||
Binary file not shown.
BIN
test/junit/org/luaj/vm2/compiler/lua5.2.1-tests.zip
Normal file
BIN
test/junit/org/luaj/vm2/compiler/lua5.2.1-tests.zip
Normal file
Binary file not shown.
Reference in New Issue
Block a user