Initial sources for planned 2.0 luaj vm release. Most interpreter features and library functions working.

This commit is contained in:
James Roseborough
2009-10-27 06:12:24 +00:00
parent d16fad00e8
commit 3863ff8e46
116 changed files with 33600 additions and 122 deletions

View File

@@ -0,0 +1 @@
org.luaj.vm2.script.LuaScriptEngineFactory

199
src/jse/lua.java Normal file
View 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
View 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
View 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();
}
}
}

View 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;
}
}

View 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 );
}
}

View 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;
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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);
}
}

View 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();
}
}
}

View 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;
}
}

View 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();
}
}

View 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");
}
}

View 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 );
}
}

View 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();}
;

View 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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; }
}

View 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);
}
}

View 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;
}
}

View 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) {
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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+")"; }
}
}

View 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;
}
}

View 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();
}
}

View 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; }
}

View 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));
}
}
}
}

View 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;
}
}