Add javadoc content to source files.

This commit is contained in:
James Roseborough
2011-01-21 01:38:35 +00:00
parent b94df87262
commit 1a648fef56
16 changed files with 778 additions and 69 deletions

View File

@@ -25,20 +25,48 @@ package org.luaj.vm2;
/** /**
* String buffer for use in string library methods, optimized for production * String buffer for use in string library methods, optimized for production
* of StrValue instances. * of StrValue instances.
* <p>
* The buffer can begin initially as a wrapped {@link LuaValue}
* and only when concatenation actually occurs are the bytes first copied.
* <p>
* To convert back to a {@link LuaValue} again,
* the function {@link Buffer#value()} is used.
* @see LuaValue
* @see LuaValue#buffer()
* @see LuaString
*/ */
public final class Buffer { public final class Buffer {
/** Default capacity for a buffer: 64 */
private static final int DEFAULT_CAPACITY = 64; private static final int DEFAULT_CAPACITY = 64;
/** Shared static array with no bytes */
private static final byte[] NOBYTES = {}; private static final byte[] NOBYTES = {};
/** Bytes in this buffer */
private byte[] bytes; private byte[] bytes;
/** Length of this buffer */
private int length; private int length;
/** Offset into the byte array */
private int offset; private int offset;
/** Value of this buffer, when not represented in bytes */
private LuaValue value; private LuaValue value;
/**
* Create buffer with default capacity
* @see #DEFAULT_CAPACITY
*/
public Buffer() { public Buffer() {
this(DEFAULT_CAPACITY); this(DEFAULT_CAPACITY);
} }
/**
* Create buffer with specified initial capacity
* @param initialCapacity the initial capacity
*/
public Buffer( int initialCapacity ) { public Buffer( int initialCapacity ) {
bytes = new byte[ initialCapacity ]; bytes = new byte[ initialCapacity ];
length = 0; length = 0;
@@ -46,16 +74,28 @@ public final class Buffer {
value = null; value = null;
} }
/**
* Create buffer with specified initial value
* @param value the initial value
*/
public Buffer(LuaValue value) { public Buffer(LuaValue value) {
bytes = NOBYTES; bytes = NOBYTES;
length = offset = 0; length = offset = 0;
this.value = value; this.value = value;
} }
/**
* Get buffer contents as a {@link LuaValue}
* @return value as a {@link LuaValue}, converting as necessary
*/
public LuaValue value() { public LuaValue value() {
return value != null? value: this.tostring(); return value != null? value: this.tostring();
} }
/**
* Set buffer contents as a {@link LuaValue}
* @param value value to set
*/
public Buffer setvalue(LuaValue value) { public Buffer setvalue(LuaValue value) {
bytes = NOBYTES; bytes = NOBYTES;
offset = length = 0; offset = length = 0;
@@ -63,30 +103,54 @@ public final class Buffer {
return this; return this;
} }
/**
* Convert the buffer to a {@link LuaString}
* @return the value as a {@link LuaString}
*/
public final LuaString tostring() { public final LuaString tostring() {
realloc( length, 0 ); realloc( length, 0 );
return LuaString.valueOf( bytes, offset, length ); return LuaString.valueOf( bytes, offset, length );
} }
/**
* Convert the buffer to a Java String
* @return the value as a Java String
*/
public String tojstring() { public String tojstring() {
return value().tojstring(); return value().tojstring();
} }
/**
* Convert the buffer to a Java String
* @return the value as a Java String
*/
public String toString() { public String toString() {
return tojstring(); return tojstring();
} }
/**
* Append a single byte to the buffer.
* @return {@code this} to allow call chaining
*/
public final Buffer append( byte b ) { public final Buffer append( byte b ) {
makeroom( 0, 1 ); makeroom( 0, 1 );
bytes[ offset + length++ ] = b; bytes[ offset + length++ ] = b;
return this; return this;
} }
/**
* Append a {@link LuaValue} to the buffer.
* @return {@code this} to allow call chaining
*/
public final Buffer append( LuaValue val ) { public final Buffer append( LuaValue val ) {
append( val.strvalue() ); append( val.strvalue() );
return this; return this;
} }
/**
* Append a {@link LuaString} to the buffer.
* @return {@code this} to allow call chaining
*/
public final Buffer append( LuaString str ) { public final Buffer append( LuaString str ) {
final int n = str.m_length; final int n = str.m_length;
makeroom( 0, n ); makeroom( 0, n );
@@ -95,6 +159,12 @@ public final class Buffer {
return this; return this;
} }
/**
* Append a Java String to the buffer.
* The Java string will be converted to bytes using the UTF8 encoding.
* @return {@code this} to allow call chaining
* @see LuaString#encodeToUtf8(char[], byte[], int)
*/
public final Buffer append( String str ) { public final Buffer append( String str ) {
char[] chars = str.toCharArray(); char[] chars = str.toCharArray();
final int n = LuaString.lengthAsUtf8( chars ); final int n = LuaString.lengthAsUtf8( chars );
@@ -104,18 +174,36 @@ public final class Buffer {
return this; return this;
} }
/** Concatenate this buffer onto a {@link LuaValue}
* @param lhs the left-hand-side value onto which we are concatenating {@code this}
* @return {@link Buffer} for use in call chaining.
*/
public Buffer concatTo(LuaValue lhs) { public Buffer concatTo(LuaValue lhs) {
return setvalue(lhs.concat(value())); return setvalue(lhs.concat(value()));
} }
/** Concatenate this buffer onto a {@link LuaString}
* @param lhs the left-hand-side value onto which we are concatenating {@code this}
* @return {@link Buffer} for use in call chaining.
*/
public Buffer concatTo(LuaString lhs) { public Buffer concatTo(LuaString lhs) {
return value!=null&&!value.isstring()? setvalue(lhs.concat(value)): prepend(lhs); return value!=null&&!value.isstring()? setvalue(lhs.concat(value)): prepend(lhs);
} }
/** Concatenate this buffer onto a {@link LuaNumber}
* <p>
* The {@link LuaNumber} will be converted to a string before concatenating.
* @param lhs the left-hand-side value onto which we are concatenating {@code this}
* @return {@link Buffer} for use in call chaining.
*/
public Buffer concatTo(LuaNumber lhs) { public Buffer concatTo(LuaNumber lhs) {
return value!=null&&!value.isstring()? setvalue(lhs.concat(value)): prepend(lhs.strvalue()); return value!=null&&!value.isstring()? setvalue(lhs.concat(value)): prepend(lhs.strvalue());
} }
/** Concatenate bytes from a {@link LuaString} onto the front of this buffer
* @param s the left-hand-side value which we will concatenate onto the front of {@code this}
* @return {@link Buffer} for use in call chaining.
*/
public Buffer prepend(LuaString s) { public Buffer prepend(LuaString s) {
int n = s.m_length; int n = s.m_length;
makeroom( n, 0 ); makeroom( n, 0 );
@@ -126,6 +214,10 @@ public final class Buffer {
return this; return this;
} }
/** Ensure there is enough room before and after the bytes.
* @param nbefore number of unused bytes which must precede the data after this completes
* @param nafter number of unused bytes which must follow the data after this completes
*/
public final void makeroom( int nbefore, int nafter ) { public final void makeroom( int nbefore, int nafter ) {
if ( value != null ) { if ( value != null ) {
LuaString s = value.strvalue(); LuaString s = value.strvalue();
@@ -141,6 +233,10 @@ public final class Buffer {
} }
} }
/** Reallocate the internal storage for the buffer
* @param newSize the size of the buffer to use
* @param newOffset the offset to use
*/
private final void realloc( int newSize, int newOffset ) { private final void realloc( int newSize, int newOffset ) {
if ( newSize != bytes.length ) { if ( newSize != bytes.length ) {
byte[] newBytes = new byte[ newSize ]; byte[] newBytes = new byte[ newSize ];

View File

@@ -25,8 +25,14 @@ import java.io.DataInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
/* /**
** Loader to load compiled function prototypes * Class to manage loading of {@link Prototype} instances.
* <p>
* @see LuaCompiler
* @see LuaClosure
* @see LuaFunction
* @see LoadState#compiler
* @see LoadState#load(InputStream, String, LuaValue)
*/ */
public class LoadState { public class LoadState {
@@ -53,7 +59,12 @@ public class LoadState {
public static final int LUA_TTHREAD = 8; public static final int LUA_TTHREAD = 8;
public static final int LUA_TVALUE = 9; public static final int LUA_TVALUE = 9;
/** Interface for the compiler, if it is installed. */ /** Interface for the compiler, if it is installed.
* <p>
* See the {@link LuaClosure} documentation for examples of how to use the compiler.
* @see LuaClosure
* @see #load(InputStream, String, LuaValue)
* */
public interface LuaCompiler { public interface LuaCompiler {
/** Load into a Closure or LuaFunction from a Stream and initializes the environment /** Load into a Closure or LuaFunction from a Stream and initializes the environment
@@ -106,6 +117,9 @@ public class LoadState {
private byte[] buf = new byte[512]; private byte[] buf = new byte[512];
/** Load a 4-byte int value from the input stream
* @return the int value laoded.
**/
int loadInt() throws IOException { int loadInt() throws IOException {
is.readFully(buf,0,4); is.readFully(buf,0,4);
return luacLittleEndian? return luacLittleEndian?
@@ -113,6 +127,9 @@ public class LoadState {
(buf[0] << 24) | ((0xff & buf[1]) << 16) | ((0xff & buf[2]) << 8) | (0xff & buf[3]); (buf[0] << 24) | ((0xff & buf[1]) << 16) | ((0xff & buf[2]) << 8) | (0xff & buf[3]);
} }
/** Load an array of int values from the input stream
* @return the array of int values laoded.
**/
int[] loadIntArray() throws IOException { int[] loadIntArray() throws IOException {
int n = loadInt(); int n = loadInt();
if ( n == 0 ) if ( n == 0 )
@@ -132,7 +149,9 @@ public class LoadState {
return array; return array;
} }
/** Load a long value from the input stream
* @return the long value laoded.
**/
long loadInt64() throws IOException { long loadInt64() throws IOException {
int a,b; int a,b;
if ( this.luacLittleEndian ) { if ( this.luacLittleEndian ) {
@@ -145,6 +164,9 @@ public class LoadState {
return (((long)b)<<32) | (((long)a)&0xffffffffL); return (((long)b)<<32) | (((long)a)&0xffffffffL);
} }
/** Load a lua strin gvalue from the input stream
* @return the {@link LuaString} value laoded.
**/
LuaString loadString() throws IOException { LuaString loadString() throws IOException {
int size = loadInt(); int size = loadInt();
if ( size == 0 ) if ( size == 0 )
@@ -154,6 +176,11 @@ public class LoadState {
return LuaString.valueOf( bytes, 0, bytes.length - 1 ); return LuaString.valueOf( bytes, 0, bytes.length - 1 );
} }
/**
* 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.
*/
public static LuaValue longBitsToLuaNumber( long bits ) { public static LuaValue longBitsToLuaNumber( long bits ) {
if ( ( bits & ( ( 1L << 63 ) - 1 ) ) == 0L ) { if ( ( bits & ( ( 1L << 63 ) - 1 ) ) == 0L ) {
return LuaValue.ZERO; return LuaValue.ZERO;
@@ -174,6 +201,11 @@ public class LoadState {
return LuaValue.valueOf( Double.longBitsToDouble(bits) ); 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
*/
LuaValue loadNumber() throws IOException { LuaValue loadNumber() throws IOException {
if ( luacNumberFormat == NUMBER_FORMAT_INTS_ONLY ) { if ( luacNumberFormat == NUMBER_FORMAT_INTS_ONLY ) {
return LuaInteger.valueOf( loadInt() ); return LuaInteger.valueOf( loadInt() );
@@ -182,6 +214,11 @@ public class LoadState {
} }
} }
/**
* Load a list of constants from a binary chunk
* @param f the function prototype
* @throws IOException if an i/o exception occurs
*/
void loadConstants(Prototype f) throws IOException { void loadConstants(Prototype f) throws IOException {
int n = loadInt(); int n = loadInt();
LuaValue[] values = n>0? new LuaValue[n]: NOVALUES; LuaValue[] values = n>0? new LuaValue[n]: NOVALUES;
@@ -215,6 +252,11 @@ public class LoadState {
f.p = protos; f.p = protos;
} }
/**
* Load the debug infor for a function prototype
* @param f the function Prototype
* @throws IOException if there is an i/o exception
*/
void loadDebug( Prototype f ) throws IOException { void loadDebug( Prototype f ) throws IOException {
f.lineinfo = loadIntArray(); f.lineinfo = loadIntArray();
int n = loadInt(); int n = loadInt();
@@ -233,6 +275,12 @@ public class LoadState {
} }
} }
/**
* Load a function prototype from the input stream
* @param p name of the source
* @return {@link Prototype} instance that was loaded
* @throws IOException
*/
public Prototype loadFunction(LuaString p) throws IOException { public Prototype loadFunction(LuaString p) throws IOException {
Prototype f = new Prototype(); Prototype f = new Prototype();
// this.L.push(f); // this.L.push(f);
@@ -257,6 +305,10 @@ public class LoadState {
return f; return f;
} }
/**
* Load the lua chunk header values.
* @throws IOException if an i/o exception occurs.
*/
public void loadHeader() throws IOException { public void loadHeader() throws IOException {
luacVersion = is.readByte(); luacVersion = is.readByte();
luacFormat = is.readByte(); luacFormat = is.readByte();
@@ -268,6 +320,15 @@ public class LoadState {
luacNumberFormat = is.readByte(); luacNumberFormat = is.readByte();
} }
/**
* Load lua in either binary or text form from an input stream.
* @param firstByte the first byte of the input stream
* @param stream InputStream to read, after having read the first byte already
* @param name Name to apply to the loaded chunk
* @return {@link Prototype} that was loaded
* @throws IllegalArgumentException if the signature is bac
* @throws IOException if an IOException occurs
*/
public static LuaFunction load( InputStream stream, String name, LuaValue env ) throws IOException { public static LuaFunction load( InputStream stream, String name, LuaValue env ) throws IOException {
if ( compiler != null ) if ( compiler != null )
return compiler.load(stream, name, env); return compiler.load(stream, name, env);
@@ -280,6 +341,15 @@ public class LoadState {
} }
} }
/**
* Load lua thought to be a binary chunk from its first byte from an input stream.
* @param firstByte the first byte of the input stream
* @param stream InputStream to read, after having read the first byte already
* @param name Name to apply to the loaded chunk
* @return {@link Prototype} that was loaded
* @throws IllegalArgumentException if the signature is bac
* @throws IOException if an IOException occurs
*/
public static Prototype loadBinaryChunk( int firstByte, InputStream stream, String name ) throws IOException { public static Prototype loadBinaryChunk( int firstByte, InputStream stream, String name ) throws IOException {
// check rest of signature // check rest of signature
@@ -306,6 +376,11 @@ public class LoadState {
return s.loadFunction( LuaString.valueOf(sname) ); return s.loadFunction( LuaString.valueOf(sname) );
} }
/**
* Construct a source name from a supplied chunk name
* @param name String name that appears in the chunk
* @return source file name
*/
public static String getSourceName(String name) { public static String getSourceName(String name) {
String sname = name; String sname = name;
if ( name.startsWith("@") || name.startsWith("=") ) if ( name.startsWith("@") || name.startsWith("=") )

View File

@@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2009 Luaj.org. All rights reserved. * Copyright (c) 2009-2011 Luaj.org. All rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -21,11 +21,25 @@
******************************************************************************/ ******************************************************************************/
package org.luaj.vm2; package org.luaj.vm2;
/**
* Data class to hold debug information relatign to local variables for a {@link Prototype}
*/
public class LocVars { public class LocVars {
/** The local variable name */
public LuaString varname; public LuaString varname;
/** The instruction offset when the variable comes into scope */
public int startpc; public int startpc;
/** The instruction offset when the variable goes out of scope */
public int endpc; public int endpc;
/**
* Construct a LocVars instance.
* @param varname The local variable name
* @param startpc The instruction offset when the variable comes into scope
* @param endpc The instruction offset when the variable goes out of scope
*/
public LocVars(LuaString varname, int startpc, int endpc) { public LocVars(LuaString varname, int startpc, int endpc) {
this.varname = varname; this.varname = varname;
this.startpc = startpc; this.startpc = startpc;

View File

@@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2009 Luaj.org. All rights reserved. * Copyright (c) 2009-2011 Luaj.org. All rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +23,10 @@ package org.luaj.vm2;
/** /**
* Constants for lua limits and opcodes * Constants for lua limits and opcodes.
* <p>
* This is a direct translation of C lua distribution header file constants
* for bytecode creation and processing.
*/ */
public class Lua { public class Lua {
/** version is supplied by ant build task */ /** version is supplied by ant build task */

View File

@@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2009 Luaj.org. All rights reserved. * Copyright (c) 2009-2011 Luaj.org. All rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -21,13 +21,36 @@
******************************************************************************/ ******************************************************************************/
package org.luaj.vm2; package org.luaj.vm2;
/**
* Extension of {@link LuaValue} which can hold a Java boolean as its value.
* <p>
* These instance are not instantiated directly by clients.
* Instead, there are exactly twon instances of this class,
* {@link LuaValue#TRUE} and {@link LuaValue#FALSE}
* representing the lua values {@code true} and {@link false}.
* The function {@link LuaValue#valueOf(boolean)} will always
* return one of these two values.
* <p>
* Any {@link LuaValue} can be converted to its equivalent
* boolean representation using {@link LuaValue#toboolean()}
* <p>
* @see LuaValue
* @see LuaValue#valueOf(boolean)
* @see LuaValue#TRUE
* @see LuaValue#FALSE
*/
public final class LuaBoolean extends LuaValue { public final class LuaBoolean extends LuaValue {
/** The singleton instance representing lua {@code true} */
static final LuaBoolean _TRUE = new LuaBoolean(true); static final LuaBoolean _TRUE = new LuaBoolean(true);
/** The singleton instance representing lua {@code false} */
static final LuaBoolean _FALSE = new LuaBoolean(false); static final LuaBoolean _FALSE = new LuaBoolean(false);
/** Shared static metatable for boolean values represented in lua. */
public static LuaValue s_metatable; public static LuaValue s_metatable;
/** The value of the boolean */
public final boolean v; public final boolean v;
LuaBoolean(boolean b) { LuaBoolean(boolean b) {
@@ -50,6 +73,10 @@ public final class LuaBoolean extends LuaValue {
return v ? FALSE : LuaValue.TRUE; return v ? FALSE : LuaValue.TRUE;
} }
/**
* Return the boolean value for this boolean
* @return value as a Java boolean
*/
public boolean booleanValue() { public boolean booleanValue() {
return v; return v;
} }

View File

@@ -21,8 +21,74 @@
******************************************************************************/ ******************************************************************************/
package org.luaj.vm2; package org.luaj.vm2;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import org.luaj.vm2.LoadState.LuaCompiler;
import org.luaj.vm2.compiler.LuaC;
import org.luaj.vm2.lib.DebugLib; import org.luaj.vm2.lib.DebugLib;
/**
* Extension of {@link LuaFunction} which executes lua bytecode.
* <p>
* A {@link LuaClosure} is a combination of a {@link Prototype}
* and a {@link LuaValue} to use as an environment for execution.
* <p>
* There are three main ways {@link LuaClosure} instances are created:
* <ul>
* <li>Construct an instance using {@link #LuaClosure(Prototype, LuaValue)}</li>
* <li>Construct it indirectly by loading a chunk via {@link LuaCompiler#load(java.io.InputStream, String, LuaValue)}
* <li>Execute the lua bytecode {@link Lua#OP_CLOSURE} as part of bytecode processing
* </ul>
* <p>
* To construct it directly, the {@link Prototype} is typically created via a compiler such as {@link LuaC}:
* <pre> {@code
* InputStream is = new ByteArrayInputStream("print('hello,world').getBytes());
* Prototype p = LuaC.instance.compile(is, "script");
* LuaValue _G = JsePlatform.standardGlobals()
* LuaClosure f = new LuaClosure(p, _G);
* }</pre>
* <p>
* To construct it indirectly, the {@link LuaC} compiler may be used,
* which implements the {@link LuaCompiler} interface:
* <pre> {@code
* LuaFunction f = LuaC.instance.load(is, "script", _G);
* }</pre>
* <p>
* Typically, a closure that has just been loaded needs to be initialized by executing it,
* and its return value can be saved if needed:
* <pre> {@code
* LuaValue r = f.call();
* _G.set( "mypkg", r )
* }</pre>
* <p>
* In the preceding, the loaded value is typed as {@link LuaFunction}
* to allow for the possibility of other compilers such as {@link LuaJC}
* producing {@link LuaFunction} directly without
* creating a {@link Prototype} or {@link LuaClosure}.
* <p>
* Since a {@link LuaClosure} is a {@link LuaFunction} which is a {@link LuaValue},
* all the value operations can be used directly such as:
* <ul>
* <li>{@link LuaValue#setfenv(LuaValue)}</li>
* <li>{@link LuaValue#call()}</li>
* <li>{@link LuaValue#call(LuaValue)}</li>
* <li>{@link LuaValue#invoke()}</li>
* <li>{@link LuaValue#invoke(Varargs)}</li>
* <li>{@link LuaValue#method(String)}</li>
* <li>{@link LuaValue#method(String,LuaValue)}</li>
* <li>{@link LuaValue#invokemethod(String)}</li>
* <li>{@link LuaValue#invokemethod(String,Varargs)}</li>
* <li> ...</li>
* </ul>
* @see LuaValue
* @see LuaFunction
* @see LuaValue#isclosure()
* @see LuaValue#checkclosure()
* @see LuaValue#optclosure(LuaClosure)
* @see LoadState
* @see LoadState#compiler
*/
public class LuaClosure extends LuaFunction { public class LuaClosure extends LuaFunction {
private static final UpValue[] NOUPVALUES = new UpValue[0]; private static final UpValue[] NOUPVALUES = new UpValue[0];

View File

@@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2009 Luaj.org. All rights reserved. * Copyright (c) 2009-2011 Luaj.org. All rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -25,17 +25,25 @@ import org.luaj.vm2.lib.DebugLib;
/** /**
* RuntimeException that is thrown and caught in response to a lua error. * RuntimeException that is thrown and caught in response to a lua error.
* This error does not indicate any problem with the normal functioning * <p>
* of the Lua VM, but rather indicates that the lua script being interpreted * {@link LuaError} is used wherever a lua call to {@code error()}
* has encountered a lua error, eigher via LuaState.error() or lua error() calls. * would be used within a script.
* * <p>
* Since it is an unchecked exception inheriting from {@link RuntimeException},
* Java method signatures do notdeclare this exception, althoug it can
* be thrown on almost any luaj Java operation.
* This is analagous to the fact that any lua script can throw a lua error at any time.
* <p>
*/ */
public class LuaError extends RuntimeException { public class LuaError extends RuntimeException {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private String traceback; private String traceback;
/** Run the error hook if there is one */ /**
* Run the error hook if there is one
* @param msg the message to use in error hook processing.
* */
private static String errorHook(String msg) { private static String errorHook(String msg) {
LuaThread thread = LuaThread.getRunning(); LuaThread thread = LuaThread.getRunning();
if ( thread.err != null ) { if ( thread.err != null ) {
@@ -54,11 +62,10 @@ public class LuaError extends RuntimeException {
private Throwable cause; private Throwable cause;
/** /** Construct LuaError when a program exception occurs.
* Construct a LuaErrorException in response to a Throwable that was caught * <p>
* indicating a problem with the VM rather than the lua code.
*
* All errors generated from lua code should throw LuaError(String) instead. * All errors generated from lua code should throw LuaError(String) instead.
* @param cause the Throwable that caused the error, if known.
*/ */
public LuaError(Throwable cause) { public LuaError(Throwable cause) {
super( errorHook( addFileLine( "vm error: "+cause ) ) ); super( errorHook( addFileLine( "vm error: "+cause ) ) );
@@ -67,8 +74,7 @@ public class LuaError extends RuntimeException {
} }
/** /**
* Construct a LuaError with a specific message indicating a problem * Construct a LuaError with a specific message.
* within the lua code itself such as an argument type error.
* *
* @param message message to supply * @param message message to supply
*/ */
@@ -78,6 +84,7 @@ public class LuaError extends RuntimeException {
} }
/** /**
* Construct a LuaError with a message, and level to draw line number information from.
* @param message message to supply * @param message message to supply
* @param level where to supply line info from in call stack * @param level where to supply line info from in call stack
*/ */
@@ -86,7 +93,11 @@ public class LuaError extends RuntimeException {
this.traceback = DebugLib.traceback(1); this.traceback = DebugLib.traceback(1);
} }
/** Add file and line info to a message at a particular level */ /**
* Add file and line info to a message at a particular level
* @param message the String message to use
* @param level where to supply line info from in call stack
* */
private static String addFileLine( String message, int level ) { private static String addFileLine( String message, int level ) {
if ( message == null ) return null; if ( message == null ) return null;
if ( level == 0 ) return message; if ( level == 0 ) return message;
@@ -94,19 +105,15 @@ public class LuaError extends RuntimeException {
return fileline!=null? fileline+": "+message: message; return fileline!=null? fileline+": "+message: message;
} }
/** Add file and line info for the nearest enclosing closure */ /** Add file and line info for the nearest enclosing closure
* @param message the String message to use
* */
private static String addFileLine( String message ) { private static String addFileLine( String message ) {
if ( message == null ) return null; if ( message == null ) return null;
String fileline = DebugLib.fileline(); String fileline = DebugLib.fileline();
return fileline!=null? fileline+": "+message: message; return fileline!=null? fileline+": "+message: message;
} }
// /** Get the message, including source line info if there is any */
// public String getMessage() {
// String msg = super.getMessage();
// return msg!=null && traceback!=null? traceback+": "+msg: msg;
// }
/** Print the message and stack trace */ /** Print the message and stack trace */
public void printStackTrace() { public void printStackTrace() {
System.out.println( toString() ); System.out.println( toString() );

View File

@@ -21,6 +21,21 @@
******************************************************************************/ ******************************************************************************/
package org.luaj.vm2; package org.luaj.vm2;
/**
* Class to encapsulate behavior of the singleton instance {@code nil}
* <p>
* There will be one instance of this class, {@link LuaValue#NIL},
* per Java virtual machine.
* However, the {@link Varargs} instance {@link LuaValue#NONE}
* which is the empty list,
* is also considered treated as a nil value by default.
* <p>
* Although it is possible to test for nil using Java == operator,
* the recommended approach is to use the method {@link LuaValue#isnil()}
* instead. By using that any ambiguities between
* {@link LuaValue#NIL} and {@link LuaValue#NONE} are avoided.
*
*/
public class LuaNil extends LuaValue { public class LuaNil extends LuaValue {
static final LuaNil _NIL = new LuaNil(); static final LuaNil _NIL = new LuaNil();

View File

@@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2009 Luaj.org. All rights reserved. * Copyright (c) 2009-2011 Luaj.org. All rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -21,6 +21,7 @@
******************************************************************************/ ******************************************************************************/
package org.luaj.vm2; package org.luaj.vm2;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
@@ -31,12 +32,44 @@ import java.util.Hashtable;
import org.luaj.vm2.lib.MathLib; import org.luaj.vm2.lib.MathLib;
import org.luaj.vm2.lib.StringLib; import org.luaj.vm2.lib.StringLib;
/**
* Subclass of {@link LuaValue} for representing lua strings.
* <p>
* 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.
* <p>
* {@link LuaString} values are generally not 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,
* instance construction should be via {@link LuaValue#valueOf(byte[])} or similar API.
* <p>
* When Java Strings are used to initialize {@link LuaString} data, the UTF8 encoding is assumed.
* The functions
* {@link LuaString#lengthAsUtf8(char[]),
* {@link LuaString#encodeToUtf8(char[], byte[], int)}, and
* {@link LuaString#decodeAsUtf8(byte[], int, int)
* are used to convert back and forth between UTF8 byte arrays and character arrays.
*
* @see LuaValue
* @see LuaValue#valueOf(String)
* @see LuaValue#valueOf(byte[])
*/
public class LuaString extends LuaValue { public class LuaString extends LuaValue {
/** The singleton instance representing lua {@code true} */
public static LuaValue s_metatable; public static LuaValue s_metatable;
/** The bytes for the string */
public final byte[] m_bytes; public final byte[] m_bytes;
/** The offset into the byte array, 0 means start at the first byte */
public final int m_offset; public final int m_offset;
/** The number of bytes that comprise this string */
public final int m_length; public final int m_length;
private static final Hashtable index_java = new Hashtable(); private static final Hashtable index_java = new Hashtable();
@@ -50,6 +83,12 @@ public class LuaString extends LuaValue {
indextable.put(key, new WeakReference(value)); indextable.put(key, new WeakReference(value));
} }
/**
* Get a {@link LuaString} instance whose bytes match
* the supplied Java String using the UTF8 encoding.
* @param string Java String containing characters to encode as UTF8
* @return {@link LuaString} with UTF8 bytes corresponding to the supplied String
*/
public static LuaString valueOf(String string) { public static LuaString valueOf(String string) {
LuaString s = index_get( index_java, string ); LuaString s = index_get( index_java, string );
if ( s != null ) return s; if ( s != null ) return s;
@@ -61,10 +100,28 @@ public class LuaString extends LuaValue {
return s; return s;
} }
// TODO: should this be deprecated or made private?
/** Construct a {@link LuaString} around a byte array without copying the contents.
* <p>
* The array is used directly after this is called, so clients must not change contents.
* <p>
* @param bytes byte buffer
* @param off offset into the byte buffer
* @param len length of the byte buffer
* @return {@link LuaString} wrapping the byte buffer
*/
public static LuaString valueOf(byte[] bytes, int off, int len) { public static LuaString valueOf(byte[] bytes, int off, int len) {
return new LuaString(bytes, off, len); return new LuaString(bytes, off, len);
} }
/** Construct a {@link LuaString} using the supplied characters as byte values.
* <p>
* Only th elow-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
*/
public static LuaString valueOf(char[] bytes) { public static LuaString valueOf(char[] bytes) {
int n = bytes.length; int n = bytes.length;
byte[] b = new byte[n]; byte[] b = new byte[n];
@@ -73,10 +130,27 @@ public class LuaString extends LuaValue {
return valueOf(b, 0, n); return valueOf(b, 0, n);
} }
/** Construct a {@link LuaString} around a byte array without copying the contents.
* <p>
* The array is used directly after this is called, so clients must not change contents.
* <p>
* @param bytes byte buffer
* @return {@link LuaString} wrapping the byte buffer
*/
public static LuaString valueOf(byte[] bytes) { public static LuaString valueOf(byte[] bytes) {
return valueOf(bytes, 0, bytes.length); return valueOf(bytes, 0, bytes.length);
} }
/** Construct a {@link LuaString} around a byte array without copying the contents.
* <p>
* The array is used directly after this is called, so clients must not change contents.
* <p>
* @param bytes byte buffer
* @param offset offset into the byte buffer
* @param length length of the byte buffer
* @return {@link LuaString} wrapping the byte buffer
*/
private LuaString(byte[] bytes, int offset, int length) { private LuaString(byte[] bytes, int offset, int length) {
this.m_bytes = bytes; this.m_bytes = bytes;
this.m_offset = offset; this.m_offset = offset;
@@ -364,18 +438,29 @@ public class LuaString extends LuaValue {
return this; return this;
} }
/** Convert value to an input stream.
*
* @return {@link InputStream} whose data matches the bytes in this {@link LuaString}
*/
public InputStream toInputStream() { public InputStream toInputStream() {
return new ByteArrayInputStream(m_bytes, m_offset, m_length); return new ByteArrayInputStream(m_bytes, m_offset, m_length);
} }
/** /**
* 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
* @param len number of bytes to copy
*/ */
public void copyInto( int strOffset, byte[] bytes, int arrayOffset, int len ) { public void copyInto( int strOffset, byte[] bytes, int arrayOffset, int len ) {
System.arraycopy( m_bytes, m_offset+strOffset, bytes, arrayOffset, len ); System.arraycopy( m_bytes, m_offset+strOffset, bytes, arrayOffset, len );
} }
/** Java version of strpbrk, which is a terribly named C function. */ /** Java version of strpbrk - find index of any byte that in an accept string.
* @param accept {@link LuaString} containing characters to look for.
* @return index of first match in the {@code accept} string, or -1 if not found.
*/
public int indexOfAny( LuaString accept ) { public int indexOfAny( LuaString accept ) {
final int ilimit = m_offset + m_length; final int ilimit = m_offset + m_length;
final int jlimit = accept.m_offset + accept.m_length; final int jlimit = accept.m_offset + accept.m_length;
@@ -389,6 +474,12 @@ public class LuaString extends LuaValue {
return -1; return -1;
} }
/**
* Find the index of a byte starting at a point in this string
* @param b the byte to look for
* @param start the first index in the string
* @return index of first match found, or -1 if not found.
*/
public int indexOf( byte b, int start ) { public int indexOf( byte b, int start ) {
for ( int i=0, j=m_offset+start; i < m_length; ++i ) { for ( int i=0, j=m_offset+start; i < m_length; ++i ) {
if ( m_bytes[j++] == b ) if ( m_bytes[j++] == b )
@@ -397,6 +488,12 @@ public class LuaString extends LuaValue {
return -1; return -1;
} }
/**
* Find the index of a string starting at a point in this string
* @param s the string to search for
* @param start the first index in the string
* @return index of first match found, or -1 if not found.
*/
public int indexOf( LuaString s, int start ) { public int indexOf( LuaString s, int start ) {
final int slen = s.length(); final int slen = s.length();
final int limit = m_offset + m_length - slen; final int limit = m_offset + m_length - slen;
@@ -408,6 +505,11 @@ public class LuaString extends LuaValue {
return -1; return -1;
} }
/**
* Find the last index of a string in this string
* @param s the string to search for
* @return index of last match found, or -1 if not found.
*/
public int lastIndexOf( LuaString s ) { public int lastIndexOf( LuaString s ) {
final int slen = s.length(); final int slen = s.length();
final int limit = m_offset + m_length - slen; final int limit = m_offset + m_length - slen;
@@ -419,10 +521,17 @@ public class LuaString extends LuaValue {
return -1; return -1;
} }
// --------------------- utf8 conversion -------------------------
/** /**
* 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
* @see #lengthAsUtf8(char[])
* @see #encodeToUtf8(char[], byte[], int)
* @see #isValidUtf8()
*/ */
public static String decodeAsUtf8(byte[] bytes, int offset, int length) { public static String decodeAsUtf8(byte[] bytes, int offset, int length) {
int i,j,n,b; int i,j,n,b;
@@ -444,6 +553,11 @@ public class LuaString extends LuaValue {
/** /**
* Count the number of bytes required to encode the string as UTF-8. * Count the number of bytes required to encode the string as UTF-8.
* @param chars Array of unicode characters to be encoded as UTF-8
* @return count of bytes needed to encode using UTF-8
* @see #encodeToUtf8(char[], byte[], int)
* @see #decodeAsUtf8(byte[], int, int)
* @see #isValidUtf8()
*/ */
public static int lengthAsUtf8(char[] chars) { public static int lengthAsUtf8(char[] chars) {
int i,b; int i,b;
@@ -456,8 +570,16 @@ public class LuaString extends LuaValue {
/** /**
* Encode the given Java string as UTF-8 bytes, writing the result to bytes * Encode the given Java string as UTF-8 bytes, writing the result to bytes
* starting at offset. The string should be measured first with lengthAsUtf8 * starting at offset.
* <p>
* The string should be measured first with lengthAsUtf8
* to make sure the given byte array is large enough. * to make sure the given byte array is large enough.
* @param chars Array of unicode characters to be encoded as UTF-8
* @param bytes byte array to hold the result
* @param off offset into the byte array to start writing
* @see #lengthAsUtf8(char[])
* @see #decodeAsUtf8(byte[], int, int)
* @see #isValidUtf8()
*/ */
public static void encodeToUtf8(char[] chars, byte[] bytes, int off) { public static void encodeToUtf8(char[] chars, byte[] bytes, int off) {
final int n = chars.length; final int n = chars.length;
@@ -476,6 +598,12 @@ public class LuaString extends LuaValue {
} }
} }
/** Check that a byte sequence is valid UTF-8
* @return true if it is valid UTF-8, otherwise false
* @see #lengthAsUtf8(char[])
* @see #encodeToUtf8(char[], byte[], int)
* @see #decodeAsUtf8(byte[], int, int)
*/
public boolean isValidUtf8() { public boolean isValidUtf8() {
int i,j,n,b,e=0; int i,j,n,b,e=0;
for ( i=m_offset,j=m_offset+m_length,n=0; i<j; ++n ) { for ( i=m_offset,j=m_offset+m_length,n=0; i<j; ++n ) {
@@ -497,7 +625,9 @@ public class LuaString extends LuaValue {
/** /**
* convert to a number using a supplied base, or NIL if it can't be converted * convert to a number using a supplied base, or NIL if it can't be converted
* @param base the base to use, such as 10
* @return IntValue, DoubleValue, or NIL depending on the content of the string. * @return IntValue, DoubleValue, or NIL depending on the content of the string.
* @see LuaValue#tonumber()
*/ */
public LuaValue tonumber( int base ) { public LuaValue tonumber( int base ) {
double d = scannumber( base ); double d = scannumber( base );
@@ -506,6 +636,8 @@ public class LuaString extends LuaValue {
/** /**
* Convert to a number in a base, or return Double.NaN if not a number. * Convert to a number in a base, or return Double.NaN if not a number.
* @param base the base to use, such as 10
* @return double value if conversion is valid, or Double.NaN if not
*/ */
public double scannumber( int base ) { public double scannumber( int base ) {
if ( base >= 2 && base <= 36 ) { if ( base >= 2 && base <= 36 ) {
@@ -527,7 +659,11 @@ public class LuaString extends LuaValue {
/** /**
* Scan and convert a long value, or return Double.NaN if not found. * Scan and convert a long value, or return Double.NaN if not found.
* @return DoubleValue, IntValue, or Double.NaN depending on what is found. * @param base the base to use, such as 10
* @param start the index to start searching from
* @param end the first index beyond the search range
* @return double value if conversion is valid,
* or Double.NaN if not
*/ */
private double scanlong( int base, int start, int end ) { private double scanlong( int base, int start, int end ) {
long x = 0; long x = 0;
@@ -544,7 +680,10 @@ public class LuaString extends LuaValue {
/** /**
* Scan and convert a double value, or return Double.NaN if not a double. * Scan and convert a double value, or return Double.NaN if not a double.
* @return DoubleValue, IntValue, or Double.NaN depending on what is found. * @param start the index to start searching from
* @param end the first index beyond the search range
* @return double value if conversion is valid,
* or Double.NaN if not
*/ */
private double scandouble(int start, int end) { private double scandouble(int start, int end) {
if ( end>start+64 ) end=start+64; if ( end>start+64 ) end=start+64;

View File

@@ -23,26 +23,90 @@ package org.luaj.vm2;
import java.util.Vector; import java.util.Vector;
/**
* 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 #checktable()}, or
* {@link #opttable(LuaTable)}
* <p>
* 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 #rawset(LuaValue,LuaValue)}</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
* <pre> {@code
* LuaValue k = LuaValue.NIL;
* while ( true ) {
* Varargs n = table.next(k);
* if ( (k = n.arg1()).isnil() )
* break;
* LuaValue v = n.arg(2)
* process( k, v )
* }</pre>
*
* <p>
* 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>
* <li>{@link LuaValue#tableOf(int, int)} table with capacity</li>
* <li>{@link LuaValue#tableOf(LuaValue[])} initialize array part</li>
* <li>{@link LuaValue#tableOf(Varargs, int)} initialize array part</li>
* <li>{@link LuaValue#tableOf(LuaValue[], LuaValue[])} initialize array and named parts</li>
* <li>{@link LuaValue#tableOf(LuaValue[], LuaValue[], Varargs)} initialize array and named parts</li>
* </ul>
*/
public class LuaTable extends LuaValue { public class LuaTable extends LuaValue {
private static final int MIN_HASH_CAPACITY = 2; private static final int MIN_HASH_CAPACITY = 2;
private static final LuaString N = valueOf("n"); private static final LuaString N = valueOf("n");
/** the array values */
protected LuaValue[] array; protected LuaValue[] array;
/** the hash keys */
protected LuaValue[] hashKeys; protected LuaValue[] hashKeys;
/** the hash values */
protected LuaValue[] hashValues; protected LuaValue[] hashValues;
/** the number of hash entries */
protected int hashEntries; protected int hashEntries;
/** metatable for this table, or null */
protected LuaValue m_metatable; protected LuaValue m_metatable;
/** Construct empty table */
public LuaTable() { public LuaTable() {
array = NOVALS; array = NOVALS;
hashKeys = NOVALS; hashKeys = NOVALS;
hashValues = NOVALS; hashValues = NOVALS;
} }
/**
* Construct table with preset capacity.
* @param narray capacity of array part
* @param nhash capacity of hash part
*/
public LuaTable(int narray, int nhash) { public LuaTable(int narray, int nhash) {
presize(narray, nhash); presize(narray, nhash);
} }
/**
* 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 lastarg Additional unnamed values beyond {@code unnamed.length}
*/
public LuaTable(LuaValue[] named, LuaValue[] unnamed, Varargs lastarg) { public LuaTable(LuaValue[] named, LuaValue[] unnamed, Varargs lastarg) {
int nn = (named!=null? named.length: 0); int nn = (named!=null? named.length: 0);
int nu = (unnamed!=null? unnamed.length: 0); int nu = (unnamed!=null? unnamed.length: 0);
@@ -58,10 +122,19 @@ public class LuaTable extends LuaValue {
rawset(named[i], named[i+1]); rawset(named[i], named[i+1]);
} }
/**
* Construct table of unnamed elements.
* @param varargs Unnamed elements in order {@code value-1, value-2, ... }
*/
public LuaTable(Varargs varargs) { public LuaTable(Varargs varargs) {
this(varargs,1); this(varargs,1);
} }
/**
* Construct table of unnamed elements.
* @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
*/
public LuaTable(Varargs varargs, int firstarg) { public LuaTable(Varargs varargs, int firstarg) {
int nskip = firstarg-1; int nskip = firstarg-1;
int n = Math.max(varargs.narg()-nskip,0); int n = Math.max(varargs.narg()-nskip,0);
@@ -105,16 +178,25 @@ public class LuaTable extends LuaValue {
hashEntries = 0; hashEntries = 0;
} }
/** Resize the table */
private static LuaValue[] resize( LuaValue[] old, int n ) { private static LuaValue[] resize( LuaValue[] old, int n ) {
LuaValue[] v = new LuaValue[n]; LuaValue[] v = new LuaValue[n];
System.arraycopy(old, 0, v, 0, old.length); System.arraycopy(old, 0, v, 0, old.length);
return v; 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.
*/
protected int getArrayLength() { protected int getArrayLength() {
return array.length; 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.
*/
protected int getHashLength() { protected int getHashLength() {
return hashValues.length; return hashValues.length;
} }
@@ -135,6 +217,12 @@ public class LuaTable extends LuaValue {
return this; return this;
} }
/**
* Change the mode of a table
* @param weakkeys true to make the table have weak keys going forward
* @param weakvalues true to make the table have weak values going forward
* @return {@code this} or a new {@link WeakTable} if the mode change requires copying.
*/
protected LuaTable changemode(boolean weakkeys, boolean weakvalues) { protected LuaTable changemode(boolean weakkeys, boolean weakvalues) {
if ( weakkeys || weakvalues ) if ( weakkeys || weakvalues )
return new WeakTable(weakkeys, weakvalues, this); return new WeakTable(weakkeys, weakvalues, this);
@@ -197,6 +285,7 @@ public class LuaTable extends LuaValue {
hashset( key, value ); hashset( key, value );
} }
/** Set an array element */
private boolean arrayset( int key, LuaValue value ) { private boolean arrayset( int key, LuaValue value ) {
if ( key>0 && key<=array.length ) { if ( key>0 && key<=array.length ) {
array[key-1] = (value.isnil()? null: value); array[key-1] = (value.isnil()? null: value);
@@ -209,6 +298,7 @@ public class LuaTable extends LuaValue {
return false; return false;
} }
/** Expand the array part */
private void expandarray() { private void expandarray() {
int n = array.length; int n = array.length;
int m = Math.max(2,n*2); int m = Math.max(2,n*2);
@@ -223,6 +313,11 @@ public class LuaTable extends LuaValue {
} }
} }
/** 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) { public LuaValue remove(int pos) {
if ( pos == 0 ) if ( pos == 0 )
pos = length(); pos = length();
@@ -234,6 +329,11 @@ public class LuaTable extends LuaValue {
return v.isnil()? NONE: v; 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) { public void insert(int pos, LuaValue value) {
if ( pos == 0 ) if ( pos == 0 )
pos = length()+1; pos = length()+1;
@@ -244,6 +344,13 @@ public class LuaTable extends LuaValue {
} }
} }
/** Concatenate the contents of a table efficiently, using {@link Buffer}
*
* @param sep {@link LuaString} separater to apply between elements
* @param i the first element index
* @param j the last element index, inclusive
* @return {@link LuaString} value of the concatenation
*/
public LuaValue concat(LuaString sep, int i, int j) { public LuaValue concat(LuaString sep, int i, int j) {
Buffer sb = new Buffer (); Buffer sb = new Buffer ();
if ( i<=j ) { if ( i<=j ) {
@@ -263,9 +370,6 @@ public class LuaTable extends LuaValue {
return ZERO; return ZERO;
} }
/**
* Get the length of this table, as lua defines it.
*/
public int length() { public int length() {
int a = getArrayLength(); int a = getArrayLength();
int n = a+1,m=0; int n = a+1,m=0;
@@ -287,6 +391,11 @@ public class LuaTable extends LuaValue {
return LuaInteger.valueOf(length()); return LuaInteger.valueOf(length());
} }
/** Return table.maxn() as defined by lua 5.0.
* <p>
* Provided for compatibility, not a scalable operation.
* @return value for maxn
*/
public int maxn() { public int maxn() {
int n = 0; int n = 0;
for ( int i=0; i<array.length; i++ ) for ( int i=0; i<array.length; i++ )
@@ -303,10 +412,6 @@ public class LuaTable extends LuaValue {
return n; return n;
} }
/**
* Get the next element after a particular key in the table
* @return key,value or nil
*/
/** /**
* Get the next element after a particular key in the table * Get the next element after a particular key in the table
* @return key,value or nil * @return key,value or nil
@@ -388,8 +493,11 @@ public class LuaTable extends LuaValue {
} }
// ======================= hashset ================= /**
* Set a hashtable value
* @param key key to set
* @param value value to set
*/
public void hashset(LuaValue key, LuaValue value) { public void hashset(LuaValue key, LuaValue value) {
if ( value.isnil() ) if ( value.isnil() )
hashRemove(key); hashRemove(key);
@@ -408,6 +516,11 @@ public class LuaTable extends LuaValue {
} }
} }
/**
* Find the hashtable slot to use
* @param key key to look for
* @return slot to use
*/
public int hashFindSlot(LuaValue key) { public int hashFindSlot(LuaValue key) {
int i = ( key.hashCode() & 0x7FFFFFFF ) % hashKeys.length; int i = ( key.hashCode() & 0x7FFFFFFF ) % hashKeys.length;
@@ -437,6 +550,10 @@ public class LuaTable extends LuaValue {
} }
} }
/**
* Clear a particular slot in the table
* @param i slot to clear.
*/
protected void hashClearSlot( int i ) { protected void hashClearSlot( int i ) {
if ( hashKeys[ i ] != null ) { if ( hashKeys[ i ] != null ) {
@@ -497,6 +614,9 @@ public class LuaTable extends LuaValue {
// //
// 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.
*/
public void sort(LuaValue comparator) { public void sort(LuaValue comparator) {
int n = array.length; int n = array.length;
while ( n > 0 && array[n-1] == null ) while ( n > 0 && array[n-1] == null )
@@ -550,7 +670,9 @@ public class LuaTable extends LuaValue {
} }
/** 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 */ * It is recommended to count via iteration over next() instead
* @return count of keys in the table
* */
public int keyCount() { public int keyCount() {
LuaValue k = LuaValue.NIL; LuaValue k = LuaValue.NIL;
for ( int i=0; true; i++ ) { for ( int i=0; true; i++ ) {
@@ -561,7 +683,9 @@ public class LuaTable extends LuaValue {
} }
/** This may be deprecated in a future release. /** This may be deprecated in a future release.
* It is recommended to use next() instead */ * It is recommended to use next() instead
* @return array of keys in the table
* */
public LuaValue[] keys() { public LuaValue[] keys() {
Vector l = new Vector(); Vector l = new Vector();
LuaValue k = LuaValue.NIL; LuaValue k = LuaValue.NIL;

View File

@@ -24,6 +24,11 @@ package org.luaj.vm2;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.PrintStream; import java.io.PrintStream;
/**
* Debug helper class to pretty-print lua bytecodes.
* @see Prototype
* @see LuaClosure
*/
public class Print extends Lua { public class Print extends Lua {
/** opcode names */ /** opcode names */
@@ -131,6 +136,10 @@ public class Print extends Lua {
printValue( ps, f.k[i] ); printValue( ps, f.k[i] );
} }
/**
* Print the code in a prototype
* @param f the {@link Prototype}
*/
public static void printCode(Prototype f) { public static void printCode(Prototype f) {
int[] code = f.code; int[] code = f.code;
int pc, n = code.length; int pc, n = code.length;
@@ -140,10 +149,21 @@ public class Print extends Lua {
} }
} }
/**
* Print an opcode in a prototype
* @param f the {@link Prototype}
* @param pc the program counter to look up and print
*/
public static void printOpCode(Prototype f, int pc) { public static void printOpCode(Prototype f, int pc) {
printOpCode(ps,f,pc); printOpCode(ps,f,pc);
} }
/**
* Print an opcode in a prototype
* @param ps the {@link PrintStream} to print to
* @param f the {@link Prototype}
* @param pc the program counter to look up and print
*/
public static void printOpCode(PrintStream ps, Prototype f, int pc) { public static void printOpCode(PrintStream ps, Prototype f, int pc) {
int[] code = f.code; int[] code = f.code;
int i = code[pc]; int i = code[pc];
@@ -335,6 +355,14 @@ public class Print extends Lua {
throw new NullPointerException("_assert failed"); throw new NullPointerException("_assert failed");
} }
/**
* Print the state of a {@link LuaClosure} that is being executed
* @param cl the {@link LuaClosure}
* @param pc the program counter
* @param stack the stack of {@link LuaValue}
* @param top the top of the stack
* @param varargs any {@link Varargs} value that may apply
*/
public static void printState(LuaClosure cl, int pc, LuaValue[] stack, int top, Varargs varargs) { public static void printState(LuaClosure cl, int pc, LuaValue[] stack, int top, Varargs varargs) {
// print opcode into buffer // print opcode into buffer
PrintStream previous = ps; PrintStream previous = ps;

View File

@@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2009 Luaj.org. All rights reserved. * Copyright (c) 2009-2011 Luaj.org. All rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -21,7 +21,16 @@
******************************************************************************/ ******************************************************************************/
package org.luaj.vm2; package org.luaj.vm2;
/**
* Prototype representing compiled lua code.
* <p>
* This is both a straight translation of the corresponding C type,
* and the main data structure for execution of compiled lua bytecode.
* <p>
* See documentatation on {@link LuaClosure} for information on how to load
* and execute a {@link Prototype}.
* @see LuaClosure
*/
public class Prototype { public class Prototype {
/* constants used by the function */ /* constants used by the function */

View File

@@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2010 Luaj.org. All rights reserved. * Copyright (c) 2010-2011 Luaj.org. All rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -21,6 +21,25 @@
******************************************************************************/ ******************************************************************************/
package org.luaj.vm2; package org.luaj.vm2;
/**
* Subclass of {@link Varargs} that represents a lua tail call
* in a Java library function execution environment.
* <p>
* Since Java doesn't have direct support for tail calls,
* any lua function whose {@link Prototype} contains the
* {@link Lua#OP_TAILCALL} bytecode needs a mechanism
* for tail calls when converting lua-bytecode to java-bytecode.
* <p>
* The tail call holds the next function and arguments,
* and the client a call to {@link #eval()} executes the function
* repeatedly until the tail calls are completed.
* <p>
* Normally, users of luaj need not concern themselves with the
* details of this mechanism, as it is built into the core
* execution framework.
* @see Prototype
* @see LuaJC
*/
public class TailcallVarargs extends Varargs { public class TailcallVarargs extends Varargs {
private LuaValue func; private LuaValue func;

View File

@@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2009 Luaj.org. All rights reserved. * Copyright (c) 2009-2011 Luaj.org. All rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -22,29 +22,54 @@
package org.luaj.vm2; package org.luaj.vm2;
/** Upvalue used with Closure formulation */ /** Upvalue used with Closure formulation
* <p>
* @see LuaClosure
* @see Prototype
*/
public final class UpValue { public final class UpValue {
LuaValue[] array; // initially the stack, becomes a holder LuaValue[] array; // initially the stack, becomes a holder
int index; int index;
/**
* Create an upvalue relative to a stack
* @param stack the stack
* @param index the index on the stack for the upvalue
*/
public UpValue( LuaValue[] stack, int index) { public UpValue( LuaValue[] stack, int index) {
this.array = stack; this.array = stack;
this.index = index; this.index = index;
} }
/**
* Convert this upvalue to a Java String
* @return the Java String for this upvalue.
* @see LuaValue#tojstring()
*/
public String tojstring() { public String tojstring() {
return array[index].tojstring(); return array[index].tojstring();
} }
/**
* Get the value of the upvalue
* @return the {@link LuaValue} for this upvalue
*/
public final LuaValue getValue() { public final LuaValue getValue() {
return array[index]; return array[index];
} }
/**
* Set the value of the upvalue
* @param the {@link LuaValue} to set it to
*/
public final void setValue( LuaValue value ) { public final void setValue( LuaValue value ) {
array[index] = value; array[index] = value;
} }
/**
* Close this upvalue so it is no longer on the stack
*/
public final void close() { public final void close() {
array = new LuaValue[] { array[index] }; array = new LuaValue[] { array[index] };
index = 0; index = 0;

View File

@@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2009 Luaj.org. All rights reserved. * Copyright (c) 2009-2011 Luaj.org. All rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -25,17 +25,46 @@ import java.lang.ref.WeakReference;
import org.luaj.vm2.lib.TwoArgFunction; import org.luaj.vm2.lib.TwoArgFunction;
/**
* Subclass of {@link LuaTable} that provides weak key and weak value semantics.
* <p>
* Normally these are not created directly, but indirectly when changing the mode
* of a {@link LuaTable} as lua script executes.
* <p>
* However, calling the constructors directly when weak tables are required from
* Java will reduce overhead.
*/
public class WeakTable extends LuaTable { public class WeakTable extends LuaTable {
private boolean weakkeys,weakvalues; private boolean weakkeys,weakvalues;
/**
* Construct a table with weak keys, weak values, or both
* @param weakkeys true to let the table have weak keys
* @param weakvalues true to let the table have weak values
*/
public WeakTable(boolean weakkeys, boolean weakvalues) { public WeakTable(boolean weakkeys, boolean weakvalues) {
this(weakkeys, weakvalues, 0, 0); this(weakkeys, weakvalues, 0, 0);
} }
/**
* Construct a table with weak keys, weak values, or both, and an initial capacity
* @param weakkeys true to let the table have weak keys
* @param weakvalues true to let the table have weak values
* @param narray capacity of array part
* @param nhash capacity of hash part
*/
protected WeakTable(boolean weakkeys, boolean weakvalues, int narray, int nhash) { protected WeakTable(boolean weakkeys, boolean weakvalues, int narray, int nhash) {
super(narray, nhash); super(narray, nhash);
this.weakkeys = weakkeys; this.weakkeys = weakkeys;
this.weakvalues = weakvalues; this.weakvalues = weakvalues;
} }
/**
* Construct a table with weak keys, weak values, or both, and a source of initial data
* @param weakkeys true to let the table have weak keys
* @param weakvalues true to let the table have weak values
* @param source {@link LuaTable} containing the initial elements
*/
protected WeakTable(boolean weakkeys, boolean weakvalues, LuaTable source) { protected WeakTable(boolean weakkeys, boolean weakvalues, LuaTable source) {
this(weakkeys, weakvalues, source.getArrayLength(), source.getHashLength()); this(weakkeys, weakvalues, source.getArrayLength(), source.getHashLength());
Varargs n; Varargs n;
@@ -49,6 +78,11 @@ public class WeakTable extends LuaTable {
super.presize(narray); super.presize(narray);
} }
/**
* Presize capacity of both array and hash parts.
* @param narray capacity of array part
* @param nhash capacity of hash part
*/
public void presize(int narray, int nhash) { public void presize(int narray, int nhash) {
super.presize(narray, nhash); super.presize(narray, nhash);
} }
@@ -67,6 +101,11 @@ public class WeakTable extends LuaTable {
return this; return this;
} }
/**
* Self-sent message to convert a value to its weak counterpart
* @param value value to convert
* @return {@link LuaValue} that is a strong or weak reference, depending on type of {@code value}
*/
LuaValue weaken( LuaValue value ) { LuaValue weaken( LuaValue value ) {
switch ( value.type() ) { switch ( value.type() ) {
case LuaValue.TFUNCTION: case LuaValue.TFUNCTION:
@@ -86,7 +125,6 @@ public class WeakTable extends LuaTable {
super.rawset(key, value); super.rawset(key, value);
} }
/** caller must ensure key is not nil */
public void rawset( LuaValue key, LuaValue value ) { public void rawset( LuaValue key, LuaValue value ) {
if ( weakvalues ) if ( weakvalues )
value = weaken( value ); value = weaken( value );
@@ -114,6 +152,9 @@ public class WeakTable extends LuaTable {
return super.rawget(key).strongvalue(); return super.rawget(key).strongvalue();
} }
/** Get the hash value for a key
* key the key to look up
* */
protected LuaValue hashget(LuaValue key) { protected LuaValue hashget(LuaValue key) {
if ( hashEntries > 0 ) { if ( hashEntries > 0 ) {
int i = hashFindSlot(key); int i = hashFindSlot(key);
@@ -179,6 +220,9 @@ public class WeakTable extends LuaTable {
} ); } );
} }
/** Internal class to implement weak values.
* @see WeakTable
*/
static class WeakValue extends LuaValue { static class WeakValue extends LuaValue {
final WeakReference ref; final WeakReference ref;
@@ -215,6 +259,9 @@ public class WeakTable extends LuaTable {
} }
} }
/** Internal class to implement weak userdata values.
* @see WeakTable
*/
static final class WeakUserdata extends WeakValue { static final class WeakUserdata extends WeakValue {
private final WeakReference ob; private final WeakReference ob;
private final LuaValue mt; private final LuaValue mt;
@@ -247,6 +294,9 @@ public class WeakTable extends LuaTable {
} }
} }
/** Internal class to implement weak table entries.
* @see WeakTable
*/
static final class WeakEntry extends LuaValue { static final class WeakEntry extends LuaValue {
final LuaValue weakkey; final LuaValue weakkey;
LuaValue weakvalue; LuaValue weakvalue;

View File

@@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2009 Luaj.org. All rights reserved. * Copyright (c) 2009-2011 Luaj.org. All rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -38,7 +38,19 @@ import org.luaj.vm2.LoadState.LuaCompiler;
/** /**
* Compiler for Lua * Compiler for Lua.
* <p>
* Compiles lua source files into lua bytecode within a {@link Prototype},
* loads lua binary files directly into a{@link Prototype},
* and optionaly instantiates a {@link LuaClosure} around the result
* using a user-supplied environment.
* <p>
* Implements the {@link LuaCompiler} interface for loading
* initialized chunks, which is an interface common to
* lua bytecode compiling and java bytecode compiling.
* <p>
* @see LuaCompiler
* @see Prototype
*/ */
public class LuaC extends Lua implements LuaCompiler { public class LuaC extends Lua implements LuaCompiler {