[NOTHING CHANGED] Assorted fixes #48

Closed
asiekierka wants to merge 61 commits from asiekierka/master into master
23 changed files with 700 additions and 567 deletions
Showing only changes of commit a3507cf771 - Show all commits

1
.gitignore vendored
View File

@@ -1,7 +1,6 @@
bin/
target/
build/
lib/
jit/
*.ser
*.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>
Copyright &copy; 2009-2014 Luaj.org.
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>
<hr>
<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
to simplify access to underlying Android APIs.
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.
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>
* The {@link LoadState} class provides the default {@link Globals.Undumper}
* which is used to undump a string of bytes that represent a lua binary file
* using either the C-based lua compiler, or luaj's
* using either the C-based lua compiler, or luaj's
* {@link org.luaj.vm2.compiler.LuaC} compiler.
* <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:
* <pre> {@code
* 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}
* have been installed.
* <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}
* to construct globals, the {@link LoadState} default undumper is installed
* as the default {@link Globals.Undumper}.
* as the default {@link Globals.Undumper}.
* <p>
*
* 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();
* } </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:
* <pre> {@code
* 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 */
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_TNONE = (-1);
public static final int LUA_TNIL = 0;
@@ -155,7 +155,6 @@ public class LoadState {
private static final LuaValue[] NOVALUES = {};
private static final Prototype[] NOPROTOS = {};
private static final LocVars[] NOLOCVARS = {};
private static final LuaString[] NOSTRVALUES = {};
private static final Upvaldesc[] NOUPVALDESCS = {};
private static final int[] NOINTS = {};
@@ -168,17 +167,17 @@ public class LoadState {
}
/** Load a 4-byte int value from the input stream
* @return the int value laoded.
* @return the int value laoded.
**/
int loadInt() throws IOException {
is.readFully(buf,0,4);
return luacLittleEndian?
return luacLittleEndian?
(buf[3] << 24) | ((0xff & buf[2]) << 16) | ((0xff & buf[1]) << 8) | (0xff & buf[0]):
(buf[0] << 24) | ((0xff & buf[1]) << 16) | ((0xff & buf[2]) << 8) | (0xff & buf[3]);
}
/** Load an array of int values from the input stream
* @return the array of int values laoded.
* @return the array of int values laoded.
**/
int[] loadIntArray() throws IOException {
int n = loadInt();
@@ -192,7 +191,7 @@ public class LoadState {
is.readFully(buf,0,m);
int[] array = new int[n];
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+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
* @return the long value laoded.
* @return the long value laoded.
**/
long loadInt64() throws IOException {
int a,b;
@@ -215,7 +214,7 @@ public class LoadState {
}
/** 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 {
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
* @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) );
}
/**
/**
* Load a number from a binary chunk
* @return the {@link LuaValue} loaded
* @throws IOException if an i/o exception occurs
@@ -335,7 +334,7 @@ public class LoadState {
f.upvalues[i].name = loadString();
}
/**
/**
* Load a function prototype from the input stream
* @param p name of the source
* @return {@link Prototype} instance that was loaded
@@ -366,8 +365,8 @@ public class LoadState {
}
/**
* Load the lua chunk header values.
* @throws IOException if an i/o exception occurs.
* Load the lua chunk header values.
* @throws IOException if an i/o exception occurs.
*/
public void loadHeader() throws IOException {
luacVersion = is.readByte();
@@ -392,7 +391,7 @@ public class LoadState {
*/
public static Prototype undump(InputStream stream, String chunkname) throws IOException {
// 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[2]
|| stream.read() != LUA_SIGNATURE[3] )

View File

@@ -21,6 +21,8 @@
******************************************************************************/
package org.luaj.vm2;
import org.luaj.vm2.lib.DebugLib.CallFrame;
/**
* Extension of {@link LuaFunction} which executes lua bytecode.
* <p>
@@ -415,7 +417,7 @@ public class LuaClosure extends LuaFunction {
{
LuaValue limit = stack[a + 1];
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)) {
stack[a] = idx;
stack[a + 3] = idx;
@@ -547,8 +549,24 @@ public class LuaClosure extends LuaFunction {
}
private void processErrorHooks(LuaError le, Prototype p, int pc) {
le.fileline = (p.source != null? p.source.tojstring(): "?") + ":"
+ (p.lineinfo != null && pc >= 0 && pc < p.lineinfo.length? String.valueOf(p.lineinfo[pc]): "?") + ": ";
String file = "?";
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);
}

View File

@@ -25,12 +25,12 @@ import org.luaj.vm2.compat.JavaCompat;
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>
* 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)}
* functions. This ensures that values which can be represented as int
* are wrapped in {@link LuaInteger} instead of {@link LuaDouble}.
* functions. This ensures that values which can be represented as int
* are wrapped in {@link LuaInteger} instead of {@link LuaDouble}.
* <p>
* Almost all API's implemented in LuaDouble are defined and documented in {@link LuaValue}.
* <p>
@@ -44,7 +44,7 @@ import org.luaj.vm2.lib.MathLib;
* <li>{@link #ddiv_d(double, double)}</li>
* <li>{@link #dmod(double, double)}</li>
* <li>{@link #dmod_d(double, double)}</li>
* </ul>
* </ul>
* <p>
* @see LuaValue
* @see LuaNumber
@@ -97,7 +97,7 @@ public class LuaDouble extends LuaNumber {
}
public boolean islong() {
return v == (long) v;
return v == (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.
* @param lhs Left-hand-side of the division.
* @param rhs Right-hand-side of the division.
* @return {@link LuaValue} for the result of the division,
* @return {@link LuaValue} for the result of the division,
* 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) {
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.
@@ -173,15 +173,15 @@ public class LuaDouble extends LuaNumber {
* @see #ddiv(double, double)
*/
public static double ddiv_d(double lhs, double rhs) {
return rhs!=0? lhs / rhs: lhs>0? Double.POSITIVE_INFINITY: lhs==0? Double.NaN: Double.NEGATIVE_INFINITY;
return rhs!=0? lhs / rhs: lhs>0? Double.POSITIVE_INFINITY: lhs==0? Double.NaN: Double.NEGATIVE_INFINITY;
}
/** Take modulo double numbers according to lua math, and return a {@link LuaValue} result.
* @param lhs Left-hand-side of the modulo.
* @param rhs Right-hand-side of the modulo.
* @return {@link LuaValue} for the result of the modulo,
* @return {@link LuaValue} for the result of the 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) {
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.
* @param lhs Left-hand-side of the modulo.
* @param rhs Right-hand-side of the modulo.
* @return double value for the result of the modulo,
* @return double value for the result of the modulo,
* using lua's rules for modulo
* @see #dmod(double, double)
*/
@@ -213,28 +213,28 @@ public class LuaDouble extends LuaNumber {
}
// 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( 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( 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( 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( 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( 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( 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( 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( double rhs ) { return v >= rhs; }
@@ -245,7 +245,7 @@ public class LuaDouble extends LuaNumber {
if ( v == 0.0 ) // never occurs on J2ME
return (JavaCompat.INSTANCE.doubleToRawLongBits(v)<0? "-0": "0");
long l = (long) v;
if ( l == v )
if ( l == v )
return Long.toString(l);
if ( Double.isNaN(v) )
return (JavaCompat.INSTANCE.doubleToRawLongBits(v)<0? JSTR_NEGNAN: JSTR_NAN);
@@ -271,11 +271,11 @@ public class LuaDouble extends LuaNumber {
}
public LuaNumber optnumber(LuaNumber defval) {
return this;
return this;
}
public boolean isnumber() {
return true;
return true;
}
public boolean isstring() {
@@ -290,14 +290,14 @@ public class LuaDouble extends LuaNumber {
public LuaNumber checknumber() { return this; }
public double checkdouble() { return v; }
public String checkjstring() {
public String checkjstring() {
return tojstring();
}
public LuaString checkstring() {
public LuaString checkstring() {
return LuaString.valueOf(tojstring());
}
public boolean isvalidkey() {
return !Double.isNaN(v);
}
}
}

View File

@@ -22,14 +22,14 @@
package org.luaj.vm2;
/**
* Base class for functions implemented in Java.
/**
* Base class for functions implemented in Java.
* <p>
* Direct subclass include {@link org.luaj.vm2.lib.LibFunction}
* which is the base class for
* all built-in library functions coded in Java,
* and {@link LuaClosure}, which represents a lua closure
* whose bytecode is interpreted when the function is invoked.
* Direct subclass include {@link org.luaj.vm2.lib.LibFunction}
* which is the base class for
* all built-in library functions coded in Java,
* and {@link LuaClosure}, which represents a lua closure
* whose bytecode is interpreted when the function is invoked.
* @see LuaValue
* @see LuaClosure
* @see org.luaj.vm2.lib.LibFunction
@@ -57,11 +57,11 @@ public class LuaFunction extends LuaValue {
}
public LuaFunction optfunction(LuaFunction defval) {
return this;
return this;
}
public LuaValue getmetatable() {
return s_metatable;
public LuaValue getmetatable() {
return s_metatable;
}
public String tojstring() {
@@ -72,12 +72,15 @@ public class LuaFunction extends LuaValue {
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 ($).
* If the first character is '_', it is skipped.
*/
public String classnamestub() {
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.

View File

@@ -24,14 +24,14 @@ package org.luaj.vm2;
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>
* 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)}
* functions. This ensures that policies regarding pooling of instances are
* encapsulated.
* functions. This ensures that policies regarding pooling of instances are
* encapsulated.
* <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}.
*
* @see LuaValue
@@ -61,16 +61,16 @@ public class LuaInteger extends LuaNumber {
*/
public static LuaNumber valueOf(long l) {
int i = (int) l;
return l==i? (i<=255 && i>=-256? intValues[i+256]:
(LuaNumber) new LuaInteger(i)):
return l==i? (i<=255 && i>=-256? intValues[i+256]:
(LuaNumber) new LuaInteger(i)):
(LuaNumber) LuaDouble.valueOf(l);
}
/** The value being held by this instance. */
public final int v;
/**
* Package protected constructor.
/**
* Package protected constructor.
* @see LuaValue#valueOf(int)
**/
LuaInteger(int i) {
@@ -103,15 +103,15 @@ public class LuaInteger extends LuaNumber {
}
public LuaString optstring(LuaString defval) {
return LuaString.valueOf(Integer.toString(v));
return LuaString.valueOf(Integer.toString(v));
}
public LuaValue tostring() {
return LuaString.valueOf(Integer.toString(v));
return LuaString.valueOf(Integer.toString(v));
}
public String optjstring(String defval) {
return Integer.toString(v);
public String optjstring(String defval) {
return Integer.toString(v);
}
public LuaInteger checkinteger() {
@@ -172,48 +172,48 @@ public class LuaInteger extends LuaNumber {
public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs,v); }
// 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( 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( 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( 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( 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( 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( 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( 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( double rhs ) { return v >= rhs; }
// string comparison
public int strcmp( LuaString rhs ) { typerror("attempt to compare number with string"); return 0; }
public int checkint() {
return v;
public int checkint() {
return v;
}
public long checklong() {
return v;
return v;
}
public double checkdouble() {
return v;
}
public String checkjstring() {
return String.valueOf(v);
public String checkjstring() {
return String.valueOf(v);
}
public LuaString checkstring() {
return valueOf( String.valueOf(v) );
public LuaString checkstring() {
return valueOf( String.valueOf(v) );
}
}

View File

@@ -31,28 +31,28 @@ import java.io.PrintStream;
import org.luaj.vm2.lib.MathLib;
/**
* Subclass of {@link LuaValue} for representing lua strings.
* Subclass of {@link LuaValue} for representing lua strings.
* <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}
* implementation holds the string value in an internal byte array.
* implementation holds the string value in an internal byte array.
* <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.
* <p>
* Currently {@link LuaString}s are pooled via a centrally managed weak table.
* To ensure that as many string values as possible take advantage of this,
* Constructors are not exposed directly. As with number, booleans, and nil,
* To ensure that as many string values as possible take advantage of this,
* Constructors are not exposed directly. As with number, booleans, and nil,
* instance construction should be via {@link LuaValue#valueOf(byte[])} or similar API.
* <p>
* Because of this pooling, users of LuaString <em>must not directly alter the
* bytes in a LuaString</em>, or undefined behavior will result.
* <p>
* When Java Strings are used to initialize {@link LuaString} data, the UTF8 encoding is assumed.
* The functions
* When Java Strings are used to initialize {@link LuaString} data, the UTF8 encoding is assumed.
* The functions
* {@link #lengthAsUtf8(char[])},
* {@link #encodeToUtf8(char[], int, byte[], int)}, and
* {@link #decodeAsUtf8(byte[], int, int)}
* {@link #encodeToUtf8(char[], int, byte[], int)}, and
* {@link #decodeAsUtf8(byte[], int, int)}
* are used to convert back and forth between UTF8 byte arrays and character arrays.
*
* @see LuaValue
@@ -63,15 +63,15 @@ public class LuaString extends LuaValue {
/** The singleton instance for string metatables that forwards to the string functions.
* Typically, this is set to the string metatable as a side effect of loading the string
* library, and is read-write to provide flexible behavior by default. When used in a
* library, and is read-write to provide flexible behavior by default. When used in a
* server environment where there may be roge scripts, this should be replaced with a
* read-only table since it is shared across all lua code in this Java VM.
*/
public static LuaValue s_metatable;
/** The bytes for the string. These <em><b>must not be mutated directly</b></em> because
* the backing may be shared by multiple LuaStrings, and the hash code is
* computed only at construction time.
* the backing may be shared by multiple LuaStrings, and the hash code is
* computed only at construction time.
* It is exposed only for performance and legacy reasons. */
public final byte[] m_bytes;
@@ -84,29 +84,29 @@ public class LuaString extends LuaValue {
/** The hashcode for this string. Computed at construct time. */
private final int m_hashcode;
/** Size of cache of recent short strings. This is the maximum number of LuaStrings that
/** Size of cache of recent short strings. This is the maximum number of LuaStrings that
* will be retained in the cache of recent short strings. Exposed to package for testing. */
static final int RECENT_STRINGS_CACHE_SIZE = 128;
/** Maximum length of a string to be considered for recent short strings caching.
/** Maximum length of a string to be considered for recent short strings caching.
* This effectively limits the total memory that can be spent on the recent strings cache,
* because no LuaString whose backing exceeds this length will be put into the cache.
* because no LuaString whose backing exceeds this length will be put into the cache.
* Exposed to package for testing. */
static final int RECENT_STRINGS_MAX_LENGTH = 32;
/** Simple cache of recently created strings that are short.
* This is simply a list of strings, indexed by their hash codes modulo the cache size
* that have been recently constructed. If a string is being constructed frequently
* from different contexts, it will generally show up as a cache hit and resolve
/** Simple cache of recently created strings that are short.
* This is simply a list of strings, indexed by their hash codes modulo the cache size
* that have been recently constructed. If a string is being constructed frequently
* from different contexts, it will generally show up as a cache hit and resolve
* to the same value. */
private static final class RecentShortStrings {
private static final LuaString recent_short_strings[] =
private static final LuaString recent_short_strings[] =
new LuaString[RECENT_STRINGS_CACHE_SIZE];
}
/**
* Get a {@link LuaString} instance whose bytes match
* the supplied Java String using the UTF8 encoding.
* Get a {@link LuaString} instance whose bytes match
* the supplied Java String using the UTF8 encoding.
* @param string Java String containing characters to encode as UTF8
* @return {@link LuaString} with UTF8 bytes corresponding to the supplied String
*/
@@ -120,7 +120,7 @@ public class LuaString extends LuaValue {
/** Construct a {@link LuaString} for a portion of a byte array.
* <p>
* 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
* new byte array, and cache lookup may be performed.
* <p>
@@ -172,11 +172,11 @@ public class LuaString extends LuaValue {
/** Construct a {@link LuaString} using the supplied characters as byte values.
* <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>
* This is most useful for constructing byte sequences that do not conform to UTF8.
* @param bytes array of char, whose values are truncated at 8-bits each and put into a byte array.
* @return {@link LuaString} wrapping a copy of the byte buffer
* This is most useful for constructing byte sequences that do not conform to UTF8.
* @param bytes array of char, whose values are truncated at 8-bits each and put into a byte array.
* @return {@link LuaString} wrapping a copy of the byte buffer
*/
public static LuaString valueOf(char[] bytes) {
return valueOf(bytes, 0, bytes.length);
@@ -184,11 +184,11 @@ public class LuaString extends LuaValue {
/** Construct a {@link LuaString} using the supplied characters as byte values.
* <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>
* This is most useful for constructing byte sequences that do not conform to UTF8.
* @param bytes array of char, whose values are truncated at 8-bits each and put into a byte array.
* @return {@link LuaString} wrapping a copy of the byte buffer
* This is most useful for constructing byte sequences that do not conform to UTF8.
* @param bytes array of char, whose values are truncated at 8-bits each and put into a byte array.
* @return {@link LuaString} wrapping a copy of the byte buffer
*/
public static LuaString valueOf(char[] bytes, int off, int len) {
byte[] b = new byte[len];
@@ -215,7 +215,7 @@ public class LuaString extends LuaValue {
* The LuaString returned will either be a new LuaString containing the byte array,
* or be an existing LuaString used already having the same value.
* <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.
* @param bytes byte buffer
* @return {@link LuaString} wrapping the byte buffer
@@ -241,11 +241,11 @@ public class LuaString extends LuaValue {
}
public boolean isstring() {
return true;
return true;
}
public LuaValue getmetatable() {
return s_metatable;
public LuaValue getmetatable() {
return s_metatable;
}
public int type() {
@@ -289,20 +289,20 @@ public class LuaString extends LuaValue {
public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs, checkarith()); }
// relational operators, these only work with other strings
public LuaValue lt( LuaValue rhs ) { return rhs.strcmp(this)>0? LuaValue.TRUE: FALSE; }
public boolean lt_b( LuaValue rhs ) { return rhs.strcmp(this)>0; }
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.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( 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 boolean lteq_b( LuaValue rhs ) { return rhs.strcmp(this)>=0; }
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.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( 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 boolean gt_b( LuaValue rhs ) { return rhs.strcmp(this)<0; }
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.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( 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 boolean gteq_b( LuaValue rhs ) { return rhs.strcmp(this)<=0; }
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.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( 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 Buffer concat(Buffer rhs) { return rhs.concatTo(this); }
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];
System.arraycopy(lhs.m_bytes, lhs.m_offset, b, 0, lhs.m_length);
System.arraycopy(this.m_bytes, this.m_offset, b, lhs.m_length, this.m_length);
return valueUsing(b, 0, b.length);
}
// string comparison
// string comparison
public int strcmp(LuaValue lhs) { return -lhs.strcmp(this); }
public int strcmp(LuaString rhs) {
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 */
private double checkarith() {
private double checkarith() {
double d = scannumber();
if ( Double.isNaN(d) )
if ( Double.isNaN(d) )
aritherror();
return d;
}
@@ -368,15 +368,15 @@ public class LuaString extends LuaValue {
public boolean isint() {
double d = scannumber();
if ( Double.isNaN(d) )
if ( Double.isNaN(d) )
return false;
int i = (int) d;
return i == d;
}
public boolean islong() {
public boolean islong() {
double d = scannumber();
if ( Double.isNaN(d) )
if ( Double.isNaN(d) )
return false;
long l = (long) d;
return l == d;
@@ -398,7 +398,7 @@ public class LuaString extends LuaValue {
return checkint();
}
public LuaInteger optinteger(LuaInteger defval) {
public LuaInteger optinteger(LuaInteger defval) {
return checkinteger();
}
@@ -411,15 +411,15 @@ public class LuaString extends LuaValue {
}
public LuaString optstring(LuaString defval) {
return this;
return this;
}
public LuaValue tostring() {
return this;
}
public String optjstring(String defval) {
return tojstring();
public String optjstring(String defval) {
return tojstring();
}
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.
* @param beginIndex The zero-based index of the first character to include.
* @param endIndex The zero-based index of position after the last character.
* @return LuaString which is a substring whose first character is at offset
* @return LuaString which is a substring whose first character is at offset
* beginIndex and extending for (endIndex - beginIndex ) characters.
*/
public LuaString substring( int beginIndex, int endIndex ) {
@@ -476,7 +476,7 @@ public class LuaString extends LuaValue {
return val.raweq(this);
}
public boolean raweq( LuaString s ) {
public boolean raweq( LuaString s ) {
if ( this == s )
return true;
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 ) {
if ( a.length < i + n || b.length < j + n )
return false;
while ( --n>=0 )
while ( --n>=0 )
if ( a[i++]!=b[j++] )
return false;
return true;
@@ -535,8 +535,8 @@ public class LuaString extends LuaValue {
return luaByte( index );
}
public String checkjstring() {
return tojstring();
public String checkjstring() {
return tojstring();
}
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 bytes destination byte array
* @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 offset starting index in byte array
* @param length number of bytes to convert
* @return Java String corresponding to the value of bytes interpreted using UTF8
* @return Java String corresponding to the value of bytes interpreted using UTF8
* @see #lengthAsUtf8(char[])
* @see #encodeToUtf8(char[], int, byte[], int)
* @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
* starting at offset.
* starting at offset.
* <p>
* The string should be measured first with lengthAsUtf8
* to make sure the given byte array is large enough.
@@ -759,22 +759,22 @@ public class LuaString extends LuaValue {
// --------------------- 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
* @return IntValue, DoubleValue, or NIL depending on the content of the string.
* @see LuaValue#tonumber()
* @see LuaValue#tonumber()
*/
public LuaValue tonumber() {
double d = scannumber();
return Double.isNaN(d)? NIL: valueOf(d);
}
/**
/**
* convert to a number using a supplied base, or NIL if it can't be converted
* @param base the base to use, such as 10
* @return IntValue, DoubleValue, or NIL depending on the content of the string.
* @see LuaValue#tonumber()
* @see LuaValue#tonumber()
*/
public LuaValue tonumber( int 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',
* 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() {
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);
}
/**
/**
* Convert to a number in a base, or return Double.NaN if not a number.
* @param base the base to use between 2 and 36
* @return double value if conversion is valid, or Double.NaN if not
* @return double value if conversion is valid, or Double.NaN if not
*/
public double scannumber(int base) {
if ( base < 2 || base > 36 )
@@ -884,7 +884,7 @@ public class LuaString extends LuaValue {
* @param base the base to use, such as 10
* @param start the index to start searching from
* @param end the first index beyond the search range
* @return double value if conversion is valid,
* @return double value if conversion is valid,
* or Double.NaN if not
*/
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':
m_bytes[i]>='A'&&m_bytes[i]<='Z'? ('A'-10): ('a'-10));
if ( digit < 0 || digit >= base )
return Double.NaN;
return Double.NaN;
x = x * base + digit;
if ( x < 0 )
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.
* @param start the index to start searching from
* @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
*/
private double scandouble(int start, int end) {
@@ -930,7 +930,7 @@ public class LuaString extends LuaValue {
c[i-start] = (char) m_bytes[i];
try {
return Double.parseDouble(new String(c));
} catch ( Exception e ) {
} catch ( Exception e ) {
return Double.NaN;
}
}

View File

@@ -25,23 +25,23 @@ import java.lang.ref.WeakReference;
import java.util.Vector;
/**
* Subclass of {@link LuaValue} for representing lua tables.
* Subclass of {@link LuaValue} for representing lua tables.
* <p>
* Almost all API's implemented in {@link LuaTable} are defined and documented in {@link LuaValue}.
* <p>
* 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 #opttable(LuaTable)}
* {@link #opttable(LuaTable)}
* <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:
* <ul>
* <li>{@link #get(LuaValue)}</li>
* <li>{@link #set(LuaValue,LuaValue)}</li>
* <li>{@link #rawget(LuaValue)}</li>
* <li>{@link #get(LuaValue)}</li>
* <li>{@link #set(LuaValue,LuaValue)}</li>
* <li>{@link #rawget(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>
* <p>
* To iterate over key-value pairs from Java, use
@@ -56,7 +56,7 @@ import java.util.Vector;
* }}</pre>
*
* <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}:
* <ul>
* <li>{@link LuaValue#tableOf()} empty table</li>
@@ -92,7 +92,7 @@ public class LuaTable extends LuaValue implements Metatable {
hash = NOBUCKETS;
}
/**
/**
* Construct table with preset capacity.
* @param narray capacity of array 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 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}
*/
public LuaTable(LuaValue[] named, LuaValue[] unnamed, Varargs lastarg) {
@@ -123,17 +123,17 @@ public class LuaTable extends LuaValue implements Metatable {
}
/**
* Construct table of unnamed elements.
* @param varargs Unnamed elements in order {@code value-1, value-2, ... }
* Construct table of unnamed elements.
* @param varargs Unnamed elements in order {@code value-1, value-2, ... }
*/
public LuaTable(Varargs varargs) {
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 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) {
int nskip = firstarg-1;
@@ -152,8 +152,8 @@ public class LuaTable extends LuaValue implements Metatable {
return "table";
}
public boolean istable() {
return true;
public boolean istable() {
return true;
}
public LuaTable checktable() {
@@ -185,17 +185,17 @@ public class LuaTable extends LuaValue implements Metatable {
return v;
}
/**
* 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.
/**
* 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.
*/
protected int getArrayLength() {
return array.length;
}
/**
* 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.
/**
* 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.
*/
protected int getHashLength() {
return hash.length;
@@ -294,35 +294,35 @@ public class LuaTable extends LuaValue implements Metatable {
}
/** Remove the element at a position in a list-table
*
*
* @param pos the position to remove
* @return The removed item, or {@link #NONE} if not removed
*/
public LuaValue remove(int pos) {
int n = rawlen();
int n = length();
if ( pos == 0 )
pos = n;
else if (pos > n)
return NONE;
LuaValue v = rawget(pos);
LuaValue v = get(pos);
for ( LuaValue r=v; !r.isnil(); ) {
r = rawget(pos+1);
rawset(pos++, r);
r = get(pos+1);
set(pos++, r);
}
return v.isnil()? NONE: v;
}
/** Insert an element at a position in a list-table
*
*
* @param pos the position to remove
* @param value The value to insert
*/
public void insert(int pos, LuaValue value) {
if ( pos == 0 )
pos = rawlen()+1;
pos = length()+1;
while ( ! value.isnil() ) {
LuaValue v = rawget( pos );
rawset(pos++, value);
LuaValue v = get( pos );
set(pos++, value);
value = v;
}
}
@@ -355,14 +355,14 @@ public class LuaTable extends LuaValue implements Metatable {
return rawlen();
}
public LuaValue len() {
public LuaValue len() {
final LuaValue h = metatag(LEN);
if (h.toboolean())
return h.call(this);
return LuaInteger.valueOf(rawlen());
}
public int rawlen() {
public int rawlen() {
int a = getArrayLength();
int n = a+1,m=0;
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
*/
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
* contiguous array part of a table
* Get the next element after a particular key in the
* contiguous array part of a table
* @return key,value or none
*/
public Varargs inext(LuaValue key) {
@@ -472,7 +472,8 @@ public class LuaTable extends LuaValue implements Metatable {
}
}
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.
rehash( key.toint() );
if ( arrayset(key.toint(), value) )
@@ -517,7 +518,7 @@ public class LuaTable extends LuaValue implements Metatable {
}
}
/**
/**
* Find the hashtable slot to use
* @param key key to look for
* @return slot to use
@@ -719,7 +720,7 @@ public class LuaTable extends LuaValue implements Metatable {
StrongSlot entry = slot.first();
if (entry != null)
newArray[ k - 1 ] = entry.value();
} else {
} else if ( !(slot instanceof DeadSlot) ) {
int j = slot.keyindex( newHashMask );
newHash[j] = slot.relink( newHash[j] );
}
@@ -779,7 +780,7 @@ public class LuaTable extends LuaValue implements Metatable {
//
// implemented heap sort from wikipedia
//
// Only sorts the contiguous array part.
// Only sorts the contiguous array part.
//
/** Sort the table using a comparator.
* @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()) {
dropWeakArrayValues();
}
int n = array.length;
while ( n > 0 && array[n-1] == null )
--n;
if ( n > 1 )
heapSort(n, comparator);
int n = length();
if ( n > 1 )
heapSort(n, comparator.isnil() ? null : comparator);
}
private void heapSort(int count, LuaValue cmpfunc) {
heapify(count, cmpfunc);
for ( int end=count-1; end>0; ) {
swap(end, 0);
siftDown(0, --end, cmpfunc);
for ( int end=count; end>1; ) {
LuaValue a = get(end); // swap(end, 1)
set(end, get(1));
set(1, a);
siftDown(1, --end, cmpfunc);
}
}
private void heapify(int count, LuaValue cmpfunc) {
for ( int start=count/2-1; start>=0; --start )
siftDown(start, count - 1, cmpfunc);
for ( int start=count/2; start>0; --start )
siftDown(start, count, cmpfunc);
}
private void siftDown(int start, int end, LuaValue cmpfunc) {
for ( int root=start; root*2+1 <= end; ) {
int child = root*2+1;
for ( int root=start; root*2 <= end; ) {
int child = root*2;
if (child < end && compare(child, child + 1, cmpfunc))
++child;
++child;
if (compare(root, child, cmpfunc)) {
swap(root, child);
LuaValue a = get(root); // swap(root, child)
set(root, get(child));
set(child, a);
root = child;
} else
return;
@@ -823,32 +826,19 @@ public class LuaTable extends LuaValue implements Metatable {
}
private boolean compare(int i, int j, LuaValue cmpfunc) {
LuaValue a, b;
if (m_metatable == null) {
a = array[i];
b = array[j];
} else {
a = m_metatable.arrayget(array, i);
b = m_metatable.arrayget(array, j);
}
LuaValue a = get(i), b = get(j);
if ( a == null || b == null )
return false;
if ( ! cmpfunc.isnil() ) {
if ( cmpfunc != null ) {
return cmpfunc.call(a,b).toboolean();
} else {
return a.lt_b(b);
}
}
private void swap(int i, int j) {
LuaValue a = array[i];
array[i] = array[j];
array[j] = a;
}
/** This may be deprecated in a future release.
/** This may be deprecated in a future release.
* 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() {
LuaValue k = LuaValue.NIL;
@@ -859,9 +849,9 @@ public class LuaTable extends LuaValue implements Metatable {
}
}
/** This may be deprecated in a future release.
* It is recommended to use next() instead
* @return array of keys in the table
/** This may be deprecated in a future release.
* It is recommended to use next() instead
* @return array of keys in the table
* */
public LuaValue[] keys() {
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.
* <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)}
* <p>
* <p>
* Any LuaValue can be used as a stand-in for Varargs, for both calls and return values.
* When doing so, nargs() will return 1 and arg1() or arg(1) will return this.
* This simplifies the case when calling or implementing varargs functions with only
* 1 argument or 1 return value.
* Any LuaValue can be used as a stand-in for Varargs, for both calls and return values.
* When doing so, nargs() will return 1 and arg1() or arg(1) will return this.
* This simplifies the case when calling or implementing varargs functions with only
* 1 argument or 1 return value.
* <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)}
* or by taking a portion of the args using {@code Varargs.subargs(int start)}
* <p>
@@ -57,22 +57,22 @@ public abstract class Varargs {
abstract public LuaValue arg( int i );
/**
* Get the number of arguments, or 0 if there are none.
* @return number of arguments.
* Get the number of arguments, or 0 if there are none.
* @return number of arguments.
*/
abstract public int narg();
/**
* Get the first argument in the list.
* Get the first argument in the list.
* @return LuaValue which is first in the list, or LuaValue.NIL if there are no values.
* @see Varargs#arg(int)
* @see LuaValue#NIL
*/
abstract public LuaValue arg1();
/**
/**
* 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; }
@@ -88,7 +88,7 @@ public abstract class Varargs {
// utilities to get specific arguments and type-check them.
// -----------------------------------------------------------------------
/** Gets the type of argument {@code i}
/** Gets the type of argument {@code i}
* @param i the index of the argument to convert, 1 is the first argument
* @return int value corresponding to one of the LuaValue integer type values
* @see LuaValue#TNIL
@@ -117,20 +117,20 @@ public abstract class Varargs {
public boolean isfunction(int i) { return arg(i).isfunction(); }
/** Tests if argument i is a number.
* Since anywhere a number is required, a string can be used that
* is a number, this will return true for both numbers and
* strings that can be interpreted as numbers.
* Since anywhere a number is required, a string can be used that
* is a number, this will return true for both numbers and
* strings that can be interpreted as numbers.
* @param i the index of the argument to test, 1 is the first argument
* @return true if the argument exists and is a number or
* @return true if the argument exists and is a number or
* string that can be interpreted as a number, false otherwise
* @see LuaValue#TNUMBER
* @see LuaValue#TSTRING
* */
public boolean isnumber(int i) { return arg(i).isnumber(); }
/** Tests if argument i is a string.
* Since all lua numbers can be used where strings are used,
* this will return true for both strings and numbers.
/** Tests if argument i is a string.
* Since all lua numbers can be used where strings are used,
* this will return true for both strings and numbers.
* @param i the index of the argument to test, 1 is the first argument
* @return true if the argument exists and is a string or number, false otherwise
* @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.
* @param i the index of the argument to test, 1 is the first argument
* @return true if argument i is boolean true, false if it is false, or defval if not supplied or nil
* @return true if argument i is boolean true, false if it is false, or defval if not supplied or nil
* @exception LuaError if the argument is not a lua boolean
* */
public boolean optboolean(int i, boolean defval) { return arg(i).optboolean(defval); }
@@ -256,7 +256,7 @@ public abstract class Varargs {
* */
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.
* @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
@@ -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
* @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.
* @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(); }
/** 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
* @return int value with fraction discarded and truncated if necessary if argument i is number
* @exception LuaError if the argument is not a number
* @return int value if argument i is a number or string that converts to a number
* @exception LuaError if the argument cannot be represented by a java int value
* */
public int checkint(int i) { return arg(i).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.
* @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(); }
/** 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
* @return long value with fraction discarded and truncated if necessary if argument i is number
* @exception LuaError if the argument is not a number
* @return long value if argument i is a number or string that converts to a number
* @exception LuaError if the argument cannot be represented by a java long value
* */
public long checklong(int i) { return arg(i).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.
* @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(); }
/** 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.
* @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
@@ -387,7 +387,7 @@ public abstract class Varargs {
public LuaValue checknotnil(int i) { return arg(i).checknotnil(); }
/** Performs test on argument i as a LuaValue when a user-supplied assertion passes, or throw an error.
* Returns normally if the value of {@code test} is {@code true}, otherwise throws and argument error with
* Returns normally if the value of {@code test} is {@code true}, otherwise throws and argument error with
* the supplied message, {@code msg}.
* @param test user supplied assertion to test against
* @param i the index to report in any error message
@@ -404,20 +404,20 @@ public abstract class Varargs {
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
* @return {@code false} if argument i is nil or false, otherwise {@code true}
* */
public boolean toboolean(int i) { return arg(i).toboolean(); }
/** Return argument i as a java byte value, discarding any fractional part and truncating,
/** Return argument i as a java byte value, discarding any fractional part and truncating,
* or 0 if not a number.
* @param i the index of the argument to convert, 1 is the first argument
* @return byte value with fraction discarded and truncated if necessary if argument i is number, otherwise 0
* */
public byte tobyte(int i) { return arg(i).tobyte(); }
/** Return argument i as a java char value, discarding any fractional part and truncating,
/** Return argument i as a java char value, discarding any fractional part and truncating,
* or 0 if not a number.
* @param i the index of the argument to convert, 1 is the first argument
* @return char value with fraction discarded and truncated if necessary if argument i is number, otherwise 0
@@ -430,21 +430,21 @@ public abstract class Varargs {
* */
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.
* @param i the index of the argument to convert, 1 is the first argument
* @return float value with excess fraction discarded and truncated if necessary if argument i is number, otherwise 0
* */
public float tofloat(int i) { return arg(i).tofloat(); }
/** Return argument i as a java int value, discarding any fractional part and truncating,
/** Return argument i as a java int value, discarding any fractional part and truncating,
* or 0 if not a number.
* @param i the index of the argument to convert, 1 is the first argument
* @return int value with fraction discarded and truncated if necessary if argument i is number, otherwise 0
* */
public int toint(int i) { return arg(i).toint(); }
/** Return 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.
* @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
@@ -457,7 +457,7 @@ public abstract class Varargs {
* */
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.
* @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
@@ -477,8 +477,8 @@ public abstract class Varargs {
* */
public Object touserdata(int i,Class c) { return arg(i).touserdata(c); }
/** Convert the list of varargs values to a human readable java String.
* @return String value in human readable form such as {1,2}.
/** Convert the list of varargs values to a human readable java String.
* @return String value in human readable form such as {1,2}.
*/
public String tojstring() {
Buffer sb = new Buffer();
@@ -491,8 +491,8 @@ public abstract class Varargs {
return sb.tojstring();
}
/** Convert the value or values to a java String using Varargs.tojstring()
* @return String value in human readable form.
/** Convert the value or values to a java String using Varargs.tojstring()
* @return String value in human readable form.
* @see Varargs#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>
* 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)
*/
static final class PairVarargs extends Varargs {
private final LuaValue v1;
private final Varargs v2;
/** Construct a Varargs from an two LuaValue.
/** Construct a Varargs from an two LuaValue.
* <p>
* 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)
*/
PairVarargs(LuaValue v1, Varargs v2) {
@@ -571,8 +571,8 @@ public abstract class Varargs {
public int narg() {
return 1+v2.narg();
}
public LuaValue arg1() {
return v1;
public LuaValue arg1() {
return v1;
}
public Varargs subargs(final int start) {
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>
* 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[], Varargs)
*/
static final class ArrayVarargs extends Varargs {
private final LuaValue[] v;
private final Varargs r;
/** Construct a Varargs from an array of LuaValue.
/** Construct a Varargs from an array of LuaValue.
* <p>
* 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[], 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>
* 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, Varargs)
*/
@@ -644,11 +644,11 @@ public abstract class Varargs {
private final LuaValue[] v;
private final int length;
private final Varargs more;
/** Construct a Varargs from an array of LuaValue.
/** Construct a Varargs from an array of LuaValue.
* <p>
* 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)
*/
ArrayPartVarargs(LuaValue[] v, int offset, int length) {
@@ -657,11 +657,11 @@ public abstract class Varargs {
this.length = length;
this.more = LuaValue.NONE;
}
/** Construct a Varargs from an array of LuaValue and additional arguments.
/** Construct a Varargs from an array of LuaValue and additional arguments.
* <p>
* 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)
*/
public ArrayPartVarargs(LuaValue[] v, int offset, int length, Varargs more) {
@@ -676,8 +676,8 @@ public abstract class Varargs {
public int narg() {
return length + more.narg();
}
public LuaValue arg1() {
return length>0? v[offset]: more.arg1();
public LuaValue arg1() {
return length>0? v[offset]: more.arg1();
}
public Varargs subargs(int start) {
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.
* 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.
* @exclude
* @hide
*/
Varargs dealias() {
public Varargs dealias() {
int n = narg();
switch (n) {
case 0: return LuaValue.NONE;

View File

@@ -28,14 +28,14 @@ import java.io.OutputStream;
import org.luaj.vm2.Globals;
import org.luaj.vm2.LoadState;
import org.luaj.vm2.LocVars;
import org.luaj.vm2.Prototype;
import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Prototype;
/** Class to dump a {@link Prototype} into an output stream, as part of compiling.
* <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}.
* <p>
* 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;
// header fields
private boolean IS_LITTLE_ENDIAN = false;
private boolean IS_LITTLE_ENDIAN = true;
private int NUMBER_FORMAT = NUMBER_FORMAT_DEFAULT;
private int SIZEOF_LUA_NUMBER = 8;
private static final int SIZEOF_INT = 4;
@@ -190,7 +190,7 @@ public class DumpState {
dumpString((LuaString)o);
break;
default:
throw new IllegalArgumentException("bad type for " + o);
throw new IllegalArgumentException("bad type for " + o);
}
}
n = f.p.length;

View File

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

View File

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

View File

@@ -442,6 +442,10 @@ public class DebugLib extends TwoArgFunction {
return callstack().traceback(level);
}
public CallFrame getCallFrame(int level) {
return callstack().getCallFrame(level);
}
void callHook(LuaThread.State s, LuaValue type, LuaValue arg) {
if (s.inhook || s.hookfunc == null) return;
s.inhook = true;
@@ -645,7 +649,7 @@ public class DebugLib extends TwoArgFunction {
}
static class CallFrame {
public static class CallFrame {
LuaFunction f;
int pc;
int top;
@@ -691,7 +695,7 @@ public class DebugLib extends TwoArgFunction {
return NIL;
}
}
int currentline() {
public int currentline() {
if ( !f.isclosure() ) return -1;
int[] li = f.checkclosure().p.lineinfo;
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 */
? p.getlocalname(t + 1, pc)
: (t < p.upvalues.length ? p.upvalues[t].name : QMARK);
name = kname(p, k);
return new NameWhat( name.tojstring(), vn != null && vn.eq_b(ENV)? "global": "field" );
String jname = kname(p, pc, k);
return new NameWhat( jname, vn != null && vn.eq_b(ENV)? "global": "field" );
}
case Lua.OP_GETUPVAL: {
int u = Lua.GETARG_B(i); /* upvalue index */
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_LOADKX: {
@@ -816,8 +820,8 @@ public class DebugLib extends TwoArgFunction {
}
case Lua.OP_SELF: {
int k = Lua.GETARG_C(i); /* key index */
name = kname(p, k);
return new NameWhat( name.tojstring(), "method" );
String jname = kname(p, pc, k);
return new NameWhat( jname, "method" );
}
default:
break;
@@ -826,11 +830,20 @@ public class DebugLib extends TwoArgFunction {
return null; /* no useful name found */
}
static LuaString kname(Prototype p, int c) {
if (Lua.ISK(c) && p.k[Lua.INDEXK(c)].isstring())
return p.k[Lua.INDEXK(c)].strvalue();
else
return QMARK;
static String kname(Prototype p, int pc, int c) {
if (Lua.ISK(c)) { /* is 'c' a constant? */
LuaValue k = p.k[Lua.INDEXK(c)];
if (k.isstring()) { /* literal constant? */
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
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
public LuaValue get( LuaValue key ) {
return filemethods.get(key);
@@ -112,6 +118,14 @@ public class IoLib extends TwoArgFunction {
public String tojstring() {
return "file: " + Integer.toHexString(hashCode());
}
public void finalize() {
if (!isclosed()) {
try {
close();
} catch (IOException ignore) {}
}
}
}
/** Enumerated value representing stdin */
@@ -269,8 +283,15 @@ public class IoLib extends TwoArgFunction {
static final class IoLibV extends VarArgFunction {
private File f;
public IoLib iolib;
private boolean toclose;
private Varargs args;
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) {
super();
this.f = f;
@@ -290,22 +311,26 @@ public class IoLib extends TwoArgFunction {
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_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_WRITE: return iolib._io_write(args);
case FILE_CLOSE: return iolib._file_close(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_LINES: return iolib._file_lines(args.arg1());
case FILE_SETVBUF: return iolib._file_setvbuf(args.arg1(),args.checkjstring(2),args.optint(3,8192));
case FILE_LINES: return iolib._file_lines(args);
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_WRITE: return iolib._file_write(args.arg1(),args.subargs(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 ) {
if (opcode == LINES_ITER) {
String s = ioe.getMessage();
error(s != null ? s : ioe.toString());
}
return errorresult(ioe);
}
return NONE;
@@ -361,6 +386,7 @@ public class IoLib extends TwoArgFunction {
// io.popen(prog, [mode]) -> file
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);
}
@@ -369,11 +395,12 @@ public class IoLib extends TwoArgFunction {
return rawopenfile(FTYPE_NAMED, filename, mode);
}
// io.lines(filename) -> iterator
public Varargs _io_lines(String filename) {
infile = filename==null? input(): ioopenfile(FTYPE_NAMED, filename,"r");
// io.lines(filename, ...) -> iterator
public Varargs _io_lines(Varargs args) {
String filename = args.optjstring(1, null);
File infile = filename==null? input(): ioopenfile(FTYPE_NAMED, filename,"r");
checkopen(infile);
return lines(infile);
return lines(infile, filename != null, args.subargs(2));
}
// io.read(...) -> (...)
@@ -401,13 +428,19 @@ public class IoLib extends TwoArgFunction {
// file:setvbuf(mode,[size]) -> void
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);
return LuaValue.TRUE;
}
// file:lines() -> iterator
public Varargs _file_lines(LuaValue file) {
return lines(checkfile(file));
// file:lines(...) -> iterator
public Varargs _file_lines(Varargs args) {
return lines(checkfile(args.arg1()), false, args.subargs(2));
}
// file:read(...) -> (...)
@@ -417,6 +450,12 @@ public class IoLib extends TwoArgFunction {
// file:seek([whence][,offset]) -> pos | nil,error
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) );
}
@@ -433,8 +472,13 @@ public class IoLib extends TwoArgFunction {
}
// lines iterator(s,var) -> var'
public Varargs _lines_iter(LuaValue file) throws IOException {
return freadline(checkfile(file));
public Varargs _lines_iter(LuaValue file, boolean toclose, Varargs args) throws IOException {
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() {
@@ -476,9 +520,9 @@ public class IoLib extends TwoArgFunction {
return varargsOf(NIL, valueOf(errortext));
}
private Varargs lines(final File f) {
private Varargs lines(final File f, boolean toclose, Varargs args) {
try {
return new IoLibV(f,"lnext",LINES_ITER,this);
return new IoLibV(f,"lnext",LINES_ITER,this,toclose,args);
} catch ( Exception e ) {
return error("lines: "+e);
}
@@ -492,6 +536,7 @@ public class IoLib extends TwoArgFunction {
private Varargs ioread(File f, Varargs args) throws IOException {
int i,n=args.narg();
if (n == 0) return freadline(f,false);
LuaValue[] v = new LuaValue[n];
LuaValue ai,vi;
LuaString fmt;
@@ -502,10 +547,11 @@ public class IoLib extends TwoArgFunction {
break item;
case LuaValue.TSTRING:
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] ) {
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;
}
}
@@ -537,6 +583,17 @@ public class IoLib extends TwoArgFunction {
}
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) {
case FTYPE_STDIN: return wrapStdin();
case FTYPE_STDOUT: return wrapStdout();
@@ -553,26 +610,27 @@ public class IoLib extends TwoArgFunction {
// ------------- file reading utilitied ------------------
public static LuaValue freadbytes(File f, int count) throws IOException {
if (count == 0) return f.eof() ? NIL : EMPTYSTRING;
byte[] b = new byte[count];
int r;
if ( ( r = f.read(b,0,b.length) ) < 0 )
return NIL;
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();
int c;
try {
if ( lineonly ) {
loop: while ( (c = f.read()) > 0 ) {
loop: while ( (c = f.read()) >= 0 ) {
switch ( c ) {
case '\r': break;
case '\n': break loop;
case '\r': if (withend) baos.write(c); break;
case '\n': if (withend) baos.write(c); break loop;
default: baos.write(c); break;
}
}
} else {
while ( (c = f.read()) > 0 )
while ( (c = f.read()) >= 0 )
baos.write(c);
}
} catch ( EOFException e ) {
@@ -582,15 +640,15 @@ public class IoLib extends TwoArgFunction {
(LuaValue) NIL:
(LuaValue) LuaString.valueUsing(baos.toByteArray());
}
public static LuaValue freadline(File f) throws IOException {
return freaduntil(f,true);
public static LuaValue freadline(File f,boolean withend) throws IOException {
return freaduntil(f,true,withend);
}
public static LuaValue freadall(File f) throws IOException {
int n = f.remaining();
if ( n >= 0 ) {
return freadbytes(f, n);
return n == 0 ? EMPTYSTRING : freadbytes(f, n);
} else {
return freaduntil(f,false);
return freaduntil(f,false,false);
}
}
public static LuaValue freadnumber(File f) throws IOException {

View File

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

View File

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

View File

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

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.LibFunction;
/**
* Subclass of {@link IoLib} and therefore {@link LibFunction} which implements the lua standard {@code io}
* library for the JSE platform.
* <p>
* It uses RandomAccessFile to implement seek on files.
/**
* Subclass of {@link IoLib} and therefore {@link LibFunction} which implements the lua standard {@code io}
* library for the JSE platform.
* <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()}
* <pre> {@code
* Globals globals = JsePlatform.standardGlobals();
* globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
* } </pre>
* <p>
* For special cases where the smallest possible footprint is desired,
* For special cases where the smallest possible footprint is desired,
* a minimal set of libraries could be loaded
* directly via {@link Globals#load(LuaValue)} using code such as:
* <pre> {@code
@@ -96,9 +96,9 @@ public class JseIoLib extends IoLib {
protected File openProgram(String prog, String mode) throws IOException {
final Process p = Runtime.getRuntime().exec(prog);
return "w".equals(mode)?
new FileImpl( p.getOutputStream() ):
new FileImpl( p.getInputStream() );
return "w".equals(mode)?
new FileImpl( p.getOutputStream() ):
new FileImpl( p.getInputStream() );
}
protected File tmpFile() throws IOException {
@@ -133,7 +133,7 @@ public class JseIoLib extends IoLib {
this( null, null, o );
}
public String tojstring() {
return "file ("+this.hashCode()+")";
return "file (" + (this.closed ? "closed" : String.valueOf(this.hashCode())) + ")";
}
public boolean isstdfile() {
return file == null;
@@ -199,11 +199,11 @@ public class JseIoLib extends IoLib {
}
notimplemented();
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 {
if ( is != null )
if ( is != null )
return is.read();
else if ( file != null ) {
return file.read();
@@ -321,7 +321,7 @@ public class JseIoLib extends IoLib {
}
public int remaining() throws IOException {
return 0;
return -1;
}
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.
* <p>
* This contains more complete implementations of the following functions
* using features that are specific to JSE:
* This contains more complete implementations of the following functions
* using features that are specific to JSE:
* <ul>
* <li>{@code execute()}</li>
* <li>{@code remove()}</li>
@@ -42,18 +42,18 @@ import org.luaj.vm2.lib.OsLib;
* <li>{@code tmpname()}</li>
* </ul>
* <p>
* Because the nature of the {@code os} library is to encapsulate
* os-specific features, the behavior of these functions varies considerably
* from their counterparts in the C platform.
* Because the nature of the {@code os} library is to encapsulate
* os-specific features, the behavior of these functions varies considerably
* from their counterparts in the C platform.
* <p>
* Typically, this library is included as part of a call to
* Typically, this library is included as part of a call to
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()}
* <pre> {@code
* Globals globals = JsePlatform.standardGlobals();
* System.out.println( globals.get("os").get("time").call() );
* } </pre>
* <p>
* For special cases where the smallest possible footprint is desired,
* For special cases where the smallest possible footprint is desired,
* a minimal set of libraries could be loaded
* directly via {@link Globals#load(LuaValue)} using code such as:
* <pre> {@code
@@ -126,7 +126,7 @@ public class JseOsLib extends org.luaj.vm2.lib.OsLib {
protected String tmpname() {
try {
java.io.File f = java.io.File.createTempFile(TMP_PREFIX ,TMP_SUFFIX);
return f.getName();
return f.getAbsolutePath();
} catch ( IOException ioe ) {
return super.tmpname();
}