Mercurial Hosting > luan
changeset 32:c3eab5a3ce3c
implement closures
git-svn-id: https://luan-java.googlecode.com/svn/trunk@33 21e917c8-12df-6dd8-5cb6-c86387c605b9
author | fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9> |
---|---|
date | Fri, 14 Dec 2012 05:40:35 +0000 |
parents | 5cf15507d77e |
children | 8793c71ad47a |
files | src/luan/interp/Block.java src/luan/interp/Chunk.java src/luan/interp/GenericForStmt.java src/luan/interp/GetLocalVar.java src/luan/interp/GetUpVar.java src/luan/interp/LuaClosure.java src/luan/interp/LuaParser.java src/luan/interp/LuaStateImpl.java src/luan/interp/NumericForStmt.java src/luan/interp/SetLocalVar.java src/luan/interp/SetUpVar.java src/luan/interp/UpValue.java |
diffstat | 12 files changed, 245 insertions(+), 78 deletions(-) [+] |
line wrap: on
line diff
--- a/src/luan/interp/Block.java Thu Dec 13 02:50:04 2012 +0000 +++ b/src/luan/interp/Block.java Fri Dec 14 05:40:35 2012 +0000 @@ -22,10 +22,7 @@ stmt.eval(lua); } } finally { - Object[] stack = lua.stack(); - for( int i=stackStart; i<stackEnd; i++ ) { - stack[i] = null; - } + lua.stackClear(stackStart,stackEnd); } }
--- a/src/luan/interp/Chunk.java Thu Dec 13 02:50:04 2012 +0000 +++ b/src/luan/interp/Chunk.java Fri Dec 14 05:40:35 2012 +0000 @@ -4,16 +4,18 @@ final class Chunk implements Expr { - public final Stmt block; - public final int stackSize; - public final int numArgs; - public final boolean isVarArg; + final Stmt block; + final int stackSize; + final int numArgs; + final boolean isVarArg; + final UpValue.Getter[] upValueGetters; - Chunk(Stmt block,int stackSize,int numArgs,boolean isVarArg) { + Chunk(Stmt block,int stackSize,int numArgs,boolean isVarArg,UpValue.Getter[] upValueGetters) { this.block = block; this.stackSize = stackSize; this.numArgs = numArgs; this.isVarArg = isVarArg; + this.upValueGetters = upValueGetters; fixReturns(block); }
--- a/src/luan/interp/GenericForStmt.java Thu Dec 13 02:50:04 2012 +0000 +++ b/src/luan/interp/GenericForStmt.java Fri Dec 14 05:40:35 2012 +0000 @@ -20,22 +20,19 @@ @Override public void eval(LuaStateImpl lua) throws LuaException { LuaFunction iter = Lua.checkFunction( iterExpr.eval(lua) ); - Object[] stack = lua.stack(); try { while(true) { Object[] vals = iter.call(lua); if( vals.length==0 || vals[0]==null ) break; for( int i=0; i<nVars; i++ ) { - stack[iVars+i] = i < vals.length ? vals[i] : null; + lua.stackSet( iVars+i, i < vals.length ? vals[i] : null ); } block.eval(lua); } } catch(BreakException e) { } finally { - for( int i=iVars; i<iVars+nVars; i++ ) { - stack[i] = null; - } + lua.stackClear(iVars,iVars+nVars); } }
--- a/src/luan/interp/GetLocalVar.java Thu Dec 13 02:50:04 2012 +0000 +++ b/src/luan/interp/GetLocalVar.java Fri Dec 14 05:40:35 2012 +0000 @@ -9,6 +9,6 @@ } @Override public Object eval(LuaStateImpl lua) { - return lua.stack()[index]; + return lua.stackGet(index); } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/interp/GetUpVar.java Fri Dec 14 05:40:35 2012 +0000 @@ -0,0 +1,14 @@ +package luan.interp; + + +final class GetUpVar implements Expr { + private final int index; + + GetUpVar(int index) { + this.index = index; + } + + @Override public Object eval(LuaStateImpl lua) { + return lua.closure().upValues[index].get(); + } +}
--- a/src/luan/interp/LuaClosure.java Thu Dec 13 02:50:04 2012 +0000 +++ b/src/luan/interp/LuaClosure.java Fri Dec 14 05:40:35 2012 +0000 @@ -7,15 +7,29 @@ final class LuaClosure extends LuaFunction { private final Chunk chunk; + final UpValue[] upValues; + private final static UpValue[] NO_UP_VALUES = new UpValue[0]; LuaClosure(Chunk chunk,LuaStateImpl lua) { this.chunk = chunk; + UpValue.Getter[] upValueGetters = chunk.upValueGetters; + if( upValueGetters.length==0 ) { + upValues = NO_UP_VALUES; + } else { + upValues = new UpValue[upValueGetters.length]; + for( int i=0; i<upValues.length; i++ ) { + upValues[i] = upValueGetters[i].get(lua); + } + } } - public Object[] call(LuaState luaState,Object... args) throws LuaException { - LuaStateImpl lua = (LuaStateImpl)luaState; - Chunk chunk = this.chunk; + public Object[] call(LuaState lua,Object... args) throws LuaException { + return call(this,(LuaStateImpl)lua,args); + } + + private static Object[] call(LuaClosure closure,LuaStateImpl lua,Object[] args) throws LuaException { while(true) { + Chunk chunk = closure.chunk; Object[] varArgs = null; if( chunk.isVarArg ) { if( args.length > chunk.numArgs ) { @@ -27,7 +41,7 @@ varArgs = LuaFunction.EMPTY_RTN; } } - Object[] stack = lua.newStack(chunk.stackSize,varArgs); + Object[] stack = lua.newFrame(closure,chunk.stackSize,varArgs); final int n = Math.min(args.length,chunk.numArgs); for( int i=0; i<n; i++ ) { stack[i] = args[i]; @@ -39,12 +53,11 @@ } catch(ReturnException e) { } finally { returnValues = lua.returnValues; - tailFn = lua.tailFn; - lua.popStack(); + closure = lua.tailFn; + lua.popFrame(); } - if( tailFn == null ) + if( closure == null ) return returnValues; - chunk = tailFn.chunk; args = returnValues; } }
--- a/src/luan/interp/LuaParser.java Thu Dec 13 02:50:04 2012 +0000 +++ b/src/luan/interp/LuaParser.java Fri Dec 14 05:40:35 2012 +0000 @@ -29,12 +29,46 @@ int stackSize = 0; int loops = 0; boolean isVarArg = false; + final List<String> upValueSymbols = new ArrayList<String>(); + final List<UpValue.Getter> upValueGetters = new ArrayList<UpValue.Getter>(); Frame(Frame parent) { this.parent = parent; } + + int stackIndex(String name) { + int i = symbols.size(); + while( --i >= 0 ) { + if( symbols.get(i).equals(name) ) + return i; + } + return -1; + } + + int upValueIndex(String name) { + int i = upValueSymbols.size(); + while( --i >= 0 ) { + if( upValueSymbols.get(i).equals(name) ) + return i; + } + if( parent==null ) + return -1; + i = parent.stackIndex(name); + if( i != -1 ) { + upValueGetters.add(new UpValue.StackGetter(i)); + } else { + i = parent.upValueIndex(name); + if( i == -1 ) + return -1; + upValueGetters.add(new UpValue.NestedGetter(i)); + } + upValueSymbols.add(name); + return upValueSymbols.size() - 1; + } } + static final UpValue.Getter[] NO_UP_VALUE_GETTERS = new UpValue.Getter[0]; + int nEquals; int parens = 0; Frame frame = new Frame(null); @@ -76,14 +110,8 @@ return true; } - int index(String name) { - List<String> symbols = frame.symbols; - int i = symbols.size(); - while( --i >= 0 ) { - if( symbols.get(i).equals(name) ) - return i; - } - return -1; + int stackIndex(String name) { + return frame.stackIndex(name); } boolean popSymbols(int n) { @@ -94,6 +122,10 @@ return true; } + int upValueIndex(String name) { + return frame.upValueIndex(name); + } + boolean incLoops() { frame.loops++; return true; @@ -104,6 +136,9 @@ return true; } + Chunk newChunk() { + return new Chunk( (Stmt)pop(), frame.stackSize, symbolsSize(), frame.isVarArg, frame.upValueGetters.toArray(NO_UP_VALUE_GETTERS) ); + } Rule Target() { return Sequence( @@ -114,7 +149,7 @@ action( frame.isVarArg = true ), Block(), EOI, - push( new Chunk( (Stmt)pop(), frame.stackSize, 0, frame.isVarArg ) ) + push( newChunk() ) ) ) ); @@ -386,20 +421,19 @@ if( obj2==null ) return false; Object obj1 = pop(); - if( obj1==null ) { - String name = (String)obj2; - int index = index(name); - if( index == -1 ) { - push( new SetTableEntry( EnvExpr.INSTANCE, new ConstExpr(name) ) ); - } else { - push( new SetLocalVar(index) ); - } - } else { + if( obj1!=null ) { Expr key = expr(obj2); Expr table = expr(obj1); - push( new SetTableEntry(table,key) ); + return push( new SetTableEntry(table,key) ); } - return true; + String name = (String)obj2; + int index = stackIndex(name); + if( index != -1 ) + return push( new SetLocalVar(index) ); + index = upValueIndex(name); + if( index != -1 ) + return push( new SetUpVar(index) ); + return push( new SetTableEntry( EnvExpr.INSTANCE, new ConstExpr(name) ) ); } Rule Expr() { @@ -515,7 +549,7 @@ ) ), ')', decParens(), Spaces(), Block(), Keyword("end"), - push( new Chunk( (Stmt)pop(), frame.stackSize, symbolsSize(), frame.isVarArg ) ), + push( newChunk() ), action( frame = frame.parent ) ); } @@ -617,16 +651,16 @@ if( obj2==null ) return true; Object obj1 = pop(); - if( obj1==null ) { - String name = (String)obj2; - int index = index(name); - if( index == -1 ) { - return push( new GetExpr( EnvExpr.INSTANCE, new ConstExpr(name) ) ); - } else { - return push( new GetLocalVar(index) ); - } - } - return push( new GetExpr( expr(obj1), expr(obj2) ) ); + if( obj1 != null ) + return push( new GetExpr( expr(obj1), expr(obj2) ) ); + String name = (String)obj2; + int index = stackIndex(name); + if( index != -1 ) + return push( new GetLocalVar(index) ); + index = upValueIndex(name); + if( index != -1 ) + return push( new GetUpVar(index) ); + return push( new GetExpr( EnvExpr.INSTANCE, new ConstExpr(name) ) ); } // function should be on top of the stack
--- a/src/luan/interp/LuaStateImpl.java Thu Dec 13 02:50:04 2012 +0000 +++ b/src/luan/interp/LuaStateImpl.java Fri Dec 14 05:40:35 2012 +0000 @@ -8,43 +8,86 @@ final class LuaStateImpl implements LuaState { private final LuaTable env = new LuaTable(); - public LuaTable env() { + @Override public LuaTable env() { return env; } - private static class LuaStack { - final LuaStack previousStack; - final Object[] a; + private static class Frame { + final Frame previousFrame; + final LuaClosure closure; + final Object[] stack; final Object[] varArgs; + UpValue[] downValues = null; + + Frame( Frame previousFrame, LuaClosure closure, int stackSize, Object[] varArgs) { + this.previousFrame = previousFrame; + this.closure = closure; + this.stack = new Object[stackSize]; + this.varArgs = varArgs; + } - LuaStack( LuaStack previousStack, int stackSize, Object[] varArgs) { - this.previousStack = previousStack; - this.a = new Object[stackSize]; - this.varArgs = varArgs; + void stackClear(int start,int end) { + if( downValues != null ) { + for( int i=start; i<end; i++ ) { + UpValue downValue = downValues[i]; + if( downValue != null ) { + downValue.close(); + downValues[i] = null; + } + } + } + for( int i=start; i<end; i++ ) { + stack[i] = null; + } + } + + UpValue getUpValue(int index) { + if( downValues==null ) + downValues = new UpValue[stack.length]; + if( downValues[index] == null ) + downValues[index] = new UpValue(stack,index); + return downValues[index]; } } - private LuaStack stack = null; - public Object[] returnValues; - public LuaClosure tailFn; + private Frame frame = null; + Object[] returnValues; + LuaClosure tailFn; - Object[] newStack(int stackSize, Object[] varArgs) { - stack = new LuaStack(stack,stackSize,varArgs); - return stack.a; + // returns stack + Object[] newFrame(LuaClosure closure, int stackSize, Object[] varArgs) { + frame = new Frame(frame,closure,stackSize,varArgs); + return frame.stack; } - void popStack() { + void popFrame() { returnValues = LuaFunction.EMPTY_RTN; tailFn = null; - stack = stack.previousStack; + frame = frame.previousFrame; + } + + Object stackGet(int index) { + return frame.stack[index]; + } + + void stackSet(int index,Object value) { + frame.stack[index] = value; } - public Object[] stack() { - return stack.a; + void stackClear(int start,int end) { + frame.stackClear(start,end); + } + + Object[] varArgs() { + return frame.varArgs; } - public Object[] varArgs() { - return stack.varArgs; + LuaClosure closure() { + return frame.closure; + } + + UpValue getUpValue(int index) { + return frame.getUpValue(index); } }
--- a/src/luan/interp/NumericForStmt.java Thu Dec 13 02:50:04 2012 +0000 +++ b/src/luan/interp/NumericForStmt.java Fri Dec 14 05:40:35 2012 +0000 @@ -24,16 +24,15 @@ double v = Lua.checkNumber( fromExpr.eval(lua) ).value(); double limit = Lua.checkNumber( toExpr.eval(lua) ).value(); double step = Lua.checkNumber( stepExpr.eval(lua) ).value(); - Object[] stack = lua.stack(); try { while( step > 0.0 && v <= limit || step < 0.0 && v >= limit ) { - stack[iVar] = new LuaNumber(v); + lua.stackSet( iVar, new LuaNumber(v) ); block.eval(lua); v += step; } } catch(BreakException e) { } finally { - stack[iVar] = null; + lua.stackClear(iVar,iVar+1); } }
--- a/src/luan/interp/SetLocalVar.java Thu Dec 13 02:50:04 2012 +0000 +++ b/src/luan/interp/SetLocalVar.java Fri Dec 14 05:40:35 2012 +0000 @@ -9,6 +9,6 @@ } @Override public void set(LuaStateImpl lua,Object value) { - lua.stack()[index] = value; + lua.stackSet( index, value ); } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/interp/SetUpVar.java Fri Dec 14 05:40:35 2012 +0000 @@ -0,0 +1,14 @@ +package luan.interp; + + +final class SetUpVar implements Settable { + private final int index; + + SetUpVar(int index) { + this.index = index; + } + + @Override public void set(LuaStateImpl lua,Object value) { + lua.closure().upValues[index].set(value); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/interp/UpValue.java Fri Dec 14 05:40:35 2012 +0000 @@ -0,0 +1,54 @@ +package luan.interp; + + +final class UpValue { + private Object[] stack; + private int index; + + UpValue(Object[] stack,int index) { + this.stack = stack; + this.index = index; + } + + Object get() { + return stack[index]; + } + + void set(Object value) { + stack[index] = value; + } + + void close() { + stack = new Object[]{get()}; + index = 0; + } + + static interface Getter { + public UpValue get(LuaStateImpl lua); + } + + static final class StackGetter implements Getter { + private final int index; + + StackGetter(int index) { + this.index = index; + } + + public UpValue get(LuaStateImpl lua) { + return lua.getUpValue(index); + } + } + + static final class NestedGetter implements Getter { + private final int index; + + NestedGetter(int index) { + this.index = index; + } + + public UpValue get(LuaStateImpl lua) { + return lua.closure().upValues[index]; + } + } + +}