diff --git a/src/addon/java/lua/addon/luacompat/LuaCompat.java b/src/addon/java/lua/addon/luacompat/LuaCompat.java index 5eaf2b26..376a4a93 100644 --- a/src/addon/java/lua/addon/luacompat/LuaCompat.java +++ b/src/addon/java/lua/addon/luacompat/LuaCompat.java @@ -663,24 +663,26 @@ public class LuaCompat extends LFunction { * 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(); + int n = vm.gettop(); + LTable table = vm.totable(2); + LString sep = (n>2? vm.tolstring(3): null); + int i = vm.tointeger(4); + int j = vm.tointeger(5); + int len = table.luaLength(); if ( i == 0 ) i = 1; if ( j == 0 ) - j = keys.length; + j = len; ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { for ( int k=i; k<=j; k++ ) { - LValue v = table.get(keys[k-1]); + LValue v = table.get(k); v.luaAsString().write(baos); - if ( k2? vm.getArgAsInt(1): 0); - LValue value = vm.getArg(n-1); + int n = vm.gettop(); + LTable table = vm.totable(2); + int pos = (n>3? vm.tointeger(3): 0); + LValue value = vm.topointer(-1); table.luaInsertPos( pos, value ); } @@ -707,8 +709,9 @@ public class LuaCompat extends LFunction { * 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( LInteger.valueOf( table.luaMaxN() ) ); + LTable table = vm.totable(2); + vm.settop(0); + vm.pushinteger( table.luaMaxN() ); } @@ -719,9 +722,9 @@ public class LuaCompat extends LFunction { * 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); + int n = vm.gettop(); + LTable table = vm.totable(2); + int pos = (n>1? vm.tointeger(3): 0); table.luaRemovePos( pos ); } @@ -735,7 +738,8 @@ public class LuaCompat extends LFunction { * 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(); + LTable table = vm.totable(2); + LValue compare = vm.topointer(3); + table.luaSort( vm, compare ); } } diff --git a/src/main/java/lua/StackState.java b/src/main/java/lua/StackState.java index 0f1450ba..0b9d065c 100644 --- a/src/main/java/lua/StackState.java +++ b/src/main/java/lua/StackState.java @@ -1011,6 +1011,10 @@ public class StackState extends Lua implements VM { pushlvalue(new LString(bytes, offset, length)); } + public void pushlstring(byte[] byteArray) { + pushlstring(byteArray, 0, byteArray.length); + } + public void pushnil() { pushlvalue(LNil.NIL); } diff --git a/src/main/java/lua/VM.java b/src/main/java/lua/VM.java index 8e8bee52..0ccb3846 100644 --- a/src/main/java/lua/VM.java +++ b/src/main/java/lua/VM.java @@ -4,6 +4,7 @@ import java.io.InputStream; import lua.io.Closure; import lua.value.LString; +import lua.value.LTable; import lua.value.LValue; /** *
@@ -938,6 +939,14 @@ public interface VM { */ public void pushlstring(byte[] bytes, int offset, int length); + /** + * Push string bytes onto the stack as a string. [-0, +1, + * m] + * + * Pushes the bytes in byteArray onto the stack as a lua string. + */ + public void pushlstring(byte[] byteArray); + /** * Push an LValue onto the stack. [-0, +1, * m] @@ -1341,6 +1350,15 @@ public interface VM { */ public StackState tothread(int index); + /** + * Get a value from the stack as a lua table. [-0, +0, -] + * + *

+ * Converts the value at the given acceptable index to a Lua table + * This value must be a table otherwise, the function returns NIL. + */ + public LTable totable(int index); + /** * Get the Object from a userdata value. [-0, +0, * -] diff --git a/src/main/java/lua/value/LTable.java b/src/main/java/lua/value/LTable.java index d15133a0..9de86cbd 100644 --- a/src/main/java/lua/value/LTable.java +++ b/src/main/java/lua/value/LTable.java @@ -1,5 +1,7 @@ package lua.value; +import java.util.Arrays; + import lua.Lua; import lua.VM; @@ -513,25 +515,98 @@ public class LTable extends LValue { return m_vector.length; } - /* + /** + * Insert element at a position in the list. * @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"); + if ( pos > m_arrayEntries + 1 ) + put( pos, value ); + else { + final int index = Math.max(0,pos==0? m_arrayEntries: pos-1); + if ( m_arrayEntries + 1 > m_vector.length ) + resize( ( m_arrayEntries + 1 ) * 2 ); + if ( m_vector[index] != LNil.NIL ) { + System.arraycopy(m_vector, index, m_vector, index+1, m_vector.length-1-index); + } + m_vector[index] = value; + ++m_arrayEntries; + } } + /** + * Remove an element from the list part of the table + * @param pos position to remove, or 0 to remove last element + */ public void luaRemovePos(int pos) { - throw new RuntimeException("luaRemovePos() not implemented"); + if ( pos > m_arrayEntries ) { + put( pos, LNil.NIL ); + } else { + final int index = Math.max(0,pos<=0? m_arrayEntries: pos)-1; + if ( index < 0 ) + return; + System.arraycopy(m_vector, index+1, m_vector, index, m_vector.length-1-index); + m_vector[m_vector.length-1] = LNil.NIL; + --m_arrayEntries; + } } public int luaMaxN() { - throw new RuntimeException("luaMaxN() not implemented"); + return m_arrayEntries; + } + + // ----------------- sort support ----------------------------- + // + // implemented heap sort from wikipedia + // + public void luaSort(VM vm, LValue compare) { + heapSort(m_arrayEntries, vm, compare); + } + + private void heapSort(int count, VM vm, LValue cmpfunc) { + heapify(count, vm, cmpfunc); + for ( int end=count-1; end>0; ) { + swap(end, 0); + siftDown(0, --end, vm, cmpfunc); + } + } + + private void heapify(int count, VM vm, LValue cmpfunc) { + for ( int start=count/2-1; start>=0; --start ) + siftDown(start, count - 1, vm, cmpfunc); + } + + private void siftDown(int start, int end, VM vm, LValue cmpfunc) { + for ( int root=start; root*2+1 <= end; ) { + int child = root*2+1; + if (child < end && compare(child, child + 1, vm, cmpfunc)) + ++child; + if (compare(root, child, vm, cmpfunc)) { + swap(root, child); + root = child; + } else + return; + } + } + + private boolean compare(int i, int j, VM vm, LValue cmpfunc) { + if ( cmpfunc != LNil.NIL ) { + vm.pushlvalue(cmpfunc); + vm.pushlvalue(m_vector[i]); + vm.pushlvalue(m_vector[j]); + vm.call(2, 1); + boolean result = vm.toboolean(1); + vm.settop(0); + return result; + } else { + return m_vector[j].luaBinCmpUnknown( Lua.OP_LT, m_vector[i] ); + } + } + + private void swap(int i, int j) { + LValue tmp = m_vector[i]; + m_vector[i] = m_vector[j]; + m_vector[j] = tmp; } } diff --git a/src/test/java/LuacRunner.java b/src/test/java/LuacRunner.java index f247ed2b..3a6c7536 100644 --- a/src/test/java/LuacRunner.java +++ b/src/test/java/LuacRunner.java @@ -30,7 +30,7 @@ public class LuacRunner { LuaJava.install(); // new lua state - StackState state = new DebugStackState(); + StackState state = new StackState(); VM vm = state; // load the file diff --git a/src/test/java/lua/LuaJTest.java b/src/test/java/lua/LuaJTest.java index 2b7edbd2..c1ec49cc 100644 --- a/src/test/java/lua/LuaJTest.java +++ b/src/test/java/lua/LuaJTest.java @@ -96,6 +96,10 @@ public class LuaJTest extends TestCase { runTest( "strlib" ); } + public void testTable() throws IOException, InterruptedException { + runTest( "table" ); + } + public void testType() throws IOException, InterruptedException { runTest( "type" ); } @@ -120,7 +124,7 @@ public class LuaJTest extends TestCase { LuaCompat.install(); // new lua state - StackState state = new DebugStackState(); + StackState state = new StackState(); // load the file Proto p = loadScriptResource( state, testName ); diff --git a/src/test/res/table.luac b/src/test/res/table.luac new file mode 100644 index 00000000..91b14f2e Binary files /dev/null and b/src/test/res/table.luac differ