Refactor java code generator.
This commit is contained in:
@@ -74,7 +74,7 @@ public final class Buffer {
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
public final LuaString tostrvalue() {
|
||||
public final LuaString tostring() {
|
||||
return new LuaString( realloc( bytes, length ) );
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ package org.luaj.vm2;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Hashtable;
|
||||
|
||||
/*
|
||||
** Loader to load compiled function prototypes
|
||||
|
||||
@@ -236,7 +236,7 @@ public class LuaClosure extends LuaFunction {
|
||||
Buffer sb = new Buffer();
|
||||
for ( ; b<=c; )
|
||||
sb.append( stack[b++].checkstring() );
|
||||
stack[a] = sb.tostrvalue();
|
||||
stack[a] = sb.tostring();
|
||||
}
|
||||
continue;
|
||||
|
||||
|
||||
@@ -56,13 +56,17 @@ public class LuaTable extends LuaValue {
|
||||
rawset(named[i], named[i+1]);
|
||||
}
|
||||
|
||||
|
||||
public LuaTable(Varargs varargs) {
|
||||
int n = varargs.narg();
|
||||
this(varargs,1);
|
||||
}
|
||||
|
||||
public LuaTable(Varargs varargs, int firstarg) {
|
||||
int nskip = firstarg-1;
|
||||
int n = Math.max(varargs.narg()-nskip,0);
|
||||
presize( n, 1 );
|
||||
set(N, valueOf(n));
|
||||
for ( int i=1; i<=n; i++ )
|
||||
set(i, varargs.arg(i));
|
||||
set(i, varargs.arg(i+nskip));
|
||||
}
|
||||
|
||||
private void presize(int narray, int nhash) {
|
||||
@@ -232,7 +236,7 @@ public class LuaTable extends LuaValue {
|
||||
sb.append( get(i).checkstring() );
|
||||
}
|
||||
}
|
||||
return sb.tostrvalue();
|
||||
return sb.tostring();
|
||||
}
|
||||
|
||||
public LuaValue getn() {
|
||||
|
||||
@@ -286,7 +286,7 @@ public class LuaValue extends Varargs {
|
||||
public LuaValue or( LuaValue rhs ) { return this.toboolean()? this: rhs; }
|
||||
|
||||
// for loop helpers
|
||||
/** test numeric for loop */
|
||||
/** @deprecated - used during development only */
|
||||
public boolean testfor_b(LuaValue limit, boolean stepgtzero) { return stepgtzero? lteq_b(limit): gteq_b(limit); }
|
||||
/** used in for loop only */
|
||||
public boolean testfor_b(LuaValue limit, LuaValue step) { return step.gt_b(0)? lteq_b(limit): gteq_b(limit); }
|
||||
@@ -312,7 +312,7 @@ public class LuaValue extends Varargs {
|
||||
|
||||
// table initializers
|
||||
public static LuaTable tableOf() { return new LuaTable(); }
|
||||
public static LuaTable tableOf(Varargs varargs, int firstarg) { return new LuaTable(varargs.subargs(firstarg)); }
|
||||
public static LuaTable tableOf(Varargs varargs, int firstarg) { return new LuaTable(varargs,firstarg); }
|
||||
public static LuaTable tableOf(int narray, int nhash) { return new LuaTable(narray, nhash); }
|
||||
public static LuaTable listOf(LuaValue[] unnamedValues) { return new LuaTable(null,unnamedValues,null); }
|
||||
public static LuaTable listOf(LuaValue[] unnamedValues,Varargs lastarg) { return new LuaTable(null,unnamedValues,lastarg); }
|
||||
@@ -421,8 +421,12 @@ public class LuaValue extends Varargs {
|
||||
public static Varargs varargsOf(LuaValue v1,LuaValue v2,Varargs v3) {
|
||||
switch ( v3.narg() ) {
|
||||
case 0: return new PairVarargs(v1,v2);
|
||||
default: return new ArrayVarargs(new LuaValue[] {v1,v2},v3); }
|
||||
default: return new ArrayVarargs(new LuaValue[] {v1,v2},v3);
|
||||
}
|
||||
}
|
||||
public static Varargs tailcallOf(LuaValue func, Varargs args) {
|
||||
return new TailcallVarargs(func, args);
|
||||
}
|
||||
|
||||
// empty varargs
|
||||
private static final class None extends LuaNil {
|
||||
|
||||
@@ -48,21 +48,18 @@ public class TailcallVarargs extends Varargs {
|
||||
} while (nextcall != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuaValue arg( int i ) {
|
||||
if ( result == null )
|
||||
eval();
|
||||
return result.arg(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuaValue arg1() {
|
||||
if (result == null)
|
||||
eval();
|
||||
return result.arg1();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int narg() {
|
||||
if (result == null)
|
||||
eval();
|
||||
|
||||
@@ -143,5 +143,4 @@ public abstract class Varargs {
|
||||
return end+1-start;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -259,7 +259,7 @@ public class StringLib extends OneArgFunction {
|
||||
}
|
||||
}
|
||||
|
||||
return result.tostrvalue();
|
||||
return result.tostring();
|
||||
}
|
||||
|
||||
private static void addquoted(Buffer buf, LuaString s) {
|
||||
@@ -575,7 +575,7 @@ public class StringLib extends OneArgFunction {
|
||||
break;
|
||||
}
|
||||
lbuf.append( src.substring( soffset, srclen ) );
|
||||
return varargsOf(lbuf.tostrvalue(), valueOf(n));
|
||||
return varargsOf(lbuf.tostring(), valueOf(n));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -35,7 +35,7 @@ import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
import org.luaj.vm2.lib.JsePlatform;
|
||||
import org.luaj.vm2.luajc.JavaBytecodeCompiler;
|
||||
import org.luaj.vm2.luajc.LuaJC;
|
||||
|
||||
|
||||
/**
|
||||
@@ -89,7 +89,7 @@ public class lua {
|
||||
// input script - defer to last stage
|
||||
break;
|
||||
case 'j':
|
||||
JavaBytecodeCompiler.install();
|
||||
LuaJC.install();
|
||||
break;
|
||||
case 'l':
|
||||
if ( ++i >= args.length )
|
||||
|
||||
@@ -30,7 +30,7 @@ import java.util.Hashtable;
|
||||
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.compiler.DumpState;
|
||||
import org.luaj.vm2.luajc.JavaBytecodeCompiler;
|
||||
import org.luaj.vm2.luajc.LuaJC;
|
||||
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ public class luajc {
|
||||
private void processScript( InputStream script, String chunkname, OutputStream out ) throws IOException {
|
||||
try {
|
||||
// create the chunk
|
||||
Hashtable t = JavaBytecodeCompiler.loadClasses(script, chunkname);
|
||||
Hashtable t = LuaJC.getInstance().compileAll(script, chunkname, chunkname);
|
||||
|
||||
// write out the chunk
|
||||
if (!parseonly) {
|
||||
|
||||
701
src/jse/org/luaj/vm2/luajc/JavaBuilder.java
Normal file
701
src/jse/org/luaj/vm2/luajc/JavaBuilder.java
Normal file
@@ -0,0 +1,701 @@
|
||||
/*******************************************************************************
|
||||
* 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.luajc;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.bcel.Constants;
|
||||
import org.apache.bcel.generic.AASTORE;
|
||||
import org.apache.bcel.generic.ALOAD;
|
||||
import org.apache.bcel.generic.ANEWARRAY;
|
||||
import org.apache.bcel.generic.ASTORE;
|
||||
import org.apache.bcel.generic.ArrayType;
|
||||
import org.apache.bcel.generic.BranchInstruction;
|
||||
import org.apache.bcel.generic.ClassGen;
|
||||
import org.apache.bcel.generic.CompoundInstruction;
|
||||
import org.apache.bcel.generic.ConstantPoolGen;
|
||||
import org.apache.bcel.generic.FieldGen;
|
||||
import org.apache.bcel.generic.GOTO;
|
||||
import org.apache.bcel.generic.IFEQ;
|
||||
import org.apache.bcel.generic.IFNE;
|
||||
import org.apache.bcel.generic.Instruction;
|
||||
import org.apache.bcel.generic.InstructionConstants;
|
||||
import org.apache.bcel.generic.InstructionFactory;
|
||||
import org.apache.bcel.generic.InstructionHandle;
|
||||
import org.apache.bcel.generic.InstructionList;
|
||||
import org.apache.bcel.generic.LocalVariableGen;
|
||||
import org.apache.bcel.generic.MethodGen;
|
||||
import org.apache.bcel.generic.ObjectType;
|
||||
import org.apache.bcel.generic.PUSH;
|
||||
import org.apache.bcel.generic.Type;
|
||||
import org.luaj.vm2.Buffer;
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.LuaBoolean;
|
||||
import org.luaj.vm2.LuaDouble;
|
||||
import org.luaj.vm2.LuaInteger;
|
||||
import org.luaj.vm2.LuaNumber;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.lib.OneArgFunction;
|
||||
import org.luaj.vm2.lib.ThreeArgFunction;
|
||||
import org.luaj.vm2.lib.TwoArgFunction;
|
||||
import org.luaj.vm2.lib.VarArgFunction;
|
||||
import org.luaj.vm2.lib.ZeroArgFunction;
|
||||
|
||||
public class JavaBuilder {
|
||||
|
||||
private static final String STR_VARARGS = Varargs.class.getName();
|
||||
private static final String STR_LUAVALUE = LuaValue.class.getName();
|
||||
private static final String STR_LUASTRING = LuaString.class.getName();
|
||||
private static final String STR_LUAINTEGER = LuaInteger.class.getName();
|
||||
private static final String STR_LUADOUBLE = LuaDouble.class.getName();
|
||||
private static final String STR_LUANUMBER = LuaNumber.class.getName();
|
||||
private static final String STR_LUABOOLEAN = LuaBoolean.class.getName();
|
||||
private static final String STR_LUATABLE = LuaTable.class.getName();
|
||||
private static final String STR_BUFFER = Buffer.class.getName();
|
||||
private static final String STR_STRING = String.class.getName();
|
||||
|
||||
private static final ObjectType TYPE_VARARGS = new ObjectType(STR_VARARGS);
|
||||
private static final ObjectType TYPE_LUAVALUE = new ObjectType(STR_LUAVALUE);
|
||||
private static final ObjectType TYPE_LUASTRING = new ObjectType(STR_LUASTRING);
|
||||
private static final ObjectType TYPE_LUAINTEGER = new ObjectType(STR_LUAINTEGER);
|
||||
private static final ObjectType TYPE_LUADOUBLE = new ObjectType(STR_LUADOUBLE);
|
||||
private static final ObjectType TYPE_LUANUMBER = new ObjectType(STR_LUANUMBER);
|
||||
private static final ObjectType TYPE_LUABOOLEAN = new ObjectType(STR_LUABOOLEAN);
|
||||
private static final ObjectType TYPE_LUATABLE = new ObjectType(STR_LUATABLE);
|
||||
private static final ObjectType TYPE_BUFFER = new ObjectType(STR_BUFFER);
|
||||
|
||||
private static final ArrayType TYPE_LOCALUPVALUE = new ArrayType( TYPE_LUAVALUE, 1 );
|
||||
private static final ArrayType TYPE_CHARARRAY = new ArrayType( Type.CHAR, 1 );
|
||||
|
||||
private static final Class[] NO_INNER_CLASSES = {};
|
||||
|
||||
private static final String STR_FUNCV = VarArgFunction.class.getName();
|
||||
private static final String STR_FUNC0 = ZeroArgFunction.class.getName();
|
||||
private static final String STR_FUNC1 = OneArgFunction.class.getName();
|
||||
private static final String STR_FUNC2 = TwoArgFunction.class.getName();
|
||||
private static final String STR_FUNC3 = ThreeArgFunction.class.getName();
|
||||
|
||||
// names, arg types for main prototype classes
|
||||
private static final String[] SUPER_NAME_N = { STR_FUNC0, STR_FUNC1, STR_FUNC2, STR_FUNC3, STR_FUNCV, };
|
||||
private static final ObjectType[] RETURN_TYPE_N = { TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_VARARGS, };
|
||||
private static final Type[][] ARG_TYPES_N = { {}, {TYPE_LUAVALUE}, {TYPE_LUAVALUE,TYPE_LUAVALUE}, {TYPE_LUAVALUE,TYPE_LUAVALUE,TYPE_LUAVALUE}, {TYPE_VARARGS}, };
|
||||
private static final String[][] ARG_NAMES_N = { {}, {"arg"}, {"arg1","arg2"}, {"arg1","arg2","arg3"}, {"args"}, };
|
||||
private static final String[] METH_NAME_N = { "call", "call", "call", "call", "invoke", };
|
||||
|
||||
// varable naming
|
||||
private static final String PREFIX_CONSTANT = "k";
|
||||
private static final String PREFIX_UPVALUE = "u";
|
||||
private static final String PREFIX_PLAIN_SLOT = "s";
|
||||
private static final String PREFIX_UPVALUE_SLOT = "a";
|
||||
private static final String NAME_VARRESULT = "v";
|
||||
|
||||
// basic info
|
||||
private final Prototype p;
|
||||
private final String classname;
|
||||
private final Slots slots;
|
||||
|
||||
// bcel variables
|
||||
private final ClassGen cg;
|
||||
private final ConstantPoolGen cp;
|
||||
private final InstructionFactory factory;
|
||||
|
||||
// main instruction list for the main function of this class
|
||||
private final InstructionList init;
|
||||
private final InstructionList main;
|
||||
private final MethodGen mg;
|
||||
|
||||
// the superclass arg count, 0-3 args, 4=varargs
|
||||
private int superclassType;
|
||||
private static int SUPERTYPE_VARARGS = 4;
|
||||
|
||||
// storage for goto locations
|
||||
private final int[] targets;
|
||||
private final BranchInstruction[] branches;
|
||||
private final InstructionHandle[] branchDestHandles;
|
||||
private InstructionHandle beginningOfLuaInstruction;
|
||||
|
||||
// hold vararg result
|
||||
private LocalVariableGen varresult = null;
|
||||
|
||||
public JavaBuilder(Prototype p, String classname, String filename) {
|
||||
this.p = p;
|
||||
this.classname = classname;
|
||||
this.slots = new Slots(p);
|
||||
|
||||
// what class to inherit from
|
||||
superclassType = p.numparams;
|
||||
if ( p.is_vararg != 0 || superclassType >= SUPERTYPE_VARARGS )
|
||||
superclassType = SUPERTYPE_VARARGS;
|
||||
for ( int i=0, n=p.code.length; i<n; i++ ) {
|
||||
int inst = p.code[i];
|
||||
if ( Lua.GET_OPCODE(inst) == Lua.OP_RETURN && (Lua.GETARG_B(inst) < 1 || Lua.GETARG_B(inst) > 2) )
|
||||
superclassType = SUPERTYPE_VARARGS;
|
||||
}
|
||||
|
||||
// create class generator
|
||||
cg = new ClassGen(classname, SUPER_NAME_N[superclassType], filename,
|
||||
Constants.ACC_PUBLIC | Constants.ACC_SUPER, null);
|
||||
cp = cg.getConstantPool(); // cg creates constant pool
|
||||
|
||||
// main instruction lists
|
||||
factory = new InstructionFactory(cg);
|
||||
init = new InstructionList();
|
||||
main = new InstructionList();
|
||||
|
||||
// create the fields
|
||||
for ( int i=0; i<p.nups; i++ ) {
|
||||
FieldGen fg = new FieldGen(0, TYPE_LOCALUPVALUE, upvalueName(i), cp);
|
||||
cg.addField(fg.getField());
|
||||
}
|
||||
|
||||
// create the method
|
||||
mg = new MethodGen( Constants.ACC_PUBLIC | Constants.ACC_FINAL, // access flags
|
||||
RETURN_TYPE_N[superclassType], // return type
|
||||
ARG_TYPES_N[superclassType], // argument types
|
||||
ARG_NAMES_N[superclassType], // arg names
|
||||
METH_NAME_N[superclassType],
|
||||
STR_LUAVALUE, // method, defining class
|
||||
main, cp);
|
||||
|
||||
// initialize the values in the slots
|
||||
initializeSlots();
|
||||
|
||||
// initialize branching
|
||||
int nc = p.code.length;
|
||||
targets = new int[nc];
|
||||
branches = new BranchInstruction[nc];
|
||||
branchDestHandles = new InstructionHandle[nc];
|
||||
}
|
||||
|
||||
public void initializeSlots() {
|
||||
int slot = 0;
|
||||
if ( superclassType == SUPERTYPE_VARARGS ) {
|
||||
for ( slot=0; slot<p.numparams; slot++ ) {
|
||||
if ( slots.isInitialValueUsed(slot) ) {
|
||||
append(new ALOAD(1));
|
||||
append(new PUSH(cp, slot+1));
|
||||
append(factory.createInvoke(STR_VARARGS, "arg", TYPE_LUAVALUE, new Type[] { Type.INT }, Constants.INVOKEVIRTUAL));
|
||||
storeLocal(-1, slot);
|
||||
}
|
||||
}
|
||||
boolean needsarg = ((p.is_vararg & Lua.VARARG_NEEDSARG) != 0);
|
||||
if ( needsarg ) {
|
||||
append(new ALOAD(1));
|
||||
append(new PUSH(cp, 1 + p.numparams));
|
||||
append(factory.createInvoke(STR_LUAVALUE, "tableOf", TYPE_LUATABLE, new Type[] { TYPE_VARARGS, Type.INT }, Constants.INVOKESTATIC));
|
||||
storeLocal(-1, slot++ );
|
||||
}
|
||||
else if ( p.numparams > 0 ) {
|
||||
append(new ALOAD(1));
|
||||
append(new PUSH(cp, 1 + p.numparams));
|
||||
append(factory.createInvoke(STR_VARARGS, "subargs", TYPE_VARARGS, new Type[] { Type.INT }, Constants.INVOKEVIRTUAL));
|
||||
append(new ASTORE(1));
|
||||
}
|
||||
} else {
|
||||
// fixed arg function between 0 and 3 arguments
|
||||
for ( slot=0; slot<p.numparams; slot++ ) {
|
||||
this.plainSlotVars.put( slot, 1+slot );
|
||||
if ( slots.isUpvalueCreate(-1, slot) ) {
|
||||
append(new ALOAD(1+slot));
|
||||
storeLocal(-1, slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// nil parameters
|
||||
for ( ; slot<p.maxstacksize; slot++ ) {
|
||||
if ( slots.isInitialValueUsed(slot) ) {
|
||||
loadNil();
|
||||
storeLocal(-1, slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] completeClass() {
|
||||
|
||||
// add class initializer
|
||||
if ( ! init.isEmpty() ) {
|
||||
MethodGen mg = new MethodGen(Constants.ACC_STATIC, Type.VOID,
|
||||
new Type[] {}, new String[] {}, "<clinit>", cg
|
||||
.getClassName(), init, cg.getConstantPool());
|
||||
init.append(InstructionConstants.RETURN);
|
||||
mg.setMaxStack();
|
||||
cg.addMethod(mg.getMethod());
|
||||
init.dispose();
|
||||
}
|
||||
|
||||
// add default constructor
|
||||
cg.addEmptyConstructor(Constants.ACC_PUBLIC);
|
||||
|
||||
// gen method
|
||||
resolveBranches();
|
||||
mg.setMaxStack();
|
||||
cg.addMethod(mg.getMethod());
|
||||
main.dispose();
|
||||
|
||||
// convert to class bytes
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
cg.getJavaClass().dump(baos);
|
||||
return baos.toByteArray();
|
||||
} catch ( IOException ioe ) {
|
||||
throw new RuntimeException("JavaClass.dump() threw "+ioe);
|
||||
}
|
||||
}
|
||||
|
||||
public void dup() {
|
||||
append(InstructionConstants.DUP);
|
||||
}
|
||||
|
||||
public void pop() {
|
||||
append(InstructionConstants.POP);
|
||||
}
|
||||
|
||||
public void loadNil() {
|
||||
append(factory.createFieldAccess(STR_LUAVALUE, "NIL", TYPE_LUAVALUE, Constants.GETSTATIC));
|
||||
}
|
||||
|
||||
public void loadNone() {
|
||||
append(factory.createFieldAccess(STR_LUAVALUE, "NONE", TYPE_LUAVALUE, Constants.GETSTATIC));
|
||||
}
|
||||
|
||||
public void loadBoolean(boolean b) {
|
||||
String field = (b? "TRUE": "FALSE");
|
||||
append(factory.createFieldAccess(STR_LUAVALUE, field, TYPE_LUABOOLEAN, Constants.GETSTATIC));
|
||||
}
|
||||
|
||||
private Map<Integer,Integer> plainSlotVars = new HashMap<Integer,Integer>();
|
||||
private Map<Integer,Integer> upvalueSlotVars = new HashMap<Integer,Integer>();
|
||||
private int findSlot( int slot, Map<Integer,Integer> map, String prefix, Type type ) {
|
||||
if ( map.containsKey(slot) )
|
||||
return map.get(slot);
|
||||
String name = prefix+slot;
|
||||
LocalVariableGen local = mg.addLocalVariable(name, type, null, null);
|
||||
int index = local.getIndex();
|
||||
map.put(slot, index);
|
||||
return index;
|
||||
}
|
||||
private int findSlotIndex( int slot, boolean isupvalue ) {
|
||||
return isupvalue?
|
||||
findSlot( slot, upvalueSlotVars, PREFIX_UPVALUE_SLOT, TYPE_LOCALUPVALUE ):
|
||||
findSlot( slot, plainSlotVars, PREFIX_PLAIN_SLOT, TYPE_LUAVALUE );
|
||||
}
|
||||
|
||||
public void loadLocal(int pc, int slot) {
|
||||
boolean isupval = slots.isUpvalueRefer(pc, slot);
|
||||
int index = findSlotIndex( slot, isupval );
|
||||
append(new ALOAD(index));
|
||||
if (isupval) {
|
||||
append(new PUSH(cp, 0));
|
||||
append(InstructionConstants.AALOAD);
|
||||
}
|
||||
}
|
||||
|
||||
public void storeLocal(int pc, int slot) {
|
||||
boolean isupval = slots.isUpvalueAssign(pc, slot);
|
||||
int index = findSlotIndex( slot, isupval );
|
||||
if (isupval) {
|
||||
boolean isupcreate = slots.isUpvalueCreate(pc, slot);
|
||||
if ( isupcreate ) {
|
||||
append(new PUSH(cp, 1));
|
||||
append(new ANEWARRAY(cp.addClass(STR_LUAVALUE)));
|
||||
append(InstructionConstants.DUP);
|
||||
append(new ASTORE(index));
|
||||
} else {
|
||||
append(new ALOAD(index));
|
||||
}
|
||||
append(InstructionConstants.SWAP);
|
||||
append(new PUSH(cp, 0));
|
||||
append(InstructionConstants.SWAP);
|
||||
append(InstructionConstants.AASTORE);
|
||||
} else {
|
||||
append(new ASTORE(index));
|
||||
}
|
||||
}
|
||||
|
||||
private static String upvalueName(int upindex) {
|
||||
return PREFIX_UPVALUE+upindex;
|
||||
}
|
||||
|
||||
public void loadUpvalue(int upindex) {
|
||||
append(InstructionConstants.THIS);
|
||||
append(factory.createFieldAccess(classname, upvalueName(upindex), TYPE_LOCALUPVALUE, Constants.GETFIELD));
|
||||
append(new PUSH(cp,0));
|
||||
append(InstructionConstants.AALOAD);
|
||||
}
|
||||
|
||||
public void storeUpvalue(int pc, int upindex, int slot) {
|
||||
append(InstructionConstants.THIS);
|
||||
append(factory.createFieldAccess(classname, upvalueName(upindex), TYPE_LOCALUPVALUE, Constants.GETFIELD));
|
||||
append(new PUSH(cp,0));
|
||||
loadLocal(pc, slot);
|
||||
append(InstructionConstants.AASTORE);
|
||||
}
|
||||
|
||||
public void newTable( int b, int c ) {
|
||||
append(new PUSH(cp, b));
|
||||
append(new PUSH(cp, c));
|
||||
append(factory.createInvoke(STR_LUAVALUE, "tableOf", TYPE_LUATABLE, new Type[] { Type.INT, Type.INT }, Constants.INVOKESTATIC));
|
||||
}
|
||||
|
||||
public void loadEnv() {
|
||||
append(InstructionConstants.THIS);
|
||||
append(factory.createFieldAccess(classname, "env", TYPE_LUAVALUE, Constants.GETFIELD));
|
||||
}
|
||||
|
||||
public void loadVarargs() {
|
||||
append(new ALOAD(1));
|
||||
}
|
||||
|
||||
public void loadVarargs(int argindex) {
|
||||
loadVarargs();
|
||||
arg(argindex);
|
||||
}
|
||||
|
||||
public void arg(int argindex) {
|
||||
if ( argindex == 1 ) {
|
||||
append(factory.createInvoke(STR_VARARGS, "arg1", TYPE_LUAVALUE, new Type[] {}, Constants.INVOKEVIRTUAL));
|
||||
} else {
|
||||
append(new PUSH(cp, argindex));
|
||||
append(factory.createInvoke(STR_VARARGS, "arg", TYPE_LUAVALUE, new Type[] { Type.INT }, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
}
|
||||
|
||||
private int getVarresultIndex() {
|
||||
if ( varresult == null )
|
||||
varresult = mg.addLocalVariable(NAME_VARRESULT, TYPE_VARARGS, null, null);
|
||||
return varresult.getIndex();
|
||||
}
|
||||
|
||||
public void loadVarresult() {
|
||||
append(new ALOAD(getVarresultIndex()));
|
||||
}
|
||||
|
||||
public void storeVarresult() {
|
||||
append(new ASTORE(getVarresultIndex()));
|
||||
}
|
||||
|
||||
public void subargs(int firstarg) {
|
||||
append(new PUSH(cp, firstarg));
|
||||
append(factory.createInvoke(STR_VARARGS, "subargs", TYPE_VARARGS, new Type[] { Type.INT }, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void getTable() {
|
||||
append(factory.createInvoke(STR_LUAVALUE, "get", TYPE_LUAVALUE, new Type[] { TYPE_LUAVALUE }, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void setTable() {
|
||||
append(factory.createInvoke(STR_LUAVALUE, "set", Type.VOID, new Type[] { TYPE_LUAVALUE, TYPE_LUAVALUE }, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void unaryop(int o) {
|
||||
String op;
|
||||
switch (o) {
|
||||
default:
|
||||
case Lua.OP_UNM: op = "neg"; break;
|
||||
case Lua.OP_NOT: op = "not"; break;
|
||||
case Lua.OP_LEN: op = "len"; break;
|
||||
}
|
||||
append(factory.createInvoke(STR_LUAVALUE, op, TYPE_LUAVALUE, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void binaryop(int o) {
|
||||
String op;
|
||||
switch (o) {
|
||||
default:
|
||||
case Lua.OP_ADD: op = "add"; break;
|
||||
case Lua.OP_SUB: op = "sub"; break;
|
||||
case Lua.OP_MUL: op = "mul"; break;
|
||||
case Lua.OP_DIV: op = "div"; break;
|
||||
case Lua.OP_MOD: op = "mod"; break;
|
||||
case Lua.OP_POW: op = "pow"; break;
|
||||
}
|
||||
append(factory.createInvoke(STR_LUAVALUE, op, TYPE_LUAVALUE, new Type[] { TYPE_LUAVALUE }, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void compareop(int o) {
|
||||
String op;
|
||||
switch (o) {
|
||||
default:
|
||||
case Lua.OP_EQ: op = "eq_b"; break;
|
||||
case Lua.OP_LT: op = "lt_b"; break;
|
||||
case Lua.OP_LE: op = "lteq_b"; break;
|
||||
}
|
||||
append(factory.createInvoke(STR_LUAVALUE, op, Type.BOOLEAN, new Type[] { TYPE_LUAVALUE }, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void areturn() {
|
||||
append(InstructionConstants.ARETURN);
|
||||
}
|
||||
|
||||
public void toBoolean() {
|
||||
append(factory.createInvoke(STR_LUAVALUE, "toboolean", Type.BOOLEAN, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void tostring() {
|
||||
append(factory.createInvoke(STR_BUFFER, "tostring", TYPE_LUASTRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void isNil() {
|
||||
append(factory.createInvoke(STR_LUAVALUE, "isnil", Type.BOOLEAN, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void testForLoop() {
|
||||
append(factory.createInvoke(STR_LUAVALUE, "testfor_b", Type.BOOLEAN, new Type[] { TYPE_LUAVALUE, TYPE_LUAVALUE }, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void loadArrayArgs(int pc, int firstslot, int nargs) {
|
||||
append(new PUSH(cp, nargs));
|
||||
append(new ANEWARRAY(cp.addClass(STR_LUAVALUE)));
|
||||
for ( int i=0; i<nargs; i++ ) {
|
||||
append(InstructionConstants.DUP);
|
||||
append(new PUSH(cp, i));
|
||||
loadLocal(pc, firstslot++);
|
||||
append(new AASTORE());
|
||||
}
|
||||
|
||||
}
|
||||
public void newVarargs(int pc, int firstslot, int nargs) {
|
||||
switch ( nargs ) {
|
||||
case 0: loadNone();
|
||||
break;
|
||||
case 1: loadLocal(pc, firstslot);
|
||||
break;
|
||||
case 2: loadLocal(pc, firstslot); loadLocal(pc, firstslot+1);
|
||||
append(factory.createInvoke(STR_LUAVALUE, "varargsOf", TYPE_VARARGS, new Type[] { TYPE_LUAVALUE, TYPE_VARARGS }, Constants.INVOKESTATIC));
|
||||
break;
|
||||
case 3: loadLocal(pc, firstslot); loadLocal(pc, firstslot+1); loadLocal(pc, firstslot+2);
|
||||
append(factory.createInvoke(STR_LUAVALUE, "varargsOf", TYPE_VARARGS, new Type[] { TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_VARARGS }, Constants.INVOKESTATIC));
|
||||
break;
|
||||
default:
|
||||
loadArrayArgs(pc, firstslot, nargs);
|
||||
append(factory.createInvoke(STR_LUAVALUE, "varargsOf", TYPE_VARARGS, new Type[] { new ArrayType( TYPE_LUAVALUE, 1 ) }, Constants.INVOKESTATIC));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void newVarargsVarresult(int pc, int firstslot, int nslots) {
|
||||
loadArrayArgs(pc, firstslot, nslots );
|
||||
loadVarresult();
|
||||
append(factory.createInvoke(STR_LUAVALUE, "varargsOf", TYPE_VARARGS, new Type[] { new ArrayType( TYPE_LUAVALUE, 1 ), TYPE_VARARGS }, Constants.INVOKESTATIC));
|
||||
}
|
||||
|
||||
public void call(int nargs) {
|
||||
switch ( nargs ) {
|
||||
case 0: append(factory.createInvoke(STR_LUAVALUE, "call", TYPE_LUAVALUE, new Type[] {}, Constants.INVOKEVIRTUAL)); break;
|
||||
case 1: append(factory.createInvoke(STR_LUAVALUE, "call", TYPE_LUAVALUE, new Type[] { TYPE_LUAVALUE }, Constants.INVOKEVIRTUAL)); break;
|
||||
case 2: append(factory.createInvoke(STR_LUAVALUE, "call", TYPE_LUAVALUE, new Type[] { TYPE_LUAVALUE, TYPE_LUAVALUE }, Constants.INVOKEVIRTUAL)); break;
|
||||
case 3: append(factory.createInvoke(STR_LUAVALUE, "call", TYPE_LUAVALUE, new Type[] { TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_LUAVALUE }, Constants.INVOKEVIRTUAL)); break;
|
||||
default: throw new IllegalArgumentException("can't call with "+nargs+" args");
|
||||
}
|
||||
}
|
||||
|
||||
public void newTailcallVarargs() {
|
||||
append(factory.createInvoke(STR_LUAVALUE, "tailcallOf", TYPE_VARARGS, new Type[] { TYPE_LUAVALUE, TYPE_VARARGS }, Constants.INVOKESTATIC));
|
||||
}
|
||||
|
||||
public void invoke(int nargs) {
|
||||
switch ( nargs ) {
|
||||
case -1: append(factory.createInvoke(STR_LUAVALUE, "invoke", TYPE_VARARGS, new Type[] { TYPE_VARARGS }, Constants.INVOKEVIRTUAL)); break;
|
||||
case 0: append(factory.createInvoke(STR_LUAVALUE, "invoke", TYPE_VARARGS, new Type[] {}, Constants.INVOKEVIRTUAL)); break;
|
||||
case 1: append(factory.createInvoke(STR_LUAVALUE, "invoke", TYPE_VARARGS, new Type[] { TYPE_VARARGS }, Constants.INVOKEVIRTUAL)); break;
|
||||
case 2: append(factory.createInvoke(STR_LUAVALUE, "invoke", TYPE_VARARGS, new Type[] { TYPE_LUAVALUE, TYPE_VARARGS }, Constants.INVOKEVIRTUAL)); break;
|
||||
case 3: append(factory.createInvoke(STR_LUAVALUE, "invoke", TYPE_VARARGS, new Type[] { TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_VARARGS }, Constants.INVOKEVIRTUAL)); break;
|
||||
default: throw new IllegalArgumentException("can't invoke with "+nargs+" args");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------ closures ------------------------
|
||||
|
||||
public void closureCreate(String protoname) {
|
||||
append(factory.createNew(new ObjectType(protoname)));
|
||||
append(InstructionConstants.DUP);
|
||||
append(factory.createInvoke(protoname, "<init>", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL));
|
||||
append(InstructionConstants.DUP);
|
||||
loadEnv();
|
||||
append(factory.createInvoke(STR_LUAVALUE, "setfenv", Type.VOID, new Type[] { TYPE_LUAVALUE }, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void closureInitUpvalueFromUpvalue(String protoname, int newup, int upindex) {
|
||||
String srcname = upvalueName(upindex);
|
||||
String destname = upvalueName(newup);
|
||||
append(InstructionConstants.THIS);
|
||||
append(factory.createFieldAccess(classname, srcname, TYPE_LOCALUPVALUE, Constants.GETFIELD));
|
||||
append(factory.createFieldAccess(protoname, destname, TYPE_LOCALUPVALUE, Constants.PUTFIELD));
|
||||
}
|
||||
|
||||
public void closureInitUpvalueFromLocal(String protoname, int newup, int pc, int srcslot) {
|
||||
String destname = upvalueName(newup);
|
||||
int index = findSlotIndex( srcslot, true );
|
||||
append(new ALOAD(index));
|
||||
append(factory.createFieldAccess(protoname, destname, TYPE_LOCALUPVALUE, Constants.PUTFIELD));
|
||||
}
|
||||
|
||||
private Map<LuaValue,String> constants = new HashMap<LuaValue,String>();
|
||||
|
||||
public void loadConstant(LuaValue value) {
|
||||
String name = constants.get(value);
|
||||
if ( name == null ) {
|
||||
name = value.type() == LuaValue.TNUMBER?
|
||||
value.isinttype()?
|
||||
createLuaIntegerField(value.checkint()):
|
||||
createLuaDoubleField(value.checkdouble()):
|
||||
createLuaStringField(value.checkstring());
|
||||
constants.put(value, name);
|
||||
}
|
||||
append(factory.createGetStatic(classname, name, TYPE_LUAVALUE));
|
||||
}
|
||||
|
||||
private String createLuaIntegerField(int value) {
|
||||
String name = PREFIX_CONSTANT+constants.size();
|
||||
FieldGen fg = new FieldGen(Constants.ACC_STATIC | Constants.ACC_FINAL,
|
||||
TYPE_LUAVALUE, name, cp);
|
||||
cg.addField(fg.getField());
|
||||
init.append(new PUSH(cp, value));
|
||||
init.append(factory.createInvoke(STR_LUAVALUE, "valueOf",
|
||||
TYPE_LUAINTEGER, new Type[] { Type.INT }, Constants.INVOKESTATIC));
|
||||
init.append(factory.createPutStatic(classname, name, TYPE_LUAVALUE));
|
||||
return name;
|
||||
}
|
||||
|
||||
private String createLuaDoubleField(double value) {
|
||||
String name = PREFIX_CONSTANT+constants.size();
|
||||
FieldGen fg = new FieldGen(Constants.ACC_STATIC | Constants.ACC_FINAL,
|
||||
TYPE_LUAVALUE, name, cp);
|
||||
cg.addField(fg.getField());
|
||||
init.append(new PUSH(cp, value));
|
||||
init.append(factory.createInvoke(STR_LUAVALUE, "valueOf",
|
||||
TYPE_LUANUMBER, new Type[] { Type.DOUBLE }, Constants.INVOKESTATIC));
|
||||
init.append(factory.createPutStatic(classname, name, TYPE_LUAVALUE));
|
||||
return name;
|
||||
}
|
||||
|
||||
private String createLuaStringField(LuaString value) {
|
||||
String name = PREFIX_CONSTANT+constants.size();
|
||||
FieldGen fg = new FieldGen(Constants.ACC_STATIC | Constants.ACC_FINAL,
|
||||
TYPE_LUAVALUE, name, cp);
|
||||
cg.addField(fg.getField());
|
||||
LuaString ls = value.checkstring();
|
||||
if ( ls.isValidUtf8() ) {
|
||||
init.append(new PUSH(cp, value.toString()));
|
||||
init.append(factory.createInvoke(STR_LUASTRING, "valueOf",
|
||||
TYPE_LUASTRING, new Type[] { Type.STRING }, Constants.INVOKESTATIC));
|
||||
} else {
|
||||
char[] c = new char[ls.m_length];
|
||||
for ( int j=0; j<ls.m_length; j++ )
|
||||
c[j] = (char) (0xff & (int) (ls.m_bytes[ls.m_offset+j]));
|
||||
init.append(new PUSH(cp, new String(c)));
|
||||
init.append(factory.createInvoke(STR_STRING, "toCharArray",
|
||||
TYPE_CHARARRAY, Type.NO_ARGS,
|
||||
Constants.INVOKEVIRTUAL));
|
||||
init.append(factory.createInvoke(STR_LUASTRING, "valueOf",
|
||||
TYPE_LUASTRING, new Type[] { TYPE_CHARARRAY },
|
||||
Constants.INVOKESTATIC));
|
||||
}
|
||||
init.append(factory.createPutStatic(classname, name, TYPE_LUAVALUE));
|
||||
return name;
|
||||
}
|
||||
|
||||
// --------------------- branching support -------------------------
|
||||
public static final int BRANCH_GOTO = 1;
|
||||
public static final int BRANCH_IFNE = 2;
|
||||
public static final int BRANCH_IFEQ = 3;
|
||||
|
||||
public void addBranch( int pc, int branchType, int targetpc ) {
|
||||
switch ( branchType ) {
|
||||
default:
|
||||
case BRANCH_GOTO: branches[pc] = new GOTO(null); break;
|
||||
case BRANCH_IFNE: branches[pc] = new IFNE(null); break;
|
||||
case BRANCH_IFEQ: branches[pc] = new IFEQ(null); break;
|
||||
}
|
||||
targets[pc] = targetpc;
|
||||
append(branches[pc]);
|
||||
}
|
||||
|
||||
|
||||
private void append( Instruction i ) {
|
||||
conditionalSetBeginningOfLua( main.append(i) );
|
||||
}
|
||||
|
||||
private void append( CompoundInstruction i ) {
|
||||
conditionalSetBeginningOfLua( main.append(i) );
|
||||
}
|
||||
|
||||
private void append( BranchInstruction i ) {
|
||||
conditionalSetBeginningOfLua( main.append(i) );
|
||||
}
|
||||
|
||||
private void conditionalSetBeginningOfLua(InstructionHandle ih) {
|
||||
if ( beginningOfLuaInstruction == null )
|
||||
beginningOfLuaInstruction = ih;
|
||||
}
|
||||
|
||||
public void onEndOfLuaInstruction(int pc) {
|
||||
branchDestHandles[pc] = beginningOfLuaInstruction;
|
||||
beginningOfLuaInstruction = null;
|
||||
}
|
||||
|
||||
private void resolveBranches() {
|
||||
int nc = p.code.length;
|
||||
for (int pc = 0; pc < nc; pc++) {
|
||||
if (branches[pc] != null) {
|
||||
if ( branchDestHandles[targets[pc]] == null )
|
||||
throw new IllegalArgumentException("no target at "+targets[pc]+" op="+Lua.GET_OPCODE(p.code[targets[pc]]));
|
||||
branches[pc].setTarget(branchDestHandles[targets[pc]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setlistStack(int pc, int a0, int index0, int nvals) {
|
||||
for ( int i=0; i<nvals; i++ ) {
|
||||
dup();
|
||||
append(new PUSH(cp, index0+i));
|
||||
loadLocal( pc, a0+i );
|
||||
append(factory.createInvoke(STR_LUAVALUE, "rawset", Type.VOID, new Type[] { Type.INT, TYPE_LUAVALUE }, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
}
|
||||
|
||||
public void setlistVarargs(int index0, int vresultbase) {
|
||||
append(new PUSH(cp, index0));
|
||||
loadVarresult();
|
||||
append(factory.createInvoke(STR_LUAVALUE, "rawsetlist", Type.VOID, new Type[] { Type.INT, TYPE_VARARGS }, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void newBuffer() {
|
||||
append(factory.createNew(TYPE_BUFFER));
|
||||
append(InstructionConstants.DUP);
|
||||
append(factory.createInvoke(STR_BUFFER, "<init>", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL));
|
||||
}
|
||||
|
||||
public void appendBuffer() {
|
||||
append(factory.createInvoke(STR_LUAVALUE, "checkstring", TYPE_LUASTRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
|
||||
append(factory.createInvoke(STR_BUFFER, "append", Type.VOID, new Type[] { TYPE_LUASTRING }, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 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.luajc;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import org.luaj.vm2.LoadState;
|
||||
import org.luaj.vm2.LuaClosure;
|
||||
import org.luaj.vm2.LuaFunction;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.LoadState.LuaCompiler;
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
import org.luaj.vm2.lib.PackageLib;
|
||||
|
||||
public class JavaBytecodeCompiler implements LuaCompiler {
|
||||
|
||||
private static JavaBytecodeCompiler instance;
|
||||
private JavaBytecodeGenerator gen;
|
||||
private LuaC luac;
|
||||
|
||||
public static JavaBytecodeCompiler getInstance() {
|
||||
if ( instance == null )
|
||||
instance = new JavaBytecodeCompiler();
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Install the compiler as the main compiler to use.
|
||||
* Will fall back to the LuaC prototype compiler.
|
||||
*/
|
||||
public static final void install() {
|
||||
LoadState.compiler = getInstance();
|
||||
}
|
||||
|
||||
public JavaBytecodeCompiler() {
|
||||
luac = new LuaC();
|
||||
gen = new JavaBytecodeGenerator();
|
||||
}
|
||||
|
||||
/** Compile int a prototype */
|
||||
public static Prototype compile(InputStream is, String chunkname) throws IOException {
|
||||
return getInstance().compile(is.read(), is, chunkname);
|
||||
}
|
||||
|
||||
/** Compile and load a chunk
|
||||
* @throws IOException */
|
||||
public static LuaValue load(InputStream is, String filename, LuaValue _g) throws IOException {
|
||||
return getInstance().load(is.read(), is, filename, _g);
|
||||
}
|
||||
|
||||
/** Compile into protoype form. */
|
||||
public Prototype compile(int firstByte, InputStream stream, String chunkname) throws IOException {
|
||||
return luac.compile(firstByte, stream, chunkname);
|
||||
}
|
||||
|
||||
/** Compile and load a chunk
|
||||
* @throws IOException */
|
||||
public static byte[] loadClass(InputStream is, String filename) throws IOException {
|
||||
return getInstance().loadClass( is.read(), is, filename );
|
||||
}
|
||||
|
||||
/** Compile into class form. */
|
||||
public LuaFunction load(int firstByte, InputStream stream, String filename, LuaValue env) throws IOException {
|
||||
Prototype p = compile( firstByte, stream, filename);
|
||||
return load( p, filename, env );
|
||||
}
|
||||
|
||||
/** Compile into a class */
|
||||
private byte[] loadClass(int firstByte, InputStream stream, String filename) throws IOException {
|
||||
Prototype p = compile(firstByte, stream, filename);
|
||||
return gen.generateBytecode(p, PackageLib.toClassname(filename), toSourcename(filename));
|
||||
}
|
||||
|
||||
/** Compile all classes produced by a prototype, and put results in a hashtable */
|
||||
public static Hashtable loadClasses( InputStream stream, String filename ) throws IOException {
|
||||
if ( LoadState.compiler == null )
|
||||
install();
|
||||
Prototype p = LoadState.compile( stream, filename );
|
||||
Hashtable t = new Hashtable();
|
||||
getInstance().genClass(t, p, PackageLib.toClassname(filename), toSourcename(filename));
|
||||
return t;
|
||||
}
|
||||
|
||||
private void genClass( Hashtable t, Prototype p, String classname, String sourceName ) throws IOException {
|
||||
t.put( classname, gen.generateBytecode( p, classname, sourceName ) );
|
||||
for ( int i=0, n=p.p!=null? p.p.length: 0; i<n; i++ )
|
||||
genClass( t, p.p[i], classname + "$" + i, sourceName );
|
||||
}
|
||||
|
||||
public LuaFunction load(Prototype p, String filename, LuaValue env) {
|
||||
try {
|
||||
Class c = gen.toJavaBytecode(p, PackageLib.toClassname(filename), toSourcename(filename));
|
||||
Object o = c.newInstance();
|
||||
LuaFunction f = (LuaFunction) o;
|
||||
f.setfenv(env);
|
||||
return f;
|
||||
} catch ( Throwable t ) {
|
||||
t.printStackTrace();
|
||||
return new LuaClosure( p, env );
|
||||
}
|
||||
}
|
||||
|
||||
private static final String toSourcename( String filename ) {
|
||||
return filename.substring( filename.lastIndexOf('/')+1 );
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,785 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 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.luajc;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.luaj.vm2.lib.LibFunction;
|
||||
import org.luaj.vm2.luajc.lst.LSChunk;
|
||||
import org.luaj.vm2.luajc.lst.LSExpression;
|
||||
import org.luaj.vm2.luajc.lst.LSField;
|
||||
import org.luaj.vm2.luajc.lst.LSFunction;
|
||||
import org.luaj.vm2.luajc.lst.LSIfStatement;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement;
|
||||
import org.luaj.vm2.luajc.lst.LSVariable;
|
||||
import org.luaj.vm2.luajc.lst.Name;
|
||||
import org.luaj.vm2.luajc.lst.Scope;
|
||||
import org.luaj.vm2.luajc.lst.LSExpression.BinopExpr;
|
||||
import org.luaj.vm2.luajc.lst.LSExpression.FunctionExpr;
|
||||
import org.luaj.vm2.luajc.lst.LSExpression.NumberConstant;
|
||||
import org.luaj.vm2.luajc.lst.LSExpression.StringConstant;
|
||||
import org.luaj.vm2.luajc.lst.LSExpression.TableConstructor;
|
||||
import org.luaj.vm2.luajc.lst.LSExpression.UnopExpr;
|
||||
import org.luaj.vm2.luajc.lst.LSExpression.VarargsRef;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.BreakStat;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.DoBlock;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.ForList;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.ForLoop;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.FunctionCall;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.LocalAssign;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.LocalFunction;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.RepeatUntil;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.ReturnStat;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.VarAssign;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.VarNamedFunction;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.WhileLoop;
|
||||
import org.luaj.vm2.luajc.lst.LSVariable.CallFunction;
|
||||
import org.luaj.vm2.luajc.lst.LSVariable.CallMethod;
|
||||
import org.luaj.vm2.luajc.lst.LSVariable.Field;
|
||||
import org.luaj.vm2.luajc.lst.LSVariable.Index;
|
||||
import org.luaj.vm2.luajc.lst.LSVariable.Method;
|
||||
import org.luaj.vm2.luajc.lst.LSVariable.NameReference;
|
||||
import org.luaj.vm2.luajc.lst.LSVariable.Parentheses;
|
||||
|
||||
public class JavaCodeGenerator {
|
||||
|
||||
public static String toJava(LSChunk chunk) {
|
||||
JavaCodeGenerator jcg = new JavaCodeGenerator();
|
||||
return jcg.writeChunk( chunk );
|
||||
}
|
||||
|
||||
public final Stack<StringBuffer> stringBuffers = new Stack<StringBuffer>();
|
||||
public StringBuffer sb;
|
||||
private int indent = 0;
|
||||
|
||||
public JavaCodeGenerator() {
|
||||
this.sb = new StringBuffer();
|
||||
}
|
||||
|
||||
private String writeChunk(LSChunk chunk) {
|
||||
pushFunctionContext();
|
||||
writeln( "import org.luaj.vm2.*;" );
|
||||
writeln( "import org.luaj.vm2.lib.*;" );
|
||||
writeln();
|
||||
writeln( "public class "+chunk.chunkname+" extends VarArgFunction {" );
|
||||
++indent;
|
||||
writeln( "public Varargs invoke(Varargs $args) {");
|
||||
++indent;
|
||||
writeFunctionBody( chunk.function );
|
||||
--indent;
|
||||
writeln( "}");
|
||||
--indent;
|
||||
// TODO: write out chunk constants
|
||||
writeln( "}" );
|
||||
return popFunctionContext();
|
||||
}
|
||||
|
||||
private void pushFunctionContext() {
|
||||
stringBuffers.push( sb = new StringBuffer() );
|
||||
}
|
||||
|
||||
private String popFunctionContext() {
|
||||
String v = stringBuffers.pop().toString();
|
||||
sb = stringBuffers.isEmpty()? null: stringBuffers.lastElement();
|
||||
return v;
|
||||
}
|
||||
|
||||
private void writeFunctionBody(LSFunction function) {
|
||||
if ( function.hasandlogic || function.hasorlogic )
|
||||
writeln( "LuaValue $t;" );
|
||||
if ( function.hasvarargassign )
|
||||
writeln( "Varargs $v;" );
|
||||
writeStatements( function.stats );
|
||||
if ( LSStatement.isNextStatementReachable( function.stats ) )
|
||||
writeln( "return NONE;" );
|
||||
}
|
||||
|
||||
private void writeStatements(List<LSStatement> statements) {
|
||||
for ( LSStatement s : statements ) {
|
||||
writeStatement( s );
|
||||
}
|
||||
}
|
||||
|
||||
private void writeStatement(LSStatement s) {
|
||||
if ( s==null ) return;
|
||||
switch ( s.type ) {
|
||||
case functionCall: writeFunctionCall( (LSStatement.FunctionCall) s ); break;
|
||||
case doBlock: writeDoBlock( (LSStatement.DoBlock) s ); break;
|
||||
case whileLoop: writeWhileLoop( (LSStatement.WhileLoop) s ); break;
|
||||
case repeatUntil: writeRepeatUntil( (LSStatement.RepeatUntil) s ); break;
|
||||
case varAssign: writeVarAssign( (LSStatement.VarAssign) s ); break;
|
||||
case forLoop: writeForLoop( (LSStatement.ForLoop) s ); break;
|
||||
case forList: writeForList( (LSStatement.ForList) s ); break;
|
||||
case varNamedFunction: writeVarNamedFunction((LSStatement.VarNamedFunction) s ); break;
|
||||
case localFunction: writeLocalFunction( (LSStatement.LocalFunction) s ); break;
|
||||
case localAssign: writeLocalAssign( (LSStatement.LocalAssign) s ); break;
|
||||
case returnStat: writeReturnStat( (LSStatement.ReturnStat) s ); break;
|
||||
case breakStat: writeBreakStat( (LSStatement.BreakStat) s ); break;
|
||||
case ifStat: writeIfStat( (LSIfStatement) s ); break;
|
||||
}
|
||||
}
|
||||
|
||||
private void writeFunctionCall(FunctionCall s) {
|
||||
writeindent();
|
||||
write( eval(s.variable)+";" );
|
||||
writeln();
|
||||
}
|
||||
|
||||
private void writeDoBlock(DoBlock s) {
|
||||
writeln( "{" );
|
||||
++indent;
|
||||
writeStatements( s.statements );
|
||||
--indent;
|
||||
writeln( "}" );
|
||||
}
|
||||
|
||||
private void writeWhileLoop(WhileLoop s) {
|
||||
writeln( "while ("+eval(s.condition)+".toboolean()) {" );
|
||||
++indent;
|
||||
writeStatements( s.statements );
|
||||
--indent;
|
||||
writeln( "}" );
|
||||
}
|
||||
|
||||
private void writeRepeatUntil(RepeatUntil s) {
|
||||
writeln( "do {" );
|
||||
++indent;
|
||||
writeStatements( s.statements );
|
||||
--indent;
|
||||
writeln( "} while (!"+eval(s.condition)+");" );
|
||||
}
|
||||
|
||||
private void writeForLoop(ForLoop s) {
|
||||
writeln( "{" );
|
||||
++indent;
|
||||
// TODO: name handling, also upvalues!
|
||||
String index = javaName( s.index );
|
||||
String limit = javaName( s.scope.declare("$limit") );
|
||||
String step = javaName( s.scope.declare("$step") );
|
||||
writeln( "LuaValue "+index+"="+eval(s.initial)+";" );
|
||||
writeln( "final LuaValue "+limit+"="+eval(s.limit)+";" );
|
||||
if ( s.step != null ) {
|
||||
writeln( "final LuaValue "+step+"="+eval(s.step)+";" );
|
||||
writeln( "final boolean "+step+"$b="+step+".gt_b(0);" );
|
||||
}
|
||||
if ( s.step != null ) {
|
||||
writeln( "for ( ; "+index+".testfor_b("+limit+","+step+"$b); "+index+"="+index+".add("+step+") ) {" );
|
||||
} else {
|
||||
writeln( "for ( ; "+index+".lteq_b("+limit+"); "+index+"="+index+".add(1) ) {" );
|
||||
}
|
||||
++indent;
|
||||
writeStatements( s.statements );
|
||||
--indent;
|
||||
writeln( "}" );
|
||||
--indent;
|
||||
writeln( "}" );
|
||||
}
|
||||
|
||||
private void writeForList(ForList s) {
|
||||
writeln( "{" );
|
||||
++indent;
|
||||
List<String> exprs = evalExpressions(s.expressions, 3, s.scope);
|
||||
// TODO: upvalues handling!
|
||||
String fun = javaName( s.scope.declare("$f") );
|
||||
String sta = javaName( s.scope.declare("$s") );
|
||||
String var = javaName( s.scope.declare("$var") );
|
||||
String res = javaName( s.scope.declare("$res") );
|
||||
writeln( "LuaValue "+fun+"="+exprs.get(0)+";" );
|
||||
writeln( "LuaValue "+sta+"="+exprs.get(1)+";" );
|
||||
writeln( "LuaValue "+var+"="+exprs.get(2)+";" );
|
||||
writeln( "while ( true ) {" );
|
||||
++indent;
|
||||
writeln( "Varargs "+res+" = "+fun+".invoke(varargsOf("+sta+","+var+"));" );
|
||||
for ( int i=1, n=s.names.size(); i<=n; i++ )
|
||||
writeln( "LuaValue "+javaName(s.names.get(i-1))+"="+res+".arg("+i+");" );
|
||||
writeln( var+"="+javaName(s.names.get(0))+";" );
|
||||
writeln( "if ( "+var+".isnil() ) break;" );
|
||||
writeStatements( s.statements );
|
||||
--indent;
|
||||
writeln( "}" );
|
||||
--indent;
|
||||
writeln( "}" );
|
||||
}
|
||||
|
||||
private final static Set<String> reserved = new HashSet<String>();
|
||||
static {
|
||||
String[] specials = {
|
||||
// keywors used by our code generator
|
||||
"name", "opcode", "env",
|
||||
|
||||
// java keywords
|
||||
"abstract", "continue", "for", "new", "switch",
|
||||
"assert", "default", "goto", "package", "synchronized",
|
||||
"boolean", "do", "if", "private", "this",
|
||||
"break", "double", "implements", "protected", "throw",
|
||||
"byte", "else", "import", "public", "throws",
|
||||
"case", "enum", "instanceof", "return", "transient",
|
||||
"catch", "extends", "int", "short", "try",
|
||||
"char", "final", "interface", "static", "void",
|
||||
"class", "finally", "long", "strictfp", "volatile",
|
||||
"const", "float", "native", "super", "while",
|
||||
};
|
||||
for ( int i=0; i<specials.length; i++ )
|
||||
reserved.add( specials[i] );
|
||||
java.lang.reflect.Field[] f = LibFunction.class.getFields();
|
||||
for ( int i=0; i<f.length; i++ )
|
||||
reserved.add( f[i].getName() );
|
||||
}
|
||||
|
||||
private String javaName(Name name) {
|
||||
return name.innerrevision>0?
|
||||
name.luaname+"$"+name.innerrevision:
|
||||
reserved.contains(name.luaname)? (name.luaname+"$"): name.luaname;
|
||||
}
|
||||
|
||||
private void writeVarNamedFunction(VarNamedFunction s) {
|
||||
String funcdef = evalFuncbody(s.funcbody);
|
||||
writeAssign( s.funcname, funcdef );
|
||||
}
|
||||
|
||||
private String evalFuncbody(LSFunction funcbody) {
|
||||
pushFunctionContext();
|
||||
int n = funcbody.paramnames!=null? funcbody.paramnames.size(): 0;
|
||||
boolean isvararg = (funcbody.isvararg || n > 3);
|
||||
if ( isvararg ) {
|
||||
write( "new VarArgFunction(env) {\n" );
|
||||
++indent;
|
||||
writeln( "public Varargs invoke(Varargs $args) {" );
|
||||
++indent;
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
Name name = funcbody.paramnames.get(i);
|
||||
if ( name.isupvalue )
|
||||
writeln( "final LuaValue[] "+javaName(funcbody.paramnames.get(i))+"={$args.arg("+(i+1)+")};" );
|
||||
else
|
||||
writeln( "LuaValue "+javaName(funcbody.paramnames.get(i))+"=$args.arg("+(i+1)+");" );
|
||||
}
|
||||
if ( (n > 0 && funcbody.usesvarargs) || funcbody.needsarg )
|
||||
writeln( "$args = $args.subargs("+(n+1)+");" );
|
||||
if ( funcbody.needsarg )
|
||||
writeln( "LuaValue arg = new LuaTable($args);" );
|
||||
else if ( funcbody.hasarg )
|
||||
writeln( "LuaValue arg = NIL;" );
|
||||
writeFunctionBody(funcbody);
|
||||
--indent;
|
||||
writeln( "}" );
|
||||
--indent;
|
||||
writeindent();
|
||||
write( "}" );
|
||||
} else {
|
||||
write(
|
||||
n==0? "new ZeroArgFunction(env) {\n":
|
||||
n==1? "new OneArgFunction(env) {\n":
|
||||
n==2? "new TwoArgFunction(env) {\n":
|
||||
"new ThreeArgFunction(env) {\n" );
|
||||
++indent;
|
||||
writeindent();
|
||||
write( "public LuaValue call(");
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
if (i>0) write( "," );
|
||||
Name name = funcbody.paramnames.get(i);
|
||||
if ( name.isupvalue )
|
||||
write( "LuaValue "+javaName(name)+"$u" );
|
||||
else
|
||||
write( "LuaValue "+javaName(name) );
|
||||
}
|
||||
write( ") {" );
|
||||
writeln();
|
||||
++indent;
|
||||
|
||||
// upvalues
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
Name name = funcbody.paramnames.get(i);
|
||||
if ( name.isupvalue )
|
||||
writeln( "final LuaValue[] "+javaName(name)+"={"+javaName(name)+"$u};" );
|
||||
}
|
||||
|
||||
// function body
|
||||
writeFunctionBody(funcbody);
|
||||
--indent;
|
||||
writeln( "}" );
|
||||
--indent;
|
||||
writeindent();
|
||||
write( "}" );
|
||||
}
|
||||
return popFunctionContext();
|
||||
}
|
||||
|
||||
private void writeVarAssign(VarAssign s) {
|
||||
int nassign = s.variables.size();
|
||||
List<String> exprs = evalExpressions(s.expressions, nassign, s.scope);
|
||||
for ( int i=0; i<nassign; i++ )
|
||||
writeAssign( s.variables.get(i), exprs.get(i) );
|
||||
for ( int i=nassign; i<exprs.size(); i++ )
|
||||
writeln( exprs.get(i) );
|
||||
}
|
||||
|
||||
private void writeLocalFunction(LocalFunction s) {
|
||||
String funcdef = evalFuncbody(s.funcbody);
|
||||
if ( s.name.isupvalue ) {
|
||||
writeln( "final LuaValue[] "+javaName(s.name)+"={null};" );
|
||||
writeln( javaName(s.name)+"[0]="+funcdef+";" );
|
||||
} else
|
||||
writeln( "LuaValue "+javaName(s.name)+"="+funcdef+";" );
|
||||
}
|
||||
|
||||
private void writeLocalAssign(LocalAssign s) {
|
||||
int nassign = s.names.size();
|
||||
List<String> exprs = evalExpressions(s.expressions, nassign, s.scope);
|
||||
for ( int i=0; i<nassign; i++ ) {
|
||||
Name name= s.names.get(i);
|
||||
if ( name.isupvalue )
|
||||
writeln( "final LuaValue[] "+javaName(name)+"={"+exprs.get(i)+"};" );
|
||||
else
|
||||
writeln( "LuaValue "+javaName(name)+"="+exprs.get(i)+";" );
|
||||
}
|
||||
for ( int i=nassign; i<exprs.size(); i++ )
|
||||
writeln( exprs.get(i)+";" );
|
||||
}
|
||||
|
||||
/** Evaluate expressions for use in assignment
|
||||
* @param scope */
|
||||
private List<String> evalExpressions(List<LSExpression> exprs, int nassign, Scope scope) {
|
||||
int nexpr = (exprs!=null? exprs.size(): 0);
|
||||
List<String> e = new ArrayList<String>(nexpr);
|
||||
boolean hasvarargs = false;
|
||||
for ( int i=0; i<nexpr || i<nassign; i++ ) {
|
||||
if ( i<nexpr-1 || nassign <= nexpr ) {
|
||||
e.add( eval( exprs.get(i) ) );
|
||||
} else if ( i==nexpr-1 ) {
|
||||
int nr = exprs.get(i).getNumReturns();
|
||||
hasvarargs = (nr==-1) || (nr>1);
|
||||
if ( hasvarargs )
|
||||
e.add( "($v="+eval(exprs.get(i))+").arg1()" );
|
||||
else
|
||||
e.add( eval(exprs.get(i)) );
|
||||
} else if (hasvarargs) {
|
||||
e.add( "$v.arg("+(i-nexpr+2)+")" );
|
||||
} else {
|
||||
e.add( "NIL" );
|
||||
}
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
private void writeReturnStat(ReturnStat s) {
|
||||
int n = s.expressions!=null? s.expressions.size(): 0;
|
||||
if ( ! s.function.isvararg )
|
||||
writeln( n==0? "return NONE;": "return "+eval(s.expressions.get(0))+";" );
|
||||
else {
|
||||
writeindent();
|
||||
switch ( n ) {
|
||||
case 0:
|
||||
write( "return NONE;" );
|
||||
break;
|
||||
case 1:
|
||||
write( "return "+eval( s.expressions.get(0))+";" );
|
||||
break;
|
||||
case 2: case 3: {
|
||||
write( "return varargsOf(" );
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
if (i>0) write( "," );
|
||||
write( eval( s.expressions.get(i)) );
|
||||
}
|
||||
write( ");" );
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
write( "return varargsOf(new LuaValue[] {" );
|
||||
for ( int i=0; i<n-1; i++ ) {
|
||||
if (i>0) write( "," );
|
||||
write( eval( s.expressions.get(i)) );
|
||||
}
|
||||
write( "},"+eval(s.expressions.get(n-1))+");" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
writeln();
|
||||
}
|
||||
}
|
||||
|
||||
private void writeBreakStat(BreakStat s) {
|
||||
writeln( "break;" );
|
||||
}
|
||||
|
||||
private void writeIfStat(LSIfStatement s) {
|
||||
writeln( "if ("+eval_bool(s.condition)+") {" );
|
||||
++indent;
|
||||
writeStatements( s.statements );
|
||||
if ( s.elseifs != null ) {
|
||||
for ( LSIfStatement.ElseIf elseif : s.elseifs ) {
|
||||
--indent;
|
||||
writeln( "} else if ("+eval_bool(elseif.condition)+") {" );
|
||||
++indent;
|
||||
writeStatements( elseif.statements );
|
||||
}
|
||||
}
|
||||
if ( s.elsestatements != null ) {
|
||||
--indent;
|
||||
writeln( "} else {" );
|
||||
++indent;
|
||||
writeStatements( s.elsestatements );
|
||||
}
|
||||
--indent;
|
||||
writeln( "}" );
|
||||
}
|
||||
|
||||
//-------------------------------------------
|
||||
// assignment using variables
|
||||
//-------------------------------------------
|
||||
|
||||
/** Write assignment of a particular variable value */
|
||||
private void writeAssign(LSVariable v, String expression) {
|
||||
switch ( v.type ) {
|
||||
case nameVariable: writeNameAssign( (LSVariable.NameReference) v, expression); break;
|
||||
case fieldVariable: writeFieldAssign( (LSVariable.Field) v, expression); break;
|
||||
case methodVariable: writeMethodAssign( (LSVariable.Method) v, expression); break;
|
||||
case parenthesesVariable: writeParenAssign( (LSVariable.Parentheses) v, expression); break;
|
||||
case indexVariable: writeIndexAssign( (LSVariable.Index) v, expression); break;
|
||||
case callFunctionVariable: writeCallFuncAssign((LSVariable.CallFunction)v, expression); break;
|
||||
case callMethodVariable: writeCallMethAssign((LSVariable.CallMethod) v, expression); break;
|
||||
}
|
||||
}
|
||||
|
||||
private void writeNameAssign(NameReference v, String expression) {
|
||||
if ( v.name.isGlobal() )
|
||||
writeln( "env.set(\""+v.name.luaname+"\","+expression+");");
|
||||
else if ( v.name.isupvalue )
|
||||
writeln( javaName(v.name)+"[0]="+expression+";");
|
||||
else
|
||||
writeln( javaName(v.name)+"="+expression+";");
|
||||
}
|
||||
|
||||
private void writeFieldAssign(Field v, String expression) {
|
||||
String base = eval(v.variable);
|
||||
writeln( base+".set(\""+v.field+"\","+expression+");");
|
||||
}
|
||||
|
||||
private void writeMethodAssign(Method v, String expression) {
|
||||
String base = eval(v.variable);
|
||||
writeln( base+".set(\""+v.method+"\","+expression+");");
|
||||
}
|
||||
|
||||
private void writeParenAssign(Parentheses v, String expression) {
|
||||
throw new IllegalArgumentException("no assignment for parenthesis expressions");
|
||||
}
|
||||
|
||||
private void writeIndexAssign(Index v, String expression) {
|
||||
String base = eval(v.variable);
|
||||
writeln( base+".set("+eval(v.expression)+","+expression+");");
|
||||
}
|
||||
|
||||
private void writeCallFuncAssign(CallFunction v, String expression) {
|
||||
throw new IllegalArgumentException("no assignment for call function expressions");
|
||||
}
|
||||
|
||||
private void writeCallMethAssign(CallMethod v, String expression) {
|
||||
throw new IllegalArgumentException("no assignment for call method expressions");
|
||||
}
|
||||
|
||||
//-------------------------------------------
|
||||
// write out expressions
|
||||
//-------------------------------------------
|
||||
|
||||
private String eval_bool(LSExpression e) {
|
||||
return eval(e)+".toboolean()";
|
||||
}
|
||||
|
||||
/** evaluate the expression to a particular operand type */
|
||||
private String eval(LSExpression e) {
|
||||
if ( e==null ) return "NONE";
|
||||
switch ( e.type ) {
|
||||
case nilConstant: return "NIL";
|
||||
case trueConstant: return "TRUE";
|
||||
case falseConstant: return "FALSE";
|
||||
case unop: return evalUnop( (LSExpression.UnopExpr) e);
|
||||
case binop: return evalBinop( (LSExpression.BinopExpr) e);
|
||||
case functionExpr: return evalFunction((LSExpression.FunctionExpr) e);
|
||||
case tableConstructor: return evalTable( (LSExpression.TableConstructor) e);
|
||||
case numberConstant: return evalNumber( (LSExpression.NumberConstant) e);
|
||||
case stringConstant: return evalString( (LSExpression.StringConstant) e);
|
||||
|
||||
// variable types
|
||||
case nameVariable: return evalNameRef( (LSVariable.NameReference) e);
|
||||
case fieldVariable: return evalField( (LSVariable.Field) e);
|
||||
case methodVariable: return evalMethod( (LSVariable.Method) e);
|
||||
case parenthesesVariable: return evalParen( (LSVariable.Parentheses) e);
|
||||
case indexVariable: return evalIndex( (LSVariable.Index) e);
|
||||
case callFunctionVariable: return evalCallFunc((LSVariable.CallFunction) e);
|
||||
case callMethodVariable: return evalCallMeth((LSVariable.CallMethod) e);
|
||||
case varargsRef: return evalVarargs( (LSExpression.VarargsRef) e);
|
||||
|
||||
default: throw new IllegalArgumentException("unknown expression type: "+e.type);
|
||||
}
|
||||
}
|
||||
|
||||
private String evalUnop(UnopExpr e) {
|
||||
switch ( e.op.type ) {
|
||||
case neg: return eval( e.rhs )+".neg()";
|
||||
case not: return eval( e.rhs )+".not()";
|
||||
case len: return eval( e.rhs )+".len()";
|
||||
}
|
||||
throw new IllegalArgumentException("unknown unary operand: "+e.op );
|
||||
}
|
||||
|
||||
private String evalBinop(BinopExpr e) {
|
||||
switch ( e.op.type ) {
|
||||
case pow: return eval(e.lhs)+".pow("+eval(e.rhs)+")";
|
||||
case mul: return eval(e.lhs)+".mul("+eval(e.rhs)+")";
|
||||
case div: return eval(e.lhs)+".div("+eval(e.rhs)+")";
|
||||
case mod: return eval(e.lhs)+".mod("+eval(e.rhs)+")";
|
||||
case add: return eval(e.lhs)+".add("+eval(e.rhs)+")";
|
||||
case sub: return eval(e.lhs)+".sub("+eval(e.rhs)+")";
|
||||
case concat: return eval(e.lhs)+".concat("+eval(e.rhs)+")";
|
||||
case lt: return eval(e.lhs)+".lt("+eval(e.rhs)+")";
|
||||
case lteq: return eval(e.lhs)+".lteq("+eval(e.rhs)+")";
|
||||
case gt: return eval(e.lhs)+".gt("+eval(e.rhs)+")";
|
||||
case gteq: return eval(e.lhs)+".gteq("+eval(e.rhs)+")";
|
||||
case eq: return eval(e.lhs)+".eq("+eval(e.rhs)+")";
|
||||
case neq: return eval(e.lhs)+".neq("+eval(e.rhs)+")";
|
||||
case and: return "(($t="+eval(e.lhs)+").toboolean()? "+eval(e.rhs)+": $t)";
|
||||
case or: return "(($t="+eval(e.lhs)+").toboolean()? $t: "+eval(e.rhs)+")";
|
||||
default: throw new IllegalStateException("unknoqn binary operator: "+e.op);
|
||||
}
|
||||
}
|
||||
|
||||
private String evalFunction(FunctionExpr e) {
|
||||
return evalFuncbody(e.function);
|
||||
}
|
||||
|
||||
private String evalTable(TableConstructor e) {
|
||||
StringBuffer named = new StringBuffer();
|
||||
StringBuffer numbered = new StringBuffer();
|
||||
LSExpression varargsLastListValue = null;
|
||||
for ( int i=0, n=e.fields.size(); i<n; i++ ) {
|
||||
LSField f = e.fields.get(i);
|
||||
switch ( f.type ) {
|
||||
case keyValue:
|
||||
LSField.KeyValue k = (LSField.KeyValue) f;
|
||||
named.append( eval(k.key)+","+eval(k.value)+",");
|
||||
break;
|
||||
case nameValue:
|
||||
LSField.NameValue nv = (LSField.NameValue) f;
|
||||
named.append( "valueOf(\""+nv.name+"\"),"+eval(nv.value)+",");
|
||||
break;
|
||||
case listValue:
|
||||
LSField.ListValue l = (LSField.ListValue) f;
|
||||
int nr = l.value.getNumReturns();
|
||||
if ( i<n-1 && (nr==1) )
|
||||
numbered.append( eval(l.value)+",");
|
||||
else
|
||||
varargsLastListValue = l.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// TODO: generated more targeted constructor
|
||||
return "tableOf("
|
||||
+(named .length()>0? "new LuaValue[] {"+named +"}": "null")+","
|
||||
+(numbered.length()>0? "new LuaValue[] {"+numbered+"}": "null")
|
||||
+(varargsLastListValue!=null? ","+eval(varargsLastListValue): "")+")";
|
||||
}
|
||||
|
||||
private String evalNumber(NumberConstant e) {
|
||||
// TODO: internalize constants
|
||||
return "valueOf("+e.value+")";
|
||||
}
|
||||
|
||||
private String evalString(StringConstant e) {
|
||||
// TODO: internalize constants
|
||||
return "valueOf("+toStrValueInitializer(e.bytes)+")";
|
||||
}
|
||||
|
||||
private String toStrValueInitializer(byte[] bytes) {
|
||||
int n = bytes.length;
|
||||
StringBuffer sb = new StringBuffer(n+2);
|
||||
|
||||
// check for characters beyond ascii 128
|
||||
for ( int i=0; i<n; i++ )
|
||||
if (bytes[i]<0) {
|
||||
sb.append( "new byte[]{" );
|
||||
for ( int j=0; j<n; j++ ) {
|
||||
if ( j>0 ) sb.append(",");
|
||||
byte b = bytes[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<n; i++ ) {
|
||||
byte b = bytes[i];
|
||||
switch ( b ) {
|
||||
case '\b': sb.append( "\\b" ); break;
|
||||
case '\f': sb.append( "\\f" ); break;
|
||||
case '\n': sb.append( "\\n" ); break;
|
||||
case '\r': sb.append( "\\r" ); break;
|
||||
case '\t': sb.append( "\\t" ); break;
|
||||
case '"': sb.append( "\\\"" ); break;
|
||||
case '\\': sb.append( "\\\\" ); break;
|
||||
default:
|
||||
if ( b >= ' ' ) {
|
||||
sb.append( (char) b ); break;
|
||||
} else {
|
||||
// convert from UTF-8
|
||||
int u = 0xff & (int) b;
|
||||
if ( u>=0xc0 && i+1<n ) {
|
||||
if ( u>=0xe0 && i+2<n ) {
|
||||
u = ((u & 0xf) << 12) | ((0x3f & bytes[i+1]) << 6) | (0x3f & bytes[i+2]);
|
||||
i+= 2;
|
||||
} else {
|
||||
u = ((u & 0x1f) << 6) | (0x3f & bytes[++i]);
|
||||
}
|
||||
}
|
||||
sb.append( "\\u" );
|
||||
sb.append( Integer.toHexString(0x10000+u).substring(1) );
|
||||
}
|
||||
}
|
||||
}
|
||||
sb.append('"');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
private String evalNameRef(NameReference v) {
|
||||
if ( v.name.isGlobal() )
|
||||
return "env.get(\""+v.name.luaname+"\")";
|
||||
else if ( v.name.isupvalue )
|
||||
return javaName(v.name)+"[0]";
|
||||
else
|
||||
return javaName(v.name);
|
||||
}
|
||||
|
||||
private String evalField(Field e) {
|
||||
return eval(e.variable)+".get(\""+e.field+"\")";
|
||||
}
|
||||
|
||||
private String evalMethod(Method e) {
|
||||
// FIXME: check api, fix this
|
||||
return eval(e.variable)+".get(\""+e.method+"\")";
|
||||
}
|
||||
|
||||
private String evalParen(Parentheses e) {
|
||||
return eval(e.expression)+".arg1()";
|
||||
}
|
||||
|
||||
private String evalIndex(Index e) {
|
||||
return eval(e.variable)+".get("+eval(e.expression)+")";
|
||||
}
|
||||
|
||||
private String evalCallFunc(CallFunction e) {
|
||||
int n = e.parameters.size();
|
||||
boolean isVarargsReturn = e.numReturns < 0 || e.numReturns > 1;
|
||||
boolean isVarargsCall = n>0 && e.parameters.get(n-1).getNumReturns() < 0;
|
||||
String base = eval(e.variable);
|
||||
if ( n <= 3 && !isVarargsReturn && !isVarargsCall ) {
|
||||
return base+".call("+evalParamList(e.parameters)+")";
|
||||
} else {
|
||||
String coerce = e.numReturns==1? ".arg1()": "";
|
||||
switch ( n ) {
|
||||
case 0:
|
||||
return base+".invoke()"+coerce;
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
return base+".invoke("+evalParamList(e.parameters)+")"+coerce;
|
||||
default:
|
||||
if ( isVarargsCall ) {
|
||||
LSExpression last = e.parameters.remove(n-1);
|
||||
return base+".invoke(new LuaValue[]{"+evalParamList(e.parameters)+"},"+eval(last)+")"+coerce;
|
||||
} else {
|
||||
return base+".invoke(new LuaValue[]{"+evalParamList(e.parameters)+"})"+coerce;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String evalCallMeth(CallMethod e) {
|
||||
int n = e.parameters.size();
|
||||
String base = eval(e.variable);
|
||||
if ( n <= 3 && e.numReturns == 0 || e.numReturns == 1 ) {
|
||||
return base+".method(\""+e.method+"\""+(e.parameters.size()>0? ",": "")+evalParamList(e.parameters)+")";
|
||||
} else {
|
||||
return base+".invokemethod(\""+e.method+"\",new LuaValue[]{"+evalParamList(e.parameters)+"})";
|
||||
}
|
||||
}
|
||||
|
||||
private String evalVarargs(VarargsRef e) {
|
||||
switch ( e.numReturns ) {
|
||||
case 0: return "NIL";
|
||||
case 1: return "$args.arg1()";
|
||||
default: return "$args";
|
||||
}
|
||||
}
|
||||
|
||||
private String evalParamList(List<LSExpression> parameters) {
|
||||
if ( parameters == null || parameters.size() == 0 )
|
||||
return "";
|
||||
StringBuffer p = new StringBuffer();
|
||||
for ( int i=0, n=parameters.size(); i<n; i++ ) {
|
||||
if (i>0) p.append(",");
|
||||
p.append( eval( parameters.get(i) ) );
|
||||
}
|
||||
return p.toString();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------
|
||||
// write individual strings and lines
|
||||
//-------------------------------------------
|
||||
|
||||
|
||||
private void writeindent() {
|
||||
for ( int i=0; i<indent; i++ )
|
||||
sb.append( " " );
|
||||
}
|
||||
private void write( String str ) {
|
||||
sb.append( str );
|
||||
}
|
||||
private void writeln() {
|
||||
sb.append( '\n' );
|
||||
}
|
||||
private void writeln( String line ) {
|
||||
writeindent();
|
||||
write( line );
|
||||
writeln();
|
||||
}
|
||||
|
||||
}
|
||||
418
src/jse/org/luaj/vm2/luajc/JavaGen.java
Normal file
418
src/jse/org/luaj/vm2/luajc/JavaGen.java
Normal file
@@ -0,0 +1,418 @@
|
||||
/*******************************************************************************
|
||||
* 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.luajc;
|
||||
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.Prototype;
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
* propogate constants
|
||||
* loader can find inner classes
|
||||
*/
|
||||
public class JavaGen {
|
||||
|
||||
public String classname;
|
||||
public byte[] bytecode;
|
||||
public JavaGen[] inners;
|
||||
|
||||
public JavaGen( Prototype p, String classname, String filename ) {
|
||||
this.classname = classname;
|
||||
|
||||
// build this class
|
||||
JavaBuilder builder = new JavaBuilder(p, classname, filename);
|
||||
scanInstructions(p, classname, builder);
|
||||
this.bytecode = builder.completeClass();
|
||||
|
||||
// build sub-prototypes
|
||||
int n = p.p.length;
|
||||
inners = new JavaGen[n];
|
||||
for ( int i=0; i<n; i++ )
|
||||
inners[i] = new JavaGen(p.p[i], closureName(classname,i), filename);
|
||||
}
|
||||
|
||||
private String closureName(String classname, int subprotoindex) {
|
||||
return classname+"$"+subprotoindex;
|
||||
}
|
||||
|
||||
private void scanInstructions(Prototype p, String classname, JavaBuilder builder) {
|
||||
int vresultbase = -1;
|
||||
|
||||
for ( int pc=0, n=p.code.length; pc<n; pc++ ) {
|
||||
int ins = p.code[pc];
|
||||
int o = Lua.GET_OPCODE(ins);
|
||||
int a = Lua.GETARG_A(ins);
|
||||
int b = Lua.GETARG_B(ins);
|
||||
int bx = Lua.GETARG_Bx(ins);
|
||||
int sbx = Lua.GETARG_sBx(ins);
|
||||
int c = Lua.GETARG_C(ins);
|
||||
|
||||
switch ( o ) {
|
||||
case Lua.OP_GETUPVAL: /* A B R(A):= UpValue[B] */
|
||||
builder.loadUpvalue( b );
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_SETUPVAL: /* A B UpValue[B]:= R(A) */
|
||||
builder.storeUpvalue( pc, b, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_NEWTABLE: /* A B C R(A):= {} (size = B,C) */
|
||||
builder.newTable( b, c );
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_MOVE:/* A B R(A):= R(B) */
|
||||
builder.loadLocal( pc, b );
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_UNM: /* A B R(A):= -R(B) */
|
||||
case Lua.OP_NOT: /* A B R(A):= not R(B) */
|
||||
case Lua.OP_LEN: /* A B R(A):= length of R(B) */
|
||||
builder.loadLocal( pc, b );
|
||||
builder.unaryop( o );
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_LOADK:/* A Bx R(A):= Kst(Bx) */
|
||||
builder.loadConstant( p.k[bx] );
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_GETGLOBAL: /* A Bx R(A):= Gbl[Kst(Bx)] */
|
||||
builder.loadEnv();
|
||||
builder.loadConstant( p.k[bx] );
|
||||
builder.getTable();
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_SETGLOBAL: /* A Bx Gbl[Kst(Bx)]:= R(A) */
|
||||
builder.loadEnv();
|
||||
builder.loadConstant( p.k[bx] );
|
||||
builder.loadLocal( pc, a );
|
||||
builder.setTable();
|
||||
break;
|
||||
|
||||
case Lua.OP_LOADNIL: /* A B R(A):= ...:= R(B):= nil */
|
||||
builder.loadNil();
|
||||
for ( ; a<=b; a++ ) {
|
||||
if ( a < b )
|
||||
builder.dup();
|
||||
builder.storeLocal( pc, a );
|
||||
}
|
||||
break;
|
||||
|
||||
case Lua.OP_GETTABLE: /* A B C R(A):= R(B)[RK(C)] */
|
||||
builder.loadLocal( pc, b );
|
||||
loadLocalOrConstant( p, builder, pc, c );
|
||||
builder.getTable();
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_SETTABLE: /* A B C R(A)[RK(B)]:= RK(C) */
|
||||
builder.loadLocal( pc, a );
|
||||
loadLocalOrConstant( p, builder, pc, b );
|
||||
loadLocalOrConstant( p, builder, pc, c );
|
||||
builder.setTable();
|
||||
break;
|
||||
|
||||
case Lua.OP_ADD: /* A B C R(A):= RK(B) + RK(C) */
|
||||
case Lua.OP_SUB: /* A B C R(A):= RK(B) - RK(C) */
|
||||
case Lua.OP_MUL: /* A B C R(A):= RK(B) * RK(C) */
|
||||
case Lua.OP_DIV: /* A B C R(A):= RK(B) / RK(C) */
|
||||
case Lua.OP_MOD: /* A B C R(A):= RK(B) % RK(C) */
|
||||
case Lua.OP_POW: /* A B C R(A):= RK(B) ^ RK(C) */
|
||||
loadLocalOrConstant( p, builder, pc, b );
|
||||
loadLocalOrConstant( p, builder, pc, c );
|
||||
builder.binaryop( o );
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_SELF: /* A B C R(A+1):= R(B): R(A):= R(B)[RK(C)] */
|
||||
builder.loadLocal(pc,b);
|
||||
builder.dup();
|
||||
builder.storeLocal(pc, a+1);
|
||||
loadLocalOrConstant( p, builder, pc, c );
|
||||
builder.getTable();
|
||||
builder.storeLocal(pc, a);
|
||||
break;
|
||||
|
||||
case Lua.OP_CONCAT: /* A B C R(A):= R(B).. ... ..R(C) */
|
||||
builder.newBuffer();
|
||||
while ( b<=c ) {
|
||||
builder.dup();
|
||||
builder.loadLocal(pc, b++);
|
||||
builder.appendBuffer();
|
||||
}
|
||||
builder.tostring();
|
||||
builder.storeLocal(pc, a);
|
||||
break;
|
||||
|
||||
case Lua.OP_LOADBOOL:/* A B C R(A):= (Bool)B: if (C) pc++ */
|
||||
builder.loadBoolean( b!=0 );
|
||||
builder.storeLocal( pc, a );
|
||||
//if ( c != 0 ) branchdest[index+2] = true;
|
||||
break;
|
||||
|
||||
case Lua.OP_JMP: /* sBx pc+=sBx */
|
||||
builder.addBranch(pc, JavaBuilder.BRANCH_GOTO, pc+1+sbx);
|
||||
break;
|
||||
|
||||
case Lua.OP_EQ: /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
|
||||
case Lua.OP_LT: /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
|
||||
case Lua.OP_LE: /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
|
||||
loadLocalOrConstant( p, builder, pc, b );
|
||||
loadLocalOrConstant( p, builder, pc, c );
|
||||
builder.compareop(o);
|
||||
builder.addBranch(pc, (a!=0? JavaBuilder.BRANCH_IFEQ: JavaBuilder.BRANCH_IFNE), pc+2);
|
||||
break;
|
||||
|
||||
case Lua.OP_TEST: /* A C if not (R(A) <=> C) then pc++ */
|
||||
builder.loadLocal( pc, a );
|
||||
builder.toBoolean();
|
||||
builder.addBranch(pc, (c!=0? JavaBuilder.BRANCH_IFEQ: JavaBuilder.BRANCH_IFNE), pc+2);
|
||||
break;
|
||||
|
||||
case Lua.OP_TESTSET: /* A B C if (R(B) <=> C) then R(A):= R(B) else pc++ */
|
||||
builder.loadLocal( pc, b );
|
||||
builder.toBoolean();
|
||||
builder.addBranch(pc, (c!=0? JavaBuilder.BRANCH_IFEQ: JavaBuilder.BRANCH_IFNE), pc+2);
|
||||
builder.loadLocal( pc, b );
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_CALL: /* A B C R(A), ... ,R(A+C-2):= R(A)(R(A+1), ... ,R(A+B-1)) */
|
||||
|
||||
// load function
|
||||
builder.loadLocal(pc, a);
|
||||
|
||||
// load args
|
||||
int narg = b - 1;
|
||||
switch ( narg ) {
|
||||
case 0: case 1: case 2: case 3:
|
||||
for ( int i=1; i<b; i++ )
|
||||
builder.loadLocal(pc, a+i);
|
||||
break;
|
||||
default: // fixed arg count > 3
|
||||
builder.newVarargs( pc, a+1, b-1 );
|
||||
narg = -1;
|
||||
break;
|
||||
case -1: // prev vararg result
|
||||
loadVarargResults( builder, pc, a+1, vresultbase );
|
||||
narg = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
// call or invoke
|
||||
boolean useinvoke = narg<0 || c<1 || c>2;
|
||||
if ( useinvoke )
|
||||
builder.invoke(narg);
|
||||
else
|
||||
builder.call(narg);
|
||||
|
||||
// handle results
|
||||
switch ( c ) {
|
||||
case 1:
|
||||
builder.pop();
|
||||
break;
|
||||
case 2:
|
||||
if ( useinvoke )
|
||||
builder.arg( 1 );
|
||||
builder.storeLocal(pc, a);
|
||||
break;
|
||||
default: // fixed result count - unpack args
|
||||
for ( int i=1; i<c; i++ ) {
|
||||
if ( i+1 < c )
|
||||
builder.dup();
|
||||
builder.arg( i );
|
||||
builder.storeLocal(pc, a+i-1);
|
||||
}
|
||||
break;
|
||||
case 0: // vararg result
|
||||
vresultbase = a;
|
||||
builder.storeVarresult();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case Lua.OP_TAILCALL: /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
|
||||
|
||||
// load function
|
||||
builder.loadLocal(pc, a);
|
||||
|
||||
// load args
|
||||
switch ( b ) {
|
||||
case 1:
|
||||
builder.loadNone();
|
||||
break;
|
||||
case 2:
|
||||
builder.loadLocal(pc, a+1);
|
||||
break;
|
||||
default: // fixed arg count > 1
|
||||
builder.newVarargs( pc, a+1, b-1 );
|
||||
break;
|
||||
case 0: // prev vararg result
|
||||
loadVarargResults( builder, pc, a+1, vresultbase );
|
||||
break;
|
||||
}
|
||||
builder.newTailcallVarargs();
|
||||
builder.areturn();
|
||||
break;
|
||||
|
||||
case Lua.OP_RETURN: /* A B return R(A), ... ,R(A+B-2) (see note) */
|
||||
if ( c == 1 )
|
||||
break;
|
||||
switch ( b ) {
|
||||
case 0: loadVarargResults( builder, pc, a, vresultbase ); break;
|
||||
case 1: builder.loadNone(); break;
|
||||
case 2: builder.loadLocal(pc, a); break;
|
||||
default: builder.newVarargs(pc, a, b-1); break;
|
||||
}
|
||||
builder.areturn();
|
||||
break;
|
||||
|
||||
case Lua.OP_FORPREP: /* A sBx R(A)-=R(A+2): pc+=sBx */
|
||||
builder.loadLocal(pc, a);
|
||||
builder.loadLocal(pc, a+2);
|
||||
builder.binaryop( Lua.OP_SUB );
|
||||
builder.storeLocal(pc, a);
|
||||
builder.addBranch(pc, JavaBuilder.BRANCH_GOTO, pc+1+sbx);
|
||||
break;
|
||||
|
||||
case Lua.OP_FORLOOP: /* A sBx R(A)+=R(A+2): if R(A) <?= R(A+1) then { pc+=sBx: R(A+3)=R(A) }*/
|
||||
builder.loadLocal(pc, a);
|
||||
builder.loadLocal(pc, a+2);
|
||||
builder.binaryop( Lua.OP_ADD );
|
||||
builder.dup();
|
||||
builder.dup();
|
||||
builder.storeLocal(pc, a);
|
||||
builder.storeLocal(pc, a+3);
|
||||
builder.loadLocal(pc, a+1); // limit
|
||||
builder.loadLocal(pc, a+2); // step
|
||||
builder.testForLoop();
|
||||
builder.addBranch(pc, JavaBuilder.BRANCH_IFNE, pc+1+sbx);
|
||||
break;
|
||||
|
||||
case Lua.OP_TFORLOOP: /*
|
||||
* A C R(A+3), ... ,R(A+2+C):= R(A)(R(A+1),
|
||||
* R(A+2)): if R(A+3) ~= nil then R(A+2)=R(A+3)
|
||||
* else pc++
|
||||
*/
|
||||
builder.loadLocal(pc, a);
|
||||
builder.loadLocal(pc, a+1);
|
||||
builder.loadLocal(pc, a+2);
|
||||
builder.invoke(2);
|
||||
for ( int i=0; i<c; i++ ) {
|
||||
if ( i+1 < c )
|
||||
builder.dup();
|
||||
builder.arg( i+1 );
|
||||
builder.storeLocal(pc, a+3+i);
|
||||
}
|
||||
|
||||
builder.loadLocal(pc, a+3);
|
||||
builder.isNil();
|
||||
builder.addBranch(pc, JavaBuilder.BRANCH_IFNE, pc+2);
|
||||
builder.loadLocal(pc, a+3);
|
||||
builder.storeLocal(pc, a+2);
|
||||
break;
|
||||
|
||||
case Lua.OP_SETLIST: /* A B C R(A)[(C-1)*FPF+i]:= R(A+i), 1 <= i <= B */
|
||||
int index0 = (c-1)*Lua.LFIELDS_PER_FLUSH + 1;
|
||||
builder.loadLocal( pc, a );
|
||||
if ( b == 0 ) {
|
||||
int nstack = vresultbase - (a+1);
|
||||
if ( nstack > 0 ) {
|
||||
builder.setlistStack( pc, a+1, index0, nstack );
|
||||
index0 += nstack;
|
||||
}
|
||||
builder.setlistVarargs( index0, vresultbase );
|
||||
} else {
|
||||
builder.setlistStack( pc, a+1, index0, b );
|
||||
builder.pop();
|
||||
}
|
||||
break;
|
||||
|
||||
case Lua.OP_CLOSE: /* A close all variables in the stack up to (>=) R(A)*/
|
||||
break;
|
||||
|
||||
case Lua.OP_CLOSURE: /* A Bx R(A):= closure(KPROTO[Bx], R(A), ... ,R(A+n)) */
|
||||
{
|
||||
Prototype newp = p.p[bx];
|
||||
String protoname = closureName(classname, bx);
|
||||
int nup = newp.nups;
|
||||
builder.closureCreate( protoname );
|
||||
if ( nup > 0 )
|
||||
builder.dup();
|
||||
builder.storeLocal( pc, a );
|
||||
if ( nup > 0 ) {
|
||||
for ( int up=0; up<nup; ++up ) {
|
||||
if ( up+1 < nup )
|
||||
builder.dup();
|
||||
ins = p.code[++pc];
|
||||
b = Lua.GETARG_B(ins);
|
||||
if ( (ins&4) != 0 ) {
|
||||
builder.closureInitUpvalueFromUpvalue( protoname, up, b );
|
||||
} else {
|
||||
builder.closureInitUpvalueFromLocal( protoname, up, pc, b );
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Lua.OP_VARARG: /* A B R(A), R(A+1), ..., R(A+B-1) = vararg */
|
||||
if ( b == 0 ) {
|
||||
builder.loadVarargs();
|
||||
builder.storeVarresult();
|
||||
vresultbase = a;
|
||||
} else {
|
||||
for ( int i=1; i<b; ++a, ++i ) {
|
||||
builder.loadVarargs( i );
|
||||
builder.storeLocal(pc, a);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// let builder process branch instructions
|
||||
builder.onEndOfLuaInstruction( pc );
|
||||
}
|
||||
}
|
||||
|
||||
private void loadVarargResults(JavaBuilder builder, int pc, int a, int vresultbase) {
|
||||
if ( vresultbase <= a ) {
|
||||
builder.loadVarresult();
|
||||
builder.subargs( a+1-vresultbase );
|
||||
} else if ( vresultbase == a ) {
|
||||
builder.loadVarresult();
|
||||
} else {
|
||||
builder.newVarargsVarresult(pc, a, vresultbase-a);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadLocalOrConstant(Prototype p, JavaBuilder builder, int pc, int borc) {
|
||||
if ( borc<=0xff )
|
||||
builder.loadLocal( pc, borc );
|
||||
else
|
||||
builder.loadConstant( p.k[borc&0xff] );
|
||||
}
|
||||
}
|
||||
83
src/jse/org/luaj/vm2/luajc/JavaLoader.java
Normal file
83
src/jse/org/luaj/vm2/luajc/JavaLoader.java
Normal file
@@ -0,0 +1,83 @@
|
||||
package org.luaj.vm2.luajc;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
public class JavaLoader extends ClassLoader {
|
||||
|
||||
private final LuaValue env;
|
||||
|
||||
private Map<String,byte[]> unloaded = new HashMap<String,byte[]>();
|
||||
|
||||
public JavaLoader( LuaValue env ) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public LuaValue load( InputStream is, String classname, String filename ) throws IOException {
|
||||
Prototype p = LuaC.compile(is, classname);
|
||||
return load( p, classname, filename );
|
||||
}
|
||||
|
||||
public LuaValue load( Prototype p, String classname, String filename ) {
|
||||
JavaGen jg = new JavaGen( p, classname, filename );
|
||||
return load( jg );
|
||||
}
|
||||
|
||||
public LuaValue load( JavaGen jg ) {
|
||||
include( jg );
|
||||
return load( jg.classname );
|
||||
}
|
||||
|
||||
public LuaValue load(String classname) {
|
||||
try {
|
||||
Class c = loadClass( classname );
|
||||
LuaValue v = (LuaValue) c.newInstance();
|
||||
v.setfenv(env);
|
||||
return v;
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
throw new IllegalStateException("bad class gen: "+e);
|
||||
}
|
||||
}
|
||||
|
||||
public void include( JavaGen jg ) {
|
||||
unloaded.put( jg.classname, jg.bytecode );
|
||||
for ( int i=0; i<jg.inners.length; i++ )
|
||||
include( jg.inners[i] );
|
||||
}
|
||||
|
||||
public Class findClass(String classname) throws ClassNotFoundException {
|
||||
byte[] bytes = unloaded.get(classname);
|
||||
if ( bytes != null )
|
||||
return defineClass(classname, bytes, 0, bytes.length);
|
||||
return super.findClass(classname);
|
||||
}
|
||||
|
||||
}
|
||||
91
src/jse/org/luaj/vm2/luajc/LuaJC.java
Normal file
91
src/jse/org/luaj/vm2/luajc/LuaJC.java
Normal file
@@ -0,0 +1,91 @@
|
||||
/*******************************************************************************
|
||||
* 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.luajc;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import org.luaj.vm2.LoadState;
|
||||
import org.luaj.vm2.LuaFunction;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.LoadState.LuaCompiler;
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
|
||||
public class LuaJC implements LuaCompiler {
|
||||
|
||||
private static LuaJC instance;
|
||||
private LuaC luac;
|
||||
|
||||
public static LuaJC getInstance() {
|
||||
if ( instance == null )
|
||||
instance = new LuaJC();
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Install the compiler as the main compiler to use.
|
||||
* Will fall back to the LuaC prototype compiler.
|
||||
*/
|
||||
public static final void install() {
|
||||
LoadState.compiler = getInstance();
|
||||
}
|
||||
|
||||
public LuaJC() {
|
||||
luac = new LuaC();
|
||||
}
|
||||
|
||||
public Hashtable compileAll(InputStream script, String classname, String filename) throws IOException {
|
||||
Hashtable h = new Hashtable();
|
||||
Prototype p = luac.compile(script.read(), script, classname);
|
||||
JavaGen gen = new JavaGen(p, classname, filename);
|
||||
insert( h, gen );
|
||||
return h;
|
||||
}
|
||||
|
||||
private void insert(Hashtable h, JavaGen gen) {
|
||||
h.put(gen.classname, gen.bytecode);
|
||||
for ( int i=0; i<gen.inners.length; i++ )
|
||||
insert(h, gen.inners[i]);
|
||||
}
|
||||
|
||||
public Prototype compile(int firstByte, InputStream stream, String name) throws IOException {
|
||||
return luac.compile(firstByte, stream, name);
|
||||
}
|
||||
|
||||
public LuaFunction load(int firstByte, InputStream stream, String name, LuaValue env) throws IOException {
|
||||
return load( compile(firstByte, stream, name), name, env );
|
||||
}
|
||||
|
||||
public LuaFunction load(Prototype p, String filename, LuaValue env) {
|
||||
JavaGen gen = new JavaGen(p, filename, filename);
|
||||
JavaLoader loader = new JavaLoader(env);
|
||||
loader.include(gen);
|
||||
return (LuaFunction) loader.load(p, filename, filename);
|
||||
}
|
||||
|
||||
public LuaValue load(InputStream stream, String name, LuaValue env) throws IOException {
|
||||
return load(stream.read(), stream, name, env);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 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.luajc;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.tools.JavaCompiler;
|
||||
import javax.tools.JavaFileObject;
|
||||
import javax.tools.StandardJavaFileManager;
|
||||
import javax.tools.StandardLocation;
|
||||
import javax.tools.ToolProvider;
|
||||
import javax.tools.JavaCompiler.CompilationTask;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
public class LuaJCompiler {
|
||||
|
||||
public static LuaValue compile( InputStream luaSource, String chunkName, LuaValue env ) throws Exception {
|
||||
String java = compileToJava( luaSource, chunkName );
|
||||
LuaValue chunk = javaCompile( java, chunkName );
|
||||
chunk.setfenv(env);
|
||||
return chunk;
|
||||
}
|
||||
|
||||
public static String compileToJava( InputStream luaSource, String chunkName ) throws Exception {
|
||||
// return AntlrLuaJCompiler.compile( luaSource, chunkName );
|
||||
throw new RuntimeException( "not supported" );
|
||||
}
|
||||
|
||||
|
||||
public static LuaValue javaCompile( String java, String className) throws Exception {
|
||||
final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
|
||||
if (compiler == null) {
|
||||
LuaValue.error("no java compiler");
|
||||
}
|
||||
|
||||
// write the file
|
||||
new File("jit").mkdirs();
|
||||
File source = new File("jit/"+className+JavaFileObject.Kind.SOURCE.extension);
|
||||
PrintStream ps = new PrintStream(new FileOutputStream(source));
|
||||
ps.print(java);
|
||||
ps.close();
|
||||
|
||||
// set up output location
|
||||
Iterable<? extends File> dest = Arrays.asList(new File[] { new File("bin") });
|
||||
StandardJavaFileManager fm = compiler.getStandardFileManager( null, null, null);
|
||||
fm.setLocation(StandardLocation.CLASS_OUTPUT, dest);
|
||||
|
||||
// compile the file
|
||||
Iterable<? extends JavaFileObject> compilationUnits = fm.getJavaFileObjects(source);
|
||||
CompilationTask task = compiler.getTask(null, fm, null, null, null, compilationUnits);
|
||||
boolean success = task.call();
|
||||
|
||||
// instantiate, config and return
|
||||
if (success) {
|
||||
// compile sub-prototypes
|
||||
// if ( p.p != null ) {
|
||||
// for ( int i=0, n=p.p.length; i<n; i++ ) {
|
||||
// if ( ! (p.p[i] instanceof JitPrototype) )
|
||||
// p.p[i] = jitCompile( p.p[i] );
|
||||
// }
|
||||
// }
|
||||
|
||||
// create JitPrototype instance
|
||||
Class clazz = Class.forName(className);
|
||||
Object instance = clazz.newInstance();
|
||||
LuaValue value = (LuaValue) instance;
|
||||
return value;
|
||||
}
|
||||
return LuaValue.error("compile task failed");
|
||||
}
|
||||
|
||||
}
|
||||
387
src/jse/org/luaj/vm2/luajc/Slots.java
Normal file
387
src/jse/org/luaj/vm2/luajc/Slots.java
Normal file
@@ -0,0 +1,387 @@
|
||||
/*******************************************************************************
|
||||
* 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.luajc;
|
||||
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.Prototype;
|
||||
|
||||
/**
|
||||
* Analyze slot usage to find:
|
||||
* - which assignments and references are to upvalue 'u'
|
||||
* - which slots must be initialized with the implied "nil"
|
||||
* - which assignment locations need to create upvalue storage 'U'
|
||||
*
|
||||
* Eventually add:
|
||||
* - subexpression sequences that can remain in primitive types
|
||||
* - assignments of constant values to upvalues that are never modified
|
||||
*/
|
||||
public class Slots {
|
||||
|
||||
private static final byte ASSIGN = 'a'; // assignment to a slot position
|
||||
private static final byte REFER = 'r'; // reference to a slot position
|
||||
private static final byte REFER_ASSIGN = 'b'; // i.e. "both"
|
||||
private static final byte UPVAL_CREATE = 'U'; // where upvalue must be alloced
|
||||
private static final byte UPVAL_USE = 'u'; // continuation of existing upvalue
|
||||
private static final byte UPVAL_USE_ASSIGN = 'c'; // on create closure only
|
||||
private static final byte UPVAL_USE_CREATE = 'C'; // on create closure only, create new upvalue
|
||||
private static final byte INVALID = 'x'; // after call, etc
|
||||
private static final byte INITIAL_NIL = 'n'; // above parameters at initial call
|
||||
|
||||
final int n,m;
|
||||
public final byte[][] slots;
|
||||
public final boolean[] branchdest;
|
||||
|
||||
public boolean isUpvalueCreate(int pc, int slot) {
|
||||
switch (slots[pc+1][slot]) {
|
||||
case UPVAL_CREATE:
|
||||
case UPVAL_USE_CREATE:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isUpvalueAssign(int pc, int slot) {
|
||||
switch (slots[pc+1][slot]) {
|
||||
case UPVAL_CREATE:
|
||||
case UPVAL_USE_CREATE:
|
||||
case UPVAL_USE_ASSIGN:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isUpvalueRefer(int pc, int slot) {
|
||||
switch (slots[pc+1][slot]) {
|
||||
case UPVAL_USE:
|
||||
case UPVAL_USE_ASSIGN:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isInitialValueUsed(int slot) {
|
||||
return slots[0][slot] != INVALID;
|
||||
}
|
||||
|
||||
public Slots(Prototype p) {
|
||||
n = p.code.length;
|
||||
m = p.maxstacksize;
|
||||
slots = new byte[n+1][m];
|
||||
branchdest = new boolean[n+1];
|
||||
markassignments( p );
|
||||
markuninitialized( p );
|
||||
markupvalues( p );
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for ( int i=0; i<slots.length; i++ ) {
|
||||
if ( i > 0 ) sb.append( "\n" );
|
||||
byte[] s = slots[i];
|
||||
for ( int j=s.length; --j>=0; ) {
|
||||
if ( s[j] == 0 )
|
||||
s[j] = ' ';
|
||||
}
|
||||
sb.append( i>0 && branchdest[i]? "D": " " );
|
||||
sb.append( new String(s) );
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void markassignments( Prototype p ) {
|
||||
// mark initial assignments and references
|
||||
int j=0;
|
||||
for ( ; j<p.numparams; j++ )
|
||||
slots[0][j] = ASSIGN;
|
||||
for ( ; j<m; j++ )
|
||||
slots[0][j] = INITIAL_NIL;
|
||||
|
||||
for ( int index=1; index<=n; index++ ) {
|
||||
byte[] s = slots[index];
|
||||
|
||||
int pc = index-1;
|
||||
int ins = p.code[pc];
|
||||
int a = Lua.GETARG_A(ins);
|
||||
int b = Lua.GETARG_B(ins);
|
||||
int bx = Lua.GETARG_Bx(ins);
|
||||
int sbx = Lua.GETARG_sBx(ins);
|
||||
int c = Lua.GETARG_C(ins);
|
||||
|
||||
switch ( Lua.GET_OPCODE(ins) ) {
|
||||
case Lua.OP_GETUPVAL: /* A B R(A):= UpValue[B] */
|
||||
case Lua.OP_SETUPVAL: /* A B UpValue[B]:= R(A) */
|
||||
case Lua.OP_NEWTABLE: /* A B C R(A):= {} (size = B,C) */
|
||||
s[a] = ASSIGN;
|
||||
break;
|
||||
|
||||
case Lua.OP_MOVE:/* A B R(A):= R(B) */
|
||||
case Lua.OP_UNM: /* A B R(A):= -R(B) */
|
||||
case Lua.OP_NOT: /* A B R(A):= not R(B) */
|
||||
case Lua.OP_LEN: /* A B R(A):= length of R(B) */
|
||||
s[a] = ASSIGN;
|
||||
s[b] = REFER;
|
||||
break;
|
||||
|
||||
case Lua.OP_LOADK:/* A Bx R(A):= Kst(Bx) */
|
||||
case Lua.OP_GETGLOBAL: /* A Bx R(A):= Gbl[Kst(Bx)] */
|
||||
case Lua.OP_SETGLOBAL: /* A Bx Gbl[Kst(Bx)]:= R(A) */
|
||||
s[a] = ASSIGN;
|
||||
break;
|
||||
|
||||
case Lua.OP_LOADNIL: /* A B R(A):= ...:= R(B):= nil */
|
||||
while ( a<b )
|
||||
s[a++] = ASSIGN;
|
||||
break;
|
||||
|
||||
case Lua.OP_GETTABLE: /* A B C R(A):= R(B)[RK(C)] */
|
||||
s[a] = ASSIGN;
|
||||
s[b] = REFER;
|
||||
if (c<=0xff) s[c] = REFER;
|
||||
break;
|
||||
|
||||
case Lua.OP_SETTABLE: /* A B C R(A)[RK(B)]:= RK(C) */
|
||||
case Lua.OP_ADD: /* A B C R(A):= RK(B) + RK(C) */
|
||||
case Lua.OP_SUB: /* A B C R(A):= RK(B) - RK(C) */
|
||||
case Lua.OP_MUL: /* A B C R(A):= RK(B) * RK(C) */
|
||||
case Lua.OP_DIV: /* A B C R(A):= RK(B) / RK(C) */
|
||||
case Lua.OP_MOD: /* A B C R(A):= RK(B) % RK(C) */
|
||||
case Lua.OP_POW: /* A B C R(A):= RK(B) ^ RK(C) */
|
||||
s[a] = ASSIGN;
|
||||
if (bx<=0xff) s[bx] = REFER;
|
||||
if (c<=0xff) s[c] = REFER;
|
||||
break;
|
||||
|
||||
case Lua.OP_SELF: /* A B C R(A+1):= R(B): R(A):= R(B)[RK(C)] */
|
||||
s[a] = ASSIGN;
|
||||
s[a+1] = ASSIGN;
|
||||
s[b] = REFER;
|
||||
if (c<=0xff) s[c] = REFER;
|
||||
break;
|
||||
|
||||
case Lua.OP_CONCAT: /* A B C R(A):= R(B).. ... ..R(C) */
|
||||
s[a] = ASSIGN;
|
||||
while ( b<=c )
|
||||
s[b++] = REFER;
|
||||
break;
|
||||
|
||||
case Lua.OP_LOADBOOL:/* A B C R(A):= (Bool)B: if (C) pc++ */
|
||||
s[a] = ASSIGN;
|
||||
if ( c!=0 ) branchdest[index+2] = true;
|
||||
break;
|
||||
|
||||
case Lua.OP_JMP: /* sBx pc+=sBx */
|
||||
branchdest[index+1+sbx] = true;
|
||||
break;
|
||||
|
||||
case Lua.OP_EQ: /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
|
||||
case Lua.OP_LT: /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
|
||||
case Lua.OP_LE: /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
|
||||
if (bx<=0xff) s[bx] = REFER;
|
||||
if (c<=0xff) s[c] = REFER;
|
||||
branchdest[index+2] = true;
|
||||
break;
|
||||
|
||||
case Lua.OP_TEST: /* A C if not (R(A) <=> C) then pc++ */
|
||||
s[a] = REFER;
|
||||
branchdest[index+2] = true;
|
||||
break;
|
||||
|
||||
case Lua.OP_TESTSET: /* A B C if (R(B) <=> C) then R(A):= R(B) else pc++ */
|
||||
s[a] = REFER;
|
||||
s[b] = REFER;
|
||||
branchdest[index+2] = true;
|
||||
break;
|
||||
|
||||
case Lua.OP_CALL: /* A B C R(A), ... ,R(A+C-2):= R(A)(R(A+1), ... ,R(A+B-1)) */
|
||||
while ( a < c-1 || a < b )
|
||||
s[a++] = (byte) (a<c-1 && a<b? REFER_ASSIGN: a<c-1? ASSIGN: REFER);
|
||||
while ( a < m )
|
||||
s[a++] = INVALID;
|
||||
break;
|
||||
|
||||
case Lua.OP_TAILCALL: /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
|
||||
while ( a < b )
|
||||
s[a++] = REFER;
|
||||
while ( a < m )
|
||||
s[a++] = INVALID;
|
||||
break;
|
||||
|
||||
case Lua.OP_RETURN: /* A B return R(A), ... ,R(A+B-2) (see note) */
|
||||
while ( a < b-1 )
|
||||
s[a++] = REFER;
|
||||
break;
|
||||
|
||||
case Lua.OP_FORPREP: /* A sBx R(A)-=R(A+2): pc+=sBx */
|
||||
s[a] = REFER_ASSIGN;
|
||||
s[a+2] = REFER;
|
||||
branchdest[index+1+sbx] = true;
|
||||
break;
|
||||
|
||||
case Lua.OP_FORLOOP: /* A sBx R(A)+=R(A+2): if R(A) <?= R(A+1) then { pc+=sBx: R(A+3)=R(A) }*/
|
||||
s[a] = REFER_ASSIGN;
|
||||
s[a+1] = REFER;
|
||||
s[a+2] = REFER;
|
||||
s[a+3] = ASSIGN;
|
||||
branchdest[index+1+sbx] = true;
|
||||
break;
|
||||
|
||||
case Lua.OP_TFORLOOP: /*
|
||||
* A C R(A+3), ... ,R(A+2+C):= R(A)(R(A+1),
|
||||
* R(A+2)): if R(A+3) ~= nil then R(A+2)=R(A+3)
|
||||
* else pc++
|
||||
*/
|
||||
s[a] = REFER;
|
||||
s[a+1] = REFER;
|
||||
s[a+2] = REFER_ASSIGN;
|
||||
for ( int aa=a+3; aa<a+3+c; aa++ )
|
||||
s[aa] = ASSIGN;
|
||||
for ( int aa=a+3+c; aa<m; aa++ )
|
||||
s[aa] = INVALID;
|
||||
branchdest[index+2] = true;
|
||||
break;
|
||||
|
||||
case Lua.OP_SETLIST: /* A B C R(A)[(C-1)*FPF+i]:= R(A+i), 1 <= i <= B */
|
||||
s[a] = REFER;
|
||||
for ( int aa=1; aa<=b; aa++ )
|
||||
s[aa] = REFER;
|
||||
break;
|
||||
|
||||
case Lua.OP_CLOSE: /* A close all variables in the stack up to (>=) R(A)*/
|
||||
while ( a<m )
|
||||
s[a++] = INVALID;
|
||||
break;
|
||||
|
||||
case Lua.OP_CLOSURE: /* A Bx R(A):= closure(KPROTO[Bx], R(A), ... ,R(A+n)) */
|
||||
{
|
||||
Prototype newp = p.p[bx];
|
||||
for ( int up=0, nup=newp.nups; up<nup; ++up ) {
|
||||
ins = p.code[++pc];
|
||||
b = Lua.GETARG_B(ins);
|
||||
if ( (ins&4) != 0 ) {
|
||||
// up : ups[b]
|
||||
} else {
|
||||
s[b] = UPVAL_USE;
|
||||
}
|
||||
}
|
||||
s[a] = (byte) (s[a] == UPVAL_USE? UPVAL_USE_ASSIGN: ASSIGN);
|
||||
break;
|
||||
}
|
||||
case Lua.OP_VARARG: /* A B R(A), R(A+1), ..., R(A+B-1) = vararg */
|
||||
while ( a<b )
|
||||
s[a++] = ASSIGN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void markuninitialized(Prototype p) {
|
||||
for ( int j=p.numparams; j<m; j++ )
|
||||
if ( ! isreferrededtofirst(j) )
|
||||
slots[0][j] = INVALID;
|
||||
}
|
||||
|
||||
private boolean isreferrededtofirst(int j) {
|
||||
for ( int i=1; i<=n; i++ ) {
|
||||
switch (slots[i][j]) {
|
||||
case REFER_ASSIGN:
|
||||
case REFER:
|
||||
case UPVAL_USE:
|
||||
return true;
|
||||
case ASSIGN:
|
||||
case INVALID:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void markupvalues( Prototype p ) {
|
||||
for ( int pc=0; pc<n; ++pc ) {
|
||||
if ( Lua.GET_OPCODE(p.code[pc]) == Lua.OP_CLOSURE ) {
|
||||
int index = pc+1;
|
||||
byte[] s = slots[index];
|
||||
for ( int j=0; j<m; j++ )
|
||||
if ( s[j] == UPVAL_USE || s[j] == UPVAL_USE_ASSIGN ) {
|
||||
promoteUpvalueBefore( s, index, j );
|
||||
if ( pc<n-1 )
|
||||
promoteUpvalueAfter( s, index+1, j );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void promoteUpvalueBefore(byte[] s, int index, int j) {
|
||||
int begin = prevUndefined(index,j);
|
||||
int assign = firstAssignAfter(begin,index,j);
|
||||
slots[assign][j] = slots[assign][j]==UPVAL_USE_ASSIGN? UPVAL_USE_CREATE: UPVAL_CREATE;
|
||||
while ( index>assign)
|
||||
slots[index--][j] = UPVAL_USE;
|
||||
}
|
||||
|
||||
private void promoteUpvalueAfter(byte[] s, int index, int j) {
|
||||
int end = nextUndefined(index,j);
|
||||
int access = lastAccessBefore(end,index,j);
|
||||
while ( index<=access )
|
||||
slots[index++][j] = UPVAL_USE;
|
||||
}
|
||||
|
||||
private int prevUndefined(int index, int j) {
|
||||
while ( index>0 && slots[index][j] != INVALID )
|
||||
--index;
|
||||
return index;
|
||||
}
|
||||
|
||||
private int firstAssignAfter(int index, int limit, int j) {
|
||||
for ( ; index<limit; ++index ) {
|
||||
switch (slots[index][j]) {
|
||||
case ASSIGN:
|
||||
case REFER_ASSIGN:
|
||||
return index;
|
||||
case UPVAL_CREATE:
|
||||
throw new IllegalStateException("overlapping upvalues");
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
private int nextUndefined(int index, int j) {
|
||||
while ( index+1<slots.length && slots[index+1][j] != INVALID )
|
||||
++index;
|
||||
return index;
|
||||
}
|
||||
|
||||
private int lastAccessBefore(int index, int limit, int j) {
|
||||
for ( ; index>limit; --index ) {
|
||||
switch (slots[index][j]) {
|
||||
case ASSIGN:
|
||||
case REFER_ASSIGN:
|
||||
case REFER:
|
||||
return index;
|
||||
case UPVAL_CREATE:
|
||||
case UPVAL_USE:
|
||||
throw new IllegalStateException("overlapping upvalues");
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 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.luajc.antlr;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.antlr.runtime.ANTLRInputStream;
|
||||
import org.antlr.runtime.CommonTokenStream;
|
||||
import org.antlr.runtime.RecognitionException;
|
||||
import org.luaj.vm2.luajc.JavaCodeGenerator;
|
||||
import org.luaj.vm2.luajc.antlr.LuaLexer;
|
||||
import org.luaj.vm2.luajc.antlr.LuaParser;
|
||||
import org.luaj.vm2.luajc.lst.LSChunk;
|
||||
|
||||
/**
|
||||
* Implementation of lua-to-java compiler using antlr
|
||||
*/
|
||||
public class AntlrLuaJCompiler {
|
||||
|
||||
private final String chunkname;
|
||||
|
||||
public AntlrLuaJCompiler(String chunkname) {
|
||||
this.chunkname = chunkname;
|
||||
}
|
||||
|
||||
public static String compile(InputStream script, String chunkname) throws RecognitionException, IOException {
|
||||
return new AntlrLuaJCompiler(chunkname).docompile( script );
|
||||
}
|
||||
|
||||
private String docompile(InputStream script) throws RecognitionException, IOException {
|
||||
|
||||
ANTLRInputStream input = new ANTLRInputStream(script);
|
||||
LuaLexer lexer = new LuaLexer(input);
|
||||
CommonTokenStream tokens = new CommonTokenStream(lexer);
|
||||
LuaParser parser = new LuaParser(tokens);
|
||||
LSChunk chunk = parser.chunk(chunkname);
|
||||
return new JavaCodeGenerator().toJava( chunk );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,301 +0,0 @@
|
||||
/*
|
||||
* Lua 5.1 grammar producing typed parse tree.
|
||||
*
|
||||
* Adapted from the grammar produced by Nicolai Mainiero, May 2007
|
||||
*
|
||||
* see http://www.antlr.org/grammar/list
|
||||
*/
|
||||
|
||||
grammar Lua;
|
||||
|
||||
options {
|
||||
backtrack=true;
|
||||
}
|
||||
|
||||
@header {
|
||||
package org.luaj.vm2.luajc.antlr;
|
||||
import org.luaj.vm2.luajc.lst.*;
|
||||
}
|
||||
@lexer::header {
|
||||
package org.luaj.vm2.luajc.antlr;
|
||||
}
|
||||
@members {
|
||||
LSChunk CHK = null;
|
||||
}
|
||||
|
||||
chunk [String chunkname] returns [LSChunk c]
|
||||
@init { CHK = new LSChunk(chunkname); }
|
||||
: funcblock[CHK.function] {$c=CHK;}
|
||||
;
|
||||
|
||||
funcblock [LSFunction f]
|
||||
scope { LSFunction func; }
|
||||
@init { $funcblock::func = $f; }
|
||||
: {CHK.pushScope("body");} block {$f.setStatements($block.stats); CHK.popScope("body"); }
|
||||
;
|
||||
|
||||
block returns [List<LSStatement> stats]
|
||||
@init { $stats = new ArrayList<LSStatement>(); }
|
||||
: (stat {$stats.add($stat.s);} (';')?)*
|
||||
(laststat {$stats.add($laststat.s);} (';')?)?
|
||||
;
|
||||
|
||||
stat returns [LSStatement s]
|
||||
@init { Name name=null; List<Name> names=null; }
|
||||
: varlist1 '=' explist1 { $s=LSStatement.varAssignStatement($varlist1.vars,$explist1.exprs, CHK.peekScope(), $funcblock::func); }
|
||||
| functioncall { $s=LSStatement.functionCallStatement($functioncall.v); }
|
||||
| 'do' {CHK.pushScope("do");} block {CHK.popScope("do");} 'end'
|
||||
{ $s=LSStatement.doBlockStatement($block.stats); }
|
||||
| 'while' exp 'do' {CHK.pushScope("while");} block {CHK.popScope("while");} 'end'
|
||||
{ $s=LSStatement.whileLoopStatement($exp.e,$block.stats); }
|
||||
| 'repeat' {CHK.pushScope("repeat");} block {CHK.popScope("repeat");} 'until' exp
|
||||
{ $s=LSStatement.repeatUntilStatement($block.stats,$exp.e); }
|
||||
| ifstat { $s=$ifstat.s; }
|
||||
| 'for' {CHK.pushScope("fori");} NAME {name=CHK.declare($NAME.text);} '=' e1=exp ',' e2=exp (',' e3=exp)? 'do' {CHK.pushScope("foriblock");} block {CHK.popScope("foriblock");} 'end'
|
||||
{ $s=LSStatement.forLoopStatement(name,$e1.e,$e2.e,$e3.e,$block.stats,CHK.peekScope()); CHK.popScope("fori"); }
|
||||
| 'for' {CHK.pushScope("for");} namelist {names=CHK.declare($namelist.names);} 'in' explist1 'do' {CHK.pushScope("forblock");} block {CHK.popScope("forblock");}'end'
|
||||
{ $s=LSStatement.forListStatement(names,$explist1.exprs,$block.stats,CHK.peekScope(), $funcblock::func); CHK.popScope("for");}
|
||||
| 'function' funcname funcbody { $s=LSStatement.varFunctionStatement($funcname.v,$funcbody.f); }
|
||||
| 'local' 'function' NAME {name=CHK.declare($NAME.text);} funcbody
|
||||
{ $s=LSStatement.localFunctionStatement(name,$funcbody.f); }
|
||||
| 'local' namelist ('=' explist1)? { $s=LSStatement.localAssignStatement(CHK.declare($namelist.names),$explist1.exprs,CHK.peekScope(), $funcblock::func); }
|
||||
;
|
||||
|
||||
ifstat returns [LSStatement s]
|
||||
scope { LSIfStatement current; }
|
||||
: 'if' e1=exp 'then' {CHK.pushScope("if");} b1=block {$ifstat::current=new LSIfStatement($e1.e,$b1.stats); CHK.popScope("if");}
|
||||
('elseif' e2=exp 'then' {CHK.pushScope("elseif");} b2=block {$ifstat::current.addElseif($e2.e,$b2.stats); CHK.popScope("elseif");})*
|
||||
('else' {CHK.pushScope("else");} b3=block {$ifstat::current.addElse($b3.stats); CHK.popScope("else");})?
|
||||
'end'
|
||||
{ $s=$ifstat::current; }
|
||||
;
|
||||
|
||||
laststat returns [LSStatement s]
|
||||
: 'return' (e=explist1)? {$s=LSStatement.returnStatement($funcblock::func,$e.exprs);}
|
||||
| 'break' {$s=LSStatement.breakStatement();}
|
||||
;
|
||||
|
||||
funcname returns [LSVariable v]
|
||||
: n=NAME {$v = LSVariable.nameVariable(CHK.reference($n.text,$funcblock::func));}
|
||||
('.' n2=NAME {$v = $v.fieldVariable($n2.text);})*
|
||||
(':' n3=NAME {$v = $v.methodVariable($n3.text);})?
|
||||
;
|
||||
|
||||
varlist1 returns [List<LSVariable> vars]
|
||||
@init { $vars = new ArrayList<LSVariable>(); }
|
||||
: v1=var {$vars.add($v1.v);}
|
||||
(',' v2=var {$vars.add($v2.v);})*
|
||||
;
|
||||
|
||||
namelist returns [List<String> names]
|
||||
: n=NAME {$names=new ArrayList<String>(); $names.add($n.text);}
|
||||
(',' n2=NAME {$names.add($n2.text);})*
|
||||
;
|
||||
|
||||
explist1 returns [List<LSExpression> exprs]
|
||||
@init { $exprs = new ArrayList<LSExpression>(); }
|
||||
: (e1=exp ',' {$exprs.add($e1.e);})*
|
||||
e2=exp {$exprs.add($e2.e);}
|
||||
;
|
||||
|
||||
exp returns [LSExpression e]
|
||||
: ('nil' { $e=LSExpression.ENIL; }
|
||||
| 'false' { $e=LSExpression.EFALSE; }
|
||||
| 'true' { $e=LSExpression.ETRUE; }
|
||||
| number { $e=LSExpression.numberExpression($number.text); }
|
||||
| string { $e=$string.e; }
|
||||
| '...' { $e=LSExpression.varargsRef(); $funcblock::func.setUsesVarargs(); }
|
||||
| function { $e=LSExpression.functionExpression($function.f); }
|
||||
| prefixexp { $e=$prefixexp.v; }
|
||||
| tableconstructor { $e=$tableconstructor.e;}
|
||||
| unop e1=exp { $e=LSExpression.unopExpression($unop.op,$e1.e,CHK.peekScope());}
|
||||
) (binop e2=exp { $e=LSExpression.binopExpression($e,$binop.op,$e2.e,CHK.peekScope());})*
|
||||
;
|
||||
|
||||
var returns [LSVariable v]
|
||||
scope { LSVariable current; }
|
||||
: (n=NAME {$var::current=LSVariable.nameVariable(CHK.reference($n.text,$funcblock::func));}
|
||||
| '(' exp ')' {$var::current=LSVariable.parenthesesVariable($exp.e);} varSuffix)
|
||||
varSuffix*
|
||||
{$v=$var::current;}
|
||||
;
|
||||
|
||||
varSuffix
|
||||
: (n=nameAndArgs[$var::current] {$var::current=$n.v;})*
|
||||
('[' e=exp ']' {$var::current=$var::current.indexVariable($e.e);}
|
||||
| '.' n2=NAME {$var::current=$var::current.fieldVariable($n2.text);}
|
||||
)
|
||||
;
|
||||
|
||||
prefixexp returns [LSVariable v]
|
||||
scope { LSVariable current; }
|
||||
: e=varOrExp {$prefixexp::current=$e.v;}
|
||||
(n=nameAndArgs[$prefixexp::current] {$prefixexp::current=$n.v;})*
|
||||
{$v=$prefixexp::current;}
|
||||
;
|
||||
|
||||
functioncall returns [LSVariable v]
|
||||
scope { LSVariable current; }
|
||||
: e=varOrExp {$functioncall::current=$e.v;}
|
||||
(n=nameAndArgs[$functioncall::current] {$functioncall::current=$n.v;})+
|
||||
{$v=$functioncall::current;}
|
||||
;
|
||||
|
||||
varOrExp returns [LSVariable v]
|
||||
: var {$v=$var.v;}
|
||||
| '(' exp ')' {$v=LSVariable.parenthesesVariable($exp.e);}
|
||||
;
|
||||
|
||||
nameAndArgs [LSVariable vin] returns [LSVariable v]
|
||||
@init { String method=null; }
|
||||
: (':' n=NAME {method=$n.text;})?
|
||||
a=args {$v=((method==null)?
|
||||
$vin.callFuncVariable($a.exprs):
|
||||
$vin.callMethVariable(method,$a.exprs));}
|
||||
;
|
||||
|
||||
args returns [List<LSExpression> exprs]
|
||||
@init { $exprs = new ArrayList<LSExpression>(); }
|
||||
: '(' (e=explist1 {$exprs=$e.exprs;})? ')'
|
||||
| t=tableconstructor {$exprs.add($t.e);}
|
||||
| s=string {$exprs.add($s.e);}
|
||||
;
|
||||
|
||||
function returns [LSFunction f]
|
||||
: 'function' b=funcbody {$f = $b.f;}
|
||||
;
|
||||
|
||||
funcbody returns [LSFunction f]
|
||||
@init {
|
||||
$f = new LSFunction();
|
||||
$funcblock::func.functions.add($f);
|
||||
}
|
||||
: {CHK.pushScope("func",true);} '(' (parlist1 [f])? ')' funcblock[f] 'end' {CHK.popScope("func");}
|
||||
;
|
||||
|
||||
parlist1 [LSFunction f]
|
||||
: namelist {f.setParameterNames(CHK.declare($namelist.names));} (',' '...' {f.isvararg=true;})?
|
||||
| '...' {f.isvararg=true;}
|
||||
;
|
||||
|
||||
tableconstructor returns [LSExpression e]
|
||||
@init { List<LSField> fields = new ArrayList<LSField>(); }
|
||||
: '{' (fieldlist[fields])? '}' {$e=LSExpression.tableConstructorExpression(fields);}
|
||||
;
|
||||
|
||||
fieldlist [List<LSField> fields]
|
||||
: field [fields] (fieldsep field [fields])* (fieldsep)?
|
||||
;
|
||||
|
||||
field [List<LSField> fields]
|
||||
: '[' k=exp ']' '=' e=exp {$fields.add(LSField.keyValueField($k.e,$e.e));}
|
||||
| n=NAME '=' e=exp {$fields.add(LSField.nameValueField($n.text,$e.e));}
|
||||
| e=exp {$fields.add(LSField.valueField($e.e));}
|
||||
;
|
||||
|
||||
fieldsep
|
||||
: ','
|
||||
| ';'
|
||||
;
|
||||
|
||||
binop returns [BinOp op]
|
||||
: '+' {$op=BinOp.ADD;}
|
||||
| '-' {$op=BinOp.SUB;}
|
||||
| '*' {$op=BinOp.MUL;}
|
||||
| '/' {$op=BinOp.DIV;}
|
||||
| '^' {$op=BinOp.POW;}
|
||||
| '%' {$op=BinOp.MOD;}
|
||||
| '..' {$op=BinOp.CONCAT;}
|
||||
| '<' {$op=BinOp.LT;}
|
||||
| '<=' {$op=BinOp.LTEQ;}
|
||||
| '>' {$op=BinOp.GT;}
|
||||
| '>=' {$op=BinOp.GTEQ;}
|
||||
| '==' {$op=BinOp.EQ;}
|
||||
| '~=' {$op=BinOp.NEQ;}
|
||||
| 'and' {$op=BinOp.AND; $funcblock::func.hasandlogic=true;}
|
||||
| 'or' {$op=BinOp.OR; $funcblock::func.hasorlogic=true;}
|
||||
;
|
||||
|
||||
unop returns [UnOp op]
|
||||
: '-' {$op=UnOp.NEG;}
|
||||
| 'not' {$op=UnOp.NOT;}
|
||||
| '#' {$op=UnOp.LEN;}
|
||||
;
|
||||
|
||||
number
|
||||
: ('-')? INT
|
||||
| ('-')? FLOAT1
|
||||
| ('-')? FLOAT2
|
||||
| ('-')? FLOAT3
|
||||
| ('-')? EXP
|
||||
| HEX
|
||||
;
|
||||
|
||||
string returns [LSExpression e]
|
||||
: NORMALSTRING {$e=LSExpression.normalStringExpression($NORMALSTRING.text);}
|
||||
| CHARSTRING {$e=LSExpression.charStringExpression($CHARSTRING.text);}
|
||||
| LONGSTRING {$e=LSExpression.longStringExpression($LONGSTRING.text);}
|
||||
;
|
||||
|
||||
|
||||
// LEXER
|
||||
|
||||
|
||||
NAME :('a'..'z'|'A'..'Z'|'_')(options{greedy=true;}: 'a'..'z'|'A'..'Z'|'_'|'0'..'9')*
|
||||
;
|
||||
|
||||
INT : ('0'..'9')+;
|
||||
|
||||
FLOAT1 :'.' INT ;
|
||||
|
||||
FLOAT2 :INT '.' ;
|
||||
|
||||
FLOAT3 :INT '.' INT ;
|
||||
|
||||
EXP : (INT | FLOAT1 | FLOAT2 | FLOAT3) ('E'|'e') ('-'|'+')? INT;
|
||||
|
||||
HEX :'0' ('x' | 'X') ('0'..'9'| 'a'..'f' | 'A'..'F')+ ;
|
||||
|
||||
|
||||
|
||||
NORMALSTRING
|
||||
: '"' ( EscapeSequence | ~('\\'|'"') )* '"'
|
||||
;
|
||||
|
||||
CHARSTRING
|
||||
: '\'' ( EscapeSequence | ~('\\'|'\'') )* '\''
|
||||
;
|
||||
|
||||
LONGSTRING
|
||||
: '['('=')*'[' ( EscapeSequence | ~('\\'|']') )* ']'('=')*']'
|
||||
;
|
||||
|
||||
fragment
|
||||
EscapeSequence
|
||||
: '\\' ('a'|'b'|'f'|'n'|'r'|'t'|'v'|'\"'|'\''|'\\'|'\n')
|
||||
| DecimalEscape
|
||||
;
|
||||
|
||||
fragment
|
||||
DecimalEscape
|
||||
: '\\' ('0'..'9') (('0'..'9') ('0'..'9')?)?
|
||||
;
|
||||
|
||||
|
||||
COMMENT
|
||||
: '--[[' ( options {greedy=false;} : . )* '--]]' {skip();}
|
||||
| '--[=[' ( options {greedy=false;} : . )* '--]==]' {skip();}
|
||||
| '--[==[' ( options {greedy=false;} : . )* '--]==]' {skip();}
|
||||
| '--[===[' ( options {greedy=false;} : . )* '--]===]' {skip();}
|
||||
;
|
||||
|
||||
LINE_COMMENT
|
||||
: '--' ~('\n'|'\r')* '\r'? '\n' {skip();}
|
||||
;
|
||||
|
||||
|
||||
WS : (' '|'\t'|'\u000C') {skip();}
|
||||
;
|
||||
|
||||
NEWLINE : ('\r')? '\n' {skip();}
|
||||
;
|
||||
@@ -1,110 +0,0 @@
|
||||
T__66=66
|
||||
T__64=64
|
||||
T__29=29
|
||||
T__65=65
|
||||
T__28=28
|
||||
T__62=62
|
||||
T__27=27
|
||||
T__63=63
|
||||
T__26=26
|
||||
T__25=25
|
||||
T__24=24
|
||||
T__23=23
|
||||
T__22=22
|
||||
T__21=21
|
||||
T__20=20
|
||||
T__61=61
|
||||
T__60=60
|
||||
FLOAT3=8
|
||||
FLOAT2=7
|
||||
FLOAT1=6
|
||||
T__55=55
|
||||
T__56=56
|
||||
T__57=57
|
||||
NAME=4
|
||||
T__58=58
|
||||
T__51=51
|
||||
T__52=52
|
||||
T__53=53
|
||||
T__54=54
|
||||
EXP=9
|
||||
HEX=10
|
||||
T__59=59
|
||||
DecimalEscape=15
|
||||
COMMENT=16
|
||||
T__50=50
|
||||
T__42=42
|
||||
T__43=43
|
||||
T__40=40
|
||||
T__41=41
|
||||
T__46=46
|
||||
T__47=47
|
||||
T__44=44
|
||||
T__45=45
|
||||
LINE_COMMENT=17
|
||||
T__48=48
|
||||
T__49=49
|
||||
CHARSTRING=12
|
||||
INT=5
|
||||
LONGSTRING=13
|
||||
T__30=30
|
||||
NORMALSTRING=11
|
||||
T__31=31
|
||||
T__32=32
|
||||
WS=18
|
||||
T__33=33
|
||||
T__34=34
|
||||
NEWLINE=19
|
||||
T__35=35
|
||||
T__36=36
|
||||
T__37=37
|
||||
T__38=38
|
||||
T__39=39
|
||||
EscapeSequence=14
|
||||
'..'=56
|
||||
'end'=23
|
||||
'#'=66
|
||||
'>='=60
|
||||
'=='=61
|
||||
'/'=53
|
||||
'then'=33
|
||||
'>'=59
|
||||
'repeat'=25
|
||||
';'=20
|
||||
'='=21
|
||||
'return'=36
|
||||
'for'=27
|
||||
'+'=50
|
||||
')'=45
|
||||
'function'=30
|
||||
'.'=38
|
||||
'^'=54
|
||||
'%'=55
|
||||
'do'=22
|
||||
'elseif'=34
|
||||
'true'=42
|
||||
'}'=49
|
||||
'else'=35
|
||||
'and'=63
|
||||
'break'=37
|
||||
'{'=48
|
||||
'...'=43
|
||||
'~='=62
|
||||
'nil'=40
|
||||
'until'=26
|
||||
'<='=58
|
||||
'false'=41
|
||||
'<'=57
|
||||
'if'=32
|
||||
'not'=65
|
||||
':'=39
|
||||
'('=44
|
||||
'or'=64
|
||||
'*'=52
|
||||
'-'=51
|
||||
'['=46
|
||||
'while'=24
|
||||
'local'=31
|
||||
','=28
|
||||
'in'=29
|
||||
']'=47
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,63 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 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.luajc.lst;
|
||||
|
||||
|
||||
public class BinOp {
|
||||
// unary precedence is between POW and MUL
|
||||
public static final int UNARY_PRECEDENCE = 7;
|
||||
|
||||
public enum Type {
|
||||
pow,mul,div,mod,add,sub,concat,lt,lteq,gt,gteq,eq,neq,and,or,
|
||||
}
|
||||
|
||||
public static final BinOp POW = new BinOp(Type.pow, 8, true, "^");
|
||||
public static final BinOp MUL = new BinOp(Type.mul, 6, false, "*");
|
||||
public static final BinOp DIV = new BinOp(Type.div, 6, false, "/");
|
||||
public static final BinOp MOD = new BinOp(Type.mod, 6, false, "%");
|
||||
public static final BinOp ADD = new BinOp(Type.add, 5, false, "+");
|
||||
public static final BinOp SUB = new BinOp(Type.sub, 5, false, "-");
|
||||
public static final BinOp CONCAT = new BinOp(Type.concat, 4, true, "..");
|
||||
public static final BinOp LT = new BinOp(Type.lt, 3, false, "<");
|
||||
public static final BinOp LTEQ = new BinOp(Type.lteq, 3, false, "<=");
|
||||
public static final BinOp GT = new BinOp(Type.gt, 3, false, ">");
|
||||
public static final BinOp GTEQ = new BinOp(Type.gteq, 3, false, ">=");
|
||||
public static final BinOp EQ = new BinOp(Type.eq, 3, false, "==");
|
||||
public static final BinOp NEQ = new BinOp(Type.neq, 3, false, "~=");
|
||||
public static final BinOp AND = new BinOp(Type.and, 2, true, "and");
|
||||
public static final BinOp OR = new BinOp(Type.or, 1, true, "or");
|
||||
|
||||
public final Type type;
|
||||
public final int precedence;
|
||||
public final boolean isrightassoc;
|
||||
public final String luaop;
|
||||
|
||||
private BinOp(Type type, int precedence, boolean isrightassoc, String luaop) {
|
||||
super();
|
||||
this.type = type;
|
||||
this.precedence = precedence;
|
||||
this.isrightassoc = isrightassoc;
|
||||
this.luaop = luaop;
|
||||
}
|
||||
|
||||
public String toString() { return luaop; }
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 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.luajc.lst;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/* A Lua Source Chunk */
|
||||
public class LSChunk {
|
||||
public static final boolean SCOPES = System.getProperty("SCOPES")!=null;
|
||||
|
||||
public final String chunkname;
|
||||
public final LSFunction function;
|
||||
public Scope scope;
|
||||
|
||||
public LSChunk( String chunkname ) {
|
||||
this.chunkname = chunkname;
|
||||
this.function = new LSFunction( true );
|
||||
this.scope = null;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "@"+chunkname+": "+function;
|
||||
}
|
||||
|
||||
/** push a block scope onto the name scope stack */
|
||||
public void pushScope(String name) {
|
||||
scope = new Scope(scope, false);
|
||||
if(SCOPES)System.out.println(space(scope)+"push "+name+" scope="+scope);
|
||||
|
||||
}
|
||||
|
||||
/** push a function scope onto the name scope stack */
|
||||
public void pushScope(String name,boolean isFunction) {
|
||||
scope = new Scope(scope, isFunction);
|
||||
if(SCOPES)System.out.println(space(scope)+"push "+name+" scope="+scope);
|
||||
}
|
||||
|
||||
/** pop a scope from the scope stack */
|
||||
public Scope popScope(String name) {
|
||||
Scope s = scope;
|
||||
scope = scope.parent;
|
||||
if(SCOPES)System.out.println(space(s)+"pop "+name+" scope="+scope);
|
||||
return s;
|
||||
}
|
||||
|
||||
/** return the current scope */
|
||||
public Scope peekScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
/** Declare a single name in the current scope, and return the Name element for it */
|
||||
public Name declare(String name) {
|
||||
Name n = scope.declare( name );
|
||||
if(SCOPES)System.out.println(space(scope)+" declared "+n+" scope="+scope);
|
||||
return n;
|
||||
}
|
||||
|
||||
/** Declare a list of names in the current scope, and return List of Name for them */
|
||||
public List<Name> declare(List<String> names) {
|
||||
List<Name> results = new ArrayList<Name>(names.size());
|
||||
for ( String s : names )
|
||||
results.add( declare(s) );
|
||||
return results;
|
||||
}
|
||||
|
||||
/** Reference a name, and find either the local scope within the function, the upvalue, or a global name
|
||||
* @param func */
|
||||
public Name reference(String name, LSFunction func) {
|
||||
Name n = scope.reference(name);
|
||||
if ("arg".equals(name) && n.isGlobal() && func.isvararg && !scope.isMainChunkScope()) {
|
||||
n = scope.declare(name);
|
||||
func.setHasArg();
|
||||
}
|
||||
if(SCOPES)System.out.println(space(scope)+" reference "+n+" scope="+scope);
|
||||
return n;
|
||||
}
|
||||
|
||||
/** Print out indentation for a scope */
|
||||
private static final String ws = " ";
|
||||
private String space(Scope i) {
|
||||
return ws.substring(0,i.level*2);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,267 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 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.luajc.lst;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.List;
|
||||
|
||||
public class LSExpression {
|
||||
public enum Type {
|
||||
unop,
|
||||
binop,
|
||||
functionExpr,
|
||||
tableConstructor,
|
||||
nilConstant,
|
||||
trueConstant,
|
||||
falseConstant,
|
||||
varargsRef,
|
||||
numberConstant,
|
||||
stringConstant,
|
||||
|
||||
// variable types
|
||||
nameVariable,
|
||||
fieldVariable,
|
||||
methodVariable,
|
||||
parenthesesVariable,
|
||||
indexVariable,
|
||||
callFunctionVariable,
|
||||
callMethodVariable,
|
||||
}
|
||||
|
||||
public static final LSExpression ENIL = new LSExpression(Type.nilConstant); // nil
|
||||
public static final LSExpression EFALSE = new LSExpression(Type.falseConstant); // false
|
||||
public static final LSExpression ETRUE = new LSExpression(Type.trueConstant); // true
|
||||
|
||||
public final Type type;
|
||||
|
||||
LSExpression(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static LSExpression functionExpression(LSFunction function) {
|
||||
return new FunctionExpr(function);
|
||||
}
|
||||
|
||||
public static LSExpression unopExpression(UnOp unop, LSExpression rhs, Scope scope) {
|
||||
if ( rhs instanceof BinopExpr ) {
|
||||
BinopExpr b = (BinopExpr) rhs;
|
||||
if ( BinOp.UNARY_PRECEDENCE > b.op.precedence )
|
||||
return binopExpression( unopExpression( unop, b.lhs, scope ), b.op, b.rhs, scope );
|
||||
}
|
||||
return new UnopExpr( unop, rhs );
|
||||
}
|
||||
|
||||
public static LSExpression binopExpression(LSExpression lhs, BinOp binop, LSExpression rhs, Scope scope) {
|
||||
if ( lhs instanceof UnopExpr ) {
|
||||
UnopExpr u = (UnopExpr) lhs;
|
||||
if ( binop.precedence > BinOp.UNARY_PRECEDENCE )
|
||||
return unopExpression( u.op, binopExpression( u.rhs, binop, rhs, scope ), scope );
|
||||
}
|
||||
// TODO: cumulate string concatenations together
|
||||
// TODO: constant folding
|
||||
if ( lhs instanceof BinopExpr ) {
|
||||
BinopExpr b = (BinopExpr) lhs;
|
||||
if ( (binop.precedence > b.op.precedence) ||
|
||||
((binop.precedence == b.op.precedence) && binop.isrightassoc) )
|
||||
return binopExpression( b.lhs, b.op, binopExpression( b.rhs, binop, rhs, scope ), scope );
|
||||
}
|
||||
if ( rhs instanceof BinopExpr ) {
|
||||
BinopExpr b = (BinopExpr) rhs;
|
||||
if ( (binop.precedence > b.op.precedence) ||
|
||||
((binop.precedence == b.op.precedence) && ! binop.isrightassoc) )
|
||||
return binopExpression( binopExpression( lhs, binop, b.lhs, scope ), b.op, b.rhs, scope );
|
||||
}
|
||||
return new BinopExpr( lhs, binop, rhs, scope );
|
||||
}
|
||||
|
||||
public static LSExpression numberExpression(String number) {
|
||||
return new NumberConstant(number);
|
||||
}
|
||||
|
||||
public static LSExpression tableConstructorExpression(List<LSField> fields) {
|
||||
return new TableConstructor( fields );
|
||||
}
|
||||
|
||||
public static LSExpression normalStringExpression(String luaSourceString) {
|
||||
return new StringConstant(luaSourceString.substring(1,luaSourceString.length()-1));
|
||||
}
|
||||
|
||||
public static LSExpression charStringExpression(String luaSourceString) {
|
||||
return new StringConstant(luaSourceString.substring(1,luaSourceString.length()-1));
|
||||
}
|
||||
|
||||
public static LSExpression longStringExpression(String luaSourceString) {
|
||||
luaSourceString = luaSourceString.substring(1,luaSourceString.length()-1);
|
||||
luaSourceString = luaSourceString.substring(luaSourceString.indexOf('[',1)+1, luaSourceString.lastIndexOf(']'));
|
||||
return new StringConstant(luaSourceString);
|
||||
}
|
||||
|
||||
public static LSExpression varargsRef() {
|
||||
return new VarargsRef();
|
||||
}
|
||||
|
||||
/** varargs such as "..." */
|
||||
public static class VarargsRef extends LSExpression {
|
||||
public int numReturns = -1;
|
||||
public VarargsRef() {
|
||||
super( Type.varargsRef );
|
||||
}
|
||||
public void setNumReturns(int i) {
|
||||
this.numReturns = i;
|
||||
}
|
||||
public int getNumReturns() {
|
||||
return numReturns;
|
||||
}
|
||||
public String toString() { return "..."; }
|
||||
}
|
||||
|
||||
/** prefix expression such as "(foo)(bar)" ? */
|
||||
public static class FunctionExpr extends LSExpression {
|
||||
public final LSFunction function;
|
||||
public FunctionExpr( LSFunction function) {
|
||||
super( Type.functionExpr );
|
||||
this.function = function;
|
||||
}
|
||||
public String toString() { return function.toString(); }
|
||||
}
|
||||
|
||||
/** unary operator such as "not foo" */
|
||||
public static class UnopExpr extends LSExpression {
|
||||
public final UnOp op;
|
||||
public final LSExpression rhs;
|
||||
public UnopExpr( UnOp op, LSExpression rhs ) {
|
||||
super( Type.unop );
|
||||
this.op = op;
|
||||
this.rhs = rhs;
|
||||
}
|
||||
public String toString() { return op.luaop+rhs; }
|
||||
}
|
||||
|
||||
/** binary operator such as "a + b" */
|
||||
public static class BinopExpr extends LSExpression {
|
||||
public final LSExpression lhs;
|
||||
public final BinOp op;
|
||||
public final LSExpression rhs;
|
||||
public final Scope scope;
|
||||
public BinopExpr( LSExpression lhs, BinOp op, LSExpression rhs, Scope scope ) {
|
||||
super( Type.binop );
|
||||
this.lhs = lhs;
|
||||
this.op = op;
|
||||
this.rhs = rhs;
|
||||
this.scope = scope;
|
||||
}
|
||||
public String toString() { return lhs+op.luaop+rhs; }
|
||||
}
|
||||
|
||||
/** table constructor such as "{ 'foo', [0]='bar' }" */
|
||||
public static class TableConstructor extends LSExpression {
|
||||
public final List<LSField> fields;
|
||||
public TableConstructor( List<LSField> fields ) {
|
||||
super( Type.tableConstructor );
|
||||
this.fields = fields;
|
||||
int n = fields.size();
|
||||
for ( int i=0; i<n-1; i++ )
|
||||
fields.get(i).setNumReturns(1);
|
||||
if ( n>0 )
|
||||
fields.get(n-1).setNumReturns(-1);
|
||||
}
|
||||
public String toString() { return "{"+fields+"}"; }
|
||||
}
|
||||
|
||||
/** number constants such as '123', "4.56", "0x11fe */
|
||||
public static class NumberConstant extends LSExpression {
|
||||
public final Number value;
|
||||
public NumberConstant( String number ) {
|
||||
super( Type.numberConstant );
|
||||
number = number.toLowerCase();
|
||||
if ( number.startsWith("0x") ) {
|
||||
Long l = Long.parseLong(number.substring(2), 16);
|
||||
value = (l.intValue()==l.longValue()? (Number) Integer.valueOf(l.intValue()): (Number) l);
|
||||
} else {
|
||||
Double d = Double.parseDouble(number);
|
||||
value = (d.doubleValue()==(double)d.intValue()? (Number) Integer.valueOf(d.intValue()): (Number) d);
|
||||
}
|
||||
}
|
||||
public String toString() { return value.toString(); }
|
||||
}
|
||||
|
||||
/** string constants such as 'abc', "def", [[ghi]], and [==[pqr]==] */
|
||||
public static class StringConstant extends LSExpression {
|
||||
public final byte[] bytes;
|
||||
public StringConstant( String luaSourceChars ) {
|
||||
super( Type.stringConstant );
|
||||
this.bytes = unquoteLua( luaSourceChars );
|
||||
}
|
||||
public String toString() { return "\""+new String(bytes)+"\""; }
|
||||
}
|
||||
|
||||
/** Unquote lua quoted sequences, and convert to the bytes represented by the source string. */
|
||||
public static byte[] unquoteLua( String luaSourceChars ) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
char[] c = luaSourceChars.toCharArray();
|
||||
int n = c.length;
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
if ( c[i] == '\\' && i<n ) {
|
||||
switch ( c[++i] ) {
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
int d=(int) (c[i++]-'0');
|
||||
for ( int j=0; i<n && j<2 && c[i]>='0' && c[i]<='9'; i++, j++ )
|
||||
d = d * 10 + (int) (c[i]-'0');
|
||||
baos.write( (byte) d );
|
||||
--i;
|
||||
continue;
|
||||
case 'a': baos.write( (byte) 7 ); continue;
|
||||
case 'b': baos.write( (byte) '\b' ); continue;
|
||||
case 'f': baos.write( (byte) '\f' ); continue;
|
||||
case 'n': baos.write( (byte) '\n' ); continue;
|
||||
case 'r': baos.write( (byte) '\r' ); continue;
|
||||
case 't': baos.write( (byte) '\t' ); continue;
|
||||
case 'v': baos.write( (byte) 11 ); continue;
|
||||
case '"': baos.write( (byte) '"' ); continue;
|
||||
case '\'': baos.write( (byte) '\'' ); continue;
|
||||
case '\\': baos.write( (byte) '\\' ); continue;
|
||||
default: baos.write( (byte) c[i] ); break;
|
||||
}
|
||||
} else {
|
||||
baos.write( (byte) c[i] );
|
||||
}
|
||||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
/** Set number of return values, return actual number of returns in practice.
|
||||
*
|
||||
* @param i desired number of returns, or -1 for varargs.
|
||||
*/
|
||||
public void setNumReturns(int i) {
|
||||
}
|
||||
|
||||
/** Get actual number of returns for this subexpression, or -1 for varargs.
|
||||
*
|
||||
* @return actual number of returns, or -1 for varargs.
|
||||
*/
|
||||
public int getNumReturns() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 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.luajc.lst;
|
||||
|
||||
public class LSField {
|
||||
public enum Type {
|
||||
keyValue,
|
||||
nameValue,
|
||||
listValue,
|
||||
}
|
||||
|
||||
public final Type type;
|
||||
|
||||
LSField(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static LSField keyValueField(LSExpression key, LSExpression value) {
|
||||
return new KeyValue(key, value);
|
||||
}
|
||||
|
||||
public static LSField nameValueField(String name, LSExpression value) {
|
||||
return new NameValue(name, value);
|
||||
}
|
||||
|
||||
public static LSField valueField(LSExpression value) {
|
||||
return new ListValue(value);
|
||||
}
|
||||
|
||||
/** table constructor field with an explicit key index value */
|
||||
public static class KeyValue extends LSField {
|
||||
public final LSExpression key;
|
||||
public final LSExpression value;
|
||||
public KeyValue(LSExpression key, LSExpression value) {
|
||||
super( Type.keyValue );
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
value.setNumReturns(1);
|
||||
}
|
||||
public String toString() { return "["+key+"]="+value; }
|
||||
}
|
||||
|
||||
|
||||
/** table constructor field with an named field for key */
|
||||
public static class NameValue extends LSField {
|
||||
public final String name;
|
||||
public final LSExpression value;
|
||||
public NameValue(String name, LSExpression value) {
|
||||
super( Type.nameValue );
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
value.setNumReturns(1);
|
||||
}
|
||||
public String toString() { return name+"="+value; }
|
||||
}
|
||||
|
||||
/** table constructor field with an implied index key */
|
||||
public static class ListValue extends LSField {
|
||||
public final LSExpression value;
|
||||
public ListValue(LSExpression value) {
|
||||
super( Type.listValue );
|
||||
this.value = value;
|
||||
}
|
||||
public void setNumReturns(int i) {
|
||||
value.setNumReturns(i);
|
||||
}
|
||||
public String toString() { return value.toString(); }
|
||||
}
|
||||
|
||||
public void setNumReturns(int i) {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 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.luajc.lst;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class LSFunction {
|
||||
|
||||
public final List<LSStatement> stats = new ArrayList<LSStatement>();
|
||||
public final List<LSFunction> functions = new ArrayList<LSFunction>();
|
||||
public final List<Name> paramnames = new ArrayList<Name>();
|
||||
|
||||
/** set if this is a vararg function */
|
||||
public boolean isvararg;
|
||||
|
||||
/** needsarg is set if the code is vararg and needs the "arg" table to be created. */
|
||||
public boolean hasarg,needsarg;
|
||||
|
||||
/** max number of returns, or -1 for varargs */
|
||||
public int maxReturns = 0;
|
||||
|
||||
/** set if there are logical subexpressions, or varargs assignment */
|
||||
public boolean hasandlogic, hasorlogic, hasvarargassign, usesvarargs;
|
||||
|
||||
public LSFunction() {
|
||||
}
|
||||
|
||||
public LSFunction(boolean isvararg) {
|
||||
this.isvararg = isvararg;
|
||||
}
|
||||
|
||||
public void setStatements(List<LSStatement> stats) {
|
||||
this.stats.clear();
|
||||
this.stats.addAll(stats);
|
||||
}
|
||||
|
||||
public void setParameterNames(List<Name> list) {
|
||||
this.paramnames.clear();
|
||||
this.paramnames.addAll( list );
|
||||
}
|
||||
|
||||
public String toString() { return "function("+paramnames+") "+stats+" end"; }
|
||||
|
||||
public void setUsesVarargs() {
|
||||
this.usesvarargs = true;
|
||||
if ( this.hasarg )
|
||||
this.needsarg = false;
|
||||
}
|
||||
|
||||
public void setHasArg() {
|
||||
this.hasarg = true;
|
||||
if ( ! this.usesvarargs )
|
||||
this.needsarg = true;
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 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.luajc.lst;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class LSIfStatement extends LSStatement {
|
||||
|
||||
public final LSExpression condition;
|
||||
public final List<LSStatement> statements;
|
||||
public List<ElseIf> elseifs;
|
||||
public List<LSStatement> elsestatements;
|
||||
|
||||
public static class ElseIf {
|
||||
public final LSExpression condition;
|
||||
public final List<LSStatement> statements;
|
||||
public ElseIf(LSExpression condition, List<LSStatement> statements) {
|
||||
this.condition = condition;
|
||||
this.statements = statements;
|
||||
}
|
||||
}
|
||||
|
||||
public LSIfStatement(LSExpression condition, List<LSStatement> statements) {
|
||||
super( Type.ifStat );
|
||||
this.condition = condition;
|
||||
this.statements = statements;
|
||||
}
|
||||
|
||||
public void addElseif(LSExpression condition, List<LSStatement> statements) {
|
||||
if ( elseifs == null )
|
||||
elseifs = new ArrayList<ElseIf>();
|
||||
elseifs.add( new ElseIf( condition, statements ) );
|
||||
}
|
||||
|
||||
public void addElse(List<LSStatement> statements) {
|
||||
elsestatements = statements;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "if "+condition+" then "+statements+
|
||||
(elseifs!=null? elseifs.toString(): "")+
|
||||
(elsestatements!=null? " else "+elsestatements: "");
|
||||
}
|
||||
public boolean isNextStatementReachable() {
|
||||
if ( isNextStatementReachable(statements) )
|
||||
return true;
|
||||
if ( elseifs != null )
|
||||
for ( ElseIf e : elseifs )
|
||||
if ( isNextStatementReachable(statements) )
|
||||
return true;
|
||||
if ( isNextStatementReachable(elsestatements) )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,327 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 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.luajc.lst;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class LSStatement {
|
||||
|
||||
public enum Type {
|
||||
functionCall,
|
||||
doBlock,
|
||||
whileLoop,
|
||||
repeatUntil,
|
||||
varAssign,
|
||||
forLoop,
|
||||
forList,
|
||||
varNamedFunction,
|
||||
localFunction,
|
||||
localAssign,
|
||||
returnStat,
|
||||
breakStat,
|
||||
ifStat,
|
||||
}
|
||||
|
||||
public final Type type;
|
||||
|
||||
LSStatement( Type type ) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static LSStatement functionCallStatement(LSVariable variable) {
|
||||
return new FunctionCall( variable );
|
||||
}
|
||||
|
||||
public static LSStatement doBlockStatement(List<LSStatement> statements) {
|
||||
return new DoBlock( statements );
|
||||
}
|
||||
|
||||
public static LSStatement whileLoopStatement(LSExpression condition, List<LSStatement> statements) {
|
||||
return new WhileLoop( condition, statements );
|
||||
}
|
||||
|
||||
public static LSStatement repeatUntilStatement(List<LSStatement> statements, LSExpression condition) {
|
||||
return new RepeatUntil( statements, condition );
|
||||
}
|
||||
|
||||
public static LSStatement forLoopStatement(Name name, LSExpression initial,
|
||||
LSExpression limit, LSExpression step, List<LSStatement> statements, Scope scope) {
|
||||
return new ForLoop( name, initial, limit, step, statements, scope );
|
||||
}
|
||||
|
||||
public static LSStatement forListStatement(List<Name> names,
|
||||
List<LSExpression> expressions, List<LSStatement> statements, Scope scope, LSFunction function) {
|
||||
return new ForList( names, expressions, statements, scope, function );
|
||||
}
|
||||
|
||||
public static LSStatement varFunctionStatement(LSVariable funcname, LSFunction funcbody) {
|
||||
return new VarNamedFunction( funcname, funcbody );
|
||||
}
|
||||
|
||||
public static LSStatement localFunctionStatement(Name name, LSFunction funcbody) {
|
||||
return new LocalFunction( name, funcbody );
|
||||
}
|
||||
|
||||
public static LSStatement varAssignStatement(List<LSVariable> variables, List<LSExpression> expressions, Scope scope, LSFunction function) {
|
||||
setExprNumReturns( variables.size(), expressions, function );
|
||||
return new VarAssign( variables, expressions, scope );
|
||||
}
|
||||
|
||||
public static LSStatement localAssignStatement(List<Name> names, List<LSExpression> expressions, Scope scope, LSFunction function) {
|
||||
setExprNumReturns( names.size(), expressions, function );
|
||||
return new LocalAssign( names, expressions, scope );
|
||||
}
|
||||
|
||||
public static void setExprNumReturns( int nassign, List<LSExpression> expressions, LSFunction function ) {
|
||||
int nexpr = expressions!=null? expressions.size(): 0;
|
||||
for ( int i=0; i<nexpr; i++ )
|
||||
expressions.get(i).setNumReturns(
|
||||
(nassign<=nexpr)?
|
||||
(i<nassign? 1: 0): // same or more expressions than names
|
||||
(i<nexpr-1? 1: -1) ); // more names than expressions
|
||||
if ( nassign > nexpr && nexpr > 0 && expressions.get(nexpr-1).getNumReturns() == -1 )
|
||||
function.hasvarargassign = true;
|
||||
}
|
||||
|
||||
public static LSStatement returnStatement(LSFunction function, List<LSExpression> expressions) {
|
||||
int n=expressions!=null? expressions.size(): 0;
|
||||
|
||||
// set num returns of subexpressions
|
||||
for ( int i=0; i<n; i++ )
|
||||
expressions.get(i).setNumReturns(i<n-1? 1: -1); // last in list returns vararg
|
||||
int nreturns = 0;
|
||||
if ( n > 0 ) {
|
||||
LSExpression last = expressions.get(n-1);
|
||||
int lastreturns = last.getNumReturns();
|
||||
nreturns = (lastreturns<0? -1: lastreturns+n-1);
|
||||
}
|
||||
|
||||
// change the containing function to varargs if necessary.
|
||||
if ( function.maxReturns != -1 && function.maxReturns < nreturns )
|
||||
function.maxReturns = nreturns;
|
||||
if ( function.maxReturns == -1 || function.maxReturns > 1 || nreturns < 0 )
|
||||
function.isvararg = true;
|
||||
|
||||
return new ReturnStat( function, expressions );
|
||||
}
|
||||
|
||||
public static LSStatement breakStatement() {
|
||||
return new BreakStat();
|
||||
}
|
||||
|
||||
/** Statement representing a function call on a variable, such as "foo.bar()" */
|
||||
public static final class FunctionCall extends LSStatement {
|
||||
public final LSVariable variable;
|
||||
FunctionCall(LSVariable variable) {
|
||||
super( Type.functionCall );
|
||||
this.variable = variable;
|
||||
}
|
||||
public String toString() { return variable.toString()+"();"; }
|
||||
}
|
||||
|
||||
/** do block, such as "do foo = bar end" */
|
||||
public static final class DoBlock extends LSStatement {
|
||||
public final List<LSStatement> statements;
|
||||
DoBlock(List<LSStatement> statements) {
|
||||
super( Type.doBlock );
|
||||
this.statements = statements;
|
||||
}
|
||||
public String toString() { return "do "+statements+" end;"; }
|
||||
public boolean isNextStatementReachable() {
|
||||
return isNextStatementReachable(statements);
|
||||
}
|
||||
}
|
||||
|
||||
/** while loop, such as "while foo = true do bar() end" */
|
||||
public static final class WhileLoop extends LSStatement {
|
||||
public final LSExpression condition;
|
||||
public final List<LSStatement> statements;
|
||||
WhileLoop(LSExpression condition, List<LSStatement> statements) {
|
||||
super( Type.whileLoop );
|
||||
this.condition = condition;
|
||||
this.statements = statements;
|
||||
}
|
||||
public String toString() { return "while "+condition+" do "+statements+" end;"; }
|
||||
public boolean isNextStatementReachable() {
|
||||
return isNextStatementReachable(statements);
|
||||
}
|
||||
}
|
||||
|
||||
/** repeat loop, such as "repeat foo() until bar == true" */
|
||||
public static final class RepeatUntil extends LSStatement {
|
||||
public final List<LSStatement> statements;
|
||||
public final LSExpression condition;
|
||||
RepeatUntil(List<LSStatement> statements, LSExpression condition) {
|
||||
super( Type.repeatUntil );
|
||||
this.statements = statements;
|
||||
this.condition = condition;
|
||||
}
|
||||
public String toString() { return "repeat "+statements+" until "+condition+";"; }
|
||||
public boolean isNextStatementReachable() {
|
||||
return isNextStatementReachable(statements);
|
||||
}
|
||||
}
|
||||
|
||||
/** assignment to variables, such as "x.a,y.b = foo,bar" */
|
||||
public static final class VarAssign extends LSStatement {
|
||||
public final List<LSVariable> variables;
|
||||
public final List<LSExpression> expressions;
|
||||
public final Scope scope;
|
||||
VarAssign(List<LSVariable> variables, List<LSExpression> expressions, Scope scope) {
|
||||
super( Type.varAssign );
|
||||
this.variables = variables;
|
||||
this.expressions = expressions;
|
||||
this.scope = scope;
|
||||
}
|
||||
public String toString() { return variables+"="+expressions+";"; }
|
||||
}
|
||||
|
||||
/** for loop with index, such as "for i=1,10,2 do ... end" */
|
||||
public static final class ForLoop extends LSStatement {
|
||||
public final Name index;
|
||||
public final LSExpression initial;
|
||||
public final LSExpression limit;
|
||||
public final LSExpression step;
|
||||
public final List<LSStatement> statements;
|
||||
public final Scope scope;
|
||||
ForLoop(Name name, LSExpression initial, LSExpression limit, LSExpression step, List<LSStatement> statements, Scope scope) {
|
||||
super( Type.forLoop );
|
||||
this.index = name;
|
||||
this.initial = initial;
|
||||
this.limit = limit;
|
||||
this.step = step;
|
||||
this.statements = statements;
|
||||
this.scope = scope;
|
||||
initial.setNumReturns(1);
|
||||
limit.setNumReturns(1);
|
||||
if ( step != null )
|
||||
step.setNumReturns(1);
|
||||
}
|
||||
public String toString() { return "for "+index+"="+initial+","+limit+","+step+" do "+statements+" end;"; }
|
||||
public boolean isNextStatementReachable() {
|
||||
return isNextStatementReachable(statements);
|
||||
}
|
||||
}
|
||||
|
||||
/** for loop with variable, such as "for i,j,k in foo() do ... end" */
|
||||
public static final class ForList extends LSStatement {
|
||||
public final List<Name> names;
|
||||
public final List<LSExpression> expressions;
|
||||
public final List<LSStatement> statements;
|
||||
public final Scope scope;
|
||||
ForList(List<Name> names, List<LSExpression> expressions, List<LSStatement> statements, Scope scope, LSFunction function) {
|
||||
super( Type.forList );
|
||||
this.names = names;
|
||||
this.expressions = expressions;
|
||||
this.statements = statements;
|
||||
this.scope = scope;
|
||||
|
||||
// set return value count for each expression in list;
|
||||
int ne = expressions.size();
|
||||
for ( int i=0; i<ne-1 && i<3; i++ )
|
||||
expressions.get(i).setNumReturns(1);
|
||||
if ( ne<=3 ) {
|
||||
expressions.get(ne-1).setNumReturns(3-(ne-1));
|
||||
function.hasvarargassign = true;
|
||||
}
|
||||
}
|
||||
public String toString() { return "for "+names+" in "+expressions+" do "+statements+" end;"; }
|
||||
public boolean isNextStatementReachable() {
|
||||
return isNextStatementReachable(statements);
|
||||
}
|
||||
}
|
||||
|
||||
/** variable function declaration, such as "a.b = function() end" */
|
||||
public static final class VarNamedFunction extends LSStatement {
|
||||
public final LSVariable funcname;
|
||||
public final LSFunction funcbody;
|
||||
VarNamedFunction(LSVariable funcname, LSFunction funcbody) {
|
||||
super( Type.varNamedFunction );
|
||||
this.funcname = funcname;
|
||||
this.funcbody = funcbody;
|
||||
}
|
||||
public String toString() { return funcname+"=f:"+funcbody+";"; }
|
||||
}
|
||||
|
||||
/** simple function declaration, such as "a = function() end" */
|
||||
public static final class LocalFunction extends LSStatement {
|
||||
public final Name name;
|
||||
public final LSFunction funcbody;
|
||||
LocalFunction(Name name, LSFunction funcbody) {
|
||||
super( Type.localFunction );
|
||||
this.name = name;
|
||||
this.funcbody = funcbody;
|
||||
}
|
||||
public String toString() { return name+"=f:"+funcbody+";"; }
|
||||
}
|
||||
|
||||
/** assignment, such as "a,b = foo,bar" */
|
||||
public static final class LocalAssign extends LSStatement {
|
||||
public final List<Name> names;
|
||||
public final List<LSExpression> expressions;
|
||||
public final Scope scope;
|
||||
LocalAssign(List<Name> list, List<LSExpression> expressions, Scope scope) {
|
||||
super( Type.localAssign );
|
||||
this.names = list;
|
||||
this.expressions = expressions;
|
||||
this.scope = scope;
|
||||
}
|
||||
public String toString() { return names+"="+expressions+";"; }
|
||||
}
|
||||
|
||||
/** return statement, such as "return foo,bar" */
|
||||
public static final class ReturnStat extends LSStatement {
|
||||
public final LSFunction function;
|
||||
public final List<LSExpression> expressions;
|
||||
ReturnStat(LSFunction function, List<LSExpression> expressions) {
|
||||
super( Type.returnStat );
|
||||
this.function = function;
|
||||
this.expressions = expressions;
|
||||
}
|
||||
public String toString() { return "return "+expressions+";"; }
|
||||
public boolean isNextStatementReachable() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** break statement */
|
||||
public static final class BreakStat extends LSStatement {
|
||||
BreakStat() {
|
||||
super( Type.breakStat );
|
||||
}
|
||||
public String toString() { return "break;"; }
|
||||
}
|
||||
|
||||
/** True of this statment could return and therefore the next statement is reachable. */
|
||||
public boolean isNextStatementReachable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isNextStatementReachable(List<LSStatement> stats) {
|
||||
if ( stats == null )
|
||||
return true;
|
||||
for ( LSStatement s : stats )
|
||||
if ( ! s.isNextStatementReachable() )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,172 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 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.luajc.lst;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class LSVariable extends LSExpression {
|
||||
|
||||
LSVariable(Type type) {
|
||||
super(type);
|
||||
}
|
||||
|
||||
/** name, such as 'foo' */
|
||||
public static LSVariable nameVariable(Name name) {
|
||||
return new NameReference(name);
|
||||
}
|
||||
|
||||
/** table field, such as 'a.b' */
|
||||
public LSVariable fieldVariable(String field) {
|
||||
return new Field(this, field);
|
||||
}
|
||||
|
||||
/** method reference, such as foo:bar */
|
||||
public LSVariable methodVariable(String method) {
|
||||
return new Method(this, method);
|
||||
}
|
||||
|
||||
/** parenthetical reference, such as '(foo())' */
|
||||
public static LSVariable parenthesesVariable(LSExpression expression) {
|
||||
if ( expression != null )
|
||||
expression.setNumReturns(1);
|
||||
return new Parentheses(expression);
|
||||
}
|
||||
|
||||
/** table index, such as 'a[b]' */
|
||||
public LSVariable indexVariable(LSExpression expression) {
|
||||
return new Index(this, expression);
|
||||
}
|
||||
|
||||
/** Variable is a method, such as 'a(x,y)' */
|
||||
public LSVariable callFuncVariable(List<LSExpression> parameters) {
|
||||
int n = parameters.size();
|
||||
for ( int i=0; i<n; i++ )
|
||||
parameters.get(i).setNumReturns(i<n-1? 1: -1);
|
||||
return new CallFunction(this, parameters);
|
||||
}
|
||||
|
||||
/** Variable is a method, such as 'a:b(x,y)' */
|
||||
public LSVariable callMethVariable(String method, List<LSExpression> parameters) {
|
||||
int n = parameters.size();
|
||||
for ( int i=0; i<n; i++ )
|
||||
parameters.get(i).setNumReturns(i<n-1? 1: -1);
|
||||
return new CallMethod(this, method, parameters);
|
||||
}
|
||||
|
||||
/** name, such as 'foo' */
|
||||
public static class NameReference extends LSVariable {
|
||||
public final Name name;
|
||||
public NameReference(Name name) {
|
||||
super( Type.nameVariable );
|
||||
this.name = name;
|
||||
}
|
||||
public String toString() { return name.toString(); }
|
||||
}
|
||||
|
||||
/** field reference, such as foo.bar */
|
||||
public static class Field extends LSVariable {
|
||||
public final LSVariable variable;
|
||||
public final String field;
|
||||
public Field(LSVariable variable, String field) {
|
||||
super( Type.fieldVariable );
|
||||
this.variable = variable;
|
||||
this.field = field;
|
||||
}
|
||||
public String toString() { return variable+"."+field; }
|
||||
}
|
||||
|
||||
/** method reference, such as foo:bar */
|
||||
public static class Method extends LSVariable {
|
||||
public final LSVariable variable;
|
||||
public final String method;
|
||||
public Method(LSVariable variable, String method) {
|
||||
super( Type.methodVariable );
|
||||
this.variable = variable;
|
||||
this.method = method;
|
||||
}
|
||||
public String toString() { return variable+":"+method; }
|
||||
}
|
||||
|
||||
/** parenthetical reference, such as '(foo())' */
|
||||
public static class Parentheses extends LSVariable {
|
||||
public final LSExpression expression;
|
||||
public Parentheses(LSExpression expression) {
|
||||
super( Type.parenthesesVariable );
|
||||
this.expression = expression;
|
||||
}
|
||||
public String toString() { return "("+expression+")"; }
|
||||
}
|
||||
|
||||
/** table index, such as 'a[b]' */
|
||||
public static class Index extends LSVariable {
|
||||
public final LSVariable variable;
|
||||
public final LSExpression expression;
|
||||
public Index(LSVariable variable, LSExpression expression) {
|
||||
super( Type.indexVariable );
|
||||
this.variable = variable;
|
||||
this.expression = expression;
|
||||
}
|
||||
public String toString() { return variable+"["+expression+"]"; }
|
||||
}
|
||||
|
||||
|
||||
/** Variable is a function invocation, such as 'a(x,y)' */
|
||||
public static class CallFunction extends LSVariable {
|
||||
public final LSVariable variable;
|
||||
public final List<LSExpression> parameters;
|
||||
public int numReturns = 0;
|
||||
public CallFunction(LSVariable variable, List<LSExpression> parameters) {
|
||||
super( Type.callFunctionVariable );
|
||||
this.variable = variable;
|
||||
this.parameters = parameters;
|
||||
}
|
||||
public void setNumReturns(int i) {
|
||||
this.numReturns = i;
|
||||
}
|
||||
public int getNumReturns() {
|
||||
return numReturns;
|
||||
}
|
||||
public String toString() { return variable+"("+parameters+")"; }
|
||||
}
|
||||
|
||||
/** Variable is a method invocation, such as 'a:bc()' */
|
||||
public static class CallMethod extends LSVariable {
|
||||
public final LSVariable variable;
|
||||
public final String method;
|
||||
public final List<LSExpression> parameters;
|
||||
public int numReturns = 0;
|
||||
public CallMethod(LSVariable variable, String method, List<LSExpression> parameters) {
|
||||
super( Type.callMethodVariable );
|
||||
this.variable = variable;
|
||||
this.method = method;
|
||||
this.parameters = parameters;
|
||||
}
|
||||
public void setNumReturns(int i) {
|
||||
this.numReturns = i;
|
||||
}
|
||||
public int getNumReturns() {
|
||||
return numReturns;
|
||||
}
|
||||
public String toString() { return variable+":"+method+"("+parameters+")"; }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 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.luajc.lst;
|
||||
|
||||
/** A name in lua source, which resolves to one of:
|
||||
* - global reference
|
||||
* - local that is not an upvalue
|
||||
* - local that is an upvalue
|
||||
*/
|
||||
public class Name {
|
||||
|
||||
/** Name in lua source file */
|
||||
public final String luaname;
|
||||
|
||||
/** 0 if in outermost scope, 1 if in next inner scope, ect. */
|
||||
public final int scopelevel;
|
||||
|
||||
/** 0 if first declaration in global program, 1 if second use, etc. */
|
||||
public final int outerrevision;
|
||||
|
||||
/** 0 if first declaration in nearest enclosing function, 1 if second use, etc */
|
||||
public final int innerrevision;
|
||||
|
||||
/** true if used as an upvalue by some enclosed function */
|
||||
public boolean isupvalue;
|
||||
|
||||
/** Construct a name instance */
|
||||
public Name(String luaname, int scopelevel, int outerrevision, int innterrevision) {
|
||||
super();
|
||||
this.luaname = luaname;
|
||||
this.scopelevel = scopelevel;
|
||||
this.outerrevision = outerrevision;
|
||||
this.innerrevision = innterrevision;
|
||||
}
|
||||
|
||||
/** Construct a name reference representing a global reference */
|
||||
public Name(String name) {
|
||||
this.luaname = name;
|
||||
this.scopelevel = -1;
|
||||
this.outerrevision = -1;
|
||||
this.innerrevision = -1;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return scopelevel<0?
|
||||
"_G$"+luaname:
|
||||
luaname+"$s"+scopelevel+"$v"+outerrevision+"$f"+innerrevision;
|
||||
}
|
||||
|
||||
public boolean isGlobal() {
|
||||
return -1 == outerrevision;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 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.luajc.lst;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/** A name scope in lua source terms.
|
||||
* Combination of function scope and block scope.
|
||||
*/
|
||||
public class Scope {
|
||||
public final Scope parent;
|
||||
public final int level;
|
||||
public final boolean isFunctionScope;
|
||||
public boolean hasAndOrLogic;
|
||||
public final Map<String,Name> names = new HashMap<String,Name>();
|
||||
|
||||
/** Construct a new default scope for a chunk */
|
||||
public Scope() {
|
||||
this.parent = null;
|
||||
this.isFunctionScope = true;
|
||||
this.level = 0;
|
||||
}
|
||||
|
||||
/** Construct an inner scope
|
||||
* @param parent the outer scope to fall back to, or null if a global scope
|
||||
* @param isFunctionScope true if this is a function scope, false otherwise
|
||||
*/
|
||||
public Scope(Scope parent, boolean isFunctionScope) {
|
||||
this.parent = parent;
|
||||
this.isFunctionScope = isFunctionScope;
|
||||
this.level = parent!=null? parent.level + 1: 0;
|
||||
}
|
||||
|
||||
/** Declare a single name in the current scope, and return the Name element for it */
|
||||
public Name declare(String name) {
|
||||
boolean crossesFunctionBoundary = false;
|
||||
for ( Scope s=this; s!=null; s=s.parent ) {
|
||||
Name n = s.names.get(name);
|
||||
if ( n != null ) {
|
||||
Name result = new Name(name,
|
||||
level,
|
||||
n.outerrevision+1,
|
||||
crossesFunctionBoundary? 0: n.innerrevision+1);
|
||||
names.put(name, result);
|
||||
return result;
|
||||
}
|
||||
if ( s.isFunctionScope )
|
||||
crossesFunctionBoundary = true;
|
||||
}
|
||||
Name result = new Name(name, level, 0, 0);
|
||||
names.put(name, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Reference a name, and find either the local scope within the function, the upvalue, or a global name */
|
||||
public Name reference(String name) {
|
||||
boolean crossesFunctionBoundary = false;
|
||||
for ( Scope s=this; s!=null; s=s.parent ) {
|
||||
Name n = s.names.get(name);
|
||||
if ( n != null ) {
|
||||
if ( crossesFunctionBoundary ) {
|
||||
n.isupvalue = true;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
if ( s.isFunctionScope )
|
||||
crossesFunctionBoundary = true;
|
||||
}
|
||||
// globally scoped name
|
||||
return new Name(name);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
String ours = (isFunctionScope? "F": "")+names;
|
||||
return (parent==null? ours: ours+"->"+parent.toString());
|
||||
}
|
||||
|
||||
/** Return true iff this scope is part the main chunk */
|
||||
public boolean isMainChunkScope() {
|
||||
return isFunctionScope? false: parent==null? true: parent.isMainChunkScope();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 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.luajc.lst;
|
||||
|
||||
public class UnOp {
|
||||
public enum Type {
|
||||
neg,not,len
|
||||
}
|
||||
|
||||
public static final UnOp NEG = new UnOp(Type.neg, "-");
|
||||
public static final UnOp NOT = new UnOp(Type.not, "~");
|
||||
public static final UnOp LEN = new UnOp(Type.len, "#");
|
||||
|
||||
public final Type type;
|
||||
public final String luaop;
|
||||
|
||||
private UnOp(Type type, String luaop) {
|
||||
super();
|
||||
this.type = type;
|
||||
this.luaop = luaop;
|
||||
}
|
||||
|
||||
public String toString() { return luaop; }
|
||||
}
|
||||
@@ -28,7 +28,7 @@ import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.lib.JsePlatform;
|
||||
import org.luaj.vm2.luajc.LuaJCompiler;
|
||||
import org.luaj.vm2.luajc.LuaJC;
|
||||
|
||||
public class TestLuaJC {
|
||||
// create the script
|
||||
@@ -48,9 +48,7 @@ public class TestLuaJC {
|
||||
LuaValue chunk;
|
||||
if ( ! (args.length>0 && args[0].equals("nocompile")) ) {
|
||||
InputStream is = new ByteArrayInputStream( script.getBytes() );
|
||||
String java =LuaJCompiler.compileToJava(is, "script");
|
||||
System.out.println("java:\n"+java);
|
||||
chunk = LuaJCompiler.javaCompile(java, "script");
|
||||
chunk = LuaJC.getInstance().load(is, "script", _G);
|
||||
} else {
|
||||
chunk = (LuaValue) Class.forName("script").newInstance();
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
import org.luaj.vm2.luajc.JavaBytecodeCompiler;
|
||||
import org.luaj.vm2.luajc.LuaJC;
|
||||
|
||||
/**
|
||||
* Compatibility tests for the Luaj VM
|
||||
@@ -92,7 +92,7 @@ public class CompatibiltyTest {
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
System.setProperty("JME", "false");
|
||||
JavaBytecodeCompiler.install();
|
||||
LuaJC.install();
|
||||
}
|
||||
// not supported on this platform - don't test
|
||||
public void testDebugLib() {}
|
||||
|
||||
@@ -27,7 +27,7 @@ import java.io.InputStream;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
import org.luaj.vm2.luajc.JavaBytecodeCompiler;
|
||||
import org.luaj.vm2.luajc.LuaJC;
|
||||
|
||||
/**
|
||||
* Test compilation of various fragments that have
|
||||
@@ -43,7 +43,7 @@ public class FragmentsTest extends TestCase {
|
||||
InputStream is = new ByteArrayInputStream(script.getBytes("UTF-8"));
|
||||
LuaValue chunk ;
|
||||
if ( true ) {
|
||||
chunk = JavaBytecodeCompiler.load(is,name,_G);
|
||||
chunk = LuaJC.getInstance().load(is,name,_G);
|
||||
} else {
|
||||
chunk = (new LuaC()).load( is, name, _G );
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ import java.io.PrintStream;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.luaj.vm2.lib.BaseLib;
|
||||
import org.luaj.vm2.luajc.JavaBytecodeCompiler;
|
||||
import org.luaj.vm2.luajc.LuaJC;
|
||||
|
||||
abstract
|
||||
public class ScriptDrivenTest extends TestCase {
|
||||
@@ -111,7 +111,7 @@ public class ScriptDrivenTest extends TestCase {
|
||||
return c;
|
||||
} else {
|
||||
script = new FileInputStream(file);
|
||||
return JavaBytecodeCompiler.load( script, name, _G);
|
||||
return LuaJC.getInstance().load( script, name, _G);
|
||||
}
|
||||
default:
|
||||
script = new FileInputStream(file);
|
||||
|
||||
Reference in New Issue
Block a user