Merge remote-tracking branch 'farmboy0/master'
This commit is contained in:
77
luaj-jse/pom.xml
Normal file
77
luaj-jse/pom.xml
Normal file
@@ -0,0 +1,77 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.luaj</groupId>
|
||||
<artifactId>luaj-parent</artifactId>
|
||||
<version>3.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>luaj-jse</artifactId>
|
||||
|
||||
<name>luaj-jse</name>
|
||||
<description>LuaJ for Java SE</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.luaj</groupId>
|
||||
<artifactId>luaj-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.bcel</groupId>
|
||||
<artifactId>bcel</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.helger.maven</groupId>
|
||||
<artifactId>ph-javacc-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>generate-grammar</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>javacc</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<jdkVersion>1.8</jdkVersion>
|
||||
<javadocFriendlyComments>true</javadocFriendlyComments>
|
||||
<packageName>org.luaj.vm2.parser</packageName>
|
||||
<sourceDirectory>src/main/javacc</sourceDirectory>
|
||||
<outputDirectory>${project.build.directory}/generated-sources/javacc</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-source</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>add-source</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>${project.build.directory}/generated-sources/javacc</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
233
luaj-jse/src/main/java/lua.java
Normal file
233
luaj-jse/src/main/java/lua.java
Normal file
@@ -0,0 +1,233 @@
|
||||
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2012 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Vector;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Print;
|
||||
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 void usageExit() {
|
||||
System.out.println(usage);
|
||||
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 {
|
||||
|
||||
// process args
|
||||
boolean interactive = args.length == 0;
|
||||
boolean versioninfo = false;
|
||||
boolean processing = true;
|
||||
boolean nodebug = false;
|
||||
boolean luajc = false;
|
||||
Vector libs = null;
|
||||
try {
|
||||
// stateful argument processing
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (!processing || !args[i].startsWith("-")) {
|
||||
// input file - defer to last stage
|
||||
break;
|
||||
} else if (args[i].length() <= 1) {
|
||||
// input file - defer to last stage
|
||||
break;
|
||||
} else {
|
||||
switch (args[i].charAt(1)) {
|
||||
case 'e':
|
||||
if (++i >= args.length)
|
||||
usageExit();
|
||||
// input script - defer to last stage
|
||||
break;
|
||||
case 'b':
|
||||
luajc = true;
|
||||
break;
|
||||
case 'l':
|
||||
if (++i >= args.length)
|
||||
usageExit();
|
||||
libs = libs != null? libs: new Vector();
|
||||
libs.addElement(args[i]);
|
||||
break;
|
||||
case 'i':
|
||||
interactive = true;
|
||||
break;
|
||||
case 'v':
|
||||
versioninfo = true;
|
||||
break;
|
||||
case 'n':
|
||||
nodebug = true;
|
||||
break;
|
||||
case 'p':
|
||||
print = true;
|
||||
break;
|
||||
case 'c':
|
||||
if (++i >= args.length)
|
||||
usageExit();
|
||||
encoding = args[i];
|
||||
break;
|
||||
case '-':
|
||||
if (args[i].length() > 2)
|
||||
usageExit();
|
||||
processing = false;
|
||||
break;
|
||||
default:
|
||||
usageExit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// echo version
|
||||
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));
|
||||
|
||||
// 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);
|
||||
break;
|
||||
} else if ("-".equals(args[i])) {
|
||||
processScript(System.in, "=stdin", args, i);
|
||||
break;
|
||||
} else {
|
||||
switch (args[i].charAt(1)) {
|
||||
case 'l':
|
||||
case 'c':
|
||||
++i;
|
||||
break;
|
||||
case 'e':
|
||||
++i;
|
||||
processScript(new ByteArrayInputStream(args[i].getBytes()), "string", args, i);
|
||||
break;
|
||||
case '-':
|
||||
processing = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (interactive)
|
||||
interactiveMode();
|
||||
|
||||
} catch (IOException ioe) {
|
||||
System.err.println(ioe.toString());
|
||||
System.exit(-2);
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadLibrary(String libname) throws IOException {
|
||||
LuaValue slibname = LuaValue.valueOf(libname);
|
||||
try {
|
||||
// load via plain require
|
||||
globals.get("require").call(slibname);
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
// load as java class
|
||||
LuaValue v = (LuaValue) Class.forName(libname).newInstance();
|
||||
v.call(slibname, globals);
|
||||
} 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 {
|
||||
try {
|
||||
LuaValue c;
|
||||
try {
|
||||
script = new BufferedInputStream(script);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
private static Varargs setGlobalArg(String chunkname, String[] args, int i, LuaValue globals) {
|
||||
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]));
|
||||
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));
|
||||
while ( true ) {
|
||||
System.out.print("> ");
|
||||
System.out.flush();
|
||||
String line = reader.readLine();
|
||||
if (line == null)
|
||||
return;
|
||||
processScript(new ByteArrayInputStream(line.getBytes()), "=stdin", null, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
185
luaj-jse/src/main/java/luac.java
Normal file
185
luaj-jse/src/main/java/luac.java
Normal file
@@ -0,0 +1,185 @@
|
||||
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.Print;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.compiler.DumpState;
|
||||
import org.luaj.vm2.lib.jse.JsePlatform;
|
||||
|
||||
/**
|
||||
* 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 void usageExit() {
|
||||
System.out.println(usage);
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
private boolean list = false;
|
||||
private String output = "luac.out";
|
||||
private boolean parseonly = false;
|
||||
private boolean stripdebug = false;
|
||||
private boolean littleendian = false;
|
||||
private int numberformat = DumpState.NUMBER_FORMAT_DEFAULT;
|
||||
private boolean versioninfo = false;
|
||||
private boolean processing = true;
|
||||
private String encoding = null;
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
new luac(args);
|
||||
}
|
||||
|
||||
private luac(String[] args) throws IOException {
|
||||
|
||||
// process args
|
||||
try {
|
||||
// get stateful args
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (!processing || !args[i].startsWith("-")) {
|
||||
// input file - defer to next stage
|
||||
} else if (args[i].length() <= 1) {
|
||||
// input file - defer to next stage
|
||||
} else {
|
||||
switch (args[i].charAt(1)) {
|
||||
case 'l':
|
||||
list = true;
|
||||
break;
|
||||
case 'o':
|
||||
if (++i >= args.length)
|
||||
usageExit();
|
||||
output = args[i];
|
||||
break;
|
||||
case 'p':
|
||||
parseonly = true;
|
||||
break;
|
||||
case 's':
|
||||
stripdebug = true;
|
||||
break;
|
||||
case 'e':
|
||||
littleendian = true;
|
||||
break;
|
||||
case 'i':
|
||||
if (args[i].length() <= 2)
|
||||
usageExit();
|
||||
numberformat = Integer.parseInt(args[i].substring(2));
|
||||
break;
|
||||
case 'v':
|
||||
versioninfo = true;
|
||||
break;
|
||||
case 'c':
|
||||
if (++i >= args.length)
|
||||
usageExit();
|
||||
encoding = args[i];
|
||||
break;
|
||||
case '-':
|
||||
if (args[i].length() > 2)
|
||||
usageExit();
|
||||
processing = false;
|
||||
break;
|
||||
default:
|
||||
usageExit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// echo version
|
||||
if (versioninfo)
|
||||
System.out.println(version);
|
||||
|
||||
// open output file
|
||||
// process input files
|
||||
try (OutputStream fos = new FileOutputStream(output)) {
|
||||
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);
|
||||
} else {
|
||||
switch (args[i].charAt(1)) {
|
||||
case 'o':
|
||||
case 'c':
|
||||
++i;
|
||||
break;
|
||||
case '-':
|
||||
processing = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (IOException ioe) {
|
||||
System.err.println(ioe.toString());
|
||||
System.exit(-2);
|
||||
}
|
||||
}
|
||||
|
||||
private void processScript(Globals globals, InputStream script, String chunkname, OutputStream out)
|
||||
throws IOException {
|
||||
try {
|
||||
// create the chunk
|
||||
script = new BufferedInputStream(script);
|
||||
Prototype chunk = encoding != null
|
||||
? globals.compilePrototype(new InputStreamReader(script, encoding), chunkname)
|
||||
: globals.compilePrototype(script, chunkname);
|
||||
|
||||
// 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);
|
||||
} finally {
|
||||
script.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
270
luaj-jse/src/main/java/luajc.java
Normal file
270
luaj-jse/src/main/java/luajc.java
Normal file
@@ -0,0 +1,270 @@
|
||||
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2012 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.Lua;
|
||||
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.
|
||||
*/
|
||||
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 void usageExit() {
|
||||
System.out.println(usage);
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
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 final List files = new ArrayList();
|
||||
private final Globals globals;
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
new luajc(args);
|
||||
}
|
||||
|
||||
private luajc(String[] args) throws IOException {
|
||||
|
||||
// process args
|
||||
List seeds = new ArrayList();
|
||||
|
||||
// get stateful args
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (!args[i].startsWith("-")) {
|
||||
seeds.add(args[i]);
|
||||
} else {
|
||||
switch (args[i].charAt(1)) {
|
||||
case 's':
|
||||
if (++i >= args.length)
|
||||
usageExit();
|
||||
srcdir = args[i];
|
||||
break;
|
||||
case 'd':
|
||||
if (++i >= args.length)
|
||||
usageExit();
|
||||
destdir = args[i];
|
||||
break;
|
||||
case 'l':
|
||||
loadclasses = true;
|
||||
break;
|
||||
case 'p':
|
||||
if (++i >= args.length)
|
||||
usageExit();
|
||||
pkgprefix = args[i];
|
||||
break;
|
||||
case 'm':
|
||||
genmain = true;
|
||||
break;
|
||||
case 'r':
|
||||
recurse = true;
|
||||
break;
|
||||
case 'c':
|
||||
if (++i >= args.length)
|
||||
usageExit();
|
||||
encoding = args[i];
|
||||
break;
|
||||
case 'v':
|
||||
verbose = true;
|
||||
break;
|
||||
default:
|
||||
usageExit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// echo version
|
||||
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);
|
||||
}
|
||||
|
||||
// need at least one seed
|
||||
if (seeds.size() <= 0) {
|
||||
System.err.println(usage);
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
// collect up files to process
|
||||
for (Object seed : seeds)
|
||||
collectFiles(srcdir + "/" + seed);
|
||||
|
||||
// check for at least one file
|
||||
if (files.size() <= 0) {
|
||||
System.err.println("no files found in " + seeds);
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
// process input files
|
||||
globals = JsePlatform.standardGlobals();
|
||||
for (Object file : files)
|
||||
processFile((InputFile) file);
|
||||
}
|
||||
|
||||
private void collectFiles(String path) {
|
||||
File f = new File(path);
|
||||
if (f.isDirectory() && recurse)
|
||||
scandir(f, pkgprefix);
|
||||
else if (f.isFile()) {
|
||||
File dir = f.getAbsoluteFile().getParentFile();
|
||||
if (dir != null)
|
||||
scanfile(dir, f, pkgprefix);
|
||||
}
|
||||
}
|
||||
|
||||
private void scandir(File dir, String javapackage) {
|
||||
File[] f = dir.listFiles();
|
||||
for (File element : f)
|
||||
scanfile(dir, element, 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));
|
||||
}
|
||||
}
|
||||
|
||||
private static final class LocalClassLoader extends ClassLoader {
|
||||
private final Hashtable t;
|
||||
|
||||
private LocalClassLoader(Hashtable t) {
|
||||
this.t = t;
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
class InputFile {
|
||||
public String luachunkname;
|
||||
public String srcfilename;
|
||||
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;
|
||||
this.javapackage = javapackage;
|
||||
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) {
|
||||
inf.outdir.mkdirs();
|
||||
try {
|
||||
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);
|
||||
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) {
|
||||
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);
|
||||
System.err.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
42
luaj-jse/src/main/java/org/luaj/vm2/ast/Block.java
Normal file
42
luaj-jse/src/main/java/org/luaj/vm2/ast/Block.java
Normal file
@@ -0,0 +1,42 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Block extends Stat {
|
||||
|
||||
public List<Stat> stats = new ArrayList<>();
|
||||
public NameScope scope;
|
||||
|
||||
public void add(Stat s) {
|
||||
if (s == null)
|
||||
return;
|
||||
stats.add(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
34
luaj-jse/src/main/java/org/luaj/vm2/ast/Chunk.java
Normal file
34
luaj-jse/src/main/java/org/luaj/vm2/ast/Chunk.java
Normal file
@@ -0,0 +1,34 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
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);
|
||||
}
|
||||
}
|
||||
362
luaj-jse/src/main/java/org/luaj/vm2/ast/Exp.java
Normal file
362
luaj-jse/src/main/java/org/luaj/vm2/ast/Exp.java
Normal file
@@ -0,0 +1,362 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.ast;
|
||||
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
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 varargs() {
|
||||
return new VarargsExp();
|
||||
}
|
||||
|
||||
public static Exp tableconstructor(TableConstructor tc) {
|
||||
return tc;
|
||||
}
|
||||
|
||||
public static Exp unaryexp(int op, Exp rhs) {
|
||||
if (rhs instanceof BinopExp) {
|
||||
BinopExp b = (BinopExp) 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) {
|
||||
UnopExp u = (UnopExp) lhs;
|
||||
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) {
|
||||
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 (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);
|
||||
}
|
||||
return new BinopExp(lhs, op, rhs);
|
||||
}
|
||||
|
||||
static boolean isrightassoc(int op) {
|
||||
switch (op) {
|
||||
case Lua.OP_CONCAT:
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
public static Exp anonymousfunction(FuncBody funcbody) {
|
||||
return new AnonFuncDef(funcbody);
|
||||
}
|
||||
|
||||
/** foo */
|
||||
public static NameExp nameprefix(String name) {
|
||||
return new NameExp(name);
|
||||
}
|
||||
|
||||
/** ( foo.bar ) */
|
||||
public static ParensExp parensprefix(Exp exp) {
|
||||
return new ParensExp(exp);
|
||||
}
|
||||
|
||||
/** foo[exp] */
|
||||
public static IndexExp indexop(PrimaryExp lhs, Exp exp) {
|
||||
return new IndexExp(lhs, exp);
|
||||
}
|
||||
|
||||
/** foo.bar */
|
||||
public static FieldExp fieldop(PrimaryExp lhs, String name) {
|
||||
return new FieldExp(lhs, name);
|
||||
}
|
||||
|
||||
/** foo(2,3) */
|
||||
public static FuncCall functionop(PrimaryExp lhs, FuncArgs args) {
|
||||
return new FuncCall(lhs, args);
|
||||
}
|
||||
|
||||
/** foo:bar(4,5) */
|
||||
public static MethodCall methodop(PrimaryExp lhs, String name, FuncArgs args) {
|
||||
return new MethodCall(lhs, name, args);
|
||||
}
|
||||
|
||||
public boolean isvarexp() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isfunccall() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isvarargexp() {
|
||||
return false;
|
||||
}
|
||||
|
||||
abstract public static class PrimaryExp extends Exp {
|
||||
@Override
|
||||
public boolean isvarexp() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isfunccall() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
abstract public static class VarExp extends PrimaryExp {
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markHasAssignment() {
|
||||
name.variable.hasassignments = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class FieldExp extends VarExp {
|
||||
public final PrimaryExp lhs;
|
||||
public final Name name;
|
||||
|
||||
public FieldExp(PrimaryExp lhs, String name) {
|
||||
this.lhs = lhs;
|
||||
this.name = new Name(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class IndexExp extends VarExp {
|
||||
public final PrimaryExp lhs;
|
||||
public final Exp exp;
|
||||
|
||||
public IndexExp(PrimaryExp lhs, Exp exp) {
|
||||
this.lhs = lhs;
|
||||
this.exp = exp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class FuncCall extends PrimaryExp {
|
||||
public final PrimaryExp lhs;
|
||||
public final FuncArgs args;
|
||||
|
||||
public FuncCall(PrimaryExp lhs, FuncArgs args) {
|
||||
this.lhs = lhs;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isfunccall() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isfunccall() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Constant extends Exp {
|
||||
public final LuaValue value;
|
||||
|
||||
public Constant(LuaValue value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class VarargsExp extends Exp {
|
||||
|
||||
@Override
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class BinopExp extends Exp {
|
||||
public final Exp lhs, rhs;
|
||||
public final int op;
|
||||
|
||||
public BinopExp(Exp lhs, int op, Exp rhs) {
|
||||
this.lhs = lhs;
|
||||
this.op = op;
|
||||
this.rhs = rhs;
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
66
luaj-jse/src/main/java/org/luaj/vm2/ast/FuncArgs.java
Normal file
66
luaj-jse/src/main/java/org/luaj/vm2/ast/FuncArgs.java
Normal file
@@ -0,0 +1,66 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/** {...} */
|
||||
public static FuncArgs tableconstructor(TableConstructor table) {
|
||||
return new FuncArgs(table);
|
||||
}
|
||||
|
||||
/** "mylib" */
|
||||
public static FuncArgs string(LuaString string) {
|
||||
return new FuncArgs(string);
|
||||
}
|
||||
|
||||
public FuncArgs(List<Exp> exps) {
|
||||
this.exps = exps;
|
||||
}
|
||||
|
||||
public FuncArgs(LuaString string) {
|
||||
this.exps = new ArrayList<>();
|
||||
this.exps.add(Exp.constant(string));
|
||||
}
|
||||
|
||||
public FuncArgs(TableConstructor table) {
|
||||
this.exps = new ArrayList<>();
|
||||
this.exps.add(table);
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
}
|
||||
37
luaj-jse/src/main/java/org/luaj/vm2/ast/FuncBody.java
Normal file
37
luaj-jse/src/main/java/org/luaj/vm2/ast/FuncBody.java
Normal file
@@ -0,0 +1,37 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.ast;
|
||||
|
||||
public class FuncBody extends SyntaxElement {
|
||||
public ParList parlist;
|
||||
public Block block;
|
||||
public NameScope scope;
|
||||
|
||||
public FuncBody(ParList parlist, Block block) {
|
||||
this.parlist = parlist != null? parlist: ParList.EMPTY_PARLIST;
|
||||
this.block = block;
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
49
luaj-jse/src/main/java/org/luaj/vm2/ast/FuncName.java
Normal file
49
luaj-jse/src/main/java/org/luaj/vm2/ast/FuncName.java
Normal file
@@ -0,0 +1,49 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
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) {
|
||||
this.name = new Name(name);
|
||||
}
|
||||
|
||||
public void adddot(String dot) {
|
||||
if (dots == null)
|
||||
dots = new ArrayList<>();
|
||||
dots.add(dot);
|
||||
}
|
||||
|
||||
}
|
||||
31
luaj-jse/src/main/java/org/luaj/vm2/ast/Name.java
Normal file
31
luaj-jse/src/main/java/org/luaj/vm2/ast/Name.java
Normal file
@@ -0,0 +1,31 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.ast;
|
||||
|
||||
public class Name {
|
||||
public final String name;
|
||||
public Variable variable;
|
||||
|
||||
public Name(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
139
luaj-jse/src/main/java/org/luaj/vm2/ast/NameResolver.java
Normal file
139
luaj-jse/src/main/java/org/luaj/vm2/ast/NameResolver.java
Normal file
@@ -0,0 +1,139 @@
|
||||
package org.luaj.vm2.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.ast.Exp.Constant;
|
||||
import org.luaj.vm2.ast.Exp.NameExp;
|
||||
import org.luaj.vm2.ast.Exp.VarExp;
|
||||
import org.luaj.vm2.ast.Stat.Assign;
|
||||
import org.luaj.vm2.ast.Stat.FuncDef;
|
||||
import org.luaj.vm2.ast.Stat.GenericFor;
|
||||
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.
|
||||
*/
|
||||
public class NameResolver extends Visitor {
|
||||
|
||||
private NameScope scope = null;
|
||||
|
||||
private void pushScope() {
|
||||
scope = new NameScope(scope);
|
||||
}
|
||||
|
||||
private void popScope() {
|
||||
scope = scope.outerScope;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NameScope scope) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Block block) {
|
||||
pushScope();
|
||||
block.scope = scope;
|
||||
super.visit(block);
|
||||
popScope();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(FuncBody body) {
|
||||
pushScope();
|
||||
scope.functionNestingCount++;
|
||||
body.scope = scope;
|
||||
super.visit(body);
|
||||
popScope();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(LocalFuncDef stat) {
|
||||
defineLocalVar(stat.name);
|
||||
super.visit(stat);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NumericFor stat) {
|
||||
pushScope();
|
||||
stat.scope = scope;
|
||||
defineLocalVar(stat.name);
|
||||
super.visit(stat);
|
||||
popScope();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(GenericFor stat) {
|
||||
pushScope();
|
||||
stat.scope = scope;
|
||||
defineLocalVars(stat.names);
|
||||
super.visit(stat);
|
||||
popScope();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NameExp exp) {
|
||||
exp.name.variable = resolveNameReference(exp.name);
|
||||
super.visit(exp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(FuncDef stat) {
|
||||
stat.name.name.variable = resolveNameReference(stat.name.name);
|
||||
stat.name.name.variable.hasassignments = true;
|
||||
super.visit(stat);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Assign stat) {
|
||||
super.visit(stat);
|
||||
for (VarExp element : stat.vars) {
|
||||
VarExp v = element;
|
||||
v.markHasAssignment();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(LocalAssign stat) {
|
||||
visitExps(stat.values);
|
||||
defineLocalVars(stat.names);
|
||||
int n = stat.names.size();
|
||||
int m = stat.values != null? stat.values.size(): 0;
|
||||
boolean isvarlist = m > 0 && m < n && 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)
|
||||
stat.names.get(i).variable.initialValue = ((Constant) stat.values.get(i)).value;
|
||||
if (!isvarlist)
|
||||
for (int i = m; i < n; i++)
|
||||
stat.names.get(i).variable.initialValue = LuaValue.NIL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ParList pars) {
|
||||
if (pars.names != null)
|
||||
defineLocalVars(pars.names);
|
||||
if (pars.isvararg)
|
||||
scope.define("arg");
|
||||
super.visit(pars);
|
||||
}
|
||||
|
||||
protected void defineLocalVars(List<Name> names) {
|
||||
for (Name name : names)
|
||||
defineLocalVar(name);
|
||||
}
|
||||
|
||||
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)
|
||||
v.isupvalue = true;
|
||||
return v;
|
||||
}
|
||||
}
|
||||
87
luaj-jse/src/main/java/org/luaj/vm2/ast/NameScope.java
Normal file
87
luaj-jse/src/main/java/org/luaj/vm2/ast/NameScope.java
Normal file
@@ -0,0 +1,87 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.ast;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class NameScope {
|
||||
|
||||
private static final Set<String> LUA_KEYWORDS = new HashSet<>();
|
||||
|
||||
static {
|
||||
String[] k = { "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if", "in", "local",
|
||||
"nil", "not", "or", "repeat", "return", "then", "true", "until", "while" };
|
||||
for (String element : k)
|
||||
LUA_KEYWORDS.add(element);
|
||||
}
|
||||
|
||||
public final Map<String, Variable> namedVariables = new HashMap<>();
|
||||
|
||||
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 */
|
||||
public NameScope(NameScope outerScope) {
|
||||
this.outerScope = outerScope;
|
||||
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 {
|
||||
validateIsNotKeyword(name);
|
||||
for (NameScope n = this; n != null; n = n.outerScope)
|
||||
if (n.namedVariables.containsKey(name))
|
||||
return 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 {
|
||||
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 + "'");
|
||||
}
|
||||
}
|
||||
42
luaj-jse/src/main/java/org/luaj/vm2/ast/ParList.java
Normal file
42
luaj-jse/src/main/java/org/luaj/vm2/ast/ParList.java
Normal file
@@ -0,0 +1,42 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ParList extends SyntaxElement {
|
||||
public static final List<Name> EMPTY_NAMELIST = new ArrayList<>();
|
||||
public static final ParList EMPTY_PARLIST = new ParList(EMPTY_NAMELIST, false);
|
||||
|
||||
public final List<Name> names;
|
||||
public final boolean isvararg;
|
||||
|
||||
public ParList(List<Name> names, boolean isvararg) {
|
||||
this.names = names;
|
||||
this.isvararg = isvararg;
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
307
luaj-jse/src/main/java/org/luaj/vm2/ast/Stat.java
Normal file
307
luaj-jse/src/main/java/org/luaj/vm2/ast/Stat.java
Normal file
@@ -0,0 +1,307 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.luaj.vm2.ast.Exp.VarExp;
|
||||
|
||||
abstract public class Stat extends SyntaxElement {
|
||||
public abstract void accept(Visitor visitor);
|
||||
|
||||
public static Stat block(Block block) {
|
||||
return block;
|
||||
}
|
||||
|
||||
public static Stat whiledo(Exp exp, Block block) {
|
||||
return new WhileDo(exp, block);
|
||||
}
|
||||
|
||||
public static Stat repeatuntil(Block block, Exp exp) {
|
||||
return new RepeatUntil(block, exp);
|
||||
}
|
||||
|
||||
public static Stat breakstat() {
|
||||
return new Break();
|
||||
}
|
||||
|
||||
public static Stat returnstat(List<Exp> exps) {
|
||||
return new Return(exps);
|
||||
}
|
||||
|
||||
public static Stat assignment(List<VarExp> vars, List<Exp> exps) {
|
||||
return new Assign(vars, exps);
|
||||
}
|
||||
|
||||
public static Stat functioncall(Exp.FuncCall funccall) {
|
||||
return new FuncCallStat(funccall);
|
||||
}
|
||||
|
||||
public static Stat localfunctiondef(String name, FuncBody funcbody) {
|
||||
return new LocalFuncDef(name, funcbody);
|
||||
}
|
||||
|
||||
public static Stat fornumeric(String name, Exp initial, Exp limit, Exp step, Block block) {
|
||||
return new NumericFor(name, initial, limit, step, block);
|
||||
}
|
||||
|
||||
public static Stat functiondef(FuncName funcname, FuncBody funcbody) {
|
||||
return new FuncDef(funcname, funcbody);
|
||||
}
|
||||
|
||||
public static Stat forgeneric(List<Name> names, List<Exp> exps, Block 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) {
|
||||
return new IfThenElse(ifexp, ifblock, elseifexps, elseifblocks, elseblock);
|
||||
}
|
||||
|
||||
public static Stat gotostat(String name) {
|
||||
return new Goto(name);
|
||||
}
|
||||
|
||||
public static Stat labelstat(String name) {
|
||||
return new Label(name);
|
||||
}
|
||||
|
||||
public static class Goto extends Stat {
|
||||
public final String name;
|
||||
|
||||
public Goto(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Label extends Stat {
|
||||
public final String name;
|
||||
|
||||
public Label(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Assign extends Stat {
|
||||
public final List<VarExp> vars;
|
||||
public final List<Exp> exps;
|
||||
|
||||
public Assign(List<VarExp> vars, List<Exp> exps) {
|
||||
this.vars = vars;
|
||||
this.exps = exps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class WhileDo extends Stat {
|
||||
public final Exp exp;
|
||||
public final Block block;
|
||||
|
||||
public WhileDo(Exp exp, Block block) {
|
||||
this.exp = exp;
|
||||
this.block = block;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class RepeatUntil extends Stat {
|
||||
public final Block block;
|
||||
public final Exp exp;
|
||||
|
||||
public RepeatUntil(Block block, Exp exp) {
|
||||
this.block = block;
|
||||
this.exp = exp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Break extends Stat {
|
||||
@Override
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Return extends Stat {
|
||||
public final List<Exp> values;
|
||||
|
||||
public Return(List<Exp> values) {
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
public int nreturns() {
|
||||
int n = values != null? values.size(): 0;
|
||||
if (n > 0 && values.get(n-1).isvarargexp())
|
||||
n = -1;
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
public static class FuncCallStat extends Stat {
|
||||
public final Exp.FuncCall funccall;
|
||||
|
||||
public FuncCallStat(Exp.FuncCall funccall) {
|
||||
this.funccall = funccall;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class LocalFuncDef extends Stat {
|
||||
public final Name name;
|
||||
public final FuncBody body;
|
||||
|
||||
public LocalFuncDef(String name, FuncBody body) {
|
||||
this.name = new Name(name);
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor visitor) {
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class GenericFor extends Stat {
|
||||
public List<Name> names;
|
||||
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;
|
||||
this.block = block;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class NumericFor extends Stat {
|
||||
public final Name name;
|
||||
public final Exp initial, limit, step;
|
||||
public final Block block;
|
||||
public NameScope scope;
|
||||
|
||||
public NumericFor(String name, Exp initial, Exp limit, Exp step, Block block) {
|
||||
this.name = new Name(name);
|
||||
this.initial = initial;
|
||||
this.limit = limit;
|
||||
this.step = step;
|
||||
this.block = block;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class LocalAssign extends Stat {
|
||||
public final List<Name> names;
|
||||
public final List<Exp> values;
|
||||
|
||||
public LocalAssign(List<Name> names, List<Exp> values) {
|
||||
this.names = names;
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class IfThenElse extends Stat {
|
||||
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) {
|
||||
this.ifexp = ifexp;
|
||||
this.ifblock = ifblock;
|
||||
this.elseifexps = elseifexps;
|
||||
this.elseifblocks = elseifblocks;
|
||||
this.elseblock = elseblock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
123
luaj-jse/src/main/java/org/luaj/vm2/ast/Str.java
Normal file
123
luaj-jse/src/main/java/org/luaj/vm2/ast/Str.java
Normal file
@@ -0,0 +1,123 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.ast;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
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);
|
||||
byte[] b = iso88591bytes(s);
|
||||
return LuaString.valueUsing(b);
|
||||
}
|
||||
|
||||
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 = c[i++]-'0';
|
||||
for (int j = 0; i < n && j < 2 && c[i] >= '0' && c[i] <= '9'; i++, j++)
|
||||
d = d*10+c[i]-'0';
|
||||
baos.write((byte) d);
|
||||
--i;
|
||||
continue;
|
||||
case 'a':
|
||||
baos.write((byte) 7);
|
||||
continue;
|
||||
case 'b':
|
||||
baos.write((byte) '\b');
|
||||
continue;
|
||||
case 'f':
|
||||
baos.write((byte) '\f');
|
||||
continue;
|
||||
case 'n':
|
||||
baos.write((byte) '\n');
|
||||
continue;
|
||||
case 'r':
|
||||
baos.write((byte) '\r');
|
||||
continue;
|
||||
case 't':
|
||||
baos.write((byte) '\t');
|
||||
continue;
|
||||
case 'v':
|
||||
baos.write((byte) 11);
|
||||
continue;
|
||||
case '"':
|
||||
baos.write((byte) '"');
|
||||
continue;
|
||||
case '\'':
|
||||
baos.write((byte) '\'');
|
||||
continue;
|
||||
case '\\':
|
||||
baos.write((byte) '\\');
|
||||
continue;
|
||||
default:
|
||||
baos.write((byte) c[i]);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
baos.write((byte) c[i]);
|
||||
}
|
||||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
}
|
||||
41
luaj-jse/src/main/java/org/luaj/vm2/ast/SyntaxElement.java
Normal file
41
luaj-jse/src/main/java/org/luaj/vm2/ast/SyntaxElement.java
Normal file
@@ -0,0 +1,41 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.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
|
||||
* 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;
|
||||
|
||||
/** The column at which the element ends. */
|
||||
public short endColumn;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TableConstructor extends Exp {
|
||||
public List<TableField> fields;
|
||||
|
||||
@Override
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
51
luaj-jse/src/main/java/org/luaj/vm2/ast/TableField.java
Normal file
51
luaj-jse/src/main/java/org/luaj/vm2/ast/TableField.java
Normal file
@@ -0,0 +1,51 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.ast;
|
||||
|
||||
public class TableField extends SyntaxElement {
|
||||
|
||||
public final Exp index;
|
||||
public final String name;
|
||||
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);
|
||||
}
|
||||
|
||||
public static TableField namedField(String name, Exp rhs) {
|
||||
return new TableField(null, name, rhs);
|
||||
}
|
||||
|
||||
public static TableField listField(Exp rhs) {
|
||||
return new TableField(null, null, rhs);
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
65
luaj-jse/src/main/java/org/luaj/vm2/ast/Variable.java
Normal file
65
luaj-jse/src/main/java/org/luaj/vm2/ast/Variable.java
Normal file
@@ -0,0 +1,65 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
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.
|
||||
*/
|
||||
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. */
|
||||
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
|
||||
*/
|
||||
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. */
|
||||
this.name = name;
|
||||
this.definingScope = definingScope;
|
||||
}
|
||||
|
||||
public boolean isLocal() { return this.definingScope != null; }
|
||||
|
||||
public boolean isConstant() { return !hasassignments && initialValue != null; }
|
||||
}
|
||||
217
luaj-jse/src/main/java/org/luaj/vm2/ast/Visitor.java
Normal file
217
luaj-jse/src/main/java/org/luaj/vm2/ast/Visitor.java
Normal file
@@ -0,0 +1,217 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.ast;
|
||||
|
||||
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(Block block) {
|
||||
visit(block.scope);
|
||||
if (block.stats != null)
|
||||
for (Stat element : block.stats)
|
||||
element.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++) {
|
||||
stat.elseifexps.get(i).accept(this);
|
||||
stat.elseifblocks.get(i).accept(this);
|
||||
}
|
||||
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)
|
||||
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)
|
||||
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 (TableField element : table.fields)
|
||||
element.accept(this);
|
||||
}
|
||||
|
||||
public void visitVars(List<VarExp> vars) {
|
||||
if (vars != null)
|
||||
for (VarExp var : vars)
|
||||
var.accept(this);
|
||||
}
|
||||
|
||||
public void visitExps(List<Exp> exps) {
|
||||
if (exps != null)
|
||||
for (Exp exp : exps)
|
||||
exp.accept(this);
|
||||
}
|
||||
|
||||
public void visitNames(List<Name> names) {
|
||||
if (names != null)
|
||||
for (Name name : names)
|
||||
visit(name);
|
||||
}
|
||||
|
||||
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) {
|
||||
}
|
||||
}
|
||||
204
luaj-jse/src/main/java/org/luaj/vm2/lib/jse/CoerceJavaToLua.java
Normal file
204
luaj-jse/src/main/java/org/luaj/vm2/lib/jse/CoerceJavaToLua.java
Normal file
@@ -0,0 +1,204 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.luaj.vm2.LuaDouble;
|
||||
import org.luaj.vm2.LuaInteger;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaUserdata;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* <p>
|
||||
* 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>
|
||||
* <li>{@link LuaValue#valueOf(double)}</li>
|
||||
* <li>{@link LuaValue#valueOf(int)}</li>
|
||||
* <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:
|
||||
* <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.
|
||||
*
|
||||
* @see CoerceJavaToLua#coerce(Object)
|
||||
* @see org.luaj.vm2.lib.jse.LuajavaLib
|
||||
*/
|
||||
public class CoerceJavaToLua {
|
||||
|
||||
interface Coercion {
|
||||
LuaValue coerce(Object javaValue);
|
||||
}
|
||||
|
||||
private static final class BoolCoercion implements Coercion {
|
||||
@Override
|
||||
public LuaValue coerce(Object javaValue) {
|
||||
Boolean b = (Boolean) javaValue;
|
||||
return b.booleanValue()? LuaValue.TRUE: LuaValue.FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class IntCoercion implements Coercion {
|
||||
@Override
|
||||
public LuaValue coerce(Object javaValue) {
|
||||
Number n = (Number) javaValue;
|
||||
return LuaInteger.valueOf(n.intValue());
|
||||
}
|
||||
}
|
||||
|
||||
private static final class CharCoercion implements Coercion {
|
||||
@Override
|
||||
public LuaValue coerce(Object javaValue) {
|
||||
Character c = (Character) javaValue;
|
||||
return LuaInteger.valueOf(c.charValue());
|
||||
}
|
||||
}
|
||||
|
||||
private static final class DoubleCoercion implements Coercion {
|
||||
@Override
|
||||
public LuaValue coerce(Object javaValue) {
|
||||
Number n = (Number) javaValue;
|
||||
return LuaDouble.valueOf(n.doubleValue());
|
||||
}
|
||||
}
|
||||
|
||||
private static final class StringCoercion implements Coercion {
|
||||
@Override
|
||||
public LuaValue coerce(Object javaValue) {
|
||||
return LuaString.valueOf(javaValue.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private static final class BytesCoercion implements Coercion {
|
||||
@Override
|
||||
public LuaValue coerce(Object javaValue) {
|
||||
return LuaValue.valueOf((byte[]) javaValue);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ClassCoercion implements Coercion {
|
||||
@Override
|
||||
public LuaValue coerce(Object javaValue) {
|
||||
return JavaClass.forClass((Class) javaValue);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class InstanceCoercion implements Coercion {
|
||||
@Override
|
||||
public LuaValue coerce(Object javaValue) {
|
||||
return new JavaInstance(javaValue);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ArrayCoercion implements Coercion {
|
||||
@Override
|
||||
public LuaValue coerce(Object javaValue) {
|
||||
// should be userdata?
|
||||
return new JavaArray(javaValue);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class LuaCoercion implements Coercion {
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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}.
|
||||
*
|
||||
* @param o Java object needing conversion
|
||||
* @return {@link LuaValue} corresponding to the supplied Java value.
|
||||
* @see LuaValue
|
||||
* @see LuaInteger
|
||||
* @see LuaDouble
|
||||
* @see LuaString
|
||||
* @see LuaUserdata
|
||||
*/
|
||||
public static LuaValue coerce(Object o) {
|
||||
if (o == null)
|
||||
return LuaValue.NIL;
|
||||
Class clazz = o.getClass();
|
||||
Coercion c = (Coercion) COERCIONS.get(clazz);
|
||||
if (c == null) {
|
||||
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();
|
||||
}
|
||||
422
luaj-jse/src/main/java/org/luaj/vm2/lib/jse/CoerceLuaToJava.java
Normal file
422
luaj-jse/src/main/java/org/luaj/vm2/lib/jse/CoerceLuaToJava.java
Normal file
@@ -0,0 +1,422 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* <p>
|
||||
* 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>
|
||||
* <li>{@link LuaValue#tochar()}</li>
|
||||
* <li>{@link LuaValue#toshort()}</li>
|
||||
* <li>{@link LuaValue#toint()}</li>
|
||||
* <li>{@link LuaValue#tofloat()}</li>
|
||||
* <li>{@link LuaValue#todouble()}</li>
|
||||
* <li>{@link LuaValue#tojstring()}</li>
|
||||
* <li>{@link LuaValue#touserdata()}</li>
|
||||
* <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.
|
||||
*
|
||||
* @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;
|
||||
|
||||
interface Coercion {
|
||||
int score(LuaValue value);
|
||||
|
||||
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.
|
||||
*/
|
||||
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 {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BoolCoercion()";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int score(LuaValue value) {
|
||||
switch (value.type()) {
|
||||
case LuaValue.TBOOLEAN:
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object coerce(LuaValue value) {
|
||||
return value.toboolean()? Boolean.TRUE: Boolean.FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NumericCoercion(" + TYPE_NAMES[targetType] + ")";
|
||||
}
|
||||
|
||||
NumericCoercion(int targetType) {
|
||||
this.targetType = targetType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int score(LuaValue value) {
|
||||
int fromStringPenalty = 0;
|
||||
if (value.type() == LuaValue.TSTRING) {
|
||||
value = value.tonumber();
|
||||
if (value.isnil()) {
|
||||
return SCORE_UNCOERCIBLE;
|
||||
}
|
||||
fromStringPenalty = 4;
|
||||
}
|
||||
if (value.isint()) {
|
||||
switch (targetType) {
|
||||
case TARGET_TYPE_BYTE: {
|
||||
int i = value.toint();
|
||||
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);
|
||||
}
|
||||
case TARGET_TYPE_SHORT: {
|
||||
int i = value.toint();
|
||||
return fromStringPenalty+(i == (byte) i? 1: i == (short) i? 0: SCORE_WRONG_TYPE);
|
||||
}
|
||||
case TARGET_TYPE_INT: {
|
||||
int i = value.toint();
|
||||
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;
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
case TARGET_TYPE_FLOAT: {
|
||||
double d = value.todouble();
|
||||
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);
|
||||
}
|
||||
default:
|
||||
return SCORE_WRONG_TYPE;
|
||||
}
|
||||
} else {
|
||||
return SCORE_UNCOERCIBLE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object coerce(LuaValue value) {
|
||||
switch (targetType) {
|
||||
case TARGET_TYPE_BYTE:
|
||||
return Byte.valueOf((byte) value.toint());
|
||||
case TARGET_TYPE_CHAR:
|
||||
return Character.valueOf((char) value.toint());
|
||||
case TARGET_TYPE_SHORT:
|
||||
return Short.valueOf((short) value.toint());
|
||||
case TARGET_TYPE_INT:
|
||||
return Integer.valueOf(value.toint());
|
||||
case TARGET_TYPE_LONG:
|
||||
return Long.valueOf((long) value.todouble());
|
||||
case TARGET_TYPE_FLOAT:
|
||||
return Float.valueOf((float) value.todouble());
|
||||
case TARGET_TYPE_DOUBLE:
|
||||
return Double.valueOf(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 StringCoercion(int targetType) {
|
||||
this.targetType = targetType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StringCoercion(" + (targetType == TARGET_TYPE_STRING? "String": "byte[]") + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int score(LuaValue value) {
|
||||
switch (value.type()) {
|
||||
case LuaValue.TSTRING:
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object coerce(LuaValue value) {
|
||||
if (value.isnil())
|
||||
return null;
|
||||
if (targetType == TARGET_TYPE_STRING)
|
||||
return value.tojstring();
|
||||
LuaString s = value.checkstring();
|
||||
byte[] b = new byte[s.m_length];
|
||||
s.copyInto(0, b, 0, b.length);
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
static final class ArrayCoercion implements Coercion {
|
||||
final Class componentType;
|
||||
final Coercion componentCoercion;
|
||||
|
||||
public ArrayCoercion(Class componentType) {
|
||||
this.componentType = componentType;
|
||||
this.componentCoercion = getCoercion(componentType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ArrayCoercion(" + componentType.getName() + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int score(LuaValue value) {
|
||||
switch (value.type()) {
|
||||
case LuaValue.TTABLE:
|
||||
return value.length() == 0? 0: componentCoercion.score(value.get(1));
|
||||
case LuaValue.TUSERDATA:
|
||||
return inheritanceLevels(componentType, value.touserdata().getClass().getComponentType());
|
||||
case LuaValue.TNIL:
|
||||
return SCORE_NULL_VALUE;
|
||||
default:
|
||||
return SCORE_UNCOERCIBLE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object coerce(LuaValue value) {
|
||||
switch (value.type()) {
|
||||
case LuaValue.TTABLE: {
|
||||
int n = value.length();
|
||||
Object a = Array.newInstance(componentType, n);
|
||||
for (int i = 0; i < n; i++)
|
||||
Array.set(a, i, componentCoercion.coerce(value.get(i+1)));
|
||||
return a;
|
||||
}
|
||||
case LuaValue.TUSERDATA:
|
||||
return value.touserdata();
|
||||
case LuaValue.TNIL:
|
||||
return null;
|
||||
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
|
||||
*/
|
||||
static final int inheritanceLevels(Class baseclass, Class subclass) {
|
||||
if (subclass == null)
|
||||
return SCORE_UNCOERCIBLE;
|
||||
if (baseclass == subclass)
|
||||
return 0;
|
||||
int min = Math.min(SCORE_UNCOERCIBLE, inheritanceLevels(baseclass, subclass.getSuperclass())+1);
|
||||
Class[] ifaces = subclass.getInterfaces();
|
||||
for (Class element : ifaces)
|
||||
min = Math.min(min, inheritanceLevels(baseclass, element)+1);
|
||||
return min;
|
||||
}
|
||||
|
||||
static final class ObjectCoercion implements Coercion {
|
||||
final Class targetType;
|
||||
|
||||
ObjectCoercion(Class targetType) {
|
||||
this.targetType = targetType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ObjectCoercion(" + targetType.getName() + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int score(LuaValue value) {
|
||||
switch (value.type()) {
|
||||
case LuaValue.TNUMBER:
|
||||
return inheritanceLevels(targetType, value.isint()? Integer.class: Double.class);
|
||||
case LuaValue.TBOOLEAN:
|
||||
return inheritanceLevels(targetType, Boolean.class);
|
||||
case LuaValue.TSTRING:
|
||||
return inheritanceLevels(targetType, String.class);
|
||||
case LuaValue.TUSERDATA:
|
||||
return inheritanceLevels(targetType, value.touserdata().getClass());
|
||||
case LuaValue.TNIL:
|
||||
return SCORE_NULL_VALUE;
|
||||
default:
|
||||
return inheritanceLevels(targetType, value.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object coerce(LuaValue value) {
|
||||
switch (value.type()) {
|
||||
case LuaValue.TNUMBER:
|
||||
return value.isint()? (Object) Integer.valueOf(value.toint())
|
||||
: (Object) Double.valueOf(value.todouble());
|
||||
case LuaValue.TBOOLEAN:
|
||||
return value.toboolean()? Boolean.TRUE: Boolean.FALSE;
|
||||
case LuaValue.TSTRING:
|
||||
return value.tojstring();
|
||||
case LuaValue.TUSERDATA:
|
||||
return value.optuserdata(targetType, null);
|
||||
case LuaValue.TNIL:
|
||||
return null;
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 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);
|
||||
}
|
||||
|
||||
static Coercion getCoercion(Class c) {
|
||||
Coercion co = (Coercion) COERCIONS.get(c);
|
||||
if (co != null) {
|
||||
return co;
|
||||
}
|
||||
if (c.isArray()) {
|
||||
Class typ = c.getComponentType();
|
||||
co = new ArrayCoercion(c.getComponentType());
|
||||
} else {
|
||||
co = new ObjectCoercion(c);
|
||||
}
|
||||
COERCIONS.put(c, co);
|
||||
return co;
|
||||
}
|
||||
}
|
||||
88
luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JavaArray.java
Normal file
88
luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JavaArray.java
Normal file
@@ -0,0 +1,88 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2011 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaUserdata;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.OneArgFunction;
|
||||
|
||||
/**
|
||||
* LuaValue that represents a Java instance of array type.
|
||||
* <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.
|
||||
*
|
||||
* @see CoerceJavaToLua
|
||||
* @see CoerceLuaToJava
|
||||
*/
|
||||
class JavaArray extends LuaUserdata {
|
||||
|
||||
private static final class LenFunction extends OneArgFunction {
|
||||
@Override
|
||||
public LuaValue call(LuaValue u) {
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuaValue get(LuaValue key) {
|
||||
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;
|
||||
}
|
||||
return super.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
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
|
||||
super.set(key, value);
|
||||
}
|
||||
}
|
||||
153
luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JavaClass.java
Normal file
153
luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JavaClass.java
Normal file
@@ -0,0 +1,153 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2011 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
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.
|
||||
* <p>
|
||||
* 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
|
||||
*/
|
||||
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));
|
||||
return j;
|
||||
}
|
||||
|
||||
JavaClass(Class c) {
|
||||
super(c);
|
||||
this.jclass = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuaValue coerce(Object javaValue) {
|
||||
return this;
|
||||
}
|
||||
|
||||
Field getField(LuaValue key) {
|
||||
if (fields == null) {
|
||||
Map m = new HashMap();
|
||||
Field[] f = ((Class) m_instance).getFields();
|
||||
for (Field fi : f) {
|
||||
if (Modifier.isPublic(fi.getModifiers())) {
|
||||
m.put(LuaValue.valueOf(fi.getName()), fi);
|
||||
try {
|
||||
if (!fi.isAccessible())
|
||||
fi.setAccessible(true);
|
||||
} catch (SecurityException s) {
|
||||
}
|
||||
}
|
||||
}
|
||||
fields = m;
|
||||
}
|
||||
return (Field) fields.get(key);
|
||||
}
|
||||
|
||||
LuaValue getMethod(LuaValue key) {
|
||||
if (methods == null) {
|
||||
Map namedlists = new HashMap();
|
||||
Method[] m = ((Class) m_instance).getMethods();
|
||||
for (Method mi : m) {
|
||||
if (Modifier.isPublic(mi.getModifiers())) {
|
||||
String name = mi.getName();
|
||||
List list = (List) namedlists.get(name);
|
||||
if (list == null)
|
||||
namedlists.put(name, list = new ArrayList());
|
||||
list.add(JavaMethod.forMethod(mi));
|
||||
}
|
||||
}
|
||||
Map map = new HashMap();
|
||||
Constructor[] c = ((Class) m_instance).getConstructors();
|
||||
List list = new ArrayList();
|
||||
for (Constructor element : c)
|
||||
if (Modifier.isPublic(element.getModifiers()))
|
||||
list.add(JavaConstructor.forConstructor(element));
|
||||
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();) {
|
||||
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()])));
|
||||
}
|
||||
methods = map;
|
||||
}
|
||||
return (LuaValue) methods.get(key);
|
||||
}
|
||||
|
||||
Class getInnerClass(LuaValue key) {
|
||||
if (innerclasses == null) {
|
||||
Map m = new HashMap();
|
||||
Class[] c = ((Class) m_instance).getClasses();
|
||||
for (Class ci : c) {
|
||||
String name = ci.getName();
|
||||
String stub = name.substring(Math.max(name.lastIndexOf('$'), name.lastIndexOf('.'))+1);
|
||||
m.put(LuaValue.valueOf(stub), ci);
|
||||
}
|
||||
innerclasses = m;
|
||||
}
|
||||
return (Class) innerclasses.get(key);
|
||||
}
|
||||
|
||||
public LuaValue getConstructor() { return getMethod(NEW); }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
import org.luaj.vm2.compat.JavaCompat;
|
||||
|
||||
public class JavaCompatJSE extends JavaCompat {
|
||||
public long doubleToRawLongBits(double x) {
|
||||
return Double.doubleToRawLongBits(x);
|
||||
}
|
||||
}
|
||||
119
luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JavaConstructor.java
Normal file
119
luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JavaConstructor.java
Normal file
@@ -0,0 +1,119 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2011 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
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.
|
||||
* <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".
|
||||
*
|
||||
* @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));
|
||||
return j;
|
||||
}
|
||||
|
||||
public static LuaValue forConstructors(JavaConstructor[] array) {
|
||||
return new Overload(array);
|
||||
}
|
||||
|
||||
final Constructor constructor;
|
||||
|
||||
private JavaConstructor(Constructor c) {
|
||||
super(c.getParameterTypes(), c.getModifiers());
|
||||
this.constructor = c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Varargs invoke(Varargs args) {
|
||||
Object[] a = convertArgs(args);
|
||||
try {
|
||||
return CoerceJavaToLua.coerce(constructor.newInstance(a));
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new LuaError(e.getTargetException());
|
||||
} catch (Exception e) {
|
||||
return LuaValue.error("coercion error " + e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* LuaValue that represents an overloaded Java constructor.
|
||||
* <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.
|
||||
*/
|
||||
static class Overload extends VarArgFunction {
|
||||
final JavaConstructor[] constructors;
|
||||
|
||||
public Overload(JavaConstructor[] c) {
|
||||
this.constructors = c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Varargs invoke(Varargs args) {
|
||||
JavaConstructor best = null;
|
||||
int score = CoerceLuaToJava.SCORE_UNCOERCIBLE;
|
||||
for (JavaConstructor constructor : constructors) {
|
||||
int s = constructor.score(args);
|
||||
if (s < score) {
|
||||
score = s;
|
||||
best = constructor;
|
||||
if (score == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// any match?
|
||||
if (best == null)
|
||||
LuaValue.error("no coercible public method");
|
||||
|
||||
// invoke it
|
||||
return best.invoke(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2011 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaUserdata;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
/**
|
||||
* LuaValue that represents a Java instance.
|
||||
* <p>
|
||||
* 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.
|
||||
*
|
||||
* @see CoerceJavaToLua
|
||||
* @see CoerceLuaToJava
|
||||
*/
|
||||
class JavaInstance extends LuaUserdata {
|
||||
|
||||
JavaClass jclass;
|
||||
|
||||
JavaInstance(Object instance) {
|
||||
super(instance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuaValue get(LuaValue key) {
|
||||
if (jclass == null)
|
||||
jclass = JavaClass.forClass(m_instance.getClass());
|
||||
Field f = jclass.getField(key);
|
||||
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)
|
||||
return m;
|
||||
Class c = jclass.getInnerClass(key);
|
||||
if (c != null)
|
||||
return JavaClass.forClass(c);
|
||||
return super.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(LuaValue key, LuaValue value) {
|
||||
if (jclass == null)
|
||||
jclass = JavaClass.forClass(m_instance.getClass());
|
||||
Field f = jclass.getField(key);
|
||||
if (f != null)
|
||||
try {
|
||||
f.set(m_instance, CoerceLuaToJava.coerce(value, f.getType()));
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
throw new LuaError(e);
|
||||
}
|
||||
super.set(key, value);
|
||||
}
|
||||
|
||||
}
|
||||
84
luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JavaMember.java
Normal file
84
luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JavaMember.java
Normal file
@@ -0,0 +1,84 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2011 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.lib.VarArgFunction;
|
||||
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.
|
||||
* <p>
|
||||
* 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 {
|
||||
|
||||
static final int METHOD_MODIFIERS_VARARGS = 0x80;
|
||||
|
||||
final Coercion[] fixedargs;
|
||||
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;
|
||||
}
|
||||
|
||||
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));
|
||||
return s;
|
||||
}
|
||||
|
||||
protected Object[] convertArgs(Varargs args) {
|
||||
Object[] a;
|
||||
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));
|
||||
} else {
|
||||
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));
|
||||
}
|
||||
return a;
|
||||
}
|
||||
}
|
||||
173
luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JavaMethod.java
Normal file
173
luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JavaMethod.java
Normal file
@@ -0,0 +1,173 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2011 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaFunction;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/**
|
||||
* LuaValue that represents a Java method.
|
||||
* <p>
|
||||
* 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.
|
||||
*
|
||||
* @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));
|
||||
return j;
|
||||
}
|
||||
|
||||
static LuaFunction forMethods(JavaMethod[] m) {
|
||||
return new Overload(m);
|
||||
}
|
||||
|
||||
final Method method;
|
||||
|
||||
private JavaMethod(Method m) {
|
||||
super(m.getParameterTypes(), m.getModifiers());
|
||||
this.method = m;
|
||||
try {
|
||||
if (!m.isAccessible())
|
||||
m.setAccessible(true);
|
||||
} catch (SecurityException s) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuaValue call() {
|
||||
return error("method cannot be called without instance");
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return invokeMethod(arg.checkuserdata(), LuaValue.NONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return invokeMethod(arg1.checkuserdata(), arg2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
|
||||
return invokeMethod(arg1.checkuserdata(), LuaValue.varargsOf(arg2, arg3));
|
||||
}
|
||||
|
||||
@Override
|
||||
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));
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new LuaError(e.getTargetException());
|
||||
} catch (Exception 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.
|
||||
*/
|
||||
static class Overload extends LuaFunction {
|
||||
|
||||
final JavaMethod[] methods;
|
||||
|
||||
Overload(JavaMethod[] methods) {
|
||||
this.methods = methods;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuaValue call() {
|
||||
return error("method cannot be called without instance");
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return invokeBestMethod(arg.checkuserdata(), LuaValue.NONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return invokeBestMethod(arg1.checkuserdata(), arg2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
|
||||
return invokeBestMethod(arg1.checkuserdata(), LuaValue.varargsOf(arg2, arg3));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Varargs invoke(Varargs args) {
|
||||
return invokeBestMethod(args.checkuserdata(1), args.subargs(2));
|
||||
}
|
||||
|
||||
private LuaValue invokeBestMethod(Object instance, Varargs args) {
|
||||
JavaMethod best = null;
|
||||
int score = CoerceLuaToJava.SCORE_UNCOERCIBLE;
|
||||
for (JavaMethod method : methods) {
|
||||
int s = method.score(args);
|
||||
if (s < score) {
|
||||
score = s;
|
||||
best = method;
|
||||
if (score == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// any match?
|
||||
if (best == null)
|
||||
LuaValue.error("no coercible public method");
|
||||
|
||||
// invoke it
|
||||
return best.invokeMethod(instance, args);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
142
luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JseBaseLib.java
Normal file
142
luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JseBaseLib.java
Normal file
@@ -0,0 +1,142 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
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}.
|
||||
* <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
|
||||
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()}
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* @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.
|
||||
* <p>
|
||||
* This is a direct port of the corresponding library in C.
|
||||
*
|
||||
* @see Globals
|
||||
* @see BaseLib
|
||||
* @see ResourceFinder
|
||||
* @see Globals#finder
|
||||
* @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>
|
||||
*/
|
||||
|
||||
public class JseBaseLib extends org.luaj.vm2.lib.BaseLib {
|
||||
|
||||
<<<<<<< HEAD:src/jse/org/luaj/vm2/lib/jse/JseBaseLib.java
|
||||
/** 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}
|
||||
*
|
||||
>>>>>>> farmboy0/master:luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JseBaseLib.java
|
||||
* @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.
|
||||
*/
|
||||
@Override
|
||||
public LuaValue call(LuaValue modname, LuaValue env) {
|
||||
super.call(modname, env);
|
||||
env.checkglobals().STDIN = System.in;
|
||||
return env;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to open a file in the current working directory, or fall back to base
|
||||
* opener if not found.
|
||||
*
|
||||
* This implementation attempts to open the file using new File(filename).
|
||||
* It falls back to the base implementation that looks it up as a resource
|
||||
* in the class path if not found as a plain file.
|
||||
*
|
||||
* @see org.luaj.vm2.lib.BaseLib
|
||||
* @see org.luaj.vm2.lib.ResourceFinder
|
||||
*
|
||||
* @param filename
|
||||
* @return InputStream, or null if not found.
|
||||
*/
|
||||
@Override
|
||||
public InputStream findResource(String filename) {
|
||||
File f = new File(filename);
|
||||
if (!f.exists())
|
||||
return super.findResource(filename);
|
||||
try {
|
||||
return new BufferedInputStream(new FileInputStream(f));
|
||||
} catch (IOException ioe) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
402
luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JseIoLib.java
Normal file
402
luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JseIoLib.java
Normal file
@@ -0,0 +1,402 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
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.
|
||||
* <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>
|
||||
* <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.
|
||||
* <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>
|
||||
*/
|
||||
public class JseIoLib extends IoLib {
|
||||
|
||||
@Override
|
||||
protected File wrapStdin() throws IOException {
|
||||
return new StdinFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected File wrapStdout() throws IOException {
|
||||
return new StdoutFile(FTYPE_STDOUT);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected File wrapStderr() throws IOException {
|
||||
return new StdoutFile(FTYPE_STDERR);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected File openFile(String filename, boolean readMode, boolean appendMode, boolean updateMode,
|
||||
boolean binaryMode) throws IOException {
|
||||
RandomAccessFile f = new RandomAccessFile(filename, readMode? "r": "rw");
|
||||
if (appendMode) {
|
||||
f.seek(f.length());
|
||||
} else {
|
||||
if (!readMode)
|
||||
f.setLength(0);
|
||||
}
|
||||
return new FileImpl(f);
|
||||
}
|
||||
|
||||
@Override
|
||||
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());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected File tmpFile() throws IOException {
|
||||
java.io.File f = java.io.File.createTempFile(".luaj", "bin");
|
||||
f.deleteOnExit();
|
||||
return new FileImpl(new RandomAccessFile(f, "rw"));
|
||||
}
|
||||
|
||||
private static void notimplemented() {
|
||||
throw new LuaError("not implemented");
|
||||
}
|
||||
|
||||
private final class FileImpl extends File {
|
||||
private final RandomAccessFile file;
|
||||
private final InputStream is;
|
||||
private final OutputStream os;
|
||||
private boolean closed = false;
|
||||
private boolean nobuffer = false;
|
||||
|
||||
private FileImpl(RandomAccessFile file, InputStream is, OutputStream os) {
|
||||
this.file = file;
|
||||
this.is = is != null? is.markSupported()? is: new BufferedInputStream(is): null;
|
||||
this.os = os;
|
||||
}
|
||||
|
||||
private FileImpl(RandomAccessFile f) {
|
||||
this(f, null, null);
|
||||
}
|
||||
|
||||
private FileImpl(InputStream i) {
|
||||
this(null, i, null);
|
||||
}
|
||||
|
||||
private FileImpl(OutputStream o) {
|
||||
this(null, null, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tojstring() {
|
||||
return "file (" + (this.closed? "closed": String.valueOf(this.hashCode())) + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isstdfile() {
|
||||
return file == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
closed = true;
|
||||
if (file != null) {
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
if (os != null)
|
||||
os.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(LuaString s) throws IOException {
|
||||
if (os != null)
|
||||
os.write(s.m_bytes, s.m_offset, s.m_length);
|
||||
else if (file != null)
|
||||
file.write(s.m_bytes, s.m_offset, s.m_length);
|
||||
else
|
||||
notimplemented();
|
||||
if (nobuffer)
|
||||
flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isclosed() {
|
||||
return closed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int seek(String option, int pos) throws IOException {
|
||||
if (file != null) {
|
||||
if ("set".equals(option)) {
|
||||
file.seek(pos);
|
||||
} else if ("end".equals(option)) {
|
||||
file.seek(file.length()+pos);
|
||||
} else {
|
||||
file.seek(file.getFilePointer()+pos);
|
||||
}
|
||||
return (int) file.getFilePointer();
|
||||
}
|
||||
notimplemented();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setvbuf(String mode, int size) {
|
||||
nobuffer = "no".equals(mode);
|
||||
}
|
||||
|
||||
// get length remaining to read
|
||||
@Override
|
||||
public int remaining() throws IOException {
|
||||
return file != null? (int) (file.length()-file.getFilePointer()): -1;
|
||||
}
|
||||
|
||||
// peek ahead one character
|
||||
@Override
|
||||
public int peek() throws IOException {
|
||||
if (is != null) {
|
||||
is.mark(1);
|
||||
int c = is.read();
|
||||
is.reset();
|
||||
return c;
|
||||
} else if (file != null) {
|
||||
long fp = file.getFilePointer();
|
||||
int c = file.read();
|
||||
file.seek(fp);
|
||||
return c;
|
||||
}
|
||||
notimplemented();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// return char if read, -1 if eof, throw IOException on other exception
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if (is != null)
|
||||
return is.read();
|
||||
else if (file != null) {
|
||||
return file.read();
|
||||
}
|
||||
notimplemented();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// return number of bytes read if positive, -1 if eof, throws IOException
|
||||
@Override
|
||||
public int read(byte[] bytes, int offset, int length) throws IOException {
|
||||
if (file != null) {
|
||||
return file.read(bytes, offset, length);
|
||||
} else if (is != null) {
|
||||
return is.read(bytes, offset, length);
|
||||
} else {
|
||||
notimplemented();
|
||||
}
|
||||
return length;
|
||||
}
|
||||
}
|
||||
|
||||
private final class StdoutFile extends File {
|
||||
private final int file_type;
|
||||
|
||||
private StdoutFile(int file_type) {
|
||||
this.file_type = file_type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tojstring() {
|
||||
return "file (" + this.hashCode() + ")";
|
||||
}
|
||||
|
||||
private PrintStream getPrintStream() { return file_type == FTYPE_STDERR? globals.STDERR: globals.STDOUT; }
|
||||
|
||||
@Override
|
||||
public void write(LuaString string) throws IOException {
|
||||
getPrintStream().write(string.m_bytes, string.m_offset, string.m_length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
getPrintStream().flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isstdfile() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
// do not close std files.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isclosed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int seek(String option, int bytecount) throws IOException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setvbuf(String mode, int size) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int remaining() throws IOException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int peek() throws IOException, EOFException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException, EOFException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] bytes, int offset, int length) throws IOException {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private final class StdinFile extends File {
|
||||
private StdinFile() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tojstring() {
|
||||
return "file (" + this.hashCode() + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(LuaString string) throws IOException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isstdfile() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
// do not close std files.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isclosed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int seek(String option, int bytecount) throws IOException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setvbuf(String mode, int size) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int remaining() throws IOException {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int peek() throws IOException, EOFException {
|
||||
globals.STDIN.mark(1);
|
||||
int c = globals.STDIN.read();
|
||||
globals.STDIN.reset();
|
||||
return c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException, EOFException {
|
||||
return globals.STDIN.read();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] bytes, int offset, int length) throws IOException {
|
||||
return globals.STDIN.read(bytes, offset, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
176
luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JseMathLib.java
Normal file
176
luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JseMathLib.java
Normal file
@@ -0,0 +1,176 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
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.
|
||||
* <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>
|
||||
* <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.
|
||||
* <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>
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
@Override
|
||||
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());
|
||||
math.set("atan", new atan());
|
||||
math.set("atan2", new atan2());
|
||||
math.set("cosh", new cosh());
|
||||
math.set("exp", new exp());
|
||||
math.set("log", new log());
|
||||
math.set("pow", new pow());
|
||||
math.set("sinh", new sinh());
|
||||
math.set("tanh", new tanh());
|
||||
return math;
|
||||
}
|
||||
|
||||
static final class acos extends UnaryOp {
|
||||
@Override
|
||||
protected double call(double d) { return Math.acos(d); }
|
||||
}
|
||||
|
||||
static final class asin extends UnaryOp {
|
||||
@Override
|
||||
protected double call(double d) { return Math.asin(d); }
|
||||
}
|
||||
|
||||
static final class atan extends TwoArgFunction {
|
||||
@Override
|
||||
public LuaValue call(LuaValue x, LuaValue y) {
|
||||
return valueOf(Math.atan2(x.checkdouble(), y.optdouble(1)));
|
||||
}
|
||||
}
|
||||
|
||||
static final class atan2 extends TwoArgFunction {
|
||||
@Override
|
||||
public LuaValue call(LuaValue x, LuaValue y) {
|
||||
return valueOf(Math.atan2(x.checkdouble(), y.checkdouble()));
|
||||
}
|
||||
}
|
||||
|
||||
static final class cosh extends UnaryOp {
|
||||
@Override
|
||||
protected double call(double d) { return Math.cosh(d); }
|
||||
}
|
||||
|
||||
static final class exp extends UnaryOp {
|
||||
@Override
|
||||
protected double call(double d) { return Math.exp(d); }
|
||||
}
|
||||
|
||||
static final class log extends TwoArgFunction {
|
||||
@Override
|
||||
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);
|
||||
return valueOf(nat);
|
||||
}
|
||||
}
|
||||
|
||||
static final class pow extends BinaryOp {
|
||||
@Override
|
||||
protected double call(double x, double y) { return Math.pow(x, y); }
|
||||
}
|
||||
|
||||
static final class sinh extends UnaryOp {
|
||||
@Override
|
||||
protected double call(double d) { return Math.sinh(d); }
|
||||
}
|
||||
|
||||
static final class tanh extends UnaryOp {
|
||||
@Override
|
||||
protected double call(double d) { return Math.tanh(d); }
|
||||
}
|
||||
|
||||
/** Faster, better version of pow() used by arithmetic operator ^ */
|
||||
@Override
|
||||
public double dpow_lib(double a, double b) {
|
||||
return Math.pow(a, b);
|
||||
}
|
||||
|
||||
}
|
||||
153
luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JseOsLib.java
Normal file
153
luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JseOsLib.java
Normal file
@@ -0,0 +1,153 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.lib.LibFunction;
|
||||
import org.luaj.vm2.lib.OsLib;
|
||||
|
||||
/**
|
||||
* 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:
|
||||
* <ul>
|
||||
* <li>{@code execute()}</li>
|
||||
* <li>{@code remove()}</li>
|
||||
* <li>{@code rename()}</li>
|
||||
* <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.
|
||||
* <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>
|
||||
* <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.
|
||||
* <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>
|
||||
*/
|
||||
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;
|
||||
|
||||
/** 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 constructor */
|
||||
public JseOsLib() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getenv(String varname) {
|
||||
String s = System.getenv(varname);
|
||||
return s != null? s: System.getProperty(varname);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Varargs execute(String command) {
|
||||
int exitValue;
|
||||
try {
|
||||
exitValue = new JseProcess(command, null, globals.STDOUT, globals.STDERR).waitFor();
|
||||
} catch (IOException ioe) {
|
||||
exitValue = EXEC_IOEXCEPTION;
|
||||
} catch (InterruptedException e) {
|
||||
exitValue = EXEC_INTERRUPTED;
|
||||
} catch (Throwable t) {
|
||||
exitValue = EXEC_ERROR;
|
||||
}
|
||||
if (exitValue == 0)
|
||||
return varargsOf(TRUE, valueOf("exit"), ZERO);
|
||||
return varargsOf(NIL, valueOf("signal"), valueOf(exitValue));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void remove(String filename) throws IOException {
|
||||
File f = new File(filename);
|
||||
if (!f.exists())
|
||||
throw new IOException("No such file or directory");
|
||||
if (!f.delete())
|
||||
throw new IOException("Failed to delete");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void rename(String oldname, String newname) throws IOException {
|
||||
File f = new File(oldname);
|
||||
if (!f.exists())
|
||||
throw new IOException("No such file or directory");
|
||||
if (!f.renameTo(new File(newname)))
|
||||
throw new IOException("Failed to rename");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String tmpname() {
|
||||
try {
|
||||
java.io.File f = java.io.File.createTempFile(TMP_PREFIX, TMP_SUFFIX);
|
||||
return f.getAbsolutePath();
|
||||
} catch (IOException ioe) {
|
||||
return super.tmpname();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
162
luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JsePlatform.java
Normal file
162
luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JsePlatform.java
Normal file
@@ -0,0 +1,162 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LoadState;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
import org.luaj.vm2.lib.Bit32Lib;
|
||||
import org.luaj.vm2.lib.CoroutineLib;
|
||||
import org.luaj.vm2.lib.DebugLib;
|
||||
import org.luaj.vm2.lib.PackageLib;
|
||||
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.
|
||||
* <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>
|
||||
* <p>
|
||||
* Once globals are created, a simple way to load and run a script is:
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* globals.load( new FileInputStream("main.lua"), "main.lua" ).call();
|
||||
* }
|
||||
* </pre>
|
||||
* <p>
|
||||
* although {@code require} could also be used:
|
||||
*
|
||||
* <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}.
|
||||
* <p>
|
||||
* 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>
|
||||
* <li>{@link PackageLib}</li>
|
||||
* <li>{@link Bit32Lib}</li>
|
||||
* <li>{@link TableLib}</li>
|
||||
* <li>{@link StringLib}</li>
|
||||
* <li>{@link CoroutineLib}</li>
|
||||
* <li>{@link org.luaj.vm2.lib.jse.JseMathLib}</li>
|
||||
* <li>{@link org.luaj.vm2.lib.jse.JseIoLib}</li>
|
||||
* <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.
|
||||
* <p>
|
||||
* 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.
|
||||
*
|
||||
* @see Globals
|
||||
* @see org.luaj.vm2.lib.jme.JmePlatform
|
||||
*/
|
||||
public class JsePlatform {
|
||||
|
||||
/**
|
||||
* Create a standard set of globals for JSE including all the libraries.
|
||||
*
|
||||
* @return Table of globals initialized with the standard JSE libraries
|
||||
* @see #debugGlobals()
|
||||
* @see org.luaj.vm2.lib.jse.JsePlatform
|
||||
* @see org.luaj.vm2.lib.jme.JmePlatform
|
||||
*/
|
||||
public static Globals standardGlobals() {
|
||||
Globals globals = new Globals();
|
||||
globals.load(new JseBaseLib());
|
||||
globals.load(new PackageLib());
|
||||
globals.load(new Bit32Lib());
|
||||
globals.load(new TableLib());
|
||||
globals.load(new JseStringLib());
|
||||
globals.load(new CoroutineLib());
|
||||
globals.load(new JseMathLib());
|
||||
globals.load(new JseIoLib());
|
||||
globals.load(new JseOsLib());
|
||||
globals.load(new LuajavaLib());
|
||||
LoadState.install(globals);
|
||||
LuaC.install(globals);
|
||||
return globals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create standard globals including the {@link DebugLib} library.
|
||||
*
|
||||
* @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
|
||||
* @see DebugLib
|
||||
*/
|
||||
public static Globals debugGlobals() {
|
||||
Globals globals = standardGlobals();
|
||||
globals.load(new DebugLib());
|
||||
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.
|
||||
*
|
||||
* @return {@link Varargs} containing any values returned by mainChunk.
|
||||
*/
|
||||
public static Varargs luaMain(LuaValue mainChunk, String[] args) {
|
||||
Globals g = standardGlobals();
|
||||
int n = args.length;
|
||||
LuaValue[] vargs = new LuaValue[args.length];
|
||||
for (int i = 0; i < n; ++i)
|
||||
vargs[i] = LuaValue.valueOf(args[i]);
|
||||
LuaValue arg = LuaValue.listOf(vargs);
|
||||
arg.set("n", n);
|
||||
g.set("arg", arg);
|
||||
mainChunk.initupvalue1(g);
|
||||
return mainChunk.invoke(LuaValue.varargsOf(vargs));
|
||||
}
|
||||
}
|
||||
144
luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JseProcess.java
Normal file
144
luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JseProcess.java
Normal file
@@ -0,0 +1,144 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Analog of Process that pipes input and output to client-specified streams.
|
||||
*/
|
||||
public class JseProcess {
|
||||
|
||||
final Process process;
|
||||
final Thread input, output, error;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @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);
|
||||
}
|
||||
|
||||
private JseProcess(Process process, InputStream stdin, OutputStream stdout, OutputStream stderr) {
|
||||
this.process = process;
|
||||
input = stdin == null? null: copyBytes(stdin, process.getOutputStream(), null, process.getOutputStream());
|
||||
output = stdout == null? null: copyBytes(process.getInputStream(), stdout, process.getInputStream(), null);
|
||||
error = stderr == null? null: copyBytes(process.getErrorStream(), stderr, process.getErrorStream(), null);
|
||||
}
|
||||
|
||||
/** Get the exit value of the process. */
|
||||
public int exitValue() {
|
||||
return process.exitValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the process to complete, and all pending output to finish.
|
||||
*
|
||||
* @return The exit status.
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public int waitFor() throws InterruptedException {
|
||||
int r = process.waitFor();
|
||||
if (input != null)
|
||||
input.join();
|
||||
if (output != null)
|
||||
output.join();
|
||||
if (error != null)
|
||||
error.join();
|
||||
process.destroy();
|
||||
return r;
|
||||
}
|
||||
|
||||
/** 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) {
|
||||
Thread t = new CopyThread(output, ownedOutput, ownedInput, input);
|
||||
t.start();
|
||||
return t;
|
||||
}
|
||||
|
||||
private static final class CopyThread extends Thread {
|
||||
private final OutputStream output;
|
||||
private final OutputStream ownedOutput;
|
||||
private final InputStream ownedInput;
|
||||
private final InputStream input;
|
||||
|
||||
private CopyThread(OutputStream output, OutputStream ownedOutput, InputStream ownedInput, InputStream input) {
|
||||
this.output = output;
|
||||
this.ownedOutput = ownedOutput;
|
||||
this.ownedInput = ownedInput;
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
byte[] buf = new byte[1024];
|
||||
int r;
|
||||
try {
|
||||
while ( (r = input.read(buf)) >= 0 ) {
|
||||
output.write(buf, 0, r);
|
||||
}
|
||||
} finally {
|
||||
if (ownedInput != null)
|
||||
ownedInput.close();
|
||||
if (ownedOutput != null)
|
||||
ownedOutput.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
public class JseStringLib extends org.luaj.vm2.lib.StringLib {
|
||||
|
||||
/** public constructor */
|
||||
public JseStringLib() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String format(String src, double x) {
|
||||
String out;
|
||||
try {
|
||||
out = String.format(src, Double.valueOf(x));
|
||||
} catch (Throwable e) {
|
||||
out = super.format(src, x);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
223
luaj-jse/src/main/java/org/luaj/vm2/lib/jse/LuajavaLib.java
Normal file
223
luaj-jse/src/main/java/org/luaj/vm2/lib/jse/LuajavaLib.java
Normal file
@@ -0,0 +1,223 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
import org.luaj.vm2.lib.LibFunction;
|
||||
import org.luaj.vm2.lib.VarArgFunction;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* <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>
|
||||
* <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>
|
||||
* <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.
|
||||
* <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 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>
|
||||
*/
|
||||
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 String[] NAMES = { "bindClass", "newInstance", "new", "createProxy", "loadLib", };
|
||||
|
||||
static final int METHOD_MODIFIERS_VARARGS = 0x80;
|
||||
|
||||
public LuajavaLib() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Varargs invoke(Varargs args) {
|
||||
try {
|
||||
switch (opcode) {
|
||||
case INIT: {
|
||||
// LuaValue modname = args.arg1();
|
||||
LuaValue env = args.arg(2);
|
||||
LuaTable t = new LuaTable();
|
||||
bind(t, this.getClass(), NAMES, BINDCLASS);
|
||||
env.set("luajava", t);
|
||||
if (!env.get("package").isnil())
|
||||
env.get("package").get("loaded").set("luajava", t);
|
||||
return t;
|
||||
}
|
||||
case BINDCLASS: {
|
||||
final Class clazz = classForName(args.checkjstring(1));
|
||||
return JavaClass.forClass(clazz);
|
||||
}
|
||||
case NEWINSTANCE:
|
||||
case NEW: {
|
||||
// get constructor
|
||||
final LuaValue c = args.checkvalue(1);
|
||||
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)
|
||||
throw new LuaError("no interfaces");
|
||||
final LuaValue lobj = args.checktable(niface+1);
|
||||
|
||||
// get the interfaces
|
||||
final Class[] ifaces = new Class[niface];
|
||||
for (int i = 0; i < niface; i++)
|
||||
ifaces[i] = 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);
|
||||
}
|
||||
case LOADLIB: {
|
||||
// get constructor
|
||||
String classname = args.checkjstring(1);
|
||||
String methodname = args.checkjstring(2);
|
||||
Class clazz = classForName(classname);
|
||||
Method method = clazz.getMethod(methodname);
|
||||
Object result = method.invoke(clazz);
|
||||
if (result instanceof LuaValue) {
|
||||
return (LuaValue) result;
|
||||
} else {
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw new LuaError("not yet supported: " + this);
|
||||
}
|
||||
} catch (LuaError e) {
|
||||
throw e;
|
||||
} catch (InvocationTargetException ite) {
|
||||
throw new LuaError(ite.getTargetException());
|
||||
} catch (Exception e) {
|
||||
throw new LuaError(e);
|
||||
}
|
||||
}
|
||||
|
||||
// load classes using app loader to allow luaj to be used as an extension
|
||||
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;
|
||||
|
||||
private ProxyInvocationHandler(LuaValue lobj) {
|
||||
this.lobj = lobj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
String name = method.getName();
|
||||
LuaValue func = lobj.get(name);
|
||||
if (func.isnil())
|
||||
return null;
|
||||
boolean isvarargs = (method.getModifiers() & METHOD_MODIFIERS_VARARGS) != 0;
|
||||
int n = args != null? args.length: 0;
|
||||
LuaValue[] v;
|
||||
if (isvarargs) {
|
||||
Object o = args[--n];
|
||||
int m = Array.getLength(o);
|
||||
v = new LuaValue[n+m];
|
||||
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));
|
||||
} else {
|
||||
v = new LuaValue[n];
|
||||
for (int i = 0; i < n; i++)
|
||||
v[i] = CoerceJavaToLua.coerce(args[i]);
|
||||
}
|
||||
LuaValue result = func.invoke(v).arg1();
|
||||
return CoerceLuaToJava.coerce(result, method.getReturnType());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
222
luaj-jse/src/main/java/org/luaj/vm2/luajc/BasicBlock.java
Normal file
222
luaj-jse/src/main/java/org/luaj/vm2/luajc/BasicBlock.java
Normal file
@@ -0,0 +1,222 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.luaj.vm2.luajc;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
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
|
||||
|
||||
public BasicBlock(Prototype p, int pc0) {
|
||||
this.pc0 = this.pc1 = pc0;
|
||||
}
|
||||
|
||||
@Override
|
||||
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");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String str(BasicBlock[] b, int p) {
|
||||
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));
|
||||
}
|
||||
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];
|
||||
final boolean[] isend = new boolean[n];
|
||||
isbeg[0] = true;
|
||||
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++) {
|
||||
isbeg[i] = true;
|
||||
BasicBlock b = new BasicBlock(p, i);
|
||||
blocks[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));
|
||||
return blocks;
|
||||
}
|
||||
|
||||
private static final class AllocAndXRefVisitor extends BranchVisitor {
|
||||
private final int[] nnext;
|
||||
private final int[] nprev;
|
||||
private final BasicBlock[] blocks;
|
||||
|
||||
private AllocAndXRefVisitor(boolean[] isbeg, int[] nnext, int[] nprev, BasicBlock[] blocks) {
|
||||
super(isbeg);
|
||||
this.nnext = nnext;
|
||||
this.nprev = nprev;
|
||||
this.blocks = blocks;
|
||||
}
|
||||
|
||||
@Override
|
||||
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]];
|
||||
blocks[pc0].next[--nnext[pc0]] = blocks[pc1];
|
||||
blocks[pc1].prev[--nprev[pc1]] = blocks[pc0];
|
||||
}
|
||||
}
|
||||
|
||||
private static final class CountPrevNextVistor extends BranchVisitor {
|
||||
private final int[] nnext;
|
||||
private final int[] nprev;
|
||||
|
||||
private CountPrevNextVistor(boolean[] isbeg, int[] nnext, int[] nprev) {
|
||||
super(isbeg);
|
||||
this.nnext = nnext;
|
||||
this.nprev = nprev;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitBranch(int pc0, int pc1) {
|
||||
nnext[pc0]++;
|
||||
nprev[pc1]++;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class MarkAndMergeVisitor extends BranchVisitor {
|
||||
private final boolean[] isend;
|
||||
|
||||
private MarkAndMergeVisitor(boolean[] isbeg, boolean[] isend) {
|
||||
super(isbeg);
|
||||
this.isend = isend;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitBranch(int pc0, int pc1) {
|
||||
isend[pc0] = true;
|
||||
isbeg[pc1] = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReturn(int pc) {
|
||||
isend[pc] = true;
|
||||
}
|
||||
}
|
||||
|
||||
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 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++) {
|
||||
int ins = code[i];
|
||||
switch (Lua.GET_OPCODE(ins)) {
|
||||
case Lua.OP_LOADBOOL:
|
||||
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);
|
||||
continue;
|
||||
case Lua.OP_EQ:
|
||||
case Lua.OP_LT:
|
||||
case Lua.OP_LE:
|
||||
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);
|
||||
sbx = Lua.GETARG_sBx(code[i+1]);
|
||||
++i;
|
||||
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);
|
||||
continue;
|
||||
case Lua.OP_JMP:
|
||||
case Lua.OP_FORPREP:
|
||||
sbx = Lua.GETARG_sBx(ins);
|
||||
j = i+sbx+1;
|
||||
visitor.visitBranch(i, j);
|
||||
continue;
|
||||
case Lua.OP_TAILCALL:
|
||||
case Lua.OP_RETURN:
|
||||
visitor.visitReturn(i);
|
||||
continue;
|
||||
}
|
||||
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() ) {
|
||||
BasicBlock b = (BasicBlock) next.elementAt(0);
|
||||
next.removeElementAt(0);
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
list.addElement(blocks[i]);
|
||||
|
||||
// convert to array
|
||||
BasicBlock[] array = new BasicBlock[list.size()];
|
||||
list.copyInto(array);
|
||||
return array;
|
||||
}
|
||||
}
|
||||
919
luaj-jse/src/main/java/org/luaj/vm2/luajc/JavaBuilder.java
Normal file
919
luaj-jse/src/main/java/org/luaj/vm2/luajc/JavaBuilder.java
Normal file
@@ -0,0 +1,919 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.luajc;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.bcel.Constants;
|
||||
import org.apache.bcel.generic.AASTORE;
|
||||
import org.apache.bcel.generic.ALOAD;
|
||||
import org.apache.bcel.generic.ANEWARRAY;
|
||||
import org.apache.bcel.generic.ASTORE;
|
||||
import org.apache.bcel.generic.ArrayType;
|
||||
import org.apache.bcel.generic.BranchInstruction;
|
||||
import org.apache.bcel.generic.ClassGen;
|
||||
import org.apache.bcel.generic.CompoundInstruction;
|
||||
import org.apache.bcel.generic.ConstantPoolGen;
|
||||
import org.apache.bcel.generic.FieldGen;
|
||||
import org.apache.bcel.generic.GOTO;
|
||||
import org.apache.bcel.generic.IFEQ;
|
||||
import org.apache.bcel.generic.IFNE;
|
||||
import org.apache.bcel.generic.Instruction;
|
||||
import org.apache.bcel.generic.InstructionConstants;
|
||||
import org.apache.bcel.generic.InstructionFactory;
|
||||
import org.apache.bcel.generic.InstructionHandle;
|
||||
import org.apache.bcel.generic.InstructionList;
|
||||
import org.apache.bcel.generic.LocalVariableGen;
|
||||
import org.apache.bcel.generic.MethodGen;
|
||||
import org.apache.bcel.generic.ObjectType;
|
||||
import org.apache.bcel.generic.PUSH;
|
||||
import org.apache.bcel.generic.Type;
|
||||
import org.luaj.vm2.Buffer;
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.LuaBoolean;
|
||||
import org.luaj.vm2.LuaInteger;
|
||||
import org.luaj.vm2.LuaNumber;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.lib.OneArgFunction;
|
||||
import org.luaj.vm2.lib.ThreeArgFunction;
|
||||
import org.luaj.vm2.lib.TwoArgFunction;
|
||||
import org.luaj.vm2.lib.VarArgFunction;
|
||||
import org.luaj.vm2.lib.ZeroArgFunction;
|
||||
|
||||
public class JavaBuilder {
|
||||
|
||||
private static final String STR_VARARGS = Varargs.class.getName();
|
||||
private static final String STR_LUAVALUE = LuaValue.class.getName();
|
||||
private static final String STR_LUASTRING = LuaString.class.getName();
|
||||
private static final String STR_LUAINTEGER = LuaInteger.class.getName();
|
||||
private static final String STR_LUANUMBER = LuaNumber.class.getName();
|
||||
private static final String STR_LUABOOLEAN = LuaBoolean.class.getName();
|
||||
private static final String STR_LUATABLE = LuaTable.class.getName();
|
||||
private static final String STR_BUFFER = Buffer.class.getName();
|
||||
private static final String STR_STRING = String.class.getName();
|
||||
private static final String STR_JSEPLATFORM = "org.luaj.vm2.lib.jse.JsePlatform";
|
||||
|
||||
private static final ObjectType TYPE_VARARGS = new ObjectType(STR_VARARGS);
|
||||
private static final ObjectType TYPE_LUAVALUE = new ObjectType(STR_LUAVALUE);
|
||||
private static final ObjectType TYPE_LUASTRING = new ObjectType(STR_LUASTRING);
|
||||
private static final ObjectType TYPE_LUAINTEGER = new ObjectType(STR_LUAINTEGER);
|
||||
private static final ObjectType TYPE_LUANUMBER = new ObjectType(STR_LUANUMBER);
|
||||
private static final ObjectType TYPE_LUABOOLEAN = new ObjectType(STR_LUABOOLEAN);
|
||||
private static final ObjectType TYPE_LUATABLE = new ObjectType(STR_LUATABLE);
|
||||
private static final ObjectType TYPE_BUFFER = new ObjectType(STR_BUFFER);
|
||||
private static final ObjectType TYPE_STRING = new ObjectType(STR_STRING);
|
||||
|
||||
private static final ArrayType TYPE_LOCALUPVALUE = new ArrayType(TYPE_LUAVALUE, 1);
|
||||
private static final ArrayType TYPE_CHARARRAY = new ArrayType(Type.CHAR, 1);
|
||||
private static final ArrayType TYPE_STRINGARRAY = new ArrayType(TYPE_STRING, 1);
|
||||
|
||||
private static final String STR_FUNCV = VarArgFunction.class.getName();
|
||||
private static final String STR_FUNC0 = ZeroArgFunction.class.getName();
|
||||
private static final String STR_FUNC1 = OneArgFunction.class.getName();
|
||||
private static final String STR_FUNC2 = TwoArgFunction.class.getName();
|
||||
private static final String STR_FUNC3 = ThreeArgFunction.class.getName();
|
||||
|
||||
// argument list types
|
||||
private static final Type[] ARG_TYPES_NONE = {};
|
||||
private static final Type[] ARG_TYPES_INT = { Type.INT };
|
||||
private static final Type[] ARG_TYPES_DOUBLE = { Type.DOUBLE };
|
||||
private static final Type[] ARG_TYPES_STRING = { Type.STRING };
|
||||
private static final Type[] ARG_TYPES_CHARARRAY = { TYPE_CHARARRAY };
|
||||
private static final Type[] ARG_TYPES_INT_LUAVALUE = { Type.INT, TYPE_LUAVALUE };
|
||||
private static final Type[] ARG_TYPES_INT_VARARGS = { Type.INT, TYPE_VARARGS };
|
||||
private static final Type[] ARG_TYPES_LUAVALUE_VARARGS = { TYPE_LUAVALUE, TYPE_VARARGS };
|
||||
private static final Type[] ARG_TYPES_LUAVALUE_LUAVALUE_VARARGS = { TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_VARARGS };
|
||||
private static final Type[] ARG_TYPES_LUAVALUEARRAY = { new ArrayType(TYPE_LUAVALUE, 1) };
|
||||
private static final Type[] ARG_TYPES_LUAVALUEARRAY_VARARGS = { new ArrayType(TYPE_LUAVALUE, 1),
|
||||
TYPE_VARARGS };
|
||||
private static final Type[] ARG_TYPES_LUAVALUE_LUAVALUE_LUAVALUE = { TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_LUAVALUE };
|
||||
private static final Type[] ARG_TYPES_VARARGS = { TYPE_VARARGS };
|
||||
private static final Type[] ARG_TYPES_LUAVALUE_LUAVALUE = { TYPE_LUAVALUE, TYPE_LUAVALUE };
|
||||
private static final Type[] ARG_TYPES_INT_INT = { Type.INT, Type.INT };
|
||||
private static final Type[] ARG_TYPES_LUAVALUE = { TYPE_LUAVALUE };
|
||||
private static final Type[] ARG_TYPES_BUFFER = { TYPE_BUFFER };
|
||||
private static final Type[] ARG_TYPES_STRINGARRAY = { TYPE_STRINGARRAY };
|
||||
private static final Type[] ARG_TYPES_LUAVALUE_STRINGARRAY = { TYPE_LUAVALUE, TYPE_STRINGARRAY };
|
||||
|
||||
// names, arg types for main prototype classes
|
||||
private static final String[] SUPER_NAME_N = { STR_FUNC0, STR_FUNC1, STR_FUNC2, STR_FUNC3, STR_FUNCV, };
|
||||
private static final ObjectType[] RETURN_TYPE_N = { TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_LUAVALUE,
|
||||
TYPE_VARARGS, };
|
||||
private static final Type[][] ARG_TYPES_N = { ARG_TYPES_NONE, ARG_TYPES_LUAVALUE, ARG_TYPES_LUAVALUE_LUAVALUE,
|
||||
ARG_TYPES_LUAVALUE_LUAVALUE_LUAVALUE, ARG_TYPES_VARARGS, };
|
||||
private static final String[][] ARG_NAMES_N = { {}, { "arg" }, { "arg1", "arg2" }, { "arg1", "arg2", "arg3" },
|
||||
{ "args" }, };
|
||||
private static final String[] METH_NAME_N = { "call", "call", "call", "call", "onInvoke", };
|
||||
|
||||
// varable naming
|
||||
private static final String PREFIX_CONSTANT = "k";
|
||||
private static final String PREFIX_UPVALUE = "u";
|
||||
private static final String PREFIX_PLAIN_SLOT = "s";
|
||||
private static final String PREFIX_UPVALUE_SLOT = "a";
|
||||
private static final String NAME_VARRESULT = "v";
|
||||
|
||||
// basic info
|
||||
private final ProtoInfo pi;
|
||||
private final Prototype p;
|
||||
private final String classname;
|
||||
|
||||
// bcel variables
|
||||
private final ClassGen cg;
|
||||
private final ConstantPoolGen cp;
|
||||
private final InstructionFactory factory;
|
||||
|
||||
// main instruction list for the main function of this class
|
||||
private final InstructionList init;
|
||||
private final InstructionList main;
|
||||
private final MethodGen mg;
|
||||
|
||||
// the superclass arg count, 0-3 args, 4=varargs
|
||||
private int superclassType;
|
||||
private static int SUPERTYPE_VARARGS = 4;
|
||||
|
||||
// storage for goto locations
|
||||
private final int[] targets;
|
||||
private final BranchInstruction[] branches;
|
||||
private final InstructionHandle[] branchDestHandles;
|
||||
private final InstructionHandle[] lastInstrHandles;
|
||||
private InstructionHandle beginningOfLuaInstruction;
|
||||
|
||||
// hold vararg result
|
||||
private LocalVariableGen varresult = null;
|
||||
private int prev_line = -1;
|
||||
|
||||
public JavaBuilder(ProtoInfo pi, String classname, String filename) {
|
||||
this.pi = pi;
|
||||
this.p = pi.prototype;
|
||||
this.classname = classname;
|
||||
|
||||
// what class to inherit from
|
||||
superclassType = p.numparams;
|
||||
if (p.is_vararg != 0 || superclassType >= SUPERTYPE_VARARGS)
|
||||
superclassType = SUPERTYPE_VARARGS;
|
||||
for (int inst : p.code) {
|
||||
int o = Lua.GET_OPCODE(inst);
|
||||
if (o == Lua.OP_TAILCALL || o == Lua.OP_RETURN && (Lua.GETARG_B(inst) < 1 || Lua.GETARG_B(inst) > 2)) {
|
||||
superclassType = SUPERTYPE_VARARGS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// create class generator
|
||||
cg = new ClassGen(classname, SUPER_NAME_N[superclassType], filename, Constants.ACC_PUBLIC | Constants.ACC_SUPER,
|
||||
null);
|
||||
cp = cg.getConstantPool(); // cg creates constant pool
|
||||
|
||||
// main instruction lists
|
||||
factory = new InstructionFactory(cg);
|
||||
init = new InstructionList();
|
||||
main = new InstructionList();
|
||||
|
||||
// create the fields
|
||||
for (int i = 0; i < p.upvalues.length; i++) {
|
||||
boolean isrw = pi.isReadWriteUpvalue(pi.upvals[i]);
|
||||
Type uptype = isrw? (Type) TYPE_LOCALUPVALUE: (Type) TYPE_LUAVALUE;
|
||||
FieldGen fg = new FieldGen(0, uptype, upvalueName(i), cp);
|
||||
cg.addField(fg.getField());
|
||||
}
|
||||
|
||||
// create the method
|
||||
mg = new MethodGen(Constants.ACC_PUBLIC | Constants.ACC_FINAL, // access flags
|
||||
RETURN_TYPE_N[superclassType], // return type
|
||||
ARG_TYPES_N[superclassType], // argument types
|
||||
ARG_NAMES_N[superclassType], // arg names
|
||||
METH_NAME_N[superclassType], STR_LUAVALUE, // method, defining class
|
||||
main, cp);
|
||||
|
||||
// initialize the values in the slots
|
||||
initializeSlots();
|
||||
|
||||
// initialize branching
|
||||
int nc = p.code.length;
|
||||
targets = new int[nc];
|
||||
branches = new BranchInstruction[nc];
|
||||
branchDestHandles = new InstructionHandle[nc];
|
||||
lastInstrHandles = new InstructionHandle[nc];
|
||||
}
|
||||
|
||||
public void initializeSlots() {
|
||||
int slot = 0;
|
||||
createUpvalues(-1, 0, p.maxstacksize);
|
||||
if (superclassType == SUPERTYPE_VARARGS) {
|
||||
for (slot = 0; slot < p.numparams; slot++) {
|
||||
if (pi.isInitialValueUsed(slot)) {
|
||||
append(new ALOAD(1));
|
||||
append(new PUSH(cp, slot+1));
|
||||
append(factory.createInvoke(STR_VARARGS, "arg", TYPE_LUAVALUE, ARG_TYPES_INT,
|
||||
Constants.INVOKEVIRTUAL));
|
||||
storeLocal(-1, slot);
|
||||
}
|
||||
}
|
||||
append(new ALOAD(1));
|
||||
append(new PUSH(cp, 1+p.numparams));
|
||||
append(factory.createInvoke(STR_VARARGS, "subargs", TYPE_VARARGS, ARG_TYPES_INT, Constants.INVOKEVIRTUAL));
|
||||
append(new ASTORE(1));
|
||||
} else {
|
||||
// fixed arg function between 0 and 3 arguments
|
||||
for (slot = 0; slot < p.numparams; slot++) {
|
||||
this.plainSlotVars.put(slot, 1+slot);
|
||||
if (pi.isUpvalueCreate(-1, slot)) {
|
||||
append(new ALOAD(1+slot));
|
||||
storeLocal(-1, slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// nil parameters
|
||||
// TODO: remove this for lua 5.2, not needed
|
||||
for (; slot < p.maxstacksize; slot++) {
|
||||
if (pi.isInitialValueUsed(slot)) {
|
||||
loadNil();
|
||||
storeLocal(-1, slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] completeClass(boolean genmain) {
|
||||
|
||||
// add class initializer
|
||||
if (!init.isEmpty()) {
|
||||
MethodGen mg = new MethodGen(Constants.ACC_STATIC, Type.VOID, ARG_TYPES_NONE, new String[] {}, "<clinit>",
|
||||
cg.getClassName(), init, cg.getConstantPool());
|
||||
init.append(InstructionConstants.RETURN);
|
||||
mg.setMaxStack();
|
||||
cg.addMethod(mg.getMethod());
|
||||
init.dispose();
|
||||
}
|
||||
|
||||
// add default constructor
|
||||
cg.addEmptyConstructor(Constants.ACC_PUBLIC);
|
||||
|
||||
// gen method
|
||||
resolveBranches();
|
||||
mg.setMaxStack();
|
||||
cg.addMethod(mg.getMethod());
|
||||
main.dispose();
|
||||
|
||||
// add initupvalue1(LuaValue env) to initialize environment for main chunk
|
||||
if (p.upvalues.length == 1 && superclassType == SUPERTYPE_VARARGS) {
|
||||
MethodGen mg = new MethodGen(Constants.ACC_PUBLIC | Constants.ACC_FINAL, // access flags
|
||||
Type.VOID, // return type
|
||||
ARG_TYPES_LUAVALUE, // argument types
|
||||
new String[] { "env" }, // arg names
|
||||
"initupvalue1", STR_LUAVALUE, // method, defining class
|
||||
main, cp);
|
||||
boolean isrw = pi.isReadWriteUpvalue(pi.upvals[0]);
|
||||
append(InstructionConstants.THIS);
|
||||
append(new ALOAD(1));
|
||||
if (isrw) {
|
||||
append(factory.createInvoke(classname, "newupl", TYPE_LOCALUPVALUE, ARG_TYPES_LUAVALUE,
|
||||
Constants.INVOKESTATIC));
|
||||
append(factory.createFieldAccess(classname, upvalueName(0), TYPE_LOCALUPVALUE, Constants.PUTFIELD));
|
||||
} else {
|
||||
append(factory.createFieldAccess(classname, upvalueName(0), TYPE_LUAVALUE, Constants.PUTFIELD));
|
||||
}
|
||||
append(InstructionConstants.RETURN);
|
||||
mg.setMaxStack();
|
||||
cg.addMethod(mg.getMethod());
|
||||
main.dispose();
|
||||
}
|
||||
|
||||
// add main function so class is invokable from the java command line
|
||||
if (genmain) {
|
||||
MethodGen mg = new MethodGen(Constants.ACC_PUBLIC | Constants.ACC_STATIC, // access flags
|
||||
Type.VOID, // return type
|
||||
ARG_TYPES_STRINGARRAY, // argument types
|
||||
new String[] { "arg" }, // arg names
|
||||
"main", classname, // method, defining class
|
||||
main, cp);
|
||||
append(factory.createNew(classname));
|
||||
append(InstructionConstants.DUP);
|
||||
append(factory.createInvoke(classname, Constants.CONSTRUCTOR_NAME, Type.VOID, ARG_TYPES_NONE,
|
||||
Constants.INVOKESPECIAL));
|
||||
append(new ALOAD(0));
|
||||
append(factory.createInvoke(STR_JSEPLATFORM, "luaMain", Type.VOID, ARG_TYPES_LUAVALUE_STRINGARRAY,
|
||||
Constants.INVOKESTATIC));
|
||||
append(InstructionConstants.RETURN);
|
||||
mg.setMaxStack();
|
||||
cg.addMethod(mg.getMethod());
|
||||
main.dispose();
|
||||
}
|
||||
|
||||
// convert to class bytes
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
cg.getJavaClass().dump(baos);
|
||||
return baos.toByteArray();
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException("JavaClass.dump() threw " + ioe);
|
||||
}
|
||||
}
|
||||
|
||||
public void dup() {
|
||||
append(InstructionConstants.DUP);
|
||||
}
|
||||
|
||||
public void pop() {
|
||||
append(InstructionConstants.POP);
|
||||
}
|
||||
|
||||
public void loadNil() {
|
||||
append(factory.createFieldAccess(STR_LUAVALUE, "NIL", TYPE_LUAVALUE, Constants.GETSTATIC));
|
||||
}
|
||||
|
||||
public void loadNone() {
|
||||
append(factory.createFieldAccess(STR_LUAVALUE, "NONE", TYPE_LUAVALUE, Constants.GETSTATIC));
|
||||
}
|
||||
|
||||
public void loadBoolean(boolean b) {
|
||||
String field = b? "TRUE": "FALSE";
|
||||
append(factory.createFieldAccess(STR_LUAVALUE, field, TYPE_LUABOOLEAN, Constants.GETSTATIC));
|
||||
}
|
||||
|
||||
private final Map<Integer, Integer> plainSlotVars = new HashMap<>();
|
||||
private final Map<Integer, Integer> upvalueSlotVars = new HashMap<>();
|
||||
private final Map<Integer, LocalVariableGen> localVarGenBySlot = new HashMap<>();
|
||||
|
||||
private int findSlot(int slot, Map<Integer, Integer> map, String prefix, Type type) {
|
||||
Integer islot = slot;
|
||||
if (map.containsKey(islot))
|
||||
return map.get(islot).intValue();
|
||||
String name = prefix+slot;
|
||||
LocalVariableGen local = mg.addLocalVariable(name, type, null, null);
|
||||
int index = local.getIndex();
|
||||
map.put(islot, index);
|
||||
localVarGenBySlot.put(islot, local);
|
||||
return index;
|
||||
}
|
||||
|
||||
private int findSlotIndex(int slot, boolean isupvalue) {
|
||||
return isupvalue? findSlot(slot, upvalueSlotVars, PREFIX_UPVALUE_SLOT, TYPE_LOCALUPVALUE)
|
||||
: findSlot(slot, plainSlotVars, PREFIX_PLAIN_SLOT, TYPE_LUAVALUE);
|
||||
}
|
||||
|
||||
public void loadLocal(int pc, int slot) {
|
||||
boolean isupval = pi.isUpvalueRefer(pc, slot);
|
||||
int index = findSlotIndex(slot, isupval);
|
||||
append(new ALOAD(index));
|
||||
if (isupval) {
|
||||
append(new PUSH(cp, 0));
|
||||
append(InstructionConstants.AALOAD);
|
||||
}
|
||||
}
|
||||
|
||||
public void storeLocal(int pc, int slot) {
|
||||
boolean isupval = pi.isUpvalueAssign(pc, slot);
|
||||
int index = findSlotIndex(slot, isupval);
|
||||
if (isupval) {
|
||||
boolean isupcreate = pi.isUpvalueCreate(pc, slot);
|
||||
if (isupcreate) {
|
||||
append(factory.createInvoke(classname, "newupe", TYPE_LOCALUPVALUE, ARG_TYPES_NONE,
|
||||
Constants.INVOKESTATIC));
|
||||
append(InstructionConstants.DUP);
|
||||
append(new ASTORE(index));
|
||||
} else {
|
||||
append(new ALOAD(index));
|
||||
}
|
||||
append(InstructionConstants.SWAP);
|
||||
append(new PUSH(cp, 0));
|
||||
append(InstructionConstants.SWAP);
|
||||
append(InstructionConstants.AASTORE);
|
||||
} else {
|
||||
append(new ASTORE(index));
|
||||
}
|
||||
}
|
||||
|
||||
public void createUpvalues(int pc, int firstslot, int numslots) {
|
||||
for (int i = 0; i < numslots; i++) {
|
||||
int slot = firstslot+i;
|
||||
boolean isupcreate = pi.isUpvalueCreate(pc, slot);
|
||||
if (isupcreate) {
|
||||
int index = findSlotIndex(slot, true);
|
||||
append(factory.createInvoke(classname, "newupn", TYPE_LOCALUPVALUE, ARG_TYPES_NONE,
|
||||
Constants.INVOKESTATIC));
|
||||
append(new ASTORE(index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void convertToUpvalue(int pc, int slot) {
|
||||
boolean isupassign = pi.isUpvalueAssign(pc, slot);
|
||||
if (isupassign) {
|
||||
int index = findSlotIndex(slot, false);
|
||||
append(new ALOAD(index));
|
||||
append(factory.createInvoke(classname, "newupl", TYPE_LOCALUPVALUE, ARG_TYPES_LUAVALUE,
|
||||
Constants.INVOKESTATIC));
|
||||
int upindex = findSlotIndex(slot, true);
|
||||
append(new ASTORE(upindex));
|
||||
}
|
||||
}
|
||||
|
||||
private static String upvalueName(int upindex) {
|
||||
return PREFIX_UPVALUE+upindex;
|
||||
}
|
||||
|
||||
public void loadUpvalue(int upindex) {
|
||||
boolean isrw = pi.isReadWriteUpvalue(pi.upvals[upindex]);
|
||||
append(InstructionConstants.THIS);
|
||||
if (isrw) {
|
||||
append(factory.createFieldAccess(classname, upvalueName(upindex), TYPE_LOCALUPVALUE, Constants.GETFIELD));
|
||||
append(new PUSH(cp, 0));
|
||||
append(InstructionConstants.AALOAD);
|
||||
} else {
|
||||
append(factory.createFieldAccess(classname, upvalueName(upindex), TYPE_LUAVALUE, Constants.GETFIELD));
|
||||
}
|
||||
}
|
||||
|
||||
public void storeUpvalue(int pc, int upindex, int slot) {
|
||||
boolean isrw = pi.isReadWriteUpvalue(pi.upvals[upindex]);
|
||||
append(InstructionConstants.THIS);
|
||||
if (isrw) {
|
||||
append(factory.createFieldAccess(classname, upvalueName(upindex), TYPE_LOCALUPVALUE, Constants.GETFIELD));
|
||||
append(new PUSH(cp, 0));
|
||||
loadLocal(pc, slot);
|
||||
append(InstructionConstants.AASTORE);
|
||||
} else {
|
||||
loadLocal(pc, slot);
|
||||
append(factory.createFieldAccess(classname, upvalueName(upindex), TYPE_LUAVALUE, Constants.PUTFIELD));
|
||||
}
|
||||
}
|
||||
|
||||
public void newTable(int b, int c) {
|
||||
append(new PUSH(cp, b));
|
||||
append(new PUSH(cp, c));
|
||||
append(factory.createInvoke(STR_LUAVALUE, "tableOf", TYPE_LUATABLE, ARG_TYPES_INT_INT, Constants.INVOKESTATIC));
|
||||
}
|
||||
|
||||
public void loadVarargs() {
|
||||
append(new ALOAD(1));
|
||||
}
|
||||
|
||||
public void loadVarargs(int argindex) {
|
||||
loadVarargs();
|
||||
arg(argindex);
|
||||
}
|
||||
|
||||
public void arg(int argindex) {
|
||||
if (argindex == 1) {
|
||||
append(factory.createInvoke(STR_VARARGS, "arg1", TYPE_LUAVALUE, ARG_TYPES_NONE, Constants.INVOKEVIRTUAL));
|
||||
} else {
|
||||
append(new PUSH(cp, argindex));
|
||||
append(factory.createInvoke(STR_VARARGS, "arg", TYPE_LUAVALUE, ARG_TYPES_INT, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
}
|
||||
|
||||
private int getVarresultIndex() {
|
||||
if (varresult == null)
|
||||
varresult = mg.addLocalVariable(NAME_VARRESULT, TYPE_VARARGS, null, null);
|
||||
return varresult.getIndex();
|
||||
}
|
||||
|
||||
public void loadVarresult() {
|
||||
append(new ALOAD(getVarresultIndex()));
|
||||
}
|
||||
|
||||
public void storeVarresult() {
|
||||
append(new ASTORE(getVarresultIndex()));
|
||||
}
|
||||
|
||||
public void subargs(int firstarg) {
|
||||
append(new PUSH(cp, firstarg));
|
||||
append(factory.createInvoke(STR_VARARGS, "subargs", TYPE_VARARGS, ARG_TYPES_INT, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void getTable() {
|
||||
append(factory.createInvoke(STR_LUAVALUE, "get", TYPE_LUAVALUE, ARG_TYPES_LUAVALUE, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void setTable() {
|
||||
append(
|
||||
factory.createInvoke(STR_LUAVALUE, "set", Type.VOID, ARG_TYPES_LUAVALUE_LUAVALUE, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void unaryop(int o) {
|
||||
String op;
|
||||
switch (o) {
|
||||
default:
|
||||
case Lua.OP_UNM:
|
||||
op = "neg";
|
||||
break;
|
||||
case Lua.OP_NOT:
|
||||
op = "not";
|
||||
break;
|
||||
case Lua.OP_LEN:
|
||||
op = "len";
|
||||
break;
|
||||
}
|
||||
append(factory.createInvoke(STR_LUAVALUE, op, TYPE_LUAVALUE, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void binaryop(int o) {
|
||||
String op;
|
||||
switch (o) {
|
||||
default:
|
||||
case Lua.OP_ADD:
|
||||
op = "add";
|
||||
break;
|
||||
case Lua.OP_SUB:
|
||||
op = "sub";
|
||||
break;
|
||||
case Lua.OP_MUL:
|
||||
op = "mul";
|
||||
break;
|
||||
case Lua.OP_DIV:
|
||||
op = "div";
|
||||
break;
|
||||
case Lua.OP_MOD:
|
||||
op = "mod";
|
||||
break;
|
||||
case Lua.OP_POW:
|
||||
op = "pow";
|
||||
break;
|
||||
}
|
||||
append(factory.createInvoke(STR_LUAVALUE, op, TYPE_LUAVALUE, ARG_TYPES_LUAVALUE, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void compareop(int o) {
|
||||
String op;
|
||||
switch (o) {
|
||||
default:
|
||||
case Lua.OP_EQ:
|
||||
op = "eq_b";
|
||||
break;
|
||||
case Lua.OP_LT:
|
||||
op = "lt_b";
|
||||
break;
|
||||
case Lua.OP_LE:
|
||||
op = "lteq_b";
|
||||
break;
|
||||
}
|
||||
append(factory.createInvoke(STR_LUAVALUE, op, Type.BOOLEAN, ARG_TYPES_LUAVALUE, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void areturn() {
|
||||
append(InstructionConstants.ARETURN);
|
||||
}
|
||||
|
||||
public void toBoolean() {
|
||||
append(factory.createInvoke(STR_LUAVALUE, "toboolean", Type.BOOLEAN, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void tostring() {
|
||||
append(factory.createInvoke(STR_BUFFER, "tostring", TYPE_LUASTRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void isNil() {
|
||||
append(factory.createInvoke(STR_LUAVALUE, "isnil", Type.BOOLEAN, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void testForLoop() {
|
||||
append(factory.createInvoke(STR_LUAVALUE, "testfor_b", Type.BOOLEAN, ARG_TYPES_LUAVALUE_LUAVALUE,
|
||||
Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void loadArrayArgs(int pc, int firstslot, int nargs) {
|
||||
append(new PUSH(cp, nargs));
|
||||
append(new ANEWARRAY(cp.addClass(STR_LUAVALUE)));
|
||||
for (int i = 0; i < nargs; i++) {
|
||||
append(InstructionConstants.DUP);
|
||||
append(new PUSH(cp, i));
|
||||
loadLocal(pc, firstslot++);
|
||||
append(new AASTORE());
|
||||
}
|
||||
}
|
||||
|
||||
public void newVarargs(int pc, int firstslot, int nargs) {
|
||||
switch (nargs) {
|
||||
case 0:
|
||||
loadNone();
|
||||
break;
|
||||
case 1:
|
||||
loadLocal(pc, firstslot);
|
||||
break;
|
||||
case 2:
|
||||
loadLocal(pc, firstslot);
|
||||
loadLocal(pc, firstslot+1);
|
||||
append(factory.createInvoke(STR_LUAVALUE, "varargsOf", TYPE_VARARGS, ARG_TYPES_LUAVALUE_VARARGS,
|
||||
Constants.INVOKESTATIC));
|
||||
break;
|
||||
case 3:
|
||||
loadLocal(pc, firstslot);
|
||||
loadLocal(pc, firstslot+1);
|
||||
loadLocal(pc, firstslot+2);
|
||||
append(factory.createInvoke(STR_LUAVALUE, "varargsOf", TYPE_VARARGS, ARG_TYPES_LUAVALUE_LUAVALUE_VARARGS,
|
||||
Constants.INVOKESTATIC));
|
||||
break;
|
||||
default:
|
||||
loadArrayArgs(pc, firstslot, nargs);
|
||||
append(factory.createInvoke(STR_LUAVALUE, "varargsOf", TYPE_VARARGS, ARG_TYPES_LUAVALUEARRAY,
|
||||
Constants.INVOKESTATIC));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void newVarargsVarresult(int pc, int firstslot, int nslots) {
|
||||
loadArrayArgs(pc, firstslot, nslots);
|
||||
loadVarresult();
|
||||
append(factory.createInvoke(STR_LUAVALUE, "varargsOf", TYPE_VARARGS, ARG_TYPES_LUAVALUEARRAY_VARARGS,
|
||||
Constants.INVOKESTATIC));
|
||||
}
|
||||
|
||||
public void call(int nargs) {
|
||||
switch (nargs) {
|
||||
case 0:
|
||||
append(factory.createInvoke(STR_LUAVALUE, "call", TYPE_LUAVALUE, ARG_TYPES_NONE, Constants.INVOKEVIRTUAL));
|
||||
break;
|
||||
case 1:
|
||||
append(
|
||||
factory.createInvoke(STR_LUAVALUE, "call", TYPE_LUAVALUE, ARG_TYPES_LUAVALUE, Constants.INVOKEVIRTUAL));
|
||||
break;
|
||||
case 2:
|
||||
append(factory.createInvoke(STR_LUAVALUE, "call", TYPE_LUAVALUE, ARG_TYPES_LUAVALUE_LUAVALUE,
|
||||
Constants.INVOKEVIRTUAL));
|
||||
break;
|
||||
case 3:
|
||||
append(factory.createInvoke(STR_LUAVALUE, "call", TYPE_LUAVALUE, ARG_TYPES_LUAVALUE_LUAVALUE_LUAVALUE,
|
||||
Constants.INVOKEVIRTUAL));
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("can't call with " + nargs + " args");
|
||||
}
|
||||
}
|
||||
|
||||
public void newTailcallVarargs() {
|
||||
append(factory.createInvoke(STR_LUAVALUE, "tailcallOf", TYPE_VARARGS, ARG_TYPES_LUAVALUE_VARARGS,
|
||||
Constants.INVOKESTATIC));
|
||||
}
|
||||
|
||||
public void invoke(int nargs) {
|
||||
switch (nargs) {
|
||||
case -1:
|
||||
append(
|
||||
factory.createInvoke(STR_LUAVALUE, "invoke", TYPE_VARARGS, ARG_TYPES_VARARGS, Constants.INVOKEVIRTUAL));
|
||||
break;
|
||||
case 0:
|
||||
append(factory.createInvoke(STR_LUAVALUE, "invoke", TYPE_VARARGS, ARG_TYPES_NONE, Constants.INVOKEVIRTUAL));
|
||||
break;
|
||||
case 1:
|
||||
append(
|
||||
factory.createInvoke(STR_LUAVALUE, "invoke", TYPE_VARARGS, ARG_TYPES_VARARGS, Constants.INVOKEVIRTUAL));
|
||||
break;
|
||||
case 2:
|
||||
append(factory.createInvoke(STR_LUAVALUE, "invoke", TYPE_VARARGS, ARG_TYPES_LUAVALUE_VARARGS,
|
||||
Constants.INVOKEVIRTUAL));
|
||||
break;
|
||||
case 3:
|
||||
append(factory.createInvoke(STR_LUAVALUE, "invoke", TYPE_VARARGS, ARG_TYPES_LUAVALUE_LUAVALUE_VARARGS,
|
||||
Constants.INVOKEVIRTUAL));
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("can't invoke with " + nargs + " args");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------ closures ------------------------
|
||||
|
||||
public void closureCreate(String protoname) {
|
||||
append(factory.createNew(new ObjectType(protoname)));
|
||||
append(InstructionConstants.DUP);
|
||||
append(factory.createInvoke(protoname, "<init>", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL));
|
||||
}
|
||||
|
||||
public void closureInitUpvalueFromUpvalue(String protoname, int newup, int upindex) {
|
||||
boolean isrw = pi.isReadWriteUpvalue(pi.upvals[upindex]);
|
||||
Type uptype = isrw? (Type) TYPE_LOCALUPVALUE: (Type) TYPE_LUAVALUE;
|
||||
String srcname = upvalueName(upindex);
|
||||
String destname = upvalueName(newup);
|
||||
append(InstructionConstants.THIS);
|
||||
append(factory.createFieldAccess(classname, srcname, uptype, Constants.GETFIELD));
|
||||
append(factory.createFieldAccess(protoname, destname, uptype, Constants.PUTFIELD));
|
||||
}
|
||||
|
||||
public void closureInitUpvalueFromLocal(String protoname, int newup, int pc, int srcslot) {
|
||||
boolean isrw = pi.isReadWriteUpvalue(pi.vars[srcslot][pc].upvalue);
|
||||
Type uptype = isrw? (Type) TYPE_LOCALUPVALUE: (Type) TYPE_LUAVALUE;
|
||||
String destname = upvalueName(newup);
|
||||
int index = findSlotIndex(srcslot, isrw);
|
||||
append(new ALOAD(index));
|
||||
append(factory.createFieldAccess(protoname, destname, uptype, Constants.PUTFIELD));
|
||||
}
|
||||
|
||||
private final Map<LuaValue, String> constants = new HashMap<>();
|
||||
|
||||
public void loadConstant(LuaValue value) {
|
||||
switch (value.type()) {
|
||||
case LuaValue.TNIL:
|
||||
loadNil();
|
||||
break;
|
||||
case LuaValue.TBOOLEAN:
|
||||
loadBoolean(value.toboolean());
|
||||
break;
|
||||
case LuaValue.TNUMBER:
|
||||
case LuaValue.TSTRING:
|
||||
String name = constants.get(value);
|
||||
if (name == null) {
|
||||
name = value.type() == LuaValue.TNUMBER? value.isinttype()? createLuaIntegerField(value.checkint())
|
||||
: createLuaDoubleField(value.checkdouble()): createLuaStringField(value.checkstring());
|
||||
constants.put(value, name);
|
||||
}
|
||||
append(factory.createGetStatic(classname, name, TYPE_LUAVALUE));
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("bad constant type: " + value.type());
|
||||
}
|
||||
}
|
||||
|
||||
private String createLuaIntegerField(int value) {
|
||||
String name = PREFIX_CONSTANT+constants.size();
|
||||
FieldGen fg = new FieldGen(Constants.ACC_STATIC | Constants.ACC_FINAL, TYPE_LUAVALUE, name, cp);
|
||||
cg.addField(fg.getField());
|
||||
init.append(new PUSH(cp, value));
|
||||
init.append(
|
||||
factory.createInvoke(STR_LUAVALUE, "valueOf", TYPE_LUAINTEGER, ARG_TYPES_INT, Constants.INVOKESTATIC));
|
||||
init.append(factory.createPutStatic(classname, name, TYPE_LUAVALUE));
|
||||
return name;
|
||||
}
|
||||
|
||||
private String createLuaDoubleField(double value) {
|
||||
String name = PREFIX_CONSTANT+constants.size();
|
||||
FieldGen fg = new FieldGen(Constants.ACC_STATIC | Constants.ACC_FINAL, TYPE_LUAVALUE, name, cp);
|
||||
cg.addField(fg.getField());
|
||||
init.append(new PUSH(cp, value));
|
||||
init.append(
|
||||
factory.createInvoke(STR_LUAVALUE, "valueOf", TYPE_LUANUMBER, ARG_TYPES_DOUBLE, Constants.INVOKESTATIC));
|
||||
init.append(factory.createPutStatic(classname, name, TYPE_LUAVALUE));
|
||||
return name;
|
||||
}
|
||||
|
||||
private String createLuaStringField(LuaString value) {
|
||||
String name = PREFIX_CONSTANT+constants.size();
|
||||
FieldGen fg = new FieldGen(Constants.ACC_STATIC | Constants.ACC_FINAL, TYPE_LUAVALUE, name, cp);
|
||||
cg.addField(fg.getField());
|
||||
LuaString ls = value.checkstring();
|
||||
if (ls.isValidUtf8()) {
|
||||
init.append(new PUSH(cp, value.tojstring()));
|
||||
init.append(factory.createInvoke(STR_LUASTRING, "valueOf", TYPE_LUASTRING, ARG_TYPES_STRING,
|
||||
Constants.INVOKESTATIC));
|
||||
} else {
|
||||
char[] c = new char[ls.m_length];
|
||||
for (int j = 0; j < ls.m_length; j++)
|
||||
c[j] = (char) (0xff & ls.m_bytes[ls.m_offset+j]);
|
||||
init.append(new PUSH(cp, new String(c)));
|
||||
init.append(
|
||||
factory.createInvoke(STR_STRING, "toCharArray", TYPE_CHARARRAY, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
|
||||
init.append(factory.createInvoke(STR_LUASTRING, "valueOf", TYPE_LUASTRING, ARG_TYPES_CHARARRAY,
|
||||
Constants.INVOKESTATIC));
|
||||
}
|
||||
init.append(factory.createPutStatic(classname, name, TYPE_LUAVALUE));
|
||||
return name;
|
||||
}
|
||||
|
||||
// --------------------- branching support -------------------------
|
||||
public static final int BRANCH_GOTO = 1;
|
||||
public static final int BRANCH_IFNE = 2;
|
||||
public static final int BRANCH_IFEQ = 3;
|
||||
|
||||
public void addBranch(int pc, int branchType, int targetpc) {
|
||||
switch (branchType) {
|
||||
default:
|
||||
case BRANCH_GOTO:
|
||||
branches[pc] = new GOTO(null);
|
||||
break;
|
||||
case BRANCH_IFNE:
|
||||
branches[pc] = new IFNE(null);
|
||||
break;
|
||||
case BRANCH_IFEQ:
|
||||
branches[pc] = new IFEQ(null);
|
||||
break;
|
||||
}
|
||||
targets[pc] = targetpc;
|
||||
append(branches[pc]);
|
||||
}
|
||||
|
||||
private void append(Instruction i) {
|
||||
conditionalSetBeginningOfLua(main.append(i));
|
||||
}
|
||||
|
||||
private void append(CompoundInstruction i) {
|
||||
conditionalSetBeginningOfLua(main.append(i));
|
||||
}
|
||||
|
||||
private void append(BranchInstruction i) {
|
||||
conditionalSetBeginningOfLua(main.append(i));
|
||||
}
|
||||
|
||||
private void conditionalSetBeginningOfLua(InstructionHandle ih) {
|
||||
if (beginningOfLuaInstruction == null)
|
||||
beginningOfLuaInstruction = ih;
|
||||
}
|
||||
|
||||
public void onEndOfLuaInstruction(int pc, int line) {
|
||||
branchDestHandles[pc] = beginningOfLuaInstruction;
|
||||
lastInstrHandles[pc] = main.getEnd();
|
||||
if (line != prev_line)
|
||||
mg.addLineNumber(beginningOfLuaInstruction, prev_line = line);
|
||||
beginningOfLuaInstruction = null;
|
||||
}
|
||||
|
||||
public void setVarStartEnd(int slot, int start_pc, int end_pc, String name) {
|
||||
Integer islot = slot;
|
||||
if (localVarGenBySlot.containsKey(islot)) {
|
||||
name = name.replaceAll("[^a-zA-Z0-9]", "_");
|
||||
LocalVariableGen l = localVarGenBySlot.get(islot);
|
||||
l.setEnd(lastInstrHandles[end_pc-1]);
|
||||
if (start_pc > 1)
|
||||
l.setStart(lastInstrHandles[start_pc-2]);
|
||||
l.setName(name);
|
||||
}
|
||||
}
|
||||
|
||||
private void resolveBranches() {
|
||||
int nc = p.code.length;
|
||||
for (int pc = 0; pc < nc; pc++) {
|
||||
if (branches[pc] != null) {
|
||||
int t = targets[pc];
|
||||
while ( t < branchDestHandles.length && branchDestHandles[t] == null )
|
||||
t++;
|
||||
if (t >= branchDestHandles.length)
|
||||
throw new IllegalArgumentException(
|
||||
"no target at or after " + targets[pc] + " op=" + Lua.GET_OPCODE(p.code[targets[pc]]));
|
||||
branches[pc].setTarget(branchDestHandles[t]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setlistStack(int pc, int a0, int index0, int nvals) {
|
||||
for (int i = 0; i < nvals; i++) {
|
||||
dup();
|
||||
append(new PUSH(cp, index0+i));
|
||||
loadLocal(pc, a0+i);
|
||||
append(factory.createInvoke(STR_LUAVALUE, "rawset", Type.VOID, ARG_TYPES_INT_LUAVALUE,
|
||||
Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
}
|
||||
|
||||
public void setlistVarargs(int index0, int vresultbase) {
|
||||
append(new PUSH(cp, index0));
|
||||
loadVarresult();
|
||||
append(factory.createInvoke(STR_LUAVALUE, "rawsetlist", Type.VOID, ARG_TYPES_INT_VARARGS,
|
||||
Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void concatvalue() {
|
||||
append(
|
||||
factory.createInvoke(STR_LUAVALUE, "concat", TYPE_LUAVALUE, ARG_TYPES_LUAVALUE, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void concatbuffer() {
|
||||
append(factory.createInvoke(STR_LUAVALUE, "concat", TYPE_BUFFER, ARG_TYPES_BUFFER, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void tobuffer() {
|
||||
append(factory.createInvoke(STR_LUAVALUE, "buffer", TYPE_BUFFER, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void tovalue() {
|
||||
append(factory.createInvoke(STR_BUFFER, "value", TYPE_LUAVALUE, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void closeUpvalue(int pc, int upindex) {
|
||||
// TODO: assign the upvalue location the value null;
|
||||
/*
|
||||
boolean isrw = pi.isReadWriteUpvalue( pi.upvals[upindex] );
|
||||
append(InstructionConstants.THIS);
|
||||
append(InstructionConstants.ACONST_NULL);
|
||||
if ( isrw ) {
|
||||
append(factory.createFieldAccess(classname, upvalueName(upindex), TYPE_LUAVALUEARRAY, Constants.PUTFIELD));
|
||||
} else {
|
||||
append(factory.createFieldAccess(classname, upvalueName(upindex), TYPE_LUAVALUE, Constants.PUTFIELD));
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
454
luaj-jse/src/main/java/org/luaj/vm2/luajc/JavaGen.java
Normal file
454
luaj-jse/src/main/java/org/luaj/vm2/luajc/JavaGen.java
Normal file
@@ -0,0 +1,454 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.luajc;
|
||||
|
||||
import org.luaj.vm2.LocVars;
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.Upvaldesc;
|
||||
|
||||
/**
|
||||
* TODO: propogate constants loader can find inner classes
|
||||
*/
|
||||
public class JavaGen {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
for (int i = 0; i < pi.prototype.locvars.length; ++i) {
|
||||
LocVars l = pi.prototype.locvars[i];
|
||||
builder.setVarStartEnd(i, l.startpc, l.endpc, l.varname.tojstring());
|
||||
}
|
||||
this.bytecode = builder.completeClass(genmain);
|
||||
|
||||
// build sub-prototypes
|
||||
if (pi.subprotos != null) {
|
||||
int n = pi.subprotos.length;
|
||||
inners = new JavaGen[n];
|
||||
for (int i = 0; i < n; i++)
|
||||
inners[i] = new JavaGen(pi.subprotos[i], pi.subprotos[i].name, filename, false);
|
||||
} else {
|
||||
inners = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void scanInstructions(ProtoInfo pi, String classname, JavaBuilder builder) {
|
||||
Prototype p = pi.prototype;
|
||||
int vresultbase = -1;
|
||||
|
||||
for (BasicBlock b0 : pi.blocklist) {
|
||||
// convert upvalues that are phi-variables
|
||||
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())
|
||||
builder.convertToUpvalue(pc, slot);
|
||||
}
|
||||
|
||||
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;
|
||||
final int o = Lua.GET_OPCODE(ins);
|
||||
int a = Lua.GETARG_A(ins);
|
||||
int b = Lua.GETARG_B(ins);
|
||||
int bx = Lua.GETARG_Bx(ins);
|
||||
int sbx = Lua.GETARG_sBx(ins);
|
||||
int c = Lua.GETARG_C(ins);
|
||||
|
||||
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);
|
||||
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);
|
||||
break;
|
||||
|
||||
case Lua.OP_LOADK:/* A Bx R(A):= Kst(Bx) */
|
||||
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)
|
||||
builder.dup();
|
||||
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.getTable();
|
||||
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.getTable();
|
||||
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.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.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);
|
||||
break;
|
||||
|
||||
case Lua.OP_SELF: /* A B C R(A+1):= R(B): R(A):= R(B)[RK(C)] */
|
||||
builder.loadLocal(pc, b);
|
||||
builder.dup();
|
||||
builder.storeLocal(pc, a+1);
|
||||
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) {
|
||||
builder.tobuffer();
|
||||
for (int k = c; --k >= b;)
|
||||
builder.concatbuffer();
|
||||
builder.tovalue();
|
||||
} else {
|
||||
builder.concatvalue();
|
||||
}
|
||||
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.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) {
|
||||
builder.closeUpvalue(pc, i);
|
||||
}
|
||||
}
|
||||
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);
|
||||
builder.compareop(o);
|
||||
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);
|
||||
builder.toBoolean();
|
||||
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.toBoolean();
|
||||
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++)
|
||||
builder.loadLocal(pc, a+i);
|
||||
break;
|
||||
default: // fixed arg count > 3
|
||||
builder.newVarargs(pc, a+1, b-1);
|
||||
narg = -1;
|
||||
break;
|
||||
case -1: // prev vararg result
|
||||
loadVarargResults(builder, pc, a+1, vresultbase);
|
||||
narg = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
// call or invoke
|
||||
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();
|
||||
break;
|
||||
case 2:
|
||||
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)
|
||||
builder.dup();
|
||||
builder.arg(i);
|
||||
builder.storeLocal(pc, a+i-1);
|
||||
}
|
||||
break;
|
||||
case 0: // vararg result
|
||||
vresultbase = a;
|
||||
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:
|
||||
builder.loadNone();
|
||||
break;
|
||||
case 2:
|
||||
builder.loadLocal(pc, a+1);
|
||||
break;
|
||||
default: // fixed arg count > 1
|
||||
builder.newVarargs(pc, a+1, b-1);
|
||||
break;
|
||||
case 0: // prev vararg result
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
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.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.dup();
|
||||
builder.dup();
|
||||
builder.storeLocal(pc, a);
|
||||
builder.storeLocal(pc, a+3);
|
||||
builder.loadLocal(pc, a+1); // limit
|
||||
builder.loadLocal(pc, a+2); // step
|
||||
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)
|
||||
builder.dup();
|
||||
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();
|
||||
builder.storeLocal(pc, a);
|
||||
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);
|
||||
index0 += nstack;
|
||||
}
|
||||
builder.setlistVarargs(index0, vresultbase);
|
||||
} else {
|
||||
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.dup();
|
||||
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);
|
||||
else
|
||||
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) {
|
||||
builder.loadVarargs();
|
||||
builder.storeVarresult();
|
||||
vresultbase = a;
|
||||
} else {
|
||||
for (int i = 1; i < b; ++a, ++i) {
|
||||
builder.loadVarargs(i);
|
||||
builder.storeLocal(pc, a);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// let builder process branch instructions
|
||||
builder.onEndOfLuaInstruction(pc0, line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadVarargResults(JavaBuilder builder, int pc, int a, int vresultbase) {
|
||||
if (vresultbase <= a) {
|
||||
builder.loadVarresult();
|
||||
builder.subargs(a+1-vresultbase);
|
||||
} else if (vresultbase == a) {
|
||||
builder.loadVarresult();
|
||||
} else {
|
||||
builder.newVarargsVarresult(pc, a, vresultbase-a);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadLocalOrConstant(Prototype p, JavaBuilder builder, int pc, int borc) {
|
||||
if (borc <= 0xff)
|
||||
builder.loadLocal(pc, borc);
|
||||
else
|
||||
builder.loadConstant(p.k[borc & 0xff]);
|
||||
}
|
||||
}
|
||||
74
luaj-jse/src/main/java/org/luaj/vm2/luajc/JavaLoader.java
Normal file
74
luaj-jse/src/main/java/org/luaj/vm2/luajc/JavaLoader.java
Normal file
@@ -0,0 +1,74 @@
|
||||
package org.luaj.vm2.luajc;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.luaj.vm2.LuaFunction;
|
||||
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.
|
||||
******************************************************************************/
|
||||
public class JavaLoader extends ClassLoader {
|
||||
|
||||
private final Map<String, byte[]> unloaded = new HashMap<>();
|
||||
|
||||
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(JavaGen jg, LuaValue env) {
|
||||
include(jg);
|
||||
return load(jg.classname, env);
|
||||
}
|
||||
|
||||
public LuaFunction load(String classname, LuaValue env) {
|
||||
try {
|
||||
Class c = loadClass(classname);
|
||||
LuaFunction v = (LuaFunction) c.newInstance();
|
||||
v.initupvalue1(env);
|
||||
return v;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
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]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class findClass(String classname) throws ClassNotFoundException {
|
||||
byte[] bytes = unloaded.get(classname);
|
||||
if (bytes != null)
|
||||
return defineClass(classname, bytes, 0, bytes.length);
|
||||
return super.findClass(classname);
|
||||
}
|
||||
|
||||
}
|
||||
138
luaj-jse/src/main/java/org/luaj/vm2/luajc/LuaJC.java
Normal file
138
luaj-jse/src/main/java/org/luaj/vm2/luajc/LuaJC.java
Normal file
@@ -0,0 +1,138 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.luajc;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaClosure;
|
||||
import org.luaj.vm2.LuaFunction;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
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.
|
||||
* <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}.
|
||||
* <p>
|
||||
* 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>
|
||||
* <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.
|
||||
*
|
||||
* @see Globals#compiler
|
||||
* @see #install(Globals)
|
||||
* @see 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.
|
||||
*/
|
||||
public static final void install(Globals G) {
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
final Hashtable h = new Hashtable();
|
||||
final JavaGen gen = new JavaGen(p, classname, luaname, genmain);
|
||||
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++)
|
||||
insert(h, gen.inners[i]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuaFunction load(Prototype p, String name, LuaValue globals) throws IOException {
|
||||
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);
|
||||
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: '_');
|
||||
}
|
||||
return classname.toString();
|
||||
}
|
||||
|
||||
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) {
|
||||
return s.endsWith(".lua")? s.substring(0, s.length()-4): s;
|
||||
}
|
||||
}
|
||||
547
luaj-jse/src/main/java/org/luaj/vm2/luajc/ProtoInfo.java
Normal file
547
luaj-jse/src/main/java/org/luaj/vm2/luajc/ProtoInfo.java
Normal file
@@ -0,0 +1,547 @@
|
||||
package org.luaj.vm2.luajc;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.Print;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.Upvaldesc;
|
||||
|
||||
/**
|
||||
* Prototype information for static single-assignment analysis
|
||||
*/
|
||||
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 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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
// 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++) {
|
||||
VarInfo v = VarInfo.PARAM(slot);
|
||||
params[slot] = v;
|
||||
}
|
||||
|
||||
// find variables
|
||||
this.vars = findVariables();
|
||||
replaceTrivialPhiVariables();
|
||||
|
||||
// find upvalues, create sub-prototypes
|
||||
this.openups = new UpvalInfo[p.maxstacksize][];
|
||||
findUpvalues();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
// prototpye name
|
||||
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");
|
||||
|
||||
// basic blocks
|
||||
for (BasicBlock b : blocklist) {
|
||||
int pc0 = b.pc0;
|
||||
sb.append(" block " + b.toString());
|
||||
appendOpenUps(sb, -1);
|
||||
|
||||
// instructions
|
||||
for (int pc = pc0; pc <= b.pc1; pc++) {
|
||||
|
||||
// open upvalue storage
|
||||
appendOpenUps(sb, pc);
|
||||
|
||||
// opcode
|
||||
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);
|
||||
}
|
||||
sb.append(" ");
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
PrintStream ops = Print.ps;
|
||||
Print.ps = new PrintStream(baos);
|
||||
try {
|
||||
Print.printOpCode(prototype, pc);
|
||||
} finally {
|
||||
Print.ps.close();
|
||||
Print.ps = ops;
|
||||
}
|
||||
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());
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
// process instructions
|
||||
for (BasicBlock element : blocklist) {
|
||||
BasicBlock b0 = element;
|
||||
|
||||
// input from previous blocks
|
||||
int nprev = b0.prev != null? b0.prev.length: 0;
|
||||
for (int slot = 0; slot < m; slot++) {
|
||||
VarInfo var = null;
|
||||
if (nprev == 0)
|
||||
var = params[slot];
|
||||
else if (nprev == 1)
|
||||
var = v[slot][b0.prev[0].pc1];
|
||||
else {
|
||||
for (int i = 0; i < nprev; i++) {
|
||||
BasicBlock bp = b0.prev[i];
|
||||
if (v[slot][bp.pc1] == VarInfo.INVALID)
|
||||
var = VarInfo.INVALID;
|
||||
}
|
||||
}
|
||||
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++) {
|
||||
|
||||
// propogate previous values except at block boundaries
|
||||
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) {
|
||||
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);
|
||||
break;
|
||||
|
||||
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);
|
||||
v[b][pc].isreferenced = true;
|
||||
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);
|
||||
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);
|
||||
v[a][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++)
|
||||
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);
|
||||
v[a+2][pc].isreferenced = true;
|
||||
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);
|
||||
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_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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
v[a][pc].isreferenced = true;
|
||||
v[a+2][pc].isreferenced = true;
|
||||
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);
|
||||
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);
|
||||
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++)
|
||||
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);
|
||||
v[a][pc].isreferenced = true;
|
||||
v[a][pc].isreferenced = true;
|
||||
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++)
|
||||
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);
|
||||
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++)
|
||||
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);
|
||||
v[a+1][pc].isreferenced = true;
|
||||
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);
|
||||
v[a][pc].isreferenced = true;
|
||||
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++)
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
v[a][pc].isreferenced = true;
|
||||
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);
|
||||
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;
|
||||
break;
|
||||
|
||||
case Lua.OP_JMP: /* sBx pc+=sBx */
|
||||
a = Lua.GETARG_A(ins);
|
||||
if (a > 0)
|
||||
for (--a; a < m; a++)
|
||||
v[a][pc] = VarInfo.INVALID;
|
||||
break;
|
||||
|
||||
default:
|
||||
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++)
|
||||
v[j][pcto] = v[j][pcfrom];
|
||||
}
|
||||
|
||||
private void replaceTrivialPhiVariables() {
|
||||
for (BasicBlock b0 : blocklist) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private void replaceAll(VarInfo[] v, int n, VarInfo vold, VarInfo vnew) {
|
||||
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) {
|
||||
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) {
|
||||
Upvaldesc u = newp.upvalues[j];
|
||||
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)
|
||||
upvals[Lua.GETARG_B(code[pc])].rw = true;
|
||||
}
|
||||
}
|
||||
|
||||
private UpvalInfo findOpenUp(int pc, int slot) {
|
||||
if (openups[slot] == null)
|
||||
openups[slot] = new UpvalInfo[prototype.code.length];
|
||||
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)
|
||||
openups[slot][i] = u;
|
||||
return u;
|
||||
}
|
||||
|
||||
public boolean isUpvalueAssign(int pc, int slot) {
|
||||
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];
|
||||
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)
|
||||
pc -= 1;
|
||||
VarInfo v = pc < 0? params[slot]: vars[slot][pc];
|
||||
return v != null && v.upvalue != null && v.upvalue.rw;
|
||||
}
|
||||
|
||||
public boolean isInitialValueUsed(int slot) {
|
||||
VarInfo v = params[slot];
|
||||
return v.isreferenced;
|
||||
}
|
||||
|
||||
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();
|
||||
int[] code = prototype.code;
|
||||
int n = code.length;
|
||||
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;
|
||||
}
|
||||
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) );
|
||||
}
|
||||
used.put(name, Boolean.TRUE);
|
||||
names[bx] = name;
|
||||
}
|
||||
}
|
||||
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): '_');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
152
luaj-jse/src/main/java/org/luaj/vm2/luajc/UpvalInfo.java
Normal file
152
luaj-jse/src/main/java/org/luaj/vm2/luajc/UpvalInfo.java
Normal file
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.luaj.vm2.luajc;
|
||||
|
||||
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
|
||||
|
||||
// Upval info representing the implied context containing only the environment.
|
||||
public UpvalInfo(ProtoInfo pi) {
|
||||
this.pi = pi;
|
||||
this.slot = 0;
|
||||
this.nvars = 1;
|
||||
this.var = new VarInfo[] { VarInfo.PARAM(0) };
|
||||
this.rw = false;
|
||||
}
|
||||
|
||||
public UpvalInfo(ProtoInfo pi, int pc, int slot) {
|
||||
this.pi = pi;
|
||||
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;
|
||||
}
|
||||
|
||||
private boolean includeVarAndPosteriorVars(VarInfo var) {
|
||||
if (var == null || var == VarInfo.INVALID)
|
||||
return false;
|
||||
if (var.upvalue == this)
|
||||
return true;
|
||||
var.upvalue = this;
|
||||
appendVar(var);
|
||||
if (isLoopVariable(var))
|
||||
return false;
|
||||
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])) {
|
||||
case Lua.OP_TFORLOOP:
|
||||
case Lua.OP_FORLOOP:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean includePosteriorVarsCheckLoops(VarInfo prior) {
|
||||
boolean loopDetected = false;
|
||||
for (BasicBlock b : pi.blocklist) {
|
||||
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++) {
|
||||
BasicBlock b1 = b.next[j];
|
||||
VarInfo v1 = pi.vars[slot][b1.pc0];
|
||||
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]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return loopDetected;
|
||||
}
|
||||
|
||||
private void includePriorVarsIgnoreLoops(VarInfo poster) {
|
||||
for (BasicBlock b : pi.blocklist) {
|
||||
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++) {
|
||||
BasicBlock b0 = b.prev[j];
|
||||
VarInfo v0 = pi.vars[slot][b0.pc1];
|
||||
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]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void appendVar(VarInfo v) {
|
||||
if (nvars == 0) {
|
||||
var = new VarInfo[1];
|
||||
} else if (nvars+1 >= var.length) {
|
||||
VarInfo[] s = var;
|
||||
var = new VarInfo[nvars*2+1];
|
||||
System.arraycopy(s, 0, var, 0, nvars);
|
||||
}
|
||||
var[nvars++] = v;
|
||||
}
|
||||
|
||||
@Override
|
||||
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]));
|
||||
}
|
||||
if (rw)
|
||||
sb.append("(rw)");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private boolean testIsAllocUpvalue(VarInfo v) {
|
||||
if (v.pc < 0)
|
||||
return true;
|
||||
BasicBlock b = pi.blocks[v.pc];
|
||||
if (v.pc > b.pc0)
|
||||
return pi.vars[slot][v.pc-1].upvalue != this;
|
||||
if (b.prev == null) {
|
||||
v = pi.params[slot];
|
||||
if (v != null && v.upvalue != this)
|
||||
return true;
|
||||
} else {
|
||||
for (BasicBlock element : b.prev) {
|
||||
v = pi.vars[slot][element.pc1];
|
||||
if (v != null && v.upvalue != this)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
149
luaj-jse/src/main/java/org/luaj/vm2/luajc/VarInfo.java
Normal file
149
luaj-jse/src/main/java/org/luaj/vm2/luajc/VarInfo.java
Normal file
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.luaj.vm2.luajc;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
public class VarInfo {
|
||||
|
||||
public static VarInfo INVALID = new VarInfo(-1, -1);
|
||||
|
||||
public static VarInfo PARAM(int slot) {
|
||||
return new ParamVarInfo(slot, -1);
|
||||
}
|
||||
|
||||
public static VarInfo NIL(final int slot) {
|
||||
return new NilVarInfo(slot, -1);
|
||||
}
|
||||
|
||||
public static VarInfo PHI(final ProtoInfo pi, final int slot, final int pc) {
|
||||
return new PhiVarInfo(pi, slot, pc);
|
||||
}
|
||||
|
||||
public final int slot; // where assigned
|
||||
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
|
||||
// storage
|
||||
public boolean isreferenced; // true if this variable is refenced by some
|
||||
// opcode
|
||||
|
||||
public VarInfo(int slot, int pc) {
|
||||
this.slot = slot;
|
||||
this.pc = pc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
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 new Variable to replace with if there is only one value, or null
|
||||
* to leave alone.
|
||||
*/
|
||||
public VarInfo resolvePhiVariableValues() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void collectUniqueValues(Set visitedBlocks, Set vars) {
|
||||
vars.add(this);
|
||||
}
|
||||
|
||||
public boolean isPhiVar() { return false; }
|
||||
|
||||
private static final class ParamVarInfo extends VarInfo {
|
||||
private ParamVarInfo(int slot, int pc) {
|
||||
super(slot, pc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return slot + ".p";
|
||||
}
|
||||
}
|
||||
|
||||
private static final class NilVarInfo extends VarInfo {
|
||||
private NilVarInfo(int slot, int pc) {
|
||||
super(slot, pc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "nil";
|
||||
}
|
||||
}
|
||||
|
||||
private static final class PhiVarInfo extends VarInfo {
|
||||
private final ProtoInfo pi;
|
||||
VarInfo[] values;
|
||||
|
||||
private PhiVarInfo(ProtoInfo pi, int slot, int pc) {
|
||||
super(slot, pc);
|
||||
this.pi = pi;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPhiVar() { return true; }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(super.toString());
|
||||
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("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public VarInfo resolvePhiVariableValues() {
|
||||
Set visitedBlocks = new HashSet();
|
||||
Set vars = new HashSet();
|
||||
this.collectUniqueValues(visitedBlocks, vars);
|
||||
if (vars.contains(INVALID))
|
||||
return INVALID;
|
||||
int n = vars.size();
|
||||
Iterator it = vars.iterator();
|
||||
if (n == 1) {
|
||||
VarInfo v = (VarInfo) it.next();
|
||||
v.isreferenced |= this.isreferenced;
|
||||
return v;
|
||||
}
|
||||
this.values = new VarInfo[n];
|
||||
for (int i = 0; i < n; i++) {
|
||||
this.values[i] = (VarInfo) it.next();
|
||||
this.values[i].isreferenced |= this.isreferenced;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void collectUniqueValues(Set visitedBlocks, Set vars) {
|
||||
BasicBlock b = pi.blocks[pc];
|
||||
if (pc == 0)
|
||||
vars.add(pi.params[slot]);
|
||||
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)
|
||||
v.collectUniqueValues(visitedBlocks, vars);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
287
luaj-jse/src/main/java/org/luaj/vm2/script/LuaScriptEngine.java
Normal file
287
luaj-jse/src/main/java/org/luaj/vm2/script/LuaScriptEngine.java
Normal file
@@ -0,0 +1,287 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2008-2013 LuaJ. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.script;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
|
||||
import javax.script.AbstractScriptEngine;
|
||||
import javax.script.Bindings;
|
||||
import javax.script.Compilable;
|
||||
import javax.script.CompiledScript;
|
||||
import javax.script.ScriptContext;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineFactory;
|
||||
import javax.script.ScriptException;
|
||||
import javax.script.SimpleBindings;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.LuaClosure;
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaFunction;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.lib.ThreeArgFunction;
|
||||
import org.luaj.vm2.lib.TwoArgFunction;
|
||||
import org.luaj.vm2.lib.jse.CoerceJavaToLua;
|
||||
|
||||
/**
|
||||
* Implementation of the ScriptEngine interface which can compile and execute
|
||||
* 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.
|
||||
*/
|
||||
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 final 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 {
|
||||
return compile(new StringReader(script));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompiledScript compile(Reader script) throws ScriptException {
|
||||
try {
|
||||
try (InputStream is = new Utf8Encoder(script)) {
|
||||
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());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new ScriptException("eval threw " + e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object eval(Reader reader, Bindings bindings) throws ScriptException {
|
||||
return ((LuajCompiledScript) compile(reader)).eval(context.globals, bindings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object eval(String script, Bindings bindings) throws ScriptException {
|
||||
return eval(new StringReader(script), bindings);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ScriptContext getScriptContext(Bindings nn) {
|
||||
throw new IllegalStateException("LuajScriptEngine should not be allocating contexts.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bindings createBindings() {
|
||||
return new SimpleBindings();
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptEngineFactory getFactory() { return myFactory; }
|
||||
|
||||
class LuajCompiledScript extends CompiledScript {
|
||||
final LuaFunction function;
|
||||
final Globals compiling_globals;
|
||||
|
||||
LuajCompiledScript(LuaFunction function, Globals compiling_globals) {
|
||||
this.function = function;
|
||||
this.compiling_globals = compiling_globals;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptEngine getEngine() { return LuaScriptEngine.this; }
|
||||
|
||||
@Override
|
||||
public Object eval() throws ScriptException {
|
||||
return eval(getContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object eval(Bindings bindings) throws ScriptException {
|
||||
return eval(((LuajContext) getContext()).globals, bindings);
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
else {
|
||||
try {
|
||||
f = f.getClass().newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new ScriptException(e);
|
||||
}
|
||||
f.initupvalue1(g);
|
||||
}
|
||||
return toJava(f.invoke(LuaValue.NONE));
|
||||
}
|
||||
}
|
||||
|
||||
// ------ convert char stream to byte stream for lua compiler -----
|
||||
|
||||
private final class Utf8Encoder extends InputStream {
|
||||
private final Reader r;
|
||||
private final int[] buf = new int[2];
|
||||
private int n;
|
||||
|
||||
private Utf8Encoder(Reader r) {
|
||||
this.r = r;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if (n > 0)
|
||||
return buf[--n];
|
||||
int c = r.read();
|
||||
if (c < 0x80)
|
||||
return c;
|
||||
n = 0;
|
||||
if (c < 0x800) {
|
||||
buf[n++] = 0x80 | c & 0x3f;
|
||||
return 0xC0 | c>>6 & 0x1f;
|
||||
} else {
|
||||
buf[n++] = 0x80 | c & 0x3f;
|
||||
buf[n++] = 0x80 | c>>6 & 0x3f;
|
||||
return 0xE0 | c>>12 & 0x0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class BindingsMetatable extends LuaTable {
|
||||
|
||||
BindingsMetatable(final Bindings bindings) {
|
||||
this.rawset(LuaValue.INDEX, new TwoArgFunction() {
|
||||
@Override
|
||||
public LuaValue call(LuaValue table, LuaValue key) {
|
||||
if (key.isstring())
|
||||
return toLua(bindings.get(key.tojstring()));
|
||||
else
|
||||
return this.rawget(key);
|
||||
}
|
||||
});
|
||||
this.rawset(LuaValue.NEWINDEX, new ThreeArgFunction() {
|
||||
@Override
|
||||
public LuaValue call(LuaValue table, LuaValue key, LuaValue value) {
|
||||
if (key.isstring()) {
|
||||
final String k = key.tojstring();
|
||||
final Object v = toJava(value);
|
||||
if (v == null)
|
||||
bindings.remove(k);
|
||||
else
|
||||
bindings.put(k, v);
|
||||
} else {
|
||||
this.rawset(key, value);
|
||||
}
|
||||
return LuaValue.NONE;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static private LuaValue toLua(Object 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) Integer.valueOf(luajValue.toint())
|
||||
: (Object) Double.valueOf(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());
|
||||
default:
|
||||
Object[] o = new Object[n];
|
||||
for (int i = 0; i < n; ++i)
|
||||
o[i] = toJava(v.arg(i+1));
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2008 LuaJ. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.script;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.script.ScriptEngine;
|
||||
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.
|
||||
*/
|
||||
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 final List<String> extensions;
|
||||
private final List<String> mimeTypes;
|
||||
private final List<String> names;
|
||||
|
||||
public LuaScriptEngineFactory() {
|
||||
extensions = Arrays.asList(EXTENSIONS);
|
||||
mimeTypes = Arrays.asList(MIMETYPES);
|
||||
names = Arrays.asList(NAMES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEngineName() { return getScriptEngine().get(ScriptEngine.ENGINE).toString(); }
|
||||
|
||||
@Override
|
||||
public String getEngineVersion() { return getScriptEngine().get(ScriptEngine.ENGINE_VERSION).toString(); }
|
||||
|
||||
@Override
|
||||
public List<String> getExtensions() { return extensions; }
|
||||
|
||||
@Override
|
||||
public List<String> getMimeTypes() { return mimeTypes; }
|
||||
|
||||
@Override
|
||||
public List<String> getNames() { return names; }
|
||||
|
||||
@Override
|
||||
public String getLanguageName() { return getScriptEngine().get(ScriptEngine.LANGUAGE).toString(); }
|
||||
|
||||
@Override
|
||||
public String getLanguageVersion() { return getScriptEngine().get(ScriptEngine.LANGUAGE_VERSION).toString(); }
|
||||
|
||||
@Override
|
||||
public Object getParameter(String key) {
|
||||
return getScriptEngine().get(key).toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
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();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOutputStatement(String toDisplay) {
|
||||
return "print(" + toDisplay + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
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();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptEngine getScriptEngine() { return new LuaScriptEngine(); }
|
||||
}
|
||||
147
luaj-jse/src/main/java/org/luaj/vm2/script/LuajContext.java
Normal file
147
luaj-jse/src/main/java/org/luaj/vm2/script/LuajContext.java
Normal file
@@ -0,0 +1,147 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013 LuaJ. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.script;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
|
||||
import javax.script.ScriptContext;
|
||||
import javax.script.SimpleScriptContext;
|
||||
|
||||
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.
|
||||
*/
|
||||
public class LuajContext extends SimpleScriptContext implements ScriptContext {
|
||||
|
||||
/** Globals for this context instance. */
|
||||
public final Globals globals;
|
||||
|
||||
/** The initial value of globals.STDIN */
|
||||
private final InputStream stdin;
|
||||
/** The initial value of globals.STDOUT */
|
||||
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'
|
||||
* <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.
|
||||
*/
|
||||
public LuajContext() {
|
||||
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.
|
||||
* <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.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
static final class WriterOutputStream extends OutputStream {
|
||||
final Writer w;
|
||||
|
||||
WriterOutputStream(Writer w) {
|
||||
this.w = w;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
w.write(new String(new byte[] { (byte) b }));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int o, int l) throws IOException {
|
||||
w.write(new String(b, o, l));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b) throws IOException {
|
||||
w.write(new String(b));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
w.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
w.flush();
|
||||
}
|
||||
}
|
||||
|
||||
static final class ReaderInputStream extends InputStream {
|
||||
final Reader r;
|
||||
|
||||
ReaderInputStream(Reader r) {
|
||||
this.r = r;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return r.read();
|
||||
}
|
||||
}
|
||||
}
|
||||
110
luaj-jse/src/main/java/org/luaj/vm2/server/DefaultLauncher.java
Normal file
110
luaj-jse/src/main/java/org/luaj/vm2/server/DefaultLauncher.java
Normal file
@@ -0,0 +1,110 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2015 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.server;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
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'.
|
||||
* <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.
|
||||
*
|
||||
* @see Launcher
|
||||
* @see LuajClassLoader
|
||||
* @see LuajClassLoader#NewLauncher()
|
||||
* @see LuajClassLoader#NewLauncher(Class)
|
||||
* @since luaj 3.0.1
|
||||
*/
|
||||
public class DefaultLauncher implements Launcher {
|
||||
protected Globals g;
|
||||
|
||||
public DefaultLauncher() {
|
||||
g = JsePlatform.standardGlobals();
|
||||
}
|
||||
|
||||
/** Launches the script with chunk name 'main' */
|
||||
@Override
|
||||
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'
|
||||
*/
|
||||
@Override
|
||||
public Object[] launch(InputStream script, Object[] arg) {
|
||||
return launchChunk(g.load(script, "main", "bt", g), arg);
|
||||
}
|
||||
|
||||
/** Launches the script with chunk name 'main' */
|
||||
@Override
|
||||
public Object[] launch(Reader script, Object[] arg) {
|
||||
return launchChunk(g.load(script, "main"), arg);
|
||||
}
|
||||
|
||||
private Object[] launchChunk(LuaValue chunk, Object[] arg) {
|
||||
LuaValue args[] = new LuaValue[arg.length];
|
||||
for (int i = 0; i < args.length; ++i)
|
||||
args[i] = CoerceJavaToLua.coerce(arg[i]);
|
||||
Varargs results = chunk.invoke(LuaValue.varargsOf(args));
|
||||
|
||||
final int n = results.narg();
|
||||
Object return_values[] = new Object[n];
|
||||
for (int i = 0; i < n; ++i) {
|
||||
LuaValue r = results.arg(i+1);
|
||||
switch (r.type()) {
|
||||
case LuaValue.TBOOLEAN:
|
||||
return_values[i] = r.toboolean();
|
||||
break;
|
||||
case LuaValue.TNUMBER:
|
||||
return_values[i] = r.todouble();
|
||||
break;
|
||||
case LuaValue.TINT:
|
||||
return_values[i] = r.toint();
|
||||
break;
|
||||
case LuaValue.TNIL:
|
||||
return_values[i] = null;
|
||||
break;
|
||||
case LuaValue.TSTRING:
|
||||
return_values[i] = r.tojstring();
|
||||
break;
|
||||
case LuaValue.TUSERDATA:
|
||||
return_values[i] = r.touserdata();
|
||||
break;
|
||||
default:
|
||||
return_values[i] = r;
|
||||
}
|
||||
}
|
||||
return return_values;
|
||||
}
|
||||
}
|
||||
76
luaj-jse/src/main/java/org/luaj/vm2/server/Launcher.java
Normal file
76
luaj-jse/src/main/java/org/luaj/vm2/server/Launcher.java
Normal file
@@ -0,0 +1,76 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2015 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.server;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
|
||||
/**
|
||||
* Interface to launch lua scripts using the {@link LuajClassLoader}.
|
||||
* <P>
|
||||
* <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.
|
||||
* <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 shared metatables.
|
||||
*
|
||||
* @see LuajClassLoader
|
||||
* @see LuajClassLoader#NewLauncher()
|
||||
* @see LuajClassLoader#NewLauncher(Class)
|
||||
* @see DefaultLauncher
|
||||
* @since luaj 3.0.1
|
||||
*/
|
||||
public interface Launcher {
|
||||
|
||||
/**
|
||||
* Launch a script contained in a String.
|
||||
*
|
||||
* @param script The script contents.
|
||||
* @param arg Optional arguments supplied to the script.
|
||||
* @return return values from the script.
|
||||
*/
|
||||
Object[] launch(String script, Object[] arg);
|
||||
|
||||
/**
|
||||
* Launch a script from an InputStream.
|
||||
*
|
||||
* @param script The script as an InputStream.
|
||||
* @param arg Optional arguments supplied to the script.
|
||||
* @return return values from the script.
|
||||
*/
|
||||
Object[] launch(InputStream script, Object[] arg);
|
||||
|
||||
/**
|
||||
* Launch a script from a Reader.
|
||||
*
|
||||
* @param script The script as a Reader.
|
||||
* @param arg Optional arguments supplied to the script.
|
||||
* @return return values from the script.
|
||||
*/
|
||||
Object[] launch(Reader script, Object[] arg);
|
||||
}
|
||||
158
luaj-jse/src/main/java/org/luaj/vm2/server/LuajClassLoader.java
Normal file
158
luaj-jse/src/main/java/org/luaj/vm2/server/LuajClassLoader.java
Normal file
@@ -0,0 +1,158 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2015 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.server;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
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.
|
||||
* <P>
|
||||
* <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.
|
||||
* <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
|
||||
* classes are considered systemc classes and loaded via the system loader. This
|
||||
* class set can be extended by overriding {@link #isUserClass(String)}.
|
||||
* <P>
|
||||
* The {@link Launcher} interface is loaded as a system class by exception so
|
||||
* that the caller may use it to launch lua scripts.
|
||||
* <P>
|
||||
* By default {@link #NewLauncher()} creates a subclass of {@link Launcher} of
|
||||
* type {@link DefaultLauncher} which creates debug globals, runs the script,
|
||||
* and prints the return values. This behavior can be changed by supplying a
|
||||
* different implementation class to {@link #NewLauncher(Class)} which must
|
||||
* extend {@link Launcher}.
|
||||
*
|
||||
* @see Launcher
|
||||
* @see #NewLauncher()
|
||||
* @see #NewLauncher(Class)
|
||||
* @see DefaultLauncher
|
||||
* @since luaj 3.0.1
|
||||
*/
|
||||
public class LuajClassLoader extends ClassLoader {
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
static final String launcherInterfaceRoot = Launcher.class.getName();
|
||||
|
||||
/** Local cache of classes loaded by this loader. */
|
||||
Map<String, Class<?>> classes = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Construct a default {@link Launcher} instance that will load classes in
|
||||
* 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.
|
||||
*
|
||||
* @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 {
|
||||
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}.
|
||||
* <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.
|
||||
*
|
||||
* @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 {
|
||||
final LuajClassLoader loader = new LuajClassLoader();
|
||||
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.
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> loadClass(String classname) throws ClassNotFoundException {
|
||||
if (classes.containsKey(classname))
|
||||
return classes.get(classname);
|
||||
if (!isUserClass(classname))
|
||||
return super.findSystemClass(classname);
|
||||
return loadAsUserClass(classname);
|
||||
}
|
||||
|
||||
private Class<?> loadAsUserClass(String classname) throws ClassNotFoundException {
|
||||
final String path = classname.replace('.', '/').concat(".class");
|
||||
InputStream is = getResourceAsStream(path);
|
||||
if (is != null) {
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
byte[] b = new byte[1024];
|
||||
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);
|
||||
classes.put(classname, result);
|
||||
return result;
|
||||
} catch (java.io.IOException e) {
|
||||
throw new ClassNotFoundException("Read failed: " + classname + ": " + e);
|
||||
}
|
||||
}
|
||||
throw new ClassNotFoundException("Not found: " + classname);
|
||||
}
|
||||
}
|
||||
349
luaj-jse/src/main/javacc/Lua51.jj
Normal file
349
luaj-jse/src/main/javacc/Lua51.jj
Normal file
@@ -0,0 +1,349 @@
|
||||
/**
|
||||
* Javacc grammar for lua language version 5.1
|
||||
*
|
||||
* Originally created for use in luaj, a Java implementation of the lua language
|
||||
* @see http://sourceforge.net/projects/luaj/
|
||||
*
|
||||
* For documentation on the lua language
|
||||
* @see http://www.lua.org/manual/5.1/
|
||||
*
|
||||
* Empty grammar that validates syntax without producing a parse tree.
|
||||
*
|
||||
* @author Jim Roseborough
|
||||
* @date June 21, 2010
|
||||
*/
|
||||
|
||||
options {
|
||||
STATIC = false;
|
||||
JDK_VERSION = "1.3";
|
||||
ERROR_REPORTING = false;
|
||||
DEBUG_LOOKAHEAD = false;
|
||||
DEBUG_PARSER = false;
|
||||
DEBUG_TOKEN_MANAGER = false;
|
||||
OUTPUT_DIRECTORY = "org/luaj/vm2/parser/lua51";
|
||||
}
|
||||
|
||||
PARSER_BEGIN(LuaParser)
|
||||
package org.luaj.vm2.parser.lua51;
|
||||
|
||||
public class LuaParser {
|
||||
|
||||
public static void main(String args[]) throws ParseException {
|
||||
LuaParser parser = new LuaParser(System.in);
|
||||
parser.Chunk();
|
||||
}
|
||||
|
||||
public static final int VAR = 0;
|
||||
public static final int CALL = 1;
|
||||
}
|
||||
|
||||
PARSER_END(LuaParser)
|
||||
|
||||
/* WHITE SPACE */
|
||||
|
||||
SKIP :
|
||||
{
|
||||
" " | "\t" | "\n" | "\r" | "\f"
|
||||
}
|
||||
|
||||
/* COMMENTS and LONG STRINGS */
|
||||
|
||||
MORE :
|
||||
{
|
||||
"--[[": IN_LC0
|
||||
| "--[=[": IN_LC1
|
||||
| "--[==[": IN_LC2
|
||||
| "--[===[": IN_LC3
|
||||
| < "--[====" ("=")* "[" > : IN_LCN
|
||||
| "[[" : IN_LS0
|
||||
| "[=[" : IN_LS1
|
||||
| "[==[" : IN_LS2
|
||||
| "[===[" : IN_LS3
|
||||
| < "[====" ("=")* "[" > : IN_LSN
|
||||
| "--" : IN_COMMENT
|
||||
}
|
||||
|
||||
<IN_COMMENT> SPECIAL_TOKEN :
|
||||
{
|
||||
<COMMENT: (~["\n","\r"])* ("\n"|"\r"|"\r\n")? > : DEFAULT
|
||||
}
|
||||
|
||||
<IN_LC0> SPECIAL_TOKEN : { <LONGCOMMENT0: "]]" > : DEFAULT }
|
||||
<IN_LC1> SPECIAL_TOKEN : { <LONGCOMMENT1: "]=]" > : DEFAULT }
|
||||
<IN_LC2> SPECIAL_TOKEN : { <LONGCOMMENT2: "]==]" > : DEFAULT }
|
||||
<IN_LC3> SPECIAL_TOKEN : { <LONGCOMMENT3: "]===]" > : DEFAULT }
|
||||
<IN_LCN> SPECIAL_TOKEN : { <LONGCOMMENTN: "]====" ("=")* "]" > : DEFAULT }
|
||||
|
||||
<IN_LS0> TOKEN : { <LONGSTRING0: "]]" > : DEFAULT }
|
||||
<IN_LS1> TOKEN : { <LONGSTRING1: "]=]" > : DEFAULT }
|
||||
<IN_LS2> TOKEN : { <LONGSTRING2: "]==]" > : DEFAULT }
|
||||
<IN_LS3> TOKEN : { <LONGSTRING3: "]===]" > : DEFAULT }
|
||||
<IN_LSN> TOKEN : { <LONGSTRINGN: "]====" ("=")* "]" > : DEFAULT }
|
||||
|
||||
<IN_LC0,IN_LC1,IN_LC2,IN_LC3,IN_LCN,IN_LS0,IN_LS1,IN_LS2,IN_LS3,IN_LSN> MORE :
|
||||
{
|
||||
< ~[] >
|
||||
}
|
||||
|
||||
|
||||
/* RESERVED WORDS AND LITERALS */
|
||||
|
||||
TOKEN :
|
||||
{
|
||||
<AND: "and">
|
||||
| <BREAK: "break">
|
||||
| <DO: "do">
|
||||
| <ELSE: "else">
|
||||
| <ELSEIF: "elseif">
|
||||
| <END: "end">
|
||||
| <FALSE: "false">
|
||||
| <FOR: "for">
|
||||
| <FUNCTION: "function">
|
||||
| <IF: "if">
|
||||
| <IN: "in">
|
||||
| <LOCAL: "local">
|
||||
| <NIL: "nil">
|
||||
| <NOT: "not">
|
||||
| <OR: "or">
|
||||
| <RETURN: "return">
|
||||
| <REPEAT: "repeat">
|
||||
| <THEN: "then">
|
||||
| <TRUE: "true">
|
||||
| <UNTIL: "until">
|
||||
| <WHILE: "while">
|
||||
}
|
||||
|
||||
/* LITERALS */
|
||||
|
||||
TOKEN :
|
||||
{
|
||||
< NAME: ["a"-"z", "A"-"Z", "_"] (["a"-"z", "A"-"Z", "_", "0"-"9"])* >
|
||||
| < NUMBER: <HEX> | <FLOAT> >
|
||||
| < #FLOAT: (<DIGIT>)+ "." (<DIGIT>)* (<EXP>)? | "." (<DIGIT>)+ (<EXP>)? | (<DIGIT>)+ (<EXP>)? >
|
||||
| < #DIGIT: ["0"-"9"] >
|
||||
| < #EXP: ["e","E"] (["+","-"])? (<DIGIT>)+ >
|
||||
| < #HEX: "0" ["x","X"] (<HEXDIGIT>)+ >
|
||||
| < #HEXDIGIT: ["0"-"9","a"-"f","A"-"F"] >
|
||||
| < STRING: "\"" (<QUOTED> | ~["\\","\""])* "\"" >
|
||||
| < CHARSTRING: "'" (<QUOTED> | ~["\\","'"])* "'" >
|
||||
| < #QUOTED: <DECIMAL> | <UNICODE> | <CHAR> >
|
||||
| < #DECIMAL: "\\" ["0"-"9"] (["0"-"9"])? (["0"-"9"])? >
|
||||
| < #UNICODE: "\\" "u" <HEXDIGIT> <HEXDIGIT> <HEXDIGIT> <HEXDIGIT> >
|
||||
//| < #CHAR: "\\" ("a"|"b"|"f"|"n"|"r"|"t"|"v"|"["|"]"|"'"|"\""|"\\"|"0"|<LF>) >
|
||||
| < #CHAR: "\\" (~[]) >
|
||||
| < #LF: ("\n" | "\r" | "\r\n") >
|
||||
}
|
||||
|
||||
/** Root production. */
|
||||
void Chunk():
|
||||
{}
|
||||
{
|
||||
Block() <EOF>
|
||||
}
|
||||
|
||||
void Block():
|
||||
{}
|
||||
{
|
||||
(Stat() (";")? )* (LastStat() (";")? )?
|
||||
}
|
||||
|
||||
void Stat():
|
||||
{}
|
||||
{
|
||||
<DO> Block() <END>
|
||||
| <WHILE> Exp() <DO> Block() <END>
|
||||
| <REPEAT> Block() <UNTIL> Exp()
|
||||
| <IF> Exp() <THEN> Block() (<ELSEIF> Exp() <THEN> Block())* (<ELSE> Block())? <END>
|
||||
| LOOKAHEAD(3) <FOR> <NAME> "=" Exp() "," Exp() ( "," Exp() )? <DO> Block() <END>
|
||||
| <FOR> NameList() <IN> ExpList() <DO> Block() <END>
|
||||
| <FUNCTION> FuncName() FuncBody()
|
||||
| LOOKAHEAD(2) <LOCAL> <FUNCTION> <NAME> FuncBody()
|
||||
| <LOCAL> NameList() ( "=" ExpList() )?
|
||||
| ExprStat()
|
||||
}
|
||||
|
||||
void LastStat():
|
||||
{}
|
||||
{
|
||||
<BREAK> | <RETURN> ( ExpList() )?
|
||||
}
|
||||
|
||||
void ExprStat():
|
||||
{ int type,need=CALL; }
|
||||
{
|
||||
type=PrimaryExp() ( Assign() { need=VAR; } )?
|
||||
{ if ( type!=need ) throw new ParseException("expected function call or assignment"); }
|
||||
}
|
||||
|
||||
void Assign():
|
||||
{}
|
||||
{
|
||||
( "," VarExp() )* "=" ExpList()
|
||||
}
|
||||
|
||||
void VarExp():
|
||||
{ int type; }
|
||||
{
|
||||
type=PrimaryExp()
|
||||
{ if ( type!=VAR ) throw new ParseException("expected variable expression"); }
|
||||
}
|
||||
|
||||
void FuncName():
|
||||
{}
|
||||
{
|
||||
<NAME> ( "." <NAME> )* ( ":" <NAME> )?
|
||||
}
|
||||
|
||||
void PrefixExp():
|
||||
{}
|
||||
{
|
||||
<NAME>
|
||||
| ParenExp()
|
||||
}
|
||||
|
||||
void ParenExp():
|
||||
{}
|
||||
{
|
||||
"(" Exp() ")"
|
||||
}
|
||||
|
||||
int PrimaryExp():
|
||||
{ int type=VAR; }
|
||||
{
|
||||
PrefixExp() ( LOOKAHEAD(2) type=PostfixOp() )* { return type; }
|
||||
}
|
||||
|
||||
int PostfixOp():
|
||||
{}
|
||||
{
|
||||
FieldOp() { return VAR; }
|
||||
| FuncOp() { return CALL; }
|
||||
}
|
||||
|
||||
void FieldOp():
|
||||
{}
|
||||
{
|
||||
"." <NAME>
|
||||
| "[" Exp() "]"
|
||||
}
|
||||
|
||||
void FuncOp():
|
||||
{}
|
||||
{
|
||||
":" <NAME> FuncArgs()
|
||||
| FuncArgs()
|
||||
}
|
||||
|
||||
void FuncArgs():
|
||||
{}
|
||||
{
|
||||
"(" ( ExpList() )? ")"
|
||||
| TableConstructor()
|
||||
| Str()
|
||||
}
|
||||
|
||||
void NameList():
|
||||
{}
|
||||
{
|
||||
<NAME> ( LOOKAHEAD(2) "," <NAME> )*
|
||||
}
|
||||
|
||||
void ExpList():
|
||||
{}
|
||||
{
|
||||
Exp() ( "," Exp() )*
|
||||
}
|
||||
|
||||
void SimpleExp():
|
||||
{}
|
||||
{
|
||||
<NIL>
|
||||
| <TRUE>
|
||||
| <FALSE>
|
||||
| <NUMBER>
|
||||
| Str()
|
||||
| "..."
|
||||
| TableConstructor()
|
||||
| Function()
|
||||
| PrimaryExp()
|
||||
}
|
||||
|
||||
void Str():
|
||||
{}
|
||||
{
|
||||
<STRING>
|
||||
| <CHARSTRING>
|
||||
| <LONGSTRING0>
|
||||
| <LONGSTRING1>
|
||||
| <LONGSTRING2>
|
||||
| <LONGSTRING3>
|
||||
| <LONGSTRINGN>
|
||||
}
|
||||
|
||||
void Exp():
|
||||
{}
|
||||
{
|
||||
SubExp()
|
||||
}
|
||||
|
||||
void SubExp():
|
||||
{}
|
||||
{
|
||||
( SimpleExp() | Unop() SubExp() ) (LOOKAHEAD(2) Binop() SubExp())*
|
||||
}
|
||||
|
||||
void Function():
|
||||
{}
|
||||
{
|
||||
<FUNCTION> FuncBody()
|
||||
}
|
||||
|
||||
void FuncBody():
|
||||
{}
|
||||
{
|
||||
"(" ( ParList() )? ")" Block() <END>
|
||||
}
|
||||
|
||||
void ParList():
|
||||
{}
|
||||
{
|
||||
NameList() ( "," "..." )? | "..."
|
||||
}
|
||||
|
||||
void TableConstructor():
|
||||
{}
|
||||
{
|
||||
"{" ( FieldList() )? "}"
|
||||
}
|
||||
|
||||
void FieldList():
|
||||
{}
|
||||
{
|
||||
Field() (LOOKAHEAD(2) FieldSep() Field())* (FieldSep())?
|
||||
}
|
||||
|
||||
void Field():
|
||||
{}
|
||||
{
|
||||
"[" Exp() "]" "=" Exp()
|
||||
| LOOKAHEAD(2) <NAME> "=" Exp()
|
||||
| Exp()
|
||||
}
|
||||
|
||||
void FieldSep():
|
||||
{}
|
||||
{
|
||||
"," | ";"
|
||||
}
|
||||
|
||||
void Binop():
|
||||
{}
|
||||
{
|
||||
"+" | "-" | "*" | "/" | "^" | "%" | ".." | "<" | "<=" | ">" | ">=" | "==" | "~=" | <AND> | <OR>
|
||||
}
|
||||
|
||||
void Unop():
|
||||
{}
|
||||
{
|
||||
"-" | <NOT> | "#"
|
||||
}
|
||||
363
luaj-jse/src/main/javacc/Lua52.jj
Normal file
363
luaj-jse/src/main/javacc/Lua52.jj
Normal file
@@ -0,0 +1,363 @@
|
||||
/**
|
||||
* Javacc grammar for lua language version 5.2
|
||||
*
|
||||
* Originally created for use in luaj, a Java implementation of the lua language
|
||||
* @see http://sourceforge.net/projects/luaj/
|
||||
*
|
||||
* For documentation on the lua language
|
||||
* @see http://www.lua.org/manual/5.2/
|
||||
*
|
||||
* Empty grammar that validates syntax without producing a parse tree.
|
||||
*
|
||||
* @author Jim Roseborough
|
||||
* @date August 30, 2012
|
||||
*/
|
||||
|
||||
options {
|
||||
STATIC = false;
|
||||
JDK_VERSION = "1.3";
|
||||
ERROR_REPORTING = false;
|
||||
DEBUG_LOOKAHEAD = false;
|
||||
DEBUG_PARSER = false;
|
||||
DEBUG_TOKEN_MANAGER = false;
|
||||
OUTPUT_DIRECTORY = "org/luaj/vm2/parser/lua52";
|
||||
}
|
||||
|
||||
PARSER_BEGIN(LuaParser)
|
||||
package org.luaj.vm2.parser.lua52;
|
||||
|
||||
public class LuaParser {
|
||||
|
||||
public static void main(String args[]) throws ParseException {
|
||||
LuaParser parser = new LuaParser(System.in);
|
||||
parser.Chunk();
|
||||
}
|
||||
|
||||
public static final int VAR = 0;
|
||||
public static final int CALL = 1;
|
||||
}
|
||||
|
||||
PARSER_END(LuaParser)
|
||||
|
||||
/* WHITE SPACE */
|
||||
|
||||
SKIP :
|
||||
{
|
||||
" " | "\t" | "\n" | "\r" | "\f"
|
||||
}
|
||||
|
||||
/* COMMENTS and LONG STRINGS */
|
||||
|
||||
MORE :
|
||||
{
|
||||
"--[[": IN_LC0
|
||||
| "--[=[": IN_LC1
|
||||
| "--[==[": IN_LC2
|
||||
| "--[===[": IN_LC3
|
||||
| < "--[====" ("=")* "[" > : IN_LCN
|
||||
| "[[" : IN_LS0
|
||||
| "[=[" : IN_LS1
|
||||
| "[==[" : IN_LS2
|
||||
| "[===[" : IN_LS3
|
||||
| < "[====" ("=")* "[" > : IN_LSN
|
||||
| "--" : IN_COMMENT
|
||||
}
|
||||
|
||||
<IN_COMMENT> SPECIAL_TOKEN :
|
||||
{
|
||||
<COMMENT: (~["\n","\r"])* ("\n"|"\r"|"\r\n")? > : DEFAULT
|
||||
}
|
||||
|
||||
<IN_LC0> SPECIAL_TOKEN : { <LONGCOMMENT0: "]]" > : DEFAULT }
|
||||
<IN_LC1> SPECIAL_TOKEN : { <LONGCOMMENT1: "]=]" > : DEFAULT }
|
||||
<IN_LC2> SPECIAL_TOKEN : { <LONGCOMMENT2: "]==]" > : DEFAULT }
|
||||
<IN_LC3> SPECIAL_TOKEN : { <LONGCOMMENT3: "]===]" > : DEFAULT }
|
||||
<IN_LCN> SPECIAL_TOKEN : { <LONGCOMMENTN: "]====" ("=")* "]" > : DEFAULT }
|
||||
|
||||
<IN_LS0> TOKEN : { <LONGSTRING0: "]]" > : DEFAULT }
|
||||
<IN_LS1> TOKEN : { <LONGSTRING1: "]=]" > : DEFAULT }
|
||||
<IN_LS2> TOKEN : { <LONGSTRING2: "]==]" > : DEFAULT }
|
||||
<IN_LS3> TOKEN : { <LONGSTRING3: "]===]" > : DEFAULT }
|
||||
<IN_LSN> TOKEN : { <LONGSTRINGN: "]====" ("=")* "]" > : DEFAULT }
|
||||
|
||||
<IN_LC0,IN_LC1,IN_LC2,IN_LC3,IN_LCN,IN_LS0,IN_LS1,IN_LS2,IN_LS3,IN_LSN> MORE :
|
||||
{
|
||||
< ~[] >
|
||||
}
|
||||
|
||||
|
||||
/* RESERVED WORDS AND LITERALS */
|
||||
|
||||
TOKEN :
|
||||
{
|
||||
<AND: "and">
|
||||
| <BREAK: "break">
|
||||
| <DO: "do">
|
||||
| <ELSE: "else">
|
||||
| <ELSEIF: "elseif">
|
||||
| <END: "end">
|
||||
| <FALSE: "false">
|
||||
| <FOR: "for">
|
||||
| <FUNCTION: "function">
|
||||
| <GOTO: "goto">
|
||||
| <IF: "if">
|
||||
| <IN: "in">
|
||||
| <LOCAL: "local">
|
||||
| <NIL: "nil">
|
||||
| <NOT: "not">
|
||||
| <OR: "or">
|
||||
| <RETURN: "return">
|
||||
| <REPEAT: "repeat">
|
||||
| <THEN: "then">
|
||||
| <TRUE: "true">
|
||||
| <UNTIL: "until">
|
||||
| <WHILE: "while">
|
||||
}
|
||||
|
||||
/* LITERALS */
|
||||
|
||||
TOKEN :
|
||||
{
|
||||
< NAME: ["a"-"z", "A"-"Z", "_"] (["a"-"z", "A"-"Z", "_", "0"-"9"])* >
|
||||
| < NUMBER: <HEX> | <FLOAT> >
|
||||
| < #FLOAT: <FNUM> (<EXP>)? >
|
||||
| < #FNUM: (<DIGIT>)+ "." (<DIGIT>)* | "." (<DIGIT>)+ | (<DIGIT>)+ >
|
||||
| < #DIGIT: ["0"-"9"] >
|
||||
| < #EXP: ["e","E"] (["+","-"])? (<DIGIT>)+ >
|
||||
| < #HEX: "0" ["x","X"] <HEXNUM> (<HEXEXP>)? >
|
||||
| < #HEXNUM: (<HEXDIGIT>)+ "." (<HEXDIGIT>)* | "." (<HEXDIGIT>)+ | (<HEXDIGIT>)+ >
|
||||
| < #HEXDIGIT: ["0"-"9","a"-"f","A"-"F"] >
|
||||
| < #HEXEXP: ["e","E","p","P"] (["+","-"])? (<DIGIT>)+ >
|
||||
| < STRING: "\"" (<QUOTED> | ~["\\","\""])* "\"" >
|
||||
| < CHARSTRING: "'" (<QUOTED> | ~["\\","'"])* "'" >
|
||||
| < #QUOTED: <DECIMAL> | <UNICODE> | <CHAR> >
|
||||
| < #DECIMAL: "\\" ["0"-"9"] (["0"-"9"])? (["0"-"9"])? >
|
||||
| < DBCOLON: "::" >
|
||||
| < #UNICODE: "\\" "u" <HEXDIGIT> <HEXDIGIT> <HEXDIGIT> <HEXDIGIT> >
|
||||
| < #CHAR: "\\" (~[]) >
|
||||
| < #LF: ("\n" | "\r" | "\r\n") >
|
||||
}
|
||||
|
||||
/** Root production. */
|
||||
void Chunk():
|
||||
{}
|
||||
{
|
||||
( "#" { token_source.SwitchTo(IN_COMMENT); } )? Block() <EOF>
|
||||
}
|
||||
|
||||
void Block():
|
||||
{}
|
||||
{
|
||||
( Stat() )* ( ReturnStat() )?
|
||||
}
|
||||
|
||||
void Stat():
|
||||
{}
|
||||
{
|
||||
";"
|
||||
| Label()
|
||||
| <BREAK>
|
||||
| <GOTO> <NAME>
|
||||
| <DO> Block() <END>
|
||||
| <WHILE> Exp() <DO> Block() <END>
|
||||
| <REPEAT> Block() <UNTIL> Exp()
|
||||
| <IF> Exp() <THEN> Block() (<ELSEIF> Exp() <THEN> Block())* (<ELSE> Block())? <END>
|
||||
| LOOKAHEAD(3) <FOR> <NAME> "=" Exp() "," Exp() ( "," Exp() )? <DO> Block() <END>
|
||||
| <FOR> NameList() <IN> ExpList() <DO> Block() <END>
|
||||
| <FUNCTION> FuncName() FuncBody()
|
||||
| LOOKAHEAD(2) <LOCAL> <FUNCTION> <NAME> FuncBody()
|
||||
| <LOCAL> NameList() ( "=" ExpList() )?
|
||||
| ExprStat()
|
||||
}
|
||||
|
||||
void ReturnStat():
|
||||
{}
|
||||
{
|
||||
<RETURN> ( ExpList() )? ( ";" )?
|
||||
}
|
||||
|
||||
void Label():
|
||||
{}
|
||||
{
|
||||
<DBCOLON> <NAME> <DBCOLON>
|
||||
}
|
||||
|
||||
void ExprStat():
|
||||
{ int type,need=CALL; }
|
||||
{
|
||||
type=PrimaryExp() ( Assign() { need=VAR; } )?
|
||||
{ if ( type!=need ) throw new ParseException("expected function call or assignment"); }
|
||||
}
|
||||
|
||||
void Assign():
|
||||
{}
|
||||
{
|
||||
( "," VarExp() )* "=" ExpList()
|
||||
}
|
||||
|
||||
void VarExp():
|
||||
{ int type; }
|
||||
{
|
||||
type=PrimaryExp()
|
||||
{ if ( type!=VAR ) throw new ParseException("expected variable expression"); }
|
||||
}
|
||||
|
||||
void FuncName():
|
||||
{}
|
||||
{
|
||||
<NAME> ( "." <NAME> )* ( ":" <NAME> )?
|
||||
}
|
||||
|
||||
void PrefixExp():
|
||||
{}
|
||||
{
|
||||
<NAME>
|
||||
| ParenExp()
|
||||
}
|
||||
|
||||
void ParenExp():
|
||||
{}
|
||||
{
|
||||
"(" Exp() ")"
|
||||
}
|
||||
|
||||
int PrimaryExp():
|
||||
{ int type=VAR; }
|
||||
{
|
||||
PrefixExp() ( LOOKAHEAD(2) type=PostfixOp() )* { return type; }
|
||||
}
|
||||
|
||||
int PostfixOp():
|
||||
{}
|
||||
{
|
||||
FieldOp() { return VAR; }
|
||||
| FuncOp() { return CALL; }
|
||||
}
|
||||
|
||||
void FieldOp():
|
||||
{}
|
||||
{
|
||||
"." <NAME>
|
||||
| "[" Exp() "]"
|
||||
}
|
||||
|
||||
void FuncOp():
|
||||
{}
|
||||
{
|
||||
":" <NAME> FuncArgs()
|
||||
| FuncArgs()
|
||||
}
|
||||
|
||||
void FuncArgs():
|
||||
{}
|
||||
{
|
||||
"(" ( ExpList() )? ")"
|
||||
| TableConstructor()
|
||||
| Str()
|
||||
}
|
||||
|
||||
void NameList():
|
||||
{}
|
||||
{
|
||||
<NAME> ( LOOKAHEAD(2) "," <NAME> )*
|
||||
}
|
||||
|
||||
void ExpList():
|
||||
{}
|
||||
{
|
||||
Exp() ( "," Exp() )*
|
||||
}
|
||||
|
||||
void SimpleExp():
|
||||
{}
|
||||
{
|
||||
<NIL>
|
||||
| <TRUE>
|
||||
| <FALSE>
|
||||
| <NUMBER>
|
||||
| Str()
|
||||
| "..."
|
||||
| TableConstructor()
|
||||
| FunctionCall()
|
||||
| PrimaryExp()
|
||||
}
|
||||
|
||||
void Str():
|
||||
{}
|
||||
{
|
||||
<STRING>
|
||||
| <CHARSTRING>
|
||||
| <LONGSTRING0>
|
||||
| <LONGSTRING1>
|
||||
| <LONGSTRING2>
|
||||
| <LONGSTRING3>
|
||||
| <LONGSTRINGN>
|
||||
}
|
||||
|
||||
void Exp():
|
||||
{}
|
||||
{
|
||||
SubExp()
|
||||
}
|
||||
|
||||
void SubExp():
|
||||
{}
|
||||
{
|
||||
( SimpleExp() | Unop() SubExp() ) (LOOKAHEAD(2) Binop() SubExp())*
|
||||
}
|
||||
|
||||
void FunctionCall():
|
||||
{}
|
||||
{
|
||||
<FUNCTION> FuncBody()
|
||||
}
|
||||
|
||||
void FuncBody():
|
||||
{}
|
||||
{
|
||||
"(" ( ParList() )? ")" Block() <END>
|
||||
}
|
||||
|
||||
void ParList():
|
||||
{}
|
||||
{
|
||||
NameList() ( "," "..." )? | "..."
|
||||
}
|
||||
|
||||
void TableConstructor():
|
||||
{}
|
||||
{
|
||||
"{" ( FieldList() )? "}"
|
||||
}
|
||||
|
||||
void FieldList():
|
||||
{}
|
||||
{
|
||||
Field() (LOOKAHEAD(2) FieldSep() Field())* (FieldSep())?
|
||||
}
|
||||
|
||||
void Field():
|
||||
{}
|
||||
{
|
||||
"[" Exp() "]" "=" Exp()
|
||||
| LOOKAHEAD(2) <NAME> "=" Exp()
|
||||
| Exp()
|
||||
}
|
||||
|
||||
void FieldSep():
|
||||
{}
|
||||
{
|
||||
"," | ";"
|
||||
}
|
||||
|
||||
void Binop():
|
||||
{}
|
||||
{
|
||||
"+" | "-" | "*" | "/" | "^" | "%" | ".." | "<" | "<=" | ">" | ">=" | "==" | "~=" | <AND> | <OR>
|
||||
}
|
||||
|
||||
void Unop():
|
||||
{}
|
||||
{
|
||||
"-" | <NOT> | "#"
|
||||
}
|
||||
531
luaj-jse/src/main/javacc/LuaParser.jj
Normal file
531
luaj-jse/src/main/javacc/LuaParser.jj
Normal file
@@ -0,0 +1,531 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2010-2012 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.
|
||||
******************************************************************************/
|
||||
/**
|
||||
* Javacc grammar used to produce a parse tree. Based on lua 5.2 syntax.
|
||||
*
|
||||
*/
|
||||
|
||||
options {
|
||||
STATIC = false;
|
||||
JDK_VERSION = "1.3";
|
||||
ERROR_REPORTING = true;
|
||||
UNICODE_INPUT = true;
|
||||
DEBUG_LOOKAHEAD = false;
|
||||
DEBUG_PARSER = false;
|
||||
DEBUG_TOKEN_MANAGER = false;
|
||||
OUTPUT_DIRECTORY = "src/jse/org/luaj/vm2/parser";
|
||||
}
|
||||
|
||||
PARSER_BEGIN(LuaParser)
|
||||
package org.luaj.vm2.parser;
|
||||
import org.luaj.vm2.*;
|
||||
import org.luaj.vm2.ast.*;
|
||||
import java.util.*;
|
||||
|
||||
public class LuaParser {
|
||||
static {
|
||||
LuaValue.valueOf(true);
|
||||
}
|
||||
|
||||
public static void main(String args[]) throws ParseException {
|
||||
LuaParser parser = new LuaParser(System.in);
|
||||
parser.Chunk();
|
||||
}
|
||||
|
||||
private static Exp.VarExp assertvarexp(Exp.PrimaryExp pe) throws ParseException {
|
||||
if (!pe.isvarexp())
|
||||
throw new ParseException("expected variable");
|
||||
return (Exp.VarExp) pe;
|
||||
}
|
||||
|
||||
private static Exp.FuncCall assertfunccall(Exp.PrimaryExp pe) throws ParseException {
|
||||
if (!pe.isfunccall())
|
||||
throw new ParseException("expected function call");
|
||||
return (Exp.FuncCall) pe;
|
||||
}
|
||||
|
||||
public SimpleCharStream getCharStream() {
|
||||
return jj_input_stream;
|
||||
}
|
||||
|
||||
private long LineInfo() {
|
||||
return ((long) jj_input_stream.getBeginLine() << 32) | jj_input_stream.getBeginColumn();
|
||||
}
|
||||
|
||||
private void L(SyntaxElement e, long startinfo) {
|
||||
e.beginLine = (int) (startinfo >> 32);
|
||||
e.beginColumn = (short) startinfo;
|
||||
e.endLine = token.endLine;
|
||||
e.endColumn = (short) token.endColumn;
|
||||
}
|
||||
|
||||
private void L(SyntaxElement e, Token starttoken) {
|
||||
e.beginLine = starttoken.beginLine;
|
||||
e.beginColumn = (short) starttoken.beginColumn;
|
||||
e.endLine = token.endLine;
|
||||
e.endColumn = (short) token.endColumn;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
PARSER_END(LuaParser)
|
||||
|
||||
/* WHITE SPACE */
|
||||
|
||||
SKIP :
|
||||
{
|
||||
" " | "\t" | "\n" | "\r" | "\f"
|
||||
}
|
||||
|
||||
/* COMMENTS and LONG STRINGS */
|
||||
|
||||
MORE :
|
||||
{
|
||||
"--[[": IN_LC0
|
||||
| "--[=[": IN_LC1
|
||||
| "--[==[": IN_LC2
|
||||
| "--[===[": IN_LC3
|
||||
| < "--[====" ("=")* "[" > : IN_LCN
|
||||
| "[[" : IN_LS0
|
||||
| "[=[" : IN_LS1
|
||||
| "[==[" : IN_LS2
|
||||
| "[===[" : IN_LS3
|
||||
| < "[====" ("=")* "[" > : IN_LSN
|
||||
| "--" : IN_COMMENT
|
||||
}
|
||||
|
||||
<IN_COMMENT> SPECIAL_TOKEN :
|
||||
{
|
||||
<COMMENT: (~["\n","\r"])* ("\n"|"\r"|"\r\n")? > : DEFAULT
|
||||
}
|
||||
|
||||
<IN_LC0> SPECIAL_TOKEN : { <LONGCOMMENT0: "]]" > : DEFAULT }
|
||||
<IN_LC1> SPECIAL_TOKEN : { <LONGCOMMENT1: "]=]" > : DEFAULT }
|
||||
<IN_LC2> SPECIAL_TOKEN : { <LONGCOMMENT2: "]==]" > : DEFAULT }
|
||||
<IN_LC3> SPECIAL_TOKEN : { <LONGCOMMENT3: "]===]" > : DEFAULT }
|
||||
<IN_LCN> SPECIAL_TOKEN : { <LONGCOMMENTN: "]====" ("=")* "]" > : DEFAULT }
|
||||
|
||||
<IN_LS0> TOKEN : { <LONGSTRING0: "]]" > : DEFAULT }
|
||||
<IN_LS1> TOKEN : { <LONGSTRING1: "]=]" > : DEFAULT }
|
||||
<IN_LS2> TOKEN : { <LONGSTRING2: "]==]" > : DEFAULT }
|
||||
<IN_LS3> TOKEN : { <LONGSTRING3: "]===]" > : DEFAULT }
|
||||
<IN_LSN> TOKEN : { <LONGSTRINGN: "]====" ("=")* "]" > : DEFAULT }
|
||||
|
||||
<IN_LC0,IN_LC1,IN_LC2,IN_LC3,IN_LCN,IN_LS0,IN_LS1,IN_LS2,IN_LS3,IN_LSN> MORE :
|
||||
{
|
||||
< ~[] >
|
||||
}
|
||||
|
||||
|
||||
/* RESERVED WORDS AND LITERALS */
|
||||
|
||||
TOKEN :
|
||||
{
|
||||
<AND: "and">
|
||||
| <BREAK: "break">
|
||||
| <DO: "do">
|
||||
| <ELSE: "else">
|
||||
| <ELSEIF: "elseif">
|
||||
| <END: "end">
|
||||
| <FALSE: "false">
|
||||
| <FOR: "for">
|
||||
| <FUNCTION: "function">
|
||||
| <GOTO: "goto">
|
||||
| <IF: "if">
|
||||
| <IN: "in">
|
||||
| <LOCAL: "local">
|
||||
| <NIL: "nil">
|
||||
| <NOT: "not">
|
||||
| <OR: "or">
|
||||
| <RETURN: "return">
|
||||
| <REPEAT: "repeat">
|
||||
| <THEN: "then">
|
||||
| <TRUE: "true">
|
||||
| <UNTIL: "until">
|
||||
| <WHILE: "while">
|
||||
}
|
||||
|
||||
/* LITERALS */
|
||||
|
||||
TOKEN :
|
||||
{
|
||||
< NAME: ["a"-"z", "A"-"Z", "_"] (["a"-"z", "A"-"Z", "_", "0"-"9"])* >
|
||||
| < NUMBER: <HEX> | <FLOAT> >
|
||||
| < #FLOAT: <FNUM> (<EXP>)? >
|
||||
| < #FNUM: (<DIGIT>)+ "." (<DIGIT>)* | "." (<DIGIT>)+ | (<DIGIT>)+ >
|
||||
| < #DIGIT: ["0"-"9"] >
|
||||
| < #EXP: ["e","E"] (["+","-"])? (<DIGIT>)+ >
|
||||
| < #HEX: "0" ["x","X"] <HEXNUM> (<HEXEXP>)? >
|
||||
| < #HEXNUM: (<HEXDIGIT>)+ "." (<HEXDIGIT>)* | "." (<HEXDIGIT>)+ | (<HEXDIGIT>)+ >
|
||||
| < #HEXDIGIT: ["0"-"9","a"-"f","A"-"F"] >
|
||||
| < #HEXEXP: ["e","E","p","P"] (["+","-"])? (<DIGIT>)+ >
|
||||
| < STRING: "\"" (<QUOTED> | ~["\\","\""])* "\"" >
|
||||
| < CHARSTRING: "'" (<QUOTED> | ~["\\","'"])* "'" >
|
||||
| < #QUOTED: <DECIMAL> | <UNICODE> | <CHAR> >
|
||||
| < #DECIMAL: "\\" ["0"-"9"] (["0"-"9"])? (["0"-"9"])? >
|
||||
| < DBCOLON: "::" >
|
||||
| < #UNICODE: "\\" "u" <HEXDIGIT> <HEXDIGIT> <HEXDIGIT> <HEXDIGIT> >
|
||||
| < #CHAR: "\\" (~[]) >
|
||||
| < #LF: ("\n" | "\r" | "\r\n") >
|
||||
}
|
||||
|
||||
/** Root production. */
|
||||
Chunk Chunk():
|
||||
{
|
||||
Block b;
|
||||
Chunk c;
|
||||
long i = LineInfo();
|
||||
}
|
||||
{
|
||||
( "#" { token_source.SwitchTo(IN_COMMENT); } )? b=Block() <EOF> { c=new Chunk(b); L(c,i); return c; }
|
||||
}
|
||||
|
||||
Block Block():
|
||||
{
|
||||
Block b = new Block();
|
||||
Stat s;
|
||||
long i = LineInfo();
|
||||
}
|
||||
{
|
||||
(s=Stat() {b.add(s);} )* (s=ReturnStat() {b.add(s);} )? { L(b,i); return b; }
|
||||
}
|
||||
|
||||
Stat Stat():
|
||||
{
|
||||
Block b,b2;
|
||||
Exp e,e2,e3=null;
|
||||
Stat s;
|
||||
FuncName fn;
|
||||
FuncBody fb;
|
||||
Token n;
|
||||
List<Name> nl;
|
||||
List<Exp> el=null;
|
||||
long i = LineInfo();
|
||||
}
|
||||
{
|
||||
";" { return null; }
|
||||
| s=Label() { L(s,i); return s; }
|
||||
| <BREAK> { s=Stat.breakstat(); L(s,i); return s; }
|
||||
| <GOTO> n=<NAME> { s=Stat.gotostat(n.image); L(s,i); return s; }
|
||||
| <DO> b=Block() <END> { s=Stat.block(b); L(s,i); return s; }
|
||||
| <WHILE> e=Exp() <DO> b=Block() <END> { s=Stat.whiledo(e,b); L(s,i); return s; }
|
||||
| <REPEAT> b=Block() <UNTIL> e=Exp() { s=Stat.repeatuntil(b,e); L(s,i); return s; }
|
||||
| s=IfThenElse() { L(s,i); return s; }
|
||||
| LOOKAHEAD(3) <FOR> n=<NAME> "=" e=Exp() "," e2=Exp() ( "," e3=Exp() )? <DO> b=Block() <END> { s=Stat.fornumeric(n.image,e,e2,e3,b); L(s,i); return s; }
|
||||
| <FOR> nl=NameList() <IN> el=ExpList() <DO> b=Block() <END> { s=Stat.forgeneric(nl,el,b); L(s,i); return s; }
|
||||
| <FUNCTION> fn=FuncName() fb=FuncBody() { s=Stat.functiondef(fn,fb); L(s,i); return s; }
|
||||
| LOOKAHEAD(2) <LOCAL> <FUNCTION> n=<NAME> fb=FuncBody() { s=Stat.localfunctiondef(n.image,fb); L(s,i); return s; }
|
||||
| <LOCAL> nl=NameList() ( "=" el=ExpList() )? { s=Stat.localassignment(nl,el); L(s,i); return s; }
|
||||
| s=ExprStat() { L(s,i); return s; }
|
||||
}
|
||||
|
||||
Stat IfThenElse():
|
||||
{
|
||||
Block b,b2,b3=null;
|
||||
Exp e,e2;
|
||||
List<Exp> el=null;
|
||||
List<Block> bl=null;
|
||||
}
|
||||
{
|
||||
<IF> e=Exp()
|
||||
<THEN> b=Block()
|
||||
(<ELSEIF> e2=Exp() <THEN> b2=Block() {
|
||||
if (el==null) el=new ArrayList<Exp>();
|
||||
if (bl==null) bl=new ArrayList<Block>();
|
||||
el.add(e2);
|
||||
bl.add(b2);
|
||||
} )*
|
||||
(<ELSE> b3=Block())? <END>
|
||||
{ return Stat.ifthenelse(e,b,el,bl,b3); }
|
||||
}
|
||||
|
||||
Stat ReturnStat():
|
||||
{
|
||||
List<Exp> el=null;
|
||||
Stat s;
|
||||
long i = LineInfo();
|
||||
}
|
||||
{
|
||||
<RETURN> ( el=ExpList() )? ( ";" )? { s=Stat.returnstat(el); L(s,i); return s; }
|
||||
}
|
||||
|
||||
Stat Label():
|
||||
{
|
||||
Token n;
|
||||
}
|
||||
{
|
||||
<DBCOLON> n=<NAME> <DBCOLON> { return Stat.labelstat(n.image); }
|
||||
}
|
||||
|
||||
Stat ExprStat():
|
||||
{
|
||||
Exp.PrimaryExp p;
|
||||
Stat s=null;
|
||||
long i = LineInfo();
|
||||
}
|
||||
{
|
||||
p=PrimaryExp() ( s=Assign(assertvarexp(p)) )?
|
||||
{ if (s==null) { s=Stat.functioncall(assertfunccall(p)); } L(s,i); return s; }
|
||||
}
|
||||
|
||||
Stat Assign(Exp.VarExp v0):
|
||||
{
|
||||
List<Exp.VarExp> vl = new ArrayList<Exp.VarExp>();
|
||||
vl.add(v0);
|
||||
Exp.VarExp ve;
|
||||
List<Exp> el;
|
||||
Stat s;
|
||||
long i = LineInfo();
|
||||
}
|
||||
{
|
||||
( "," ve=VarExp() { vl.add(ve); } )* "=" el=ExpList() { s=Stat.assignment(vl,el); L(s,i); return s; }
|
||||
}
|
||||
|
||||
Exp.VarExp VarExp():
|
||||
{
|
||||
Exp.PrimaryExp p;
|
||||
}
|
||||
{
|
||||
p=PrimaryExp() { return assertvarexp(p); }
|
||||
}
|
||||
|
||||
FuncName FuncName():
|
||||
{
|
||||
Token n;
|
||||
FuncName f;
|
||||
}
|
||||
{
|
||||
n=<NAME> {f=new FuncName(n.image);}
|
||||
( "." n=<NAME> {f.adddot(n.image);} )*
|
||||
( ":" n=<NAME> {f.method=n.image;} )?
|
||||
{L(f,n); return f;}
|
||||
}
|
||||
|
||||
Exp.PrimaryExp PrefixExp():
|
||||
{
|
||||
Token n;
|
||||
Exp e;
|
||||
Exp.PrimaryExp p;
|
||||
long i = LineInfo();
|
||||
}
|
||||
{
|
||||
n=<NAME> { p=Exp.nameprefix(n.image); L(p,i); return p; }
|
||||
| "(" e=Exp() ")" { p=Exp.parensprefix(e); L(p,i); return p; }
|
||||
}
|
||||
|
||||
Exp.PrimaryExp PrimaryExp():
|
||||
{
|
||||
Exp.PrimaryExp p;
|
||||
long i = LineInfo();
|
||||
}
|
||||
{
|
||||
p=PrefixExp() ( LOOKAHEAD(2) p=PostfixOp(p) )* { L(p,i); return p; }
|
||||
}
|
||||
|
||||
Exp.PrimaryExp PostfixOp(Exp.PrimaryExp lhs):
|
||||
{
|
||||
Token n;
|
||||
Exp e;
|
||||
FuncArgs a;
|
||||
Exp.PrimaryExp p;
|
||||
long i = LineInfo();
|
||||
}
|
||||
{
|
||||
"." n=<NAME> { p=Exp.fieldop(lhs, n.image); L(p,i); return p; }
|
||||
| "[" e=Exp() "]" { p=Exp.indexop(lhs, e); L(p,i); return p; }
|
||||
| ":" n=<NAME> a=FuncArgs() { p=Exp.methodop(lhs, n.image,a); L(p,i); return p; }
|
||||
| a=FuncArgs() { p=Exp.functionop(lhs, a); L(p,i); return p; }
|
||||
}
|
||||
|
||||
FuncArgs FuncArgs():
|
||||
{
|
||||
List<Exp> el=null;
|
||||
TableConstructor tc;
|
||||
LuaString s;
|
||||
FuncArgs a;
|
||||
long i = LineInfo();
|
||||
}
|
||||
{
|
||||
"(" ( el=ExpList() )? ")" { a=FuncArgs.explist(el); L(a,i); return a; }
|
||||
| tc=TableConstructor() { a=FuncArgs.tableconstructor(tc); L(a,i); return a; }
|
||||
| s=Str() { a=FuncArgs.string(s); L(a,i); return a; }
|
||||
}
|
||||
|
||||
List<Name> NameList():
|
||||
{
|
||||
List<Name> l = new ArrayList<Name>();
|
||||
Token name;
|
||||
}
|
||||
{
|
||||
name=<NAME> {l.add(new Name(name.image));} ( LOOKAHEAD(2) "," name=<NAME> {l.add(new Name(name.image));} )* {return l;}
|
||||
}
|
||||
|
||||
List<Exp> ExpList():
|
||||
{
|
||||
List<Exp> l = new ArrayList<Exp>();
|
||||
Exp e;
|
||||
}
|
||||
{
|
||||
e=Exp() {l.add(e);} ( "," e=Exp() {l.add(e);} )* {return l;}
|
||||
}
|
||||
|
||||
Exp SimpleExp():
|
||||
{
|
||||
Token n;
|
||||
LuaString s;
|
||||
Exp e;
|
||||
TableConstructor c;
|
||||
FuncBody b;
|
||||
long i = LineInfo();
|
||||
}
|
||||
{
|
||||
<NIL> { e=Exp.constant(LuaValue.NIL); L(e,i); return e; }
|
||||
| <TRUE> { e=Exp.constant(LuaValue.TRUE); L(e,i); return e; }
|
||||
| <FALSE> { e=Exp.constant(LuaValue.FALSE); L(e,i); return e; }
|
||||
| n=<NUMBER> { e=Exp.numberconstant(n.image); L(e,i); return e; }
|
||||
| s=Str() { e=Exp.constant(s); L(e,i); return e; }
|
||||
| "..." { e=Exp.varargs(); L(e,i); return e; }
|
||||
| c=TableConstructor() { e=Exp.tableconstructor(c); L(e,i); return e; }
|
||||
| b=FunctionCall() { e=Exp.anonymousfunction(b); L(e,i); return e; }
|
||||
| e=PrimaryExp() { return e; }
|
||||
}
|
||||
|
||||
LuaString Str():
|
||||
{}
|
||||
{
|
||||
<STRING> { return Str.quoteString(token.image); }
|
||||
| <CHARSTRING> { return Str.charString(token.image); }
|
||||
| <LONGSTRING0> { return Str.longString(token.image); }
|
||||
| <LONGSTRING1> { return Str.longString(token.image); }
|
||||
| <LONGSTRING2> { return Str.longString(token.image); }
|
||||
| <LONGSTRING3> { return Str.longString(token.image); }
|
||||
| <LONGSTRINGN> { return Str.longString(token.image); }
|
||||
}
|
||||
|
||||
Exp Exp():
|
||||
{
|
||||
Exp e,s;
|
||||
int op;
|
||||
long i = LineInfo();
|
||||
}
|
||||
{
|
||||
( e=SimpleExp() | op=Unop() s=Exp() {e=Exp.unaryexp(op,s);})
|
||||
(LOOKAHEAD(2) op=Binop() s=Exp() {e=Exp.binaryexp(e,op,s);} )* { L(e,i); return e; }
|
||||
}
|
||||
|
||||
FuncBody FunctionCall():
|
||||
{
|
||||
FuncBody b;
|
||||
long i = LineInfo();
|
||||
}
|
||||
{
|
||||
<FUNCTION> b=FuncBody() { L(b,i); return b; }
|
||||
}
|
||||
|
||||
FuncBody FuncBody():
|
||||
{
|
||||
ParList pl=null;
|
||||
Block b;
|
||||
FuncBody f;
|
||||
long i = LineInfo();
|
||||
}
|
||||
{
|
||||
"(" ( pl=ParList() )? ")" b=Block() <END> { f=new FuncBody(pl,b); L(f,i); return f; }
|
||||
}
|
||||
|
||||
ParList ParList():
|
||||
{
|
||||
List<Name> l=null;
|
||||
boolean v=false;
|
||||
ParList p;
|
||||
long i = LineInfo();
|
||||
}
|
||||
{
|
||||
l=NameList() ( "," "..." { v=true; } )? { p=new ParList(l,v); L(p,i); return p; }
|
||||
| "..." { p=new ParList(null,true); L(p,i); return p; }
|
||||
}
|
||||
|
||||
TableConstructor TableConstructor():
|
||||
{
|
||||
TableConstructor c = new TableConstructor();
|
||||
List<TableField> l = null;
|
||||
long i = LineInfo();
|
||||
}
|
||||
{
|
||||
"{" ( l=FieldList() {c.fields=l;} )? "}" { L(c,i); return c; }
|
||||
}
|
||||
|
||||
List<TableField> FieldList():
|
||||
{
|
||||
List<TableField> l = new ArrayList<TableField>();
|
||||
TableField f;
|
||||
}
|
||||
{
|
||||
f=Field() {l.add(f);} (LOOKAHEAD(2) FieldSep() f=Field() {l.add(f);})* (FieldSep())? { return l; }
|
||||
}
|
||||
|
||||
TableField Field():
|
||||
{
|
||||
Token name;
|
||||
Exp exp,rhs;
|
||||
TableField f;
|
||||
long i = LineInfo();
|
||||
}
|
||||
{
|
||||
"[" exp=Exp() "]" "=" rhs=Exp() { f=TableField.keyedField(exp,rhs); L(f,i); return f; }
|
||||
| LOOKAHEAD(2) name=<NAME> "=" rhs=Exp() { f=TableField.namedField(name.image,rhs); L(f,i); return f; }
|
||||
| rhs=Exp() { f=TableField.listField(rhs); L(f,i); return f; }
|
||||
}
|
||||
|
||||
void FieldSep():
|
||||
{}
|
||||
{
|
||||
"," | ";"
|
||||
}
|
||||
|
||||
int Binop():
|
||||
{}
|
||||
{
|
||||
"+" { return Lua.OP_ADD; }
|
||||
| "-" { return Lua.OP_SUB; }
|
||||
| "*" { return Lua.OP_MUL; }
|
||||
| "/" { return Lua.OP_DIV; }
|
||||
| "^" { return Lua.OP_POW; }
|
||||
| "%" { return Lua.OP_MOD; }
|
||||
| ".." { return Lua.OP_CONCAT; }
|
||||
| "<" { return Lua.OP_LT; }
|
||||
| "<=" { return Lua.OP_LE; }
|
||||
| ">" { return Lua.OP_GT; }
|
||||
| ">=" { return Lua.OP_GE; }
|
||||
| "==" { return Lua.OP_EQ; }
|
||||
| "~=" { return Lua.OP_NEQ; }
|
||||
| <AND> { return Lua.OP_AND; }
|
||||
| <OR> { return Lua.OP_OR; }
|
||||
}
|
||||
|
||||
int Unop():
|
||||
{}
|
||||
{
|
||||
"-" { return Lua.OP_UNM; }
|
||||
| <NOT> { return Lua.OP_NOT; }
|
||||
| "#" { return Lua.OP_LEN; }
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
org.luaj.vm2.script.LuaScriptEngineFactory
|
||||
148
luaj-jse/src/test/java/org/luaj/jse/DumpLoadEndianIntTest.java
Normal file
148
luaj-jse/src/test/java/org/luaj/jse/DumpLoadEndianIntTest.java
Normal file
@@ -0,0 +1,148 @@
|
||||
package org.luaj.jse;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaClosure;
|
||||
import org.luaj.vm2.LuaFunction;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.compiler.DumpState;
|
||||
import org.luaj.vm2.lib.jse.JsePlatform;
|
||||
|
||||
class DumpLoadEndianIntTest {
|
||||
private static final String SAVECHUNKS = "SAVECHUNKS";
|
||||
|
||||
private static final boolean SHOULDPASS = true;
|
||||
private static final boolean SHOULDFAIL = false;
|
||||
private static final String mixedscript = "return tostring(1234)..'-#!-'..tostring(23.75)";
|
||||
private static final String intscript = "return tostring(1234)..'-#!-'..tostring(23)";
|
||||
private static final String withdoubles = "1234-#!-23.75";
|
||||
private static final String withints = "1234-#!-23";
|
||||
|
||||
private Globals globals;
|
||||
|
||||
@BeforeEach
|
||||
protected void setUp() throws Exception {
|
||||
globals = JsePlatform.standardGlobals();
|
||||
DumpState.ALLOW_INTEGER_CASTING = false;
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBigDoubleCompile() {
|
||||
doTest(false, DumpState.NUMBER_FORMAT_FLOATS_OR_DOUBLES, false, mixedscript, withdoubles, withdoubles,
|
||||
SHOULDPASS);
|
||||
doTest(false, DumpState.NUMBER_FORMAT_FLOATS_OR_DOUBLES, true, mixedscript, withdoubles, withdoubles,
|
||||
SHOULDPASS);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLittleDoubleCompile() {
|
||||
doTest(true, DumpState.NUMBER_FORMAT_FLOATS_OR_DOUBLES, false, mixedscript, withdoubles, withdoubles,
|
||||
SHOULDPASS);
|
||||
doTest(true, DumpState.NUMBER_FORMAT_FLOATS_OR_DOUBLES, true, mixedscript, withdoubles, withdoubles,
|
||||
SHOULDPASS);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBigIntCompile() {
|
||||
DumpState.ALLOW_INTEGER_CASTING = true;
|
||||
doTest(false, DumpState.NUMBER_FORMAT_INTS_ONLY, false, mixedscript, withdoubles, withints, SHOULDPASS);
|
||||
doTest(false, DumpState.NUMBER_FORMAT_INTS_ONLY, true, mixedscript, withdoubles, withints, SHOULDPASS);
|
||||
DumpState.ALLOW_INTEGER_CASTING = false;
|
||||
doTest(false, DumpState.NUMBER_FORMAT_INTS_ONLY, false, mixedscript, withdoubles, withints, SHOULDFAIL);
|
||||
doTest(false, DumpState.NUMBER_FORMAT_INTS_ONLY, true, mixedscript, withdoubles, withints, SHOULDFAIL);
|
||||
doTest(false, DumpState.NUMBER_FORMAT_INTS_ONLY, false, intscript, withints, withints, SHOULDPASS);
|
||||
doTest(false, DumpState.NUMBER_FORMAT_INTS_ONLY, true, intscript, withints, withints, SHOULDPASS);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLittleIntCompile() {
|
||||
DumpState.ALLOW_INTEGER_CASTING = true;
|
||||
doTest(true, DumpState.NUMBER_FORMAT_INTS_ONLY, false, mixedscript, withdoubles, withints, SHOULDPASS);
|
||||
doTest(true, DumpState.NUMBER_FORMAT_INTS_ONLY, true, mixedscript, withdoubles, withints, SHOULDPASS);
|
||||
DumpState.ALLOW_INTEGER_CASTING = false;
|
||||
doTest(true, DumpState.NUMBER_FORMAT_INTS_ONLY, false, mixedscript, withdoubles, withints, SHOULDFAIL);
|
||||
doTest(true, DumpState.NUMBER_FORMAT_INTS_ONLY, true, mixedscript, withdoubles, withints, SHOULDFAIL);
|
||||
doTest(true, DumpState.NUMBER_FORMAT_INTS_ONLY, false, intscript, withints, withints, SHOULDPASS);
|
||||
doTest(true, DumpState.NUMBER_FORMAT_INTS_ONLY, true, intscript, withints, withints, SHOULDPASS);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBigNumpatchCompile() {
|
||||
doTest(false, DumpState.NUMBER_FORMAT_NUM_PATCH_INT32, false, mixedscript, withdoubles, withdoubles,
|
||||
SHOULDPASS);
|
||||
doTest(false, DumpState.NUMBER_FORMAT_NUM_PATCH_INT32, true, mixedscript, withdoubles, withdoubles, SHOULDPASS);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLittleNumpatchCompile() {
|
||||
doTest(true, DumpState.NUMBER_FORMAT_NUM_PATCH_INT32, false, mixedscript, withdoubles, withdoubles, SHOULDPASS);
|
||||
doTest(true, DumpState.NUMBER_FORMAT_NUM_PATCH_INT32, true, mixedscript, withdoubles, withdoubles, SHOULDPASS);
|
||||
}
|
||||
|
||||
private void doTest(boolean littleEndian, int numberFormat, boolean stripDebug, String script,
|
||||
String expectedPriorDump, String expectedPostDump, boolean shouldPass) {
|
||||
try {
|
||||
|
||||
// compile into prototype
|
||||
Reader reader = new StringReader(script);
|
||||
Prototype p = globals.compilePrototype(reader, "script");
|
||||
|
||||
// double check script result before dumping
|
||||
LuaFunction f = new LuaClosure(p, globals);
|
||||
LuaValue r = f.call();
|
||||
String actual = r.tojstring();
|
||||
assertEquals(expectedPriorDump, actual);
|
||||
|
||||
// dump into bytes
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try {
|
||||
DumpState.dump(p, baos, stripDebug, numberFormat, littleEndian);
|
||||
if (!shouldPass)
|
||||
fail("dump should not have succeeded");
|
||||
} catch (Exception e) {
|
||||
if (shouldPass)
|
||||
fail("dump threw " + e);
|
||||
else
|
||||
return;
|
||||
}
|
||||
byte[] dumped = baos.toByteArray();
|
||||
|
||||
// load again using compiler
|
||||
InputStream is = new ByteArrayInputStream(dumped);
|
||||
f = globals.load(is, "dumped", "b", globals).checkfunction();
|
||||
r = f.call();
|
||||
actual = r.tojstring();
|
||||
assertEquals(expectedPostDump, actual);
|
||||
|
||||
// write test chunk
|
||||
if (System.getProperty(SAVECHUNKS) != null && script.equals(mixedscript)) {
|
||||
new File("build").mkdirs();
|
||||
String filename = "build/test-" + (littleEndian? "little-": "big-")
|
||||
+ (numberFormat == DumpState.NUMBER_FORMAT_FLOATS_OR_DOUBLES? "double-"
|
||||
: numberFormat == DumpState.NUMBER_FORMAT_INTS_ONLY? "int-"
|
||||
: numberFormat == DumpState.NUMBER_FORMAT_NUM_PATCH_INT32? "numpatch4-": "???-")
|
||||
+ (stripDebug? "nodebug-": "debug-") + "bin.lua";
|
||||
FileOutputStream fos = new FileOutputStream(filename);
|
||||
fos.write(dumped);
|
||||
fos.close();
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
fail(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
460
luaj-jse/src/test/java/org/luaj/jse/FragmentsTest.java
Normal file
460
luaj-jse/src/test/java/org/luaj/jse/FragmentsTest.java
Normal file
@@ -0,0 +1,460 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.jse;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaClosure;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Print;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.lib.jse.JsePlatform;
|
||||
import org.luaj.vm2.luajc.LuaJC;
|
||||
|
||||
/**
|
||||
* Test compilation of various fragments that have caused problems for jit
|
||||
* compiling during development.
|
||||
*
|
||||
*/
|
||||
public class FragmentsTest {
|
||||
|
||||
static final int TEST_TYPE_LUAC = 0;
|
||||
static final int TEST_TYPE_LUAJC = 1;
|
||||
|
||||
@Nested
|
||||
public static class JseFragmentsTest extends FragmentsTestCase {
|
||||
public JseFragmentsTest() { super(TEST_TYPE_LUAC); }
|
||||
}
|
||||
|
||||
@Nested
|
||||
public static class LuaJCFragmentsTest extends FragmentsTestCase {
|
||||
public LuaJCFragmentsTest() { super(TEST_TYPE_LUAJC); }
|
||||
}
|
||||
|
||||
abstract protected static class FragmentsTestCase {
|
||||
|
||||
final int TEST_TYPE;
|
||||
|
||||
protected FragmentsTestCase(int testType) {
|
||||
this.TEST_TYPE = testType;
|
||||
}
|
||||
|
||||
public void runFragment(Varargs expected, String script) {
|
||||
try {
|
||||
String name = this.getClass().getName();
|
||||
Globals globals = JsePlatform.debugGlobals();
|
||||
Reader reader = new StringReader(script);
|
||||
LuaValue chunk;
|
||||
switch (TEST_TYPE) {
|
||||
case TEST_TYPE_LUAJC:
|
||||
LuaJC.install(globals);
|
||||
chunk = globals.load(reader, name);
|
||||
break;
|
||||
default:
|
||||
Prototype p = globals.compilePrototype(reader, name);
|
||||
chunk = new LuaClosure(p, globals);
|
||||
Print.print(p);
|
||||
break;
|
||||
}
|
||||
Varargs actual = chunk.invoke();
|
||||
assertEquals(expected.narg(), actual.narg());
|
||||
for (int i = 1; i <= actual.narg(); i++)
|
||||
assertEquals(expected.arg(i), actual.arg(i));
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
fail(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFirstArgNilExtended() {
|
||||
runFragment(LuaValue.NIL, "function f1(a) print( 'f1:', a ) return a end\n" + "b = f1()\n" + "return b");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleForloop() {
|
||||
runFragment(LuaValue.valueOf(77),
|
||||
"for n,p in ipairs({77}) do\n" + " print('n,p',n,p)\n" + " return p\n" + "end\n");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForloopParamUpvalues() {
|
||||
runFragment(LuaValue.varargsOf(new LuaValue[] { LuaValue.valueOf(77), LuaValue.valueOf(1) }),
|
||||
"for n,p in ipairs({77}) do\n" + " print('n,p',n,p)\n" + " foo = function()\n" + " return p,n\n"
|
||||
+ " end\n" + " return foo()\n" + "end\n");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArgVarargsUseBoth() {
|
||||
runFragment(
|
||||
LuaValue
|
||||
.varargsOf(new LuaValue[] { LuaValue.valueOf("a"), LuaValue.valueOf("b"), LuaValue.valueOf("c") }),
|
||||
"function v(arg,...)\n" + " return arg,...\n" + "end\n" + "return v('a','b','c')\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArgParamUseNone() {
|
||||
runFragment(LuaValue.valueOf("string"),
|
||||
"function v(arg,...)\n" + " return type(arg)\n" + "end\n" + "return v('abc')\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetlistVarargs() {
|
||||
runFragment(LuaValue.valueOf("abc"),
|
||||
"local f = function() return 'abc' end\n" + "local g = { f() }\n" + "return g[1]\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelfOp() {
|
||||
runFragment(LuaValue.valueOf("bcd"), "local s = 'abcde'\n" + "return s:sub(2,4)\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetListWithOffsetAndVarargs() {
|
||||
runFragment(LuaValue.valueOf(1003), "local bar = {1000, math.sqrt(9)}\n" + "return bar[1]+bar[2]\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiAssign() {
|
||||
// arargs evaluations are all done before assignments
|
||||
runFragment(
|
||||
LuaValue
|
||||
.varargsOf(new LuaValue[] { LuaValue.valueOf(111), LuaValue.valueOf(111), LuaValue.valueOf(111) }),
|
||||
"a,b,c = 1,10,100\n" + "a,b,c = a+b+c, a+b+c, a+b+c\n" + "return a,b,c\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpvalues() {
|
||||
runFragment(LuaValue.valueOf(999),
|
||||
"local a = function(x)\n" + " return function(y)\n" + " return x + y\n" + " end\n" + "end\n"
|
||||
+ "local b = a(222)\n" + "local c = b(777)\n" + "print( 'c=', c )\n" + "return c\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonAsciiStringLiterals() {
|
||||
runFragment(LuaValue.valueOf("7,8,12,10,9,11,133,222"), "local a='\\a\\b\\f\\n\\t\\v\\133\\222'\n"
|
||||
+ "local t={string.byte(a,1,#a)}\n" + "return table.concat(t,',')\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testControlCharStringLiterals() {
|
||||
runFragment(LuaValue.valueOf("97,0,98,18,99,18,100,18,48,101"), "local a='a\\0b\\18c\\018d\\0180e'\n"
|
||||
+ "local t={string.byte(a,1,#a)}\n" + "return table.concat(t,',')\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoopVarNames() {
|
||||
runFragment(LuaValue.valueOf(" 234,1,aa 234,2,bb"),
|
||||
"local w = ''\n" + "function t()\n" + " for f,var in ipairs({'aa','bb'}) do\n" + " local s = 234\n"
|
||||
+ " w = w..' '..s..','..f..','..var\n" + " end\n" + "end\n" + "t()\n" + "return w\n");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForLoops() {
|
||||
runFragment(LuaValue.valueOf("12345 357 963"),
|
||||
"local s,t,u = '','',''\n" + "for m=1,5 do\n" + " s = s..m\n" + "end\n" + "for m=3,7,2 do\n"
|
||||
+ " t = t..m\n" + "end\n" + "for m=9,3,-3 do\n" + " u = u..m\n" + "end\n"
|
||||
+ "return s..' '..t..' '..u\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocalFunctionDeclarations() {
|
||||
runFragment(LuaValue.varargsOf(LuaValue.valueOf("function"), LuaValue.valueOf("nil")),
|
||||
"local function aaa()\n" + " return type(aaa)\n" + "end\n" + "local bbb = function()\n"
|
||||
+ " return type(bbb)\n" + "end\n" + "return aaa(),bbb()\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNilsInTableConstructor() {
|
||||
runFragment(LuaValue.valueOf("1=111 2=222 3=333 "),
|
||||
"local t = { 111, 222, 333, nil, nil }\n" + "local s = ''\n" + "for i,v in ipairs(t) do \n"
|
||||
+ " s=s..tostring(i)..'='..tostring(v)..' '\n" + "end\n" + "return s\n");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnreachableCode() {
|
||||
runFragment(LuaValue.valueOf(66),
|
||||
"local function foo(x) return x * 2 end\n" + "local function bar(x, y)\n" + " if x==y then\n"
|
||||
+ " return y\n" + " else\n" + " return foo(x)\n" + " end\n" + "end\n"
|
||||
+ "return bar(33,44)\n");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVarargsWithParameters() {
|
||||
runFragment(LuaValue.valueOf(222),
|
||||
"local func = function(t,...)\n" + " return (...)\n" + "end\n" + "return func(111,222,333)\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoReturnValuesPlainCall() {
|
||||
runFragment(LuaValue.TRUE, "local testtable = {}\n" + "return pcall( function() testtable[1]=2 end )\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVarargsInTableConstructor() {
|
||||
runFragment(LuaValue.valueOf(222), "local function foo() return 111,222,333 end\n"
|
||||
+ "local t = {'a','b',c='c',foo()}\n" + "return t[4]\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVarargsInFirstArg() {
|
||||
runFragment(LuaValue.valueOf(123), "function aaa(x) return x end\n" + "function bbb(y) return y end\n"
|
||||
+ "function ccc(z) return z end\n" + "return ccc( aaa(bbb(123)), aaa(456) )\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetUpvalueTableInitializer() {
|
||||
runFragment(LuaValue.valueOf("b"), "local aliases = {a='b'}\n" + "local foo = function()\n"
|
||||
+ " return aliases\n" + "end\n" + "return foo().a\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadNilUpvalue() {
|
||||
runFragment(LuaValue.NIL, "tostring = function() end\n" + "local pc \n" + "local pcall = function(...)\n"
|
||||
+ " pc(...)\n" + "end\n" + "return NIL\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpvalueClosure() {
|
||||
runFragment(LuaValue.NIL, "print()\n" + "local function f2() end\n" + "local function f3()\n"
|
||||
+ " return f3\n" + "end\n" + "return NIL\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUninitializedUpvalue() {
|
||||
runFragment(LuaValue.NIL, "local f\n" + "do\n" + " function g()\n" + " print(f())\n" + " end\n"
|
||||
+ "end\n" + "return NIL\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTestOpUpvalues() {
|
||||
runFragment(LuaValue.varargsOf(LuaValue.valueOf(1), LuaValue.valueOf(2), LuaValue.valueOf(3)),
|
||||
"print( nil and 'T' or 'F' )\n" + "local a,b,c = 1,2,3\n" + "function foo()\n" + " return a,b,c\n"
|
||||
+ "end\n" + "return foo()\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTestSimpleBinops() {
|
||||
runFragment(
|
||||
LuaValue.varargsOf(
|
||||
new LuaValue[] { LuaValue.FALSE, LuaValue.FALSE, LuaValue.TRUE, LuaValue.TRUE, LuaValue.FALSE }),
|
||||
"local a,b,c = 2,-2.5,0\n" + "return (a==c), (b==c), (a==a), (a>c), (b>0)\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNumericForUpvalues() {
|
||||
runFragment(LuaValue.valueOf(8), "for i = 3,4 do\n" + " i = i + 5\n" + " local a = function()\n"
|
||||
+ " return i\n" + " end\n" + " return a()\n" + "end\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNumericForUpvalues2() {
|
||||
runFragment(LuaValue.valueOf("222 222"),
|
||||
"local t = {}\n" + "local template = [[123 456]]\n" + "for i = 1,2 do\n"
|
||||
+ " t[i] = template:gsub('%d', function(s)\n" + " return i\n" + " end)\n" + "end\n"
|
||||
+ "return t[2]\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReturnUpvalue() {
|
||||
runFragment(LuaValue.varargsOf(new LuaValue[] { LuaValue.ONE, LuaValue.valueOf(5), }), "local a = 1\n"
|
||||
+ "local b\n" + "function c()\n" + " b=5\n" + " return a\n" + "end\n" + "return c(),b\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUninitializedAroundBranch() {
|
||||
runFragment(LuaValue.valueOf(333),
|
||||
"local state\n" + "if _G then\n" + " state = 333\n" + "end\n" + "return state\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadedNilUpvalue() {
|
||||
runFragment(LuaValue.NIL, "local a = print()\n" + "local b = c and { d = e }\n" + "local f\n"
|
||||
+ "local function g()\n" + " return f\n" + "end\n" + "return g()\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpvalueInFirstSlot() {
|
||||
runFragment(LuaValue.valueOf("foo"), "local p = {'foo'}\n" + "bar = function()\n" + " return p \n"
|
||||
+ "end\n" + "for i,key in ipairs(p) do\n" + " print()\n" + "end\n" + "return bar()[1]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadOnlyAndReadWriteUpvalues() {
|
||||
runFragment(LuaValue.varargsOf(new LuaValue[] { LuaValue.valueOf(333), LuaValue.valueOf(222) }),
|
||||
"local a = 111\n" + "local b = 222\n" + "local c = function()\n" + " a = a + b\n"
|
||||
+ " return a,b\n" + "end\n" + "return c()\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNestedUpvalues() {
|
||||
runFragment(
|
||||
LuaValue.varargsOf(new LuaValue[] { LuaValue.valueOf(5), LuaValue.valueOf(8), LuaValue.valueOf(9) }),
|
||||
"local x = 3\n" + "local y = 5\n" + "local function f()\n" + " return y\n" + "end\n"
|
||||
+ "local function g(x1, y1)\n" + " x = x1\n" + " y = y1\n" + " return x,y\n" + "end\n"
|
||||
+ "return f(), g(8,9)\n" + "\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadBool() {
|
||||
runFragment(LuaValue.NONE, "print( type(foo)=='string' )\n" + "local a,b\n" + "if print() then\n"
|
||||
+ " b = function()\n" + " return a\n" + " end\n" + "end\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicForLoop() {
|
||||
runFragment(LuaValue.valueOf(2), "local data\n" + "for i = 1, 2 do\n" + " data = i\n" + "end\n"
|
||||
+ "local bar = function()\n" + " return data\n" + "end\n" + "return bar()\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenericForMultipleValues() {
|
||||
runFragment(LuaValue.varargsOf(LuaValue.valueOf(3), LuaValue.valueOf(2), LuaValue.valueOf(1)),
|
||||
"local iter = function() return 1,2,3,4 end\n" + "local foo = function() return iter,5 end\n"
|
||||
+ "for a,b,c in foo() do\n" + " return c,b,a\n" + "end\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPhiUpvalue() {
|
||||
runFragment(LuaValue.valueOf(6), "local a = foo or 0\n" + "local function b(c)\n"
|
||||
+ " if c > a then a = c end\n" + " return a\n" + "end\n" + "b(6)\n" + "return a\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAssignReferUpvalues() {
|
||||
runFragment(LuaValue.valueOf(123), "local entity = 234\n" + "local function c()\n" + " return entity\n"
|
||||
+ "end\n" + "entity = (a == b) and 123\n" + "if entity then\n" + " return entity\n" + "end\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleRepeatUntil() {
|
||||
runFragment(LuaValue.valueOf(5),
|
||||
"local a\n" + "local w\n" + "repeat\n" + " a = w\n" + "until not a\n" + "return 5\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoopVarUpvalues() {
|
||||
runFragment(LuaValue.valueOf("b"),
|
||||
"local env = {}\n" + "for a,b in pairs(_G) do\n" + " c = function()\n" + " return b\n"
|
||||
+ " end\n" + "end\n" + "local e = env\n" + "local f = {a='b'}\n" + "for k,v in pairs(f) do\n"
|
||||
+ " return env[k] or v\n" + "end\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPhiVarUpvalue() {
|
||||
runFragment(LuaValue.valueOf(2), "local a = 1\n" + "local function b()\n" + " a = a + 1\n"
|
||||
+ " return function() end\n" + "end\n" + "for i in b() do\n" + " a = 3\n" + "end\n" + "return a\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpvaluesInElseClauses() {
|
||||
runFragment(LuaValue.valueOf(111),
|
||||
"if a then\n" + " foo(bar)\n" + "elseif _G then\n" + " local x = 111\n" + " if d then\n"
|
||||
+ " foo(bar)\n" + " else\n" + " local y = function()\n" + " return x\n"
|
||||
+ " end\n" + " return y()\n" + " end\n" + "end\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpvalueInDoBlock() {
|
||||
runFragment(LuaValue.NONE,
|
||||
"do\n" + " local x = 10\n" + " function g()\n" + " return x\n" + " end\n" + "end\n" + "g()\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullError() {
|
||||
runFragment(LuaValue.varargsOf(LuaValue.FALSE, LuaValue.NIL), "return pcall(error)\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindWithOffset() {
|
||||
runFragment(LuaValue.varargsOf(LuaValue.valueOf(8), LuaValue.valueOf(5)), "string = \"abcdef:ghi\"\n"
|
||||
+ "substring = string:sub(3)\n" + "idx = substring:find(\":\")\n" + "return #substring, idx\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testErrorArgIsString() {
|
||||
runFragment(LuaValue.varargsOf(LuaValue.valueOf("string"), LuaValue.valueOf("c")),
|
||||
"a,b = pcall(error, 'c'); return type(b), b\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testErrorArgIsNil() {
|
||||
runFragment(LuaValue.varargsOf(LuaValue.valueOf("nil"), LuaValue.NIL),
|
||||
"a,b = pcall(error); return type(b), b\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testErrorArgIsTable() {
|
||||
runFragment(LuaValue.varargsOf(LuaValue.valueOf("table"), LuaValue.valueOf("d")),
|
||||
"a,b = pcall(error, {c='d'}); return type(b), b.c\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testErrorArgIsNumber() {
|
||||
runFragment(LuaValue.varargsOf(LuaValue.valueOf("string"), LuaValue.valueOf("1")),
|
||||
"a,b = pcall(error, 1); return type(b), b\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testErrorArgIsBool() {
|
||||
runFragment(LuaValue.varargsOf(LuaValue.valueOf("boolean"), LuaValue.TRUE),
|
||||
"a,b = pcall(error, true); return type(b), b\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBalancedMatchOnEmptyString() {
|
||||
runFragment(LuaValue.NIL, "return (\"\"):match(\"%b''\")\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReturnValueForTableRemove() {
|
||||
runFragment(LuaValue.NONE, "return table.remove({ })");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTypeOfTableRemoveReturnValue() {
|
||||
runFragment(LuaValue.valueOf("nil"), "local k = table.remove({ }) return type(k)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVarargBugReport() {
|
||||
runFragment(
|
||||
LuaValue.varargsOf(new LuaValue[] { LuaValue.valueOf(1), LuaValue.valueOf(2), LuaValue.valueOf(3) }),
|
||||
"local i = function(...) return ... end\n" + "local v1, v2, v3 = i(1, 2, 3)\n" + "return v1, v2, v3");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
78
luaj-jse/src/test/java/org/luaj/jse/LoadOrderTest.java
Normal file
78
luaj-jse/src/test/java/org/luaj/jse/LoadOrderTest.java
Normal file
@@ -0,0 +1,78 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2015 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.jse;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.lib.jse.JsePlatform;
|
||||
import org.luaj.vm2.server.Launcher;
|
||||
import org.luaj.vm2.server.LuajClassLoader;
|
||||
|
||||
// Tests using class loading orders that have caused problems for some use cases.
|
||||
class LoadOrderTest {
|
||||
|
||||
@Test
|
||||
void testLoadGlobalsFirst() {
|
||||
Globals g = JsePlatform.standardGlobals();
|
||||
assertNotNull(g);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoadStringFirst() {
|
||||
LuaString BAR = LuaString.valueOf("bar");
|
||||
assertNotNull(BAR);
|
||||
}
|
||||
|
||||
public static class TestLauncherLoadStringFirst implements Launcher {
|
||||
// Static initializer that causes LuaString->LuaValue->LuaString
|
||||
private static final LuaString FOO = LuaString.valueOf("foo");
|
||||
|
||||
@Override
|
||||
public Object[] launch(String script, Object[] arg) {
|
||||
return new Object[] { FOO };
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] launch(InputStream script, Object[] arg) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] launch(Reader script, Object[] arg) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testClassLoadsStringFirst() throws Exception {
|
||||
Launcher launcher = LuajClassLoader.NewLauncher(TestLauncherLoadStringFirst.class);
|
||||
Object[] results = launcher.launch("foo", null);
|
||||
assertNotNull(results);
|
||||
}
|
||||
|
||||
}
|
||||
90
luaj-jse/src/test/java/org/luaj/jse/LuaPrototypeTest.java
Normal file
90
luaj-jse/src/test/java/org/luaj/jse/LuaPrototypeTest.java
Normal file
@@ -0,0 +1,90 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.jse;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaClosure;
|
||||
import org.luaj.vm2.LuaFunction;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.lib.ZeroArgFunction;
|
||||
import org.luaj.vm2.lib.jse.JsePlatform;
|
||||
|
||||
class LuaPrototypeTest {
|
||||
|
||||
private Prototype createPrototype(String script, String name) {
|
||||
try {
|
||||
Globals globals = JsePlatform.standardGlobals();
|
||||
Reader reader = new StringReader(script);
|
||||
return globals.compilePrototype(reader, name);
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
fail(e.toString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFunctionClosureThreadEnv() {
|
||||
|
||||
// set up suitable environments for execution
|
||||
LuaValue aaa = LuaValue.valueOf("aaa");
|
||||
LuaValue eee = LuaValue.valueOf("eee");
|
||||
final Globals globals = JsePlatform.standardGlobals();
|
||||
LuaTable newenv = LuaValue.tableOf(new LuaValue[] { LuaValue.valueOf("a"), LuaValue.valueOf("aaa"),
|
||||
LuaValue.valueOf("b"), LuaValue.valueOf("bbb"), });
|
||||
LuaTable mt = LuaValue.tableOf(new LuaValue[] { LuaValue.INDEX, globals });
|
||||
newenv.setmetatable(mt);
|
||||
globals.set("a", aaa);
|
||||
newenv.set("a", eee);
|
||||
|
||||
// function tests
|
||||
{
|
||||
LuaFunction f = new ZeroArgFunction() {
|
||||
@Override
|
||||
public LuaValue call() { return globals.get("a"); }
|
||||
};
|
||||
assertEquals(aaa, f.call());
|
||||
}
|
||||
|
||||
// closure tests
|
||||
{
|
||||
Prototype p = createPrototype("return a\n", "closuretester");
|
||||
LuaClosure c = new LuaClosure(p, globals);
|
||||
|
||||
// Test that a clusure with a custom enviroment uses that environment.
|
||||
assertEquals(aaa, c.call());
|
||||
c = new LuaClosure(p, newenv);
|
||||
assertEquals(newenv, c.upValues[0].getValue());
|
||||
assertEquals(eee, c.call());
|
||||
}
|
||||
}
|
||||
}
|
||||
186
luaj-jse/src/test/java/org/luaj/jse/OrphanedThreadTest.java
Normal file
186
luaj-jse/src/test/java/org/luaj/jse/OrphanedThreadTest.java
Normal file
@@ -0,0 +1,186 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.jse;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaThread;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.lib.OneArgFunction;
|
||||
import org.luaj.vm2.lib.jse.JsePlatform;
|
||||
|
||||
class OrphanedThreadTest {
|
||||
|
||||
Globals globals;
|
||||
|
||||
LuaThread luathread;
|
||||
LuaValue function;
|
||||
|
||||
WeakReference<LuaThread> luathr_ref;
|
||||
WeakReference<LuaValue> func_ref;
|
||||
|
||||
@BeforeEach
|
||||
protected void setUp() throws Exception {
|
||||
LuaThread.thread_orphan_check_interval = 5;
|
||||
globals = JsePlatform.standardGlobals();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
protected void tearDown() {
|
||||
LuaThread.thread_orphan_check_interval = 30000;
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCollectOrphanedNormalThread() throws Exception {
|
||||
function = new NormalFunction(globals);
|
||||
doTest(LuaValue.TRUE, LuaValue.ZERO);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCollectOrphanedEarlyCompletionThread() throws Exception {
|
||||
function = new EarlyCompletionFunction(globals);
|
||||
doTest(LuaValue.TRUE, LuaValue.ZERO);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCollectOrphanedAbnormalThread() throws Exception {
|
||||
function = new AbnormalFunction(globals);
|
||||
doTest(LuaValue.FALSE, LuaValue.valueOf("abnormal condition"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCollectOrphanedClosureThread() throws Exception {
|
||||
String script = "print('in closure, arg is '..(...))\n" + "arg = coroutine.yield(1)\n"
|
||||
+ "print('in closure.2, arg is '..arg)\n" + "arg = coroutine.yield(0)\n"
|
||||
+ "print('leakage in closure.3, arg is '..arg)\n" + "return 'done'\n";
|
||||
function = globals.load(script, "script");
|
||||
doTest(LuaValue.TRUE, LuaValue.ZERO);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCollectOrphanedPcallClosureThread() throws Exception {
|
||||
String script = "f = function(x)\n" + " print('in pcall-closure, arg is '..(x))\n"
|
||||
+ " arg = coroutine.yield(1)\n" + " print('in pcall-closure.2, arg is '..arg)\n"
|
||||
+ " arg = coroutine.yield(0)\n" + " print('leakage in pcall-closure.3, arg is '..arg)\n"
|
||||
+ " return 'done'\n" + "end\n" + "print( 'pcall-closre.result:', pcall( f, ... ) )\n";
|
||||
function = globals.load(script, "script");
|
||||
doTest(LuaValue.TRUE, LuaValue.ZERO);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCollectOrphanedLoadCloasureThread() throws Exception {
|
||||
String script = "t = { \"print \", \"'hello, \", \"world'\", }\n" + "i = 0\n" + "arg = ...\n"
|
||||
+ "f = function()\n" + " i = i + 1\n" + " print('in load-closure, arg is', arg, 'next is', t[i])\n"
|
||||
+ " arg = coroutine.yield(1)\n" + " return t[i]\n" + "end\n" + "load(f)()\n";
|
||||
function = globals.load(script, "script");
|
||||
doTest(LuaValue.TRUE, LuaValue.ONE);
|
||||
}
|
||||
|
||||
private void doTest(LuaValue status2, LuaValue value2) throws Exception {
|
||||
luathread = new LuaThread(globals, function);
|
||||
luathr_ref = new WeakReference<>(luathread);
|
||||
func_ref = new WeakReference<>(function);
|
||||
assertNotNull(luathr_ref.get());
|
||||
|
||||
// resume two times
|
||||
Varargs a = luathread.resume(LuaValue.valueOf("foo"));
|
||||
assertEquals(LuaValue.ONE, a.arg(2));
|
||||
assertEquals(LuaValue.TRUE, a.arg1());
|
||||
a = luathread.resume(LuaValue.valueOf("bar"));
|
||||
assertEquals(value2, a.arg(2));
|
||||
assertEquals(status2, a.arg1());
|
||||
|
||||
// drop strong references
|
||||
luathread = null;
|
||||
function = null;
|
||||
|
||||
// gc
|
||||
for (int i = 0; i < 100 && (luathr_ref.get() != null || func_ref.get() != null); i++) {
|
||||
Runtime.getRuntime().gc();
|
||||
Thread.sleep(5);
|
||||
}
|
||||
|
||||
// check reference
|
||||
assertNull(luathr_ref.get());
|
||||
assertNull(func_ref.get());
|
||||
}
|
||||
|
||||
static class NormalFunction extends OneArgFunction {
|
||||
final Globals globals;
|
||||
|
||||
public NormalFunction(Globals globals) {
|
||||
this.globals = globals;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuaValue call(LuaValue arg) {
|
||||
System.out.println("in normal.1, arg is " + arg);
|
||||
arg = globals.yield(ONE).arg1();
|
||||
System.out.println("in normal.2, arg is " + arg);
|
||||
arg = globals.yield(ZERO).arg1();
|
||||
System.out.println("in normal.3, arg is " + arg);
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static class EarlyCompletionFunction extends OneArgFunction {
|
||||
final Globals globals;
|
||||
|
||||
public EarlyCompletionFunction(Globals globals) {
|
||||
this.globals = globals;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuaValue call(LuaValue arg) {
|
||||
System.out.println("in early.1, arg is " + arg);
|
||||
arg = globals.yield(ONE).arg1();
|
||||
System.out.println("in early.2, arg is " + arg);
|
||||
return ZERO;
|
||||
}
|
||||
}
|
||||
|
||||
static class AbnormalFunction extends OneArgFunction {
|
||||
final Globals globals;
|
||||
|
||||
public AbnormalFunction(Globals globals) {
|
||||
this.globals = globals;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuaValue call(LuaValue arg) {
|
||||
System.out.println("in abnormal.1, arg is " + arg);
|
||||
arg = globals.yield(ONE).arg1();
|
||||
System.out.println("in abnormal.2, arg is " + arg);
|
||||
error("abnormal condition");
|
||||
return ZERO;
|
||||
}
|
||||
}
|
||||
}
|
||||
96
luaj-jse/src/test/java/org/luaj/jse/RequireClassTest.java
Normal file
96
luaj-jse/src/test/java/org/luaj/jse/RequireClassTest.java
Normal file
@@ -0,0 +1,96 @@
|
||||
package org.luaj.jse;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.luaj.jse.require.RequireSampleClassCastExcep;
|
||||
import org.luaj.jse.require.RequireSampleLoadLuaError;
|
||||
import org.luaj.jse.require.RequireSampleLoadRuntimeExcep;
|
||||
import org.luaj.jse.require.RequireSampleSuccess;
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.jse.JsePlatform;
|
||||
|
||||
class RequireClassTest {
|
||||
|
||||
private LuaTable globals;
|
||||
private LuaValue require;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
globals = JsePlatform.standardGlobals();
|
||||
require = globals.get("require");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoadClass() {
|
||||
LuaValue result = globals.load(new RequireSampleSuccess());
|
||||
assertEquals("require-sample-success-", result.tojstring());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRequireClassSuccess() {
|
||||
LuaValue result = require.call(LuaValue.valueOf(RequireSampleSuccess.class.getName()));
|
||||
assertEquals("require-sample-success-" + RequireSampleSuccess.class.getName(), result.tojstring());
|
||||
result = require.call(LuaValue.valueOf(RequireSampleSuccess.class.getName()));
|
||||
assertEquals("require-sample-success-" + RequireSampleSuccess.class.getName(), result.tojstring());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRequireClassLoadLuaError() {
|
||||
try {
|
||||
LuaValue result = require.call(LuaValue.valueOf(RequireSampleLoadLuaError.class.getName()));
|
||||
fail("incorrectly loaded class that threw lua error");
|
||||
} catch (LuaError le) {
|
||||
assertEquals("sample-load-lua-error", le.getMessage());
|
||||
}
|
||||
try {
|
||||
LuaValue result = require.call(LuaValue.valueOf(RequireSampleLoadLuaError.class.getName()));
|
||||
fail("incorrectly loaded class that threw lua error");
|
||||
} catch (LuaError le) {
|
||||
assertEquals("loop or previous error loading module '" + RequireSampleLoadLuaError.class.getName() + "'",
|
||||
le.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRequireClassLoadRuntimeException() {
|
||||
try {
|
||||
LuaValue result = require.call(LuaValue.valueOf(RequireSampleLoadRuntimeExcep.class.getName()));
|
||||
fail("incorrectly loaded class that threw runtime exception");
|
||||
} catch (RuntimeException le) {
|
||||
assertEquals("sample-load-runtime-exception", le.getMessage());
|
||||
}
|
||||
try {
|
||||
LuaValue result = require.call(LuaValue.valueOf(RequireSampleLoadRuntimeExcep.class.getName()));
|
||||
fail("incorrectly loaded class that threw runtime exception");
|
||||
} catch (LuaError le) {
|
||||
assertEquals(
|
||||
"loop or previous error loading module '" + RequireSampleLoadRuntimeExcep.class.getName() + "'",
|
||||
le.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRequireClassClassCastException() {
|
||||
try {
|
||||
LuaValue result = require.call(LuaValue.valueOf(RequireSampleClassCastExcep.class.getName()));
|
||||
fail("incorrectly loaded class that threw class cast exception");
|
||||
} catch (LuaError le) {
|
||||
String msg = le.getMessage();
|
||||
if (msg.indexOf("not found") < 0)
|
||||
fail("expected 'not found' message but got " + msg);
|
||||
}
|
||||
try {
|
||||
LuaValue result = require.call(LuaValue.valueOf(RequireSampleClassCastExcep.class.getName()));
|
||||
fail("incorrectly loaded class that threw class cast exception");
|
||||
} catch (LuaError le) {
|
||||
String msg = le.getMessage();
|
||||
if (msg.indexOf("not found") < 0)
|
||||
fail("expected 'not found' message but got " + msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
96
luaj-jse/src/test/java/org/luaj/jse/SimpleLuaCallsTest.java
Normal file
96
luaj-jse/src/test/java/org/luaj/jse/SimpleLuaCallsTest.java
Normal file
@@ -0,0 +1,96 @@
|
||||
package org.luaj.jse;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaDouble;
|
||||
import org.luaj.vm2.LuaInteger;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.jse.JsePlatform;
|
||||
|
||||
class SimpleLuaCallsTest {
|
||||
|
||||
private Globals globals;
|
||||
|
||||
@BeforeEach
|
||||
protected void setUp() throws Exception {
|
||||
globals = JsePlatform.standardGlobals();
|
||||
}
|
||||
|
||||
private void doTest(String script) {
|
||||
try {
|
||||
LuaValue c = globals.load(script, "script");
|
||||
c.call();
|
||||
} catch (Exception e) {
|
||||
fail("i/o exception: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTrivial() {
|
||||
String s = "print( 2 )\n";
|
||||
doTest(s);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAlmostTrivial() {
|
||||
String s = "print( 2 )\n" + "print( 3 )\n";
|
||||
doTest(s);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSimple() {
|
||||
String s = "print( 'hello, world' )\n" + "for i = 2,4 do\n" + " print( 'i', i )\n" + "end\n";
|
||||
doTest(s);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBreak() {
|
||||
String s = "a=1\n" + "while true do\n" + " if a>10 then\n" + " break\n" + " end\n" + " a=a+1\n"
|
||||
+ " print( a )\n" + "end\n";
|
||||
doTest(s);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testShebang() {
|
||||
String s = "#!../lua\n" + "print( 2 )\n";
|
||||
doTest(s);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInlineTable() {
|
||||
String s = "A = {g=10}\n" + "print( A )\n";
|
||||
doTest(s);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEqualsAnd() {
|
||||
String s = "print( 1 == b and b )\n";
|
||||
doTest(s);
|
||||
}
|
||||
|
||||
private static final int[] samehash = { 0, 1, -1, 2, -2, 4, 8, 16, 32, Integer.MAX_VALUE, Integer.MIN_VALUE };
|
||||
private static final double[] diffhash = { .5, 1, 1.5, 1, .5, 1.5, 1.25, 2.5 };
|
||||
|
||||
@Test
|
||||
void testDoubleHashCode() {
|
||||
for (int i = 0; i < samehash.length; i++) {
|
||||
LuaValue j = LuaInteger.valueOf(samehash[i]);
|
||||
LuaValue d = LuaDouble.valueOf(samehash[i]);
|
||||
int hj = j.hashCode();
|
||||
int hd = d.hashCode();
|
||||
assertEquals(hj, hd);
|
||||
}
|
||||
for (int i = 0; i < diffhash.length; i += 2) {
|
||||
LuaValue c = LuaValue.valueOf(diffhash[i+0]);
|
||||
LuaValue d = LuaValue.valueOf(diffhash[i+1]);
|
||||
int hc = c.hashCode();
|
||||
int hd = d.hashCode();
|
||||
assertTrue(hc != hd, "hash codes are same: " + hc);
|
||||
}
|
||||
}
|
||||
}
|
||||
47
luaj-jse/src/test/java/org/luaj/jse/StringMatchingTest.java
Normal file
47
luaj-jse/src/test/java/org/luaj/jse/StringMatchingTest.java
Normal file
@@ -0,0 +1,47 @@
|
||||
package org.luaj.jse;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.jse.JsePlatform;
|
||||
|
||||
class StringMatchingTest {
|
||||
|
||||
@BeforeEach
|
||||
protected void setUp() throws Exception {
|
||||
JsePlatform.standardGlobals();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMatchShortPatterns() {
|
||||
LuaValue[] args = { LuaString.valueOf("%bxy") };
|
||||
LuaString empty = LuaString.valueOf("");
|
||||
|
||||
LuaString a = LuaString.valueOf("a");
|
||||
LuaString ax = LuaString.valueOf("ax");
|
||||
LuaString axb = LuaString.valueOf("axb");
|
||||
LuaString axby = LuaString.valueOf("axby");
|
||||
LuaString xbya = LuaString.valueOf("xbya");
|
||||
LuaString bya = LuaString.valueOf("bya");
|
||||
LuaString xby = LuaString.valueOf("xby");
|
||||
LuaString axbya = LuaString.valueOf("axbya");
|
||||
LuaValue nil = LuaValue.NIL;
|
||||
|
||||
assertEquals(nil, empty.invokemethod("match", args));
|
||||
assertEquals(nil, a.invokemethod("match", args));
|
||||
assertEquals(nil, ax.invokemethod("match", args));
|
||||
assertEquals(nil, axb.invokemethod("match", args));
|
||||
assertEquals(xby, axby.invokemethod("match", args));
|
||||
assertEquals(xby, xbya.invokemethod("match", args));
|
||||
assertEquals(nil, bya.invokemethod("match", args));
|
||||
assertEquals(xby, xby.invokemethod("match", args));
|
||||
assertEquals(xby, axbya.invokemethod("match", args));
|
||||
assertEquals(xby, axbya.substring(0, 4).invokemethod("match", args));
|
||||
assertEquals(nil, axbya.substring(0, 3).invokemethod("match", args));
|
||||
assertEquals(xby, axbya.substring(1, 5).invokemethod("match", args));
|
||||
assertEquals(nil, axbya.substring(2, 5).invokemethod("match", args));
|
||||
}
|
||||
}
|
||||
43
luaj-jse/src/test/java/org/luaj/jse/UTF8StreamTest.java
Normal file
43
luaj-jse/src/test/java/org/luaj/jse/UTF8StreamTest.java
Normal file
@@ -0,0 +1,43 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.jse;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.jse.JsePlatform;
|
||||
|
||||
class UTF8StreamTest {
|
||||
|
||||
@Test
|
||||
void testUtf8CharsInStream() {
|
||||
String script = "x = \"98\u00b0: today's temp!\"\n" + "print('x = ', x)\n" + "return x";
|
||||
Globals globals = JsePlatform.standardGlobals();
|
||||
LuaValue chunk = globals.load(script);
|
||||
LuaValue result = chunk.call();
|
||||
String str = result.tojstring();
|
||||
assertEquals("98\u00b0: today's temp!", str);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package org.luaj.jse.require;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
/**
|
||||
* This should fail while trying to load via "require() because it is not a
|
||||
* LibFunction"
|
||||
*
|
||||
*/
|
||||
public class RequireSampleClassCastExcep {
|
||||
|
||||
public RequireSampleClassCastExcep() {
|
||||
}
|
||||
|
||||
public LuaValue call() {
|
||||
return LuaValue.valueOf("require-sample-class-cast-excep");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package org.luaj.jse.require;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.ZeroArgFunction;
|
||||
|
||||
/**
|
||||
* This should fail while trying to load via "require()" because it throws a
|
||||
* LuaError
|
||||
*
|
||||
*/
|
||||
public class RequireSampleLoadLuaError extends ZeroArgFunction {
|
||||
|
||||
public RequireSampleLoadLuaError() {
|
||||
}
|
||||
|
||||
public LuaValue call() {
|
||||
error("sample-load-lua-error");
|
||||
return LuaValue.valueOf("require-sample-load-lua-error");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.luaj.jse.require;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.ZeroArgFunction;
|
||||
|
||||
/**
|
||||
* This should fail while trying to load via "require()" because it throws a
|
||||
* RuntimeException
|
||||
*
|
||||
*/
|
||||
public class RequireSampleLoadRuntimeExcep extends ZeroArgFunction {
|
||||
|
||||
public RequireSampleLoadRuntimeExcep() {
|
||||
}
|
||||
|
||||
public LuaValue call() {
|
||||
throw new RuntimeException("sample-load-runtime-exception");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.luaj.jse.require;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.TwoArgFunction;
|
||||
|
||||
/**
|
||||
* This should succeed as a library that can be loaded dynamically via
|
||||
* "require()"
|
||||
*/
|
||||
public class RequireSampleSuccess extends TwoArgFunction {
|
||||
|
||||
public RequireSampleSuccess() {
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue modname, LuaValue env) {
|
||||
env.checkglobals();
|
||||
return LuaValue.valueOf("require-sample-success-" + modname.tojstring());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
class JsePlatformTest {
|
||||
@Test
|
||||
void testLuaMainPassesArguments() {
|
||||
Globals globals = JsePlatform.standardGlobals();
|
||||
LuaValue chunk = globals.load("return #arg, arg.n, arg[2], arg[1]");
|
||||
Varargs results = JsePlatform.luaMain(chunk, new String[] { "aaa", "bbb" });
|
||||
assertEquals(results.narg(), 4);
|
||||
assertEquals(results.arg(1), LuaValue.valueOf(2));
|
||||
assertEquals(results.arg(2), LuaValue.valueOf(2));
|
||||
assertEquals(results.arg(3), LuaValue.valueOf("bbb"));
|
||||
assertEquals(results.arg(4), LuaValue.valueOf("aaa"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,531 @@
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaInteger;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
class LuaJavaCoercionTest {
|
||||
|
||||
private static LuaValue globals;
|
||||
private static LuaValue ZERO = LuaValue.ZERO;
|
||||
private static LuaValue ONE = LuaValue.ONE;
|
||||
private static LuaValue TWO = LuaValue.valueOf(2);
|
||||
private static LuaValue THREE = LuaValue.valueOf(3);
|
||||
private static LuaString LENGTH = LuaString.valueOf("length");
|
||||
|
||||
@BeforeEach
|
||||
protected void setUp() throws Exception {
|
||||
globals = JsePlatform.standardGlobals();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testJavaIntToLuaInt() {
|
||||
Integer i = Integer.valueOf(777);
|
||||
LuaValue v = CoerceJavaToLua.coerce(i);
|
||||
assertEquals(LuaInteger.class, v.getClass());
|
||||
assertEquals(777, v.toint());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLuaIntToJavaInt() {
|
||||
LuaInteger i = LuaInteger.valueOf(777);
|
||||
Object o = CoerceLuaToJava.coerce(i, int.class);
|
||||
assertEquals(Integer.class, o.getClass());
|
||||
assertEquals(777, ((Number) o).intValue());
|
||||
o = CoerceLuaToJava.coerce(i, Integer.class);
|
||||
assertEquals(Integer.class, o.getClass());
|
||||
assertEquals(new Integer(777), o);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testJavaStringToLuaString() {
|
||||
String s = new String("777");
|
||||
LuaValue v = CoerceJavaToLua.coerce(s);
|
||||
assertEquals(LuaString.class, v.getClass());
|
||||
assertEquals("777", v.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLuaStringToJavaString() {
|
||||
LuaString s = LuaValue.valueOf("777");
|
||||
Object o = CoerceLuaToJava.coerce(s, String.class);
|
||||
assertEquals(String.class, o.getClass());
|
||||
assertEquals("777", o);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testJavaClassToLuaUserdata() {
|
||||
LuaValue va = CoerceJavaToLua.coerce(ClassA.class);
|
||||
LuaValue va1 = CoerceJavaToLua.coerce(ClassA.class);
|
||||
LuaValue vb = CoerceJavaToLua.coerce(ClassB.class);
|
||||
assertSame(va, va1);
|
||||
assertNotSame(va, vb);
|
||||
LuaValue vi = CoerceJavaToLua.coerce(new ClassA());
|
||||
assertNotSame(va, vi);
|
||||
assertTrue(vi.isuserdata());
|
||||
assertTrue(vi.isuserdata(ClassA.class));
|
||||
assertFalse(vi.isuserdata(ClassB.class));
|
||||
LuaValue vj = CoerceJavaToLua.coerce(new ClassB());
|
||||
assertNotSame(vb, vj);
|
||||
assertTrue(vj.isuserdata());
|
||||
assertFalse(vj.isuserdata(ClassA.class));
|
||||
assertTrue(vj.isuserdata(ClassB.class));
|
||||
}
|
||||
|
||||
static class ClassA {
|
||||
}
|
||||
|
||||
static class ClassB {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testJavaIntArrayToLuaTable() {
|
||||
int[] i = { 222, 333 };
|
||||
LuaValue v = CoerceJavaToLua.coerce(i);
|
||||
assertEquals(JavaArray.class, v.getClass());
|
||||
assertEquals(LuaInteger.valueOf(222), v.get(ONE));
|
||||
assertEquals(LuaInteger.valueOf(333), v.get(TWO));
|
||||
assertEquals(TWO, v.get(LENGTH));
|
||||
assertEquals(LuaValue.NIL, v.get(THREE));
|
||||
assertEquals(LuaValue.NIL, v.get(ZERO));
|
||||
v.set(ONE, LuaInteger.valueOf(444));
|
||||
v.set(TWO, LuaInteger.valueOf(555));
|
||||
assertEquals(444, i[0]);
|
||||
assertEquals(555, i[1]);
|
||||
assertEquals(LuaInteger.valueOf(444), v.get(ONE));
|
||||
assertEquals(LuaInteger.valueOf(555), v.get(TWO));
|
||||
try {
|
||||
v.set(ZERO, LuaInteger.valueOf(777));
|
||||
fail("array bound exception not thrown");
|
||||
} catch (LuaError lee) {
|
||||
// expected
|
||||
}
|
||||
try {
|
||||
v.set(THREE, LuaInteger.valueOf(777));
|
||||
fail("array bound exception not thrown");
|
||||
} catch (LuaError lee) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLuaTableToJavaIntArray() {
|
||||
LuaTable t = new LuaTable();
|
||||
t.set(1, LuaInteger.valueOf(222));
|
||||
t.set(2, LuaInteger.valueOf(333));
|
||||
int[] i = null;
|
||||
Object o = CoerceLuaToJava.coerce(t, int[].class);
|
||||
assertEquals(int[].class, o.getClass());
|
||||
i = (int[]) o;
|
||||
assertEquals(2, i.length);
|
||||
assertEquals(222, i[0]);
|
||||
assertEquals(333, i[1]);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIntArrayScoringTables() {
|
||||
int a = 5;
|
||||
LuaValue la = LuaInteger.valueOf(a);
|
||||
LuaTable tb = new LuaTable();
|
||||
tb.set(1, la);
|
||||
LuaTable tc = new LuaTable();
|
||||
tc.set(1, tb);
|
||||
|
||||
int saa = CoerceLuaToJava.getCoercion(int.class).score(la);
|
||||
int sab = CoerceLuaToJava.getCoercion(int[].class).score(la);
|
||||
int sac = CoerceLuaToJava.getCoercion(int[][].class).score(la);
|
||||
assertTrue(saa < sab);
|
||||
assertTrue(saa < sac);
|
||||
int sba = CoerceLuaToJava.getCoercion(int.class).score(tb);
|
||||
int sbb = CoerceLuaToJava.getCoercion(int[].class).score(tb);
|
||||
int sbc = CoerceLuaToJava.getCoercion(int[][].class).score(tb);
|
||||
assertTrue(sbb < sba);
|
||||
assertTrue(sbb < sbc);
|
||||
int sca = CoerceLuaToJava.getCoercion(int.class).score(tc);
|
||||
int scb = CoerceLuaToJava.getCoercion(int[].class).score(tc);
|
||||
int scc = CoerceLuaToJava.getCoercion(int[][].class).score(tc);
|
||||
assertTrue(scc < sca);
|
||||
assertTrue(scc < scb);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIntArrayScoringUserdata() {
|
||||
int a = 5;
|
||||
int[] b = { 44, 66 };
|
||||
int[][] c = { { 11, 22 }, { 33, 44 } };
|
||||
LuaValue va = CoerceJavaToLua.coerce(a);
|
||||
LuaValue vb = CoerceJavaToLua.coerce(b);
|
||||
LuaValue vc = CoerceJavaToLua.coerce(c);
|
||||
|
||||
int vaa = CoerceLuaToJava.getCoercion(int.class).score(va);
|
||||
int vab = CoerceLuaToJava.getCoercion(int[].class).score(va);
|
||||
int vac = CoerceLuaToJava.getCoercion(int[][].class).score(va);
|
||||
assertTrue(vaa < vab);
|
||||
assertTrue(vaa < vac);
|
||||
int vba = CoerceLuaToJava.getCoercion(int.class).score(vb);
|
||||
int vbb = CoerceLuaToJava.getCoercion(int[].class).score(vb);
|
||||
int vbc = CoerceLuaToJava.getCoercion(int[][].class).score(vb);
|
||||
assertTrue(vbb < vba);
|
||||
assertTrue(vbb < vbc);
|
||||
int vca = CoerceLuaToJava.getCoercion(int.class).score(vc);
|
||||
int vcb = CoerceLuaToJava.getCoercion(int[].class).score(vc);
|
||||
int vcc = CoerceLuaToJava.getCoercion(int[][].class).score(vc);
|
||||
assertTrue(vcc < vca);
|
||||
assertTrue(vcc < vcb);
|
||||
}
|
||||
|
||||
public static class SampleClass {
|
||||
public String sample() { return "void-args"; }
|
||||
|
||||
public String sample(int a) { return "int-args " + a; }
|
||||
|
||||
public String sample(int[] a) { return "int-array-args " + a[0] + "," + a[1]; }
|
||||
|
||||
public String sample(int[][] a) {
|
||||
return "int-array-array-args " + a[0][0] + "," + a[0][1] + "," + a[1][0] + "," + a[1][1];
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMatchVoidArgs() {
|
||||
LuaValue v = CoerceJavaToLua.coerce(new SampleClass());
|
||||
LuaValue result = v.method("sample");
|
||||
assertEquals("void-args", result.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMatchIntArgs() {
|
||||
LuaValue v = CoerceJavaToLua.coerce(new SampleClass());
|
||||
LuaValue arg = CoerceJavaToLua.coerce(new Integer(123));
|
||||
LuaValue result = v.method("sample", arg);
|
||||
assertEquals("int-args 123", result.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMatchIntArrayArgs() {
|
||||
LuaValue v = CoerceJavaToLua.coerce(new SampleClass());
|
||||
LuaValue arg = CoerceJavaToLua.coerce(new int[] { 345, 678 });
|
||||
LuaValue result = v.method("sample", arg);
|
||||
assertEquals("int-array-args 345,678", result.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMatchIntArrayArrayArgs() {
|
||||
LuaValue v = CoerceJavaToLua.coerce(new SampleClass());
|
||||
LuaValue arg = CoerceJavaToLua.coerce(new int[][] { { 22, 33 }, { 44, 55 } });
|
||||
LuaValue result = v.method("sample", arg);
|
||||
assertEquals("int-array-array-args 22,33,44,55", result.toString());
|
||||
}
|
||||
|
||||
public static final class SomeException extends RuntimeException {
|
||||
public SomeException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class SomeClass {
|
||||
public static void someMethod() {
|
||||
throw new SomeException("this is some message");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExceptionMessage() {
|
||||
String script = "local c = luajava.bindClass( \"" + SomeClass.class.getName() + "\" )\n"
|
||||
+ "return pcall( c.someMethod, c )";
|
||||
Varargs vresult = globals.get("load").call(LuaValue.valueOf(script)).invoke(LuaValue.NONE);
|
||||
LuaValue status = vresult.arg1();
|
||||
LuaValue message = vresult.arg(2);
|
||||
assertEquals(LuaValue.FALSE, status);
|
||||
int index = message.toString().indexOf("this is some message");
|
||||
assertTrue(index >= 0, "bad message: " + message);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLuaErrorCause() {
|
||||
String script = "luajava.bindClass( \"" + SomeClass.class.getName() + "\"):someMethod()";
|
||||
LuaValue chunk = globals.get("load").call(LuaValue.valueOf(script));
|
||||
try {
|
||||
chunk.invoke(LuaValue.NONE);
|
||||
fail("call should not have succeeded");
|
||||
} catch (LuaError lee) {
|
||||
Throwable c = lee.getCause();
|
||||
assertEquals(SomeException.class, c.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
public interface VarArgsInterface {
|
||||
public String varargsMethod(String a, String... v);
|
||||
|
||||
public String arrayargsMethod(String a, String[] v);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testVarArgsProxy() {
|
||||
String script = "return luajava.createProxy( \"" + VarArgsInterface.class.getName() + "\", \n" + "{\n"
|
||||
+ " varargsMethod = function(a,...)\n" + " return table.concat({a,...},'-')\n" + " end,\n"
|
||||
+ " arrayargsMethod = function(a,array)\n" + " return tostring(a)..(array and \n"
|
||||
+ " ('-'..tostring(array.length)\n" + " ..'-'..tostring(array[1])\n"
|
||||
+ " ..'-'..tostring(array[2])\n" + " ) or '-nil')\n" + " end,\n" + "} )\n";
|
||||
Varargs chunk = globals.get("load").call(LuaValue.valueOf(script));
|
||||
if (!chunk.arg1().toboolean())
|
||||
fail(chunk.arg(2).toString());
|
||||
LuaValue result = chunk.arg1().call();
|
||||
Object u = result.touserdata();
|
||||
VarArgsInterface v = (VarArgsInterface) u;
|
||||
assertEquals("foo", v.varargsMethod("foo"));
|
||||
assertEquals("foo-bar", v.varargsMethod("foo", "bar"));
|
||||
assertEquals("foo-bar-etc", v.varargsMethod("foo", "bar", "etc"));
|
||||
assertEquals("foo-0-nil-nil", v.arrayargsMethod("foo", new String[0]));
|
||||
assertEquals("foo-1-bar-nil", v.arrayargsMethod("foo", new String[] { "bar" }));
|
||||
assertEquals("foo-2-bar-etc", v.arrayargsMethod("foo", new String[] { "bar", "etc" }));
|
||||
assertEquals("foo-3-bar-etc", v.arrayargsMethod("foo", new String[] { "bar", "etc", "etc" }));
|
||||
assertEquals("foo-nil", v.arrayargsMethod("foo", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBigNum() {
|
||||
String script = "bigNumA = luajava.newInstance('java.math.BigDecimal','12345678901234567890');\n"
|
||||
+ "bigNumB = luajava.newInstance('java.math.BigDecimal','12345678901234567890');\n"
|
||||
+ "bigNumC = bigNumA:multiply(bigNumB);\n" +
|
||||
//"print(bigNumA:toString())\n" +
|
||||
//"print(bigNumB:toString())\n" +
|
||||
//"print(bigNumC:toString())\n" +
|
||||
"return bigNumA:toString(), bigNumB:toString(), bigNumC:toString()";
|
||||
Varargs chunk = globals.get("load").call(LuaValue.valueOf(script));
|
||||
if (!chunk.arg1().toboolean())
|
||||
fail(chunk.arg(2).toString());
|
||||
Varargs results = chunk.arg1().invoke();
|
||||
int nresults = results.narg();
|
||||
String sa = results.tojstring(1);
|
||||
String sb = results.tojstring(2);
|
||||
String sc = results.tojstring(3);
|
||||
assertEquals(3, nresults);
|
||||
assertEquals("12345678901234567890", sa);
|
||||
assertEquals("12345678901234567890", sb);
|
||||
assertEquals("152415787532388367501905199875019052100", sc);
|
||||
}
|
||||
|
||||
public interface IA {
|
||||
}
|
||||
|
||||
public interface IB extends IA {
|
||||
}
|
||||
|
||||
public interface IC extends IB {
|
||||
}
|
||||
|
||||
public static class A implements IA {
|
||||
}
|
||||
|
||||
public static class B extends A implements IB {
|
||||
public String set(Object x) { return "set(Object) "; }
|
||||
|
||||
public String set(String x) { return "set(String) " + x; }
|
||||
|
||||
public String set(A x) { return "set(A) "; }
|
||||
|
||||
public String set(B x) { return "set(B) "; }
|
||||
|
||||
public String set(C x) { return "set(C) "; }
|
||||
|
||||
public String set(byte x) { return "set(byte) " + x; }
|
||||
|
||||
public String set(char x) { return "set(char) " + (int) x; }
|
||||
|
||||
public String set(short x) { return "set(short) " + x; }
|
||||
|
||||
public String set(int x) { return "set(int) " + x; }
|
||||
|
||||
public String set(long x) { return "set(long) " + x; }
|
||||
|
||||
public String set(float x) { return "set(float) " + x; }
|
||||
|
||||
public String set(double x) { return "set(double) " + x; }
|
||||
|
||||
public String setr(double x) { return "setr(double) " + x; }
|
||||
|
||||
public String setr(float x) { return "setr(float) " + x; }
|
||||
|
||||
public String setr(long x) { return "setr(long) " + x; }
|
||||
|
||||
public String setr(int x) { return "setr(int) " + x; }
|
||||
|
||||
public String setr(short x) { return "setr(short) " + x; }
|
||||
|
||||
public String setr(char x) { return "setr(char) " + (int) x; }
|
||||
|
||||
public String setr(byte x) { return "setr(byte) " + x; }
|
||||
|
||||
public String setr(C x) { return "setr(C) "; }
|
||||
|
||||
public String setr(B x) { return "setr(B) "; }
|
||||
|
||||
public String setr(A x) { return "setr(A) "; }
|
||||
|
||||
public String setr(String x) { return "setr(String) " + x; }
|
||||
|
||||
public String setr(Object x) { return "setr(Object) "; }
|
||||
|
||||
public Object getObject() { return new Object(); }
|
||||
|
||||
public String getString() { return "abc"; }
|
||||
|
||||
public byte[] getbytearray() { return new byte[] { 1, 2, 3 }; }
|
||||
|
||||
public A getA() { return new A(); }
|
||||
|
||||
public B getB() { return new B(); }
|
||||
|
||||
public C getC() { return new C(); }
|
||||
|
||||
public byte getbyte() { return 1; }
|
||||
|
||||
public char getchar() { return 65000; }
|
||||
|
||||
public short getshort() { return -32000; }
|
||||
|
||||
public int getint() { return 100000; }
|
||||
|
||||
public long getlong() { return 50000000000L; }
|
||||
|
||||
public float getfloat() { return 6.5f; }
|
||||
|
||||
public double getdouble() { return Math.PI; }
|
||||
}
|
||||
|
||||
public static class C extends B implements IC {
|
||||
}
|
||||
|
||||
public static class D extends C implements IA {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testOverloadedJavaMethodObject() { doOverloadedMethodTest("Object", ""); }
|
||||
|
||||
@Test
|
||||
void testOverloadedJavaMethodString() { doOverloadedMethodTest("String", "abc"); }
|
||||
|
||||
@Test
|
||||
void testOverloadedJavaMethodA() { doOverloadedMethodTest("A", ""); }
|
||||
|
||||
@Test
|
||||
void testOverloadedJavaMethodB() { doOverloadedMethodTest("B", ""); }
|
||||
|
||||
@Test
|
||||
void testOverloadedJavaMethodC() { doOverloadedMethodTest("C", ""); }
|
||||
|
||||
@Test
|
||||
void testOverloadedJavaMethodByte() { doOverloadedMethodTest("byte", "1"); }
|
||||
|
||||
@Test
|
||||
void testOverloadedJavaMethodChar() { doOverloadedMethodTest("char", "65000"); }
|
||||
|
||||
@Test
|
||||
void testOverloadedJavaMethodShort() { doOverloadedMethodTest("short", "-32000"); }
|
||||
|
||||
@Test
|
||||
void testOverloadedJavaMethodInt() { doOverloadedMethodTest("int", "100000"); }
|
||||
|
||||
@Test
|
||||
void testOverloadedJavaMethodLong() { doOverloadedMethodTest("long", "50000000000"); }
|
||||
|
||||
@Test
|
||||
void testOverloadedJavaMethodFloat() { doOverloadedMethodTest("float", "6.5"); }
|
||||
|
||||
@Test
|
||||
void testOverloadedJavaMethodDouble() { doOverloadedMethodTest("double", "3.141592653589793"); }
|
||||
|
||||
private void doOverloadedMethodTest(String typename, String value) {
|
||||
String script = "local a = luajava.newInstance('" + B.class.getName() + "');\n" + "local b = a:set(a:get"
|
||||
+ typename + "())\n" + "local c = a:setr(a:get" + typename + "())\n" + "return b,c";
|
||||
Varargs chunk = globals.get("load").call(LuaValue.valueOf(script));
|
||||
if (!chunk.arg1().toboolean())
|
||||
fail(chunk.arg(2).toString());
|
||||
Varargs results = chunk.arg1().invoke();
|
||||
int nresults = results.narg();
|
||||
assertEquals(2, nresults);
|
||||
LuaValue b = results.arg(1);
|
||||
LuaValue c = results.arg(2);
|
||||
String sb = b.tojstring();
|
||||
String sc = c.tojstring();
|
||||
assertEquals("set(" + typename + ") " + value, sb);
|
||||
assertEquals("setr(" + typename + ") " + value, sc);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testClassInheritanceLevels() {
|
||||
assertEquals(0, CoerceLuaToJava.inheritanceLevels(Object.class, Object.class));
|
||||
assertEquals(1, CoerceLuaToJava.inheritanceLevels(Object.class, String.class));
|
||||
assertEquals(1, CoerceLuaToJava.inheritanceLevels(Object.class, A.class));
|
||||
assertEquals(2, CoerceLuaToJava.inheritanceLevels(Object.class, B.class));
|
||||
assertEquals(3, CoerceLuaToJava.inheritanceLevels(Object.class, C.class));
|
||||
|
||||
assertEquals(CoerceLuaToJava.SCORE_UNCOERCIBLE, CoerceLuaToJava.inheritanceLevels(A.class, Object.class));
|
||||
assertEquals(CoerceLuaToJava.SCORE_UNCOERCIBLE, CoerceLuaToJava.inheritanceLevels(A.class, String.class));
|
||||
assertEquals(0, CoerceLuaToJava.inheritanceLevels(A.class, A.class));
|
||||
assertEquals(1, CoerceLuaToJava.inheritanceLevels(A.class, B.class));
|
||||
assertEquals(2, CoerceLuaToJava.inheritanceLevels(A.class, C.class));
|
||||
|
||||
assertEquals(CoerceLuaToJava.SCORE_UNCOERCIBLE, CoerceLuaToJava.inheritanceLevels(B.class, Object.class));
|
||||
assertEquals(CoerceLuaToJava.SCORE_UNCOERCIBLE, CoerceLuaToJava.inheritanceLevels(B.class, String.class));
|
||||
assertEquals(CoerceLuaToJava.SCORE_UNCOERCIBLE, CoerceLuaToJava.inheritanceLevels(B.class, A.class));
|
||||
assertEquals(0, CoerceLuaToJava.inheritanceLevels(B.class, B.class));
|
||||
assertEquals(1, CoerceLuaToJava.inheritanceLevels(B.class, C.class));
|
||||
|
||||
assertEquals(CoerceLuaToJava.SCORE_UNCOERCIBLE, CoerceLuaToJava.inheritanceLevels(C.class, Object.class));
|
||||
assertEquals(CoerceLuaToJava.SCORE_UNCOERCIBLE, CoerceLuaToJava.inheritanceLevels(C.class, String.class));
|
||||
assertEquals(CoerceLuaToJava.SCORE_UNCOERCIBLE, CoerceLuaToJava.inheritanceLevels(C.class, A.class));
|
||||
assertEquals(CoerceLuaToJava.SCORE_UNCOERCIBLE, CoerceLuaToJava.inheritanceLevels(C.class, B.class));
|
||||
assertEquals(0, CoerceLuaToJava.inheritanceLevels(C.class, C.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInterfaceInheritanceLevels() {
|
||||
assertEquals(1, CoerceLuaToJava.inheritanceLevels(IA.class, A.class));
|
||||
assertEquals(1, CoerceLuaToJava.inheritanceLevels(IB.class, B.class));
|
||||
assertEquals(2, CoerceLuaToJava.inheritanceLevels(IA.class, B.class));
|
||||
assertEquals(1, CoerceLuaToJava.inheritanceLevels(IC.class, C.class));
|
||||
assertEquals(2, CoerceLuaToJava.inheritanceLevels(IB.class, C.class));
|
||||
assertEquals(3, CoerceLuaToJava.inheritanceLevels(IA.class, C.class));
|
||||
assertEquals(1, CoerceLuaToJava.inheritanceLevels(IA.class, D.class));
|
||||
assertEquals(2, CoerceLuaToJava.inheritanceLevels(IC.class, D.class));
|
||||
assertEquals(3, CoerceLuaToJava.inheritanceLevels(IB.class, D.class));
|
||||
|
||||
assertEquals(CoerceLuaToJava.SCORE_UNCOERCIBLE, CoerceLuaToJava.inheritanceLevels(IB.class, A.class));
|
||||
assertEquals(CoerceLuaToJava.SCORE_UNCOERCIBLE, CoerceLuaToJava.inheritanceLevels(IC.class, A.class));
|
||||
assertEquals(CoerceLuaToJava.SCORE_UNCOERCIBLE, CoerceLuaToJava.inheritanceLevels(IC.class, B.class));
|
||||
assertEquals(CoerceLuaToJava.SCORE_UNCOERCIBLE, CoerceLuaToJava.inheritanceLevels(IB.class, IA.class));
|
||||
assertEquals(1, CoerceLuaToJava.inheritanceLevels(IA.class, IB.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCoerceJavaToLuaLuaValue() {
|
||||
assertSame(LuaValue.NIL, CoerceJavaToLua.coerce(LuaValue.NIL));
|
||||
assertSame(LuaValue.ZERO, CoerceJavaToLua.coerce(LuaValue.ZERO));
|
||||
assertSame(LuaValue.ONE, CoerceJavaToLua.coerce(LuaValue.ONE));
|
||||
assertSame(LuaValue.INDEX, CoerceJavaToLua.coerce(LuaValue.INDEX));
|
||||
LuaTable table = LuaValue.tableOf();
|
||||
assertSame(table, CoerceJavaToLua.coerce(table));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCoerceJavaToLuaByeArray() {
|
||||
byte[] bytes = "abcd".getBytes();
|
||||
LuaValue value = CoerceJavaToLua.coerce(bytes);
|
||||
assertEquals(LuaString.class, value.getClass());
|
||||
assertEquals(LuaValue.valueOf("abcd"), value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
class LuajavaAccessibleMembersTest {
|
||||
|
||||
private Globals globals;
|
||||
|
||||
@BeforeEach
|
||||
protected void setUp() throws Exception {
|
||||
globals = JsePlatform.standardGlobals();
|
||||
}
|
||||
|
||||
private String invokeScript(String script) {
|
||||
try {
|
||||
LuaValue c = globals.load(script, "script");
|
||||
return c.call().tojstring();
|
||||
} catch (Exception e) {
|
||||
fail("exception: " + e);
|
||||
return "failed";
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAccessFromPrivateClassImplementedMethod() {
|
||||
assertEquals("privateImpl-aaa-interface_method(bar)",
|
||||
invokeScript("b = luajava.newInstance('" + TestClass.class.getName() + "');"
|
||||
+ "a = b:create_PrivateImpl('aaa');" + "return a:interface_method('bar');"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAccessFromPrivateClassPublicMethod() {
|
||||
assertEquals("privateImpl-aaa-public_method", invokeScript("b = luajava.newInstance('"
|
||||
+ TestClass.class.getName() + "');" + "a = b:create_PrivateImpl('aaa');" + "return a:public_method();"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAccessFromPrivateClassGetPublicField() {
|
||||
assertEquals("aaa", invokeScript("b = luajava.newInstance('" + TestClass.class.getName() + "');"
|
||||
+ "a = b:create_PrivateImpl('aaa');" + "return a.public_field;"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAccessFromPrivateClassSetPublicField() {
|
||||
assertEquals("foo", invokeScript("b = luajava.newInstance('" + TestClass.class.getName() + "');"
|
||||
+ "a = b:create_PrivateImpl('aaa');" + "a.public_field = 'foo';" + "return a.public_field;"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAccessFromPrivateClassPublicConstructor() {
|
||||
assertEquals("privateImpl-constructor", invokeScript("b = luajava.newInstance('" + TestClass.class.getName()
|
||||
+ "');" + "c = b:get_PrivateImplClass();" + "return luajava.new(c);"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAccessPublicEnum() {
|
||||
assertEquals("class org.luaj.vm2.lib.jse.TestClass$SomeEnum",
|
||||
invokeScript("b = luajava.newInstance('" + TestClass.class.getName() + "');" + "return b.SomeEnum"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,318 @@
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
class LuajavaClassMembersTest {
|
||||
public static class A {
|
||||
protected A() {}
|
||||
}
|
||||
|
||||
public static class B extends A {
|
||||
public byte m_byte_field;
|
||||
public int m_int_field;
|
||||
public double m_double_field;
|
||||
public String m_string_field;
|
||||
|
||||
protected B() {}
|
||||
|
||||
public B(int i) { m_int_field = i; }
|
||||
|
||||
public String setString(String x) { return "setString(String) " + x; }
|
||||
|
||||
public String getString() { return "abc"; }
|
||||
|
||||
public int getint() { return 100000; }
|
||||
|
||||
public String uniq() { return "uniq()"; }
|
||||
|
||||
public String uniqs(String s) { return "uniqs(string:" + s + ")"; }
|
||||
|
||||
public String uniqi(int i) { return "uniqi(int:" + i + ")"; }
|
||||
|
||||
public String uniqsi(String s, int i) { return "uniqsi(string:" + s + ",int:" + i + ")"; }
|
||||
|
||||
public String uniqis(int i, String s) { return "uniqis(int:" + i + ",string:" + s + ")"; }
|
||||
|
||||
public String pick() { return "pick()"; }
|
||||
|
||||
public String pick(String s) { return "pick(string:" + s + ")"; }
|
||||
|
||||
public String pick(int i) { return "pick(int:" + i + ")"; }
|
||||
|
||||
public String pick(String s, int i) { return "pick(string:" + s + ",int:" + i + ")"; }
|
||||
|
||||
public String pick(int i, String s) { return "pick(int:" + i + ",string:" + s + ")"; }
|
||||
|
||||
public static String staticpick() { return "static-pick()"; }
|
||||
|
||||
public static String staticpick(String s) { return "static-pick(string:" + s + ")"; }
|
||||
|
||||
public static String staticpick(int i) { return "static-pick(int:" + i + ")"; }
|
||||
|
||||
public static String staticpick(String s, int i) { return "static-pick(string:" + s + ",int:" + i + ")"; }
|
||||
|
||||
public static String staticpick(int i, String s) { return "static-pick(int:" + i + ",string:" + s + ")"; }
|
||||
}
|
||||
|
||||
public static class C extends B {
|
||||
public C() {}
|
||||
|
||||
public C(String s) { m_string_field = s; }
|
||||
|
||||
public C(int i) { m_int_field = i; }
|
||||
|
||||
public C(String s, int i) { m_string_field = s; m_int_field = i; }
|
||||
|
||||
@Override
|
||||
public int getint() { return 200000; }
|
||||
|
||||
@Override
|
||||
public String pick(String s) { return "class-c-pick(string:" + s + ")"; }
|
||||
|
||||
@Override
|
||||
public String pick(int i) { return "class-c-pick(int:" + i + ")"; }
|
||||
|
||||
public static class D {
|
||||
public static String name() { return "name-of-D"; }
|
||||
}
|
||||
}
|
||||
|
||||
static LuaValue ZERO = LuaValue.ZERO;
|
||||
static LuaValue ONE = LuaValue.ONE;
|
||||
static LuaValue PI = LuaValue.valueOf(Math.PI);
|
||||
static LuaValue THREE = LuaValue.valueOf(3);
|
||||
static LuaValue NUMS = LuaValue.valueOf(123);
|
||||
static LuaValue ABC = LuaValue.valueOf("abc");
|
||||
static LuaValue SOMEA = CoerceJavaToLua.coerce(new A());
|
||||
static LuaValue SOMEB = CoerceJavaToLua.coerce(new B());
|
||||
static LuaValue SOMEC = CoerceJavaToLua.coerce(new C());
|
||||
|
||||
@Test
|
||||
void testSetByteField() {
|
||||
B b = new B();
|
||||
JavaInstance i = new JavaInstance(b);
|
||||
i.set("m_byte_field", ONE);
|
||||
assertEquals(1, b.m_byte_field);
|
||||
assertEquals(ONE, i.get("m_byte_field"));
|
||||
i.set("m_byte_field", PI);
|
||||
assertEquals(3, b.m_byte_field);
|
||||
assertEquals(THREE, i.get("m_byte_field"));
|
||||
i.set("m_byte_field", ABC);
|
||||
assertEquals(0, b.m_byte_field);
|
||||
assertEquals(ZERO, i.get("m_byte_field"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSetDoubleField() {
|
||||
B b = new B();
|
||||
JavaInstance i = new JavaInstance(b);
|
||||
i.set("m_double_field", ONE);
|
||||
assertEquals(1., b.m_double_field);
|
||||
assertEquals(ONE, i.get("m_double_field"));
|
||||
i.set("m_double_field", PI);
|
||||
assertEquals(Math.PI, b.m_double_field);
|
||||
assertEquals(PI, i.get("m_double_field"));
|
||||
i.set("m_double_field", ABC);
|
||||
assertEquals(0., b.m_double_field);
|
||||
assertEquals(ZERO, i.get("m_double_field"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNoFactory() {
|
||||
JavaClass c = JavaClass.forClass(A.class);
|
||||
try {
|
||||
c.call();
|
||||
fail("did not throw lua error as expected");
|
||||
} catch (LuaError e) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUniqueFactoryCoercible() {
|
||||
JavaClass c = JavaClass.forClass(B.class);
|
||||
assertEquals(JavaClass.class, c.getClass());
|
||||
LuaValue constr = c.get("new");
|
||||
assertEquals(JavaConstructor.class, constr.getClass());
|
||||
LuaValue v = constr.call(NUMS);
|
||||
Object b = v.touserdata();
|
||||
assertEquals(B.class, b.getClass());
|
||||
assertEquals(123, ((B) b).m_int_field);
|
||||
Object b0 = constr.call().touserdata();
|
||||
assertEquals(B.class, b0.getClass());
|
||||
assertEquals(0, ((B) b0).m_int_field);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUniqueFactoryUncoercible() {
|
||||
JavaClass f = JavaClass.forClass(B.class);
|
||||
LuaValue constr = f.get("new");
|
||||
assertEquals(JavaConstructor.class, constr.getClass());
|
||||
try {
|
||||
LuaValue v = constr.call(LuaValue.userdataOf(new Object()));
|
||||
Object b = v.touserdata();
|
||||
// fail( "did not throw lua error as expected" );
|
||||
assertEquals(0, ((B) b).m_int_field);
|
||||
} catch (LuaError e) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testOverloadedFactoryCoercible() {
|
||||
JavaClass f = JavaClass.forClass(C.class);
|
||||
LuaValue constr = f.get("new");
|
||||
assertEquals(JavaConstructor.Overload.class, constr.getClass());
|
||||
Object c = constr.call().touserdata();
|
||||
Object ci = constr.call(LuaValue.valueOf(123)).touserdata();
|
||||
Object cs = constr.call(LuaValue.valueOf("abc")).touserdata();
|
||||
Object csi = constr.call(LuaValue.valueOf("def"), LuaValue.valueOf(456)).touserdata();
|
||||
assertEquals(C.class, c.getClass());
|
||||
assertEquals(C.class, ci.getClass());
|
||||
assertEquals(C.class, cs.getClass());
|
||||
assertEquals(C.class, csi.getClass());
|
||||
assertEquals(null, ((C) c).m_string_field);
|
||||
assertEquals(0, ((C) c).m_int_field);
|
||||
assertEquals("abc", ((C) cs).m_string_field);
|
||||
assertEquals(0, ((C) cs).m_int_field);
|
||||
assertEquals(null, ((C) ci).m_string_field);
|
||||
assertEquals(123, ((C) ci).m_int_field);
|
||||
assertEquals("def", ((C) csi).m_string_field);
|
||||
assertEquals(456, ((C) csi).m_int_field);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testOverloadedFactoryUncoercible() {
|
||||
JavaClass f = JavaClass.forClass(C.class);
|
||||
try {
|
||||
Object c = f.call(LuaValue.userdataOf(new Object()));
|
||||
// fail( "did not throw lua error as expected" );
|
||||
assertEquals(0, ((C) c).m_int_field);
|
||||
assertEquals(null, ((C) c).m_string_field);
|
||||
} catch (LuaError e) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNoAttribute() {
|
||||
JavaClass f = JavaClass.forClass(A.class);
|
||||
LuaValue v = f.get("bogus");
|
||||
assertEquals(v, LuaValue.NIL);
|
||||
try {
|
||||
f.set("bogus", ONE);
|
||||
fail("did not throw lua error as expected");
|
||||
} catch (LuaError e) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFieldAttributeCoercible() {
|
||||
JavaInstance i = new JavaInstance(new B());
|
||||
i.set("m_int_field", ONE);
|
||||
assertEquals(1, i.get("m_int_field").toint());
|
||||
i.set("m_int_field", THREE);
|
||||
assertEquals(3, i.get("m_int_field").toint());
|
||||
i = new JavaInstance(new C());
|
||||
i.set("m_int_field", ONE);
|
||||
assertEquals(1, i.get("m_int_field").toint());
|
||||
i.set("m_int_field", THREE);
|
||||
assertEquals(3, i.get("m_int_field").toint());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUniqueMethodAttributeCoercible() {
|
||||
B b = new B();
|
||||
JavaInstance ib = new JavaInstance(b);
|
||||
LuaValue b_getString = ib.get("getString");
|
||||
LuaValue b_getint = ib.get("getint");
|
||||
assertEquals(JavaMethod.class, b_getString.getClass());
|
||||
assertEquals(JavaMethod.class, b_getint.getClass());
|
||||
assertEquals("abc", b_getString.call(SOMEB).tojstring());
|
||||
assertEquals(100000, b_getint.call(SOMEB).toint());
|
||||
assertEquals("abc", b_getString.call(SOMEC).tojstring());
|
||||
assertEquals(200000, b_getint.call(SOMEC).toint());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUniqueMethodAttributeArgsCoercible() {
|
||||
B b = new B();
|
||||
JavaInstance ib = new JavaInstance(b);
|
||||
LuaValue uniq = ib.get("uniq");
|
||||
LuaValue uniqs = ib.get("uniqs");
|
||||
LuaValue uniqi = ib.get("uniqi");
|
||||
LuaValue uniqsi = ib.get("uniqsi");
|
||||
LuaValue uniqis = ib.get("uniqis");
|
||||
assertEquals(JavaMethod.class, uniq.getClass());
|
||||
assertEquals(JavaMethod.class, uniqs.getClass());
|
||||
assertEquals(JavaMethod.class, uniqi.getClass());
|
||||
assertEquals(JavaMethod.class, uniqsi.getClass());
|
||||
assertEquals(JavaMethod.class, uniqis.getClass());
|
||||
assertEquals("uniq()", uniq.call(SOMEB).tojstring());
|
||||
assertEquals("uniqs(string:abc)", uniqs.call(SOMEB, ABC).tojstring());
|
||||
assertEquals("uniqi(int:1)", uniqi.call(SOMEB, ONE).tojstring());
|
||||
assertEquals("uniqsi(string:abc,int:1)", uniqsi.call(SOMEB, ABC, ONE).tojstring());
|
||||
assertEquals("uniqis(int:1,string:abc)", uniqis.call(SOMEB, ONE, ABC).tojstring());
|
||||
assertEquals("uniqis(int:1,string:abc)",
|
||||
uniqis.invoke(LuaValue.varargsOf(new LuaValue[] { SOMEB, ONE, ABC, ONE })).arg1().tojstring());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testOverloadedMethodAttributeCoercible() {
|
||||
B b = new B();
|
||||
JavaInstance ib = new JavaInstance(b);
|
||||
LuaValue p = ib.get("pick");
|
||||
assertEquals("pick()", p.call(SOMEB).tojstring());
|
||||
assertEquals("pick(string:abc)", p.call(SOMEB, ABC).tojstring());
|
||||
assertEquals("pick(int:1)", p.call(SOMEB, ONE).tojstring());
|
||||
assertEquals("pick(string:abc,int:1)", p.call(SOMEB, ABC, ONE).tojstring());
|
||||
assertEquals("pick(int:1,string:abc)", p.call(SOMEB, ONE, ABC).tojstring());
|
||||
assertEquals("pick(int:1,string:abc)",
|
||||
p.invoke(LuaValue.varargsOf(new LuaValue[] { SOMEB, ONE, ABC, ONE })).arg1().tojstring());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUnboundOverloadedMethodAttributeCoercible() {
|
||||
B b = new B();
|
||||
JavaInstance ib = new JavaInstance(b);
|
||||
LuaValue p = ib.get("pick");
|
||||
assertEquals(JavaMethod.Overload.class, p.getClass());
|
||||
assertEquals("pick()", p.call(SOMEC).tojstring());
|
||||
assertEquals("class-c-pick(string:abc)", p.call(SOMEC, ABC).tojstring());
|
||||
assertEquals("class-c-pick(int:1)", p.call(SOMEC, ONE).tojstring());
|
||||
assertEquals("pick(string:abc,int:1)", p.call(SOMEC, ABC, ONE).tojstring());
|
||||
assertEquals("pick(int:1,string:abc)", p.call(SOMEC, ONE, ABC).tojstring());
|
||||
assertEquals("pick(int:1,string:abc)",
|
||||
p.invoke(LuaValue.varargsOf(new LuaValue[] { SOMEC, ONE, ABC, ONE })).arg1().tojstring());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testOverloadedStaticMethodAttributeCoercible() {
|
||||
B b = new B();
|
||||
JavaInstance ib = new JavaInstance(b);
|
||||
LuaValue p = ib.get("staticpick");
|
||||
assertEquals("static-pick()", p.call(SOMEB).tojstring());
|
||||
assertEquals("static-pick(string:abc)", p.call(SOMEB, ABC).tojstring());
|
||||
assertEquals("static-pick(int:1)", p.call(SOMEB, ONE).tojstring());
|
||||
assertEquals("static-pick(string:abc,int:1)", p.call(SOMEB, ABC, ONE).tojstring());
|
||||
assertEquals("static-pick(int:1,string:abc)", p.call(SOMEB, ONE, ABC).tojstring());
|
||||
assertEquals("static-pick(int:1,string:abc)",
|
||||
p.invoke(LuaValue.varargsOf(new LuaValue[] { SOMEB, ONE, ABC, ONE })).arg1().tojstring());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetInnerClass() {
|
||||
C c = new C();
|
||||
JavaInstance ic = new JavaInstance(c);
|
||||
LuaValue d = ic.get("D");
|
||||
assertFalse(d.isnil());
|
||||
assertSame(d, JavaClass.forClass(C.D.class));
|
||||
LuaValue e = ic.get("E");
|
||||
assertTrue(e.isnil());
|
||||
}
|
||||
}
|
||||
138
luaj-jse/src/test/java/org/luaj/vm2/lib/jse/OsLibTest.java
Normal file
138
luaj-jse/src/test/java/org/luaj/vm2/lib/jse/OsLibTest.java
Normal file
@@ -0,0 +1,138 @@
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
class OsLibTest {
|
||||
|
||||
LuaValue jse_lib;
|
||||
double time;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
jse_lib = JsePlatform.standardGlobals().get("os");
|
||||
time = new Date(2001-1900, 7, 23, 14, 55, 02).getTime()/1000.0;
|
||||
}
|
||||
|
||||
private void test(String format, String expected) {
|
||||
String actual = jse_lib.get("date").call(LuaValue.valueOf(format), LuaValue.valueOf(time)).tojstring();
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStringDateChars() { test("foo", "foo"); }
|
||||
|
||||
@Test
|
||||
void testStringDate_a() { test("%a", "Thu"); }
|
||||
|
||||
@Test
|
||||
void testStringDate_A() { test("%A", "Thursday"); }
|
||||
|
||||
@Test
|
||||
void testStringDate_b() { test("%b", "Aug"); }
|
||||
|
||||
@Test
|
||||
void testStringDate_B() { test("%B", "August"); }
|
||||
|
||||
@Test
|
||||
void testStringDate_c() { test("%c", "Thu Aug 23 14:55:02 2001"); }
|
||||
|
||||
@Test
|
||||
void testStringDate_d() { test("%d", "23"); }
|
||||
|
||||
@Test
|
||||
void testStringDate_H() { test("%H", "14"); }
|
||||
|
||||
@Test
|
||||
void testStringDate_I() { test("%I", "02"); }
|
||||
|
||||
@Test
|
||||
void testStringDate_j() { test("%j", "235"); }
|
||||
|
||||
@Test
|
||||
void testStringDate_m() { test("%m", "08"); }
|
||||
|
||||
@Test
|
||||
void testStringDate_M() { test("%M", "55"); }
|
||||
|
||||
@Test
|
||||
void testStringDate_p() { test("%p", "PM"); }
|
||||
|
||||
@Test
|
||||
void testStringDate_S() { test("%S", "02"); }
|
||||
|
||||
@Test
|
||||
void testStringDate_U() { test("%U", "33"); }
|
||||
|
||||
@Test
|
||||
void testStringDate_w() { test("%w", "4"); }
|
||||
|
||||
@Test
|
||||
void testStringDate_W() { test("%W", "34"); }
|
||||
|
||||
@Test
|
||||
void testStringDate_x() { test("%x", "08/23/01"); }
|
||||
|
||||
@Test
|
||||
void testStringDate_X() { test("%X", "14:55:02"); }
|
||||
|
||||
@Test
|
||||
void testStringDate_y() { test("%y", "01"); }
|
||||
|
||||
@Test
|
||||
void testStringDate_Y() { test("%Y", "2001"); }
|
||||
|
||||
@Test
|
||||
void testStringDate_Pct() { test("%%", "%"); }
|
||||
|
||||
static final double DAY = 24.*3600.;
|
||||
|
||||
@Test
|
||||
void testStringDate_UW_neg4() { time -= 4*DAY; test("%c %U %W", "Sun Aug 19 14:55:02 2001 33 33"); }
|
||||
|
||||
@Test
|
||||
void testStringDate_UW_neg3() { time -= 3*DAY; test("%c %U %W", "Mon Aug 20 14:55:02 2001 33 34"); }
|
||||
|
||||
@Test
|
||||
void testStringDate_UW_neg2() { time -= 2*DAY; test("%c %U %W", "Tue Aug 21 14:55:02 2001 33 34"); }
|
||||
|
||||
@Test
|
||||
void testStringDate_UW_neg1() { time -= DAY; test("%c %U %W", "Wed Aug 22 14:55:02 2001 33 34"); }
|
||||
|
||||
@Test
|
||||
void testStringDate_UW_pos0() { time += 0; test("%c %U %W", "Thu Aug 23 14:55:02 2001 33 34"); }
|
||||
|
||||
@Test
|
||||
void testStringDate_UW_pos1() { time += DAY; test("%c %U %W", "Fri Aug 24 14:55:02 2001 33 34"); }
|
||||
|
||||
@Test
|
||||
void testStringDate_UW_pos2() { time += 2*DAY; test("%c %U %W", "Sat Aug 25 14:55:02 2001 33 34"); }
|
||||
|
||||
@Test
|
||||
void testStringDate_UW_pos3() { time += 3*DAY; test("%c %U %W", "Sun Aug 26 14:55:02 2001 34 34"); }
|
||||
|
||||
@Test
|
||||
void testStringDate_UW_pos4() { time += 4*DAY; test("%c %U %W", "Mon Aug 27 14:55:02 2001 34 35"); }
|
||||
|
||||
@Test
|
||||
void testJseOsGetenvForEnvVariables() {
|
||||
LuaValue USER = LuaValue.valueOf("USER");
|
||||
LuaValue jse_user = jse_lib.get("getenv").call(USER);
|
||||
assertFalse(jse_user.isnil());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testJseOsGetenvForSystemProperties() {
|
||||
System.setProperty("test.key.foo", "test.value.bar");
|
||||
LuaValue key = LuaValue.valueOf("test.key.foo");
|
||||
LuaValue value = LuaValue.valueOf("test.value.bar");
|
||||
LuaValue jse_value = jse_lib.get("getenv").call(key);
|
||||
assertEquals(value, jse_value);
|
||||
}
|
||||
}
|
||||
31
luaj-jse/src/test/java/org/luaj/vm2/lib/jse/TestClass.java
Normal file
31
luaj-jse/src/test/java/org/luaj/vm2/lib/jse/TestClass.java
Normal file
@@ -0,0 +1,31 @@
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
public class TestClass {
|
||||
private static class PrivateImpl implements TestInterface {
|
||||
public String public_field;
|
||||
|
||||
public PrivateImpl() {
|
||||
this.public_field = "privateImpl-constructor";
|
||||
}
|
||||
|
||||
PrivateImpl(String f) {
|
||||
this.public_field = f;
|
||||
}
|
||||
|
||||
public String public_method() { return "privateImpl-" + public_field + "-public_method"; }
|
||||
|
||||
public String interface_method(String x) {
|
||||
return "privateImpl-" + public_field + "-interface_method(" + x + ")";
|
||||
}
|
||||
|
||||
public String toString() { return public_field; }
|
||||
}
|
||||
|
||||
public TestInterface create_PrivateImpl(String f) { return new PrivateImpl(f); }
|
||||
|
||||
public Class get_PrivateImplClass() { return PrivateImpl.class; }
|
||||
|
||||
public enum SomeEnum {
|
||||
ValueOne, ValueTwo,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
public interface TestInterface {
|
||||
String interface_method(String x);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.luaj.vm2.script;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import javax.script.Compilable;
|
||||
import javax.script.CompiledScript;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
class CompileClosureTest extends DefaultBindingsTestCase {
|
||||
@BeforeEach
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
System.setProperty("org.luaj.luajc", "false");
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCompiledFunctionIsClosure() throws ScriptException {
|
||||
CompiledScript cs = ((Compilable) e).compile("return 'foo'");
|
||||
LuaValue value = ((LuaScriptEngine.LuajCompiledScript) cs).function;
|
||||
assertTrue(value.isclosure());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.luaj.vm2.script;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
|
||||
import javax.script.Compilable;
|
||||
import javax.script.CompiledScript;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
class CompileNonClosureTest extends DefaultBindingsTestCase {
|
||||
@BeforeEach
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
System.setProperty("org.luaj.luajc", "true");
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCompiledFunctionIsNotClosure() throws ScriptException {
|
||||
CompiledScript cs = ((Compilable) e).compile("return 'foo'");
|
||||
LuaValue value = ((LuaScriptEngine.LuajCompiledScript) cs).function;
|
||||
assertFalse(value.isclosure());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.luaj.vm2.script;
|
||||
|
||||
import javax.script.Bindings;
|
||||
|
||||
abstract class DefaultBindingsTestCase extends EngineTestCase {
|
||||
@Override
|
||||
protected Bindings createBindings() {
|
||||
return e.createBindings();
|
||||
}
|
||||
}
|
||||
186
luaj-jse/src/test/java/org/luaj/vm2/script/EngineTestCase.java
Normal file
186
luaj-jse/src/test/java/org/luaj/vm2/script/EngineTestCase.java
Normal file
@@ -0,0 +1,186 @@
|
||||
package org.luaj.vm2.script;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import java.io.CharArrayReader;
|
||||
import java.io.CharArrayWriter;
|
||||
import java.io.Reader;
|
||||
|
||||
import javax.script.Bindings;
|
||||
import javax.script.Compilable;
|
||||
import javax.script.CompiledScript;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.luaj.vm2.LuaFunction;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.OneArgFunction;
|
||||
|
||||
abstract class EngineTestCase {
|
||||
protected ScriptEngine e;
|
||||
protected Bindings b;
|
||||
|
||||
protected abstract Bindings createBindings();
|
||||
|
||||
@BeforeEach
|
||||
protected void setUp() throws Exception {
|
||||
this.e = new ScriptEngineManager().getEngineByName("luaj");
|
||||
this.b = createBindings();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSqrtIntResult() throws ScriptException {
|
||||
e.put("x", 25);
|
||||
e.eval("y = math.sqrt(x)");
|
||||
Object y = e.get("y");
|
||||
assertEquals(5, y);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testOneArgFunction() throws ScriptException {
|
||||
e.put("x", 25);
|
||||
e.eval("y = math.sqrt(x)");
|
||||
Object y = e.get("y");
|
||||
assertEquals(5, y);
|
||||
e.put("f", new OneArgFunction() {
|
||||
@Override
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return LuaValue.valueOf(arg.toString() + "123");
|
||||
}
|
||||
});
|
||||
Object r = e.eval("return f('abc')");
|
||||
assertEquals("abc123", r);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCompiledScript() throws ScriptException {
|
||||
CompiledScript cs = ((Compilable) e).compile("y = math.sqrt(x); return y");
|
||||
b.put("x", 144);
|
||||
assertEquals(12, cs.eval(b));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBuggyLuaScript() {
|
||||
try {
|
||||
e.eval("\n\nbuggy lua code\n\n");
|
||||
} catch (ScriptException se) {
|
||||
assertEquals("eval threw javax.script.ScriptException: [string \"script\"]:3: syntax error",
|
||||
se.getMessage());
|
||||
return;
|
||||
}
|
||||
fail("buggy script did not throw ScriptException as expected.");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testScriptRedirection() throws ScriptException {
|
||||
Reader input = new CharArrayReader("abcdefg\nhijk".toCharArray());
|
||||
CharArrayWriter output = new CharArrayWriter();
|
||||
CharArrayWriter errors = new CharArrayWriter();
|
||||
String script = "print(\"string written using 'print'\")\n"
|
||||
+ "io.write(\"string written using 'io.write()'\\n\")\n"
|
||||
+ "io.stdout:write(\"string written using 'io.stdout:write()'\\n\")\n"
|
||||
+ "io.stderr:write(\"string written using 'io.stderr:write()'\\n\")\n"
|
||||
+ "io.write([[string read using 'io.stdin:read(\"*l\")':]]..io.stdin:read(\"*l\")..\"\\n\")\n";
|
||||
|
||||
// Evaluate script with redirection set
|
||||
e.getContext().setReader(input);
|
||||
e.getContext().setWriter(output);
|
||||
e.getContext().setErrorWriter(errors);
|
||||
e.eval(script);
|
||||
final String expectedOutput = "string written using 'print'\n" + "string written using 'io.write()'\n"
|
||||
+ "string written using 'io.stdout:write()'\n" + "string read using 'io.stdin:read(\"*l\")':abcdefg\n";
|
||||
assertEquals(expectedOutput, output.toString());
|
||||
final String expectedErrors = "string written using 'io.stderr:write()'\n";
|
||||
assertEquals(expectedErrors, errors.toString());
|
||||
|
||||
// Evaluate script with redirection reset
|
||||
output.reset();
|
||||
errors.reset();
|
||||
// e.getContext().setReader(null); // This will block if using actual STDIN
|
||||
e.getContext().setWriter(null);
|
||||
e.getContext().setErrorWriter(null);
|
||||
e.eval(script);
|
||||
assertEquals("", output.toString());
|
||||
assertEquals("", errors.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingJavaInt() throws ScriptException {
|
||||
CompiledScript cs = ((Compilable) e).compile("y = x; return 'x '..type(x)..' '..tostring(x)\n");
|
||||
b.put("x", 111);
|
||||
assertEquals("x number 111", cs.eval(b));
|
||||
assertEquals(111, b.get("y"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingJavaDouble() throws ScriptException {
|
||||
CompiledScript cs = ((Compilable) e).compile("y = x; return 'x '..type(x)..' '..tostring(x)\n");
|
||||
b.put("x", 125.125);
|
||||
assertEquals("x number 125.125", cs.eval(b));
|
||||
assertEquals(125.125, b.get("y"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingJavaString() throws ScriptException {
|
||||
CompiledScript cs = ((Compilable) e).compile("y = x; return 'x '..type(x)..' '..tostring(x)\n");
|
||||
b.put("x", "foo");
|
||||
assertEquals("x string foo", cs.eval(b));
|
||||
assertEquals("foo", b.get("y"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingJavaObject() throws ScriptException {
|
||||
CompiledScript cs = ((Compilable) e).compile("y = x; return 'x '..type(x)..' '..tostring(x)\n");
|
||||
b.put("x", new SomeUserClass());
|
||||
assertEquals("x userdata some-user-value", cs.eval(b));
|
||||
assertEquals(SomeUserClass.class, b.get("y").getClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingJavaArray() throws ScriptException {
|
||||
CompiledScript cs = ((Compilable) e).compile("y = x; return 'x '..type(x)..' '..#x..' '..x[1]..' '..x[2]\n");
|
||||
b.put("x", new int[] { 777, 888 });
|
||||
assertEquals("x userdata 2 777 888", cs.eval(b));
|
||||
assertEquals(int[].class, b.get("y").getClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingLuaFunction() throws ScriptException {
|
||||
CompiledScript cs = ((Compilable) e).compile("y = function(x) return 678 + x end; return 'foo'");
|
||||
assertEquals("foo", cs.eval(b).toString());
|
||||
assertTrue(b.get("y") instanceof LuaFunction);
|
||||
assertEquals(LuaValue.valueOf(801), ((LuaFunction) b.get("y")).call(LuaValue.valueOf(123)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUserClasses() throws ScriptException {
|
||||
CompiledScript cs = ((Compilable) e).compile("x = x or luajava.newInstance('java.lang.String', 'test')\n"
|
||||
+ "return 'x ' .. type(x) .. ' ' .. tostring(x)\n");
|
||||
assertEquals("x string test", cs.eval(b));
|
||||
b.put("x", new SomeUserClass());
|
||||
assertEquals("x userdata some-user-value", cs.eval(b));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testReturnMultipleValues() throws ScriptException {
|
||||
CompiledScript cs = ((Compilable) e).compile("return 'foo', 'bar'\n");
|
||||
Object o = cs.eval();
|
||||
assertEquals(Object[].class, o.getClass());
|
||||
Object[] array = (Object[]) o;
|
||||
assertEquals(2, array.length);
|
||||
assertEquals("foo", array[0]);
|
||||
assertEquals("bar", array[1]);
|
||||
}
|
||||
|
||||
private static class SomeUserClass {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "some-user-value";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package org.luaj.vm2.script;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineFactory;
|
||||
import javax.script.ScriptEngineManager;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class LookupEngineTest {
|
||||
@Test
|
||||
void testGetEngineByExtension() {
|
||||
ScriptEngine e = new ScriptEngineManager().getEngineByExtension(".lua");
|
||||
assertNotNull(e);
|
||||
assertEquals(LuaScriptEngine.class, e.getClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetEngineByName() {
|
||||
ScriptEngine e = new ScriptEngineManager().getEngineByName("luaj");
|
||||
assertNotNull(e);
|
||||
assertEquals(LuaScriptEngine.class, e.getClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetEngineByMimeType() {
|
||||
ScriptEngine e = new ScriptEngineManager().getEngineByMimeType("text/lua");
|
||||
assertNotNull(e);
|
||||
assertEquals(LuaScriptEngine.class, e.getClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFactoryMetadata() {
|
||||
ScriptEngine e = new ScriptEngineManager().getEngineByName("luaj");
|
||||
ScriptEngineFactory f = e.getFactory();
|
||||
assertEquals("Luaj", f.getEngineName());
|
||||
assertEquals("Luaj 0.0", f.getEngineVersion());
|
||||
assertEquals("lua", f.getLanguageName());
|
||||
assertEquals("5.2", f.getLanguageVersion());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.luaj.vm2.script;
|
||||
|
||||
import javax.script.Bindings;
|
||||
import javax.script.SimpleBindings;
|
||||
|
||||
class SimpleBindingsTest extends EngineTestCase {
|
||||
@Override
|
||||
protected Bindings createBindings() {
|
||||
return new SimpleBindings();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package org.luaj.vm2.script;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import javax.script.Bindings;
|
||||
import javax.script.Compilable;
|
||||
import javax.script.CompiledScript;
|
||||
import javax.script.ScriptContext;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class UserContextTest {
|
||||
protected ScriptEngine e;
|
||||
protected Bindings b;
|
||||
protected ScriptContext c;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
this.e = new ScriptEngineManager().getEngineByName("luaj");
|
||||
this.c = new LuajContext();
|
||||
this.b = c.getBindings(ScriptContext.ENGINE_SCOPE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUncompiledScript() throws ScriptException {
|
||||
b.put("x", 144);
|
||||
assertEquals(12, e.eval("z = math.sqrt(x); return z", b));
|
||||
assertEquals(12, b.get("z"));
|
||||
assertEquals(null, e.getBindings(ScriptContext.ENGINE_SCOPE).get("z"));
|
||||
assertEquals(null, e.getBindings(ScriptContext.GLOBAL_SCOPE).get("z"));
|
||||
|
||||
b.put("x", 25);
|
||||
assertEquals(5, e.eval("z = math.sqrt(x); return z", c));
|
||||
assertEquals(5, b.get("z"));
|
||||
assertEquals(null, e.getBindings(ScriptContext.ENGINE_SCOPE).get("z"));
|
||||
assertEquals(null, e.getBindings(ScriptContext.GLOBAL_SCOPE).get("z"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCompiledScript() throws ScriptException {
|
||||
CompiledScript cs = ((Compilable) e).compile("z = math.sqrt(x); return z");
|
||||
|
||||
b.put("x", 144);
|
||||
assertEquals(12, cs.eval(b));
|
||||
assertEquals(12, b.get("z"));
|
||||
|
||||
b.put("x", 25);
|
||||
assertEquals(5, cs.eval(c));
|
||||
assertEquals(5, b.get("z"));
|
||||
}
|
||||
}
|
||||
38
luaj-jse/src/test/java/org/luaj/vm2/script/WriterTest.java
Normal file
38
luaj-jse/src/test/java/org/luaj/vm2/script/WriterTest.java
Normal file
@@ -0,0 +1,38 @@
|
||||
package org.luaj.vm2.script;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.io.CharArrayWriter;
|
||||
|
||||
import javax.script.Bindings;
|
||||
import javax.script.ScriptContext;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class WriterTest {
|
||||
protected ScriptEngine e;
|
||||
protected Bindings b;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
this.e = new ScriptEngineManager().getEngineByName("luaj");
|
||||
this.b = e.getBindings(ScriptContext.ENGINE_SCOPE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testWriter() throws ScriptException {
|
||||
CharArrayWriter output = new CharArrayWriter();
|
||||
CharArrayWriter errors = new CharArrayWriter();
|
||||
e.getContext().setWriter(output);
|
||||
e.getContext().setErrorWriter(errors);
|
||||
e.eval("io.write( [[line]] )");
|
||||
assertEquals("line", output.toString());
|
||||
e.eval("io.write( [[ one\nline two\n]] )");
|
||||
assertEquals("line one\nline two\n", output.toString());
|
||||
output.reset();
|
||||
}
|
||||
}
|
||||
0
luaj-jse/src/test/resources/.keep
Normal file
0
luaj-jse/src/test/resources/.keep
Normal file
Reference in New Issue
Block a user