Add a new test case for upvalues, and enhance upvalue handling so that
they pass.
This commit is contained in:
@@ -5,6 +5,7 @@ package lua;
|
|||||||
|
|
||||||
import lua.io.Closure;
|
import lua.io.Closure;
|
||||||
import lua.io.Proto;
|
import lua.io.Proto;
|
||||||
|
import lua.io.UpVal;
|
||||||
import lua.value.LBoolean;
|
import lua.value.LBoolean;
|
||||||
import lua.value.LInteger;
|
import lua.value.LInteger;
|
||||||
import lua.value.LNil;
|
import lua.value.LNil;
|
||||||
@@ -121,7 +122,7 @@ public class CallFrame {
|
|||||||
}
|
}
|
||||||
case StackState.OP_GETUPVAL: {
|
case StackState.OP_GETUPVAL: {
|
||||||
b = StackState.GETARG_B(i);
|
b = StackState.GETARG_B(i);
|
||||||
this.stack[base + a] = cl.upVals[b].value;
|
this.stack[base + a] = cl.upVals[b].getValue();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
case StackState.OP_GETGLOBAL: {
|
case StackState.OP_GETGLOBAL: {
|
||||||
@@ -148,7 +149,7 @@ public class CallFrame {
|
|||||||
}
|
}
|
||||||
case StackState.OP_SETUPVAL: {
|
case StackState.OP_SETUPVAL: {
|
||||||
b = StackState.GETARG_B(i);
|
b = StackState.GETARG_B(i);
|
||||||
cl.upVals[b].value = this.stack[base + a];
|
cl.upVals[b].setValue( this.stack[base + a] );
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
case StackState.OP_SETTABLE: {
|
case StackState.OP_SETTABLE: {
|
||||||
@@ -272,6 +273,8 @@ public class CallFrame {
|
|||||||
if (b != 0) // else use previous instruction set top
|
if (b != 0) // else use previous instruction set top
|
||||||
top = base + a + b;
|
top = base + a + b;
|
||||||
|
|
||||||
|
close( base ); // Close open upvals
|
||||||
|
|
||||||
// make or set up the call
|
// make or set up the call
|
||||||
this.stack[base + a].luaStackCall(this, base + a, top, c - 1);
|
this.stack[base + a].luaStackCall(this, base + a, top, c - 1);
|
||||||
|
|
||||||
@@ -298,6 +301,7 @@ public class CallFrame {
|
|||||||
b = StackState.GETARG_B(i); // number of return vals
|
b = StackState.GETARG_B(i); // number of return vals
|
||||||
if (b != 0) // else use previous top
|
if (b != 0) // else use previous top
|
||||||
top = base + a + b - 1;
|
top = base + a + b - 1;
|
||||||
|
close( base ); // close open upvals
|
||||||
n = top - (base + a); // number to copy down
|
n = top - (base + a); // number to copy down
|
||||||
System.arraycopy(this.stack, base + a, this.stack,
|
System.arraycopy(this.stack, base + a, this.stack,
|
||||||
base - 1, n);
|
base - 1, n);
|
||||||
@@ -379,7 +383,7 @@ public class CallFrame {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
case StackState.OP_CLOSE: {
|
case StackState.OP_CLOSE: {
|
||||||
// for java, no need to do anything!
|
close( a ); // close upvals higher in the stack than position a
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
case StackState.OP_CLOSURE: {
|
case StackState.OP_CLOSURE: {
|
||||||
@@ -391,12 +395,9 @@ public class CallFrame {
|
|||||||
o = StackState.GET_OPCODE(i);
|
o = StackState.GET_OPCODE(i);
|
||||||
b = StackState.GETARG_B(i);
|
b = StackState.GETARG_B(i);
|
||||||
if (o == StackState.OP_GETUPVAL) {
|
if (o == StackState.OP_GETUPVAL) {
|
||||||
newClosure.upVals[j] = cl.upVals[b]; // TODO
|
newClosure.upVals[j] = cl.upVals[b];
|
||||||
} else if (o == StackState.OP_MOVE) {
|
} else if (o == StackState.OP_MOVE) {
|
||||||
newClosure.upVals[j].value = this.stack[base + b]; // TODO:
|
newClosure.upVals[j] = findUpVal( proto.upvalues[j], base + b );
|
||||||
// what
|
|
||||||
// to do
|
|
||||||
// here?
|
|
||||||
} else {
|
} else {
|
||||||
throw new java.lang.IllegalArgumentException(
|
throw new java.lang.IllegalArgumentException(
|
||||||
"bad opcode: " + o);
|
"bad opcode: " + o);
|
||||||
@@ -425,7 +426,30 @@ public class CallFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private UpVal findUpVal( LString upValName, int target ) {
|
||||||
|
UpVal up;
|
||||||
|
int i;
|
||||||
|
for ( i = this.state.upvals.size() - 1; i >= 0; --i ) {
|
||||||
|
up = (UpVal) this.state.upvals.elementAt( i );
|
||||||
|
if ( up.stack == this.stack && up.position == target ) {
|
||||||
|
return up;
|
||||||
|
} else if ( up.position < target ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
up = new UpVal( upValName, this.stack, target );
|
||||||
|
this.state.upvals.insertElementAt( up, i + 1 );
|
||||||
|
return up;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void close( int limit ) {
|
||||||
|
while ( !state.upvals.empty() && ( (UpVal) this.state.upvals.lastElement() ).close( limit ) ) {
|
||||||
|
this.state.upvals.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void push(LValue value) {
|
public void push(LValue value) {
|
||||||
stack[top++] = value;
|
stack[top++] = value;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,6 @@ public class Closure extends LFunction {
|
|||||||
this.env = state._G;
|
this.env = state._G;
|
||||||
this.p = p;
|
this.p = p;
|
||||||
upVals = new UpVal[p.nups];
|
upVals = new UpVal[p.nups];
|
||||||
for ( int i=0; i<p.nups; i++ )
|
|
||||||
upVals[i] = new UpVal( p.upvalues[i] );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// perform a lua call
|
// perform a lua call
|
||||||
|
|||||||
@@ -6,14 +6,35 @@ import lua.value.LValue;
|
|||||||
public class UpVal {
|
public class UpVal {
|
||||||
|
|
||||||
private LString name;
|
private LString name;
|
||||||
public LValue value;
|
public LValue[] stack;
|
||||||
|
public int position;
|
||||||
|
|
||||||
public UpVal( LString string ) {
|
public UpVal( LString string, LValue[] stack, int i ) {
|
||||||
this.name = string;
|
this.name = string;
|
||||||
|
this.stack = stack;
|
||||||
|
this.position = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "up."+name;
|
return "up."+name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LValue getValue() {
|
||||||
|
return stack[ position ];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue( LValue value ) {
|
||||||
|
stack[ position ] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean close( int limit ) {
|
||||||
|
if ( position >= limit ) {
|
||||||
|
final LValue v = stack[ position ];
|
||||||
|
stack = new LValue[] { v };
|
||||||
|
position = 0;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,10 @@ public class LuaJTest extends TestCase {
|
|||||||
runTest( "upvalues" );
|
runTest( "upvalues" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testUpvalues2() throws IOException, InterruptedException {
|
||||||
|
runTest( "upvalues2" );
|
||||||
|
}
|
||||||
|
|
||||||
private void runTest( String testName ) throws IOException, InterruptedException {
|
private void runTest( String testName ) throws IOException, InterruptedException {
|
||||||
// add LuaJava bindings
|
// add LuaJava bindings
|
||||||
LuaJava.install();
|
LuaJava.install();
|
||||||
|
|||||||
42
src/test/res/upvalues2.lua
Normal file
42
src/test/res/upvalues2.lua
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
-- The point of this test is that when an upvalue is created, it may
|
||||||
|
-- need to be inserted in the middle of the list, rather than always
|
||||||
|
-- appended at the end. Otherwise, it may not be found when it is
|
||||||
|
-- needed by another closure.
|
||||||
|
|
||||||
|
local function test()
|
||||||
|
local x = 3
|
||||||
|
local y = 5
|
||||||
|
local z = 7
|
||||||
|
|
||||||
|
local function f()
|
||||||
|
print("y=", y)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function g()
|
||||||
|
print("z=", z)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function h()
|
||||||
|
print("x=", x)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function setter(x1, y1, z1)
|
||||||
|
x = x1
|
||||||
|
y = y1
|
||||||
|
z = z1
|
||||||
|
end
|
||||||
|
|
||||||
|
return f, g, h, setter
|
||||||
|
end
|
||||||
|
|
||||||
|
local f, g, h, setter = test()
|
||||||
|
|
||||||
|
h()
|
||||||
|
f()
|
||||||
|
g()
|
||||||
|
|
||||||
|
setter("x", "y", "z")
|
||||||
|
|
||||||
|
h()
|
||||||
|
f()
|
||||||
|
g()
|
||||||
BIN
src/test/res/upvalues2.luac
Normal file
BIN
src/test/res/upvalues2.luac
Normal file
Binary file not shown.
Reference in New Issue
Block a user