diff core/src/luan/LuanTable.java @ 432:d9df6d6cb927

finish fixing LuanTable to use metatables
author Franklin Schmidt <fschmidt@gmail.com>
date Sat, 02 May 2015 23:41:59 -0600
parents 3ffe8ba5b297
children c6bcb8859b93
line wrap: on
line diff
--- a/core/src/luan/LuanTable.java	Sat May 02 21:12:48 2015 -0600
+++ b/core/src/luan/LuanTable.java	Sat May 02 23:41:59 2015 -0600
@@ -15,7 +15,7 @@
 import java.util.regex.Pattern;
 
 
-public final class LuanTable implements Iterable<Map.Entry<Object,Object>>, DeepCloneable<LuanTable> {
+public final class LuanTable implements DeepCloneable<LuanTable> {
 	private Map<Object,Object> map = null;
 	private List<Object> list = null;
 	private LuanTable metatable = null;
@@ -24,21 +24,34 @@
 	public LuanTable() {}
 
 	public LuanTable(List<Object> list) {
-		this.list = list;
-		this.map = newMap();
-		map.put("n",list.size());
-		for( int i=0; i<list.size(); i++ ) {
-			if( list.get(i) == null ) {
-				listToMap(i);
-				break;
-			}
+		int n = list.size();
+		for( int i=0; i<n; i++ ) {
+			Object val = list.get(i);
+			if( val != null )
+				rawPut(i+1,val);
+		}
+	}
+
+	public LuanTable(Map<Object,Object> map) {
+		for( Map.Entry<Object,Object> entry : map.entrySet() ) {
+			Object key = entry.getKey();
+			Object value = entry.getValue();
+			if( key != null && value != null )
+				rawPut(key,value);
+		}
+	}
+
+	public LuanTable(Set<Object> set) {
+		for( Object el : set ) {
+			if( el != null )
+				rawPut(el,Boolean.TRUE);
 		}
 	}
 
 	public LuanTable(LuanTable tbl) {
 		if( tbl.map != null && !tbl.map.isEmpty() )
 			this.map = new LinkedHashMap<Object,Object>(tbl.map);
-		if( tbl.length() > 0 )
+		if( tbl.rawLength() > 0 )
 			this.list = new ArrayList<Object>(tbl.list);
 		this.metatable = tbl.metatable;
 	}
@@ -223,13 +236,6 @@
 		mapToList();
 	}
 
-	public void rawAdd(Object value) {
-		if( value==null )
-			throw new IllegalArgumentException("can't add a nil value");
-		list().add(value);
-		mapToList();
-	}
-
 	public Object rawRemove(int pos) {
 		return list().remove(pos-1);
 	}
@@ -238,11 +244,97 @@
 		Collections.sort(list(),cmp);
 	}
 
-	public int length() {
+	public int length(LuanState luan) throws LuanException {
+		Object h = getHandler("__len");
+		if( h != null ) {
+			LuanFunction fn = luan.checkFunction(h);
+			return (Integer)Luan.first(luan.call(fn,"__len",new Object[]{this}));
+		}
+		return rawLength();
+	}
+
+	public int rawLength() {
 		return list==null ? 0 : list.size();
 	}
 
-	@Override public Iterator<Map.Entry<Object,Object>> iterator() {
+	public Iterable<Map.Entry<Object,Object>> iterable(LuanState luan) throws LuanException {
+		final Iterator<Map.Entry<Object,Object>> iter = iterator(luan);
+		return new Iterable<Map.Entry<Object,Object>>() {
+			public Iterator<Map.Entry<Object,Object>> iterator() {
+				return iter;
+			}
+		};
+	}
+
+	public Iterator<Map.Entry<Object,Object>> iterator(final LuanState luan) throws LuanException {
+		if( getHandler("__pairs") == null )
+			return rawIterator();
+		final LuanFunction fn = pairs(luan);
+		return new Iterator<Map.Entry<Object,Object>>() {
+			private Map.Entry<Object,Object> next = getNext();
+
+			private Map.Entry<Object,Object> getNext() {
+				try {
+					Object obj = luan.call(fn);
+					if( obj==null )
+						return null;
+					Object[] a = (Object[])obj;
+					if( a.length == 0 )
+						return null;
+					return new AbstractMap.SimpleEntry<Object,Object>(a[0],a[1]);
+				} catch(LuanException e) {
+					throw new LuanRuntimeException(e);
+				}
+			}
+
+			public boolean hasNext() {
+				return next != null;
+			}
+
+			public Map.Entry<Object,Object> next() {
+				Map.Entry<Object,Object> rtn = next;
+				next = getNext();
+				return rtn;
+			}
+
+			public void remove() {
+				throw new UnsupportedOperationException();
+			}
+		};
+	}
+
+	public LuanFunction pairs(final LuanState luan) throws LuanException {
+		Object h = getHandler("__pairs");
+		if( h != null ) {
+			if( h instanceof LuanFunction ) {
+				Object obj = Luan.first(luan.call((LuanFunction)h,"__pairs",new Object[]{this}));
+				if( !(obj instanceof LuanFunction) )
+					throw luan.exception( "metamethod __pairs should return function but returned " + Luan.type(obj) );
+				return (LuanFunction)obj;
+			}
+			if( h instanceof LuanMeta ) {
+				LuanMeta meta = (LuanMeta)h;
+				return meta.__pairs(luan,this);
+			}
+			throw luan.exception( "invalid type of metamethod __pairs: " + Luan.type(h) );
+		}
+		return rawPairs();
+	}
+
+	private LuanFunction rawPairs() {
+		return new LuanFunction() {
+			final Iterator<Map.Entry<Object,Object>> iter = rawIterator();
+
+			@Override public Object[] call(LuanState luan,Object[] args) {
+				if( !iter.hasNext() )
+					return LuanFunction.NOTHING;
+				Map.Entry<Object,Object> entry = iter.next();
+				return new Object[]{entry.getKey(),entry.getValue()};
+			}
+		};
+	}
+
+	public Iterator<Map.Entry<Object,Object>> rawIterator() {
 		if( list == null ) {
 			if( map == null )
 				return Collections.<Map.Entry<Object,Object>>emptyList().iterator();
@@ -253,6 +345,7 @@
 		return new Iterator<Map.Entry<Object,Object>>() {
 			Iterator<Map.Entry<Object,Object>> iter = listIterator();
 			boolean isList = true;
+
 			public boolean hasNext() {
 				boolean b = iter.hasNext();
 				if( !b && isList ) {
@@ -262,9 +355,11 @@
 				}
 				return b;
 			}
+
 			public Map.Entry<Object,Object> next() {
 				return iter.next();
 			}
+
 			public void remove() {
 				throw new UnsupportedOperationException();
 			}
@@ -276,13 +371,16 @@
 			return Collections.<Map.Entry<Object,Object>>emptyList().iterator();
 		final ListIterator iter = list.listIterator();
 		return new Iterator<Map.Entry<Object,Object>>() {
+
 			public boolean hasNext() {
 				return iter.hasNext();
 			}
+
 			public Map.Entry<Object,Object> next() {
-				Double key = Double.valueOf(iter.nextIndex()+1);
+				Integer key = iter.nextIndex()+1;
 				return new AbstractMap.SimpleEntry<Object,Object>(key,iter.next());
 			}
+
 			public void remove() {
 				throw new UnsupportedOperationException();
 			}
@@ -304,8 +402,7 @@
 	}
 
 	public Object getHandler(String op) {
-		LuanTable t = getMetatable();
-		return t==null ? null : t.rawGet(op);
+		return metatable==null ? null : metatable.rawGet(op);
 	}
 
 	public boolean hasJava() {
@@ -323,25 +420,25 @@
 		return new LinkedHashMap<Object,Object>();
 	}
 
-	public boolean isSet() {
-		for( Map.Entry<Object,Object> entry : this ) {
+	public boolean isSet(LuanState luan) throws LuanException {
+		for( Map.Entry<Object,Object> entry : iterable(luan) ) {
 			if( !entry.getValue().equals(Boolean.TRUE) )
 				return false;
 		}
 		return true;
 	}
 
-	public Set<Object> asSet() {
+	public Set<Object> asSet(LuanState luan) throws LuanException {
 		Set<Object> set = new HashSet<Object>();
-		for( Map.Entry<Object,Object> entry : this ) {
+		for( Map.Entry<Object,Object> entry : iterable(luan) ) {
 			set.add(entry.getKey());
 		}
 		return set;
 	}
 
-	public Map<Object,Object> asMap() {
+	public Map<Object,Object> asMap(LuanState luan) throws LuanException {
 		Map<Object,Object> map = newMap();
-		for( Map.Entry<Object,Object> entry : this ) {
+		for( Map.Entry<Object,Object> entry : iterable(luan) ) {
 			map.put(entry.getKey(),entry.getValue());
 		}
 		return map;