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];
+		}
+	}
+
+}