All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.luaj.vm2.lua2java.JavaCodeGen Maven / Gradle / Ivy

There is a newer version: 3.0.1
Show newest version
/*******************************************************************************
* 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 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




© 2015 - 2024 Weber Informatics LLC | Privacy Policy