Merge remote-tracking branch 'src/master'

This commit is contained in:
Adrian Siekierka
2022-09-04 01:43:37 +02:00
23 changed files with 700 additions and 567 deletions

1
.gitignore vendored
View File

@@ -1,7 +1,6 @@
bin/ bin/
target/ target/
build/ build/
lib/
jit/ jit/
*.ser *.ser
*.gz *.gz

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2007 LuaJ. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -18,7 +18,7 @@ James Roseborough, Ian Farmer, Version 3.0.2
<small> <small>
Copyright &copy; 2009-2014 Luaj.org. Copyright &copy; 2009-2014 Luaj.org.
Freely available under the terms of the Freely available under the terms of the
<a href="http://sourceforge.net/dbimage.php?id=196142">Luaj license</a>. <a href="LICENSE">Luaj license</a>.
</small> </small>
<hr> <hr>
<p> <p>
@@ -412,7 +412,7 @@ and the math operations include all those supported by Java SE.
Android applications should use the JsePlatform, and can include the <a href="#luajava">Luajava</a> library Android applications should use the JsePlatform, and can include the <a href="#luajava">Luajava</a> library
to simplify access to underlying Android APIs. to simplify access to underlying Android APIs.
A specialized Globals.finder should be provided to find scripts and data for loading. A specialized Globals.finder should be provided to find scripts and data for loading.
See <a href="examples/android/src/android/LuajView">examples/android/src/android/LuajView</a> See <a href="examples/android/src/android/LuajView.java">examples/android/src/android/LuajView.java</a>
for an example that loads from the "res" Android project directory. for an example that loads from the "res" Android project directory.
The ant build script is <a href="examples/android/build.xml">examples/android/build.xml</a>. The ant build script is <a href="examples/android/build.xml">examples/android/build.xml</a>.

View File

