changeset 1561:e1a13e707bf3

start immutable
author Franklin Schmidt <fschmidt@gmail.com>
date Thu, 05 Nov 2020 20:24:09 -0700
parents 33a53c43e2f7
children b89212fd04b5
files src/luan/Luan.java src/luan/LuanCloneable.java src/luan/LuanCloner.java src/luan/LuanClosure.java src/luan/LuanException.java src/luan/LuanFunction.java src/luan/LuanImmutabler.java src/luan/LuanTable.java src/luan/impl/Compiled.java src/luan/impl/LuanCompiler.java src/luan/impl/LuanParser.java src/luan/impl/Pointer.java src/luan/modules/BasicLuan.java src/luan/modules/JavaLuan.java
diffstat 14 files changed, 186 insertions(+), 80 deletions(-) [+]
line wrap: on
line diff
diff -r 33a53c43e2f7 -r e1a13e707bf3 src/luan/Luan.java
--- a/src/luan/Luan.java	Thu Oct 22 00:33:04 2020 -0600
+++ b/src/luan/Luan.java	Thu Nov 05 20:24:09 2020 -0700
@@ -43,6 +43,8 @@
 			isLocked = true;
 	}
 
+	@Override public void makeImmutable(LuanImmutabler immutabler) {}
+
 	public LuanClosure peek() {
 		return peek(1);
 	}
diff -r 33a53c43e2f7 -r e1a13e707bf3 src/luan/LuanCloneable.java
--- a/src/luan/LuanCloneable.java	Thu Oct 22 00:33:04 2020 -0600
+++ b/src/luan/LuanCloneable.java	Thu Nov 05 20:24:09 2020 -0700
@@ -4,4 +4,5 @@
 public interface LuanCloneable {
 	public LuanCloneable shallowClone();
 	public void deepenClone(LuanCloneable clone,LuanCloner cloner);
+	public void makeImmutable(LuanImmutabler immutabler) throws LuanException;
 }
