Initial sources for planned 2.0 luaj vm release. Most interpreter features and library functions working.
This commit is contained in:
95
src/core/org/luaj/vm2/Buffer.java
Normal file
95
src/core/org/luaj/vm2/Buffer.java
Normal file
@@ -0,0 +1,95 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
|
||||
/**
|
||||
* String buffer for use in string library methods, optimized for production
|
||||
* of StrValue instances.
|
||||
*/
|
||||
public class Buffer {
|
||||
private static final int DEFAULT_CAPACITY = 64;
|
||||
|
||||
private byte[] bytes;
|
||||
private int length;
|
||||
|
||||
public Buffer() {
|
||||
this(DEFAULT_CAPACITY);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return new LuaString(bytes, 0, length).toString();
|
||||
}
|
||||
|
||||
public Buffer( int initialCapacity ) {
|
||||
bytes = new byte[ initialCapacity ];
|
||||
length = 0;
|
||||
}
|
||||
|
||||
public void append( byte b ) {
|
||||
ensureCapacity( length + 1 );
|
||||
bytes[ length++ ] = b;
|
||||
}
|
||||
|
||||
public void append( LuaValue val ) {
|
||||
append( val.strvalue() );
|
||||
}
|
||||
|
||||
public void append( LuaString str ) {
|
||||
final int alen = str.length();
|
||||
ensureCapacity( length + alen );
|
||||
str.copyInto( 0, bytes, length, alen );
|
||||
length += alen;
|
||||
}
|
||||
|
||||
public void append( String str ) {
|
||||
char[] chars = str.toCharArray();
|
||||
final int alen = LuaString.lengthAsUtf8( chars );
|
||||
ensureCapacity( length + alen );
|
||||
LuaString.encodeToUtf8( chars, bytes, length );
|
||||
length += alen;
|
||||
}
|
||||
|
||||
public void setLength( int length ) {
|
||||
ensureCapacity( length );
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
public LuaString tostrvalue() {
|
||||
return new LuaString( realloc( bytes, length ) );
|
||||
}
|
||||
|
||||
public void ensureCapacity( int minSize ) {
|
||||
if ( minSize > bytes.length )
|
||||
realloc( minSize );
|
||||
}
|
||||
|
||||
private void realloc( int minSize ) {
|
||||
bytes = realloc( bytes, Math.max( bytes.length * 2, minSize ) );
|
||||
}
|
||||
|
||||
private static byte[] realloc( byte[] b, int newSize ) {
|
||||
byte[] newBytes = new byte[ newSize ];
|
||||
System.arraycopy( b, 0, newBytes, 0, Math.min( b.length, newSize ) );
|
||||
return newBytes;
|
||||
}
|
||||
}
|
||||
316
src/core/org/luaj/vm2/LoadState.java
Normal file
316
src/core/org/luaj/vm2/LoadState.java
Normal file
@@ -0,0 +1,316 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/*
|
||||
** Loader to load compiled function prototypes
|
||||
*/
|
||||
public class LoadState {
|
||||
|
||||
/** format corresponding to non-number-patched lua, all numbers are floats or doubles */
|
||||
public static final int NUMBER_FORMAT_FLOATS_OR_DOUBLES = 0;
|
||||
|
||||
/** format corresponding to non-number-patched lua, all numbers are ints */
|
||||
public static final int NUMBER_FORMAT_INTS_ONLY = 1;
|
||||
|
||||
/** format corresponding to number-patched lua, all numbers are 32-bit (4 byte) ints */
|
||||
public static final int NUMBER_FORMAT_NUM_PATCH_INT32 = 4;
|
||||
|
||||
// type constants
|
||||
|
||||
public static final int LUA_TINT = (-2);
|
||||
public static final int LUA_TNONE = (-1);
|
||||
public static final int LUA_TNIL = 0;
|
||||
public static final int LUA_TBOOLEAN = 1;
|
||||
public static final int LUA_TLIGHTUSERDATA = 2;
|
||||
public static final int LUA_TNUMBER = 3;
|
||||
public static final int LUA_TSTRING = 4;
|
||||
public static final int LUA_TTABLE = 5;
|
||||
public static final int LUA_TFUNCTION = 6;
|
||||
public static final int LUA_TUSERDATA = 7;
|
||||
public static final int LUA_TTHREAD = 8;
|
||||
public static final int LUA_TVALUE = 9;
|
||||
|
||||
/** Interface for the compiler, if it is installed. */
|
||||
public interface LuaCompiler {
|
||||
public Prototype compile(int firstByte, InputStream stream, String name) throws IOException;
|
||||
}
|
||||
|
||||
/** Compiler instance, if installed */
|
||||
public static LuaCompiler compiler = null;
|
||||
|
||||
/** Signature byte indicating the file is a compiled binary chunk */
|
||||
private static final byte[] LUA_SIGNATURE = { '\033', 'L', 'u', 'a' };
|
||||
|
||||
/** Name for compiled chunks */
|
||||
public static final String SOURCE_BINARY_STRING = "binary string";
|
||||
|
||||
|
||||
/** 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;
|
||||
|
||||
// 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 int luacNumberFormat;
|
||||
|
||||
/** input stream from which we are loading */
|
||||
public final DataInputStream is;
|
||||
|
||||
/** Name of what is being loaded? */
|
||||
String name;
|
||||
|
||||
private static final LuaValue[] NOVALUES = {};
|
||||
private static final Prototype[] NOPROTOS = {};
|
||||
private static final LocVars[] NOLOCVARS = {};
|
||||
private static final LuaString[] NOSTRVALUES = {};
|
||||
private static final int[] NOINTS = {};
|
||||
|
||||
/** Read buffer */
|
||||
private byte[] buf = new byte[512];
|
||||
|
||||
|
||||
int loadInt() throws IOException {
|
||||
is.readFully(buf,0,4);
|
||||
return luacLittleEndian?
|
||||
(buf[3] << 24) | ((0xff & buf[2]) << 16) | ((0xff & buf[1]) << 8) | (0xff & buf[0]):
|
||||
(buf[0] << 24) | ((0xff & buf[1]) << 16) | ((0xff & buf[2]) << 8) | (0xff & buf[3]);
|
||||
}
|
||||
|
||||
int[] loadIntArray() throws IOException {
|
||||
int n = loadInt();
|
||||
if ( n == 0 )
|
||||
return NOINTS;
|
||||
|
||||
// read all data at once
|
||||
int m = n << 2;
|
||||
if ( buf.length < m )
|
||||
buf = new byte[m];
|
||||
is.readFully(buf,0,m);
|
||||
int[] array = new int[n];
|
||||
for ( int i=0, j=0; i<n; ++i, j+=4 )
|
||||
array[i] = luacLittleEndian?
|
||||
(buf[j+3] << 24) | ((0xff & buf[j+2]) << 16) | ((0xff & buf[j+1]) << 8) | (0xff & buf[j+0]):
|
||||
(buf[j+0] << 24) | ((0xff & buf[j+1]) << 16) | ((0xff & buf[j+2]) << 8) | (0xff & buf[j+3]);
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
LuaString loadString() throws IOException {
|
||||
int size = loadInt();
|
||||
if ( size == 0 )
|
||||
return null;
|
||||
byte[] bytes = new byte[size];
|
||||
is.readFully( bytes, 0, size );
|
||||
return new LuaString( bytes, 0, bytes.length - 1 );
|
||||
}
|
||||
|
||||
public static LuaValue longBitsToLuaNumber( long bits ) {
|
||||
if ( ( bits & ( ( 1L << 63 ) - 1 ) ) == 0L ) {
|
||||
return LuaValue.ZERO;
|
||||
}
|
||||
|
||||
int e = (int)((bits >> 52) & 0x7ffL) - 1023;
|
||||
|
||||
if ( e >= 0 && e < 31 ) {
|
||||
long f = bits & 0xFFFFFFFFFFFFFL;
|
||||
int shift = 52 - e;
|
||||
long intPrecMask = ( 1L << shift ) - 1;
|
||||
if ( ( f & intPrecMask ) == 0 ) {
|
||||
int intValue = (int)( f >> shift ) | ( 1 << e );
|
||||
return LuaInteger.valueOf( ( ( bits >> 63 ) != 0 ) ? -intValue : intValue );
|
||||
}
|
||||
}
|
||||
|
||||
return LuaValue.valueOf( Double.longBitsToDouble(bits) );
|
||||
}
|
||||
|
||||
LuaValue loadNumber() throws IOException {
|
||||
if ( luacNumberFormat == NUMBER_FORMAT_INTS_ONLY ) {
|
||||
return LuaInteger.valueOf( loadInt() );
|
||||
} else {
|
||||
return longBitsToLuaNumber( loadInt64() );
|
||||
}
|
||||
}
|
||||
|
||||
void loadConstants(Prototype f) throws IOException {
|
||||
int n = loadInt();
|
||||
LuaValue[] values = n>0? new LuaValue[n]: NOVALUES;
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
switch ( is.readByte() ) {
|
||||
case LUA_TNIL:
|
||||
values[i] = LuaValue.NIL;
|
||||
break;
|
||||
case LUA_TBOOLEAN:
|
||||
values[i] = (0 != is.readUnsignedByte()? LuaValue.TRUE: LuaValue.FALSE);
|
||||
break;
|
||||
case LUA_TINT:
|
||||
values[i] = LuaInteger.valueOf( loadInt() );
|
||||
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();
|
||||
Prototype[] protos = n>0? new Prototype[n]: NOPROTOS;
|
||||
for ( int i=0; i<n; i++ )
|
||||
protos[i] = loadFunction(f.source);
|
||||
f.p = protos;
|
||||
}
|
||||
|
||||
void loadDebug( Prototype f ) throws IOException {
|
||||
f.lineinfo = loadIntArray();
|
||||
int n = loadInt();
|
||||
f.locvars = n>0? new LocVars[n]: NOLOCVARS;
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
LuaString varname = loadString();
|
||||
int startpc = loadInt();
|
||||
int endpc = loadInt();
|
||||
f.locvars[i] = new LocVars(varname, startpc, endpc);
|
||||
}
|
||||
|
||||
n = loadInt();
|
||||
f.upvalues = n>0? new LuaString[n]: NOSTRVALUES;
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
f.upvalues[i] = loadString();
|
||||
}
|
||||
}
|
||||
|
||||
public Prototype loadFunction(LuaString p) throws IOException {
|
||||
Prototype f = new Prototype();
|
||||
// this.L.push(f);
|
||||
f.source = loadString();
|
||||
if ( f.source == null )
|
||||
f.source = p;
|
||||
f.linedefined = loadInt();
|
||||
f.lastlinedefined = loadInt();
|
||||
f.nups = is.readUnsignedByte();
|
||||
f.numparams = is.readUnsignedByte();
|
||||
f.is_vararg = is.readUnsignedByte();
|
||||
f.maxstacksize = is.readUnsignedByte();
|
||||
f.code = loadIntArray();
|
||||
loadConstants(f);
|
||||
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;
|
||||
}
|
||||
|
||||
public void loadHeader() throws IOException {
|
||||
luacVersion = is.readByte();
|
||||
luacFormat = is.readByte();
|
||||
luacLittleEndian = (0 != is.readByte());
|
||||
luacSizeofInt = is.readByte();
|
||||
luacSizeofSizeT = is.readByte();
|
||||
luacSizeofInstruction = is.readByte();
|
||||
luacSizeofLuaNumber = is.readByte();
|
||||
luacNumberFormat = is.readByte();
|
||||
}
|
||||
|
||||
public static Prototype undump( InputStream stream, String name ) throws IOException {
|
||||
// check first byte to see if its a precompiled chunk
|
||||
int c = stream.read();
|
||||
if ( c != LUA_SIGNATURE[0] ) {
|
||||
if ( compiler != null )
|
||||
return compiler.compile(c, stream, name);
|
||||
throw new LuaError("no compiler");
|
||||
}
|
||||
|
||||
// check rest of signature
|
||||
for ( int i=1; i<4; i++ ) {
|
||||
if ( stream.read() != LUA_SIGNATURE[i] )
|
||||
throw new IllegalArgumentException("bad signature");
|
||||
}
|
||||
|
||||
// load file as a compiled chunk
|
||||
String sname = getSourceName(name);
|
||||
LoadState s = new LoadState( stream, sname );
|
||||
s.loadHeader();
|
||||
|
||||
// check format
|
||||
switch ( s.luacNumberFormat ) {
|
||||
case NUMBER_FORMAT_FLOATS_OR_DOUBLES:
|
||||
case NUMBER_FORMAT_INTS_ONLY:
|
||||
case NUMBER_FORMAT_NUM_PATCH_INT32:
|
||||
break;
|
||||
default:
|
||||
throw new LuaError("unsupported int size");
|
||||
}
|
||||
|
||||
return s.loadFunction( LuaString.valueOf(sname) );
|
||||
}
|
||||
|
||||
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( InputStream stream, String name ) {
|
||||
this.name = name;
|
||||
this.is = new DataInputStream( stream );
|
||||
}
|
||||
}
|
||||
38
src/core/org/luaj/vm2/LocVars.java
Normal file
38
src/core/org/luaj/vm2/LocVars.java
Normal file
@@ -0,0 +1,38 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
public class LocVars {
|
||||
public LuaString varname;
|
||||
public int startpc;
|
||||
public int endpc;
|
||||
|
||||
public LocVars(LuaString varname, int startpc, int endpc) {
|
||||
this.varname = varname;
|
||||
this.startpc = startpc;
|
||||
this.endpc = endpc;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return varname+" "+startpc+"-"+endpc;
|
||||
}
|
||||
}
|
||||
328
src/core/org/luaj/vm2/Lua.java
Normal file
328
src/core/org/luaj/vm2/Lua.java
Normal file
@@ -0,0 +1,328 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
|
||||
/**
|
||||
* Constants for lua limits and opcodes
|
||||
* @deprecatd these will all move to LuaC or LoadState or DumpState
|
||||
*/
|
||||
public class Lua {
|
||||
/** version is supplied by ant build task */
|
||||
public static final String _VERSION = "Luaj 0.0";
|
||||
|
||||
/** use return values from previous op */
|
||||
public static final int LUA_MULTRET = -1;
|
||||
|
||||
/** masks for new-style vararg */
|
||||
public static final int VARARG_HASARG = 1;
|
||||
public static final int VARARG_ISVARARG = 2;
|
||||
public static final int VARARG_NEEDSARG = 4;
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
/* number of list items to accumulate before a SETLIST instruction */
|
||||
public static final int LFIELDS_PER_FLUSH = 50;
|
||||
|
||||
}
|
||||
73
src/core/org/luaj/vm2/LuaBoolean.java
Normal file
73
src/core/org/luaj/vm2/LuaBoolean.java
Normal file
@@ -0,0 +1,73 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
public class LuaBoolean extends LuaValue {
|
||||
|
||||
public static LuaValue s_metatable;
|
||||
|
||||
public final boolean v;
|
||||
|
||||
LuaBoolean(boolean b) {
|
||||
this.v = b;
|
||||
}
|
||||
|
||||
public int type() {
|
||||
return LuaValue.TBOOLEAN;
|
||||
}
|
||||
|
||||
public String typename() {
|
||||
return "boolean";
|
||||
}
|
||||
|
||||
public boolean isboolean() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public LuaValue not() {
|
||||
return v ? FALSE : LuaValue.TRUE;
|
||||
}
|
||||
|
||||
public boolean booleanValue() {
|
||||
return v;
|
||||
}
|
||||
|
||||
public boolean toboolean() {
|
||||
return v;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return v ? "true" : "false";
|
||||
}
|
||||
|
||||
public boolean optboolean(boolean defval) {
|
||||
return this.v;
|
||||
}
|
||||
|
||||
public boolean checkboolean() {
|
||||
return v;
|
||||
}
|
||||
|
||||
public LuaValue getmetatable() {
|
||||
return s_metatable;
|
||||
}
|
||||
}
|
||||
491
src/core/org/luaj/vm2/LuaClosure.java
Normal file
491
src/core/org/luaj/vm2/LuaClosure.java
Normal file
@@ -0,0 +1,491 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
import org.luaj.vm2.lib.DebugLib;
|
||||
|
||||
public class LuaClosure extends LuaFunction {
|
||||
private static final UpValue[] NOUPVALUES = new UpValue[0];
|
||||
|
||||
public LuaValue s_metatable;
|
||||
|
||||
public final Prototype p;
|
||||
public final UpValue[] upValues;
|
||||
private UpValue openUpValues = null;
|
||||
|
||||
LuaClosure() {
|
||||
p = null;
|
||||
upValues = null;
|
||||
}
|
||||
/** Supply the initial environment */
|
||||
public LuaClosure(Prototype p, LuaValue env) {
|
||||
super( env );
|
||||
this.p = p;
|
||||
this.upValues = p.nups>0? new UpValue[p.nups]: NOUPVALUES;
|
||||
}
|
||||
|
||||
public boolean isclosure() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public LuaClosure optclosure(LuaClosure defval) {
|
||||
return this;
|
||||
}
|
||||
|
||||
public LuaClosure checkclosure() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public LuaValue getmetatable() {
|
||||
return s_metatable;
|
||||
}
|
||||
|
||||
public final LuaValue call() {
|
||||
LuaValue[] stack = new LuaValue[p.maxstacksize];
|
||||
System.arraycopy(NILS, 0, stack, 0, p.maxstacksize);
|
||||
return execute(stack,NONE).arg1();
|
||||
}
|
||||
|
||||
public final LuaValue call(LuaValue arg) {
|
||||
LuaValue[] stack = new LuaValue[p.maxstacksize];
|
||||
System.arraycopy(NILS, 0, stack, 0, p.maxstacksize);
|
||||
switch ( p.numparams ) {
|
||||
default: stack[0]=arg; return execute(stack,NONE).arg1();
|
||||
case 0: return execute(stack,arg).arg1();
|
||||
}
|
||||
}
|
||||
|
||||
public final LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
LuaValue[] stack = new LuaValue[p.maxstacksize];
|
||||
System.arraycopy(NILS, 0, stack, 0, p.maxstacksize);
|
||||
switch ( p.numparams ) {
|
||||
default: stack[0]=arg1; stack[1]=arg2; return execute(stack,NONE).arg1();
|
||||
case 1: stack[0]=arg1; return execute(stack,arg2).arg1();
|
||||
case 0: return execute(stack,p.is_vararg!=0? varargsOf(arg1,arg2): NONE).arg1();
|
||||
}
|
||||
}
|
||||
|
||||
public final LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
|
||||
LuaValue[] stack = new LuaValue[p.maxstacksize];
|
||||
System.arraycopy(NILS, 0, stack, 0, p.maxstacksize);
|
||||
switch ( p.numparams ) {
|
||||
default: stack[0]=arg1; stack[1]=arg2; stack[2]=arg3; return execute(stack,NONE).arg1();
|
||||
case 2: stack[0]=arg1; stack[1]=arg2; return execute(stack,arg3).arg1();
|
||||
case 1: stack[0]=arg1; return execute(stack,p.is_vararg!=0? varargsOf(arg2,arg3): NONE).arg1();
|
||||
case 0: return execute(stack,p.is_vararg!=0? varargsOf(arg1,arg2,arg3): NONE).arg1();
|
||||
}
|
||||
}
|
||||
|
||||
public final Varargs invoke(Varargs varargs) {
|
||||
LuaValue[] stack = new LuaValue[p.maxstacksize];
|
||||
System.arraycopy(NILS, 0, stack, 0, p.maxstacksize);
|
||||
for ( int i=0; i<p.numparams; i++ )
|
||||
stack[i] = varargs.arg(i+1);
|
||||
return execute(stack,p.is_vararg!=0? varargs.subargs(p.numparams+1): NONE);
|
||||
}
|
||||
|
||||
private final Varargs execute( LuaValue[] stack, Varargs varargs ) {
|
||||
// loop through instructions
|
||||
int i,a,b,c,pc=0,top=0;
|
||||
LuaValue o;
|
||||
Varargs v = NONE;
|
||||
int[] code = p.code;
|
||||
LuaValue[] k = p.k;
|
||||
|
||||
// create varargs "arg" table
|
||||
if ( p.is_vararg >= Lua.VARARG_NEEDSARG )
|
||||
stack[p.numparams] = new LuaTable(varargs);
|
||||
|
||||
// debug wants args to this function
|
||||
if (DebugLib.DEBUG_ENABLED)
|
||||
DebugLib.debugSetupCall(varargs, stack);
|
||||
|
||||
// process instructions
|
||||
LuaThread.onCall( this );
|
||||
try {
|
||||
while ( true ) {
|
||||
if (DebugLib.DEBUG_ENABLED)
|
||||
DebugLib.debugBytecode(pc, v, top);
|
||||
|
||||
// pull out instruction
|
||||
i = code[pc++];
|
||||
a = ((i>>6) & 0xff);
|
||||
|
||||
// process the op code
|
||||
switch ( i & 0x3f ) {
|
||||
|
||||
case Lua.OP_MOVE:/* A B R(A):= R(B) */
|
||||
stack[a] = stack[i>>>23];
|
||||
continue;
|
||||
|
||||
case Lua.OP_LOADK:/* A Bx R(A):= Kst(Bx) */
|
||||
stack[a] = k[i>>>14];
|
||||
continue;
|
||||
|
||||
case Lua.OP_LOADBOOL:/* A B C R(A):= (Bool)B: if (C) pc++ */
|
||||
stack[a] = (i>>>23!=0)? LuaValue.TRUE: LuaValue.FALSE;
|
||||
if ((i&(0x1ff<<14)) != 0)
|
||||
pc++; /* skip next instruction (if C) */
|
||||
continue;
|
||||
|
||||
case Lua.OP_LOADNIL: /* A B R(A):= ...:= R(B):= nil */
|
||||
for ( b=i>>>23; a<=b; )
|
||||
stack[a++] = LuaValue.NIL;
|
||||
continue;
|
||||
|
||||
case Lua.OP_GETUPVAL: /* A B R(A):= UpValue[B] */
|
||||
stack[a] = upValues[i>>>23].getValue();
|
||||
continue;
|
||||
|
||||
case Lua.OP_GETGLOBAL: /* A Bx R(A):= Gbl[Kst(Bx)] */
|
||||
stack[a] = env.get(k[i>>>14]);
|
||||
continue;
|
||||
|
||||
case Lua.OP_GETTABLE: /* A B C R(A):= R(B)[RK(C)] */
|
||||
stack[a] = stack[i>>>23].get((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
|
||||
continue;
|
||||
|
||||
case Lua.OP_SETGLOBAL: /* A Bx Gbl[Kst(Bx)]:= R(A) */
|
||||
env.set(k[i>>>14], stack[a]);
|
||||
continue;
|
||||
|
||||
case Lua.OP_SETUPVAL: /* A B UpValue[B]:= R(A) */
|
||||
upValues[i>>>23].setValue(stack[a]);
|
||||
continue;
|
||||
|
||||
case Lua.OP_SETTABLE: /* A B C R(A)[RK(B)]:= RK(C) */
|
||||
stack[a].set(((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]), (c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
|
||||
continue;
|
||||
|
||||
case Lua.OP_NEWTABLE: /* A B C R(A):= {} (size = B,C) */
|
||||
stack[a] = new LuaTable(i>>>23,(i>>14)&0x1ff);
|
||||
continue;
|
||||
|
||||
case Lua.OP_SELF: /* A B C R(A+1):= R(B): R(A):= R(B)[RK(C)] */
|
||||
stack[a+1] = (o = stack[i>>>23]);
|
||||
stack[a] = o.get((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
|
||||
continue;
|
||||
|
||||
case Lua.OP_ADD: /* A B C R(A):= RK(B) + RK(C) */
|
||||
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).add((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
|
||||
continue;
|
||||
|
||||
case Lua.OP_SUB: /* A B C R(A):= RK(B) - RK(C) */
|
||||
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).sub((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
|
||||
continue;
|
||||
|
||||
case Lua.OP_MUL: /* A B C R(A):= RK(B) * RK(C) */
|
||||
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).mul((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
|
||||
continue;
|
||||
|
||||
case Lua.OP_DIV: /* A B C R(A):= RK(B) / RK(C) */
|
||||
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).div((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
|
||||
continue;
|
||||
|
||||
case Lua.OP_MOD: /* A B C R(A):= RK(B) % RK(C) */
|
||||
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).mod((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
|
||||
continue;
|
||||
|
||||
case Lua.OP_POW: /* A B C R(A):= RK(B) ^ RK(C) */
|
||||
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).pow((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
|
||||
continue;
|
||||
|
||||
case Lua.OP_UNM: /* A B R(A):= -R(B) */
|
||||
stack[a] = stack[i>>>23].neg();
|
||||
continue;
|
||||
|
||||
case Lua.OP_NOT: /* A B R(A):= not R(B) */
|
||||
stack[a] = stack[i>>>23].not();
|
||||
continue;
|
||||
|
||||
case Lua.OP_LEN: /* A B R(A):= length of R(B) */
|
||||
stack[a] = stack[i>>>23].len();
|
||||
continue;
|
||||
|
||||
case Lua.OP_CONCAT: /* A B C R(A):= R(B).. ... ..R(C) */
|
||||
b = i>>>23;
|
||||
c = (i>>14)&0x1ff;
|
||||
{
|
||||
Buffer sb = new Buffer();
|
||||
for ( ; b<=c; )
|
||||
sb.append( stack[b++].checkstring() );
|
||||
stack[a] = sb.tostrvalue();
|
||||
}
|
||||
continue;
|
||||
|
||||
case Lua.OP_JMP: /* sBx pc+=sBx */
|
||||
pc += (i>>>14)-0x1ffff;
|
||||
continue;
|
||||
|
||||
case Lua.OP_EQ: /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
|
||||
if ( ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).eq_b((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]) != (a!=0) )
|
||||
++pc;
|
||||
continue;
|
||||
|
||||
case Lua.OP_LT: /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
|
||||
if ( ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).lt_b((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]) != (a!=0) )
|
||||
++pc;
|
||||
continue;
|
||||
|
||||
case Lua.OP_LE: /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
|
||||
if ( ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).lteq_b((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]) != (a!=0) )
|
||||
++pc;
|
||||
continue;
|
||||
|
||||
case Lua.OP_TEST: /* A C if not (R(A) <=> C) then pc++ */
|
||||
if ( stack[a].toboolean() != ((i&(0x1ff<<14))!=0) )
|
||||
++pc;
|
||||
continue;
|
||||
|
||||
case Lua.OP_TESTSET: /* A B C if (R(B) <=> C) then R(A):= R(B) else pc++ */
|
||||
/* note: doc appears to be reversed */
|
||||
if ( (o=stack[i>>>23]).toboolean() != ((i&(0x1ff<<14))!=0) )
|
||||
++pc;
|
||||
else
|
||||
stack[a] = o; // TODO: should be sBx?
|
||||
continue;
|
||||
|
||||
case Lua.OP_CALL: /* A B C R(A), ... ,R(A+C-2):= R(A)(R(A+1), ... ,R(A+B-1)) */
|
||||
switch ( i & (Lua.MASK_B | Lua.MASK_C) ) {
|
||||
case (1<<Lua.POS_B) | (0<<Lua.POS_C): v=stack[a].invoke(NONE); top=a+v.narg(); continue;
|
||||
case (2<<Lua.POS_B) | (0<<Lua.POS_C): v=stack[a].invoke(stack[a+1]); top=a+v.narg(); continue;
|
||||
case (1<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(); continue;
|
||||
case (2<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(stack[a+1]); continue;
|
||||
case (3<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(stack[a+1],stack[a+2]); continue;
|
||||
case (4<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(stack[a+1],stack[a+2],stack[a+3]); continue;
|
||||
case (1<<Lua.POS_B) | (2<<Lua.POS_C): stack[a] = stack[a].call(); continue;
|
||||
case (2<<Lua.POS_B) | (2<<Lua.POS_C): stack[a] = stack[a].call(stack[a+1]); continue;
|
||||
case (3<<Lua.POS_B) | (2<<Lua.POS_C): stack[a] = stack[a].call(stack[a+1],stack[a+2]); continue;
|
||||
case (4<<Lua.POS_B) | (2<<Lua.POS_C): stack[a] = stack[a].call(stack[a+1],stack[a+2],stack[a+3]); continue;
|
||||
default:
|
||||
b = i>>>23;
|
||||
c = (i>>14)&0x1ff;
|
||||
v = b>0?
|
||||
varargsOf(stack,a+1,b-1): // exact arg count
|
||||
varargsOf(stack, a+1, top-v.narg()-(a+1), v); // from prev top
|
||||
v = stack[a].invoke(v);
|
||||
if ( c > 0 ) {
|
||||
while ( --c > 0 )
|
||||
stack[a+c-1] = v.arg(c);
|
||||
v = NONE; // TODO: necessary?
|
||||
} else {
|
||||
top = a + v.narg();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
case Lua.OP_TAILCALL: /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
|
||||
switch ( i & (Lua.MASK_B | Lua.MASK_C) ) {
|
||||
case (1<<Lua.POS_B) | (0<<Lua.POS_C): return stack[a].invoke(NONE);
|
||||
case (2<<Lua.POS_B) | (0<<Lua.POS_C): return stack[a].invoke(stack[a+1]);
|
||||
case (1<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(); return NONE;
|
||||
case (2<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(stack[a+1]); return NONE;
|
||||
case (3<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(stack[a+1],stack[a+2]); return NONE;
|
||||
case (4<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(stack[a+1],stack[a+2],stack[a+3]); return NONE;
|
||||
case (1<<Lua.POS_B) | (2<<Lua.POS_C): return stack[a].call();
|
||||
case (2<<Lua.POS_B) | (2<<Lua.POS_C): return stack[a].call(stack[a+1]);
|
||||
case (3<<Lua.POS_B) | (2<<Lua.POS_C): return stack[a].call(stack[a+1],stack[a+2]);
|
||||
case (4<<Lua.POS_B) | (2<<Lua.POS_C): return stack[a].call(stack[a+1],stack[a+2],stack[a+3]);
|
||||
default:
|
||||
b = i>>>23;
|
||||
c = (i>>14)&0x1ff;
|
||||
v = b>0?
|
||||
varargsOf(stack,a+1,b-1): // exact arg count
|
||||
varargsOf(stack, a+1, top-v.narg()-(a+1), v); // from prev top
|
||||
switch ( c ) {
|
||||
case 1: stack[a].invoke(v); return NONE;
|
||||
case 2: return stack[a].invoke(v).arg1();
|
||||
default: return stack[a].invoke(v);
|
||||
}
|
||||
}
|
||||
|
||||
case Lua.OP_RETURN: /* A B return R(A), ... ,R(A+B-2) (see note) */
|
||||
closeUpValues();
|
||||
b = i>>>23;
|
||||
switch ( b ) {
|
||||
case 0: return varargsOf(stack, a, top-v.narg()-a, v);
|
||||
case 1: return NONE;
|
||||
case 2: return stack[a];
|
||||
default:
|
||||
return varargsOf(stack, a, b-1);
|
||||
}
|
||||
|
||||
case Lua.OP_FORLOOP: /* A sBx R(A)+=R(A+2): if R(A) <?= R(A+1) then { pc+=sBx: R(A+3)=R(A) }*/
|
||||
{
|
||||
LuaValue limit = stack[a + 1];
|
||||
LuaValue step = stack[a + 2];
|
||||
LuaValue idx = step.add(stack[a]);
|
||||
if (step.gt_b(0)? idx.lteq_b(limit): idx.gteq_b(limit)) {
|
||||
stack[a] = idx;
|
||||
stack[a + 3] = idx;
|
||||
pc += (i>>>14)-0x1ffff;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
|
||||
case Lua.OP_FORPREP: /* A sBx R(A)-=R(A+2): pc+=sBx */
|
||||
{
|
||||
LuaValue init = stack[a].checknumber();
|
||||
LuaValue limit = stack[a + 1].checknumber();
|
||||
LuaValue step = stack[a + 2].checknumber();
|
||||
stack[a] = init.sub(step);
|
||||
stack[a + 1] = limit;
|
||||
stack[a + 2] = step;
|
||||
pc += (i>>>14)-0x1ffff;
|
||||
}
|
||||
continue;
|
||||
|
||||
case Lua.OP_TFORLOOP: /*
|
||||
* A C R(A+3), ... ,R(A+2+C):= R(A)(R(A+1),
|
||||
* R(A+2)): if R(A+3) ~= nil then R(A+2)=R(A+3)
|
||||
* else pc++
|
||||
*/
|
||||
// TODO: stack call on for loop body, such as: stack[a].call(ci);
|
||||
v = stack[a].invoke(varargsOf(stack[a+1],stack[a+2]));
|
||||
if ( (o=v.arg1()).isnil() )
|
||||
++pc;
|
||||
else {
|
||||
stack[a+2] = stack[a+3] = o;
|
||||
for ( c=(i>>14)&0x1ff; c>1; --c )
|
||||
stack[a+2+c] = v.arg(c);
|
||||
v = NONE; // todo: necessary?
|
||||
}
|
||||
continue;
|
||||
|
||||
case Lua.OP_SETLIST: /* A B C R(A)[(C-1)*FPF+i]:= R(A+i), 1 <= i <= B */
|
||||
{
|
||||
if ( (c=(i>>14)&0x1ff) == 0 )
|
||||
c = code[pc++];
|
||||
int offset = (c-1) * Lua.LFIELDS_PER_FLUSH;
|
||||
o = stack[a];
|
||||
if ( (b=i>>>23) == 0 ) {
|
||||
b = top - a - 1;
|
||||
int m = b - v.narg();
|
||||
int j=1;
|
||||
for ( ;j<=m; j++ )
|
||||
o.set(offset+j, stack[a + j]);
|
||||
for ( ;j<=b; j++ )
|
||||
o.set(offset+j, v.arg(j-m));
|
||||
} else {
|
||||
o.presize( offset + b );
|
||||
for (int j=1; j<=b; j++)
|
||||
o.set(offset+j, stack[a + j]);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
|
||||
case Lua.OP_CLOSE: /* A close all variables in the stack up to (>=) R(A)*/
|
||||
closeUpValues( a );
|
||||
continue;
|
||||
|
||||
case Lua.OP_CLOSURE: /* A Bx R(A):= closure(KPROTO[Bx], R(A), ... ,R(A+n)) */
|
||||
{
|
||||
Prototype newp = p.p[i>>>14];
|
||||
LuaClosure newcl = new LuaClosure(newp, env);
|
||||
for ( int j=0, nup=newp.nups; j<nup; ++j ) {
|
||||
i = code[pc++];
|
||||
//b = B(i);
|
||||
b = i>>>23;
|
||||
newcl.upValues[j] = (i&4) != 0?
|
||||
upValues[b]:
|
||||
findUpValue(stack,b);
|
||||
}
|
||||
stack[a] = newcl;
|
||||
}
|
||||
continue;
|
||||
|
||||
case Lua.OP_VARARG: /* A B R(A), R(A+1), ..., R(A+B-1) = vararg */
|
||||
b = i>>>23;
|
||||
if ( b == 0 ) {
|
||||
top = a + (b = varargs.narg());
|
||||
v = varargs;
|
||||
} else {
|
||||
for ( int j=1; j<b; ++j )
|
||||
stack[a+j-1] = varargs.arg(j);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} catch ( LuaError le ) {
|
||||
if ( p.lineinfo!=null && p.lineinfo.length>=pc )
|
||||
le.addTracebackLine(p.source+":"+p.lineinfo[pc-1]);
|
||||
throw le;
|
||||
} catch ( Throwable t ) {
|
||||
LuaError le = new LuaError(t);
|
||||
if ( p.lineinfo!=null && p.lineinfo.length>=pc )
|
||||
le.addTracebackLine(p.source+":"+p.lineinfo[pc-1]);
|
||||
throw le;
|
||||
} finally {
|
||||
LuaThread.onReturn();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: inline, optimize when targs come in ascending order?
|
||||
UpValue findUpValue(LuaValue[] stack, int target) {
|
||||
UpValue prev=null,up=openUpValues;
|
||||
while ( up != null ) {
|
||||
if (up.index == target) {
|
||||
return up;
|
||||
} else if (up.index < target) {
|
||||
break;
|
||||
}
|
||||
up = (prev=up).next;
|
||||
}
|
||||
up = new UpValue(stack, target, up);
|
||||
if ( prev!=null )
|
||||
prev.next = up;
|
||||
else
|
||||
this.openUpValues = up;
|
||||
return up;
|
||||
}
|
||||
|
||||
// TODO: inline?
|
||||
void closeUpValues(int limit) {
|
||||
UpValue prev=null,up=openUpValues;
|
||||
while ( up != null ) {
|
||||
UpValue next = up.next;
|
||||
if ( up.close(limit) ) {
|
||||
if ( prev==null )
|
||||
this.openUpValues = up.next;
|
||||
else
|
||||
prev.next = up.next;
|
||||
up.next = null;
|
||||
} else {
|
||||
prev = up;
|
||||
}
|
||||
up = next;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: inline?
|
||||
void closeUpValues() {
|
||||
UpValue up=openUpValues;
|
||||
while ( up != null ) {
|
||||
UpValue next = up.next;
|
||||
up.close(-1);
|
||||
up.next = null;
|
||||
up = next;
|
||||
}
|
||||
openUpValues = null;
|
||||
}
|
||||
|
||||
}
|
||||
192
src/core/org/luaj/vm2/LuaDouble.java
Normal file
192
src/core/org/luaj/vm2/LuaDouble.java
Normal file
@@ -0,0 +1,192 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
import org.luaj.vm2.lib.MathLib;
|
||||
|
||||
public class LuaDouble extends LuaNumber {
|
||||
|
||||
public static final LuaDouble NAN = new LuaDouble( Double.NaN );
|
||||
public static final LuaDouble POSINF = new LuaDouble( Double.POSITIVE_INFINITY );
|
||||
public static final LuaDouble NEGINF = new LuaDouble( Double.NEGATIVE_INFINITY );
|
||||
|
||||
private static Hashtable ALIASES = new Hashtable();
|
||||
static {
|
||||
ALIASES.put( "NaN", "nan" );
|
||||
ALIASES.put( "Infinity", "inf" );
|
||||
ALIASES.put( "-Infinity", "-inf" );
|
||||
}
|
||||
|
||||
final double v;
|
||||
|
||||
public static LuaNumber valueOf(double d) {
|
||||
int id = (int) d;
|
||||
return d==id? (LuaNumber) LuaInteger.valueOf(id): (LuaNumber) new LuaDouble(d);
|
||||
}
|
||||
|
||||
/** Don't allow ints to be boxed by DoubleValues */
|
||||
private LuaDouble(double d) {
|
||||
this.v = d;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return (int) Double.doubleToLongBits(v);
|
||||
}
|
||||
|
||||
public boolean islong() {
|
||||
return v == (long) v;
|
||||
}
|
||||
|
||||
public byte tobyte() { return (byte) (long) v; }
|
||||
public char tochar() { return (char) (long) v; }
|
||||
public double todouble() { return v; }
|
||||
public float tofloat() { return (float) v; }
|
||||
public int toint() { return (int) (long) v; }
|
||||
public long tolong() { return (long) v; }
|
||||
public short toshort() { return (short) (long) v; }
|
||||
|
||||
public double optdouble(double defval) { return v; }
|
||||
public int optint(int defval) { return (int) (long) v; }
|
||||
public LuaInteger optinteger(LuaInteger defval) { return LuaInteger.valueOf((int) (long)v); }
|
||||
public long optlong(long defval) { return (long) v; }
|
||||
|
||||
public LuaInteger checkinteger() { return LuaInteger.valueOf( (int) (long) v ); }
|
||||
|
||||
// unary operators
|
||||
public LuaValue neg() { return valueOf(-v); }
|
||||
|
||||
// object equality, used for key comparison
|
||||
public boolean equals(Object o) { return o instanceof LuaDouble? ((LuaDouble)o).v == v: false; }
|
||||
|
||||
// arithmetic equality
|
||||
public boolean eq_b( LuaValue rhs ) { return rhs.eq_b(v); }
|
||||
public boolean eq_b( double rhs ) { return v == rhs; }
|
||||
public boolean eq_b( int rhs ) { return v == rhs; }
|
||||
|
||||
// basic binary arithmetic
|
||||
public LuaValue add( LuaValue rhs ) { return rhs.add(v); }
|
||||
public LuaValue add( double lhs ) { return LuaDouble.valueOf(lhs + v); }
|
||||
public LuaValue sub( LuaValue rhs ) { return rhs.subFrom(v); }
|
||||
public LuaValue subFrom( double lhs ) { return LuaDouble.valueOf(lhs - v); }
|
||||
public LuaValue mul( LuaValue rhs ) { return rhs.mul(v); }
|
||||
public LuaValue mul( double lhs ) { return LuaDouble.valueOf(lhs * v); }
|
||||
public LuaValue mul( int lhs ) { return LuaDouble.valueOf(lhs * v); }
|
||||
public LuaValue pow( LuaValue rhs ) { return rhs.powWith(v); }
|
||||
public LuaValue powWith( double lhs ) { return MathLib.dpow(lhs,v); }
|
||||
public LuaValue powWith( int lhs ) { return MathLib.dpow(lhs,v); }
|
||||
public LuaValue div( LuaValue rhs ) { return rhs.divInto(v); }
|
||||
public LuaValue divInto( double lhs ) { return LuaDouble.ddiv(lhs,v); }
|
||||
public LuaValue mod( LuaValue rhs ) { return rhs.modFrom(v); }
|
||||
public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs,v); }
|
||||
|
||||
/** lua division is always double, specific values for singularities */
|
||||
public static LuaValue ddiv(double lhs, double rhs) {
|
||||
return rhs!=0? valueOf( lhs / rhs ): lhs>0? POSINF: lhs==0? NAN: NEGINF;
|
||||
}
|
||||
|
||||
/** lua module is always wrt double. */
|
||||
public static LuaValue dmod(double lhs, double rhs) {
|
||||
return rhs!=0? valueOf( lhs-rhs*Math.floor(lhs/rhs) ): NAN;
|
||||
}
|
||||
|
||||
// relational operators
|
||||
public LuaValue lt( LuaValue rhs ) { return rhs.gt_b(v)? LuaValue.TRUE: FALSE; }
|
||||
public boolean lt_b( LuaValue rhs ) { return rhs.gt_b(v); }
|
||||
public boolean lt_b( int rhs ) { return v < rhs; }
|
||||
public boolean lt_b( double rhs ) { return v < rhs; }
|
||||
public LuaValue lteq( LuaValue rhs ) { return rhs.gteq_b(v)? LuaValue.TRUE: FALSE; }
|
||||
public boolean lteq_b( LuaValue rhs ) { return rhs.gteq_b(v); }
|
||||
public boolean lteq_b( int rhs ) { return v <= rhs; }
|
||||
public boolean lteq_b( double rhs ) { return v <= rhs; }
|
||||
public LuaValue gt( LuaValue rhs ) { return rhs.lt_b(v)? LuaValue.TRUE: FALSE; }
|
||||
public boolean gt_b( LuaValue rhs ) { return rhs.lt_b(v); }
|
||||
public boolean gt_b( int rhs ) { return v > rhs; }
|
||||
public boolean gt_b( double rhs ) { return v > rhs; }
|
||||
public LuaValue gteq( LuaValue rhs ) { return rhs.lteq_b(v)? LuaValue.TRUE: FALSE; }
|
||||
public boolean gteq_b( LuaValue rhs ) { return rhs.lteq_b(v); }
|
||||
public boolean gteq_b( int rhs ) { return v >= rhs; }
|
||||
public boolean gteq_b( double rhs ) { return v >= rhs; }
|
||||
|
||||
// string comparison
|
||||
public int strcmp( LuaString rhs ) { typerror("attempt to compare number with string"); return 0; }
|
||||
|
||||
// concatenation
|
||||
public String concat_s(LuaValue rhs) { return rhs.concatTo_s(Double.toString(v)); }
|
||||
public String concatTo_s(String lhs) { return lhs + v; }
|
||||
|
||||
public String toString() {
|
||||
/*
|
||||
if ( v == 0.0 ) { // never occurs in J2me
|
||||
long bits = Double.doubleToLongBits( v );
|
||||
return ( bits >> 63 == 0 ) ? "0" : "-0";
|
||||
}
|
||||
*/
|
||||
long l = (long) v;
|
||||
if ( l == v ) return Long.toString(l);
|
||||
String s = Double.toString(v);
|
||||
Object n = ALIASES.get(s);
|
||||
return n!=null? (String)n: s;
|
||||
}
|
||||
|
||||
public LuaString strvalue() {
|
||||
return LuaString.valueOf(toString());
|
||||
}
|
||||
|
||||
public LuaString optstring(LuaString defval) {
|
||||
return LuaString.valueOf(toString());
|
||||
}
|
||||
|
||||
public String optString(String defval) {
|
||||
long l = (long)v;
|
||||
return v==l? Long.toString(l): Double.toString(v);
|
||||
}
|
||||
|
||||
public LuaNumber optnumber(LuaNumber defval) {
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isnumber() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isstring() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public LuaValue tonumber() {
|
||||
return this;
|
||||
}
|
||||
public int checkint() { return (int) (long) v; }
|
||||
public long checklong() { return (long) v; }
|
||||
public LuaNumber checknumber() { return this; }
|
||||
public double checkdouble() { return v; }
|
||||
|
||||
public String checkString() {
|
||||
return toString();
|
||||
}
|
||||
public LuaString checkstring() {
|
||||
return LuaString.valueOf(toString());
|
||||
}
|
||||
|
||||
}
|
||||
98
src/core/org/luaj/vm2/LuaError.java
Normal file
98
src/core/org/luaj/vm2/LuaError.java
Normal file
@@ -0,0 +1,98 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* RuntimeException that is thrown and caught in response to a lua error.
|
||||
* This error does not indicate any problem with the normal functioning
|
||||
* of the Lua VM, but rather indicates that the lua script being interpreted
|
||||
* has encountered a lua error, eigher via LuaState.error() or lua error() calls.
|
||||
*
|
||||
*/
|
||||
public class LuaError extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private LuaValue msgvalue = null;
|
||||
private Vector traceback = null;
|
||||
|
||||
/** Run the error hook if there is one */
|
||||
private static String errorHook(String msg) {
|
||||
LuaThread thread = LuaThread.getRunning();
|
||||
if ( thread.err != null ) {
|
||||
try {
|
||||
return thread.err.call( LuaValue.valueOf(msg) ).toString();
|
||||
} catch ( Throwable t ) {
|
||||
return "error in error handling";
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a LuaErrorException in response to a Throwable that was caught
|
||||
* indicating a problem with the VM rather than the lua code.
|
||||
*
|
||||
* All errors generated from lua code should throw LuaError(String) instead.
|
||||
*/
|
||||
public LuaError(Throwable cause) {
|
||||
this( errorHook( "vm error: "+cause ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a LuaError with a specific message indicating a problem
|
||||
* within the lua code itself such as an argument type error.
|
||||
*
|
||||
* @param message message to supply
|
||||
*/
|
||||
public LuaError(String message) {
|
||||
super( errorHook( message ) );
|
||||
}
|
||||
|
||||
/** Get the message, including source line info if there is any */
|
||||
public String getMessage() {
|
||||
String msg = super.getMessage();
|
||||
return msg!=null && traceback!=null? traceback.elementAt(0)+": "+msg: msg;
|
||||
}
|
||||
|
||||
/** Add a line of traceback info */
|
||||
public void addTracebackLine( String line ) {
|
||||
if ( traceback == null ) {
|
||||
traceback = new Vector();
|
||||
}
|
||||
traceback.addElement( line );
|
||||
}
|
||||
|
||||
/** Print the message and stack trace */
|
||||
public void printStackTrace() {
|
||||
System.out.println( toString() );
|
||||
if ( traceback != null ) {
|
||||
for ( int i=0,n=traceback.size(); i<n; i++ ) {
|
||||
System.out.print("\t");
|
||||
System.out.println(traceback.elementAt(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
72
src/core/org/luaj/vm2/LuaFunction.java
Normal file
72
src/core/org/luaj/vm2/LuaFunction.java
Normal file
@@ -0,0 +1,72 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
abstract
|
||||
public class LuaFunction extends LuaValue {
|
||||
|
||||
public static LuaValue s_metatable;
|
||||
|
||||
protected LuaValue env;
|
||||
|
||||
public LuaFunction() {
|
||||
this.env = NIL;
|
||||
}
|
||||
|
||||
public LuaFunction(LuaValue env) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public int type() {
|
||||
return TFUNCTION;
|
||||
}
|
||||
|
||||
public String typename() {
|
||||
return "function";
|
||||
}
|
||||
|
||||
public boolean isfunction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public LuaValue checkfunction() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public LuaFunction optfunction(LuaFunction defval) {
|
||||
return this;
|
||||
}
|
||||
|
||||
public LuaValue getmetatable() {
|
||||
return s_metatable;
|
||||
}
|
||||
|
||||
public LuaValue getfenv() {
|
||||
return env;
|
||||
}
|
||||
|
||||
public void setfenv(LuaValue env) {
|
||||
this.env = env!=null? env: NIL;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
167
src/core/org/luaj/vm2/LuaInteger.java
Normal file
167
src/core/org/luaj/vm2/LuaInteger.java
Normal file
@@ -0,0 +1,167 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
import org.luaj.vm2.lib.MathLib;
|
||||
|
||||
public class LuaInteger extends LuaNumber {
|
||||
|
||||
private static final LuaInteger[] intValues = new LuaInteger[512];
|
||||
static {
|
||||
for ( int i=0; i<512; i++ )
|
||||
intValues[i] = new LuaInteger(i-256);
|
||||
}
|
||||
|
||||
public static LuaInteger valueOf(int i) {
|
||||
return i<=255 && i>=-256? intValues[i+256]: new LuaInteger(i);
|
||||
};
|
||||
|
||||
public static LuaNumber valueOf(long l) {
|
||||
int i = (int) l;
|
||||
return l==i? (i<=255 && i>=-256? intValues[i+256]:
|
||||
(LuaNumber) new LuaInteger(i)):
|
||||
(LuaNumber) LuaDouble.valueOf(l);
|
||||
}
|
||||
|
||||
public final int v;
|
||||
|
||||
/** package protected constructor, @see IntValue.valueOf(int) */
|
||||
LuaInteger(int i) {
|
||||
this.v = i;
|
||||
}
|
||||
|
||||
public boolean isint() { return true; }
|
||||
public boolean isinttype() { return true; }
|
||||
public boolean islong() { return true; }
|
||||
|
||||
public byte tobyte() { return (byte) v; }
|
||||
public char tochar() { return (char) v; }
|
||||
public double todouble() { return v; }
|
||||
public float tofloat() { return v; }
|
||||
public int toint() { return v; }
|
||||
public long tolong() { return v; }
|
||||
public short toshort() { return (short) v; }
|
||||
|
||||
public double optdouble(double defval) { return v; }
|
||||
public int optint(int defval) { return v; }
|
||||
public LuaInteger optinteger(LuaInteger defval) { return this; }
|
||||
public long optlong(long defval) { return v; }
|
||||
|
||||
public String toString() {
|
||||
return Integer.toString(v);
|
||||
}
|
||||
|
||||
public LuaString strvalue() {
|
||||
return LuaString.valueOf(Integer.toString(v));
|
||||
}
|
||||
|
||||
public LuaString optstring(LuaString defval) {
|
||||
return LuaString.valueOf(Integer.toString(v));
|
||||
}
|
||||
|
||||
public String optString(String defval) {
|
||||
return Integer.toString(v);
|
||||
}
|
||||
|
||||
public LuaInteger checkinteger() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isstring() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return v;
|
||||
}
|
||||
|
||||
// unary operators
|
||||
public LuaValue neg() { return valueOf(-(long)v); }
|
||||
|
||||
// object equality, used for key comparison
|
||||
public boolean equals(Object o) { return o instanceof LuaInteger? ((LuaInteger)o).v == v: false; }
|
||||
|
||||
// arithmetic equality
|
||||
public boolean eq_b( LuaValue rhs ) { return rhs.eq_b(v); }
|
||||
public boolean eq_b( double rhs ) { return v == rhs; }
|
||||
public boolean eq_b( int rhs ) { return v == rhs; }
|
||||
|
||||
// arithmetic operators
|
||||
public LuaValue add( LuaValue rhs ) { return rhs.add(v); }
|
||||
public LuaValue add( double lhs ) { return LuaDouble.valueOf(lhs + v); }
|
||||
public LuaValue add( int lhs ) { return LuaInteger.valueOf(lhs + (long)v); }
|
||||
public LuaValue sub( LuaValue rhs ) { return rhs.subFrom(v); }
|
||||
public LuaValue subFrom( double lhs ) { return LuaDouble.valueOf(lhs - v); }
|
||||
public LuaValue subFrom( int lhs ) { return LuaInteger.valueOf(lhs - (long)v); }
|
||||
public LuaValue mul( LuaValue rhs ) { return rhs.mul(v); }
|
||||
public LuaValue mul( double lhs ) { return LuaDouble.valueOf(lhs * v); }
|
||||
public LuaValue mul( int lhs ) { return LuaInteger.valueOf(lhs * (long)v); }
|
||||
public LuaValue pow( LuaValue rhs ) { return rhs.powWith(v); }
|
||||
public LuaValue powWith( double lhs ) { return MathLib.dpow(lhs,v); }
|
||||
public LuaValue powWith( int lhs ) { return MathLib.dpow(lhs,v); }
|
||||
public LuaValue div( LuaValue rhs ) { return rhs.divInto(v); }
|
||||
public LuaValue divInto( double lhs ) { return LuaDouble.ddiv(lhs,v); }
|
||||
public LuaValue mod( LuaValue rhs ) { return rhs.modFrom(v); }
|
||||
public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs,v); }
|
||||
|
||||
// relational operators
|
||||
public LuaValue lt( LuaValue rhs ) { return rhs.gt_b(v)? LuaValue.TRUE: FALSE; }
|
||||
public boolean lt_b( LuaValue rhs ) { return rhs.gt_b(v); }
|
||||
public boolean lt_b( int rhs ) { return v < rhs; }
|
||||
public boolean lt_b( double rhs ) { return v < rhs; }
|
||||
public LuaValue lteq( LuaValue rhs ) { return rhs.gteq_b(v)? LuaValue.TRUE: FALSE; }
|
||||
public boolean lteq_b( LuaValue rhs ) { return rhs.gteq_b(v); }
|
||||
public boolean lteq_b( int rhs ) { return v <= rhs; }
|
||||
public boolean lteq_b( double rhs ) { return v <= rhs; }
|
||||
public LuaValue gt( LuaValue rhs ) { return rhs.lt_b(v)? LuaValue.TRUE: FALSE; }
|
||||
public boolean gt_b( LuaValue rhs ) { return rhs.lt_b(v); }
|
||||
public boolean gt_b( int rhs ) { return v > rhs; }
|
||||
public boolean gt_b( double rhs ) { return v > rhs; }
|
||||
public LuaValue gteq( LuaValue rhs ) { return rhs.lteq_b(v)? LuaValue.TRUE: FALSE; }
|
||||
public boolean gteq_b( LuaValue rhs ) { return rhs.lteq_b(v); }
|
||||
public boolean gteq_b( int rhs ) { return v >= rhs; }
|
||||
public boolean gteq_b( double rhs ) { return v >= rhs; }
|
||||
|
||||
// string comparison
|
||||
public int strcmp( LuaString rhs ) { typerror("attempt to compare number with string"); return 0; }
|
||||
|
||||
// concatenation
|
||||
public String concat_s(LuaValue rhs) { return rhs.concatTo_s(Integer.toString(v)); }
|
||||
public String concatTo_s(String lhs) { return lhs + v; }
|
||||
|
||||
public int checkint() {
|
||||
return v;
|
||||
}
|
||||
public long checklong() {
|
||||
return v;
|
||||
}
|
||||
public double checkdouble() {
|
||||
return v;
|
||||
}
|
||||
public String checkString() {
|
||||
return String.valueOf(v);
|
||||
}
|
||||
public LuaString checkstring() {
|
||||
return valueOf( String.valueOf(v) );
|
||||
}
|
||||
|
||||
}
|
||||
82
src/core/org/luaj/vm2/LuaNil.java
Normal file
82
src/core/org/luaj/vm2/LuaNil.java
Normal file
@@ -0,0 +1,82 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
public class LuaNil extends LuaValue {
|
||||
|
||||
public static LuaValue s_metatable;
|
||||
|
||||
LuaNil() {}
|
||||
|
||||
public int type() {
|
||||
return LuaValue.TNIL;
|
||||
}
|
||||
|
||||
public String typename() {
|
||||
return "nil";
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "nil";
|
||||
}
|
||||
|
||||
public LuaValue not() {
|
||||
return LuaValue.TRUE;
|
||||
}
|
||||
|
||||
public boolean toboolean() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isnil() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public LuaValue getmetatable() {
|
||||
return s_metatable;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof LuaNil;
|
||||
}
|
||||
|
||||
public LuaValue checknotnil() {
|
||||
return typerror("value");
|
||||
}
|
||||
|
||||
// optional argument conversions - nil alwas falls badk to default value
|
||||
public boolean optboolean(boolean defval) { return defval; }
|
||||
public LuaClosure optclosure(LuaClosure defval) { return defval; }
|
||||
public double optdouble(double defval) { return defval; }
|
||||
public LuaFunction optfunction(LuaFunction defval) { return defval; }
|
||||
public int optint(int defval) { return defval; }
|
||||
public LuaInteger optinteger(LuaInteger defval) { return defval; }
|
||||
public long optlong(long defval) { return defval; }
|
||||
public LuaNumber optnumber(LuaNumber defval) { return defval; }
|
||||
public LuaTable opttable(LuaTable defval) { return defval; }
|
||||
public LuaThread optthread(LuaThread defval) { return defval; }
|
||||
public String optString(String defval) { return defval; }
|
||||
public LuaString optstring(LuaString defval) { return defval; }
|
||||
public Object optuserdata(Object defval) { return defval; }
|
||||
public Object optuserdata(Class c, Object defval) { return defval; }
|
||||
public LuaValue optvalue(LuaValue defval) { return defval; }
|
||||
}
|
||||
61
src/core/org/luaj/vm2/LuaNumber.java
Normal file
61
src/core/org/luaj/vm2/LuaNumber.java
Normal file
@@ -0,0 +1,61 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
abstract
|
||||
public class LuaNumber extends LuaValue {
|
||||
|
||||
public static LuaValue s_metatable;
|
||||
|
||||
public int type() {
|
||||
return TNUMBER;
|
||||
}
|
||||
|
||||
public String typename() {
|
||||
return "number";
|
||||
}
|
||||
|
||||
public LuaNumber checknumber() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public LuaNumber optnumber(LuaNumber defval) {
|
||||
return this;
|
||||
}
|
||||
|
||||
public LuaValue tonumber() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isnumber() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isstring() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public LuaValue getmetatable() {
|
||||
return s_metatable;
|
||||
}
|
||||
|
||||
}
|
||||
473
src/core/org/luaj/vm2/LuaString.java
Normal file
473
src/core/org/luaj/vm2/LuaString.java
Normal file
@@ -0,0 +1,473 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.luaj.vm2.lib.MathLib;
|
||||
import org.luaj.vm2.lib.StringLib;
|
||||
|
||||
public class LuaString extends LuaValue {
|
||||
|
||||
public static LuaValue s_metatable;
|
||||
|
||||
public final byte[] m_bytes;
|
||||
public final int m_offset;
|
||||
public final int m_length;
|
||||
|
||||
public static LuaString valueOf(String string) {
|
||||
char[] c = string.toCharArray();
|
||||
byte[] b = new byte[lengthAsUtf8(c)];
|
||||
encodeToUtf8(c, b, 0);
|
||||
return new LuaString(b);
|
||||
}
|
||||
|
||||
public LuaString(byte[] bytes, int offset, int length) {
|
||||
this.m_bytes = bytes;
|
||||
this.m_offset = offset;
|
||||
this.m_length = length;
|
||||
}
|
||||
|
||||
public LuaString(byte[] bytes) {
|
||||
this.m_bytes = bytes;
|
||||
this.m_offset = 0;
|
||||
this.m_length = bytes.length;
|
||||
}
|
||||
|
||||
public boolean isstring() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public LuaValue getmetatable() {
|
||||
return s_metatable;
|
||||
}
|
||||
|
||||
public int type() {
|
||||
return LuaValue.TSTRING;
|
||||
}
|
||||
|
||||
public String typename() {
|
||||
return "string";
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return decodeAsUtf8(m_bytes, m_offset, m_length);
|
||||
}
|
||||
|
||||
// get is delegated to the string library
|
||||
public LuaValue get(LuaValue key) {
|
||||
return s_metatable!=null? gettable(this,key): StringLib.instance.get(key);
|
||||
}
|
||||
|
||||
// unary operators
|
||||
public LuaValue neg() { return checkarith().neg(); }
|
||||
|
||||
// basic binary arithmetic
|
||||
public LuaValue add( LuaValue rhs ) { return checkarith().add(rhs); }
|
||||
public LuaValue add( double lhs ) { return checkarith().add(lhs); }
|
||||
public LuaValue sub( LuaValue rhs ) { return checkarith().sub(rhs); }
|
||||
public LuaValue subFrom( double lhs ) { return checkarith().subFrom(lhs); }
|
||||
public LuaValue mul( LuaValue rhs ) { return checkarith().mul(rhs); }
|
||||
public LuaValue mul( double lhs ) { return checkarith().mul(lhs); }
|
||||
public LuaValue mul( int lhs ) { return checkarith().mul(lhs); }
|
||||
public LuaValue pow( LuaValue rhs ) { return checkarith().pow(rhs); }
|
||||
public LuaValue powWith( double lhs ) { return checkarith().powWith(lhs); }
|
||||
public LuaValue powWith( int lhs ) { return checkarith().powWith(lhs); }
|
||||
public LuaValue div( LuaValue rhs ) { return checkarith().div(rhs); }
|
||||
public LuaValue divInto( double lhs ) { return checkarith().divInto(lhs); }
|
||||
public LuaValue mod( LuaValue rhs ) { return checkarith().mod(rhs); }
|
||||
public LuaValue modFrom( double lhs ) { return checkarith().modFrom(lhs); }
|
||||
|
||||
// relational operators, these only work with other strings
|
||||
public LuaValue lt( LuaValue rhs ) { return rhs.strcmp(this)>0? LuaValue.TRUE: FALSE; }
|
||||
public boolean lt_b( LuaValue rhs ) { return rhs.strcmp(this)>0; }
|
||||
public boolean lt_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
|
||||
public boolean lt_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
|
||||
public LuaValue lteq( LuaValue rhs ) { return rhs.strcmp(this)>=0? LuaValue.TRUE: FALSE; }
|
||||
public boolean lteq_b( LuaValue rhs ) { return rhs.strcmp(this)>=0; }
|
||||
public boolean lteq_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
|
||||
public boolean lteq_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
|
||||
public LuaValue gt( LuaValue rhs ) { return rhs.strcmp(this)<0? LuaValue.TRUE: FALSE; }
|
||||
public boolean gt_b( LuaValue rhs ) { return rhs.strcmp(this)<0; }
|
||||
public boolean gt_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
|
||||
public boolean gt_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
|
||||
public LuaValue gteq( LuaValue rhs ) { return rhs.strcmp(this)<=0? LuaValue.TRUE: FALSE; }
|
||||
public boolean gteq_b( LuaValue rhs ) { return rhs.strcmp(this)<=0; }
|
||||
public boolean gteq_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
|
||||
public boolean gteq_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
|
||||
|
||||
// concatenation
|
||||
public String concat_s(LuaValue rhs) { return rhs.concatTo_s(toString()); }
|
||||
public String concatTo_s(String lhs) { return lhs + toString(); }
|
||||
|
||||
// string comparison
|
||||
public int strcmp(LuaValue lhs) { return -lhs.strcmp(this); }
|
||||
public int strcmp(LuaString rhs) {
|
||||
for ( int i=0, j=0; i<m_length && j<rhs.m_length; ++i, ++j ) {
|
||||
if ( m_bytes[m_offset+i] != rhs.m_bytes[rhs.m_offset+j] ) {
|
||||
return ((int)m_bytes[m_offset+i]) - ((int) rhs.m_bytes[rhs.m_offset+j]);
|
||||
}
|
||||
}
|
||||
return m_length - rhs.m_length;
|
||||
}
|
||||
|
||||
/** Check for number in arithmetic, or throw aritherror */
|
||||
private LuaValue checkarith() {
|
||||
LuaValue v = tonumber(10);
|
||||
return v.isnil()? aritherror(): v;
|
||||
}
|
||||
|
||||
public int checkint() {
|
||||
return checknumber().toint();
|
||||
}
|
||||
public LuaInteger checkinteger() {
|
||||
return checknumber().checkinteger();
|
||||
}
|
||||
public long checklong() {
|
||||
return checknumber().tolong();
|
||||
}
|
||||
public double checkdouble() {
|
||||
return checknumber().todouble();
|
||||
}
|
||||
public LuaNumber checknumber() {
|
||||
LuaValue n = tonumber(10);
|
||||
if ( ! n.isnumber() )
|
||||
typerror("number");
|
||||
return (LuaNumber) n;
|
||||
}
|
||||
public LuaValue tonumber() {
|
||||
return tonumber(10);
|
||||
}
|
||||
|
||||
public boolean isnumber() {
|
||||
return ! tonumber(10).isnil();
|
||||
}
|
||||
|
||||
public boolean isint() {
|
||||
return tonumber(10).isint();
|
||||
}
|
||||
|
||||
public boolean islong() {
|
||||
return tonumber(10).islong();
|
||||
}
|
||||
|
||||
public byte tobyte() { return (byte) toint(); }
|
||||
public char tochar() { return (char) toint(); }
|
||||
public double todouble() { LuaValue n=tonumber(10); return n.isnil()? 0: n.todouble(); }
|
||||
public float tofloat() { return (float) todouble(); }
|
||||
public int toint() { LuaValue n=tonumber(10); return n.isnil()? 0: n.toint(); }
|
||||
public long tolong() { return (long) todouble(); }
|
||||
public short toshort() { return (short) toint(); }
|
||||
|
||||
public double optdouble(double defval) {
|
||||
return checknumber().checkdouble();
|
||||
}
|
||||
|
||||
public int optint(int defval) {
|
||||
return checknumber().checkint();
|
||||
}
|
||||
|
||||
public LuaInteger optinteger(LuaInteger defval) {
|
||||
return checknumber().checkinteger();
|
||||
}
|
||||
|
||||
public long optlong(long defval) {
|
||||
return checknumber().checklong();
|
||||
}
|
||||
|
||||
public LuaNumber optnumber(LuaNumber defval) {
|
||||
return checknumber().checknumber();
|
||||
}
|
||||
|
||||
public LuaString optstring(LuaString defval) {
|
||||
return this;
|
||||
}
|
||||
|
||||
public String optString(String defval) {
|
||||
return toString();
|
||||
}
|
||||
|
||||
public LuaString strvalue() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public LuaString substring( int beginIndex, int endIndex ) {
|
||||
return new LuaString( m_bytes, m_offset + beginIndex, endIndex - beginIndex );
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int h = m_length; /* seed */
|
||||
int step = (m_length>>5)+1; /* if string is too long, don't hash all its chars */
|
||||
for (int l1=m_length; l1>=step; l1-=step) /* compute hash */
|
||||
h = h ^ ((h<<5)+(h>>2)+(((int) m_bytes[m_offset+l1-1] ) & 0x0FF ));
|
||||
return h;
|
||||
}
|
||||
|
||||
// object comparison, used in key comparison
|
||||
public boolean equals( Object o ) {
|
||||
if ( o instanceof LuaString ) {
|
||||
LuaString s = (LuaString) o;
|
||||
if ( s.m_length != m_length )
|
||||
return false;
|
||||
if ( s.hashCode() != hashCode() )
|
||||
return false;
|
||||
for ( int i=0; i<m_length; i++ )
|
||||
if ( s.m_bytes[s.m_offset+i] != m_bytes[m_offset+i] )
|
||||
return false;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean eq_b( LuaValue val ) {
|
||||
return equals( val );
|
||||
}
|
||||
|
||||
public static boolean equals( LuaString a, int i, LuaString 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;
|
||||
while ( --n>=0 )
|
||||
if ( a[i++]!=b[j++] )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void write(DataOutputStream writer, int i, int len) throws IOException {
|
||||
writer.write(m_bytes,m_offset+i,len);
|
||||
}
|
||||
|
||||
public LuaValue len() {
|
||||
return LuaInteger.valueOf(m_length);
|
||||
}
|
||||
|
||||
public int length() {
|
||||
return m_length;
|
||||
}
|
||||
|
||||
public int luaByte(int index) {
|
||||
return m_bytes[m_offset + index] & 0x0FF;
|
||||
}
|
||||
|
||||
public int charAt( int index ) {
|
||||
if ( index < 0 || index >= m_length )
|
||||
throw new IndexOutOfBoundsException();
|
||||
return luaByte( index );
|
||||
}
|
||||
|
||||
public String checkString() {
|
||||
return toString();
|
||||
}
|
||||
|
||||
public LuaString checkstring() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public InputStream toInputStream() {
|
||||
return new ByteArrayInputStream(m_bytes, m_offset, 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 );
|
||||
}
|
||||
|
||||
/** Java version of strpbrk, which is a terribly named C function. */
|
||||
public int indexOfAny( LuaString 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( byte b, int start ) {
|
||||
for ( int i=0, j=m_offset+start; i < m_length; ++i ) {
|
||||
if ( m_bytes[j++] == b )
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int indexOf( LuaString 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 int lastIndexOf( LuaString s ) {
|
||||
final int slen = s.length();
|
||||
final int limit = m_offset + m_length - slen;
|
||||
for ( int i = limit; i >= m_offset; --i ) {
|
||||
if ( equals( m_bytes, i, s.m_bytes, s.m_offset, slen ) ) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// --------------------- utf8 conversion -------------------------
|
||||
|
||||
/**
|
||||
* Convert to Java String interpreting as utf8 characters
|
||||
*/
|
||||
public static String decodeAsUtf8(byte[] bytes, int offset, int length) {
|
||||
int i,j,n,b;
|
||||
for ( i=offset,j=offset+length,n=0; i<j; ++n ) {
|
||||
switch ( 0xC0 & bytes[i++] ) {
|
||||
case 0xE0: ++i;
|
||||
case 0xC0: ++i;
|
||||
}
|
||||
}
|
||||
char[] chars=new char[n];
|
||||
for ( i=offset,j=offset+length,n=0; i<j; ) {
|
||||
chars[n++] = (char) (
|
||||
((b=bytes[i++])>=0||i>=j)? b:
|
||||
(b<-32||i+1>=j)? (((b&0x3f) << 6) | (bytes[i++]&0x3f)):
|
||||
(((b&0xf) << 12) | ((bytes[i++]&0x3f)<<6) | (bytes[i++]&0x3f)));
|
||||
}
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the number of bytes required to encode the string as UTF-8.
|
||||
*/
|
||||
public static int lengthAsUtf8(char[] chars) {
|
||||
int i,b;
|
||||
char c;
|
||||
for ( i=b=chars.length; --i>=0; )
|
||||
if ( (c=chars[i]) >=0x80 )
|
||||
b += (c>=0x800)? 2: 1;
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the given Java string as UTF-8 bytes, writing the result to bytes
|
||||
* starting at offset. The string should be measured first with lengthAsUtf8
|
||||
* to make sure the given byte array is large enough.
|
||||
*/
|
||||
public static void encodeToUtf8(char[] chars, byte[] bytes, int off) {
|
||||
final int n = chars.length;
|
||||
char c;
|
||||
for ( int i=0, j=off; i<n; i++ ) {
|
||||
if ( (c = chars[i]) < 0x80 ) {
|
||||
bytes[j++] = (byte) c;
|
||||
} else if ( c < 0x800 ) {
|
||||
bytes[j++] = (byte) (0xC0 | ((c>>6) & 0x1f));
|
||||
bytes[j++] = (byte) (0x80 | ( c & 0x3f));
|
||||
} else {
|
||||
bytes[j++] = (byte) (0xE0 | ((c>>12) & 0x0f));
|
||||
bytes[j++] = (byte) (0x80 | ((c>>6) & 0x3f));
|
||||
bytes[j++] = (byte) (0x80 | ( c & 0x3f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------- number conversion -----------------------
|
||||
|
||||
/**
|
||||
* convert to a number using a supplied base, or NIL if it can't be converted
|
||||
* @return IntValue, DoubleValue, or NIL depending on the content of the string.
|
||||
*/
|
||||
public LuaValue tonumber( int base ) {
|
||||
if ( base >= 2 && base <= 36 ) {
|
||||
int i=m_offset,j=m_offset+m_length;
|
||||
while ( i<j && m_bytes[i]==' ' ) ++i;
|
||||
while ( i<j && m_bytes[j-1]==' ' ) --j;
|
||||
if ( i>=j ) return FALSE;
|
||||
if ( ( base == 10 || base == 16 ) && ( m_bytes[i]=='0' && i+1<j && (m_bytes[i+1]=='x'||m_bytes[i+1]=='X') ) ) {
|
||||
base = 16;
|
||||
i+=2;
|
||||
}
|
||||
LuaValue l = scanlong( base, i, j );
|
||||
return l!=NIL? l: base==10? scandouble(i,j): NIL;
|
||||
}
|
||||
|
||||
return NIL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan and convert a long value, or return NIL if not found.
|
||||
* @return DoubleValue, IntValue, or NIL depending on what is found.
|
||||
*/
|
||||
private LuaValue scanlong( int base, int start, int end ) {
|
||||
long x = 0;
|
||||
boolean neg = (m_bytes[start] == '-');
|
||||
for ( int i=(neg?start+1:start); i<end; i++ ) {
|
||||
int digit = m_bytes[i] - (base<=10||(m_bytes[i]>='0'&&m_bytes[i]<='9')? '0':
|
||||
m_bytes[i]>='A'&&m_bytes[i]<='Z'? ('A'-10): ('a'-10));
|
||||
if ( digit < 0 || digit >= base )
|
||||
return NIL;
|
||||
x = x * base + digit;
|
||||
}
|
||||
return valueOf(neg? -x: x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan and convert a double value, or return NIL if not a double.
|
||||
* @return DoubleValue, IntValue, or NIL depending on what is found.
|
||||
*/
|
||||
private LuaValue scandouble(int start, int end) {
|
||||
if ( end>start+64 ) end=start+64;
|
||||
for ( int i=start; i<end; i++ ) {
|
||||
switch ( m_bytes[i] ) {
|
||||
case '-':
|
||||
case '+':
|
||||
case '.':
|
||||
case 'e': case 'E':
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
break;
|
||||
default:
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
char [] c = new char[end-start];
|
||||
for ( int i=start; i<end; i++ )
|
||||
c[i-start] = (char) m_bytes[i];
|
||||
try {
|
||||
return valueOf( Double.parseDouble(new String(c)));
|
||||
} catch ( Exception e ) {
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
|
||||
}
|
||||
559
src/core/org/luaj/vm2/LuaTable.java
Normal file
559
src/core/org/luaj/vm2/LuaTable.java
Normal file
@@ -0,0 +1,559 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
public class LuaTable extends LuaValue {
|
||||
private static final int MIN_HASH_CAPACITY = 2;
|
||||
private static final LuaString N = valueOf("n");
|
||||
|
||||
protected LuaValue[] array;
|
||||
protected LuaValue[] hashKeys;
|
||||
protected LuaValue[] hashValues;
|
||||
private int hashEntries;
|
||||
private LuaValue m_metatable;
|
||||
|
||||
public LuaTable() {
|
||||
array = NOVALS;
|
||||
hashKeys = NOVALS;
|
||||
hashValues = NOVALS;
|
||||
}
|
||||
|
||||
public LuaTable(int narray, int nhash) {
|
||||
presize(narray, nhash);
|
||||
}
|
||||
|
||||
public LuaTable(LuaValue[] named, LuaValue[] unnamed, Varargs lastarg) {
|
||||
int nn = (named!=null? named.length: 0);
|
||||
int nu = (unnamed!=null? unnamed.length: 0);
|
||||
int nl = (lastarg!=null? lastarg.narg(): 0);
|
||||
presize(nu+nl, nn-(nn>>1));
|
||||
for ( int i=0; i<nu; i++ )
|
||||
array[i] = unnamed[i].optvalue(null);
|
||||
if ( lastarg != null )
|
||||
for ( int i=0,n=lastarg.narg(); i<n; ++i )
|
||||
array[nu+i] = lastarg.arg(i+1).optvalue(null);
|
||||
for ( int i=0; i<nn; i+=2 )
|
||||
if (!named[i+1].isnil())
|
||||
rawset(named[i], named[i+1]);
|
||||
}
|
||||
|
||||
|
||||
public LuaTable(Varargs varargs) {
|
||||
int n = varargs.narg();
|
||||
presize( n, 1 );
|
||||
set(N, valueOf(n));
|
||||
for ( int i=1; i<=n; i++ )
|
||||
set(i, varargs.arg(i));
|
||||
}
|
||||
|
||||
private void presize(int narray, int nhash) {
|
||||
if ( nhash > 0 && nhash < MIN_HASH_CAPACITY )
|
||||
nhash = MIN_HASH_CAPACITY;
|
||||
array = (narray>0? new LuaValue[narray]: NOVALS);
|
||||
hashKeys = (nhash>0? new LuaValue[nhash]: NOVALS);
|
||||
hashValues = (nhash>0? new LuaValue[nhash]: NOVALS);
|
||||
hashEntries = 0;
|
||||
}
|
||||
|
||||
public int type() {
|
||||
return LuaValue.TTABLE;
|
||||
}
|
||||
|
||||
public String typename() {
|
||||
return "table";
|
||||
}
|
||||
|
||||
public boolean istable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public LuaTable checktable() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public LuaTable opttable(LuaTable defval) {
|
||||
return this;
|
||||
}
|
||||
|
||||
public void presize( int i ) {
|
||||
if ( i > array.length )
|
||||
array = resize( array, i );
|
||||
}
|
||||
|
||||
private static LuaValue[] resize( LuaValue[] old, int n ) {
|
||||
LuaValue[] v = new LuaValue[n];
|
||||
System.arraycopy(old, 0, v, 0, old.length);
|
||||
return v;
|
||||
}
|
||||
|
||||
public LuaValue getmetatable() {
|
||||
if ( m_metatable!=null )
|
||||
return m_metatable.rawget(METATABLE).optvalue(m_metatable);
|
||||
return m_metatable;
|
||||
}
|
||||
|
||||
public LuaValue setmetatable(LuaValue metatable) {
|
||||
if ( m_metatable!=null && !m_metatable.rawget(METATABLE).isnil() )
|
||||
error("cannot change a protected metatable");
|
||||
m_metatable = metatable;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LuaValue get( int key ) {
|
||||
LuaValue v = rawget(key);
|
||||
return v.isnil() && m_metatable!=null? gettable(this,valueOf(key)): v;
|
||||
}
|
||||
|
||||
public LuaValue get( LuaValue key ) {
|
||||
LuaValue v = rawget(key);
|
||||
return v.isnil() && m_metatable!=null? gettable(this,key): v;
|
||||
}
|
||||
|
||||
public LuaValue rawget( int key ) {
|
||||
if ( key>0 && key<=array.length )
|
||||
return array[key-1]!=null? array[key-1]: NIL;
|
||||
return hashget( LuaInteger.valueOf(key) );
|
||||
}
|
||||
|
||||
public LuaValue rawget( LuaValue key ) {
|
||||
if ( key.isinttype() ) {
|
||||
int ikey = key.toint();
|
||||
if ( ikey>0 && ikey<=array.length )
|
||||
return array[ikey-1]!=null? array[ikey-1]: NIL;
|
||||
}
|
||||
return hashget( key );
|
||||
}
|
||||
|
||||
private LuaValue hashget(LuaValue key) {
|
||||
if ( hashEntries > 0 ) {
|
||||
LuaValue v = hashValues[hashFindSlot(key)];
|
||||
return v!=null? v: NIL;
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
|
||||
public void set( int key, LuaValue value ) {
|
||||
if ( m_metatable==null || ! rawget(key).isnil() || ! settable(this,LuaInteger.valueOf(key),value) )
|
||||
rawset(key, value);
|
||||
}
|
||||
|
||||
/** caller must ensure key is not nil */
|
||||
public void set( LuaValue key, LuaValue value ) {
|
||||
key.checknotnil();
|
||||
if ( m_metatable==null || ! rawget(key).isnil() || ! settable(this,key,value) )
|
||||
rawset(key, value);
|
||||
}
|
||||
|
||||
public void rawset( int key, LuaValue value ) {
|
||||
if ( ! arrayset(key, value) )
|
||||
hashset( LuaInteger.valueOf(key), value );
|
||||
}
|
||||
|
||||
/** caller must ensure key is not nil */
|
||||
public void rawset( LuaValue key, LuaValue value ) {
|
||||
if ( !key.isinttype() || !arrayset(key.toint(), value) )
|
||||
hashset( key, value );
|
||||
}
|
||||
|
||||
private boolean arrayset( int key, LuaValue value ) {
|
||||
if ( key>0 && key<=array.length ) {
|
||||
array[key-1] = (value.isnil()? null: value);
|
||||
return true;
|
||||
} else if ( key==array.length+1 && !value.isnil() ) {
|
||||
expandarray();
|
||||
array[key-1] = value;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void expandarray() {
|
||||
int n = array.length;
|
||||
int m = Math.max(2,n*2);
|
||||
array = resize(array, m);
|
||||
for ( int i=n; i<m; i++ ) {
|
||||
LuaValue k = LuaInteger.valueOf(i+1);
|
||||
LuaValue v = hashget(k);
|
||||
if ( !v.isnil() ) {
|
||||
hashset(k, NIL);
|
||||
array[i] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Varargs remove(int pos) {
|
||||
if ( pos == 0 )
|
||||
pos = length();
|
||||
if ( pos < 1 || pos > array.length )
|
||||
return NONE;
|
||||
LuaValue v = rawget(pos);
|
||||
for ( LuaValue r=v; !r.isnil(); ) {
|
||||
r = rawget(pos+1);
|
||||
rawset(pos++, r);
|
||||
}
|
||||
return v.isnil()? NONE: v;
|
||||
}
|
||||
|
||||
public void insert(int pos, LuaValue value) {
|
||||
if ( pos == 0 )
|
||||
pos = length()+1;
|
||||
while ( ! value.isnil() ) {
|
||||
LuaValue v = rawget( pos );
|
||||
rawset(pos++, value);
|
||||
value = v;
|
||||
}
|
||||
}
|
||||
|
||||
public LuaValue concat(LuaString sep, int i, int j) {
|
||||
Buffer sb = new Buffer ();
|
||||
if ( i<=j ) {
|
||||
sb.append( get(i).checkstring() );
|
||||
while ( ++i<=j ) {
|
||||
sb.append( sep );
|
||||
sb.append( get(i).checkstring() );
|
||||
}
|
||||
}
|
||||
return sb.tostrvalue();
|
||||
}
|
||||
|
||||
public LuaValue getn() {
|
||||
for ( int n=array.length; --n>0; )
|
||||
if ( array[n]!=null )
|
||||
return LuaInteger.valueOf(n+1);
|
||||
return ZERO;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the length of this table, as lua defines it.
|
||||
*/
|
||||
public int length() {
|
||||
int n=array.length+1,m=0;
|
||||
while ( !rawget(n).isnil() ) {
|
||||
m = n;
|
||||
n += array.length+hashEntries+1;
|
||||
}
|
||||
while ( n > m+1 ) {
|
||||
int k = (n+m) / 2;
|
||||
if ( !rawget(k).isnil() )
|
||||
m = k;
|
||||
else
|
||||
n = k;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
public LuaValue len() {
|
||||
return LuaInteger.valueOf(length());
|
||||
}
|
||||
|
||||
public int maxn() {
|
||||
int n = 0;
|
||||
for ( int i=0; i<array.length; i++ )
|
||||
if ( array[i] != null )
|
||||
n = i+1;
|
||||
for ( int i=0; i<hashKeys.length; i++ ) {
|
||||
LuaValue v = hashKeys[i];
|
||||
if ( v!=null && v.isinttype() ) {
|
||||
int key = v.toint();
|
||||
if ( key > n )
|
||||
n = key;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the next element after a particular key in the table
|
||||
* @return key,value or nil
|
||||
*/
|
||||
public Varargs next( LuaValue key ) {
|
||||
int i = 0;
|
||||
do {
|
||||
// find current key index
|
||||
if ( ! key.isnil() ) {
|
||||
if ( key.isinttype() ) {
|
||||
i = key.toint();
|
||||
if ( i>0 && i<=array.length ) {
|
||||
if ( array[i-1] == null )
|
||||
error( "invalid key to 'next'" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
i = hashFindSlot(key);
|
||||
if ( hashKeys[i] == null )
|
||||
error( "invalid key to 'next'" );
|
||||
i += 1+array.length;
|
||||
}
|
||||
} while ( false );
|
||||
|
||||
// check array part
|
||||
for ( ; i<array.length; ++i )
|
||||
if ( array[i] != null )
|
||||
return varargsOf(LuaInteger.valueOf(i+1),array[i]);
|
||||
|
||||
// check hash part
|
||||
for ( i-=array.length; i<hashKeys.length; ++i )
|
||||
if ( hashKeys[i] != null )
|
||||
return varargsOf(hashKeys[i],hashValues[i]);
|
||||
|
||||
// nothing found, push nil, return nil.
|
||||
return NIL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next element after a particular key in the
|
||||
* contiguous array part of a table
|
||||
* @return key,value or nil
|
||||
*/
|
||||
public Varargs inext(LuaValue key) {
|
||||
int i = key.optint(0);
|
||||
return i<0 || i>=array.length || array[i]==null?
|
||||
NIL:
|
||||
varargsOf(LuaInteger.valueOf(i+1),array[i]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the supplied function once for each key-value pair
|
||||
*
|
||||
* @param func function to call
|
||||
*/
|
||||
public LuaValue foreach(LuaValue func) {
|
||||
LuaValue v = NIL;
|
||||
for ( int i=0; i<array.length; i++ )
|
||||
if ( array[i] != null )
|
||||
if ( !(v = func.call(LuaInteger.valueOf(i+1), array[i])).isnil() )
|
||||
return v;
|
||||
for ( int i=0; i<hashKeys.length; i++ )
|
||||
if ( hashKeys[i] != null )
|
||||
if ( !(v = func.call(hashKeys[i], hashValues[i])).isnil() )
|
||||
return v;
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the supplied function once for each key-value pair
|
||||
* in the contiguous array part
|
||||
*
|
||||
* @param func
|
||||
*/
|
||||
public LuaValue foreachi(LuaValue func) {
|
||||
LuaValue v = NIL;
|
||||
for ( int i=0; i<array.length && array[i]!=null; i++ )
|
||||
if ( !(v = func.call(LuaInteger.valueOf(i+1), array[i])).isnil() )
|
||||
return v;
|
||||
return v;
|
||||
}
|
||||
|
||||
// ======================= test hooks =================
|
||||
|
||||
/** Value used in testing to provide the capacity of the array part */
|
||||
int arrayCapacity() {
|
||||
return array.length;
|
||||
}
|
||||
|
||||
/** Value used in testing to provide the capacity of the hash part */
|
||||
int hashCapacity() {
|
||||
return hashKeys.length;
|
||||
}
|
||||
|
||||
/** Value used in testing to provide the total count of elements */
|
||||
int keyCount() {
|
||||
int n = 0;
|
||||
for ( int i=0; i<array.length; i++ )
|
||||
if ( array[i] != null )
|
||||
++n;
|
||||
return n + hashEntries;
|
||||
}
|
||||
|
||||
/** Value used in testing to enumerate the keys */
|
||||
public LuaValue[] keys() {
|
||||
LuaValue[] vals = new LuaValue[keyCount()];
|
||||
int n = 0;
|
||||
for ( int i=0; i<array.length; i++ )
|
||||
if ( array[i] != null )
|
||||
vals[n++] = LuaInteger.valueOf(i+1);
|
||||
for ( int i=0; i<hashKeys.length; i++ )
|
||||
if ( hashKeys[i] != null )
|
||||
vals[n++] = hashKeys[i];
|
||||
return vals;
|
||||
}
|
||||
|
||||
// ======================= hashset =================
|
||||
|
||||
public void hashset(LuaValue key, LuaValue value) {
|
||||
if ( value.isnil() )
|
||||
hashRemove(key);
|
||||
else {
|
||||
if ( checkLoadFactor() )
|
||||
rehash();
|
||||
|
||||
int slot = hashFindSlot( key );
|
||||
if ( hashFillSlot( slot, value ) )
|
||||
return;
|
||||
hashKeys[slot] = key;
|
||||
hashValues[slot] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int hashFindSlot(LuaValue key) {
|
||||
int i = ( key.hashCode() & 0x7FFFFFFF ) % hashKeys.length;
|
||||
|
||||
// This loop is guaranteed to terminate as long as we never allow the
|
||||
// table to get 100% full.
|
||||
LuaValue k;
|
||||
while ( ( k = hashKeys[i] ) != null && !k.eq_b(key) ) {
|
||||
i = ( i + 1 ) % hashKeys.length;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
private boolean hashFillSlot( int slot, LuaValue value ) {
|
||||
hashValues[ slot ] = value;
|
||||
if ( hashKeys[ slot ] != null ) {
|
||||
return true;
|
||||
} else {
|
||||
++hashEntries;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void hashRemove( LuaValue key ) {
|
||||
if ( hashKeys.length > 0 ) {
|
||||
int slot = hashFindSlot( key );
|
||||
hashClearSlot( slot );
|
||||
}
|
||||
}
|
||||
|
||||
private void hashClearSlot( int i ) {
|
||||
if ( hashKeys[ i ] != null ) {
|
||||
|
||||
int j = i;
|
||||
int n = hashKeys.length;
|
||||
while ( hashKeys[ j = ( ( j + 1 ) % n ) ] != null ) {
|
||||
final int k = ( ( hashKeys[ j ].hashCode() )& 0x7FFFFFFF ) % n;
|
||||
if ( ( j > i && ( k <= i || k > j ) ) ||
|
||||
( j < i && ( k <= i && k > j ) ) ) {
|
||||
hashKeys[ i ] = hashKeys[ j ];
|
||||
hashValues[ i ] = hashValues[ j ];
|
||||
i = j;
|
||||
}
|
||||
}
|
||||
|
||||
--hashEntries;
|
||||
hashKeys[ i ] = null;
|
||||
hashValues[ i ] = null;
|
||||
|
||||
if ( hashEntries == 0 ) {
|
||||
hashKeys = NOVALS;
|
||||
hashValues = NOVALS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkLoadFactor() {
|
||||
// Using a load factor of (n+1) >= 7/8 because that is easy to compute without
|
||||
// overflow or division.
|
||||
final int hashCapacity = hashKeys.length;
|
||||
return hashEntries+1 >= (hashCapacity - (hashCapacity>>3));
|
||||
}
|
||||
|
||||
private void rehash() {
|
||||
final int oldCapacity = hashKeys.length;
|
||||
final int newCapacity = oldCapacity+(oldCapacity>>2)+MIN_HASH_CAPACITY;
|
||||
|
||||
final LuaValue[] oldKeys = hashKeys;
|
||||
final LuaValue[] oldValues = hashValues;
|
||||
|
||||
hashKeys = new LuaValue[ newCapacity ];
|
||||
hashValues = new LuaValue[ newCapacity ];
|
||||
|
||||
for ( int i = 0; i < oldCapacity; ++i ) {
|
||||
final LuaValue k = oldKeys[i];
|
||||
if ( k != null ) {
|
||||
final LuaValue v = oldValues[i];
|
||||
final int slot = hashFindSlot( k );
|
||||
hashKeys[slot] = k;
|
||||
hashValues[slot] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------- sort support -----------------------------
|
||||
//
|
||||
// implemented heap sort from wikipedia
|
||||
//
|
||||
// Only sorts the contiguous array part.
|
||||
//
|
||||
public void sort(LuaValue comparator) {
|
||||
int n = array.length;
|
||||
while ( n > 0 && array[n-1] == null )
|
||||
--n;
|
||||
if ( n > 1 )
|
||||
heapSort(n, comparator);
|
||||
}
|
||||
|
||||
private void heapSort(int count, LuaValue cmpfunc) {
|
||||
heapify(count, cmpfunc);
|
||||
for ( int end=count-1; end>0; ) {
|
||||
swap(end, 0);
|
||||
siftDown(0, --end, cmpfunc);
|
||||
}
|
||||
}
|
||||
|
||||
private void heapify(int count, LuaValue cmpfunc) {
|
||||
for ( int start=count/2-1; start>=0; --start )
|
||||
siftDown(start, count - 1, cmpfunc);
|
||||
}
|
||||
|
||||
private void siftDown(int start, int end, LuaValue cmpfunc) {
|
||||
for ( int root=start; root*2+1 <= end; ) {
|
||||
int child = root*2+1;
|
||||
if (child < end && compare(child, child + 1, cmpfunc))
|
||||
++child;
|
||||
if (compare(root, child, cmpfunc)) {
|
||||
swap(root, child);
|
||||
root = child;
|
||||
} else
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean compare(int i, int j, LuaValue cmpfunc) {
|
||||
LuaValue a = array[i];
|
||||
LuaValue b = array[j];
|
||||
if ( a == null || b == null )
|
||||
return false;
|
||||
if ( ! cmpfunc.isnil() ) {
|
||||
return cmpfunc.call(a,b).toboolean();
|
||||
} else {
|
||||
return a.lt_b(b);
|
||||
}
|
||||
}
|
||||
|
||||
private void swap(int i, int j) {
|
||||
LuaValue a = array[i];
|
||||
array[i] = array[j];
|
||||
array[j] = a;
|
||||
}
|
||||
|
||||
}
|
||||
225
src/core/org/luaj/vm2/LuaThread.java
Normal file
225
src/core/org/luaj/vm2/LuaThread.java
Normal file
@@ -0,0 +1,225 @@
|
||||
/*******************************************************************************
|
||||
* 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 org.luaj.vm2;
|
||||
|
||||
import org.luaj.vm2.lib.DebugLib;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of lua coroutines using Java Threads
|
||||
*/
|
||||
public class LuaThread extends LuaValue implements Runnable {
|
||||
|
||||
public static LuaValue s_metatable;
|
||||
|
||||
private static final int STATUS_SUSPENDED = 0;
|
||||
private static final int STATUS_RUNNING = 1;
|
||||
private static final int STATUS_NORMAL = 2;
|
||||
private static final int STATUS_DEAD = 3;
|
||||
private static final String[] STATUS_NAMES = {
|
||||
"suspended",
|
||||
"running",
|
||||
"normal",
|
||||
"dead" };
|
||||
|
||||
private int status = STATUS_SUSPENDED;
|
||||
|
||||
private Thread thread;
|
||||
private LuaValue env;
|
||||
private LuaValue func;
|
||||
private Varargs args;
|
||||
public LuaValue err;
|
||||
|
||||
|
||||
public static final int MAX_CALLSTACK = 64;
|
||||
public final LuaFunction[] callstack = new LuaFunction[MAX_CALLSTACK];
|
||||
public int calls = 0;
|
||||
|
||||
private static final LuaThread mainthread = new LuaThread();
|
||||
|
||||
// state of running thread including call stack
|
||||
private static LuaThread running_thread = mainthread;
|
||||
|
||||
// thread-local used by DebugLib to store debugging state
|
||||
public Object debugState;
|
||||
|
||||
|
||||
LuaThread() {
|
||||
}
|
||||
|
||||
public LuaThread(LuaValue func, LuaValue env) {
|
||||
this.env = env;
|
||||
this.func = func;
|
||||
}
|
||||
|
||||
public int type() {
|
||||
return LuaValue.TTHREAD;
|
||||
}
|
||||
|
||||
public String typename() {
|
||||
return "thread";
|
||||
}
|
||||
|
||||
public boolean isthread() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public LuaThread optthread(LuaThread defval) {
|
||||
return this;
|
||||
}
|
||||
|
||||
public LuaThread checkthread() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public LuaValue getmetatable() {
|
||||
return s_metatable;
|
||||
}
|
||||
|
||||
public LuaValue getfenv() {
|
||||
return env;
|
||||
}
|
||||
|
||||
public void setfenv(LuaValue env) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return STATUS_NAMES[status];
|
||||
}
|
||||
|
||||
public static LuaThread getRunning() {
|
||||
return running_thread;
|
||||
}
|
||||
|
||||
public static boolean isMainThread(LuaThread r) {
|
||||
return r == mainthread;
|
||||
}
|
||||
|
||||
/** get environment of the running thread, or defval if not defined */
|
||||
public static LuaValue getRunningEnv(LuaValue defval) {
|
||||
return running_thread.env!=null? running_thread.env: defval;
|
||||
}
|
||||
|
||||
public static final void onCall(LuaFunction function) {
|
||||
running_thread.callstack[running_thread.calls++] = function;
|
||||
if (DebugLib.DEBUG_ENABLED)
|
||||
DebugLib.debugOnCall(running_thread, running_thread.calls, function);
|
||||
}
|
||||
|
||||
public static final void onReturn() {
|
||||
running_thread.callstack[--running_thread.calls] = null;
|
||||
if (DebugLib.DEBUG_ENABLED)
|
||||
DebugLib.debugOnReturn(running_thread, running_thread.calls);
|
||||
}
|
||||
|
||||
public static int getCallstackDepth() {
|
||||
return running_thread.calls;
|
||||
}
|
||||
|
||||
public static final LuaFunction getCallstackFunction(int level) {
|
||||
return level>=0 || level<running_thread.calls?
|
||||
running_thread.callstack[running_thread.calls-level-1]:
|
||||
null;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
synchronized ( this ) {
|
||||
try {
|
||||
this.args = func.invoke(this.args);
|
||||
} finally {
|
||||
status = STATUS_DEAD;
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Varargs yield(Varargs args) {
|
||||
synchronized ( this ) {
|
||||
if ( status != STATUS_RUNNING )
|
||||
error(this+" not running");
|
||||
status = STATUS_SUSPENDED;
|
||||
this.args = args;
|
||||
this.notify();
|
||||
try {
|
||||
this.wait();
|
||||
status = STATUS_RUNNING;
|
||||
return this.args;
|
||||
} catch ( InterruptedException e ) {
|
||||
status = STATUS_DEAD;
|
||||
error( "thread interrupted" );
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Start or resume this thread */
|
||||
public Varargs resume(Varargs args) {
|
||||
|
||||
synchronized ( this ) {
|
||||
if ( status == STATUS_DEAD ) {
|
||||
return varargsOf(FALSE, valueOf("cannot resume dead coroutine"));
|
||||
}
|
||||
|
||||
// set prior thread to normal status while we are running
|
||||
LuaThread prior = running_thread;
|
||||
try {
|
||||
// set our status to running
|
||||
prior.status = STATUS_NORMAL;
|
||||
running_thread = this;
|
||||
this.status = STATUS_RUNNING;
|
||||
|
||||
// copy args in
|
||||
this.args = args;
|
||||
|
||||
// start the thread
|
||||
if ( thread == null ) {
|
||||
thread = new Thread(this);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
// run this vm until it yields
|
||||
this.notify();
|
||||
this.wait();
|
||||
|
||||
// copy return values from yielding stack state
|
||||
return varargsOf(LuaValue.TRUE, this.args);
|
||||
|
||||
} catch ( Throwable t ) {
|
||||
status = STATUS_DEAD;
|
||||
try {
|
||||
return varargsOf(FALSE, valueOf("thread: "+t));
|
||||
} finally {
|
||||
this.notify();
|
||||
}
|
||||
|
||||
} finally {
|
||||
// previous thread is now running again
|
||||
running_thread = prior;
|
||||
prior.status = STATUS_RUNNING;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
105
src/core/org/luaj/vm2/LuaUserdata.java
Normal file
105
src/core/org/luaj/vm2/LuaUserdata.java
Normal file
@@ -0,0 +1,105 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
|
||||
public class LuaUserdata extends LuaValue {
|
||||
|
||||
public final Object m_instance;
|
||||
public LuaValue m_metatable;
|
||||
|
||||
public LuaUserdata(Object obj) {
|
||||
m_instance = obj;
|
||||
}
|
||||
|
||||
public LuaUserdata(Object obj, LuaValue metatable) {
|
||||
m_instance = obj;
|
||||
m_metatable = metatable;
|
||||
}
|
||||
|
||||
public int type() {
|
||||
return LuaValue.TUSERDATA;
|
||||
}
|
||||
|
||||
public String typename() {
|
||||
return "userdata";
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return m_instance.hashCode();
|
||||
}
|
||||
|
||||
public Object userdata() {
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
public boolean isuserdata() { return true; }
|
||||
public boolean isuserdata(Class c) { return c.isAssignableFrom(m_instance.getClass()); }
|
||||
public Object touserdata() { return m_instance; }
|
||||
public Object touserdata(Class c) { return c.isAssignableFrom(m_instance.getClass())? m_instance: null; }
|
||||
public Object optuserdata(Object defval) { return m_instance; }
|
||||
public Object optuserdata(Class c, Object defval) {
|
||||
if (!c.isAssignableFrom(m_instance.getClass()))
|
||||
typerror(c.getName());
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
public LuaValue getmetatable() {
|
||||
return m_metatable;
|
||||
}
|
||||
|
||||
public LuaValue setmetatable(LuaValue metatable) {
|
||||
this.m_metatable = metatable;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Object checkuserdata() {
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
public Object checkuserdata(Class c) {
|
||||
if ( c.isAssignableFrom(m_instance.getClass()) )
|
||||
return m_instance;
|
||||
return typerror(c.getName());
|
||||
}
|
||||
|
||||
public LuaValue get( LuaValue key ) {
|
||||
return m_metatable!=null? gettable(this,key): NIL;
|
||||
}
|
||||
|
||||
public void set( LuaValue key, LuaValue value ) {
|
||||
if ( m_metatable!=null && ! settable(this,key,value) )
|
||||
error( "cannot set "+key+" for userdata" );
|
||||
}
|
||||
|
||||
public boolean equals( Object val ) {
|
||||
if ( ! (val instanceof LuaUserdata) )
|
||||
return false;
|
||||
LuaUserdata u = (LuaUserdata) val;
|
||||
return m_instance.equals(u.m_instance);
|
||||
}
|
||||
|
||||
public boolean eq_b( LuaValue val ) {
|
||||
return equals(val);
|
||||
}
|
||||
|
||||
}
|
||||
500
src/core/org/luaj/vm2/LuaValue.java
Normal file
500
src/core/org/luaj/vm2/LuaValue.java
Normal file
@@ -0,0 +1,500 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
|
||||
|
||||
abstract
|
||||
public class LuaValue extends Varargs {
|
||||
|
||||
public static final int TINT = (-2);
|
||||
public static final int TNONE = (-1);
|
||||
public static final int TNIL = 0;
|
||||
public static final int TBOOLEAN = 1;
|
||||
public static final int TLIGHTUSERDATA = 2;
|
||||
public static final int TNUMBER = 3;
|
||||
public static final int TSTRING = 4;
|
||||
public static final int TTABLE = 5;
|
||||
public static final int TFUNCTION = 6;
|
||||
public static final int TUSERDATA = 7;
|
||||
public static final int TTHREAD = 8;
|
||||
public static final int TVALUE = 9;
|
||||
|
||||
public static final String[] TYPE_NAMES = {
|
||||
"nil",
|
||||
"boolean",
|
||||
"lightuserdata",
|
||||
"number",
|
||||
"string",
|
||||
"table",
|
||||
"function",
|
||||
"userdata",
|
||||
"thread",
|
||||
"value",
|
||||
};
|
||||
|
||||
public static final LuaValue NIL = new LuaNil();
|
||||
public static final LuaBoolean TRUE = new LuaBoolean(true);
|
||||
public static final LuaBoolean FALSE = new LuaBoolean(false);
|
||||
public static final LuaValue NONE = new None();
|
||||
public static final LuaNumber ZERO = LuaInteger.valueOf(0);
|
||||
public static final LuaNumber ONE = LuaInteger.valueOf(1);
|
||||
public static final LuaNumber MINUSONE = LuaInteger.valueOf(-1);
|
||||
public static final LuaValue[] NOVALS = {};
|
||||
|
||||
public static final LuaString INDEX = valueOf("__index");
|
||||
public static final LuaString NEWINDEX = valueOf("__newindex");
|
||||
public static final LuaString CALL = valueOf("__call");
|
||||
public static final LuaString MODE = valueOf("__mode");
|
||||
public static final LuaString METATABLE = valueOf("__metatable");
|
||||
public static final LuaString EMPTYSTRING = valueOf("");
|
||||
|
||||
private static int MAXLOCALS = 200;
|
||||
public static final LuaValue[] NILS = new LuaValue[MAXLOCALS];
|
||||
static {
|
||||
for ( int i=0; i<MAXLOCALS; i++ )
|
||||
NILS[i] = NIL;
|
||||
}
|
||||
|
||||
// type
|
||||
abstract public int type();
|
||||
abstract public String typename();
|
||||
|
||||
// type checks
|
||||
public boolean isboolean() { return false; }
|
||||
public boolean isclosure() { return false; }
|
||||
public boolean isfunction() { return false; }
|
||||
public boolean isint() { return false; } // may convert from string
|
||||
public boolean isinttype() { return false; } // will not convert string
|
||||
public boolean islong() { return false; }
|
||||
public boolean isnil() { return false; }
|
||||
public boolean isnumber() { return false; } // may convert from string
|
||||
public boolean isstring() { return false; }
|
||||
public boolean isthread() { return false; }
|
||||
public boolean istable() { return false; }
|
||||
public boolean isuserdata() { return false; }
|
||||
public boolean isuserdata(Class c) { return false; }
|
||||
|
||||
// type coercion to java primitives
|
||||
public boolean toboolean() { return true; }
|
||||
public byte tobyte() { return 0; }
|
||||
public char tochar() { return 0; }
|
||||
public double todouble() { return 0; }
|
||||
public float tofloat() { return 0; }
|
||||
public int toint() { return 0; }
|
||||
public long tolong() { return 0; }
|
||||
public short toshort() { return 0; }
|
||||
public String toString() { return typename() + ": " + Integer.toHexString(hashCode()); }
|
||||
public Object touserdata() { return null; }
|
||||
public Object touserdata(Class c) { return null; }
|
||||
|
||||
// type coercion to lua values
|
||||
/** @return NIL if not a number or convertible to a number */
|
||||
public LuaValue tonumber() { return NIL; }
|
||||
|
||||
// optional argument conversions
|
||||
public boolean optboolean(boolean defval) { typerror("boolean"); return false; }
|
||||
public LuaClosure optclosure(LuaClosure defval) { typerror("closure"); return null; }
|
||||
public double optdouble(double defval) { typerror("double"); return 0; }
|
||||
public LuaFunction optfunction(LuaFunction defval) { typerror("function"); return null; }
|
||||
public int optint(int defval) { typerror("int"); return 0; }
|
||||
public LuaInteger optinteger(LuaInteger defval) { typerror("integer"); return null; }
|
||||
public long optlong(long defval) { typerror("long"); return 0; }
|
||||
public LuaNumber optnumber(LuaNumber defval) { typerror("number"); return null; }
|
||||
public String optString(String defval) { typerror("String"); return null; }
|
||||
public LuaString optstring(LuaString defval) { typerror("string"); return null; }
|
||||
public LuaTable opttable(LuaTable defval) { typerror("table"); return null; }
|
||||
public LuaThread optthread(LuaThread defval) { typerror("thread"); return null; }
|
||||
public Object optuserdata(Object defval) { typerror("object"); return null; }
|
||||
public Object optuserdata(Class c, Object defval) { typerror(c.getName()); return null; }
|
||||
public LuaValue optvalue(LuaValue defval) { return this; }
|
||||
|
||||
// argument type checks
|
||||
public boolean checkboolean() { typerror("boolean"); return false; }
|
||||
public LuaClosure checkclosure() { typerror("closure"); return null; }
|
||||
public double checkdouble() { typerror("double"); return 0; }
|
||||
public LuaValue checkfunction() { typerror("function"); return null; }
|
||||
public int checkint() { typerror("int"); return 0; }
|
||||
public LuaInteger checkinteger() { typerror("integer"); return null; }
|
||||
public long checklong() { typerror("long"); return 0; }
|
||||
public LuaNumber checknumber() { typerror("number"); return null; }
|
||||
public String checkString() { typerror("string"); return null; }
|
||||
public LuaString checkstring() { typerror("string"); return null; }
|
||||
public LuaTable checktable() { typerror("table"); return null; }
|
||||
public LuaThread checkthread() { typerror("thread"); return null; }
|
||||
public Object checkuserdata() { typerror("userdata"); return null; }
|
||||
public Object checkuserdata(Class c) { typerror("userdata"); return null; }
|
||||
public LuaValue checknotnil() { return this; }
|
||||
|
||||
// errors
|
||||
public static LuaValue error(String message) { throw new LuaError(message); }
|
||||
public static LuaValue error(int iarg, String message) { throw new LuaError("arg "+iarg+": "+message); }
|
||||
public static void assert_(boolean b,String msg) { if(!b) throw new LuaError(msg); }
|
||||
public static void argerror(int i,String msg) { throw new LuaError("arg "+i+": "+msg); }
|
||||
protected LuaValue typerror(String expected) { throw new LuaError("expected "+expected+" got "+typename()); }
|
||||
protected LuaValue typerror(int iarg, String expected) { throw new LuaError("arg "+iarg+": expected "+expected+" got "+typename()); }
|
||||
protected LuaValue unimplemented(String fun) { throw new LuaError("'"+fun+"' not implemented for "+typename()); }
|
||||
protected LuaValue aritherror() { throw new LuaError("attempt to perform arithmetic on "+typename()); }
|
||||
protected LuaValue aritherror(String fun) { throw new LuaError("attempt to perform arithmetic '"+fun+"' on "+typename()); }
|
||||
|
||||
// table operations
|
||||
public LuaValue get( LuaValue key ) { return gettable(this,key); }
|
||||
public LuaValue get( int key ) { return get(LuaInteger.valueOf(key)); }
|
||||
public LuaValue get( String key ) { return get(valueOf(key)); }
|
||||
public void set( LuaValue key, LuaValue value ) { settable(this, key, value); }
|
||||
public void set( int key, LuaValue value ) { set(LuaInteger.valueOf(key), value ); }
|
||||
public void set( int key, String value ) { set(key, valueOf(value) ); }
|
||||
public void set( String key, LuaValue value ) { set(valueOf(key), value ); }
|
||||
public void set( String key, double value ) { set(valueOf(key), valueOf(value) ); }
|
||||
public void set( String key, int value ) { set(valueOf(key), valueOf(value) ); }
|
||||
public void set( String key, String value ) { set(valueOf(key), valueOf(value) ); }
|
||||
public LuaValue rawget( LuaValue key ) { return unimplemented("rawget"); }
|
||||
public LuaValue rawget( int key ) { return rawget(valueOf(key)); }
|
||||
public LuaValue rawget( String key ) { return rawget(valueOf(key)); }
|
||||
public void rawset( LuaValue key, LuaValue value ) { unimplemented("rawset"); }
|
||||
public void rawset( int key, LuaValue value ) { rawset(valueOf(key),value); }
|
||||
public void rawset( int key, String value ) { rawset(key,valueOf(value)); }
|
||||
public void rawset( String key, LuaValue value ) { rawset(valueOf(key),value); }
|
||||
public void rawset( String key, double value ) { rawset(valueOf(key),valueOf(value)); }
|
||||
public void rawset( String key, int value ) { rawset(valueOf(key),valueOf(value)); }
|
||||
public void rawset( String key, String value ) { rawset(valueOf(key),valueOf(value)); }
|
||||
public void presize( int i) { unimplemented("presize"); }
|
||||
public Varargs next(LuaValue index) { unimplemented("next"); return null; }
|
||||
public Varargs inext(LuaValue index) { unimplemented("inext"); return null; }
|
||||
|
||||
// varargs references
|
||||
public LuaValue arg(int index) { return index==1? this: NIL; }
|
||||
public int narg() { return 1; };
|
||||
public LuaValue arg1() { return this; }
|
||||
|
||||
// metatable operations
|
||||
public LuaValue getmetatable() { return null; };
|
||||
public LuaValue setmetatable(LuaValue metatable) { return error("setmetatable not allowed for "+typename()); }
|
||||
public LuaValue getfenv() { typerror("function or thread"); return null; }
|
||||
public void setfenv(LuaValue env) { typerror("function or thread"); }
|
||||
|
||||
// function calls
|
||||
public LuaValue call() { return unimplemented("call"); }
|
||||
public LuaValue call(LuaValue arg) { return unimplemented("call"); }
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) { return unimplemented("call"); }
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) { return unimplemented("call"); }
|
||||
public LuaValue method(String name) { return this.get(name).call(this); }
|
||||
public LuaValue method(LuaValue name) { return this.get(name).call(this); }
|
||||
public LuaValue method(String name, LuaValue arg) { return this.get(name).call(this,arg); }
|
||||
public LuaValue method(LuaValue name, LuaValue arg) { return this.get(name).call(this,arg); }
|
||||
public LuaValue method(String name, LuaValue arg1, LuaValue arg2) { return this.get(name).call(this,arg1,arg2); }
|
||||
public LuaValue method(LuaValue name, LuaValue arg1, LuaValue arg2) { return this.get(name).call(this,arg1,arg2); }
|
||||
public Varargs invoke() { return invoke(NONE); }
|
||||
public Varargs invoke(Varargs args) { unimplemented("call"); return null; }
|
||||
public Varargs invoke(LuaValue arg,Varargs varargs) { return invoke(varargsOf(arg,varargs)); }
|
||||
public Varargs invoke(LuaValue arg1,LuaValue arg2,Varargs varargs) { return invoke(varargsOf(arg1,arg2,varargs)); }
|
||||
public Varargs invoke(LuaValue[] args) { return invoke(varargsOf(args)); }
|
||||
public Varargs invoke(LuaValue[] args,Varargs varargs) { return invoke(varargsOf(args,varargs)); }
|
||||
public Varargs invokemethod(String name, Varargs args) { return get(name).invoke(varargsOf(this,args)); }
|
||||
public Varargs invokemethod(LuaValue name, Varargs args) { return get(name).invoke(varargsOf(this,args)); }
|
||||
public Varargs invokemethod(String name, LuaValue[] args) { return get(name).invoke(varargsOf(this,varargsOf(args))); }
|
||||
public Varargs invokemethod(LuaValue name, LuaValue[] args) { return get(name).invoke(varargsOf(this,varargsOf(args))); }
|
||||
|
||||
// unary operators
|
||||
public LuaValue not() { return FALSE; }
|
||||
public LuaValue neg() { return aritherror("neg"); }
|
||||
public LuaValue len() { return typerror("len"); }
|
||||
public int length() { typerror("len"); return 0; }
|
||||
public LuaValue getn() { return typerror("getn"); }
|
||||
|
||||
// object equality, used for key comparison
|
||||
public boolean equals(Object obj) { return this == obj; }
|
||||
|
||||
// arithmetic equality
|
||||
public LuaValue eq( LuaValue val ) { return valueOf(eq_b(val)); }
|
||||
public boolean eq_b( LuaValue val ) { return this == val; }
|
||||
public boolean eq_b( double val ) { return false; }
|
||||
public boolean eq_b( int val ) { return false; }
|
||||
public LuaValue neq( LuaValue val ) { return valueOf(!eq_b(val)); }
|
||||
public boolean neq_b( LuaValue val ) { return ! eq_b(val); }
|
||||
public boolean neq_b( double val ) { return ! eq_b(val); }
|
||||
public boolean neq_b( int val ) { return ! eq_b(val); }
|
||||
|
||||
// arithmetic operators
|
||||
public LuaValue add( LuaValue rhs ) { return aritherror("add"); }
|
||||
public LuaValue add(double rhs) { return aritherror("add"); }
|
||||
public LuaValue add(int rhs) { return add((double)rhs); }
|
||||
public LuaValue sub( LuaValue rhs ) { return aritherror("sub"); }
|
||||
public LuaValue subFrom(double lhs) { return aritherror("sub"); }
|
||||
public LuaValue subFrom(int lhs) { return subFrom((double)lhs); }
|
||||
public LuaValue mul( LuaValue rhs ) { return aritherror("mul"); }
|
||||
public LuaValue mul(double rhs) { return aritherror("mul"); }
|
||||
public LuaValue mul(int rhs) { return mul((double)rhs); }
|
||||
public LuaValue pow( LuaValue rhs ) { return aritherror("pow"); }
|
||||
public LuaValue powWith(double lhs) { return aritherror("mul"); }
|
||||
public LuaValue powWith(int lhs) { return powWith((double)lhs); }
|
||||
public LuaValue div( LuaValue rhs ) { return aritherror("div"); }
|
||||
public LuaValue divInto(double lhs) { return aritherror("divInto"); }
|
||||
public LuaValue mod( LuaValue rhs ) { return aritherror("mod"); }
|
||||
public LuaValue modFrom(double lhs) { return aritherror("modFrom"); }
|
||||
|
||||
// relational operators
|
||||
public LuaValue lt( LuaValue rhs ) { return aritherror("lt"); }
|
||||
public boolean lt_b( LuaValue rhs ) { aritherror("lt"); return false; }
|
||||
public boolean lt_b( int rhs ) { aritherror("lt"); return false; }
|
||||
public boolean lt_b( double rhs ) { aritherror("lt"); return false; }
|
||||
public LuaValue lteq( LuaValue rhs ) { return aritherror("lteq"); }
|
||||
public boolean lteq_b( LuaValue rhs ) { aritherror("lteq"); return false; }
|
||||
public boolean lteq_b( int rhs ) { aritherror("lteq"); return false; }
|
||||
public boolean lteq_b( double rhs ) { aritherror("lteq"); return false; }
|
||||
public LuaValue gt( LuaValue rhs ) { return aritherror("gt"); }
|
||||
public boolean gt_b( LuaValue rhs ) { aritherror("gt"); return false; }
|
||||
public boolean gt_b( int rhs ) { aritherror("gt"); return false; }
|
||||
public boolean gt_b( double rhs ) { aritherror("gt"); return false; }
|
||||
public LuaValue gteq( LuaValue rhs ) { return aritherror("gteq"); }
|
||||
public boolean gteq_b( LuaValue rhs ) { aritherror("gteq"); return false; }
|
||||
public boolean gteq_b( int rhs ) { aritherror("gteq"); return false; }
|
||||
public boolean gteq_b( double rhs ) { aritherror("gteq"); return false; }
|
||||
|
||||
// string comparison
|
||||
public int strcmp( LuaValue rhs ) { typerror("attempt to compare "+typename()); return 0; }
|
||||
public int strcmp( LuaString rhs ) { typerror("attempt to compare "+typename()); return 0; }
|
||||
|
||||
// concatenation
|
||||
public LuaValue concat( LuaValue rhs ) { return valueOf(concat_s(rhs)); }
|
||||
public String concat_s( LuaValue rhs ) { error("attempt to concatenate "+this.typename()); return null; }
|
||||
public String concatTo_s( String lhs ) { error("attempt to concatenate "+this.typename()); return null; }
|
||||
|
||||
// boolean operators
|
||||
public LuaValue and( LuaValue rhs ) { return this.toboolean()? rhs: this; }
|
||||
public LuaValue or( LuaValue rhs ) { return this.toboolean()? this: rhs; }
|
||||
|
||||
// for loop helpers
|
||||
/** test numeric for loop */
|
||||
public boolean testfor_b(LuaValue limit, boolean stepgtzero) { return stepgtzero? lteq_b(limit): gteq_b(limit); }
|
||||
/** @deprecated - used in samples only */
|
||||
public boolean testfor_b(LuaValue limit) { return lteq(limit).toboolean(); }
|
||||
/** @deprecated - used in samples only */
|
||||
public boolean testfor_b(LuaValue limit, LuaValue step) { return step.gt_b(0)? lteq_b(limit): gteq_b(limit); }
|
||||
/** @deprecated - used in samples only, use add(1) instead */
|
||||
public LuaValue incr() { return add(ONE); }
|
||||
|
||||
// lua number/string conversion
|
||||
public LuaString strvalue() { typerror("strValue"); return null; }
|
||||
public LuaValue strongvalue() { return this; }
|
||||
|
||||
|
||||
// conversion from java values
|
||||
public static LuaBoolean valueOf(boolean b) { return b? LuaValue.TRUE: FALSE; };
|
||||
public static LuaInteger valueOf(int i) { return LuaInteger.valueOf(i); }
|
||||
public static LuaNumber valueOf(double d) { return LuaDouble.valueOf(d); };
|
||||
public static LuaString valueOf(String s) { return LuaString.valueOf(s); }
|
||||
public static LuaString valueOf(byte[] bytes) { return new LuaString(bytes); }
|
||||
public static LuaString valueOf(byte[] bytes, int off, int len) {
|
||||
return new LuaString(bytes,off,len);
|
||||
}
|
||||
|
||||
// table initializers
|
||||
public static LuaTable tableOf() { return new LuaTable(); }
|
||||
public static LuaTable listOf(LuaValue[] unnamedValues) { return new LuaTable(null,unnamedValues,null); }
|
||||
public static LuaTable listOf(LuaValue[] unnamedValues,Varargs lastarg) { return new LuaTable(null,unnamedValues,lastarg); }
|
||||
public static LuaTable tableOf(LuaValue[] namedValues) { return new LuaTable(namedValues,null,null); }
|
||||
public static LuaTable tableOf(LuaValue[] namedValues, LuaValue[] unnamedValues) {return new LuaTable(namedValues,unnamedValues,null); }
|
||||
public static LuaTable tableOf(LuaValue[] namedValues, LuaValue[] unnamedValues, Varargs lastarg) {return new LuaTable(namedValues,unnamedValues,lastarg); }
|
||||
|
||||
// userdata intializers
|
||||
public static LuaUserdata userdataOf(Object o) { return new LuaUserdata(o); }
|
||||
public static LuaUserdata userdataOf(Object o,LuaValue metatable) { return new LuaUserdata(o,metatable); }
|
||||
|
||||
private static final int MAXTAGLOOP = 100;
|
||||
|
||||
// metatable processing
|
||||
/** get value from metatable operations, or NIL if not defined by metatables */
|
||||
protected static LuaValue gettable(LuaValue t, LuaValue key) {
|
||||
LuaValue tm;
|
||||
int loop = 0;
|
||||
do {
|
||||
if (t.istable()) {
|
||||
LuaValue res = t.rawget(key);
|
||||
if ((!res.isnil()) || (tm = t.metatag(INDEX)).isnil())
|
||||
return res;
|
||||
} else if ((tm = t.metatag(INDEX)).isnil())
|
||||
t.typerror("index");
|
||||
if (tm.isfunction())
|
||||
return tm.call(t, key);
|
||||
t = tm;
|
||||
}
|
||||
while ( ++loop < MAXTAGLOOP );
|
||||
error("loop in gettable");
|
||||
return NIL;
|
||||
}
|
||||
|
||||
/** returns true if value was set via metatable processing, false otherwise */
|
||||
protected static boolean settable(LuaValue t, LuaValue key, LuaValue val) {
|
||||
LuaValue tm;
|
||||
int loop = 0;
|
||||
do {
|
||||
if (t.istable()) {
|
||||
if ((!t.rawget(key).isnil()) || (tm = t.metatag(NEWINDEX)).isnil()) {
|
||||
t.rawset(key, val);
|
||||
return true;
|
||||
}
|
||||
} else if ((tm = t.metatag(NEWINDEX)).isnil())
|
||||
t.typerror("index");
|
||||
if (tm.isfunction()) {
|
||||
tm.call(t, key, val);
|
||||
return true;
|
||||
}
|
||||
t = tm;
|
||||
}
|
||||
while ( ++loop < MAXTAGLOOP );
|
||||
error("loop in settable");
|
||||
return false;
|
||||
}
|
||||
|
||||
public LuaValue metatag(LuaValue tag) {
|
||||
LuaValue mt = getmetatable();
|
||||
if ( mt == null )
|
||||
return NIL;
|
||||
return mt.rawget(tag);
|
||||
}
|
||||
|
||||
private void indexerror() {
|
||||
error( "attempt to index ? (a "+typename()+" value)" );
|
||||
}
|
||||
|
||||
// common varargs constructors
|
||||
public static Varargs varargsOf(final LuaValue[] v) {
|
||||
switch ( v.length ) {
|
||||
case 0: return NONE;
|
||||
case 1: return v[0];
|
||||
case 2: return new PairVarargs(v[0],v[1]);
|
||||
default: return new ArrayVarargs(v,NONE);
|
||||
}
|
||||
}
|
||||
public static Varargs varargsOf(final LuaValue[] v,Varargs r) {
|
||||
switch ( v.length ) {
|
||||
case 0: return r;
|
||||
case 1: return new PairVarargs(v[0],r);
|
||||
default: return new ArrayVarargs(v,r);
|
||||
}
|
||||
}
|
||||
public static Varargs varargsOf(final LuaValue[] v, final int offset, final int length) {
|
||||
switch ( length ) {
|
||||
case 0: return NONE;
|
||||
case 1: return v[offset];
|
||||
case 2: return new PairVarargs(v[offset+0],v[offset+1]);
|
||||
default: return new ArrayPartVarargs(v,offset,length);
|
||||
}
|
||||
}
|
||||
public static Varargs varargsOf(final LuaValue[] v, final int offset, final int length,Varargs more) {
|
||||
switch ( length ) {
|
||||
case 0: return more;
|
||||
case 1: return new PairVarargs(v[offset],more);
|
||||
default: return new ArrayPartVarargs(v,offset,length,more);
|
||||
}
|
||||
}
|
||||
public static Varargs varargsOf(LuaValue v, Varargs r) {
|
||||
switch ( r.narg() ) {
|
||||
case 0: return v;
|
||||
default: return new PairVarargs(v,r);
|
||||
}
|
||||
}
|
||||
public static Varargs varargsOf(LuaValue v1,LuaValue v2,Varargs v3) {
|
||||
switch ( v3.narg() ) {
|
||||
case 0: return new PairVarargs(v1,v2);
|
||||
default: return new ArrayVarargs(new LuaValue[] {v1,v2},v3); }
|
||||
}
|
||||
|
||||
// empty varargs
|
||||
private static final class None extends LuaNil {
|
||||
public LuaValue arg(int i) { return NIL; }
|
||||
public int narg() { return 0; }
|
||||
public LuaValue arg1() { return NIL; }
|
||||
public String toString() { return "none"; }
|
||||
}
|
||||
|
||||
// varargs from array
|
||||
static final class ArrayVarargs extends Varargs {
|
||||
private final LuaValue[] v;
|
||||
private final Varargs r;
|
||||
ArrayVarargs(LuaValue[] v, Varargs r) {
|
||||
this.v = v;
|
||||
this.r = r ;
|
||||
}
|
||||
public LuaValue arg(int i) {
|
||||
return i >=1 && i<=v.length? v[i - 1]: r.arg(i-v.length);
|
||||
}
|
||||
public int narg() {
|
||||
return v.length+r.narg();
|
||||
}
|
||||
public LuaValue arg1() { return v.length>0? v[0]: r.arg1(); }
|
||||
}
|
||||
|
||||
// varargs from array part
|
||||
static final class ArrayPartVarargs extends Varargs {
|
||||
private final int offset;
|
||||
private final LuaValue[] v;
|
||||
private final int length;
|
||||
private final Varargs more;
|
||||
ArrayPartVarargs(LuaValue[] v, int offset, int length) {
|
||||
this.v = v;
|
||||
this.offset = offset;
|
||||
this.length = length;
|
||||
this.more = NONE;
|
||||
}
|
||||
public ArrayPartVarargs(LuaValue[] v, int offset, int length, Varargs more) {
|
||||
this.v = v;
|
||||
this.offset = offset;
|
||||
this.length = length;
|
||||
this.more = more;
|
||||
}
|
||||
public LuaValue arg(int i) {
|
||||
return i>=1&&i<=length? v[i+offset-1]: more.arg(i-length);
|
||||
}
|
||||
public int narg() {
|
||||
return length + more.narg();
|
||||
}
|
||||
public LuaValue arg1() {
|
||||
return length>0? v[offset]: more.arg1();
|
||||
}
|
||||
}
|
||||
|
||||
// varargs from two values
|
||||
static final class PairVarargs extends Varargs {
|
||||
private final LuaValue v1;
|
||||
private final Varargs v2;
|
||||
PairVarargs(LuaValue v1, Varargs v2) {
|
||||
this.v1 = v1;
|
||||
this.v2 = v2;
|
||||
}
|
||||
public LuaValue arg(int i) {
|
||||
return i==1? v1: v2.arg(i-1);
|
||||
}
|
||||
public int narg() {
|
||||
return 1+v2.narg();
|
||||
}
|
||||
public LuaValue arg1() {
|
||||
return v1;
|
||||
}
|
||||
public String toString() {
|
||||
return "{"+v1+","+v2+"}";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
377
src/core/org/luaj/vm2/Print.java
Normal file
377
src/core/org/luaj/vm2/Print.java
Normal file
@@ -0,0 +1,377 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintStream;
|
||||
|
||||
public class Print extends Lua {
|
||||
|
||||
/** opcode names */
|
||||
private static final String STRING_FOR_NULL = "null";
|
||||
public static PrintStream ps = System.out;
|
||||
|
||||
private 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,
|
||||
};
|
||||
|
||||
|
||||
static void printString(PrintStream ps, final LuaString s) {
|
||||
|
||||
ps.print('"');
|
||||
for (int i = 0, n = s.m_length; i < n; i++) {
|
||||
int c = s.m_bytes[s.m_offset+i];
|
||||
if ( c >= ' ' && c <= '~' && c != '\"' && c != '\\' )
|
||||
ps.print((char) c);
|
||||
else {
|
||||
switch (c) {
|
||||
case '"':
|
||||
ps.print("\\\"");
|
||||
break;
|
||||
case '\\':
|
||||
ps.print("\\\\");
|
||||
break;
|
||||
case 0x0007: /* bell */
|
||||
ps.print("\\a");
|
||||
break;
|
||||
case '\b': /* backspace */
|
||||
ps.print("\\b");
|
||||
break;
|
||||
case '\f': /* form feed */
|
||||
ps.print("\\f");
|
||||
break;
|
||||
case '\t': /* tab */
|
||||
ps.print("\\t");
|
||||
break;
|
||||
case '\r': /* carriage return */
|
||||
ps.print("\\r");
|
||||
break;
|
||||
case '\n': /* newline */
|
||||
ps.print("\\n");
|
||||
break;
|
||||
case 0x000B: /* vertical tab */
|
||||
ps.print("\\v");
|
||||
break;
|
||||
default:
|
||||
ps.print('\\');
|
||||
ps.print(Integer.toString(1000 + 0xff&c).substring(1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ps.print('"');
|
||||
}
|
||||
|
||||
static void printValue( PrintStream ps, LuaValue v ) {
|
||||
switch ( v.type() ) {
|
||||
case LuaValue.TSTRING: printString( ps, (LuaString) v ); break;
|
||||
default: ps.print( v.toString() );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void printConstant(PrintStream ps, Prototype f, int i) {
|
||||
printValue( ps, f.k[i] );
|
||||
}
|
||||
|
||||
public static void printCode(Prototype f) {
|
||||
int[] code = f.code;
|
||||
int pc, n = code.length;
|
||||
for (pc = 0; pc < n; pc++) {
|
||||
printOpCode(f, pc);
|
||||
ps.println();
|
||||
}
|
||||
}
|
||||
|
||||
public static void printOpCode(Prototype f, int pc) {
|
||||
printOpCode(ps,f,pc);
|
||||
}
|
||||
|
||||
public static void printOpCode(PrintStream ps, Prototype f, int pc) {
|
||||
int[] code = f.code;
|
||||
int i = code[pc];
|
||||
int o = GET_OPCODE(i);
|
||||
int a = GETARG_A(i);
|
||||
int b = GETARG_B(i);
|
||||
int c = GETARG_C(i);
|
||||
int bx = GETARG_Bx(i);
|
||||
int sbx = GETARG_sBx(i);
|
||||
int line = getline(f, pc);
|
||||
ps.print(" " + (pc + 1) + " ");
|
||||
if (line > 0)
|
||||
ps.print("[" + line + "] ");
|
||||
else
|
||||
ps.print("[-] ");
|
||||
ps.print(luaP_opnames[o] + " ");
|
||||
switch (getOpMode(o)) {
|
||||
case iABC:
|
||||
ps.print( a );
|
||||
if (getBMode(o) != OpArgN)
|
||||
ps.print(" "+(ISK(b) ? (-1 - INDEXK(b)) : b));
|
||||
if (getCMode(o) != OpArgN)
|
||||
ps.print(" "+(ISK(c) ? (-1 - INDEXK(c)) : c));
|
||||
break;
|
||||
case iABx:
|
||||
if (getBMode(o) == OpArgK) {
|
||||
ps.print(a + " " + (-1 - bx));
|
||||
} else {
|
||||
ps.print(a + " " + (bx));
|
||||
}
|
||||
break;
|
||||
case iAsBx:
|
||||
if (o == OP_JMP)
|
||||
ps.print( sbx );
|
||||
else
|
||||
ps.print(a + " " + sbx);
|
||||
break;
|
||||
}
|
||||
switch (o) {
|
||||
case OP_LOADK:
|
||||
ps.print(" ; ");
|
||||
printConstant(ps, f, bx);
|
||||
break;
|
||||
case OP_GETUPVAL:
|
||||
case OP_SETUPVAL:
|
||||
ps.print(" ; ");
|
||||
if ( f.upvalues.length > b )
|
||||
printValue(ps, f.upvalues[b]);
|
||||
else
|
||||
ps.print( "-" );
|
||||
break;
|
||||
case OP_GETGLOBAL:
|
||||
case OP_SETGLOBAL:
|
||||
ps.print(" ; ");
|
||||
printConstant( ps, f, bx );
|
||||
break;
|
||||
case OP_GETTABLE:
|
||||
case OP_SELF:
|
||||
if (ISK(c)) {
|
||||
ps.print(" ; ");
|
||||
printConstant(ps, f, INDEXK(c));
|
||||
}
|
||||
break;
|
||||
case OP_SETTABLE:
|
||||
case OP_ADD:
|
||||
case OP_SUB:
|
||||
case OP_MUL:
|
||||
case OP_DIV:
|
||||
case OP_POW:
|
||||
case OP_EQ:
|
||||
case OP_LT:
|
||||
case OP_LE:
|
||||
if (ISK(b) || ISK(c)) {
|
||||
ps.print(" ; ");
|
||||
if (ISK(b))
|
||||
printConstant(ps, f, INDEXK(b));
|
||||
else
|
||||
ps.print("-");
|
||||
ps.print(" ");
|
||||
if (ISK(c))
|
||||
printConstant(ps, f, INDEXK(c));
|
||||
else
|
||||
ps.print("-");
|
||||
}
|
||||
break;
|
||||
case OP_JMP:
|
||||
case OP_FORLOOP:
|
||||
case OP_FORPREP:
|
||||
ps.print(" ; to " + (sbx + pc + 2));
|
||||
break;
|
||||
case OP_CLOSURE:
|
||||
ps.print(" ; " + f.p[bx].getClass().getName());
|
||||
break;
|
||||
case OP_SETLIST:
|
||||
if (c == 0)
|
||||
ps.print(" ; " + ((int) code[++pc]));
|
||||
else
|
||||
ps.print(" ; " + ((int) c));
|
||||
break;
|
||||
case OP_VARARG:
|
||||
ps.print( " ; is_vararg="+ f.is_vararg );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static int getline(Prototype f, int pc) {
|
||||
return pc>0 && f.lineinfo!=null && pc<f.lineinfo.length? f.lineinfo[pc]: -1;
|
||||
}
|
||||
|
||||
static void printHeader(Prototype f) {
|
||||
String s = String.valueOf(f.source);
|
||||
if (s.startsWith("@") || s.startsWith("="))
|
||||
s = s.substring(1);
|
||||
else if ("\033Lua".equals(s))
|
||||
s = "(bstring)";
|
||||
else
|
||||
s = "(string)";
|
||||
String a = (f.linedefined == 0) ? "main" : "function";
|
||||
ps.print("\n%" + a + " <" + s + ":" + f.linedefined + ","
|
||||
+ f.lastlinedefined + "> (" + f.code.length + " instructions, "
|
||||
+ f.code.length * 4 + " bytes at " + id(f) + ")\n");
|
||||
ps.print(f.numparams + " param, " + f.maxstacksize + " slot, "
|
||||
+ f.upvalues.length + " upvalue, ");
|
||||
ps.print(f.locvars.length + " local, " + f.k.length
|
||||
+ " constant, " + f.p.length + " function\n");
|
||||
}
|
||||
|
||||
static void printConstants(Prototype f) {
|
||||
int i, n = f.k.length;
|
||||
ps.print("constants (" + n + ") for " + id(f) + ":\n");
|
||||
for (i = 0; i < n; i++) {
|
||||
ps.print(" " + (i + 1) + " ");
|
||||
printValue( ps, f.k[i] );
|
||||
ps.print( "\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void printLocals(Prototype f) {
|
||||
int i, n = f.locvars.length;
|
||||
ps.print("locals (" + n + ") for " + id(f) + ":\n");
|
||||
for (i = 0; i < n; i++) {
|
||||
ps.println(" "+i+" "+f.locvars[i].varname+" "+(f.locvars[i].startpc+1)+" "+(f.locvars[i].endpc+1));
|
||||
}
|
||||
}
|
||||
|
||||
static void printUpValues(Prototype f) {
|
||||
int i, n = f.upvalues.length;
|
||||
ps.print("upvalues (" + n + ") for " + id(f) + ":\n");
|
||||
for (i = 0; i < n; i++) {
|
||||
ps.print(" " + i + " " + f.upvalues[i] + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
public void printFunction(Prototype f, boolean full) {
|
||||
int i, n = f.p.length;
|
||||
printHeader(f);
|
||||
printCode(f);
|
||||
if (full) {
|
||||
printConstants(f);
|
||||
printLocals(f);
|
||||
printUpValues(f);
|
||||
}
|
||||
for (i = 0; i < n; i++)
|
||||
printFunction(f.p[i], full);
|
||||
}
|
||||
|
||||
private static void format( String s, int maxcols ) {
|
||||
int n = s.length();
|
||||
if ( n > maxcols )
|
||||
ps.print( s.substring(0,maxcols) );
|
||||
else {
|
||||
ps.print( s );
|
||||
for ( int i=maxcols-n; --i>=0; )
|
||||
ps.print( ' ' );
|
||||
}
|
||||
}
|
||||
|
||||
private static String id(Prototype f) {
|
||||
return "Proto";
|
||||
}
|
||||
|
||||
public static void printState(LuaClosure cl, int pc, LuaValue[] stack, int top, Varargs varargs) {
|
||||
// print opcode into buffer
|
||||
PrintStream previous = ps;
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ps = new PrintStream( baos );
|
||||
printOpCode( cl.p, pc );
|
||||
ps.flush();
|
||||
ps.close();
|
||||
ps = previous;
|
||||
format( baos.toString(), 50 );
|
||||
|
||||
// print stack
|
||||
ps.print('[');
|
||||
for ( int i=0; i<stack.length; i++ ) {
|
||||
LuaValue v = stack[i];
|
||||
if ( v == null )
|
||||
ps.print(STRING_FOR_NULL);
|
||||
else switch ( v.type() ) {
|
||||
case LuaValue.TSTRING:
|
||||
LuaString s = v.checkstring();
|
||||
ps.print( s.length() < 48?
|
||||
s.toString():
|
||||
s.substring(0, 32).toString()+"...+"+(s.length()-32)+"b");
|
||||
break;
|
||||
case LuaValue.TFUNCTION:
|
||||
ps.print( ( v instanceof LuaClosure )?
|
||||
((LuaClosure)v).p.toString(): v.toString() );
|
||||
break;
|
||||
case LuaValue.TUSERDATA:
|
||||
Object o = v.touserdata();
|
||||
String n = o.getClass().getName();
|
||||
n = n.substring(n.lastIndexOf('.')+1);
|
||||
ps.print( n+": "+Integer.toHexString(o.hashCode()) );
|
||||
break;
|
||||
default:
|
||||
ps.print(v.toString());
|
||||
}
|
||||
if ( i+1 == top )
|
||||
ps.print(']');
|
||||
ps.print( " | " );
|
||||
}
|
||||
ps.print(varargs);
|
||||
ps.println();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
68
src/core/org/luaj/vm2/Prototype.java
Normal file
68
src/core/org/luaj/vm2/Prototype.java
Normal file
@@ -0,0 +1,68 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
|
||||
|
||||
public class Prototype {
|
||||
/* constants used by the function */
|
||||
public LuaValue[] k;
|
||||
public int[] code;
|
||||
/* functions defined inside the function */
|
||||
public Prototype[] p;
|
||||
/* map from opcodes to source lines */
|
||||
public int[] lineinfo;
|
||||
/* information about local variables */
|
||||
public LocVars[] locvars;
|
||||
/* upvalue names */
|
||||
public LuaString[] upvalues;
|
||||
public LuaString source;
|
||||
public int nups;
|
||||
public int linedefined;
|
||||
public int lastlinedefined;
|
||||
public int numparams;
|
||||
public int is_vararg;
|
||||
public int maxstacksize;
|
||||
|
||||
|
||||
public String toString() {
|
||||
return source + ":" + linedefined;
|
||||
}
|
||||
|
||||
/** Get the name of a local variable.
|
||||
*
|
||||
* @param number the local variable number to look up
|
||||
* @param pc the program counter
|
||||
* @return the name, or null if not found
|
||||
*/
|
||||
public LuaString getlocalname(int number, int pc) {
|
||||
int i;
|
||||
for (i = 0; i<locvars.length && locvars[i].startpc <= pc; i++) {
|
||||
if (pc < locvars[i].endpc) { /* is variable active? */
|
||||
number--;
|
||||
if (number == 0)
|
||||
return locvars[i].varname;
|
||||
}
|
||||
}
|
||||
return null; /* not found */
|
||||
}
|
||||
}
|
||||
64
src/core/org/luaj/vm2/UpValue.java
Normal file
64
src/core/org/luaj/vm2/UpValue.java
Normal file
@@ -0,0 +1,64 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
|
||||
/** Upvalue used with Closure formulation */
|
||||
public class UpValue {
|
||||
|
||||
LuaValue[] array; // initially the stack, becomes a holder
|
||||
int index;
|
||||
boolean closed;
|
||||
UpValue next = null;
|
||||
|
||||
public UpValue( LuaValue[] stack, int index, UpValue next ) {
|
||||
this.array = stack;
|
||||
this.index = index;
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return (closed? "-": "+") + array[index];
|
||||
}
|
||||
|
||||
public LuaValue getValue() {
|
||||
return array[index];
|
||||
}
|
||||
|
||||
public void setValue( LuaValue value ) {
|
||||
array[index] = value;
|
||||
}
|
||||
|
||||
public boolean close( int limit ) {
|
||||
if ( (!closed) && (index>=limit) ) {
|
||||
array = new LuaValue[] { array[index] };
|
||||
index = 0;
|
||||
return (closed = true);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isClosed() {
|
||||
return closed;
|
||||
}
|
||||
}
|
||||
135
src/core/org/luaj/vm2/Varargs.java
Normal file
135
src/core/org/luaj/vm2/Varargs.java
Normal file
@@ -0,0 +1,135 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
/**
|
||||
* Class to encapsulate varargs values.
|
||||
*/
|
||||
public abstract class Varargs {
|
||||
|
||||
/**
|
||||
* Get the n-th argument value (1-based)
|
||||
*
|
||||
* @param i 1 for the first argument, 2 for the second, etc.
|
||||
* @return Value at position i, or Value.NIL if there is none.
|
||||
*/
|
||||
abstract public LuaValue arg( int i );
|
||||
|
||||
/**
|
||||
* Get the number of arguments, or 0 if there are none.
|
||||
* @return number of arguments.
|
||||
*/
|
||||
abstract public int narg();
|
||||
|
||||
/**
|
||||
* Get the first argument
|
||||
* @return Value
|
||||
*/
|
||||
abstract public LuaValue arg1();
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// utilities to get specific arguments and type-check them.
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
// argument types
|
||||
public int type(int i) { return arg(i).type(); }
|
||||
public boolean isnil(int i) { return arg(i).isnil(); }
|
||||
public boolean isfunction(int i) { return arg(i).isfunction(); }
|
||||
public boolean isnumber(int i) { return arg(i).isnumber(); }
|
||||
public boolean isstring(int i) { return arg(i).isstring(); }
|
||||
public boolean istable(int i) { return arg(i).istable(); }
|
||||
public boolean isthread(int i) { return arg(i).isthread(); }
|
||||
public boolean isuserdata(int i) { return arg(i).isuserdata(); }
|
||||
public boolean isvalue(int i) { return i>0 && i<=narg(); }
|
||||
|
||||
// optional argument types
|
||||
public LuaFunction optfunction(int i, LuaFunction defval) { return arg(i).optfunction(defval); }
|
||||
public int optint(int i, int defval) { return arg(i).optint(defval); }
|
||||
public long optlong(int i, long defval) { return arg(i).optlong(defval); }
|
||||
public LuaNumber optnumber(int i, LuaNumber defval) { return arg(i).optnumber(defval); }
|
||||
public String optString(int i, String defval) { return arg(i).optString(defval); }
|
||||
public LuaString optstring(int i, LuaString defval) { return arg(i).optstring(defval); }
|
||||
public LuaValue optvalue(int i, LuaValue defval) { return i>0 && i<=narg()? arg(i): defval; }
|
||||
|
||||
// required argument types
|
||||
public boolean checkboolean(int i) { return arg(i).checkboolean(); }
|
||||
public double checkdouble(int i) { return arg(i).checknumber().todouble(); }
|
||||
public LuaValue checkfunction(int i) { return arg(i).checkfunction(); }
|
||||
public int checkint(int i) { return arg(i).checknumber().toint(); }
|
||||
public long checklong(int i) { return arg(i).checknumber().tolong(); }
|
||||
public LuaValue checknumber(int i) { return arg(i).checknumber(); }
|
||||
public String checkString(int i) { return arg(i).checkString(); }
|
||||
public LuaString checkstring(int i) { return arg(i).checkstring(); }
|
||||
public LuaTable checktable(int i) { return arg(i).checktable(); }
|
||||
public LuaThread checkthread(int i) { return arg(i).checkthread(); }
|
||||
public Object checkuserdata(int i,Class c) { return arg(i).checkuserdata(c); }
|
||||
public LuaValue checkvalue(int i) { return i<=narg()? arg(i): LuaValue.error("value expected"); }
|
||||
public LuaValue checknotnil(int i) { return arg(i).checknotnil(); }
|
||||
|
||||
public void argcheck(boolean test, int i, String msg) { if (!test) LuaValue.argerror(i,msg); }
|
||||
|
||||
public boolean isnoneornil(int i) {
|
||||
return i>narg() || arg(i).isnil();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
Buffer sb = new Buffer();
|
||||
sb.append( "(" );
|
||||
for ( int i=1,n=narg(); i<=n; i++ ) {
|
||||
if (i>1) sb.append( "," );
|
||||
sb.append( arg(i).toString() );
|
||||
}
|
||||
sb.append( ")" );
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public Varargs subargs(final int start) {
|
||||
int end = narg();
|
||||
switch ( end-start ) {
|
||||
case 0: return arg(start);
|
||||
case 1: return new LuaValue.PairVarargs(arg(start),arg(end));
|
||||
}
|
||||
return end<start? (Varargs) LuaValue.NONE: new SubVarargs(this,start,end);
|
||||
}
|
||||
|
||||
private static class SubVarargs extends Varargs {
|
||||
private final Varargs v;
|
||||
private final int start;
|
||||
private final int end;
|
||||
public SubVarargs(Varargs varargs, int start, int end) {
|
||||
this.v = varargs;
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
public LuaValue arg(int i) {
|
||||
i += start-1;
|
||||
return i>=start && i<=end? v.arg(i): LuaValue.NIL;
|
||||
}
|
||||
public LuaValue arg1() {
|
||||
return v.arg(start);
|
||||
}
|
||||
public int narg() {
|
||||
return end+1-start;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
179
src/core/org/luaj/vm2/WeakTable.java
Normal file
179
src/core/org/luaj/vm2/WeakTable.java
Normal file
@@ -0,0 +1,179 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
public class WeakTable extends LuaTable {
|
||||
|
||||
private final boolean weakKeys,weakValues;
|
||||
|
||||
WeakTable( boolean weakKeys, boolean weakValues ) {
|
||||
this.weakKeys = weakKeys;
|
||||
this.weakValues = weakValues;
|
||||
}
|
||||
|
||||
private static class WeakValue extends LuaValue {
|
||||
private final WeakReference ref;
|
||||
public WeakValue(LuaValue val) {
|
||||
ref = new WeakReference(val);
|
||||
}
|
||||
public int type() {
|
||||
return LuaValue.TNIL;
|
||||
}
|
||||
public String typename() {
|
||||
return "value";
|
||||
}
|
||||
public LuaValue strongvalue() {
|
||||
Object o = ref.get();
|
||||
return o!=null? (LuaValue)o: NIL;
|
||||
}
|
||||
}
|
||||
|
||||
private static class WeakUserdata extends LuaValue {
|
||||
private final WeakReference ref;
|
||||
private LuaValue metatable;
|
||||
public WeakUserdata(Object val, LuaValue metatable) {
|
||||
ref = new WeakReference(val);
|
||||
}
|
||||
public int type() {
|
||||
return LuaValue.TNIL;
|
||||
}
|
||||
public String typename() {
|
||||
return "value";
|
||||
}
|
||||
public LuaValue strongvalue() {
|
||||
Object o = ref.get();
|
||||
if ( o == null ) {
|
||||
metatable = null;
|
||||
return NIL;
|
||||
}
|
||||
return userdataOf( o, metatable );
|
||||
}
|
||||
}
|
||||
|
||||
private static class WeakEntry extends LuaValue {
|
||||
private LuaValue key;
|
||||
private LuaValue val;
|
||||
private WeakEntry(LuaValue key, LuaValue val) {
|
||||
this.key = key;
|
||||
this.val = val;
|
||||
}
|
||||
public int type() {
|
||||
return LuaValue.TNIL;
|
||||
}
|
||||
public String typename() {
|
||||
return "weakentry";
|
||||
}
|
||||
public LuaValue strongkey() {
|
||||
LuaValue k = key.strongvalue();
|
||||
LuaValue v = val.strongvalue();
|
||||
if ( k.isnil() || v.isnil() )
|
||||
return key = val = NIL;
|
||||
return k;
|
||||
}
|
||||
public LuaValue strongvalue() {
|
||||
LuaValue k = key.strongvalue();
|
||||
LuaValue v = val.strongvalue();
|
||||
if ( k.isnil() || v.isnil() )
|
||||
return key = val = NIL;
|
||||
return v;
|
||||
}
|
||||
public boolean eq_b(LuaValue rhs) {
|
||||
return strongkey().eq_b(rhs);
|
||||
}
|
||||
public int hashCode() {
|
||||
return strongkey().hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean shouldWeaken( LuaValue value ) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TFUNCTION:
|
||||
case LuaValue.TTHREAD:
|
||||
case LuaValue.TTABLE:
|
||||
case LuaValue.TUSERDATA:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private LuaValue toWeak( LuaValue value ) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TFUNCTION:
|
||||
case LuaValue.TTHREAD:
|
||||
case LuaValue.TTABLE: return new WeakValue( value );
|
||||
case LuaValue.TUSERDATA: return new WeakUserdata( value.checkuserdata(), value.getmetatable() );
|
||||
default: return value;
|
||||
}
|
||||
}
|
||||
|
||||
public LuaValue rawget(int key) {
|
||||
LuaValue v = super.rawget(key);
|
||||
if ( v.isnil() )
|
||||
return NIL;
|
||||
v = v.strongvalue();
|
||||
if ( v.isnil() ) {
|
||||
// TODO: mark table for culling?
|
||||
rawset(key, NIL);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
public LuaValue rawget(LuaValue key) {
|
||||
LuaValue v = super.rawget(key);
|
||||
if ( v.isnil() )
|
||||
return NIL;
|
||||
v = v.strongvalue();
|
||||
if ( v.isnil() ) {
|
||||
// TODO: mark table for culling?
|
||||
rawset(key, NIL);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
public void rawset(int key, LuaValue val) {
|
||||
if ( val.isnil() || !weakValues || !shouldWeaken(val) ) {
|
||||
super.rawset(key, val);
|
||||
} else {
|
||||
super.rawset(key, toWeak(val));
|
||||
}
|
||||
}
|
||||
|
||||
public void rawset(LuaValue key, LuaValue val) {
|
||||
if ( val.isnil() ) {
|
||||
super.rawset(key, val);
|
||||
} else {
|
||||
boolean weakenKey = weakKeys && shouldWeaken(key);
|
||||
boolean weakenVal = weakValues && shouldWeaken(val);
|
||||
if ( weakenKey ) {
|
||||
WeakEntry e = new WeakEntry( toWeak(key), weakenVal? toWeak(val): val);
|
||||
super.rawset(e, e);
|
||||
} else if ( weakenVal ) {
|
||||
super.rawset(key, toWeak(val));
|
||||
} else {
|
||||
super.rawset(key, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
267
src/core/org/luaj/vm2/compiler/DumpState.java
Normal file
267
src/core/org/luaj/vm2/compiler/DumpState.java
Normal file
@@ -0,0 +1,267 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.compiler;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.luaj.vm2.LocVars;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
|
||||
public class DumpState {
|
||||
|
||||
/** 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 byte[] LUAC_HEADER_SIGNATURE = { '\033', 'L', 'u', 'a' };
|
||||
|
||||
/** set true to allow integer compilation */
|
||||
public static boolean ALLOW_INTEGER_CASTING = false;
|
||||
|
||||
/** format corresponding to non-number-patched lua, all numbers are floats or doubles */
|
||||
public static final int NUMBER_FORMAT_FLOATS_OR_DOUBLES = 0;
|
||||
|
||||
/** format corresponding to non-number-patched lua, all numbers are ints */
|
||||
public static final int NUMBER_FORMAT_INTS_ONLY = 1;
|
||||
|
||||
/** format corresponding to number-patched lua, all numbers are 32-bit (4 byte) ints */
|
||||
public static final int NUMBER_FORMAT_NUM_PATCH_INT32 = 4;
|
||||
|
||||
/** default number format */
|
||||
public static final int NUMBER_FORMAT_DEFAULT = NUMBER_FORMAT_FLOATS_OR_DOUBLES;
|
||||
|
||||
// header fields
|
||||
private boolean IS_LITTLE_ENDIAN = false;
|
||||
private int NUMBER_FORMAT = NUMBER_FORMAT_DEFAULT;
|
||||
private int SIZEOF_LUA_NUMBER = 8;
|
||||
private static final int SIZEOF_INT = 4;
|
||||
private static final int SIZEOF_SIZET = 4;
|
||||
private static final int SIZEOF_INSTRUCTION = 4;
|
||||
|
||||
DataOutputStream writer;
|
||||
boolean strip;
|
||||
int status;
|
||||
|
||||
public DumpState(OutputStream w, boolean strip) {
|
||||
this.writer = new DataOutputStream( w );
|
||||
this.strip = strip;
|
||||
this.status = 0;
|
||||
}
|
||||
|
||||
void dumpBlock(final byte[] b, int size) throws IOException {
|
||||
writer.write(b, 0, size);
|
||||
}
|
||||
|
||||
void dumpChar(int b) throws IOException {
|
||||
writer.write( b );
|
||||
}
|
||||
|
||||
void dumpInt(int x) throws IOException {
|
||||
if ( IS_LITTLE_ENDIAN ) {
|
||||
writer.writeByte(x&0xff);
|
||||
writer.writeByte((x>>8)&0xff);
|
||||
writer.writeByte((x>>16)&0xff);
|
||||
writer.writeByte((x>>24)&0xff);
|
||||
} else {
|
||||
writer.writeInt(x);
|
||||
}
|
||||
}
|
||||
|
||||
void dumpString(LuaString s) throws IOException {
|
||||
final int len = s.len().toint();
|
||||
dumpInt( len+1 );
|
||||
s.write( writer, 0, len );
|
||||
writer.write( 0 );
|
||||
}
|
||||
|
||||
void dumpDouble(double d) throws IOException {
|
||||
long l = Double.doubleToLongBits(d);
|
||||
if ( IS_LITTLE_ENDIAN ) {
|
||||
dumpInt( (int) l );
|
||||
dumpInt( (int) (l>>32) );
|
||||
} else {
|
||||
writer.writeLong(l);
|
||||
}
|
||||
}
|
||||
|
||||
void dumpCode( final Prototype f ) throws IOException {
|
||||
final int[] code = f.code;
|
||||
int n = code.length;
|
||||
dumpInt( n );
|
||||
for ( int i=0; i<n; i++ )
|
||||
dumpInt( code[i] );
|
||||
}
|
||||
|
||||
void dumpConstants(final Prototype f) throws IOException {
|
||||
final LuaValue[] k = f.k;
|
||||
int i, n = k.length;
|
||||
dumpInt(n);
|
||||
for (i = 0; i < n; i++) {
|
||||
final LuaValue o = k[i];
|
||||
switch ( o.type() ) {
|
||||
case LuaValue.TNIL:
|
||||
writer.write(LuaValue.TNIL);
|
||||
break;
|
||||
case LuaValue.TBOOLEAN:
|
||||
writer.write(LuaValue.TBOOLEAN);
|
||||
dumpChar(o.toboolean() ? 1 : 0);
|
||||
break;
|
||||
case LuaValue.TNUMBER:
|
||||
switch (NUMBER_FORMAT) {
|
||||
case NUMBER_FORMAT_FLOATS_OR_DOUBLES:
|
||||
writer.write(LuaValue.TNUMBER);
|
||||
dumpDouble(o.todouble());
|
||||
break;
|
||||
case NUMBER_FORMAT_INTS_ONLY:
|
||||
if ( ! ALLOW_INTEGER_CASTING && ! o.isint() )
|
||||
throw new java.lang.IllegalArgumentException("not an integer: "+o);
|
||||
writer.write(LuaValue.TNUMBER);
|
||||
dumpInt(o.toint());
|
||||
break;
|
||||
case NUMBER_FORMAT_NUM_PATCH_INT32:
|
||||
if ( o.isint() ) {
|
||||
writer.write(LuaValue.TINT);
|
||||
dumpInt(o.toint());
|
||||
} else {
|
||||
writer.write(LuaValue.TNUMBER);
|
||||
dumpDouble(o.todouble());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("number format not supported: "+NUMBER_FORMAT);
|
||||
}
|
||||
break;
|
||||
case LuaValue.TSTRING:
|
||||
writer.write(LuaValue.TSTRING);
|
||||
dumpString((LuaString)o);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("bad type for " + o);
|
||||
}
|
||||
}
|
||||
n = f.p.length;
|
||||
dumpInt(n);
|
||||
for (i = 0; i < n; i++)
|
||||
dumpFunction(f.p[i], f.source);
|
||||
}
|
||||
|
||||
void dumpDebug(final Prototype f) throws IOException {
|
||||
int i, n;
|
||||
n = (strip) ? 0 : f.lineinfo.length;
|
||||
dumpInt(n);
|
||||
for (i = 0; i < n; i++)
|
||||
dumpInt(f.lineinfo[i]);
|
||||
n = (strip) ? 0 : f.locvars.length;
|
||||
dumpInt(n);
|
||||
for (i = 0; i < n; i++) {
|
||||
LocVars lvi = f.locvars[i];
|
||||
dumpString(lvi.varname);
|
||||
dumpInt(lvi.startpc);
|
||||
dumpInt(lvi.endpc);
|
||||
}
|
||||
n = (strip) ? 0 : f.upvalues.length;
|
||||
dumpInt(n);
|
||||
for (i = 0; i < n; i++)
|
||||
dumpString(f.upvalues[i]);
|
||||
}
|
||||
|
||||
void dumpFunction(final Prototype f, final LuaString string) throws IOException {
|
||||
if ( f.source == null || f.source.equals(string) || strip )
|
||||
dumpInt(0);
|
||||
else
|
||||
dumpString(f.source);
|
||||
dumpInt(f.linedefined);
|
||||
dumpInt(f.lastlinedefined);
|
||||
dumpChar(f.nups);
|
||||
dumpChar(f.numparams);
|
||||
dumpChar(f.is_vararg);
|
||||
dumpChar(f.maxstacksize);
|
||||
dumpCode(f);
|
||||
dumpConstants(f);
|
||||
dumpDebug(f);
|
||||
}
|
||||
|
||||
void dumpHeader() throws IOException {
|
||||
writer.write( LUAC_HEADER_SIGNATURE );
|
||||
writer.write( LUAC_VERSION );
|
||||
writer.write( LUAC_FORMAT );
|
||||
writer.write( IS_LITTLE_ENDIAN? 1: 0 );
|
||||
writer.write( SIZEOF_INT );
|
||||
writer.write( SIZEOF_SIZET );
|
||||
writer.write( SIZEOF_INSTRUCTION );
|
||||
writer.write( SIZEOF_LUA_NUMBER );
|
||||
writer.write( NUMBER_FORMAT );
|
||||
}
|
||||
|
||||
/*
|
||||
** dump Lua function as precompiled chunk
|
||||
*/
|
||||
public static int dump( Prototype f, OutputStream w, boolean strip ) throws IOException {
|
||||
DumpState D = new DumpState(w,strip);
|
||||
D.dumpHeader();
|
||||
D.dumpFunction(f,null);
|
||||
return D.status;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param f the function to dump
|
||||
* @param w the output stream to dump to
|
||||
* @param stripDebug true to strip debugging info, false otherwise
|
||||
* @param numberFormat one of NUMBER_FORMAT_FLOATS_OR_DOUBLES, NUMBER_FORMAT_INTS_ONLY, NUMBER_FORMAT_NUM_PATCH_INT32
|
||||
* @param littleendian true to use little endian for numbers, false for big endian
|
||||
* @return 0 if dump succeeds
|
||||
* @throws IOException
|
||||
* @throws IllegalArgumentException if the number format it not supported
|
||||
*/
|
||||
public static int dump(Prototype f, OutputStream w, boolean stripDebug, int numberFormat, boolean littleendian) throws IOException {
|
||||
switch ( numberFormat ) {
|
||||
case NUMBER_FORMAT_FLOATS_OR_DOUBLES:
|
||||
case NUMBER_FORMAT_INTS_ONLY:
|
||||
case NUMBER_FORMAT_NUM_PATCH_INT32:
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("number format not supported: "+numberFormat);
|
||||
}
|
||||
DumpState D = new DumpState(w,stripDebug);
|
||||
D.IS_LITTLE_ENDIAN = littleendian;
|
||||
D.NUMBER_FORMAT = numberFormat;
|
||||
D.SIZEOF_LUA_NUMBER = (numberFormat==NUMBER_FORMAT_INTS_ONLY? 4: 8);
|
||||
D.dumpHeader();
|
||||
D.dumpFunction(f,null);
|
||||
return D.status;
|
||||
}
|
||||
}
|
||||
1084
src/core/org/luaj/vm2/compiler/FuncState.java
Normal file
1084
src/core/org/luaj/vm2/compiler/FuncState.java
Normal file
File diff suppressed because it is too large
Load Diff
37
src/core/org/luaj/vm2/compiler/InstructionPtr.java
Normal file
37
src/core/org/luaj/vm2/compiler/InstructionPtr.java
Normal file
@@ -0,0 +1,37 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.compiler;
|
||||
|
||||
class InstructionPtr {
|
||||
final int[] code;
|
||||
final int idx;
|
||||
InstructionPtr(int[] code, int idx ) {
|
||||
this.code = code;
|
||||
this.idx = idx;
|
||||
}
|
||||
int get() {
|
||||
return code[idx];
|
||||
}
|
||||
void set(int value) {
|
||||
code[idx] = value;
|
||||
}
|
||||
}
|
||||
31
src/core/org/luaj/vm2/compiler/IntPtr.java
Normal file
31
src/core/org/luaj/vm2/compiler/IntPtr.java
Normal file
@@ -0,0 +1,31 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.compiler;
|
||||
|
||||
public class IntPtr {
|
||||
int i;
|
||||
IntPtr() {
|
||||
}
|
||||
IntPtr(int value) {
|
||||
this.i = value;
|
||||
}
|
||||
}
|
||||
1905
src/core/org/luaj/vm2/compiler/LexState.java
Normal file
1905
src/core/org/luaj/vm2/compiler/LexState.java
Normal file
File diff suppressed because it is too large
Load Diff
223
src/core/org/luaj/vm2/compiler/LuaC.java
Normal file
223
src/core/org/luaj/vm2/compiler/LuaC.java
Normal file
@@ -0,0 +1,223 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.compiler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import org.luaj.vm2.LocVars;
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.LoadState.LuaCompiler;
|
||||
|
||||
|
||||
/**
|
||||
* Compiler for Lua
|
||||
*/
|
||||
public class LuaC extends Lua implements LuaCompiler {
|
||||
|
||||
/** Install the compiler so that LoadState will first
|
||||
* try to use it when handed bytes that are
|
||||
* not already a compiled lua chunk.
|
||||
*/
|
||||
public static void install() {
|
||||
org.luaj.vm2.LoadState.compiler = new LuaC();
|
||||
}
|
||||
|
||||
protected static void _assert(boolean b) {
|
||||
if (!b)
|
||||
throw new LuaError("compiler assert failed");
|
||||
}
|
||||
|
||||
public static final int MAXSTACK = 250;
|
||||
static final int LUAI_MAXUPVALUES = 60;
|
||||
static final int LUAI_MAXVARS = 200;
|
||||
static final int NO_REG = MAXARG_A;
|
||||
|
||||
|
||||
/* OpMode - basic instruction format */
|
||||
static final int
|
||||
iABC = 0,
|
||||
iABx = 1,
|
||||
iAsBx = 2;
|
||||
|
||||
/* OpArgMask */
|
||||
static final int
|
||||
OpArgN = 0, /* argument is not used */
|
||||
OpArgU = 1, /* argument is used */
|
||||
OpArgR = 2, /* argument is a register or a jump offset */
|
||||
OpArgK = 3; /* argument is a constant or register/constant */
|
||||
|
||||
|
||||
static void SET_OPCODE(InstructionPtr i,int o) {
|
||||
i.set( ( i.get() & (MASK_NOT_OP)) | ((o << POS_OP) & MASK_OP) );
|
||||
}
|
||||
|
||||
static void SETARG_A(InstructionPtr i,int u) {
|
||||
i.set( ( i.get() & (MASK_NOT_A)) | ((u << POS_A) & MASK_A) );
|
||||
}
|
||||
|
||||
static void SETARG_B(InstructionPtr i,int u) {
|
||||
i.set( ( i.get() & (MASK_NOT_B)) | ((u << POS_B) & MASK_B) );
|
||||
}
|
||||
|
||||
static void SETARG_C(InstructionPtr i,int u) {
|
||||
i.set( ( i.get() & (MASK_NOT_C)) | ((u << POS_C) & MASK_C) );
|
||||
}
|
||||
|
||||
static void SETARG_Bx(InstructionPtr i,int u) {
|
||||
i.set( ( i.get() & (MASK_NOT_Bx)) | ((u << POS_Bx) & MASK_Bx) );
|
||||
}
|
||||
|
||||
static void SETARG_sBx(InstructionPtr i,int u) {
|
||||
SETARG_Bx( i, u + MAXARG_sBx );
|
||||
}
|
||||
|
||||
static int CREATE_ABC(int o, int a, int b, int c) {
|
||||
return ((o << POS_OP) & MASK_OP) |
|
||||
((a << POS_A) & MASK_A) |
|
||||
((b << POS_B) & MASK_B) |
|
||||
((c << POS_C) & MASK_C) ;
|
||||
}
|
||||
|
||||
static int CREATE_ABx(int o, int a, int bc) {
|
||||
return ((o << POS_OP) & MASK_OP) |
|
||||
((a << POS_A) & MASK_A) |
|
||||
((bc << POS_Bx) & MASK_Bx) ;
|
||||
}
|
||||
|
||||
// vector reallocation
|
||||
|
||||
static LuaValue[] realloc(LuaValue[] v, int n) {
|
||||
LuaValue[] a = new LuaValue[n];
|
||||
if ( v != null )
|
||||
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
|
||||
return a;
|
||||
}
|
||||
|
||||
static Prototype[] realloc(Prototype[] v, int n) {
|
||||
Prototype[] a = new Prototype[n];
|
||||
if ( v != null )
|
||||
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
|
||||
return a;
|
||||
}
|
||||
|
||||
static LuaString[] realloc(LuaString[] v, int n) {
|
||||
LuaString[] a = new LuaString[n];
|
||||
if ( v != null )
|
||||
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
|
||||
return a;
|
||||
}
|
||||
|
||||
static LocVars[] realloc(LocVars[] v, int n) {
|
||||
LocVars[] a = new LocVars[n];
|
||||
if ( v != null )
|
||||
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
|
||||
return a;
|
||||
}
|
||||
|
||||
static int[] realloc(int[] v, int n) {
|
||||
int[] a = new int[n];
|
||||
if ( v != null )
|
||||
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
|
||||
return a;
|
||||
}
|
||||
|
||||
static byte[] realloc(byte[] v, int n) {
|
||||
byte[] a = new byte[n];
|
||||
if ( v != null )
|
||||
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
|
||||
return a;
|
||||
}
|
||||
|
||||
public int nCcalls;
|
||||
Hashtable strings = new Hashtable();
|
||||
|
||||
/** Utility method to invoke the compiler for an input stream
|
||||
*/
|
||||
public static Prototype compile(InputStream is, String string) throws IOException {
|
||||
return new LuaC().compile(is.read(), is, string);
|
||||
}
|
||||
|
||||
/** Compile source bytes into a LPrototype.
|
||||
*
|
||||
* Try to compile the file, and return the Prototype on success,
|
||||
* or throw LuaErrorException on syntax error or I/O Exception
|
||||
*
|
||||
* @param firstByte the first byte from the InputStream.
|
||||
* This can be read by the client and tested to see if it is already a binary chunk.
|
||||
* @param stream InputStream to read from.
|
||||
* @param name Name of the chunk
|
||||
* @return null if the first byte indicates it is a binary chunk,
|
||||
* a LPrototype instance if it can be compiled,
|
||||
* or an exception is thrown if there is an error.
|
||||
* @throws IOException if an I/O exception occurs
|
||||
* @throws LuaError if there is a syntax error.
|
||||
*/
|
||||
public Prototype compile(int firstByte, InputStream stream, String name) throws IOException {
|
||||
LuaC compiler = new LuaC();
|
||||
return compiler.luaY_parser(firstByte, stream, name);
|
||||
}
|
||||
|
||||
/** Parse the input */
|
||||
private Prototype luaY_parser(int firstByte, InputStream z, String name) {
|
||||
LexState lexstate = new LexState(this, z);
|
||||
FuncState funcstate = new FuncState();
|
||||
// lexstate.buff = buff;
|
||||
lexstate.setinput( this, firstByte, z, (LuaString) LuaValue.valueOf(name) );
|
||||
lexstate.open_func(funcstate);
|
||||
/* main func. is always vararg */
|
||||
funcstate.f.is_vararg = LuaC.VARARG_ISVARARG;
|
||||
funcstate.f.source = (LuaString) LuaValue.valueOf("@"+name);
|
||||
lexstate.next(); /* read first token */
|
||||
lexstate.chunk();
|
||||
lexstate.check(LexState.TK_EOS);
|
||||
lexstate.close_func();
|
||||
LuaC._assert (funcstate.prev == null);
|
||||
LuaC._assert (funcstate.f.nups == 0);
|
||||
LuaC._assert (lexstate.fs == null);
|
||||
return funcstate.f;
|
||||
}
|
||||
|
||||
// look up and keep at most one copy of each string
|
||||
public LuaString newTString(byte[] bytes, int offset, int len) {
|
||||
LuaString tmp = LuaString.valueOf(bytes, offset, len);
|
||||
LuaString v = (LuaString) strings.get(tmp);
|
||||
if ( v == null ) {
|
||||
// must copy bytes, since bytes could be from reusable buffer
|
||||
byte[] copy = new byte[len];
|
||||
System.arraycopy(bytes, offset, copy, 0, len);
|
||||
v = LuaString.valueOf(copy);
|
||||
strings.put(v, v);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
public String pushfstring(String string) {
|
||||
return string;
|
||||
}
|
||||
|
||||
}
|
||||
403
src/core/org/luaj/vm2/lib/BaseLib.java
Normal file
403
src/core/org/luaj/vm2/lib/BaseLib.java
Normal file
@@ -0,0 +1,403 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/package org.luaj.vm2.lib;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintStream;
|
||||
|
||||
import org.luaj.vm2.LoadState;
|
||||
import org.luaj.vm2.LuaClosure;
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaThread;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/**
|
||||
* Base library implementation, targeted for JME platforms.
|
||||
*
|
||||
* BaseLib instances are typically used as the initial globals table
|
||||
* when creating a new uniqued runtime context.
|
||||
*
|
||||
* Since JME has no file system by default, dofile and loadfile use the
|
||||
* FINDER instance to find resource files. The default loader chain
|
||||
* in PackageLib will use these as well.
|
||||
*
|
||||
* For an implementation that looks in the current directory on JSE,
|
||||
* use org.luaj.lib.j2se.BaseLib instead.
|
||||
*
|
||||
* @see org.luaj.vm2.lib.jse.JseBaseLib
|
||||
*/
|
||||
public class BaseLib extends LuaTable implements ResourceFinder {
|
||||
public static final String VERSION = "Luaj 2.0";
|
||||
|
||||
public static InputStream STDIN = null;
|
||||
public static PrintStream STDOUT = System.out;
|
||||
public static PrintStream STDERR = System.err;
|
||||
|
||||
/**
|
||||
* Singleton file opener for this Java ClassLoader realm.
|
||||
*
|
||||
* Unless set or changed elsewhere, will be set by the BaseLib that is created.
|
||||
*/
|
||||
public static ResourceFinder FINDER;
|
||||
|
||||
/**
|
||||
* Construct a base libarary instance and initialize the functions in it.
|
||||
*/
|
||||
public BaseLib() {
|
||||
this.set( "_G", this );
|
||||
this.set( "_VERSION", VERSION );
|
||||
LibFunction.bind( this, new BaseFunc1().getClass(), new String[] {
|
||||
"getfenv", // ( [f] ) -> env
|
||||
"getmetatable", // ( object ) -> table
|
||||
"tostring", // (e) -> value
|
||||
} );
|
||||
LibFunction.bind( this, new BaseFunc2().getClass(), new String[] {
|
||||
"collectgarbage", // ( opt [,arg] ) -> value
|
||||
"error", // ( message [,level] ) -> ERR
|
||||
"rawequal", // (v1, v2) -> boolean
|
||||
"setfenv", // (f, table) -> void
|
||||
"tonumber", // (e [,base]) -> value
|
||||
} );
|
||||
LibFunction.bind( this, new BaseFuncV().getClass(), new String[] {
|
||||
"assert", // ( v [,message] ) -> v, message | ERR
|
||||
"dofile", // ( filename ) -> result1, ...
|
||||
"load", // ( func [,chunkname] ) -> chunk | nil, msg
|
||||
"loadfile", // ( [filename] ) -> chunk | nil, msg
|
||||
"loadstring", // ( string [,chunkname] ) -> chunk | nil, msg
|
||||
"pcall", // (f, arg1, ...) -> status, result1, ...
|
||||
"xpcall", // (f, err) -> result1, ...
|
||||
"print", // (...) -> void
|
||||
"select", // (f, ...) -> value1, ...
|
||||
"unpack", // (list [,i [,j]]) -> result1, ...
|
||||
"type", // (v) -> value
|
||||
"rawget", // (table, index) -> value
|
||||
"rawset", // (table, index, value) -> table
|
||||
"setmetatable", // (table, metatable) -> table
|
||||
} );
|
||||
|
||||
// pairs and ipars need iterator functions
|
||||
// "next", // ( table, [index] ) -> next-index, next-value
|
||||
// "inext", // not public ( table, [int-index] ) -> next-index, next-value
|
||||
// "ipairs", // (t) -> iter-func, t, 0
|
||||
// "pairs", // (t) -> iter-func, t, nil
|
||||
LuaValue next = new BaseIter(0,"next",null);
|
||||
LuaValue inext = new BaseIter(1,"inext",null);
|
||||
this.set( "pairs", new BaseIter(2,"pairs",next) );
|
||||
this.set( "ipairs", new BaseIter(3,"ipairs",inext) );
|
||||
this.set( "next", next );
|
||||
|
||||
// set the default resource finder if not set already
|
||||
if ( FINDER == null )
|
||||
FINDER = this;
|
||||
}
|
||||
|
||||
/** ResourceFinder implementation
|
||||
*
|
||||
* Tries to open the file as a resource, which can work for .
|
||||
*/
|
||||
public InputStream findResource(String filename) {
|
||||
Class c = getClass();
|
||||
return c.getResourceAsStream(filename.startsWith("/")? filename: "/"+filename);
|
||||
}
|
||||
|
||||
public static class BaseFunc1 extends OneArgFunction {
|
||||
public LuaValue call(LuaValue arg) {
|
||||
switch ( opcode ) {
|
||||
case 0: { // "getfenv", // ( [f] ) -> env
|
||||
if ( ! arg.isfunction() ) {
|
||||
int i = arg.checkint();
|
||||
arg = (i==0)? (LuaValue) LuaThread.getRunning(): (LuaValue) LuaThread.getCallstackFunction(i-1);
|
||||
if ( arg == null )
|
||||
LuaValue.argerror(1, "invalid level");
|
||||
}
|
||||
return arg.getfenv();
|
||||
}
|
||||
case 1: // "getmetatable", // ( object ) -> table
|
||||
LuaValue mt = arg.getmetatable();
|
||||
return mt!=null? mt: NIL;
|
||||
case 2: // "tostring", // (e) -> value
|
||||
return arg.type() == LuaValue.TSTRING? arg: valueOf(arg.toString());
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
public static class BaseFunc2 extends TwoArgFunction {
|
||||
public LuaValue call(LuaValue arg1,LuaValue arg2) {
|
||||
switch ( opcode ) {
|
||||
case 0: // "collectgarbage", // ( opt [,arg] ) -> value
|
||||
String s = arg1.optString("collect");
|
||||
int result = 0;
|
||||
if ( "collect".equals(s) ) {
|
||||
System.gc();
|
||||
return ZERO;
|
||||
}
|
||||
else if ( "count".equals(s) ) {
|
||||
Runtime rt = Runtime.getRuntime();
|
||||
long used = rt.totalMemory() - rt.freeMemory();
|
||||
return valueOf(used/1024.);
|
||||
} else if ( "step".equals(s) ) {
|
||||
System.gc();
|
||||
return LuaValue.TRUE;
|
||||
}
|
||||
return NIL;
|
||||
case 1: // "error", // ( message [,level] ) -> ERR
|
||||
throw new LuaError( arg1.isnil()? null: arg1.toString() );
|
||||
case 2: // "rawequal", // (v1, v2) -> boolean
|
||||
return valueOf(arg1 == arg2);
|
||||
case 3: { // "setfenv", // (f, table) -> void
|
||||
LuaValue f = arg1;
|
||||
if ( ! f.isfunction() ) {
|
||||
int i = arg1.checkint();
|
||||
f = (i==0)? (LuaValue) LuaThread.getRunning(): (LuaValue) LuaThread.getCallstackFunction(i-1);
|
||||
if ( f == null )
|
||||
LuaValue.argerror(1, "invalid level");
|
||||
}
|
||||
f.setfenv(arg2);
|
||||
return f;
|
||||
}
|
||||
case 4: // "tonumber", // (e [,base]) -> value
|
||||
final int base = arg2.optint(10);
|
||||
if (base == 10) { /* standard conversion */
|
||||
return arg1.tonumber();
|
||||
} else {
|
||||
if ( base < 2 || base > 36 )
|
||||
argerror(2, "base out of range");
|
||||
final LuaString str = arg1.optstring(null);
|
||||
return str!=null? str.tonumber(base): NIL;
|
||||
}
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
public static class BaseFuncV extends VarArgFunction {
|
||||
private final BaseLib lib;
|
||||
public BaseFuncV() {
|
||||
this.lib = null;
|
||||
}
|
||||
public BaseFuncV(BaseLib lib) {
|
||||
this.lib = lib;
|
||||
}
|
||||
public Varargs invoke(Varargs args) {
|
||||
switch ( opcode ) {
|
||||
case 0: // "assert", // ( v [,message] ) -> v, message | ERR
|
||||
if ( !args.arg1().toboolean() ) error("assertion failed!");
|
||||
return args;
|
||||
case 1: // "dofile", // ( filename ) -> result1, ...
|
||||
{
|
||||
LuaValue chunk;
|
||||
try {
|
||||
String filename = args.checkString(1);
|
||||
chunk = loadFile(filename).arg1();
|
||||
} catch ( IOException e ) {
|
||||
return error(e.getMessage());
|
||||
}
|
||||
return chunk.invoke();
|
||||
}
|
||||
case 2: // "load", // ( func [,chunkname] ) -> chunk | nil, msg
|
||||
try {
|
||||
LuaValue func = args.checkfunction(1);
|
||||
String chunkname = args.optString(2, "function");
|
||||
Prototype p = LoadState.undump(new StringInputStream(func), chunkname);
|
||||
return new LuaClosure(p,LuaThread.getRunningEnv(env));
|
||||
} catch ( Exception e ) {
|
||||
return varargsOf(NIL, valueOf(e.getMessage()));
|
||||
}
|
||||
case 3: // "loadfile", // ( [filename] ) -> chunk | nil, msg
|
||||
{
|
||||
try {
|
||||
String filename = args.checkString(1);
|
||||
return loadFile(filename);
|
||||
} catch ( Exception e ) {
|
||||
return varargsOf(NIL, valueOf(e.getMessage()));
|
||||
}
|
||||
}
|
||||
case 4: // "loadstring", // ( string [,chunkname] ) -> chunk | nil, msg
|
||||
try {
|
||||
LuaString script = args.checkstring(1);
|
||||
LuaString chunkname = args.optstring(2, script);
|
||||
Prototype p = LoadState.undump(script.toInputStream(), chunkname.toString());
|
||||
return new LuaClosure(p,LuaThread.getRunningEnv(env));
|
||||
} catch ( Exception e ) {
|
||||
return varargsOf(NIL, valueOf(e.getMessage()));
|
||||
}
|
||||
case 5: // "pcall", // (f, arg1, ...) -> status, result1, ...
|
||||
try {
|
||||
LuaThread.onCall(this);
|
||||
try {
|
||||
return varargsOf(LuaValue.TRUE, args.arg1().invoke(args.subargs(2)));
|
||||
} finally {
|
||||
LuaThread.onReturn();
|
||||
}
|
||||
} catch ( LuaError le ) {
|
||||
String m = le.getMessage();
|
||||
return varargsOf(FALSE, m!=null? valueOf(m): NIL);
|
||||
} catch ( Exception e ) {
|
||||
String m = e.getMessage();
|
||||
return varargsOf(FALSE, valueOf(m!=null? m: e.toString()));
|
||||
}
|
||||
case 6: // "xpcall", // (f, err) -> result1, ...
|
||||
try {
|
||||
LuaThread.onCall(this);
|
||||
try {
|
||||
LuaThread thread = LuaThread.getRunning();
|
||||
LuaValue olderr = thread.err;
|
||||
try {
|
||||
thread.err = args.arg(2);
|
||||
return varargsOf(LuaValue.TRUE, args.arg1().invoke(args.subargs(2)));
|
||||
} finally {
|
||||
thread.err = olderr;
|
||||
}
|
||||
} finally {
|
||||
LuaThread.onReturn();
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
try {
|
||||
return args.arg(2).invoke(valueOf(e.getMessage()));
|
||||
} catch ( Exception f ) {
|
||||
return varargsOf(FALSE, valueOf(f.getMessage()));
|
||||
}
|
||||
}
|
||||
case 7: // "print", // (...) -> void
|
||||
{
|
||||
LuaValue tostring = env.get("tostring");
|
||||
for ( int i=1, n=args.narg(); i<=n; i++ ) {
|
||||
if ( i>1 ) STDOUT.write( '\t' );
|
||||
LuaString s = tostring.call( args.arg(i) ).strvalue();
|
||||
int z = s.indexOf((byte)0, 0);
|
||||
STDOUT.write( s.m_bytes, s.m_offset, z>=0? z: s.m_length );
|
||||
}
|
||||
STDOUT.println();
|
||||
return NONE;
|
||||
}
|
||||
case 8: // "select", // (f, ...) -> value1, ...
|
||||
{
|
||||
int n = args.narg()-1;
|
||||
if ( args.arg1().equals(valueOf("#")) )
|
||||
return valueOf(n);
|
||||
int i = args.checkint(1);
|
||||
if ( i == 0 || i < -n )
|
||||
typerror(1,"index out of range");
|
||||
return args.subargs(i<0? n+i+2: i+1);
|
||||
}
|
||||
case 9: // "unpack", // (list [,i [,j]]) -> result1, ...
|
||||
{
|
||||
int na = args.narg();
|
||||
LuaTable t = args.checktable(1);
|
||||
int n = t.length();
|
||||
int i = na>=2? args.checkint(2): 1;
|
||||
int j = na>=3? args.checkint(3): n;
|
||||
n = j-i+1;
|
||||
if ( n<0 ) return NONE;
|
||||
if ( n==1 ) return t.get(i);
|
||||
if ( n==2 ) return varargsOf(t.get(i),t.get(j));
|
||||
LuaValue[] v = new LuaValue[n];
|
||||
for ( int k=0; k<n; k++ )
|
||||
v[k] = t.get(i+k);
|
||||
return varargsOf(v);
|
||||
}
|
||||
case 10: // "type", // (v) -> value
|
||||
return valueOf(args.checkvalue(1).typename());
|
||||
case 11: // "rawget", // (table, index) -> value
|
||||
return args.checktable(1).rawget(args.checkvalue(2));
|
||||
case 12: { // "rawset", // (table, index, value) -> table
|
||||
LuaTable t = args.checktable(1);
|
||||
t.rawset(args.checknotnil(2), args.checkvalue(3));
|
||||
return t;
|
||||
}
|
||||
case 13: { // "setmetatable", // (table, metatable) -> table
|
||||
final LuaValue t = args.arg1();
|
||||
final LuaValue mt = args.checkvalue(2);
|
||||
t.setmetatable(mt.isnil()? null: mt.checktable());
|
||||
return t;
|
||||
}
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
|
||||
private Varargs loadFile(String filename) throws IOException {
|
||||
InputStream is = FINDER.findResource(filename);
|
||||
if ( is == null )
|
||||
return varargsOf(NIL, valueOf("not found: "+filename));
|
||||
try {
|
||||
Prototype p = LoadState.undump(is, filename);
|
||||
return new LuaClosure(p,LuaThread.getRunningEnv(env));
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class BaseIter extends VarArgFunction {
|
||||
final LuaValue aux;
|
||||
BaseIter(int opcode, String name, LuaValue aux) {
|
||||
this.name = name;
|
||||
this.opcode = opcode;
|
||||
this.aux = aux;
|
||||
}
|
||||
public Varargs invoke(Varargs args) {
|
||||
switch ( opcode ) {
|
||||
case 0: // "next" ( table, [index] ) -> next-index, next-value
|
||||
return args.arg1().next(args.arg(2));
|
||||
case 1: // "inext" ( table, [int-index] ) -> next-index, next-value
|
||||
return args.arg1().inext(args.arg(2));
|
||||
case 2: // "pairs" (t) -> iter-func, t, nil
|
||||
return varargsOf( aux, args.checktable(1), NIL );
|
||||
case 3: // "ipairs", // (t) -> iter-func, t, 0
|
||||
return varargsOf( aux, args.checktable(1), ZERO );
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class StringInputStream extends InputStream {
|
||||
LuaValue func;
|
||||
byte[] bytes;
|
||||
int offset;
|
||||
StringInputStream(LuaValue func) {
|
||||
this.func = func;
|
||||
}
|
||||
public int read() throws IOException {
|
||||
if ( func == null ) return -1;
|
||||
if ( bytes == null ) {
|
||||
LuaValue s = func.call();
|
||||
if ( s.isnil() ) {
|
||||
func = null;
|
||||
bytes = null;
|
||||
return -1;
|
||||
}
|
||||
bytes = s.toString().getBytes();
|
||||
offset = 0;
|
||||
}
|
||||
if ( offset >= bytes.length )
|
||||
return -1;
|
||||
return bytes[offset++];
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
111
src/core/org/luaj/vm2/lib/CoroutineLib.java
Normal file
111
src/core/org/luaj/vm2/lib/CoroutineLib.java
Normal file
@@ -0,0 +1,111 @@
|
||||
/*******************************************************************************
|
||||
* 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 org.luaj.vm2.lib;
|
||||
|
||||
import org.luaj.vm2.LuaThread;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
public class CoroutineLib extends VarArgFunction {
|
||||
|
||||
private static final String[] NAMES = {
|
||||
"<coroutine>",
|
||||
"create",
|
||||
"resume",
|
||||
"running",
|
||||
"status",
|
||||
"yield",
|
||||
"wrap",
|
||||
"wrapped"
|
||||
};
|
||||
|
||||
private static final int INSTALL = 0;
|
||||
private static final int CREATE = 1;
|
||||
private static final int RESUME = 2;
|
||||
private static final int RUNNING = 3;
|
||||
private static final int STATUS = 4;
|
||||
private static final int YIELD = 5;
|
||||
private static final int WRAP = 6;
|
||||
private static final int WRAPPED = 7;
|
||||
|
||||
public static void install(LuaValue globals) {
|
||||
globals.set("coroutine", createInstance());
|
||||
}
|
||||
|
||||
public static final LuaValue createInstance() {
|
||||
LuaTable t = new LuaTable();
|
||||
CoroutineLib f = new CoroutineLib();
|
||||
LibFunction.bind(t, f.getClass(), NAMES);
|
||||
return t;
|
||||
}
|
||||
|
||||
public CoroutineLib() {}
|
||||
|
||||
private CoroutineLib(String name, int opcode, LuaThread thread) {
|
||||
super(name, opcode, thread);
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs args) {
|
||||
switch ( opcode ) {
|
||||
case INSTALL:
|
||||
return createInstance();
|
||||
case CREATE: {
|
||||
final LuaValue func = args.checkfunction(1);
|
||||
return new LuaThread(func, func.getfenv() );
|
||||
}
|
||||
case RESUME: {
|
||||
final LuaThread t = args.checkthread(1);
|
||||
return t.resume( args.subargs(2) );
|
||||
}
|
||||
case RUNNING: {
|
||||
final LuaThread r = LuaThread.getRunning();
|
||||
return LuaThread.isMainThread(r)? NIL: r;
|
||||
}
|
||||
case STATUS: {
|
||||
return valueOf( args.checkthread(1).getStatus() );
|
||||
}
|
||||
case YIELD: {
|
||||
final LuaThread r = LuaThread.getRunning();
|
||||
if ( LuaThread.isMainThread( r ) )
|
||||
error("main thread can't yield");
|
||||
return r.yield( args );
|
||||
}
|
||||
case WRAP: {
|
||||
final LuaValue func = args.checkfunction(1);
|
||||
final LuaThread thread = new LuaThread(func, func.getfenv());
|
||||
return new CoroutineLib("wrapped",WRAPPED,thread);
|
||||
}
|
||||
case WRAPPED: {
|
||||
final LuaThread t = (LuaThread) env;
|
||||
final Varargs result = t.resume( args );
|
||||
if ( result.arg1().toboolean() ) {
|
||||
return result.subargs(2);
|
||||
} else {
|
||||
error( result.arg(2).toString() );
|
||||
}
|
||||
}
|
||||
default:
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
905
src/core/org/luaj/vm2/lib/DebugLib.java
Normal file
905
src/core/org/luaj/vm2/lib/DebugLib.java
Normal file
@@ -0,0 +1,905 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib;
|
||||
|
||||
|
||||
import org.luaj.vm2.LuaClosure;
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaFunction;
|
||||
import org.luaj.vm2.LuaThread;
|
||||
import org.luaj.vm2.Print;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
public class DebugLib extends VarArgFunction {
|
||||
public static final boolean CALLS = (null != System.getProperty("CALLS"));
|
||||
public static final boolean TRACE = (null != System.getProperty("TRACE"));
|
||||
|
||||
// leave this unset to allow obfuscators to remove it in production builds
|
||||
public static boolean DEBUG_ENABLED = false;
|
||||
|
||||
private static final String[] NAMES = {
|
||||
"<debug>",
|
||||
"debug",
|
||||
"getfenv",
|
||||
"gethook",
|
||||
"getinfo",
|
||||
"getlocal",
|
||||
"getmetatable",
|
||||
"getregistry",
|
||||
"getupvalue",
|
||||
"setfenv",
|
||||
"sethook",
|
||||
"setlocal",
|
||||
"setmetatable",
|
||||
"setupvalue",
|
||||
"traceback",
|
||||
};
|
||||
|
||||
private static final int INSTALL = 0;
|
||||
private static final int DEBUG = 1;
|
||||
private static final int GETFENV = 2;
|
||||
private static final int GETHOOK = 3;
|
||||
private static final int GETINFO = 4;
|
||||
private static final int GETLOCAL = 5;
|
||||
private static final int GETMETATABLE = 6;
|
||||
private static final int GETREGISTRY = 7;
|
||||
private static final int GETUPVALUE = 8;
|
||||
private static final int SETFENV = 9;
|
||||
private static final int SETHOOK = 10;
|
||||
private static final int SETLOCAL = 11;
|
||||
private static final int SETMETATABLE = 12;
|
||||
private static final int SETUPVALUE = 13;
|
||||
private static final int TRACEBACK = 14;
|
||||
|
||||
/* maximum stack for a Lua function */
|
||||
private static final int MAXSTACK = 250;
|
||||
|
||||
private static final LuaString LUA = LuaString.valueOf("Lua");
|
||||
private static final LuaString JAVA = LuaString.valueOf("Java");
|
||||
private static final LuaString QMARK = LuaString.valueOf("?");
|
||||
private static final LuaString GLOBAL = LuaString.valueOf("global");
|
||||
private static final LuaString LOCAL = LuaString.valueOf("local");
|
||||
private static final LuaString METHOD = LuaString.valueOf("method");
|
||||
private static final LuaString UPVALUE = LuaString.valueOf("upvalue");
|
||||
private static final LuaString FIELD = LuaString.valueOf("field");
|
||||
private static final LuaString CALL = LuaString.valueOf("call");
|
||||
private static final LuaString LINE = LuaString.valueOf("line");
|
||||
private static final LuaString RETURN = LuaString.valueOf("return");
|
||||
private static final LuaString TAILRETURN = LuaString.valueOf("tail return");
|
||||
|
||||
private static final LuaString FUNC = LuaString.valueOf("func");
|
||||
private static final LuaString NUPS = LuaString.valueOf("nups");
|
||||
private static final LuaString NAME = LuaString.valueOf("name");
|
||||
private static final LuaString NAMEWHAT = LuaString.valueOf("namewhat");
|
||||
private static final LuaString WHAT = LuaString.valueOf("what");
|
||||
private static final LuaString SOURCE = LuaString.valueOf("source");
|
||||
private static final LuaString SHORT_SRC = LuaString.valueOf("short_src");
|
||||
private static final LuaString LINEDEFINED = LuaString.valueOf("linedefined");
|
||||
private static final LuaString LASTLINEDEFINED = LuaString.valueOf("lastlinedefined");
|
||||
private static final LuaString CURRENTLINE = LuaString.valueOf("currentline");
|
||||
private static final LuaString ACTIVELINES = LuaString.valueOf("activelines");
|
||||
|
||||
public static void install(LuaValue globals) {
|
||||
globals.set("debug", DebugLib.createInstance() );
|
||||
}
|
||||
|
||||
public static final LuaValue createInstance() {
|
||||
LuaTable t = new LuaTable();
|
||||
DebugLib f = new DebugLib();
|
||||
LibFunction.bind(t, f.getClass(), NAMES);
|
||||
if ( ! DEBUG_ENABLED ) {
|
||||
DEBUG_ENABLED = true;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
public DebugLib() {}
|
||||
|
||||
public Varargs invoke(Varargs args) {
|
||||
switch ( opcode ) {
|
||||
case INSTALL:
|
||||
return createInstance();
|
||||
case DEBUG:
|
||||
return _debug(args);
|
||||
case GETFENV:
|
||||
return _getfenv(args);
|
||||
case GETHOOK:
|
||||
return _gethook(args);
|
||||
case GETINFO:
|
||||
return _getinfo(args);
|
||||
case GETLOCAL:
|
||||
return _getlocal(args);
|
||||
case GETMETATABLE:
|
||||
return _getmetatable(args);
|
||||
case GETREGISTRY:
|
||||
return _getregistry(args);
|
||||
case GETUPVALUE:
|
||||
return _getupvalue(args);
|
||||
case SETFENV:
|
||||
return _setfenv(args);
|
||||
case SETHOOK:
|
||||
return _sethook(args);
|
||||
case SETLOCAL:
|
||||
return _setlocal(args);
|
||||
case SETMETATABLE:
|
||||
return _setmetatable(args);
|
||||
case SETUPVALUE:
|
||||
return _setupvalue(args);
|
||||
case TRACEBACK:
|
||||
return _traceback(args);
|
||||
default:
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------ Debug Info management --------------------------
|
||||
//
|
||||
// when DEBUG_ENABLED is set to true, these functions will be called
|
||||
// by Closure instances as they process bytecodes.
|
||||
//
|
||||
// Each thread will get a DebugState attached to it by the debug library
|
||||
// which will track function calls, hook functions, etc.
|
||||
//
|
||||
private static class DebugInfo {
|
||||
LuaValue func;
|
||||
LuaClosure closure;
|
||||
LuaValue[] stack;
|
||||
Varargs varargs, extras;
|
||||
int pc, top;
|
||||
|
||||
private DebugInfo() {
|
||||
func = NIL;
|
||||
}
|
||||
private DebugInfo(LuaValue func) {
|
||||
pc = -1;
|
||||
setfunction( func );
|
||||
}
|
||||
void setargs(Varargs varargs, LuaValue[] stack) {
|
||||
this.varargs = varargs;
|
||||
this.stack = stack;
|
||||
}
|
||||
void setfunction( LuaValue func ) {
|
||||
this.func = func;
|
||||
this.closure = (func instanceof LuaClosure? (LuaClosure) func: null);
|
||||
}
|
||||
void clear() {
|
||||
func = NIL;
|
||||
closure = null;
|
||||
stack = null;
|
||||
varargs = extras = null;
|
||||
pc = top = 0;
|
||||
}
|
||||
public void bytecode(int pc, Varargs extras, int top) {
|
||||
this.pc = pc;
|
||||
this.top = top;
|
||||
this.extras = extras;
|
||||
}
|
||||
public int currentline() {
|
||||
if ( closure == null ) return -1;
|
||||
int[] li = closure.p.lineinfo;
|
||||
return li==null || pc<0 || pc>=li.length? -1: li[pc];
|
||||
}
|
||||
public LuaString[] getfunckind() {
|
||||
if ( closure == null || pc<0 ) return null;
|
||||
int stackpos = (closure.p.code[pc] >> 6) & 0xff;
|
||||
return getobjname(this, stackpos);
|
||||
}
|
||||
public Object sourceline() {
|
||||
if ( closure == null ) return func.toString();
|
||||
String s = closure.p.source.toString();
|
||||
int line = currentline();
|
||||
return (s.startsWith("@")||s.startsWith("=")? s.substring(1): s) + ":" + line;
|
||||
}
|
||||
public String tracename() {
|
||||
// if ( func != null )
|
||||
// return func.toString();
|
||||
LuaString[] kind = getfunckind();
|
||||
if ( kind == null )
|
||||
return "function ?";
|
||||
return "function "+kind[0].toString();
|
||||
}
|
||||
public LuaString getlocalname(int index) {
|
||||
if ( closure == null ) return null;
|
||||
return closure.p.getlocalname(index, pc);
|
||||
}
|
||||
public String toString() {
|
||||
return sourceline()+": in "+tracename();
|
||||
}
|
||||
}
|
||||
|
||||
/** DebugState is associated with a Thread */
|
||||
private static class DebugState {
|
||||
private final LuaThread thread;
|
||||
private int debugCalls = 0;
|
||||
private DebugInfo[] debugInfo = new DebugInfo[LuaThread.MAX_CALLSTACK+1];
|
||||
private LuaValue hookfunc;
|
||||
private boolean hookcall,hookline,hookrtrn,inhook;
|
||||
private int hookcount;
|
||||
private int line;
|
||||
private DebugState(LuaThread thread) {
|
||||
this.thread = thread;
|
||||
}
|
||||
public DebugInfo nextInfo() {
|
||||
DebugInfo di = debugInfo[debugCalls];
|
||||
if ( di == null )
|
||||
debugInfo[debugCalls] = di = new DebugInfo();
|
||||
return di;
|
||||
}
|
||||
public DebugInfo pushInfo( int calls ) {
|
||||
while ( debugCalls < calls ) {
|
||||
nextInfo();
|
||||
++debugCalls;
|
||||
}
|
||||
return debugInfo[debugCalls-1];
|
||||
}
|
||||
public void popInfo(int calls) {
|
||||
while ( debugCalls > calls )
|
||||
debugInfo[--debugCalls].clear();
|
||||
}
|
||||
private void callHookFunc(DebugState ds, LuaString type, LuaValue arg) {
|
||||
if ( inhook || hookfunc == null )
|
||||
return;
|
||||
inhook = true;
|
||||
try {
|
||||
int n = debugCalls;
|
||||
ds.nextInfo().setargs( arg, null );
|
||||
ds.pushInfo(n+1).setfunction(hookfunc);
|
||||
try {
|
||||
hookfunc.call(type,arg);
|
||||
} finally {
|
||||
ds.popInfo(n);
|
||||
}
|
||||
} catch ( Throwable t ) {
|
||||
t.printStackTrace();
|
||||
} finally {
|
||||
inhook = false;
|
||||
}
|
||||
}
|
||||
public void sethook(LuaValue func, boolean call, boolean line, boolean rtrn, int count) {
|
||||
this.hookcount = count;
|
||||
this.hookcall = call;
|
||||
this.hookline = line;
|
||||
this.hookrtrn = rtrn;
|
||||
this.hookfunc = func;
|
||||
}
|
||||
private DebugInfo getDebugInfo() {
|
||||
return debugInfo[debugCalls-1];
|
||||
}
|
||||
private DebugInfo getDebugInfo(int level) {
|
||||
return level < 0 || level >= debugCalls? null: debugInfo[debugCalls-level-1];
|
||||
}
|
||||
public DebugInfo findDebugInfo(LuaValue func) {
|
||||
for ( int i=debugCalls; --i>=0; ) {
|
||||
if ( debugInfo[i].func == func ) {
|
||||
return debugInfo[i];
|
||||
}
|
||||
}
|
||||
return new DebugInfo(func);
|
||||
}
|
||||
public String toString() {
|
||||
return DebugLib.traceback(thread, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private static DebugState getDebugState( LuaThread thread ) {
|
||||
if ( thread.debugState == null )
|
||||
thread.debugState = new DebugState(thread);
|
||||
return (DebugState) thread.debugState;
|
||||
}
|
||||
|
||||
private static DebugState getDebugState() {
|
||||
return getDebugState( LuaThread.getRunning() );
|
||||
}
|
||||
|
||||
/** Called by Closures to set up stack and arguments to next call */
|
||||
public static void debugSetupCall(Varargs args, LuaValue[] stack) {
|
||||
DebugState ds = getDebugState();
|
||||
if ( ds.inhook )
|
||||
return;
|
||||
ds.nextInfo().setargs( args, stack );
|
||||
}
|
||||
|
||||
/** Called by Closures and recursing java functions on entry
|
||||
* @param calls */
|
||||
public static void debugOnCall(LuaThread thread, int calls, LuaFunction func) {
|
||||
DebugState ds = getDebugState();
|
||||
if ( ds.inhook )
|
||||
return;
|
||||
DebugInfo di = ds.pushInfo(calls);
|
||||
di.setfunction( func );
|
||||
if(CALLS)System.out.println("calling "+func);
|
||||
if ( ds.hookcall )
|
||||
ds.callHookFunc( ds, CALL, LuaValue.NIL );
|
||||
}
|
||||
|
||||
/** Called by Closures and recursing java functions on return
|
||||
* @param running_calls
|
||||
* @param thread */
|
||||
public static void debugOnReturn(LuaThread thread, int calls) {
|
||||
DebugState ds = getDebugState(thread);
|
||||
if ( ds.inhook )
|
||||
return;
|
||||
if(CALLS)System.out.println("returning");
|
||||
try {
|
||||
if ( ds.hookrtrn )
|
||||
ds.callHookFunc( ds, RETURN, LuaValue.NIL );
|
||||
} finally {
|
||||
getDebugState().popInfo(calls);
|
||||
}
|
||||
}
|
||||
|
||||
/** Called by Closures on bytecode execution */
|
||||
public static void debugBytecode( int pc, Varargs extras, int top ) {
|
||||
DebugState ds = getDebugState();
|
||||
if ( ds.inhook )
|
||||
return;
|
||||
DebugInfo di = ds.getDebugInfo();
|
||||
if(TRACE)Print.printState(di.closure, pc, di.stack, top, di.varargs);
|
||||
ds.getDebugInfo().bytecode( pc, extras, top );
|
||||
if ( ds.hookline ) {
|
||||
int newline = di.currentline();
|
||||
if ( newline != ds.line ) {
|
||||
ds.line = newline;
|
||||
ds.callHookFunc( ds, LINE, LuaValue.valueOf(newline) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------- library function implementations -----------------
|
||||
|
||||
// j2se subclass may wish to override and provide actual console here.
|
||||
// j2me platform has not System.in to provide console.
|
||||
private static Varargs _debug(Varargs args) {
|
||||
return NONE;
|
||||
}
|
||||
|
||||
private static Varargs _gethook(Varargs args) {
|
||||
int a=1;
|
||||
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();
|
||||
DebugState ds = getDebugState(thread);
|
||||
return varargsOf(
|
||||
ds.hookfunc,
|
||||
valueOf((ds.hookcall?"c":"")+(ds.hookline?"l":"")+(ds.hookrtrn?"r":"")),
|
||||
valueOf(ds.hookcount));
|
||||
}
|
||||
|
||||
private static Varargs _sethook(Varargs args) {
|
||||
int a=1;
|
||||
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();
|
||||
LuaValue func = args.optfunction(a++, null);
|
||||
String str = args.optString(a++,"");
|
||||
int count = args.optint(a++,0);
|
||||
boolean call=false,line=false,rtrn=false;
|
||||
for ( int i=0; i<str.length(); i++ )
|
||||
switch ( str.charAt(i) ) {
|
||||
case 'c': call=true; break;
|
||||
case 'l': line=true; break;
|
||||
case 'r': rtrn=true; break;
|
||||
}
|
||||
getDebugState(thread).sethook(func, call, line, rtrn, count);
|
||||
return NONE;
|
||||
}
|
||||
|
||||
private static Varargs _getfenv(Varargs args) {
|
||||
LuaValue object = args.arg1();
|
||||
LuaValue env = object.getfenv();
|
||||
return env!=null? env: LuaValue.NIL;
|
||||
}
|
||||
|
||||
private static Varargs _setfenv(Varargs args) {
|
||||
LuaValue object = args.arg1();
|
||||
LuaTable table = args.checktable(2);
|
||||
object.setfenv(table);
|
||||
return object;
|
||||
}
|
||||
|
||||
protected Varargs _getinfo(Varargs args) {
|
||||
int a=1;
|
||||
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();
|
||||
LuaValue func = args.arg(a++);
|
||||
String what = args.optString(a++, "nSluf");
|
||||
|
||||
// find the stack info
|
||||
DebugState ds = getDebugState( thread );
|
||||
DebugInfo di = null;
|
||||
if ( func.isnumber() ) {
|
||||
int level = func.checkint();
|
||||
di = level>0?
|
||||
ds.getDebugInfo(level-1):
|
||||
new DebugInfo( this );
|
||||
} else {
|
||||
di = ds.findDebugInfo( func.checkfunction() );
|
||||
}
|
||||
if ( di == null )
|
||||
return NIL;
|
||||
|
||||
// start a table
|
||||
LuaTable info = new LuaTable();
|
||||
LuaClosure c = di.closure;
|
||||
for (int i = 0, j = what.length(); i < j; i++) {
|
||||
switch (what.charAt(i)) {
|
||||
case 'S': {
|
||||
if ( c != null ) {
|
||||
Prototype p = c.p;
|
||||
info.set(WHAT, LUA);
|
||||
info.set(SOURCE, p.source);
|
||||
info.set(SHORT_SRC, valueOf(sourceshort(p)));
|
||||
info.set(LINEDEFINED, valueOf(p.linedefined));
|
||||
info.set(LASTLINEDEFINED, valueOf(p.lastlinedefined));
|
||||
} else {
|
||||
String shortName = di.func.toString();
|
||||
LuaString name = LuaString.valueOf("[Java] "+shortName);
|
||||
info.set(WHAT, JAVA);
|
||||
info.set(SOURCE, name);
|
||||
info.set(SHORT_SRC, valueOf(shortName));
|
||||
info.set(LINEDEFINED, LuaValue.MINUSONE);
|
||||
info.set(LASTLINEDEFINED, LuaValue.MINUSONE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'l': {
|
||||
int line = di.currentline();
|
||||
info.set( CURRENTLINE, valueOf(line) );
|
||||
break;
|
||||
}
|
||||
case 'u': {
|
||||
info.set(NUPS, valueOf(c!=null? c.p.nups: 0));
|
||||
break;
|
||||
}
|
||||
case 'n': {
|
||||
LuaString[] kind = di.getfunckind();
|
||||
info.set(NAME, kind!=null? kind[0]: QMARK);
|
||||
info.set(NAMEWHAT, kind!=null? kind[1]: EMPTYSTRING);
|
||||
break;
|
||||
}
|
||||
case 'f': {
|
||||
info.set( FUNC, di.func );
|
||||
break;
|
||||
}
|
||||
case 'L': {
|
||||
LuaTable lines = new LuaTable();
|
||||
info.set(ACTIVELINES, lines);
|
||||
// if ( di.luainfo != null ) {
|
||||
// int line = di.luainfo.currentline();
|
||||
// if ( line >= 0 )
|
||||
// lines.set(1, IntValue.valueOf(line));
|
||||
// }
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
public static String sourceshort(Prototype p) {
|
||||
String name = p.source.toString();
|
||||
if ( name.startsWith("@") || name.startsWith("=") )
|
||||
name = name.substring(1);
|
||||
else if ( name.startsWith("\033") )
|
||||
name = "binary string";
|
||||
return name;
|
||||
}
|
||||
|
||||
private static Varargs _getlocal(Varargs args) {
|
||||
int a=1;
|
||||
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();
|
||||
int level = args.checkint(a++);
|
||||
int local = args.checkint(a++);
|
||||
|
||||
DebugState ds = getDebugState(thread);
|
||||
DebugInfo di = ds.getDebugInfo(level-1);
|
||||
LuaString name = (di!=null? di.getlocalname(local): null);
|
||||
if ( name != null ) {
|
||||
LuaValue value = di.stack[local-1];
|
||||
return varargsOf( name, value );
|
||||
} else {
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
private static Varargs _setlocal(Varargs args) {
|
||||
int a=1;
|
||||
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();
|
||||
int level = args.checkint(a++);
|
||||
int local = args.checkint(a++);
|
||||
LuaValue value = args.arg(a++);
|
||||
|
||||
DebugState ds = getDebugState(thread);
|
||||
DebugInfo di = ds.getDebugInfo(level-1);
|
||||
LuaString name = (di!=null? di.getlocalname(local): null);
|
||||
if ( name != null ) {
|
||||
di.stack[local-1] = value;
|
||||
return name;
|
||||
} else {
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
private static LuaValue _getmetatable(Varargs args) {
|
||||
LuaValue object = args.arg(1);
|
||||
LuaValue mt = object.getmetatable();
|
||||
return mt!=null? mt: NIL;
|
||||
}
|
||||
|
||||
private static Varargs _setmetatable(Varargs args) {
|
||||
LuaValue object = args.arg(1);
|
||||
try {
|
||||
if ( ! args.isnoneornil(2) )
|
||||
object.setmetatable(args.checktable(2));
|
||||
else
|
||||
object.setmetatable(null);
|
||||
return LuaValue.TRUE;
|
||||
} catch ( LuaError e ) {
|
||||
return varargsOf(FALSE, valueOf(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
private static Varargs _getregistry(Varargs args) {
|
||||
return new LuaTable();
|
||||
}
|
||||
|
||||
private static LuaString findupvalue(LuaClosure c, int up) {
|
||||
if ( c.upValues != null && up > 0 && up <= c.upValues.length ) {
|
||||
if ( c.p.upvalues != null && up <= c.p.upvalues.length )
|
||||
return c.p.upvalues[up-1];
|
||||
else
|
||||
return LuaString.valueOf( "."+up );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Varargs _getupvalue(Varargs args) {
|
||||
LuaValue func = args.checkfunction(1);
|
||||
int up = args.checkint(2);
|
||||
if ( func instanceof LuaClosure ) {
|
||||
LuaClosure c = (LuaClosure) func;
|
||||
LuaString name = findupvalue(c, up);
|
||||
if ( name != null ) {
|
||||
return varargsOf(name, c.upValues[up-1].getValue() );
|
||||
}
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
|
||||
private static LuaValue _setupvalue(Varargs args) {
|
||||
LuaValue func = args.checkfunction(1);
|
||||
int up = args.checkint(2);
|
||||
LuaValue value = args.arg(3);
|
||||
if ( func instanceof LuaClosure ) {
|
||||
LuaClosure c = (LuaClosure) func;
|
||||
LuaString name = findupvalue(c, up);
|
||||
if ( name != null ) {
|
||||
c.upValues[up-1].setValue(value);
|
||||
return name;
|
||||
}
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
|
||||
private static LuaValue _traceback(Varargs args) {
|
||||
int a=1;
|
||||
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();
|
||||
String message = args.optString(a++, "stack traceback:");
|
||||
int level = args.optint(a++,1);
|
||||
String tb = DebugLib.traceback(thread, level);
|
||||
return valueOf(message+"\n"+tb);
|
||||
}
|
||||
|
||||
// =================== public utilities ====================
|
||||
|
||||
/**
|
||||
* Get a traceback as a string for the current thread
|
||||
*/
|
||||
public static String traceback(int level) {
|
||||
return traceback(LuaThread.getRunning(), level);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a traceback for a particular thread.
|
||||
* @param thread
|
||||
* @param level
|
||||
* @return
|
||||
*/
|
||||
public static String traceback(LuaThread thread, int level) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
DebugState ds = getDebugState(thread);
|
||||
DebugInfo di;
|
||||
for ( int i=level, n=ds.debugCalls; i<n; i++ ) {
|
||||
di = ds.getDebugInfo(i);
|
||||
if ( di != null ) {
|
||||
sb.append( "\t" );
|
||||
sb.append( di.toString() );
|
||||
if ( i<n )
|
||||
sb.append( "\n" );
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
// =======================================================
|
||||
|
||||
private static void lua_assert(boolean x) {
|
||||
if (!x) throw new RuntimeException("lua_assert failed");
|
||||
}
|
||||
|
||||
|
||||
// return StrValue[] { name, namewhat } if found, null if not
|
||||
private static LuaString[] getobjname(DebugInfo di, int stackpos) {
|
||||
LuaString name;
|
||||
if (di.closure != null) { /* a Lua function? */
|
||||
Prototype p = di.closure.p;
|
||||
int pc = di.pc; // currentpc(L, ci);
|
||||
int i;// Instruction i;
|
||||
name = p.getlocalname(stackpos + 1, pc);
|
||||
if (name != null) /* is a local? */
|
||||
return new LuaString[] { name, LOCAL };
|
||||
i = symbexec(p, pc, stackpos); /* try symbolic execution */
|
||||
lua_assert(pc != -1);
|
||||
switch (Lua.GET_OPCODE(i)) {
|
||||
case Lua.OP_GETGLOBAL: {
|
||||
int g = Lua.GETARG_Bx(i); /* global index */
|
||||
// lua_assert(p.k[g].isString());
|
||||
return new LuaString[] { p.k[g].strvalue(), GLOBAL };
|
||||
}
|
||||
case Lua.OP_MOVE: {
|
||||
int a = Lua.GETARG_A(i);
|
||||
int b = Lua.GETARG_B(i); /* move from `b' to `a' */
|
||||
if (b < a)
|
||||
return getobjname(di, b); /* get name for `b' */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_GETTABLE: {
|
||||
int k = Lua.GETARG_C(i); /* key index */
|
||||
name = kname(p, k);
|
||||
return new LuaString[] { name, FIELD };
|
||||
}
|
||||
case Lua.OP_GETUPVAL: {
|
||||
int u = Lua.GETARG_B(i); /* upvalue index */
|
||||
name = u < p.upvalues.length ? p.upvalues[u] : QMARK;
|
||||
return new LuaString[] { name, UPVALUE };
|
||||
}
|
||||
case Lua.OP_SELF: {
|
||||
int k = Lua.GETARG_C(i); /* key index */
|
||||
name = kname(p, k);
|
||||
return new LuaString[] { name, METHOD };
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return null; /* no useful name found */
|
||||
}
|
||||
|
||||
private static LuaString kname(Prototype p, int c) {
|
||||
if (Lua.ISK(c) && p.k[Lua.INDEXK(c)].isstring())
|
||||
return p.k[Lua.INDEXK(c)].strvalue();
|
||||
else
|
||||
return QMARK;
|
||||
}
|
||||
|
||||
private static boolean checkreg(Prototype pt,int reg) {
|
||||
return (reg < pt.maxstacksize);
|
||||
}
|
||||
|
||||
private static boolean precheck(Prototype pt) {
|
||||
if (!(pt.maxstacksize <= MAXSTACK)) return false;
|
||||
lua_assert(pt.numparams + (pt.is_vararg & Lua.VARARG_HASARG) <= pt.maxstacksize);
|
||||
lua_assert((pt.is_vararg & Lua.VARARG_NEEDSARG) == 0
|
||||
|| (pt.is_vararg & Lua.VARARG_HASARG) != 0);
|
||||
if (!(pt.upvalues.length <= pt.nups)) return false;
|
||||
if (!(pt.lineinfo.length == pt.code.length || pt.lineinfo.length == 0)) return false;
|
||||
if (!(Lua.GET_OPCODE(pt.code[pt.code.length - 1]) == Lua.OP_RETURN)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean checkopenop(Prototype pt,int pc) {
|
||||
int i = pt.code[(pc)+1];
|
||||
switch (Lua.GET_OPCODE(i)) {
|
||||
case Lua.OP_CALL:
|
||||
case Lua.OP_TAILCALL:
|
||||
case Lua.OP_RETURN:
|
||||
case Lua.OP_SETLIST: {
|
||||
if (!(Lua.GETARG_B(i) == 0)) return false;
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false; /* invalid instruction after an open call */
|
||||
}
|
||||
}
|
||||
|
||||
//static int checkArgMode (Prototype pt, int r, enum OpArgMask mode) {
|
||||
private static boolean checkArgMode (Prototype pt, int r, int mode) {
|
||||
switch (mode) {
|
||||
case Lua.OpArgN: if (!(r == 0)) return false; break;
|
||||
case Lua.OpArgU: break;
|
||||
case Lua.OpArgR: checkreg(pt, r); break;
|
||||
case Lua.OpArgK:
|
||||
if (!(Lua.ISK(r) ? Lua.INDEXK(r) < pt.k.length : r < pt.maxstacksize)) return false;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// return last instruction, or 0 if error
|
||||
private static int symbexec(Prototype pt, int lastpc, int reg) {
|
||||
int pc;
|
||||
int last; /* stores position of last instruction that changed `reg' */
|
||||
last = pt.code.length - 1; /*
|
||||
* points to final return (a `neutral'
|
||||
* instruction)
|
||||
*/
|
||||
if (!(precheck(pt))) return 0;
|
||||
for (pc = 0; pc < lastpc; pc++) {
|
||||
int i = pt.code[pc];
|
||||
int op = Lua.GET_OPCODE(i);
|
||||
int a = Lua.GETARG_A(i);
|
||||
int b = 0;
|
||||
int c = 0;
|
||||
if (!(op < Lua.NUM_OPCODES)) return 0;
|
||||
if (!checkreg(pt, a)) return 0;
|
||||
switch (Lua.getOpMode(op)) {
|
||||
case Lua.iABC: {
|
||||
b = Lua.GETARG_B(i);
|
||||
c = Lua.GETARG_C(i);
|
||||
if (!(checkArgMode(pt, b, Lua.getBMode(op)))) return 0;
|
||||
if (!(checkArgMode(pt, c, Lua.getCMode(op)))) return 0;
|
||||
break;
|
||||
}
|
||||
case Lua.iABx: {
|
||||
b = Lua.GETARG_Bx(i);
|
||||
if (Lua.getBMode(op) == Lua.OpArgK)
|
||||
if (!(b < pt.k.length)) return 0;
|
||||
break;
|
||||
}
|
||||
case Lua.iAsBx: {
|
||||
b = Lua.GETARG_sBx(i);
|
||||
if (Lua.getBMode(op) == Lua.OpArgR) {
|
||||
int dest = pc + 1 + b;
|
||||
if (!(0 <= dest && dest < pt.code.length)) return 0;
|
||||
if (dest > 0) {
|
||||
/* cannot jump to a setlist count */
|
||||
int d = pt.code[dest - 1];
|
||||
if ((Lua.GET_OPCODE(d) == Lua.OP_SETLIST && Lua.GETARG_C(d) == 0)) return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (Lua.testAMode(op)) {
|
||||
if (a == reg)
|
||||
last = pc; /* change register `a' */
|
||||
}
|
||||
if (Lua.testTMode(op)) {
|
||||
if (!(pc + 2 < pt.code.length)) return 0; /* check skip */
|
||||
if (!(Lua.GET_OPCODE(pt.code[pc + 1]) == Lua.OP_JMP)) return 0;
|
||||
}
|
||||
switch (op) {
|
||||
case Lua.OP_LOADBOOL: {
|
||||
if (!(c == 0 || pc + 2 < pt.code.length)) return 0; /* check its jump */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_LOADNIL: {
|
||||
if (a <= reg && reg <= b)
|
||||
last = pc; /* set registers from `a' to `b' */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_GETUPVAL:
|
||||
case Lua.OP_SETUPVAL: {
|
||||
if (!(b < pt.nups)) return 0;
|
||||
break;
|
||||
}
|
||||
case Lua.OP_GETGLOBAL:
|
||||
case Lua.OP_SETGLOBAL: {
|
||||
if (!(pt.k[b].isstring())) return 0;
|
||||
break;
|
||||
}
|
||||
case Lua.OP_SELF: {
|
||||
if (!checkreg(pt, a + 1)) return 0;
|
||||
if (reg == a + 1)
|
||||
last = pc;
|
||||
break;
|
||||
}
|
||||
case Lua.OP_CONCAT: {
|
||||
if (!(b < c)) return 0; /* at least two operands */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_TFORLOOP: {
|
||||
if (!(c >= 1)) return 0; /* at least one result (control variable) */
|
||||
if (!checkreg(pt, a + 2 + c)) return 0; /* space for results */
|
||||
if (reg >= a + 2)
|
||||
last = pc; /* affect all regs above its base */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_FORLOOP:
|
||||
case Lua.OP_FORPREP:
|
||||
if (!checkreg(pt, a + 3)) return 0;
|
||||
/* go through */
|
||||
case Lua.OP_JMP: {
|
||||
int dest = pc + 1 + b;
|
||||
/* not full check and jump is forward and do not skip `lastpc'? */
|
||||
if (reg != Lua.NO_REG && pc < dest && dest <= lastpc)
|
||||
pc += b; /* do the jump */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_CALL:
|
||||
case Lua.OP_TAILCALL: {
|
||||
if (b != 0) {
|
||||
if (!checkreg(pt, a + b - 1)) return 0;
|
||||
}
|
||||
c--; /* c = num. returns */
|
||||
if (c == Lua.LUA_MULTRET) {
|
||||
if (!(checkopenop(pt, pc))) return 0;
|
||||
} else if (c != 0)
|
||||
if (!checkreg(pt, a + c - 1)) return 0;
|
||||
if (reg >= a)
|
||||
last = pc; /* affect all registers above base */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_RETURN: {
|
||||
b--; /* b = num. returns */
|
||||
if (b > 0)
|
||||
if (!checkreg(pt, a + b - 1)) return 0;
|
||||
break;
|
||||
}
|
||||
case Lua.OP_SETLIST: {
|
||||
if (b > 0)
|
||||
if (!checkreg(pt, a + b)) return 0;
|
||||
if (c == 0)
|
||||
pc++;
|
||||
break;
|
||||
}
|
||||
case Lua.OP_CLOSURE: {
|
||||
int nup, j;
|
||||
if (!(b < pt.p.length)) return 0;
|
||||
nup = pt.p[b].nups;
|
||||
if (!(pc + nup < pt.code.length)) return 0;
|
||||
for (j = 1; j <= nup; j++) {
|
||||
int op1 = Lua.GET_OPCODE(pt.code[pc + j]);
|
||||
if (!(op1 == Lua.OP_GETUPVAL || op1 == Lua.OP_MOVE)) return 0;
|
||||
}
|
||||
if (reg != Lua.NO_REG) /* tracing? */
|
||||
pc += nup; /* do not 'execute' these pseudo-instructions */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_VARARG: {
|
||||
if (!((pt.is_vararg & Lua.VARARG_ISVARARG) != 0
|
||||
&& (pt.is_vararg & Lua.VARARG_NEEDSARG) == 0)) return 0;
|
||||
b--;
|
||||
if (b == Lua.LUA_MULTRET)
|
||||
if (!(checkopenop(pt, pc))) return 0;
|
||||
if (!checkreg(pt, a + b - 1)) return 0;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return pt.code[last];
|
||||
}
|
||||
|
||||
}
|
||||
431
src/core/org/luaj/vm2/lib/IoLib.java
Normal file
431
src/core/org/luaj/vm2/lib/IoLib.java
Normal file
@@ -0,0 +1,431 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
|
||||
|
||||
abstract
|
||||
public class IoLib extends LuaTable {
|
||||
|
||||
abstract
|
||||
protected class File extends LuaValue{
|
||||
abstract public void write( LuaString string ) throws IOException;
|
||||
abstract public void flush() throws IOException;
|
||||
abstract public boolean isstdfile();
|
||||
abstract public void close() throws IOException;
|
||||
abstract public boolean isclosed();
|
||||
// returns new position
|
||||
abstract public int seek(String option, int bytecount) throws IOException;
|
||||
abstract public void setvbuf(String mode, int size);
|
||||
// get length remaining to read
|
||||
abstract public int remaining() throws IOException;
|
||||
// peek ahead one character
|
||||
abstract public int peek() throws IOException, EOFException;
|
||||
// return char if read, -1 if eof, throw IOException on other exception
|
||||
abstract public int read() throws IOException, EOFException;
|
||||
// return number of bytes read if positive, false if eof, throw IOException on other exception
|
||||
abstract public int read(byte[] bytes, int offset, int length) throws IOException;
|
||||
|
||||
// delegate method access to file methods table
|
||||
public LuaValue get( LuaValue key ) {
|
||||
return filemethods.get(key);
|
||||
}
|
||||
|
||||
// essentially a userdata instance
|
||||
public int type() {
|
||||
return LuaValue.TUSERDATA;
|
||||
}
|
||||
public String typename() {
|
||||
return "userdata";
|
||||
}
|
||||
|
||||
// displays as "file" type
|
||||
public String toString() {
|
||||
return "file: " + Integer.toHexString(hashCode());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Wrap the standard input.
|
||||
* @return File
|
||||
* @throws IOException
|
||||
*/
|
||||
abstract protected File wrapStdin() throws IOException;
|
||||
|
||||
/**
|
||||
* Wrap the standard output.
|
||||
* @return File
|
||||
* @throws IOException
|
||||
*/
|
||||
abstract protected File wrapStdout() throws IOException;
|
||||
|
||||
/**
|
||||
* Open a file in a particular mode.
|
||||
* @param filename
|
||||
* @param mode
|
||||
* @return File object if successful
|
||||
* @throws IOException if could not be opened
|
||||
*/
|
||||
abstract protected File openFile( String filename, boolean readMode, boolean appendMode, boolean updateMode, boolean binaryMode ) throws IOException;
|
||||
|
||||
/**
|
||||
* Open a temporary file.
|
||||
* @return File object if successful
|
||||
* @throws IOException if could not be opened
|
||||
*/
|
||||
abstract protected File tmpFile() throws IOException;
|
||||
|
||||
/**
|
||||
* Start a new process and return a file for input or output
|
||||
* @param prog the program to execute
|
||||
* @param mode "r" to read, "w" to write
|
||||
* @return File to read to or write from
|
||||
* @throws IOException if an i/o exception occurs
|
||||
*/
|
||||
abstract protected File openProgram(String prog, String mode) throws IOException;
|
||||
|
||||
|
||||
//protected final Table filemt;
|
||||
protected final LuaTable filemethods;
|
||||
private final LuaValue linesiter;
|
||||
|
||||
private File infile = null;
|
||||
private File outfile = null;
|
||||
private File errfile = null;
|
||||
|
||||
private static final LuaValue STDIN = valueOf("stdin");
|
||||
private static final LuaValue STDOUT = valueOf("stdout");
|
||||
private static final LuaValue STDERR = valueOf("stderr");
|
||||
private static final LuaValue FILE = valueOf("file");
|
||||
private static final LuaValue CLOSED_FILE = valueOf("closed file");
|
||||
|
||||
public IoLib() {
|
||||
|
||||
// io lib functions
|
||||
set("flush", new IoFuncV("flush",0));
|
||||
set("tmpfile", new IoFuncV("tmpfile",1));
|
||||
set("close", new IoFuncV("close",2));
|
||||
set("input", new IoFuncV("input",3));
|
||||
set("output", new IoFuncV("output",4));
|
||||
set("type", new IoFuncV("type",5));
|
||||
set("popen", new IoFuncV("popen",6));
|
||||
set("open", new IoFuncV("open",7));
|
||||
set("lines", new IoFuncV("lines",8));
|
||||
set("read", new IoFuncV("read",9));
|
||||
set("write", new IoFuncV("write",10));
|
||||
setmetatable( tableOf(new LuaValue[] {
|
||||
valueOf("__index"),new IoFuncV("__index",11),
|
||||
}) );
|
||||
|
||||
// create file metatable
|
||||
filemethods = tableOf(new LuaValue[] {
|
||||
valueOf("close"), new IoFuncV("close",12),
|
||||
valueOf("flush"), new IoFuncV("flush",13),
|
||||
valueOf("setvbuf"), new IoFuncV("setvbuf",14),
|
||||
valueOf("lines"), new IoFuncV("lines",15),
|
||||
valueOf("read"), new IoFuncV("read",16),
|
||||
valueOf("seek"), new IoFuncV("seek",17),
|
||||
valueOf("write"), new IoFuncV("write",18),
|
||||
});
|
||||
//filemt = tableOf(new Value[]{valueOf("__index"),filemethods});
|
||||
|
||||
// lines iterator
|
||||
linesiter = new IoFuncV("linesiter",19);
|
||||
}
|
||||
|
||||
public class IoFuncV extends VarArgFunction {
|
||||
public IoFuncV(String name, int opcode) {
|
||||
super(name,opcode,IoLib.this);
|
||||
}
|
||||
public Varargs invoke(Varargs args) {
|
||||
File f;
|
||||
int n;
|
||||
LuaValue v;
|
||||
try {
|
||||
switch ( opcode ) {
|
||||
case 0: // io.flush() -> bool
|
||||
checkopen(output());
|
||||
outfile.flush();
|
||||
return LuaValue.TRUE;
|
||||
case 1: // io.tmpfile() -> file
|
||||
return tmpFile();
|
||||
case 2: // io.close([file]) -> void
|
||||
f = args.arg1().isnil()? output(): checkfile(args.arg1());
|
||||
checkopen(f);
|
||||
return ioclose(f);
|
||||
case 3: // io.input([file]) -> file
|
||||
infile = args.arg1().isnil()? input(): args.arg1().isstring()?
|
||||
ioopenfile(args.checkString(1),"r"):
|
||||
checkfile(args.arg1());
|
||||
return infile;
|
||||
|
||||
case 4: // io.output(filename) -> file
|
||||
outfile = args.arg1().isnil()? output(): args.arg1().isstring()?
|
||||
ioopenfile(args.checkString(1),"w"):
|
||||
checkfile(args.arg1());
|
||||
return outfile;
|
||||
case 5: // io.type(obj) -> "file" | "closed file" | nil
|
||||
if ( (f=optfile(args.arg1())) != null )
|
||||
return f.isclosed()? CLOSED_FILE: FILE;
|
||||
return NIL;
|
||||
case 6: // io.popen(prog, [mode]) -> file
|
||||
return openProgram(args.checkString(1),args.optString(2,"r"));
|
||||
case 7: // io.open(filename, [mode]) -> file | nil,err
|
||||
return rawopenfile(args.checkString(1), args.optString(2,"r"));
|
||||
case 8: // io.lines(filename) -> iterator
|
||||
infile = args.arg1().isnil()? input(): ioopenfile(args.checkString(1),"r");
|
||||
checkopen(infile);
|
||||
return lines(infile);
|
||||
case 9: // io.read(...) -> (...)
|
||||
checkopen(infile);
|
||||
return ioread(infile,args);
|
||||
case 10: // io.write(...) -> void
|
||||
checkopen(output());
|
||||
return iowrite(outfile,args);
|
||||
case 11: // __index, returns a field
|
||||
v = args.arg(2);
|
||||
return v.equals(STDOUT)?output():
|
||||
v.equals(STDIN)? input():
|
||||
v.equals(STDERR)? errput(): NIL;
|
||||
|
||||
// ------------ file metatable operations
|
||||
|
||||
case 12: // file:close() -> void
|
||||
return ioclose(checkfile(args.arg1()));
|
||||
case 13: // file:flush() -> void
|
||||
checkfile(args.arg1()).flush();
|
||||
return LuaValue.TRUE;
|
||||
case 14: // file:setvbuf(mode,[size]) -> void
|
||||
f = checkfile(args.arg1());
|
||||
f.setvbuf(args.checkString(2),args.optint(3, 1024));
|
||||
return LuaValue.TRUE;
|
||||
case 15: // file:lines() -> iterator
|
||||
return lines(checkfile(args.arg1()));
|
||||
case 16: // file:read(...) -> (...)
|
||||
f = checkfile(args.arg1());
|
||||
return ioread(f,args.subargs(2));
|
||||
case 17: // file:seek([whence][,offset]) -> pos | nil,error
|
||||
f = checkfile(args.arg1());
|
||||
n = f.seek(args.optString(2,"cur"),args.optint(3,0));
|
||||
return valueOf(n);
|
||||
case 18: // file:write(...) -> void
|
||||
f = checkfile(args.arg1());
|
||||
return iowrite(f,args.subargs(2));
|
||||
case 19: // lines iterator(s,var) -> var'
|
||||
f = checkfile(args.arg1());
|
||||
return freadline(f);
|
||||
}
|
||||
} catch ( IOException ioe ) {
|
||||
return errorresult(ioe);
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
private File input() {
|
||||
return infile!=null? infile: (infile=ioopenfile("-","r"));
|
||||
}
|
||||
|
||||
private File output() {
|
||||
return outfile!=null? outfile: (outfile=ioopenfile("-","w"));
|
||||
}
|
||||
|
||||
private File errput() {
|
||||
return errfile!=null? errfile: (errfile=ioopenfile("-","w"));
|
||||
}
|
||||
|
||||
private File ioopenfile(String filename, String mode) {
|
||||
try {
|
||||
return rawopenfile(filename, mode);
|
||||
} catch ( Exception e ) {
|
||||
error("io error: "+e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static Varargs ioclose(File f) throws IOException {
|
||||
if ( f.isstdfile() )
|
||||
return errorresult("cannot close standard file");
|
||||
else {
|
||||
f.close();
|
||||
return successresult();
|
||||
}
|
||||
}
|
||||
|
||||
private static Varargs successresult() {
|
||||
return LuaValue.TRUE;
|
||||
}
|
||||
|
||||
private static Varargs errorresult(IOException ioe) {
|
||||
String s = ioe.getMessage();
|
||||
return errorresult("io error: "+(s!=null? s: ioe.toString()));
|
||||
}
|
||||
|
||||
private static Varargs errorresult(String errortext) {
|
||||
return varargsOf(NIL, valueOf(errortext));
|
||||
}
|
||||
|
||||
// TODO: how to close on finalization
|
||||
private Varargs lines(final File f) throws IOException {
|
||||
return varargsOf( linesiter, f );
|
||||
}
|
||||
|
||||
private static Varargs iowrite(File f, Varargs args) throws IOException {
|
||||
for ( int i=1, n=args.narg(); i<=n; i++ )
|
||||
f.write( args.checkstring(i) );
|
||||
return LuaValue.TRUE;
|
||||
}
|
||||
|
||||
private Varargs ioread(File f, Varargs args) throws IOException {
|
||||
int i,n=args.narg();
|
||||
LuaValue[] v = new LuaValue[n];
|
||||
for ( i=0; i<n; i++ ) {
|
||||
if ( args.isnumber(i+1) ) {
|
||||
v[i] = freadbytes(f,args.checkint(i+1));
|
||||
} else {
|
||||
String format = args.checkString(i+1);
|
||||
if ( "*n".equals(format) )
|
||||
v[i] = valueOf( freadnumber(f) );
|
||||
else if ( "*a".equals(format) )
|
||||
v[i] = freadall(f);
|
||||
else if ( "*l".equals(format) )
|
||||
v[i] = freadline(f);
|
||||
else
|
||||
typerror( i+1, "(invalid format)" );
|
||||
}
|
||||
if ( v[i].isnil() )
|
||||
return varargsOf(v,0,i);
|
||||
}
|
||||
return varargsOf(v);
|
||||
}
|
||||
|
||||
private static File checkfile(LuaValue val) {
|
||||
File f = optfile(val);
|
||||
if ( f == null )
|
||||
argerror(1,"file");
|
||||
checkopen( f );
|
||||
return f;
|
||||
}
|
||||
|
||||
private static File optfile(LuaValue val) {
|
||||
return (val instanceof File)? (File) val: null;
|
||||
}
|
||||
|
||||
private static File checkopen(File file) {
|
||||
if ( file.isclosed() )
|
||||
error("attempt to use a closed file");
|
||||
return file;
|
||||
}
|
||||
|
||||
private File rawopenfile(String filename, String mode) throws IOException {
|
||||
boolean isstdfile = "-".equals(filename);
|
||||
boolean isreadmode = mode.startsWith("r");
|
||||
if ( isstdfile ) {
|
||||
return isreadmode?
|
||||
wrapStdin():
|
||||
wrapStdout();
|
||||
}
|
||||
boolean isappend = mode.startsWith("a");
|
||||
boolean isupdate = mode.indexOf("+") > 0;
|
||||
boolean isbinary = mode.endsWith("b");
|
||||
return openFile( filename, isreadmode, isappend, isupdate, isbinary );
|
||||
}
|
||||
|
||||
|
||||
// ------------- file reading utilitied ------------------
|
||||
|
||||
public static LuaValue freadbytes(File f, int count) throws IOException {
|
||||
byte[] b = new byte[count];
|
||||
int r;
|
||||
if ( ( r = f.read(b,0,b.length) ) < 0 )
|
||||
return NIL;
|
||||
return valueOf(b, 0, r);
|
||||
}
|
||||
public static LuaValue freaduntil(File f,int delim) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
int c;
|
||||
try {
|
||||
while ( true ) {
|
||||
c = f.read();
|
||||
if ( c < 0 || c == delim )
|
||||
break;
|
||||
baos.write(c);
|
||||
}
|
||||
} catch ( EOFException e ) {
|
||||
c = -1;
|
||||
}
|
||||
return ( c < 0 && baos.size() == 0 )?
|
||||
(LuaValue) NIL:
|
||||
(LuaValue) valueOf(baos.toByteArray());
|
||||
}
|
||||
public static LuaValue freadline(File f) throws IOException {
|
||||
return freaduntil(f,'\n');
|
||||
}
|
||||
public static LuaValue freadall(File f) throws IOException {
|
||||
int n = f.remaining();
|
||||
if ( n >= 0 ) {
|
||||
return freadbytes(f, n);
|
||||
} else {
|
||||
return freaduntil(f,-1);
|
||||
}
|
||||
}
|
||||
public static double freadnumber(File f) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
freadchars(f," \t\r\n",null);
|
||||
freadchars(f,"-+",baos);
|
||||
//freadchars(f,"0",baos);
|
||||
//freadchars(f,"xX",baos);
|
||||
freadchars(f,"0123456789",baos);
|
||||
freadchars(f,".",baos);
|
||||
freadchars(f,"0123456789",baos);
|
||||
//freadchars(f,"eEfFgG",baos);
|
||||
// freadchars(f,"+-",baos);
|
||||
//freadchars(f,"0123456789",baos);
|
||||
String s = baos.toString();
|
||||
return s.length()>0? Double.parseDouble(s): 0;
|
||||
}
|
||||
private static void freadchars(File f, String chars, ByteArrayOutputStream baos) throws IOException {
|
||||
int c;
|
||||
while ( true ) {
|
||||
c = f.peek();
|
||||
if ( chars.indexOf(c) < 0 ) {
|
||||
return;
|
||||
}
|
||||
f.read();
|
||||
if ( baos != null )
|
||||
baos.write( c );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
76
src/core/org/luaj/vm2/lib/LibFunction.java
Normal file
76
src/core/org/luaj/vm2/lib/LibFunction.java
Normal file
@@ -0,0 +1,76 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib;
|
||||
|
||||
import org.luaj.vm2.LuaFunction;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
;
|
||||
|
||||
|
||||
abstract public class LibFunction extends LuaFunction {
|
||||
|
||||
protected int opcode;
|
||||
protected String name;
|
||||
|
||||
public LibFunction() {
|
||||
}
|
||||
|
||||
public LibFunction(String name, int opcode, LuaValue env) {
|
||||
super(env);
|
||||
this.name = name;
|
||||
this.opcode = opcode;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return name!=null? name: super.toString();
|
||||
}
|
||||
|
||||
/** Bind a set of names to class instances, put values into the table. */
|
||||
public static LuaTable bind( LuaTable table, Class libFuncClass, String[] names ) {
|
||||
try {
|
||||
for ( int i=0, n=names.length; i<n; i++ ) {
|
||||
LibFunction f = (LibFunction) libFuncClass.newInstance();
|
||||
f.opcode = i;
|
||||
f.name = names[i];
|
||||
f.env = table;
|
||||
table.set( names[i], f );
|
||||
}
|
||||
} catch (InstantiationException e) {
|
||||
throw new RuntimeException(e.toString());
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e.toString());
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
/** Bind a complete set of names and classes , put values into the table. */
|
||||
public static LuaTable bind( LuaTable table, Class[] libFuncClasses, String[][] nameLists ) {
|
||||
for ( int j=0, n=libFuncClasses.length; j<n; j++ ) {
|
||||
bind( table, libFuncClasses[j], nameLists[j] );
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
194
src/core/org/luaj/vm2/lib/MathLib.java
Normal file
194
src/core/org/luaj/vm2/lib/MathLib.java
Normal file
@@ -0,0 +1,194 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import org.luaj.vm2.LuaDouble;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/**
|
||||
* Base math library with JME support.
|
||||
*
|
||||
* For j2se support use org.luaj.lib.j2se.MathLib
|
||||
*
|
||||
* @see org.luaj.vm2.lib.jse.JseMathLib
|
||||
*/
|
||||
public class MathLib extends LuaTable {
|
||||
public static MathLib MATHLIB = null;
|
||||
|
||||
private Random random;
|
||||
|
||||
public MathLib() {
|
||||
MATHLIB = this;
|
||||
this.set( "pi", Math.PI );
|
||||
this.set( "huge", LuaDouble.POSINF );
|
||||
LibFunction.bind( this, new MathFunc1().getClass(), new String[] {
|
||||
"abs", "ceil", "cos", "deg",
|
||||
"exp", "floor", "rad", "sin",
|
||||
"sqrt", "tan" } );
|
||||
LibFunction.bind( this, new MathFunc2().getClass(), new String[] {
|
||||
"fmod", "ldexp", "pow", "random",
|
||||
} );
|
||||
LibFunction.bind( this, new MathFuncV().getClass(), new String[] {
|
||||
"frexp", "max", "min", "modf",
|
||||
"randomseed" } );
|
||||
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "math";
|
||||
}
|
||||
|
||||
public static class MathFunc1 extends OneArgFunction {
|
||||
public LuaValue call(LuaValue arg) {
|
||||
switch ( opcode ) {
|
||||
case 0: return valueOf(Math.abs(arg.todouble()));
|
||||
case 1: return valueOf(Math.ceil(arg.todouble()));
|
||||
case 2: return valueOf(Math.cos(arg.todouble()));
|
||||
case 3: return valueOf(Math.toDegrees(arg.todouble()));
|
||||
case 4: return dpow(Math.E,arg.todouble());
|
||||
case 5: return valueOf(Math.floor(arg.todouble()));
|
||||
case 6: return valueOf(Math.toRadians(arg.todouble()));
|
||||
case 7: return valueOf(Math.sin(arg.todouble()));
|
||||
case 8: return valueOf(Math.sqrt(arg.todouble()));
|
||||
case 9: return valueOf(Math.tan(arg.todouble()));
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
public static class MathFunc2 extends TwoArgFunction {
|
||||
public LuaValue call(LuaValue arg1,LuaValue arg2) {
|
||||
switch ( opcode ) {
|
||||
case 0: { // fmod
|
||||
double x = arg1.checkdouble();
|
||||
double y = arg2.checkdouble();
|
||||
double q = x/y;
|
||||
double f = x - y * (q>=0? Math.floor(q): Math.ceil(q));
|
||||
return valueOf( f );
|
||||
}
|
||||
case 1: { // ldexp
|
||||
double x = arg1.checkdouble();
|
||||
double y = arg2.checkdouble()+1023.5;
|
||||
long e = (long) ((0!=(1&((int)y)))? Math.floor(y): Math.ceil(y-1));
|
||||
return valueOf(x * Double.longBitsToDouble(e << 52));
|
||||
}
|
||||
case 2: { // pow
|
||||
return dpow(arg1.todouble(), arg2.todouble());
|
||||
}
|
||||
case 3: { // random
|
||||
MathLib lib = (MathLib) env;
|
||||
if ( lib.random == null )
|
||||
lib.random = new Random();
|
||||
if ( arg1.isnil() )
|
||||
return valueOf( lib.random.nextDouble() );
|
||||
int m = arg1.toint();
|
||||
if ( arg2.isnil() )
|
||||
return valueOf( 1 + lib.random.nextInt(m) );
|
||||
else
|
||||
return valueOf( m + lib.random.nextInt(arg2.toint()-m) );
|
||||
}
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** compute power using installed math library, or default if there is no math library installed */
|
||||
public static LuaValue dpow(double a, double b) {
|
||||
return LuaDouble.valueOf(
|
||||
MATHLIB!=null?
|
||||
MATHLIB.dpow_d(a,b):
|
||||
dpow_default(a,b) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to override default dpow behavior with faster implementation.
|
||||
*/
|
||||
public double dpow_d(double a, double b) {
|
||||
return dpow_default(a,b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default JME version computes using longhand heuristics.
|
||||
*/
|
||||
protected static double dpow_default(double a, double b) {
|
||||
if ( b < 0 )
|
||||
return 1 / dpow_default( a, -b );
|
||||
double p = 1;
|
||||
int whole = (int) b;
|
||||
for ( double v=a; whole > 0; whole>>=1, v*=v )
|
||||
if ( (whole & 1) != 0 )
|
||||
p *= v;
|
||||
if ( (b -= whole) > 0 ) {
|
||||
int frac = (int) (0x10000 * b);
|
||||
for ( ; (frac&0xffff)!=0; frac<<=1 ) {
|
||||
a = Math.sqrt(a);
|
||||
if ( (frac & 0x8000) != 0 )
|
||||
p *= a;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
public static class MathFuncV extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
switch ( opcode ) {
|
||||
case 0: { // frexp
|
||||
double x = args.checkdouble(1);
|
||||
if ( x == 0 ) return varargsOf(ZERO,ZERO);
|
||||
long bits = Double.doubleToLongBits( x );
|
||||
double m = ((bits & (~(-1L<<52))) + (1L<<52)) * ((bits >= 0)? (.5 / (1L<<52)): (-.5 / (1L<<52)));
|
||||
double e = (((int) (bits >> 52)) & 0x7ff) - 1022;
|
||||
return varargsOf( valueOf(m), valueOf(e) );
|
||||
}
|
||||
case 1: { // max
|
||||
double m = args.checkdouble(1);
|
||||
for ( int i=2,n=args.narg(); i<=n; ++i )
|
||||
m = Math.max(m,args.checkdouble(i));
|
||||
return valueOf(m);
|
||||
}
|
||||
case 2: { // min
|
||||
double m = args.checkdouble(1);
|
||||
for ( int i=2,n=args.narg(); i<=n; ++i )
|
||||
m = Math.min(m,args.checkdouble(i));
|
||||
return valueOf(m);
|
||||
}
|
||||
case 3: { // modf
|
||||
double x = args.checkdouble(1);
|
||||
double intPart = ( x > 0 ) ? Math.floor( x ) : Math.ceil( x );
|
||||
double fracPart = x - intPart;
|
||||
return varargsOf( valueOf(intPart), valueOf(fracPart) );
|
||||
}
|
||||
case 4: { // randomseed
|
||||
long seed = args.checklong(1);
|
||||
((MathLib) env).random = new Random(seed);
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
57
src/core/org/luaj/vm2/lib/OneArgFunction.java
Normal file
57
src/core/org/luaj/vm2/lib/OneArgFunction.java
Normal file
@@ -0,0 +1,57 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
abstract public class OneArgFunction extends LibFunction {
|
||||
|
||||
abstract public LuaValue call(LuaValue arg);
|
||||
|
||||
public OneArgFunction() {
|
||||
}
|
||||
|
||||
public OneArgFunction( LuaValue env ) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public OneArgFunction( String name, int opcode, LuaValue env ) {
|
||||
super(name, opcode, env);
|
||||
}
|
||||
|
||||
public final LuaValue call() {
|
||||
return call(NIL);
|
||||
}
|
||||
|
||||
public final LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return call(arg1);
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
|
||||
return call(arg1);
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs varargs) {
|
||||
return call(varargs.arg1());
|
||||
}
|
||||
}
|
||||
292
src/core/org/luaj/vm2/lib/OsLib.java
Normal file
292
src/core/org/luaj/vm2/lib/OsLib.java
Normal file
@@ -0,0 +1,292 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/**
|
||||
* Base implementation of OsLib, with simplified stub functions
|
||||
* for library functions that cannot be implemented uniformly
|
||||
* on J2se and J2me.
|
||||
*
|
||||
* <p>
|
||||
* This can be installed as-is on either platform, or extended
|
||||
* and refined to be used in a complete J2se implementation.
|
||||
*
|
||||
* <p>Contains limited implementations of features not supported well on J2me:
|
||||
* <bl>
|
||||
* <li>execute()</li>
|
||||
* <li>remove()</li>
|
||||
* <li>rename()</li>
|
||||
* <li>tmpname()</li>
|
||||
* </bl>
|
||||
*
|
||||
* @see org.luaj.vm2.lib.jse.JseOsLib
|
||||
*/
|
||||
public class OsLib extends LuaTable {
|
||||
public static String TMP_PREFIX = ".luaj";
|
||||
public static String TMP_SUFFIX = "tmp";
|
||||
|
||||
private static final int CLOCK = 0;
|
||||
private static final int DATE = 1;
|
||||
private static final int DIFFTIME = 2;
|
||||
private static final int EXECUTE = 3;
|
||||
private static final int EXIT = 4;
|
||||
private static final int GETENV = 5;
|
||||
private static final int REMOVE = 6;
|
||||
private static final int RENAME = 7;
|
||||
private static final int SETLOCALE = 8;
|
||||
private static final int TIME = 9;
|
||||
private static final int TMPNAME = 10;
|
||||
|
||||
private static final long t0 = System.currentTimeMillis();
|
||||
private static long tmpnames = t0;
|
||||
|
||||
/**
|
||||
* Create and OsLib instance.
|
||||
*/
|
||||
public OsLib() {
|
||||
String[] NAMES = {
|
||||
"clock",
|
||||
"date",
|
||||
"difftime",
|
||||
"execute",
|
||||
"exit",
|
||||
"getenv",
|
||||
"remove",
|
||||
"rename",
|
||||
"setlocale",
|
||||
"time",
|
||||
"tmpname",
|
||||
};
|
||||
for ( int i=NAMES.length; --i>=0; )
|
||||
set(NAMES[i], new OsFuncV(NAMES[i], i, this));
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "os";
|
||||
}
|
||||
|
||||
private class OsFuncV extends VarArgFunction {
|
||||
public OsFuncV(String name, int opcode, OsLib lib) {
|
||||
super(name, opcode, lib);
|
||||
}
|
||||
public Varargs invoke(Varargs args) {
|
||||
try {
|
||||
switch ( opcode ) {
|
||||
case CLOCK:
|
||||
return valueOf(clock());
|
||||
case DATE: {
|
||||
String s = args.optString(1, null);
|
||||
long t = args.optlong(2,-1);
|
||||
return valueOf( date(s, t==-1? System.currentTimeMillis(): t) );
|
||||
}
|
||||
case DIFFTIME:
|
||||
return valueOf(difftime(args.checklong(1),args.checklong(2)));
|
||||
case EXECUTE:
|
||||
return valueOf(execute(args.optString(1, null)));
|
||||
case EXIT:
|
||||
exit(args.optint(1, 0));
|
||||
return NONE;
|
||||
case GETENV: {
|
||||
final String val = getenv(args.checkString(1));
|
||||
return val!=null? valueOf(val): NIL;
|
||||
}
|
||||
case REMOVE:
|
||||
remove(args.checkString(1));
|
||||
return LuaValue.TRUE;
|
||||
case RENAME:
|
||||
rename(args.checkString(1), args.checkString(2));
|
||||
return LuaValue.TRUE;
|
||||
case SETLOCALE: {
|
||||
String s = setlocale(args.optString(1,null), args.optString(2, "all"));
|
||||
return s!=null? valueOf(s): NIL;
|
||||
}
|
||||
case TIME:
|
||||
return valueOf(time(args.arg1().isnil()? null: args.checktable(1)));
|
||||
case TMPNAME:
|
||||
return valueOf(tmpname());
|
||||
}
|
||||
return NONE;
|
||||
} catch ( IOException e ) {
|
||||
return varargsOf(NIL, valueOf(e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an approximation of the amount in seconds of CPU time used by
|
||||
* the program.
|
||||
*/
|
||||
protected double clock() {
|
||||
return (System.currentTimeMillis()-t0) / 1000.;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of seconds from time t1 to time t2.
|
||||
* In POSIX, Windows, and some other systems, this value is exactly t2-t1.
|
||||
* @param t2
|
||||
* @param t1
|
||||
* @return diffeence in time values, in seconds
|
||||
*/
|
||||
protected double difftime(long t2, long t1) {
|
||||
return (t2 - t1) / 1000.;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the time argument is present, this is the time to be formatted
|
||||
* (see the os.time function for a description of this value).
|
||||
* Otherwise, date formats the current time.
|
||||
*
|
||||
* If format starts with '!', then the date is formatted in Coordinated
|
||||
* Universal Time. After this optional character, if format is the string
|
||||
* "*t", then date returns a table with the following fields: year
|
||||
* (four digits), month (1--12), day (1--31), hour (0--23), min (0--59),
|
||||
* sec (0--61), wday (weekday, Sunday is 1), yday (day of the year),
|
||||
* and isdst (daylight saving flag, a boolean).
|
||||
*
|
||||
* If format is not "*t", then date returns the date as a string,
|
||||
* formatted according to the same rules as the C function strftime.
|
||||
*
|
||||
* When called without arguments, date returns a reasonable date and
|
||||
* time representation that depends on the host system and on the
|
||||
* current locale (that is, os.date() is equivalent to os.date("%c")).
|
||||
*
|
||||
* @param format
|
||||
* @param time time since epoch, or -1 if not supplied
|
||||
* @return a LString or a LTable containing date and time,
|
||||
* formatted according to the given string format.
|
||||
*/
|
||||
protected String date(String format, long time) {
|
||||
return new java.util.Date(time).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is equivalent to the C function system.
|
||||
* It passes command to be executed by an operating system shell.
|
||||
* It returns a status code, which is system-dependent.
|
||||
* If command is absent, then it returns nonzero if a shell
|
||||
* is available and zero otherwise.
|
||||
* @param command command to pass to the system
|
||||
*/
|
||||
protected int execute(String command) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the C function exit, with an optional code, to terminate the host program.
|
||||
* @param code
|
||||
*/
|
||||
protected void exit(int code) {
|
||||
System.exit(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the process environment variable varname,
|
||||
* or null if the variable is not defined.
|
||||
* @param varname
|
||||
* @return String value, or null if not defined
|
||||
*/
|
||||
protected String getenv(String varname) {
|
||||
return System.getProperty(varname);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the file or directory with the given name.
|
||||
* Directories must be empty to be removed.
|
||||
* If this function fails, it throws and IOException
|
||||
*
|
||||
* @param filename
|
||||
* @throws IOException if it fails
|
||||
*/
|
||||
protected void remove(String filename) throws IOException {
|
||||
throw new IOException( "not implemented" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames file or directory named oldname to newname.
|
||||
* If this function fails,it throws and IOException
|
||||
*
|
||||
* @param oldname old file name
|
||||
* @param newname new file name
|
||||
* @throws IOException if it fails
|
||||
*/
|
||||
protected void rename(String oldname, String newname) throws IOException {
|
||||
throw new IOException( "not implemented" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current locale of the program. locale is a string specifying
|
||||
* a locale; category is an optional string describing which category to change:
|
||||
* "all", "collate", "ctype", "monetary", "numeric", or "time"; the default category
|
||||
* is "all".
|
||||
*
|
||||
* If locale is the empty string, the current locale is set to an implementation-
|
||||
* defined native locale. If locale is the string "C", the current locale is set
|
||||
* to the standard C locale.
|
||||
*
|
||||
* When called with null as the first argument, this function only returns the
|
||||
* name of the current locale for the given category.
|
||||
*
|
||||
* @param locale
|
||||
* @param category
|
||||
* @return the name of the new locale, or null if the request
|
||||
* cannot be honored.
|
||||
*/
|
||||
protected String setlocale(String locale, String category) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current time when called without arguments,
|
||||
* or a time representing the date and time specified by the given table.
|
||||
* This table must have fields year, month, and day,
|
||||
* and may have fields hour, min, sec, and isdst
|
||||
* (for a description of these fields, see the os.date function).
|
||||
* @param table
|
||||
* @return long value for the time
|
||||
*/
|
||||
protected long time(LuaTable table) {
|
||||
return System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string with a file name that can be used for a temporary file.
|
||||
* The file must be explicitly opened before its use and explicitly removed
|
||||
* when no longer needed.
|
||||
*
|
||||
* On some systems (POSIX), this function also creates a file with that name,
|
||||
* to avoid security risks. (Someone else might create the file with wrong
|
||||
* permissions in the time between getting the name and creating the file.)
|
||||
* You still have to open the file to use it and to remove it (even if you
|
||||
* do not use it).
|
||||
*
|
||||
* @return String filename to use
|
||||
*/
|
||||
protected String tmpname() {
|
||||
return TMP_PREFIX+(tmpnames++)+TMP_SUFFIX;
|
||||
}
|
||||
}
|
||||
366
src/core/org/luaj/vm2/lib/PackageLib.java
Normal file
366
src/core/org/luaj/vm2/lib/PackageLib.java
Normal file
@@ -0,0 +1,366 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 200 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintStream;
|
||||
|
||||
import org.luaj.vm2.LuaFunction;
|
||||
import org.luaj.vm2.LuaThread;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
|
||||
public class PackageLib extends LuaTable {
|
||||
|
||||
public static String DEFAULT_LUA_PATH = "?.lua";
|
||||
|
||||
public LuaValue _G = null;
|
||||
public InputStream STDIN = null;
|
||||
public PrintStream STDOUT = System.out;
|
||||
public LuaTable LOADED = null;
|
||||
public LuaTable PACKAGE = null;
|
||||
|
||||
private static final LuaString _M = LuaString.valueOf("_M");
|
||||
private static final LuaString _NAME = LuaString.valueOf("_NAME");
|
||||
private static final LuaString _PACKAGE = LuaString.valueOf("_PACKAGE");
|
||||
private static final LuaString _DOT = LuaString.valueOf(".");
|
||||
private static final LuaString _LOADERS = LuaString.valueOf("loaders");
|
||||
private static final LuaString _LOADED = LuaString.valueOf("loaded");
|
||||
private static final LuaString _LOADLIB = LuaString.valueOf("loadlib");
|
||||
private static final LuaString _PRELOAD = LuaString.valueOf("preload");
|
||||
private static final LuaString _PATH = LuaString.valueOf("path");
|
||||
private static final LuaString _SEEALL = LuaString.valueOf("seeall");
|
||||
private static final LuaValue _SENTINEL = EMPTYSTRING;
|
||||
|
||||
private static final int MODULE = 1;
|
||||
private static final int REQUIRE = 2;
|
||||
private static final int LOADLIB = 3;
|
||||
private static final int SEEALL = 4;
|
||||
private static final int PRELOAD_LOADER = 5;
|
||||
private static final int LUA_LOADER = 6;
|
||||
private static final int JAVA_LOADER = 7;
|
||||
|
||||
|
||||
public PackageLib(LuaValue _G) {
|
||||
this._G = _G;
|
||||
_G.set( "module", new PackageFuncV(MODULE, "module", _G) );
|
||||
_G.set( "require", new PackageFuncV(REQUIRE, "require",_G) );
|
||||
_G.set( "package", PACKAGE = tableOf( new LuaValue[] {
|
||||
_LOADED, LOADED=tableOf(),
|
||||
_PRELOAD, tableOf(),
|
||||
_PATH, valueOf(DEFAULT_LUA_PATH),
|
||||
_LOADLIB, new PackageFuncV(LOADLIB, "loadlib",_G),
|
||||
_SEEALL, new PackageFuncV(SEEALL, "seeall",_G),
|
||||
_LOADERS, listOf(new LuaValue[] {
|
||||
new PackageFuncV(PRELOAD_LOADER,"preload_loader",_G),
|
||||
new PackageFuncV(LUA_LOADER, "lua_loader",_G),
|
||||
new PackageFuncV(JAVA_LOADER, "java_loader",_G),
|
||||
}),
|
||||
} ) );
|
||||
}
|
||||
|
||||
private class PackageFuncV extends VarArgFunction {
|
||||
public PackageFuncV(int opcode, String name, LuaValue env) {
|
||||
super(name, opcode, env);
|
||||
}
|
||||
public Varargs invoke(Varargs args) {
|
||||
switch ( opcode ) {
|
||||
case MODULE:
|
||||
return module(args);
|
||||
case REQUIRE:
|
||||
return require(args);
|
||||
case LOADLIB:
|
||||
return loadlib(args);
|
||||
case SEEALL: {
|
||||
LuaTable t = args.checktable(1);
|
||||
LuaValue m = t.getmetatable();
|
||||
if ( m == null )
|
||||
t.setmetatable(m=tableOf());
|
||||
m.set( INDEX, env );
|
||||
return NONE;
|
||||
}
|
||||
case PRELOAD_LOADER: {
|
||||
return loader_preload(args);
|
||||
}
|
||||
case LUA_LOADER: {
|
||||
return loader_Lua(args);
|
||||
}
|
||||
case JAVA_LOADER: {
|
||||
return loader_Java(args);
|
||||
}
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/** Allow packages to mark themselves as loaded */
|
||||
public void setIsLoaded(String name, LuaTable value) {
|
||||
LOADED.set(name, value);
|
||||
}
|
||||
|
||||
public void setLuaPath( String newLuaPath ) {
|
||||
PACKAGE.set( _PATH, valueOf(newLuaPath) );
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "package";
|
||||
}
|
||||
|
||||
|
||||
// ======================== Module, Package loading =============================
|
||||
/**
|
||||
* module (name [, ...])
|
||||
*
|
||||
* Creates a module. If there is a table in package.loaded[name], this table
|
||||
* is the module. Otherwise, if there is a global table t with the given
|
||||
* name, this table is the module. Otherwise creates a new table t and sets
|
||||
* it as the value of the global name and the value of package.loaded[name].
|
||||
* This function also initializes t._NAME with the given name, t._M with the
|
||||
* module (t itself), and t._PACKAGE with the package name (the full module
|
||||
* name minus last component; see below). Finally, module sets t as the new
|
||||
* environment of the current function and the new value of
|
||||
* package.loaded[name], so that require returns t.
|
||||
*
|
||||
* If name is a compound name (that is, one with components separated by
|
||||
* dots), module creates (or reuses, if they already exist) tables for each
|
||||
* component. For instance, if name is a.b.c, then module stores the module
|
||||
* table in field c of field b of global a.
|
||||
*
|
||||
* This function may receive optional options after the module name, where
|
||||
* each option is a function to be applied over the module.
|
||||
*/
|
||||
public Varargs module(Varargs args) {
|
||||
LuaString modname = args.checkstring(1);
|
||||
int n = args.narg();
|
||||
LuaValue value = LOADED.get(modname);
|
||||
LuaValue module;
|
||||
if ( ! value.istable() ) { /* not found? */
|
||||
|
||||
/* try global variable (and create one if it does not exist) */
|
||||
module = findtable( _G, modname );
|
||||
if ( module == null )
|
||||
error( "name conflict for module '"+modname+"'" );
|
||||
LOADED.set(modname, module);
|
||||
} else {
|
||||
module = (LuaTable) value;
|
||||
}
|
||||
|
||||
|
||||
/* check whether table already has a _NAME field */
|
||||
LuaValue name = module.get(_NAME);
|
||||
if ( name.isnil() ) {
|
||||
modinit( module, modname );
|
||||
}
|
||||
|
||||
// set the environment of the current function
|
||||
LuaFunction f = LuaThread.getCallstackFunction(0);
|
||||
if ( f == null )
|
||||
error(1, "no calling function");
|
||||
f.setfenv(module);
|
||||
|
||||
// apply the functions
|
||||
for ( int i=2; i<=n; i++ )
|
||||
args.arg(i).call( module );
|
||||
|
||||
// returns no results
|
||||
return NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param table the table at which to start the search
|
||||
* @param fname the name to look up or create, such as "abc.def.ghi"
|
||||
* @return the table for that name, possible a new one, or null if a non-table has that name already.
|
||||
*/
|
||||
private static LuaValue findtable(LuaValue table, LuaString fname) {
|
||||
int b, e=(-1);
|
||||
do {
|
||||
e = fname.indexOf(_DOT, b=e+1 );
|
||||
if ( e < 0 )
|
||||
e = fname.m_length;
|
||||
LuaString key = fname.substring(b, e);
|
||||
LuaValue val = table.get(key);
|
||||
if ( val.isnil() ) { /* no such field? */
|
||||
LuaTable field = new LuaTable(); /* new table for field */
|
||||
table.set(key, field);
|
||||
table = field;
|
||||
} else if ( ! val.istable() ) { /* field has a non-table value? */
|
||||
return NIL;
|
||||
} else {
|
||||
table = val;
|
||||
}
|
||||
} while ( e < fname.m_length );
|
||||
return table;
|
||||
}
|
||||
|
||||
private static void modinit(LuaValue module, LuaString modname) {
|
||||
/* module._M = module */
|
||||
module.set(_M, module);
|
||||
int e = modname.lastIndexOf(_DOT);
|
||||
module.set(_NAME, modname );
|
||||
module.set(_PACKAGE, (e<0? EMPTYSTRING: modname.substring(0,e+1)) );
|
||||
}
|
||||
|
||||
/**
|
||||
* require (modname)
|
||||
*
|
||||
* Loads the given module. The function starts by looking into the package.loaded table to
|
||||
* determine whether modname is already loaded. If it is, then require returns the value
|
||||
* stored at package.loaded[modname]. Otherwise, it tries to find a loader for the module.
|
||||
*
|
||||
* To find a loader, require is guided by the package.loaders array. By changing this array,
|
||||
* we can change how require looks for a module. The following explanation is based on the
|
||||
* default configuration for package.loaders.
|
||||
*
|
||||
* First require queries package.preload[modname]. If it has a value, this value
|
||||
* (which should be a function) is the loader. Otherwise require searches for a Lua loader
|
||||
* using the path stored in package.path. If that also fails, it searches for a C loader
|
||||
* using the path stored in package.cpath. If that also fails, it tries an all-in-one loader
|
||||
* (see package.loaders).
|
||||
*
|
||||
* Once a loader is found, require calls the loader with a single argument, modname.
|
||||
* If the loader returns any value, require assigns the returned value to package.loaded[modname].
|
||||
* If the loader returns no value and has not assigned any value to package.loaded[modname],
|
||||
* then require assigns true to this entry. In any case, require returns the final value of
|
||||
* package.loaded[modname].
|
||||
*
|
||||
* If there is any error loading or running the module, or if it cannot find any loader for
|
||||
* the module, then require signals an error.
|
||||
*/
|
||||
public Varargs require( Varargs args ) {
|
||||
LuaString name = args.checkstring(1);
|
||||
LuaValue loaded = LOADED.get(name);
|
||||
if ( loaded.toboolean() ) {
|
||||
if ( loaded == _SENTINEL )
|
||||
error("loop or previous error loading module '"+name+"'");
|
||||
return loaded;
|
||||
}
|
||||
|
||||
/* else must load it; iterate over available loaders */
|
||||
LuaTable tbl = PACKAGE.get(_LOADERS).checktable();
|
||||
StringBuffer sb = new StringBuffer();
|
||||
LuaValue chunk = null;
|
||||
for ( int i=1; true; i++ ) {
|
||||
LuaValue loader = tbl.get(i);
|
||||
if ( loader.isnil() ) {
|
||||
error( "module '"+name+"' not found: "+name+"\n"+sb );
|
||||
}
|
||||
|
||||
/* call loader with module name as argument */
|
||||
chunk = loader.call(name);
|
||||
if ( chunk.isfunction() )
|
||||
break;
|
||||
if ( chunk.isstring() )
|
||||
sb.append( chunk.toString() );
|
||||
}
|
||||
|
||||
// load the module using the loader
|
||||
LOADED.set(name, _SENTINEL);
|
||||
LuaValue result = chunk.call(name);
|
||||
if ( ! result.isnil() )
|
||||
LOADED.set( name, result );
|
||||
else if ( LOADED.get(name) == _SENTINEL )
|
||||
LOADED.set( name, result = LuaValue.TRUE );
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Varargs loadlib( Varargs args ) {
|
||||
return varargsOf(NIL, valueOf("dynamic libraries not enabled"), valueOf("absent"));
|
||||
}
|
||||
|
||||
private LuaValue loader_preload( Varargs args ) {
|
||||
LuaString name = args.checkstring(1);
|
||||
LuaValue preload = PACKAGE.get(_PRELOAD).checktable();
|
||||
LuaValue val = preload.get(name);
|
||||
return val.isnil()?
|
||||
valueOf("\n\tno field package.preload['"+name+"']"):
|
||||
val;
|
||||
}
|
||||
|
||||
private LuaValue loader_Lua( Varargs args ) {
|
||||
String name = args.checkString(1);
|
||||
InputStream is = null;
|
||||
|
||||
// try to use loadfile for the file
|
||||
LuaValue loadfile = _G.get("loadfile");
|
||||
if ( ! loadfile.isfunction() )
|
||||
return valueOf("loadfile is not a function" );
|
||||
|
||||
|
||||
// get package path
|
||||
LuaValue pp = PACKAGE.get(_PATH);
|
||||
if ( ! pp.isstring() )
|
||||
return valueOf("package.path is not a string");
|
||||
String path = pp.toString();
|
||||
|
||||
// check the path elements
|
||||
int e = -1;
|
||||
int n = path.length();
|
||||
StringBuffer sb = null;
|
||||
name = name.replace('.','/');
|
||||
while ( e < n ) {
|
||||
|
||||
// find next template
|
||||
int b = e+1;
|
||||
e = path.indexOf(';',b);
|
||||
if ( e < 0 )
|
||||
e = path.length();
|
||||
String template = path.substring(b,e);
|
||||
|
||||
// create filename
|
||||
int q = template.indexOf('?');
|
||||
String filename = template;
|
||||
if ( q >= 0 ) {
|
||||
filename = template.substring(0,q) + name + template.substring(q+1);
|
||||
}
|
||||
|
||||
// try loading the file
|
||||
Varargs v = loadfile.invoke(valueOf(filename));
|
||||
if ( v.arg1().isfunction() )
|
||||
return v.arg1();
|
||||
|
||||
// report error
|
||||
if ( sb == null )
|
||||
sb = new StringBuffer();
|
||||
sb.append( "\n\t'"+filename+"': "+v.arg(2) );
|
||||
}
|
||||
return valueOf(sb.toString());
|
||||
}
|
||||
|
||||
private LuaValue loader_Java( Varargs args ) {
|
||||
String name = args.checkString(1);
|
||||
Class c = null;
|
||||
LuaValue v = null;
|
||||
try {
|
||||
c = Class.forName(name);
|
||||
v = (LuaValue) c.newInstance();
|
||||
return v;
|
||||
} catch ( ClassNotFoundException cnfe ) {
|
||||
return valueOf("\n\tno class '"+name+"'" );
|
||||
} catch ( Exception e ) {
|
||||
return valueOf("\n\tjava load failed on '"+name+"', "+e );
|
||||
}
|
||||
}
|
||||
}
|
||||
50
src/core/org/luaj/vm2/lib/ResourceFinder.java
Normal file
50
src/core/org/luaj/vm2/lib/ResourceFinder.java
Normal file
@@ -0,0 +1,50 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Interface for opening application resource files such as scripts sources.
|
||||
*
|
||||
* This is used by required to load files that are part of
|
||||
* the application, and implemented by BaseLib
|
||||
* for both the Jme and Jse platforms.
|
||||
*
|
||||
* The Jme version implements FileOpener via getResourceAsStream(),
|
||||
* while the Jse version implements it using new File().
|
||||
*
|
||||
* The io library does not use this API for file manipulation.
|
||||
*/
|
||||
public interface ResourceFinder {
|
||||
|
||||
/**
|
||||
* Try to open a file, or return null if not found.
|
||||
*
|
||||
* @see org.luaj.vm2.lib.BaseLib
|
||||
* @see org.luaj.vm2.lib.jse.JseBaseLib
|
||||
*
|
||||
* @param filename
|
||||
* @return InputStream, or null if not found.
|
||||
*/
|
||||
public InputStream findResource( String filename );
|
||||
}
|
||||
1139
src/core/org/luaj/vm2/lib/StringLib.java
Normal file
1139
src/core/org/luaj/vm2/lib/StringLib.java
Normal file
File diff suppressed because it is too large
Load Diff
93
src/core/org/luaj/vm2/lib/TableLib.java
Normal file
93
src/core/org/luaj/vm2/lib/TableLib.java
Normal file
@@ -0,0 +1,93 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib;
|
||||
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
public class TableLib extends LuaTable {
|
||||
|
||||
public TableLib() {
|
||||
LibFunction.bind( this, new TableFunc1().getClass(), new String[] {
|
||||
"getn", // (table) -> number
|
||||
"maxn", // (table) -> number
|
||||
} );
|
||||
LibFunction.bind( this, new TableFuncV().getClass(), new String[] {
|
||||
"remove", // (table [, pos]) -> removed-ele
|
||||
"concat", // (table [, sep [, i [, j]]]) -> string
|
||||
"insert", // (table, [pos,] value) -> prev-ele
|
||||
"sort", // (table [, comp]) -> void
|
||||
"foreach", // (table, func) -> void
|
||||
"foreachi", // (table, func) -> void
|
||||
} );
|
||||
}
|
||||
|
||||
public static class TableFunc1 extends OneArgFunction {
|
||||
public LuaValue call(LuaValue arg) {
|
||||
switch ( opcode ) {
|
||||
case 0: return arg.checktable().getn();
|
||||
case 1: return valueOf( arg.checktable().maxn());
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static class TableFuncV extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
switch ( opcode ) {
|
||||
case 0: { // "remove" (table [, pos]) -> removed-ele
|
||||
LuaTable table = args.checktable(1);
|
||||
int pos = args.narg()>1? args.checkint(2): 0;
|
||||
return table.remove(pos);
|
||||
}
|
||||
case 1: { // "concat" (table [, sep [, i [, j]]]) -> string
|
||||
LuaTable table = args.checktable(1);
|
||||
return table.concat(
|
||||
args.optstring(2,LuaValue.EMPTYSTRING),
|
||||
args.optint(3,1),
|
||||
args.isvalue(4)? args.checkint(4): table.length() );
|
||||
}
|
||||
case 2: { // "insert" (table, [pos,] value) -> prev-ele
|
||||
final LuaTable table = args.checktable(1);
|
||||
final int pos = args.narg()>2? args.checkint(2): 0;
|
||||
final LuaValue value = args.arg( args.narg()>2? 3: 2 );
|
||||
table.insert( pos, value );
|
||||
return NONE;
|
||||
}
|
||||
case 3: { // "sort" (table [, comp]) -> void
|
||||
args.checktable(1).sort( args.optvalue(2,NIL) );
|
||||
return NONE;
|
||||
}
|
||||
case 4: { // (table, func) -> void
|
||||
return args.checktable(1).foreach( args.checkfunction(2) );
|
||||
}
|
||||
case 5: { // "foreachi" (table, func) -> void
|
||||
return args.checktable(1).foreachi( args.checkfunction(2) );
|
||||
}
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
58
src/core/org/luaj/vm2/lib/ThreeArgFunction.java
Normal file
58
src/core/org/luaj/vm2/lib/ThreeArgFunction.java
Normal file
@@ -0,0 +1,58 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
abstract public class ThreeArgFunction extends LibFunction {
|
||||
|
||||
abstract public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3);
|
||||
|
||||
public ThreeArgFunction() {
|
||||
}
|
||||
|
||||
public ThreeArgFunction( LuaValue env ) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public ThreeArgFunction( String name, int opcode, LuaValue env ) {
|
||||
super(name, opcode, env);
|
||||
}
|
||||
|
||||
public final LuaValue call() {
|
||||
return call(NIL, NIL, NIL);
|
||||
}
|
||||
|
||||
public final LuaValue call(LuaValue arg) {
|
||||
return call(arg, NIL, NIL);
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return call(arg1, arg2, NIL);
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs varargs) {
|
||||
return call(varargs.arg1(),varargs.arg(2),varargs.arg(3));
|
||||
}
|
||||
|
||||
}
|
||||
58
src/core/org/luaj/vm2/lib/TwoArgFunction.java
Normal file
58
src/core/org/luaj/vm2/lib/TwoArgFunction.java
Normal file
@@ -0,0 +1,58 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
abstract public class TwoArgFunction extends LibFunction {
|
||||
|
||||
abstract public LuaValue call(LuaValue arg1, LuaValue arg2);
|
||||
|
||||
public TwoArgFunction() {
|
||||
}
|
||||
|
||||
public TwoArgFunction( LuaValue env ) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public TwoArgFunction( String name, int opcode, LuaValue env ) {
|
||||
super(name, opcode, env);
|
||||
}
|
||||
|
||||
public final LuaValue call() {
|
||||
return call(NIL, NIL);
|
||||
}
|
||||
|
||||
public final LuaValue call(LuaValue arg) {
|
||||
return call(arg, NIL);
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
|
||||
return call(arg1, arg2);
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs varargs) {
|
||||
return call(varargs.arg1(),varargs.arg(2));
|
||||
}
|
||||
|
||||
}
|
||||
57
src/core/org/luaj/vm2/lib/VarArgFunction.java
Normal file
57
src/core/org/luaj/vm2/lib/VarArgFunction.java
Normal file
@@ -0,0 +1,57 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
abstract public class VarArgFunction extends LibFunction {
|
||||
|
||||
abstract public Varargs invoke(Varargs args);
|
||||
|
||||
public VarArgFunction() {
|
||||
}
|
||||
|
||||
public VarArgFunction( LuaValue env ) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public VarArgFunction( String name, int opcode, LuaValue env ) {
|
||||
super(name, opcode, env);
|
||||
}
|
||||
|
||||
public final LuaValue call() {
|
||||
return invoke(NONE).arg1();
|
||||
}
|
||||
|
||||
public final LuaValue call(LuaValue arg) {
|
||||
return invoke(arg).arg1();
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return invoke(varargsOf(arg1,arg2)).arg1();
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
|
||||
return invoke(varargsOf(arg1,arg2,arg3)).arg1();
|
||||
}
|
||||
}
|
||||
57
src/core/org/luaj/vm2/lib/ZeroArgFunction.java
Normal file
57
src/core/org/luaj/vm2/lib/ZeroArgFunction.java
Normal file
@@ -0,0 +1,57 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
abstract public class ZeroArgFunction extends LibFunction {
|
||||
|
||||
abstract public LuaValue call();
|
||||
|
||||
public ZeroArgFunction() {
|
||||
}
|
||||
|
||||
public ZeroArgFunction( LuaValue env ) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public ZeroArgFunction( String name, int opcode, LuaValue env ) {
|
||||
super(name, opcode, env);
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return call();
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return call();
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
|
||||
return call();
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs varargs) {
|
||||
return call();
|
||||
}
|
||||
}
|
||||
45
src/jme/org/luaj/vm2/lib/JmePlatform.java
Normal file
45
src/jme/org/luaj/vm2/lib/JmePlatform.java
Normal file
@@ -0,0 +1,45 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib;
|
||||
|
||||
import org.luaj.vm2.LuaTable;
|
||||
|
||||
public class JmePlatform {
|
||||
|
||||
/**
|
||||
* Create a standard set of globals for JME including all the libraries.
|
||||
*
|
||||
* @return Table of globals initialized with the standard JME libraries
|
||||
*/
|
||||
public static LuaTable standardGlobals() {
|
||||
LuaTable _G = new BaseLib();
|
||||
new org.luaj.vm2.lib.PackageLib(_G);
|
||||
_G.set( "io", new org.luaj.vm2.lib.jme.JseIoLib() );
|
||||
_G.set( "math", new org.luaj.vm2.lib.MathLib() );
|
||||
_G.set( "os", new org.luaj.vm2.lib.OsLib() );
|
||||
_G.set( "table", new org.luaj.vm2.lib.TableLib() );
|
||||
_G.set( "string", new org.luaj.vm2.lib.StringLib() );
|
||||
CoroutineLib.install( _G );
|
||||
return _G;
|
||||
}
|
||||
|
||||
}
|
||||
199
src/jme/org/luaj/vm2/lib/jme/JseIoLib.java
Normal file
199
src/jme/org/luaj/vm2/lib/jme/JseIoLib.java
Normal file
@@ -0,0 +1,199 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib.jme;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import javax.microedition.io.Connector;
|
||||
import javax.microedition.io.StreamConnection;
|
||||
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.lib.BaseLib;
|
||||
import org.luaj.vm2.lib.IoLib;
|
||||
|
||||
/**
|
||||
* Implementation of the lua io library based on CLDC 1.0 and StreamConnection.
|
||||
*
|
||||
* Seek is not supported.
|
||||
*/
|
||||
public class JseIoLib extends IoLib {
|
||||
|
||||
public JseIoLib() {
|
||||
super();
|
||||
}
|
||||
|
||||
protected File wrapStdin() throws IOException {
|
||||
return new FileImpl(BaseLib.STDIN);
|
||||
}
|
||||
|
||||
protected File wrapStdout() throws IOException {
|
||||
return new FileImpl(BaseLib.STDOUT);
|
||||
}
|
||||
|
||||
protected File openFile( String filename, boolean readMode, boolean appendMode, boolean updateMode, boolean binaryMode ) throws IOException {
|
||||
String url = "file:///" + filename;
|
||||
int mode = readMode? Connector.READ: Connector.READ_WRITE;
|
||||
StreamConnection conn = (StreamConnection) Connector.open( url, mode );
|
||||
File f = readMode?
|
||||
new FileImpl(conn, conn.openInputStream(), null):
|
||||
new FileImpl(conn, conn.openInputStream(), conn.openOutputStream());
|
||||
/*
|
||||
if ( appendMode ) {
|
||||
f.seek("end",0);
|
||||
} else {
|
||||
if ( ! readMode )
|
||||
conn.truncate(0);
|
||||
}
|
||||
*/
|
||||
return f;
|
||||
}
|
||||
|
||||
private static void notimplemented() throws IOException {
|
||||
throw new IOException("not implemented");
|
||||
}
|
||||
|
||||
protected File openProgram(String prog, String mode) throws IOException {
|
||||
notimplemented();
|
||||
return null;
|
||||
}
|
||||
|
||||
protected File tmpFile() throws IOException {
|
||||
notimplemented();
|
||||
return null;
|
||||
}
|
||||
|
||||
private final class FileImpl extends File {
|
||||
private final StreamConnection conn;
|
||||
private final InputStream is;
|
||||
private final OutputStream os;
|
||||
private boolean closed = false;
|
||||
private boolean nobuffer = false;
|
||||
private int lookahead = -1;
|
||||
private FileImpl( StreamConnection conn, InputStream is, OutputStream os ) {
|
||||
this.conn = conn;
|
||||
this.is = is;
|
||||
this.os = os;
|
||||
}
|
||||
private FileImpl( InputStream i ) {
|
||||
this( null, i, null );
|
||||
}
|
||||
private FileImpl( OutputStream o ) {
|
||||
this( null, null, o );
|
||||
}
|
||||
public String toString() {
|
||||
return "file ("+this.hashCode()+")";
|
||||
}
|
||||
public boolean isstdfile() {
|
||||
return conn == null;
|
||||
}
|
||||
public void close() throws IOException {
|
||||
closed = true;
|
||||
if ( conn != null ) {
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
public void flush() throws IOException {
|
||||
if ( os != null )
|
||||
os.flush();
|
||||
}
|
||||
public void write(LuaString s) throws IOException {
|
||||
if ( os != null )
|
||||
os.write( s.m_bytes, s.m_offset, s.m_length );
|
||||
else
|
||||
notimplemented();
|
||||
if ( nobuffer )
|
||||
flush();
|
||||
}
|
||||
public boolean isclosed() {
|
||||
return closed;
|
||||
}
|
||||
public int seek(String option, int pos) throws IOException {
|
||||
/*
|
||||
if ( conn != null ) {
|
||||
if ( "set".equals(option) ) {
|
||||
conn.seek(pos);
|
||||
return (int) conn.getFilePointer();
|
||||
} else if ( "end".equals(option) ) {
|
||||
conn.seek(conn.length()+1+pos);
|
||||
return (int) conn.length()+1;
|
||||
} else {
|
||||
conn.seek(conn.getFilePointer()+pos);
|
||||
return (int) conn.getFilePointer();
|
||||
}
|
||||
}
|
||||
*/
|
||||
notimplemented();
|
||||
return 0;
|
||||
}
|
||||
public void setvbuf(String mode, int size) {
|
||||
nobuffer = "no".equals(mode);
|
||||
}
|
||||
|
||||
// get length remaining to read
|
||||
public int remaining() throws IOException {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// peek ahead one character
|
||||
public int peek() throws IOException {
|
||||
if ( lookahead < 0 )
|
||||
lookahead = is.read();
|
||||
return lookahead;
|
||||
}
|
||||
|
||||
// return char if read, -1 if eof, throw IOException on other exception
|
||||
public int read() throws IOException {
|
||||
if ( lookahead >= 0 ) {
|
||||
int c = lookahead;
|
||||
lookahead = -1;
|
||||
return c;
|
||||
}
|
||||
if ( is != null )
|
||||
return is.read();
|
||||
notimplemented();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// return number of bytes read if positive, -1 if eof, throws IOException
|
||||
public int read(byte[] bytes, int offset, int length) throws IOException {
|
||||
int n,i=0;
|
||||
if (is!=null) {
|
||||
if ( length > 0 && lookahead >= 0 ) {
|
||||
bytes[offset] = (byte) lookahead;
|
||||
lookahead = -1;
|
||||
i += 1;
|
||||
}
|
||||
for ( ; i<length; ) {
|
||||
n = is.read(bytes, offset+i, length-i);
|
||||
if ( n < 0 )
|
||||
return ( i > 0 ? i : -1 );
|
||||
i += n;
|
||||
}
|
||||
} else {
|
||||
notimplemented();
|
||||
}
|
||||
return length;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
org.luaj.vm2.script.LuaScriptEngineFactory
|
||||
199
src/jse/lua.java
Normal file
199
src/jse/lua.java
Normal file
@@ -0,0 +1,199 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
import org.luaj.vm2.LoadState;
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.LuaClosure;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
import org.luaj.vm2.lib.DebugLib;
|
||||
import org.luaj.vm2.lib.JsePlatform;
|
||||
|
||||
|
||||
/**
|
||||
* lua command for use in java se environments.
|
||||
*/
|
||||
public class lua {
|
||||
private static final String version = Lua._VERSION + "Copyright (c) 2009 Luaj.org.org";
|
||||
|
||||
private static final String usage =
|
||||
"usage: java -cp luaj-jse.jar lua [options] [script [args]].\n" +
|
||||
"Available options are:\n" +
|
||||
" -e stat execute string 'stat'\n" +
|
||||
" -l name require library 'name'\n" +
|
||||
" -i enter interactive mode after executing 'script'\n" +
|
||||
" -v show version information\n" +
|
||||
" -- stop handling options\n" +
|
||||
" - execute stdin and stop handling options";
|
||||
|
||||
private static void usageExit() {
|
||||
System.out.println(usage);
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
private static LuaValue _G;
|
||||
|
||||
public static void main( String[] args ) throws IOException {
|
||||
|
||||
// new lua state
|
||||
LuaC.install();
|
||||
_G = JsePlatform.standardGlobals();
|
||||
DebugLib.install( _G );
|
||||
|
||||
// process args
|
||||
boolean interactive = (args.length == 0);
|
||||
boolean versioninfo = false;
|
||||
boolean processing = true;
|
||||
try {
|
||||
// stateful argument processing
|
||||
for ( int i=0; i<args.length; i++ ) {
|
||||
if ( ! processing || ! args[i].startsWith("-") ) {
|
||||
// input file - defer to last stage
|
||||
break;
|
||||
} else if ( args[i].length() <= 1 ) {
|
||||
// input file - defer to last stage
|
||||
break;
|
||||
} else {
|
||||
switch ( args[i].charAt(1) ) {
|
||||
case 'e':
|
||||
if ( ++i >= args.length )
|
||||
usageExit();
|
||||
// input script - defer to last stage
|
||||
break;
|
||||
case 'l':
|
||||
if ( ++i >= args.length )
|
||||
usageExit();
|
||||
loadLibrary( args[i] );
|
||||
break;
|
||||
case 'i':
|
||||
interactive = true;
|
||||
break;
|
||||
case 'v':
|
||||
versioninfo = true;
|
||||
break;
|
||||
case '-':
|
||||
if ( args[i].length() > 2 )
|
||||
usageExit();
|
||||
processing = false;
|
||||
break;
|
||||
default:
|
||||
usageExit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// echo version
|
||||
if ( versioninfo )
|
||||
System.out.println(version);
|
||||
|
||||
// input script processing
|
||||
processing = true;
|
||||
for ( int i=0; i<args.length; i++ ) {
|
||||
if ( ! processing || ! args[i].startsWith("-") ) {
|
||||
processScript( new FileInputStream(args[i]), args[i], args, i+1 );
|
||||
break;
|
||||
} else if ( args[i].length() <= 1 ) {
|
||||
processScript( System.in, "-", args, i+1 );
|
||||
break;
|
||||
} else {
|
||||
switch ( args[i].charAt(1) ) {
|
||||
case 'l':
|
||||
++i;
|
||||
break;
|
||||
case 'e':
|
||||
++i;
|
||||
processScript( new ByteArrayInputStream(args[i].getBytes()), args[i], null, 0 );
|
||||
break;
|
||||
case '-':
|
||||
processing = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( interactive )
|
||||
interactiveMode();
|
||||
|
||||
} catch ( IOException ioe ) {
|
||||
System.err.println( ioe.toString() );
|
||||
System.exit(-2);
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadLibrary( String libname ) throws IOException {
|
||||
LuaValue slibname =LuaValue.valueOf(libname);
|
||||
try {
|
||||
// load via plain require
|
||||
_G.get("require").call(slibname);
|
||||
} catch ( Exception e ) {
|
||||
try {
|
||||
// load as java class
|
||||
LuaValue v = (LuaValue) Class.forName(libname).newInstance();
|
||||
v.setfenv(_G);
|
||||
v.call(slibname, _G);
|
||||
} catch ( Exception f ) {
|
||||
throw new IOException("loadLibrary("+libname+") failed: "+e+","+f );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void processScript( InputStream script, String chunkname, String[] args, int offset ) throws IOException {
|
||||
try {
|
||||
LuaClosure c;
|
||||
try {
|
||||
Prototype p = LoadState.undump(script, chunkname );
|
||||
c = new LuaClosure(p,_G);
|
||||
} finally {
|
||||
script.close();
|
||||
}
|
||||
LuaValue[] a = new LuaValue[args.length-offset];
|
||||
for ( int i=0; i<a.length; i++ )
|
||||
a[i] = LuaValue.valueOf(args[offset+i]);
|
||||
c.invoke( a );
|
||||
} catch ( Throwable t ) {
|
||||
t.printStackTrace( System.err );
|
||||
}
|
||||
}
|
||||
|
||||
private static final String[] NOARGS = {};
|
||||
|
||||
private static void interactiveMode( ) throws IOException {
|
||||
BufferedReader reader = new BufferedReader( new InputStreamReader( System.in ) );
|
||||
while ( true ) {
|
||||
System.out.print("> ");
|
||||
System.out.flush();
|
||||
String line = reader.readLine();
|
||||
if ( line == null )
|
||||
return;
|
||||
processScript( new ByteArrayInputStream(line.getBytes()), "-", NOARGS, 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
179
src/jse/luac.java
Normal file
179
src/jse/luac.java
Normal file
@@ -0,0 +1,179 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.Print;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.compiler.DumpState;
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
|
||||
|
||||
/**
|
||||
* Compiler for lua files to lua bytecode.
|
||||
*/
|
||||
public class luac {
|
||||
private static final String version = Lua._VERSION + "Copyright (C) 2009 luaj.org";
|
||||
|
||||
private static final String usage =
|
||||
"usage: java -cp luaj-jse.jar luac [options] [filenames].\n" +
|
||||
"Available options are:\n" +
|
||||
" - process stdin\n" +
|
||||
" -l list\n" +
|
||||
" -o name output to file 'name' (default is \"luac.out\")\n" +
|
||||
" -p parse only\n" +
|
||||
" -s strip debug information\n" +
|
||||
" -e little endian format for numbers\n" +
|
||||
" -i<n> number format 'n', (n=0,1 or 4, default="+DumpState.NUMBER_FORMAT_DEFAULT+")\n" +
|
||||
" -v show version information\n" +
|
||||
" -- stop handling options\n";
|
||||
|
||||
private static void usageExit() {
|
||||
System.out.println(usage);
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
private boolean list = false;
|
||||
private String output = "luac.out";
|
||||
private boolean parseonly = false;
|
||||
private boolean stripdebug = false;
|
||||
private boolean littleendian = false;
|
||||
private int numberformat = DumpState.NUMBER_FORMAT_DEFAULT;
|
||||
private boolean versioninfo = false;
|
||||
private boolean processing = true;
|
||||
|
||||
public static void main( String[] args ) throws IOException {
|
||||
new luac( args );
|
||||
}
|
||||
|
||||
private luac( String[] args ) throws IOException {
|
||||
|
||||
// process args
|
||||
try {
|
||||
// get stateful args
|
||||
for ( int i=0; i<args.length; i++ ) {
|
||||
if ( ! processing || ! args[i].startsWith("-") ) {
|
||||
// input file - defer to next stage
|
||||
} else if ( args[i].length() <= 1 ) {
|
||||
// input file - defer to next stage
|
||||
} else {
|
||||
switch ( args[i].charAt(1) ) {
|
||||
case 'l':
|
||||
list = true;
|
||||
break;
|
||||
case 'o':
|
||||
if ( ++i >= args.length )
|
||||
usageExit();
|
||||
output = args[i];
|
||||
break;
|
||||
case 'p':
|
||||
parseonly = true;
|
||||
break;
|
||||
case 's':
|
||||
stripdebug = true;
|
||||
break;
|
||||
case 'e':
|
||||
littleendian = true;
|
||||
break;
|
||||
case 'i':
|
||||
if ( args[i].length() <= 2 )
|
||||
usageExit();
|
||||
numberformat = Integer.parseInt(args[i].substring(2));
|
||||
break;
|
||||
case 'v':
|
||||
versioninfo = true;
|
||||
break;
|
||||
case '-':
|
||||
if ( args[i].length() > 2 )
|
||||
usageExit();
|
||||
processing = false;
|
||||
break;
|
||||
default:
|
||||
usageExit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// echo version
|
||||
if ( versioninfo )
|
||||
System.out.println(version);
|
||||
|
||||
// open output file
|
||||
OutputStream fos = new FileOutputStream( output );
|
||||
|
||||
// process input files
|
||||
try {
|
||||
processing = true;
|
||||
for ( int i=0; i<args.length; i++ ) {
|
||||
if ( ! processing || ! args[i].startsWith("-") ) {
|
||||
String chunkname = args[i].substring(0,args[i].length()-4);
|
||||
processScript( new FileInputStream(args[i]), chunkname, fos );
|
||||
} else if ( args[i].length() <= 1 ) {
|
||||
processScript( System.in, "stdin", fos );
|
||||
} else {
|
||||
switch ( args[i].charAt(1) ) {
|
||||
case 'o':
|
||||
++i;
|
||||
break;
|
||||
case '-':
|
||||
processing = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
fos.close();
|
||||
}
|
||||
|
||||
} catch ( IOException ioe ) {
|
||||
System.err.println( ioe.toString() );
|
||||
System.exit(-2);
|
||||
}
|
||||
}
|
||||
|
||||
private void processScript( InputStream script, String chunkname, OutputStream out ) throws IOException {
|
||||
try {
|
||||
// create the chunk
|
||||
Prototype chunk = LuaC.compile(script, chunkname);
|
||||
|
||||
// list the chunk
|
||||
if (list)
|
||||
Print.printCode(chunk);
|
||||
|
||||
// write out the chunk
|
||||
if (!parseonly) {
|
||||
DumpState.dump(chunk, out, stripdebug, numberformat, littleendian);
|
||||
}
|
||||
|
||||
} catch ( Throwable t ) {
|
||||
t.printStackTrace( System.err );
|
||||
} finally {
|
||||
script.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
179
src/jse/luajc.java
Normal file
179
src/jse/luajc.java
Normal file
@@ -0,0 +1,179 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.compiler.DumpState;
|
||||
import org.luaj.vm2.luajc.antlr.AntlrLuaJCompiler;
|
||||
|
||||
|
||||
/**
|
||||
* Compiler for lua files to compile lua sources into java sources.
|
||||
*/
|
||||
public class luajc {
|
||||
private static final String version = Lua._VERSION + "Copyright (C) 2009 luaj.org";
|
||||
|
||||
private static final String usage =
|
||||
"usage: java -cp luaj-jse.jar,antlr-3.1.3.jar luajc [options] [filenames].\n" +
|
||||
"Available options are:\n" +
|
||||
" - process stdin\n" +
|
||||
" -l list\n" +
|
||||
" -o name output to file 'name' (default is \"luac.out\")\n" +
|
||||
" -p parse only\n" +
|
||||
" -s strip debug information\n" +
|
||||
" -e little endian format for numbers\n" +
|
||||
" -i<n> number format 'n', (n=0,1 or 4, default="+DumpState.NUMBER_FORMAT_DEFAULT+")\n" +
|
||||
" -v show version information\n" +
|
||||
" -- stop handling options\n";
|
||||
|
||||
private static void usageExit() {
|
||||
System.out.println(usage);
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
private boolean list = false;
|
||||
private String output = "luacj.out";
|
||||
private boolean parseonly = false;
|
||||
private boolean stripdebug = false;
|
||||
private boolean littleendian = false;
|
||||
private int numberformat = DumpState.NUMBER_FORMAT_DEFAULT;
|
||||
private boolean versioninfo = false;
|
||||
private boolean processing = true;
|
||||
|
||||
public static void main( String[] args ) throws IOException {
|
||||
new luajc( args );
|
||||
}
|
||||
|
||||
private luajc( String[] args ) throws IOException {
|
||||
|
||||
// process args
|
||||
try {
|
||||
// get stateful args
|
||||
for ( int i=0; i<args.length; i++ ) {
|
||||
if ( ! processing || ! args[i].startsWith("-") ) {
|
||||
// input file - defer to next stage
|
||||
} else if ( args[i].length() <= 1 ) {
|
||||
// input file - defer to next stage
|
||||
} else {
|
||||
switch ( args[i].charAt(1) ) {
|
||||
case 'l':
|
||||
list = true;
|
||||
break;
|
||||
case 'o':
|
||||
if ( ++i >= args.length )
|
||||
usageExit();
|
||||
output = args[i];
|
||||
break;
|
||||
case 'p':
|
||||
parseonly = true;
|
||||
break;
|
||||
case 's':
|
||||
stripdebug = true;
|
||||
break;
|
||||
case 'e':
|
||||
littleendian = true;
|
||||
break;
|
||||
case 'i':
|
||||
if ( args[i].length() <= 2 )
|
||||
usageExit();
|
||||
numberformat = Integer.parseInt(args[i].substring(2));
|
||||
break;
|
||||
case 'v':
|
||||
versioninfo = true;
|
||||
break;
|
||||
case '-':
|
||||
if ( args[i].length() > 2 )
|
||||
usageExit();
|
||||
processing = false;
|
||||
break;
|
||||
default:
|
||||
usageExit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// echo version
|
||||
if ( versioninfo )
|
||||
System.out.println(version);
|
||||
|
||||
// open output file
|
||||
OutputStream fos = new FileOutputStream( output );
|
||||
|
||||
// process input files
|
||||
try {
|
||||
processing = true;
|
||||
for ( int i=0; i<args.length; i++ ) {
|
||||
if ( ! processing || ! args[i].startsWith("-") ) {
|
||||
String chunkname = args[i].substring(0,args[i].length()-4);
|
||||
processScript( new FileInputStream(args[i]), chunkname, fos );
|
||||
} else if ( args[i].length() <= 1 ) {
|
||||
processScript( System.in, "stdin", fos );
|
||||
} else {
|
||||
switch ( args[i].charAt(1) ) {
|
||||
case 'o':
|
||||
++i;
|
||||
break;
|
||||
case '-':
|
||||
processing = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
fos.close();
|
||||
}
|
||||
|
||||
} catch ( IOException ioe ) {
|
||||
System.err.println( ioe.toString() );
|
||||
System.exit(-2);
|
||||
}
|
||||
}
|
||||
|
||||
private void processScript( InputStream script, String chunkname, OutputStream out ) throws IOException {
|
||||
try {
|
||||
// create the chunk
|
||||
String source = AntlrLuaJCompiler.compile(script, chunkname);
|
||||
|
||||
// list the chunk
|
||||
if (list)
|
||||
System.out.println(source);
|
||||
|
||||
// write out the chunk
|
||||
if (!parseonly) {
|
||||
FileOutputStream fos = new FileOutputStream( chunkname+".java" );
|
||||
fos.write( source.getBytes() );
|
||||
fos.close();
|
||||
}
|
||||
|
||||
} catch ( Throwable t ) {
|
||||
t.printStackTrace( System.err );
|
||||
} finally {
|
||||
script.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
52
src/jse/org/luaj/vm2/lib/JsePlatform.java
Normal file
52
src/jse/org/luaj/vm2/lib/JsePlatform.java
Normal file
@@ -0,0 +1,52 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib;
|
||||
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.lib.CoroutineLib;
|
||||
import org.luaj.vm2.lib.jse.JseBaseLib;
|
||||
import org.luaj.vm2.lib.jse.JseIoLib;
|
||||
import org.luaj.vm2.lib.jse.JseMathLib;
|
||||
import org.luaj.vm2.lib.jse.JseOsLib;
|
||||
import org.luaj.vm2.lib.jse.LuajavaLib;
|
||||
|
||||
public class JsePlatform {
|
||||
|
||||
/**
|
||||
* Create a standard set of globals for JSE including all the libraries.
|
||||
*
|
||||
* @return Table of globals initialized with the standard JSE libraries
|
||||
*/
|
||||
public static LuaTable standardGlobals() {
|
||||
LuaTable _G = new JseBaseLib();
|
||||
new org.luaj.vm2.lib.PackageLib(_G);
|
||||
_G.set( "io", new org.luaj.vm2.lib.jse.JseIoLib() );
|
||||
_G.set( "math", new org.luaj.vm2.lib.jse.JseMathLib() );
|
||||
_G.set( "os", new org.luaj.vm2.lib.jse.JseOsLib() );
|
||||
_G.set( "table", new org.luaj.vm2.lib.TableLib() );
|
||||
_G.set( "string", new org.luaj.vm2.lib.StringLib() );
|
||||
_G.set( "luajava", new org.luaj.vm2.lib.jse.LuajavaLib() );
|
||||
CoroutineLib.install(_G);
|
||||
return _G;
|
||||
}
|
||||
|
||||
}
|
||||
91
src/jse/org/luaj/vm2/lib/jse/CoerceJavaToLua.java
Normal file
91
src/jse/org/luaj/vm2/lib/jse/CoerceJavaToLua.java
Normal file
@@ -0,0 +1,91 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.luaj.vm2.LuaDouble;
|
||||
import org.luaj.vm2.LuaInteger;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
|
||||
public class CoerceJavaToLua {
|
||||
|
||||
public static interface Coercion {
|
||||
public LuaValue coerce( Object javaValue );
|
||||
};
|
||||
|
||||
private static Map COERCIONS = new HashMap();
|
||||
|
||||
static {
|
||||
Coercion boolCoercion = new Coercion() {
|
||||
public LuaValue coerce( Object javaValue ) {
|
||||
Boolean b = (Boolean) javaValue;
|
||||
return b.booleanValue()? LuaValue.TRUE: LuaValue.FALSE;
|
||||
}
|
||||
} ;
|
||||
Coercion intCoercion = new Coercion() {
|
||||
public LuaValue coerce( Object javaValue ) {
|
||||
Number n = (Number) javaValue;
|
||||
return LuaInteger.valueOf( n.intValue() );
|
||||
}
|
||||
} ;
|
||||
Coercion charCoercion = new Coercion() {
|
||||
public LuaValue coerce( Object javaValue ) {
|
||||
Character c = (Character) javaValue;
|
||||
return LuaInteger.valueOf( c.charValue() );
|
||||
}
|
||||
} ;
|
||||
Coercion doubleCoercion = new Coercion() {
|
||||
public LuaValue coerce( Object javaValue ) {
|
||||
Number n = (Number) javaValue;
|
||||
return LuaDouble.valueOf( n.doubleValue() );
|
||||
}
|
||||
} ;
|
||||
Coercion stringCoercion = new Coercion() {
|
||||
public LuaValue coerce( Object javaValue ) {
|
||||
return LuaString.valueOf( javaValue.toString() );
|
||||
}
|
||||
} ;
|
||||
COERCIONS.put( Boolean.class, boolCoercion );
|
||||
COERCIONS.put( Byte.class, intCoercion );
|
||||
COERCIONS.put( Character.class, charCoercion );
|
||||
COERCIONS.put( Short.class, intCoercion );
|
||||
COERCIONS.put( Integer.class, intCoercion );
|
||||
COERCIONS.put( Float.class, doubleCoercion );
|
||||
COERCIONS.put( Double.class, doubleCoercion );
|
||||
COERCIONS.put( String.class, stringCoercion );
|
||||
}
|
||||
|
||||
public static LuaValue coerce(Object o) {
|
||||
if ( o == null )
|
||||
return LuaValue.NIL;
|
||||
Class clazz = o.getClass();
|
||||
Coercion c = (Coercion) COERCIONS.get( clazz );
|
||||
if ( c != null )
|
||||
return c.coerce( o );
|
||||
return LuajavaLib.toUserdata( o, clazz );
|
||||
}
|
||||
|
||||
}
|
||||
262
src/jse/org/luaj/vm2/lib/jse/CoerceLuaToJava.java
Normal file
262
src/jse/org/luaj/vm2/lib/jse/CoerceLuaToJava.java
Normal file
@@ -0,0 +1,262 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
|
||||
public class CoerceLuaToJava {
|
||||
|
||||
public static interface Coercion {
|
||||
public Object coerce( LuaValue value );
|
||||
public int score( LuaValue value );
|
||||
};
|
||||
|
||||
private static Map COERCIONS = new HashMap();
|
||||
private static Coercion OBJECT_COERCION;
|
||||
|
||||
static {
|
||||
Coercion boolCoercion = new Coercion() {
|
||||
public Object coerce(LuaValue value) {
|
||||
return value.toboolean()? Boolean.TRUE: Boolean.FALSE;
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TNIL:
|
||||
case LuaValue.TBOOLEAN:
|
||||
return 0;
|
||||
case LuaValue.TNUMBER:
|
||||
return 1;
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
};
|
||||
Coercion byteCoercion = new Coercion() {
|
||||
public Object coerce(LuaValue value) {
|
||||
return new Byte( (byte) value.toint() );
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TNUMBER:
|
||||
return (value.isinttype()? 1: 2);
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
};
|
||||
Coercion charCoercion = new Coercion() {
|
||||
public Object coerce(LuaValue value) {
|
||||
return new Character( (char) value.toint() );
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TNUMBER:
|
||||
return (value.isinttype()? 1: 2);
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
};
|
||||
Coercion shortCoercion = new Coercion() {
|
||||
public Object coerce(LuaValue value) {
|
||||
return new Short( (short) value.toint() );
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TNUMBER:
|
||||
return (value.isinttype()? 1: 2);
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
};
|
||||
Coercion intCoercion = new Coercion() {
|
||||
public Object coerce(LuaValue value) {
|
||||
return new Integer( value.toint() );
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TNUMBER:
|
||||
return (value.isinttype()? 0: 1);
|
||||
case LuaValue.TBOOLEAN:
|
||||
case LuaValue.TNIL:
|
||||
return 2;
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
};
|
||||
Coercion longCoercion = new Coercion() {
|
||||
public Object coerce(LuaValue value) {
|
||||
return new Long( value.tolong() );
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TNUMBER:
|
||||
return (value.isinttype()? 1: 2);
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
};
|
||||
Coercion floatCoercion = new Coercion() {
|
||||
public Object coerce(LuaValue value) {
|
||||
return new Float( value.tofloat() );
|
||||
}
|
||||
public int score( LuaValue value ) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TNUMBER:
|
||||
return 1;
|
||||
case LuaValue.TBOOLEAN:
|
||||
return 2;
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
};
|
||||
Coercion doubleCoercion = new Coercion() {
|
||||
public Object coerce(LuaValue value) {
|
||||
return new Double( value.todouble() );
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TNUMBER:
|
||||
return (value.isinttype()? 1: 0);
|
||||
case LuaValue.TBOOLEAN:
|
||||
return 2;
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
};
|
||||
Coercion stringCoercion = new Coercion() {
|
||||
public Object coerce(LuaValue value) {
|
||||
return value.toString();
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TUSERDATA:
|
||||
return 0;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
Coercion objectCoercion = new Coercion() {
|
||||
public Object coerce(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TUSERDATA:
|
||||
return value.optuserdata(Object.class, null);
|
||||
case LuaValue.TSTRING:
|
||||
return value.toString();
|
||||
case LuaValue.TNUMBER:
|
||||
return (value.isinttype()?
|
||||
new Integer(value.toint()):
|
||||
new Double(value.todouble()));
|
||||
case LuaValue.TBOOLEAN:
|
||||
return value.toboolean()? Boolean.TRUE: Boolean.FALSE;
|
||||
case LuaValue.TNIL:
|
||||
return null;
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TSTRING:
|
||||
return 0;
|
||||
default:
|
||||
return 0x10;
|
||||
}
|
||||
}
|
||||
};
|
||||
COERCIONS.put( Boolean.TYPE, boolCoercion );
|
||||
COERCIONS.put( Boolean.class, boolCoercion );
|
||||
COERCIONS.put( Byte.TYPE, byteCoercion );
|
||||
COERCIONS.put( Byte.class, byteCoercion );
|
||||
COERCIONS.put( Character.TYPE, charCoercion );
|
||||
COERCIONS.put( Character.class, charCoercion );
|
||||
COERCIONS.put( Short.TYPE, shortCoercion );
|
||||
COERCIONS.put( Short.class, shortCoercion );
|
||||
COERCIONS.put( Integer.TYPE, intCoercion );
|
||||
COERCIONS.put( Integer.class, intCoercion );
|
||||
COERCIONS.put( Long.TYPE, longCoercion );
|
||||
COERCIONS.put( Long.class, longCoercion );
|
||||
COERCIONS.put( Float.TYPE, floatCoercion );
|
||||
COERCIONS.put( Float.class, floatCoercion );
|
||||
COERCIONS.put( Double.TYPE, doubleCoercion );
|
||||
COERCIONS.put( Double.class, doubleCoercion );
|
||||
COERCIONS.put( String.class, stringCoercion );
|
||||
COERCIONS.put( Object.class, objectCoercion );
|
||||
}
|
||||
|
||||
static Object coerceArg(LuaValue v, Class type) {
|
||||
Coercion co = (Coercion) COERCIONS.get( type );
|
||||
if ( co != null )
|
||||
return co.coerce( v );
|
||||
Object o = v.optuserdata(type, null);
|
||||
if ( o != null )
|
||||
return o;
|
||||
return v;
|
||||
}
|
||||
|
||||
static Object[] coerceArgs(LuaValue[] suppliedArgs, Class[] parameterTypes) {
|
||||
int nargs = suppliedArgs.length;
|
||||
int n = parameterTypes.length;
|
||||
Object[] args = new Object[n];
|
||||
for ( int i=0; i<n && i<nargs; i++ )
|
||||
args[i] = coerceArg( suppliedArgs[i], parameterTypes[i] );
|
||||
return args;
|
||||
}
|
||||
|
||||
/*
|
||||
* Score parameter types for match with supplied parameter list
|
||||
*
|
||||
* 1) exact number of args
|
||||
* 2) java has more args
|
||||
* 3) java has less args
|
||||
* 4) types coerce well
|
||||
*/
|
||||
static int scoreParamTypes(LuaValue[] suppliedArgs, Class[] paramTypes) {
|
||||
int nargs = suppliedArgs.length;
|
||||
int njava = paramTypes.length;
|
||||
int score = (njava == nargs? 0: njava > nargs? 0x4000: 0x8000);
|
||||
for ( int i=0; i<nargs && i<njava; i++ ) {
|
||||
LuaValue a = suppliedArgs[i];
|
||||
Class c = paramTypes[i];
|
||||
Coercion co = (Coercion) COERCIONS.get( c );
|
||||
if ( co != null ) {
|
||||
score += co.score( a );
|
||||
} else if ( a.optuserdata(c, null) == null ) {
|
||||
score += 0x10000;
|
||||
} else {
|
||||
score += 0x100;
|
||||
}
|
||||
}
|
||||
return score;
|
||||
}
|
||||
|
||||
}
|
||||
73
src/jse/org/luaj/vm2/lib/jse/JseBaseLib.java
Normal file
73
src/jse/org/luaj/vm2/lib/jse/JseBaseLib.java
Normal file
@@ -0,0 +1,73 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
|
||||
/**
|
||||
* Base library implementation, targeted for JSE platforms.
|
||||
*
|
||||
* Implements the same library functions as org.luaj.lib.BaseLib,
|
||||
* but looks in the current directory for files loaded via
|
||||
* loadfile(), dofile() and require().
|
||||
*
|
||||
* @see org.luaj.vm2.lib.jse.JseBaseLib
|
||||
*/
|
||||
public class JseBaseLib extends org.luaj.vm2.lib.BaseLib {
|
||||
|
||||
static {
|
||||
STDIN = System.in;
|
||||
}
|
||||
|
||||
/** Construct a JSE base library instance */
|
||||
public JseBaseLib() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to open a file in the current working directory,
|
||||
* or fall back to base opener if not found.
|
||||
*
|
||||
* This implementation attempts to open the file using new File(filename).
|
||||
* It falls back to the base implementation that looks it up as a resource
|
||||
* in the class path if not found as a plain file.
|
||||
*
|
||||
* @see org.luaj.vm2.lib.BaseLib
|
||||
* @see org.luaj.vm2.lib.ResourceFinder
|
||||
*
|
||||
* @param filename
|
||||
* @return InputStream, or null if not found.
|
||||
*/
|
||||
public InputStream findResource(String filename) {
|
||||
File f = new File(filename);
|
||||
if ( ! f.exists() )
|
||||
return super.findResource(filename);
|
||||
try {
|
||||
return new FileInputStream(f);
|
||||
} catch ( IOException ioe ) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
191
src/jse/org/luaj/vm2/lib/jse/JseIoLib.java
Normal file
191
src/jse/org/luaj/vm2/lib/jse/JseIoLib.java
Normal file
@@ -0,0 +1,191 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.lib.IoLib;
|
||||
|
||||
/**
|
||||
* Implementation of the lua io library for J2se using RandomAccessFile
|
||||
* to implement seek.
|
||||
*/
|
||||
public class JseIoLib extends IoLib {
|
||||
|
||||
public JseIoLib() {
|
||||
super();
|
||||
}
|
||||
|
||||
protected File wrapStdin() throws IOException {
|
||||
return new FileImpl(JseBaseLib.STDIN);
|
||||
}
|
||||
|
||||
protected File wrapStdout() throws IOException {
|
||||
return new FileImpl(JseBaseLib.STDOUT);
|
||||
}
|
||||
|
||||
protected File openFile( String filename, boolean readMode, boolean appendMode, boolean updateMode, boolean binaryMode ) throws IOException {
|
||||
RandomAccessFile f = new RandomAccessFile(filename,readMode? "r": "rw");
|
||||
if ( appendMode ) {
|
||||
f.seek(f.length());
|
||||
} else {
|
||||
if ( ! readMode )
|
||||
f.setLength(0);
|
||||
}
|
||||
return new FileImpl( f );
|
||||
}
|
||||
|
||||
protected File openProgram(String prog, String mode) throws IOException {
|
||||
final Process p = Runtime.getRuntime().exec(prog);
|
||||
return "w".equals(mode)?
|
||||
new FileImpl( p.getOutputStream() ):
|
||||
new FileImpl( p.getInputStream() );
|
||||
}
|
||||
|
||||
protected File tmpFile() throws IOException {
|
||||
java.io.File f = java.io.File.createTempFile(".luaj","bin");
|
||||
f.deleteOnExit();
|
||||
return new FileImpl( new RandomAccessFile(f,"rw") );
|
||||
}
|
||||
|
||||
private static void notimplemented() {
|
||||
throw new LuaError("not implemented");
|
||||
}
|
||||
|
||||
private final class FileImpl extends File {
|
||||
private final RandomAccessFile file;
|
||||
private final InputStream is;
|
||||
private final OutputStream os;
|
||||
private boolean closed = false;
|
||||
private boolean nobuffer = false;
|
||||
private FileImpl( RandomAccessFile file, InputStream is, OutputStream os ) {
|
||||
this.file = file;
|
||||
this.is = is!=null? is.markSupported()? is: new BufferedInputStream(is): null;
|
||||
this.os = os;
|
||||
}
|
||||
private FileImpl( RandomAccessFile f ) {
|
||||
this( f, null, null );
|
||||
}
|
||||
private FileImpl( InputStream i ) {
|
||||
this( null, i, null );
|
||||
}
|
||||
private FileImpl( OutputStream o ) {
|
||||
this( null, null, o );
|
||||
}
|
||||
public String toString() {
|
||||
return "file ("+this.hashCode()+")";
|
||||
}
|
||||
public boolean isstdfile() {
|
||||
return file == null;
|
||||
}
|
||||
public void close() throws IOException {
|
||||
closed = true;
|
||||
if ( file != null ) {
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
public void flush() throws IOException {
|
||||
if ( os != null )
|
||||
os.flush();
|
||||
}
|
||||
public void write(LuaString s) throws IOException {
|
||||
if ( os != null )
|
||||
os.write( s.m_bytes, s.m_offset, s.m_length );
|
||||
else if ( file != null )
|
||||
file.write( s.m_bytes, s.m_offset, s.m_length );
|
||||
else
|
||||
notimplemented();
|
||||
if ( nobuffer )
|
||||
flush();
|
||||
}
|
||||
public boolean isclosed() {
|
||||
return closed;
|
||||
}
|
||||
public int seek(String option, int pos) throws IOException {
|
||||
if ( file != null ) {
|
||||
if ( "set".equals(option) ) {
|
||||
file.seek(pos);
|
||||
} else if ( "end".equals(option) ) {
|
||||
file.seek(file.length()+pos);
|
||||
} else {
|
||||
file.seek(file.getFilePointer()+pos);
|
||||
}
|
||||
return (int) file.getFilePointer();
|
||||
}
|
||||
notimplemented();
|
||||
return 0;
|
||||
}
|
||||
public void setvbuf(String mode, int size) {
|
||||
nobuffer = "no".equals(mode);
|
||||
}
|
||||
|
||||
// get length remaining to read
|
||||
public int remaining() throws IOException {
|
||||
return file!=null? (int) (file.length()-file.getFilePointer()): -1;
|
||||
}
|
||||
|
||||
// peek ahead one character
|
||||
public int peek() throws IOException {
|
||||
if ( is != null ) {
|
||||
is.mark(1);
|
||||
int c = is.read();
|
||||
is.reset();
|
||||
return c;
|
||||
} else if ( file != null ) {
|
||||
int c = file.read();
|
||||
file.seek(file.getFilePointer()-1);
|
||||
return c;
|
||||
}
|
||||
notimplemented();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// return char if read, -1 if eof, throw IOException on other exception
|
||||
public int read() throws IOException {
|
||||
if ( is != null )
|
||||
return is.read();
|
||||
else if ( file != null ) {
|
||||
return file.read();
|
||||
}
|
||||
notimplemented();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// return number of bytes read if positive, -1 if eof, throws IOException
|
||||
public int read(byte[] bytes, int offset, int length) throws IOException {
|
||||
if (file!=null) {
|
||||
return file.read(bytes, offset, length);
|
||||
} else if (is!=null) {
|
||||
return is.read(bytes, offset, length);
|
||||
} else {
|
||||
notimplemented();
|
||||
}
|
||||
return length;
|
||||
}
|
||||
}
|
||||
}
|
||||
80
src/jse/org/luaj/vm2/lib/jse/JseMathLib.java
Normal file
80
src/jse/org/luaj/vm2/lib/jse/JseMathLib.java
Normal file
@@ -0,0 +1,80 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.LibFunction;
|
||||
import org.luaj.vm2.lib.OneArgFunction;
|
||||
import org.luaj.vm2.lib.TwoArgFunction;
|
||||
|
||||
/**
|
||||
* Math library implementation for use on JSE platform.
|
||||
*
|
||||
* Implements all "math" functions, including platform-specific
|
||||
* overrides for pow() and exp()
|
||||
*/
|
||||
public class JseMathLib extends org.luaj.vm2.lib.MathLib {
|
||||
|
||||
public JseMathLib() {
|
||||
LibFunction.bind( this, new J2seMathFunc1().getClass(), new String[] {
|
||||
"acos", "asin", "atan", "cosh",
|
||||
"exp", "log", "log10", "sinh",
|
||||
"tanh" } );
|
||||
LibFunction.bind( this, new J2seMathFunc2().getClass(), new String[] {
|
||||
"atan2", "pow", } );
|
||||
|
||||
}
|
||||
|
||||
public static class J2seMathFunc1 extends OneArgFunction {
|
||||
public LuaValue call(LuaValue arg) {
|
||||
switch ( opcode ) {
|
||||
case 0: return valueOf(Math.acos(arg.todouble()));
|
||||
case 1: return valueOf(Math.asin(arg.todouble()));
|
||||
case 2: return valueOf(Math.atan(arg.todouble()));
|
||||
case 3: return valueOf(Math.cosh(arg.todouble()));
|
||||
case 4: return valueOf(Math.exp(arg.todouble()));
|
||||
case 5: return valueOf(Math.log(arg.todouble()));
|
||||
case 6: return valueOf(Math.log10(arg.todouble()));
|
||||
case 7: return valueOf(Math.sinh(arg.todouble()));
|
||||
case 8: return valueOf(Math.tanh(arg.todouble()));
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
public static class J2seMathFunc2 extends TwoArgFunction {
|
||||
public LuaValue call(LuaValue arg1,LuaValue arg2) {
|
||||
switch ( opcode ) {
|
||||
case 0: return valueOf(Math.atan2(arg1.todouble(), arg2.todouble()));
|
||||
case 1: return valueOf(Math.pow(arg1.todouble(), arg2.todouble()));
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
/** Faster, better version of pow() used by arithmetic operator ^ */
|
||||
public double dpow_d(double a, double b) {
|
||||
return Math.pow(a, b);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
98
src/jse/org/luaj/vm2/lib/jse/JseOsLib.java
Normal file
98
src/jse/org/luaj/vm2/lib/jse/JseOsLib.java
Normal file
@@ -0,0 +1,98 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib.jse;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Implementation of the lua os library for J2se.
|
||||
*
|
||||
* <p>Implements features specific to the J2se environment:
|
||||
* <bl>
|
||||
* <li>execute()</li>
|
||||
* <li>remove()</li>
|
||||
* <li>rename()</li>
|
||||
* <li>tmpname()</li>
|
||||
* </bl>
|
||||
*
|
||||
* @see org.luaj.vm2.lib.OsLib
|
||||
*/
|
||||
public class JseOsLib extends org.luaj.vm2.lib.OsLib {
|
||||
|
||||
/** return code indicating the execute() threw an I/O exception */
|
||||
public static int EXEC_IOEXCEPTION = -1;
|
||||
|
||||
/** return code indicating the execute() was interrupted */
|
||||
public static int EXEC_INTERRUPTED = -2;
|
||||
|
||||
/** return code indicating the execute() threw an unknown exception */
|
||||
public static int EXEC_ERROR = -3;
|
||||
|
||||
/** public constructor */
|
||||
public JseOsLib() {
|
||||
}
|
||||
|
||||
protected int execute(String command) {
|
||||
Runtime r = Runtime.getRuntime();
|
||||
try {
|
||||
final Process p = r.exec(command);
|
||||
try {
|
||||
p.waitFor();
|
||||
return p.exitValue();
|
||||
} finally {
|
||||
p.destroy();
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
return EXEC_IOEXCEPTION;
|
||||
} catch (InterruptedException e) {
|
||||
return EXEC_INTERRUPTED;
|
||||
} catch (Throwable t) {
|
||||
return EXEC_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
protected void remove(String filename) throws IOException {
|
||||
File f = new File(filename);
|
||||
if ( ! f.exists() )
|
||||
throw new IOException("No such file or directory");
|
||||
if ( ! f.delete() )
|
||||
throw new IOException("Failed to delete");
|
||||
}
|
||||
|
||||
protected void rename(String oldname, String newname) throws IOException {
|
||||
File f = new File(oldname);
|
||||
if ( ! f.exists() )
|
||||
throw new IOException("No such file or directory");
|
||||
if ( ! f.renameTo(new File(newname)) )
|
||||
throw new IOException("Failed to delete");
|
||||
}
|
||||
|
||||
protected String tmpname() {
|
||||
try {
|
||||
java.io.File f = java.io.File.createTempFile(TMP_PREFIX ,TMP_SUFFIX);
|
||||
return f.getName();
|
||||
} catch ( IOException ioe ) {
|
||||
return super.tmpname();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
372
src/jse/org/luaj/vm2/lib/jse/LuajavaLib.java
Normal file
372
src/jse/org/luaj/vm2/lib/jse/LuajavaLib.java
Normal file
@@ -0,0 +1,372 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
|
||||
/** LuaJava-like bindings to Java scripting.
|
||||
*
|
||||
* TODO: coerce types on way in and out, pick method base on arg count ant types.
|
||||
*/
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaUserdata;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.lib.LibFunction;
|
||||
import org.luaj.vm2.lib.ThreeArgFunction;
|
||||
import org.luaj.vm2.lib.TwoArgFunction;
|
||||
import org.luaj.vm2.lib.VarArgFunction;
|
||||
|
||||
public class LuajavaLib extends LuaTable {
|
||||
|
||||
private static final int BINDCLASS = 0;
|
||||
private static final int NEWINSTANCE = 1;
|
||||
private static final int NEW = 2;
|
||||
private static final int CREATEPROXY = 3;
|
||||
private static final int LOADLIB = 4;
|
||||
|
||||
private static final String[] NAMES = {
|
||||
"bindClass",
|
||||
"newInstance",
|
||||
"new",
|
||||
"createProxy",
|
||||
"loadLib" };
|
||||
|
||||
private static final Map classMetatables = new HashMap();
|
||||
|
||||
public static void install(LuaValue globals) {
|
||||
globals.set("luajava", new LuajavaLib());
|
||||
}
|
||||
|
||||
public LuajavaLib() {
|
||||
LibFunction.bind( this, LuajavaFuncV.class, NAMES );
|
||||
}
|
||||
|
||||
// perform a lua call
|
||||
public static class LuajavaFuncV extends VarArgFunction {
|
||||
|
||||
public Varargs invoke(final Varargs args) {
|
||||
try {
|
||||
switch ( opcode ) {
|
||||
case BINDCLASS: {
|
||||
final Class clazz = Class.forName(args.checkString(1));
|
||||
return toUserdata( clazz, clazz );
|
||||
}
|
||||
case NEWINSTANCE:
|
||||
case NEW: {
|
||||
// get constructor
|
||||
final LuaValue c = args.checkvalue(1);
|
||||
final Class clazz = (opcode==NEWINSTANCE? Class.forName(c.toString()): (Class) c.checkuserdata(Class.class));
|
||||
final ParamsList params = new ParamsList( args );
|
||||
final Constructor con = resolveConstructor( clazz, params );
|
||||
|
||||
// coerce args, construct instance
|
||||
Object[] cargs = CoerceLuaToJava.coerceArgs( params.values, con.getParameterTypes() );
|
||||
Object o = con.newInstance( cargs );
|
||||
|
||||
// return result
|
||||
return toUserdata( o, clazz );
|
||||
}
|
||||
|
||||
case CREATEPROXY: {
|
||||
final int niface = args.narg()-1;
|
||||
if ( niface <= 0 )
|
||||
throw new LuaError("no interfaces");
|
||||
final LuaValue lobj = args.checktable(niface+1);
|
||||
|
||||
// get the interfaces
|
||||
final Class[] ifaces = new Class[niface];
|
||||
for ( int i=0; i<niface; i++ )
|
||||
ifaces[i] = Class.forName(args.checkString(i+1));
|
||||
|
||||
// create the invocation handler
|
||||
InvocationHandler handler = new InvocationHandler() {
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
String name = method.getName();
|
||||
LuaValue func = lobj.get(name);
|
||||
if ( func.isnil() )
|
||||
return null;
|
||||
int n = args!=null? args.length: 0;
|
||||
LuaValue[] v = new LuaValue[n];
|
||||
for ( int i=0; i<n; i++ )
|
||||
v[i] = CoerceJavaToLua.coerce(args[i]);
|
||||
LuaValue result = func.invoke(v).arg1();
|
||||
return CoerceLuaToJava.coerceArg(result, method.getReturnType());
|
||||
}
|
||||
};
|
||||
|
||||
// create the proxy object
|
||||
Object proxy = Proxy.newProxyInstance(getClass().getClassLoader(), ifaces, handler);
|
||||
|
||||
// return the proxy
|
||||
return LuaValue.userdataOf( proxy );
|
||||
}
|
||||
case LOADLIB: {
|
||||
// get constructor
|
||||
String classname = args.checkString(1);
|
||||
String methodname = args.checkString(2);
|
||||
Class clazz = Class.forName(classname);
|
||||
Method method = clazz.getMethod(methodname, new Class[] {});
|
||||
Object result = method.invoke(clazz, new Object[] {});
|
||||
if ( result instanceof LuaValue ) {
|
||||
return (LuaValue) result;
|
||||
} else {
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw new LuaError("not yet supported: "+this);
|
||||
}
|
||||
} catch (LuaError e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new LuaError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class ParamsList {
|
||||
public final LuaValue[] values;
|
||||
public final Class[] classes;
|
||||
public int hash;
|
||||
ParamsList( Varargs args ) {
|
||||
int n = Math.max(args.narg()-1,0);
|
||||
values = new LuaValue[n];
|
||||
classes = new Class[n];
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
values[i] = args.arg(i+2);
|
||||
classes[i] = values[i].getClass();
|
||||
hash += classes[i].hashCode();
|
||||
}
|
||||
}
|
||||
public int hashCode() {
|
||||
return hash;
|
||||
}
|
||||
public boolean equals( Object o ) {
|
||||
return ( o instanceof ParamsList )?
|
||||
Arrays.equals( classes, ((ParamsList) o).classes ):
|
||||
false;
|
||||
}
|
||||
}
|
||||
|
||||
static LuaUserdata toUserdata(Object instance, final Class clazz) {
|
||||
LuaTable mt = (LuaTable) classMetatables.get(clazz);
|
||||
if ( mt == null ) {
|
||||
mt = new LuaTable();
|
||||
mt.set( LuaValue.INDEX, new TwoArgFunction() {
|
||||
public LuaValue call(LuaValue table, LuaValue key) {
|
||||
final String s = key.toString();
|
||||
try {
|
||||
Field f = clazz.getField(s);
|
||||
Object o = f.get(table.checkuserdata(Object.class));
|
||||
return CoerceJavaToLua.coerce( o );
|
||||
} catch (NoSuchFieldException nsfe) {
|
||||
return new LMethod(clazz,s);
|
||||
} catch (Exception e) {
|
||||
throw new LuaError(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
mt.set( LuaValue.NEWINDEX, new ThreeArgFunction() {
|
||||
public LuaValue call(LuaValue table, LuaValue key, LuaValue val) {
|
||||
String s = key.toString();
|
||||
try {
|
||||
Field f = clazz.getField(s);
|
||||
Object v = CoerceLuaToJava.coerceArg(val, f.getType());
|
||||
f.set(table.checkuserdata(Object.class),v);
|
||||
} catch (Exception e) {
|
||||
throw new LuaError(e);
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
});
|
||||
classMetatables.put(clazz, mt);
|
||||
}
|
||||
return LuaValue.userdataOf(instance,mt);
|
||||
}
|
||||
|
||||
private static final class LMethod extends VarArgFunction {
|
||||
private final Class clazz;
|
||||
private final String s;
|
||||
private LMethod(Class clazz, String s) {
|
||||
this.clazz = clazz;
|
||||
this.s = s;
|
||||
}
|
||||
public String toString() {
|
||||
return clazz.getName()+"."+s+"()";
|
||||
}
|
||||
public Varargs invoke(Varargs args) {
|
||||
try {
|
||||
// find the method
|
||||
Object instance = args.checkuserdata(1,Object.class);
|
||||
ParamsList params = new ParamsList( args );
|
||||
Method meth = resolveMethod( clazz, s, params );
|
||||
|
||||
// coerce the arguments
|
||||
Object[] margs = CoerceLuaToJava.coerceArgs( params.values, meth.getParameterTypes() );
|
||||
Object result = meth.invoke( instance, margs );
|
||||
|
||||
// coerce the result
|
||||
return CoerceJavaToLua.coerce(result);
|
||||
} catch (Exception e) {
|
||||
throw new LuaError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Map consCache =
|
||||
new HashMap();
|
||||
|
||||
private static Map consIndex =
|
||||
new HashMap();
|
||||
|
||||
private static Constructor resolveConstructor(Class clazz, ParamsList params ) {
|
||||
|
||||
// get the cache
|
||||
Map cache = (Map) consCache.get( clazz );
|
||||
if ( cache == null )
|
||||
consCache.put( clazz, cache = new HashMap() );
|
||||
|
||||
// look up in the cache
|
||||
Constructor c = (Constructor) cache.get( params );
|
||||
if ( c != null )
|
||||
return c;
|
||||
|
||||
// get index
|
||||
Map index = (Map) consIndex.get( clazz );
|
||||
if ( index == null ) {
|
||||
consIndex.put( clazz, index = new HashMap() );
|
||||
Constructor[] cons = clazz.getConstructors();
|
||||
for ( int i=0; i<cons.length; i++ ) {
|
||||
Constructor con = cons[i];
|
||||
Integer n = new Integer( con.getParameterTypes().length );
|
||||
List list = (List) index.get(n);
|
||||
if ( list == null )
|
||||
index.put( n, list = new ArrayList() );
|
||||
list.add( con );
|
||||
}
|
||||
}
|
||||
|
||||
// figure out best list of arguments == supplied args
|
||||
Integer n = new Integer( params.classes.length );
|
||||
List list = (List) index.get(n);
|
||||
if ( list == null )
|
||||
throw new IllegalArgumentException("no constructor with "+n+" args");
|
||||
|
||||
// find constructor with best score
|
||||
int bests = Integer.MAX_VALUE;
|
||||
int besti = 0;
|
||||
for ( int i=0, size=list.size(); i<size; i++ ) {
|
||||
Constructor con = (Constructor) list.get(i);
|
||||
int s = CoerceLuaToJava.scoreParamTypes(params.values, con.getParameterTypes());
|
||||
if ( s < bests ) {
|
||||
bests = s;
|
||||
besti = i;
|
||||
}
|
||||
}
|
||||
|
||||
// put into cache
|
||||
c = (Constructor) list.get(besti);
|
||||
cache.put( params, c );
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
private static Map methCache =
|
||||
new HashMap();
|
||||
|
||||
private static Map methIndex =
|
||||
new HashMap();
|
||||
|
||||
private static Method resolveMethod(Class clazz, String methodName, ParamsList params ) {
|
||||
|
||||
// get the cache
|
||||
Map nameCache = (Map) methCache.get( clazz );
|
||||
if ( nameCache == null )
|
||||
methCache.put( clazz, nameCache = new HashMap() );
|
||||
Map cache = (Map) nameCache.get( methodName );
|
||||
if ( cache == null )
|
||||
nameCache.put( methodName, cache = new HashMap() );
|
||||
|
||||
// look up in the cache
|
||||
Method m = (Method) cache.get( params );
|
||||
if ( m != null )
|
||||
return m;
|
||||
|
||||
// get index
|
||||
Map index = (Map) methIndex.get( clazz );
|
||||
if ( index == null ) {
|
||||
methIndex.put( clazz, index = new HashMap() );
|
||||
Method[] meths = clazz.getMethods();
|
||||
for ( int i=0; i<meths.length; i++ ) {
|
||||
Method meth = meths[i];
|
||||
String s = meth.getName();
|
||||
Integer n = new Integer(meth.getParameterTypes().length);
|
||||
Map map = (Map) index.get(s);
|
||||
if ( map == null )
|
||||
index.put( s, map = new HashMap() );
|
||||
List list = (List) map.get(n);
|
||||
if ( list == null )
|
||||
map.put( n, list = new ArrayList() );
|
||||
list.add( meth );
|
||||
}
|
||||
}
|
||||
|
||||
// figure out best list of arguments == supplied args
|
||||
Map map = (Map) index.get(methodName);
|
||||
if ( map == null )
|
||||
throw new IllegalArgumentException("no method named '"+methodName+"'");
|
||||
Integer n = new Integer( params.classes.length );
|
||||
List list = (List) map.get(n);
|
||||
if ( list == null )
|
||||
throw new IllegalArgumentException("no method named '"+methodName+"' with "+n+" args");
|
||||
|
||||
// find constructor with best score
|
||||
int bests = Integer.MAX_VALUE;
|
||||
int besti = 0;
|
||||
for ( int i=0, size=list.size(); i<size; i++ ) {
|
||||
Method meth = (Method) list.get(i);
|
||||
int s = CoerceLuaToJava.scoreParamTypes(params.values, meth.getParameterTypes());
|
||||
if ( s < bests ) {
|
||||
bests = s;
|
||||
besti = i;
|
||||
}
|
||||
}
|
||||
|
||||
// put into cache
|
||||
m = (Method) list.get(besti);
|
||||
cache.put( params, m );
|
||||
return m;
|
||||
}
|
||||
|
||||
}
|
||||
785
src/jse/org/luaj/vm2/luajc/JavaCodeGenerator.java
Normal file
785
src/jse/org/luaj/vm2/luajc/JavaCodeGenerator.java
Normal file
@@ -0,0 +1,785 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.luajc;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.luaj.vm2.lib.LibFunction;
|
||||
import org.luaj.vm2.luajc.lst.LSChunk;
|
||||
import org.luaj.vm2.luajc.lst.LSExpression;
|
||||
import org.luaj.vm2.luajc.lst.LSField;
|
||||
import org.luaj.vm2.luajc.lst.LSFunction;
|
||||
import org.luaj.vm2.luajc.lst.LSIfStatement;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement;
|
||||
import org.luaj.vm2.luajc.lst.LSVariable;
|
||||
import org.luaj.vm2.luajc.lst.Name;
|
||||
import org.luaj.vm2.luajc.lst.Scope;
|
||||
import org.luaj.vm2.luajc.lst.LSExpression.BinopExpr;
|
||||
import org.luaj.vm2.luajc.lst.LSExpression.FunctionExpr;
|
||||
import org.luaj.vm2.luajc.lst.LSExpression.NumberConstant;
|
||||
import org.luaj.vm2.luajc.lst.LSExpression.StringConstant;
|
||||
import org.luaj.vm2.luajc.lst.LSExpression.TableConstructor;
|
||||
import org.luaj.vm2.luajc.lst.LSExpression.UnopExpr;
|
||||
import org.luaj.vm2.luajc.lst.LSExpression.VarargsRef;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.BreakStat;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.DoBlock;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.ForList;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.ForLoop;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.FunctionCall;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.LocalAssign;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.LocalFunction;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.RepeatUntil;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.ReturnStat;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.VarAssign;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.VarNamedFunction;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.WhileLoop;
|
||||
import org.luaj.vm2.luajc.lst.LSVariable.CallFunction;
|
||||
import org.luaj.vm2.luajc.lst.LSVariable.CallMethod;
|
||||
import org.luaj.vm2.luajc.lst.LSVariable.Field;
|
||||
import org.luaj.vm2.luajc.lst.LSVariable.Index;
|
||||
import org.luaj.vm2.luajc.lst.LSVariable.Method;
|
||||
import org.luaj.vm2.luajc.lst.LSVariable.NameReference;
|
||||
import org.luaj.vm2.luajc.lst.LSVariable.Parentheses;
|
||||
|
||||
public class JavaCodeGenerator {
|
||||
|
||||
public static String toJava(LSChunk chunk) {
|
||||
JavaCodeGenerator jcg = new JavaCodeGenerator();
|
||||
return jcg.writeChunk( chunk );
|
||||
}
|
||||
|
||||
public final Stack<StringBuffer> stringBuffers = new Stack<StringBuffer>();
|
||||
public StringBuffer sb;
|
||||
private int indent = 0;
|
||||
|
||||
public JavaCodeGenerator() {
|
||||
this.sb = new StringBuffer();
|
||||
}
|
||||
|
||||
private String writeChunk(LSChunk chunk) {
|
||||
pushFunctionContext();
|
||||
writeln( "import org.luaj.vm2.*;" );
|
||||
writeln( "import org.luaj.vm2.lib.*;" );
|
||||
writeln();
|
||||
writeln( "public class "+chunk.chunkname+" extends VarArgFunction {" );
|
||||
++indent;
|
||||
writeln( "public Varargs invoke(Varargs $args) {");
|
||||
++indent;
|
||||
writeFunctionBody( chunk.function );
|
||||
--indent;
|
||||
writeln( "}");
|
||||
--indent;
|
||||
// TODO: write out chunk constants
|
||||
writeln( "}" );
|
||||
return popFunctionContext();
|
||||
}
|
||||
|
||||
private void pushFunctionContext() {
|
||||
stringBuffers.push( sb = new StringBuffer() );
|
||||
}
|
||||
|
||||
private String popFunctionContext() {
|
||||
String v = stringBuffers.pop().toString();
|
||||
sb = stringBuffers.isEmpty()? null: stringBuffers.lastElement();
|
||||
return v;
|
||||
}
|
||||
|
||||
private void writeFunctionBody(LSFunction function) {
|
||||
if ( function.hasandlogic || function.hasorlogic )
|
||||
writeln( "LuaValue $t;" );
|
||||
if ( function.hasvarargassign )
|
||||
writeln( "Varargs $v;" );
|
||||
writeStatements( function.stats );
|
||||
if ( LSStatement.isNextStatementReachable( function.stats ) )
|
||||
writeln( "return NONE;" );
|
||||
}
|
||||
|
||||
private void writeStatements(List<LSStatement> statements) {
|
||||
for ( LSStatement s : statements ) {
|
||||
writeStatement( s );
|
||||
}
|
||||
}
|
||||
|
||||
private void writeStatement(LSStatement s) {
|
||||
if ( s==null ) return;
|
||||
switch ( s.type ) {
|
||||
case functionCall: writeFunctionCall( (LSStatement.FunctionCall) s ); break;
|
||||
case doBlock: writeDoBlock( (LSStatement.DoBlock) s ); break;
|
||||
case whileLoop: writeWhileLoop( (LSStatement.WhileLoop) s ); break;
|
||||
case repeatUntil: writeRepeatUntil( (LSStatement.RepeatUntil) s ); break;
|
||||
case varAssign: writeVarAssign( (LSStatement.VarAssign) s ); break;
|
||||
case forLoop: writeForLoop( (LSStatement.ForLoop) s ); break;
|
||||
case forList: writeForList( (LSStatement.ForList) s ); break;
|
||||
case varNamedFunction: writeVarNamedFunction((LSStatement.VarNamedFunction) s ); break;
|
||||
case localFunction: writeLocalFunction( (LSStatement.LocalFunction) s ); break;
|
||||
case localAssign: writeLocalAssign( (LSStatement.LocalAssign) s ); break;
|
||||
case returnStat: writeReturnStat( (LSStatement.ReturnStat) s ); break;
|
||||
case breakStat: writeBreakStat( (LSStatement.BreakStat) s ); break;
|
||||
case ifStat: writeIfStat( (LSIfStatement) s ); break;
|
||||
}
|
||||
}
|
||||
|
||||
private void writeFunctionCall(FunctionCall s) {
|
||||
writeindent();
|
||||
write( eval(s.variable)+";" );
|
||||
writeln();
|
||||
}
|
||||
|
||||
private void writeDoBlock(DoBlock s) {
|
||||
writeln( "{" );
|
||||
++indent;
|
||||
writeStatements( s.statements );
|
||||
--indent;
|
||||
writeln( "}" );
|
||||
}
|
||||
|
||||
private void writeWhileLoop(WhileLoop s) {
|
||||
writeln( "while ("+eval(s.condition)+".toboolean()) {" );
|
||||
++indent;
|
||||
writeStatements( s.statements );
|
||||
--indent;
|
||||
writeln( "}" );
|
||||
}
|
||||
|
||||
private void writeRepeatUntil(RepeatUntil s) {
|
||||
writeln( "do {" );
|
||||
++indent;
|
||||
writeStatements( s.statements );
|
||||
--indent;
|
||||
writeln( "} while (!"+eval(s.condition)+");" );
|
||||
}
|
||||
|
||||
private void writeForLoop(ForLoop s) {
|
||||
writeln( "{" );
|
||||
++indent;
|
||||
// TODO: name handling, also upvalues!
|
||||
String index = javaName( s.index );
|
||||
String limit = javaName( s.scope.declare("$limit") );
|
||||
String step = javaName( s.scope.declare("$step") );
|
||||
writeln( "LuaValue "+index+"="+eval(s.initial)+";" );
|
||||
writeln( "final LuaValue "+limit+"="+eval(s.limit)+";" );
|
||||
if ( s.step != null ) {
|
||||
writeln( "final LuaValue "+step+"="+eval(s.step)+";" );
|
||||
writeln( "final boolean "+step+"$b="+step+".gt_b(0);" );
|
||||
}
|
||||
if ( s.step != null ) {
|
||||
writeln( "for ( ; "+index+".testfor_b("+limit+","+step+"$b); "+index+"="+index+".add("+step+") ) {" );
|
||||
} else {
|
||||
writeln( "for ( ; "+index+".lteq_b("+limit+"); "+index+"="+index+".add(1) ) {" );
|
||||
}
|
||||
++indent;
|
||||
writeStatements( s.statements );
|
||||
--indent;
|
||||
writeln( "}" );
|
||||
--indent;
|
||||
writeln( "}" );
|
||||
}
|
||||
|
||||
private void writeForList(ForList s) {
|
||||
writeln( "{" );
|
||||
++indent;
|
||||
List<String> exprs = evalExpressions(s.expressions, 3, s.scope);
|
||||
// TODO: upvalues handling!
|
||||
String fun = javaName( s.scope.declare("$f") );
|
||||
String sta = javaName( s.scope.declare("$s") );
|
||||
String var = javaName( s.scope.declare("$var") );
|
||||
String res = javaName( s.scope.declare("$res") );
|
||||
writeln( "LuaValue "+fun+"="+exprs.get(0)+";" );
|
||||
writeln( "LuaValue "+sta+"="+exprs.get(1)+";" );
|
||||
writeln( "LuaValue "+var+"="+exprs.get(2)+";" );
|
||||
writeln( "while ( true ) {" );
|
||||
++indent;
|
||||
writeln( "Varargs "+res+" = "+fun+".invoke(varargsOf("+sta+","+var+"));" );
|
||||
for ( int i=1, n=s.names.size(); i<=n; i++ )
|
||||
writeln( "LuaValue "+javaName(s.names.get(i-1))+"="+res+".arg("+i+");" );
|
||||
writeln( var+"="+javaName(s.names.get(0))+";" );
|
||||
writeln( "if ( "+var+".isnil() ) break;" );
|
||||
writeStatements( s.statements );
|
||||
--indent;
|
||||
writeln( "}" );
|
||||
--indent;
|
||||
writeln( "}" );
|
||||
}
|
||||
|
||||
private final static Set<String> reserved = new HashSet<String>();
|
||||
static {
|
||||
String[] specials = {
|
||||
// keywors used by our code generator
|
||||
"name", "opcode", "env",
|
||||
|
||||
// java keywords
|
||||
"abstract", "continue", "for", "new", "switch",
|
||||
"assert", "default", "goto", "package", "synchronized",
|
||||
"boolean", "do", "if", "private", "this",
|
||||
"break", "double", "implements", "protected", "throw",
|
||||
"byte", "else", "import", "public", "throws",
|
||||
"case", "enum", "instanceof", "return", "transient",
|
||||
"catch", "extends", "int", "short", "try",
|
||||
"char", "final", "interface", "static", "void",
|
||||
"class", "finally", "long", "strictfp", "volatile",
|
||||
"const", "float", "native", "super", "while",
|
||||
};
|
||||
for ( int i=0; i<specials.length; i++ )
|
||||
reserved.add( specials[i] );
|
||||
java.lang.reflect.Field[] f = LibFunction.class.getFields();
|
||||
for ( int i=0; i<f.length; i++ )
|
||||
reserved.add( f[i].getName() );
|
||||
}
|
||||
|
||||
private String javaName(Name name) {
|
||||
return name.innerrevision>0?
|
||||
name.luaname+"$"+name.innerrevision:
|
||||
reserved.contains(name.luaname)? (name.luaname+"$"): name.luaname;
|
||||
}
|
||||
|
||||
private void writeVarNamedFunction(VarNamedFunction s) {
|
||||
String funcdef = evalFuncbody(s.funcbody);
|
||||
writeAssign( s.funcname, funcdef );
|
||||
}
|
||||
|
||||
private String evalFuncbody(LSFunction funcbody) {
|
||||
pushFunctionContext();
|
||||
int n = funcbody.paramnames!=null? funcbody.paramnames.size(): 0;
|
||||
boolean isvararg = (funcbody.isvararg || n > 3);
|
||||
if ( isvararg ) {
|
||||
write( "new VarArgFunction(env) {\n" );
|
||||
++indent;
|
||||
writeln( "public Varargs invoke(Varargs $args) {" );
|
||||
++indent;
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
Name name = funcbody.paramnames.get(i);
|
||||
if ( name.isupvalue )
|
||||
writeln( "final LuaValue[] "+javaName(funcbody.paramnames.get(i))+"={$args.arg("+(i+1)+")};" );
|
||||
else
|
||||
writeln( "LuaValue "+javaName(funcbody.paramnames.get(i))+"=$args.arg("+(i+1)+");" );
|
||||
}
|
||||
if ( (n > 0 && funcbody.usesvarargs) || funcbody.needsarg )
|
||||
writeln( "$args = $args.subargs("+(n+1)+");" );
|
||||
if ( funcbody.needsarg )
|
||||
writeln( "LuaValue arg = new LuaTable($args);" );
|
||||
else if ( funcbody.hasarg )
|
||||
writeln( "LuaValue arg = NIL;" );
|
||||
writeFunctionBody(funcbody);
|
||||
--indent;
|
||||
writeln( "}" );
|
||||
--indent;
|
||||
writeindent();
|
||||
write( "}" );
|
||||
} else {
|
||||
write(
|
||||
n==0? "new ZeroArgFunction(env) {\n":
|
||||
n==1? "new OneArgFunction(env) {\n":
|
||||
n==2? "new TwoArgFunction(env) {\n":
|
||||
"new ThreeArgFunction(env) {\n" );
|
||||
++indent;
|
||||
writeindent();
|
||||
write( "public LuaValue call(");
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
if (i>0) write( "," );
|
||||
Name name = funcbody.paramnames.get(i);
|
||||
if ( name.isupvalue )
|
||||
write( "LuaValue "+javaName(name)+"$u" );
|
||||
else
|
||||
write( "LuaValue "+javaName(name) );
|
||||
}
|
||||
write( ") {" );
|
||||
writeln();
|
||||
++indent;
|
||||
|
||||
// upvalues
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
Name name = funcbody.paramnames.get(i);
|
||||
if ( name.isupvalue )
|
||||
writeln( "final LuaValue[] "+javaName(name)+"={"+javaName(name)+"$u};" );
|
||||
}
|
||||
|
||||
// function body
|
||||
writeFunctionBody(funcbody);
|
||||
--indent;
|
||||
writeln( "}" );
|
||||
--indent;
|
||||
writeindent();
|
||||
write( "}" );
|
||||
}
|
||||
return popFunctionContext();
|
||||
}
|
||||
|
||||
private void writeVarAssign(VarAssign s) {
|
||||
int nassign = s.variables.size();
|
||||
List<String> exprs = evalExpressions(s.expressions, nassign, s.scope);
|
||||
for ( int i=0; i<nassign; i++ )
|
||||
writeAssign( s.variables.get(i), exprs.get(i) );
|
||||
for ( int i=nassign; i<exprs.size(); i++ )
|
||||
writeln( exprs.get(i) );
|
||||
}
|
||||
|
||||
private void writeLocalFunction(LocalFunction s) {
|
||||
String funcdef = evalFuncbody(s.funcbody);
|
||||
if ( s.name.isupvalue ) {
|
||||
writeln( "final LuaValue[] "+javaName(s.name)+"={null};" );
|
||||
writeln( javaName(s.name)+"[0]="+funcdef+";" );
|
||||
} else
|
||||
writeln( "LuaValue "+javaName(s.name)+"="+funcdef+";" );
|
||||
}
|
||||
|
||||
private void writeLocalAssign(LocalAssign s) {
|
||||
int nassign = s.names.size();
|
||||
List<String> exprs = evalExpressions(s.expressions, nassign, s.scope);
|
||||
for ( int i=0; i<nassign; i++ ) {
|
||||
Name name= s.names.get(i);
|
||||
if ( name.isupvalue )
|
||||
writeln( "final LuaValue[] "+javaName(name)+"={"+exprs.get(i)+"};" );
|
||||
else
|
||||
writeln( "LuaValue "+javaName(name)+"="+exprs.get(i)+";" );
|
||||
}
|
||||
for ( int i=nassign; i<exprs.size(); i++ )
|
||||
writeln( exprs.get(i)+";" );
|
||||
}
|
||||
|
||||
/** Evaluate expressions for use in assignment
|
||||
* @param scope */
|
||||
private List<String> evalExpressions(List<LSExpression> exprs, int nassign, Scope scope) {
|
||||
int nexpr = (exprs!=null? exprs.size(): 0);
|
||||
List<String> e = new ArrayList<String>(nexpr);
|
||||
boolean hasvarargs = false;
|
||||
for ( int i=0; i<nexpr || i<nassign; i++ ) {
|
||||
if ( i<nexpr-1 || nassign <= nexpr ) {
|
||||
e.add( eval( exprs.get(i) ) );
|
||||
} else if ( i==nexpr-1 ) {
|
||||
int nr = exprs.get(i).getNumReturns();
|
||||
hasvarargs = (nr==-1) || (nr>1);
|
||||
if ( hasvarargs )
|
||||
e.add( "($v="+eval(exprs.get(i))+").arg1()" );
|
||||
else
|
||||
e.add( eval(exprs.get(i)) );
|
||||
} else if (hasvarargs) {
|
||||
e.add( "$v.arg("+(i-nexpr+2)+")" );
|
||||
} else {
|
||||
e.add( "NIL" );
|
||||
}
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
private void writeReturnStat(ReturnStat s) {
|
||||
int n = s.expressions!=null? s.expressions.size(): 0;
|
||||
if ( ! s.function.isvararg )
|
||||
writeln( n==0? "return NONE;": "return "+eval(s.expressions.get(0))+";" );
|
||||
else {
|
||||
writeindent();
|
||||
switch ( n ) {
|
||||
case 0:
|
||||
write( "return NONE;" );
|
||||
break;
|
||||
case 1:
|
||||
write( "return "+eval( s.expressions.get(0))+";" );
|
||||
break;
|
||||
case 2: case 3: {
|
||||
write( "return varargsOf(" );
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
if (i>0) write( "," );
|
||||
write( eval( s.expressions.get(i)) );
|
||||
}
|
||||
write( ");" );
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
write( "return varargsOf(new LuaValue[] {" );
|
||||
for ( int i=0; i<n-1; i++ ) {
|
||||
if (i>0) write( "," );
|
||||
write( eval( s.expressions.get(i)) );
|
||||
}
|
||||
write( "},"+eval(s.expressions.get(n-1))+");" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
writeln();
|
||||
}
|
||||
}
|
||||
|
||||
private void writeBreakStat(BreakStat s) {
|
||||
writeln( "break;" );
|
||||
}
|
||||
|
||||
private void writeIfStat(LSIfStatement s) {
|
||||
writeln( "if ("+eval_bool(s.condition)+") {" );
|
||||
++indent;
|
||||
writeStatements( s.statements );
|
||||
if ( s.elseifs != null ) {
|
||||
for ( LSIfStatement.ElseIf elseif : s.elseifs ) {
|
||||
--indent;
|
||||
writeln( "} else if ("+eval_bool(elseif.condition)+") {" );
|
||||
++indent;
|
||||
writeStatements( elseif.statements );
|
||||
}
|
||||
}
|
||||
if ( s.elsestatements != null ) {
|
||||
--indent;
|
||||
writeln( "} else {" );
|
||||
++indent;
|
||||
writeStatements( s.elsestatements );
|
||||
}
|
||||
--indent;
|
||||
writeln( "}" );
|
||||
}
|
||||
|
||||
//-------------------------------------------
|
||||
// assignment using variables
|
||||
//-------------------------------------------
|
||||
|
||||
/** Write assignment of a particular variable value */
|
||||
private void writeAssign(LSVariable v, String expression) {
|
||||
switch ( v.type ) {
|
||||
case nameVariable: writeNameAssign( (LSVariable.NameReference) v, expression); break;
|
||||
case fieldVariable: writeFieldAssign( (LSVariable.Field) v, expression); break;
|
||||
case methodVariable: writeMethodAssign( (LSVariable.Method) v, expression); break;
|
||||
case parenthesesVariable: writeParenAssign( (LSVariable.Parentheses) v, expression); break;
|
||||
case indexVariable: writeIndexAssign( (LSVariable.Index) v, expression); break;
|
||||
case callFunctionVariable: writeCallFuncAssign((LSVariable.CallFunction)v, expression); break;
|
||||
case callMethodVariable: writeCallMethAssign((LSVariable.CallMethod) v, expression); break;
|
||||
}
|
||||
}
|
||||
|
||||
private void writeNameAssign(NameReference v, String expression) {
|
||||
if ( v.name.isGlobal() )
|
||||
writeln( "env.set(\""+v.name.luaname+"\","+expression+");");
|
||||
else if ( v.name.isupvalue )
|
||||
writeln( javaName(v.name)+"[0]="+expression+";");
|
||||
else
|
||||
writeln( javaName(v.name)+"="+expression+";");
|
||||
}
|
||||
|
||||
private void writeFieldAssign(Field v, String expression) {
|
||||
String base = eval(v.variable);
|
||||
writeln( base+".set(\""+v.field+"\","+expression+");");
|
||||
}
|
||||
|
||||
private void writeMethodAssign(Method v, String expression) {
|
||||
String base = eval(v.variable);
|
||||
writeln( base+".set(\""+v.method+"\","+expression+");");
|
||||
}
|
||||
|
||||
private void writeParenAssign(Parentheses v, String expression) {
|
||||
throw new IllegalArgumentException("no assignment for parenthesis expressions");
|
||||
}
|
||||
|
||||
private void writeIndexAssign(Index v, String expression) {
|
||||
String base = eval(v.variable);
|
||||
writeln( base+".set("+eval(v.expression)+","+expression+");");
|
||||
}
|
||||
|
||||
private void writeCallFuncAssign(CallFunction v, String expression) {
|
||||
throw new IllegalArgumentException("no assignment for call function expressions");
|
||||
}
|
||||
|
||||
private void writeCallMethAssign(CallMethod v, String expression) {
|
||||
throw new IllegalArgumentException("no assignment for call method expressions");
|
||||
}
|
||||
|
||||
//-------------------------------------------
|
||||
// write out expressions
|
||||
//-------------------------------------------
|
||||
|
||||
private String eval_bool(LSExpression e) {
|
||||
return eval(e)+".toboolean()";
|
||||
}
|
||||
|
||||
/** evaluate the expression to a particular operand type */
|
||||
private String eval(LSExpression e) {
|
||||
if ( e==null ) return "NONE";
|
||||
switch ( e.type ) {
|
||||
case nilConstant: return "NIL";
|
||||
case trueConstant: return "TRUE";
|
||||
case falseConstant: return "FALSE";
|
||||
case unop: return evalUnop( (LSExpression.UnopExpr) e);
|
||||
case binop: return evalBinop( (LSExpression.BinopExpr) e);
|
||||
case functionExpr: return evalFunction((LSExpression.FunctionExpr) e);
|
||||
case tableConstructor: return evalTable( (LSExpression.TableConstructor) e);
|
||||
case numberConstant: return evalNumber( (LSExpression.NumberConstant) e);
|
||||
case stringConstant: return evalString( (LSExpression.StringConstant) e);
|
||||
|
||||
// variable types
|
||||
case nameVariable: return evalNameRef( (LSVariable.NameReference) e);
|
||||
case fieldVariable: return evalField( (LSVariable.Field) e);
|
||||
case methodVariable: return evalMethod( (LSVariable.Method) e);
|
||||
case parenthesesVariable: return evalParen( (LSVariable.Parentheses) e);
|
||||
case indexVariable: return evalIndex( (LSVariable.Index) e);
|
||||
case callFunctionVariable: return evalCallFunc((LSVariable.CallFunction) e);
|
||||
case callMethodVariable: return evalCallMeth((LSVariable.CallMethod) e);
|
||||
case varargsRef: return evalVarargs( (LSExpression.VarargsRef) e);
|
||||
|
||||
default: throw new IllegalArgumentException("unknown expression type: "+e.type);
|
||||
}
|
||||
}
|
||||
|
||||
private String evalUnop(UnopExpr e) {
|
||||
switch ( e.op.type ) {
|
||||
case neg: return eval( e.rhs )+".neg()";
|
||||
case not: return eval( e.rhs )+".not()";
|
||||
case len: return eval( e.rhs )+".len()";
|
||||
}
|
||||
throw new IllegalArgumentException("unknown unary operand: "+e.op );
|
||||
}
|
||||
|
||||
private String evalBinop(BinopExpr e) {
|
||||
switch ( e.op.type ) {
|
||||
case pow: return eval(e.lhs)+".pow("+eval(e.rhs)+")";
|
||||
case mul: return eval(e.lhs)+".mul("+eval(e.rhs)+")";
|
||||
case div: return eval(e.lhs)+".div("+eval(e.rhs)+")";
|
||||
case mod: return eval(e.lhs)+".mod("+eval(e.rhs)+")";
|
||||
case add: return eval(e.lhs)+".add("+eval(e.rhs)+")";
|
||||
case sub: return eval(e.lhs)+".sub("+eval(e.rhs)+")";
|
||||
case concat: return eval(e.lhs)+".concat("+eval(e.rhs)+")";
|
||||
case lt: return eval(e.lhs)+".lt("+eval(e.rhs)+")";
|
||||
case lteq: return eval(e.lhs)+".lteq("+eval(e.rhs)+")";
|
||||
case gt: return eval(e.lhs)+".gt("+eval(e.rhs)+")";
|
||||
case gteq: return eval(e.lhs)+".gteq("+eval(e.rhs)+")";
|
||||
case eq: return eval(e.lhs)+".eq("+eval(e.rhs)+")";
|
||||
case neq: return eval(e.lhs)+".neq("+eval(e.rhs)+")";
|
||||
case and: return "(($t="+eval(e.lhs)+").toboolean()? "+eval(e.rhs)+": $t)";
|
||||
case or: return "(($t="+eval(e.lhs)+").toboolean()? $t: "+eval(e.rhs)+")";
|
||||
default: throw new IllegalStateException("unknoqn binary operator: "+e.op);
|
||||
}
|
||||
}
|
||||
|
||||
private String evalFunction(FunctionExpr e) {
|
||||
return evalFuncbody(e.function);
|
||||
}
|
||||
|
||||
private String evalTable(TableConstructor e) {
|
||||
StringBuffer named = new StringBuffer();
|
||||
StringBuffer numbered = new StringBuffer();
|
||||
LSExpression varargsLastListValue = null;
|
||||
for ( int i=0, n=e.fields.size(); i<n; i++ ) {
|
||||
LSField f = e.fields.get(i);
|
||||
switch ( f.type ) {
|
||||
case keyValue:
|
||||
LSField.KeyValue k = (LSField.KeyValue) f;
|
||||
named.append( eval(k.key)+","+eval(k.value)+",");
|
||||
break;
|
||||
case nameValue:
|
||||
LSField.NameValue nv = (LSField.NameValue) f;
|
||||
named.append( "valueOf(\""+nv.name+"\"),"+eval(nv.value)+",");
|
||||
break;
|
||||
case listValue:
|
||||
LSField.ListValue l = (LSField.ListValue) f;
|
||||
int nr = l.value.getNumReturns();
|
||||
if ( i<n-1 && (nr==1) )
|
||||
numbered.append( eval(l.value)+",");
|
||||
else
|
||||
varargsLastListValue = l.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// TODO: generated more targeted constructor
|
||||
return "tableOf("
|
||||
+(named .length()>0? "new LuaValue[] {"+named +"}": "null")+","
|
||||
+(numbered.length()>0? "new LuaValue[] {"+numbered+"}": "null")
|
||||
+(varargsLastListValue!=null? ","+eval(varargsLastListValue): "")+")";
|
||||
}
|
||||
|
||||
private String evalNumber(NumberConstant e) {
|
||||
// TODO: internalize constants
|
||||
return "valueOf("+e.value+")";
|
||||
}
|
||||
|
||||
private String evalString(StringConstant e) {
|
||||
// TODO: internalize constants
|
||||
return "valueOf("+toStrValueInitializer(e.bytes)+")";
|
||||
}
|
||||
|
||||
private String toStrValueInitializer(byte[] bytes) {
|
||||
int n = bytes.length;
|
||||
StringBuffer sb = new StringBuffer(n+2);
|
||||
|
||||
// check for characters beyond ascii 128
|
||||
for ( int i=0; i<n; i++ )
|
||||
if (bytes[i]<0) {
|
||||
sb.append( "new byte[]{" );
|
||||
for ( int j=0; j<n; j++ ) {
|
||||
if ( j>0 ) sb.append(",");
|
||||
byte b = bytes[j];
|
||||
switch ( b ) {
|
||||
case '\n': sb.append( "'\\n'" ); break;
|
||||
case '\r': sb.append( "'\\r'" ); break;
|
||||
case '\t': sb.append( "'\\t'" ); break;
|
||||
case '\\': sb.append( "'\\\\'" ); break;
|
||||
default:
|
||||
if ( b >= ' ' ) {
|
||||
sb.append( '\'');
|
||||
sb.append( (char) b );
|
||||
sb.append( '\'');
|
||||
} else {
|
||||
sb.append( String.valueOf((int)b) );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
sb.append( "}" );
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
sb.append('"');
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
byte b = bytes[i];
|
||||
switch ( b ) {
|
||||
case '\b': sb.append( "\\b" ); break;
|
||||
case '\f': sb.append( "\\f" ); break;
|
||||
case '\n': sb.append( "\\n" ); break;
|
||||
case '\r': sb.append( "\\r" ); break;
|
||||
case '\t': sb.append( "\\t" ); break;
|
||||
case '"': sb.append( "\\\"" ); break;
|
||||
case '\\': sb.append( "\\\\" ); break;
|
||||
default:
|
||||
if ( b >= ' ' ) {
|
||||
sb.append( (char) b ); break;
|
||||
} else {
|
||||
// convert from UTF-8
|
||||
int u = 0xff & (int) b;
|
||||
if ( u>=0xc0 && i+1<n ) {
|
||||
if ( u>=0xe0 && i+2<n ) {
|
||||
u = ((u & 0xf) << 12) | ((0x3f & bytes[i+1]) << 6) | (0x3f & bytes[i+2]);
|
||||
i+= 2;
|
||||
} else {
|
||||
u = ((u & 0x1f) << 6) | (0x3f & bytes[++i]);
|
||||
}
|
||||
}
|
||||
sb.append( "\\u" );
|
||||
sb.append( Integer.toHexString(0x10000+u).substring(1) );
|
||||
}
|
||||
}
|
||||
}
|
||||
sb.append('"');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
private String evalNameRef(NameReference v) {
|
||||
if ( v.name.isGlobal() )
|
||||
return "env.get(\""+v.name.luaname+"\")";
|
||||
else if ( v.name.isupvalue )
|
||||
return javaName(v.name)+"[0]";
|
||||
else
|
||||
return javaName(v.name);
|
||||
}
|
||||
|
||||
private String evalField(Field e) {
|
||||
return eval(e.variable)+".get(\""+e.field+"\")";
|
||||
}
|
||||
|
||||
private String evalMethod(Method e) {
|
||||
// FIXME: check api, fix this
|
||||
return eval(e.variable)+".get(\""+e.method+"\")";
|
||||
}
|
||||
|
||||
private String evalParen(Parentheses e) {
|
||||
return eval(e.expression)+".arg1()";
|
||||
}
|
||||
|
||||
private String evalIndex(Index e) {
|
||||
return eval(e.variable)+".get("+eval(e.expression)+")";
|
||||
}
|
||||
|
||||
private String evalCallFunc(CallFunction e) {
|
||||
int n = e.parameters.size();
|
||||
boolean isVarargsReturn = e.numReturns < 0 || e.numReturns > 1;
|
||||
boolean isVarargsCall = n>0 && e.parameters.get(n-1).getNumReturns() < 0;
|
||||
String base = eval(e.variable);
|
||||
if ( n <= 3 && !isVarargsReturn && !isVarargsCall ) {
|
||||
return base+".call("+evalParamList(e.parameters)+")";
|
||||
} else {
|
||||
String coerce = e.numReturns==1? ".arg1()": "";
|
||||
switch ( n ) {
|
||||
case 0:
|
||||
return base+".invoke()"+coerce;
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
return base+".invoke("+evalParamList(e.parameters)+")"+coerce;
|
||||
default:
|
||||
if ( isVarargsCall ) {
|
||||
LSExpression last = e.parameters.remove(n-1);
|
||||
return base+".invoke(new LuaValue[]{"+evalParamList(e.parameters)+"},"+eval(last)+")"+coerce;
|
||||
} else {
|
||||
return base+".invoke(new LuaValue[]{"+evalParamList(e.parameters)+"})"+coerce;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String evalCallMeth(CallMethod e) {
|
||||
int n = e.parameters.size();
|
||||
String base = eval(e.variable);
|
||||
if ( n <= 3 && e.numReturns == 0 || e.numReturns == 1 ) {
|
||||
return base+".method(\""+e.method+"\""+(e.parameters.size()>0? ",": "")+evalParamList(e.parameters)+")";
|
||||
} else {
|
||||
return base+".invokemethod(\""+e.method+"\",new LuaValue[]{"+evalParamList(e.parameters)+"})";
|
||||
}
|
||||
}
|
||||
|
||||
private String evalVarargs(VarargsRef e) {
|
||||
switch ( e.numReturns ) {
|
||||
case 0: return "NIL";
|
||||
case 1: return "$args.arg1()";
|
||||
default: return "$args";
|
||||
}
|
||||
}
|
||||
|
||||
private String evalParamList(List<LSExpression> parameters) {
|
||||
if ( parameters == null || parameters.size() == 0 )
|
||||
return "";
|
||||
StringBuffer p = new StringBuffer();
|
||||
for ( int i=0, n=parameters.size(); i<n; i++ ) {
|
||||
if (i>0) p.append(",");
|
||||
p.append( eval( parameters.get(i) ) );
|
||||
}
|
||||
return p.toString();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------
|
||||
// write individual strings and lines
|
||||
//-------------------------------------------
|
||||
|
||||
|
||||
private void writeindent() {
|
||||
for ( int i=0; i<indent; i++ )
|
||||
sb.append( " " );
|
||||
}
|
||||
private void write( String str ) {
|
||||
sb.append( str );
|
||||
}
|
||||
private void writeln() {
|
||||
sb.append( '\n' );
|
||||
}
|
||||
private void writeln( String line ) {
|
||||
writeindent();
|
||||
write( line );
|
||||
writeln();
|
||||
}
|
||||
|
||||
}
|
||||
96
src/jse/org/luaj/vm2/luajc/LuaJCompiler.java
Normal file
96
src/jse/org/luaj/vm2/luajc/LuaJCompiler.java
Normal file
@@ -0,0 +1,96 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.luajc;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.tools.JavaCompiler;
|
||||
import javax.tools.JavaFileObject;
|
||||
import javax.tools.StandardJavaFileManager;
|
||||
import javax.tools.StandardLocation;
|
||||
import javax.tools.ToolProvider;
|
||||
import javax.tools.JavaCompiler.CompilationTask;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.luajc.antlr.AntlrLuaJCompiler;
|
||||
|
||||
public class LuaJCompiler {
|
||||
|
||||
public static LuaValue compile( InputStream luaSource, String chunkName, LuaValue env ) throws Exception {
|
||||
String java = compileToJava( luaSource, chunkName );
|
||||
LuaValue chunk = javaCompile( java, chunkName );
|
||||
chunk.setfenv(env);
|
||||
return chunk;
|
||||
}
|
||||
|
||||
public static String compileToJava( InputStream luaSource, String chunkName ) throws Exception {
|
||||
return AntlrLuaJCompiler.compile( luaSource, chunkName );
|
||||
}
|
||||
|
||||
|
||||
public static LuaValue javaCompile( String java, String className) throws Exception {
|
||||
final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
|
||||
if (compiler == null) {
|
||||
LuaValue.error("no java compiler");
|
||||
}
|
||||
|
||||
// write the file
|
||||
new File("jit").mkdirs();
|
||||
File source = new File("jit/"+className+JavaFileObject.Kind.SOURCE.extension);
|
||||
PrintStream ps = new PrintStream(new FileOutputStream(source));
|
||||
ps.print(java);
|
||||
ps.close();
|
||||
|
||||
// set up output location
|
||||
Iterable<? extends File> dest = Arrays.asList(new File[] { new File("bin") });
|
||||
StandardJavaFileManager fm = compiler.getStandardFileManager( null, null, null);
|
||||
fm.setLocation(StandardLocation.CLASS_OUTPUT, dest);
|
||||
|
||||
// compile the file
|
||||
Iterable<? extends JavaFileObject> compilationUnits = fm.getJavaFileObjects(source);
|
||||
CompilationTask task = compiler.getTask(null, fm, null, null, null, compilationUnits);
|
||||
boolean success = task.call();
|
||||
|
||||
// instantiate, config and return
|
||||
if (success) {
|
||||
// compile sub-prototypes
|
||||
// if ( p.p != null ) {
|
||||
// for ( int i=0, n=p.p.length; i<n; i++ ) {
|
||||
// if ( ! (p.p[i] instanceof JitPrototype) )
|
||||
// p.p[i] = jitCompile( p.p[i] );
|
||||
// }
|
||||
// }
|
||||
|
||||
// create JitPrototype instance
|
||||
Class clazz = Class.forName(className);
|
||||
Object instance = clazz.newInstance();
|
||||
LuaValue value = (LuaValue) instance;
|
||||
return value;
|
||||
}
|
||||
return LuaValue.error("compile task failed");
|
||||
}
|
||||
|
||||
}
|
||||
60
src/jse/org/luaj/vm2/luajc/antlr/AntlrLuaJCompiler.java
Normal file
60
src/jse/org/luaj/vm2/luajc/antlr/AntlrLuaJCompiler.java
Normal file
@@ -0,0 +1,60 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.luajc.antlr;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.antlr.runtime.ANTLRInputStream;
|
||||
import org.antlr.runtime.CommonTokenStream;
|
||||
import org.antlr.runtime.RecognitionException;
|
||||
import org.luaj.vm2.luajc.JavaCodeGenerator;
|
||||
import org.luaj.vm2.luajc.antlr.LuaLexer;
|
||||
import org.luaj.vm2.luajc.antlr.LuaParser;
|
||||
import org.luaj.vm2.luajc.lst.LSChunk;
|
||||
|
||||
/**
|
||||
* Implementation of lua-to-java compiler using antlr
|
||||
*/
|
||||
public class AntlrLuaJCompiler {
|
||||
|
||||
private final String chunkname;
|
||||
|
||||
public AntlrLuaJCompiler(String chunkname) {
|
||||
this.chunkname = chunkname;
|
||||
}
|
||||
|
||||
public static String compile(InputStream script, String chunkname) throws RecognitionException, IOException {
|
||||
return new AntlrLuaJCompiler(chunkname).docompile( script );
|
||||
}
|
||||
|
||||
private String docompile(InputStream script) throws RecognitionException, IOException {
|
||||
|
||||
ANTLRInputStream input = new ANTLRInputStream(script);
|
||||
LuaLexer lexer = new LuaLexer(input);
|
||||
CommonTokenStream tokens = new CommonTokenStream(lexer);
|
||||
LuaParser parser = new LuaParser(tokens);
|
||||
LSChunk chunk = parser.chunk(chunkname);
|
||||
return new JavaCodeGenerator().toJava( chunk );
|
||||
}
|
||||
|
||||
}
|
||||
301
src/jse/org/luaj/vm2/luajc/antlr/Lua.g
Normal file
301
src/jse/org/luaj/vm2/luajc/antlr/Lua.g
Normal file
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* Lua 5.1 grammar producing typed parse tree.
|
||||
*
|
||||
* Adapted from the grammar produced by Nicolai Mainiero, May 2007
|
||||
*
|
||||
* see http://www.antlr.org/grammar/list
|
||||
*/
|
||||
|
||||
grammar Lua;
|
||||
|
||||
options {
|
||||
backtrack=true;
|
||||
}
|
||||
|
||||
@header {
|
||||
package org.luaj.vm2.luajc.antlr;
|
||||
import org.luaj.vm2.luajc.lst.*;
|
||||
}
|
||||
@lexer::header {
|
||||
package org.luaj.vm2.luajc.antlr;
|
||||
}
|
||||
@members {
|
||||
LSChunk CHK = null;
|
||||
}
|
||||
|
||||
chunk [String chunkname] returns [LSChunk c]
|
||||
@init { CHK = new LSChunk(chunkname); }
|
||||
: funcblock[CHK.function] {$c=CHK;}
|
||||
;
|
||||
|
||||
funcblock [LSFunction f]
|
||||
scope { LSFunction func; }
|
||||
@init { $funcblock::func = $f; }
|
||||
: {CHK.pushScope("body");} block {$f.setStatements($block.stats); CHK.popScope("body"); }
|
||||
;
|
||||
|
||||
block returns [List<LSStatement> stats]
|
||||
@init { $stats = new ArrayList<LSStatement>(); }
|
||||
: (stat {$stats.add($stat.s);} (';')?)*
|
||||
(laststat {$stats.add($laststat.s);} (';')?)?
|
||||
;
|
||||
|
||||
stat returns [LSStatement s]
|
||||
@init { Name name=null; List<Name> names=null; }
|
||||
: varlist1 '=' explist1 { $s=LSStatement.varAssignStatement($varlist1.vars,$explist1.exprs, CHK.peekScope(), $funcblock::func); }
|
||||
| functioncall { $s=LSStatement.functionCallStatement($functioncall.v); }
|
||||
| 'do' {CHK.pushScope("do");} block {CHK.popScope("do");} 'end'
|
||||
{ $s=LSStatement.doBlockStatement($block.stats); }
|
||||
| 'while' exp 'do' {CHK.pushScope("while");} block {CHK.popScope("while");} 'end'
|
||||
{ $s=LSStatement.whileLoopStatement($exp.e,$block.stats); }
|
||||
| 'repeat' {CHK.pushScope("repeat");} block {CHK.popScope("repeat");} 'until' exp
|
||||
{ $s=LSStatement.repeatUntilStatement($block.stats,$exp.e); }
|
||||
| ifstat { $s=$ifstat.s; }
|
||||
| 'for' {CHK.pushScope("fori");} NAME {name=CHK.declare($NAME.text);} '=' e1=exp ',' e2=exp (',' e3=exp)? 'do' {CHK.pushScope("foriblock");} block {CHK.popScope("foriblock");} 'end'
|
||||
{ $s=LSStatement.forLoopStatement(name,$e1.e,$e2.e,$e3.e,$block.stats,CHK.peekScope()); CHK.popScope("fori"); }
|
||||
| 'for' {CHK.pushScope("for");} namelist {names=CHK.declare($namelist.names);} 'in' explist1 'do' {CHK.pushScope("forblock");} block {CHK.popScope("forblock");}'end'
|
||||
{ $s=LSStatement.forListStatement(names,$explist1.exprs,$block.stats,CHK.peekScope(), $funcblock::func); CHK.popScope("for");}
|
||||
| 'function' funcname funcbody { $s=LSStatement.varFunctionStatement($funcname.v,$funcbody.f); }
|
||||
| 'local' 'function' NAME {name=CHK.declare($NAME.text);} funcbody
|
||||
{ $s=LSStatement.localFunctionStatement(name,$funcbody.f); }
|
||||
| 'local' namelist ('=' explist1)? { $s=LSStatement.localAssignStatement(CHK.declare($namelist.names),$explist1.exprs,CHK.peekScope(), $funcblock::func); }
|
||||
;
|
||||
|
||||
ifstat returns [LSStatement s]
|
||||
scope { LSIfStatement current; }
|
||||
: 'if' e1=exp 'then' {CHK.pushScope("if");} b1=block {$ifstat::current=new LSIfStatement($e1.e,$b1.stats); CHK.popScope("if");}
|
||||
('elseif' e2=exp 'then' {CHK.pushScope("elseif");} b2=block {$ifstat::current.addElseif($e2.e,$b2.stats); CHK.popScope("elseif");})*
|
||||
('else' {CHK.pushScope("else");} b3=block {$ifstat::current.addElse($b3.stats); CHK.popScope("else");})?
|
||||
'end'
|
||||
{ $s=$ifstat::current; }
|
||||
;
|
||||
|
||||
laststat returns [LSStatement s]
|
||||
: 'return' (e=explist1)? {$s=LSStatement.returnStatement($funcblock::func,$e.exprs);}
|
||||
| 'break' {$s=LSStatement.breakStatement();}
|
||||
;
|
||||
|
||||
funcname returns [LSVariable v]
|
||||
: n=NAME {$v = LSVariable.nameVariable(CHK.reference($n.text,$funcblock::func));}
|
||||
('.' n2=NAME {$v = $v.fieldVariable($n2.text);})*
|
||||
(':' n3=NAME {$v = $v.methodVariable($n3.text);})?
|
||||
;
|
||||
|
||||
varlist1 returns [List<LSVariable> vars]
|
||||
@init { $vars = new ArrayList<LSVariable>(); }
|
||||
: v1=var {$vars.add($v1.v);}
|
||||
(',' v2=var {$vars.add($v2.v);})*
|
||||
;
|
||||
|
||||
namelist returns [List<String> names]
|
||||
: n=NAME {$names=new ArrayList<String>(); $names.add($n.text);}
|
||||
(',' n2=NAME {$names.add($n2.text);})*
|
||||
;
|
||||
|
||||
explist1 returns [List<LSExpression> exprs]
|
||||
@init { $exprs = new ArrayList<LSExpression>(); }
|
||||
: (e1=exp ',' {$exprs.add($e1.e);})*
|
||||
e2=exp {$exprs.add($e2.e);}
|
||||
;
|
||||
|
||||
exp returns [LSExpression e]
|
||||
: ('nil' { $e=LSExpression.ENIL; }
|
||||
| 'false' { $e=LSExpression.EFALSE; }
|
||||
| 'true' { $e=LSExpression.ETRUE; }
|
||||
| number { $e=LSExpression.numberExpression($number.text); }
|
||||
| string { $e=$string.e; }
|
||||
| '...' { $e=LSExpression.varargsRef(); $funcblock::func.setUsesVarargs(); }
|
||||
| function { $e=LSExpression.functionExpression($function.f); }
|
||||
| prefixexp { $e=$prefixexp.v; }
|
||||
| tableconstructor { $e=$tableconstructor.e;}
|
||||
| unop e1=exp { $e=LSExpression.unopExpression($unop.op,$e1.e,CHK.peekScope());}
|
||||
) (binop e2=exp { $e=LSExpression.binopExpression($e,$binop.op,$e2.e,CHK.peekScope());})*
|
||||
;
|
||||
|
||||
var returns [LSVariable v]
|
||||
scope { LSVariable current; }
|
||||
: (n=NAME {$var::current=LSVariable.nameVariable(CHK.reference($n.text,$funcblock::func));}
|
||||
| '(' exp ')' {$var::current=LSVariable.parenthesesVariable($exp.e);} varSuffix)
|
||||
varSuffix*
|
||||
{$v=$var::current;}
|
||||
;
|
||||
|
||||
varSuffix
|
||||
: (n=nameAndArgs[$var::current] {$var::current=$n.v;})*
|
||||
('[' e=exp ']' {$var::current=$var::current.indexVariable($e.e);}
|
||||
| '.' n2=NAME {$var::current=$var::current.fieldVariable($n2.text);}
|
||||
)
|
||||
;
|
||||
|
||||
prefixexp returns [LSVariable v]
|
||||
scope { LSVariable current; }
|
||||
: e=varOrExp {$prefixexp::current=$e.v;}
|
||||
(n=nameAndArgs[$prefixexp::current] {$prefixexp::current=$n.v;})*
|
||||
{$v=$prefixexp::current;}
|
||||
;
|
||||
|
||||
functioncall returns [LSVariable v]
|
||||
scope { LSVariable current; }
|
||||
: e=varOrExp {$functioncall::current=$e.v;}
|
||||
(n=nameAndArgs[$functioncall::current] {$functioncall::current=$n.v;})+
|
||||
{$v=$functioncall::current;}
|
||||
;
|
||||
|
||||
varOrExp returns [LSVariable v]
|
||||
: var {$v=$var.v;}
|
||||
| '(' exp ')' {$v=LSVariable.parenthesesVariable($exp.e);}
|
||||
;
|
||||
|
||||
nameAndArgs [LSVariable vin] returns [LSVariable v]
|
||||
@init { String method=null; }
|
||||
: (':' n=NAME {method=$n.text;})?
|
||||
a=args {$v=((method==null)?
|
||||
$vin.callFuncVariable($a.exprs):
|
||||
$vin.callMethVariable(method,$a.exprs));}
|
||||
;
|
||||
|
||||
args returns [List<LSExpression> exprs]
|
||||
@init { $exprs = new ArrayList<LSExpression>(); }
|
||||
: '(' (e=explist1 {$exprs=$e.exprs;})? ')'
|
||||
| t=tableconstructor {$exprs.add($t.e);}
|
||||
| s=string {$exprs.add($s.e);}
|
||||
;
|
||||
|
||||
function returns [LSFunction f]
|
||||
: 'function' b=funcbody {$f = $b.f;}
|
||||
;
|
||||
|
||||
funcbody returns [LSFunction f]
|
||||
@init {
|
||||
$f = new LSFunction();
|
||||
$funcblock::func.functions.add($f);
|
||||
}
|
||||
: {CHK.pushScope("func",true);} '(' (parlist1 [f])? ')' funcblock[f] 'end' {CHK.popScope("func");}
|
||||
;
|
||||
|
||||
parlist1 [LSFunction f]
|
||||
: namelist {f.setParameterNames(CHK.declare($namelist.names));} (',' '...' {f.isvararg=true;})?
|
||||
| '...' {f.isvararg=true;}
|
||||
;
|
||||
|
||||
tableconstructor returns [LSExpression e]
|
||||
@init { List<LSField> fields = new ArrayList<LSField>(); }
|
||||
: '{' (fieldlist[fields])? '}' {$e=LSExpression.tableConstructorExpression(fields);}
|
||||
;
|
||||
|
||||
fieldlist [List<LSField> fields]
|
||||
: field [fields] (fieldsep field [fields])* (fieldsep)?
|
||||
;
|
||||
|
||||
field [List<LSField> fields]
|
||||
: '[' k=exp ']' '=' e=exp {$fields.add(LSField.keyValueField($k.e,$e.e));}
|
||||
| n=NAME '=' e=exp {$fields.add(LSField.nameValueField($n.text,$e.e));}
|
||||
| e=exp {$fields.add(LSField.valueField($e.e));}
|
||||
;
|
||||
|
||||
fieldsep
|
||||
: ','
|
||||
| ';'
|
||||
;
|
||||
|
||||
binop returns [BinOp op]
|
||||
: '+' {$op=BinOp.ADD;}
|
||||
| '-' {$op=BinOp.SUB;}
|
||||
| '*' {$op=BinOp.MUL;}
|
||||
| '/' {$op=BinOp.DIV;}
|
||||
| '^' {$op=BinOp.POW;}
|
||||
| '%' {$op=BinOp.MOD;}
|
||||
| '..' {$op=BinOp.CONCAT;}
|
||||
| '<' {$op=BinOp.LT;}
|
||||
| '<=' {$op=BinOp.LTEQ;}
|
||||
| '>' {$op=BinOp.GT;}
|
||||
| '>=' {$op=BinOp.GTEQ;}
|
||||
| '==' {$op=BinOp.EQ;}
|
||||
| '~=' {$op=BinOp.NEQ;}
|
||||
| 'and' {$op=BinOp.AND; $funcblock::func.hasandlogic=true;}
|
||||
| 'or' {$op=BinOp.OR; $funcblock::func.hasorlogic=true;}
|
||||
;
|
||||
|
||||
unop returns [UnOp op]
|
||||
: '-' {$op=UnOp.NEG;}
|
||||
| 'not' {$op=UnOp.NOT;}
|
||||
| '#' {$op=UnOp.LEN;}
|
||||
;
|
||||
|
||||
number
|
||||
: ('-')? INT
|
||||
| ('-')? FLOAT1
|
||||
| ('-')? FLOAT2
|
||||
| ('-')? FLOAT3
|
||||
| ('-')? EXP
|
||||
| HEX
|
||||
;
|
||||
|
||||
string returns [LSExpression e]
|
||||
: NORMALSTRING {$e=LSExpression.normalStringExpression($NORMALSTRING.text);}
|
||||
| CHARSTRING {$e=LSExpression.charStringExpression($CHARSTRING.text);}
|
||||
| LONGSTRING {$e=LSExpression.longStringExpression($LONGSTRING.text);}
|
||||
;
|
||||
|
||||
|
||||
// LEXER
|
||||
|
||||
|
||||
NAME :('a'..'z'|'A'..'Z'|'_')(options{greedy=true;}: 'a'..'z'|'A'..'Z'|'_'|'0'..'9')*
|
||||
;
|
||||
|
||||
INT : ('0'..'9')+;
|
||||
|
||||
FLOAT1 :'.' INT ;
|
||||
|
||||
FLOAT2 :INT '.' ;
|
||||
|
||||
FLOAT3 :INT '.' INT ;
|
||||
|
||||
EXP : (INT | FLOAT1 | FLOAT2 | FLOAT3) ('E'|'e') ('-'|'+')? INT;
|
||||
|
||||
HEX :'0' ('x' | 'X') ('0'..'9'| 'a'..'f' | 'A'..'F')+ ;
|
||||
|
||||
|
||||
|
||||
NORMALSTRING
|
||||
: '"' ( EscapeSequence | ~('\\'|'"') )* '"'
|
||||
;
|
||||
|
||||
CHARSTRING
|
||||
: '\'' ( EscapeSequence | ~('\\'|'\'') )* '\''
|
||||
;
|
||||
|
||||
LONGSTRING
|
||||
: '['('=')*'[' ( EscapeSequence | ~('\\'|']') )* ']'('=')*']'
|
||||
;
|
||||
|
||||
fragment
|
||||
EscapeSequence
|
||||
: '\\' ('a'|'b'|'f'|'n'|'r'|'t'|'v'|'\"'|'\''|'\\'|'\n')
|
||||
| DecimalEscape
|
||||
;
|
||||
|
||||
fragment
|
||||
DecimalEscape
|
||||
: '\\' ('0'..'9') (('0'..'9') ('0'..'9')?)?
|
||||
;
|
||||
|
||||
|
||||
COMMENT
|
||||
: '--[[' ( options {greedy=false;} : . )* '--]]' {skip();}
|
||||
| '--[=[' ( options {greedy=false;} : . )* '--]==]' {skip();}
|
||||
| '--[==[' ( options {greedy=false;} : . )* '--]==]' {skip();}
|
||||
| '--[===[' ( options {greedy=false;} : . )* '--]===]' {skip();}
|
||||
;
|
||||
|
||||
LINE_COMMENT
|
||||
: '--' ~('\n'|'\r')* '\r'? '\n' {skip();}
|
||||
;
|
||||
|
||||
|
||||
WS : (' '|'\t'|'\u000C') {skip();}
|
||||
;
|
||||
|
||||
NEWLINE : ('\r')? '\n' {skip();}
|
||||
;
|
||||
110
src/jse/org/luaj/vm2/luajc/antlr/Lua.tokens
Normal file
110
src/jse/org/luaj/vm2/luajc/antlr/Lua.tokens
Normal file
@@ -0,0 +1,110 @@
|
||||
T__66=66
|
||||
T__64=64
|
||||
T__29=29
|
||||
T__65=65
|
||||
T__28=28
|
||||
T__62=62
|
||||
T__27=27
|
||||
T__63=63
|
||||
T__26=26
|
||||
T__25=25
|
||||
T__24=24
|
||||
T__23=23
|
||||
T__22=22
|
||||
T__21=21
|
||||
T__20=20
|
||||
T__61=61
|
||||
T__60=60
|
||||
FLOAT3=8
|
||||
FLOAT2=7
|
||||
FLOAT1=6
|
||||
T__55=55
|
||||
T__56=56
|
||||
T__57=57
|
||||
NAME=4
|
||||
T__58=58
|
||||
T__51=51
|
||||
T__52=52
|
||||
T__53=53
|
||||
T__54=54
|
||||
EXP=9
|
||||
HEX=10
|
||||
T__59=59
|
||||
DecimalEscape=15
|
||||
COMMENT=16
|
||||
T__50=50
|
||||
T__42=42
|
||||
T__43=43
|
||||
T__40=40
|
||||
T__41=41
|
||||
T__46=46
|
||||
T__47=47
|
||||
T__44=44
|
||||
T__45=45
|
||||
LINE_COMMENT=17
|
||||
T__48=48
|
||||
T__49=49
|
||||
CHARSTRING=12
|
||||
INT=5
|
||||
LONGSTRING=13
|
||||
T__30=30
|
||||
NORMALSTRING=11
|
||||
T__31=31
|
||||
T__32=32
|
||||
WS=18
|
||||
T__33=33
|
||||
T__34=34
|
||||
NEWLINE=19
|
||||
T__35=35
|
||||
T__36=36
|
||||
T__37=37
|
||||
T__38=38
|
||||
T__39=39
|
||||
EscapeSequence=14
|
||||
'..'=56
|
||||
'end'=23
|
||||
'#'=66
|
||||
'>='=60
|
||||
'=='=61
|
||||
'/'=53
|
||||
'then'=33
|
||||
'>'=59
|
||||
'repeat'=25
|
||||
';'=20
|
||||
'='=21
|
||||
'return'=36
|
||||
'for'=27
|
||||
'+'=50
|
||||
')'=45
|
||||
'function'=30
|
||||
'.'=38
|
||||
'^'=54
|
||||
'%'=55
|
||||
'do'=22
|
||||
'elseif'=34
|
||||
'true'=42
|
||||
'}'=49
|
||||
'else'=35
|
||||
'and'=63
|
||||
'break'=37
|
||||
'{'=48
|
||||
'...'=43
|
||||
'~='=62
|
||||
'nil'=40
|
||||
'until'=26
|
||||
'<='=58
|
||||
'false'=41
|
||||
'<'=57
|
||||
'if'=32
|
||||
'not'=65
|
||||
':'=39
|
||||
'('=44
|
||||
'or'=64
|
||||
'*'=52
|
||||
'-'=51
|
||||
'['=46
|
||||
'while'=24
|
||||
'local'=31
|
||||
','=28
|
||||
'in'=29
|
||||
']'=47
|
||||
3814
src/jse/org/luaj/vm2/luajc/antlr/LuaLexer.java
Normal file
3814
src/jse/org/luaj/vm2/luajc/antlr/LuaLexer.java
Normal file
File diff suppressed because it is too large
Load Diff
5168
src/jse/org/luaj/vm2/luajc/antlr/LuaParser.java
Normal file
5168
src/jse/org/luaj/vm2/luajc/antlr/LuaParser.java
Normal file
File diff suppressed because it is too large
Load Diff
63
src/jse/org/luaj/vm2/luajc/lst/BinOp.java
Normal file
63
src/jse/org/luaj/vm2/luajc/lst/BinOp.java
Normal file
@@ -0,0 +1,63 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.luajc.lst;
|
||||
|
||||
|
||||
public class BinOp {
|
||||
// unary precedence is between POW and MUL
|
||||
public static final int UNARY_PRECEDENCE = 7;
|
||||
|
||||
public enum Type {
|
||||
pow,mul,div,mod,add,sub,concat,lt,lteq,gt,gteq,eq,neq,and,or,
|
||||
}
|
||||
|
||||
public static final BinOp POW = new BinOp(Type.pow, 8, true, "^");
|
||||
public static final BinOp MUL = new BinOp(Type.mul, 6, false, "*");
|
||||
public static final BinOp DIV = new BinOp(Type.div, 6, false, "/");
|
||||
public static final BinOp MOD = new BinOp(Type.mod, 6, false, "%");
|
||||
public static final BinOp ADD = new BinOp(Type.add, 5, false, "+");
|
||||
public static final BinOp SUB = new BinOp(Type.sub, 5, false, "-");
|
||||
public static final BinOp CONCAT = new BinOp(Type.concat, 4, true, "..");
|
||||
public static final BinOp LT = new BinOp(Type.lt, 3, false, "<");
|
||||
public static final BinOp LTEQ = new BinOp(Type.lteq, 3, false, "<=");
|
||||
public static final BinOp GT = new BinOp(Type.gt, 3, false, ">");
|
||||
public static final BinOp GTEQ = new BinOp(Type.gteq, 3, false, ">=");
|
||||
public static final BinOp EQ = new BinOp(Type.eq, 3, false, "==");
|
||||
public static final BinOp NEQ = new BinOp(Type.neq, 3, false, "~=");
|
||||
public static final BinOp AND = new BinOp(Type.and, 2, true, "and");
|
||||
public static final BinOp OR = new BinOp(Type.or, 1, true, "or");
|
||||
|
||||
public final Type type;
|
||||
public final int precedence;
|
||||
public final boolean isrightassoc;
|
||||
public final String luaop;
|
||||
|
||||
private BinOp(Type type, int precedence, boolean isrightassoc, String luaop) {
|
||||
super();
|
||||
this.type = type;
|
||||
this.precedence = precedence;
|
||||
this.isrightassoc = isrightassoc;
|
||||
this.luaop = luaop;
|
||||
}
|
||||
|
||||
public String toString() { return luaop; }
|
||||
}
|
||||
106
src/jse/org/luaj/vm2/luajc/lst/LSChunk.java
Normal file
106
src/jse/org/luaj/vm2/luajc/lst/LSChunk.java
Normal file
@@ -0,0 +1,106 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.luajc.lst;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/* A Lua Source Chunk */
|
||||
public class LSChunk {
|
||||
public static final boolean SCOPES = System.getProperty("SCOPES")!=null;
|
||||
|
||||
public final String chunkname;
|
||||
public final LSFunction function;
|
||||
public Scope scope;
|
||||
|
||||
public LSChunk( String chunkname ) {
|
||||
this.chunkname = chunkname;
|
||||
this.function = new LSFunction( true );
|
||||
this.scope = null;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "@"+chunkname+": "+function;
|
||||
}
|
||||
|
||||
/** push a block scope onto the name scope stack */
|
||||
public void pushScope(String name) {
|
||||
scope = new Scope(scope, false);
|
||||
if(SCOPES)System.out.println(space(scope)+"push "+name+" scope="+scope);
|
||||
|
||||
}
|
||||
|
||||
/** push a function scope onto the name scope stack */
|
||||
public void pushScope(String name,boolean isFunction) {
|
||||
scope = new Scope(scope, isFunction);
|
||||
if(SCOPES)System.out.println(space(scope)+"push "+name+" scope="+scope);
|
||||
}
|
||||
|
||||
/** pop a scope from the scope stack */
|
||||
public Scope popScope(String name) {
|
||||
Scope s = scope;
|
||||
scope = scope.parent;
|
||||
if(SCOPES)System.out.println(space(s)+"pop "+name+" scope="+scope);
|
||||
return s;
|
||||
}
|
||||
|
||||
/** return the current scope */
|
||||
public Scope peekScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
/** Declare a single name in the current scope, and return the Name element for it */
|
||||
public Name declare(String name) {
|
||||
Name n = scope.declare( name );
|
||||
if(SCOPES)System.out.println(space(scope)+" declared "+n+" scope="+scope);
|
||||
return n;
|
||||
}
|
||||
|
||||
/** Declare a list of names in the current scope, and return List of Name for them */
|
||||
public List<Name> declare(List<String> names) {
|
||||
List<Name> results = new ArrayList<Name>(names.size());
|
||||
for ( String s : names )
|
||||
results.add( declare(s) );
|
||||
return results;
|
||||
}
|
||||
|
||||
/** Reference a name, and find either the local scope within the function, the upvalue, or a global name
|
||||
* @param func */
|
||||
public Name reference(String name, LSFunction func) {
|
||||
Name n = scope.reference(name);
|
||||
if ("arg".equals(name) && n.isGlobal() && func.isvararg && !scope.isMainChunkScope()) {
|
||||
n = scope.declare(name);
|
||||
func.setHasArg();
|
||||
}
|
||||
if(SCOPES)System.out.println(space(scope)+" reference "+n+" scope="+scope);
|
||||
return n;
|
||||
}
|
||||
|
||||
/** Print out indentation for a scope */
|
||||
private static final String ws = " ";
|
||||
private String space(Scope i) {
|
||||
return ws.substring(0,i.level*2);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
267
src/jse/org/luaj/vm2/luajc/lst/LSExpression.java
Normal file
267
src/jse/org/luaj/vm2/luajc/lst/LSExpression.java
Normal file
@@ -0,0 +1,267 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.luajc.lst;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.List;
|
||||
|
||||
public class LSExpression {
|
||||
public enum Type {
|
||||
unop,
|
||||
binop,
|
||||
functionExpr,
|
||||
tableConstructor,
|
||||
nilConstant,
|
||||
trueConstant,
|
||||
falseConstant,
|
||||
varargsRef,
|
||||
numberConstant,
|
||||
stringConstant,
|
||||
|
||||
// variable types
|
||||
nameVariable,
|
||||
fieldVariable,
|
||||
methodVariable,
|
||||
parenthesesVariable,
|
||||
indexVariable,
|
||||
callFunctionVariable,
|
||||
callMethodVariable,
|
||||
}
|
||||
|
||||
public static final LSExpression ENIL = new LSExpression(Type.nilConstant); // nil
|
||||
public static final LSExpression EFALSE = new LSExpression(Type.falseConstant); // false
|
||||
public static final LSExpression ETRUE = new LSExpression(Type.trueConstant); // true
|
||||
|
||||
public final Type type;
|
||||
|
||||
LSExpression(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static LSExpression functionExpression(LSFunction function) {
|
||||
return new FunctionExpr(function);
|
||||
}
|
||||
|
||||
public static LSExpression unopExpression(UnOp unop, LSExpression rhs, Scope scope) {
|
||||
if ( rhs instanceof BinopExpr ) {
|
||||
BinopExpr b = (BinopExpr) rhs;
|
||||
if ( BinOp.UNARY_PRECEDENCE > b.op.precedence )
|
||||
return binopExpression( unopExpression( unop, b.lhs, scope ), b.op, b.rhs, scope );
|
||||
}
|
||||
return new UnopExpr( unop, rhs );
|
||||
}
|
||||
|
||||
public static LSExpression binopExpression(LSExpression lhs, BinOp binop, LSExpression rhs, Scope scope) {
|
||||
if ( lhs instanceof UnopExpr ) {
|
||||
UnopExpr u = (UnopExpr) lhs;
|
||||
if ( binop.precedence > BinOp.UNARY_PRECEDENCE )
|
||||
return unopExpression( u.op, binopExpression( u.rhs, binop, rhs, scope ), scope );
|
||||
}
|
||||
// TODO: cumulate string concatenations together
|
||||
// TODO: constant folding
|
||||
if ( lhs instanceof BinopExpr ) {
|
||||
BinopExpr b = (BinopExpr) lhs;
|
||||
if ( (binop.precedence > b.op.precedence) ||
|
||||
((binop.precedence == b.op.precedence) && binop.isrightassoc) )
|
||||
return binopExpression( b.lhs, b.op, binopExpression( b.rhs, binop, rhs, scope ), scope );
|
||||
}
|
||||
if ( rhs instanceof BinopExpr ) {
|
||||
BinopExpr b = (BinopExpr) rhs;
|
||||
if ( (binop.precedence > b.op.precedence) ||
|
||||
((binop.precedence == b.op.precedence) && ! binop.isrightassoc) )
|
||||
return binopExpression( binopExpression( lhs, binop, b.lhs, scope ), b.op, b.rhs, scope );
|
||||
}
|
||||
return new BinopExpr( lhs, binop, rhs, scope );
|
||||
}
|
||||
|
||||
public static LSExpression numberExpression(String number) {
|
||||
return new NumberConstant(number);
|
||||
}
|
||||
|
||||
public static LSExpression tableConstructorExpression(List<LSField> fields) {
|
||||
return new TableConstructor( fields );
|
||||
}
|
||||
|
||||
public static LSExpression normalStringExpression(String luaSourceString) {
|
||||
return new StringConstant(luaSourceString.substring(1,luaSourceString.length()-1));
|
||||
}
|
||||
|
||||
public static LSExpression charStringExpression(String luaSourceString) {
|
||||
return new StringConstant(luaSourceString.substring(1,luaSourceString.length()-1));
|
||||
}
|
||||
|
||||
public static LSExpression longStringExpression(String luaSourceString) {
|
||||
luaSourceString = luaSourceString.substring(1,luaSourceString.length()-1);
|
||||
luaSourceString = luaSourceString.substring(luaSourceString.indexOf('[',1)+1, luaSourceString.lastIndexOf(']'));
|
||||
return new StringConstant(luaSourceString);
|
||||
}
|
||||
|
||||
public static LSExpression varargsRef() {
|
||||
return new VarargsRef();
|
||||
}
|
||||
|
||||
/** varargs such as "..." */
|
||||
public static class VarargsRef extends LSExpression {
|
||||
public int numReturns = -1;
|
||||
public VarargsRef() {
|
||||
super( Type.varargsRef );
|
||||
}
|
||||
public void setNumReturns(int i) {
|
||||
this.numReturns = i;
|
||||
}
|
||||
public int getNumReturns() {
|
||||
return numReturns;
|
||||
}
|
||||
public String toString() { return "..."; }
|
||||
}
|
||||
|
||||
/** prefix expression such as "(foo)(bar)" ? */
|
||||
public static class FunctionExpr extends LSExpression {
|
||||
public final LSFunction function;
|
||||
public FunctionExpr( LSFunction function) {
|
||||
super( Type.functionExpr );
|
||||
this.function = function;
|
||||
}
|
||||
public String toString() { return function.toString(); }
|
||||
}
|
||||
|
||||
/** unary operator such as "not foo" */
|
||||
public static class UnopExpr extends LSExpression {
|
||||
public final UnOp op;
|
||||
public final LSExpression rhs;
|
||||
public UnopExpr( UnOp op, LSExpression rhs ) {
|
||||
super( Type.unop );
|
||||
this.op = op;
|
||||
this.rhs = rhs;
|
||||
}
|
||||
public String toString() { return op.luaop+rhs; }
|
||||
}
|
||||
|
||||
/** binary operator such as "a + b" */
|
||||
public static class BinopExpr extends LSExpression {
|
||||
public final LSExpression lhs;
|
||||
public final BinOp op;
|
||||
public final LSExpression rhs;
|
||||
public final Scope scope;
|
||||
public BinopExpr( LSExpression lhs, BinOp op, LSExpression rhs, Scope scope ) {
|
||||
super( Type.binop );
|
||||
this.lhs = lhs;
|
||||
this.op = op;
|
||||
this.rhs = rhs;
|
||||
this.scope = scope;
|
||||
}
|
||||
public String toString() { return lhs+op.luaop+rhs; }
|
||||
}
|
||||
|
||||
/** table constructor such as "{ 'foo', [0]='bar' }" */
|
||||
public static class TableConstructor extends LSExpression {
|
||||
public final List<LSField> fields;
|
||||
public TableConstructor( List<LSField> fields ) {
|
||||
super( Type.tableConstructor );
|
||||
this.fields = fields;
|
||||
int n = fields.size();
|
||||
for ( int i=0; i<n-1; i++ )
|
||||
fields.get(i).setNumReturns(1);
|
||||
if ( n>0 )
|
||||
fields.get(n-1).setNumReturns(-1);
|
||||
}
|
||||
public String toString() { return "{"+fields+"}"; }
|
||||
}
|
||||
|
||||
/** number constants such as '123', "4.56", "0x11fe */
|
||||
public static class NumberConstant extends LSExpression {
|
||||
public final Number value;
|
||||
public NumberConstant( String number ) {
|
||||
super( Type.numberConstant );
|
||||
number = number.toLowerCase();
|
||||
if ( number.startsWith("0x") ) {
|
||||
Long l = Long.parseLong(number.substring(2), 16);
|
||||
value = (l.intValue()==l.longValue()? (Number) Integer.valueOf(l.intValue()): (Number) l);
|
||||
} else {
|
||||
Double d = Double.parseDouble(number);
|
||||
value = (d.doubleValue()==(double)d.intValue()? (Number) Integer.valueOf(d.intValue()): (Number) d);
|
||||
}
|
||||
}
|
||||
public String toString() { return value.toString(); }
|
||||
}
|
||||
|
||||
/** string constants such as 'abc', "def", [[ghi]], and [==[pqr]==] */
|
||||
public static class StringConstant extends LSExpression {
|
||||
public final byte[] bytes;
|
||||
public StringConstant( String luaSourceChars ) {
|
||||
super( Type.stringConstant );
|
||||
this.bytes = unquoteLua( luaSourceChars );
|
||||
}
|
||||
public String toString() { return "\""+new String(bytes)+"\""; }
|
||||
}
|
||||
|
||||
/** Unquote lua quoted sequences, and convert to the bytes represented by the source string. */
|
||||
public static byte[] unquoteLua( String luaSourceChars ) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
char[] c = luaSourceChars.toCharArray();
|
||||
int n = c.length;
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
if ( c[i] == '\\' && i<n ) {
|
||||
switch ( c[++i] ) {
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
int d=(int) (c[i++]-'0');
|
||||
for ( int j=0; i<n && j<2 && c[i]>='0' && c[i]<='9'; i++, j++ )
|
||||
d = d * 10 + (int) (c[i]-'0');
|
||||
baos.write( (byte) d );
|
||||
--i;
|
||||
continue;
|
||||
case 'a': baos.write( (byte) 7 ); continue;
|
||||
case 'b': baos.write( (byte) '\b' ); continue;
|
||||
case 'f': baos.write( (byte) '\f' ); continue;
|
||||
case 'n': baos.write( (byte) '\n' ); continue;
|
||||
case 'r': baos.write( (byte) '\r' ); continue;
|
||||
case 't': baos.write( (byte) '\t' ); continue;
|
||||
case 'v': baos.write( (byte) 11 ); continue;
|
||||
case '"': baos.write( (byte) '"' ); continue;
|
||||
case '\'': baos.write( (byte) '\'' ); continue;
|
||||
case '\\': baos.write( (byte) '\\' ); continue;
|
||||
default: baos.write( (byte) c[i] ); break;
|
||||
}
|
||||
} else {
|
||||
baos.write( (byte) c[i] );
|
||||
}
|
||||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
/** Set number of return values, return actual number of returns in practice.
|
||||
*
|
||||
* @param i desired number of returns, or -1 for varargs.
|
||||
*/
|
||||
public void setNumReturns(int i) {
|
||||
}
|
||||
|
||||
/** Get actual number of returns for this subexpression, or -1 for varargs.
|
||||
*
|
||||
* @return actual number of returns, or -1 for varargs.
|
||||
*/
|
||||
public int getNumReturns() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
92
src/jse/org/luaj/vm2/luajc/lst/LSField.java
Normal file
92
src/jse/org/luaj/vm2/luajc/lst/LSField.java
Normal file
@@ -0,0 +1,92 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.luajc.lst;
|
||||
|
||||
public class LSField {
|
||||
public enum Type {
|
||||
keyValue,
|
||||
nameValue,
|
||||
listValue,
|
||||
}
|
||||
|
||||
public final Type type;
|
||||
|
||||
LSField(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static LSField keyValueField(LSExpression key, LSExpression value) {
|
||||
return new KeyValue(key, value);
|
||||
}
|
||||
|
||||
public static LSField nameValueField(String name, LSExpression value) {
|
||||
return new NameValue(name, value);
|
||||
}
|
||||
|
||||
public static LSField valueField(LSExpression value) {
|
||||
return new ListValue(value);
|
||||
}
|
||||
|
||||
/** table constructor field with an explicit key index value */
|
||||
public static class KeyValue extends LSField {
|
||||
public final LSExpression key;
|
||||
public final LSExpression value;
|
||||
public KeyValue(LSExpression key, LSExpression value) {
|
||||
super( Type.keyValue );
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
value.setNumReturns(1);
|
||||
}
|
||||
public String toString() { return "["+key+"]="+value; }
|
||||
}
|
||||
|
||||
|
||||
/** table constructor field with an named field for key */
|
||||
public static class NameValue extends LSField {
|
||||
public final String name;
|
||||
public final LSExpression value;
|
||||
public NameValue(String name, LSExpression value) {
|
||||
super( Type.nameValue );
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
value.setNumReturns(1);
|
||||
}
|
||||
public String toString() { return name+"="+value; }
|
||||
}
|
||||
|
||||
/** table constructor field with an implied index key */
|
||||
public static class ListValue extends LSField {
|
||||
public final LSExpression value;
|
||||
public ListValue(LSExpression value) {
|
||||
super( Type.listValue );
|
||||
this.value = value;
|
||||
}
|
||||
public void setNumReturns(int i) {
|
||||
value.setNumReturns(i);
|
||||
}
|
||||
public String toString() { return value.toString(); }
|
||||
}
|
||||
|
||||
public void setNumReturns(int i) {
|
||||
}
|
||||
|
||||
}
|
||||
75
src/jse/org/luaj/vm2/luajc/lst/LSFunction.java
Normal file
75
src/jse/org/luaj/vm2/luajc/lst/LSFunction.java
Normal file
@@ -0,0 +1,75 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.luajc.lst;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class LSFunction {
|
||||
|
||||
public final List<LSStatement> stats = new ArrayList<LSStatement>();
|
||||
public final List<LSFunction> functions = new ArrayList<LSFunction>();
|
||||
public final List<Name> paramnames = new ArrayList<Name>();
|
||||
|
||||
/** set if this is a vararg function */
|
||||
public boolean isvararg;
|
||||
|
||||
/** needsarg is set if the code is vararg and needs the "arg" table to be created. */
|
||||
public boolean hasarg,needsarg;
|
||||
|
||||
/** max number of returns, or -1 for varargs */
|
||||
public int maxReturns = 0;
|
||||
|
||||
/** set if there are logical subexpressions, or varargs assignment */
|
||||
public boolean hasandlogic, hasorlogic, hasvarargassign, usesvarargs;
|
||||
|
||||
public LSFunction() {
|
||||
}
|
||||
|
||||
public LSFunction(boolean isvararg) {
|
||||
this.isvararg = isvararg;
|
||||
}
|
||||
|
||||
public void setStatements(List<LSStatement> stats) {
|
||||
this.stats.clear();
|
||||
this.stats.addAll(stats);
|
||||
}
|
||||
|
||||
public void setParameterNames(List<Name> list) {
|
||||
this.paramnames.clear();
|
||||
this.paramnames.addAll( list );
|
||||
}
|
||||
|
||||
public String toString() { return "function("+paramnames+") "+stats+" end"; }
|
||||
|
||||
public void setUsesVarargs() {
|
||||
this.usesvarargs = true;
|
||||
if ( this.hasarg )
|
||||
this.needsarg = false;
|
||||
}
|
||||
|
||||
public void setHasArg() {
|
||||
this.hasarg = true;
|
||||
if ( ! this.usesvarargs )
|
||||
this.needsarg = true;
|
||||
}
|
||||
}
|
||||
76
src/jse/org/luaj/vm2/luajc/lst/LSIfStatement.java
Normal file
76
src/jse/org/luaj/vm2/luajc/lst/LSIfStatement.java
Normal file
@@ -0,0 +1,76 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.luajc.lst;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class LSIfStatement extends LSStatement {
|
||||
|
||||
public final LSExpression condition;
|
||||
public final List<LSStatement> statements;
|
||||
public List<ElseIf> elseifs;
|
||||
public List<LSStatement> elsestatements;
|
||||
|
||||
public static class ElseIf {
|
||||
public final LSExpression condition;
|
||||
public final List<LSStatement> statements;
|
||||
public ElseIf(LSExpression condition, List<LSStatement> statements) {
|
||||
this.condition = condition;
|
||||
this.statements = statements;
|
||||
}
|
||||
}
|
||||
|
||||
public LSIfStatement(LSExpression condition, List<LSStatement> statements) {
|
||||
super( Type.ifStat );
|
||||
this.condition = condition;
|
||||
this.statements = statements;
|
||||
}
|
||||
|
||||
public void addElseif(LSExpression condition, List<LSStatement> statements) {
|
||||
if ( elseifs == null )
|
||||
elseifs = new ArrayList<ElseIf>();
|
||||
elseifs.add( new ElseIf( condition, statements ) );
|
||||
}
|
||||
|
||||
public void addElse(List<LSStatement> statements) {
|
||||
elsestatements = statements;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "if "+condition+" then "+statements+
|
||||
(elseifs!=null? elseifs.toString(): "")+
|
||||
(elsestatements!=null? " else "+elsestatements: "");
|
||||
}
|
||||
public boolean isNextStatementReachable() {
|
||||
if ( isNextStatementReachable(statements) )
|
||||
return true;
|
||||
if ( elseifs != null )
|
||||
for ( ElseIf e : elseifs )
|
||||
if ( isNextStatementReachable(statements) )
|
||||
return true;
|
||||
if ( isNextStatementReachable(elsestatements) )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
327
src/jse/org/luaj/vm2/luajc/lst/LSStatement.java
Normal file
327
src/jse/org/luaj/vm2/luajc/lst/LSStatement.java
Normal file
@@ -0,0 +1,327 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.luajc.lst;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class LSStatement {
|
||||
|
||||
public enum Type {
|
||||
functionCall,
|
||||
doBlock,
|
||||
whileLoop,
|
||||
repeatUntil,
|
||||
varAssign,
|
||||
forLoop,
|
||||
forList,
|
||||
varNamedFunction,
|
||||
localFunction,
|
||||
localAssign,
|
||||
returnStat,
|
||||
breakStat,
|
||||
ifStat,
|
||||
}
|
||||
|
||||
public final Type type;
|
||||
|
||||
LSStatement( Type type ) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static LSStatement functionCallStatement(LSVariable variable) {
|
||||
return new FunctionCall( variable );
|
||||
}
|
||||
|
||||
public static LSStatement doBlockStatement(List<LSStatement> statements) {
|
||||
return new DoBlock( statements );
|
||||
}
|
||||
|
||||
public static LSStatement whileLoopStatement(LSExpression condition, List<LSStatement> statements) {
|
||||
return new WhileLoop( condition, statements );
|
||||
}
|
||||
|
||||
public static LSStatement repeatUntilStatement(List<LSStatement> statements, LSExpression condition) {
|
||||
return new RepeatUntil( statements, condition );
|
||||
}
|
||||
|
||||
public static LSStatement forLoopStatement(Name name, LSExpression initial,
|
||||
LSExpression limit, LSExpression step, List<LSStatement> statements, Scope scope) {
|
||||
return new ForLoop( name, initial, limit, step, statements, scope );
|
||||
}
|
||||
|
||||
public static LSStatement forListStatement(List<Name> names,
|
||||
List<LSExpression> expressions, List<LSStatement> statements, Scope scope, LSFunction function) {
|
||||
return new ForList( names, expressions, statements, scope, function );
|
||||
}
|
||||
|
||||
public static LSStatement varFunctionStatement(LSVariable funcname, LSFunction funcbody) {
|
||||
return new VarNamedFunction( funcname, funcbody );
|
||||
}
|
||||
|
||||
public static LSStatement localFunctionStatement(Name name, LSFunction funcbody) {
|
||||
return new LocalFunction( name, funcbody );
|
||||
}
|
||||
|
||||
public static LSStatement varAssignStatement(List<LSVariable> variables, List<LSExpression> expressions, Scope scope, LSFunction function) {
|
||||
setExprNumReturns( variables.size(), expressions, function );
|
||||
return new VarAssign( variables, expressions, scope );
|
||||
}
|
||||
|
||||
public static LSStatement localAssignStatement(List<Name> names, List<LSExpression> expressions, Scope scope, LSFunction function) {
|
||||
setExprNumReturns( names.size(), expressions, function );
|
||||
return new LocalAssign( names, expressions, scope );
|
||||
}
|
||||
|
||||
public static void setExprNumReturns( int nassign, List<LSExpression> expressions, LSFunction function ) {
|
||||
int nexpr = expressions!=null? expressions.size(): 0;
|
||||
for ( int i=0; i<nexpr; i++ )
|
||||
expressions.get(i).setNumReturns(
|
||||
(nassign<=nexpr)?
|
||||
(i<nassign? 1: 0): // same or more expressions than names
|
||||
(i<nexpr-1? 1: -1) ); // more names than expressions
|
||||
if ( nassign > nexpr && nexpr > 0 && expressions.get(nexpr-1).getNumReturns() == -1 )
|
||||
function.hasvarargassign = true;
|
||||
}
|
||||
|
||||
public static LSStatement returnStatement(LSFunction function, List<LSExpression> expressions) {
|
||||
int n=expressions!=null? expressions.size(): 0;
|
||||
|
||||
// set num returns of subexpressions
|
||||
for ( int i=0; i<n; i++ )
|
||||
expressions.get(i).setNumReturns(i<n-1? 1: -1); // last in list returns vararg
|
||||
int nreturns = 0;
|
||||
if ( n > 0 ) {
|
||||
LSExpression last = expressions.get(n-1);
|
||||
int lastreturns = last.getNumReturns();
|
||||
nreturns = (lastreturns<0? -1: lastreturns+n-1);
|
||||
}
|
||||
|
||||
// change the containing function to varargs if necessary.
|
||||
if ( function.maxReturns != -1 && function.maxReturns < nreturns )
|
||||
function.maxReturns = nreturns;
|
||||
if ( function.maxReturns == -1 || function.maxReturns > 1 || nreturns < 0 )
|
||||
function.isvararg = true;
|
||||
|
||||
return new ReturnStat( function, expressions );
|
||||
}
|
||||
|
||||
public static LSStatement breakStatement() {
|
||||
return new BreakStat();
|
||||
}
|
||||
|
||||
/** Statement representing a function call on a variable, such as "foo.bar()" */
|
||||
public static final class FunctionCall extends LSStatement {
|
||||
public final LSVariable variable;
|
||||
FunctionCall(LSVariable variable) {
|
||||
super( Type.functionCall );
|
||||
this.variable = variable;
|
||||
}
|
||||
public String toString() { return variable.toString()+"();"; }
|
||||
}
|
||||
|
||||
/** do block, such as "do foo = bar end" */
|
||||
public static final class DoBlock extends LSStatement {
|
||||
public final List<LSStatement> statements;
|
||||
DoBlock(List<LSStatement> statements) {
|
||||
super( Type.doBlock );
|
||||
this.statements = statements;
|
||||
}
|
||||
public String toString() { return "do "+statements+" end;"; }
|
||||
public boolean isNextStatementReachable() {
|
||||
return isNextStatementReachable(statements);
|
||||
}
|
||||
}
|
||||
|
||||
/** while loop, such as "while foo = true do bar() end" */
|
||||
public static final class WhileLoop extends LSStatement {
|
||||
public final LSExpression condition;
|
||||
public final List<LSStatement> statements;
|
||||
WhileLoop(LSExpression condition, List<LSStatement> statements) {
|
||||
super( Type.whileLoop );
|
||||
this.condition = condition;
|
||||
this.statements = statements;
|
||||
}
|
||||
public String toString() { return "while "+condition+" do "+statements+" end;"; }
|
||||
public boolean isNextStatementReachable() {
|
||||
return isNextStatementReachable(statements);
|
||||
}
|
||||
}
|
||||
|
||||
/** repeat loop, such as "repeat foo() until bar == true" */
|
||||
public static final class RepeatUntil extends LSStatement {
|
||||
public final List<LSStatement> statements;
|
||||
public final LSExpression condition;
|
||||
RepeatUntil(List<LSStatement> statements, LSExpression condition) {
|
||||
super( Type.repeatUntil );
|
||||
this.statements = statements;
|
||||
this.condition = condition;
|
||||
}
|
||||
public String toString() { return "repeat "+statements+" until "+condition+";"; }
|
||||
public boolean isNextStatementReachable() {
|
||||
return isNextStatementReachable(statements);
|
||||
}
|
||||
}
|
||||
|
||||
/** assignment to variables, such as "x.a,y.b = foo,bar" */
|
||||
public static final class VarAssign extends LSStatement {
|
||||
public final List<LSVariable> variables;
|
||||
public final List<LSExpression> expressions;
|
||||
public final Scope scope;
|
||||
VarAssign(List<LSVariable> variables, List<LSExpression> expressions, Scope scope) {
|
||||
super( Type.varAssign );
|
||||
this.variables = variables;
|
||||
this.expressions = expressions;
|
||||
this.scope = scope;
|
||||
}
|
||||
public String toString() { return variables+"="+expressions+";"; }
|
||||
}
|
||||
|
||||
/** for loop with index, such as "for i=1,10,2 do ... end" */
|
||||
public static final class ForLoop extends LSStatement {
|
||||
public final Name index;
|
||||
public final LSExpression initial;
|
||||
public final LSExpression limit;
|
||||
public final LSExpression step;
|
||||
public final List<LSStatement> statements;
|
||||
public final Scope scope;
|
||||
ForLoop(Name name, LSExpression initial, LSExpression limit, LSExpression step, List<LSStatement> statements, Scope scope) {
|
||||
super( Type.forLoop );
|
||||
this.index = name;
|
||||
this.initial = initial;
|
||||
this.limit = limit;
|
||||
this.step = step;
|
||||
this.statements = statements;
|
||||
this.scope = scope;
|
||||
initial.setNumReturns(1);
|
||||
limit.setNumReturns(1);
|
||||
if ( step != null )
|
||||
step.setNumReturns(1);
|
||||
}
|
||||
public String toString() { return "for "+index+"="+initial+","+limit+","+step+" do "+statements+" end;"; }
|
||||
public boolean isNextStatementReachable() {
|
||||
return isNextStatementReachable(statements);
|
||||
}
|
||||
}
|
||||
|
||||
/** for loop with variable, such as "for i,j,k in foo() do ... end" */
|
||||
public static final class ForList extends LSStatement {
|
||||
public final List<Name> names;
|
||||
public final List<LSExpression> expressions;
|
||||
public final List<LSStatement> statements;
|
||||
public final Scope scope;
|
||||
ForList(List<Name> names, List<LSExpression> expressions, List<LSStatement> statements, Scope scope, LSFunction function) {
|
||||
super( Type.forList );
|
||||
this.names = names;
|
||||
this.expressions = expressions;
|
||||
this.statements = statements;
|
||||
this.scope = scope;
|
||||
|
||||
// set return value count for each expression in list;
|
||||
int ne = expressions.size();
|
||||
for ( int i=0; i<ne-1 && i<3; i++ )
|
||||
expressions.get(i).setNumReturns(1);
|
||||
if ( ne<=3 ) {
|
||||
expressions.get(ne-1).setNumReturns(3-(ne-1));
|
||||
function.hasvarargassign = true;
|
||||
}
|
||||
}
|
||||
public String toString() { return "for "+names+" in "+expressions+" do "+statements+" end;"; }
|
||||
public boolean isNextStatementReachable() {
|
||||
return isNextStatementReachable(statements);
|
||||
}
|
||||
}
|
||||
|
||||
/** variable function declaration, such as "a.b = function() end" */
|
||||
public static final class VarNamedFunction extends LSStatement {
|
||||
public final LSVariable funcname;
|
||||
public final LSFunction funcbody;
|
||||
VarNamedFunction(LSVariable funcname, LSFunction funcbody) {
|
||||
super( Type.varNamedFunction );
|
||||
this.funcname = funcname;
|
||||
this.funcbody = funcbody;
|
||||
}
|
||||
public String toString() { return funcname+"=f:"+funcbody+";"; }
|
||||
}
|
||||
|
||||
/** simple function declaration, such as "a = function() end" */
|
||||
public static final class LocalFunction extends LSStatement {
|
||||
public final Name name;
|
||||
public final LSFunction funcbody;
|
||||
LocalFunction(Name name, LSFunction funcbody) {
|
||||
super( Type.localFunction );
|
||||
this.name = name;
|
||||
this.funcbody = funcbody;
|
||||
}
|
||||
public String toString() { return name+"=f:"+funcbody+";"; }
|
||||
}
|
||||
|
||||
/** assignment, such as "a,b = foo,bar" */
|
||||
public static final class LocalAssign extends LSStatement {
|
||||
public final List<Name> names;
|
||||
public final List<LSExpression> expressions;
|
||||
public final Scope scope;
|
||||
LocalAssign(List<Name> list, List<LSExpression> expressions, Scope scope) {
|
||||
super( Type.localAssign );
|
||||
this.names = list;
|
||||
this.expressions = expressions;
|
||||
this.scope = scope;
|
||||
}
|
||||
public String toString() { return names+"="+expressions+";"; }
|
||||
}
|
||||
|
||||
/** return statement, such as "return foo,bar" */
|
||||
public static final class ReturnStat extends LSStatement {
|
||||
public final LSFunction function;
|
||||
public final List<LSExpression> expressions;
|
||||
ReturnStat(LSFunction function, List<LSExpression> expressions) {
|
||||
super( Type.returnStat );
|
||||
this.function = function;
|
||||
this.expressions = expressions;
|
||||
}
|
||||
public String toString() { return "return "+expressions+";"; }
|
||||
public boolean isNextStatementReachable() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** break statement */
|
||||
public static final class BreakStat extends LSStatement {
|
||||
BreakStat() {
|
||||
super( Type.breakStat );
|
||||
}
|
||||
public String toString() { return "break;"; }
|
||||
}
|
||||
|
||||
/** True of this statment could return and therefore the next statement is reachable. */
|
||||
public boolean isNextStatementReachable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isNextStatementReachable(List<LSStatement> stats) {
|
||||
if ( stats == null )
|
||||
return true;
|
||||
for ( LSStatement s : stats )
|
||||
if ( ! s.isNextStatementReachable() )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
172
src/jse/org/luaj/vm2/luajc/lst/LSVariable.java
Normal file
172
src/jse/org/luaj/vm2/luajc/lst/LSVariable.java
Normal file
@@ -0,0 +1,172 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.luajc.lst;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class LSVariable extends LSExpression {
|
||||
|
||||
LSVariable(Type type) {
|
||||
super(type);
|
||||
}
|
||||
|
||||
/** name, such as 'foo' */
|
||||
public static LSVariable nameVariable(Name name) {
|
||||
return new NameReference(name);
|
||||
}
|
||||
|
||||
/** table field, such as 'a.b' */
|
||||
public LSVariable fieldVariable(String field) {
|
||||
return new Field(this, field);
|
||||
}
|
||||
|
||||
/** method reference, such as foo:bar */
|
||||
public LSVariable methodVariable(String method) {
|
||||
return new Method(this, method);
|
||||
}
|
||||
|
||||
/** parenthetical reference, such as '(foo())' */
|
||||
public static LSVariable parenthesesVariable(LSExpression expression) {
|
||||
if ( expression != null )
|
||||
expression.setNumReturns(1);
|
||||
return new Parentheses(expression);
|
||||
}
|
||||
|
||||
/** table index, such as 'a[b]' */
|
||||
public LSVariable indexVariable(LSExpression expression) {
|
||||
return new Index(this, expression);
|
||||
}
|
||||
|
||||
/** Variable is a method, such as 'a(x,y)' */
|
||||
public LSVariable callFuncVariable(List<LSExpression> parameters) {
|
||||
int n = parameters.size();
|
||||
for ( int i=0; i<n; i++ )
|
||||
parameters.get(i).setNumReturns(i<n-1? 1: -1);
|
||||
return new CallFunction(this, parameters);
|
||||
}
|
||||
|
||||
/** Variable is a method, such as 'a:b(x,y)' */
|
||||
public LSVariable callMethVariable(String method, List<LSExpression> parameters) {
|
||||
int n = parameters.size();
|
||||
for ( int i=0; i<n; i++ )
|
||||
parameters.get(i).setNumReturns(i<n-1? 1: -1);
|
||||
return new CallMethod(this, method, parameters);
|
||||
}
|
||||
|
||||
/** name, such as 'foo' */
|
||||
public static class NameReference extends LSVariable {
|
||||
public final Name name;
|
||||
public NameReference(Name name) {
|
||||
super( Type.nameVariable );
|
||||
this.name = name;
|
||||
}
|
||||
public String toString() { return name.toString(); }
|
||||
}
|
||||
|
||||
/** field reference, such as foo.bar */
|
||||
public static class Field extends LSVariable {
|
||||
public final LSVariable variable;
|
||||
public final String field;
|
||||
public Field(LSVariable variable, String field) {
|
||||
super( Type.fieldVariable );
|
||||
this.variable = variable;
|
||||
this.field = field;
|
||||
}
|
||||
public String toString() { return variable+"."+field; }
|
||||
}
|
||||
|
||||
/** method reference, such as foo:bar */
|
||||
public static class Method extends LSVariable {
|
||||
public final LSVariable variable;
|
||||
public final String method;
|
||||
public Method(LSVariable variable, String method) {
|
||||
super( Type.methodVariable );
|
||||
this.variable = variable;
|
||||
this.method = method;
|
||||
}
|
||||
public String toString() { return variable+":"+method; }
|
||||
}
|
||||
|
||||
/** parenthetical reference, such as '(foo())' */
|
||||
public static class Parentheses extends LSVariable {
|
||||
public final LSExpression expression;
|
||||
public Parentheses(LSExpression expression) {
|
||||
super( Type.parenthesesVariable );
|
||||
this.expression = expression;
|
||||
}
|
||||
public String toString() { return "("+expression+")"; }
|
||||
}
|
||||
|
||||
/** table index, such as 'a[b]' */
|
||||
public static class Index extends LSVariable {
|
||||
public final LSVariable variable;
|
||||
public final LSExpression expression;
|
||||
public Index(LSVariable variable, LSExpression expression) {
|
||||
super( Type.indexVariable );
|
||||
this.variable = variable;
|
||||
this.expression = expression;
|
||||
}
|
||||
public String toString() { return variable+"["+expression+"]"; }
|
||||
}
|
||||
|
||||
|
||||
/** Variable is a function invocation, such as 'a(x,y)' */
|
||||
public static class CallFunction extends LSVariable {
|
||||
public final LSVariable variable;
|
||||
public final List<LSExpression> parameters;
|
||||
public int numReturns = 0;
|
||||
public CallFunction(LSVariable variable, List<LSExpression> parameters) {
|
||||
super( Type.callFunctionVariable );
|
||||
this.variable = variable;
|
||||
this.parameters = parameters;
|
||||
}
|
||||
public void setNumReturns(int i) {
|
||||
this.numReturns = i;
|
||||
}
|
||||
public int getNumReturns() {
|
||||
return numReturns;
|
||||
}
|
||||
public String toString() { return variable+"("+parameters+")"; }
|
||||
}
|
||||
|
||||
/** Variable is a method invocation, such as 'a:bc()' */
|
||||
public static class CallMethod extends LSVariable {
|
||||
public final LSVariable variable;
|
||||
public final String method;
|
||||
public final List<LSExpression> parameters;
|
||||
public int numReturns = 0;
|
||||
public CallMethod(LSVariable variable, String method, List<LSExpression> parameters) {
|
||||
super( Type.callMethodVariable );
|
||||
this.variable = variable;
|
||||
this.method = method;
|
||||
this.parameters = parameters;
|
||||
}
|
||||
public void setNumReturns(int i) {
|
||||
this.numReturns = i;
|
||||
}
|
||||
public int getNumReturns() {
|
||||
return numReturns;
|
||||
}
|
||||
public String toString() { return variable+":"+method+"("+parameters+")"; }
|
||||
}
|
||||
|
||||
}
|
||||
73
src/jse/org/luaj/vm2/luajc/lst/Name.java
Normal file
73
src/jse/org/luaj/vm2/luajc/lst/Name.java
Normal file
@@ -0,0 +1,73 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.luajc.lst;
|
||||
|
||||
/** A name in lua source, which resolves to one of:
|
||||
* - global reference
|
||||
* - local that is not an upvalue
|
||||
* - local that is an upvalue
|
||||
*/
|
||||
public class Name {
|
||||
|
||||
/** Name in lua source file */
|
||||
public final String luaname;
|
||||
|
||||
/** 0 if in outermost scope, 1 if in next inner scope, ect. */
|
||||
public final int scopelevel;
|
||||
|
||||
/** 0 if first declaration in global program, 1 if second use, etc. */
|
||||
public final int outerrevision;
|
||||
|
||||
/** 0 if first declaration in nearest enclosing function, 1 if second use, etc */
|
||||
public final int innerrevision;
|
||||
|
||||
/** true if used as an upvalue by some enclosed function */
|
||||
public boolean isupvalue;
|
||||
|
||||
/** Construct a name instance */
|
||||
public Name(String luaname, int scopelevel, int outerrevision, int innterrevision) {
|
||||
super();
|
||||
this.luaname = luaname;
|
||||
this.scopelevel = scopelevel;
|
||||
this.outerrevision = outerrevision;
|
||||
this.innerrevision = innterrevision;
|
||||
}
|
||||
|
||||
/** Construct a name reference representing a global reference */
|
||||
public Name(String name) {
|
||||
this.luaname = name;
|
||||
this.scopelevel = -1;
|
||||
this.outerrevision = -1;
|
||||
this.innerrevision = -1;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return scopelevel<0?
|
||||
"_G$"+luaname:
|
||||
luaname+"$s"+scopelevel+"$v"+outerrevision+"$f"+innerrevision;
|
||||
}
|
||||
|
||||
public boolean isGlobal() {
|
||||
return -1 == outerrevision;
|
||||
}
|
||||
|
||||
}
|
||||
103
src/jse/org/luaj/vm2/luajc/lst/Scope.java
Normal file
103
src/jse/org/luaj/vm2/luajc/lst/Scope.java
Normal file
@@ -0,0 +1,103 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.luajc.lst;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/** A name scope in lua source terms.
|
||||
* Combination of function scope and block scope.
|
||||
*/
|
||||
public class Scope {
|
||||
public final Scope parent;
|
||||
public final int level;
|
||||
public final boolean isFunctionScope;
|
||||
public boolean hasAndOrLogic;
|
||||
public final Map<String,Name> names = new HashMap<String,Name>();
|
||||
|
||||
/** Construct a new default scope for a chunk */
|
||||
public Scope() {
|
||||
this.parent = null;
|
||||
this.isFunctionScope = true;
|
||||
this.level = 0;
|
||||
}
|
||||
|
||||
/** Construct an inner scope
|
||||
* @param parent the outer scope to fall back to, or null if a global scope
|
||||
* @param isFunctionScope true if this is a function scope, false otherwise
|
||||
*/
|
||||
public Scope(Scope parent, boolean isFunctionScope) {
|
||||
this.parent = parent;
|
||||
this.isFunctionScope = isFunctionScope;
|
||||
this.level = parent!=null? parent.level + 1: 0;
|
||||
}
|
||||
|
||||
/** Declare a single name in the current scope, and return the Name element for it */
|
||||
public Name declare(String name) {
|
||||
boolean crossesFunctionBoundary = false;
|
||||
for ( Scope s=this; s!=null; s=s.parent ) {
|
||||
Name n = s.names.get(name);
|
||||
if ( n != null ) {
|
||||
Name result = new Name(name,
|
||||
level,
|
||||
n.outerrevision+1,
|
||||
crossesFunctionBoundary? 0: n.innerrevision+1);
|
||||
names.put(name, result);
|
||||
return result;
|
||||
}
|
||||
if ( s.isFunctionScope )
|
||||
crossesFunctionBoundary = true;
|
||||
}
|
||||
Name result = new Name(name, level, 0, 0);
|
||||
names.put(name, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Reference a name, and find either the local scope within the function, the upvalue, or a global name */
|
||||
public Name reference(String name) {
|
||||
boolean crossesFunctionBoundary = false;
|
||||
for ( Scope s=this; s!=null; s=s.parent ) {
|
||||
Name n = s.names.get(name);
|
||||
if ( n != null ) {
|
||||
if ( crossesFunctionBoundary ) {
|
||||
n.isupvalue = true;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
if ( s.isFunctionScope )
|
||||
crossesFunctionBoundary = true;
|
||||
}
|
||||
// globally scoped name
|
||||
return new Name(name);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
String ours = (isFunctionScope? "F": "")+names;
|
||||
return (parent==null? ours: ours+"->"+parent.toString());
|
||||
}
|
||||
|
||||
/** Return true iff this scope is part the main chunk */
|
||||
public boolean isMainChunkScope() {
|
||||
return isFunctionScope? false: parent==null? true: parent.isMainChunkScope();
|
||||
}
|
||||
}
|
||||
|
||||
43
src/jse/org/luaj/vm2/luajc/lst/UnOp.java
Normal file
43
src/jse/org/luaj/vm2/luajc/lst/UnOp.java
Normal file
@@ -0,0 +1,43 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.luajc.lst;
|
||||
|
||||
public class UnOp {
|
||||
public enum Type {
|
||||
neg,not,len
|
||||
}
|
||||
|
||||
public static final UnOp NEG = new UnOp(Type.neg, "-");
|
||||
public static final UnOp NOT = new UnOp(Type.not, "~");
|
||||
public static final UnOp LEN = new UnOp(Type.len, "#");
|
||||
|
||||
public final Type type;
|
||||
public final String luaop;
|
||||
|
||||
private UnOp(Type type, String luaop) {
|
||||
super();
|
||||
this.type = type;
|
||||
this.luaop = luaop;
|
||||
}
|
||||
|
||||
public String toString() { return luaop; }
|
||||
}
|
||||
303
src/jse/org/luaj/vm2/script/LuaScriptEngine.java
Normal file
303
src/jse/org/luaj/vm2/script/LuaScriptEngine.java
Normal file
@@ -0,0 +1,303 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2008 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 org.luaj.vm2.script;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.script.Bindings;
|
||||
import javax.script.Compilable;
|
||||
import javax.script.CompiledScript;
|
||||
import javax.script.ScriptContext;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineFactory;
|
||||
import javax.script.ScriptException;
|
||||
import javax.script.SimpleScriptContext;
|
||||
|
||||
import org.luaj.vm2.LoadState;
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.LuaClosure;
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
import org.luaj.vm2.lib.JsePlatform;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jim_roseborough
|
||||
*/
|
||||
public class LuaScriptEngine implements ScriptEngine, Compilable {
|
||||
|
||||
private static final String __ENGINE_VERSION__ = Lua._VERSION;
|
||||
private static final String __NAME__ = "Luaj";
|
||||
private static final String __SHORT_NAME__ = "Luaj";
|
||||
private static final String __LANGUAGE__ = "lua";
|
||||
private static final String __LANGUAGE_VERSION__ = "5.1";
|
||||
private static final String __ARGV__ = "arg";
|
||||
private static final String __FILENAME__ = "?";
|
||||
|
||||
static {
|
||||
LuaC.install();
|
||||
}
|
||||
|
||||
private static final ScriptEngineFactory myFactory = new LuaScriptEngineFactory();
|
||||
|
||||
private ScriptContext defaultContext;
|
||||
|
||||
private final LuaValue _G;
|
||||
|
||||
public LuaScriptEngine() {
|
||||
|
||||
// create globals
|
||||
_G = JsePlatform.standardGlobals();
|
||||
|
||||
// set up context
|
||||
ScriptContext ctx = new SimpleScriptContext();
|
||||
ctx.setBindings(createBindings(), ScriptContext.ENGINE_SCOPE);
|
||||
setContext(ctx);
|
||||
|
||||
// set special values
|
||||
put(LANGUAGE_VERSION, __LANGUAGE_VERSION__);
|
||||
put(LANGUAGE, __LANGUAGE__);
|
||||
put(ENGINE, __NAME__);
|
||||
put(ENGINE_VERSION, __ENGINE_VERSION__);
|
||||
put(ARGV, __ARGV__);
|
||||
put(FILENAME, __FILENAME__);
|
||||
put(NAME, __SHORT_NAME__);
|
||||
put("THREADING", null);
|
||||
}
|
||||
|
||||
|
||||
public Object eval(String script) throws ScriptException {
|
||||
return eval(new StringReader(script));
|
||||
}
|
||||
|
||||
public Object eval(String script, ScriptContext context) throws ScriptException {
|
||||
return eval(new StringReader(script), context);
|
||||
}
|
||||
|
||||
public Object eval(String script, Bindings bindings) throws ScriptException {
|
||||
return eval(new StringReader(script), bindings);
|
||||
}
|
||||
|
||||
public Object eval(Reader reader) throws ScriptException {
|
||||
return eval(reader, getContext());
|
||||
}
|
||||
|
||||
public Object eval(Reader reader, ScriptContext scriptContext) throws ScriptException {
|
||||
return compile(reader).eval(scriptContext);
|
||||
}
|
||||
|
||||
public Object eval(Reader reader, Bindings bindings) throws ScriptException {
|
||||
ScriptContext c = getContext();
|
||||
Bindings current = c.getBindings(ScriptContext.ENGINE_SCOPE);
|
||||
c.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
|
||||
Object result = eval(reader);
|
||||
c.setBindings(current, ScriptContext.ENGINE_SCOPE);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void put(String key, Object value) {
|
||||
Bindings b = getBindings(ScriptContext.ENGINE_SCOPE);
|
||||
((LuaBindings)b).put(key, value);
|
||||
}
|
||||
|
||||
public Object get(String key) {
|
||||
Bindings b = getBindings(ScriptContext.ENGINE_SCOPE);
|
||||
return ((LuaBindings)b).get(key);
|
||||
}
|
||||
|
||||
public Bindings getBindings(int scope) {
|
||||
return getContext().getBindings(scope);
|
||||
}
|
||||
|
||||
public void setBindings(Bindings bindings, int scope) {
|
||||
getContext().setBindings(bindings, scope);
|
||||
}
|
||||
|
||||
public Bindings createBindings() {
|
||||
return new LuaBindings( _G );
|
||||
}
|
||||
|
||||
public ScriptContext getContext() {
|
||||
return defaultContext;
|
||||
}
|
||||
|
||||
public void setContext(ScriptContext context) {
|
||||
defaultContext = context;
|
||||
}
|
||||
|
||||
public ScriptEngineFactory getFactory() {
|
||||
return myFactory;
|
||||
}
|
||||
|
||||
public CompiledScript compile(String script) throws ScriptException {
|
||||
return compile(new StringReader(script));
|
||||
}
|
||||
|
||||
public CompiledScript compile(Reader reader) throws ScriptException {
|
||||
try {
|
||||
InputStream ris = new Utf8Encoder(reader);
|
||||
try {
|
||||
final Prototype p = LoadState.undump(ris, "script");
|
||||
return new CompiledScript() {
|
||||
public Object eval(ScriptContext context) throws ScriptException {
|
||||
Bindings b = context.getBindings(ScriptContext.ENGINE_SCOPE);
|
||||
LuaBindings lb = (LuaBindings) b;
|
||||
LuaClosure c = new LuaClosure( p, lb.env );
|
||||
return c.call();
|
||||
}
|
||||
public ScriptEngine getEngine() {
|
||||
return LuaScriptEngine.this;
|
||||
}
|
||||
};
|
||||
} catch ( LuaError lee ) {
|
||||
throw new ScriptException(lee.getMessage() );
|
||||
} finally {
|
||||
ris.close();
|
||||
}
|
||||
} catch ( Throwable t ) {
|
||||
throw new ScriptException("eval threw "+t.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// ------ lua bindings -----
|
||||
private static final class LuaBindings implements Bindings {
|
||||
private LuaValue env;
|
||||
private LuaValue mt;
|
||||
private LuaBindings( LuaValue _G ) {
|
||||
mt = LuaValue.tableOf();
|
||||
mt.set( LuaValue.INDEX, _G );
|
||||
clear();
|
||||
}
|
||||
public void clear() {
|
||||
env = LuaValue.tableOf();
|
||||
env.setmetatable(mt);
|
||||
}
|
||||
private Object toJava(LuaValue v) {
|
||||
switch ( v.type() ) {
|
||||
case LuaValue.TNIL: return null;
|
||||
case LuaValue.TSTRING: return v.toString();
|
||||
case LuaValue.TUSERDATA: return v.checkuserdata(Object.class);
|
||||
case LuaValue.TNUMBER: return v.isinttype()? new Integer(v.toint()): new Double(v.todouble());
|
||||
default:
|
||||
throw new java.lang.UnsupportedOperationException(
|
||||
"LuaBindings cannot convert lua type '"+v.typename()+"' to Java");
|
||||
}
|
||||
}
|
||||
private LuaValue toLua(Object javaValue) {
|
||||
if ( javaValue instanceof Number ) {
|
||||
return LuaValue.valueOf(((Number)javaValue).doubleValue());
|
||||
} else if ( javaValue instanceof String ) {
|
||||
return LuaValue.valueOf(javaValue.toString());
|
||||
} else if ( javaValue == null ) {
|
||||
return LuaValue.NIL;
|
||||
} else {
|
||||
return LuaValue.userdataOf(javaValue);
|
||||
}
|
||||
}
|
||||
public boolean containsKey(Object key) {
|
||||
return ! env.get(toLua(key)).isnil();
|
||||
}
|
||||
public Object get(Object key) {
|
||||
return toJava(env.get(toLua(key)));
|
||||
}
|
||||
public Object put(String name, Object value) {
|
||||
LuaValue key = toLua(name);
|
||||
Object result = toJava(env.get(key));
|
||||
env.set(key, toLua(value));
|
||||
return result;
|
||||
}
|
||||
public void putAll(Map<? extends String, ? extends Object> toMerge) {
|
||||
for ( Iterator it=toMerge.entrySet().iterator(); it.hasNext(); ) {
|
||||
Map.Entry<String, Object> e = (Map.Entry<String, Object>) it.next();
|
||||
put( e.getKey(), e.getValue() );
|
||||
}
|
||||
}
|
||||
public Object remove(Object javakey) {
|
||||
LuaValue key = toLua(javakey);
|
||||
Object result = toJava(env.get(key));
|
||||
env.set(key, LuaValue.NIL);
|
||||
return result;
|
||||
}
|
||||
public boolean containsValue(Object value) {
|
||||
throw new java.lang.UnsupportedOperationException(
|
||||
"containsValue() not supported for LuaBindings");
|
||||
}
|
||||
public Set<java.util.Map.Entry<String, Object>> entrySet() {
|
||||
throw new java.lang.UnsupportedOperationException(
|
||||
"entrySet() not supported for LuaBindings");
|
||||
}
|
||||
public boolean isEmpty() {
|
||||
throw new java.lang.UnsupportedOperationException(
|
||||
"isEmpty() not supported for LuaBindings");
|
||||
}
|
||||
public Set<String> keySet() {
|
||||
throw new java.lang.UnsupportedOperationException(
|
||||
"keySet() not supported for LuaBindings");
|
||||
}
|
||||
public int size() {
|
||||
throw new java.lang.UnsupportedOperationException(
|
||||
"size() not supported for LuaBindings");
|
||||
}
|
||||
public Collection<Object> values() {
|
||||
throw new java.lang.UnsupportedOperationException(
|
||||
"values() not supported for LuaBindings");
|
||||
}
|
||||
}
|
||||
|
||||
// ------ convert char stream to byte stream for lua compiler -----
|
||||
|
||||
private final class Utf8Encoder extends InputStream {
|
||||
private final Reader r;
|
||||
private final int[] buf = new int[2];
|
||||
private int n;
|
||||
|
||||
private Utf8Encoder(Reader r) {
|
||||
this.r = r;
|
||||
}
|
||||
|
||||
public int read() throws IOException {
|
||||
if ( n > 0 )
|
||||
return buf[--n];
|
||||
int c = r.read();
|
||||
if ( c < 0x80 )
|
||||
return c;
|
||||
n = 0;
|
||||
if ( c < 0x800 ) {
|
||||
buf[n++] = (0x80 | ( c & 0x3f));
|
||||
return (0xC0 | ((c>>6) & 0x1f));
|
||||
} else {
|
||||
buf[n++] = (0x80 | ( c & 0x3f));
|
||||
buf[n++] = (0x80 | ((c>>6) & 0x3f));
|
||||
return (0xE0 | ((c>>12) & 0x0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
127
src/jse/org/luaj/vm2/script/LuaScriptEngineFactory.java
Normal file
127
src/jse/org/luaj/vm2/script/LuaScriptEngineFactory.java
Normal file
@@ -0,0 +1,127 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2008 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 org.luaj.vm2.script;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jim_roseborough
|
||||
*/
|
||||
public class LuaScriptEngineFactory implements ScriptEngineFactory {
|
||||
|
||||
private static final String FILEEXT = ".lua";
|
||||
|
||||
private static final String [] MIMETYPES = {
|
||||
"text/plain",
|
||||
"text/lua",
|
||||
"application/lua"
|
||||
};
|
||||
|
||||
private static final String [] NAMES = {
|
||||
"lua",
|
||||
"luaj",
|
||||
};
|
||||
|
||||
private ScriptEngine myScriptEngine;
|
||||
private List<String> extensions;
|
||||
private List<String> mimeTypes;
|
||||
private List<String> names;
|
||||
|
||||
public LuaScriptEngineFactory() {
|
||||
myScriptEngine = new LuaScriptEngine();
|
||||
extensions = Collections.nCopies(1, FILEEXT);
|
||||
mimeTypes = Arrays.asList(MIMETYPES);
|
||||
names = Arrays.asList(NAMES);
|
||||
}
|
||||
|
||||
public String getEngineName() {
|
||||
return getScriptEngine().get(ScriptEngine.ENGINE).toString();
|
||||
}
|
||||
|
||||
public String getEngineVersion() {
|
||||
return getScriptEngine().get(ScriptEngine.ENGINE_VERSION).toString();
|
||||
}
|
||||
|
||||
public List<String> getExtensions() {
|
||||
return extensions;
|
||||
}
|
||||
|
||||
public List<String> getMimeTypes() {
|
||||
return mimeTypes;
|
||||
}
|
||||
|
||||
public List<String> getNames() {
|
||||
return names;
|
||||
}
|
||||
|
||||
public String getLanguageName() {
|
||||
return getScriptEngine().get(ScriptEngine.LANGUAGE).toString();
|
||||
}
|
||||
|
||||
public String getLanguageVersion() {
|
||||
return getScriptEngine().get(ScriptEngine.LANGUAGE_VERSION).toString();
|
||||
}
|
||||
|
||||
public Object getParameter(String key) {
|
||||
return getScriptEngine().get(key).toString();
|
||||
}
|
||||
|
||||
public String getMethodCallSyntax(String obj, String m, String... args) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(obj + ":" + m + "(");
|
||||
int len = args.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(',');
|
||||
}
|
||||
sb.append(args[i]);
|
||||
}
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getOutputStatement(String toDisplay) {
|
||||
return "print(" + toDisplay + ")";
|
||||
}
|
||||
|
||||
public String getProgram(String ... statements) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
int len = statements.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (i > 0) {
|
||||
sb.append('\n');
|
||||
}
|
||||
sb.append(statements[i]);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public ScriptEngine getScriptEngine() {
|
||||
return myScriptEngine;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user