Mercurial Hosting > luan
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; - } - } - -}