Initial draft of interpreter. Lua compiled "chunks" can be unmarshalled. Approximately half of bytecodes implemented in some form or another.
This commit is contained in:
8
.classpath
Normal file
8
.classpath
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src/main/java"/>
|
||||
<classpathentry kind="src" path="src/test/java"/>
|
||||
<classpathentry kind="src" path="src/test/res"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
17
.project
Normal file
17
.project
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>luaj-vm</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
13
pom.xml
Normal file
13
pom.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>luaj</groupId>
|
||||
<artifactId>luaj</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<name>LuaJ Interpreter</name>
|
||||
|
||||
<build>
|
||||
<finalName>LuaJ</finalName>
|
||||
</build>
|
||||
</project>
|
||||
33
src/main/java/lua/Builtin.java
Normal file
33
src/main/java/lua/Builtin.java
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package lua;
|
||||
|
||||
import lua.value.LFunction;
|
||||
import lua.value.LString;
|
||||
import lua.value.LTable;
|
||||
|
||||
final class Builtin extends LFunction {
|
||||
|
||||
static void addBuiltins(LTable table) {
|
||||
table.luaSetTable( new LString( "print" ), new Builtin(0) );
|
||||
}
|
||||
|
||||
private static final int PRINT = 0;
|
||||
private int id;
|
||||
Builtin( int id ) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
// perform a lua call
|
||||
public void luaStackCall(StackState state, int base, int nresults) {
|
||||
switch ( id ) {
|
||||
case PRINT:
|
||||
System.out.println( String.valueOf( state.stack[base+1] ) );
|
||||
return;
|
||||
default:
|
||||
luaUnsupportedOperation();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
49
src/main/java/lua/GlobalState.java
Normal file
49
src/main/java/lua/GlobalState.java
Normal file
@@ -0,0 +1,49 @@
|
||||
package lua;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
import lua.value.LTable;
|
||||
import lua.value.LValue;
|
||||
|
||||
/**
|
||||
** `global state', shared by all threads of this state
|
||||
*/
|
||||
public class GlobalState {
|
||||
|
||||
// typedef struct global_State {
|
||||
// stringtable strt; /* hash table for strings */
|
||||
Hashtable strt; /* hash table for strings */
|
||||
// lua_Alloc frealloc; /* function to reallocate memory */
|
||||
// void *ud; /* auxiliary data to `frealloc' */
|
||||
// lu_byte currentwhite;
|
||||
// lu_byte gcstate; /* state of garbage collector */
|
||||
// int sweepstrgc; /* position of sweep in `strt' */
|
||||
// GCObject *rootgc; /* list of all collectable objects */
|
||||
// GCObject **sweepgc; /* position of sweep in `rootgc' */
|
||||
// GCObject *gray; /* list of gray objects */
|
||||
// GCObject *grayagain; /* list of objects to be traversed atomically */
|
||||
// GCObject *weak; /* list of weak tables (to be cleared) */
|
||||
// GCObject *tmudata; /* last element of list of userdata to be GC */
|
||||
// Mbuffer buff; /* temporary buffer for string concatentation */
|
||||
StringBuffer buff; /* temporary buffer for string concatentation */
|
||||
// lu_mem GCthreshold;
|
||||
// lu_mem totalbytes; /* number of bytes currently allocated */
|
||||
// lu_mem estimate; /* an estimate of number of bytes actually in use */
|
||||
// lu_mem gcdept; /* how much GC is `behind schedule' */
|
||||
// int gcpause; /* size of pause between successive GCs */
|
||||
// int gcstepmul; /* GC `granularity' */
|
||||
// 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;
|
||||
//
|
||||
public static LValue getGlobalsTable() {
|
||||
LTable table = new LTable();
|
||||
Builtin.addBuiltins( table );
|
||||
return table;
|
||||
}
|
||||
}
|
||||
383
src/main/java/lua/Lua.java
Normal file
383
src/main/java/lua/Lua.java
Normal file
@@ -0,0 +1,383 @@
|
||||
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;
|
||||
|
||||
|
||||
// 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 SET_OPCODE(int i,int o) {
|
||||
return (i & (MASK_NOT_OP)) | ((o & MAX_OP) << POS_OP);
|
||||
}
|
||||
|
||||
public static int GETARG_A(int i) {
|
||||
return (i >> POS_A) & MAXARG_A;
|
||||
}
|
||||
public static int SETARG_A(int i,int u) {
|
||||
return (i & (MASK_NOT_A)) | ((u & MAXARG_A) << POS_A);
|
||||
}
|
||||
|
||||
public static int GETARG_B(int i) {
|
||||
return (i >> POS_B) & MAXARG_B;
|
||||
}
|
||||
public static int SETARG_B(int i,int u) {
|
||||
return (i & (MASK_NOT_B)) | ((u & MAXARG_B) << POS_B);
|
||||
}
|
||||
|
||||
public static int GETARG_C(int i) {
|
||||
return (i >> POS_C) & MAXARG_C;
|
||||
}
|
||||
public static int SETARG_C(int i,int u) {
|
||||
return (i & (MASK_NOT_C)) | ((u & MAXARG_C) << POS_C);
|
||||
}
|
||||
|
||||
public static int GETARG_Bx(int i) {
|
||||
return (i >> POS_Bx) & MAXARG_Bx;
|
||||
}
|
||||
public static int SETARG_Bx(int i,int u) {
|
||||
return (i & (MASK_NOT_Bx)) | ((u & MAXARG_Bx) << POS_Bx);
|
||||
}
|
||||
|
||||
public static int GETARG_sBx(int i) {
|
||||
return ((i >> POS_Bx) & MAXARG_Bx) - MAXARG_sBx;
|
||||
}
|
||||
public static int SETARG_sBx(int i,int u) {
|
||||
return (i & (MASK_NOT_Bx)) | ((u + MAXARG_sBx) << POS_Bx);
|
||||
}
|
||||
|
||||
public static int CREATE_ABC(int o, int a, int b, int c) {
|
||||
return (o<<POS_OP) | (a<<POS_A) | (b<<POS_B) | (c<<POS_C);
|
||||
}
|
||||
public static int CREATE_ABx(int o, int a, int bc) {
|
||||
return (o<<POS_OP) | (a<<POS_A) | (bc<<POS_Bx);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** 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,
|
||||
};
|
||||
|
||||
|
||||
/** number of list items to accumulate before a SETLIST instruction */
|
||||
public static final int LFIELDS_PER_FLUSH = 50;
|
||||
|
||||
}
|
||||
23
src/main/java/lua/io/Closure.java
Normal file
23
src/main/java/lua/io/Closure.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package lua.io;
|
||||
|
||||
import lua.StackState;
|
||||
import lua.value.LValue;
|
||||
|
||||
public class Closure extends LValue {
|
||||
public LValue env;
|
||||
public Proto p;
|
||||
public UpVal[] upVals;
|
||||
public Closure(StackState state, Proto p) {
|
||||
this.env = state.gt();
|
||||
this.p = p;
|
||||
upVals = new UpVal[p.nups];
|
||||
for ( int i=0; i<p.nups; i++ )
|
||||
upVals[i] = new UpVal();
|
||||
}
|
||||
|
||||
|
||||
// perform a lua call
|
||||
public void luaStackCall(StackState state, int base, int nresults) {
|
||||
state.vmExecute( this, base+1 );
|
||||
}
|
||||
}
|
||||
432
src/main/java/lua/io/LoadState.java
Normal file
432
src/main/java/lua/io/LoadState.java
Normal file
@@ -0,0 +1,432 @@
|
||||
package lua.io;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import lua.StackState;
|
||||
import lua.value.LBoolean;
|
||||
import lua.value.LDouble;
|
||||
import lua.value.LInteger;
|
||||
import lua.value.LNil;
|
||||
import lua.value.LNumber;
|
||||
import lua.value.LValue;
|
||||
import lua.value.LString;
|
||||
|
||||
/*
|
||||
** Function Prototypes
|
||||
*/
|
||||
public class LoadState {
|
||||
|
||||
/** mark for precompiled code (`<esc>Lua') */
|
||||
public static final String LUA_SIGNATURE = "\033Lua";
|
||||
|
||||
|
||||
/** for header of binary files -- this is Lua 5.1 */
|
||||
public static final int LUAC_VERSION = 0x51;
|
||||
|
||||
/** for header of binary files -- this is the official format */
|
||||
public static final int LUAC_FORMAT = 0;
|
||||
|
||||
/** size of header of binary files */
|
||||
public static final int LUAC_HEADERSIZE = 12;
|
||||
|
||||
/** expected lua header bytes */
|
||||
private static final int LUAC_HEADER_SIGNATURE = ('\033'<<24) | ('L'<<16) | ('u'<<8) | ('a');
|
||||
|
||||
// values read from the header
|
||||
private int luacVersion;
|
||||
private int luacFormat;
|
||||
private boolean luacLittleEndian;
|
||||
private int luacSizeofInt;
|
||||
private int luacSizeofSizeT;
|
||||
private int luacSizeofInstruction;
|
||||
private int luacSizeofLuaNumber;
|
||||
private boolean luacIsNumberIntegral;
|
||||
|
||||
/** The lua state that is loading the code */
|
||||
private StackState L;
|
||||
|
||||
/** input stream from which we are loading */
|
||||
private DataInputStream is;
|
||||
|
||||
/** Name of what is being loaded? */
|
||||
String name;
|
||||
|
||||
|
||||
private static final int LUA_TNONE = (-1);
|
||||
|
||||
private static final int LUA_TNIL = 0;
|
||||
private static final int LUA_TBOOLEAN = 1;
|
||||
private static final int LUA_TLIGHTUSERDATA = 2;
|
||||
private static final int LUA_TNUMBER = 3;
|
||||
private static final int LUA_TSTRING = 4;
|
||||
private static final int LUA_TTABLE = 5;
|
||||
private static final int LUA_TFUNCTION = 6;
|
||||
private static final int LUA_TUSERDATA = 7;
|
||||
private static final int LUA_TTHREAD = 8;
|
||||
|
||||
// /*
|
||||
// ** $Id$
|
||||
// ** load precompiled Lua chunks
|
||||
// ** See Copyright Notice in lua.h
|
||||
// */
|
||||
//
|
||||
// #include <string.h>
|
||||
//
|
||||
// #define lundump_c
|
||||
// #define LUA_CORE
|
||||
//
|
||||
// #include "lua.h"
|
||||
//
|
||||
// #include "ldebug.h"
|
||||
// #include "ldo.h"
|
||||
// #include "lfunc.h"
|
||||
// #include "lmem.h"
|
||||
// #include "lobject.h"
|
||||
// #include "lstring.h"
|
||||
// #include "lundump.h"
|
||||
// #include "lzio.h"
|
||||
//
|
||||
// typedef struct {
|
||||
// lua_State* L;
|
||||
// ZIO* Z;
|
||||
// Mbuffer* b;
|
||||
// const char* name;
|
||||
// } LoadState;
|
||||
//
|
||||
// #ifdef LUAC_TRUST_BINARIES
|
||||
// #define IF(c,s)
|
||||
// #else
|
||||
// #define IF(c,s) if (c) error(S,s)
|
||||
//
|
||||
// static void error(LoadState* S, const char* why)
|
||||
// {
|
||||
// luaO_pushfstring(S->L,"%s: %s in precompiled chunk",S->name,why);
|
||||
// luaD_throw(S->L,LUA_ERRSYNTAX);
|
||||
// }
|
||||
// #endif
|
||||
//
|
||||
// #define LoadMem(S,b,n,size) LoadBlock(S,b,(n)*(size))
|
||||
// #define LoadByte(S) (lu_byte)LoadChar(S)
|
||||
// #define LoadVar(S,x) LoadMem(S,&x,1,sizeof(x))
|
||||
// #define LoadVector(S,b,n,size) LoadMem(S,b,n,size)
|
||||
//
|
||||
// static void LoadBlock(LoadState* S, void* b, size_t size)
|
||||
// {
|
||||
// size_t r=luaZ_read(S->Z,b,size);
|
||||
// IF (r!=0, "unexpected end");
|
||||
// }
|
||||
//
|
||||
// static int LoadChar(LoadState* S)
|
||||
// {
|
||||
// char x;
|
||||
// LoadVar(S,x);
|
||||
// return x;
|
||||
// }
|
||||
int loadByte() throws IOException {
|
||||
return is.readUnsignedByte();
|
||||
}
|
||||
//
|
||||
// static int LoadInt(LoadState* S)
|
||||
// {
|
||||
// int x;
|
||||
// LoadVar(S,x);
|
||||
// IF (x<0, "bad integer");
|
||||
// return x;
|
||||
// }
|
||||
int loadInt() throws IOException {
|
||||
if ( this.luacLittleEndian ) {
|
||||
int a = is.readUnsignedByte();
|
||||
int b = is.readUnsignedByte();
|
||||
int c = is.readUnsignedByte();
|
||||
int d = is.readUnsignedByte();
|
||||
return (d << 24) | (c << 16) | (b << 8) | a;
|
||||
} else {
|
||||
return is.readInt();
|
||||
}
|
||||
}
|
||||
|
||||
long loadInt64() throws IOException {
|
||||
int a,b;
|
||||
if ( this.luacLittleEndian ) {
|
||||
a = loadInt();
|
||||
b = loadInt();
|
||||
} else {
|
||||
b = loadInt();
|
||||
a = loadInt();
|
||||
}
|
||||
return (((long)b)<<32) | (((long)a)&0xffffffffL);
|
||||
}
|
||||
//
|
||||
// static lua_Number LoadNumber(LoadState* S)
|
||||
// {
|
||||
// lua_Number x;
|
||||
// LoadVar(S,x);
|
||||
// return x;
|
||||
// }
|
||||
//
|
||||
// static TString* LoadString(LoadState* S)
|
||||
// {
|
||||
// size_t size;
|
||||
// LoadVar(S,size);
|
||||
// if (size==0)
|
||||
// return NULL;
|
||||
// else
|
||||
// {
|
||||
// char* s=luaZ_openspace(S->L,S->b,size);
|
||||
// LoadBlock(S,s,size);
|
||||
// return luaS_newlstr(S->L,s,size-1); /* remove trailing '\0' */
|
||||
// }
|
||||
// }
|
||||
LString loadString() throws IOException {
|
||||
int size = loadInt();
|
||||
if ( size == 0 )
|
||||
return null;
|
||||
byte[] bytes = new byte[size];
|
||||
is.readFully( bytes );
|
||||
String s = new String( bytes, 0, size-1 );
|
||||
return new LString( s );
|
||||
}
|
||||
|
||||
LNumber loadNumber() throws IOException {
|
||||
if ( this.luacIsNumberIntegral ) {
|
||||
int value = loadInt();
|
||||
return new LInteger( value );
|
||||
} else {
|
||||
long bits = loadInt64();
|
||||
double value = Double.longBitsToDouble(bits);
|
||||
return new LDouble( value );
|
||||
}
|
||||
}
|
||||
//
|
||||
// static void LoadCode(LoadState* S, Proto* f)
|
||||
// {
|
||||
// int n=LoadInt(S);
|
||||
// f->code=luaM_newvector(S->L,n,Instruction);
|
||||
// f->sizecode=n;
|
||||
// LoadVector(S,f->code,n,sizeof(Instruction));
|
||||
// }
|
||||
public void loadCode( Proto f ) throws IOException {
|
||||
int n = loadInt();
|
||||
int[] code = new int[n];
|
||||
for ( int i=0; i<n; i++ )
|
||||
code[i] = loadInt();
|
||||
f.code = code;
|
||||
}
|
||||
//
|
||||
// static Proto* LoadFunction(LoadState* S, TString* p);
|
||||
//
|
||||
// static void LoadConstants(LoadState* S, Proto* f)
|
||||
// {
|
||||
// int i,n;
|
||||
// n=LoadInt(S);
|
||||
// f->k=luaM_newvector(S->L,n,TValue);
|
||||
// f->sizek=n;
|
||||
// for (i=0; i<n; i++) setnilvalue(&f->k[i]);
|
||||
// for (i=0; i<n; i++)
|
||||
// {
|
||||
// TValue* o=&f->k[i];
|
||||
// int t=LoadChar(S);
|
||||
// switch (t)
|
||||
// {
|
||||
// case LUA_TNIL:
|
||||
// setnilvalue(o);
|
||||
// break;
|
||||
// case LUA_TBOOLEAN:
|
||||
// setbvalue(o,LoadChar(S));
|
||||
// break;
|
||||
// case LUA_TNUMBER:
|
||||
// setnvalue(o,LoadNumber(S));
|
||||
// break;
|
||||
// case LUA_TSTRING:
|
||||
// setsvalue2n(S->L,o,LoadString(S));
|
||||
// break;
|
||||
// default:
|
||||
// IF (1, "bad constant");
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// n=LoadInt(S);
|
||||
// f->p=luaM_newvector(S->L,n,Proto*);
|
||||
// f->sizep=n;
|
||||
// for (i=0; i<n; i++) f->p[i]=NULL;
|
||||
// for (i=0; i<n; i++) f->p[i]=LoadFunction(S,f->source);
|
||||
// }
|
||||
void loadConstants(Proto f) throws IOException {
|
||||
int n = loadInt();
|
||||
LValue[] values = new LValue[n];
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
switch ( loadByte() ) {
|
||||
case LUA_TNIL:
|
||||
values[i] = LNil.NIL;
|
||||
break;
|
||||
case LUA_TBOOLEAN:
|
||||
values[i] = (0 != loadByte()? LBoolean.TRUE: LBoolean.FALSE);
|
||||
break;
|
||||
case LUA_TNUMBER:
|
||||
values[i] = loadNumber();
|
||||
break;
|
||||
case LUA_TSTRING:
|
||||
values[i] = loadString();
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("bad constant");
|
||||
}
|
||||
}
|
||||
f.k = values;
|
||||
|
||||
n = loadInt();
|
||||
Proto[] protos = new Proto[n];
|
||||
for ( int i=0; i<n; i++ )
|
||||
protos[i] = loadFunction(f.source);
|
||||
f.p = protos;
|
||||
}
|
||||
//
|
||||
// static void LoadDebug(LoadState* S, Proto* f)
|
||||
// {
|
||||
// int i,n;
|
||||
// n=LoadInt(S);
|
||||
// f->lineinfo=luaM_newvector(S->L,n,int);
|
||||
// f->sizelineinfo=n;
|
||||
// LoadVector(S,f->lineinfo,n,sizeof(int));
|
||||
|
||||
// n=LoadInt(S);
|
||||
// f->locvars=luaM_newvector(S->L,n,LocVar);
|
||||
// f->sizelocvars=n;
|
||||
// for (i=0; i<n; i++) f->locvars[i].varname=NULL;
|
||||
// for (i=0; i<n; i++)
|
||||
// {
|
||||
// f->locvars[i].varname=LoadString(S);
|
||||
// f->locvars[i].startpc=LoadInt(S);
|
||||
// f->locvars[i].endpc=LoadInt(S);
|
||||
// }
|
||||
|
||||
// n=LoadInt(S);
|
||||
// f->upvalues=luaM_newvector(S->L,n,TString*);
|
||||
// f->sizeupvalues=n;
|
||||
// for (i=0; i<n; i++) f->upvalues[i]=NULL;
|
||||
// for (i=0; i<n; i++) f->upvalues[i]=LoadString(S);
|
||||
// }
|
||||
void loadDebug( Proto f ) throws IOException {
|
||||
int n = loadInt();
|
||||
f.lineinfo = new int[n];
|
||||
for ( int i=0; i<n; i++ )
|
||||
f.lineinfo[i] = loadInt();
|
||||
|
||||
n = loadInt();
|
||||
f.locvars = new LocVars[n];
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
LString varname = loadString();
|
||||
int startpc = loadInt();
|
||||
int endpc = loadInt();
|
||||
f.locvars[i] = new LocVars(varname, startpc, endpc);
|
||||
}
|
||||
|
||||
n = loadInt();
|
||||
f.upvalues = new LString[n];
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
f.upvalues[i] = loadString();
|
||||
}
|
||||
}
|
||||
//
|
||||
// static Proto* LoadFunction(LoadState* S, TString* p)
|
||||
// {
|
||||
// Proto* f=luaF_newproto(S->L);
|
||||
// setptvalue2s(S->L,S->L->top,f); incr_top(S->L);
|
||||
// f->source=LoadString(S); if (f->source==NULL) f->source=p;
|
||||
// f->linedefined=LoadInt(S);
|
||||
// f->lastlinedefined=LoadInt(S);
|
||||
// f->nups=LoadByte(S);
|
||||
// f->numparams=LoadByte(S);
|
||||
// f->is_vararg=LoadByte(S);
|
||||
// f->maxstacksize=LoadByte(S);
|
||||
// LoadCode(S,f);
|
||||
// LoadConstants(S,f);
|
||||
// LoadDebug(S,f);
|
||||
// IF (!luaG_checkcode(f), "bad code");
|
||||
// S->L->top--;
|
||||
// return f;
|
||||
// }
|
||||
public Proto loadFunction(LString p) throws IOException {
|
||||
Proto f = new Proto(this.L);
|
||||
this.L.push(f);
|
||||
f.source = loadString();
|
||||
f.linedefined = loadInt();
|
||||
f.lastlinedefined = loadInt();
|
||||
f.nups = loadByte();
|
||||
f.numparams = loadByte();
|
||||
f.is_vararg = (0 != loadByte());
|
||||
f.maxstacksize = loadByte();
|
||||
loadCode(f);
|
||||
loadConstants(f);
|
||||
loadDebug(f);
|
||||
|
||||
// TODO: add check here, for debugging purposes, I believe
|
||||
// see ldebug.c
|
||||
// IF (!luaG_checkcode(f), "bad code");
|
||||
|
||||
this.L.pop();
|
||||
return f;
|
||||
}
|
||||
//
|
||||
// static void LoadHeader(LoadState* S)
|
||||
// {
|
||||
// char h[LUAC_HEADERSIZE];
|
||||
// char s[LUAC_HEADERSIZE];
|
||||
// luaU_header(h);
|
||||
// LoadBlock(S,s,LUAC_HEADERSIZE);
|
||||
// IF (memcmp(h,s,LUAC_HEADERSIZE)!=0, "bad header");
|
||||
// }
|
||||
public void loadHeader() throws IOException {
|
||||
int sig = is.readInt();
|
||||
luacVersion = is.readByte();
|
||||
luacFormat = is.readByte();
|
||||
luacLittleEndian = (0 != is.readByte());
|
||||
luacSizeofInt = is.readByte();
|
||||
luacSizeofSizeT = is.readByte();
|
||||
luacSizeofInstruction = is.readByte();
|
||||
luacSizeofLuaNumber = is.readByte();
|
||||
luacIsNumberIntegral = (0 != is.readByte());
|
||||
if ( sig != LUAC_HEADER_SIGNATURE )
|
||||
throw new IllegalArgumentException("bad signature");
|
||||
}
|
||||
//
|
||||
// /*
|
||||
// ** load precompiled chunk
|
||||
// */
|
||||
// Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name)
|
||||
// {
|
||||
// LoadState S;
|
||||
// if (*name=='@' || *name=='=')
|
||||
// S.name=name+1;
|
||||
// else if (*name==LUA_SIGNATURE[0])
|
||||
// S.name="binary string";
|
||||
// else
|
||||
// S.name=name;
|
||||
// S.L=L;
|
||||
// S.Z=Z;
|
||||
// S.b=buff;
|
||||
// LoadHeader(&S);
|
||||
// return LoadFunction(&S,luaS_newliteral(L,"=?"));
|
||||
// }
|
||||
|
||||
public static Proto undump( StackState L, InputStream stream, String name ) throws IOException {
|
||||
String sname = name;
|
||||
if ( name.startsWith("@") || name.startsWith("=") )
|
||||
sname = name.substring(1);
|
||||
else if ( name.startsWith("\033") )
|
||||
sname = "binary string";
|
||||
LoadState s = new LoadState( L, stream, sname );
|
||||
s.loadHeader();
|
||||
LString literal = new LString(L, "=?");
|
||||
return s.loadFunction( literal );
|
||||
}
|
||||
|
||||
/** Private constructor for create a load state */
|
||||
private LoadState( StackState L, InputStream stream, String name ) {
|
||||
this.L = L;
|
||||
this.name = name;
|
||||
this.is = new DataInputStream( stream );
|
||||
}
|
||||
}
|
||||
16
src/main/java/lua/io/LocVars.java
Normal file
16
src/main/java/lua/io/LocVars.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package lua.io;
|
||||
|
||||
import lua.value.LString;
|
||||
|
||||
public class LocVars {
|
||||
final LString m_varname;
|
||||
final int m_startpc;
|
||||
final int m_endpc;
|
||||
|
||||
public LocVars(LString varname, int startpc, int endpc) {
|
||||
this.m_varname = varname;
|
||||
this.m_startpc = startpc;
|
||||
this.m_endpc = endpc;
|
||||
}
|
||||
|
||||
}
|
||||
39
src/main/java/lua/io/Proto.java
Normal file
39
src/main/java/lua/io/Proto.java
Normal file
@@ -0,0 +1,39 @@
|
||||
package lua.io;
|
||||
|
||||
import lua.StackState;
|
||||
import lua.value.LValue;
|
||||
import lua.value.LString;
|
||||
|
||||
/*
|
||||
** Function Prototypes
|
||||
*/
|
||||
public class Proto extends LValue {
|
||||
// TODO: what to do with state?
|
||||
public Proto(StackState l) {
|
||||
}
|
||||
|
||||
public LValue[] k; /* constants used by the function */
|
||||
// TValue *k; /* constants used by the function */
|
||||
// Instruction *code;
|
||||
public int[] code;
|
||||
// struct Proto **p; /* functions defined inside the function */
|
||||
public Proto[] p;
|
||||
// int *lineinfo; /* map from opcodes to source lines */
|
||||
public int[] lineinfo;
|
||||
// struct LocVar *locvars; /* information about local variables */
|
||||
public LocVars[] locvars;
|
||||
// TString **upvalues; /* upvalue names */
|
||||
public LString[] upvalues;
|
||||
public LString source;
|
||||
public int nups;
|
||||
public int sizeupvalues;
|
||||
public int sizek; /* size of `k' */
|
||||
public int sizecode;
|
||||
public int sizep; /* size of `p' */
|
||||
public int linedefined;
|
||||
public int lastlinedefined;
|
||||
// GCObject *gclist;
|
||||
public int numparams;
|
||||
public boolean is_vararg;
|
||||
public int maxstacksize;
|
||||
}
|
||||
5
src/main/java/lua/io/UpVal.java
Normal file
5
src/main/java/lua/io/UpVal.java
Normal file
@@ -0,0 +1,5 @@
|
||||
package lua.io;
|
||||
|
||||
public class UpVal {
|
||||
|
||||
}
|
||||
28
src/main/java/lua/value/LBoolean.java
Normal file
28
src/main/java/lua/value/LBoolean.java
Normal file
@@ -0,0 +1,28 @@
|
||||
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);
|
||||
|
||||
private final String m_name;
|
||||
private final boolean m_value;
|
||||
|
||||
private LBoolean( String name, boolean value ) {
|
||||
this.m_name = name;
|
||||
this.m_value = value;
|
||||
}
|
||||
|
||||
public final String luaAsString() {
|
||||
return m_name;
|
||||
}
|
||||
|
||||
public final boolean luaAsBoolean() {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
public final static LBoolean valueOf(boolean value) {
|
||||
return value? TRUE: FALSE;
|
||||
}
|
||||
}
|
||||
48
src/main/java/lua/value/LDouble.java
Normal file
48
src/main/java/lua/value/LDouble.java
Normal file
@@ -0,0 +1,48 @@
|
||||
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 String luaAsString() {
|
||||
return String.valueOf(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 % rhs );
|
||||
case Lua.OP_POW: return new LDouble( Math.pow(lhs, rhs) );
|
||||
}
|
||||
return luaUnsupportedOperation();
|
||||
}
|
||||
|
||||
public int luaAsInt() {
|
||||
return (int) m_value;
|
||||
}
|
||||
|
||||
}
|
||||
7
src/main/java/lua/value/LFunction.java
Normal file
7
src/main/java/lua/value/LFunction.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package lua.value;
|
||||
|
||||
public class LFunction extends LValue {
|
||||
|
||||
|
||||
|
||||
}
|
||||
43
src/main/java/lua/value/LInteger.java
Normal file
43
src/main/java/lua/value/LInteger.java
Normal file
@@ -0,0 +1,43 @@
|
||||
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 int luaAsInt() {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
public String luaAsString() {
|
||||
return String.valueOf(m_value);
|
||||
}
|
||||
|
||||
// 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 % rhs );
|
||||
case Lua.OP_POW: return new LInteger( (int) Math.pow(m_value, rhs) );
|
||||
}
|
||||
return luaUnsupportedOperation();
|
||||
}
|
||||
|
||||
// binary operations on mixed integer, double
|
||||
public LValue luaBinOpDouble(int opcode, double rhs) {
|
||||
return LDouble.luaBinOpDoubleDouble(opcode, (double) m_value, rhs );
|
||||
}
|
||||
}
|
||||
13
src/main/java/lua/value/LNil.java
Normal file
13
src/main/java/lua/value/LNil.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package lua.value;
|
||||
|
||||
public final class LNil extends LValue {
|
||||
public static final LNil NIL = new LNil();
|
||||
|
||||
public final String luaAsString() {
|
||||
return "nil";
|
||||
}
|
||||
|
||||
public boolean luaAsBoolean() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
6
src/main/java/lua/value/LNumber.java
Normal file
6
src/main/java/lua/value/LNumber.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package lua.value;
|
||||
|
||||
abstract
|
||||
public class LNumber extends LValue {
|
||||
|
||||
}
|
||||
21
src/main/java/lua/value/LString.java
Normal file
21
src/main/java/lua/value/LString.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package lua.value;
|
||||
|
||||
import lua.StackState;
|
||||
|
||||
public class LString extends LValue {
|
||||
|
||||
final String m_string;
|
||||
|
||||
public LString(String string) {
|
||||
this.m_string = string;
|
||||
}
|
||||
|
||||
// TODO: what to do with LuaState?
|
||||
public LString(StackState l, String string) {
|
||||
this(string);
|
||||
}
|
||||
|
||||
public String luaAsString() {
|
||||
return m_string;
|
||||
}
|
||||
}
|
||||
29
src/main/java/lua/value/LTable.java
Normal file
29
src/main/java/lua/value/LTable.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package lua.value;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.Vector;
|
||||
|
||||
public class LTable extends LValue {
|
||||
|
||||
private Hashtable m_hash = new Hashtable();
|
||||
private Vector m_array = new Vector();
|
||||
|
||||
public LTable() {
|
||||
}
|
||||
|
||||
public LTable(int narray, int nhash) {
|
||||
}
|
||||
|
||||
public void luaSetTable(LValue key, LValue val) {
|
||||
m_hash.put( key.luaAsString(), val );
|
||||
m_array.add( val );
|
||||
}
|
||||
|
||||
public LValue luaGetTable(LValue key) {
|
||||
return (LValue) m_hash.get( key.luaAsString() );
|
||||
}
|
||||
|
||||
public String luaAsString() {
|
||||
return m_hash.toString();
|
||||
}
|
||||
}
|
||||
5
src/main/java/lua/value/LThread.java
Normal file
5
src/main/java/lua/value/LThread.java
Normal file
@@ -0,0 +1,5 @@
|
||||
package lua.value;
|
||||
|
||||
public class LThread extends LValue {
|
||||
|
||||
}
|
||||
65
src/main/java/lua/value/LValue.java
Normal file
65
src/main/java/lua/value/LValue.java
Normal file
@@ -0,0 +1,65 @@
|
||||
package lua.value;
|
||||
|
||||
import lua.StackState;
|
||||
|
||||
abstract
|
||||
public class LValue {
|
||||
|
||||
protected static LValue luaUnsupportedOperation() {
|
||||
throw new java.lang.UnsupportedOperationException();
|
||||
}
|
||||
|
||||
// test if value is true
|
||||
public boolean luaAsBoolean() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// perform a lua call
|
||||
public void luaStackCall(StackState state, int base, int nresults) {
|
||||
luaUnsupportedOperation();
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
/** set a value in a table
|
||||
*/
|
||||
public void luaSetTable(LValue key, LValue value) {
|
||||
luaUnsupportedOperation();
|
||||
}
|
||||
|
||||
/** Get a value from a table */
|
||||
public LValue luaGetTable(LValue value) {
|
||||
return luaUnsupportedOperation();
|
||||
}
|
||||
|
||||
/** Get the value as a String
|
||||
*/
|
||||
public String luaAsString() {
|
||||
return super.toString();
|
||||
}
|
||||
|
||||
/** Override standard toString with lua String conversion by default */
|
||||
public String toString() {
|
||||
return luaAsString();
|
||||
}
|
||||
|
||||
/** Return value as an integer */
|
||||
public int luaAsInt() {
|
||||
luaUnsupportedOperation();
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
49
src/test/java/LuacRunner.java
Normal file
49
src/test/java/LuacRunner.java
Normal file
@@ -0,0 +1,49 @@
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import lua.StackState;
|
||||
import lua.io.Closure;
|
||||
import lua.io.LoadState;
|
||||
import lua.io.Proto;
|
||||
import lua.value.LString;
|
||||
|
||||
/**
|
||||
* Program to run a compiled lua chunk for test purposes
|
||||
*
|
||||
* @author jim_roseborough
|
||||
*/
|
||||
public class LuacRunner {
|
||||
|
||||
public static void main( String[] args ) throws IOException {
|
||||
|
||||
// get script name
|
||||
String script = (args.length>0? args[0]: "src/test/res/test1.luac");
|
||||
System.out.println("loading '"+script+"'");
|
||||
|
||||
// new lua state
|
||||
StackState state = new StackState();
|
||||
|
||||
// push args onto stack
|
||||
for ( int i=1; i<args.length; i++ )
|
||||
state.push(new LString(args[i]));
|
||||
|
||||
// load the file
|
||||
InputStream is = new FileInputStream( script );
|
||||
Proto p = LoadState.undump(state, is, script);
|
||||
|
||||
// create closure to execute
|
||||
Closure c = new Closure( state, p );
|
||||
state.push( c );
|
||||
for ( int i=0; i<args.length; i++ )
|
||||
state.push( new LString(args[i]) );
|
||||
state.docall(args.length, false);
|
||||
|
||||
// print result?
|
||||
System.out.println("stack:");
|
||||
for ( int i=0; i<state.top; i++ )
|
||||
System.out.println(" ["+i+"]="+state.stack[i] );
|
||||
|
||||
}
|
||||
}
|
||||
7
src/test/res/compile.sh
Normal file
7
src/test/res/compile.sh
Normal file
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
LUA_HOME=/cygdrive/c/programs/lua5.1
|
||||
for x in test1 test2 test3 test4
|
||||
do
|
||||
echo compiling $x
|
||||
${LUA_HOME}/luac5.1.exe -l -o ${x}.luac ${x}.lua
|
||||
done
|
||||
5
src/test/res/test1.lua
Normal file
5
src/test/res/test1.lua
Normal file
@@ -0,0 +1,5 @@
|
||||
a = 123 + 456
|
||||
print( a )
|
||||
|
||||
|
||||
|
||||
BIN
src/test/res/test1.luac
Normal file
BIN
src/test/res/test1.luac
Normal file
Binary file not shown.
10
src/test/res/test2.lua
Normal file
10
src/test/res/test2.lua
Normal file
@@ -0,0 +1,10 @@
|
||||
function sum(a,b,c,d) -- "sum" method
|
||||
return a+b+c+d -- return sum
|
||||
end
|
||||
print( sum( 1, 2, 3, 4 ) )
|
||||
print( sum( 5, 6, 7 ) )
|
||||
print( sum( 9, 10, 11, 12, 13, 14 ) )
|
||||
print( sum( sum(1,2,3,4), sum(5,6,7), sum(9,10,11,12,13,14), 15 ) )
|
||||
|
||||
|
||||
|
||||
BIN
src/test/res/test2.luac
Normal file
BIN
src/test/res/test2.luac
Normal file
Binary file not shown.
6
src/test/res/test3.lua
Normal file
6
src/test/res/test3.lua
Normal file
@@ -0,0 +1,6 @@
|
||||
a = func(1, 2, 3)
|
||||
a = func(3, 2, 1)
|
||||
a = func(func(),func(),func())
|
||||
|
||||
|
||||
|
||||
BIN
src/test/res/test3.luac
Normal file
BIN
src/test/res/test3.luac
Normal file
Binary file not shown.
8
src/test/res/test4.lua
Normal file
8
src/test/res/test4.lua
Normal file
@@ -0,0 +1,8 @@
|
||||
function Point(x, y) -- "Point" object constructor
|
||||
return { x = x, y = y } -- Creates and returns a new object (table)
|
||||
end
|
||||
array = { Point(10, 20), Point(30, 40), Point(50, 60) } -- Creates array of points
|
||||
print(array[2].y) -- Prints 40
|
||||
|
||||
|
||||
|
||||
BIN
src/test/res/test4.luac
Normal file
BIN
src/test/res/test4.luac
Normal file
Binary file not shown.
Reference in New Issue
Block a user