Streamline delegation chain for table event processing.

This commit is contained in:
James Roseborough
2008-05-26 19:21:15 +00:00
parent b8d0191dc9
commit 2c857d3cb3
6 changed files with 195 additions and 114 deletions

View File

@@ -188,14 +188,14 @@ public class PackageLib extends LFunction {
module = findtable( vm._G, modname );
if ( module == null )
vm.error( "name conflict for module '"+modname+"'" );
LOADED.luaSetTable(vm, LOADED, modname, module);
LOADED.luaSetTable(vm, modname, module);
} else {
module = (LTable) value;
}
/* check whether table already has a _NAME field */
LValue name = module.luaGetTable(vm, module, _NAME);
LValue name = module.luaGetTable(vm, _NAME);
if ( name.isNil() ) {
modinit( vm, module, modname );
}
@@ -244,10 +244,10 @@ public class PackageLib extends LFunction {
private static void modinit(LuaState vm, LTable module, LString modname) {
/* module._M = module */
module.luaSetTable(vm, module, _M, module);
module.luaSetTable(vm, _M, module);
int e = modname.lastIndexOf(_DOT);
module.luaSetTable(vm, module, _NAME, modname );
module.luaSetTable(vm, module, _PACKAGE, (e<0? _EMPTY: modname.substring(0,e+1)) );
module.luaSetTable(vm, _NAME, modname );
module.luaSetTable(vm, _PACKAGE, (e<0? _EMPTY: modname.substring(0,e+1)) );
}
/**
@@ -289,7 +289,7 @@ public class PackageLib extends LFunction {
vm.resettop();
/* else must load it; iterate over available loaders */
LValue val = pckg.luaGetTable(vm, pckg, _LOADERS);
LValue val = pckg.luaGetTable(vm, _LOADERS);
if ( ! val.isTable() )
vm.error( "'package.loaders' must be a table" );
vm.pushlvalue(val);
@@ -310,14 +310,14 @@ public class PackageLib extends LFunction {
}
// load the module using the loader
LOADED.luaSetTable(vm, LOADED, name, _SENTINEL);
LOADED.luaSetTable(vm, name, _SENTINEL);
vm.pushlstring( name ); /* pass name as argument to module */
vm.call( 1, 1 ); /* run loaded module */
if ( ! vm.isnil(-1) ) /* non-nil return? */
LOADED.luaSetTable(vm, LOADED, name, vm.topointer(-1) ); /* _LOADED[name] = returned value */
LValue result = LOADED.luaGetTable(vm, LOADED, name);
LOADED.luaSetTable(vm, name, vm.topointer(-1) ); /* _LOADED[name] = returned value */
LValue result = LOADED.luaGetTable(vm, name);
if ( result == _SENTINEL ) { /* module did not set a value? */
LOADED.luaSetTable(vm, LOADED, name, result=LBoolean.TRUE ); /* _LOADED[name] = true */
LOADED.luaSetTable(vm, name, result=LBoolean.TRUE ); /* _LOADED[name] = true */
}
vm.resettop();
vm.pushlvalue(result);
@@ -330,10 +330,10 @@ public class PackageLib extends LFunction {
private void loader_preload( LuaState vm ) {
LString name = vm.tolstring(2);
LValue preload = pckg.luaGetTable(vm, pckg, _PRELOAD);
LValue preload = pckg.luaGetTable(vm, _PRELOAD);
if ( ! preload.isTable() )
vm.error("package.preload '"+name+"' must be a table");
LValue val = preload.luaGetTable(vm, preload, name);
LValue val = preload.luaGetTable(vm, name);
if ( val.isNil() )
vm.pushstring("\n\tno field package.preload['"+name+"']");
vm.resettop();
@@ -371,7 +371,7 @@ public class PackageLib extends LFunction {
private InputStream findfile(LuaState vm, String name, LString pname) {
Platform p = Platform.getInstance();
LValue pkg = pckg.luaGetTable(vm, pckg, pname);
LValue pkg = pckg.luaGetTable(vm, pname);
if ( ! pkg.isString() )
vm.error("package."+pname+" must be a string");
String path = pkg.toJavaString();

View File

@@ -667,7 +667,7 @@ public class StringLib extends LFunction {
push_onecapture( 0, soffset, end );
LValue k = vm.topointer( -1 );
vm.pop( 1 );
vm.pushlvalue( ((LTable) repl).luaGetTable( vm, repl, k ) );
vm.pushlvalue( ((LTable) repl).luaGetTable( vm, k ) );
} else {
vm.error( "string/function/table expected" );
return;

View File

@@ -65,5 +65,31 @@ public class LFunction extends LValue {
public int invoke( LuaState lua ) {
return 0;
}
/**
* Process lua tag method __index when it points to a function.
* Default method calls the function using the vm.
*
* @param vm
* @param table
* @param key
* @return
*/
public LValue __index(LuaState vm, LValue table, LValue key) {
return vm.call(this, table, key);
}
/**
* Process lua tag method __newindex when it points to a function
* Default method calls the function using the vm.
*
* @param vm
* @param table
* @param key
* @param val
*/
public void __newindex(LuaState vm, LValue table, LValue key, LValue val) {
vm.call(this, table, key, val);
}
}

View File

@@ -202,6 +202,32 @@ public class LTable extends LValue {
array[key-1]:
hashGet(LInteger.valueOf(key)) );
}
/** Set a table value, including metatable processing.
*
* As an optimization for the common case, looks directly in the table first
* before delgating to the vm for metatable processing.
*/
public void luaSetTable(LuaState vm, LValue key, LValue val) {
if ( containsKey(key) || m_metatable == null || ! m_metatable.containsKey(TM_NEWINDEX) )
put( key, val );
else
vm.luaV_settable(this, key, val);
}
/** Get a table value, including metatable processing.
*
* As an optimization for the common case, looks directly in the table first
* before delgating to the vm for metatable processing.
*/
public LValue luaGetTable(LuaState vm, LValue key) {
LValue val = get(key);
return ! val.isNil() || m_metatable == null || ! m_metatable.containsKey(TM_INDEX)?
val:
vm.luaV_gettable(this, key);
}
/** Check for null, and convert to nilor leave alone
*/
@@ -232,14 +258,6 @@ public class LTable extends LValue {
(hashKeys.length>0 && hashKeys[hashFindSlot(LInteger.valueOf(key))]!=null));
}
public LValue luaGetTable(LuaState vm, LValue table, LValue key) {
return vm.luaV_gettable(table, key);
}
public void luaSetTable(LuaState vm, LValue table, LValue key, LValue val) {
vm.luaV_settable(table, key, val);
}
private static final int MAX_KEY = 0x3fffffff;
/**

View File

@@ -39,6 +39,8 @@ public class LValue {
/** Metatable tag for setting table mode */
public static final LString TM_MODE = new LString("__mode");
private static final int MAXTAGLOOP = 100;
protected void conversionError(String target) {
throw new LuaErrorException( "bad conversion: "+luaGetTypeName()+" to "+target );
}
@@ -124,40 +126,19 @@ public class LValue {
return false;
}
/** set a value in a table
* For non-tables, goes straight to the meta-table.
* @param vm the calling vm
* @param table the table to operate on
* @param the key to set
* @param the value to set
/** Dispatch a settable operation.
* Default method delegates back to the vm for metatable processing.
*/
public void luaSetTable(LuaState vm, LValue table, LValue key, LValue val) {
LTable mt = luaGetMetatable();
if ( mt != null ) {
LValue event = mt.get( TM_NEWINDEX );
if ( event != null && ! event.isNil() ) {
event.luaSetTable( vm, table, key, val );
return;
}
}
indexError( vm, table );
public void luaSetTable(LuaState vm, LValue key, LValue val) {
vm.luaV_settable(this, key, val);
}
/** Get a value from a table
* @param vm the calling vm
* @param table the table from which to get the value
* @param key the key to look up
* @return TODO
/** Dispatch a gettable operation.
* Default method delegates back to the vm for metatable processing.
*/
public LValue luaGetTable(LuaState vm, LValue table, LValue key) {
LTable mt = luaGetMetatable();
if ( mt != null ) {
LValue event = mt.get( TM_INDEX );
if ( event != null && ! event.isNil() ) {
return event.luaGetTable( vm, table, key );
}
}
return indexError( vm, table );
public LValue luaGetTable(LuaState vm, LValue key) {
return vm.luaV_gettable(this, key);
}
/** Get the value as a LString

View File

@@ -290,26 +290,28 @@ public class LuaState extends Lua {
public void call( int nargs, int nreturns ) {
// save stack state
int oldbase = base;
// rb is base of new call frame
int rb = this.base = top - 1 - nargs;
// make or set up the call
this.nresults = nreturns;
if (this.stack[base].luaStackCall(this)) {
// call was set up on the stack,
// we still have to execute it
execute();
try {
// rb is base of new call frame
int rb = this.base = top - 1 - nargs;
// make or set up the call
this.nresults = nreturns;
if (this.stack[base].luaStackCall(this)) {
// call was set up on the stack,
// we still have to execute it
execute();
}
// adjustTop only for case when call was completed
// and number of args > 0. If call completed but
// c == 0, leave top to point to end of results
if (nreturns >= 0)
luaV_adjusttop(rb + nreturns);
} finally {
this.base = oldbase;
}
// adjustTop only for case when call was completed
// and number of args > 0. If call completed but
// c == 0, leave top to point to end of results
if (nreturns >= 0)
luaV_adjusttop(rb + nreturns);
// restore base
this.base = oldbase;
}
/**
@@ -554,7 +556,7 @@ public class LuaState extends Lua {
b = LuaState.GETARG_Bx(i);
key = k[b];
table = cl.env;
val = luaV_gettable(table, key);
val = table.luaGetTable(this, key);
this.stack[base + a] = val;
continue;
}
@@ -562,7 +564,7 @@ public class LuaState extends Lua {
b = LuaState.GETARG_B(i);
key = GETARG_RKC(k, i);
table = this.stack[base + b];
val = luaV_gettable(table, key);
val = table.luaGetTable(this, key);
this.stack[base + a] = val;
continue;
}
@@ -571,7 +573,7 @@ public class LuaState extends Lua {
key = k[b];
val = this.stack[base + a];
table = cl.env;
luaV_settable(table, key, val);
table.luaSetTable(this, key, val);
continue;
}
case LuaState.OP_SETUPVAL: {
@@ -583,7 +585,7 @@ public class LuaState extends Lua {
key = GETARG_RKB(k, i);
val = GETARG_RKC(k, i);
table = this.stack[base + a];
luaV_settable(table, key, val);
table.luaSetTable(this, key, val);
continue;
}
case LuaState.OP_NEWTABLE: {
@@ -595,7 +597,7 @@ public class LuaState extends Lua {
case LuaState.OP_SELF: {
rkb = GETARG_RKB(k, i);
rkc = GETARG_RKC(k, i);
val = luaV_gettable(rkb, rkc);
val = rkb.luaGetTable(this, rkc);
this.stack[base + a] = val;
this.stack[base + a + 1] = rkb;
continue;
@@ -903,7 +905,7 @@ public class LuaState extends Lua {
error( "attempt to index ? (a "+nontable.luaGetTypeName()+" value)", 1 );
}
private LValue luaV_getmetafield(LValue t, LString tag) {
public static LValue luaV_getmetafield(LValue t, LString tag) {
LTable mt = t.luaGetMetatable();
if ( mt == null )
return null;
@@ -911,6 +913,7 @@ public class LuaState extends Lua {
return h.isNil()? null: h;
}
/** Get a key from a table using full metatable processing */
public LValue luaV_gettable(LValue table, LValue key) {
LValue h=LNil.NIL,t=table;
for ( int loop=0; loop<MAXTAGLOOP; loop++ ) {
@@ -930,21 +933,7 @@ public class LuaState extends Lua {
}
}
if (h.isFunction()) {
int oldtop = top;
int oldbase = base;
try {
base = base + this.calls[cc].closure.p.maxstacksize;
top = base;
pushlvalue(h);
pushlvalue(table);
pushlvalue(key);
call(2,1);
return poplvalue();
} finally {
resettop();
base = oldbase;
top = oldtop;
}
return ((LFunction)h).__index(this, table, key);
}
t = h;
}
@@ -952,6 +941,7 @@ public class LuaState extends Lua {
return LNil.NIL;
}
/** Get a key from a table using full metatable processing */
public void luaV_settable(LValue table, LValue key, LValue val) {
LValue h=LNil.NIL,t=table;
for ( int loop=0; loop<MAXTAGLOOP; loop++ ) {
@@ -973,22 +963,8 @@ public class LuaState extends Lua {
}
}
if (h.isFunction()) {
int oldtop = top;
int oldbase = base;
try {
base = base + this.calls[cc].closure.p.maxstacksize;
top = base;
pushlvalue(h);
pushlvalue(table);
pushlvalue(key);
pushlvalue(val);
call(3,0);
return;
} finally {
resettop();
base = oldbase;
top = oldtop;
}
((LFunction)h).__newindex(this, table, key, val);
return;
}
t = h;
}
@@ -1432,7 +1408,7 @@ public class LuaState extends Lua {
*/
public void getfield(int index, LString k) {
LTable t = totable(index);
pushlvalue( luaV_gettable(t, k) );
pushlvalue( t.luaGetTable(this, k) );
}
/**
@@ -1448,7 +1424,7 @@ public class LuaState extends Lua {
* </pre>
*/
public void getglobal(String s) {
pushlvalue( luaV_gettable(_G, new LString(s)) );
pushlvalue( _G.luaGetTable(this, new LString(s)) );
}
/**
@@ -1487,7 +1463,7 @@ public class LuaState extends Lua {
public void gettable(int index) {
LValue t = totable(index);
LValue k = poplvalue();
pushlvalue( luaV_gettable(t, k) );
pushlvalue( t.luaGetTable(this, k) );
}
/**
@@ -2101,7 +2077,7 @@ public class LuaState extends Lua {
*/
public void setfield(int index, LString k) {
LTable t = totable(index);
luaV_settable(t, k, poplvalue());
t.luaSetTable(this, k, poplvalue());
}
/**
@@ -2118,7 +2094,7 @@ public class LuaState extends Lua {
* </pre>
*/
public void setglobal(String name) {
luaV_settable(_G, new LString(name), poplvalue());
_G.luaSetTable(this, new LString(name), poplvalue());
}
/**
@@ -2158,7 +2134,7 @@ public class LuaState extends Lua {
LTable t = totable(index);
LValue v = poplvalue();
LValue k = poplvalue();
luaV_settable(t, k, v);
t.luaSetTable(this, k, v);
}
/**
@@ -2637,4 +2613,84 @@ public class LuaState extends Lua {
public static void vmerror(String description) {
throw new LuaErrorException( "internal error: "+description );
}
/**
* Call a function with no arguments and one return value
* @param function
* @return
*/
public LValue call(LFunction function) {
int oldtop = top;
try {
top = base + this.calls[cc].closure.p.maxstacksize;
pushlvalue(function);
call(0,1);
return poplvalue();
} finally {
top = oldtop;
}
}
/**
* Call a function with one argument and one return value
* @param function
* @param arg0
* @return
*/
public LValue call(LFunction function, LValue arg0) {
int oldtop = top;
try {
top = base + this.calls[cc].closure.p.maxstacksize;
pushlvalue(function);
pushlvalue(arg0);
call(1,1);
return poplvalue();
} finally {
top = oldtop;
}
}
/**
* Call a function with two arguments and one return value
* @param function
* @param arg0
* @param arg1
* @return
*/
public LValue call(LFunction function, LValue arg0, LValue arg1) {
int oldtop = top;
try {
top = base + this.calls[cc].closure.p.maxstacksize;
pushlvalue(function);
pushlvalue(arg0);
pushlvalue(arg1);
call(2,1);
return poplvalue();
} finally {
top = oldtop;
}
}
/**
* Call a function with three arguments and one return value
* @param function
* @param arg0
* @param arg1
* @param arg2
* @return
*/
public LValue call(LFunction function, LValue arg0, LValue arg1, LValue arg2) {
int oldtop = top;
try {
top = base + this.calls[cc].closure.p.maxstacksize;
pushlvalue(function);
pushlvalue(arg0);
pushlvalue(arg1);
pushlvalue(arg2);
call(3,1);
return poplvalue();
} finally {
top = oldtop;
}
}
}