changeset 408:1b38de2b1845

merge LuanTableImpl into LuanTable
author Franklin Schmidt <fschmidt@gmail.com>
date Wed, 29 Apr 2015 13:15:17 -0600
parents 7fd9f1b7b878
children abce9b0041b0
files core/src/luan/Luan.java core/src/luan/LuanJavaFunction.java core/src/luan/LuanMeta.java core/src/luan/LuanPropertyMeta.java core/src/luan/LuanState.java core/src/luan/LuanTable.java core/src/luan/LuanTableImpl.java
diffstat 7 files changed, 404 insertions(+), 433 deletions(-) [+]
line wrap: on
line diff
diff -r 7fd9f1b7b878 -r 1b38de2b1845 core/src/luan/Luan.java
--- a/core/src/luan/Luan.java	Wed Apr 29 13:01:00 2015 -0600
+++ b/core/src/luan/Luan.java	Wed Apr 29 13:15:17 2015 -0600
@@ -150,11 +150,11 @@
 	}
 
 	public static LuanTable newTable() {
-		return new LuanTableImpl();
+		return new LuanTable();
 	}
 
 	public static LuanTable newTable(List<Object> list) {
-		return new LuanTableImpl(list);
+		return new LuanTable(list);
 	}
 
 	private Luan() {}  // never
diff -r 7fd9f1b7b878 -r 1b38de2b1845 core/src/luan/LuanJavaFunction.java
--- a/core/src/luan/LuanJavaFunction.java	Wed Apr 29 13:01:00 2015 -0600
+++ b/core/src/luan/LuanJavaFunction.java	Wed Apr 29 13:15:17 2015 -0600
@@ -201,7 +201,7 @@
 			for( int i=0; i<a.length; i++ ) {
 				a[i] = Array.get(obj,i);
 			}
-			return new LuanTableImpl(new ArrayList<Object>(Arrays.asList(a)));
+			return new LuanTable(new ArrayList<Object>(Arrays.asList(a)));
 		}
 	};
 
@@ -397,22 +397,22 @@
 			if( obj instanceof List ) {
 				@SuppressWarnings("unchecked")
 				List<Object> list = (List<Object>)obj;
-				return new LuanTableImpl(list);
+				return new LuanTable(list);
 			}
 			if( obj instanceof Map ) {
 				@SuppressWarnings("unchecked")
 				Map<Object,Object> map = (Map<Object,Object>)obj;
-				return new LuanTableImpl(map);
+				return new LuanTable(map);
 			}
 			if( obj instanceof Set ) {
 				@SuppressWarnings("unchecked")
 				Set<Object> set = (Set<Object>)obj;
-				return new LuanTableImpl(set);
+				return new LuanTable(set);
 			}
 			Class cls = obj.getClass();
 			if( cls.isArray() && !cls.getComponentType().isPrimitive() ) {
 				Object[] a = (Object[])obj;
-				return new LuanTableImpl(Arrays.asList(a));
+				return new LuanTable(Arrays.asList(a));
 			}
 			return obj;
 		}
