diff src/luan/LuaJavaFunction.java @ 1:2df768b926aa

start Luan git-svn-id: https://luan-java.googlecode.com/svn/trunk@2 21e917c8-12df-6dd8-5cb6-c86387c605b9
author fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9>
date Tue, 13 Nov 2012 05:54:32 +0000
parents
children 4da26b11d12a
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/LuaJavaFunction.java	Tue Nov 13 05:54:32 2012 +0000
@@ -0,0 +1,209 @@
+package luan;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+
+
+public final class LuaJavaFunction extends LuaFunction {
+	private final Method method;
+	private final Object obj;
+	private final RtnConverter rtnConverter;
+	private final ArgConverter[] argConverters;
+
+	public LuaJavaFunction(Method method,Object obj) {
+		this.method = method;
+		this.obj = obj;
+		rtnConverter = getRtnConverter(method);
+		argConverters = getArgConverters(method);
+	}
+
+	public Object[] call(Object... args) {
+		args = fixArgs(args);
+		Object rtn;
+		try {
+			rtn = method.invoke(obj,args);
+		} catch(IllegalAccessException e) {
+			throw new RuntimeException(e);
+		} catch(InvocationTargetException e) {
+			throw new RuntimeException(e);
+		}
+		return rtnConverter.convert(rtn);
+	}
+
+	private Object[] fixArgs(Object[] args) {
+		if( args.length != argConverters.length ) {
+			Object[] t = new Object[argConverters.length];
+			System.arraycopy(args,0,t,0,Math.min(args.length,t.length));
+			args = t;
+		}
+		for( int i=0; i<args.length; i++ ) {
+			args[i] = argConverters[i].convert(args[i]);
+		}
+		return args;
+	}
+
+
+	private interface RtnConverter {
+		public Object[] convert(Object obj);
+	}
+
+	private static final Object[] EMPTY = new Object[0];
+
+	private static final RtnConverter RTN_EMPTY = new RtnConverter() {
+		public Object[] convert(Object obj) {
+			return EMPTY;
+		}
+	};
+
+	private static final RtnConverter RTN_SAME = new RtnConverter() {
+		public Object[] convert(Object obj) {
+			return new Object[]{obj};
+		}
+	};
+
+	private static final RtnConverter RTN_NUMBER = new RtnConverter() {
+		public Object[] convert(Object obj) {
+			if( obj == null )
+				return new Object[1];
+			Number n = (Number)obj;
+			LuaNumber ln = new LuaNumber(n.doubleValue());
+			return new Object[]{ln};
+		}
+	};
+
+	private static RtnConverter getRtnConverter(Method m) {
+		Class<?> rtnType = m.getReturnType();
+		if( rtnType == Void.TYPE )
+			return RTN_EMPTY;
+		if( Number.class.isAssignableFrom(rtnType)
+			|| rtnType == Short.TYPE
+			|| rtnType == Integer.TYPE
+			|| rtnType == Long.TYPE
+			|| rtnType == Float.TYPE
+			|| rtnType == Double.TYPE
+		)
+			return RTN_NUMBER;
+		return RTN_SAME;
+	}
+
+
+	private interface ArgConverter {
+		public Object convert(Object obj);
+	}
+
+	private static final ArgConverter ARG_SAME = new ArgConverter() {
+		public Object convert(Object obj) {
+			return obj;
+		}
+	};
+
+	private static final ArgConverter ARG_DOUBLE = new ArgConverter() {
+		public Object convert(Object obj) {
+			if( obj instanceof LuaNumber ) {
+				LuaNumber ln = (LuaNumber)obj;
+				return Double.valueOf(ln.n);
+			}
+			if( obj instanceof String ) {
+				String s = (String)obj;
+				try {
+					return Double.valueOf(s);
+				} catch(NumberFormatException e) {}
+			}
+			return obj;
+		}
+	};
+
+	private static final ArgConverter ARG_FLOAT = new ArgConverter() {
+		public Object convert(Object obj) {
+			if( obj instanceof LuaNumber ) {
+				LuaNumber ln = (LuaNumber)obj;
+				return Float.valueOf((float)ln.n);
+			}
+			if( obj instanceof String ) {
+				String s = (String)obj;
+				try {
+					return Float.valueOf(s);
+				} catch(NumberFormatException e) {}
+			}
+			return obj;
+		}
+	};
+
+	private static final ArgConverter ARG_LONG = new ArgConverter() {
+		public Object convert(Object obj) {
+			if( obj instanceof LuaNumber ) {
+				LuaNumber ln = (LuaNumber)obj;
+				long i = (long)ln.n;
+				if( i == ln.n )
+					return Long.valueOf(i);
+			}
+			else if( obj instanceof String ) {
+				String s = (String)obj;
+				try {
+					return Long.valueOf(s);
+				} catch(NumberFormatException e) {}
+			}
+			return obj;
+		}
+	};
+
+	private static final ArgConverter ARG_INTEGER = new ArgConverter() {
+		public Object convert(Object obj) {
+			if( obj instanceof LuaNumber ) {
+				LuaNumber ln = (LuaNumber)obj;
+				int i = (int)ln.n;
+				if( i == ln.n )
+					return Integer.valueOf(i);
+			}
+			else if( obj instanceof String ) {
+				String s = (String)obj;
+				try {
+					return Integer.valueOf(s);
+				} catch(NumberFormatException e) {}
+			}
+			return obj;
+		}
+	};
+
+	private static final ArgConverter ARG_SHORT = new ArgConverter() {
+		public Object convert(Object obj) {
+			if( obj instanceof LuaNumber ) {
+				LuaNumber ln = (LuaNumber)obj;
+				short i = (short)ln.n;
+				if( i == ln.n )
+					return Short.valueOf(i);
+			}
+			else if( obj instanceof String ) {
+				String s = (String)obj;
+				try {
+					return Short.valueOf(s);
+				} catch(NumberFormatException e) {}
+			}
+			return obj;
+		}
+	};
+
+	private static ArgConverter[] getArgConverters(Method m) {
+		Class<?>[] paramTypes = m.getParameterTypes();
+		ArgConverter[] a = new ArgConverter[paramTypes.length];
+		for( int i=0; i<a.length; i++ ) {
+			a[i] = getArgConverter(paramTypes[i]);
+		}
+		return a;
+	}
+
+	private static ArgConverter getArgConverter(Class<?> cls) {
+		if( cls == Double.TYPE || cls.equals(Double.class) )
+			return ARG_DOUBLE;
+		if( cls == Float.TYPE || cls.equals(Float.class) )
+			return ARG_FLOAT;
+		if( cls == Long.TYPE || cls.equals(Long.class) )
+			return ARG_LONG;
+		if( cls == Integer.TYPE || cls.equals(Integer.class) )
+			return ARG_INTEGER;
+		if( cls == Short.TYPE || cls.equals(Short.class) )
+			return ARG_SHORT;
+		return ARG_SAME;
+	}
+
+}