changeset 1562:b89212fd04b5

remove table.luan
author Franklin Schmidt <fschmidt@gmail.com>
date Sun, 08 Nov 2020 16:50:59 -0700
parents e1a13e707bf3
children 8fbcc4747091
files src/luan/Luan.java src/luan/LuanException.java src/luan/LuanTable.java src/luan/host/WebHandler.java src/luan/impl/Compiled.java src/luan/impl/LuanImpl.java src/luan/impl/LuanParser.java src/luan/modules/BasicLuan.java src/luan/modules/Boot.luan src/luan/modules/IoLuan.java src/luan/modules/JavaLuan.java src/luan/modules/PackageLuan.java src/luan/modules/StringLuan.java src/luan/modules/TableLuan.java src/luan/modules/ThreadLuan.java src/luan/modules/http/LuanDomainHandler.java src/luan/modules/http/LuanHandler.java src/luan/modules/lucene/LuceneIndex.java src/luan/modules/lucene/PostgresBackup.java src/luan/modules/lucene/SupplementingConfig.java src/luan/modules/parsers/Css.java src/luan/modules/parsers/Csv.java src/luan/modules/parsers/Html.java src/luan/modules/parsers/LuanParser.java src/luan/modules/parsers/LuanToString.java src/luan/modules/parsers/Xml.java
diffstat 26 files changed, 216 insertions(+), 237 deletions(-) [+]
line wrap: on
line diff
diff -r e1a13e707bf3 -r b89212fd04b5 src/luan/Luan.java
--- a/src/luan/Luan.java	Thu Nov 05 20:24:09 2020 -0700
+++ b/src/luan/Luan.java	Sun Nov 08 16:50:59 2020 -0700
@@ -93,7 +93,7 @@
 	public Object index(Object obj,Object key) throws LuanException {
 		if( obj instanceof LuanTable ) {
 			LuanTable tbl = (LuanTable)obj;
-			return tbl.get(key);
+			return tbl.get(this,key);
 		}
 		if( obj != null && peek().javaOk )
 			return JavaLuan.__index(this,obj,key);
@@ -140,13 +140,13 @@
 		if( obj instanceof LuanTable )
 			return (LuanTable)obj;
 		if( obj instanceof List ) {
-			return new LuanTable(this,(List)obj);
+			return new LuanTable((List)obj);
 		}
 		if( obj instanceof Map ) {
-			return new LuanTable(this,(Map)obj);
+			return new LuanTable((Map)obj);
 		}
 		if( obj instanceof Set ) {
-			return new LuanTable(this,(Set)obj);
+			return new LuanTable((Set)obj);
 		}
 		Class cls = obj.getClass();
 		if( cls.isArray() ) {
@@ -156,10 +156,10 @@
 				for( int i=0; i<len; i++ ) {
 					list.add(Array.get(obj,i));
 				}
-				return new LuanTable(this,list);
+				return new LuanTable(list);
 			} else {
 				Object[] a = (Object[])obj;
-				return new LuanTable(this,Arrays.asList(a));
+				return new LuanTable(Arrays.asList(a));
 			}
 		}
 		return null;
diff -r e1a13e707bf3 -r b89212fd04b5 src/luan/LuanException.java
--- a/src/luan/LuanException.java	Thu Nov 05 20:24:09 2020 -0700
+++ b/src/luan/LuanException.java	Sun Nov 08 16:50:59 2020 -0700
@@ -44,7 +44,7 @@
 		if( table == null ) {
 			extra.put(key,value);
 		} else {
-			table.put(key,value);
+			table.rawPut(key,value);
 		}
 	}
 