diff -r 33a53c43e2f7 -r e1a13e707bf3 src/luan/LuanCloner.java
--- a/src/luan/LuanCloner.java	Thu Oct 22 00:33:04 2020 -0600
+++ b/src/luan/LuanCloner.java	Thu Nov 05 20:24:09 2020 -0700
@@ -34,7 +34,7 @@
 	}
 
 	public Object[] clone(Object[] obj) {
-		if( obj.length == 0 )
+		if( obj==null || obj.length == 0 )
 			return obj;
 		Object[] rtn = (Object[])cloned.get(obj);
 		if( rtn == null ) {
@@ -48,6 +48,8 @@
 	}
 
 	public Map clone(Map obj) {
+		if( obj==null )
+			return null;
 		Map rtn = (Map)cloned.get(obj);
 		if( rtn == null ) {
 			try {
@@ -57,6 +59,7 @@
 			} catch(IllegalAccessException e) {
 				throw new RuntimeException(e);
 			}
+			cloned.put(obj,rtn);
 			for( Object stupid : obj.entrySet() ) {
 				Map.Entry entry = (Map.Entry)stupid;
 				rtn.put( get(entry.getKey()), get(entry.getValue()) );
@@ -66,6 +69,8 @@
 	}
 
 	public Collection clone(Collection obj) {
+		if( obj==null )
+			return null;
 		Collection rtn = (Collection)cloned.get(obj);
 		if( rtn == null ) {
 			try {
diff -r 33a53c43e2f7 -r e1a13e707bf3 src/luan/LuanClosure.java
--- a/src/luan/LuanClosure.java	Thu Oct 22 00:33:04 2020 -0600
+++ b/src/luan/LuanClosure.java	Thu Nov 05 20:24:09 2020 -0700
@@ -21,6 +21,11 @@
 		super.completeClone(dc,cloner);
 	}
 
+	@Override public void makeImmutable(LuanImmutabler immutabler) throws LuanException {
+		immutabler.makeImmutable(upValues);
+		super.makeImmutable(immutabler);
+	}
+
 	@Override public final Object call(Object... args) throws LuanException {
 		Luan luan = luan();
 		luan.push(this);
diff -r 33a53c43e2f7 -r e1a13e707bf3 src/luan/LuanException.java
--- a/src/luan/LuanException.java	Thu Oct 22 00:33:04 2020 -0600
+++ b/src/luan/LuanException.java	Thu Nov 05 20:24:09 2020 -0700
@@ -35,6 +35,11 @@
 		clone.extra = (Map)cloner.clone(extra);
 	}
 
+	@Override public void makeImmutable(LuanImmutabler immutabler) throws LuanException {
+		immutabler.makeImmutable(table);
+		immutabler.makeImmutable(extra);
+	}
+
 	public void put(String key,Object value) throws LuanException {
 		if( table == null ) {
 			extra.put(key,value);
diff -r 33a53c43e2f7 -r e1a13e707bf3 src/luan/LuanFunction.java
--- a/src/luan/LuanFunction.java	Thu Oct 22 00:33:04 2020 -0600
+++ b/src/luan/LuanFunction.java	Thu Nov 05 20:24:09 2020 -0700
@@ -58,6 +58,10 @@
 		clone.luan = (Luan)cloner.clone(luan);
 	}
 
+	@Override public void makeImmutable(LuanImmutabler immutabler) throws LuanException {
+		immutabler.makeImmutable(luan);
+	}
+
 	public Luan luan() {
 		check();
 		return luan;
diff -r 33a53c43e2f7 -r e1a13e707bf3 src/luan/LuanImmutabler.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/LuanImmutabler.java	Thu Nov 05 20:24:09 2020 -0700
@@ -0,0 +1,61 @@
+package luan;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.IdentityHashMap;
+
+
+public final class LuanImmutabler {
+	private final Set handled = Collections.newSetFromMap(new IdentityHashMap());
+	private Luan luan = null;
+
+	public void makeImmutable(LuanCloneable obj) throws LuanException {
+		if( obj==null || !handled.add(obj) )
+			return;
+		if( obj instanceof Luan ) {
+			if( luan != null )
+				throw new RuntimeException("2 luans in "+this+" - "+luan+" "+obj);
+			luan = (Luan)obj;
+		}
+		obj.makeImmutable(this);
+	}
+
+	public void makeImmutable(Object[] obj) throws LuanException {
+		if( obj==null || !handled.add(obj) )
+			return;
+		for( Object entry : obj ) {
+			makeImmutable(entry);
+		}
+	}
+
+	public void makeImmutable(Map obj) throws LuanException {
+		if( obj==null || !handled.add(obj) )
+			return;
+		for( Object stupid : obj.entrySet() ) {
+			Map.Entry entry = (Map.Entry)stupid;
+			makeImmutable(entry.getKey());
+			makeImmutable(entry.getValue());
+		}
+	}
+
+	public void makeImmutable(Collection obj) throws LuanException {
+		if( obj==null || !handled.add(obj) )
+			return;
+		for( Object entry : (Collection)obj ) {
+			makeImmutable(entry);
+		}
+	}
+
+	public void makeImmutable(Object obj) throws LuanException {
+		if( obj instanceof LuanCloneable )
+			makeImmutable((LuanCloneable)obj);
+		else if( obj instanceof Object[] )
+			makeImmutable((Object[])obj);
+		else if( obj instanceof Map )
+			makeImmutable((Map)obj);
+		else if( obj instanceof Collection )
+			makeImmutable((Collection)obj);
+	}
+}
diff -r 33a53c43e2f7 -r e1a13e707bf3 src/luan/LuanTable.java
--- a/src/luan/LuanTable.java	Thu Oct 22 00:33:04 2020 -0600
+++ b/src/luan/LuanTable.java	Thu Nov 05 20:24:09 2020 -0700
@@ -21,12 +21,13 @@
 	public LuanClosure closure;
 	private LuanCloner cloner;
 	private String security = null;
+	private boolean immutable = false;
 
 	public LuanTable(Luan luan) {
 		this.luan = luan;
 	}
 
-	public LuanTable(Luan luan,List list){
+	public LuanTable(Luan luan,List list) {
 		this.luan = luan;
 		list();
 		int n = list.size();
@@ -48,7 +49,7 @@
 		}
 	}
 
-	public LuanTable(Luan luan,Set set){
+	public LuanTable(Luan luan,Set set) {
 		this.luan = luan;
 		for( Object el : set ) {
 			if( el != null )
@@ -66,6 +67,7 @@
 	}
 
 	@Override public LuanTable shallowClone() {
+		if(immutable) throw new RuntimeException();
 		return new LuanTable(luan);
 	}
 
@@ -101,25 +103,22 @@
 
 	private void completeClone(LuanTable clone,LuanCloner cloner) {
 		clone.luan = (Luan)cloner.clone(luan);
-		if( map != null ) {
-			Map newMap = newMap();
-			for( Object stupid : map.entrySet() ) {
-				Map.Entry entry = (Map.Entry)stupid;
-				newMap.put( cloner.get(entry.getKey()), cloner.get(entry.getValue()) );
-			}
-			clone.map = newMap;
-		}
-		if( list != null ) {
-			List newList = new ArrayList<Object>();
-			for( Object obj : list ) {
-				newList.add(cloner.get(obj));
-			}
-			clone.list = newList;
-		}
+		clone.map = cloner.clone(map);
+		clone.list = (List)cloner.clone(list);
 		clone.metatable = (LuanTable)cloner.clone(metatable);
 		clone.closure = (LuanClosure)cloner.clone(closure);
 	}
 
+	@Override public void makeImmutable(LuanImmutabler immutabler) throws LuanException {
+		check();
+		immutabler.makeImmutable(luan);
+		immutabler.makeImmutable(map);
+		immutabler.makeImmutable(list);
+		immutabler.makeImmutable(metatable);
+		immutabler.makeImmutable(closure);
+		immutable = true;
+	}
+
 	public boolean isList() {
 		return map==null || map.isEmpty();
 	}
@@ -203,6 +202,8 @@
 	}
 
 	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);
@@ -479,7 +480,7 @@
 		return metatable==null ? null : metatable.get(op);
 	}
 
-	private Map<Object,Object> newMap() {
+	private static Map<Object,Object> newMap() {
 		return new LinkedHashMap<Object,Object>();
 	}
 
@@ -535,7 +536,9 @@
 		return n;
 	}
 
-	public Object remove(Object key) {
+	public Object remove(Object key) throws LuanException {
+		if( immutable )
+			throw new LuanException("table is immutable");
 		Object old = rawGet(key);
 		rawPut2(key,null);
 		return old;
diff -r 33a53c43e2f7 -r e1a13e707bf3 src/luan/impl/Compiled.java
--- a/src/luan/impl/Compiled.java	Thu Oct 22 00:33:04 2020 -0600
+++ b/src/luan/impl/Compiled.java	Thu Nov 05 20:24:09 2020 -0700
@@ -133,7 +133,7 @@
 	}
 
 
-	private static final int VERSION = 3;
+	private static final int VERSION = 4;
 	private static final File tmpDir;
 	static {
 		File f = new File(System.getProperty("java.io.tmpdir"));
diff -r 33a53c43e2f7 -r e1a13e707bf3 src/luan/impl/LuanCompiler.java
--- a/src/luan/impl/LuanCompiler.java	Thu Oct 22 00:33:04 2020 -0600
+++ b/src/luan/impl/LuanCompiler.java	Thu Nov 05 20:24:09 2020 -0700
@@ -40,9 +40,9 @@
 		} catch(InvocationTargetException e) {
 			throw new RuntimeException(e);
 		}
-		closure.upValues[0].o = PackageLuan.requireFn(luan);
+		closure.upValues[0].set( PackageLuan.requireFn(luan) );
 		if( env != null ) {
-			closure.upValues[1].o = env;
+			closure.upValues[1].set(env);
 			env.closure = closure;
 		}
 		return closure;
diff -r 33a53c43e2f7 -r e1a13e707bf3 src/luan/impl/LuanParser.java
--- a/src/luan/impl/LuanParser.java	Thu Oct 22 00:33:04 2020 -0600
+++ b/src/luan/impl/LuanParser.java	Thu Nov 05 20:24:09 2020 -0700
@@ -17,6 +17,7 @@
 
 	private interface Sym {
 		public Expr exp();
+		public Stmts set(Expr val);
 	}
 
 	private int symCounter = 0;
@@ -72,11 +73,33 @@
 					if( !isPointer )
 						return javaName;
 					else
-						return javaName + ".o";
+						return javaName + ".get()";
 				}
 			} );
 			return exp;
 		}
+
+		@Override public Stmts set(Expr val) {
+			Stmts stmt = new Stmts();
+			stmt.add( new Object() {
+				@Override public String toString() {
+					if( !isPointer )
+						return javaName + " = ";
+					else
+						return javaName + ".set(";
+				}
+			} );
+			stmt.addAll( val.single() );
+			stmt.add( new Object() {
+				@Override public String toString() {
+					if( !isPointer )
+						return ";  ";
+					else
+						return ");  ";
+				}
+			} );
+			return stmt;
+		}
 	}
 
 	private class UpSym implements Sym {
@@ -89,20 +112,28 @@
 			this.i = i;
 			this.value = value;
 		}
-/*
-		String init() {
-			return "upValues[" + i + "] = " + value + ";  ";
-		}
-*/
+
 		@Override public Expr exp() {
 			Expr exp = new Expr(Val.SINGLE,false);
 			exp.add( new Object() {
 				@Override public String toString() {
-					return "upValues[" + i + "].o";
+					return "upValues[" + i + "].get()";
 				}
 			} );
 			return exp;
 		}
+
+		@Override public Stmts set(Expr val) {
+			Stmts stmt = new Stmts();
+			stmt.add( new Object() {
+				@Override public String toString() {
+					return "upValues[" + i + "].set(";
+				}
+			} );
+			stmt.addAll( val.single() );
+			stmt.add( ");  " );
+			return stmt;
+		}
 	}
 
 	private final class Frame {
@@ -1312,15 +1343,9 @@
 
 			public Stmts set(Expr val) throws ParseException {
 				Sym sym = getSym(name);
-				if( sym != null ) {
-					Stmts stmt = new Stmts();
-					stmt.addAll( sym.exp() );
-					stmt.add( " = " );
-					stmt.addAll( val.single() );
-					stmt.add( ";  " );
-					return stmt;
-				}
-				Expr envExpr = env();
+				if( sym != null )
+					return sym.set(val);
+ 				Expr envExpr = env();
 				if( envExpr != null )
 					return indexVar( envExpr, constExpStr(name) ).set(val);
 				parser.failure(null);
@@ -2087,47 +2112,7 @@
 		}
 		return lines;
 	}
-/*
-	private Expr toFnExp(Stmts stmt,List<UpSym> upValueSymbols,String name) {
-		stmt.addNewLines();
-		if( !stmt.hasReturn )
-			stmt.add( "return LuanFunction.NOTHING;  " );
-		Expr exp = new Expr(Val.SINGLE,false);
-		exp.add( ""
-			+"new LuanClosure(luan(),"+upValueSymbols.size()+",javaOk,sourceName) {  "
-				+"{  "
-				+ init(upValueSymbols)
-				+"}  "
-				+"@Override public Object doCall(Luan luan,Object[] args) throws LuanException {  "
-		);
-		if( name != null ) {
-			exp.add( ""
-					+"return _" + name + "(luan,args);  "
-				+"}  "
-				+"private Object _" + name + "(Luan luan,Object[] args) throws LuanException {  "
-			);
-		}
-		exp.add( ""
-					+"final Pointer[] parentUpValues = upValues;  "
-					+"Object t;  "
-					+"Object[] a;  "
-		);
-		exp.addAll( stmt );
-		exp.add( ""
-				+"}  "
-			+"}  "
-		);
-		return exp;
-	}
 
-	private static String init(List<UpSym> upValueSymbols) {
-		StringBuilder sb = new StringBuilder();
-		for( UpSym upSym : upValueSymbols ) {
-			sb.append( upSym.init() );
-		}
-		return sb.toString();
-	}
-*/
 	private static String toUpValues(List<UpSym> upValueSymbols) {
 		StringBuilder sb = new StringBuilder();
 		sb.append( "new Pointer[]{ " );
diff -r 33a53c43e2f7 -r e1a13e707bf3 src/luan/impl/Pointer.java
--- a/src/luan/impl/Pointer.java	Thu Oct 22 00:33:04 2020 -0600
+++ b/src/luan/impl/Pointer.java	Thu Nov 05 20:24:09 2020 -0700
@@ -2,10 +2,13 @@
 
 import luan.LuanCloneable;
 import luan.LuanCloner;
+import luan.LuanImmutabler;
+import luan.LuanException;
 
 
 public final class Pointer implements LuanCloneable {
-	public Object o;
+	private Object o;
+	private boolean immutable = false;
 
 	public Pointer() {}
 
@@ -20,4 +23,19 @@
 	@Override public void deepenClone(LuanCloneable clone,LuanCloner cloner) {
 		((Pointer)clone).o = cloner.get(o);
 	}
+
+	@Override public void makeImmutable(LuanImmutabler immutabler) throws LuanException {
+		immutabler.makeImmutable(o);
+		immutable = true;
+	}
+
+	public Object get() {
+		return o;
+	}
+
+	public void set(Object o) throws LuanException {
+		if( immutable )
+			throw new LuanException("variable is immutable");
+		this.o = o;
+	}
 }
diff -r 33a53c43e2f7 -r e1a13e707bf3 src/luan/modules/BasicLuan.java
--- a/src/luan/modules/BasicLuan.java	Thu Oct 22 00:33:04 2020 -0600
+++ b/src/luan/modules/BasicLuan.java	Thu Nov 05 20:24:09 2020 -0700
@@ -15,6 +15,7 @@
 import luan.LuanFunction;
 import luan.LuanException;
 import luan.LuanCloner;
+import luan.LuanImmutabler;
 import luan.modules.parsers.LuanToString;
 
 
@@ -72,6 +73,10 @@
 			clone.list = (List)cloner.clone(list);
 			super.completeClone(dc,cloner);
 		}
+
+		@Override public void makeImmutable(LuanImmutabler immutabler) throws LuanException {
+			throw new LuanException("ipairs cannot be made immutable");
+		}
 	}
 
 	public static LuanFunction ipairs(LuanTable t) throws LuanException {
@@ -184,6 +189,10 @@
 			clone.args = (Object[])cloner.clone(args);
 			super.completeClone(dc,cloner);
 		}
