Refactor luajava method mapping computation.
This commit is contained in:
@@ -27,13 +27,14 @@ import java.util.Map;
|
||||
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
|
||||
public class CoerceLuaToJava {
|
||||
|
||||
public static interface Coercion {
|
||||
public Object coerce( LuaValue value );
|
||||
public int score( LuaValue value );
|
||||
public int score( int paramType );
|
||||
};
|
||||
|
||||
private static Map COERCIONS = new HashMap();
|
||||
@@ -44,11 +45,12 @@ public class CoerceLuaToJava {
|
||||
public Object coerce(LuaValue value) {
|
||||
return value.toboolean()? Boolean.TRUE: Boolean.FALSE;
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
public int score(int paramType) {
|
||||
switch ( paramType ) {
|
||||
case LuaValue.TNIL:
|
||||
case LuaValue.TBOOLEAN:
|
||||
return 0;
|
||||
case LuaValue.TINT:
|
||||
case LuaValue.TNUMBER:
|
||||
return 1;
|
||||
default:
|
||||
@@ -60,10 +62,12 @@ public class CoerceLuaToJava {
|
||||
public Object coerce(LuaValue value) {
|
||||
return new Byte( (byte) value.toint() );
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
public int score(int paramType) {
|
||||
switch ( paramType ) {
|
||||
case LuaValue.TINT:
|
||||
return 1;
|
||||
case LuaValue.TNUMBER:
|
||||
return (value.isinttype()? 1: 2);
|
||||
return 2;
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
@@ -73,10 +77,12 @@ public class CoerceLuaToJava {
|
||||
public Object coerce(LuaValue value) {
|
||||
return new Character( (char) value.toint() );
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
public int score(int paramType) {
|
||||
switch ( paramType ) {
|
||||
case LuaValue.TINT:
|
||||
return 1;
|
||||
case LuaValue.TNUMBER:
|
||||
return (value.isinttype()? 1: 2);
|
||||
return 2;
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
@@ -86,10 +92,12 @@ public class CoerceLuaToJava {
|
||||
public Object coerce(LuaValue value) {
|
||||
return new Short( (short) value.toint() );
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
public int score(int paramType) {
|
||||
switch ( paramType ) {
|
||||
case LuaValue.TINT:
|
||||
return 1;
|
||||
case LuaValue.TNUMBER:
|
||||
return (value.isinttype()? 1: 2);
|
||||
return 2;
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
@@ -99,10 +107,12 @@ public class CoerceLuaToJava {
|
||||
public Object coerce(LuaValue value) {
|
||||
return new Integer( value.toint() );
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
public int score(int paramType) {
|
||||
switch ( paramType ) {
|
||||
case LuaValue.TINT:
|
||||
return 0;
|
||||
case LuaValue.TNUMBER:
|
||||
return (value.isinttype()? 0: 1);
|
||||
return 1;
|
||||
case LuaValue.TBOOLEAN:
|
||||
case LuaValue.TNIL:
|
||||
return 2;
|
||||
@@ -115,10 +125,12 @@ public class CoerceLuaToJava {
|
||||
public Object coerce(LuaValue value) {
|
||||
return new Long( value.tolong() );
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
public int score(int paramType) {
|
||||
switch ( paramType ) {
|
||||
case LuaValue.TINT:
|
||||
return 1;
|
||||
case LuaValue.TNUMBER:
|
||||
return (value.isinttype()? 1: 2);
|
||||
return 2;
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
@@ -128,8 +140,9 @@ public class CoerceLuaToJava {
|
||||
public Object coerce(LuaValue value) {
|
||||
return new Float( value.tofloat() );
|
||||
}
|
||||
public int score( LuaValue value ) {
|
||||
switch ( value.type() ) {
|
||||
public int score( int paramType ) {
|
||||
switch ( paramType ) {
|
||||
case LuaValue.TINT:
|
||||
case LuaValue.TNUMBER:
|
||||
return 1;
|
||||
case LuaValue.TBOOLEAN:
|
||||
@@ -143,10 +156,12 @@ public class CoerceLuaToJava {
|
||||
public Object coerce(LuaValue value) {
|
||||
return new Double( value.todouble() );
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
public int score(int paramType) {
|
||||
switch ( paramType ) {
|
||||
case LuaValue.TINT:
|
||||
return 1;
|
||||
case LuaValue.TNUMBER:
|
||||
return (value.isinttype()? 1: 0);
|
||||
return 0;
|
||||
case LuaValue.TBOOLEAN:
|
||||
return 2;
|
||||
default:
|
||||
@@ -158,8 +173,8 @@ public class CoerceLuaToJava {
|
||||
public Object coerce(LuaValue value) {
|
||||
return value.tojstring();
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
public int score(int paramType) {
|
||||
switch ( paramType ) {
|
||||
case LuaValue.TUSERDATA:
|
||||
return 0;
|
||||
default:
|
||||
@@ -174,10 +189,10 @@ public class CoerceLuaToJava {
|
||||
return value.optuserdata(Object.class, null);
|
||||
case LuaValue.TSTRING:
|
||||
return value.tojstring();
|
||||
case LuaValue.TINT:
|
||||
return new Integer(value.toint());
|
||||
case LuaValue.TNUMBER:
|
||||
return (value.isinttype()?
|
||||
new Integer(value.toint()):
|
||||
new Double(value.todouble()));
|
||||
return new Double(value.todouble());
|
||||
case LuaValue.TBOOLEAN:
|
||||
return value.toboolean()? Boolean.TRUE: Boolean.FALSE;
|
||||
case LuaValue.TNIL:
|
||||
@@ -186,8 +201,8 @@ public class CoerceLuaToJava {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
public int score(int paramType) {
|
||||
switch ( paramType ) {
|
||||
case LuaValue.TSTRING:
|
||||
return 0;
|
||||
default:
|
||||
@@ -217,21 +232,22 @@ public class CoerceLuaToJava {
|
||||
|
||||
|
||||
/** Score a single parameter, including array handling */
|
||||
private static int scoreParam(LuaValue a, Class c) {
|
||||
if ( a.isuserdata(c) )
|
||||
private static int scoreParam(int paramType, Class c) {
|
||||
if ( paramType == LuaValue.TUSERDATA && !c.isArray() )
|
||||
return 0;
|
||||
Coercion co = (Coercion) COERCIONS.get( c );
|
||||
if ( co != null ) {
|
||||
return co.score( a );
|
||||
int b = LuajavaLib.paramBaseTypeFromParamType(paramType);
|
||||
int d = LuajavaLib.paramDepthFromParamType(paramType);
|
||||
return co.score( b ) * d;
|
||||
}
|
||||
if ( c.isArray() ) {
|
||||
Class typ = c.getComponentType();
|
||||
switch ( a.type() ) {
|
||||
case LuaValue.TTABLE:
|
||||
return scoreParam( a.checktable().get(1), typ );
|
||||
default:
|
||||
return 0x10 + (scoreParam(a, typ) << 8);
|
||||
}
|
||||
int d = LuajavaLib.paramDepthFromParamType(paramType);
|
||||
if ( d > 0 )
|
||||
return scoreParam( LuajavaLib.paramComponentTypeOfParamType(paramType), typ );
|
||||
else
|
||||
return 0x10 + (scoreParam(paramType, typ) << 8);
|
||||
}
|
||||
return 0x1000;
|
||||
}
|
||||
@@ -261,12 +277,11 @@ public class CoerceLuaToJava {
|
||||
throw new LuaError("no coercion found for "+a.getClass()+" to "+c);
|
||||
}
|
||||
|
||||
static Object[] coerceArgs(LuaValue[] suppliedArgs, Class[] parameterTypes) {
|
||||
int nargs = suppliedArgs.length;
|
||||
static Object[] coerceArgs(Varargs suppliedArgs, Class[] parameterTypes) {
|
||||
int n = parameterTypes.length;
|
||||
Object[] args = new Object[n];
|
||||
for ( int i=0; i<n && i<nargs; i++ )
|
||||
args[i] = coerceArg( suppliedArgs[i], parameterTypes[i] );
|
||||
for ( int i=0; i<n; i++ )
|
||||
args[i] = coerceArg( suppliedArgs.arg(i+1), parameterTypes[i] );
|
||||
return args;
|
||||
}
|
||||
|
||||
@@ -278,14 +293,14 @@ public class CoerceLuaToJava {
|
||||
* 3) java has less args
|
||||
* 4) types coerce well
|
||||
*/
|
||||
static int scoreParamTypes(LuaValue[] suppliedArgs, Class[] paramTypes) {
|
||||
int nargs = suppliedArgs.length;
|
||||
static int scoreParamTypes(long paramssig, Class[] paramTypes) {
|
||||
int nargs = LuajavaLib.paramsCountFromSig(paramssig);
|
||||
int njava = paramTypes.length;
|
||||
int score = (njava == nargs? 0: njava > nargs? 0x4000: 0x8000);
|
||||
for ( int i=0; i<nargs && i<njava; i++ ) {
|
||||
LuaValue a = suppliedArgs[i];
|
||||
int paramType = LuajavaLib.paramTypeFromSig(paramssig, i);
|
||||
Class c = paramTypes[i];
|
||||
int s = scoreParam( a, c );
|
||||
int s = scoreParam( paramType, c );
|
||||
score += s;
|
||||
}
|
||||
return score;
|
||||
|
||||
@@ -34,7 +34,6 @@ import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -96,11 +95,11 @@ public class LuajavaLib extends OneArgFunction {
|
||||
// get constructor
|
||||
final LuaValue c = args.checkvalue(1);
|
||||
final Class clazz = (opcode==NEWINSTANCE? Class.forName(c.tojstring()): (Class) c.checkuserdata(Class.class));
|
||||
final ParamsList params = new ParamsList( args );
|
||||
final Constructor con = resolveConstructor( clazz, params );
|
||||
final long paramssig = LuajavaLib.paramsSignatureOf( args );
|
||||
final Constructor con = resolveConstructor( clazz, paramssig );
|
||||
|
||||
// coerce args, construct instance
|
||||
Object[] cargs = CoerceLuaToJava.coerceArgs( params.values, con.getParameterTypes() );
|
||||
Object[] cargs = CoerceLuaToJava.coerceArgs( args, con.getParameterTypes() );
|
||||
Object o = con.newInstance( cargs );
|
||||
|
||||
// return result
|
||||
@@ -177,28 +176,64 @@ public class LuajavaLib extends OneArgFunction {
|
||||
}
|
||||
}
|
||||
|
||||
public static class ParamsList {
|
||||
public final LuaValue[] values;
|
||||
public final Class[] classes;
|
||||
public int hash;
|
||||
ParamsList( Varargs args ) {
|
||||
int n = Math.max(args.narg()-1,0);
|
||||
values = new LuaValue[n];
|
||||
classes = new Class[n];
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
values[i] = args.arg(i+2);
|
||||
classes[i] = values[i].getClass();
|
||||
hash += classes[i].hashCode();
|
||||
// params signature is
|
||||
// - low 6-bits are number of parameters
|
||||
// - each of next 9 6-bit fields encode a parameter type:
|
||||
// - low 4 bits are lua type
|
||||
// - high 2 bits are number of indexes deep (0,1,2, or 3)
|
||||
|
||||
public static long paramsSignatureOf( Varargs args ) {
|
||||
long sig = 0;
|
||||
int narg = args.narg();
|
||||
int n = Math.min( narg, 9 );
|
||||
for ( int i=1; i<=n; i++ ) {
|
||||
LuaValue a = args.arg(i);
|
||||
sig |= (paramTypeOf(a) << (i*6));
|
||||
}
|
||||
return sig | Math.min( narg, 0x3F );
|
||||
}
|
||||
|
||||
public static int paramTypeOf( LuaValue arg ) {
|
||||
int type = arg.type();
|
||||
int tabledepth = 0;
|
||||
if ( type == TTABLE ) {
|
||||
for ( tabledepth=1; (type=(arg=arg.get(1)).type()) == TTABLE && (tabledepth<3); )
|
||||
++tabledepth;
|
||||
}
|
||||
if ( type == TNUMBER && arg.isinttype() )
|
||||
type = TINT;
|
||||
if ( type == TUSERDATA ) {
|
||||
Class c = arg.touserdata().getClass();
|
||||
for ( ; c.isArray() && (tabledepth<3); ) {
|
||||
c = c.getComponentType();
|
||||
++tabledepth;
|
||||
}
|
||||
}
|
||||
public int hashCode() {
|
||||
return hash;
|
||||
}
|
||||
public boolean equals( Object o ) {
|
||||
return ( o instanceof ParamsList )?
|
||||
Arrays.equals( classes, ((ParamsList) o).classes ):
|
||||
false;
|
||||
}
|
||||
return (type & 0xF) | (tabledepth << 4);
|
||||
}
|
||||
|
||||
public static int paramsCountFromSig( long paramssig ) {
|
||||
return ((int) paramssig) & 0x3F;
|
||||
}
|
||||
|
||||
public static int paramTypeFromSig(long paramssig, int argindex) {
|
||||
return ((int) (paramssig>>(6*(argindex+1)))) & 0x3F;
|
||||
}
|
||||
|
||||
public static int paramBaseTypeFromParamType(int paramType) {
|
||||
int t = paramType & 0xf;
|
||||
return t == (TINT & 0xF)? TINT: t;
|
||||
}
|
||||
|
||||
public static int paramDepthFromParamType(int paramType) {
|
||||
return (paramType >> 4) & 0x3;
|
||||
}
|
||||
|
||||
public static int paramComponentTypeOfParamType(int paramType) {
|
||||
int b = paramBaseTypeFromParamType( paramType );
|
||||
int d = paramDepthFromParamType( paramType );
|
||||
d = d>0? d-1: 0;
|
||||
return (d<<4) | (b&0xF);
|
||||
}
|
||||
|
||||
static LuaUserdata toUserdata(Object instance, final Class clazz) {
|
||||
@@ -284,11 +319,12 @@ public class LuajavaLib extends OneArgFunction {
|
||||
try {
|
||||
// find the method
|
||||
Object instance = args.touserdata(1);
|
||||
ParamsList params = new ParamsList( args );
|
||||
Method meth = resolveMethod( clazz, s, params );
|
||||
Varargs methargs = args.subargs(2);
|
||||
long paramssig = LuajavaLib.paramsSignatureOf(methargs);
|
||||
Method meth = resolveMethod( clazz, s, paramssig );
|
||||
|
||||
// coerce the arguments
|
||||
Object[] margs = CoerceLuaToJava.coerceArgs( params.values, meth.getParameterTypes() );
|
||||
Object[] margs = CoerceLuaToJava.coerceArgs( methargs, meth.getParameterTypes() );
|
||||
Object result = meth.invoke( instance, margs );
|
||||
|
||||
// coerce the result
|
||||
@@ -307,7 +343,7 @@ public class LuajavaLib extends OneArgFunction {
|
||||
private static Map consIndex =
|
||||
new HashMap();
|
||||
|
||||
private static Constructor resolveConstructor(Class clazz, ParamsList params ) {
|
||||
private static Constructor resolveConstructor(Class clazz, long paramssig ) {
|
||||
|
||||
// get the cache
|
||||
Map cache = (Map) consCache.get( clazz );
|
||||
@@ -315,7 +351,7 @@ public class LuajavaLib extends OneArgFunction {
|
||||
consCache.put( clazz, cache = new HashMap() );
|
||||
|
||||
// look up in the cache
|
||||
Constructor c = (Constructor) cache.get( params );
|
||||
Constructor c = (Constructor) cache.get( paramssig );
|
||||
if ( c != null )
|
||||
return c;
|
||||
|
||||
@@ -335,7 +371,7 @@ public class LuajavaLib extends OneArgFunction {
|
||||
}
|
||||
|
||||
// figure out best list of arguments == supplied args
|
||||
Integer n = new Integer( params.classes.length );
|
||||
Integer n = new Integer( LuajavaLib.paramsCountFromSig(paramssig) );
|
||||
List list = (List) index.get(n);
|
||||
if ( list == null )
|
||||
throw new IllegalArgumentException("no constructor with "+n+" args");
|
||||
@@ -345,7 +381,8 @@ public class LuajavaLib extends OneArgFunction {
|
||||
int besti = 0;
|
||||
for ( int i=0, size=list.size(); i<size; i++ ) {
|
||||
Constructor con = (Constructor) list.get(i);
|
||||
int s = CoerceLuaToJava.scoreParamTypes(params.values, con.getParameterTypes());
|
||||
int paramType = LuajavaLib.paramTypeFromSig(paramssig, 0);
|
||||
int s = CoerceLuaToJava.scoreParamTypes(paramType, con.getParameterTypes());
|
||||
if ( s < bests ) {
|
||||
bests = s;
|
||||
besti = i;
|
||||
@@ -354,7 +391,7 @@ public class LuajavaLib extends OneArgFunction {
|
||||
|
||||
// put into cache
|
||||
c = (Constructor) list.get(besti);
|
||||
cache.put( params, c );
|
||||
cache.put( paramssig, c );
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -365,7 +402,7 @@ public class LuajavaLib extends OneArgFunction {
|
||||
private static Map methIndex =
|
||||
new HashMap();
|
||||
|
||||
private static Method resolveMethod(Class clazz, String methodName, ParamsList params ) {
|
||||
private static Method resolveMethod(Class clazz, String methodName, long paramssig ) {
|
||||
|
||||
// get the cache
|
||||
Map nameCache = (Map) methCache.get( clazz );
|
||||
@@ -376,7 +413,7 @@ public class LuajavaLib extends OneArgFunction {
|
||||
nameCache.put( methodName, cache = new HashMap() );
|
||||
|
||||
// look up in the cache
|
||||
Method m = (Method) cache.get( params );
|
||||
Method m = (Method) cache.get( paramssig );
|
||||
if ( m != null )
|
||||
return m;
|
||||
|
||||
@@ -403,7 +440,7 @@ public class LuajavaLib extends OneArgFunction {
|
||||
Map map = (Map) index.get(methodName);
|
||||
if ( map == null )
|
||||
throw new IllegalArgumentException("no method named '"+methodName+"'");
|
||||
Integer n = new Integer( params.classes.length );
|
||||
Integer n = new Integer( LuajavaLib.paramsCountFromSig( paramssig ) );
|
||||
List list = (List) map.get(n);
|
||||
if ( list == null )
|
||||
throw new IllegalArgumentException("no method named '"+methodName+"' with "+n+" args");
|
||||
@@ -413,7 +450,7 @@ public class LuajavaLib extends OneArgFunction {
|
||||
int besti = 0;
|
||||
for ( int i=0, size=list.size(); i<size; i++ ) {
|
||||
Method meth = (Method) list.get(i);
|
||||
int s = CoerceLuaToJava.scoreParamTypes(params.values, meth.getParameterTypes());
|
||||
int s = CoerceLuaToJava.scoreParamTypes(paramssig, meth.getParameterTypes());
|
||||
if ( s < bests ) {
|
||||
bests = s;
|
||||
besti = i;
|
||||
@@ -422,7 +459,7 @@ public class LuajavaLib extends OneArgFunction {
|
||||
|
||||
// put into cache
|
||||
m = (Method) list.get(besti);
|
||||
cache.put( params, m );
|
||||
cache.put( paramssig, m );
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user