Fix java code generator including adding tail call support.

This commit is contained in:
James Roseborough
2010-07-26 05:58:34 +00:00
parent 69bbae70a1
commit 6364b002e4
4 changed files with 49 additions and 13 deletions

View File

@@ -32,6 +32,11 @@ public class TailcallVarargs extends Varargs {
this.args = args; this.args = args;
} }
public TailcallVarargs(LuaValue object, LuaValue methodname, Varargs args) {
this.func = object.get(methodname);
this.args = args;
}
public boolean isTailcall() { public boolean isTailcall() {
return true; return true;
} }

View File

@@ -135,7 +135,7 @@ public class JavaCodeGen {
outl("import org.luaj.vm2.*;"); outl("import org.luaj.vm2.*;");
outl("import org.luaj.vm2.lib.*;"); outl("import org.luaj.vm2.lib.*;");
outb("public class "+classname+" extends VarArgFunction {"); outb("public class "+classname+" extends VarArgFunction {");
outl("public Varargs invoke(Varargs $arg) {"); outl("public Varargs onInvoke(Varargs $arg) {");
addindent(); addindent();
javascope = JavaScope.newJavaScope( chunk ); javascope = JavaScope.newJavaScope( chunk );
writeBodyBlock(chunk.block); writeBodyBlock(chunk.block);
@@ -182,9 +182,18 @@ public class JavaCodeGen {
public void visit(Stat.Return s) { public void visit(Stat.Return s) {
int n = s.nreturns(); int n = s.nreturns();
switch ( n ) { switch ( n ) {
case 0: outl( "return NONE;" ); break; case 0:
case 1: outl( "return "+evalLuaValue(s.values.get(0))+";" ); break; outl( "return NONE;" );
default: outl( "return "+evalListAsVarargs(s.values)+";" ); break; break;
case 1:
outl( "return "+evalLuaValue(s.values.get(0))+";" );
break;
default:
if ( s.values.size()==1 && s.values.get(0).isfunccall() )
tailCall( s.values.get(0) );
else
outl( "return "+evalListAsVarargs(s.values)+";" );
break;
} }
} }
@@ -249,7 +258,7 @@ public class JavaCodeGen {
if ( exp.name.variable.isLocal() ) if ( exp.name.variable.isLocal() )
singleLocalAssign(exp.name, valu); singleLocalAssign(exp.name, valu);
else else
outl( "env.set("+evalLuaValue(exp)+","+valu+");"); outl( "env.set("+evalStringConstant(exp.name.name)+","+valu+");");
} }
}; };
if ( varOrName instanceof VarExp ) if ( varOrName instanceof VarExp )
@@ -446,7 +455,7 @@ public class JavaCodeGen {
public void visit(VarargsExp exp) { public void visit(VarargsExp exp) {
int c = callerExpects.containsKey(exp)? callerExpects.get(exp): 0; int c = callerExpects.containsKey(exp)? callerExpects.get(exp): 0;
out( c==1? "arg.arg1()": "arg" ); out( c==1? "$arg.arg1()": "$arg" );
} }
public void visit(MethodCall exp) { public void visit(MethodCall exp) {
@@ -497,6 +506,18 @@ public class JavaCodeGen {
} }
} }
public void tailCall( Exp e ) {
if ( e instanceof MethodCall ) {
MethodCall mc = (MethodCall) e;
outl("return new TailcallVarargs("+evalLuaValue(mc.lhs)+","+evalStringConstant(mc.name)+","+evalListAsVarargs(mc.args.exps)+");");
} else if ( e instanceof FuncCall ) {
FuncCall fc = (FuncCall) e;
outl("return new TailcallVarargs("+evalLuaValue(fc.lhs)+","+evalListAsVarargs(fc.args.exps)+");");
} else {
throw new IllegalArgumentException("can't tail call "+e);
}
}
public void visit(FuncArgs args) { public void visit(FuncArgs args) {
if ( args.exps != null ) { if ( args.exps != null ) {
int n = args.exps.size(); int n = args.exps.size();
@@ -551,12 +572,6 @@ public class JavaCodeGen {
outr("new VarArgFunction(env) {"); outr("new VarArgFunction(env) {");
addindent(); addindent();
outb("public Varargs invoke(Varargs $arg) {"); outb("public Varargs invoke(Varargs $arg) {");
if ( body.parlist.isvararg ) {
NamedVariable arg = body.scope.find("arg");
javascope.setJavaName(arg,"arg");
String value = "LuaValue.tableOf($arg,"+(m+1)+")";
outl( arg.isupvalue? "final LuaValue[] arg = {"+value+"};": "LuaValue arg = "+value+";" );
}
for ( int i=0; i<m; i++ ) { for ( int i=0; i<m; i++ ) {
Name name = body.parlist.names.get(i); Name name = body.parlist.names.get(i);
String argname = javascope.getJavaName(name.variable); String argname = javascope.getJavaName(name.variable);
@@ -566,6 +581,14 @@ public class JavaCodeGen {
else else
outl( "LuaValue "+argname+" = "+value+";" ); outl( "LuaValue "+argname+" = "+value+";" );
} }
if ( body.parlist.isvararg ) {
NamedVariable arg = body.scope.find("arg");
javascope.setJavaName(arg,"arg");
if ( m > 0 )
outl( "$arg = $arg.subargs("+(m+1)+");" );
String value = (javascope.usesvarargs? "NIL": "LuaValue.tableOf($arg,1)");
outl( arg.isupvalue? "final LuaValue[] arg = {"+value+"};": "LuaValue arg = "+value+";" );
}
} }
writeBodyBlock(body.block); writeBodyBlock(body.block);
oute("}"); oute("}");

View File

@@ -32,6 +32,7 @@ import org.luaj.vm2.ast.FuncBody;
import org.luaj.vm2.ast.NameScope; import org.luaj.vm2.ast.NameScope;
import org.luaj.vm2.ast.Visitor; import org.luaj.vm2.ast.Visitor;
import org.luaj.vm2.ast.Exp.BinopExp; import org.luaj.vm2.ast.Exp.BinopExp;
import org.luaj.vm2.ast.Exp.VarargsExp;
import org.luaj.vm2.ast.Stat.Return; import org.luaj.vm2.ast.Stat.Return;
import org.luaj.vm2.lib.LibFunction; import org.luaj.vm2.lib.LibFunction;
@@ -72,6 +73,7 @@ public class JavaScope extends NameScope {
public int nreturns; public int nreturns;
public boolean needsbinoptmp; public boolean needsbinoptmp;
public boolean usesvarargs;
final Set<String> staticnames; final Set<String> staticnames;
final Set<String> javanames = new HashSet<String>(); final Set<String> javanames = new HashSet<String>();
@@ -150,12 +152,14 @@ public class JavaScope extends NameScope {
block.accept( v ); block.accept( v );
this.nreturns = v.nreturns; this.nreturns = v.nreturns;
this.needsbinoptmp = v.needsbinoptmp; this.needsbinoptmp = v.needsbinoptmp;
this.usesvarargs = v.usesvarargs;
return this; return this;
} }
class NewScopeVisitor extends Visitor { class NewScopeVisitor extends Visitor {
int nreturns = 0; int nreturns = 0;
boolean needsbinoptmp = false; boolean needsbinoptmp = false;
boolean usesvarargs = false;
NewScopeVisitor(int nreturns) { NewScopeVisitor(int nreturns) {
this.nreturns = nreturns; this.nreturns = nreturns;
} }
@@ -173,6 +177,10 @@ public class JavaScope extends NameScope {
} }
super.visit(exp); super.visit(exp);
} }
public void visit(VarargsExp exp) {
usesvarargs = true;
}
} }
} }

View File

@@ -135,7 +135,7 @@ local p = function( s,e )
print( s, e and aliases[tostring(e)] or e ) print( s, e and aliases[tostring(e)] or e )
end end
p(pcall(fib_bad, 30)) p(pcall(fib_bad, 30))
p((pcall(fib_bad, 25000))) --p((pcall(fib_bad, 25000)))
p(pcall(fib_good, 30)) p(pcall(fib_good, 30))
p(pcall(fib_good, 25000)) p(pcall(fib_good, 25000))