@@ -52,10 +52,10 @@
 		if( table==null ) {
 			try {
 				LuanTable Boot = (LuanTable)luan.require("luan:Boot.luan");
-				table = (LuanTable)Boot.fn("new_error_table").call(this );
+				table = (LuanTable)Boot.fn(luan,"new_error_table").call(this );
 				for( Object stupid : extra.entrySet() ) {
 					Map.Entry entry = (Map.Entry)stupid;
-					table.put( entry.getKey(), entry.getValue() );
+					table.put( luan, entry.getKey(), entry.getValue() );
 				}
 			} catch(LuanException e) {
 				throw new RuntimeException(e);
diff -r e1a13e707bf3 -r b89212fd04b5 src/luan/LuanTable.java
--- a/src/luan/LuanTable.java	Thu Nov 05 20:24:09 2020 -0700
+++ b/src/luan/LuanTable.java	Sun Nov 08 16:50:59 2020 -0700
@@ -14,51 +14,55 @@
 
 
 public final class LuanTable implements LuanCloneable {
-	private Luan luan;
 	private Map map = null;
 	private List list = null;
 	private LuanTable metatable = null;
 	public LuanClosure closure;
 	private LuanCloner cloner;
-	private String security = null;
 	private boolean immutable = false;
 
-	public LuanTable(Luan luan) {
-		this.luan = luan;
-	}
+	public LuanTable() {}
 
-	public LuanTable(Luan luan,List list) {
-		this.luan = luan;
-		list();
-		int n = list.size();
-		for( int i=0; i<n; i++ ) {
-			Object val = list.get(i);
-			if( val != null )
-				rawPut2(i+1,val);
+	public LuanTable(List list) {
+		try {
+			list();
+			int n = list.size();
+			for( int i=0; i<n; i++ ) {
+				Object val = list.get(i);
+				if( val != null )
+					rawPut(i+1,val);
+			}
+		} catch(LuanException e) {
+			throw new RuntimeException(e);
 		}
 	}
 
-	public LuanTable(Luan luan,Map map) {
-		this.luan = luan;
-		for( Object stupid : map.entrySet() ) {
-			Map.Entry entry = (Map.Entry)stupid;
-			Object key = entry.getKey();
-			Object value = entry.getValue();
-			if( key != null && value != null )
-				rawPut2(key,value);
+	public LuanTable(Map map) {
+		try {
+			for( Object stupid : map.entrySet() ) {
+				Map.Entry entry = (Map.Entry)stupid;
+				Object key = entry.getKey();
+				Object value = entry.getValue();
+				if( key != null && value != null )
+					rawPut(key,value);
+			}
+		} catch(LuanException e) {
+			throw new RuntimeException(e);
 		}
 	}
 
-	public LuanTable(Luan luan,Set set) {
-		this.luan = luan;
-		for( Object el : set ) {
-			if( el != null )
-				rawPut2(el,Boolean.TRUE);
+	public LuanTable(Set set) {
+		try {
+			for( Object el : set ) {
+				if( el != null )
+					rawPut(el,Boolean.TRUE);
+			}
+		} catch(LuanException e) {
+			throw new RuntimeException(e);
 		}
 	}
 
 	public LuanTable(LuanTable tbl) {
-		this.luan = tbl.luan;
 		if( tbl.map != null && !tbl.map.isEmpty() )
 			this.map = new LinkedHashMap<Object,Object>(tbl.map);
 		if( tbl.rawLength() > 0 )
@@ -68,13 +72,12 @@
 
 	@Override public LuanTable shallowClone() {
 		if(immutable) throw new RuntimeException();
-		return new LuanTable(luan);
+		return new LuanTable();
 	}
 
 	@Override public void deepenClone(LuanCloneable dc,LuanCloner cloner) {
 		check();
 		LuanTable clone = (LuanTable)dc;
-		clone.security = security;
 		switch( cloner.type ) {
 		case COMPLETE:
 			completeClone(clone,cloner);
@@ -96,13 +99,7 @@
 		}
 	}
 
-	public Luan luan() {
-		check();
-		return luan;
-	}
-
 	private void completeClone(LuanTable clone,LuanCloner cloner) {
-		clone.luan = (Luan)cloner.clone(luan);
 		clone.map = cloner.clone(map);
 		clone.list = (List)cloner.clone(list);
 		clone.metatable = (LuanTable)cloner.clone(metatable);
@@ -111,7 +108,6 @@
 
 	@Override public void makeImmutable(LuanImmutabler immutabler) throws LuanException {
 		check();
-		immutabler.makeImmutable(luan);
 		immutabler.makeImmutable(map);
 		immutabler.makeImmutable(list);
 		immutabler.makeImmutable(metatable);
@@ -149,7 +145,7 @@
 		return "table: " + Integer.toHexString(hashCode());
 	}
 
-	public Object get(Object key) throws LuanException {
+	public Object get(Luan luan,Object key) throws LuanException {
 		Object value = rawGet(key);
 		if( value != null )
 			return value;
@@ -182,7 +178,7 @@
 		return map.get(key);
 	}
 
-	public void put(Object key,Object value) throws LuanException {
+	public void put(Luan luan,Object key,Object value) throws LuanException {
 		Object h = getHandler("__new_index");
 		if( h==null || rawGet(key)!=null ) {
 			rawPut(key,value);
@@ -195,7 +191,7 @@
 		}
 		if( h instanceof LuanTable ) {
 			LuanTable tbl = (LuanTable)h;
-			tbl.put(key,value);
+			tbl.put(luan,key,value);
 			return;
 		}
 		throw new LuanException("invalid type "+Luan.type(h)+" for metamethod __new_index");
@@ -204,12 +200,6 @@
 	public Object rawPut(Object key,Object val) throws LuanException {
 		if( immutable )
 			throw new LuanException("table is immutable");
-		if( security != null )
-			Luan.checkSecurity(luan,"table",security,"put",key,val);
-		return rawPut2(key,val);
-	}
-
-	private Object rawPut2(Object key,Object val) {
 		check();
 		Integer iT = Luan.asInteger(key);
 		if( iT != null ) {
@@ -458,7 +448,7 @@
 
 	public LuanTable rawSubList(int from,int to) {
 		check();
-		LuanTable tbl = new LuanTable(luan);
+		LuanTable tbl = new LuanTable();
 		tbl.list = new ArrayList<Object>(list().subList(from-1,to-1));
 		return tbl;
 	}
@@ -469,15 +459,13 @@
 	}
 
 	public void setMetatable(LuanTable metatable) throws LuanException {
-		if( security != null )
-			Luan.checkSecurity(luan,"table",security,"set_metatable",metatable);
 		check();
 		this.metatable = metatable;
 	}
 
 	public Object getHandler(String op) throws LuanException {
 		check();
-		return metatable==null ? null : metatable.get(op);
+		return metatable==null ? null : metatable.rawGet(op);
 	}
 
 	private static Map<Object,Object> newMap() {
@@ -540,7 +528,7 @@
 		if( immutable )
 			throw new LuanException("table is immutable");
 		Object old = rawGet(key);
-		rawPut2(key,null);
+		rawPut(key,null);
 		return old;
 	}
 
@@ -553,12 +541,8 @@
 		super.finalize();
 	}
 
-	public LuanFunction fn(String fnName) throws LuanException {
-		return (LuanFunction)get(fnName);
-	}
-
-	public static void setSecurity(LuanTable tbl,String security) {
-		tbl.security = security;
+	public LuanFunction fn(Luan luan,String fnName) throws LuanException {
+		return (LuanFunction)get(luan,fnName);
 	}
 
 	public static void debug(LuanTable table) {
diff -r e1a13e707bf3 -r b89212fd04b5 src/luan/host/WebHandler.java
--- a/src/luan/host/WebHandler.java	Thu Nov 05 20:24:09 2020 -0700
+++ b/src/luan/host/WebHandler.java	Sun Nov 08 16:50:59 2020 -0700
@@ -59,9 +59,9 @@
 		return domainHandler.handle(request);
 	}
 
-	public static Object callSite(String domain,String fnName,Object... args) throws LuanException {
+	public static Object callSite(Luan luan,String domain,String fnName,Object... args) throws LuanException {
 		LuanHandler luanHandler = (LuanHandler)domainHandler.getHandler(domain);
-		return luanHandler.call_rpc(fnName,args);
+		return luanHandler.call_rpc(luan,fnName,args);
 	}
 
 	private static void initLuan(Luan luan,String dir,String domain) {
diff -r e1a13e707bf3 -r b89212fd04b5 src/luan/impl/Compiled.java
--- a/src/luan/impl/Compiled.java	Thu Nov 05 20:24:09 2020 -0700
+++ b/src/luan/impl/Compiled.java	Sun Nov 08 16:50:59 2020 -0700
@@ -133,7 +133,7 @@
 	}
 
 
-	private static final int VERSION = 4;
+	private static final int VERSION = 5;
 	private static final File tmpDir;
 	static {
 		File f = new File(System.getProperty("java.io.tmpdir"));
diff -r e1a13e707bf3 -r b89212fd04b5 src/luan/impl/LuanImpl.java
--- a/src/luan/impl/LuanImpl.java	Thu Nov 05 20:24:09 2020 -0700
+++ b/src/luan/impl/LuanImpl.java	Sun Nov 08 16:50:59 2020 -0700
@@ -158,7 +158,7 @@
 	public static void put(Luan luan,Object t,Object key,Object value) throws LuanException {
 		if( t instanceof LuanTable ) {
 			LuanTable tbl = (LuanTable)t;
-			tbl.put(key,value);
+			tbl.put(luan,key,value);
 			return;
 		}
 		if( t != null && luan.peek().javaOk )
@@ -228,8 +228,8 @@
 		}
 	}
 
-	public static LuanTable table(Luan luan,Object[] a) throws LuanException {
-		LuanTable table = new LuanTable(luan);
+	public static LuanTable table(Object[] a) throws LuanException {
+		LuanTable table = new LuanTable();
 		int i = 0;
 		for( Object fld : a ) {
 			if( fld instanceof TableField ) {
diff -r e1a13e707bf3 -r b89212fd04b5 src/luan/impl/LuanParser.java
--- a/src/luan/impl/LuanParser.java	Thu Nov 05 20:24:09 2020 -0700
+++ b/src/luan/impl/LuanParser.java	Sun Nov 08 16:50:59 2020 -0700
@@ -1192,7 +1192,7 @@
 		if( !parser.match('{') )
 			return parser.failure(null);
 		Expr tblExp = new Expr(Val.SINGLE,false);
-		tblExp.add( "LuanImpl.table(luan," );
+		tblExp.add( "LuanImpl.table(" );
 		Expr lastExp = tblExp;
 		List<Expr> builder = new ArrayList<Expr>();
 		do {
diff -r e1a13e707bf3 -r b89212fd04b5 src/luan/modules/BasicLuan.java
--- a/src/luan/modules/BasicLuan.java	Thu Nov 05 20:24:09 2020 -0700
+++ b/src/luan/modules/BasicLuan.java	Sun Nov 08 16:50:59 2020 -0700
@@ -218,8 +218,8 @@
 		}
 	}
 
-	public static String stringify(Object obj,LuanTable options,LuanTable subOptions) throws LuanException {
-		LuanToString lts = new LuanToString(options,subOptions);
+	public static String stringify(Luan luan,Object obj,LuanTable options,LuanTable subOptions) throws LuanException {
+		LuanToString lts = new LuanToString(luan,options,subOptions);
 		return lts.toString(obj);
 	}
 
diff -r e1a13e707bf3 -r b89212fd04b5 src/luan/modules/Boot.luan
--- a/src/luan/modules/Boot.luan	Thu Nov 05 20:24:09 2020 -0700
+++ b/src/luan/modules/Boot.luan	Sun Nov 08 16:50:59 2020 -0700
@@ -87,7 +87,7 @@
 end
 
 local schemes = {}
-LuanTable.setSecurity(schemes,"schemes")
+--LuanTable.setSecurity(schemes,"schemes")
 
 function schemes.null(path)
 	return new_LuanIO( IoLuan.nullIO )
diff -r e1a13e707bf3 -r b89212fd04b5 src/luan/modules/IoLuan.java
--- a/src/luan/modules/IoLuan.java	Thu Nov 05 20:24:09 2020 -0700
+++ b/src/luan/modules/IoLuan.java	Sun Nov 08 16:50:59 2020 -0700
@@ -428,7 +428,7 @@
 			File[] files = file.listFiles();
 			if( files==null )
 				return null;
-			LuanTable list = new LuanTable(luan);
+			LuanTable list = new LuanTable();
 			for( File f : files ) {
 				list.rawPut(list.rawLength()+1,new LuanFile(luan,f));
 			}
@@ -630,22 +630,22 @@
 	}
 
 	public static LuanTable my_ips(Luan luan) throws IOException, LuanException {
-		LuanTable tbl = new LuanTable(luan);
+		LuanTable tbl = new LuanTable();
 		for( Enumeration<NetworkInterface> e1 = NetworkInterface.getNetworkInterfaces(); e1.hasMoreElements(); ) {
 			NetworkInterface ni = e1.nextElement();
 			for( Enumeration<InetAddress> e2 = ni.getInetAddresses(); e2.hasMoreElements(); ) {
 				InetAddress ia = e2.nextElement();
 				if( ia instanceof Inet4Address )
-					tbl.put(ia.getHostAddress(),true);
+					tbl.put(luan,ia.getHostAddress(),true);
 			}
 		}
 		return tbl;
 	}
 
-	public static LuanTable dns_lookup(Luan luan,String domain,String type)
+	public static LuanTable dns_lookup(String domain,String type)
 		throws NamingException
 	{
-		LuanTable tbl = new LuanTable(luan);
+		LuanTable tbl = new LuanTable();
 		InitialDirContext idc = new InitialDirContext();
 		Attribute attribute;
 		try {
diff -r e1a13e707bf3 -r b89212fd04b5 src/luan/modules/JavaLuan.java
--- a/src/luan/modules/JavaLuan.java	Thu Nov 05 20:24:09 2020 -0700
+++ b/src/luan/modules/JavaLuan.java	Sun Nov 08 16:50:59 2020 -0700
@@ -302,7 +302,7 @@
 			return cls.isSynthetic();
 		}
 
-		public Object luan_proxy(final LuanTable t) throws LuanException {
+		public Object luan_proxy(Luan luan,final LuanTable t) throws LuanException {
 			return Proxy.newProxyInstance(
 				cls.getClassLoader(),
 				new Class[]{cls},
@@ -313,7 +313,7 @@
 						if( args==null )
 							args = new Object[0];
 						String name = method.getName();
-						Object fnObj = t.get(name);
+						Object fnObj = t.get(luan,name);
 						if( fnObj == null )
 							throw new NullPointerException("luan_proxy couldn't find method '"+name+"'");
 						LuanFunction fn = Luan.checkFunction(fnObj);
@@ -326,7 +326,7 @@
 	private static final Method luan_proxyMethod;
 	static {
 		try {
-			luan_proxyMethod = Static.class.getMethod("luan_proxy",LuanTable.class);
+			luan_proxyMethod = Static.class.getMethod("luan_proxy",Luan.class,LuanTable.class);
 			luan_proxyMethod.setAccessible(true);
 		} catch(NoSuchMethodException e) {
 			throw new RuntimeException(e);
diff -r e1a13e707bf3 -r b89212fd04b5 src/luan/modules/PackageLuan.java
--- a/src/luan/modules/PackageLuan.java	Thu Nov 05 20:24:09 2020 -0700
+++ b/src/luan/modules/PackageLuan.java	Sun Nov 08 16:50:59 2020 -0700
@@ -32,7 +32,7 @@
 	public static LuanTable loaded(Luan luan) {
 		LuanTable tbl = (LuanTable)luan.registry().get("Package.loaded");
 		if( tbl == null ) {
-			tbl = new LuanTable(luan);
+			tbl = new LuanTable();
 			luan.registry().put("Package.loaded",tbl);
 		}
 		return tbl;
@@ -103,7 +103,7 @@
 		}
 		Luan.Security security = Luan.setSecurity(luan,null);
 		try {
-			return (String)Luan.first(boot.fn("read").call(uri));
+			return (String)Luan.first(boot.fn(luan,"read").call(uri));
 		} catch(LuanException e) {
 			return null;
 		} finally {
diff -r e1a13e707bf3 -r b89212fd04b5 src/luan/modules/StringLuan.java
--- a/src/luan/modules/StringLuan.java	Thu Nov 05 20:24:09 2020 -0700
+++ b/src/luan/modules/StringLuan.java	Sun Nov 08 16:50:59 2020 -0700
@@ -145,7 +145,7 @@
 		};
 	}
 
-	public static Object[] gsub(String s,String pattern,Object repl,Integer n) throws LuanException {
+	public static Object[] gsub(Luan luan,String s,String pattern,Object repl,Integer n) throws LuanException {
 		Utils.checkNotNull(s);
 		int max = n==null ? Integer.MAX_VALUE : n;
 		final Matcher m = Pattern.compile(pattern).matcher(s);
@@ -166,7 +166,7 @@
 			StringBuffer sb = new StringBuffer();
 			while( i<max && m.find() ) {
 				String match = m.groupCount()==0 ? m.group() : m.group(1);
-				Object val = t.get(match);
+				Object val = t.get(luan,match);
 				if( val != null ) {
 					String replacement = Luan.luanToString(val);
 					m.appendReplacement(sb,replacement);
diff -r e1a13e707bf3 -r b89212fd04b5 src/luan/modules/TableLuan.java
--- a/src/luan/modules/TableLuan.java	Thu Nov 05 20:24:09 2020 -0700
+++ b/src/luan/modules/TableLuan.java	Sun Nov 08 16:50:59 2020 -0700
@@ -13,12 +13,12 @@
 
 public final class TableLuan {
 
-	public static String concat(LuanTable list,String sep,Integer i,Integer j) throws LuanException {
+	public static String concat(Luan luan,LuanTable list,String sep,Integer i,Integer j) throws LuanException {
 		int first = i==null ? 1 : i;
 		int last = j==null ? list.length() : j;
 		StringBuilder buf = new StringBuilder();
 		for( int k=first; k<=last; k++ ) {
-			Object val = list.get(k);
+			Object val = list.get(luan,k);
 			if( val==null )
 				break;
 			if( sep!=null && k > first )
@@ -82,24 +82,24 @@
 		}
 	}
 
-	public static LuanTable pack(Luan luan,Object... args) throws LuanException {
-		LuanTable tbl = new LuanTable(luan,Arrays.asList(args));
+	public static LuanTable pack(Object... args) throws LuanException {
+		LuanTable tbl = new LuanTable(Arrays.asList(args));
 		tbl.rawPut( "n", args.length );
 		return tbl;
 	}
 
-	public static Object[] unpack(LuanTable tbl,Integer iFrom,Integer iTo) throws LuanException {
+	public static Object[] unpack(Luan luan,LuanTable tbl,Integer iFrom,Integer iTo) throws LuanException {
 		int from = iFrom!=null ? iFrom : 1;
 		int to;
 		if( iTo != null ) {
 			to = iTo;
 		} else {
-			Integer n = Luan.asInteger( tbl.get("n") );
+			Integer n = Luan.asInteger( tbl.get(luan,"n") );
 			to = n!=null ? n : tbl.length();
 		}
 		List<Object> list = new ArrayList<Object>();
 		for( int i=from; i<=to; i++ ) {
-			list.add( tbl.get(i) );
+			list.add( tbl.get(luan,i) );
 		}
 		return list.toArray();
 	}
diff -r e1a13e707bf3 -r b89212fd04b5 src/luan/modules/ThreadLuan.java
--- a/src/luan/modules/ThreadLuan.java	Thu Nov 05 20:24:09 2020 -0700
+++ b/src/luan/modules/ThreadLuan.java	Sun Nov 08 16:50:59 2020 -0700
@@ -157,17 +157,17 @@
 		}
 	}
 
-	private static Object makeSafe(Luan luan,Object v) throws LuanException {
+	private static Object makeSafe(Object v) throws LuanException {
 		if( v instanceof LuanTable ) {
 			LuanTable tbl = (LuanTable)v;
 			if( tbl.getMetatable() != null )
 				return new Unsafe("table with metatable");
-			LuanTable rtn = new LuanTable(luan);
+			LuanTable rtn = new LuanTable();
 			for( Map.Entry entry : tbl.rawIterable() ) {
-				Object key = makeSafe( luan, entry.getKey() );
+				Object key = makeSafe( entry.getKey() );
 				if( key instanceof Unsafe )
 					return key;
-				Object value = makeSafe( luan, entry.getValue() );
+				Object value = makeSafe( entry.getValue() );
 				if( value instanceof Unsafe )
 					return value;
 				rtn.rawPut(key,value);
@@ -176,7 +176,7 @@
 		} else if( v instanceof Object[] ) {
 			Object[] a = (Object[])v;
 			for( int i=0; i<a.length; i++ ) {
-				Object obj = makeSafe(luan,a[i]);
+				Object obj = makeSafe(a[i]);
 				if( obj instanceof Unsafe )
 					return obj;
 				a[i] = obj;
@@ -200,18 +200,18 @@
 		}
 
 		public synchronized Object call(Luan callerLuan,String fnName,Object... args) throws LuanException {
-			Object obj = makeSafe(luan,args);
+			Object obj = makeSafe(args);
 			if( obj instanceof Unsafe )
 				throw new LuanException("can't pass "+((Unsafe)obj).reason+" to global_callable "+Arrays.asList(args));
 			args = (Object[])obj;
-			Object f = fns.get(fnName);
+			Object f = fns.get(luan,fnName);
 			if( f == null )
 				throw new LuanException("function '"+fnName+"' not found in global_callable");
 			if( !(f instanceof LuanFunction) )
 				throw new LuanException("value of '"+fnName+"' not a function in global_callable");
 			LuanFunction fn = (LuanFunction)f;
 			Object rtn = fn.call(args);
-			rtn = makeSafe(callerLuan,rtn);
+			rtn = makeSafe(rtn);
 			if( rtn instanceof Unsafe )
 				throw new LuanException("can't return "+((Unsafe)rtn).reason+" from global_callable");
 			return rtn;
diff -r e1a13e707bf3 -r b89212fd04b5 src/luan/modules/http/LuanDomainHandler.java
--- a/src/luan/modules/http/LuanDomainHandler.java	Thu Nov 05 20:24:09 2020 -0700
+++ b/src/luan/modules/http/LuanDomainHandler.java	Sun Nov 08 16:50:59 2020 -0700
@@ -39,8 +39,8 @@
 		};
 		try {
 			LuanTable Http = (LuanTable)luan.require("luan:http/Http.luan");
-			Http.put( "domain", domain );
-			Http.put( "reset_luan", reset_luan );
+			Http.put( luan, "domain", domain );
+			Http.put( luan, "reset_luan", reset_luan );
 		} catch(LuanException e) {
 			throw new RuntimeException(e);
 		}
diff -r e1a13e707bf3 -r b89212fd04b5 src/luan/modules/http/LuanHandler.java
--- a/src/luan/modules/http/LuanHandler.java	Thu Nov 05 20:24:09 2020 -0700
+++ b/src/luan/modules/http/LuanHandler.java	Sun Nov 08 16:50:59 2020 -0700
@@ -66,11 +66,11 @@
 		try {
 			Fns fns = new Fns(this);
 			LuanTable Http = (LuanTable)luanInit.require("luan:http/Http.luan");
-			if( Http.get("reset_luan") == null )
-				Http.put( "reset_luan", new LuanJavaFunction(luanInit,resetLuanMethod,fns) );
-			Http.put( "eval_in_root", new LuanJavaFunction(luanInit,evalInRootMethod,fns) );
-			Http.put( "disable_luan", new LuanJavaFunction(luanInit,disableLuanMethod,fns) );
-			Http.put( "dont_gc", new LuanJavaFunction(luanInit,dontGcMethod,fns) );
+			if( Http.get(luanInit,"reset_luan") == null )
+				Http.put( luanInit, "reset_luan", new LuanJavaFunction(luanInit,resetLuanMethod,fns) );
+			Http.put( luanInit, "eval_in_root", new LuanJavaFunction(luanInit,evalInRootMethod,fns) );
+			Http.put( luanInit, "disable_luan", new LuanJavaFunction(luanInit,disableLuanMethod,fns) );
+			Http.put( luanInit, "dont_gc", new LuanJavaFunction(luanInit,dontGcMethod,fns) );
 		} catch(LuanException e) {
 			throw new RuntimeException(e);
 		}
@@ -138,7 +138,7 @@
 		//logger.info("close "+domain+" "+(obj!=null));
 	}
 
-	public Object call_rpc(String fnName,Object... args) throws LuanException {
+	public Object call_rpc(Luan luan,String fnName,Object... args) throws LuanException {
 		rwLock.readLock().lock();
 		LuanLogger.startThreadLogging(currentLuan);
 		try {
@@ -146,8 +146,8 @@
 			synchronized(luanInit) {
 				enableLoad("luan:Rpc.luan");
 				LuanTable rpc = (LuanTable)currentLuan.require("luan:Rpc.luan");
-				LuanTable fns = (LuanTable)rpc.get("functions");
-				fn = (LuanFunction)fns.get(fnName);
+				LuanTable fns = (LuanTable)rpc.get(luan,"functions");
+				fn = (LuanFunction)fns.get(luan,fnName);
 				if( fn == null )
 					throw new LuanException( "function not found: " + fnName );
 				LuanCloner cloner = new LuanCloner(LuanCloner.Type.INCREMENTAL);
@@ -256,7 +256,7 @@
 			luan = (Luan)cloner.clone(currentLuan);
 		}
 		LuanTable module = (LuanTable)luan.require("luan:http/Http.luan");
-		return (Response)module.fn("handle_error").call( request, e.table(luan) );
+		return (Response)module.fn(luan,"handle_error").call( request, e.table(luan) );
 	}
 
 	private Response serviceLuan(Request request)
@@ -278,10 +278,10 @@
 			fn = (LuanFunction)cloner.get(mod);
 		}
 		LuanTable module = (LuanTable)luan.require("luan:http/Http.luan");
-		module.fn("new_request").call(request);
-		module.fn("new_response").call();
+		module.fn(luan,"new_request").call(request);
+		module.fn(luan,"new_response").call();
 		fn.call();
-		return (Response)module.fn("finish").call();
+		return (Response)module.fn(luan,"finish").call();
 	}
 
 	private Response serviceNotFound(Request request)
@@ -292,7 +292,7 @@
 		synchronized(luanInit) {
 			enableLoad("luan:http/Http.luan");
  			LuanTable module = (LuanTable)currentLuan.require("luan:http/Http.luan");
-			fn = module.fn("not_found_handler");
+			fn = module.fn(currentLuan,"not_found_handler");
 			if( fn == null )
 				return null;
 			LuanCloner cloner = new LuanCloner(LuanCloner.Type.INCREMENTAL);
@@ -300,13 +300,13 @@
 			fn = (LuanFunction)cloner.get(fn);
 		}
 		LuanTable module = (LuanTable)luan.require("luan:http/Http.luan");
-		module.fn("new_request").call(request);
-		module.fn("new_response").call();
+		module.fn(luan,"new_request").call(request);
+		module.fn(luan,"new_response").call();
 		Object obj = Luan.first(fn.call());
 		if( !(obj instanceof Boolean) )
 			throw new LuanException("not_found_handler must return boolean");
 		boolean handled = (Boolean)obj;
-		return handled ? (Response)module.fn("finish").call() : null;
+		return handled ? (Response)module.fn(luan,"finish").call() : null;
 	}
 
 	private void enableLoad(String... mods) throws LuanException {
diff -r e1a13e707bf3 -r b89212fd04b5 src/luan/modules/lucene/LuceneIndex.java
--- a/src/luan/modules/lucene/LuceneIndex.java	Thu Nov 05 20:24:09 2020 -0700
+++ b/src/luan/modules/lucene/LuceneIndex.java	Sun Nov 08 16:50:59 2020 -0700
@@ -107,7 +107,7 @@
 			if( ref != null ) {
 				LuceneIndex li = ref.get();
 				if( li != null ) {
-					Object version = options.get("version");
+					Object version = options.get(luan,"version");
 					if( version==null || version.equals(li.version) )
 						return li;
 					li.closeWriter();
@@ -287,10 +287,10 @@
 		}
 	}
 
-	public void save(LuanTable doc)
+	public void save(Luan luan,LuanTable doc)
 		throws LuanException, IOException, SQLException
 	{
-		Object obj = doc.get("id");
+		Object obj = doc.get(luan,"id");
 		Long id;
 		try {
 			id = (Long)obj;
@@ -303,13 +303,13 @@
 		try {
 			if( id == null ) {
 				id = ++this.id;
-				doc.put("id",id);
+				doc.put(luan,"id",id);
 				if( postgresBackup != null )
-					postgresBackup.add(doc);
+					postgresBackup.add(luan,doc);
 				writer.addDocument(toLucene(doc));
 			} else {
 				if( postgresBackup != null )
-					postgresBackup.update(doc);
+					postgresBackup.update(luan,doc);
 				writer.updateDocument( "id", toLucene(doc) );
 			}
 			if(commit) writer.commit();
@@ -413,7 +413,7 @@
 		IndexCommit ic = snapshotDeletionPolicy.snapshot();
 		try {
 			String dir = fsDir.getDirectory().toString();
-			LuanTable fileNames = new LuanTable(fn.luan(),new ArrayList(ic.getFileNames()));
+			LuanTable fileNames = new LuanTable(new ArrayList(ic.getFileNames()));
 			return fn.call(dir,fileNames);
 		} finally {
 			snapshotDeletionPolicy.release(ic);
@@ -472,7 +472,7 @@
 
 		@Override public Object call(Object[] args) throws LuanException {
 			try {
-				LuanTable doc = toTable(luan(),searcher.doc(docID));
+				LuanTable doc = toTable(searcher.doc(docID));
 				if( args.length > 0 && "explain".equals(args[0]) ) {
 					Explanation explanation = searcher.explain(query,docID);
 					return new Object[]{doc,explanation};
@@ -605,8 +605,8 @@
 		return SupplementingConfig.toLucene(table);
 	}
 
-	private static LuanTable toTable(Luan luan,Document doc) throws LuanException {
-		return doc==null ? null : SupplementingConfig.toTable(luan,LuceneUtils.toMap(doc));
+	private static LuanTable toTable(Document doc) throws LuanException {
+		return doc==null ? null : SupplementingConfig.toTable(LuceneUtils.toMap(doc));
 	}
 
 
@@ -706,8 +706,8 @@
 				@Override public void collect(int iDoc) throws IOException {
 					try {
 						Document doc = searcher.doc( docBase + iDoc );
-						LuanTable tbl = toTable(luan,doc);
-						postgresBackup.add(tbl);
+						LuanTable tbl = toTable(doc);
+						postgresBackup.add(luan,tbl);
 					} catch(LuanException e) {
 						throw new LuanRuntimeException(e);
 					} catch(SQLException e) {
@@ -872,7 +872,7 @@
 			final int nPostgres = idsPostgres.size();
 			int iLucene = 0;
 			int iPostgres = 0;
-			LuanToString lts = new LuanToString(null,null);
+			LuanToString lts = new LuanToString(luan,null,null);
 			lts.settingsInit.strict = true;
 			lts.settingsInit.numberTypes = true;
 			while( iLucene < nLucene && iPostgres < nPostgres ) {
@@ -880,18 +880,18 @@
 				long idPostgres = idsPostgres.get(iPostgres);
 				if( idLucene < idPostgres ) {
 					iLucene++;
-					checkPostgres(luan,postgresChecker,lts,idLucene);
+					checkPostgres(postgresChecker,lts,idLucene);
 				} else if( idLucene > idPostgres ) {
 					iPostgres++;
-					checkPostgres(luan,postgresChecker,lts,idPostgres);
+					checkPostgres(postgresChecker,lts,idPostgres);
 				} else {  // ==
 					LuanTable docPostgres = postgresChecker.getDoc(idPostgres);
 					TopDocs td = searcher.search(new TermQuery(term("id",idLucene)),1);
 					if( td.totalHits != 1 )  throw new RuntimeException();
 					Document doc = searcher.doc( td.scoreDocs[0].doc );
-					LuanTable docLucene = toTable(luan,doc);
+					LuanTable docLucene = toTable(doc);
 					if( !equal(docPostgres,docLucene) ) {
-						checkPostgres(luan,postgresChecker,lts,idPostgres);
+						checkPostgres(postgresChecker,lts,idPostgres);
 					}
 					iLucene++;
 					iPostgres++;
@@ -899,11 +899,11 @@
 			}
 			while( iLucene < nLucene ) {
 				long idLucene = idsLucene.get(iLucene++);
-				checkPostgres(luan,postgresChecker,lts,idLucene);
+				checkPostgres(postgresChecker,lts,idLucene);
 			}
 			while( iPostgres < nPostgres ) {
 				long idPostgres = idsPostgres.get(iPostgres++);
-				checkPostgres(luan,postgresChecker,lts,idPostgres);
+				checkPostgres(postgresChecker,lts,idPostgres);
 			}
 		} finally {
 			close(searcher);
@@ -911,7 +911,7 @@
 		}
 	}
 
-	private void checkPostgres(Luan luan,PostgresBackup.Checker postgresChecker,LuanToString lts,long id)
+	private void checkPostgres(PostgresBackup.Checker postgresChecker,LuanToString lts,long id)
 		throws IOException, SQLException, LuanException, ParseException
 	{
 		//logger.info("check id "+id);
@@ -926,7 +926,7 @@
 					docLucene = null;
 				} else if( td.totalHits == 1 ) {
 					Document doc = searcher.doc( td.scoreDocs[0].doc );
-					docLucene = toTable(luan,doc);
+					docLucene = toTable(doc);
 				} else
 					throw new RuntimeException();
 				if( docPostgres == null ) {
diff -r e1a13e707bf3 -r b89212fd04b5 src/luan/modules/lucene/PostgresBackup.java
--- a/src/luan/modules/lucene/PostgresBackup.java	Thu Nov 05 20:24:09 2020 -0700
+++ b/src/luan/modules/lucene/PostgresBackup.java	Sun Nov 08 16:50:59 2020 -0700
@@ -34,7 +34,7 @@
 	private final PreparedStatement updateStmt;
 	private final PreparedStatement deleteStmt;
 	private int trans = 0;
-	private final LuanToString luanToString = new LuanToString(null,null);
+	private final LuanToString luanToString;
 
 	PostgresBackup(Luan luan,LuanTable spec)
 		throws ClassNotFoundException, SQLException, LuanException
@@ -82,6 +82,7 @@
 			"delete from lucene where id=?"
 		);
 
+		luanToString = new LuanToString(luan,null,null);
 		luanToString.settingsInit.strict = true;
 		luanToString.settingsInit.numberTypes = true;
 	}
@@ -102,23 +103,23 @@
 		super.finalize();
 	}
 
-	void add(LuanTable doc) throws LuanException, SQLException {
-		Long id = (Long)doc.get("id");
+	void add(Luan luan,LuanTable doc) throws LuanException, SQLException {
+		Long id = (Long)doc.get(luan,"id");
 		String data = luanToString.toString(doc);
 		insertStmt.setLong(1,id);
 		insertStmt.setString(2,data);
 		insertStmt.executeUpdate();
 	}
 
-	void update(LuanTable doc) throws LuanException, SQLException {
-		Long id = (Long)doc.get("id");
+	void update(Luan luan,LuanTable doc) throws LuanException, SQLException {
+		Long id = (Long)doc.get(luan,"id");
 		String data = luanToString.toString(doc);
 		updateStmt.setString(1,data);
 		updateStmt.setLong(2,id);
 		int n = updateStmt.executeUpdate();
 		if( n==0 ) {
 			logger.error("update not found for id="+id+", trying add");
-			add(doc);
+			add(luan,doc);
 		} else if( n!=1 )
 			throw new RuntimeException();
 	}
@@ -158,12 +159,11 @@
 	void restoreLucene(LuceneIndex li)
 		throws LuanException, IOException, SQLException, ParseException
 	{
-		Luan luan = new Luan();
 		Statement stmt = con.createStatement();
 		ResultSet rs = stmt.executeQuery("select data from lucene");
 		while( rs.next() ) {
 			String data = rs.getString("data");
-			LuanTable doc = (LuanTable)LuanParser.parse(luan,data);
+			LuanTable doc = (LuanTable)LuanParser.parse(data);
 			li.restore(doc);
 		}
 		stmt.close();
@@ -172,7 +172,6 @@
 	final class Checker {
 		private final Connection con;
 		private final PreparedStatement pstmt;
-		private final Luan luan = new Luan();
 
 		Checker() throws SQLException {
 			con = newConnection();
@@ -205,7 +204,7 @@
 			if( !rs.next() )
 				return null;
 			String data = rs.getString("data");
-			LuanTable doc = (LuanTable)LuanParser.parse(luan,data);
+			LuanTable doc = (LuanTable)LuanParser.parse(data);
 			return doc;
 		}
 	}
diff -r e1a13e707bf3 -r b89212fd04b5 src/luan/modules/lucene/SupplementingConfig.java
--- a/src/luan/modules/lucene/SupplementingConfig.java	Thu Nov 05 20:24:09 2020 -0700
+++ b/src/luan/modules/lucene/SupplementingConfig.java	Sun Nov 08 16:50:59 2020 -0700
@@ -38,7 +38,7 @@
 		if( supplementer == null )
 			return super.getMoreFieldInfo(storedFields);
 		try {
-			LuanTable tbl = toTable(supplementer.luan(),storedFields);
+			LuanTable tbl = toTable(storedFields);
 			tbl = (LuanTable)supplementer.call(tbl);
 			if( tbl == null ) {
 				return super.getMoreFieldInfo(storedFields);
@@ -50,13 +50,13 @@
 		}
 	}
 
-	static LuanTable toTable(Luan luan,Map map) throws LuanException {
-		LuanTable table = new LuanTable(luan);
+	static LuanTable toTable(Map map) throws LuanException {
+		LuanTable table = new LuanTable();
 		for( Object obj : map.entrySet() ) {
 			Map.Entry entry = (Map.Entry)obj;
 			Object value = entry.getValue();
 			if( value instanceof List )
-				value = new LuanTable(luan,(List)value);
+				value = new LuanTable((List)value);
 			table.rawPut( entry.getKey(), value );
 		}
 		return table;
diff -r e1a13e707bf3 -r b89212fd04b5 src/luan/modules/parsers/Css.java
--- a/src/luan/modules/parsers/Css.java	Thu Nov 05 20:24:09 2020 -0700
+++ b/src/luan/modules/parsers/Css.java	Sun Nov 08 16:50:59 2020 -0700
@@ -8,24 +8,22 @@
 
 public final class Css {
 
-	public static LuanTable style(Luan luan,String text) {
+	public static LuanTable style(String text) {
 		try {
-			return new Css(luan,text).parseStyle();
+			return new Css(text).parseStyle();
 		} catch(LuanException e) {
 			throw new RuntimeException(e);
 		}
 	}
 
-	private final Luan luan;
 	private final Parser parser;
 
-	private Css(Luan luan,String text) {
-		this.luan = luan;
+	private Css(String text) {
 		this.parser = new Parser(text);
 	}
 
 	private LuanTable parseStyle() throws LuanException {
-		LuanTable tbl = new LuanTable(luan);
+		LuanTable tbl = new LuanTable();
 		while( matchSpace() );
 		while( !parser.endOfInput() ) {
 			int start = parser.currentIndex();
@@ -42,7 +40,7 @@
 			while( !parser.endOfInput() && parser.noneOf(";") );
 			String val = parser.textFrom(start).trim();
 
-			tbl.put(prop,val);
+			tbl.rawPut(prop,val);
 			parser.match(';');
 			while( matchSpace() );
 		}
diff -r e1a13e707bf3 -r b89212fd04b5 src/luan/modules/parsers/Csv.java
--- a/src/luan/modules/parsers/Csv.java	Thu Nov 05 20:24:09 2020 -0700
+++ b/src/luan/modules/parsers/Csv.java	Sun Nov 08 16:50:59 2020 -0700
@@ -9,9 +9,9 @@
 
 public final class Csv {
 
-	public static LuanTable toList(Luan luan,String line) throws ParseException {
+	public static LuanTable toList(String line) throws ParseException {
 		try {
-			return new Csv(line).parse(luan);
+			return new Csv(line).parse();
 		} catch(LuanException e) {
 			throw new RuntimeException(e);
 		}
@@ -27,12 +27,12 @@
 		return new ParseException(parser,msg);
 	}
 
-	private LuanTable parse(Luan luan) throws ParseException, LuanException {
-		LuanTable list = new LuanTable(luan);
+	private LuanTable parse() throws ParseException, LuanException {
+		LuanTable list = new LuanTable();
 		while(true) {
 			Spaces();
 			String field = parseField();
-			list.put(list.rawLength()+1,field);
+			list.rawPut(list.rawLength()+1,field);
 			Spaces();
 			if( parser.endOfInput() )
 				return list;
diff -r e1a13e707bf3 -r b89212fd04b5 src/luan/modules/parsers/Html.java
--- a/src/luan/modules/parsers/Html.java	Thu Nov 05 20:24:09 2020 -0700
+++ b/src/luan/modules/parsers/Html.java	Sun Nov 08 16:50:59 2020 -0700
@@ -12,20 +12,18 @@
 
 public final class Html {
 
-	public static LuanTable toList(Luan luan,String text,LuanTable containerTagsTbl) {
+	public static LuanTable toList(String text,LuanTable containerTagsTbl) {
 		try {
-			return new Html(luan,text,containerTagsTbl).parse();
+			return new Html(text,containerTagsTbl).parse();
 		} catch(LuanException e) {
 			throw new RuntimeException(e);
 		}
 	}
 
-	private final Luan luan;
 	private final Parser parser;
 	private final Set<String> containerTags = new HashSet<String>();
 
-	private Html(Luan luan,String text,LuanTable containerTagsTbl) {
-		this.luan = luan;
+	private Html(String text,LuanTable containerTagsTbl) {
 		this.parser = new Parser(text);
 		for( Object v : containerTagsTbl.asList() ) {
 			containerTags.add((String)v);
@@ -63,7 +61,7 @@
 		}
 		if( sb.length() > 0 )
 			list.add(sb.toString());
-		return new LuanTable(luan,list);
+		return new LuanTable(list);
 	}
 
 	private LuanTable parseComment() throws LuanException {
@@ -76,9 +74,9 @@
 				return parser.failure(null);
 		}
 		String text = parser.textFrom(start);
-		LuanTable tbl = new LuanTable(luan);
-		tbl.put("type","comment");
-		tbl.put("text",text);
+		LuanTable tbl = new LuanTable();
+		tbl.rawPut("type","comment");
+		tbl.rawPut("text",text);
 		return parser.success(tbl);
 	}
 
@@ -92,9 +90,9 @@
 				return parser.failure(null);
 		}
 		String text = parser.textFrom(start);
-		LuanTable tbl = new LuanTable(luan);
-		tbl.put("type","cdata");
-		tbl.put("text",text);
+		LuanTable tbl = new LuanTable();
+		tbl.rawPut("type","cdata");
+		tbl.rawPut("text",text);
 		return parser.success(tbl);
 	}
 
@@ -114,16 +112,16 @@
 				return parser.failure(null);
 		}
 		String text = parser.text.substring(start,end);
-		LuanTable tbl = new LuanTable(luan);
-		tbl.put("type","container");
-		tbl.put("tag",tag);
-		tbl.put("text",text);
+		LuanTable tbl = new LuanTable();
+		tbl.rawPut("type","container");
+		tbl.rawPut("tag",tag);
+		tbl.rawPut("text",text);
 		return parser.success(tbl);
 	}
 
 	private LuanTable parseTag() throws LuanException {
-		LuanTable tbl = new LuanTable(luan);
-		tbl.put("type","tag");
+		LuanTable tbl = new LuanTable();
+		tbl.rawPut("type","tag");
 		int tagStart = parser.begin();
 		if( !parser.match('<') )
 			return parser.failure(null);
@@ -133,26 +131,26 @@
 			return parser.failure(null);
 		while( matchNameChar() );
 		String name = parser.textFrom(start).toLowerCase();
-		tbl.put("name",name);
-		LuanTable attributes = new LuanTable(luan);
-		tbl.put("attributes",attributes);
+		tbl.rawPut("name",name);
+		LuanTable attributes = new LuanTable();
+		tbl.rawPut("attributes",attributes);
 		String attrName;
 		while( (attrName = parseAttrName()) != null ) {
 			String attrValue = parseAttrValue();
-			attributes.put( attrName, attrValue!=null ? attrValue : true );
+			attributes.rawPut( attrName, attrValue!=null ? attrValue : true );
 			if( attrName.equals("style") && attrValue!=null ) {
-				LuanTable style = Css.style(luan,attrValue);
+				LuanTable style = Css.style(attrValue);
 				if( style!=null )
-					tbl.put("style",style);
+					tbl.rawPut("style",style);
 			}
 		}
 		while( matchSpace() );
 		boolean isEmpty = parser.match('/');
-		tbl.put("is_empty",isEmpty);
+		tbl.rawPut("is_empty",isEmpty);
 		if( !parser.match('>') )
 			return parser.failure(null);
 		String raw = parser.textFrom(tagStart);
-		tbl.put("raw",raw);
+		tbl.rawPut("raw",raw);
 		return parser.success(tbl);
 	}
 
diff -r e1a13e707bf3 -r b89212fd04b5 src/luan/modules/parsers/LuanParser.java
--- a/src/luan/modules/parsers/LuanParser.java	Thu Nov 05 20:24:09 2020 -0700
+++ b/src/luan/modules/parsers/LuanParser.java	Sun Nov 08 16:50:59 2020 -0700
@@ -9,16 +9,14 @@
 
 public final class LuanParser {
 
-	public static Object parse(Luan luan,String text) throws ParseException {
-		return new LuanParser(luan,text).parse();
+	public static Object parse(String text) throws ParseException {
+		return new LuanParser(text).parse();
 	}
 
 	private static final Object NULL = new Object();
-	private final Luan luan;
 	private final Parser parser;
 
-	private LuanParser(Luan luan,String text) {
-		this.luan = luan;
+	private LuanParser(String text) {
 		this.parser = new Parser(text);
 	}
 
@@ -217,7 +215,7 @@
 		parser.begin();
 		if( !parser.match('{') )
 			return parser.failure(null);
-		LuanTable tbl = new LuanTable(luan);
+		LuanTable tbl = new LuanTable();
 		do {
 			spaces();
 			Object obj = value();
diff -r e1a13e707bf3 -r b89212fd04b5 src/luan/modules/parsers/LuanToString.java
--- a/src/luan/modules/parsers/LuanToString.java	Thu Nov 05 20:24:09 2020 -0700
+++ b/src/luan/modules/parsers/LuanToString.java	Sun Nov 08 16:50:59 2020 -0700
@@ -19,21 +19,21 @@
 		public boolean longStrings = false;
 		public boolean inline = false;
 
-		void applyOptions(LuanTable options) throws LuanException {
+		void applyOptions(Luan luan,LuanTable options) throws LuanException {
 			Boolean b;
-			b = (Boolean)options.get("strict");
+			b = (Boolean)options.get(luan,"strict");
 			if( b != null )
 				strict = b;
-			b = (Boolean)options.get("number_types");
+			b = (Boolean)options.get(luan,"number_types");
 			if( b != null )
 				numberTypes = b;
-			b = (Boolean)options.get("compressed");
+			b = (Boolean)options.get(luan,"compressed");
 			if( b != null )
 				compressed = b;
-			b = (Boolean)options.get("long_strings");
+			b = (Boolean)options.get(luan,"long_strings");
 			if( b != null )
 				longStrings = b;
-			b = (Boolean)options.get("inline");
+			b = (Boolean)options.get(luan,"inline");
 			if( b != null )
 				inline = b;
 		}
@@ -62,13 +62,15 @@
 	}
 
 	public final Settings settingsInit = new Settings();
+	private final Luan luan;
 	private final LuanTable subOptions;
 
-	public LuanToString(LuanTable options,LuanTable subOptions) throws LuanException {
+	public LuanToString(Luan luan,LuanTable options,LuanTable subOptions) throws LuanException {
+		this.luan = luan;
 		this.subOptions = subOptions;
 		if( options != null ) {
 			checkOptions(options);
-			settingsInit.applyOptions(options);
+			settingsInit.applyOptions(luan,options);
 		}
 		if( subOptions != null ) {
 			for( Map.Entry entry : subOptions.iterable() ) {
@@ -181,10 +183,10 @@
 		}
 		sb.append( settings.compressed ? "=" : " = " );
 		if( subOptions != null ) {
-			LuanTable options = (LuanTable)subOptions.get(key);
+			LuanTable options = (LuanTable)subOptions.get(luan,key);
 			if( options != null ) {
 				settings = settings.cloneSettings();
-				settings.applyOptions(options);
+				settings.applyOptions(luan,options);
 			}
 		}
 		toString( entry.getValue(), sb, indented, settings );
@@ -207,13 +209,13 @@
 			sb.append( ')' );
 	}
 
-	public static void addNumberTypes(LuanTable env) {
+	public static void addNumberTypes(Luan luan,LuanTable env) {
 		try {
-			LuanTable module = (LuanTable)env.luan().require("luan:Number.luan");
-			env.put( "double", module.fn("double") );
-			env.put( "float", module.fn("float") );
-			env.put( "integer", module.fn("integer") );
-			env.put( "long", module.fn("long") );
+			LuanTable module = (LuanTable)luan.require("luan:Number.luan");
+			env.put( luan, "double", module.fn(luan,"double") );
+			env.put( luan, "float", module.fn(luan,"float") );
+			env.put( luan, "integer", module.fn(luan,"integer") );
+			env.put( luan, "long", module.fn(luan,"long") );
 		} catch(LuanException e) {
 			throw new LuanRuntimeException(e);
 		}
diff -r e1a13e707bf3 -r b89212fd04b5 src/luan/modules/parsers/Xml.java
--- a/src/luan/modules/parsers/Xml.java	Thu Nov 05 20:24:09 2020 -0700
+++ b/src/luan/modules/parsers/Xml.java	Sun Nov 08 16:50:59 2020 -0700
@@ -16,8 +16,8 @@
 
 public final class Xml {
 
-	public static String toString(LuanTable tbl) throws LuanException {
-		XmlElement[] elements = elements(tbl);
+	public static String toString(Luan luan,LuanTable tbl) throws LuanException {
+		XmlElement[] elements = elements(luan,tbl);
 		if( elements.length != 1 )
 			throw new LuanException("XML must have 1 root element");
 		return elements[0].toString();
@@ -26,7 +26,7 @@
 	private static final String ATTRIBUTES = "xml_attributes";
 	private static final String TEXT = "xml_text";
 
-	private static XmlElement[] elements(LuanTable tbl) throws LuanException {
+	private static XmlElement[] elements(Luan luan,LuanTable tbl) throws LuanException {
 		List<XmlElement> list = new ArrayList<XmlElement>();
 		for( Map.Entry entry : tbl.iterable() ) {
 			Object key = entry.getKey();
@@ -40,27 +40,27 @@
 				throw new LuanException("Can't mix text and elements");
 			LuanTable t = (LuanTable)value;
 			if( t.isMap() ) {
-				list.add( element(name,t) );
+				list.add( element(luan,name,t) );
 			} else {
 				for( Object obj : t.asList() ) {
-					list.add( element(name,obj) );
+					list.add( element(luan,name,obj) );
 				}
 			}
 		}
 		return list.toArray(new XmlElement[0]);
 	}
 
-	private static XmlElement element(String name,Object obj) throws LuanException {
+	private static XmlElement element(Luan luan,String name,Object obj) throws LuanException {
 		if( obj instanceof String ) {
 			return new XmlElement( name, Collections.emptyMap(), (String)obj );
 		}
 		LuanTable t = (LuanTable)obj;
-		Map<String,String> attributes = attributes(t);
-		String s = (String)t.get(TEXT);
+		Map<String,String> attributes = attributes(luan,t);
+		String s = (String)t.get(luan,TEXT);
 		if( s != null ) {
 			return new XmlElement(name,attributes,s);
 		} else {
-			XmlElement[] elements = elements(t);
+			XmlElement[] elements = elements(luan,t);
 			if( elements.length==0 ) {
 				return new XmlElement(name,attributes);
 			} else {
@@ -69,8 +69,8 @@
 		}
 	}
 
-	private static Map<String,String> attributes(LuanTable tbl) throws LuanException {
-		Object obj = tbl.get(ATTRIBUTES);
+	private static Map<String,String> attributes(Luan luan,LuanTable tbl) throws LuanException {
+		Object obj = tbl.get(luan,ATTRIBUTES);
 		if( obj==null )
 			return Collections.emptyMap();
 		LuanTable t = (LuanTable)obj;
@@ -84,40 +84,40 @@
 	}
 
 
-	public static LuanTable parse(Luan luan,String s) throws ParseException, LuanException {
+	public static LuanTable parse(String s) throws ParseException, LuanException {
 		XmlElement element = XmlParser.parse(s);
-		LuanTable tbl = new LuanTable(luan);
+		LuanTable tbl = new LuanTable();
 		addElements(tbl,new XmlElement[]{element});
 		return tbl;
 	}
 
 	private static LuanTable addElements(LuanTable tbl,XmlElement[] elements) throws LuanException {
 		for( XmlElement element : elements ) {
-			LuanTable t = new LuanTable(tbl.luan());
+			LuanTable t = new LuanTable();
 			if( !element.attributes.isEmpty() ) {
-				LuanTable attrs = new LuanTable(tbl.luan());
+				LuanTable attrs = new LuanTable();
 				for( Map.Entry<String,String> entry : element.attributes.entrySet() ) {
-					attrs.put(entry.getKey(),entry.getValue());
+					attrs.rawPut(entry.getKey(),entry.getValue());
 				}
-				t.put( ATTRIBUTES, attrs );
+				t.rawPut( ATTRIBUTES, attrs );
 			}
 			if( element.content == null ) {
 				// nothing
 			} else if( element.content instanceof String ) {
-				t.put( TEXT, element.content );
+				t.rawPut( TEXT, element.content );
 			} else {
 				XmlElement[] els = (XmlElement[])element.content;
 				addElements(t,els);
 			}
-			LuanTable old = (LuanTable)tbl.get(element.name);
+			LuanTable old = (LuanTable)tbl.rawGet(element.name);
 			if( old==null ) {
-				tbl.put(element.name,t);
+				tbl.rawPut(element.name,t);
 			} else {
 				if( !old.isList() ) {
-					LuanTable list = new LuanTable(tbl.luan());
+					LuanTable list = new LuanTable();
 					list.rawAdd(old);
 					old = list;
-					tbl.put(element.name,old);
+					tbl.rawPut(element.name,old);
 				}
 				old.rawAdd(t);
 			}