Implemented Support of Java 21 VirtualThread
This commit is contained in:
134
jse/pom.xml
Normal file
134
jse/pom.xml
Normal file
@@ -0,0 +1,134 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.openautonomousconnection.luaj</groupId>
|
||||
<artifactId>parent</artifactId>
|
||||
<version>3.0.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>jse</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.openautonomousconnection.luaj</groupId>
|
||||
<artifactId>core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.bcel</groupId>
|
||||
<artifactId>bcel</artifactId>
|
||||
<version>6.12.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.3.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-sources</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals><goal>copy-resources</goal></goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/generated-sources/luaj-jse</outputDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>${project.basedir}/../luaj-core/src/main/java</directory>
|
||||
<includes><include>**/*.java</include></includes>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>${project.basedir}/src/main/java</directory>
|
||||
<includes><include>**/*.java</include></includes>
|
||||
</resource>
|
||||
</resources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.google.code.maven-replacer-plugin</groupId>
|
||||
<artifactId>replacer</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>rewrite-branding-and-cleanup</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals><goal>replace</goal></goals>
|
||||
<configuration>
|
||||
<basedir>${project.build.directory}/generated-sources/luaj-jse</basedir>
|
||||
<includes>
|
||||
<include>**/*.java</include>
|
||||
</includes>
|
||||
<replacements>
|
||||
<replacement>
|
||||
<token>"Luaj 0.0"</token>
|
||||
<value>"${luaj.brand.jse}"</value>
|
||||
</replacement>
|
||||
<replacement><token><String></token><value></value></replacement>
|
||||
<replacement><token><Stat></token><value></value></replacement>
|
||||
<replacement><token><Exp></token><value></value></replacement>
|
||||
<replacement><token><Name></token><value></value></replacement>
|
||||
<replacement><token><Block></token><value></value></replacement>
|
||||
<replacement><token><TableField></token><value></value></replacement>
|
||||
<replacement><token><VarExp></token><value></value></replacement>
|
||||
<replacement><token><Exp.VarExp></token><value></value></replacement>
|
||||
<replacement><token><Object,String></token><value></value></replacement>
|
||||
<replacement><token><Double,String></token><value></value></replacement>
|
||||
<replacement><token><Integer,Integer></token><value></value></replacement>
|
||||
<replacement><token><Integer,LocalVariableGen></token><value></value></replacement>
|
||||
<replacement><token><Exp,Integer></token><value></value></replacement>
|
||||
<replacement><token><String,byte[]></token><value></value></replacement>
|
||||
<replacement><token><String,Variable></token><value></value></replacement>
|
||||
<replacement><token><LuaValue,String></token><value></value></replacement>
|
||||
<replacement><token><LuaString,String></token><value></value></replacement>
|
||||
</replacements>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-generated-sources</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals><goal>add-source</goal></goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>${project.build.directory}/generated-sources/luaj-jse</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.4.2</version>
|
||||
<configuration>
|
||||
<includes>
|
||||
<include>**/*</include>
|
||||
</includes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-sources</id>
|
||||
<goals><goal>jar</goal></goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
238
jse/src/main/java/lua.java
Normal file
238
jse/src/main/java/lua.java
Normal file
@@ -0,0 +1,238 @@
|
||||
/*******************************************************************************
|
||||
* 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
194
jse/src/main/java/luac.java
Normal file
194
jse/src/main/java/luac.java
Normal file
@@ -0,0 +1,194 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
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
|
||||
OutputStream fos = new FileOutputStream( output );
|
||||
|
||||
// process input files
|
||||
try {
|
||||
Globals globals = JsePlatform.standardGlobals();
|
||||
processing = true;
|
||||
for ( int i=0; i<args.length; i++ ) {
|
||||
if ( ! processing || ! args[i].startsWith("-") ) {
|
||||
String chunkname = args[i].substring(0,args[i].length()-4);
|
||||
processScript( globals, new FileInputStream(args[i]), chunkname, fos );
|
||||
} else if ( args[i].length() <= 1 ) {
|
||||
processScript( globals, System.in, "=stdin", fos );
|
||||
} else {
|
||||
switch ( args[i].charAt(1) ) {
|
||||
case 'o':
|
||||
case 'c':
|
||||
++i;
|
||||
break;
|
||||
case '-':
|
||||
processing = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
fos.close();
|
||||
}
|
||||
|
||||
} 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
jse/src/main/java/luajc.java
Normal file
270
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 List files = new ArrayList();
|
||||
private 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 ( int i=0; i<seeds.size(); i++ )
|
||||
collectFiles( srcdir+"/"+seeds.get(i) );
|
||||
|
||||
// check for at least one file
|
||||
if ( files.size() <= 0 ) {
|
||||
System.err.println("no files found in "+seeds);
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
// process input files
|
||||
globals = JsePlatform.standardGlobals();
|
||||
for ( int i=0,n=files.size(); i<n; i++ )
|
||||
processFile( (InputFile) files.get(i) );
|
||||
}
|
||||
|
||||
private void collectFiles(String path) {
|
||||
File f = new File(path);
|
||||
if ( f.isDirectory() && recurse )
|
||||
scandir(f,pkgprefix);
|
||||
else if ( f.isFile() ) {
|
||||
File dir = f.getAbsoluteFile().getParentFile();
|
||||
if ( dir != null )
|
||||
scanfile( dir, f, pkgprefix );
|
||||
}
|
||||
}
|
||||
private void scandir(File dir, String javapackage) {
|
||||
File[] f = dir.listFiles();
|
||||
for ( int i=0; i<f.length; i++ )
|
||||
scanfile( dir, f[i], javapackage );
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
41
jse/src/main/java/org/luaj/vm2/ast/Block.java
Normal file
41
jse/src/main/java/org/luaj/vm2/ast/Block.java
Normal file
@@ -0,0 +1,41 @@
|
||||
/*******************************************************************************
|
||||
* 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<Stat>();
|
||||
public NameScope scope;
|
||||
|
||||
public void add(Stat s) {
|
||||
if ( s == null )
|
||||
return;
|
||||
stats.add(s);
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
34
jse/src/main/java/org/luaj/vm2/ast/Chunk.java
Normal file
34
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 );
|
||||
}
|
||||
}
|
||||
313
jse/src/main/java/org/luaj/vm2/ast/Exp.java
Normal file
313
jse/src/main/java/org/luaj/vm2/ast/Exp.java
Normal file
@@ -0,0 +1,313 @@
|
||||
/*******************************************************************************
|
||||
* 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 {
|
||||
public boolean isvarexp() {
|
||||
return false;
|
||||
}
|
||||
public boolean isfunccall() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
abstract public static class VarExp extends PrimaryExp {
|
||||
public boolean isvarexp() {
|
||||
return true;
|
||||
}
|
||||
public void markHasAssignment() {
|
||||
}
|
||||
}
|
||||
|
||||
public static class NameExp extends VarExp {
|
||||
public final Name name;
|
||||
public NameExp(String name) {
|
||||
this.name = new Name(name);
|
||||
}
|
||||
public void markHasAssignment() {
|
||||
name.variable.hasassignments = true;
|
||||
}
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ParensExp extends PrimaryExp {
|
||||
public final Exp exp;
|
||||
public ParensExp(Exp exp) {
|
||||
this.exp = exp;
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class FieldExp extends VarExp {
|
||||
public final PrimaryExp lhs;
|
||||
public final Name name;
|
||||
public FieldExp(PrimaryExp lhs, String name) {
|
||||
this.lhs = lhs;
|
||||
this.name = new Name(name);
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class IndexExp extends VarExp {
|
||||
public final PrimaryExp lhs;
|
||||
public final Exp exp;
|
||||
public IndexExp(PrimaryExp lhs, Exp exp) {
|
||||
this.lhs = lhs;
|
||||
this.exp = exp;
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class FuncCall extends PrimaryExp {
|
||||
public final PrimaryExp lhs;
|
||||
public final FuncArgs args;
|
||||
|
||||
public FuncCall(PrimaryExp lhs, FuncArgs args) {
|
||||
this.lhs = lhs;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public boolean isfunccall() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
public boolean isvarargexp() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static class MethodCall extends FuncCall {
|
||||
public final String name;
|
||||
|
||||
public MethodCall(PrimaryExp lhs, String name, FuncArgs args) {
|
||||
super(lhs, args);
|
||||
this.name = new String(name);
|
||||
}
|
||||
|
||||
public boolean isfunccall() {
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class VarargsExp extends Exp {
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
public boolean isvarargexp() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static class UnopExp extends Exp {
|
||||
public final int op;
|
||||
public final Exp rhs;
|
||||
public UnopExp(int op, Exp rhs) {
|
||||
this.op = op;
|
||||
this.rhs = rhs;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class AnonFuncDef extends Exp {
|
||||
public final FuncBody body;
|
||||
public AnonFuncDef(FuncBody funcbody) {
|
||||
this.body = funcbody;
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
66
jse/src/main/java/org/luaj/vm2/ast/FuncArgs.java
Normal file
66
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<Exp>();
|
||||
this.exps.add( Exp.constant(string) );
|
||||
}
|
||||
|
||||
public FuncArgs(TableConstructor table) {
|
||||
this.exps = new ArrayList<Exp>();
|
||||
this.exps.add( table );
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
}
|
||||
36
jse/src/main/java/org/luaj/vm2/ast/FuncBody.java
Normal file
36
jse/src/main/java/org/luaj/vm2/ast/FuncBody.java
Normal file
@@ -0,0 +1,36 @@
|
||||
/*******************************************************************************
|
||||
* 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
jse/src/main/java/org/luaj/vm2/ast/FuncName.java
Normal file
49
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<String>();
|
||||
dots.add(dot);
|
||||
}
|
||||
|
||||
}
|
||||
31
jse/src/main/java/org/luaj/vm2/ast/Name.java
Normal file
31
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;
|
||||
}
|
||||
}
|
||||
127
jse/src/main/java/org/luaj/vm2/ast/NameResolver.java
Normal file
127
jse/src/main/java/org/luaj/vm2/ast/NameResolver.java
Normal file
@@ -0,0 +1,127 @@
|
||||
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;
|
||||
}
|
||||
|
||||
public void visit(NameScope scope) {
|
||||
}
|
||||
|
||||
public void visit(Block block) {
|
||||
pushScope();
|
||||
block.scope = scope;
|
||||
super.visit(block);
|
||||
popScope();
|
||||
}
|
||||
|
||||
public void visit(FuncBody body) {
|
||||
pushScope();
|
||||
scope.functionNestingCount++;
|
||||
body.scope = scope;
|
||||
super.visit(body);
|
||||
popScope();
|
||||
}
|
||||
|
||||
public void visit(LocalFuncDef stat) {
|
||||
defineLocalVar(stat.name);
|
||||
super.visit(stat);
|
||||
}
|
||||
|
||||
public void visit(NumericFor stat) {
|
||||
pushScope();
|
||||
stat.scope = scope;
|
||||
defineLocalVar(stat.name);
|
||||
super.visit(stat);
|
||||
popScope();
|
||||
}
|
||||
|
||||
public void visit(GenericFor stat) {
|
||||
pushScope();
|
||||
stat.scope = scope;
|
||||
defineLocalVars( stat.names );
|
||||
super.visit(stat);
|
||||
popScope();
|
||||
}
|
||||
|
||||
public void visit(NameExp exp) {
|
||||
exp.name.variable = resolveNameReference(exp.name);
|
||||
super.visit(exp);
|
||||
}
|
||||
|
||||
public void visit(FuncDef stat) {
|
||||
stat.name.name.variable = resolveNameReference(stat.name.name);
|
||||
stat.name.name.variable.hasassignments = true;
|
||||
super.visit(stat);
|
||||
}
|
||||
|
||||
public void visit(Assign stat) {
|
||||
super.visit(stat);
|
||||
for ( int i=0, n=stat.vars.size(); i<n; i++ ) {
|
||||
VarExp v = (VarExp) stat.vars.get(i);
|
||||
v.markHasAssignment();
|
||||
}
|
||||
}
|
||||
|
||||
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 && ((Exp)stat.values.get(m-1)).isvarargexp();
|
||||
for ( int i=0; i<n && i<(isvarlist?m-1:m); i++ )
|
||||
if ( stat.values.get(i) instanceof Constant )
|
||||
((Name)stat.names.get(i)).variable.initialValue = ((Constant) stat.values.get(i)).value;
|
||||
if ( !isvarlist )
|
||||
for ( int i=m; i<n; i++ )
|
||||
((Name)stat.names.get(i)).variable.initialValue = LuaValue.NIL;
|
||||
}
|
||||
|
||||
public void visit(ParList pars) {
|
||||
if ( pars.names != null )
|
||||
defineLocalVars(pars.names);
|
||||
if ( pars.isvararg )
|
||||
scope.define("arg");
|
||||
super.visit(pars);
|
||||
}
|
||||
|
||||
protected void defineLocalVars(List<Name> names) {
|
||||
for ( int i=0, n=names.size(); i<n; i++ )
|
||||
defineLocalVar((Name) names.get(i));
|
||||
}
|
||||
|
||||
protected void defineLocalVar(Name name) {
|
||||
name.variable = scope.define(name.name);
|
||||
}
|
||||
|
||||
protected Variable resolveNameReference(Name name) {
|
||||
Variable v = scope.find(name.name);
|
||||
if ( v.isLocal() && scope.functionNestingCount != v.definingScope.functionNestingCount )
|
||||
v.isupvalue = true;
|
||||
return v;
|
||||
}
|
||||
}
|
||||
85
jse/src/main/java/org/luaj/vm2/ast/NameScope.java
Normal file
85
jse/src/main/java/org/luaj/vm2/ast/NameScope.java
Normal file
@@ -0,0 +1,85 @@
|
||||
/*******************************************************************************
|
||||
* 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<String>();
|
||||
|
||||
static {
|
||||
String[] k = new String[] {
|
||||
"and", "break", "do", "else", "elseif", "end",
|
||||
"false", "for", "function", "if", "in", "local",
|
||||
"nil", "not", "or", "repeat", "return",
|
||||
"then", "true", "until", "while" };
|
||||
for ( int i=0; i<k.length; i++ )
|
||||
LUA_KEYWORDS.add( k[i] );
|
||||
}
|
||||
|
||||
public final Map<String,Variable> namedVariables = new HashMap<String,Variable>();
|
||||
|
||||
public final NameScope outerScope;
|
||||
|
||||
public int functionNestingCount;
|
||||
|
||||
/** Construct default names scope */
|
||||
public NameScope() {
|
||||
this.outerScope = null;
|
||||
this.functionNestingCount = 0;
|
||||
}
|
||||
|
||||
/** Construct name scope within another scope*/
|
||||
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 (Variable)n.namedVariables.get(name);
|
||||
Variable value = new Variable(name);
|
||||
this.namedVariables.put(name, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
/** Define a name in this scope. If it is a global name, then throw IllegalArgumentException. */
|
||||
public Variable define( String name ) throws IllegalStateException, IllegalArgumentException {
|
||||
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
jse/src/main/java/org/luaj/vm2/ast/ParList.java
Normal file
42
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<Name>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
278
jse/src/main/java/org/luaj/vm2/ast/Stat.java
Normal file
278
jse/src/main/java/org/luaj/vm2/ast/Stat.java
Normal file
@@ -0,0 +1,278 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit( this );
|
||||
}
|
||||
}
|
||||
|
||||
public static class Break extends Stat {
|
||||
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;
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit( this );
|
||||
}
|
||||
|
||||
public int nreturns() {
|
||||
int n = values!=null? values.size(): 0;
|
||||
if ( n>0 && ((Exp)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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit( this );
|
||||
}
|
||||
}
|
||||
}
|
||||
93
jse/src/main/java/org/luaj/vm2/ast/Str.java
Normal file
93
jse/src/main/java/org/luaj/vm2/ast/Str.java
Normal file
@@ -0,0 +1,93 @@
|
||||
/*******************************************************************************
|
||||
* 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=(int) (c[i++]-'0');
|
||||
for ( int j=0; i<n && j<2 && c[i]>='0' && c[i]<='9'; i++, j++ )
|
||||
d = d * 10 + (int) (c[i]-'0');
|
||||
baos.write( (byte) d );
|
||||
--i;
|
||||
continue;
|
||||
case 'a': baos.write( (byte) 7 ); continue;
|
||||
case 'b': baos.write( (byte) '\b' ); continue;
|
||||
case 'f': baos.write( (byte) '\f' ); continue;
|
||||
case 'n': baos.write( (byte) '\n' ); continue;
|
||||
case 'r': baos.write( (byte) '\r' ); continue;
|
||||
case 't': baos.write( (byte) '\t' ); continue;
|
||||
case 'v': baos.write( (byte) 11 ); continue;
|
||||
case '"': baos.write( (byte) '"' ); continue;
|
||||
case '\'': baos.write( (byte) '\'' ); continue;
|
||||
case '\\': baos.write( (byte) '\\' ); continue;
|
||||
default: baos.write( (byte) c[i] ); break;
|
||||
}
|
||||
} else {
|
||||
baos.write( (byte) c[i] );
|
||||
}
|
||||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
}
|
||||
40
jse/src/main/java/org/luaj/vm2/ast/SyntaxElement.java
Normal file
40
jse/src/main/java/org/luaj/vm2/ast/SyntaxElement.java
Normal file
@@ -0,0 +1,40 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
}
|
||||
32
jse/src/main/java/org/luaj/vm2/ast/TableConstructor.java
Normal file
32
jse/src/main/java/org/luaj/vm2/ast/TableConstructor.java
Normal file
@@ -0,0 +1,32 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
51
jse/src/main/java/org/luaj/vm2/ast/TableField.java
Normal file
51
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);
|
||||
}
|
||||
}
|
||||
62
jse/src/main/java/org/luaj/vm2/ast/Variable.java
Normal file
62
jse/src/main/java/org/luaj/vm2/ast/Variable.java
Normal file
@@ -0,0 +1,62 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
180
jse/src/main/java/org/luaj/vm2/ast/Visitor.java
Normal file
180
jse/src/main/java/org/luaj/vm2/ast/Visitor.java
Normal file
@@ -0,0 +1,180 @@
|
||||
/*******************************************************************************
|
||||
* 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 ( int i=0, n=block.stats.size(); i<n; i++ )
|
||||
((Stat)block.stats.get(i)).accept(this);
|
||||
};
|
||||
public void visit(Stat.Assign stat) {
|
||||
visitVars(stat.vars);
|
||||
visitExps(stat.exps);
|
||||
}
|
||||
public void visit(Stat.Break breakstat) {
|
||||
}
|
||||
public void visit(Stat.FuncCallStat stat) {
|
||||
stat.funccall.accept(this);
|
||||
}
|
||||
public void visit(Stat.FuncDef stat) {
|
||||
stat.body.accept(this);
|
||||
}
|
||||
public void visit(Stat.GenericFor stat) {
|
||||
visit(stat.scope);
|
||||
visitNames(stat.names);
|
||||
visitExps(stat.exps);
|
||||
stat.block.accept(this);
|
||||
}
|
||||
public void visit(Stat.IfThenElse stat) {
|
||||
stat.ifexp.accept(this);
|
||||
stat.ifblock.accept(this);
|
||||
if ( stat.elseifblocks != null )
|
||||
for ( int i=0, n=stat.elseifblocks.size(); i<n; i++ ) {
|
||||
((Exp)stat.elseifexps.get(i)).accept(this);
|
||||
((Block)stat.elseifblocks.get(i)).accept(this);
|
||||
}
|
||||
if ( stat.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 ( int i=0, n=table.fields.size(); i<n; i++ )
|
||||
((TableField)table.fields.get(i)).accept(this);
|
||||
}
|
||||
public void visitVars(List<VarExp> vars) {
|
||||
if ( vars != null )
|
||||
for ( int i=0, n=vars.size(); i<n; i++ )
|
||||
((VarExp)vars.get(i)).accept(this);
|
||||
}
|
||||
public void visitExps(List<Exp> exps) {
|
||||
if ( exps != null )
|
||||
for ( int i=0, n=exps.size(); i<n; i++ )
|
||||
((Exp)exps.get(i)).accept(this);
|
||||
}
|
||||
public void visitNames(List<Name> names) {
|
||||
if ( names != null )
|
||||
for ( int i=0, n=names.size(); i<n; i++ )
|
||||
visit((Name) names.get(i));
|
||||
}
|
||||
public void visit(Name name) {
|
||||
}
|
||||
public void visit(String name) {
|
||||
}
|
||||
public void visit(NameScope scope) {
|
||||
}
|
||||
public void visit(Stat.Goto gotostat) {
|
||||
}
|
||||
public void visit(Stat.Label label) {
|
||||
}
|
||||
}
|
||||
215
jse/src/main/java/org/luaj/vm2/luajc/BasicBlock.java
Normal file
215
jse/src/main/java/org/luaj/vm2/luajc/BasicBlock.java
Normal file
@@ -0,0 +1,215 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public void visitBranch(int pc0, int pc1) {
|
||||
isend[pc0] = true;
|
||||
isbeg[pc1] = true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
853
jse/src/main/java/org/luaj/vm2/luajc/JavaBuilder.java
Normal file
853
jse/src/main/java/org/luaj/vm2/luajc/JavaBuilder.java
Normal file
@@ -0,0 +1,853 @@
|
||||
/*******************************************************************************
|
||||
* 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 i=0, n=p.code.length; i<n; i++ ) {
|
||||
int inst = p.code[i];
|
||||
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( Integer.valueOf(slot), Integer.valueOf(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 Map<Integer,Integer> plainSlotVars = new HashMap<Integer,Integer>();
|
||||
private Map<Integer,Integer> upvalueSlotVars = new HashMap<Integer,Integer>();
|
||||
private Map<Integer,LocalVariableGen> localVarGenBySlot = new HashMap<Integer,LocalVariableGen>();
|
||||
private int findSlot( int slot, Map<Integer,Integer> map, String prefix, Type type ) {
|
||||
Integer islot = Integer.valueOf(slot);
|
||||
if ( map.containsKey(islot) )
|
||||
return ((Integer)map.get(islot)).intValue();
|
||||
String name = prefix+slot;
|
||||
LocalVariableGen local = mg.addLocalVariable(name, type, null, null);
|
||||
int index = local.getIndex();
|
||||
map.put(islot, Integer.valueOf(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 Map<LuaValue,String> constants = new HashMap<LuaValue,String>();
|
||||
|
||||
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 = (String) 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 & (int) (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 = Integer.valueOf(slot);
|
||||
if (localVarGenBySlot.containsKey(islot)) {
|
||||
name = name.replaceAll("[^a-zA-Z0-9]", "_");
|
||||
LocalVariableGen l = (LocalVariableGen)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));
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
447
jse/src/main/java/org/luaj/vm2/luajc/JavaGen.java
Normal file
447
jse/src/main/java/org/luaj/vm2/luajc/JavaGen.java
Normal file
@@ -0,0 +1,447 @@
|
||||
/*******************************************************************************
|
||||
* 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 ( int bi=0; bi<pi.blocklist.length; bi++ ) {
|
||||
BasicBlock b0 = pi.blocklist[bi];
|
||||
|
||||
// convert upvalues that are phi-variables
|
||||
for ( int slot=0; slot<p.maxstacksize; slot++ ) {
|
||||
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] );
|
||||
}
|
||||
}
|
||||
73
jse/src/main/java/org/luaj/vm2/luajc/JavaLoader.java
Normal file
73
jse/src/main/java/org/luaj/vm2/luajc/JavaLoader.java
Normal file
@@ -0,0 +1,73 @@
|
||||
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 Map<String,byte[]> unloaded = new HashMap<String,byte[]>();
|
||||
|
||||
public JavaLoader() {
|
||||
}
|
||||
|
||||
public LuaFunction load( Prototype p, String classname, String filename, LuaValue env ) {
|
||||
JavaGen jg = new JavaGen( p, classname, filename, false );
|
||||
return load( jg, env );
|
||||
}
|
||||
|
||||
public LuaFunction load( 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] );
|
||||
}
|
||||
|
||||
public Class findClass(String classname) throws ClassNotFoundException {
|
||||
byte[] bytes = (byte[]) unloaded.get(classname);
|
||||
if ( bytes != null )
|
||||
return defineClass(classname, bytes, 0, bytes.length);
|
||||
return super.findClass(classname);
|
||||
}
|
||||
|
||||
}
|
||||
132
jse/src/main/java/org/luaj/vm2/luajc/LuaJC.java
Normal file
132
jse/src/main/java/org/luaj/vm2/luajc/LuaJC.java
Normal file
@@ -0,0 +1,132 @@
|
||||
/*******************************************************************************
|
||||
* 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 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 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]);
|
||||
}
|
||||
|
||||
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 ) {
|
||||
String stub = s.endsWith(".lua")? s.substring(0,s.length()-4): s;
|
||||
return stub;
|
||||
}
|
||||
}
|
||||
534
jse/src/main/java/org/luaj/vm2/luajc/ProtoInfo.java
Normal file
534
jse/src/main/java/org/luaj/vm2/luajc/ProtoInfo.java
Normal file
@@ -0,0 +1,534 @@
|
||||
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();
|
||||
}
|
||||
|
||||
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 ( int i=0; i<blocklist.length; i++ ) {
|
||||
BasicBlock b = blocklist[i];
|
||||
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 ( int bi=0; bi<blocklist.length; bi++ ) {
|
||||
BasicBlock b0 = blocklist[bi];
|
||||
|
||||
// input from previous blocks
|
||||
int nprev = b0.prev!=null? b0.prev.length: 0;
|
||||
for ( int slot=0; slot<m; slot++ ) {
|
||||
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 ( int i=0; i<blocklist.length; i++ ) {
|
||||
BasicBlock b0 = blocklist[i];
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
153
jse/src/main/java/org/luaj/vm2/luajc/UpvalInfo.java
Normal file
153
jse/src/main/java/org/luaj/vm2/luajc/UpvalInfo.java
Normal file
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
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 ( int i=0, n=pi.blocklist.length; i<n; i++ ) {
|
||||
BasicBlock b = pi.blocklist[i];
|
||||
VarInfo v = pi.vars[slot][b.pc1];
|
||||
if ( v == prior ) {
|
||||
for ( int j=0, m=b.next!=null? b.next.length: 0; j<m; j++ ) {
|
||||
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 ( int i=0, n=pi.blocklist.length; i<n; i++ ) {
|
||||
BasicBlock b = pi.blocklist[i];
|
||||
VarInfo v = pi.vars[slot][b.pc0];
|
||||
if ( v == poster ) {
|
||||
for ( int j=0, m=b.prev!=null? b.prev.length: 0; j<m; j++ ) {
|
||||
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;
|
||||
}
|
||||
|
||||
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 ( int i=0, n=b.prev.length; i<n; i++ ) {
|
||||
v = pi.vars[slot][b.prev[i].pc1];
|
||||
if ( v != null && v.upvalue != this )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
144
jse/src/main/java/org/luaj/vm2/luajc/VarInfo.java
Normal file
144
jse/src/main/java/org/luaj/vm2/luajc/VarInfo.java
Normal file
@@ -0,0 +1,144 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return slot + ".p";
|
||||
}
|
||||
}
|
||||
|
||||
private static final class NilVarInfo extends VarInfo {
|
||||
private NilVarInfo(int slot, int pc) {
|
||||
super(slot, pc);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public boolean isPhiVar() {
|
||||
return true;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1914
jse/src/main/java/org/luaj/vm2/parser/LuaParser.java
Normal file
1914
jse/src/main/java/org/luaj/vm2/parser/LuaParser.java
Normal file
File diff suppressed because it is too large
Load Diff
240
jse/src/main/java/org/luaj/vm2/parser/LuaParserConstants.java
Normal file
240
jse/src/main/java/org/luaj/vm2/parser/LuaParserConstants.java
Normal file
@@ -0,0 +1,240 @@
|
||||
/* Generated By:JavaCC: Do not edit this line. LuaParserConstants.java */
|
||||
package org.luaj.vm2.parser;
|
||||
|
||||
|
||||
/**
|
||||
* Token literal values and constants.
|
||||
* Generated by org.javacc.parser.OtherFilesGen#start()
|
||||
*/
|
||||
public interface LuaParserConstants {
|
||||
|
||||
/** End of File. */
|
||||
int EOF = 0;
|
||||
/** RegularExpression Id. */
|
||||
int COMMENT = 17;
|
||||
/** RegularExpression Id. */
|
||||
int LONGCOMMENT0 = 18;
|
||||
/** RegularExpression Id. */
|
||||
int LONGCOMMENT1 = 19;
|
||||
/** RegularExpression Id. */
|
||||
int LONGCOMMENT2 = 20;
|
||||
/** RegularExpression Id. */
|
||||
int LONGCOMMENT3 = 21;
|
||||
/** RegularExpression Id. */
|
||||
int LONGCOMMENTN = 22;
|
||||
/** RegularExpression Id. */
|
||||
int LONGSTRING0 = 23;
|
||||
/** RegularExpression Id. */
|
||||
int LONGSTRING1 = 24;
|
||||
/** RegularExpression Id. */
|
||||
int LONGSTRING2 = 25;
|
||||
/** RegularExpression Id. */
|
||||
int LONGSTRING3 = 26;
|
||||
/** RegularExpression Id. */
|
||||
int LONGSTRINGN = 27;
|
||||
/** RegularExpression Id. */
|
||||
int AND = 29;
|
||||
/** RegularExpression Id. */
|
||||
int BREAK = 30;
|
||||
/** RegularExpression Id. */
|
||||
int DO = 31;
|
||||
/** RegularExpression Id. */
|
||||
int ELSE = 32;
|
||||
/** RegularExpression Id. */
|
||||
int ELSEIF = 33;
|
||||
/** RegularExpression Id. */
|
||||
int END = 34;
|
||||
/** RegularExpression Id. */
|
||||
int FALSE = 35;
|
||||
/** RegularExpression Id. */
|
||||
int FOR = 36;
|
||||
/** RegularExpression Id. */
|
||||
int FUNCTION = 37;
|
||||
/** RegularExpression Id. */
|
||||
int GOTO = 38;
|
||||
/** RegularExpression Id. */
|
||||
int IF = 39;
|
||||
/** RegularExpression Id. */
|
||||
int IN = 40;
|
||||
/** RegularExpression Id. */
|
||||
int LOCAL = 41;
|
||||
/** RegularExpression Id. */
|
||||
int NIL = 42;
|
||||
/** RegularExpression Id. */
|
||||
int NOT = 43;
|
||||
/** RegularExpression Id. */
|
||||
int OR = 44;
|
||||
/** RegularExpression Id. */
|
||||
int RETURN = 45;
|
||||
/** RegularExpression Id. */
|
||||
int REPEAT = 46;
|
||||
/** RegularExpression Id. */
|
||||
int THEN = 47;
|
||||
/** RegularExpression Id. */
|
||||
int TRUE = 48;
|
||||
/** RegularExpression Id. */
|
||||
int UNTIL = 49;
|
||||
/** RegularExpression Id. */
|
||||
int WHILE = 50;
|
||||
/** RegularExpression Id. */
|
||||
int NAME = 51;
|
||||
/** RegularExpression Id. */
|
||||
int NUMBER = 52;
|
||||
/** RegularExpression Id. */
|
||||
int FLOAT = 53;
|
||||
/** RegularExpression Id. */
|
||||
int FNUM = 54;
|
||||
/** RegularExpression Id. */
|
||||
int DIGIT = 55;
|
||||
/** RegularExpression Id. */
|
||||
int EXP = 56;
|
||||
/** RegularExpression Id. */
|
||||
int HEX = 57;
|
||||
/** RegularExpression Id. */
|
||||
int HEXNUM = 58;
|
||||
/** RegularExpression Id. */
|
||||
int HEXDIGIT = 59;
|
||||
/** RegularExpression Id. */
|
||||
int HEXEXP = 60;
|
||||
/** RegularExpression Id. */
|
||||
int STRING = 61;
|
||||
/** RegularExpression Id. */
|
||||
int CHARSTRING = 62;
|
||||
/** RegularExpression Id. */
|
||||
int QUOTED = 63;
|
||||
/** RegularExpression Id. */
|
||||
int DECIMAL = 64;
|
||||
/** RegularExpression Id. */
|
||||
int DBCOLON = 65;
|
||||
/** RegularExpression Id. */
|
||||
int UNICODE = 66;
|
||||
/** RegularExpression Id. */
|
||||
int CHAR = 67;
|
||||
/** RegularExpression Id. */
|
||||
int LF = 68;
|
||||
|
||||
/** Lexical state. */
|
||||
int DEFAULT = 0;
|
||||
/** Lexical state. */
|
||||
int IN_COMMENT = 1;
|
||||
/** Lexical state. */
|
||||
int IN_LC0 = 2;
|
||||
/** Lexical state. */
|
||||
int IN_LC1 = 3;
|
||||
/** Lexical state. */
|
||||
int IN_LC2 = 4;
|
||||
/** Lexical state. */
|
||||
int IN_LC3 = 5;
|
||||
/** Lexical state. */
|
||||
int IN_LCN = 6;
|
||||
/** Lexical state. */
|
||||
int IN_LS0 = 7;
|
||||
/** Lexical state. */
|
||||
int IN_LS1 = 8;
|
||||
/** Lexical state. */
|
||||
int IN_LS2 = 9;
|
||||
/** Lexical state. */
|
||||
int IN_LS3 = 10;
|
||||
/** Lexical state. */
|
||||
int IN_LSN = 11;
|
||||
|
||||
/** Literal token values. */
|
||||
String[] tokenImage = {
|
||||
"<EOF>",
|
||||
"\" \"",
|
||||
"\"\\t\"",
|
||||
"\"\\n\"",
|
||||
"\"\\r\"",
|
||||
"\"\\f\"",
|
||||
"\"--[[\"",
|
||||
"\"--[=[\"",
|
||||
"\"--[==[\"",
|
||||
"\"--[===[\"",
|
||||
"<token of kind 10>",
|
||||
"\"[[\"",
|
||||
"\"[=[\"",
|
||||
"\"[==[\"",
|
||||
"\"[===[\"",
|
||||
"<token of kind 15>",
|
||||
"\"--\"",
|
||||
"<COMMENT>",
|
||||
"\"]]\"",
|
||||
"\"]=]\"",
|
||||
"\"]==]\"",
|
||||
"\"]===]\"",
|
||||
"<LONGCOMMENTN>",
|
||||
"\"]]\"",
|
||||
"\"]=]\"",
|
||||
"\"]==]\"",
|
||||
"\"]===]\"",
|
||||
"<LONGSTRINGN>",
|
||||
"<token of kind 28>",
|
||||
"\"and\"",
|
||||
"\"break\"",
|
||||
"\"do\"",
|
||||
"\"else\"",
|
||||
"\"elseif\"",
|
||||
"\"end\"",
|
||||
"\"false\"",
|
||||
"\"for\"",
|
||||
"\"function\"",
|
||||
"\"goto\"",
|
||||
"\"if\"",
|
||||
"\"in\"",
|
||||
"\"local\"",
|
||||
"\"nil\"",
|
||||
"\"not\"",
|
||||
"\"or\"",
|
||||
"\"return\"",
|
||||
"\"repeat\"",
|
||||
"\"then\"",
|
||||
"\"true\"",
|
||||
"\"until\"",
|
||||
"\"while\"",
|
||||
"<NAME>",
|
||||
"<NUMBER>",
|
||||
"<FLOAT>",
|
||||
"<FNUM>",
|
||||
"<DIGIT>",
|
||||
"<EXP>",
|
||||
"<HEX>",
|
||||
"<HEXNUM>",
|
||||
"<HEXDIGIT>",
|
||||
"<HEXEXP>",
|
||||
"<STRING>",
|
||||
"<CHARSTRING>",
|
||||
"<QUOTED>",
|
||||
"<DECIMAL>",
|
||||
"\"::\"",
|
||||
"<UNICODE>",
|
||||
"<CHAR>",
|
||||
"<LF>",
|
||||
"\"#\"",
|
||||
"\";\"",
|
||||
"\"=\"",
|
||||
"\",\"",
|
||||
"\".\"",
|
||||
"\":\"",
|
||||
"\"(\"",
|
||||
"\")\"",
|
||||
"\"[\"",
|
||||
"\"]\"",
|
||||
"\"...\"",
|
||||
"\"{\"",
|
||||
"\"}\"",
|
||||
"\"+\"",
|
||||
"\"-\"",
|
||||
"\"*\"",
|
||||
"\"/\"",
|
||||
"\"^\"",
|
||||
"\"%\"",
|
||||
"\"..\"",
|
||||
"\"<\"",
|
||||
"\"<=\"",
|
||||
"\">\"",
|
||||
"\">=\"",
|
||||
"\"==\"",
|
||||
"\"~=\"",
|
||||
};
|
||||
|
||||
}
|
||||
2102
jse/src/main/java/org/luaj/vm2/parser/LuaParserTokenManager.java
Normal file
2102
jse/src/main/java/org/luaj/vm2/parser/LuaParserTokenManager.java
Normal file
File diff suppressed because it is too large
Load Diff
187
jse/src/main/java/org/luaj/vm2/parser/ParseException.java
Normal file
187
jse/src/main/java/org/luaj/vm2/parser/ParseException.java
Normal file
@@ -0,0 +1,187 @@
|
||||
/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 5.0 */
|
||||
/* JavaCCOptions:KEEP_LINE_COL=null */
|
||||
package org.luaj.vm2.parser;
|
||||
|
||||
/**
|
||||
* This exception is thrown when parse errors are encountered.
|
||||
* You can explicitly create objects of this exception type by
|
||||
* calling the method generateParseException in the generated
|
||||
* parser.
|
||||
*
|
||||
* You can modify this class to customize your error reporting
|
||||
* mechanisms so long as you retain the public fields.
|
||||
*/
|
||||
public class ParseException extends Exception {
|
||||
|
||||
/**
|
||||
* The version identifier for this Serializable class.
|
||||
* Increment only if the <i>serialized</i> form of the
|
||||
* class changes.
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* This constructor is used by the method "generateParseException"
|
||||
* in the generated parser. Calling this constructor generates
|
||||
* a new object of this type with the fields "currentToken",
|
||||
* "expectedTokenSequences", and "tokenImage" set.
|
||||
*/
|
||||
public ParseException(Token currentTokenVal,
|
||||
int[][] expectedTokenSequencesVal,
|
||||
String[] tokenImageVal
|
||||
)
|
||||
{
|
||||
super(initialise(currentTokenVal, expectedTokenSequencesVal, tokenImageVal));
|
||||
currentToken = currentTokenVal;
|
||||
expectedTokenSequences = expectedTokenSequencesVal;
|
||||
tokenImage = tokenImageVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* The following constructors are for use by you for whatever
|
||||
* purpose you can think of. Constructing the exception in this
|
||||
* manner makes the exception behave in the normal way - i.e., as
|
||||
* documented in the class "Throwable". The fields "errorToken",
|
||||
* "expectedTokenSequences", and "tokenImage" do not contain
|
||||
* relevant information. The JavaCC generated code does not use
|
||||
* these constructors.
|
||||
*/
|
||||
|
||||
public ParseException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/** Constructor with message. */
|
||||
public ParseException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This is the last token that has been consumed successfully. If
|
||||
* this object has been created due to a parse error, the token
|
||||
* followng this token will (therefore) be the first error token.
|
||||
*/
|
||||
public Token currentToken;
|
||||
|
||||
/**
|
||||
* Each entry in this array is an array of integers. Each array
|
||||
* of integers represents a sequence of tokens (by their ordinal
|
||||
* values) that is expected at this point of the parse.
|
||||
*/
|
||||
public int[][] expectedTokenSequences;
|
||||
|
||||
/**
|
||||
* This is a reference to the "tokenImage" array of the generated
|
||||
* parser within which the parse error occurred. This array is
|
||||
* defined in the generated ...Constants interface.
|
||||
*/
|
||||
public String[] tokenImage;
|
||||
|
||||
/**
|
||||
* It uses "currentToken" and "expectedTokenSequences" to generate a parse
|
||||
* error message and returns it. If this object has been created
|
||||
* due to a parse error, and you do not catch it (it gets thrown
|
||||
* from the parser) the correct error message
|
||||
* gets displayed.
|
||||
*/
|
||||
private static String initialise(Token currentToken,
|
||||
int[][] expectedTokenSequences,
|
||||
String[] tokenImage) {
|
||||
String eol = System.getProperty("line.separator", "\n");
|
||||
StringBuffer expected = new StringBuffer();
|
||||
int maxSize = 0;
|
||||
for (int i = 0; i < expectedTokenSequences.length; i++) {
|
||||
if (maxSize < expectedTokenSequences[i].length) {
|
||||
maxSize = expectedTokenSequences[i].length;
|
||||
}
|
||||
for (int j = 0; j < expectedTokenSequences[i].length; j++) {
|
||||
expected.append(tokenImage[expectedTokenSequences[i][j]]).append(' ');
|
||||
}
|
||||
if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) {
|
||||
expected.append("...");
|
||||
}
|
||||
expected.append(eol).append(" ");
|
||||
}
|
||||
String retval = "Encountered \"";
|
||||
Token tok = currentToken.next;
|
||||
for (int i = 0; i < maxSize; i++) {
|
||||
if (i != 0) retval += " ";
|
||||
if (tok.kind == 0) {
|
||||
retval += tokenImage[0];
|
||||
break;
|
||||
}
|
||||
retval += " " + tokenImage[tok.kind];
|
||||
retval += " \"";
|
||||
retval += add_escapes(tok.image);
|
||||
retval += " \"";
|
||||
tok = tok.next;
|
||||
}
|
||||
retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn;
|
||||
retval += "." + eol;
|
||||
if (expectedTokenSequences.length == 1) {
|
||||
retval += "Was expecting:" + eol + " ";
|
||||
} else {
|
||||
retval += "Was expecting one of:" + eol + " ";
|
||||
}
|
||||
retval += expected.toString();
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* The end of line string for this machine.
|
||||
*/
|
||||
protected String eol = System.getProperty("line.separator", "\n");
|
||||
|
||||
/**
|
||||
* Used to convert raw characters to their escaped version
|
||||
* when these raw version cannot be used as part of an ASCII
|
||||
* string literal.
|
||||
*/
|
||||
static String add_escapes(String str) {
|
||||
StringBuffer retval = new StringBuffer();
|
||||
char ch;
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
switch (str.charAt(i))
|
||||
{
|
||||
case 0 :
|
||||
continue;
|
||||
case '\b':
|
||||
retval.append("\\b");
|
||||
continue;
|
||||
case '\t':
|
||||
retval.append("\\t");
|
||||
continue;
|
||||
case '\n':
|
||||
retval.append("\\n");
|
||||
continue;
|
||||
case '\f':
|
||||
retval.append("\\f");
|
||||
continue;
|
||||
case '\r':
|
||||
retval.append("\\r");
|
||||
continue;
|
||||
case '\"':
|
||||
retval.append("\\\"");
|
||||
continue;
|
||||
case '\'':
|
||||
retval.append("\\\'");
|
||||
continue;
|
||||
case '\\':
|
||||
retval.append("\\\\");
|
||||
continue;
|
||||
default:
|
||||
if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
|
||||
String s = "0000" + Integer.toString(ch, 16);
|
||||
retval.append("\\u" + s.substring(s.length() - 4, s.length()));
|
||||
} else {
|
||||
retval.append(ch);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return retval.toString();
|
||||
}
|
||||
|
||||
}
|
||||
/* JavaCC - OriginalChecksum=ef246095a930e4915c0d4bbf4c9880ad (do not edit this line) */
|
||||
469
jse/src/main/java/org/luaj/vm2/parser/SimpleCharStream.java
Normal file
469
jse/src/main/java/org/luaj/vm2/parser/SimpleCharStream.java
Normal file
@@ -0,0 +1,469 @@
|
||||
/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 5.0 */
|
||||
/* JavaCCOptions:STATIC=false,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
|
||||
package org.luaj.vm2.parser;
|
||||
|
||||
/**
|
||||
* An implementation of interface CharStream, where the stream is assumed to
|
||||
* contain only ASCII characters (without unicode processing).
|
||||
*/
|
||||
|
||||
public class SimpleCharStream
|
||||
{
|
||||
/** Whether parser is static. */
|
||||
public static final boolean staticFlag = false;
|
||||
int bufsize;
|
||||
int available;
|
||||
int tokenBegin;
|
||||
/** Position in buffer. */
|
||||
public int bufpos = -1;
|
||||
protected int bufline[];
|
||||
protected int bufcolumn[];
|
||||
|
||||
protected int column = 0;
|
||||
protected int line = 1;
|
||||
|
||||
protected boolean prevCharIsCR = false;
|
||||
protected boolean prevCharIsLF = false;
|
||||
|
||||
protected java.io.Reader inputStream;
|
||||
|
||||
protected char[] buffer;
|
||||
protected int maxNextCharInd = 0;
|
||||
protected int inBuf = 0;
|
||||
protected int tabSize = 1;
|
||||
|
||||
public void setTabSize(int i) { tabSize = i; }
|
||||
public int getTabSize(int i) { return tabSize; }
|
||||
|
||||
|
||||
protected void ExpandBuff(boolean wrapAround)
|
||||
{
|
||||
char[] newbuffer = new char[bufsize + 2048];
|
||||
int newbufline[] = new int[bufsize + 2048];
|
||||
int newbufcolumn[] = new int[bufsize + 2048];
|
||||
|
||||
try
|
||||
{
|
||||
if (wrapAround)
|
||||
{
|
||||
System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
|
||||
System.arraycopy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos);
|
||||
buffer = newbuffer;
|
||||
|
||||
System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
|
||||
System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
|
||||
bufline = newbufline;
|
||||
|
||||
System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
|
||||
System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos);
|
||||
bufcolumn = newbufcolumn;
|
||||
|
||||
maxNextCharInd = (bufpos += (bufsize - tokenBegin));
|
||||
}
|
||||
else
|
||||
{
|
||||
System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
|
||||
buffer = newbuffer;
|
||||
|
||||
System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
|
||||
bufline = newbufline;
|
||||
|
||||
System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
|
||||
bufcolumn = newbufcolumn;
|
||||
|
||||
maxNextCharInd = (bufpos -= tokenBegin);
|
||||
}
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
throw new Error(t.getMessage());
|
||||
}
|
||||
|
||||
|
||||
bufsize += 2048;
|
||||
available = bufsize;
|
||||
tokenBegin = 0;
|
||||
}
|
||||
|
||||
protected void FillBuff() throws java.io.IOException
|
||||
{
|
||||
if (maxNextCharInd == available)
|
||||
{
|
||||
if (available == bufsize)
|
||||
{
|
||||
if (tokenBegin > 2048)
|
||||
{
|
||||
bufpos = maxNextCharInd = 0;
|
||||
available = tokenBegin;
|
||||
}
|
||||
else if (tokenBegin < 0)
|
||||
bufpos = maxNextCharInd = 0;
|
||||
else
|
||||
ExpandBuff(false);
|
||||
}
|
||||
else if (available > tokenBegin)
|
||||
available = bufsize;
|
||||
else if ((tokenBegin - available) < 2048)
|
||||
ExpandBuff(true);
|
||||
else
|
||||
available = tokenBegin;
|
||||
}
|
||||
|
||||
int i;
|
||||
try {
|
||||
if ((i = inputStream.read(buffer, maxNextCharInd, available - maxNextCharInd)) == -1)
|
||||
{
|
||||
inputStream.close();
|
||||
throw new java.io.IOException();
|
||||
}
|
||||
else
|
||||
maxNextCharInd += i;
|
||||
return;
|
||||
}
|
||||
catch(java.io.IOException e) {
|
||||
--bufpos;
|
||||
backup(0);
|
||||
if (tokenBegin == -1)
|
||||
tokenBegin = bufpos;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/** Start. */
|
||||
public char BeginToken() throws java.io.IOException
|
||||
{
|
||||
tokenBegin = -1;
|
||||
char c = readChar();
|
||||
tokenBegin = bufpos;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
protected void UpdateLineColumn(char c)
|
||||
{
|
||||
column++;
|
||||
|
||||
if (prevCharIsLF)
|
||||
{
|
||||
prevCharIsLF = false;
|
||||
line += (column = 1);
|
||||
}
|
||||
else if (prevCharIsCR)
|
||||
{
|
||||
prevCharIsCR = false;
|
||||
if (c == '\n')
|
||||
{
|
||||
prevCharIsLF = true;
|
||||
}
|
||||
else
|
||||
line += (column = 1);
|
||||
}
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '\r' :
|
||||
prevCharIsCR = true;
|
||||
break;
|
||||
case '\n' :
|
||||
prevCharIsLF = true;
|
||||
break;
|
||||
case '\t' :
|
||||
column--;
|
||||
column += (tabSize - (column % tabSize));
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
|
||||
bufline[bufpos] = line;
|
||||
bufcolumn[bufpos] = column;
|
||||
}
|
||||
|
||||
/** Read a character. */
|
||||
public char readChar() throws java.io.IOException
|
||||
{
|
||||
if (inBuf > 0)
|
||||
{
|
||||
--inBuf;
|
||||
|
||||
if (++bufpos == bufsize)
|
||||
bufpos = 0;
|
||||
|
||||
return buffer[bufpos];
|
||||
}
|
||||
|
||||
if (++bufpos >= maxNextCharInd)
|
||||
FillBuff();
|
||||
|
||||
char c = buffer[bufpos];
|
||||
|
||||
UpdateLineColumn(c);
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @see #getEndColumn
|
||||
*/
|
||||
|
||||
public int getColumn() {
|
||||
return bufcolumn[bufpos];
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @see #getEndLine
|
||||
*/
|
||||
|
||||
public int getLine() {
|
||||
return bufline[bufpos];
|
||||
}
|
||||
|
||||
/** Get token end column number. */
|
||||
public int getEndColumn() {
|
||||
return bufcolumn[bufpos];
|
||||
}
|
||||
|
||||
/** Get token end line number. */
|
||||
public int getEndLine() {
|
||||
return bufline[bufpos];
|
||||
}
|
||||
|
||||
/** Get token beginning column number. */
|
||||
public int getBeginColumn() {
|
||||
return bufcolumn[tokenBegin];
|
||||
}
|
||||
|
||||
/** Get token beginning line number. */
|
||||
public int getBeginLine() {
|
||||
return bufline[tokenBegin];
|
||||
}
|
||||
|
||||
/** Backup a number of characters. */
|
||||
public void backup(int amount) {
|
||||
|
||||
inBuf += amount;
|
||||
if ((bufpos -= amount) < 0)
|
||||
bufpos += bufsize;
|
||||
}
|
||||
|
||||
/** Constructor. */
|
||||
public SimpleCharStream(java.io.Reader dstream, int startline,
|
||||
int startcolumn, int buffersize)
|
||||
{
|
||||
inputStream = dstream;
|
||||
line = startline;
|
||||
column = startcolumn - 1;
|
||||
|
||||
available = bufsize = buffersize;
|
||||
buffer = new char[buffersize];
|
||||
bufline = new int[buffersize];
|
||||
bufcolumn = new int[buffersize];
|
||||
}
|
||||
|
||||
/** Constructor. */
|
||||
public SimpleCharStream(java.io.Reader dstream, int startline,
|
||||
int startcolumn)
|
||||
{
|
||||
this(dstream, startline, startcolumn, 4096);
|
||||
}
|
||||
|
||||
/** Constructor. */
|
||||
public SimpleCharStream(java.io.Reader dstream)
|
||||
{
|
||||
this(dstream, 1, 1, 4096);
|
||||
}
|
||||
|
||||
/** Reinitialise. */
|
||||
public void ReInit(java.io.Reader dstream, int startline,
|
||||
int startcolumn, int buffersize)
|
||||
{
|
||||
inputStream = dstream;
|
||||
line = startline;
|
||||
column = startcolumn - 1;
|
||||
|
||||
if (buffer == null || buffersize != buffer.length)
|
||||
{
|
||||
available = bufsize = buffersize;
|
||||
buffer = new char[buffersize];
|
||||
bufline = new int[buffersize];
|
||||
bufcolumn = new int[buffersize];
|
||||
}
|
||||
prevCharIsLF = prevCharIsCR = false;
|
||||
tokenBegin = inBuf = maxNextCharInd = 0;
|
||||
bufpos = -1;
|
||||
}
|
||||
|
||||
/** Reinitialise. */
|
||||
public void ReInit(java.io.Reader dstream, int startline,
|
||||
int startcolumn)
|
||||
{
|
||||
ReInit(dstream, startline, startcolumn, 4096);
|
||||
}
|
||||
|
||||
/** Reinitialise. */
|
||||
public void ReInit(java.io.Reader dstream)
|
||||
{
|
||||
ReInit(dstream, 1, 1, 4096);
|
||||
}
|
||||
/** Constructor. */
|
||||
public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
|
||||
int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
|
||||
{
|
||||
this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
|
||||
}
|
||||
|
||||
/** Constructor. */
|
||||
public SimpleCharStream(java.io.InputStream dstream, int startline,
|
||||
int startcolumn, int buffersize)
|
||||
{
|
||||
this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
|
||||
}
|
||||
|
||||
/** Constructor. */
|
||||
public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
|
||||
int startcolumn) throws java.io.UnsupportedEncodingException
|
||||
{
|
||||
this(dstream, encoding, startline, startcolumn, 4096);
|
||||
}
|
||||
|
||||
/** Constructor. */
|
||||
public SimpleCharStream(java.io.InputStream dstream, int startline,
|
||||
int startcolumn)
|
||||
{
|
||||
this(dstream, startline, startcolumn, 4096);
|
||||
}
|
||||
|
||||
/** Constructor. */
|
||||
public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
|
||||
{
|
||||
this(dstream, encoding, 1, 1, 4096);
|
||||
}
|
||||
|
||||
/** Constructor. */
|
||||
public SimpleCharStream(java.io.InputStream dstream)
|
||||
{
|
||||
this(dstream, 1, 1, 4096);
|
||||
}
|
||||
|
||||
/** Reinitialise. */
|
||||
public void ReInit(java.io.InputStream dstream, String encoding, int startline,
|
||||
int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
|
||||
{
|
||||
ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
|
||||
}
|
||||
|
||||
/** Reinitialise. */
|
||||
public void ReInit(java.io.InputStream dstream, int startline,
|
||||
int startcolumn, int buffersize)
|
||||
{
|
||||
ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
|
||||
}
|
||||
|
||||
/** Reinitialise. */
|
||||
public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
|
||||
{
|
||||
ReInit(dstream, encoding, 1, 1, 4096);
|
||||
}
|
||||
|
||||
/** Reinitialise. */
|
||||
public void ReInit(java.io.InputStream dstream)
|
||||
{
|
||||
ReInit(dstream, 1, 1, 4096);
|
||||
}
|
||||
/** Reinitialise. */
|
||||
public void ReInit(java.io.InputStream dstream, String encoding, int startline,
|
||||
int startcolumn) throws java.io.UnsupportedEncodingException
|
||||
{
|
||||
ReInit(dstream, encoding, startline, startcolumn, 4096);
|
||||
}
|
||||
/** Reinitialise. */
|
||||
public void ReInit(java.io.InputStream dstream, int startline,
|
||||
int startcolumn)
|
||||
{
|
||||
ReInit(dstream, startline, startcolumn, 4096);
|
||||
}
|
||||
/** Get token literal value. */
|
||||
public String GetImage()
|
||||
{
|
||||
if (bufpos >= tokenBegin)
|
||||
return new String(buffer, tokenBegin, bufpos - tokenBegin + 1);
|
||||
else
|
||||
return new String(buffer, tokenBegin, bufsize - tokenBegin) +
|
||||
new String(buffer, 0, bufpos + 1);
|
||||
}
|
||||
|
||||
/** Get the suffix. */
|
||||
public char[] GetSuffix(int len)
|
||||
{
|
||||
char[] ret = new char[len];
|
||||
|
||||
if ((bufpos + 1) >= len)
|
||||
System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
|
||||
else
|
||||
{
|
||||
System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0,
|
||||
len - bufpos - 1);
|
||||
System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Reset buffer when finished. */
|
||||
public void Done()
|
||||
{
|
||||
buffer = null;
|
||||
bufline = null;
|
||||
bufcolumn = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to adjust line and column numbers for the start of a token.
|
||||
*/
|
||||
public void adjustBeginLineColumn(int newLine, int newCol)
|
||||
{
|
||||
int start = tokenBegin;
|
||||
int len;
|
||||
|
||||
if (bufpos >= tokenBegin)
|
||||
{
|
||||
len = bufpos - tokenBegin + inBuf + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
len = bufsize - tokenBegin + bufpos + 1 + inBuf;
|
||||
}
|
||||
|
||||
int i = 0, j = 0, k = 0;
|
||||
int nextColDiff = 0, columnDiff = 0;
|
||||
|
||||
while (i < len && bufline[j = start % bufsize] == bufline[k = ++start % bufsize])
|
||||
{
|
||||
bufline[j] = newLine;
|
||||
nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
|
||||
bufcolumn[j] = newCol + columnDiff;
|
||||
columnDiff = nextColDiff;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i < len)
|
||||
{
|
||||
bufline[j] = newLine++;
|
||||
bufcolumn[j] = newCol + columnDiff;
|
||||
|
||||
while (i++ < len)
|
||||
{
|
||||
if (bufline[j = start % bufsize] != bufline[++start % bufsize])
|
||||
bufline[j] = newLine++;
|
||||
else
|
||||
bufline[j] = newLine;
|
||||
}
|
||||
}
|
||||
|
||||
line = bufline[j];
|
||||
column = bufcolumn[j];
|
||||
}
|
||||
|
||||
}
|
||||
/* JavaCC - OriginalChecksum=ab0c629eabd887d4c88cec51eb5e6477 (do not edit this line) */
|
||||
131
jse/src/main/java/org/luaj/vm2/parser/Token.java
Normal file
131
jse/src/main/java/org/luaj/vm2/parser/Token.java
Normal file
@@ -0,0 +1,131 @@
|
||||
/* Generated By:JavaCC: Do not edit this line. Token.java Version 5.0 */
|
||||
/* JavaCCOptions:TOKEN_EXTENDS=,KEEP_LINE_COL=null,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
|
||||
package org.luaj.vm2.parser;
|
||||
|
||||
/**
|
||||
* Describes the input token stream.
|
||||
*/
|
||||
|
||||
public class Token implements java.io.Serializable {
|
||||
|
||||
/**
|
||||
* The version identifier for this Serializable class.
|
||||
* Increment only if the <i>serialized</i> form of the
|
||||
* class changes.
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* An integer that describes the kind of this token. This numbering
|
||||
* system is determined by JavaCCParser, and a table of these numbers is
|
||||
* stored in the file ...Constants.java.
|
||||
*/
|
||||
public int kind;
|
||||
|
||||
/** The line number of the first character of this Token. */
|
||||
public int beginLine;
|
||||
/** The column number of the first character of this Token. */
|
||||
public int beginColumn;
|
||||
/** The line number of the last character of this Token. */
|
||||
public int endLine;
|
||||
/** The column number of the last character of this Token. */
|
||||
public int endColumn;
|
||||
|
||||
/**
|
||||
* The string image of the token.
|
||||
*/
|
||||
public String image;
|
||||
|
||||
/**
|
||||
* A reference to the next regular (non-special) token from the input
|
||||
* stream. If this is the last token from the input stream, or if the
|
||||
* token manager has not read tokens beyond this one, this field is
|
||||
* set to null. This is true only if this token is also a regular
|
||||
* token. Otherwise, see below for a description of the contents of
|
||||
* this field.
|
||||
*/
|
||||
public Token next;
|
||||
|
||||
/**
|
||||
* This field is used to access special tokens that occur prior to this
|
||||
* token, but after the immediately preceding regular (non-special) token.
|
||||
* If there are no such special tokens, this field is set to null.
|
||||
* When there are more than one such special token, this field refers
|
||||
* to the last of these special tokens, which in turn refers to the next
|
||||
* previous special token through its specialToken field, and so on
|
||||
* until the first special token (whose specialToken field is null).
|
||||
* The next fields of special tokens refer to other special tokens that
|
||||
* immediately follow it (without an intervening regular token). If there
|
||||
* is no such token, this field is null.
|
||||
*/
|
||||
public Token specialToken;
|
||||
|
||||
/**
|
||||
* An optional attribute value of the Token.
|
||||
* Tokens which are not used as syntactic sugar will often contain
|
||||
* meaningful values that will be used later on by the compiler or
|
||||
* interpreter. This attribute value is often different from the image.
|
||||
* Any subclass of Token that actually wants to return a non-null value can
|
||||
* override this method as appropriate.
|
||||
*/
|
||||
public Object getValue() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* No-argument constructor
|
||||
*/
|
||||
public Token() {}
|
||||
|
||||
/**
|
||||
* Constructs a new token for the specified Image.
|
||||
*/
|
||||
public Token(int kind)
|
||||
{
|
||||
this(kind, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new token for the specified Image and Kind.
|
||||
*/
|
||||
public Token(int kind, String image)
|
||||
{
|
||||
this.kind = kind;
|
||||
this.image = image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the image.
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new Token object, by default. However, if you want, you
|
||||
* can create and return subclass objects based on the value of ofKind.
|
||||
* Simply add the cases to the switch for all those special cases.
|
||||
* For example, if you have a subclass of Token called IDToken that
|
||||
* you want to create if ofKind is ID, simply add something like :
|
||||
*
|
||||
* case MyParserConstants.ID : return new IDToken(ofKind, image);
|
||||
*
|
||||
* to the following switch statement. Then you can cast matchedToken
|
||||
* variable to the appropriate type and use sit in your lexical actions.
|
||||
*/
|
||||
public static Token newToken(int ofKind, String image)
|
||||
{
|
||||
switch(ofKind)
|
||||
{
|
||||
default : return new Token(ofKind, image);
|
||||
}
|
||||
}
|
||||
|
||||
public static Token newToken(int ofKind)
|
||||
{
|
||||
return newToken(ofKind, null);
|
||||
}
|
||||
|
||||
}
|
||||
/* JavaCC - OriginalChecksum=70d73add5771158f10d1ae81755e7cfc (do not edit this line) */
|
||||
147
jse/src/main/java/org/luaj/vm2/parser/TokenMgrError.java
Normal file
147
jse/src/main/java/org/luaj/vm2/parser/TokenMgrError.java
Normal file
@@ -0,0 +1,147 @@
|
||||
/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 5.0 */
|
||||
/* JavaCCOptions: */
|
||||
package org.luaj.vm2.parser;
|
||||
|
||||
/** Token Manager Error. */
|
||||
public class TokenMgrError extends Error
|
||||
{
|
||||
|
||||
/**
|
||||
* The version identifier for this Serializable class.
|
||||
* Increment only if the <i>serialized</i> form of the
|
||||
* class changes.
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/*
|
||||
* Ordinals for various reasons why an Error of this type can be thrown.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Lexical error occurred.
|
||||
*/
|
||||
static final int LEXICAL_ERROR = 0;
|
||||
|
||||
/**
|
||||
* An attempt was made to create a second instance of a static token manager.
|
||||
*/
|
||||
static final int STATIC_LEXER_ERROR = 1;
|
||||
|
||||
/**
|
||||
* Tried to change to an invalid lexical state.
|
||||
*/
|
||||
static final int INVALID_LEXICAL_STATE = 2;
|
||||
|
||||
/**
|
||||
* Detected (and bailed out of) an infinite loop in the token manager.
|
||||
*/
|
||||
static final int LOOP_DETECTED = 3;
|
||||
|
||||
/**
|
||||
* Indicates the reason why the exception is thrown. It will have
|
||||
* one of the above 4 values.
|
||||
*/
|
||||
int errorCode;
|
||||
|
||||
/**
|
||||
* Replaces unprintable characters by their escaped (or unicode escaped)
|
||||
* equivalents in the given string
|
||||
*/
|
||||
protected static final String addEscapes(String str) {
|
||||
StringBuffer retval = new StringBuffer();
|
||||
char ch;
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
switch (str.charAt(i))
|
||||
{
|
||||
case 0 :
|
||||
continue;
|
||||
case '\b':
|
||||
retval.append("\\b");
|
||||
continue;
|
||||
case '\t':
|
||||
retval.append("\\t");
|
||||
continue;
|
||||
case '\n':
|
||||
retval.append("\\n");
|
||||
continue;
|
||||
case '\f':
|
||||
retval.append("\\f");
|
||||
continue;
|
||||
case '\r':
|
||||
retval.append("\\r");
|
||||
continue;
|
||||
case '\"':
|
||||
retval.append("\\\"");
|
||||
continue;
|
||||
case '\'':
|
||||
retval.append("\\\'");
|
||||
continue;
|
||||
case '\\':
|
||||
retval.append("\\\\");
|
||||
continue;
|
||||
default:
|
||||
if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
|
||||
String s = "0000" + Integer.toString(ch, 16);
|
||||
retval.append("\\u" + s.substring(s.length() - 4, s.length()));
|
||||
} else {
|
||||
retval.append(ch);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return retval.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a detailed message for the Error when it is thrown by the
|
||||
* token manager to indicate a lexical error.
|
||||
* Parameters :
|
||||
* EOFSeen : indicates if EOF caused the lexical error
|
||||
* curLexState : lexical state in which this error occurred
|
||||
* errorLine : line number when the error occurred
|
||||
* errorColumn : column number when the error occurred
|
||||
* errorAfter : prefix that was seen before this error occurred
|
||||
* curchar : the offending character
|
||||
* Note: You can customize the lexical error message by modifying this method.
|
||||
*/
|
||||
protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) {
|
||||
return("Lexical error at line " +
|
||||
errorLine + ", column " +
|
||||
errorColumn + ". Encountered: " +
|
||||
(EOFSeen ? "<EOF> " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") +
|
||||
"after : \"" + addEscapes(errorAfter) + "\"");
|
||||
}
|
||||
|
||||
/**
|
||||
* You can also modify the body of this method to customize your error messages.
|
||||
* For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not
|
||||
* of end-users concern, so you can return something like :
|
||||
*
|
||||
* "Internal Error : Please file a bug report .... "
|
||||
*
|
||||
* from this method for such cases in the release version of your parser.
|
||||
*/
|
||||
public String getMessage() {
|
||||
return super.getMessage();
|
||||
}
|
||||
|
||||
/*
|
||||
* Constructors of various flavors follow.
|
||||
*/
|
||||
|
||||
/** No arg constructor. */
|
||||
public TokenMgrError() {
|
||||
}
|
||||
|
||||
/** Constructor with message and reason. */
|
||||
public TokenMgrError(String message, int reason) {
|
||||
super(message);
|
||||
errorCode = reason;
|
||||
}
|
||||
|
||||
/** Full Constructor. */
|
||||
public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) {
|
||||
this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason);
|
||||
}
|
||||
}
|
||||
/* JavaCC - OriginalChecksum=bd3720425dc7b44a5223b12676db358c (do not edit this line) */
|
||||
266
jse/src/main/java/org/luaj/vm2/script/LuaScriptEngine.java
Normal file
266
jse/src/main/java/org/luaj/vm2/script/LuaScriptEngine.java
Normal file
@@ -0,0 +1,266 @@
|
||||
/*******************************************************************************
|
||||
* 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.*;
|
||||
|
||||
import javax.script.*;
|
||||
|
||||
import org.luaj.vm2.*;
|
||||
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 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 {
|
||||
InputStream is = new Utf8Encoder(script);
|
||||
try {
|
||||
final Globals g = context.globals;
|
||||
final LuaFunction f = g.load(script, "script").checkfunction();
|
||||
return new LuajCompiledScript(f, g);
|
||||
} catch ( LuaError lee ) {
|
||||
throw new ScriptException(lee.getMessage() );
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
throw new ScriptException("eval threw "+e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
public ScriptEngine getEngine() {
|
||||
return LuaScriptEngine.this;
|
||||
}
|
||||
|
||||
public Object eval() throws ScriptException {
|
||||
return eval(getContext());
|
||||
}
|
||||
|
||||
public Object eval(Bindings bindings) throws ScriptException {
|
||||
return eval(((LuajContext) getContext()).globals, bindings);
|
||||
}
|
||||
|
||||
public Object eval(ScriptContext context) throws ScriptException {
|
||||
return eval(((LuajContext) context).globals, context.getBindings(ScriptContext.ENGINE_SCOPE));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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() {
|
||||
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() {
|
||||
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()?
|
||||
luajValue.toint():
|
||||
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,128 @@
|
||||
/*******************************************************************************
|
||||
* 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 List<String> extensions;
|
||||
private List<String> mimeTypes;
|
||||
private List<String> names;
|
||||
|
||||
public LuaScriptEngineFactory() {
|
||||
extensions = Arrays.asList(EXTENSIONS);
|
||||
mimeTypes = Arrays.asList(MIMETYPES);
|
||||
names = Arrays.asList(NAMES);
|
||||
}
|
||||
|
||||
public String getEngineName() {
|
||||
return getScriptEngine().get(ScriptEngine.ENGINE).toString();
|
||||
}
|
||||
|
||||
public String getEngineVersion() {
|
||||
return getScriptEngine().get(ScriptEngine.ENGINE_VERSION).toString();
|
||||
}
|
||||
|
||||
public List<String> getExtensions() {
|
||||
return extensions;
|
||||
}
|
||||
|
||||
public List<String> getMimeTypes() {
|
||||
return mimeTypes;
|
||||
}
|
||||
|
||||
public List<String> getNames() {
|
||||
return names;
|
||||
}
|
||||
|
||||
public String getLanguageName() {
|
||||
return getScriptEngine().get(ScriptEngine.LANGUAGE).toString();
|
||||
}
|
||||
|
||||
public String getLanguageVersion() {
|
||||
return getScriptEngine().get(ScriptEngine.LANGUAGE_VERSION).toString();
|
||||
}
|
||||
|
||||
public Object getParameter(String key) {
|
||||
return getScriptEngine().get(key).toString();
|
||||
}
|
||||
|
||||
public String getMethodCallSyntax(String obj, String m, String... args) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(obj + ":" + m + "(");
|
||||
int len = args.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(',');
|
||||
}
|
||||
sb.append(args[i]);
|
||||
}
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getOutputStatement(String toDisplay) {
|
||||
return "print(" + toDisplay + ")";
|
||||
}
|
||||
|
||||
public String getProgram(String ... statements) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
int len = statements.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (i > 0) {
|
||||
sb.append('\n');
|
||||
}
|
||||
sb.append(statements[i]);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public ScriptEngine getScriptEngine() {
|
||||
return new LuaScriptEngine();
|
||||
}
|
||||
}
|
||||
144
jse/src/main/java/org/luaj/vm2/script/LuajContext.java
Normal file
144
jse/src/main/java/org/luaj/vm2/script/LuajContext.java
Normal file
@@ -0,0 +1,144 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
}
|
||||
public void write(int b) throws IOException {
|
||||
w.write(new String(new byte[] {(byte)b}));
|
||||
}
|
||||
public void write(byte[] b, int o, int l) throws IOException {
|
||||
w.write(new String(b, o, l));
|
||||
}
|
||||
public void write(byte[] b) throws IOException {
|
||||
w.write(new String(b));
|
||||
}
|
||||
public void close() throws IOException {
|
||||
w.close();
|
||||
}
|
||||
public void flush() throws IOException {
|
||||
w.flush();
|
||||
}
|
||||
}
|
||||
|
||||
static final class ReaderInputStream extends InputStream {
|
||||
final Reader r;
|
||||
ReaderInputStream(Reader r) {
|
||||
this.r = r;
|
||||
}
|
||||
public int read() throws IOException {
|
||||
return r.read();
|
||||
}
|
||||
}
|
||||
}
|
||||
105
jse/src/main/java/org/luaj/vm2/server/DefaultLauncher.java
Normal file
105
jse/src/main/java/org/luaj/vm2/server/DefaultLauncher.java
Normal file
@@ -0,0 +1,105 @@
|
||||
/*******************************************************************************
|
||||
* 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' */
|
||||
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' */
|
||||
public Object[] launch(InputStream script, Object[] arg) {
|
||||
return launchChunk(g.load(script, "main", "bt", g), arg);
|
||||
}
|
||||
|
||||
/** Launches the script with chunk name 'main' */
|
||||
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;
|
||||
}
|
||||
}
|
||||
70
jse/src/main/java/org/luaj/vm2/server/Launcher.java
Normal file
70
jse/src/main/java/org/luaj/vm2/server/Launcher.java
Normal file
@@ -0,0 +1,70 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
*/
|
||||
public 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.
|
||||
*/
|
||||
public 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.
|
||||
*/
|
||||
public Object[] launch(Reader script, Object[] arg);
|
||||
}
|
||||
157
jse/src/main/java/org/luaj/vm2/server/LuajClassLoader.java
Normal file
157
jse/src/main/java/org/luaj/vm2/server/LuajClassLoader.java
Normal file
@@ -0,0 +1,157 @@
|
||||
/*******************************************************************************
|
||||
* 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<String, Class<?>>();
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
org.luaj.vm2.script.LuaScriptEngineFactory
|
||||
61
jse/src/test/java/org/luaj/luajc/SampleMainChunk.java
Normal file
61
jse/src/test/java/org/luaj/luajc/SampleMainChunk.java
Normal file
@@ -0,0 +1,61 @@
|
||||
package org.luaj.luajc;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.lib.TwoArgFunction;
|
||||
import org.luaj.vm2.lib.VarArgFunction;
|
||||
|
||||
public class SampleMainChunk extends VarArgFunction {
|
||||
|
||||
static final LuaValue $print = valueOf("print");
|
||||
static final LuaValue $foo = valueOf("foo");
|
||||
|
||||
LuaValue[] rw_ENV; // The environment when it is read-write
|
||||
// LuaValue ro_ENV; // The environment when it is read-only in all sub-functions
|
||||
|
||||
LuaValue[] rw_openup1; // upvalue that we create and modify in "slot" 1, passed to sub-function in initer.
|
||||
LuaValue[] rw_openup2; // array is instantiated on first set or before supply to closure, after that value is get, set.
|
||||
LuaValue[] rw_openup3; // closing these nulls them out, sub-functions still retain references to array & can use
|
||||
LuaValue ro_openup4; // open upvalue that is read-only once it is supplied to an inner function.
|
||||
LuaValue ro_openup5; // closing this also nulls it out.
|
||||
|
||||
// Must have this in the main chunk so it can be loaded and instantiated on all platforms.
|
||||
public SampleMainChunk() {
|
||||
}
|
||||
|
||||
public void initupvalue1(LuaValue[] v) {
|
||||
this.rw_ENV = v;
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs args) {
|
||||
rw_ENV[0].get($print).call($foo);
|
||||
|
||||
rw_ENV[0].set($print, new InnerFunction(rw_openup3, rw_openup1, ro_openup5));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static class InnerFunction extends TwoArgFunction {
|
||||
static final LuaValue $print = valueOf("print"); // A constant, named for what it is.
|
||||
static final LuaValue $foo = valueOf("foo");
|
||||
|
||||
final LuaValue[] rw_upvalue1; // from enclosing function, corresponds to upvaldesc not instack.
|
||||
final LuaValue[] rw_upvalue2; // from enclosing function, corresponds to upvaldesc not instack.
|
||||
final LuaValue ro_upvalue3; // from enclosing function, but read-only everywhere.
|
||||
|
||||
LuaValue[] rw_openup1; // closing these nulls them out, sub-functions still retain references to array & can use
|
||||
LuaValue ro_openup2; // open upvalue that is read-only once it is supplied to an inner function.
|
||||
|
||||
InnerFunction(LuaValue[] rw_upvalue1, LuaValue[] rw_upvalue2, LuaValue ro_upvalue3) {
|
||||
this.rw_upvalue1 = rw_upvalue1;
|
||||
this.rw_upvalue2 = rw_upvalue2;
|
||||
this.ro_upvalue3 = ro_upvalue3;
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return NIL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
70
jse/src/test/java/org/luaj/luajc/TestLuaJ.java
Normal file
70
jse/src/test/java/org/luaj/luajc/TestLuaJ.java
Normal file
@@ -0,0 +1,70 @@
|
||||
/*******************************************************************************
|
||||
* 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.luajc;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Print;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.lib.jse.JsePlatform;
|
||||
|
||||
/** Test the plain old bytecode interpreter */
|
||||
public class TestLuaJ {
|
||||
// create the script
|
||||
public static String name = "script";
|
||||
public static String script =
|
||||
"function r(q,...)\n"+
|
||||
" local a=arg\n"+
|
||||
" return a and a[2]\n"+
|
||||
"end\n" +
|
||||
"function s(q,...)\n"+
|
||||
" local a=arg\n"+
|
||||
" local b=...\n"+
|
||||
" return a and a[2],b\n"+
|
||||
"end\n" +
|
||||
"print( r(111,222,333),s(111,222,333) )";
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println(script);
|
||||
|
||||
// create an environment to run in
|
||||
Globals globals = JsePlatform.standardGlobals();
|
||||
|
||||
// compile into a chunk, or load as a class
|
||||
LuaValue chunk = globals.load(script, "script");
|
||||
|
||||
// The loaded chunk should be a closure, which contains the prototype.
|
||||
print( chunk.checkclosure().p );
|
||||
|
||||
// The chunk can be called with arguments as desired.
|
||||
chunk.call(LuaValue.ZERO, LuaValue.ONE);
|
||||
}
|
||||
|
||||
private static void print(Prototype p) {
|
||||
System.out.println("--- "+p);
|
||||
Print.printCode(p);
|
||||
if (p.p!=null)
|
||||
for ( int i=0,n=p.p.length; i<n; i++ )
|
||||
print( p.p[i] );
|
||||
}
|
||||
|
||||
}
|
||||
102
jse/src/test/java/org/luaj/luajc/TestLuaJC.java
Normal file
102
jse/src/test/java/org/luaj/luajc/TestLuaJC.java
Normal file
@@ -0,0 +1,102 @@
|
||||
/*******************************************************************************
|
||||
* 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.luajc;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
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;
|
||||
|
||||
public class TestLuaJC {
|
||||
// This file will be loaded using the finder as a resource, provided it is in the
|
||||
// build path. This allows the debugger to find the file when stepping into the function.
|
||||
public static String filename = "perf/nsieve.lua";
|
||||
|
||||
static Globals globals;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (args.length > 0)
|
||||
filename = args[0];
|
||||
System.out.println("filename: "+filename);
|
||||
try {
|
||||
|
||||
// create an environment to run in
|
||||
globals = JsePlatform.standardGlobals();
|
||||
|
||||
// print the chunk as a closure, and pretty-print the closure.
|
||||
LuaValue f = globals.loadfile(filename).arg1();
|
||||
Prototype p = f.checkclosure().p;
|
||||
Print.print(p);
|
||||
|
||||
// load into a luajc java-bytecode based chunk by installing the LuaJC compiler first
|
||||
if ( ! (args.length>0 && args[0].equals("nocompile")) ) {
|
||||
LuaJC.install(globals);
|
||||
f = globals.loadfile(filename).arg1();
|
||||
}
|
||||
|
||||
// call with arguments
|
||||
Varargs v = f.invoke(LuaValue.NONE);
|
||||
|
||||
// print the result
|
||||
System.out.println("result: "+v);
|
||||
|
||||
// Write out the files.
|
||||
// saveClasses();
|
||||
|
||||
} catch ( Throwable e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void saveClasses() throws Exception {
|
||||
// create the chunk
|
||||
String destdir = ".";
|
||||
|
||||
InputStream is = globals.finder.findResource(filename);
|
||||
Hashtable t = LuaJC.instance.compileAll(is, filename, filename, globals, true);
|
||||
|
||||
// write out the chunk
|
||||
for ( Enumeration e = t.keys(); e.hasMoreElements(); ) {
|
||||
String key = (String) e.nextElement();
|
||||
byte[] bytes = (byte[]) t.get(key);
|
||||
String destpath = (destdir!=null? destdir+"/": "") + key + ".class";
|
||||
System.out.println(
|
||||
"chunk "+filename+
|
||||
" from "+filename+
|
||||
" written to "+destpath
|
||||
+" length="+bytes.length+" bytes");
|
||||
FileOutputStream fos = new FileOutputStream( destpath );
|
||||
fos.write( bytes );
|
||||
fos.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
109
jse/src/test/java/org/luaj/vm2/AllTests.java
Normal file
109
jse/src/test/java/org/luaj/vm2/AllTests.java
Normal file
@@ -0,0 +1,109 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import org.luaj.vm2.WeakTableTest.WeakKeyTableTest;
|
||||
import org.luaj.vm2.WeakTableTest.WeakKeyValueTableTest;
|
||||
import org.luaj.vm2.WeakTableTest.WeakValueTableTest;
|
||||
import org.luaj.vm2.compiler.CompilerUnitTests;
|
||||
import org.luaj.vm2.compiler.DumpLoadEndianIntTest;
|
||||
import org.luaj.vm2.compiler.LuaParserTests;
|
||||
import org.luaj.vm2.compiler.RegressionTests;
|
||||
import org.luaj.vm2.compiler.SimpleTests;
|
||||
import org.luaj.vm2.lib.jse.JsePlatformTest;
|
||||
import org.luaj.vm2.lib.jse.LuaJavaCoercionTest;
|
||||
import org.luaj.vm2.lib.jse.LuajavaAccessibleMembersTest;
|
||||
import org.luaj.vm2.lib.jse.LuajavaClassMembersTest;
|
||||
import org.luaj.vm2.lib.jse.OsLibTest;
|
||||
import org.luaj.vm2.script.ScriptEngineTests;
|
||||
|
||||
public class AllTests {
|
||||
|
||||
public static Test suite() {
|
||||
TestSuite suite = new TestSuite("All Tests for Luaj-vm2");
|
||||
|
||||
// vm tests
|
||||
TestSuite vm = new TestSuite("VM Tests");
|
||||
vm.addTestSuite(TypeTest.class);
|
||||
vm.addTestSuite(UnaryBinaryOperatorsTest.class);
|
||||
vm.addTestSuite(MetatableTest.class);
|
||||
vm.addTestSuite(LuaOperationsTest.class);
|
||||
vm.addTestSuite(StringTest.class);
|
||||
vm.addTestSuite(OrphanedThreadTest.class);
|
||||
vm.addTestSuite(VarargsTest.class);
|
||||
vm.addTestSuite(LoadOrderTest.class);
|
||||
suite.addTest(vm);
|
||||
|
||||
// table tests
|
||||
TestSuite table = new TestSuite("Table Tests");
|
||||
table.addTestSuite(TableTest.class);
|
||||
table.addTestSuite(TableHashTest.class);
|
||||
table.addTestSuite(WeakValueTableTest.class);
|
||||
table.addTestSuite(WeakKeyTableTest.class);
|
||||
table.addTestSuite(WeakKeyValueTableTest.class);
|
||||
suite.addTest(table);
|
||||
|
||||
// bytecode compilers regression tests
|
||||
TestSuite bytecodetests = FragmentsTest.suite();
|
||||
suite.addTest(bytecodetests);
|
||||
|
||||
// I/O tests
|
||||
TestSuite io = new TestSuite("I/O Tests");
|
||||
io.addTestSuite(BufferedStreamTest.class);
|
||||
io.addTestSuite(UTF8StreamTest.class);
|
||||
suite.addTest(io);
|
||||
|
||||
// prototype compiler
|
||||
TestSuite compiler = new TestSuite("Lua Compiler Tests");
|
||||
compiler.addTestSuite(CompilerUnitTests.class);
|
||||
compiler.addTestSuite(DumpLoadEndianIntTest.class);
|
||||
compiler.addTestSuite(LuaParserTests.class);
|
||||
compiler.addTestSuite(RegressionTests.class);
|
||||
compiler.addTestSuite(SimpleTests.class);
|
||||
suite.addTest(compiler);
|
||||
|
||||
// library tests
|
||||
TestSuite lib = new TestSuite("Library Tests");
|
||||
lib.addTestSuite(JsePlatformTest.class);
|
||||
lib.addTestSuite(LuajavaAccessibleMembersTest.class);
|
||||
lib.addTestSuite(LuajavaClassMembersTest.class);
|
||||
lib.addTestSuite(LuaJavaCoercionTest.class);
|
||||
lib.addTestSuite(RequireClassTest.class);
|
||||
lib.addTestSuite(OsLibTest.class);
|
||||
suite.addTest(lib);
|
||||
|
||||
// Script engine tests.
|
||||
TestSuite script = ScriptEngineTests.suite();
|
||||
suite.addTest(script);
|
||||
|
||||
// compatiblity tests
|
||||
TestSuite compat = CompatibiltyTest.suite();
|
||||
suite.addTest(compat);
|
||||
compat.addTestSuite(ErrorsTest.class);
|
||||
|
||||
return suite;
|
||||
}
|
||||
|
||||
}
|
||||
115
jse/src/test/java/org/luaj/vm2/BufferedStreamTest.java
Normal file
115
jse/src/test/java/org/luaj/vm2/BufferedStreamTest.java
Normal file
@@ -0,0 +1,115 @@
|
||||
/*******************************************************************************
|
||||
* 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.vm2;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.luaj.vm2.Globals.BufferedStream;
|
||||
|
||||
|
||||
public class BufferedStreamTest extends TestCase {
|
||||
|
||||
public BufferedStreamTest() {}
|
||||
|
||||
private BufferedStream NewBufferedStream(int buflen, String contents) {
|
||||
return new BufferedStream(buflen, new ByteArrayInputStream(contents.getBytes()));
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
public void testReadEmptyStream() throws java.io.IOException {
|
||||
BufferedStream bs = NewBufferedStream(4, "");
|
||||
assertEquals(-1, bs.read());
|
||||
assertEquals(-1, bs.read(new byte[10]));
|
||||
assertEquals(-1, bs.read(new byte[10], 0, 10));
|
||||
}
|
||||
|
||||
public void testReadByte() throws java.io.IOException {
|
||||
BufferedStream bs = NewBufferedStream(2, "abc");
|
||||
assertEquals('a', bs.read());
|
||||
assertEquals('b', bs.read());
|
||||
assertEquals('c', bs.read());
|
||||
assertEquals(-1, bs.read());
|
||||
}
|
||||
|
||||
public void testReadByteArray() throws java.io.IOException {
|
||||
byte[] array = new byte[3];
|
||||
BufferedStream bs = NewBufferedStream(4, "abcdef");
|
||||
assertEquals(3, bs.read(array));
|
||||
assertEquals("abc", new String(array));
|
||||
assertEquals(1, bs.read(array));
|
||||
assertEquals("d", new String(array, 0, 1));
|
||||
assertEquals(2, bs.read(array));
|
||||
assertEquals("ef", new String(array, 0, 2));
|
||||
assertEquals(-1, bs.read());
|
||||
}
|
||||
|
||||
public void testReadByteArrayOffsetLength() throws java.io.IOException {
|
||||
byte[] array = new byte[10];
|
||||
BufferedStream bs = NewBufferedStream(8, "abcdefghijklmn");
|
||||
assertEquals(4, bs.read(array, 0, 4));
|
||||
assertEquals("abcd", new String(array, 0, 4));
|
||||
assertEquals(4, bs.read(array, 2, 8));
|
||||
assertEquals("efgh", new String(array, 2, 4));
|
||||
assertEquals(6, bs.read(array, 0, 10));
|
||||
assertEquals("ijklmn", new String(array, 0, 6));
|
||||
assertEquals(-1, bs.read());
|
||||
}
|
||||
|
||||
public void testMarkOffsetBeginningOfStream() throws java.io.IOException {
|
||||
byte[] array = new byte[4];
|
||||
BufferedStream bs = NewBufferedStream(8, "abcdefghijkl");
|
||||
assertEquals(true, bs.markSupported());
|
||||
bs.mark(4);
|
||||
assertEquals(4, bs.read(array));
|
||||
assertEquals("abcd", new String(array));
|
||||
bs.reset();
|
||||
assertEquals(4, bs.read(array));
|
||||
assertEquals("abcd", new String(array));
|
||||
assertEquals(4, bs.read(array));
|
||||
assertEquals("efgh", new String(array));
|
||||
assertEquals(4, bs.read(array));
|
||||
assertEquals("ijkl", new String(array));
|
||||
assertEquals(-1, bs.read());
|
||||
}
|
||||
|
||||
public void testMarkOffsetMiddleOfStream() throws java.io.IOException {
|
||||
byte[] array = new byte[4];
|
||||
BufferedStream bs = NewBufferedStream(8, "abcdefghijkl");
|
||||
assertEquals(true, bs.markSupported());
|
||||
assertEquals(4, bs.read(array));
|
||||
assertEquals("abcd", new String(array));
|
||||
bs.mark(4);
|
||||
assertEquals(4, bs.read(array));
|
||||
assertEquals("efgh", new String(array));
|
||||
bs.reset();
|
||||
assertEquals(4, bs.read(array));
|
||||
assertEquals("efgh", new String(array));
|
||||
assertEquals(4, bs.read(array));
|
||||
assertEquals("ijkl", new String(array));
|
||||
assertEquals(-1, bs.read());
|
||||
}
|
||||
}
|
||||
115
jse/src/test/java/org/luaj/vm2/CompatibiltyTest.java
Normal file
115
jse/src/test/java/org/luaj/vm2/CompatibiltyTest.java
Normal file
@@ -0,0 +1,115 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import org.luaj.vm2.luajc.LuaJC;
|
||||
|
||||
/**
|
||||
* Compatibility tests for the Luaj VM
|
||||
*
|
||||
* Results are compared for exact match with
|
||||
* the installed C-based lua environment.
|
||||
*/
|
||||
public class CompatibiltyTest extends TestSuite {
|
||||
|
||||
private static final String dir = "";
|
||||
|
||||
abstract protected static class CompatibiltyTestSuite extends ScriptDrivenTest {
|
||||
LuaValue savedStringMetatable;
|
||||
protected CompatibiltyTestSuite(PlatformType platform) {
|
||||
super(platform,dir);
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
savedStringMetatable = LuaString.s_metatable;
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
LuaNil.s_metatable = null;
|
||||
LuaBoolean.s_metatable = null;
|
||||
LuaNumber.s_metatable = null;
|
||||
LuaFunction.s_metatable = null;
|
||||
LuaThread.s_metatable = null;
|
||||
LuaString.s_metatable = savedStringMetatable;
|
||||
}
|
||||
|
||||
public void testBaseLib() { runTest("baselib"); }
|
||||
public void testCoroutineLib() { runTest("coroutinelib"); }
|
||||
public void testDebugLib() { runTest("debuglib"); }
|
||||
public void testErrors() { runTest("errors"); }
|
||||
public void testFunctions() { runTest("functions"); }
|
||||
public void testIoLib() { runTest("iolib"); }
|
||||
public void testManyUpvals() { runTest("manyupvals"); }
|
||||
public void testMathLib() { runTest("mathlib"); }
|
||||
public void testMetatags() { runTest("metatags"); }
|
||||
public void testOsLib() { runTest("oslib"); }
|
||||
public void testStringLib() { runTest("stringlib"); }
|
||||
public void testTableLib() { runTest("tablelib"); }
|
||||
public void testTailcalls() { runTest("tailcalls"); }
|
||||
public void testUpvalues() { runTest("upvalues"); }
|
||||
public void testVm() { runTest("vm"); }
|
||||
}
|
||||
|
||||
|
||||
public static TestSuite suite() {
|
||||
TestSuite suite = new TestSuite("Compatibility Tests");
|
||||
suite.addTest( new TestSuite( JseCompatibilityTest.class, "JSE Compatibility Tests" ) );
|
||||
suite.addTest( new TestSuite( JmeCompatibilityTest.class, "JME Compatibility Tests" ) );
|
||||
suite.addTest( new TestSuite( LuaJCCompatibilityTest.class, "LuaJC Compatibility Tests" ) );
|
||||
return suite;
|
||||
}
|
||||
|
||||
public static class JmeCompatibilityTest extends CompatibiltyTestSuite {
|
||||
public JmeCompatibilityTest() {
|
||||
super(PlatformType.JME);
|
||||
}
|
||||
protected void setUp() throws Exception {
|
||||
System.setProperty("JME", "true");
|
||||
super.setUp();
|
||||
}
|
||||
}
|
||||
public static class JseCompatibilityTest extends CompatibiltyTestSuite {
|
||||
public JseCompatibilityTest() {
|
||||
super(PlatformType.JSE);
|
||||
}
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
System.setProperty("JME", "false");
|
||||
}
|
||||
}
|
||||
public static class LuaJCCompatibilityTest extends CompatibiltyTestSuite {
|
||||
public LuaJCCompatibilityTest() {
|
||||
super(PlatformType.LUAJIT);
|
||||
}
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
System.setProperty("JME", "false");
|
||||
LuaJC.install(globals);
|
||||
}
|
||||
// not supported on this platform - don't test
|
||||
public void testDebugLib() {}
|
||||
}
|
||||
}
|
||||
63
jse/src/test/java/org/luaj/vm2/ErrorsTest.java
Normal file
63
jse/src/test/java/org/luaj/vm2/ErrorsTest.java
Normal file
@@ -0,0 +1,63 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
|
||||
/**
|
||||
* Test argument type check errors
|
||||
*
|
||||
* Results are compared for exact match with
|
||||
* the installed C-based lua environment.
|
||||
*/
|
||||
public class ErrorsTest extends ScriptDrivenTest {
|
||||
|
||||
private static final String dir = "errors/";
|
||||
|
||||
public ErrorsTest() {
|
||||
super(PlatformType.JSE, dir);
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
public void testBaseLibArgs() {
|
||||
globals.STDIN = new InputStream() {
|
||||
public int read() throws IOException {
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
runTest("baselibargs");
|
||||
}
|
||||
public void testCoroutineLibArgs() { runTest("coroutinelibargs"); }
|
||||
public void testDebugLibArgs() { runTest("debuglibargs"); }
|
||||
public void testIoLibArgs() { runTest("iolibargs"); }
|
||||
public void testMathLibArgs() { runTest("mathlibargs"); }
|
||||
public void testModuleLibArgs() { runTest("modulelibargs"); }
|
||||
public void testOperators() { runTest("operators"); }
|
||||
public void testStringLibArgs() { runTest("stringlibargs"); }
|
||||
public void testTableLibArgs() { runTest("tablelibargs"); }
|
||||
|
||||
}
|
||||
612
jse/src/test/java/org/luaj/vm2/FragmentsTest.java
Normal file
612
jse/src/test/java/org/luaj/vm2/FragmentsTest.java
Normal file
@@ -0,0 +1,612 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
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 extends TestSuite {
|
||||
|
||||
static final int TEST_TYPE_LUAC = 0;
|
||||
static final int TEST_TYPE_LUAJC = 1;
|
||||
|
||||
public static class JseFragmentsTest extends FragmentsTestCase {
|
||||
public JseFragmentsTest() { super( TEST_TYPE_LUAC ); }
|
||||
}
|
||||
public static class LuaJCFragmentsTest extends FragmentsTestCase {
|
||||
public LuaJCFragmentsTest() { super( TEST_TYPE_LUAJC ); }
|
||||
}
|
||||
public static TestSuite suite() {
|
||||
TestSuite suite = new TestSuite("Compiler Fragments Tests");
|
||||
suite.addTest( new TestSuite( JseFragmentsTest.class, "JSE Fragments Tests" ) );
|
||||
suite.addTest( new TestSuite( LuaJCFragmentsTest.class, "LuaJC Fragments Tests" ) );
|
||||
return suite;
|
||||
}
|
||||
|
||||
abstract protected static class FragmentsTestCase extends TestCase {
|
||||
|
||||
final int TEST_TYPE;
|
||||
|
||||
protected FragmentsTestCase(int testType) {
|
||||
this.TEST_TYPE = testType;
|
||||
}
|
||||
|
||||
public void runFragment( Varargs expected, String script ) {
|
||||
try {
|
||||
String name = 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());
|
||||
}
|
||||
}
|
||||
|
||||
public void testFirstArgNilExtended() {
|
||||
runFragment( LuaValue.NIL,
|
||||
"function f1(a) print( 'f1:', a ) return a end\n" +
|
||||
"b = f1()\n" +
|
||||
"return b" );
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
}
|
||||
|
||||
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" );
|
||||
}
|
||||
|
||||
public void testArgParamUseNone() {
|
||||
runFragment( LuaValue.valueOf("string"),
|
||||
"function v(arg,...)\n" +
|
||||
" return type(arg)\n" +
|
||||
"end\n" +
|
||||
"return v('abc')\n" );
|
||||
}
|
||||
|
||||
public void testSetlistVarargs() {
|
||||
runFragment( LuaValue.valueOf("abc"),
|
||||
"local f = function() return 'abc' end\n" +
|
||||
"local g = { f() }\n" +
|
||||
"return g[1]\n" );
|
||||
}
|
||||
|
||||
public void testSelfOp() {
|
||||
runFragment( LuaValue.valueOf("bcd"),
|
||||
"local s = 'abcde'\n"+
|
||||
"return s:sub(2,4)\n" );
|
||||
}
|
||||
|
||||
public void testSetListWithOffsetAndVarargs() {
|
||||
runFragment( LuaValue.valueOf(1003),
|
||||
"local bar = {1000, math.sqrt(9)}\n"+
|
||||
"return bar[1]+bar[2]\n" );
|
||||
}
|
||||
|
||||
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" );
|
||||
}
|
||||
|
||||
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" );
|
||||
}
|
||||
|
||||
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" );
|
||||
}
|
||||
|
||||
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" );
|
||||
}
|
||||
|
||||
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" );
|
||||
|
||||
}
|
||||
|
||||
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" );
|
||||
}
|
||||
|
||||
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" );
|
||||
}
|
||||
|
||||
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" );
|
||||
|
||||
}
|
||||
|
||||
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" );
|
||||
|
||||
}
|
||||
public void testVarargsWithParameters() {
|
||||
runFragment( LuaValue.valueOf(222),
|
||||
"local func = function(t,...)\n"+
|
||||
" return (...)\n"+
|
||||
"end\n"+
|
||||
"return func(111,222,333)\n" );
|
||||
}
|
||||
|
||||
public void testNoReturnValuesPlainCall() {
|
||||
runFragment( LuaValue.TRUE,
|
||||
"local testtable = {}\n"+
|
||||
"return pcall( function() testtable[1]=2 end )\n" );
|
||||
}
|
||||
|
||||
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" );
|
||||
}
|
||||
|
||||
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" );
|
||||
}
|
||||
|
||||
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" );
|
||||
}
|
||||
|
||||
|
||||
public void testLoadNilUpvalue() {
|
||||
runFragment( LuaValue.NIL,
|
||||
"tostring = function() end\n" +
|
||||
"local pc \n" +
|
||||
"local pcall = function(...)\n" +
|
||||
" pc(...)\n" +
|
||||
"end\n" +
|
||||
"return NIL\n" );
|
||||
}
|
||||
|
||||
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" );
|
||||
}
|
||||
|
||||
public void testUninitializedUpvalue() {
|
||||
runFragment( LuaValue.NIL,
|
||||
"local f\n"+
|
||||
"do\n"+
|
||||
" function g()\n"+
|
||||
" print(f())\n"+
|
||||
" end\n"+
|
||||
"end\n" +
|
||||
"return NIL\n" );
|
||||
}
|
||||
|
||||
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" );
|
||||
}
|
||||
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" );
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
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" );
|
||||
}
|
||||
|
||||
public void testUninitializedAroundBranch() {
|
||||
runFragment( LuaValue.valueOf(333),
|
||||
"local state\n"+
|
||||
"if _G then\n"+
|
||||
" state = 333\n"+
|
||||
"end\n"+
|
||||
"return state\n" );
|
||||
}
|
||||
|
||||
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" );
|
||||
}
|
||||
|
||||
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]");
|
||||
}
|
||||
|
||||
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" );
|
||||
}
|
||||
|
||||
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" );
|
||||
}
|
||||
|
||||
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" );
|
||||
}
|
||||
|
||||
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" );
|
||||
}
|
||||
|
||||
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" );
|
||||
}
|
||||
|
||||
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" );
|
||||
}
|
||||
|
||||
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" );
|
||||
}
|
||||
|
||||
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" );
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
public void testUpvalueInDoBlock() {
|
||||
runFragment( LuaValue.NONE, "do\n"+
|
||||
" local x = 10\n"+
|
||||
" function g()\n"+
|
||||
" return x\n"+
|
||||
" end\n"+
|
||||
"end\n"+
|
||||
"g()\n");
|
||||
}
|
||||
|
||||
public void testNullError() {
|
||||
runFragment( LuaValue.varargsOf(LuaValue.FALSE, LuaValue.NIL),
|
||||
"return pcall(error)\n");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
public void testErrorArgIsString() {
|
||||
runFragment(LuaValue.varargsOf(LuaValue.valueOf("string"), LuaValue.valueOf("c")),
|
||||
"a,b = pcall(error, 'c'); return type(b), b\n");
|
||||
}
|
||||
public void testErrorArgIsNil() {
|
||||
runFragment(LuaValue.varargsOf(LuaValue.valueOf("nil"), LuaValue.NIL),
|
||||
"a,b = pcall(error); return type(b), b\n");
|
||||
}
|
||||
public void testErrorArgIsTable() {
|
||||
runFragment(LuaValue.varargsOf(LuaValue.valueOf("table"), LuaValue.valueOf("d")),
|
||||
"a,b = pcall(error, {c='d'}); return type(b), b.c\n");
|
||||
}
|
||||
public void testErrorArgIsNumber() {
|
||||
runFragment(LuaValue.varargsOf(LuaValue.valueOf("string"), LuaValue.valueOf("1")),
|
||||
"a,b = pcall(error, 1); return type(b), b\n");
|
||||
}
|
||||
public void testErrorArgIsBool() {
|
||||
runFragment(LuaValue.varargsOf(LuaValue.valueOf("boolean"), LuaValue.TRUE),
|
||||
"a,b = pcall(error, true); return type(b), b\n");
|
||||
}
|
||||
public void testBalancedMatchOnEmptyString() {
|
||||
runFragment(LuaValue.NIL, "return (\"\"):match(\"%b''\")\n");
|
||||
}
|
||||
public void testReturnValueForTableRemove() {
|
||||
runFragment(LuaValue.NONE, "return table.remove({ })");
|
||||
}
|
||||
public void testTypeOfTableRemoveReturnValue() {
|
||||
runFragment(LuaValue.valueOf("nil"), "local k = table.remove({ }) return type(k)");
|
||||
}
|
||||
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");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
70
jse/src/test/java/org/luaj/vm2/LoadOrderTest.java
Normal file
70
jse/src/test/java/org/luaj/vm2/LoadOrderTest.java
Normal file
@@ -0,0 +1,70 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
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.
|
||||
public class LoadOrderTest extends TestCase {
|
||||
|
||||
public void testLoadGlobalsFirst() {
|
||||
Globals g = JsePlatform.standardGlobals();
|
||||
assertNotNull(g);
|
||||
}
|
||||
|
||||
public 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");
|
||||
|
||||
public Object[] launch(String script, Object[] arg) {
|
||||
return new Object[] { FOO };
|
||||
}
|
||||
|
||||
public Object[] launch(InputStream script, Object[] arg) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object[] launch(Reader script, Object[] arg) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void testClassLoadsStringFirst() throws Exception {
|
||||
Launcher launcher = LuajClassLoader
|
||||
.NewLauncher(TestLauncherLoadStringFirst.class);
|
||||
Object[] results = launcher.launch("foo", null);
|
||||
assertNotNull(results);
|
||||
}
|
||||
|
||||
}
|
||||
176
jse/src/test/java/org/luaj/vm2/LuaOperationsTest.java
Normal file
176
jse/src/test/java/org/luaj/vm2/LuaOperationsTest.java
Normal file
@@ -0,0 +1,176 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.luaj.vm2.TypeTest.MyData;
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
import org.luaj.vm2.lib.ZeroArgFunction;
|
||||
|
||||
public class LuaOperationsTest extends TestCase {
|
||||
|
||||
private final int sampleint = 77;
|
||||
private final long samplelong = 123400000000L;
|
||||
private final double sampledouble = 55.25;
|
||||
private final String samplestringstring = "abcdef";
|
||||
private final String samplestringint = String.valueOf(sampleint);
|
||||
private final String samplestringlong = String.valueOf(samplelong);
|
||||
private final String samplestringdouble = String.valueOf(sampledouble);
|
||||
private final Object sampleobject = new Object();
|
||||
private final MyData sampledata = new MyData();
|
||||
|
||||
private final LuaValue somenil = LuaValue.NIL;
|
||||
private final LuaValue sometrue = LuaValue.TRUE;
|
||||
private final LuaValue somefalse = LuaValue.FALSE;
|
||||
private final LuaValue zero = LuaValue.ZERO;
|
||||
private final LuaValue intint = LuaValue.valueOf(sampleint);
|
||||
private final LuaValue longdouble = LuaValue.valueOf(samplelong);
|
||||
private final LuaValue doubledouble = LuaValue.valueOf(sampledouble);
|
||||
private final LuaValue stringstring = LuaValue.valueOf(samplestringstring);
|
||||
private final LuaValue stringint = LuaValue.valueOf(samplestringint);
|
||||
private final LuaValue stringlong = LuaValue.valueOf(samplestringlong);
|
||||
private final LuaValue stringdouble = LuaValue.valueOf(samplestringdouble);
|
||||
private final LuaTable table = LuaValue.listOf( new LuaValue[] { LuaValue.valueOf("aaa"), LuaValue.valueOf("bbb") } );
|
||||
private final LuaValue somefunc = new ZeroArgFunction() { public LuaValue call() { return NONE;}};
|
||||
private final LuaThread thread = new LuaThread(new Globals(), somefunc);
|
||||
private final Prototype proto = new Prototype(1);
|
||||
private final LuaClosure someclosure = new LuaClosure(proto,table);
|
||||
private final LuaUserdata userdataobj = LuaValue.userdataOf(sampleobject);
|
||||
private final LuaUserdata userdatacls = LuaValue.userdataOf(sampledata);
|
||||
|
||||
private void throwsLuaError(String methodName, Object obj) {
|
||||
try {
|
||||
LuaValue.class.getMethod(methodName).invoke(obj);
|
||||
fail("failed to throw LuaError as required");
|
||||
} catch (InvocationTargetException e) {
|
||||
if ( ! (e.getTargetException() instanceof LuaError) )
|
||||
fail("not a LuaError: "+e.getTargetException());
|
||||
return; // pass
|
||||
} catch ( Exception e ) {
|
||||
fail( "bad exception: "+e );
|
||||
}
|
||||
}
|
||||
|
||||
private void throwsLuaError(String methodName, Object obj, Object arg) {
|
||||
try {
|
||||
LuaValue.class.getMethod(methodName,LuaValue.class).invoke(obj,arg);
|
||||
fail("failed to throw LuaError as required");
|
||||
} catch (InvocationTargetException e) {
|
||||
if ( ! (e.getTargetException() instanceof LuaError) )
|
||||
fail("not a LuaError: "+e.getTargetException());
|
||||
return; // pass
|
||||
} catch ( Exception e ) {
|
||||
fail( "bad exception: "+e );
|
||||
}
|
||||
}
|
||||
|
||||
public void testLen() {
|
||||
throwsLuaError( "len", somenil );
|
||||
throwsLuaError( "len", sometrue );
|
||||
throwsLuaError( "len", somefalse );
|
||||
throwsLuaError( "len", zero );
|
||||
throwsLuaError( "len", intint );
|
||||
throwsLuaError( "len", longdouble );
|
||||
throwsLuaError( "len", doubledouble );
|
||||
assertEquals( LuaInteger.valueOf(samplestringstring.length()), stringstring.len() );
|
||||
assertEquals( LuaInteger.valueOf(samplestringint.length()), stringint.len() );
|
||||
assertEquals( LuaInteger.valueOf(samplestringlong.length()), stringlong.len() );
|
||||
assertEquals( LuaInteger.valueOf(samplestringdouble.length()), stringdouble.len() );
|
||||
assertEquals( LuaInteger.valueOf(2), table.len() );
|
||||
throwsLuaError( "len", somefunc );
|
||||
throwsLuaError( "len", thread );
|
||||
throwsLuaError( "len", someclosure );
|
||||
throwsLuaError( "len", userdataobj );
|
||||
throwsLuaError( "len", userdatacls );
|
||||
}
|
||||
|
||||
public void testLength() {
|
||||
throwsLuaError( "length", somenil );
|
||||
throwsLuaError( "length", sometrue );
|
||||
throwsLuaError( "length", somefalse );
|
||||
throwsLuaError( "length", zero );
|
||||
throwsLuaError( "length", intint );
|
||||
throwsLuaError( "length", longdouble );
|
||||
throwsLuaError( "length", doubledouble );
|
||||
assertEquals( samplestringstring.length(), stringstring.length() );
|
||||
assertEquals( samplestringint.length(), stringint.length() );
|
||||
assertEquals( samplestringlong.length(), stringlong.length() );
|
||||
assertEquals( samplestringdouble.length(), stringdouble.length() );
|
||||
assertEquals( 2, table.length() );
|
||||
throwsLuaError( "length", somefunc );
|
||||
throwsLuaError( "length", thread );
|
||||
throwsLuaError( "length", someclosure );
|
||||
throwsLuaError( "length", userdataobj );
|
||||
throwsLuaError( "length", userdatacls );
|
||||
}
|
||||
|
||||
public Prototype createPrototype( String script, String name ) {
|
||||
try {
|
||||
Globals globals = org.luaj.vm2.lib.jse.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;
|
||||
}
|
||||
}
|
||||
|
||||
public void testFunctionClosureThreadEnv() {
|
||||
|
||||
// set up suitable environments for execution
|
||||
LuaValue aaa = LuaValue.valueOf("aaa");
|
||||
LuaValue eee = LuaValue.valueOf("eee");
|
||||
final Globals globals = org.luaj.vm2.lib.jse.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() { 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() );
|
||||
}
|
||||
}
|
||||
}
|
||||
232
jse/src/test/java/org/luaj/vm2/MathLibTest.java
Normal file
232
jse/src/test/java/org/luaj/vm2/MathLibTest.java
Normal file
@@ -0,0 +1,232 @@
|
||||
package org.luaj.vm2;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.luaj.vm2.lib.jme.JmePlatform;
|
||||
import org.luaj.vm2.lib.jse.JsePlatform;
|
||||
|
||||
public class MathLibTest extends TestCase {
|
||||
|
||||
private LuaValue j2se;
|
||||
private LuaValue j2me;
|
||||
private boolean supportedOnJ2me;
|
||||
|
||||
public MathLibTest() {
|
||||
j2se = JsePlatform.standardGlobals().get("math");
|
||||
j2me = JmePlatform.standardGlobals().get("math");
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
supportedOnJ2me = true;
|
||||
}
|
||||
|
||||
public void testMathDPow() {
|
||||
assertEquals( 1, j2mepow(2, 0), 0 );
|
||||
assertEquals( 2, j2mepow(2, 1), 0 );
|
||||
assertEquals( 8, j2mepow(2, 3), 0 );
|
||||
assertEquals( -8, j2mepow(-2, 3), 0 );
|
||||
assertEquals( 1/8., j2mepow(2, -3), 0 );
|
||||
assertEquals( -1/8., j2mepow(-2, -3), 0 );
|
||||
assertEquals( 16, j2mepow(256, .5), 0 );
|
||||
assertEquals( 4, j2mepow(256, .25), 0 );
|
||||
assertEquals( 64, j2mepow(256, .75), 0 );
|
||||
assertEquals( 1./16, j2mepow(256, - .5), 0 );
|
||||
assertEquals( 1./ 4, j2mepow(256, -.25), 0 );
|
||||
assertEquals( 1./64, j2mepow(256, -.75), 0 );
|
||||
assertEquals( Double.NaN, j2mepow(-256, .5), 0 );
|
||||
assertEquals( 1, j2mepow(.5, 0), 0 );
|
||||
assertEquals( .5, j2mepow(.5, 1), 0 );
|
||||
assertEquals(.125, j2mepow(.5, 3), 0 );
|
||||
assertEquals( 2, j2mepow(.5, -1), 0 );
|
||||
assertEquals( 8, j2mepow(.5, -3), 0 );
|
||||
assertEquals(1, j2mepow(0.0625, 0), 0 );
|
||||
assertEquals(0.00048828125, j2mepow(0.0625, 2.75), 0 );
|
||||
}
|
||||
|
||||
private double j2mepow(double x, double y) {
|
||||
return j2me.get("pow").call(LuaValue.valueOf(x),LuaValue.valueOf(y)).todouble();
|
||||
}
|
||||
|
||||
public void testAbs() {
|
||||
tryMathOp( "abs", 23.45 );
|
||||
tryMathOp( "abs", -23.45 );
|
||||
}
|
||||
|
||||
public void testCos() {
|
||||
tryTrigOps( "cos" );
|
||||
}
|
||||
|
||||
public void testCosh() {
|
||||
supportedOnJ2me = false;
|
||||
tryTrigOps( "cosh" );
|
||||
}
|
||||
|
||||
public void testDeg() {
|
||||
tryTrigOps( "deg" );
|
||||
}
|
||||
|
||||
public void testExp() {
|
||||
//supportedOnJ2me = false;
|
||||
tryMathOp( "exp", 0 );
|
||||
tryMathOp( "exp", 0.1 );
|
||||
tryMathOp( "exp", .9 );
|
||||
tryMathOp( "exp", 1. );
|
||||
tryMathOp( "exp", 9 );
|
||||
tryMathOp( "exp", -.1 );
|
||||
tryMathOp( "exp", -.9 );
|
||||
tryMathOp( "exp", -1. );
|
||||
tryMathOp( "exp", -9 );
|
||||
}
|
||||
|
||||
public void testLog() {
|
||||
supportedOnJ2me = false;
|
||||
tryMathOp( "log", 0.1 );
|
||||
tryMathOp( "log", .9 );
|
||||
tryMathOp( "log", 1. );
|
||||
tryMathOp( "log", 9 );
|
||||
tryMathOp( "log", -.1 );
|
||||
tryMathOp( "log", -.9 );
|
||||
tryMathOp( "log", -1. );
|
||||
tryMathOp( "log", -9 );
|
||||
}
|
||||
|
||||
public void testRad() {
|
||||
tryMathOp( "rad", 0 );
|
||||
tryMathOp( "rad", 0.1 );
|
||||
tryMathOp( "rad", .9 );
|
||||
tryMathOp( "rad", 1. );
|
||||
tryMathOp( "rad", 9 );
|
||||
tryMathOp( "rad", 10 );
|
||||
tryMathOp( "rad", 100 );
|
||||
tryMathOp( "rad", -.1 );
|
||||
tryMathOp( "rad", -.9 );
|
||||
tryMathOp( "rad", -1. );
|
||||
tryMathOp( "rad", -9 );
|
||||
tryMathOp( "rad", -10 );
|
||||
tryMathOp( "rad", -100 );
|
||||
}
|
||||
|
||||
public void testSin() {
|
||||
tryTrigOps( "sin" );
|
||||
}
|
||||
|
||||
public void testSinh() {
|
||||
supportedOnJ2me = false;
|
||||
tryTrigOps( "sinh" );
|
||||
}
|
||||
|
||||
public void testSqrt() {
|
||||
tryMathOp( "sqrt", 0 );
|
||||
tryMathOp( "sqrt", 0.1 );
|
||||
tryMathOp( "sqrt", .9 );
|
||||
tryMathOp( "sqrt", 1. );
|
||||
tryMathOp( "sqrt", 9 );
|
||||
tryMathOp( "sqrt", 10 );
|
||||
tryMathOp( "sqrt", 100 );
|
||||
}
|
||||
public void testTan() {
|
||||
tryTrigOps( "tan" );
|
||||
}
|
||||
|
||||
public void testTanh() {
|
||||
supportedOnJ2me = false;
|
||||
tryTrigOps( "tanh" );
|
||||
}
|
||||
|
||||
public void testAtan2() {
|
||||
supportedOnJ2me = false;
|
||||
tryDoubleOps( "atan2", false );
|
||||
}
|
||||
|
||||
public void testFmod() {
|
||||
tryDoubleOps( "fmod", false );
|
||||
}
|
||||
|
||||
public void testPow() {
|
||||
tryDoubleOps( "pow", true );
|
||||
}
|
||||
|
||||
private void tryDoubleOps( String op, boolean positiveOnly ) {
|
||||
// y>0, x>0
|
||||
tryMathOp( op, 0.1, 4.0 );
|
||||
tryMathOp( op, .9, 4.0 );
|
||||
tryMathOp( op, 1., 4.0 );
|
||||
tryMathOp( op, 9, 4.0 );
|
||||
tryMathOp( op, 10, 4.0 );
|
||||
tryMathOp( op, 100, 4.0 );
|
||||
|
||||
// y>0, x<0
|
||||
tryMathOp( op, 0.1, -4.0 );
|
||||
tryMathOp( op, .9, -4.0 );
|
||||
tryMathOp( op, 1., -4.0 );
|
||||
tryMathOp( op, 9, -4.0 );
|
||||
tryMathOp( op, 10, -4.0 );
|
||||
tryMathOp( op, 100, -4.0 );
|
||||
|
||||
if ( ! positiveOnly ) {
|
||||
// y<0, x>0
|
||||
tryMathOp( op, -0.1, 4.0 );
|
||||
tryMathOp( op, -.9, 4.0 );
|
||||
tryMathOp( op, -1., 4.0 );
|
||||
tryMathOp( op, -9, 4.0 );
|
||||
tryMathOp( op, -10, 4.0 );
|
||||
tryMathOp( op, -100, 4.0 );
|
||||
|
||||
// y<0, x<0
|
||||
tryMathOp( op, -0.1, -4.0 );
|
||||
tryMathOp( op, -.9, -4.0 );
|
||||
tryMathOp( op, -1., -4.0 );
|
||||
tryMathOp( op, -9, -4.0 );
|
||||
tryMathOp( op, -10, -4.0 );
|
||||
tryMathOp( op, -100, -4.0 );
|
||||
}
|
||||
|
||||
// degenerate cases
|
||||
tryMathOp( op, 0, 1 );
|
||||
tryMathOp( op, 1, 0 );
|
||||
tryMathOp( op, -1, 0 );
|
||||
tryMathOp( op, 0, -1 );
|
||||
tryMathOp( op, 0, 0 );
|
||||
}
|
||||
|
||||
private void tryTrigOps(String op) {
|
||||
tryMathOp( op, 0 );
|
||||
tryMathOp( op, Math.PI/8 );
|
||||
tryMathOp( op, Math.PI*7/8 );
|
||||
tryMathOp( op, Math.PI*8/8 );
|
||||
tryMathOp( op, Math.PI*9/8 );
|
||||
tryMathOp( op, -Math.PI/8 );
|
||||
tryMathOp( op, -Math.PI*7/8 );
|
||||
tryMathOp( op, -Math.PI*8/8 );
|
||||
tryMathOp( op, -Math.PI*9/8 );
|
||||
}
|
||||
|
||||
private void tryMathOp(String op, double x) {
|
||||
try {
|
||||
double expected = j2se.get(op).call( LuaValue.valueOf(x)).todouble();
|
||||
double actual = j2me.get(op).call( LuaValue.valueOf(x)).todouble();
|
||||
if ( supportedOnJ2me )
|
||||
assertEquals( expected, actual, 1.e-4 );
|
||||
else
|
||||
fail("j2me should throw exception for math."+op+" but returned "+actual);
|
||||
} catch ( LuaError lee ) {
|
||||
if ( supportedOnJ2me )
|
||||
throw lee;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void tryMathOp(String op, double a, double b) {
|
||||
try {
|
||||
double expected = j2se.get(op).call( LuaValue.valueOf(a), LuaValue.valueOf(b)).todouble();
|
||||
double actual = j2me.get(op).call( LuaValue.valueOf(a), LuaValue.valueOf(b)).todouble();
|
||||
if ( supportedOnJ2me )
|
||||
assertEquals( expected, actual, 1.e-5 );
|
||||
else
|
||||
fail("j2me should throw exception for math."+op+" but returned "+actual);
|
||||
} catch ( LuaError lee ) {
|
||||
if ( supportedOnJ2me )
|
||||
throw lee;
|
||||
}
|
||||
}
|
||||
}
|
||||
366
jse/src/test/java/org/luaj/vm2/MetatableTest.java
Normal file
366
jse/src/test/java/org/luaj/vm2/MetatableTest.java
Normal file
@@ -0,0 +1,366 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.luaj.vm2.TypeTest.MyData;
|
||||
import org.luaj.vm2.lib.StringLib;
|
||||
import org.luaj.vm2.lib.ThreeArgFunction;
|
||||
import org.luaj.vm2.lib.TwoArgFunction;
|
||||
import org.luaj.vm2.lib.ZeroArgFunction;
|
||||
|
||||
public class MetatableTest extends TestCase {
|
||||
|
||||
private final String samplestring = "abcdef";
|
||||
private final Object sampleobject = new Object();
|
||||
private final MyData sampledata = new MyData();
|
||||
|
||||
private final LuaValue string = LuaValue.valueOf(samplestring);
|
||||
private final LuaTable table = LuaValue.tableOf();
|
||||
private final LuaFunction function = new ZeroArgFunction() { public LuaValue call() { return NONE;}};
|
||||
private final LuaThread thread = new LuaThread(new Globals(), function);
|
||||
private final LuaClosure closure = new LuaClosure(new Prototype(), new LuaTable());
|
||||
private final LuaUserdata userdata = LuaValue.userdataOf(sampleobject);
|
||||
private final LuaUserdata userdatamt = LuaValue.userdataOf(sampledata,table);
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
// needed for metatable ops to work on strings
|
||||
new StringLib();
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
LuaBoolean.s_metatable = null;
|
||||
LuaFunction.s_metatable = null;
|
||||
LuaNil.s_metatable = null;
|
||||
LuaNumber.s_metatable = null;
|
||||
// LuaString.s_metatable = null;
|
||||
LuaThread.s_metatable = null;
|
||||
}
|
||||
|
||||
public void testGetMetatable() {
|
||||
assertEquals( null, LuaValue.NIL.getmetatable() );
|
||||
assertEquals( null, LuaValue.TRUE.getmetatable() );
|
||||
assertEquals( null, LuaValue.ONE.getmetatable() );
|
||||
// assertEquals( null, string.getmetatable() );
|
||||
assertEquals( null, table.getmetatable() );
|
||||
assertEquals( null, function.getmetatable() );
|
||||
assertEquals( null, thread.getmetatable() );
|
||||
assertEquals( null, closure.getmetatable() );
|
||||
assertEquals( null, userdata.getmetatable() );
|
||||
assertEquals( table, userdatamt.getmetatable() );
|
||||
}
|
||||
|
||||
public void testSetMetatable() {
|
||||
LuaValue mt = LuaValue.tableOf();
|
||||
assertEquals( null, table.getmetatable() );
|
||||
assertEquals( null, userdata.getmetatable() );
|
||||
assertEquals( table, userdatamt.getmetatable() );
|
||||
assertEquals( table, table.setmetatable(mt) );
|
||||
assertEquals( userdata, userdata.setmetatable(mt) );
|
||||
assertEquals( userdatamt, userdatamt.setmetatable(mt) );
|
||||
assertEquals( mt, table.getmetatable() );
|
||||
assertEquals( mt, userdata.getmetatable() );
|
||||
assertEquals( mt, userdatamt.getmetatable() );
|
||||
|
||||
// these all get metatable behind-the-scenes
|
||||
assertEquals( null, LuaValue.NIL.getmetatable() );
|
||||
assertEquals( null, LuaValue.TRUE.getmetatable() );
|
||||
assertEquals( null, LuaValue.ONE.getmetatable() );
|
||||
// assertEquals( null, string.getmetatable() );
|
||||
assertEquals( null, function.getmetatable() );
|
||||
assertEquals( null, thread.getmetatable() );
|
||||
assertEquals( null, closure.getmetatable() );
|
||||
LuaNil.s_metatable = mt;
|
||||
assertEquals( mt, LuaValue.NIL.getmetatable() );
|
||||
assertEquals( null, LuaValue.TRUE.getmetatable() );
|
||||
assertEquals( null, LuaValue.ONE.getmetatable() );
|
||||
// assertEquals( null, string.getmetatable() );
|
||||
assertEquals( null, function.getmetatable() );
|
||||
assertEquals( null, thread.getmetatable() );
|
||||
assertEquals( null, closure.getmetatable() );
|
||||
LuaBoolean.s_metatable = mt;
|
||||
assertEquals( mt, LuaValue.TRUE.getmetatable() );
|
||||
assertEquals( null, LuaValue.ONE.getmetatable() );
|
||||
// assertEquals( null, string.getmetatable() );
|
||||
assertEquals( null, function.getmetatable() );
|
||||
assertEquals( null, thread.getmetatable() );
|
||||
assertEquals( null, closure.getmetatable() );
|
||||
LuaNumber.s_metatable = mt;
|
||||
assertEquals( mt, LuaValue.ONE.getmetatable() );
|
||||
assertEquals( mt, LuaValue.valueOf(1.25).getmetatable() );
|
||||
// assertEquals( null, string.getmetatable() );
|
||||
assertEquals( null, function.getmetatable() );
|
||||
assertEquals( null, thread.getmetatable() );
|
||||
assertEquals( null, closure.getmetatable() );
|
||||
// LuaString.s_metatable = mt;
|
||||
// assertEquals( mt, string.getmetatable() );
|
||||
assertEquals( null, function.getmetatable() );
|
||||
assertEquals( null, thread.getmetatable() );
|
||||
assertEquals( null, closure.getmetatable() );
|
||||
LuaFunction.s_metatable = mt;
|
||||
assertEquals( mt, function.getmetatable() );
|
||||
assertEquals( null, thread.getmetatable() );
|
||||
LuaThread.s_metatable = mt;
|
||||
assertEquals( mt, thread.getmetatable() );
|
||||
}
|
||||
|
||||
public void testMetatableIndex() {
|
||||
assertEquals( table, table.setmetatable(null) );
|
||||
assertEquals( userdata, userdata.setmetatable(null) );
|
||||
assertEquals( userdatamt, userdatamt.setmetatable(null) );
|
||||
assertEquals( LuaValue.NIL, table.get(1) );
|
||||
assertEquals( LuaValue.NIL, userdata.get(1) );
|
||||
assertEquals( LuaValue.NIL, userdatamt.get(1) );
|
||||
|
||||
// empty metatable
|
||||
LuaValue mt = LuaValue.tableOf();
|
||||
assertEquals( table, table.setmetatable(mt) );
|
||||
assertEquals( userdata, userdata.setmetatable(mt) );
|
||||
LuaBoolean.s_metatable = mt;
|
||||
LuaFunction.s_metatable = mt;
|
||||
LuaNil.s_metatable = mt;
|
||||
LuaNumber.s_metatable = mt;
|
||||
// LuaString.s_metatable = mt;
|
||||
LuaThread.s_metatable = mt;
|
||||
assertEquals( mt, table.getmetatable() );
|
||||
assertEquals( mt, userdata.getmetatable() );
|
||||
assertEquals( mt, LuaValue.NIL.getmetatable() );
|
||||
assertEquals( mt, LuaValue.TRUE.getmetatable() );
|
||||
assertEquals( mt, LuaValue.ONE.getmetatable() );
|
||||
// assertEquals( StringLib.instance, string.getmetatable() );
|
||||
assertEquals( mt, function.getmetatable() );
|
||||
assertEquals( mt, thread.getmetatable() );
|
||||
|
||||
// plain metatable
|
||||
LuaValue abc = LuaValue.valueOf("abc");
|
||||
mt.set( LuaValue.INDEX, LuaValue.listOf(new LuaValue[] { abc } ) );
|
||||
assertEquals( abc, table.get(1) );
|
||||
assertEquals( abc, userdata.get(1) );
|
||||
assertEquals( abc, LuaValue.NIL.get(1) );
|
||||
assertEquals( abc, LuaValue.TRUE.get(1) );
|
||||
assertEquals( abc, LuaValue.ONE.get(1) );
|
||||
// assertEquals( abc, string.get(1) );
|
||||
assertEquals( abc, function.get(1) );
|
||||
assertEquals( abc, thread.get(1) );
|
||||
|
||||
// plain metatable
|
||||
mt.set( LuaValue.INDEX, new TwoArgFunction() {
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return LuaValue.valueOf( arg1.typename()+"["+arg2.tojstring()+"]=xyz" );
|
||||
}
|
||||
|
||||
});
|
||||
assertEquals( "table[1]=xyz", table.get(1).tojstring() );
|
||||
assertEquals( "userdata[1]=xyz", userdata.get(1).tojstring() );
|
||||
assertEquals( "nil[1]=xyz", LuaValue.NIL.get(1).tojstring() );
|
||||
assertEquals( "boolean[1]=xyz", LuaValue.TRUE.get(1).tojstring() );
|
||||
assertEquals( "number[1]=xyz", LuaValue.ONE.get(1).tojstring() );
|
||||
// assertEquals( "string[1]=xyz", string.get(1).tojstring() );
|
||||
assertEquals( "function[1]=xyz", function.get(1).tojstring() );
|
||||
assertEquals( "thread[1]=xyz", thread.get(1).tojstring() );
|
||||
}
|
||||
|
||||
|
||||
public void testMetatableNewIndex() {
|
||||
// empty metatable
|
||||
LuaValue mt = LuaValue.tableOf();
|
||||
assertEquals( table, table.setmetatable(mt) );
|
||||
assertEquals( userdata, userdata.setmetatable(mt) );
|
||||
LuaBoolean.s_metatable = mt;
|
||||
LuaFunction.s_metatable = mt;
|
||||
LuaNil.s_metatable = mt;
|
||||
LuaNumber.s_metatable = mt;
|
||||
// LuaString.s_metatable = mt;
|
||||
LuaThread.s_metatable = mt;
|
||||
|
||||
// plain metatable
|
||||
final LuaValue fallback = LuaValue.tableOf();
|
||||
LuaValue abc = LuaValue.valueOf("abc");
|
||||
mt.set( LuaValue.NEWINDEX, fallback );
|
||||
table.set(2,abc);
|
||||
userdata.set(3,abc);
|
||||
LuaValue.NIL.set(4,abc);
|
||||
LuaValue.TRUE.set(5,abc);
|
||||
LuaValue.ONE.set(6,abc);
|
||||
// string.set(7,abc);
|
||||
function.set(8,abc);
|
||||
thread.set(9,abc);
|
||||
assertEquals( abc, fallback.get(2) );
|
||||
assertEquals( abc, fallback.get(3) );
|
||||
assertEquals( abc, fallback.get(4) );
|
||||
assertEquals( abc, fallback.get(5) );
|
||||
assertEquals( abc, fallback.get(6) );
|
||||
// assertEquals( abc, StringLib.instance.get(7) );
|
||||
assertEquals( abc, fallback.get(8) );
|
||||
assertEquals( abc, fallback.get(9) );
|
||||
|
||||
// metatable with function call
|
||||
mt.set( LuaValue.NEWINDEX, new ThreeArgFunction() {
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
|
||||
fallback.rawset(arg2, LuaValue.valueOf( "via-func-"+arg3 ));
|
||||
return NONE;
|
||||
}
|
||||
|
||||
});
|
||||
table.set(12,abc);
|
||||
userdata.set(13,abc);
|
||||
LuaValue.NIL.set(14,abc);
|
||||
LuaValue.TRUE.set(15,abc);
|
||||
LuaValue.ONE.set(16,abc);
|
||||
// string.set(17,abc);
|
||||
function.set(18,abc);
|
||||
thread.set(19,abc);
|
||||
LuaValue via = LuaValue.valueOf( "via-func-abc" );
|
||||
assertEquals( via, fallback.get(12) );
|
||||
assertEquals( via, fallback.get(13) );
|
||||
assertEquals( via, fallback.get(14) );
|
||||
assertEquals( via, fallback.get(15) );
|
||||
assertEquals( via, fallback.get(16) );
|
||||
// assertEquals( via, StringLib.instance.get(17) );
|
||||
assertEquals( via, fallback.get(18) );
|
||||
assertEquals( via, fallback.get(19) );
|
||||
}
|
||||
|
||||
|
||||
private void checkTable( LuaValue t,
|
||||
LuaValue aa, LuaValue bb, LuaValue cc, LuaValue dd, LuaValue ee, LuaValue ff, LuaValue gg,
|
||||
LuaValue ra, LuaValue rb, LuaValue rc, LuaValue rd, LuaValue re, LuaValue rf, LuaValue rg ) {
|
||||
assertEquals( aa, t.get("aa") );
|
||||
assertEquals( bb, t.get("bb") );
|
||||
assertEquals( cc, t.get("cc") );
|
||||
assertEquals( dd, t.get("dd") );
|
||||
assertEquals( ee, t.get("ee") );
|
||||
assertEquals( ff, t.get("ff") );
|
||||
assertEquals( gg, t.get("gg") );
|
||||
assertEquals( ra, t.rawget("aa") );
|
||||
assertEquals( rb, t.rawget("bb") );
|
||||
assertEquals( rc, t.rawget("cc") );
|
||||
assertEquals( rd, t.rawget("dd") );
|
||||
assertEquals( re, t.rawget("ee") );
|
||||
assertEquals( rf, t.rawget("ff") );
|
||||
assertEquals( rg, t.rawget("gg") );
|
||||
}
|
||||
|
||||
private LuaValue makeTable( String key1, String val1, String key2, String val2 ) {
|
||||
return LuaValue.tableOf( new LuaValue[] {
|
||||
LuaValue.valueOf(key1), LuaValue.valueOf(val1),
|
||||
LuaValue.valueOf(key2), LuaValue.valueOf(val2),
|
||||
} );
|
||||
}
|
||||
|
||||
public void testRawsetMetatableSet() {
|
||||
// set up tables
|
||||
LuaValue m = makeTable( "aa", "aaa", "bb", "bbb" );
|
||||
m.set(LuaValue.INDEX, m);
|
||||
m.set(LuaValue.NEWINDEX, m);
|
||||
LuaValue s = makeTable( "cc", "ccc", "dd", "ddd" );
|
||||
LuaValue t = makeTable( "cc", "ccc", "dd", "ddd" );
|
||||
t.setmetatable(m);
|
||||
LuaValue aaa = LuaValue.valueOf("aaa");
|
||||
LuaValue bbb = LuaValue.valueOf("bbb");
|
||||
LuaValue ccc = LuaValue.valueOf("ccc");
|
||||
LuaValue ddd = LuaValue.valueOf("ddd");
|
||||
LuaValue ppp = LuaValue.valueOf("ppp");
|
||||
LuaValue qqq = LuaValue.valueOf("qqq");
|
||||
LuaValue rrr = LuaValue.valueOf("rrr");
|
||||
LuaValue sss = LuaValue.valueOf("sss");
|
||||
LuaValue ttt = LuaValue.valueOf("ttt");
|
||||
LuaValue www = LuaValue.valueOf("www");
|
||||
LuaValue xxx = LuaValue.valueOf("xxx");
|
||||
LuaValue yyy = LuaValue.valueOf("yyy");
|
||||
LuaValue zzz = LuaValue.valueOf("zzz");
|
||||
LuaValue nil = LuaValue.NIL;
|
||||
|
||||
// check initial values
|
||||
// values via "bet()" values via "rawget()"
|
||||
checkTable( s, nil,nil,ccc,ddd,nil,nil,nil, nil,nil,ccc,ddd,nil,nil,nil );
|
||||
checkTable( t, aaa,bbb,ccc,ddd,nil,nil,nil, nil,nil,ccc,ddd,nil,nil,nil );
|
||||
checkTable( m, aaa,bbb,nil,nil,nil,nil,nil, aaa,bbb,nil,nil,nil,nil,nil );
|
||||
|
||||
// rawset()
|
||||
s.rawset("aa", www);
|
||||
checkTable( s, www,nil,ccc,ddd,nil,nil,nil, www,nil,ccc,ddd,nil,nil,nil );
|
||||
checkTable( t, aaa,bbb,ccc,ddd,nil,nil,nil, nil,nil,ccc,ddd,nil,nil,nil );
|
||||
checkTable( m, aaa,bbb,nil,nil,nil,nil,nil, aaa,bbb,nil,nil,nil,nil,nil );
|
||||
s.rawset("cc", xxx);
|
||||
checkTable( s, www,nil,xxx,ddd,nil,nil,nil, www,nil,xxx,ddd,nil,nil,nil );
|
||||
checkTable( t, aaa,bbb,ccc,ddd,nil,nil,nil, nil,nil,ccc,ddd,nil,nil,nil );
|
||||
checkTable( m, aaa,bbb,nil,nil,nil,nil,nil, aaa,bbb,nil,nil,nil,nil,nil );
|
||||
t.rawset("bb", yyy);
|
||||
checkTable( s, www,nil,xxx,ddd,nil,nil,nil, www,nil,xxx,ddd,nil,nil,nil );
|
||||
checkTable( t, aaa,yyy,ccc,ddd,nil,nil,nil, nil,yyy,ccc,ddd,nil,nil,nil );
|
||||
checkTable( m, aaa,bbb,nil,nil,nil,nil,nil, aaa,bbb,nil,nil,nil,nil,nil );
|
||||
t.rawset("dd", zzz);
|
||||
checkTable( s, www,nil,xxx,ddd,nil,nil,nil, www,nil,xxx,ddd,nil,nil,nil );
|
||||
checkTable( t, aaa,yyy,ccc,zzz,nil,nil,nil, nil,yyy,ccc,zzz,nil,nil,nil );
|
||||
checkTable( m, aaa,bbb,nil,nil,nil,nil,nil, aaa,bbb,nil,nil,nil,nil,nil );
|
||||
|
||||
// set() invoking metatables
|
||||
s.set("ee", ppp);
|
||||
checkTable( s, www,nil,xxx,ddd,ppp,nil,nil, www,nil,xxx,ddd,ppp,nil,nil );
|
||||
checkTable( t, aaa,yyy,ccc,zzz,nil,nil,nil, nil,yyy,ccc,zzz,nil,nil,nil );
|
||||
checkTable( m, aaa,bbb,nil,nil,nil,nil,nil, aaa,bbb,nil,nil,nil,nil,nil );
|
||||
s.set("cc", qqq);
|
||||
checkTable( s, www,nil,qqq,ddd,ppp,nil,nil, www,nil,qqq,ddd,ppp,nil,nil );
|
||||
checkTable( t, aaa,yyy,ccc,zzz,nil,nil,nil, nil,yyy,ccc,zzz,nil,nil,nil );
|
||||
checkTable( m, aaa,bbb,nil,nil,nil,nil,nil, aaa,bbb,nil,nil,nil,nil,nil );
|
||||
t.set("ff", rrr);
|
||||
checkTable( s, www,nil,qqq,ddd,ppp,nil,nil, www,nil,qqq,ddd,ppp,nil,nil );
|
||||
checkTable( t, aaa,yyy,ccc,zzz,nil,rrr,nil, nil,yyy,ccc,zzz,nil,nil,nil );
|
||||
checkTable( m, aaa,bbb,nil,nil,nil,rrr,nil, aaa,bbb,nil,nil,nil,rrr,nil );
|
||||
t.set("dd", sss);
|
||||
checkTable( s, www,nil,qqq,ddd,ppp,nil,nil, www,nil,qqq,ddd,ppp,nil,nil );
|
||||
checkTable( t, aaa,yyy,ccc,sss,nil,rrr,nil, nil,yyy,ccc,sss,nil,nil,nil );
|
||||
checkTable( m, aaa,bbb,nil,nil,nil,rrr,nil, aaa,bbb,nil,nil,nil,rrr,nil );
|
||||
m.set("gg", ttt);
|
||||
checkTable( s, www,nil,qqq,ddd,ppp,nil,nil, www,nil,qqq,ddd,ppp,nil,nil );
|
||||
checkTable( t, aaa,yyy,ccc,sss,nil,rrr,ttt, nil,yyy,ccc,sss,nil,nil,nil );
|
||||
checkTable( m, aaa,bbb,nil,nil,nil,rrr,ttt, aaa,bbb,nil,nil,nil,rrr,ttt );
|
||||
|
||||
// make s fall back to t
|
||||
s.setmetatable(LuaValue.tableOf(new LuaValue[] {LuaValue.INDEX,t,LuaValue.NEWINDEX,t}));
|
||||
checkTable( s, www,yyy,qqq,ddd,ppp,rrr,ttt, www,nil,qqq,ddd,ppp,nil,nil );
|
||||
checkTable( t, aaa,yyy,ccc,sss,nil,rrr,ttt, nil,yyy,ccc,sss,nil,nil,nil );
|
||||
checkTable( m, aaa,bbb,nil,nil,nil,rrr,ttt, aaa,bbb,nil,nil,nil,rrr,ttt );
|
||||
s.set("aa", www);
|
||||
checkTable( s, www,yyy,qqq,ddd,ppp,rrr,ttt, www,nil,qqq,ddd,ppp,nil,nil );
|
||||
checkTable( t, aaa,yyy,ccc,sss,nil,rrr,ttt, nil,yyy,ccc,sss,nil,nil,nil );
|
||||
checkTable( m, aaa,bbb,nil,nil,nil,rrr,ttt, aaa,bbb,nil,nil,nil,rrr,ttt );
|
||||
s.set("bb", zzz);
|
||||
checkTable( s, www,zzz,qqq,ddd,ppp,rrr,ttt, www,nil,qqq,ddd,ppp,nil,nil );
|
||||
checkTable( t, aaa,zzz,ccc,sss,nil,rrr,ttt, nil,zzz,ccc,sss,nil,nil,nil );
|
||||
checkTable( m, aaa,bbb,nil,nil,nil,rrr,ttt, aaa,bbb,nil,nil,nil,rrr,ttt );
|
||||
s.set("ee", xxx);
|
||||
checkTable( s, www,zzz,qqq,ddd,xxx,rrr,ttt, www,nil,qqq,ddd,xxx,nil,nil );
|
||||
checkTable( t, aaa,zzz,ccc,sss,nil,rrr,ttt, nil,zzz,ccc,sss,nil,nil,nil );
|
||||
checkTable( m, aaa,bbb,nil,nil,nil,rrr,ttt, aaa,bbb,nil,nil,nil,rrr,ttt );
|
||||
s.set("ff", yyy);
|
||||
checkTable( s, www,zzz,qqq,ddd,xxx,yyy,ttt, www,nil,qqq,ddd,xxx,nil,nil );
|
||||
checkTable( t, aaa,zzz,ccc,sss,nil,yyy,ttt, nil,zzz,ccc,sss,nil,nil,nil );
|
||||
checkTable( m, aaa,bbb,nil,nil,nil,yyy,ttt, aaa,bbb,nil,nil,nil,yyy,ttt );
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
178
jse/src/test/java/org/luaj/vm2/OrphanedThreadTest.java
Normal file
178
jse/src/test/java/org/luaj/vm2/OrphanedThreadTest.java
Normal file
@@ -0,0 +1,178 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.luaj.vm2.lib.OneArgFunction;
|
||||
import org.luaj.vm2.lib.jse.JsePlatform;
|
||||
|
||||
|
||||
public class OrphanedThreadTest extends TestCase {
|
||||
|
||||
Globals globals;
|
||||
LuaThread luathread;
|
||||
WeakReference luathr_ref;
|
||||
LuaValue function;
|
||||
WeakReference func_ref;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
LuaThread.thread_orphan_check_interval = 5;
|
||||
globals = JsePlatform.standardGlobals();
|
||||
}
|
||||
|
||||
protected void tearDown() {
|
||||
LuaThread.thread_orphan_check_interval = 30000;
|
||||
}
|
||||
|
||||
public void testCollectOrphanedNormalThread() throws Exception {
|
||||
function = new NormalFunction(globals);
|
||||
doTest(LuaValue.TRUE, LuaValue.ZERO);
|
||||
}
|
||||
|
||||
public void testCollectOrphanedEarlyCompletionThread() throws Exception {
|
||||
function = new EarlyCompletionFunction(globals);
|
||||
doTest(LuaValue.TRUE, LuaValue.ZERO);
|
||||
}
|
||||
|
||||
public void testCollectOrphanedAbnormalThread() throws Exception {
|
||||
function = new AbnormalFunction(globals);
|
||||
doTest(LuaValue.FALSE, LuaValue.valueOf("abnormal condition"));
|
||||
}
|
||||
|
||||
public 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);
|
||||
}
|
||||
|
||||
public 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);
|
||||
}
|
||||
|
||||
public 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
89
jse/src/test/java/org/luaj/vm2/RequireClassTest.java
Normal file
89
jse/src/test/java/org/luaj/vm2/RequireClassTest.java
Normal file
@@ -0,0 +1,89 @@
|
||||
package org.luaj.vm2;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.luaj.vm2.lib.jse.JsePlatform;
|
||||
import org.luaj.vm2.require.RequireSampleClassCastExcep;
|
||||
import org.luaj.vm2.require.RequireSampleLoadLuaError;
|
||||
import org.luaj.vm2.require.RequireSampleLoadRuntimeExcep;
|
||||
|
||||
public class RequireClassTest extends TestCase {
|
||||
|
||||
private LuaTable globals;
|
||||
private LuaValue require;
|
||||
|
||||
public void setUp() {
|
||||
globals = JsePlatform.standardGlobals();
|
||||
require = globals.get("require");
|
||||
}
|
||||
|
||||
public void testLoadClass() {
|
||||
LuaValue result = globals.load(new org.luaj.vm2.require.RequireSampleSuccess());
|
||||
assertEquals( "require-sample-success-", result.tojstring() );
|
||||
}
|
||||
|
||||
public void testRequireClassSuccess() {
|
||||
LuaValue result = require.call( LuaValue.valueOf("org.luaj.vm2.require.RequireSampleSuccess") );
|
||||
assertEquals( "require-sample-success-org.luaj.vm2.require.RequireSampleSuccess", result.tojstring() );
|
||||
result = require.call( LuaValue.valueOf("org.luaj.vm2.require.RequireSampleSuccess") );
|
||||
assertEquals( "require-sample-success-org.luaj.vm2.require.RequireSampleSuccess", result.tojstring() );
|
||||
}
|
||||
|
||||
public 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() );
|
||||
}
|
||||
}
|
||||
|
||||
public 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() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
257
jse/src/test/java/org/luaj/vm2/ScriptDrivenTest.java
Normal file
257
jse/src/test/java/org/luaj/vm2/ScriptDrivenTest.java
Normal file
@@ -0,0 +1,257 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.luaj.vm2.lib.ResourceFinder;
|
||||
import org.luaj.vm2.lib.jse.JseProcess;
|
||||
import org.luaj.vm2.luajc.LuaJC;
|
||||
|
||||
abstract
|
||||
public class ScriptDrivenTest extends TestCase implements ResourceFinder {
|
||||
public static final boolean nocompile = "true".equals(System.getProperty("nocompile"));
|
||||
|
||||
public enum PlatformType {
|
||||
JME, JSE, LUAJIT,
|
||||
}
|
||||
|
||||
private final PlatformType platform;
|
||||
private final String subdir;
|
||||
protected Globals globals;
|
||||
|
||||
static final String zipdir = "test/lua/";
|
||||
static final String zipfile = "luaj3.0-tests.zip";
|
||||
|
||||
protected ScriptDrivenTest( PlatformType platform, String subdir ) {
|
||||
this.platform = platform;
|
||||
this.subdir = subdir;
|
||||
initGlobals();
|
||||
}
|
||||
|
||||
private void initGlobals() {
|
||||
switch ( platform ) {
|
||||
default:
|
||||
case JSE:
|
||||
case LUAJIT:
|
||||
globals = org.luaj.vm2.lib.jse.JsePlatform.debugGlobals();
|
||||
break;
|
||||
case JME:
|
||||
globals = org.luaj.vm2.lib.jme.JmePlatform.debugGlobals();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
initGlobals();
|
||||
globals.finder = this;
|
||||
}
|
||||
|
||||
// ResourceFinder implementation.
|
||||
public InputStream findResource(String filename) {
|
||||
InputStream is = findInPlainFile(filename);
|
||||
if (is != null) return is;
|
||||
is = findInPlainFileAsResource("",filename);
|
||||
if (is != null) return is;
|
||||
is = findInPlainFileAsResource("/",filename);
|
||||
if (is != null) return is;
|
||||
is = findInZipFileAsPlainFile(filename);
|
||||
if (is != null) return is;
|
||||
is = findInZipFileAsResource("",filename);
|
||||
if (is != null) return is;
|
||||
is = findInZipFileAsResource("/",filename);
|
||||
return is;
|
||||
}
|
||||
|
||||
private InputStream findInPlainFileAsResource(String prefix, String filename) {
|
||||
return getClass().getResourceAsStream(prefix + subdir + filename);
|
||||
}
|
||||
|
||||
private InputStream findInPlainFile(String filename) {
|
||||
try {
|
||||
File f = new File(zipdir+subdir+filename);
|
||||
if (f.exists())
|
||||
return new FileInputStream(f);
|
||||
} catch ( IOException ioe ) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private InputStream findInZipFileAsPlainFile(String filename) {
|
||||
URL zip;
|
||||
File file = new File(zipdir+zipfile);
|
||||
try {
|
||||
if ( file.exists() ) {
|
||||
zip = file.toURI().toURL();
|
||||
String path = "jar:"+zip.toExternalForm()+ "!/"+subdir+filename;
|
||||
URL url = new URL(path);
|
||||
return url.openStream();
|
||||
}
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
} catch (FileNotFoundException e) {
|
||||
// Ignore and return null.
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private InputStream findInZipFileAsResource(String prefix, String filename) {
|
||||
URL zip = null;
|
||||
zip = getClass().getResource(zipfile);
|
||||
if ( zip != null )
|
||||
try {
|
||||
String path = "jar:"+zip.toExternalForm()+ "!/"+subdir+filename;
|
||||
URL url = new URL(path);
|
||||
return url.openStream();
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// */
|
||||
protected void runTest(String testName) {
|
||||
try {
|
||||
// override print()
|
||||
final ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
final PrintStream oldps = globals.STDOUT;
|
||||
final PrintStream ps = new PrintStream( output );
|
||||
globals.STDOUT = ps;
|
||||
|
||||
// run the script
|
||||
try {
|
||||
LuaValue chunk = loadScript(testName, globals);
|
||||
chunk.call(LuaValue.valueOf(platform.toString()));
|
||||
|
||||
ps.flush();
|
||||
String actualOutput = new String(output.toByteArray());
|
||||
String expectedOutput = getExpectedOutput(testName);
|
||||
actualOutput = actualOutput.replaceAll("\r\n", "\n");
|
||||
expectedOutput = expectedOutput.replaceAll("\r\n", "\n");
|
||||
|
||||
assertEquals(expectedOutput, actualOutput);
|
||||
} finally {
|
||||
globals.STDOUT = oldps;
|
||||
ps.close();
|
||||
}
|
||||
} catch ( IOException ioe ) {
|
||||
throw new RuntimeException(ioe.toString());
|
||||
} catch ( InterruptedException ie ) {
|
||||
throw new RuntimeException(ie.toString());
|
||||
}
|
||||
}
|
||||
|
||||
protected LuaValue loadScript(String name, Globals globals) throws IOException {
|
||||
InputStream script = this.findResource(name+".lua");
|
||||
if ( script == null )
|
||||
fail("Could not load script for test case: " + name);
|
||||
try {
|
||||
switch ( this.platform ) {
|
||||
case LUAJIT:
|
||||
if ( nocompile ) {
|
||||
LuaValue c = (LuaValue) Class.forName(name).newInstance();
|
||||
return c;
|
||||
} else {
|
||||
LuaJC.install(globals);
|
||||
return globals.load(script, name, "bt", globals);
|
||||
}
|
||||
default:
|
||||
return globals.load(script, "@"+name+".lua", "bt", globals);
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
throw new IOException( e.toString() );
|
||||
} finally {
|
||||
script.close();
|
||||
}
|
||||
}
|
||||
|
||||
private String getExpectedOutput(final String name) throws IOException,
|
||||
InterruptedException {
|
||||
InputStream output = this.findResource(name+".out");
|
||||
if (output != null)
|
||||
try {
|
||||
return readString(output);
|
||||
} finally {
|
||||
output.close();
|
||||
}
|
||||
String expectedOutput = executeLuaProcess(name);
|
||||
if (expectedOutput == null)
|
||||
throw new IOException("Failed to get comparison output or run process for "+name);
|
||||
return expectedOutput;
|
||||
}
|
||||
|
||||
private String executeLuaProcess(String name) throws IOException, InterruptedException {
|
||||
InputStream script = findResource(name+".lua");
|
||||
if ( script == null )
|
||||
throw new IOException("Failed to find source file "+script);
|
||||
try {
|
||||
String luaCommand = System.getProperty("LUA_COMMAND");
|
||||
if ( luaCommand == null )
|
||||
luaCommand = "lua";
|
||||
String[] args = new String[] { luaCommand, "-", platform.toString() };
|
||||
return collectProcessOutput(args, script);
|
||||
} finally {
|
||||
script.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static String collectProcessOutput(String[] cmd, final InputStream input)
|
||||
throws IOException, InterruptedException {
|
||||
Runtime r = Runtime.getRuntime();
|
||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
new JseProcess(cmd, input, baos, System.err).waitFor();
|
||||
return new String(baos.toByteArray());
|
||||
}
|
||||
|
||||
private String readString(InputStream is) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
copy(is, baos);
|
||||
return new String(baos.toByteArray());
|
||||
}
|
||||
|
||||
private static void copy(InputStream is, OutputStream os) throws IOException {
|
||||
byte[] buf = new byte[1024];
|
||||
int r;
|
||||
while ((r = is.read(buf)) >= 0) {
|
||||
os.write(buf, 0, r);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
381
jse/src/test/java/org/luaj/vm2/StringTest.java
Normal file
381
jse/src/test/java/org/luaj/vm2/StringTest.java
Normal file
@@ -0,0 +1,381 @@
|
||||
package org.luaj.vm2;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.luaj.vm2.lib.jse.JsePlatform;
|
||||
|
||||
public class StringTest extends TestCase {
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
JsePlatform.standardGlobals();
|
||||
}
|
||||
|
||||
public void testToInputStream() throws IOException {
|
||||
LuaString str = LuaString.valueOf("Hello");
|
||||
|
||||
InputStream is = str.toInputStream();
|
||||
|
||||
assertEquals( 'H', is.read() );
|
||||
assertEquals( 'e', is.read() );
|
||||
assertEquals( 2, is.skip( 2 ) );
|
||||
assertEquals( 'o', is.read() );
|
||||
assertEquals( -1, is.read() );
|
||||
|
||||
assertTrue( is.markSupported() );
|
||||
|
||||
is.reset();
|
||||
|
||||
assertEquals( 'H', is.read() );
|
||||
is.mark( 4 );
|
||||
|
||||
assertEquals( 'e', is.read() );
|
||||
is.reset();
|
||||
assertEquals( 'e', is.read() );
|
||||
|
||||
LuaString substr = str.substring( 1, 4 );
|
||||
assertEquals( 3, substr.length() );
|
||||
|
||||
is.close();
|
||||
is = substr.toInputStream();
|
||||
|
||||
assertEquals( 'e', is.read() );
|
||||
assertEquals( 'l', is.read() );
|
||||
assertEquals( 'l', is.read() );
|
||||
assertEquals( -1, is.read() );
|
||||
|
||||
is = substr.toInputStream();
|
||||
is.reset();
|
||||
|
||||
assertEquals( 'e', is.read() );
|
||||
}
|
||||
|
||||
|
||||
private static final String userFriendly( String s ) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for ( int i=0, n=s.length(); i<n; i++ ) {
|
||||
int c = s.charAt(i);
|
||||
if ( c < ' ' || c >= 0x80 ) {
|
||||
sb.append( "\\u"+Integer.toHexString(0x10000+c).substring(1) );
|
||||
} else {
|
||||
sb.append( (char) c );
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void testUtf820482051() throws UnsupportedEncodingException {
|
||||
int i = 2048;
|
||||
char[] c = { (char) (i+0), (char) (i+1), (char) (i+2), (char) (i+3) };
|
||||
String before = new String(c)+" "+i+"-"+(i+4);
|
||||
LuaString ls = LuaString.valueOf(before);
|
||||
String after = ls.tojstring();
|
||||
assertEquals( userFriendly( before ), userFriendly( after ) );
|
||||
}
|
||||
|
||||
public void testUtf8() {
|
||||
for ( int i=4; i<0xffff; i+=4 ) {
|
||||
char[] c = { (char) (i+0), (char) (i+1), (char) (i+2), (char) (i+3) };
|
||||
String before = new String(c)+" "+i+"-"+(i+4);
|
||||
LuaString ls = LuaString.valueOf(before);
|
||||
String after = ls.tojstring();
|
||||
assertEquals( userFriendly( before ), userFriendly( after ) );
|
||||
}
|
||||
char[] c = { (char) (1), (char) (2), (char) (3) };
|
||||
String before = new String(c)+" 1-3";
|
||||
LuaString ls = LuaString.valueOf(before);
|
||||
String after = ls.tojstring();
|
||||
assertEquals( userFriendly( before ), userFriendly( after ) );
|
||||
}
|
||||
|
||||
public void testSpotCheckUtf8() throws UnsupportedEncodingException {
|
||||
byte[] bytes = {(byte)194,(byte)160,(byte)194,(byte)161,(byte)194,(byte)162,(byte)194,(byte)163,(byte)194,(byte)164};
|
||||
String expected = new String(bytes, "UTF8");
|
||||
String actual = LuaString.valueOf(bytes).tojstring();
|
||||
char[] d = actual.toCharArray();
|
||||
assertEquals(160, d[0]);
|
||||
assertEquals(161, d[1]);
|
||||
assertEquals(162, d[2]);
|
||||
assertEquals(163, d[3]);
|
||||
assertEquals(164, d[4]);
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
public void testNullTerminated() {
|
||||
char[] c = { 'a', 'b', 'c', '\0', 'd', 'e', 'f' };
|
||||
String before = new String(c);
|
||||
LuaString ls = LuaString.valueOf(before);
|
||||
String after = ls.tojstring();
|
||||
assertEquals( userFriendly( "abc\0def" ), userFriendly( after ) );
|
||||
}
|
||||
|
||||
public void testRecentStringsCacheDifferentHashcodes() {
|
||||
final byte[] abc = {'a', 'b', 'c' };
|
||||
final byte[] xyz = {'x', 'y', 'z' };
|
||||
final LuaString abc1 = LuaString.valueOf(abc);
|
||||
final LuaString xyz1 = LuaString.valueOf(xyz);
|
||||
final LuaString abc2 = LuaString.valueOf(abc);
|
||||
final LuaString xyz2 = LuaString.valueOf(xyz);
|
||||
final int mod = LuaString.RECENT_STRINGS_CACHE_SIZE;
|
||||
assertTrue(abc1.hashCode() % mod != xyz1.hashCode() % mod);
|
||||
assertSame(abc1, abc2);
|
||||
assertSame(xyz1, xyz2);
|
||||
}
|
||||
|
||||
public void testRecentStringsCacheHashCollisionCacheHit() {
|
||||
final byte[] abc = {'a', 'b', 'c' };
|
||||
final byte[] lyz = {'l', 'y', 'z' }; // chosen to have hash collision with 'abc'
|
||||
final LuaString abc1 = LuaString.valueOf(abc);
|
||||
final LuaString abc2 = LuaString.valueOf(abc); // in cache: 'abc'
|
||||
final LuaString lyz1 = LuaString.valueOf(lyz);
|
||||
final LuaString lyz2 = LuaString.valueOf(lyz); // in cache: 'lyz'
|
||||
final int mod = LuaString.RECENT_STRINGS_CACHE_SIZE;
|
||||
assertEquals(abc1.hashCode() % mod, lyz1.hashCode() % mod);
|
||||
assertNotSame(abc1, lyz1);
|
||||
assertFalse(abc1.equals(lyz1));
|
||||
assertSame(abc1, abc2);
|
||||
assertSame(lyz1, lyz2);
|
||||
}
|
||||
|
||||
public void testRecentStringsCacheHashCollisionCacheMiss() {
|
||||
final byte[] abc = {'a', 'b', 'c' };
|
||||
final byte[] lyz = {'l', 'y', 'z' }; // chosen to have hash collision with 'abc'
|
||||
final LuaString abc1 = LuaString.valueOf(abc);
|
||||
final LuaString lyz1 = LuaString.valueOf(lyz); // in cache: 'abc'
|
||||
final LuaString abc2 = LuaString.valueOf(abc); // in cache: 'lyz'
|
||||
final LuaString lyz2 = LuaString.valueOf(lyz); // in cache: 'abc'
|
||||
final int mod = LuaString.RECENT_STRINGS_CACHE_SIZE;
|
||||
assertEquals(abc1.hashCode() % mod, lyz1.hashCode() % mod);
|
||||
assertNotSame(abc1, lyz1);
|
||||
assertFalse(abc1.equals(lyz1));
|
||||
assertNotSame(abc1, abc2);
|
||||
assertNotSame(lyz1, lyz2);
|
||||
}
|
||||
|
||||
public void testRecentStringsLongStrings() {
|
||||
byte[] abc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".getBytes();
|
||||
assertTrue(abc.length > LuaString.RECENT_STRINGS_MAX_LENGTH);
|
||||
LuaString abc1 = LuaString.valueOf(abc);
|
||||
LuaString abc2 = LuaString.valueOf(abc);
|
||||
assertNotSame(abc1, abc2);
|
||||
}
|
||||
|
||||
public void testRecentStringsUsingJavaStrings() {
|
||||
final String abc = "abc";
|
||||
final String lyz = "lyz"; // chosen to have hash collision with 'abc'
|
||||
final String xyz = "xyz";
|
||||
|
||||
final LuaString abc1 = LuaString.valueOf(abc);
|
||||
final LuaString abc2 = LuaString.valueOf(abc);
|
||||
final LuaString lyz1 = LuaString.valueOf(lyz);
|
||||
final LuaString lyz2 = LuaString.valueOf(lyz);
|
||||
final LuaString xyz1 = LuaString.valueOf(xyz);
|
||||
final LuaString xyz2 = LuaString.valueOf(xyz);
|
||||
final int mod = LuaString.RECENT_STRINGS_CACHE_SIZE;
|
||||
assertEquals(abc1.hashCode() % mod, lyz1.hashCode() % mod);
|
||||
assertFalse(abc1.hashCode() % mod == xyz1.hashCode() % mod);
|
||||
assertSame(abc1, abc2);
|
||||
assertSame(lyz1, lyz2);
|
||||
assertSame(xyz1, xyz2);
|
||||
|
||||
final LuaString abc3 = LuaString.valueOf(abc);
|
||||
final LuaString lyz3 = LuaString.valueOf(lyz);
|
||||
final LuaString xyz3 = LuaString.valueOf(xyz);
|
||||
|
||||
final LuaString abc4 = LuaString.valueOf(abc);
|
||||
final LuaString lyz4 = LuaString.valueOf(lyz);
|
||||
final LuaString xyz4 = LuaString.valueOf(xyz);
|
||||
assertNotSame(abc3, abc4); // because of hash collision
|
||||
assertNotSame(lyz3, lyz4); // because of hash collision
|
||||
assertSame(xyz3, xyz4); // because hashes do not collide
|
||||
}
|
||||
|
||||
public void testLongSubstringGetsOldBacking() {
|
||||
LuaString src = LuaString.valueOf("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
||||
LuaString sub1 = src.substring(10, 40);
|
||||
assertSame(src.m_bytes, sub1.m_bytes);
|
||||
assertEquals(sub1.m_offset, 10);
|
||||
assertEquals(sub1.m_length, 30);
|
||||
}
|
||||
|
||||
public void testShortSubstringGetsNewBacking() {
|
||||
LuaString src = LuaString.valueOf("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
||||
LuaString sub1 = src.substring(10, 20);
|
||||
LuaString sub2 = src.substring(10, 20);
|
||||
assertEquals(sub1.m_offset, 0);
|
||||
assertEquals(sub1.m_length, 10);
|
||||
assertSame(sub1, sub2);
|
||||
assertFalse(src.m_bytes == sub1.m_bytes);
|
||||
}
|
||||
|
||||
public void testShortSubstringOfVeryLongStringGetsNewBacking() {
|
||||
LuaString src = LuaString.valueOf(
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" +
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" );
|
||||
LuaString sub1 = src.substring(10, 50);
|
||||
LuaString sub2 = src.substring(10, 50);
|
||||
assertEquals(sub1.m_offset, 0);
|
||||
assertEquals(sub1.m_length, 40);
|
||||
assertFalse(sub1 == sub2);
|
||||
assertFalse(src.m_bytes == sub1.m_bytes);
|
||||
}
|
||||
|
||||
public void testIndexOfByteInSubstring() {
|
||||
LuaString str = LuaString.valueOf("abcdef:ghi");
|
||||
LuaString sub = str.substring(2, 10);
|
||||
assertEquals(10, str.m_length);
|
||||
assertEquals(8, sub.m_length);
|
||||
assertEquals(0, str.m_offset);
|
||||
assertEquals(2, sub.m_offset);
|
||||
|
||||
assertEquals(6, str.indexOf((byte) ':', 0));
|
||||
assertEquals(6, str.indexOf((byte) ':', 2));
|
||||
assertEquals(6, str.indexOf((byte) ':', 6));
|
||||
assertEquals(-1, str.indexOf((byte) ':', 7));
|
||||
assertEquals(-1, str.indexOf((byte) ':', 9));
|
||||
assertEquals(9, str.indexOf((byte) 'i', 0));
|
||||
assertEquals(9, str.indexOf((byte) 'i', 2));
|
||||
assertEquals(9, str.indexOf((byte) 'i', 9));
|
||||
assertEquals(-1, str.indexOf((byte) 'z', 0));
|
||||
assertEquals(-1, str.indexOf((byte) 'z', 2));
|
||||
assertEquals(-1, str.indexOf((byte) 'z', 9));
|
||||
|
||||
assertEquals(4, sub.indexOf((byte) ':', 0));
|
||||
assertEquals(4, sub.indexOf((byte) ':', 2));
|
||||
assertEquals(4, sub.indexOf((byte) ':', 4));
|
||||
assertEquals(-1, sub.indexOf((byte) ':', 5));
|
||||
assertEquals(-1, sub.indexOf((byte) ':', 7));
|
||||
assertEquals(7, sub.indexOf((byte) 'i', 0));
|
||||
assertEquals(7, sub.indexOf((byte) 'i', 2));
|
||||
assertEquals(7, sub.indexOf((byte) 'i', 7));
|
||||
assertEquals(-1, sub.indexOf((byte) 'z', 0));
|
||||
assertEquals(-1, sub.indexOf((byte) 'z', 2));
|
||||
assertEquals(-1, sub.indexOf((byte) 'z', 7));
|
||||
}
|
||||
|
||||
public void testIndexOfPatternInSubstring() {
|
||||
LuaString str = LuaString.valueOf("abcdef:ghi");
|
||||
LuaString sub = str.substring(2, 10);
|
||||
assertEquals(10, str.m_length);
|
||||
assertEquals(8, sub.m_length);
|
||||
assertEquals(0, str.m_offset);
|
||||
assertEquals(2, sub.m_offset);
|
||||
|
||||
LuaString pat = LuaString.valueOf(":");
|
||||
LuaString i = LuaString.valueOf("i");
|
||||
LuaString xyz = LuaString.valueOf("xyz");
|
||||
|
||||
assertEquals(6, str.indexOf(pat, 0));
|
||||
assertEquals(6, str.indexOf(pat, 2));
|
||||
assertEquals(6, str.indexOf(pat, 6));
|
||||
assertEquals(-1, str.indexOf(pat, 7));
|
||||
assertEquals(-1, str.indexOf(pat, 9));
|
||||
assertEquals(9, str.indexOf(i, 0));
|
||||
assertEquals(9, str.indexOf(i, 2));
|
||||
assertEquals(9, str.indexOf(i, 9));
|
||||
assertEquals(-1, str.indexOf(xyz, 0));
|
||||
assertEquals(-1, str.indexOf(xyz, 2));
|
||||
assertEquals(-1, str.indexOf(xyz, 9));
|
||||
|
||||
assertEquals(4, sub.indexOf(pat, 0));
|
||||
assertEquals(4, sub.indexOf(pat, 2));
|
||||
assertEquals(4, sub.indexOf(pat, 4));
|
||||
assertEquals(-1, sub.indexOf(pat, 5));
|
||||
assertEquals(-1, sub.indexOf(pat, 7));
|
||||
assertEquals(7, sub.indexOf(i, 0));
|
||||
assertEquals(7, sub.indexOf(i, 2));
|
||||
assertEquals(7, sub.indexOf(i, 7));
|
||||
assertEquals(-1, sub.indexOf(xyz, 0));
|
||||
assertEquals(-1, sub.indexOf(xyz, 2));
|
||||
assertEquals(-1, sub.indexOf(xyz, 7));
|
||||
}
|
||||
|
||||
public void testLastIndexOfPatternInSubstring() {
|
||||
LuaString str = LuaString.valueOf("abcdef:ghi");
|
||||
LuaString sub = str.substring(2, 10);
|
||||
assertEquals(10, str.m_length);
|
||||
assertEquals(8, sub.m_length);
|
||||
assertEquals(0, str.m_offset);
|
||||
assertEquals(2, sub.m_offset);
|
||||
|
||||
LuaString pat = LuaString.valueOf(":");
|
||||
LuaString i = LuaString.valueOf("i");
|
||||
LuaString xyz = LuaString.valueOf("xyz");
|
||||
|
||||
assertEquals(6, str.lastIndexOf(pat));
|
||||
assertEquals(9, str.lastIndexOf(i));
|
||||
assertEquals(-1, str.lastIndexOf(xyz));
|
||||
|
||||
assertEquals(4, sub.lastIndexOf(pat));
|
||||
assertEquals(7, sub.lastIndexOf(i));
|
||||
assertEquals(-1, sub.lastIndexOf(xyz));
|
||||
}
|
||||
|
||||
public void testIndexOfAnyInSubstring() {
|
||||
LuaString str = LuaString.valueOf("abcdef:ghi");
|
||||
LuaString sub = str.substring(2, 10);
|
||||
assertEquals(10, str.m_length);
|
||||
assertEquals(8, sub.m_length);
|
||||
assertEquals(0, str.m_offset);
|
||||
assertEquals(2, sub.m_offset);
|
||||
|
||||
LuaString ghi = LuaString.valueOf("ghi");
|
||||
LuaString ihg = LuaString.valueOf("ihg");
|
||||
LuaString ijk = LuaString.valueOf("ijk");
|
||||
LuaString kji= LuaString.valueOf("kji");
|
||||
LuaString xyz = LuaString.valueOf("xyz");
|
||||
LuaString ABCdEFGHIJKL = LuaString.valueOf("ABCdEFGHIJKL");
|
||||
LuaString EFGHIJKL = ABCdEFGHIJKL.substring(4, 12);
|
||||
LuaString CdEFGHIJ = ABCdEFGHIJKL.substring(2, 10);
|
||||
assertEquals(4, EFGHIJKL.m_offset);
|
||||
assertEquals(2, CdEFGHIJ.m_offset);
|
||||
|
||||
assertEquals(7, str.indexOfAny(ghi));
|
||||
assertEquals(7, str.indexOfAny(ihg));
|
||||
assertEquals(9, str.indexOfAny(ijk));
|
||||
assertEquals(9, str.indexOfAny(kji));
|
||||
assertEquals(-1, str.indexOfAny(xyz));
|
||||
assertEquals(3, str.indexOfAny(CdEFGHIJ));
|
||||
assertEquals(-1, str.indexOfAny(EFGHIJKL));
|
||||
|
||||
assertEquals(5, sub.indexOfAny(ghi));
|
||||
assertEquals(5, sub.indexOfAny(ihg));
|
||||
assertEquals(7, sub.indexOfAny(ijk));
|
||||
assertEquals(7, sub.indexOfAny(kji));
|
||||
assertEquals(-1, sub.indexOfAny(xyz));
|
||||
assertEquals(1, sub.indexOfAny(CdEFGHIJ));
|
||||
assertEquals(-1, sub.indexOfAny(EFGHIJKL));
|
||||
}
|
||||
|
||||
public void testMatchShortPatterns() {
|
||||
LuaValue[] args = { LuaString.valueOf("%bxy") };
|
||||
LuaString _ = 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, _.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));
|
||||
}
|
||||
}
|
||||
320
jse/src/test/java/org/luaj/vm2/TableHashTest.java
Normal file
320
jse/src/test/java/org/luaj/vm2/TableHashTest.java
Normal file
@@ -0,0 +1,320 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.TwoArgFunction;
|
||||
|
||||
/**
|
||||
* Tests for tables used as lists.
|
||||
*/
|
||||
public class TableHashTest extends TestCase {
|
||||
|
||||
protected LuaTable new_Table() {
|
||||
return new LuaTable();
|
||||
}
|
||||
|
||||
protected LuaTable new_Table(int n,int m) {
|
||||
return new LuaTable(n,m);
|
||||
}
|
||||
|
||||
public void testSetRemove() {
|
||||
LuaTable t = new_Table();
|
||||
|
||||
assertEquals( 0, t.getHashLength() );
|
||||
assertEquals( 0, t.length() );
|
||||
assertEquals( 0, t.keyCount() );
|
||||
|
||||
String[] keys = { "abc", "def", "ghi", "jkl", "mno", "pqr", "stu", "wxy", "z01",
|
||||
"cd", "ef", "g", "hi", "jk", "lm", "no", "pq", "rs", };
|
||||
int[] capacities = { 0, 2, 2, 4, 4, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 32, 32, 32 };
|
||||
for ( int i = 0; i < keys.length; ++i ) {
|
||||
assertEquals( capacities[i], t.getHashLength() );
|
||||
String si = "Test Value! "+i;
|
||||
t.set( keys[i], si );
|
||||
assertEquals( 0, t.length() );
|
||||
assertEquals( i+1, t.keyCount() );
|
||||
}
|
||||
assertEquals( capacities[keys.length], t.getHashLength() );
|
||||
for ( int i = 0; i < keys.length; ++i ) {
|
||||
LuaValue vi = LuaString.valueOf( "Test Value! "+i );
|
||||
assertEquals( vi, t.get( keys[i] ) );
|
||||
assertEquals( vi, t.get( LuaString.valueOf(keys[i]) ) );
|
||||
assertEquals( vi, t.rawget( keys[i] ) );
|
||||
assertEquals( vi, t.rawget( keys[i] ) );
|
||||
}
|
||||
|
||||
// replace with new values
|
||||
for ( int i = 0; i < keys.length; ++i ) {
|
||||
t.set( keys[i], LuaString.valueOf( "Replacement Value! "+i ) );
|
||||
assertEquals( 0, t.length() );
|
||||
assertEquals( keys.length, t.keyCount() );
|
||||
assertEquals( capacities[keys.length], t.getHashLength() );
|
||||
}
|
||||
for ( int i = 0; i < keys.length; ++i ) {
|
||||
LuaValue vi = LuaString.valueOf( "Replacement Value! "+i );
|
||||
assertEquals( vi, t.get( keys[i] ) );
|
||||
}
|
||||
|
||||
// remove
|
||||
for ( int i = 0; i < keys.length; ++i ) {
|
||||
t.set( keys[i], LuaValue.NIL );
|
||||
assertEquals( 0, t.length() );
|
||||
assertEquals( keys.length-i-1, t.keyCount() );
|
||||
if ( i<keys.length-1 )
|
||||
assertEquals( capacities[keys.length], t.getHashLength() );
|
||||
else
|
||||
assertTrue( 0<=t.getHashLength() );
|
||||
}
|
||||
for ( int i = 0; i < keys.length; ++i ) {
|
||||
assertEquals( LuaValue.NIL, t.get( keys[i] ) );
|
||||
}
|
||||
}
|
||||
|
||||
public void testIndexMetatag() {
|
||||
LuaTable t = new_Table();
|
||||
LuaTable mt = new_Table();
|
||||
LuaTable fb = new_Table();
|
||||
|
||||
// set basic values
|
||||
t.set( "ppp", "abc" );
|
||||
t.set( 123, "def" );
|
||||
mt.set(LuaValue.INDEX, fb);
|
||||
fb.set( "qqq", "ghi" );
|
||||
fb.set( 456, "jkl" );
|
||||
|
||||
// check before setting metatable
|
||||
assertEquals( "abc", t.get("ppp").tojstring() );
|
||||
assertEquals( "def", t.get(123).tojstring() );
|
||||
assertEquals( "nil", t.get("qqq").tojstring() );
|
||||
assertEquals( "nil", t.get(456).tojstring() );
|
||||
assertEquals( "nil", fb.get("ppp").tojstring() );
|
||||
assertEquals( "nil", fb.get(123).tojstring() );
|
||||
assertEquals( "ghi", fb.get("qqq").tojstring() );
|
||||
assertEquals( "jkl", fb.get(456).tojstring() );
|
||||
assertEquals( "nil", mt.get("ppp").tojstring() );
|
||||
assertEquals( "nil", mt.get(123).tojstring() );
|
||||
assertEquals( "nil", mt.get("qqq").tojstring() );
|
||||
assertEquals( "nil", mt.get(456).tojstring() );
|
||||
|
||||
// check before setting metatable
|
||||
t.setmetatable(mt);
|
||||
assertEquals( mt, t.getmetatable() );
|
||||
assertEquals( "abc", t.get("ppp").tojstring() );
|
||||
assertEquals( "def", t.get(123).tojstring() );
|
||||
assertEquals( "ghi", t.get("qqq").tojstring() );
|
||||
assertEquals( "jkl", t.get(456).tojstring() );
|
||||
assertEquals( "nil", fb.get("ppp").tojstring() );
|
||||
assertEquals( "nil", fb.get(123).tojstring() );
|
||||
assertEquals( "ghi", fb.get("qqq").tojstring() );
|
||||
assertEquals( "jkl", fb.get(456).tojstring() );
|
||||
assertEquals( "nil", mt.get("ppp").tojstring() );
|
||||
assertEquals( "nil", mt.get(123).tojstring() );
|
||||
assertEquals( "nil", mt.get("qqq").tojstring() );
|
||||
assertEquals( "nil", mt.get(456).tojstring() );
|
||||
|
||||
// set metatable to metatable without values
|
||||
t.setmetatable(fb);
|
||||
assertEquals( "abc", t.get("ppp").tojstring() );
|
||||
assertEquals( "def", t.get(123).tojstring() );
|
||||
assertEquals( "nil", t.get("qqq").tojstring() );
|
||||
assertEquals( "nil", t.get(456).tojstring() );
|
||||
|
||||
// set metatable to null
|
||||
t.setmetatable(null);
|
||||
assertEquals( "abc", t.get("ppp").tojstring() );
|
||||
assertEquals( "def", t.get(123).tojstring() );
|
||||
assertEquals( "nil", t.get("qqq").tojstring() );
|
||||
assertEquals( "nil", t.get(456).tojstring() );
|
||||
}
|
||||
|
||||
public void testIndexFunction() {
|
||||
final LuaTable t = new_Table();
|
||||
final LuaTable mt = new_Table();
|
||||
|
||||
final TwoArgFunction fb = new TwoArgFunction() {
|
||||
public LuaValue call(LuaValue tbl, LuaValue key) {
|
||||
assertEquals(tbl, t);
|
||||
return valueOf("from mt: "+key);
|
||||
}
|
||||
};
|
||||
|
||||
// set basic values
|
||||
t.set( "ppp", "abc" );
|
||||
t.set( 123, "def" );
|
||||
mt.set(LuaValue.INDEX, fb);
|
||||
|
||||
// check before setting metatable
|
||||
assertEquals( "abc", t.get("ppp").tojstring() );
|
||||
assertEquals( "def", t.get(123).tojstring() );
|
||||
assertEquals( "nil", t.get("qqq").tojstring() );
|
||||
assertEquals( "nil", t.get(456).tojstring() );
|
||||
|
||||
|
||||
// check before setting metatable
|
||||
t.setmetatable(mt);
|
||||
assertEquals( mt, t.getmetatable() );
|
||||
assertEquals( "abc", t.get("ppp").tojstring() );
|
||||
assertEquals( "def", t.get(123).tojstring() );
|
||||
assertEquals( "from mt: qqq", t.get("qqq").tojstring() );
|
||||
assertEquals( "from mt: 456", t.get(456).tojstring() );
|
||||
|
||||
// use raw set
|
||||
t.rawset("qqq", "alt-qqq");
|
||||
t.rawset(456, "alt-456");
|
||||
assertEquals( "abc", t.get("ppp").tojstring() );
|
||||
assertEquals( "def", t.get(123).tojstring() );
|
||||
assertEquals( "alt-qqq", t.get("qqq").tojstring() );
|
||||
assertEquals( "alt-456", t.get(456).tojstring() );
|
||||
|
||||
// remove using raw set
|
||||
t.rawset("qqq", LuaValue.NIL);
|
||||
t.rawset(456, LuaValue.NIL);
|
||||
assertEquals( "abc", t.get("ppp").tojstring() );
|
||||
assertEquals( "def", t.get(123).tojstring() );
|
||||
assertEquals( "from mt: qqq", t.get("qqq").tojstring() );
|
||||
assertEquals( "from mt: 456", t.get(456).tojstring() );
|
||||
|
||||
// set metatable to null
|
||||
t.setmetatable(null);
|
||||
assertEquals( "abc", t.get("ppp").tojstring() );
|
||||
assertEquals( "def", t.get(123).tojstring() );
|
||||
assertEquals( "nil", t.get("qqq").tojstring() );
|
||||
assertEquals( "nil", t.get(456).tojstring() );
|
||||
}
|
||||
|
||||
public void testNext() {
|
||||
final LuaTable t = new_Table();
|
||||
assertEquals( LuaValue.NIL, t.next(LuaValue.NIL) );
|
||||
|
||||
// insert array elements
|
||||
t.set( 1, "one" );
|
||||
assertEquals( LuaValue.valueOf(1), t.next(LuaValue.NIL).arg(1) );
|
||||
assertEquals( LuaValue.valueOf("one"), t.next(LuaValue.NIL).arg(2) );
|
||||
assertEquals( LuaValue.NIL, t.next(LuaValue.ONE) );
|
||||
t.set( 2, "two" );
|
||||
assertEquals( LuaValue.valueOf(1), t.next(LuaValue.NIL).arg(1) );
|
||||
assertEquals( LuaValue.valueOf("one"), t.next(LuaValue.NIL).arg(2) );
|
||||
assertEquals( LuaValue.valueOf(2), t.next(LuaValue.ONE).arg(1) );
|
||||
assertEquals( LuaValue.valueOf("two"), t.next(LuaValue.ONE).arg(2) );
|
||||
assertEquals( LuaValue.NIL, t.next(LuaValue.valueOf(2)) );
|
||||
|
||||
// insert hash elements
|
||||
t.set( "aa", "aaa" );
|
||||
assertEquals( LuaValue.valueOf(1), t.next(LuaValue.NIL).arg(1) );
|
||||
assertEquals( LuaValue.valueOf("one"), t.next(LuaValue.NIL).arg(2) );
|
||||
assertEquals( LuaValue.valueOf(2), t.next(LuaValue.ONE).arg(1) );
|
||||
assertEquals( LuaValue.valueOf("two"), t.next(LuaValue.ONE).arg(2) );
|
||||
assertEquals( LuaValue.valueOf("aa"), t.next(LuaValue.valueOf(2)).arg(1) );
|
||||
assertEquals( LuaValue.valueOf("aaa"), t.next(LuaValue.valueOf(2)).arg(2) );
|
||||
assertEquals( LuaValue.NIL, t.next(LuaValue.valueOf("aa")) );
|
||||
t.set( "bb", "bbb" );
|
||||
assertEquals( LuaValue.valueOf(1), t.next(LuaValue.NIL).arg(1) );
|
||||
assertEquals( LuaValue.valueOf("one"), t.next(LuaValue.NIL).arg(2) );
|
||||
assertEquals( LuaValue.valueOf(2), t.next(LuaValue.ONE).arg(1) );
|
||||
assertEquals( LuaValue.valueOf("two"), t.next(LuaValue.ONE).arg(2) );
|
||||
assertEquals( LuaValue.valueOf("aa"), t.next(LuaValue.valueOf(2)).arg(1) );
|
||||
assertEquals( LuaValue.valueOf("aaa"), t.next(LuaValue.valueOf(2)).arg(2) );
|
||||
assertEquals( LuaValue.valueOf("bb"), t.next(LuaValue.valueOf("aa")).arg(1) );
|
||||
assertEquals( LuaValue.valueOf("bbb"), t.next(LuaValue.valueOf("aa")).arg(2) );
|
||||
assertEquals( LuaValue.NIL, t.next(LuaValue.valueOf("bb")) );
|
||||
}
|
||||
|
||||
public void testLoopWithRemoval() {
|
||||
final LuaTable t = new_Table();
|
||||
|
||||
t.set( LuaValue.valueOf(1), LuaValue.valueOf("1") );
|
||||
t.set( LuaValue.valueOf(3), LuaValue.valueOf("3") );
|
||||
t.set( LuaValue.valueOf(8), LuaValue.valueOf("4") );
|
||||
t.set( LuaValue.valueOf(17), LuaValue.valueOf("5") );
|
||||
t.set( LuaValue.valueOf(26), LuaValue.valueOf("6") );
|
||||
t.set( LuaValue.valueOf(35), LuaValue.valueOf("7") );
|
||||
t.set( LuaValue.valueOf(42), LuaValue.valueOf("8") );
|
||||
t.set( LuaValue.valueOf(60), LuaValue.valueOf("10") );
|
||||
t.set( LuaValue.valueOf(63), LuaValue.valueOf("11") );
|
||||
|
||||
Varargs entry = t.next(LuaValue.NIL);
|
||||
while ( !entry.isnil(1) ) {
|
||||
LuaValue k = entry.arg1();
|
||||
LuaValue v = entry.arg(2);
|
||||
if ( ( k.toint() & 1 ) == 0 ) {
|
||||
t.set( k, LuaValue.NIL );
|
||||
}
|
||||
entry = t.next(k);
|
||||
}
|
||||
|
||||
int numEntries = 0;
|
||||
entry = t.next(LuaValue.NIL);
|
||||
while ( !entry.isnil(1) ) {
|
||||
LuaValue k = entry.arg1();
|
||||
// Only odd keys should remain
|
||||
assertTrue( ( k.toint() & 1 ) == 1 );
|
||||
numEntries++;
|
||||
entry = t.next(k);
|
||||
}
|
||||
assertEquals( 5, numEntries );
|
||||
}
|
||||
|
||||
public void testLoopWithRemovalAndSet() {
|
||||
final LuaTable t = new_Table();
|
||||
|
||||
t.set( LuaValue.valueOf(1), LuaValue.valueOf("1") );
|
||||
t.set( LuaValue.valueOf(3), LuaValue.valueOf("3") );
|
||||
t.set( LuaValue.valueOf(8), LuaValue.valueOf("4") );
|
||||
t.set( LuaValue.valueOf(17), LuaValue.valueOf("5") );
|
||||
t.set( LuaValue.valueOf(26), LuaValue.valueOf("6") );
|
||||
t.set( LuaValue.valueOf(35), LuaValue.valueOf("7") );
|
||||
t.set( LuaValue.valueOf(42), LuaValue.valueOf("8") );
|
||||
t.set( LuaValue.valueOf(60), LuaValue.valueOf("10") );
|
||||
t.set( LuaValue.valueOf(63), LuaValue.valueOf("11") );
|
||||
|
||||
Varargs entry = t.next(LuaValue.NIL);
|
||||
Varargs entry2 = entry;
|
||||
while ( !entry.isnil(1) ) {
|
||||
LuaValue k = entry.arg1();
|
||||
LuaValue v = entry.arg(2);
|
||||
if ( ( k.toint() & 1 ) == 0 ) {
|
||||
t.set( k, LuaValue.NIL );
|
||||
} else {
|
||||
t.set( k, v.tonumber() );
|
||||
entry2 = t.next(entry2.arg1());
|
||||
}
|
||||
entry = t.next(k);
|
||||
}
|
||||
|
||||
int numEntries = 0;
|
||||
entry = t.next(LuaValue.NIL);
|
||||
while ( !entry.isnil(1) ) {
|
||||
LuaValue k = entry.arg1();
|
||||
// Only odd keys should remain
|
||||
assertTrue( ( k.toint() & 1 ) == 1 );
|
||||
assertTrue( entry.arg(2).type() == LuaValue.TNUMBER );
|
||||
numEntries++;
|
||||
entry = t.next(k);
|
||||
}
|
||||
assertEquals( 5, numEntries );
|
||||
}
|
||||
}
|
||||
419
jse/src/test/java/org/luaj/vm2/TableTest.java
Normal file
419
jse/src/test/java/org/luaj/vm2/TableTest.java
Normal file
@@ -0,0 +1,419 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Vector;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class TableTest extends TestCase {
|
||||
|
||||
protected LuaTable new_Table() {
|
||||
return new LuaTable();
|
||||
}
|
||||
|
||||
protected LuaTable new_Table(int n,int m) {
|
||||
return new LuaTable(n,m);
|
||||
}
|
||||
|
||||
private int keyCount(LuaTable t) {
|
||||
return keys(t).length;
|
||||
}
|
||||
|
||||
private LuaValue[] keys(LuaTable t) {
|
||||
ArrayList<LuaValue> l = new ArrayList<LuaValue>();
|
||||
LuaValue k = LuaValue.NIL;
|
||||
while ( true ) {
|
||||
Varargs n = t.next(k);
|
||||
if ( (k = n.arg1()).isnil() )
|
||||
break;
|
||||
l.add( k );
|
||||
}
|
||||
return l.toArray(new LuaValue[t.length()]);
|
||||
}
|
||||
|
||||
|
||||
public void testInOrderIntegerKeyInsertion() {
|
||||
LuaTable t = new_Table();
|
||||
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
t.set( i, LuaValue.valueOf( "Test Value! "+i ) );
|
||||
}
|
||||
|
||||
// Ensure all keys are still there.
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
assertEquals( "Test Value! " + i, t.get( i ).tojstring() );
|
||||
}
|
||||
|
||||
// Ensure capacities make sense
|
||||
assertEquals( 0, t.getHashLength() );
|
||||
|
||||
assertTrue( t.getArrayLength() >= 32 );
|
||||
assertTrue( t.getArrayLength() <= 64 );
|
||||
|
||||
}
|
||||
|
||||
public void testRekeyCount() {
|
||||
LuaTable t = new_Table();
|
||||
|
||||
// NOTE: This order of insertion is important.
|
||||
t.set(3, LuaInteger.valueOf(3));
|
||||
t.set(1, LuaInteger.valueOf(1));
|
||||
t.set(5, LuaInteger.valueOf(5));
|
||||
t.set(4, LuaInteger.valueOf(4));
|
||||
t.set(6, LuaInteger.valueOf(6));
|
||||
t.set(2, LuaInteger.valueOf(2));
|
||||
|
||||
for ( int i = 1; i < 6; ++i ) {
|
||||
assertEquals(LuaInteger.valueOf(i), t.get(i));
|
||||
}
|
||||
|
||||
assertTrue( t.getArrayLength() >= 3 );
|
||||
assertTrue( t.getArrayLength() <= 12 );
|
||||
assertTrue( t.getHashLength() <= 3 );
|
||||
}
|
||||
|
||||
public void testOutOfOrderIntegerKeyInsertion() {
|
||||
LuaTable t = new_Table();
|
||||
|
||||
for ( int i = 32; i > 0; --i ) {
|
||||
t.set( i, LuaValue.valueOf( "Test Value! "+i ) );
|
||||
}
|
||||
|
||||
// Ensure all keys are still there.
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
assertEquals( "Test Value! "+i, t.get( i ).tojstring() );
|
||||
}
|
||||
|
||||
// Ensure capacities make sense
|
||||
assertEquals( 32, t.getArrayLength() );
|
||||
assertEquals( 0, t.getHashLength() );
|
||||
}
|
||||
|
||||
public void testStringAndIntegerKeys() {
|
||||
LuaTable t = new_Table();
|
||||
|
||||
for ( int i = 0; i < 10; ++i ) {
|
||||
LuaString str = LuaValue.valueOf( String.valueOf( i ) );
|
||||
t.set( i, str );
|
||||
t.set( str, LuaInteger.valueOf( i ) );
|
||||
}
|
||||
|
||||
assertTrue( t.getArrayLength() >= 8 ); // 1, 2, ..., 9
|
||||
assertTrue( t.getArrayLength() <= 16 );
|
||||
assertTrue( t.getHashLength() >= 11 ); // 0, "0", "1", ..., "9"
|
||||
assertTrue( t.getHashLength() <= 33 );
|
||||
|
||||
LuaValue[] keys = keys(t);
|
||||
|
||||
int intKeys = 0;
|
||||
int stringKeys = 0;
|
||||
|
||||
assertEquals( 20, keys.length );
|
||||
for ( int i = 0; i < keys.length; ++i ) {
|
||||
LuaValue k = keys[i];
|
||||
|
||||
if ( k instanceof LuaInteger ) {
|
||||
final int ik = k.toint();
|
||||
assertTrue( ik >= 0 && ik < 10 );
|
||||
final int mask = 1 << ik;
|
||||
assertTrue( ( intKeys & mask ) == 0 );
|
||||
intKeys |= mask;
|
||||
} else if ( k instanceof LuaString ) {
|
||||
final int ik = Integer.parseInt( k.strvalue().tojstring() );
|
||||
assertEquals( String.valueOf( ik ), k.strvalue().tojstring() );
|
||||
assertTrue( ik >= 0 && ik < 10 );
|
||||
final int mask = 1 << ik;
|
||||
assertTrue( "Key \""+ik+"\" found more than once", ( stringKeys & mask ) == 0 );
|
||||
stringKeys |= mask;
|
||||
} else {
|
||||
fail( "Unexpected type of key found" );
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals( 0x03FF, intKeys );
|
||||
assertEquals( 0x03FF, stringKeys );
|
||||
}
|
||||
|
||||
public void testBadInitialCapacity() {
|
||||
LuaTable t = new_Table(0, 1);
|
||||
|
||||
t.set( "test", LuaValue.valueOf("foo") );
|
||||
t.set( "explode", LuaValue.valueOf("explode") );
|
||||
assertEquals( 2, keyCount(t) );
|
||||
}
|
||||
|
||||
public void testRemove0() {
|
||||
LuaTable t = new_Table(2, 0);
|
||||
|
||||
t.set( 1, LuaValue.valueOf("foo") );
|
||||
t.set( 2, LuaValue.valueOf("bah") );
|
||||
assertNotSame(LuaValue.NIL, t.get(1));
|
||||
assertNotSame(LuaValue.NIL, t.get(2));
|
||||
assertEquals(LuaValue.NIL, t.get(3));
|
||||
|
||||
t.set( 1, LuaValue.NIL );
|
||||
t.set( 2, LuaValue.NIL );
|
||||
t.set( 3, LuaValue.NIL );
|
||||
assertEquals(LuaValue.NIL, t.get(1));
|
||||
assertEquals(LuaValue.NIL, t.get(2));
|
||||
assertEquals(LuaValue.NIL, t.get(3));
|
||||
}
|
||||
|
||||
public void testRemove1() {
|
||||
LuaTable t = new_Table(0, 1);
|
||||
|
||||
t.set( "test", LuaValue.valueOf("foo") );
|
||||
t.set( "explode", LuaValue.NIL );
|
||||
t.set( 42, LuaValue.NIL );
|
||||
t.set( new_Table(), LuaValue.NIL );
|
||||
t.set( "test", LuaValue.NIL );
|
||||
assertEquals( 0, keyCount(t) );
|
||||
|
||||
t.set( 10, LuaInteger.valueOf( 5 ) );
|
||||
t.set( 10, LuaValue.NIL );
|
||||
assertEquals( 0, keyCount(t) );
|
||||
}
|
||||
|
||||
public void testRemove2() {
|
||||
LuaTable t = new_Table(0, 1);
|
||||
|
||||
t.set( "test", LuaValue.valueOf("foo") );
|
||||
t.set( "string", LuaInteger.valueOf( 10 ) );
|
||||
assertEquals( 2, keyCount(t) );
|
||||
|
||||
t.set( "string", LuaValue.NIL );
|
||||
t.set( "three", LuaValue.valueOf( 3.14 ) );
|
||||
assertEquals( 2, keyCount(t) );
|
||||
|
||||
t.set( "test", LuaValue.NIL );
|
||||
assertEquals( 1, keyCount(t) );
|
||||
|
||||
t.set( 10, LuaInteger.valueOf( 5 ) );
|
||||
assertEquals( 2, keyCount(t) );
|
||||
|
||||
t.set( 10, LuaValue.NIL );
|
||||
assertEquals( 1, keyCount(t) );
|
||||
|
||||
t.set( "three", LuaValue.NIL );
|
||||
assertEquals( 0, keyCount(t) );
|
||||
}
|
||||
|
||||
public void testShrinkNonPowerOfTwoArray() {
|
||||
LuaTable t = new_Table(6, 2);
|
||||
|
||||
t.set(1, "one");
|
||||
t.set(2, "two");
|
||||
t.set(3, "three");
|
||||
t.set(4, "four");
|
||||
t.set(5, "five");
|
||||
t.set(6, "six");
|
||||
|
||||
t.set("aa", "aaa");
|
||||
t.set("bb", "bbb");
|
||||
|
||||
t.set(3, LuaValue.NIL);
|
||||
t.set(4, LuaValue.NIL);
|
||||
t.set(6, LuaValue.NIL);
|
||||
|
||||
t.set("cc", "ccc");
|
||||
t.set("dd", "ddd");
|
||||
|
||||
assertEquals(4, t.getArrayLength());
|
||||
assertTrue(t.getHashLength() < 10);
|
||||
assertEquals(5, t.hashEntries);
|
||||
assertEquals("one", t.get(1).tojstring());
|
||||
assertEquals("two", t.get(2).tojstring());
|
||||
assertEquals(LuaValue.NIL, t.get(3));
|
||||
assertEquals(LuaValue.NIL, t.get(4));
|
||||
assertEquals("five", t.get(5).tojstring());
|
||||
assertEquals(LuaValue.NIL, t.get(6));
|
||||
assertEquals("aaa", t.get("aa").tojstring());
|
||||
assertEquals("bbb", t.get("bb").tojstring());
|
||||
assertEquals("ccc", t.get("cc").tojstring());
|
||||
assertEquals("ddd", t.get("dd").tojstring());
|
||||
}
|
||||
|
||||
public void testInOrderLuaLength() {
|
||||
LuaTable t = new_Table();
|
||||
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
t.set( i, LuaValue.valueOf( "Test Value! "+i ) );
|
||||
assertEquals( i, t.length() );
|
||||
}
|
||||
}
|
||||
|
||||
public void testOutOfOrderLuaLength() {
|
||||
LuaTable t = new_Table();
|
||||
|
||||
for ( int j=8; j<32; j+=8 ) {
|
||||
for ( int i = j; i > 0; --i ) {
|
||||
t.set( i, LuaValue.valueOf( "Test Value! "+i ) );
|
||||
}
|
||||
assertEquals( j, t.length() );
|
||||
}
|
||||
}
|
||||
|
||||
public void testStringKeysLuaLength() {
|
||||
LuaTable t = new_Table();
|
||||
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
t.set( "str-"+i, LuaValue.valueOf( "String Key Test Value! "+i ) );
|
||||
assertEquals( 0, t.length() );
|
||||
}
|
||||
}
|
||||
|
||||
public void testMixedKeysLuaLength() {
|
||||
LuaTable t = new_Table();
|
||||
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
t.set( "str-"+i, LuaValue.valueOf( "String Key Test Value! "+i ) );
|
||||
t.set( i, LuaValue.valueOf( "Int Key Test Value! "+i ) );
|
||||
assertEquals( i, t.length() );
|
||||
}
|
||||
}
|
||||
|
||||
private static final void compareLists(LuaTable t,Vector v) {
|
||||
int n = v.size();
|
||||
assertEquals(v.size(),t.length());
|
||||
for ( int j=0; j<n; j++ ) {
|
||||
Object vj = v.elementAt(j);
|
||||
Object tj = t.get(j+1).tojstring();
|
||||
vj = ((LuaString)vj).tojstring();
|
||||
assertEquals(vj,tj);
|
||||
}
|
||||
}
|
||||
|
||||
public void testInsertBeginningOfList() {
|
||||
LuaTable t = new_Table();
|
||||
Vector v = new Vector();
|
||||
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
LuaString test = LuaValue.valueOf("Test Value! "+i);
|
||||
t.insert(1, test);
|
||||
v.insertElementAt(test, 0);
|
||||
compareLists(t,v);
|
||||
}
|
||||
}
|
||||
|
||||
public void testInsertEndOfList() {
|
||||
LuaTable t = new_Table();
|
||||
Vector v = new Vector();
|
||||
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
LuaString test = LuaValue.valueOf("Test Value! "+i);
|
||||
t.insert(0, test);
|
||||
v.insertElementAt(test, v.size());
|
||||
compareLists(t,v);
|
||||
}
|
||||
}
|
||||
|
||||
public void testInsertMiddleOfList() {
|
||||
LuaTable t = new_Table();
|
||||
Vector v = new Vector();
|
||||
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
LuaString test = LuaValue.valueOf("Test Value! "+i);
|
||||
int m = i / 2;
|
||||
t.insert(m+1, test);
|
||||
v.insertElementAt(test, m);
|
||||
compareLists(t,v);
|
||||
}
|
||||
}
|
||||
|
||||
private static final void prefillLists(LuaTable t,Vector v) {
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
LuaString test = LuaValue.valueOf("Test Value! "+i);
|
||||
t.insert(0, test);
|
||||
v.insertElementAt(test, v.size());
|
||||
}
|
||||
}
|
||||
|
||||
public void testRemoveBeginningOfList() {
|
||||
LuaTable t = new_Table();
|
||||
Vector v = new Vector();
|
||||
prefillLists(t,v);
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
t.remove(1);
|
||||
v.removeElementAt(0);
|
||||
compareLists(t,v);
|
||||
}
|
||||
}
|
||||
|
||||
public void testRemoveEndOfList() {
|
||||
LuaTable t = new_Table();
|
||||
Vector v = new Vector();
|
||||
prefillLists(t,v);
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
t.remove(0);
|
||||
v.removeElementAt(v.size()-1);
|
||||
compareLists(t,v);
|
||||
}
|
||||
}
|
||||
|
||||
public void testRemoveMiddleOfList() {
|
||||
LuaTable t = new_Table();
|
||||
Vector v = new Vector();
|
||||
prefillLists(t,v);
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
int m = v.size() / 2;
|
||||
t.remove(m+1);
|
||||
v.removeElementAt(m);
|
||||
compareLists(t,v);
|
||||
}
|
||||
}
|
||||
public void testRemoveWhileIterating() {
|
||||
LuaTable t = LuaValue.tableOf(new LuaValue[] {
|
||||
LuaValue.valueOf("a"), LuaValue.valueOf("aa"),
|
||||
LuaValue.valueOf("b"), LuaValue.valueOf("bb"),
|
||||
LuaValue.valueOf("c"), LuaValue.valueOf("cc"),
|
||||
LuaValue.valueOf("d"), LuaValue.valueOf("dd"),
|
||||
LuaValue.valueOf("e"), LuaValue.valueOf("ee"),
|
||||
}, new LuaValue[] {
|
||||
LuaValue.valueOf("11"),
|
||||
LuaValue.valueOf("22"),
|
||||
LuaValue.valueOf("33"),
|
||||
LuaValue.valueOf("44"),
|
||||
LuaValue.valueOf("55"),
|
||||
});
|
||||
// Find expected order after removal.
|
||||
java.util.List<String> expected = new ArrayList<String>();
|
||||
Varargs n;
|
||||
int i;
|
||||
for (n = t.next(LuaValue.NIL), i = 0; !n.arg1().isnil(); n = t.next(n.arg1()), ++i) {
|
||||
if (i % 2 == 0)
|
||||
expected.add(n.arg1() + "=" + n.arg(2));
|
||||
}
|
||||
// Remove every other key while iterating over the table.
|
||||
for (n = t.next(LuaValue.NIL), i = 0; !n.arg1().isnil(); n = t.next(n.arg1()), ++i) {
|
||||
if (i % 2 != 0)
|
||||
t.set(n.arg1(), LuaValue.NIL);
|
||||
}
|
||||
// Iterate over remaining table, and form list of entries still in table.
|
||||
java.util.List<String> actual = new ArrayList<String>();
|
||||
for (n = t.next(LuaValue.NIL); !n.arg1().isnil(); n = t.next(n.arg1())) {
|
||||
actual.add(n.arg1() + "=" + n.arg(2));
|
||||
}
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
}
|
||||
1246
jse/src/test/java/org/luaj/vm2/TypeTest.java
Normal file
1246
jse/src/test/java/org/luaj/vm2/TypeTest.java
Normal file
File diff suppressed because it is too large
Load Diff
41
jse/src/test/java/org/luaj/vm2/UTF8StreamTest.java
Normal file
41
jse/src/test/java/org/luaj/vm2/UTF8StreamTest.java
Normal file
@@ -0,0 +1,41 @@
|
||||
/*******************************************************************************
|
||||
* 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.vm2;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.luaj.vm2.lib.jse.JsePlatform;
|
||||
|
||||
public class UTF8StreamTest extends TestCase {
|
||||
|
||||
public 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);
|
||||
}
|
||||
|
||||
}
|
||||
1149
jse/src/test/java/org/luaj/vm2/UnaryBinaryOperatorsTest.java
Normal file
1149
jse/src/test/java/org/luaj/vm2/UnaryBinaryOperatorsTest.java
Normal file
File diff suppressed because it is too large
Load Diff
230
jse/src/test/java/org/luaj/vm2/VarargsTest.java
Normal file
230
jse/src/test/java/org/luaj/vm2/VarargsTest.java
Normal file
@@ -0,0 +1,230 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Tests of basic unary and binary operators on main value types.
|
||||
*/
|
||||
public class VarargsTest extends TestCase {
|
||||
|
||||
static LuaValue A = LuaValue.valueOf("a");
|
||||
static LuaValue B = LuaValue.valueOf("b");
|
||||
static LuaValue C = LuaValue.valueOf("c");
|
||||
static LuaValue D = LuaValue.valueOf("d");
|
||||
static LuaValue E = LuaValue.valueOf("e");
|
||||
static LuaValue F = LuaValue.valueOf("f");
|
||||
static LuaValue G = LuaValue.valueOf("g");
|
||||
static LuaValue H = LuaValue.valueOf("h");
|
||||
static LuaValue Z = LuaValue.valueOf("z");
|
||||
static LuaValue NIL = LuaValue.NIL;
|
||||
static Varargs A_G = LuaValue.varargsOf(new LuaValue[] { A, B, C, D, E, F, G });
|
||||
static Varargs B_E = LuaValue.varargsOf(new LuaValue[] { B, C, D, E });
|
||||
static Varargs C_G = LuaValue.varargsOf(new LuaValue[] { C, D, E, F, G });
|
||||
static Varargs C_E = LuaValue.varargsOf(new LuaValue[] { C, D, E });
|
||||
static Varargs DE = LuaValue.varargsOf(new LuaValue[] { D, E });
|
||||
static Varargs E_G = LuaValue.varargsOf(new LuaValue[] { E, F, G });
|
||||
static Varargs FG = LuaValue.varargsOf(new LuaValue[] { F, G });
|
||||
static LuaValue[] Z_H_array = {Z, A, B, C, D, E, F, G, H };
|
||||
static Varargs A_G_alt = new Varargs.ArrayPartVarargs(Z_H_array, 1, 7);
|
||||
static Varargs B_E_alt = new Varargs.ArrayPartVarargs(Z_H_array, 2, 4);
|
||||
static Varargs C_G_alt = new Varargs.ArrayPartVarargs(Z_H_array, 3, 5);
|
||||
static Varargs C_E_alt = new Varargs.ArrayPartVarargs(Z_H_array, 3, 3);
|
||||
static Varargs C_E_alt2 = LuaValue.varargsOf(C, D, E);
|
||||
static Varargs DE_alt = new Varargs.PairVarargs(D,E);
|
||||
static Varargs DE_alt2 = LuaValue.varargsOf(D,E);
|
||||
static Varargs E_G_alt = new Varargs.ArrayPartVarargs(Z_H_array, 5, 3);
|
||||
static Varargs FG_alt = new Varargs.PairVarargs(F, G);
|
||||
static Varargs NONE = LuaValue.NONE;
|
||||
|
||||
static void expectEquals(Varargs x, Varargs y) {
|
||||
assertEquals(x.narg(), y.narg());
|
||||
assertEquals(x.arg1(), y.arg1());
|
||||
assertEquals(x.arg(0), y.arg(0));
|
||||
assertEquals(x.arg(-1), y.arg(-1));
|
||||
assertEquals(x.arg(2), y.arg(2));
|
||||
assertEquals(x.arg(3), y.arg(3));
|
||||
for (int i = 4; i < x.narg() + 2; ++i)
|
||||
assertEquals(x.arg(i), y.arg(i));
|
||||
}
|
||||
|
||||
public void testSanity() {
|
||||
expectEquals(A_G, A_G);
|
||||
expectEquals(A_G_alt, A_G_alt);
|
||||
expectEquals(A_G, A_G_alt);
|
||||
expectEquals(B_E, B_E_alt);
|
||||
expectEquals(C_G, C_G_alt);
|
||||
expectEquals(C_E, C_E_alt);
|
||||
expectEquals(C_E, C_E_alt2);
|
||||
expectEquals(DE, DE_alt);
|
||||
expectEquals(DE, DE_alt2);
|
||||
expectEquals(E_G, E_G_alt);
|
||||
expectEquals(FG, FG_alt);
|
||||
expectEquals(FG_alt, FG_alt);
|
||||
expectEquals(A, A);
|
||||
expectEquals(NONE, NONE);
|
||||
expectEquals(NIL, NIL);
|
||||
}
|
||||
|
||||
public void testNegativeIndices() {
|
||||
expectNegSubargsError(A_G);
|
||||
expectNegSubargsError(A_G_alt);
|
||||
expectNegSubargsError(B_E);
|
||||
expectNegSubargsError(B_E_alt);
|
||||
expectNegSubargsError(C_G);
|
||||
expectNegSubargsError(C_G_alt);
|
||||
expectNegSubargsError(C_E);
|
||||
expectNegSubargsError(C_E_alt);
|
||||
expectNegSubargsError(C_E_alt2);
|
||||
expectNegSubargsError(DE);
|
||||
expectNegSubargsError(DE_alt);
|
||||
expectNegSubargsError(DE_alt2);
|
||||
expectNegSubargsError(E_G);
|
||||
expectNegSubargsError(FG);
|
||||
expectNegSubargsError(A);
|
||||
expectNegSubargsError(NONE);
|
||||
expectNegSubargsError(NIL);
|
||||
}
|
||||
|
||||
static void standardTestsA_G(Varargs a_g) {
|
||||
expectEquals(A_G, a_g);
|
||||
expectEquals(A_G, a_g.subargs(1));
|
||||
expectEquals(C_G, a_g.subargs(3).subargs(1));
|
||||
expectEquals(E_G, a_g.subargs(5));
|
||||
expectEquals(E_G, a_g.subargs(5).subargs(1));
|
||||
expectEquals(FG, a_g.subargs(6));
|
||||
expectEquals(FG, a_g.subargs(6).subargs(1));
|
||||
expectEquals(G, a_g.subargs(7));
|
||||
expectEquals(G, a_g.subargs(7).subargs(1));
|
||||
expectEquals(NONE, a_g.subargs(8));
|
||||
expectEquals(NONE, a_g.subargs(8).subargs(1));
|
||||
standardTestsC_G(A_G.subargs(3));
|
||||
}
|
||||
|
||||
static void standardTestsC_G(Varargs c_g) {
|
||||
expectEquals(C_G, c_g.subargs(1));
|
||||
expectEquals(E_G, c_g.subargs(3));
|
||||
expectEquals(E_G, c_g.subargs(3).subargs(1));
|
||||
expectEquals(FG, c_g.subargs(4));
|
||||
expectEquals(FG, c_g.subargs(4).subargs(1));
|
||||
expectEquals(G, c_g.subargs(5));
|
||||
expectEquals(G, c_g.subargs(5).subargs(1));
|
||||
expectEquals(NONE, c_g.subargs(6));
|
||||
expectEquals(NONE, c_g.subargs(6).subargs(1));
|
||||
standardTestsE_G(c_g.subargs(3));
|
||||
}
|
||||
|
||||
static void standardTestsE_G(Varargs e_g) {
|
||||
expectEquals(E_G, e_g.subargs(1));
|
||||
expectEquals(FG, e_g.subargs(2));
|
||||
expectEquals(FG, e_g.subargs(2).subargs(1));
|
||||
expectEquals(G, e_g.subargs(3));
|
||||
expectEquals(G, e_g.subargs(3).subargs(1));
|
||||
expectEquals(NONE, e_g.subargs(4));
|
||||
expectEquals(NONE, e_g.subargs(4).subargs(1));
|
||||
standardTestsFG(e_g.subargs(2));
|
||||
}
|
||||
|
||||
static void standardTestsFG(Varargs fg) {
|
||||
expectEquals(FG, fg.subargs(1));
|
||||
expectEquals(G, fg.subargs(2));
|
||||
expectEquals(G, fg.subargs(2).subargs(1));
|
||||
expectEquals(NONE, fg.subargs(3));
|
||||
expectEquals(NONE, fg.subargs(3).subargs(1));
|
||||
}
|
||||
|
||||
static void standardTestsNone(Varargs none) {
|
||||
expectEquals(NONE, none.subargs(1));
|
||||
expectEquals(NONE, none.subargs(2));
|
||||
}
|
||||
|
||||
public void testVarargsSubargs() {
|
||||
standardTestsA_G(A_G);
|
||||
standardTestsA_G(A_G_alt);
|
||||
standardTestsC_G(C_G);
|
||||
standardTestsC_G(C_G_alt);
|
||||
standardTestsE_G(E_G);
|
||||
standardTestsE_G(E_G_alt);
|
||||
standardTestsFG(FG);
|
||||
standardTestsFG(FG_alt);
|
||||
standardTestsNone(NONE);
|
||||
}
|
||||
|
||||
public void testVarargsMore() {
|
||||
Varargs a_g;
|
||||
a_g = LuaValue.varargsOf(new LuaValue[] { A, }, LuaValue.varargsOf( new LuaValue[] { B, C, D, E, F, G }));
|
||||
standardTestsA_G(a_g);
|
||||
a_g = LuaValue.varargsOf(new LuaValue[] { A, B, }, LuaValue.varargsOf( new LuaValue[] { C, D, E, F, G }));
|
||||
standardTestsA_G(a_g);
|
||||
a_g = LuaValue.varargsOf(new LuaValue[] { A, B, C, }, LuaValue.varargsOf( new LuaValue[] { D, E, F, G }));
|
||||
standardTestsA_G(a_g);
|
||||
a_g = LuaValue.varargsOf(new LuaValue[] { A, B, C, D, }, LuaValue.varargsOf(E, F, G));
|
||||
standardTestsA_G(a_g);
|
||||
a_g = LuaValue.varargsOf(new LuaValue[] { A, B, C, D, E }, LuaValue.varargsOf( F, G ));
|
||||
standardTestsA_G(a_g);
|
||||
a_g = LuaValue.varargsOf(new LuaValue[] { A, B, C, D, E, F, }, G );
|
||||
standardTestsA_G(a_g);
|
||||
}
|
||||
|
||||
public void testPairVarargsMore() {
|
||||
Varargs a_g = new Varargs.PairVarargs(A,
|
||||
new Varargs.PairVarargs(B,
|
||||
new Varargs.PairVarargs(C,
|
||||
new Varargs.PairVarargs(D,
|
||||
new Varargs.PairVarargs(E,
|
||||
new Varargs.PairVarargs(F, G))))));
|
||||
standardTestsA_G(a_g);
|
||||
}
|
||||
|
||||
public void testArrayPartMore() {
|
||||
Varargs a_g;
|
||||
a_g = new Varargs.ArrayPartVarargs(Z_H_array, 1, 1, new Varargs.ArrayPartVarargs(Z_H_array, 2, 6));
|
||||
standardTestsA_G(a_g);
|
||||
a_g = new Varargs.ArrayPartVarargs(Z_H_array, 1, 2, new Varargs.ArrayPartVarargs(Z_H_array, 3, 5));
|
||||
standardTestsA_G(a_g);
|
||||
a_g = new Varargs.ArrayPartVarargs(Z_H_array, 1, 3, new Varargs.ArrayPartVarargs(Z_H_array, 4, 4));
|
||||
standardTestsA_G(a_g);
|
||||
a_g = new Varargs.ArrayPartVarargs(Z_H_array, 1, 4, new Varargs.ArrayPartVarargs(Z_H_array, 5, 3));
|
||||
standardTestsA_G(a_g);
|
||||
a_g = new Varargs.ArrayPartVarargs(Z_H_array, 1, 5, new Varargs.ArrayPartVarargs(Z_H_array, 6, 2));
|
||||
standardTestsA_G(a_g);
|
||||
a_g = new Varargs.ArrayPartVarargs(Z_H_array, 1, 6, new Varargs.ArrayPartVarargs(Z_H_array, 7, 1));
|
||||
standardTestsA_G(a_g);
|
||||
}
|
||||
|
||||
static void expectNegSubargsError(Varargs v) {
|
||||
String expected_msg = "bad argument #1: start must be > 0";
|
||||
try {
|
||||
v.subargs(0);
|
||||
fail("Failed to throw exception for index 0");
|
||||
} catch ( LuaError e ) {
|
||||
assertEquals(expected_msg, e.getMessage());
|
||||
}
|
||||
try {
|
||||
v.subargs(-1);
|
||||
fail("Failed to throw exception for index -1");
|
||||
} catch ( LuaError e ) {
|
||||
assertEquals(expected_msg, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
261
jse/src/test/java/org/luaj/vm2/WeakTableTest.java
Normal file
261
jse/src/test/java/org/luaj/vm2/WeakTableTest.java
Normal file
@@ -0,0 +1,261 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
abstract public class WeakTableTest extends TableTest {
|
||||
|
||||
public static class MyData {
|
||||
public final int value;
|
||||
public MyData( int value ) {
|
||||
this.value = value;
|
||||
}
|
||||
public int hashCode() {
|
||||
return value;
|
||||
}
|
||||
public boolean equals( Object o ) {
|
||||
return (o instanceof MyData) && ((MyData)o).value == value;
|
||||
}
|
||||
public String toString() {
|
||||
return "mydata-"+value;
|
||||
}
|
||||
}
|
||||
|
||||
static void collectGarbage() {
|
||||
Runtime rt = Runtime.getRuntime();
|
||||
rt.gc();
|
||||
try {
|
||||
Thread.sleep(20);
|
||||
rt.gc();
|
||||
Thread.sleep(20);
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
rt.gc();
|
||||
}
|
||||
|
||||
public static class WeakValueTableTest extends WeakTableTest {
|
||||
protected LuaTable new_Table() { return WeakTable.make(false, true); }
|
||||
protected LuaTable new_Table(int n,int m) { return WeakTable.make(false, true); }
|
||||
|
||||
public void testWeakValuesTable() {
|
||||
LuaTable t = new_Table();
|
||||
|
||||
Object obj = new Object();
|
||||
LuaTable tableValue = new LuaTable();
|
||||
LuaString stringValue = LuaString.valueOf("this is a test");
|
||||
LuaTable tableValue2 = new LuaTable();
|
||||
|
||||
t.set("table", tableValue);
|
||||
t.set("userdata", LuaValue.userdataOf(obj, null));
|
||||
t.set("string", stringValue);
|
||||
t.set("string2", LuaValue.valueOf("another string"));
|
||||
t.set(1, tableValue2);
|
||||
assertTrue("table must have at least 4 elements", t.getHashLength() >= 4);
|
||||
assertTrue("array part must have 1 element", t.getArrayLength() >= 1);
|
||||
|
||||
// check that table can be used to get elements
|
||||
assertEquals(tableValue, t.get("table"));
|
||||
assertEquals(stringValue, t.get("string"));
|
||||
assertEquals(obj, t.get("userdata").checkuserdata());
|
||||
assertEquals(tableValue2, t.get(1));
|
||||
|
||||
// nothing should be collected, since we have strong references here
|
||||
collectGarbage();
|
||||
|
||||
// check that elements are still there
|
||||
assertEquals(tableValue, t.get("table"));
|
||||
assertEquals(stringValue, t.get("string"));
|
||||
assertEquals(obj, t.get("userdata").checkuserdata());
|
||||
assertEquals(tableValue2, t.get(1));
|
||||
|
||||
// drop our strong references
|
||||
obj = null;
|
||||
tableValue = null;
|
||||
tableValue2 = null;
|
||||
stringValue = null;
|
||||
|
||||
// Garbage collection should cause weak entries to be dropped.
|
||||
collectGarbage();
|
||||
|
||||
// check that they are dropped
|
||||
assertEquals(LuaValue.NIL, t.get("table"));
|
||||
assertEquals(LuaValue.NIL, t.get("userdata"));
|
||||
assertEquals(LuaValue.NIL, t.get(1));
|
||||
assertFalse("strings should not be in weak references", t.get("string").isnil());
|
||||
}
|
||||
}
|
||||
|
||||
public static class WeakKeyTableTest extends WeakTableTest {
|
||||
protected LuaTable new_Table() { return WeakTable.make(true, false); }
|
||||
protected LuaTable new_Table(int n,int m) { return WeakTable.make(true, false); }
|
||||
|
||||
public void testWeakKeysTable() {
|
||||
LuaTable t = WeakTable.make(true, false);
|
||||
|
||||
LuaValue key = LuaValue.userdataOf(new MyData(111));
|
||||
LuaValue val = LuaValue.userdataOf(new MyData(222));
|
||||
|
||||
// set up the table
|
||||
t.set( key, val );
|
||||
assertEquals( val, t.get(key) );
|
||||
System.gc();
|
||||
assertEquals( val, t.get(key) );
|
||||
|
||||
// drop key and value references, replace them with new ones
|
||||
WeakReference origkey = new WeakReference(key);
|
||||
WeakReference origval = new WeakReference(val);
|
||||
key = LuaValue.userdataOf(new MyData(111));
|
||||
val = LuaValue.userdataOf(new MyData(222));
|
||||
|
||||
// new key and value should be interchangeable (feature of this test class)
|
||||
assertEquals( key, origkey.get() );
|
||||
assertEquals( val, origval.get() );
|
||||
assertEquals( val, t.get(key) );
|
||||
assertEquals( val, t.get((LuaValue) origkey.get()) );
|
||||
assertEquals( origval.get(), t.get(key) );
|
||||
|
||||
// value should not be reachable after gc
|
||||
collectGarbage();
|
||||
assertEquals( null, origkey.get() );
|
||||
assertEquals( LuaValue.NIL, t.get(key) );
|
||||
collectGarbage();
|
||||
assertEquals( null, origval.get() );
|
||||
}
|
||||
|
||||
public void testNext() {
|
||||
LuaTable t = WeakTable.make(true, true);
|
||||
|
||||
LuaValue key = LuaValue.userdataOf(new MyData(111));
|
||||
LuaValue val = LuaValue.userdataOf(new MyData(222));
|
||||
LuaValue key2 = LuaValue.userdataOf(new MyData(333));
|
||||
LuaValue val2 = LuaValue.userdataOf(new MyData(444));
|
||||
LuaValue key3 = LuaValue.userdataOf(new MyData(555));
|
||||
LuaValue val3 = LuaValue.userdataOf(new MyData(666));
|
||||
|
||||
// set up the table
|
||||
t.set( key, val );
|
||||
t.set( key2, val2 );
|
||||
t.set( key3, val3 );
|
||||
|
||||
// forget one of the keys
|
||||
key2 = null;
|
||||
val2 = null;
|
||||
collectGarbage();
|
||||
|
||||
// table should have 2 entries
|
||||
int size = 0;
|
||||
for ( LuaValue k = t.next(LuaValue.NIL).arg1(); !k.isnil();
|
||||
k = t.next(k).arg1() ) {
|
||||
size++;
|
||||
}
|
||||
assertEquals(2, size);
|
||||
}
|
||||
}
|
||||
|
||||
public static class WeakKeyValueTableTest extends WeakTableTest {
|
||||
protected LuaTable new_Table() { return WeakTable.make(true, true); }
|
||||
protected LuaTable new_Table(int n,int m) { return WeakTable.make(true, true); }
|
||||
|
||||
public void testWeakKeysValuesTable() {
|
||||
LuaTable t = WeakTable.make(true, true);
|
||||
|
||||
LuaValue key = LuaValue.userdataOf(new MyData(111));
|
||||
LuaValue val = LuaValue.userdataOf(new MyData(222));
|
||||
LuaValue key2 = LuaValue.userdataOf(new MyData(333));
|
||||
LuaValue val2 = LuaValue.userdataOf(new MyData(444));
|
||||
LuaValue key3 = LuaValue.userdataOf(new MyData(555));
|
||||
LuaValue val3 = LuaValue.userdataOf(new MyData(666));
|
||||
|
||||
// set up the table
|
||||
t.set( key, val );
|
||||
t.set( key2, val2 );
|
||||
t.set( key3, val3 );
|
||||
assertEquals( val, t.get(key) );
|
||||
assertEquals( val2, t.get(key2) );
|
||||
assertEquals( val3, t.get(key3) );
|
||||
System.gc();
|
||||
assertEquals( val, t.get(key) );
|
||||
assertEquals( val2, t.get(key2) );
|
||||
assertEquals( val3, t.get(key3) );
|
||||
|
||||
// drop key and value references, replace them with new ones
|
||||
WeakReference origkey = new WeakReference(key);
|
||||
WeakReference origval = new WeakReference(val);
|
||||
WeakReference origkey2 = new WeakReference(key2);
|
||||
WeakReference origval2 = new WeakReference(val2);
|
||||
WeakReference origkey3 = new WeakReference(key3);
|
||||
WeakReference origval3 = new WeakReference(val3);
|
||||
key = LuaValue.userdataOf(new MyData(111));
|
||||
val = LuaValue.userdataOf(new MyData(222));
|
||||
key2 = LuaValue.userdataOf(new MyData(333));
|
||||
// don't drop val2, or key3
|
||||
val3 = LuaValue.userdataOf(new MyData(666));
|
||||
|
||||
// no values should be reachable after gc
|
||||
collectGarbage();
|
||||
assertEquals( null, origkey.get() );
|
||||
assertEquals( null, origval.get() );
|
||||
assertEquals( null, origkey2.get() );
|
||||
assertEquals( null, origval3.get() );
|
||||
assertEquals( LuaValue.NIL, t.get(key) );
|
||||
assertEquals( LuaValue.NIL, t.get(key2) );
|
||||
assertEquals( LuaValue.NIL, t.get(key3) );
|
||||
|
||||
// all originals should be gone after gc, then access
|
||||
val2 = null;
|
||||
key3 = null;
|
||||
collectGarbage();
|
||||
assertEquals( null, origval2.get() );
|
||||
assertEquals( null, origkey3.get() );
|
||||
}
|
||||
|
||||
public void testReplace() {
|
||||
LuaTable t = WeakTable.make(true, true);
|
||||
|
||||
LuaValue key = LuaValue.userdataOf(new MyData(111));
|
||||
LuaValue val = LuaValue.userdataOf(new MyData(222));
|
||||
LuaValue key2 = LuaValue.userdataOf(new MyData(333));
|
||||
LuaValue val2 = LuaValue.userdataOf(new MyData(444));
|
||||
LuaValue key3 = LuaValue.userdataOf(new MyData(555));
|
||||
LuaValue val3 = LuaValue.userdataOf(new MyData(666));
|
||||
|
||||
// set up the table
|
||||
t.set( key, val );
|
||||
t.set( key2, val2 );
|
||||
t.set( key3, val3 );
|
||||
|
||||
LuaValue val4 = LuaValue.userdataOf(new MyData(777));
|
||||
t.set( key2, val4 );
|
||||
|
||||
// table should have 3 entries
|
||||
int size = 0;
|
||||
for ( LuaValue k = t.next(LuaValue.NIL).arg1();
|
||||
!k.isnil() && size < 1000;
|
||||
k = t.next(k).arg1() ) {
|
||||
size++;
|
||||
}
|
||||
assertEquals(3, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
117
jse/src/test/java/org/luaj/vm2/compiler/AbstractUnitTests.java
Normal file
117
jse/src/test/java/org/luaj/vm2/compiler/AbstractUnitTests.java
Normal file
@@ -0,0 +1,117 @@
|
||||
package org.luaj.vm2.compiler;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.Print;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.compiler.DumpState;
|
||||
import org.luaj.vm2.lib.jse.JsePlatform;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
abstract public class AbstractUnitTests extends TestCase {
|
||||
|
||||
private final String dir;
|
||||
private final String jar;
|
||||
private Globals globals;
|
||||
|
||||
public AbstractUnitTests(String zipdir, String zipfile, String dir) {
|
||||
URL zip = null;
|
||||
zip = getClass().getResource(zipfile);
|
||||
if ( zip == null ) {
|
||||
File file = new File(zipdir+"/"+zipfile);
|
||||
try {
|
||||
if ( file.exists() )
|
||||
zip = file.toURI().toURL();
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if ( zip == null )
|
||||
throw new RuntimeException("not found: "+zipfile);
|
||||
this.jar = "jar:" + zip.toExternalForm()+ "!/";
|
||||
this.dir = dir;
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
globals = JsePlatform.standardGlobals();
|
||||
}
|
||||
|
||||
protected String pathOfFile(String file) {
|
||||
return jar + dir + "/" + file;
|
||||
}
|
||||
|
||||
protected InputStream inputStreamOfPath(String path) throws IOException {
|
||||
URL url = new URL(path);
|
||||
return url.openStream();
|
||||
}
|
||||
|
||||
protected InputStream inputStreamOfFile(String file) throws IOException {
|
||||
return inputStreamOfPath(pathOfFile(file));
|
||||
}
|
||||
|
||||
protected void doTest(String file) {
|
||||
try {
|
||||
// load source from jar
|
||||
String path = pathOfFile(file);
|
||||
byte[] lua = bytesFromJar(path);
|
||||
|
||||
// compile in memory
|
||||
InputStream is = new ByteArrayInputStream(lua);
|
||||
Prototype p = globals.loadPrototype(is, "@" + file, "bt");
|
||||
String actual = protoToString(p);
|
||||
|
||||
// load expected value from jar
|
||||
byte[] luac = bytesFromJar(path.substring(0, path.length()-4)+".lc");
|
||||
Prototype e = loadFromBytes(luac, file);
|
||||
String expected = protoToString(e);
|
||||
|
||||
// compare results
|
||||
assertEquals(expected, actual);
|
||||
|
||||
// dump into memory
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
DumpState.dump(p, baos, false);
|
||||
byte[] dumped = baos.toByteArray();
|
||||
|
||||
// re-undump
|
||||
Prototype p2 = loadFromBytes(dumped, file);
|
||||
String actual2 = protoToString(p2);
|
||||
|
||||
// compare again
|
||||
assertEquals(actual, actual2);
|
||||
|
||||
} catch (IOException e) {
|
||||
fail(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
protected byte[] bytesFromJar(String path) throws IOException {
|
||||
InputStream is = inputStreamOfPath(path);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[2048];
|
||||
int n;
|
||||
while ((n = is.read(buffer)) >= 0)
|
||||
baos.write(buffer, 0, n);
|
||||
is.close();
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
protected Prototype loadFromBytes(byte[] bytes, String script)
|
||||
throws IOException {
|
||||
InputStream is = new ByteArrayInputStream(bytes);
|
||||
return globals.loadPrototype(is, script, "b");
|
||||
}
|
||||
|
||||
protected String protoToString(Prototype p) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
PrintStream ps = new PrintStream(baos);
|
||||
Print.ps = ps;
|
||||
new Print().printFunction(p, true);
|
||||
return baos.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.luaj.vm2.compiler;
|
||||
|
||||
|
||||
|
||||
public class CompilerUnitTests extends AbstractUnitTests {
|
||||
|
||||
public CompilerUnitTests() {
|
||||
super("test/lua", "luaj3.0-tests.zip", "lua5.2.1-tests");
|
||||
}
|
||||
|
||||
public void testAll() { doTest("all.lua"); }
|
||||
public void testApi() { doTest("api.lua"); }
|
||||
public void testAttrib() { doTest("attrib.lua"); }
|
||||
public void testBig() { doTest("big.lua"); }
|
||||
public void testBitwise() { doTest("bitwise.lua"); }
|
||||
public void testCalls() { doTest("calls.lua"); }
|
||||
public void testChecktable() { doTest("checktable.lua"); }
|
||||
public void testClosure() { doTest("closure.lua"); }
|
||||
public void testCode() { doTest("code.lua"); }
|
||||
public void testConstruct() { doTest("constructs.lua"); }
|
||||
public void testCoroutine() { doTest("coroutine.lua"); }
|
||||
public void testDb() { doTest("db.lua"); }
|
||||
public void testErrors() { doTest("errors.lua"); }
|
||||
public void testEvents() { doTest("events.lua"); }
|
||||
public void testFiles() { doTest("files.lua"); }
|
||||
public void testGc() { doTest("gc.lua"); }
|
||||
public void testGoto() { doTest("goto.lua"); }
|
||||
public void testLiterals() { doTest("literals.lua"); }
|
||||
public void testLocals() { doTest("locals.lua"); }
|
||||
public void testMain() { doTest("main.lua"); }
|
||||
public void testMath() { doTest("math.lua"); }
|
||||
public void testNextvar() { doTest("nextvar.lua"); }
|
||||
public void testPm() { doTest("pm.lua"); }
|
||||
public void testSort() { doTest("sort.lua"); }
|
||||
public void testStrings() { doTest("strings.lua"); }
|
||||
public void testVararg() { doTest("vararg.lua"); }
|
||||
public void testVerybig() { doTest("verybig.lua"); }
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package org.luaj.vm2.compiler;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.luaj.vm2.*;
|
||||
import org.luaj.vm2.compiler.DumpState;
|
||||
import org.luaj.vm2.lib.jse.JsePlatform;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
|
||||
public class DumpLoadEndianIntTest extends TestCase {
|
||||
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;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
globals = JsePlatform.standardGlobals();
|
||||
DumpState.ALLOW_INTEGER_CASTING = false;
|
||||
}
|
||||
|
||||
public 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 );
|
||||
}
|
||||
|
||||
public 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 );
|
||||
}
|
||||
|
||||
public 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 );
|
||||
}
|
||||
|
||||
public 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 );
|
||||
}
|
||||
|
||||
public 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 );
|
||||
}
|
||||
|
||||
public 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 );
|
||||
}
|
||||
|
||||
public 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
29
jse/src/test/java/org/luaj/vm2/compiler/LuaParserTests.java
Normal file
29
jse/src/test/java/org/luaj/vm2/compiler/LuaParserTests.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package org.luaj.vm2.compiler;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.compiler.CompilerUnitTests;
|
||||
import org.luaj.vm2.parser.LuaParser;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
|
||||
public class LuaParserTests extends CompilerUnitTests {
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
LuaValue.valueOf(true);
|
||||
}
|
||||
|
||||
protected void doTest(String file) {
|
||||
try {
|
||||
InputStream is = inputStreamOfFile(file);
|
||||
Reader r = new InputStreamReader(is, "ISO-8859-1");
|
||||
LuaParser parser = new LuaParser(r);
|
||||
parser.Chunk();
|
||||
} catch (Exception e) {
|
||||
fail(e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
30
jse/src/test/java/org/luaj/vm2/compiler/RegressionTests.java
Normal file
30
jse/src/test/java/org/luaj/vm2/compiler/RegressionTests.java
Normal file
@@ -0,0 +1,30 @@
|
||||
package org.luaj.vm2.compiler;
|
||||
|
||||
/**
|
||||
* Framework to add regression tests as problem areas are found.
|
||||
*
|
||||
* To add a new regression test:
|
||||
* 1) run "unpack.sh" in the project root
|
||||
* 2) add a new "lua" file in the "regressions" subdirectory
|
||||
* 3) run "repack.sh" in the project root
|
||||
* 4) add a line to the source file naming the new test
|
||||
*
|
||||
* After adding a test, check in the zip file
|
||||
* rather than the individual regression test files.
|
||||
*
|
||||
* @author jrosebor
|
||||
*/
|
||||
public class RegressionTests extends AbstractUnitTests {
|
||||
|
||||
public RegressionTests() {
|
||||
super( "test/lua", "luaj3.0-tests.zip", "regressions" );
|
||||
}
|
||||
|
||||
public void testModulo() { doTest("modulo.lua"); }
|
||||
public void testConstruct() { doTest("construct.lua"); }
|
||||
public void testBigAttrs() { doTest("bigattr.lua"); }
|
||||
public void testControlChars() { doTest("controlchars.lua"); }
|
||||
public void testComparators() { doTest("comparators.lua"); }
|
||||
public void testMathRandomseed() { doTest("mathrandomseed.lua"); }
|
||||
public void testVarargs() { doTest("varargs.lua"); }
|
||||
}
|
||||
95
jse/src/test/java/org/luaj/vm2/compiler/SimpleTests.java
Normal file
95
jse/src/test/java/org/luaj/vm2/compiler/SimpleTests.java
Normal file
@@ -0,0 +1,95 @@
|
||||
package org.luaj.vm2.compiler;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
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;
|
||||
|
||||
public class SimpleTests extends TestCase {
|
||||
|
||||
private Globals globals;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
public void testTrivial() {
|
||||
String s = "print( 2 )\n";
|
||||
doTest( s );
|
||||
}
|
||||
|
||||
public void testAlmostTrivial() {
|
||||
String s = "print( 2 )\n" +
|
||||
"print( 3 )\n";
|
||||
doTest( s );
|
||||
}
|
||||
|
||||
public void testSimple() {
|
||||
String s = "print( 'hello, world' )\n"+
|
||||
"for i = 2,4 do\n" +
|
||||
" print( 'i', i )\n" +
|
||||
"end\n";
|
||||
doTest( s );
|
||||
}
|
||||
|
||||
public 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 );
|
||||
}
|
||||
|
||||
public void testShebang() {
|
||||
String s = "#!../lua\n"+
|
||||
"print( 2 )\n";
|
||||
doTest( s );
|
||||
}
|
||||
|
||||
public void testInlineTable() {
|
||||
String s = "A = {g=10}\n"+
|
||||
"print( A )\n";
|
||||
doTest( s );
|
||||
}
|
||||
|
||||
public 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 };
|
||||
|
||||
public 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("hash codes are same: "+hc,hc!=hd);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package org.luaj.vm2.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.vm2.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,18 @@
|
||||
package org.luaj.vm2.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,18 @@
|
||||
package org.luaj.vm2.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());
|
||||
}
|
||||
}
|
||||
311
jse/src/test/java/org/luaj/vm2/script/ScriptEngineTests.java
Normal file
311
jse/src/test/java/org/luaj/vm2/script/ScriptEngineTests.java
Normal file
@@ -0,0 +1,311 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013 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.script;
|
||||
|
||||
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.ScriptContext;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineFactory;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
import javax.script.SimpleBindings;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import org.luaj.vm2.LuaFunction;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.OneArgFunction;
|
||||
|
||||
public class ScriptEngineTests extends TestSuite {
|
||||
|
||||
public static TestSuite suite() {
|
||||
TestSuite suite = new TestSuite("Script Engine Tests");
|
||||
suite.addTest( new TestSuite( LookupEngineTestCase.class, "Lookup Engine" ) );
|
||||
suite.addTest( new TestSuite( DefaultBindingsTest.class, "Default Bindings" ) );
|
||||
suite.addTest( new TestSuite( SimpleBindingsTest.class, "Simple Bindings" ) );
|
||||
suite.addTest( new TestSuite( CompileClosureTest.class, "Compile Closure" ) );
|
||||
suite.addTest( new TestSuite( CompileNonClosureTest.class, "Compile NonClosure" ) );
|
||||
suite.addTest( new TestSuite( UserContextTest.class, "User Context" ) );
|
||||
suite.addTest( new TestSuite( WriterTest.class, "Writer" ) );
|
||||
return suite;
|
||||
}
|
||||
|
||||
public static class LookupEngineTestCase extends TestCase {
|
||||
public void testGetEngineByExtension() {
|
||||
ScriptEngine e = new ScriptEngineManager().getEngineByExtension(".lua");
|
||||
assertNotNull(e);
|
||||
assertEquals(LuaScriptEngine.class, e.getClass());
|
||||
}
|
||||
public void testGetEngineByName() {
|
||||
ScriptEngine e = new ScriptEngineManager().getEngineByName("luaj");
|
||||
assertNotNull(e);
|
||||
assertEquals(LuaScriptEngine.class, e.getClass());
|
||||
}
|
||||
public void testGetEngineByMimeType() {
|
||||
ScriptEngine e = new ScriptEngineManager().getEngineByMimeType("text/lua");
|
||||
assertNotNull(e);
|
||||
assertEquals(LuaScriptEngine.class, e.getClass());
|
||||
}
|
||||
public 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());
|
||||
}
|
||||
}
|
||||
|
||||
public static class DefaultBindingsTest extends EngineTestCase {
|
||||
protected Bindings createBindings() {
|
||||
return e.createBindings();
|
||||
}
|
||||
}
|
||||
|
||||
public static class SimpleBindingsTest extends EngineTestCase {
|
||||
protected Bindings createBindings() {
|
||||
return new SimpleBindings();
|
||||
}
|
||||
}
|
||||
|
||||
public static class CompileClosureTest extends DefaultBindingsTest {
|
||||
protected void setUp() throws Exception {
|
||||
System.setProperty("org.luaj.luajc", "false");
|
||||
super.setUp();
|
||||
}
|
||||
public void testCompiledFunctionIsClosure() throws ScriptException {
|
||||
CompiledScript cs = ((Compilable)e).compile("return 'foo'");
|
||||
LuaValue value = ((LuaScriptEngine.LuajCompiledScript)cs).function;
|
||||
assertTrue(value.isclosure());
|
||||
}
|
||||
}
|
||||
|
||||
public static class CompileNonClosureTest extends DefaultBindingsTest {
|
||||
protected void setUp() throws Exception {
|
||||
System.setProperty("org.luaj.luajc", "true");
|
||||
super.setUp();
|
||||
}
|
||||
public void testCompiledFunctionIsNotClosure() throws ScriptException {
|
||||
CompiledScript cs = ((Compilable)e).compile("return 'foo'");
|
||||
LuaValue value = ((LuaScriptEngine.LuajCompiledScript)cs).function;
|
||||
assertFalse(value.isclosure());
|
||||
}
|
||||
}
|
||||
|
||||
abstract public static class EngineTestCase extends TestCase {
|
||||
protected ScriptEngine e;
|
||||
protected Bindings b;
|
||||
abstract protected Bindings createBindings();
|
||||
protected void setUp() throws Exception {
|
||||
this.e = new ScriptEngineManager().getEngineByName("luaj");
|
||||
this.b = createBindings();
|
||||
}
|
||||
public void testSqrtIntResult() throws ScriptException {
|
||||
e.put("x", 25);
|
||||
e.eval("y = math.sqrt(x)");
|
||||
Object y = e.get("y");
|
||||
assertEquals(5, y);
|
||||
}
|
||||
public 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() {
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return LuaValue.valueOf(arg.toString()+"123");
|
||||
}
|
||||
});
|
||||
Object r = e.eval("return f('abc')");
|
||||
assertEquals("abc123", r);
|
||||
}
|
||||
public void testCompiledScript() throws ScriptException {
|
||||
CompiledScript cs = ((Compilable)e).compile("y = math.sqrt(x); return y");
|
||||
b.put("x", 144);
|
||||
assertEquals(12, cs.eval(b));
|
||||
}
|
||||
public 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.");
|
||||
}
|
||||
public 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());
|
||||
}
|
||||
public 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"));
|
||||
}
|
||||
public 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"));
|
||||
}
|
||||
public 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"));
|
||||
}
|
||||
public 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());
|
||||
}
|
||||
public 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());
|
||||
}
|
||||
public 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)));
|
||||
}
|
||||
public 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));
|
||||
}
|
||||
public 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]);
|
||||
}
|
||||
}
|
||||
|
||||
public static class SomeUserClass {
|
||||
public String toString() {
|
||||
return "some-user-value";
|
||||
}
|
||||
}
|
||||
|
||||
public static class UserContextTest extends TestCase {
|
||||
protected ScriptEngine e;
|
||||
protected Bindings b;
|
||||
protected ScriptContext c;
|
||||
public void setUp() {
|
||||
this.e = new ScriptEngineManager().getEngineByName("luaj");
|
||||
this.c = new LuajContext();
|
||||
this.b = c.getBindings(ScriptContext.ENGINE_SCOPE);
|
||||
}
|
||||
public 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"));
|
||||
}
|
||||
public 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"));
|
||||
}
|
||||
}
|
||||
|
||||
public static class WriterTest extends TestCase {
|
||||
protected ScriptEngine e;
|
||||
protected Bindings b;
|
||||
public void setUp() {
|
||||
this.e = new ScriptEngineManager().getEngineByName("luaj");
|
||||
this.b = e.getBindings(ScriptContext.ENGINE_SCOPE);
|
||||
}
|
||||
public 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user