Add formatter definition and format code

This commit is contained in:
Enrico Horn
2021-07-03 22:23:09 +02:00
parent 3c266bcc98
commit e7e6190f9c
144 changed files with 17201 additions and 14311 deletions

View File

@@ -1,3 +1,4 @@
/*******************************************************************************
* Copyright (c) 2009-2012 Luaj.org. All rights reserved.
*
@@ -38,37 +39,30 @@ import org.luaj.vm2.Varargs;
import org.luaj.vm2.lib.jse.JsePlatform;
import org.luaj.vm2.luajc.LuaJC;
/**
* lua command for use in JSE environments.
*/
public class lua {
private static final String version = Lua._VERSION + " Copyright (c) 2012 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" +
" -b use luajc bytecode-to-bytecode compiler (requires bcel on class path)\n" +
" -n nodebug - do not load debug library by default\n" +
" -p print the prototype\n" +
" -c enc use the supplied encoding 'enc' for input files\n" +
" -- stop handling options\n" +
" - execute stdin and stop handling options";
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"
+ " -b use luajc bytecode-to-bytecode compiler (requires bcel on class path)\n"
+ " -n nodebug - do not load debug library by default\n" + " -p print the prototype\n"
+ " -c enc use the supplied encoding 'enc' for input files\n" + " -- stop handling options\n"
+ " - execute stdin and stop handling options";
private static void usageExit() {
System.out.println(usage);
System.exit(-1);
System.exit(-1);
}
private static Globals globals;
private static boolean print = false;
private static String encoding = null;
public static void main( String[] args ) throws IOException {
private static boolean print = false;
private static String encoding = null;
public static void main(String[] args) throws IOException {
// process args
boolean interactive = (args.length == 0);
@@ -79,17 +73,17 @@ public class lua {
Vector libs = null;
try {
// stateful argument processing
for ( int i=0; i<args.length; i++ ) {
if ( ! processing || ! args[i].startsWith("-") ) {
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 ) {
} else if (args[i].length() <= 1) {
// input file - defer to last stage
break;
} else {
switch ( args[i].charAt(1) ) {
switch (args[i].charAt(1)) {
case 'e':
if ( ++i >= args.length )
if (++i >= args.length)
usageExit();
// input script - defer to last stage
break;
@@ -97,10 +91,10 @@ public class lua {
luajc = true;
break;
case 'l':
if ( ++i >= args.length )
if (++i >= args.length)
usageExit();
libs = libs!=null? libs: new Vector();
libs.addElement( args[i] );
libs = libs != null? libs: new Vector();
libs.addElement(args[i]);
break;
case 'i':
interactive = true;
@@ -115,12 +109,12 @@ public class lua {
print = true;
break;
case 'c':
if ( ++i >= args.length )
if (++i >= args.length)
usageExit();
encoding = args[i];
break;
case '-':
if ( args[i].length() > 2 )
if (args[i].length() > 2)
usageExit();
processing = false;
break;
@@ -132,33 +126,34 @@ public class lua {
}
// echo version
if ( versioninfo )
if (versioninfo)
System.out.println(version);
// new lua state
globals = nodebug? JsePlatform.standardGlobals(): JsePlatform.debugGlobals();
if ( luajc ) LuaJC.install(globals);
for ( int i=0, n=libs!=null? libs.size(): 0; i<n; i++ )
loadLibrary( (String) libs.elementAt(i) );
if (luajc)
LuaJC.install(globals);
for (int i = 0, n = libs != null? libs.size(): 0; i < n; i++)
loadLibrary((String) libs.elementAt(i));
// 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 );
for (int i = 0; i < args.length; i++) {
if (!processing || !args[i].startsWith("-")) {
processScript(new FileInputStream(args[i]), args[i], args, i);
break;
} else if ( "-".equals( args[i] ) ) {
processScript( System.in, "=stdin", args, i );
} else if ("-".equals(args[i])) {
processScript(System.in, "=stdin", args, i);
break;
} else {
switch ( args[i].charAt(1) ) {
switch (args[i].charAt(1)) {
case 'l':
case 'c':
++i;
break;
case 'e':
++i;
processScript( new ByteArrayInputStream(args[i].getBytes()), "string", args, i );
processScript(new ByteArrayInputStream(args[i].getBytes()), "string", args, i);
break;
case '-':
processing = false;
@@ -166,49 +161,49 @@ public class lua {
}
}
}
if ( interactive )
if (interactive)
interactiveMode();
} catch ( IOException ioe ) {
System.err.println( ioe.toString() );
} catch (IOException ioe) {
System.err.println(ioe.toString());
System.exit(-2);
}
}
private static void loadLibrary( String libname ) throws IOException {
LuaValue slibname =LuaValue.valueOf(libname);
private static void loadLibrary(String libname) throws IOException {
LuaValue slibname = LuaValue.valueOf(libname);
try {
// load via plain require
globals.get("require").call(slibname);
} catch ( Exception e ) {
} catch (Exception e) {
try {
// load as java class
LuaValue v = (LuaValue) Class.forName(libname).newInstance();
LuaValue v = (LuaValue) Class.forName(libname).newInstance();
v.call(slibname, globals);
} catch ( Exception f ) {
throw new IOException("loadLibrary("+libname+") failed: "+e+","+f );
} catch (Exception f) {
throw new IOException("loadLibrary(" + libname + ") failed: " + e + "," + f);
}
}
}
private static void processScript( InputStream script, String chunkname, String[] args, int firstarg ) throws IOException {
private static void processScript(InputStream script, String chunkname, String[] args, int firstarg)
throws IOException {
try {
LuaValue c;
try {
script = new BufferedInputStream(script);
c = encoding != null?
globals.load(new InputStreamReader(script, encoding), chunkname):
globals.load(script, chunkname, "bt", globals);
c = encoding != null? globals.load(new InputStreamReader(script, encoding), chunkname)
: globals.load(script, chunkname, "bt", globals);
} finally {
script.close();
}
if (print && c.isclosure())
Print.print(c.checkclosure().p);
Varargs scriptargs = setGlobalArg(chunkname, args, firstarg, globals);
c.invoke( scriptargs );
} catch ( Exception e ) {
e.printStackTrace( System.err );
c.invoke(scriptargs);
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
@@ -216,23 +211,23 @@ public class lua {
if (args == null)
return LuaValue.NONE;
LuaTable arg = LuaValue.tableOf();
for ( int j=0; j<args.length; j++ )
arg.set( j-i, LuaValue.valueOf(args[j]) );
for (int j = 0; j < args.length; j++)
arg.set(j-i, LuaValue.valueOf(args[j]));
arg.set(0, LuaValue.valueOf(chunkname));
arg.set(-1, LuaValue.valueOf("luaj"));
globals.set("arg", arg);
return arg.unpack();
}
private static void interactiveMode( ) throws IOException {
BufferedReader reader = new BufferedReader( new InputStreamReader( System.in ) );
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 )
if (line == null)
return;
processScript( new ByteArrayInputStream(line.getBytes()), "=stdin", null, 0 );
processScript(new ByteArrayInputStream(line.getBytes()), "=stdin", null, 0);
}
}
}

View File

@@ -1,3 +1,4 @@
/*******************************************************************************
* Copyright (c) 2009 Luaj.org. All rights reserved.
*
@@ -35,63 +36,56 @@ import org.luaj.vm2.Prototype;
import org.luaj.vm2.compiler.DumpState;
import org.luaj.vm2.lib.jse.JsePlatform;
/**
* Compiler for lua files to lua bytecode.
* 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" +
" -c enc use the supplied encoding 'enc' for input files\n" +
" -- stop handling options\n";
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" + " -c enc use the supplied encoding 'enc' for input files\n"
+ " -- stop handling options\n";
private static void usageExit() {
System.out.println(usage);
System.exit(-1);
System.exit(-1);
}
private boolean list = false;
private String output = "luac.out";
private boolean parseonly = false;
private boolean stripdebug = false;
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;
private String encoding = null;
private int numberformat = DumpState.NUMBER_FORMAT_DEFAULT;
private boolean versioninfo = false;
private boolean processing = true;
private String encoding = null;
public static void main( String[] args ) throws IOException {
new luac( args );
public static void main(String[] args) throws IOException {
new luac(args);
}
private luac( String[] args ) throws IOException {
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("-") ) {
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 ) {
} else if (args[i].length() <= 1) {
// input file - defer to next stage
} else {
switch ( args[i].charAt(1) ) {
switch (args[i].charAt(1)) {
case 'l':
list = true;
break;
case 'o':
if ( ++i >= args.length )
if (++i >= args.length)
usageExit();
output = args[i];
break;
@@ -105,7 +99,7 @@ public class luac {
littleendian = true;
break;
case 'i':
if ( args[i].length() <= 2 )
if (args[i].length() <= 2)
usageExit();
numberformat = Integer.parseInt(args[i].substring(2));
break;
@@ -113,12 +107,12 @@ public class luac {
versioninfo = true;
break;
case 'c':
if ( ++i >= args.length )
if (++i >= args.length)
usageExit();
encoding = args[i];
break;
case '-':
if ( args[i].length() > 2 )
if (args[i].length() > 2)
usageExit();
processing = false;
break;
@@ -128,26 +122,26 @@ public class luac {
}
}
}
// echo version
if ( versioninfo )
if (versioninfo)
System.out.println(version);
// open output file
OutputStream fos = new FileOutputStream( output );
OutputStream fos = new FileOutputStream(output);
// process input files
try {
Globals globals = JsePlatform.standardGlobals();
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( globals, new FileInputStream(args[i]), chunkname, fos );
} else if ( args[i].length() <= 1 ) {
processScript( globals, System.in, "=stdin", fos );
for (int i = 0; i < args.length; i++) {
if (!processing || !args[i].startsWith("-")) {
String chunkname = args[i].substring(0, args[i].length()-4);
processScript(globals, new FileInputStream(args[i]), chunkname, fos);
} else if (args[i].length() <= 1) {
processScript(globals, System.in, "=stdin", fos);
} else {
switch ( args[i].charAt(1) ) {
switch (args[i].charAt(1)) {
case 'o':
case 'c':
++i;
@@ -161,32 +155,33 @@ public class luac {
} finally {
fos.close();
}
} catch ( IOException ioe ) {
System.err.println( ioe.toString() );
} catch (IOException ioe) {
System.err.println(ioe.toString());
System.exit(-2);
}
}
private void processScript( Globals globals, InputStream script, String chunkname, OutputStream out ) throws IOException {
private void processScript(Globals globals, InputStream script, String chunkname, OutputStream out)
throws IOException {
try {
// create the chunk
// create the chunk
script = new BufferedInputStream(script);
Prototype chunk = encoding != null?
globals.compilePrototype(new InputStreamReader(script, encoding), chunkname):
globals.compilePrototype(script, chunkname);
Prototype chunk = encoding != null
? globals.compilePrototype(new InputStreamReader(script, encoding), chunkname)
: globals.compilePrototype(script, chunkname);
// list the chunk
if (list)
Print.printCode(chunk);
// list the chunk
if (list)
Print.printCode(chunk);
// write out the chunk
if (!parseonly) {
DumpState.dump(chunk, out, stripdebug, numberformat, littleendian);
}
} catch ( Exception e ) {
e.printStackTrace( System.err );
// write out the chunk
if (!parseonly) {
DumpState.dump(chunk, out, stripdebug, numberformat, littleendian);
}
} catch (Exception e) {
e.printStackTrace(System.err);
} finally {
script.close();
}

View File

@@ -1,3 +1,4 @@
/*******************************************************************************
* Copyright (c) 2009-2012 Luaj.org. All rights reserved.
*
@@ -36,62 +37,57 @@ import org.luaj.vm2.lib.jse.JsePlatform;
import org.luaj.vm2.luajc.LuaJC;
/**
* Compiler for lua files to compile lua sources or lua binaries into java classes.
* Compiler for lua files to compile lua sources or lua binaries into java
* classes.
*/
public class luajc {
private static final String version = Lua._VERSION + " Copyright (C) 2012 luaj.org";
private static final String usage =
"usage: java -cp luaj-jse.jar,bcel-5.2.jar luajc [options] fileordir [, fileordir ...]\n" +
"Available options are:\n" +
" - process stdin\n" +
" -s src source directory\n" +
" -d dir destination directory\n" +
" -p pkg package prefix to apply to all classes\n" +
" -m generate main(String[]) function for JSE\n" +
" -r recursively compile all\n" +
" -l load classes to verify generated bytecode\n" +
" -c enc use the supplied encoding 'enc' for input files\n" +
" -v verbose\n";
private static final String usage = "usage: java -cp luaj-jse.jar,bcel-5.2.jar luajc [options] fileordir [, fileordir ...]\n"
+ "Available options are:\n" + " - process stdin\n" + " -s src source directory\n"
+ " -d dir destination directory\n" + " -p pkg package prefix to apply to all classes\n"
+ " -m generate main(String[]) function for JSE\n" + " -r recursively compile all\n"
+ " -l load classes to verify generated bytecode\n"
+ " -c enc use the supplied encoding 'enc' for input files\n" + " -v verbose\n";
private static void usageExit() {
System.out.println(usage);
System.exit(-1);
System.exit(-1);
}
private String srcdir = ".";
private String destdir = ".";
private boolean genmain = false;
private boolean recurse = false;
private boolean verbose = false;
private String srcdir = ".";
private String destdir = ".";
private boolean genmain = false;
private boolean recurse = false;
private boolean verbose = false;
private boolean loadclasses = false;
private String encoding = null;
private String pkgprefix = null;
private List files = new ArrayList();
private String encoding = null;
private String pkgprefix = null;
private List files = new ArrayList();
private Globals globals;
public static void main( String[] args ) throws IOException {
new luajc( args );
public static void main(String[] args) throws IOException {
new luajc(args);
}
private luajc( String[] args ) throws IOException {
private luajc(String[] args) throws IOException {
// process args
List seeds = new ArrayList ();
List seeds = new ArrayList();
// get stateful args
for ( int i=0; i<args.length; i++ ) {
if ( ! args[i].startsWith("-") ) {
for (int i = 0; i < args.length; i++) {
if (!args[i].startsWith("-")) {
seeds.add(args[i]);
} else {
switch ( args[i].charAt(1) ) {
switch (args[i].charAt(1)) {
case 's':
if ( ++i >= args.length )
if (++i >= args.length)
usageExit();
srcdir = args[i];
break;
case 'd':
if ( ++i >= args.length )
if (++i >= args.length)
usageExit();
destdir = args[i];
break;
@@ -99,7 +95,7 @@ public class luajc {
loadclasses = true;
break;
case 'p':
if ( ++i >= args.length )
if (++i >= args.length)
usageExit();
pkgprefix = args[i];
break;
@@ -110,7 +106,7 @@ public class luajc {
recurse = true;
break;
case 'c':
if ( ++i >= args.length )
if (++i >= args.length)
usageExit();
encoding = args[i];
break;
@@ -123,60 +119,61 @@ public class luajc {
}
}
}
// echo version
if ( verbose ) {
if (verbose) {
System.out.println(version);
System.out.println("srcdir: "+srcdir);
System.out.println("destdir: "+destdir);
System.out.println("files: "+seeds);
System.out.println("recurse: "+recurse);
System.out.println("srcdir: " + srcdir);
System.out.println("destdir: " + destdir);
System.out.println("files: " + seeds);
System.out.println("recurse: " + recurse);
}
// need at least one seed
if ( seeds.size() <= 0 ) {
if (seeds.size() <= 0) {
System.err.println(usage);
System.exit(-1);
}
// collect up files to process
for ( int i=0; i<seeds.size(); i++ )
collectFiles( srcdir+"/"+seeds.get(i) );
for (int i = 0; i < seeds.size(); i++)
collectFiles(srcdir + "/" + seeds.get(i));
// check for at least one file
if ( files.size() <= 0 ) {
System.err.println("no files found in "+seeds);
if (files.size() <= 0) {
System.err.println("no files found in " + seeds);
System.exit(-1);
}
// process input files
globals = JsePlatform.standardGlobals();
for ( int i=0,n=files.size(); i<n; i++ )
processFile( (InputFile) files.get(i) );
for (int i = 0, n = files.size(); i < n; i++)
processFile((InputFile) files.get(i));
}
private void collectFiles(String path) {
File f = new File(path);
if ( f.isDirectory() && recurse )
scandir(f,pkgprefix);
else if ( f.isFile() ) {
if (f.isDirectory() && recurse)
scandir(f, pkgprefix);
else if (f.isFile()) {
File dir = f.getAbsoluteFile().getParentFile();
if ( dir != null )
scanfile( dir, f, pkgprefix );
if (dir != null)
scanfile(dir, f, pkgprefix);
}
}
private void scandir(File dir, String javapackage) {
File[] f = dir.listFiles();
for ( int i=0; i<f.length; i++ )
scanfile( dir, f[i], javapackage );
for (int i = 0; i < f.length; i++)
scanfile(dir, f[i], javapackage);
}
private void scanfile(File dir, File f, String javapackage) {
if ( f.exists() ) {
if ( f.isDirectory() && recurse )
scandir( f, (javapackage!=null? javapackage+"."+f.getName(): f.getName()) );
else if ( f.isFile() && f.getName().endsWith(".lua") )
files.add( new InputFile(dir,f,javapackage) );
if (f.exists()) {
if (f.isDirectory() && recurse)
scandir(f, (javapackage != null? javapackage + "." + f.getName(): f.getName()));
else if (f.isFile() && f.getName().endsWith(".lua"))
files.add(new InputFile(dir, f, javapackage));
}
}
@@ -188,82 +185,84 @@ public class luajc {
}
public Class findClass(String classname) throws ClassNotFoundException {
byte[] bytes = (byte[]) t.get(classname);
if ( bytes != null )
return defineClass(classname, bytes, 0, bytes.length);
return super.findClass(classname);
}
byte[] bytes = (byte[]) t.get(classname);
if (bytes != null)
return defineClass(classname, bytes, 0, bytes.length);
return super.findClass(classname);
}
}
class InputFile {
public String luachunkname;
public String srcfilename;
public File infile;
public File outdir;
public File infile;
public File outdir;
public String javapackage;
public InputFile(File dir, File f, String javapackage) {
this.infile = f;
String subdir = javapackage!=null? javapackage.replace('.', '/'): null;
String outdirpath = subdir!=null? destdir+"/"+subdir: destdir;
String subdir = javapackage != null? javapackage.replace('.', '/'): null;
String outdirpath = subdir != null? destdir + "/" + subdir: destdir;
this.javapackage = javapackage;
this.srcfilename = (subdir!=null? subdir+"/": "")+infile.getName();
this.luachunkname = (subdir!=null? subdir+"/": "")+infile.getName().substring( 0, infile.getName().lastIndexOf('.') );
this.srcfilename = (subdir != null? subdir + "/": "")+infile.getName();
this.luachunkname = (subdir != null? subdir + "/": "")
+infile.getName().substring(0, infile.getName().lastIndexOf('.'));
this.infile = f;
this.outdir = new File(outdirpath);
}
}
private void processFile( InputFile inf ) {
private void processFile(InputFile inf) {
inf.outdir.mkdirs();
try {
if ( verbose )
System.out.println("chunk="+inf.luachunkname+" srcfile="+inf.srcfilename);
if (verbose)
System.out.println("chunk=" + inf.luachunkname + " srcfile=" + inf.srcfilename);
// create the chunk
FileInputStream fis = new FileInputStream( inf.infile );
final Hashtable t = encoding != null?
LuaJC.instance.compileAll( new InputStreamReader(fis, encoding), inf.luachunkname, inf.srcfilename, globals, genmain):
LuaJC.instance.compileAll( fis, inf.luachunkname, inf.srcfilename, globals, genmain);
// create the chunk
FileInputStream fis = new FileInputStream(inf.infile);
final Hashtable t = encoding != null
? LuaJC.instance.compileAll(new InputStreamReader(fis, encoding), inf.luachunkname, inf.srcfilename,
globals, genmain)
: LuaJC.instance.compileAll(fis, inf.luachunkname, inf.srcfilename, globals, genmain);
fis.close();
// write out the chunk
for ( Enumeration e = t.keys(); e.hasMoreElements(); ) {
String key = (String) e.nextElement();
byte[] bytes = (byte[]) t.get(key);
if ( key.indexOf('/')>=0 ) {
String d = (destdir!=null? destdir+"/": "")+key.substring(0,key.lastIndexOf('/'));
new File(d).mkdirs();
}
String destpath = (destdir!=null? destdir+"/": "") + key + ".class";
if ( verbose )
System.out.println( " "+destpath +" ("+bytes.length+" bytes)");
FileOutputStream fos = new FileOutputStream( destpath );
fos.write( bytes );
fos.close();
}
// try to load the files
if ( loadclasses ) {
// write out the chunk
for (Enumeration e = t.keys(); e.hasMoreElements();) {
String key = (String) e.nextElement();
byte[] bytes = (byte[]) t.get(key);
if (key.indexOf('/') >= 0) {
String d = (destdir != null? destdir + "/": "")+key.substring(0, key.lastIndexOf('/'));
new File(d).mkdirs();
}
String destpath = (destdir != null? destdir + "/": "") + key + ".class";
if (verbose)
System.out.println(" " + destpath + " (" + bytes.length + " bytes)");
FileOutputStream fos = new FileOutputStream(destpath);
fos.write(bytes);
fos.close();
}
// try to load the files
if (loadclasses) {
ClassLoader loader = new LocalClassLoader(t);
for ( Enumeration e = t.keys(); e.hasMoreElements(); ) {
String classname = (String) e.nextElement();
try {
Class c = loader.loadClass(classname);
Object o = c.newInstance();
if ( verbose )
System.out.println(" loaded "+classname+" as "+o );
} catch ( Exception ex ) {
System.out.flush();
System.err.println(" failed to load "+classname+": "+ex );
System.err.flush();
}
}
}
} catch ( Exception e ) {
System.err.println(" failed to load "+inf.srcfilename+": "+e );
e.printStackTrace( System.err );
for (Enumeration e = t.keys(); e.hasMoreElements();) {
String classname = (String) e.nextElement();
try {
Class c = loader.loadClass(classname);
Object o = c.newInstance();
if (verbose)
System.out.println(" loaded " + classname + " as " + o);
} catch (Exception ex) {
System.out.flush();
System.err.println(" failed to load " + classname + ": " + ex);
System.err.flush();
}
}
}
} catch (Exception e) {
System.err.println(" failed to load " + inf.srcfilename + ": " + e);
e.printStackTrace(System.err);
System.err.flush();
}
}

View File

@@ -25,12 +25,12 @@ import java.util.ArrayList;
import java.util.List;
public class Block extends Stat {
public List<Stat> stats = new ArrayList<Stat>();
public NameScope scope;
public NameScope scope;
public void add(Stat s) {
if ( s == null )
if (s == null)
return;
stats.add(s);
}

View File

@@ -23,12 +23,12 @@ package org.luaj.vm2.ast;
public class Chunk extends SyntaxElement {
public final Block block;
public Chunk(Block b) {
this.block = b;
}
public void accept( Visitor visitor ) {
visitor.visit( this );
public void accept(Visitor visitor) {
visitor.visit(this);
}
}

View File

@@ -24,16 +24,15 @@ package org.luaj.vm2.ast;
import org.luaj.vm2.Lua;
import org.luaj.vm2.LuaValue;
abstract
public class Exp extends SyntaxElement {
abstract public class Exp extends SyntaxElement {
abstract public void accept(Visitor visitor);
public static Exp constant(LuaValue value) {
return new Constant(value);
}
public static Exp numberconstant(String token) {
return new Constant( LuaValue.valueOf(token).tonumber() );
public static Exp numberconstant(String token) {
return new Constant(LuaValue.valueOf(token).tonumber());
}
public static Exp varargs() {
@@ -45,59 +44,78 @@ public class Exp extends SyntaxElement {
}
public static Exp unaryexp(int op, Exp rhs) {
if ( rhs instanceof BinopExp ) {
if (rhs instanceof BinopExp) {
BinopExp b = (BinopExp) rhs;
if ( precedence(op) > precedence(b.op) )
return binaryexp( unaryexp(op, b.lhs), b.op, b.rhs );
if (precedence(op) > precedence(b.op))
return binaryexp(unaryexp(op, b.lhs), b.op, b.rhs);
}
return new UnopExp(op, rhs);
}
public static Exp binaryexp(Exp lhs, int op, Exp rhs) {
if ( lhs instanceof UnopExp ) {
if (lhs instanceof UnopExp) {
UnopExp u = (UnopExp) lhs;
if ( precedence(op) > precedence(u.op) )
return unaryexp( u.op, binaryexp( u.rhs, op, rhs ) );
if (precedence(op) > precedence(u.op))
return unaryexp(u.op, binaryexp(u.rhs, op, rhs));
}
// TODO: cumulate string concatenations together
// TODO: constant folding
if ( lhs instanceof BinopExp ) {
if (lhs instanceof BinopExp) {
BinopExp b = (BinopExp) lhs;
if ( (precedence(op) > precedence(b.op)) ||
((precedence(op) == precedence(b.op)) && isrightassoc(op)) )
return binaryexp( b.lhs, b.op, binaryexp( b.rhs, op, rhs ) );
if ((precedence(op) > precedence(b.op)) || ((precedence(op) == precedence(b.op)) && isrightassoc(op)))
return binaryexp(b.lhs, b.op, binaryexp(b.rhs, op, rhs));
}
if ( rhs instanceof BinopExp ) {
if (rhs instanceof BinopExp) {
BinopExp b = (BinopExp) rhs;
if ( (precedence(op) > precedence(b.op)) ||
((precedence(op) == precedence(b.op)) && ! isrightassoc(op)) )
return binaryexp( binaryexp( lhs, op, b.lhs ), b.op, b.rhs );
if ((precedence(op) > precedence(b.op)) || ((precedence(op) == precedence(b.op)) && !isrightassoc(op)))
return binaryexp(binaryexp(lhs, op, b.lhs), b.op, b.rhs);
}
return new BinopExp(lhs, op, rhs);
}
static boolean isrightassoc(int op) {
switch ( op ) {
switch (op) {
case Lua.OP_CONCAT:
case Lua.OP_POW: return true;
default: return false;
case Lua.OP_POW:
return true;
default:
return false;
}
}
static int precedence(int op) {
switch ( op ) {
case Lua.OP_OR: return 0;
case Lua.OP_AND: return 1;
case Lua.OP_LT: case Lua.OP_GT: case Lua.OP_LE: case Lua.OP_GE: case Lua.OP_NEQ: case Lua.OP_EQ: return 2;
case Lua.OP_CONCAT: return 3;
case Lua.OP_ADD: case Lua.OP_SUB: return 4;
case Lua.OP_MUL: case Lua.OP_DIV: case Lua.OP_MOD: return 5;
case Lua.OP_NOT: case Lua.OP_UNM: case Lua.OP_LEN: return 6;
case Lua.OP_POW: return 7;
default: throw new IllegalStateException("precedence of bad op "+op);
switch (op) {
case Lua.OP_OR:
return 0;
case Lua.OP_AND:
return 1;
case Lua.OP_LT:
case Lua.OP_GT:
case Lua.OP_LE:
case Lua.OP_GE:
case Lua.OP_NEQ:
case Lua.OP_EQ:
return 2;
case Lua.OP_CONCAT:
return 3;
case Lua.OP_ADD:
case Lua.OP_SUB:
return 4;
case Lua.OP_MUL:
case Lua.OP_DIV:
case Lua.OP_MOD:
return 5;
case Lua.OP_NOT:
case Lua.OP_UNM:
case Lua.OP_LEN:
return 6;
case Lua.OP_POW:
return 7;
default:
throw new IllegalStateException("precedence of bad op " + op);
}
}
}
public static Exp anonymousfunction(FuncBody funcbody) {
return new AnonFuncDef(funcbody);
}
@@ -143,11 +161,12 @@ public class Exp extends SyntaxElement {
public boolean isvarargexp() {
return false;
}
abstract public static class PrimaryExp extends Exp {
public boolean isvarexp() {
return false;
}
public boolean isfunccall() {
return false;
}
@@ -157,64 +176,71 @@ public class Exp extends SyntaxElement {
public boolean isvarexp() {
return true;
}
public void markHasAssignment() {
}
}
public static class NameExp extends VarExp {
public final Name name;
public NameExp(String name) {
this.name = new Name(name);
}
public void markHasAssignment() {
name.variable.hasassignments = true;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
public static class ParensExp extends PrimaryExp {
public final Exp exp;
public ParensExp(Exp exp) {
this.exp = exp;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
public static class FieldExp extends VarExp {
public final PrimaryExp lhs;
public final Name name;
public final Name name;
public FieldExp(PrimaryExp lhs, String name) {
this.lhs = lhs;
this.name = new Name(name);
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
public static class IndexExp extends VarExp {
public final PrimaryExp lhs;
public final Exp exp;
public final Exp exp;
public IndexExp(PrimaryExp lhs, Exp exp) {
this.lhs = lhs;
this.exp = exp;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
public static class FuncCall extends PrimaryExp {
public final PrimaryExp lhs;
public final FuncArgs args;
public final FuncArgs args;
public FuncCall(PrimaryExp lhs, FuncArgs args) {
this.lhs = lhs;
this.args = args;
@@ -223,19 +249,19 @@ public class Exp extends SyntaxElement {
public boolean isfunccall() {
return true;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
public boolean isvarargexp() {
return true;
}
}
public static class MethodCall extends FuncCall {
public final String name;
public MethodCall(PrimaryExp lhs, String name, FuncArgs args) {
super(lhs, args);
this.name = new String(name);
@@ -244,7 +270,7 @@ public class Exp extends SyntaxElement {
public boolean isfunccall() {
return true;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
@@ -252,29 +278,31 @@ public class Exp extends SyntaxElement {
public static class Constant extends Exp {
public final LuaValue value;
public Constant(LuaValue value) {
this.value = value;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
}
public static class VarargsExp extends Exp {
public void accept(Visitor visitor) {
visitor.visit(this);
}
public boolean isvarargexp() {
return true;
}
}
public static class UnopExp extends Exp {
public final int op;
public final Exp rhs;
public UnopExp(int op, Exp rhs) {
this.op = op;
this.rhs = rhs;
@@ -282,12 +310,13 @@ public class Exp extends SyntaxElement {
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
}
public static class BinopExp extends Exp {
public final Exp lhs,rhs;
public final Exp lhs, rhs;
public final int op;
public BinopExp(Exp lhs, int op, Exp rhs) {
this.lhs = lhs;
this.op = op;
@@ -296,18 +325,19 @@ public class Exp extends SyntaxElement {
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
}
public static class AnonFuncDef extends Exp {
public final FuncBody body;
public AnonFuncDef(FuncBody funcbody) {
this.body = funcbody;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
}
}

View File

@@ -29,7 +29,7 @@ import org.luaj.vm2.LuaString;
public class FuncArgs extends SyntaxElement {
public final List<Exp> exps;
/** exp1,exp2... */
public static FuncArgs explist(List<Exp> explist) {
return new FuncArgs(explist);
@@ -51,12 +51,12 @@ public class FuncArgs extends SyntaxElement {
public FuncArgs(LuaString string) {
this.exps = new ArrayList<Exp>();
this.exps.add( Exp.constant(string) );
this.exps.add(Exp.constant(string));
}
public FuncArgs(TableConstructor table) {
this.exps = new ArrayList<Exp>();
this.exps.add( table );
this.exps.add(table);
}
public void accept(Visitor visitor) {

View File

@@ -22,14 +22,15 @@
package org.luaj.vm2.ast;
public class FuncBody extends SyntaxElement {
public ParList parlist;
public Block block;
public ParList parlist;
public Block block;
public NameScope scope;
public FuncBody(ParList parlist, Block block) {
this.parlist = parlist!=null? parlist: ParList.EMPTY_PARLIST;
this.parlist = parlist != null? parlist: ParList.EMPTY_PARLIST;
this.block = block;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}

View File

@@ -26,24 +26,24 @@ import java.util.List;
public class FuncName extends SyntaxElement {
// example: a.b.c.d:e
// initial base name: "a"
public final Name name;
// intermediate field accesses: "b", "c", "d"
public List<String> dots;
// optional final method name: "e"
public String method;
public FuncName( String name ) {
public FuncName(String name) {
this.name = new Name(name);
}
public void adddot(String dot) {
if ( dots == null )
if (dots == null)
dots = new ArrayList<String>();
dots.add(dot);
}
}

View File

@@ -21,10 +21,10 @@
******************************************************************************/
package org.luaj.vm2.ast;
public class Name {
public final String name;
public Variable variable;
public Variable variable;
public Name(String name) {
this.name = name;
}

View File

@@ -13,10 +13,10 @@ import org.luaj.vm2.ast.Stat.LocalAssign;
import org.luaj.vm2.ast.Stat.LocalFuncDef;
import org.luaj.vm2.ast.Stat.NumericFor;
/**
* Visitor that resolves names to scopes.
* Each Name is resolved to a NamedVarible, possibly in a NameScope
* if it is a local, or in no named scope if it is a global.
/**
* Visitor that resolves names to scopes. Each Name is resolved to a
* NamedVarible, possibly in a NameScope if it is a local, or in no named scope
* if it is a global.
*/
public class NameResolver extends Visitor {
@@ -25,12 +25,13 @@ public class NameResolver extends Visitor {
private void pushScope() {
scope = new NameScope(scope);
}
private void popScope() {
scope = scope.outerScope;
}
public void visit(NameScope scope) {
}
}
public void visit(Block block) {
pushScope();
@@ -38,7 +39,7 @@ public class NameResolver extends Visitor {
super.visit(block);
popScope();
}
public void visit(FuncBody body) {
pushScope();
scope.functionNestingCount++;
@@ -46,7 +47,7 @@ public class NameResolver extends Visitor {
super.visit(body);
popScope();
}
public void visit(LocalFuncDef stat) {
defineLocalVar(stat.name);
super.visit(stat);
@@ -63,7 +64,7 @@ public class NameResolver extends Visitor {
public void visit(GenericFor stat) {
pushScope();
stat.scope = scope;
defineLocalVars( stat.names );
defineLocalVars(stat.names);
super.visit(stat);
popScope();
}
@@ -72,16 +73,16 @@ public class NameResolver extends Visitor {
exp.name.variable = resolveNameReference(exp.name);
super.visit(exp);
}
public void visit(FuncDef stat) {
stat.name.name.variable = resolveNameReference(stat.name.name);
stat.name.name.variable.hasassignments = true;
super.visit(stat);
}
public void visit(Assign stat) {
super.visit(stat);
for ( int i=0, n=stat.vars.size(); i<n; i++ ) {
for (int i = 0, n = stat.vars.size(); i < n; i++) {
VarExp v = (VarExp) stat.vars.get(i);
v.markHasAssignment();
}
@@ -89,38 +90,38 @@ public class NameResolver extends Visitor {
public void visit(LocalAssign stat) {
visitExps(stat.values);
defineLocalVars( stat.names );
defineLocalVars(stat.names);
int n = stat.names.size();
int m = stat.values!=null? stat.values.size(): 0;
boolean isvarlist = m>0 && m<n && ((Exp)stat.values.get(m-1)).isvarargexp();
for ( int i=0; i<n && i<(isvarlist?m-1:m); i++ )
if ( stat.values.get(i) instanceof Constant )
((Name)stat.names.get(i)).variable.initialValue = ((Constant) stat.values.get(i)).value;
if ( !isvarlist )
for ( int i=m; i<n; i++ )
((Name)stat.names.get(i)).variable.initialValue = LuaValue.NIL;
int m = stat.values != null? stat.values.size(): 0;
boolean isvarlist = m > 0 && m < n && ((Exp) stat.values.get(m-1)).isvarargexp();
for (int i = 0; i < n && i < (isvarlist? m-1: m); i++)
if (stat.values.get(i) instanceof Constant)
((Name) stat.names.get(i)).variable.initialValue = ((Constant) stat.values.get(i)).value;
if (!isvarlist)
for (int i = m; i < n; i++)
((Name) stat.names.get(i)).variable.initialValue = LuaValue.NIL;
}
public void visit(ParList pars) {
if ( pars.names != null )
if (pars.names != null)
defineLocalVars(pars.names);
if ( pars.isvararg )
if (pars.isvararg)
scope.define("arg");
super.visit(pars);
}
protected void defineLocalVars(List<Name> names) {
for ( int i=0, n=names.size(); i<n; i++ )
for (int i = 0, n = names.size(); i < n; i++)
defineLocalVar((Name) names.get(i));
}
protected void defineLocalVar(Name name) {
name.variable = scope.define(name.name);
}
protected Variable resolveNameReference(Name name) {
Variable v = scope.find(name.name);
if ( v.isLocal() && scope.functionNestingCount != v.definingScope.functionNestingCount )
if (v.isLocal() && scope.functionNestingCount != v.definingScope.functionNestingCount)
v.isupvalue = true;
return v;
}

View File

@@ -26,60 +26,62 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class NameScope {
private static final Set<String> LUA_KEYWORDS = new HashSet<String>();
static {
String[] k = new String[] {
"and", "break", "do", "else", "elseif", "end",
"false", "for", "function", "if", "in", "local",
"nil", "not", "or", "repeat", "return",
"then", "true", "until", "while" };
for ( int i=0; i<k.length; i++ )
LUA_KEYWORDS.add( k[i] );
static {
String[] k = new String[] { "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if",
"in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while" };
for (int i = 0; i < k.length; i++)
LUA_KEYWORDS.add(k[i]);
}
public final Map<String,Variable> namedVariables = new HashMap<String,Variable>();
public final Map<String, Variable> namedVariables = new HashMap<String, Variable>();
public final NameScope outerScope;
public int functionNestingCount;
/** Construct default names scope */
public NameScope() {
this.outerScope = null;
this.functionNestingCount = 0;
}
/** Construct name scope within another scope*/
/** Construct name scope within another scope */
public NameScope(NameScope outerScope) {
this.outerScope = outerScope;
this.functionNestingCount = outerScope!=null? outerScope.functionNestingCount: 0;
this.functionNestingCount = outerScope != null? outerScope.functionNestingCount: 0;
}
/** Look up a name. If it is a global name, then throw IllegalArgumentException. */
public Variable find( String name ) throws IllegalArgumentException {
/**
* Look up a name. If it is a global name, then throw
* IllegalArgumentException.
*/
public Variable find(String name) throws IllegalArgumentException {
validateIsNotKeyword(name);
for ( NameScope n = this; n!=null; n=n.outerScope )
if ( n.namedVariables.containsKey(name) )
return (Variable)n.namedVariables.get(name);
for (NameScope n = this; n != null; n = n.outerScope)
if (n.namedVariables.containsKey(name))
return (Variable) n.namedVariables.get(name);
Variable value = new Variable(name);
this.namedVariables.put(name, value);
return value;
}
/** Define a name in this scope. If it is a global name, then throw IllegalArgumentException. */
public Variable define( String name ) throws IllegalStateException, IllegalArgumentException {
/**
* Define a name in this scope. If it is a global name, then throw
* IllegalArgumentException.
*/
public Variable define(String name) throws IllegalStateException, IllegalArgumentException {
validateIsNotKeyword(name);
Variable value = new Variable(name, this);
this.namedVariables.put(name, value);
return value;
}
private void validateIsNotKeyword(String name) {
if ( LUA_KEYWORDS.contains(name) )
throw new IllegalArgumentException("name is a keyword: '"+name+"'");
if (LUA_KEYWORDS.contains(name))
throw new IllegalArgumentException("name is a keyword: '" + name + "'");
}
}

View File

@@ -26,10 +26,10 @@ import java.util.List;
public class ParList extends SyntaxElement {
public static final List<Name> EMPTY_NAMELIST = new ArrayList<Name>();
public static final ParList EMPTY_PARLIST = new ParList(EMPTY_NAMELIST,false);
public static final ParList EMPTY_PARLIST = new ParList(EMPTY_NAMELIST, false);
public final List<Name> names;
public final boolean isvararg;
public final boolean isvararg;
public ParList(List<Name> names, boolean isvararg) {
this.names = names;

View File

@@ -25,8 +25,7 @@ import java.util.List;
import org.luaj.vm2.ast.Exp.VarExp;
abstract
public class Stat extends SyntaxElement {
abstract public class Stat extends SyntaxElement {
public abstract void accept(Visitor visitor);
public static Stat block(Block block) {
@@ -39,8 +38,8 @@ public class Stat extends SyntaxElement {
public static Stat repeatuntil(Block block, Exp exp) {
return new RepeatUntil(block, exp);
}
}
public static Stat breakstat() {
return new Break();
}
@@ -50,7 +49,7 @@ public class Stat extends SyntaxElement {
}
public static Stat assignment(List<VarExp> vars, List<Exp> exps) {
return new Assign(vars,exps);
return new Assign(vars, exps);
}
public static Stat functioncall(Exp.FuncCall funccall) {
@@ -66,18 +65,19 @@ public class Stat extends SyntaxElement {
}
public static Stat functiondef(FuncName funcname, FuncBody funcbody) {
return new FuncDef( funcname, funcbody );
return new FuncDef(funcname, funcbody);
}
public static Stat forgeneric(List<Name> names, List<Exp> exps, Block block) {
return new GenericFor(names, exps, block);
return new GenericFor(names, exps, block);
}
public static Stat localassignment(List<Name> names, List<Exp> values) {
return new LocalAssign(names, values);
}
public static Stat ifthenelse(Exp ifexp, Block ifblock, List<Exp> elseifexps, List<Block> elseifblocks, Block elseblock) {
public static Stat ifthenelse(Exp ifexp, Block ifblock, List<Exp> elseifexps, List<Block> elseifblocks,
Block elseblock) {
return new IfThenElse(ifexp, ifblock, elseifexps, elseifblocks, elseblock);
}
@@ -91,9 +91,11 @@ public class Stat extends SyntaxElement {
public static class Goto extends Stat {
public final String name;
public Goto(String name) {
this.name = name;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
@@ -101,9 +103,11 @@ public class Stat extends SyntaxElement {
public static class Label extends Stat {
public final String name;
public Label(String name) {
this.name = name;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
@@ -111,8 +115,8 @@ public class Stat extends SyntaxElement {
public static class Assign extends Stat {
public final List<VarExp> vars;
public final List<Exp> exps;
public final List<Exp> exps;
public Assign(List<VarExp> vars, List<Exp> exps) {
this.vars = vars;
this.exps = exps;
@@ -125,95 +129,104 @@ public class Stat extends SyntaxElement {
}
public static class WhileDo extends Stat {
public final Exp exp;
public final Exp exp;
public final Block block;
public WhileDo( Exp exp, Block block ) {
public WhileDo(Exp exp, Block block) {
this.exp = exp;
this.block = block;
}
public void accept(Visitor visitor) {
visitor.visit( this );
visitor.visit(this);
}
}
}
public static class RepeatUntil extends Stat {
public final Block block;
public final Exp exp;
public RepeatUntil( Block block, Exp exp ) {
public final Exp exp;
public RepeatUntil(Block block, Exp exp) {
this.block = block;
this.exp = exp;
}
public void accept(Visitor visitor) {
visitor.visit( this );
visitor.visit(this);
}
}
public static class Break extends Stat {
public void accept(Visitor visitor) {
visitor.visit( this );
visitor.visit(this);
}
}
public static class Return extends Stat {
public final List<Exp> values;
public Return(List<Exp> values) {
this.values = values;
}
public void accept(Visitor visitor) {
visitor.visit( this );
visitor.visit(this);
}
public int nreturns() {
int n = values!=null? values.size(): 0;
if ( n>0 && ((Exp)values.get(n-1)).isvarargexp() )
int n = values != null? values.size(): 0;
if (n > 0 && ((Exp) values.get(n-1)).isvarargexp())
n = -1;
return n;
return n;
}
}
public static class FuncCallStat extends Stat {
public final Exp.FuncCall funccall;
public FuncCallStat(Exp.FuncCall funccall) {
this.funccall = funccall;
}
public void accept(Visitor visitor) {
visitor.visit( this );
visitor.visit(this);
}
}
public static class LocalFuncDef extends Stat {
public final Name name;
public final Name name;
public final FuncBody body;
public LocalFuncDef(String name, FuncBody body) {
this.name = new Name(name);
this.body = body;
}
public void accept(Visitor visitor) {
visitor.visit( this );
visitor.visit(this);
}
}
public static class FuncDef extends Stat {
public final FuncName name;
public final FuncBody body;
public FuncDef(FuncName name, FuncBody body) {
this.name = name;
this.body = body;
}
public void accept(Visitor visitor) {
visitor.visit( this );
visitor.visit(this);
}
}
public static class GenericFor extends Stat {
public List<Name> names;
public List<Exp> exps;
public Block block;
public NameScope scope;
public List<Exp> exps;
public Block block;
public NameScope scope;
public GenericFor(List<Name> names, List<Exp> exps, Block block) {
this.names = names;
this.exps = exps;
@@ -221,15 +234,16 @@ public class Stat extends SyntaxElement {
}
public void accept(Visitor visitor) {
visitor.visit( this );
visitor.visit(this);
}
}
public static class NumericFor extends Stat {
public final Name name;
public final Exp initial,limit,step;
public final Name name;
public final Exp initial, limit, step;
public final Block block;
public NameScope scope;
public NameScope scope;
public NumericFor(String name, Exp initial, Exp limit, Exp step, Block block) {
this.name = new Name(name);
this.initial = initial;
@@ -239,31 +253,32 @@ public class Stat extends SyntaxElement {
}
public void accept(Visitor visitor) {
visitor.visit( this );
visitor.visit(this);
}
}
public static class LocalAssign extends Stat {
public final List<Name> names;
public final List<Exp> values;
public final List<Exp> values;
public LocalAssign(List<Name> names, List<Exp> values) {
this.names = names;
this.values = values;
}
public void accept(Visitor visitor) {
visitor.visit( this );
visitor.visit(this);
}
}
public static class IfThenElse extends Stat {
public final Exp ifexp;
public final Block ifblock;
public final List<Exp> elseifexps;
public final Exp ifexp;
public final Block ifblock;
public final List<Exp> elseifexps;
public final List<Block> elseifblocks;
public final Block elseblock;
public IfThenElse(Exp ifexp, Block ifblock, List<Exp> elseifexps,
List<Block> elseifblocks, Block elseblock) {
public final Block elseblock;
public IfThenElse(Exp ifexp, Block ifblock, List<Exp> elseifexps, List<Block> elseifblocks, Block elseblock) {
this.ifexp = ifexp;
this.ifblock = ifblock;
this.elseifexps = elseifexps;
@@ -272,7 +287,7 @@ public class Stat extends SyntaxElement {
}
public void accept(Visitor visitor) {
visitor.visit( this );
visitor.visit(this);
}
}
}

View File

@@ -27,65 +27,95 @@ import java.io.UnsupportedEncodingException;
import org.luaj.vm2.LuaString;
public class Str {
private Str() {}
public static LuaString quoteString(String image) {
String s = image.substring(1, image.length()-1);
byte[] bytes = unquote(s);
return LuaString.valueUsing(bytes);
}
public static LuaString charString(String image) {
String s = image.substring(1, image.length()-1);
byte[] bytes = unquote(s);
return LuaString.valueUsing(bytes);
}
public static LuaString longString(String image) {
int i = image.indexOf('[', image.indexOf('[')+1)+1;
String s = image.substring(i,image.length()-i);
String s = image.substring(i, image.length()-i);
byte[] b = iso88591bytes(s);
return LuaString.valueUsing(b);
}
public static byte[] iso88591bytes( String s ) {
public static byte[] iso88591bytes(String s) {
try {
return s.getBytes("ISO8859-1");
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException("ISO8859-1 not supported");
}
}
public static byte[] unquote(String s) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
char[] c = s.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 );
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;
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] );
baos.write((byte) c[i]);
}
}
return baos.toByteArray();

View File

@@ -21,17 +21,18 @@
******************************************************************************/
package org.luaj.vm2.ast;
/** Base class for syntax elements of the parse tree that appear in source files.
* The LuaParser class will fill these values out during parsing for use in
/**
* Base class for syntax elements of the parse tree that appear in source files.
* The LuaParser class will fill these values out during parsing for use in
* syntax highlighting, for example.
*/
public class SyntaxElement {
/** The line number on which the element begins. */
public int beginLine;
/** The column at which the element begins. */
public short beginColumn;
/** The line number on which the element ends. */
public int endLine;

View File

@@ -23,16 +23,16 @@ package org.luaj.vm2.ast;
public class TableField extends SyntaxElement {
public final Exp index;
public final Exp index;
public final String name;
public final Exp rhs;
public final Exp rhs;
public TableField(Exp index, String name, Exp rhs) {
this.index = index;
this.name = name;
this.rhs = rhs;
}
public static TableField keyedField(Exp index, Exp rhs) {
return new TableField(index, null, rhs);
}

View File

@@ -23,40 +23,43 @@ package org.luaj.vm2.ast;
import org.luaj.vm2.LuaValue;
/** Variable is created lua name scopes, and is a named, lua variable that
* either refers to a lua local, global, or upvalue storage location.
/**
* Variable is created lua name scopes, and is a named, lua variable that either
* refers to a lua local, global, or upvalue storage location.
*/
public class Variable {
/** The name as it appears in lua source code */
public final String name;
/** The lua scope in which this variable is defined. */
/** The lua scope in which this variable is defined. */
public final NameScope definingScope;
/** true if this variable is an upvalue */
public boolean isupvalue;
/** true if there are assignments made to this variable */
public boolean hasassignments;
/** When hasassignments == false, and the initial value is a constant, this is the initial value */
/**
* When hasassignments == false, and the initial value is a constant, this
* is the initial value
*/
public LuaValue initialValue;
/** Global is named variable not associated with a defining scope */
public Variable(String name) {
this.name = name;
this.definingScope = null;
}
public Variable(String name, NameScope definingScope) {
/** Local variable is defined in a particular scope. */
/** Local variable is defined in a particular scope. */
this.name = name;
this.definingScope = definingScope;
}
public boolean isLocal() {
return this.definingScope != null;
}
public boolean isConstant() {
return ! hasassignments && initialValue != null;
}
}
public boolean isLocal() { return this.definingScope != null; }
public boolean isConstant() { return !hasassignments && initialValue != null; }
}

View File

@@ -26,155 +26,192 @@ import java.util.List;
import org.luaj.vm2.ast.Exp.VarExp;
abstract public class Visitor {
public void visit(Chunk chunk) {
chunk.block.accept(this);
public void visit(Chunk chunk) {
chunk.block.accept(this);
};
public void visit(Block block) {
visit(block.scope);
if ( block.stats != null )
for ( int i=0, n=block.stats.size(); i<n; i++ )
((Stat)block.stats.get(i)).accept(this);
if (block.stats != null)
for (int i = 0, n = block.stats.size(); i < n; i++)
((Stat) block.stats.get(i)).accept(this);
};
public void visit(Stat.Assign stat) {
visitVars(stat.vars);
visitExps(stat.exps);
}
public void visit(Stat.Break breakstat) {
}
public void visit(Stat.FuncCallStat stat) {
stat.funccall.accept(this);
}
public void visit(Stat.FuncDef stat) {
stat.body.accept(this);
}
public void visit(Stat.GenericFor stat) {
visit(stat.scope);
visitNames(stat.names);
visitExps(stat.exps);
stat.block.accept(this);
}
public void visit(Stat.IfThenElse stat) {
stat.ifexp.accept(this);
stat.ifblock.accept(this);
if ( stat.elseifblocks != null )
for ( int i=0, n=stat.elseifblocks.size(); i<n; i++ ) {
((Exp)stat.elseifexps.get(i)).accept(this);
((Block)stat.elseifblocks.get(i)).accept(this);
if (stat.elseifblocks != null)
for (int i = 0, n = stat.elseifblocks.size(); i < n; i++) {
((Exp) stat.elseifexps.get(i)).accept(this);
((Block) stat.elseifblocks.get(i)).accept(this);
}
if ( stat.elseblock != null )
visit( stat.elseblock );
if (stat.elseblock != null)
visit(stat.elseblock);
}
public void visit(Stat.LocalAssign stat) {
visitNames(stat.names);
visitExps(stat.values);
}
public void visit(Stat.LocalFuncDef stat) {
visit(stat.name);
stat.body.accept(this);
}
public void visit(Stat.NumericFor stat) {
visit(stat.scope);
visit(stat.name);
stat.initial.accept(this);
stat.limit.accept(this);
if ( stat.step != null )
if (stat.step != null)
stat.step.accept(this);
stat.block.accept(this);
}
public void visit(Stat.RepeatUntil stat) {
stat.block.accept(this);
stat.exp.accept(this);
}
public void visit(Stat.Return stat) {
visitExps(stat.values);
}
public void visit(Stat.WhileDo stat) {
stat.exp.accept(this);
stat.block.accept(this);
}
public void visit(FuncBody body) {
visit(body.scope);
body.parlist.accept(this);
body.block.accept(this);
}
public void visit(FuncArgs args) {
visitExps(args.exps);
}
public void visit(TableField field) {
if ( field.name != null )
visit( field.name );
if ( field.index != null )
if (field.name != null)
visit(field.name);
if (field.index != null)
field.index.accept(this);
field.rhs.accept(this);
}
public void visit(Exp.AnonFuncDef exp) {
exp.body.accept(this);
}
public void visit(Exp.BinopExp exp) {
exp.lhs.accept(this);
exp.rhs.accept(this);
}
public void visit(Exp.Constant exp) {
}
public void visit(Exp.FieldExp exp) {
exp.lhs.accept(this);
visit(exp.name);
}
public void visit(Exp.FuncCall exp) {
exp.lhs.accept(this);
exp.args.accept(this);
}
public void visit(Exp.IndexExp exp) {
exp.lhs.accept(this);
exp.exp.accept(this);
}
public void visit(Exp.MethodCall exp) {
exp.lhs.accept(this);
visit(exp.name);
exp.args.accept(this);
}
public void visit(Exp.NameExp exp) {
visit(exp.name);
}
public void visit(Exp.ParensExp exp) {
exp.exp.accept(this);
}
public void visit(Exp.UnopExp exp) {
exp.rhs.accept(this);
}
public void visit(Exp.VarargsExp exp) {
}
public void visit(ParList pars) {
visitNames(pars.names);
}
public void visit(TableConstructor table) {
if( table.fields != null)
for ( int i=0, n=table.fields.size(); i<n; i++ )
((TableField)table.fields.get(i)).accept(this);
if (table.fields != null)
for (int i = 0, n = table.fields.size(); i < n; i++)
((TableField) table.fields.get(i)).accept(this);
}
public void visitVars(List<VarExp> vars) {
if ( vars != null )
for ( int i=0, n=vars.size(); i<n; i++ )
((Exp.VarExp)vars.get(i)).accept(this);
if (vars != null)
for (int i = 0, n = vars.size(); i < n; i++)
((Exp.VarExp) vars.get(i)).accept(this);
}
public void visitExps(List<Exp> exps) {
if ( exps != null )
for ( int i=0, n=exps.size(); i<n; i++ )
((Exp)exps.get(i)).accept(this);
if (exps != null)
for (int i = 0, n = exps.size(); i < n; i++)
((Exp) exps.get(i)).accept(this);
}
public void visitNames(List<Name> names) {
if ( names != null )
for ( int i=0, n=names.size(); i<n; i++ )
if (names != null)
for (int i = 0, n = names.size(); i < n; i++)
visit((Name) names.get(i));
}
public void visit(Name name) {
}
public void visit(String name) {
}
public void visit(NameScope scope) {
}
public void visit(Stat.Goto gotostat) {
}
public void visit(Stat.Label label) {
}
}

View File

@@ -32,13 +32,13 @@ import org.luaj.vm2.LuaUserdata;
import org.luaj.vm2.LuaValue;
/**
* Helper class to coerce values from Java to lua within the luajava library.
* Helper class to coerce values from Java to lua within the luajava library.
* <p>
* This class is primarily used by the {@link org.luaj.vm2.lib.jse.LuajavaLib},
* but can also be used directly when working with Java/lua bindings.
* This class is primarily used by the {@link org.luaj.vm2.lib.jse.LuajavaLib},
* but can also be used directly when working with Java/lua bindings.
* <p>
* To coerce scalar types, the various, generally the {@code valueOf(type)} methods
* on {@link LuaValue} may be used:
* To coerce scalar types, the various, generally the {@code valueOf(type)}
* methods on {@link LuaValue} may be used:
* <ul>
* <li>{@link LuaValue#valueOf(boolean)}</li>
* <li>{@link LuaValue#valueOf(byte[])}</li>
@@ -47,69 +47,69 @@ import org.luaj.vm2.LuaValue;
* <li>{@link LuaValue#valueOf(String)}</li>
* </ul>
* <p>
* To coerce arrays of objects and lists, the {@code listOf(..)} and {@code tableOf(...)} methods
* on {@link LuaValue} may be used:
* To coerce arrays of objects and lists, the {@code listOf(..)} and
* {@code tableOf(...)} methods on {@link LuaValue} may be used:
* <ul>
* <li>{@link LuaValue#listOf(LuaValue[])}</li>
* <li>{@link LuaValue#listOf(LuaValue[], org.luaj.vm2.Varargs)}</li>
* <li>{@link LuaValue#tableOf(LuaValue[])}</li>
* <li>{@link LuaValue#tableOf(LuaValue[], LuaValue[], org.luaj.vm2.Varargs)}</li>
* </ul>
* The method {@link CoerceJavaToLua#coerce(Object)} looks as the type and dimesioning
* of the argument and tries to guess the best fit for corrsponding lua scalar,
* table, or table of tables.
* The method {@link CoerceJavaToLua#coerce(Object)} looks as the type and
* dimesioning of the argument and tries to guess the best fit for corrsponding
* lua scalar, table, or table of tables.
*
* @see CoerceJavaToLua#coerce(Object)
* @see org.luaj.vm2.lib.jse.LuajavaLib
*/
public class CoerceJavaToLua {
static interface Coercion {
public LuaValue coerce( Object javaValue );
static interface Coercion {
public LuaValue coerce(Object javaValue);
};
private static final class BoolCoercion implements Coercion {
public LuaValue coerce( Object javaValue ) {
public LuaValue coerce(Object javaValue) {
Boolean b = (Boolean) javaValue;
return b.booleanValue()? LuaValue.TRUE: LuaValue.FALSE;
}
}
private static final class IntCoercion implements Coercion {
public LuaValue coerce( Object javaValue ) {
public LuaValue coerce(Object javaValue) {
Number n = (Number) javaValue;
return LuaInteger.valueOf( n.intValue() );
return LuaInteger.valueOf(n.intValue());
}
}
private static final class CharCoercion implements Coercion {
public LuaValue coerce( Object javaValue ) {
public LuaValue coerce(Object javaValue) {
Character c = (Character) javaValue;
return LuaInteger.valueOf( c.charValue() );
return LuaInteger.valueOf(c.charValue());
}
}
private static final class DoubleCoercion implements Coercion {
public LuaValue coerce( Object javaValue ) {
public LuaValue coerce(Object javaValue) {
Number n = (Number) javaValue;
return LuaDouble.valueOf( n.doubleValue() );
return LuaDouble.valueOf(n.doubleValue());
}
}
private static final class StringCoercion implements Coercion {
public LuaValue coerce( Object javaValue ) {
return LuaString.valueOf( javaValue.toString() );
public LuaValue coerce(Object javaValue) {
return LuaString.valueOf(javaValue.toString());
}
}
private static final class BytesCoercion implements Coercion {
public LuaValue coerce( Object javaValue ) {
public LuaValue coerce(Object javaValue) {
return LuaValue.valueOf((byte[]) javaValue);
}
}
private static final class ClassCoercion implements Coercion {
public LuaValue coerce( Object javaValue ) {
public LuaValue coerce(Object javaValue) {
return JavaClass.forClass((Class) javaValue);
}
}
@@ -128,46 +128,46 @@ public class CoerceJavaToLua {
}
private static final class LuaCoercion implements Coercion {
public LuaValue coerce( Object javaValue ) {
public LuaValue coerce(Object javaValue) {
return (LuaValue) javaValue;
}
}
static final Map COERCIONS = Collections.synchronizedMap(new HashMap());
static {
Coercion boolCoercion = new BoolCoercion() ;
Coercion intCoercion = new IntCoercion() ;
Coercion charCoercion = new CharCoercion() ;
Coercion doubleCoercion = new DoubleCoercion() ;
Coercion stringCoercion = new StringCoercion() ;
Coercion bytesCoercion = new BytesCoercion() ;
Coercion classCoercion = new ClassCoercion() ;
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( Long.class, doubleCoercion );
COERCIONS.put( Float.class, doubleCoercion );
COERCIONS.put( Double.class, doubleCoercion );
COERCIONS.put( String.class, stringCoercion );
COERCIONS.put( byte[].class, bytesCoercion );
COERCIONS.put( Class.class, classCoercion );
Coercion boolCoercion = new BoolCoercion();
Coercion intCoercion = new IntCoercion();
Coercion charCoercion = new CharCoercion();
Coercion doubleCoercion = new DoubleCoercion();
Coercion stringCoercion = new StringCoercion();
Coercion bytesCoercion = new BytesCoercion();
Coercion classCoercion = new ClassCoercion();
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(Long.class, doubleCoercion);
COERCIONS.put(Float.class, doubleCoercion);
COERCIONS.put(Double.class, doubleCoercion);
COERCIONS.put(String.class, stringCoercion);
COERCIONS.put(byte[].class, bytesCoercion);
COERCIONS.put(Class.class, classCoercion);
}
/**
* Coerse a Java object to a corresponding lua value.
* Coerse a Java object to a corresponding lua value.
* <p>
* Integral types {@code boolean}, {@code byte}, {@code char}, and {@code int}
* will become {@link LuaInteger};
* {@code long}, {@code float}, and {@code double} will become {@link LuaDouble};
* {@code String} and {@code byte[]} will become {@link LuaString};
* types inheriting from {@link LuaValue} will be returned without coercion;
* other types will become {@link LuaUserdata}.
* Integral types {@code boolean}, {@code byte}, {@code char}, and
* {@code int} will become {@link LuaInteger}; {@code long}, {@code float},
* and {@code double} will become {@link LuaDouble}; {@code String} and
* {@code byte[]} will become {@link LuaString}; types inheriting from
* {@link LuaValue} will be returned without coercion; other types will
* become {@link LuaUserdata}.
*
* @param o Java object needing conversion
* @return {@link LuaValue} corresponding to the supplied Java value.
* @return {@link LuaValue} corresponding to the supplied Java value.
* @see LuaValue
* @see LuaInteger
* @see LuaDouble
@@ -175,22 +175,20 @@ public class CoerceJavaToLua {
* @see LuaUserdata
*/
public static LuaValue coerce(Object o) {
if ( o == null )
if (o == null)
return LuaValue.NIL;
Class clazz = o.getClass();
Coercion c = (Coercion) COERCIONS.get( clazz );
if ( c == null ) {
c = clazz.isArray()? arrayCoercion:
o instanceof LuaValue ? luaCoercion:
instanceCoercion;
COERCIONS.put( clazz, c );
Coercion c = (Coercion) COERCIONS.get(clazz);
if (c == null) {
c = clazz.isArray()? arrayCoercion: o instanceof LuaValue? luaCoercion: instanceCoercion;
COERCIONS.put(clazz, c);
}
return c.coerce(o);
}
static final Coercion instanceCoercion = new InstanceCoercion();
static final Coercion arrayCoercion = new ArrayCoercion();
static final Coercion luaCoercion = new LuaCoercion() ;
static final Coercion arrayCoercion = new ArrayCoercion();
static final Coercion luaCoercion = new LuaCoercion();
}

View File

@@ -31,13 +31,13 @@ import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
/**
* Helper class to coerce values from lua to Java within the luajava library.
* Helper class to coerce values from lua to Java within the luajava library.
* <p>
* This class is primarily used by the {@link org.luaj.vm2.lib.jse.LuajavaLib},
* but can also be used directly when working with Java/lua bindings.
* This class is primarily used by the {@link org.luaj.vm2.lib.jse.LuajavaLib},
* but can also be used directly when working with Java/lua bindings.
* <p>
* To coerce to specific Java values, generally the {@code toType()} methods
* on {@link LuaValue} may be used:
* To coerce to specific Java values, generally the {@code toType()} methods on
* {@link LuaValue} may be used:
* <ul>
* <li>{@link LuaValue#toboolean()}</li>
* <li>{@link LuaValue#tobyte()}</li>
@@ -51,41 +51,45 @@ import org.luaj.vm2.LuaValue;
* <li>{@link LuaValue#touserdata(Class)}</li>
* </ul>
* <p>
* For data in lua tables, the various methods on {@link LuaTable} can be used directly
* to convert data to something more useful.
* For data in lua tables, the various methods on {@link LuaTable} can be used
* directly to convert data to something more useful.
*
* @see org.luaj.vm2.lib.jse.LuajavaLib
* @see CoerceJavaToLua
*/
public class CoerceLuaToJava {
static int SCORE_NULL_VALUE = 0x10;
static int SCORE_WRONG_TYPE = 0x100;
static int SCORE_UNCOERCIBLE = 0x10000;
static interface Coercion {
public int score( LuaValue value );
public Object coerce( LuaValue value );
static int SCORE_NULL_VALUE = 0x10;
static int SCORE_WRONG_TYPE = 0x100;
static int SCORE_UNCOERCIBLE = 0x10000;
static interface Coercion {
public int score(LuaValue value);
public Object coerce(LuaValue value);
};
/**
/**
* Coerce a LuaValue value to a specified java class
*
* @param value LuaValue to coerce
* @param clazz Class to coerce into
* @return Object of type clazz (or a subclass) with the corresponding value.
* @return Object of type clazz (or a subclass) with the corresponding
* value.
*/
public static Object coerce(LuaValue value, Class clazz) {
return getCoercion(clazz).coerce(value);
}
static final Map COERCIONS = Collections.synchronizedMap(new HashMap());
static final class BoolCoercion implements Coercion {
public String toString() {
return "BoolCoercion()";
}
public int score( LuaValue value ) {
switch ( value.type() ) {
public int score(LuaValue value) {
switch (value.type()) {
case LuaValue.TBOOLEAN:
return 0;
}
@@ -98,74 +102,84 @@ public class CoerceLuaToJava {
}
static final class NumericCoercion implements Coercion {
static final int TARGET_TYPE_BYTE = 0;
static final int TARGET_TYPE_CHAR = 1;
static final int TARGET_TYPE_SHORT = 2;
static final int TARGET_TYPE_INT = 3;
static final int TARGET_TYPE_LONG = 4;
static final int TARGET_TYPE_FLOAT = 5;
static final int TARGET_TYPE_DOUBLE = 6;
static final String[] TYPE_NAMES = { "byte", "char", "short", "int", "long", "float", "double" };
final int targetType;
static final int TARGET_TYPE_BYTE = 0;
static final int TARGET_TYPE_CHAR = 1;
static final int TARGET_TYPE_SHORT = 2;
static final int TARGET_TYPE_INT = 3;
static final int TARGET_TYPE_LONG = 4;
static final int TARGET_TYPE_FLOAT = 5;
static final int TARGET_TYPE_DOUBLE = 6;
static final String[] TYPE_NAMES = { "byte", "char", "short", "int", "long", "float", "double" };
final int targetType;
public String toString() {
return "NumericCoercion("+TYPE_NAMES[targetType]+")";
return "NumericCoercion(" + TYPE_NAMES[targetType] + ")";
}
NumericCoercion(int targetType) {
this.targetType = targetType;
}
public int score( LuaValue value ) {
public int score(LuaValue value) {
int fromStringPenalty = 0;
if ( value.type() == LuaValue.TSTRING ) {
if (value.type() == LuaValue.TSTRING) {
value = value.tonumber();
if ( value.isnil() ) {
if (value.isnil()) {
return SCORE_UNCOERCIBLE;
}
fromStringPenalty = 4;
}
if ( value.isint() ) {
switch ( targetType ) {
if (value.isint()) {
switch (targetType) {
case TARGET_TYPE_BYTE: {
int i = value.toint();
return fromStringPenalty + ((i==(byte)i)? 0: SCORE_WRONG_TYPE);
return fromStringPenalty+((i == (byte) i)? 0: SCORE_WRONG_TYPE);
}
case TARGET_TYPE_CHAR: {
int i = value.toint();
return fromStringPenalty + ((i==(byte)i)? 1: (i==(char)i)? 0: SCORE_WRONG_TYPE);
return fromStringPenalty+((i == (byte) i)? 1: (i == (char) i)? 0: SCORE_WRONG_TYPE);
}
case TARGET_TYPE_SHORT: {
int i = value.toint();
return fromStringPenalty +
((i==(byte)i)? 1: (i==(short)i)? 0: SCORE_WRONG_TYPE);
return fromStringPenalty+((i == (byte) i)? 1: (i == (short) i)? 0: SCORE_WRONG_TYPE);
}
case TARGET_TYPE_INT: {
case TARGET_TYPE_INT: {
int i = value.toint();
return fromStringPenalty +
((i==(byte)i)? 2: ((i==(char)i) || (i==(short)i))? 1: 0);
return fromStringPenalty+((i == (byte) i)? 2: ((i == (char) i) || (i == (short) i))? 1: 0);
}
case TARGET_TYPE_FLOAT: return fromStringPenalty + 1;
case TARGET_TYPE_LONG: return fromStringPenalty + 1;
case TARGET_TYPE_DOUBLE: return fromStringPenalty + 2;
default: return SCORE_WRONG_TYPE;
case TARGET_TYPE_FLOAT:
return fromStringPenalty+1;
case TARGET_TYPE_LONG:
return fromStringPenalty+1;
case TARGET_TYPE_DOUBLE:
return fromStringPenalty+2;
default:
return SCORE_WRONG_TYPE;
}
} else if ( value.isnumber() ) {
switch ( targetType ) {
case TARGET_TYPE_BYTE: return SCORE_WRONG_TYPE;
case TARGET_TYPE_CHAR: return SCORE_WRONG_TYPE;
case TARGET_TYPE_SHORT: return SCORE_WRONG_TYPE;
case TARGET_TYPE_INT: return SCORE_WRONG_TYPE;
} else if (value.isnumber()) {
switch (targetType) {
case TARGET_TYPE_BYTE:
return SCORE_WRONG_TYPE;
case TARGET_TYPE_CHAR:
return SCORE_WRONG_TYPE;
case TARGET_TYPE_SHORT:
return SCORE_WRONG_TYPE;
case TARGET_TYPE_INT:
return SCORE_WRONG_TYPE;
case TARGET_TYPE_LONG: {
double d = value.todouble();
return fromStringPenalty + ((d==(long)d)? 0: SCORE_WRONG_TYPE);
return fromStringPenalty+((d == (long) d)? 0: SCORE_WRONG_TYPE);
}
case TARGET_TYPE_FLOAT: {
double d = value.todouble();
return fromStringPenalty + ((d==(float)d)? 0: SCORE_WRONG_TYPE);
return fromStringPenalty+((d == (float) d)? 0: SCORE_WRONG_TYPE);
}
case TARGET_TYPE_DOUBLE: {
double d = value.todouble();
return fromStringPenalty + (((d==(long)d) || (d==(float)d))? 1: 0);
return fromStringPenalty+(((d == (long) d) || (d == (float) d))? 1: 0);
}
default: return SCORE_WRONG_TYPE;
default:
return SCORE_WRONG_TYPE;
}
} else {
return SCORE_UNCOERCIBLE;
@@ -173,45 +187,56 @@ public class CoerceLuaToJava {
}
public Object coerce(LuaValue value) {
switch ( targetType ) {
case TARGET_TYPE_BYTE: return new Byte( (byte) value.toint() );
case TARGET_TYPE_CHAR: return new Character( (char) value.toint() );
case TARGET_TYPE_SHORT: return new Short( (short) value.toint() );
case TARGET_TYPE_INT: return new Integer( (int) value.toint() );
case TARGET_TYPE_LONG: return new Long( (long) value.todouble() );
case TARGET_TYPE_FLOAT: return new Float( (float) value.todouble() );
case TARGET_TYPE_DOUBLE: return new Double( (double) value.todouble() );
default: return null;
switch (targetType) {
case TARGET_TYPE_BYTE:
return new Byte((byte) value.toint());
case TARGET_TYPE_CHAR:
return new Character((char) value.toint());
case TARGET_TYPE_SHORT:
return new Short((short) value.toint());
case TARGET_TYPE_INT:
return new Integer((int) value.toint());
case TARGET_TYPE_LONG:
return new Long((long) value.todouble());
case TARGET_TYPE_FLOAT:
return new Float((float) value.todouble());
case TARGET_TYPE_DOUBLE:
return new Double((double) value.todouble());
default:
return null;
}
}
}
static final class StringCoercion implements Coercion {
public static final int TARGET_TYPE_STRING = 0;
public static final int TARGET_TYPE_BYTES = 1;
final int targetType;
public static final int TARGET_TYPE_BYTES = 1;
final int targetType;
public StringCoercion(int targetType) {
this.targetType = targetType;
}
public String toString() {
return "StringCoercion("+(targetType==TARGET_TYPE_STRING? "String": "byte[]")+")";
return "StringCoercion(" + (targetType == TARGET_TYPE_STRING? "String": "byte[]") + ")";
}
public int score(LuaValue value) {
switch ( value.type() ) {
switch (value.type()) {
case LuaValue.TSTRING:
return value.checkstring().isValidUtf8()?
(targetType==TARGET_TYPE_STRING? 0: 1):
(targetType==TARGET_TYPE_BYTES? 0: SCORE_WRONG_TYPE);
return value.checkstring().isValidUtf8()? (targetType == TARGET_TYPE_STRING? 0: 1)
: (targetType == TARGET_TYPE_BYTES? 0: SCORE_WRONG_TYPE);
case LuaValue.TNIL:
return SCORE_NULL_VALUE;
default:
return targetType == TARGET_TYPE_STRING? SCORE_WRONG_TYPE: SCORE_UNCOERCIBLE;
}
}
public Object coerce(LuaValue value) {
if ( value.isnil() )
if (value.isnil())
return null;
if ( targetType == TARGET_TYPE_STRING )
if (targetType == TARGET_TYPE_STRING)
return value.tojstring();
LuaString s = value.checkstring();
byte[] b = new byte[s.m_length];
@@ -221,33 +246,37 @@ public class CoerceLuaToJava {
}
static final class ArrayCoercion implements Coercion {
final Class componentType;
final Class componentType;
final Coercion componentCoercion;
public ArrayCoercion(Class componentType) {
this.componentType = componentType;
this.componentCoercion = getCoercion(componentType);
}
public String toString() {
return "ArrayCoercion("+componentType.getName()+")";
return "ArrayCoercion(" + componentType.getName() + ")";
}
public int score(LuaValue value) {
switch ( value.type() ) {
switch (value.type()) {
case LuaValue.TTABLE:
return value.length()==0? 0: componentCoercion.score( value.get(1) );
return value.length() == 0? 0: componentCoercion.score(value.get(1));
case LuaValue.TUSERDATA:
return inheritanceLevels( componentType, value.touserdata().getClass().getComponentType() );
return inheritanceLevels(componentType, value.touserdata().getClass().getComponentType());
case LuaValue.TNIL:
return SCORE_NULL_VALUE;
default:
default:
return SCORE_UNCOERCIBLE;
}
}
public Object coerce(LuaValue value) {
switch ( value.type() ) {
switch (value.type()) {
case LuaValue.TTABLE: {
int n = value.length();
Object a = Array.newInstance(componentType, n);
for ( int i=0; i<n; i++ )
for (int i = 0; i < n; i++)
Array.set(a, i, componentCoercion.coerce(value.get(i+1)));
return a;
}
@@ -255,60 +284,65 @@ public class CoerceLuaToJava {
return value.touserdata();
case LuaValue.TNIL:
return null;
default:
default:
return null;
}
}
}
/**
/**
* Determine levels of inheritance between a base class and a subclass
*
* @param baseclass base class to look for
* @param subclass class from which to start looking
* @return number of inheritance levels between subclass and baseclass,
* or SCORE_UNCOERCIBLE if not a subclass
* @param subclass class from which to start looking
* @return number of inheritance levels between subclass and baseclass, or
* SCORE_UNCOERCIBLE if not a subclass
*/
static final int inheritanceLevels( Class baseclass, Class subclass ) {
if ( subclass == null )
static final int inheritanceLevels(Class baseclass, Class subclass) {
if (subclass == null)
return SCORE_UNCOERCIBLE;
if ( baseclass == subclass )
if (baseclass == subclass)
return 0;
int min = Math.min( SCORE_UNCOERCIBLE, inheritanceLevels( baseclass, subclass.getSuperclass() ) + 1 );
int min = Math.min(SCORE_UNCOERCIBLE, inheritanceLevels(baseclass, subclass.getSuperclass())+1);
Class[] ifaces = subclass.getInterfaces();
for ( int i=0; i<ifaces.length; i++ )
min = Math.min(min, inheritanceLevels(baseclass, ifaces[i]) + 1 );
for (int i = 0; i < ifaces.length; i++)
min = Math.min(min, inheritanceLevels(baseclass, ifaces[i])+1);
return min;
}
static final class ObjectCoercion implements Coercion {
final Class targetType;
ObjectCoercion(Class targetType) {
this.targetType = targetType;
}
public String toString() {
return "ObjectCoercion("+targetType.getName()+")";
return "ObjectCoercion(" + targetType.getName() + ")";
}
public int score(LuaValue value) {
switch ( value.type() ) {
switch (value.type()) {
case LuaValue.TNUMBER:
return inheritanceLevels( targetType, value.isint()? Integer.class: Double.class );
return inheritanceLevels(targetType, value.isint()? Integer.class: Double.class);
case LuaValue.TBOOLEAN:
return inheritanceLevels( targetType, Boolean.class );
return inheritanceLevels(targetType, Boolean.class);
case LuaValue.TSTRING:
return inheritanceLevels( targetType, String.class );
return inheritanceLevels(targetType, String.class);
case LuaValue.TUSERDATA:
return inheritanceLevels( targetType, value.touserdata().getClass() );
return inheritanceLevels(targetType, value.touserdata().getClass());
case LuaValue.TNIL:
return SCORE_NULL_VALUE;
default:
return inheritanceLevels( targetType, value.getClass() );
return inheritanceLevels(targetType, value.getClass());
}
}
public Object coerce(LuaValue value) {
switch ( value.type() ) {
switch (value.type()) {
case LuaValue.TNUMBER:
return value.isint()? (Object)new Integer(value.toint()): (Object)new Double(value.todouble());
return value.isint()? (Object) new Integer(value.toint()): (Object) new Double(value.todouble());
case LuaValue.TBOOLEAN:
return value.toboolean()? Boolean.TRUE: Boolean.FALSE;
case LuaValue.TSTRING:
@@ -324,49 +358,49 @@ public class CoerceLuaToJava {
}
static {
Coercion boolCoercion = new BoolCoercion();
Coercion byteCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_BYTE);
Coercion charCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_CHAR);
Coercion shortCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_SHORT);
Coercion intCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_INT);
Coercion longCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_LONG);
Coercion floatCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_FLOAT);
Coercion boolCoercion = new BoolCoercion();
Coercion byteCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_BYTE);
Coercion charCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_CHAR);
Coercion shortCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_SHORT);
Coercion intCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_INT);
Coercion longCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_LONG);
Coercion floatCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_FLOAT);
Coercion doubleCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_DOUBLE);
Coercion stringCoercion = new StringCoercion(StringCoercion.TARGET_TYPE_STRING);
Coercion bytesCoercion = new StringCoercion(StringCoercion.TARGET_TYPE_BYTES);
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( byte[].class, bytesCoercion );
Coercion bytesCoercion = new StringCoercion(StringCoercion.TARGET_TYPE_BYTES);
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(byte[].class, bytesCoercion);
}
static Coercion getCoercion(Class c) {
Coercion co = (Coercion) COERCIONS.get( c );
if ( co != null ) {
Coercion co = (Coercion) COERCIONS.get(c);
if (co != null) {
return co;
}
if ( c.isArray() ) {
if (c.isArray()) {
Class typ = c.getComponentType();
co = new ArrayCoercion(c.getComponentType());
} else {
co = new ObjectCoercion(c);
}
COERCIONS.put( c, co );
COERCIONS.put(c, co);
return co;
}
}

View File

@@ -33,9 +33,9 @@ import org.luaj.vm2.lib.OneArgFunction;
* <p>
* Can get elements by their integer key index, as well as the length.
* <p>
* This class is not used directly.
* It is returned by calls to {@link CoerceJavaToLua#coerce(Object)}
* when an array is supplied.
* This class is not used directly. It is returned by calls to
* {@link CoerceJavaToLua#coerce(Object)} when an array is supplied.
*
* @see CoerceJavaToLua
* @see CoerceLuaToJava
*/
@@ -43,44 +43,43 @@ class JavaArray extends LuaUserdata {
private static final class LenFunction extends OneArgFunction {
public LuaValue call(LuaValue u) {
return LuaValue.valueOf(Array.getLength(((LuaUserdata)u).m_instance));
return LuaValue.valueOf(Array.getLength(((LuaUserdata) u).m_instance));
}
}
static final LuaValue LENGTH = valueOf("length");
static final LuaTable array_metatable;
static {
array_metatable = new LuaTable();
array_metatable.rawset(LuaValue.LEN, new LenFunction());
}
JavaArray(Object instance) {
super(instance);
setmetatable(array_metatable);
}
public LuaValue get(LuaValue key) {
if ( key.equals(LENGTH) )
if (key.equals(LENGTH))
return valueOf(Array.getLength(m_instance));
if ( key.isint() ) {
int i = key.toint() - 1;
return i>=0 && i<Array.getLength(m_instance)?
CoerceJavaToLua.coerce(Array.get(m_instance,key.toint()-1)):
NIL;
if (key.isint()) {
int i = key.toint()-1;
return i >= 0 && i < Array.getLength(m_instance)
? CoerceJavaToLua.coerce(Array.get(m_instance, key.toint()-1))
: NIL;
}
return super.get(key);
}
public void set(LuaValue key, LuaValue value) {
if ( key.isint() ) {
int i = key.toint() - 1;
if ( i>=0 && i<Array.getLength(m_instance) )
Array.set(m_instance,i,CoerceLuaToJava.coerce(value, m_instance.getClass().getComponentType()));
else if ( m_metatable==null || ! settable(this,key,value) )
error("array index out of bounds");
}
else
if (key.isint()) {
int i = key.toint()-1;
if (i >= 0 && i < Array.getLength(m_instance))
Array.set(m_instance, i, CoerceLuaToJava.coerce(value, m_instance.getClass().getComponentType()));
else if (m_metatable == null || !settable(this, key, value))
error("array index out of bounds");
} else
super.set(key, value);
}
}
}

View File

@@ -38,11 +38,11 @@ import org.luaj.vm2.LuaValue;
/**
* LuaValue that represents a Java class.
* <p>
* Will respond to get() and set() by returning field values, or java methods.
* Will respond to get() and set() by returning field values, or java methods.
* <p>
* This class is not used directly.
* It is returned by calls to {@link CoerceJavaToLua#coerce(Object)}
* when a Class is supplied.
* This class is not used directly. It is returned by calls to
* {@link CoerceJavaToLua#coerce(Object)} when a Class is supplied.
*
* @see CoerceJavaToLua
* @see CoerceLuaToJava
*/
@@ -51,18 +51,18 @@ class JavaClass extends JavaInstance implements CoerceJavaToLua.Coercion {
static final Map classes = Collections.synchronizedMap(new HashMap());
static final LuaValue NEW = valueOf("new");
Map fields;
Map methods;
Map innerclasses;
static JavaClass forClass(Class c) {
JavaClass j = (JavaClass) classes.get(c);
if ( j == null )
classes.put( c, j = new JavaClass(c) );
if (j == null)
classes.put(c, j = new JavaClass(c));
return j;
}
JavaClass(Class c) {
super(c);
this.jclass = this;
@@ -71,14 +71,14 @@ class JavaClass extends JavaInstance implements CoerceJavaToLua.Coercion {
public LuaValue coerce(Object javaValue) {
return this;
}
Field getField(LuaValue key) {
if ( fields == null ) {
if (fields == null) {
Map m = new HashMap();
Field[] f = ((Class)m_instance).getFields();
for ( int i=0; i<f.length; i++ ) {
Field[] f = ((Class) m_instance).getFields();
for (int i = 0; i < f.length; i++) {
Field fi = f[i];
if ( Modifier.isPublic(fi.getModifiers()) ) {
if (Modifier.isPublic(fi.getModifiers())) {
m.put(LuaValue.valueOf(fi.getName()), fi);
try {
if (!fi.isAccessible())
@@ -91,52 +91,56 @@ class JavaClass extends JavaInstance implements CoerceJavaToLua.Coercion {
}
return (Field) fields.get(key);
}
LuaValue getMethod(LuaValue key) {
if ( methods == null ) {
if (methods == null) {
Map namedlists = new HashMap();
Method[] m = ((Class)m_instance).getMethods();
for ( int i=0; i<m.length; i++ ) {
Method[] m = ((Class) m_instance).getMethods();
for (int i = 0; i < m.length; i++) {
Method mi = m[i];
if ( Modifier.isPublic( mi.getModifiers()) ) {
if (Modifier.isPublic(mi.getModifiers())) {
String name = mi.getName();
List list = (List) namedlists.get(name);
if ( list == null )
if (list == null)
namedlists.put(name, list = new ArrayList());
list.add( JavaMethod.forMethod(mi) );
list.add(JavaMethod.forMethod(mi));
}
}
Map map = new HashMap();
Constructor[] c = ((Class)m_instance).getConstructors();
Constructor[] c = ((Class) m_instance).getConstructors();
List list = new ArrayList();
for ( int i=0; i<c.length; i++ )
if ( Modifier.isPublic(c[i].getModifiers()) )
list.add( JavaConstructor.forConstructor(c[i]) );
switch ( list.size() ) {
case 0: break;
case 1: map.put(NEW, list.get(0)); break;
default: map.put(NEW, JavaConstructor.forConstructors( (JavaConstructor[])list.toArray(new JavaConstructor[list.size()]) ) ); break;
for (int i = 0; i < c.length; i++)
if (Modifier.isPublic(c[i].getModifiers()))
list.add(JavaConstructor.forConstructor(c[i]));
switch (list.size()) {
case 0:
break;
case 1:
map.put(NEW, list.get(0));
break;
default:
map.put(NEW, JavaConstructor
.forConstructors((JavaConstructor[]) list.toArray(new JavaConstructor[list.size()])));
break;
}
for ( Iterator it=namedlists.entrySet().iterator(); it.hasNext(); ) {
for (Iterator it = namedlists.entrySet().iterator(); it.hasNext();) {
Entry e = (Entry) it.next();
String name = (String) e.getKey();
List methods = (List) e.getValue();
map.put( LuaValue.valueOf(name),
methods.size()==1?
methods.get(0):
JavaMethod.forMethods( (JavaMethod[])methods.toArray(new JavaMethod[methods.size()])) );
map.put(LuaValue.valueOf(name), methods.size() == 1? methods.get(0)
: JavaMethod.forMethods((JavaMethod[]) methods.toArray(new JavaMethod[methods.size()])));
}
methods = map;
}
return (LuaValue) methods.get(key);
}
Class getInnerClass(LuaValue key) {
if ( innerclasses == null ) {
if (innerclasses == null) {
Map m = new HashMap();
Class[] c = ((Class)m_instance).getClasses();
for ( int i=0; i<c.length; i++ ) {
Class[] c = ((Class) m_instance).getClasses();
for (int i = 0; i < c.length; i++) {
Class ci = c[i];
String name = ci.getName();
String stub = name.substring(Math.max(name.lastIndexOf('$'), name.lastIndexOf('.'))+1);
@@ -147,7 +151,5 @@ class JavaClass extends JavaInstance implements CoerceJavaToLua.Coercion {
return (Class) innerclasses.get(key);
}
public LuaValue getConstructor() {
return getMethod(NEW);
}
public LuaValue getConstructor() { return getMethod(NEW); }
}

View File

@@ -35,45 +35,45 @@ import org.luaj.vm2.lib.VarArgFunction;
/**
* LuaValue that represents a particular public Java constructor.
* <p>
* May be called with arguments to return a JavaInstance
* created by calling the constructor.
* May be called with arguments to return a JavaInstance created by calling the
* constructor.
* <p>
* This class is not used directly.
* It is returned by calls to {@link JavaClass#new(LuaValue key)}
* when the value of key is "new".
* This class is not used directly. It is returned by calls to
* {@link JavaClass#new(LuaValue key)} when the value of key is "new".
*
* @see CoerceJavaToLua
* @see CoerceLuaToJava
*/
class JavaConstructor extends JavaMember {
static final Map constructors = Collections.synchronizedMap(new HashMap());
static JavaConstructor forConstructor(Constructor c) {
JavaConstructor j = (JavaConstructor) constructors.get(c);
if ( j == null )
constructors.put( c, j = new JavaConstructor(c) );
if (j == null)
constructors.put(c, j = new JavaConstructor(c));
return j;
}
public static LuaValue forConstructors(JavaConstructor[] array) {
return new Overload(array);
}
final Constructor constructor;
private JavaConstructor(Constructor c) {
super( c.getParameterTypes(), c.getModifiers() );
super(c.getParameterTypes(), c.getModifiers());
this.constructor = c;
}
public Varargs invoke(Varargs args) {
Object[] a = convertArgs(args);
try {
return CoerceJavaToLua.coerce( constructor.newInstance(a) );
return CoerceJavaToLua.coerce(constructor.newInstance(a));
} catch (InvocationTargetException e) {
throw new LuaError(e.getTargetException());
} catch (Exception e) {
return LuaValue.error("coercion error "+e);
return LuaValue.error("coercion error " + e);
}
}
@@ -82,12 +82,13 @@ class JavaConstructor extends JavaMember {
* <p>
* On invocation, will pick the best method from the list, and invoke it.
* <p>
* This class is not used directly.
* It is returned by calls to calls to {@link JavaClass#get(LuaValue key)}
* when key is "new" and there is more than one public constructor.
* This class is not used directly. It is returned by calls to calls to
* {@link JavaClass#get(LuaValue key)} when key is "new" and there is more
* than one public constructor.
*/
static class Overload extends VarArgFunction {
final JavaConstructor[] constructors;
final JavaConstructor[] constructors;
public Overload(JavaConstructor[] c) {
this.constructors = c;
}
@@ -95,20 +96,20 @@ class JavaConstructor extends JavaMember {
public Varargs invoke(Varargs args) {
JavaConstructor best = null;
int score = CoerceLuaToJava.SCORE_UNCOERCIBLE;
for ( int i=0; i<constructors.length; i++ ) {
for (int i = 0; i < constructors.length; i++) {
int s = constructors[i].score(args);
if ( s < score ) {
if (s < score) {
score = s;
best = constructors[i];
if ( score == 0 )
if (score == 0)
break;
}
}
// any match?
if ( best == null )
if (best == null)
LuaValue.error("no coercible public method");
// invoke it
return best.invoke(args);
}

View File

@@ -30,46 +30,46 @@ import org.luaj.vm2.LuaValue;
/**
* LuaValue that represents a Java instance.
* <p>
* Will respond to get() and set() by returning field values or methods.
* Will respond to get() and set() by returning field values or methods.
* <p>
* This class is not used directly.
* It is returned by calls to {@link CoerceJavaToLua#coerce(Object)}
* when a subclass of Object is supplied.
* This class is not used directly. It is returned by calls to
* {@link CoerceJavaToLua#coerce(Object)} when a subclass of Object is supplied.
*
* @see CoerceJavaToLua
* @see CoerceLuaToJava
*/
class JavaInstance extends LuaUserdata {
JavaClass jclass;
JavaInstance(Object instance) {
super(instance);
}
public LuaValue get(LuaValue key) {
if ( jclass == null )
if (jclass == null)
jclass = JavaClass.forClass(m_instance.getClass());
Field f = jclass.getField(key);
if ( f != null )
if (f != null)
try {
return CoerceJavaToLua.coerce(f.get(m_instance));
} catch (Exception e) {
throw new LuaError(e);
}
LuaValue m = jclass.getMethod(key);
if ( m != null )
if (m != null)
return m;
Class c = jclass.getInnerClass(key);
if ( c != null )
if (c != null)
return JavaClass.forClass(c);
return super.get(key);
}
public void set(LuaValue key, LuaValue value) {
if ( jclass == null )
if (jclass == null)
jclass = JavaClass.forClass(m_instance.getClass());
Field f = jclass.getField(key);
if ( f != null )
if (f != null)
try {
f.set(m_instance, CoerceLuaToJava.coerce(value, f.getType()));
return;
@@ -77,6 +77,6 @@ class JavaInstance extends LuaUserdata {
throw new LuaError(e);
}
super.set(key, value);
}
}
}

View File

@@ -28,56 +28,56 @@ import org.luaj.vm2.lib.jse.CoerceLuaToJava.Coercion;
/**
* Java method or constructor.
* <p>
* Primarily handles argument coercion for parameter lists including scoring of compatibility and
* java varargs handling.
* Primarily handles argument coercion for parameter lists including scoring of
* compatibility and java varargs handling.
* <p>
* This class is not used directly.
* It is an abstract base class for {@link JavaConstructor} and {@link JavaMethod}.
* This class is not used directly. It is an abstract base class for
* {@link JavaConstructor} and {@link JavaMethod}.
*
* @see JavaConstructor
* @see JavaMethod
* @see CoerceJavaToLua
* @see CoerceLuaToJava
*/
abstract
class JavaMember extends VarArgFunction {
abstract class JavaMember extends VarArgFunction {
static final int METHOD_MODIFIERS_VARARGS = 0x80;
final Coercion[] fixedargs;
final Coercion varargs;
final Coercion varargs;
protected JavaMember(Class[] params, int modifiers) {
boolean isvarargs = ((modifiers & METHOD_MODIFIERS_VARARGS) != 0);
fixedargs = new CoerceLuaToJava.Coercion[isvarargs? params.length-1: params.length];
for ( int i=0; i<fixedargs.length; i++ )
fixedargs[i] = CoerceLuaToJava.getCoercion( params[i] );
varargs = isvarargs? CoerceLuaToJava.getCoercion( params[params.length-1] ): null;
for (int i = 0; i < fixedargs.length; i++)
fixedargs[i] = CoerceLuaToJava.getCoercion(params[i]);
varargs = isvarargs? CoerceLuaToJava.getCoercion(params[params.length-1]): null;
}
int score(Varargs args) {
int n = args.narg();
int s = n>fixedargs.length? CoerceLuaToJava.SCORE_WRONG_TYPE * (n-fixedargs.length): 0;
for ( int j=0; j<fixedargs.length; j++ )
s += fixedargs[j].score( args.arg(j+1) );
if ( varargs != null )
for ( int k=fixedargs.length; k<n; k++ )
s += varargs.score( args.arg(k+1) );
int s = n > fixedargs.length? CoerceLuaToJava.SCORE_WRONG_TYPE*(n-fixedargs.length): 0;
for (int j = 0; j < fixedargs.length; j++)
s += fixedargs[j].score(args.arg(j+1));
if (varargs != null)
for (int k = fixedargs.length; k < n; k++)
s += varargs.score(args.arg(k+1));
return s;
}
protected Object[] convertArgs(Varargs args) {
Object[] a;
if ( varargs == null ) {
if (varargs == null) {
a = new Object[fixedargs.length];
for ( int i=0; i<a.length; i++ )
a[i] = fixedargs[i].coerce( args.arg(i+1) );
for (int i = 0; i < a.length; i++)
a[i] = fixedargs[i].coerce(args.arg(i+1));
} else {
int n = Math.max(fixedargs.length,args.narg());
int n = Math.max(fixedargs.length, args.narg());
a = new Object[n];
for ( int i=0; i<fixedargs.length; i++ )
a[i] = fixedargs[i].coerce( args.arg(i+1) );
for ( int i=fixedargs.length; i<n; i++ )
a[i] = varargs.coerce( args.arg(i+1) );
for (int i = 0; i < fixedargs.length; i++)
a[i] = fixedargs[i].coerce(args.arg(i+1));
for (int i = fixedargs.length; i < n; i++)
a[i] = varargs.coerce(args.arg(i+1));
}
return a;
}

View File

@@ -35,33 +35,33 @@ import org.luaj.vm2.Varargs;
/**
* LuaValue that represents a Java method.
* <p>
* Can be invoked via call(LuaValue...) and related methods.
* Can be invoked via call(LuaValue...) and related methods.
* <p>
* This class is not used directly.
* It is returned by calls to calls to {@link JavaInstance#get(LuaValue key)}
* when a method is named.
* This class is not used directly. It is returned by calls to calls to
* {@link JavaInstance#get(LuaValue key)} when a method is named.
*
* @see CoerceJavaToLua
* @see CoerceLuaToJava
*/
class JavaMethod extends JavaMember {
static final Map methods = Collections.synchronizedMap(new HashMap());
static JavaMethod forMethod(Method m) {
JavaMethod j = (JavaMethod) methods.get(m);
if ( j == null )
methods.put( m, j = new JavaMethod(m) );
if (j == null)
methods.put(m, j = new JavaMethod(m));
return j;
}
static LuaFunction forMethods(JavaMethod[] m) {
return new Overload(m);
}
final Method method;
private JavaMethod(Method m) {
super( m.getParameterTypes(), m.getModifiers() );
super(m.getParameterTypes(), m.getModifiers());
this.method = m;
try {
if (!m.isAccessible())
@@ -81,39 +81,39 @@ class JavaMethod extends JavaMember {
public LuaValue call(LuaValue arg1, LuaValue arg2) {
return invokeMethod(arg1.checkuserdata(), arg2);
}
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
return invokeMethod(arg1.checkuserdata(), LuaValue.varargsOf(arg2, arg3));
}
public Varargs invoke(Varargs args) {
return invokeMethod(args.checkuserdata(1), args.subargs(2));
}
LuaValue invokeMethod(Object instance, Varargs args) {
Object[] a = convertArgs(args);
try {
return CoerceJavaToLua.coerce( method.invoke(instance, a) );
return CoerceJavaToLua.coerce(method.invoke(instance, a));
} catch (InvocationTargetException e) {
throw new LuaError(e.getTargetException());
} catch (Exception e) {
return LuaValue.error("coercion error "+e);
return LuaValue.error("coercion error " + e);
}
}
/**
* LuaValue that represents an overloaded Java method.
* <p>
* On invocation, will pick the best method from the list, and invoke it.
* <p>
* This class is not used directly.
* It is returned by calls to calls to {@link JavaInstance#get(LuaValue key)}
* when an overloaded method is named.
* This class is not used directly. It is returned by calls to calls to
* {@link JavaInstance#get(LuaValue key)} when an overloaded method is
* named.
*/
static class Overload extends LuaFunction {
final JavaMethod[] methods;
Overload(JavaMethod[] methods) {
this.methods = methods;
}
@@ -129,11 +129,11 @@ class JavaMethod extends JavaMember {
public LuaValue call(LuaValue arg1, LuaValue arg2) {
return invokeBestMethod(arg1.checkuserdata(), arg2);
}
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
return invokeBestMethod(arg1.checkuserdata(), LuaValue.varargsOf(arg2, arg3));
}
public Varargs invoke(Varargs args) {
return invokeBestMethod(args.checkuserdata(1), args.subargs(2));
}
@@ -141,20 +141,20 @@ class JavaMethod extends JavaMember {
private LuaValue invokeBestMethod(Object instance, Varargs args) {
JavaMethod best = null;
int score = CoerceLuaToJava.SCORE_UNCOERCIBLE;
for ( int i=0; i<methods.length; i++ ) {
for (int i = 0; i < methods.length; i++) {
int s = methods[i].score(args);
if ( s < score ) {
if (s < score) {
score = s;
best = methods[i];
if ( score == 0 )
if (score == 0)
break;
}
}
// any match?
if ( best == null )
if (best == null)
LuaValue.error("no coercible public method");
// invoke it
return best.invokeMethod(instance, args);
}

View File

@@ -33,34 +33,47 @@ import org.luaj.vm2.lib.BaseLib;
import org.luaj.vm2.lib.LibFunction;
import org.luaj.vm2.lib.ResourceFinder;
/**
* Subclass of {@link BaseLib} and {@link LibFunction} which implements the lua basic library functions
* and provides a directory based {@link ResourceFinder} as the {@link Globals#finder}.
/**
* Subclass of {@link BaseLib} and {@link LibFunction} which implements the lua
* basic library functions and provides a directory based {@link ResourceFinder}
* as the {@link Globals#finder}.
* <p>
* Since JME has no file system by default, {@link BaseLib} implements
* {@link ResourceFinder} using {@link Class#getResource(String)}.
* The {@link org.luaj.vm2.lib.jse.JseBaseLib} implements {@link Globals#finder} by scanning the current directory
* first, then falling back to {@link Class#getResource(String)} if that fails.
* Otherwise, the behavior is the same as that of {@link BaseLib}.
* <p>
* Typically, this library is included as part of a call to
* Since JME has no file system by default, {@link BaseLib} implements
* {@link ResourceFinder} using {@link Class#getResource(String)}. The
* {@link org.luaj.vm2.lib.jse.JseBaseLib} implements {@link Globals#finder} by
* scanning the current directory first, then falling back to
* {@link Class#getResource(String)} if that fails. Otherwise, the behavior is
* the same as that of {@link BaseLib}.
* <p>
* Typically, this library is included as part of a call to
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()}
* <pre> {@code
* Globals globals = JsePlatform.standardGlobals();
* globals.get("print").call(LuaValue.valueOf("hello, world"));
* } </pre>
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* globals.get("print").call(LuaValue.valueOf("hello, world"));
* }
* </pre>
* <p>
* For special cases where the smallest possible footprint is desired,
* a minimal set of libraries could be loaded
* directly via {@link Globals#load(LuaValue)} using code such as:
* <pre> {@code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.get("print").call(LuaValue.valueOf("hello, world"));
* } </pre>
* <p>However, other libraries such as <em>PackageLib</em> are not loaded in this case.
* For special cases where the smallest possible footprint is desired, a minimal
* set of libraries could be loaded directly via {@link Globals#load(LuaValue)}
* using code such as:
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.get("print").call(LuaValue.valueOf("hello, world"));
* }
* </pre>
* <p>
* However, other libraries such as <em>PackageLib</em> are not loaded in this
* case.
* <p>
* This is a direct port of the corresponding library in C.
*
* @see Globals
* @see BaseLib
* @see ResourceFinder
@@ -68,18 +81,24 @@ import org.luaj.vm2.lib.ResourceFinder;
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.1">Lua 5.2 Base Lib Reference</a>
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.1">Lua 5.2 Base Lib
* Reference</a>
*/
public class JseBaseLib extends org.luaj.vm2.lib.BaseLib {
/** Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied environment,
* adding the table to package.loaded, and returning table as the return value.
* <P>Specifically, extend the library loading to set the default value for {@link Globals#STDIN}
/**
* Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied
* environment, adding the table to package.loaded, and returning table as
* the return value.
* <P>
* Specifically, extend the library loading to set the default value for
* {@link Globals#STDIN}
*
* @param modname the module name supplied if this is loaded via 'require'.
* @param env the environment to load into, which must be a Globals instance.
* @param env the environment to load into, which must be a Globals
* instance.
*/
public LuaValue call(LuaValue modname, LuaValue env) {
super.call(modname, env);
@@ -87,30 +106,28 @@ public class JseBaseLib extends org.luaj.vm2.lib.BaseLib {
return env;
}
/**
* Try to open a file in the current working directory,
* or fall back to base opener if not found.
/**
* 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).
* 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.
*
* 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.
* @return InputStream, or null if not found.
*/
public InputStream findResource(String filename) {
File f = new File(filename);
if ( ! f.exists() )
if (!f.exists())
return super.findResource(filename);
try {
return new BufferedInputStream(new FileInputStream(f));
} catch ( IOException ioe ) {
} catch (IOException ioe) {
return null;
}
}
}

View File

@@ -37,135 +37,157 @@ import org.luaj.vm2.lib.IoLib;
import org.luaj.vm2.lib.LibFunction;
/**
* Subclass of {@link IoLib} and therefore {@link LibFunction} which implements the lua standard {@code io}
* library for the JSE platform.
* Subclass of {@link IoLib} and therefore {@link LibFunction} which implements
* the lua standard {@code io} library for the JSE platform.
* <p>
* It uses RandomAccessFile to implement seek on files.
* <p>
* Typically, this library is included as part of a call to
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()}
* <pre> {@code
* Globals globals = JsePlatform.standardGlobals();
* globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
* } </pre>
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
* }
* </pre>
* <p>
* For special cases where the smallest possible footprint is desired,
* a minimal set of libraries could be loaded
* directly via {@link Globals#load(LuaValue)} using code such as:
* <pre> {@code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.load(new PackageLib());
* globals.load(new JseIoLib());
* globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
* } </pre>
* <p>However, other libraries such as <em>MathLib</em> are not loaded in this case.
* For special cases where the smallest possible footprint is desired, a minimal
* set of libraries could be loaded directly via {@link Globals#load(LuaValue)}
* using code such as:
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.load(new PackageLib());
* globals.load(new JseIoLib());
* globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
* }
* </pre>
* <p>
* This has been implemented to match as closely as possible the behavior in the corresponding library in C.
* However, other libraries such as <em>MathLib</em> are not loaded in this
* case.
* <p>
* This has been implemented to match as closely as possible the behavior in the
* corresponding library in C.
*
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see IoLib
* @see org.luaj.vm2.lib.jme.JmeIoLib
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.8">Lua 5.2 I/O Lib Reference</a>
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.8">Lua 5.2 I/O Lib
* Reference</a>
*/
public class JseIoLib extends IoLib {
protected File wrapStdin() throws IOException {
return new StdinFile();
}
protected File wrapStdout() throws IOException {
return new StdoutFile(FTYPE_STDOUT);
}
protected File wrapStderr() throws IOException {
return new StdoutFile(FTYPE_STDERR);
}
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 ) {
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 )
if (!readMode)
f.setLength(0);
}
return new FileImpl( f );
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() );
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");
java.io.File f = java.io.File.createTempFile(".luaj", "bin");
f.deleteOnExit();
return new FileImpl( new RandomAccessFile(f,"rw") );
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 ) {
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.is = is != null? is.markSupported()? is: new BufferedInputStream(is): null;
this.os = os;
}
private FileImpl( RandomAccessFile f ) {
this( f, null, null );
private FileImpl(RandomAccessFile f) {
this(f, null, null);
}
private FileImpl( InputStream i ) {
this( null, i, null );
private FileImpl(InputStream i) {
this(null, i, null);
}
private FileImpl( OutputStream o ) {
this( null, null, o );
private FileImpl(OutputStream o) {
this(null, null, o);
}
public String tojstring() {
return "file (" + (this.closed ? "closed" : String.valueOf(this.hashCode())) + ")";
return "file (" + (this.closed? "closed": String.valueOf(this.hashCode())) + ")";
}
public boolean isstdfile() {
return file == null;
}
public void close() throws IOException {
public void close() throws IOException {
closed = true;
if ( file != null ) {
if (file != null) {
file.close();
}
}
public void flush() throws IOException {
if ( os != null )
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 );
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 )
if (nobuffer)
flush();
}
public boolean isclosed() {
return closed;
}
public int seek(String option, int pos) throws IOException {
if ( file != null ) {
if ( "set".equals(option) ) {
if (file != null) {
if ("set".equals(option)) {
file.seek(pos);
} else if ( "end".equals(option) ) {
} else if ("end".equals(option)) {
file.seek(file.length()+pos);
} else {
file.seek(file.getFilePointer()+pos);
@@ -175,23 +197,24 @@ public class JseIoLib extends IoLib {
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;
return file != null? (int) (file.length()-file.getFilePointer()): -1;
}
// peek ahead one character
public int peek() throws IOException {
if ( is != null ) {
if (is != null) {
is.mark(1);
int c = is.read();
is.reset();
return c;
} else if ( file != null ) {
} else if (file != null) {
long fp = file.getFilePointer();
int c = file.read();
file.seek(fp);
@@ -200,12 +223,12 @@ public class JseIoLib extends IoLib {
notimplemented();
return 0;
}
// return char if read, -1 if eof, throw IOException on other exception
public int read() throws IOException {
if ( is != null )
if (is != null)
return is.read();
else if ( file != null ) {
else if (file != null) {
return file.read();
}
notimplemented();
@@ -214,9 +237,9 @@ public class JseIoLib extends IoLib {
// 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) {
if (file != null) {
return file.read(bytes, offset, length);
} else if (is!=null) {
} else if (is != null) {
return is.read(bytes, offset, length);
} else {
notimplemented();
@@ -233,14 +256,10 @@ public class JseIoLib extends IoLib {
}
public String tojstring() {
return "file ("+this.hashCode()+")";
return "file (" + this.hashCode() + ")";
}
private final PrintStream getPrintStream() {
return file_type == FTYPE_STDERR?
globals.STDERR:
globals.STDOUT;
}
private final PrintStream getPrintStream() { return file_type == FTYPE_STDERR? globals.STDERR: globals.STDOUT; }
public void write(LuaString string) throws IOException {
getPrintStream().write(string.m_bytes, string.m_offset, string.m_length);
@@ -281,8 +300,7 @@ public class JseIoLib extends IoLib {
return 0;
}
public int read(byte[] bytes, int offset, int length)
throws IOException {
public int read(byte[] bytes, int offset, int length) throws IOException {
return 0;
}
}
@@ -292,7 +310,7 @@ public class JseIoLib extends IoLib {
}
public String tojstring() {
return "file ("+this.hashCode()+")";
return "file (" + this.hashCode() + ")";
}
public void write(LuaString string) throws IOException {
@@ -335,8 +353,7 @@ public class JseIoLib extends IoLib {
return globals.STDIN.read();
}
public int read(byte[] bytes, int offset, int length)
throws IOException {
public int read(byte[] bytes, int offset, int length) throws IOException {
return globals.STDIN.read(bytes, offset, length);
}
}

View File

@@ -26,58 +26,76 @@ import org.luaj.vm2.LuaValue;
import org.luaj.vm2.lib.LibFunction;
import org.luaj.vm2.lib.TwoArgFunction;
/**
* Subclass of {@link LibFunction} which implements the lua standard {@code math}
* library.
* <p>
* It contains all lua math functions, including those not available on the JME platform.
* See {@link org.luaj.vm2.lib.MathLib} for the exception list.
/**
* Subclass of {@link LibFunction} which implements the lua standard
* {@code math} library.
* <p>
* Typically, this library is included as part of a call to
* It contains all lua math functions, including those not available on the JME
* platform. See {@link org.luaj.vm2.lib.MathLib} for the exception list.
* <p>
* Typically, this library is included as part of a call to
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()}
* <pre> {@code
* Globals globals = JsePlatform.standardGlobals();
* System.out.println( globals.get("math").get("sqrt").call( LuaValue.valueOf(2) ) );
* } </pre>
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* System.out.println(globals.get("math").get("sqrt").call(LuaValue.valueOf(2)));
* }
* </pre>
* <p>
* For special cases where the smallest possible footprint is desired,
* a minimal set of libraries could be loaded
* directly via {@link Globals#load(LuaValue)} using code such as:
* <pre> {@code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.load(new PackageLib());
* globals.load(new JseMathLib());
* System.out.println( globals.get("math").get("sqrt").call( LuaValue.valueOf(2) ) );
* } </pre>
* <p>However, other libraries such as <em>CoroutineLib</em> are not loaded in this case.
* For special cases where the smallest possible footprint is desired, a minimal
* set of libraries could be loaded directly via {@link Globals#load(LuaValue)}
* using code such as:
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.load(new PackageLib());
* globals.load(new JseMathLib());
* System.out.println(globals.get("math").get("sqrt").call(LuaValue.valueOf(2)));
* }
* </pre>
* <p>
* This has been implemented to match as closely as possible the behavior in the corresponding library in C.
* However, other libraries such as <em>CoroutineLib</em> are not loaded in this
* case.
* <p>
* This has been implemented to match as closely as possible the behavior in the
* corresponding library in C.
*
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see org.luaj.vm2.lib.jse.JseMathLib
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.6">Lua 5.2 Math Lib Reference</a>
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.6">Lua 5.2 Math Lib
* Reference</a>
*/
public class JseMathLib extends org.luaj.vm2.lib.MathLib {
public JseMathLib() {}
/** Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied environment,
* adding the table to package.loaded, and returning table as the return value.
* <P>Specifically, adds all library functions that can be implemented directly
* in JSE but not JME: acos, asin, atan, atan2, cosh, exp, log, pow, sinh, and tanh.
/**
* Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied
* environment, adding the table to package.loaded, and returning table as
* the return value.
* <P>
* Specifically, adds all library functions that can be implemented directly
* in JSE but not JME: acos, asin, atan, atan2, cosh, exp, log, pow, sinh,
* and tanh.
*
* @param modname the module name supplied if this is loaded via 'require'.
* @param env the environment to load into, which must be a Globals instance.
* @param env the environment to load into, which must be a Globals
* instance.
*/
public LuaValue call(LuaValue modname, LuaValue env) {
super.call(modname, env);
LuaValue math = env.get("math");
math.set("acos", new acos());
math.set("asin", new asin());
LuaValue atan = new atan2();
LuaValue atan = new atan2();
math.set("atan", atan);
math.set("atan2", atan);
math.set("cosh", new cosh());
@@ -89,32 +107,53 @@ public class JseMathLib extends org.luaj.vm2.lib.MathLib {
return math;
}
static final class acos extends UnaryOp { protected double call(double d) { return Math.acos(d); } }
static final class asin extends UnaryOp { protected double call(double d) { return Math.asin(d); } }
static final class atan2 extends TwoArgFunction {
static final class acos extends UnaryOp {
protected double call(double d) { return Math.acos(d); }
}
static final class asin extends UnaryOp {
protected double call(double d) { return Math.asin(d); }
}
static final class atan2 extends TwoArgFunction {
public LuaValue call(LuaValue x, LuaValue y) {
return valueOf(Math.atan2(x.checkdouble(), y.optdouble(1)));
}
}
}
static final class cosh extends UnaryOp { protected double call(double d) { return Math.cosh(d); } }
static final class exp extends UnaryOp { protected double call(double d) { return Math.exp(d); } }
static final class cosh extends UnaryOp {
protected double call(double d) { return Math.cosh(d); }
}
static final class exp extends UnaryOp {
protected double call(double d) { return Math.exp(d); }
}
static final class log extends TwoArgFunction {
public LuaValue call(LuaValue x, LuaValue base) {
double nat = Math.log(x.checkdouble());
double b = base.optdouble(Math.E);
if (b != Math.E) nat /= Math.log(b);
if (b != Math.E)
nat /= Math.log(b);
return valueOf(nat);
}
}
static final class pow extends BinaryOp { protected double call(double x, double y) { return Math.pow(x, y); } }
static final class sinh extends UnaryOp { protected double call(double d) { return Math.sinh(d); } }
static final class tanh extends UnaryOp { protected double call(double d) { return Math.tanh(d); } }
static final class pow extends BinaryOp {
protected double call(double x, double y) { return Math.pow(x, y); }
}
static final class sinh extends UnaryOp {
protected double call(double d) { return Math.sinh(d); }
}
static final class tanh extends UnaryOp {
protected double call(double d) { return Math.tanh(d); }
}
/** Faster, better version of pow() used by arithmetic operator ^ */
public double dpow_lib(double a, double b) {
return Math.pow(a, b);
}
}
}

View File

@@ -31,10 +31,11 @@ import org.luaj.vm2.lib.LibFunction;
import org.luaj.vm2.lib.OsLib;
/**
* Subclass of {@link LibFunction} which implements the standard lua {@code os} library.
* Subclass of {@link LibFunction} which implements the standard lua {@code os}
* library.
* <p>
* This contains more complete implementations of the following functions
* using features that are specific to JSE:
* This contains more complete implementations of the following functions using
* features that are specific to JSE:
* <ul>
* <li>{@code execute()}</li>
* <li>{@code remove()}</li>
@@ -42,53 +43,65 @@ import org.luaj.vm2.lib.OsLib;
* <li>{@code tmpname()}</li>
* </ul>
* <p>
* Because the nature of the {@code os} library is to encapsulate
* os-specific features, the behavior of these functions varies considerably
* from their counterparts in the C platform.
* Because the nature of the {@code os} library is to encapsulate os-specific
* features, the behavior of these functions varies considerably from their
* counterparts in the C platform.
* <p>
* Typically, this library is included as part of a call to
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()}
* <pre> {@code
* Globals globals = JsePlatform.standardGlobals();
* System.out.println( globals.get("os").get("time").call() );
* } </pre>
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* System.out.println(globals.get("os").get("time").call());
* }
* </pre>
* <p>
* For special cases where the smallest possible footprint is desired,
* a minimal set of libraries could be loaded
* directly via {@link Globals#load(LuaValue)} using code such as:
* <pre> {@code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.load(new PackageLib());
* globals.load(new JseOsLib());
* System.out.println( globals.get("os").get("time").call() );
* } </pre>
* <p>However, other libraries such as <em>MathLib</em> are not loaded in this case.
* For special cases where the smallest possible footprint is desired, a minimal
* set of libraries could be loaded directly via {@link Globals#load(LuaValue)}
* using code such as:
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.load(new PackageLib());
* globals.load(new JseOsLib());
* System.out.println(globals.get("os").get("time").call());
* }
* </pre>
* <p>
* However, other libraries such as <em>MathLib</em> are not loaded in this
* case.
* <p>
*
* @see LibFunction
* @see OsLib
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.9">Lua 5.2 OS Lib Reference</a>
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.9">Lua 5.2 OS Lib
* Reference</a>
*/
public class JseOsLib extends org.luaj.vm2.lib.OsLib {
/** return code indicating the execute() threw an I/O exception */
public static final int EXEC_IOEXCEPTION = 1;
public static final int EXEC_IOEXCEPTION = 1;
/** return code indicating the execute() was interrupted */
public static final int EXEC_INTERRUPTED = -2;
/** return code indicating the execute() threw an unknown exception */
public static final int EXEC_ERROR = -3;
public static final int EXEC_ERROR = -3;
/** public constructor */
public JseOsLib() {
}
protected String getenv(String varname) {
String s = System.getenv(varname);
return s != null? s : System.getProperty(varname);
return s != null? s: System.getProperty(varname);
}
protected Varargs execute(String command) {
@@ -109,27 +122,27 @@ public class JseOsLib extends org.luaj.vm2.lib.OsLib {
protected void remove(String filename) throws IOException {
File f = new File(filename);
if ( ! f.exists() )
if (!f.exists())
throw new IOException("No such file or directory");
if ( ! f.delete() )
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() )
if (!f.exists())
throw new IOException("No such file or directory");
if ( ! f.renameTo(new File(newname)) )
if (!f.renameTo(new File(newname)))
throw new IOException("Failed to rename");
}
protected String tmpname() {
try {
java.io.File f = java.io.File.createTempFile(TMP_PREFIX ,TMP_SUFFIX);
java.io.File f = java.io.File.createTempFile(TMP_PREFIX, TMP_SUFFIX);
return f.getAbsolutePath();
} catch ( IOException ioe ) {
} catch (IOException ioe) {
return super.tmpname();
}
}
}

View File

@@ -34,31 +34,45 @@ import org.luaj.vm2.lib.ResourceFinder;
import org.luaj.vm2.lib.StringLib;
import org.luaj.vm2.lib.TableLib;
/** The {@link org.luaj.vm2.lib.jse.JsePlatform} class is a convenience class to standardize
* how globals tables are initialized for the JSE platform.
/**
* The {@link org.luaj.vm2.lib.jse.JsePlatform} class is a convenience class to
* standardize how globals tables are initialized for the JSE platform.
* <p>
* It is used to allocate either a set of standard globals using
* {@link #standardGlobals()} or debug globals using {@link #debugGlobals()}
* <p>
* A simple example of initializing globals and using them from Java is:
* <pre> {@code
* Globals globals = JsePlatform.standardGlobals();
* globals.get("print").call(LuaValue.valueOf("hello, world"));
* } </pre>
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* globals.get("print").call(LuaValue.valueOf("hello, world"));
* }
* </pre>
* <p>
* Once globals are created, a simple way to load and run a script is:
* <pre> {@code
*
* <pre>
* {@code
* globals.load( new FileInputStream("main.lua"), "main.lua" ).call();
* } </pre>
* }
* </pre>
* <p>
* although {@code require} could also be used:
* <pre> {@code
*
* <pre>
* {@code
* globals.get("require").call(LuaValue.valueOf("main"));
* } </pre>
* For this to succeed, the file "main.lua" must be in the current directory or a resource.
* See {@link org.luaj.vm2.lib.jse.JseBaseLib} for details on finding scripts using {@link ResourceFinder}.
* }
* </pre>
*
* For this to succeed, the file "main.lua" must be in the current directory or
* a resource. See {@link org.luaj.vm2.lib.jse.JseBaseLib} for details on
* finding scripts using {@link ResourceFinder}.
* <p>
* The standard globals will contain all standard libraries plus {@code luajava}:
* The standard globals will contain all standard libraries plus
* {@code luajava}:
* <ul>
* <li>{@link Globals}</li>
* <li>{@link org.luaj.vm2.lib.jse.JseBaseLib}</li>
@@ -72,9 +86,11 @@ import org.luaj.vm2.lib.TableLib;
* <li>{@link org.luaj.vm2.lib.jse.JseOsLib}</li>
* <li>{@link org.luaj.vm2.lib.jse.LuajavaLib}</li>
* </ul>
* In addition, the {@link LuaC} compiler is installed so lua files may be loaded in their source form.
* In addition, the {@link LuaC} compiler is installed so lua files may be
* loaded in their source form.
* <p>
* The debug globals are simply the standard globals plus the {@code debug} library {@link DebugLib}.
* The debug globals are simply the standard globals plus the {@code debug}
* library {@link DebugLib}.
* <p>
* The class ensures that initialization is done in the correct order.
*
@@ -108,9 +124,11 @@ public class JsePlatform {
return globals;
}
/** Create standard globals including the {@link DebugLib} library.
/**
* Create standard globals including the {@link DebugLib} library.
*
* @return Table of globals initialized with the standard JSE and debug libraries
* @return Table of globals initialized with the standard JSE and debug
* libraries
* @see #standardGlobals()
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
@@ -122,10 +140,11 @@ public class JsePlatform {
return globals;
}
/** Simple wrapper for invoking a lua function with command line arguments.
* The supplied function is first given a new Globals object as its environment
* then the program is run with arguments.
/**
* Simple wrapper for invoking a lua function with command line arguments.
* The supplied function is first given a new Globals object as its
* environment then the program is run with arguments.
*
* @return {@link Varargs} containing any values returned by mainChunk.
*/
public static Varargs luaMain(LuaValue mainChunk, String[] args) {

View File

@@ -25,37 +25,48 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/** Analog of Process that pipes input and output to client-specified streams.
/**
* Analog of Process that pipes input and output to client-specified streams.
*/
public class JseProcess {
final Process process;
final Thread input,output,error;
final Thread input, output, error;
/** Construct a process around a command, with specified streams to redirect input and output to.
/**
* Construct a process around a command, with specified streams to redirect
* input and output to.
*
* @param cmd The command to execute, including arguments, if any
* @param stdin Optional InputStream to read from as process input, or null if input is not needed.
* @param stdout Optional OutputStream to copy process output to, or null if output is ignored.
* @param stderr Optinoal OutputStream to copy process stderr output to, or null if output is ignored.
* @param cmd The command to execute, including arguments, if any
* @param stdin Optional InputStream to read from as process input, or null
* if input is not needed.
* @param stdout Optional OutputStream to copy process output to, or null if
* output is ignored.
* @param stderr Optinoal OutputStream to copy process stderr output to, or
* null if output is ignored.
* @throws IOException If the system process could not be created.
* @see Process
*/
public JseProcess(String[] cmd, InputStream stdin, OutputStream stdout, OutputStream stderr) throws IOException {
this(Runtime.getRuntime().exec(cmd), stdin, stdout, stderr);
this(Runtime.getRuntime().exec(cmd), stdin, stdout, stderr);
}
/** Construct a process around a command, with specified streams to redirect input and output to.
/**
* Construct a process around a command, with specified streams to redirect
* input and output to.
*
* @param cmd The command to execute, including arguments, if any
* @param stdin Optional InputStream to read from as process input, or null if input is not needed.
* @param stdout Optional OutputStream to copy process output to, or null if output is ignored.
* @param stderr Optinoal OutputStream to copy process stderr output to, or null if output is ignored.
* @param cmd The command to execute, including arguments, if any
* @param stdin Optional InputStream to read from as process input, or null
* if input is not needed.
* @param stdout Optional OutputStream to copy process output to, or null if
* output is ignored.
* @param stderr Optinoal OutputStream to copy process stderr output to, or
* null if output is ignored.
* @throws IOException If the system process could not be created.
* @see Process
*/
public JseProcess(String cmd, InputStream stdin, OutputStream stdout, OutputStream stderr) throws IOException {
this(Runtime.getRuntime().exec(cmd), stdin, stdout, stderr);
this(Runtime.getRuntime().exec(cmd), stdin, stdout, stderr);
}
private JseProcess(Process process, InputStream stdin, OutputStream stdout, OutputStream stderr) {
@@ -70,7 +81,9 @@ public class JseProcess {
return process.exitValue();
}
/** Wait for the process to complete, and all pending output to finish.
/**
* Wait for the process to complete, and all pending output to finish.
*
* @return The exit status.
* @throws InterruptedException
*/
@@ -87,9 +100,8 @@ public class JseProcess {
}
/** Create a thread to copy bytes from input to output. */
private Thread copyBytes(final InputStream input,
final OutputStream output, final InputStream ownedInput,
final OutputStream ownedOutput) {
private Thread copyBytes(final InputStream input, final OutputStream output, final InputStream ownedInput,
final OutputStream ownedOutput) {
Thread t = (new CopyThread(output, ownedOutput, ownedInput, input));
t.start();
return t;
@@ -98,11 +110,10 @@ public class JseProcess {
private static final class CopyThread extends Thread {
private final OutputStream output;
private final OutputStream ownedOutput;
private final InputStream ownedInput;
private final InputStream input;
private final InputStream ownedInput;
private final InputStream input;
private CopyThread(OutputStream output, OutputStream ownedOutput,
InputStream ownedInput, InputStream input) {
private CopyThread(OutputStream output, OutputStream ownedOutput, InputStream ownedInput, InputStream input) {
this.output = output;
this.ownedOutput = ownedOutput;
this.ownedInput = ownedInput;
@@ -114,7 +125,7 @@ public class JseProcess {
byte[] buf = new byte[1024];
int r;
try {
while ((r = input.read(buf)) >= 0) {
while ( (r = input.read(buf)) >= 0 ) {
output.write(buf, 0, r);
}
} finally {

View File

@@ -22,7 +22,7 @@
package org.luaj.vm2.lib.jse;
public class JseStringLib extends org.luaj.vm2.lib.StringLib {
/** public constructor */
public JseStringLib() {
}
@@ -30,7 +30,7 @@ public class JseStringLib extends org.luaj.vm2.lib.StringLib {
protected String format(String src, double x) {
String out;
try {
out = String.format(src, new Object[] {Double.valueOf(x)});
out = String.format(src, new Object[] { Double.valueOf(x) });
} catch (Throwable e) {
out = super.format(src, x);
}

View File

@@ -21,7 +21,6 @@
******************************************************************************/
package org.luaj.vm2.lib.jse;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
@@ -38,40 +37,51 @@ import org.luaj.vm2.lib.LibFunction;
import org.luaj.vm2.lib.VarArgFunction;
/**
* Subclass of {@link LibFunction} which implements the features of the luajava package.
* Subclass of {@link LibFunction} which implements the features of the luajava
* package.
* <p>
* Luajava is an approach to mixing lua and java using simple functions that bind
* java classes and methods to lua dynamically. The API is documented on the
* <a href="http://www.keplerproject.org/luajava/">luajava</a> documentation pages.
* Luajava is an approach to mixing lua and java using simple functions that
* bind java classes and methods to lua dynamically. The API is documented on
* the <a href="http://www.keplerproject.org/luajava/">luajava</a> documentation
* pages.
*
* <p>
* Typically, this library is included as part of a call to
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()}
* <pre> {@code
* Globals globals = JsePlatform.standardGlobals();
* System.out.println( globals.get("luajava").get("bindClass").call( LuaValue.valueOf("java.lang.System") ).invokeMethod("currentTimeMillis") );
* } </pre>
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* System.out.println(globals.get("luajava").get("bindClass").call(LuaValue.valueOf("java.lang.System"))
* .invokeMethod("currentTimeMillis"));
* }
* </pre>
* <p>
* To instantiate and use it directly,
* link it into your globals table via {@link Globals#load} using code such as:
* <pre> {@code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.load(new PackageLib());
* globals.load(new LuajavaLib());
* globals.load(
* "sys = luajava.bindClass('java.lang.System')\n"+
* "print ( sys:currentTimeMillis() )\n", "main.lua" ).call();
* } </pre>
* To instantiate and use it directly, link it into your globals table via
* {@link Globals#load} using code such as:
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.load(new PackageLib());
* globals.load(new LuajavaLib());
* globals.load("sys = luajava.bindClass('java.lang.System')\n" + "print ( sys:currentTimeMillis() )\n", "main.lua")
* .call();
* }
* </pre>
* <p>
*
* The {@code luajava} library is available
* on all JSE platforms via the call to {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()}
* and the luajava api's are simply invoked from lua.
* Because it makes extensive use of Java's reflection API, it is not available
* on JME, but can be used in Android applications.
* The {@code luajava} library is available on all JSE platforms via the call to
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} and the luajava
* api's are simply invoked from lua. Because it makes extensive use of Java's
* reflection API, it is not available on JME, but can be used in Android
* applications.
* <p>
* This has been implemented to match as closely as possible the behavior in the corresponding library in C.
* This has been implemented to match as closely as possible the behavior in the
* corresponding library in C.
*
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
@@ -79,25 +89,20 @@ import org.luaj.vm2.lib.VarArgFunction;
* @see LuaC
* @see CoerceJavaToLua
* @see CoerceLuaToJava
* @see <a href="http://www.keplerproject.org/luajava/manual.html#luareference">http://www.keplerproject.org/luajava/manual.html#luareference</a>
* @see <a href=
* "http://www.keplerproject.org/luajava/manual.html#luareference">http://www.keplerproject.org/luajava/manual.html#luareference</a>
*/
public class LuajavaLib extends VarArgFunction {
static final int INIT = 0;
static final int BINDCLASS = 1;
static final int NEWINSTANCE = 2;
static final int NEW = 3;
static final int CREATEPROXY = 4;
static final int LOADLIB = 5;
static final int INIT = 0;
static final int BINDCLASS = 1;
static final int NEWINSTANCE = 2;
static final int NEW = 3;
static final int CREATEPROXY = 4;
static final int LOADLIB = 5;
static final String[] NAMES = { "bindClass", "newInstance", "new", "createProxy", "loadLib", };
static final String[] NAMES = {
"bindClass",
"newInstance",
"new",
"createProxy",
"loadLib",
};
static final int METHOD_MODIFIERS_VARARGS = 0x80;
public LuajavaLib() {
@@ -105,14 +110,15 @@ public class LuajavaLib extends VarArgFunction {
public Varargs invoke(Varargs args) {
try {
switch ( opcode ) {
switch (opcode) {
case INIT: {
// LuaValue modname = args.arg1();
LuaValue env = args.arg(2);
LuaTable t = new LuaTable();
bind( t, this.getClass(), NAMES, BINDCLASS );
bind(t, this.getClass(), NAMES, BINDCLASS);
env.set("luajava", t);
if (!env.get("package").isnil()) env.get("package").get("loaded").set("luajava", t);
if (!env.get("package").isnil())
env.get("package").get("loaded").set("luajava", t);
return t;
}
case BINDCLASS: {
@@ -123,30 +129,31 @@ public class LuajavaLib extends VarArgFunction {
case NEW: {
// get constructor
final LuaValue c = args.checkvalue(1);
final Class clazz = (opcode==NEWINSTANCE? classForName(c.tojstring()): (Class) c.checkuserdata(Class.class));
final Class clazz = (opcode == NEWINSTANCE? classForName(c.tojstring())
: (Class) c.checkuserdata(Class.class));
final Varargs consargs = args.subargs(2);
return JavaClass.forClass(clazz).getConstructor().invoke(consargs);
}
case CREATEPROXY: {
final int niface = args.narg()-1;
if ( niface <= 0 )
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++ )
for (int i = 0; i < niface; i++)
ifaces[i] = classForName(args.checkjstring(i+1));
// create the invocation handler
InvocationHandler handler = new ProxyInvocationHandler(lobj);
// create the proxy object
Object proxy = Proxy.newProxyInstance(getClass().getClassLoader(), ifaces, handler);
// return the proxy
return LuaValue.userdataOf( proxy );
return LuaValue.userdataOf(proxy);
}
case LOADLIB: {
// get constructor
@@ -155,14 +162,14 @@ public class LuajavaLib extends VarArgFunction {
Class clazz = classForName(classname);
Method method = clazz.getMethod(methodname, new Class[] {});
Object result = method.invoke(clazz, new Object[] {});
if ( result instanceof LuaValue ) {
if (result instanceof LuaValue) {
return (LuaValue) result;
} else {
return NIL;
}
}
default:
throw new LuaError("not yet supported: "+this);
throw new LuaError("not yet supported: " + this);
}
} catch (LuaError e) {
throw e;
@@ -177,7 +184,7 @@ public class LuajavaLib extends VarArgFunction {
protected Class classForName(String name) throws ClassNotFoundException {
return Class.forName(name, true, ClassLoader.getSystemClassLoader());
}
private static final class ProxyInvocationHandler implements InvocationHandler {
private final LuaValue lobj;
@@ -188,27 +195,27 @@ public class LuajavaLib extends VarArgFunction {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String name = method.getName();
LuaValue func = lobj.get(name);
if ( func.isnil() )
if (func.isnil())
return null;
boolean isvarargs = ((method.getModifiers() & METHOD_MODIFIERS_VARARGS) != 0);
int n = args!=null? args.length: 0;
int n = args != null? args.length: 0;
LuaValue[] v;
if ( isvarargs ) {
if (isvarargs) {
Object o = args[--n];
int m = Array.getLength( o );
int m = Array.getLength(o);
v = new LuaValue[n+m];
for ( int i=0; i<n; i++ )
for (int i = 0; i < n; i++)
v[i] = CoerceJavaToLua.coerce(args[i]);
for ( int i=0; i<m; i++ )
v[i+n] = CoerceJavaToLua.coerce(Array.get(o,i));
for (int i = 0; i < m; i++)
v[i+n] = CoerceJavaToLua.coerce(Array.get(o, i));
} else {
v = new LuaValue[n];
for ( int i=0; i<n; i++ )
for (int i = 0; i < n; i++)
v[i] = CoerceJavaToLua.coerce(args[i]);
}
LuaValue result = func.invoke(v).arg1();
return CoerceLuaToJava.coerce(result, method.getReturnType());
}
}
}
}

View File

@@ -9,40 +9,38 @@ import org.luaj.vm2.Lua;
import org.luaj.vm2.Prototype;
public class BasicBlock {
int pc0,pc1; // range of program counter values for the block
BasicBlock[] prev; // previous basic blocks (0-n of these)
BasicBlock[] next; // next basic blocks (0, 1, or 2 of these)
boolean islive; // true if this block is used
int pc0, pc1; // range of program counter values for the block
BasicBlock[] prev; // previous basic blocks (0-n of these)
BasicBlock[] next; // next basic blocks (0, 1, or 2 of these)
boolean islive; // true if this block is used
public BasicBlock(Prototype p, int pc0) {
this.pc0 = this.pc1 = pc0;
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append( (pc0+1)+"-"+(pc1+1)
+(prev!=null? " prv: "+str(prev,1): "")
+(next!=null? " nxt: "+str(next,0): "")
+"\n" );
StringBuffer sb = new StringBuffer();
sb.append((pc0+1) + "-" + (pc1+1) + (prev != null? " prv: " + str(prev, 1): "")
+ (next != null? " nxt: " + str(next, 0): "") + "\n");
return sb.toString();
}
private String str(BasicBlock[] b, int p) {
if ( b == null )
if (b == null)
return "";
StringBuffer sb = new StringBuffer();
sb.append("(");
for ( int i=0, n=b.length; i<n; i++ ) {
if ( i > 0 )
sb.append( "," );
sb.append( String.valueOf( p==1? b[i].pc1+1: b[i].pc0+1 ) );
for (int i = 0, n = b.length; i < n; i++) {
if (i > 0)
sb.append(",");
sb.append(String.valueOf(p == 1? b[i].pc1+1: b[i].pc0+1));
}
sb.append(")");
return sb.toString();
}
public static BasicBlock[] findBasicBlocks(Prototype p) {
// mark beginnings, endings
final int n = p.code.length;
final boolean[] isbeg = new boolean[n];
@@ -51,34 +49,33 @@ public class BasicBlock {
BranchVisitor bv = new MarkAndMergeVisitor(isbeg, isend);
visitBranches(p, bv); // 1st time to mark branches
visitBranches(p, bv); // 2nd time to catch merges
// create basic blocks
final BasicBlock[] blocks = new BasicBlock[n];
for ( int i=0; i<n; i++ ) {
for (int i = 0; i < n; i++) {
isbeg[i] = true;
BasicBlock b = new BasicBlock(p,i);
BasicBlock b = new BasicBlock(p, i);
blocks[i] = b;
while ( !isend[i] && i+1<n && !isbeg[i+1] )
blocks[b.pc1=++i] = b;
while ( !isend[i] && i+1 < n && !isbeg[i+1] )
blocks[b.pc1 = ++i] = b;
}
// count previous, next
final int[] nnext = new int[n];
final int[] nprev = new int[n];
visitBranches(p, new CountPrevNextVistor(isbeg, nnext, nprev));
// allocate and cross-reference
visitBranches( p, new AllocAndXRefVisitor(isbeg, nnext, nprev, blocks));
visitBranches(p, new AllocAndXRefVisitor(isbeg, nnext, nprev, blocks));
return blocks;
}
private static final class AllocAndXRefVisitor extends BranchVisitor {
private final int[] nnext;
private final int[] nprev;
private final int[] nnext;
private final int[] nprev;
private final BasicBlock[] blocks;
private AllocAndXRefVisitor(boolean[] isbeg, int[] nnext, int[] nprev,
BasicBlock[] blocks) {
private AllocAndXRefVisitor(boolean[] isbeg, int[] nnext, int[] nprev, BasicBlock[] blocks) {
super(isbeg);
this.nnext = nnext;
this.nprev = nprev;
@@ -86,8 +83,10 @@ public class BasicBlock {
}
public void visitBranch(int pc0, int pc1) {
if ( blocks[pc0].next == null ) blocks[pc0].next = new BasicBlock[nnext[pc0]];
if ( blocks[pc1].prev == null ) blocks[pc1].prev = new BasicBlock[nprev[pc1]];
if (blocks[pc0].next == null)
blocks[pc0].next = new BasicBlock[nnext[pc0]];
if (blocks[pc1].prev == null)
blocks[pc1].prev = new BasicBlock[nprev[pc1]];
blocks[pc0].next[--nnext[pc0]] = blocks[pc1];
blocks[pc1].prev[--nprev[pc1]] = blocks[pc0];
}
@@ -129,87 +128,90 @@ public class BasicBlock {
abstract public static class BranchVisitor {
final boolean[] isbeg;
public BranchVisitor(boolean[] isbeg) {
this.isbeg = isbeg;
}
public void visitBranch( int frompc, int topc ) {}
public void visitReturn( int atpc ) {}
public void visitBranch(int frompc, int topc) {}
public void visitReturn(int atpc) {}
}
public static void visitBranches( Prototype p, BranchVisitor visitor ) {
int sbx,j,c;
public static void visitBranches(Prototype p, BranchVisitor visitor) {
int sbx, j, c;
int[] code = p.code;
int n = code.length;
for ( int i=0; i<n; i++ ) {
for (int i = 0; i < n; i++) {
int ins = code[i];
switch ( Lua.GET_OPCODE( ins ) ) {
switch (Lua.GET_OPCODE(ins)) {
case Lua.OP_LOADBOOL:
if ( 0 == Lua.GETARG_C(ins) )
if (0 == Lua.GETARG_C(ins))
break;
if ( Lua.GET_OPCODE(code[i+1]) == Lua.OP_JMP )
throw new IllegalArgumentException("OP_LOADBOOL followed by jump at "+i);
visitor.visitBranch( i, i+2 );
if (Lua.GET_OPCODE(code[i+1]) == Lua.OP_JMP)
throw new IllegalArgumentException("OP_LOADBOOL followed by jump at " + i);
visitor.visitBranch(i, i+2);
continue;
case Lua.OP_EQ:
case Lua.OP_LT:
case Lua.OP_LE:
case Lua.OP_TEST:
case Lua.OP_TEST:
case Lua.OP_TESTSET:
if ( Lua.GET_OPCODE(code[i+1]) != Lua.OP_JMP )
throw new IllegalArgumentException("test not followed by jump at "+i);
if (Lua.GET_OPCODE(code[i+1]) != Lua.OP_JMP)
throw new IllegalArgumentException("test not followed by jump at " + i);
sbx = Lua.GETARG_sBx(code[i+1]);
++i;
j = i + sbx + 1;
visitor.visitBranch( i, j );
visitor.visitBranch( i, i+1 );
j = i+sbx+1;
visitor.visitBranch(i, j);
visitor.visitBranch(i, i+1);
continue;
case Lua.OP_TFORLOOP:
case Lua.OP_FORLOOP:
sbx = Lua.GETARG_sBx(ins);
j = i + sbx + 1;
visitor.visitBranch( i, j );
visitor.visitBranch( i, i+1 );
j = i+sbx+1;
visitor.visitBranch(i, j);
visitor.visitBranch(i, i+1);
continue;
case Lua.OP_JMP:
case Lua.OP_FORPREP:
sbx = Lua.GETARG_sBx(ins);
j = i + sbx + 1;
visitor.visitBranch( i, j );
j = i+sbx+1;
visitor.visitBranch(i, j);
continue;
case Lua.OP_TAILCALL:
case Lua.OP_RETURN:
visitor.visitReturn( i );
visitor.visitReturn(i);
continue;
}
if ( i+1<n && visitor.isbeg[i+1] )
visitor.visitBranch( i, i+1 );
if (i+1 < n && visitor.isbeg[i+1])
visitor.visitBranch(i, i+1);
}
}
public static BasicBlock[] findLiveBlocks(BasicBlock[] blocks) {
// add reachable blocks
Vector next = new Vector ();
next.addElement( blocks[0] );
while ( ! next.isEmpty() ) {
Vector next = new Vector();
next.addElement(blocks[0]);
while ( !next.isEmpty() ) {
BasicBlock b = (BasicBlock) next.elementAt(0);
next.removeElementAt(0);
if ( ! b.islive ) {
if (!b.islive) {
b.islive = true;
for ( int i=0, n=b.next!=null? b.next.length: 0; i<n; i++ )
if ( ! b.next[i].islive )
next.addElement( b.next[i] );
for (int i = 0, n = b.next != null? b.next.length: 0; i < n; i++)
if (!b.next[i].islive)
next.addElement(b.next[i]);
}
}
// create list in natural order
Vector list = new Vector();
for ( int i=0; i<blocks.length; i=blocks[i].pc1+1 )
if ( blocks[i].islive )
for (int i = 0; i < blocks.length; i = blocks[i].pc1+1)
if (blocks[i].islive)
list.addElement(blocks[i]);
// convert to array
BasicBlock[] array = new BasicBlock[list.size()];
list.copyInto(array);
return array;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -27,23 +27,21 @@ import org.luaj.vm2.Prototype;
import org.luaj.vm2.Upvaldesc;
/**
* TODO:
* propogate constants
* loader can find inner classes
* TODO: propogate constants loader can find inner classes
*/
public class JavaGen {
public final String classname;
public final byte[] bytecode;
public final String classname;
public final byte[] bytecode;
public final JavaGen[] inners;
public JavaGen( Prototype p, String classname, String filename, boolean genmain ) {
this( new ProtoInfo(p,classname), classname, filename, genmain );
public JavaGen(Prototype p, String classname, String filename, boolean genmain) {
this(new ProtoInfo(p, classname), classname, filename, genmain);
}
private JavaGen( ProtoInfo pi, String classname, String filename, boolean genmain ) {
private JavaGen(ProtoInfo pi, String classname, String filename, boolean genmain) {
this.classname = classname;
// build this class
JavaBuilder builder = new JavaBuilder(pi, classname, filename);
scanInstructions(pi, classname, builder);
@@ -52,12 +50,12 @@ public class JavaGen {
builder.setVarStartEnd(i, l.startpc, l.endpc, l.varname.tojstring());
}
this.bytecode = builder.completeClass(genmain);
// build sub-prototypes
if ( pi.subprotos != null ) {
if (pi.subprotos != null) {
int n = pi.subprotos.length;
inners = new JavaGen[n];
for ( int i=0; i<n; i++ )
for (int i = 0; i < n; i++)
inners[i] = new JavaGen(pi.subprotos[i], pi.subprotos[i].name, filename, false);
} else {
inners = null;
@@ -67,20 +65,20 @@ public class JavaGen {
private void scanInstructions(ProtoInfo pi, String classname, JavaBuilder builder) {
Prototype p = pi.prototype;
int vresultbase = -1;
for ( int bi=0; bi<pi.blocklist.length; bi++ ) {
for (int bi = 0; bi < pi.blocklist.length; bi++) {
BasicBlock b0 = pi.blocklist[bi];
// convert upvalues that are phi-variables
for ( int slot=0; slot<p.maxstacksize; slot++ ) {
for (int slot = 0; slot < p.maxstacksize; slot++) {
int pc = b0.pc0;
boolean c = pi.isUpvalueCreate(pc, slot);
if ( c && pi.vars[slot][pc].isPhiVar() )
if (c && pi.vars[slot][pc].isPhiVar())
builder.convertToUpvalue(pc, slot);
}
for ( int pc=b0.pc0; pc<=b0.pc1; pc++ ) {
for (int pc = b0.pc0; pc <= b0.pc1; pc++) {
final int pc0 = pc; // closure changes pc
final int ins = p.code[pc];
final int line = pc < p.lineinfo.length? p.lineinfo[pc]: -1;
@@ -90,104 +88,104 @@ public class JavaGen {
int bx = Lua.GETARG_Bx(ins);
int sbx = Lua.GETARG_sBx(ins);
int c = Lua.GETARG_C(ins);
switch ( o ) {
switch (o) {
case Lua.OP_GETUPVAL: /* A B R(A):= UpValue[B] */
builder.loadUpvalue( b );
builder.storeLocal( pc, a );
break;
case Lua.OP_SETUPVAL: /* A B UpValue[B]:= R(A) */
builder.storeUpvalue( pc, b, a );
break;
case Lua.OP_NEWTABLE: /* A B C R(A):= {} (size = B,C) */
builder.newTable( b, c );
builder.storeLocal( pc, a );
break;
case Lua.OP_MOVE:/* A B R(A):= R(B) */
builder.loadLocal( pc, b );
builder.storeLocal( pc, a );
builder.loadUpvalue(b);
builder.storeLocal(pc, a);
break;
case Lua.OP_SETUPVAL: /* A B UpValue[B]:= R(A) */
builder.storeUpvalue(pc, b, a);
break;
case Lua.OP_NEWTABLE: /* A B C R(A):= {} (size = B,C) */
builder.newTable(b, c);
builder.storeLocal(pc, a);
break;
case Lua.OP_MOVE:/* A B R(A):= R(B) */
builder.loadLocal(pc, b);
builder.storeLocal(pc, a);
break;
case Lua.OP_UNM: /* A B R(A):= -R(B) */
case Lua.OP_NOT: /* A B R(A):= not R(B) */
case Lua.OP_LEN: /* A B R(A):= length of R(B) */
builder.loadLocal( pc, b );
builder.unaryop( o );
builder.storeLocal( pc, a );
builder.loadLocal(pc, b);
builder.unaryop(o);
builder.storeLocal(pc, a);
break;
case Lua.OP_LOADK:/* A Bx R(A):= Kst(Bx) */
builder.loadConstant( p.k[bx] );
builder.storeLocal( pc, a );
builder.loadConstant(p.k[bx]);
builder.storeLocal(pc, a);
break;
case Lua.OP_LOADNIL: /* A B R(A):= ...:= R(A+B):= nil */
builder.loadNil();
for ( ; b>=0; a++, b-- ) {
if ( b > 0 )
for (; b >= 0; a++, b--) {
if (b > 0)
builder.dup();
builder.storeLocal( pc, a );
builder.storeLocal(pc, a);
}
break;
case Lua.OP_GETTABUP: /* A B C R(A) := UpValue[B][RK(C)] */
builder.loadUpvalue( b );
loadLocalOrConstant( p, builder, pc, c );
builder.loadUpvalue(b);
loadLocalOrConstant(p, builder, pc, c);
builder.getTable();
builder.storeLocal( pc, a );
builder.storeLocal(pc, a);
break;
case Lua.OP_GETTABLE: /* A B C R(A):= R(B)[RK(C)] */
builder.loadLocal( pc, b );
loadLocalOrConstant( p, builder, pc, c );
builder.loadLocal(pc, b);
loadLocalOrConstant(p, builder, pc, c);
builder.getTable();
builder.storeLocal( pc, a );
builder.storeLocal(pc, a);
break;
case Lua.OP_SETTABUP: /* A B C UpValue[A][RK(B)] := RK(C) */
builder.loadUpvalue( a );
loadLocalOrConstant( p, builder, pc, b );
loadLocalOrConstant( p, builder, pc, c );
builder.loadUpvalue(a);
loadLocalOrConstant(p, builder, pc, b);
loadLocalOrConstant(p, builder, pc, c);
builder.setTable();
break;
case Lua.OP_SETTABLE: /* A B C R(A)[RK(B)]:= RK(C) */
builder.loadLocal( pc, a );
loadLocalOrConstant( p, builder, pc, b );
loadLocalOrConstant( p, builder, pc, c );
builder.loadLocal(pc, a);
loadLocalOrConstant(p, builder, pc, b);
loadLocalOrConstant(p, builder, pc, c);
builder.setTable();
break;
case Lua.OP_ADD: /* A B C R(A):= RK(B) + RK(C) */
case Lua.OP_SUB: /* A B C R(A):= RK(B) - RK(C) */
case Lua.OP_MUL: /* A B C R(A):= RK(B) * RK(C) */
case Lua.OP_DIV: /* A B C R(A):= RK(B) / RK(C) */
case Lua.OP_MOD: /* A B C R(A):= RK(B) % RK(C) */
case Lua.OP_POW: /* A B C R(A):= RK(B) ^ RK(C) */
loadLocalOrConstant( p, builder, pc, b );
loadLocalOrConstant( p, builder, pc, c );
builder.binaryop( o );
builder.storeLocal( pc, a );
loadLocalOrConstant(p, builder, pc, b);
loadLocalOrConstant(p, builder, pc, c);
builder.binaryop(o);
builder.storeLocal(pc, a);
break;
case Lua.OP_SELF: /* A B C R(A+1):= R(B): R(A):= R(B)[RK(C)] */
builder.loadLocal(pc,b);
builder.loadLocal(pc, b);
builder.dup();
builder.storeLocal(pc, a+1);
loadLocalOrConstant( p, builder, pc, c );
loadLocalOrConstant(p, builder, pc, c);
builder.getTable();
builder.storeLocal(pc, a);
break;
case Lua.OP_CONCAT: /* A B C R(A):= R(B).. ... ..R(C) */
for ( int k=b; k<=c; k++ )
builder.loadLocal(pc, k);
if ( c > b+1 ) {
for (int k = b; k <= c; k++)
builder.loadLocal(pc, k);
if (c > b+1) {
builder.tobuffer();
for ( int k=c; --k>=b; )
for (int k = c; --k >= b;)
builder.concatbuffer();
builder.tovalue();
} else {
@@ -195,14 +193,14 @@ public class JavaGen {
}
builder.storeLocal(pc, a);
break;
case Lua.OP_LOADBOOL:/* A B C R(A):= (Bool)B: if (C) pc++ */
builder.loadBoolean( b!=0 );
builder.storeLocal( pc, a );
if ( c!=0 )
builder.loadBoolean(b != 0);
builder.storeLocal(pc, a);
if (c != 0)
builder.addBranch(pc, JavaBuilder.BRANCH_GOTO, pc+2);
break;
case Lua.OP_JMP: /* sBx pc+=sBx */
if (a > 0) {
for (int i = a-1; i < pi.openups.length; ++i) {
@@ -211,74 +209,77 @@ public class JavaGen {
}
builder.addBranch(pc, JavaBuilder.BRANCH_GOTO, pc+1+sbx);
break;
case Lua.OP_EQ: /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
case Lua.OP_LT: /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
case Lua.OP_LE: /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
loadLocalOrConstant( p, builder, pc, b );
loadLocalOrConstant( p, builder, pc, c );
loadLocalOrConstant(p, builder, pc, b);
loadLocalOrConstant(p, builder, pc, c);
builder.compareop(o);
builder.addBranch(pc, (a!=0? JavaBuilder.BRANCH_IFEQ: JavaBuilder.BRANCH_IFNE), pc+2);
builder.addBranch(pc, (a != 0? JavaBuilder.BRANCH_IFEQ: JavaBuilder.BRANCH_IFNE), pc+2);
break;
case Lua.OP_TEST: /* A C if not (R(A) <=> C) then pc++ */
builder.loadLocal( pc, a );
case Lua.OP_TEST: /* A C if not (R(A) <=> C) then pc++ */
builder.loadLocal(pc, a);
builder.toBoolean();
builder.addBranch(pc, (c!=0? JavaBuilder.BRANCH_IFEQ: JavaBuilder.BRANCH_IFNE), pc+2);
builder.addBranch(pc, (c != 0? JavaBuilder.BRANCH_IFEQ: JavaBuilder.BRANCH_IFNE), pc+2);
break;
case Lua.OP_TESTSET: /* A B C if (R(B) <=> C) then R(A):= R(B) else pc++ */
builder.loadLocal( pc, b );
builder.loadLocal(pc, b);
builder.toBoolean();
builder.addBranch(pc, (c!=0? JavaBuilder.BRANCH_IFEQ: JavaBuilder.BRANCH_IFNE), pc+2);
builder.loadLocal( pc, b );
builder.storeLocal( pc, a );
builder.addBranch(pc, (c != 0? JavaBuilder.BRANCH_IFEQ: JavaBuilder.BRANCH_IFNE), pc+2);
builder.loadLocal(pc, b);
builder.storeLocal(pc, a);
break;
case Lua.OP_CALL: { /* A B C R(A), ... ,R(A+C-2):= R(A)(R(A+1), ... ,R(A+B-1)) */
// load function
builder.loadLocal(pc, a);
// load args
int narg = b - 1;
switch ( narg ) {
case 0: case 1: case 2: case 3:
for ( int i=1; i<b; i++ )
int narg = b-1;
switch (narg) {
case 0:
case 1:
case 2:
case 3:
for (int i = 1; i < b; i++)
builder.loadLocal(pc, a+i);
break;
default: // fixed arg count > 3
builder.newVarargs( pc, a+1, b-1 );
builder.newVarargs(pc, a+1, b-1);
narg = -1;
break;
case -1: // prev vararg result
loadVarargResults( builder, pc, a+1, vresultbase );
loadVarargResults(builder, pc, a+1, vresultbase);
narg = -1;
break;
}
// call or invoke
boolean useinvoke = narg<0 || c<1 || c>2;
if ( useinvoke )
boolean useinvoke = narg < 0 || c < 1 || c > 2;
if (useinvoke)
builder.invoke(narg);
else
builder.call(narg);
// handle results
switch ( c ) {
case 1:
builder.pop();
switch (c) {
case 1:
builder.pop();
break;
case 2:
if ( useinvoke )
builder.arg( 1 );
if (useinvoke)
builder.arg(1);
builder.storeLocal(pc, a);
break;
default: // fixed result count - unpack args
for ( int i=1; i<c; i++ ) {
if ( i+1 < c )
for (int i = 1; i < c; i++) {
if (i+1 < c)
builder.dup();
builder.arg( i );
builder.arg(i);
builder.storeLocal(pc, a+i-1);
}
break;
@@ -287,59 +288,67 @@ public class JavaGen {
builder.storeVarresult();
break;
}
}
}
break;
case Lua.OP_TAILCALL: /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
// load function
builder.loadLocal(pc, a);
// load args
switch ( b ) {
case 1:
switch (b) {
case 1:
builder.loadNone();
break;
case 2:
case 2:
builder.loadLocal(pc, a+1);
break;
default: // fixed arg count > 1
builder.newVarargs( pc, a+1, b-1 );
builder.newVarargs(pc, a+1, b-1);
break;
case 0: // prev vararg result
loadVarargResults( builder, pc, a+1, vresultbase );
loadVarargResults(builder, pc, a+1, vresultbase);
break;
}
builder.newTailcallVarargs();
builder.areturn();
break;
case Lua.OP_RETURN: /* A B return R(A), ... ,R(A+B-2) (see note) */
if ( c == 1 ) {
if (c == 1) {
builder.loadNone();
} else {
switch ( b ) {
case 0: loadVarargResults( builder, pc, a, vresultbase ); break;
case 1: builder.loadNone(); break;
case 2: builder.loadLocal(pc, a); break;
default: builder.newVarargs(pc, a, b-1); break;
switch (b) {
case 0:
loadVarargResults(builder, pc, a, vresultbase);
break;
case 1:
builder.loadNone();
break;
case 2:
builder.loadLocal(pc, a);
break;
default:
builder.newVarargs(pc, a, b-1);
break;
}
}
builder.areturn();
builder.areturn();
break;
case Lua.OP_FORPREP: /* A sBx R(A)-=R(A+2): pc+=sBx */
builder.loadLocal(pc, a);
builder.loadLocal(pc, a+2);
builder.binaryop( Lua.OP_SUB );
builder.binaryop(Lua.OP_SUB);
builder.storeLocal(pc, a);
builder.addBranch(pc, JavaBuilder.BRANCH_GOTO, pc+1+sbx);
break;
case Lua.OP_FORLOOP: /* A sBx R(A)+=R(A+2): if R(A) <?= R(A+1) then { pc+=sBx: R(A+3)=R(A) }*/
builder.loadLocal(pc, a);
builder.loadLocal(pc, a+2);
builder.binaryop( Lua.OP_ADD );
builder.binaryop(Lua.OP_ADD);
builder.dup();
builder.dup();
builder.storeLocal(pc, a);
@@ -349,20 +358,20 @@ public class JavaGen {
builder.testForLoop();
builder.addBranch(pc, JavaBuilder.BRANCH_IFNE, pc+1+sbx);
break;
case Lua.OP_TFORCALL: /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */
builder.loadLocal(pc, a);
builder.loadLocal(pc, a+1);
builder.loadLocal(pc, a+2);
builder.invoke(2);
for ( int i=1; i<=c; i++ ) {
if ( i < c )
for (int i = 1; i <= c; i++) {
if (i < c)
builder.dup();
builder.arg( i );
builder.arg(i);
builder.storeLocal(pc, a+2+i);
}
break;
case Lua.OP_TFORLOOP:/* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx } */
builder.loadLocal(pc, a+1);
builder.dup();
@@ -370,68 +379,68 @@ public class JavaGen {
builder.isNil();
builder.addBranch(pc, JavaBuilder.BRANCH_IFEQ, pc+1+sbx);
break;
case Lua.OP_SETLIST: /* A B C R(A)[(C-1)*FPF+i]:= R(A+i), 1 <= i <= B */
int index0 = (c-1)*Lua.LFIELDS_PER_FLUSH + 1;
builder.loadLocal( pc, a );
if ( b == 0 ) {
int nstack = vresultbase - (a+1);
if ( nstack > 0 ) {
builder.setlistStack( pc, a+1, index0, nstack );
int index0 = (c-1)*Lua.LFIELDS_PER_FLUSH+1;
builder.loadLocal(pc, a);
if (b == 0) {
int nstack = vresultbase-(a+1);
if (nstack > 0) {
builder.setlistStack(pc, a+1, index0, nstack);
index0 += nstack;
}
builder.setlistVarargs( index0, vresultbase );
builder.setlistVarargs(index0, vresultbase);
} else {
builder.setlistStack( pc, a+1, index0, b );
builder.setlistStack(pc, a+1, index0, b);
builder.pop();
}
break;
case Lua.OP_CLOSURE: /* A Bx R(A):= closure(KPROTO[Bx], R(A), ... ,R(A+n)) */
{
Prototype newp = p.p[bx];
int nup = newp.upvalues.length;
String protoname = pi.subprotos[bx].name;
builder.closureCreate( protoname );
if ( nup > 0 )
builder.closureCreate(protoname);
if (nup > 0)
builder.dup();
builder.storeLocal( pc, a );
for ( int up=0; up<nup; ++up ) {
if ( up+1 < nup )
builder.storeLocal(pc, a);
for (int up = 0; up < nup; ++up) {
if (up+1 < nup)
builder.dup();
Upvaldesc u = newp.upvalues[up];
if (u.instack)
builder.closureInitUpvalueFromLocal( protoname, up, pc, u.idx );
builder.closureInitUpvalueFromLocal(protoname, up, pc, u.idx);
else
builder.closureInitUpvalueFromUpvalue( protoname, up, u.idx );
builder.closureInitUpvalueFromUpvalue(protoname, up, u.idx);
}
break;
}
}
case Lua.OP_VARARG: /* A B R(A), R(A+1), ..., R(A+B-1) = vararg */
if ( b == 0 ) {
if (b == 0) {
builder.loadVarargs();
builder.storeVarresult();
vresultbase = a;
} else {
for ( int i=1; i<b; ++a, ++i ) {
builder.loadVarargs( i );
for (int i = 1; i < b; ++a, ++i) {
builder.loadVarargs(i);
builder.storeLocal(pc, a);
}
}
break;
break;
}
// let builder process branch instructions
builder.onEndOfLuaInstruction( pc0, line );
builder.onEndOfLuaInstruction(pc0, line);
}
}
}
private void loadVarargResults(JavaBuilder builder, int pc, int a, int vresultbase) {
if ( vresultbase <= a ) {
if (vresultbase <= a) {
builder.loadVarresult();
builder.subargs( a+1-vresultbase );
} else if ( vresultbase == a ) {
builder.subargs(a+1-vresultbase);
} else if (vresultbase == a) {
builder.loadVarresult();
} else {
builder.newVarargsVarresult(pc, a, vresultbase-a);
@@ -439,9 +448,9 @@ public class JavaGen {
}
private void loadLocalOrConstant(Prototype p, JavaBuilder builder, int pc, int borc) {
if ( borc<=0xff )
builder.loadLocal( pc, borc );
if (borc <= 0xff)
builder.loadLocal(pc, borc);
else
builder.loadConstant( p.k[borc&0xff] );
builder.loadConstant(p.k[borc & 0xff]);
}
}

View File

@@ -8,64 +8,64 @@ import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Prototype;
/*******************************************************************************
* Copyright (c) 2010 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.
******************************************************************************/
* Copyright (c) 2010 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.
******************************************************************************/
public class JavaLoader extends ClassLoader {
private Map<String,byte[]> unloaded = new HashMap<String,byte[]>();
private Map<String, byte[]> unloaded = new HashMap<String, byte[]>();
public JavaLoader() {
}
public LuaFunction load( Prototype p, String classname, String filename, LuaValue env ) {
JavaGen jg = new JavaGen( p, classname, filename, false );
return load( jg, env );
public LuaFunction load(Prototype p, String classname, String filename, LuaValue env) {
JavaGen jg = new JavaGen(p, classname, filename, false);
return load(jg, env);
}
public LuaFunction load( JavaGen jg, LuaValue env ) {
include( jg );
return load( jg.classname, env );
public LuaFunction load(JavaGen jg, LuaValue env) {
include(jg);
return load(jg.classname, env);
}
public LuaFunction load(String classname, LuaValue env) {
try {
Class c = loadClass( classname );
Class c = loadClass(classname);
LuaFunction v = (LuaFunction) c.newInstance();
v.initupvalue1(env);
return v;
} catch ( Exception e ) {
} catch (Exception e) {
e.printStackTrace();
throw new IllegalStateException("bad class gen: "+e);
throw new IllegalStateException("bad class gen: " + e);
}
}
public void include( JavaGen jg ) {
unloaded.put( jg.classname, jg.bytecode );
for ( int i=0, n=jg.inners!=null? jg.inners.length: 0; i<n; i++ )
include( jg.inners[i] );
public void include(JavaGen jg) {
unloaded.put(jg.classname, jg.bytecode);
for (int i = 0, n = jg.inners != null? jg.inners.length: 0; i < n; i++)
include(jg.inners[i]);
}
public Class findClass(String classname) throws ClassNotFoundException {
byte[] bytes = (byte[]) unloaded.get(classname);
if ( bytes != null )
if (bytes != null)
return defineClass(classname, bytes, 0, bytes.length);
return super.findClass(classname);
}

View File

@@ -34,28 +34,30 @@ import org.luaj.vm2.Prototype;
import org.luaj.vm2.compiler.LuaC;
/**
* Implementation of {@link org.luaj.vm2.Globals.Compiler} which does direct
* lua-to-java-bytecode compiling.
* Implementation of {@link org.luaj.vm2.Globals.Compiler} which does direct
* lua-to-java-bytecode compiling.
* <p>
* By default, when using {@link org.luaj.vm2.lib.jse.JsePlatform} or
* {@link org.luaj.vm2.lib.jme.JmePlatform}
* to construct globals, the plain compiler {@link LuaC} is installed and lua code
* will only be compiled into lua bytecode and execute as {@link LuaClosure}.
* By default, when using {@link org.luaj.vm2.lib.jse.JsePlatform} or
* {@link org.luaj.vm2.lib.jme.JmePlatform} to construct globals, the plain
* compiler {@link LuaC} is installed and lua code will only be compiled into
* lua bytecode and execute as {@link LuaClosure}.
* <p>
* To override the default compiling behavior with {@link LuaJC}
* lua-to-java bytecode compiler, install it before undumping code,
* for example:
* <pre> {@code
* To override the default compiling behavior with {@link LuaJC} lua-to-java
* bytecode compiler, install it before undumping code, for example:
*
* <pre>
* {@code
* LuaValue globals = JsePlatform.standardGlobals();
* LuaJC.install(globals);
* LuaValue chunk = globals.load( "print('hello, world'), "main.lua");
* System.out.println(chunk.isclosure()); // Will be false when LuaJC is working.
* chunk.call();
* } </pre>
* }
* </pre>
* <p>
* This requires the bcel library to be on the class path to work as expected.
* If the library is not found, the default {@link LuaC} lua-to-lua-bytecode
* compiler will be used.
* This requires the bcel library to be on the class path to work as expected.
* If the library is not found, the default {@link LuaC} lua-to-lua-bytecode
* compiler will be used.
*
* @see Globals#compiler
* @see #install(Globals)
@@ -63,70 +65,75 @@ import org.luaj.vm2.compiler.LuaC;
* @see LuaValue
*/
public class LuaJC implements Globals.Loader {
public static final LuaJC instance = new LuaJC();
/**
* Install the compiler as the main Globals.Loader to use in a set of globals.
* Will fall back to the LuaC prototype compiler.
/**
* Install the compiler as the main Globals.Loader to use in a set of
* globals. Will fall back to the LuaC prototype compiler.
*/
public static final void install(Globals G) {
G.loader = instance;
G.loader = instance;
}
protected LuaJC() {}
public Hashtable compileAll(InputStream script, String chunkname, String filename, Globals globals, boolean genmain) throws IOException {
final String classname = toStandardJavaClassName( chunkname );
public Hashtable compileAll(InputStream script, String chunkname, String filename, Globals globals, boolean genmain)
throws IOException {
final String classname = toStandardJavaClassName(chunkname);
final Prototype p = globals.loadPrototype(script, classname, "bt");
return compileProtoAndSubProtos(p, classname, filename, genmain);
}
public Hashtable compileAll(Reader script, String chunkname, String filename, Globals globals, boolean genmain) throws IOException {
final String classname = toStandardJavaClassName( chunkname );
public Hashtable compileAll(Reader script, String chunkname, String filename, Globals globals, boolean genmain)
throws IOException {
final String classname = toStandardJavaClassName(chunkname);
final Prototype p = globals.compilePrototype(script, classname);
return compileProtoAndSubProtos(p, classname, filename, genmain);
}
private Hashtable compileProtoAndSubProtos(Prototype p, String classname, String filename, boolean genmain) throws IOException {
final String luaname = toStandardLuaFileName( filename );
private Hashtable compileProtoAndSubProtos(Prototype p, String classname, String filename, boolean genmain)
throws IOException {
final String luaname = toStandardLuaFileName(filename);
final Hashtable h = new Hashtable();
final JavaGen gen = new JavaGen(p, classname, luaname, genmain);
insert( h, gen );
insert(h, gen);
return h;
}
private void insert(Hashtable h, JavaGen gen) {
h.put(gen.classname, gen.bytecode);
for ( int i=0, n=gen.inners!=null? gen.inners.length: 0; i<n; i++ )
for (int i = 0, n = gen.inners != null? gen.inners.length: 0; i < n; i++)
insert(h, gen.inners[i]);
}
public LuaFunction load(Prototype p, String name, LuaValue globals) throws IOException {
String luaname = toStandardLuaFileName( name );
String classname = toStandardJavaClassName( luaname );
String luaname = toStandardLuaFileName(name);
String classname = toStandardJavaClassName(luaname);
JavaLoader loader = new JavaLoader();
return loader.load(p, classname, luaname, globals);
}
private static String toStandardJavaClassName( String luachunkname ) {
String stub = toStub( luachunkname );
private static String toStandardJavaClassName(String luachunkname) {
String stub = toStub(luachunkname);
StringBuffer classname = new StringBuffer();
for (int i = 0, n = stub.length(); i < n; ++i) {
final char c = stub.charAt(i);
classname.append((((i == 0) && Character.isJavaIdentifierStart(c)) || ((i > 0) && Character.isJavaIdentifierPart(c)))? c: '_');
classname.append(
(((i == 0) && Character.isJavaIdentifierStart(c)) || ((i > 0) && Character.isJavaIdentifierPart(c)))? c
: '_');
}
return classname.toString();
}
private static String toStandardLuaFileName( String luachunkname ) {
String stub = toStub( luachunkname );
String filename = stub.replace('.','/')+".lua";
private static String toStandardLuaFileName(String luachunkname) {
String stub = toStub(luachunkname);
String filename = stub.replace('.', '/') + ".lua";
return filename.startsWith("@")? filename.substring(1): filename;
}
private static String toStub( String s ) {
String stub = s.endsWith(".lua")? s.substring(0,s.length()-4): s;
private static String toStub(String s) {
String stub = s.endsWith(".lua")? s.substring(0, s.length()-4): s;
return stub;
}
}

View File

@@ -15,39 +15,39 @@ import org.luaj.vm2.Upvaldesc;
*/
public class ProtoInfo {
public final String name;
public final Prototype prototype; // the prototype that this info is about
public final ProtoInfo[] subprotos; // one per enclosed prototype, or null
public final BasicBlock[] blocks; // basic block analysis of code branching
public final BasicBlock[] blocklist; // blocks in breadth-first order
public final VarInfo[] params; // Parameters and initial values of stack variables
public final VarInfo[][] vars; // Each variable
public final UpvalInfo[] upvals; // from outer scope
public final String name;
public final Prototype prototype; // the prototype that this info is about
public final ProtoInfo[] subprotos; // one per enclosed prototype, or null
public final BasicBlock[] blocks; // basic block analysis of code branching
public final BasicBlock[] blocklist; // blocks in breadth-first order
public final VarInfo[] params; // Parameters and initial values of stack variables
public final VarInfo[][] vars; // Each variable
public final UpvalInfo[] upvals; // from outer scope
public final UpvalInfo[][] openups; // per slot, upvalues allocated by this prototype
// A main chunk proto info.
public ProtoInfo(Prototype p, String name) {
// For the outer chunk, we have one upvalue which is the environment.
this(p,name,null);
this(p, name, null);
}
private ProtoInfo(Prototype p, String name, UpvalInfo[] u) {
this.name = name;
this.prototype = p;
this.upvals = u != null? u: new UpvalInfo[] { new UpvalInfo(this) };
this.subprotos = p.p!=null&&p.p.length>0? new ProtoInfo[p.p.length]: null;
this.subprotos = p.p != null && p.p.length > 0? new ProtoInfo[p.p.length]: null;
// find basic blocks
this.blocks = BasicBlock.findBasicBlocks(p);
this.blocklist = BasicBlock.findLiveBlocks(blocks);
// params are inputs to first block
this.params = new VarInfo[p.maxstacksize];
for ( int slot=0; slot<p.maxstacksize; slot++ ) {
for (int slot = 0; slot < p.maxstacksize; slot++) {
VarInfo v = VarInfo.PARAM(slot);
params[slot] = v;
}
// find variables
this.vars = findVariables();
replaceTrivialPhiVariables();
@@ -59,36 +59,38 @@ public class ProtoInfo {
public String toString() {
StringBuffer sb = new StringBuffer();
// prototpye name
sb.append( "proto '"+name+"'\n" );
sb.append("proto '" + name + "'\n");
// upvalues from outer scopes
for ( int i=0, n=(upvals!=null? upvals.length: 0); i<n; i++ )
sb.append( " up["+i+"]: "+upvals[i]+"\n" );
for (int i = 0, n = (upvals != null? upvals.length: 0); i < n; i++)
sb.append(" up[" + i + "]: " + upvals[i] + "\n");
// basic blocks
for ( int i=0; i<blocklist.length; i++ ) {
for (int i = 0; i < blocklist.length; i++) {
BasicBlock b = blocklist[i];
int pc0 = b.pc0;
sb.append( " block "+b.toString() );
appendOpenUps( sb, -1 );
sb.append(" block " + b.toString());
appendOpenUps(sb, -1);
// instructions
for ( int pc=pc0; pc<=b.pc1; pc++ ) {
for (int pc = pc0; pc <= b.pc1; pc++) {
// open upvalue storage
appendOpenUps( sb, pc );
appendOpenUps(sb, pc);
// opcode
sb.append( " " );
for ( int j=0; j<prototype.maxstacksize; j++ ) {
sb.append(" ");
for (int j = 0; j < prototype.maxstacksize; j++) {
VarInfo v = vars[j][pc];
String u = (v==null? "": v.upvalue!=null? !v.upvalue.rw? "[C] ": (v.allocupvalue&&v.pc==pc? "[*] ": "[] "): " ");
String s = v==null? "null ": String.valueOf(v);
sb.append( s+u);
String u = (v == null? ""
: v.upvalue != null? !v.upvalue.rw? "[C] ": (v.allocupvalue && v.pc == pc? "[*] ": "[] ")
: " ");
String s = v == null? "null ": String.valueOf(v);
sb.append(s+u);
}
sb.append( " " );
sb.append(" ");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream ops = Print.ps;
Print.ps = new PrintStream(baos);
@@ -96,371 +98,383 @@ public class ProtoInfo {
Print.printOpCode(prototype, pc);
} finally {
Print.ps.close();
Print.ps = ops;
Print.ps = ops;
}
sb.append( baos.toString() );
sb.append( "\n" );
sb.append(baos.toString());
sb.append("\n");
}
}
// nested functions
for ( int i=0, n=subprotos!=null? subprotos.length: 0; i<n; i++ ) {
sb.append( subprotos[i].toString() );
for (int i = 0, n = subprotos != null? subprotos.length: 0; i < n; i++) {
sb.append(subprotos[i].toString());
}
return sb.toString();
}
private void appendOpenUps(StringBuffer sb, int pc) {
for ( int j=0; j<prototype.maxstacksize; j++ ) {
VarInfo v = (pc<0? params[j]: vars[j][pc]);
if ( v != null && v.pc == pc && v.allocupvalue ) {
sb.append( " open: "+v.upvalue+"\n" );
for (int j = 0; j < prototype.maxstacksize; j++) {
VarInfo v = (pc < 0? params[j]: vars[j][pc]);
if (v != null && v.pc == pc && v.allocupvalue) {
sb.append(" open: " + v.upvalue + "\n");
}
}
}
private VarInfo[][] findVariables() {
// create storage for variables.
int n = prototype.code.length;
int m = prototype.maxstacksize;
VarInfo[][] v = new VarInfo[m][];
for ( int i=0; i<v.length; i++ )
v[i] = new VarInfo[n];
for (int i = 0; i < v.length; i++)
v[i] = new VarInfo[n];
// process instructions
for ( int bi=0; bi<blocklist.length; bi++ ) {
for (int bi = 0; bi < blocklist.length; bi++) {
BasicBlock b0 = blocklist[bi];
// input from previous blocks
int nprev = b0.prev!=null? b0.prev.length: 0;
for ( int slot=0; slot<m; slot++ ) {
int nprev = b0.prev != null? b0.prev.length: 0;
for (int slot = 0; slot < m; slot++) {
VarInfo var = null;
if ( nprev == 0 )
if (nprev == 0)
var = params[slot];
else if ( nprev == 1 )
else if (nprev == 1)
var = v[slot][b0.prev[0].pc1];
else {
for ( int i=0; i<nprev; i++ ) {
for (int i = 0; i < nprev; i++) {
BasicBlock bp = b0.prev[i];
if ( v[slot][bp.pc1] == VarInfo.INVALID )
if (v[slot][bp.pc1] == VarInfo.INVALID)
var = VarInfo.INVALID;
}
}
if ( var == null )
if (var == null)
var = VarInfo.PHI(this, slot, b0.pc0);
v[slot][b0.pc0] = var;
}
// process instructions for this basic block
for ( int pc=b0.pc0; pc<=b0.pc1; pc++ ) {
for (int pc = b0.pc0; pc <= b0.pc1; pc++) {
// propogate previous values except at block boundaries
if ( pc > b0.pc0 )
propogateVars( v, pc-1, pc );
int a,b,c;
if (pc > b0.pc0)
propogateVars(v, pc-1, pc);
int a, b, c;
int ins = prototype.code[pc];
int op = Lua.GET_OPCODE(ins);
// account for assignments, references and invalidations
switch ( op ) {
switch (op) {
case Lua.OP_LOADK:/* A Bx R(A) := Kst(Bx) */
case Lua.OP_LOADBOOL:/* A B C R(A) := (Bool)B; if (C) pc++ */
case Lua.OP_GETUPVAL: /* A B R(A) := UpValue[B] */
case Lua.OP_NEWTABLE: /* A B C R(A) := {} (size = B,C) */
a = Lua.GETARG_A( ins );
v[a][pc] = new VarInfo(a,pc);
a = Lua.GETARG_A(ins);
v[a][pc] = new VarInfo(a, pc);
break;
case Lua.OP_MOVE:/* A B R(A) := R(B) */
case Lua.OP_MOVE:/* A B R(A) := R(B) */
case Lua.OP_UNM: /* A B R(A) := -R(B) */
case Lua.OP_NOT: /* A B R(A) := not R(B) */
case Lua.OP_LEN: /* A B R(A) := length of R(B) */
case Lua.OP_TESTSET: /* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */
a = Lua.GETARG_A( ins );
b = Lua.GETARG_B( ins );
case Lua.OP_TESTSET: /* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */
a = Lua.GETARG_A(ins);
b = Lua.GETARG_B(ins);
v[b][pc].isreferenced = true;
v[a][pc] = new VarInfo(a,pc);
v[a][pc] = new VarInfo(a, pc);
break;
case Lua.OP_ADD: /* A B C R(A) := RK(B) + RK(C) */
case Lua.OP_SUB: /* A B C R(A) := RK(B) - RK(C) */
case Lua.OP_MUL: /* A B C R(A) := RK(B) * RK(C) */
case Lua.OP_DIV: /* A B C R(A) := RK(B) / RK(C) */
case Lua.OP_MOD: /* A B C R(A) := RK(B) % RK(C) */
case Lua.OP_POW: /* A B C R(A) := RK(B) ^ RK(C) */
a = Lua.GETARG_A( ins );
b = Lua.GETARG_B( ins );
c = Lua.GETARG_C( ins );
if (!Lua.ISK(b)) v[b][pc].isreferenced = true;
if (!Lua.ISK(c)) v[c][pc].isreferenced = true;
v[a][pc] = new VarInfo(a,pc);
a = Lua.GETARG_A(ins);
b = Lua.GETARG_B(ins);
c = Lua.GETARG_C(ins);
if (!Lua.ISK(b))
v[b][pc].isreferenced = true;
if (!Lua.ISK(c))
v[c][pc].isreferenced = true;
v[a][pc] = new VarInfo(a, pc);
break;
case Lua.OP_SETTABLE: /* A B C R(A)[RK(B)]:= RK(C) */
a = Lua.GETARG_A( ins );
b = Lua.GETARG_B( ins );
c = Lua.GETARG_C( ins );
a = Lua.GETARG_A(ins);
b = Lua.GETARG_B(ins);
c = Lua.GETARG_C(ins);
v[a][pc].isreferenced = true;
if (!Lua.ISK(b)) v[b][pc].isreferenced = true;
if (!Lua.ISK(c)) v[c][pc].isreferenced = true;
if (!Lua.ISK(b))
v[b][pc].isreferenced = true;
if (!Lua.ISK(c))
v[c][pc].isreferenced = true;
break;
case Lua.OP_SETTABUP: /* A B C UpValue[A][RK(B)] := RK(C) */
b = Lua.GETARG_B( ins );
c = Lua.GETARG_C( ins );
if (!Lua.ISK(b)) v[b][pc].isreferenced = true;
if (!Lua.ISK(c)) v[c][pc].isreferenced = true;
break;
case Lua.OP_CONCAT: /* A B C R(A) := R(B).. ... ..R(C) */
a = Lua.GETARG_A( ins );
b = Lua.GETARG_B( ins );
c = Lua.GETARG_C( ins );
for ( ; b<=c; b++ )
b = Lua.GETARG_B(ins);
c = Lua.GETARG_C(ins);
if (!Lua.ISK(b))
v[b][pc].isreferenced = true;
v[a][pc] = new VarInfo(a,pc);
if (!Lua.ISK(c))
v[c][pc].isreferenced = true;
break;
case Lua.OP_CONCAT: /* A B C R(A) := R(B).. ... ..R(C) */
a = Lua.GETARG_A(ins);
b = Lua.GETARG_B(ins);
c = Lua.GETARG_C(ins);
for (; b <= c; b++)
v[b][pc].isreferenced = true;
v[a][pc] = new VarInfo(a, pc);
break;
case Lua.OP_FORPREP: /* A sBx R(A)-=R(A+2); pc+=sBx */
a = Lua.GETARG_A( ins );
a = Lua.GETARG_A(ins);
v[a+2][pc].isreferenced = true;
v[a][pc] = new VarInfo(a,pc);
v[a][pc] = new VarInfo(a, pc);
break;
case Lua.OP_GETTABLE: /* A B C R(A) := R(B)[RK(C)] */
a = Lua.GETARG_A( ins );
b = Lua.GETARG_B( ins );
c = Lua.GETARG_C( ins );
a = Lua.GETARG_A(ins);
b = Lua.GETARG_B(ins);
c = Lua.GETARG_C(ins);
v[b][pc].isreferenced = true;
if (!Lua.ISK(c)) v[c][pc].isreferenced = true;
v[a][pc] = new VarInfo(a,pc);
if (!Lua.ISK(c))
v[c][pc].isreferenced = true;
v[a][pc] = new VarInfo(a, pc);
break;
case Lua.OP_GETTABUP: /* A B C R(A) := UpValue[B][RK(C)] */
a = Lua.GETARG_A( ins );
c = Lua.GETARG_C( ins );
if (!Lua.ISK(c)) v[c][pc].isreferenced = true;
v[a][pc] = new VarInfo(a,pc);
a = Lua.GETARG_A(ins);
c = Lua.GETARG_C(ins);
if (!Lua.ISK(c))
v[c][pc].isreferenced = true;
v[a][pc] = new VarInfo(a, pc);
break;
case Lua.OP_SELF: /* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */
a = Lua.GETARG_A( ins );
b = Lua.GETARG_B( ins );
c = Lua.GETARG_C( ins );
a = Lua.GETARG_A(ins);
b = Lua.GETARG_B(ins);
c = Lua.GETARG_C(ins);
v[b][pc].isreferenced = true;
if (!Lua.ISK(c)) v[c][pc].isreferenced = true;
v[a][pc] = new VarInfo(a,pc);
v[a+1][pc] = new VarInfo(a+1,pc);
if (!Lua.ISK(c))
v[c][pc].isreferenced = true;
v[a][pc] = new VarInfo(a, pc);
v[a+1][pc] = new VarInfo(a+1, pc);
break;
case Lua.OP_FORLOOP: /* A sBx R(A)+=R(A+2);
if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/
a = Lua.GETARG_A( ins );
if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/
a = Lua.GETARG_A(ins);
v[a][pc].isreferenced = true;
v[a+2][pc].isreferenced = true;
v[a][pc] = new VarInfo(a,pc);
v[a][pc] = new VarInfo(a, pc);
v[a][pc].isreferenced = true;
v[a+1][pc].isreferenced = true;
v[a+3][pc] = new VarInfo(a+3,pc);
v[a+3][pc] = new VarInfo(a+3, pc);
break;
case Lua.OP_LOADNIL: /* A B R(A) := ... := R(A+B) := nil */
a = Lua.GETARG_A( ins );
b = Lua.GETARG_B( ins );
for ( ; b-->=0; a++ )
v[a][pc] = new VarInfo(a,pc);
a = Lua.GETARG_A(ins);
b = Lua.GETARG_B(ins);
for (; b-- >= 0; a++)
v[a][pc] = new VarInfo(a, pc);
break;
case Lua.OP_VARARG: /* A B R(A), R(A+1), ..., R(A+B-1) = vararg */
a = Lua.GETARG_A( ins );
b = Lua.GETARG_B( ins );
for ( int j=1; j<b; j++, a++ )
v[a][pc] = new VarInfo(a,pc);
if ( b == 0 )
for ( ; a<m; a++ )
case Lua.OP_VARARG: /* A B R(A), R(A+1), ..., R(A+B-1) = vararg */
a = Lua.GETARG_A(ins);
b = Lua.GETARG_B(ins);
for (int j = 1; j < b; j++, a++)
v[a][pc] = new VarInfo(a, pc);
if (b == 0)
for (; a < m; a++)
v[a][pc] = VarInfo.INVALID;
break;
case Lua.OP_CALL: /* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
a = Lua.GETARG_A( ins );
b = Lua.GETARG_B( ins );
c = Lua.GETARG_C( ins );
a = Lua.GETARG_A(ins);
b = Lua.GETARG_B(ins);
c = Lua.GETARG_C(ins);
v[a][pc].isreferenced = true;
v[a][pc].isreferenced = true;
for ( int i=1; i<=b-1; i++ )
for (int i = 1; i <= b-1; i++)
v[a+i][pc].isreferenced = true;
for ( int j=0; j<=c-2; j++, a++ )
v[a][pc] = new VarInfo(a,pc);
for ( ; a<m; a++ )
for (int j = 0; j <= c-2; j++, a++)
v[a][pc] = new VarInfo(a, pc);
for (; a < m; a++)
v[a][pc] = VarInfo.INVALID;
break;
case Lua.OP_TFORCALL: /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */
a = Lua.GETARG_A( ins );
c = Lua.GETARG_C( ins );
a = Lua.GETARG_A(ins);
c = Lua.GETARG_C(ins);
v[a++][pc].isreferenced = true;
v[a++][pc].isreferenced = true;
v[a++][pc].isreferenced = true;
for ( int j=0; j<c; j++, a++ )
v[a][pc] = new VarInfo(a,pc);
for ( ; a<m; a++ )
for (int j = 0; j < c; j++, a++)
v[a][pc] = new VarInfo(a, pc);
for (; a < m; a++)
v[a][pc] = VarInfo.INVALID;
break;
case Lua.OP_TFORLOOP: /* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx */
a = Lua.GETARG_A( ins );
a = Lua.GETARG_A(ins);
v[a+1][pc].isreferenced = true;
v[a][pc] = new VarInfo(a,pc);
v[a][pc] = new VarInfo(a, pc);
break;
case Lua.OP_TAILCALL: /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
a = Lua.GETARG_A( ins );
b = Lua.GETARG_B( ins );
a = Lua.GETARG_A(ins);
b = Lua.GETARG_B(ins);
v[a][pc].isreferenced = true;
for ( int i=1; i<=b-1; i++ )
for (int i = 1; i <= b-1; i++)
v[a+i][pc].isreferenced = true;
break;
case Lua.OP_RETURN: /* A B return R(A), ... ,R(A+B-2) (see note) */
a = Lua.GETARG_A( ins );
b = Lua.GETARG_B( ins );
for ( int i=0; i<=b-2; i++ )
a = Lua.GETARG_A(ins);
b = Lua.GETARG_B(ins);
for (int i = 0; i <= b-2; i++)
v[a+i][pc].isreferenced = true;
break;
case Lua.OP_CLOSURE: { /* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */
a = Lua.GETARG_A( ins );
b = Lua.GETARG_Bx( ins );
a = Lua.GETARG_A(ins);
b = Lua.GETARG_Bx(ins);
Upvaldesc[] upvalues = prototype.p[b].upvalues;
for (int k = 0, nups = upvalues.length; k < nups; ++k)
if (upvalues[k].instack)
v[upvalues[k].idx][pc].isreferenced = true;
v[a][pc] = new VarInfo(a,pc);
v[a][pc] = new VarInfo(a, pc);
break;
}
case Lua.OP_SETLIST: /* A B C R(A)[(C-1)*FPF+i]:= R(A+i), 1 <= i <= B */
a = Lua.GETARG_A( ins );
b = Lua.GETARG_B( ins );
a = Lua.GETARG_A(ins);
b = Lua.GETARG_B(ins);
v[a][pc].isreferenced = true;
for ( int i=1; i<=b; i++ )
for (int i = 1; i <= b; i++)
v[a+i][pc].isreferenced = true;
break;
case Lua.OP_SETUPVAL: /* A B UpValue[B]:= R(A) */
case Lua.OP_TEST: /* A C if not (R(A) <=> C) then pc++ */
a = Lua.GETARG_A( ins );
case Lua.OP_TEST: /* A C if not (R(A) <=> C) then pc++ */
a = Lua.GETARG_A(ins);
v[a][pc].isreferenced = true;
break;
case Lua.OP_EQ: /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
case Lua.OP_LT: /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
case Lua.OP_LE: /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
b = Lua.GETARG_B( ins );
c = Lua.GETARG_C( ins );
if (!Lua.ISK(b)) v[b][pc].isreferenced = true;
if (!Lua.ISK(c)) v[c][pc].isreferenced = true;
b = Lua.GETARG_B(ins);
c = Lua.GETARG_C(ins);
if (!Lua.ISK(b))
v[b][pc].isreferenced = true;
if (!Lua.ISK(c))
v[c][pc].isreferenced = true;
break;
case Lua.OP_JMP: /* sBx pc+=sBx */
a = Lua.GETARG_A( ins );
a = Lua.GETARG_A(ins);
if (a > 0)
for ( --a; a<m; a++ )
for (--a; a < m; a++)
v[a][pc] = VarInfo.INVALID;
break;
default:
throw new IllegalStateException("unhandled opcode: "+ins);
throw new IllegalStateException("unhandled opcode: " + ins);
}
}
}
}
return v;
}
private static void propogateVars(VarInfo[][] v, int pcfrom, int pcto) {
for ( int j=0, m=v.length; j<m; j++ )
for (int j = 0, m = v.length; j < m; j++)
v[j][pcto] = v[j][pcfrom];
}
private void replaceTrivialPhiVariables() {
for ( int i=0; i<blocklist.length; i++ ) {
private void replaceTrivialPhiVariables() {
for (int i = 0; i < blocklist.length; i++) {
BasicBlock b0 = blocklist[i];
for ( int slot=0; slot<prototype.maxstacksize; slot++ ) {
for (int slot = 0; slot < prototype.maxstacksize; slot++) {
VarInfo vold = vars[slot][b0.pc0];
VarInfo vnew = vold.resolvePhiVariableValues();
if ( vnew != null )
substituteVariable( slot, vold, vnew );
if (vnew != null)
substituteVariable(slot, vold, vnew);
}
}
}
}
private void substituteVariable(int slot, VarInfo vold, VarInfo vnew) {
for ( int i=0, n=prototype.code.length; i<n; i++ )
replaceAll( vars[slot], vars[slot].length, vold, vnew );
for (int i = 0, n = prototype.code.length; i < n; i++)
replaceAll(vars[slot], vars[slot].length, vold, vnew);
}
private void replaceAll(VarInfo[] v, int n, VarInfo vold, VarInfo vnew) {
for ( int i=0; i<n; i++ )
if ( v[i] == vold )
for (int i = 0; i < n; i++)
if (v[i] == vold)
v[i] = vnew;
}
private void findUpvalues() {
int[] code = prototype.code;
int n = code.length;
// propogate to inner prototypes
String[] names = findInnerprotoNames();
for ( int pc=0; pc<n; pc++ ) {
if ( Lua.GET_OPCODE(code[pc]) == Lua.OP_CLOSURE ) {
for (int pc = 0; pc < n; pc++) {
if (Lua.GET_OPCODE(code[pc]) == Lua.OP_CLOSURE) {
int bx = Lua.GETARG_Bx(code[pc]);
Prototype newp = prototype.p[bx];
UpvalInfo[] newu = new UpvalInfo[newp.upvalues.length];
String newname = name + "$" + names[bx];
for ( int j=0; j<newp.upvalues.length; ++j ) {
for (int j = 0; j < newp.upvalues.length; ++j) {
Upvaldesc u = newp.upvalues[j];
newu[j] = u.instack? findOpenUp(pc,u.idx) : upvals[u.idx];
newu[j] = u.instack? findOpenUp(pc, u.idx): upvals[u.idx];
}
subprotos[bx] = new ProtoInfo(newp, newname, newu);
}
}
// mark all upvalues that are written locally as read/write
for ( int pc=0; pc<n; pc++ ) {
if ( Lua.GET_OPCODE(code[pc]) == Lua.OP_SETUPVAL )
for (int pc = 0; pc < n; pc++) {
if (Lua.GET_OPCODE(code[pc]) == Lua.OP_SETUPVAL)
upvals[Lua.GETARG_B(code[pc])].rw = true;
}
}
private UpvalInfo findOpenUp(int pc, int slot) {
if ( openups[slot] == null )
if (openups[slot] == null)
openups[slot] = new UpvalInfo[prototype.code.length];
if ( openups[slot][pc] != null )
if (openups[slot][pc] != null)
return openups[slot][pc];
UpvalInfo u = new UpvalInfo(this, pc, slot);
for ( int i=0, n=prototype.code.length; i<n; ++i )
if ( vars[slot][i] != null && vars[slot][i].upvalue == u )
for (int i = 0, n = prototype.code.length; i < n; ++i)
if (vars[slot][i] != null && vars[slot][i].upvalue == u)
openups[slot][i] = u;
return u;
}
public boolean isUpvalueAssign(int pc, int slot) {
VarInfo v = pc<0? params[slot]: vars[slot][pc];
VarInfo v = pc < 0? params[slot]: vars[slot][pc];
return v != null && v.upvalue != null && v.upvalue.rw;
}
public boolean isUpvalueCreate(int pc, int slot) {
VarInfo v = pc<0? params[slot]: vars[slot][pc];
VarInfo v = pc < 0? params[slot]: vars[slot][pc];
return v != null && v.upvalue != null && v.upvalue.rw && v.allocupvalue && pc == v.pc;
}
public boolean isUpvalueRefer(int pc, int slot) {
// special case when both refer and assign in same instruction
if ( pc > 0 && vars[slot][pc] != null && vars[slot][pc].pc == pc && vars[slot][pc-1] != null )
if (pc > 0 && vars[slot][pc] != null && vars[slot][pc].pc == pc && vars[slot][pc-1] != null)
pc -= 1;
VarInfo v = pc<0? params[slot]: vars[slot][pc];
VarInfo v = pc < 0? params[slot]: vars[slot][pc];
return v != null && v.upvalue != null && v.upvalue.rw;
}
@@ -472,49 +486,49 @@ public class ProtoInfo {
public boolean isReadWriteUpvalue(UpvalInfo u) {
return u.rw;
}
private String[] findInnerprotoNames() {
if (prototype.p.length <= 0)
return null;
// find all the prototype names
String[] names = new String[prototype.p.length];
Hashtable used = new Hashtable();
Hashtable used = new Hashtable();
int[] code = prototype.code;
int n = code.length;
for ( int pc=0; pc<n; pc++ ) {
if ( Lua.GET_OPCODE(code[pc]) == Lua.OP_CLOSURE ) {
for (int pc = 0; pc < n; pc++) {
if (Lua.GET_OPCODE(code[pc]) == Lua.OP_CLOSURE) {
int bx = Lua.GETARG_Bx(code[pc]);
String name = null;
final int i = code[pc+1];
switch (Lua.GET_OPCODE(i)) {
case Lua.OP_SETTABLE:
case Lua.OP_SETTABUP: {
final int b = Lua.GETARG_B(i);
if (Lua.ISK(b))
name = prototype.k[b&0x0ff].tojstring();
break;
}
case Lua.OP_SETUPVAL: {
final int b = Lua.GETARG_B(i);
final LuaString s = prototype.upvalues[b].name;
if (s != null)
name = s.tojstring();
break;
}
default: // Local variable
final int a = Lua.GETARG_A(code[pc]);
final LuaString s = prototype.getlocalname(a+1, pc+1);
if (s != null)
name = s.tojstring();
break;
case Lua.OP_SETTABLE:
case Lua.OP_SETTABUP: {
final int b = Lua.GETARG_B(i);
if (Lua.ISK(b))
name = prototype.k[b & 0x0ff].tojstring();
break;
}
case Lua.OP_SETUPVAL: {
final int b = Lua.GETARG_B(i);
final LuaString s = prototype.upvalues[b].name;
if (s != null)
name = s.tojstring();
break;
}
default: // Local variable
final int a = Lua.GETARG_A(code[pc]);
final LuaString s = prototype.getlocalname(a+1, pc+1);
if (s != null)
name = s.tojstring();
break;
}
name = name != null? toJavaClassPart(name): String.valueOf(bx);
if (used.containsKey(name)) {
String basename = name;
int count = 1;
do {
name = basename + '$' + count++;
} while (used.containsKey(name));
name = basename+'$'+count++;
} while ( used.containsKey(name) );
}
used.put(name, Boolean.TRUE);
names[bx] = name;
@@ -522,12 +536,12 @@ public class ProtoInfo {
}
return names;
}
private static String toJavaClassPart(String s) {
final int n = s.length();
StringBuffer sb = new StringBuffer(n);
for (int i = 0; i < n; ++i)
sb.append( Character.isJavaIdentifierPart(s.charAt(i)) ? s.charAt(i): '_' );
sb.append(Character.isJavaIdentifierPart(s.charAt(i))? s.charAt(i): '_');
return sb.toString();
}

View File

@@ -7,10 +7,10 @@ import org.luaj.vm2.Lua;
public class UpvalInfo {
ProtoInfo pi; // where defined
int slot; // where defined
int nvars; // number of vars involved
VarInfo var[]; // list of vars
boolean rw; // read-write
int slot; // where defined
int nvars; // number of vars involved
VarInfo var[]; // list of vars
boolean rw; // read-write
// Upval info representing the implied context containing only the environment.
public UpvalInfo(ProtoInfo pi) {
@@ -26,30 +26,30 @@ public class UpvalInfo {
this.slot = slot;
this.nvars = 0;
this.var = null;
includeVarAndPosteriorVars( pi.vars[slot][pc] );
for ( int i=0; i<nvars; i++ )
var[i].allocupvalue = testIsAllocUpvalue( var[i] );
this.rw = nvars > 1;
includeVarAndPosteriorVars(pi.vars[slot][pc]);
for (int i = 0; i < nvars; i++)
var[i].allocupvalue = testIsAllocUpvalue(var[i]);
this.rw = nvars > 1;
}
private boolean includeVarAndPosteriorVars( VarInfo var ) {
if ( var == null || var == VarInfo.INVALID )
private boolean includeVarAndPosteriorVars(VarInfo var) {
if (var == null || var == VarInfo.INVALID)
return false;
if ( var.upvalue == this )
if (var.upvalue == this)
return true;
var.upvalue = this;
appendVar( var );
if ( isLoopVariable( var ) )
appendVar(var);
if (isLoopVariable(var))
return false;
boolean loopDetected = includePosteriorVarsCheckLoops( var );
if ( loopDetected )
includePriorVarsIgnoreLoops( var );
boolean loopDetected = includePosteriorVarsCheckLoops(var);
if (loopDetected)
includePriorVarsIgnoreLoops(var);
return loopDetected;
}
private boolean isLoopVariable(VarInfo var) {
if ( var.pc >= 0 ) {
switch ( Lua.GET_OPCODE(pi.prototype.code[var.pc]) ) {
if (var.pc >= 0) {
switch (Lua.GET_OPCODE(pi.prototype.code[var.pc])) {
case Lua.OP_TFORLOOP:
case Lua.OP_FORLOOP:
return true;
@@ -58,25 +58,25 @@ public class UpvalInfo {
return false;
}
private boolean includePosteriorVarsCheckLoops( VarInfo prior ) {
private boolean includePosteriorVarsCheckLoops(VarInfo prior) {
boolean loopDetected = false;
for ( int i=0, n=pi.blocklist.length; i<n; i++ ) {
for (int i = 0, n = pi.blocklist.length; i < n; i++) {
BasicBlock b = pi.blocklist[i];
VarInfo v = pi.vars[slot][b.pc1];
if ( v == prior ) {
for ( int j=0, m=b.next!=null? b.next.length: 0; j<m; j++ ) {
if (v == prior) {
for (int j = 0, m = b.next != null? b.next.length: 0; j < m; j++) {
BasicBlock b1 = b.next[j];
VarInfo v1 = pi.vars[slot][b1.pc0];
if ( v1 != prior ) {
loopDetected |= includeVarAndPosteriorVars( v1 );
if ( v1.isPhiVar() )
includePriorVarsIgnoreLoops( v1 );
if (v1 != prior) {
loopDetected |= includeVarAndPosteriorVars(v1);
if (v1.isPhiVar())
includePriorVarsIgnoreLoops(v1);
}
}
} else {
for ( int pc=b.pc1-1; pc>=b.pc0; pc-- ) {
if ( pi.vars[slot][pc] == prior ) {
loopDetected |= includeVarAndPosteriorVars( pi.vars[slot][pc+1] );
for (int pc = b.pc1-1; pc >= b.pc0; pc--) {
if (pi.vars[slot][pc] == prior) {
loopDetected |= includeVarAndPosteriorVars(pi.vars[slot][pc+1]);
break;
}
}
@@ -84,22 +84,22 @@ public class UpvalInfo {
}
return loopDetected;
}
private void includePriorVarsIgnoreLoops(VarInfo poster) {
for ( int i=0, n=pi.blocklist.length; i<n; i++ ) {
for (int i = 0, n = pi.blocklist.length; i < n; i++) {
BasicBlock b = pi.blocklist[i];
VarInfo v = pi.vars[slot][b.pc0];
if ( v == poster ) {
for ( int j=0, m=b.prev!=null? b.prev.length: 0; j<m; j++ ) {
if (v == poster) {
for (int j = 0, m = b.prev != null? b.prev.length: 0; j < m; j++) {
BasicBlock b0 = b.prev[j];
VarInfo v0 = pi.vars[slot][b0.pc1];
if ( v0 != poster )
includeVarAndPosteriorVars( v0 );
if (v0 != poster)
includeVarAndPosteriorVars(v0);
}
} else {
for ( int pc=b.pc0+1; pc<=b.pc1; pc++ ) {
if ( pi.vars[slot][pc] == poster ) {
includeVarAndPosteriorVars( pi.vars[slot][pc-1] );
for (int pc = b.pc0+1; pc <= b.pc1; pc++) {
if (pi.vars[slot][pc] == poster) {
includeVarAndPosteriorVars(pi.vars[slot][pc-1]);
break;
}
}
@@ -108,46 +108,46 @@ public class UpvalInfo {
}
private void appendVar(VarInfo v) {
if ( nvars == 0 ) {
if (nvars == 0) {
var = new VarInfo[1];
} else if ( nvars+1 >= var.length ) {
} else if (nvars+1 >= var.length) {
VarInfo[] s = var;
var = new VarInfo[nvars*2+1];
System.arraycopy(s, 0, var, 0, nvars);
System.arraycopy(s, 0, var, 0, nvars);
}
var[nvars++] = v;
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append( pi.name );
for ( int i=0; i<nvars; i++ ) {
sb.append( i>0? ",": " " );
sb.append( String.valueOf(var[i]));
sb.append(pi.name);
for (int i = 0; i < nvars; i++) {
sb.append(i > 0? ",": " ");
sb.append(String.valueOf(var[i]));
}
if ( rw )
sb.append( "(rw)" );
if (rw)
sb.append("(rw)");
return sb.toString();
}
private boolean testIsAllocUpvalue(VarInfo v) {
if ( v.pc < 0 )
if (v.pc < 0)
return true;
BasicBlock b = pi.blocks[v.pc];
if ( v.pc > b.pc0 )
if (v.pc > b.pc0)
return pi.vars[slot][v.pc-1].upvalue != this;
if ( b.prev == null ) {
if (b.prev == null) {
v = pi.params[slot];
if ( v != null && v.upvalue != this )
if (v != null && v.upvalue != this)
return true;
} else {
for ( int i=0, n=b.prev.length; i<n; i++ ) {
for (int i = 0, n = b.prev.length; i < n; i++) {
v = pi.vars[slot][b.prev[i].pc1];
if ( v != null && v.upvalue != this )
if (v != null && v.upvalue != this)
return true;
}
}
return false;
}
}
}

View File

@@ -24,10 +24,10 @@ public class VarInfo {
}
public final int slot; // where assigned
public final int pc; // where assigned, or -1 if for block inputs
public final int pc; // where assigned, or -1 if for block inputs
public UpvalInfo upvalue; // not null if this var is an upvalue
public boolean allocupvalue; // true if this variable allocates r/w upvalue
public UpvalInfo upvalue; // not null if this var is an upvalue
public boolean allocupvalue; // true if this variable allocates r/w upvalue
// storage
public boolean isreferenced; // true if this variable is refenced by some
// opcode
@@ -38,14 +38,16 @@ public class VarInfo {
}
public String toString() {
return slot < 0 ? "x.x" : (slot + "." + pc);
return slot < 0? "x.x": (slot + "." + pc);
}
/** Return replacement variable if there is exactly one value possible,
* otherwise compute entire collection of variables and return null.
* Computes the list of aall variable values, and saves it for the future.
/**
* Return replacement variable if there is exactly one value possible,
* otherwise compute entire collection of variables and return null.
* Computes the list of aall variable values, and saves it for the future.
*
* @return new Variable to replace with if there is only one value, or null to leave alone.
* @return new Variable to replace with if there is only one value, or null
* to leave alone.
*/
public VarInfo resolvePhiVariableValues() {
return null;
@@ -55,9 +57,7 @@ public class VarInfo {
vars.add(this);
}
public boolean isPhiVar() {
return false;
}
public boolean isPhiVar() { return false; }
private static final class ParamVarInfo extends VarInfo {
private ParamVarInfo(int slot, int pc) {
@@ -81,24 +81,22 @@ public class VarInfo {
private static final class PhiVarInfo extends VarInfo {
private final ProtoInfo pi;
VarInfo[] values;
VarInfo[] values;
private PhiVarInfo(ProtoInfo pi, int slot, int pc) {
super(slot, pc);
this.pi = pi;
}
public boolean isPhiVar() {
return true;
}
public boolean isPhiVar() { return true; }
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append( super.toString() );
sb.append(super.toString());
sb.append("={");
for (int i=0, n=(values!=null? values.length : 0); i<n; i++) {
if ( i>0 )
sb.append( "," );
for (int i = 0, n = (values != null? values.length: 0); i < n; i++) {
if (i > 0)
sb.append(",");
sb.append(String.valueOf(values[i]));
}
sb.append("}");
@@ -119,7 +117,7 @@ public class VarInfo {
return v;
}
this.values = new VarInfo[n];
for ( int i=0; i<n; i++ ) {
for (int i = 0; i < n; i++) {
this.values[i] = (VarInfo) it.next();
this.values[i].isreferenced |= this.isreferenced;
}
@@ -128,17 +126,17 @@ public class VarInfo {
protected void collectUniqueValues(Set visitedBlocks, Set vars) {
BasicBlock b = pi.blocks[pc];
if ( pc == 0 )
if (pc == 0)
vars.add(pi.params[slot]);
for (int i = 0, n = b.prev != null ? b.prev.length : 0; i < n; i++) {
for (int i = 0, n = b.prev != null? b.prev.length: 0; i < n; i++) {
BasicBlock bp = b.prev[i];
if (!visitedBlocks.contains(bp)) {
visitedBlocks.add(bp);
VarInfo v = pi.vars[slot][bp.pc1];
if ( v != null )
if (v != null)
v.collectUniqueValues(visitedBlocks, vars);
}
}
}
}
}
}

View File

@@ -35,42 +35,42 @@ import org.luaj.vm2.lib.jse.CoerceJavaToLua;
* scripts using luaj.
*
* <p>
* This engine requires the types of the Bindings and ScriptContext to be
* compatible with the engine. For creating new client context use
* ScriptEngine.createContext() which will return {@link LuajContext},
* and for client bindings use the default engine scoped bindings or
* construct a {@link LuajBindings} directly.
* This engine requires the types of the Bindings and ScriptContext to be
* compatible with the engine. For creating new client context use
* ScriptEngine.createContext() which will return {@link LuajContext}, and for
* client bindings use the default engine scoped bindings or construct a
* {@link LuajBindings} directly.
*/
public class LuaScriptEngine extends AbstractScriptEngine 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.2";
private static final String __ARGV__ = "arg";
private static final String __FILENAME__ = "?";
private static final ScriptEngineFactory myFactory = new LuaScriptEngineFactory();
private LuajContext context;
public LuaScriptEngine() {
// set up context
context = new LuajContext();
context.setBindings(createBindings(), ScriptContext.ENGINE_SCOPE);
setContext(context);
// 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);
}
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.2";
private static final String __ARGV__ = "arg";
private static final String __FILENAME__ = "?";
private static final ScriptEngineFactory myFactory = new LuaScriptEngineFactory();
private LuajContext context;
public LuaScriptEngine() {
// set up context
context = new LuajContext();
context.setBindings(createBindings(), ScriptContext.ENGINE_SCOPE);
setContext(context);
// 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);
}
@Override
public CompiledScript compile(String script) throws ScriptException {
@@ -80,18 +80,18 @@ public class LuaScriptEngine extends AbstractScriptEngine implements ScriptEngin
@Override
public CompiledScript compile(Reader script) throws ScriptException {
try {
InputStream is = new Utf8Encoder(script);
try {
final Globals g = context.globals;
final LuaFunction f = g.load(script, "script").checkfunction();
return new LuajCompiledScript(f, g);
} catch ( LuaError lee ) {
throw new ScriptException(lee.getMessage() );
} finally {
InputStream is = new Utf8Encoder(script);
try {
final Globals g = context.globals;
final LuaFunction f = g.load(script, "script").checkfunction();
return new LuajCompiledScript(f, g);
} catch (LuaError lee) {
throw new ScriptException(lee.getMessage());
} finally {
is.close();
}
} catch ( Exception e ) {
throw new ScriptException("eval threw "+e.toString());
} catch (Exception e) {
throw new ScriptException("eval threw " + e.toString());
}
}
@@ -116,49 +116,43 @@ public class LuaScriptEngine extends AbstractScriptEngine implements ScriptEngin
}
@Override
public Object eval(String script, ScriptContext context)
throws ScriptException {
public Object eval(String script, ScriptContext context) throws ScriptException {
return eval(new StringReader(script), context);
}
@Override
public Object eval(Reader reader, ScriptContext context)
throws ScriptException {
return compile(reader).eval(context);
public Object eval(Reader reader, ScriptContext context) throws ScriptException {
return compile(reader).eval(context);
}
@Override
public ScriptEngineFactory getFactory() {
return myFactory;
}
public ScriptEngineFactory getFactory() { return myFactory; }
class LuajCompiledScript extends CompiledScript {
final LuaFunction function;
final Globals compiling_globals;
final Globals compiling_globals;
LuajCompiledScript(LuaFunction function, Globals compiling_globals) {
this.function = function;
this.compiling_globals = compiling_globals;
}
public ScriptEngine getEngine() {
return LuaScriptEngine.this;
public ScriptEngine getEngine() { return LuaScriptEngine.this; }
public Object eval() throws ScriptException {
return eval(getContext());
}
public Object eval() throws ScriptException {
return eval(getContext());
}
public Object eval(Bindings bindings) throws ScriptException {
return eval(((LuajContext) getContext()).globals, bindings);
}
public Object eval(ScriptContext context) throws ScriptException {
return eval(((LuajContext) context).globals, context.getBindings(ScriptContext.ENGINE_SCOPE));
public Object eval(Bindings bindings) throws ScriptException {
return eval(((LuajContext) getContext()).globals, bindings);
}
Object eval(Globals g, Bindings b) throws ScriptException {
g.setmetatable(new BindingsMetatable(b));
public Object eval(ScriptContext context) throws ScriptException {
return eval(((LuajContext) context).globals, context.getBindings(ScriptContext.ENGINE_SCOPE));
}
Object eval(Globals g, Bindings b) throws ScriptException {
g.setmetatable(new BindingsMetatable(b));
LuaFunction f = function;
if (f.isclosure())
f = new LuaClosure(f.checkclosure().p, g);
@@ -178,37 +172,37 @@ public class LuaScriptEngine extends AbstractScriptEngine implements ScriptEngin
private final class Utf8Encoder extends InputStream {
private final Reader r;
private final int[] buf = new int[2];
private int n;
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 )
if (n > 0)
return buf[--n];
int c = r.read();
if ( c < 0x80 )
if (c < 0x80)
return c;
n = 0;
if ( c < 0x800 ) {
buf[n++] = (0x80 | ( c & 0x3f));
return (0xC0 | ((c>>6) & 0x1f));
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));
buf[n++] = (0x80 | (c & 0x3f));
buf[n++] = (0x80 | ((c>>6) & 0x3f));
return (0xE0 | ((c>>12) & 0x0f));
}
}
}
static class BindingsMetatable extends LuaTable {
BindingsMetatable(final Bindings bindings) {
this.rawset(LuaValue.INDEX, new TwoArgFunction() {
public LuaValue call(LuaValue table, LuaValue key) {
if (key.isstring())
if (key.isstring())
return toLua(bindings.get(key.tojstring()));
else
return this.rawget(key);
@@ -231,33 +225,38 @@ public class LuaScriptEngine extends AbstractScriptEngine implements ScriptEngin
});
}
}
static private LuaValue toLua(Object javaValue) {
return javaValue == null? LuaValue.NIL:
javaValue instanceof LuaValue? (LuaValue) javaValue:
CoerceJavaToLua.coerce(javaValue);
return javaValue == null? LuaValue.NIL
: javaValue instanceof LuaValue? (LuaValue) javaValue: CoerceJavaToLua.coerce(javaValue);
}
static private Object toJava(LuaValue luajValue) {
switch ( luajValue.type() ) {
case LuaValue.TNIL: return null;
case LuaValue.TSTRING: return luajValue.tojstring();
case LuaValue.TUSERDATA: return luajValue.checkuserdata(Object.class);
case LuaValue.TNUMBER: return luajValue.isinttype()?
(Object) new Integer(luajValue.toint()):
(Object) new Double(luajValue.todouble());
default: return luajValue;
switch (luajValue.type()) {
case LuaValue.TNIL:
return null;
case LuaValue.TSTRING:
return luajValue.tojstring();
case LuaValue.TUSERDATA:
return luajValue.checkuserdata(Object.class);
case LuaValue.TNUMBER:
return luajValue.isinttype()? (Object) new Integer(luajValue.toint())
: (Object) new Double(luajValue.todouble());
default:
return luajValue;
}
}
static private Object toJava(Varargs v) {
final int n = v.narg();
switch (n) {
case 0: return null;
case 1: return toJava(v.arg1());
case 0:
return null;
case 1:
return toJava(v.arg1());
default:
Object[] o = new Object[n];
for (int i=0; i<n; ++i)
for (int i = 0; i < n; ++i)
o[i] = toJava(v.arg(i+1));
return o;
}

View File

@@ -30,99 +30,74 @@ import javax.script.ScriptEngineFactory;
/**
* Jsr 223 scripting engine factory.
*
* Exposes metadata to support the lua language, and constructs
* instances of LuaScriptEngine to handl lua scripts.
* Exposes metadata to support the lua language, and constructs instances of
* LuaScriptEngine to handl lua scripts.
*/
public class LuaScriptEngineFactory implements ScriptEngineFactory {
private static final String [] EXTENSIONS = {
"lua",
".lua",
};
private static final String [] MIMETYPES = {
"text/lua",
"application/lua"
};
private static final String [] NAMES = {
"lua",
"luaj",
};
private List<String> extensions;
private List<String> mimeTypes;
private List<String> names;
public LuaScriptEngineFactory() {
extensions = Arrays.asList(EXTENSIONS);
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 new LuaScriptEngine();
}
private static final String[] EXTENSIONS = { "lua", ".lua", };
private static final String[] MIMETYPES = { "text/lua", "application/lua" };
private static final String[] NAMES = { "lua", "luaj", };
private List<String> extensions;
private List<String> mimeTypes;
private List<String> names;
public LuaScriptEngineFactory() {
extensions = Arrays.asList(EXTENSIONS);
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 new LuaScriptEngine(); }
}

View File

@@ -35,9 +35,9 @@ import org.luaj.vm2.Globals;
import org.luaj.vm2.lib.jse.JsePlatform;
import org.luaj.vm2.luajc.LuaJC;
/**
* Context for LuaScriptEngine execution which maintains its own Globals,
* and manages the input and output redirection.
/**
* Context for LuaScriptEngine execution which maintains its own Globals, and
* manages the input and output redirection.
*/
public class LuajContext extends SimpleScriptContext implements ScriptContext {
@@ -50,93 +50,90 @@ public class LuajContext extends SimpleScriptContext implements ScriptContext {
private final PrintStream stdout;
/** The initial value of globals.STDERR */
private final PrintStream stderr;
/** Construct a LuajContext with its own globals which may
* be debug globals depending on the value of the system
* property 'org.luaj.debug'
/**
* Construct a LuajContext with its own globals which may be debug globals
* depending on the value of the system property 'org.luaj.debug'
* <p>
* If the system property 'org.luaj.debug' is set, the globals
* created will be a debug globals that includes the debug
* library. This may provide better stack traces, but may
* have negative impact on performance.
* If the system property 'org.luaj.debug' is set, the globals created will
* be a debug globals that includes the debug library. This may provide
* better stack traces, but may have negative impact on performance.
*/
public LuajContext() {
this("true".equals(System.getProperty("org.luaj.debug")),
"true".equals(System.getProperty("org.luaj.luajc")));
this("true".equals(System.getProperty("org.luaj.debug")), "true".equals(System.getProperty("org.luaj.luajc")));
}
/** Construct a LuajContext with its own globals, which
* which optionally are debug globals, and optionally use the
* luajc direct lua to java bytecode compiler.
/**
* Construct a LuajContext with its own globals, which which optionally are
* debug globals, and optionally use the luajc direct lua to java bytecode
* compiler.
* <p>
* If createDebugGlobals is set, the globals
* created will be a debug globals that includes the debug
* library. This may provide better stack traces, but may
* have negative impact on performance.
* @param createDebugGlobals true to create debug globals,
* false for standard globals.
* @param useLuaJCCompiler true to use the luajc compiler,
* reqwuires bcel to be on the class path.
* If createDebugGlobals is set, the globals created will be a debug globals
* that includes the debug library. This may provide better stack traces,
* but may have negative impact on performance.
*
* @param createDebugGlobals true to create debug globals, false for
* standard globals.
* @param useLuaJCCompiler true to use the luajc compiler, reqwuires bcel
* to be on the class path.
*/
public LuajContext(boolean createDebugGlobals, boolean useLuaJCCompiler) {
globals = createDebugGlobals?
JsePlatform.debugGlobals():
JsePlatform.standardGlobals();
if (useLuaJCCompiler)
LuaJC.install(globals);
stdin = globals.STDIN;
stdout = globals.STDOUT;
stderr = globals.STDERR;
}
@Override
public void setErrorWriter(Writer writer) {
globals.STDERR = writer != null?
new PrintStream(new WriterOutputStream(writer)):
stderr;
globals = createDebugGlobals? JsePlatform.debugGlobals(): JsePlatform.standardGlobals();
if (useLuaJCCompiler)
LuaJC.install(globals);
stdin = globals.STDIN;
stdout = globals.STDOUT;
stderr = globals.STDERR;
}
@Override
public void setReader(Reader reader) {
globals.STDIN = reader != null?
new ReaderInputStream(reader):
stdin;
public void setErrorWriter(Writer writer) {
globals.STDERR = writer != null? new PrintStream(new WriterOutputStream(writer)): stderr;
}
@Override
public void setReader(Reader reader) { globals.STDIN = reader != null? new ReaderInputStream(reader): stdin; }
@Override
public void setWriter(Writer writer) {
globals.STDOUT = writer != null?
new PrintStream(new WriterOutputStream(writer), true):
stdout;
globals.STDOUT = writer != null? new PrintStream(new WriterOutputStream(writer), true): stdout;
}
static final class WriterOutputStream extends OutputStream {
final Writer w;
WriterOutputStream(Writer w) {
this.w = w;
}
public void write(int b) throws IOException {
w.write(new String(new byte[] {(byte)b}));
w.write(new String(new byte[] { (byte) b }));
}
public void write(byte[] b, int o, int l) throws IOException {
w.write(new String(b, o, l));
}
public void write(byte[] b) throws IOException {
w.write(new String(b));
}
public void close() throws IOException {
w.close();
}
public void flush() throws IOException {
w.flush();
}
}
static final class ReaderInputStream extends InputStream {
final Reader r;
ReaderInputStream(Reader r) {
this.r = r;
}
public int read() throws IOException {
return r.read();
}

View File

@@ -31,13 +31,13 @@ import org.luaj.vm2.lib.jse.CoerceJavaToLua;
import org.luaj.vm2.lib.jse.JsePlatform;
/**
* Default {@link Launcher} instance that creates standard globals
* and runs the supplied scripts with chunk name 'main'.
* Default {@link Launcher} instance that creates standard globals and runs the
* supplied scripts with chunk name 'main'.
* <P>
* Arguments are coerced into lua using {@link CoerceJavaToLua#coerce(Object)}.
* <P>
* Return values with simple types are coerced into Java simple types.
* Tables, threads, and functions are returned as lua objects.
* Return values with simple types are coerced into Java simple types. Tables,
* threads, and functions are returned as lua objects.
*
* @see Launcher
* @see LuajClassLoader
@@ -51,13 +51,15 @@ public class DefaultLauncher implements Launcher {
public DefaultLauncher() {
g = JsePlatform.standardGlobals();
}
/** Launches the script with chunk name 'main' */
public Object[] launch(String script, Object[] arg) {
return launchChunk(g.load(script, "main"), arg);
}
/** Launches the script with chunk name 'main' and loading using modes 'bt' */
/**
* Launches the script with chunk name 'main' and loading using modes 'bt'
*/
public Object[] launch(InputStream script, Object[] arg) {
return launchChunk(g.load(script, "main", "bt", g), arg);
}
@@ -102,4 +104,4 @@ public class DefaultLauncher implements Launcher {
}
return return_values;
}
}
}

View File

@@ -24,16 +24,19 @@ package org.luaj.vm2.server;
import java.io.InputStream;
import java.io.Reader;
/** Interface to launch lua scripts using the {@link LuajClassLoader}.
/**
* Interface to launch lua scripts using the {@link LuajClassLoader}.
* <P>
* <em>Note: This class is experimental and subject to change in future versions.</em>
* <em>Note: This class is experimental and subject to change in future
* versions.</em>
* <P>
* This interface is purposely genericized to defer class loading so that
* luaj classes can come from the class loader.
* This interface is purposely genericized to defer class loading so that luaj
* classes can come from the class loader.
* <P>
* The implementation should be acquired using {@link LuajClassLoader#NewLauncher()}
* or {@link LuajClassLoader#NewLauncher(Class)} which ensure that the classes are
* loaded to give each Launcher instance a pristine set of Globals, including
* The implementation should be acquired using
* {@link LuajClassLoader#NewLauncher()} or
* {@link LuajClassLoader#NewLauncher(Class)} which ensure that the classes are
* loaded to give each Launcher instance a pristine set of Globals, including
* the shared metatables.
*
* @see LuajClassLoader
@@ -43,28 +46,31 @@ import java.io.Reader;
* @since luaj 3.0.1
*/
public interface Launcher {
/** Launch a script contained in a String.
/**
* Launch a script contained in a String.
*
* @param script The script contents.
* @param arg Optional arguments supplied to the script.
* @param script The script contents.
* @param arg Optional arguments supplied to the script.
* @return return values from the script.
*/
public Object[] launch(String script, Object[] arg);
public Object[] launch(String script, Object[] arg);
/** Launch a script from an InputStream.
/**
* Launch a script from an InputStream.
*
* @param script The script as an InputStream.
* @param arg Optional arguments supplied to the script.
* @param script The script as an InputStream.
* @param arg Optional arguments supplied to the script.
* @return return values from the script.
*/
public Object[] launch(InputStream script, Object[] arg);
public Object[] launch(InputStream script, Object[] arg);
/** Launch a script from a Reader.
/**
* Launch a script from a Reader.
*
* @param script The script as a Reader.
* @param arg Optional arguments supplied to the script.
* @param script The script as a Reader.
* @param arg Optional arguments supplied to the script.
* @return return values from the script.
*/
public Object[] launch(Reader script, Object[] arg);
}
}

View File

@@ -28,16 +28,16 @@ import java.util.Map;
/**
* Class loader that can be used to launch a lua script in a Java VM that has a
* unique set of classes for org.luaj classes.
* unique set of classes for org.luaj classes.
* <P>
* <em>Note: This class is experimental and subject to change in future versions.</em>
* <em>Note: This class is experimental and subject to change in future
* versions.</em>
* <P>
* By using a custom class loader per script, it allows the script to have
* its own set of globals, including static values such as shared metatables
* that cannot access lua values from other scripts because their classes are
* loaded from different class loaders. Thus normally unsafe libraries such
* as luajava can be exposed to scripts in a server environment using these
* techniques.
* By using a custom class loader per script, it allows the script to have its
* own set of globals, including static values such as shared metatables that
* cannot access lua values from other scripts because their classes are loaded
* from different class loaders. Thus normally unsafe libraries such as luajava
* can be exposed to scripts in a server environment using these techniques.
* <P>
* All classes in the package "org.luaj.vm2." are considered user classes, and
* loaded into this class loader from their bytes in the class path. Other
@@ -61,10 +61,14 @@ import java.util.Map;
*/
public class LuajClassLoader extends ClassLoader {
/** String describing the luaj packages to consider part of the user classes */
/**
* String describing the luaj packages to consider part of the user classes
*/
static final String luajPackageRoot = "org.luaj.vm2.";
/** String describing the Launcher interface to be considered a system class */
/**
* String describing the Launcher interface to be considered a system class
*/
static final String launcherInterfaceRoot = Launcher.class.getName();
/** Local cache of classes loaded by this loader. */
@@ -75,54 +79,52 @@ public class LuajClassLoader extends ClassLoader {
* its own {@link LuajClassLoader} using the default implementation class
* {@link DefaultLauncher}.
* <P>
* The {@link Launcher} that is returned will be a pristine luaj vm
* whose classes are loaded into this loader including static variables
* such as shared metatables, and should not be able to directly access
* variables from other Launcher instances.
* The {@link Launcher} that is returned will be a pristine luaj vm whose
* classes are loaded into this loader including static variables such as
* shared metatables, and should not be able to directly access variables
* from other Launcher instances.
*
* @return {@link Launcher} instance that can be used to launch scripts.
* @throws InstantiationException
* @throws IllegalAccessException
* @throws ClassNotFoundException
*/
public static Launcher NewLauncher() throws InstantiationException,
IllegalAccessException, ClassNotFoundException {
public static Launcher NewLauncher() throws InstantiationException, IllegalAccessException, ClassNotFoundException {
return NewLauncher(DefaultLauncher.class);
}
/**
* Construct a {@link Launcher} instance that will load classes in
* its own {@link LuajClassLoader} using a user-supplied implementation class
* that implements {@link Launcher}.
* Construct a {@link Launcher} instance that will load classes in its own
* {@link LuajClassLoader} using a user-supplied implementation class that
* implements {@link Launcher}.
* <P>
* The {@link Launcher} that is returned will be a pristine luaj vm
* whose classes are loaded into this loader including static variables
* such as shared metatables, and should not be able to directly access
* variables from other Launcher instances.
* The {@link Launcher} that is returned will be a pristine luaj vm whose
* classes are loaded into this loader including static variables such as
* shared metatables, and should not be able to directly access variables
* from other Launcher instances.
*
* @return instance of type 'launcher_class' that can be used to launch scripts.
* @return instance of type 'launcher_class' that can be used to launch
* scripts.
* @throws InstantiationException
* @throws IllegalAccessException
* @throws ClassNotFoundException
*/
public static Launcher NewLauncher(Class<? extends Launcher> launcher_class)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
final LuajClassLoader loader = new LuajClassLoader();
final Object instance = loader.loadAsUserClass(launcher_class.getName())
.newInstance();
final Object instance = loader.loadAsUserClass(launcher_class.getName()).newInstance();
return (Launcher) instance;
}
/**
* Test if a class name should be considered a user class and loaded
* by this loader, or a system class and loaded by the system loader.
* Test if a class name should be considered a user class and loaded by this
* loader, or a system class and loaded by the system loader.
*
* @param classname Class name to test.
* @return true if this should be loaded into this class loader.
*/
public static boolean isUserClass(String classname) {
return classname.startsWith(luajPackageRoot)
&& !classname.startsWith(launcherInterfaceRoot);
return classname.startsWith(luajPackageRoot) && !classname.startsWith(launcherInterfaceRoot);
}
public Class<?> loadClass(String classname) throws ClassNotFoundException {
@@ -143,13 +145,11 @@ public class LuajClassLoader extends ClassLoader {
for (int n = 0; (n = is.read(b)) >= 0;)
baos.write(b, 0, n);
byte[] bytes = baos.toByteArray();
Class<?> result = super.defineClass(classname, bytes, 0,
bytes.length);
Class<?> result = super.defineClass(classname, bytes, 0, bytes.length);
classes.put(classname, result);
return result;
} catch (java.io.IOException e) {
throw new ClassNotFoundException("Read failed: " + classname
+ ": " + e);
throw new ClassNotFoundException("Read failed: " + classname + ": " + e);
}
}
throw new ClassNotFoundException("Not found: " + classname);