added debugging support and integrated with Eclipse debugger
This commit is contained in:
@@ -1,105 +0,0 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package lua;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
|
||||
import lua.value.LBoolean;
|
||||
import lua.value.LFunction;
|
||||
import lua.value.LNil;
|
||||
import lua.value.LTable;
|
||||
import lua.value.LValue;
|
||||
|
||||
final class Builtin extends LFunction {
|
||||
|
||||
static void addBuiltins(LTable table) {
|
||||
for ( int i=0; i<NAMES.length; i++ )
|
||||
table.put( NAMES[i], new Builtin(i) );
|
||||
}
|
||||
|
||||
private static final String[] NAMES = {
|
||||
"print",
|
||||
"pairs",
|
||||
"getmetatable",
|
||||
"setmetatable",
|
||||
"type",
|
||||
"pcall",
|
||||
"ipairs",
|
||||
};
|
||||
private static final int PRINT = 0;
|
||||
private static final int PAIRS = 1;
|
||||
private static final int GETMETATABLE = 2;
|
||||
private static final int SETMETATABLE = 3;
|
||||
private static final int TYPE = 4;
|
||||
private static final int PCALL = 5;
|
||||
private static final int IPAIRS = 6;
|
||||
|
||||
private static PrintStream stdout = System.out;
|
||||
|
||||
private int id;
|
||||
private Builtin( int id ) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "builtin."+NAMES[id];
|
||||
}
|
||||
|
||||
// perform a lua call
|
||||
public boolean luaStackCall(VM vm) {
|
||||
switch ( id ) {
|
||||
case PRINT: {
|
||||
int n = vm.getArgCount();
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
if ( i > 0 )
|
||||
stdout.print( "\t" );
|
||||
stdout.print( vm.getArg(i).luaAsString() );
|
||||
}
|
||||
stdout.println();
|
||||
vm.setResult();
|
||||
}
|
||||
break;
|
||||
case PAIRS:
|
||||
case IPAIRS:
|
||||
vm.setResult( vm.getArg(0).luaPairs(id==PAIRS) );
|
||||
break;
|
||||
case GETMETATABLE:
|
||||
vm.setResult( vm.getArg(0).luaGetMetatable() );
|
||||
break;
|
||||
case SETMETATABLE:
|
||||
LValue t = vm.getArg(0);
|
||||
t.luaSetMetatable(vm.getArg(1));
|
||||
vm.setResult( t );
|
||||
break;
|
||||
case TYPE:
|
||||
vm.setResult( vm.getArg(0).luaGetType() );
|
||||
break;
|
||||
case PCALL: {
|
||||
int n = vm.getArgCount();
|
||||
int s = vm.lua_pcall( n-1, Lua.LUA_MULTRET );
|
||||
if ( s != 0 ) {
|
||||
LValue v = vm.lua_tolvalue(-1);
|
||||
vm.setResult( LBoolean.FALSE );
|
||||
vm.push( v );
|
||||
} else {
|
||||
vm.setResult( LBoolean.TRUE );
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
luaUnsupportedOperation();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void redirectOutput( OutputStream newStdOut ) {
|
||||
stdout = new PrintStream( newStdOut );
|
||||
}
|
||||
|
||||
static void restoreStandardOutput() {
|
||||
stdout = System.out;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package lua;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
import lua.value.LTable;
|
||||
|
||||
/**
|
||||
** `global state', shared by all threads of this state
|
||||
*/
|
||||
public class GlobalState {
|
||||
|
||||
// typedef struct global_State {
|
||||
Hashtable strt; /* hash table for strings */
|
||||
StringBuffer buff; /* temporary buffer for string concatentation */
|
||||
// lu_mem totalbytes; /* number of bytes currently allocated */
|
||||
// lu_mem estimate; /* an estimate of number of bytes actually in use */
|
||||
// lua_CFunction panic; /* to be called in unprotected errors */
|
||||
// TValue l_registry;
|
||||
// struct lua_State *mainthread;
|
||||
StackState mainthread;
|
||||
// UpVal uvhead; /* head of double-linked list of all open upvalues */
|
||||
// struct Table *mt[NUM_TAGS]; /* metatables for basic types */
|
||||
// TString *tmname[TM_N]; /* array with tag-method names */
|
||||
// } global_State;
|
||||
//
|
||||
private static LTable _G;
|
||||
|
||||
static {
|
||||
resetGlobals();
|
||||
}
|
||||
|
||||
static void resetGlobals() {
|
||||
_G = new LTable();
|
||||
_G .put( "_G", _G );
|
||||
Builtin.addBuiltins( _G );
|
||||
}
|
||||
|
||||
public static LTable getGlobalsTable() {
|
||||
return _G;
|
||||
}
|
||||
}
|
||||
@@ -1,357 +0,0 @@
|
||||
package lua;
|
||||
/**
|
||||
* Constants for lua limits and opcodes
|
||||
*
|
||||
* @author jim_roseborough
|
||||
*
|
||||
*/
|
||||
public class Lua {
|
||||
|
||||
// from llimits.h
|
||||
|
||||
/** maximum stack for a Lua function */
|
||||
public static final int MAXSTACK = 250;
|
||||
|
||||
/** minimum size for the string table (must be power of 2) */
|
||||
public static final int MINSTRTABSIZE = 32;
|
||||
|
||||
/** minimum size for string buffer */
|
||||
public static final int LUA_MINBUFFER = 32;
|
||||
|
||||
/** use return values from previous op */
|
||||
public static final int LUA_MULTRET = -1;
|
||||
|
||||
|
||||
// from lopcodes.h
|
||||
|
||||
/*===========================================================================
|
||||
We assume that instructions are unsigned numbers.
|
||||
All instructions have an opcode in the first 6 bits.
|
||||
Instructions can have the following fields:
|
||||
`A' : 8 bits
|
||||
`B' : 9 bits
|
||||
`C' : 9 bits
|
||||
`Bx' : 18 bits (`B' and `C' together)
|
||||
`sBx' : signed Bx
|
||||
|
||||
A signed argument is represented in excess K; that is, the number
|
||||
value is the unsigned value minus K. K is exactly the maximum value
|
||||
for that argument (so that -max is represented by 0, and +max is
|
||||
represented by 2*max), which is half the maximum for the corresponding
|
||||
unsigned argument.
|
||||
===========================================================================*/
|
||||
|
||||
|
||||
/* basic instruction format */
|
||||
public static final int iABC = 0;
|
||||
public static final int iABx = 1;
|
||||
public static final int iAsBx = 2;
|
||||
|
||||
|
||||
/*
|
||||
** size and position of opcode arguments.
|
||||
*/
|
||||
public static final int SIZE_C = 9;
|
||||
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_OP = 6;
|
||||
|
||||
public static final int POS_OP = 0;
|
||||
public static final int POS_A = (POS_OP + SIZE_OP);
|
||||
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 MAX_OP = ((1<<SIZE_OP)-1);
|
||||
public static final int MAXARG_A = ((1<<SIZE_A)-1);
|
||||
public static final int MAXARG_B = ((1<<SIZE_B)-1);
|
||||
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 MASK_OP = ((1<<SIZE_OP)-1)<<POS_OP;
|
||||
public static final int MASK_A = ((1<<SIZE_A)-1)<<POS_A;
|
||||
public static final int MASK_B = ((1<<SIZE_B)-1)<<POS_B;
|
||||
public static final int MASK_C = ((1<<SIZE_C)-1)<<POS_C;
|
||||
public static final int MASK_Bx = ((1<<SIZE_Bx)-1)<<POS_Bx;
|
||||
|
||||
public static final int MASK_NOT_OP = ~MASK_OP;
|
||||
public static final int MASK_NOT_A = ~MASK_A;
|
||||
public static final int MASK_NOT_B = ~MASK_B;
|
||||
public static final int MASK_NOT_C = ~MASK_C;
|
||||
public static final int MASK_NOT_Bx = ~MASK_Bx;
|
||||
|
||||
/*
|
||||
** the following macros help to manipulate instructions
|
||||
*/
|
||||
public static int GET_OPCODE(int i) {
|
||||
return (i >> POS_OP) & MAX_OP;
|
||||
}
|
||||
|
||||
public static int GETARG_A(int i) {
|
||||
return (i >> POS_A) & MAXARG_A;
|
||||
}
|
||||
|
||||
public static int GETARG_B(int i) {
|
||||
return (i >> POS_B) & MAXARG_B;
|
||||
}
|
||||
|
||||
public static int GETARG_C(int i) {
|
||||
return (i >> POS_C) & MAXARG_C;
|
||||
}
|
||||
|
||||
public static int GETARG_Bx(int i) {
|
||||
return (i >> POS_Bx) & MAXARG_Bx;
|
||||
}
|
||||
|
||||
public static int GETARG_sBx(int i) {
|
||||
return ((i >> POS_Bx) & MAXARG_Bx) - MAXARG_sBx;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Macros to operate RK indices
|
||||
*/
|
||||
|
||||
/** this bit 1 means constant (0 means register) */
|
||||
public static final int BITRK = (1 << (SIZE_B - 1));
|
||||
|
||||
/** test whether value is a constant */
|
||||
public static boolean ISK(int x) {
|
||||
return 0 != ((x) & BITRK);
|
||||
}
|
||||
|
||||
/** gets the index of the constant */
|
||||
public static int INDEXK(int r) {
|
||||
return ((int)(r) & ~BITRK);
|
||||
}
|
||||
|
||||
public static final int MAXINDEXRK = (BITRK - 1);
|
||||
|
||||
/** code a constant index as a RK value */
|
||||
public static int RKASK(int x) {
|
||||
return ((x) | BITRK);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
** invalid register that fits in 8 bits
|
||||
*/
|
||||
public static final int NO_REG = MAXARG_A;
|
||||
|
||||
|
||||
/*
|
||||
** R(x) - register
|
||||
** Kst(x) - constant (in constant table)
|
||||
** RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x)
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
** grep "ORDER OP" if you change these enums
|
||||
*/
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
name args description
|
||||
------------------------------------------------------------------------*/
|
||||
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_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_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_NEWTABLE = 10; /* 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_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_CONCAT = 21; /* A B C R(A) := R(B).. ... ..R(C) */
|
||||
|
||||
public static final int OP_JMP = 22; /* sBx pc+=sBx */
|
||||
|
||||
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 = 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 = 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);
|
||||
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_TFORLOOP = 33; /* 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_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;
|
||||
|
||||
|
||||
|
||||
/*===========================================================================
|
||||
Notes:
|
||||
(*) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1,
|
||||
and can be 0: OP_CALL then sets `top' to last_result+1, so
|
||||
next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use `top'.
|
||||
|
||||
(*) In OP_VARARG, if (B == 0) then use actual number of varargs and
|
||||
set top (like in OP_CALL with C == 0).
|
||||
|
||||
(*) In OP_RETURN, if (B == 0) then return up to `top'
|
||||
|
||||
(*) In OP_SETLIST, if (B == 0) then B = `top';
|
||||
if (C == 0) then next `instruction' is real C
|
||||
|
||||
(*) For comparisons, A specifies what condition the test should accept
|
||||
(true or false).
|
||||
|
||||
(*) All `skips' (pc++) assume that next instruction is a jump
|
||||
===========================================================================*/
|
||||
|
||||
|
||||
/*
|
||||
** masks for instruction properties. The format is:
|
||||
** bits 0-1: op mode
|
||||
** bits 2-3: C arg mode
|
||||
** bits 4-5: B arg mode
|
||||
** bit 6: instruction set register A
|
||||
** bit 7: operator is a test
|
||||
*/
|
||||
|
||||
public static final int OpArgN = 0; /* argument is not used */
|
||||
public static final int OpArgU = 1; /* argument is used */
|
||||
public static final int OpArgR = 2; /* argument is a register or a jump offset */
|
||||
public static final int OpArgK = 3; /* argument is a constant or register/constant */
|
||||
|
||||
public static final int[] luaP_opmodes = {
|
||||
/* 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) | (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_GETUPVAL */
|
||||
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgN<<2) | (iABx), /* OP_GETGLOBAL */
|
||||
(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) | (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 */
|
||||
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgK<<2) | (iABC), /* OP_SELF */
|
||||
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_ADD */
|
||||
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_SUB */
|
||||
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_MUL */
|
||||
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_DIV */
|
||||
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_MOD */
|
||||
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_POW */
|
||||
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iABC), /* OP_UNM */
|
||||
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iABC), /* OP_NOT */
|
||||
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iABC), /* OP_LEN */
|
||||
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgR<<2) | (iABC), /* OP_CONCAT */
|
||||
(0<<7) | (0<<6) | (OpArgR<<4) | (OpArgN<<2) | (iAsBx), /* OP_JMP */
|
||||
(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) | (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) | (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 */
|
||||
};
|
||||
|
||||
public static int getOpMode(int m) {
|
||||
return luaP_opmodes[m] & 3;
|
||||
}
|
||||
public static int getBMode(int m) {
|
||||
return (luaP_opmodes[m] >> 4) & 3;
|
||||
}
|
||||
public static int getCMode(int m) {
|
||||
return (luaP_opmodes[m] >> 2) & 3;
|
||||
}
|
||||
public static boolean testAMode(int m) {
|
||||
return 0 != (luaP_opmodes[m] & (1 << 6));
|
||||
}
|
||||
public static boolean testTMode(int m) {
|
||||
return 0 != (luaP_opmodes[m] & (1 << 7));
|
||||
}
|
||||
|
||||
|
||||
/** opcode names */
|
||||
public static final String[] luaP_opnames = {
|
||||
"MOVE",
|
||||
"LOADK",
|
||||
"LOADBOOL",
|
||||
"LOADNIL",
|
||||
"GETUPVAL",
|
||||
"GETGLOBAL",
|
||||
"GETTABLE",
|
||||
"SETGLOBAL",
|
||||
"SETUPVAL",
|
||||
"SETTABLE",
|
||||
"NEWTABLE",
|
||||
"SELF",
|
||||
"ADD",
|
||||
"SUB",
|
||||
"MUL",
|
||||
"DIV",
|
||||
"MOD",
|
||||
"POW",
|
||||
"UNM",
|
||||
"NOT",
|
||||
"LEN",
|
||||
"CONCAT",
|
||||
"JMP",
|
||||
"EQ",
|
||||
"LT",
|
||||
"LE",
|
||||
"TEST",
|
||||
"TESTSET",
|
||||
"CALL",
|
||||
"TAILCALL",
|
||||
"RETURN",
|
||||
"FORLOOP",
|
||||
"FORPREP",
|
||||
"TFORLOOP",
|
||||
"SETLIST",
|
||||
"CLOSE",
|
||||
"CLOSURE",
|
||||
"VARARG",
|
||||
null,
|
||||
};
|
||||
|
||||
}
|
||||
@@ -25,12 +25,21 @@ import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.StringTokenizer;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import lua.addon.luacompat.LuaCompat;
|
||||
import lua.addon.luajava.LuaJava;
|
||||
import lua.debug.DebugEvent;
|
||||
import lua.debug.DebugEventType;
|
||||
import lua.debug.DebugRequest;
|
||||
import lua.debug.DebugRequestListener;
|
||||
import lua.debug.DebugServer;
|
||||
import lua.debug.DebugResponse;
|
||||
import lua.debug.DebugStackState;
|
||||
import lua.debug.DebugSupport;
|
||||
import lua.debug.DebugUtils;
|
||||
import lua.io.Closure;
|
||||
import lua.io.LoadState;
|
||||
import lua.io.Proto;
|
||||
@@ -54,12 +63,14 @@ import org.apache.commons.cli.ParseException;
|
||||
public class LuaJVM implements DebugRequestListener {
|
||||
protected Options options = new Options();
|
||||
protected boolean isDebugMode = false;
|
||||
protected DebugServer debugServer;
|
||||
protected DebugSupport debugSupport;
|
||||
protected int requestPort;
|
||||
protected int eventPort;
|
||||
protected String script;
|
||||
protected String[] scriptArgs;
|
||||
protected DebugStackState state;
|
||||
protected StackState state;
|
||||
protected boolean isReady = false;
|
||||
protected boolean isTerminated = false;
|
||||
|
||||
@SuppressWarnings("static-access")
|
||||
public LuaJVM() {
|
||||
@@ -107,15 +118,18 @@ public class LuaJVM implements DebugRequestListener {
|
||||
|
||||
if (line.hasOption("file")) {
|
||||
String[] fileArgs = line.getOptionValues("file");
|
||||
this.script = fileArgs[0];
|
||||
this.script = URLDecoder.decode(fileArgs[0], "UTF-8");
|
||||
DebugUtils.println("Lua script to run: " + this.script);
|
||||
this.scriptArgs = new String[fileArgs.length - 1];
|
||||
for (int i = 1; i < fileArgs.length; i++) {
|
||||
this.scriptArgs[i-1] = fileArgs[i];
|
||||
this.scriptArgs[i-1] = URLDecoder.decode(fileArgs[i], "UTF-8");
|
||||
}
|
||||
}
|
||||
} catch(NumberFormatException e) {
|
||||
throw new ParseException("Invalid port number: " + e.getMessage());
|
||||
}
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new ParseException("Malformed program argument strings: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isDebug() {
|
||||
@@ -144,16 +158,28 @@ public class LuaJVM implements DebugRequestListener {
|
||||
|
||||
public void run() throws IOException {
|
||||
if (isDebug()) {
|
||||
setupDebugHooks(getRequestPort(), getEventPort());
|
||||
doDebug();
|
||||
} else {
|
||||
doRun();
|
||||
}
|
||||
|
||||
// TODO: VM hook for debugging
|
||||
}
|
||||
|
||||
protected void init() {
|
||||
// reset global states
|
||||
GlobalState.resetGlobals();
|
||||
|
||||
// add LuaJava bindings
|
||||
LuaJava.install();
|
||||
|
||||
// add LuaCompat bindings
|
||||
LuaCompat.install();
|
||||
}
|
||||
|
||||
public void doRun() throws IOException {
|
||||
init();
|
||||
|
||||
// new lua state
|
||||
state = new DebugStackState();
|
||||
state = new StackState();
|
||||
|
||||
// convert args to lua
|
||||
int numOfScriptArgs = getScriptArgs().length;
|
||||
@@ -163,33 +189,99 @@ public class LuaJVM implements DebugRequestListener {
|
||||
}
|
||||
|
||||
// load the Lua file
|
||||
System.out.println("loading Lua script '" + getScript() + "'");
|
||||
DebugUtils.println("loading Lua script '" + getScript() + "'");
|
||||
InputStream is = new FileInputStream(new File(getScript()));
|
||||
Proto p = LoadState.undump(state, is, getScript());
|
||||
|
||||
// create closure and execute
|
||||
Closure c = new Closure(state, p);
|
||||
state.doCall(c, vargs);
|
||||
state.doCall(c, vargs);
|
||||
}
|
||||
|
||||
protected void setupDebugHooks(int requestPort, int eventPort)
|
||||
throws IOException {
|
||||
this.debugServer = new DebugServer(this, requestPort, eventPort);
|
||||
this.debugServer.start();
|
||||
private void doDebug() throws IOException {
|
||||
DebugUtils.println("start debugging...");
|
||||
this.debugSupport = new DebugSupport(this, getRequestPort(), getEventPort());
|
||||
DebugUtils.println("created client request socket connection...");
|
||||
debugSupport.start();
|
||||
|
||||
DebugUtils.println("setting up LuaJava and debug stack state...");
|
||||
|
||||
init();
|
||||
|
||||
// new lua state
|
||||
state = new DebugStackState();
|
||||
getDebugState().addDebugEventListener(debugSupport);
|
||||
|
||||
// load the Lua file
|
||||
DebugUtils.println("loading Lua script '" + getScript() + "'");
|
||||
InputStream is = new FileInputStream(new File(getScript()));
|
||||
Proto p = LoadState.undump(state, is, getScript());
|
||||
|
||||
// create closure and execute
|
||||
final Closure c = new Closure(state, p);
|
||||
getDebugState().suspend();
|
||||
|
||||
new Thread(new Runnable() {
|
||||
public void run() {
|
||||
int numOfScriptArgs = getScriptArgs().length;
|
||||
LValue[] vargs = new LValue[numOfScriptArgs];
|
||||
for (int i = 0; i < numOfScriptArgs; i++) {
|
||||
vargs[i] = new LString(getScriptArgs()[i]);
|
||||
}
|
||||
|
||||
getDebugState().doCall(c, vargs);
|
||||
stop();
|
||||
}
|
||||
}).start();
|
||||
|
||||
debugSupport.fireEvent(new DebugEvent(DebugEventType.started));
|
||||
}
|
||||
|
||||
private DebugStackState getDebugState() {
|
||||
return (DebugStackState)state;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see lua.debug.DebugRequestListener#handleRequest(java.lang.String)
|
||||
*/
|
||||
public String handleRequest(String request) {
|
||||
return state.handleRequest( request );
|
||||
public DebugResponse handleRequest(DebugRequest request) {
|
||||
if (!isDebug()) {
|
||||
throw new UnsupportedOperationException("Must be in debug mode to handle the debug requests");
|
||||
}
|
||||
|
||||
DebugUtils.println("handling request: " + request.toString());
|
||||
switch (request.getType()) {
|
||||
case suspend:
|
||||
DebugResponse status = getDebugState().handleRequest(request);
|
||||
DebugEvent event = new DebugEvent(DebugEventType.suspendedByClient);
|
||||
debugSupport.fireEvent(event);
|
||||
return status;
|
||||
case resume:
|
||||
status = getDebugState().handleRequest(request);
|
||||
event = new DebugEvent(DebugEventType.resumedByClient);
|
||||
debugSupport.fireEvent(event);
|
||||
return status;
|
||||
case exit:
|
||||
stop();
|
||||
default:
|
||||
return getDebugState().handleRequest(request);
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (this.debugServer != null) {
|
||||
this.debugServer.stop();
|
||||
this.debugServer = null;
|
||||
protected void stop() {
|
||||
DebugUtils.println("exit LuaJ VM...");
|
||||
if (this.debugSupport != null) {
|
||||
DebugEvent event = new DebugEvent(DebugEventType.terminated);
|
||||
debugSupport.fireEvent(event);
|
||||
Timer timer = new Timer("DebugServerDeathThread");
|
||||
timer.schedule(new TimerTask() {
|
||||
public void run() {
|
||||
debugSupport.stop();
|
||||
debugSupport = null;
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
getDebugState().exit();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -198,18 +290,22 @@ public class LuaJVM implements DebugRequestListener {
|
||||
* [-debug requestPort eventPort] -file luaProgram args
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void main(String[] args) throws IOException {
|
||||
public static void main(String[] args) {
|
||||
LuaJVM vm = new LuaJVM();
|
||||
|
||||
try {
|
||||
vm.parse(args);
|
||||
} catch (ParseException e) {
|
||||
System.out.println(e.getMessage());
|
||||
System.out.println();
|
||||
DebugUtils.println(e.getMessage());
|
||||
vm.printUsage();
|
||||
return;
|
||||
}
|
||||
|
||||
vm.run();
|
||||
try {
|
||||
vm.run();
|
||||
} catch (IOException e) {
|
||||
//TODO: handle the error
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,197 +0,0 @@
|
||||
package lua;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import lua.io.Closure;
|
||||
import lua.value.LNil;
|
||||
import lua.value.LString;
|
||||
import lua.value.LValue;
|
||||
|
||||
public interface VM {
|
||||
|
||||
// ================ interfaces for performing calls
|
||||
|
||||
/** Push an argument or return value onto the stack
|
||||
*/
|
||||
public void push( LValue value );
|
||||
|
||||
/** Push an int argument or return value onto the stack
|
||||
*/
|
||||
public void push( int value );
|
||||
|
||||
/** Push a double argument or return value onto the stack
|
||||
*/
|
||||
public void push( double value );
|
||||
|
||||
/** Push a boolean argument or return value onto the stack
|
||||
*/
|
||||
public void push( boolean value );
|
||||
|
||||
/** Push a String argument or return value onto the stack
|
||||
*/
|
||||
public void push( String value );
|
||||
|
||||
/**
|
||||
* Create a call frame for a call that has been set up on
|
||||
* the stack. The first value on the stack must be a Closure,
|
||||
* and subsequent values are arguments to the closure.
|
||||
*/
|
||||
public void prepStackCall();
|
||||
|
||||
/**
|
||||
* Execute bytecodes until the current call completes
|
||||
* or the vm yields.
|
||||
*/
|
||||
public void execute();
|
||||
|
||||
/**
|
||||
* Put the closure on the stack with arguments,
|
||||
* then perform the call. Leave return values
|
||||
* on the stack for later querying.
|
||||
*
|
||||
* @param c
|
||||
* @param values
|
||||
*/
|
||||
public void doCall(Closure c, LValue[] values);
|
||||
|
||||
/**
|
||||
* Set the number of results that are expected from the function being called.
|
||||
* (This should be called before prepStackCall)
|
||||
*/
|
||||
public void setExpectedResultCount( int nresults );
|
||||
|
||||
/**
|
||||
* Returns the number of results that are expected by the calling function,
|
||||
* or -1 if the calling function can accept a variable number of results.
|
||||
*/
|
||||
public int getExpectedResultCount();
|
||||
|
||||
/**
|
||||
* Adjust the stack to contain the expected number of results by adjusting
|
||||
* the top.
|
||||
*/
|
||||
public void adjustResults();
|
||||
|
||||
// ================ interfaces for getting arguments when called
|
||||
|
||||
/**
|
||||
* Get the number of argumnets supplied in the call.
|
||||
*/
|
||||
public int getArgCount();
|
||||
|
||||
/**
|
||||
* Get the index-th argument supplied, or NIL if fewer than index were supplied.
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
public LValue getArg(int index);
|
||||
|
||||
/**
|
||||
* Get the index-th argument as an int value, or 0 if fewer than index arguments were supplied.
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
public int getArgAsInt( int index );
|
||||
|
||||
/**
|
||||
* Get the index-th argument as a double value, or 0 if fewer than index arguments were supplied.
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
public double getArgAsDouble( int index );
|
||||
|
||||
/**
|
||||
* Get the index-th argument as a boolean value, or false if fewer than index arguments were supplied.
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
public boolean getArgAsBoolean( int index );
|
||||
|
||||
/**
|
||||
* Get the index-th argument as a String value, or "" if fewer than index arguments were supplied.
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
public String getArgAsString( int index );
|
||||
|
||||
/**
|
||||
* Get the index-th argument as an LString value, or "" if fewer than index arguments were supplied.
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
public LString getArgAsLuaString( int index );
|
||||
|
||||
/** Set top to base in preparation for pushing return values.
|
||||
* Can be used when returning no values.
|
||||
*
|
||||
* Once this is called, calls to getArg() are undefined.
|
||||
*
|
||||
* @see push() to push additional results once result is reset.
|
||||
*/
|
||||
public void setResult();
|
||||
|
||||
/** Convenience utility to set val to stack[base] and top to base + 1
|
||||
* in preparation for returning one value
|
||||
*
|
||||
* Once this is called, calls to getArg() are undefined.
|
||||
*
|
||||
* @param val value to provide as the only result.
|
||||
*/
|
||||
public void setResult(LValue val);
|
||||
|
||||
|
||||
/**
|
||||
* Set up an error result on the stack.
|
||||
* @param value the LValue to return as the first return value
|
||||
* @param message the String error message to supply
|
||||
*/
|
||||
public void setErrorResult(LValue value, String message);
|
||||
|
||||
// ====================== lua Java API =======================
|
||||
|
||||
/**
|
||||
* Raises an error. The message is pushed onto the stack and used as the error message.
|
||||
* It also adds at the beginning of the message the file name and the line number where
|
||||
* the error occurred, if this information is available.
|
||||
*
|
||||
* In the java implementation this throws a RuntimeException, possibly filling
|
||||
* line number information first.
|
||||
*/
|
||||
public void lua_error(String message);
|
||||
|
||||
/**
|
||||
* Run the method on the stack, propagating any error that occurs.
|
||||
* @param nArgs number of arguments on the stack
|
||||
* @param nResults number of results on the stack
|
||||
*/
|
||||
public void lua_call(int nArgs, int nResults);
|
||||
|
||||
/**
|
||||
* Run the method on the stack in protected mode.
|
||||
* @param nArgs number of arguments on the stack
|
||||
* @param nResults number of results on the stack
|
||||
* @return 0 if successful, LUA_ERRMEM if no memory, LUA_ERRRUN for any other error
|
||||
*/
|
||||
public int lua_pcall(int nArgs, int nResults);
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param is InputStream providing the data to be loaded
|
||||
* @param chunkname Name of the chunk to be used in debugging
|
||||
* @return 0 if successful, LUA_ERRMEM if no memory, LUA_ERRSYNTAX for i/o or any other errors
|
||||
*/
|
||||
public int lua_load( InputStream is, String chunkname );
|
||||
|
||||
/**
|
||||
* Get a value on the stack, relative to the top or bottom
|
||||
* @param i index from bottom if 0 or greater, index from top if less than 0
|
||||
* @return
|
||||
*/
|
||||
public LValue lua_tolvalue(int i);
|
||||
|
||||
/**
|
||||
* Pop some number of items off the stack.
|
||||
*/
|
||||
public void lua_pop(int n);
|
||||
}
|
||||
30
src/main/java/lua/debug/AbortException.java
Normal file
30
src/main/java/lua/debug/AbortException.java
Normal file
@@ -0,0 +1,30 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2007 LuaJ. 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 lua.debug;
|
||||
|
||||
public class AbortException extends RuntimeException {
|
||||
private static final long serialVersionUID = 8043724992294286647L;
|
||||
|
||||
public AbortException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
50
src/main/java/lua/debug/DebugEvent.java
Normal file
50
src/main/java/lua/debug/DebugEvent.java
Normal file
@@ -0,0 +1,50 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2007 LuaJ. 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 lua.debug;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class DebugEvent implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -6167781055176807311L;
|
||||
protected DebugEventType type;
|
||||
|
||||
public DebugEvent(DebugEventType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public DebugEventType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(DebugEventType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return type.toString();
|
||||
}
|
||||
}
|
||||
50
src/main/java/lua/debug/DebugEventBreakpoint.java
Normal file
50
src/main/java/lua/debug/DebugEventBreakpoint.java
Normal file
@@ -0,0 +1,50 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2007 LuaJ. 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 lua.debug;
|
||||
|
||||
public class DebugEventBreakpoint extends DebugEvent {
|
||||
private static final long serialVersionUID = -7573362646669094458L;
|
||||
protected String source;
|
||||
protected int lineNumber;
|
||||
|
||||
public DebugEventBreakpoint(String source, int lineNumber) {
|
||||
super(DebugEventType.suspendedOnBreakpoint);
|
||||
this.source = source;
|
||||
this.lineNumber = lineNumber;
|
||||
}
|
||||
|
||||
public String getSource() {
|
||||
return this.source;
|
||||
}
|
||||
|
||||
public int getLineNumber() {
|
||||
return this.lineNumber;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see lua.debug.DebugEvent#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + " source:" + getSource() + " line:" + getLineNumber();
|
||||
}
|
||||
}
|
||||
44
src/main/java/lua/debug/DebugEventError.java
Normal file
44
src/main/java/lua/debug/DebugEventError.java
Normal file
@@ -0,0 +1,44 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2007 LuaJ. 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 lua.debug;
|
||||
|
||||
public class DebugEventError extends DebugEvent {
|
||||
private static final long serialVersionUID = -7911842790951966147L;
|
||||
protected String detail;
|
||||
|
||||
public DebugEventError(String detail) {
|
||||
super(DebugEventType.error);
|
||||
this.detail = detail;
|
||||
}
|
||||
|
||||
public String getDetail() {
|
||||
return this.detail;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see lua.debug.DebugEvent#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + " detail: " + getDetail();
|
||||
}
|
||||
}
|
||||
26
src/main/java/lua/debug/DebugEventListener.java
Normal file
26
src/main/java/lua/debug/DebugEventListener.java
Normal file
@@ -0,0 +1,26 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2007 LuaJ. 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 lua.debug;
|
||||
|
||||
public interface DebugEventListener {
|
||||
public void notifyDebugEvent(DebugEvent event);
|
||||
}
|
||||
30
src/main/java/lua/debug/DebugEventStepping.java
Normal file
30
src/main/java/lua/debug/DebugEventStepping.java
Normal file
@@ -0,0 +1,30 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2007 LuaJ. 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 lua.debug;
|
||||
|
||||
public class DebugEventStepping extends DebugEvent {
|
||||
private static final long serialVersionUID = 3902898567880012107L;
|
||||
|
||||
public DebugEventStepping() {
|
||||
super(DebugEventType.suspendedOnStepping);
|
||||
}
|
||||
}
|
||||
36
src/main/java/lua/debug/DebugEventType.java
Normal file
36
src/main/java/lua/debug/DebugEventType.java
Normal file
@@ -0,0 +1,36 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2007 LuaJ. 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 lua.debug;
|
||||
|
||||
public enum DebugEventType {
|
||||
started,
|
||||
suspendedByClient,
|
||||
suspendedOnBreakpoint,
|
||||
suspendedOnWatchpoint,
|
||||
suspendedOnStepping,
|
||||
suspendedOnError,
|
||||
resumedByClient,
|
||||
resumedOnStepping,
|
||||
resumedOnError,
|
||||
error,
|
||||
terminated
|
||||
}
|
||||
45
src/main/java/lua/debug/DebugRequest.java
Normal file
45
src/main/java/lua/debug/DebugRequest.java
Normal file
@@ -0,0 +1,45 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2007 LuaJ. 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 lua.debug;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class DebugRequest implements Serializable {
|
||||
private static final long serialVersionUID = 2741129244733000595L;
|
||||
protected DebugRequestType type;
|
||||
|
||||
public DebugRequest(DebugRequestType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public DebugRequestType getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return type.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2007 LuaJ. 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 lua.debug;
|
||||
|
||||
public class DebugRequestLineBreakpointToggle extends DebugRequest {
|
||||
private static final long serialVersionUID = -3954500569399285372L;
|
||||
protected String source;
|
||||
protected int lineNumber;
|
||||
|
||||
public DebugRequestLineBreakpointToggle(DebugRequestType type, String source, int lineNumber) {
|
||||
super(type);
|
||||
if (lineNumber < 0) {
|
||||
throw new IllegalArgumentException("lineNumber must be equal to greater than zero");
|
||||
}
|
||||
this.source = source;
|
||||
this.lineNumber = lineNumber;
|
||||
}
|
||||
|
||||
public int getLineNumber() {
|
||||
return this.lineNumber;
|
||||
}
|
||||
|
||||
public String getSource() {
|
||||
return this.source;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see lua.debug.DebugRequest#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + " Source:" + getSource() + " lineNumber:" + getLineNumber();
|
||||
}
|
||||
}
|
||||
@@ -21,12 +21,6 @@
|
||||
******************************************************************************/
|
||||
package lua.debug;
|
||||
|
||||
/**
|
||||
* <code>DebugRequestListener</code> handles debugging requests.
|
||||
*
|
||||
* @author: Shu Lei
|
||||
* @version: 1.0
|
||||
*/
|
||||
public interface DebugRequestListener {
|
||||
|
||||
/**
|
||||
@@ -40,10 +34,7 @@ public interface DebugRequestListener {
|
||||
* old to new, include information about file, method, etc.)
|
||||
* stack -- return the content of the current stack frame,
|
||||
* listing the (variable, value) pairs
|
||||
* step -- single step forward (go to next statement)
|
||||
* variable N M
|
||||
* -- return the value of variable M from the stack frame N
|
||||
* (stack frames are indexed from 0)
|
||||
* step -- single step forward (go to next statement)
|
||||
*/
|
||||
public String handleRequest(String request);
|
||||
public DebugResponse handleRequest(DebugRequest request);
|
||||
}
|
||||
|
||||
44
src/main/java/lua/debug/DebugRequestStack.java
Normal file
44
src/main/java/lua/debug/DebugRequestStack.java
Normal file
@@ -0,0 +1,44 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2007 LuaJ. 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 lua.debug;
|
||||
|
||||
public class DebugRequestStack extends DebugRequest {
|
||||
private static final long serialVersionUID = 6270383432060791307L;
|
||||
protected int index;
|
||||
|
||||
public DebugRequestStack(int index) {
|
||||
super(DebugRequestType.stack);
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return this.index;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see lua.debug.DebugRequest#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + " stack frame:" + getIndex();
|
||||
}
|
||||
}
|
||||
35
src/main/java/lua/debug/DebugRequestType.java
Normal file
35
src/main/java/lua/debug/DebugRequestType.java
Normal file
@@ -0,0 +1,35 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2007 LuaJ. 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 lua.debug;
|
||||
|
||||
public enum DebugRequestType {
|
||||
suspend,
|
||||
resume,
|
||||
exit,
|
||||
lineBreakpointSet,
|
||||
lineBreakpointClear,
|
||||
watchpointSet,
|
||||
watchpointClear,
|
||||
callgraph,
|
||||
stack,
|
||||
step
|
||||
}
|
||||
60
src/main/java/lua/debug/DebugRequestWatchpointToggle.java
Normal file
60
src/main/java/lua/debug/DebugRequestWatchpointToggle.java
Normal file
@@ -0,0 +1,60 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2007 LuaJ. 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 lua.debug;
|
||||
|
||||
public class DebugRequestWatchpointToggle extends DebugRequest {
|
||||
private static final long serialVersionUID = -2978341358052851046L;
|
||||
|
||||
public enum AccessType {
|
||||
Ignore,
|
||||
Read,
|
||||
Modify,
|
||||
ReadAndModify
|
||||
};
|
||||
|
||||
protected String functionName;
|
||||
protected String variableName;
|
||||
|
||||
public DebugRequestWatchpointToggle(String functionName,
|
||||
String variableName,
|
||||
AccessType accessType) {
|
||||
super(accessType == AccessType.Ignore ? DebugRequestType.watchpointClear : DebugRequestType.watchpointSet);
|
||||
this.functionName = functionName;
|
||||
this.variableName = variableName;
|
||||
}
|
||||
|
||||
public String getFunctionName() {
|
||||
return this.functionName;
|
||||
}
|
||||
|
||||
public String getVariableName() {
|
||||
return this.variableName;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see lua.debug.DebugRequest#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + " functionName:" + getFunctionName() + " variableName:" + getVariableName();
|
||||
}
|
||||
}
|
||||
24
src/main/java/lua/debug/DebugResponse.java
Normal file
24
src/main/java/lua/debug/DebugResponse.java
Normal file
@@ -0,0 +1,24 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2007 LuaJ. 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 lua.debug;
|
||||
|
||||
public interface DebugResponse {}
|
||||
51
src/main/java/lua/debug/DebugResponseCallgraph.java
Normal file
51
src/main/java/lua/debug/DebugResponseCallgraph.java
Normal file
@@ -0,0 +1,51 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2007 LuaJ. 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 lua.debug;
|
||||
|
||||
public class DebugResponseCallgraph extends DebugResponseSimple {
|
||||
private static final long serialVersionUID = -7761865402188853413L;
|
||||
protected StackFrame[] stackFrames;
|
||||
|
||||
public DebugResponseCallgraph(StackFrame[] callgraph) {
|
||||
super(true);
|
||||
this.stackFrames = callgraph;
|
||||
}
|
||||
|
||||
public StackFrame[] getCallgraph() {
|
||||
return this.stackFrames;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
if (this.stackFrames != null) {
|
||||
for (StackFrame frame : stackFrames) {
|
||||
buffer.append(frame.toString());
|
||||
buffer.append("\n");
|
||||
}
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
49
src/main/java/lua/debug/DebugResponseSimple.java
Normal file
49
src/main/java/lua/debug/DebugResponseSimple.java
Normal file
@@ -0,0 +1,49 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2007 LuaJ. 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 lua.debug;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class DebugResponseSimple implements DebugResponse, Serializable {
|
||||
private static final long serialVersionUID = 7042417813840650230L;
|
||||
|
||||
protected boolean isSuccessful;
|
||||
|
||||
public static final DebugResponseSimple SUCCESS = new DebugResponseSimple(true);
|
||||
public static final DebugResponseSimple FAILURE = new DebugResponseSimple(false);
|
||||
|
||||
public DebugResponseSimple(boolean isSuccessful) {
|
||||
this.isSuccessful = isSuccessful;
|
||||
}
|
||||
|
||||
public boolean isSuccessful() {
|
||||
return this.isSuccessful;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.valueOf(isSuccessful);
|
||||
}
|
||||
}
|
||||
48
src/main/java/lua/debug/DebugResponseStack.java
Normal file
48
src/main/java/lua/debug/DebugResponseStack.java
Normal file
@@ -0,0 +1,48 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2007 LuaJ. 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 lua.debug;
|
||||
|
||||
public class DebugResponseStack extends DebugResponseSimple {
|
||||
private static final long serialVersionUID = -2108425321162834731L;
|
||||
protected Variable[] variables;
|
||||
|
||||
public DebugResponseStack(Variable[] variables) {
|
||||
super(true);
|
||||
this.variables = variables;
|
||||
}
|
||||
|
||||
public Variable[] getVariables() {
|
||||
return this.variables;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
for (int i = 0; variables != null && i < variables.length; i++) {
|
||||
buffer.append("\t" + variables[i].getName() + ":" + variables[i].getIndex() + "\n");
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,75 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2007 LuaJ. 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 lua.debug;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.Set;
|
||||
|
||||
import lua.CallInfo;
|
||||
import lua.StackState;
|
||||
import lua.addon.compile.LexState;
|
||||
import lua.io.LocVars;
|
||||
import lua.io.Proto;
|
||||
import lua.value.LTable;
|
||||
import lua.value.LValue;
|
||||
import lua.value.Type;
|
||||
|
||||
public class DebugStackState extends StackState implements DebugRequestListener {
|
||||
|
||||
public Map<Integer,Boolean> breakpoints = new HashMap<Integer,Boolean>();
|
||||
private boolean exiting = false;
|
||||
private boolean suspended = false;
|
||||
private boolean stepping = false;
|
||||
private int lastline = -1;
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
protected Map<String,Boolean> breakpoints = new HashMap<String,Boolean>();
|
||||
protected boolean exiting = false;
|
||||
protected boolean suspended = false;
|
||||
protected boolean stepping = false;
|
||||
protected int lastline = -1;
|
||||
protected List<DebugEventListener> debugEventListeners
|
||||
= new ArrayList<DebugEventListener>();
|
||||
|
||||
public DebugStackState() {
|
||||
}
|
||||
|
||||
public void addDebugEventListener(DebugEventListener listener) {
|
||||
if (!debugEventListeners.contains(listener)) {
|
||||
debugEventListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeDebugEventListener(DebugEventListener listener) {
|
||||
if (debugEventListeners.contains(listener)) {
|
||||
debugEventListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
protected void notifyDebugEventListeners(DebugEvent event) {
|
||||
for (DebugEventListener listener : debugEventListeners) {
|
||||
listener.notifyDebugEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
private String getFileLine(int cindex) {
|
||||
String func = "?";
|
||||
String line = "?";
|
||||
@@ -29,119 +79,136 @@ public class DebugStackState extends StackState implements DebugRequestListener
|
||||
Proto p = call.closure.p;
|
||||
if ( p != null && p.source != null )
|
||||
source = p.source.toJavaString();
|
||||
if ( p.lineinfo != null && p.lineinfo.length > call.pc-1 )
|
||||
line = String.valueOf( p.lineinfo[call.pc-1] );
|
||||
if ( p.lineinfo != null && p.lineinfo.length > call.pc )
|
||||
line = String.valueOf( p.lineinfo[call.pc] );
|
||||
// TODO: reverse lookup on function name ????
|
||||
func = call.closure.luaAsString().toJavaString();
|
||||
}
|
||||
return source+":"+line+"("+func+")";
|
||||
}
|
||||
|
||||
private String addLineInfo( String message ) {
|
||||
return getFileLine(cc)+": "+message;
|
||||
}
|
||||
|
||||
private void printLuaTrace(String message) {
|
||||
System.out.println( "Lua error: "+addLineInfo( message ) );
|
||||
for ( int cindex=cc-1; cindex>=0; cindex-- )
|
||||
System.out.println( "\tcalled by "+getFileLine( cindex ) );
|
||||
}
|
||||
|
||||
protected void debugPcallError(Throwable t) {
|
||||
System.out.println(addLineInfo("(caught in pcall) "+t.getMessage()));
|
||||
System.out.flush();
|
||||
}
|
||||
|
||||
// override and fill in line number info
|
||||
public void lua_error(String message) {
|
||||
throw new RuntimeException( message );
|
||||
super.lua_error( getFileLine(cc)+": "+message );
|
||||
}
|
||||
|
||||
private void printLuaTrace() {
|
||||
System.out.println( "Lua location: "+getFileLine(cc) );
|
||||
for ( int cindex=cc-1; cindex>=0; cindex-- )
|
||||
System.out.println( "\tin "+getFileLine( cindex ) );
|
||||
}
|
||||
|
||||
// intercept exceptions and fill in line numbers
|
||||
public void exec() {
|
||||
try {
|
||||
super.exec();
|
||||
} catch ( RuntimeException t ) {
|
||||
t.printStackTrace();
|
||||
printLuaTrace(t.getMessage());
|
||||
} catch (AbortException e) {
|
||||
// ignored. Client aborts the debugging session.
|
||||
} catch ( Exception t ) {
|
||||
t.printStackTrace();
|
||||
printLuaTrace();
|
||||
System.out.flush();
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// debug hooks
|
||||
public void debugHooks( int pc ) {
|
||||
DebugUtils.println("entered debugHook...");
|
||||
|
||||
if ( exiting )
|
||||
throw new java.lang.RuntimeException("exiting");
|
||||
throw new AbortException("exiting");
|
||||
|
||||
// make sure line numbers are current in any stack traces
|
||||
calls[cc].pc = pc;
|
||||
|
||||
synchronized ( this ) {
|
||||
|
||||
|
||||
// anytime the line doesn't change we keep going
|
||||
int[] li = calls[cc].closure.p.lineinfo;
|
||||
int line = (li!=null && li.length>pc? li[pc]: -1);
|
||||
if ( lastline == line )
|
||||
int line = getLineNumber(calls[cc]);
|
||||
DebugUtils.println("debugHook - executing line: " + line);
|
||||
if ( !stepping && lastline == line ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// save line in case next op is a step
|
||||
lastline = line;
|
||||
if ( stepping )
|
||||
stepping = false;
|
||||
|
||||
// check for a break point if we aren't suspended already
|
||||
if ( ! suspended ) {
|
||||
if ( breakpoints.containsKey(line) )
|
||||
suspended = true;
|
||||
else
|
||||
return;
|
||||
|
||||
if ( stepping ) {
|
||||
DebugUtils.println("suspended by stepping at pc=" + pc);
|
||||
notifyDebugEventListeners(new DebugEventStepping());
|
||||
suspended = true;
|
||||
} else if ( !suspended ) {
|
||||
// check for a break point if we aren't suspended already
|
||||
Proto p = calls[cc].closure.p;
|
||||
String source = DebugUtils.getSourceFileName(p.source);
|
||||
if ( breakpoints.containsKey(constructBreakpointKey(source, line))){
|
||||
DebugUtils.println("hitting breakpoint " + constructBreakpointKey(source, line));
|
||||
notifyDebugEventListeners(
|
||||
new DebugEventBreakpoint(source, line));
|
||||
suspended = true;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// wait for a state change
|
||||
while ( suspended && (!exiting) && (!stepping) ) {
|
||||
while (suspended && !exiting ) {
|
||||
try {
|
||||
this.wait();
|
||||
DebugUtils.println("resuming execution...");
|
||||
} catch ( InterruptedException ie ) {
|
||||
ie.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------ commands coming from the debugger -------------------
|
||||
|
||||
public enum RequestType {
|
||||
suspend,
|
||||
resume,
|
||||
exit,
|
||||
set,
|
||||
clear,
|
||||
callgraph,
|
||||
stack,
|
||||
step,
|
||||
variable,
|
||||
|
||||
/**
|
||||
* Get the current line number
|
||||
* @param pc program counter
|
||||
* @return the line number corresponding to the pc
|
||||
*/
|
||||
private int getLineNumber(CallInfo ci) {
|
||||
int[] lineNumbers = ci.closure.p.lineinfo;
|
||||
int pc = ci.pc;
|
||||
int line = (lineNumbers != null && lineNumbers.length > pc ? lineNumbers[pc] : -1);
|
||||
return line;
|
||||
}
|
||||
|
||||
// ------------------ commands coming from the debugger -------------------
|
||||
|
||||
public String handleRequest(String request) {
|
||||
StringTokenizer st = new StringTokenizer( request );
|
||||
String req = st.nextToken();
|
||||
RequestType rt = RequestType.valueOf(req);
|
||||
switch ( rt ) {
|
||||
case suspend: suspend(); return "true";
|
||||
case resume: resume(); return "true";
|
||||
case exit: exit(); return "true";
|
||||
case set: set( Integer.parseInt(st.nextToken()) ); return "true";
|
||||
case clear: clear( Integer.parseInt(st.nextToken()) ); return "true";
|
||||
case callgraph: return callgraph();
|
||||
case stack: return stack();
|
||||
case step: step(); return "true";
|
||||
case variable:
|
||||
String N = st.nextToken();
|
||||
String M = st.nextToken();
|
||||
return variable( Integer.parseInt(N), Integer.parseInt(M) );
|
||||
}
|
||||
throw new java.lang.IllegalArgumentException( "unkown request type: "+req );
|
||||
public DebugResponse handleRequest(DebugRequest request) {
|
||||
DebugUtils.println("DebugStackState is handling request: " + request.toString());
|
||||
switch (request.getType()) {
|
||||
case suspend:
|
||||
suspend();
|
||||
return DebugResponseSimple.SUCCESS;
|
||||
case resume:
|
||||
resume();
|
||||
return DebugResponseSimple.SUCCESS;
|
||||
case exit:
|
||||
exit();
|
||||
return DebugResponseSimple.SUCCESS;
|
||||
case lineBreakpointSet:
|
||||
DebugRequestLineBreakpointToggle setBreakpointRequest
|
||||
= (DebugRequestLineBreakpointToggle)request;
|
||||
setBreakpoint(setBreakpointRequest.getSource(), setBreakpointRequest.getLineNumber());
|
||||
return DebugResponseSimple.SUCCESS;
|
||||
case lineBreakpointClear:
|
||||
DebugRequestLineBreakpointToggle clearBreakpointRequest
|
||||
= (DebugRequestLineBreakpointToggle)request;
|
||||
clearBreakpoint(clearBreakpointRequest.getSource(), clearBreakpointRequest.getLineNumber());
|
||||
return DebugResponseSimple.SUCCESS;
|
||||
case callgraph:
|
||||
return new DebugResponseCallgraph(getCallgraph());
|
||||
case stack:
|
||||
DebugRequestStack stackRequest = (DebugRequestStack) request;
|
||||
int index = stackRequest.getIndex();
|
||||
return new DebugResponseStack(getStack(index));
|
||||
case step:
|
||||
step();
|
||||
return DebugResponseSimple.SUCCESS;
|
||||
}
|
||||
throw new java.lang.IllegalArgumentException( "unkown request type: "+request.getType() );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -155,13 +222,14 @@ public class DebugStackState extends StackState implements DebugRequestListener
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* resume the execution
|
||||
*/
|
||||
public void resume() {
|
||||
synchronized ( this ) {
|
||||
suspended = false;
|
||||
stepping = false;
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
@@ -180,18 +248,24 @@ public class DebugStackState extends StackState implements DebugRequestListener
|
||||
* set breakpoint at line N
|
||||
* @param N the line to set the breakpoint at
|
||||
*/
|
||||
public void set( int N ) {
|
||||
public void setBreakpoint(String source, int lineNumber) {
|
||||
DebugUtils.println("adding breakpoint " + constructBreakpointKey(source, lineNumber));
|
||||
synchronized ( this ) {
|
||||
breakpoints.put( N, Boolean.TRUE );
|
||||
breakpoints.put(constructBreakpointKey(source, lineNumber), Boolean.TRUE );
|
||||
}
|
||||
}
|
||||
|
||||
protected String constructBreakpointKey(String source, int lineNumber) {
|
||||
return source + ":" + lineNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* clear breakpoint at line N
|
||||
* clear breakpoint at line lineNumber of source source
|
||||
*/
|
||||
public void clear( int N ) {
|
||||
public void clearBreakpoint(String source, int lineNumber) {
|
||||
DebugUtils.println("removing breakpoint " + constructBreakpointKey(source, lineNumber));
|
||||
synchronized ( this ) {
|
||||
breakpoints.remove( N );
|
||||
breakpoints.remove(constructBreakpointKey(source, lineNumber));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,36 +273,71 @@ public class DebugStackState extends StackState implements DebugRequestListener
|
||||
* return the current call graph (i.e. stack frames from
|
||||
* old to new, include information about file, method, etc.)
|
||||
*/
|
||||
public String callgraph() {
|
||||
public StackFrame[] getCallgraph() {
|
||||
int n = cc;
|
||||
|
||||
if ( n < 0 || n >= calls.length )
|
||||
return "";
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for ( int i=0; i<=n; i++ ) {
|
||||
return new StackFrame[0];
|
||||
|
||||
StackFrame[] frames = new StackFrame[n+1];
|
||||
for ( int i = 0; i <= n; i++ ) {
|
||||
CallInfo ci = calls[i];
|
||||
// TODO: fill this out with proper format, names, etc.
|
||||
sb.append( String.valueOf(ci.closure.p) );
|
||||
sb.append( "\n" );
|
||||
frames[i] = new StackFrame(ci, getLineNumber(ci));
|
||||
}
|
||||
return sb.toString();
|
||||
return frames;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the content of the current stack frame,
|
||||
* listing the (variable, value) pairs
|
||||
*/
|
||||
public String stack() {
|
||||
CallInfo ci;
|
||||
if ( cc < 0 || cc >= calls.length || (ci=calls[cc]) == null )
|
||||
return "<out of scope>";
|
||||
LocVars[] lv = ci.closure.p.locvars;
|
||||
int n = (lv != null? lv.length: 0);
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
// TODO: figure out format
|
||||
sb.append( "(" + lv[i].varname + "," + super.stack[ci.base+i] + ")\n" );
|
||||
}
|
||||
return sb.toString();
|
||||
public Variable[] getStack(int index) {
|
||||
if (index < 0 || index >= calls.length) {
|
||||
//TODO: this is an error, handle it differently
|
||||
return new Variable[0];
|
||||
}
|
||||
|
||||
CallInfo callInfo = calls[index];
|
||||
DebugUtils.println("Stack Frame: " + index + "[" + callInfo.base + "," + callInfo.top + "]");
|
||||
int top = callInfo.top < callInfo.base ? callInfo.base : callInfo.top;
|
||||
Proto prototype = callInfo.closure.p;
|
||||
LocVars[] localVariables = prototype.locvars;
|
||||
List<Variable> variables = new ArrayList<Variable>();
|
||||
int localVariableCount = 0;
|
||||
Set<String> variablesSeen = new HashSet<String>();
|
||||
for (int i = 0; localVariables != null && i < localVariables.length && i <= top; i++) {
|
||||
String varName = localVariables[i].varname.toString();
|
||||
DebugUtils.print("\tVariable: " + varName);
|
||||
DebugUtils.print("\tValue: " + stack[callInfo.base + i]);
|
||||
if (!variablesSeen.contains(varName) &&
|
||||
!LexState.isReservedKeyword(varName)) {
|
||||
variablesSeen.add(varName);
|
||||
LValue value = stack[callInfo.base + i];
|
||||
if (value != null) {
|
||||
Type type = Type.valueOf(value.luaGetType().toJavaString());
|
||||
DebugUtils.print("\tType: " + type);
|
||||
if (type == Type.table) {
|
||||
DebugUtils.println(" (selected)");
|
||||
variables.add(
|
||||
new TableVariable(localVariableCount++,
|
||||
varName,
|
||||
type,
|
||||
(LTable) value));
|
||||
} else if (type != Type.function &&
|
||||
type != Type.thread) {
|
||||
DebugUtils.println(" (selected)");
|
||||
variables.add(
|
||||
new Variable(localVariableCount++,
|
||||
varName,
|
||||
type,
|
||||
value.toString()));
|
||||
} else {
|
||||
DebugUtils.println("");
|
||||
}
|
||||
} else {
|
||||
DebugUtils.println("");
|
||||
}
|
||||
} else {
|
||||
DebugUtils.println("");
|
||||
}
|
||||
}
|
||||
return (Variable[])variables.toArray(new Variable[0]);
|
||||
}
|
||||
|
||||
|
||||
@@ -237,19 +346,9 @@ public class DebugStackState extends StackState implements DebugRequestListener
|
||||
*/
|
||||
public void step() {
|
||||
synchronized ( this ) {
|
||||
suspended = false;
|
||||
stepping = true;
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return the value of variable M from the stack frame N
|
||||
* (stack frames are indexed from 0)
|
||||
*/
|
||||
public String variable( int N, int M ) {
|
||||
CallInfo ci;
|
||||
if ( M < 0 || M >= calls.length || (ci=calls[M]) == null )
|
||||
return "<out of scope>";
|
||||
return String.valueOf( super.stack[ci.base] );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,21 +21,14 @@
|
||||
******************************************************************************/
|
||||
package lua.debug;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
|
||||
/**
|
||||
* <code>DebugServer</code> manages the communications between LuaJ VM and
|
||||
* the debugging client.
|
||||
*
|
||||
* @author: Shu Lei
|
||||
* @version: <version>
|
||||
*/
|
||||
public class DebugServer {
|
||||
public class DebugSupport implements DebugEventListener {
|
||||
public enum State {
|
||||
UNKNOWN,
|
||||
RUNNING,
|
||||
@@ -50,14 +43,14 @@ public class DebugServer {
|
||||
|
||||
protected ServerSocket requestSocket;
|
||||
protected Socket clientRequestSocket;
|
||||
protected BufferedReader requestReader;
|
||||
protected PrintWriter requestWriter;
|
||||
protected ObjectInputStream requestReader;
|
||||
protected ObjectOutputStream requestWriter;
|
||||
|
||||
protected ServerSocket eventSocket;
|
||||
protected Socket clientEventSocket;
|
||||
protected PrintWriter eventWriter;
|
||||
protected ObjectOutputStream eventWriter;
|
||||
|
||||
public DebugServer(DebugRequestListener listener,
|
||||
public DebugSupport(DebugRequestListener listener,
|
||||
int requestPort,
|
||||
int eventPort) {
|
||||
this.listener = listener;
|
||||
@@ -65,7 +58,8 @@ public class DebugServer {
|
||||
this.eventPort = eventPort;
|
||||
}
|
||||
|
||||
protected void destroy() {
|
||||
protected void releaseServer() {
|
||||
DebugUtils.println("shutting down the debug server...");
|
||||
if (requestReader != null) {
|
||||
try {
|
||||
requestReader.close();
|
||||
@@ -73,7 +67,11 @@ public class DebugServer {
|
||||
}
|
||||
|
||||
if (requestWriter != null) {
|
||||
requestWriter.close();
|
||||
try {
|
||||
requestWriter.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (clientRequestSocket != null) {
|
||||
@@ -89,7 +87,11 @@ public class DebugServer {
|
||||
}
|
||||
|
||||
if (eventWriter != null) {
|
||||
eventWriter.close();
|
||||
try {
|
||||
eventWriter.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (clientEventSocket != null) {
|
||||
@@ -108,20 +110,22 @@ public class DebugServer {
|
||||
public synchronized void start() throws IOException {
|
||||
this.requestSocket = new ServerSocket(requestPort);
|
||||
this.clientRequestSocket = requestSocket.accept();
|
||||
this.requestReader = new BufferedReader(
|
||||
new InputStreamReader(clientRequestSocket.getInputStream()));
|
||||
this.requestWriter = new PrintWriter(clientRequestSocket.getOutputStream());
|
||||
this.requestReader
|
||||
= new ObjectInputStream(clientRequestSocket.getInputStream());
|
||||
this.requestWriter
|
||||
= new ObjectOutputStream(clientRequestSocket.getOutputStream());
|
||||
|
||||
this.eventSocket = new ServerSocket(eventPort);
|
||||
this.clientEventSocket = eventSocket.accept();
|
||||
this.eventWriter = new PrintWriter(clientEventSocket.getOutputStream());
|
||||
this.eventWriter
|
||||
= new ObjectOutputStream(clientEventSocket.getOutputStream());
|
||||
|
||||
this.requestWatcherThread = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
if (getState() != State.STOPPED) {
|
||||
handleRequest();
|
||||
} else {
|
||||
destroy();
|
||||
releaseServer();
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -139,25 +143,39 @@ public class DebugServer {
|
||||
|
||||
public void handleRequest() {
|
||||
synchronized (clientRequestSocket) {
|
||||
String request = null;
|
||||
try {
|
||||
while (getState() != State.STOPPED &&
|
||||
(request = requestReader.readLine()) != null) {
|
||||
System.out.println("SERVER receives request: " + request);
|
||||
String response = listener.handleRequest(request);
|
||||
requestWriter.write(response);
|
||||
while (getState() != State.STOPPED) {
|
||||
DebugRequest request
|
||||
= (DebugRequest) requestReader.readObject();
|
||||
DebugUtils.println("SERVER receives request: " + request.toString());
|
||||
DebugResponse response = listener.handleRequest(request);
|
||||
requestWriter.writeObject(response);
|
||||
requestWriter.flush();
|
||||
DebugUtils.println("SERVER sends response: " + response);
|
||||
}
|
||||
|
||||
if (getState() == State.STOPPED) {
|
||||
destroy();
|
||||
cleanup();
|
||||
}
|
||||
} catch (EOFException e) {
|
||||
cleanup();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private void cleanup() {
|
||||
DebugUtils.println("SERVER terminated...");
|
||||
releaseServer();
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method provides the second communication channel with the debugging
|
||||
* client. The server can send events via this channel to notify the client
|
||||
@@ -175,10 +193,22 @@ public class DebugServer {
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
public void fireEvent(String event) {
|
||||
public void fireEvent(DebugEvent event) {
|
||||
DebugUtils.println("SERVER sending event: " + event.toString());
|
||||
synchronized (eventSocket) {
|
||||
eventWriter.println(event);
|
||||
eventWriter.flush();
|
||||
try {
|
||||
eventWriter.writeObject(event);
|
||||
eventWriter.flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see lua.debug.DebugEventListener#notifyDebugEvent(lua.debug.DebugEvent)
|
||||
*/
|
||||
public void notifyDebugEvent(DebugEvent event) {
|
||||
fireEvent(event);
|
||||
}
|
||||
}
|
||||
54
src/main/java/lua/debug/DebugUtils.java
Normal file
54
src/main/java/lua/debug/DebugUtils.java
Normal file
@@ -0,0 +1,54 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2007 LuaJ. 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 lua.debug;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import lua.io.LoadState;
|
||||
import lua.value.LString;
|
||||
|
||||
public class DebugUtils {
|
||||
public static final boolean IS_DEBUG = false;
|
||||
|
||||
public static void println(String message) {
|
||||
if (IS_DEBUG) {
|
||||
System.out.println(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void print(String message) {
|
||||
if (IS_DEBUG) {
|
||||
System.out.print(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getSourceFileName(LString source) {
|
||||
String sourceStr = source.toJavaString();
|
||||
sourceStr = LoadState.getSourceName(sourceStr);
|
||||
if (!LoadState.SOURCE_BINARY_STRING.equals(sourceStr)) {
|
||||
File sourceFile = new File(sourceStr);
|
||||
return sourceFile.getName();
|
||||
} else {
|
||||
return sourceStr;
|
||||
}
|
||||
}
|
||||
}
|
||||
77
src/main/java/lua/debug/StackFrame.java
Normal file
77
src/main/java/lua/debug/StackFrame.java
Normal file
@@ -0,0 +1,77 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2007 LuaJ. 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.
|
||||
******************************************************************************/
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2007 LuaJ. 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 lua.debug;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import lua.CallInfo;
|
||||
import lua.io.Proto;
|
||||
|
||||
public class StackFrame implements Serializable {
|
||||
private static final long serialVersionUID = 2102834561519501432L;
|
||||
protected int lineNumber;
|
||||
protected String source;
|
||||
|
||||
public StackFrame(CallInfo callInfo, int lineNumber) {
|
||||
Proto prototype = callInfo.closure.p;
|
||||
|
||||
this.lineNumber = lineNumber;
|
||||
this.source = DebugUtils.getSourceFileName(prototype.source);
|
||||
}
|
||||
|
||||
public int getLineNumber() {
|
||||
return this.lineNumber;
|
||||
}
|
||||
|
||||
public String getSource() {
|
||||
return this.source;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return getSource() + ":" + getLineNumber();
|
||||
}
|
||||
}
|
||||
61
src/main/java/lua/debug/TableVariable.java
Normal file
61
src/main/java/lua/debug/TableVariable.java
Normal file
@@ -0,0 +1,61 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2007 LuaJ. 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 lua.debug;
|
||||
|
||||
import lua.value.LTable;
|
||||
import lua.value.LValue;
|
||||
import lua.value.Type;
|
||||
|
||||
public class TableVariable extends Variable {
|
||||
|
||||
private static final long serialVersionUID = 1194778378382802700L;
|
||||
protected String[] keys;
|
||||
protected Object[] values;
|
||||
|
||||
public TableVariable(int index, String name, Type type, LTable table) {
|
||||
super(index, name, type, null);
|
||||
|
||||
int size = table.size();
|
||||
DebugUtils.println("table size:" + size);
|
||||
this.keys = new String[size];
|
||||
this.values = new Object[size];
|
||||
LValue[] keyValues = table.getKeys();
|
||||
for (int i = 0; i < size; i++) {
|
||||
this.keys[i] = keyValues[i].toString();
|
||||
LValue value = table.get(keyValues[i]);
|
||||
if (value instanceof LTable) {
|
||||
this.values[i] = new TableVariable(i, "<table>", Type.table, (LTable)value);
|
||||
} else {
|
||||
this.values[i] = value.toString();
|
||||
}
|
||||
DebugUtils.println("["+ keys[i] + "," + values[i].toString() + "]");
|
||||
}
|
||||
}
|
||||
|
||||
public String[] getKeys() {
|
||||
return this.keys;
|
||||
}
|
||||
|
||||
public Object[] getValues() {
|
||||
return this.values;
|
||||
}
|
||||
}
|
||||
66
src/main/java/lua/debug/Variable.java
Normal file
66
src/main/java/lua/debug/Variable.java
Normal file
@@ -0,0 +1,66 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2007 LuaJ. 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 lua.debug;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import lua.value.Type;
|
||||
|
||||
public class Variable implements Serializable {
|
||||
private static final long serialVersionUID = 8194091816623233934L;
|
||||
|
||||
protected int index;
|
||||
protected String name;
|
||||
protected String value;
|
||||
protected Type type;
|
||||
|
||||
public Variable(int index, String name, Type type, String value) {
|
||||
this.index = index;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return this.index;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "index: " + getIndex() + " name:" + getName() + " type: " + getType() + " value:" + getValue();
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package lua.io;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
import lua.VM;
|
||||
import lua.value.LBoolean;
|
||||
@@ -19,7 +18,10 @@ import lua.value.LValue;
|
||||
*/
|
||||
public class LoadState {
|
||||
|
||||
/** mark for precompiled code (`<esc>Lua') */
|
||||
public static final String SOURCE_BINARY_STRING = "binary string";
|
||||
|
||||
|
||||
/** mark for precompiled code (`<esc>Lua') */
|
||||
public static final String LUA_SIGNATURE = "\033Lua";
|
||||
|
||||
|
||||
@@ -251,17 +253,22 @@ public class LoadState {
|
||||
}
|
||||
|
||||
// load file
|
||||
String sname = name;
|
||||
if ( name.startsWith("@") || name.startsWith("=") )
|
||||
sname = name.substring(1);
|
||||
else if ( name.startsWith("\033") )
|
||||
sname = "binary string";
|
||||
String sname = getSourceName(name);
|
||||
LoadState s = new LoadState( L, stream, sname );
|
||||
s.loadHeader();
|
||||
LString literal = new LString("=?");
|
||||
return s.loadFunction( literal );
|
||||
}
|
||||
|
||||
public static String getSourceName(String name) {
|
||||
String sname = name;
|
||||
if ( name.startsWith("@") || name.startsWith("=") )
|
||||
sname = name.substring(1);
|
||||
else if ( name.startsWith("\033") )
|
||||
sname = SOURCE_BINARY_STRING;
|
||||
return sname;
|
||||
}
|
||||
|
||||
/** Private constructor for create a load state */
|
||||
private LoadState( VM L, InputStream stream, String name ) {
|
||||
this.L = L;
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
package lua.value;
|
||||
|
||||
public final class LBoolean extends LValue {
|
||||
|
||||
public static final LBoolean TRUE = new LBoolean("true",true);
|
||||
|
||||
public static final LBoolean FALSE = new LBoolean("false",false);
|
||||
|
||||
public static final LString TYPE_NAME = new LString("boolean");
|
||||
|
||||
private final LString m_name;
|
||||
private final boolean m_value;
|
||||
|
||||
private LBoolean( String name, boolean value ) {
|
||||
this.m_name = new LString( name );
|
||||
this.m_value = value;
|
||||
}
|
||||
|
||||
public final LString luaAsString() {
|
||||
return m_name;
|
||||
}
|
||||
|
||||
public final boolean luaAsBoolean() {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
public final int luaAsInt() {
|
||||
return m_value? 1: 0;
|
||||
}
|
||||
|
||||
public final static LBoolean valueOf(boolean value) {
|
||||
return value? TRUE: FALSE;
|
||||
}
|
||||
|
||||
public LString luaGetType() {
|
||||
return TYPE_NAME;
|
||||
}
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
package lua.value;
|
||||
|
||||
import lua.Lua;
|
||||
|
||||
public class LDouble extends LNumber {
|
||||
|
||||
private final double m_value;
|
||||
|
||||
public LDouble(double value) {
|
||||
this.m_value = value;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return (int) m_value;
|
||||
}
|
||||
|
||||
public LString luaAsString() {
|
||||
long l = (long) m_value;
|
||||
if ( m_value == (double) l ) {
|
||||
// TODO: is this a good idea?
|
||||
return new LString( Long.toString( l ) );
|
||||
} else {
|
||||
return LString.valueOf( m_value );
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isInteger() {
|
||||
// Cast to int and then back to double and see if the value
|
||||
// survives the round trip.
|
||||
return ( (double) ( (int) m_value ) ) == m_value;
|
||||
}
|
||||
|
||||
// binary operations on integers, first dispatch
|
||||
public LValue luaBinOpUnknown(int opcode, LValue lhs) {
|
||||
return lhs.luaBinOpDouble( opcode, this.m_value );
|
||||
}
|
||||
|
||||
// binary operations on mixtures of doubles and integers
|
||||
public LValue luaBinOpInteger(int opcode, int rhs) {
|
||||
return luaBinOpDoubleDouble( opcode, m_value, (double) rhs );
|
||||
}
|
||||
|
||||
// binary operations on doubles
|
||||
public LValue luaBinOpDouble(int opcode, double rhs) {
|
||||
return luaBinOpDoubleDouble( opcode, m_value, rhs );
|
||||
}
|
||||
|
||||
public static LValue luaBinOpDoubleDouble( int opcode, double lhs, double rhs ) {
|
||||
switch ( opcode ) {
|
||||
case Lua.OP_ADD: return new LDouble( lhs + rhs );
|
||||
case Lua.OP_SUB: return new LDouble( lhs - rhs );
|
||||
case Lua.OP_MUL: return new LDouble( lhs * rhs );
|
||||
case Lua.OP_DIV: return new LDouble( lhs / rhs );
|
||||
case Lua.OP_MOD: return new LDouble( lhs - Math.floor(lhs/rhs) * rhs );
|
||||
// case Lua.OP_POW: return new LDouble( dpow(lhs, rhs) );
|
||||
}
|
||||
return luaUnsupportedOperation();
|
||||
}
|
||||
|
||||
/*
|
||||
public static double dpow(double a, double b) {
|
||||
if ( b < 0 )
|
||||
return 1 / dpow( a, -b );
|
||||
int p = 1;
|
||||
int whole = (int) b;
|
||||
for ( double v=a; whole > 0; whole>>=1, v=v*v )
|
||||
if ( (whole & 1) != 0 )
|
||||
p *= v;
|
||||
int frac = (int) (0x10000 * b);
|
||||
for ( ; (frac&0xffff)!=0; frac<<=1 ) {
|
||||
a = Math.sqrt(a);
|
||||
if ( (frac & 0x8000) != 0 )
|
||||
p *= a;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
public int luaAsInt() {
|
||||
return (int) m_value;
|
||||
}
|
||||
|
||||
public double luaAsDouble() {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
// binary compares on integers, first dispatch
|
||||
public boolean luaBinCmpUnknown(int opcode, LValue lhs) {
|
||||
return lhs.luaBinCmpDouble( opcode, this.m_value );
|
||||
}
|
||||
|
||||
// binary compares on mixtures of doubles and integers
|
||||
public boolean luaBinCmpInteger(int opcode, int rhs) {
|
||||
return luaBinCmpDoubleDouble( opcode, m_value, (double) rhs );
|
||||
}
|
||||
|
||||
// binary compares on doubles
|
||||
public boolean luaBinCmpDouble(int opcode, double rhs) {
|
||||
return luaBinCmpDoubleDouble( opcode, m_value, rhs );
|
||||
}
|
||||
|
||||
// compare two doubles
|
||||
public static boolean luaBinCmpDoubleDouble( int opcode, double lhs, double rhs ) {
|
||||
switch ( opcode ) {
|
||||
case Lua.OP_EQ: return lhs == rhs;
|
||||
case Lua.OP_LT: return lhs < rhs;
|
||||
case Lua.OP_LE: return lhs <= rhs;
|
||||
}
|
||||
luaUnsupportedOperation();
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Arithmetic negative */
|
||||
public LValue luaUnaryMinus() {
|
||||
return new LDouble( -m_value );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package lua.value;
|
||||
|
||||
import lua.VM;
|
||||
|
||||
|
||||
public class LFunction extends LValue {
|
||||
|
||||
public static final LString TYPE_NAME = new LString("function");
|
||||
|
||||
public LString luaAsString() {
|
||||
return new LString( "function: "+hashCode() );
|
||||
}
|
||||
|
||||
public void luaSetTable(VM vm, LValue table, LValue key, LValue val) {
|
||||
vm.push( this );
|
||||
vm.push( table );
|
||||
vm.push( key );
|
||||
vm.push( val );
|
||||
vm.lua_call( 3, 0 );
|
||||
}
|
||||
|
||||
public void luaGetTable(VM vm, LValue table, LValue key) {
|
||||
vm.push( this );
|
||||
vm.push( table );
|
||||
vm.push( key );
|
||||
vm.lua_call( 2, 1 );
|
||||
}
|
||||
|
||||
public LString luaGetType() {
|
||||
return TYPE_NAME;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
package lua.value;
|
||||
|
||||
import lua.Lua;
|
||||
|
||||
public class LInteger extends LNumber {
|
||||
|
||||
private final int m_value;
|
||||
|
||||
public LInteger(int value) {
|
||||
this.m_value = value;
|
||||
}
|
||||
|
||||
public final int hashCode() {
|
||||
return hashCodeOf( m_value );
|
||||
}
|
||||
|
||||
public static int hashCodeOf( int v ) {
|
||||
return v;
|
||||
}
|
||||
|
||||
public int luaAsInt() {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
public LString luaAsString() {
|
||||
return LString.valueOf(m_value);
|
||||
}
|
||||
|
||||
public boolean isInteger() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// binary operations on integers, first dispatch
|
||||
public LValue luaBinOpUnknown(int opcode, LValue lhs) {
|
||||
return lhs.luaBinOpInteger( opcode, this.m_value );
|
||||
}
|
||||
|
||||
// binary operations on integers
|
||||
public LValue luaBinOpInteger(int opcode, int rhs) {
|
||||
switch ( opcode ) {
|
||||
case Lua.OP_ADD: return new LInteger( m_value + rhs );
|
||||
case Lua.OP_SUB: return new LInteger( m_value - rhs );
|
||||
case Lua.OP_MUL: return new LInteger( m_value * rhs );
|
||||
case Lua.OP_DIV: return new LInteger( m_value / rhs );
|
||||
case Lua.OP_MOD: return new LInteger( m_value - ((int) Math.floor(m_value/(double)rhs)) * rhs );
|
||||
case Lua.OP_POW: return new LInteger( ipow(m_value, rhs) );
|
||||
}
|
||||
return luaUnsupportedOperation();
|
||||
}
|
||||
|
||||
private static int ipow(int v, int rhs) {
|
||||
int p = 1;
|
||||
for ( ; rhs > 0; rhs>>=1, v=v*v )
|
||||
if ( (rhs & 1) != 0 )
|
||||
p *= v;
|
||||
return p;
|
||||
}
|
||||
|
||||
// binary operations on mixed integer, double
|
||||
public LValue luaBinOpDouble(int opcode, double rhs) {
|
||||
return LDouble.luaBinOpDoubleDouble(opcode, (double) m_value, rhs );
|
||||
}
|
||||
|
||||
// binary compare for integers, first dispatch
|
||||
public boolean luaBinCmpUnknown(int opcode, LValue lhs) {
|
||||
return lhs.luaBinCmpInteger( opcode, this.m_value );
|
||||
}
|
||||
|
||||
// unsupported except for numbers
|
||||
public boolean luaBinCmpInteger(int opcode, int rhs) {
|
||||
switch ( opcode ) {
|
||||
case Lua.OP_EQ: return m_value == rhs;
|
||||
case Lua.OP_LT: return m_value < rhs;
|
||||
case Lua.OP_LE: return m_value <= rhs;
|
||||
}
|
||||
luaUnsupportedOperation();
|
||||
return false;
|
||||
}
|
||||
|
||||
// unsupported except for numbers
|
||||
public boolean luaBinCmpDouble(int opcode, double rhs) {
|
||||
return LDouble.luaBinCmpDoubleDouble(opcode, (double) m_value, rhs );
|
||||
}
|
||||
|
||||
/** Arithmetic negative */
|
||||
public LValue luaUnaryMinus() {
|
||||
return new LInteger( -m_value );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package lua.value;
|
||||
|
||||
public final class LNil extends LValue {
|
||||
public static final LNil NIL = new LNil();
|
||||
public static final LString TYPE_NAME = new LString("nil");
|
||||
|
||||
public final LString luaAsString() {
|
||||
return TYPE_NAME;
|
||||
}
|
||||
|
||||
public boolean luaAsBoolean() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public LString luaGetType() {
|
||||
return TYPE_NAME;
|
||||
}
|
||||
|
||||
public int luaAsInt() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package lua.value;
|
||||
|
||||
import lua.Lua;
|
||||
|
||||
abstract
|
||||
public class LNumber extends LValue {
|
||||
|
||||
public static final LString TYPE_NAME = new LString("number");
|
||||
|
||||
/** Compare for equivalence by using lua op comparator */
|
||||
public boolean equals(Object o) {
|
||||
if ( ! ( o instanceof LValue) )
|
||||
return false;
|
||||
LValue v = (LValue) o;
|
||||
return this.luaBinCmpUnknown(Lua.OP_EQ, v );
|
||||
}
|
||||
|
||||
public LString luaGetType() {
|
||||
return TYPE_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false by default for non-LNumbers, but subclasses of LNumber must
|
||||
* override.
|
||||
*/
|
||||
public abstract boolean isInteger();
|
||||
}
|
||||
@@ -1,392 +0,0 @@
|
||||
package lua.value;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import lua.Lua;
|
||||
|
||||
/**
|
||||
* A String implementation for Lua using bytes instead of chars.
|
||||
*
|
||||
* This should have the following advantages:
|
||||
*
|
||||
* (1) We can use strings as byte buffers, as Lua does, and therefore avoid
|
||||
* questions about how to adapt Lua APIs that use strings with binary data.
|
||||
*
|
||||
* (2) Half the memory usage when strings are primarily ASCII
|
||||
*
|
||||
*
|
||||
* TODO: Decide if/when to copy the bytes to a new array to ensure memory does
|
||||
* not "leak" in the form of unused portions of byte arrays. Currently, for
|
||||
* efficiency, new LStrings and substrings never create copies.
|
||||
*/
|
||||
public class LString extends LValue {
|
||||
|
||||
public static final LString TYPE_NAME = new LString("string");
|
||||
|
||||
public final byte[] m_bytes;
|
||||
public final int m_offset;
|
||||
public final int m_length;
|
||||
public final int m_hash;
|
||||
|
||||
private static LTable s_stringMT;
|
||||
|
||||
/**
|
||||
* Construct a Lua string from the given Java string. Characters are encoded
|
||||
* using UTF-8.
|
||||
*/
|
||||
public LString(String string) {
|
||||
byte[] bytes;
|
||||
try {
|
||||
bytes = string.getBytes( "UTF-8" );
|
||||
} catch ( UnsupportedEncodingException exn ) {
|
||||
bytes = stringToUtf8Bytes( string );
|
||||
}
|
||||
this.m_bytes = bytes;
|
||||
this.m_offset = 0;
|
||||
this.m_length = m_bytes.length;
|
||||
this.m_hash = hashBytes( m_bytes, 0, m_length );
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a string from the given byte array.
|
||||
*
|
||||
* new LString(b) is identical to new LString(b, 0, b.length)
|
||||
*/
|
||||
public LString(byte[] bytes) {
|
||||
this( bytes, 0, bytes.length );
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a string from the given byte array and range. For efficiency,
|
||||
* the byte array is not copied. Lua strings are immutable so the bytes must
|
||||
* not be modified after the string is constructed.
|
||||
*/
|
||||
public LString(byte[] bytes, int off, int len) {
|
||||
if ( off < 0 || len < 0 || off+len > bytes.length )
|
||||
throw new IndexOutOfBoundsException();
|
||||
this.m_bytes = bytes;
|
||||
this.m_offset = off;
|
||||
this.m_length = len;
|
||||
this.m_hash = hashBytes( bytes, off, len );
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if ( o != null && o instanceof LString ) {
|
||||
LString s = (LString) o;
|
||||
return m_hash == s.m_hash &&
|
||||
m_length == s.m_length &&
|
||||
( ( m_bytes == s.m_bytes && m_offset == s.m_offset ) ||
|
||||
equals( m_bytes, m_offset, s.m_bytes, s.m_offset, m_length ) );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int compareTo( LString o ) {
|
||||
final byte[] a = this.m_bytes;
|
||||
final byte[] b = o.m_bytes;
|
||||
int i = this.m_offset;
|
||||
int j = o.m_offset;
|
||||
final int imax = i + m_length;
|
||||
final int jmax = j + o.m_length;
|
||||
|
||||
if ( a == b && i == j && imax == jmax )
|
||||
return 0;
|
||||
|
||||
while ( i < imax && j < jmax ) {
|
||||
if ( a[i] != b[i] ) {
|
||||
return ( ( (int)a[i] ) & 0x0FF ) - ( ( (int)b[j] ) & 0x0FF );
|
||||
}
|
||||
i++;
|
||||
j++;
|
||||
}
|
||||
|
||||
return m_length - o.m_length;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return m_hash;
|
||||
}
|
||||
|
||||
public int length() {
|
||||
return m_length;
|
||||
}
|
||||
|
||||
public LString substring( int beginIndex, int endIndex ) {
|
||||
return new LString( m_bytes, m_offset + beginIndex, endIndex - beginIndex );
|
||||
}
|
||||
|
||||
public int charAt( int index ) {
|
||||
if ( index < 0 || index >= m_length )
|
||||
throw new IndexOutOfBoundsException();
|
||||
return luaByte( index );
|
||||
}
|
||||
|
||||
/** Java version of strpbrk, which is a terribly named C function. */
|
||||
public int indexOfAny( LString accept ) {
|
||||
final int ilimit = m_offset + m_length;
|
||||
final int jlimit = accept.m_offset + accept.m_length;
|
||||
for ( int i = m_offset; i < ilimit; ++i ) {
|
||||
for ( int j = accept.m_offset; j < jlimit; ++j ) {
|
||||
if ( m_bytes[i] == accept.m_bytes[j] ) {
|
||||
return i - m_offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int indexOf( LString s, int start ) {
|
||||
final int slen = s.length();
|
||||
final int limit = m_offset + m_length - slen;
|
||||
for ( int i = m_offset + start; i <= limit; ++i ) {
|
||||
if ( equals( m_bytes, i, s.m_bytes, s.m_offset, slen ) ) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static LString valueOf( double d ) {
|
||||
return new LString( String.valueOf( d ) );
|
||||
}
|
||||
|
||||
public static LString valueOf( int x ) {
|
||||
return new LString( String.valueOf( x ) );
|
||||
}
|
||||
|
||||
public static LString concat( final LString[] strings ) {
|
||||
int length = 0;
|
||||
for ( int i = 0; i < strings.length; ++i ) {
|
||||
length += strings[i].length();
|
||||
}
|
||||
byte[] bytes = new byte[length];
|
||||
|
||||
for ( int i = 0, offset = 0; i < strings.length; ++i ) {
|
||||
LString s = strings[i];
|
||||
final int len = s.length();
|
||||
System.arraycopy( s.m_bytes, s.m_offset, bytes, offset, len );
|
||||
offset += len;
|
||||
}
|
||||
|
||||
return new LString( bytes );
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the specified substring of this string to the given output stream.
|
||||
*/
|
||||
public void write( OutputStream os, int offset, int len ) throws IOException {
|
||||
if ( offset < 0 || len < 0 )
|
||||
throw new IndexOutOfBoundsException();
|
||||
if ( offset + len > m_length )
|
||||
throw new IndexOutOfBoundsException();
|
||||
|
||||
os.write( m_bytes, m_offset+offset, len );
|
||||
}
|
||||
|
||||
public void write(OutputStream os) throws IOException {
|
||||
write(os, 0, m_length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the bytes of the string into the given byte array.
|
||||
*/
|
||||
public void copyInto( int strOffset, byte[] bytes, int arrayOffset, int len ) {
|
||||
System.arraycopy( m_bytes, m_offset+strOffset, bytes, arrayOffset, len );
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce an InputStream instance from which the bytes of this LString can be read.
|
||||
* Underlying byte array is not copied.
|
||||
*/
|
||||
public ByteArrayInputStream toInputStream() {
|
||||
// Well, this is really something.
|
||||
// Javadoc for java versions 1.3 and earlier states that if reset() is
|
||||
// called on a ByteArrayInputStream constructed with the 3-argument
|
||||
// constructor, then bytes 0 .. offset will be returned by the next
|
||||
// calls to read(). In JDK 1.4, the behavior improved, so that the
|
||||
// initial mark is set to the initial offset. We still need to
|
||||
// override ByteArrayInputStream here just in case we run on a
|
||||
// JVM with the older behavior.
|
||||
return new ByteArrayInputStream( m_bytes, m_offset, m_length ) {
|
||||
public synchronized void reset() {
|
||||
pos = Math.max( m_offset, mark );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public boolean luaBinCmpUnknown(int opcode, LValue lhs) {
|
||||
return lhs.luaBinCmpString(opcode, this);
|
||||
}
|
||||
|
||||
public boolean luaBinCmpString(int opcode, LString rhs) {
|
||||
switch ( opcode ) {
|
||||
case Lua.OP_EQ: return equals(rhs);
|
||||
case Lua.OP_LT: return compareTo(rhs) < 0;
|
||||
case Lua.OP_LE: return compareTo(rhs) <= 0;
|
||||
}
|
||||
luaUnsupportedOperation();
|
||||
return false;
|
||||
}
|
||||
|
||||
public LValue luaBinOpDouble( int opcode, double m_value ) {
|
||||
return luaToNumber().luaBinOpDouble( opcode, m_value );
|
||||
}
|
||||
|
||||
public LValue luaBinOpInteger( int opcode, int m_value ) {
|
||||
return luaToNumber().luaBinOpInteger( opcode, m_value );
|
||||
}
|
||||
|
||||
public LValue luaBinOpUnknown( int opcode, LValue lhs ) {
|
||||
return luaToNumber().luaBinOpUnknown( opcode, lhs );
|
||||
}
|
||||
|
||||
public LValue luaUnaryMinus() {
|
||||
return luaToNumber().luaUnaryMinus();
|
||||
}
|
||||
|
||||
public LValue luaToNumber() {
|
||||
return luaToNumber( 10 );
|
||||
}
|
||||
|
||||
public LValue luaToNumber( int base ) {
|
||||
if ( base >= 2 && base <= 36 ) {
|
||||
String str = toJavaString().trim();
|
||||
try {
|
||||
return new LInteger( Integer.parseInt( str, base ) );
|
||||
} catch ( NumberFormatException nfe ) {
|
||||
if ( base == 10 ) {
|
||||
try {
|
||||
return new LDouble( Double.parseDouble( str ) );
|
||||
} catch ( NumberFormatException nfe2 ) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return LNil.NIL;
|
||||
}
|
||||
|
||||
public LString luaAsString() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public String toJavaString() {
|
||||
try {
|
||||
return new String( m_bytes, m_offset, m_length, "UTF-8" );
|
||||
} catch ( UnsupportedEncodingException uee ) {
|
||||
throw new RuntimeException("toJavaString: UTF-8 decoding not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
/** Built-in opcode LEN, for Strings and Tables */
|
||||
public LValue luaLength() {
|
||||
return new LInteger( length() );
|
||||
}
|
||||
|
||||
public LString luaGetType() {
|
||||
return TYPE_NAME;
|
||||
}
|
||||
|
||||
public LTable luaGetMetatable() {
|
||||
synchronized ( LString.class ) {
|
||||
return s_stringMT;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the metatable for all string values. Creates the table if it does not
|
||||
* exist yet, and sets its __index entry to point to itself.
|
||||
*
|
||||
* @return metatable that will be used for all strings
|
||||
*/
|
||||
public static synchronized LTable getMetatable() {
|
||||
if ( s_stringMT == null ) {
|
||||
s_stringMT = new LTable();
|
||||
s_stringMT.put( TM_INDEX, s_stringMT );
|
||||
}
|
||||
return s_stringMT;
|
||||
}
|
||||
|
||||
public static boolean equals( LString a, int i, LString b, int j, int n ) {
|
||||
return equals( a.m_bytes, a.m_offset + i, b.m_bytes, b.m_offset + j, n );
|
||||
}
|
||||
|
||||
public static boolean equals( byte[] a, int i, byte[] b, int j, int n ) {
|
||||
if ( a.length < i + n || b.length < j + n )
|
||||
return false;
|
||||
final int imax = i + n;
|
||||
final int jmax = j + n;
|
||||
while ( i < imax && j < jmax ) {
|
||||
if ( a[i++] != b[j++] )
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static int hashBytes( byte[] bytes, int offset, int length ) {
|
||||
// Compute the hash of the given bytes.
|
||||
// This code comes right out of Lua 5.1.2 (translated from C to Java)
|
||||
int h = length; /* seed */
|
||||
int step = (length>>5)+1; /* if string is too long, don't hash all its chars */
|
||||
for (int l1=length; l1>=step; l1-=step) /* compute hash */
|
||||
h = h ^ ((h<<5)+(h>>2)+(((int) bytes[offset+l1-1] ) & 0x0FF ));
|
||||
return h;
|
||||
}
|
||||
|
||||
private static byte[] stringToUtf8Bytes( final String string ) {
|
||||
final int strlen = string.length();
|
||||
byte[] bytes = new byte[ strlen ];
|
||||
byte b1 = 0, b2 = 0, b3 = 0;
|
||||
|
||||
int j = 0;
|
||||
for ( int i = 0; i < strlen; ++i ) {
|
||||
int c = string.charAt( i );
|
||||
// TODO: combine 2-character combinations
|
||||
int count;
|
||||
if ( c > 0x07FF ) {
|
||||
count = 3;
|
||||
b3 = (byte)( 0xE0 | ( c >> 12 ) );
|
||||
b2 = (byte)( 0x80 | ( ( c >> 6 ) & 0x03F ) );
|
||||
b1 = (byte)( 0x80 | ( ( c ) & 0x03F ) );
|
||||
} else if ( c > 0x07F ) {
|
||||
count = 2;
|
||||
b2 = (byte)( 0xC0 | ( c >> 6 ) );
|
||||
b1 = (byte)( 0x80 | ( c & 0x03F ) );
|
||||
} else {
|
||||
count = 1;
|
||||
b1 = (byte) c;
|
||||
}
|
||||
if ( j + count > bytes.length ) {
|
||||
bytes = realloc( bytes, ( j + count ) * 2 );
|
||||
}
|
||||
switch ( count ) {
|
||||
case 3:
|
||||
bytes[j++] = b3;
|
||||
case 2:
|
||||
bytes[j++] = b2;
|
||||
case 1:
|
||||
bytes[j++] = b1;
|
||||
}
|
||||
}
|
||||
|
||||
if ( j != bytes.length ) {
|
||||
bytes = realloc( bytes, j );
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private static byte[] realloc( byte[] a, int newSize ) {
|
||||
final byte[] newbytes = new byte[ newSize ];
|
||||
System.arraycopy( a, 0, newbytes, 0, Math.min( newSize, a.length ) );
|
||||
return newbytes;
|
||||
}
|
||||
|
||||
public int luaByte(int index) {
|
||||
return m_bytes[m_offset + index] & 0x0FF;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,540 +0,0 @@
|
||||
package lua.value;
|
||||
|
||||
import lua.Lua;
|
||||
import lua.VM;
|
||||
|
||||
/**
|
||||
* Simple implementation of table structure for Lua VM. Maintains both an array
|
||||
* part and a hash part. Does not attempt to achieve the same performance as the
|
||||
* C version.
|
||||
*
|
||||
* Java code can put values in the table or get values out (bypassing the
|
||||
* metatable, if there is one) using put() and get(). There are specializations
|
||||
* of put() and get() for integers and Strings to avoid allocating wrapper
|
||||
* objects when possible.
|
||||
*
|
||||
* remove() methods are private: setting a key's value to nil is the correct way
|
||||
* to remove an entry from the table.
|
||||
*
|
||||
* TODO: Support for weak tables has to be shoehorned in here somehow.
|
||||
*
|
||||
*/
|
||||
public class LTable extends LValue {
|
||||
|
||||
public static final LString TYPE_NAME = new LString("table");
|
||||
|
||||
/**
|
||||
* Zero-length array to use instead of null, so that we don't need to
|
||||
* check for null everywhere.
|
||||
*/
|
||||
private static final LValue[] EMPTY_ARRAY = new LValue[0];
|
||||
|
||||
/**
|
||||
* Minimum legal capacity for the hash portion. Note that the hash portion
|
||||
* must never be filled to capacity or findSlot() will run forever.
|
||||
*/
|
||||
private static final int MIN_HASH_CAPACITY = 2;
|
||||
|
||||
/**
|
||||
* Array of keys in the hash part. When there is no hash part this is null.
|
||||
* Elements of m_hashKeys are never LNil.NIL - they are null to indicate
|
||||
* the hash slot is empty and some non-null, non-nil value otherwise.
|
||||
*/
|
||||
private LValue[] m_hashKeys;
|
||||
|
||||
/**
|
||||
* Values in the hash part. Must be null when m_hashKeys is null and equal
|
||||
* in size otherwise.
|
||||
*/
|
||||
private LValue[] m_hashValues;
|
||||
|
||||
/**
|
||||
* m_hashEntries is the number of slots that are used. Must always be less
|
||||
* than m_hashKeys.length.
|
||||
*/
|
||||
private int m_hashEntries;
|
||||
|
||||
/**
|
||||
* Array of values to store the "array part" of the table, that is the
|
||||
* entries with positive integer keys. Elements must never be null: "empty"
|
||||
* slots are set to LNil.NIL.
|
||||
*/
|
||||
private LValue[] m_vector;
|
||||
|
||||
/**
|
||||
* Number of values in m_vector that non-nil.
|
||||
*/
|
||||
private int m_arrayEntries;
|
||||
|
||||
private LTable m_metatable;
|
||||
|
||||
|
||||
|
||||
/** Construct an empty LTable with no initial capacity. */
|
||||
public LTable() {
|
||||
m_vector = EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an empty LTable that is expected to contain entries with keys
|
||||
* in the range 1 .. narray and nhash non-integer keys.
|
||||
*/
|
||||
public LTable( int narray, int nhash ) {
|
||||
if ( nhash > 0 ) {
|
||||
// Allocate arrays 25% bigger than nhash to account for load factor.
|
||||
final int capacity = Math.max( nhash + ( nhash >> 2 ), nhash + 1 );
|
||||
m_hashKeys = new LValue[capacity];
|
||||
m_hashValues = new LValue[capacity];
|
||||
}
|
||||
m_vector = new LValue[narray];
|
||||
for ( int i = 0; i < narray; ++i ) {
|
||||
m_vector[i] = LNil.NIL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return total number of keys mapped to non-nil values. Not to be confused
|
||||
* with luaLength, which returns some number n such that the value at n+1 is
|
||||
* nil.
|
||||
*/
|
||||
public int size() {
|
||||
return m_hashEntries + m_arrayEntries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic put method for all types of keys, but does not use the metatable.
|
||||
*/
|
||||
public void put( LValue key, LValue val ) {
|
||||
if ( key.isInteger() ) {
|
||||
// call the integer-specific put method
|
||||
put( key.luaAsInt(), val );
|
||||
} else if ( val == null || val == LNil.NIL ) {
|
||||
// Remove the key if the value is nil. This comes after the check
|
||||
// for an integer key so that values are properly removed from
|
||||
// the array part.
|
||||
remove( key );
|
||||
} else {
|
||||
if ( checkLoadFactor() )
|
||||
rehash();
|
||||
int slot = findSlot( key );
|
||||
if ( fillHashSlot( slot, val ) )
|
||||
return;
|
||||
m_hashKeys[slot] = key;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method for putting a string-keyed value directly, typically for
|
||||
* initializing a table. Bypasses the metatable, if any.
|
||||
*/
|
||||
public void put( String key, LValue value ) {
|
||||
put( new LString( key ), value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for putting an integer-keyed value. Bypasses the metatable, if
|
||||
* any.
|
||||
*/
|
||||
public void put( int key, LValue value ) {
|
||||
if (value == null || value == LNil.NIL) {
|
||||
remove( key );
|
||||
return;
|
||||
}
|
||||
if ( key > 0 ) {
|
||||
final int index = key - 1;
|
||||
for ( ;; ) {
|
||||
if ( index < m_vector.length ) {
|
||||
if ( m_vector[index] == LNil.NIL ) {
|
||||
++m_arrayEntries;
|
||||
}
|
||||
m_vector[index] = value;
|
||||
return;
|
||||
} else if ( index < ( m_arrayEntries + 1 ) * 2 ) {
|
||||
resize( ( m_arrayEntries + 1 ) * 2 );
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No room in array part, use hash part instead.
|
||||
if ( checkLoadFactor() )
|
||||
rehash();
|
||||
int slot = findSlot( key );
|
||||
if ( fillHashSlot( slot, value ) )
|
||||
return;
|
||||
m_hashKeys[ slot ] = new LInteger( key );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Utility method to directly get the value in a table, without metatable
|
||||
* calls. Must never return null, use LNil.NIL instead.
|
||||
*/
|
||||
public LValue get( LValue key ) {
|
||||
if ( m_vector.length > 0 && key.isInteger() ) {
|
||||
final int index = key.luaAsInt() - 1;
|
||||
if ( index >= 0 && index < m_vector.length ) {
|
||||
return m_vector[index];
|
||||
}
|
||||
}
|
||||
|
||||
if ( m_hashKeys == null )
|
||||
return LNil.NIL;
|
||||
|
||||
int slot = findSlot( key );
|
||||
return ( m_hashKeys[slot] != null ) ? m_hashValues[slot] : LNil.NIL;
|
||||
}
|
||||
|
||||
/** Utility method for retrieving an integer-keyed value */
|
||||
public LValue get( int key ) {
|
||||
if ( key > 0 && key <= m_vector.length ) {
|
||||
return m_vector[key - 1];
|
||||
}
|
||||
|
||||
int slot = findSlot( key );
|
||||
return ( m_hashKeys[slot] != null ) ? m_hashValues[slot] : LNil.NIL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return true if the table contains an entry with the given key, false if
|
||||
* not. Ignores the metatable.
|
||||
*/
|
||||
public boolean containsKey( LValue key ) {
|
||||
if ( m_vector.length > 0 && key.isInteger() ) {
|
||||
final int index = key.luaAsInt() - 1;
|
||||
if ( index >= 0 && index < m_vector.length ) {
|
||||
final LValue v = m_vector[index];
|
||||
return v != LNil.NIL;
|
||||
}
|
||||
}
|
||||
if ( m_hashKeys == null )
|
||||
return false;
|
||||
final int slot = findSlot( key );
|
||||
return m_hashKeys[ slot ] != null;
|
||||
}
|
||||
|
||||
public void luaGetTable(VM vm, LValue table, LValue key) {
|
||||
LValue v = get(key);
|
||||
if ( v == LNil.NIL && m_metatable != null ) {
|
||||
super.luaGetTable( vm, table, key );
|
||||
} else {
|
||||
vm.push(v);
|
||||
}
|
||||
}
|
||||
|
||||
public void luaSetTable(VM vm, LValue table, LValue key, LValue val) {
|
||||
if ( !containsKey( key ) && m_metatable != null ) {
|
||||
super.luaSetTable( vm, table, key, val );
|
||||
} else {
|
||||
put(key, val);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the "length" of this table. This will not return the same result
|
||||
* as the C version in all cases, but that's ok because the length operation
|
||||
* on a table where the integer keys are sparse is vaguely defined.
|
||||
*/
|
||||
public LValue luaLength() {
|
||||
for ( int i = Math.max( 0, m_arrayEntries-1 ); i < m_vector.length; ++i ) {
|
||||
if ( m_vector[i] != LNil.NIL &&
|
||||
( i+1 == m_vector.length || m_vector[i+1] == LNil.NIL ) ) {
|
||||
return new LInteger( i+1 );
|
||||
}
|
||||
}
|
||||
return new LInteger( 0 );
|
||||
}
|
||||
|
||||
/** Valid for tables */
|
||||
public LTable luaGetMetatable() {
|
||||
return this.m_metatable;
|
||||
}
|
||||
|
||||
/** Valid for tables */
|
||||
public void luaSetMetatable(LValue metatable) {
|
||||
this.m_metatable = ( metatable != null && metatable != LNil.NIL ) ?
|
||||
(LTable) metatable : null;
|
||||
}
|
||||
|
||||
public LString luaAsString() {
|
||||
return new LString("table: "+id());
|
||||
}
|
||||
|
||||
public LString luaGetType() {
|
||||
return TYPE_NAME;
|
||||
}
|
||||
|
||||
/** Valid for tables */
|
||||
public LValue luaPairs(boolean isPairs) {
|
||||
return new LTableIterator(isPairs);
|
||||
}
|
||||
|
||||
/** Iterator for tables */
|
||||
private final class LTableIterator extends LFunction {
|
||||
private int arrayIndex;
|
||||
private int hashIndex;
|
||||
private final boolean isPairs;
|
||||
|
||||
private LTableIterator(boolean isPairs) {
|
||||
this.arrayIndex = 0;
|
||||
this.hashIndex = 0;
|
||||
this.isPairs = isPairs;
|
||||
}
|
||||
|
||||
// perform a lua call
|
||||
public boolean luaStackCall(VM vm) {
|
||||
vm.setResult();
|
||||
int i;
|
||||
while ( ( i = arrayIndex++ ) < m_vector.length ) {
|
||||
if ( m_vector[i] != LNil.NIL ) {
|
||||
vm.push( new LInteger( arrayIndex ) );
|
||||
vm.push( m_vector[ i ] );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ( isPairs && (m_hashKeys != null) ) {
|
||||
while ( ( i = hashIndex++ ) < m_hashKeys.length ) {
|
||||
if ( m_hashKeys[i] != null ) {
|
||||
vm.push( m_hashKeys[i] );
|
||||
vm.push( m_hashValues[i] );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to get all the keys in this table in an array. Meant to be
|
||||
* used instead of keys() (which returns an enumeration) when an array is
|
||||
* more convenient. Note that for a very large table, getting an Enumeration
|
||||
* instead would be more space efficient.
|
||||
*/
|
||||
public LValue[] getKeys() {
|
||||
LValue[] keys = new LValue[ m_arrayEntries + m_hashEntries ];
|
||||
int out = 0;
|
||||
|
||||
for ( int i = 0; i < m_vector.length; ++i ) {
|
||||
if ( m_vector[ i ] != LNil.NIL ) {
|
||||
keys[ out++ ] = new LInteger( i + 1 );
|
||||
}
|
||||
}
|
||||
|
||||
if ( m_hashKeys != null ) {
|
||||
for ( int i = 0; i < m_hashKeys.length; ++i ) {
|
||||
if ( m_hashKeys[ i ] != null )
|
||||
keys[ out++ ] = m_hashKeys[i];
|
||||
}
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
/** Remove the value in the table with the given integer key. */
|
||||
private void remove( int key ) {
|
||||
if ( key > 0 ) {
|
||||
final int index = key - 1;
|
||||
if ( index < m_vector.length ) {
|
||||
if ( m_vector[ index ] != LNil.NIL ) {
|
||||
--m_arrayEntries;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( m_hashKeys != null ) {
|
||||
int slot = findSlot( key );
|
||||
clearSlot( slot );
|
||||
}
|
||||
}
|
||||
|
||||
private void remove( LValue key ) {
|
||||
if ( m_hashKeys != null ) {
|
||||
int slot = findSlot( key );
|
||||
clearSlot( slot );
|
||||
}
|
||||
}
|
||||
|
||||
private void clearSlot( int i ) {
|
||||
if ( m_hashKeys[ i ] != null ) {
|
||||
|
||||
int j = i;
|
||||
while ( m_hashKeys[ j = ( ( j + 1 ) % m_hashKeys.length ) ] != null ) {
|
||||
final int k = hashToIndex( m_hashKeys[ j ].hashCode() );
|
||||
if ( ( j > i && ( k <= i || k > j ) ) ||
|
||||
( j < i && ( k <= i && k > j ) ) ) {
|
||||
m_hashKeys[ i ] = m_hashKeys[ j ];
|
||||
m_hashValues[ i ] = m_hashValues[ j ];
|
||||
i = j;
|
||||
}
|
||||
}
|
||||
|
||||
--m_hashEntries;
|
||||
m_hashKeys[ i ] = null;
|
||||
m_hashValues[ i ] = null;
|
||||
|
||||
if ( m_hashEntries == 0 ) {
|
||||
m_hashKeys = null;
|
||||
m_hashValues = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int findSlot( LValue key ) {
|
||||
int i = hashToIndex( key.hashCode() );
|
||||
|
||||
// This loop is guaranteed to terminate as long as we never allow the
|
||||
// table to get 100% full.
|
||||
LValue k;
|
||||
while ( ( k = m_hashKeys[i] ) != null &&
|
||||
!key.luaBinCmpUnknown( Lua.OP_EQ, k ) ) {
|
||||
i = ( i + 1 ) % m_hashKeys.length;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
private int findSlot( int key ) {
|
||||
int i = hashToIndex( LInteger.hashCodeOf( key ) );
|
||||
|
||||
// This loop is guaranteed to terminate as long as we never allow the
|
||||
// table to get 100% full.
|
||||
LValue k;
|
||||
while ( ( k = m_hashKeys[i] ) != null &&
|
||||
!k.luaBinCmpInteger( Lua.OP_EQ, key ) ) {
|
||||
i = ( i + 1 ) % m_hashKeys.length;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the given slot was already occupied, false otherwise.
|
||||
*/
|
||||
private boolean fillHashSlot( int slot, LValue value ) {
|
||||
m_hashValues[ slot ] = value;
|
||||
if ( m_hashKeys[ slot ] != null ) {
|
||||
return true;
|
||||
} else {
|
||||
++m_hashEntries;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private int hashToIndex( int hash ) {
|
||||
return ( hash & 0x7FFFFFFF ) % m_hashKeys.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be called before inserting a value into the hash.
|
||||
*
|
||||
* @return true if the hash portion of the LTable is at its capacity.
|
||||
*/
|
||||
private boolean checkLoadFactor() {
|
||||
if ( m_hashKeys == null )
|
||||
return true;
|
||||
// Using a load factor of 2/3 because that is easy to compute without
|
||||
// overflow or division.
|
||||
final int hashCapacity = m_hashKeys.length;
|
||||
return ( hashCapacity >> 1 ) >= ( hashCapacity - m_hashEntries );
|
||||
}
|
||||
|
||||
private void rehash() {
|
||||
final int oldCapacity = ( m_hashKeys != null ) ? m_hashKeys.length : 0;
|
||||
final int newCapacity = ( oldCapacity > 0 ) ? 2 * oldCapacity : MIN_HASH_CAPACITY;
|
||||
|
||||
final LValue[] oldKeys = m_hashKeys;
|
||||
final LValue[] oldValues = m_hashValues;
|
||||
|
||||
m_hashKeys = new LValue[ newCapacity ];
|
||||
m_hashValues = new LValue[ newCapacity ];
|
||||
|
||||
for ( int i = 0; i < oldCapacity; ++i ) {
|
||||
final LValue k = oldKeys[i];
|
||||
if ( k != null ) {
|
||||
final LValue v = oldValues[i];
|
||||
final int slot = findSlot( k );
|
||||
m_hashKeys[slot] = k;
|
||||
m_hashValues[slot] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void resize( int newCapacity ) {
|
||||
final int oldCapacity = m_vector.length;
|
||||
LValue[] newVector = new LValue[ newCapacity ];
|
||||
System.arraycopy( m_vector, 0, newVector, 0, Math.min( oldCapacity, newCapacity ) );
|
||||
|
||||
// We need to move keys from hash part to array part if array part is
|
||||
// getting bigger, and from array part to hash part if array is getting
|
||||
// smaller.
|
||||
if ( newCapacity > oldCapacity ) {
|
||||
if ( m_hashKeys != null ) {
|
||||
for ( int i = oldCapacity; i < newCapacity; ++i ) {
|
||||
int slot = findSlot( i+1 );
|
||||
if ( m_hashKeys[ slot ] != null ) {
|
||||
newVector[ i ] = m_hashValues[ slot ];
|
||||
m_hashKeys[ i ] = null;
|
||||
--m_hashEntries;
|
||||
} else {
|
||||
// Make sure all array-part values are initialized to nil
|
||||
// so that we can just do one compare instead of two
|
||||
// whenever we need to check if a slot is full or not.
|
||||
newVector[ i ] = LNil.NIL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for ( int i = oldCapacity; i < newCapacity; ++i ) {
|
||||
newVector[ i ] = LNil.NIL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for ( int i = newCapacity; i < oldCapacity; ++i ) {
|
||||
LValue v = m_vector[i];
|
||||
if ( v != LNil.NIL ) {
|
||||
if (checkLoadFactor())
|
||||
rehash();
|
||||
final int slot = findSlot( i+1 );
|
||||
m_hashKeys[ slot ] = new LInteger( i+1 );
|
||||
m_hashValues[ slot ] = v;
|
||||
++m_hashEntries;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_vector = newVector;
|
||||
}
|
||||
|
||||
// hooks for junit
|
||||
|
||||
int getHashCapacity() {
|
||||
return ( m_hashKeys != null ) ? m_hashKeys.length : 0;
|
||||
}
|
||||
|
||||
int getArrayCapacity() {
|
||||
return m_vector.length;
|
||||
}
|
||||
|
||||
/*
|
||||
* @pos index to insert at, or 0 to insert at end.
|
||||
*/
|
||||
public void luaInsertPos(int pos, LValue value) {
|
||||
if ( pos != 0 )
|
||||
throw new RuntimeException("luaInsertPos() not implemented");
|
||||
put( m_arrayEntries + m_hashEntries + 1, value );
|
||||
}
|
||||
|
||||
public void luaSort() {
|
||||
throw new RuntimeException("luaSort() not implemented");
|
||||
}
|
||||
|
||||
public void luaRemovePos(int pos) {
|
||||
throw new RuntimeException("luaRemovePos() not implemented");
|
||||
}
|
||||
|
||||
public int luaMaxN() {
|
||||
throw new RuntimeException("luaMaxN() not implemented");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package lua.value;
|
||||
|
||||
public class LThread extends LValue {
|
||||
public static final LString TYPE_NAME = new LString("thread");
|
||||
|
||||
public LString luaGetType() {
|
||||
return TYPE_NAME;
|
||||
}
|
||||
|
||||
public LString luaAsString() {
|
||||
return new LString("thread: "+hashCode());
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package lua.value;
|
||||
|
||||
public class LUserData extends LValue {
|
||||
public static final LString TYPE_NAME = new LString("userdata");
|
||||
|
||||
public final Object m_instance;
|
||||
public LTable m_metatable;
|
||||
|
||||
public LUserData(Object obj) {
|
||||
m_instance = obj;
|
||||
}
|
||||
|
||||
public LString luaAsString() {
|
||||
return new LString(m_instance.toString());
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
return (this == obj) ||
|
||||
(obj instanceof LUserData && this.m_instance == ((LUserData) obj).m_instance);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return System.identityHashCode( m_instance );
|
||||
}
|
||||
|
||||
public LString luaGetType() {
|
||||
return TYPE_NAME;
|
||||
}
|
||||
|
||||
public LTable luaGetMetatable() {
|
||||
return m_metatable;
|
||||
}
|
||||
}
|
||||
@@ -1,182 +0,0 @@
|
||||
package lua.value;
|
||||
|
||||
import lua.Lua;
|
||||
import lua.VM;
|
||||
|
||||
abstract
|
||||
public class LValue {
|
||||
|
||||
/** Metatable tag for intercepting table gets */
|
||||
public static final LString TM_INDEX = new LString("__index");
|
||||
|
||||
/** Metatable tag for intercepting table sets */
|
||||
public static final LString TM_NEWINDEX = new LString("__newindex");
|
||||
|
||||
protected static LValue luaUnsupportedOperation() {
|
||||
throw new java.lang.RuntimeException( "not supported" );
|
||||
}
|
||||
|
||||
public String id() {
|
||||
return Integer.toHexString(hashCode());
|
||||
}
|
||||
|
||||
// test if value is true
|
||||
public boolean luaAsBoolean() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Return true if this value can be represented as an "int" */
|
||||
public boolean isInteger() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// perform a lua call, return true if the call is to a lua function, false
|
||||
// if it ran to completion.
|
||||
public boolean luaStackCall(VM vm) {
|
||||
vm.lua_error("attempt to call "+this);
|
||||
return false;
|
||||
}
|
||||
|
||||
// unsupported except for numbers
|
||||
public LValue luaBinOpUnknown(int opcode, LValue lhs) {
|
||||
return luaUnsupportedOperation();
|
||||
}
|
||||
|
||||
// unsupported except for numbers
|
||||
public LValue luaBinOpInteger(int opcode, int m_value) {
|
||||
return luaUnsupportedOperation();
|
||||
}
|
||||
|
||||
// unsupported except for numbers
|
||||
public LValue luaBinOpDouble(int opcode, double m_value) {
|
||||
return luaUnsupportedOperation();
|
||||
}
|
||||
|
||||
// unsupported except for numbers, strings, and == with various combinations of Nil, Boolean, etc.
|
||||
public boolean luaBinCmpUnknown(int opcode, LValue lhs) {
|
||||
if ( opcode == Lua.OP_EQ )
|
||||
return lhs == this;
|
||||
luaUnsupportedOperation();
|
||||
return false;
|
||||
}
|
||||
|
||||
// unsupported except for strings
|
||||
public boolean luaBinCmpString(int opcode, LString rhs) {
|
||||
if ( opcode == Lua.OP_EQ )
|
||||
return false;
|
||||
luaUnsupportedOperation();
|
||||
return false;
|
||||
}
|
||||
|
||||
// unsupported except for numbers
|
||||
public boolean luaBinCmpInteger(int opcode, int rhs) {
|
||||
if ( opcode == Lua.OP_EQ )
|
||||
return false;
|
||||
luaUnsupportedOperation();
|
||||
return false;
|
||||
}
|
||||
|
||||
// unsupported except for numbers
|
||||
public boolean luaBinCmpDouble(int opcode, double rhs) {
|
||||
if ( opcode == Lua.OP_EQ )
|
||||
return false;
|
||||
luaUnsupportedOperation();
|
||||
return false;
|
||||
}
|
||||
|
||||
/** set a value in a table
|
||||
* For non-tables, goes straight to the meta-table.
|
||||
* @param vm the calling vm
|
||||
* @param table the table to operate on
|
||||
* @param the key to set
|
||||
* @param the value to set
|
||||
*/
|
||||
public void luaSetTable(VM vm, LValue table, LValue key, LValue val) {
|
||||
LTable mt = luaGetMetatable();
|
||||
if ( mt != null ) {
|
||||
LValue event = mt.get( TM_NEWINDEX );
|
||||
if ( event != null && event != LNil.NIL ) {
|
||||
event.luaSetTable( vm, table, key, val );
|
||||
return;
|
||||
}
|
||||
}
|
||||
vm.push( LNil.NIL );
|
||||
}
|
||||
|
||||
/** Get a value from a table
|
||||
* @param vm the calling vm
|
||||
* @param table the table from which to get the value
|
||||
* @param key the key to look up
|
||||
*/
|
||||
public void luaGetTable(VM vm, LValue table, LValue key) {
|
||||
LTable mt = luaGetMetatable();
|
||||
if ( mt != null ) {
|
||||
LValue event = mt.get( TM_INDEX );
|
||||
if ( event != null && event != LNil.NIL ) {
|
||||
event.luaGetTable( vm, table, key );
|
||||
return;
|
||||
}
|
||||
}
|
||||
vm.push(LNil.NIL);
|
||||
}
|
||||
|
||||
/** Get the value as a String
|
||||
*/
|
||||
public abstract LString luaAsString();
|
||||
|
||||
/** Override standard toString with lua String conversion by default */
|
||||
public String toString() {
|
||||
return luaAsString().toJavaString();
|
||||
}
|
||||
|
||||
/** Return value as an integer */
|
||||
public int luaAsInt() {
|
||||
luaUnsupportedOperation();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Return value as a double */
|
||||
public double luaAsDouble() {
|
||||
return luaAsInt();
|
||||
}
|
||||
|
||||
/** Arithmetic negative */
|
||||
public LValue luaUnaryMinus() {
|
||||
return luaUnsupportedOperation();
|
||||
}
|
||||
|
||||
/** Built-in opcode LEN, for Strings and Tables */
|
||||
public LValue luaLength() {
|
||||
// TODO: call meta-method TM_LEN here
|
||||
return luaUnsupportedOperation();
|
||||
}
|
||||
|
||||
/** Valid for tables
|
||||
* @param isPairs true to iterate over non-integers as well */
|
||||
public LValue luaPairs(boolean isPairs) {
|
||||
return luaUnsupportedOperation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Valid for all types: get a metatable. Only tables and userdata can have a
|
||||
* different metatable per instance, though, other types are restricted to
|
||||
* one metatable per type.
|
||||
*
|
||||
* Since metatables on non-tables can only be set through Java and not Lua,
|
||||
* this function should be overridden for each value type as necessary.
|
||||
*
|
||||
* @return null if there is no meta-table
|
||||
*/
|
||||
public LTable luaGetMetatable() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Valid for tables */
|
||||
public void luaSetMetatable(LValue metatable) {
|
||||
luaUnsupportedOperation();
|
||||
}
|
||||
|
||||
/** Valid for all types: return the type of this value as an LString */
|
||||
public abstract LString luaGetType();
|
||||
|
||||
}
|
||||
81
src/main/java/lua/value/Type.java
Normal file
81
src/main/java/lua/value/Type.java
Normal file
@@ -0,0 +1,81 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2007 LuaJ. 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 lua.value;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class Type implements Serializable, Comparable {
|
||||
private static final long serialVersionUID = 877640303374122782L;
|
||||
|
||||
public static Type bool = new Type("boolean");
|
||||
public static Type function = new Type("function");
|
||||
public static Type nil = new Type("nil");
|
||||
public static Type number = new Type("number");
|
||||
public static Type string = new Type("string");
|
||||
public static Type table = new Type("table");
|
||||
public static Type thread = new Type("thread");
|
||||
public static Type userdata = new Type("userdata");
|
||||
protected static Type[] VALUES = new Type[] {
|
||||
bool,
|
||||
function,
|
||||
nil,
|
||||
number,
|
||||
string,
|
||||
table,
|
||||
thread,
|
||||
userdata
|
||||
};
|
||||
protected static int ORDINAL = 0;
|
||||
|
||||
private String name;
|
||||
private int ordinal;
|
||||
Type(String name) {
|
||||
this.name = name;
|
||||
this.ordinal = ORDINAL++;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Enum#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public static Type valueOf(String strValue) {
|
||||
Type[] values = Type.VALUES;
|
||||
for (Type value : values) {
|
||||
if (value.toString().equals(strValue)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("String '" + strValue + "' cannot be converted to enum Type");
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Comparable#compareTo(java.lang.Object)
|
||||
*/
|
||||
public int compareTo(Object o) {
|
||||
return this.ordinal - ((Type)o).ordinal;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user