Fix vararg parameter handling, self and setlist bytecode processing.
This commit is contained in:
@@ -311,6 +311,7 @@ public class LuaValue extends Varargs {
|
|||||||
|
|
||||||
// table initializers
|
// table initializers
|
||||||
public static LuaTable tableOf() { return new LuaTable(); }
|
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(int narray, int nhash) { return new LuaTable(narray, nhash); }
|
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) { return new LuaTable(null,unnamedValues,null); }
|
||||||
public static LuaTable listOf(LuaValue[] unnamedValues,Varargs lastarg) { return new LuaTable(null,unnamedValues,lastarg); }
|
public static LuaTable listOf(LuaValue[] unnamedValues,Varargs lastarg) { return new LuaTable(null,unnamedValues,lastarg); }
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import java.io.InputStream;
|
|||||||
import org.luaj.vm2.LoadState;
|
import org.luaj.vm2.LoadState;
|
||||||
import org.luaj.vm2.LuaClosure;
|
import org.luaj.vm2.LuaClosure;
|
||||||
import org.luaj.vm2.LuaFunction;
|
import org.luaj.vm2.LuaFunction;
|
||||||
|
import org.luaj.vm2.LuaTable;
|
||||||
import org.luaj.vm2.LuaValue;
|
import org.luaj.vm2.LuaValue;
|
||||||
import org.luaj.vm2.Prototype;
|
import org.luaj.vm2.Prototype;
|
||||||
import org.luaj.vm2.LoadState.LuaCompiler;
|
import org.luaj.vm2.LoadState.LuaCompiler;
|
||||||
@@ -52,14 +53,25 @@ public class JavaBytecodeCompiler implements LuaCompiler {
|
|||||||
LoadState.compiler = getInstance();
|
LoadState.compiler = getInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
private JavaBytecodeCompiler() {
|
public JavaBytecodeCompiler() {
|
||||||
luac = new LuaC();
|
luac = new LuaC();
|
||||||
gen = new JavaBytecodeGenerator();
|
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. */
|
/** Compile into protoype form. */
|
||||||
public Prototype compile(int firstByte, InputStream stream, String name) throws IOException {
|
public Prototype compile(int firstByte, InputStream stream, String chunkname) throws IOException {
|
||||||
return luac.compile(firstByte, stream, name);
|
return luac.compile(firstByte, stream, chunkname);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Compile into class form. */
|
/** Compile into class form. */
|
||||||
@@ -70,10 +82,8 @@ public class JavaBytecodeCompiler implements LuaCompiler {
|
|||||||
classname = classname.replace('/', '.');
|
classname = classname.replace('/', '.');
|
||||||
classname = classname.replace('\\', '.');
|
classname = classname.replace('\\', '.');
|
||||||
String sourcename = filename.substring( filename.lastIndexOf('/')+1 );
|
String sourcename = filename.substring( filename.lastIndexOf('/')+1 );
|
||||||
System.out.println("compiling file "+filename+" using sourcename "+sourcename+" and classname "+classname);
|
|
||||||
Class c = gen.toJavaBytecode(p, classname, sourcename);
|
Class c = gen.toJavaBytecode(p, classname, sourcename);
|
||||||
Object o = c.newInstance();
|
Object o = c.newInstance();
|
||||||
System.out.println("instance is: "+o);
|
|
||||||
LuaFunction f = (LuaFunction) o;
|
LuaFunction f = (LuaFunction) o;
|
||||||
f.setfenv(env);
|
f.setfenv(env);
|
||||||
return f;
|
return f;
|
||||||
|
|||||||
@@ -286,6 +286,7 @@ public class JavaBytecodeGenerator {
|
|||||||
LocalVariableGen[] locals = new LocalVariableGen[nl];
|
LocalVariableGen[] locals = new LocalVariableGen[nl];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// initialize locals
|
// initialize locals
|
||||||
LocalVariableGen nil = null;
|
LocalVariableGen nil = null;
|
||||||
// LocalVariableGen reg[] = new LocalVariableGen[nl];
|
// LocalVariableGen reg[] = new LocalVariableGen[nl];
|
||||||
@@ -293,14 +294,13 @@ public class JavaBytecodeGenerator {
|
|||||||
boolean isup[] = new boolean[nl];
|
boolean isup[] = new boolean[nl];
|
||||||
markups(p, isup, code, 0, 0);
|
markups(p, isup, code, 0, 0);
|
||||||
|
|
||||||
|
// initialize slotc
|
||||||
|
boolean needsarg = ((p.is_vararg & Lua.VARARG_NEEDSARG) != 0);
|
||||||
for (int j = 0; j < nl; j++) {
|
for (int j = 0; j < nl; j++) {
|
||||||
|
// create space
|
||||||
String name = j < p.locvars.length && p.locvars[j].varname != null ?
|
LuaString luaname = p.getlocalname(j,0);
|
||||||
toLegalJavaName(p.locvars[j].varname.toString()):
|
String name = toLegalJavaName( luaname!=null? luaname.toString(): "r"+j );
|
||||||
"r" + j;
|
locals[j] = mg.addLocalVariable(name, isup[j] ? TYPE_LOCALUPVALUE : TYPE_LUAVALUE, null, null);
|
||||||
|
|
||||||
locals[j] = mg.addLocalVariable(name, isup[j] ? TYPE_LOCALUPVALUE
|
|
||||||
: TYPE_LUAVALUE, null, null);
|
|
||||||
|
|
||||||
if (isup[j]) { // upvalue storage
|
if (isup[j]) { // upvalue storage
|
||||||
il.append(new PUSH(cp, 1));
|
il.append(new PUSH(cp, 1));
|
||||||
@@ -314,9 +314,11 @@ public class JavaBytecodeGenerator {
|
|||||||
if (j < np) {
|
if (j < np) {
|
||||||
il.append(new ALOAD(1));
|
il.append(new ALOAD(1));
|
||||||
il.append(new PUSH(cp, j + 1));
|
il.append(new PUSH(cp, j + 1));
|
||||||
il.append(factory.createInvoke(STR_VARARGS, "arg",
|
il.append(factory.createInvoke(STR_VARARGS, "arg", TYPE_LUAVALUE, new Type[] { Type.INT }, Constants.INVOKEVIRTUAL));
|
||||||
TYPE_LUAVALUE, new Type[] { Type.INT },
|
} else if ( (j == np) && needsarg ) {
|
||||||
Constants.INVOKEVIRTUAL));
|
il.append(new ALOAD(1));
|
||||||
|
il.append(new PUSH(cp, np+1));
|
||||||
|
il.append(factory.createInvoke(STR_LUAVALUE, "tableOf", TYPE_LUATABLE, new Type[] { TYPE_VARARGS, Type.INT }, Constants.INVOKESTATIC));
|
||||||
} else {
|
} else {
|
||||||
nil = il_initLocalNil(mg, factory, il, nil);
|
nil = il_initLocalNil(mg, factory, il, nil);
|
||||||
il.append(new ALOAD(nil.getIndex()));
|
il.append(new ALOAD(nil.getIndex()));
|
||||||
@@ -384,6 +386,7 @@ public class JavaBytecodeGenerator {
|
|||||||
// pc++; /* skip next instruction (if C) */
|
// pc++; /* skip next instruction (if C) */
|
||||||
branches[pc] = new GOTO(null);
|
branches[pc] = new GOTO(null);
|
||||||
targets[pc] = pc + 2;
|
targets[pc] = pc + 2;
|
||||||
|
il.append(branches[pc]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -475,6 +478,7 @@ public class JavaBytecodeGenerator {
|
|||||||
// stack[a+1] = (o = stack[B(i)]);
|
// stack[a+1] = (o = stack[B(i)]);
|
||||||
ih[pc] =
|
ih[pc] =
|
||||||
il_append_new_ALOAD(cp,il, (locals[B(i)]));
|
il_append_new_ALOAD(cp,il, (locals[B(i)]));
|
||||||
|
il.append(InstructionConstants.DUP);
|
||||||
il_append_new_ASTORE(cp,il, (locals[a+1]));
|
il_append_new_ASTORE(cp,il, (locals[a+1]));
|
||||||
// stack[a] = o.get((c=C(i))>0xff? k[c&0x0ff]: stack[c]);
|
// stack[a] = o.get((c=C(i))>0xff? k[c&0x0ff]: stack[c]);
|
||||||
if ((c=C(i))>0xff)
|
if ((c=C(i))>0xff)
|
||||||
@@ -880,12 +884,14 @@ public class JavaBytecodeGenerator {
|
|||||||
//o = stack[a];
|
//o = stack[a];
|
||||||
il_append_new_ALOAD(cp,il, (locals[a]));
|
il_append_new_ALOAD(cp,il, (locals[a]));
|
||||||
if ( (b=B(i)) == 0 ) {
|
if ( (b=B(i)) == 0 ) {
|
||||||
for ( int j=1; a+j<vbase; j++ ) {
|
int j=1;
|
||||||
|
for ( ; a+j<vbase; j++ ) {
|
||||||
il.append(InstructionConstants.DUP);
|
il.append(InstructionConstants.DUP);
|
||||||
il.append(new PUSH(cp,offset+j));
|
il.append(new PUSH(cp,offset+j));
|
||||||
il_append_new_ALOAD(cp,il, (locals[a+j]));
|
il_append_new_ALOAD(cp,il, (locals[a+j]));
|
||||||
il.append(factory.createInvoke(STR_LUAVALUE, "rawset", Type.VOID, new Type[] { Type.INT, TYPE_LUAVALUE }, Constants.INVOKEVIRTUAL));
|
il.append(factory.createInvoke(STR_LUAVALUE, "rawset", Type.VOID, new Type[] { Type.INT, TYPE_LUAVALUE }, Constants.INVOKEVIRTUAL));
|
||||||
}
|
}
|
||||||
|
il.append(new PUSH(cp,offset+j));
|
||||||
il.append(new ALOAD(v.getIndex()));
|
il.append(new ALOAD(v.getIndex()));
|
||||||
il.append(factory.createInvoke(STR_LUAVALUE, "rawsetlist", Type.VOID, new Type[] { Type.INT, TYPE_VARARGS }, Constants.INVOKEVIRTUAL));
|
il.append(factory.createInvoke(STR_LUAVALUE, "rawsetlist", Type.VOID, new Type[] { Type.INT, TYPE_VARARGS }, Constants.INVOKEVIRTUAL));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ import java.io.InputStream;
|
|||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
import org.luaj.vm2.luajc.LuaJCompiler;
|
import org.luaj.vm2.compiler.LuaC;
|
||||||
|
import org.luaj.vm2.luajc.JavaBytecodeCompiler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test compilation of various fragments that have
|
* Test compilation of various fragments that have
|
||||||
@@ -40,9 +41,12 @@ public class FragmentsTest extends TestCase {
|
|||||||
String name = getName();
|
String name = getName();
|
||||||
LuaTable _G = org.luaj.vm2.lib.JsePlatform.standardGlobals();
|
LuaTable _G = org.luaj.vm2.lib.JsePlatform.standardGlobals();
|
||||||
InputStream is = new ByteArrayInputStream(script.getBytes("UTF-8"));
|
InputStream is = new ByteArrayInputStream(script.getBytes("UTF-8"));
|
||||||
String java = LuaJCompiler.compileToJava(is, name);
|
LuaValue chunk ;
|
||||||
LuaValue chunk = LuaJCompiler.javaCompile(java, name);
|
if ( true ) {
|
||||||
chunk.setfenv(_G);
|
chunk = JavaBytecodeCompiler.load(is,name,_G);
|
||||||
|
} else {
|
||||||
|
chunk = (new LuaC()).load( is, name, _G );
|
||||||
|
}
|
||||||
Varargs actual = chunk.invoke();
|
Varargs actual = chunk.invoke();
|
||||||
assertEquals( expected.narg(), actual.narg() );
|
assertEquals( expected.narg(), actual.narg() );
|
||||||
for ( int i=1; i<=actual.narg(); i++ )
|
for ( int i=1; i<=actual.narg(); i++ )
|
||||||
@@ -54,15 +58,70 @@ public class FragmentsTest extends TestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testArgParam() {
|
public void testVarVarargsUseArg() {
|
||||||
// the name "arg" is treated specially, and ends up masking the argument value in 5.1
|
runFragment( LuaValue.varargsOf( new LuaValue[] {
|
||||||
runFragment( LuaValue.NIL,
|
LuaValue.valueOf("a"),
|
||||||
|
LuaValue.valueOf(2),
|
||||||
|
LuaValue.valueOf("b"),
|
||||||
|
LuaValue.valueOf("c"),
|
||||||
|
LuaValue.NIL }),
|
||||||
|
"function q(a,...)\n" +
|
||||||
|
" return a,arg.n,arg[1],arg[2],arg[3]\n" +
|
||||||
|
"end\n" +
|
||||||
|
"return q('a','b','c')\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testVarVarargsUseBoth() {
|
||||||
|
runFragment( LuaValue.varargsOf( new LuaValue[] {
|
||||||
|
LuaValue.valueOf("a"),
|
||||||
|
LuaValue.valueOf("nil"),
|
||||||
|
LuaValue.valueOf("b"),
|
||||||
|
LuaValue.valueOf("c")}),
|
||||||
|
"function r(a,...)\n" +
|
||||||
|
" return a,type(arg),...\n" +
|
||||||
|
"end\n" +
|
||||||
|
"return r('a','b','c')\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testArgVarargsUseBoth() {
|
||||||
|
runFragment( LuaValue.varargsOf( new LuaValue[] {
|
||||||
|
LuaValue.NIL,
|
||||||
|
LuaValue.valueOf("b"),
|
||||||
|
LuaValue.valueOf("c")}),
|
||||||
"function v(arg,...)\n" +
|
"function v(arg,...)\n" +
|
||||||
" return arg\n" +
|
" return arg,...\n" +
|
||||||
|
"end\n" +
|
||||||
|
"return v('a','b','c')\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testArgParamUseNone() {
|
||||||
|
// the name "arg" is treated specially, and ends up masking the argument value in 5.1
|
||||||
|
runFragment( LuaValue.valueOf("table"),
|
||||||
|
"function v(arg,...)\n" +
|
||||||
|
" return type(arg)\n" +
|
||||||
"end\n" +
|
"end\n" +
|
||||||
"return v('abc')\n" );
|
"return v('abc')\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testSetlistVarargs() {
|
||||||
|
runFragment( LuaValue.valueOf("abc"),
|
||||||
|
"local f = function() return 'abc' end\n" +
|
||||||
|
"local g = { f() }\n" +
|
||||||
|
"return g[1]\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSelfOp() {
|
||||||
|
runFragment( LuaValue.valueOf("bcd"),
|
||||||
|
"local s = 'abcde'\n"+
|
||||||
|
"return s:sub(2,4)\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSetListWithOffsetAndVarargs() {
|
||||||
|
runFragment( LuaValue.valueOf(1003),
|
||||||
|
"local bar = {1000, math.sqrt(9)}\n"+
|
||||||
|
"return bar[1]+bar[2]\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void testMultiAssign() {
|
public void testMultiAssign() {
|
||||||
// arargs evaluations are all done before assignments
|
// arargs evaluations are all done before assignments
|
||||||
@@ -192,7 +251,7 @@ public class FragmentsTest extends TestCase {
|
|||||||
public void testNoReturnValuesPlainCall() {
|
public void testNoReturnValuesPlainCall() {
|
||||||
runFragment( LuaValue.TRUE,
|
runFragment( LuaValue.TRUE,
|
||||||
"local testtable = {}\n"+
|
"local testtable = {}\n"+
|
||||||
"return pcall( function() testtable[1]=2 end ) )\n" );
|
"return pcall( function() testtable[1]=2 end )\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testVarargsInTableConstructor() {
|
public void testVarargsInTableConstructor() {
|
||||||
|
|||||||
Reference in New Issue
Block a user