changeset 22:1e37f22a34c8

proper tail calls git-svn-id: https://luan-java.googlecode.com/svn/trunk@23 21e917c8-12df-6dd8-5cb6-c86387c605b9
author fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9>
date Wed, 05 Dec 2012 09:03:50 +0000
parents c93d8c781853
children 2446c1755d9b
files src/luan/LuaClosure.java src/luan/LuaState.java src/luan/interp/FnCall.java src/luan/interp/ReturnStmt.java
diffstat 4 files changed, 46 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
diff -r c93d8c781853 -r 1e37f22a34c8 src/luan/LuaClosure.java
--- a/src/luan/LuaClosure.java	Tue Dec 04 09:16:03 2012 +0000
+++ b/src/luan/LuaClosure.java	Wed Dec 05 09:03:50 2012 +0000
@@ -12,18 +12,28 @@
 	}
 
 	public Object[] call(LuaState lua,Object... args) throws LuaException {
-		Object[] stack = lua.newStack(chunk.stackSize);
-		final int n = Math.min(args.length,chunk.numArgs);
-		for( int i=0; i<n; i++ ) {
-			stack[i] = args[i];
+		Chunk chunk = this.chunk;
+		while(true) {
+			Object[] stack = lua.newStack(chunk.stackSize);
+			final int n = Math.min(args.length,chunk.numArgs);
+			for( int i=0; i<n; i++ ) {
+				stack[i] = args[i];
+			}
+			Object[] returnValues;
+			LuaClosure tailFn;
+			try {
+				chunk.block.eval(lua);
+			} catch(ReturnException e) {
+			} finally {
+				returnValues = lua.returnValues;
+				tailFn = lua.tailFn;
+				lua.popStack();
+			}
+			if( tailFn == null )
+				return returnValues;
+			chunk = tailFn.chunk;
+			args = returnValues;
 		}
-		try {
-			chunk.block.eval(lua);
-		} catch(ReturnException e) {
-		} finally {
-			lua.popStack();
-		}
-		return lua.returnValues;
 	}
 
 }
diff -r c93d8c781853 -r 1e37f22a34c8 src/luan/LuaState.java
--- a/src/luan/LuaState.java	Tue Dec 04 09:16:03 2012 +0000
+++ b/src/luan/LuaState.java	Wed Dec 05 09:03:50 2012 +0000
@@ -21,14 +21,16 @@
 
 	private LuaStack stack = null;
 	public Object[] returnValues;
+	public LuaClosure tailFn;
 
 	Object[] newStack(int stackSize) {
-		returnValues = LuaFunction.EMPTY_RTN;
 		stack = new LuaStack(stack,stackSize);
 		return stack.a;
 	}
 
 	void popStack() {
+		returnValues = LuaFunction.EMPTY_RTN;
+		tailFn = null;
 		stack = stack.previousStack;
 	}
 
diff -r c93d8c781853 -r 1e37f22a34c8 src/luan/interp/FnCall.java
--- a/src/luan/interp/FnCall.java	Tue Dec 04 09:16:03 2012 +0000
+++ b/src/luan/interp/FnCall.java	Wed Dec 05 09:03:50 2012 +0000
@@ -7,8 +7,8 @@
 
 
 final class FnCall implements Expressions {
-	private final Expr fnExpr;
-	private final Expressions args;
+	final Expr fnExpr;
+	final Expressions args;
 
 	FnCall(Expr fnExpr,Expressions args) {
 		this.fnExpr = fnExpr;
diff -r c93d8c781853 -r 1e37f22a34c8 src/luan/interp/ReturnStmt.java
--- a/src/luan/interp/ReturnStmt.java	Tue Dec 04 09:16:03 2012 +0000
+++ b/src/luan/interp/ReturnStmt.java	Wed Dec 05 09:03:50 2012 +0000
@@ -1,19 +1,38 @@
 package luan.interp;
 
+import luan.Lua;
 import luan.LuaState;
 import luan.LuaException;
+import luan.LuaFunction;
+import luan.LuaClosure;
 
 
 final class ReturnStmt implements Stmt {
 	private final Expressions expressions;
+	private final Expr tailFnExpr;
 	boolean throwReturnException = true;
 
 	ReturnStmt(Expressions expressions) {
-		this.expressions = expressions;
+		if( expressions instanceof FnCall ) {  // tail call
+			FnCall fnCall = (FnCall)expressions;
+			this.expressions = fnCall.args;
+			this.tailFnExpr = fnCall.fnExpr;
+		} else {
+			this.expressions = expressions;
+			this.tailFnExpr = null;
+		}
 	}
 
 	@Override public void eval(LuaState lua) throws LuaException {
 		lua.returnValues = expressions.eval(lua);
+		if( tailFnExpr != null ) {
+			LuaFunction tailFn = Lua.checkFunction( tailFnExpr.eval(lua) );
+			if( tailFn instanceof LuaClosure ) {
+				lua.tailFn = (LuaClosure)tailFn;
+			} else {
+				lua.returnValues =  tailFn.call(lua,lua.returnValues);
+			}
+		}
 		if( throwReturnException )
 			throw new ReturnException();
 	}