org.luaj.vm2.lua2java.JavaCodeGen Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of luaj-jse Show documentation
Show all versions of luaj-jse Show documentation
Luaj 2.0 for the jse platform
/*******************************************************************************
* Copyright (c) 2010 Luaj.org. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
package org.luaj.vm2.lua2java;
import java.io.CharArrayWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.luaj.vm2.Lua;
import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.ast.Block;
import org.luaj.vm2.ast.Chunk;
import org.luaj.vm2.ast.Exp;
import org.luaj.vm2.ast.FuncArgs;
import org.luaj.vm2.ast.FuncBody;
import org.luaj.vm2.ast.Name;
import org.luaj.vm2.ast.NameResolver;
import org.luaj.vm2.ast.Variable;
import org.luaj.vm2.ast.ParList;
import org.luaj.vm2.ast.Stat;
import org.luaj.vm2.ast.TableConstructor;
import org.luaj.vm2.ast.TableField;
import org.luaj.vm2.ast.Visitor;
import org.luaj.vm2.ast.Exp.AnonFuncDef;
import org.luaj.vm2.ast.Exp.BinopExp;
import org.luaj.vm2.ast.Exp.Constant;
import org.luaj.vm2.ast.Exp.FieldExp;
import org.luaj.vm2.ast.Exp.FuncCall;
import org.luaj.vm2.ast.Exp.IndexExp;
import org.luaj.vm2.ast.Exp.MethodCall;
import org.luaj.vm2.ast.Exp.NameExp;
import org.luaj.vm2.ast.Exp.ParensExp;
import org.luaj.vm2.ast.Exp.UnopExp;
import org.luaj.vm2.ast.Exp.VarExp;
import org.luaj.vm2.ast.Exp.VarargsExp;
import org.luaj.vm2.ast.Stat.Assign;
import org.luaj.vm2.ast.Stat.Break;
import org.luaj.vm2.ast.Stat.FuncCallStat;
import org.luaj.vm2.ast.Stat.FuncDef;
import org.luaj.vm2.ast.Stat.GenericFor;
import org.luaj.vm2.ast.Stat.IfThenElse;
import org.luaj.vm2.ast.Stat.LocalAssign;
import org.luaj.vm2.ast.Stat.LocalFuncDef;
import org.luaj.vm2.ast.Stat.NumericFor;
import org.luaj.vm2.ast.Stat.RepeatUntil;
import org.luaj.vm2.ast.Stat.Return;
import org.luaj.vm2.ast.Stat.WhileDo;
public class JavaCodeGen {
final Chunk chunk;
final String packagename;
final String classname;
Writer writer;
public JavaCodeGen( Chunk chunk, Writer writer,String packagename, String classname) {
this.chunk = chunk;
this.writer = writer;
this.packagename = packagename;
this.classname = classname;
chunk.accept( new NameResolver() );
chunk.accept( new JavaClassWriterVisitor() );
}
class JavaClassWriterVisitor extends Visitor {
JavaScope javascope = null;
List constantDeclarations = new ArrayList();
Map stringConstants = new HashMap();
Map numberConstants = new HashMap();
String indent = "";
void addindent() {
indent+=" ";
}
void subindent() {
indent = indent.substring(3);
}
void out(String s) {
try {
writer.write(s);
} catch (IOException e) {
throw new RuntimeException("write failed: "+e, e);
}
}
void outi(String s) {
out( indent );
out( s );
}
void outl(String s) {
outi( s );
out( "\n" );
}
void outr(String s) {
out( s );
out( "\n" );
}
void outb(String s) {
outl( s );
addindent();
}
void oute(String s) {
subindent();
outl( s );
}
public void visit(Chunk chunk) {
if ( packagename != null )
outl("package "+packagename+";");
outl("import org.luaj.vm2.*;");
outl("import org.luaj.vm2.lib.*;");
outb("public class "+classname+" extends VarArgFunction {");
outl("public Varargs onInvoke(Varargs $arg) {");
addindent();
javascope = JavaScope.newJavaScope( chunk );
writeBodyBlock(chunk.block);
oute("}");
for ( int i=0, n=constantDeclarations.size(); i names = stat.names;
List values = stat.values;
int n = names.size();
int m = values != null? values.size(): 0;
boolean isvarlist = m>0 && m exps) {
final boolean[] needsTmpvarsMultiAssign = { false };
if ( exps.size() > 1 ) {
new Visitor() {
public void visit(FuncBody body) {}
public void visit(FieldExp exp) { needsTmpvarsMultiAssign[0] = true; }
public void visit(FuncCall exp) { needsTmpvarsMultiAssign[0] = true; }
public void visit(IndexExp exp) { needsTmpvarsMultiAssign[0] = true; }
public void visit(MethodCall exp) { needsTmpvarsMultiAssign[0] = true; }
public void visit(NameExp exp) { needsTmpvarsMultiAssign[0] = true; }
}.visitExps(exps);
}
if ( needsTmpvarsMultiAssign[0] )
tmpvarsMultiAssign( varsOrNames, exps );
else
directMultiAssign( varsOrNames, exps );
}
private void directMultiAssign(List varsOrNames, List values) {
int n = varsOrNames.size();
int m = values != null? values.size(): 0;
boolean isvarlist = m>0 && m exps) {
int n = varsOrNames.size();
int m = exps != null? exps.size(): 0;
boolean isvarlist = m>0 && m tmpnames = new ArrayList();
for ( int i=0; i values) {
int n = values!=null? values.size(): 0;
switch ( n ) {
case 0: return "NONE";
case 1: return evalVarargs((Exp) values.get(0));
default:
case 2: case 3:
Writer x = pushWriter();
out( n>3? "varargsOf(new LuaValue[] {":"varargsOf(" );
for ( int i=1; i3 )
out( "}," );
out( evalVarargs((Exp) values.get(n-1))+")" );
return popWriter(x);
}
}
Map callerExpects = new HashMap();
public String evalLuaValue(Exp exp) {
Writer x = pushWriter();
callerExpects.put(exp,Integer.valueOf(1));
exp.accept(this);
return popWriter(x);
}
public String evalVarargs(Exp exp) {
Writer x = pushWriter();
callerExpects.put(exp,Integer.valueOf(-1));
exp.accept(this);
return popWriter(x);
}
public String evalBoolean(Exp exp) {
Writer x = pushWriter();
exp.accept(new Visitor() {
public void visit(UnopExp exp) {
switch ( exp.op ) {
case Lua.OP_NOT:
String rhs = evalBoolean( exp.rhs );
out( "true".equals(rhs)? "false":
"false".equals(rhs)? "true":
"(!"+rhs+")");
break;
default: out(evalLuaValue(exp)+".toboolean()"); break;
}
}
public void visit(BinopExp exp) {
switch ( exp.op ) {
case Lua.OP_AND: out("("+evalBoolean(exp.lhs)+"&&"+evalBoolean(exp.rhs)+")"); return;
case Lua.OP_OR: out("("+evalBoolean(exp.lhs)+"||"+evalBoolean(exp.rhs)+")"); return;
case Lua.OP_GT: out(evalLuaValue(exp.lhs)+".gt_b("+evalLuaValue(exp.rhs)+")"); return;
case Lua.OP_GE: out(evalLuaValue(exp.lhs)+".gteq_b("+evalLuaValue(exp.rhs)+")"); return;
case Lua.OP_LT: out(evalLuaValue(exp.lhs)+".lt_b("+evalLuaValue(exp.rhs)+")"); return;
case Lua.OP_LE: out(evalLuaValue(exp.lhs)+".lteq_b("+evalLuaValue(exp.rhs)+")"); return;
case Lua.OP_EQ: out(evalLuaValue(exp.lhs)+".eq_b("+evalLuaValue(exp.rhs)+")"); return;
case Lua.OP_NEQ: out(evalLuaValue(exp.lhs)+".neq_b("+evalLuaValue(exp.rhs)+")"); return;
default: out(evalLuaValue(exp)+".toboolean()"); return;
}
}
public void visit(Constant exp) {
switch ( exp.value.type() ) {
case LuaValue.TBOOLEAN:
out(exp.value.toboolean()? "true": "false");
break;
default:
out(evalLuaValue(exp)+".toboolean()");
break;
}
}
public void visit(ParensExp exp) {
out(evalBoolean(exp.exp));
}
public void visit(VarargsExp exp) {
out(evalLuaValue(exp)+".toboolean()");
}
public void visit(FieldExp exp) {
out(evalLuaValue(exp)+".toboolean()");
}
public void visit(IndexExp exp) {
out(evalLuaValue(exp)+".toboolean()");
}
public void visit(NameExp exp) {
if ( exp.name.variable.isConstant() ) {
out ( exp.name.variable.initialValue.toboolean()? "true": "false");
return;
}
out(evalLuaValue(exp)+".toboolean()");
}
public void visit(FuncCall exp) {
out(evalLuaValue(exp)+".toboolean()");
}
public void visit(MethodCall exp) {
out(evalLuaValue(exp)+".toboolean()");
}
public void visit(TableConstructor exp) {
out(evalLuaValue(exp)+".toboolean()");
}
});
return popWriter(x);
}
public String evalNumber(Exp exp) {
Writer x = pushWriter();
exp.accept(new Visitor() {
public void visit(UnopExp exp) {
switch ( exp.op ) {
case Lua.OP_LEN: out(evalLuaValue(exp.rhs)+".length()"); break;
case Lua.OP_UNM: out("(-"+evalNumber(exp.rhs)+")"); break;
default: out(evalLuaValue(exp)+".checkdouble()"); break;
}
}
public void visit(BinopExp exp) {
String op;
switch ( exp.op ) {
case Lua.OP_ADD:
case Lua.OP_SUB:
case Lua.OP_MUL:
op = (exp.op==Lua.OP_ADD? "+": exp.op==Lua.OP_SUB? "-": "*");
out("("+evalNumber(exp.lhs)+op+evalNumber(exp.rhs)+")");
break;
case Lua.OP_POW: out("MathLib.dpow_d("+evalNumber(exp.lhs)+","+evalNumber(exp.rhs)+")"); break;
case Lua.OP_DIV: out("LuaDouble.ddiv_d("+evalNumber(exp.lhs)+","+evalNumber(exp.rhs)+")"); break;
case Lua.OP_MOD: out("LuaDouble.dmod_d("+evalNumber(exp.lhs)+","+evalNumber(exp.rhs)+")"); break;
default: out(evalLuaValue(exp)+".checkdouble()"); break;
}
}
public void visit(Constant exp) {
switch ( exp.value.type() ) {
case LuaValue.TNUMBER:
out( evalNumberLiteral(exp.value.checkdouble()) );
break;
default:
out(evalLuaValue(exp)+".checkdouble()");
break;
}
}
public void visit(ParensExp exp) {
out(evalNumber(exp.exp));
}
public void visit(VarargsExp exp) {
out(evalLuaValue(exp)+".checkdouble()");
}
public void visit(FieldExp exp) {
out(evalLuaValue(exp)+".checkdouble()");
}
public void visit(IndexExp exp) {
out(evalLuaValue(exp)+".checkdouble()");
}
public void visit(NameExp exp) {
if ( exp.name.variable.isConstant() ) {
if ( exp.name.variable.initialValue.isnumber() ) {
out( evalNumberLiteral(exp.name.variable.initialValue.checkdouble()) );
return;
}
}
out(evalLuaValue(exp)+".checkdouble()");
}
public void visit(FuncCall exp) {
out(evalLuaValue(exp)+".checkdouble()");
}
public void visit(MethodCall exp) {
out(evalLuaValue(exp)+".checkdouble()");
}
public void visit(TableConstructor exp) {
out(evalLuaValue(exp)+".checkdouble()");
}
});
return popWriter(x);
}
public void visit(FuncCallStat stat) {
outi("");
stat.funccall.accept(this);
outr(";");
}
public void visit(BinopExp exp) {
switch ( exp.op ) {
case Lua.OP_AND:
case Lua.OP_OR:
String not = (exp.op==Lua.OP_AND? "!": "");
out("("+not+"($b="+evalLuaValue(exp.lhs)+").toboolean()?$b:"+evalLuaValue(exp.rhs)+")");
return;
}
switch ( exp.op ) {
case Lua.OP_ADD: out("valueOf("+evalNumber(exp.lhs)+"+"+evalNumber(exp.rhs)+")"); return;
case Lua.OP_SUB: out("valueOf("+evalNumber(exp.lhs)+"-"+evalNumber(exp.rhs)+")"); return;
case Lua.OP_MUL: out("valueOf("+evalNumber(exp.lhs)+"*"+evalNumber(exp.rhs)+")"); return;
case Lua.OP_POW: out("MathLib.dpow("+evalNumber(exp.lhs)+","+evalNumber(exp.rhs)+")"); return;
case Lua.OP_DIV: out("LuaDouble.ddiv("+evalNumber(exp.lhs)+","+evalNumber(exp.rhs)+")"); return;
case Lua.OP_MOD: out("LuaDouble.dmod("+evalNumber(exp.lhs)+","+evalNumber(exp.rhs)+")"); return;
case Lua.OP_GT: out(evalLuaValue(exp.lhs)+".gt("+evalLuaValue(exp.rhs)+")"); return;
case Lua.OP_GE: out(evalLuaValue(exp.lhs)+".gteq("+evalLuaValue(exp.rhs)+")"); return;
case Lua.OP_LT: out(evalLuaValue(exp.lhs)+".lt("+evalLuaValue(exp.rhs)+")"); return;
case Lua.OP_LE: out(evalLuaValue(exp.lhs)+".lteq("+evalLuaValue(exp.rhs)+")"); return;
case Lua.OP_EQ: out(evalLuaValue(exp.lhs)+".eq("+evalLuaValue(exp.rhs)+")"); return;
case Lua.OP_NEQ: out(evalLuaValue(exp.lhs)+".neq("+evalLuaValue(exp.rhs)+")"); return;
case Lua.OP_CONCAT:
if ( isConcatExp(exp.rhs) ) {
out( evalLuaValue(exp.lhs) );
Exp e = exp.rhs;
String close = "";
for ( ; isConcatExp(e); e=((BinopExp)e).rhs ) {
out( ".concat("+evalLuaValue(((BinopExp)e).lhs) );
close += ')';
}
out( ".concat("+evalLuaValue(e)+".buffer())" );
out( close );
out( ".value()" );
} else {
out(evalLuaValue(exp.lhs)+".concat("+evalLuaValue(exp.rhs)+")");
}
return;
default: throw new IllegalStateException("unknown bin op:"+exp.op);
}
}
private boolean isConcatExp(Exp e) {
return (e instanceof BinopExp) && (((BinopExp)e).op == Lua.OP_CONCAT);
}
public void visit(UnopExp exp) {
exp.rhs.accept(this);
switch ( exp.op ) {
case Lua.OP_NOT: out(".not()"); break;
case Lua.OP_LEN: out(".len()"); break;
case Lua.OP_UNM: out(".neg()"); break;
}
}
public void visit(Constant exp) {
out( evalConstant(exp.value) );
}
protected String evalConstant(LuaValue value) {
switch ( value.type() ) {
case LuaValue.TSTRING:
return evalLuaStringConstant(value.checkstring());
case LuaValue.TNIL:
return "NIL";
case LuaValue.TBOOLEAN:
return value.toboolean()? "TRUE": "FALSE";
case LuaValue.TNUMBER:
return evalNumberConstant(value.todouble());
default:
throw new IllegalStateException("unknown constant type: "+value.typename());
}
}
private String evalStringConstant(String str) {
return evalLuaStringConstant( LuaValue.valueOf(str) );
}
private String evalLuaStringConstant(LuaString str) {
if ( stringConstants.containsKey(str) )
return (String) stringConstants.get(str);
String declvalue = quotedStringInitializer(str);
String javaname = javascope.createConstantName(str.tojstring());
constantDeclarations.add( "static final LuaValue "+javaname+" = valueOf("+declvalue+");" );
stringConstants.put(str,javaname);
return javaname;
}
private String evalNumberConstant(double value) {
if ( value == 0 ) return "ZERO";
if ( value == -1 ) return "MINUSONE";
if ( value == 1 ) return "ONE";
if ( numberConstants.containsKey(Double.valueOf(value)) )
return (String) numberConstants.get(Double.valueOf(value));
String declvalue = evalNumberLiteral(value);
String javaname = javascope.createConstantName(declvalue);
constantDeclarations.add( "static final LuaValue "+javaname+" = valueOf("+declvalue+");" );
numberConstants.put(Double.valueOf(value),javaname);
return javaname;
}
private String evalNumberLiteral(double value) {
int ivalue = (int) value;
String svalue = value==ivalue? String.valueOf(ivalue): String.valueOf(value);
return (value < 0? "("+svalue+")": svalue);
}
public void visit(FieldExp exp) {
exp.lhs.accept(this);
out(".get("+evalStringConstant(exp.name.name)+")");
}
public void visit(IndexExp exp) {
exp.lhs.accept(this);
out(".get(");
exp.exp.accept(this);
out(")");
}
public void visit(NameExp exp) {
singleReference( exp.name );
}
public void visit(ParensExp exp) {
if ( exp.exp.isvarargexp() )
out( evalLuaValue(exp.exp) );
else
exp.exp.accept(this);
}
public void visit(VarargsExp exp) {
int c = callerExpects.containsKey(exp)? ((Integer)callerExpects.get(exp)).intValue(): 0;
out( c==1? "$arg.arg1()": "$arg" );
}
public void visit(MethodCall exp) {
List e = exp.args.exps;
int n = e != null? e.size(): 0;
int c = callerExpects.containsKey(exp)? ((Integer)callerExpects.get(exp)).intValue(): 0;
if ( c == -1 )
n = -1;
out( evalLuaValue(exp.lhs) );
switch ( n ) {
case 0:
out(".method("+evalStringConstant(exp.name)+")");
break;
case 1: case 2:
out(".method("+evalStringConstant(exp.name)+",");
exp.args.accept(this);
out(")");
break;
default:
out(".invokemethod("+evalStringConstant(exp.name)
+((e==null||e.size()==0)? "": ","+evalListAsVarargs(exp.args.exps))+")");
if ( c == 1 )
out(".arg1()");
break;
}
}
public void visit(FuncCall exp) {
List e = exp.args.exps;
int n = e != null? e.size(): 0;
if ( n > 0 && ((Exp)e.get(n-1)).isvarargexp() )
n = -1;
int c = callerExpects.containsKey(exp)? ((Integer)callerExpects.get(exp)).intValue(): 0;
if ( c == -1 )
n = -1;
out( evalLuaValue(exp.lhs) );
switch ( n ) {
case 0: case 1: case 2: case 3:
out(".call(");
exp.args.accept(this);
out(")");
break;
default:
out(".invoke("+((e==null||e.size()==0)? "": evalListAsVarargs(e))+")");
if ( c == 1 )
out(".arg1()");
break;
}
}
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) {
if ( args.exps != null ) {
int n = args.exps.size();
if ( n > 0 ) {
for ( int i=1; i=0 && n<=1 && m<=3 && ! body.parlist.isvararg ) {
switch ( m ) {
case 0:
outr("new ZeroArgFunction(env) {");
addindent();
outb("public LuaValue call() {");
break;
case 1:
outr("new OneArgFunction(env) {");
addindent();
outb("public LuaValue call("
+declareArg((Name) body.parlist.names.get(0))+") {");
assignArg((Name) body.parlist.names.get(0));
break;
case 2:
outr("new TwoArgFunction(env) {");
addindent();
outb("public LuaValue call("
+declareArg((Name) body.parlist.names.get(0))+","
+declareArg((Name) body.parlist.names.get(1))+") {");
assignArg((Name) body.parlist.names.get(0));
assignArg((Name) body.parlist.names.get(1));
break;
case 3:
outr("new ThreeArgFunction(env) {");
addindent();
outb("public LuaValue call("
+declareArg((Name) body.parlist.names.get(0))+","
+declareArg((Name) body.parlist.names.get(1))+","
+declareArg((Name) body.parlist.names.get(2))+") {");
assignArg((Name) body.parlist.names.get(0));
assignArg((Name) body.parlist.names.get(1));
assignArg((Name) body.parlist.names.get(2));
break;
}
} else {
outr("new VarArgFunction(env) {");
addindent();
outb("public Varargs invoke(Varargs $arg) {");
for ( int i=0; i0? "$arg.arg("+(i+1)+")": "$arg.arg1()";
singleLocalDeclareAssign( name, value );
}
if ( body.parlist.isvararg ) {
Variable 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)");
singleLocalDeclareAssign( arg, value );
}
}
writeBodyBlock(body.block);
oute("}");
subindent();
outi("}");
javascope = javascope.popJavaScope();
}
private String declareArg(Name name) {
String argname = javascope.getJavaName(name.variable);
return "LuaValue "+argname+(name.variable.isupvalue? "$0": "");
}
private void assignArg(Name name) {
if ( name.variable.isupvalue ) {
String argname = javascope.getJavaName(name.variable);
singleLocalDeclareAssign(name, argname+"$0");
}
}
public void visit(FuncDef stat) {
Writer x = pushWriter();
stat.body.accept(this);
String value = popWriter(x);
int n = stat.name.dots!=null? stat.name.dots.size(): 0;
boolean m = stat.name.method != null;
if ( n>0 && !m && stat.name.name.variable.isLocal() )
singleAssign( stat.name.name, value );
else if ( n==0 && !m ) {
singleAssign( stat.name.name, value );
} else {
singleReference( stat.name.name );
for ( int i=0; i0? ("+i+"<="+j+"$limit): ("+i+">="+j+"$limit);" );
outr( " "+i+"+="+j+"$step ) {" );
}
addindent();
singleLocalDeclareAssign(stat.name, "valueOf("+i+")");
super.visit(stat.block);
oute( "}" );
}
private Name tmpJavaVar(String s) {
Name n = new Name(s);
n.variable = javascope.define(s);
return n;
}
public void visit(GenericFor stat) {
Name f = tmpJavaVar("f");
Name s = tmpJavaVar("s");
Name var = tmpJavaVar("var");
Name v = tmpJavaVar("v");
String javaf = javascope.getJavaName(f.variable);
String javas = javascope.getJavaName(s.variable);
String javavar = javascope.getJavaName(var.variable);
String javav = javascope.getJavaName(v.variable);
outl("LuaValue "+javaf+","+javas+","+javavar+";");
outl("Varargs "+javav+";");
List fsvar = new ArrayList();
fsvar.add(f);
fsvar.add(s);
fsvar.add(var);
multiAssign(fsvar, stat.exps);
outb("while (true) {");
outl( javav+" = "+javaf+".invoke(varargsOf("+javas+","+javavar+"));");
outl( "if (("+javavar+"="+javav+".arg1()).isnil()) break;");
singleLocalDeclareAssign((Name) stat.names.get(0),javavar);
for ( int i=1, n=stat.names.size(); i keyed = new ArrayList();
List list = new ArrayList();
for ( int i=0; i exps) {
super.visitExps(exps);
}
public void visitNames(List names) {
super.visitNames(names);
}
public void visitVars(List vars) {
super.visitVars(vars);
}
}
private static String quotedStringInitializer(LuaString s) {
byte[] bytes = s.m_bytes;
int o = s.m_offset;
int n = s.m_length;
StringBuffer sb = new StringBuffer(n+2);
// check for bytes not encodable as utf8
if ( ! s.isValidUtf8() ) {
sb.append( "new byte[]{" );
for ( int j=0; j0 ) sb.append(",");
byte b = bytes[o+j];
switch ( b ) {
case '\n': sb.append( "'\\n'" ); break;
case '\r': sb.append( "'\\r'" ); break;
case '\t': sb.append( "'\\t'" ); break;
case '\\': sb.append( "'\\\\'" ); break;
default:
if ( b >= ' ' ) {
sb.append( '\'');
sb.append( (char) b );
sb.append( '\'');
} else {
sb.append( String.valueOf((int)b) );
}
break;
}
}
sb.append( "}" );
return sb.toString();
}
sb.append('"');
for ( int i=0; i= ' ' ) {
sb.append( (char) b ); break;
} else {
// convert from UTF-8
int u = 0xff & (int) b;
if ( u>=0xc0 && i+1=0xe0 && i+2