Many built-ins: ipairs, table.insert, require, pcall
This commit is contained in:
@@ -13,8 +13,6 @@ import lua.Lua;
|
||||
import lua.StackState;
|
||||
import lua.VM;
|
||||
import lua.io.Closure;
|
||||
import lua.io.LoadState;
|
||||
import lua.io.Proto;
|
||||
import lua.value.LBoolean;
|
||||
import lua.value.LDouble;
|
||||
import lua.value.LFunction;
|
||||
@@ -52,6 +50,11 @@ public class LuaCompat extends LFunction {
|
||||
installNames( pckg, PACKAGE_NAMES, PACKAGES_BASE );
|
||||
globals.put( "package", pckg );
|
||||
pckg.put( "loaded", LOADED );
|
||||
|
||||
// table lib
|
||||
LTable table = new LTable();
|
||||
installNames( pckg, TABLE_NAMES, TABLES_BASE );
|
||||
globals.put( "table", pckg );
|
||||
}
|
||||
|
||||
private static void installNames( LTable table, String[] names, int indexBase ) {
|
||||
@@ -107,6 +110,14 @@ public class LuaCompat extends LFunction {
|
||||
"seeall",
|
||||
};
|
||||
|
||||
public static final String[] TABLE_NAMES = {
|
||||
"concat",
|
||||
"insert",
|
||||
"maxn",
|
||||
"remove",
|
||||
"sort",
|
||||
};
|
||||
|
||||
private static final int GLOBALS_BASE = 0;
|
||||
private static final int ASSERT = GLOBALS_BASE + 0;
|
||||
private static final int LOADFILE = GLOBALS_BASE + 1;
|
||||
@@ -152,6 +163,13 @@ public class LuaCompat extends LFunction {
|
||||
private static final int LOADLIB = PACKAGES_BASE + 0;
|
||||
private static final int SEEALL = PACKAGES_BASE + 1;
|
||||
|
||||
private static final int TABLES_BASE = 60;
|
||||
private static final int CONCAT = TABLES_BASE + 0;
|
||||
private static final int INSERT = TABLES_BASE + 1;
|
||||
private static final int MAXN = TABLES_BASE + 2;
|
||||
private static final int REMOVE = TABLES_BASE + 3;
|
||||
private static final int SORT = TABLES_BASE + 4;
|
||||
|
||||
private final int id;
|
||||
|
||||
private LuaCompat( int id ) {
|
||||
@@ -198,7 +216,8 @@ public class LuaCompat extends LFunction {
|
||||
vm.setResult();
|
||||
break;
|
||||
case DOFILE:
|
||||
return dofile(vm, vm.getArgAsString(0));
|
||||
dofile(vm);
|
||||
break;
|
||||
case LOADSTRING:
|
||||
loadstring(vm, vm.getArg(0), vm.getArgAsString(1));
|
||||
break;
|
||||
@@ -209,8 +228,7 @@ public class LuaCompat extends LFunction {
|
||||
vm.setResult( tostring(vm, vm.getArg(0)) );
|
||||
break;
|
||||
case UNPACK:
|
||||
vm.setResult();
|
||||
unpack(vm, vm.getArg(0), vm.getArgAsInt(1), vm.getArgAsInt(2));
|
||||
unpack(vm);
|
||||
break;
|
||||
case NEXT:
|
||||
vm.setResult( next(vm, vm.getArg(0), vm.getArgAsInt(1)) );
|
||||
@@ -290,12 +308,30 @@ public class LuaCompat extends LFunction {
|
||||
case SEEALL:
|
||||
seeall(vm);
|
||||
break;
|
||||
|
||||
// table library
|
||||
case CONCAT:
|
||||
concat(vm);
|
||||
break;
|
||||
case INSERT:
|
||||
insert(vm);
|
||||
break;
|
||||
case MAXN:
|
||||
maxn(vm);
|
||||
break;
|
||||
case REMOVE:
|
||||
remove(vm);
|
||||
break;
|
||||
case SORT:
|
||||
sort(vm);
|
||||
break;
|
||||
|
||||
default:
|
||||
luaUnsupportedOperation();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void select( VM vm ) {
|
||||
LValue arg = vm.getArg( 0 );
|
||||
if ( arg instanceof LNumber ) {
|
||||
@@ -451,13 +487,14 @@ public class LuaCompat extends LFunction {
|
||||
return loadis( vm, is, script );
|
||||
}
|
||||
|
||||
// return true if call placed on the stack & ready to execute, false otherwise
|
||||
private boolean dofile( VM vm, String fileName ) {
|
||||
if ( loadfile( vm, fileName ) ) {
|
||||
vm.prepStackCall(); // TODO: is this necessary?
|
||||
return true;
|
||||
// if load succeeds, return 0 for success, 1 for error (as per lua spec)
|
||||
private void dofile( VM vm ) {
|
||||
String filename = vm.getArgAsString(0);
|
||||
if ( loadfile( vm, filename ) ) {
|
||||
int s = vm.lua_pcall(1, 0);
|
||||
vm.setResult( new LInteger( s!=0? 1: 0 ) );
|
||||
} else {
|
||||
return false;
|
||||
vm.lua_error("cannot open "+filename);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -508,25 +545,26 @@ public class LuaCompat extends LFunction {
|
||||
return arg.luaAsString();
|
||||
}
|
||||
|
||||
private static LTable toTable(VM vm, LValue list) {
|
||||
if ( ! (list instanceof LTable) ) {
|
||||
vm.lua_error("not a list: "+list);
|
||||
return null;
|
||||
}
|
||||
return (LTable) list;
|
||||
}
|
||||
|
||||
private void unpack(VM vm, LValue list, int i, int j) {
|
||||
LTable t = toTable(vm, list);
|
||||
if ( t == null )
|
||||
return;
|
||||
/** unpack (list [, i [, j]])
|
||||
*
|
||||
* Returns the elements from the given table. This function is equivalent to
|
||||
* return list[i], list[i+1], ···, list[j]
|
||||
*
|
||||
* except that the above code can be written only for a fixed number of elements.
|
||||
* By default, i is 1 and j is the length of the list, as defined by the length operator (see §2.5.5).
|
||||
*/
|
||||
private void unpack(VM vm) {
|
||||
LValue v = vm.getArg(0);
|
||||
int i = vm.getArgAsInt(1);
|
||||
int j = vm.getArgAsInt(2);
|
||||
LTable list = (LTable) v;
|
||||
if ( i == 0 )
|
||||
i = 1;
|
||||
if ( j == 0 )
|
||||
j = t.size();
|
||||
LValue[] keys = t.getKeys();
|
||||
for ( int k=i; k<=j; k++ )
|
||||
vm.push( t.get(keys[k-1]) );
|
||||
j = list.luaLength().luaAsInt();
|
||||
vm.setResult();
|
||||
for ( int k=i; k<=j; k++ )
|
||||
vm.push( list.get(k) );
|
||||
}
|
||||
|
||||
private LValue next(VM vm, LValue table, int index) {
|
||||
@@ -575,13 +613,12 @@ public class LuaCompat extends LFunction {
|
||||
if ( ! loadfile(vm, s+".luac") && ! loadfile(vm, s+".lua") )
|
||||
vm.lua_error( "not found: "+s );
|
||||
else if ( 0 == vm.lua_pcall(0, 1) ) {
|
||||
LValue result = vm.getArg(0);
|
||||
LValue result = vm.lua_tolvalue( -1 );
|
||||
if ( result != LNil.NIL )
|
||||
LOADED.put(modname, result);
|
||||
else if ( ! LOADED.containsKey(modname) ) {
|
||||
LOADED.put(modname, LBoolean.TRUE);
|
||||
vm.setResult( LBoolean.TRUE );
|
||||
}
|
||||
else if ( ! LOADED.containsKey(modname) )
|
||||
LOADED.put(modname, result = LBoolean.TRUE);
|
||||
vm.setResult( result );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -594,5 +631,88 @@ public class LuaCompat extends LFunction {
|
||||
vm.lua_error( "seeall not implemented" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ============= tables support =============
|
||||
/** table.concat (table [, sep [, i [, j]]])
|
||||
*
|
||||
* Given an array where all elements are strings or numbers, returns table[i]..sep..table[i+1] ··· sep..table[j].
|
||||
* The default value for sep is the empty string, the default for i is 1, and the default for j is the length of the table.
|
||||
* If i is greater than j, returns the empty string.
|
||||
*/
|
||||
private void concat(VM vm) {
|
||||
LTable table = (LTable) vm.getArg(0);
|
||||
LString sep = vm.getArgAsLuaString(1);
|
||||
int i = vm.getArgAsInt(2);
|
||||
int j = vm.getArgAsInt(3);
|
||||
LValue[] keys = table.getKeys();
|
||||
if ( i == 0 )
|
||||
i = 1;
|
||||
if ( j == 0 )
|
||||
j = keys.length;
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try {
|
||||
for ( int k=i; k<=j; k++ ) {
|
||||
LValue v = table.get(keys[k-1]);
|
||||
v.luaAsString().write(baos);
|
||||
if ( k<j )
|
||||
sep.write( baos );
|
||||
}
|
||||
vm.setResult( new LString( baos.toByteArray() ) );
|
||||
} catch (IOException e) {
|
||||
vm.lua_error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/** table.insert (table, [pos,] value)
|
||||
*
|
||||
* Inserts element value at position pos in table, shifting up other elements to open space, if necessary.
|
||||
* The default value for pos is n+1, where n is the length of the table (see §2.5.5), so that a call
|
||||
* table.insert(t,x) inserts x at the end of table t.
|
||||
*/
|
||||
private void insert(VM vm) {
|
||||
int n = vm.getArgCount();
|
||||
LTable table = (LTable) vm.getArg(0);
|
||||
int pos = (n>2? vm.getArgAsInt(1): 0);
|
||||
LValue value = vm.getArg(n-1);
|
||||
table.luaInsertPos( pos, value );
|
||||
}
|
||||
|
||||
|
||||
/** table.maxn (table)
|
||||
*
|
||||
* Returns the largest positive numerical index of the given table, or zero if the table has no positive numerical
|
||||
* indices. (To do its job this function does a linear traversal of the whole table.)
|
||||
*/
|
||||
private void maxn(VM vm) {
|
||||
LTable table = (LTable) vm.getArg(0);
|
||||
vm.setResult( new LInteger( table.luaMaxN() ) );
|
||||
}
|
||||
|
||||
|
||||
/** table.remove (table [, pos])
|
||||
*
|
||||
* Removes from table the element at position pos, shifting down other elements to close the space, if necessary.
|
||||
* Returns the value of the removed element. The default value for pos is n, where n is the length of the table,
|
||||
* so that a call table.remove(t) removes the last element of table t.
|
||||
*/
|
||||
private void remove(VM vm) {
|
||||
int n = vm.getArgCount();
|
||||
LTable table = (LTable) vm.getArg(0);
|
||||
int pos = (n>1? vm.getArgAsInt(1): 0);
|
||||
table.luaRemovePos( pos );
|
||||
}
|
||||
|
||||
/** table.sort (table [, comp])
|
||||
*
|
||||
* Sorts table elements in a given order, in-place, from table[1] to table[n], where n is the length of the table.
|
||||
* If comp is given, then it must be a function that receives two table elements, and returns true when the first
|
||||
* is less than the second (so that not comp(a[i+1],a[i]) will be true after the sort). If comp is not given,
|
||||
* then the standard Lua operator < is used instead.
|
||||
*
|
||||
* The sort algorithm is not stable; that is, elements considered equal by the given order may have their relative positions changed by the sort.
|
||||
*/
|
||||
private void sort(VM vm) {
|
||||
LTable table = (LTable) vm.getArg(0);
|
||||
table.luaSort();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,13 +25,16 @@ final class Builtin extends LFunction {
|
||||
"getmetatable",
|
||||
"setmetatable",
|
||||
"type",
|
||||
"pcall" };
|
||||
"pcall",
|
||||
"ipairs",
|
||||
};
|
||||
private static final int PRINT = 0;
|
||||
private static final int PAIRS = 1;
|
||||
private static final int GETMETATABLE = 2;
|
||||
private static final int SETMETATABLE = 3;
|
||||
private static final int TYPE = 4;
|
||||
private static final int PCALL = 5;
|
||||
private static final int IPAIRS = 6;
|
||||
|
||||
private static PrintStream stdout = System.out;
|
||||
|
||||
@@ -47,18 +50,20 @@ final class Builtin extends LFunction {
|
||||
// perform a lua call
|
||||
public boolean luaStackCall(VM vm) {
|
||||
switch ( id ) {
|
||||
case PRINT:
|
||||
int n = vm.getArgCount();
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
if ( i > 0 )
|
||||
stdout.print( "\t" );
|
||||
stdout.print( vm.getArg(i).luaAsString() );
|
||||
case PRINT: {
|
||||
int n = vm.getArgCount();
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
if ( i > 0 )
|
||||
stdout.print( "\t" );
|
||||
stdout.print( vm.getArg(i).luaAsString() );
|
||||
}
|
||||
stdout.println();
|
||||
vm.setResult();
|
||||
}
|
||||
stdout.println();
|
||||
vm.setResult();
|
||||
break;
|
||||
case PAIRS:
|
||||
vm.setResult( vm.getArg(0).luaPairs() );
|
||||
case IPAIRS:
|
||||
vm.setResult( vm.getArg(0).luaPairs(id==PAIRS) );
|
||||
break;
|
||||
case GETMETATABLE:
|
||||
vm.setResult( vm.getArg(0).luaGetMetatable() );
|
||||
@@ -71,13 +76,16 @@ final class Builtin extends LFunction {
|
||||
case TYPE:
|
||||
vm.setResult( vm.getArg(0).luaGetType() );
|
||||
break;
|
||||
case PCALL:
|
||||
if ( 0 != vm.lua_pcall( vm.getArgCount()-1, Lua.LUA_MULTRET ) ) {
|
||||
LValue v = vm.getArg(0);
|
||||
vm.setResult( LBoolean.FALSE );
|
||||
vm.push( v );
|
||||
} else {
|
||||
vm.setResult( LBoolean.TRUE );
|
||||
case PCALL: {
|
||||
int n = vm.getArgCount();
|
||||
int s = vm.lua_pcall( n-1, Lua.LUA_MULTRET );
|
||||
if ( s != 0 ) {
|
||||
LValue v = vm.lua_tolvalue(-1);
|
||||
vm.setResult( LBoolean.FALSE );
|
||||
vm.push( v );
|
||||
} else {
|
||||
vm.setResult( LBoolean.TRUE );
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -179,4 +179,11 @@ public interface VM {
|
||||
* @return 0 if successful, LUA_ERRMEM if no memory, LUA_ERRSYNTAX for i/o or any other errors
|
||||
*/
|
||||
public int lua_load( InputStream is, String chunkname );
|
||||
|
||||
/**
|
||||
* Get a value on the stack, relative to the top or bottom
|
||||
* @param i index from bottom if 0 or greater, index from top if less than 0
|
||||
* @return
|
||||
*/
|
||||
public LValue lua_tolvalue(int i);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import lua.CallInfo;
|
||||
import lua.Print;
|
||||
import lua.StackState;
|
||||
import lua.io.LocVars;
|
||||
import lua.io.Proto;
|
||||
@@ -38,22 +37,34 @@ public class DebugStackState extends StackState implements DebugRequestListener
|
||||
return source+":"+line+"("+func+")";
|
||||
}
|
||||
|
||||
private String addLineInfo( String message ) {
|
||||
return getFileLine(cc)+": "+message;
|
||||
}
|
||||
|
||||
private void printLuaTrace(String message) {
|
||||
System.out.println( "Lua error: "+message );
|
||||
System.out.println( "Lua error: "+addLineInfo( message ) );
|
||||
for ( int cindex=cc-1; cindex>=0; cindex-- )
|
||||
System.out.println( "\tcalled by "+getFileLine( cindex ) );
|
||||
}
|
||||
|
||||
protected void debugPcallError(Throwable t) {
|
||||
System.out.println(addLineInfo("(caught in pcall) "+t.getMessage()));
|
||||
System.out.flush();
|
||||
}
|
||||
|
||||
public void lua_error(String message) {
|
||||
throw new RuntimeException( message );
|
||||
}
|
||||
|
||||
// intercept exceptions and fill in line numbers
|
||||
public void exec() {
|
||||
try {
|
||||
super.exec();
|
||||
} catch ( RuntimeException t ) {
|
||||
String message = getFileLine(cc)+": "+t.getMessage();
|
||||
t.printStackTrace();
|
||||
printLuaTrace(message);
|
||||
printLuaTrace(t.getMessage());
|
||||
System.out.flush();
|
||||
throw new RuntimeException( message, t );
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +74,9 @@ public class DebugStackState extends StackState implements DebugRequestListener
|
||||
if ( exiting )
|
||||
throw new java.lang.RuntimeException("exiting");
|
||||
|
||||
// make sure line numbers are current in any stack traces
|
||||
calls[cc].pc = pc;
|
||||
|
||||
synchronized ( this ) {
|
||||
|
||||
// anytime the line doesn't change we keep going
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package lua.value;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
@@ -185,6 +186,10 @@ public class LString extends LValue {
|
||||
|
||||
os.write( m_bytes, m_offset+offset, len );
|
||||
}
|
||||
|
||||
public void write(OutputStream os) throws IOException {
|
||||
write(os, 0, m_length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the bytes of the string into the given byte array.
|
||||
|
||||
@@ -267,18 +267,20 @@ public class LTable extends LValue {
|
||||
}
|
||||
|
||||
/** Valid for tables */
|
||||
public LValue luaPairs() {
|
||||
return new LTableIterator();
|
||||
public LValue luaPairs(boolean isPairs) {
|
||||
return new LTableIterator(isPairs);
|
||||
}
|
||||
|
||||
/** Iterator for tables */
|
||||
private final class LTableIterator extends LFunction {
|
||||
private int arrayIndex;
|
||||
private int hashIndex;
|
||||
private final boolean isPairs;
|
||||
|
||||
private LTableIterator() {
|
||||
private LTableIterator(boolean isPairs) {
|
||||
this.arrayIndex = 0;
|
||||
this.hashIndex = 0;
|
||||
this.isPairs = isPairs;
|
||||
}
|
||||
|
||||
// perform a lua call
|
||||
@@ -292,7 +294,7 @@ public class LTable extends LValue {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ( m_hashKeys != null ) {
|
||||
if ( isPairs && (m_hashKeys != null) ) {
|
||||
while ( ( i = hashIndex++ ) < m_hashKeys.length ) {
|
||||
if ( m_hashKeys[i] != null ) {
|
||||
vm.push( m_hashKeys[i] );
|
||||
@@ -513,5 +515,26 @@ public class LTable extends LValue {
|
||||
int getArrayCapacity() {
|
||||
return m_vector.length;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @pos index to insert at, or 0 to insert at end.
|
||||
*/
|
||||
public void luaInsertPos(int pos, LValue value) {
|
||||
if ( pos != 0 )
|
||||
throw new RuntimeException("luaInsertPos() not implemented");
|
||||
put( m_arrayEntries + m_hashEntries + 1, value );
|
||||
}
|
||||
|
||||
public void luaSort() {
|
||||
throw new RuntimeException("luaSort() not implemented");
|
||||
}
|
||||
|
||||
public void luaRemovePos(int pos) {
|
||||
throw new RuntimeException("luaRemovePos() not implemented");
|
||||
}
|
||||
|
||||
public int luaMaxN() {
|
||||
throw new RuntimeException("luaMaxN() not implemented");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -151,8 +151,9 @@ public class LValue {
|
||||
return luaUnsupportedOperation();
|
||||
}
|
||||
|
||||
/** Valid for tables */
|
||||
public LValue luaPairs() {
|
||||
/** Valid for tables
|
||||
* @param isPairs true to iterate over non-integers as well */
|
||||
public LValue luaPairs(boolean isPairs) {
|
||||
return luaUnsupportedOperation();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user