diff --git a/.classpath b/.classpath
deleted file mode 100644
index eded28b8..00000000
--- a/.classpath
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
+ mvn clean verify +
-Other targets exist for creating distribution file an measuring code coverage of unit tests.
-The main luaj JUnit tests are organized into a JUnit 3 suite: -
- test/junit/org/luaj/vm2/AllTests.lua -+All unit tests are executed during the build.
-Unit test scripts can be found in these locations +Test scripts can be found in these locations
- test/lua/*.lua - test/lua/errors/*.lua - test/lua/perf/*.lua - test/lua/luaj3.0.2-tests.zip + luaj-test/src/test/resources+Executon is included in the build of luaj-test.
-A build script for running unit tests and producing code coverage statistics is in -
- build-coverage.xml -- -It relies on the cobertura code coverage library. +The maven build creates the coverage report in the luaj-test/target/site folder +during the verify phase.
- * The buffer can begin initially as a wrapped {@link LuaValue} - * and only when concatenation actually occurs are the bytes first copied. - *
- * To convert back to a {@link LuaValue} again, - * the function {@link Buffer#value()} is used. + * The buffer can begin initially as a wrapped {@link LuaValue} and only when + * concatenation actually occurs are the bytes first copied. + *
+ * To convert back to a {@link LuaValue} again, the function + * {@link Buffer#value()} is used. + * * @see LuaValue * @see LuaValue#buffer() * @see LuaString */ public final class Buffer { - + /** Default capacity for a buffer: 64 */ private static final int DEFAULT_CAPACITY = 64; - + /** Shared static array with no bytes */ private static final byte[] NOBYTES = {}; /** Bytes in this buffer */ private byte[] bytes; - + /** Length of this buffer */ private int length; - + /** Offset into the byte array */ private int offset; - + /** Value of this buffer, when not represented in bytes */ private LuaValue value; - + /** * Create buffer with default capacity + * * @see #DEFAULT_CAPACITY */ public Buffer() { this(DEFAULT_CAPACITY); } - + /** * Create buffer with specified initial capacity + * * @param initialCapacity the initial capacity */ - public Buffer( int initialCapacity ) { - bytes = new byte[ initialCapacity ]; + public Buffer(int initialCapacity) { + bytes = new byte[initialCapacity]; length = 0; offset = 0; value = null; } - + /** * Create buffer with specified initial value + * * @param value the initial value */ public Buffer(LuaValue value) { @@ -84,16 +87,18 @@ public final class Buffer { this.value = value; } - /** + /** * Get buffer contents as a {@link LuaValue} + * * @return value as a {@link LuaValue}, converting as necessary */ public LuaValue value() { return value != null? value: this.tostring(); } - /** + /** * Set buffer contents as a {@link LuaValue} + * * @param value value to set */ public Buffer setvalue(LuaValue value) { @@ -102,145 +107,171 @@ public final class Buffer { this.value = value; return this; } - - /** + + /** * Convert the buffer to a {@link LuaString} + * * @return the value as a {@link LuaString} */ - public final LuaString tostring() { - realloc( length, 0 ); - return LuaString.valueOf( bytes, offset, length ); + public LuaString tostring() { + realloc(length, 0); + return LuaString.valueOf(bytes, offset, length); } - - /** + + /** * Convert the buffer to a Java String + * * @return the value as a Java String */ public String tojstring() { return value().tojstring(); } - - /** + + /** * Convert the buffer to a Java String + * * @return the value as a Java String */ + @Override public String toString() { return tojstring(); } - /** + /** * Append a single byte to the buffer. + * * @return {@code this} to allow call chaining */ - public final Buffer append( byte b ) { - makeroom( 0, 1 ); - bytes[ offset + length++ ] = b; + public Buffer append(byte b) { + makeroom(0, 1); + bytes[offset+length++] = b; return this; } - /** + /** * Append a {@link LuaValue} to the buffer. + * * @return {@code this} to allow call chaining */ - public final Buffer append( LuaValue val ) { - append( val.strvalue() ); + public Buffer append(LuaValue val) { + append(val.strvalue()); return this; } - - /** + + /** * Append a {@link LuaString} to the buffer. + * * @return {@code this} to allow call chaining */ - public final Buffer append( LuaString str ) { + public Buffer append(LuaString str) { final int n = str.m_length; - makeroom( 0, n ); - str.copyInto( 0, bytes, offset + length, n ); + makeroom(0, n); + str.copyInto(0, bytes, offset+length, n); length += n; return this; } - - /** - * Append a Java String to the buffer. - * The Java string will be converted to bytes using the UTF8 encoding. + + /** + * Append a Java String to the buffer. The Java string will be converted to + * bytes using the UTF8 encoding. + * * @return {@code this} to allow call chaining * @see LuaString#encodeToUtf8(char[], int, byte[], int) */ - public final Buffer append( String str ) { + public Buffer append(String str) { char[] c = str.toCharArray(); - final int n = LuaString.lengthAsUtf8( c ); - makeroom( 0, n ); - LuaString.encodeToUtf8( c, c.length, bytes, offset + length ); + final int n = LuaString.lengthAsUtf8(c); + makeroom(0, n); + LuaString.encodeToUtf8(c, c.length, bytes, offset+length); length += n; return this; } - /** Concatenate this buffer onto a {@link LuaValue} - * @param lhs the left-hand-side value onto which we are concatenating {@code this} + /** + * Concatenate this buffer onto a {@link LuaValue} + * + * @param lhs the left-hand-side value onto which we are concatenating + * {@code this} * @return {@link Buffer} for use in call chaining. */ public Buffer concatTo(LuaValue lhs) { return setvalue(lhs.concat(value())); } - /** Concatenate this buffer onto a {@link LuaString} - * @param lhs the left-hand-side value onto which we are concatenating {@code this} + /** + * Concatenate this buffer onto a {@link LuaString} + * + * @param lhs the left-hand-side value onto which we are concatenating + * {@code this} * @return {@link Buffer} for use in call chaining. */ public Buffer concatTo(LuaString lhs) { - return value!=null&&!value.isstring()? setvalue(lhs.concat(value)): prepend(lhs); + return value != null && !value.isstring()? setvalue(lhs.concat(value)): prepend(lhs); } - /** Concatenate this buffer onto a {@link LuaNumber} + /** + * Concatenate this buffer onto a {@link LuaNumber} *
- * The {@link LuaNumber} will be converted to a string before concatenating.
- * @param lhs the left-hand-side value onto which we are concatenating {@code this}
+ * The {@link LuaNumber} will be converted to a string before concatenating.
+ *
+ * @param lhs the left-hand-side value onto which we are concatenating
+ * {@code this}
* @return {@link Buffer} for use in call chaining.
*/
public Buffer concatTo(LuaNumber lhs) {
- return value!=null&&!value.isstring()? setvalue(lhs.concat(value)): prepend(lhs.strvalue());
+ return value != null && !value.isstring()? setvalue(lhs.concat(value)): prepend(lhs.strvalue());
}
- /** Concatenate bytes from a {@link LuaString} onto the front of this buffer
- * @param s the left-hand-side value which we will concatenate onto the front of {@code this}
+ /**
+ * Concatenate bytes from a {@link LuaString} onto the front of this buffer
+ *
+ * @param s the left-hand-side value which we will concatenate onto the
+ * front of {@code this}
* @return {@link Buffer} for use in call chaining.
*/
public Buffer prepend(LuaString s) {
int n = s.m_length;
- makeroom( n, 0 );
- System.arraycopy( s.m_bytes, s.m_offset, bytes, offset-n, n );
+ makeroom(n, 0);
+ System.arraycopy(s.m_bytes, s.m_offset, bytes, offset-n, n);
offset -= n;
length += n;
value = null;
return this;
}
- /** Ensure there is enough room before and after the bytes.
- * @param nbefore number of unused bytes which must precede the data after this completes
- * @param nafter number of unused bytes which must follow the data after this completes
+ /**
+ * Ensure there is enough room before and after the bytes.
+ *
+ * @param nbefore number of unused bytes which must precede the data after
+ * this completes
+ * @param nafter number of unused bytes which must follow the data after
+ * this completes
*/
- public final void makeroom( int nbefore, int nafter ) {
- if ( value != null ) {
+ public void makeroom(int nbefore, int nafter) {
+ if (value != null) {
LuaString s = value.strvalue();
value = null;
length = s.m_length;
offset = nbefore;
bytes = new byte[nbefore+length+nafter];
System.arraycopy(s.m_bytes, s.m_offset, bytes, offset, length);
- } else if ( offset+length+nafter > bytes.length || offset
- * For specialized circumstances, the Globals may be constructed directly and loaded
- * with only those libraries that are needed, for example.
- *
- * There are alternate flows when the direct lua-to-Java bytecode compiling {@link org.luaj.vm2.luajc.LuaJC} is used.
+ * There are alternate flows when the direct lua-to-Java bytecode compiling
+ * {@link org.luaj.vm2.luajc.LuaJC} is used.
*
- *
+ *
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see LuaValue
@@ -115,7 +136,7 @@ import org.luaj.vm2.lib.ResourceFinder;
public class Globals extends LuaTable {
/** The current default input stream. */
- public InputStream STDIN = null;
+ public InputStream STDIN = null;
/** The current default output stream. */
public PrintStream STDOUT = System.out;
@@ -125,28 +146,42 @@ public class Globals extends LuaTable {
/** The installed ResourceFinder for looking files by name. */
public ResourceFinder finder;
-
- /** The currently running thread. Should not be changed by non-library code. */
+
+ /**
+ * The currently running thread. Should not be changed by non-library code.
+ */
public LuaThread running = new LuaThread(this);
/** The BaseLib instance loaded into this Globals */
public BaseLib baselib;
-
+
/** The PackageLib instance loaded into this Globals */
public PackageLib package_;
-
- /** The DebugLib instance loaded into this Globals, or null if debugging is not enabled */
+
+ /**
+ * The DebugLib instance loaded into this Globals, or null if debugging is
+ * not enabled
+ */
public DebugLib debuglib;
- /** Interface for module that converts a Prototype into a LuaFunction with an environment. */
+ /**
+ * Interface for module that converts a Prototype into a LuaFunction with an
+ * environment.
+ */
public interface Loader {
- /** Convert the prototype into a LuaFunction with the supplied environment. */
+ /**
+ * Convert the prototype into a LuaFunction with the supplied
+ * environment.
+ */
LuaFunction load(Prototype prototype, String chunkname, LuaValue env) throws IOException;
}
/** Interface for module that converts lua source text into a prototype. */
public interface Compiler {
- /** Compile lua source into a Prototype. The InputStream is assumed to be in UTF-8. */
+ /**
+ * Compile lua source into a Prototype. The InputStream is assumed to be
+ * in UTF-8.
+ */
Prototype compile(InputStream stream, String chunkname) throws IOException;
}
@@ -155,100 +190,143 @@ public class Globals extends LuaTable {
/** Load the supplied input stream into a prototype. */
Prototype undump(InputStream stream, String chunkname) throws IOException;
}
-
- /** Check that this object is a Globals object, and return it, otherwise throw an error. */
+
+ /**
+ * Check that this object is a Globals object, and return it, otherwise
+ * throw an error.
+ */
+ @Override
public Globals checkglobals() {
return this;
}
-
- /** The installed loader.
- * @see Loader */
+
+ /**
+ * The installed loader.
+ *
+ * @see Loader
+ */
public Loader loader;
- /** The installed compiler.
- * @see Compiler */
+ /**
+ * The installed compiler.
+ *
+ * @see Compiler
+ */
public Compiler compiler;
- /** The installed undumper.
- * @see Undumper */
+ /**
+ * The installed undumper.
+ *
+ * @see Undumper
+ */
public Undumper undumper;
- /** Convenience function for loading a file that is either binary lua or lua source.
+ /**
+ * Convenience function for loading a file that is either binary lua or lua
+ * source.
+ *
* @param filename Name of the file to load.
* @return LuaValue that can be call()'ed or invoke()'ed.
* @throws LuaError if the file could not be loaded.
*/
public LuaValue loadfile(String filename) {
try {
- return load(finder.findResource(filename), "@"+filename, "bt", this);
+ return load(finder.findResource(filename), "@" + filename, "bt", this);
} catch (Exception e) {
- return error("load "+filename+": "+e);
+ return error("load " + filename + ": " + e);
}
}
- /** Convenience function to load a string value as a script. Must be lua source.
- * @param script Contents of a lua script, such as "print 'hello, world.'"
+ /**
+ * Convenience function to load a string value as a script. Must be lua
+ * source.
+ *
+ * @param script Contents of a lua script, such as "print 'hello,
+ * world.'"
* @param chunkname Name that will be used within the chunk as the source.
- * @return LuaValue that may be executed via .call(), .invoke(), or .method() calls.
+ * @return LuaValue that may be executed via .call(), .invoke(), or
+ * .method() calls.
* @throws LuaError if the script could not be compiled.
*/
public LuaValue load(String script, String chunkname) {
return load(new StrReader(script), chunkname);
}
-
- /** Convenience function to load a string value as a script. Must be lua source.
+
+ /**
+ * Convenience function to load a string value as a script. Must be lua
+ * source.
+ *
* @param script Contents of a lua script, such as "print 'hello, world.'"
- * @return LuaValue that may be executed via .call(), .invoke(), or .method() calls.
+ * @return LuaValue that may be executed via .call(), .invoke(), or
+ * .method() calls.
* @throws LuaError if the script could not be compiled.
*/
public LuaValue load(String script) {
return load(new StrReader(script), script);
}
- /** Convenience function to load a string value as a script with a custom environment.
- * Must be lua source.
- * @param script Contents of a lua script, such as "print 'hello, world.'"
- * @param chunkname Name that will be used within the chunk as the source.
- * @param environment LuaTable to be used as the environment for the loaded function.
- * @return LuaValue that may be executed via .call(), .invoke(), or .method() calls.
+ /**
+ * Convenience function to load a string value as a script with a custom
+ * environment. Must be lua source.
+ *
+ * @param script Contents of a lua script, such as "print 'hello,
+ * world.'"
+ * @param chunkname Name that will be used within the chunk as the source.
+ * @param environment LuaTable to be used as the environment for the loaded
+ * function.
+ * @return LuaValue that may be executed via .call(), .invoke(), or
+ * .method() calls.
* @throws LuaError if the script could not be compiled.
*/
public LuaValue load(String script, String chunkname, LuaTable environment) {
return load(new StrReader(script), chunkname, environment);
}
- /** Load the content form a reader as a text file. Must be lua source.
- * The source is converted to UTF-8, so any characters appearing in quoted literals
- * above the range 128 will be converted into multiple bytes.
- * @param reader Reader containing text of a lua script, such as "print 'hello, world.'"
+ /**
+ * Load the content form a reader as a text file. Must be lua source. The
+ * source is converted to UTF-8, so any characters appearing in quoted
+ * literals above the range 128 will be converted into multiple bytes.
+ *
+ * @param reader Reader containing text of a lua script, such as "print
+ * 'hello, world.'"
* @param chunkname Name that will be used within the chunk as the source.
- * @return LuaValue that may be executed via .call(), .invoke(), or .method() calls.
+ * @return LuaValue that may be executed via .call(), .invoke(), or
+ * .method() calls.
* @throws LuaError if the script could not be compiled.
- */
+ */
public LuaValue load(Reader reader, String chunkname) {
return load(new UTF8Stream(reader), chunkname, "t", this);
}
- /** Load the content form a reader as a text file, supplying a custom environment.
- * Must be lua source. The source is converted to UTF-8, so any characters
- * appearing in quoted literals above the range 128 will be converted into
- * multiple bytes.
- * @param reader Reader containing text of a lua script, such as "print 'hello, world.'"
- * @param chunkname Name that will be used within the chunk as the source.
- * @param environment LuaTable to be used as the environment for the loaded function.
- * @return LuaValue that may be executed via .call(), .invoke(), or .method() calls.
+ /**
+ * Load the content form a reader as a text file, supplying a custom
+ * environment. Must be lua source. The source is converted to UTF-8, so any
+ * characters appearing in quoted literals above the range 128 will be
+ * converted into multiple bytes.
+ *
+ * @param reader Reader containing text of a lua script, such as "print
+ * 'hello, world.'"
+ * @param chunkname Name that will be used within the chunk as the source.
+ * @param environment LuaTable to be used as the environment for the loaded
+ * function.
+ * @return LuaValue that may be executed via .call(), .invoke(), or
+ * .method() calls.
* @throws LuaError if the script could not be compiled.
- */
+ */
public LuaValue load(Reader reader, String chunkname, LuaTable environment) {
return load(new UTF8Stream(reader), chunkname, "t", environment);
- }
+ }
- /** Load the content form an input stream as a binary chunk or text file.
- * @param is InputStream containing a lua script or compiled lua"
- * @param chunkname Name that will be used within the chunk as the source.
- * @param mode String containing 'b' or 't' or both to control loading as binary or text or either.
- * @param environment LuaTable to be used as the environment for the loaded function.
- * */
+ /**
+ * Load the content form an input stream as a binary chunk or text file.
+ *
+ * @param is InputStream containing a lua script or compiled lua"
+ * @param chunkname Name that will be used within the chunk as the source.
+ * @param mode String containing 'b' or 't' or both to control
+ * loading as binary or text or either.
+ * @param environment LuaTable to be used as the environment for the loaded
+ * function.
+ */
public LuaValue load(InputStream is, String chunkname, String mode, LuaValue environment) {
try {
Prototype p = loadPrototype(is, chunkname, mode);
@@ -256,16 +334,20 @@ public class Globals extends LuaTable {
} catch (LuaError l) {
throw l;
} catch (Exception e) {
- return error("load "+chunkname+": "+e);
+ return error("load " + chunkname + ": " + e);
}
}
- /** Load lua source or lua binary from an input stream into a Prototype.
- * The InputStream is either a binary lua chunk starting with the lua binary chunk signature,
- * or a text input file. If it is a text input file, it is interpreted as a UTF-8 byte sequence.
- * @param is Input stream containing a lua script or compiled lua"
+ /**
+ * Load lua source or lua binary from an input stream into a Prototype. The
+ * InputStream is either a binary lua chunk starting with the lua binary
+ * chunk signature, or a text input file. If it is a text input file, it is
+ * interpreted as a UTF-8 byte sequence.
+ *
+ * @param is Input stream containing a lua script or compiled lua"
* @param chunkname Name that will be used within the chunk as the source.
- * @param mode String containing 'b' or 't' or both to control loading as binary or text or either.
+ * @param mode String containing 'b' or 't' or both to control loading
+ * as binary or text or either.
*/
public Prototype loadPrototype(InputStream is, String chunkname, String mode) throws IOException {
if (mode.indexOf('b') >= 0) {
@@ -282,21 +364,25 @@ public class Globals extends LuaTable {
if (mode.indexOf('t') >= 0) {
return compilePrototype(is, chunkname);
}
- error("Failed to load prototype "+chunkname+" using mode '"+mode+"'");
+ error("Failed to load prototype " + chunkname + " using mode '" + mode + "'");
return null;
}
-
- /** Compile lua source from a Reader into a Prototype. The characters in the reader
- * are converted to bytes using the UTF-8 encoding, so a string literal containing
- * characters with codepoints 128 or above will be converted into multiple bytes.
+
+ /**
+ * Compile lua source from a Reader into a Prototype. The characters in the
+ * reader are converted to bytes using the UTF-8 encoding, so a string
+ * literal containing characters with codepoints 128 or above will be
+ * converted into multiple bytes.
*/
public Prototype compilePrototype(Reader reader, String chunkname) throws IOException {
return compilePrototype(new UTF8Stream(reader), chunkname);
}
-
- /** Compile lua source from an InputStream into a Prototype.
- * The input is assumed to be UTf-8, but since bytes in the range 128-255 are passed along as
- * literal bytes, any ASCII-compatible encoding such as ISO 8859-1 may also be used.
+
+ /**
+ * Compile lua source from an InputStream into a Prototype. The input is
+ * assumed to be UTf-8, but since bytes in the range 128-255 are passed
+ * along as literal bytes, any ASCII-compatible encoding such as ISO 8859-1
+ * may also be used.
*/
public Prototype compilePrototype(InputStream stream, String chunkname) throws IOException {
if (compiler == null)
@@ -304,9 +390,13 @@ public class Globals extends LuaTable {
return compiler.compile(stream, chunkname);
}
- /** Function which yields the current thread.
- * @param args Arguments to supply as return values in the resume function of the resuming thread.
- * @return Values supplied as arguments to the resume() call that reactivates this thread.
+ /**
+ * Function which yields the current thread.
+ *
+ * @param args Arguments to supply as return values in the resume function
+ * of the resuming thread.
+ * @return Values supplied as arguments to the resume() call that
+ * reactivates this thread.
*/
public Varargs yield(Varargs args) {
if (running == null || running.isMainThread())
@@ -318,23 +408,30 @@ public class Globals extends LuaTable {
/** Reader implementation to read chars from a String in JME or JSE. */
static class StrReader extends Reader {
final String s;
- int i = 0;
- final int n;
+ int i = 0;
+ final int n;
+
StrReader(String s) {
this.s = s;
n = s.length();
}
+
+ @Override
public void close() throws IOException {
i = n;
}
+
+ @Override
public int read() throws IOException {
- return i < n ? s.charAt(i++) : -1;
+ return i < n? s.charAt(i++): -1;
}
+
+ @Override
public int read(char[] cbuf, int off, int len) throws IOException {
int j = 0;
for (; j < len && i < n; ++j, ++i)
cbuf[off+j] = s.charAt(i);
- return j > 0 || len == 0 ? j : -1;
+ return j > 0 || len == 0? j: -1;
}
}
@@ -343,49 +440,67 @@ public class Globals extends LuaTable {
*/
abstract static class AbstractBufferedStream extends InputStream {
protected byte[] b;
- protected int i = 0, j = 0;
+ protected int i = 0, j = 0;
+
protected AbstractBufferedStream(int buflen) {
this.b = new byte[buflen];
}
+
abstract protected int avail() throws IOException;
+
+ @Override
public int read() throws IOException {
int a = avail();
- return (a <= 0 ? -1 : 0xff & b[i++]);
+ return a <= 0? -1: 0xff & b[i++];
}
+
+ @Override
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
+
+ @Override
public int read(byte[] b, int i0, int n) throws IOException {
int a = avail();
- if (a <= 0) return -1;
+ if (a <= 0)
+ return -1;
final int n_read = Math.min(a, n);
- System.arraycopy(this.b, i, b, i0, n_read);
+ System.arraycopy(this.b, i, b, i0, n_read);
i += n_read;
return n_read;
}
+
+ @Override
public long skip(long n) throws IOException {
- final long k = Math.min(n, j - i);
+ final long k = Math.min(n, j-i);
i += k;
return k;
- }
+ }
+
+ @Override
public int available() throws IOException {
- return j - i;
+ return j-i;
}
}
- /** Simple converter from Reader to InputStream using UTF8 encoding that will work
- * on both JME and JSE.
- * This class may be moved to its own package in the future.
+ /**
+ * Simple converter from Reader to InputStream using UTF8 encoding that will
+ * work on both JME and JSE. This class may be moved to its own package in
+ * the future.
*/
static class UTF8Stream extends AbstractBufferedStream {
private final char[] c = new char[32];
private final Reader r;
+
UTF8Stream(Reader r) {
super(96);
this.r = r;
}
+
+ @Override
protected int avail() throws IOException {
- if (i < j) return j - i;
+ if (i < j)
+ return j-i;
int n = r.read(c);
if (n < 0)
return -1;
@@ -399,31 +514,40 @@ public class Globals extends LuaTable {
j = LuaString.encodeToUtf8(c, n, b, i = 0);
return j;
}
+
+ @Override
public void close() throws IOException {
r.close();
}
}
-
- /** Simple buffered InputStream that supports mark.
- * Used to examine an InputStream for a 4-byte binary lua signature,
- * and fall back to text input when the signature is not found,
- * as well as speed up normal compilation and reading of lua scripts.
- * This class may be moved to its own package in the future.
+
+ /**
+ * Simple buffered InputStream that supports mark. Used to examine an
+ * InputStream for a 4-byte binary lua signature, and fall back to text
+ * input when the signature is not found, as well as speed up normal
+ * compilation and reading of lua scripts. This class may be moved to its
+ * own package in the future.
*/
static class BufferedStream extends AbstractBufferedStream {
private final InputStream s;
+
public BufferedStream(InputStream s) {
this(128, s);
}
+
BufferedStream(int buflen, InputStream s) {
super(buflen);
this.s = s;
}
+
+ @Override
protected int avail() throws IOException {
- if (i < j) return j - i;
- if (j >= b.length) i = j = 0;
+ if (i < j)
+ return j-i;
+ if (j >= b.length)
+ i = j = 0;
// leave previous bytes in place to implement mark()/reset().
- int n = s.read(b, j, b.length - j);
+ int n = s.read(b, j, b.length-j);
if (n < 0)
return -1;
if (n == 0) {
@@ -436,21 +560,29 @@ public class Globals extends LuaTable {
j += n;
return n;
}
+
+ @Override
public void close() throws IOException {
s.close();
}
+
+ @Override
public synchronized void mark(int n) {
if (i > 0 || n > b.length) {
- byte[] dest = n > b.length ? new byte[n] : b;
- System.arraycopy(b, i, dest, 0, j - i);
+ byte[] dest = n > b.length? new byte[n]: b;
+ System.arraycopy(b, i, dest, 0, j-i);
j -= i;
i = 0;
b = dest;
}
}
+
+ @Override
public boolean markSupported() {
return true;
}
+
+ @Override
public synchronized void reset() throws IOException {
i = 0;
}
diff --git a/src/core/org/luaj/vm2/LoadState.java b/luaj-core/src/main/java/org/luaj/vm2/LoadState.java
similarity index 51%
rename from src/core/org/luaj/vm2/LoadState.java
rename to luaj-core/src/main/java/org/luaj/vm2/LoadState.java
index 8d71a74a..3dd25cff 100644
--- a/src/core/org/luaj/vm2/LoadState.java
+++ b/luaj-core/src/main/java/org/luaj/vm2/LoadState.java
@@ -10,7 +10,7 @@
*
* 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
@@ -25,116 +25,141 @@ import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
-
/**
-* Class to undump compiled lua bytecode into a {@link Prototype} instances.
-*
-* The {@link LoadState} class provides the default {@link Globals.Undumper}
-* which is used to undump a string of bytes that represent a lua binary file
-* using either the C-based lua compiler, or luaj's
-* {@link org.luaj.vm2.compiler.LuaC} compiler.
-*
-* The canonical method to load and execute code is done
-* indirectly using the Globals:
-*
-* By default, when using {@link org.luaj.vm2.lib.jse.JsePlatform} or
-* {@link org.luaj.vm2.lib.jme.JmePlatform}
-* to construct globals, the {@link LoadState} default undumper is installed
-* as the default {@link Globals.Undumper}.
-*
-*
-* A lua binary file is created via the {@link org.luaj.vm2.compiler.DumpState} class
-:
-*
+ * The {@link LoadState} class provides the default {@link Globals.Undumper}
+ * which is used to undump a string of bytes that represent a lua binary file
+ * using either the C-based lua compiler, or luaj's
+ * {@link org.luaj.vm2.compiler.LuaC} compiler.
+ *
+ * The canonical method to load and execute code is done indirectly using the
+ * Globals:
+ *
+ *
+ * By default, when using {@link org.luaj.vm2.lib.jse.JsePlatform} or
+ * {@link org.luaj.vm2.lib.jme.JmePlatform} to construct globals, the
+ * {@link LoadState} default undumper is installed as the default
+ * {@link Globals.Undumper}.
+ *
+ *
+ * A lua binary file is created via the {@link org.luaj.vm2.compiler.DumpState}
+ * class :
+ *
+ *
- * These instance are not instantiated directly by clients.
- * Instead, there are exactly twon instances of this class,
- * {@link LuaValue#TRUE} and {@link LuaValue#FALSE}
- * representing the lua values {@code true} and {@code false}.
- * The function {@link LuaValue#valueOf(boolean)} will always
- * return one of these two values.
+ * These instance are not instantiated directly by clients. Instead, there are
+ * exactly twon instances of this class, {@link LuaValue#TRUE} and
+ * {@link LuaValue#FALSE} representing the lua values {@code true} and
+ * {@code false}. The function {@link LuaValue#valueOf(boolean)} will always
+ * return one of these two values.
*
- * Any {@link LuaValue} can be converted to its equivalent
- * boolean representation using {@link LuaValue#toboolean()}
+ * Any {@link LuaValue} can be converted to its equivalent boolean
+ * representation using {@link LuaValue#toboolean()}
*
+ *
* @see LuaValue
* @see LuaValue#valueOf(boolean)
* @see LuaValue#TRUE
@@ -43,10 +43,10 @@ public final class LuaBoolean extends LuaValue {
/** The singleton instance representing lua {@code true} */
static final LuaBoolean _TRUE = new LuaBoolean(true);
-
+
/** The singleton instance representing lua {@code false} */
static final LuaBoolean _FALSE = new LuaBoolean(false);
-
+
/** Shared static metatable for boolean values represented in lua. */
public static LuaValue s_metatable;
@@ -57,47 +57,57 @@ public final class LuaBoolean extends LuaValue {
this.v = b;
}
+ @Override
public int type() {
return LuaValue.TBOOLEAN;
}
+ @Override
public String typename() {
return "boolean";
}
+ @Override
public boolean isboolean() {
return true;
}
+ @Override
public LuaValue not() {
- return v ? FALSE : LuaValue.TRUE;
+ return v? FALSE: LuaValue.TRUE;
}
/**
* Return the boolean value for this boolean
+ *
* @return value as a Java boolean
*/
public boolean booleanValue() {
return v;
}
+ @Override
public boolean toboolean() {
return v;
}
+ @Override
public String tojstring() {
- return v ? "true" : "false";
+ return v? "true": "false";
}
+ @Override
public boolean optboolean(boolean defval) {
return this.v;
}
-
+
+ @Override
public boolean checkboolean() {
return v;
}
-
- public LuaValue getmetatable() {
- return s_metatable;
+
+ @Override
+ public LuaValue getmetatable() {
+ return s_metatable;
}
}
diff --git a/src/core/org/luaj/vm2/LuaClosure.java b/luaj-core/src/main/java/org/luaj/vm2/LuaClosure.java
similarity index 52%
rename from src/core/org/luaj/vm2/LuaClosure.java
rename to luaj-core/src/main/java/org/luaj/vm2/LuaClosure.java
index 46a3556f..5354246c 100644
--- a/src/core/org/luaj/vm2/LuaClosure.java
+++ b/luaj-core/src/main/java/org/luaj/vm2/LuaClosure.java
@@ -10,7 +10,7 @@
*
* 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
@@ -26,44 +26,56 @@ import org.luaj.vm2.lib.DebugLib.CallFrame;
/**
* Extension of {@link LuaFunction} which executes lua bytecode.
*
- * A {@link LuaClosure} is a combination of a {@link Prototype}
- * and a {@link LuaValue} to use as an environment for execution.
- * Normally the {@link LuaValue} is a {@link Globals} in which case the environment
- * will contain standard lua libraries.
- *
+ * A {@link LuaClosure} is a combination of a {@link Prototype} and a
+ * {@link LuaValue} to use as an environment for execution. Normally the
+ * {@link LuaValue} is a {@link Globals} in which case the environment will
+ * contain standard lua libraries.
+ *
*
* There are three main ways {@link LuaClosure} instances are created:
*
- * To construct it directly, the {@link Prototype} is typically created via a compiler such as
- * {@link org.luaj.vm2.compiler.LuaC}:
- *
- * To construct it indirectly, the {@link Globals#load(java.io.Reader, String)} method may be used:
- *
* In this example, the "checkclosure()" may fail if direct lua-to-java-bytecode
- * compiling using LuaJC is installed, because no LuaClosure is created in that case
- * and the value returned is a {@link LuaFunction} but not a {@link LuaClosure}.
+ * compiling using LuaJC is installed, because no LuaClosure is created in that
+ * case and the value returned is a {@link LuaFunction} but not a
+ * {@link LuaClosure}.
*
- * Since a {@link LuaClosure} is a {@link LuaFunction} which is a {@link LuaValue},
- * all the value operations can be used directly such as:
+ * Since a {@link LuaClosure} is a {@link LuaFunction} which is a
+ * {@link LuaValue}, all the value operations can be used directly such as:
*
+ * These instance are not instantiated directly by clients, but indirectly via
+ * the static functions {@link LuaValue#valueOf(int)} or
+ * {@link LuaValue#valueOf(double)} functions. This ensures that values which
+ * can be represented as int are wrapped in {@link LuaInteger} instead of
+ * {@link LuaDouble}.
+ *
+ * Almost all API's implemented in LuaDouble are defined and documented in
+ * {@link LuaValue}.
+ *
+ * However the constants {@link #NAN}, {@link #POSINF}, {@link #NEGINF},
+ * {@link #JSTR_NAN}, {@link #JSTR_POSINF}, and {@link #JSTR_NEGINF} may be
+ * useful when dealing with Nan or Infinite values.
+ *
+ * LuaDouble also defines functions for handling the unique math rules of lua
+ * devision and modulo in
+ *
+ *
+ * @see LuaValue
+ * @see LuaNumber
+ * @see LuaInteger
+ * @see LuaValue#valueOf(int)
+ * @see LuaValue#valueOf(double)
+ */
+public class LuaDouble extends LuaNumber {
+
+ /** Constant LuaDouble representing NaN (not a number) */
+ public static final LuaDouble NAN = new LuaDouble(Double.NaN);
+
+ /** Constant LuaDouble representing positive infinity */
+ public static final LuaDouble POSINF = new LuaDouble(Double.POSITIVE_INFINITY);
+
+ /** Constant LuaDouble representing negative infinity */
+ public static final LuaDouble NEGINF = new LuaDouble(Double.NEGATIVE_INFINITY);
+
+ /** Constant String representation for NaN (not a number), "nan" */
+ public static final String JSTR_NAN = "nan";
+
+ /** Constant String representation for positive infinity, "inf" */
+ public static final String JSTR_POSINF = "inf";
+
+ /** Constant String representation for negative infinity, "-inf" */
+ public static final String JSTR_NEGINF = "-inf";
+
+ /** The value being held by this instance. */
+ final double v;
+
+ public static LuaNumber valueOf(double d) {
+ int id = (int) d;
+ return d == id? (LuaNumber) LuaInteger.valueOf(id): (LuaNumber) new LuaDouble(d);
+ }
+
+ /** Don't allow ints to be boxed by DoubleValues */
+ private LuaDouble(double d) {
+ this.v = d;
+ }
+
+ @Override
+ public int hashCode() {
+ long l = Double.doubleToLongBits(v+1);
+ return (int) (l>>32)+(int) l;
+ }
+
+ @Override
+ public boolean islong() {
+ return v == (long) v;
+ }
+
+ @Override
+ public byte tobyte() { return (byte) (long) v; }
+
+ @Override
+ public char tochar() { return (char) (long) v; }
+
+ @Override
+ public double todouble() { return v; }
+
+ @Override
+ public float tofloat() { return (float) v; }
+
+ @Override
+ public int toint() { return (int) (long) v; }
+
+ @Override
+ public long tolong() { return (long) v; }
+
+ @Override
+ public short toshort() { return (short) (long) v; }
+
+ @Override
+ public double optdouble(double defval) { return v; }
+
+ @Override
+ public int optint(int defval) { return (int) (long) v; }
+
+ @Override
+ public LuaInteger optinteger(LuaInteger defval) { return LuaInteger.valueOf((int) (long) v); }
+
+ @Override
+ public long optlong(long defval) { return (long) v; }
+
+ @Override
+ public LuaInteger checkinteger() { return LuaInteger.valueOf((int) (long) v); }
+
+ // unary operators
+ @Override
+ public LuaValue neg() { return valueOf(-v); }
+
+ // object equality, used for key comparison
+ @Override
+ public boolean equals(Object o) { return o instanceof LuaDouble? ((LuaDouble) o).v == v: false; }
+
+ // equality w/ metatable processing
+ @Override
+ public LuaValue eq(LuaValue val) { return val.raweq(v)? TRUE: FALSE; }
+
+ @Override
+ public boolean eq_b(LuaValue val) { return val.raweq(v); }
+
+ // equality w/o metatable processing
+ @Override
+ public boolean raweq(LuaValue val) { return val.raweq(v); }
+
+ @Override
+ public boolean raweq(double val) { return v == val; }
+
+ @Override
+ public boolean raweq(int val) { return v == val; }
+
+ // basic binary arithmetic
+ @Override
+ public LuaValue add(LuaValue rhs) { return rhs.add(v); }
+
+ @Override
+ public LuaValue add(double lhs) { return LuaDouble.valueOf(lhs+v); }
+
+ @Override
+ public LuaValue sub(LuaValue rhs) { return rhs.subFrom(v); }
+
+ @Override
+ public LuaValue sub(double rhs) { return LuaDouble.valueOf(v-rhs); }
+
+ @Override
+ public LuaValue sub(int rhs) { return LuaDouble.valueOf(v-rhs); }
+
+ @Override
+ public LuaValue subFrom(double lhs) { return LuaDouble.valueOf(lhs-v); }
+
+ @Override
+ public LuaValue mul(LuaValue rhs) { return rhs.mul(v); }
+
+ @Override
+ public LuaValue mul(double lhs) { return LuaDouble.valueOf(lhs*v); }
+
+ @Override
+ public LuaValue mul(int lhs) { return LuaDouble.valueOf(lhs*v); }
+
+ @Override
+ public LuaValue pow(LuaValue rhs) { return rhs.powWith(v); }
+
+ @Override
+ public LuaValue pow(double rhs) { return MathLib.dpow(v, rhs); }
+
+ @Override
+ public LuaValue pow(int rhs) { return MathLib.dpow(v, rhs); }
+
+ @Override
+ public LuaValue powWith(double lhs) { return MathLib.dpow(lhs, v); }
+
+ @Override
+ public LuaValue powWith(int lhs) { return MathLib.dpow(lhs, v); }
+
+ @Override
+ public LuaValue div(LuaValue rhs) { return rhs.divInto(v); }
+
+ @Override
+ public LuaValue div(double rhs) { return LuaDouble.ddiv(v, rhs); }
+
+ @Override
+ public LuaValue div(int rhs) { return LuaDouble.ddiv(v, rhs); }
+
+ @Override
+ public LuaValue divInto(double lhs) { return LuaDouble.ddiv(lhs, v); }
+
+ @Override
+ public LuaValue mod(LuaValue rhs) { return rhs.modFrom(v); }
+
+ @Override
+ public LuaValue mod(double rhs) { return LuaDouble.dmod(v, rhs); }
+
+ @Override
+ public LuaValue mod(int rhs) { return LuaDouble.dmod(v, rhs); }
+
+ @Override
+ public LuaValue modFrom(double lhs) { return LuaDouble.dmod(lhs, v); }
+
+ /**
+ * Divide two double numbers according to lua math, and return a
+ * {@link LuaValue} result.
+ *
+ * @param lhs Left-hand-side of the division.
+ * @param rhs Right-hand-side of the division.
+ * @return {@link LuaValue} for the result of the division, taking into
+ * account positive and negiative infinity, and Nan
+ * @see #ddiv_d(double, double)
+ */
+ public static LuaValue ddiv(double lhs, double rhs) {
+ return rhs != 0? valueOf(lhs/rhs): lhs > 0? POSINF: lhs == 0? NAN: NEGINF;
+ }
+
+ /**
+ * Divide two double numbers according to lua math, and return a double
+ * result.
+ *
+ * @param lhs Left-hand-side of the division.
+ * @param rhs Right-hand-side of the division.
+ * @return Value of the division, taking into account positive and negative
+ * infinity, and Nan
+ * @see #ddiv(double, double)
+ */
+ public static double ddiv_d(double lhs, double rhs) {
+ return rhs != 0? lhs/rhs: lhs > 0? Double.POSITIVE_INFINITY: lhs == 0? Double.NaN: Double.NEGATIVE_INFINITY;
+ }
+
+ /**
+ * Take modulo double numbers according to lua math, and return a
+ * {@link LuaValue} result.
+ *
+ * @param lhs Left-hand-side of the modulo.
+ * @param rhs Right-hand-side of the modulo.
+ * @return {@link LuaValue} for the result of the modulo, using lua's rules
+ * for modulo
+ * @see #dmod_d(double, double)
+ */
+ public static LuaValue dmod(double lhs, double rhs) {
+ if (rhs == 0 || lhs == Double.POSITIVE_INFINITY || lhs == Double.NEGATIVE_INFINITY)
+ return NAN;
+ if (rhs == Double.POSITIVE_INFINITY) {
+ return lhs < 0? POSINF: valueOf(lhs);
+ }
+ if (rhs == Double.NEGATIVE_INFINITY) {
+ return lhs > 0? NEGINF: valueOf(lhs);
+ }
+ return valueOf(lhs-rhs*Math.floor(lhs/rhs));
+ }
+
+ /**
+ * Take modulo for double numbers according to lua math, and return a double
+ * result.
+ *
+ * @param lhs Left-hand-side of the modulo.
+ * @param rhs Right-hand-side of the modulo.
+ * @return double value for the result of the modulo, using lua's rules for
+ * modulo
+ * @see #dmod(double, double)
+ */
+ public static double dmod_d(double lhs, double rhs) {
+ if (rhs == 0 || lhs == Double.POSITIVE_INFINITY || lhs == Double.NEGATIVE_INFINITY)
+ return Double.NaN;
+ if (rhs == Double.POSITIVE_INFINITY) {
+ return lhs < 0? Double.POSITIVE_INFINITY: lhs;
+ }
+ if (rhs == Double.NEGATIVE_INFINITY) {
+ return lhs > 0? Double.NEGATIVE_INFINITY: lhs;
+ }
+ return lhs-rhs*Math.floor(lhs/rhs);
+ }
+
+ // relational operators
+ @Override
+ public LuaValue lt(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.gt_b(v)? TRUE: FALSE: super.lt(rhs); }
+
+ @Override
+ public LuaValue lt(double rhs) { return v < rhs? TRUE: FALSE; }
+
+ @Override
+ public LuaValue lt(int rhs) { return v < rhs? TRUE: FALSE; }
+
+ @Override
+ public boolean lt_b(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.gt_b(v): super.lt_b(rhs); }
+
+ @Override
+ public boolean lt_b(int rhs) { return v < rhs; }
+
+ @Override
+ public boolean lt_b(double rhs) { return v < rhs; }
+
+ @Override
+ public LuaValue lteq(LuaValue rhs) {
+ return rhs instanceof LuaNumber? rhs.gteq_b(v)? TRUE: FALSE: super.lteq(rhs);
+ }
+
+ @Override
+ public LuaValue lteq(double rhs) { return v <= rhs? TRUE: FALSE; }
+
+ @Override
+ public LuaValue lteq(int rhs) { return v <= rhs? TRUE: FALSE; }
+
+ @Override
+ public boolean lteq_b(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.gteq_b(v): super.lteq_b(rhs); }
+
+ @Override
+ public boolean lteq_b(int rhs) { return v <= rhs; }
+
+ @Override
+ public boolean lteq_b(double rhs) { return v <= rhs; }
+
+ @Override
+ public LuaValue gt(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.lt_b(v)? TRUE: FALSE: super.gt(rhs); }
+
+ @Override
+ public LuaValue gt(double rhs) { return v > rhs? TRUE: FALSE; }
+
+ @Override
+ public LuaValue gt(int rhs) { return v > rhs? TRUE: FALSE; }
+
+ @Override
+ public boolean gt_b(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.lt_b(v): super.gt_b(rhs); }
+
+ @Override
+ public boolean gt_b(int rhs) { return v > rhs; }
+
+ @Override
+ public boolean gt_b(double rhs) { return v > rhs; }
+
+ @Override
+ public LuaValue gteq(LuaValue rhs) {
+ return rhs instanceof LuaNumber? rhs.lteq_b(v)? TRUE: FALSE: super.gteq(rhs);
+ }
+
+ @Override
+ public LuaValue gteq(double rhs) { return v >= rhs? TRUE: FALSE; }
+
+ @Override
+ public LuaValue gteq(int rhs) { return v >= rhs? TRUE: FALSE; }
+
+ @Override
+ public boolean gteq_b(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.lteq_b(v): super.gteq_b(rhs); }
+
+ @Override
+ public boolean gteq_b(int rhs) { return v >= rhs; }
+
+ @Override
+ public boolean gteq_b(double rhs) { return v >= rhs; }
+
+ // string comparison
+ @Override
+ public int strcmp(LuaString rhs) { typerror("attempt to compare number with string"); return 0; }
+
+ @Override
+ public String tojstring() {
+ /*
+ if ( v == 0.0 ) { // never occurs in J2me
+ long bits = Double.doubleToLongBits( v );
+ return ( bits >> 63 == 0 ) ? "0" : "-0";
+ }
+ */
+ long l = (long) v;
+ if (l == v)
+ return Long.toString(l);
+ if (Double.isNaN(v))
+ return JSTR_NAN;
+ if (Double.isInfinite(v))
+ return v < 0? JSTR_NEGINF: JSTR_POSINF;
+ return Float.toString((float) v);
+ }
+
+ @Override
+ public LuaString strvalue() {
+ return LuaString.valueOf(tojstring());
+ }
+
+ @Override
+ public LuaString optstring(LuaString defval) {
+ return LuaString.valueOf(tojstring());
+ }
+
+ @Override
+ public LuaValue tostring() {
+ return LuaString.valueOf(tojstring());
+ }
+
+ @Override
+ public String optjstring(String defval) {
+ return tojstring();
+ }
+
+ @Override
+ public LuaNumber optnumber(LuaNumber defval) {
+ return this;
+ }
+
+ @Override
+ public boolean isnumber() {
+ return true;
+ }
+
+ @Override
+ public boolean isstring() {
+ return true;
+ }
+
+ @Override
+ public LuaValue tonumber() {
+ return this;
+ }
+
+ @Override
+ public int checkint() { return (int) (long) v; }
+
+ @Override
+ public long checklong() { return (long) v; }
+
+ @Override
+ public LuaNumber checknumber() { return this; }
+
+ @Override
+ public double checkdouble() { return v; }
+
+ @Override
+ public String checkjstring() {
+ return tojstring();
+ }
+
+ @Override
+ public LuaString checkstring() {
+ return LuaString.valueOf(tojstring());
+ }
+
+ @Override
+ public boolean isvalidkey() {
+ return !Double.isNaN(v);
+ }
+}
diff --git a/src/core/org/luaj/vm2/LuaError.java b/luaj-core/src/main/java/org/luaj/vm2/LuaError.java
similarity index 67%
rename from src/core/org/luaj/vm2/LuaError.java
rename to luaj-core/src/main/java/org/luaj/vm2/LuaError.java
index 37a8df8d..b24f4a98 100644
--- a/src/core/org/luaj/vm2/LuaError.java
+++ b/luaj-core/src/main/java/org/luaj/vm2/LuaError.java
@@ -10,7 +10,7 @@
*
* 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
@@ -21,39 +21,40 @@
******************************************************************************/
package org.luaj.vm2;
-
/**
- * RuntimeException that is thrown and caught in response to a lua error.
+ * RuntimeException that is thrown and caught in response to a lua error.
*
- * {@link LuaError} is used wherever a lua call to {@code error()}
- * would be used within a script.
+ * {@link LuaError} is used wherever a lua call to {@code error()} would be used
+ * within a script.
*
* Since it is an unchecked exception inheriting from {@link RuntimeException},
- * Java method signatures do notdeclare this exception, althoug it can
- * be thrown on almost any luaj Java operation.
- * This is analagous to the fact that any lua script can throw a lua error at any time.
- *
- * The LuaError may be constructed with a message object, in which case the message
- * is the string representation of that object. getMessageObject will get the object
- * supplied at construct time, or a LuaString containing the message of an object
- * was not supplied.
+ * Java method signatures do notdeclare this exception, althoug it can be thrown
+ * on almost any luaj Java operation. This is analagous to the fact that any lua
+ * script can throw a lua error at any time.
+ *
+ * The LuaError may be constructed with a message object, in which case the
+ * message is the string representation of that object. getMessageObject will
+ * get the object supplied at construct time, or a LuaString containing the
+ * message of an object was not supplied.
*/
public class LuaError extends RuntimeException {
private static final long serialVersionUID = 1L;
-
+
protected int level;
-
+
protected String fileline;
-
+
protected String traceback;
-
+
protected Throwable cause;
private LuaValue object;
-
- /** Get the string message if it was supplied, or a string
- * representation of the message object if that was supplied.
+
+ /**
+ * Get the string message if it was supplied, or a string representation of
+ * the message object if that was supplied.
*/
+ @Override
public String getMessage() {
if (traceback != null)
return traceback;
@@ -65,66 +66,71 @@ public class LuaError extends RuntimeException {
return m;
}
- /** Get the LuaValue that was provided in the constructor, or
- * a LuaString containing the message if it was a string error argument.
+ /**
+ * Get the LuaValue that was provided in the constructor, or a LuaString
+ * containing the message if it was a string error argument.
+ *
* @return LuaValue which was used in the constructor, or a LuaString
- * containing the message.
+ * containing the message.
*/
public LuaValue getMessageObject() {
- if (object != null) return object;
+ if (object != null)
+ return object;
String m = getMessage();
- return m != null ? LuaValue.valueOf(m): null;
+ return m != null? LuaValue.valueOf(m): null;
}
-
- /** Construct LuaError when a program exception occurs.
- *
+
+ /**
+ * Construct LuaError when a program exception occurs.
+ *
* All errors generated from lua code should throw LuaError(String) instead.
- * @param cause the Throwable that caused the error, if known.
+ *
+ * @param cause the Throwable that caused the error, if known.
*/
public LuaError(Throwable cause) {
- super( "vm error: "+cause );
+ super("vm error: " + cause);
this.cause = cause;
this.level = 1;
}
/**
- * Construct a LuaError with a specific message.
- *
+ * Construct a LuaError with a specific message.
+ *
* @param message message to supply
*/
public LuaError(String message) {
- super( message );
+ super(message);
this.level = 1;
- }
+ }
/**
- * Construct a LuaError with a message, and level to draw line number information from.
+ * Construct a LuaError with a message, and level to draw line number
+ * information from.
+ *
* @param message message to supply
- * @param level where to supply line info from in call stack
+ * @param level where to supply line info from in call stack
*/
public LuaError(String message, int level) {
- super( message );
+ super(message);
this.level = level;
- }
+ }
/**
- * Construct a LuaError with a LuaValue as the message object,
- * and level to draw line number information from.
+ * Construct a LuaError with a LuaValue as the message object, and level to
+ * draw line number information from.
+ *
* @param message_object message string or object to supply
*/
public LuaError(LuaValue message_object) {
- super( message_object.tojstring() );
+ super(message_object.tojstring());
this.object = message_object;
this.level = 1;
- }
-
-
- /**
- * Get the cause, if any.
- */
- public Throwable getCause() {
- return cause;
}
+ /**
+ * Get the cause, if any.
+ */
+ @Override
+ public Throwable getCause() { return cause; }
}
diff --git a/src/core/org/luaj/vm2/LuaFunction.java b/luaj-core/src/main/java/org/luaj/vm2/LuaFunction.java
similarity index 67%
rename from src/core/org/luaj/vm2/LuaFunction.java
rename to luaj-core/src/main/java/org/luaj/vm2/LuaFunction.java
index 83bee86d..38403bd7 100644
--- a/src/core/org/luaj/vm2/LuaFunction.java
+++ b/luaj-core/src/main/java/org/luaj/vm2/LuaFunction.java
@@ -10,7 +10,7 @@
*
* 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
@@ -21,71 +21,86 @@
******************************************************************************/
package org.luaj.vm2;
-
/**
* Base class for functions implemented in Java.
*
- * Direct subclass include {@link org.luaj.vm2.lib.LibFunction}
- * which is the base class for
- * all built-in library functions coded in Java,
- * and {@link LuaClosure}, which represents a lua closure
- * whose bytecode is interpreted when the function is invoked.
+ * Direct subclass include {@link org.luaj.vm2.lib.LibFunction} which is the
+ * base class for all built-in library functions coded in Java, and
+ * {@link LuaClosure}, which represents a lua closure whose bytecode is
+ * interpreted when the function is invoked.
+ *
* @see LuaValue
* @see LuaClosure
* @see org.luaj.vm2.lib.LibFunction
*/
-abstract
-public class LuaFunction extends LuaValue {
-
+abstract public class LuaFunction extends LuaValue {
+
/** Shared static metatable for all functions and closures. */
public static LuaValue s_metatable;
+ @Override
public int type() {
return TFUNCTION;
}
-
+
+ @Override
public String typename() {
return "function";
}
-
+
+ @Override
public boolean isfunction() {
return true;
}
- public LuaFunction checkfunction() {
+ @Override
+ public LuaFunction checkfunction() {
return this;
}
-
+
+ @Override
public LuaFunction optfunction(LuaFunction defval) {
return this;
}
+ @Override
public LuaValue getmetatable() {
return s_metatable;
}
+ @Override
public String tojstring() {
return "function: " + classnamestub();
}
+ @Override
public LuaString strvalue() {
return valueOf(tojstring());
}
- /** Return the last part of the class name, to be used as a function name in tojstring and elsewhere.
- * @return String naming the last part of the class name after the last dot (.) or dollar sign ($).
- * If the first character is '_', it is skipped.
+ /**
+ * Return the last part of the class name, to be used as a function name in
+ * tojstring and elsewhere.
+ *
+ * @return String naming the last part of the class name after the last dot
+ * (.) or dollar sign ($). If the first character is '_', it is
+ * skipped.
*/
public String classnamestub() {
String s = getClass().getName();
- int offset = Math.max(s.lastIndexOf('.'), s.lastIndexOf('$')) + 1;
- if (s.charAt(offset) == '_') offset++;
+ int offset = Math.max(s.lastIndexOf('.'), s.lastIndexOf('$'))+1;
+ if (s.charAt(offset) == '_')
+ offset++;
return s.substring(offset);
}
-
- /** Return a human-readable name for this function. Returns the last part of the class name by default.
- * Is overridden by LuaClosure to return the source file and line, and by LibFunctions to return the name.
- * @return common name for this function. */
+
+ /**
+ * Return a human-readable name for this function. Returns the last part of
+ * the class name by default. Is overridden by LuaClosure to return the
+ * source file and line, and by LibFunctions to return the name.
+ *
+ * @return common name for this function.
+ */
public String name() {
return classnamestub();
}
diff --git a/luaj-core/src/main/java/org/luaj/vm2/LuaInteger.java b/luaj-core/src/main/java/org/luaj/vm2/LuaInteger.java
new file mode 100644
index 00000000..ac41cb9b
--- /dev/null
+++ b/luaj-core/src/main/java/org/luaj/vm2/LuaInteger.java
@@ -0,0 +1,372 @@
+/*******************************************************************************
+* Copyright (c) 2009 Luaj.org. All rights reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+******************************************************************************/
+package org.luaj.vm2;
+
+import org.luaj.vm2.lib.MathLib;
+
+/**
+ * Extension of {@link LuaNumber} which can hold a Java int as its value.
+ *
+ * These instance are not instantiated directly by clients, but indirectly via
+ * the static functions {@link LuaValue#valueOf(int)} or
+ * {@link LuaValue#valueOf(double)} functions. This ensures that policies
+ * regarding pooling of instances are encapsulated.
+ *
+ * There are no API's specific to LuaInteger that are useful beyond what is
+ * already exposed in {@link LuaValue}.
+ *
+ * @see LuaValue
+ * @see LuaNumber
+ * @see LuaDouble
+ * @see LuaValue#valueOf(int)
+ * @see LuaValue#valueOf(double)
+ */
+public class LuaInteger extends LuaNumber {
+
+ private static final LuaInteger[] intValues = new LuaInteger[512];
+ static {
+ for (int i = 0; i < 512; i++)
+ intValues[i] = new LuaInteger(i-256);
+ }
+
+ public static LuaInteger valueOf(int i) {
+ return i <= 255 && i >= -256? intValues[i+256]: new LuaInteger(i);
+ }
+
+ // TODO consider moving this to LuaValue
+ /**
+ * Return a LuaNumber that represents the value provided
+ *
+ * @param l long value to represent.
+ * @return LuaNumber that is eithe LuaInteger or LuaDouble representing l
+ * @see LuaValue#valueOf(int)
+ * @see LuaValue#valueOf(double)
+ */
+ public static LuaNumber valueOf(long l) {
+ int i = (int) l;
+ return l == i? i <= 255 && i >= -256? intValues[i+256]: (LuaNumber) new LuaInteger(i)
+ : (LuaNumber) LuaDouble.valueOf(l);
+ }
+
+ /** The value being held by this instance. */
+ public final int v;
+
+ /**
+ * Package protected constructor.
+ *
+ * @see LuaValue#valueOf(int)
+ **/
+ LuaInteger(int i) {
+ this.v = i;
+ }
+
+ @Override
+ public boolean isint() { return true; }
+
+ @Override
+ public boolean isinttype() { return true; }
+
+ @Override
+ public boolean islong() { return true; }
+
+ @Override
+ public byte tobyte() { return (byte) v; }
+
+ @Override
+ public char tochar() { return (char) v; }
+
+ @Override
+ public double todouble() { return v; }
+
+ @Override
+ public float tofloat() { return v; }
+
+ @Override
+ public int toint() { return v; }
+
+ @Override
+ public long tolong() { return v; }
+
+ @Override
+ public short toshort() { return (short) v; }
+
+ @Override
+ public double optdouble(double defval) { return v; }
+
+ @Override
+ public int optint(int defval) { return v; }
+
+ @Override
+ public LuaInteger optinteger(LuaInteger defval) { return this; }
+
+ @Override
+ public long optlong(long defval) { return v; }
+
+ @Override
+ public String tojstring() {
+ return Integer.toString(v);
+ }
+
+ @Override
+ public LuaString strvalue() {
+ return LuaString.valueOf(Integer.toString(v));
+ }
+
+ @Override
+ public LuaString optstring(LuaString defval) {
+ return LuaString.valueOf(Integer.toString(v));
+ }
+
+ @Override
+ public LuaValue tostring() {
+ return LuaString.valueOf(Integer.toString(v));
+ }
+
+ @Override
+ public String optjstring(String defval) {
+ return Integer.toString(v);
+ }
+
+ @Override
+ public LuaInteger checkinteger() {
+ return this;
+ }
+
+ @Override
+ public boolean isstring() {
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return v;
+ }
+
+ public static int hashCode(int x) {
+ return x;
+ }
+
+ // unary operators
+ @Override
+ public LuaValue neg() { return valueOf(-(long) v); }
+
+ // object equality, used for key comparison
+ @Override
+ public boolean equals(Object o) { return o instanceof LuaInteger? ((LuaInteger) o).v == v: false; }
+
+ // equality w/ metatable processing
+ @Override
+ public LuaValue eq(LuaValue val) { return val.raweq(v)? TRUE: FALSE; }
+
+ @Override
+ public boolean eq_b(LuaValue val) { return val.raweq(v); }
+
+ // equality w/o metatable processing
+ @Override
+ public boolean raweq(LuaValue val) { return val.raweq(v); }
+
+ @Override
+ public boolean raweq(double val) { return v == val; }
+
+ @Override
+ public boolean raweq(int val) { return v == val; }
+
+ // arithmetic operators
+ @Override
+ public LuaValue add(LuaValue rhs) { return rhs.add(v); }
+
+ @Override
+ public LuaValue add(double lhs) { return LuaDouble.valueOf(lhs+v); }
+
+ @Override
+ public LuaValue add(int lhs) { return LuaInteger.valueOf(lhs+(long) v); }
+
+ @Override
+ public LuaValue sub(LuaValue rhs) { return rhs.subFrom(v); }
+
+ @Override
+ public LuaValue sub(double rhs) { return LuaDouble.valueOf(v-rhs); }
+
+ @Override
+ public LuaValue sub(int rhs) { return LuaValue.valueOf(v-rhs); }
+
+ @Override
+ public LuaValue subFrom(double lhs) { return LuaDouble.valueOf(lhs-v); }
+
+ @Override
+ public LuaValue subFrom(int lhs) { return LuaInteger.valueOf(lhs-(long) v); }
+
+ @Override
+ public LuaValue mul(LuaValue rhs) { return rhs.mul(v); }
+
+ @Override
+ public LuaValue mul(double lhs) { return LuaDouble.valueOf(lhs*v); }
+
+ @Override
+ public LuaValue mul(int lhs) { return LuaInteger.valueOf(lhs*(long) v); }
+
+ @Override
+ public LuaValue pow(LuaValue rhs) { return rhs.powWith(v); }
+
+ @Override
+ public LuaValue pow(double rhs) { return MathLib.dpow(v, rhs); }
+
+ @Override
+ public LuaValue pow(int rhs) { return MathLib.dpow(v, rhs); }
+
+ @Override
+ public LuaValue powWith(double lhs) { return MathLib.dpow(lhs, v); }
+
+ @Override
+ public LuaValue powWith(int lhs) { return MathLib.dpow(lhs, v); }
+
+ @Override
+ public LuaValue div(LuaValue rhs) { return rhs.divInto(v); }
+
+ @Override
+ public LuaValue div(double rhs) { return LuaDouble.ddiv(v, rhs); }
+
+ @Override
+ public LuaValue div(int rhs) { return LuaDouble.ddiv(v, rhs); }
+
+ @Override
+ public LuaValue divInto(double lhs) { return LuaDouble.ddiv(lhs, v); }
+
+ @Override
+ public LuaValue mod(LuaValue rhs) { return rhs.modFrom(v); }
+
+ @Override
+ public LuaValue mod(double rhs) { return LuaDouble.dmod(v, rhs); }
+
+ @Override
+ public LuaValue mod(int rhs) { return LuaDouble.dmod(v, rhs); }
+
+ @Override
+ public LuaValue modFrom(double lhs) { return LuaDouble.dmod(lhs, v); }
+
+ // relational operators
+ @Override
+ public LuaValue lt(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.gt_b(v)? TRUE: FALSE: super.lt(rhs); }
+
+ @Override
+ public LuaValue lt(double rhs) { return v < rhs? TRUE: FALSE; }
+
+ @Override
+ public LuaValue lt(int rhs) { return v < rhs? TRUE: FALSE; }
+
+ @Override
+ public boolean lt_b(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.gt_b(v): super.lt_b(rhs); }
+
+ @Override
+ public boolean lt_b(int rhs) { return v < rhs; }
+
+ @Override
+ public boolean lt_b(double rhs) { return v < rhs; }
+
+ @Override
+ public LuaValue lteq(LuaValue rhs) {
+ return rhs instanceof LuaNumber? rhs.gteq_b(v)? TRUE: FALSE: super.lteq(rhs);
+ }
+
+ @Override
+ public LuaValue lteq(double rhs) { return v <= rhs? TRUE: FALSE; }
+
+ @Override
+ public LuaValue lteq(int rhs) { return v <= rhs? TRUE: FALSE; }
+
+ @Override
+ public boolean lteq_b(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.gteq_b(v): super.lteq_b(rhs); }
+
+ @Override
+ public boolean lteq_b(int rhs) { return v <= rhs; }
+
+ @Override
+ public boolean lteq_b(double rhs) { return v <= rhs; }
+
+ @Override
+ public LuaValue gt(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.lt_b(v)? TRUE: FALSE: super.gt(rhs); }
+
+ @Override
+ public LuaValue gt(double rhs) { return v > rhs? TRUE: FALSE; }
+
+ @Override
+ public LuaValue gt(int rhs) { return v > rhs? TRUE: FALSE; }
+
+ @Override
+ public boolean gt_b(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.lt_b(v): super.gt_b(rhs); }
+
+ @Override
+ public boolean gt_b(int rhs) { return v > rhs; }
+
+ @Override
+ public boolean gt_b(double rhs) { return v > rhs; }
+
+ @Override
+ public LuaValue gteq(LuaValue rhs) {
+ return rhs instanceof LuaNumber? rhs.lteq_b(v)? TRUE: FALSE: super.gteq(rhs);
+ }
+
+ @Override
+ public LuaValue gteq(double rhs) { return v >= rhs? TRUE: FALSE; }
+
+ @Override
+ public LuaValue gteq(int rhs) { return v >= rhs? TRUE: FALSE; }
+
+ @Override
+ public boolean gteq_b(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.lteq_b(v): super.gteq_b(rhs); }
+
+ @Override
+ public boolean gteq_b(int rhs) { return v >= rhs; }
+
+ @Override
+ public boolean gteq_b(double rhs) { return v >= rhs; }
+
+ // string comparison
+ @Override
+ public int strcmp(LuaString rhs) { typerror("attempt to compare number with string"); return 0; }
+
+ @Override
+ public int checkint() {
+ return v;
+ }
+
+ @Override
+ public long checklong() {
+ return v;
+ }
+
+ @Override
+ public double checkdouble() {
+ return v;
+ }
+
+ @Override
+ public String checkjstring() {
+ return String.valueOf(v);
+ }
+
+ @Override
+ public LuaString checkstring() {
+ return valueOf(String.valueOf(v));
+ }
+
+}
diff --git a/src/core/org/luaj/vm2/LuaNil.java b/luaj-core/src/main/java/org/luaj/vm2/LuaNil.java
similarity index 53%
rename from src/core/org/luaj/vm2/LuaNil.java
rename to luaj-core/src/main/java/org/luaj/vm2/LuaNil.java
index 1b247cbd..ace94717 100644
--- a/src/core/org/luaj/vm2/LuaNil.java
+++ b/luaj-core/src/main/java/org/luaj/vm2/LuaNil.java
@@ -10,7 +10,7 @@
*
* 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
@@ -22,87 +22,127 @@
package org.luaj.vm2;
/**
- * Class to encapsulate behavior of the singleton instance {@code nil}
+ * Class to encapsulate behavior of the singleton instance {@code nil}
*
- * There will be one instance of this class, {@link LuaValue#NIL},
- * per Java virtual machine.
- * However, the {@link Varargs} instance {@link LuaValue#NONE}
- * which is the empty list,
- * is also considered treated as a nil value by default.
+ * There will be one instance of this class, {@link LuaValue#NIL}, per Java
+ * virtual machine. However, the {@link Varargs} instance {@link LuaValue#NONE}
+ * which is the empty list, is also considered treated as a nil value by
+ * default.
*
- * Although it is possible to test for nil using Java == operator,
- * the recommended approach is to use the method {@link LuaValue#isnil()}
- * instead. By using that any ambiguities between
- * {@link LuaValue#NIL} and {@link LuaValue#NONE} are avoided.
+ * Although it is possible to test for nil using Java == operator, the
+ * recommended approach is to use the method {@link LuaValue#isnil()} instead.
+ * By using that any ambiguities between {@link LuaValue#NIL} and
+ * {@link LuaValue#NONE} are avoided.
+ *
* @see LuaValue
* @see LuaValue#NIL
*/
public class LuaNil extends LuaValue {
-
+
static final LuaNil _NIL = new LuaNil();
-
+
public static LuaValue s_metatable;
-
+
LuaNil() {}
+ @Override
public int type() {
return LuaValue.TNIL;
}
+ @Override
public String toString() {
- return "nil";
+ return "nil";
}
-
+
+ @Override
public String typename() {
return "nil";
}
-
+
+ @Override
public String tojstring() {
return "nil";
}
- public LuaValue not() {
- return LuaValue.TRUE;
+ @Override
+ public LuaValue not() {
+ return LuaValue.TRUE;
}
-
- public boolean toboolean() {
- return false;
+
+ @Override
+ public boolean toboolean() {
+ return false;
}
-
+
+ @Override
public boolean isnil() {
return true;
}
-
- public LuaValue getmetatable() {
- return s_metatable;
+
+ @Override
+ public LuaValue getmetatable() {
+ return s_metatable;
}
-
+
+ @Override
public boolean equals(Object o) {
return o instanceof LuaNil;
}
- public LuaValue checknotnil() {
+ @Override
+ public LuaValue checknotnil() {
return argerror("value");
}
-
+
+ @Override
public boolean isvalidkey() {
return false;
}
// optional argument conversions - nil alwas falls badk to default value
- public boolean optboolean(boolean defval) { return defval; }
- public LuaClosure optclosure(LuaClosure defval) { return defval; }
- public double optdouble(double defval) { return defval; }
- public LuaFunction optfunction(LuaFunction defval) { return defval; }
- public int optint(int defval) { return defval; }
- public LuaInteger optinteger(LuaInteger defval) { return defval; }
- public long optlong(long defval) { return defval; }
- public LuaNumber optnumber(LuaNumber defval) { return defval; }
- public LuaTable opttable(LuaTable defval) { return defval; }
- public LuaThread optthread(LuaThread defval) { return defval; }
- public String optjstring(String defval) { return defval; }
- public LuaString optstring(LuaString defval) { return defval; }
- public Object optuserdata(Object defval) { return defval; }
- public Object optuserdata(Class c, Object defval) { return defval; }
- public LuaValue optvalue(LuaValue defval) { return defval; }
+ @Override
+ public boolean optboolean(boolean defval) { return defval; }
+
+ @Override
+ public LuaClosure optclosure(LuaClosure defval) { return defval; }
+
+ @Override
+ public double optdouble(double defval) { return defval; }
+
+ @Override
+ public LuaFunction optfunction(LuaFunction defval) { return defval; }
+
+ @Override
+ public int optint(int defval) { return defval; }
+
+ @Override
+ public LuaInteger optinteger(LuaInteger defval) { return defval; }
+
+ @Override
+ public long optlong(long defval) { return defval; }
+
+ @Override
+ public LuaNumber optnumber(LuaNumber defval) { return defval; }
+
+ @Override
+ public LuaTable opttable(LuaTable defval) { return defval; }
+
+ @Override
+ public LuaThread optthread(LuaThread defval) { return defval; }
+
+ @Override
+ public String optjstring(String defval) { return defval; }
+
+ @Override
+ public LuaString optstring(LuaString defval) { return defval; }
+
+ @Override
+ public Object optuserdata(Object defval) { return defval; }
+
+ @Override
+ public Object optuserdata(Class c, Object defval) { return defval; }
+
+ @Override
+ public LuaValue optvalue(LuaValue defval) { return defval; }
}
diff --git a/src/core/org/luaj/vm2/LuaNumber.java b/luaj-core/src/main/java/org/luaj/vm2/LuaNumber.java
similarity index 71%
rename from src/core/org/luaj/vm2/LuaNumber.java
rename to luaj-core/src/main/java/org/luaj/vm2/LuaNumber.java
index ef972218..b1dd89f2 100644
--- a/src/core/org/luaj/vm2/LuaNumber.java
+++ b/luaj-core/src/main/java/org/luaj/vm2/LuaNumber.java
@@ -10,7 +10,7 @@
*
* 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
@@ -21,61 +21,77 @@
******************************************************************************/
package org.luaj.vm2;
-/**
- * Base class for representing numbers as lua values directly.
+/**
+ * Base class for representing numbers as lua values directly.
*
- * The main subclasses are {@link LuaInteger} which holds values that fit in a java int,
- * and {@link LuaDouble} which holds all other number values.
+ * The main subclasses are {@link LuaInteger} which holds values that fit in a
+ * java int, and {@link LuaDouble} which holds all other number values.
+ *
* @see LuaInteger
* @see LuaDouble
* @see LuaValue
- *
+ *
*/
-abstract
-public class LuaNumber extends LuaValue {
+abstract public class LuaNumber extends LuaValue {
/** Shared static metatable for all number values represented in lua. */
public static LuaValue s_metatable;
-
+
+ @Override
public int type() {
return TNUMBER;
}
-
+
+ @Override
public String typename() {
return "number";
}
-
+
+ @Override
public LuaNumber checknumber() {
- return this;
+ return this;
}
-
+
+ @Override
public LuaNumber checknumber(String errmsg) {
- return this;
+ return this;
}
-
+
+ @Override
public LuaNumber optnumber(LuaNumber defval) {
- return this;
+ return this;
}
-
+
+ @Override
public LuaValue tonumber() {
return this;
}
-
+
+ @Override
public boolean isnumber() {
return true;
}
-
+
+ @Override
public boolean isstring() {
return true;
}
-
- public LuaValue getmetatable() {
- return s_metatable;
+
+ @Override
+ public LuaValue getmetatable() {
+ return s_metatable;
}
- public LuaValue concat(LuaValue rhs) { return rhs.concatTo(this); }
- public Buffer concat(Buffer rhs) { return rhs.concatTo(this); }
- public LuaValue concatTo(LuaNumber lhs) { return strvalue().concatTo(lhs.strvalue()); }
- public LuaValue concatTo(LuaString lhs) { return strvalue().concatTo(lhs); }
+ @Override
+ public LuaValue concat(LuaValue rhs) { return rhs.concatTo(this); }
+
+ @Override
+ public Buffer concat(Buffer rhs) { return rhs.concatTo(this); }
+
+ @Override
+ public LuaValue concatTo(LuaNumber lhs) { return strvalue().concatTo(lhs.strvalue()); }
+
+ @Override
+ public LuaValue concatTo(LuaString lhs) { return strvalue().concatTo(lhs); }
}
diff --git a/luaj-core/src/main/java/org/luaj/vm2/LuaString.java b/luaj-core/src/main/java/org/luaj/vm2/LuaString.java
new file mode 100644
index 00000000..1746240d
--- /dev/null
+++ b/luaj-core/src/main/java/org/luaj/vm2/LuaString.java
@@ -0,0 +1,1101 @@
+/*******************************************************************************
+* Copyright (c) 2009-2011 Luaj.org. All rights reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+******************************************************************************/
+package org.luaj.vm2;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+
+import org.luaj.vm2.lib.MathLib;
+
+/**
+ * Subclass of {@link LuaValue} for representing lua strings.
+ *
+ * Because lua string values are more nearly sequences of bytes than sequences
+ * of characters or unicode code points, the {@link LuaString} implementation
+ * holds the string value in an internal byte array.
+ *
+ * {@link LuaString} values are not considered mutable once constructed, so
+ * multiple {@link LuaString} values can chare a single byte array.
+ *
+ * Currently {@link LuaString}s are pooled via a centrally managed weak table.
+ * To ensure that as many string values as possible take advantage of this,
+ * Constructors are not exposed directly. As with number, booleans, and nil,
+ * instance construction should be via {@link LuaValue#valueOf(byte[])} or
+ * similar API.
+ *
+ * Because of this pooling, users of LuaString must not directly alter the
+ * bytes in a LuaString, or undefined behavior will result.
+ *
+ * When Java Strings are used to initialize {@link LuaString} data, the UTF8
+ * encoding is assumed. The functions {@link #lengthAsUtf8(char[])},
+ * {@link #encodeToUtf8(char[], int, byte[], int)}, and
+ * {@link #decodeAsUtf8(byte[], int, int)} are used to convert back and forth
+ * between UTF8 byte arrays and character arrays.
+ *
+ * @see LuaValue
+ * @see LuaValue#valueOf(String)
+ * @see LuaValue#valueOf(byte[])
+ */
+public class LuaString extends LuaValue {
+
+ /**
+ * The singleton instance for string metatables that forwards to the string
+ * functions. Typically, this is set to the string metatable as a side
+ * effect of loading the string library, and is read-write to provide
+ * flexible behavior by default. When used in a server environment where
+ * there may be roge scripts, this should be replaced with a read-only table
+ * since it is shared across all lua code in this Java VM.
+ */
+ public static LuaValue s_metatable;
+
+ /**
+ * The bytes for the string. These must not be mutated
+ * directly because the backing may be shared by multiple
+ * LuaStrings, and the hash code is computed only at construction time. It
+ * is exposed only for performance and legacy reasons.
+ */
+ public final byte[] m_bytes;
+
+ /** The offset into the byte array, 0 means start at the first byte */
+ public final int m_offset;
+
+ /** The number of bytes that comprise this string */
+ public final int m_length;
+
+ /** The hashcode for this string. Computed at construct time. */
+ private final int m_hashcode;
+
+ /**
+ * Size of cache of recent short strings. This is the maximum number of
+ * LuaStrings that will be retained in the cache of recent short strings.
+ * Exposed to package for testing.
+ */
+ static final int RECENT_STRINGS_CACHE_SIZE = 128;
+
+ /**
+ * Maximum length of a string to be considered for recent short strings
+ * caching. This effectively limits the total memory that can be spent on
+ * the recent strings cache, because no LuaString whose backing exceeds this
+ * length will be put into the cache. Exposed to package for testing.
+ */
+ static final int RECENT_STRINGS_MAX_LENGTH = 32;
+
+ /**
+ * Simple cache of recently created strings that are short. This is simply a
+ * list of strings, indexed by their hash codes modulo the cache size that
+ * have been recently constructed. If a string is being constructed
+ * frequently from different contexts, it will generally show up as a cache
+ * hit and resolve to the same value.
+ */
+ private static final class RecentShortStrings {
+ private static final LuaString recent_short_strings[] = new LuaString[RECENT_STRINGS_CACHE_SIZE];
+ }
+
+ /**
+ * Get a {@link LuaString} instance whose bytes match the supplied Java
+ * String using the UTF8 encoding.
+ *
+ * @param string Java String containing characters to encode as UTF8
+ * @return {@link LuaString} with UTF8 bytes corresponding to the supplied
+ * String
+ */
+ public static LuaString valueOf(String string) {
+ char[] c = string.toCharArray();
+ byte[] b = new byte[lengthAsUtf8(c)];
+ encodeToUtf8(c, c.length, b, 0);
+ return valueUsing(b, 0, b.length);
+ }
+
+ /**
+ * Construct a {@link LuaString} for a portion of a byte array.
+ *
+ * The array is first be used as the backing for this object, so clients
+ * must not change contents. If the supplied value for 'len' is more than
+ * half the length of the container, the supplied byte array will be used as
+ * the backing, otherwise the bytes will be copied to a new byte array, and
+ * cache lookup may be performed.
+ *
+ *
+ * @param bytes byte buffer
+ * @param off offset into the byte buffer
+ * @param len length of the byte buffer
+ * @return {@link LuaString} wrapping the byte buffer
+ */
+ public static LuaString valueOf(byte[] bytes, int off, int len) {
+ if (len > RECENT_STRINGS_MAX_LENGTH)
+ return valueFromCopy(bytes, off, len);
+ final int hash = hashCode(bytes, off, len);
+ final int bucket = hash & RECENT_STRINGS_CACHE_SIZE-1;
+ final LuaString t = RecentShortStrings.recent_short_strings[bucket];
+ if (t != null && t.m_hashcode == hash && t.byteseq(bytes, off, len))
+ return t;
+ final LuaString s = valueFromCopy(bytes, off, len);
+ RecentShortStrings.recent_short_strings[bucket] = s;
+ return s;
+ }
+
+ /** Construct a new LuaString using a copy of the bytes array supplied */
+ private static LuaString valueFromCopy(byte[] bytes, int off, int len) {
+ final byte[] copy = new byte[len];
+ System.arraycopy(bytes, off, copy, 0, len);
+ return new LuaString(copy, 0, len);
+ }
+
+ /**
+ * Construct a {@link LuaString} around, possibly using the the supplied
+ * byte array as the backing store.
+ *
+ * The caller must ensure that the array is not mutated after the call.
+ * However, if the string is short enough the short-string cache is checked
+ * for a match which may be used instead of the supplied byte array.
+ *
+ *
+ * @param bytes byte buffer
+ * @return {@link LuaString} wrapping the byte buffer, or an equivalent
+ * string.
+ */
+ static public LuaString valueUsing(byte[] bytes, int off, int len) {
+ if (bytes.length > RECENT_STRINGS_MAX_LENGTH)
+ return new LuaString(bytes, off, len);
+ final int hash = hashCode(bytes, off, len);
+ final int bucket = hash & RECENT_STRINGS_CACHE_SIZE-1;
+ final LuaString t = RecentShortStrings.recent_short_strings[bucket];
+ if (t != null && t.m_hashcode == hash && t.byteseq(bytes, off, len))
+ return t;
+ final LuaString s = new LuaString(bytes, off, len);
+ RecentShortStrings.recent_short_strings[bucket] = s;
+ return s;
+ }
+
+ /**
+ * Construct a {@link LuaString} using the supplied characters as byte
+ * values.
+ *
+ * Only the low-order 8-bits of each character are used, the remainder is
+ * ignored.
+ *
+ * This is most useful for constructing byte sequences that do not conform
+ * to UTF8.
+ *
+ * @param bytes array of char, whose values are truncated at 8-bits each and
+ * put into a byte array.
+ * @return {@link LuaString} wrapping a copy of the byte buffer
+ */
+ public static LuaString valueOf(char[] bytes) {
+ return valueOf(bytes, 0, bytes.length);
+ }
+
+ /**
+ * Construct a {@link LuaString} using the supplied characters as byte
+ * values.
+ *
+ * Only the low-order 8-bits of each character are used, the remainder is
+ * ignored.
+ *
+ * This is most useful for constructing byte sequences that do not conform
+ * to UTF8.
+ *
+ * @param bytes array of char, whose values are truncated at 8-bits each and
+ * put into a byte array.
+ * @return {@link LuaString} wrapping a copy of the byte buffer
+ */
+ public static LuaString valueOf(char[] bytes, int off, int len) {
+ byte[] b = new byte[len];
+ for (int i = 0; i < len; i++)
+ b[i] = (byte) bytes[i+off];
+ return valueUsing(b, 0, len);
+ }
+
+ /**
+ * Construct a {@link LuaString} for all the bytes in a byte array.
+ *
+ * The LuaString returned will either be a new LuaString containing a copy
+ * of the bytes array, or be an existing LuaString used already having the
+ * same value.
+ *
+ *
+ * @param bytes byte buffer
+ * @return {@link LuaString} wrapping the byte buffer
+ */
+ public static LuaString valueOf(byte[] bytes) {
+ return valueOf(bytes, 0, bytes.length);
+ }
+
+ /**
+ * Construct a {@link LuaString} for all the bytes in a byte array, possibly
+ * using the supplied array as the backing store.
+ *
+ * The LuaString returned will either be a new LuaString containing the byte
+ * array, or be an existing LuaString used already having the same value.
+ *
+ * The caller must not mutate the contents of the byte array after this
+ * call, as it may be used elsewhere due to recent short string caching.
+ *
+ * @param bytes byte buffer
+ * @return {@link LuaString} wrapping the byte buffer
+ */
+ public static LuaString valueUsing(byte[] bytes) {
+ return valueUsing(bytes, 0, bytes.length);
+ }
+
+ /**
+ * Construct a {@link LuaString} around a byte array without copying the
+ * contents.
+ *
+ * The array is used directly after this is called, so clients must not
+ * change contents.
+ *
+ *
+ * @param bytes byte buffer
+ * @param offset offset into the byte buffer
+ * @param length length of the byte buffer
+ * @return {@link LuaString} wrapping the byte buffer
+ */
+ private LuaString(byte[] bytes, int offset, int length) {
+ this.m_bytes = bytes;
+ this.m_offset = offset;
+ this.m_length = length;
+ this.m_hashcode = hashCode(bytes, offset, length);
+ }
+
+ @Override
+ public boolean isstring() {
+ return true;
+ }
+
+ @Override
+ public LuaValue getmetatable() {
+ return s_metatable;
+ }
+
+ @Override
+ public int type() {
+ return LuaValue.TSTRING;
+ }
+
+ @Override
+ public String typename() {
+ return "string";
+ }
+
+ @Override
+ public String tojstring() {
+ return decodeAsUtf8(m_bytes, m_offset, m_length);
+ }
+
+ // unary operators
+ @Override
+ public LuaValue neg() { double d = scannumber(); return Double.isNaN(d)? super.neg(): valueOf(-d); }
+
+ // basic binary arithmetic
+ @Override
+ public LuaValue add(LuaValue rhs) {
+ double d = scannumber();
+ return Double.isNaN(d)? arithmt(ADD, rhs): rhs.add(d);
+ }
+
+ @Override
+ public LuaValue add(double rhs) { return valueOf(checkarith()+rhs); }
+
+ @Override
+ public LuaValue add(int rhs) { return valueOf(checkarith()+rhs); }
+
+ @Override
+ public LuaValue sub(LuaValue rhs) {
+ double d = scannumber();
+ return Double.isNaN(d)? arithmt(SUB, rhs): rhs.subFrom(d);
+ }
+
+ @Override
+ public LuaValue sub(double rhs) { return valueOf(checkarith()-rhs); }
+
+ @Override
+ public LuaValue sub(int rhs) { return valueOf(checkarith()-rhs); }
+
+ @Override
+ public LuaValue subFrom(double lhs) { return valueOf(lhs-checkarith()); }
+
+ @Override
+ public LuaValue mul(LuaValue rhs) {
+ double d = scannumber();
+ return Double.isNaN(d)? arithmt(MUL, rhs): rhs.mul(d);
+ }
+
+ @Override
+ public LuaValue mul(double rhs) { return valueOf(checkarith()*rhs); }
+
+ @Override
+ public LuaValue mul(int rhs) { return valueOf(checkarith()*rhs); }
+
+ @Override
+ public LuaValue pow(LuaValue rhs) {
+ double d = scannumber();
+ return Double.isNaN(d)? arithmt(POW, rhs): rhs.powWith(d);
+ }
+
+ @Override
+ public LuaValue pow(double rhs) { return MathLib.dpow(checkarith(), rhs); }
+
+ @Override
+ public LuaValue pow(int rhs) { return MathLib.dpow(checkarith(), rhs); }
+
+ @Override
+ public LuaValue powWith(double lhs) { return MathLib.dpow(lhs, checkarith()); }
+
+ @Override
+ public LuaValue powWith(int lhs) { return MathLib.dpow(lhs, checkarith()); }
+
+ @Override
+ public LuaValue div(LuaValue rhs) {
+ double d = scannumber();
+ return Double.isNaN(d)? arithmt(DIV, rhs): rhs.divInto(d);
+ }
+
+ @Override
+ public LuaValue div(double rhs) { return LuaDouble.ddiv(checkarith(), rhs); }
+
+ @Override
+ public LuaValue div(int rhs) { return LuaDouble.ddiv(checkarith(), rhs); }
+
+ @Override
+ public LuaValue divInto(double lhs) { return LuaDouble.ddiv(lhs, checkarith()); }
+
+ @Override
+ public LuaValue mod(LuaValue rhs) {
+ double d = scannumber();
+ return Double.isNaN(d)? arithmt(MOD, rhs): rhs.modFrom(d);
+ }
+
+ @Override
+ public LuaValue mod(double rhs) { return LuaDouble.dmod(checkarith(), rhs); }
+
+ @Override
+ public LuaValue mod(int rhs) { return LuaDouble.dmod(checkarith(), rhs); }
+
+ @Override
+ public LuaValue modFrom(double lhs) { return LuaDouble.dmod(lhs, checkarith()); }
+
+ // relational operators, these only work with other strings
+ @Override
+ public LuaValue lt(LuaValue rhs) {
+ return rhs.isstring()? rhs.strcmp(this) > 0? LuaValue.TRUE: FALSE: super.lt(rhs);
+ }
+
+ @Override
+ public boolean lt_b(LuaValue rhs) { return rhs.isstring()? rhs.strcmp(this) > 0: super.lt_b(rhs); }
+
+ @Override
+ public boolean lt_b(int rhs) { typerror("attempt to compare string with number"); return false; }
+
+ @Override
+ public boolean lt_b(double rhs) { typerror("attempt to compare string with number"); return false; }
+
+ @Override
+ public LuaValue lteq(LuaValue rhs) {
+ return rhs.isstring()? rhs.strcmp(this) >= 0? LuaValue.TRUE: FALSE: super.lteq(rhs);
+ }
+
+ @Override
+ public boolean lteq_b(LuaValue rhs) { return rhs.isstring()? rhs.strcmp(this) >= 0: super.lteq_b(rhs); }
+
+ @Override
+ public boolean lteq_b(int rhs) { typerror("attempt to compare string with number"); return false; }
+
+ @Override
+ public boolean lteq_b(double rhs) { typerror("attempt to compare string with number"); return false; }
+
+ @Override
+ public LuaValue gt(LuaValue rhs) {
+ return rhs.isstring()? rhs.strcmp(this) < 0? LuaValue.TRUE: FALSE: super.gt(rhs);
+ }
+
+ @Override
+ public boolean gt_b(LuaValue rhs) { return rhs.isstring()? rhs.strcmp(this) < 0: super.gt_b(rhs); }
+
+ @Override
+ public boolean gt_b(int rhs) { typerror("attempt to compare string with number"); return false; }
+
+ @Override
+ public boolean gt_b(double rhs) { typerror("attempt to compare string with number"); return false; }
+
+ @Override
+ public LuaValue gteq(LuaValue rhs) {
+ return rhs.isstring()? rhs.strcmp(this) <= 0? LuaValue.TRUE: FALSE: super.gteq(rhs);
+ }
+
+ @Override
+ public boolean gteq_b(LuaValue rhs) { return rhs.isstring()? rhs.strcmp(this) <= 0: super.gteq_b(rhs); }
+
+ @Override
+ public boolean gteq_b(int rhs) { typerror("attempt to compare string with number"); return false; }
+
+ @Override
+ public boolean gteq_b(double rhs) { typerror("attempt to compare string with number"); return false; }
+
+ // concatenation
+ @Override
+ public LuaValue concat(LuaValue rhs) { return rhs.concatTo(this); }
+
+ @Override
+ public Buffer concat(Buffer rhs) { return rhs.concatTo(this); }
+
+ @Override
+ public LuaValue concatTo(LuaNumber lhs) { return concatTo(lhs.strvalue()); }
+
+ @Override
+ public LuaValue concatTo(LuaString lhs) {
+ byte[] b = new byte[lhs.m_length+this.m_length];
+ System.arraycopy(lhs.m_bytes, lhs.m_offset, b, 0, lhs.m_length);
+ System.arraycopy(this.m_bytes, this.m_offset, b, lhs.m_length, this.m_length);
+ return valueUsing(b, 0, b.length);
+ }
+
+ // string comparison
+ @Override
+ public int strcmp(LuaValue lhs) { return -lhs.strcmp(this); }
+
+ @Override
+ public int strcmp(LuaString rhs) {
+ for (int i = 0, j = 0; i < m_length && j < rhs.m_length; ++i, ++j) {
+ if (m_bytes[m_offset+i] != rhs.m_bytes[rhs.m_offset+j]) {
+ return m_bytes[m_offset+i]-rhs.m_bytes[rhs.m_offset+j];
+ }
+ }
+ return m_length-rhs.m_length;
+ }
+
+ /** Check for number in arithmetic, or throw aritherror */
+ private double checkarith() {
+ double d = scannumber();
+ if (Double.isNaN(d))
+ aritherror();
+ return d;
+ }
+
+ @Override
+ public int checkint() {
+ return (int) (long) checkdouble();
+ }
+
+ @Override
+ public LuaInteger checkinteger() {
+ return valueOf(checkint());
+ }
+
+ @Override
+ public long checklong() {
+ return (long) checkdouble();
+ }
+
+ @Override
+ public double checkdouble() {
+ double d = scannumber();
+ if (Double.isNaN(d))
+ argerror("number");
+ return d;
+ }
+
+ @Override
+ public LuaNumber checknumber() {
+ return valueOf(checkdouble());
+ }
+
+ @Override
+ public LuaNumber checknumber(String msg) {
+ double d = scannumber();
+ if (Double.isNaN(d))
+ error(msg);
+ return valueOf(d);
+ }
+
+ @Override
+ public boolean isnumber() {
+ double d = scannumber();
+ return !Double.isNaN(d);
+ }
+
+ @Override
+ public boolean isint() {
+ double d = scannumber();
+ if (Double.isNaN(d))
+ return false;
+ int i = (int) d;
+ return i == d;
+ }
+
+ @Override
+ public boolean islong() {
+ double d = scannumber();
+ if (Double.isNaN(d))
+ return false;
+ long l = (long) d;
+ return l == d;
+ }
+
+ @Override
+ public byte tobyte() { return (byte) toint(); }
+
+ @Override
+ public char tochar() { return (char) toint(); }
+
+ @Override
+ public double todouble() { double d = scannumber(); return Double.isNaN(d)? 0: d; }
+
+ @Override
+ public float tofloat() { return (float) todouble(); }
+
+ @Override
+ public int toint() { return (int) tolong(); }
+
+ @Override
+ public long tolong() { return (long) todouble(); }
+
+ @Override
+ public short toshort() { return (short) toint(); }
+
+ @Override
+ public double optdouble(double defval) {
+ return checkdouble();
+ }
+
+ @Override
+ public int optint(int defval) {
+ return checkint();
+ }
+
+ @Override
+ public LuaInteger optinteger(LuaInteger defval) {
+ return checkinteger();
+ }
+
+ @Override
+ public long optlong(long defval) {
+ return checklong();
+ }
+
+ @Override
+ public LuaNumber optnumber(LuaNumber defval) {
+ return checknumber();
+ }
+
+ @Override
+ public LuaString optstring(LuaString defval) {
+ return this;
+ }
+
+ @Override
+ public LuaValue tostring() {
+ return this;
+ }
+
+ @Override
+ public String optjstring(String defval) {
+ return tojstring();
+ }
+
+ @Override
+ public LuaString strvalue() {
+ return this;
+ }
+
+ /**
+ * Take a substring using Java zero-based indexes for begin and end or
+ * range.
+ *
+ * @param beginIndex The zero-based index of the first character to include.
+ * @param endIndex The zero-based index of position after the last
+ * character.
+ * @return LuaString which is a substring whose first character is at offset
+ * beginIndex and extending for (endIndex - beginIndex ) characters.
+ */
+ public LuaString substring(int beginIndex, int endIndex) {
+ final int off = m_offset+beginIndex;
+ final int len = endIndex-beginIndex;
+ return len >= m_length/2? valueUsing(m_bytes, off, len): valueOf(m_bytes, off, len);
+ }
+
+ @Override
+ public int hashCode() {
+ return m_hashcode;
+ }
+
+ /**
+ * Compute the hash code of a sequence of bytes within a byte array using
+ * lua's rules for string hashes. For long strings, not all bytes are
+ * hashed.
+ *
+ * @param bytes byte array containing the bytes.
+ * @param offset offset into the hash for the first byte.
+ * @param length number of bytes starting with offset that are part of the
+ * string.
+ * @return hash for the string defined by bytes, offset, and length.
+ */
+ public static int hashCode(byte[] bytes, int offset, int length) {
+ int h = length; /* seed */
+ int step = (length>>5)+1; /* if string is too long, don't hash all its chars */
+ for (int l1 = length; l1 >= step; l1 -= step) /* compute hash */
+ h = h ^ (h<<5)+(h>>2)+(bytes[offset+l1-1] & 0x0FF);
+ return h;
+ }
+
+ // object comparison, used in key comparison
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof LuaString) {
+ return raweq((LuaString) o);
+ }
+ return false;
+ }
+
+ // equality w/ metatable processing
+ @Override
+ public LuaValue eq(LuaValue val) { return val.raweq(this)? TRUE: FALSE; }
+
+ @Override
+ public boolean eq_b(LuaValue val) { return val.raweq(this); }
+
+ // equality w/o metatable processing
+ @Override
+ public boolean raweq(LuaValue val) {
+ return val.raweq(this);
+ }
+
+ @Override
+ public boolean raweq(LuaString s) {
+ if (this == s)
+ return true;
+ if (s.m_length != m_length)
+ return false;
+ if (s.m_bytes == m_bytes && s.m_offset == m_offset)
+ return true;
+ if (s.hashCode() != hashCode())
+ return false;
+ for (int i = 0; i < m_length; i++)
+ if (s.m_bytes[s.m_offset+i] != m_bytes[m_offset+i])
+ return false;
+ return true;
+ }
+
+ public static boolean equals(LuaString a, int i, LuaString b, int j, int n) {
+ return equals(a.m_bytes, a.m_offset+i, b.m_bytes, b.m_offset+j, n);
+ }
+
+ /**
+ * Return true if the bytes in the supplied range match this LuaStrings
+ * bytes.
+ */
+ private boolean byteseq(byte[] bytes, int off, int len) {
+ return m_length == len && equals(m_bytes, m_offset, bytes, off, len);
+ }
+
+ public static boolean equals(byte[] a, int i, byte[] b, int j, int n) {
+ if (a.length < i+n || b.length < j+n)
+ return false;
+ while ( --n >= 0 )
+ if (a[i++] != b[j++])
+ return false;
+ return true;
+ }
+
+ public void write(DataOutputStream writer, int i, int len) throws IOException {
+ writer.write(m_bytes, m_offset+i, len);
+ }
+
+ @Override
+ public LuaValue len() {
+ return LuaInteger.valueOf(m_length);
+ }
+
+ @Override
+ public int length() {
+ return m_length;
+ }
+
+ @Override
+ public int rawlen() {
+ return m_length;
+ }
+
+ public int luaByte(int index) {
+ return m_bytes[m_offset+index] & 0x0FF;
+ }
+
+ public int charAt(int index) {
+ if (index < 0 || index >= m_length)
+ throw new IndexOutOfBoundsException();
+ return luaByte(index);
+ }
+
+ @Override
+ public String checkjstring() {
+ return tojstring();
+ }
+
+ @Override
+ public LuaString checkstring() {
+ return this;
+ }
+
+ /**
+ * Convert value to an input stream.
+ *
+ * @return {@link InputStream} whose data matches the bytes in this
+ * {@link LuaString}
+ */
+ public InputStream toInputStream() {
+ return new ByteArrayInputStream(m_bytes, m_offset, m_length);
+ }
+
+ /**
+ * Copy the bytes of the string into the given byte array.
+ *
+ * @param strOffset offset from which to copy
+ * @param bytes destination byte array
+ * @param arrayOffset offset in destination
+ * @param len number of bytes to copy
+ */
+ public void copyInto(int strOffset, byte[] bytes, int arrayOffset, int len) {
+ System.arraycopy(m_bytes, m_offset+strOffset, bytes, arrayOffset, len);
+ }
+
+ /**
+ * Java version of strpbrk - find index of any byte that in an accept
+ * string.
+ *
+ * @param accept {@link LuaString} containing characters to look for.
+ * @return index of first match in the {@code accept} string, or -1 if not
+ * found.
+ */
+ public int indexOfAny(LuaString accept) {
+ final int ilimit = m_offset+m_length;
+ final int jlimit = accept.m_offset+accept.m_length;
+ for (int i = m_offset; i < ilimit; ++i) {
+ for (int j = accept.m_offset; j < jlimit; ++j) {
+ if (m_bytes[i] == accept.m_bytes[j]) {
+ return i-m_offset;
+ }
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Find the index of a byte starting at a point in this string
+ *
+ * @param b the byte to look for
+ * @param start the first index in the string
+ * @return index of first match found, or -1 if not found.
+ */
+ public int indexOf(byte b, int start) {
+ for (int i = start; i < m_length; ++i) {
+ if (m_bytes[m_offset+i] == b)
+ return i;
+ }
+ return -1;
+ }
+
+ /**
+ * Find the index of a string starting at a point in this string
+ *
+ * @param s the string to search for
+ * @param start the first index in the string
+ * @return index of first match found, or -1 if not found.
+ */
+ public int indexOf(LuaString s, int start) {
+ final int slen = s.length();
+ final int limit = m_length-slen;
+ for (int i = start; i <= limit; ++i) {
+ if (equals(m_bytes, m_offset+i, s.m_bytes, s.m_offset, slen))
+ return i;
+ }
+ return -1;
+ }
+
+ /**
+ * Find the last index of a string in this string
+ *
+ * @param s the string to search for
+ * @return index of last match found, or -1 if not found.
+ */
+ public int lastIndexOf(LuaString s) {
+ final int slen = s.length();
+ final int limit = m_length-slen;
+ for (int i = limit; i >= 0; --i) {
+ if (equals(m_bytes, m_offset+i, s.m_bytes, s.m_offset, slen))
+ return i;
+ }
+ return -1;
+ }
+
+ /**
+ * Convert to Java String interpreting as utf8 characters.
+ *
+ * @param bytes byte array in UTF8 encoding to convert
+ * @param offset starting index in byte array
+ * @param length number of bytes to convert
+ * @return Java String corresponding to the value of bytes interpreted using
+ * UTF8
+ * @see #lengthAsUtf8(char[])
+ * @see #encodeToUtf8(char[], int, byte[], int)
+ * @see #isValidUtf8()
+ */
+ public static String decodeAsUtf8(byte[] bytes, int offset, int length) {
+ int i, j, n, b;
+ for (i = offset, j = offset+length, n = 0; i < j; ++n) {
+ switch (0xE0 & bytes[i++]) {
+ case 0xE0:
+ ++i;
+ case 0xC0:
+ ++i;
+ }
+ }
+ char[] chars = new char[n];
+ for (i = offset, j = offset+length, n = 0; i < j;) {
+ chars[n++] = (char) ((b = bytes[i++]) >= 0 || i >= j? b
+ : b < -32 || i+1 >= j? (b & 0x3f)<<6 | bytes[i++] & 0x3f
+ : (b & 0xf)<<12 | (bytes[i++] & 0x3f)<<6 | bytes[i++] & 0x3f);
+ }
+ return new String(chars);
+ }
+
+ /**
+ * Count the number of bytes required to encode the string as UTF-8.
+ *
+ * @param chars Array of unicode characters to be encoded as UTF-8
+ * @return count of bytes needed to encode using UTF-8
+ * @see #encodeToUtf8(char[], int, byte[], int)
+ * @see #decodeAsUtf8(byte[], int, int)
+ * @see #isValidUtf8()
+ */
+ public static int lengthAsUtf8(char[] chars) {
+ int i, b;
+ char c;
+ for (i = b = chars.length; --i >= 0;)
+ if ((c = chars[i]) >= 0x80)
+ b += c >= 0x800? 2: 1;
+ return b;
+ }
+
+ /**
+ * Encode the given Java string as UTF-8 bytes, writing the result to bytes
+ * starting at offset.
+ *
+ * The string should be measured first with lengthAsUtf8 to make sure the
+ * given byte array is large enough.
+ *
+ * @param chars Array of unicode characters to be encoded as UTF-8
+ * @param nchars Number of characters in the array to convert.
+ * @param bytes byte array to hold the result
+ * @param off offset into the byte array to start writing
+ * @return number of bytes converted.
+ * @see #lengthAsUtf8(char[])
+ * @see #decodeAsUtf8(byte[], int, int)
+ * @see #isValidUtf8()
+ */
+ public static int encodeToUtf8(char[] chars, int nchars, byte[] bytes, int off) {
+ char c;
+ int j = off;
+ for (int i = 0; i < nchars; i++) {
+ if ((c = chars[i]) < 0x80) {
+ bytes[j++] = (byte) c;
+ } else if (c < 0x800) {
+ bytes[j++] = (byte) (0xC0 | c>>6 & 0x1f);
+ bytes[j++] = (byte) (0x80 | c & 0x3f);
+ } else {
+ bytes[j++] = (byte) (0xE0 | c>>12 & 0x0f);
+ bytes[j++] = (byte) (0x80 | c>>6 & 0x3f);
+ bytes[j++] = (byte) (0x80 | c & 0x3f);
+ }
+ }
+ return j-off;
+ }
+
+ /**
+ * Check that a byte sequence is valid UTF-8
+ *
+ * @return true if it is valid UTF-8, otherwise false
+ * @see #lengthAsUtf8(char[])
+ * @see #encodeToUtf8(char[], int, byte[], int)
+ * @see #decodeAsUtf8(byte[], int, int)
+ */
+ public boolean isValidUtf8() {
+ for (int i = m_offset, j = m_offset+m_length; i < j;) {
+ int c = m_bytes[i++];
+ if (c >= 0 || (c & 0xE0) == 0xC0 && i < j && (m_bytes[i++] & 0xC0) == 0x80)
+ continue;
+ if ((c & 0xF0) == 0xE0 && i+1 < j && (m_bytes[i++] & 0xC0) == 0x80 && (m_bytes[i++] & 0xC0) == 0x80)
+ continue;
+ return false;
+ }
+ return true;
+ }
+
+ // --------------------- number conversion -----------------------
+
+ /**
+ * convert to a number using baee 10 or base 16 if it starts with '0x', or
+ * NIL if it can't be converted
+ *
+ * @return IntValue, DoubleValue, or NIL depending on the content of the
+ * string.
+ * @see LuaValue#tonumber()
+ */
+ @Override
+ public LuaValue tonumber() {
+ double d = scannumber();
+ return Double.isNaN(d)? NIL: valueOf(d);
+ }
+
+ /**
+ * convert to a number using a supplied base, or NIL if it can't be
+ * converted
+ *
+ * @param base the base to use, such as 10
+ * @return IntValue, DoubleValue, or NIL depending on the content of the
+ * string.
+ * @see LuaValue#tonumber()
+ */
+ public LuaValue tonumber(int base) {
+ double d = scannumber(base);
+ return Double.isNaN(d)? NIL: valueOf(d);
+ }
+
+ /**
+ * Convert to a number in base 10, or base 16 if the string starts with
+ * '0x', or return Double.NaN if it cannot be converted to a number.
+ *
+ * @return double value if conversion is valid, or Double.NaN if not
+ */
+ public double scannumber() {
+ int i = m_offset, j = m_offset+m_length;
+ while ( i < j && m_bytes[i] == ' ' )
+ ++i;
+ while ( i < j && m_bytes[j-1] == ' ' )
+ --j;
+ if (i >= j)
+ return Double.NaN;
+ if (m_bytes[i] == '0' && i+1 < j && (m_bytes[i+1] == 'x' || m_bytes[i+1] == 'X'))
+ return scanlong(16, i+2, j);
+ double l = scanlong(10, i, j);
+ return Double.isNaN(l)? scandouble(i, j): l;
+ }
+
+ /**
+ * Convert to a number in a base, or return Double.NaN if not a number.
+ *
+ * @param base the base to use between 2 and 36
+ * @return double value if conversion is valid, or Double.NaN if not
+ */
+ public double scannumber(int base) {
+ if (base < 2 || base > 36)
+ return Double.NaN;
+ int i = m_offset, j = m_offset+m_length;
+ while ( i < j && m_bytes[i] == ' ' )
+ ++i;
+ while ( i < j && m_bytes[j-1] == ' ' )
+ --j;
+ if (i >= j)
+ return Double.NaN;
+ return scanlong(base, i, j);
+ }
+
+ /**
+ * Scan and convert a long value, or return Double.NaN if not found.
+ *
+ * @param base the base to use, such as 10
+ * @param start the index to start searching from
+ * @param end the first index beyond the search range
+ * @return double value if conversion is valid, or Double.NaN if not
+ */
+ private double scanlong(int base, int start, int end) {
+ long x = 0;
+ boolean neg = m_bytes[start] == '-';
+ for (int i = neg? start+1: start; i < end; i++) {
+ int digit = m_bytes[i]-(base <= 10 || m_bytes[i] >= '0' && m_bytes[i] <= '9'? '0'
+ : m_bytes[i] >= 'A' && m_bytes[i] <= 'Z'? 'A'-10: 'a'-10);
+ if (digit < 0 || digit >= base)
+ return Double.NaN;
+ x = x*base+digit;
+ if (x < 0)
+ return Double.NaN; // overflow
+ }
+ return neg? -x: x;
+ }
+
+ /**
+ * Scan and convert a double value, or return Double.NaN if not a double.
+ *
+ * @param start the index to start searching from
+ * @param end the first index beyond the search range
+ * @return double value if conversion is valid, or Double.NaN if not
+ */
+ private double scandouble(int start, int end) {
+ if (end > start+64)
+ end = start+64;
+ for (int i = start; i < end; i++) {
+ switch (m_bytes[i]) {
+ case '-':
+ case '+':
+ case '.':
+ case 'e':
+ case 'E':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ break;
+ default:
+ return Double.NaN;
+ }
+ }
+ char[] c = new char[end-start];
+ for (int i = start; i < end; i++)
+ c[i-start] = (char) m_bytes[i];
+ try {
+ return Double.parseDouble(new String(c));
+ } catch (Exception e) {
+ return Double.NaN;
+ }
+ }
+
+ /**
+ * Print the bytes of the LuaString to a PrintStream as if it were an ASCII
+ * string, quoting and escaping control characters.
+ *
+ * @param ps PrintStream to print to.
+ */
+ public void printToStream(PrintStream ps) {
+ for (int i = 0, n = m_length; i < n; i++) {
+ int c = m_bytes[m_offset+i];
+ ps.print((char) c);
+ }
+ }
+}
diff --git a/src/core/org/luaj/vm2/LuaTable.java b/luaj-core/src/main/java/org/luaj/vm2/LuaTable.java
similarity index 58%
rename from src/core/org/luaj/vm2/LuaTable.java
rename to luaj-core/src/main/java/org/luaj/vm2/LuaTable.java
index a35dcc3f..6f689024 100644
--- a/src/core/org/luaj/vm2/LuaTable.java
+++ b/luaj-core/src/main/java/org/luaj/vm2/LuaTable.java
@@ -10,7 +10,7 @@
*
* 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
@@ -27,25 +27,27 @@ import java.util.Vector;
/**
* Subclass of {@link LuaValue} for representing lua tables.
*
- * Almost all API's implemented in {@link LuaTable} are defined and documented in {@link LuaValue}.
+ * Almost all API's implemented in {@link LuaTable} are defined and documented
+ * in {@link LuaValue}.
*
- * If a table is needed, the one of the type-checking functions can be used such as
- * {@link #istable()},
- * {@link #checktable()}, or
- * {@link #opttable(LuaTable)}
+ * If a table is needed, the one of the type-checking functions can be used such
+ * as {@link #istable()}, {@link #checktable()}, or {@link #opttable(LuaTable)}
*
- * The main table operations are defined on {@link LuaValue}
- * for getting and setting values with and without metatag processing:
+ * The main table operations are defined on {@link LuaValue} for getting and
+ * setting values with and without metatag processing:
*
* To iterate over key-value pairs from Java, use
- *
- * As with other types, {@link LuaTable} instances should be constructed via one of the table constructor
- * methods on {@link LuaValue}:
+ * As with other types, {@link LuaTable} instances should be constructed via one
+ * of the table constructor methods on {@link LuaValue}:
*
* If the key may be an integer, the {@link #arraykey(int)} method must be
* overridden to handle that case.
*/
static abstract class Entry extends Varargs implements StrongSlot {
+ @Override
public abstract LuaValue key();
- public abstract LuaValue value();
- abstract Entry set(LuaValue value);
- public abstract boolean keyeq( LuaValue key );
- public abstract int keyindex( int hashMask );
- public int arraykey( int max ) {
+ @Override
+ public abstract LuaValue value();
+
+ abstract Entry set(LuaValue value);
+
+ @Override
+ public abstract boolean keyeq(LuaValue key);
+
+ @Override
+ public abstract int keyindex(int hashMask);
+
+ @Override
+ public int arraykey(int max) {
return 0;
}
+ @Override
public LuaValue arg(int i) {
switch (i) {
- case 1: return key();
- case 2: return value();
+ case 1:
+ return key();
+ case 2:
+ return value();
}
return NIL;
}
+ @Override
public int narg() {
return 2;
}
@@ -1100,81 +1211,99 @@ public class LuaTable extends LuaValue implements Metatable {
/**
* Subclasses should redefine as "return this;" whenever possible.
*/
+ @Override
public Varargs toVarargs() {
return varargsOf(key(), value());
}
+ @Override
public LuaValue arg1() {
return key();
}
+ @Override
public Varargs subargs(int start) {
switch (start) {
- case 1: return this;
- case 2: return value();
+ case 1:
+ return this;
+ case 2:
+ return value();
}
return NONE;
}
+ @Override
public StrongSlot first() {
return this;
}
+ @Override
public Slot rest() {
return null;
}
+ @Override
public StrongSlot find(LuaValue key) {
- return keyeq(key) ? this : null;
+ return keyeq(key)? this: null;
}
+ @Override
public Slot set(StrongSlot target, LuaValue value) {
- return set( value );
+ return set(value);
}
- public Slot add( Slot entry ) {
- return new LinkSlot( this, entry );
+ @Override
+ public Slot add(Slot entry) {
+ return new LinkSlot(this, entry);
}
+ @Override
public Slot remove(StrongSlot target) {
- return new DeadSlot( key(), null );
+ return new DeadSlot(key(), null);
}
- public Slot relink( Slot rest ) {
- return ( rest != null ) ? new LinkSlot( this, rest ) : (Slot)this;
+ @Override
+ public Slot relink(Slot rest) {
+ return rest != null? new LinkSlot(this, rest): (Slot) this;
}
}
static class NormalEntry extends Entry {
private final LuaValue key;
- private LuaValue value;
+ private LuaValue value;
- NormalEntry( LuaValue key, LuaValue value ) {
+ NormalEntry(LuaValue key, LuaValue value) {
this.key = key;
this.value = value;
}
+ @Override
public LuaValue key() {
return key;
}
+ @Override
public LuaValue value() {
return value;
}
+ @Override
public Entry set(LuaValue value) {
this.value = value;
return this;
}
+ @Override
public Varargs toVarargs() {
return this;
}
- public int keyindex( int hashMask ) {
- return hashSlot( key, hashMask );
+ @Override
+ public int keyindex(int hashMask) {
+ return hashSlot(key, hashMask);
}
+ @Override
public boolean keyeq(LuaValue key) {
return key.raweq(this.key);
}
@@ -1182,44 +1311,51 @@ public class LuaTable extends LuaValue implements Metatable {
private static class IntKeyEntry extends Entry {
private final int key;
- private LuaValue value;
+ private LuaValue value;
IntKeyEntry(int key, LuaValue value) {
this.key = key;
this.value = value;
}
+ @Override
public LuaValue key() {
- return valueOf( key );
+ return valueOf(key);
}
+ @Override
public int arraykey(int max) {
- return ( key >= 1 && key <= max ) ? key : 0;
+ return key >= 1 && key <= max? key: 0;
}
+ @Override
public LuaValue value() {
return value;
}
+ @Override
public Entry set(LuaValue value) {
this.value = value;
return this;
}
- public int keyindex( int mask ) {
- return hashmod( LuaInteger.hashCode( key ), mask );
+ @Override
+ public int keyindex(int mask) {
+ return hashmod(LuaInteger.hashCode(key), mask);
}
+ @Override
public boolean keyeq(LuaValue key) {
- return key.raweq( this.key );
+ return key.raweq(this.key);
}
}
/**
- * Entry class used with numeric values, but only when the key is not an integer.
+ * Entry class used with numeric values, but only when the key is not an
+ * integer.
*/
private static class NumberValueEntry extends Entry {
- private double value;
+ private double value;
private final LuaValue key;
NumberValueEntry(LuaValue key, double value) {
@@ -1227,14 +1363,17 @@ public class LuaTable extends LuaValue implements Metatable {
this.value = value;
}
+ @Override
public LuaValue key() {
return key;
}
+ @Override
public LuaValue value() {
return valueOf(value);
}
+ @Override
public Entry set(LuaValue value) {
if (value.type() == TNUMBER) {
LuaValue n = value.tonumber();
@@ -1243,65 +1382,74 @@ public class LuaTable extends LuaValue implements Metatable {
return this;
}
}
- return new NormalEntry( this.key, value );
+ return new NormalEntry(this.key, value);
}
- public int keyindex( int mask ) {
- return hashSlot( key, mask );
+ @Override
+ public int keyindex(int mask) {
+ return hashSlot(key, mask);
}
+ @Override
public boolean keyeq(LuaValue key) {
return key.raweq(this.key);
}
}
/**
- * A Slot whose value has been set to nil. The key is kept in a weak reference so that
- * it can be found by next().
+ * A Slot whose value has been set to nil. The key is kept in a weak
+ * reference so that it can be found by next().
*/
private static class DeadSlot implements Slot {
private final Object key;
- private Slot next;
+ private Slot next;
- private DeadSlot( LuaValue key, Slot next ) {
- this.key = isLargeKey(key) ? new WeakReference( key ) : (Object)key;
+ private DeadSlot(LuaValue key, Slot next) {
+ this.key = isLargeKey(key)? new WeakReference(key): (Object) key;
this.next = next;
}
private LuaValue key() {
- return (LuaValue) (key instanceof WeakReference ? ((WeakReference) key).get() : key);
+ return (LuaValue) (key instanceof WeakReference? ((WeakReference) key).get(): key);
}
+ @Override
public int keyindex(int hashMask) {
// Not needed: this entry will be dropped during rehash.
return 0;
}
+ @Override
public StrongSlot first() {
return null;
}
+ @Override
public StrongSlot find(LuaValue key) {
return null;
}
+ @Override
public boolean keyeq(LuaValue key) {
LuaValue k = key();
return k != null && key.raweq(k);
}
+ @Override
public Slot rest() {
return next;
}
+ @Override
public int arraykey(int max) {
return -1;
}
+ @Override
public Slot set(StrongSlot target, LuaValue value) {
- Slot next = ( this.next != null ) ? this.next.set( target, value ) : null;
- if ( key() != null ) {
+ Slot next = this.next != null? this.next.set(target, value): null;
+ if (key() != null) {
// if key hasn't been garbage collected, it is still potentially a valid argument
// to next(), so we can't drop this entry yet.
this.next = next;
@@ -1311,12 +1459,14 @@ public class LuaTable extends LuaValue implements Metatable {
}
}
+ @Override
public Slot add(Slot newEntry) {
- return ( next != null ) ? next.add(newEntry) : newEntry;
+ return next != null? next.add(newEntry): newEntry;
}
+ @Override
public Slot remove(StrongSlot target) {
- if ( key() != null ) {
+ if (key() != null) {
next = next.remove(target);
return this;
} else {
@@ -1324,10 +1474,12 @@ public class LuaTable extends LuaValue implements Metatable {
}
}
+ @Override
public Slot relink(Slot rest) {
return rest;
}
+ @Override
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("
- * The threads must be initialized with the globals, so that
- * the global environment may be passed along according to rules of lua.
- * This is done via the constructor arguments {@link #LuaThread(Globals)} or
+ * The threads must be initialized with the globals, so that the global
+ * environment may be passed along according to rules of lua. This is done via
+ * the constructor arguments {@link #LuaThread(Globals)} or
* {@link #LuaThread(Globals, LuaValue)}.
- *
- * The utility classes {@link org.luaj.vm2.lib.jse.JsePlatform} and
- * {@link org.luaj.vm2.lib.jme.JmePlatform}
- * see to it that this {@link Globals} are initialized properly.
*
- * The behavior of coroutine threads matches closely the behavior
- * of C coroutine library. However, because of the use of Java threads
- * to manage call state, it is possible to yield from anywhere in luaj.
+ * The utility classes {@link org.luaj.vm2.lib.jse.JsePlatform} and
+ * {@link org.luaj.vm2.lib.jme.JmePlatform} see to it that this {@link Globals}
+ * are initialized properly.
*
- * Each Java thread wakes up at regular intervals and checks a weak reference
- * to determine if it can ever be resumed. If not, it throws
- * {@link OrphanedThread} which is an {@link java.lang.Error}.
- * Applications should not catch {@link OrphanedThread}, because it can break
- * the thread safety of luaj. The value controlling the polling interval
- * is {@link #thread_orphan_check_interval} and may be set by the user.
- *
- * There are two main ways to abandon a coroutine. The first is to call
- * {@code yield()} from lua, or equivalently {@link Globals#yield(Varargs)},
- * and arrange to have it never resumed possibly by values passed to yield.
- * The second is to throw {@link OrphanedThread}, which should put the thread
- * in a dead state. In either case all references to the thread must be
- * dropped, and the garbage collector must run for the thread to be
- * garbage collected.
+ * The behavior of coroutine threads matches closely the behavior of C coroutine
+ * library. However, because of the use of Java threads to manage call state, it
+ * is possible to yield from anywhere in luaj.
+ *
+ * Each Java thread wakes up at regular intervals and checks a weak reference to
+ * determine if it can ever be resumed. If not, it throws {@link OrphanedThread}
+ * which is an {@link java.lang.Error}. Applications should not catch
+ * {@link OrphanedThread}, because it can break the thread safety of luaj. The
+ * value controlling the polling interval is
+ * {@link #thread_orphan_check_interval} and may be set by the user.
+ *
+ * There are two main ways to abandon a coroutine. The first is to call
+ * {@code yield()} from lua, or equivalently {@link Globals#yield(Varargs)}, and
+ * arrange to have it never resumed possibly by values passed to yield. The
+ * second is to throw {@link OrphanedThread}, which should put the thread in a
+ * dead state. In either case all references to the thread must be dropped, and
+ * the garbage collector must run for the thread to be garbage collected.
+ *
*
- *
* @see LuaValue
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
@@ -70,107 +68,108 @@ public class LuaThread extends LuaValue {
/** Shared metatable for lua threads. */
public static LuaValue s_metatable;
- /** The current number of coroutines. Should not be set. */
+ /** The current number of coroutines. Should not be set. */
public static int coroutine_count = 0;
- /** Polling interval, in milliseconds, which each thread uses while waiting to
- * return from a yielded state to check if the lua threads is no longer
- * referenced and therefore should be garbage collected.
- * A short polling interval for many threads will consume server resources.
- * Orphaned threads cannot be detected and collected unless garbage
- * collection is run. This can be changed by Java startup code if desired.
+ /**
+ * Polling interval, in milliseconds, which each thread uses while waiting
+ * to return from a yielded state to check if the lua threads is no longer
+ * referenced and therefore should be garbage collected. A short polling
+ * interval for many threads will consume server resources. Orphaned threads
+ * cannot be detected and collected unless garbage collection is run. This
+ * can be changed by Java startup code if desired.
*/
public static long thread_orphan_check_interval = 5000;
-
- public static final int STATUS_INITIAL = 0;
- public static final int STATUS_SUSPENDED = 1;
- public static final int STATUS_RUNNING = 2;
- public static final int STATUS_NORMAL = 3;
- public static final int STATUS_DEAD = 4;
- public static final String[] STATUS_NAMES = {
- "suspended",
- "suspended",
- "running",
- "normal",
- "dead",};
-
+
+ public static final int STATUS_INITIAL = 0;
+ public static final int STATUS_SUSPENDED = 1;
+ public static final int STATUS_RUNNING = 2;
+ public static final int STATUS_NORMAL = 3;
+ public static final int STATUS_DEAD = 4;
+ public static final String[] STATUS_NAMES = { "suspended", "suspended", "running", "normal", "dead", };
+
public final State state;
- public static final int MAX_CALLSTACK = 256;
+ public static final int MAX_CALLSTACK = 256;
- /** Thread-local used by DebugLib to store debugging state.
- * This is an opaque value that should not be modified by applications. */
+ /**
+ * Thread-local used by DebugLib to store debugging state. This is an opaque
+ * value that should not be modified by applications.
+ */
public Object callstack;
public final Globals globals;
- /** Error message handler for this thread, if any. */
+ /** Error message handler for this thread, if any. */
public LuaValue errorfunc;
-
+
/** Private constructor for main thread only */
public LuaThread(Globals globals) {
state = new State(globals, this, null);
state.status = STATUS_RUNNING;
this.globals = globals;
}
-
- /**
+
+ /**
* Create a LuaThread around a function and environment
+ *
* @param func The function to execute
*/
- public LuaThread(Globals globals, LuaValue func) {
+ public LuaThread(Globals globals, LuaValue func) {
LuaValue.assert_(func != null, "function cannot be null");
state = new State(globals, this, func);
this.globals = globals;
}
-
+
+ @Override
public int type() {
return LuaValue.TTHREAD;
}
-
+
+ @Override
public String typename() {
return "thread";
}
-
+
+ @Override
public boolean isthread() {
return true;
}
-
+
+ @Override
public LuaThread optthread(LuaThread defval) {
return this;
}
-
+
+ @Override
public LuaThread checkthread() {
return this;
}
-
- public LuaValue getmetatable() {
- return s_metatable;
- }
-
- public String getStatus() {
- return STATUS_NAMES[state.status];
+
+ @Override
+ public LuaValue getmetatable() {
+ return s_metatable;
}
- public boolean isMainThread() {
- return this.state.function == null;
- }
+ public String getStatus() { return STATUS_NAMES[state.status]; }
+
+ public boolean isMainThread() { return this.state.function == null; }
public Varargs resume(Varargs args) {
final LuaThread.State s = this.state;
if (s.status > LuaThread.STATUS_SUSPENDED)
- return LuaValue.varargsOf(LuaValue.FALSE,
- LuaValue.valueOf("cannot resume "+(s.status==LuaThread.STATUS_DEAD? "dead": "non-suspended")+" coroutine"));
+ return LuaValue.varargsOf(LuaValue.FALSE, LuaValue.valueOf(
+ "cannot resume " + (s.status == LuaThread.STATUS_DEAD? "dead": "non-suspended") + " coroutine"));
return s.lua_resume(this, args);
}
public static class State implements Runnable {
private final Globals globals;
- final WeakReference lua_thread;
+ final WeakReference lua_thread;
public final LuaValue function;
- Varargs args = LuaValue.NONE;
- Varargs result = LuaValue.NONE;
- String error = null;
+ Varargs args = LuaValue.NONE;
+ Varargs result = LuaValue.NONE;
+ String error = null;
/** Hook function control state used by debug lib. */
public LuaValue hookfunc;
@@ -178,11 +177,11 @@ public class LuaThread extends LuaValue {
public boolean hookline;
public boolean hookcall;
public boolean hookrtrn;
- public int hookcount;
+ public int hookcount;
public boolean inhook;
- public int lastline;
- public int bytecodes;
-
+ public int lastline;
+ public int bytecodes;
+
public int status = LuaThread.STATUS_INITIAL;
State(Globals globals, LuaThread lua_thread, LuaValue function) {
@@ -190,7 +189,8 @@ public class LuaThread extends LuaValue {
this.lua_thread = new WeakReference(lua_thread);
this.function = function;
}
-
+
+ @Override
public synchronized void run() {
try {
Varargs a = this.args;
@@ -210,8 +210,8 @@ public class LuaThread extends LuaValue {
globals.running = new_thread;
this.args = args;
if (this.status == STATUS_INITIAL) {
- this.status = STATUS_RUNNING;
- new Thread(this, "Coroutine-"+(++coroutine_count)).start();
+ this.status = STATUS_RUNNING;
+ new Thread(this, "Coroutine-" + (++coroutine_count)).start();
} else {
this.notify();
}
@@ -219,9 +219,8 @@ public class LuaThread extends LuaValue {
previous_thread.state.status = STATUS_NORMAL;
this.status = STATUS_RUNNING;
this.wait();
- return (this.error != null?
- LuaValue.varargsOf(LuaValue.FALSE, LuaValue.valueOf(this.error)):
- LuaValue.varargsOf(LuaValue.TRUE, this.result));
+ return this.error != null? LuaValue.varargsOf(LuaValue.FALSE, LuaValue.valueOf(this.error))
+ : LuaValue.varargsOf(LuaValue.TRUE, this.result);
} catch (InterruptedException ie) {
throw new OrphanedThread();
} finally {
@@ -230,7 +229,7 @@ public class LuaThread extends LuaValue {
this.error = null;
globals.running = previous_thread;
if (previous_thread != null)
- globals.running.state.status =STATUS_RUNNING;
+ globals.running.state.status = STATUS_RUNNING;
}
}
@@ -245,7 +244,7 @@ public class LuaThread extends LuaValue {
this.status = STATUS_DEAD;
throw new OrphanedThread();
}
- } while (this.status == STATUS_SUSPENDED);
+ } while ( this.status == STATUS_SUSPENDED );
return this.args;
} catch (InterruptedException ie) {
this.status = STATUS_DEAD;
@@ -256,5 +255,5 @@ public class LuaThread extends LuaValue {
}
}
}
-
+
}
diff --git a/src/core/org/luaj/vm2/LuaUserdata.java b/luaj-core/src/main/java/org/luaj/vm2/LuaUserdata.java
similarity index 58%
rename from src/core/org/luaj/vm2/LuaUserdata.java
rename to luaj-core/src/main/java/org/luaj/vm2/LuaUserdata.java
index b6f58e09..7b36212c 100644
--- a/src/core/org/luaj/vm2/LuaUserdata.java
+++ b/luaj-core/src/main/java/org/luaj/vm2/LuaUserdata.java
@@ -10,7 +10,7 @@
*
* 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
@@ -21,106 +21,136 @@
******************************************************************************/
package org.luaj.vm2;
-
public class LuaUserdata extends LuaValue {
-
- public Object m_instance;
+
+ public Object m_instance;
public LuaValue m_metatable;
-
+
public LuaUserdata(Object obj) {
m_instance = obj;
}
-
+
public LuaUserdata(Object obj, LuaValue metatable) {
m_instance = obj;
m_metatable = metatable;
}
-
+
+ @Override
public String tojstring() {
return String.valueOf(m_instance);
}
-
+
+ @Override
public int type() {
return LuaValue.TUSERDATA;
}
-
+
+ @Override
public String typename() {
return "userdata";
}
+ @Override
public int hashCode() {
return m_instance.hashCode();
}
-
+
public Object userdata() {
return m_instance;
}
-
- public boolean isuserdata() { return true; }
- public boolean isuserdata(Class c) { return c.isAssignableFrom(m_instance.getClass()); }
- public Object touserdata() { return m_instance; }
- public Object touserdata(Class c) { return c.isAssignableFrom(m_instance.getClass())? m_instance: null; }
- public Object optuserdata(Object defval) { return m_instance; }
+
+ @Override
+ public boolean isuserdata() { return true; }
+
+ @Override
+ public boolean isuserdata(Class c) { return c.isAssignableFrom(m_instance.getClass()); }
+
+ @Override
+ public Object touserdata() { return m_instance; }
+
+ @Override
+ public Object touserdata(Class c) { return c.isAssignableFrom(m_instance.getClass())? m_instance: null; }
+
+ @Override
+ public Object optuserdata(Object defval) { return m_instance; }
+
+ @Override
public Object optuserdata(Class c, Object defval) {
if (!c.isAssignableFrom(m_instance.getClass()))
typerror(c.getName());
return m_instance;
}
-
+
+ @Override
public LuaValue getmetatable() {
return m_metatable;
}
+ @Override
public LuaValue setmetatable(LuaValue metatable) {
this.m_metatable = metatable;
return this;
}
+ @Override
public Object checkuserdata() {
return m_instance;
}
-
- public Object checkuserdata(Class c) {
- if ( c.isAssignableFrom(m_instance.getClass()) )
- return m_instance;
+
+ @Override
+ public Object checkuserdata(Class c) {
+ if (c.isAssignableFrom(m_instance.getClass()))
+ return m_instance;
return typerror(c.getName());
}
-
- public LuaValue get( LuaValue key ) {
- return m_metatable!=null? gettable(this,key): NIL;
- }
-
- public void set( LuaValue key, LuaValue value ) {
- if ( m_metatable==null || ! settable(this,key,value) )
- error( "cannot set "+key+" for userdata" );
+
+ @Override
+ public LuaValue get(LuaValue key) {
+ return m_metatable != null? gettable(this, key): NIL;
}
- public boolean equals( Object val ) {
- if ( this == val )
+ @Override
+ public void set(LuaValue key, LuaValue value) {
+ if (m_metatable == null || !settable(this, key, value))
+ error("cannot set " + key + " for userdata");
+ }
+
+ @Override
+ public boolean equals(Object val) {
+ if (this == val)
return true;
- if ( ! (val instanceof LuaUserdata) )
+ if (!(val instanceof LuaUserdata))
return false;
LuaUserdata u = (LuaUserdata) val;
return m_instance.equals(u.m_instance);
}
// equality w/ metatable processing
- public LuaValue eq( LuaValue val ) { return eq_b(val)? TRUE: FALSE; }
- public boolean eq_b( LuaValue val ) {
- if ( val.raweq(this) ) return true;
- if ( m_metatable == null || !val.isuserdata() ) return false;
+ @Override
+ public LuaValue eq(LuaValue val) { return eq_b(val)? TRUE: FALSE; }
+
+ @Override
+ public boolean eq_b(LuaValue val) {
+ if (val.raweq(this))
+ return true;
+ if (m_metatable == null || !val.isuserdata())
+ return false;
LuaValue valmt = val.getmetatable();
- return valmt!=null && LuaValue.eqmtcall(this, m_metatable, val, valmt);
+ return valmt != null && LuaValue.eqmtcall(this, m_metatable, val, valmt);
}
-
+
// equality w/o metatable processing
- public boolean raweq( LuaValue val ) { return val.raweq(this); }
- public boolean raweq( LuaUserdata val ) {
- return this == val || (m_metatable == val.m_metatable && m_instance.equals(val.m_instance));
+ @Override
+ public boolean raweq(LuaValue val) { return val.raweq(this); }
+
+ @Override
+ public boolean raweq(LuaUserdata val) {
+ return this == val || m_metatable == val.m_metatable && m_instance.equals(val.m_instance);
}
-
+
// __eq metatag processing
- public boolean eqmt( LuaValue val ) {
- return m_metatable!=null && val.isuserdata()? LuaValue.eqmtcall(this, m_metatable, val, val.getmetatable()): false;
+ public boolean eqmt(LuaValue val) {
+ return m_metatable != null && val.isuserdata()? LuaValue.eqmtcall(this, m_metatable, val, val.getmetatable())
+ : false;
}
}
diff --git a/luaj-core/src/main/java/org/luaj/vm2/LuaValue.java b/luaj-core/src/main/java/org/luaj/vm2/LuaValue.java
new file mode 100644
index 00000000..da5d49e3
--- /dev/null
+++ b/luaj-core/src/main/java/org/luaj/vm2/LuaValue.java
@@ -0,0 +1,4176 @@
+/*******************************************************************************
+* Copyright (c) 2009-2011 Luaj.org. All rights reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+******************************************************************************/
+package org.luaj.vm2;
+
+/**
+ * Base class for all concrete lua type values.
+ *
+ * Establishes base implementations for all the operations on lua types. This
+ * allows Java clients to deal essentially with one type for all Java values,
+ * namely {@link LuaValue}.
+ *
+ * Constructors are provided as static methods for common Java types, such as
+ * {@link LuaValue#valueOf(int)} or {@link LuaValue#valueOf(String)} to allow
+ * for instance pooling.
+ *
+ * Constants are defined for the lua values {@link #NIL}, {@link #TRUE}, and
+ * {@link #FALSE}. A constant {@link #NONE} is defined which is a
+ * {@link Varargs} list having no values.
+ *
+ * Operations are performed on values directly via their Java methods. For
+ * example, the following code divides two numbers:
+ *
+ *
+ * Field access and function calls are similar, with common overloads to
+ * simplify Java usage:
+ *
+ *
+ * To supply variable arguments or get multiple return values, use
+ * {@link #invoke(Varargs)} or {@link #invokemethod(LuaValue, Varargs)} methods:
+ *
+ *
+ * To load and run a script, {@link LoadState} is used:
+ *
+ *
+ * although {@code require} could also be used:
+ *
+ *
+ * In general a {@link LuaError} may be thrown on any operation when the types
+ * supplied to any operation are illegal from a lua perspective. Examples could
+ * be attempting to concatenate a NIL value, or attempting arithmetic on values
+ * that are not number.
+ *
+ * There are several methods for preinitializing tables, such as:
+ *
+ * Predefined constants exist for the standard lua type constants {@link #TNIL},
+ * {@link #TBOOLEAN}, {@link #TLIGHTUSERDATA}, {@link #TNUMBER},
+ * {@link #TSTRING}, {@link #TTABLE}, {@link #TFUNCTION}, {@link #TUSERDATA},
+ * {@link #TTHREAD}, and extended lua type constants {@link #TINT},
+ * {@link #TNONE}, {@link #TVALUE}
+ *
+ * Predefined constants exist for all strings used as metatags: {@link #INDEX},
+ * {@link #NEWINDEX}, {@link #CALL}, {@link #MODE}, {@link #METATABLE},
+ * {@link #ADD}, {@link #SUB}, {@link #DIV}, {@link #MUL}, {@link #POW},
+ * {@link #MOD}, {@link #UNM}, {@link #LEN}, {@link #EQ}, {@link #LT},
+ * {@link #LE}, {@link #TOSTRING}, and {@link #CONCAT}.
+ *
+ * @see org.luaj.vm2.lib.jse.JsePlatform
+ * @see org.luaj.vm2.lib.jme.JmePlatform
+ * @see LoadState
+ * @see Varargs
+ */
+abstract public class LuaValue extends Varargs {
+
+ /**
+ * Type enumeration constant for lua numbers that are ints, for
+ * compatibility with lua 5.1 number patch only
+ */
+ public static final int TINT = -2;
+
+ /**
+ * Type enumeration constant for lua values that have no type, for example
+ * weak table entries
+ */
+ public static final int TNONE = -1;
+
+ /** Type enumeration constant for lua nil */
+ public static final int TNIL = 0;
+
+ /** Type enumeration constant for lua booleans */
+ public static final int TBOOLEAN = 1;
+
+ /**
+ * Type enumeration constant for lua light userdata, for compatibility with
+ * C-based lua only
+ */
+ public static final int TLIGHTUSERDATA = 2;
+
+ /** Type enumeration constant for lua numbers */
+ public static final int TNUMBER = 3;
+
+ /** Type enumeration constant for lua strings */
+ public static final int TSTRING = 4;
+
+ /** Type enumeration constant for lua tables */
+ public static final int TTABLE = 5;
+
+ /** Type enumeration constant for lua functions */
+ public static final int TFUNCTION = 6;
+
+ /** Type enumeration constant for lua userdatas */
+ public static final int TUSERDATA = 7;
+
+ /** Type enumeration constant for lua threads */
+ public static final int TTHREAD = 8;
+
+ /**
+ * Type enumeration constant for unknown values, for compatibility with
+ * C-based lua only
+ */
+ public static final int TVALUE = 9;
+
+ /**
+ * String array constant containing names of each of the lua value types
+ *
+ * @see #type()
+ * @see #typename()
+ */
+ public static final String[] TYPE_NAMES = { "nil", "boolean", "lightuserdata", "number", "string", "table",
+ "function", "userdata", "thread", "value", };
+
+ /** LuaValue constant corresponding to lua {@code #NIL} */
+ public static final LuaValue NIL = LuaNil._NIL;
+
+ /** LuaBoolean constant corresponding to lua {@code true} */
+ public static final LuaBoolean TRUE = LuaBoolean._TRUE;
+
+ /** LuaBoolean constant corresponding to lua {@code false} */
+ public static final LuaBoolean FALSE = LuaBoolean._FALSE;
+
+ /**
+ * LuaValue constant corresponding to a {@link Varargs} list of no values
+ */
+ public static final LuaValue NONE = None._NONE;
+
+ /** LuaValue number constant equal to 0 */
+ public static final LuaNumber ZERO = LuaInteger.valueOf(0);
+
+ /** LuaValue number constant equal to 1 */
+ public static final LuaNumber ONE = LuaInteger.valueOf(1);
+
+ /** LuaValue number constant equal to -1 */
+ public static final LuaNumber MINUSONE = LuaInteger.valueOf(-1);
+
+ /** LuaValue array constant with no values */
+ public static final LuaValue[] NOVALS = {};
+
+ /** The variable name of the environment. */
+ public static LuaString ENV = valueOf("_ENV");
+
+ /** LuaString constant with value "__index" for use as metatag */
+ public static final LuaString INDEX = valueOf("__index");
+
+ /** LuaString constant with value "__newindex" for use as metatag */
+ public static final LuaString NEWINDEX = valueOf("__newindex");
+
+ /** LuaString constant with value "__call" for use as metatag */
+ public static final LuaString CALL = valueOf("__call");
+
+ /** LuaString constant with value "__mode" for use as metatag */
+ public static final LuaString MODE = valueOf("__mode");
+
+ /** LuaString constant with value "__metatable" for use as metatag */
+ public static final LuaString METATABLE = valueOf("__metatable");
+
+ /** LuaString constant with value "__add" for use as metatag */
+ public static final LuaString ADD = valueOf("__add");
+
+ /** LuaString constant with value "__sub" for use as metatag */
+ public static final LuaString SUB = valueOf("__sub");
+
+ /** LuaString constant with value "__div" for use as metatag */
+ public static final LuaString DIV = valueOf("__div");
+
+ /** LuaString constant with value "__mul" for use as metatag */
+ public static final LuaString MUL = valueOf("__mul");
+
+ /** LuaString constant with value "__pow" for use as metatag */
+ public static final LuaString POW = valueOf("__pow");
+
+ /** LuaString constant with value "__mod" for use as metatag */
+ public static final LuaString MOD = valueOf("__mod");
+
+ /** LuaString constant with value "__unm" for use as metatag */
+ public static final LuaString UNM = valueOf("__unm");
+
+ /** LuaString constant with value "__len" for use as metatag */
+ public static final LuaString LEN = valueOf("__len");
+
+ /** LuaString constant with value "__eq" for use as metatag */
+ public static final LuaString EQ = valueOf("__eq");
+
+ /** LuaString constant with value "__lt" for use as metatag */
+ public static final LuaString LT = valueOf("__lt");
+
+ /** LuaString constant with value "__le" for use as metatag */
+ public static final LuaString LE = valueOf("__le");
+
+ /** LuaString constant with value "__tostring" for use as metatag */
+ public static final LuaString TOSTRING = valueOf("__tostring");
+
+ /** LuaString constant with value "__concat" for use as metatag */
+ public static final LuaString CONCAT = valueOf("__concat");
+
+ /** LuaString constant with value "" */
+ public static final LuaString EMPTYSTRING = valueOf("");
+
+ /** Limit on lua stack size */
+ private static int MAXSTACK = 250;
+
+ /**
+ * Array of {@link #NIL} values to optimize filling stacks using
+ * System.arraycopy(). Must not be modified.
+ */
+ public static final LuaValue[] NILS = new LuaValue[MAXSTACK];
+ static {
+ for (int i = 0; i < MAXSTACK; i++)
+ NILS[i] = NIL;
+ }
+
+ // type
+ /**
+ * Get the enumeration value for the type of this value.
+ *
+ * @return value for this type, one of {@link #TNIL}, {@link #TBOOLEAN},
+ * {@link #TNUMBER}, {@link #TSTRING}, {@link #TTABLE},
+ * {@link #TFUNCTION}, {@link #TUSERDATA}, {@link #TTHREAD}
+ * @see #typename()
+ */
+ abstract public int type();
+
+ /**
+ * Get the String name of the type of this value.
+ *
+ *
+ * @return name from type name list {@link #TYPE_NAMES} corresponding to the
+ * type of this value: "nil", "boolean", "number", "string",
+ * "table", "function", "userdata", "thread"
+ * @see #type()
+ */
+ abstract public String typename();
+
+ /**
+ * Check if {@code this} is a {@code boolean}
+ *
+ * @return true if this is a {@code boolean}, otherwise false
+ * @see #isboolean()
+ * @see #toboolean()
+ * @see #checkboolean()
+ * @see #optboolean(boolean)
+ * @see #TBOOLEAN
+ */
+ public boolean isboolean() { return false; }
+
+ /**
+ * Check if {@code this} is a {@code function} that is a closure, meaning
+ * interprets lua bytecode for its execution
+ *
+ * @return true if this is a {@code closure}, otherwise false
+ * @see #isfunction()
+ * @see #checkclosure()
+ * @see #optclosure(LuaClosure)
+ * @see #TFUNCTION
+ */
+ public boolean isclosure() { return false; }
+
+ /**
+ * Check if {@code this} is a {@code function}
+ *
+ * @return true if this is a {@code function}, otherwise false
+ * @see #isclosure()
+ * @see #checkfunction()
+ * @see #optfunction(LuaFunction)
+ * @see #TFUNCTION
+ */
+ public boolean isfunction() { return false; }
+
+ /**
+ * Check if {@code this} is a {@code number} and is representable by java
+ * int without rounding or truncation
+ *
+ * @return true if this is a {@code number} meaning derives from
+ * {@link LuaNumber} or derives from {@link LuaString} and is
+ * convertible to a number, and can be represented by int, otherwise
+ * false
+ * @see #isinttype()
+ * @see #islong()
+ * @see #tonumber()
+ * @see #checkint()
+ * @see #optint(int)
+ * @see #TNUMBER
+ */
+ public boolean isint() { return false; }
+
+ /**
+ * Check if {@code this} is a {@link LuaInteger}
+ *
+ * No attempt to convert from string will be made by this call.
+ *
+ * @return true if this is a {@code LuaInteger}, otherwise false
+ * @see #isint()
+ * @see #isnumber()
+ * @see #tonumber()
+ * @see #TNUMBER
+ */
+ public boolean isinttype() { return false; }
+
+ /**
+ * Check if {@code this} is a {@code number} and is representable by java
+ * long without rounding or truncation
+ *
+ * @return true if this is a {@code number} meaning derives from
+ * {@link LuaNumber} or derives from {@link LuaString} and is
+ * convertible to a number, and can be represented by long,
+ * otherwise false
+ * @see #tonumber()
+ * @see #checklong()
+ * @see #optlong(long)
+ * @see #TNUMBER
+ */
+ public boolean islong() { return false; }
+
+ /**
+ * Check if {@code this} is {@code #NIL}
+ *
+ * @return true if this is {@code #NIL}, otherwise false
+ * @see #NIL
+ * @see #NONE
+ * @see #checknotnil()
+ * @see #optvalue(LuaValue)
+ * @see Varargs#isnoneornil(int)
+ * @see #TNIL
+ * @see #TNONE
+ */
+ public boolean isnil() { return false; }
+
+ /**
+ * Check if {@code this} is a {@code number}
+ *
+ * @return true if this is a {@code number}, meaning derives from
+ * {@link LuaNumber} or derives from {@link LuaString} and is
+ * convertible to a number, otherwise false
+ * @see #tonumber()
+ * @see #checknumber()
+ * @see #optnumber(LuaNumber)
+ * @see #TNUMBER
+ */
+ public boolean isnumber() { return false; } // may convert from string
+
+ /**
+ * Check if {@code this} is a {@code string}
+ *
+ * @return true if this is a {@code string}, meaning derives from
+ * {@link LuaString} or {@link LuaNumber}, otherwise false
+ * @see #tostring()
+ * @see #checkstring()
+ * @see #optstring(LuaString)
+ * @see #TSTRING
+ */
+ public boolean isstring() { return false; }
+
+ /**
+ * Check if {@code this} is a {@code thread}
+ *
+ * @return true if this is a {@code thread}, otherwise false
+ * @see #checkthread()
+ * @see #optthread(LuaThread)
+ * @see #TTHREAD
+ */
+ public boolean isthread() { return false; }
+
+ /**
+ * Check if {@code this} is a {@code table}
+ *
+ * @return true if this is a {@code table}, otherwise false
+ * @see #checktable()
+ * @see #opttable(LuaTable)
+ * @see #TTABLE
+ */
+ public boolean istable() { return false; }
+
+ /**
+ * Check if {@code this} is a {@code userdata}
+ *
+ * @return true if this is a {@code userdata}, otherwise false
+ * @see #isuserdata(Class)
+ * @see #touserdata()
+ * @see #checkuserdata()
+ * @see #optuserdata(Object)
+ * @see #TUSERDATA
+ */
+ public boolean isuserdata() { return false; }
+
+ /**
+ * Check if {@code this} is a {@code userdata} of type {@code c}
+ *
+ * @param c Class to test instance against
+ * @return true if this is a {@code userdata} and the instance is assignable
+ * to {@code c}, otherwise false
+ * @see #isuserdata()
+ * @see #touserdata(Class)
+ * @see #checkuserdata(Class)
+ * @see #optuserdata(Class, Object)
+ * @see #TUSERDATA
+ */
+ public boolean isuserdata(Class c) { return false; }
+
+ /**
+ * Convert to boolean false if {@link #NIL} or {@link #FALSE}, true if
+ * anything else
+ *
+ * @return Value cast to byte if number or string convertible to number,
+ * otherwise 0
+ * @see #optboolean(boolean)
+ * @see #checkboolean()
+ * @see #isboolean()
+ * @see #TBOOLEAN
+ */
+ public boolean toboolean() { return true; }
+
+ /**
+ * Convert to byte if numeric, or 0 if not.
+ *
+ * @return Value cast to byte if number or string convertible to number,
+ * otherwise 0
+ * @see #toint()
+ * @see #todouble()
+ * @see #checknumber()
+ * @see #isnumber()
+ * @see #TNUMBER
+ */
+ public byte tobyte() { return 0; }
+
+ /**
+ * Convert to char if numeric, or 0 if not.
+ *
+ * @return Value cast to char if number or string convertible to number,
+ * otherwise 0
+ * @see #toint()
+ * @see #todouble()
+ * @see #checknumber()
+ * @see #isnumber()
+ * @see #TNUMBER
+ */
+ public char tochar() { return 0; }
+
+ /**
+ * Convert to double if numeric, or 0 if not.
+ *
+ * @return Value cast to double if number or string convertible to number,
+ * otherwise 0
+ * @see #toint()
+ * @see #tobyte()
+ * @see #tochar()
+ * @see #toshort()
+ * @see #tolong()
+ * @see #tofloat()
+ * @see #optdouble(double)
+ * @see #checknumber()
+ * @see #isnumber()
+ * @see #TNUMBER
+ */
+ public double todouble() { return 0; }
+
+ /**
+ * Convert to float if numeric, or 0 if not.
+ *
+ * @return Value cast to float if number or string convertible to number,
+ * otherwise 0
+ * @see #toint()
+ * @see #todouble()
+ * @see #checknumber()
+ * @see #isnumber()
+ * @see #TNUMBER
+ */
+ public float tofloat() { return 0; }
+
+ /**
+ * Convert to int if numeric, or 0 if not.
+ *
+ * @return Value cast to int if number or string convertible to number,
+ * otherwise 0
+ * @see #tobyte()
+ * @see #tochar()
+ * @see #toshort()
+ * @see #tolong()
+ * @see #tofloat()
+ * @see #todouble()
+ * @see #optint(int)
+ * @see #checknumber()
+ * @see #isnumber()
+ * @see #TNUMBER
+ */
+ public int toint() { return 0; }
+
+ /**
+ * Convert to long if numeric, or 0 if not.
+ *
+ * @return Value cast to long if number or string convertible to number,
+ * otherwise 0
+ * @see #isint()
+ * @see #isinttype()
+ * @see #toint()
+ * @see #todouble()
+ * @see #optlong(long)
+ * @see #checknumber()
+ * @see #isnumber()
+ * @see #TNUMBER
+ */
+ public long tolong() { return 0; }
+
+ /**
+ * Convert to short if numeric, or 0 if not.
+ *
+ * @return Value cast to short if number or string convertible to number,
+ * otherwise 0
+ * @see #toint()
+ * @see #todouble()
+ * @see #checknumber()
+ * @see #isnumber()
+ * @see #TNUMBER
+ */
+ public short toshort() { return 0; }
+
+ /**
+ * Convert to human readable String for any type.
+ *
+ * @return String for use by human readers based on type.
+ * @see #tostring()
+ * @see #optjstring(String)
+ * @see #checkjstring()
+ * @see #isstring()
+ * @see #TSTRING
+ */
+ @Override
+ public String tojstring() { return typename() + ": " + Integer.toHexString(hashCode()); }
+
+ /**
+ * Convert to userdata instance, or null.
+ *
+ * @return userdata instance if userdata, or null if not {@link LuaUserdata}
+ * @see #optuserdata(Object)
+ * @see #checkuserdata()
+ * @see #isuserdata()
+ * @see #TUSERDATA
+ */
+ public Object touserdata() { return null; }
+
+ /**
+ * Convert to userdata instance if specific type, or null.
+ *
+ * @return userdata instance if is a userdata whose instance derives from
+ * {@code c}, or null if not {@link LuaUserdata}
+ * @see #optuserdata(Class,Object)
+ * @see #checkuserdata(Class)
+ * @see #isuserdata(Class)
+ * @see #TUSERDATA
+ */
+ public Object touserdata(Class c) { return null; }
+
+ /**
+ * Convert the value to a human readable string using {@link #tojstring()}
+ *
+ * @return String value intended to be human readible.
+ * @see #tostring()
+ * @see #tojstring()
+ * @see #optstring(LuaString)
+ * @see #checkstring()
+ * @see #toString()
+ */
+ @Override
+ public String toString() { return tojstring(); }
+
+ /**
+ * Conditionally convert to lua number without throwing errors.
+ *
+ * In lua all numbers are strings, but not all strings are numbers. This
+ * function will return the {@link LuaValue} {@code this} if it is a number
+ * or a string convertible to a number, and {@link #NIL} for all other
+ * cases.
+ *
+ * This allows values to be tested for their "numeric-ness" without the
+ * penalty of throwing exceptions, nor the cost of converting the type and
+ * creating storage for it.
+ *
+ * @return {@code this} if it is a {@link LuaNumber} or {@link LuaString}
+ * that can be converted to a number, otherwise {@link #NIL}
+ * @see #tostring()
+ * @see #optnumber(LuaNumber)
+ * @see #checknumber()
+ * @see #toint()
+ * @see #todouble()
+ */
+ public LuaValue tonumber() { return NIL; }
+
+ /**
+ * Conditionally convert to lua string without throwing errors.
+ *
+ * In lua all numbers are strings, so this function will return the
+ * {@link LuaValue} {@code this} if it is a string or number, and
+ * {@link #NIL} for all other cases.
+ *
+ * This allows values to be tested for their "string-ness" without the
+ * penalty of throwing exceptions.
+ *
+ * @return {@code this} if it is a {@link LuaString} or {@link LuaNumber},
+ * otherwise {@link #NIL}
+ * @see #tonumber()
+ * @see #tojstring()
+ * @see #optstring(LuaString)
+ * @see #checkstring()
+ * @see #toString()
+ */
+ public LuaValue tostring() { return NIL; }
+
+ /**
+ * Check that optional argument is a boolean and return its boolean value
+ *
+ * @param defval boolean value to return if {@code this} is nil or none
+ * @return {@code this} cast to boolean if a {@link LuaBoolean},
+ * {@code defval} if nil or none, throws {@link LuaError} otherwise
+ * @throws LuaError if was not a boolean or nil or none.
+ * @see #checkboolean()
+ * @see #isboolean()
+ * @see #TBOOLEAN
+ */
+ public boolean optboolean(boolean defval) { argerror("boolean"); return false; }
+
+ /**
+ * Check that optional argument is a closure and return as
+ * {@link LuaClosure}
+ *
+ * A {@link LuaClosure} is a {@link LuaFunction} that executes lua
+ * byteccode.
+ *
+ * @param defval {@link LuaClosure} to return if {@code this} is nil or none
+ * @return {@code this} cast to {@link LuaClosure} if a function,
+ * {@code defval} if nil or none, throws {@link LuaError} otherwise
+ * @throws LuaError if was not a closure or nil or none.
+ * @see #checkclosure()
+ * @see #isclosure()
+ * @see #TFUNCTION
+ */
+ public LuaClosure optclosure(LuaClosure defval) { argerror("closure"); return null; }
+
+ /**
+ * Check that optional argument is a number or string convertible to number
+ * and return as double
+ *
+ * @param defval double to return if {@code this} is nil or none
+ * @return {@code this} cast to double if numeric, {@code defval} if nil or
+ * none, throws {@link LuaError} otherwise
+ * @throws LuaError if was not numeric or nil or none.
+ * @see #optint(int)
+ * @see #optinteger(LuaInteger)
+ * @see #checkdouble()
+ * @see #todouble()
+ * @see #tonumber()
+ * @see #isnumber()
+ * @see #TNUMBER
+ */
+ public double optdouble(double defval) { argerror("number"); return 0; }
+
+ /**
+ * Check that optional argument is a function and return as
+ * {@link LuaFunction}
+ *
+ * A {@link LuaFunction} may either be a Java function that implements
+ * functionality directly in Java, or a {@link LuaClosure} which is a
+ * {@link LuaFunction} that executes lua bytecode.
+ *
+ * @param defval {@link LuaFunction} to return if {@code this} is nil or
+ * none
+ * @return {@code this} cast to {@link LuaFunction} if a function,
+ * {@code defval} if nil or none, throws {@link LuaError} otherwise
+ * @throws LuaError if was not a function or nil or none.
+ * @see #checkfunction()
+ * @see #isfunction()
+ * @see #TFUNCTION
+ */
+ public LuaFunction optfunction(LuaFunction defval) { argerror("function"); return null; }
+
+ /**
+ * Check that optional argument is a number or string convertible to number
+ * and return as int
+ *
+ * @param defval int to return if {@code this} is nil or none
+ * @return {@code this} cast to int if numeric, {@code defval} if nil or
+ * none, throws {@link LuaError} otherwise
+ * @throws LuaError if was not numeric or nil or none.
+ * @see #optdouble(double)
+ * @see #optlong(long)
+ * @see #optinteger(LuaInteger)
+ * @see #checkint()
+ * @see #toint()
+ * @see #tonumber()
+ * @see #isnumber()
+ * @see #TNUMBER
+ */
+ public int optint(int defval) { argerror("int"); return 0; }
+
+ /**
+ * Check that optional argument is a number or string convertible to number
+ * and return as {@link LuaInteger}
+ *
+ * @param defval {@link LuaInteger} to return if {@code this} is nil or none
+ * @return {@code this} converted and wrapped in {@link LuaInteger} if
+ * numeric, {@code defval} if nil or none, throws {@link LuaError}
+ * otherwise
+ * @throws LuaError if was not numeric or nil or none.
+ * @see #optdouble(double)
+ * @see #optint(int)
+ * @see #checkint()
+ * @see #toint()
+ * @see #tonumber()
+ * @see #isnumber()
+ * @see #TNUMBER
+ */
+ public LuaInteger optinteger(LuaInteger defval) { argerror("integer"); return null; }
+
+ /**
+ * Check that optional argument is a number or string convertible to number
+ * and return as long
+ *
+ * @param defval long to return if {@code this} is nil or none
+ * @return {@code this} cast to long if numeric, {@code defval} if nil or
+ * none, throws {@link LuaError} otherwise
+ * @throws LuaError if was not numeric or nil or none.
+ * @see #optdouble(double)
+ * @see #optint(int)
+ * @see #checkint()
+ * @see #toint()
+ * @see #tonumber()
+ * @see #isnumber()
+ * @see #TNUMBER
+ */
+ public long optlong(long defval) { argerror("long"); return 0; }
+
+ /**
+ * Check that optional argument is a number or string convertible to number
+ * and return as {@link LuaNumber}
+ *
+ * @param defval {@link LuaNumber} to return if {@code this} is nil or none
+ * @return {@code this} cast to {@link LuaNumber} if numeric, {@code defval}
+ * if nil or none, throws {@link LuaError} otherwise
+ * @throws LuaError if was not numeric or nil or none.
+ * @see #optdouble(double)
+ * @see #optlong(long)
+ * @see #optint(int)
+ * @see #checkint()
+ * @see #toint()
+ * @see #tonumber()
+ * @see #isnumber()
+ * @see #TNUMBER
+ */
+ public LuaNumber optnumber(LuaNumber defval) { argerror("number"); return null; }
+
+ /**
+ * Check that optional argument is a string or number and return as Java
+ * String
+ *
+ * @param defval {@link LuaString} to return if {@code this} is nil or none
+ * @return {@code this} converted to String if a string or number,
+ * {@code defval} if nil or none, throws {@link LuaError} if some
+ * other type
+ * @throws LuaError if was not a string or number or nil or none.
+ * @see #tojstring()
+ * @see #optstring(LuaString)
+ * @see #checkjstring()
+ * @see #toString()
+ * @see #TSTRING
+ */
+ public String optjstring(String defval) { argerror("string"); return null; }
+
+ /**
+ * Check that optional argument is a string or number and return as
+ * {@link LuaString}
+ *
+ * @param defval {@link LuaString} to return if {@code this} is nil or none
+ * @return {@code this} converted to {@link LuaString} if a string or
+ * number, {@code defval} if nil or none, throws {@link LuaError} if
+ * some other type
+ * @throws LuaError if was not a string or number or nil or none.
+ * @see #tojstring()
+ * @see #optjstring(String)
+ * @see #checkstring()
+ * @see #toString()
+ * @see #TSTRING
+ */
+ public LuaString optstring(LuaString defval) { argerror("string"); return null; }
+
+ /**
+ * Check that optional argument is a table and return as {@link LuaTable}
+ *
+ * @param defval {@link LuaTable} to return if {@code this} is nil or none
+ * @return {@code this} cast to {@link LuaTable} if a table, {@code defval}
+ * if nil or none, throws {@link LuaError} if some other type
+ * @throws LuaError if was not a table or nil or none.
+ * @see #checktable()
+ * @see #istable()
+ * @see #TTABLE
+ */
+ public LuaTable opttable(LuaTable defval) { argerror("table"); return null; }
+
+ /**
+ * Check that optional argument is a thread and return as {@link LuaThread}
+ *
+ * @param defval {@link LuaThread} to return if {@code this} is nil or none
+ * @return {@code this} cast to {@link LuaTable} if a thread, {@code defval}
+ * if nil or none, throws {@link LuaError} if some other type
+ * @throws LuaError if was not a thread or nil or none.
+ * @see #checkthread()
+ * @see #isthread()
+ * @see #TTHREAD
+ */
+ public LuaThread optthread(LuaThread defval) { argerror("thread"); return null; }
+
+ /**
+ * Check that optional argument is a userdata and return the Object instance
+ *
+ * @param defval Object to return if {@code this} is nil or none
+ * @return Object instance of the userdata if a {@link LuaUserdata},
+ * {@code defval} if nil or none, throws {@link LuaError} if some
+ * other type
+ * @throws LuaError if was not a userdata or nil or none.
+ * @see #checkuserdata()
+ * @see #isuserdata()
+ * @see #optuserdata(Class, Object)
+ * @see #TUSERDATA
+ */
+ public Object optuserdata(Object defval) { argerror("object"); return null; }
+
+ /**
+ * Check that optional argument is a userdata whose instance is of a type
+ * and return the Object instance
+ *
+ * @param c Class to test userdata instance against
+ * @param defval Object to return if {@code this} is nil or none
+ * @return Object instance of the userdata if a {@link LuaUserdata} and
+ * instance is assignable to {@code c}, {@code defval} if nil or
+ * none, throws {@link LuaError} if some other type
+ * @throws LuaError if was not a userdata whose instance is assignable to
+ * {@code c} or nil or none.
+ * @see #checkuserdata(Class)
+ * @see #isuserdata(Class)
+ * @see #optuserdata(Object)
+ * @see #TUSERDATA
+ */
+ public Object optuserdata(Class c, Object defval) { argerror(c.getName()); return null; }
+
+ /**
+ * Perform argument check that this is not nil or none.
+ *
+ * @param defval {@link LuaValue} to return if {@code this} is nil or none
+ * @return {@code this} if not nil or none, else {@code defval}
+ * @see #NIL
+ * @see #NONE
+ * @see #isnil()
+ * @see Varargs#isnoneornil(int)
+ * @see #TNIL
+ * @see #TNONE
+ */
+ public LuaValue optvalue(LuaValue defval) { return this; }
+
+ /**
+ * Check that the value is a {@link LuaBoolean}, or throw {@link LuaError}
+ * if not
+ *
+ * @return boolean value for {@code this} if it is a {@link LuaBoolean}
+ * @throws LuaError if not a {@link LuaBoolean}
+ * @see #optboolean(boolean)
+ * @see #TBOOLEAN
+ */
+ public boolean checkboolean() { argerror("boolean"); return false; }
+
+ /**
+ * Check that the value is a {@link LuaClosure} , or throw {@link LuaError}
+ * if not
+ *
+ * {@link LuaClosure} is a subclass of {@link LuaFunction} that interprets
+ * lua bytecode.
+ *
+ * @return {@code this} cast as {@link LuaClosure}
+ * @throws LuaError if not a {@link LuaClosure}
+ * @see #checkfunction()
+ * @see #optclosure(LuaClosure)
+ * @see #isclosure()
+ * @see #TFUNCTION
+ */
+ public LuaClosure checkclosure() { argerror("function"); return null; }
+
+ /**
+ * Check that the value is numeric and return the value as a double, or
+ * throw {@link LuaError} if not numeric
+ *
+ * Values that are {@link LuaNumber} and values that are {@link LuaString}
+ * that can be converted to a number will be converted to double.
+ *
+ * @return value cast to a double if numeric
+ * @throws LuaError if not a {@link LuaNumber} or is a {@link LuaString}
+ * that can't be converted to number
+ * @see #checkint()
+ * @see #checkinteger()
+ * @see #checklong()
+ * @see #optdouble(double)
+ * @see #TNUMBER
+ */
+ public double checkdouble() { argerror("number"); return 0; }
+
+ /**
+ * Check that the value is a function , or throw {@link LuaError} if not
+ *
+ * A {@link LuaFunction} may either be a Java function that implements
+ * functionality directly in Java, or a {@link LuaClosure} which is a
+ * {@link LuaFunction} that executes lua bytecode.
+ *
+ * @return {@code this} if it is a lua function or closure
+ * @throws LuaError if not a function
+ * @see #checkclosure()
+ */
+ public LuaFunction checkfunction() { argerror("function"); return null; }
+
+ /**
+ * Check that the value is a Globals instance, or throw {@link LuaError} if
+ * not
+ *
+ * {@link Globals} are a special {@link LuaTable} that establish the default
+ * global environment.
+ *
+ * @return {@code this} if if an instance fof {@link Globals}
+ * @throws LuaError if not a {@link Globals} instance.
+ */
+ public Globals checkglobals() { argerror("globals"); return null; }
+
+ /**
+ * Check that the value is numeric, and convert and cast value to int, or
+ * throw {@link LuaError} if not numeric
+ *
+ * Values that are {@link LuaNumber} will be cast to int and may lose
+ * precision. Values that are {@link LuaString} that can be converted to a
+ * number will be converted, then cast to int, so may also lose precision.
+ *
+ * @return value cast to a int if numeric
+ * @throws LuaError if not a {@link LuaNumber} or is a {@link LuaString}
+ * that can't be converted to number
+ * @see #checkinteger()
+ * @see #checklong()
+ * @see #checkdouble()
+ * @see #optint(int)
+ * @see #TNUMBER
+ */
+ public int checkint() { argerror("number"); return 0; }
+
+ /**
+ * Check that the value is numeric, and convert and cast value to int, or
+ * throw {@link LuaError} if not numeric
+ *
+ * Values that are {@link LuaNumber} will be cast to int and may lose
+ * precision. Values that are {@link LuaString} that can be converted to a
+ * number will be converted, then cast to int, so may also lose precision.
+ *
+ * @return value cast to a int and wrapped in {@link LuaInteger} if numeric
+ * @throws LuaError if not a {@link LuaNumber} or is a {@link LuaString}
+ * that can't be converted to number
+ * @see #checkint()
+ * @see #checklong()
+ * @see #checkdouble()
+ * @see #optinteger(LuaInteger)
+ * @see #TNUMBER
+ */
+ public LuaInteger checkinteger() { argerror("integer"); return null; }
+
+ /**
+ * Check that the value is numeric, and convert and cast value to long, or
+ * throw {@link LuaError} if not numeric
+ *
+ * Values that are {@link LuaNumber} will be cast to long and may lose
+ * precision. Values that are {@link LuaString} that can be converted to a
+ * number will be converted, then cast to long, so may also lose precision.
+ *
+ * @return value cast to a long if numeric
+ * @throws LuaError if not a {@link LuaNumber} or is a {@link LuaString}
+ * that can't be converted to number
+ * @see #checkint()
+ * @see #checkinteger()
+ * @see #checkdouble()
+ * @see #optlong(long)
+ * @see #TNUMBER
+ */
+ public long checklong() { argerror("long"); return 0; }
+
+ /**
+ * Check that the value is numeric, and return as a LuaNumber if so, or
+ * throw {@link LuaError}
+ *
+ * Values that are {@link LuaString} that can be converted to a number will
+ * be converted and returned.
+ *
+ * @return value as a {@link LuaNumber} if numeric
+ * @throws LuaError if not a {@link LuaNumber} or is a {@link LuaString}
+ * that can't be converted to number
+ * @see #checkint()
+ * @see #checkinteger()
+ * @see #checkdouble()
+ * @see #checklong()
+ * @see #optnumber(LuaNumber)
+ * @see #TNUMBER
+ */
+ public LuaNumber checknumber() { argerror("number"); return null; }
+
+ /**
+ * Check that the value is numeric, and return as a LuaNumber if so, or
+ * throw {@link LuaError}
+ *
+ * Values that are {@link LuaString} that can be converted to a number will
+ * be converted and returned.
+ *
+ * @param msg String message to supply if conversion fails
+ * @return value as a {@link LuaNumber} if numeric
+ * @throws LuaError if not a {@link LuaNumber} or is a {@link LuaString}
+ * that can't be converted to number
+ * @see #checkint()
+ * @see #checkinteger()
+ * @see #checkdouble()
+ * @see #checklong()
+ * @see #optnumber(LuaNumber)
+ * @see #TNUMBER
+ */
+ public LuaNumber checknumber(String msg) { throw new LuaError(msg); }
+
+ /**
+ * Convert this value to a Java String.
+ *
+ * The string representations here will roughly match what is produced by
+ * the C lua distribution, however hash codes have no relationship, and
+ * there may be differences in number formatting.
+ *
+ * @return String representation of the value
+ * @see #checkstring()
+ * @see #optjstring(String)
+ * @see #tojstring()
+ * @see #isstring
+ * @see #TSTRING
+ */
+ public String checkjstring() { argerror("string"); return null; }
+
+ /**
+ * Check that this is a lua string, or throw {@link LuaError} if it is not.
+ *
+ * In lua all numbers are strings, so this will succeed for anything that
+ * derives from {@link LuaString} or {@link LuaNumber}. Numbers will be
+ * converted to {@link LuaString}.
+ *
+ * @return {@link LuaString} representation of the value if it is a
+ * {@link LuaString} or {@link LuaNumber}
+ * @throws LuaError if {@code this} is not a {@link LuaTable}
+ * @see #checkjstring()
+ * @see #optstring(LuaString)
+ * @see #tostring()
+ * @see #isstring()
+ * @see #TSTRING
+ */
+ public LuaString checkstring() { argerror("string"); return null; }
+
+ /**
+ * Check that this is a {@link LuaTable}, or throw {@link LuaError} if it is
+ * not
+ *
+ * @return {@code this} if it is a {@link LuaTable}
+ * @throws LuaError if {@code this} is not a {@link LuaTable}
+ * @see #istable()
+ * @see #opttable(LuaTable)
+ * @see #TTABLE
+ */
+ public LuaTable checktable() { argerror("table"); return null; }
+
+ /**
+ * Check that this is a {@link LuaThread}, or throw {@link LuaError} if it
+ * is not
+ *
+ * @return {@code this} if it is a {@link LuaThread}
+ * @throws LuaError if {@code this} is not a {@link LuaThread}
+ * @see #isthread()
+ * @see #optthread(LuaThread)
+ * @see #TTHREAD
+ */
+ public LuaThread checkthread() { argerror("thread"); return null; }
+
+ /**
+ * Check that this is a {@link LuaUserdata}, or throw {@link LuaError} if it
+ * is not
+ *
+ * @return {@code this} if it is a {@link LuaUserdata}
+ * @throws LuaError if {@code this} is not a {@link LuaUserdata}
+ * @see #isuserdata()
+ * @see #optuserdata(Object)
+ * @see #checkuserdata(Class)
+ * @see #TUSERDATA
+ */
+ public Object checkuserdata() { argerror("userdata"); return null; }
+
+ /**
+ * Check that this is a {@link LuaUserdata}, or throw {@link LuaError} if it
+ * is not
+ *
+ * @return {@code this} if it is a {@link LuaUserdata}
+ * @throws LuaError if {@code this} is not a {@link LuaUserdata}
+ * @see #isuserdata(Class)
+ * @see #optuserdata(Class, Object)
+ * @see #checkuserdata()
+ * @see #TUSERDATA
+ */
+ public Object checkuserdata(Class c) { argerror("userdata"); return null; }
+
+ /**
+ * Check that this is not the value {@link #NIL}, or throw {@link LuaError}
+ * if it is
+ *
+ * @return {@code this} if it is not {@link #NIL}
+ * @throws LuaError if {@code this} is {@link #NIL}
+ * @see #optvalue(LuaValue)
+ */
+ public LuaValue checknotnil() { return this; }
+
+ /**
+ * Return true if this is a valid key in a table index operation.
+ *
+ * @return true if valid as a table key, otherwise false
+ * @see #isnil()
+ * @see #isinttype()
+ */
+ public boolean isvalidkey() { return true; }
+
+ /**
+ * Throw a {@link LuaError} with a particular message
+ *
+ * @param message String providing message details
+ * @throws LuaError in all cases
+ */
+ public static LuaValue error(String message) { throw new LuaError(message); }
+
+ /**
+ * Assert a condition is true, or throw a {@link LuaError} if not Returns no
+ * value when b is true, throws {@link #error(String)} with {@code msg} as
+ * argument and does not return if b is false.
+ *
+ * @param b condition to test
+ * @param msg String message to produce on failure
+ * @throws LuaError if b is not true
+ */
+ public static void assert_(boolean b, String msg) {
+ if (!b)
+ throw new LuaError(msg);
+ }
+
+ /**
+ * Throw a {@link LuaError} indicating an invalid argument was supplied to a
+ * function
+ *
+ * @param expected String naming the type that was expected
+ * @throws LuaError in all cases
+ */
+ protected LuaValue argerror(String expected) {
+ throw new LuaError("bad argument: " + expected + " expected, got " + typename());
+ }
+
+ /**
+ * Throw a {@link LuaError} indicating an invalid argument was supplied to a
+ * function
+ *
+ * @param iarg index of the argument that was invalid, first index is 1
+ * @param msg String providing information about the invalid argument
+ * @throws LuaError in all cases
+ */
+ public static LuaValue argerror(int iarg, String msg) {
+ throw new LuaError("bad argument #" + iarg + ": " + msg);
+ }
+
+ /**
+ * Throw a {@link LuaError} indicating an invalid type was supplied to a
+ * function
+ *
+ * @param expected String naming the type that was expected
+ * @throws LuaError in all cases
+ */
+ protected LuaValue typerror(String expected) { throw new LuaError(expected + " expected, got " + typename()); }
+
+ /**
+ * Throw a {@link LuaError} indicating an operation is not implemented
+ *
+ * @throws LuaError in all cases
+ */
+ protected LuaValue unimplemented(String fun) {
+ throw new LuaError("'" + fun + "' not implemented for " + typename());
+ }
+
+ /**
+ * Throw a {@link LuaError} indicating an illegal operation occurred,
+ * typically involved in managing weak references
+ *
+ * @throws LuaError in all cases
+ */
+ protected LuaValue illegal(String op, String typename) {
+ throw new LuaError("illegal operation '" + op + "' for " + typename);
+ }
+
+ /**
+ * Throw a {@link LuaError} based on the len operator, typically due to an
+ * invalid operand type
+ *
+ * @throws LuaError in all cases
+ */
+ protected LuaValue lenerror() { throw new LuaError("attempt to get length of " + typename()); }
+
+ /**
+ * Throw a {@link LuaError} based on an arithmetic error such as add, or
+ * pow, typically due to an invalid operand type
+ *
+ * @throws LuaError in all cases
+ */
+ protected LuaValue aritherror() { throw new LuaError("attempt to perform arithmetic on " + typename()); }
+
+ /**
+ * Throw a {@link LuaError} based on an arithmetic error such as add, or
+ * pow, typically due to an invalid operand type
+ *
+ * @param fun String description of the function that was attempted
+ * @throws LuaError in all cases
+ */
+ protected LuaValue aritherror(String fun) {
+ throw new LuaError("attempt to perform arithmetic '" + fun + "' on " + typename());
+ }
+
+ /**
+ * Throw a {@link LuaError} based on a comparison error such as greater-than
+ * or less-than, typically due to an invalid operand type
+ *
+ * @param rhs String description of what was on the right-hand-side of the
+ * comparison that resulted in the error.
+ * @throws LuaError in all cases
+ */
+ protected LuaValue compareerror(String rhs) {
+ throw new LuaError("attempt to compare " + typename() + " with " + rhs);
+ }
+
+ /**
+ * Throw a {@link LuaError} based on a comparison error such as greater-than
+ * or less-than, typically due to an invalid operand type
+ *
+ * @param rhs Right-hand-side of the comparison that resulted in the error.
+ * @throws LuaError in all cases
+ */
+ protected LuaValue compareerror(LuaValue rhs) {
+ throw new LuaError("attempt to compare " + typename() + " with " + rhs.typename());
+ }
+
+ /**
+ * Get a value in a table including metatag processing using {@link #INDEX}.
+ *
+ * @param key the key to look up, must not be {@link #NIL} or null
+ * @return {@link LuaValue} for that key, or {@link #NIL} if not found and
+ * no metatag
+ * @throws LuaError if {@code this} is not a table, or there is no
+ * {@link #INDEX} metatag, or key is {@link #NIL}
+ * @see #get(int)
+ * @see #get(String)
+ * @see #rawget(LuaValue)
+ */
+ public LuaValue get(LuaValue key) { return gettable(this, key); }
+
+ /**
+ * Get a value in a table including metatag processing using {@link #INDEX}.
+ *
+ * @param key the key to look up
+ * @return {@link LuaValue} for that key, or {@link #NIL} if not found
+ * @throws LuaError if {@code this} is not a table, or there is no
+ * {@link #INDEX} metatag
+ * @see #get(LuaValue)
+ * @see #rawget(int)
+ */
+ public LuaValue get(int key) { return get(LuaInteger.valueOf(key)); }
+
+ /**
+ * Get a value in a table including metatag processing using {@link #INDEX}.
+ *
+ * @param key the key to look up, must not be null
+ * @return {@link LuaValue} for that key, or {@link #NIL} if not found
+ * @throws LuaError if {@code this} is not a table, or there is no
+ * {@link #INDEX} metatag
+ * @see #get(LuaValue)
+ * @see #rawget(String)
+ */
+ public LuaValue get(String key) { return get(valueOf(key)); }
+
+ /**
+ * Set a value in a table without metatag processing using
+ * {@link #NEWINDEX}.
+ *
+ * @param key the key to use, must not be {@link #NIL} or null
+ * @param value the value to use, can be {@link #NIL}, must not be null
+ * @throws LuaError if {@code this} is not a table, or key is {@link #NIL},
+ * or there is no {@link #NEWINDEX} metatag
+ */
+ public void set(LuaValue key, LuaValue value) { settable(this, key, value); }
+
+ /**
+ * Set a value in a table without metatag processing using
+ * {@link #NEWINDEX}.
+ *
+ * @param key the key to use
+ * @param value the value to use, can be {@link #NIL}, must not be null
+ * @throws LuaError if {@code this} is not a table, or there is no
+ * {@link #NEWINDEX} metatag
+ */
+ public void set(int key, LuaValue value) { set(LuaInteger.valueOf(key), value); }
+
+ /**
+ * Set a value in a table without metatag processing using
+ * {@link #NEWINDEX}.
+ *
+ * @param key the key to use
+ * @param value the value to use, must not be null
+ * @throws LuaError if {@code this} is not a table, or there is no
+ * {@link #NEWINDEX} metatag
+ */
+ public void set(int key, String value) { set(key, valueOf(value)); }
+
+ /**
+ * Set a value in a table without metatag processing using
+ * {@link #NEWINDEX}.
+ *
+ * @param key the key to use, must not be {@link #NIL} or null
+ * @param value the value to use, can be {@link #NIL}, must not be null
+ * @throws LuaError if {@code this} is not a table, or there is no
+ * {@link #NEWINDEX} metatag
+ */
+ public void set(String key, LuaValue value) { set(valueOf(key), value); }
+
+ /**
+ * Set a value in a table without metatag processing using
+ * {@link #NEWINDEX}.
+ *
+ * @param key the key to use, must not be null
+ * @param value the value to use
+ * @throws LuaError if {@code this} is not a table, or there is no
+ * {@link #NEWINDEX} metatag
+ */
+ public void set(String key, double value) { set(valueOf(key), valueOf(value)); }
+
+ /**
+ * Set a value in a table without metatag processing using
+ * {@link #NEWINDEX}.
+ *
+ * @param key the key to use, must not be null
+ * @param value the value to use
+ * @throws LuaError if {@code this} is not a table, or there is no
+ * {@link #NEWINDEX} metatag
+ */
+ public void set(String key, int value) { set(valueOf(key), valueOf(value)); }
+
+ /**
+ * Set a value in a table without metatag processing using
+ * {@link #NEWINDEX}.
+ *
+ * @param key the key to use, must not be null
+ * @param value the value to use, must not be null
+ * @throws LuaError if {@code this} is not a table, or there is no
+ * {@link #NEWINDEX} metatag
+ */
+ public void set(String key, String value) { set(valueOf(key), valueOf(value)); }
+
+ /**
+ * Get a value in a table without metatag processing.
+ *
+ * @param key the key to look up, must not be {@link #NIL} or null
+ * @return {@link LuaValue} for that key, or {@link #NIL} if not found
+ * @throws LuaError if {@code this} is not a table, or key is {@link #NIL}
+ */
+ public LuaValue rawget(LuaValue key) { return unimplemented("rawget"); }
+
+ /**
+ * Get a value in a table without metatag processing.
+ *
+ * @param key the key to look up
+ * @return {@link LuaValue} for that key, or {@link #NIL} if not found
+ * @throws LuaError if {@code this} is not a table
+ */
+ public LuaValue rawget(int key) { return rawget(valueOf(key)); }
+
+ /**
+ * Get a value in a table without metatag processing.
+ *
+ * @param key the key to look up, must not be null
+ * @return {@link LuaValue} for that key, or {@link #NIL} if not found
+ * @throws LuaError if {@code this} is not a table
+ */
+ public LuaValue rawget(String key) { return rawget(valueOf(key)); }
+
+ /**
+ * Set a value in a table without metatag processing.
+ *
+ * @param key the key to use, must not be {@link #NIL} or null
+ * @param value the value to use, can be {@link #NIL}, must not be null
+ * @throws LuaError if {@code this} is not a table, or key is {@link #NIL}
+ */
+ public void rawset(LuaValue key, LuaValue value) { unimplemented("rawset"); }
+
+ /**
+ * Set a value in a table without metatag processing.
+ *
+ * @param key the key to use
+ * @param value the value to use, can be {@link #NIL}, must not be null
+ * @throws LuaError if {@code this} is not a table
+ */
+ public void rawset(int key, LuaValue value) { rawset(valueOf(key), value); }
+
+ /**
+ * Set a value in a table without metatag processing.
+ *
+ * @param key the key to use
+ * @param value the value to use, can be {@link #NIL}, must not be null
+ * @throws LuaError if {@code this} is not a table
+ */
+ public void rawset(int key, String value) { rawset(key, valueOf(value)); }
+
+ /**
+ * Set a value in a table without metatag processing.
+ *
+ * @param key the key to use, must not be null
+ * @param value the value to use, can be {@link #NIL}, must not be null
+ * @throws LuaError if {@code this} is not a table
+ */
+ public void rawset(String key, LuaValue value) { rawset(valueOf(key), value); }
+
+ /**
+ * Set a value in a table without metatag processing.
+ *
+ * @param key the key to use, must not be null
+ * @param value the value to use
+ * @throws LuaError if {@code this} is not a table
+ */
+ public void rawset(String key, double value) { rawset(valueOf(key), valueOf(value)); }
+
+ /**
+ * Set a value in a table without metatag processing.
+ *
+ * @param key the key to use, must not be null
+ * @param value the value to use
+ * @throws LuaError if {@code this} is not a table
+ */
+ public void rawset(String key, int value) { rawset(valueOf(key), valueOf(value)); }
+
+ /**
+ * Set a value in a table without metatag processing.
+ *
+ * @param key the key to use, must not be null
+ * @param value the value to use, must not be null
+ * @throws LuaError if {@code this} is not a table
+ */
+ public void rawset(String key, String value) { rawset(valueOf(key), valueOf(value)); }
+
+ /**
+ * Set list values in a table without invoking metatag processing
+ *
+ * Primarily used internally in response to a SETLIST bytecode.
+ *
+ * @param key0 the first key to set in the table
+ * @param values the list of values to set
+ * @throws LuaError if this is not a table.
+ */
+ public void rawsetlist(int key0, Varargs values) {
+ for (int i = 0, n = values.narg(); i < n; i++)
+ rawset(key0+i, values.arg(i+1));
+ }
+
+ /**
+ * Preallocate the array part of a table to be a certain size,
+ *
+ * Primarily used internally in response to a SETLIST bytecode.
+ *
+ * @param i the number of array slots to preallocate in the table.
+ * @throws LuaError if this is not a table.
+ */
+ public void presize(int i) { typerror("table"); }
+
+ /**
+ * Find the next key,value pair if {@code this} is a table, return
+ * {@link #NIL} if there are no more, or throw a {@link LuaError} if not a
+ * table.
+ *
+ * To iterate over all key-value pairs in a table you can use
+ *
+ *
+ * To iterate over integer keys in a table you can use
+ *
+ *
+ * For {@link LuaTable} and {@link LuaUserdata} instances, the metatable
+ * returned is this instance metatable. For all other types, the class
+ * metatable value will be returned.
+ *
+ * @return metatable, or null if it there is none
+ * @see LuaBoolean#s_metatable
+ * @see LuaNumber#s_metatable
+ * @see LuaNil#s_metatable
+ * @see LuaFunction#s_metatable
+ * @see LuaThread#s_metatable
+ */
+ public LuaValue getmetatable() { return null; }
+
+ /**
+ * Set the metatable for this {@link LuaValue}
+ *
+ * For {@link LuaTable} and {@link LuaUserdata} instances, the metatable is
+ * per instance. For all other types, there is one metatable per type that
+ * can be set directly from java
+ *
+ * @param metatable {@link LuaValue} instance to serve as the metatable, or
+ * null to reset it.
+ * @return {@code this} to allow chaining of Java function calls
+ * @see LuaBoolean#s_metatable
+ * @see LuaNumber#s_metatable
+ * @see LuaNil#s_metatable
+ * @see LuaFunction#s_metatable
+ * @see LuaThread#s_metatable
+ */
+ public LuaValue setmetatable(LuaValue metatable) { return argerror("table"); }
+
+ /**
+ * Call {@code this} with 0 arguments, including metatag processing, and
+ * return only the first return value.
+ *
+ * If {@code this} is a {@link LuaFunction}, call it, and return only its
+ * first return value, dropping any others. Otherwise, look for the
+ * {@link #CALL} metatag and call that.
+ *
+ * If the return value is a {@link Varargs}, only the 1st value will be
+ * returned. To get multiple values, use {@link #invoke()} instead.
+ *
+ * To call {@code this} as a method call, use {@link #method(LuaValue)}
+ * instead.
+ *
+ * @return First return value {@code (this())}, or {@link #NIL} if there
+ * were none.
+ * @throws LuaError if not a function and {@link #CALL} is not defined, or
+ * the invoked function throws a {@link LuaError} or the
+ * invoked closure throw a lua {@code error}
+ * @see #call(LuaValue)
+ * @see #call(LuaValue,LuaValue)
+ * @see #call(LuaValue, LuaValue, LuaValue)
+ * @see #invoke()
+ * @see #method(String)
+ * @see #method(LuaValue)
+ */
+ public LuaValue call() { return callmt().call(this); }
+
+ /**
+ * Call {@code this} with 1 argument, including metatag processing, and
+ * return only the first return value.
+ *
+ * If {@code this} is a {@link LuaFunction}, call it, and return only its
+ * first return value, dropping any others. Otherwise, look for the
+ * {@link #CALL} metatag and call that.
+ *
+ * If the return value is a {@link Varargs}, only the 1st value will be
+ * returned. To get multiple values, use {@link #invoke()} instead.
+ *
+ * To call {@code this} as a method call, use {@link #method(LuaValue)}
+ * instead.
+ *
+ * @param arg First argument to supply to the called function
+ * @return First return value {@code (this(arg))}, or {@link #NIL} if there
+ * were none.
+ * @throws LuaError if not a function and {@link #CALL} is not defined, or
+ * the invoked function throws a {@link LuaError} or the
+ * invoked closure throw a lua {@code error}
+ * @see #call()
+ * @see #call(LuaValue,LuaValue)
+ * @see #call(LuaValue, LuaValue, LuaValue)
+ * @see #invoke(Varargs)
+ * @see #method(String,LuaValue)
+ * @see #method(LuaValue,LuaValue)
+ */
+ public LuaValue call(LuaValue arg) { return callmt().call(this, arg); }
+
+ /**
+ * Convenience function which calls a luavalue with a single, string
+ * argument.
+ *
+ * @param arg String argument to the function. This will be converted to a
+ * LuaString.
+ * @return return value of the invocation.
+ * @see #call(LuaValue)
+ */
+ public LuaValue call(String arg) { return call(valueOf(arg)); }
+
+ /**
+ * Call {@code this} with 2 arguments, including metatag processing, and
+ * return only the first return value.
+ *
+ * If {@code this} is a {@link LuaFunction}, call it, and return only its
+ * first return value, dropping any others. Otherwise, look for the
+ * {@link #CALL} metatag and call that.
+ *
+ * If the return value is a {@link Varargs}, only the 1st value will be
+ * returned. To get multiple values, use {@link #invoke()} instead.
+ *
+ * To call {@code this} as a method call, use {@link #method(LuaValue)}
+ * instead.
+ *
+ * @param arg1 First argument to supply to the called function
+ * @param arg2 Second argument to supply to the called function
+ * @return First return value {@code (this(arg1,arg2))}, or {@link #NIL} if
+ * there were none.
+ * @throws LuaError if not a function and {@link #CALL} is not defined, or
+ * the invoked function throws a {@link LuaError} or the
+ * invoked closure throw a lua {@code error}
+ * @see #call()
+ * @see #call(LuaValue)
+ * @see #call(LuaValue, LuaValue, LuaValue)
+ * @see #invoke(LuaValue, Varargs)
+ * @see #method(String,LuaValue,LuaValue)
+ * @see #method(LuaValue,LuaValue,LuaValue)
+ */
+ public LuaValue call(LuaValue arg1, LuaValue arg2) { return callmt().call(this, arg1, arg2); }
+
+ /**
+ * Call {@code this} with 3 arguments, including metatag processing, and
+ * return only the first return value.
+ *
+ * If {@code this} is a {@link LuaFunction}, call it, and return only its
+ * first return value, dropping any others. Otherwise, look for the
+ * {@link #CALL} metatag and call that.
+ *
+ * If the return value is a {@link Varargs}, only the 1st value will be
+ * returned. To get multiple values, use {@link #invoke()} instead.
+ *
+ * To call {@code this} as a method call, use {@link #method(LuaValue)}
+ * instead.
+ *
+ * @param arg1 First argument to supply to the called function
+ * @param arg2 Second argument to supply to the called function
+ * @param arg3 Second argument to supply to the called function
+ * @return First return value {@code (this(arg1,arg2,arg3))}, or
+ * {@link #NIL} if there were none.
+ * @throws LuaError if not a function and {@link #CALL} is not defined, or
+ * the invoked function throws a {@link LuaError} or the
+ * invoked closure throw a lua {@code error}
+ * @see #call()
+ * @see #call(LuaValue)
+ * @see #call(LuaValue, LuaValue)
+ * @see #invoke(LuaValue, LuaValue, Varargs)
+ * @see #invokemethod(String,Varargs)
+ * @see #invokemethod(LuaValue,Varargs)
+ */
+ public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
+ return callmt().invoke(new LuaValue[] { this, arg1, arg2, arg3 }).arg1();
+ }
+
+ /**
+ * Call named method on {@code this} with 0 arguments, including metatag
+ * processing, and return only the first return value.
+ *
+ * Look up {@code this[name]} and if it is a {@link LuaFunction}, call it
+ * inserting {@code this} as an additional first argument. and return only
+ * its first return value, dropping any others. Otherwise, look for the
+ * {@link #CALL} metatag and call that.
+ *
+ * If the return value is a {@link Varargs}, only the 1st value will be
+ * returned. To get multiple values, use {@link #invoke()} instead.
+ *
+ * To call {@code this} as a plain call, use {@link #call()} instead.
+ *
+ * @param name Name of the method to look up for invocation
+ * @return All values returned from {@code this:name()} as a {@link Varargs}
+ * instance
+ * @throws LuaError if not a function and {@link #CALL} is not defined, or
+ * the invoked function throws a {@link LuaError} or the
+ * invoked closure throw a lua {@code error}
+ * @see #call()
+ * @see #invoke()
+ * @see #method(LuaValue)
+ * @see #method(String,LuaValue)
+ * @see #method(String,LuaValue,LuaValue)
+ */
+ public LuaValue method(String name) { return this.get(name).call(this); }
+
+ /**
+ * Call named method on {@code this} with 0 arguments, including metatag
+ * processing, and return only the first return value.
+ *
+ * Look up {@code this[name]} and if it is a {@link LuaFunction}, call it
+ * inserting {@code this} as an additional first argument, and return only
+ * its first return value, dropping any others. Otherwise, look for the
+ * {@link #CALL} metatag and call that.
+ *
+ * If the return value is a {@link Varargs}, only the 1st value will be
+ * returned. To get multiple values, use {@link #invoke()} instead.
+ *
+ * To call {@code this} as a plain call, use {@link #call()} instead.
+ *
+ * @param name Name of the method to look up for invocation
+ * @return All values returned from {@code this:name()} as a {@link Varargs}
+ * instance
+ * @throws LuaError if not a function and {@link #CALL} is not defined, or
+ * the invoked function throws a {@link LuaError} or the
+ * invoked closure throw a lua {@code error}
+ * @see #call()
+ * @see #invoke()
+ * @see #method(String)
+ * @see #method(LuaValue,LuaValue)
+ * @see #method(LuaValue,LuaValue,LuaValue)
+ */
+ public LuaValue method(LuaValue name) { return this.get(name).call(this); }
+
+ /**
+ * Call named method on {@code this} with 1 argument, including metatag
+ * processing, and return only the first return value.
+ *
+ * Look up {@code this[name]} and if it is a {@link LuaFunction}, call it
+ * inserting {@code this} as an additional first argument, and return only
+ * its first return value, dropping any others. Otherwise, look for the
+ * {@link #CALL} metatag and call that.
+ *
+ * If the return value is a {@link Varargs}, only the 1st value will be
+ * returned. To get multiple values, use {@link #invoke()} instead.
+ *
+ * To call {@code this} as a plain call, use {@link #call(LuaValue)}
+ * instead.
+ *
+ * @param name Name of the method to look up for invocation
+ * @param arg Argument to supply to the method
+ * @return All values returned from {@code this:name(arg)} as a
+ * {@link Varargs} instance
+ * @throws LuaError if not a function and {@link #CALL} is not defined, or
+ * the invoked function throws a {@link LuaError} or the
+ * invoked closure throw a lua {@code error}
+ * @see #call(LuaValue)
+ * @see #invoke(Varargs)
+ * @see #method(String)
+ * @see #method(LuaValue)
+ * @see #method(String,LuaValue,LuaValue)
+ */
+ public LuaValue method(String name, LuaValue arg) { return this.get(name).call(this, arg); }
+
+ /**
+ * Call named method on {@code this} with 1 argument, including metatag
+ * processing, and return only the first return value.
+ *
+ * Look up {@code this[name]} and if it is a {@link LuaFunction}, call it
+ * inserting {@code this} as an additional first argument, and return only
+ * its first return value, dropping any others. Otherwise, look for the
+ * {@link #CALL} metatag and call that.
+ *
+ * If the return value is a {@link Varargs}, only the 1st value will be
+ * returned. To get multiple values, use {@link #invoke()} instead.
+ *
+ * To call {@code this} as a plain call, use {@link #call(LuaValue)}
+ * instead.
+ *
+ * @param name Name of the method to look up for invocation
+ * @param arg Argument to supply to the method
+ * @return All values returned from {@code this:name(arg)} as a
+ * {@link Varargs} instance
+ * @throws LuaError if not a function and {@link #CALL} is not defined, or
+ * the invoked function throws a {@link LuaError} or the
+ * invoked closure throw a lua {@code error}
+ * @see #call(LuaValue)
+ * @see #invoke(Varargs)
+ * @see #method(String,LuaValue)
+ * @see #method(LuaValue)
+ * @see #method(LuaValue,LuaValue,LuaValue)
+ */
+ public LuaValue method(LuaValue name, LuaValue arg) { return this.get(name).call(this, arg); }
+
+ /**
+ * Call named method on {@code this} with 2 arguments, including metatag
+ * processing, and return only the first return value.
+ *
+ * Look up {@code this[name]} and if it is a {@link LuaFunction}, call it
+ * inserting {@code this} as an additional first argument, and return only
+ * its first return value, dropping any others. Otherwise, look for the
+ * {@link #CALL} metatag and call that.
+ *
+ * If the return value is a {@link Varargs}, only the 1st value will be
+ * returned. To get multiple values, use {@link #invoke()} instead.
+ *
+ * To call {@code this} as a plain call, use
+ * {@link #call(LuaValue,LuaValue)} instead.
+ *
+ * @param name Name of the method to look up for invocation
+ * @param arg1 First argument to supply to the method
+ * @param arg2 Second argument to supply to the method
+ * @return All values returned from {@code this:name(arg1,arg2)} as a
+ * {@link Varargs} instance
+ * @throws LuaError if not a function and {@link #CALL} is not defined, or
+ * the invoked function throws a {@link LuaError} or the
+ * invoked closure throw a lua {@code error}
+ * @see #call(LuaValue,LuaValue)
+ * @see #invoke(LuaValue,Varargs)
+ * @see #method(String,LuaValue)
+ * @see #method(LuaValue,LuaValue,LuaValue)
+ */
+ public LuaValue method(String name, LuaValue arg1, LuaValue arg2) {
+ return this.get(name).call(this, arg1, arg2);
+ }
+
+ /**
+ * Call named method on {@code this} with 2 arguments, including metatag
+ * processing, and return only the first return value.
+ *
+ * Look up {@code this[name]} and if it is a {@link LuaFunction}, call it
+ * inserting {@code this} as an additional first argument, and return only
+ * its first return value, dropping any others. Otherwise, look for the
+ * {@link #CALL} metatag and call that.
+ *
+ * If the return value is a {@link Varargs}, only the 1st value will be
+ * returned. To get multiple values, use {@link #invoke()} instead.
+ *
+ * To call {@code this} as a plain call, use
+ * {@link #call(LuaValue,LuaValue)} instead.
+ *
+ * @param name Name of the method to look up for invocation
+ * @param arg1 First argument to supply to the method
+ * @param arg2 Second argument to supply to the method
+ * @return All values returned from {@code this:name(arg1,arg2)} as a
+ * {@link Varargs} instance
+ * @throws LuaError if not a function and {@link #CALL} is not defined, or
+ * the invoked function throws a {@link LuaError} or the
+ * invoked closure throw a lua {@code error}
+ * @see #call(LuaValue,LuaValue)
+ * @see #invoke(LuaValue,Varargs)
+ * @see #method(LuaValue,LuaValue)
+ * @see #method(String,LuaValue,LuaValue)
+ */
+ public LuaValue method(LuaValue name, LuaValue arg1, LuaValue arg2) {
+ return this.get(name).call(this, arg1, arg2);
+ }
+
+ /**
+ * Call {@code this} with 0 arguments, including metatag processing, and
+ * retain all return values in a {@link Varargs}.
+ *
+ * If {@code this} is a {@link LuaFunction}, call it, and return all values.
+ * Otherwise, look for the {@link #CALL} metatag and call that.
+ *
+ * To get a particular return value, us {@link Varargs#arg(int)}
+ *
+ * To call {@code this} as a method call, use
+ * {@link #invokemethod(LuaValue)} instead.
+ *
+ * @return All return values as a {@link Varargs} instance.
+ * @throws LuaError if not a function and {@link #CALL} is not defined, or
+ * the invoked function throws a {@link LuaError} or the
+ * invoked closure throw a lua {@code error}
+ * @see #call()
+ * @see #invoke(Varargs)
+ * @see #invokemethod(String)
+ * @see #invokemethod(LuaValue)
+ */
+ public Varargs invoke() { return invoke(NONE); }
+
+ /**
+ * Call {@code this} with variable arguments, including metatag processing,
+ * and retain all return values in a {@link Varargs}.
+ *
+ * If {@code this} is a {@link LuaFunction}, call it, and return all values.
+ * Otherwise, look for the {@link #CALL} metatag and call that.
+ *
+ * To get a particular return value, us {@link Varargs#arg(int)}
+ *
+ * To call {@code this} as a method call, use
+ * {@link #invokemethod(LuaValue)} instead.
+ *
+ * @param args Varargs containing the arguments to supply to the called
+ * function
+ * @return All return values as a {@link Varargs} instance.
+ * @throws LuaError if not a function and {@link #CALL} is not defined, or
+ * the invoked function throws a {@link LuaError} or the
+ * invoked closure throw a lua {@code error}
+ * @see #varargsOf(LuaValue[])
+ * @see #call(LuaValue)
+ * @see #invoke()
+ * @see #invoke(LuaValue,Varargs)
+ * @see #invokemethod(String,Varargs)
+ * @see #invokemethod(LuaValue,Varargs)
+ */
+ public Varargs invoke(Varargs args) { return callmt().invoke(this, args); }
+
+ /**
+ * Call {@code this} with variable arguments, including metatag processing,
+ * and retain all return values in a {@link Varargs}.
+ *
+ * If {@code this} is a {@link LuaFunction}, call it, and return all values.
+ * Otherwise, look for the {@link #CALL} metatag and call that.
+ *
+ * To get a particular return value, us {@link Varargs#arg(int)}
+ *
+ * To call {@code this} as a method call, use
+ * {@link #invokemethod(LuaValue,Varargs)} instead.
+ *
+ * @param arg The first argument to supply to the called function
+ * @param varargs Varargs containing the remaining arguments to supply to
+ * the called function
+ * @return All return values as a {@link Varargs} instance.
+ * @throws LuaError if not a function and {@link #CALL} is not defined, or
+ * the invoked function throws a {@link LuaError} or the
+ * invoked closure throw a lua {@code error}
+ * @see #varargsOf(LuaValue[])
+ * @see #call(LuaValue,LuaValue)
+ * @see #invoke(LuaValue,Varargs)
+ * @see #invokemethod(String,Varargs)
+ * @see #invokemethod(LuaValue,Varargs)
+ */
+ public Varargs invoke(LuaValue arg, Varargs varargs) { return invoke(varargsOf(arg, varargs)); }
+
+ /**
+ * Call {@code this} with variable arguments, including metatag processing,
+ * and retain all return values in a {@link Varargs}.
+ *
+ * If {@code this} is a {@link LuaFunction}, call it, and return all values.
+ * Otherwise, look for the {@link #CALL} metatag and call that.
+ *
+ * To get a particular return value, us {@link Varargs#arg(int)}
+ *
+ * To call {@code this} as a method call, use
+ * {@link #invokemethod(LuaValue,Varargs)} instead.
+ *
+ * @param arg1 The first argument to supply to the called function
+ * @param arg2 The second argument to supply to the called function
+ * @param varargs Varargs containing the remaining arguments to supply to
+ * the called function
+ * @return All return values as a {@link Varargs} instance.
+ * @throws LuaError if not a function and {@link #CALL} is not defined, or
+ * the invoked function throws a {@link LuaError} or the
+ * invoked closure throw a lua {@code error}
+ * @see #varargsOf(LuaValue[])
+ * @see #call(LuaValue,LuaValue,LuaValue)
+ * @see #invoke(LuaValue,LuaValue,Varargs)
+ * @see #invokemethod(String,Varargs)
+ * @see #invokemethod(LuaValue,Varargs)
+ */
+ public Varargs invoke(LuaValue arg1, LuaValue arg2, Varargs varargs) {
+ return invoke(varargsOf(arg1, arg2, varargs));
+ }
+
+ /**
+ * Call {@code this} with variable arguments, including metatag processing,
+ * and retain all return values in a {@link Varargs}.
+ *
+ * If {@code this} is a {@link LuaFunction}, call it, and return all values.
+ * Otherwise, look for the {@link #CALL} metatag and call that.
+ *
+ * To get a particular return value, us {@link Varargs#arg(int)}
+ *
+ * To call {@code this} as a method call, use
+ * {@link #invokemethod(LuaValue,Varargs)} instead.
+ *
+ * @param args Array of arguments to supply to the called function
+ * @return All return values as a {@link Varargs} instance.
+ * @throws LuaError if not a function and {@link #CALL} is not defined, or
+ * the invoked function throws a {@link LuaError} or the
+ * invoked closure throw a lua {@code error}
+ * @see #varargsOf(LuaValue[])
+ * @see #call(LuaValue,LuaValue,LuaValue)
+ * @see #invoke(LuaValue,LuaValue,Varargs)
+ * @see #invokemethod(String,LuaValue[])
+ * @see #invokemethod(LuaValue,LuaValue[])
+ */
+ public Varargs invoke(LuaValue[] args) { return invoke(varargsOf(args)); }
+
+ /**
+ * Call {@code this} with variable arguments, including metatag processing,
+ * and retain all return values in a {@link Varargs}.
+ *
+ * If {@code this} is a {@link LuaFunction}, call it, and return all values.
+ * Otherwise, look for the {@link #CALL} metatag and call that.
+ *
+ * To get a particular return value, us {@link Varargs#arg(int)}
+ *
+ * To call {@code this} as a method call, use
+ * {@link #invokemethod(LuaValue,Varargs)} instead.
+ *
+ * @param args Array of arguments to supply to the called function
+ * @param varargs Varargs containing additional arguments to supply to the
+ * called function
+ * @return All return values as a {@link Varargs} instance.
+ * @throws LuaError if not a function and {@link #CALL} is not defined, or
+ * the invoked function throws a {@link LuaError} or the
+ * invoked closure throw a lua {@code error}
+ * @see #varargsOf(LuaValue[])
+ * @see #call(LuaValue,LuaValue,LuaValue)
+ * @see #invoke(LuaValue,LuaValue,Varargs)
+ * @see #invokemethod(String,LuaValue[])
+ * @see #invokemethod(LuaValue,LuaValue[])
+ * @see #invokemethod(String,Varargs)
+ * @see #invokemethod(LuaValue,Varargs)
+ */
+ public Varargs invoke(LuaValue[] args, Varargs varargs) { return invoke(varargsOf(args, varargs)); }
+
+ /**
+ * Call named method on {@code this} with 0 arguments, including metatag
+ * processing, and retain all return values in a {@link Varargs}.
+ *
+ * Look up {@code this[name]} and if it is a {@link LuaFunction}, call it
+ * inserting {@code this} as an additional first argument, and return all
+ * return values as a {@link Varargs} instance. Otherwise, look for the
+ * {@link #CALL} metatag and call that.
+ *
+ * To get a particular return value, us {@link Varargs#arg(int)}
+ *
+ * To call {@code this} as a plain call, use {@link #invoke()} instead.
+ *
+ * @param name Name of the method to look up for invocation
+ * @return All values returned from {@code this:name()} as a {@link Varargs}
+ * instance
+ * @throws LuaError if not a function and {@link #CALL} is not defined, or
+ * the invoked function throws a {@link LuaError} or the
+ * invoked closure throw a lua {@code error}
+ * @see #call()
+ * @see #invoke()
+ * @see #method(String)
+ * @see #invokemethod(LuaValue)
+ * @see #invokemethod(String, LuaValue[])
+ * @see #invokemethod(String, Varargs)
+ * @see #invokemethod(LuaValue, LuaValue[])
+ * @see #invokemethod(LuaValue, Varargs)
+ */
+ public Varargs invokemethod(String name) { return get(name).invoke(this); }
+
+ /**
+ * Call named method on {@code this} with 0 arguments, including metatag
+ * processing, and retain all return values in a {@link Varargs}.
+ *
+ * Look up {@code this[name]} and if it is a {@link LuaFunction}, call it
+ * inserting {@code this} as an additional first argument, and return all
+ * return values as a {@link Varargs} instance. Otherwise, look for the
+ * {@link #CALL} metatag and call that.
+ *
+ * To get a particular return value, us {@link Varargs#arg(int)}
+ *
+ * To call {@code this} as a plain call, use {@link #invoke()} instead.
+ *
+ * @param name Name of the method to look up for invocation
+ * @return All values returned from {@code this:name()} as a {@link Varargs}
+ * instance
+ * @throws LuaError if not a function and {@link #CALL} is not defined, or
+ * the invoked function throws a {@link LuaError} or the
+ * invoked closure throw a lua {@code error}
+ * @see #call()
+ * @see #invoke()
+ * @see #method(LuaValue)
+ * @see #invokemethod(String)
+ * @see #invokemethod(String, LuaValue[])
+ * @see #invokemethod(String, Varargs)
+ * @see #invokemethod(LuaValue, LuaValue[])
+ * @see #invokemethod(LuaValue, Varargs)
+ */
+ public Varargs invokemethod(LuaValue name) { return get(name).invoke(this); }
+
+ /**
+ * Call named method on {@code this} with 1 argument, including metatag
+ * processing, and retain all return values in a {@link Varargs}.
+ *
+ * Look up {@code this[name]} and if it is a {@link LuaFunction}, call it
+ * inserting {@code this} as an additional first argument, and return all
+ * return values as a {@link Varargs} instance. Otherwise, look for the
+ * {@link #CALL} metatag and call that.
+ *
+ * To get a particular return value, us {@link Varargs#arg(int)}
+ *
+ * To call {@code this} as a plain call, use {@link #invoke(Varargs)}
+ * instead.
+ *
+ * @param name Name of the method to look up for invocation
+ * @param args {@link Varargs} containing arguments to supply to the called
+ * function after {@code this}
+ * @return All values returned from {@code this:name(args)} as a
+ * {@link Varargs} instance
+ * @throws LuaError if not a function and {@link #CALL} is not defined, or
+ * the invoked function throws a {@link LuaError} or the
+ * invoked closure throw a lua {@code error}
+ * @see #call()
+ * @see #invoke(Varargs)
+ * @see #method(String)
+ * @see #invokemethod(String)
+ * @see #invokemethod(LuaValue)
+ * @see #invokemethod(String, LuaValue[])
+ * @see #invokemethod(LuaValue, LuaValue[])
+ * @see #invokemethod(LuaValue, Varargs)
+ */
+ public Varargs invokemethod(String name, Varargs args) { return get(name).invoke(varargsOf(this, args)); }
+
+ /**
+ * Call named method on {@code this} with variable arguments, including
+ * metatag processing, and retain all return values in a {@link Varargs}.
+ *
+ * Look up {@code this[name]} and if it is a {@link LuaFunction}, call it
+ * inserting {@code this} as an additional first argument, and return all
+ * return values as a {@link Varargs} instance. Otherwise, look for the
+ * {@link #CALL} metatag and call that.
+ *
+ * To get a particular return value, us {@link Varargs#arg(int)}
+ *
+ * To call {@code this} as a plain call, use {@link #invoke(Varargs)}
+ * instead.
+ *
+ * @param name Name of the method to look up for invocation
+ * @param args {@link Varargs} containing arguments to supply to the called
+ * function after {@code this}
+ * @return All values returned from {@code this:name(args)} as a
+ * {@link Varargs} instance
+ * @throws LuaError if not a function and {@link #CALL} is not defined, or
+ * the invoked function throws a {@link LuaError} or the
+ * invoked closure throw a lua {@code error}
+ * @see #call()
+ * @see #invoke(Varargs)
+ * @see #method(String)
+ * @see #invokemethod(String)
+ * @see #invokemethod(LuaValue)
+ * @see #invokemethod(String, LuaValue[])
+ * @see #invokemethod(String, Varargs)
+ * @see #invokemethod(LuaValue, LuaValue[])
+ */
+ public Varargs invokemethod(LuaValue name, Varargs args) { return get(name).invoke(varargsOf(this, args)); }
+
+ /**
+ * Call named method on {@code this} with 1 argument, including metatag
+ * processing, and retain all return values in a {@link Varargs}.
+ *
+ * Look up {@code this[name]} and if it is a {@link LuaFunction}, call it
+ * inserting {@code this} as an additional first argument, and return all
+ * return values as a {@link Varargs} instance. Otherwise, look for the
+ * {@link #CALL} metatag and call that.
+ *
+ * To get a particular return value, us {@link Varargs#arg(int)}
+ *
+ * To call {@code this} as a plain call, use {@link #invoke(Varargs)}
+ * instead.
+ *
+ * @param name Name of the method to look up for invocation
+ * @param args Array of {@link LuaValue} containing arguments to supply to
+ * the called function after {@code this}
+ * @return All values returned from {@code this:name(args)} as a
+ * {@link Varargs} instance
+ * @throws LuaError if not a function and {@link #CALL} is not defined, or
+ * the invoked function throws a {@link LuaError} or the
+ * invoked closure throw a lua {@code error}
+ * @see #call()
+ * @see #invoke(Varargs)
+ * @see #method(String)
+ * @see #invokemethod(String)
+ * @see #invokemethod(LuaValue)
+ * @see #invokemethod(String, Varargs)
+ * @see #invokemethod(LuaValue, LuaValue[])
+ * @see #invokemethod(LuaValue, Varargs)
+ * @see LuaValue#varargsOf(LuaValue[])
+ */
+ public Varargs invokemethod(String name, LuaValue[] args) {
+ return get(name).invoke(varargsOf(this, varargsOf(args)));
+ }
+
+ /**
+ * Call named method on {@code this} with variable arguments, including
+ * metatag processing, and retain all return values in a {@link Varargs}.
+ *
+ * Look up {@code this[name]} and if it is a {@link LuaFunction}, call it
+ * inserting {@code this} as an additional first argument, and return all
+ * return values as a {@link Varargs} instance. Otherwise, look for the
+ * {@link #CALL} metatag and call that.
+ *
+ * To get a particular return value, us {@link Varargs#arg(int)}
+ *
+ * To call {@code this} as a plain call, use {@link #invoke(Varargs)}
+ * instead.
+ *
+ * @param name Name of the method to look up for invocation
+ * @param args Array of {@link LuaValue} containing arguments to supply to
+ * the called function after {@code this}
+ * @return All values returned from {@code this:name(args)} as a
+ * {@link Varargs} instance
+ * @throws LuaError if not a function and {@link #CALL} is not defined, or
+ * the invoked function throws a {@link LuaError} or the
+ * invoked closure throw a lua {@code error}
+ * @see #call()
+ * @see #invoke(Varargs)
+ * @see #method(String)
+ * @see #invokemethod(String)
+ * @see #invokemethod(LuaValue)
+ * @see #invokemethod(String, LuaValue[])
+ * @see #invokemethod(String, Varargs)
+ * @see #invokemethod(LuaValue, Varargs)
+ * @see LuaValue#varargsOf(LuaValue[])
+ */
+ public Varargs invokemethod(LuaValue name, LuaValue[] args) {
+ return get(name).invoke(varargsOf(this, varargsOf(args)));
+ }
+
+ /**
+ * Get the metatag value for the {@link #CALL} metatag, if it exists.
+ *
+ * @return {@link LuaValue} value if metatag is defined
+ * @throws LuaError if {@link #CALL} metatag is not defined.
+ */
+ protected LuaValue callmt() {
+ return checkmetatag(CALL, "attempt to call ");
+ }
+
+ /**
+ * Unary not: return inverse boolean value {@code (~this)} as defined by lua
+ * not operator
+ *
+ * @return {@link #TRUE} if {@link #NIL} or {@link #FALSE}, otherwise
+ * {@link #FALSE}
+ */
+ public LuaValue not() { return FALSE; }
+
+ /**
+ * Unary minus: return negative value {@code (-this)} as defined by lua
+ * unary minus operator
+ *
+ * @return boolean inverse as {@link LuaBoolean} if boolean or nil, numeric
+ * inverse as {@link LuaNumber} if numeric, or metatag processing
+ * result if {@link #UNM} metatag is defined
+ * @throws LuaError if {@code this} is not a table or string, and has no
+ * {@link #UNM} metatag
+ */
+ public LuaValue neg() { return checkmetatag(UNM, "attempt to perform arithmetic on ").call(this); }
+
+ /**
+ * Length operator: return lua length of object {@code (#this)} including
+ * metatag processing as java int
+ *
+ * @return length as defined by the lua # operator or metatag processing
+ * result
+ * @throws LuaError if {@code this} is not a table or string, and has no
+ * {@link #LEN} metatag
+ */
+ public LuaValue len() { return checkmetatag(LEN, "attempt to get length of ").call(this); }
+
+ /**
+ * Length operator: return lua length of object {@code (#this)} including
+ * metatag processing as java int
+ *
+ * @return length as defined by the lua # operator or metatag processing
+ * result converted to java int using {@link #toint()}
+ * @throws LuaError if {@code this} is not a table or string, and has no
+ * {@link #LEN} metatag
+ */
+ public int length() { return len().toint(); }
+
+ /**
+ * Get raw length of table or string without metatag processing.
+ *
+ * @return the length of the table or string.
+ * @throws LuaError if {@code this} is not a table or string.
+ */
+ public int rawlen() { typerror("table or string"); return 0; }
+
+ // object equality, used for key comparison
+ @Override
+ public boolean equals(Object obj) { return this == obj; }
+
+ /**
+ * Equals: Perform equality comparison with another value including metatag
+ * processing using {@link #EQ}.
+ *
+ * @param val The value to compare with.
+ * @return {@link #TRUE} if values are comparable and {@code (this == rhs)},
+ * {@link #FALSE} if comparable but not equal, {@link LuaValue} if
+ * metatag processing occurs.
+ * @see #eq_b(LuaValue)
+ * @see #raweq(LuaValue)
+ * @see #neq(LuaValue)
+ * @see #eqmtcall(LuaValue, LuaValue, LuaValue, LuaValue)
+ * @see #EQ
+ */
+ public LuaValue eq(LuaValue val) { return eq_b(val)? TRUE: FALSE; }
+
+ /**
+ * Equals: Perform equality comparison with another value including metatag
+ * processing using {@link #EQ}, and return java boolean
+ *
+ * @param val The value to compare with.
+ * @return true if values are comparable and {@code (this == rhs)}, false if
+ * comparable but not equal, result converted to java boolean if
+ * metatag processing occurs.
+ * @see #eq(LuaValue)
+ * @see #raweq(LuaValue)
+ * @see #neq_b(LuaValue)
+ * @see #eqmtcall(LuaValue, LuaValue, LuaValue, LuaValue)
+ * @see #EQ
+ */
+ public boolean eq_b(LuaValue val) { return this == val; }
+
+ /**
+ * Notquals: Perform inequality comparison with another value including
+ * metatag processing using {@link #EQ}.
+ *
+ * @param val The value to compare with.
+ * @return {@link #TRUE} if values are comparable and {@code (this != rhs)},
+ * {@link #FALSE} if comparable but equal, inverse of
+ * {@link LuaValue} converted to {@link LuaBoolean} if metatag
+ * processing occurs.
+ * @see #eq(LuaValue)
+ * @see #raweq(LuaValue)
+ * @see #eqmtcall(LuaValue, LuaValue, LuaValue, LuaValue)
+ * @see #EQ
+ */
+ public LuaValue neq(LuaValue val) { return eq_b(val)? FALSE: TRUE; }
+
+ /**
+ * Notquals: Perform inequality comparison with another value including
+ * metatag processing using {@link #EQ}.
+ *
+ * @param val The value to compare with.
+ * @return true if values are comparable and {@code (this != rhs)}, false if
+ * comparable but equal, inverse of result converted to boolean if
+ * metatag processing occurs.
+ * @see #eq_b(LuaValue)
+ * @see #raweq(LuaValue)
+ * @see #eqmtcall(LuaValue, LuaValue, LuaValue, LuaValue)
+ * @see #EQ
+ */
+ public boolean neq_b(LuaValue val) { return !eq_b(val); }
+
+ /**
+ * Equals: Perform direct equality comparison with another value without
+ * metatag processing.
+ *
+ * @param val The value to compare with.
+ * @return true if {@code (this == rhs)}, false otherwise
+ * @see #eq(LuaValue)
+ * @see #raweq(LuaUserdata)
+ * @see #raweq(LuaString)
+ * @see #raweq(double)
+ * @see #raweq(int)
+ * @see #EQ
+ */
+ public boolean raweq(LuaValue val) { return this == val; }
+
+ /**
+ * Equals: Perform direct equality comparison with a {@link LuaUserdata}
+ * value without metatag processing.
+ *
+ * @param val The {@link LuaUserdata} to compare with.
+ * @return true if {@code this} is userdata and their metatables are the
+ * same using == and their instances are equal using
+ * {@link #equals(Object)}, otherwise false
+ * @see #eq(LuaValue)
+ * @see #raweq(LuaValue)
+ */
+ public boolean raweq(LuaUserdata val) { return false; }
+
+ /**
+ * Equals: Perform direct equality comparison with a {@link LuaString} value
+ * without metatag processing.
+ *
+ * @param val The {@link LuaString} to compare with.
+ * @return true if {@code this} is a {@link LuaString} and their byte
+ * sequences match, otherwise false
+ */
+ public boolean raweq(LuaString val) { return false; }
+
+ /**
+ * Equals: Perform direct equality comparison with a double value without
+ * metatag processing.
+ *
+ * @param val The double value to compare with.
+ * @return true if {@code this} is a {@link LuaNumber} whose value equals
+ * val, otherwise false
+ */
+ public boolean raweq(double val) { return false; }
+
+ /**
+ * Equals: Perform direct equality comparison with a int value without
+ * metatag processing.
+ *
+ * @param val The double value to compare with.
+ * @return true if {@code this} is a {@link LuaNumber} whose value equals
+ * val, otherwise false
+ */
+ public boolean raweq(int val) { return false; }
+
+ /**
+ * Perform equality testing metatag processing
+ *
+ * @param lhs left-hand-side of equality expression
+ * @param lhsmt metatag value for left-hand-side
+ * @param rhs right-hand-side of equality expression
+ * @param rhsmt metatag value for right-hand-side
+ * @return true if metatag processing result is not {@link #NIL} or
+ * {@link #FALSE}
+ * @throws LuaError if metatag was not defined for either operand
+ * @see #equals(Object)
+ * @see #eq(LuaValue)
+ * @see #raweq(LuaValue)
+ * @see #EQ
+ */
+ public static final boolean eqmtcall(LuaValue lhs, LuaValue lhsmt, LuaValue rhs, LuaValue rhsmt) {
+ LuaValue h = lhsmt.rawget(EQ);
+ return h.isnil() || h != rhsmt.rawget(EQ)? false: h.call(lhs, rhs).toboolean();
+ }
+
+ /**
+ * Add: Perform numeric add operation with another value including metatag
+ * processing.
+ *
+ * Each operand must derive from {@link LuaNumber} or derive from
+ * {@link LuaString} and be convertible to a number
+ *
+ * @param rhs The right-hand-side value to perform the add with
+ * @return value of {@code (this + rhs)} if both are numeric, or
+ * {@link LuaValue} if metatag processing occurs
+ * @throws LuaError if either operand is not a number or string convertible
+ * to number, and neither has the {@link #ADD} metatag
+ * defined
+ * @see #arithmt(LuaValue, LuaValue)
+ */
+ public LuaValue add(LuaValue rhs) { return arithmt(ADD, rhs); }
+
+ /**
+ * Add: Perform numeric add operation with another value of double type with
+ * metatag processing
+ *
+ * {@code this} must derive from {@link LuaNumber} or derive from
+ * {@link LuaString} and be convertible to a number
+ *
+ * @param rhs The right-hand-side value to perform the add with
+ * @return value of {@code (this + rhs)} if this is numeric
+ * @throws LuaError if {@code this} is not a number or string convertible to
+ * number
+ * @see #add(LuaValue)
+ */
+ public LuaValue add(double rhs) { return arithmtwith(ADD, rhs); }
+
+ /**
+ * Add: Perform numeric add operation with another value of int type with
+ * metatag processing
+ *
+ * {@code this} must derive from {@link LuaNumber} or derive from
+ * {@link LuaString} and be convertible to a number
+ *
+ * @param rhs The right-hand-side value to perform the add with
+ * @return value of {@code (this + rhs)} if this is numeric
+ * @throws LuaError if {@code this} is not a number or string convertible to
+ * number
+ * @see #add(LuaValue)
+ */
+ public LuaValue add(int rhs) { return add((double) rhs); }
+
+ /**
+ * Subtract: Perform numeric subtract operation with another value of
+ * unknown type, including metatag processing.
+ *
+ * Each operand must derive from {@link LuaNumber} or derive from
+ * {@link LuaString} and be convertible to a number
+ *
+ * @param rhs The right-hand-side value to perform the subtract with
+ * @return value of {@code (this - rhs)} if both are numeric, or
+ * {@link LuaValue} if metatag processing occurs
+ * @throws LuaError if either operand is not a number or string convertible
+ * to number, and neither has the {@link #SUB} metatag
+ * defined
+ * @see #arithmt(LuaValue, LuaValue)
+ */
+ public LuaValue sub(LuaValue rhs) { return arithmt(SUB, rhs); }
+
+ /**
+ * Subtract: Perform numeric subtract operation with another value of double
+ * type with metatag processing
+ *
+ * {@code this} must derive from {@link LuaNumber} or derive from
+ * {@link LuaString} and be convertible to a number
+ *
+ * @param rhs The right-hand-side value to perform the subtract with
+ * @return value of {@code (this - rhs)} if this is numeric
+ * @throws LuaError if {@code this} is not a number or string convertible to
+ * number
+ * @see #sub(LuaValue)
+ */
+ public LuaValue sub(double rhs) { return aritherror("sub"); }
+
+ /**
+ * Subtract: Perform numeric subtract operation with another value of int
+ * type with metatag processing
+ *
+ * {@code this} must derive from {@link LuaNumber} or derive from
+ * {@link LuaString} and be convertible to a number
+ *
+ * @param rhs The right-hand-side value to perform the subtract with
+ * @return value of {@code (this - rhs)} if this is numeric
+ * @throws LuaError if {@code this} is not a number or string convertible to
+ * number
+ * @see #sub(LuaValue)
+ */
+ public LuaValue sub(int rhs) { return aritherror("sub"); }
+
+ /**
+ * Reverse-subtract: Perform numeric subtract operation from an int value
+ * with metatag processing
+ *
+ * {@code this} must derive from {@link LuaNumber} or derive from
+ * {@link LuaString} and be convertible to a number
+ *
+ * @param lhs The left-hand-side value from which to perform the subtraction
+ * @return value of {@code (lhs - this)} if this is numeric
+ * @throws LuaError if {@code this} is not a number or string convertible to
+ * number
+ * @see #sub(LuaValue)
+ * @see #sub(double)
+ * @see #sub(int)
+ */
+ public LuaValue subFrom(double lhs) { return arithmtwith(SUB, lhs); }
+
+ /**
+ * Reverse-subtract: Perform numeric subtract operation from a double value
+ * without metatag processing
+ *
+ * {@code this} must derive from {@link LuaNumber} or derive from
+ * {@link LuaString} and be convertible to a number
+ *
+ * For metatag processing {@link #sub(LuaValue)} must be used
+ *
+ * @param lhs The left-hand-side value from which to perform the subtraction
+ * @return value of {@code (lhs - this)} if this is numeric
+ * @throws LuaError if {@code this} is not a number or string convertible to
+ * number
+ * @see #sub(LuaValue)
+ * @see #sub(double)
+ * @see #sub(int)
+ */
+ public LuaValue subFrom(int lhs) { return subFrom((double) lhs); }
+
+ /**
+ * Multiply: Perform numeric multiply operation with another value of
+ * unknown type, including metatag processing.
+ *
+ * Each operand must derive from {@link LuaNumber} or derive from
+ * {@link LuaString} and be convertible to a number
+ *
+ * @param rhs The right-hand-side value to perform the multiply with
+ * @return value of {@code (this * rhs)} if both are numeric, or
+ * {@link LuaValue} if metatag processing occurs
+ * @throws LuaError if either operand is not a number or string convertible
+ * to number, and neither has the {@link #MUL} metatag
+ * defined
+ * @see #arithmt(LuaValue, LuaValue)
+ */
+ public LuaValue mul(LuaValue rhs) { return arithmt(MUL, rhs); }
+
+ /**
+ * Multiply: Perform numeric multiply operation with another value of double
+ * type with metatag processing
+ *
+ * {@code this} must derive from {@link LuaNumber} or derive from
+ * {@link LuaString} and be convertible to a number
+ *
+ * @param rhs The right-hand-side value to perform the multiply with
+ * @return value of {@code (this * rhs)} if this is numeric
+ * @throws LuaError if {@code this} is not a number or string convertible to
+ * number
+ * @see #mul(LuaValue)
+ */
+ public LuaValue mul(double rhs) { return arithmtwith(MUL, rhs); }
+
+ /**
+ * Multiply: Perform numeric multiply operation with another value of int
+ * type with metatag processing
+ *
+ * {@code this} must derive from {@link LuaNumber} or derive from
+ * {@link LuaString} and be convertible to a number
+ *
+ * @param rhs The right-hand-side value to perform the multiply with
+ * @return value of {@code (this * rhs)} if this is numeric
+ * @throws LuaError if {@code this} is not a number or string convertible to
+ * number
+ * @see #mul(LuaValue)
+ */
+ public LuaValue mul(int rhs) { return mul((double) rhs); }
+
+ /**
+ * Raise to power: Raise this value to a power including metatag processing.
+ *
+ * Each operand must derive from {@link LuaNumber} or derive from
+ * {@link LuaString} and be convertible to a number
+ *
+ * @param rhs The power to raise this value to
+ * @return value of {@code (this ^ rhs)} if both are numeric, or
+ * {@link LuaValue} if metatag processing occurs
+ * @throws LuaError if either operand is not a number or string convertible
+ * to number, and neither has the {@link #POW} metatag
+ * defined
+ * @see #arithmt(LuaValue, LuaValue)
+ */
+ public LuaValue pow(LuaValue rhs) { return arithmt(POW, rhs); }
+
+ /**
+ * Raise to power: Raise this value to a power of double type with metatag
+ * processing
+ *
+ * {@code this} must derive from {@link LuaNumber} or derive from
+ * {@link LuaString} and be convertible to a number
+ *
+ * @param rhs The power to raise this value to
+ * @return value of {@code (this ^ rhs)} if this is numeric
+ * @throws LuaError if {@code this} is not a number or string convertible to
+ * number
+ * @see #pow(LuaValue)
+ */
+ public LuaValue pow(double rhs) { return aritherror("pow"); }
+
+ /**
+ * Raise to power: Raise this value to a power of int type with metatag
+ * processing
+ *
+ * {@code this} must derive from {@link LuaNumber} or derive from
+ * {@link LuaString} and be convertible to a number
+ *
+ * @param rhs The power to raise this value to
+ * @return value of {@code (this ^ rhs)} if this is numeric
+ * @throws LuaError if {@code this} is not a number or string convertible to
+ * number
+ * @see #pow(LuaValue)
+ */
+ public LuaValue pow(int rhs) { return aritherror("pow"); }
+
+ /**
+ * Reverse-raise to power: Raise another value of double type to this power
+ * with metatag processing
+ *
+ * {@code this} must derive from {@link LuaNumber} or derive from
+ * {@link LuaString} and be convertible to a number
+ *
+ * @param lhs The left-hand-side value which will be raised to this power
+ * @return value of {@code (lhs ^ this)} if this is numeric
+ * @throws LuaError if {@code this} is not a number or string convertible to
+ * number
+ * @see #pow(LuaValue)
+ * @see #pow(double)
+ * @see #pow(int)
+ */
+ public LuaValue powWith(double lhs) { return arithmtwith(POW, lhs); }
+
+ /**
+ * Reverse-raise to power: Raise another value of double type to this power
+ * with metatag processing
+ *
+ * {@code this} must derive from {@link LuaNumber} or derive from
+ * {@link LuaString} and be convertible to a number
+ *
+ * @param lhs The left-hand-side value which will be raised to this power
+ * @return value of {@code (lhs ^ this)} if this is numeric
+ * @throws LuaError if {@code this} is not a number or string convertible to
+ * number
+ * @see #pow(LuaValue)
+ * @see #pow(double)
+ * @see #pow(int)
+ */
+ public LuaValue powWith(int lhs) { return powWith((double) lhs); }
+
+ /**
+ * Divide: Perform numeric divide operation by another value of unknown
+ * type, including metatag processing.
+ *
+ * Each operand must derive from {@link LuaNumber} or derive from
+ * {@link LuaString} and be convertible to a number
+ *
+ * @param rhs The right-hand-side value to perform the divulo with
+ * @return value of {@code (this / rhs)} if both are numeric, or
+ * {@link LuaValue} if metatag processing occurs
+ * @throws LuaError if either operand is not a number or string convertible
+ * to number, and neither has the {@link #DIV} metatag
+ * defined
+ * @see #arithmt(LuaValue, LuaValue)
+ */
+ public LuaValue div(LuaValue rhs) { return arithmt(DIV, rhs); }
+
+ /**
+ * Divide: Perform numeric divide operation by another value of double type
+ * without metatag processing
+ *
+ * {@code this} must derive from {@link LuaNumber} or derive from
+ * {@link LuaString} and be convertible to a number
+ *
+ * For metatag processing {@link #div(LuaValue)} must be used
+ *
+ * @param rhs The right-hand-side value to perform the divulo with
+ * @return value of {@code (this / rhs)} if this is numeric
+ * @throws LuaError if {@code this} is not a number or string convertible to
+ * number
+ * @see #div(LuaValue)
+ */
+ public LuaValue div(double rhs) { return aritherror("div"); }
+
+ /**
+ * Divide: Perform numeric divide operation by another value of int type
+ * without metatag processing
+ *
+ * {@code this} must derive from {@link LuaNumber} or derive from
+ * {@link LuaString} and be convertible to a number
+ *
+ * For metatag processing {@link #div(LuaValue)} must be used
+ *
+ * @param rhs The right-hand-side value to perform the divulo with
+ * @return value of {@code (this / rhs)} if this is numeric
+ * @throws LuaError if {@code this} is not a number or string convertible to
+ * number
+ * @see #div(LuaValue)
+ */
+ public LuaValue div(int rhs) { return aritherror("div"); }
+
+ /**
+ * Reverse-divide: Perform numeric divide operation into another value with
+ * metatag processing
+ *
+ * {@code this} must derive from {@link LuaNumber} or derive from
+ * {@link LuaString} and be convertible to a number
+ *
+ * @param lhs The left-hand-side value which will be divided by this
+ * @return value of {@code (lhs / this)} if this is numeric
+ * @throws LuaError if {@code this} is not a number or string convertible to
+ * number
+ * @see #div(LuaValue)
+ * @see #div(double)
+ * @see #div(int)
+ */
+ public LuaValue divInto(double lhs) { return arithmtwith(DIV, lhs); }
+
+ /**
+ * Modulo: Perform numeric modulo operation with another value of unknown
+ * type, including metatag processing.
+ *
+ * Each operand must derive from {@link LuaNumber} or derive from
+ * {@link LuaString} and be convertible to a number
+ *
+ * @param rhs The right-hand-side value to perform the modulo with
+ * @return value of {@code (this % rhs)} if both are numeric, or
+ * {@link LuaValue} if metatag processing occurs
+ * @throws LuaError if either operand is not a number or string convertible
+ * to number, and neither has the {@link #MOD} metatag
+ * defined
+ * @see #arithmt(LuaValue, LuaValue)
+ */
+ public LuaValue mod(LuaValue rhs) { return arithmt(MOD, rhs); }
+
+ /**
+ * Modulo: Perform numeric modulo operation with another value of double
+ * type without metatag processing
+ *
+ * {@code this} must derive from {@link LuaNumber} or derive from
+ * {@link LuaString} and be convertible to a number
+ *
+ * For metatag processing {@link #mod(LuaValue)} must be used
+ *
+ * @param rhs The right-hand-side value to perform the modulo with
+ * @return value of {@code (this % rhs)} if this is numeric
+ * @throws LuaError if {@code this} is not a number or string convertible to
+ * number
+ * @see #mod(LuaValue)
+ */
+ public LuaValue mod(double rhs) { return aritherror("mod"); }
+
+ /**
+ * Modulo: Perform numeric modulo operation with another value of int type
+ * without metatag processing
+ *
+ * {@code this} must derive from {@link LuaNumber} or derive from
+ * {@link LuaString} and be convertible to a number
+ *
+ * For metatag processing {@link #mod(LuaValue)} must be used
+ *
+ * @param rhs The right-hand-side value to perform the modulo with
+ * @return value of {@code (this % rhs)} if this is numeric
+ * @throws LuaError if {@code this} is not a number or string convertible to
+ * number
+ * @see #mod(LuaValue)
+ */
+ public LuaValue mod(int rhs) { return aritherror("mod"); }
+
+ /**
+ * Reverse-modulo: Perform numeric modulo operation from another value with
+ * metatag processing
+ *
+ * {@code this} must derive from {@link LuaNumber} or derive from
+ * {@link LuaString} and be convertible to a number
+ *
+ * @param lhs The left-hand-side value which will be modulo'ed by this
+ * @return value of {@code (lhs % this)} if this is numeric
+ * @throws LuaError if {@code this} is not a number or string convertible to
+ * number
+ * @see #mod(LuaValue)
+ * @see #mod(double)
+ * @see #mod(int)
+ */
+ public LuaValue modFrom(double lhs) { return arithmtwith(MOD, lhs); }
+
+ /**
+ * Perform metatag processing for arithmetic operations.
+ *
+ * Finds the supplied metatag value for {@code this} or {@code op2} and
+ * invokes it, or throws {@link LuaError} if neither is defined.
+ *
+ * @param tag The metatag to look up
+ * @param op2 The other operand value to perform the operation with
+ * @return {@link LuaValue} resulting from metatag processing
+ * @throws LuaError if metatag was not defined for either operand
+ * @see #add(LuaValue)
+ * @see #sub(LuaValue)
+ * @see #mul(LuaValue)
+ * @see #pow(LuaValue)
+ * @see #div(LuaValue)
+ * @see #mod(LuaValue)
+ * @see #ADD
+ * @see #SUB
+ * @see #MUL
+ * @see #POW
+ * @see #DIV
+ * @see #MOD
+ */
+ protected LuaValue arithmt(LuaValue tag, LuaValue op2) {
+ LuaValue h = this.metatag(tag);
+ if (h.isnil()) {
+ h = op2.metatag(tag);
+ if (h.isnil())
+ error("attempt to perform arithmetic " + tag + " on " + typename() + " and " + op2.typename());
+ }
+ return h.call(this, op2);
+ }
+
+ /**
+ * Perform metatag processing for arithmetic operations when the
+ * left-hand-side is a number.
+ *
+ * Finds the supplied metatag value for {@code this} and invokes it, or
+ * throws {@link LuaError} if neither is defined.
+ *
+ * @param tag The metatag to look up
+ * @param op1 The value of the left-hand-side to perform the operation with
+ * @return {@link LuaValue} resulting from metatag processing
+ * @throws LuaError if metatag was not defined for either operand
+ * @see #add(LuaValue)
+ * @see #sub(LuaValue)
+ * @see #mul(LuaValue)
+ * @see #pow(LuaValue)
+ * @see #div(LuaValue)
+ * @see #mod(LuaValue)
+ * @see #ADD
+ * @see #SUB
+ * @see #MUL
+ * @see #POW
+ * @see #DIV
+ * @see #MOD
+ */
+ protected LuaValue arithmtwith(LuaValue tag, double op1) {
+ LuaValue h = metatag(tag);
+ if (h.isnil())
+ error("attempt to perform arithmetic " + tag + " on number and " + typename());
+ return h.call(LuaValue.valueOf(op1), this);
+ }
+
+ /**
+ * Less than: Perform numeric or string comparison with another value of
+ * unknown type, including metatag processing, and returning
+ * {@link LuaValue}.
+ *
+ * To be comparable, both operands must derive from {@link LuaString} or
+ * both must derive from {@link LuaNumber}.
+ *
+ * @param rhs The right-hand-side value to perform the comparison with
+ * @return {@link #TRUE} if {@code (this < rhs)}, {@link #FALSE} if not, or
+ * {@link LuaValue} if metatag processing occurs
+ * @throws LuaError if either both operands are not a strings or both are
+ * not numbers and no {@link #LT} metatag is defined.
+ * @see #gteq_b(LuaValue)
+ * @see #comparemt(LuaValue, LuaValue)
+ */
+ public LuaValue lt(LuaValue rhs) { return comparemt(LT, rhs); }
+
+ /**
+ * Less than: Perform numeric comparison with another value of double type,
+ * including metatag processing, and returning {@link LuaValue}.
+ *
+ * To be comparable, this must derive from {@link LuaNumber}.
+ *
+ * @param rhs The right-hand-side value to perform the comparison with
+ * @return {@link #TRUE} if {@code (this < rhs)}, {@link #FALSE} if not, or
+ * {@link LuaValue} if metatag processing occurs
+ * @throws LuaError if this is not a number and no {@link #LT} metatag is
+ * defined.
+ * @see #gteq_b(double)
+ * @see #comparemt(LuaValue, LuaValue)
+ */
+ public LuaValue lt(double rhs) { return compareerror("number"); }
+
+ /**
+ * Less than: Perform numeric comparison with another value of int type,
+ * including metatag processing, and returning {@link LuaValue}.
+ *
+ * To be comparable, this must derive from {@link LuaNumber}.
+ *
+ * @param rhs The right-hand-side value to perform the comparison with
+ * @return {@link #TRUE} if {@code (this < rhs)}, {@link #FALSE} if not, or
+ * {@link LuaValue} if metatag processing occurs
+ * @throws LuaError if this is not a number and no {@link #LT} metatag is
+ * defined.
+ * @see #gteq_b(int)
+ * @see #comparemt(LuaValue, LuaValue)
+ */
+ public LuaValue lt(int rhs) { return compareerror("number"); }
+
+ /**
+ * Less than: Perform numeric or string comparison with another value of
+ * unknown type, including metatag processing, and returning java boolean.
+ *
+ * To be comparable, both operands must derive from {@link LuaString} or
+ * both must derive from {@link LuaNumber}.
+ *
+ * @param rhs The right-hand-side value to perform the comparison with
+ * @return true if {@code (this < rhs)}, false if not, and boolean
+ * interpreation of result if metatag processing occurs.
+ * @throws LuaError if either both operands are not a strings or both are
+ * not numbers and no {@link #LT} metatag is defined.
+ * @see #gteq(LuaValue)
+ * @see #comparemt(LuaValue, LuaValue)
+ */
+ public boolean lt_b(LuaValue rhs) { return comparemt(LT, rhs).toboolean(); }
+
+ /**
+ * Less than: Perform numeric comparison with another value of int type,
+ * including metatag processing, and returning java boolean.
+ *
+ * To be comparable, this must derive from {@link LuaNumber}.
+ *
+ * @param rhs The right-hand-side value to perform the comparison with
+ * @return true if {@code (this < rhs)}, false if not, and boolean
+ * interpreation of result if metatag processing occurs.
+ * @throws LuaError if this is not a number and no {@link #LT} metatag is
+ * defined.
+ * @see #gteq(int)
+ * @see #comparemt(LuaValue, LuaValue)
+ */
+ public boolean lt_b(int rhs) { compareerror("number"); return false; }
+
+ /**
+ * Less than: Perform numeric or string comparison with another value of
+ * unknown type, including metatag processing, and returning java boolean.
+ *
+ * To be comparable, both operands must derive from {@link LuaString} or
+ * both must derive from {@link LuaNumber}.
+ *
+ * @param rhs The right-hand-side value to perform the comparison with
+ * @return true if {@code (this < rhs)}, false if not, and boolean
+ * interpreation of result if metatag processing occurs.
+ * @throws LuaError if either both operands are not a strings or both are
+ * not numbers and no {@link #LT} metatag is defined.
+ * @see #gteq(LuaValue)
+ * @see #comparemt(LuaValue, LuaValue)
+ */
+ public boolean lt_b(double rhs) { compareerror("number"); return false; }
+
+ /**
+ * Less than or equals: Perform numeric or string comparison with another
+ * value of unknown type, including metatag processing, and returning
+ * {@link LuaValue}.
+ *
+ * To be comparable, both operands must derive from {@link LuaString} or
+ * both must derive from {@link LuaNumber}.
+ *
+ * @param rhs The right-hand-side value to perform the comparison with
+ * @return {@link #TRUE} if {@code (this <= rhs)}, {@link #FALSE} if not, or
+ * {@link LuaValue} if metatag processing occurs
+ * @throws LuaError if either both operands are not a strings or both are
+ * not numbers and no {@link #LE} metatag is defined.
+ * @see #gteq_b(LuaValue)
+ * @see #comparemt(LuaValue, LuaValue)
+ */
+ public LuaValue lteq(LuaValue rhs) { return comparemt(LE, rhs); }
+
+ /**
+ * Less than or equals: Perform numeric comparison with another value of
+ * double type, including metatag processing, and returning
+ * {@link LuaValue}.
+ *
+ * To be comparable, this must derive from {@link LuaNumber}.
+ *
+ * @param rhs The right-hand-side value to perform the comparison with
+ * @return {@link #TRUE} if {@code (this <= rhs)}, {@link #FALSE} if not, or
+ * {@link LuaValue} if metatag processing occurs
+ * @throws LuaError if this is not a number and no {@link #LE} metatag is
+ * defined.
+ * @see #gteq_b(double)
+ * @see #comparemt(LuaValue, LuaValue)
+ */
+ public LuaValue lteq(double rhs) { return compareerror("number"); }
+
+ /**
+ * Less than or equals: Perform numeric comparison with another value of int
+ * type, including metatag processing, and returning {@link LuaValue}.
+ *
+ * To be comparable, this must derive from {@link LuaNumber}.
+ *
+ * @param rhs The right-hand-side value to perform the comparison with
+ * @return {@link #TRUE} if {@code (this <= rhs)}, {@link #FALSE} if not, or
+ * {@link LuaValue} if metatag processing occurs
+ * @throws LuaError if this is not a number and no {@link #LE} metatag is
+ * defined.
+ * @see #gteq_b(int)
+ * @see #comparemt(LuaValue, LuaValue)
+ */
+ public LuaValue lteq(int rhs) { return compareerror("number"); }
+
+ /**
+ * Less than or equals: Perform numeric or string comparison with another
+ * value of unknown type, including metatag processing, and returning java
+ * boolean.
+ *
+ * To be comparable, both operands must derive from {@link LuaString} or
+ * both must derive from {@link LuaNumber}.
+ *
+ * @param rhs The right-hand-side value to perform the comparison with
+ * @return true if {@code (this <= rhs)}, false if not, and boolean
+ * interpreation of result if metatag processing occurs.
+ * @throws LuaError if either both operands are not a strings or both are
+ * not numbers and no {@link #LE} metatag is defined.
+ * @see #gteq(LuaValue)
+ * @see #comparemt(LuaValue, LuaValue)
+ */
+ public boolean lteq_b(LuaValue rhs) { return comparemt(LE, rhs).toboolean(); }
+
+ /**
+ * Less than or equals: Perform numeric comparison with another value of int
+ * type, including metatag processing, and returning java boolean.
+ *
+ * To be comparable, this must derive from {@link LuaNumber}.
+ *
+ * @param rhs The right-hand-side value to perform the comparison with
+ * @return true if {@code (this <= rhs)}, false if not, and boolean
+ * interpreation of result if metatag processing occurs.
+ * @throws LuaError if this is not a number and no {@link #LE} metatag is
+ * defined.
+ * @see #gteq(int)
+ * @see #comparemt(LuaValue, LuaValue)
+ */
+ public boolean lteq_b(int rhs) { compareerror("number"); return false; }
+
+ /**
+ * Less than or equals: Perform numeric comparison with another value of
+ * double type, including metatag processing, and returning java boolean.
+ *
+ * To be comparable, this must derive from {@link LuaNumber}.
+ *
+ * @param rhs The right-hand-side value to perform the comparison with
+ * @return true if {@code (this <= rhs)}, false if not, and boolean
+ * interpreation of result if metatag processing occurs.
+ * @throws LuaError if this is not a number and no {@link #LE} metatag is
+ * defined.
+ * @see #gteq(double)
+ * @see #comparemt(LuaValue, LuaValue)
+ */
+ public boolean lteq_b(double rhs) { compareerror("number"); return false; }
+
+ /**
+ * Greater than: Perform numeric or string comparison with another value of
+ * unknown type, including metatag processing, and returning
+ * {@link LuaValue}.
+ *
+ * To be comparable, both operands must derive from {@link LuaString} or
+ * both must derive from {@link LuaNumber}.
+ *
+ * @param rhs The right-hand-side value to perform the comparison with
+ * @return {@link #TRUE} if {@code (this > rhs)}, {@link #FALSE} if not, or
+ * {@link LuaValue} if metatag processing occurs
+ * @throws LuaError if either both operands are not a strings or both are
+ * not numbers and no {@link #LE} metatag is defined.
+ * @see #gteq_b(LuaValue)
+ * @see #comparemt(LuaValue, LuaValue)
+ */
+ public LuaValue gt(LuaValue rhs) { return rhs.comparemt(LE, this); }
+
+ /**
+ * Greater than: Perform numeric comparison with another value of double
+ * type, including metatag processing, and returning {@link LuaValue}.
+ *
+ * To be comparable, this must derive from {@link LuaNumber}.
+ *
+ * @param rhs The right-hand-side value to perform the comparison with
+ * @return {@link #TRUE} if {@code (this > rhs)}, {@link #FALSE} if not, or
+ * {@link LuaValue} if metatag processing occurs
+ * @throws LuaError if this is not a number and no {@link #LE} metatag is
+ * defined.
+ * @see #gteq_b(double)
+ * @see #comparemt(LuaValue, LuaValue)
+ */
+ public LuaValue gt(double rhs) { return compareerror("number"); }
+
+ /**
+ * Greater than: Perform numeric comparison with another value of int type,
+ * including metatag processing, and returning {@link LuaValue}.
+ *
+ * To be comparable, this must derive from {@link LuaNumber}.
+ *
+ * @param rhs The right-hand-side value to perform the comparison with
+ * @return {@link #TRUE} if {@code (this > rhs)}, {@link #FALSE} if not, or
+ * {@link LuaValue} if metatag processing occurs
+ * @throws LuaError if this is not a number and no {@link #LE} metatag is
+ * defined.
+ * @see #gteq_b(int)
+ * @see #comparemt(LuaValue, LuaValue)
+ */
+ public LuaValue gt(int rhs) { return compareerror("number"); }
+
+ /**
+ * Greater than: Perform numeric or string comparison with another value of
+ * unknown type, including metatag processing, and returning java boolean.
+ *
+ * To be comparable, both operands must derive from {@link LuaString} or
+ * both must derive from {@link LuaNumber}.
+ *
+ * @param rhs The right-hand-side value to perform the comparison with
+ * @return true if {@code (this > rhs)}, false if not, and boolean
+ * interpreation of result if metatag processing occurs.
+ * @throws LuaError if either both operands are not a strings or both are
+ * not numbers and no {@link #LE} metatag is defined.
+ * @see #gteq(LuaValue)
+ * @see #comparemt(LuaValue, LuaValue)
+ */
+ public boolean gt_b(LuaValue rhs) { return rhs.comparemt(LE, this).toboolean(); }
+
+ /**
+ * Greater than: Perform numeric comparison with another value of int type,
+ * including metatag processing, and returning java boolean.
+ *
+ * To be comparable, this must derive from {@link LuaNumber}.
+ *
+ * @param rhs The right-hand-side value to perform the comparison with
+ * @return true if {@code (this > rhs)}, false if not, and boolean
+ * interpreation of result if metatag processing occurs.
+ * @throws LuaError if this is not a number and no {@link #LE} metatag is
+ * defined.
+ * @see #gteq(int)
+ * @see #comparemt(LuaValue, LuaValue)
+ */
+ public boolean gt_b(int rhs) { compareerror("number"); return false; }
+
+ /**
+ * Greater than: Perform numeric or string comparison with another value of
+ * unknown type, including metatag processing, and returning java boolean.
+ *
+ * To be comparable, both operands must derive from {@link LuaString} or
+ * both must derive from {@link LuaNumber}.
+ *
+ * @param rhs The right-hand-side value to perform the comparison with
+ * @return true if {@code (this > rhs)}, false if not, and boolean
+ * interpreation of result if metatag processing occurs.
+ * @throws LuaError if either both operands are not a strings or both are
+ * not numbers and no {@link #LE} metatag is defined.
+ * @see #gteq(LuaValue)
+ * @see #comparemt(LuaValue, LuaValue)
+ */
+ public boolean gt_b(double rhs) { compareerror("number"); return false; }
+
+ /**
+ * Greater than or equals: Perform numeric or string comparison with another
+ * value of unknown type, including metatag processing, and returning
+ * {@link LuaValue}.
+ *
+ * To be comparable, both operands must derive from {@link LuaString} or
+ * both must derive from {@link LuaNumber}.
+ *
+ * @param rhs The right-hand-side value to perform the comparison with
+ * @return {@link #TRUE} if {@code (this >= rhs)}, {@link #FALSE} if not, or
+ * {@link LuaValue} if metatag processing occurs
+ * @throws LuaError if either both operands are not a strings or both are
+ * not numbers and no {@link #LT} metatag is defined.
+ * @see #gteq_b(LuaValue)
+ * @see #comparemt(LuaValue, LuaValue)
+ */
+ public LuaValue gteq(LuaValue rhs) { return rhs.comparemt(LT, this); }
+
+ /**
+ * Greater than or equals: Perform numeric comparison with another value of
+ * double type, including metatag processing, and returning
+ * {@link LuaValue}.
+ *
+ * To be comparable, this must derive from {@link LuaNumber}.
+ *
+ * @param rhs The right-hand-side value to perform the comparison with
+ * @return {@link #TRUE} if {@code (this >= rhs)}, {@link #FALSE} if not, or
+ * {@link LuaValue} if metatag processing occurs
+ * @throws LuaError if this is not a number and no {@link #LT} metatag is
+ * defined.
+ * @see #gteq_b(double)
+ * @see #comparemt(LuaValue, LuaValue)
+ */
+ public LuaValue gteq(double rhs) { return compareerror("number"); }
+
+ /**
+ * Greater than or equals: Perform numeric comparison with another value of
+ * int type, including metatag processing, and returning {@link LuaValue}.
+ *
+ * To be comparable, this must derive from {@link LuaNumber}.
+ *
+ * @param rhs The right-hand-side value to perform the comparison with
+ * @return {@link #TRUE} if {@code (this >= rhs)}, {@link #FALSE} if not, or
+ * {@link LuaValue} if metatag processing occurs
+ * @throws LuaError if this is not a number and no {@link #LT} metatag is
+ * defined.
+ * @see #gteq_b(int)
+ * @see #comparemt(LuaValue, LuaValue)
+ */
+ public LuaValue gteq(int rhs) { return valueOf(todouble() >= rhs); }
+
+ /**
+ * Greater than or equals: Perform numeric or string comparison with another
+ * value of unknown type, including metatag processing, and returning java
+ * boolean.
+ *
+ * To be comparable, both operands must derive from {@link LuaString} or
+ * both must derive from {@link LuaNumber}.
+ *
+ * @param rhs The right-hand-side value to perform the comparison with
+ * @return true if {@code (this >= rhs)}, false if not, and boolean
+ * interpreation of result if metatag processing occurs.
+ * @throws LuaError if either both operands are not a strings or both are
+ * not numbers and no {@link #LT} metatag is defined.
+ * @see #gteq(LuaValue)
+ * @see #comparemt(LuaValue, LuaValue)
+ */
+ public boolean gteq_b(LuaValue rhs) { return rhs.comparemt(LT, this).toboolean(); }
+
+ /**
+ * Greater than or equals: Perform numeric comparison with another value of
+ * int type, including metatag processing, and returning java boolean.
+ *
+ * To be comparable, this must derive from {@link LuaNumber}.
+ *
+ * @param rhs The right-hand-side value to perform the comparison with
+ * @return true if {@code (this >= rhs)}, false if not, and boolean
+ * interpreation of result if metatag processing occurs.
+ * @throws LuaError if this is not a number and no {@link #LT} metatag is
+ * defined.
+ * @see #gteq(int)
+ * @see #comparemt(LuaValue, LuaValue)
+ */
+ public boolean gteq_b(int rhs) { compareerror("number"); return false; }
+
+ /**
+ * Greater than or equals: Perform numeric comparison with another value of
+ * double type, including metatag processing, and returning java boolean.
+ *
+ * To be comparable, this must derive from {@link LuaNumber}.
+ *
+ * @param rhs The right-hand-side value to perform the comparison with
+ * @return true if {@code (this >= rhs)}, false if not, and boolean
+ * interpreation of result if metatag processing occurs.
+ * @throws LuaError if this is not a number and no {@link #LT} metatag is
+ * defined.
+ * @see #gteq(double)
+ * @see #comparemt(LuaValue, LuaValue)
+ */
+ public boolean gteq_b(double rhs) { compareerror("number"); return false; }
+
+ /**
+ * Perform metatag processing for comparison operations.
+ *
+ * Finds the supplied metatag value and invokes it, or throws
+ * {@link LuaError} if none applies.
+ *
+ * @param tag The metatag to look up
+ * @param op1 The operand with which to to perform the operation
+ * @return {@link LuaValue} resulting from metatag processing
+ * @throws LuaError if metatag was not defined for either operand, or if the
+ * operands are not the same type, or the metatag values
+ * for the two operands are different.
+ * @see #gt(LuaValue)
+ * @see #gteq(LuaValue)
+ * @see #lt(LuaValue)
+ * @see #lteq(LuaValue)
+ */
+ public LuaValue comparemt(LuaValue tag, LuaValue op1) {
+ LuaValue h;
+ if (!(h = metatag(tag)).isnil() || !(h = op1.metatag(tag)).isnil())
+ return h.call(this, op1);
+ if (LuaValue.LE.raweq(tag) && (!(h = metatag(LT)).isnil() || !(h = op1.metatag(LT)).isnil()))
+ return h.call(op1, this).not();
+ return error("bad argument: attempt to compare " + tag + " on " + typename() + " and " + op1.typename());
+ }
+
+ /**
+ * Perform string comparison with another value of any type using string
+ * comparison based on byte values.
+ *
+ * Only strings can be compared, meaning each operand must derive from
+ * {@link LuaString}.
+ *
+ * @param rhs The right-hand-side value to perform the comparison with
+ * @return int < 0 for {@code (this < rhs)}, int > 0 for
+ * {@code (this > rhs)}, or 0 when same string.
+ * @throws LuaError if either operand is not a string
+ */
+ public int strcmp(LuaValue rhs) { error("attempt to compare " + typename()); return 0; }
+
+ /**
+ * Perform string comparison with another value known to be a
+ * {@link LuaString} using string comparison based on byte values.
+ *
+ * Only strings can be compared, meaning each operand must derive from
+ * {@link LuaString}.
+ *
+ * @param rhs The right-hand-side value to perform the comparison with
+ * @return int < 0 for {@code (this < rhs)}, int > 0 for
+ * {@code (this > rhs)}, or 0 when same string.
+ * @throws LuaError if this is not a string
+ */
+ public int strcmp(LuaString rhs) { error("attempt to compare " + typename()); return 0; }
+
+ /**
+ * Concatenate another value onto this value and return the result using
+ * rules of lua string concatenation including metatag processing.
+ *
+ * Only strings and numbers as represented can be concatenated, meaning each
+ * operand must derive from {@link LuaString} or {@link LuaNumber}.
+ *
+ * @param rhs The right-hand-side value to perform the operation with
+ * @return {@link LuaValue} resulting from concatenation of
+ * {@code (this .. rhs)}
+ * @throws LuaError if either operand is not of an appropriate type, such as
+ * nil or a table
+ */
+ public LuaValue concat(LuaValue rhs) { return this.concatmt(rhs); }
+
+ /**
+ * Reverse-concatenation: concatenate this value onto another value whose
+ * type is unknwon and return the result using rules of lua string
+ * concatenation including metatag processing.
+ *
+ * Only strings and numbers as represented can be concatenated, meaning each
+ * operand must derive from {@link LuaString} or {@link LuaNumber}.
+ *
+ * @param lhs The left-hand-side value onto which this will be concatenated
+ * @return {@link LuaValue} resulting from concatenation of
+ * {@code (lhs .. this)}
+ * @throws LuaError if either operand is not of an appropriate type, such as
+ * nil or a table
+ * @see #concat(LuaValue)
+ */
+ public LuaValue concatTo(LuaValue lhs) { return lhs.concatmt(this); }
+
+ /**
+ * Reverse-concatenation: concatenate this value onto another value known to
+ * be a {@link LuaNumber} and return the result using rules of lua string
+ * concatenation including metatag processing.
+ *
+ * Only strings and numbers as represented can be concatenated, meaning each
+ * operand must derive from {@link LuaString} or {@link LuaNumber}.
+ *
+ * @param lhs The left-hand-side value onto which this will be concatenated
+ * @return {@link LuaValue} resulting from concatenation of
+ * {@code (lhs .. this)}
+ * @throws LuaError if either operand is not of an appropriate type, such as
+ * nil or a table
+ * @see #concat(LuaValue)
+ */
+ public LuaValue concatTo(LuaNumber lhs) { return lhs.concatmt(this); }
+
+ /**
+ * Reverse-concatenation: concatenate this value onto another value known to
+ * be a {@link LuaString} and return the result using rules of lua string
+ * concatenation including metatag processing.
+ *
+ * Only strings and numbers as represented can be concatenated, meaning each
+ * operand must derive from {@link LuaString} or {@link LuaNumber}.
+ *
+ * @param lhs The left-hand-side value onto which this will be concatenated
+ * @return {@link LuaValue} resulting from concatenation of
+ * {@code (lhs .. this)}
+ * @throws LuaError if either operand is not of an appropriate type, such as
+ * nil or a table
+ * @see #concat(LuaValue)
+ */
+ public LuaValue concatTo(LuaString lhs) { return lhs.concatmt(this); }
+
+ /**
+ * Convert the value to a {@link Buffer} for more efficient concatenation of
+ * multiple strings.
+ *
+ * @return Buffer instance containing the string or number
+ */
+ public Buffer buffer() { return new Buffer(this); }
+
+ /**
+ * Concatenate a {@link Buffer} onto this value and return the result using
+ * rules of lua string concatenation including metatag processing.
+ *
+ * Only strings and numbers as represented can be concatenated, meaning each
+ * operand must derive from {@link LuaString} or {@link LuaNumber}.
+ *
+ * @param rhs The right-hand-side {@link Buffer} to perform the operation
+ * with
+ * @return LuaString resulting from concatenation of {@code (this .. rhs)}
+ * @throws LuaError if either operand is not of an appropriate type, such as
+ * nil or a table
+ */
+ public Buffer concat(Buffer rhs) { return rhs.concatTo(this); }
+
+ /**
+ * Perform metatag processing for concatenation operations.
+ *
+ * Finds the {@link #CONCAT} metatag value and invokes it, or throws
+ * {@link LuaError} if it doesn't exist.
+ *
+ * @param rhs The right-hand-side value to perform the operation with
+ * @return {@link LuaValue} resulting from metatag processing for
+ * {@link #CONCAT} metatag.
+ * @throws LuaError if metatag was not defined for either operand
+ */
+ public LuaValue concatmt(LuaValue rhs) {
+ LuaValue h = metatag(CONCAT);
+ if (h.isnil() && (h = rhs.metatag(CONCAT)).isnil())
+ error("attempt to concatenate " + typename() + " and " + rhs.typename());
+ return h.call(this, rhs);
+ }
+
+ /**
+ * Perform boolean {@code and} with another operand, based on lua rules for
+ * boolean evaluation. This returns either {@code this} or {@code rhs}
+ * depending on the boolean value for {@code this}.
+ *
+ * @param rhs The right-hand-side value to perform the operation with
+ * @return {@code this} if {@code this.toboolean()} is false, {@code rhs}
+ * otherwise.
+ */
+ public LuaValue and(LuaValue rhs) { return this.toboolean()? rhs: this; }
+
+ /**
+ * Perform boolean {@code or} with another operand, based on lua rules for
+ * boolean evaluation. This returns either {@code this} or {@code rhs}
+ * depending on the boolean value for {@code this}.
+ *
+ * @param rhs The right-hand-side value to perform the operation with
+ * @return {@code this} if {@code this.toboolean()} is true, {@code rhs}
+ * otherwise.
+ */
+ public LuaValue or(LuaValue rhs) { return this.toboolean()? this: rhs; }
+
+ /**
+ * Perform end-condition test in for-loop processing.
+ *
+ * Used in lua-bytecode to Java-bytecode conversion.
+ *
+ * @param limit the numerical limit to complete the for loop
+ * @param step the numberical step size to use.
+ * @return true if limit has not been reached, false otherwise.
+ */
+ public boolean testfor_b(LuaValue limit, LuaValue step) { return step.gt_b(0)? lteq_b(limit): gteq_b(limit); }
+
+ /**
+ * Convert this value to a string if it is a {@link LuaString} or
+ * {@link LuaNumber}, or throw a {@link LuaError} if it is not
+ *
+ * @return {@link LuaString} corresponding to the value if a string or
+ * number
+ * @throws LuaError if not a string or number
+ */
+ public LuaString strvalue() { typerror("string or number"); return null; }
+
+ /**
+ * Return this value as a strong reference, or null if it was weak and is no
+ * longer referenced.
+ *
+ * @return {@link LuaValue} referred to, or null if it was weak and is no
+ * longer referenced.
+ * @see WeakTable
+ */
+ public LuaValue strongvalue() { return this; }
+
+ /**
+ * Convert java boolean to a {@link LuaValue}.
+ *
+ * @param b boolean value to convert
+ * @return {@link #TRUE} if not or {@link #FALSE} if false
+ */
+ public static LuaBoolean valueOf(boolean b) { return b? LuaValue.TRUE: FALSE; }
+
+ /**
+ * Convert java int to a {@link LuaValue}.
+ *
+ * @param i int value to convert
+ * @return {@link LuaInteger} instance, possibly pooled, whose value is i
+ */
+ public static LuaInteger valueOf(int i) { return LuaInteger.valueOf(i); }
+
+ /**
+ * Convert java double to a {@link LuaValue}. This may return a
+ * {@link LuaInteger} or {@link LuaDouble} depending on the value supplied.
+ *
+ * @param d double value to convert
+ * @return {@link LuaNumber} instance, possibly pooled, whose value is d
+ */
+ public static LuaNumber valueOf(double d) { return LuaDouble.valueOf(d); }
+
+ /**
+ * Convert java string to a {@link LuaValue}.
+ *
+ * @param s String value to convert
+ * @return {@link LuaString} instance, possibly pooled, whose value is s
+ */
+ public static LuaString valueOf(String s) { return LuaString.valueOf(s); }
+
+ /**
+ * Convert bytes in an array to a {@link LuaValue}.
+ *
+ * @param bytes byte array to convert
+ * @return {@link LuaString} instance, possibly pooled, whose bytes are
+ * those in the supplied array
+ */
+ public static LuaString valueOf(byte[] bytes) { return LuaString.valueOf(bytes); }
+
+ /**
+ * Convert bytes in an array to a {@link LuaValue}.
+ *
+ * @param bytes byte array to convert
+ * @param off offset into the byte array, starting at 0
+ * @param len number of bytes to include in the {@link LuaString}
+ * @return {@link LuaString} instance, possibly pooled, whose bytes are
+ * those in the supplied array
+ */
+ public static LuaString valueOf(byte[] bytes, int off, int len) {
+ return LuaString.valueOf(bytes, off, len);
+ }
+
+ /**
+ * Construct an empty {@link LuaTable}.
+ *
+ * @return new {@link LuaTable} instance with no values and no metatable.
+ */
+ public static LuaTable tableOf() { return new LuaTable(); }
+
+ /**
+ * Construct a {@link LuaTable} initialized with supplied array values.
+ *
+ * @param varargs {@link Varargs} containing the values to use in
+ * initialization
+ * @param firstarg the index of the first argument to use from the varargs,
+ * 1 being the first.
+ * @return new {@link LuaTable} instance with sequential elements coming
+ * from the varargs.
+ */
+ public static LuaTable tableOf(Varargs varargs, int firstarg) { return new LuaTable(varargs, firstarg); }
+
+ /**
+ * Construct an empty {@link LuaTable} preallocated to hold array and hashed
+ * elements
+ *
+ * @param narray Number of array elements to preallocate
+ * @param nhash Number of hash elements to preallocate
+ * @return new {@link LuaTable} instance with no values and no metatable,
+ * but preallocated for array and hashed elements.
+ */
+ public static LuaTable tableOf(int narray, int nhash) { return new LuaTable(narray, nhash); }
+
+ /**
+ * Construct a {@link LuaTable} initialized with supplied array values.
+ *
+ * @param unnamedValues array of {@link LuaValue} containing the values to
+ * use in initialization
+ * @return new {@link LuaTable} instance with sequential elements coming
+ * from the array.
+ */
+ public static LuaTable listOf(LuaValue[] unnamedValues) { return new LuaTable(null, unnamedValues, null); }
+
+ /**
+ * Construct a {@link LuaTable} initialized with supplied array values.
+ *
+ * @param unnamedValues array of {@link LuaValue} containing the first
+ * values to use in initialization
+ * @param lastarg {@link Varargs} containing additional values to use
+ * in initialization to be put after the last
+ * unnamedValues element
+ * @return new {@link LuaTable} instance with sequential elements coming
+ * from the array and varargs.
+ */
+ public static LuaTable listOf(LuaValue[] unnamedValues, Varargs lastarg) {
+ return new LuaTable(null, unnamedValues, lastarg);
+ }
+
+ /**
+ * Construct a {@link LuaTable} initialized with supplied named values.
+ *
+ * @param namedValues array of {@link LuaValue} containing the keys and
+ * values to use in initialization in order
+ * {@code {key-a, value-a, key-b, value-b, ...} }
+ * @return new {@link LuaTable} instance with non-sequential keys coming
+ * from the supplied array.
+ */
+ public static LuaTable tableOf(LuaValue[] namedValues) { return new LuaTable(namedValues, null, null); }
+
+ /**
+ * Construct a {@link LuaTable} initialized with supplied named values and
+ * sequential elements. The named values will be assigned first, and the
+ * sequential elements will be assigned later, possibly overwriting named
+ * values at the same slot if there are conflicts.
+ *
+ * @param namedValues array of {@link LuaValue} containing the keys and
+ * values to use in initialization in order
+ * {@code {key-a, value-a, key-b, value-b, ...} }
+ * @param unnamedValues array of {@link LuaValue} containing the sequenctial
+ * elements to use in initialization in order
+ * {@code {value-1, value-2, ...} }, or null if there
+ * are none
+ * @return new {@link LuaTable} instance with named and sequential values
+ * supplied.
+ */
+ public static LuaTable tableOf(LuaValue[] namedValues, LuaValue[] unnamedValues) {
+ return new LuaTable(namedValues, unnamedValues, null);
+ }
+
+ /**
+ * Construct a {@link LuaTable} initialized with supplied named values and
+ * sequential elements in an array part and as varargs. The named values
+ * will be assigned first, and the sequential elements will be assigned
+ * later, possibly overwriting named values at the same slot if there are
+ * conflicts.
+ *
+ * @param namedValues array of {@link LuaValue} containing the keys and
+ * values to use in initialization in order
+ * {@code {key-a, value-a, key-b, value-b, ...} }
+ * @param unnamedValues array of {@link LuaValue} containing the first
+ * sequenctial elements to use in initialization in
+ * order {@code {value-1, value-2, ...} }, or null if
+ * there are none
+ * @param lastarg {@link Varargs} containing additional values to use
+ * in the sequential part of the initialization, to be
+ * put after the last unnamedValues element
+ * @return new {@link LuaTable} instance with named and sequential values
+ * supplied.
+ */
+ public static LuaTable tableOf(LuaValue[] namedValues, LuaValue[] unnamedValues, Varargs lastarg) {
+ return new LuaTable(namedValues, unnamedValues, lastarg);
+ }
+
+ /**
+ * Construct a LuaUserdata for an object.
+ *
+ * @param o The java instance to be wrapped as userdata
+ * @return {@link LuaUserdata} value wrapping the java instance.
+ */
+ public static LuaUserdata userdataOf(Object o) { return new LuaUserdata(o); }
+
+ /**
+ * Construct a LuaUserdata for an object with a user supplied metatable.
+ *
+ * @param o The java instance to be wrapped as userdata
+ * @param metatable The metatble to associate with the userdata instance.
+ * @return {@link LuaUserdata} value wrapping the java instance.
+ */
+ public static LuaUserdata userdataOf(Object o, LuaValue metatable) { return new LuaUserdata(o, metatable); }
+
+ /** Constant limiting metatag loop processing */
+ private static final int MAXTAGLOOP = 100;
+
+ /**
+ * Return value for field reference including metatag processing, or
+ * {@link LuaValue#NIL} if it doesn't exist.
+ *
+ * @param t {@link LuaValue} on which field is being referenced, typically
+ * a table or something with the metatag {@link LuaValue#INDEX}
+ * defined
+ * @param key {@link LuaValue} naming the field to reference
+ * @return {@link LuaValue} for the {@code key} if it exists, or
+ * {@link LuaValue#NIL}
+ * @throws LuaError if there is a loop in metatag processing
+ */
+ /**
+ * get value from metatable operations, or NIL if not defined by metatables
+ */
+ protected static LuaValue gettable(LuaValue t, LuaValue key) {
+ LuaValue tm;
+ int loop = 0;
+ do {
+ if (t.istable()) {
+ LuaValue res = t.rawget(key);
+ if (!res.isnil() || (tm = t.metatag(INDEX)).isnil())
+ return res;
+ } else if ((tm = t.metatag(INDEX)).isnil())
+ t.indexerror(key.tojstring());
+ if (tm.isfunction())
+ return tm.call(t, key);
+ t = tm;
+ } while ( ++loop < MAXTAGLOOP );
+ error("loop in gettable");
+ return NIL;
+ }
+
+ /**
+ * Perform field assignment including metatag processing.
+ *
+ * @param t {@link LuaValue} on which value is being set, typically a
+ * table or something with the metatag
+ * {@link LuaValue#NEWINDEX} defined
+ * @param key {@link LuaValue} naming the field to assign
+ * @param value {@link LuaValue} the new value to assign to {@code key}
+ * @throws LuaError if there is a loop in metatag processing
+ * @return true if assignment or metatag processing succeeded, false
+ * otherwise
+ */
+ protected static boolean settable(LuaValue t, LuaValue key, LuaValue value) {
+ LuaValue tm;
+ int loop = 0;
+ do {
+ if (t.istable()) {
+ if (!t.rawget(key).isnil() || (tm = t.metatag(NEWINDEX)).isnil()) {
+ t.rawset(key, value);
+ return true;
+ }
+ } else if ((tm = t.metatag(NEWINDEX)).isnil())
+ throw new LuaError("table expected for set index ('" + key + "') value, got " + t.typename());
+ if (tm.isfunction()) {
+ tm.call(t, key, value);
+ return true;
+ }
+ t = tm;
+ } while ( ++loop < MAXTAGLOOP );
+ error("loop in settable");
+ return false;
+ }
+
+ /**
+ * Get particular metatag, or return {@link LuaValue#NIL} if it doesn't
+ * exist
+ *
+ * @param tag Metatag name to look up, typically a string such as
+ * {@link LuaValue#INDEX} or {@link LuaValue#NEWINDEX}
+ * @return {@link LuaValue} for tag {@code reason}, or {@link LuaValue#NIL}
+ */
+ public LuaValue metatag(LuaValue tag) {
+ LuaValue mt = getmetatable();
+ if (mt == null)
+ return NIL;
+ return mt.rawget(tag);
+ }
+
+ /**
+ * Get particular metatag, or throw {@link LuaError} if it doesn't exist
+ *
+ * @param tag Metatag name to look up, typically a string such as
+ * {@link LuaValue#INDEX} or {@link LuaValue#NEWINDEX}
+ * @param reason Description of error when tag lookup fails.
+ * @return {@link LuaValue} that can be called
+ * @throws LuaError when the lookup fails.
+ */
+ protected LuaValue checkmetatag(LuaValue tag, String reason) {
+ LuaValue h = this.metatag(tag);
+ if (h.isnil())
+ throw new LuaError(reason + "a " + typename() + " value");
+ return h;
+ }
+
+ /** Construct a Metatable instance from the given LuaValue */
+ protected static Metatable metatableOf(LuaValue mt) {
+ if (mt != null && mt.istable()) {
+ LuaValue mode = mt.rawget(MODE);
+ if (mode.isstring()) {
+ String m = mode.tojstring();
+ boolean weakkeys = m.indexOf('k') >= 0;
+ boolean weakvalues = m.indexOf('v') >= 0;
+ if (weakkeys || weakvalues) {
+ return new WeakTable(weakkeys, weakvalues, mt);
+ }
+ }
+ return (LuaTable) mt;
+ } else if (mt != null) {
+ return new NonTableMetatable(mt);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Throw {@link LuaError} indicating index was attempted on illegal type
+ *
+ * @throws LuaError when called.
+ */
+ private void indexerror(String key) {
+ error("attempt to index ? (a " + typename() + " value) with key '" + key + "'");
+ }
+
+ /**
+ * Construct a {@link Varargs} around an array of {@link LuaValue}s.
+ *
+ * @param v The array of {@link LuaValue}s
+ * @return {@link Varargs} wrapping the supplied values.
+ * @see LuaValue#varargsOf(LuaValue, Varargs)
+ * @see LuaValue#varargsOf(LuaValue[], int, int)
+ */
+ public static Varargs varargsOf(final LuaValue[] v) {
+ switch (v.length) {
+ case 0:
+ return NONE;
+ case 1:
+ return v[0];
+ case 2:
+ return new Varargs.PairVarargs(v[0], v[1]);
+ default:
+ return new Varargs.ArrayVarargs(v, NONE);
+ }
+ }
+
+ /**
+ * Construct a {@link Varargs} around an array of {@link LuaValue}s.
+ *
+ * @param v The array of {@link LuaValue}s
+ * @param r {@link Varargs} contain values to include at the end
+ * @return {@link Varargs} wrapping the supplied values.
+ * @see LuaValue#varargsOf(LuaValue[])
+ * @see LuaValue#varargsOf(LuaValue[], int, int, Varargs)
+ */
+ public static Varargs varargsOf(final LuaValue[] v, Varargs r) {
+ switch (v.length) {
+ case 0:
+ return r;
+ case 1:
+ return r.narg() > 0? (Varargs) new Varargs.PairVarargs(v[0], r): (Varargs) v[0];
+ case 2:
+ return r.narg() > 0? (Varargs) new Varargs.ArrayVarargs(v, r)
+ : (Varargs) new Varargs.PairVarargs(v[0], v[1]);
+ default:
+ return new Varargs.ArrayVarargs(v, r);
+ }
+ }
+
+ /**
+ * Construct a {@link Varargs} around an array of {@link LuaValue}s.
+ *
+ * @param v The array of {@link LuaValue}s
+ * @param offset number of initial values to skip in the array
+ * @param length number of values to include from the array
+ * @return {@link Varargs} wrapping the supplied values.
+ * @see LuaValue#varargsOf(LuaValue[])
+ * @see LuaValue#varargsOf(LuaValue[], int, int, Varargs)
+ */
+ public static Varargs varargsOf(final LuaValue[] v, final int offset, final int length) {
+ switch (length) {
+ case 0:
+ return NONE;
+ case 1:
+ return v[offset];
+ case 2:
+ return new Varargs.PairVarargs(v[offset+0], v[offset+1]);
+ default:
+ return new Varargs.ArrayPartVarargs(v, offset, length, NONE);
+ }
+ }
+
+ /**
+ * Construct a {@link Varargs} around an array of {@link LuaValue}s.
+ *
+ * Caller must ensure that array contents are not mutated after this call or
+ * undefined behavior will result.
+ *
+ * @param v The array of {@link LuaValue}s
+ * @param offset number of initial values to skip in the array
+ * @param length number of values to include from the array
+ * @param more {@link Varargs} contain values to include at the end
+ * @return {@link Varargs} wrapping the supplied values.
+ * @see LuaValue#varargsOf(LuaValue[], Varargs)
+ * @see LuaValue#varargsOf(LuaValue[], int, int)
+ */
+ public static Varargs varargsOf(final LuaValue[] v, final int offset, final int length, Varargs more) {
+ switch (length) {
+ case 0:
+ return more;
+ case 1:
+ return more.narg() > 0? (Varargs) new Varargs.PairVarargs(v[offset], more): (Varargs) v[offset];
+ case 2:
+ return more.narg() > 0? (Varargs) new Varargs.ArrayPartVarargs(v, offset, length, more)
+ : (Varargs) new Varargs.PairVarargs(v[offset], v[offset+1]);
+ default:
+ return new Varargs.ArrayPartVarargs(v, offset, length, more);
+ }
+ }
+
+ /**
+ * Construct a {@link Varargs} around a set of 2 or more {@link LuaValue}s.
+ *
+ * This can be used to wrap exactly 2 values, or a list consisting of 1
+ * initial value followed by another variable list of remaining values.
+ *
+ * @param v First {@link LuaValue} in the {@link Varargs}
+ * @param r {@link LuaValue} supplying the 2rd value, or {@link Varargs}s
+ * supplying all values beyond the first
+ * @return {@link Varargs} wrapping the supplied values.
+ */
+ public static Varargs varargsOf(LuaValue v, Varargs r) {
+ switch (r.narg()) {
+ case 0:
+ return v;
+ default:
+ return new Varargs.PairVarargs(v, r);
+ }
+ }
+
+ /**
+ * Construct a {@link Varargs} around a set of 3 or more {@link LuaValue}s.
+ *
+ * This can be used to wrap exactly 3 values, or a list consisting of 2
+ * initial values followed by another variable list of remaining values.
+ *
+ * @param v1 First {@link LuaValue} in the {@link Varargs}
+ * @param v2 Second {@link LuaValue} in the {@link Varargs}
+ * @param v3 {@link LuaValue} supplying the 3rd value, or {@link Varargs}s
+ * supplying all values beyond the second
+ * @return {@link Varargs} wrapping the supplied values.
+ */
+ public static Varargs varargsOf(LuaValue v1, LuaValue v2, Varargs v3) {
+ switch (v3.narg()) {
+ case 0:
+ return new Varargs.PairVarargs(v1, v2);
+ default:
+ return new Varargs.ArrayPartVarargs(new LuaValue[] { v1, v2 }, 0, 2, v3);
+ }
+ }
+
+ /**
+ * Construct a {@link TailcallVarargs} around a function and arguments.
+ *
+ * The tail call is not yet called or processing until the client invokes
+ * {@link TailcallVarargs#eval()} which performs the tail call processing.
+ *
+ * This method is typically not used directly by client code. Instead use
+ * one of the function invocation methods.
+ *
+ * @param func {@link LuaValue} to be called as a tail call
+ * @param args {@link Varargs} containing the arguments to the call
+ * @return {@link TailcallVarargs} to be used in tailcall oprocessing.
+ * @see LuaValue#call()
+ * @see LuaValue#invoke()
+ * @see LuaValue#method(LuaValue)
+ * @see LuaValue#invokemethod(LuaValue)
+ */
+ public static Varargs tailcallOf(LuaValue func, Varargs args) {
+ return new TailcallVarargs(func, args);
+ }
+
+ /**
+ * Callback used during tail call processing to invoke the function once.
+ *
+ * This may return a {@link TailcallVarargs} to be evaluated by the client.
+ *
+ * This should not be called directly, instead use one of the call
+ * invocation functions.
+ *
+ * @param args the arguments to the call invocation.
+ * @return Varargs the return values, possible a TailcallVarargs.
+ * @see LuaValue#call()
+ * @see LuaValue#invoke()
+ * @see LuaValue#method(LuaValue)
+ * @see LuaValue#invokemethod(LuaValue)
+ */
+ public Varargs onInvoke(Varargs args) {
+ return invoke(args);
+ }
+
+ /**
+ * Hook for implementations such as LuaJC to load the environment of the
+ * main chunk into the first upvalue location. If the function has no
+ * upvalues or is not a main chunk, calling this will be no effect.
+ *
+ * @param env The environment to load into the first upvalue, if there is
+ * one.
+ */
+ public void initupvalue1(LuaValue env) {}
+
+ /**
+ * Varargs implemenation with no values.
+ *
+ * This is an internal class not intended to be used directly. Instead use
+ * the predefined constant {@link LuaValue#NONE}
+ *
+ * @see LuaValue#NONE
+ */
+ private static final class None extends LuaNil {
+ static None _NONE = new None();
+
+ @Override
+ public LuaValue arg(int i) { return NIL; }
+
+ @Override
+ public int narg() { return 0; }
+
+ @Override
+ public LuaValue arg1() { return NIL; }
+
+ @Override
+ public String tojstring() { return "none"; }
+
+ @Override
+ public Varargs subargs(final int start) { return start > 0? this: argerror(1, "start must be > 0"); }
+
+ @Override
+ void copyto(LuaValue[] dest, int offset, int length) {
+ for (; length > 0; length--)
+ dest[offset++] = NIL;
+ }
+ }
+
+ /**
+ * Create a {@code Varargs} instance containing arguments starting at index
+ * {@code start}
+ *
+ * @param start the index from which to include arguments, where 1 is the
+ * first argument.
+ * @return Varargs containing argument { start, start+1, ... , narg-start-1
+ * }
+ */
+ @Override
+ public Varargs subargs(final int start) {
+ if (start == 1)
+ return this;
+ if (start > 1)
+ return NONE;
+ return argerror(1, "start must be > 0");
+ }
+
+}
diff --git a/src/core/org/luaj/vm2/Metatable.java b/luaj-core/src/main/java/org/luaj/vm2/Metatable.java
similarity index 86%
rename from src/core/org/luaj/vm2/Metatable.java
rename to luaj-core/src/main/java/org/luaj/vm2/Metatable.java
index 49c639b6..f57b3647 100644
--- a/src/core/org/luaj/vm2/Metatable.java
+++ b/luaj-core/src/main/java/org/luaj/vm2/Metatable.java
@@ -10,7 +10,7 @@
*
* 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
@@ -29,23 +29,23 @@ import org.luaj.vm2.LuaTable.Slot;
interface Metatable {
/** Return whether or not this table's keys are weak. */
- public boolean useWeakKeys();
+ boolean useWeakKeys();
/** Return whether or not this table's values are weak. */
- public boolean useWeakValues();
+ boolean useWeakValues();
/** Return this metatable as a LuaValue. */
- public LuaValue toLuaValue();
+ LuaValue toLuaValue();
/** Return an instance of Slot appropriate for the given key and value. */
- public Slot entry( LuaValue key, LuaValue value );
+ Slot entry(LuaValue key, LuaValue value);
/** Returns the given value wrapped in a weak reference if appropriate. */
- public LuaValue wrap( LuaValue value );
+ LuaValue wrap(LuaValue value);
/**
- * Returns the value at the given index in the array, or null if it is a weak reference that
- * has been dropped.
+ * Returns the value at the given index in the array, or null if it is a
+ * weak reference that has been dropped.
*/
- public LuaValue arrayget(LuaValue[] array, int index);
+ LuaValue arrayget(LuaValue[] array, int index);
}
diff --git a/src/core/org/luaj/vm2/NonTableMetatable.java b/luaj-core/src/main/java/org/luaj/vm2/NonTableMetatable.java
similarity index 90%
rename from src/core/org/luaj/vm2/NonTableMetatable.java
rename to luaj-core/src/main/java/org/luaj/vm2/NonTableMetatable.java
index 4cf112a8..6fa72761 100644
--- a/src/core/org/luaj/vm2/NonTableMetatable.java
+++ b/luaj-core/src/main/java/org/luaj/vm2/NonTableMetatable.java
@@ -10,26 +10,32 @@ class NonTableMetatable implements Metatable {
this.value = value;
}
+ @Override
public boolean useWeakKeys() {
return false;
}
+ @Override
public boolean useWeakValues() {
return false;
}
+ @Override
public LuaValue toLuaValue() {
return value;
}
+ @Override
public Slot entry(LuaValue key, LuaValue value) {
return LuaTable.defaultEntry(key, value);
}
+ @Override
public LuaValue wrap(LuaValue value) {
return value;
}
+ @Override
public LuaValue arrayget(LuaValue[] array, int index) {
return array[index];
}
diff --git a/src/core/org/luaj/vm2/OrphanedThread.java b/luaj-core/src/main/java/org/luaj/vm2/OrphanedThread.java
similarity index 98%
rename from src/core/org/luaj/vm2/OrphanedThread.java
rename to luaj-core/src/main/java/org/luaj/vm2/OrphanedThread.java
index b3c931f1..24337a32 100644
--- a/src/core/org/luaj/vm2/OrphanedThread.java
+++ b/luaj-core/src/main/java/org/luaj/vm2/OrphanedThread.java
@@ -10,7 +10,7 @@
*
* 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
@@ -29,7 +29,8 @@ package org.luaj.vm2;
* {@link LuaThread} being used as a coroutine that could not possibly be
* resumed again because there are no more references to the LuaThread with
* which it is associated. Rather than locking up resources forever, this error
- * is thrown, and should fall through all the way to the thread's {@link Thread#run()} method.
+ * is thrown, and should fall through all the way to the thread's
+ * {@link Thread#run()} method.
*
* Java code mixed with the luaj vm should not catch this error because it may
* occur when the coroutine is not running, so any processing done during error
diff --git a/src/core/org/luaj/vm2/Print.java b/luaj-core/src/main/java/org/luaj/vm2/Print.java
similarity index 62%
rename from src/core/org/luaj/vm2/Print.java
rename to luaj-core/src/main/java/org/luaj/vm2/Print.java
index 8b0bd572..08ca99be 100644
--- a/src/core/org/luaj/vm2/Print.java
+++ b/luaj-core/src/main/java/org/luaj/vm2/Print.java
@@ -10,7 +10,7 @@
*
* 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
@@ -25,131 +25,96 @@ import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
/**
- * Debug helper class to pretty-print lua bytecodes.
+ * Debug helper class to pretty-print lua bytecodes.
+ *
* @see Prototype
- * @see LuaClosure
+ * @see LuaClosure
*/
public class Print extends Lua {
/** opcode names */
private static final String STRING_FOR_NULL = "null";
- public static PrintStream ps = System.out;
+ public static PrintStream ps = System.out;
/** String names for each lua opcode value. */
- public static final String[] OPNAMES = {
- "MOVE",
- "LOADK",
- "LOADKX",
- "LOADBOOL",
- "LOADNIL",
- "GETUPVAL",
- "GETTABUP",
- "GETTABLE",
- "SETTABUP",
- "SETUPVAL",
- "SETTABLE",
- "NEWTABLE",
- "SELF",
- "ADD",
- "SUB",
- "MUL",
- "DIV",
- "MOD",
- "POW",
- "UNM",
- "NOT",
- "LEN",
- "CONCAT",
- "JMP",
- "EQ",
- "LT",
- "LE",
- "TEST",
- "TESTSET",
- "CALL",
- "TAILCALL",
- "RETURN",
- "FORLOOP",
- "FORPREP",
- "TFORCALL",
- "TFORLOOP",
- "SETLIST",
- "CLOSURE",
- "VARARG",
- "EXTRAARG",
- null,
- };
-
+ public static final String[] OPNAMES = { "MOVE", "LOADK", "LOADKX", "LOADBOOL", "LOADNIL", "GETUPVAL", "GETTABUP",
+ "GETTABLE", "SETTABUP", "SETUPVAL", "SETTABLE", "NEWTABLE", "SELF", "ADD", "SUB", "MUL", "DIV", "MOD",
+ "POW", "UNM", "NOT", "LEN", "CONCAT", "JMP", "EQ", "LT", "LE", "TEST", "TESTSET", "CALL", "TAILCALL",
+ "RETURN", "FORLOOP", "FORPREP", "TFORCALL", "TFORLOOP", "SETLIST", "CLOSURE", "VARARG", "EXTRAARG", null, };
static void printString(PrintStream ps, final LuaString s) {
-
+
ps.print('"');
for (int i = 0, n = s.m_length; i < n; i++) {
int c = s.m_bytes[s.m_offset+i];
- if ( c >= ' ' && c <= '~' && c != '\"' && c != '\\' )
+ if (c >= ' ' && c <= '~' && c != '\"' && c != '\\')
ps.print((char) c);
else {
switch (c) {
- case '"':
- ps.print("\\\"");
- break;
- case '\\':
- ps.print("\\\\");
- break;
- case 0x0007: /* bell */
- ps.print("\\a");
- break;
- case '\b': /* backspace */
- ps.print("\\b");
- break;
- case '\f': /* form feed */
- ps.print("\\f");
- break;
- case '\t': /* tab */
- ps.print("\\t");
- break;
- case '\r': /* carriage return */
- ps.print("\\r");
- break;
- case '\n': /* newline */
- ps.print("\\n");
- break;
- case 0x000B: /* vertical tab */
- ps.print("\\v");
- break;
- default:
- ps.print('\\');
- ps.print(Integer.toString(1000 + 0xff&c).substring(1));
- break;
+ case '"':
+ ps.print("\\\"");
+ break;
+ case '\\':
+ ps.print("\\\\");
+ break;
+ case 0x0007: /* bell */
+ ps.print("\\a");
+ break;
+ case '\b': /* backspace */
+ ps.print("\\b");
+ break;
+ case '\f': /* form feed */
+ ps.print("\\f");
+ break;
+ case '\t': /* tab */
+ ps.print("\\t");
+ break;
+ case '\r': /* carriage return */
+ ps.print("\\r");
+ break;
+ case '\n': /* newline */
+ ps.print("\\n");
+ break;
+ case 0x000B: /* vertical tab */
+ ps.print("\\v");
+ break;
+ default:
+ ps.print('\\');
+ ps.print(Integer.toString(1000+0xff & c).substring(1));
+ break;
}
}
}
ps.print('"');
}
- static void printValue( PrintStream ps, LuaValue v ) {
+ static void printValue(PrintStream ps, LuaValue v) {
if (v == null) {
ps.print("null");
return;
}
- switch ( v.type() ) {
- case LuaValue.TSTRING: printString( ps, (LuaString) v ); break;
- default: ps.print( v.tojstring() );
-
+ switch (v.type()) {
+ case LuaValue.TSTRING:
+ printString(ps, (LuaString) v);
+ break;
+ default:
+ ps.print(v.tojstring());
+
}
}
-
+
static void printConstant(PrintStream ps, Prototype f, int i) {
- printValue( ps, i < f.k.length ? f.k[i] : LuaValue.valueOf("UNKNOWN_CONST_" + i) );
+ printValue(ps, i < f.k.length? f.k[i]: LuaValue.valueOf("UNKNOWN_CONST_" + i));
}
static void printUpvalue(PrintStream ps, Upvaldesc u) {
- ps.print( u.idx + " " );
- printValue( ps, u.name );
+ ps.print(u.idx + " ");
+ printValue(ps, u.name);
}
- /**
+ /**
* Print the code in a prototype
+ *
* @param f the {@link Prototype}
*/
public static void printCode(Prototype f) {
@@ -161,20 +126,22 @@ public class Print extends Lua {
}
}
- /**
+ /**
* Print an opcode in a prototype
- * @param f the {@link Prototype}
+ *
+ * @param f the {@link Prototype}
* @param pc the program counter to look up and print
* @return pc same as above or changed
*/
public static int printOpCode(Prototype f, int pc) {
- return printOpCode(ps,f,pc);
+ return printOpCode(ps, f, pc);
}
-
- /**
+
+ /**
* Print an opcode in a prototype
+ *
* @param ps the {@link PrintStream} to print to
- * @param f the {@link Prototype}
+ * @param f the {@link Prototype}
* @param pc the program counter to look up and print
* @return pc same as above or changed
*/
@@ -188,33 +155,33 @@ public class Print extends Lua {
int bx = GETARG_Bx(i);
int sbx = GETARG_sBx(i);
int line = getline(f, pc);
- ps.print(" " + (pc + 1) + " ");
+ ps.print(" " + (pc+1) + " ");
if (line > 0)
ps.print("[" + line + "] ");
else
ps.print("[-] ");
- if (o >= OPNAMES.length - 1) {
+ if (o >= OPNAMES.length-1) {
ps.print("UNKNOWN_OP_" + o + " ");
} else {
ps.print(OPNAMES[o] + " ");
switch (getOpMode(o)) {
case iABC:
- ps.print( a );
+ ps.print(a);
if (getBMode(o) != OpArgN)
- ps.print(" "+(ISK(b) ? (-1 - INDEXK(b)) : b));
+ ps.print(" " + (ISK(b)? -1-INDEXK(b): b));
if (getCMode(o) != OpArgN)
- ps.print(" "+(ISK(c) ? (-1 - INDEXK(c)) : c));
+ ps.print(" " + (ISK(c)? -1-INDEXK(c): c));
break;
case iABx:
if (getBMode(o) == OpArgK) {
- ps.print(a + " " + (-1 - bx));
+ ps.print(a + " " + (-1-bx));
} else {
- ps.print(a + " " + (bx));
+ ps.print(a + " " + bx);
}
break;
case iAsBx:
if (o == OP_JMP)
- ps.print( sbx );
+ ps.print(sbx);
else
ps.print(a + " " + sbx);
break;
@@ -231,7 +198,7 @@ public class Print extends Lua {
printUpvalue(ps, f.upvalues[b]);
} else {
ps.print("UNKNOWN_UPVALUE_" + b);
- }
+ }
break;
case OP_GETTABUP:
ps.print(" ; ");
@@ -296,7 +263,7 @@ public class Print extends Lua {
case OP_JMP:
case OP_FORLOOP:
case OP_FORPREP:
- ps.print(" ; to " + (sbx + pc + 2));
+ ps.print(" ; to " + (sbx+pc+2));
break;
case OP_CLOSURE:
if (bx < f.p.length) {
@@ -307,13 +274,13 @@ public class Print extends Lua {
break;
case OP_SETLIST:
if (c == 0)
- ps.print(" ; " + ((int) code[++pc]) + " (stored in the next OP)");
+ ps.print(" ; " + code[++pc] + " (stored in the next OP)");
else
- ps.print(" ; " + ((int) c));
+ ps.print(" ; " + c);
break;
case OP_VARARG:
- ps.print( " ; is_vararg="+ f.is_vararg );
- break;
+ ps.print(" ; is_vararg=" + f.is_vararg);
+ break;
default:
break;
}
@@ -322,7 +289,7 @@ public class Print extends Lua {
}
private static int getline(Prototype f, int pc) {
- return pc>0 && f.lineinfo!=null && pc
+ * Generally, the {@link Prototype} is not constructed directly is an
+ * intermediate result as lua code is loaded using
+ * {@link Globals#load(java.io.Reader, String)}:
+ *
+ *
+ * To create a {@link Prototype} directly, a compiler such as
+ * {@link org.luaj.vm2.compiler.LuaC} may be used:
+ *
+ *
+ *
+ * @see LuaClosure
+ * @see Globals
+ * @see Globals#undumper
+ * @see Globals#compiler
+ * @see Print#print
+ */
+
+public class Prototype {
+ /* constants used by the function */
+ public LuaValue[] k;
+ public int[] code;
+ /* functions defined inside the function */
+ public Prototype[] p;
+ /* map from opcodes to source lines */
+ public int[] lineinfo;
+ /* information about local variables */
+ public LocVars[] locvars;
+ /* upvalue information */
+ public Upvaldesc[] upvalues;
+ public LuaString source;
+ public int linedefined;
+ public int lastlinedefined;
+ public int numparams;
+ public int is_vararg;
+ public int maxstacksize;
+ private static final Upvaldesc[] NOUPVALUES = {};
+ private static final Prototype[] NOSUBPROTOS = {};
+
+ public Prototype() {
+ p = NOSUBPROTOS;
+ upvalues = NOUPVALUES;
+ }
+
+ public Prototype(int n_upvalues) {
+ p = NOSUBPROTOS;
+ upvalues = new Upvaldesc[n_upvalues];
+ }
+
+ @Override
+ public String toString() {
+ return source + ":" + linedefined + "-" + lastlinedefined;
+ }
+
+ /**
+ * Get the name of a local variable.
+ *
+ * @param number the local variable number to look up
+ * @param pc the program counter
+ * @return the name, or null if not found
+ */
+ public LuaString getlocalname(int number, int pc) {
+ int i;
+ for (i = 0; i < locvars.length && locvars[i].startpc <= pc; i++) {
+ if (pc < locvars[i].endpc) { /* is variable active? */
+ number--;
+ if (number == 0)
+ return locvars[i].varname;
+ }
+ }
+ return null; /* not found */
+ }
+
+ public String shortsource() {
+ String name = source.tojstring();
+ if (name.startsWith("@") || name.startsWith("="))
+ name = name.substring(1);
+ else if (name.startsWith("\033"))
+ name = "binary string";
+ return name;
+ }
+}
diff --git a/src/core/org/luaj/vm2/TailcallVarargs.java b/luaj-core/src/main/java/org/luaj/vm2/TailcallVarargs.java
similarity index 73%
rename from src/core/org/luaj/vm2/TailcallVarargs.java
rename to luaj-core/src/main/java/org/luaj/vm2/TailcallVarargs.java
index 69eebc5b..bdd9e914 100644
--- a/src/core/org/luaj/vm2/TailcallVarargs.java
+++ b/luaj-core/src/main/java/org/luaj/vm2/TailcallVarargs.java
@@ -10,7 +10,7 @@
*
* 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
@@ -22,44 +22,43 @@
package org.luaj.vm2;
/**
- * Subclass of {@link Varargs} that represents a lua tail call
- * in a Java library function execution environment.
+ * Subclass of {@link Varargs} that represents a lua tail call in a Java library
+ * function execution environment.
*
- * Since Java doesn't have direct support for tail calls,
- * any lua function whose {@link Prototype} contains the
- * {@link Lua#OP_TAILCALL} bytecode needs a mechanism
- * for tail calls when converting lua-bytecode to java-bytecode.
+ * Since Java doesn't have direct support for tail calls, any lua function whose
+ * {@link Prototype} contains the {@link Lua#OP_TAILCALL} bytecode needs a
+ * mechanism for tail calls when converting lua-bytecode to java-bytecode.
*
- * The tail call holds the next function and arguments,
- * and the client a call to {@link #eval()} executes the function
- * repeatedly until the tail calls are completed.
+ * The tail call holds the next function and arguments, and the client a call to
+ * {@link #eval()} executes the function repeatedly until the tail calls are
+ * completed.
*
- * Normally, users of luaj need not concern themselves with the
- * details of this mechanism, as it is built into the core
- * execution framework.
- * @see Prototype
+ * Normally, users of luaj need not concern themselves with the details of this
+ * mechanism, as it is built into the core execution framework.
+ *
+ * @see Prototype
* @see org.luaj.vm2.luajc.LuaJC
*/
public class TailcallVarargs extends Varargs {
private LuaValue func;
- private Varargs args;
- private Varargs result;
-
+ private Varargs args;
+ private Varargs result;
+
public TailcallVarargs(LuaValue f, Varargs args) {
this.func = f;
this.args = args;
}
-
+
public TailcallVarargs(LuaValue object, LuaValue methodname, Varargs args) {
this.func = object.get(methodname);
this.args = LuaValue.varargsOf(object, args);
}
-
- public boolean isTailcall() {
- return true;
- }
-
+
+ @Override
+ public boolean isTailcall() { return true; }
+
+ @Override
public Varargs eval() {
while ( result == null ) {
Varargs r = func.onInvoke(args);
@@ -67,37 +66,40 @@ public class TailcallVarargs extends Varargs {
TailcallVarargs t = (TailcallVarargs) r;
func = t.func;
args = t.args;
- }
- else {
- result = r;
+ } else {
+ result = r;
func = null;
args = null;
}
}
return result;
}
-
- public LuaValue arg( int i ) {
- if ( result == null )
+
+ @Override
+ public LuaValue arg(int i) {
+ if (result == null)
eval();
return result.arg(i);
}
-
+
+ @Override
public LuaValue arg1() {
if (result == null)
eval();
return result.arg1();
}
-
+
+ @Override
public int narg() {
if (result == null)
eval();
return result.narg();
}
+ @Override
public Varargs subargs(int start) {
if (result == null)
eval();
return result.subargs(start);
}
-}
\ No newline at end of file
+}
diff --git a/src/core/org/luaj/vm2/UpValue.java b/luaj-core/src/main/java/org/luaj/vm2/UpValue.java
similarity index 84%
rename from src/core/org/luaj/vm2/UpValue.java
rename to luaj-core/src/main/java/org/luaj/vm2/UpValue.java
index 8fa8186b..3e746974 100644
--- a/src/core/org/luaj/vm2/UpValue.java
+++ b/luaj-core/src/main/java/org/luaj/vm2/UpValue.java
@@ -10,7 +10,7 @@
*
* 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
@@ -21,60 +21,62 @@
******************************************************************************/
package org.luaj.vm2;
-
-/** Upvalue used with Closure formulation
+/**
+ * Upvalue used with Closure formulation
*
+ *
* @see LuaClosure
* @see Prototype
*/
public final class UpValue {
- LuaValue[] array; // initially the stack, becomes a holder
- int index;
+ LuaValue[] array; // initially the stack, becomes a holder
+ int index;
/**
- * Create an upvalue relative to a stack
+ * Create an upvalue relative to a stack
+ *
* @param stack the stack
* @param index the index on the stack for the upvalue
*/
- public UpValue( LuaValue[] stack, int index) {
+ public UpValue(LuaValue[] stack, int index) {
this.array = stack;
this.index = index;
}
+ @Override
public String toString() {
return index + "/" + array.length + " " + array[index];
}
-
- /**
+
+ /**
* Convert this upvalue to a Java String
+ *
* @return the Java String for this upvalue.
* @see LuaValue#tojstring()
*/
public String tojstring() {
return array[index].tojstring();
}
-
+
/**
* Get the value of the upvalue
+ *
* @return the {@link LuaValue} for this upvalue
*/
- public final LuaValue getValue() {
- return array[index];
- }
-
+ public LuaValue getValue() { return array[index]; }
+
/**
* Set the value of the upvalue
+ *
* @param value the {@link LuaValue} to set it to
*/
- public final void setValue( LuaValue value ) {
- array[index] = value;
- }
-
+ public void setValue(LuaValue value) { array[index] = value; }
+
/**
* Close this upvalue so it is no longer on the stack
*/
- public final void close() {
+ public void close() {
LuaValue[] old = array;
array = new LuaValue[] { old[index] };
old[index] = null;
diff --git a/src/core/org/luaj/vm2/Upvaldesc.java b/luaj-core/src/main/java/org/luaj/vm2/Upvaldesc.java
similarity index 95%
rename from src/core/org/luaj/vm2/Upvaldesc.java
rename to luaj-core/src/main/java/org/luaj/vm2/Upvaldesc.java
index c1e44974..26233892 100644
--- a/src/core/org/luaj/vm2/Upvaldesc.java
+++ b/luaj-core/src/main/java/org/luaj/vm2/Upvaldesc.java
@@ -10,7 +10,7 @@
*
* 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
@@ -25,20 +25,21 @@ public class Upvaldesc {
/* upvalue name (for debug information) */
public LuaString name;
-
+
/* whether it is in stack */
public final boolean instack;
-
+
/* index of upvalue (in stack or in outer function's list) */
public final short idx;
-
+
public Upvaldesc(LuaString name, boolean instack, int idx) {
this.name = name;
this.instack = instack;
this.idx = (short) idx;
}
-
+
+ @Override
public String toString() {
- return idx + (instack? " instack ": " closed ") + String.valueOf(name);
+ return idx+(instack? " instack ": " closed ")+String.valueOf(name);
}
}
diff --git a/src/core/org/luaj/vm2/Varargs.java b/luaj-core/src/main/java/org/luaj/vm2/Varargs.java
similarity index 52%
rename from src/core/org/luaj/vm2/Varargs.java
rename to luaj-core/src/main/java/org/luaj/vm2/Varargs.java
index e56d8dcf..2d4b92cb 100644
--- a/src/core/org/luaj/vm2/Varargs.java
+++ b/luaj-core/src/main/java/org/luaj/vm2/Varargs.java
@@ -10,7 +10,7 @@
*
* 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
@@ -22,21 +22,23 @@
package org.luaj.vm2;
/**
- * Class to encapsulate varargs values, either as part of a variable argument list, or multiple return values.
+ * Class to encapsulate varargs values, either as part of a variable argument
+ * list, or multiple return values.
*
* To construct varargs, use one of the static methods such as
* {@code LuaValue.varargsOf(LuaValue,LuaValue)}
*
*
- * Any LuaValue can be used as a stand-in for Varargs, for both calls and return values.
- * When doing so, nargs() will return 1 and arg1() or arg(1) will return this.
- * This simplifies the case when calling or implementing varargs functions with only
- * 1 argument or 1 return value.
+ * Any LuaValue can be used as a stand-in for Varargs, for both calls and return
+ * values. When doing so, nargs() will return 1 and arg1() or arg(1) will return
+ * this. This simplifies the case when calling or implementing varargs functions
+ * with only 1 argument or 1 return value.
*
- * Varargs can also be derived from other varargs by appending to the front with a call
- * such as {@code LuaValue.varargsOf(LuaValue,Varargs)}
- * or by taking a portion of the args using {@code Varargs.subargs(int start)}
+ * Varargs can also be derived from other varargs by appending to the front with
+ * a call such as {@code LuaValue.varargsOf(LuaValue,Varargs)} or by taking a
+ * portion of the args using {@code Varargs.subargs(int start)}
*
+ *
* @see LuaValue#varargsOf(LuaValue[])
* @see LuaValue#varargsOf(LuaValue, Varargs)
* @see LuaValue#varargsOf(LuaValue[], Varargs)
@@ -49,22 +51,26 @@ public abstract class Varargs {
/**
* Get the n-th argument value (1-based).
+ *
* @param i the index of the argument to get, 1 is the first argument
* @return Value at position i, or LuaValue.NIL if there is none.
* @see Varargs#arg1()
* @see LuaValue#NIL
*/
- abstract public LuaValue arg( int i );
-
+ abstract public LuaValue arg(int i);
+
/**
* Get the number of arguments, or 0 if there are none.
+ *
* @return number of arguments.
*/
abstract public int narg();
-
+
/**
* Get the first argument in the list.
- * @return LuaValue which is first in the list, or LuaValue.NIL if there are no values.
+ *
+ * @return LuaValue which is first in the list, or LuaValue.NIL if there are
+ * no values.
* @see Varargs#arg(int)
* @see LuaValue#NIL
*/
@@ -72,25 +78,28 @@ public abstract class Varargs {
/**
* Evaluate any pending tail call and return result.
+ *
* @return the evaluated tail call result
*/
public Varargs eval() { return this; }
-
+
/**
* Return true if this is a TailcallVarargs
+ *
* @return true if a tail call, false otherwise
*/
- public boolean isTailcall() {
- return false;
- }
-
+ public boolean isTailcall() { return false; }
+
// -----------------------------------------------------------------------
// utilities to get specific arguments and type-check them.
// -----------------------------------------------------------------------
-
- /** Gets the type of argument {@code i}
+
+ /**
+ * Gets the type of argument {@code i}
+ *
* @param i the index of the argument to convert, 1 is the first argument
- * @return int value corresponding to one of the LuaValue integer type values
+ * @return int value corresponding to one of the LuaValue integer type
+ * values
* @see LuaValue#TNIL
* @see LuaValue#TBOOLEAN
* @see LuaValue#TNUMBER
@@ -99,438 +108,626 @@ public abstract class Varargs {
* @see LuaValue#TFUNCTION
* @see LuaValue#TUSERDATA
* @see LuaValue#TTHREAD
- * */
- public int type(int i) { return arg(i).type(); }
-
- /** Tests if argument i is nil.
+ */
+ public int type(int i) { return arg(i).type(); }
+
+ /**
+ * Tests if argument i is nil.
+ *
* @param i the index of the argument to test, 1 is the first argument
* @return true if the argument is nil or does not exist, false otherwise
* @see LuaValue#TNIL
- * */
- public boolean isnil(int i) { return arg(i).isnil(); }
+ */
+ public boolean isnil(int i) { return arg(i).isnil(); }
- /** Tests if argument i is a function.
+ /**
+ * Tests if argument i is a function.
+ *
* @param i the index of the argument to test, 1 is the first argument
- * @return true if the argument exists and is a function or closure, false otherwise
+ * @return true if the argument exists and is a function or closure, false
+ * otherwise
* @see LuaValue#TFUNCTION
- * */
- public boolean isfunction(int i) { return arg(i).isfunction(); }
+ */
+ public boolean isfunction(int i) { return arg(i).isfunction(); }
- /** Tests if argument i is a number.
- * Since anywhere a number is required, a string can be used that
- * is a number, this will return true for both numbers and
- * strings that can be interpreted as numbers.
+ /**
+ * Tests if argument i is a number. Since anywhere a number is required, a
+ * string can be used that is a number, this will return true for both
+ * numbers and strings that can be interpreted as numbers.
+ *
* @param i the index of the argument to test, 1 is the first argument
- * @return true if the argument exists and is a number or
- * string that can be interpreted as a number, false otherwise
+ * @return true if the argument exists and is a number or string that can be
+ * interpreted as a number, false otherwise
* @see LuaValue#TNUMBER
* @see LuaValue#TSTRING
- * */
- public boolean isnumber(int i) { return arg(i).isnumber(); }
+ */
+ public boolean isnumber(int i) { return arg(i).isnumber(); }
- /** Tests if argument i is a string.
- * Since all lua numbers can be used where strings are used,
- * this will return true for both strings and numbers.
+ /**
+ * Tests if argument i is a string. Since all lua numbers can be used where
+ * strings are used, this will return true for both strings and numbers.
+ *
* @param i the index of the argument to test, 1 is the first argument
- * @return true if the argument exists and is a string or number, false otherwise
+ * @return true if the argument exists and is a string or number, false
+ * otherwise
* @see LuaValue#TNUMBER
* @see LuaValue#TSTRING
- * */
- public boolean isstring(int i) { return arg(i).isstring(); }
+ */
+ public boolean isstring(int i) { return arg(i).isstring(); }
- /** Tests if argument i is a table.
+ /**
+ * Tests if argument i is a table.
+ *
* @param i the index of the argument to test, 1 is the first argument
* @return true if the argument exists and is a lua table, false otherwise
* @see LuaValue#TTABLE
- * */
- public boolean istable(int i) { return arg(i).istable(); }
+ */
+ public boolean istable(int i) { return arg(i).istable(); }
- /** Tests if argument i is a thread.
+ /**
+ * Tests if argument i is a thread.
+ *
* @param i the index of the argument to test, 1 is the first argument
* @return true if the argument exists and is a lua thread, false otherwise
* @see LuaValue#TTHREAD
- * */
- public boolean isthread(int i) { return arg(i).isthread(); }
+ */
+ public boolean isthread(int i) { return arg(i).isthread(); }
- /** Tests if argument i is a userdata.
+ /**
+ * Tests if argument i is a userdata.
+ *
* @param i the index of the argument to test, 1 is the first argument
* @return true if the argument exists and is a userdata, false otherwise
* @see LuaValue#TUSERDATA
- * */
- public boolean isuserdata(int i) { return arg(i).isuserdata(); }
+ */
+ public boolean isuserdata(int i) { return arg(i).isuserdata(); }
- /** Tests if a value exists at argument i.
+ /**
+ * Tests if a value exists at argument i.
+ *
* @param i the index of the argument to test, 1 is the first argument
* @return true if the argument exists, false otherwise
- * */
- public boolean isvalue(int i) { return i>0 && i<=narg(); }
-
- /** Return argument i as a boolean value, {@code defval} if nil, or throw a LuaError if any other type.
+ */
+ public boolean isvalue(int i) { return i > 0 && i <= narg(); }
+
+ /**
+ * Return argument i as a boolean value, {@code defval} if nil, or throw a
+ * LuaError if any other type.
+ *
* @param i the index of the argument to test, 1 is the first argument
- * @return true if argument i is boolean true, false if it is false, or defval if not supplied or nil
+ * @return true if argument i is boolean true, false if it is false, or
+ * defval if not supplied or nil
* @exception LuaError if the argument is not a lua boolean
- * */
- public boolean optboolean(int i, boolean defval) { return arg(i).optboolean(defval); }
+ */
+ public boolean optboolean(int i, boolean defval) { return arg(i).optboolean(defval); }
- /** Return argument i as a closure, {@code defval} if nil, or throw a LuaError if any other type.
+ /**
+ * Return argument i as a closure, {@code defval} if nil, or throw a
+ * LuaError if any other type.
+ *
* @param i the index of the argument to test, 1 is the first argument
- * @return LuaClosure if argument i is a closure, or defval if not supplied or nil
+ * @return LuaClosure if argument i is a closure, or defval if not supplied
+ * or nil
* @exception LuaError if the argument is not a lua closure
- * */
- public LuaClosure optclosure(int i, LuaClosure defval) { return arg(i).optclosure(defval); }
+ */
+ public LuaClosure optclosure(int i, LuaClosure defval) { return arg(i).optclosure(defval); }
- /** Return argument i as a double, {@code defval} if nil, or throw a LuaError if it cannot be converted to one.
+ /**
+ * Return argument i as a double, {@code defval} if nil, or throw a LuaError
+ * if it cannot be converted to one.
+ *
* @param i the index of the argument to test, 1 is the first argument
- * @return java double value if argument i is a number or string that converts to a number, or defval if not supplied or nil
+ * @return java double value if argument i is a number or string that
+ * converts to a number, or defval if not supplied or nil
* @exception LuaError if the argument is not a number
- * */
- public double optdouble(int i, double defval) { return arg(i).optdouble(defval); }
+ */
+ public double optdouble(int i, double defval) { return arg(i).optdouble(defval); }
- /** Return argument i as a function, {@code defval} if nil, or throw a LuaError if an incompatible type.
+ /**
+ * Return argument i as a function, {@code defval} if nil, or throw a
+ * LuaError if an incompatible type.
+ *
* @param i the index of the argument to test, 1 is the first argument
- * @return LuaValue that can be called if argument i is lua function or closure, or defval if not supplied or nil
+ * @return LuaValue that can be called if argument i is lua function or
+ * closure, or defval if not supplied or nil
* @exception LuaError if the argument is not a lua function or closure
- * */
- public LuaFunction optfunction(int i, LuaFunction defval) { return arg(i).optfunction(defval); }
+ */
+ public LuaFunction optfunction(int i, LuaFunction defval) { return arg(i).optfunction(defval); }
- /** Return argument i as a java int value, discarding any fractional part, {@code defval} if nil, or throw a LuaError if not a number.
+ /**
+ * Return argument i as a java int value, discarding any fractional part,
+ * {@code defval} if nil, or throw a LuaError if not a number.
+ *
* @param i the index of the argument to test, 1 is the first argument
- * @return int value with fraction discarded and truncated if necessary if argument i is number, or defval if not supplied or nil
+ * @return int value with fraction discarded and truncated if necessary if
+ * argument i is number, or defval if not supplied or nil
* @exception LuaError if the argument is not a number
- * */
- public int optint(int i, int defval) { return arg(i).optint(defval); }
+ */
+ public int optint(int i, int defval) { return arg(i).optint(defval); }
- /** Return argument i as a java int value, {@code defval} if nil, or throw a LuaError if not a number or is not representable by a java int.
+ /**
+ * Return argument i as a java int value, {@code defval} if nil, or throw a
+ * LuaError if not a number or is not representable by a java int.
+ *
* @param i the index of the argument to test, 1 is the first argument
- * @return LuaInteger value that fits in a java int without rounding, or defval if not supplied or nil
- * @exception LuaError if the argument cannot be represented by a java int value
- * */
- public LuaInteger optinteger(int i, LuaInteger defval) { return arg(i).optinteger(defval); }
+ * @return LuaInteger value that fits in a java int without rounding, or
+ * defval if not supplied or nil
+ * @exception LuaError if the argument cannot be represented by a java int
+ * value
+ */
+ public LuaInteger optinteger(int i, LuaInteger defval) { return arg(i).optinteger(defval); }
- /** Return argument i as a java long value, discarding any fractional part, {@code defval} if nil, or throw a LuaError if not a number.
+ /**
+ * Return argument i as a java long value, discarding any fractional part,
+ * {@code defval} if nil, or throw a LuaError if not a number.
+ *
* @param i the index of the argument to test, 1 is the first argument
- * @return long value with fraction discarded and truncated if necessary if argument i is number, or defval if not supplied or nil
+ * @return long value with fraction discarded and truncated if necessary if
+ * argument i is number, or defval if not supplied or nil
* @exception LuaError if the argument is not a number
- * */
- public long optlong(int i, long defval) { return arg(i).optlong(defval); }
+ */
+ public long optlong(int i, long defval) { return arg(i).optlong(defval); }
- /** Return argument i as a LuaNumber, {@code defval} if nil, or throw a LuaError if not a number or string that can be converted to a number.
- * @param i the index of the argument to test, 1 is the first argument, or defval if not supplied or nil
+ /**
+ * Return argument i as a LuaNumber, {@code defval} if nil, or throw a
+ * LuaError if not a number or string that can be converted to a number.
+ *
+ * @param i the index of the argument to test, 1 is the first argument, or
+ * defval if not supplied or nil
* @return LuaNumber if argument i is number or can be converted to a number
* @exception LuaError if the argument is not a number
- * */
- public LuaNumber optnumber(int i, LuaNumber defval) { return arg(i).optnumber(defval); }
+ */
+ public LuaNumber optnumber(int i, LuaNumber defval) { return arg(i).optnumber(defval); }
- /** Return argument i as a java String if a string or number, {@code defval} if nil, or throw a LuaError if any other type
+ /**
+ * Return argument i as a java String if a string or number, {@code defval}
+ * if nil, or throw a LuaError if any other type
+ *
* @param i the index of the argument to test, 1 is the first argument
- * @return String value if argument i is a string or number, or defval if not supplied or nil
+ * @return String value if argument i is a string or number, or defval if
+ * not supplied or nil
* @exception LuaError if the argument is not a string or number
- * */
- public String optjstring(int i, String defval) { return arg(i).optjstring(defval); }
+ */
+ public String optjstring(int i, String defval) { return arg(i).optjstring(defval); }
- /** Return argument i as a LuaString if a string or number, {@code defval} if nil, or throw a LuaError if any other type
+ /**
+ * Return argument i as a LuaString if a string or number, {@code defval} if
+ * nil, or throw a LuaError if any other type
+ *
* @param i the index of the argument to test, 1 is the first argument
- * @return LuaString value if argument i is a string or number, or defval if not supplied or nil
+ * @return LuaString value if argument i is a string or number, or defval if
+ * not supplied or nil
* @exception LuaError if the argument is not a string or number
- * */
- public LuaString optstring(int i, LuaString defval) { return arg(i).optstring(defval); }
+ */
+ public LuaString optstring(int i, LuaString defval) { return arg(i).optstring(defval); }
- /** Return argument i as a LuaTable if a lua table, {@code defval} if nil, or throw a LuaError if any other type.
+ /**
+ * Return argument i as a LuaTable if a lua table, {@code defval} if nil, or
+ * throw a LuaError if any other type.
+ *
* @param i the index of the argument to test, 1 is the first argument
* @return LuaTable value if a table, or defval if not supplied or nil
* @exception LuaError if the argument is not a lua table
- * */
- public LuaTable opttable(int i, LuaTable defval) { return arg(i).opttable(defval); }
+ */
+ public LuaTable opttable(int i, LuaTable defval) { return arg(i).opttable(defval); }
- /** Return argument i as a LuaThread if a lua thread, {@code defval} if nil, or throw a LuaError if any other type.
+ /**
+ * Return argument i as a LuaThread if a lua thread, {@code defval} if nil,
+ * or throw a LuaError if any other type.
+ *
* @param i the index of the argument to test, 1 is the first argument
* @return LuaThread value if a thread, or defval if not supplied or nil
* @exception LuaError if the argument is not a lua thread
- * */
- public LuaThread optthread(int i, LuaThread defval) { return arg(i).optthread(defval); }
+ */
+ public LuaThread optthread(int i, LuaThread defval) { return arg(i).optthread(defval); }
- /** Return argument i as a java Object if a userdata, {@code defval} if nil, or throw a LuaError if any other type.
+ /**
+ * Return argument i as a java Object if a userdata, {@code defval} if nil,
+ * or throw a LuaError if any other type.
+ *
* @param i the index of the argument to test, 1 is the first argument
- * @return java Object value if argument i is a userdata, or defval if not supplied or nil
+ * @return java Object value if argument i is a userdata, or defval if not
+ * supplied or nil
* @exception LuaError if the argument is not a userdata
- * */
- public Object optuserdata(int i, Object defval) { return arg(i).optuserdata(defval); }
+ */
+ public Object optuserdata(int i, Object defval) { return arg(i).optuserdata(defval); }
- /** Return argument i as a java Object if it is a userdata whose instance Class c or a subclass,
- * {@code defval} if nil, or throw a LuaError if any other type.
+ /**
+ * Return argument i as a java Object if it is a userdata whose instance
+ * Class c or a subclass, {@code defval} if nil, or throw a LuaError if any
+ * other type.
+ *
* @param i the index of the argument to test, 1 is the first argument
* @param c the class to which the userdata instance must be assignable
- * @return java Object value if argument i is a userdata whose instance Class c or a subclass, or defval if not supplied or nil
- * @exception LuaError if the argument is not a userdata or from whose instance c is not assignable
- * */
- public Object optuserdata(int i, Class c, Object defval) { return arg(i).optuserdata(c,defval); }
+ * @return java Object value if argument i is a userdata whose instance
+ * Class c or a subclass, or defval if not supplied or nil
+ * @exception LuaError if the argument is not a userdata or from whose
+ * instance c is not assignable
+ */
+ public Object optuserdata(int i, Class c, Object defval) { return arg(i).optuserdata(c, defval); }
- /** Return argument i as a LuaValue if it exists, or {@code defval}.
+ /**
+ * Return argument i as a LuaValue if it exists, or {@code defval}.
+ *
* @param i the index of the argument to test, 1 is the first argument
* @return LuaValue value if the argument exists, defval if not
* @exception LuaError if the argument does not exist.
- * */
- public LuaValue optvalue(int i, LuaValue defval) { return i>0 && i<=narg()? arg(i): defval; }
+ */
+ public LuaValue optvalue(int i, LuaValue defval) { return i > 0 && i <= narg()? arg(i): defval; }
- /** Return argument i as a boolean value, or throw an error if any other type.
+ /**
+ * Return argument i as a boolean value, or throw an error if any other
+ * type.
+ *
* @param i the index of the argument to test, 1 is the first argument
* @return true if argument i is boolean true, false if it is false
* @exception LuaError if the argument is not a lua boolean
- * */
- public boolean checkboolean(int i) { return arg(i).checkboolean(); }
+ */
+ public boolean checkboolean(int i) { return arg(i).checkboolean(); }
- /** Return argument i as a closure, or throw an error if any other type.
+ /**
+ * Return argument i as a closure, or throw an error if any other type.
+ *
* @param i the index of the argument to test, 1 is the first argument
* @return LuaClosure if argument i is a closure.
* @exception LuaError if the argument is not a lua closure
- * */
- public LuaClosure checkclosure(int i) { return arg(i).checkclosure(); }
+ */
+ public LuaClosure checkclosure(int i) { return arg(i).checkclosure(); }
- /** Return argument i as a double, or throw an error if it cannot be converted to one.
+ /**
+ * Return argument i as a double, or throw an error if it cannot be
+ * converted to one.
+ *
* @param i the index of the argument to test, 1 is the first argument
- * @return java double value if argument i is a number or string that converts to a number
+ * @return java double value if argument i is a number or string that
+ * converts to a number
* @exception LuaError if the argument is not a number
- * */
- public double checkdouble(int i) { return arg(i).checkdouble(); }
+ */
+ public double checkdouble(int i) { return arg(i).checkdouble(); }
- /** Return argument i as a function, or throw an error if an incompatible type.
+ /**
+ * Return argument i as a function, or throw an error if an incompatible
+ * type.
+ *
* @param i the index of the argument to test, 1 is the first argument
- * @return LuaValue that can be called if argument i is lua function or closure
+ * @return LuaValue that can be called if argument i is lua function or
+ * closure
* @exception LuaError if the argument is not a lua function or closure
- * */
- public LuaFunction checkfunction(int i) { return arg(i).checkfunction(); }
+ */
+ public LuaFunction checkfunction(int i) { return arg(i).checkfunction(); }
- /** Return argument i as a java int value, or throw an error if it cannot be converted to one.
+ /**
+ * Return argument i as a java int value, or throw an error if it cannot be
+ * converted to one.
+ *
* @param i the index of the argument to test, 1 is the first argument
- * @return int value if argument i is a number or string that converts to a number
- * @exception LuaError if the argument cannot be represented by a java int value
- * */
- public int checkint(int i) { return arg(i).checkint(); }
+ * @return int value if argument i is a number or string that converts to a
+ * number
+ * @exception LuaError if the argument cannot be represented by a java int
+ * value
+ */
+ public int checkint(int i) { return arg(i).checkint(); }
- /** Return argument i as a java int value, or throw an error if not a number or is not representable by a java int.
+ /**
+ * Return argument i as a java int value, or throw an error if not a number
+ * or is not representable by a java int.
+ *
* @param i the index of the argument to test, 1 is the first argument
* @return LuaInteger value that fits in a java int without rounding
- * @exception LuaError if the argument cannot be represented by a java int value
- * */
- public LuaInteger checkinteger(int i) { return arg(i).checkinteger(); }
+ * @exception LuaError if the argument cannot be represented by a java int
+ * value
+ */
+ public LuaInteger checkinteger(int i) { return arg(i).checkinteger(); }
- /** Return argument i as a java long value, or throw an error if it cannot be converted to one.
+ /**
+ * Return argument i as a java long value, or throw an error if it cannot be
+ * converted to one.
+ *
* @param i the index of the argument to test, 1 is the first argument
- * @return long value if argument i is a number or string that converts to a number
- * @exception LuaError if the argument cannot be represented by a java long value
- * */
- public long checklong(int i) { return arg(i).checklong(); }
+ * @return long value if argument i is a number or string that converts to a
+ * number
+ * @exception LuaError if the argument cannot be represented by a java long
+ * value
+ */
+ public long checklong(int i) { return arg(i).checklong(); }
- /** Return argument i as a LuaNumber, or throw an error if not a number or string that can be converted to a number.
+ /**
+ * Return argument i as a LuaNumber, or throw an error if not a number or
+ * string that can be converted to a number.
+ *
* @param i the index of the argument to test, 1 is the first argument
* @return LuaNumber if argument i is number or can be converted to a number
* @exception LuaError if the argument is not a number
- * */
- public LuaNumber checknumber(int i) { return arg(i).checknumber(); }
+ */
+ public LuaNumber checknumber(int i) { return arg(i).checknumber(); }
- /** Return argument i as a java String if a string or number, or throw an error if any other type
+ /**
+ * Return argument i as a java String if a string or number, or throw an
+ * error if any other type
+ *
* @param i the index of the argument to test, 1 is the first argument
* @return String value if argument i is a string or number
* @exception LuaError if the argument is not a string or number
- * */
- public String checkjstring(int i) { return arg(i).checkjstring(); }
+ */
+ public String checkjstring(int i) { return arg(i).checkjstring(); }
- /** Return argument i as a LuaString if a string or number, or throw an error if any other type
+ /**
+ * Return argument i as a LuaString if a string or number, or throw an error
+ * if any other type
+ *
* @param i the index of the argument to test, 1 is the first argument
* @return LuaString value if argument i is a string or number
* @exception LuaError if the argument is not a string or number
- * */
- public LuaString checkstring(int i) { return arg(i).checkstring(); }
+ */
+ public LuaString checkstring(int i) { return arg(i).checkstring(); }
- /** Return argument i as a LuaTable if a lua table, or throw an error if any other type.
+ /**
+ * Return argument i as a LuaTable if a lua table, or throw an error if any
+ * other type.
+ *
* @param i the index of the argument to test, 1 is the first argument
* @return LuaTable value if a table
* @exception LuaError if the argument is not a lua table
- * */
- public LuaTable checktable(int i) { return arg(i).checktable(); }
+ */
+ public LuaTable checktable(int i) { return arg(i).checktable(); }
- /** Return argument i as a LuaThread if a lua thread, or throw an error if any other type.
+ /**
+ * Return argument i as a LuaThread if a lua thread, or throw an error if
+ * any other type.
+ *
* @param i the index of the argument to test, 1 is the first argument
* @return LuaThread value if a thread
* @exception LuaError if the argument is not a lua thread
- * */
- public LuaThread checkthread(int i) { return arg(i).checkthread(); }
+ */
+ public LuaThread checkthread(int i) { return arg(i).checkthread(); }
- /** Return argument i as a java Object if a userdata, or throw an error if any other type.
+ /**
+ * Return argument i as a java Object if a userdata, or throw an error if
+ * any other type.
+ *
* @param i the index of the argument to test, 1 is the first argument
* @return java Object value if argument i is a userdata
* @exception LuaError if the argument is not a userdata
- * */
- public Object checkuserdata(int i) { return arg(i).checkuserdata(); }
+ */
+ public Object checkuserdata(int i) { return arg(i).checkuserdata(); }
- /** Return argument i as a java Object if it is a userdata whose instance Class c or a subclass,
- * or throw an error if any other type.
+ /**
+ * Return argument i as a java Object if it is a userdata whose instance
+ * Class c or a subclass, or throw an error if any other type.
+ *
* @param i the index of the argument to test, 1 is the first argument
* @param c the class to which the userdata instance must be assignable
- * @return java Object value if argument i is a userdata whose instance Class c or a subclass
- * @exception LuaError if the argument is not a userdata or from whose instance c is not assignable
- * */
- public Object checkuserdata(int i,Class c) { return arg(i).checkuserdata(c); }
+ * @return java Object value if argument i is a userdata whose instance
+ * Class c or a subclass
+ * @exception LuaError if the argument is not a userdata or from whose
+ * instance c is not assignable
+ */
+ public Object checkuserdata(int i, Class c) { return arg(i).checkuserdata(c); }
- /** Return argument i as a LuaValue if it exists, or throw an error.
+ /**
+ * Return argument i as a LuaValue if it exists, or throw an error.
+ *
* @param i the index of the argument to test, 1 is the first argument
* @return LuaValue value if the argument exists
* @exception LuaError if the argument does not exist.
- * */
- public LuaValue checkvalue(int i) { return i<=narg()? arg(i): LuaValue.argerror(i,"value expected"); }
+ */
+ public LuaValue checkvalue(int i) { return i <= narg()? arg(i): LuaValue.argerror(i, "value expected"); }
- /** Return argument i as a LuaValue if it is not nil, or throw an error if it is nil.
+ /**
+ * Return argument i as a LuaValue if it is not nil, or throw an error if it
+ * is nil.
+ *
* @param i the index of the argument to test, 1 is the first argument
* @return LuaValue value if the argument is not nil
* @exception LuaError if the argument doesn't exist or evaluates to nil.
- * */
- public LuaValue checknotnil(int i) { return arg(i).checknotnil(); }
-
- /** Performs test on argument i as a LuaValue when a user-supplied assertion passes, or throw an error.
- * Returns normally if the value of {@code test} is {@code true}, otherwise throws and argument error with
- * the supplied message, {@code msg}.
+ */
+ public LuaValue checknotnil(int i) { return arg(i).checknotnil(); }
+
+ /**
+ * Performs test on argument i as a LuaValue when a user-supplied assertion
+ * passes, or throw an error. Returns normally if the value of {@code test}
+ * is {@code true}, otherwise throws and argument error with the supplied
+ * message, {@code msg}.
+ *
* @param test user supplied assertion to test against
- * @param i the index to report in any error message
- * @param msg the error message to use when the test fails
+ * @param i the index to report in any error message
+ * @param msg the error message to use when the test fails
* @exception LuaError if the the value of {@code test} is {@code false}
- * */
- public void argcheck(boolean test, int i, String msg) { if (!test) LuaValue.argerror(i,msg); }
-
- /** Return true if there is no argument or nil at argument i.
+ */
+ public void argcheck(boolean test, int i, String msg) {
+ if (!test)
+ LuaValue.argerror(i, msg);
+ }
+
+ /**
+ * Return true if there is no argument or nil at argument i.
+ *
* @param i the index of the argument to test, 1 is the first argument
* @return true if argument i contains either no argument or nil
- * */
+ */
public boolean isnoneornil(int i) {
- return i>narg() || arg(i).isnil();
+ return i > narg() || arg(i).isnil();
}
-
- /** Convert argument {@code i} to java boolean based on lua rules for boolean evaluation.
- * @param i the index of the argument to convert, 1 is the first argument
- * @return {@code false} if argument i is nil or false, otherwise {@code true}
- * */
- public boolean toboolean(int i) { return arg(i).toboolean(); }
- /** Return argument i as a java byte value, discarding any fractional part and truncating,
- * or 0 if not a number.
+ /**
+ * Convert argument {@code i} to java boolean based on lua rules for boolean
+ * evaluation.
+ *
* @param i the index of the argument to convert, 1 is the first argument
- * @return byte value with fraction discarded and truncated if necessary if argument i is number, otherwise 0
- * */
- public byte tobyte(int i) { return arg(i).tobyte(); }
-
- /** Return argument i as a java char value, discarding any fractional part and truncating,
- * or 0 if not a number.
- * @param i the index of the argument to convert, 1 is the first argument
- * @return char value with fraction discarded and truncated if necessary if argument i is number, otherwise 0
- * */
- public char tochar(int i) { return arg(i).tochar(); }
+ * @return {@code false} if argument i is nil or false, otherwise
+ * {@code true}
+ */
+ public boolean toboolean(int i) { return arg(i).toboolean(); }
- /** Return argument i as a java double value or 0 if not a number.
+ /**
+ * Return argument i as a java byte value, discarding any fractional part
+ * and truncating, or 0 if not a number.
+ *
+ * @param i the index of the argument to convert, 1 is the first argument
+ * @return byte value with fraction discarded and truncated if necessary if
+ * argument i is number, otherwise 0
+ */
+ public byte tobyte(int i) { return arg(i).tobyte(); }
+
+ /**
+ * Return argument i as a java char value, discarding any fractional part
+ * and truncating, or 0 if not a number.
+ *
+ * @param i the index of the argument to convert, 1 is the first argument
+ * @return char value with fraction discarded and truncated if necessary if
+ * argument i is number, otherwise 0
+ */
+ public char tochar(int i) { return arg(i).tochar(); }
+
+ /**
+ * Return argument i as a java double value or 0 if not a number.
+ *
* @param i the index of the argument to convert, 1 is the first argument
* @return double value if argument i is number, otherwise 0
- * */
- public double todouble(int i) { return arg(i).todouble(); }
+ */
+ public double todouble(int i) { return arg(i).todouble(); }
- /** Return argument i as a java float value, discarding excess fractional part and truncating,
- * or 0 if not a number.
+ /**
+ * Return argument i as a java float value, discarding excess fractional
+ * part and truncating, or 0 if not a number.
+ *
* @param i the index of the argument to convert, 1 is the first argument
- * @return float value with excess fraction discarded and truncated if necessary if argument i is number, otherwise 0
- * */
- public float tofloat(int i) { return arg(i).tofloat(); }
-
- /** Return argument i as a java int value, discarding any fractional part and truncating,
- * or 0 if not a number.
- * @param i the index of the argument to convert, 1 is the first argument
- * @return int value with fraction discarded and truncated if necessary if argument i is number, otherwise 0
- * */
- public int toint(int i) { return arg(i).toint(); }
+ * @return float value with excess fraction discarded and truncated if
+ * necessary if argument i is number, otherwise 0
+ */
+ public float tofloat(int i) { return arg(i).tofloat(); }
- /** Return argument i as a java long value, discarding any fractional part and truncating,
- * or 0 if not a number.
+ /**
+ * Return argument i as a java int value, discarding any fractional part and
+ * truncating, or 0 if not a number.
+ *
* @param i the index of the argument to convert, 1 is the first argument
- * @return long value with fraction discarded and truncated if necessary if argument i is number, otherwise 0
- * */
- public long tolong(int i) { return arg(i).tolong(); }
+ * @return int value with fraction discarded and truncated if necessary if
+ * argument i is number, otherwise 0
+ */
+ public int toint(int i) { return arg(i).toint(); }
- /** Return argument i as a java String based on the type of the argument.
+ /**
+ * Return argument i as a java long value, discarding any fractional part
+ * and truncating, or 0 if not a number.
+ *
+ * @param i the index of the argument to convert, 1 is the first argument
+ * @return long value with fraction discarded and truncated if necessary if
+ * argument i is number, otherwise 0
+ */
+ public long tolong(int i) { return arg(i).tolong(); }
+
+ /**
+ * Return argument i as a java String based on the type of the argument.
+ *
* @param i the index of the argument to convert, 1 is the first argument
* @return String value representing the type
- * */
- public String tojstring(int i) { return arg(i).tojstring(); }
-
- /** Return argument i as a java short value, discarding any fractional part and truncating,
- * or 0 if not a number.
- * @param i the index of the argument to convert, 1 is the first argument
- * @return short value with fraction discarded and truncated if necessary if argument i is number, otherwise 0
- * */
- public short toshort(int i) { return arg(i).toshort(); }
+ */
+ public String tojstring(int i) { return arg(i).tojstring(); }
- /** Return argument i as a java Object if a userdata, or null.
+ /**
+ * Return argument i as a java short value, discarding any fractional part
+ * and truncating, or 0 if not a number.
+ *
+ * @param i the index of the argument to convert, 1 is the first argument
+ * @return short value with fraction discarded and truncated if necessary if
+ * argument i is number, otherwise 0
+ */
+ public short toshort(int i) { return arg(i).toshort(); }
+
+ /**
+ * Return argument i as a java Object if a userdata, or null.
+ *
* @param i the index of the argument to convert, 1 is the first argument
* @return java Object value if argument i is a userdata, otherwise null
- * */
- public Object touserdata(int i) { return arg(i).touserdata(); }
+ */
+ public Object touserdata(int i) { return arg(i).touserdata(); }
- /** Return argument i as a java Object if it is a userdata whose instance Class c or a subclass, or null.
+ /**
+ * Return argument i as a java Object if it is a userdata whose instance
+ * Class c or a subclass, or null.
+ *
* @param i the index of the argument to convert, 1 is the first argument
* @param c the class to which the userdata instance must be assignable
- * @return java Object value if argument i is a userdata whose instance Class c or a subclass, otherwise null
- * */
- public Object touserdata(int i,Class c) { return arg(i).touserdata(c); }
-
- /** Convert the list of varargs values to a human readable java String.
+ * @return java Object value if argument i is a userdata whose instance
+ * Class c or a subclass, otherwise null
+ */
+ public Object touserdata(int i, Class c) { return arg(i).touserdata(c); }
+
+ /**
+ * Convert the list of varargs values to a human readable java String.
+ *
* @return String value in human readable form such as {1,2}.
*/
public String tojstring() {
Buffer sb = new Buffer();
- sb.append( "(" );
- for ( int i=1,n=narg(); i<=n; i++ ) {
- if (i>1) sb.append( "," );
- sb.append( arg(i).tojstring() );
+ sb.append("(");
+ for (int i = 1, n = narg(); i <= n; i++) {
+ if (i > 1)
+ sb.append(",");
+ sb.append(arg(i).tojstring());
}
- sb.append( ")" );
+ sb.append(")");
return sb.tojstring();
}
-
- /** Convert the value or values to a java String using Varargs.tojstring()
+
+ /**
+ * Convert the value or values to a java String using Varargs.tojstring()
+ *
* @return String value in human readable form.
* @see Varargs#tojstring()
*/
+ @Override
public String toString() { return tojstring(); }
/**
- * Create a {@code Varargs} instance containing arguments starting at index {@code start}
- * @param start the index from which to include arguments, where 1 is the first argument.
- * @return Varargs containing argument { start, start+1, ... , narg-start-1 }
+ * Create a {@code Varargs} instance containing arguments starting at index
+ * {@code start}
+ *
+ * @param start the index from which to include arguments, where 1 is the
+ * first argument.
+ * @return Varargs containing argument { start, start+1, ... , narg-start-1
+ * }
*/
abstract public Varargs subargs(final int start);
/**
* Implementation of Varargs for use in the Varargs.subargs() function.
+ *
* @see Varargs#subargs(int)
*/
static class SubVarargs extends Varargs {
private final Varargs v;
- private final int start;
- private final int end;
+ private final int start;
+ private final int end;
+
public SubVarargs(Varargs varargs, int start, int end) {
this.v = varargs;
this.start = start;
this.end = end;
}
+
+ @Override
public LuaValue arg(int i) {
i += start-1;
- return i>=start && i<=end? v.arg(i): LuaValue.NIL;
+ return i >= start && i <= end? v.arg(i): LuaValue.NIL;
}
+
+ @Override
public LuaValue arg1() {
return v.arg(start);
}
+
+ @Override
public int narg() {
return end+1-start;
}
+
+ @Override
public Varargs subargs(final int start) {
if (start == 1)
return this;
- final int newstart = this.start + start - 1;
+ final int newstart = this.start+start-1;
if (start > 0) {
if (newstart >= this.end)
return LuaValue.NONE;
@@ -544,111 +741,138 @@ public abstract class Varargs {
}
}
- /** Varargs implemenation backed by two values.
+ /**
+ * Varargs implemenation backed by two values.
*
- * This is an internal class not intended to be used directly.
- * Instead use the corresponding static method on LuaValue.
- *
+ * This is an internal class not intended to be used directly. Instead use
+ * the corresponding static method on LuaValue.
+ *
* @see LuaValue#varargsOf(LuaValue, Varargs)
*/
static final class PairVarargs extends Varargs {
private final LuaValue v1;
- private final Varargs v2;
- /** Construct a Varargs from an two LuaValue.
+ private final Varargs v2;
+
+ /**
+ * Construct a Varargs from an two LuaValue.
*
- * This is an internal class not intended to be used directly.
- * Instead use the corresponding static method on LuaValue.
- *
+ * This is an internal class not intended to be used directly. Instead
+ * use the corresponding static method on LuaValue.
+ *
* @see LuaValue#varargsOf(LuaValue, Varargs)
*/
PairVarargs(LuaValue v1, Varargs v2) {
this.v1 = v1;
this.v2 = v2;
}
+
+ @Override
public LuaValue arg(int i) {
- return i==1? v1: v2.arg(i-1);
+ return i == 1? v1: v2.arg(i-1);
}
+
+ @Override
public int narg() {
return 1+v2.narg();
}
+
+ @Override
public LuaValue arg1() {
return v1;
}
+
+ @Override
public Varargs subargs(final int start) {
if (start == 1)
return this;
if (start == 2)
return v2;
if (start > 2)
- return v2.subargs(start - 1);
+ return v2.subargs(start-1);
return LuaValue.argerror(1, "start must be > 0");
}
}
- /** Varargs implemenation backed by an array of LuaValues
+ /**
+ * Varargs implemenation backed by an array of LuaValues
*
- * This is an internal class not intended to be used directly.
- * Instead use the corresponding static methods on LuaValue.
- *
+ * This is an internal class not intended to be used directly. Instead use
+ * the corresponding static methods on LuaValue.
+ *
* @see LuaValue#varargsOf(LuaValue[])
* @see LuaValue#varargsOf(LuaValue[], Varargs)
*/
static final class ArrayVarargs extends Varargs {
private final LuaValue[] v;
- private final Varargs r;
- /** Construct a Varargs from an array of LuaValue.
+ private final Varargs r;
+
+ /**
+ * Construct a Varargs from an array of LuaValue.
*
- * This is an internal class not intended to be used directly.
- * Instead use the corresponding static methods on LuaValue.
- *
+ * This is an internal class not intended to be used directly. Instead
+ * use the corresponding static methods on LuaValue.
+ *
* @see LuaValue#varargsOf(LuaValue[])
* @see LuaValue#varargsOf(LuaValue[], Varargs)
*/
ArrayVarargs(LuaValue[] v, Varargs r) {
this.v = v;
- this.r = r ;
+ this.r = r;
}
+
+ @Override
public LuaValue arg(int i) {
- return i < 1 ? LuaValue.NIL: i <= v.length? v[i - 1]: r.arg(i-v.length);
+ return i < 1? LuaValue.NIL: i <= v.length? v[i-1]: r.arg(i-v.length);
}
+
+ @Override
public int narg() {
return v.length+r.narg();
}
- public LuaValue arg1() { return v.length>0? v[0]: r.arg1(); }
+
+ @Override
+ public LuaValue arg1() { return v.length > 0? v[0]: r.arg1(); }
+
+ @Override
public Varargs subargs(int start) {
if (start <= 0)
LuaValue.argerror(1, "start must be > 0");
if (start == 1)
return this;
if (start > v.length)
- return r.subargs(start - v.length);
- return LuaValue.varargsOf(v, start - 1, v.length - (start - 1), r);
+ return r.subargs(start-v.length);
+ return LuaValue.varargsOf(v, start-1, v.length-(start-1), r);
}
+
+ @Override
void copyto(LuaValue[] dest, int offset, int length) {
int n = Math.min(v.length, length);
System.arraycopy(v, 0, dest, offset, n);
- r.copyto(dest, offset + n, length - n);
+ r.copyto(dest, offset+n, length-n);
}
}
- /** Varargs implemenation backed by an array of LuaValues
+ /**
+ * Varargs implemenation backed by an array of LuaValues
*
- * This is an internal class not intended to be used directly.
- * Instead use the corresponding static methods on LuaValue.
- *
+ * This is an internal class not intended to be used directly. Instead use
+ * the corresponding static methods on LuaValue.
+ *
* @see LuaValue#varargsOf(LuaValue[], int, int)
* @see LuaValue#varargsOf(LuaValue[], int, int, Varargs)
*/
static final class ArrayPartVarargs extends Varargs {
- private final int offset;
+ private final int offset;
private final LuaValue[] v;
- private final int length;
- private final Varargs more;
- /** Construct a Varargs from an array of LuaValue.
+ private final int length;
+ private final Varargs more;
+
+ /**
+ * Construct a Varargs from an array of LuaValue.
*
- * This is an internal class not intended to be used directly.
- * Instead use the corresponding static methods on LuaValue.
- *
+ * This is an internal class not intended to be used directly. Instead
+ * use the corresponding static methods on LuaValue.
+ *
* @see LuaValue#varargsOf(LuaValue[], int, int)
*/
ArrayPartVarargs(LuaValue[] v, int offset, int length) {
@@ -657,11 +881,14 @@ public abstract class Varargs {
this.length = length;
this.more = LuaValue.NONE;
}
- /** Construct a Varargs from an array of LuaValue and additional arguments.
+
+ /**
+ * Construct a Varargs from an array of LuaValue and additional
+ * arguments.
*
- * This is an internal class not intended to be used directly.
- * Instead use the corresponding static method on LuaValue.
- *
+ * This is an internal class not intended to be used directly. Instead
+ * use the corresponding static method on LuaValue.
+ *
* @see LuaValue#varargsOf(LuaValue[], int, int, Varargs)
*/
public ArrayPartVarargs(LuaValue[] v, int offset, int length, Varargs more) {
@@ -670,52 +897,71 @@ public abstract class Varargs {
this.length = length;
this.more = more;
}
+
+ @Override
public LuaValue arg(final int i) {
return i < 1? LuaValue.NIL: i <= length? v[offset+i-1]: more.arg(i-length);
}
+
+ @Override
public int narg() {
- return length + more.narg();
+ return length+more.narg();
}
+
+ @Override
public LuaValue arg1() {
- return length>0? v[offset]: more.arg1();
+ return length > 0? v[offset]: more.arg1();
}
+
+ @Override
public Varargs subargs(int start) {
if (start <= 0)
LuaValue.argerror(1, "start must be > 0");
if (start == 1)
return this;
if (start > length)
- return more.subargs(start - length);
- return LuaValue.varargsOf(v, offset + start - 1, length - (start - 1), more);
+ return more.subargs(start-length);
+ return LuaValue.varargsOf(v, offset+start-1, length-(start-1), more);
}
+
+ @Override
void copyto(LuaValue[] dest, int offset, int length) {
int n = Math.min(this.length, length);
System.arraycopy(this.v, this.offset, dest, offset, n);
- more.copyto(dest, offset + n, length - n);
+ more.copyto(dest, offset+n, length-n);
}
}
- /** Copy values in a varargs into a destination array.
- * Internal utility method not intended to be called directly from user code.
+ /**
+ * Copy values in a varargs into a destination array. Internal utility
+ * method not intended to be called directly from user code.
+ *
* @return Varargs containing same values, but flattened.
*/
void copyto(LuaValue[] dest, int offset, int length) {
- for (int i=0; i
- * However, calling the constructors directly when weak tables are required from
- * Java will reduce overhead.
+ * Normally these are not created directly, but indirectly when changing the
+ * mode of a {@link LuaTable} as lua script executes.
+ *
+ * However, calling the constructors directly when weak tables are required from
+ * Java will reduce overhead.
*/
public class WeakTable implements Metatable {
- private boolean weakkeys, weakvalues;
- private LuaValue backing;
+ private final boolean weakkeys, weakvalues;
+ private final LuaValue backing;
public static LuaTable make(boolean weakkeys, boolean weakvalues) {
LuaString mode;
- if ( weakkeys && weakvalues ) {
+ if (weakkeys && weakvalues) {
mode = LuaString.valueOf("kv");
- } else if ( weakkeys ) {
+ } else if (weakkeys) {
mode = LuaString.valueOf("k");
- } else if ( weakvalues ) {
+ } else if (weakvalues) {
mode = LuaString.valueOf("v");
} else {
- return LuaTable.tableOf();
+ return LuaValue.tableOf();
}
- LuaTable table = LuaTable.tableOf();
- LuaTable mt = LuaTable.tableOf(new LuaValue[] { LuaValue.MODE, mode });
+ LuaTable table = LuaValue.tableOf();
+ LuaTable mt = LuaValue.tableOf(new LuaValue[] { LuaValue.MODE, mode });
table.setmetatable(mt);
return table;
}
/**
* Construct a table with weak keys, weak values, or both
- * @param weakkeys true to let the table have weak keys
+ *
+ * @param weakkeys true to let the table have weak keys
* @param weakvalues true to let the table have weak values
*/
public WeakTable(boolean weakkeys, boolean weakvalues, LuaValue backing) {
@@ -68,40 +69,44 @@ public class WeakTable implements Metatable {
this.backing = backing;
}
+ @Override
public boolean useWeakKeys() {
return weakkeys;
}
+ @Override
public boolean useWeakValues() {
return weakvalues;
}
+ @Override
public LuaValue toLuaValue() {
return backing;
}
+ @Override
public Slot entry(LuaValue key, LuaValue value) {
value = value.strongvalue();
- if ( value == null )
+ if (value == null)
return null;
- if ( weakkeys && !( key.isnumber() || key.isstring() || key.isboolean() )) {
- if ( weakvalues && !( value.isnumber() || value.isstring() || value.isboolean() )) {
- return new WeakKeyAndValueSlot( key, value, null );
+ if (weakkeys && !(key.isnumber() || key.isstring() || key.isboolean())) {
+ if (weakvalues && !(value.isnumber() || value.isstring() || value.isboolean())) {
+ return new WeakKeyAndValueSlot(key, value, null);
} else {
- return new WeakKeySlot( key, value, null );
+ return new WeakKeySlot(key, value, null);
}
}
- if ( weakvalues && ! (value.isnumber() || value.isstring() || value.isboolean() )) {
- return new WeakValueSlot( key, value, null );
+ if (weakvalues && !(value.isnumber() || value.isstring() || value.isboolean())) {
+ return new WeakValueSlot(key, value, null);
}
- return LuaTable.defaultEntry( key, value );
+ return LuaTable.defaultEntry(key, value);
}
public static abstract class WeakSlot implements Slot {
protected Object key;
protected Object value;
- protected Slot next;
+ protected Slot next;
protected WeakSlot(Object key, Object value, Slot next) {
this.key = key;
@@ -109,14 +114,16 @@ public class WeakTable implements Metatable {
this.next = next;
}
- public abstract int keyindex( int hashMask );
+ @Override
+ public abstract int keyindex(int hashMask);
public abstract Slot set(LuaValue value);
+ @Override
public StrongSlot first() {
LuaValue key = strongkey();
LuaValue value = strongvalue();
- if ( key != null && value != null ) {
+ if (key != null && value != null) {
return new LuaTable.NormalEntry(key, value);
} else {
this.key = null;
@@ -125,67 +132,75 @@ public class WeakTable implements Metatable {
}
}
+ @Override
public StrongSlot find(LuaValue key) {
StrongSlot first = first();
- return ( first != null ) ? first.find( key ) : null;
+ return first != null? first.find(key): null;
}
+ @Override
public boolean keyeq(LuaValue key) {
StrongSlot first = first();
- return ( first != null ) && first.keyeq( key );
+ return first != null && first.keyeq(key);
}
+ @Override
public Slot rest() {
return next;
}
+ @Override
public int arraykey(int max) {
// Integer keys can never be weak.
return 0;
}
+ @Override
public Slot set(StrongSlot target, LuaValue value) {
LuaValue key = strongkey();
- if ( key != null && target.find( key ) != null ) {
- return set( value );
- } else if ( key != null ) {
+ if (key != null && target.find(key) != null) {
+ return set(value);
+ } else if (key != null) {
// Our key is still good.
- next = next.set( target, value );
+ next = next.set(target, value);
return this;
} else {
// our key was dropped, remove ourselves from the chain.
- return next.set( target, value );
+ return next.set(target, value);
}
}
- public Slot add( Slot entry ) {
- next = ( next != null ) ? next.add( entry ) : entry;
- if ( strongkey() != null && strongvalue() != null ) {
+ @Override
+ public Slot add(Slot entry) {
+ next = next != null? next.add(entry): entry;
+ if (strongkey() != null && strongvalue() != null) {
return this;
} else {
return next;
}
}
- public Slot remove( StrongSlot target ) {
+ @Override
+ public Slot remove(StrongSlot target) {
LuaValue key = strongkey();
- if ( key == null ) {
- return next.remove( target );
- } else if ( target.keyeq( key ) ) {
+ if (key == null) {
+ return next.remove(target);
+ } else if (target.keyeq(key)) {
this.value = null;
return this;
} else {
- next = next.remove( target );
+ next = next.remove(target);
return this;
}
}
- public Slot relink( Slot rest ) {
- if ( strongkey() != null && strongvalue() != null ) {
- if ( rest == null && this.next == null ) {
+ @Override
+ public Slot relink(Slot rest) {
+ if (strongkey() != null && strongvalue() != null) {
+ if (rest == null && this.next == null) {
return this;
} else {
- return copy( rest );
+ return copy(rest);
}
} else {
return rest;
@@ -200,66 +215,74 @@ public class WeakTable implements Metatable {
return (LuaValue) value;
}
- protected abstract WeakSlot copy( Slot next );
+ protected abstract WeakSlot copy(Slot next);
}
static class WeakKeySlot extends WeakSlot {
private final int keyhash;
- protected WeakKeySlot( LuaValue key, LuaValue value, Slot next ) {
+ protected WeakKeySlot(LuaValue key, LuaValue value, Slot next) {
super(weaken(key), value, next);
keyhash = key.hashCode();
}
- protected WeakKeySlot( WeakKeySlot copyFrom, Slot next ) {
- super( copyFrom.key, copyFrom.value, next );
+ protected WeakKeySlot(WeakKeySlot copyFrom, Slot next) {
+ super(copyFrom.key, copyFrom.value, next);
this.keyhash = copyFrom.keyhash;
}
- public int keyindex( int mask ) {
- return LuaTable.hashmod( keyhash, mask );
+ @Override
+ public int keyindex(int mask) {
+ return LuaTable.hashmod(keyhash, mask);
}
+ @Override
public Slot set(LuaValue value) {
this.value = value;
return this;
}
+ @Override
public LuaValue strongkey() {
- return strengthen( key );
+ return strengthen(key);
}
- protected WeakSlot copy( Slot rest ) {
- return new WeakKeySlot( this, rest );
+ @Override
+ protected WeakSlot copy(Slot rest) {
+ return new WeakKeySlot(this, rest);
}
}
static class WeakValueSlot extends WeakSlot {
- protected WeakValueSlot( LuaValue key, LuaValue value, Slot next ) {
- super( key, weaken(value), next);
+ protected WeakValueSlot(LuaValue key, LuaValue value, Slot next) {
+ super(key, weaken(value), next);
}
- protected WeakValueSlot( WeakValueSlot copyFrom, Slot next ) {
- super( copyFrom.key, copyFrom.value, next );
+ protected WeakValueSlot(WeakValueSlot copyFrom, Slot next) {
+ super(copyFrom.key, copyFrom.value, next);
}
- public int keyindex( int mask ) {
- return LuaTable.hashSlot( strongkey(), mask );
+ @Override
+ public int keyindex(int mask) {
+ return LuaTable.hashSlot(strongkey(), mask);
}
+ @Override
public Slot set(LuaValue value) {
this.value = weaken(value);
return this;
}
+ @Override
public LuaValue strongvalue() {
- return strengthen( value );
+ return strengthen(value);
}
+ @Override
protected WeakSlot copy(Slot next) {
- return new WeakValueSlot( this, next );
+ return new WeakValueSlot(this, next);
}
}
@@ -267,73 +290,83 @@ public class WeakTable implements Metatable {
private final int keyhash;
- protected WeakKeyAndValueSlot( LuaValue key, LuaValue value, Slot next ) {
- super( weaken(key), weaken(value), next );
+ protected WeakKeyAndValueSlot(LuaValue key, LuaValue value, Slot next) {
+ super(weaken(key), weaken(value), next);
keyhash = key.hashCode();
}
protected WeakKeyAndValueSlot(WeakKeyAndValueSlot copyFrom, Slot next) {
- super( copyFrom.key, copyFrom.value, next );
+ super(copyFrom.key, copyFrom.value, next);
keyhash = copyFrom.keyhash;
}
- public int keyindex( int hashMask ) {
- return LuaTable.hashmod( keyhash, hashMask );
+ @Override
+ public int keyindex(int hashMask) {
+ return LuaTable.hashmod(keyhash, hashMask);
}
+ @Override
public Slot set(LuaValue value) {
this.value = weaken(value);
return this;
}
+ @Override
public LuaValue strongkey() {
- return strengthen( key );
+ return strengthen(key);
}
+ @Override
public LuaValue strongvalue() {
- return strengthen( value );
+ return strengthen(value);
}
- protected WeakSlot copy( Slot next ) {
- return new WeakKeyAndValueSlot( this, next );
+ @Override
+ protected WeakSlot copy(Slot next) {
+ return new WeakKeyAndValueSlot(this, next);
}
}
/**
* Self-sent message to convert a value to its weak counterpart
+ *
* @param value value to convert
- * @return {@link LuaValue} that is a strong or weak reference, depending on type of {@code value}
+ * @return {@link LuaValue} that is a strong or weak reference, depending on
+ * type of {@code value}
*/
- protected static LuaValue weaken( LuaValue value ) {
- switch ( value.type() ) {
- case LuaValue.TFUNCTION:
- case LuaValue.TTHREAD:
- case LuaValue.TTABLE:
- return new WeakValue(value);
- case LuaValue.TUSERDATA:
- return new WeakUserdata(value);
- default:
- return value;
+ protected static LuaValue weaken(LuaValue value) {
+ switch (value.type()) {
+ case LuaValue.TFUNCTION:
+ case LuaValue.TTHREAD:
+ case LuaValue.TTABLE:
+ return new WeakValue(value);
+ case LuaValue.TUSERDATA:
+ return new WeakUserdata(value);
+ default:
+ return value;
}
}
/**
* Unwrap a LuaValue from a WeakReference and/or WeakUserdata.
+ *
* @param ref reference to convert
* @return LuaValue or null
* @see #weaken(LuaValue)
*/
protected static LuaValue strengthen(Object ref) {
- if ( ref instanceof WeakReference ) {
+ if (ref instanceof WeakReference) {
ref = ((WeakReference) ref).get();
}
- if ( ref instanceof WeakValue ) {
+ if (ref instanceof WeakValue) {
return ((WeakValue) ref).strongvalue();
}
return (LuaValue) ref;
}
- /** Internal class to implement weak values.
+ /**
+ * Internal class to implement weak values.
+ *
* @see WeakTable
*/
static class WeakValue extends LuaValue {
@@ -343,37 +376,44 @@ public class WeakTable implements Metatable {
ref = new WeakReference(value);
}
+ @Override
public int type() {
- illegal("type","weak value");
+ illegal("type", "weak value");
return 0;
}
+ @Override
public String typename() {
- illegal("typename","weak value");
+ illegal("typename", "weak value");
return null;
}
+ @Override
public String toString() {
- return "weak<"+ref.get()+">";
+ return "weak<" + ref.get() + ">";
}
+ @Override
public LuaValue strongvalue() {
Object o = ref.get();
- return (LuaValue)o;
+ return (LuaValue) o;
}
+ @Override
public boolean raweq(LuaValue rhs) {
Object o = ref.get();
- return o!=null && rhs.raweq((LuaValue)o);
+ return o != null && rhs.raweq((LuaValue) o);
}
}
- /** Internal class to implement weak userdata values.
+ /**
+ * Internal class to implement weak userdata values.
+ *
* @see WeakTable
*/
static final class WeakUserdata extends WeakValue {
private final WeakReference ob;
- private final LuaValue mt;
+ private final LuaValue mt;
private WeakUserdata(LuaValue value) {
super(value);
@@ -381,13 +421,14 @@ public class WeakTable implements Metatable {
mt = value.getmetatable();
}
+ @Override
public LuaValue strongvalue() {
Object u = ref.get();
- if ( u != null )
+ if (u != null)
return (LuaValue) u;
Object o = ob.get();
- if ( o != null ) {
- LuaValue ud = LuaValue.userdataOf(o,mt);
+ if (o != null) {
+ LuaValue ud = LuaValue.userdataOf(o, mt);
ref = new WeakReference(ud);
return ud;
} else {
@@ -396,10 +437,12 @@ public class WeakTable implements Metatable {
}
}
+ @Override
public LuaValue wrap(LuaValue value) {
- return weakvalues ? weaken( value ) : value;
+ return weakvalues? weaken(value): value;
}
+ @Override
public LuaValue arrayget(LuaValue[] array, int index) {
LuaValue value = array[index];
if (value != null) {
diff --git a/src/core/org/luaj/vm2/compiler/Constants.java b/luaj-core/src/main/java/org/luaj/vm2/compiler/Constants.java
similarity index 59%
rename from src/core/org/luaj/vm2/compiler/Constants.java
rename to luaj-core/src/main/java/org/luaj/vm2/compiler/Constants.java
index fc505b49..143d952d 100644
--- a/src/core/org/luaj/vm2/compiler/Constants.java
+++ b/luaj-core/src/main/java/org/luaj/vm2/compiler/Constants.java
@@ -10,7 +10,7 @@
*
* 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
@@ -31,158 +31,146 @@ import org.luaj.vm2.Upvaldesc;
/**
* Constants used by the LuaC compiler and related classes.
- *
+ *
* @see LuaC
* @see FuncState
*/
public class Constants extends Lua {
-
+
/** Maximum stack size of a luaj vm interpreter instance. */
public static final int MAXSTACK = 250;
static final int LUAI_MAXUPVAL = 0xff;
- static final int LUAI_MAXVARS = 200;
- static final int NO_REG = MAXARG_A;
-
+ static final int LUAI_MAXVARS = 200;
+ static final int NO_REG = MAXARG_A;
/* OpMode - basic instruction format */
- static final int
- iABC = 0,
- iABx = 1,
- iAsBx = 2;
+ static final int iABC = 0, iABx = 1, iAsBx = 2;
/* OpArgMask */
- static final int
- OpArgN = 0, /* argument is not used */
- OpArgU = 1, /* argument is used */
- OpArgR = 2, /* argument is a register or a jump offset */
- OpArgK = 3; /* argument is a constant or register/constant */
-
+ static final int OpArgN = 0, /* argument is not used */
+ OpArgU = 1, /* argument is used */
+ OpArgR = 2, /* argument is a register or a jump offset */
+ OpArgK = 3; /* argument is a constant or register/constant */
protected static void _assert(boolean b) {
if (!b)
throw new LuaError("compiler assert failed");
}
- static void SET_OPCODE(InstructionPtr i,int o) {
- i.set( ( i.get() & (MASK_NOT_OP)) | ((o << POS_OP) & MASK_OP) );
+ static void SET_OPCODE(InstructionPtr i, int o) {
+ i.set(i.get() & MASK_NOT_OP | o<
* A lua binary file is created via {@link DumpState#dump}:
- *
- * Compiles lua source files into lua bytecode within a {@link Prototype},
- * loads lua binary files directly into a {@link Prototype},
- * and optionaly instantiates a {@link LuaClosure} around the result
- * using a user-supplied environment.
- *
+ * Compiles lua source files into lua bytecode within a {@link Prototype}, loads
+ * lua binary files directly into a {@link Prototype}, and optionaly
+ * instantiates a {@link LuaClosure} around the result using a user-supplied
+ * environment.
+ *
*
- * Implements the {@link org.luaj.vm2.Globals.Compiler} interface for loading
- * initialized chunks, which is an interface common to
- * lua bytecode compiling and java bytecode compiling.
- *
- *
- * The {@link LuaC} compiler is installed by default by both the
- * {@link org.luaj.vm2.lib.jse.JsePlatform} and {@link org.luaj.vm2.lib.jme.JmePlatform} classes,
- * so in the following example, the default {@link LuaC} compiler
- * will be used:
- *
+ * The {@link LuaC} compiler is installed by default by both the
+ * {@link org.luaj.vm2.lib.jse.JsePlatform} and
+ * {@link org.luaj.vm2.lib.jme.JmePlatform} classes, so in the following
+ * example, the default {@link LuaC} compiler will be used:
+ *
+ *
- * This contains all library functions listed as "basic functions" in the lua documentation for JME.
- * The functions dofile and loadfile use the
- * {@link Globals#finder} instance to find resource files.
- * Since JME has no file system by default, {@link BaseLib} implements
- * {@link ResourceFinder} using {@link Class#getResource(String)},
- * which is the closest equivalent on JME.
- * The default loader chain in {@link PackageLib} will use these as well.
- *
- * To use basic library functions that include a {@link ResourceFinder} based on
- * directory lookup, use {@link org.luaj.vm2.lib.jse.JseBaseLib} instead.
- *
- * Typically, this library is included as part of a call to either
- * {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
- * {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
- *
- * For special cases where the smallest possible footprint is desired,
- * a minimal set of libraries could be loaded
- * directly via {@link Globals#load(LuaValue)} using code such as:
- *
- * This is a direct port of the corresponding library in C.
- * @see org.luaj.vm2.lib.jse.JseBaseLib
- * @see ResourceFinder
- * @see Globals#finder
- * @see LibFunction
- * @see org.luaj.vm2.lib.jse.JsePlatform
- * @see org.luaj.vm2.lib.jme.JmePlatform
- * @see Lua 5.2 Base Lib Reference
- */
-public class BaseLib extends TwoArgFunction implements ResourceFinder {
-
- Globals globals;
-
-
- /** Perform one-time initialization on the library by adding base functions
- * to the supplied environment, and returning it as the return value.
- * @param modname the module name supplied if this is loaded via 'require'.
- * @param env the environment to load into, which must be a Globals instance.
- */
- public LuaValue call(LuaValue modname, LuaValue env) {
- globals = env.checkglobals();
- globals.finder = this;
- globals.baselib = this;
- env.set( "_G", env );
- env.set( "_VERSION", Lua._VERSION );
- env.set("assert", new _assert());
- env.set("collectgarbage", new collectgarbage());
- env.set("dofile", new dofile());
- env.set("error", new error());
- env.set("getmetatable", new getmetatable());
- env.set("load", new load());
- env.set("loadfile", new loadfile());
- env.set("pcall", new pcall());
- env.set("print", new print(this));
- env.set("rawequal", new rawequal());
- env.set("rawget", new rawget());
- env.set("rawlen", new rawlen());
- env.set("rawset", new rawset());
- env.set("select", new select());
- env.set("setmetatable", new setmetatable());
- env.set("tonumber", new tonumber());
- env.set("tostring", new tostring());
- env.set("type", new type());
- env.set("xpcall", new xpcall());
-
- next next;
- env.set("next", next = new next());
- env.set("pairs", new pairs(next));
- env.set("ipairs", new ipairs());
-
- return env;
- }
-
- /** ResourceFinder implementation
- *
- * Tries to open the file as a resource, which can work for JSE and JME.
- */
- public InputStream findResource(String filename) {
- return getClass().getResourceAsStream(filename.startsWith("/")? filename: "/"+filename);
- }
-
-
- // "assert", // ( v [,message] ) -> v, message | ERR
- static final class _assert extends VarArgFunction {
- public Varargs invoke(Varargs args) {
- if ( !args.arg1().toboolean() )
- error( args.narg()>1? args.optjstring(2,"assertion failed!"): "assertion failed!" );
- return args;
- }
- }
-
- // "collectgarbage", // ( opt [,arg] ) -> value
- static final class collectgarbage extends VarArgFunction {
- public Varargs invoke(Varargs args) {
- String s = args.optjstring(1, "collect");
- if ( "collect".equals(s) ) {
- System.gc();
- return ZERO;
- } else if ( "count".equals(s) ) {
- Runtime rt = Runtime.getRuntime();
- long used = rt.totalMemory() - rt.freeMemory();
- return varargsOf(valueOf(used/1024.), valueOf(used%1024));
- } else if ( "step".equals(s) ) {
- System.gc();
- return LuaValue.TRUE;
- } else {
- argerror(1, "invalid option '" + s + "'");
- }
- return NIL;
- }
- }
-
- // "dofile", // ( filename ) -> result1, ...
- final class dofile extends VarArgFunction {
- public Varargs invoke(Varargs args) {
- args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or nil");
- String filename = args.isstring(1)? args.tojstring(1): null;
- Varargs v = filename == null?
- loadStream( globals.STDIN, "=stdin", "bt", globals ):
- loadFile( args.checkjstring(1), "bt", globals );
- return v.isnil(1)? error(v.tojstring(2)): v.arg1().invoke();
- }
- }
-
- // "error", // ( message [,level] ) -> ERR
- static final class error extends TwoArgFunction {
- public LuaValue call(LuaValue arg1, LuaValue arg2) {
- if (arg1.isnil()) throw new LuaError(NIL);
- if (!arg1.isstring() || arg2.optint(1) == 0) throw new LuaError(arg1);
- throw new LuaError(arg1.tojstring(), arg2.optint(1));
- }
- }
-
- // "getmetatable", // ( object ) -> table
- static final class getmetatable extends LibFunction {
- public LuaValue call() {
- return argerror(1, "value expected");
- }
- public LuaValue call(LuaValue arg) {
- LuaValue mt = arg.getmetatable();
- return mt!=null? mt.rawget(METATABLE).optvalue(mt): NIL;
- }
- }
- // "load", // ( ld [, source [, mode [, env]]] ) -> chunk | nil, msg
- final class load extends VarArgFunction {
- public Varargs invoke(Varargs args) {
- LuaValue ld = args.arg1();
- if (!ld.isstring() && !ld.isfunction()) {
- throw new LuaError("bad argument #1 to 'load' (string or function expected, got " + ld.typename() + ")");
- }
- String source = args.optjstring(2, ld.isstring()? ld.tojstring(): "=(load)");
- String mode = args.optjstring(3, "bt");
- LuaValue env = args.optvalue(4, globals);
- return loadStream(ld.isstring()? ld.strvalue().toInputStream():
- new StringInputStream(ld.checkfunction()), source, mode, env);
- }
- }
-
- // "loadfile", // ( [filename [, mode [, env]]] ) -> chunk | nil, msg
- final class loadfile extends VarArgFunction {
- public Varargs invoke(Varargs args) {
- args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or nil");
- String filename = args.isstring(1)? args.tojstring(1): null;
- String mode = args.optjstring(2, "bt");
- LuaValue env = args.optvalue(3, globals);
- return filename == null?
- loadStream( globals.STDIN, "=stdin", mode, env ):
- loadFile( filename, mode, env );
- }
- }
-
- // "pcall", // (f, arg1, ...) -> status, result1, ...
- final class pcall extends VarArgFunction {
- public Varargs invoke(Varargs args) {
- LuaValue func = args.checkvalue(1);
- if (globals != null && globals.debuglib != null)
- globals.debuglib.onCall(this);
- try {
- return varargsOf(TRUE, func.invoke(args.subargs(2)));
- } catch ( LuaError le ) {
- final LuaValue m = le.getMessageObject();
- return varargsOf(FALSE, m!=null? m: NIL);
- } catch ( Exception e ) {
- final String m = e.getMessage();
- return varargsOf(FALSE, valueOf(m!=null? m: e.toString()));
- } finally {
- if (globals != null && globals.debuglib != null)
- globals.debuglib.onReturn();
- }
- }
- }
-
- // "print", // (...) -> void
- final class print extends VarArgFunction {
- final BaseLib baselib;
- print(BaseLib baselib) {
- this.baselib = baselib;
- }
- public Varargs invoke(Varargs args) {
- LuaValue tostring = globals.get("tostring");
- for ( int i=1, n=args.narg(); i<=n; i++ ) {
- if ( i>1 ) globals.STDOUT.print( '\t' );
- LuaString s = tostring.call( args.arg(i) ).strvalue();
- globals.STDOUT.print(s.tojstring());
- }
- globals.STDOUT.print('\n');
- return NONE;
- }
- }
-
-
- // "rawequal", // (v1, v2) -> boolean
- static final class rawequal extends LibFunction {
- public LuaValue call() {
- return argerror(1, "value expected");
- }
- public LuaValue call(LuaValue arg) {
- return argerror(2, "value expected");
- }
- public LuaValue call(LuaValue arg1, LuaValue arg2) {
- return valueOf(arg1.raweq(arg2));
- }
- }
-
- // "rawget", // (table, index) -> value
- static final class rawget extends TableLibFunction {
- public LuaValue call(LuaValue arg) {
- return argerror(2, "value expected");
- }
- public LuaValue call(LuaValue arg1, LuaValue arg2) {
- return arg1.checktable().rawget(arg2);
- }
- }
-
-
- // "rawlen", // (v) -> value
- static final class rawlen extends LibFunction {
- public LuaValue call(LuaValue arg) {
- return valueOf(arg.rawlen());
- }
- }
-
- // "rawset", // (table, index, value) -> table
- static final class rawset extends TableLibFunction {
- public LuaValue call(LuaValue table) {
- return argerror(2,"value expected");
- }
- public LuaValue call(LuaValue table, LuaValue index) {
- return argerror(3,"value expected");
- }
- public LuaValue call(LuaValue table, LuaValue index, LuaValue value) {
- LuaTable t = table.checktable();
- if (!index.isvalidkey()) argerror(2, "table index is nil");
- t.rawset(index, value);
- return t;
- }
- }
-
- // "select", // (f, ...) -> value1, ...
- static final class select extends VarArgFunction {
- public Varargs invoke(Varargs args) {
- int n = args.narg()-1;
- if ( args.arg1().equals(valueOf("#")) )
- return valueOf(n);
- int i = args.checkint(1);
- if ( i == 0 || i < -n )
- argerror(1,"index out of range");
- return args.subargs(i<0? n+i+2: i+1);
- }
- }
-
- // "setmetatable", // (table, metatable) -> table
- static final class setmetatable extends TableLibFunction {
- public LuaValue call(LuaValue table) {
- return argerror(2,"nil or table expected");
- }
- public LuaValue call(LuaValue table, LuaValue metatable) {
- final LuaValue mt0 = table.checktable().getmetatable();
- if ( mt0!=null && !mt0.rawget(METATABLE).isnil() )
- error("cannot change a protected metatable");
- return table.setmetatable(metatable.isnil()? null: metatable.checktable());
- }
- }
-
- // "tonumber", // (e [,base]) -> value
- static final class tonumber extends LibFunction {
- public LuaValue call(LuaValue e) {
- return e.tonumber();
- }
- public LuaValue call(LuaValue e, LuaValue base) {
- if (base.isnil())
- return e.tonumber();
- final int b = base.checkint();
- if ( b < 2 || b > 36 )
- argerror(2, "base out of range");
- return e.checkstring().tonumber(b);
- }
- }
-
- // "tostring", // (e) -> value
- static final class tostring extends LibFunction {
- public LuaValue call(LuaValue arg) {
- LuaValue h = arg.metatag(TOSTRING);
- if ( ! h.isnil() )
- return h.call(arg);
- LuaValue v = arg.tostring();
- if ( ! v.isnil() )
- return v;
- return valueOf(arg.tojstring());
- }
- }
-
- // "type", // (v) -> value
- static final class type extends LibFunction {
- public LuaValue call(LuaValue arg) {
- return valueOf(arg.typename());
- }
- }
-
- // "xpcall", // (f, err) -> result1, ...
- final class xpcall extends VarArgFunction {
- public Varargs invoke(Varargs args) {
- final LuaThread t = globals.running;
- final LuaValue preverror = t.errorfunc;
- t.errorfunc = args.checkvalue(2);
- try {
- if (globals != null && globals.debuglib != null)
- globals.debuglib.onCall(this);
- try {
- return varargsOf(TRUE, args.arg1().invoke(args.subargs(3)));
- } catch ( LuaError le ) {
- final LuaValue m = le.getMessageObject();
- return varargsOf(FALSE, m!=null? m: NIL);
- } catch ( Exception e ) {
- final String m = e.getMessage();
- return varargsOf(FALSE, valueOf(m!=null? m: e.toString()));
- } finally {
- if (globals != null && globals.debuglib != null)
- globals.debuglib.onReturn();
- }
- } finally {
- t.errorfunc = preverror;
- }
- }
- }
-
- // "pairs" (t) -> iter-func, t, nil
- static final class pairs extends VarArgFunction {
- final next next;
- pairs(next next) {
- this.next = next;
- }
- public Varargs invoke(Varargs args) {
- return varargsOf( next, args.checktable(1), NIL );
- }
- }
-
- // // "ipairs", // (t) -> iter-func, t, 0
- static final class ipairs extends VarArgFunction {
- inext inext = new inext();
- public Varargs invoke(Varargs args) {
- return varargsOf( inext, args.checktable(1), ZERO );
- }
- }
-
- // "next" ( table, [index] ) -> next-index, next-value
- static final class next extends VarArgFunction {
- public Varargs invoke(Varargs args) {
- return args.checktable(1).next(args.arg(2));
- }
- }
-
- // "inext" ( table, [int-index] ) -> next-index, next-value
- static final class inext extends VarArgFunction {
- public Varargs invoke(Varargs args) {
- return args.checktable(1).inext(args.arg(2));
- }
- }
-
- /**
- * Load from a named file, returning the chunk or nil,error of can't load
- * @param env
- * @param mode
- * @return Varargs containing chunk, or NIL,error-text on error
- */
- public Varargs loadFile(String filename, String mode, LuaValue env) {
- InputStream is = globals.finder.findResource(filename);
- if ( is == null )
- return varargsOf(NIL, valueOf("cannot open "+filename+": No such file or directory"));
- try {
- return loadStream(is, "@"+filename, mode, env);
- } finally {
- try {
- is.close();
- } catch ( Exception e ) {
- e.printStackTrace();
- }
- }
- }
-
- public Varargs loadStream(InputStream is, String chunkname, String mode, LuaValue env) {
- try {
- if ( is == null )
- return varargsOf(NIL, valueOf("not found: "+chunkname));
- return globals.load(is, chunkname, mode, env);
- } catch (Exception e) {
- return varargsOf(NIL, valueOf(e.getMessage()));
- }
- }
-
-
- private static class StringInputStream extends InputStream {
- final LuaValue func;
- byte[] bytes;
- int offset, remaining = 0;
- StringInputStream(LuaValue func) {
- this.func = func;
- }
- public int read() throws IOException {
- if ( remaining < 0 )
- return -1;
- if ( remaining == 0 ) {
- LuaValue s = func.call();
- if ( s.isnil() )
- return remaining = -1;
- LuaString ls = s.strvalue();
- bytes = ls.m_bytes;
- offset = ls.m_offset;
- remaining = ls.m_length;
- if (remaining <= 0)
- return -1;
- }
- --remaining;
- return 0xFF&bytes[offset++];
- }
- }
-}
+/*******************************************************************************
+* Copyright (c) 2009 Luaj.org. All rights reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+******************************************************************************/
+package org.luaj.vm2.lib;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.luaj.vm2.Globals;
+import org.luaj.vm2.Lua;
+import org.luaj.vm2.LuaError;
+import org.luaj.vm2.LuaString;
+import org.luaj.vm2.LuaTable;
+import org.luaj.vm2.LuaThread;
+import org.luaj.vm2.LuaValue;
+import org.luaj.vm2.Varargs;
+
+/**
+ * Subclass of {@link LibFunction} which implements the lua basic library
+ * functions.
+ *
+ * This contains all library functions listed as "basic functions" in the lua
+ * documentation for JME. The functions dofile and loadfile use the
+ * {@link Globals#finder} instance to find resource files. Since JME has no file
+ * system by default, {@link BaseLib} implements {@link ResourceFinder} using
+ * {@link Class#getResource(String)}, which is the closest equivalent on JME.
+ * The default loader chain in {@link PackageLib} will use these as well.
+ *
+ * To use basic library functions that include a {@link ResourceFinder} based on
+ * directory lookup, use {@link org.luaj.vm2.lib.jse.JseBaseLib} instead.
+ *
+ * Typically, this library is included as part of a call to either
+ * {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
+ * {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
+ *
+ *
+ * For special cases where the smallest possible footprint is desired, a minimal
+ * set of libraries could be loaded directly via {@link Globals#load(LuaValue)}
+ * using code such as:
+ *
+ *
+ * This is a direct port of the corresponding library in C.
+ *
+ * @see org.luaj.vm2.lib.jse.JseBaseLib
+ * @see ResourceFinder
+ * @see Globals#finder
+ * @see LibFunction
+ * @see org.luaj.vm2.lib.jse.JsePlatform
+ * @see org.luaj.vm2.lib.jme.JmePlatform
+ * @see Lua 5.2 Base Lib
+ * Reference
+ */
+public class BaseLib extends TwoArgFunction implements ResourceFinder {
+
+ Globals globals;
+
+ /**
+ * Perform one-time initialization on the library by adding base functions
+ * to the supplied environment, and returning it as the return value.
+ *
+ * @param modname the module name supplied if this is loaded via 'require'.
+ * @param env the environment to load into, which must be a Globals
+ * instance.
+ */
+ @Override
+ public LuaValue call(LuaValue modname, LuaValue env) {
+ globals = env.checkglobals();
+ globals.finder = this;
+ globals.baselib = this;
+ env.set("_G", env);
+ env.set("_VERSION", Lua._VERSION);
+ env.set("assert", new _assert());
+ env.set("collectgarbage", new collectgarbage());
+ env.set("dofile", new dofile());
+ env.set("error", new error());
+ env.set("getmetatable", new getmetatable());
+ env.set("load", new load());
+ env.set("loadfile", new loadfile());
+ env.set("pcall", new pcall());
+ env.set("print", new print(this));
+ env.set("rawequal", new rawequal());
+ env.set("rawget", new rawget());
+ env.set("rawlen", new rawlen());
+ env.set("rawset", new rawset());
+ env.set("select", new select());
+ env.set("setmetatable", new setmetatable());
+ env.set("tonumber", new tonumber());
+ env.set("tostring", new tostring());
+ env.set("type", new type());
+ env.set("xpcall", new xpcall());
+
+ next next;
+ env.set("next", next = new next());
+ env.set("pairs", new pairs(next));
+ env.set("ipairs", new ipairs());
+
+ return env;
+ }
+
+ /**
+ * ResourceFinder implementation
+ *
+ * Tries to open the file as a resource, which can work for JSE and JME.
+ */
+ @Override
+ public InputStream findResource(String filename) {
+ return getClass().getResourceAsStream(filename.startsWith("/")? filename: "/" + filename);
+ }
+
+ // "assert", // ( v [,message] ) -> v, message | ERR
+ static final class _assert extends VarArgFunction {
+ @Override
+ public Varargs invoke(Varargs args) {
+ if (!args.arg1().toboolean())
+ error(args.narg() > 1? args.optjstring(2, "assertion failed!"): "assertion failed!");
+ return args;
+ }
+ }
+
+ // "collectgarbage", // ( opt [,arg] ) -> value
+ static final class collectgarbage extends VarArgFunction {
+ @Override
+ public Varargs invoke(Varargs args) {
+ String s = args.optjstring(1, "collect");
+ if ("collect".equals(s)) {
+ System.gc();
+ return ZERO;
+ } else if ("count".equals(s)) {
+ Runtime rt = Runtime.getRuntime();
+ long used = rt.totalMemory()-rt.freeMemory();
+ return varargsOf(valueOf(used/1024.), valueOf(used%1024));
+ } else if ("step".equals(s)) {
+ System.gc();
+ return LuaValue.TRUE;
+ } else {
+ argerror(1, "invalid option '" + s + "'");
+ }
+ return NIL;
+ }
+ }
+
+ // "dofile", // ( filename ) -> result1, ...
+ final class dofile extends VarArgFunction {
+ @Override
+ public Varargs invoke(Varargs args) {
+ args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or nil");
+ String filename = args.isstring(1)? args.tojstring(1): null;
+ Varargs v = filename == null? loadStream(globals.STDIN, "=stdin", "bt", globals)
+ : loadFile(args.checkjstring(1), "bt", globals);
+ return v.isnil(1)? error(v.tojstring(2)): v.arg1().invoke();
+ }
+ }
+
+ // "error", // ( message [,level] ) -> ERR
+ static final class error extends TwoArgFunction {
+ @Override
+ public LuaValue call(LuaValue arg1, LuaValue arg2) {
+ if (arg1.isnil())
+ throw new LuaError(NIL);
+ if (!arg1.isstring() || arg2.optint(1) == 0)
+ throw new LuaError(arg1);
+ throw new LuaError(arg1.tojstring(), arg2.optint(1));
+ }
+ }
+
+ // "getmetatable", // ( object ) -> table
+ static final class getmetatable extends LibFunction {
+ @Override
+ public LuaValue call() {
+ return argerror(1, "value expected");
+ }
+
+ @Override
+ public LuaValue call(LuaValue arg) {
+ LuaValue mt = arg.getmetatable();
+ return mt != null? mt.rawget(METATABLE).optvalue(mt): NIL;
+ }
+ }
+
+ // "load", // ( ld [, source [, mode [, env]]] ) -> chunk | nil, msg
+ final class load extends VarArgFunction {
+ @Override
+ public Varargs invoke(Varargs args) {
+ LuaValue ld = args.arg1();
+ if (!ld.isstring() && !ld.isfunction()) {
+ throw new LuaError(
+ "bad argument #1 to 'load' (string or function expected, got " + ld.typename() + ")");
+ }
+ String source = args.optjstring(2, ld.isstring()? ld.tojstring(): "=(load)");
+ String mode = args.optjstring(3, "bt");
+ LuaValue env = args.optvalue(4, globals);
+ return loadStream(ld.isstring()? ld.strvalue().toInputStream(): new StringInputStream(ld.checkfunction()),
+ source, mode, env);
+ }
+ }
+
+ // "loadfile", // ( [filename [, mode [, env]]] ) -> chunk | nil, msg
+ final class loadfile extends VarArgFunction {
+ @Override
+ public Varargs invoke(Varargs args) {
+ args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or nil");
+ String filename = args.isstring(1)? args.tojstring(1): null;
+ String mode = args.optjstring(2, "bt");
+ LuaValue env = args.optvalue(3, globals);
+ return filename == null? loadStream(globals.STDIN, "=stdin", mode, env): loadFile(filename, mode, env);
+ }
+ }
+
+ // "pcall", // (f, arg1, ...) -> status, result1, ...
+ final class pcall extends VarArgFunction {
+ @Override
+ public Varargs invoke(Varargs args) {
+ LuaValue func = args.checkvalue(1);
+ if (globals != null && globals.debuglib != null)
+ globals.debuglib.onCall(this);
+ try {
+ return varargsOf(TRUE, func.invoke(args.subargs(2)));
+ } catch (LuaError le) {
+ final LuaValue m = le.getMessageObject();
+ return varargsOf(FALSE, m != null? m: NIL);
+ } catch (Exception e) {
+ final String m = e.getMessage();
+ return varargsOf(FALSE, valueOf(m != null? m: e.toString()));
+ } finally {
+ if (globals != null && globals.debuglib != null)
+ globals.debuglib.onReturn();
+ }
+ }
+ }
+
+ // "print", // (...) -> void
+ final class print extends VarArgFunction {
+ final BaseLib baselib;
+
+ print(BaseLib baselib) {
+ this.baselib = baselib;
+ }
+
+ @Override
+ public Varargs invoke(Varargs args) {
+ LuaValue tostring = globals.get("tostring");
+ for (int i = 1, n = args.narg(); i <= n; i++) {
+ if (i > 1)
+ globals.STDOUT.print('\t');
+ LuaString s = tostring.call(args.arg(i)).strvalue();
+ globals.STDOUT.print(s.tojstring());
+ }
+ globals.STDOUT.print('\n');
+ return NONE;
+ }
+ }
+
+ // "rawequal", // (v1, v2) -> boolean
+ static final class rawequal extends LibFunction {
+ @Override
+ public LuaValue call() {
+ return argerror(1, "value expected");
+ }
+
+ @Override
+ public LuaValue call(LuaValue arg) {
+ return argerror(2, "value expected");
+ }
+
+ @Override
+ public LuaValue call(LuaValue arg1, LuaValue arg2) {
+ return valueOf(arg1.raweq(arg2));
+ }
+ }
+
+ // "rawget", // (table, index) -> value
+ static final class rawget extends TableLibFunction {
+ @Override
+ public LuaValue call(LuaValue arg) {
+ return argerror(2, "value expected");
+ }
+
+ @Override
+ public LuaValue call(LuaValue arg1, LuaValue arg2) {
+ return arg1.checktable().rawget(arg2);
+ }
+ }
+
+ // "rawlen", // (v) -> value
+ static final class rawlen extends LibFunction {
+ @Override
+ public LuaValue call(LuaValue arg) {
+ return valueOf(arg.rawlen());
+ }
+ }
+
+ // "rawset", // (table, index, value) -> table
+ static final class rawset extends TableLibFunction {
+ @Override
+ public LuaValue call(LuaValue table) {
+ return argerror(2, "value expected");
+ }
+
+ @Override
+ public LuaValue call(LuaValue table, LuaValue index) {
+ return argerror(3, "value expected");
+ }
+
+ @Override
+ public LuaValue call(LuaValue table, LuaValue index, LuaValue value) {
+ LuaTable t = table.checktable();
+ if (!index.isvalidkey())
+ argerror(2, "table index is nil");
+ t.rawset(index, value);
+ return t;
+ }
+ }
+
+ // "select", // (f, ...) -> value1, ...
+ static final class select extends VarArgFunction {
+ @Override
+ public Varargs invoke(Varargs args) {
+ int n = args.narg()-1;
+ if (args.arg1().equals(valueOf("#")))
+ return valueOf(n);
+ int i = args.checkint(1);
+ if (i == 0 || i < -n)
+ argerror(1, "index out of range");
+ return args.subargs(i < 0? n+i+2: i+1);
+ }
+ }
+
+ // "setmetatable", // (table, metatable) -> table
+ static final class setmetatable extends TableLibFunction {
+ @Override
+ public LuaValue call(LuaValue table) {
+ return argerror(2, "nil or table expected");
+ }
+
+ @Override
+ public LuaValue call(LuaValue table, LuaValue metatable) {
+ final LuaValue mt0 = table.checktable().getmetatable();
+ if (mt0 != null && !mt0.rawget(METATABLE).isnil())
+ error("cannot change a protected metatable");
+ return table.setmetatable(metatable.isnil()? null: metatable.checktable());
+ }
+ }
+
+ // "tonumber", // (e [,base]) -> value
+ static final class tonumber extends LibFunction {
+ @Override
+ public LuaValue call(LuaValue e) {
+ return e.tonumber();
+ }
+
+ @Override
+ public LuaValue call(LuaValue e, LuaValue base) {
+ if (base.isnil())
+ return e.tonumber();
+ final int b = base.checkint();
+ if (b < 2 || b > 36)
+ argerror(2, "base out of range");
+ return e.checkstring().tonumber(b);
+ }
+ }
+
+ // "tostring", // (e) -> value
+ static final class tostring extends LibFunction {
+ @Override
+ public LuaValue call(LuaValue arg) {
+ LuaValue h = arg.metatag(TOSTRING);
+ if (!h.isnil())
+ return h.call(arg);
+ LuaValue v = arg.tostring();
+ if (!v.isnil())
+ return v;
+ return valueOf(arg.tojstring());
+ }
+ }
+
+ // "type", // (v) -> value
+ static final class type extends LibFunction {
+ @Override
+ public LuaValue call(LuaValue arg) {
+ return valueOf(arg.typename());
+ }
+ }
+
+ // "xpcall", // (f, err) -> result1, ...
+ final class xpcall extends VarArgFunction {
+ @Override
+ public Varargs invoke(Varargs args) {
+ final LuaThread t = globals.running;
+ final LuaValue preverror = t.errorfunc;
+ t.errorfunc = args.checkvalue(2);
+ try {
+ if (globals != null && globals.debuglib != null)
+ globals.debuglib.onCall(this);
+ try {
+ return varargsOf(TRUE, args.arg1().invoke(args.subargs(3)));
+ } catch (LuaError le) {
+ final LuaValue m = le.getMessageObject();
+ return varargsOf(FALSE, m != null? m: NIL);
+ } catch (Exception e) {
+ final String m = e.getMessage();
+ return varargsOf(FALSE, valueOf(m != null? m: e.toString()));
+ } finally {
+ if (globals != null && globals.debuglib != null)
+ globals.debuglib.onReturn();
+ }
+ } finally {
+ t.errorfunc = preverror;
+ }
+ }
+ }
+
+ // "pairs" (t) -> iter-func, t, nil
+ static final class pairs extends VarArgFunction {
+ final next next;
+
+ pairs(next next) {
+ this.next = next;
+ }
+
+ @Override
+ public Varargs invoke(Varargs args) {
+ return varargsOf(next, args.checktable(1), NIL);
+ }
+ }
+
+ // // "ipairs", // (t) -> iter-func, t, 0
+ static final class ipairs extends VarArgFunction {
+ inext inext = new inext();
+
+ @Override
+ public Varargs invoke(Varargs args) {
+ return varargsOf(inext, args.checktable(1), ZERO);
+ }
+ }
+
+ // "next" ( table, [index] ) -> next-index, next-value
+ static final class next extends VarArgFunction {
+ @Override
+ public Varargs invoke(Varargs args) {
+ return args.checktable(1).next(args.arg(2));
+ }
+ }
+
+ // "inext" ( table, [int-index] ) -> next-index, next-value
+ static final class inext extends VarArgFunction {
+ @Override
+ public Varargs invoke(Varargs args) {
+ return args.checktable(1).inext(args.arg(2));
+ }
+ }
+
+ /**
+ * Load from a named file, returning the chunk or nil,error of can't load
+ *
+ * @param env
+ * @param mode
+ * @return Varargs containing chunk, or NIL,error-text on error
+ */
+ public Varargs loadFile(String filename, String mode, LuaValue env) {
+ InputStream is = globals.finder.findResource(filename);
+ if (is == null)
+ return varargsOf(NIL, valueOf("cannot open " + filename + ": No such file or directory"));
+ try {
+ return loadStream(is, "@" + filename, mode, env);
+ } finally {
+ try {
+ is.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public Varargs loadStream(InputStream is, String chunkname, String mode, LuaValue env) {
+ try {
+ if (is == null)
+ return varargsOf(NIL, valueOf("not found: " + chunkname));
+ return globals.load(is, chunkname, mode, env);
+ } catch (Exception e) {
+ return varargsOf(NIL, valueOf(e.getMessage()));
+ }
+ }
+
+ private static class StringInputStream extends InputStream {
+ final LuaValue func;
+ byte[] bytes;
+ int offset, remaining = 0;
+
+ StringInputStream(LuaValue func) {
+ this.func = func;
+ }
+
+ @Override
+ public int read() throws IOException {
+ if (remaining < 0)
+ return -1;
+ if (remaining == 0) {
+ LuaValue s = func.call();
+ if (s.isnil())
+ return remaining = -1;
+ LuaString ls = s.strvalue();
+ bytes = ls.m_bytes;
+ offset = ls.m_offset;
+ remaining = ls.m_length;
+ if (remaining <= 0)
+ return -1;
+ }
+ --remaining;
+ return 0xFF & bytes[offset++];
+ }
+ }
+}
diff --git a/src/core/org/luaj/vm2/lib/Bit32Lib.java b/luaj-core/src/main/java/org/luaj/vm2/lib/Bit32Lib.java
similarity index 54%
rename from src/core/org/luaj/vm2/lib/Bit32Lib.java
rename to luaj-core/src/main/java/org/luaj/vm2/lib/Bit32Lib.java
index 699c6945..477e7317 100644
--- a/src/core/org/luaj/vm2/lib/Bit32Lib.java
+++ b/luaj-core/src/main/java/org/luaj/vm2/lib/Bit32Lib.java
@@ -10,7 +10,7 @@
*
* 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
@@ -26,68 +26,88 @@ import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/**
- * Subclass of LibFunction that implements the Lua standard {@code bit32} library.
+ * Subclass of LibFunction that implements the Lua standard {@code bit32}
+ * library.
*
* Typically, this library is included as part of a call to either
- * {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
- *
- * To instantiate and use it directly,
- * link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
- *
- * This has been implemented to match as closely as possible the behavior in the corresponding library in C.
+ * This has been implemented to match as closely as possible the behavior in the
+ * corresponding library in C.
+ *
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
- * @see Lua 5.2 Bitwise Operation Lib Reference
+ * @see Lua 5.2 Bitwise
+ * Operation Lib Reference
*/
public class Bit32Lib extends TwoArgFunction {
public Bit32Lib() {
}
- /** Perform one-time initialization on the library by creating a table
- * containing the library functions, adding that table to the supplied environment,
- * adding the table to package.loaded, and returning table as the return value.
+ /**
+ * Perform one-time initialization on the library by creating a table
+ * containing the library functions, adding that table to the supplied
+ * environment, adding the table to package.loaded, and returning table as
+ * the return value.
+ *
* @param modname the module name supplied if this is loaded via 'require'.
- * @param env the environment to load into, which must be a Globals instance.
+ * @param env the environment to load into, which must be a Globals
+ * instance.
*/
+ @Override
public LuaValue call(LuaValue modname, LuaValue env) {
LuaTable t = new LuaTable();
- bind(t, Bit32LibV.class, new String[] {
- "band", "bnot", "bor", "btest", "bxor", "extract", "replace"
- });
- bind(t, Bit32Lib2.class, new String[] {
- "arshift", "lrotate", "lshift", "rrotate", "rshift"
- });
+ bind(t, Bit32LibV.class, new String[] { "band", "bnot", "bor", "btest", "bxor", "extract", "replace" });
+ bind(t, Bit32Lib2.class, new String[] { "arshift", "lrotate", "lshift", "rrotate", "rshift" });
env.set("bit32", t);
- if (!env.get("package").isnil()) env.get("package").get("loaded").set("bit32", t);
+ if (!env.get("package").isnil())
+ env.get("package").get("loaded").set("bit32", t);
return t;
}
static final class Bit32LibV extends VarArgFunction {
+ @Override
public Varargs invoke(Varargs args) {
- switch ( opcode ) {
- case 0: return Bit32Lib.band( args );
- case 1: return Bit32Lib.bnot( args );
- case 2: return Bit32Lib.bor( args );
- case 3: return Bit32Lib.btest( args );
- case 4: return Bit32Lib.bxor( args );
+ switch (opcode) {
+ case 0:
+ return Bit32Lib.band(args);
+ case 1:
+ return Bit32Lib.bnot(args);
+ case 2:
+ return Bit32Lib.bor(args);
+ case 3:
+ return Bit32Lib.btest(args);
+ case 4:
+ return Bit32Lib.bxor(args);
case 5:
- return Bit32Lib.extract( args.checkint(1), args.checkint(2), args.optint(3, 1) );
+ return Bit32Lib.extract(args.checkint(1), args.checkint(2), args.optint(3, 1));
case 6:
- return Bit32Lib.replace( args.checkint(1), args.checkint(2),
- args.checkint(3), args.optint(4, 1) );
+ return Bit32Lib.replace(args.checkint(1), args.checkint(2), args.checkint(3), args.optint(4, 1));
}
return NIL;
}
@@ -95,24 +115,30 @@ public class Bit32Lib extends TwoArgFunction {
static final class Bit32Lib2 extends TwoArgFunction {
+ @Override
public LuaValue call(LuaValue arg1, LuaValue arg2) {
- switch ( opcode ) {
- case 0: return Bit32Lib.arshift(arg1.checkint(), arg2.checkint());
- case 1: return Bit32Lib.lrotate(arg1.checkint(), arg2.checkint());
- case 2: return Bit32Lib.lshift(arg1.checkint(), arg2.checkint());
- case 3: return Bit32Lib.rrotate(arg1.checkint(), arg2.checkint());
- case 4: return Bit32Lib.rshift(arg1.checkint(), arg2.checkint());
+ switch (opcode) {
+ case 0:
+ return Bit32Lib.arshift(arg1.checkint(), arg2.checkint());
+ case 1:
+ return Bit32Lib.lrotate(arg1.checkint(), arg2.checkint());
+ case 2:
+ return Bit32Lib.lshift(arg1.checkint(), arg2.checkint());
+ case 3:
+ return Bit32Lib.rrotate(arg1.checkint(), arg2.checkint());
+ case 4:
+ return Bit32Lib.rshift(arg1.checkint(), arg2.checkint());
}
return NIL;
}
-
+
}
static LuaValue arshift(int x, int disp) {
if (disp >= 0) {
- return bitsToValue(x >> disp);
+ return bitsToValue(x>>disp);
} else {
- return bitsToValue(x << -disp);
+ return bitsToValue(x<<-disp);
}
}
@@ -120,9 +146,9 @@ public class Bit32Lib extends TwoArgFunction {
if (disp >= 32 || disp <= -32) {
return ZERO;
} else if (disp >= 0) {
- return bitsToValue(x >>> disp);
+ return bitsToValue(x>>>disp);
} else {
- return bitsToValue(x << -disp);
+ return bitsToValue(x<<-disp);
}
}
@@ -130,46 +156,46 @@ public class Bit32Lib extends TwoArgFunction {
if (disp >= 32 || disp <= -32) {
return ZERO;
} else if (disp >= 0) {
- return bitsToValue(x << disp);
+ return bitsToValue(x<
* Typically, this library is included as part of a call to either
- * {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
- *
- * To instantiate and use it directly,
- * link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
- *
+ *
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
- * @see Lua 5.2 Coroutine Lib Reference
+ * @see Lua 5.2
+ * Coroutine Lib Reference
*/
public class CoroutineLib extends TwoArgFunction {
static int coroutine_count = 0;
Globals globals;
-
- /** Perform one-time initialization on the library by creating a table
- * containing the library functions, adding that table to the supplied environment,
- * adding the table to package.loaded, and returning table as the return value.
+
+ /**
+ * Perform one-time initialization on the library by creating a table
+ * containing the library functions, adding that table to the supplied
+ * environment, adding the table to package.loaded, and returning table as
+ * the return value.
+ *
* @param modname the module name supplied if this is loaded via 'require'.
- * @param env the environment to load into, which must be a Globals instance.
+ * @param env the environment to load into, which must be a Globals
+ * instance.
*/
+ @Override
public LuaValue call(LuaValue modname, LuaValue env) {
globals = env.checkglobals();
LuaTable coroutine = new LuaTable();
@@ -82,24 +98,28 @@ public class CoroutineLib extends TwoArgFunction {
coroutine.set("yield", new yield());
coroutine.set("wrap", new wrap());
env.set("coroutine", coroutine);
- if (!env.get("package").isnil()) env.get("package").get("loaded").set("coroutine", coroutine);
+ if (!env.get("package").isnil())
+ env.get("package").get("loaded").set("coroutine", coroutine);
return coroutine;
}
final class create extends LibFunction {
+ @Override
public LuaValue call(LuaValue f) {
return new LuaThread(globals, f.checkfunction());
}
}
static final class resume extends VarArgFunction {
+ @Override
public Varargs invoke(Varargs args) {
final LuaThread t = args.checkthread(1);
- return t.resume( args.subargs(2) );
+ return t.resume(args.subargs(2));
}
}
final class running extends VarArgFunction {
+ @Override
public Varargs invoke(Varargs args) {
final LuaThread r = globals.running;
return varargsOf(r, valueOf(r.isMainThread()));
@@ -107,19 +127,22 @@ public class CoroutineLib extends TwoArgFunction {
}
static final class status extends LibFunction {
+ @Override
public LuaValue call(LuaValue t) {
LuaThread lt = t.checkthread();
- return valueOf( lt.getStatus() );
+ return valueOf(lt.getStatus());
}
}
-
+
final class yield extends VarArgFunction {
+ @Override
public Varargs invoke(Varargs args) {
- return globals.yield( args );
+ return globals.yield(args);
}
}
final class wrap extends LibFunction {
+ @Override
public LuaValue call(LuaValue f) {
final LuaValue func = f.checkfunction();
final LuaThread thread = new LuaThread(globals, func);
@@ -129,15 +152,18 @@ public class CoroutineLib extends TwoArgFunction {
static final class wrapper extends VarArgFunction {
final LuaThread luathread;
+
wrapper(LuaThread luathread) {
this.luathread = luathread;
}
+
+ @Override
public Varargs invoke(Varargs args) {
final Varargs result = luathread.resume(args);
- if ( result.arg1().toboolean() ) {
+ if (result.arg1().toboolean()) {
return result.subargs(2);
} else {
- return error( result.arg(2).tojstring() );
+ return error(result.arg(2).tojstring());
}
}
}
diff --git a/src/core/org/luaj/vm2/lib/DebugLib.java b/luaj-core/src/main/java/org/luaj/vm2/lib/DebugLib.java
similarity index 60%
rename from src/core/org/luaj/vm2/lib/DebugLib.java
rename to luaj-core/src/main/java/org/luaj/vm2/lib/DebugLib.java
index 167ea36c..db138151 100644
--- a/src/core/org/luaj/vm2/lib/DebugLib.java
+++ b/luaj-core/src/main/java/org/luaj/vm2/lib/DebugLib.java
@@ -10,7 +10,7 @@
*
* 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
@@ -39,58 +39,73 @@ import org.luaj.vm2.Prototype;
import org.luaj.vm2.Varargs;
/**
- * Subclass of {@link LibFunction} which implements the lua standard {@code debug}
- * library.
+ * Subclass of {@link LibFunction} which implements the lua standard
+ * {@code debug} library.
*
- * The debug library in luaj tries to emulate the behavior of the corresponding C-based lua library.
- * To do this, it must maintain a separate stack of calls to {@link LuaClosure} and {@link LibFunction}
- * instances.
- * Especially when lua-to-java bytecode compiling is being used
- * via a {@link org.luaj.vm2.Globals.Compiler} such as {@link org.luaj.vm2.luajc.LuaJC},
- * this cannot be done in all cases.
+ * The debug library in luaj tries to emulate the behavior of the corresponding
+ * C-based lua library. To do this, it must maintain a separate stack of calls
+ * to {@link LuaClosure} and {@link LibFunction} instances. Especially when
+ * lua-to-java bytecode compiling is being used via a
+ * {@link org.luaj.vm2.Globals.Compiler} such as
+ * {@link org.luaj.vm2.luajc.LuaJC}, this cannot be done in all cases.
*
* Typically, this library is included as part of a call to either
* {@link org.luaj.vm2.lib.jse.JsePlatform#debugGlobals()} or
* {@link org.luaj.vm2.lib.jme.JmePlatform#debugGlobals()}
- *
- * To instantiate and use it directly,
- * link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
- *
- * This library exposes the entire state of lua code, and provides method to see and modify
- * all underlying lua values within a Java VM so should not be exposed to client code
- * in a shared server environment.
- *
+ * This library exposes the entire state of lua code, and provides method to see
+ * and modify all underlying lua values within a Java VM so should not be
+ * exposed to client code in a shared server environment.
+ *
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
- * @see Lua 5.2 Debug Lib Reference
+ * @see Lua 5.2 Debug
+ * Lib Reference
*/
public class DebugLib extends TwoArgFunction {
public static boolean CALLS;
public static boolean TRACE;
static {
- try { CALLS = (null != System.getProperty("CALLS")); } catch (Exception e) {}
- try { TRACE = (null != System.getProperty("TRACE")); } catch (Exception e) {}
+ try {
+ CALLS = null != System.getProperty("CALLS");
+ } catch (Exception e) {
+ }
+ try {
+ TRACE = null != System.getProperty("TRACE");
+ } catch (Exception e) {
+ }
}
-
- static final LuaString LUA = valueOf("Lua");
- private static final LuaString QMARK = valueOf("?");
- private static final LuaString CALL = valueOf("call");
- private static final LuaString LINE = valueOf("line");
- private static final LuaString COUNT = valueOf("count");
- private static final LuaString RETURN = valueOf("return");
-
+
+ static final LuaString LUA = valueOf("Lua");
+ private static final LuaString QMARK = valueOf("?");
+ private static final LuaString CALL = valueOf("call");
+ private static final LuaString LINE = valueOf("line");
+ private static final LuaString COUNT = valueOf("count");
+ private static final LuaString RETURN = valueOf("return");
+
static final LuaString FUNC = valueOf("func");
static final LuaString ISTAILCALL = valueOf("istailcall");
static final LuaString ISVARARG = valueOf("isvararg");
@@ -107,13 +122,18 @@ public class DebugLib extends TwoArgFunction {
static final LuaString ACTIVELINES = valueOf("activelines");
Globals globals;
-
- /** Perform one-time initialization on the library by creating a table
- * containing the library functions, adding that table to the supplied environment,
- * adding the table to package.loaded, and returning table as the return value.
+
+ /**
+ * Perform one-time initialization on the library by creating a table
+ * containing the library functions, adding that table to the supplied
+ * environment, adding the table to package.loaded, and returning table as
+ * the return value.
+ *
* @param modname the module name supplied if this is loaded via 'require'.
- * @param env the environment to load into, which must be a Globals instance.
+ * @param env the environment to load into, which must be a Globals
+ * instance.
*/
+ @Override
public LuaValue call(LuaValue modname, LuaValue env) {
globals = env.checkglobals();
globals.debuglib = this;
@@ -135,12 +155,14 @@ public class DebugLib extends TwoArgFunction {
debug.set("upvalueid", new upvalueid());
debug.set("upvaluejoin", new upvaluejoin());
env.set("debug", debug);
- if (!env.get("package").isnil()) env.get("package").get("loaded").set("debug", debug);
+ if (!env.get("package").isnil())
+ env.get("package").get("loaded").set("debug", debug);
return debug;
}
// debug.debug()
static final class debug extends ZeroArgFunction {
+ @Override
public LuaValue call() {
return NONE;
}
@@ -148,20 +170,20 @@ public class DebugLib extends TwoArgFunction {
// debug.gethook ([thread])
final class gethook extends VarArgFunction {
+ @Override
public Varargs invoke(Varargs args) {
- LuaThread t = args.narg() > 0 ? args.checkthread(1): globals.running;
+ LuaThread t = args.narg() > 0? args.checkthread(1): globals.running;
LuaThread.State s = t.state;
- return varargsOf(
- s.hookfunc != null? s.hookfunc: NIL,
- valueOf((s.hookcall?"c":"")+(s.hookline?"l":"")+(s.hookrtrn?"r":"")),
- valueOf(s.hookcount));
+ return varargsOf(s.hookfunc != null? s.hookfunc: NIL,
+ valueOf((s.hookcall? "c": "")+(s.hookline? "l": "")+(s.hookrtrn? "r": "")), valueOf(s.hookcount));
}
}
// debug.getinfo ([thread,] f [, what])
final class getinfo extends VarArgFunction {
+ @Override
public Varargs invoke(Varargs args) {
- int a=1;
+ int a = 1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running;
LuaValue func = args.arg(a++);
String what = args.optjstring(a++, "flnStu");
@@ -169,12 +191,12 @@ public class DebugLib extends TwoArgFunction {
// find the stack info
DebugLib.CallFrame frame;
- if ( func.isnumber() ) {
+ if (func.isnumber()) {
frame = callstack.getCallFrame(func.toint());
if (frame == null)
return NONE;
func = frame.f;
- } else if ( func.isfunction() ) {
+ } else if (func.isfunction()) {
frame = callstack.findCallFrame(func);
} else {
return argerror(a-2, "function or level");
@@ -191,7 +213,7 @@ public class DebugLib extends TwoArgFunction {
info.set(LASTLINEDEFINED, valueOf(ar.lastlinedefined));
}
if (what.indexOf('l') >= 0) {
- info.set( CURRENTLINE, valueOf(ar.currentline) );
+ info.set(CURRENTLINE, valueOf(ar.currentline));
}
if (what.indexOf('u') >= 0) {
info.set(NUPS, valueOf(ar.nups));
@@ -199,7 +221,7 @@ public class DebugLib extends TwoArgFunction {
info.set(ISVARARG, ar.isvararg? ONE: ZERO);
}
if (what.indexOf('n') >= 0) {
- info.set(NAME, LuaValue.valueOf(ar.name!=null? ar.name: "?"));
+ info.set(NAME, LuaValue.valueOf(ar.name != null? ar.name: "?"));
info.set(NAMEWHAT, LuaValue.valueOf(ar.namewhat));
}
if (what.indexOf('t') >= 0) {
@@ -209,13 +231,13 @@ public class DebugLib extends TwoArgFunction {
LuaTable lines = new LuaTable();
info.set(ACTIVELINES, lines);
DebugLib.CallFrame cf;
- for (int l = 1; (cf=callstack.getCallFrame(l)) != null; ++l)
+ for (int l = 1; (cf = callstack.getCallFrame(l)) != null; ++l)
if (cf.f == func)
lines.insert(-1, valueOf(cf.currentline()));
}
if (what.indexOf('f') >= 0) {
if (func != null)
- info.set( FUNC, func );
+ info.set(FUNC, func);
}
return info;
}
@@ -223,18 +245,27 @@ public class DebugLib extends TwoArgFunction {
// debug.getlocal ([thread,] f, local)
final class getlocal extends VarArgFunction {
+ @Override
public Varargs invoke(Varargs args) {
- int a=1;
+ int a = 1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running;
- int level = args.checkint(a++);
- int local = args.checkint(a++);
- CallFrame f = callstack(thread).getCallFrame(level);
- return f != null? f.getLocal(local): NONE;
+ LuaValue func = args.arg(a++);
+ int local = args.checkint(a);
+
+ if (func.isfunction())
+ return func.checkclosure().p.getlocalname(local, 0);
+
+ // find the stack info
+ DebugLib.CallFrame frame = callstack(thread).getCallFrame(func.checkint());
+ if (frame == null)
+ return argerror(a, "level out of range");
+ return frame.getLocal(local);
}
}
// debug.getmetatable (value)
static final class getmetatable extends LibFunction {
+ @Override
public LuaValue call(LuaValue v) {
LuaValue mt = v.getmetatable();
return mt != null? mt: NIL;
@@ -243,6 +274,7 @@ public class DebugLib extends TwoArgFunction {
// debug.getregistry ()
final class getregistry extends ZeroArgFunction {
+ @Override
public LuaValue call() {
return globals;
}
@@ -250,14 +282,15 @@ public class DebugLib extends TwoArgFunction {
// debug.getupvalue (f, up)
static final class getupvalue extends VarArgFunction {
+ @Override
public Varargs invoke(Varargs args) {
LuaValue func = args.checkfunction(1);
int up = args.checkint(2);
- if ( func instanceof LuaClosure ) {
+ if (func instanceof LuaClosure) {
LuaClosure c = (LuaClosure) func;
LuaString name = findupvalue(c, up);
- if ( name != null ) {
- return varargsOf(name, c.upValues[up-1].getValue() );
+ if (name != null) {
+ return varargsOf(name, c.upValues[up-1].getValue());
}
}
return NIL;
@@ -266,26 +299,33 @@ public class DebugLib extends TwoArgFunction {
// debug.getuservalue (u)
static final class getuservalue extends LibFunction {
+ @Override
public LuaValue call(LuaValue u) {
return u.isuserdata()? u: NIL;
}
}
-
-
+
// debug.sethook ([thread,] hook, mask [, count])
final class sethook extends VarArgFunction {
+ @Override
public Varargs invoke(Varargs args) {
- int a=1;
+ int a = 1;
LuaThread t = args.isthread(a)? args.checkthread(a++): globals.running;
- LuaValue func = args.optfunction(a++, null);
- String str = args.optjstring(a++,"");
- int count = args.optint(a++,0);
- boolean call=false,line=false,rtrn=false;
- for ( int i=0; i
* It contains the implementation of the io library support that is common to
- * the JSE and JME platforms.
- * In practice on of the concrete IOLib subclasses is chosen:
- * {@link org.luaj.vm2.lib.jse.JseIoLib} for the JSE platform, and
+ * the JSE and JME platforms. In practice on of the concrete IOLib subclasses is
+ * chosen: {@link org.luaj.vm2.lib.jse.JseIoLib} for the JSE platform, and
* {@link org.luaj.vm2.lib.jme.JmeIoLib} for the JME platform.
*
* The JSE implementation conforms almost completely to the C-based lua library,
- * while the JME implementation follows closely except in the area of random-access files,
- * which are difficult to support properly on JME.
+ * while the JME implementation follows closely except in the area of
+ * random-access files, which are difficult to support properly on JME.
*
* Typically, this library is included as part of a call to either
- * {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
- *
- * To instantiate and use it directly,
- * link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
- *
- * This has been implemented to match as closely as possible the behavior in the corresponding library in C.
+ * This has been implemented to match as closely as possible the behavior in the
+ * corresponding library in C.
+ *
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see org.luaj.vm2.lib.jse.JseIoLib
* @see org.luaj.vm2.lib.jme.JmeIoLib
- * @see http://www.lua.org/manual/5.1/manual.html#5.7
+ * @see http://www.lua.org/manual/5.1/manual.html#5.7
*/
-abstract
-public class IoLib extends TwoArgFunction {
+public abstract class IoLib extends TwoArgFunction {
+
+ protected abstract class File extends LuaValue {
+ public abstract void write(LuaString string) throws IOException;
+
+ public abstract void flush() throws IOException;
+
+ public abstract boolean isstdfile();
+
+ public abstract void close() throws IOException;
+
+ public abstract boolean isclosed();
- abstract
- protected class File extends LuaValue{
- abstract public void write( LuaString string ) throws IOException;
- abstract public void flush() throws IOException;
- abstract public boolean isstdfile();
- abstract public void close() throws IOException;
- abstract public boolean isclosed();
// returns new position
- abstract public int seek(String option, int bytecount) throws IOException;
- abstract public void setvbuf(String mode, int size);
+ public abstract int seek(String option, int bytecount) throws IOException;
+
+ public abstract void setvbuf(String mode, int size);
+
// get length remaining to read
- abstract public int remaining() throws IOException;
+ public abstract int remaining() throws IOException;
+
// peek ahead one character
- abstract public int peek() throws IOException, EOFException;
+ public abstract int peek() throws IOException, EOFException;
+
// return char if read, -1 if eof, throw IOException on other exception
- abstract public int read() throws IOException, EOFException;
+ public abstract int read() throws IOException, EOFException;
+
// return number of bytes read if positive, false if eof, throw IOException on other exception
- abstract public int read(byte[] bytes, int offset, int length) throws IOException;
-
+ public abstract int read(byte[] bytes, int offset, int length) throws IOException;
+
public boolean eof() throws IOException {
try {
return peek() < 0;
- } catch (EOFException e) { return true; }
+ } catch (EOFException e) {
+ return true;
+ }
}
-
+
// delegate method access to file methods table
- public LuaValue get( LuaValue key ) {
+ @Override
+ public LuaValue get(LuaValue key) {
return filemethods.get(key);
}
// essentially a userdata instance
+ @Override
public int type() {
return LuaValue.TUSERDATA;
}
+
+ @Override
public String typename() {
return "userdata";
}
-
+
// displays as "file" type
+ @Override
public String tojstring() {
return "file: " + Integer.toHexString(hashCode());
}
-
+
+ @Override
public void finalize() {
if (!isclosed()) {
try {
close();
- } catch (IOException ignore) {}
+ } catch (IOException ignore) {
+ }
}
}
}
/** Enumerated value representing stdin */
- protected static final int FTYPE_STDIN = 0;
+ protected static final int FTYPE_STDIN = 0;
/** Enumerated value representing stdout */
protected static final int FTYPE_STDOUT = 1;
/** Enumerated value representing stderr */
protected static final int FTYPE_STDERR = 2;
/** Enumerated value representing a file type for a named file */
- protected static final int FTYPE_NAMED = 3;
+ protected static final int FTYPE_NAMED = 3;
/**
* Wrap the standard input.
+ *
* @return File
* @throws IOException
*/
@@ -146,32 +177,37 @@ public class IoLib extends TwoArgFunction {
/**
* Wrap the standard output.
+ *
* @return File
* @throws IOException
*/
abstract protected File wrapStdout() throws IOException;
-
+
/**
* Wrap the standard error output.
+ *
* @return File
* @throws IOException
*/
abstract protected File wrapStderr() throws IOException;
-
+
/**
* Open a file in a particular mode.
+ *
* @param filename
- * @param readMode true if opening in read mode
+ * @param readMode true if opening in read mode
* @param appendMode true if opening in append mode
* @param updateMode true if opening in update mode
* @param binaryMode true if opening in binary mode
* @return File object if successful
* @throws IOException if could not be opened
*/
- abstract protected File openFile( String filename, boolean readMode, boolean appendMode, boolean updateMode, boolean binaryMode ) throws IOException;
+ abstract protected File openFile(String filename, boolean readMode, boolean appendMode, boolean updateMode,
+ boolean binaryMode) throws IOException;
/**
* Open a temporary file.
+ *
* @return File object if successful
* @throws IOException if could not be opened
*/
@@ -179,6 +215,7 @@ public class IoLib extends TwoArgFunction {
/**
* Start a new process and return a file for input or output
+ *
* @param prog the program to execute
* @param mode "r" to read, "w" to write
* @return File to read to or write from
@@ -195,152 +232,158 @@ public class IoLib extends TwoArgFunction {
private static final LuaValue STDERR = valueOf("stderr");
private static final LuaValue FILE = valueOf("file");
private static final LuaValue CLOSED_FILE = valueOf("closed file");
-
- private static final int IO_CLOSE = 0;
- private static final int IO_FLUSH = 1;
- private static final int IO_INPUT = 2;
- private static final int IO_LINES = 3;
- private static final int IO_OPEN = 4;
- private static final int IO_OUTPUT = 5;
- private static final int IO_POPEN = 6;
- private static final int IO_READ = 7;
- private static final int IO_TMPFILE = 8;
- private static final int IO_TYPE = 9;
- private static final int IO_WRITE = 10;
- private static final int FILE_CLOSE = 11;
- private static final int FILE_FLUSH = 12;
- private static final int FILE_LINES = 13;
- private static final int FILE_READ = 14;
- private static final int FILE_SEEK = 15;
- private static final int FILE_SETVBUF = 16;
- private static final int FILE_WRITE = 17;
-
- private static final int IO_INDEX = 18;
- private static final int LINES_ITER = 19;
+ private static final int IO_CLOSE = 0;
+ private static final int IO_FLUSH = 1;
+ private static final int IO_INPUT = 2;
+ private static final int IO_LINES = 3;
+ private static final int IO_OPEN = 4;
+ private static final int IO_OUTPUT = 5;
+ private static final int IO_POPEN = 6;
+ private static final int IO_READ = 7;
+ private static final int IO_TMPFILE = 8;
+ private static final int IO_TYPE = 9;
+ private static final int IO_WRITE = 10;
- public static final String[] IO_NAMES = {
- "close",
- "flush",
- "input",
- "lines",
- "open",
- "output",
- "popen",
- "read",
- "tmpfile",
- "type",
- "write",
- };
-
- public static final String[] FILE_NAMES = {
- "close",
- "flush",
- "lines",
- "read",
- "seek",
- "setvbuf",
- "write",
- };
+ private static final int FILE_CLOSE = 11;
+ private static final int FILE_FLUSH = 12;
+ private static final int FILE_LINES = 13;
+ private static final int FILE_READ = 14;
+ private static final int FILE_SEEK = 15;
+ private static final int FILE_SETVBUF = 16;
+ private static final int FILE_WRITE = 17;
+
+ private static final int IO_INDEX = 18;
+ private static final int LINES_ITER = 19;
+
+ public static final String[] IO_NAMES = { "close", "flush", "input", "lines", "open", "output", "popen", "read",
+ "tmpfile", "type", "write", };
+
+ public static final String[] FILE_NAMES = { "close", "flush", "lines", "read", "seek", "setvbuf", "write", };
LuaTable filemethods;
-
+
protected Globals globals;
-
+
+ @Override
public LuaValue call(LuaValue modname, LuaValue env) {
globals = env.checkglobals();
-
+
// io lib functions
LuaTable t = new LuaTable();
- bind(t, IoLibV.class, IO_NAMES );
-
+ bind(t, IoLibV.class, IO_NAMES);
+
// create file methods table
filemethods = new LuaTable();
- bind(filemethods, IoLibV.class, FILE_NAMES, FILE_CLOSE );
+ bind(filemethods, IoLibV.class, FILE_NAMES, FILE_CLOSE);
// set up file metatable
LuaTable mt = new LuaTable();
- bind(mt, IoLibV.class, new String[] { "__index" }, IO_INDEX );
- t.setmetatable( mt );
-
+ bind(mt, IoLibV.class, new String[] { "__index" }, IO_INDEX);
+ t.setmetatable(mt);
+
// all functions link to library instance
- setLibInstance( t );
- setLibInstance( filemethods );
- setLibInstance( mt );
-
+ setLibInstance(t);
+ setLibInstance(filemethods);
+ setLibInstance(mt);
+
// return the table
env.set("io", t);
- if (!env.get("package").isnil()) env.get("package").get("loaded").set("io", t);
+ if (!env.get("package").isnil())
+ env.get("package").get("loaded").set("io", t);
return t;
}
private void setLibInstance(LuaTable t) {
LuaValue[] k = t.keys();
- for ( int i=0, n=k.length; i
- * To provide for common implementations in JME and JSE,
- * library functions are typically grouped on one or more library classes
- * and an opcode per library function is defined and used to key the switch
- * to the correct function within the library.
+ * To provide for common implementations in JME and JSE, library functions are
+ * typically grouped on one or more library classes and an opcode per library
+ * function is defined and used to key the switch to the correct function within
+ * the library.
*
- * Since lua functions can be called with too few or too many arguments,
- * and there are overloaded {@link LuaValue#call()} functions with varying
- * number of arguments, a Java function exposed in lua needs to handle the
- * argument fixup when a function is called with a number of arguments
- * differs from that expected.
+ * Since lua functions can be called with too few or too many arguments, and
+ * there are overloaded {@link LuaValue#call()} functions with varying number of
+ * arguments, a Java function exposed in lua needs to handle the argument fixup
+ * when a function is called with a number of arguments differs from that
+ * expected.
*
- * To simplify the creation of library functions,
- * there are 5 direct subclasses to handle common cases based on number of
- * argument values and number of return return values.
+ * To simplify the creation of library functions, there are 5 direct subclasses
+ * to handle common cases based on number of argument values and number of
+ * return return values.
*
- * To be a Java library that can be loaded via {@code require}, it should have
- * a public constructor that returns a {@link LuaValue} that, when executed,
+ * To be a Java library that can be loaded via {@code require}, it should have a
+ * public constructor that returns a {@link LuaValue} that, when executed,
* initializes the library.
*
* For example, the following code will implement a library called "hyperbolic"
* with two functions, "sinh", and "cosh":
-
* To test it, a script such as this can be used:
- *
* It should produce something like:
- *
- * See the source code in any of the library functions
- * such as {@link BaseLib} or {@link TableLib} for other examples.
+ * See the source code in any of the library functions such as {@link BaseLib}
+ * or {@link TableLib} for other examples.
*/
abstract public class LibFunction extends LuaFunction {
-
- /** User-defined opcode to differentiate between instances of the library function class.
+
+ /**
+ * User-defined opcode to differentiate between instances of the library
+ * function class.
*
- * Subclass will typicall switch on this value to provide the specific behavior for each function.
+ * Subclass will typicall switch on this value to provide the specific
+ * behavior for each function.
*/
protected int opcode;
-
- /** The common name for this function, useful for debugging.
+
+ /**
+ * The common name for this function, useful for debugging.
*
* Binding functions initialize this to the name to which it is bound.
*/
protected String name;
-
+
/** Default constructor for use by subclasses */
protected LibFunction() {
}
-
+
+ @Override
public String tojstring() {
- return name != null ? "function: " + name : super.tojstring();
+ return name != null? "function: " + name: super.tojstring();
}
-
+
/**
* Bind a set of library functions.
*
- * An array of names is provided, and the first name is bound
- * with opcode = 0, second with 1, etc.
- * @param env The environment to apply to each bound function
+ * An array of names is provided, and the first name is bound with opcode =
+ * 0, second with 1, etc.
+ *
+ * @param env The environment to apply to each bound function
* @param factory the Class to instantiate for each bound function
- * @param names array of String names, one for each function.
+ * @param names array of String names, one for each function.
* @see #bind(LuaValue, Class, String[], int)
*/
- protected void bind(LuaValue env, Class factory, String[] names ) {
- bind( env, factory, names, 0 );
+ protected void bind(LuaValue env, Class factory, String[] names) {
+ bind(env, factory, names, 0);
}
-
+
/**
* Bind a set of library functions, with an offset
*
- * An array of names is provided, and the first name is bound
- * with opcode = {@code firstopcode}, second with {@code firstopcode+1}, etc.
- * @param env The environment to apply to each bound function
- * @param factory the Class to instantiate for each bound function
- * @param names array of String names, one for each function.
+ * An array of names is provided, and the first name is bound with opcode =
+ * {@code firstopcode}, second with {@code firstopcode+1}, etc.
+ *
+ * @param env The environment to apply to each bound function
+ * @param factory the Class to instantiate for each bound function
+ * @param names array of String names, one for each function.
* @param firstopcode the first opcode to use
* @see #bind(LuaValue, Class, String[])
*/
- protected void bind(LuaValue env, Class factory, String[] names, int firstopcode ) {
+ protected void bind(LuaValue env, Class factory, String[] names, int firstopcode) {
try {
- for ( int i=0, n=names.length; i
* The implementations of {@code exp()} and {@code pow()} are constructed by
- * hand for JME, so will be slower and less accurate than when executed on the JSE platform.
+ * hand for JME, so will be slower and less accurate than when executed on the
+ * JSE platform.
*
* Typically, this library is included as part of a call to either
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
- *
- * To instantiate and use it directly,
- * link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
- *
- * This has been implemented to match as closely as possible the behavior in the corresponding library in C.
+ * This has been implemented to match as closely as possible the behavior in the
+ * corresponding library in C.
+ *
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see org.luaj.vm2.lib.jse.JseMathLib
- * @see Lua 5.2 Math Lib Reference
+ * @see Lua 5.2 Math Lib
+ * Reference
*/
public class MathLib extends TwoArgFunction {
- /** Pointer to the latest MathLib instance, used only to dispatch
- * math.exp to tha correct platform math library.
+ /**
+ * Pointer to the latest MathLib instance, used only to dispatch math.exp to
+ * tha correct platform math library.
*/
public static MathLib MATHLIB = null;
- /** Construct a MathLib, which can be initialized by calling it with a
+ /**
+ * Construct a MathLib, which can be initialized by calling it with a
* modname string, and a global environment table as arguments using
- * {@link #call(LuaValue, LuaValue)}. */
+ * {@link #call(LuaValue, LuaValue)}.
+ */
public MathLib() {
MATHLIB = this;
}
- /** Perform one-time initialization on the library by creating a table
- * containing the library functions, adding that table to the supplied environment,
- * adding the table to package.loaded, and returning table as the return value.
+ /**
+ * Perform one-time initialization on the library by creating a table
+ * containing the library functions, adding that table to the supplied
+ * environment, adding the table to package.loaded, and returning table as
+ * the return value.
+ *
* @param modname the module name supplied if this is loaded via 'require'.
- * @param env the environment to load into, typically a Globals instance.
+ * @param env the environment to load into, typically a Globals
+ * instance.
*/
+ @Override
public LuaValue call(LuaValue modname, LuaValue env) {
- LuaTable math = new LuaTable(0,30);
+ LuaTable math = new LuaTable(0, 30);
math.set("abs", new abs());
math.set("ceil", new ceil());
math.set("cos", new cos());
@@ -110,12 +132,12 @@ public class MathLib extends TwoArgFunction {
math.set("floor", new floor());
math.set("fmod", new fmod());
math.set("frexp", new frexp());
- math.set("huge", LuaDouble.POSINF );
+ math.set("huge", LuaDouble.POSINF);
math.set("ldexp", new ldexp());
math.set("max", new max());
math.set("min", new min());
math.set("modf", new modf());
- math.set("pi", Math.PI );
+ math.set("pi", Math.PI);
math.set("pow", new pow());
random r;
math.set("random", r = new random());
@@ -125,178 +147,246 @@ public class MathLib extends TwoArgFunction {
math.set("sqrt", new sqrt());
math.set("tan", new tan());
env.set("math", math);
- if (!env.get("package").isnil()) env.get("package").get("loaded").set("math", math);
+ if (!env.get("package").isnil())
+ env.get("package").get("loaded").set("math", math);
return math;
}
-
+
abstract protected static class UnaryOp extends OneArgFunction {
+ @Override
public LuaValue call(LuaValue arg) {
return valueOf(call(arg.checkdouble()));
}
+
abstract protected double call(double d);
}
abstract protected static class BinaryOp extends TwoArgFunction {
+ @Override
public LuaValue call(LuaValue x, LuaValue y) {
return valueOf(call(x.checkdouble(), y.checkdouble()));
}
+
abstract protected double call(double x, double y);
}
- static final class abs extends UnaryOp { protected double call(double d) { return Math.abs(d); } }
- static final class ceil extends UnaryOp { protected double call(double d) { return Math.ceil(d); } }
- static final class cos extends UnaryOp { protected double call(double d) { return Math.cos(d); } }
- static final class deg extends UnaryOp { protected double call(double d) { return Math.toDegrees(d); } }
- static final class floor extends UnaryOp { protected double call(double d) { return Math.floor(d); } }
- static final class rad extends UnaryOp { protected double call(double d) { return Math.toRadians(d); } }
- static final class sin extends UnaryOp { protected double call(double d) { return Math.sin(d); } }
- static final class sqrt extends UnaryOp { protected double call(double d) { return Math.sqrt(d); } }
- static final class tan extends UnaryOp { protected double call(double d) { return Math.tan(d); } }
+ static final class abs extends UnaryOp {
+ @Override
+ protected double call(double d) { return Math.abs(d); }
+ }
+
+ static final class ceil extends UnaryOp {
+ @Override
+ protected double call(double d) { return Math.ceil(d); }
+ }
+
+ static final class cos extends UnaryOp {
+ @Override
+ protected double call(double d) { return Math.cos(d); }
+ }
+
+ static final class deg extends UnaryOp {
+ @Override
+ protected double call(double d) { return Math.toDegrees(d); }
+ }
+
+ static final class floor extends UnaryOp {
+ @Override
+ protected double call(double d) { return Math.floor(d); }
+ }
+
+ static final class rad extends UnaryOp {
+ @Override
+ protected double call(double d) { return Math.toRadians(d); }
+ }
+
+ static final class sin extends UnaryOp {
+ @Override
+ protected double call(double d) { return Math.sin(d); }
+ }
+
+ static final class sqrt extends UnaryOp {
+ @Override
+ protected double call(double d) { return Math.sqrt(d); }
+ }
+
+ static final class tan extends UnaryOp {
+ @Override
+ protected double call(double d) { return Math.tan(d); }
+ }
static final class exp extends UnaryOp {
final MathLib mathlib;
+
exp(MathLib mathlib) {
this.mathlib = mathlib;
}
+
+ @Override
protected double call(double d) {
- return mathlib.dpow_lib(Math.E,d);
+ return mathlib.dpow_lib(Math.E, d);
}
}
-
+
static final class fmod extends TwoArgFunction {
+ @Override
public LuaValue call(LuaValue xv, LuaValue yv) {
+ if (yv.checkdouble() == 0.0d)
+ return LuaDouble.NAN;
if (xv.islong() && yv.islong()) {
- return valueOf(xv.tolong() % yv.tolong());
+ return valueOf(xv.tolong()%yv.tolong());
}
- return valueOf(xv.checkdouble() % yv.checkdouble());
+ return valueOf(xv.checkdouble()%yv.checkdouble());
}
}
+
static final class ldexp extends BinaryOp {
+ @Override
protected double call(double x, double y) {
// This is the behavior on os-x, windows differs in rounding behavior.
- return x * Double.longBitsToDouble((((long) y) + 1023) << 52);
+ return x*Double.longBitsToDouble((long) y+1023<<52);
}
}
+
static final class pow extends BinaryOp {
+ @Override
protected double call(double x, double y) {
return MathLib.dpow_default(x, y);
}
}
static class frexp extends VarArgFunction {
+ @Override
public Varargs invoke(Varargs args) {
double x = args.checkdouble(1);
- if ( x == 0 ) return varargsOf(ZERO,ZERO);
- long bits = Double.doubleToLongBits( x );
- double m = ((bits & (~(-1L<<52))) + (1L<<52)) * ((bits >= 0)? (.5 / (1L<<52)): (-.5 / (1L<<52)));
- double e = (((int) (bits >> 52)) & 0x7ff) - 1022;
- return varargsOf( valueOf(m), valueOf(e) );
+ if (x == 0)
+ return varargsOf(ZERO, ZERO);
+ long bits = Double.doubleToLongBits(x);
+ double m = ((bits & ~(-1L<<52))+(1L<<52))*(bits >= 0? .5/(1L<<52): -.5/(1L<<52));
+ double e = ((int) (bits>>52) & 0x7ff)-1022;
+ return varargsOf(valueOf(m), valueOf(e));
}
}
static class max extends VarArgFunction {
+ @Override
public Varargs invoke(Varargs args) {
- LuaValue m = args.checkvalue(1);
- for ( int i=2,n=args.narg(); i<=n; ++i ) {
- LuaValue v = args.checkvalue(i);
- if (m.lt_b(v)) m = v;
+ LuaValue m = args.checknumber(1);
+ for (int i = 2, n = args.narg(); i <= n; ++i) {
+ LuaValue v = args.checknumber(i);
+ if (m.lt_b(v))
+ m = v;
}
return m;
}
}
-
+
static class min extends VarArgFunction {
+ @Override
public Varargs invoke(Varargs args) {
- LuaValue m = args.checkvalue(1);
- for ( int i=2,n=args.narg(); i<=n; ++i ) {
- LuaValue v = args.checkvalue(i);
- if (v.lt_b(m)) m = v;
+ LuaValue m = args.checknumber(1);
+ for (int i = 2, n = args.narg(); i <= n; ++i) {
+ LuaValue v = args.checknumber(i);
+ if (v.lt_b(m))
+ m = v;
}
return m;
}
}
-
+
static class modf extends VarArgFunction {
+ @Override
public Varargs invoke(Varargs args) {
LuaValue n = args.arg1();
/* number is its own integer part, no fractional part */
- if (n.islong()) return varargsOf(n, valueOf(0.0));
+ if (n.islong())
+ return varargsOf(n.tonumber(), valueOf(0.0));
double x = n.checkdouble();
/* integer part (rounds toward zero) */
- double intPart = ( x > 0 ) ? Math.floor( x ) : Math.ceil( x );
+ double intPart = x > 0? Math.floor(x): Math.ceil(x);
/* fractional part (test needed for inf/-inf) */
- double fracPart = x == intPart ? 0.0 : x - intPart;
- return varargsOf( valueOf(intPart), valueOf(fracPart) );
+ double fracPart = x == intPart? 0.0: x-intPart;
+ return varargsOf(valueOf(intPart), valueOf(fracPart));
}
}
-
+
static class random extends LibFunction {
Random random = new Random();
+
+ @Override
public LuaValue call() {
- return valueOf( random.nextDouble() );
+ return valueOf(random.nextDouble());
}
+
+ @Override
public LuaValue call(LuaValue a) {
int m = a.checkint();
- if (m<1) argerror(1, "interval is empty");
- return valueOf( 1 + random.nextInt(m) );
+ if (m < 1)
+ argerror(1, "interval is empty");
+ return valueOf(1+random.nextInt(m));
}
+
+ @Override
public LuaValue call(LuaValue a, LuaValue b) {
int m = a.checkint();
int n = b.checkint();
- if (n
- * Subclasses need only implement {@link LuaValue#call(LuaValue)} to complete this class,
- * simplifying development.
- * All other uses of {@link #call()}, {@link #invoke(Varargs)},etc,
- * are routed through this method by this class,
+ * Subclasses need only implement {@link LuaValue#call(LuaValue)} to complete
+ * this class, simplifying development. All other uses of {@link #call()},
+ * {@link #invoke(Varargs)},etc, are routed through this method by this class,
* dropping or extending arguments with {@code nil} values as required.
*
- * If more than one argument are required, or no arguments are required,
- * or variable argument or variable return values,
- * then use one of the related function
- * {@link ZeroArgFunction}, {@link TwoArgFunction}, {@link ThreeArgFunction}, or {@link VarArgFunction}.
+ * If more than one argument are required, or no arguments are required, or
+ * variable argument or variable return values, then use one of the related
+ * function {@link ZeroArgFunction}, {@link TwoArgFunction},
+ * {@link ThreeArgFunction}, or {@link VarArgFunction}.
*
- * See {@link LibFunction} for more information on implementation libraries and library functions.
+ * See {@link LibFunction} for more information on implementation libraries and
+ * library functions.
+ *
* @see #call(LuaValue)
* @see LibFunction
* @see ZeroArgFunction
@@ -48,25 +50,30 @@ import org.luaj.vm2.Varargs;
*/
abstract public class OneArgFunction extends LibFunction {
+ @Override
abstract public LuaValue call(LuaValue arg);
-
+
/** Default constructor */
public OneArgFunction() {
}
-
+
+ @Override
public final LuaValue call() {
return call(NIL);
}
+ @Override
public final LuaValue call(LuaValue arg1, LuaValue arg2) {
return call(arg1);
}
+ @Override
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
return call(arg1);
}
+ @Override
public Varargs invoke(Varargs varargs) {
return call(varargs.arg1());
}
-}
+}
diff --git a/luaj-core/src/main/java/org/luaj/vm2/lib/OsLib.java b/luaj-core/src/main/java/org/luaj/vm2/lib/OsLib.java
new file mode 100644
index 00000000..e87cafed
--- /dev/null
+++ b/luaj-core/src/main/java/org/luaj/vm2/lib/OsLib.java
@@ -0,0 +1,522 @@
+/*******************************************************************************
+* Copyright (c) 2009 Luaj.org. All rights reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+******************************************************************************/
+package org.luaj.vm2.lib;
+
+import java.io.IOException;
+import java.time.format.TextStyle;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import org.luaj.vm2.Buffer;
+import org.luaj.vm2.Globals;
+import org.luaj.vm2.LuaTable;
+import org.luaj.vm2.LuaValue;
+import org.luaj.vm2.Varargs;
+
+/**
+ * Subclass of {@link LibFunction} which implements the standard lua {@code os}
+ * library.
+ *
+ * It is a usable base with simplified stub functions for library functions that
+ * cannot be implemented uniformly on Jse and Jme.
+ *
+ * This can be installed as-is on either platform, or extended and refined to be
+ * used in a complete Jse implementation.
+ *
+ * Because the nature of the {@code os} library is to encapsulate os-specific
+ * features, the behavior of these functions varies considerably from their
+ * counterparts in the C platform.
+ *
+ * The following functions have limited implementations of features that are not
+ * supported well on Jme:
+ *
+ * Typically, this library is included as part of a call to either
+ * {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
+ * {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
+ *
+ *
+ * To instantiate and use it directly, link it into your globals table via
+ * {@link LuaValue#load(LuaValue)} using code such as:
+ *
+ *
+ *
+ * @see LibFunction
+ * @see org.luaj.vm2.lib.jse.JseOsLib
+ * @see org.luaj.vm2.lib.jse.JsePlatform
+ * @see org.luaj.vm2.lib.jme.JmePlatform
+ * @see http://www.lua.org/manual/5.1/manual.html#5.8
+ */
+public class OsLib extends TwoArgFunction {
+ public static final String TMP_PREFIX = ".luaj";
+ public static final String TMP_SUFFIX = "tmp";
+
+ private static final int CLOCK = 0;
+ private static final int DATE = 1;
+ private static final int DIFFTIME = 2;
+ private static final int EXECUTE = 3;
+ private static final int EXIT = 4;
+ private static final int GETENV = 5;
+ private static final int REMOVE = 6;
+ private static final int RENAME = 7;
+ private static final int SETLOCALE = 8;
+ private static final int TIME = 9;
+ private static final int TMPNAME = 10;
+
+ private static final String[] NAMES = { "clock", "date", "difftime", "execute", "exit", "getenv", "remove",
+ "rename", "setlocale", "time", "tmpname", };
+
+ private static final long t0 = System.currentTimeMillis();
+ private static long tmpnames = t0;
+
+ protected Globals globals;
+
+ /**
+ * Create and OsLib instance.
+ */
+ public OsLib() {
+ }
+
+ /**
+ * Perform one-time initialization on the library by creating a table
+ * containing the library functions, adding that table to the supplied
+ * environment, adding the table to package.loaded, and returning table as
+ * the return value.
+ *
+ * @param modname the module name supplied if this is loaded via 'require'.
+ * @param env the environment to load into, typically a Globals
+ * instance.
+ */
+ @Override
+ public LuaValue call(LuaValue modname, LuaValue env) {
+ globals = env.checkglobals();
+ LuaTable os = new LuaTable();
+ for (int i = 0; i < NAMES.length; ++i)
+ os.set(NAMES[i], new OsLibFunc(i, NAMES[i]));
+ env.set("os", os);
+ if (!env.get("package").isnil())
+ env.get("package").get("loaded").set("os", os);
+ return os;
+ }
+
+ class OsLibFunc extends VarArgFunction {
+ public OsLibFunc(int opcode, String name) {
+ this.opcode = opcode;
+ this.name = name;
+ }
+
+ @Override
+ public Varargs invoke(Varargs args) {
+ try {
+ switch (opcode) {
+ case CLOCK:
+ return valueOf(clock());
+ case DATE: {
+ String s = args.optjstring(1, "%c");
+ long t = args.isnumber(2)? args.tolong(2): time(null);
+ if (s.equals("*t")) {
+ Calendar d = Calendar.getInstance();
+ d.setTime(new Date(t*1000));
+ LuaTable tbl = LuaValue.tableOf();
+ tbl.set("year", LuaValue.valueOf(d.get(Calendar.YEAR)));
+ tbl.set("month", LuaValue.valueOf(d.get(Calendar.MONTH)+1));
+ tbl.set("day", LuaValue.valueOf(d.get(Calendar.DAY_OF_MONTH)));
+ tbl.set("hour", LuaValue.valueOf(d.get(Calendar.HOUR_OF_DAY)));
+ tbl.set("min", LuaValue.valueOf(d.get(Calendar.MINUTE)));
+ tbl.set("sec", LuaValue.valueOf(d.get(Calendar.SECOND)));
+ tbl.set("wday", LuaValue.valueOf(d.get(Calendar.DAY_OF_WEEK)));
+ tbl.set("yday", LuaValue.valueOf(d.get(0x6))); // Day of year
+ tbl.set("isdst", LuaValue.valueOf(isDaylightSavingsTime(d)));
+ return tbl;
+ }
+ return valueOf(date(s, t == -1? time(null): t));
+ }
+ case DIFFTIME:
+ return valueOf(difftime(args.checkdouble(1), args.checkdouble(2)));
+ case EXECUTE:
+ return execute(args.optjstring(1, null));
+ case EXIT:
+ exit(args.optint(1, 0));
+ return NONE;
+ case GETENV: {
+ final String val = getenv(args.checkjstring(1));
+ return val != null? valueOf(val): NIL;
+ }
+ case REMOVE:
+ remove(args.checkjstring(1));
+ return LuaValue.TRUE;
+ case RENAME:
+ rename(args.checkjstring(1), args.checkjstring(2));
+ return LuaValue.TRUE;
+ case SETLOCALE: {
+ String s = setlocale(args.optjstring(1, null), args.optjstring(2, "all"));
+ return s != null? valueOf(s): NIL;
+ }
+ case TIME:
+ return valueOf(time(args.opttable(1, null)));
+ case TMPNAME:
+ return valueOf(tmpname());
+ }
+ return NONE;
+ } catch (IOException e) {
+ return varargsOf(NIL, valueOf(e.getMessage()));
+ }
+ }
+ }
+
+ /**
+ * @return an approximation of the amount in seconds of CPU time used by the
+ * program. For luaj this simple returns the elapsed time since the
+ * OsLib class was loaded.
+ */
+ protected double clock() {
+ return (System.currentTimeMillis()-t0)/1000.;
+ }
+
+ /**
+ * Returns the number of seconds from time t1 to time t2. In POSIX, Windows,
+ * and some other systems, this value is exactly t2-t1.
+ *
+ * @param t2
+ * @param t1
+ * @return diffeence in time values, in seconds
+ */
+ protected double difftime(double t2, double t1) {
+ return t2-t1;
+ }
+
+ /**
+ * If the time argument is present, this is the time to be formatted (see
+ * the os.time function for a description of this value). Otherwise, date
+ * formats the current time.
+ *
+ * Date returns the date as a string, formatted according to the same rules
+ * as ANSII strftime, but without support for %g, %G, or %V.
+ *
+ * When called without arguments, date returns a reasonable date and time
+ * representation that depends on the host system and on the current locale
+ * (that is, os.date() is equivalent to os.date("%c")).
+ *
+ * @param format
+ * @param timeInSec time since epoch, or -1 if not supplied
+ * @return a LString or a LTable containing date and time, formatted
+ * according to the given string format.
+ */
+ private static String date(String format, long timeInSec) {
+ Calendar d = Calendar.getInstance();
+ d.setTime(new Date(timeInSec*1000));
+ if (format.startsWith("!")) {
+ timeInSec -= timeZoneOffset(d);
+ d.setTime(new Date(timeInSec*1000));
+ format = format.substring(1);
+ }
+ byte[] fmt = format.getBytes();
+ final int n = fmt.length;
+
+ Buffer result = new Buffer(n);
+ for (int i = 0; i < n; i++) {
+ byte c = fmt[i];
+ switch (c) {
+ case '\n':
+ result.append("\n");
+ break;
+ case '%':
+ if (++i >= n)
+ break;
+ String conv = Character.toString((char) fmt[i]);
+ if (CONVERTERS.containsKey(conv)) {
+ result.append(CONVERTERS.get(conv).convert(d));
+ } else {
+ LuaValue.argerror(1, "invalid conversion specifier '%" + conv + "'");
+ }
+ break;
+ default:
+ result.append(c);
+ break;
+ }
+ }
+ return result.tojstring();
+ }
+
+ private static final String[] WeekdayNameAbbrev = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
+ private static final String[] WeekdayName = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
+ "Friday", "Saturday" };
+ private static final String[] MonthNameAbbrev = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
+ "Oct", "Nov", "Dec" };
+ private static final String[] MonthName = { "January", "February", "March", "April", "May", "June", "July",
+ "August", "September", "October", "November", "December" };
+
+ private static interface DateConversion {
+ public String convert(Calendar d);
+ }
+
+ private static final Map
- * To instantiate and use it directly,
- * link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
- *
+ *
* @see LibFunction
* @see BaseLib
* @see org.luaj.vm2.lib.jse.JseBaseLib
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
- * @see Lua 5.2 Package Lib Reference
+ * @see Lua 5.2 Package
+ * Lib Reference
*/
public class PackageLib extends TwoArgFunction {
- /** The default value to use for package.path. This can be set with the system property
- *
- * This is used by required to load files that are part of
- * the application, and implemented by BaseLib
- * for both the Jme and Jse platforms.
+ * This is used by required to load files that are part of the application, and
+ * implemented by BaseLib for both the Jme and Jse platforms.
*
- * The Jme version of base lib {@link BaseLib}
- * implements {@link Globals#finder} via {@link Class#getResourceAsStream(String)},
- * while the Jse version {@link org.luaj.vm2.lib.jse.JseBaseLib} implements it using {@link java.io.File#File(String)}.
+ * The Jme version of base lib {@link BaseLib} implements {@link Globals#finder}
+ * via {@link Class#getResourceAsStream(String)}, while the Jse version
+ * {@link org.luaj.vm2.lib.jse.JseBaseLib} implements it using
+ * {@link java.io.File#File(String)}.
*
* The io library does not use this API for file manipulation.
*
+ *
* @see BaseLib
* @see Globals#finder
* @see org.luaj.vm2.lib.jse.JseBaseLib
* @see org.luaj.vm2.lib.jme.JmePlatform
- * @see org.luaj.vm2.lib.jse.JsePlatform
+ * @see org.luaj.vm2.lib.jse.JsePlatform
*/
public interface ResourceFinder {
-
- /**
+
+ /**
* Try to open a file, or return null if not found.
- *
+ *
* @see org.luaj.vm2.lib.BaseLib
* @see org.luaj.vm2.lib.jse.JseBaseLib
- *
+ *
* @param filename
- * @return InputStream, or null if not found.
+ * @return InputStream, or null if not found.
*/
- public InputStream findResource( String filename );
-}
\ No newline at end of file
+ InputStream findResource(String filename);
+}
diff --git a/luaj-core/src/main/java/org/luaj/vm2/lib/StringLib.java b/luaj-core/src/main/java/org/luaj/vm2/lib/StringLib.java
new file mode 100644
index 00000000..c2351f3e
--- /dev/null
+++ b/luaj-core/src/main/java/org/luaj/vm2/lib/StringLib.java
@@ -0,0 +1,1298 @@
+/*******************************************************************************
+* Copyright (c) 2009-2011 Luaj.org. All rights reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+******************************************************************************/
+package org.luaj.vm2.lib;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import org.luaj.vm2.Buffer;
+import org.luaj.vm2.LuaClosure;
+import org.luaj.vm2.LuaString;
+import org.luaj.vm2.LuaTable;
+import org.luaj.vm2.LuaValue;
+import org.luaj.vm2.Varargs;
+import org.luaj.vm2.compiler.DumpState;
+
+/**
+ * Subclass of {@link LibFunction} which implements the lua standard
+ * {@code string} library.
+ *
+ * Typically, this library is included as part of a call to either
+ * {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
+ * {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
+ *
+ *
+ * To instantiate and use it directly, link it into your globals table via
+ * {@link LuaValue#load(LuaValue)} using code such as:
+ *
+ *
+ * This is a direct port of the corresponding library in C.
+ *
+ * @see LibFunction
+ * @see org.luaj.vm2.lib.jse.JsePlatform
+ * @see org.luaj.vm2.lib.jme.JmePlatform
+ * @see Lua 5.2 String
+ * Lib Reference
+ */
+public class StringLib extends TwoArgFunction {
+
+ /**
+ * Construct a StringLib, which can be initialized by calling it with a
+ * modname string, and a global environment table as arguments using
+ * {@link #call(LuaValue, LuaValue)}.
+ */
+ public StringLib() {
+ }
+
+ /**
+ * Perform one-time initialization on the library by creating a table
+ * containing the library functions, adding that table to the supplied
+ * environment, adding the table to package.loaded, and returning table as
+ * the return value. Creates a metatable that uses __INDEX to fall back on
+ * itself to support string method operations. If the shared strings
+ * metatable instance is null, will set the metatable as the global shared
+ * metatable for strings.
+ *
+ * All tables and metatables are read-write by default so if this will be
+ * used in a server environment, sandboxing should be used. In particular,
+ * the {@link LuaString#s_metatable} table should probably be made
+ * read-only.
+ *
+ * @param modname the module name supplied if this is loaded via 'require'.
+ * @param env the environment to load into, typically a Globals
+ * instance.
+ */
+ @Override
+ public LuaValue call(LuaValue modname, LuaValue env) {
+ LuaTable string = new LuaTable();
+ string.set("byte", new _byte());
+ string.set("char", new _char());
+ string.set("dump", new dump());
+ string.set("find", new find());
+ string.set("format", new format());
+ string.set("gmatch", new gmatch());
+ string.set("gsub", new gsub());
+ string.set("len", new len());
+ string.set("lower", new lower());
+ string.set("match", new match());
+ string.set("rep", new rep());
+ string.set("reverse", new reverse());
+ string.set("sub", new sub());
+ string.set("upper", new upper());
+
+ env.set("string", string);
+ if (!env.get("package").isnil())
+ env.get("package").get("loaded").set("string", string);
+ if (LuaString.s_metatable == null) {
+ LuaString.s_metatable = LuaValue.tableOf(new LuaValue[] { INDEX, string });
+ }
+ return string;
+ }
+
+ /**
+ * string.byte (s [, i [, j]])
+ *
+ * Returns the internal numerical codes of the characters s[i], s[i+1], ...,
+ * s[j]. The default value for i is 1; the default value for j is i.
+ *
+ * Note that numerical codes are not necessarily portable across platforms.
+ *
+ * @param args the calling args
+ */
+ static final class _byte extends VarArgFunction {
+ @Override
+ public Varargs invoke(Varargs args) {
+ LuaString s = args.checkstring(1);
+ int l = s.m_length;
+ int posi = posrelat(args.optint(2, 1), l);
+ int pose = posrelat(args.optint(3, posi), l);
+ int n, i;
+ if (posi <= 0)
+ posi = 1;
+ if (pose > l)
+ pose = l;
+ if (posi > pose)
+ return NONE; /* empty interval; return no values */
+ n = pose-posi+1;
+ if (posi+n <= pose) /* overflow? */
+ error("string slice too long");
+ LuaValue[] v = new LuaValue[n];
+ for (i = 0; i < n; i++)
+ v[i] = valueOf(s.luaByte(posi+i-1));
+ return varargsOf(v);
+ }
+ }
+
+ /**
+ * string.char (...)
+ *
+ * Receives zero or more integers. Returns a string with length equal to the
+ * number of arguments, in which each character has the internal numerical
+ * code equal to its corresponding argument.
+ *
+ * Note that numerical codes are not necessarily portable across platforms.
+ *
+ * @param args the calling VM
+ */
+ static final class _char extends VarArgFunction {
+ @Override
+ public Varargs invoke(Varargs args) {
+ int n = args.narg();
+ byte[] bytes = new byte[n];
+ for (int i = 0, a = 1; i < n; i++, a++) {
+ int c = args.checkint(a);
+ if (c < 0 || c >= 256)
+ argerror(a, "invalid value for string.char [0; 255]: " + c);
+ bytes[i] = (byte) c;
+ }
+ return LuaString.valueUsing(bytes);
+ }
+ }
+
+ /**
+ * string.dump (function[, stripDebug])
+ *
+ * Returns a string containing a binary representation of the given
+ * function, so that a later loadstring on this string returns a copy of the
+ * function. function must be a Lua function without upvalues. Boolean param
+ * stripDebug - true to strip debugging info, false otherwise. The default
+ * value for stripDebug is true.
+ *
+ * TODO: port dumping code as optional add-on
+ */
+ static final class dump extends VarArgFunction {
+ @Override
+ public Varargs invoke(Varargs args) {
+ LuaValue f = args.checkfunction(1);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ DumpState.dump(((LuaClosure) f).p, baos, args.optboolean(2, true));
+ return LuaString.valueUsing(baos.toByteArray());
+ } catch (IOException e) {
+ return error(e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * string.find (s, pattern [, init [, plain]])
+ *
+ * Looks for the first match of pattern in the string s. If it finds a
+ * match, then find returns the indices of s where this occurrence starts
+ * and ends; otherwise, it returns nil. A third, optional numerical argument
+ * init specifies where to start the search; its default value is 1 and may
+ * be negative. A value of true as a fourth, optional argument plain turns
+ * off the pattern matching facilities, so the function does a plain "find
+ * substring" operation, with no characters in pattern being considered
+ * "magic". Note that if plain is given, then init must be given as well.
+ *
+ * If the pattern has captures, then in a successful match the captured
+ * values are also returned, after the two indices.
+ */
+ static final class find extends VarArgFunction {
+ @Override
+ public Varargs invoke(Varargs args) {
+ return str_find_aux(args, true);
+ }
+ }
+
+ /**
+ * string.format (formatstring, ...)
+ *
+ * Returns a formatted version of its variable number of arguments following
+ * the description given in its first argument (which must be a string). The
+ * format string follows the same rules as the printf family of standard C
+ * functions. The only differences are that the options/modifiers *, l, L,
+ * n, p, and h are not supported and that there is an extra option, q. The q
+ * option formats a string in a form suitable to be safely read back by the
+ * Lua interpreter: the string is written between double quotes, and all
+ * double quotes, newlines, embedded zeros, and backslashes in the string
+ * are correctly escaped when written. For instance, the call
+ * string.format('%q', 'a string with "quotes" and \n new line')
+ *
+ * will produce the string: "a string with \"quotes\" and \ new line"
+ *
+ * The options c, d, E, e, f, g, G, i, o, u, X, and x all expect a number as
+ * argument, whereas q and s expect a string.
+ *
+ * This function does not accept string values containing embedded zeros,
+ * except as arguments to the q option.
+ */
+ final class format extends VarArgFunction {
+ @Override
+ public Varargs invoke(Varargs args) {
+ LuaString fmt = args.checkstring(1);
+ final int n = fmt.length();
+ Buffer result = new Buffer(n);
+ int arg = 1;
+ int c;
+
+ for (int i = 0; i < n;) {
+ switch (c = fmt.luaByte(i++)) {
+ case '\n':
+ result.append("\n");
+ break;
+ default:
+ result.append((byte) c);
+ break;
+ case L_ESC:
+ if (i < n) {
+ if ((c = fmt.luaByte(i)) == L_ESC) {
+ ++i;
+ result.append((byte) L_ESC);
+ } else {
+ arg++;
+ FormatDesc fdsc = new FormatDesc(args, fmt, i);
+ i += fdsc.length;
+ switch (fdsc.conversion) {
+ case 'c':
+ fdsc.format(result, (byte) args.checkint(arg));
+ break;
+ case 'i':
+ case 'd':
+ fdsc.format(result, args.checklong(arg));
+ break;
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ fdsc.format(result, args.checklong(arg));
+ break;
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+ fdsc.format(result, args.checkdouble(arg));
+ break;
+ case 'q':
+ addquoted(result, args.checkstring(arg));
+ break;
+ case 's': {
+ LuaString s = args.checkstring(arg);
+ if (fdsc.precision == -1 && s.length() >= 100) {
+ result.append(s);
+ } else {
+ fdsc.format(result, s);
+ }
+ }
+ break;
+ default:
+ error("invalid option '%" + (char) fdsc.conversion + "' to 'format'");
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return result.tostring();
+ }
+ }
+
+ static void addquoted(Buffer buf, LuaString s) {
+ int c;
+ buf.append((byte) '"');
+ for (int i = 0, n = s.length(); i < n; i++) {
+ switch (c = s.luaByte(i)) {
+ case '"':
+ case '\\':
+ case '\n':
+ buf.append((byte) '\\');
+ buf.append((byte) c);
+ break;
+ default:
+ if (c <= 0x1F || c == 0x7F) {
+ buf.append((byte) '\\');
+ if (i+1 == n || s.luaByte(i+1) < '0' || s.luaByte(i+1) > '9') {
+ buf.append(Integer.toString(c));
+ } else {
+ buf.append((byte) '0');
+ buf.append((byte) (char) ('0'+c/10));
+ buf.append((byte) (char) ('0'+c%10));
+ }
+ } else {
+ buf.append((byte) c);
+ }
+ break;
+ }
+ }
+ buf.append((byte) '"');
+ }
+
+ private static final String FLAGS = "-+ #0";
+
+ class FormatDesc {
+
+ private boolean leftAdjust;
+ private boolean zeroPad;
+ private boolean explicitPlus;
+ private boolean space;
+ private boolean alternateForm;
+ private static final int MAX_FLAGS = 5;
+
+ private int width;
+ int precision;
+
+ public final int conversion;
+ public final int length;
+
+ public final String src;
+
+ public FormatDesc(Varargs args, LuaString strfrmt, final int start) {
+ int p = start, n = strfrmt.length();
+ int c = 0;
+
+ boolean moreFlags = true;
+ while ( moreFlags ) {
+ switch (c = p < n? strfrmt.luaByte(p++): 0) {
+ case '-':
+ leftAdjust = true;
+ break;
+ case '+':
+ explicitPlus = true;
+ break;
+ case ' ':
+ space = true;
+ break;
+ case '#':
+ alternateForm = true;
+ break;
+ case '0':
+ zeroPad = true;
+ break;
+ default:
+ moreFlags = false;
+ break;
+ }
+ }
+ if (p-start > MAX_FLAGS)
+ error("invalid format (repeated flags)");
+
+ width = -1;
+ if (Character.isDigit((char) c)) {
+ width = c-'0';
+ c = p < n? strfrmt.luaByte(p++): 0;
+ if (Character.isDigit((char) c)) {
+ width = width*10+c-'0';
+ c = p < n? strfrmt.luaByte(p++): 0;
+ }
+ }
+
+ precision = -1;
+ if (c == '.') {
+ c = p < n? strfrmt.luaByte(p++): 0;
+ if (Character.isDigit((char) c)) {
+ precision = c-'0';
+ c = p < n? strfrmt.luaByte(p++): 0;
+ if (Character.isDigit((char) c)) {
+ precision = precision*10+c-'0';
+ c = p < n? strfrmt.luaByte(p++): 0;
+ }
+ }
+ }
+
+ if (Character.isDigit((char) c))
+ error("invalid format (width or precision too long)");
+
+ zeroPad &= !leftAdjust; // '-' overrides '0'
+ conversion = c;
+ length = p-start;
+ src = strfrmt.substring(start-1, p).tojstring();
+ }
+
+ public void format(Buffer buf, byte c) {
+ // TODO: not clear that any of width, precision, or flags apply here.
+ buf.append(c);
+ }
+
+ public void format(Buffer buf, long number) {
+ String digits;
+
+ if (number == 0 && precision == 0) {
+ digits = "";
+ } else {
+ int radix;
+ switch (conversion) {
+ case 'x':
+ case 'X':
+ radix = 16;
+ break;
+ case 'o':
+ radix = 8;
+ break;
+ default:
+ radix = 10;
+ break;
+ }
+ digits = Long.toString(number, radix);
+ if (conversion == 'X')
+ digits = digits.toUpperCase();
+ }
+
+ int minwidth = digits.length();
+ int ndigits = minwidth;
+ int nzeros;
+
+ if (number < 0) {
+ ndigits--;
+ } else if (explicitPlus || space) {
+ minwidth++;
+ }
+
+ if (precision > ndigits)
+ nzeros = precision-ndigits;
+ else if (precision == -1 && zeroPad && width > minwidth)
+ nzeros = width-minwidth;
+ else
+ nzeros = 0;
+
+ minwidth += nzeros;
+ int nspaces = width > minwidth? width-minwidth: 0;
+
+ if (!leftAdjust)
+ pad(buf, ' ', nspaces);
+
+ if (number < 0) {
+ if (nzeros > 0) {
+ buf.append((byte) '-');
+ digits = digits.substring(1);
+ }
+ } else if (explicitPlus) {
+ buf.append((byte) '+');
+ } else if (space) {
+ buf.append((byte) ' ');
+ }
+
+ if (nzeros > 0)
+ pad(buf, '0', nzeros);
+
+ buf.append(digits);
+
+ if (leftAdjust)
+ pad(buf, ' ', nspaces);
+ }
+
+ public void format(Buffer buf, double x) {
+ buf.append(StringLib.this.format(src, x));
+ }
+
+ public void format(Buffer buf, LuaString s) {
+ int nullindex = s.indexOf((byte) '\0', 0);
+ if (nullindex != -1)
+ s = s.substring(0, nullindex);
+ buf.append(s);
+ }
+
+ public final void pad(Buffer buf, char c, int n) {
+ byte b = (byte) c;
+ while ( n-- > 0 )
+ buf.append(b);
+ }
+ }
+
+ protected String format(String src, double x) {
+ return String.valueOf(x);
+ }
+
+ /**
+ * string.gmatch (s, pattern)
+ *
+ * Returns an iterator function that, each time it is called, returns the
+ * next captures from pattern over string s. If pattern specifies no
+ * captures, then the whole match is produced in each call.
+ *
+ * As an example, the following loop s = "hello world from Lua" for w in
+ * string.gmatch(s, "%a+") do print(w) end
+ *
+ * will iterate over all the words from string s, printing one per line. The
+ * next example collects all pairs key=value from the given string into a
+ * table: t = {} s = "from=world, to=Lua" for k, v in string.gmatch(s,
+ * "(%w+)=(%w+)") do t[k] = v end
+ *
+ * For this function, a '^' at the start of a pattern does not work as an
+ * anchor, as this would prevent the iteration.
+ */
+ static final class gmatch extends VarArgFunction {
+ @Override
+ public Varargs invoke(Varargs args) {
+ LuaString src = args.checkstring(1);
+ LuaString pat = args.checkstring(2);
+ return new GMatchAux(args, src, pat);
+ }
+ }
+
+ static class GMatchAux extends VarArgFunction {
+ private final int srclen;
+ private final MatchState ms;
+ private int soffset;
+ private int lastmatch;
+
+ public GMatchAux(Varargs args, LuaString src, LuaString pat) {
+ this.srclen = src.length();
+ this.ms = new MatchState(args, src, pat);
+ this.soffset = 0;
+ this.lastmatch = -1;
+ }
+
+ @Override
+ public Varargs invoke(Varargs args) {
+ for (; soffset <= srclen; soffset++) {
+ ms.reset();
+ int res = ms.match(soffset, 0);
+ if (res >= 0 && res != lastmatch) {
+ int soff = soffset;
+ lastmatch = soffset = res;
+ return ms.push_captures(true, soff, res);
+ }
+ }
+ return NIL;
+ }
+ }
+
+ /**
+ * string.gsub (s, pattern, repl [, n]) Returns a copy of s in which all (or
+ * the first n, if given) occurrences of the pattern have been replaced by a
+ * replacement string specified by repl, which may be a string, a table, or
+ * a function. gsub also returns, as its second value, the total number of
+ * matches that occurred.
+ *
+ * If repl is a string, then its value is used for replacement. The
+ * character % works as an escape character: any sequence in repl of the
+ * form %n, with n between 1 and 9, stands for the value of the n-th
+ * captured substring (see below). The sequence %0 stands for the whole
+ * match. The sequence %% stands for a single %.
+ *
+ * If repl is a table, then the table is queried for every match, using the
+ * first capture as the key; if the pattern specifies no captures, then the
+ * whole match is used as the key.
+ *
+ * If repl is a function, then this function is called every time a match
+ * occurs, with all captured substrings passed as arguments, in order; if
+ * the pattern specifies no captures, then the whole match is passed as a
+ * sole argument.
+ *
+ * If the value returned by the table query or by the function call is a
+ * string or a number, then it is used as the replacement string; otherwise,
+ * if it is false or nil, then there is no replacement (that is, the
+ * original match is kept in the string).
+ *
+ * Here are some examples: x = string.gsub("hello world", "(%w+)", "%1 %1")
+ * --> x="hello hello world world"
+ *
+ * x = string.gsub("hello world", "%w+", "%0 %0", 1) --> x="hello hello
+ * world"
+ *
+ * x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1") -->
+ * x="world hello Lua from"
+ *
+ * x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv) -->
+ * x="home = /home/roberto, user = roberto"
+ *
+ * x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s) return
+ * loadstring(s)() end) --> x="4+5 = 9"
+ *
+ * local t = {name="lua", version="5.1"} x =
+ * string.gsub("$name-$version.tar.gz", "%$(%w+)", t) --> x="lua-5.1.tar.gz"
+ */
+ static final class gsub extends VarArgFunction {
+ @Override
+ public Varargs invoke(Varargs args) {
+ LuaString src = args.checkstring(1);
+ final int srclen = src.length();
+ LuaString p = args.checkstring(2);
+ int lastmatch = -1; /* end of last match */
+ LuaValue repl = args.arg(3);
+ int max_s = args.optint(4, srclen+1);
+ if (max_s < 0)
+ max_s = srclen+1;
+ final boolean anchor = p.length() > 0 && p.charAt(0) == '^';
+
+ Buffer lbuf = new Buffer(srclen);
+ MatchState ms = new MatchState(args, src, p);
+
+ int soffset = 0;
+ int n = 0;
+ while ( n < max_s ) {
+ ms.reset();
+ int res = ms.match(soffset, anchor? 1: 0);
+ if (res != -1 && res != lastmatch) { /* match? */
+ n++;
+ ms.add_value(lbuf, soffset, res, repl); /* add replacement to buffer */
+ soffset = lastmatch = res;
+ } else if (soffset < srclen) /* otherwise, skip one character */
+ lbuf.append((byte) src.luaByte(soffset++));
+ else
+ break; /* end of subject */
+ if (anchor)
+ break;
+ }
+ lbuf.append(src.substring(soffset, srclen));
+ return varargsOf(lbuf.tostring(), valueOf(n));
+ }
+ }
+
+ /**
+ * string.len (s)
+ *
+ * Receives a string and returns its length. The empty string "" has length
+ * 0. Embedded zeros are counted, so "a\000bc\000" has length 5.
+ */
+ static final class len extends OneArgFunction {
+ @Override
+ public LuaValue call(LuaValue arg) {
+ return arg.checkstring().len();
+ }
+ }
+
+ /**
+ * string.lower (s)
+ *
+ * Receives a string and returns a copy of this string with all uppercase
+ * letters changed to lowercase. All other characters are left unchanged.
+ * The definition of what an uppercase letter is depends on the current
+ * locale.
+ */
+ static final class lower extends OneArgFunction {
+ @Override
+ public LuaValue call(LuaValue arg) {
+ return valueOf(arg.checkjstring().toLowerCase());
+ }
+ }
+
+ /**
+ * string.match (s, pattern [, init])
+ *
+ * Looks for the first match of pattern in the string s. If it finds one,
+ * then match returns the captures from the pattern; otherwise it returns
+ * nil. If pattern specifies no captures, then the whole match is returned.
+ * A third, optional numerical argument init specifies where to start the
+ * search; its default value is 1 and may be negative.
+ */
+ static final class match extends VarArgFunction {
+ @Override
+ public Varargs invoke(Varargs args) {
+ return str_find_aux(args, false);
+ }
+ }
+
+ /**
+ * string.rep (s, n)
+ *
+ * Returns a string that is the concatenation of n copies of the string s.
+ */
+ static final class rep extends VarArgFunction {
+ @Override
+ public Varargs invoke(Varargs args) {
+ LuaString s = args.checkstring(1);
+ int n = args.checkint(2);
+ final byte[] bytes = new byte[s.length()*n];
+ int len = s.length();
+ for (int offset = 0; offset < bytes.length; offset += len) {
+ s.copyInto(0, bytes, offset, len);
+ }
+ return LuaString.valueUsing(bytes);
+ }
+ }
+
+ /**
+ * string.reverse (s)
+ *
+ * Returns a string that is the string s reversed.
+ */
+ static final class reverse extends OneArgFunction {
+ @Override
+ public LuaValue call(LuaValue arg) {
+ LuaString s = arg.checkstring();
+ int n = s.length();
+ byte[] b = new byte[n];
+ for (int i = 0, j = n-1; i < n; i++, j--)
+ b[j] = (byte) s.luaByte(i);
+ return LuaString.valueUsing(b);
+ }
+ }
+
+ /**
+ * string.sub (s, i [, j])
+ *
+ * Returns the substring of s that starts at i and continues until j; i and
+ * j may be negative. If j is absent, then it is assumed to be equal to -1
+ * (which is the same as the string length). In particular, the call
+ * string.sub(s,1,j) returns a prefix of s with length j, and string.sub(s,
+ * -i) returns a suffix of s with length i.
+ */
+ static final class sub extends VarArgFunction {
+ @Override
+ public Varargs invoke(Varargs args) {
+ final LuaString s = args.checkstring(1);
+ final int l = s.length();
+
+ int start = posrelat(args.checkint(2), l);
+ int end = posrelat(args.optint(3, -1), l);
+
+ if (start < 1)
+ start = 1;
+ if (end > l)
+ end = l;
+
+ if (start <= end) {
+ return s.substring(start-1, end);
+ } else {
+ return EMPTYSTRING;
+ }
+ }
+ }
+
+ /**
+ * string.upper (s)
+ *
+ * Receives a string and returns a copy of this string with all lowercase
+ * letters changed to uppercase. All other characters are left unchanged.
+ * The definition of what a lowercase letter is depends on the current
+ * locale.
+ */
+ static final class upper extends OneArgFunction {
+ @Override
+ public LuaValue call(LuaValue arg) {
+ return valueOf(arg.checkjstring().toUpperCase());
+ }
+ }
+
+ /**
+ * This utility method implements both string.find and string.match.
+ */
+ static Varargs str_find_aux(Varargs args, boolean find) {
+ LuaString s = args.checkstring(1);
+ LuaString pat = args.checkstring(2);
+ int init = args.optint(3, 1);
+
+ if (init > 0) {
+ init = Math.min(init-1, s.length());
+ } else if (init < 0) {
+ init = Math.max(0, s.length()+init);
+ }
+
+ boolean fastMatch = find && (args.arg(4).toboolean() || pat.indexOfAny(SPECIALS) == -1);
+
+ if (fastMatch) {
+ int result = s.indexOf(pat, init);
+ if (result != -1) {
+ return varargsOf(valueOf(result+1), valueOf(result+pat.length()));
+ }
+ } else {
+ MatchState ms = new MatchState(args, s, pat);
+
+ boolean anchor = false;
+ int poff = 0;
+ if (pat.length() > 0 && pat.luaByte(0) == '^') {
+ anchor = true;
+ poff = 1;
+ }
+
+ int soff = init;
+ do {
+ int res;
+ ms.reset();
+ if ((res = ms.match(soff, poff)) != -1) {
+ if (find) {
+ return varargsOf(valueOf(soff+1), valueOf(res), ms.push_captures(false, soff, res));
+ } else {
+ return ms.push_captures(true, soff, res);
+ }
+ }
+ } while ( soff++ < s.length() && !anchor );
+ }
+ return NIL;
+ }
+
+ static int posrelat(int pos, int len) {
+ return pos >= 0? pos: len+pos+1;
+ }
+
+ // Pattern matching implementation
+
+ private static final int L_ESC = '%';
+ private static final LuaString SPECIALS = valueOf("^$*+?.([%-");
+ private static final int MAX_CAPTURES = 32;
+
+ private static final int MAXCCALLS = 200;
+
+ private static final int CAP_UNFINISHED = -1;
+ private static final int CAP_POSITION = -2;
+
+ private static final byte MASK_ALPHA = 0x01;
+ private static final byte MASK_LOWERCASE = 0x02;
+ private static final byte MASK_UPPERCASE = 0x04;
+ private static final byte MASK_DIGIT = 0x08;
+ private static final byte MASK_PUNCT = 0x10;
+ private static final byte MASK_SPACE = 0x20;
+ private static final byte MASK_CONTROL = 0x40;
+ private static final byte MASK_HEXDIGIT = (byte) 0x80;
+
+ static final byte[] CHAR_TABLE;
+
+ static {
+ CHAR_TABLE = new byte[256];
+
+ for (int i = 0; i < 128; ++i) {
+ final char c = (char) i;
+ CHAR_TABLE[i] = (byte) ((Character.isDigit(c)? MASK_DIGIT: 0)
+ | (Character.isLowerCase(c)? MASK_LOWERCASE: 0) | (Character.isUpperCase(c)? MASK_UPPERCASE: 0)
+ | (c < ' ' || c == 0x7F? MASK_CONTROL: 0));
+ if (c >= 'a' && c <= 'f' || c >= 'A' && c <= 'F' || c >= '0' && c <= '9') {
+ CHAR_TABLE[i] |= MASK_HEXDIGIT;
+ }
+ if (c >= '!' && c <= '/' || c >= ':' && c <= '@' || c >= '[' && c <= '`' || c >= '{' && c <= '~') {
+ CHAR_TABLE[i] |= MASK_PUNCT;
+ }
+ if ((CHAR_TABLE[i] & (MASK_LOWERCASE | MASK_UPPERCASE)) != 0) {
+ CHAR_TABLE[i] |= MASK_ALPHA;
+ }
+ }
+
+ CHAR_TABLE[' '] = MASK_SPACE;
+ CHAR_TABLE['\r'] |= MASK_SPACE;
+ CHAR_TABLE['\n'] |= MASK_SPACE;
+ CHAR_TABLE['\t'] |= MASK_SPACE;
+ CHAR_TABLE[0x0B /* '\v' */ ] |= MASK_SPACE;
+ CHAR_TABLE['\f'] |= MASK_SPACE;
+ }
+
+ static class MatchState {
+ int matchdepth; /* control for recursive depth (to avoid C stack overflow) */
+ final LuaString s;
+ final LuaString p;
+ final Varargs args;
+ int level;
+ int[] cinit;
+ int[] clen;
+
+ MatchState(Varargs args, LuaString s, LuaString pattern) {
+ this.s = s;
+ this.p = pattern;
+ this.args = args;
+ this.level = 0;
+ this.cinit = new int[MAX_CAPTURES];
+ this.clen = new int[MAX_CAPTURES];
+ this.matchdepth = MAXCCALLS;
+ }
+
+ void reset() {
+ level = 0;
+ this.matchdepth = MAXCCALLS;
+ }
+
+ private void add_s(Buffer lbuf, LuaString news, int soff, int e) {
+ int l = news.length();
+ for (int i = 0; i < l; ++i) {
+ byte b = (byte) news.luaByte(i);
+ if (b != L_ESC) {
+ lbuf.append(b);
+ } else {
+ ++i; // skip ESC
+ b = (byte) (i < l? news.luaByte(i): 0);
+ if (!Character.isDigit((char) b)) {
+ if (b != L_ESC)
+ error("invalid use of '" + (char) L_ESC + "' in replacement string: after '" + (char) L_ESC
+ + "' must be '0'-'9' or '" + (char) L_ESC + "', but found "
+ + (i < l? "symbol '" + (char) b + "' with code " + b + " at pos " + (i+1)
+ : "end of string"));
+ lbuf.append(b);
+ } else if (b == '0') {
+ lbuf.append(s.substring(soff, e));
+ } else {
+ lbuf.append(push_onecapture(b-'1', soff, e).strvalue());
+ }
+ }
+ }
+ }
+
+ public void add_value(Buffer lbuf, int soffset, int end, LuaValue repl) {
+ switch (repl.type()) {
+ case LuaValue.TSTRING:
+ case LuaValue.TNUMBER:
+ add_s(lbuf, repl.strvalue(), soffset, end);
+ return;
+
+ case LuaValue.TFUNCTION:
+ repl = repl.invoke(push_captures(true, soffset, end)).arg1();
+ break;
+
+ case LuaValue.TTABLE:
+ // Need to call push_onecapture here for the error checking
+ repl = repl.get(push_onecapture(0, soffset, end));
+ break;
+
+ default:
+ error("bad argument: string/function/table expected");
+ return;
+ }
+
+ if (!repl.toboolean()) {
+ repl = s.substring(soffset, end);
+ } else if (!repl.isstring()) {
+ error("invalid replacement value (a " + repl.typename() + ")");
+ }
+ lbuf.append(repl.strvalue());
+ }
+
+ Varargs push_captures(boolean wholeMatch, int soff, int end) {
+ int nlevels = this.level == 0 && wholeMatch? 1: this.level;
+ switch (nlevels) {
+ case 0:
+ return NONE;
+ case 1:
+ return push_onecapture(0, soff, end);
+ }
+ LuaValue[] v = new LuaValue[nlevels];
+ for (int i = 0; i < nlevels; ++i)
+ v[i] = push_onecapture(i, soff, end);
+ return varargsOf(v);
+ }
+
+ private LuaValue push_onecapture(int i, int soff, int end) {
+ if (i >= this.level) {
+ if (i == 0) {
+ return s.substring(soff, end);
+ } else {
+ return error("invalid capture index %" + (i+1));
+ }
+ } else {
+ int l = clen[i];
+ if (l == CAP_UNFINISHED) {
+ return error("unfinished capture");
+ }
+ if (l == CAP_POSITION) {
+ return valueOf(cinit[i]+1);
+ } else {
+ int begin = cinit[i];
+ return s.substring(begin, begin+l);
+ }
+ }
+ }
+
+ private int check_capture(int l) {
+ l -= '1';
+ if (l < 0 || l >= level || this.clen[l] == CAP_UNFINISHED) {
+ error("invalid capture index %" + (l+1));
+ }
+ return l;
+ }
+
+ private int capture_to_close() {
+ int level = this.level;
+ for (level--; level >= 0; level--)
+ if (clen[level] == CAP_UNFINISHED)
+ return level;
+ error("invalid pattern capture");
+ return 0;
+ }
+
+ int classend(int poffset) {
+ switch (p.luaByte(poffset++)) {
+ case L_ESC:
+ if (poffset == p.length()) {
+ error("malformed pattern (ends with '%')");
+ }
+ return poffset+1;
+
+ case '[':
+ if (poffset != p.length() && p.luaByte(poffset) == '^')
+ poffset++;
+ do {
+ if (poffset == p.length()) {
+ error("malformed pattern (missing ']')");
+ }
+ if (p.luaByte(poffset++) == L_ESC && poffset < p.length())
+ poffset++; /* skip escapes (e.g. '%]') */
+ } while ( poffset == p.length() || p.luaByte(poffset) != ']' );
+ return poffset+1;
+ default:
+ return poffset;
+ }
+ }
+
+ static boolean match_class(int c, int cl) {
+ final char lcl = Character.toLowerCase((char) cl);
+ int cdata = CHAR_TABLE[c];
+
+ boolean res;
+ switch (lcl) {
+ case 'a':
+ res = (cdata & MASK_ALPHA) != 0;
+ break;
+ case 'd':
+ res = (cdata & MASK_DIGIT) != 0;
+ break;
+ case 'l':
+ res = (cdata & MASK_LOWERCASE) != 0;
+ break;
+ case 'u':
+ res = (cdata & MASK_UPPERCASE) != 0;
+ break;
+ case 'c':
+ res = (cdata & MASK_CONTROL) != 0;
+ break;
+ case 'p':
+ res = (cdata & MASK_PUNCT) != 0;
+ break;
+ case 's':
+ res = (cdata & MASK_SPACE) != 0;
+ break;
+ case 'g':
+ res = (cdata & (MASK_ALPHA | MASK_DIGIT | MASK_PUNCT)) != 0;
+ break;
+ case 'w':
+ res = (cdata & (MASK_ALPHA | MASK_DIGIT)) != 0;
+ break;
+ case 'x':
+ res = (cdata & MASK_HEXDIGIT) != 0;
+ break;
+ case 'z':
+ res = c == 0;
+ break; /* deprecated option */
+ default:
+ return cl == c;
+ }
+ return lcl == cl == res;
+ }
+
+ boolean matchbracketclass(int c, int poff, int ec) {
+ boolean sig = true;
+ if (p.luaByte(poff+1) == '^') {
+ sig = false;
+ poff++;
+ }
+ while ( ++poff < ec ) {
+ if (p.luaByte(poff) == L_ESC) {
+ poff++;
+ if (match_class(c, p.luaByte(poff)))
+ return sig;
+ } else if (p.luaByte(poff+1) == '-' && poff+2 < ec) {
+ poff += 2;
+ if (p.luaByte(poff-2) <= c && c <= p.luaByte(poff))
+ return sig;
+ } else if (p.luaByte(poff) == c)
+ return sig;
+ }
+ return !sig;
+ }
+
+ boolean singlematch(int c, int poff, int ep) {
+ switch (p.luaByte(poff)) {
+ case '.':
+ return true;
+ case L_ESC:
+ return match_class(c, p.luaByte(poff+1));
+ case '[':
+ return matchbracketclass(c, poff, ep-1);
+ default:
+ return p.luaByte(poff) == c;
+ }
+ }
+
+ /**
+ * Perform pattern matching. If there is a match, returns offset into s
+ * where match ends, otherwise returns -1.
+ */
+ int match(int soffset, int poffset) {
+ if (matchdepth-- == 0)
+ error("pattern too complex");
+ try {
+ while ( true ) {
+ // Check if we are at the end of the pattern -
+ // equivalent to the '\0' case in the C version, but our pattern
+ // string is not NUL-terminated.
+ if (poffset == p.length())
+ return soffset;
+ switch (p.luaByte(poffset)) {
+ case '(':
+ if (++poffset < p.length() && p.luaByte(poffset) == ')')
+ return start_capture(soffset, poffset+1, CAP_POSITION);
+ else
+ return start_capture(soffset, poffset, CAP_UNFINISHED);
+ case ')':
+ return end_capture(soffset, poffset+1);
+ case L_ESC:
+ if (poffset+1 == p.length())
+ error("malformed pattern (ends with '%')");
+ switch (p.luaByte(poffset+1)) {
+ case 'b':
+ soffset = matchbalance(soffset, poffset+2);
+ if (soffset == -1)
+ return -1;
+ poffset += 4;
+ continue;
+ case 'f': {
+ poffset += 2;
+ if (poffset == p.length() || p.luaByte(poffset) != '[') {
+ error("missing '[' after '%f' in pattern");
+ }
+ int ep = classend(poffset);
+ int previous = soffset == 0? '\0': s.luaByte(soffset-1);
+ int next = soffset == s.length()? '\0': s.luaByte(soffset);
+ if (matchbracketclass(previous, poffset, ep-1) || !matchbracketclass(next, poffset, ep-1))
+ return -1;
+ poffset = ep;
+ continue;
+ }
+ default: {
+ int c = p.luaByte(poffset+1);
+ if (Character.isDigit((char) c)) {
+ soffset = match_capture(soffset, c);
+ if (soffset == -1)
+ return -1;
+ return match(soffset, poffset+2);
+ }
+ }
+ }
+ case '$':
+ if (poffset+1 == p.length())
+ return soffset == s.length()? soffset: -1;
+ }
+ int ep = classend(poffset);
+ boolean m = soffset < s.length() && singlematch(s.luaByte(soffset), poffset, ep);
+ int pc = ep < p.length()? p.luaByte(ep): '\0';
+
+ switch (pc) {
+ case '?':
+ int res;
+ if (m && (res = match(soffset+1, ep+1)) != -1)
+ return res;
+ poffset = ep+1;
+ continue;
+ case '*':
+ return max_expand(soffset, poffset, ep);
+ case '+':
+ return m? max_expand(soffset+1, poffset, ep): -1;
+ case '-':
+ return min_expand(soffset, poffset, ep);
+ default:
+ if (!m)
+ return -1;
+ soffset++;
+ poffset = ep;
+ }
+ }
+ } finally {
+ matchdepth++;
+ }
+ }
+
+ int max_expand(int soff, int poff, int ep) {
+ int i = 0;
+ while ( soff+i < s.length() && singlematch(s.luaByte(soff+i), poff, ep) )
+ i++;
+ while ( i >= 0 ) {
+ int res = match(soff+i, ep+1);
+ if (res != -1)
+ return res;
+ i--;
+ }
+ return -1;
+ }
+
+ int min_expand(int soff, int poff, int ep) {
+ for (;;) {
+ int res = match(soff, ep+1);
+ if (res != -1)
+ return res;
+ else if (soff < s.length() && singlematch(s.luaByte(soff), poff, ep))
+ soff++;
+ else
+ return -1;
+ }
+ }
+
+ int start_capture(int soff, int poff, int what) {
+ int res;
+ int level = this.level;
+ if (level >= MAX_CAPTURES) {
+ error("too many captures");
+ }
+ cinit[level] = soff;
+ clen[level] = what;
+ this.level = level+1;
+ if ((res = match(soff, poff)) == -1)
+ this.level--;
+ return res;
+ }
+
+ int end_capture(int soff, int poff) {
+ int l = capture_to_close();
+ int res;
+ clen[l] = soff-cinit[l];
+ if ((res = match(soff, poff)) == -1)
+ clen[l] = CAP_UNFINISHED;
+ return res;
+ }
+
+ int match_capture(int soff, int l) {
+ l = check_capture(l);
+ int len = clen[l];
+ if (s.length()-soff >= len && LuaString.equals(s, cinit[l], s, soff, len))
+ return soff+len;
+ else
+ return -1;
+ }
+
+ int matchbalance(int soff, int poff) {
+ final int plen = p.length();
+ if (poff == plen || poff+1 == plen) {
+ error("malformed pattern (missing arguments to '%b')");
+ }
+ final int slen = s.length();
+ if (soff >= slen)
+ return -1;
+ final int b = p.luaByte(poff);
+ if (s.luaByte(soff) != b)
+ return -1;
+ final int e = p.luaByte(poff+1);
+ int cont = 1;
+ while ( ++soff < slen ) {
+ if (s.luaByte(soff) == e) {
+ if (--cont == 0)
+ return soff+1;
+ } else if (s.luaByte(soff) == b)
+ cont++;
+ }
+ return -1;
+ }
+ }
+}
diff --git a/src/core/org/luaj/vm2/lib/TableLib.java b/luaj-core/src/main/java/org/luaj/vm2/lib/TableLib.java
similarity index 68%
rename from src/core/org/luaj/vm2/lib/TableLib.java
rename to luaj-core/src/main/java/org/luaj/vm2/lib/TableLib.java
index 64959277..3c5cc258 100644
--- a/src/core/org/luaj/vm2/lib/TableLib.java
+++ b/luaj-core/src/main/java/org/luaj/vm2/lib/TableLib.java
@@ -10,7 +10,7 @@
*
* 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
@@ -26,41 +26,58 @@ import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/**
- * Subclass of {@link LibFunction} which implements the lua standard {@code table}
- * library.
- *
+ * Subclass of {@link LibFunction} which implements the lua standard
+ * {@code table} library.
+ *
*
* Typically, this library is included as part of a call to either
- * {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
- *
- * To instantiate and use it directly,
- * link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
- *
- * This has been implemented to match as closely as possible the behavior in the corresponding library in C.
+ * This has been implemented to match as closely as possible the behavior in the
+ * corresponding library in C.
+ *
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
- * @see Lua 5.2 Table Lib Reference
+ * @see Lua 5.2 Table
+ * Lib Reference
*/
public class TableLib extends TwoArgFunction {
- /** Perform one-time initialization on the library by creating a table
- * containing the library functions, adding that table to the supplied environment,
- * adding the table to package.loaded, and returning table as the return value.
+ /**
+ * Perform one-time initialization on the library by creating a table
+ * containing the library functions, adding that table to the supplied
+ * environment, adding the table to package.loaded, and returning table as
+ * the return value.
+ *
* @param modname the module name supplied if this is loaded via 'require'.
- * @param env the environment to load into, typically a Globals instance.
+ * @param env the environment to load into, typically a Globals
+ * instance.
*/
+ @Override
public LuaValue call(LuaValue modname, LuaValue env) {
LuaTable table = new LuaTable();
table.set("concat", new concat());
@@ -70,40 +87,50 @@ public class TableLib extends TwoArgFunction {
table.set("sort", new sort());
table.set("unpack", new unpack());
env.set("table", table);
- if (!env.get("package").isnil()) env.get("package").get("loaded").set("table", table);
+ if (!env.get("package").isnil())
+ env.get("package").get("loaded").set("table", table);
return NIL;
}
-
+
// "concat" (table [, sep [, i [, j]]]) -> string
static class concat extends TableLibFunction {
+ @Override
public LuaValue call(LuaValue list) {
- return list.checktable().concat(EMPTYSTRING,1,list.length());
+ return list.checktable().concat(EMPTYSTRING, 1, list.length());
}
+
+ @Override
public LuaValue call(LuaValue list, LuaValue sep) {
- return list.checktable().concat(sep.checkstring(),1,list.length());
+ return list.checktable().concat(sep.checkstring(), 1, list.length());
}
+
+ @Override
public LuaValue call(LuaValue list, LuaValue sep, LuaValue i) {
- return list.checktable().concat(sep.checkstring(),i.checkint(),list.length());
+ return list.checktable().concat(sep.checkstring(), i.checkint(), list.length());
}
+
+ @Override
public LuaValue call(LuaValue list, LuaValue sep, LuaValue i, LuaValue j) {
- return list.checktable().concat(sep.checkstring(),i.checkint(),j.checkint());
+ return list.checktable().concat(sep.checkstring(), i.checkint(), j.checkint());
}
}
// "insert" (table, [pos,] value)
static class insert extends VarArgFunction {
+ @Override
public Varargs invoke(Varargs args) {
switch (args.narg()) {
case 2: {
LuaTable table = args.checktable(1);
- table.insert(table.length()+1,args.arg(2));
+ table.insert(table.length()+1, args.arg(2));
return NONE;
}
case 3: {
LuaTable table = args.checktable(1);
int pos = args.checkint(2);
- int max = table.length() + 1;
- if (pos < 1 || pos > max) argerror(2, "position out of bounds: " + pos + " not between 1 and " + max);
+ int max = table.length()+1;
+ if (pos < 1 || pos > max)
+ argerror(2, "position out of bounds: " + pos + " not between 1 and " + max);
table.insert(pos, args.arg(3));
return NONE;
}
@@ -113,9 +140,10 @@ public class TableLib extends TwoArgFunction {
}
}
}
-
+
// "pack" (...) -> table
static class pack extends VarArgFunction {
+ @Override
public Varargs invoke(Varargs args) {
LuaValue t = tableOf(args, 1);
t.set("n", args.narg());
@@ -125,12 +153,13 @@ public class TableLib extends TwoArgFunction {
// "remove" (table [, pos]) -> removed-ele
static class remove extends VarArgFunction {
+ @Override
public Varargs invoke(Varargs args) {
LuaTable table = args.checktable(1);
int size = table.length();
int pos = args.optint(2, size);
- if (pos != size && (pos < 1 || pos > size + 1)) {
- argerror(2, "position out of bounds: " + pos + " not between 1 and " + (size + 1));
+ if (pos != size && (pos < 1 || pos > size+1)) {
+ argerror(2, "position out of bounds: " + pos + " not between 1 and " + (size+1));
}
return table.remove(pos);
}
@@ -138,20 +167,20 @@ public class TableLib extends TwoArgFunction {
// "sort" (table [, comp])
static class sort extends VarArgFunction {
+ @Override
public Varargs invoke(Varargs args) {
- args.checktable(1).sort(
- args.isnil(2)? NIL: args.checkfunction(2));
+ args.checktable(1).sort(args.isnil(2)? NIL: args.checkfunction(2));
return NONE;
}
}
-
// "unpack", // (list [,i [,j]]) -> result1, ...
static class unpack extends VarArgFunction {
+ @Override
public Varargs invoke(Varargs args) {
LuaTable t = args.checktable(1);
// do not waste resource for calc rawlen if arg3 is not nil
- int len = args.arg(3).isnil() ? t.length() : 0;
+ int len = args.arg(3).isnil()? t.length(): 0;
return t.unpack(args.optint(2, 1), args.optint(3, len));
}
}
diff --git a/src/core/org/luaj/vm2/lib/TableLibFunction.java b/luaj-core/src/main/java/org/luaj/vm2/lib/TableLibFunction.java
similarity index 94%
rename from src/core/org/luaj/vm2/lib/TableLibFunction.java
rename to luaj-core/src/main/java/org/luaj/vm2/lib/TableLibFunction.java
index 5fabef7e..f9286b0a 100644
--- a/src/core/org/luaj/vm2/lib/TableLibFunction.java
+++ b/luaj-core/src/main/java/org/luaj/vm2/lib/TableLibFunction.java
@@ -3,6 +3,7 @@ package org.luaj.vm2.lib;
import org.luaj.vm2.LuaValue;
class TableLibFunction extends LibFunction {
+ @Override
public LuaValue call() {
return argerror(1, "table expected, got no value");
}
diff --git a/src/core/org/luaj/vm2/lib/ThreeArgFunction.java b/luaj-core/src/main/java/org/luaj/vm2/lib/ThreeArgFunction.java
similarity index 75%
rename from src/core/org/luaj/vm2/lib/ThreeArgFunction.java
rename to luaj-core/src/main/java/org/luaj/vm2/lib/ThreeArgFunction.java
index 68ceb243..05a6b3a1 100644
--- a/src/core/org/luaj/vm2/lib/ThreeArgFunction.java
+++ b/luaj-core/src/main/java/org/luaj/vm2/lib/ThreeArgFunction.java
@@ -10,7 +10,7 @@
*
* 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
@@ -24,21 +24,24 @@ package org.luaj.vm2.lib;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
-/** Abstract base class for Java function implementations that take two arguments and
- * return one value.
+/**
+ * Abstract base class for Java function implementations that take two arguments
+ * and return one value.
*
- * Subclasses need only implement {@link LuaValue#call(LuaValue,LuaValue,LuaValue)} to complete this class,
- * simplifying development.
- * All other uses of {@link #call()}, {@link #invoke(Varargs)},etc,
- * are routed through this method by this class,
+ * Subclasses need only implement
+ * {@link LuaValue#call(LuaValue,LuaValue,LuaValue)} to complete this class,
+ * simplifying development. All other uses of {@link #call()},
+ * {@link #invoke(Varargs)},etc, are routed through this method by this class,
* dropping or extending arguments with {@code nil} values as required.
*
- * If more or less than three arguments are required,
- * or variable argument or variable return values,
- * then use one of the related function
- * {@link ZeroArgFunction}, {@link OneArgFunction}, {@link TwoArgFunction}, or {@link VarArgFunction}.
+ * If more or less than three arguments are required, or variable argument or
+ * variable return values, then use one of the related function
+ * {@link ZeroArgFunction}, {@link OneArgFunction}, {@link TwoArgFunction}, or
+ * {@link VarArgFunction}.
*
- * See {@link LibFunction} for more information on implementation libraries and library functions.
+ * See {@link LibFunction} for more information on implementation libraries and
+ * library functions.
+ *
* @see #call(LuaValue,LuaValue,LuaValue)
* @see LibFunction
* @see ZeroArgFunction
@@ -48,26 +51,31 @@ import org.luaj.vm2.Varargs;
*/
abstract public class ThreeArgFunction extends LibFunction {
+ @Override
abstract public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3);
-
+
/** Default constructor */
public ThreeArgFunction() {
}
-
+
+ @Override
public final LuaValue call() {
return call(NIL, NIL, NIL);
}
+ @Override
public final LuaValue call(LuaValue arg) {
return call(arg, NIL, NIL);
}
+ @Override
public LuaValue call(LuaValue arg1, LuaValue arg2) {
return call(arg1, arg2, NIL);
}
-
+
+ @Override
public Varargs invoke(Varargs varargs) {
- return call(varargs.arg1(),varargs.arg(2),varargs.arg(3));
+ return call(varargs.arg1(), varargs.arg(2), varargs.arg(3));
}
-
-}
+
+}
diff --git a/src/core/org/luaj/vm2/lib/TwoArgFunction.java b/luaj-core/src/main/java/org/luaj/vm2/lib/TwoArgFunction.java
similarity index 75%
rename from src/core/org/luaj/vm2/lib/TwoArgFunction.java
rename to luaj-core/src/main/java/org/luaj/vm2/lib/TwoArgFunction.java
index 8a97f6fb..f7ef431d 100644
--- a/src/core/org/luaj/vm2/lib/TwoArgFunction.java
+++ b/luaj-core/src/main/java/org/luaj/vm2/lib/TwoArgFunction.java
@@ -10,7 +10,7 @@
*
* 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
@@ -24,21 +24,24 @@ package org.luaj.vm2.lib;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
-/** Abstract base class for Java function implementations that take two arguments and
- * return one value.
+/**
+ * Abstract base class for Java function implementations that take two arguments
+ * and return one value.
*
- * Subclasses need only implement {@link LuaValue#call(LuaValue,LuaValue)} to complete this class,
- * simplifying development.
- * All other uses of {@link #call()}, {@link #invoke(Varargs)},etc,
- * are routed through this method by this class,
- * dropping or extending arguments with {@code nil} values as required.
+ * Subclasses need only implement {@link LuaValue#call(LuaValue,LuaValue)} to
+ * complete this class, simplifying development. All other uses of
+ * {@link #call()}, {@link #invoke(Varargs)},etc, are routed through this method
+ * by this class, dropping or extending arguments with {@code nil} values as
+ * required.
*
- * If more or less than two arguments are required,
- * or variable argument or variable return values,
- * then use one of the related function
- * {@link ZeroArgFunction}, {@link OneArgFunction}, {@link ThreeArgFunction}, or {@link VarArgFunction}.
+ * If more or less than two arguments are required, or variable argument or
+ * variable return values, then use one of the related function
+ * {@link ZeroArgFunction}, {@link OneArgFunction}, {@link ThreeArgFunction}, or
+ * {@link VarArgFunction}.
*
- * See {@link LibFunction} for more information on implementation libraries and library functions.
+ * See {@link LibFunction} for more information on implementation libraries and
+ * library functions.
+ *
* @see #call(LuaValue,LuaValue)
* @see LibFunction
* @see ZeroArgFunction
@@ -48,26 +51,31 @@ import org.luaj.vm2.Varargs;
*/
abstract public class TwoArgFunction extends LibFunction {
+ @Override
abstract public LuaValue call(LuaValue arg1, LuaValue arg2);
-
+
/** Default constructor */
public TwoArgFunction() {
}
-
+
+ @Override
public final LuaValue call() {
return call(NIL, NIL);
}
+ @Override
public final LuaValue call(LuaValue arg) {
return call(arg, NIL);
}
+ @Override
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
return call(arg1, arg2);
}
-
+
+ @Override
public Varargs invoke(Varargs varargs) {
- return call(varargs.arg1(),varargs.arg(2));
+ return call(varargs.arg1(), varargs.arg(2));
}
-
-}
+
+}
diff --git a/src/core/org/luaj/vm2/lib/VarArgFunction.java b/luaj-core/src/main/java/org/luaj/vm2/lib/VarArgFunction.java
similarity index 70%
rename from src/core/org/luaj/vm2/lib/VarArgFunction.java
rename to luaj-core/src/main/java/org/luaj/vm2/lib/VarArgFunction.java
index 8e2bd614..e286bdd2 100644
--- a/src/core/org/luaj/vm2/lib/VarArgFunction.java
+++ b/luaj-core/src/main/java/org/luaj/vm2/lib/VarArgFunction.java
@@ -10,7 +10,7 @@
*
* 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
@@ -24,20 +24,23 @@ package org.luaj.vm2.lib;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
-/** Abstract base class for Java function implementations that takes varaiable arguments and
- * returns multiple return values.
+/**
+ * Abstract base class for Java function implementations that takes varaiable
+ * arguments and returns multiple return values.
*
- * Subclasses need only implement {@link LuaValue#invoke(Varargs)} to complete this class,
- * simplifying development.
- * All other uses of {@link #call(LuaValue)}, {@link #invoke()},etc,
- * are routed through this method by this class,
- * converting arguments to {@link Varargs} and
- * dropping or extending return values with {@code nil} values as required.
+ * Subclasses need only implement {@link LuaValue#invoke(Varargs)} to complete
+ * this class, simplifying development. All other uses of
+ * {@link #call(LuaValue)}, {@link #invoke()},etc, are routed through this
+ * method by this class, converting arguments to {@link Varargs} and dropping or
+ * extending return values with {@code nil} values as required.
*
- * If between one and three arguments are required, and only one return value is returned,
- * {@link ZeroArgFunction}, {@link OneArgFunction}, {@link TwoArgFunction}, or {@link ThreeArgFunction}.
+ * If between one and three arguments are required, and only one return value is
+ * returned, {@link ZeroArgFunction}, {@link OneArgFunction},
+ * {@link TwoArgFunction}, or {@link ThreeArgFunction}.
*
- * See {@link LibFunction} for more information on implementation libraries and library functions.
+ * See {@link LibFunction} for more information on implementation libraries and
+ * library functions.
+ *
* @see #invoke(Varargs)
* @see LibFunction
* @see ZeroArgFunction
@@ -49,35 +52,41 @@ abstract public class VarArgFunction extends LibFunction {
public VarArgFunction() {
}
-
+
+ @Override
public LuaValue call() {
return invoke(NONE).arg1();
}
+ @Override
public LuaValue call(LuaValue arg) {
return invoke(arg).arg1();
}
+ @Override
public LuaValue call(LuaValue arg1, LuaValue arg2) {
- return invoke(varargsOf(arg1,arg2)).arg1();
+ return invoke(varargsOf(arg1, arg2)).arg1();
}
+ @Override
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
- return invoke(varargsOf(arg1,arg2,arg3)).arg1();
+ return invoke(varargsOf(arg1, arg2, arg3)).arg1();
}
- /**
- * Subclass responsibility.
- * May not have expected behavior for tail calls.
- * Should not be used if:
- * - function has a possibility of returning a TailcallVarargs
+ /**
+ * Subclass responsibility. May not have expected behavior for tail calls.
+ * Should not be used if: - function has a possibility of returning a
+ * TailcallVarargs
+ *
* @param args the arguments to the function call.
*/
+ @Override
public Varargs invoke(Varargs args) {
return onInvoke(args).eval();
}
-
+
+ @Override
public Varargs onInvoke(Varargs args) {
return invoke(args);
}
-}
+}
diff --git a/src/core/org/luaj/vm2/lib/ZeroArgFunction.java b/luaj-core/src/main/java/org/luaj/vm2/lib/ZeroArgFunction.java
similarity index 79%
rename from src/core/org/luaj/vm2/lib/ZeroArgFunction.java
rename to luaj-core/src/main/java/org/luaj/vm2/lib/ZeroArgFunction.java
index 06169d74..9841a869 100644
--- a/src/core/org/luaj/vm2/lib/ZeroArgFunction.java
+++ b/luaj-core/src/main/java/org/luaj/vm2/lib/ZeroArgFunction.java
@@ -10,7 +10,7 @@
*
* 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
@@ -24,19 +24,21 @@ package org.luaj.vm2.lib;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
-/** Abstract base class for Java function implementations that take no arguments and
- * return one value.
+/**
+ * Abstract base class for Java function implementations that take no arguments
+ * and return one value.
*
- * Subclasses need only implement {@link LuaValue#call()} to complete this class,
- * simplifying development.
- * All other uses of {@link #call(LuaValue)}, {@link #invoke(Varargs)},etc,
- * are routed through this method by this class.
+ * Subclasses need only implement {@link LuaValue#call()} to complete this
+ * class, simplifying development. All other uses of {@link #call(LuaValue)},
+ * {@link #invoke(Varargs)},etc, are routed through this method by this class.
*
- * If one or more arguments are required, or variable argument or variable return values,
- * then use one of the related function
- * {@link OneArgFunction}, {@link TwoArgFunction}, {@link ThreeArgFunction}, or {@link VarArgFunction}.
+ * If one or more arguments are required, or variable argument or variable
+ * return values, then use one of the related function {@link OneArgFunction},
+ * {@link TwoArgFunction}, {@link ThreeArgFunction}, or {@link VarArgFunction}.
*
- * See {@link LibFunction} for more information on implementation libraries and library functions.
+ * See {@link LibFunction} for more information on implementation libraries and
+ * library functions.
+ *
* @see #call()
* @see LibFunction
* @see OneArgFunction
@@ -46,25 +48,30 @@ import org.luaj.vm2.Varargs;
*/
abstract public class ZeroArgFunction extends LibFunction {
+ @Override
abstract public LuaValue call();
/** Default constructor */
public ZeroArgFunction() {
}
-
+
+ @Override
public LuaValue call(LuaValue arg) {
return call();
}
+ @Override
public LuaValue call(LuaValue arg1, LuaValue arg2) {
return call();
}
+ @Override
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
return call();
}
+ @Override
public Varargs invoke(Varargs varargs) {
return call();
}
-}
+}
diff --git a/test/lua/errors/abc.txt b/luaj-core/src/main/resources/.keep
similarity index 100%
rename from test/lua/errors/abc.txt
rename to luaj-core/src/main/resources/.keep
diff --git a/test/junit/org/luaj/vm2/BufferedStreamTest.java b/luaj-core/src/test/java/org/luaj/vm2/BufferedStreamTest.java
similarity index 86%
rename from test/junit/org/luaj/vm2/BufferedStreamTest.java
rename to luaj-core/src/test/java/org/luaj/vm2/BufferedStreamTest.java
index 45161a2e..485a1b2c 100644
--- a/test/junit/org/luaj/vm2/BufferedStreamTest.java
+++ b/luaj-core/src/test/java/org/luaj/vm2/BufferedStreamTest.java
@@ -21,41 +21,38 @@
******************************************************************************/
package org.luaj.vm2;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
import java.io.ByteArrayInputStream;
-import junit.framework.TestCase;
-
+import org.junit.jupiter.api.Test;
import org.luaj.vm2.Globals.BufferedStream;
+class BufferedStreamTest {
-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 {
+
+ @Test
+ 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 {
+
+ @Test
+ 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 {
+
+ @Test
+ void testReadByteArray() throws java.io.IOException {
byte[] array = new byte[3];
BufferedStream bs = NewBufferedStream(4, "abcdef");
assertEquals(3, bs.read(array));
@@ -66,8 +63,9 @@ public class BufferedStreamTest extends TestCase {
assertEquals("ef", new String(array, 0, 2));
assertEquals(-1, bs.read());
}
-
- public void testReadByteArrayOffsetLength() throws java.io.IOException {
+
+ @Test
+ void testReadByteArrayOffsetLength() throws java.io.IOException {
byte[] array = new byte[10];
BufferedStream bs = NewBufferedStream(8, "abcdefghijklmn");
assertEquals(4, bs.read(array, 0, 4));
@@ -78,8 +76,9 @@ public class BufferedStreamTest extends TestCase {
assertEquals("ijklmn", new String(array, 0, 6));
assertEquals(-1, bs.read());
}
-
- public void testMarkOffsetBeginningOfStream() throws java.io.IOException {
+
+ @Test
+ void testMarkOffsetBeginningOfStream() throws java.io.IOException {
byte[] array = new byte[4];
BufferedStream bs = NewBufferedStream(8, "abcdefghijkl");
assertEquals(true, bs.markSupported());
@@ -96,7 +95,8 @@ public class BufferedStreamTest extends TestCase {
assertEquals(-1, bs.read());
}
- public void testMarkOffsetMiddleOfStream() throws java.io.IOException {
+ @Test
+ void testMarkOffsetMiddleOfStream() throws java.io.IOException {
byte[] array = new byte[4];
BufferedStream bs = NewBufferedStream(8, "abcdefghijkl");
assertEquals(true, bs.markSupported());
diff --git a/luaj-core/src/test/java/org/luaj/vm2/LuaOperationsTest.java b/luaj-core/src/test/java/org/luaj/vm2/LuaOperationsTest.java
new file mode 100644
index 00000000..8b7a48ff
--- /dev/null
+++ b/luaj-core/src/test/java/org/luaj/vm2/LuaOperationsTest.java
@@ -0,0 +1,135 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Luaj.org. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ ******************************************************************************/
+package org.luaj.vm2;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.junit.jupiter.api.Test;
+import org.luaj.vm2.TypeTest.MyData;
+import org.luaj.vm2.lib.ZeroArgFunction;
+
+class LuaOperationsTest {
+
+ 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() {
+ @Override
+ 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);
+ }
+ }
+
+ @Test
+ 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);
+ }
+
+ @Test
+ 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);
+ }
+}
diff --git a/luaj-core/src/test/java/org/luaj/vm2/MetatableTest.java b/luaj-core/src/test/java/org/luaj/vm2/MetatableTest.java
new file mode 100644
index 00000000..68e1ddb5
--- /dev/null
+++ b/luaj-core/src/test/java/org/luaj/vm2/MetatableTest.java
@@ -0,0 +1,372 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Luaj.org. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ ******************************************************************************/
+package org.luaj.vm2;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+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;
+
+class MetatableTest {
+
+ 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() {
+ @Override
+ 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);
+
+ @BeforeEach
+ protected void setUp() throws Exception {
+ // needed for metatable ops to work on strings
+ new StringLib();
+ }
+
+ @AfterEach
+ protected void tearDown() throws Exception {
+ LuaBoolean.s_metatable = null;
+ LuaFunction.s_metatable = null;
+ LuaNil.s_metatable = null;
+ LuaNumber.s_metatable = null;
+// LuaString.s_metatable = null;
+ LuaThread.s_metatable = null;
+ }
+
+ @Test
+ 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());
+ }
+
+ @Test
+ 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());
+ }
+
+ @Test
+ 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() {
+ @Override
+ 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());
+ }
+
+ @Test
+ 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() {
+ @Override
+ 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), });
+ }
+
+ @Test
+ 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);
+ }
+}
diff --git a/test/junit/org/luaj/vm2/StringTest.java b/luaj-core/src/test/java/org/luaj/vm2/StringTest.java
similarity index 64%
rename from test/junit/org/luaj/vm2/StringTest.java
rename to luaj-core/src/test/java/org/luaj/vm2/StringTest.java
index ff01d0d6..e4f1fc95 100644
--- a/test/junit/org/luaj/vm2/StringTest.java
+++ b/luaj-core/src/test/java/org/luaj/vm2/StringTest.java
@@ -1,98 +1,102 @@
package org.luaj.vm2;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
-import junit.framework.TestCase;
+import org.junit.jupiter.api.Test;
-import org.luaj.vm2.lib.jse.JsePlatform;
+class StringTest {
-public class StringTest extends TestCase {
-
- protected void setUp() throws Exception {
- JsePlatform.standardGlobals();
- }
-
- public void testToInputStream() throws IOException {
+ @Test
+ 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() );
-
+
+ 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() );
+
+ 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() );
-
+ 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() );
-
+
+ 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() );
+
+ assertEquals('e', is.read());
}
-
-
- private static final String userFriendly( String s ) {
+
+ private static final String userFriendly(String s) {
StringBuffer sb = new StringBuffer();
- for ( int i=0, n=s.length(); i
- * The implementation of the is based on CLDC 1.0 and StreamConnection.
- * However, seek is not supported.
+/**
+ * Subclass of {@link IoLib} and therefore {@link LibFunction} which implements
+ * the lua standard {@code io} library for the JSE platform.
*
- * Typically, this library is included as part of a call to
+ * The implementation of the is based on CLDC 1.0 and StreamConnection. However,
+ * seek is not supported.
+ *
+ * Typically, this library is included as part of a call to
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
- *
- * For special cases where the smallest possible footprint is desired,
- * a minimal set of libraries could be loaded
- * directly via {@link Globals#load(LuaValue)} using code such as:
- * However, other libraries such as MathLib are not loaded in this case.
+ * For special cases where the smallest possible footprint is desired, a minimal
+ * set of libraries could be loaded directly via {@link Globals#load(LuaValue)}
+ * using code such as:
+ *
+ *
- * This has been implemented to match as closely as possible the behavior in the corresponding library in C.
+ * However, other libraries such as MathLib are not loaded in this
+ * case.
+ *
+ * This has been implemented to match as closely as possible the behavior in the
+ * corresponding library in C.
+ *
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see IoLib
* @see org.luaj.vm2.lib.jse.JseIoLib
- * @see Lua 5.2 I/O Lib Reference
+ * @see Lua 5.2 I/O Lib
+ * Reference
*/
public class JmeIoLib extends IoLib {
-
+
+ @Override
protected File wrapStdin() throws IOException {
return new FileImpl(globals.STDIN);
}
-
+
+ @Override
protected File wrapStdout() throws IOException {
return new FileImpl(globals.STDOUT);
}
-
+
+ @Override
protected File wrapStderr() throws IOException {
return new FileImpl(globals.STDERR);
}
-
- protected File openFile( String filename, boolean readMode, boolean appendMode, boolean updateMode, boolean binaryMode ) throws IOException {
+
+ @Override
+ protected File openFile(String filename, boolean readMode, boolean appendMode, boolean updateMode,
+ boolean binaryMode) throws IOException {
String url = "file:///" + filename;
- int mode = readMode? Connector.READ: Connector.READ_WRITE;
- StreamConnection conn = (StreamConnection) Connector.open( url, mode );
- File f = readMode?
- new FileImpl(conn, conn.openInputStream(), null):
- new FileImpl(conn, conn.openInputStream(), conn.openOutputStream());
+ int mode = readMode? Connector.READ: Connector.READ_WRITE;
+ StreamConnection conn = (StreamConnection) Connector.open(url, mode);
+
/*
if ( appendMode ) {
f.seek("end",0);
@@ -97,68 +113,88 @@ public class JmeIoLib extends IoLib {
conn.truncate(0);
}
*/
- return f;
+ return readMode? new FileImpl(conn, conn.openInputStream(), null)
+ : new FileImpl(conn, conn.openInputStream(), conn.openOutputStream());
}
-
+
private static void notimplemented() throws IOException {
throw new IOException("not implemented");
}
-
+
+ @Override
protected File openProgram(String prog, String mode) throws IOException {
notimplemented();
return null;
}
+ @Override
protected File tmpFile() throws IOException {
notimplemented();
return null;
}
-
+
private final class FileImpl extends File {
private final StreamConnection conn;
- private final InputStream is;
- private final OutputStream os;
- private boolean closed = false;
- private boolean nobuffer = false;
- private int lookahead = -1;
- private FileImpl( StreamConnection conn, InputStream is, OutputStream os ) {
+ private final InputStream is;
+ private final OutputStream os;
+ private boolean closed = false;
+ private boolean nobuffer = false;
+ private int lookahead = -1;
+
+ private FileImpl(StreamConnection conn, InputStream is, OutputStream os) {
this.conn = conn;
this.is = is;
this.os = os;
}
- private FileImpl( InputStream i ) {
- this( null, i, null );
+
+ private FileImpl(InputStream i) {
+ this(null, i, null);
}
- private FileImpl( OutputStream o ) {
- this( null, null, o );
+
+ private FileImpl(OutputStream o) {
+ this(null, null, o);
}
+
+ @Override
public String tojstring() {
- return "file ("+this.hashCode()+")";
+ return "file (" + this.hashCode() + ")";
}
+
+ @Override
public boolean isstdfile() {
return conn == null;
}
- public void close() throws IOException {
+
+ @Override
+ public void close() throws IOException {
closed = true;
- if ( conn != null ) {
+ if (conn != null) {
conn.close();
}
}
+
+ @Override
public void flush() throws IOException {
- if ( os != null )
+ if (os != null)
os.flush();
}
+
+ @Override
public void write(LuaString s) throws IOException {
- if ( os != null )
- os.write( s.m_bytes, s.m_offset, s.m_length );
+ if (os != null)
+ os.write(s.m_bytes, s.m_offset, s.m_length);
else
notimplemented();
- if ( nobuffer )
+ if (nobuffer)
flush();
}
+
+ @Override
public boolean isclosed() {
return closed;
}
+
+ @Override
public int seek(String option, int pos) throws IOException {
/*
if ( conn != null ) {
@@ -177,48 +213,54 @@ public class JmeIoLib extends IoLib {
notimplemented();
return 0;
}
+
+ @Override
public void setvbuf(String mode, int size) {
nobuffer = "no".equals(mode);
}
// get length remaining to read
+ @Override
public int remaining() throws IOException {
return -1;
}
-
+
// peek ahead one character
+ @Override
public int peek() throws IOException {
- if ( lookahead < 0 )
+ if (lookahead < 0)
lookahead = is.read();
return lookahead;
- }
-
- // return char if read, -1 if eof, throw IOException on other exception
+ }
+
+ // return char if read, -1 if eof, throw IOException on other exception
+ @Override
public int read() throws IOException {
- if ( lookahead >= 0 ) {
+ if (lookahead >= 0) {
int c = lookahead;
lookahead = -1;
return c;
}
- if ( is != null )
+ if (is != null)
return is.read();
notimplemented();
return 0;
}
// return number of bytes read if positive, -1 if eof, throws IOException
+ @Override
public int read(byte[] bytes, int offset, int length) throws IOException {
- int n,i=0;
- if (is!=null) {
- if ( length > 0 && lookahead >= 0 ) {
+ int n, i = 0;
+ if (is != null) {
+ if (length > 0 && lookahead >= 0) {
bytes[offset] = (byte) lookahead;
lookahead = -1;
i += 1;
}
- for ( ; i
- * The JME platform, being limited, cannot implement all libraries in all aspects. The main limitations are
+ * The JME platform, being limited, cannot implement all libraries in all
+ * aspects. The main limitations are
*
- * It is used to allocate either a set of standard globals using
+ * It is used to allocate either a set of standard globals using
* {@link #standardGlobals()} or debug globals using {@link #debugGlobals()}
*
* A simple example of initializing globals and using them from Java is:
- *
* Once globals are created, a simple way to load and run a script is:
- *
- * although {@code require} could also be used:
- *
- * The standard globals will contain all standard libraries in their JME flavors:
+ * The standard globals will contain all standard libraries in their JME
+ * flavors:
*
- * The debug globals are simply the standard globals plus the {@code debug} library {@link DebugLib}.
+ * In addition, the {@link LuaC} compiler is installed so lua files may be
+ * loaded in their source form.
+ *
+ * The debug globals are simply the standard globals plus the {@code debug}
+ * library {@link DebugLib}.
*
*
- * The class ensures that initialization is done in the correct order.
- *
+ * The class ensures that initialization is done in the correct order.
+ *
* @see Globals
* @see org.luaj.vm2.lib.jse.JsePlatform
*/
@@ -97,7 +117,7 @@ public class JmePlatform {
/**
* Create a standard set of globals for JME including all the libraries.
- *
+ *
* @return Table of globals initialized with the standard JME libraries
* @see #debugGlobals()
* @see org.luaj.vm2.lib.jse.JsePlatform
@@ -116,12 +136,14 @@ public class JmePlatform {
globals.load(new JmeIoLib());
LoadState.install(globals);
LuaC.install(globals);
- return globals;
+ return globals;
}
-
- /** Create standard globals including the {@link DebugLib} library.
- *
- * @return Table of globals initialized with the standard JSE and debug libraries
+
+ /**
+ * Create standard globals including the {@link DebugLib} library.
+ *
+ * @return Table of globals initialized with the standard JSE and debug
+ * libraries
* @see #standardGlobals()
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
diff --git a/luaj-jme/src/main/resources/.keep b/luaj-jme/src/main/resources/.keep
new file mode 100644
index 00000000..e69de29b
diff --git a/luaj-jme/src/test/java/org/luaj/vm2/lib/jme/OsLibTest.java b/luaj-jme/src/test/java/org/luaj/vm2/lib/jme/OsLibTest.java
new file mode 100644
index 00000000..39adf903
--- /dev/null
+++ b/luaj-jme/src/test/java/org/luaj/vm2/lib/jme/OsLibTest.java
@@ -0,0 +1,136 @@
+package org.luaj.vm2.lib.jme;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.luaj.vm2.LuaValue;
+
+class OsLibTest {
+
+ LuaValue jme_lib;
+ double time;
+
+ @BeforeEach
+ public void setUp() {
+ jme_lib = JmePlatform.standardGlobals().get("os");
+ time = 998571302000L/1000.0;
+ }
+
+ void test(String format, String expected) {
+ String actual = jme_lib.get("date").call(LuaValue.valueOf(format), LuaValue.valueOf(time)).tojstring();
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ void testStringDateChars() { test("foo", "foo"); }
+
+ @Test
+ void testStringDate_a() { test("%a", "Thu"); }
+
+ @Test
+ void testStringDate_A() { test("%A", "Thursday"); }
+
+ @Test
+ void testStringDate_b() { test("%b", "Aug"); }
+
+ @Test
+ void testStringDate_B() { test("%B", "August"); }
+
+ @Test
+ void testStringDate_c() { test("%c", "Thu Aug 23 14:55:02 2001"); }
+
+ @Test
+ void testStringDate_d() { test("%d", "23"); }
+
+ @Test
+ void testStringDate_H() { test("%H", "14"); }
+
+ @Test
+ void testStringDate_I() { test("%I", "02"); }
+
+ @Test
+ void testStringDate_j() { test("%j", "235"); }
+
+ @Test
+ void testStringDate_m() { test("%m", "08"); }
+
+ @Test
+ void testStringDate_M() { test("%M", "55"); }
+
+ @Test
+ void testStringDate_p() { test("%p", "PM"); }
+
+ @Test
+ void testStringDate_S() { test("%S", "02"); }
+
+ @Test
+ void testStringDate_U() { test("%U", "33"); }
+
+ @Test
+ void testStringDate_w() { test("%w", "4"); }
+
+ @Test
+ void testStringDate_W() { test("%W", "34"); }
+
+ @Test
+ void testStringDate_x() { test("%x", "08/23/01"); }
+
+ @Test
+ void testStringDate_X() { test("%X", "14:55:02"); }
+
+ @Test
+ void testStringDate_y() { test("%y", "01"); }
+
+ @Test
+ void testStringDate_Y() { test("%Y", "2001"); }
+
+ @Test
+ void testStringDate_Pct() { test("%%", "%"); }
+
+ static final double DAY = 24.*3600.;
+
+ @Test
+ void testStringDate_UW_neg4() { time -= 4*DAY; test("%c %U %W", "Sun Aug 19 14:55:02 2001 33 33"); }
+
+ @Test
+ void testStringDate_UW_neg3() { time -= 3*DAY; test("%c %U %W", "Mon Aug 20 14:55:02 2001 33 34"); }
+
+ @Test
+ void testStringDate_UW_neg2() { time -= 2*DAY; test("%c %U %W", "Tue Aug 21 14:55:02 2001 33 34"); }
+
+ @Test
+ void testStringDate_UW_neg1() { time -= DAY; test("%c %U %W", "Wed Aug 22 14:55:02 2001 33 34"); }
+
+ @Test
+ void testStringDate_UW_pos0() { time += 0; test("%c %U %W", "Thu Aug 23 14:55:02 2001 33 34"); }
+
+ @Test
+ void testStringDate_UW_pos1() { time += DAY; test("%c %U %W", "Fri Aug 24 14:55:02 2001 33 34"); }
+
+ @Test
+ void testStringDate_UW_pos2() { time += 2*DAY; test("%c %U %W", "Sat Aug 25 14:55:02 2001 33 34"); }
+
+ @Test
+ void testStringDate_UW_pos3() { time += 3*DAY; test("%c %U %W", "Sun Aug 26 14:55:02 2001 34 34"); }
+
+ @Test
+ void testStringDate_UW_pos4() { time += 4*DAY; test("%c %U %W", "Mon Aug 27 14:55:02 2001 34 35"); }
+
+ @Test
+ void testJseOsGetenvForEnvVariables() {
+ LuaValue USER = LuaValue.valueOf("USER");
+ LuaValue jme_user = jme_lib.get("getenv").call(USER);
+ assertTrue(jme_user.isnil());
+ System.out.println("User: " + jme_user);
+ }
+
+ void testJseOsGetenvForSystemProperties() {
+// System.setProperty("test.key.foo", "test.value.bar");
+ LuaValue key = LuaValue.valueOf("test.key.foo");
+ LuaValue value = LuaValue.valueOf("test.value.bar");
+ LuaValue jme_value = jme_lib.get("getenv").call(key);
+ assertEquals(value, jme_value);
+ }
+}
diff --git a/luaj-jme/src/test/resources/.keep b/luaj-jme/src/test/resources/.keep
new file mode 100644
index 00000000..e69de29b
diff --git a/luaj-jse/pom.xml b/luaj-jse/pom.xml
new file mode 100644
index 00000000..cba44a6a
--- /dev/null
+++ b/luaj-jse/pom.xml
@@ -0,0 +1,77 @@
+
- * To coerce scalar types, the various, generally the {@code valueOf(type)} methods
- * on {@link LuaValue} may be used:
+ * To coerce scalar types, the various, generally the {@code valueOf(type)}
+ * methods on {@link LuaValue} may be used:
*
- * To coerce arrays of objects and lists, the {@code listOf(..)} and {@code tableOf(...)} methods
- * on {@link LuaValue} may be used:
+ * To coerce arrays of objects and lists, the {@code listOf(..)} and
+ * {@code tableOf(...)} methods on {@link LuaValue} may be used:
*
- * Integral types {@code boolean}, {@code byte}, {@code char}, and {@code int}
- * will become {@link LuaInteger};
- * {@code long}, {@code float}, and {@code double} will become {@link LuaDouble};
- * {@code String} and {@code byte[]} will become {@link LuaString};
- * types inheriting from {@link LuaValue} will be returned without coercion;
- * other types will become {@link LuaUserdata}.
+ * Integral types {@code boolean}, {@code byte}, {@code char}, and
+ * {@code int} will become {@link LuaInteger}; {@code long}, {@code float},
+ * and {@code double} will become {@link LuaDouble}; {@code String} and
+ * {@code byte[]} will become {@link LuaString}; types inheriting from
+ * {@link LuaValue} will be returned without coercion; other types will
+ * become {@link LuaUserdata}.
+ *
* @param o Java object needing conversion
- * @return {@link LuaValue} corresponding to the supplied Java value.
+ * @return {@link LuaValue} corresponding to the supplied Java value.
* @see LuaValue
* @see LuaInteger
* @see LuaDouble
@@ -175,22 +185,20 @@ public class CoerceJavaToLua {
* @see LuaUserdata
*/
public static LuaValue coerce(Object o) {
- if ( o == null )
+ if (o == null)
return LuaValue.NIL;
Class clazz = o.getClass();
- Coercion c = (Coercion) COERCIONS.get( clazz );
- if ( c == null ) {
- c = clazz.isArray()? arrayCoercion:
- o instanceof LuaValue ? luaCoercion:
- instanceCoercion;
- COERCIONS.put( clazz, c );
+ Coercion c = (Coercion) COERCIONS.get(clazz);
+ if (c == null) {
+ c = clazz.isArray()? arrayCoercion: o instanceof LuaValue? luaCoercion: instanceCoercion;
+ COERCIONS.put(clazz, c);
}
return c.coerce(o);
}
static final Coercion instanceCoercion = new InstanceCoercion();
-
- static final Coercion arrayCoercion = new ArrayCoercion();
- static final Coercion luaCoercion = new LuaCoercion() ;
+ static final Coercion arrayCoercion = new ArrayCoercion();
+
+ static final Coercion luaCoercion = new LuaCoercion();
}
diff --git a/src/jse/org/luaj/vm2/lib/jse/CoerceLuaToJava.java b/luaj-jse/src/main/java/org/luaj/vm2/lib/jse/CoerceLuaToJava.java
similarity index 52%
rename from src/jse/org/luaj/vm2/lib/jse/CoerceLuaToJava.java
rename to luaj-jse/src/main/java/org/luaj/vm2/lib/jse/CoerceLuaToJava.java
index c658aacc..c413f16d 100644
--- a/src/jse/org/luaj/vm2/lib/jse/CoerceLuaToJava.java
+++ b/luaj-jse/src/main/java/org/luaj/vm2/lib/jse/CoerceLuaToJava.java
@@ -10,7 +10,7 @@
*
* 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
@@ -31,13 +31,13 @@ import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
/**
- * Helper class to coerce values from lua to Java within the luajava library.
+ * Helper class to coerce values from lua to Java within the luajava library.
*
- * This class is primarily used by the {@link org.luaj.vm2.lib.jse.LuajavaLib},
- * but can also be used directly when working with Java/lua bindings.
+ * This class is primarily used by the {@link org.luaj.vm2.lib.jse.LuajavaLib},
+ * but can also be used directly when working with Java/lua bindings.
*
- * To coerce to specific Java values, generally the {@code toType()} methods
- * on {@link LuaValue} may be used:
+ * To coerce to specific Java values, generally the {@code toType()} methods on
+ * {@link LuaValue} may be used:
*
- * For data in lua tables, the various methods on {@link LuaTable} can be used directly
- * to convert data to something more useful.
- *
+ * For data in lua tables, the various methods on {@link LuaTable} can be used
+ * directly to convert data to something more useful.
+ *
* @see org.luaj.vm2.lib.jse.LuajavaLib
* @see CoerceJavaToLua
*/
public class CoerceLuaToJava {
- static int SCORE_NULL_VALUE = 0x10;
- static int SCORE_WRONG_TYPE = 0x100;
- static int SCORE_UNCOERCIBLE = 0x10000;
-
- static interface Coercion {
- public int score( LuaValue value );
- public Object coerce( LuaValue value );
- };
+ static int SCORE_NULL_VALUE = 0x10;
+ static int SCORE_WRONG_TYPE = 0x100;
+ static int SCORE_UNCOERCIBLE = 0x10000;
- /**
+ interface Coercion {
+ int score(LuaValue value);
+
+ Object coerce(LuaValue value);
+ }
+
+ /**
* Coerce a LuaValue value to a specified java class
+ *
* @param value LuaValue to coerce
* @param clazz Class to coerce into
- * @return Object of type clazz (or a subclass) with the corresponding value.
+ * @return Object of type clazz (or a subclass) with the corresponding
+ * value.
*/
public static Object coerce(LuaValue value, Class clazz) {
return getCoercion(clazz).coerce(value);
}
-
+
static final Map COERCIONS = Collections.synchronizedMap(new HashMap());
-
+
static final class BoolCoercion implements Coercion {
+ @Override
public String toString() {
return "BoolCoercion()";
}
- public int score( LuaValue value ) {
- switch ( value.type() ) {
+
+ @Override
+ public int score(LuaValue value) {
+ switch (value.type()) {
case LuaValue.TBOOLEAN:
return 0;
}
return 1;
}
+ @Override
public Object coerce(LuaValue value) {
return value.toboolean()? Boolean.TRUE: Boolean.FALSE;
}
}
static final class NumericCoercion implements Coercion {
- static final int TARGET_TYPE_BYTE = 0;
- static final int TARGET_TYPE_CHAR = 1;
- static final int TARGET_TYPE_SHORT = 2;
- static final int TARGET_TYPE_INT = 3;
- static final int TARGET_TYPE_LONG = 4;
- static final int TARGET_TYPE_FLOAT = 5;
- static final int TARGET_TYPE_DOUBLE = 6;
- static final String[] TYPE_NAMES = { "byte", "char", "short", "int", "long", "float", "double" };
- final int targetType;
+ static final int TARGET_TYPE_BYTE = 0;
+ static final int TARGET_TYPE_CHAR = 1;
+ static final int TARGET_TYPE_SHORT = 2;
+ static final int TARGET_TYPE_INT = 3;
+ static final int TARGET_TYPE_LONG = 4;
+ static final int TARGET_TYPE_FLOAT = 5;
+ static final int TARGET_TYPE_DOUBLE = 6;
+ static final String[] TYPE_NAMES = { "byte", "char", "short", "int", "long", "float", "double" };
+ final int targetType;
+
+ @Override
public String toString() {
- return "NumericCoercion("+TYPE_NAMES[targetType]+")";
+ return "NumericCoercion(" + TYPE_NAMES[targetType] + ")";
}
+
NumericCoercion(int targetType) {
this.targetType = targetType;
}
- public int score( LuaValue value ) {
+
+ @Override
+ public int score(LuaValue value) {
int fromStringPenalty = 0;
- if ( value.type() == LuaValue.TSTRING ) {
+ if (value.type() == LuaValue.TSTRING) {
value = value.tonumber();
- if ( value.isnil() ) {
+ if (value.isnil()) {
return SCORE_UNCOERCIBLE;
}
fromStringPenalty = 4;
}
- if ( value.isint() ) {
- switch ( targetType ) {
+ if (value.isint()) {
+ switch (targetType) {
case TARGET_TYPE_BYTE: {
int i = value.toint();
- return fromStringPenalty + ((i==(byte)i)? 0: SCORE_WRONG_TYPE);
+ return fromStringPenalty+(i == (byte) i? 0: SCORE_WRONG_TYPE);
}
case TARGET_TYPE_CHAR: {
int i = value.toint();
- return fromStringPenalty + ((i==(byte)i)? 1: (i==(char)i)? 0: SCORE_WRONG_TYPE);
+ return fromStringPenalty+(i == (byte) i? 1: i == (char) i? 0: SCORE_WRONG_TYPE);
}
case TARGET_TYPE_SHORT: {
int i = value.toint();
- return fromStringPenalty +
- ((i==(byte)i)? 1: (i==(short)i)? 0: SCORE_WRONG_TYPE);
+ return fromStringPenalty+(i == (byte) i? 1: i == (short) i? 0: SCORE_WRONG_TYPE);
}
- case TARGET_TYPE_INT: {
+ case TARGET_TYPE_INT: {
int i = value.toint();
- return fromStringPenalty +
- ((i==(byte)i)? 2: ((i==(char)i) || (i==(short)i))? 1: 0);
+ return fromStringPenalty+(i == (byte) i? 2: i == (char) i || i == (short) i? 1: 0);
}
- case TARGET_TYPE_FLOAT: return fromStringPenalty + 1;
- case TARGET_TYPE_LONG: return fromStringPenalty + 1;
- case TARGET_TYPE_DOUBLE: return fromStringPenalty + 2;
- default: return SCORE_WRONG_TYPE;
+ case TARGET_TYPE_FLOAT:
+ return fromStringPenalty+1;
+ case TARGET_TYPE_LONG:
+ return fromStringPenalty+1;
+ case TARGET_TYPE_DOUBLE:
+ return fromStringPenalty+2;
+ default:
+ return SCORE_WRONG_TYPE;
}
- } else if ( value.isnumber() ) {
- switch ( targetType ) {
- case TARGET_TYPE_BYTE: return SCORE_WRONG_TYPE;
- case TARGET_TYPE_CHAR: return SCORE_WRONG_TYPE;
- case TARGET_TYPE_SHORT: return SCORE_WRONG_TYPE;
- case TARGET_TYPE_INT: return SCORE_WRONG_TYPE;
+ } else if (value.isnumber()) {
+ switch (targetType) {
+ case TARGET_TYPE_BYTE:
+ return SCORE_WRONG_TYPE;
+ case TARGET_TYPE_CHAR:
+ return SCORE_WRONG_TYPE;
+ case TARGET_TYPE_SHORT:
+ return SCORE_WRONG_TYPE;
+ case TARGET_TYPE_INT:
+ return SCORE_WRONG_TYPE;
case TARGET_TYPE_LONG: {
double d = value.todouble();
- return fromStringPenalty + ((d==(long)d)? 0: SCORE_WRONG_TYPE);
+ return fromStringPenalty+(d == (long) d? 0: SCORE_WRONG_TYPE);
}
case TARGET_TYPE_FLOAT: {
double d = value.todouble();
- return fromStringPenalty + ((d==(float)d)? 0: SCORE_WRONG_TYPE);
+ return fromStringPenalty+(d == (float) d? 0: SCORE_WRONG_TYPE);
}
case TARGET_TYPE_DOUBLE: {
double d = value.todouble();
- return fromStringPenalty + (((d==(long)d) || (d==(float)d))? 1: 0);
+ return fromStringPenalty+(d == (long) d || d == (float) d? 1: 0);
}
- default: return SCORE_WRONG_TYPE;
+ default:
+ return SCORE_WRONG_TYPE;
}
} else {
return SCORE_UNCOERCIBLE;
}
}
+ @Override
public Object coerce(LuaValue value) {
- switch ( targetType ) {
- case TARGET_TYPE_BYTE: return new Byte( (byte) value.toint() );
- case TARGET_TYPE_CHAR: return new Character( (char) value.toint() );
- case TARGET_TYPE_SHORT: return new Short( (short) value.toint() );
- case TARGET_TYPE_INT: return new Integer( (int) value.toint() );
- case TARGET_TYPE_LONG: return new Long( (long) value.todouble() );
- case TARGET_TYPE_FLOAT: return new Float( (float) value.todouble() );
- case TARGET_TYPE_DOUBLE: return new Double( (double) value.todouble() );
- default: return null;
+ switch (targetType) {
+ case TARGET_TYPE_BYTE:
+ return Byte.valueOf((byte) value.toint());
+ case TARGET_TYPE_CHAR:
+ return Character.valueOf((char) value.toint());
+ case TARGET_TYPE_SHORT:
+ return Short.valueOf((short) value.toint());
+ case TARGET_TYPE_INT:
+ return Integer.valueOf(value.toint());
+ case TARGET_TYPE_LONG:
+ return Long.valueOf((long) value.todouble());
+ case TARGET_TYPE_FLOAT:
+ return Float.valueOf((float) value.todouble());
+ case TARGET_TYPE_DOUBLE:
+ return Double.valueOf(value.todouble());
+ default:
+ return null;
}
}
}
static final class StringCoercion implements Coercion {
public static final int TARGET_TYPE_STRING = 0;
- public static final int TARGET_TYPE_BYTES = 1;
- final int targetType;
+ public static final int TARGET_TYPE_BYTES = 1;
+ final int targetType;
+
public StringCoercion(int targetType) {
this.targetType = targetType;
}
+
+ @Override
public String toString() {
- return "StringCoercion("+(targetType==TARGET_TYPE_STRING? "String": "byte[]")+")";
+ return "StringCoercion(" + (targetType == TARGET_TYPE_STRING? "String": "byte[]") + ")";
}
+
+ @Override
public int score(LuaValue value) {
- switch ( value.type() ) {
+ switch (value.type()) {
case LuaValue.TSTRING:
- return value.checkstring().isValidUtf8()?
- (targetType==TARGET_TYPE_STRING? 0: 1):
- (targetType==TARGET_TYPE_BYTES? 0: SCORE_WRONG_TYPE);
+ return value.checkstring().isValidUtf8()? targetType == TARGET_TYPE_STRING? 0: 1
+ : targetType == TARGET_TYPE_BYTES? 0: SCORE_WRONG_TYPE;
case LuaValue.TNIL:
return SCORE_NULL_VALUE;
default:
return targetType == TARGET_TYPE_STRING? SCORE_WRONG_TYPE: SCORE_UNCOERCIBLE;
}
}
+
+ @Override
public Object coerce(LuaValue value) {
- if ( value.isnil() )
+ if (value.isnil())
return null;
- if ( targetType == TARGET_TYPE_STRING )
+ if (targetType == TARGET_TYPE_STRING)
return value.tojstring();
LuaString s = value.checkstring();
byte[] b = new byte[s.m_length];
@@ -221,33 +255,40 @@ public class CoerceLuaToJava {
}
static final class ArrayCoercion implements Coercion {
- final Class componentType;
+ final Class componentType;
final Coercion componentCoercion;
+
public ArrayCoercion(Class componentType) {
this.componentType = componentType;
this.componentCoercion = getCoercion(componentType);
}
+
+ @Override
public String toString() {
- return "ArrayCoercion("+componentType.getName()+")";
+ return "ArrayCoercion(" + componentType.getName() + ")";
}
+
+ @Override
public int score(LuaValue value) {
- switch ( value.type() ) {
+ switch (value.type()) {
case LuaValue.TTABLE:
- return value.length()==0? 0: componentCoercion.score( value.get(1) );
+ return value.length() == 0? 0: componentCoercion.score(value.get(1));
case LuaValue.TUSERDATA:
- return inheritanceLevels( componentType, value.touserdata().getClass().getComponentType() );
+ return inheritanceLevels(componentType, value.touserdata().getClass().getComponentType());
case LuaValue.TNIL:
return SCORE_NULL_VALUE;
- default:
+ default:
return SCORE_UNCOERCIBLE;
}
}
+
+ @Override
public Object coerce(LuaValue value) {
- switch ( value.type() ) {
+ switch (value.type()) {
case LuaValue.TTABLE: {
int n = value.length();
Object a = Array.newInstance(componentType, n);
- for ( int i=0; i
- * This class is not used directly.
- * It is returned by calls to {@link CoerceJavaToLua#coerce(Object)}
- * when an array is supplied.
+ * This class is not used directly. It is returned by calls to
+ * {@link CoerceJavaToLua#coerce(Object)} when an array is supplied.
+ *
* @see CoerceJavaToLua
* @see CoerceLuaToJava
*/
class JavaArray extends LuaUserdata {
private static final class LenFunction extends OneArgFunction {
+ @Override
public LuaValue call(LuaValue u) {
- return LuaValue.valueOf(Array.getLength(((LuaUserdata)u).m_instance));
+ return LuaValue.valueOf(Array.getLength(((LuaUserdata) u).m_instance));
}
}
static final LuaValue LENGTH = valueOf("length");
-
+
static final LuaTable array_metatable;
static {
array_metatable = new LuaTable();
array_metatable.rawset(LuaValue.LEN, new LenFunction());
}
-
+
JavaArray(Object instance) {
super(instance);
setmetatable(array_metatable);
}
-
+
+ @Override
public LuaValue get(LuaValue key) {
- if ( key.equals(LENGTH) )
+ if (key.equals(LENGTH))
return valueOf(Array.getLength(m_instance));
- if ( key.isint() ) {
- int i = key.toint() - 1;
- return i>=0 && i
- * Will respond to get() and set() by returning field values, or java methods.
+ * Will respond to get() and set() by returning field values, or java methods.
*
- * This class is not used directly.
- * It is returned by calls to {@link CoerceJavaToLua#coerce(Object)}
- * when a Class is supplied.
+ * This class is not used directly. It is returned by calls to
+ * {@link CoerceJavaToLua#coerce(Object)} when a Class is supplied.
+ *
* @see CoerceJavaToLua
* @see CoerceLuaToJava
*/
@@ -51,34 +51,34 @@ class JavaClass extends JavaInstance implements CoerceJavaToLua.Coercion {
static final Map classes = Collections.synchronizedMap(new HashMap());
static final LuaValue NEW = valueOf("new");
-
+
Map fields;
Map methods;
Map innerclasses;
-
+
static JavaClass forClass(Class c) {
JavaClass j = (JavaClass) classes.get(c);
- if ( j == null )
- classes.put( c, j = new JavaClass(c) );
+ if (j == null)
+ classes.put(c, j = new JavaClass(c));
return j;
}
-
+
JavaClass(Class c) {
super(c);
this.jclass = this;
}
+ @Override
public LuaValue coerce(Object javaValue) {
return this;
}
-
+
Field getField(LuaValue key) {
- if ( fields == null ) {
+ if (fields == null) {
Map m = new HashMap();
- Field[] f = ((Class)m_instance).getFields();
- for ( int i=0; i
- * This class is not used directly.
- * It is returned by calls to {@link JavaClass#new(LuaValue key)}
- * when the value of key is "new".
+ * This class is not used directly. It is returned by calls to
+ * {@link JavaClass#new(LuaValue key)} when the value of key is "new".
+ *
* @see CoerceJavaToLua
* @see CoerceLuaToJava
*/
class JavaConstructor extends JavaMember {
static final Map constructors = Collections.synchronizedMap(new HashMap());
-
+
static JavaConstructor forConstructor(Constructor c) {
JavaConstructor j = (JavaConstructor) constructors.get(c);
- if ( j == null )
- constructors.put( c, j = new JavaConstructor(c) );
+ if (j == null)
+ constructors.put(c, j = new JavaConstructor(c));
return j;
}
-
+
public static LuaValue forConstructors(JavaConstructor[] array) {
return new Overload(array);
}
final Constructor constructor;
-
+
private JavaConstructor(Constructor c) {
- super( c.getParameterTypes(), c.getModifiers() );
+ super(c.getParameterTypes(), c.getModifiers());
this.constructor = c;
}
-
+
+ @Override
public Varargs invoke(Varargs args) {
Object[] a = convertArgs(args);
try {
- return CoerceJavaToLua.coerce( constructor.newInstance(a) );
+ return CoerceJavaToLua.coerce(constructor.newInstance(a));
} catch (InvocationTargetException e) {
throw new LuaError(e.getTargetException());
} catch (Exception e) {
- return LuaValue.error("coercion error "+e);
+ return LuaValue.error("coercion error " + e);
}
}
@@ -82,33 +83,35 @@ class JavaConstructor extends JavaMember {
*
* On invocation, will pick the best method from the list, and invoke it.
*
- * This class is not used directly.
- * It is returned by calls to calls to {@link JavaClass#get(LuaValue key)}
- * when key is "new" and there is more than one public constructor.
+ * This class is not used directly. It is returned by calls to calls to
+ * {@link JavaClass#get(LuaValue key)} when key is "new" and there is more
+ * than one public constructor.
*/
static class Overload extends VarArgFunction {
- final JavaConstructor[] constructors;
+ final JavaConstructor[] constructors;
+
public Overload(JavaConstructor[] c) {
this.constructors = c;
}
+ @Override
public Varargs invoke(Varargs args) {
JavaConstructor best = null;
int score = CoerceLuaToJava.SCORE_UNCOERCIBLE;
- for ( int i=0; i
- * This class is not used directly.
- * It is returned by calls to {@link CoerceJavaToLua#coerce(Object)}
- * when a subclass of Object is supplied.
+ * This class is not used directly. It is returned by calls to
+ * {@link CoerceJavaToLua#coerce(Object)} when a subclass of Object is supplied.
+ *
* @see CoerceJavaToLua
* @see CoerceLuaToJava
*/
class JavaInstance extends LuaUserdata {
JavaClass jclass;
-
+
JavaInstance(Object instance) {
super(instance);
}
+ @Override
public LuaValue get(LuaValue key) {
- if ( jclass == null )
+ if (jclass == null)
jclass = JavaClass.forClass(m_instance.getClass());
Field f = jclass.getField(key);
- if ( f != null )
+ if (f != null)
try {
return CoerceJavaToLua.coerce(f.get(m_instance));
} catch (Exception e) {
throw new LuaError(e);
}
LuaValue m = jclass.getMethod(key);
- if ( m != null )
+ if (m != null)
return m;
Class c = jclass.getInnerClass(key);
- if ( c != null )
+ if (c != null)
return JavaClass.forClass(c);
return super.get(key);
}
+ @Override
public void set(LuaValue key, LuaValue value) {
- if ( jclass == null )
+ if (jclass == null)
jclass = JavaClass.forClass(m_instance.getClass());
Field f = jclass.getField(key);
- if ( f != null )
+ if (f != null)
try {
f.set(m_instance, CoerceLuaToJava.coerce(value, f.getType()));
return;
@@ -77,6 +79,6 @@ class JavaInstance extends LuaUserdata {
throw new LuaError(e);
}
super.set(key, value);
- }
-
+ }
+
}
diff --git a/src/jse/org/luaj/vm2/lib/jse/JavaMember.java b/luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JavaMember.java
similarity index 64%
rename from src/jse/org/luaj/vm2/lib/jse/JavaMember.java
rename to luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JavaMember.java
index e4e9b7ed..f63e01c1 100644
--- a/src/jse/org/luaj/vm2/lib/jse/JavaMember.java
+++ b/luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JavaMember.java
@@ -10,7 +10,7 @@
*
* 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
@@ -28,56 +28,56 @@ import org.luaj.vm2.lib.jse.CoerceLuaToJava.Coercion;
/**
* Java method or constructor.
*
- * Primarily handles argument coercion for parameter lists including scoring of compatibility and
- * java varargs handling.
+ * Primarily handles argument coercion for parameter lists including scoring of
+ * compatibility and java varargs handling.
*
- * This class is not used directly.
- * It is an abstract base class for {@link JavaConstructor} and {@link JavaMethod}.
+ * This class is not used directly. It is an abstract base class for
+ * {@link JavaConstructor} and {@link JavaMethod}.
+ *
* @see JavaConstructor
* @see JavaMethod
* @see CoerceJavaToLua
* @see CoerceLuaToJava
*/
-abstract
-class JavaMember extends VarArgFunction {
-
+abstract class JavaMember extends VarArgFunction {
+
static final int METHOD_MODIFIERS_VARARGS = 0x80;
final Coercion[] fixedargs;
- final Coercion varargs;
-
+ final Coercion varargs;
+
protected JavaMember(Class[] params, int modifiers) {
- boolean isvarargs = ((modifiers & METHOD_MODIFIERS_VARARGS) != 0);
+ boolean isvarargs = (modifiers & METHOD_MODIFIERS_VARARGS) != 0;
fixedargs = new CoerceLuaToJava.Coercion[isvarargs? params.length-1: params.length];
- for ( int i=0; i
- * This class is not used directly.
- * It is returned by calls to calls to {@link JavaInstance#get(LuaValue key)}
- * when a method is named.
+ * This class is not used directly. It is returned by calls to calls to
+ * {@link JavaInstance#get(LuaValue key)} when a method is named.
+ *
* @see CoerceJavaToLua
* @see CoerceLuaToJava
*/
class JavaMethod extends JavaMember {
static final Map methods = Collections.synchronizedMap(new HashMap());
-
+
static JavaMethod forMethod(Method m) {
JavaMethod j = (JavaMethod) methods.get(m);
- if ( j == null )
- methods.put( m, j = new JavaMethod(m) );
+ if (j == null)
+ methods.put(m, j = new JavaMethod(m));
return j;
}
-
+
static LuaFunction forMethods(JavaMethod[] m) {
return new Overload(m);
}
-
+
final Method method;
-
+
private JavaMethod(Method m) {
- super( m.getParameterTypes(), m.getModifiers() );
+ super(m.getParameterTypes(), m.getModifiers());
this.method = m;
try {
if (!m.isAccessible())
@@ -70,70 +70,80 @@ class JavaMethod extends JavaMember {
}
}
+ @Override
public LuaValue call() {
return error("method cannot be called without instance");
}
+ @Override
public LuaValue call(LuaValue arg) {
return invokeMethod(arg.checkuserdata(), LuaValue.NONE);
}
+ @Override
public LuaValue call(LuaValue arg1, LuaValue arg2) {
return invokeMethod(arg1.checkuserdata(), arg2);
}
-
+
+ @Override
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
return invokeMethod(arg1.checkuserdata(), LuaValue.varargsOf(arg2, arg3));
}
-
+
+ @Override
public Varargs invoke(Varargs args) {
return invokeMethod(args.checkuserdata(1), args.subargs(2));
}
-
+
LuaValue invokeMethod(Object instance, Varargs args) {
Object[] a = convertArgs(args);
try {
- return CoerceJavaToLua.coerce( method.invoke(instance, a) );
+ return CoerceJavaToLua.coerce(method.invoke(instance, a));
} catch (InvocationTargetException e) {
throw new LuaError(e.getTargetException());
} catch (Exception e) {
- return LuaValue.error("coercion error "+e);
+ return LuaValue.error("coercion error " + e);
}
}
-
+
/**
* LuaValue that represents an overloaded Java method.
*
* On invocation, will pick the best method from the list, and invoke it.
*
- * This class is not used directly.
- * It is returned by calls to calls to {@link JavaInstance#get(LuaValue key)}
- * when an overloaded method is named.
+ * This class is not used directly. It is returned by calls to calls to
+ * {@link JavaInstance#get(LuaValue key)} when an overloaded method is
+ * named.
*/
static class Overload extends LuaFunction {
final JavaMethod[] methods;
-
+
Overload(JavaMethod[] methods) {
this.methods = methods;
}
+ @Override
public LuaValue call() {
return error("method cannot be called without instance");
}
+ @Override
public LuaValue call(LuaValue arg) {
return invokeBestMethod(arg.checkuserdata(), LuaValue.NONE);
}
+ @Override
public LuaValue call(LuaValue arg1, LuaValue arg2) {
return invokeBestMethod(arg1.checkuserdata(), arg2);
}
-
+
+ @Override
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
return invokeBestMethod(arg1.checkuserdata(), LuaValue.varargsOf(arg2, arg3));
}
-
+
+ @Override
public Varargs invoke(Varargs args) {
return invokeBestMethod(args.checkuserdata(1), args.subargs(2));
}
@@ -141,20 +151,20 @@ class JavaMethod extends JavaMember {
private LuaValue invokeBestMethod(Object instance, Varargs args) {
JavaMethod best = null;
int score = CoerceLuaToJava.SCORE_UNCOERCIBLE;
- for ( int i=0; i
- * Typically, this library is included as part of a call to
+ * Since JME has no file system by default, {@link BaseLib} implements
+ * {@link ResourceFinder} using {@link Class#getResource(String)}. The
+ * {@link org.luaj.vm2.lib.jse.JseBaseLib} implements {@link Globals#finder} by
+ * scanning the current directory first, then falling back to
+ * {@link Class#getResource(String)} if that fails. Otherwise, the behavior is
+ * the same as that of {@link BaseLib}.
+ *
+ * Typically, this library is included as part of a call to
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()}
- *
- * For special cases where the smallest possible footprint is desired,
- * a minimal set of libraries could be loaded
- * directly via {@link Globals#load(LuaValue)} using code such as:
- * However, other libraries such as PackageLib are not loaded in this case.
+ * For special cases where the smallest possible footprint is desired, a minimal
+ * set of libraries could be loaded directly via {@link Globals#load(LuaValue)}
+ * using code such as:
+ *
+ *
+ * However, other libraries such as PackageLib are not loaded in this
+ * case.
*
* This is a direct port of the corresponding library in C.
+ *
* @see Globals
* @see BaseLib
* @see ResourceFinder
@@ -68,49 +81,55 @@ import org.luaj.vm2.lib.ResourceFinder;
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
- * @see Lua 5.2 Base Lib Reference
+ * @see Lua 5.2 Base Lib
+ * Reference
*/
public class JseBaseLib extends org.luaj.vm2.lib.BaseLib {
-
- /** Perform one-time initialization on the library by creating a table
- * containing the library functions, adding that table to the supplied environment,
- * adding the table to package.loaded, and returning table as the return value.
- * Specifically, extend the library loading to set the default value for {@link Globals#STDIN}
+ /**
+ * Perform one-time initialization on the library by creating a table
+ * containing the library functions, adding that table to the supplied
+ * environment, adding the table to package.loaded, and returning table as
+ * the return value.
+ *
+ * Specifically, extend the library loading to set the default value for
+ * {@link Globals#STDIN}
+ *
* @param modname the module name supplied if this is loaded via 'require'.
- * @param env the environment to load into, which must be a Globals instance.
+ * @param env the environment to load into, which must be a Globals
+ * instance.
*/
+ @Override
public LuaValue call(LuaValue modname, LuaValue env) {
super.call(modname, env);
env.checkglobals().STDIN = System.in;
return env;
}
-
- /**
- * Try to open a file in the current working directory,
- * or fall back to base opener if not found.
- *
- * This implementation attempts to open the file using new File(filename).
+ /**
+ * Try to open a file in the current working directory, or fall back to base
+ * opener if not found.
+ *
+ * This implementation attempts to open the file using new File(filename).
* It falls back to the base implementation that looks it up as a resource
- * in the class path if not found as a plain file.
- *
+ * in the class path if not found as a plain file.
+ *
* @see org.luaj.vm2.lib.BaseLib
* @see org.luaj.vm2.lib.ResourceFinder
- *
+ *
* @param filename
- * @return InputStream, or null if not found.
+ * @return InputStream, or null if not found.
*/
+ @Override
public InputStream findResource(String filename) {
File f = new File(filename);
- if ( ! f.exists() )
+ if (!f.exists())
return super.findResource(filename);
try {
return new BufferedInputStream(new FileInputStream(f));
- } catch ( IOException ioe ) {
+ } catch (IOException ioe) {
return null;
}
}
}
-
diff --git a/src/jse/org/luaj/vm2/lib/jse/JseIoLib.java b/luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JseIoLib.java
similarity index 66%
rename from src/jse/org/luaj/vm2/lib/jse/JseIoLib.java
rename to luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JseIoLib.java
index cfaf6f4a..36e560d6 100644
--- a/src/jse/org/luaj/vm2/lib/jse/JseIoLib.java
+++ b/luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JseIoLib.java
@@ -10,7 +10,7 @@
*
* 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
@@ -37,135 +37,170 @@ import org.luaj.vm2.lib.IoLib;
import org.luaj.vm2.lib.LibFunction;
/**
- * Subclass of {@link IoLib} and therefore {@link LibFunction} which implements the lua standard {@code io}
- * library for the JSE platform.
+ * Subclass of {@link IoLib} and therefore {@link LibFunction} which implements
+ * the lua standard {@code io} library for the JSE platform.
*
* It uses RandomAccessFile to implement seek on files.
*
* Typically, this library is included as part of a call to
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()}
- *
- * For special cases where the smallest possible footprint is desired,
- * a minimal set of libraries could be loaded
- * directly via {@link Globals#load(LuaValue)} using code such as:
- * However, other libraries such as MathLib are not loaded in this case.
+ * For special cases where the smallest possible footprint is desired, a minimal
+ * set of libraries could be loaded directly via {@link Globals#load(LuaValue)}
+ * using code such as:
+ *
+ *
- * This has been implemented to match as closely as possible the behavior in the corresponding library in C.
+ * However, other libraries such as MathLib are not loaded in this
+ * case.
+ *
+ * This has been implemented to match as closely as possible the behavior in the
+ * corresponding library in C.
+ *
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see IoLib
* @see org.luaj.vm2.lib.jme.JmeIoLib
- * @see Lua 5.2 I/O Lib Reference
+ * @see Lua 5.2 I/O Lib
+ * Reference
*/
public class JseIoLib extends IoLib {
+ @Override
protected File wrapStdin() throws IOException {
return new StdinFile();
}
-
+
+ @Override
protected File wrapStdout() throws IOException {
return new StdoutFile(FTYPE_STDOUT);
}
-
+
+ @Override
protected File wrapStderr() throws IOException {
return new StdoutFile(FTYPE_STDERR);
}
-
- protected File openFile( String filename, boolean readMode, boolean appendMode, boolean updateMode, boolean binaryMode ) throws IOException {
- RandomAccessFile f = new RandomAccessFile(filename,readMode? "r": "rw");
- if ( appendMode ) {
+
+ @Override
+ protected File openFile(String filename, boolean readMode, boolean appendMode, boolean updateMode,
+ boolean binaryMode) throws IOException {
+ RandomAccessFile f = new RandomAccessFile(filename, readMode? "r": "rw");
+ if (appendMode) {
f.seek(f.length());
} else {
- if ( ! readMode )
+ if (!readMode)
f.setLength(0);
}
- return new FileImpl( f );
- }
-
- protected File openProgram(String prog, String mode) throws IOException {
- final Process p = Runtime.getRuntime().exec(prog);
- return "w".equals(mode)?
- new FileImpl( p.getOutputStream() ):
- new FileImpl( p.getInputStream() );
+ return new FileImpl(f);
}
- protected File tmpFile() throws IOException {
- java.io.File f = java.io.File.createTempFile(".luaj","bin");
- f.deleteOnExit();
- return new FileImpl( new RandomAccessFile(f,"rw") );
+ @Override
+ protected File openProgram(String prog, String mode) throws IOException {
+ final Process p = Runtime.getRuntime().exec(prog);
+ return "w".equals(mode)? new FileImpl(p.getOutputStream()): new FileImpl(p.getInputStream());
}
-
+
+ @Override
+ protected File tmpFile() throws IOException {
+ java.io.File f = java.io.File.createTempFile(".luaj", "bin");
+ f.deleteOnExit();
+ return new FileImpl(new RandomAccessFile(f, "rw"));
+ }
+
private static void notimplemented() {
throw new LuaError("not implemented");
}
-
private final class FileImpl extends File {
private final RandomAccessFile file;
- private final InputStream is;
- private final OutputStream os;
- private boolean closed = false;
- private boolean nobuffer = false;
- private FileImpl( RandomAccessFile file, InputStream is, OutputStream os ) {
+ private final InputStream is;
+ private final OutputStream os;
+ private boolean closed = false;
+ private boolean nobuffer = false;
+
+ private FileImpl(RandomAccessFile file, InputStream is, OutputStream os) {
this.file = file;
- this.is = is!=null? is.markSupported()? is: new BufferedInputStream(is): null;
+ this.is = is != null? is.markSupported()? is: new BufferedInputStream(is): null;
this.os = os;
}
- private FileImpl( RandomAccessFile f ) {
- this( f, null, null );
+
+ private FileImpl(RandomAccessFile f) {
+ this(f, null, null);
}
- private FileImpl( InputStream i ) {
- this( null, i, null );
+
+ private FileImpl(InputStream i) {
+ this(null, i, null);
}
- private FileImpl( OutputStream o ) {
- this( null, null, o );
+
+ private FileImpl(OutputStream o) {
+ this(null, null, o);
}
+
+ @Override
public String tojstring() {
- return "file (" + (this.closed ? "closed" : String.valueOf(this.hashCode())) + ")";
+ return "file (" + (this.closed? "closed": String.valueOf(this.hashCode())) + ")";
}
+
+ @Override
public boolean isstdfile() {
return file == null;
}
- public void close() throws IOException {
+
+ @Override
+ public void close() throws IOException {
closed = true;
- if ( file != null ) {
+ if (file != null) {
file.close();
}
}
+
+ @Override
public void flush() throws IOException {
- if ( os != null )
+ if (os != null)
os.flush();
}
+
+ @Override
public void write(LuaString s) throws IOException {
- if ( os != null )
- os.write( s.m_bytes, s.m_offset, s.m_length );
- else if ( file != null )
- file.write( s.m_bytes, s.m_offset, s.m_length );
+ if (os != null)
+ os.write(s.m_bytes, s.m_offset, s.m_length);
+ else if (file != null)
+ file.write(s.m_bytes, s.m_offset, s.m_length);
else
notimplemented();
- if ( nobuffer )
+ if (nobuffer)
flush();
}
+
+ @Override
public boolean isclosed() {
return closed;
}
+
+ @Override
public int seek(String option, int pos) throws IOException {
- if ( file != null ) {
- if ( "set".equals(option) ) {
+ if (file != null) {
+ if ("set".equals(option)) {
file.seek(pos);
- } else if ( "end".equals(option) ) {
+ } else if ("end".equals(option)) {
file.seek(file.length()+pos);
} else {
file.seek(file.getFilePointer()+pos);
@@ -175,23 +210,27 @@ public class JseIoLib extends IoLib {
notimplemented();
return 0;
}
+
+ @Override
public void setvbuf(String mode, int size) {
nobuffer = "no".equals(mode);
}
// get length remaining to read
+ @Override
public int remaining() throws IOException {
- return file!=null? (int) (file.length()-file.getFilePointer()): -1;
+ return file != null? (int) (file.length()-file.getFilePointer()): -1;
}
-
+
// peek ahead one character
+ @Override
public int peek() throws IOException {
- if ( is != null ) {
+ if (is != null) {
is.mark(1);
int c = is.read();
is.reset();
return c;
- } else if ( file != null ) {
+ } else if (file != null) {
long fp = file.getFilePointer();
int c = file.read();
file.seek(fp);
@@ -200,12 +239,13 @@ public class JseIoLib extends IoLib {
notimplemented();
return 0;
}
-
+
// return char if read, -1 if eof, throw IOException on other exception
+ @Override
public int read() throws IOException {
- if ( is != null )
+ if (is != null)
return is.read();
- else if ( file != null ) {
+ else if (file != null) {
return file.read();
}
notimplemented();
@@ -213,10 +253,11 @@ public class JseIoLib extends IoLib {
}
// return number of bytes read if positive, -1 if eof, throws IOException
+ @Override
public int read(byte[] bytes, int offset, int length) throws IOException {
- if (file!=null) {
+ if (file != null) {
return file.read(bytes, offset, length);
- } else if (is!=null) {
+ } else if (is != null) {
return is.read(bytes, offset, length);
} else {
notimplemented();
@@ -232,57 +273,64 @@ public class JseIoLib extends IoLib {
this.file_type = file_type;
}
+ @Override
public String tojstring() {
- return "file ("+this.hashCode()+")";
+ return "file (" + this.hashCode() + ")";
}
- private final PrintStream getPrintStream() {
- return file_type == FTYPE_STDERR?
- globals.STDERR:
- globals.STDOUT;
- }
+ private PrintStream getPrintStream() { return file_type == FTYPE_STDERR? globals.STDERR: globals.STDOUT; }
+ @Override
public void write(LuaString string) throws IOException {
getPrintStream().write(string.m_bytes, string.m_offset, string.m_length);
}
+ @Override
public void flush() throws IOException {
getPrintStream().flush();
}
+ @Override
public boolean isstdfile() {
return true;
}
+ @Override
public void close() throws IOException {
// do not close std files.
}
+ @Override
public boolean isclosed() {
return false;
}
+ @Override
public int seek(String option, int bytecount) throws IOException {
return 0;
}
+ @Override
public void setvbuf(String mode, int size) {
}
+ @Override
public int remaining() throws IOException {
return 0;
}
+ @Override
public int peek() throws IOException, EOFException {
return 0;
}
+ @Override
public int read() throws IOException, EOFException {
return 0;
}
- public int read(byte[] bytes, int offset, int length)
- throws IOException {
+ @Override
+ public int read(byte[] bytes, int offset, int length) throws IOException {
return 0;
}
}
@@ -291,39 +339,49 @@ public class JseIoLib extends IoLib {
private StdinFile() {
}
+ @Override
public String tojstring() {
- return "file ("+this.hashCode()+")";
+ return "file (" + this.hashCode() + ")";
}
+ @Override
public void write(LuaString string) throws IOException {
}
+ @Override
public void flush() throws IOException {
}
+ @Override
public boolean isstdfile() {
return true;
}
+ @Override
public void close() throws IOException {
// do not close std files.
}
+ @Override
public boolean isclosed() {
return false;
}
+ @Override
public int seek(String option, int bytecount) throws IOException {
return 0;
}
+ @Override
public void setvbuf(String mode, int size) {
}
+ @Override
public int remaining() throws IOException {
return -1;
}
+ @Override
public int peek() throws IOException, EOFException {
globals.STDIN.mark(1);
int c = globals.STDIN.read();
@@ -331,12 +389,13 @@ public class JseIoLib extends IoLib {
return c;
}
+ @Override
public int read() throws IOException, EOFException {
return globals.STDIN.read();
}
- public int read(byte[] bytes, int offset, int length)
- throws IOException {
+ @Override
+ public int read(byte[] bytes, int offset, int length) throws IOException {
return globals.STDIN.read(bytes, offset, length);
}
}
diff --git a/src/jse/org/luaj/vm2/lib/jse/JseMathLib.java b/luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JseMathLib.java
similarity index 54%
rename from src/jse/org/luaj/vm2/lib/jse/JseMathLib.java
rename to luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JseMathLib.java
index 87f133a1..e0fb80ac 100644
--- a/src/jse/org/luaj/vm2/lib/jse/JseMathLib.java
+++ b/luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JseMathLib.java
@@ -10,7 +10,7 @@
*
* 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
@@ -26,60 +26,78 @@ import org.luaj.vm2.LuaValue;
import org.luaj.vm2.lib.LibFunction;
import org.luaj.vm2.lib.TwoArgFunction;
-/**
- * Subclass of {@link LibFunction} which implements the lua standard {@code math}
- * library.
- *
- * It contains all lua math functions, including those not available on the JME platform.
- * See {@link org.luaj.vm2.lib.MathLib} for the exception list.
+/**
+ * Subclass of {@link LibFunction} which implements the lua standard
+ * {@code math} library.
*
- * Typically, this library is included as part of a call to
+ * It contains all lua math functions, including those not available on the JME
+ * platform. See {@link org.luaj.vm2.lib.MathLib} for the exception list.
+ *
+ * Typically, this library is included as part of a call to
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()}
- *
- * For special cases where the smallest possible footprint is desired,
- * a minimal set of libraries could be loaded
- * directly via {@link Globals#load(LuaValue)} using code such as:
- * However, other libraries such as CoroutineLib are not loaded in this case.
+ * For special cases where the smallest possible footprint is desired, a minimal
+ * set of libraries could be loaded directly via {@link Globals#load(LuaValue)}
+ * using code such as:
+ *
+ *
- * This has been implemented to match as closely as possible the behavior in the corresponding library in C.
+ * However, other libraries such as CoroutineLib are not loaded in this
+ * case.
+ *
+ * This has been implemented to match as closely as possible the behavior in the
+ * corresponding library in C.
+ *
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see org.luaj.vm2.lib.jse.JseMathLib
- * @see Lua 5.2 Math Lib Reference
+ * @see Lua 5.2 Math Lib
+ * Reference
*/
public class JseMathLib extends org.luaj.vm2.lib.MathLib {
-
+
public JseMathLib() {}
-
- /** Perform one-time initialization on the library by creating a table
- * containing the library functions, adding that table to the supplied environment,
- * adding the table to package.loaded, and returning table as the return value.
- * Specifically, adds all library functions that can be implemented directly
- * in JSE but not JME: acos, asin, atan, atan2, cosh, exp, log, pow, sinh, and tanh.
+ /**
+ * Perform one-time initialization on the library by creating a table
+ * containing the library functions, adding that table to the supplied
+ * environment, adding the table to package.loaded, and returning table as
+ * the return value.
+ *
+ * Specifically, adds all library functions that can be implemented directly
+ * in JSE but not JME: acos, asin, atan, atan2, cosh, exp, log, pow, sinh,
+ * and tanh.
+ *
* @param modname the module name supplied if this is loaded via 'require'.
- * @param env the environment to load into, which must be a Globals instance.
+ * @param env the environment to load into, which must be a Globals
+ * instance.
*/
+ @Override
public LuaValue call(LuaValue modname, LuaValue env) {
super.call(modname, env);
LuaValue math = env.get("math");
math.set("acos", new acos());
math.set("asin", new asin());
- LuaValue atan = new atan2();
- math.set("atan", atan);
- math.set("atan2", atan);
+ math.set("atan", new atan());
+ math.set("atan2", new atan2());
math.set("cosh", new cosh());
math.set("exp", new exp());
math.set("log", new log());
@@ -89,32 +107,70 @@ public class JseMathLib extends org.luaj.vm2.lib.MathLib {
return math;
}
- static final class acos extends UnaryOp { protected double call(double d) { return Math.acos(d); } }
- static final class asin extends UnaryOp { protected double call(double d) { return Math.asin(d); } }
- static final class atan2 extends TwoArgFunction {
+ static final class acos extends UnaryOp {
+ @Override
+ protected double call(double d) { return Math.acos(d); }
+ }
+
+ static final class asin extends UnaryOp {
+ @Override
+ protected double call(double d) { return Math.asin(d); }
+ }
+
+ static final class atan extends TwoArgFunction {
+ @Override
public LuaValue call(LuaValue x, LuaValue y) {
return valueOf(Math.atan2(x.checkdouble(), y.optdouble(1)));
- }
+ }
}
- static final class cosh extends UnaryOp { protected double call(double d) { return Math.cosh(d); } }
- static final class exp extends UnaryOp { protected double call(double d) { return Math.exp(d); } }
+
+ static final class atan2 extends TwoArgFunction {
+ @Override
+ public LuaValue call(LuaValue x, LuaValue y) {
+ return valueOf(Math.atan2(x.checkdouble(), y.checkdouble()));
+ }
+ }
+
+ static final class cosh extends UnaryOp {
+ @Override
+ protected double call(double d) { return Math.cosh(d); }
+ }
+
+ static final class exp extends UnaryOp {
+ @Override
+ protected double call(double d) { return Math.exp(d); }
+ }
+
static final class log extends TwoArgFunction {
+ @Override
public LuaValue call(LuaValue x, LuaValue base) {
double nat = Math.log(x.checkdouble());
double b = base.optdouble(Math.E);
- if (b != Math.E) nat /= Math.log(b);
+ if (b != Math.E)
+ nat /= Math.log(b);
return valueOf(nat);
}
}
- static final class pow extends BinaryOp { protected double call(double x, double y) { return Math.pow(x, y); } }
- static final class sinh extends UnaryOp { protected double call(double d) { return Math.sinh(d); } }
- static final class tanh extends UnaryOp { protected double call(double d) { return Math.tanh(d); } }
+
+ static final class pow extends BinaryOp {
+ @Override
+ protected double call(double x, double y) { return Math.pow(x, y); }
+ }
+
+ static final class sinh extends UnaryOp {
+ @Override
+ protected double call(double d) { return Math.sinh(d); }
+ }
+
+ static final class tanh extends UnaryOp {
+ @Override
+ protected double call(double d) { return Math.tanh(d); }
+ }
/** Faster, better version of pow() used by arithmetic operator ^ */
+ @Override
public double dpow_lib(double a, double b) {
return Math.pow(a, b);
}
-
-
-}
+}
diff --git a/src/jse/org/luaj/vm2/lib/jse/JseOsLib.java b/luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JseOsLib.java
similarity index 74%
rename from src/jse/org/luaj/vm2/lib/jse/JseOsLib.java
rename to luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JseOsLib.java
index af63c8af..42819775 100644
--- a/src/jse/org/luaj/vm2/lib/jse/JseOsLib.java
+++ b/luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JseOsLib.java
@@ -10,7 +10,7 @@
*
* 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
@@ -31,10 +31,11 @@ import org.luaj.vm2.lib.LibFunction;
import org.luaj.vm2.lib.OsLib;
/**
- * Subclass of {@link LibFunction} which implements the standard lua {@code os} library.
+ * Subclass of {@link LibFunction} which implements the standard lua {@code os}
+ * library.
*
- * This contains more complete implementations of the following functions
- * using features that are specific to JSE:
+ * This contains more complete implementations of the following functions using
+ * features that are specific to JSE:
*
- * Because the nature of the {@code os} library is to encapsulate
- * os-specific features, the behavior of these functions varies considerably
- * from their counterparts in the C platform.
+ * Because the nature of the {@code os} library is to encapsulate os-specific
+ * features, the behavior of these functions varies considerably from their
+ * counterparts in the C platform.
*
* Typically, this library is included as part of a call to
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()}
- *
- * For special cases where the smallest possible footprint is desired,
- * a minimal set of libraries could be loaded
- * directly via {@link Globals#load(LuaValue)} using code such as:
- * However, other libraries such as MathLib are not loaded in this case.
+ * For special cases where the smallest possible footprint is desired, a minimal
+ * set of libraries could be loaded directly via {@link Globals#load(LuaValue)}
+ * using code such as:
+ *
+ *
+ * However, other libraries such as MathLib are not loaded in this
+ * case.
+ *
+ *
* @see LibFunction
* @see OsLib
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
- * @see Lua 5.2 OS Lib Reference
+ * @see Lua 5.2 OS Lib
+ * Reference
*/
public class JseOsLib extends org.luaj.vm2.lib.OsLib {
-
+
/** return code indicating the execute() threw an I/O exception */
- public static final int EXEC_IOEXCEPTION = 1;
-
+ public static final int EXEC_IOEXCEPTION = 1;
+
/** return code indicating the execute() was interrupted */
public static final int EXEC_INTERRUPTED = -2;
-
+
/** return code indicating the execute() threw an unknown exception */
- public static final int EXEC_ERROR = -3;
-
+ public static final int EXEC_ERROR = -3;
+
/** public constructor */
public JseOsLib() {
}
+ @Override
protected String getenv(String varname) {
String s = System.getenv(varname);
- return s != null? s : System.getProperty(varname);
+ return s != null? s: System.getProperty(varname);
}
+ @Override
protected Varargs execute(String command) {
int exitValue;
try {
@@ -107,29 +122,32 @@ public class JseOsLib extends org.luaj.vm2.lib.OsLib {
return varargsOf(NIL, valueOf("signal"), valueOf(exitValue));
}
+ @Override
protected void remove(String filename) throws IOException {
File f = new File(filename);
- if ( ! f.exists() )
+ if (!f.exists())
throw new IOException("No such file or directory");
- if ( ! f.delete() )
+ if (!f.delete())
throw new IOException("Failed to delete");
}
+ @Override
protected void rename(String oldname, String newname) throws IOException {
File f = new File(oldname);
- if ( ! f.exists() )
+ if (!f.exists())
throw new IOException("No such file or directory");
- if ( ! f.renameTo(new File(newname)) )
+ if (!f.renameTo(new File(newname)))
throw new IOException("Failed to rename");
}
+ @Override
protected String tmpname() {
try {
- java.io.File f = java.io.File.createTempFile(TMP_PREFIX ,TMP_SUFFIX);
+ java.io.File f = java.io.File.createTempFile(TMP_PREFIX, TMP_SUFFIX);
return f.getAbsolutePath();
- } catch ( IOException ioe ) {
+ } catch (IOException ioe) {
return super.tmpname();
}
}
-
+
}
diff --git a/src/jse/org/luaj/vm2/lib/jse/JsePlatform.java b/luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JsePlatform.java
similarity index 83%
rename from src/jse/org/luaj/vm2/lib/jse/JsePlatform.java
rename to luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JsePlatform.java
index 00575aaf..63a01c0c 100644
--- a/src/jse/org/luaj/vm2/lib/jse/JsePlatform.java
+++ b/luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JsePlatform.java
@@ -10,7 +10,7 @@
*
* 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
@@ -34,31 +34,45 @@ import org.luaj.vm2.lib.ResourceFinder;
import org.luaj.vm2.lib.StringLib;
import org.luaj.vm2.lib.TableLib;
-/** The {@link org.luaj.vm2.lib.jse.JsePlatform} class is a convenience class to standardize
- * how globals tables are initialized for the JSE platform.
+/**
+ * The {@link org.luaj.vm2.lib.jse.JsePlatform} class is a convenience class to
+ * standardize how globals tables are initialized for the JSE platform.
*
* It is used to allocate either a set of standard globals using
* {@link #standardGlobals()} or debug globals using {@link #debugGlobals()}
*
* A simple example of initializing globals and using them from Java is:
- *
* Once globals are created, a simple way to load and run a script is:
- *
* although {@code require} could also be used:
- *
- * The standard globals will contain all standard libraries plus {@code luajava}:
+ * The standard globals will contain all standard libraries plus
+ * {@code luajava}:
*
- * The debug globals are simply the standard globals plus the {@code debug} library {@link DebugLib}.
+ * The debug globals are simply the standard globals plus the {@code debug}
+ * library {@link DebugLib}.
*
* The class ensures that initialization is done in the correct order.
- *
+ *
* @see Globals
* @see org.luaj.vm2.lib.jme.JmePlatform
*/
@@ -85,7 +101,7 @@ public class JsePlatform {
/**
* Create a standard set of globals for JSE including all the libraries.
- *
+ *
* @return Table of globals initialized with the standard JSE libraries
* @see #debugGlobals()
* @see org.luaj.vm2.lib.jse.JsePlatform
@@ -108,9 +124,11 @@ public class JsePlatform {
return globals;
}
- /** Create standard globals including the {@link DebugLib} library.
- *
- * @return Table of globals initialized with the standard JSE and debug libraries
+ /**
+ * Create standard globals including the {@link DebugLib} library.
+ *
+ * @return Table of globals initialized with the standard JSE and debug
+ * libraries
* @see #standardGlobals()
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
@@ -122,10 +140,11 @@ public class JsePlatform {
return globals;
}
-
- /** Simple wrapper for invoking a lua function with command line arguments.
- * The supplied function is first given a new Globals object as its environment
- * then the program is run with arguments.
+ /**
+ * Simple wrapper for invoking a lua function with command line arguments.
+ * The supplied function is first given a new Globals object as its
+ * environment then the program is run with arguments.
+ *
* @return {@link Varargs} containing any values returned by mainChunk.
*/
public static Varargs luaMain(LuaValue mainChunk, String[] args) {
diff --git a/src/jse/org/luaj/vm2/lib/jse/JseProcess.java b/luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JseProcess.java
similarity index 70%
rename from src/jse/org/luaj/vm2/lib/jse/JseProcess.java
rename to luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JseProcess.java
index 3fcd79f1..337cf9ad 100644
--- a/src/jse/org/luaj/vm2/lib/jse/JseProcess.java
+++ b/luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JseProcess.java
@@ -10,7 +10,7 @@
*
* 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
@@ -25,37 +25,48 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-/** Analog of Process that pipes input and output to client-specified streams.
+/**
+ * Analog of Process that pipes input and output to client-specified streams.
*/
public class JseProcess {
final Process process;
- final Thread input,output,error;
+ final Thread input, output, error;
- /** Construct a process around a command, with specified streams to redirect input and output to.
- *
- * @param cmd The command to execute, including arguments, if any
- * @param stdin Optional InputStream to read from as process input, or null if input is not needed.
- * @param stdout Optional OutputStream to copy process output to, or null if output is ignored.
- * @param stderr Optinoal OutputStream to copy process stderr output to, or null if output is ignored.
+ /**
+ * Construct a process around a command, with specified streams to redirect
+ * input and output to.
+ *
+ * @param cmd The command to execute, including arguments, if any
+ * @param stdin Optional InputStream to read from as process input, or null
+ * if input is not needed.
+ * @param stdout Optional OutputStream to copy process output to, or null if
+ * output is ignored.
+ * @param stderr Optinoal OutputStream to copy process stderr output to, or
+ * null if output is ignored.
* @throws IOException If the system process could not be created.
* @see Process
*/
public JseProcess(String[] cmd, InputStream stdin, OutputStream stdout, OutputStream stderr) throws IOException {
- this(Runtime.getRuntime().exec(cmd), stdin, stdout, stderr);
+ this(Runtime.getRuntime().exec(cmd), stdin, stdout, stderr);
}
- /** Construct a process around a command, with specified streams to redirect input and output to.
- *
- * @param cmd The command to execute, including arguments, if any
- * @param stdin Optional InputStream to read from as process input, or null if input is not needed.
- * @param stdout Optional OutputStream to copy process output to, or null if output is ignored.
- * @param stderr Optinoal OutputStream to copy process stderr output to, or null if output is ignored.
+ /**
+ * Construct a process around a command, with specified streams to redirect
+ * input and output to.
+ *
+ * @param cmd The command to execute, including arguments, if any
+ * @param stdin Optional InputStream to read from as process input, or null
+ * if input is not needed.
+ * @param stdout Optional OutputStream to copy process output to, or null if
+ * output is ignored.
+ * @param stderr Optinoal OutputStream to copy process stderr output to, or
+ * null if output is ignored.
* @throws IOException If the system process could not be created.
* @see Process
*/
public JseProcess(String cmd, InputStream stdin, OutputStream stdout, OutputStream stderr) throws IOException {
- this(Runtime.getRuntime().exec(cmd), stdin, stdout, stderr);
+ this(Runtime.getRuntime().exec(cmd), stdin, stdout, stderr);
}
private JseProcess(Process process, InputStream stdin, OutputStream stdout, OutputStream stderr) {
@@ -70,7 +81,9 @@ public class JseProcess {
return process.exitValue();
}
- /** Wait for the process to complete, and all pending output to finish.
+ /**
+ * Wait for the process to complete, and all pending output to finish.
+ *
* @return The exit status.
* @throws InterruptedException
*/
@@ -87,10 +100,9 @@ public class JseProcess {
}
/** Create a thread to copy bytes from input to output. */
- private Thread copyBytes(final InputStream input,
- final OutputStream output, final InputStream ownedInput,
- final OutputStream ownedOutput) {
- Thread t = (new CopyThread(output, ownedOutput, ownedInput, input));
+ private Thread copyBytes(final InputStream input, final OutputStream output, final InputStream ownedInput,
+ final OutputStream ownedOutput) {
+ Thread t = new CopyThread(output, ownedOutput, ownedInput, input);
t.start();
return t;
}
@@ -98,23 +110,23 @@ public class JseProcess {
private static final class CopyThread extends Thread {
private final OutputStream output;
private final OutputStream ownedOutput;
- private final InputStream ownedInput;
- private final InputStream input;
+ private final InputStream ownedInput;
+ private final InputStream input;
- private CopyThread(OutputStream output, OutputStream ownedOutput,
- InputStream ownedInput, InputStream input) {
+ private CopyThread(OutputStream output, OutputStream ownedOutput, InputStream ownedInput, InputStream input) {
this.output = output;
this.ownedOutput = ownedOutput;
this.ownedInput = ownedInput;
this.input = input;
}
+ @Override
public void run() {
try {
byte[] buf = new byte[1024];
int r;
try {
- while ((r = input.read(buf)) >= 0) {
+ while ( (r = input.read(buf)) >= 0 ) {
output.write(buf, 0, r);
}
} finally {
diff --git a/src/jse/org/luaj/vm2/lib/jse/JseStringLib.java b/luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JseStringLib.java
similarity index 95%
rename from src/jse/org/luaj/vm2/lib/jse/JseStringLib.java
rename to luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JseStringLib.java
index 41177787..3923b080 100644
--- a/src/jse/org/luaj/vm2/lib/jse/JseStringLib.java
+++ b/luaj-jse/src/main/java/org/luaj/vm2/lib/jse/JseStringLib.java
@@ -10,7 +10,7 @@
*
* 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
@@ -22,15 +22,16 @@
package org.luaj.vm2.lib.jse;
public class JseStringLib extends org.luaj.vm2.lib.StringLib {
-
+
/** public constructor */
public JseStringLib() {
}
+ @Override
protected String format(String src, double x) {
String out;
try {
- out = String.format(src, new Object[] {Double.valueOf(x)});
+ out = String.format(src, Double.valueOf(x));
} catch (Throwable e) {
out = super.format(src, x);
}
diff --git a/src/jse/org/luaj/vm2/lib/jse/LuajavaLib.java b/luaj-jse/src/main/java/org/luaj/vm2/lib/jse/LuajavaLib.java
similarity index 64%
rename from src/jse/org/luaj/vm2/lib/jse/LuajavaLib.java
rename to luaj-jse/src/main/java/org/luaj/vm2/lib/jse/LuajavaLib.java
index 35f1f850..b7c0261b 100644
--- a/src/jse/org/luaj/vm2/lib/jse/LuajavaLib.java
+++ b/luaj-jse/src/main/java/org/luaj/vm2/lib/jse/LuajavaLib.java
@@ -10,7 +10,7 @@
*
* 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
@@ -21,7 +21,6 @@
******************************************************************************/
package org.luaj.vm2.lib.jse;
-
import java.lang.reflect.Array;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
@@ -38,81 +37,89 @@ import org.luaj.vm2.lib.LibFunction;
import org.luaj.vm2.lib.VarArgFunction;
/**
- * Subclass of {@link LibFunction} which implements the features of the luajava package.
+ * Subclass of {@link LibFunction} which implements the features of the luajava
+ * package.
*
- * Luajava is an approach to mixing lua and java using simple functions that bind
- * java classes and methods to lua dynamically. The API is documented on the
- * luajava documentation pages.
- *
+ * Luajava is an approach to mixing lua and java using simple functions that
+ * bind java classes and methods to lua dynamically. The API is documented on
+ * the luajava documentation
+ * pages.
+ *
*
* Typically, this library is included as part of a call to
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()}
- *
- * To instantiate and use it directly,
- * link it into your globals table via {@link Globals#load} using code such as:
- *
- *
- * The {@code luajava} library is available
- * on all JSE platforms via the call to {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()}
- * and the luajava api's are simply invoked from lua.
- * Because it makes extensive use of Java's reflection API, it is not available
- * on JME, but can be used in Android applications.
+ *
+ * The {@code luajava} library is available on all JSE platforms via the call to
+ * {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} and the luajava
+ * api's are simply invoked from lua. Because it makes extensive use of Java's
+ * reflection API, it is not available on JME, but can be used in Android
+ * applications.
*
- * This has been implemented to match as closely as possible the behavior in the corresponding library in C.
- *
+ * This has been implemented to match as closely as possible the behavior in the
+ * corresponding library in C.
+ *
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see LuaC
* @see CoerceJavaToLua
* @see CoerceLuaToJava
- * @see http://www.keplerproject.org/luajava/manual.html#luareference
+ * @see http://www.keplerproject.org/luajava/manual.html#luareference
*/
public class LuajavaLib extends VarArgFunction {
- static final int INIT = 0;
- static final int BINDCLASS = 1;
- static final int NEWINSTANCE = 2;
- static final int NEW = 3;
- static final int CREATEPROXY = 4;
- static final int LOADLIB = 5;
+ static final int INIT = 0;
+ static final int BINDCLASS = 1;
+ static final int NEWINSTANCE = 2;
+ static final int NEW = 3;
+ static final int CREATEPROXY = 4;
+ static final int LOADLIB = 5;
+
+ static final String[] NAMES = { "bindClass", "newInstance", "new", "createProxy", "loadLib", };
- static final String[] NAMES = {
- "bindClass",
- "newInstance",
- "new",
- "createProxy",
- "loadLib",
- };
-
static final int METHOD_MODIFIERS_VARARGS = 0x80;
public LuajavaLib() {
}
+ @Override
public Varargs invoke(Varargs args) {
try {
- switch ( opcode ) {
+ switch (opcode) {
case INIT: {
// LuaValue modname = args.arg1();
LuaValue env = args.arg(2);
LuaTable t = new LuaTable();
- bind( t, this.getClass(), NAMES, BINDCLASS );
+ bind(t, this.getClass(), NAMES, BINDCLASS);
env.set("luajava", t);
- if (!env.get("package").isnil()) env.get("package").get("loaded").set("luajava", t);
+ if (!env.get("package").isnil())
+ env.get("package").get("loaded").set("luajava", t);
return t;
}
case BINDCLASS: {
@@ -123,46 +130,47 @@ public class LuajavaLib extends VarArgFunction {
case NEW: {
// get constructor
final LuaValue c = args.checkvalue(1);
- final Class clazz = (opcode==NEWINSTANCE? classForName(c.tojstring()): (Class) c.checkuserdata(Class.class));
+ final Class clazz = opcode == NEWINSTANCE? classForName(c.tojstring())
+ : (Class) c.checkuserdata(Class.class);
final Varargs consargs = args.subargs(2);
return JavaClass.forClass(clazz).getConstructor().invoke(consargs);
}
-
+
case CREATEPROXY: {
final int niface = args.narg()-1;
- if ( niface <= 0 )
+ if (niface <= 0)
throw new LuaError("no interfaces");
final LuaValue lobj = args.checktable(niface+1);
-
+
// get the interfaces
final Class[] ifaces = new Class[niface];
- for ( int i=0; i
- * By default, when using {@link org.luaj.vm2.lib.jse.JsePlatform} or
- * {@link org.luaj.vm2.lib.jme.JmePlatform}
- * to construct globals, the plain compiler {@link LuaC} is installed and lua code
- * will only be compiled into lua bytecode and execute as {@link LuaClosure}.
+ * By default, when using {@link org.luaj.vm2.lib.jse.JsePlatform} or
+ * {@link org.luaj.vm2.lib.jme.JmePlatform} to construct globals, the plain
+ * compiler {@link LuaC} is installed and lua code will only be compiled into
+ * lua bytecode and execute as {@link LuaClosure}.
*
- * To override the default compiling behavior with {@link LuaJC}
- * lua-to-java bytecode compiler, install it before undumping code,
- * for example:
- *
- * This requires the bcel library to be on the class path to work as expected.
- * If the library is not found, the default {@link LuaC} lua-to-lua-bytecode
- * compiler will be used.
- *
+ * This requires the bcel library to be on the class path to work as expected.
+ * If the library is not found, the default {@link LuaC} lua-to-lua-bytecode
+ * compiler will be used.
+ *
* @see Globals#compiler
* @see #install(Globals)
* @see org.luaj.vm2.compiler.LuaC
* @see LuaValue
*/
public class LuaJC implements Globals.Loader {
-
+
public static final LuaJC instance = new LuaJC();
-
- /**
- * Install the compiler as the main Globals.Loader to use in a set of globals.
- * Will fall back to the LuaC prototype compiler.
+
+ /**
+ * Install the compiler as the main Globals.Loader to use in a set of
+ * globals. Will fall back to the LuaC prototype compiler.
*/
public static final void install(Globals G) {
- G.loader = instance;
+ G.loader = instance;
}
-
+
protected LuaJC() {}
- public Hashtable compileAll(InputStream script, String chunkname, String filename, Globals globals, boolean genmain) throws IOException {
- final String classname = toStandardJavaClassName( chunkname );
+ public Hashtable compileAll(InputStream script, String chunkname, String filename, Globals globals, boolean genmain)
+ throws IOException {
+ final String classname = toStandardJavaClassName(chunkname);
final Prototype p = globals.loadPrototype(script, classname, "bt");
return compileProtoAndSubProtos(p, classname, filename, genmain);
}
-
- public Hashtable compileAll(Reader script, String chunkname, String filename, Globals globals, boolean genmain) throws IOException {
- final String classname = toStandardJavaClassName( chunkname );
+
+ public Hashtable compileAll(Reader script, String chunkname, String filename, Globals globals, boolean genmain)
+ throws IOException {
+ final String classname = toStandardJavaClassName(chunkname);
final Prototype p = globals.compilePrototype(script, classname);
return compileProtoAndSubProtos(p, classname, filename, genmain);
}
-
- private Hashtable compileProtoAndSubProtos(Prototype p, String classname, String filename, boolean genmain) throws IOException {
- final String luaname = toStandardLuaFileName( filename );
+
+ private Hashtable compileProtoAndSubProtos(Prototype p, String classname, String filename, boolean genmain)
+ throws IOException {
+ final String luaname = toStandardLuaFileName(filename);
final Hashtable h = new Hashtable();
final JavaGen gen = new JavaGen(p, classname, luaname, genmain);
- insert( h, gen );
+ insert(h, gen);
return h;
}
-
+
private void insert(Hashtable h, JavaGen gen) {
h.put(gen.classname, gen.bytecode);
- for ( int i=0, n=gen.inners!=null? gen.inners.length: 0; i
- * If the system property 'org.luaj.debug' is set, the globals
- * created will be a debug globals that includes the debug
- * library. This may provide better stack traces, but may
- * have negative impact on performance.
+ * If the system property 'org.luaj.debug' is set, the globals created will
+ * be a debug globals that includes the debug library. This may provide
+ * better stack traces, but may have negative impact on performance.
*/
public LuajContext() {
- this("true".equals(System.getProperty("org.luaj.debug")),
- "true".equals(System.getProperty("org.luaj.luajc")));
+ this("true".equals(System.getProperty("org.luaj.debug")), "true".equals(System.getProperty("org.luaj.luajc")));
}
- /** Construct a LuajContext with its own globals, which
- * which optionally are debug globals, and optionally use the
- * luajc direct lua to java bytecode compiler.
+ /**
+ * Construct a LuajContext with its own globals, which which optionally are
+ * debug globals, and optionally use the luajc direct lua to java bytecode
+ * compiler.
*
- * If createDebugGlobals is set, the globals
- * created will be a debug globals that includes the debug
- * library. This may provide better stack traces, but may
- * have negative impact on performance.
- * @param createDebugGlobals true to create debug globals,
- * false for standard globals.
- * @param useLuaJCCompiler true to use the luajc compiler,
- * reqwuires bcel to be on the class path.
+ * If createDebugGlobals is set, the globals created will be a debug globals
+ * that includes the debug library. This may provide better stack traces,
+ * but may have negative impact on performance.
+ *
+ * @param createDebugGlobals true to create debug globals, false for
+ * standard globals.
+ * @param useLuaJCCompiler true to use the luajc compiler, reqwuires bcel
+ * to be on the class path.
*/
public LuajContext(boolean createDebugGlobals, boolean useLuaJCCompiler) {
- globals = createDebugGlobals?
- JsePlatform.debugGlobals():
- JsePlatform.standardGlobals();
- if (useLuaJCCompiler)
- LuaJC.install(globals);
- stdin = globals.STDIN;
- stdout = globals.STDOUT;
- stderr = globals.STDERR;
- }
-
- @Override
- public void setErrorWriter(Writer writer) {
- globals.STDERR = writer != null?
- new PrintStream(new WriterOutputStream(writer)):
- stderr;
+ globals = createDebugGlobals? JsePlatform.debugGlobals(): JsePlatform.standardGlobals();
+ if (useLuaJCCompiler)
+ LuaJC.install(globals);
+ stdin = globals.STDIN;
+ stdout = globals.STDOUT;
+ stderr = globals.STDERR;
}
@Override
- public void setReader(Reader reader) {
- globals.STDIN = reader != null?
- new ReaderInputStream(reader):
- stdin;
+ public void setErrorWriter(Writer writer) {
+ globals.STDERR = writer != null? new PrintStream(new WriterOutputStream(writer)): stderr;
}
+ @Override
+ public void setReader(Reader reader) { globals.STDIN = reader != null? new ReaderInputStream(reader): stdin; }
+
@Override
public void setWriter(Writer writer) {
- globals.STDOUT = writer != null?
- new PrintStream(new WriterOutputStream(writer), true):
- stdout;
+ globals.STDOUT = writer != null? new PrintStream(new WriterOutputStream(writer), true): stdout;
}
static final class WriterOutputStream extends OutputStream {
final Writer w;
+
WriterOutputStream(Writer w) {
this.w = w;
}
+
+ @Override
public void write(int b) throws IOException {
- w.write(new String(new byte[] {(byte)b}));
+ w.write(new String(new byte[] { (byte) b }));
}
+
+ @Override
public void write(byte[] b, int o, int l) throws IOException {
w.write(new String(b, o, l));
}
+
+ @Override
public void write(byte[] b) throws IOException {
w.write(new String(b));
}
+
+ @Override
public void close() throws IOException {
w.close();
}
+
+ @Override
public void flush() throws IOException {
w.flush();
}
}
-
+
static final class ReaderInputStream extends InputStream {
final Reader r;
+
ReaderInputStream(Reader r) {
this.r = r;
}
+
+ @Override
public int read() throws IOException {
return r.read();
}
diff --git a/src/jse/org/luaj/vm2/server/DefaultLauncher.java b/luaj-jse/src/main/java/org/luaj/vm2/server/DefaultLauncher.java
similarity index 93%
rename from src/jse/org/luaj/vm2/server/DefaultLauncher.java
rename to luaj-jse/src/main/java/org/luaj/vm2/server/DefaultLauncher.java
index 098f64a4..cebf12b8 100644
--- a/src/jse/org/luaj/vm2/server/DefaultLauncher.java
+++ b/luaj-jse/src/main/java/org/luaj/vm2/server/DefaultLauncher.java
@@ -10,7 +10,7 @@
*
* 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
@@ -31,14 +31,14 @@ import org.luaj.vm2.lib.jse.CoerceJavaToLua;
import org.luaj.vm2.lib.jse.JsePlatform;
/**
- * Default {@link Launcher} instance that creates standard globals
- * and runs the supplied scripts with chunk name 'main'.
+ * Default {@link Launcher} instance that creates standard globals and runs the
+ * supplied scripts with chunk name 'main'.
*
* Arguments are coerced into lua using {@link CoerceJavaToLua#coerce(Object)}.
*
- * Return values with simple types are coerced into Java simple types.
- * Tables, threads, and functions are returned as lua objects.
- *
+ * Return values with simple types are coerced into Java simple types. Tables,
+ * threads, and functions are returned as lua objects.
+ *
* @see Launcher
* @see LuajClassLoader
* @see LuajClassLoader#NewLauncher()
@@ -51,18 +51,23 @@ public class DefaultLauncher implements Launcher {
public DefaultLauncher() {
g = JsePlatform.standardGlobals();
}
-
+
/** Launches the script with chunk name 'main' */
+ @Override
public Object[] launch(String script, Object[] arg) {
return launchChunk(g.load(script, "main"), arg);
}
- /** Launches the script with chunk name 'main' and loading using modes 'bt' */
+ /**
+ * Launches the script with chunk name 'main' and loading using modes 'bt'
+ */
+ @Override
public Object[] launch(InputStream script, Object[] arg) {
return launchChunk(g.load(script, "main", "bt", g), arg);
}
/** Launches the script with chunk name 'main' */
+ @Override
public Object[] launch(Reader script, Object[] arg) {
return launchChunk(g.load(script, "main"), arg);
}
@@ -102,4 +107,4 @@ public class DefaultLauncher implements Launcher {
}
return return_values;
}
-}
\ No newline at end of file
+}
diff --git a/src/jse/org/luaj/vm2/server/Launcher.java b/luaj-jse/src/main/java/org/luaj/vm2/server/Launcher.java
similarity index 66%
rename from src/jse/org/luaj/vm2/server/Launcher.java
rename to luaj-jse/src/main/java/org/luaj/vm2/server/Launcher.java
index 378f7c81..1707e55e 100644
--- a/src/jse/org/luaj/vm2/server/Launcher.java
+++ b/luaj-jse/src/main/java/org/luaj/vm2/server/Launcher.java
@@ -10,7 +10,7 @@
*
* 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
@@ -24,16 +24,19 @@ package org.luaj.vm2.server;
import java.io.InputStream;
import java.io.Reader;
-/** Interface to launch lua scripts using the {@link LuajClassLoader}.
+/**
+ * Interface to launch lua scripts using the {@link LuajClassLoader}.
*
- * Note: This class is experimental and subject to change in future versions.
+ * Note: This class is experimental and subject to change in future
+ * versions.
*
- * This interface is purposely genericized to defer class loading so that
- * luaj classes can come from the class loader.
+ * This interface is purposely genericized to defer class loading so that luaj
+ * classes can come from the class loader.
*
- * The implementation should be acquired using {@link LuajClassLoader#NewLauncher()}
- * or {@link LuajClassLoader#NewLauncher(Class)} which ensure that the classes are
- * loaded to give each Launcher instance a pristine set of Globals, including
+ * The implementation should be acquired using
+ * {@link LuajClassLoader#NewLauncher()} or
+ * {@link LuajClassLoader#NewLauncher(Class)} which ensure that the classes are
+ * loaded to give each Launcher instance a pristine set of Globals, including
* the shared metatables.
*
* @see LuajClassLoader
@@ -43,28 +46,31 @@ import java.io.Reader;
* @since luaj 3.0.1
*/
public interface Launcher {
-
- /** Launch a script contained in a String.
- *
- * @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.
+ /**
+ * 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(InputStream script, Object[] arg);
+ Object[] launch(String script, Object[] arg);
- /** Launch a script from a Reader.
- *
- * @param script The script as a Reader.
- * @param arg Optional arguments supplied to the script.
+ /**
+ * 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(Reader script, Object[] arg);
-}
\ No newline at end of file
+ Object[] launch(InputStream script, Object[] arg);
+
+ /**
+ * Launch a script from a Reader.
+ *
+ * @param script The script as a Reader.
+ * @param arg Optional arguments supplied to the script.
+ * @return return values from the script.
+ */
+ Object[] launch(Reader script, Object[] arg);
+}
diff --git a/src/jse/org/luaj/vm2/server/LuajClassLoader.java b/luaj-jse/src/main/java/org/luaj/vm2/server/LuajClassLoader.java
similarity index 74%
rename from src/jse/org/luaj/vm2/server/LuajClassLoader.java
rename to luaj-jse/src/main/java/org/luaj/vm2/server/LuajClassLoader.java
index 3886c1f8..6db51243 100644
--- a/src/jse/org/luaj/vm2/server/LuajClassLoader.java
+++ b/luaj-jse/src/main/java/org/luaj/vm2/server/LuajClassLoader.java
@@ -10,7 +10,7 @@
*
* 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
@@ -28,16 +28,16 @@ import java.util.Map;
/**
* Class loader that can be used to launch a lua script in a Java VM that has a
- * unique set of classes for org.luaj classes.
+ * unique set of classes for org.luaj classes.
*
-* Note: This class is experimental and subject to change in future versions.
+ * Note: This class is experimental and subject to change in future
+ * versions.
*
- * By using a custom class loader per script, it allows the script to have
- * its own set of globals, including static values such as shared metatables
- * that cannot access lua values from other scripts because their classes are
- * loaded from different class loaders. Thus normally unsafe libraries such
- * as luajava can be exposed to scripts in a server environment using these
- * techniques.
+ * By using a custom class loader per script, it allows the script to have its
+ * own set of globals, including static values such as shared metatables that
+ * cannot access lua values from other scripts because their classes are loaded
+ * from different class loaders. Thus normally unsafe libraries such as luajava
+ * can be exposed to scripts in a server environment using these techniques.
*
* 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
@@ -52,7 +52,7 @@ import java.util.Map;
* 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)
@@ -61,70 +61,73 @@ import java.util.Map;
*/
public class LuajClassLoader extends ClassLoader {
- /** String describing the luaj packages to consider part of the user classes */
+ /**
+ * String describing the luaj packages to consider part of the user classes
+ */
static final String luajPackageRoot = "org.luaj.vm2.";
- /** String describing the Launcher interface to be considered a system class */
+ /**
+ * String describing the Launcher interface to be considered a system class
+ */
static final String launcherInterfaceRoot = Launcher.class.getName();
/** Local cache of classes loaded by this loader. */
- Map
- * The {@link Launcher} that is returned will be a pristine luaj vm
- * whose classes are loaded into this loader including static variables
- * such as shared metatables, and should not be able to directly access
- * variables from other Launcher instances.
- *
+ * The {@link Launcher} that is returned will be a pristine luaj vm whose
+ * classes are loaded into this loader including static variables such as
+ * shared metatables, and should not be able to directly access variables
+ * from other Launcher instances.
+ *
* @return {@link Launcher} instance that can be used to launch scripts.
* @throws InstantiationException
* @throws IllegalAccessException
* @throws ClassNotFoundException
*/
- public static Launcher NewLauncher() throws InstantiationException,
- IllegalAccessException, ClassNotFoundException {
+ public static Launcher NewLauncher() throws InstantiationException, IllegalAccessException, ClassNotFoundException {
return NewLauncher(DefaultLauncher.class);
}
/**
- * Construct a {@link Launcher} instance that will load classes in
- * its own {@link LuajClassLoader} using a user-supplied implementation class
- * that implements {@link Launcher}.
+ * Construct a {@link Launcher} instance that will load classes in its own
+ * {@link LuajClassLoader} using a user-supplied implementation class that
+ * implements {@link Launcher}.
*
- * 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.
+ * 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 {
+ throws InstantiationException, IllegalAccessException, ClassNotFoundException {
final LuajClassLoader loader = new LuajClassLoader();
- final Object instance = loader.loadAsUserClass(launcher_class.getName())
- .newInstance();
+ final Object instance = loader.loadAsUserClass(launcher_class.getName()).newInstance();
return (Launcher) instance;
}
/**
- * Test if a class name should be considered a user class and loaded
- * by this loader, or a system class and loaded by the system loader.
+ * Test if a class name should be considered a user class and loaded by this
+ * loader, or a system class and loaded by the system loader.
+ *
* @param classname Class name to test.
* @return true if this should be loaded into this class loader.
*/
public static boolean isUserClass(String classname) {
- return classname.startsWith(luajPackageRoot)
- && !classname.startsWith(launcherInterfaceRoot);
+ return classname.startsWith(luajPackageRoot) && !classname.startsWith(launcherInterfaceRoot);
}
+ @Override
public Class> loadClass(String classname) throws ClassNotFoundException {
if (classes.containsKey(classname))
return classes.get(classname);
@@ -143,13 +146,11 @@ public class LuajClassLoader extends ClassLoader {
for (int n = 0; (n = is.read(b)) >= 0;)
baos.write(b, 0, n);
byte[] bytes = baos.toByteArray();
- Class> result = super.defineClass(classname, bytes, 0,
- bytes.length);
+ Class> result = super.defineClass(classname, bytes, 0, bytes.length);
classes.put(classname, result);
return result;
} catch (java.io.IOException e) {
- throw new ClassNotFoundException("Read failed: " + classname
- + ": " + e);
+ throw new ClassNotFoundException("Read failed: " + classname + ": " + e);
}
}
throw new ClassNotFoundException("Not found: " + classname);
diff --git a/grammar/Lua51.jj b/luaj-jse/src/main/javacc/Lua51.jj
similarity index 98%
rename from grammar/Lua51.jj
rename to luaj-jse/src/main/javacc/Lua51.jj
index 9f09de3a..7febeaa6 100644
--- a/grammar/Lua51.jj
+++ b/luaj-jse/src/main/javacc/Lua51.jj
@@ -20,11 +20,11 @@ options {
DEBUG_LOOKAHEAD = false;
DEBUG_PARSER = false;
DEBUG_TOKEN_MANAGER = false;
- OUTPUT_DIRECTORY = "org/luaj/vm2/parser";
+ OUTPUT_DIRECTORY = "org/luaj/vm2/parser/lua51";
}
PARSER_BEGIN(LuaParser)
-package org.luaj.vm2.parser;
+package org.luaj.vm2.parser.lua51;
public class LuaParser {
diff --git a/grammar/Lua52.jj b/luaj-jse/src/main/javacc/Lua52.jj
similarity index 98%
rename from grammar/Lua52.jj
rename to luaj-jse/src/main/javacc/Lua52.jj
index d84f4c6f..a8f5c239 100644
--- a/grammar/Lua52.jj
+++ b/luaj-jse/src/main/javacc/Lua52.jj
@@ -20,11 +20,11 @@ options {
DEBUG_LOOKAHEAD = false;
DEBUG_PARSER = false;
DEBUG_TOKEN_MANAGER = false;
- OUTPUT_DIRECTORY = "org/luaj/vm2/parser";
+ OUTPUT_DIRECTORY = "org/luaj/vm2/parser/lua52";
}
PARSER_BEGIN(LuaParser)
-package org.luaj.vm2.parser;
+package org.luaj.vm2.parser.lua52;
public class LuaParser {
diff --git a/grammar/LuaParser.jj b/luaj-jse/src/main/javacc/LuaParser.jj
similarity index 100%
rename from grammar/LuaParser.jj
rename to luaj-jse/src/main/javacc/LuaParser.jj
diff --git a/src/jse/META-INF/services/javax.script.ScriptEngineFactory b/luaj-jse/src/main/resources/META-INF/services/javax.script.ScriptEngineFactory
similarity index 100%
rename from src/jse/META-INF/services/javax.script.ScriptEngineFactory
rename to luaj-jse/src/main/resources/META-INF/services/javax.script.ScriptEngineFactory
diff --git a/luaj-jse/src/test/java/org/luaj/jse/DumpLoadEndianIntTest.java b/luaj-jse/src/test/java/org/luaj/jse/DumpLoadEndianIntTest.java
new file mode 100644
index 00000000..ed372072
--- /dev/null
+++ b/luaj-jse/src/test/java/org/luaj/jse/DumpLoadEndianIntTest.java
@@ -0,0 +1,148 @@
+package org.luaj.jse;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.io.StringReader;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.luaj.vm2.Globals;
+import org.luaj.vm2.LuaClosure;
+import org.luaj.vm2.LuaFunction;
+import org.luaj.vm2.LuaValue;
+import org.luaj.vm2.Prototype;
+import org.luaj.vm2.compiler.DumpState;
+import org.luaj.vm2.lib.jse.JsePlatform;
+
+class DumpLoadEndianIntTest {
+ private static final String SAVECHUNKS = "SAVECHUNKS";
+
+ private static final boolean SHOULDPASS = true;
+ private static final boolean SHOULDFAIL = false;
+ private static final String mixedscript = "return tostring(1234)..'-#!-'..tostring(23.75)";
+ private static final String intscript = "return tostring(1234)..'-#!-'..tostring(23)";
+ private static final String withdoubles = "1234-#!-23.75";
+ private static final String withints = "1234-#!-23";
+
+ private Globals globals;
+
+ @BeforeEach
+ protected void setUp() throws Exception {
+ globals = JsePlatform.standardGlobals();
+ DumpState.ALLOW_INTEGER_CASTING = false;
+ }
+
+ @Test
+ void testBigDoubleCompile() {
+ doTest(false, DumpState.NUMBER_FORMAT_FLOATS_OR_DOUBLES, false, mixedscript, withdoubles, withdoubles,
+ SHOULDPASS);
+ doTest(false, DumpState.NUMBER_FORMAT_FLOATS_OR_DOUBLES, true, mixedscript, withdoubles, withdoubles,
+ SHOULDPASS);
+ }
+
+ @Test
+ void testLittleDoubleCompile() {
+ doTest(true, DumpState.NUMBER_FORMAT_FLOATS_OR_DOUBLES, false, mixedscript, withdoubles, withdoubles,
+ SHOULDPASS);
+ doTest(true, DumpState.NUMBER_FORMAT_FLOATS_OR_DOUBLES, true, mixedscript, withdoubles, withdoubles,
+ SHOULDPASS);
+ }
+
+ @Test
+ void testBigIntCompile() {
+ DumpState.ALLOW_INTEGER_CASTING = true;
+ doTest(false, DumpState.NUMBER_FORMAT_INTS_ONLY, false, mixedscript, withdoubles, withints, SHOULDPASS);
+ doTest(false, DumpState.NUMBER_FORMAT_INTS_ONLY, true, mixedscript, withdoubles, withints, SHOULDPASS);
+ DumpState.ALLOW_INTEGER_CASTING = false;
+ doTest(false, DumpState.NUMBER_FORMAT_INTS_ONLY, false, mixedscript, withdoubles, withints, SHOULDFAIL);
+ doTest(false, DumpState.NUMBER_FORMAT_INTS_ONLY, true, mixedscript, withdoubles, withints, SHOULDFAIL);
+ doTest(false, DumpState.NUMBER_FORMAT_INTS_ONLY, false, intscript, withints, withints, SHOULDPASS);
+ doTest(false, DumpState.NUMBER_FORMAT_INTS_ONLY, true, intscript, withints, withints, SHOULDPASS);
+ }
+
+ @Test
+ void testLittleIntCompile() {
+ DumpState.ALLOW_INTEGER_CASTING = true;
+ doTest(true, DumpState.NUMBER_FORMAT_INTS_ONLY, false, mixedscript, withdoubles, withints, SHOULDPASS);
+ doTest(true, DumpState.NUMBER_FORMAT_INTS_ONLY, true, mixedscript, withdoubles, withints, SHOULDPASS);
+ DumpState.ALLOW_INTEGER_CASTING = false;
+ doTest(true, DumpState.NUMBER_FORMAT_INTS_ONLY, false, mixedscript, withdoubles, withints, SHOULDFAIL);
+ doTest(true, DumpState.NUMBER_FORMAT_INTS_ONLY, true, mixedscript, withdoubles, withints, SHOULDFAIL);
+ doTest(true, DumpState.NUMBER_FORMAT_INTS_ONLY, false, intscript, withints, withints, SHOULDPASS);
+ doTest(true, DumpState.NUMBER_FORMAT_INTS_ONLY, true, intscript, withints, withints, SHOULDPASS);
+ }
+
+ @Test
+ void testBigNumpatchCompile() {
+ doTest(false, DumpState.NUMBER_FORMAT_NUM_PATCH_INT32, false, mixedscript, withdoubles, withdoubles,
+ SHOULDPASS);
+ doTest(false, DumpState.NUMBER_FORMAT_NUM_PATCH_INT32, true, mixedscript, withdoubles, withdoubles, SHOULDPASS);
+ }
+
+ @Test
+ void testLittleNumpatchCompile() {
+ doTest(true, DumpState.NUMBER_FORMAT_NUM_PATCH_INT32, false, mixedscript, withdoubles, withdoubles, SHOULDPASS);
+ doTest(true, DumpState.NUMBER_FORMAT_NUM_PATCH_INT32, true, mixedscript, withdoubles, withdoubles, SHOULDPASS);
+ }
+
+ private void doTest(boolean littleEndian, int numberFormat, boolean stripDebug, String script,
+ String expectedPriorDump, String expectedPostDump, boolean shouldPass) {
+ try {
+
+ // compile into prototype
+ Reader reader = new StringReader(script);
+ Prototype p = globals.compilePrototype(reader, "script");
+
+ // double check script result before dumping
+ LuaFunction f = new LuaClosure(p, globals);
+ LuaValue r = f.call();
+ String actual = r.tojstring();
+ assertEquals(expectedPriorDump, actual);
+
+ // dump into bytes
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ DumpState.dump(p, baos, stripDebug, numberFormat, littleEndian);
+ if (!shouldPass)
+ fail("dump should not have succeeded");
+ } catch (Exception e) {
+ if (shouldPass)
+ fail("dump threw " + e);
+ else
+ return;
+ }
+ byte[] dumped = baos.toByteArray();
+
+ // load again using compiler
+ InputStream is = new ByteArrayInputStream(dumped);
+ f = globals.load(is, "dumped", "b", globals).checkfunction();
+ r = f.call();
+ actual = r.tojstring();
+ assertEquals(expectedPostDump, actual);
+
+ // write test chunk
+ if (System.getProperty(SAVECHUNKS) != null && script.equals(mixedscript)) {
+ new File("build").mkdirs();
+ String filename = "build/test-" + (littleEndian? "little-": "big-")
+ + (numberFormat == DumpState.NUMBER_FORMAT_FLOATS_OR_DOUBLES? "double-"
+ : numberFormat == DumpState.NUMBER_FORMAT_INTS_ONLY? "int-"
+ : numberFormat == DumpState.NUMBER_FORMAT_NUM_PATCH_INT32? "numpatch4-": "???-")
+ + (stripDebug? "nodebug-": "debug-") + "bin.lua";
+ FileOutputStream fos = new FileOutputStream(filename);
+ fos.write(dumped);
+ fos.close();
+ }
+
+ } catch (IOException e) {
+ fail(e.toString());
+ }
+ }
+}
diff --git a/luaj-jse/src/test/java/org/luaj/jse/FragmentsTest.java b/luaj-jse/src/test/java/org/luaj/jse/FragmentsTest.java
new file mode 100644
index 00000000..1e57881b
--- /dev/null
+++ b/luaj-jse/src/test/java/org/luaj/jse/FragmentsTest.java
@@ -0,0 +1,460 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Luaj.org. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ ******************************************************************************/
+package org.luaj.jse;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.io.Reader;
+import java.io.StringReader;
+
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.luaj.vm2.Globals;
+import org.luaj.vm2.LuaClosure;
+import org.luaj.vm2.LuaValue;
+import org.luaj.vm2.Print;
+import org.luaj.vm2.Prototype;
+import org.luaj.vm2.Varargs;
+import org.luaj.vm2.lib.jse.JsePlatform;
+import org.luaj.vm2.luajc.LuaJC;
+
+/**
+ * Test compilation of various fragments that have caused problems for jit
+ * compiling during development.
+ *
+ */
+public class FragmentsTest {
+
+ static final int TEST_TYPE_LUAC = 0;
+ static final int TEST_TYPE_LUAJC = 1;
+
+ @Nested
+ public static class JseFragmentsTest extends FragmentsTestCase {
+ public JseFragmentsTest() { super(TEST_TYPE_LUAC); }
+ }
+
+ @Nested
+ public static class LuaJCFragmentsTest extends FragmentsTestCase {
+ public LuaJCFragmentsTest() { super(TEST_TYPE_LUAJC); }
+ }
+
+ abstract protected static class FragmentsTestCase {
+
+ final int TEST_TYPE;
+
+ protected FragmentsTestCase(int testType) {
+ this.TEST_TYPE = testType;
+ }
+
+ public void runFragment(Varargs expected, String script) {
+ try {
+ String name = this.getClass().getName();
+ Globals globals = JsePlatform.debugGlobals();
+ Reader reader = new StringReader(script);
+ LuaValue chunk;
+ switch (TEST_TYPE) {
+ case TEST_TYPE_LUAJC:
+ LuaJC.install(globals);
+ chunk = globals.load(reader, name);
+ break;
+ default:
+ Prototype p = globals.compilePrototype(reader, name);
+ chunk = new LuaClosure(p, globals);
+ Print.print(p);
+ break;
+ }
+ Varargs actual = chunk.invoke();
+ assertEquals(expected.narg(), actual.narg());
+ for (int i = 1; i <= actual.narg(); i++)
+ assertEquals(expected.arg(i), actual.arg(i));
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ fail(e.toString());
+ }
+ }
+
+ @Test
+ public void testFirstArgNilExtended() {
+ runFragment(LuaValue.NIL, "function f1(a) print( 'f1:', a ) return a end\n" + "b = f1()\n" + "return b");
+ }
+
+ @Test
+ public void testSimpleForloop() {
+ runFragment(LuaValue.valueOf(77),
+ "for n,p in ipairs({77}) do\n" + " print('n,p',n,p)\n" + " return p\n" + "end\n");
+
+ }
+
+ @Test
+ public void testForloopParamUpvalues() {
+ runFragment(LuaValue.varargsOf(new LuaValue[] { LuaValue.valueOf(77), LuaValue.valueOf(1) }),
+ "for n,p in ipairs({77}) do\n" + " print('n,p',n,p)\n" + " foo = function()\n" + " return p,n\n"
+ + " end\n" + " return foo()\n" + "end\n");
+
+ }
+
+ @Test
+ public void testArgVarargsUseBoth() {
+ runFragment(
+ LuaValue
+ .varargsOf(new LuaValue[] { LuaValue.valueOf("a"), LuaValue.valueOf("b"), LuaValue.valueOf("c") }),
+ "function v(arg,...)\n" + " return arg,...\n" + "end\n" + "return v('a','b','c')\n");
+ }
+
+ @Test
+ public void testArgParamUseNone() {
+ runFragment(LuaValue.valueOf("string"),
+ "function v(arg,...)\n" + " return type(arg)\n" + "end\n" + "return v('abc')\n");
+ }
+
+ @Test
+ public void testSetlistVarargs() {
+ runFragment(LuaValue.valueOf("abc"),
+ "local f = function() return 'abc' end\n" + "local g = { f() }\n" + "return g[1]\n");
+ }
+
+ @Test
+ public void testSelfOp() {
+ runFragment(LuaValue.valueOf("bcd"), "local s = 'abcde'\n" + "return s:sub(2,4)\n");
+ }
+
+ @Test
+ public void testSetListWithOffsetAndVarargs() {
+ runFragment(LuaValue.valueOf(1003), "local bar = {1000, math.sqrt(9)}\n" + "return bar[1]+bar[2]\n");
+ }
+
+ @Test
+ public void testMultiAssign() {
+ // arargs evaluations are all done before assignments
+ runFragment(
+ LuaValue
+ .varargsOf(new LuaValue[] { LuaValue.valueOf(111), LuaValue.valueOf(111), LuaValue.valueOf(111) }),
+ "a,b,c = 1,10,100\n" + "a,b,c = a+b+c, a+b+c, a+b+c\n" + "return a,b,c\n");
+ }
+
+ @Test
+ public void testUpvalues() {
+ runFragment(LuaValue.valueOf(999),
+ "local a = function(x)\n" + " return function(y)\n" + " return x + y\n" + " end\n" + "end\n"
+ + "local b = a(222)\n" + "local c = b(777)\n" + "print( 'c=', c )\n" + "return c\n");
+ }
+
+ @Test
+ public void testNonAsciiStringLiterals() {
+ runFragment(LuaValue.valueOf("7,8,12,10,9,11,133,222"), "local a='\\a\\b\\f\\n\\t\\v\\133\\222'\n"
+ + "local t={string.byte(a,1,#a)}\n" + "return table.concat(t,',')\n");
+ }
+
+ @Test
+ public void testControlCharStringLiterals() {
+ runFragment(LuaValue.valueOf("97,0,98,18,99,18,100,18,48,101"), "local a='a\\0b\\18c\\018d\\0180e'\n"
+ + "local t={string.byte(a,1,#a)}\n" + "return table.concat(t,',')\n");
+ }
+
+ @Test
+ public void testLoopVarNames() {
+ runFragment(LuaValue.valueOf(" 234,1,aa 234,2,bb"),
+ "local w = ''\n" + "function t()\n" + " for f,var in ipairs({'aa','bb'}) do\n" + " local s = 234\n"
+ + " w = w..' '..s..','..f..','..var\n" + " end\n" + "end\n" + "t()\n" + "return w\n");
+
+ }
+
+ @Test
+ public void testForLoops() {
+ runFragment(LuaValue.valueOf("12345 357 963"),
+ "local s,t,u = '','',''\n" + "for m=1,5 do\n" + " s = s..m\n" + "end\n" + "for m=3,7,2 do\n"
+ + " t = t..m\n" + "end\n" + "for m=9,3,-3 do\n" + " u = u..m\n" + "end\n"
+ + "return s..' '..t..' '..u\n");
+ }
+
+ @Test
+ public void testLocalFunctionDeclarations() {
+ runFragment(LuaValue.varargsOf(LuaValue.valueOf("function"), LuaValue.valueOf("nil")),
+ "local function aaa()\n" + " return type(aaa)\n" + "end\n" + "local bbb = function()\n"
+ + " return type(bbb)\n" + "end\n" + "return aaa(),bbb()\n");
+ }
+
+ @Test
+ public void testNilsInTableConstructor() {
+ runFragment(LuaValue.valueOf("1=111 2=222 3=333 "),
+ "local t = { 111, 222, 333, nil, nil }\n" + "local s = ''\n" + "for i,v in ipairs(t) do \n"
+ + " s=s..tostring(i)..'='..tostring(v)..' '\n" + "end\n" + "return s\n");
+
+ }
+
+ @Test
+ public void testUnreachableCode() {
+ runFragment(LuaValue.valueOf(66),
+ "local function foo(x) return x * 2 end\n" + "local function bar(x, y)\n" + " if x==y then\n"
+ + " return y\n" + " else\n" + " return foo(x)\n" + " end\n" + "end\n"
+ + "return bar(33,44)\n");
+
+ }
+
+ @Test
+ public void testVarargsWithParameters() {
+ runFragment(LuaValue.valueOf(222),
+ "local func = function(t,...)\n" + " return (...)\n" + "end\n" + "return func(111,222,333)\n");
+ }
+
+ @Test
+ public void testNoReturnValuesPlainCall() {
+ runFragment(LuaValue.TRUE, "local testtable = {}\n" + "return pcall( function() testtable[1]=2 end )\n");
+ }
+
+ @Test
+ public void testVarargsInTableConstructor() {
+ runFragment(LuaValue.valueOf(222), "local function foo() return 111,222,333 end\n"
+ + "local t = {'a','b',c='c',foo()}\n" + "return t[4]\n");
+ }
+
+ @Test
+ public void testVarargsInFirstArg() {
+ runFragment(LuaValue.valueOf(123), "function aaa(x) return x end\n" + "function bbb(y) return y end\n"
+ + "function ccc(z) return z end\n" + "return ccc( aaa(bbb(123)), aaa(456) )\n");
+ }
+
+ @Test
+ public void testSetUpvalueTableInitializer() {
+ runFragment(LuaValue.valueOf("b"), "local aliases = {a='b'}\n" + "local foo = function()\n"
+ + " return aliases\n" + "end\n" + "return foo().a\n");
+ }
+
+ @Test
+ public void testLoadNilUpvalue() {
+ runFragment(LuaValue.NIL, "tostring = function() end\n" + "local pc \n" + "local pcall = function(...)\n"
+ + " pc(...)\n" + "end\n" + "return NIL\n");
+ }
+
+ @Test
+ public void testUpvalueClosure() {
+ runFragment(LuaValue.NIL, "print()\n" + "local function f2() end\n" + "local function f3()\n"
+ + " return f3\n" + "end\n" + "return NIL\n");
+ }
+
+ @Test
+ public void testUninitializedUpvalue() {
+ runFragment(LuaValue.NIL, "local f\n" + "do\n" + " function g()\n" + " print(f())\n" + " end\n"
+ + "end\n" + "return NIL\n");
+ }
+
+ @Test
+ public void testTestOpUpvalues() {
+ runFragment(LuaValue.varargsOf(LuaValue.valueOf(1), LuaValue.valueOf(2), LuaValue.valueOf(3)),
+ "print( nil and 'T' or 'F' )\n" + "local a,b,c = 1,2,3\n" + "function foo()\n" + " return a,b,c\n"
+ + "end\n" + "return foo()\n");
+ }
+
+ @Test
+ public void testTestSimpleBinops() {
+ runFragment(
+ LuaValue.varargsOf(
+ new LuaValue[] { LuaValue.FALSE, LuaValue.FALSE, LuaValue.TRUE, LuaValue.TRUE, LuaValue.FALSE }),
+ "local a,b,c = 2,-2.5,0\n" + "return (a==c), (b==c), (a==a), (a>c), (b>0)\n");
+ }
+
+ @Test
+ public void testNumericForUpvalues() {
+ runFragment(LuaValue.valueOf(8), "for i = 3,4 do\n" + " i = i + 5\n" + " local a = function()\n"
+ + " return i\n" + " end\n" + " return a()\n" + "end\n");
+ }
+
+ @Test
+ public void testNumericForUpvalues2() {
+ runFragment(LuaValue.valueOf("222 222"),
+ "local t = {}\n" + "local template = [[123 456]]\n" + "for i = 1,2 do\n"
+ + " t[i] = template:gsub('%d', function(s)\n" + " return i\n" + " end)\n" + "end\n"
+ + "return t[2]\n");
+ }
+
+ @Test
+ public void testReturnUpvalue() {
+ runFragment(LuaValue.varargsOf(new LuaValue[] { LuaValue.ONE, LuaValue.valueOf(5), }), "local a = 1\n"
+ + "local b\n" + "function c()\n" + " b=5\n" + " return a\n" + "end\n" + "return c(),b\n");
+ }
+
+ @Test
+ public void testUninitializedAroundBranch() {
+ runFragment(LuaValue.valueOf(333),
+ "local state\n" + "if _G then\n" + " state = 333\n" + "end\n" + "return state\n");
+ }
+
+ @Test
+ public void testLoadedNilUpvalue() {
+ runFragment(LuaValue.NIL, "local a = print()\n" + "local b = c and { d = e }\n" + "local f\n"
+ + "local function g()\n" + " return f\n" + "end\n" + "return g()\n");
+ }
+
+ @Test
+ public void testUpvalueInFirstSlot() {
+ runFragment(LuaValue.valueOf("foo"), "local p = {'foo'}\n" + "bar = function()\n" + " return p \n"
+ + "end\n" + "for i,key in ipairs(p) do\n" + " print()\n" + "end\n" + "return bar()[1]");
+ }
+
+ @Test
+ public void testReadOnlyAndReadWriteUpvalues() {
+ runFragment(LuaValue.varargsOf(new LuaValue[] { LuaValue.valueOf(333), LuaValue.valueOf(222) }),
+ "local a = 111\n" + "local b = 222\n" + "local c = function()\n" + " a = a + b\n"
+ + " return a,b\n" + "end\n" + "return c()\n");
+ }
+
+ @Test
+ public void testNestedUpvalues() {
+ runFragment(
+ LuaValue.varargsOf(new LuaValue[] { LuaValue.valueOf(5), LuaValue.valueOf(8), LuaValue.valueOf(9) }),
+ "local x = 3\n" + "local y = 5\n" + "local function f()\n" + " return y\n" + "end\n"
+ + "local function g(x1, y1)\n" + " x = x1\n" + " y = y1\n" + " return x,y\n" + "end\n"
+ + "return f(), g(8,9)\n" + "\n");
+ }
+
+ @Test
+ public void testLoadBool() {
+ runFragment(LuaValue.NONE, "print( type(foo)=='string' )\n" + "local a,b\n" + "if print() then\n"
+ + " b = function()\n" + " return a\n" + " end\n" + "end\n");
+ }
+
+ @Test
+ public void testBasicForLoop() {
+ runFragment(LuaValue.valueOf(2), "local data\n" + "for i = 1, 2 do\n" + " data = i\n" + "end\n"
+ + "local bar = function()\n" + " return data\n" + "end\n" + "return bar()\n");
+ }
+
+ @Test
+ public void testGenericForMultipleValues() {
+ runFragment(LuaValue.varargsOf(LuaValue.valueOf(3), LuaValue.valueOf(2), LuaValue.valueOf(1)),
+ "local iter = function() return 1,2,3,4 end\n" + "local foo = function() return iter,5 end\n"
+ + "for a,b,c in foo() do\n" + " return c,b,a\n" + "end\n");
+ }
+
+ @Test
+ public void testPhiUpvalue() {
+ runFragment(LuaValue.valueOf(6), "local a = foo or 0\n" + "local function b(c)\n"
+ + " if c > a then a = c end\n" + " return a\n" + "end\n" + "b(6)\n" + "return a\n");
+ }
+
+ @Test
+ public void testAssignReferUpvalues() {
+ runFragment(LuaValue.valueOf(123), "local entity = 234\n" + "local function c()\n" + " return entity\n"
+ + "end\n" + "entity = (a == b) and 123\n" + "if entity then\n" + " return entity\n" + "end\n");
+ }
+
+ @Test
+ public void testSimpleRepeatUntil() {
+ runFragment(LuaValue.valueOf(5),
+ "local a\n" + "local w\n" + "repeat\n" + " a = w\n" + "until not a\n" + "return 5\n");
+ }
+
+ @Test
+ public void testLoopVarUpvalues() {
+ runFragment(LuaValue.valueOf("b"),
+ "local env = {}\n" + "for a,b in pairs(_G) do\n" + " c = function()\n" + " return b\n"
+ + " end\n" + "end\n" + "local e = env\n" + "local f = {a='b'}\n" + "for k,v in pairs(f) do\n"
+ + " return env[k] or v\n" + "end\n");
+ }
+
+ @Test
+ public void testPhiVarUpvalue() {
+ runFragment(LuaValue.valueOf(2), "local a = 1\n" + "local function b()\n" + " a = a + 1\n"
+ + " return function() end\n" + "end\n" + "for i in b() do\n" + " a = 3\n" + "end\n" + "return a\n");
+ }
+
+ @Test
+ public void testUpvaluesInElseClauses() {
+ runFragment(LuaValue.valueOf(111),
+ "if a then\n" + " foo(bar)\n" + "elseif _G then\n" + " local x = 111\n" + " if d then\n"
+ + " foo(bar)\n" + " else\n" + " local y = function()\n" + " return x\n"
+ + " end\n" + " return y()\n" + " end\n" + "end\n");
+ }
+
+ @Test
+ public void testUpvalueInDoBlock() {
+ runFragment(LuaValue.NONE,
+ "do\n" + " local x = 10\n" + " function g()\n" + " return x\n" + " end\n" + "end\n" + "g()\n");
+ }
+
+ @Test
+ public void testNullError() {
+ runFragment(LuaValue.varargsOf(LuaValue.FALSE, LuaValue.NIL), "return pcall(error)\n");
+ }
+
+ @Test
+ public void testFindWithOffset() {
+ runFragment(LuaValue.varargsOf(LuaValue.valueOf(8), LuaValue.valueOf(5)), "string = \"abcdef:ghi\"\n"
+ + "substring = string:sub(3)\n" + "idx = substring:find(\":\")\n" + "return #substring, idx\n");
+ }
+
+ @Test
+ public void testErrorArgIsString() {
+ runFragment(LuaValue.varargsOf(LuaValue.valueOf("string"), LuaValue.valueOf("c")),
+ "a,b = pcall(error, 'c'); return type(b), b\n");
+ }
+
+ @Test
+ public void testErrorArgIsNil() {
+ runFragment(LuaValue.varargsOf(LuaValue.valueOf("nil"), LuaValue.NIL),
+ "a,b = pcall(error); return type(b), b\n");
+ }
+
+ @Test
+ public void testErrorArgIsTable() {
+ runFragment(LuaValue.varargsOf(LuaValue.valueOf("table"), LuaValue.valueOf("d")),
+ "a,b = pcall(error, {c='d'}); return type(b), b.c\n");
+ }
+
+ @Test
+ public void testErrorArgIsNumber() {
+ runFragment(LuaValue.varargsOf(LuaValue.valueOf("string"), LuaValue.valueOf("1")),
+ "a,b = pcall(error, 1); return type(b), b\n");
+ }
+
+ @Test
+ public void testErrorArgIsBool() {
+ runFragment(LuaValue.varargsOf(LuaValue.valueOf("boolean"), LuaValue.TRUE),
+ "a,b = pcall(error, true); return type(b), b\n");
+ }
+
+ @Test
+ public void testBalancedMatchOnEmptyString() {
+ runFragment(LuaValue.NIL, "return (\"\"):match(\"%b''\")\n");
+ }
+
+ @Test
+ public void testReturnValueForTableRemove() {
+ runFragment(LuaValue.NONE, "return table.remove({ })");
+ }
+
+ @Test
+ public void testTypeOfTableRemoveReturnValue() {
+ runFragment(LuaValue.valueOf("nil"), "local k = table.remove({ }) return type(k)");
+ }
+
+ @Test
+ public void testVarargBugReport() {
+ runFragment(
+ LuaValue.varargsOf(new LuaValue[] { LuaValue.valueOf(1), LuaValue.valueOf(2), LuaValue.valueOf(3) }),
+ "local i = function(...) return ... end\n" + "local v1, v2, v3 = i(1, 2, 3)\n" + "return v1, v2, v3");
+
+ }
+ }
+}
diff --git a/test/junit/org/luaj/vm2/LoadOrderTest.java b/luaj-jse/src/test/java/org/luaj/jse/LoadOrderTest.java
similarity index 82%
rename from test/junit/org/luaj/vm2/LoadOrderTest.java
rename to luaj-jse/src/test/java/org/luaj/jse/LoadOrderTest.java
index de8ae6a0..64096299 100644
--- a/test/junit/org/luaj/vm2/LoadOrderTest.java
+++ b/luaj-jse/src/test/java/org/luaj/jse/LoadOrderTest.java
@@ -19,26 +19,31 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
-package org.luaj.vm2;
+package org.luaj.jse;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
import java.io.InputStream;
import java.io.Reader;
-import junit.framework.TestCase;
-
+import org.junit.jupiter.api.Test;
+import org.luaj.vm2.Globals;
+import org.luaj.vm2.LuaString;
import org.luaj.vm2.lib.jse.JsePlatform;
import org.luaj.vm2.server.Launcher;
import org.luaj.vm2.server.LuajClassLoader;
// Tests using class loading orders that have caused problems for some use cases.
-public class LoadOrderTest extends TestCase {
+class LoadOrderTest {
- public void testLoadGlobalsFirst() {
+ @Test
+ void testLoadGlobalsFirst() {
Globals g = JsePlatform.standardGlobals();
assertNotNull(g);
}
- public void testLoadStringFirst() {
+ @Test
+ void testLoadStringFirst() {
LuaString BAR = LuaString.valueOf("bar");
assertNotNull(BAR);
}
@@ -47,22 +52,25 @@ public class LoadOrderTest extends TestCase {
// Static initializer that causes LuaString->LuaValue->LuaString
private static final LuaString FOO = LuaString.valueOf("foo");
+ @Override
public Object[] launch(String script, Object[] arg) {
return new Object[] { FOO };
}
+ @Override
public Object[] launch(InputStream script, Object[] arg) {
return null;
}
+ @Override
public Object[] launch(Reader script, Object[] arg) {
return null;
}
}
- public void testClassLoadsStringFirst() throws Exception {
- Launcher launcher = LuajClassLoader
- .NewLauncher(TestLauncherLoadStringFirst.class);
+ @Test
+ void testClassLoadsStringFirst() throws Exception {
+ Launcher launcher = LuajClassLoader.NewLauncher(TestLauncherLoadStringFirst.class);
Object[] results = launcher.launch("foo", null);
assertNotNull(results);
}
diff --git a/luaj-jse/src/test/java/org/luaj/jse/LuaPrototypeTest.java b/luaj-jse/src/test/java/org/luaj/jse/LuaPrototypeTest.java
new file mode 100644
index 00000000..987c56e6
--- /dev/null
+++ b/luaj-jse/src/test/java/org/luaj/jse/LuaPrototypeTest.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Luaj.org. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ ******************************************************************************/
+package org.luaj.jse;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.io.Reader;
+import java.io.StringReader;
+
+import org.junit.jupiter.api.Test;
+import org.luaj.vm2.Globals;
+import org.luaj.vm2.LuaClosure;
+import org.luaj.vm2.LuaFunction;
+import org.luaj.vm2.LuaTable;
+import org.luaj.vm2.LuaValue;
+import org.luaj.vm2.Prototype;
+import org.luaj.vm2.lib.ZeroArgFunction;
+import org.luaj.vm2.lib.jse.JsePlatform;
+
+class LuaPrototypeTest {
+
+ private Prototype createPrototype(String script, String name) {
+ try {
+ Globals globals = JsePlatform.standardGlobals();
+ Reader reader = new StringReader(script);
+ return globals.compilePrototype(reader, name);
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ fail(e.toString());
+ return null;
+ }
+ }
+
+ @Test
+ void testFunctionClosureThreadEnv() {
+
+ // set up suitable environments for execution
+ LuaValue aaa = LuaValue.valueOf("aaa");
+ LuaValue eee = LuaValue.valueOf("eee");
+ final Globals globals = JsePlatform.standardGlobals();
+ LuaTable newenv = LuaValue.tableOf(new LuaValue[] { LuaValue.valueOf("a"), LuaValue.valueOf("aaa"),
+ LuaValue.valueOf("b"), LuaValue.valueOf("bbb"), });
+ LuaTable mt = LuaValue.tableOf(new LuaValue[] { LuaValue.INDEX, globals });
+ newenv.setmetatable(mt);
+ globals.set("a", aaa);
+ newenv.set("a", eee);
+
+ // function tests
+ {
+ LuaFunction f = new ZeroArgFunction() {
+ @Override
+ public LuaValue call() { return globals.get("a"); }
+ };
+ assertEquals(aaa, f.call());
+ }
+
+ // closure tests
+ {
+ Prototype p = createPrototype("return a\n", "closuretester");
+ LuaClosure c = new LuaClosure(p, globals);
+
+ // Test that a clusure with a custom enviroment uses that environment.
+ assertEquals(aaa, c.call());
+ c = new LuaClosure(p, newenv);
+ assertEquals(newenv, c.upValues[0].getValue());
+ assertEquals(eee, c.call());
+ }
+ }
+}
diff --git a/test/junit/org/luaj/vm2/OrphanedThreadTest.java b/luaj-jse/src/test/java/org/luaj/jse/OrphanedThreadTest.java
similarity index 59%
rename from test/junit/org/luaj/vm2/OrphanedThreadTest.java
rename to luaj-jse/src/test/java/org/luaj/jse/OrphanedThreadTest.java
index 14cecb4c..3f7becd2 100644
--- a/test/junit/org/luaj/vm2/OrphanedThreadTest.java
+++ b/luaj-jse/src/test/java/org/luaj/jse/OrphanedThreadTest.java
@@ -19,97 +19,97 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
-package org.luaj.vm2;
+package org.luaj.jse;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
import java.lang.ref.WeakReference;
-import junit.framework.TestCase;
-
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.luaj.vm2.Globals;
+import org.luaj.vm2.LuaThread;
+import org.luaj.vm2.LuaValue;
+import org.luaj.vm2.Varargs;
import org.luaj.vm2.lib.OneArgFunction;
import org.luaj.vm2.lib.jse.JsePlatform;
-
-public class OrphanedThreadTest extends TestCase {
+class OrphanedThreadTest {
Globals globals;
+
LuaThread luathread;
- WeakReference luathr_ref;
- LuaValue function;
- WeakReference func_ref;
-
+ LuaValue function;
+
+ WeakReferenceConstructing and Initializing Instances
- * Typically, this is constructed indirectly by a call to
- * {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
- * {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()},
- * and then used to load lua scripts for execution as in the following example.
- * {@code
- * Globals globals = JsePlatform.standardGlobals();
- * globals.load( new StringReader("print 'hello'"), "main.lua" ).call();
- * }
+ *
+ * Constructing and Initializing Instances
Typically, this is
+ * constructed indirectly by a call to
+ * {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
+ * {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}, and then used to
+ * load lua scripts for execution as in the following example.
+ *
+ *
+ * {
+ * @code
+ * Globals globals = JsePlatform.standardGlobals();
+ * globals.load(new StringReader("print 'hello'"), "main.lua").call();
+ * }
+ *
+ *
* The creates a complete global environment with the standard libraries loaded.
* {@code
- * Globals globals = new Globals();
- * globals.load( new BaseLib() );
- * }
- *
- * Loading and Executing Lua Code
- * Globals contains convenience functions to load and execute lua source code given a Reader.
- * A simple example is:
- * {@code
- * globals.load( new StringReader("print 'hello'"), "main.lua" ).call();
- * }
- *
- * Fine-Grained Control of Compiling and Loading Lua
- * Executable LuaFunctions are created from lua code in several steps
+ * For specialized circumstances, the Globals may be constructed directly and
+ * loaded with only those libraries that are needed, for example.
+ *
+ *
+ * {
+ * @code
+ * Globals globals = new Globals();
+ * globals.load(new BaseLib());
+ * }
+ *
+ *
+ * Loading and Executing Lua Code
Globals contains convenience
+ * functions to load and execute lua source code given a Reader. A simple
+ * example is:
+ *
+ *
+ * {@code
+ * globals.load( new StringReader("print 'hello'"), "main.lua" ).call();
+ * }
+ *
+ *
+ * Fine-Grained Control of Compiling and Loading Lua
Executable
+ * LuaFunctions are created from lua code in several steps
*
*
*
- *
- *
- * Java Field
- * Certain public fields are provided that contain the current values of important global state:
+ *
+ * Java Field
Certain public fields are provided that contain the
+ * current values of important global state:
*
- *
- *
- * Lua Environment Variables
- * When using {@link org.luaj.vm2.lib.jse.JsePlatform} or {@link org.luaj.vm2.lib.jme.JmePlatform},
- * these environment variables are created within the Globals.
+ *
+ * Lua Environment Variables
When using
+ * {@link org.luaj.vm2.lib.jse.JsePlatform} or
+ * {@link org.luaj.vm2.lib.jme.JmePlatform}, these environment variables are
+ * created within the Globals.
*
*
- *
- * Use in Multithreaded Environments
- * In a multi-threaded server environment, each server thread should create one Globals instance,
- * which will be logically distinct and not interfere with each other, but share certain
- * static immutable resources such as class data and string data.
+ *
+ * Use in Multithreaded Environments
In a multi-threaded server
+ * environment, each server thread should create one Globals instance, which
+ * will be logically distinct and not interfere with each other, but share
+ * certain static immutable resources such as class data and string data.
* {@code
-* Globals globals = JsePlatform.standardGlobals();
-* LuaValue chunk = globasl.load("print('hello, world')", "main.lua");
-* chunk.call();
-* }
-* This should work regardless of which {@link Globals.Compiler} or {@link Globals.Undumper}
-* have been installed.
-* {@code
-* Globals globals = JsePlatform.standardGlobals();
-* Prototype p = globals.compilePrototype(new StringReader("print('hello, world')"), "main.lua");
-* ByteArrayOutputStream o = new ByteArrayOutputStream();
-* org.luaj.vm2.compiler.DumpState.dump(p, o, false);
-* byte[] lua_binary_file_bytes = o.toByteArray();
-* }
-*
-* The {@link LoadState}'s default undumper {@link #instance}
-* may be used directly to undump these bytes:
-* {@code
+ * Class to undump compiled lua bytecode into a {@link Prototype} instances.
+ *
+ *
+ *
+ * More commonly, the {@link Globals.Undumper} may be used to undump them:
+ *
+ *
+ * {
+ * @code
+ * Globals globals = JsePlatform.standardGlobals();
+ * LuaValue chunk = globasl.load("print('hello, world')", "main.lua");
+ * chunk.call();
+ * }
+ *
+ *
+ * This should work regardless of which {@link Globals.Compiler} or
+ * {@link Globals.Undumper} have been installed.
+ *
+ * {
+ * @code
+ * Globals globals = JsePlatform.standardGlobals();
+ * Prototype p = globals.compilePrototype(new StringReader("print('hello, world')"), "main.lua");
+ * ByteArrayOutputStream o = new ByteArrayOutputStream();
+ * org.luaj.vm2.compiler.DumpState.dump(p, o, false);
+ * byte[] lua_binary_file_bytes = o.toByteArray();
+ * }
+ *
+ *
+ * The {@link LoadState}'s default undumper {@link #instance} may be used
+ * directly to undump these bytes:
+ *
+ *
+ * {@code
* Prototypep = LoadState.instance.undump(new ByteArrayInputStream(lua_binary_file_bytes), "main.lua");
* LuaClosure c = new LuaClosure(p, globals);
* c.call();
-* }
-*
-*
-* More commonly, the {@link Globals.Undumper} may be used to undump them:
-* {@code
-* Prototype p = globals.loadPrototype(new ByteArrayInputStream(lua_binary_file_bytes), "main.lua", "b");
-* LuaClosure c = new LuaClosure(p, globals);
-* c.call();
-* }
-*
-* @see Globals.Compiler
-* @see Globals.Undumper
-* @see LuaClosure
-* @see LuaFunction
-* @see org.luaj.vm2.compiler.LuaC
-* @see org.luaj.vm2.luajc.LuaJC
-* @see Globals#compiler
-* @see Globals#load(InputStream, String, LuaValue)
-*/
+* }
+ *
+ * {
+ * @code
+ * Prototype p = globals.loadPrototype(new ByteArrayInputStream(lua_binary_file_bytes), "main.lua", "b");
+ * LuaClosure c = new LuaClosure(p, globals);
+ * c.call();
+ * }
+ *
+ *
+ * @see Globals.Compiler
+ * @see Globals.Undumper
+ * @see LuaClosure
+ * @see LuaFunction
+ * @see org.luaj.vm2.compiler.LuaC
+ * @see org.luaj.vm2.luajc.LuaJC
+ * @see Globals#compiler
+ * @see Globals#load(InputStream, String, LuaValue)
+ */
public class LoadState {
- /** Shared instance of Globals.Undumper to use loading prototypes from binary lua files */
+ /**
+ * Shared instance of Globals.Undumper to use loading prototypes from binary
+ * lua files
+ */
public static final Globals.Undumper instance = new GlobalsUndumper();
-
- /** format corresponding to non-number-patched lua, all numbers are floats or doubles */
- public static final int NUMBER_FORMAT_FLOATS_OR_DOUBLES = 0;
+
+ /**
+ * format corresponding to non-number-patched lua, all numbers are floats or
+ * doubles
+ */
+ public static final int NUMBER_FORMAT_FLOATS_OR_DOUBLES = 0;
/** format corresponding to non-number-patched lua, all numbers are ints */
- public static final int NUMBER_FORMAT_INTS_ONLY = 1;
-
- /** format corresponding to number-patched lua, all numbers are 32-bit (4 byte) ints */
- public static final int NUMBER_FORMAT_NUM_PATCH_INT32 = 4;
-
+ public static final int NUMBER_FORMAT_INTS_ONLY = 1;
+
+ /**
+ * format corresponding to number-patched lua, all numbers are 32-bit (4
+ * byte) ints
+ */
+ public static final int NUMBER_FORMAT_NUM_PATCH_INT32 = 4;
+
// type constants
- public static final int LUA_TINT = (-2);
- public static final int LUA_TNONE = (-1);
- public static final int LUA_TNIL = 0;
- public static final int LUA_TBOOLEAN = 1;
- public static final int LUA_TLIGHTUSERDATA = 2;
- public static final int LUA_TNUMBER = 3;
- public static final int LUA_TSTRING = 4;
- public static final int LUA_TTABLE = 5;
- public static final int LUA_TFUNCTION = 6;
- public static final int LUA_TUSERDATA = 7;
- public static final int LUA_TTHREAD = 8;
- public static final int LUA_TVALUE = 9;
-
- /** The character encoding to use for file encoding. Null means the default encoding */
+ public static final int LUA_TINT = -2;
+ public static final int LUA_TNONE = -1;
+ public static final int LUA_TNIL = 0;
+ public static final int LUA_TBOOLEAN = 1;
+ public static final int LUA_TLIGHTUSERDATA = 2;
+ public static final int LUA_TNUMBER = 3;
+ public static final int LUA_TSTRING = 4;
+ public static final int LUA_TTABLE = 5;
+ public static final int LUA_TFUNCTION = 6;
+ public static final int LUA_TUSERDATA = 7;
+ public static final int LUA_TTHREAD = 8;
+ public static final int LUA_TVALUE = 9;
+
+ /**
+ * The character encoding to use for file encoding. Null means the default
+ * encoding
+ */
public static String encoding = null;
-
+
/** Signature byte indicating the file is a compiled binary chunk */
- public static final byte[] LUA_SIGNATURE = { '\033', 'L', 'u', 'a' };
+ public static final byte[] LUA_SIGNATURE = { '\033', 'L', 'u', 'a' };
/** Data to catch conversion errors */
public static final byte[] LUAC_TAIL = { (byte) 0x19, (byte) 0x93, '\r', '\n', (byte) 0x1a, '\n', };
-
/** Name for compiled chunks */
public static final String SOURCE_BINARY_STRING = "binary string";
-
/** for header of binary files -- this is Lua 5.2 */
- public static final int LUAC_VERSION = 0x52;
+ public static final int LUAC_VERSION = 0x52;
/** for header of binary files -- this is the official format */
- public static final int LUAC_FORMAT = 0;
+ public static final int LUAC_FORMAT = 0;
/** size of header of binary files */
- public static final int LUAC_HEADERSIZE = 12;
+ public static final int LUAC_HEADERSIZE = 12;
// values read from the header
private int luacVersion;
@@ -144,7 +169,7 @@ public class LoadState {
private int luacSizeofSizeT;
private int luacSizeofInstruction;
private int luacSizeofLuaNumber;
- private int luacNumberFormat;
+ private int luacNumberFormat;
/** input stream from which we are loading */
public final DataInputStream is;
@@ -152,135 +177,148 @@ public class LoadState {
/** Name of what is being loaded? */
String name;
- private static final LuaValue[] NOVALUES = {};
- private static final Prototype[] NOPROTOS = {};
- private static final LocVars[] NOLOCVARS = {};
- private static final Upvaldesc[] NOUPVALDESCS = {};
- private static final int[] NOINTS = {};
-
+ private static final LuaValue[] NOVALUES = {};
+ private static final Prototype[] NOPROTOS = {};
+ private static final LocVars[] NOLOCVARS = {};
+ private static final Upvaldesc[] NOUPVALDESCS = {};
+ private static final int[] NOINTS = {};
+
/** Read buffer */
private byte[] buf = new byte[512];
- /** Install this class as the standard Globals.Undumper for the supplied Globals */
+ /**
+ * Install this class as the standard Globals.Undumper for the supplied
+ * Globals
+ */
public static void install(Globals globals) {
globals.undumper = instance;
}
-
- /** Load a 4-byte int value from the input stream
+
+ /**
+ * Load a 4-byte int value from the input stream
+ *
* @return the int value laoded.
**/
int loadInt() throws IOException {
- is.readFully(buf,0,4);
- return luacLittleEndian?
- (buf[3] << 24) | ((0xff & buf[2]) << 16) | ((0xff & buf[1]) << 8) | (0xff & buf[0]):
- (buf[0] << 24) | ((0xff & buf[1]) << 16) | ((0xff & buf[2]) << 8) | (0xff & buf[3]);
+ is.readFully(buf, 0, 4);
+ return luacLittleEndian? buf[3]<<24 | (0xff & buf[2])<<16 | (0xff & buf[1])<<8 | 0xff & buf[0]
+ : buf[0]<<24 | (0xff & buf[1])<<16 | (0xff & buf[2])<<8 | 0xff & buf[3];
}
-
- /** Load an array of int values from the input stream
+
+ /**
+ * Load an array of int values from the input stream
+ *
* @return the array of int values laoded.
**/
int[] loadIntArray() throws IOException {
int n = loadInt();
- if ( n == 0 )
+ if (n == 0)
return NOINTS;
-
+
// read all data at once
- int m = n << 2;
- if ( buf.length < m )
+ int m = n<<2;
+ if (buf.length < m)
buf = new byte[m];
- is.readFully(buf,0,m);
+ is.readFully(buf, 0, m);
int[] array = new int[n];
- for ( int i=0, j=0; i
*
* {@code
- * String script = "print( 'hello, world' )";
- * InputStream is = new ByteArrayInputStream(script.getBytes());
- * Prototype p = LuaC.instance.compile(is, "script");
- * LuaValue globals = JsePlatform.standardGlobals();
- * LuaClosure f = new LuaClosure(p, globals);
- * f.call();
- * }
+ * To construct it directly, the {@link Prototype} is typically created via a
+ * compiler such as {@link org.luaj.vm2.compiler.LuaC}:
+ *
+ *
+ * {
+ * @code
+ * String script = "print( 'hello, world' )";
+ * InputStream is = new ByteArrayInputStream(script.getBytes());
+ * Prototype p = LuaC.instance.compile(is, "script");
+ * LuaValue globals = JsePlatform.standardGlobals();
+ * LuaClosure f = new LuaClosure(p, globals);
+ * f.call();
+ * }
+ *
* {@code
- * Globals globals = JsePlatform.standardGlobals();
- * LuaFunction f = globals.load(new StringReader(script), "script");
- * LuaClosure c = f.checkclosure(); // This may fail if LuaJC is installed.
- * c.call();
- * }
+ * To construct it indirectly, the {@link Globals#load(java.io.Reader, String)}
+ * method may be used:
+ *
+ *
+ * {
+ * @code
+ * Globals globals = JsePlatform.standardGlobals();
+ * LuaFunction f = globals.load(new StringReader(script), "script");
+ * LuaClosure c = f.checkclosure(); // This may fail if LuaJC is installed.
+ * c.call();
+ * }
+ *
*
*
+ *
* @see LuaValue
* @see LuaFunction
* @see LuaValue#isclosure()
@@ -84,17 +97,20 @@ import org.luaj.vm2.lib.DebugLib.CallFrame;
* @see Globals#compiler
*/
public class LuaClosure extends LuaFunction {
- private static final UpValue[] NOUPVALUES = new UpValue[0];
-
+ private static final UpValue[] NOUPVALUES = {};
+
public final Prototype p;
public UpValue[] upValues;
-
+
final Globals globals;
-
- /** Create a closure around a Prototype with a specific environment.
- * If the prototype has upvalues, the environment will be written into the first upvalue.
- * @param p the Prototype to construct this Closure for.
+
+ /**
+ * Create a closure around a Prototype with a specific environment. If the
+ * prototype has upvalues, the environment will be written into the first
+ * upvalue.
+ *
+ * @param p the Prototype to construct this Closure for.
* @param env the environment to associate with the closure.
*/
public LuaClosure(Prototype p, LuaValue env) {
@@ -102,401 +118,467 @@ public class LuaClosure extends LuaFunction {
this.initupvalue1(env);
globals = env instanceof Globals? (Globals) env: null;
}
-
+
+ @Override
public void initupvalue1(LuaValue env) {
if (p.upvalues == null || p.upvalues.length == 0)
this.upValues = NOUPVALUES;
else {
this.upValues = new UpValue[p.upvalues.length];
- this.upValues[0] = new UpValue(new LuaValue[] {env}, 0);
+ this.upValues[0] = new UpValue(new LuaValue[] { env }, 0);
}
}
-
+ @Override
public boolean isclosure() {
return true;
}
-
+
+ @Override
public LuaClosure optclosure(LuaClosure defval) {
return this;
}
+ @Override
public LuaClosure checkclosure() {
return this;
}
-
+
+ @Override
public String tojstring() {
return "function: " + p.toString();
}
-
+
private LuaValue[] getNewStack() {
int max = p.maxstacksize;
LuaValue[] stack = new LuaValue[max];
System.arraycopy(NILS, 0, stack, 0, max);
return stack;
}
-
+
+ @Override
public final LuaValue call() {
LuaValue[] stack = getNewStack();
- return execute(stack,NONE).arg1();
+ return execute(stack, NONE).arg1();
}
+ @Override
public final LuaValue call(LuaValue arg) {
LuaValue[] stack = getNewStack();
- switch ( p.numparams ) {
- default: stack[0]=arg; return execute(stack,NONE).arg1();
- case 0: return execute(stack,arg).arg1();
+ switch (p.numparams) {
+ default:
+ stack[0] = arg;
+ return execute(stack, NONE).arg1();
+ case 0:
+ return execute(stack, arg).arg1();
}
}
-
+
+ @Override
public final LuaValue call(LuaValue arg1, LuaValue arg2) {
LuaValue[] stack = getNewStack();
- switch ( p.numparams ) {
- default: stack[0]=arg1; stack[1]=arg2; return execute(stack,NONE).arg1();
- case 1: stack[0]=arg1; return execute(stack,arg2).arg1();
- case 0: return execute(stack,p.is_vararg!=0? varargsOf(arg1,arg2): NONE).arg1();
+ switch (p.numparams) {
+ default:
+ stack[0] = arg1;
+ stack[1] = arg2;
+ return execute(stack, NONE).arg1();
+ case 1:
+ stack[0] = arg1;
+ return execute(stack, arg2).arg1();
+ case 0:
+ return execute(stack, p.is_vararg != 0? varargsOf(arg1, arg2): NONE).arg1();
}
}
+ @Override
public final LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
LuaValue[] stack = getNewStack();
- switch ( p.numparams ) {
- default: stack[0]=arg1; stack[1]=arg2; stack[2]=arg3; return execute(stack,NONE).arg1();
- case 2: stack[0]=arg1; stack[1]=arg2; return execute(stack,arg3).arg1();
- case 1: stack[0]=arg1; return execute(stack,p.is_vararg!=0? varargsOf(arg2,arg3): NONE).arg1();
- case 0: return execute(stack,p.is_vararg!=0? varargsOf(arg1,arg2,arg3): NONE).arg1();
+ switch (p.numparams) {
+ default:
+ stack[0] = arg1;
+ stack[1] = arg2;
+ stack[2] = arg3;
+ return execute(stack, NONE).arg1();
+ case 2:
+ stack[0] = arg1;
+ stack[1] = arg2;
+ return execute(stack, arg3).arg1();
+ case 1:
+ stack[0] = arg1;
+ return execute(stack, p.is_vararg != 0? varargsOf(arg2, arg3): NONE).arg1();
+ case 0:
+ return execute(stack, p.is_vararg != 0? varargsOf(arg1, arg2, arg3): NONE).arg1();
}
}
+ @Override
public final Varargs invoke(Varargs varargs) {
return onInvoke(varargs).eval();
}
-
+
+ @Override
public final Varargs onInvoke(Varargs varargs) {
LuaValue[] stack = getNewStack();
- for ( int i=0; i
+ *
+ *
*
* {@code
+ *
+ *
+ *
*
+ * {@code
* LuaValue k = LuaValue.NIL;
* while ( true ) {
* Varargs n = table.next(k);
@@ -53,11 +55,12 @@ import java.util.Vector;
* break;
* LuaValue v = n.arg(2)
* process( k, v )
- * }}
- *
+ * }}
+ *
*
+ *
* @see LuaValue
*/
public class LuaTable extends LuaValue implements Metatable {
- private static final int MIN_HASH_CAPACITY = 2;
- private static final LuaString N = valueOf("n");
-
+ private static final int MIN_HASH_CAPACITY = 2;
+ private static final LuaString N = valueOf("n");
+
/** the array values */
protected LuaValue[] array;
-
+
/** the hash part */
protected Slot[] hash;
-
+
/** the number of hash entries */
protected int hashEntries;
-
+
/** metatable for this table, or null */
protected Metatable m_metatable;
-
+
/** Construct empty table */
public LuaTable() {
array = NOVALS;
hash = NOBUCKETS;
}
-
+
/**
* Construct table with preset capacity.
+ *
* @param narray capacity of array part
- * @param nhash capacity of hash part
+ * @param nhash capacity of hash part
*/
public LuaTable(int narray, int nhash) {
presize(narray, nhash);
@@ -103,155 +110,171 @@ public class LuaTable extends LuaValue implements Metatable {
/**
* Construct table with named and unnamed parts.
- * @param named Named elements in order {@code key-a, value-a, key-b, value-b, ... }
+ *
+ * @param named Named elements in order
+ * {@code key-a, value-a, key-b, value-b, ... }
* @param unnamed Unnamed elements in order {@code value-1, value-2, ... }
* @param lastarg Additional unnamed values beyond {@code unnamed.length}
*/
public LuaTable(LuaValue[] named, LuaValue[] unnamed, Varargs lastarg) {
- int nn = (named!=null? named.length: 0);
- int nu = (unnamed!=null? unnamed.length: 0);
- int nl = (lastarg!=null? lastarg.narg(): 0);
+ int nn = named != null? named.length: 0;
+ int nu = unnamed != null? unnamed.length: 0;
+ int nl = lastarg != null? lastarg.narg(): 0;
presize(nu+nl, nn>>1);
- for ( int i=0; i
+ * {
+ * @code
+ * LuaValue a = LuaValue.valueOf(5);
+ * LuaValue b = LuaValue.valueOf(4);
+ * LuaValue c = a.div(b);
+ * }
+ *
+ *
+ * Note that in this example, c will be a {@link LuaDouble}, but would be a
+ * {@link LuaInteger} if the value of a were changed to 8, say. In general the
+ * value of c in practice will vary depending on both the types and values of a
+ * and b as well as any metatable/metatag processing that occurs.
+ *
+ * {
+ * @code
+ * LuaValue globals = JsePlatform.standardGlobals();
+ * LuaValue sqrt = globals.get("math").get("sqrt");
+ * LuaValue print = globals.get("print");
+ * LuaValue d = sqrt.call(a);
+ * print.call(LuaValue.valueOf("sqrt(5):"), a);
+ * }
+ *
+ *
+ * {
+ * @code
+ * LuaValue modf = globals.get("math").get("modf");
+ * Varargs r = modf.invoke(d);
+ * print.call(r.arg(1), r.arg(2));
+ * }
+ *
+ *
+ * {@code
+ * LoadState.load( new FileInputStream("main.lua"), "main.lua", globals ).call();
+ * }
+ *
+ *
+ * {@code
+ * globals.get("require").call(LuaValue.valueOf("main"));
+ * }
+ *
+ *
+ * For this to work the file must be in the current directory, or in the class
+ * path, dependening on the platform. See
+ * {@link org.luaj.vm2.lib.jse.JsePlatform} and
+ * {@link org.luaj.vm2.lib.jme.JmePlatform} for details.
+ *
+ *
+ *
+ * {@code
+ * LuaValue k = LuaValue.NIL;
+ * while ( true ) {
+ * Varargs n = table.next(k);
+ * if ( (k = n.arg1()).isnil() )
+ * break;
+ * LuaValue v = n.arg(2)
+ * process( k, v )
+ * }}
+ *
+ *
+ * @param index {@link LuaInteger} value identifying a key to start from, or
+ * {@link #NIL} to start at the beginning
+ * @return {@link Varargs} containing {key,value} for the next entry, or
+ * {@link #NIL} if there are no more.
+ * @throws LuaError if {@code this} is not a table, or the supplied key is
+ * invalid.
+ * @see LuaTable
+ * @see #inext(LuaValue)
+ * @see #valueOf(int)
+ * @see Varargs#arg1()
+ * @see Varargs#arg(int)
+ * @see #isnil()
+ */
+ public Varargs next(LuaValue index) { return typerror("table"); }
+
+ /**
+ * Find the next integer-key,value pair if {@code this} is a table, return
+ * {@link #NIL} if there are no more, or throw a {@link LuaError} if not a
+ * table.
+ *
+ * {@code
+ * LuaValue k = LuaValue.NIL;
+ * while ( true ) {
+ * Varargs n = table.inext(k);
+ * if ( (k = n.arg1()).isnil() )
+ * break;
+ * LuaValue v = n.arg(2)
+ * process( k, v )
+ * }
+ * }
+ *
+ *
+ * @param index {@link LuaInteger} value identifying a key to start from, or
+ * {@link #NIL} to start at the beginning
+ * @return {@link Varargs} containing {@code (key,value)} for the next
+ * entry, or {@link #NONE} if there are no more.
+ * @throws LuaError if {@code this} is not a table, or the supplied key is
+ * invalid.
+ * @see LuaTable
+ * @see #next(LuaValue)
+ * @see #valueOf(int)
+ * @see Varargs#arg1()
+ * @see Varargs#arg(int)
+ * @see #isnil()
+ */
+ public Varargs inext(LuaValue index) { return typerror("table"); }
+
+ /**
+ * Load a library instance by calling it with and empty string as the
+ * modname, and this Globals as the environment. This is normally used to
+ * iniitalize the library instance and which may install itself into these
+ * globals.
+ *
+ * @param library The callable {@link LuaValue} to load into {@code this}
+ * @return {@link LuaValue} returned by the initialization call.
+ */
+ public LuaValue load(LuaValue library) { return library.call(EMPTYSTRING, this); }
+
+ // varargs references
+ @Override
+ public LuaValue arg(int index) { return index == 1? this: NIL; }
+
+ @Override
+ public int narg() { return 1; }
+
+ @Override
+ public LuaValue arg1() { return this; }
+
+ /**
+ * Get the metatable for this {@link LuaValue}
+ *
+ * {
+ * @code
+ * Globals globals = JsePlatform.standardGlobals();
+ * globals.load(new StringReader("print 'hello'"), "main.lua").call();
+ * }
+ *
+ *
+ *
+ * {
+ * @code
+ * InputStream is = new ByteArrayInputStream("print('hello,world')".getBytes());
+ * Prototype p = LuaC.instance.compile(is, "script");
+ * }
+ *
+ *
+ * To simplify loading, the
+ * {@link Globals#compilePrototype(java.io.InputStream, String)} method may be
+ * used:
+ *
+ *
+ * {
+ * @code
+ * Prototype p = globals.compileProtoytpe(is, "script");
+ * }
+ *
+ *
+ * It may also be loaded from a {@link java.io.Reader} via
+ * {@link Globals#compilePrototype(java.io.Reader, String)}:
+ *
+ *
+ * {
+ * @code
+ * Prototype p = globals.compileProtoytpe(new StringReader(script), "script");
+ * }
+ *
+ *
+ * To un-dump a binary file known to be a binary lua file that has been dumped
+ * to a string, the {@link Globals.Undumper} interface may be used:
+ *
+ *
+ * {
+ * @code
+ * FileInputStream lua_binary_file = new FileInputStream("foo.lc"); // Known to be compiled lua.
+ * Prototype p = globals.undumper.undump(lua_binary_file, "foo.lua");
+ * }
+ *
+ *
+ * To execute the code represented by the {@link Prototype} it must be supplied
+ * to the constructor of a {@link LuaClosure}:
+ *
+ *
+ * {
+ * @code
+ * Globals globals = JsePlatform.standardGlobals();
+ * LuaClosure f = new LuaClosure(p, globals);
+ * f.call();
+ * }
+ *
+ *
+ * To simplify the debugging of prototype values, the contents may be printed
+ * using {@link Print#print}:
+ *
+ *
+ * {@code
+ * Print.print(p);
+ * }
+ *
+ * {@code
- * Globals globals = JsePlatform.standardGlobals();
- * Prototype p = globals.compilePrototype(new StringReader("print('hello, world')"), "main.lua");
- * ByteArrayOutputStream o = new ByteArrayOutputStream();
- * DumpState.dump(p, o, false);
- * byte[] lua_binary_file_bytes = o.toByteArray();
- * }
- *
+ *
+ *
+ * {
+ * @code
+ * Globals globals = JsePlatform.standardGlobals();
+ * Prototype p = globals.compilePrototype(new StringReader("print('hello, world')"), "main.lua");
+ * ByteArrayOutputStream o = new ByteArrayOutputStream();
+ * DumpState.dump(p, o, false);
+ * byte[] lua_binary_file_bytes = o.toByteArray();
+ * }
+ *
+ *
* The {@link LoadState} may be used directly to undump these bytes:
- * {@code
+ *
+ *
+ *
+ *
* More commonly, the {@link Globals#undumper} may be used to undump them:
- *
+ * {@code
* Prototypep = LoadState.instance.undump(new ByteArrayInputStream(lua_binary_file_bytes), "main.lua");
* LuaClosure c = new LuaClosure(p, globals);
* c.call();
- * }
- *
- *
+ * }
+ * {@code
- * Prototype p = globals.loadPrototype(new ByteArrayInputStream(lua_binary_file_bytes), "main.lua", "b");
- * LuaClosure c = new LuaClosure(p, globals);
- * c.call();
- * }
- *
+ *
+ *
+ * {
+ * @code
+ * Prototype p = globals.loadPrototype(new ByteArrayInputStream(lua_binary_file_bytes), "main.lua", "b");
+ * LuaClosure c = new LuaClosure(p, globals);
+ * c.call();
+ * }
+ *
+ *
* @see luac
* @see LoadState
* @see Globals
@@ -71,33 +83,39 @@ public class DumpState {
/** set true to allow integer compilation */
public static boolean ALLOW_INTEGER_CASTING = false;
-
- /** format corresponding to non-number-patched lua, all numbers are floats or doubles */
- public static final int NUMBER_FORMAT_FLOATS_OR_DOUBLES = 0;
+
+ /**
+ * format corresponding to non-number-patched lua, all numbers are floats or
+ * doubles
+ */
+ public static final int NUMBER_FORMAT_FLOATS_OR_DOUBLES = 0;
/** format corresponding to non-number-patched lua, all numbers are ints */
- public static final int NUMBER_FORMAT_INTS_ONLY = 1;
-
- /** format corresponding to number-patched lua, all numbers are 32-bit (4 byte) ints */
- public static final int NUMBER_FORMAT_NUM_PATCH_INT32 = 4;
-
+ public static final int NUMBER_FORMAT_INTS_ONLY = 1;
+
+ /**
+ * format corresponding to number-patched lua, all numbers are 32-bit (4
+ * byte) ints
+ */
+ public static final int NUMBER_FORMAT_NUM_PATCH_INT32 = 4;
+
/** default number format */
public static final int NUMBER_FORMAT_DEFAULT = NUMBER_FORMAT_FLOATS_OR_DOUBLES;
// header fields
- private boolean IS_LITTLE_ENDIAN = true;
- private int NUMBER_FORMAT = NUMBER_FORMAT_DEFAULT;
- private int SIZEOF_LUA_NUMBER = 8;
- private static final int SIZEOF_INT = 4;
- private static final int SIZEOF_SIZET = 4;
+ private boolean IS_LITTLE_ENDIAN = true;
+ private int NUMBER_FORMAT = NUMBER_FORMAT_DEFAULT;
+ private int SIZEOF_LUA_NUMBER = 8;
+ private static final int SIZEOF_INT = 4;
+ private static final int SIZEOF_SIZET = 4;
private static final int SIZEOF_INSTRUCTION = 4;
DataOutputStream writer;
- boolean strip;
- int status;
+ boolean strip;
+ int status;
public DumpState(OutputStream w, boolean strip) {
- this.writer = new DataOutputStream( w );
+ this.writer = new DataOutputStream(w);
this.strip = strip;
this.status = 0;
}
@@ -107,58 +125,58 @@ public class DumpState {
}
void dumpChar(int b) throws IOException {
- writer.write( b );
+ writer.write(b);
}
void dumpInt(int x) throws IOException {
- if ( IS_LITTLE_ENDIAN ) {
- writer.writeByte(x&0xff);
- writer.writeByte((x>>8)&0xff);
- writer.writeByte((x>>16)&0xff);
- writer.writeByte((x>>24)&0xff);
+ if (IS_LITTLE_ENDIAN) {
+ writer.writeByte(x & 0xff);
+ writer.writeByte(x>>8 & 0xff);
+ writer.writeByte(x>>16 & 0xff);
+ writer.writeByte(x>>24 & 0xff);
} else {
writer.writeInt(x);
}
}
-
+
void dumpString(LuaString s) throws IOException {
final int len = s.len().toint();
- dumpInt( len+1 );
- s.write( writer, 0, len );
- writer.write( 0 );
+ dumpInt(len+1);
+ s.write(writer, 0, len);
+ writer.write(0);
}
-
+
void dumpDouble(double d) throws IOException {
long l = Double.doubleToLongBits(d);
- if ( IS_LITTLE_ENDIAN ) {
- dumpInt( (int) l );
- dumpInt( (int) (l>>32) );
+ if (IS_LITTLE_ENDIAN) {
+ dumpInt((int) l);
+ dumpInt((int) (l>>32));
} else {
writer.writeLong(l);
}
}
- void dumpCode( final Prototype f ) throws IOException {
+ void dumpCode(final Prototype f) throws IOException {
final int[] code = f.code;
int n = code.length;
- dumpInt( n );
- for ( int i=0; i {@code
- * Globals globals = JsePlatform.standardGlobals();
- * globals.load(new StringReader("print 'hello'"), "main.lua" ).call();
- * }
- *
+ * Implements the {@link org.luaj.vm2.Globals.Compiler} interface for loading
+ * initialized chunks, which is an interface common to lua bytecode compiling
+ * and java bytecode compiling.
+ *
+ *
+ * {
+ * @code
+ * Globals globals = JsePlatform.standardGlobals();
+ * globals.load(new StringReader("print 'hello'"), "main.lua").call();
+ * }
+ *
+ *
* To load the LuaC compiler manually, use the install method:
- * {@code
+ *
+ *
+ *
* @see #install(Globals)
* @see Globals#compiler
* @see Globals#loader
@@ -76,10 +83,11 @@ public class LuaC extends Constants implements Globals.Compiler, Globals.Loader
/** A sharable instance of the LuaC compiler. */
public static final LuaC instance = new LuaC();
-
- /** Install the compiler so that LoadState will first
- * try to use it when handed bytes that are
- * not already a compiled lua chunk.
+
+ /**
+ * Install the compiler so that LoadState will first try to use it when
+ * handed bytes that are not already a compiled lua chunk.
+ *
* @param globals the Globals into which this is to be installed.
*/
public static void install(Globals globals) {
@@ -89,69 +97,77 @@ public class LuaC extends Constants implements Globals.Compiler, Globals.Loader
protected LuaC() {}
- /** Compile lua source into a Prototype.
- * @param stream InputStream representing the text source conforming to lua source syntax.
+ /**
+ * Compile lua source into a Prototype.
+ *
+ * @param stream InputStream representing the text source conforming to
+ * lua source syntax.
* @param chunkname String name of the chunk to use.
* @return Prototype representing the lua chunk for this source.
* @throws IOException
*/
+ @Override
public Prototype compile(InputStream stream, String chunkname) throws IOException {
- return (new CompileState()).luaY_parser(stream, chunkname);
+ return new CompileState().luaY_parser(stream, chunkname);
}
+ @Override
public LuaFunction load(Prototype prototype, String chunkname, LuaValue env) throws IOException {
return new LuaClosure(prototype, env);
}
- /** @deprecated
- * Use Globals.load(InputString, String, String) instead,
- * or LuaC.compile(InputStream, String) and construct LuaClosure directly.
+ /**
+ * @deprecated Use Globals.load(InputString, String, String) instead, or
+ * LuaC.compile(InputStream, String) and construct LuaClosure
+ * directly.
*/
+ @Deprecated
public LuaValue load(InputStream stream, String chunkname, Globals globals) throws IOException {
return new LuaClosure(compile(stream, chunkname), globals);
}
static class CompileState {
- int nCcalls = 0;
- private Hashtable strings = new Hashtable();
+ int nCcalls = 0;
+ private final Hashtable strings = new Hashtable();
+
protected CompileState() {}
-
+
/** Parse the input */
- Prototype luaY_parser(InputStream z, String name) throws IOException{
+ Prototype luaY_parser(InputStream z, String name) throws IOException {
LexState lexstate = new LexState(this, z);
FuncState funcstate = new FuncState();
// lexstate.buff = buff;
lexstate.fs = funcstate;
- lexstate.setinput(this, z.read(), z, (LuaString) LuaValue.valueOf(name) );
+ lexstate.setinput(this, z.read(), z, LuaValue.valueOf(name));
/* main func. is always vararg */
funcstate.f = new Prototype();
- funcstate.f.source = (LuaString) LuaValue.valueOf(name);
+ funcstate.f.source = LuaValue.valueOf(name);
lexstate.mainfunc(funcstate);
- LuaC._assert (funcstate.prev == null);
+ Constants._assert(funcstate.prev == null);
/* all scopes should be correctly finished */
- LuaC._assert (lexstate.dyd == null
- || (lexstate.dyd.n_actvar == 0 && lexstate.dyd.n_gt == 0 && lexstate.dyd.n_label == 0));
+ Constants._assert(lexstate.dyd == null
+ || lexstate.dyd.n_actvar == 0 && lexstate.dyd.n_gt == 0 && lexstate.dyd.n_label == 0);
return funcstate.f;
}
-
+
// look up and keep at most one copy of each string
public LuaString newTString(String s) {
return cachedLuaString(LuaString.valueOf(s));
}
-
+
// look up and keep at most one copy of each string
public LuaString newTString(LuaString s) {
return cachedLuaString(s);
}
-
+
public LuaString cachedLuaString(LuaString s) {
LuaString c = (LuaString) strings.get(s);
- if (c != null)
+ if (c != null)
return c;
strings.put(s, s);
return s;
}
-
+
public String pushfstring(String string) {
return string;
}
diff --git a/src/core/org/luaj/vm2/lib/BaseLib.java b/luaj-core/src/main/java/org/luaj/vm2/lib/BaseLib.java
similarity index 75%
rename from src/core/org/luaj/vm2/lib/BaseLib.java
rename to luaj-core/src/main/java/org/luaj/vm2/lib/BaseLib.java
index fb86825b..72d20aa2 100644
--- a/src/core/org/luaj/vm2/lib/BaseLib.java
+++ b/luaj-core/src/main/java/org/luaj/vm2/lib/BaseLib.java
@@ -1,485 +1,548 @@
-/*******************************************************************************
-* Copyright (c) 2009 Luaj.org. All rights reserved.
-*
-* Permission is hereby granted, free of charge, to any person obtaining a copy
-* of this software and associated documentation files (the "Software"), to deal
-* in the Software without restriction, including without limitation the rights
-* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-* copies of the Software, and to permit persons to whom the Software is
-* furnished to do so, subject to the following conditions:
-*
-* The above copyright notice and this permission notice shall be included in
-* all copies or substantial portions of the Software.
-*
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-* THE SOFTWARE.
-******************************************************************************/
-package org.luaj.vm2.lib;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.luaj.vm2.Globals;
-import org.luaj.vm2.Lua;
-import org.luaj.vm2.LuaError;
-import org.luaj.vm2.LuaString;
-import org.luaj.vm2.LuaTable;
-import org.luaj.vm2.LuaThread;
-import org.luaj.vm2.LuaValue;
-import org.luaj.vm2.Varargs;
-
-/**
- * Subclass of {@link LibFunction} which implements the lua basic library functions.
- *
+ * {@code
* LuaC.install(globals);
- * }
- *
+ * }
+ * {@code
- * Globals globals = JsePlatform.standardGlobals();
- * globals.get("print").call(LuaValue.valueOf("hello, world"));
- * }
- * {@code
- * Globals globals = new Globals();
- * globals.load(new JseBaseLib());
- * globals.get("print").call(LuaValue.valueOf("hello, world"));
- * }
- * Doing so will ensure the library is properly initialized
- * and loaded into the globals table.
- *
+ * {
+ * @code
+ * Globals globals = JsePlatform.standardGlobals();
+ * globals.get("print").call(LuaValue.valueOf("hello, world"));
+ * }
+ *
+ *
+ * {
+ * @code
+ * Globals globals = new Globals();
+ * globals.load(new JseBaseLib());
+ * globals.get("print").call(LuaValue.valueOf("hello, world"));
+ * }
+ *
+ *
+ * Doing so will ensure the library is properly initialized and loaded into the
+ * globals table.
+ * {@code
- * Globals globals = JsePlatform.standardGlobals();
- * System.out.println( globals.get("bit32").get("bnot").call( LuaValue.valueOf(2) ) );
- * }
+ * {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
+ * {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
+ *
+ *
+ * {
+ * @code
+ * Globals globals = JsePlatform.standardGlobals();
+ * System.out.println(globals.get("bit32").get("bnot").call(LuaValue.valueOf(2)));
+ * }
+ *
* {@code
- * Globals globals = new Globals();
- * globals.load(new JseBaseLib());
- * globals.load(new PackageLib());
- * globals.load(new Bit32Lib());
- * System.out.println( globals.get("bit32").get("bnot").call( LuaValue.valueOf(2) ) );
- * }
+ * To instantiate and use it directly, link it into your globals table via
+ * {@link LuaValue#load(LuaValue)} using code such as:
+ *
+ *
+ * {
+ * @code
+ * Globals globals = new Globals();
+ * globals.load(new JseBaseLib());
+ * globals.load(new PackageLib());
+ * globals.load(new Bit32Lib());
+ * System.out.println(globals.get("bit32").get("bnot").call(LuaValue.valueOf(2)));
+ * }
+ *
* {@code
- * Globals globals = JsePlatform.standardGlobals();
- * System.out.println( globals.get("coroutine").get("running").call() );
- * }
+ * {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
+ * {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
+ *
+ *
+ * {
+ * @code
+ * Globals globals = JsePlatform.standardGlobals();
+ * System.out.println(globals.get("coroutine").get("running").call());
+ * }
+ *
* {@code
- * Globals globals = new Globals();
- * globals.load(new JseBaseLib());
- * globals.load(new PackageLib());
- * globals.load(new CoroutineLib());
- * System.out.println( globals.get("coroutine").get("running").call() );
- * }
+ * To instantiate and use it directly, link it into your globals table via
+ * {@link LuaValue#load(LuaValue)} using code such as:
+ *
+ *
+ * {
+ * @code
+ * Globals globals = new Globals();
+ * globals.load(new JseBaseLib());
+ * globals.load(new PackageLib());
+ * globals.load(new CoroutineLib());
+ * System.out.println(globals.get("coroutine").get("running").call());
+ * }
+ *
* {@code
- * Globals globals = JsePlatform.debugGlobals();
- * System.out.println( globals.get("debug").get("traceback").call() );
- * }
+ *
+ *
+ * {
+ * @code
+ * Globals globals = JsePlatform.debugGlobals();
+ * System.out.println(globals.get("debug").get("traceback").call());
+ * }
+ *
* {@code
- * Globals globals = new Globals();
- * globals.load(new JseBaseLib());
- * globals.load(new PackageLib());
- * globals.load(new DebugLib());
- * System.out.println( globals.get("debug").get("traceback").call() );
- * }
+ * To instantiate and use it directly, link it into your globals table via
+ * {@link LuaValue#load(LuaValue)} using code such as:
+ *
+ *
+ * {
+ * @code
+ * Globals globals = new Globals();
+ * globals.load(new JseBaseLib());
+ * globals.load(new PackageLib());
+ * globals.load(new DebugLib());
+ * System.out.println(globals.get("debug").get("traceback").call());
+ * }
+ *
* {@code
- * Globals globals = JsePlatform.standardGlobals();
- * globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
- * }
- * In this example the platform-specific {@link org.luaj.vm2.lib.jse.JseIoLib} library will be loaded, which will include
- * the base functionality provided by this class, whereas the {@link org.luaj.vm2.lib.jse.JsePlatform} would load the
- * {@link org.luaj.vm2.lib.jse.JseIoLib}.
+ * {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
+ * {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
+ *
+ *
+ * {
+ * @code
+ * Globals globals = JsePlatform.standardGlobals();
+ * globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
+ * }
+ *
+ *
+ * In this example the platform-specific {@link org.luaj.vm2.lib.jse.JseIoLib}
+ * library will be loaded, which will include the base functionality provided by
+ * this class, whereas the {@link org.luaj.vm2.lib.jse.JsePlatform} would load
+ * the {@link org.luaj.vm2.lib.jse.JseIoLib}.
* {@code
- * Globals globals = new Globals();
- * globals.load(new JseBaseLib());
- * globals.load(new PackageLib());
- * globals.load(new OsLib());
- * globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
- * }
+ * To instantiate and use it directly, link it into your globals table via
+ * {@link LuaValue#load(LuaValue)} using code such as:
+ *
+ *
+ * {
+ * @code
+ * Globals globals = new Globals();
+ * globals.load(new JseBaseLib());
+ * globals.load(new PackageLib());
+ * globals.load(new OsLib());
+ * globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
+ * }
+ *
*
*
* {@code
+ *
+ *
+ *
+ * The default constructor is used to instantiate the library in response to
+ * {@code require 'hyperbolic'} statement, provided it is on Java"s class
+ * path. This instance is then invoked with 2 arguments: the name supplied to
+ * require(), and the environment for this function. The library may ignore
+ * these, or use them to leave side effects in the global environment, for
+ * example. In the previous example, two functions are created, 'sinh', and
+ * 'cosh', and placed into a global table called 'hyperbolic' using the supplied
+ * 'env' argument.
*
+ * {@code
* import org.luaj.vm2.LuaValue;
* import org.luaj.vm2.lib.*;
- *
+ *
* public class hyperbolic extends TwoArgFunction {
*
* public hyperbolic() {}
@@ -78,25 +80,29 @@ import org.luaj.vm2.Varargs;
* return LuaValue.valueOf(Math.sinh(x.checkdouble()));
* }
* }
- *
+ *
* static class cosh extends OneArgFunction {
* public LuaValue call(LuaValue x) {
* return LuaValue.valueOf(Math.cosh(x.checkdouble()));
* }
* }
*}
- *}
- * The default constructor is used to instantiate the library
- * in response to {@code require 'hyperbolic'} statement,
- * provided it is on Java"s class path.
- * This instance is then invoked with 2 arguments: the name supplied to require(),
- * and the environment for this function. The library may ignore these, or use
- * them to leave side effects in the global environment, for example.
- * In the previous example, two functions are created, 'sinh', and 'cosh', and placed
- * into a global table called 'hyperbolic' using the supplied 'env' argument.
+ *}
+ * {@code
+ *
+ *
*
+ * {@code
* local t = require('hyperbolic')
* print( 't', t )
* print( 'hyperbolic', hyperbolic )
@@ -105,118 +111,153 @@ import org.luaj.vm2.Varargs;
* end
* print( 'sinh(.5)', hyperbolic.sinh(.5) )
* print( 'cosh(.5)', hyperbolic.cosh(.5) )
- * }
+ * }
+ * {@code
+ *
+ *
*
+ * {@code
* t table: 3dbbd23f
* hyperbolic table: 3dbbd23f
* k,v cosh function: 3dbbd128
* k,v sinh function: 3dbbd242
* sinh(.5) 0.5210953
* cosh(.5) 1.127626
- * }
+ * }
+ *
*
* {@code
- * Globals globals = JsePlatform.standardGlobals();
- * System.out.println( globals.get("math").get("sqrt").call( LuaValue.valueOf(2) ) );
- * }
- * When using {@link org.luaj.vm2.lib.jse.JsePlatform} as in this example,
- * the subclass {@link org.luaj.vm2.lib.jse.JseMathLib} will
- * be included, which also includes this base functionality.
+ *
+ *
+ * {
+ * @code
+ * Globals globals = JsePlatform.standardGlobals();
+ * System.out.println(globals.get("math").get("sqrt").call(LuaValue.valueOf(2)));
+ * }
+ *
+ *
+ * When using {@link org.luaj.vm2.lib.jse.JsePlatform} as in this example, the
+ * subclass {@link org.luaj.vm2.lib.jse.JseMathLib} will be included, which also
+ * includes this base functionality.
* {@code
- * Globals globals = new Globals();
- * globals.load(new JseBaseLib());
- * globals.load(new PackageLib());
- * globals.load(new MathLib());
- * System.out.println( globals.get("math").get("sqrt").call( LuaValue.valueOf(2) ) );
- * }
- * Doing so will ensure the library is properly initialized
- * and loaded into the globals table.
+ * To instantiate and use it directly, link it into your globals table via
+ * {@link LuaValue#load(LuaValue)} using code such as:
+ *
+ *
+ * {
+ * @code
+ * Globals globals = new Globals();
+ * globals.load(new JseBaseLib());
+ * globals.load(new PackageLib());
+ * globals.load(new MathLib());
+ * System.out.println(globals.get("math").get("sqrt").call(LuaValue.valueOf(2)));
+ * }
+ *
+ *
+ * Doing so will ensure the library is properly initialized and loaded into the
+ * globals table.
*
+ *
+ *
+ * {
+ * @code
+ * Globals globals = JsePlatform.standardGlobals();
+ * System.out.println(globals.get("os").get("time").call());
+ * }
+ *
+ *
+ * In this example the platform-specific {@link org.luaj.vm2.lib.jse.JseOsLib}
+ * library will be loaded, which will include the base functionality provided by
+ * this class.
+ *
+ * {
+ * @code
+ * Globals globals = new Globals();
+ * globals.load(new JseBaseLib());
+ * globals.load(new PackageLib());
+ * globals.load(new OsLib());
+ * System.out.println(globals.get("os").get("time").call());
+ * }
+ *
+ * Lua Environment Variables
- * The following variables are available to lua scrips when this library has been loaded:
+ * Subclass of {@link LibFunction} which implements the lua standard package and
+ * module library functions.
+ *
+ * Lua Environment Variables
The following variables are available to
+ * lua scrips when this library has been loaded:
*
*
- *
- * "package.loaded" Lua table of loaded modules.
* "package.path" Search path for lua scripts.
- * "package.preload" Lua table of uninitialized preload functions.
- * "package.searchers" Lua table of functions that search for object to load.
+ * "package.preload" Lua table of uninitialized preload
+ * functions.
+ * "package.searchers" Lua table of functions that search for
+ * object to load.
* Java Environment Variables
- * These Java environment variables affect the library behavior:
+ *
+ * Java Environment Variables
These Java environment variables affect
+ * the library behavior:
*
- *
- *
- * "luaj.package.path" Initial value for "package.path". Default value is "?.lua"
+ * "luaj.package.path" Initial value for
+ * "package.path". Default value is "?.lua"
* Loading
- * Typically, this library is included as part of a call to either
- * {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
- * {@code
+ *
+ *
* Loading
Typically, this library is included as part of a call to
+ * either {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
+ * {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
+ *
+ *
+ * {@code
* Globals globals = JsePlatform.standardGlobals();
* System.out.println( globals.get("require").call"foo") );
- * }
+ * }
+ * {@code
- * Globals globals = new Globals();
- * globals.load(new JseBaseLib());
- * globals.load(new PackageLib());
- * System.out.println( globals.get("require").call("foo") );
- * }
- * Limitations
- * This library has been implemented to match as closely as possible the behavior in the corresponding library in C.
- * However, the default filesystem search semantics are different and delegated to the bas library
- * as outlined in the {@link BaseLib} and {@link org.luaj.vm2.lib.jse.JseBaseLib} documentation.
+ * To instantiate and use it directly, link it into your globals table via
+ * {@link LuaValue#load(LuaValue)} using code such as:
+ *
+ *
+ * {
+ * @code
+ * Globals globals = new Globals();
+ * globals.load(new JseBaseLib());
+ * globals.load(new PackageLib());
+ * System.out.println(globals.get("require").call("foo"));
+ * }
+ *
+ *
+ * Limitations
This library has been implemented to match as closely as
+ * possible the behavior in the corresponding library in C. However, the default
+ * filesystem search semantics are different and delegated to the bas library as
+ * outlined in the {@link BaseLib} and {@link org.luaj.vm2.lib.jse.JseBaseLib}
+ * documentation.
* "luaj.package.path", and is "?.lua" by default. */
+ /**
+ * The default value to use for package.path. This can be set with the
+ * system property "luaj.package.path", and is
+ * "?.lua" by default.
+ */
public static final String DEFAULT_LUA_PATH;
static {
String path = null;
@@ -95,41 +113,52 @@ public class PackageLib extends TwoArgFunction {
DEFAULT_LUA_PATH = path;
}
- static final LuaString _LOADED = valueOf("loaded");
- private static final LuaString _LOADLIB = valueOf("loadlib");
- static final LuaString _PRELOAD = valueOf("preload");
- static final LuaString _PATH = valueOf("path");
- static final LuaString _SEARCHPATH = valueOf("searchpath");
- static final LuaString _SEARCHERS = valueOf("searchers");
-
+ static final LuaString _LOADED = valueOf("loaded");
+ private static final LuaString _LOADLIB = valueOf("loadlib");
+ static final LuaString _PRELOAD = valueOf("preload");
+ static final LuaString _PATH = valueOf("path");
+ static final LuaString _SEARCHPATH = valueOf("searchpath");
+ static final LuaString _SEARCHERS = valueOf("searchers");
+ static final LuaString _SEEALL = valueOf("seeall");
+
/** The globals that were used to load this library. */
Globals globals;
/** The table for this package. */
LuaTable package_;
-
+
/** Loader that loads from {@code preload} table if found there */
public preload_searcher preload_searcher;
-
- /** Loader that loads as a lua script using the lua path currently in {@link path} */
+
+ /**
+ * Loader that loads as a lua script using the lua path currently in
+ * {@link path}
+ */
public lua_searcher lua_searcher;
-
- /** Loader that loads as a Java class. Class must have public constructor and be a LuaValue. */
+
+ /**
+ * Loader that loads as a Java class. Class must have public constructor and
+ * be a LuaValue.
+ */
public java_searcher java_searcher;
- private static final LuaString _SENTINEL = valueOf("\u0001");
-
- private static final String FILE_SEP = System.getProperty("file.separator");
+ private static final LuaString _SENTINEL = valueOf("\u0001");
+
+ private static final String FILE_SEP = FileSystems.getDefault().getSeparator();
public PackageLib() {}
- /** Perform one-time initialization on the library by adding package functions
- * to the supplied environment, and returning it as the return value.
- * It also creates the package.preload and package.loaded tables for use by
- * other libraries.
+ /**
+ * Perform one-time initialization on the library by adding package
+ * functions to the supplied environment, and returning it as the return
+ * value. It also creates the package.preload and package.loaded tables for
+ * use by other libraries.
+ *
* @param modname the module name supplied if this is loaded via 'require'.
- * @param env the environment to load into, typically a Globals instance.
+ * @param env the environment to load into, typically a Globals
+ * instance.
*/
+ @Override
public LuaValue call(LuaValue modname, LuaValue env) {
globals = env.checkglobals();
globals.set("require", new require());
@@ -139,10 +168,11 @@ public class PackageLib extends TwoArgFunction {
package_.set(_PATH, LuaValue.valueOf(DEFAULT_LUA_PATH));
package_.set(_LOADLIB, new loadlib());
package_.set(_SEARCHPATH, new searchpath());
+ package_.set(_SEEALL, new seeall());
LuaTable searchers = new LuaTable();
searchers.set(1, preload_searcher = new preload_searcher());
- searchers.set(2, lua_searcher = new lua_searcher());
- searchers.set(3, java_searcher = new java_searcher());
+ searchers.set(2, lua_searcher = new lua_searcher());
+ searchers.set(3, java_searcher = new java_searcher());
package_.set(_SEARCHERS, searchers);
package_.set("config", FILE_SEP + "\n;\n?\n!\n-\n");
package_.get(_LOADED).set("package", package_);
@@ -150,226 +180,248 @@ public class PackageLib extends TwoArgFunction {
globals.package_ = this;
return env;
}
-
+
/** Allow packages to mark themselves as loaded */
public void setIsLoaded(String name, LuaTable value) {
package_.get(_LOADED).set(name, value);
}
-
- /** Set the lua path used by this library instance to a new value.
- * Merely sets the value of {@link path} to be used in subsequent searches. */
- public void setLuaPath( String newLuaPath ) {
+ /**
+ * Set the lua path used by this library instance to a new value. Merely
+ * sets the value of {@link path} to be used in subsequent searches.
+ */
+ public void setLuaPath(String newLuaPath) {
package_.set(_PATH, LuaValue.valueOf(newLuaPath));
}
-
+
+ @Override
public String tojstring() {
return "package";
}
-
+
// ======================== Package loading =============================
/**
* require (modname)
- *
- * Loads the given module. The function starts by looking into the package.loaded table
- * to determine whether modname is already loaded. If it is, then require returns the value
- * stored at package.loaded[modname]. Otherwise, it tries to find a loader for the module.
- *
- * To find a loader, require is guided by the package.searchers sequence.
- * By changing this sequence, we can change how require looks for a module.
- * The following explanation is based on the default configuration for package.searchers.
- *
- * First require queries package.preload[modname]. If it has a value, this value
- * (which should be a function) is the loader. Otherwise require searches for a Lua loader using
- * the path stored in package.path. If that also fails, it searches for a Java loader using
- * the classpath, using the public default constructor, and casting the instance to LuaFunction.
- *
- * Once a loader is found, require calls the loader with two arguments: modname and an extra value
- * dependent on how it got the loader. If the loader came from a file, this extra value is the file name.
- * If the loader is a Java instance of LuaFunction, this extra value is the environment.
- * If the loader returns any non-nil value, require assigns the returned value to package.loaded[modname].
- * If the loader does not return a non-nil value and has not assigned any value to package.loaded[modname],
- * then require assigns true to this entry.
- * In any case, require returns the final value of package.loaded[modname].
- *
- * If there is any error loading or running the module, or if it cannot find any loader for the module,
- * then require raises an error.
+ *
+ * Loads the given module. The function starts by looking into the
+ * package.loaded table to determine whether modname is already loaded. If
+ * it is, then require returns the value stored at package.loaded[modname].
+ * Otherwise, it tries to find a loader for the module.
+ *
+ * To find a loader, require is guided by the package.searchers sequence. By
+ * changing this sequence, we can change how require looks for a module. The
+ * following explanation is based on the default configuration for
+ * package.searchers.
+ *
+ * First require queries package.preload[modname]. If it has a value, this
+ * value (which should be a function) is the loader. Otherwise require
+ * searches for a Lua loader using the path stored in package.path. If that
+ * also fails, it searches for a Java loader using the classpath, using the
+ * public default constructor, and casting the instance to LuaFunction.
+ *
+ * Once a loader is found, require calls the loader with two arguments:
+ * modname and an extra value dependent on how it got the loader. If the
+ * loader came from a file, this extra value is the file name. If the loader
+ * is a Java instance of LuaFunction, this extra value is the environment.
+ * If the loader returns any non-nil value, require assigns the returned
+ * value to package.loaded[modname]. If the loader does not return a non-nil
+ * value and has not assigned any value to package.loaded[modname], then
+ * require assigns true to this entry. In any case, require returns the
+ * final value of package.loaded[modname].
+ *
+ * If there is any error loading or running the module, or if it cannot find
+ * any loader for the module, then require raises an error.
*/
public class require extends OneArgFunction {
- public LuaValue call( LuaValue arg ) {
+ @Override
+ public LuaValue call(LuaValue arg) {
LuaString name = arg.checkstring();
LuaValue loaded = package_.get(_LOADED);
LuaValue result = loaded.get(name);
- if ( result.toboolean() ) {
- if ( result == _SENTINEL )
- error("loop or previous error loading module '"+name+"'");
+ if (result.toboolean()) {
+ if (result == _SENTINEL)
+ error("loop or previous error loading module '" + name + "'");
return result;
}
-
+
/* else must load it; iterate over available loaders */
LuaTable tbl = package_.get(_SEARCHERS).checktable();
StringBuffer sb = new StringBuffer();
Varargs loader = null;
- for ( int i=1; true; i++ ) {
+ for (int i = 1; true; i++) {
LuaValue searcher = tbl.get(i);
- if ( searcher.isnil() ) {
- error( "module '"+name+"' not found: "+name+sb );
- }
-
- /* call loader with module name as argument */
+ if (searcher.isnil()) {
+ error("module '" + name + "' not found: " + name + sb);
+ }
+
+ /* call loader with module name as argument */
loader = searcher.invoke(name);
- if ( loader.isfunction(1) )
+ if (loader.isfunction(1))
break;
- if ( loader.isstring(1) )
- sb.append( loader.tojstring(1) );
+ if (loader.isstring(1))
+ sb.append(loader.tojstring(1));
}
-
+
// load the module using the loader
loaded.set(name, _SENTINEL);
result = loader.arg1().call(name, loader.arg(2));
- if ( ! result.isnil() )
- loaded.set( name, result );
- else if ( (result = loaded.get(name)) == _SENTINEL )
- loaded.set( name, result = LuaValue.TRUE );
+ if (!result.isnil())
+ loaded.set(name, result);
+ else if ((result = loaded.get(name)) == _SENTINEL)
+ loaded.set(name, result = LuaValue.TRUE);
return result;
}
}
public static class loadlib extends VarArgFunction {
- public Varargs invoke( Varargs args ) {
+ @Override
+ public Varargs invoke(Varargs args) {
args.checkstring(1);
return varargsOf(NIL, valueOf("dynamic libraries not enabled"), valueOf("absent"));
}
}
public class preload_searcher extends VarArgFunction {
+ @Override
public Varargs invoke(Varargs args) {
LuaString name = args.checkstring(1);
LuaValue val = package_.get(_PRELOAD).get(name);
- return val.isnil()?
- valueOf("\n\tno field package.preload['"+name+"']"):
- val;
+ return val.isnil()? valueOf("\n\tno field package.preload['" + name + "']"): val;
}
}
public class lua_searcher extends VarArgFunction {
+ @Override
public Varargs invoke(Varargs args) {
LuaString name = args.checkstring(1);
-
+
// get package path
LuaValue path = package_.get(_PATH);
- if ( ! path.isstring() )
+ if (!path.isstring())
return valueOf("package.path is not a string");
-
+
// get the searchpath function.
Varargs v = package_.get(_SEARCHPATH).invoke(varargsOf(name, path));
-
+
// Did we get a result?
if (!v.isstring(1))
return v.arg(2).tostring();
LuaString filename = v.arg1().strvalue();
-
+
// Try to load the file.
v = globals.loadfile(filename.tojstring());
- if ( v.arg1().isfunction() )
+ if (v.arg1().isfunction())
return LuaValue.varargsOf(v.arg1(), filename);
-
+
// report error
- return varargsOf(NIL, valueOf("'"+filename+"': "+v.arg(2).tojstring()));
+ return varargsOf(NIL, valueOf("'" + filename + "': " + v.arg(2).tojstring()));
}
}
public class searchpath extends VarArgFunction {
+ @Override
public Varargs invoke(Varargs args) {
String name = args.checkjstring(1);
String path = args.checkjstring(2);
String sep = args.optjstring(3, ".");
String rep = args.optjstring(4, FILE_SEP);
-
+
// check the path elements
int e = -1;
int n = path.length();
StringBuffer sb = null;
name = name.replace(sep.charAt(0), rep.charAt(0));
while ( e < n ) {
-
+
// find next template
int b = e+1;
- e = path.indexOf(';',b);
- if ( e < 0 )
+ e = path.indexOf(';', b);
+ if (e < 0)
e = path.length();
- String template = path.substring(b,e);
-
+ String template = path.substring(b, e);
+
// create filename
int q = template.indexOf('?');
String filename = template;
- if ( q >= 0 ) {
- filename = template.substring(0,q) + name + template.substring(q+1);
+ if (q >= 0) {
+ filename = template.substring(0, q)+name+template.substring(q+1);
}
-
+
// try opening the file
InputStream is = globals.finder.findResource(filename);
if (is != null) {
- try { is.close(); } catch ( java.io.IOException ioe ) {}
+ try {
+ is.close();
+ } catch (java.io.IOException ioe) {
+ }
return valueOf(filename);
}
-
+
// report error
- if ( sb == null )
+ if (sb == null)
sb = new StringBuffer();
- sb.append( "\n\t"+filename );
+ sb.append("\n\t" + filename);
}
return varargsOf(NIL, valueOf(sb.toString()));
}
}
-
+
+ public class seeall extends OneArgFunction {
+ @Override
+ public LuaValue call(LuaValue arg) {
+ LuaTable mt = new LuaTable();
+ mt.set(LuaValue.INDEX, globals);
+ arg.checktable().setmetatable(mt);
+ return LuaValue.NONE;
+ }
+ }
+
public class java_searcher extends VarArgFunction {
+ @Override
public Varargs invoke(Varargs args) {
String name = args.checkjstring(1);
- String classname = toClassname( name );
+ String classname = toClassname(name);
Class c = null;
LuaValue v = null;
try {
c = Class.forName(classname);
v = (LuaValue) c.newInstance();
if (v.isfunction())
- ((LuaFunction)v).initupvalue1(globals);
+ ((LuaFunction) v).initupvalue1(globals);
return varargsOf(v, globals);
- } catch ( ClassNotFoundException cnfe ) {
- return valueOf("\n\tno class '"+classname+"'" );
- } catch ( Exception e ) {
- return valueOf("\n\tjava load failed on '"+classname+"', "+e );
+ } catch (ClassNotFoundException cnfe) {
+ return valueOf("\n\tno class '" + classname + "'");
+ } catch (Exception e) {
+ return valueOf("\n\tjava load failed on '" + classname + "', " + e);
}
}
}
-
+
/** Convert lua filename to valid class name */
- public static final String toClassname( String filename ) {
- int n=filename.length();
- int j=n;
- if ( filename.endsWith(".lua") )
+ public static final String toClassname(String filename) {
+ int n = filename.length();
+ int j = n;
+ if (filename.endsWith(".lua"))
j -= 4;
- for ( int k=0; k
+ * {
+ * @code
+ * Globals globals = JsePlatform.standardGlobals();
+ * System.out.println(globals.get("string").get("upper").call(LuaValue.valueOf("abcde")));
+ * }
+ *
+ *
+ * {
+ * @code
+ * Globals globals = new Globals();
+ * globals.load(new JseBaseLib());
+ * globals.load(new PackageLib());
+ * globals.load(new JseStringLib());
+ * System.out.println(globals.get("string").get("upper").call(LuaValue.valueOf("abcde")));
+ * }
+ *
+ * {@code
- * Globals globals = JsePlatform.standardGlobals();
- * System.out.println( globals.get("table").get("length").call( LuaValue.tableOf() ) );
- * }
+ * {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
+ * {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
+ *
+ *
+ * {
+ * @code
+ * Globals globals = JsePlatform.standardGlobals();
+ * System.out.println(globals.get("table").get("length").call(LuaValue.tableOf()));
+ * }
+ *
* {@code
- * Globals globals = new Globals();
- * globals.load(new JseBaseLib());
- * globals.load(new PackageLib());
- * globals.load(new TableLib());
- * System.out.println( globals.get("table").get("length").call( LuaValue.tableOf() ) );
- * }
+ * To instantiate and use it directly, link it into your globals table via
+ * {@link LuaValue#load(LuaValue)} using code such as:
+ *
+ *
+ * {
+ * @code
+ * Globals globals = new Globals();
+ * globals.load(new JseBaseLib());
+ * globals.load(new PackageLib());
+ * globals.load(new TableLib());
+ * System.out.println(globals.get("table").get("length").call(LuaValue.tableOf()));
+ * }
+ *
* {@code
- * Globals globals = JmePlatform.standardGlobals();
- * globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
- * }
+ *
+ *
+ * {
+ * @code
+ * Globals globals = JmePlatform.standardGlobals();
+ * globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
+ * }
+ *
* {@code
- * Globals globals = new Globals();
- * globals.load(new JmeBaseLib());
- * globals.load(new PackageLib());
- * globals.load(new JmeIoLib());
- * globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
- * }
- *
+ * {
+ * @code
+ * Globals globals = new Globals();
+ * globals.load(new JmeBaseLib());
+ * globals.load(new PackageLib());
+ * globals.load(new JmeIoLib());
+ * globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
+ * }
+ *
*
- *
* {@code
- * Globals global = JmePlatform.standardGlobals();
- * global.get("print").call(LuaValue.valueOf("hello, world"));
- * }
+ *
+ *
+ * {
+ * @code
+ * Globals global = JmePlatform.standardGlobals();
+ * global.get("print").call(LuaValue.valueOf("hello, world"));
+ * }
+ *
* {@code
+ *
+ *
*
+ * {@code
* LoadState.load( getClass().getResourceAsStream("main.lua"), "main.lua", globals ).call();
- * }
+ * }
+ * {@code
+ * although {@code require} could also be used:
+ *
+ *
+ *
+ * For this to succeed, the file "main.lua" must be a resource in the class
+ * path. See {@link BaseLib} for details on finding scripts using
+ * {@link ResourceFinder}.
*
+ * {@code
* globals.get("require").call(LuaValue.valueOf("main"));
- * }
- * For this to succeed, the file "main.lua" must be a resource in the class path.
- * See {@link BaseLib} for details on finding scripts using {@link ResourceFinder}.
+ * }
+ *
*
- * In addition, the {@link LuaC} compiler is installed so lua files may be loaded in their source form.
- *
*
*
*
- * The method {@link CoerceJavaToLua#coerce(Object)} looks as the type and dimesioning
- * of the argument and tries to guess the best fit for corrsponding lua scalar,
- * table, or table of tables.
- *
+ * The method {@link CoerceJavaToLua#coerce(Object)} looks as the type and
+ * dimesioning of the argument and tries to guess the best fit for corrsponding
+ * lua scalar, table, or table of tables.
+ *
* @see CoerceJavaToLua#coerce(Object)
* @see org.luaj.vm2.lib.jse.LuajavaLib
*/
public class CoerceJavaToLua {
- static interface Coercion {
- public LuaValue coerce( Object javaValue );
- };
-
+ interface Coercion {
+ LuaValue coerce(Object javaValue);
+ }
+
private static final class BoolCoercion implements Coercion {
- public LuaValue coerce( Object javaValue ) {
+ @Override
+ public LuaValue coerce(Object javaValue) {
Boolean b = (Boolean) javaValue;
return b.booleanValue()? LuaValue.TRUE: LuaValue.FALSE;
}
}
-
+
private static final class IntCoercion implements Coercion {
- public LuaValue coerce( Object javaValue ) {
+ @Override
+ public LuaValue coerce(Object javaValue) {
Number n = (Number) javaValue;
- return LuaInteger.valueOf( n.intValue() );
+ return LuaInteger.valueOf(n.intValue());
}
}
private static final class CharCoercion implements Coercion {
- public LuaValue coerce( Object javaValue ) {
+ @Override
+ public LuaValue coerce(Object javaValue) {
Character c = (Character) javaValue;
- return LuaInteger.valueOf( c.charValue() );
+ return LuaInteger.valueOf(c.charValue());
}
}
private static final class DoubleCoercion implements Coercion {
- public LuaValue coerce( Object javaValue ) {
+ @Override
+ public LuaValue coerce(Object javaValue) {
Number n = (Number) javaValue;
- return LuaDouble.valueOf( n.doubleValue() );
+ return LuaDouble.valueOf(n.doubleValue());
}
}
private static final class StringCoercion implements Coercion {
- public LuaValue coerce( Object javaValue ) {
- return LuaString.valueOf( javaValue.toString() );
+ @Override
+ public LuaValue coerce(Object javaValue) {
+ return LuaString.valueOf(javaValue.toString());
}
}
private static final class BytesCoercion implements Coercion {
- public LuaValue coerce( Object javaValue ) {
+ @Override
+ public LuaValue coerce(Object javaValue) {
return LuaValue.valueOf((byte[]) javaValue);
}
}
private static final class ClassCoercion implements Coercion {
- public LuaValue coerce( Object javaValue ) {
+ @Override
+ public LuaValue coerce(Object javaValue) {
return JavaClass.forClass((Class) javaValue);
}
}
private static final class InstanceCoercion implements Coercion {
+ @Override
public LuaValue coerce(Object javaValue) {
return new JavaInstance(javaValue);
}
}
private static final class ArrayCoercion implements Coercion {
+ @Override
public LuaValue coerce(Object javaValue) {
- // should be userdata?
+ // should be userdata?
return new JavaArray(javaValue);
}
}
private static final class LuaCoercion implements Coercion {
- public LuaValue coerce( Object javaValue ) {
+ @Override
+ public LuaValue coerce(Object javaValue) {
return (LuaValue) javaValue;
}
}
-
static final Map COERCIONS = Collections.synchronizedMap(new HashMap());
-
+
static {
- Coercion boolCoercion = new BoolCoercion() ;
- Coercion intCoercion = new IntCoercion() ;
- Coercion charCoercion = new CharCoercion() ;
- Coercion doubleCoercion = new DoubleCoercion() ;
- Coercion stringCoercion = new StringCoercion() ;
- Coercion bytesCoercion = new BytesCoercion() ;
- Coercion classCoercion = new ClassCoercion() ;
- COERCIONS.put( Boolean.class, boolCoercion );
- COERCIONS.put( Byte.class, intCoercion );
- COERCIONS.put( Character.class, charCoercion );
- COERCIONS.put( Short.class, intCoercion );
- COERCIONS.put( Integer.class, intCoercion );
- COERCIONS.put( Long.class, doubleCoercion );
- COERCIONS.put( Float.class, doubleCoercion );
- COERCIONS.put( Double.class, doubleCoercion );
- COERCIONS.put( String.class, stringCoercion );
- COERCIONS.put( byte[].class, bytesCoercion );
- COERCIONS.put( Class.class, classCoercion );
+ Coercion boolCoercion = new BoolCoercion();
+ Coercion intCoercion = new IntCoercion();
+ Coercion charCoercion = new CharCoercion();
+ Coercion doubleCoercion = new DoubleCoercion();
+ Coercion stringCoercion = new StringCoercion();
+ Coercion bytesCoercion = new BytesCoercion();
+ Coercion classCoercion = new ClassCoercion();
+ COERCIONS.put(Boolean.class, boolCoercion);
+ COERCIONS.put(Byte.class, intCoercion);
+ COERCIONS.put(Character.class, charCoercion);
+ COERCIONS.put(Short.class, intCoercion);
+ COERCIONS.put(Integer.class, intCoercion);
+ COERCIONS.put(Long.class, doubleCoercion);
+ COERCIONS.put(Float.class, doubleCoercion);
+ COERCIONS.put(Double.class, doubleCoercion);
+ COERCIONS.put(String.class, stringCoercion);
+ COERCIONS.put(byte[].class, bytesCoercion);
+ COERCIONS.put(Class.class, classCoercion);
}
/**
- * Coerse a Java object to a corresponding lua value.
+ * Coerse a Java object to a corresponding lua value.
*
*
* {@code
- * Globals globals = JsePlatform.standardGlobals();
- * globals.get("print").call(LuaValue.valueOf("hello, world"));
- * }
+ *
+ *
+ * {
+ * @code
+ * Globals globals = JsePlatform.standardGlobals();
+ * globals.get("print").call(LuaValue.valueOf("hello, world"));
+ * }
+ *
* {@code
- * Globals globals = new Globals();
- * globals.load(new JseBaseLib());
- * globals.get("print").call(LuaValue.valueOf("hello, world"));
- * }
- *
+ * {
+ * @code
+ * Globals globals = new Globals();
+ * globals.load(new JseBaseLib());
+ * globals.get("print").call(LuaValue.valueOf("hello, world"));
+ * }
+ *
+ * {@code
- * Globals globals = JsePlatform.standardGlobals();
- * globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
- * }
+ *
+ *
+ * {
+ * @code
+ * Globals globals = JsePlatform.standardGlobals();
+ * globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
+ * }
+ *
* {@code
- * Globals globals = new Globals();
- * globals.load(new JseBaseLib());
- * globals.load(new PackageLib());
- * globals.load(new JseIoLib());
- * globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
- * }
- *
+ * {
+ * @code
+ * Globals globals = new Globals();
+ * globals.load(new JseBaseLib());
+ * globals.load(new PackageLib());
+ * globals.load(new JseIoLib());
+ * globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
+ * }
+ *
* {@code
- * Globals globals = JsePlatform.standardGlobals();
- * System.out.println( globals.get("math").get("sqrt").call( LuaValue.valueOf(2) ) );
- * }
+ *
+ *
+ * {
+ * @code
+ * Globals globals = JsePlatform.standardGlobals();
+ * System.out.println(globals.get("math").get("sqrt").call(LuaValue.valueOf(2)));
+ * }
+ *
* {@code
- * Globals globals = new Globals();
- * globals.load(new JseBaseLib());
- * globals.load(new PackageLib());
- * globals.load(new JseMathLib());
- * System.out.println( globals.get("math").get("sqrt").call( LuaValue.valueOf(2) ) );
- * }
- *
+ * {
+ * @code
+ * Globals globals = new Globals();
+ * globals.load(new JseBaseLib());
+ * globals.load(new PackageLib());
+ * globals.load(new JseMathLib());
+ * System.out.println(globals.get("math").get("sqrt").call(LuaValue.valueOf(2)));
+ * }
+ *
*
*
* {@code
- * Globals globals = JsePlatform.standardGlobals();
- * System.out.println( globals.get("os").get("time").call() );
- * }
+ *
+ *
+ * {
+ * @code
+ * Globals globals = JsePlatform.standardGlobals();
+ * System.out.println(globals.get("os").get("time").call());
+ * }
+ *
* {@code
- * Globals globals = new Globals();
- * globals.load(new JseBaseLib());
- * globals.load(new PackageLib());
- * globals.load(new JseOsLib());
- * System.out.println( globals.get("os").get("time").call() );
- * }
- *
+ * {
+ * @code
+ * Globals globals = new Globals();
+ * globals.load(new JseBaseLib());
+ * globals.load(new PackageLib());
+ * globals.load(new JseOsLib());
+ * System.out.println(globals.get("os").get("time").call());
+ * }
+ *
* {@code
- * Globals globals = JsePlatform.standardGlobals();
- * globals.get("print").call(LuaValue.valueOf("hello, world"));
- * }
+ *
+ *
+ * {
+ * @code
+ * Globals globals = JsePlatform.standardGlobals();
+ * globals.get("print").call(LuaValue.valueOf("hello, world"));
+ * }
+ *
* {@code
+ *
+ *
*
+ * {@code
* globals.load( new FileInputStream("main.lua"), "main.lua" ).call();
- * }
+ * }
+ * {@code
+ *
+ *
+ *
+ * For this to succeed, the file "main.lua" must be in the current directory or
+ * a resource. See {@link org.luaj.vm2.lib.jse.JseBaseLib} for details on
+ * finding scripts using {@link ResourceFinder}.
*
+ * {@code
* globals.get("require").call(LuaValue.valueOf("main"));
- * }
- * For this to succeed, the file "main.lua" must be in the current directory or a resource.
- * See {@link org.luaj.vm2.lib.jse.JseBaseLib} for details on finding scripts using {@link ResourceFinder}.
+ * }
+ *
*
- * In addition, the {@link LuaC} compiler is installed so lua files may be loaded in their source form.
+ * In addition, the {@link LuaC} compiler is installed so lua files may be
+ * loaded in their source form.
* {@code
- * Globals globals = JsePlatform.standardGlobals();
- * System.out.println( globals.get("luajava").get("bindClass").call( LuaValue.valueOf("java.lang.System") ).invokeMethod("currentTimeMillis") );
- * }
+ *
+ *
+ * {
+ * @code
+ * Globals globals = JsePlatform.standardGlobals();
+ * System.out.println(globals.get("luajava").get("bindClass").call(LuaValue.valueOf("java.lang.System"))
+ * .invokeMethod("currentTimeMillis"));
+ * }
+ *
* {@code
- * Globals globals = new Globals();
- * globals.load(new JseBaseLib());
- * globals.load(new PackageLib());
- * globals.load(new LuajavaLib());
- * globals.load(
- * "sys = luajava.bindClass('java.lang.System')\n"+
- * "print ( sys:currentTimeMillis() )\n", "main.lua" ).call();
- * }
+ * To instantiate and use it directly, link it into your globals table via
+ * {@link Globals#load} using code such as:
+ *
+ *
+ * {
+ * @code
+ * Globals globals = new Globals();
+ * globals.load(new JseBaseLib());
+ * globals.load(new PackageLib());
+ * globals.load(new LuajavaLib());
+ * globals.load("sys = luajava.bindClass('java.lang.System')\n" + "print ( sys:currentTimeMillis() )\n", "main.lua")
+ * .call();
+ * }
+ *
* {@code
+ * To override the default compiling behavior with {@link LuaJC} lua-to-java
+ * bytecode compiler, install it before undumping code, for example:
+ *
+ *
*
+ * {@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();
- * }
+ * }
+ *