Fix vararg parameter handling, self and setlist bytecode processing.

This commit is contained in:
James Roseborough
2009-10-30 19:24:43 +00:00
parent 668692d0a2
commit 3e3909b14b
4 changed files with 104 additions and 28 deletions

View File

@@ -310,7 +310,8 @@ public class LuaValue extends Varargs {
}
// 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 listOf(LuaValue[] unnamedValues) { return new LuaTable(null,unnamedValues,null); }
public static LuaTable listOf(LuaValue[] unnamedValues,Varargs lastarg) { return new LuaTable(null,unnamedValues,lastarg); }

View File

@@ -27,6 +27,7 @@ import java.io.InputStream;
import org.luaj.vm2.LoadState;
import org.luaj.vm2.LuaClosure;
import org.luaj.vm2.LuaFunction;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Prototype;
import org.luaj.vm2.LoadState.LuaCompiler;
@@ -52,14 +53,25 @@ public class JavaBytecodeCompiler implements LuaCompiler {
LoadState.compiler = getInstance();
}
private JavaBytecodeCompiler() {
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 name) throws IOException {
return luac.compile(firstByte, stream, name);
public Prototype compile(int firstByte, InputStream stream, String chunkname) throws IOException {
return luac.compile(firstByte, stream, chunkname);
}
/** Compile into class form. */
@@ -70,10 +82,8 @@ public class JavaBytecodeCompiler implements LuaCompiler {
classname = classname.replace('/', '.');
classname = classname.replace('\\', '.');
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);
Object o = c.newInstance();
System.out.println("instance is: "+o);
LuaFunction f = (LuaFunction) o;
f.setfenv(env);
return f;

View File

@@ -284,6 +284,7 @@ public class JavaBytecodeGenerator {
int np = p.numparams;
int nl = p.maxstacksize;
LocalVariableGen[] locals = new LocalVariableGen[nl];
// initialize locals
@@ -292,16 +293,15 @@ public class JavaBytecodeGenerator {
// LocalVariableGen regup[] = new LocalVariableGen[nl];
boolean isup[] = new boolean[nl];
markups(p, isup, code, 0, 0);
// initialize slotc
boolean needsarg = ((p.is_vararg & Lua.VARARG_NEEDSARG) != 0);
for (int j = 0; j < nl; j++) {
String name = j < p.locvars.length && p.locvars[j].varname != null ?
toLegalJavaName(p.locvars[j].varname.toString()):
"r" + j;
locals[j] = mg.addLocalVariable(name, isup[j] ? TYPE_LOCALUPVALUE
: TYPE_LUAVALUE, null, null);
// create space
LuaString luaname = p.getlocalname(j,0);
String name = toLegalJavaName( luaname!=null? luaname.toString(): "r"+j );
locals[j] = mg.addLocalVariable(name, isup[j] ? TYPE_LOCALUPVALUE : TYPE_LUAVALUE, null, null);
if (isup[j]) { // upvalue storage
il.append(new PUSH(cp, 1));
il.append(new ANEWARRAY(cp.addClass(STR_LUAVALUE)));
@@ -314,9 +314,11 @@ public class JavaBytecodeGenerator {
if (j < np) {
il.append(new ALOAD(1));
il.append(new PUSH(cp, j + 1));
il.append(factory.createInvoke(STR_VARARGS, "arg",
TYPE_LUAVALUE, new Type[] { Type.INT },
Constants.INVOKEVIRTUAL));
il.append(factory.createInvoke(STR_VARARGS, "arg", TYPE_LUAVALUE, new Type[] { Type.INT }, Constants.INVOKEVIRTUAL));
} else if ( (j == np) && needsarg ) {
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 {
nil = il_initLocalNil(mg, factory, il, nil);
il.append(new ALOAD(nil.getIndex()));
@@ -384,6 +386,7 @@ public class JavaBytecodeGenerator {
// pc++; /* skip next instruction (if C) */
branches[pc] = new GOTO(null);
targets[pc] = pc + 2;
il.append(branches[pc]);
}
break;
@@ -475,6 +478,7 @@ public class JavaBytecodeGenerator {
// stack[a+1] = (o = stack[B(i)]);
ih[pc] =
il_append_new_ALOAD(cp,il, (locals[B(i)]));
il.append(InstructionConstants.DUP);
il_append_new_ASTORE(cp,il, (locals[a+1]));
// stack[a] = o.get((c=C(i))>0xff? k[c&0x0ff]: stack[c]);
if ((c=C(i))>0xff)
@@ -880,12 +884,14 @@ public class JavaBytecodeGenerator {
//o = stack[a];
il_append_new_ALOAD(cp,il, (locals[a]));
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(new PUSH(cp,offset+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(new PUSH(cp,offset+j));
il.append(new ALOAD(v.getIndex()));
il.append(factory.createInvoke(STR_LUAVALUE, "rawsetlist", Type.VOID, new Type[] { Type.INT, TYPE_VARARGS }, Constants.INVOKEVIRTUAL));
} else {

View File

@@ -26,7 +26,8 @@ import java.io.InputStream;
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
@@ -40,9 +41,12 @@ public class FragmentsTest extends TestCase {
String name = getName();
LuaTable _G = org.luaj.vm2.lib.JsePlatform.standardGlobals();
InputStream is = new ByteArrayInputStream(script.getBytes("UTF-8"));
String java = LuaJCompiler.compileToJava(is, name);
LuaValue chunk = LuaJCompiler.javaCompile(java, name);
chunk.setfenv(_G);
LuaValue chunk ;
if ( true ) {
chunk = JavaBytecodeCompiler.load(is,name,_G);
} else {
chunk = (new LuaC()).load( is, name, _G );
}
Varargs actual = chunk.invoke();
assertEquals( expected.narg(), actual.narg() );
for ( int i=1; i<=actual.narg(); i++ )
@@ -54,14 +58,69 @@ public class FragmentsTest extends TestCase {
}
}
public void testArgParam() {
// the name "arg" is treated specially, and ends up masking the argument value in 5.1
runFragment( LuaValue.NIL,
public void testVarVarargsUseArg() {
runFragment( LuaValue.varargsOf( new LuaValue[] {
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" +
" 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" +
"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() {
@@ -192,7 +251,7 @@ public class FragmentsTest extends TestCase {
public void testNoReturnValuesPlainCall() {
runFragment( LuaValue.TRUE,
"local testtable = {}\n"+
"return pcall( function() testtable[1]=2 end ) )\n" );
"return pcall( function() testtable[1]=2 end )\n" );
}
public void testVarargsInTableConstructor() {