@@ -423,8 +423,8 @@
 
 	private static final ArgConverter ARG_MAP = new ArgConverter() {
 		public Object convert(Object obj) {
-			if( obj instanceof LuanTableImpl ) {
-				LuanTableImpl t = (LuanTableImpl)obj;
+			if( obj instanceof LuanTable ) {
+				LuanTable t = (LuanTable)obj;
 				return t.asMap();
 			}
 			return obj;
@@ -436,8 +436,8 @@
 
 	private static final ArgConverter ARG_LIST = new ArgConverter() {
 		public Object convert(Object obj) {
-			if( obj instanceof LuanTableImpl ) {
-				LuanTableImpl t = (LuanTableImpl)obj;
+			if( obj instanceof LuanTable ) {
+				LuanTable t = (LuanTable)obj;
 				if( t.isList() )
 					return t.asList();
 			}
@@ -450,8 +450,8 @@
 
 	private static final ArgConverter ARG_SET = new ArgConverter() {
 		public Object convert(Object obj) {
-			if( obj instanceof LuanTableImpl ) {
-				LuanTableImpl t = (LuanTableImpl)obj;
+			if( obj instanceof LuanTable ) {
+				LuanTable t = (LuanTable)obj;
 				if( t.isSet() )
 					return t.asSet();
 			}
@@ -464,8 +464,8 @@
 
 	private static final ArgConverter ARG_COLLECTION = new ArgConverter() {
 		public Object convert(Object obj) {
-			if( obj instanceof LuanTableImpl ) {
-				LuanTableImpl t = (LuanTableImpl)obj;
+			if( obj instanceof LuanTable ) {
+				LuanTable t = (LuanTable)obj;
 				if( t.isList() )
 					return t.asList();
 				if( t.isSet() )
@@ -486,8 +486,8 @@
 		}
 
 		public Object convert(Object obj) {
-			if( obj instanceof LuanTableImpl ) {
-				LuanTableImpl t = (LuanTableImpl)obj;
+			if( obj instanceof LuanTable ) {
+				LuanTable t = (LuanTable)obj;
 				if( t.isList() ) {
 					try {
 						return t.asList().toArray(a);
diff -r 7fd9f1b7b878 -r 1b38de2b1845 core/src/luan/LuanMeta.java
--- a/core/src/luan/LuanMeta.java	Wed Apr 29 13:01:00 2015 -0600
+++ b/core/src/luan/LuanMeta.java	Wed Apr 29 13:15:17 2015 -0600
@@ -18,7 +18,7 @@
 	}
 
 	public LuanTable newMetatable() {
-		LuanTable mt = new LuanTableImpl();
+		LuanTable mt = new LuanTable();
 /*
 		try {
 			mt.put( "__index", new LuanJavaFunction(
@@ -41,7 +41,7 @@
 	}
 
 	public LuanTable newTable() {
-		LuanTable tbl = new LuanTableImpl();
+		LuanTable tbl = new LuanTable();
 		tbl.setMetatable( newMetatable() );
 		return tbl;
 	}
diff -r 7fd9f1b7b878 -r 1b38de2b1845 core/src/luan/LuanPropertyMeta.java
--- a/core/src/luan/LuanPropertyMeta.java	Wed Apr 29 13:01:00 2015 -0600
+++ b/core/src/luan/LuanPropertyMeta.java	Wed Apr 29 13:15:17 2015 -0600
@@ -9,8 +9,8 @@
 
 	public static LuanPropertyMeta newInstance() {
 		LuanPropertyMeta meta = new LuanPropertyMeta();
-		meta.getters = new LuanTableImpl();
-		meta.setters = new LuanTableImpl();
+		meta.getters = new LuanTable();
+		meta.setters = new LuanTable();
 		return meta;
 	}
 
diff -r 7fd9f1b7b878 -r 1b38de2b1845 core/src/luan/LuanState.java
--- a/core/src/luan/LuanState.java	Wed Apr 29 13:01:00 2015 -0600
+++ b/core/src/luan/LuanState.java	Wed Apr 29 13:15:17 2015 -0600
@@ -20,10 +20,10 @@
 
 	final List<StackTraceElement> stackTrace = new ArrayList<StackTraceElement>();
 
-	private LuanTableImpl registry;
+	private LuanTable registry;
 
 	protected LuanState() {
-		registry = new LuanTableImpl();
+		registry = new LuanTable();
 	}
 
 	protected LuanState(LuanState luan) {}
@@ -48,7 +48,7 @@
 	}
 
 	public final Object eval(String cmd) throws LuanException {
-		return eval(cmd,new LuanTableImpl());
+		return eval(cmd,new LuanTable());
 	}
 
 	public final Object eval(String cmd,LuanTable env) throws LuanException {
diff -r 7fd9f1b7b878 -r 1b38de2b1845 core/src/luan/LuanTable.java
--- a/core/src/luan/LuanTable.java	Wed Apr 29 13:01:00 2015 -0600
+++ b/core/src/luan/LuanTable.java	Wed Apr 29 13:15:17 2015 -0600
@@ -1,29 +1,388 @@
 package luan;
 
+import java.util.Iterator;
+import java.util.ListIterator;
 import java.util.Map;
+import java.util.AbstractMap;
+import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.Set;
-import java.util.Comparator;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.regex.Pattern;
 
 
-public interface LuanTable extends Iterable<Map.Entry<Object,Object>> {
-	public boolean isEmpty();
-	public boolean isList();
-	public boolean isSet();
-	public Set<Object> asSet();
-	public List<Object> asList();
-	public Map<Object,Object> asMap();
-	public Object get(Object key);
-	public void put(Object key,Object val);
-	public void insert(int pos,Object value);
-	public void add(Object value);
-	public Object remove(int pos);
-	public void sort(Comparator<Object> cmp);
-	public int length();
-	public LuanTable subList(int from,int to);
-	public LuanTable getMetatable();
-	public void setMetatable(LuanTable metatable);
-	public LuanTable cloneTable();
-	public boolean hasJava();
-	public void setJava();
+public final class LuanTable implements Iterable<Map.Entry<Object,Object>>, LuanRepr, DeepCloneable<LuanTable> {
+	private Map<Object,Object> map = null;
+	private List<Object> list = null;
+	private LuanTable metatable = null;
+	private boolean hasJava = false;
+
+	public LuanTable() {}
+
+	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;
+			}
+		}
+	}
+
+	LuanTable(Map<Object,Object> map) {
+		map.remove(null);
+		for( Iterator<Object> i=map.values().iterator(); i.hasNext(); ) {
+			if( i.next() == null )
+				i.remove();
+		}
+		this.map = map;
+	}
+
+	LuanTable(Set<Object> set) {
+		map = newMap();
+		for( Object obj : set ) {
+			if( obj != null )
+				map.put(obj,Boolean.TRUE);
+		}
+	}
+
+	@Override public LuanTable shallowClone() {
+		return new LuanTable();
+	}
+
+	@Override public void deepenClone(LuanTable clone,DeepCloner cloner) {
+		if( map != null ) {
+			clone.map = newMap();
+			for( Map.Entry<Object,Object> entry : map.entrySet() ) {
+				clone.map.put( cloner.get(entry.getKey()), cloner.get(entry.getValue()) );
+			}
+		}
+		if( list != null ) {
+			clone.list = new ArrayList<Object>();
+			for( Object obj : list ) {
+				clone.list.add( cloner.get(obj) );
+			}
+		}
+		if( metatable != null )
+			clone.metatable = cloner.get(metatable);
+		clone.hasJava = hasJava;
+	}
+
+	public boolean isList() {
+		return map==null || map.isEmpty();
+	}
+
+	public List<Object> asList() {
+		return list!=null ? list : Collections.emptyList();
+	}
+
+	private Map<Object,Object> map() {
+		return map!=null ? map : Collections.emptyMap();
+	}
+/*
+	@Override public 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;
+	}
+
+	@Override public 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;
+	}
+*/
+	protected String type() {
+		return "table";
+	}
+
+	public Object get(Object key) {
+		if( list != null ) {
+			Integer iT = Luan.asInteger(key);
+			if( iT != null ) {
+				int i = iT - 1;
+				if( i>=0 && i<list.size() )
+					return list.get(i);
+			}
+		}
+		if( map==null )
+			return null;
+		return map.get(key);
+	}
+
+	public void put(Object key,Object val) {
+		Integer iT = Luan.asInteger(key);
+		if( iT != null ) {
+			int i = iT - 1;
+			if( list != null || i == 0 ) {
+				if( i == list().size() ) {
+					if( val != null ) {
+						list.add(val);
+						mapToList();
+					}
+					return;
+				} else if( i>=0 && i<list.size() ) {
+					list.set(i,val);
+					if( val == null ) {
+						listToMap(i);
+					}
+					return;
+				}
+			}
+		}
+		if( map==null ) {
+			map = newMap();
+		}
+		if( key instanceof Number && !(key instanceof Double) ) {
+			Number n = (Number)key;
+			key = Double.valueOf(n.doubleValue());
+		}
+		if( val == null ) {
+			map.remove(key);
+		} else {
+			map.put(key,val);
+		}
+	}
+
+	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 void listToMap(int from) {
+		if( list != null ) {
+			while( list.size() > from ) {
+				int i = list.size() - 1;
+				Object v = list.remove(i);
+				if( v != null ) {
+					if( map==null )
+						map = newMap();
+					map.put(i+1,v);
+				}
+			}
+		}
+	}
+
+	private List<Object> list() {
+		if( list == null ) {
+			list = new ArrayList<Object>();
+			mapToList();
+		}
+		return list;
+	}
+
+	public void insert(int pos,Object value) {
+		if( value==null )
+			throw new IllegalArgumentException("can't insert a nil value");
+		list().add(pos-1,value);
+		mapToList();
+	}
+
+	public void add(Object value) {
+		if( value==null )
+			throw new IllegalArgumentException("can't add a nil value");
+		list().add(value);
+		mapToList();
+	}
+
+	public Object remove(int pos) {
+		return list().remove(pos-1);
+	}
+
+	public void sort(Comparator<Object> cmp) {
+		Collections.sort(list(),cmp);
+	}
+
+	public int length() {
+		return list==null ? 0 : list.size();
+	}
+
+	@Override public Iterator<Map.Entry<Object,Object>> iterator() {
+		if( list == null ) {
+			if( map == null )
+				return Collections.<Map.Entry<Object,Object>>emptyList().iterator();
+			return map.entrySet().iterator();
+		}
+		if( map == null )
+			return listIterator();
+		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 ) {
+					iter = map.entrySet().iterator();
+					isList = false;
+					b = iter.hasNext();
+				}
+				return b;
+			}
+			public Map.Entry<Object,Object> next() {
+				return iter.next();
+			}
+			public void remove() {
+				throw new UnsupportedOperationException();
+			}
+		};
+	}
+
+	private Iterator<Map.Entry<Object,Object>> listIterator() {
+		if( list == null )
+			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);
+				return new AbstractMap.SimpleEntry<Object,Object>(key,iter.next());
+			}
+			public void remove() {
+				throw new UnsupportedOperationException();
+			}
+		};
+	}
+
+	public LuanTable subList(int from,int to) {
+		LuanTable tbl = shallowClone();
+		tbl.list = new ArrayList<Object>(list().subList(from-1,to-1));
+		return tbl;
+	}
+
+	public LuanTable getMetatable() {
+		return metatable;
+	}
+
+	public void setMetatable(LuanTable metatable) {
+		this.metatable = metatable;
+	}
+
+	public boolean hasJava() {
+		return hasJava;
+	}
+
+	public void setJava() {
+		hasJava = true;
+	}
+
+
+	// from AbstractLuanTable
+
+	protected final Map<Object,Object> newMap() {
+		return new LinkedHashMap<Object,Object>();
+	}
+
+	public boolean isEmpty() {
+		return isList() && length()==0;
+	}
+
+	public boolean isSet() {
+		for( Map.Entry<Object,Object> entry : this ) {
+			if( !entry.getValue().equals(Boolean.TRUE) )
+				return false;
+		}
+		return true;
+	}
+
+	public Set<Object> asSet() {
+		Set<Object> set = new HashSet<Object>();
+		for( Map.Entry<Object,Object> entry : this ) {
+			set.add(entry.getKey());
+		}
+		return set;
+	}
+
+	public Map<Object,Object> asMap() {
+		Map<Object,Object> map = newMap();
+		for( Map.Entry<Object,Object> entry : this ) {
+			map.put(entry.getKey(),entry.getValue());
+		}
+		return map;
+	}
+
+	public LuanTable cloneTable() {
+		return isList() ? new LuanTable(new ArrayList<Object>(asList())) : new LuanTable(asMap());
+	}
+
+	@Override public String repr() {
+		return repr( Collections.newSetFromMap(new IdentityHashMap<LuanTable,Boolean>()) );
+	}
+
+	private String repr(Set<LuanTable> set) {
+		if( !set.add(this) ) {
+			return "\"<circular reference>\"";
+		}
+		StringBuilder sb = new StringBuilder();
+		sb.append('{');
+		boolean isFirst = true;
+		for( Object obj : asList() ) {
+			if( isFirst ) {
+				isFirst = false;
+			} else {
+				sb.append(", ");
+			}
+			sb.append(repr(set,obj));
+		}
+		for( Map.Entry<Object,Object> entry : map().entrySet() ) {
+			if( isFirst ) {
+				isFirst = false;
+			} else {
+				sb.append(", ");
+			}
+			sb.append(reprKey(set,entry.getKey())).append('=').append(repr(set,entry.getValue()));
+		}
+		sb.append('}');
+		return sb.toString();
+	}
+
+	private static final Pattern namePtn = Pattern.compile("[a-zA-Z_][a-zA-Z_0-9]*");
+
+	private String reprKey(Set<LuanTable> set,Object obj) {
+		if( obj instanceof String ) {
+			String s = (String)obj;
+			if( namePtn.matcher(s).matches() )
+				return s;
+		}
+		return "[" + repr(set,obj) + "]";
+	}
+
+	String repr(Set<LuanTable> set,Object obj) {
+		if( obj instanceof LuanTable ) {
+			LuanTable t = (LuanTable)obj;
+			return t.repr(set);
+		} else {
+			String s = Luan.repr(obj);
+			if( s == null )
+				s = "<couldn't repr: " + Luan.stringEncode(Luan.toString(obj)) + ">";
+			return s;
+		}
+	}
+
 }
diff -r 7fd9f1b7b878 -r 1b38de2b1845 core/src/luan/LuanTableImpl.java
--- a/core/src/luan/LuanTableImpl.java	Wed Apr 29 13:01:00 2015 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,388 +0,0 @@
-package luan;
-
-import java.util.Iterator;
-import java.util.ListIterator;
-import java.util.Map;
-import java.util.AbstractMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Set;
-import java.util.HashSet;
-import java.util.IdentityHashMap;
-import java.util.regex.Pattern;
-
-
-class LuanTableImpl implements LuanTable, LuanRepr, DeepCloneable<LuanTableImpl> {
-	private Map<Object,Object> map = null;
-	private List<Object> list = null;
-	private LuanTable metatable = null;
-	private boolean hasJava = false;
-
-	public LuanTableImpl() {}
-
-	LuanTableImpl(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;
-			}
-		}
-	}
-
-	LuanTableImpl(Map<Object,Object> map) {
-		map.remove(null);
-		for( Iterator<Object> i=map.values().iterator(); i.hasNext(); ) {
-			if( i.next() == null )
-				i.remove();
-		}
-		this.map = map;
-	}
-
-	LuanTableImpl(Set<Object> set) {
-		map = newMap();
-		for( Object obj : set ) {
-			if( obj != null )
-				map.put(obj,Boolean.TRUE);
-		}
-	}
-
-	@Override public LuanTableImpl shallowClone() {
-		return new LuanTableImpl();
-	}
-
-	@Override public void deepenClone(LuanTableImpl clone,DeepCloner cloner) {
-		if( map != null ) {
-			clone.map = newMap();
-			for( Map.Entry<Object,Object> entry : map.entrySet() ) {
-				clone.map.put( cloner.get(entry.getKey()), cloner.get(entry.getValue()) );
-			}
-		}
-		if( list != null ) {
-			clone.list = new ArrayList<Object>();
-			for( Object obj : list ) {
-				clone.list.add( cloner.get(obj) );
-			}
-		}
-		if( metatable != null )
-			clone.metatable = cloner.get(metatable);
-		clone.hasJava = hasJava;
-	}
-
-	@Override public boolean isList() {
-		return map==null || map.isEmpty();
-	}
-
-	@Override public List<Object> asList() {
-		return list!=null ? list : Collections.emptyList();
-	}
-
-	protected Map<Object,Object> map() {
-		return map!=null ? map : Collections.emptyMap();
-	}
-/*
-	@Override public 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;
-	}
-
-	@Override public 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;
-	}
-*/
-	protected String type() {
-		return "table";
-	}
-
-	@Override public Object get(Object key) {
-		if( list != null ) {
-			Integer iT = Luan.asInteger(key);
-			if( iT != null ) {
-				int i = iT - 1;
-				if( i>=0 && i<list.size() )
-					return list.get(i);
-			}
-		}
-		if( map==null )
-			return null;
-		return map.get(key);
-	}
-
-	@Override public void put(Object key,Object val) {
-		Integer iT = Luan.asInteger(key);
-		if( iT != null ) {
-			int i = iT - 1;
-			if( list != null || i == 0 ) {
-				if( i == list().size() ) {
-					if( val != null ) {
-						list.add(val);
-						mapToList();
-					}
-					return;
-				} else if( i>=0 && i<list.size() ) {
-					list.set(i,val);
-					if( val == null ) {
-						listToMap(i);
-					}
-					return;
-				}
-			}
-		}
-		if( map==null ) {
-			map = newMap();
-		}
-		if( key instanceof Number && !(key instanceof Double) ) {
-			Number n = (Number)key;
-			key = Double.valueOf(n.doubleValue());
-		}
-		if( val == null ) {
-			map.remove(key);
-		} else {
-			map.put(key,val);
-		}
-	}
-
-	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 void listToMap(int from) {
-		if( list != null ) {
-			while( list.size() > from ) {
-				int i = list.size() - 1;
-				Object v = list.remove(i);
-				if( v != null ) {
-					if( map==null )
-						map = newMap();
-					map.put(i+1,v);
-				}
-			}
-		}
-	}
-
-	private List<Object> list() {
-		if( list == null ) {
-			list = new ArrayList<Object>();
-			mapToList();
-		}
-		return list;
-	}
-
-	@Override public void insert(int pos,Object value) {
-		if( value==null )
-			throw new IllegalArgumentException("can't insert a nil value");
-		list().add(pos-1,value);
-		mapToList();
-	}
-
-	@Override public void add(Object value) {
-		if( value==null )
-			throw new IllegalArgumentException("can't add a nil value");
-		list().add(value);
-		mapToList();
-	}
-
-	@Override public Object remove(int pos) {
-		return list().remove(pos-1);
-	}
-
-	@Override public void sort(Comparator<Object> cmp) {
-		Collections.sort(list(),cmp);
-	}
-
-	@Override public int length() {
-		return list==null ? 0 : list.size();
-	}
-
-	@Override public Iterator<Map.Entry<Object,Object>> iterator() {
-		if( list == null ) {
-			if( map == null )
-				return Collections.<Map.Entry<Object,Object>>emptyList().iterator();
-			return map.entrySet().iterator();
-		}
-		if( map == null )
-			return listIterator();
-		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 ) {
-					iter = map.entrySet().iterator();
-					isList = false;
-					b = iter.hasNext();
-				}
-				return b;
-			}
-			public Map.Entry<Object,Object> next() {
-				return iter.next();
-			}
-			public void remove() {
-				throw new UnsupportedOperationException();
-			}
-		};
-	}
-
-	private Iterator<Map.Entry<Object,Object>> listIterator() {
-		if( list == null )
-			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);
-				return new AbstractMap.SimpleEntry<Object,Object>(key,iter.next());
-			}
-			public void remove() {
-				throw new UnsupportedOperationException();
-			}
-		};
-	}
-
-	@Override public LuanTable subList(int from,int to) {
-		LuanTableImpl tbl = shallowClone();
-		tbl.list = new ArrayList<Object>(list().subList(from-1,to-1));
-		return tbl;
-	}
-
-	@Override public LuanTable getMetatable() {
-		return metatable;
-	}
-
-	@Override public void setMetatable(LuanTable metatable) {
-		this.metatable = metatable;
-	}
-
-	@Override public boolean hasJava() {
-		return hasJava;
-	}
-
-	@Override public void setJava() {
-		hasJava = true;
-	}
-
-
-	// from AbstractLuanTable
-
-	protected final Map<Object,Object> newMap() {
-		return new LinkedHashMap<Object,Object>();
-	}
-
-	@Override public boolean isEmpty() {
-		return isList() && length()==0;
-	}
-
-	@Override public boolean isSet() {
-		for( Map.Entry<Object,Object> entry : this ) {
-			if( !entry.getValue().equals(Boolean.TRUE) )
-				return false;
-		}
-		return true;
-	}
-
-	@Override public Set<Object> asSet() {
-		Set<Object> set = new HashSet<Object>();
-		for( Map.Entry<Object,Object> entry : this ) {
-			set.add(entry.getKey());
-		}
-		return set;
-	}
-
-	@Override public Map<Object,Object> asMap() {
-		Map<Object,Object> map = newMap();
-		for( Map.Entry<Object,Object> entry : this ) {
-			map.put(entry.getKey(),entry.getValue());
-		}
-		return map;
-	}
-
-	@Override public LuanTable cloneTable() {
-		return isList() ? new LuanTableImpl(new ArrayList<Object>(asList())) : new LuanTableImpl(asMap());
-	}
-
-	@Override public String repr() {
-		return repr( Collections.newSetFromMap(new IdentityHashMap<LuanTableImpl,Boolean>()) );
-	}
-
-	private String repr(Set<LuanTableImpl> set) {
-		if( !set.add(this) ) {
-			return "\"<circular reference>\"";
-		}
-		StringBuilder sb = new StringBuilder();
-		sb.append('{');
-		boolean isFirst = true;
-		for( Object obj : asList() ) {
-			if( isFirst ) {
-				isFirst = false;
-			} else {
-				sb.append(", ");
-			}
-			sb.append(repr(set,obj));
-		}
-		for( Map.Entry<Object,Object> entry : map().entrySet() ) {
-			if( isFirst ) {
-				isFirst = false;
-			} else {
-				sb.append(", ");
-			}
-			sb.append(reprKey(set,entry.getKey())).append('=').append(repr(set,entry.getValue()));
-		}
-		sb.append('}');
-		return sb.toString();
-	}
-
-	private static final Pattern namePtn = Pattern.compile("[a-zA-Z_][a-zA-Z_0-9]*");
-
-	private String reprKey(Set<LuanTableImpl> set,Object obj) {
-		if( obj instanceof String ) {
-			String s = (String)obj;
-			if( namePtn.matcher(s).matches() )
-				return s;
-		}
-		return "[" + repr(set,obj) + "]";
-	}
-
-	String repr(Set<LuanTableImpl> set,Object obj) {
-		if( obj instanceof LuanTableImpl ) {
-			LuanTableImpl t = (LuanTableImpl)obj;
-			return t.repr(set);
-		} else {
-			String s = Luan.repr(obj);
-			if( s == null )
-				s = "<couldn't repr: " + Luan.stringEncode(Luan.toString(obj)) + ">";
-			return s;
-		}
-	}
-
-}