changeset 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 a89d06646ff3
children 4da26b11d12a
files src/luan/Lua.java src/luan/LuaException.java src/luan/LuaFunction.java src/luan/LuaJavaFunction.java src/luan/LuaNumber.java src/luan/LuaTable.java
diffstat 6 files changed, 359 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/Lua.java	Tue Nov 13 05:54:32 2012 +0000
@@ -0,0 +1,56 @@
+package luan;
+
+
+public class Lua {
+
+	public static String toString(Object obj) {
+		if( obj == null )
+			return "nil";
+		return obj.toString();
+	}
+
+	public static String type(Object obj) {
+		if( obj == null )
+			return "nil";
+		if( obj instanceof String )
+			return "string";
+		if( obj instanceof Boolean )
+			return "boolean";
+		if( obj instanceof LuaNumber )
+			return "number";
+		return "userdata";
+	}
+
+	public static int length(Object obj) throws LuaException {
+		if( obj instanceof String ) {
+			String s = (String)obj;
+			return s.length();
+		}
+		if( obj instanceof LuaTable ) {
+			LuaTable t = (LuaTable)obj;
+			return t.length();
+		}
+		throw new LuaException( "attempt to get length of a " + type(obj) + " value" );
+	}
+
+	static LuaNumber toNumber(Object obj) throws LuaException {
+		if( obj instanceof LuaNumber )
+			return (LuaNumber)obj;
+		if( obj instanceof String ) {
+			String s = (String)obj;
+			try {
+				return new LuaNumber( Double.parseDouble(s) );
+			} catch(NumberFormatException e) {}
+		}
+		throw new LuaException( "attempt to perform arithmetic on a " + type(obj) + " value" );
+	}
+
+	static LuaNumber add(Object n1,Object n2) throws LuaException {
+		return new LuaNumber( toNumber(n1).n + toNumber(n2).n );
+	}
+
+	static LuaNumber sub(Object n1,Object n2) throws LuaException {
+		return new LuaNumber( toNumber(n1).n - toNumber(n2).n );
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/LuaException.java	Tue Nov 13 05:54:32 2012 +0000
@@ -0,0 +1,10 @@
+package luan;
+
+
+public class LuaException extends Exception {
+
+	LuaException(String msg) {
+		super(msg);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/LuaFunction.java	Tue Nov 13 05:54:32 2012 +0000
@@ -0,0 +1,12 @@
+package luan;
+
+
+public abstract class LuaFunction {
+
+	public abstract Object[] call(Object... args);
+
+	@Override public String toString() {
+		return "function: " + Integer.toHexString(hashCode());
+	}
+
+}
--- /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;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/LuaNumber.java	Tue Nov 13 05:54:32 2012 +0000
@@ -0,0 +1,38 @@
+package luan;
+
+
+public class LuaNumber {
+	final double n;
+
+	public LuaNumber(double n) {
+		this.n = n;
+	}
+
+	// convert to Lua format
+	@Override public String toString() {
+		String s = Double.toString(n);
+		int iE = s.indexOf('E');
+		String ending  = null;
+		if( iE != -1 ) {
+			ending = s.substring(iE);
+			s = s.substring(0,iE);
+		}
+		if( s.endsWith(".0") )
+			s = s.substring(0,s.length()-2);
+		if( ending != null )
+			s += ending;
+		return s;
+	}
+
+	@Override public boolean equals(Object obj) {
+		if( !(obj instanceof LuaNumber) )
+			return false;
+		LuaNumber ln = (LuaNumber)obj;
+		return n == ln.n;
+	}
+
+	@Override public int hashCode() {
+		return Double.valueOf(n).hashCode();
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/LuaTable.java	Tue Nov 13 05:54:32 2012 +0000
@@ -0,0 +1,34 @@
+package luan;
+
+import java.util.Map;
+import java.util.HashMap;
+
+
+public class LuaTable {
+	private final Map<Object,Object> map = new HashMap<Object,Object>();
+
+	@Override public String toString() {
+		return "table: " + Integer.toHexString(hashCode());
+	}
+
+	public Object get(Object key) {
+		return map.get(key);
+	}
+
+	public void set(Object key,Object val) {
+		if( val == null ) {
+			map.remove(key);
+		} else {
+			map.put(key,val);
+		}
+	}
+
+	public int length() {
+		int i = 0;
+		while( map.containsKey( new LuaNumber(i) ) ) {
+			i++;
+		}
+		return i;
+	}
+
+}