Mercurial Hosting > luan
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(); }