changeset 47:659c7139e903

better conversion git-svn-id: https://luan-java.googlecode.com/svn/trunk@48 21e917c8-12df-6dd8-5cb6-c86387c605b9
author fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9>
date Thu, 27 Dec 2012 04:36:44 +0000
parents a443637829c1
children 64ecb7a3aad7
files src/luan/LuaJavaFunction.java src/luan/LuaTable.java
diffstat 2 files changed, 352 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/src/luan/LuaJavaFunction.java	Thu Dec 27 01:48:36 2012 +0000
+++ b/src/luan/LuaJavaFunction.java	Thu Dec 27 04:36:44 2012 +0000
@@ -4,6 +4,9 @@
 import java.lang.reflect.Method;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 
 public final class LuaJavaFunction extends LuaFunction {
@@ -45,6 +48,9 @@
 		Object rtn;
 		try {
 			rtn = method.invoke(obj,args);
+		} catch(IllegalArgumentException e) {
+			checkArgs(lua,args);
+			throw e;
 		} catch(IllegalAccessException e) {
 			throw new RuntimeException(e);
 		} catch(InvocationTargetException e) {
@@ -62,6 +68,19 @@
 		return rtnConverter.convert(rtn);
 	}
 
+	private void checkArgs(LuaState lua,Object[] args) throws LuaException {
+		Class<?>[] a = getParameterTypes();
+		for( int i=0; i<a.length; i++ ) {
+			if( !a[i].isInstance(args[i]) ) {
+				String got = args[i].getClass().getName();
+				String expected = a[i].getName();
+				if( !takesLuaState )
+					i++;
+				throw new LuaException(lua,LuaElement.JAVA,"bad argument #"+i+" ("+expected+" expected, got "+got+")");
+			}
+		}
+	}
+
 	private Object[] fixArgs(LuaState lua,Object[] args) {
 		int n = argConverters.length;
 		Object[] rtn;
@@ -125,16 +144,40 @@
 
 	private static final Object[] NULL_RTN = new Object[1];
 
+	private static final RtnConverter RTN_NUMBER_ARRAY = new RtnConverter() {
+		public Object[] convert(Object obj) {
+			if( obj == null )
+				return NULL_RTN;
+			Object[] rtn = new Object[Array.getLength(obj)];
+			for( int i=0; i<rtn.length; i++ ) {
+				rtn[i] = Array.get(obj,i);
+			}
+			return rtn;
+		}
+	};
+
 	private static RtnConverter getRtnConverter(JavaMethod m) {
 		Class<?> rtnType = m.getReturnType();
 		if( rtnType == Void.TYPE )
 			return RTN_EMPTY;
 		if( rtnType.isArray() ) {
+			rtnType = rtnType.getComponentType();
+			if( isNumber(rtnType) )
+				return RTN_NUMBER_ARRAY;
 			return RTN_ARRAY;
 		}
 		return RTN_ONE;
 	}
 
+	private static boolean isNumber(Class<?> rtnType) {
+		return rtnType == Byte.TYPE
+			|| rtnType == Short.TYPE
+			|| rtnType == Integer.TYPE
+			|| rtnType == Long.TYPE
+			|| rtnType == Float.TYPE
+			|| rtnType == Double.TYPE
+		;
+	}
 
 	private interface ArgConverter {
 		public Object convert(Object obj);
@@ -146,6 +189,177 @@
 		}
 	};
 
+	private static final ArgConverter ARG_DOUBLE = new ArgConverter() {
+		public Object convert(Object obj) {
+			if( obj instanceof Double )
+				return obj;
+			if( obj instanceof Number ) {
+				Number n = (Number)obj;
+				return n.doubleValue();
+			}
+			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 Float )
+				return obj;
+			if( obj instanceof Number ) {
+				Number n = (Number)obj;
+				float r = n.floatValue();
+				if( r==n.doubleValue() )
+					return r;
+			}
+			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 Long )
+				return obj;
+			if( obj instanceof Number ) {
+				Number n = (Number)obj;
+				long r = n.longValue();
+				if( r==n.doubleValue() )
+					return r;
+			}
+			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 Integer )
+				return obj;
+			if( obj instanceof Number ) {
+				Number n = (Number)obj;
+				int r = n.intValue();
+				if( r==n.doubleValue() )
+					return r;
+			}
+			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 Short )
+				return obj;
+			if( obj instanceof Number ) {
+				Number n = (Number)obj;
+				short r = n.shortValue();
+				if( r==n.doubleValue() )
+					return r;
+			}
+			else if( obj instanceof String ) {
+				String s = (String)obj;
+				try {
+					return Short.valueOf(s);
+				} catch(NumberFormatException e) {}
+			}
+			return obj;
+		}
+	};
+
+	private static final ArgConverter ARG_BYTE = new ArgConverter() {
+		public Object convert(Object obj) {
+			if( obj instanceof Byte )
+				return obj;
+			if( obj instanceof Number ) {
+				Number n = (Number)obj;
+				byte r = n.byteValue();
+				if( r==n.doubleValue() )
+					return r;
+			}
+			else if( obj instanceof String ) {
+				String s = (String)obj;
+				try {
+					return Byte.valueOf(s);
+				} catch(NumberFormatException e) {}
+			}
+			return obj;
+		}
+	};
+
+	private static final ArgConverter ARG_TABLE = new ArgConverter() {
+		public Object convert(Object obj) {
+			if( obj instanceof List ) {
+				@SuppressWarnings("unchecked")
+				List<Object> list = (List<Object>)obj;
+				return new LuaTable(list);
+			}
+			if( obj instanceof Map ) {
+				@SuppressWarnings("unchecked")
+				Map<Object,Object> map = (Map<Object,Object>)obj;
+				return new LuaTable(map);
+			}
+			if( obj instanceof Set ) {
+				@SuppressWarnings("unchecked")
+				Set<Object> set = (Set<Object>)obj;
+				return new LuaTable(set);
+			}
+			return obj;
+		}
+	};
+
+	private static final ArgConverter ARG_MAP = new ArgConverter() {
+		public Object convert(Object obj) {
+			if( obj instanceof LuaTable ) {
+				LuaTable t = (LuaTable)obj;
+				return t.asMap();
+			}
+			return obj;
+		}
+	};
+
+	private static final ArgConverter ARG_LIST = new ArgConverter() {
+		public Object convert(Object obj) {
+			if( obj instanceof LuaTable ) {
+				LuaTable t = (LuaTable)obj;
+				if( t.isList() )
+					return t.asList();
+			}
+			return obj;
+		}
+	};
+
+	private static final ArgConverter ARG_SET = new ArgConverter() {
+		public Object convert(Object obj) {
+			if( obj instanceof LuaTable ) {
+				LuaTable t = (LuaTable)obj;
+				if( t.isSet() )
+					return t.asSet();
+			}
+			return obj;
+		}
+	};
+
 	private static boolean takesLuaState(JavaMethod m) {
 		Class<?>[] paramTypes = m.getParameterTypes();
 		return paramTypes.length > 0 && paramTypes[0].equals(LuaState.class);
@@ -170,6 +384,26 @@
 	}
 
 	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;
