added back the files that were accidentally deleted

This commit is contained in:
Shu Lei
2007-10-03 23:33:45 +00:00
parent 35d02b287e
commit 885397a74c
8 changed files with 1022 additions and 0 deletions

View File

@@ -0,0 +1,105 @@
/**
*
*/
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;
}
}

View File

@@ -0,0 +1,41 @@
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;
}
}

357
src/main/java/lua/Lua.java Normal file
View File

@@ -0,0 +1,357 @@
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,
};
}

197
src/main/java/lua/VM.java Normal file
View File

@@ -0,0 +1,197 @@
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);
}

View File

@@ -0,0 +1,27 @@
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();
}

View File

@@ -0,0 +1,182 @@
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();
}

View File

@@ -1,3 +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;
import java.io.IOException;

View File

@@ -0,0 +1,92 @@
package lua.io;
import java.util.Random;
import junit.framework.TestCase;
import lua.value.LDouble;
import lua.value.LInteger;
import lua.value.LNumber;
public class LoadStateTest extends TestCase {
double[] DOUBLE_VALUES = {
0.0,
1.0,
2.5,
10.0,
16.0,
16.125,
-1.0,
2.0,
-2.0,
-10.0,
-0.25,
-25,
Integer.MAX_VALUE,
Integer.MAX_VALUE - 1,
(double)Integer.MAX_VALUE + 1.0,
Integer.MIN_VALUE,
Integer.MIN_VALUE + 1,
(double)Integer.MIN_VALUE - 1.0,
Double.NEGATIVE_INFINITY,
Double.POSITIVE_INFINITY,
Double.MAX_VALUE,
Double.MAX_VALUE
};
public void testLongBitsToLuaNumber() {
for ( int i = 0; i < DOUBLE_VALUES.length; ++i ) {
double v = DOUBLE_VALUES[i];
long bits = Double.doubleToLongBits( v );
LNumber luaNumber = LoadState.longBitsToLuaNumber( bits );
assertEquals( v, luaNumber.luaAsDouble() );
if ( v != Integer.MIN_VALUE ) {
// Special case of MIN_VALUE is probably not worth dealing with.
// (Unlike zero, which is also a special case but much more common.)
assertEquals( "Value "+v+" (at index "+i+") can be represented as integer but was not",
luaNumber instanceof LInteger, v == (double)( (int) v ) );
}
}
}
private LNumber simpleBitsToLuaNumber( long bits ) {
double value = Double.longBitsToDouble( bits );
int valueAsInt = (int) value;
if ( value == (double) valueAsInt ) {
return new LInteger( valueAsInt );
} else {
return new LDouble( value );
}
}
public void testLongBitsToLuaNumberSpeed() {
long[] BITS = new long[ 500000 ];
Random r = new Random();
for ( int i = 0; i < DOUBLE_VALUES.length; ++i ) {
BITS[i] = Double.doubleToLongBits( DOUBLE_VALUES[i] );
}
for ( int i = DOUBLE_VALUES.length; i < BITS.length; i += 2 ) {
BITS[i ] = r.nextLong();
BITS[i+1] = Double.doubleToLongBits( r.nextDouble() );
}
long startTime = System.currentTimeMillis();
for ( int j = 0; j < BITS.length; ++j ) {
LoadState.longBitsToLuaNumber( BITS[j] );
}
long endTime = System.currentTimeMillis();
long complexConversionTime = endTime - startTime;
startTime = System.currentTimeMillis();
for ( int j = 0; j < BITS.length; ++j ) {
simpleBitsToLuaNumber( BITS[j] );
}
endTime = System.currentTimeMillis();
long simpleConversionTime = endTime - startTime;
assertTrue( complexConversionTime < simpleConversionTime );
}
}