+
+		@Override public void makeImmutable(LuanImmutabler immutabler) throws LuanException {
+			throw new LuanException("values cannot be made immutable");
+		}
 	}
 
 	public static LuanFunction values(final Object... args) throws LuanException {
diff -r 33a53c43e2f7 -r e1a13e707bf3 src/luan/modules/JavaLuan.java
--- a/src/luan/modules/JavaLuan.java	Thu Oct 22 00:33:04 2020 -0600
+++ b/src/luan/modules/JavaLuan.java	Thu Nov 05 20:24:09 2020 -0700
@@ -23,6 +23,7 @@
 import luan.LuanFunction;
 import luan.LuanJavaFunction;
 import luan.LuanCloner;
+import luan.LuanImmutabler;
 
 
 public final class JavaLuan {
@@ -379,6 +380,13 @@
 			AmbiguousJavaFunction clone = (AmbiguousJavaFunction)dc;
 			clone.fnMap = (Map)cloner.clone(fnMap);
 			clone.varArgs = (List)cloner.clone(varArgs);
+			// no call to super?
+		}
+
+		@Override public void makeImmutable(LuanImmutabler immutabler) throws LuanException {
+			immutabler.makeImmutable(fnMap);
+			immutabler.makeImmutable(varArgs);
+			super.makeImmutable(immutabler);
 		}
 
 		@Override public Object call(Object[] args) throws LuanException {