@@ -31,10 +31,10 @@ import java.io.InputStream;
* <p> * <p>
* The {@link LoadState} class provides the default {@link Globals.Undumper} * 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 * 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 * using either the C-based lua compiler, or luaj's
* {@link org.luaj.vm2.compiler.LuaC} compiler. * {@link org.luaj.vm2.compiler.LuaC} compiler.
* <p> * <p>
* The canonical method to load and execute code is done * The canonical method to load and execute code is done
* indirectly using the Globals: * indirectly using the Globals:
* <pre> {@code * <pre> {@code
* Globals globals = JsePlatform.standardGlobals(); * Globals globals = JsePlatform.standardGlobals();
@@ -44,10 +44,10 @@ import java.io.InputStream;
* This should work regardless of which {@link Globals.Compiler} or {@link Globals.Undumper} * This should work regardless of which {@link Globals.Compiler} or {@link Globals.Undumper}
* have been installed. * have been installed.
* <p> * <p>
* By default, when using {@link org.luaj.vm2.lib.jse.JsePlatform} or * By default, when using {@link org.luaj.vm2.lib.jse.JsePlatform} or
* {@link org.luaj.vm2.lib.jme.JmePlatform} * {@link org.luaj.vm2.lib.jme.JmePlatform}
* to construct globals, the {@link LoadState} default undumper is installed * to construct globals, the {@link LoadState} default undumper is installed
* as the default {@link Globals.Undumper}. * as the default {@link Globals.Undumper}.
* <p> * <p>
* *
* A lua binary file is created via the {@link org.luaj.vm2.compiler.DumpState} class * A lua binary file is created via the {@link org.luaj.vm2.compiler.DumpState} class
@@ -60,7 +60,7 @@ import java.io.InputStream;
* byte[] lua_binary_file_bytes = o.toByteArray(); * byte[] lua_binary_file_bytes = o.toByteArray();
* } </pre> * } </pre>
* *
* The {@link LoadState}'s default undumper {@link #instance} * The {@link LoadState}'s default undumper {@link #instance}
* may be used directly to undump these bytes: * may be used directly to undump these bytes:
* <pre> {@code * <pre> {@code
* Prototypep = LoadState.instance.undump(new ByteArrayInputStream(lua_binary_file_bytes), "main.lua"); * Prototypep = LoadState.instance.undump(new ByteArrayInputStream(lua_binary_file_bytes), "main.lua");
@@ -99,7 +99,7 @@ public class LoadState {
/** format corresponding to number-patched lua, all numbers are 32-bit (4 byte) ints */ /** 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_NUM_PATCH_INT32 = 4;
// type constants // type constants
public static final int LUA_TINT = (-2); public static final int LUA_TINT = (-2);
public static final int LUA_TNONE = (-1); public static final int LUA_TNONE = (-1);
public static final int LUA_TNIL = 0; public static final int LUA_TNIL = 0;
@@ -155,7 +155,6 @@ public class LoadState {
private static final LuaValue[] NOVALUES = {}; private static final LuaValue[] NOVALUES = {};
private static final Prototype[] NOPROTOS = {}; private static final Prototype[] NOPROTOS = {};
private static final LocVars[] NOLOCVARS = {}; private static final LocVars[] NOLOCVARS = {};
private static final LuaString[] NOSTRVALUES = {};
private static final Upvaldesc[] NOUPVALDESCS = {}; private static final Upvaldesc[] NOUPVALDESCS = {};
private static final int[] NOINTS = {}; private static final int[] NOINTS = {};
@@ -168,17 +167,17 @@ public class LoadState {
} }
/** 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. * @return the int value laoded.
**/ **/
int loadInt() throws IOException { int loadInt() throws IOException {
is.readFully(buf,0,4); is.readFully(buf,0,4);
return luacLittleEndian? return luacLittleEndian?
(buf[3] << 24) | ((0xff & buf[2]) << 16) | ((0xff & buf[1]) << 8) | (0xff & buf[0]): (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]); (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. * @return the array of int values laoded.
**/ **/
int[] loadIntArray() throws IOException { int[] loadIntArray() throws IOException {
int n = loadInt(); int n = loadInt();
@@ -192,7 +191,7 @@ public class LoadState {
is.readFully(buf,0,m); is.readFully(buf,0,m);
int[] array = new int[n]; int[] array = new int[n];
for ( int i=0, j=0; i<n; ++i, j+=4 ) for ( int i=0, j=0; i<n; ++i, j+=4 )
array[i] = luacLittleEndian? array[i] = luacLittleEndian?
(buf[j+3] << 24) | ((0xff & buf[j+2]) << 16) | ((0xff & buf[j+1]) << 8) | (0xff & buf[j+0]): (buf[j+3] << 24) | ((0xff & buf[j+2]) << 16) | ((0xff & buf[j+1]) << 8) | (0xff & buf[j+0]):
(buf[j+0] << 24) | ((0xff & buf[j+1]) << 16) | ((0xff & buf[j+2]) << 8) | (0xff & buf[j+3]); (buf[j+0] << 24) | ((0xff & buf[j+1]) << 16) | ((0xff & buf[j+2]) << 8) | (0xff & buf[j+3]);
@@ -200,7 +199,7 @@ public class LoadState {
} }
/** Load a long value from the input stream /** Load a long value from the input stream
* @return the long value laoded. * @return the long value laoded.
**/ **/
long loadInt64() throws IOException { long loadInt64() throws IOException {
int a,b; int a,b;
@@ -215,7 +214,7 @@ public class LoadState {
} }
/** Load a lua strin gvalue from the input stream /** Load a lua strin gvalue from the input stream
* @return the {@link LuaString} value laoded. * @return the {@link LuaString} value laoded.
**/ **/
LuaString loadString() throws IOException { LuaString loadString() throws IOException {
int size = this.luacSizeofSizeT == 8? (int) loadInt64(): loadInt(); int size = this.luacSizeofSizeT == 8? (int) loadInt64(): loadInt();
@@ -227,7 +226,7 @@ public class LoadState {
} }
/** /**
* Convert bits in a long value to a {@link LuaValue}. * Convert bits in a long value to a {@link LuaValue}.
* @param bits long value containing the bits * @param bits long value containing the bits
* @return {@link LuaInteger} or {@link LuaDouble} whose value corresponds to the bits provided. * @return {@link LuaInteger} or {@link LuaDouble} whose value corresponds to the bits provided.
*/ */
@@ -251,7 +250,7 @@ public class LoadState {
return LuaValue.valueOf( Double.longBitsToDouble(bits) ); return LuaValue.valueOf( Double.longBitsToDouble(bits) );
} }
/** /**
* Load a number from a binary chunk * Load a number from a binary chunk
* @return the {@link LuaValue} loaded * @return the {@link LuaValue} loaded
* @throws IOException if an i/o exception occurs * @throws IOException if an i/o exception occurs
@@ -335,7 +334,7 @@ public class LoadState {
f.upvalues[i].name = loadString(); f.upvalues[i].name = loadString();
} }
/** /**
* Load a function prototype from the input stream * Load a function prototype from the input stream
* @param p name of the source * @param p name of the source
* @return {@link Prototype} instance that was loaded * @return {@link Prototype} instance that was loaded
@@ -366,8 +365,8 @@ public class LoadState {
} }
/** /**
* Load the lua chunk header values. * Load the lua chunk header values.
* @throws IOException if an i/o exception occurs. * @throws IOException if an i/o exception occurs.
*/ */
public void loadHeader() throws IOException { public void loadHeader() throws IOException {
luacVersion = is.readByte(); luacVersion = is.readByte();
@@ -392,7 +391,7 @@ public class LoadState {
*/ */
public static Prototype undump(InputStream stream, String chunkname) throws IOException { public static Prototype undump(InputStream stream, String chunkname) throws IOException {
// check rest of signature // check rest of signature
if ( stream.read() != LUA_SIGNATURE[0] if ( stream.read() != LUA_SIGNATURE[0]
|| stream.read() != LUA_SIGNATURE[1] || stream.read() != LUA_SIGNATURE[1]
|| stream.read() != LUA_SIGNATURE[2] || stream.read() != LUA_SIGNATURE[2]
|| stream.read() != LUA_SIGNATURE[3] ) || stream.read() != LUA_SIGNATURE[3] )

View File

@@ -21,6 +21,8 @@
******************************************************************************/ ******************************************************************************/
package org.luaj.vm2; package org.luaj.vm2;
import org.luaj.vm2.lib.DebugLib.CallFrame;
/** /**
* Extension of {@link LuaFunction} which executes lua bytecode. * Extension of {@link LuaFunction} which executes lua bytecode.
* <p> * <p>
@@ -415,7 +417,7 @@ public class LuaClosure extends LuaFunction {
{ {
LuaValue limit = stack[a + 1]; LuaValue limit = stack[a + 1];
LuaValue step = stack[a + 2]; LuaValue step = stack[a + 2];
LuaValue idx = step.add(stack[a]); LuaValue idx = stack[a].add(step);
if (step.gt_b(0)? idx.lteq_b(limit): idx.gteq_b(limit)) { if (step.gt_b(0)? idx.lteq_b(limit): idx.gteq_b(limit)) {
stack[a] = idx; stack[a] = idx;
stack[a + 3] = idx; stack[a + 3] = idx;
@@ -547,8 +549,24 @@ public class LuaClosure extends LuaFunction {
} }
private void processErrorHooks(LuaError le, Prototype p, int pc) { private void processErrorHooks(LuaError le, Prototype p, int pc) {
le.fileline = (p.source != null? p.source.tojstring(): "?") + ":" String file = "?";
+ (p.lineinfo != null && pc >= 0 && pc < p.lineinfo.length? String.valueOf(p.lineinfo[pc]): "?") + ": "; int line = -1;
{
CallFrame frame = null;
if (globals != null && globals.debuglib != null) {
frame = globals.debuglib.getCallFrame(le.level);
if (frame != null) {
String src = frame.shortsource();
file = src != null ? src : "?";
line = frame.currentline();
}
}
if (frame == null) {
file = p.source != null? p.source.tojstring(): "?";
line = p.lineinfo != null && pc >= 0 && pc < p.lineinfo.length ? p.lineinfo[pc] : -1;
}
}
le.fileline = file + ": " + line;
le.traceback = errorHook(le.getMessage(), le.level); le.traceback = errorHook(le.getMessage(), le.level);
} }

View File

@@ -25,12 +25,12 @@ import org.luaj.vm2.compat.JavaCompat;
import org.luaj.vm2.lib.MathLib; import org.luaj.vm2.lib.MathLib;
/** /**
* Extension of {@link LuaNumber} which can hold a Java double as its value. * Extension of {@link LuaNumber} which can hold a Java double as its value.
* <p> * <p>
* These instance are not instantiated directly by clients, but indirectly * These instance are not instantiated directly by clients, but indirectly
* via the static functions {@link LuaValue#valueOf(int)} or {@link LuaValue#valueOf(double)} * via the static functions {@link LuaValue#valueOf(int)} or {@link LuaValue#valueOf(double)}
* functions. This ensures that values which can be represented as int * functions. This ensures that values which can be represented as int
* are wrapped in {@link LuaInteger} instead of {@link LuaDouble}. * are wrapped in {@link LuaInteger} instead of {@link LuaDouble}.
* <p> * <p>
* Almost all API's implemented in LuaDouble are defined and documented in {@link LuaValue}. * Almost all API's implemented in LuaDouble are defined and documented in {@link LuaValue}.
* <p> * <p>
@@ -44,7 +44,7 @@ import org.luaj.vm2.lib.MathLib;
* <li>{@link #ddiv_d(double, double)}</li> * <li>{@link #ddiv_d(double, double)}</li>
* <li>{@link #dmod(double, double)}</li> * <li>{@link #dmod(double, double)}</li>
* <li>{@link #dmod_d(double, double)}</li> * <li>{@link #dmod_d(double, double)}</li>
* </ul> * </ul>
* <p> * <p>
* @see LuaValue * @see LuaValue
* @see LuaNumber * @see LuaNumber
@@ -97,7 +97,7 @@ public class LuaDouble extends LuaNumber {
} }
public boolean islong() { public boolean islong() {
return v == (long) v; return v == (long) v;
} }
public byte tobyte() { return (byte) (long) v; } public byte tobyte() { return (byte) (long) v; }
@@ -158,12 +158,12 @@ public class LuaDouble extends LuaNumber {
/** Divide two double numbers according to lua math, and return a {@link LuaValue} result. /** Divide two double numbers according to lua math, and return a {@link LuaValue} result.
* @param lhs Left-hand-side of the division. * @param lhs Left-hand-side of the division.
* @param rhs Right-hand-side of the division. * @param rhs Right-hand-side of the division.
* @return {@link LuaValue} for the result of the division, * @return {@link LuaValue} for the result of the division,
* taking into account positive and negiative infinity, and Nan * taking into account positive and negiative infinity, and Nan
* @see #ddiv_d(double, double) * @see #ddiv_d(double, double)
*/ */
public static LuaValue ddiv(double lhs, double rhs) { public static LuaValue ddiv(double lhs, double rhs) {
return rhs!=0? valueOf( lhs / rhs ): lhs>0? POSINF: lhs==0? NAN: NEGINF; 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. /** Divide two double numbers according to lua math, and return a double result.
@@ -173,15 +173,15 @@ public class LuaDouble extends LuaNumber {
* @see #ddiv(double, double) * @see #ddiv(double, double)
*/ */
public static double ddiv_d(double lhs, double rhs) { 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; 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. /** Take modulo double numbers according to lua math, and return a {@link LuaValue} result.
* @param lhs Left-hand-side of the modulo. * @param lhs Left-hand-side of the modulo.
* @param rhs Right-hand-side of the modulo. * @param rhs Right-hand-side of the modulo.
* @return {@link LuaValue} for the result of the modulo, * @return {@link LuaValue} for the result of the modulo,
* using lua's rules for modulo * using lua's rules for modulo
* @see #dmod_d(double, double) * @see #dmod_d(double, double)
*/ */
public static LuaValue dmod(double lhs, double rhs) { public static LuaValue dmod(double lhs, double rhs) {
if (rhs == 0 || lhs == Double.POSITIVE_INFINITY || lhs == Double.NEGATIVE_INFINITY) return NAN; if (rhs == 0 || lhs == Double.POSITIVE_INFINITY || lhs == Double.NEGATIVE_INFINITY) return NAN;
@@ -197,7 +197,7 @@ public class LuaDouble extends LuaNumber {
/** Take modulo for double numbers according to lua math, and return a double result. /** Take modulo for double numbers according to lua math, and return a double result.
* @param lhs Left-hand-side of the modulo. * @param lhs Left-hand-side of the modulo.
* @param rhs Right-hand-side of the modulo. * @param rhs Right-hand-side of the modulo.
* @return double value for the result of the modulo, * @return double value for the result of the modulo,
* using lua's rules for modulo * using lua's rules for modulo
* @see #dmod(double, double) * @see #dmod(double, double)
*/ */
@@ -213,28 +213,28 @@ public class LuaDouble extends LuaNumber {
} }
// relational operators // relational operators
public LuaValue lt( LuaValue rhs ) { return rhs.gt_b(v)? LuaValue.TRUE: FALSE; } public LuaValue lt( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.gt_b(v)? TRUE: FALSE) : super.lt(rhs); }
public LuaValue lt( double rhs ) { return v < rhs? TRUE: FALSE; } public LuaValue lt( double rhs ) { return v < rhs? TRUE: FALSE; }
public LuaValue lt( int rhs ) { return v < rhs? TRUE: FALSE; } public LuaValue lt( int rhs ) { return v < rhs? TRUE: FALSE; }
public boolean lt_b( LuaValue rhs ) { return rhs.gt_b(v); } public boolean lt_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.gt_b(v) : super.lt_b(rhs); }
public boolean lt_b( int rhs ) { return v < rhs; } public boolean lt_b( int rhs ) { return v < rhs; }
public boolean lt_b( double rhs ) { return v < rhs; } public boolean lt_b( double rhs ) { return v < rhs; }
public LuaValue lteq( LuaValue rhs ) { return rhs.gteq_b(v)? LuaValue.TRUE: FALSE; } public LuaValue lteq( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.gteq_b(v)? TRUE: FALSE) : super.lteq(rhs); }
public LuaValue lteq( double rhs ) { return v <= rhs? TRUE: FALSE; } public LuaValue lteq( double rhs ) { return v <= rhs? TRUE: FALSE; }
public LuaValue lteq( int rhs ) { return v <= rhs? TRUE: FALSE; } public LuaValue lteq( int rhs ) { return v <= rhs? TRUE: FALSE; }
public boolean lteq_b( LuaValue rhs ) { return rhs.gteq_b(v); } public boolean lteq_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.gteq_b(v) : super.lteq_b(rhs); }
public boolean lteq_b( int rhs ) { return v <= rhs; } public boolean lteq_b( int rhs ) { return v <= rhs; }
public boolean lteq_b( double rhs ) { return v <= rhs; } public boolean lteq_b( double rhs ) { return v <= rhs; }
public LuaValue gt( LuaValue rhs ) { return rhs.lt_b(v)? LuaValue.TRUE: FALSE; } public LuaValue gt( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.lt_b(v)? TRUE: FALSE) : super.gt(rhs); }
public LuaValue gt( double rhs ) { return v > rhs? TRUE: FALSE; } public LuaValue gt( double rhs ) { return v > rhs? TRUE: FALSE; }
public LuaValue gt( int rhs ) { return v > rhs? TRUE: FALSE; } public LuaValue gt( int rhs ) { return v > rhs? TRUE: FALSE; }
public boolean gt_b( LuaValue rhs ) { return rhs.lt_b(v); } public boolean gt_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.lt_b(v) : super.gt_b(rhs); }
public boolean gt_b( int rhs ) { return v > rhs; } public boolean gt_b( int rhs ) { return v > rhs; }
public boolean gt_b( double rhs ) { return v > rhs; } public boolean gt_b( double rhs ) { return v > rhs; }
public LuaValue gteq( LuaValue rhs ) { return rhs.lteq_b(v)? LuaValue.TRUE: FALSE; } public LuaValue gteq( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.lteq_b(v)? TRUE: FALSE) : super.gteq(rhs); }
public LuaValue gteq( double rhs ) { return v >= rhs? TRUE: FALSE; } public LuaValue gteq( double rhs ) { return v >= rhs? TRUE: FALSE; }
public LuaValue gteq( int rhs ) { return v >= rhs? TRUE: FALSE; } public LuaValue gteq( int rhs ) { return v >= rhs? TRUE: FALSE; }
public boolean gteq_b( LuaValue rhs ) { return rhs.lteq_b(v); } public boolean gteq_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.lteq_b(v) : super.gteq_b(rhs); }
public boolean gteq_b( int rhs ) { return v >= rhs; } public boolean gteq_b( int rhs ) { return v >= rhs; }
public boolean gteq_b( double rhs ) { return v >= rhs; } public boolean gteq_b( double rhs ) { return v >= rhs; }
@@ -245,7 +245,7 @@ public class LuaDouble extends LuaNumber {
if ( v == 0.0 ) // never occurs on J2ME if ( v == 0.0 ) // never occurs on J2ME
return (JavaCompat.INSTANCE.doubleToRawLongBits(v)<0? "-0": "0"); return (JavaCompat.INSTANCE.doubleToRawLongBits(v)<0? "-0": "0");
long l = (long) v; long l = (long) v;
if ( l == v ) if ( l == v )
return Long.toString(l); return Long.toString(l);
if ( Double.isNaN(v) ) if ( Double.isNaN(v) )
return (JavaCompat.INSTANCE.doubleToRawLongBits(v)<0? JSTR_NEGNAN: JSTR_NAN); return (JavaCompat.INSTANCE.doubleToRawLongBits(v)<0? JSTR_NEGNAN: JSTR_NAN);
@@ -271,11 +271,11 @@ public class LuaDouble extends LuaNumber {
} }
public LuaNumber optnumber(LuaNumber defval) { public LuaNumber optnumber(LuaNumber defval) {
return this; return this;
} }
public boolean isnumber() { public boolean isnumber() {
return true; return true;
} }
public boolean isstring() { public boolean isstring() {
@@ -290,14 +290,14 @@ public class LuaDouble extends LuaNumber {
public LuaNumber checknumber() { return this; } public LuaNumber checknumber() { return this; }
public double checkdouble() { return v; } public double checkdouble() { return v; }
public String checkjstring() { public String checkjstring() {
return tojstring(); return tojstring();
} }
public LuaString checkstring() { public LuaString checkstring() {
return LuaString.valueOf(tojstring()); return LuaString.valueOf(tojstring());
} }
public boolean isvalidkey() { public boolean isvalidkey() {
return !Double.isNaN(v); return !Double.isNaN(v);
} }
} }

View File

@@ -22,14 +22,14 @@
package org.luaj.vm2; package org.luaj.vm2;
/** /**
* Base class for functions implemented in Java. * Base class for functions implemented in Java.
* <p> * <p>
* Direct subclass include {@link org.luaj.vm2.lib.LibFunction} * Direct subclass include {@link org.luaj.vm2.lib.LibFunction}
* which is the base class for * which is the base class for
* all built-in library functions coded in Java, * all built-in library functions coded in Java,
* and {@link LuaClosure}, which represents a lua closure * and {@link LuaClosure}, which represents a lua closure
* whose bytecode is interpreted when the function is invoked. * whose bytecode is interpreted when the function is invoked.
* @see LuaValue * @see LuaValue
* @see LuaClosure * @see LuaClosure
* @see org.luaj.vm2.lib.LibFunction * @see org.luaj.vm2.lib.LibFunction
@@ -57,11 +57,11 @@ public class LuaFunction extends LuaValue {
} }
public LuaFunction optfunction(LuaFunction defval) { public LuaFunction optfunction(LuaFunction defval) {
return this; return this;
} }
public LuaValue getmetatable() { public LuaValue getmetatable() {
return s_metatable; return s_metatable;
} }
public String tojstring() { public String tojstring() {
@@ -72,12 +72,15 @@ public class LuaFunction extends LuaValue {
return valueOf(tojstring()); return valueOf(tojstring());
} }
/** Return the last part of the class name, to be used as a function name in tojstring and elsewhere. /** 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 ($). * @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() { public String classnamestub() {
String s = getClass().getName(); String s = getClass().getName();
return s.substring(Math.max(s.lastIndexOf('.'),s.lastIndexOf('$'))+1); 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. /** Return a human-readable name for this function. Returns the last part of the class name by default.

View File

@@ -24,14 +24,14 @@ package org.luaj.vm2;
import org.luaj.vm2.lib.MathLib; import org.luaj.vm2.lib.MathLib;
/** /**
* Extension of {@link LuaNumber} which can hold a Java int as its value. * Extension of {@link LuaNumber} which can hold a Java int as its value.
* <p> * <p>
* These instance are not instantiated directly by clients, but indirectly * These instance are not instantiated directly by clients, but indirectly
* via the static functions {@link LuaValue#valueOf(int)} or {@link LuaValue#valueOf(double)} * via the static functions {@link LuaValue#valueOf(int)} or {@link LuaValue#valueOf(double)}
* functions. This ensures that policies regarding pooling of instances are * functions. This ensures that policies regarding pooling of instances are
* encapsulated. * encapsulated.
* <p> * <p>
* There are no API's specific to LuaInteger that are useful beyond what is already * There are no API's specific to LuaInteger that are useful beyond what is already
* exposed in {@link LuaValue}. * exposed in {@link LuaValue}.
* *
* @see LuaValue * @see LuaValue
@@ -61,16 +61,16 @@ public class LuaInteger extends LuaNumber {
*/ */
public static LuaNumber valueOf(long l) { public static LuaNumber valueOf(long l) {
int i = (int) l; int i = (int) l;
return l==i? (i<=255 && i>=-256? intValues[i+256]: return l==i? (i<=255 && i>=-256? intValues[i+256]:
(LuaNumber) new LuaInteger(i)): (LuaNumber) new LuaInteger(i)):
(LuaNumber) LuaDouble.valueOf(l); (LuaNumber) LuaDouble.valueOf(l);
} }
/** The value being held by this instance. */ /** The value being held by this instance. */
public final int v; public final int v;
/** /**
* Package protected constructor. * Package protected constructor.
* @see LuaValue#valueOf(int) * @see LuaValue#valueOf(int)
**/ **/
LuaInteger(int i) { LuaInteger(int i) {
@@ -103,15 +103,15 @@ public class LuaInteger extends LuaNumber {
} }
public LuaString optstring(LuaString defval) { public LuaString optstring(LuaString defval) {
return LuaString.valueOf(Integer.toString(v)); return LuaString.valueOf(Integer.toString(v));
} }
public LuaValue tostring() { public LuaValue tostring() {
return LuaString.valueOf(Integer.toString(v)); return LuaString.valueOf(Integer.toString(v));
} }
public String optjstring(String defval) { public String optjstring(String defval) {
return Integer.toString(v); return Integer.toString(v);
} }
public LuaInteger checkinteger() { public LuaInteger checkinteger() {
@@ -172,48 +172,48 @@ public class LuaInteger extends LuaNumber {
public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs,v); } public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs,v); }
// relational operators // relational operators
public LuaValue lt( LuaValue rhs ) { return rhs.gt_b(v)? TRUE: FALSE; } public LuaValue lt( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.gt_b(v)? TRUE: FALSE) : super.lt(rhs); }
public LuaValue lt( double rhs ) { return v < rhs? TRUE: FALSE; } public LuaValue lt( double rhs ) { return v < rhs? TRUE: FALSE; }
public LuaValue lt( int rhs ) { return v < rhs? TRUE: FALSE; } public LuaValue lt( int rhs ) { return v < rhs? TRUE: FALSE; }
public boolean lt_b( LuaValue rhs ) { return rhs.gt_b(v); } public boolean lt_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.gt_b(v) : super.lt_b(rhs); }
public boolean lt_b( int rhs ) { return v < rhs; } public boolean lt_b( int rhs ) { return v < rhs; }
public boolean lt_b( double rhs ) { return v < rhs; } public boolean lt_b( double rhs ) { return v < rhs; }
public LuaValue lteq( LuaValue rhs ) { return rhs.gteq_b(v)? TRUE: FALSE; } public LuaValue lteq( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.gteq_b(v)? TRUE: FALSE) : super.lteq(rhs); }
public LuaValue lteq( double rhs ) { return v <= rhs? TRUE: FALSE; } public LuaValue lteq( double rhs ) { return v <= rhs? TRUE: FALSE; }
public LuaValue lteq( int rhs ) { return v <= rhs? TRUE: FALSE; } public LuaValue lteq( int rhs ) { return v <= rhs? TRUE: FALSE; }
public boolean lteq_b( LuaValue rhs ) { return rhs.gteq_b(v); } public boolean lteq_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.gteq_b(v) : super.lteq_b(rhs); }
public boolean lteq_b( int rhs ) { return v <= rhs; } public boolean lteq_b( int rhs ) { return v <= rhs; }
public boolean lteq_b( double rhs ) { return v <= rhs; } public boolean lteq_b( double rhs ) { return v <= rhs; }
public LuaValue gt( LuaValue rhs ) { return rhs.lt_b(v)? TRUE: FALSE; } public LuaValue gt( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.lt_b(v)? TRUE: FALSE) : super.gt(rhs); }
public LuaValue gt( double rhs ) { return v > rhs? TRUE: FALSE; } public LuaValue gt( double rhs ) { return v > rhs? TRUE: FALSE; }
public LuaValue gt( int rhs ) { return v > rhs? TRUE: FALSE; } public LuaValue gt( int rhs ) { return v > rhs? TRUE: FALSE; }
public boolean gt_b( LuaValue rhs ) { return rhs.lt_b(v); } public boolean gt_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.lt_b(v) : super.gt_b(rhs); }
public boolean gt_b( int rhs ) { return v > rhs; } public boolean gt_b( int rhs ) { return v > rhs; }
public boolean gt_b( double rhs ) { return v > rhs; } public boolean gt_b( double rhs ) { return v > rhs; }
public LuaValue gteq( LuaValue rhs ) { return rhs.lteq_b(v)? TRUE: FALSE; } public LuaValue gteq( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.lteq_b(v)? TRUE: FALSE) : super.gteq(rhs); }
public LuaValue gteq( double rhs ) { return v >= rhs? TRUE: FALSE; } public LuaValue gteq( double rhs ) { return v >= rhs? TRUE: FALSE; }
public LuaValue gteq( int rhs ) { return v >= rhs? TRUE: FALSE; } public LuaValue gteq( int rhs ) { return v >= rhs? TRUE: FALSE; }
public boolean gteq_b( LuaValue rhs ) { return rhs.lteq_b(v); } public boolean gteq_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.lteq_b(v) : super.gteq_b(rhs); }
public boolean gteq_b( int rhs ) { return v >= rhs; } public boolean gteq_b( int rhs ) { return v >= rhs; }
public boolean gteq_b( double rhs ) { return v >= rhs; } public boolean gteq_b( double rhs ) { return v >= rhs; }
// string comparison // string comparison
public int strcmp( LuaString rhs ) { typerror("attempt to compare number with string"); return 0; } public int strcmp( LuaString rhs ) { typerror("attempt to compare number with string"); return 0; }
public int checkint() { public int checkint() {
return v; return v;
} }
public long checklong() { public long checklong() {
return v; return v;
} }
public double checkdouble() { public double checkdouble() {
return v; return v;
} }
public String checkjstring() { public String checkjstring() {
return String.valueOf(v); return String.valueOf(v);
} }
public LuaString checkstring() { public LuaString checkstring() {
return valueOf( String.valueOf(v) ); return valueOf( String.valueOf(v) );
} }
} }

View File

@@ -31,28 +31,28 @@ import java.io.PrintStream;
import org.luaj.vm2.lib.MathLib; import org.luaj.vm2.lib.MathLib;
/** /**
* Subclass of {@link LuaValue} for representing lua strings. * Subclass of {@link LuaValue} for representing lua strings.
* <p> * <p>
* Because lua string values are more nearly sequences of bytes than * Because lua string values are more nearly sequences of bytes than
* sequences of characters or unicode code points, the {@link LuaString} * sequences of characters or unicode code points, the {@link LuaString}
* implementation holds the string value in an internal byte array. * implementation holds the string value in an internal byte array.
* <p> * <p>
* {@link LuaString} values are not considered mutable once constructed, * {@link LuaString} values are not considered mutable once constructed,
* so multiple {@link LuaString} values can chare a single byte array. * so multiple {@link LuaString} values can chare a single byte array.
* <p> * <p>
* Currently {@link LuaString}s are pooled via a centrally managed weak table. * 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, * To ensure that as many string values as possible take advantage of this,
* Constructors are not exposed directly. As with number, booleans, and nil, * Constructors are not exposed directly. As with number, booleans, and nil,
* instance construction should be via {@link LuaValue#valueOf(byte[])} or similar API. * instance construction should be via {@link LuaValue#valueOf(byte[])} or similar API.
* <p> * <p>
* Because of this pooling, users of LuaString <em>must not directly alter the * Because of this pooling, users of LuaString <em>must not directly alter the
* bytes in a LuaString</em>, or undefined behavior will result. * bytes in a LuaString</em>, or undefined behavior will result.
* <p> * <p>
* When Java Strings are used to initialize {@link LuaString} data, the UTF8 encoding is assumed. * When Java Strings are used to initialize {@link LuaString} data, the UTF8 encoding is assumed.
* The functions * The functions
* {@link #lengthAsUtf8(char[])}, * {@link #lengthAsUtf8(char[])},
* {@link #encodeToUtf8(char[], int, byte[], int)}, and * {@link #encodeToUtf8(char[], int, byte[], int)}, and
* {@link #decodeAsUtf8(byte[], int, int)} * {@link #decodeAsUtf8(byte[], int, int)}
* are used to convert back and forth between UTF8 byte arrays and character arrays. * are used to convert back and forth between UTF8 byte arrays and character arrays.
* *
* @see LuaValue * @see LuaValue
@@ -63,15 +63,15 @@ public class LuaString extends LuaValue {
/** The singleton instance for string metatables that forwards to the string functions. /** 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 * 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 * 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 * 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. * read-only table since it is shared across all lua code in this Java VM.
*/ */
public static LuaValue s_metatable; public static LuaValue s_metatable;
/** The bytes for the string. These <em><b>must not be mutated directly</b></em> because /** The bytes for the string. These <em><b>must not be mutated directly</b></em> because
* the backing may be shared by multiple LuaStrings, and the hash code is * the backing may be shared by multiple LuaStrings, and the hash code is
* computed only at construction time. * computed only at construction time.
* It is exposed only for performance and legacy reasons. */ * It is exposed only for performance and legacy reasons. */
public final byte[] m_bytes; public final byte[] m_bytes;
@@ -84,29 +84,29 @@ public class LuaString extends LuaValue {
/** The hashcode for this string. Computed at construct time. */ /** The hashcode for this string. Computed at construct time. */
private final int m_hashcode; private final int m_hashcode;
/** Size of cache of recent short strings. This is the maximum number of LuaStrings that /** 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. */ * will be retained in the cache of recent short strings. Exposed to package for testing. */
static final int RECENT_STRINGS_CACHE_SIZE = 128; static final int RECENT_STRINGS_CACHE_SIZE = 128;
/** Maximum length of a string to be considered for recent short strings caching. /** 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, * 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. * because no LuaString whose backing exceeds this length will be put into the cache.
* Exposed to package for testing. */ * Exposed to package for testing. */
static final int RECENT_STRINGS_MAX_LENGTH = 32; static final int RECENT_STRINGS_MAX_LENGTH = 32;
/** Simple cache of recently created strings that are short. /** 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 * 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 * 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 * from different contexts, it will generally show up as a cache hit and resolve
* to the same value. */ * to the same value. */
private static final class RecentShortStrings { private static final class RecentShortStrings {
private static final LuaString recent_short_strings[] = private static final LuaString recent_short_strings[] =
new LuaString[RECENT_STRINGS_CACHE_SIZE]; new LuaString[RECENT_STRINGS_CACHE_SIZE];
} }
/** /**
* Get a {@link LuaString} instance whose bytes match * Get a {@link LuaString} instance whose bytes match
* the supplied Java String using the UTF8 encoding. * the supplied Java String using the UTF8 encoding.
* @param string Java String containing characters to encode as UTF8 * @param string Java String containing characters to encode as UTF8
* @return {@link LuaString} with UTF8 bytes corresponding to the supplied String * @return {@link LuaString} with UTF8 bytes corresponding to the supplied String
*/ */
@@ -120,7 +120,7 @@ public class LuaString extends LuaValue {
/** Construct a {@link LuaString} for a portion of a byte array. /** Construct a {@link LuaString} for a portion of a byte array.
* <p> * <p>
* The array is first be used as the backing for this object, so clients must not change contents. * 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 * 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 * 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. * new byte array, and cache lookup may be performed.
* <p> * <p>
@@ -172,11 +172,11 @@ public class LuaString extends LuaValue {
/** Construct a {@link LuaString} using the supplied characters as byte values. /** Construct a {@link LuaString} using the supplied characters as byte values.
* <p> * <p>
* Only the low-order 8-bits of each character are used, the remainder is ignored. * Only the low-order 8-bits of each character are used, the remainder is ignored.
* <p> * <p>
* This is most useful for constructing byte sequences that do not conform to UTF8. * 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. * @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 * @return {@link LuaString} wrapping a copy of the byte buffer
*/ */
public static LuaString valueOf(char[] bytes) { public static LuaString valueOf(char[] bytes) {
return valueOf(bytes, 0, bytes.length); return valueOf(bytes, 0, bytes.length);
@@ -184,11 +184,11 @@ public class LuaString extends LuaValue {
/** Construct a {@link LuaString} using the supplied characters as byte values. /** Construct a {@link LuaString} using the supplied characters as byte values.
* <p> * <p>
* Only the low-order 8-bits of each character are used, the remainder is ignored. * Only the low-order 8-bits of each character are used, the remainder is ignored.
* <p> * <p>
* This is most useful for constructing byte sequences that do not conform to UTF8. * 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. * @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 * @return {@link LuaString} wrapping a copy of the byte buffer
*/ */
public static LuaString valueOf(char[] bytes, int off, int len) { public static LuaString valueOf(char[] bytes, int off, int len) {
byte[] b = new byte[len]; byte[] b = new byte[len];
@@ -215,7 +215,7 @@ public class LuaString extends LuaValue {
* The LuaString returned will either be a new LuaString containing the byte array, * The LuaString returned will either be a new LuaString containing the byte array,
* or be an existing LuaString used already having the same value. * or be an existing LuaString used already having the same value.
* <p> * <p>
* The caller must not mutate the contents of the byte array after this call, as * 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. * it may be used elsewhere due to recent short string caching.
* @param bytes byte buffer * @param bytes byte buffer
* @return {@link LuaString} wrapping the byte buffer * @return {@link LuaString} wrapping the byte buffer
@@ -241,11 +241,11 @@ public class LuaString extends LuaValue {
} }
public boolean isstring() { public boolean isstring() {
return true; return true;
} }
public LuaValue getmetatable() { public LuaValue getmetatable() {
return s_metatable; return s_metatable;
} }
public int type() { public int type() {
@@ -289,20 +289,20 @@ public class LuaString extends LuaValue {
public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs, checkarith()); } public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs, checkarith()); }
// relational operators, these only work with other strings // relational operators, these only work with other strings
public LuaValue lt( LuaValue rhs ) { return rhs.strcmp(this)>0? LuaValue.TRUE: FALSE; } public LuaValue lt( LuaValue rhs ) { return rhs.isstring() ? (rhs.strcmp(this)>0? LuaValue.TRUE: FALSE) : super.lt(rhs); }
public boolean lt_b( LuaValue rhs ) { return rhs.strcmp(this)>0; } public boolean lt_b( LuaValue rhs ) { return rhs.isstring() ? rhs.strcmp(this)>0 : super.lt_b(rhs); }
public boolean lt_b( int rhs ) { typerror("attempt to compare string with number"); return false; } public boolean lt_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
public boolean lt_b( double rhs ) { typerror("attempt to compare string with number"); return false; } public boolean lt_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
public LuaValue lteq( LuaValue rhs ) { return rhs.strcmp(this)>=0? LuaValue.TRUE: FALSE; } public LuaValue lteq( LuaValue rhs ) { return rhs.isstring() ? (rhs.strcmp(this)>=0? LuaValue.TRUE: FALSE) : super.lteq(rhs); }
public boolean lteq_b( LuaValue rhs ) { return rhs.strcmp(this)>=0; } public boolean lteq_b( LuaValue rhs ) { return rhs.isstring() ? rhs.strcmp(this)>=0 : super.lteq_b(rhs); }
public boolean lteq_b( int rhs ) { typerror("attempt to compare string with number"); return false; } public boolean lteq_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
public boolean lteq_b( double rhs ) { typerror("attempt to compare string with number"); return false; } public boolean lteq_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
public LuaValue gt( LuaValue rhs ) { return rhs.strcmp(this)<0? LuaValue.TRUE: FALSE; } public LuaValue gt( LuaValue rhs ) { return rhs.isstring() ? (rhs.strcmp(this)<0? LuaValue.TRUE: FALSE) : super.gt(rhs); }
public boolean gt_b( LuaValue rhs ) { return rhs.strcmp(this)<0; } public boolean gt_b( LuaValue rhs ) { return rhs.isstring() ? rhs.strcmp(this)<0 : super.gt_b(rhs); }
public boolean gt_b( int rhs ) { typerror("attempt to compare string with number"); return false; } public boolean gt_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
public boolean gt_b( double rhs ) { typerror("attempt to compare string with number"); return false; } public boolean gt_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
public LuaValue gteq( LuaValue rhs ) { return rhs.strcmp(this)<=0? LuaValue.TRUE: FALSE; } public LuaValue gteq( LuaValue rhs ) { return rhs.isstring() ? (rhs.strcmp(this)<=0? LuaValue.TRUE: FALSE) : super.gteq(rhs); }
public boolean gteq_b( LuaValue rhs ) { return rhs.strcmp(this)<=0; } public boolean gteq_b( LuaValue rhs ) { return rhs.isstring() ? rhs.strcmp(this)<=0 : super.gteq_b(rhs); }
public boolean gteq_b( int rhs ) { typerror("attempt to compare string with number"); return false; } public boolean gteq_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
public boolean gteq_b( double rhs ) { typerror("attempt to compare string with number"); return false; } public boolean gteq_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
@@ -310,14 +310,14 @@ public class LuaString extends LuaValue {
public LuaValue concat(LuaValue rhs) { return rhs.concatTo(this); } public LuaValue concat(LuaValue rhs) { return rhs.concatTo(this); }
public Buffer concat(Buffer rhs) { return rhs.concatTo(this); } public Buffer concat(Buffer rhs) { return rhs.concatTo(this); }
public LuaValue concatTo(LuaNumber lhs) { return concatTo(lhs.strvalue()); } public LuaValue concatTo(LuaNumber lhs) { return concatTo(lhs.strvalue()); }
public LuaValue concatTo(LuaString lhs) { public LuaValue concatTo(LuaString lhs) {
byte[] b = new byte[lhs.m_length+this.m_length]; 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(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); System.arraycopy(this.m_bytes, this.m_offset, b, lhs.m_length, this.m_length);
return valueUsing(b, 0, b.length); return valueUsing(b, 0, b.length);
} }
// string comparison // string comparison
public int strcmp(LuaValue lhs) { return -lhs.strcmp(this); } public int strcmp(LuaValue lhs) { return -lhs.strcmp(this); }
public int strcmp(LuaString rhs) { public int strcmp(LuaString rhs) {
for ( int i=0, j=0; i<m_length && j<rhs.m_length; ++i, ++j ) { for ( int i=0, j=0; i<m_length && j<rhs.m_length; ++i, ++j ) {
@@ -329,9 +329,9 @@ public class LuaString extends LuaValue {
} }
/** Check for number in arithmetic, or throw aritherror */ /** Check for number in arithmetic, or throw aritherror */
private double checkarith() { private double checkarith() {
double d = scannumber(); double d = scannumber();
if ( Double.isNaN(d) ) if ( Double.isNaN(d) )
aritherror(); aritherror();
return d; return d;
} }
@@ -368,15 +368,15 @@ public class LuaString extends LuaValue {
public boolean isint() { public boolean isint() {
double d = scannumber(); double d = scannumber();
if ( Double.isNaN(d) ) if ( Double.isNaN(d) )
return false; return false;
int i = (int) d; int i = (int) d;
return i == d; return i == d;
} }
public boolean islong() { public boolean islong() {
double d = scannumber(); double d = scannumber();
if ( Double.isNaN(d) ) if ( Double.isNaN(d) )
return false; return false;
long l = (long) d; long l = (long) d;
return l == d; return l == d;
@@ -398,7 +398,7 @@ public class LuaString extends LuaValue {
return checkint(); return checkint();
} }
public LuaInteger optinteger(LuaInteger defval) { public LuaInteger optinteger(LuaInteger defval) {
return checkinteger(); return checkinteger();
} }
@@ -411,15 +411,15 @@ public class LuaString extends LuaValue {
} }
public LuaString optstring(LuaString defval) { public LuaString optstring(LuaString defval) {
return this; return this;
} }
public LuaValue tostring() { public LuaValue tostring() {
return this; return this;
} }
public String optjstring(String defval) { public String optjstring(String defval) {
return tojstring(); return tojstring();
} }
public LuaString strvalue() { public LuaString strvalue() {
@@ -429,7 +429,7 @@ public class LuaString extends LuaValue {
/** Take a substring using Java zero-based indexes for begin and end or range. /** 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 beginIndex The zero-based index of the first character to include.
* @param endIndex The zero-based index of position after the last character. * @param endIndex The zero-based index of position after the last character.
* @return LuaString which is a substring whose first character is at offset * @return LuaString which is a substring whose first character is at offset
* beginIndex and extending for (endIndex - beginIndex ) characters. * beginIndex and extending for (endIndex - beginIndex ) characters.
*/ */
public LuaString substring( int beginIndex, int endIndex ) { public LuaString substring( int beginIndex, int endIndex ) {
@@ -476,7 +476,7 @@ public class LuaString extends LuaValue {
return val.raweq(this); return val.raweq(this);
} }
public boolean raweq( LuaString s ) { public boolean raweq( LuaString s ) {
if ( this == s ) if ( this == s )
return true; return true;
if ( s.m_length != m_length ) if ( s.m_length != m_length )
@@ -503,7 +503,7 @@ public class LuaString extends LuaValue {
public static boolean equals( byte[] a, int i, byte[] b, int j, int n ) { public static boolean equals( byte[] a, int i, byte[] b, int j, int n ) {
if ( a.length < i + n || b.length < j + n ) if ( a.length < i + n || b.length < j + n )
return false; return false;
while ( --n>=0 ) while ( --n>=0 )
if ( a[i++]!=b[j++] ) if ( a[i++]!=b[j++] )
return false; return false;
return true; return true;
@@ -535,8 +535,8 @@ public class LuaString extends LuaValue {
return luaByte( index ); return luaByte( index );
} }
public String checkjstring() { public String checkjstring() {
return tojstring(); return tojstring();
} }
public LuaString checkstring() { public LuaString checkstring() {
@@ -552,7 +552,7 @@ public class LuaString extends LuaValue {
} }
/** /**
* Copy the bytes of the string into the given byte array. * Copy the bytes of the string into the given byte array.
* @param strOffset offset from which to copy * @param strOffset offset from which to copy
* @param bytes destination byte array * @param bytes destination byte array
* @param arrayOffset offset in destination * @param arrayOffset offset in destination
@@ -626,12 +626,12 @@ public class LuaString extends LuaValue {
/** /**
* Convert to Java String interpreting as utf8 characters. * Convert to Java String interpreting as utf8 characters.
* *
* @param bytes byte array in UTF8 encoding to convert * @param bytes byte array in UTF8 encoding to convert
* @param offset starting index in byte array * @param offset starting index in byte array
* @param length number of bytes to convert * @param length number of bytes to convert
* @return Java String corresponding to the value of bytes interpreted using UTF8 * @return Java String corresponding to the value of bytes interpreted using UTF8
* @see #lengthAsUtf8(char[]) * @see #lengthAsUtf8(char[])
* @see #encodeToUtf8(char[], int, byte[], int) * @see #encodeToUtf8(char[], int, byte[], int)
* @see #isValidUtf8() * @see #isValidUtf8()
@@ -692,7 +692,7 @@ public class LuaString extends LuaValue {
/** /**
* Encode the given Java string as UTF-8 bytes, writing the result to bytes * Encode the given Java string as UTF-8 bytes, writing the result to bytes
* starting at offset. * starting at offset.
* <p> * <p>
* The string should be measured first with lengthAsUtf8 * The string should be measured first with lengthAsUtf8
* to make sure the given byte array is large enough. * to make sure the given byte array is large enough.
@@ -759,22 +759,22 @@ public class LuaString extends LuaValue {
// --------------------- number conversion ----------------------- // --------------------- number conversion -----------------------
/** /**
* convert to a number using baee 10 or base 16 if it starts with '0x', * convert to a number using baee 10 or base 16 if it starts with '0x',
* or NIL if it can't be converted * or NIL if it can't be converted
* @return IntValue, DoubleValue, or NIL depending on the content of the string. * @return IntValue, DoubleValue, or NIL depending on the content of the string.
* @see LuaValue#tonumber() * @see LuaValue#tonumber()
*/ */
public LuaValue tonumber() { public LuaValue tonumber() {
double d = scannumber(); double d = scannumber();
return Double.isNaN(d)? NIL: valueOf(d); return Double.isNaN(d)? NIL: valueOf(d);
} }
/** /**
* convert to a number using a supplied base, or NIL if it can't be converted * 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 * @param base the base to use, such as 10
* @return IntValue, DoubleValue, or NIL depending on the content of the string. * @return IntValue, DoubleValue, or NIL depending on the content of the string.
* @see LuaValue#tonumber() * @see LuaValue#tonumber()
*/ */
public LuaValue tonumber( int base ) { public LuaValue tonumber( int base ) {
double d = scannumber( base ); double d = scannumber( base );
@@ -800,7 +800,7 @@ public class LuaString extends LuaValue {
/** /**
* Convert to a number in base 10, or base 16 if the string starts with '0x', * 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. * or return Double.NaN if it cannot be converted to a number.
* @return double value if conversion is valid, or Double.NaN if not * @return double value if conversion is valid, or Double.NaN if not
*/ */
public double scannumber() { public double scannumber() {
int i = m_offset, j = m_offset + m_length; int i = m_offset, j = m_offset + m_length;
@@ -863,10 +863,10 @@ public class LuaString extends LuaValue {
return sgn * m * MathLib.dpow_d(2.0, e); return sgn * m * MathLib.dpow_d(2.0, e);
} }
/** /**
* Convert to a number in a base, or return Double.NaN if not a number. * 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 * @param base the base to use between 2 and 36
* @return double value if conversion is valid, or Double.NaN if not * @return double value if conversion is valid, or Double.NaN if not
*/ */
public double scannumber(int base) { public double scannumber(int base) {
if ( base < 2 || base > 36 ) if ( base < 2 || base > 36 )
@@ -884,7 +884,7 @@ public class LuaString extends LuaValue {
* @param base the base to use, such as 10 * @param base the base to use, such as 10
* @param start the index to start searching from * @param start the index to start searching from
* @param end the first index beyond the search range * @param end the first index beyond the search range
* @return double value if conversion is valid, * @return double value if conversion is valid,
* or Double.NaN if not * or Double.NaN if not
*/ */
private double scanlong( int base, int start, int end ) { private double scanlong( int base, int start, int end ) {
@@ -895,7 +895,7 @@ public class LuaString extends LuaValue {
int digit = m_bytes[i] - (base<=10||(m_bytes[i]>='0'&&m_bytes[i]<='9')? '0': 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)); m_bytes[i]>='A'&&m_bytes[i]<='Z'? ('A'-10): ('a'-10));
if ( digit < 0 || digit >= base ) if ( digit < 0 || digit >= base )
return Double.NaN; return Double.NaN;
x = x * base + digit; x = x * base + digit;
if ( x < 0 ) if ( x < 0 )
return Double.NaN; // overflow return Double.NaN; // overflow
@@ -907,7 +907,7 @@ public class LuaString extends LuaValue {
* Scan and convert a double value, or return Double.NaN if not a double. * Scan and convert a double value, or return Double.NaN if not a double.
* @param start the index to start searching from * @param start the index to start searching from
* @param end the first index beyond the search range * @param end the first index beyond the search range
* @return double value if conversion is valid, * @return double value if conversion is valid,
* or Double.NaN if not * or Double.NaN if not
*/ */
private double scandouble(int start, int end) { private double scandouble(int start, int end) {
@@ -930,7 +930,7 @@ public class LuaString extends LuaValue {
c[i-start] = (char) m_bytes[i]; c[i-start] = (char) m_bytes[i];
try { try {
return Double.parseDouble(new String(c)); return Double.parseDouble(new String(c));
} catch ( Exception e ) { } catch ( Exception e ) {
return Double.NaN; return Double.NaN;
} }
} }

View File

@@ -25,23 +25,23 @@ import java.lang.ref.WeakReference;
import java.util.Vector; import java.util.Vector;
/** /**
* Subclass of {@link LuaValue} for representing lua tables. * Subclass of {@link LuaValue} for representing lua tables.
* <p> * <p>
* 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}.
* <p> * <p>
* If a table is needed, the one of the type-checking functions can be used such as * If a table is needed, the one of the type-checking functions can be used such as
* {@link #istable()}, * {@link #istable()},
* {@link #checktable()}, or * {@link #checktable()}, or
* {@link #opttable(LuaTable)} * {@link #opttable(LuaTable)}
* <p> * <p>
* The main table operations are defined on {@link LuaValue} * The main table operations are defined on {@link LuaValue}
* for getting and setting values with and without metatag processing: * for getting and setting values with and without metatag processing:
* <ul> * <ul>
* <li>{@link #get(LuaValue)}</li> * <li>{@link #get(LuaValue)}</li>
* <li>{@link #set(LuaValue,LuaValue)}</li> * <li>{@link #set(LuaValue,LuaValue)}</li>
* <li>{@link #rawget(LuaValue)}</li> * <li>{@link #rawget(LuaValue)}</li>
* <li>{@link #rawset(LuaValue,LuaValue)}</li> * <li>{@link #rawset(LuaValue,LuaValue)}</li>
* <li>plus overloads such as {@link #get(String)}, {@link #get(int)}, and so on</li> * <li>plus overloads such as {@link #get(String)}, {@link #get(int)}, and so on</li>
* </ul> * </ul>
* <p> * <p>
* To iterate over key-value pairs from Java, use * To iterate over key-value pairs from Java, use
@@ -56,7 +56,7 @@ import java.util.Vector;
* }}</pre> * }}</pre>
* *
* <p> * <p>
* As with other types, {@link LuaTable} instances should be constructed via one of the table constructor * As with other types, {@link LuaTable} instances should be constructed via one of the table constructor
* methods on {@link LuaValue}: * methods on {@link LuaValue}:
* <ul> * <ul>
* <li>{@link LuaValue#tableOf()} empty table</li> * <li>{@link LuaValue#tableOf()} empty table</li>
@@ -92,7 +92,7 @@ public class LuaTable extends LuaValue implements Metatable {
hash = NOBUCKETS; hash = NOBUCKETS;
} }
/** /**
* Construct table with preset capacity. * Construct table with preset capacity.
* @param narray capacity of array part * @param narray capacity of array part
* @param nhash capacity of hash part * @param nhash capacity of hash part
@@ -102,9 +102,9 @@ public class LuaTable extends LuaValue implements Metatable {
} }
/** /**
* Construct table with named and unnamed parts. * 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 unnamed Unnamed elements in order {@code value-1, value-2, ... }
* @param lastarg Additional unnamed values beyond {@code unnamed.length} * @param lastarg Additional unnamed values beyond {@code unnamed.length}
*/ */
public LuaTable(LuaValue[] named, LuaValue[] unnamed, Varargs lastarg) { public LuaTable(LuaValue[] named, LuaValue[] unnamed, Varargs lastarg) {
@@ -123,17 +123,17 @@ public class LuaTable extends LuaValue implements Metatable {
} }
/** /**
* Construct table of unnamed elements. * Construct table of unnamed elements.
* @param varargs Unnamed elements in order {@code value-1, value-2, ... } * @param varargs Unnamed elements in order {@code value-1, value-2, ... }
*/ */
public LuaTable(Varargs varargs) { public LuaTable(Varargs varargs) {
this(varargs,1); this(varargs,1);
} }
/** /**
* Construct table of unnamed elements. * Construct table of unnamed elements.
* @param varargs Unnamed elements in order {@code value-1, value-2, ... } * @param varargs Unnamed elements in order {@code value-1, value-2, ... }
* @param firstarg the index in varargs of the first argument to include in the table * @param firstarg the index in varargs of the first argument to include in the table
*/ */
public LuaTable(Varargs varargs, int firstarg) { public LuaTable(Varargs varargs, int firstarg) {
int nskip = firstarg-1; int nskip = firstarg-1;
@@ -152,8 +152,8 @@ public class LuaTable extends LuaValue implements Metatable {
return "table"; return "table";
} }
public boolean istable() { public boolean istable() {
return true; return true;
} }
public LuaTable checktable() { public LuaTable checktable() {
@@ -185,17 +185,17 @@ public class LuaTable extends LuaValue implements Metatable {
return v; return v;
} }
/** /**
* Get the length of the array part of the table. * Get the length of the array part of the table.
* @return length of the array part, does not relate to count of objects in the table. * @return length of the array part, does not relate to count of objects in the table.
*/ */
protected int getArrayLength() { protected int getArrayLength() {
return array.length; return array.length;
} }
/** /**
* Get the length of the hash part of the table. * Get the length of the hash part of the table.
* @return length of the hash part, does not relate to count of objects in the table. * @return length of the hash part, does not relate to count of objects in the table.
*/ */
protected int getHashLength() { protected int getHashLength() {
return hash.length; return hash.length;
@@ -294,35 +294,35 @@ public class LuaTable extends LuaValue implements Metatable {
} }
/** Remove the element at a position in a list-table /** Remove the element at a position in a list-table
* *
* @param pos the position to remove * @param pos the position to remove
* @return The removed item, or {@link #NONE} if not removed * @return The removed item, or {@link #NONE} if not removed
*/ */
public LuaValue remove(int pos) { public LuaValue remove(int pos) {
int n = rawlen(); int n = length();
if ( pos == 0 ) if ( pos == 0 )
pos = n; pos = n;
else if (pos > n) else if (pos > n)
return NONE; return NONE;
LuaValue v = rawget(pos); LuaValue v = get(pos);
for ( LuaValue r=v; !r.isnil(); ) { for ( LuaValue r=v; !r.isnil(); ) {
r = rawget(pos+1); r = get(pos+1);
rawset(pos++, r); set(pos++, r);
} }
return v.isnil()? NONE: v; return v.isnil()? NONE: v;
} }
/** Insert an element at a position in a list-table /** Insert an element at a position in a list-table
* *
* @param pos the position to remove * @param pos the position to remove
* @param value The value to insert * @param value The value to insert
*/ */
public void insert(int pos, LuaValue value) { public void insert(int pos, LuaValue value) {
if ( pos == 0 ) if ( pos == 0 )
pos = rawlen()+1; pos = length()+1;
while ( ! value.isnil() ) { while ( ! value.isnil() ) {
LuaValue v = rawget( pos ); LuaValue v = get( pos );
rawset(pos++, value); set(pos++, value);
value = v; value = v;
} }
} }
@@ -355,14 +355,14 @@ public class LuaTable extends LuaValue implements Metatable {
return rawlen(); return rawlen();
} }
public LuaValue len() { public LuaValue len() {
final LuaValue h = metatag(LEN); final LuaValue h = metatag(LEN);
if (h.toboolean()) if (h.toboolean())
return h.call(this); return h.call(this);
return LuaInteger.valueOf(rawlen()); return LuaInteger.valueOf(rawlen());
} }
public int rawlen() { public int rawlen() {
int a = getArrayLength(); int a = getArrayLength();
int n = a+1,m=0; int n = a+1,m=0;
while ( !rawget(n).isnil() ) { while ( !rawget(n).isnil() ) {
@@ -380,7 +380,7 @@ public class LuaTable extends LuaValue implements Metatable {
} }
/** /**
* Get the next element after a particular key in the table * Get the next element after a particular key in the table
* @return key,value or nil * @return key,value or nil
*/ */
public Varargs next( LuaValue key ) { public Varargs next( LuaValue key ) {
@@ -441,8 +441,8 @@ public class LuaTable extends LuaValue implements Metatable {
} }
/** /**
* Get the next element after a particular key in the * Get the next element after a particular key in the
* contiguous array part of a table * contiguous array part of a table
* @return key,value or none * @return key,value or none
*/ */
public Varargs inext(LuaValue key) { public Varargs inext(LuaValue key) {
@@ -472,7 +472,8 @@ public class LuaTable extends LuaValue implements Metatable {
} }
} }
if ( checkLoadFactor() ) { if ( checkLoadFactor() ) {
if ( key.isinttype() && key.toint() > 0 ) { if ( (m_metatable == null || !m_metatable.useWeakValues())
&& key.isinttype() && key.toint() > 0 ) {
// a rehash might make room in the array portion for this key. // a rehash might make room in the array portion for this key.
rehash( key.toint() ); rehash( key.toint() );
if ( arrayset(key.toint(), value) ) if ( arrayset(key.toint(), value) )
@@ -517,7 +518,7 @@ public class LuaTable extends LuaValue implements Metatable {
} }
} }
/** /**
* Find the hashtable slot to use * Find the hashtable slot to use
* @param key key to look for * @param key key to look for
* @return slot to use * @return slot to use
@@ -719,7 +720,7 @@ public class LuaTable extends LuaValue implements Metatable {
StrongSlot entry = slot.first(); StrongSlot entry = slot.first();
if (entry != null) if (entry != null)
newArray[ k - 1 ] = entry.value(); newArray[ k - 1 ] = entry.value();
} else { } else if ( !(slot instanceof DeadSlot) ) {
int j = slot.keyindex( newHashMask ); int j = slot.keyindex( newHashMask );
newHash[j] = slot.relink( newHash[j] ); newHash[j] = slot.relink( newHash[j] );
} }
@@ -779,7 +780,7 @@ public class LuaTable extends LuaValue implements Metatable {
// //
// implemented heap sort from wikipedia // implemented heap sort from wikipedia
// //
// Only sorts the contiguous array part. // Only sorts the contiguous array part.
// //
/** Sort the table using a comparator. /** Sort the table using a comparator.
* @param comparator {@link LuaValue} to be called to compare elements. * @param comparator {@link LuaValue} to be called to compare elements.
@@ -789,33 +790,35 @@ public class LuaTable extends LuaValue implements Metatable {
if (m_metatable != null && m_metatable.useWeakValues()) { if (m_metatable != null && m_metatable.useWeakValues()) {
dropWeakArrayValues(); dropWeakArrayValues();
} }
int n = array.length; int n = length();
while ( n > 0 && array[n-1] == null ) if ( n > 1 )
--n; heapSort(n, comparator.isnil() ? null : comparator);
if ( n > 1 )
heapSort(n, comparator);
} }
private void heapSort(int count, LuaValue cmpfunc) { private void heapSort(int count, LuaValue cmpfunc) {
heapify(count, cmpfunc); heapify(count, cmpfunc);
for ( int end=count-1; end>0; ) { for ( int end=count; end>1; ) {
swap(end, 0); LuaValue a = get(end); // swap(end, 1)
siftDown(0, --end, cmpfunc); set(end, get(1));
set(1, a);
siftDown(1, --end, cmpfunc);
} }
} }
private void heapify(int count, LuaValue cmpfunc) { private void heapify(int count, LuaValue cmpfunc) {
for ( int start=count/2-1; start>=0; --start ) for ( int start=count/2; start>0; --start )
siftDown(start, count - 1, cmpfunc); siftDown(start, count, cmpfunc);
} }
private void siftDown(int start, int end, LuaValue cmpfunc) { private void siftDown(int start, int end, LuaValue cmpfunc) {
for ( int root=start; root*2+1 <= end; ) { for ( int root=start; root*2 <= end; ) {
int child = root*2+1; int child = root*2;
if (child < end && compare(child, child + 1, cmpfunc)) if (child < end && compare(child, child + 1, cmpfunc))
++child; ++child;
if (compare(root, child, cmpfunc)) { if (compare(root, child, cmpfunc)) {
swap(root, child); LuaValue a = get(root); // swap(root, child)
set(root, get(child));
set(child, a);
root = child; root = child;
} else } else
return; return;
@@ -823,32 +826,19 @@ public class LuaTable extends LuaValue implements Metatable {
} }
private boolean compare(int i, int j, LuaValue cmpfunc) { private boolean compare(int i, int j, LuaValue cmpfunc) {
LuaValue a, b; LuaValue a = get(i), b = get(j);
if (m_metatable == null) {
a = array[i];
b = array[j];
} else {
a = m_metatable.arrayget(array, i);
b = m_metatable.arrayget(array, j);
}
if ( a == null || b == null ) if ( a == null || b == null )
return false; return false;
if ( ! cmpfunc.isnil() ) { if ( cmpfunc != null ) {
return cmpfunc.call(a,b).toboolean(); return cmpfunc.call(a,b).toboolean();
} else { } else {
return a.lt_b(b); return a.lt_b(b);
} }
} }
private void swap(int i, int j) { /** This may be deprecated in a future release.
LuaValue a = array[i];
array[i] = array[j];
array[j] = a;
}
/** This may be deprecated in a future release.
* It is recommended to count via iteration over next() instead * It is recommended to count via iteration over next() instead
* @return count of keys in the table * @return count of keys in the table
* */ * */
public int keyCount() { public int keyCount() {
LuaValue k = LuaValue.NIL; LuaValue k = LuaValue.NIL;
@@ -859,9 +849,9 @@ public class LuaTable extends LuaValue implements Metatable {
} }
} }
/** This may be deprecated in a future release. /** This may be deprecated in a future release.
* It is recommended to use next() instead * It is recommended to use next() instead
* @return array of keys in the table * @return array of keys in the table
* */ * */
public LuaValue[] keys() { public LuaValue[] keys() {
Vector l = new Vector(); Vector l = new Vector();

View File

@@ -24,16 +24,16 @@ 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.
* <p> * <p>
* To construct varargs, use one of the static methods such as * To construct varargs, use one of the static methods such as
* {@code LuaValue.varargsOf(LuaValue,LuaValue)} * {@code LuaValue.varargsOf(LuaValue,LuaValue)}
* <p> * <p>
* <p> * <p>
* Any LuaValue can be used as a stand-in for Varargs, for both calls and return values. * 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. * 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 * This simplifies the case when calling or implementing varargs functions with only
* 1 argument or 1 return value. * 1 argument or 1 return value.
* <p> * <p>
* Varargs can also be derived from other varargs by appending to the front with a call * Varargs can also be derived from other varargs by appending to the front with a call
* such as {@code LuaValue.varargsOf(LuaValue,Varargs)} * such as {@code LuaValue.varargsOf(LuaValue,Varargs)}
* or by taking a portion of the args using {@code Varargs.subargs(int start)} * or by taking a portion of the args using {@code Varargs.subargs(int start)}
* <p> * <p>
@@ -57,22 +57,22 @@ public abstract class Varargs {
abstract public LuaValue arg( int i ); abstract public LuaValue arg( int i );
/** /**
* Get the number of arguments, or 0 if there are none. * Get the number of arguments, or 0 if there are none.
* @return number of arguments. * @return number of arguments.
*/ */
abstract public int narg(); abstract public int narg();
/** /**
* Get the first argument in the list. * 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 Varargs#arg(int)
* @see LuaValue#NIL * @see LuaValue#NIL
*/ */
abstract public LuaValue arg1(); abstract public LuaValue arg1();
/** /**
* Evaluate any pending tail call and return result. * Evaluate any pending tail call and return result.
* @return the evaluated tail call result * @return the evaluated tail call result
*/ */
public Varargs eval() { return this; } public Varargs eval() { return this; }
@@ -88,7 +88,7 @@ public abstract class Varargs {
// utilities to get specific arguments and type-check them. // 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 * @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#TNIL
@@ -117,20 +117,20 @@ public abstract class Varargs {
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. /** Tests if argument i is a number.
* Since anywhere a number is required, a string can be used that * Since anywhere a number is required, a string can be used that
* is a number, this will return true for both numbers and * is a number, this will return true for both numbers and
* strings that can be interpreted as numbers. * strings that can be interpreted as numbers.
* @param i the index of the argument to test, 1 is the first argument * @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 * @return true if the argument exists and is a number or
* string that can be interpreted as a number, false otherwise * string that can be interpreted as a number, false otherwise
* @see LuaValue#TNUMBER * @see LuaValue#TNUMBER
* @see LuaValue#TSTRING * @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. /** Tests if argument i is a string.
* Since all lua numbers can be used where strings are used, * Since all lua numbers can be used where strings are used,
* this will return true for both strings and numbers. * this will return true for both strings and numbers.
* @param i the index of the argument to test, 1 is the first argument * @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#TNUMBER
@@ -167,7 +167,7 @@ public abstract class Varargs {
/** Return argument i as a boolean value, {@code defval} if nil, or throw a LuaError if any other type. /** 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 * @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 * @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); }
@@ -256,7 +256,7 @@ public abstract class Varargs {
* */ * */
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, /** 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. * {@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 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 * @param c the class to which the userdata instance must be assignable
@@ -291,7 +291,7 @@ public abstract class Varargs {
* @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 * @exception LuaError if the argument is not a number
* */ * */
public double checkdouble(int i) { return arg(i).checknumber().todouble(); } 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 * @param i the index of the argument to test, 1 is the first argument
@@ -300,12 +300,12 @@ public abstract class Varargs {
* */ * */
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, discarding any fractional part, or throw an error if not a number. /** 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 * @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 * @return int value if argument i is a number or string that converts to a number
* @exception LuaError if the argument is not a number * @exception LuaError if the argument cannot be represented by a java int value
* */ * */
public int checkint(int i) { return arg(i).checknumber().toint(); } 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 * @param i the index of the argument to test, 1 is the first argument
@@ -314,12 +314,12 @@ public abstract class Varargs {
* */ * */
public LuaInteger checkinteger(int i) { return arg(i).checkinteger(); } public LuaInteger checkinteger(int i) { return arg(i).checkinteger(); }
/** Return argument i as a java long value, discarding any fractional part, or throw an error if not a number. /** 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 * @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 * @return long value if argument i is a number or string that converts to a number
* @exception LuaError if the argument is not a number * @exception LuaError if the argument cannot be represented by a java long value
* */ * */
public long checklong(int i) { return arg(i).checknumber().tolong(); } 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 * @param i the index of the argument to test, 1 is the first argument
@@ -363,7 +363,7 @@ public abstract class Varargs {
* */ * */
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, /** 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. * or throw an error if any other type.
* @param i the index of the argument to test, 1 is the first argument * @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 * @param c the class to which the userdata instance must be assignable
@@ -387,7 +387,7 @@ public abstract class Varargs {
public LuaValue checknotnil(int i) { return arg(i).checknotnil(); } 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. /** 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 * Returns normally if the value of {@code test} is {@code true}, otherwise throws and argument error with
* the supplied message, {@code msg}. * the supplied message, {@code msg}.
* @param test user supplied assertion to test against * @param test user supplied assertion to test against
* @param i the index to report in any error message * @param i the index to report in any error message
@@ -404,20 +404,20 @@ public abstract class Varargs {
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. /** 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 * @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} * @return {@code false} if argument i is nil or false, otherwise {@code true}
* */ * */
public boolean toboolean(int i) { return arg(i).toboolean(); } public boolean toboolean(int i) { return arg(i).toboolean(); }
/** Return argument i as a java byte value, discarding any fractional part and truncating, /** Return argument i as a java byte value, discarding any fractional part and truncating,
* or 0 if not a number. * or 0 if not a number.
* @param i the index of the argument to convert, 1 is the first argument * @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 * @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(); } public byte tobyte(int i) { return arg(i).tobyte(); }
/** Return argument i as a java char value, discarding any fractional part and truncating, /** Return argument i as a java char value, discarding any fractional part and truncating,
* or 0 if not a number. * or 0 if not a number.
* @param i the index of the argument to convert, 1 is the first argument * @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 * @return char value with fraction discarded and truncated if necessary if argument i is number, otherwise 0
@@ -430,21 +430,21 @@ public abstract class Varargs {
* */ * */
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, /** Return argument i as a java float value, discarding excess fractional part and truncating,
* or 0 if not a number. * or 0 if not a number.
* @param i the index of the argument to convert, 1 is the first argument * @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 * @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(); } public float tofloat(int i) { return arg(i).tofloat(); }
/** Return argument i as a java int value, discarding any fractional part and truncating, /** Return argument i as a java int value, discarding any fractional part and truncating,
* or 0 if not a number. * or 0 if not a number.
* @param i the index of the argument to convert, 1 is the first argument * @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 * @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(); } public int toint(int i) { return arg(i).toint(); }
/** Return argument i as a java long value, discarding any fractional part and truncating, /** Return argument i as a java long value, discarding any fractional part and truncating,
* or 0 if not a number. * or 0 if not a number.
* @param i the index of the argument to convert, 1 is the first argument * @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 * @return long value with fraction discarded and truncated if necessary if argument i is number, otherwise 0
@@ -457,7 +457,7 @@ public abstract class Varargs {
* */ * */
public String tojstring(int i) { return arg(i).tojstring(); } public String tojstring(int i) { return arg(i).tojstring(); }
/** Return argument i as a java short value, discarding any fractional part and truncating, /** Return argument i as a java short value, discarding any fractional part and truncating,
* or 0 if not a number. * or 0 if not a number.
* @param i the index of the argument to convert, 1 is the first argument * @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 * @return short value with fraction discarded and truncated if necessary if argument i is number, otherwise 0
@@ -477,8 +477,8 @@ public abstract class Varargs {
* */ * */
public Object touserdata(int i,Class c) { return arg(i).touserdata(c); } public Object touserdata(int i,Class c) { return arg(i).touserdata(c); }
/** Convert the list of varargs values to a human readable java String. /** Convert the list of varargs values to a human readable java String.
* @return String value in human readable form such as {1,2}. * @return String value in human readable form such as {1,2}.
*/ */
public String tojstring() { public String tojstring() {
Buffer sb = new Buffer(); Buffer sb = new Buffer();
@@ -491,8 +491,8 @@ public abstract class Varargs {
return sb.tojstring(); 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. * @return String value in human readable form.
* @see Varargs#tojstring() * @see Varargs#tojstring()
*/ */
public String toString() { return tojstring(); } public String toString() { return tojstring(); }
@@ -544,21 +544,21 @@ public abstract class Varargs {
} }
} }
/** Varargs implemenation backed by two values. /** Varargs implemenation backed by two values.
* <p> * <p>
* This is an internal class not intended to be used directly. * This is an internal class not intended to be used directly.
* Instead use the corresponding static method on LuaValue. * Instead use the corresponding static method on LuaValue.
* *
* @see LuaValue#varargsOf(LuaValue, Varargs) * @see LuaValue#varargsOf(LuaValue, Varargs)
*/ */
static final class PairVarargs extends Varargs { static final class PairVarargs extends Varargs {
private final LuaValue v1; private final LuaValue v1;
private final Varargs v2; private final Varargs v2;
/** Construct a Varargs from an two LuaValue. /** Construct a Varargs from an two LuaValue.
* <p> * <p>
* This is an internal class not intended to be used directly. * This is an internal class not intended to be used directly.
* Instead use the corresponding static method on LuaValue. * Instead use the corresponding static method on LuaValue.
* *
* @see LuaValue#varargsOf(LuaValue, Varargs) * @see LuaValue#varargsOf(LuaValue, Varargs)
*/ */
PairVarargs(LuaValue v1, Varargs v2) { PairVarargs(LuaValue v1, Varargs v2) {
@@ -571,8 +571,8 @@ public abstract class Varargs {
public int narg() { public int narg() {
return 1+v2.narg(); return 1+v2.narg();
} }
public LuaValue arg1() { public LuaValue arg1() {
return v1; return v1;
} }
public Varargs subargs(final int start) { public Varargs subargs(final int start) {
if (start == 1) if (start == 1)
@@ -585,22 +585,22 @@ public abstract class Varargs {
} }
} }
/** Varargs implemenation backed by an array of LuaValues /** Varargs implemenation backed by an array of LuaValues
* <p> * <p>
* This is an internal class not intended to be used directly. * This is an internal class not intended to be used directly.
* Instead use the corresponding static methods on LuaValue. * Instead use the corresponding static methods on LuaValue.
* *
* @see LuaValue#varargsOf(LuaValue[]) * @see LuaValue#varargsOf(LuaValue[])
* @see LuaValue#varargsOf(LuaValue[], Varargs) * @see LuaValue#varargsOf(LuaValue[], Varargs)
*/ */
static final class ArrayVarargs extends Varargs { static final class ArrayVarargs extends Varargs {
private final LuaValue[] v; private final LuaValue[] v;
private final Varargs r; private final Varargs r;
/** Construct a Varargs from an array of LuaValue. /** Construct a Varargs from an array of LuaValue.
* <p> * <p>
* This is an internal class not intended to be used directly. * This is an internal class not intended to be used directly.
* Instead use the corresponding static methods on LuaValue. * Instead use the corresponding static methods on LuaValue.
* *
* @see LuaValue#varargsOf(LuaValue[]) * @see LuaValue#varargsOf(LuaValue[])
* @see LuaValue#varargsOf(LuaValue[], Varargs) * @see LuaValue#varargsOf(LuaValue[], Varargs)
*/ */
@@ -631,11 +631,11 @@ public abstract class Varargs {
} }
} }
/** Varargs implemenation backed by an array of LuaValues /** Varargs implemenation backed by an array of LuaValues
* <p> * <p>
* This is an internal class not intended to be used directly. * This is an internal class not intended to be used directly.
* Instead use the corresponding static methods on LuaValue. * Instead use the corresponding static methods on LuaValue.
* *
* @see LuaValue#varargsOf(LuaValue[], int, int) * @see LuaValue#varargsOf(LuaValue[], int, int)
* @see LuaValue#varargsOf(LuaValue[], int, int, Varargs) * @see LuaValue#varargsOf(LuaValue[], int, int, Varargs)
*/ */
@@ -644,11 +644,11 @@ public abstract class Varargs {
private final LuaValue[] v; private final LuaValue[] v;
private final int length; private final int length;
private final Varargs more; private final Varargs more;
/** Construct a Varargs from an array of LuaValue. /** Construct a Varargs from an array of LuaValue.
* <p> * <p>
* This is an internal class not intended to be used directly. * This is an internal class not intended to be used directly.
* Instead use the corresponding static methods on LuaValue. * Instead use the corresponding static methods on LuaValue.
* *
* @see LuaValue#varargsOf(LuaValue[], int, int) * @see LuaValue#varargsOf(LuaValue[], int, int)
*/ */
ArrayPartVarargs(LuaValue[] v, int offset, int length) { ArrayPartVarargs(LuaValue[] v, int offset, int length) {
@@ -657,11 +657,11 @@ public abstract class Varargs {
this.length = length; this.length = length;
this.more = LuaValue.NONE; 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.
* <p> * <p>
* This is an internal class not intended to be used directly. * This is an internal class not intended to be used directly.
* Instead use the corresponding static method on LuaValue. * Instead use the corresponding static method on LuaValue.
* *
* @see LuaValue#varargsOf(LuaValue[], int, int, Varargs) * @see LuaValue#varargsOf(LuaValue[], int, int, Varargs)
*/ */
public ArrayPartVarargs(LuaValue[] v, int offset, int length, Varargs more) { public ArrayPartVarargs(LuaValue[] v, int offset, int length, Varargs more) {
@@ -676,8 +676,8 @@ public abstract class Varargs {
public int narg() { public int narg() {
return length + more.narg(); return length + more.narg();
} }
public LuaValue arg1() { public LuaValue arg1() {
return length>0? v[offset]: more.arg1(); return length>0? v[offset]: more.arg1();
} }
public Varargs subargs(int start) { public Varargs subargs(int start) {
if (start <= 0) if (start <= 0)
@@ -707,8 +707,10 @@ public abstract class Varargs {
/** Return Varargs that cannot be using a shared array for the storage, and is flattened. /** Return Varargs that cannot be using a shared array for the storage, and is flattened.
* Internal utility method not intended to be called directly from user code. * Internal utility method not intended to be called directly from user code.
* @return Varargs containing same values, but flattened and with a new array if needed. * @return Varargs containing same values, but flattened and with a new array if needed.
* @exclude
* @hide
*/ */
Varargs dealias() { public Varargs dealias() {
int n = narg(); int n = narg();
switch (n) { switch (n) {
case 0: return LuaValue.NONE; case 0: return LuaValue.NONE;

View File

@@ -28,14 +28,14 @@ import java.io.OutputStream;
import org.luaj.vm2.Globals; import org.luaj.vm2.Globals;
import org.luaj.vm2.LoadState; import org.luaj.vm2.LoadState;
import org.luaj.vm2.LocVars; import org.luaj.vm2.LocVars;
import org.luaj.vm2.Prototype;
import org.luaj.vm2.LuaString; import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaValue; import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Prototype;
/** Class to dump a {@link Prototype} into an output stream, as part of compiling. /** Class to dump a {@link Prototype} into an output stream, as part of compiling.
* <p> * <p>
* Generally, this class is not used directly, but rather indirectly via a command * Generally, this class is not used directly, but rather indirectly via a command
* line interface tool such as {@link luac}. * line interface tool such as {@link luac}.
* <p> * <p>
* A lua binary file is created via {@link DumpState#dump}: * A lua binary file is created via {@link DumpState#dump}:
@@ -85,7 +85,7 @@ public class DumpState {
public static final int NUMBER_FORMAT_DEFAULT = NUMBER_FORMAT_FLOATS_OR_DOUBLES; public static final int NUMBER_FORMAT_DEFAULT = NUMBER_FORMAT_FLOATS_OR_DOUBLES;
// header fields // header fields
private boolean IS_LITTLE_ENDIAN = false; private boolean IS_LITTLE_ENDIAN = true;
private int NUMBER_FORMAT = NUMBER_FORMAT_DEFAULT; private int NUMBER_FORMAT = NUMBER_FORMAT_DEFAULT;
private int SIZEOF_LUA_NUMBER = 8; private int SIZEOF_LUA_NUMBER = 8;
private static final int SIZEOF_INT = 4; private static final int SIZEOF_INT = 4;
@@ -190,7 +190,7 @@ public class DumpState {
dumpString((LuaString)o); dumpString((LuaString)o);
break; break;
default: default:
throw new IllegalArgumentException("bad type for " + o); throw new IllegalArgumentException("bad type for " + o);
} }
} }
n = f.p.length; n = f.p.length;

View File

@@ -198,7 +198,7 @@ public class LexState extends Constants {
} }
private boolean isspace(int c) { private boolean isspace(int c) {
return (c <= ' '); return (c >= 0 && c <= ' ');
} }
@@ -388,8 +388,13 @@ public class LexState extends Constants {
seminfo.r = LuaValue.ZERO; seminfo.r = LuaValue.ZERO;
else if (str.indexOf('x')>=0 || str.indexOf('X')>=0) else if (str.indexOf('x')>=0 || str.indexOf('X')>=0)
seminfo.r = strx2number(str, seminfo); seminfo.r = strx2number(str, seminfo);
else else {
seminfo.r = LuaValue.valueOf(Double.parseDouble(str.trim())); try {
seminfo.r = LuaValue.valueOf(Double.parseDouble(str.trim()));
} catch (NumberFormatException e) {
lexerror("malformed number (" + e.getMessage() + ")", TK_NUMBER);
}
}
return true; return true;
} }
@@ -408,7 +413,6 @@ public class LexState extends Constants {
else else
break; break;
} }
save('\0');
String str = new String(buff, 0, nbuff); String str = new String(buff, 0, nbuff);
str2d(str, seminfo); str2d(str, seminfo);
} }
@@ -585,6 +589,13 @@ public class LexState extends Constants {
inclinenumber(); inclinenumber();
continue; continue;
} }
case ' ':
case '\f':
case '\t':
case 0x0B: /* \v */ {
nextChar();
continue;
}
case '-': { case '-': {
nextChar(); nextChar();
if (current != '-') if (current != '-')
@@ -688,19 +699,12 @@ public class LexState extends Constants {
return TK_EOF; return TK_EOF;
} }
default: { default: {
if (isspace(current)) { if (isalpha(current) || current == '_') {
_assert (!currIsNewline());
nextChar();
continue;
} else if (isdigit(current)) {
read_numeral(seminfo);
return TK_NUMBER;
} else if (isalpha(current) || current == '_') {
/* identifier or reserved word */ /* identifier or reserved word */
LuaString ts; LuaString ts;
do { do {
save_and_next(); save_and_next();
} while (isalnum(current) || current == '_'); } while (isalnum(current));
ts = newstring(buff, 0, nbuff); ts = newstring(buff, 0, nbuff);
if ( RESERVED.containsKey(ts) ) if ( RESERVED.containsKey(ts) )
return ((Integer)RESERVED.get(ts)).intValue(); return ((Integer)RESERVED.get(ts)).intValue();
@@ -1744,7 +1748,7 @@ public class LexState extends Constants {
fs.checkrepeated(dyd.label, dyd.n_label, label); /* check for repeated labels */ fs.checkrepeated(dyd.label, dyd.n_label, label); /* check for repeated labels */
checknext(TK_DBCOLON); /* skip double colon */ checknext(TK_DBCOLON); /* skip double colon */
/* create new entry for this label */ /* create new entry for this label */
l = newlabelentry(dyd.label=grow(dyd.label, dyd.n_label+1), dyd.n_label++, label, line, fs.pc); l = newlabelentry(dyd.label=grow(dyd.label, dyd.n_label+1), dyd.n_label++, label, line, fs.getlabel());
skipnoopstat(); /* skip other no-op statements */ skipnoopstat(); /* skip other no-op statements */
if (block_follow(false)) { /* label is last no-op statement in the block? */ if (block_follow(false)) { /* label is last no-op statement in the block? */
/* assume that locals are already out of scope */ /* assume that locals are already out of scope */

View File

@@ -151,7 +151,7 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
System.gc(); System.gc();
return LuaValue.TRUE; return LuaValue.TRUE;
} else { } else {
this.argerror("gc op"); argerror(1, "invalid option '" + s + "'");
} }
return NIL; return NIL;
} }
@@ -172,16 +172,16 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
// "error", // ( message [,level] ) -> ERR // "error", // ( message [,level] ) -> ERR
static final class error extends TwoArgFunction { static final class error extends TwoArgFunction {
public LuaValue call(LuaValue arg1, LuaValue arg2) { public LuaValue call(LuaValue arg1, LuaValue arg2) {
throw arg1.isnil()? new LuaError(null, arg2.optint(1)): if (arg1.isnil()) throw new LuaError(NIL);
arg1.isstring()? new LuaError(arg1.tojstring(), arg2.optint(1)): if (!arg1.isstring() || arg2.optint(1) == 0) throw new LuaError(arg1);
new LuaError(arg1); throw new LuaError(arg1.tojstring(), arg2.optint(1));
} }
} }
// "getmetatable", // ( object ) -> table // "getmetatable", // ( object ) -> table
static final class getmetatable extends LibFunction { static final class getmetatable extends LibFunction {
public LuaValue call() { public LuaValue call() {
return argerror(1, "value"); return argerror(1, "value expected");
} }
public LuaValue call(LuaValue arg) { public LuaValue call(LuaValue arg) {
LuaValue mt = arg.getmetatable(); LuaValue mt = arg.getmetatable();
@@ -192,7 +192,9 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
final class load extends VarArgFunction { final class load extends VarArgFunction {
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
LuaValue ld = args.arg1(); LuaValue ld = args.arg1();
args.argcheck(ld.isstring() || ld.isfunction(), 1, "ld must be string or function"); 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 source = args.optjstring(2, ld.isstring()? ld.tojstring(): "=(load)");
String mode = args.optjstring(3, "bt"); String mode = args.optjstring(3, "bt");
LuaValue env = args.optvalue(4, globals); LuaValue env = args.optvalue(4, globals);
@@ -257,10 +259,10 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
// "rawequal", // (v1, v2) -> boolean // "rawequal", // (v1, v2) -> boolean
static final class rawequal extends LibFunction { static final class rawequal extends LibFunction {
public LuaValue call() { public LuaValue call() {
return argerror(1, "value"); return argerror(1, "value expected");
} }
public LuaValue call(LuaValue arg) { public LuaValue call(LuaValue arg) {
return argerror(2, "value"); return argerror(2, "value expected");
} }
public LuaValue call(LuaValue arg1, LuaValue arg2) { public LuaValue call(LuaValue arg1, LuaValue arg2) {
return valueOf(arg1.raweq(arg2)); return valueOf(arg1.raweq(arg2));
@@ -268,12 +270,12 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
} }
// "rawget", // (table, index) -> value // "rawget", // (table, index) -> value
static final class rawget extends LibFunction { static final class rawget extends TableLibFunction {
public LuaValue call() { public LuaValue call() {
return argerror(1, "value"); return argerror(1, "value expected");
} }
public LuaValue call(LuaValue arg) { public LuaValue call(LuaValue arg) {
return argerror(2, "value"); return argerror(2, "value expected");
} }
public LuaValue call(LuaValue arg1, LuaValue arg2) { public LuaValue call(LuaValue arg1, LuaValue arg2) {
return arg1.checktable().rawget(arg2); return arg1.checktable().rawget(arg2);
@@ -289,16 +291,16 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
} }
// "rawset", // (table, index, value) -> table // "rawset", // (table, index, value) -> table
static final class rawset extends LibFunction { static final class rawset extends TableLibFunction {
public LuaValue call(LuaValue table) { public LuaValue call(LuaValue table) {
return argerror(2,"value"); return argerror(2,"value expected");
} }
public LuaValue call(LuaValue table, LuaValue index) { public LuaValue call(LuaValue table, LuaValue index) {
return argerror(3,"value"); return argerror(3,"value expected");
} }
public LuaValue call(LuaValue table, LuaValue index, LuaValue value) { public LuaValue call(LuaValue table, LuaValue index, LuaValue value) {
LuaTable t = table.checktable(); LuaTable t = table.checktable();
if (!index.isvalidkey()) argerror(2, "value"); if (!index.isvalidkey()) argerror(2, "table index is nil");
t.rawset(index, value); t.rawset(index, value);
return t; return t;
} }
@@ -318,9 +320,9 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
} }
// "setmetatable", // (table, metatable) -> table // "setmetatable", // (table, metatable) -> table
static final class setmetatable extends LibFunction { static final class setmetatable extends TableLibFunction {
public LuaValue call(LuaValue table) { public LuaValue call(LuaValue table) {
return argerror(2,"value"); return argerror(2,"nil or table expected");
} }
public LuaValue call(LuaValue table, LuaValue metatable) { public LuaValue call(LuaValue table, LuaValue metatable) {
final LuaValue mt0 = table.checktable().getmetatable(); final LuaValue mt0 = table.checktable().getmetatable();
@@ -471,10 +473,12 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
this.func = func; this.func = func;
} }
public int read() throws IOException { public int read() throws IOException {
if ( remaining <= 0 ) { if ( remaining < 0 )
return -1;
if ( remaining == 0 ) {
LuaValue s = func.call(); LuaValue s = func.call();
if ( s.isnil() ) if ( s.isnil() )
return -1; return remaining = -1;
LuaString ls = s.strvalue(); LuaString ls = s.strvalue();
bytes = ls.m_bytes; bytes = ls.m_bytes;
offset = ls.m_offset; offset = ls.m_offset;

View File

@@ -442,6 +442,10 @@ public class DebugLib extends TwoArgFunction {
return callstack().traceback(level); return callstack().traceback(level);
} }
public CallFrame getCallFrame(int level) {
return callstack().getCallFrame(level);
}
void callHook(LuaThread.State s, LuaValue type, LuaValue arg) { void callHook(LuaThread.State s, LuaValue type, LuaValue arg) {
if (s.inhook || s.hookfunc == null) return; if (s.inhook || s.hookfunc == null) return;
s.inhook = true; s.inhook = true;
@@ -645,7 +649,7 @@ public class DebugLib extends TwoArgFunction {
} }
static class CallFrame { public static class CallFrame {
LuaFunction f; LuaFunction f;
int pc; int pc;
int top; int top;
@@ -691,7 +695,7 @@ public class DebugLib extends TwoArgFunction {
return NIL; return NIL;
} }
} }
int currentline() { public int currentline() {
if ( !f.isclosure() ) return -1; if ( !f.isclosure() ) return -1;
int[] li = f.checkclosure().p.lineinfo; int[] li = f.checkclosure().p.lineinfo;
return li==null || pc<0 || pc>=li.length? -1: li[pc]; return li==null || pc<0 || pc>=li.length? -1: li[pc];
@@ -796,13 +800,13 @@ public class DebugLib extends TwoArgFunction {
LuaString vn = (Lua.GET_OPCODE(i) == Lua.OP_GETTABLE) /* name of indexed variable */ LuaString vn = (Lua.GET_OPCODE(i) == Lua.OP_GETTABLE) /* name of indexed variable */
? p.getlocalname(t + 1, pc) ? p.getlocalname(t + 1, pc)
: (t < p.upvalues.length ? p.upvalues[t].name : QMARK); : (t < p.upvalues.length ? p.upvalues[t].name : QMARK);
name = kname(p, k); String jname = kname(p, pc, k);
return new NameWhat( name.tojstring(), vn != null && vn.eq_b(ENV)? "global": "field" ); return new NameWhat( jname, vn != null && vn.eq_b(ENV)? "global": "field" );
} }
case Lua.OP_GETUPVAL: { case Lua.OP_GETUPVAL: {
int u = Lua.GETARG_B(i); /* upvalue index */ int u = Lua.GETARG_B(i); /* upvalue index */
name = u < p.upvalues.length ? p.upvalues[u].name : QMARK; name = u < p.upvalues.length ? p.upvalues[u].name : QMARK;
return new NameWhat( name.tojstring(), "upvalue" ); return name == null ? null : new NameWhat( name.tojstring(), "upvalue" );
} }
case Lua.OP_LOADK: case Lua.OP_LOADK:
case Lua.OP_LOADKX: { case Lua.OP_LOADKX: {
@@ -816,8 +820,8 @@ public class DebugLib extends TwoArgFunction {
} }
case Lua.OP_SELF: { case Lua.OP_SELF: {
int k = Lua.GETARG_C(i); /* key index */ int k = Lua.GETARG_C(i); /* key index */
name = kname(p, k); String jname = kname(p, pc, k);
return new NameWhat( name.tojstring(), "method" ); return new NameWhat( jname, "method" );
} }
default: default:
break; break;
@@ -826,11 +830,20 @@ public class DebugLib extends TwoArgFunction {
return null; /* no useful name found */ return null; /* no useful name found */
} }
static LuaString kname(Prototype p, int c) { static String kname(Prototype p, int pc, int c) {
if (Lua.ISK(c) && p.k[Lua.INDEXK(c)].isstring()) if (Lua.ISK(c)) { /* is 'c' a constant? */
return p.k[Lua.INDEXK(c)].strvalue(); LuaValue k = p.k[Lua.INDEXK(c)];
else if (k.isstring()) { /* literal constant? */
return QMARK; return k.tojstring(); /* it is its own name */
} /* else no reasonable name found */
} else { /* 'c' is a register */
NameWhat what = getobjname(p, pc, c); /* search for 'c' */
if (what != null && "constant".equals(what.namewhat)) { /* found a constant name? */
return what.name; /* 'name' already filled */
}
/* else no reasonable name found */
}
return "?"; /* no reasonable name found */
} }
/* /*

View File

@@ -95,6 +95,12 @@ public class IoLib extends TwoArgFunction {
// return number of bytes read if positive, false if eof, throw IOException on other exception // 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; abstract public int read(byte[] bytes, int offset, int length) throws IOException;
public boolean eof() throws IOException {
try {
return peek() < 0;
} catch (EOFException e) { return true; }
}
// delegate method access to file methods table // delegate method access to file methods table
public LuaValue get( LuaValue key ) { public LuaValue get( LuaValue key ) {
return filemethods.get(key); return filemethods.get(key);
@@ -112,6 +118,14 @@ public class IoLib extends TwoArgFunction {
public String tojstring() { public String tojstring() {
return "file: " + Integer.toHexString(hashCode()); return "file: " + Integer.toHexString(hashCode());
} }
public void finalize() {
if (!isclosed()) {
try {
close();
} catch (IOException ignore) {}
}
}
} }
/** Enumerated value representing stdin */ /** Enumerated value representing stdin */
@@ -269,8 +283,15 @@ public class IoLib extends TwoArgFunction {
static final class IoLibV extends VarArgFunction { static final class IoLibV extends VarArgFunction {
private File f; private File f;
public IoLib iolib; public IoLib iolib;
private boolean toclose;
private Varargs args;
public IoLibV() { public IoLibV() {
} }
public IoLibV(File f, String name, int opcode, IoLib iolib, boolean toclose, Varargs args) {
this(f, name, opcode, iolib);
this.toclose = toclose;
this.args = args.dealias();
}
public IoLibV(File f, String name, int opcode, IoLib iolib) { public IoLibV(File f, String name, int opcode, IoLib iolib) {
super(); super();
this.f = f; this.f = f;
@@ -290,22 +311,26 @@ public class IoLib extends TwoArgFunction {
case IO_TYPE: return iolib._io_type(args.arg1()); case IO_TYPE: return iolib._io_type(args.arg1());
case IO_POPEN: return iolib._io_popen(args.checkjstring(1),args.optjstring(2,"r")); case IO_POPEN: return iolib._io_popen(args.checkjstring(1),args.optjstring(2,"r"));
case IO_OPEN: return iolib._io_open(args.checkjstring(1), args.optjstring(2,"r")); case IO_OPEN: return iolib._io_open(args.checkjstring(1), args.optjstring(2,"r"));
case IO_LINES: return iolib._io_lines(args.isvalue(1)? args.checkjstring(1): null); case IO_LINES: return iolib._io_lines(args);
case IO_READ: return iolib._io_read(args); case IO_READ: return iolib._io_read(args);
case IO_WRITE: return iolib._io_write(args); case IO_WRITE: return iolib._io_write(args);
case FILE_CLOSE: return iolib._file_close(args.arg1()); case FILE_CLOSE: return iolib._file_close(args.arg1());
case FILE_FLUSH: return iolib._file_flush(args.arg1()); case FILE_FLUSH: return iolib._file_flush(args.arg1());
case FILE_SETVBUF: return iolib._file_setvbuf(args.arg1(),args.checkjstring(2),args.optint(3,1024)); case FILE_SETVBUF: return iolib._file_setvbuf(args.arg1(),args.checkjstring(2),args.optint(3,8192));
case FILE_LINES: return iolib._file_lines(args.arg1()); case FILE_LINES: return iolib._file_lines(args);
case FILE_READ: return iolib._file_read(args.arg1(),args.subargs(2)); case FILE_READ: return iolib._file_read(args.arg1(),args.subargs(2));
case FILE_SEEK: return iolib._file_seek(args.arg1(),args.optjstring(2,"cur"),args.optint(3,0)); case FILE_SEEK: return iolib._file_seek(args.arg1(),args.optjstring(2,"cur"),args.optint(3,0));
case FILE_WRITE: return iolib._file_write(args.arg1(),args.subargs(2)); case FILE_WRITE: return iolib._file_write(args.arg1(),args.subargs(2));
case IO_INDEX: return iolib._io_index(args.arg(2)); case IO_INDEX: return iolib._io_index(args.arg(2));
case LINES_ITER: return iolib._lines_iter(f); case LINES_ITER: return iolib._lines_iter(f, toclose, this.args);
} }
} catch ( IOException ioe ) { } catch ( IOException ioe ) {
if (opcode == LINES_ITER) {
String s = ioe.getMessage();
error(s != null ? s : ioe.toString());
}
return errorresult(ioe); return errorresult(ioe);
} }
return NONE; return NONE;
@@ -361,6 +386,7 @@ public class IoLib extends TwoArgFunction {
// io.popen(prog, [mode]) -> file // io.popen(prog, [mode]) -> file
public Varargs _io_popen(String prog, String mode) throws IOException { public Varargs _io_popen(String prog, String mode) throws IOException {
if (!"r".equals(mode) && !"w".equals(mode)) argerror(2, "invalid value: '" + mode + "'; must be one of 'r' or 'w'");
return openProgram(prog, mode); return openProgram(prog, mode);
} }
@@ -369,11 +395,12 @@ public class IoLib extends TwoArgFunction {
return rawopenfile(FTYPE_NAMED, filename, mode); return rawopenfile(FTYPE_NAMED, filename, mode);
} }
// io.lines(filename) -> iterator // io.lines(filename, ...) -> iterator
public Varargs _io_lines(String filename) { public Varargs _io_lines(Varargs args) {
infile = filename==null? input(): ioopenfile(FTYPE_NAMED, filename,"r"); String filename = args.optjstring(1, null);
File infile = filename==null? input(): ioopenfile(FTYPE_NAMED, filename,"r");
checkopen(infile); checkopen(infile);
return lines(infile); return lines(infile, filename != null, args.subargs(2));
} }
// io.read(...) -> (...) // io.read(...) -> (...)
@@ -401,13 +428,19 @@ public class IoLib extends TwoArgFunction {
// file:setvbuf(mode,[size]) -> void // file:setvbuf(mode,[size]) -> void
public Varargs _file_setvbuf(LuaValue file, String mode, int size) { public Varargs _file_setvbuf(LuaValue file, String mode, int size) {
if ("no".equals(mode)) {
} else if ("full".equals(mode)) {
} else if ("line".equals(mode)) {
} else {
argerror(1, "invalid value: '" + mode + "'; must be one of 'no', 'full' or 'line'");
}
checkfile(file).setvbuf(mode,size); checkfile(file).setvbuf(mode,size);
return LuaValue.TRUE; return LuaValue.TRUE;
} }
// file:lines() -> iterator // file:lines(...) -> iterator
public Varargs _file_lines(LuaValue file) { public Varargs _file_lines(Varargs args) {
return lines(checkfile(file)); return lines(checkfile(args.arg1()), false, args.subargs(2));
} }
// file:read(...) -> (...) // file:read(...) -> (...)
@@ -417,6 +450,12 @@ public class IoLib extends TwoArgFunction {
// file:seek([whence][,offset]) -> pos | nil,error // file:seek([whence][,offset]) -> pos | nil,error
public Varargs _file_seek(LuaValue file, String whence, int offset) throws IOException { public Varargs _file_seek(LuaValue file, String whence, int offset) throws IOException {
if ("set".equals(whence)) {
} else if ("end".equals(whence)) {
} else if ("cur".equals(whence)) {
} else {
argerror(1, "invalid value: '" + whence + "'; must be one of 'set', 'cur' or 'end'");
}
return valueOf( checkfile(file).seek(whence,offset) ); return valueOf( checkfile(file).seek(whence,offset) );
} }
@@ -433,8 +472,13 @@ public class IoLib extends TwoArgFunction {
} }
// lines iterator(s,var) -> var' // lines iterator(s,var) -> var'
public Varargs _lines_iter(LuaValue file) throws IOException { public Varargs _lines_iter(LuaValue file, boolean toclose, Varargs args) throws IOException {
return freadline(checkfile(file)); File f = optfile(file);
if ( f == null ) argerror(1, "not a file: " + file);
if ( f.isclosed() ) error("file is already closed");
Varargs ret = ioread(f, args);
if (toclose && ret.isnil(1) && f.eof()) f.close();
return ret;
} }
private File output() { private File output() {
@@ -476,9 +520,9 @@ public class IoLib extends TwoArgFunction {
return varargsOf(NIL, valueOf(errortext)); return varargsOf(NIL, valueOf(errortext));
} }
private Varargs lines(final File f) { private Varargs lines(final File f, boolean toclose, Varargs args) {
try { try {
return new IoLibV(f,"lnext",LINES_ITER,this); return new IoLibV(f,"lnext",LINES_ITER,this,toclose,args);
} catch ( Exception e ) { } catch ( Exception e ) {
return error("lines: "+e); return error("lines: "+e);
} }
@@ -492,6 +536,7 @@ public class IoLib extends TwoArgFunction {
private Varargs ioread(File f, Varargs args) throws IOException { private Varargs ioread(File f, Varargs args) throws IOException {
int i,n=args.narg(); int i,n=args.narg();
if (n == 0) return freadline(f,false);
LuaValue[] v = new LuaValue[n]; LuaValue[] v = new LuaValue[n];
LuaValue ai,vi; LuaValue ai,vi;
LuaString fmt; LuaString fmt;
@@ -502,10 +547,11 @@ public class IoLib extends TwoArgFunction {
break item; break item;
case LuaValue.TSTRING: case LuaValue.TSTRING:
fmt = ai.checkstring(); fmt = ai.checkstring();
if ( fmt.m_length == 2 && fmt.m_bytes[fmt.m_offset] == '*' ) { if ( fmt.m_length >= 2 && fmt.m_bytes[fmt.m_offset] == '*' ) {
switch ( fmt.m_bytes[fmt.m_offset+1] ) { switch ( fmt.m_bytes[fmt.m_offset+1] ) {
case 'n': vi = freadnumber(f); break item; case 'n': vi = freadnumber(f); break item;
case 'l': vi = freadline(f); break item; case 'l': vi = freadline(f,false); break item;
case 'L': vi = freadline(f,true); break item;
case 'a': vi = freadall(f); break item; case 'a': vi = freadall(f); break item;
} }
} }
@@ -537,6 +583,17 @@ public class IoLib extends TwoArgFunction {
} }
private File rawopenfile(int filetype, String filename, String mode) throws IOException { private File rawopenfile(int filetype, String filename, String mode) throws IOException {
int len = mode.length();
for (int i = 0; i < len; i++) { // [rwa][+]?b*
char ch = mode.charAt(i);
if (i == 0 && "rwa".indexOf(ch) >= 0) continue;
if (i == 1 && ch == '+') continue;
if (i >= 1 && ch == 'b') continue;
len = -1;
break;
}
if (len <= 0) argerror(2, "invalid mode: '" + mode + "'");
switch (filetype) { switch (filetype) {
case FTYPE_STDIN: return wrapStdin(); case FTYPE_STDIN: return wrapStdin();
case FTYPE_STDOUT: return wrapStdout(); case FTYPE_STDOUT: return wrapStdout();
@@ -553,26 +610,27 @@ public class IoLib extends TwoArgFunction {
// ------------- file reading utilitied ------------------ // ------------- file reading utilitied ------------------
public static LuaValue freadbytes(File f, int count) throws IOException { public static LuaValue freadbytes(File f, int count) throws IOException {
if (count == 0) return f.eof() ? NIL : EMPTYSTRING;
byte[] b = new byte[count]; byte[] b = new byte[count];
int r; int r;
if ( ( r = f.read(b,0,b.length) ) < 0 ) if ( ( r = f.read(b,0,b.length) ) < 0 )
return NIL; return NIL;
return LuaString.valueUsing(b, 0, r); return LuaString.valueUsing(b, 0, r);
} }
public static LuaValue freaduntil(File f,boolean lineonly) throws IOException { public static LuaValue freaduntil(File f,boolean lineonly,boolean withend) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
int c; int c;
try { try {
if ( lineonly ) { if ( lineonly ) {
loop: while ( (c = f.read()) > 0 ) { loop: while ( (c = f.read()) >= 0 ) {
switch ( c ) { switch ( c ) {
case '\r': break; case '\r': if (withend) baos.write(c); break;
case '\n': break loop; case '\n': if (withend) baos.write(c); break loop;
default: baos.write(c); break; default: baos.write(c); break;
} }
} }
} else { } else {
while ( (c = f.read()) > 0 ) while ( (c = f.read()) >= 0 )
baos.write(c); baos.write(c);
} }
} catch ( EOFException e ) { } catch ( EOFException e ) {
@@ -582,15 +640,15 @@ public class IoLib extends TwoArgFunction {
(LuaValue) NIL: (LuaValue) NIL:
(LuaValue) LuaString.valueUsing(baos.toByteArray()); (LuaValue) LuaString.valueUsing(baos.toByteArray());
} }
public static LuaValue freadline(File f) throws IOException { public static LuaValue freadline(File f,boolean withend) throws IOException {
return freaduntil(f,true); return freaduntil(f,true,withend);
} }
public static LuaValue freadall(File f) throws IOException { public static LuaValue freadall(File f) throws IOException {
int n = f.remaining(); int n = f.remaining();
if ( n >= 0 ) { if ( n >= 0 ) {
return freadbytes(f, n); return n == 0 ? EMPTYSTRING : freadbytes(f, n);
} else { } else {
return freaduntil(f,false); return freaduntil(f,false,false);
} }
} }
public static LuaValue freadnumber(File f) throws IOException { public static LuaValue freadnumber(File f) throws IOException {

View File

@@ -27,21 +27,21 @@ import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs; import org.luaj.vm2.Varargs;
/** /**
* Subclass of {@link LuaFunction} common to Java functions exposed to lua. * Subclass of {@link LuaFunction} common to Java functions exposed to lua.
* <p> * <p>
* To provide for common implementations in JME and JSE, * To provide for common implementations in JME and JSE,
* library functions are typically grouped on one or more library classes * 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 * and an opcode per library function is defined and used to key the switch
* to the correct function within the library. * to the correct function within the library.
* <p> * <p>
* Since lua functions can be called with too few or too many arguments, * Since lua functions can be called with too few or too many arguments,
* and there are overloaded {@link LuaValue#call()} functions with varying * and there are overloaded {@link LuaValue#call()} functions with varying
* number of arguments, a Java function exposed in lua needs to handle the * 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 * argument fixup when a function is called with a number of arguments
* differs from that expected. * differs from that expected.
* <p> * <p>
* To simplify the creation of library functions, * To simplify the creation of library functions,
* there are 5 direct subclasses to handle common cases based on number of * there are 5 direct subclasses to handle common cases based on number of
* argument values and number of return return values. * argument values and number of return return values.
* <ul> * <ul>
* <li>{@link ZeroArgFunction}</li> * <li>{@link ZeroArgFunction}</li>
@@ -51,13 +51,13 @@ import org.luaj.vm2.Varargs;
* <li>{@link VarArgFunction}</li> * <li>{@link VarArgFunction}</li>
* </ul> * </ul>
* <p> * <p>
* To be a Java library that can be loaded via {@code require}, it should have * 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, * a public constructor that returns a {@link LuaValue} that, when executed,
* initializes the library. * initializes the library.
* <p> * <p>
* For example, the following code will implement a library called "hyperbolic" * For example, the following code will implement a library called "hyperbolic"
* with two functions, "sinh", and "cosh": * with two functions, "sinh", and "cosh":
<pre> {@code <pre> {@code
* import org.luaj.vm2.LuaValue; * import org.luaj.vm2.LuaValue;
* import org.luaj.vm2.lib.*; * import org.luaj.vm2.lib.*;
* *
@@ -86,13 +86,13 @@ import org.luaj.vm2.Varargs;
* } * }
*} *}
*}</pre> *}</pre>
* The default constructor is used to instantiate the library * The default constructor is used to instantiate the library
* in response to {@code require 'hyperbolic'} statement, * in response to {@code require 'hyperbolic'} statement,
* provided it is on Java&quot;s class path. * provided it is on Java&quot;s class path.
* This instance is then invoked with 2 arguments: the name supplied to require(), * 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 * and the environment for this function. The library may ignore these, or use
* them to leave side effects in the global environment, for example. * them to leave side effects in the global environment, for example.
* In the previous example, two functions are created, 'sinh', and 'cosh', and placed * In the previous example, two functions are created, 'sinh', and 'cosh', and placed
* into a global table called 'hyperbolic' using the supplied 'env' argument. * into a global table called 'hyperbolic' using the supplied 'env' argument.
* <p> * <p>
* To test it, a script such as this can be used: * To test it, a script such as this can be used:
@@ -105,7 +105,7 @@ import org.luaj.vm2.Varargs;
* end * end
* print( 'sinh(.5)', hyperbolic.sinh(.5) ) * print( 'sinh(.5)', hyperbolic.sinh(.5) )
* print( 'cosh(.5)', hyperbolic.cosh(.5) ) * print( 'cosh(.5)', hyperbolic.cosh(.5) )
* }</pre> * }</pre>
* <p> * <p>
* It should produce something like: * It should produce something like:
* <pre> {@code * <pre> {@code
@@ -115,16 +115,16 @@ import org.luaj.vm2.Varargs;
* k,v sinh function: 3dbbd242 * k,v sinh function: 3dbbd242
* sinh(.5) 0.5210953 * sinh(.5) 0.5210953
* cosh(.5) 1.127626 * cosh(.5) 1.127626
* }</pre> * }</pre>
* <p> * <p>
* See the source code in any of the library functions * See the source code in any of the library functions
* such as {@link BaseLib} or {@link TableLib} for other examples. * such as {@link BaseLib} or {@link TableLib} for other examples.
*/ */
abstract public class LibFunction extends LuaFunction { 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.
* <p> * <p>
* 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; protected int opcode;
@@ -135,37 +135,37 @@ abstract public class LibFunction extends LuaFunction {
protected String name; protected String name;
/** Default constructor for use by subclasses */ /** Default constructor for use by subclasses */
protected LibFunction() { protected LibFunction() {
} }
public String tojstring() { public String tojstring() {
return name != null ? "function: " + name : super.tojstring(); return name != null ? "function: " + name : super.tojstring();
} }
/** /**
* Bind a set of library functions. * Bind a set of library functions.
* <p> * <p>
* An array of names is provided, and the first name is bound * An array of names is provided, and the first name is bound
* with opcode = 0, second with 1, etc. * with opcode = 0, second with 1, etc.
* @param env The environment to apply to each bound function * @param env The environment to apply to each bound function
* @param factory the Class to instantiate for 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) * @see #bind(LuaValue, Class, String[], int)
*/ */
protected void bind(LuaValue env, Class factory, String[] names ) { protected void bind(LuaValue env, Class factory, String[] names ) {
bind( env, factory, names, 0 ); bind( env, factory, names, 0 );
} }
/** /**
* Bind a set of library functions, with an offset * Bind a set of library functions, with an offset
* <p> * <p>
* An array of names is provided, and the first name is bound * An array of names is provided, and the first name is bound
* with opcode = {@code firstopcode}, second with {@code firstopcode+1}, etc. * with opcode = {@code firstopcode}, second with {@code firstopcode+1}, etc.
* @param env The environment to apply to each bound function * @param env The environment to apply to each bound function
* @param factory the Class to instantiate for 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.
* @param firstopcode the first opcode to use * @param firstopcode the first opcode to use
* @see #bind(LuaValue, Class, String[]) * @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 { try {
@@ -178,7 +178,7 @@ abstract public class LibFunction extends LuaFunction {
} catch ( Exception e ) { } catch ( Exception e ) {
throw new LuaError( "bind failed: "+e ); throw new LuaError( "bind failed: "+e );
} }
} }
/** Java code generation utility to allocate storage for upvalue, leave it empty */ /** Java code generation utility to allocate storage for upvalue, leave it empty */
protected static LuaValue[] newupe() { protected static LuaValue[] newupe() {
@@ -219,4 +219,4 @@ abstract public class LibFunction extends LuaFunction {
default: return call(args.arg1(),args.arg(2),args.arg(3),args.arg(4)); default: return call(args.arg1(),args.arg(2),args.arg(3),args.arg(4));
} }
} }
} }

View File

@@ -144,6 +144,7 @@ public class PackageLib extends TwoArgFunction {
searchers.set(2, lua_searcher = new lua_searcher()); searchers.set(2, lua_searcher = new lua_searcher());
searchers.set(3, java_searcher = new java_searcher()); searchers.set(3, java_searcher = new java_searcher());
package_.set(_SEARCHERS, searchers); package_.set(_SEARCHERS, searchers);
package_.set("config", FILE_SEP + "\n;\n?\n!\n-\n");
package_.get(_LOADED).set("package", package_); package_.get(_LOADED).set("package", package_);
env.set("package", package_); env.set("package", package_);
globals.package_ = this; globals.package_ = this;

View File

@@ -79,8 +79,8 @@ public class StringLib extends TwoArgFunction {
*/ */
public LuaValue call(LuaValue modname, LuaValue env) { public LuaValue call(LuaValue modname, LuaValue env) {
LuaTable string = new LuaTable(); LuaTable string = new LuaTable();
string.set("byte", new byte_()); string.set("byte", new _byte());
string.set("char", new char_()); string.set("char", new _char());
string.set("dump", new dump()); string.set("dump", new dump());
string.set("find", new find()); string.set("find", new find());
string.set("format", new format()); string.set("format", new format());
@@ -113,7 +113,7 @@ public class StringLib extends TwoArgFunction {
* *
* @param args the calling args * @param args the calling args
*/ */
static final class byte_ extends VarArgFunction { static final class _byte extends VarArgFunction {
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
LuaString s = args.checkstring(1); LuaString s = args.checkstring(1);
int l = s.m_length; int l = s.m_length;
@@ -144,7 +144,7 @@ public class StringLib extends TwoArgFunction {
* *
* @param args the calling VM * @param args the calling VM
*/ */
static final class char_ extends VarArgFunction { static final class _char extends VarArgFunction {
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
int n = args.narg(); int n = args.narg();
byte[] bytes = new byte[n]; byte[] bytes = new byte[n];
@@ -624,19 +624,20 @@ public class StringLib extends TwoArgFunction {
private final int srclen; private final int srclen;
private final MatchState ms; private final MatchState ms;
private int soffset; private int soffset;
private int lastmatch;
public GMatchAux(Varargs args, LuaString src, LuaString pat) { public GMatchAux(Varargs args, LuaString src, LuaString pat) {
this.srclen = src.length(); this.srclen = src.length();
this.ms = new MatchState(args, src, pat); this.ms = new MatchState(args, src, pat);
this.soffset = 0; this.soffset = 0;
this.lastmatch = -1;
} }
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
for ( ; soffset<=srclen; soffset++ ) { for ( ; soffset<=srclen; soffset++ ) {
ms.reset(); ms.reset();
int res = ms.match(soffset, 0); int res = ms.match(soffset, 0);
if ( res >=0 ) { if ( res >=0 && res != lastmatch ) {
int soff = soffset; int soff = soffset;
soffset = res; lastmatch = soffset = res;
if (soff == res) soffset++; /* empty match? go at least one position */
return ms.push_captures( true, soff, res ); return ms.push_captures( true, soff, res );
} }
} }
@@ -695,6 +696,7 @@ public class StringLib extends TwoArgFunction {
LuaString src = args.checkstring( 1 ); LuaString src = args.checkstring( 1 );
final int srclen = src.length(); final int srclen = src.length();
LuaString p = args.checkstring( 2 ); LuaString p = args.checkstring( 2 );
int lastmatch = -1; /* end of last match */
LuaValue repl = args.arg( 3 ); LuaValue repl = args.arg( 3 );
int max_s = args.optint( 4, srclen + 1 ); int max_s = args.optint( 4, srclen + 1 );
final boolean anchor = p.length() > 0 && p.charAt( 0 ) == '^'; final boolean anchor = p.length() > 0 && p.charAt( 0 ) == '^';
@@ -707,18 +709,15 @@ public class StringLib extends TwoArgFunction {
while ( n < max_s ) { while ( n < max_s ) {
ms.reset(); ms.reset();
int res = ms.match( soffset, anchor ? 1 : 0 ); int res = ms.match( soffset, anchor ? 1 : 0 );
if ( res != -1 ) { if ( res != -1 && res != lastmatch ) { /* match? */
n++; n++;
ms.add_value( lbuf, soffset, res, repl ); ms.add_value( lbuf, soffset, res, repl ); /* add replacement to buffer */
soffset = lastmatch = res;
} }
if ( res != -1 && res > soffset ) else if ( soffset < srclen ) /* otherwise, skip one character */
soffset = res;
else if ( soffset < srclen )
lbuf.append( (byte) src.luaByte( soffset++ ) ); lbuf.append( (byte) src.luaByte( soffset++ ) );
else else break; /* end of subject */
break; if ( anchor ) break;
if ( anchor )
break;
} }
lbuf.append( src.substring( soffset, srclen ) ); lbuf.append( src.substring( soffset, srclen ) );
return varargsOf(lbuf.tostring(), valueOf(n)); return varargsOf(lbuf.tostring(), valueOf(n));
@@ -914,6 +913,8 @@ public class StringLib extends TwoArgFunction {
private static final LuaString SPECIALS = valueOf("^$*+?.([%-"); private static final LuaString SPECIALS = valueOf("^$*+?.([%-");
private static final int MAX_CAPTURES = 32; 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_UNFINISHED = -1;
private static final int CAP_POSITION = -2; private static final int CAP_POSITION = -2;
@@ -931,7 +932,7 @@ public class StringLib extends TwoArgFunction {
static { static {
CHAR_TABLE = new byte[256]; CHAR_TABLE = new byte[256];
for ( int i = 0; i < 256; ++i ) { for ( int i = 0; i < 128; ++i ) {
final char c = (char) i; final char c = (char) i;
CHAR_TABLE[i] = (byte)( ( Character.isDigit( c ) ? MASK_DIGIT : 0 ) | CHAR_TABLE[i] = (byte)( ( Character.isDigit( c ) ? MASK_DIGIT : 0 ) |
( Character.isLowerCase( c ) ? MASK_LOWERCASE : 0 ) | ( Character.isLowerCase( c ) ? MASK_LOWERCASE : 0 ) |
@@ -940,7 +941,7 @@ public class StringLib extends TwoArgFunction {
if ( ( c >= 'a' && c <= 'f' ) || ( c >= 'A' && c <= 'F' ) || ( c >= '0' && c <= '9' ) ) { if ( ( c >= 'a' && c <= 'f' ) || ( c >= 'A' && c <= 'F' ) || ( c >= '0' && c <= '9' ) ) {
CHAR_TABLE[i] |= MASK_HEXDIGIT; CHAR_TABLE[i] |= MASK_HEXDIGIT;
} }
if ( ( c >= '!' && c <= '/' ) || ( c >= ':' && c <= '@' ) ) { if ( ( c >= '!' && c <= '/' ) || ( c >= ':' && c <= '@' ) || ( c >= '[' && c <= '`' ) || ( c >= '{' && c <= '~' ) ) {
CHAR_TABLE[i] |= MASK_PUNCT; CHAR_TABLE[i] |= MASK_PUNCT;
} }
if ( ( CHAR_TABLE[i] & ( MASK_LOWERCASE | MASK_UPPERCASE ) ) != 0 ) { if ( ( CHAR_TABLE[i] & ( MASK_LOWERCASE | MASK_UPPERCASE ) ) != 0 ) {
@@ -952,11 +953,12 @@ public class StringLib extends TwoArgFunction {
CHAR_TABLE['\r'] |= MASK_SPACE; CHAR_TABLE['\r'] |= MASK_SPACE;
CHAR_TABLE['\n'] |= MASK_SPACE; CHAR_TABLE['\n'] |= MASK_SPACE;
CHAR_TABLE['\t'] |= MASK_SPACE; CHAR_TABLE['\t'] |= MASK_SPACE;
CHAR_TABLE[0x0C /* '\v' */ ] |= MASK_SPACE; CHAR_TABLE[0x0B /* '\v' */ ] |= MASK_SPACE;
CHAR_TABLE['\f'] |= MASK_SPACE; CHAR_TABLE['\f'] |= MASK_SPACE;
}; };
static class MatchState { static class MatchState {
int matchdepth; /* control for recursive depth (to avoid C stack overflow) */
final LuaString s; final LuaString s;
final LuaString p; final LuaString p;
final Varargs args; final Varargs args;
@@ -971,10 +973,12 @@ public class StringLib extends TwoArgFunction {
this.level = 0; this.level = 0;
this.cinit = new int[ MAX_CAPTURES ]; this.cinit = new int[ MAX_CAPTURES ];
this.clen = new int[ MAX_CAPTURES ]; this.clen = new int[ MAX_CAPTURES ];
this.matchdepth = MAXCCALLS;
} }
void reset() { void reset() {
level = 0; level = 0;
this.matchdepth = MAXCCALLS;
} }
private void add_s( Buffer lbuf, LuaString news, int soff, int e ) { private void add_s( Buffer lbuf, LuaString news, int soff, int e ) {
@@ -1049,7 +1053,7 @@ public class StringLib extends TwoArgFunction {
if ( i == 0 ) { if ( i == 0 ) {
return s.substring( soff, end ); return s.substring( soff, end );
} else { } else {
return error( "invalid capture index" ); return error( "invalid capture index %" + (i + 1) );
} }
} else { } else {
int l = clen[i]; int l = clen[i];
@@ -1068,7 +1072,7 @@ public class StringLib extends TwoArgFunction {
private int check_capture( int l ) { private int check_capture( int l ) {
l -= '1'; l -= '1';
if ( l < 0 || l >= level || this.clen[l] == CAP_UNFINISHED ) { if ( l < 0 || l >= level || this.clen[l] == CAP_UNFINISHED ) {
error("invalid capture index"); error("invalid capture index %" + (l + 1));
} }
return l; return l;
} }
@@ -1118,9 +1122,10 @@ public class StringLib extends TwoArgFunction {
case 'c': res = ( cdata & MASK_CONTROL ) != 0; break; case 'c': res = ( cdata & MASK_CONTROL ) != 0; break;
case 'p': res = ( cdata & MASK_PUNCT ) != 0; break; case 'p': res = ( cdata & MASK_PUNCT ) != 0; break;
case 's': res = ( cdata & MASK_SPACE ) != 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 'w': res = ( cdata & ( MASK_ALPHA | MASK_DIGIT ) ) != 0; break;
case 'x': res = ( cdata & MASK_HEXDIGIT ) != 0; break; case 'x': res = ( cdata & MASK_HEXDIGIT ) != 0; break;
case 'z': res = ( c == 0 ); break; case 'z': res = ( c == 0 ); break; /* deprecated option */
default: return cl == c; default: return cl == c;
} }
return ( lcl == cl ) ? res : !res; return ( lcl == cl ) ? res : !res;
@@ -1162,81 +1167,86 @@ public class StringLib extends TwoArgFunction {
* where match ends, otherwise returns -1. * where match ends, otherwise returns -1.
*/ */
int match( int soffset, int poffset ) { int match( int soffset, int poffset ) {
while ( true ) { if (matchdepth-- == 0) error("pattern too complex");
// Check if we are at the end of the pattern - try {
// equivalent to the '\0' case in the C version, but our pattern while ( true ) {
// string is not NUL-terminated. // Check if we are at the end of the pattern -
if ( poffset == p.length() ) // equivalent to the '\0' case in the C version, but our pattern
return soffset; // string is not NUL-terminated.
switch ( p.luaByte( poffset ) ) { if ( poffset == p.length() )
case '(': return soffset;
if ( ++poffset < p.length() && p.luaByte( poffset ) == ')' ) switch ( p.luaByte( poffset ) ) {
return start_capture( soffset, poffset + 1, CAP_POSITION ); case '(':
else if ( ++poffset < p.length() && p.luaByte( poffset ) == ')' )
return start_capture( soffset, poffset, CAP_UNFINISHED ); return start_capture( soffset, poffset + 1, CAP_POSITION );
case ')': else
return end_capture( soffset, poffset + 1 ); return start_capture( soffset, poffset, CAP_UNFINISHED );
case L_ESC: case ')':
if ( poffset + 1 == p.length() ) return end_capture( soffset, poffset + 1 );
error("malformed pattern (ends with '%')"); case L_ESC:
switch ( p.luaByte( poffset + 1 ) ) { if ( poffset + 1 == p.length() )
case 'b': error("malformed pattern (ends with '%')");
soffset = matchbalance( soffset, poffset + 2 ); switch ( p.luaByte( poffset + 1 ) ) {
if ( soffset == -1 ) return -1; case 'b':
poffset += 4; soffset = matchbalance( soffset, poffset + 2 );
continue; if ( soffset == -1 ) return -1;
case 'f': { poffset += 4;
poffset += 2; continue;
if ( poffset == p.length() || p.luaByte( poffset ) != '[' ) { case 'f': {
error("Missing '[' after '%f' in pattern"); 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;
} }
int ep = classend( poffset ); default: {
int previous = ( soffset == 0 ) ? '\0' : s.luaByte( soffset - 1 ); int c = p.luaByte( poffset + 1 );
int next = ( soffset == s.length() ) ? '\0' : s.luaByte( soffset ); if ( Character.isDigit( (char) c ) ) {
if ( matchbracketclass( previous, poffset, ep - 1 ) || soffset = match_capture( soffset, c );
!matchbracketclass( next, poffset, ep - 1 ) ) 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; return -1;
soffset++;
poffset = ep; poffset = ep;
continue; 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;
continue;
} }
} finally {
matchdepth++;
} }
} }
@@ -1301,7 +1311,7 @@ public class StringLib extends TwoArgFunction {
int matchbalance( int soff, int poff ) { int matchbalance( int soff, int poff ) {
final int plen = p.length(); final int plen = p.length();
if ( poff == plen || poff + 1 == plen ) { if ( poff == plen || poff + 1 == plen ) {
error( "unbalanced pattern" ); error( "malformed pattern (missing arguments to '%b')" );
} }
final int slen = s.length(); final int slen = s.length();
if ( soff >= slen ) if ( soff >= slen )

View File

@@ -73,12 +73,6 @@ public class TableLib extends TwoArgFunction {
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; return NIL;
} }
static class TableLibFunction extends LibFunction {
public LuaValue call() {
return argerror(1, "table expected, got no value");
}
}
// "concat" (table [, sep [, i [, j]]]) -> string // "concat" (table [, sep [, i [, j]]]) -> string
static class concat extends TableLibFunction { static class concat extends TableLibFunction {
@@ -100,18 +94,22 @@ public class TableLib extends TwoArgFunction {
static class insert extends VarArgFunction { static class insert extends VarArgFunction {
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
switch (args.narg()) { switch (args.narg()) {
case 0: case 1: {
return argerror(2, "value expected");
}
case 2: { case 2: {
LuaTable table = args.arg1().checktable(); LuaTable table = args.checktable(1);
table.insert(table.length()+1,args.arg(2)); table.insert(table.length()+1,args.arg(2));
return NONE; return NONE;
} }
default: { case 3: {
args.arg1().checktable().insert(args.checkint(2),args.arg(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);
table.insert(pos, args.arg(3));
return NONE; return NONE;
} }
default: {
return error("wrong number of arguments to 'table.insert': " + args.narg() + " (must be 2 or 3)");
}
} }
} }
} }
@@ -128,15 +126,21 @@ public class TableLib extends TwoArgFunction {
// "remove" (table [, pos]) -> removed-ele // "remove" (table [, pos]) -> removed-ele
static class remove extends VarArgFunction { static class remove extends VarArgFunction {
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
return args.arg1().checktable().remove(args.optint(2, 0)); 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));
}
return table.remove(pos);
} }
} }
// "sort" (table [, comp]) // "sort" (table [, comp])
static class sort extends VarArgFunction { static class sort extends VarArgFunction {
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
args.arg1().checktable().sort( args.checktable(1).sort(
args.arg(2).isnil()? NIL: args.arg(2).checkfunction()); args.isnil(2)? NIL: args.checkfunction(2));
return NONE; return NONE;
} }
} }
@@ -146,11 +150,9 @@ public class TableLib extends TwoArgFunction {
static class unpack extends VarArgFunction { static class unpack extends VarArgFunction {
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
LuaTable t = args.checktable(1); LuaTable t = args.checktable(1);
switch (args.narg()) { // do not waste resource for calc rawlen if arg3 is not nil
case 1: return t.unpack(); int len = args.arg(3).isnil() ? t.length() : 0;
case 2: return t.unpack(args.checkint(2)); return t.unpack(args.optint(2, 1), args.optint(3, len));
default: return t.unpack(args.checkint(2), args.checkint(3));
}
} }
} }
} }

View File

@@ -0,0 +1,9 @@
package org.luaj.vm2.lib;
import org.luaj.vm2.LuaValue;
class TableLibFunction extends LibFunction {
public LuaValue call() {
return argerror(1, "table expected, got no value");
}
}

View File

@@ -36,20 +36,20 @@ import org.luaj.vm2.LuaValue;
import org.luaj.vm2.lib.IoLib; import org.luaj.vm2.lib.IoLib;
import org.luaj.vm2.lib.LibFunction; import org.luaj.vm2.lib.LibFunction;
/** /**
* Subclass of {@link IoLib} and therefore {@link LibFunction} which implements the lua standard {@code io} * Subclass of {@link IoLib} and therefore {@link LibFunction} which implements the lua standard {@code io}
* library for the JSE platform. * library for the JSE platform.
* <p>
* It uses RandomAccessFile to implement seek on files.
* <p> * <p>
* Typically, this library is included as part of a call to * It uses RandomAccessFile to implement seek on files.
* <p>
* Typically, this library is included as part of a call to
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} * {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()}
* <pre> {@code * <pre> {@code
* Globals globals = JsePlatform.standardGlobals(); * Globals globals = JsePlatform.standardGlobals();
* globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n")); * globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
* } </pre> * } </pre>
* <p> * <p>
* For special cases where the smallest possible footprint is desired, * For special cases where the smallest possible footprint is desired,
* a minimal set of libraries could be loaded * a minimal set of libraries could be loaded
* directly via {@link Globals#load(LuaValue)} using code such as: * directly via {@link Globals#load(LuaValue)} using code such as:
* <pre> {@code * <pre> {@code
@@ -96,9 +96,9 @@ public class JseIoLib extends IoLib {
protected File openProgram(String prog, String mode) throws IOException { protected File openProgram(String prog, String mode) throws IOException {
final Process p = Runtime.getRuntime().exec(prog); final Process p = Runtime.getRuntime().exec(prog);
return "w".equals(mode)? return "w".equals(mode)?
new FileImpl( p.getOutputStream() ): new FileImpl( p.getOutputStream() ):
new FileImpl( p.getInputStream() ); new FileImpl( p.getInputStream() );
} }
protected File tmpFile() throws IOException { protected File tmpFile() throws IOException {
@@ -133,7 +133,7 @@ public class JseIoLib extends IoLib {
this( null, null, o ); this( null, null, o );
} }
public String tojstring() { public String tojstring() {
return "file ("+this.hashCode()+")"; return "file (" + (this.closed ? "closed" : String.valueOf(this.hashCode())) + ")";
} }
public boolean isstdfile() { public boolean isstdfile() {
return file == null; return file == null;
@@ -199,11 +199,11 @@ public class JseIoLib extends IoLib {
} }
notimplemented(); notimplemented();
return 0; return 0;
} }
// return char if read, -1 if eof, throw IOException on other exception // return char if read, -1 if eof, throw IOException on other exception
public int read() throws IOException { public int read() throws IOException {
if ( is != null ) if ( is != null )
return is.read(); return is.read();
else if ( file != null ) { else if ( file != null ) {
return file.read(); return file.read();
@@ -321,7 +321,7 @@ public class JseIoLib extends IoLib {
} }
public int remaining() throws IOException { public int remaining() throws IOException {
return 0; return -1;
} }
public int peek() throws IOException, EOFException { public int peek() throws IOException, EOFException {

View File

@@ -33,8 +33,8 @@ import org.luaj.vm2.lib.OsLib;
/** /**
* Subclass of {@link LibFunction} which implements the standard lua {@code os} library. * Subclass of {@link LibFunction} which implements the standard lua {@code os} library.
* <p> * <p>
* This contains more complete implementations of the following functions * This contains more complete implementations of the following functions
* using features that are specific to JSE: * using features that are specific to JSE:
* <ul> * <ul>
* <li>{@code execute()}</li> * <li>{@code execute()}</li>
* <li>{@code remove()}</li> * <li>{@code remove()}</li>
@@ -42,18 +42,18 @@ import org.luaj.vm2.lib.OsLib;
* <li>{@code tmpname()}</li> * <li>{@code tmpname()}</li>
* </ul> * </ul>
* <p> * <p>
* Because the nature of the {@code os} library is to encapsulate * Because the nature of the {@code os} library is to encapsulate
* os-specific features, the behavior of these functions varies considerably * os-specific features, the behavior of these functions varies considerably
* from their counterparts in the C platform. * from their counterparts in the C platform.
* <p> * <p>
* Typically, this library is included as part of a call to * Typically, this library is included as part of a call to
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} * {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()}
* <pre> {@code * <pre> {@code
* Globals globals = JsePlatform.standardGlobals(); * Globals globals = JsePlatform.standardGlobals();
* System.out.println( globals.get("os").get("time").call() ); * System.out.println( globals.get("os").get("time").call() );
* } </pre> * } </pre>
* <p> * <p>
* For special cases where the smallest possible footprint is desired, * For special cases where the smallest possible footprint is desired,
* a minimal set of libraries could be loaded * a minimal set of libraries could be loaded
* directly via {@link Globals#load(LuaValue)} using code such as: * directly via {@link Globals#load(LuaValue)} using code such as:
* <pre> {@code * <pre> {@code
@@ -126,7 +126,7 @@ public class JseOsLib extends org.luaj.vm2.lib.OsLib {
protected String tmpname() { protected String tmpname() {
try { 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.getName(); return f.getAbsolutePath();
} catch ( IOException ioe ) { } catch ( IOException ioe ) {
return super.tmpname(); return super.tmpname();
} }