Mercurial Hosting > luan
changeset 77:4bf3d0c0b6b9
make LuanState cloneable
git-svn-id: https://luan-java.googlecode.com/svn/trunk@78 21e917c8-12df-6dd8-5cb6-c86387c605b9
author | fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9> |
---|---|
date | Fri, 15 Feb 2013 09:55:17 +0000 |
parents | 97b03fc807ad |
children | 7c08b611125d |
files | src/luan/DeepCloneable.java src/luan/DeepCloner.java src/luan/LuanState.java src/luan/LuanTable.java src/luan/interp/Closure.java src/luan/interp/LuanStateImpl.java src/luan/interp/UpValue.java src/luan/lib/BasicLib.java src/luan/lib/HtmlLib.java src/luan/lib/HttpLib.java src/luan/lib/JavaLib.java src/luan/lib/MathLib.java src/luan/lib/PackageLib.java src/luan/lib/StringLib.java src/luan/lib/TableLib.java src/luan/tools/CmdLine.java src/luan/tools/WebRun.java src/luan/tools/WebServlet.java src/luan/tools/WebShell.java |
diffstat | 19 files changed, 197 insertions(+), 48 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/DeepCloneable.java Fri Feb 15 09:55:17 2013 +0000 @@ -0,0 +1,7 @@ +package luan; + + +public interface DeepCloneable<T extends DeepCloneable> { + public T shallowClone(); + public void deepenClone(T clone,DeepCloner cloner); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/DeepCloner.java Fri Feb 15 09:55:17 2013 +0000 @@ -0,0 +1,34 @@ +package luan; + +import java.util.Map; +import java.util.IdentityHashMap; + + +public final class DeepCloner { + private final Map<Object,Object> cloned = new IdentityHashMap<Object,Object>(); + + public <T extends DeepCloneable<T>> T deepClone(T obj) { + @SuppressWarnings("unchecked") + T rtn = (T)cloned.get(obj); + if( rtn == null ) { + rtn = obj.shallowClone(); + cloned.put(obj,rtn); + obj.deepenClone(rtn,this); + } + return rtn; + } + + public void deepenClone(Object[] a) { + for( int i=0; i<a.length; i++ ) { + a[i] = get(a[i]); + } + } + + public Object get(Object obj) { + if( !(obj instanceof DeepCloneable) ) + return obj; + @SuppressWarnings("unchecked") + DeepCloneable dc = deepClone((DeepCloneable)obj); + return dc; + } +}
--- a/src/luan/LuanState.java Fri Feb 15 04:52:16 2013 +0000 +++ b/src/luan/LuanState.java Fri Feb 15 09:55:17 2013 +0000 @@ -14,21 +14,53 @@ import luan.lib.HtmlLib; -public abstract class LuanState { +public abstract class LuanState implements DeepCloneable<LuanState> { - public final LuanTable global = new LuanTable(); - public final LuanTable loaded = new LuanTable(); - public final LuanTable preload = new LuanTable(); + private LuanTable global; + private LuanTable loaded; + private LuanTable preload; public InputStream in = System.in; public PrintStream out = System.out; public PrintStream err = System.err; - private final List<MetatableGetter> mtGetters = new ArrayList<MetatableGetter>(); + private final List<MetatableGetter> mtGetters; final List<StackTraceElement> stackTrace = new ArrayList<StackTraceElement>(); + protected LuanState() { + global = new LuanTable(); + loaded = new LuanTable(); + preload = new LuanTable(); + mtGetters = new ArrayList<MetatableGetter>(); + } - public Object get(String name) { + protected LuanState(LuanState luan) { + mtGetters = new ArrayList<MetatableGetter>(luan.mtGetters); + } + + public final LuanState deepClone() { + return new DeepCloner().deepClone(this); + } + + @Override public void deepenClone(LuanState clone,DeepCloner cloner) { + clone.global = cloner.deepClone(global); + clone.loaded = cloner.deepClone(loaded); + clone.preload = cloner.deepClone(preload); + } + + public final LuanTable global() { + return global; + } + + public final LuanTable loaded() { + return loaded; + } + + public final LuanTable preload() { + return preload; + } + + public final Object get(String name) { String[] a = name.split("\\."); LuanTable t = global; for( int i=0; i<a.length-1; i++ ) { @@ -40,7 +72,7 @@ return t.get(a[a.length-1]); } - public Object set(String name,Object value) { + public final Object set(String name,Object value) { String[] a = name.split("\\."); LuanTable t = global; for( int i=0; i<a.length-1; i++ ) { @@ -52,7 +84,7 @@ return t.put(a[a.length-1],value); } - public void load(LuanFunction loader,String modName) throws LuanException { + public final void load(LuanFunction loader,String modName) throws LuanException { Object mod = Luan.first(call(loader,LuanElement.JAVA,"loader",modName)); if( mod == null ) mod = true; @@ -77,7 +109,7 @@ } } - public Object[] eval(String cmd,String sourceName) throws LuanException { + public final Object[] eval(String cmd,String sourceName) throws LuanException { LuanFunction fn = BasicLib.load(this,cmd,sourceName); return call(fn,null,null); } @@ -100,7 +132,7 @@ mtGetters.add(mg); } - public Object[] call(LuanFunction fn,LuanElement calledFrom,String fnName,Object... args) throws LuanException { + public final Object[] call(LuanFunction fn,LuanElement calledFrom,String fnName,Object... args) throws LuanException { stackTrace.add( new StackTraceElement(calledFrom,fnName) ); try { return fn.call(this,args);
--- a/src/luan/LuanTable.java Fri Feb 15 04:52:16 2013 +0000 +++ b/src/luan/LuanTable.java Fri Feb 15 09:55:17 2013 +0000 @@ -13,7 +13,7 @@ import java.util.IdentityHashMap; -public class LuanTable { +public class LuanTable implements DeepCloneable<LuanTable> { private Map<Object,Object> map = null; private List<Object> list = null; private LuanTable metatable = null; @@ -35,6 +35,27 @@ } } + @Override public LuanTable shallowClone() { + return new LuanTable(); + } + + @Override public void deepenClone(LuanTable clone,DeepCloner cloner) { + if( map != null ) { + clone.map = new HashMap<Object,Object>(); + 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.deepClone(metatable); + } + public boolean isList() { return map==null || map.isEmpty(); }
--- a/src/luan/interp/Closure.java Fri Feb 15 04:52:16 2013 +0000 +++ b/src/luan/interp/Closure.java Fri Feb 15 09:55:17 2013 +0000 @@ -4,9 +4,11 @@ import luan.LuanState; import luan.LuanElement; import luan.LuanException; +import luan.DeepCloner; +import luan.DeepCloneable; -final class Closure extends LuanFunction { +final class Closure extends LuanFunction implements DeepCloneable<Closure> { private final Chunk chunk; final UpValue[] upValues; private final static UpValue[] NO_UP_VALUES = new UpValue[0]; @@ -24,6 +26,19 @@ } } + private Closure(Closure c) { + this.chunk = c.chunk; + this.upValues = c.upValues==NO_UP_VALUES ? NO_UP_VALUES : c.upValues.clone(); + } + + @Override public Closure shallowClone() { + return new Closure(this); + } + + @Override public void deepenClone(Closure clone,DeepCloner cloner) { + cloner.deepenClone(clone.upValues); + } + public Object[] call(LuanState luan,Object[] args) throws LuanException { return call(this,(LuanStateImpl)luan,args); }
--- a/src/luan/interp/LuanStateImpl.java Fri Feb 15 04:52:16 2013 +0000 +++ b/src/luan/interp/LuanStateImpl.java Fri Feb 15 09:55:17 2013 +0000 @@ -9,19 +9,11 @@ import luan.MetatableGetter; import luan.LuanException; import luan.LuanElement; +import luan.DeepCloner; final class LuanStateImpl extends LuanState { - final Object arithmetic(LuanElement el,String op,Object o1,Object o2) throws LuanException { - LuanFunction fn = getBinHandler(el,op,o1,o2); - if( fn != null ) - return Luan.first(call(fn,el,op,o1,o2)); - String type = Luan.toNumber(o1)==null ? Luan.type(o1) : Luan.type(o2); - throw new LuanException(this,el,"attempt to perform arithmetic on a "+type+" value"); - } - - private static class Frame { final Frame previousFrame; final Closure closure; @@ -64,6 +56,18 @@ Object[] returnValues = LuanFunction.EMPTY_RTN; Closure tailFn; + public LuanStateImpl() {} + + private LuanStateImpl(LuanStateImpl luan) { + super(luan); + } + + @Override public LuanState shallowClone() { + if( frame != null ) + throw new IllegalStateException("frame isn't null"); + return new LuanStateImpl(this); + } + // returns stack Object[] newFrame(Closure closure, int stackSize, Object[] varArgs) { frame = new Frame(frame,closure,stackSize,varArgs); @@ -99,4 +103,14 @@ UpValue getUpValue(int index) { return frame.getUpValue(index); } + + + final Object arithmetic(LuanElement el,String op,Object o1,Object o2) throws LuanException { + LuanFunction fn = getBinHandler(el,op,o1,o2); + if( fn != null ) + return Luan.first(call(fn,el,op,o1,o2)); + String type = Luan.toNumber(o1)==null ? Luan.type(o1) : Luan.type(o2); + throw new LuanException(this,el,"attempt to perform arithmetic on a "+type+" value"); + } + }
--- a/src/luan/interp/UpValue.java Fri Feb 15 04:52:16 2013 +0000 +++ b/src/luan/interp/UpValue.java Fri Feb 15 09:55:17 2013 +0000 @@ -1,7 +1,10 @@ package luan.interp; +import luan.DeepCloner; +import luan.DeepCloneable; -final class UpValue { + +final class UpValue implements DeepCloneable<UpValue> { private Object[] stack; private int index; private boolean isClosed = false; @@ -17,6 +20,23 @@ this.isClosed = true; } + private UpValue() {} + + @Override public UpValue shallowClone() { + return new UpValue(); + } + + @Override public void deepenClone(UpValue clone,DeepCloner cloner) { + clone.isClosed = isClosed; + if( isClosed ) { + clone.value = cloner.get(value); + } else { + clone.stack = stack.clone(); + cloner.deepenClone(clone.stack); + clone.index = index; + } + } + Object get() { return isClosed ? value : stack[index]; } @@ -65,7 +85,7 @@ static final Getter globalGetter = new Getter() { public UpValue get(LuanStateImpl luan) { - return new UpValue(luan.global); + return new UpValue(luan.global()); } };
--- a/src/luan/lib/BasicLib.java Fri Feb 15 04:52:16 2013 +0000 +++ b/src/luan/lib/BasicLib.java Fri Feb 15 09:55:17 2013 +0000 @@ -23,7 +23,7 @@ public static final LuanFunction LOADER = new LuanFunction() { public Object[] call(LuanState luan,Object[] args) throws LuanException { - LuanTable global = luan.global; + LuanTable global = luan.global(); global.put( "_G", global ); try { global.put( "assert", new LuanJavaFunction(BasicLib.class.getMethod("assert_",LuanState.class,Object.class,String.class),null) ); @@ -63,7 +63,7 @@ } public static void make_standard(LuanState luan) { - LuanTable global = luan.global; + LuanTable global = luan.global(); global.put( "dofile", global.get("do_file") ); global.put( "getmetatable", global.get("get_metatable") ); global.put( "loadfile", global.get("load_file") );
--- a/src/luan/lib/HtmlLib.java Fri Feb 15 04:52:16 2013 +0000 +++ b/src/luan/lib/HtmlLib.java Fri Feb 15 09:55:17 2013 +0000 @@ -13,7 +13,7 @@ public static final LuanFunction LOADER = new LuanFunction() { public Object[] call(LuanState luan,Object[] args) { LuanTable module = new LuanTable(); - LuanTable global = luan.global; + LuanTable global = luan.global(); try { add( module, "encode", String.class ); } catch(NoSuchMethodException e) {
--- a/src/luan/lib/HttpLib.java Fri Feb 15 04:52:16 2013 +0000 +++ b/src/luan/lib/HttpLib.java Fri Feb 15 09:55:17 2013 +0000 @@ -23,12 +23,12 @@ public static void service(LuanState luan,HttpServletRequest request,HttpServletResponse response) throws LuanException, IOException { - LuanFunction fn = (LuanFunction)luan.global.get(FN_NAME); + LuanFunction fn = (LuanFunction)luan.global().get(FN_NAME); ServletOutputStream sout = response.getOutputStream(); luan.out = new PrintStream(sout); LuanTable module = new LuanTable(); - luan.global.put(NAME,module); + luan.global().put(NAME,module); LuanTable parameters = new LuanTable(); LuanTable parameter_lists = new LuanTable();
--- a/src/luan/lib/JavaLib.java Fri Feb 15 04:52:16 2013 +0000 +++ b/src/luan/lib/JavaLib.java Fri Feb 15 09:55:17 2013 +0000 @@ -33,7 +33,7 @@ public Object[] call(LuanState luan,Object[] args) throws LuanException { luan.addMetatableGetter(mg); LuanTable module = new LuanTable(); - LuanTable global = luan.global; + LuanTable global = luan.global(); try { global.put( "import", new LuanJavaFunction(JavaLib.class.getMethod("importClass",LuanState.class,String.class),null) ); module.put( "class", new LuanJavaFunction(JavaLib.class.getMethod("getClass",LuanState.class,String.class),null) ); @@ -298,7 +298,7 @@ } public static void importClass(LuanState luan,String name) throws LuanException { - luan.global.put( name.substring(name.lastIndexOf('.')+1), getClass(luan,name) ); + luan.global().put( name.substring(name.lastIndexOf('.')+1), getClass(luan,name) ); } static class AmbiguousJavaFunction extends LuanFunction {
--- a/src/luan/lib/MathLib.java Fri Feb 15 04:52:16 2013 +0000 +++ b/src/luan/lib/MathLib.java Fri Feb 15 09:55:17 2013 +0000 @@ -13,7 +13,7 @@ public static final LuanFunction LOADER = new LuanFunction() { public Object[] call(LuanState luan,Object[] args) { LuanTable module = new LuanTable(); - LuanTable global = luan.global; + LuanTable global = luan.global(); try { add( module, "floor", Double.TYPE ); } catch(NoSuchMethodException e) {
--- a/src/luan/lib/PackageLib.java Fri Feb 15 04:52:16 2013 +0000 +++ b/src/luan/lib/PackageLib.java Fri Feb 15 09:55:17 2013 +0000 @@ -19,10 +19,10 @@ public static final LuanFunction LOADER = new LuanFunction() { public Object[] call(LuanState luan,Object[] args) throws LuanException { - LuanTable global = luan.global; + LuanTable global = luan.global(); LuanTable module = new LuanTable(); - module.put("loaded",luan.loaded); - module.put("preload",luan.preload); + module.put("loaded",luan.loaded()); + module.put("preload",luan.preload()); // module.put("path","?.lua"); try { add( global, "require", LuanState.class, String.class ); @@ -43,11 +43,11 @@ public static void require(LuanState luan,String modName) throws LuanException { Object mod = module(luan,modName); if( mod instanceof LuanTable ) - luan.global.put(modName,mod); + luan.global().put(modName,mod); } public static Object module(LuanState luan,String modName) throws LuanException { - Object mod = luan.loaded.get(modName); + Object mod = luan.loaded().get(modName); if( mod == null ) { LuanTable searchers = (LuanTable)luan.get("package.searchers"); for( Object s : searchers.asList() ) { @@ -59,7 +59,7 @@ mod = Luan.first(luan.call(loader,LuanElement.JAVA,"loader",modName,extra)); if( mod == null ) mod = true; - luan.loaded.put(modName,mod); + luan.loaded().put(modName,mod); } } if( mod == null ) @@ -100,7 +100,7 @@ public static final LuanFunction preloadSearcher = new LuanFunction() { public Object[] call(LuanState luan,Object[] args) throws LuanException { String modName = (String)args[0]; - return new Object[]{luan.preload.get(modName)}; + return new Object[]{luan.preload().get(modName)}; } };
--- a/src/luan/lib/StringLib.java Fri Feb 15 04:52:16 2013 +0000 +++ b/src/luan/lib/StringLib.java Fri Feb 15 09:55:17 2013 +0000 @@ -18,7 +18,7 @@ public static final LuanFunction LOADER = new LuanFunction() { public Object[] call(LuanState luan,Object[] args) throws LuanException { LuanTable module = new LuanTable(); - LuanTable global = luan.global; + LuanTable global = luan.global(); try { module.put( "byte", new LuanJavaFunction(StringLib.class.getMethod("byte_",String.class,Integer.class,Integer.class),null) ); module.put( "char", new LuanJavaFunction(StringLib.class.getMethod("char_",new byte[0].getClass()),null) );
--- a/src/luan/lib/TableLib.java Fri Feb 15 04:52:16 2013 +0000 +++ b/src/luan/lib/TableLib.java Fri Feb 15 09:55:17 2013 +0000 @@ -20,7 +20,7 @@ public static final LuanFunction LOADER = new LuanFunction() { public Object[] call(LuanState luan,Object[] args) throws LuanException { LuanTable module = new LuanTable(); - LuanTable global = luan.global; + LuanTable global = luan.global(); try { add( module, "concat", LuanState.class, LuanTable.class, String.class, Integer.class, Integer.class ); add( module, "insert", LuanState.class, LuanTable.class, Integer.TYPE, Object.class );
--- a/src/luan/tools/CmdLine.java Fri Feb 15 04:52:16 2013 +0000 +++ b/src/luan/tools/CmdLine.java Fri Feb 15 09:55:17 2013 +0000 @@ -65,7 +65,7 @@ for( int j=0; j<args.length; j++ ) { argsTable.put( j, args[j] ); } - luan.global.put("arg",argsTable); + luan.global().put("arg",argsTable); try { LuanFunction fn = BasicLib.load_file(luan,file); luan.call(fn,null,null,varArgs);
--- a/src/luan/tools/WebRun.java Fri Feb 15 04:52:16 2013 +0000 +++ b/src/luan/tools/WebRun.java Fri Feb 15 09:55:17 2013 +0000 @@ -33,8 +33,8 @@ try { LuanState luan = newLuanState(); luan.out = out; - luan.global.put("request",request); - luan.global.put("response",response); + luan.global().put("request",request); + luan.global().put("response",response); luan.eval(code,"WebRun"); } catch(LuanException e) { logger.error(null,e);
--- a/src/luan/tools/WebServlet.java Fri Feb 15 04:52:16 2013 +0000 +++ b/src/luan/tools/WebServlet.java Fri Feb 15 09:55:17 2013 +0000 @@ -25,6 +25,8 @@ public static final String HTTP_SERVER = "http_server"; + protected LuanState luanState = null; + protected void loadLibs(LuanState luan) throws LuanException { luan.load(BasicLib.LOADER,BasicLib.NAME); luan.load(PackageLib.LOADER,PackageLib.NAME); @@ -36,7 +38,7 @@ protected void loadLuan(LuanState luan) throws LuanException { PackageLib.require(luan,HTTP_SERVER); - Object fn = luan.global.get(HttpLib.FN_NAME); + Object fn = luan.global().get(HttpLib.FN_NAME); if( !(fn instanceof LuanFunction) ) throw new LuanException( luan, LuanElement.JAVA, "function '"+HttpLib.FN_NAME+"' not defined" ); } @@ -48,8 +50,12 @@ return luan; } - protected LuanState getLuanState() throws LuanException { - return newLuanState(); + protected LuanState getLuanState() throws LuanException { + synchronized(this) { + if( luanState == null ) + luanState = newLuanState(); + } + return luanState.deepClone(); } protected void service(HttpServletRequest request,HttpServletResponse response)
--- a/src/luan/tools/WebShell.java Fri Feb 15 04:52:16 2013 +0000 +++ b/src/luan/tools/WebShell.java Fri Feb 15 09:55:17 2013 +0000 @@ -59,8 +59,8 @@ session.putValue("luan",luan); } luan.out = new PrintStream(history); - luan.global.put("request",request); - luan.global.put("response",response); + luan.global().put("request",request); + luan.global().put("response",response); Object[] result = eval(luan,cmd); if( result.length > 0 ) { for( int i=0; i<result.length; i++ ) {