+		if( cls == Byte.TYPE || cls.equals(Byte.class) )
+			return ARG_BYTE;
+		if( cls.equals(LuaTable.class) )
+			return ARG_TABLE;
+		if( cls.equals(Map.class) )
+			return ARG_MAP;
+		if( cls.equals(List.class) )
+			return ARG_LIST;
+		if( cls.equals(Set.class) )
+			return ARG_SET;
 		return ARG_SAME;
 	}
 
--- a/src/luan/LuaTable.java	Thu Dec 27 01:48:36 2012 +0000
+++ b/src/luan/LuaTable.java	Thu Dec 27 04:36:44 2012 +0000
@@ -8,6 +8,8 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.Set;
+import java.util.HashSet;
 
 
 public class LuaTable {
@@ -21,8 +23,97 @@
 		this.list = list;
 	}
 
+	public LuaTable(Map<Object,Object> map) {
+		this.map = map;
+	}
+
+	public LuaTable(Set<Object> set) {
+		map = new HashMap<Object,Object>();
+		for( Object obj : set ) {
+			map.put(obj,Boolean.TRUE);
+		}
+	}
+
+	boolean isList() {
+		return map==null || map.isEmpty();
+	}
+
+	List<Object> asList() {
+		return list!=null ? list : Collections.emptyList();
+	}
+
+	Map<Object,Object> asMap() {
+		if( list == null || list.isEmpty() )
+			return map!=null ? map : Collections.emptyMap();
+		Map<Object,Object> rtn = map!=null ? new HashMap<Object,Object>(map) : new HashMap<Object,Object>();
+		for( ListIterator iter = list.listIterator(); iter.hasNext(); ) {
+			int i = iter.nextIndex();
+			rtn.put(i+1,iter.next());
+		}
+		return rtn;
+	}
+
+	boolean isSet() {
+		if( list != null ) {
+			for( Object obj : list ) {
+				if( obj!=null && !obj.equals(Boolean.TRUE) )
+					return false;
+			}
+		}
+		if( map != null ) {
+			for( Object obj : map.values() ) {
+				if( !obj.equals(Boolean.TRUE) )
+					return false;
+			}
+		}
+		return true;
+	}
+
+	Set<Object> asSet() {
+		if( list == null || list.isEmpty() )
+			return map!=null ? map.keySet() : Collections.emptySet();
+		Set<Object> rtn = map!=null ? new HashSet<Object>(map.keySet()) : new HashSet<Object>();
+		for( int i=1; i<=list.size(); i++ ) {
+			rtn.add(i);
+		}
+		return rtn;
+	}
+
 	@Override public String toString() {
-		return "table: " + Integer.toHexString(hashCode());
+//		return "table: " + Integer.toHexString(hashCode());
+		StringBuilder sb = new StringBuilder();
+		sb.append('{');
+		boolean isFirst = true;
+		if( list != null ) {
+			boolean gotNull = false;
+			for( int i=0; i<list.size(); i++ ) {
+				Object obj = list.get(i);
+				if( obj==null ) {
+					gotNull = true;
+				} else {
+					if( isFirst ) {
+						isFirst = false;
+					} else {
+						sb.append(", ");
+					}
+					if( gotNull )
+						sb.append(i+1).append('=');
+					sb.append(obj);
+				}
+			}
+		}
+		if( map != null ) {
+			for( Map.Entry<Object,Object> entry : map.entrySet() ) {
+				if( isFirst ) {
+					isFirst = false;
+				} else {
+					sb.append(", ");
+				}
+				sb.append(entry.getKey()).append('=').append(entry.getValue());
+			}
+		}
+		sb.append('}');
+		return sb.toString();
 	}
 
 	public Object get(Object key) {
@@ -43,20 +134,11 @@
 		Integer iT = Lua.asInteger(key);
 		if( iT != null ) {
 			int i = iT - 1;
-			if( list == null && i == 0 )
-				list = new ArrayList<Object>();
-			if( list != null ) {
-				if( i == list.size() ) {
+			if( list != null || i == 0 ) {
+				if( i == list().size() ) {
 					if( val != null ) {
 						list.add(val);
-						if( map != null ) {
-							while(true) {
-								Object v = map.remove(Double.valueOf(list.size()+1));
-								if( v == null )
-									break;
-								list.add(v);
-							}
-						}
+						mapToList();
 					}
 					return null;
 				} else if( i>=0 && i<list.size() ) {
@@ -85,21 +167,35 @@
 		}
 	}
 
+	private void mapToList() {
+		if( map != null ) {
+			while(true) {
+				Object v = map.remove(Double.valueOf(list.size()+1));
+				if( v == null )
+					break;
+				list.add(v);
+			}
+		}
+	}
+
+	private List<Object> list() {
+		if( list == null ) {
+			list = new ArrayList<Object>();
+			mapToList();
+		}
+		return list;
+	}
+
 	public void insert(int pos,Object value) {
-		if( list == null )
-			list = new ArrayList<Object>();
-		list.add(pos-1,value);
+		list().add(pos-1,value);
 	}
 
 	public Object remove(int pos) {
-		if( list == null )
-			list = new ArrayList<Object>();
-		return list.remove(pos-1);
+		return list().remove(pos-1);
 	}
 
 	public void sort(Comparator<Object> cmp) {
-		if( list != null )
-			Collections.sort(list,cmp);
+		Collections.sort(list(),cmp);
 	}
 
 	public int length() {
@@ -158,9 +254,7 @@
 	}
 
 	public LuaTable subList(int from,int to) {
-		if( list == null )
-			list = new ArrayList<Object>();
-		return new LuaTable(new ArrayList<Object>(list.subList(from-1,to-1)));
+		return new LuaTable(new ArrayList<Object>(list().subList(from-1,to-1)));
 	}
 
 	public LuaTable getMetatable() {