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.Proto;
|
||||
import lua.io.UpVal;
|
||||
import lua.value.LBoolean;
|
||||
import lua.value.LInteger;
|
||||
import lua.value.LNil;
|
||||
@@ -121,7 +122,7 @@ public class CallFrame {
|
||||
}
|
||||
case StackState.OP_GETUPVAL: {
|
||||
b = StackState.GETARG_B(i);
|
||||
this.stack[base + a] = cl.upVals[b].value;
|
||||
this.stack[base + a] = cl.upVals[b].getValue();
|
||||
continue;
|
||||
}
|
||||
case StackState.OP_GETGLOBAL: {
|
||||
@@ -148,7 +149,7 @@ public class CallFrame {
|
||||
}
|
||||
case StackState.OP_SETUPVAL: {
|
||||
b = StackState.GETARG_B(i);
|
||||
cl.upVals[b].value = this.stack[base + a];
|
||||
cl.upVals[b].setValue( this.stack[base + a] );
|
||||
continue;
|
||||
}
|
||||
case StackState.OP_SETTABLE: {
|
||||
@@ -272,6 +273,8 @@ public class CallFrame {
|
||||
if (b != 0) // else use previous instruction set top
|
||||
top = base + a + b;
|
||||
|
||||
close( base ); // Close open upvals
|
||||
|
||||
// make or set up the call
|
||||
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
|
||||
if (b != 0) // else use previous top
|
||||
top = base + a + b - 1;
|
||||
close( base ); // close open upvals
|
||||
n = top - (base + a); // number to copy down
|
||||
System.arraycopy(this.stack, base + a, this.stack,
|
||||
base - 1, n);
|
||||
@@ -379,7 +383,7 @@ public class CallFrame {
|
||||
continue;
|
||||
}
|
||||
case StackState.OP_CLOSE: {
|
||||
// for java, no need to do anything!
|
||||
close( a ); // close upvals higher in the stack than position a
|
||||
continue;
|
||||
}
|
||||
case StackState.OP_CLOSURE: {
|
||||
@@ -391,12 +395,9 @@ public class CallFrame {
|
||||
o = StackState.GET_OPCODE(i);
|
||||
b = StackState.GETARG_B(i);
|
||||
if (o == StackState.OP_GETUPVAL) {
|
||||
newClosure.upVals[j] = cl.upVals[b]; // TODO
|
||||
newClosure.upVals[j] = cl.upVals[b];
|
||||
} else if (o == StackState.OP_MOVE) {
|
||||
newClosure.upVals[j].value = this.stack[base + b]; // TODO:
|
||||
// what
|
||||
// to do
|
||||
// here?
|
||||
newClosure.upVals[j] = findUpVal( proto.upvalues[j], base + b );
|
||||
} else {
|
||||
throw new java.lang.IllegalArgumentException(
|
||||
"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) {
|
||||
stack[top++] = value;
|
||||
}
|
||||
|
||||
@@ -13,8 +13,6 @@ public class Closure extends LFunction {
|
||||
this.env = state._G;
|
||||
this.p = p;
|
||||
upVals = new UpVal[p.nups];
|
||||
for ( int i=0; i<p.nups; i++ )
|
||||
upVals[i] = new UpVal( p.upvalues[i] );
|
||||
}
|
||||
|
||||
// perform a lua call
|
||||
|
||||
@@ -6,14 +6,35 @@ import lua.value.LValue;
|
||||
public class UpVal {
|
||||
|
||||
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.stack = stack;
|
||||
this.position = i;
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
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" );
|
||||
}
|
||||
|
||||
public void testUpvalues2() throws IOException, InterruptedException {
|
||||
runTest( "upvalues2" );
|
||||
}
|
||||
|
||||
private void runTest( String testName ) throws IOException, InterruptedException {
|
||||
// add LuaJava bindings
|
||||
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