Mercurial Hosting > luan
changeset 195:24ede40ee0aa
make MetatableGetter DeepCloneable, scoped, and secure
git-svn-id: https://luan-java.googlecode.com/svn/trunk@196 21e917c8-12df-6dd8-5cb6-c86387c605b9
author | fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9> |
---|---|
date | Thu, 03 Jul 2014 08:19:48 +0000 |
parents | 08df375e2e5f |
children | be0275bda373 |
files | core/src/luan/DeepCloner.java core/src/luan/LuanState.java core/src/luan/LuanTable.java core/src/luan/MetatableGetter.java core/src/luan/impl/Closure.java core/src/luan/impl/ConstExpr.java core/src/luan/impl/FnDef.java core/src/luan/impl/LuanCompiler.java core/src/luan/impl/LuanParser.java core/src/luan/impl/LuanStateImpl.java core/src/luan/impl/MtGetterLink.java core/src/luan/modules/JavaLuan.java core/src/luan/modules/PackageLuan.java core/src/luan/modules/StringLuan.java web/src/luan/modules/web/Web_server.luan |
diffstat | 15 files changed, 207 insertions(+), 82 deletions(-) [+] |
line wrap: on
line diff
--- a/core/src/luan/DeepCloner.java Wed Jul 02 04:52:25 2014 +0000 +++ b/core/src/luan/DeepCloner.java Thu Jul 03 08:19:48 2014 +0000 @@ -8,6 +8,8 @@ private final Map<Object,Object> cloned = new IdentityHashMap<Object,Object>(); public <T extends DeepCloneable<T>> T deepClone(T obj) { + if( obj==null ) + return null; @SuppressWarnings("unchecked") T rtn = (T)cloned.get(obj); if( rtn == null ) {
--- a/core/src/luan/LuanState.java Wed Jul 02 04:52:25 2014 +0000 +++ b/core/src/luan/LuanState.java Thu Jul 03 08:19:48 2014 +0000 @@ -57,7 +57,6 @@ private LuanTable preload; private LuanTable searchers; - private final List<MetatableGetter> mtGetters; final List<StackTraceElement> stackTrace = new ArrayList<StackTraceElement>(); protected LuanState() { @@ -66,11 +65,6 @@ loaded = new LuanTable(); preload = new LuanTable(); searchers = new LuanTable(); - mtGetters = new ArrayList<MetatableGetter>(); - } - - protected LuanState(LuanState luan) { - mtGetters = new ArrayList<MetatableGetter>(luan.mtGetters); } @Override public void deepenClone(LuanState clone,DeepCloner cloner) { @@ -146,21 +140,12 @@ } public final LuanTable getMetatable(Object obj) { - if( obj instanceof LuanTable ) { - LuanTable table = (LuanTable)obj; - return table.getMetatable(); - } - for( MetatableGetter mg : mtGetters ) { - LuanTable table = mg.getMetatable(obj); - if( table != null ) - return table; - } - return null; + return getMetatable(obj,null); } - public final void addMetatableGetter(MetatableGetter mg) { - mtGetters.add(mg); - } + public abstract LuanTable getMetatable(Object obj,MetatableGetter beforeThis); + + public abstract void addMetatableGetter(MetatableGetter mg); public final LuanBit bit(LuanElement el) { return new LuanBit(this,el);
--- a/core/src/luan/LuanTable.java Wed Jul 02 04:52:25 2014 +0000 +++ b/core/src/luan/LuanTable.java Thu Jul 03 08:19:48 2014 +0000 @@ -18,6 +18,7 @@ private Map<Object,Object> map = null; private List<Object> list = null; private LuanTable metatable = null; + public MetatableGetter metatableGetter = null; // used for modules public LuanTable() {} @@ -62,6 +63,7 @@ } @Override public void deepenClone(LuanTable clone,DeepCloner cloner) { + clone.metatableGetter = this.metatableGetter; if( map != null ) { clone.map = new HashMap<Object,Object>(); for( Map.Entry<Object,Object> entry : map.entrySet() ) {
--- a/core/src/luan/MetatableGetter.java Wed Jul 02 04:52:25 2014 +0000 +++ b/core/src/luan/MetatableGetter.java Thu Jul 03 08:19:48 2014 +0000 @@ -1,5 +1,5 @@ package luan; -public interface MetatableGetter { +public interface MetatableGetter extends DeepCloneable<MetatableGetter> { public LuanTable getMetatable(Object obj); }
--- a/core/src/luan/impl/Closure.java Wed Jul 02 04:52:25 2014 +0000 +++ b/core/src/luan/impl/Closure.java Thu Jul 03 08:19:48 2014 +0000 @@ -11,12 +11,14 @@ final class Closure extends LuanFunction implements DeepCloneable<Closure> { private final FnDef fnDef; + private MtGetterLink mtGetterLink; private UpValue[] upValues; - Closure(LuanStateImpl luan,FnDef fnDef) throws LuanException { + Closure(LuanStateImpl luan,FnDef fnDef,MtGetterLink mtGetterLink) throws LuanException { this.fnDef = fnDef; + this.mtGetterLink = mtGetterLink; UpValue.Getter[] upValueGetters = fnDef.upValueGetters; - upValues = new UpValue[upValueGetters.length]; + this.upValues = new UpValue[upValueGetters.length]; for( int i=0; i<upValues.length; i++ ) { upValues[i] = upValueGetters[i].get(luan); } @@ -31,9 +33,14 @@ } @Override public void deepenClone(Closure clone,DeepCloner cloner) { + clone.mtGetterLink = cloner.deepClone(mtGetterLink); clone.upValues = cloner.deepClone(upValues); } + MtGetterLink mtGetterLink() { + return mtGetterLink; + } + UpValue[] upValues() { return upValues; }
--- a/core/src/luan/impl/ConstExpr.java Wed Jul 02 04:52:25 2014 +0000 +++ b/core/src/luan/impl/ConstExpr.java Thu Jul 03 08:19:48 2014 +0000 @@ -6,10 +6,6 @@ final class ConstExpr extends CodeImpl implements Expr { private final Object obj; - ConstExpr(Object obj) { - this(null,obj); - } - ConstExpr(LuanSource.Element se,Object obj) { super(se); this.obj = obj;
--- a/core/src/luan/impl/FnDef.java Wed Jul 02 04:52:25 2014 +0000 +++ b/core/src/luan/impl/FnDef.java Thu Jul 03 08:19:48 2014 +0000 @@ -36,7 +36,7 @@ } @Override public Object eval(LuanStateImpl luan) throws LuanException { - return new Closure(luan,this); + return new Closure(luan,this,luan.mtGetterLink()); } }
--- a/core/src/luan/impl/LuanCompiler.java Wed Jul 02 04:52:25 2014 +0000 +++ b/core/src/luan/impl/LuanCompiler.java Thu Jul 03 08:19:48 2014 +0000 @@ -24,17 +24,28 @@ parser.addVar( (String)key, entry.getValue() ); } FnDef fnDef = parse(luan,parser,allowExpr); - if( passedEnv ) - return new Closure((LuanStateImpl)luan,fnDef); - final Closure c = new Closure((LuanStateImpl)luan,fnDef); - return new LuanFunction() { - @Override public Object call(LuanState luan,Object[] args) throws LuanException { - Object rtn = c.call(luan,args); - if( rtn instanceof Object[] && ((Object[])rtn).length==0 ) - rtn = c.upValues()[0].get(); - return rtn; - } - }; + final LuanStateImpl luanImpl = (LuanStateImpl)luan; + MtGetterLink mtGetterLink = (MtGetterLink)env.get("_MTG"); + final Closure c = new Closure(luanImpl,fnDef,mtGetterLink); + final LuanTable ENV = env; + if( passedEnv ) { + return new LuanFunction() { + @Override public Object call(LuanState luan,Object[] args) throws LuanException { + Object rtn = c.call(luan,args); + ENV.put("_MTG",luanImpl.mtGetterLink); + return rtn; + } + }; + } else { + return new LuanFunction() { + @Override public Object call(LuanState luan,Object[] args) throws LuanException { + Object rtn = c.call(luan,args); + if( rtn instanceof Object[] && ((Object[])rtn).length==0 ) + rtn = ENV; + return rtn; + } + }; + } } private static FnDef parse(LuanState luan,LuanParser parser,boolean allowExpr) throws LuanException {
--- a/core/src/luan/impl/LuanParser.java Wed Jul 02 04:52:25 2014 +0000 +++ b/core/src/luan/impl/LuanParser.java Thu Jul 03 08:19:48 2014 +0000 @@ -272,8 +272,10 @@ if( exp == null ) return null; Expr fnExp = (Expr)nameVar(start,"Io").expr(); - fnExp = new IndexExpr( se(start,"stdout"), fnExp, new ConstExpr("stdout") ); - fnExp = new IndexExpr( se(start,"write"), fnExp, new ConstExpr("write") ); + LuanSource.Element se = se(start,"stdout"); + fnExp = new IndexExpr( se, fnExp, new ConstExpr(se,"stdout") ); + se = se(start,"write"); + fnExp = new IndexExpr( se, fnExp, new ConstExpr(se,"write") ); FnCall fnCall = new FnCall( se(start), fnExp, exp ); return new ExpressionsStmt(fnCall); } @@ -304,7 +306,7 @@ throw parser.exception("Unclosed template expression"); } while( !parser.test( "<%" ) ); String match = parser.textFrom(i); - builder.add( new ConstExpr(match) ); + builder.add( new ConstExpr(se(i),match) ); } } } @@ -360,7 +362,7 @@ if( !isValidName(varName) ) throw parser.exception("invalid variable name '"+varName+"' in import"); LuanSource.Element se = se(start); - FnCall require = new FnCall( se, new ConstExpr(se,PackageLuan.requireFn), new ConstExpr(modName) ); + FnCall require = new FnCall( se, new ConstExpr(se,PackageLuan.requireFn), new ConstExpr(se(start,modName),modName) ); Settable settable; if( interactive ) { settable = nameVar(se,varName).settable(); @@ -974,7 +976,7 @@ index = upValueIndex(name); if( index != -1 ) return new GetUpVar(se,index); - return new IndexExpr( se, env(), new ConstExpr(name) ); + return new IndexExpr( se, env(), new ConstExpr(se,name) ); } public Settable settable() { @@ -984,7 +986,7 @@ index = upValueIndex(name); if( index != -1 ) return new SetUpVar(index); - return new SetTableEntry( se, env(), new ConstExpr(name) ); + return new SetTableEntry( se, env(), new ConstExpr(se,name) ); } }; } @@ -1023,6 +1025,7 @@ } private boolean args(In in,List<Expressions> builder) throws ParseException { + int start = parser.begin(); if( parser.match('(') ) { In inParens = in.parens(); Spaces(inParens); @@ -1030,26 +1033,26 @@ if( !parser.match(')') ) throw parser.exception("Expression or ')' expected"); Spaces(in); - return true; + return parser.success(); } Expr exp = TableExpr(in); if( exp != null ) { builder.add(exp); - return true; + return parser.success(); } String s = StringLiteral(in); if( s != null ) { - builder.add( new ConstExpr(s) ); - return true; + builder.add( new ConstExpr(se(start),s) ); + return parser.success(); } /* Expressions exps = TemplateExpressions(in); if( exps != null ) { builder.add(exps); - return true; + return parser.success(); } */ - return false; + return parser.failure(); } private Expressions ExpList(In in) throws ParseException { @@ -1093,8 +1096,11 @@ } private Expr NameExpr(In in) throws ParseException { + int start = parser.begin(); String name = Name(in); - return name==null ? null : new ConstExpr(name); + if( name==null ) + return parser.failure(null); + return parser.success(new ConstExpr(se(start),name)); } private String RequiredName(In in) throws ParseException { @@ -1177,18 +1183,19 @@ )); private Expr Literal(In in) throws ParseException { + int start = parser.begin(); if( NilLiteral(in) ) - return new ConstExpr(null); + return parser.success(new ConstExpr(se(start),null)); Boolean b = BooleanLiteral(in); if( b != null ) - return new ConstExpr(b); + return parser.success(new ConstExpr(se(start),b)); Number n = NumberLiteral(in); if( n != null ) - return new ConstExpr(n); + return parser.success(new ConstExpr(se(start),n)); String s = StringLiteral(in); if( s != null ) - return new ConstExpr(s); - return null; + return parser.success(new ConstExpr(se(start),s)); + return parser.failure(null); } private boolean NilLiteral(In in) throws ParseException {
--- a/core/src/luan/impl/LuanStateImpl.java Wed Jul 02 04:52:25 2014 +0000 +++ b/core/src/luan/impl/LuanStateImpl.java Thu Jul 03 08:19:48 2014 +0000 @@ -21,6 +21,7 @@ final Closure closure; final Object[] stack; final Object[] varArgs; + MtGetterLink mtGetterLink; UpValue[] downValues = null; Frame( Frame previousFrame, Closure closure, int stackSize, Object[] varArgs) { @@ -28,6 +29,7 @@ this.closure = closure; this.stack = new Object[stackSize]; this.varArgs = varArgs; + this.mtGetterLink = closure.mtGetterLink(); } void stackClear(int start,int end) { @@ -52,22 +54,24 @@ downValues[index] = new UpValue(stack,index); return downValues[index]; } + + void addMetatableGetter(MetatableGetter mg) { + if( mtGetterLink==null || !mtGetterLink.contains(mg) ) + mtGetterLink = new MtGetterLink(mg,mtGetterLink); + } } private Frame frame = null; Object returnValues; Closure tailFn; + MtGetterLink mtGetterLink = null; 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); + return new LuanStateImpl(); } // returns stack @@ -81,6 +85,7 @@ void popFrame() { returnValues = LuanFunction.NOTHING; tailFn = null; + mtGetterLink = frame.mtGetterLink; frame = frame.previousFrame; } @@ -114,4 +119,21 @@ return (LuanTable)frame.closure.upValues()[0].get(); } + MtGetterLink mtGetterLink() { + return frame==null ? null : frame.mtGetterLink; + } + + @Override public LuanTable getMetatable(Object obj,MetatableGetter beforeThis) { + if( obj instanceof LuanTable ) { + LuanTable table = (LuanTable)obj; + return table.getMetatable(); + } + MtGetterLink mtGetterLink = mtGetterLink(); + return mtGetterLink==null ? null : mtGetterLink.getMetatable(obj,beforeThis); + } + + @Override public void addMetatableGetter(MetatableGetter mg) { + frame.addMetatableGetter(mg); + } + }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/MtGetterLink.java Thu Jul 03 08:19:48 2014 +0000 @@ -0,0 +1,44 @@ +package luan.impl; + +import luan.MetatableGetter; +import luan.LuanTable; +import luan.DeepCloneable; +import luan.DeepCloner; + + +final class MtGetterLink implements DeepCloneable<MtGetterLink> { + private MetatableGetter mg; + private MtGetterLink next; + + private MtGetterLink() {} + + MtGetterLink(MetatableGetter mg,MtGetterLink next) { + this.mg = mg; + this.next = next; + } + + LuanTable getMetatable(Object obj,MetatableGetter beforeThis) { + if( beforeThis != null ) { + if( beforeThis==mg ) + beforeThis = null; + } else { + LuanTable mt = mg.getMetatable(obj); + if( mt != null ) + return mt; + } + return next==null ? null : next.getMetatable(obj,beforeThis); + } + + boolean contains(MetatableGetter mg) { + return this.mg==mg || next!=null && next.contains(mg); + } + + @Override public MtGetterLink shallowClone() { + return new MtGetterLink(); + } + + @Override public void deepenClone(MtGetterLink clone,DeepCloner cloner) { + clone.mg = cloner.deepClone(mg); + clone.next = cloner.deepClone(next); + } +}
--- a/core/src/luan/modules/JavaLuan.java Wed Jul 02 04:52:25 2014 +0000 +++ b/core/src/luan/modules/JavaLuan.java Thu Jul 03 08:19:48 2014 +0000 @@ -24,14 +24,15 @@ import luan.LuanFunction; import luan.LuanJavaFunction; import luan.LuanElement; +import luan.DeepCloner; public final class JavaLuan { public static final LuanFunction LOADER = new LuanFunction() { @Override public Object call(LuanState luan,Object[] args) { - luan.addMetatableGetter(mg); LuanTable module = new LuanTable(); + module.metatableGetter = mg; try { module.put( "class", new LuanJavaFunction(JavaLuan.class.getMethod("getClass",LuanState.class,String.class),null) ); add( module, "proxy", LuanState.class, Static.class, LuanTable.class, Object.class ); @@ -73,14 +74,30 @@ } private static final MetatableGetter mg = new MetatableGetter() { + public LuanTable getMetatable(Object obj) { if( obj==null ) return null; return mt; } + + @Override public MetatableGetter shallowClone() { + return this; + } + @Override public void deepenClone(MetatableGetter clone,DeepCloner cloner) {} }; public static Object __index(LuanState luan,Object obj,Object key) throws LuanException { + LuanTable mt = luan.getMetatable(obj,mg); + if( mt != null ) { + Object h = mt.get("__index"); + if( h instanceof LuanFunction ) { + LuanFunction fn = (LuanFunction)h; + Object rtn = Luan.first(luan.call(fn,new Object[]{obj,key})); + if( rtn != null ) + return rtn; + } + } if( obj instanceof Static ) { if( key instanceof String ) { String name = (String)key;
--- a/core/src/luan/modules/PackageLuan.java Wed Jul 02 04:52:25 2014 +0000 +++ b/core/src/luan/modules/PackageLuan.java Thu Jul 03 08:19:48 2014 +0000 @@ -82,6 +82,11 @@ } } } + if( mod instanceof LuanTable ) { + LuanTable modTbl = (LuanTable)mod; + if( modTbl.metatableGetter != null ) + luan.addMetatableGetter(modTbl.metatableGetter); + } return mod; }
--- a/core/src/luan/modules/StringLuan.java Wed Jul 02 04:52:25 2014 +0000 +++ b/core/src/luan/modules/StringLuan.java Thu Jul 03 08:19:48 2014 +0000 @@ -10,14 +10,15 @@ import luan.LuanElement; import luan.LuanException; import luan.MetatableGetter; +import luan.DeepCloner; public final class StringLuan { public static final LuanFunction LOADER = new LuanFunction() { @Override public Object call(LuanState luan,Object[] args) { - luan.addMetatableGetter(mg); LuanTable module = new LuanTable(); + module.metatableGetter = new MyMetatableGetter(module); try { add( module, "to_binary", String.class ); add( module, "to_integers", String.class ); @@ -44,25 +45,23 @@ t.put( method, new LuanJavaFunction(StringLuan.class.getMethod(method,parameterTypes),null) ); } - private static final LuanTable mt = new LuanTable(); - static { - try { - add( mt, "__index", LuanState.class, String.class, Object.class ); - } catch(NoSuchMethodException e) { - throw new RuntimeException(e); - } - } + public static class MyMetatableGetter implements MetatableGetter { + private LuanTable module; + private LuanTable metatable; + + private MyMetatableGetter() {} - private static final MetatableGetter mg = new MetatableGetter() { - public LuanTable getMetatable(Object obj) { - return obj instanceof String ? mt : null; + MyMetatableGetter(LuanTable module) { + this.module = module; + this.metatable = table(); } - }; - public static Object __index(LuanState luan,final String s,Object key) throws LuanException { - LuanTable mod = (LuanTable)luan.loaded().get("String"); - if( mod!=null ) { - Object obj = mod.get(key); + @Override public LuanTable getMetatable(Object obj) { + return obj instanceof String ? metatable : null; + } + + public Object __index(LuanState luan,final String s,Object key) throws LuanException { + Object obj = module.get(key); if( obj instanceof LuanFunction ) { final LuanFunction fn = (LuanFunction)obj; return new LuanFunction() { @@ -74,10 +73,37 @@ } }; } + LuanTable mt = luan.getMetatable(s,this); + if( mt == null ) + return null; + Object h = mt.get("__index"); + if( !(h instanceof LuanFunction) ) + return null; + LuanFunction fn = (LuanFunction)h; + return luan.call(fn,new Object[]{s,key}); } - if( luan.loaded().get("Java") != null ) - return JavaLuan.__index(luan,s,key); - return null; + + LuanTable table() { + LuanTable tbl = new LuanTable(); + try { + tbl.put( "__index", new LuanJavaFunction( + MyMetatableGetter.class.getMethod( "__index", LuanState.class, String.class, Object.class ), this + ) ); + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + return tbl; + } + + @Override public MetatableGetter shallowClone() { + return new MyMetatableGetter(); + } + + @Override public void deepenClone(MetatableGetter c,DeepCloner cloner) { + MyMetatableGetter clone = (MyMetatableGetter)c; + clone.module = cloner.deepClone(module); + clone.metatable = clone.table(); + } } static int start(String s,int i) {