From 7b6381c352f2cac3ebef13819b0fcc7848fe20cf Mon Sep 17 00:00:00 2001 From: James Roseborough Date: Tue, 2 Oct 2012 07:00:17 +0000 Subject: [PATCH] Add ability to create runnable jar file from lua script with sample build file build-app.xml --- README.html | 1 + build-app.xml | 108 ++++++++++++++++++ src/core/org/luaj/vm2/LuaFunction.java | 8 -- src/core/org/luaj/vm2/LuaValue.java | 7 ++ src/core/org/luaj/vm2/lib/PackageLib.java | 3 + src/core/org/luaj/vm2/lib/VarArgFunction.java | 1 + src/jse/luajc.java | 11 +- src/jse/org/luaj/vm2/lib/jse/JsePlatform.java | 19 +++ src/jse/org/luaj/vm2/luajc/JavaBuilder.java | 28 ++++- src/jse/org/luaj/vm2/luajc/JavaGen.java | 10 +- src/jse/org/luaj/vm2/luajc/JavaLoader.java | 2 +- src/jse/org/luaj/vm2/luajc/LuaJC.java | 4 +- test/java/org/luaj/luajc/TestLuaJC.java | 2 +- 13 files changed, 182 insertions(+), 22 deletions(-) create mode 100644 build-app.xml diff --git a/README.html b/README.html index fe74cff1..6a7b1b5f 100644 --- a/README.html +++ b/README.html @@ -732,6 +732,7 @@ and LuaForge:
  • Add line and column info to org.luaj.vm2.ast parse tree elements generated using LuaParser
  • Drop support for lua source to java surce (lua2java) in favor of direct java bytecode output (luajc)
  • Remove compatibility functions like table.getn(), table.maxn(), table.foreach(), and math.log10()
  • +
  • Add ability to create runnable jar file from lua script with sample build file build-app.xml
  • diff --git a/build-app.xml b/build-app.xml new file mode 100644 index 00000000..a3985c9d --- /dev/null +++ b/build-app.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + ------ @{cmd} + + + + + + + + + + + + + =========== @{srcdir}/@{luaprog} ============= + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/core/org/luaj/vm2/LuaFunction.java b/src/core/org/luaj/vm2/LuaFunction.java index 3e7d86a9..b0278adf 100644 --- a/src/core/org/luaj/vm2/LuaFunction.java +++ b/src/core/org/luaj/vm2/LuaFunction.java @@ -62,14 +62,6 @@ public class LuaFunction extends LuaValue { return s_metatable; } - /** Hook for implementations such as LuaJC to load the environment of the main chunk - * into the first upvalue location. If the function has no upvalues or is not a main chunk, - * calling this will be no effect. - * @param env The environment to load into the first upvalue, if there is one. - */ - public void initupvalue1(LuaValue env) { - } - public String tojstring() { return "function: " + classnamestub(); } diff --git a/src/core/org/luaj/vm2/LuaValue.java b/src/core/org/luaj/vm2/LuaValue.java index 376a97e7..a11edb69 100644 --- a/src/core/org/luaj/vm2/LuaValue.java +++ b/src/core/org/luaj/vm2/LuaValue.java @@ -3524,6 +3524,13 @@ public class LuaValue extends Varargs { return invoke(args); } + /** Hook for implementations such as LuaJC to load the environment of the main chunk + * into the first upvalue location. If the function has no upvalues or is not a main chunk, + * calling this will be no effect. + * @param env The environment to load into the first upvalue, if there is one. + */ + public void initupvalue1(LuaValue env) {} + /** Varargs implemenation with no values. *

    * This is an internal class not intended to be used directly. diff --git a/src/core/org/luaj/vm2/lib/PackageLib.java b/src/core/org/luaj/vm2/lib/PackageLib.java index 1755df36..6b1b299d 100644 --- a/src/core/org/luaj/vm2/lib/PackageLib.java +++ b/src/core/org/luaj/vm2/lib/PackageLib.java @@ -24,6 +24,7 @@ package org.luaj.vm2.lib; import java.io.InputStream; import org.luaj.vm2.Globals; +import org.luaj.vm2.LuaFunction; import org.luaj.vm2.LuaString; import org.luaj.vm2.LuaTable; import org.luaj.vm2.LuaValue; @@ -306,6 +307,8 @@ public class PackageLib extends OneArgFunction { try { c = Class.forName(classname); v = (LuaValue) c.newInstance(); + if (v.isfunction()) + ((LuaFunction)v).initupvalue1(globals); return v; } catch ( ClassNotFoundException cnfe ) { return valueOf("\n\tno class '"+classname+"'" ); diff --git a/src/core/org/luaj/vm2/lib/VarArgFunction.java b/src/core/org/luaj/vm2/lib/VarArgFunction.java index 60e98424..f529376a 100644 --- a/src/core/org/luaj/vm2/lib/VarArgFunction.java +++ b/src/core/org/luaj/vm2/lib/VarArgFunction.java @@ -46,6 +46,7 @@ import org.luaj.vm2.Varargs; * @see ThreeArgFunction */ abstract public class VarArgFunction extends LibFunction { + public VarArgFunction() { } diff --git a/src/jse/luajc.java b/src/jse/luajc.java index 0d238274..5252af42 100644 --- a/src/jse/luajc.java +++ b/src/jse/luajc.java @@ -37,7 +37,7 @@ import org.luaj.vm2.luajc.LuaJC; * Compiler for lua files to compile lua sources or lua binaries into java classes. */ public class luajc { - private static final String version = Lua._VERSION + "Copyright (C) 2009 luaj.org"; + private static final String version = Lua._VERSION + " Copyright (C) 2012 luaj.org"; private static final String usage = "usage: java -cp luaj-jse.jar,bcel-5.2.jar luajc [options] fileordir [, fileordir ...]\n" + @@ -46,6 +46,7 @@ public class luajc { " -s src source directory\n" + " -d dir destination directory\n" + " -p pkg package prefix to apply to all classes\n" + + " -m generate main(String[]) function for JSE\n" + " -r recursively compile all\n" + " -l load classes to verify generated bytecode\n" + " -v verbose\n"; @@ -57,6 +58,7 @@ public class luajc { private String srcdir = null; private String destdir = null; + private boolean genmain = false; private boolean recurse = false; private boolean verbose = false; private boolean loadclasses = false; @@ -96,6 +98,9 @@ public class luajc { usageExit(); pkgprefix = args[i]; break; + case 'm': + genmain = true; + break; case 'r': recurse = true; break; @@ -113,7 +118,7 @@ public class luajc { if ( verbose ) { System.out.println(version); System.out.println("srcdir: "+srcdir); - System.out.println("destdir: "+srcdir); + System.out.println("destdir: "+destdir); System.out.println("files: "+seeds); System.out.println("recurse: "+recurse); } @@ -192,7 +197,7 @@ public class luajc { // create the chunk FileInputStream fis = new FileInputStream( inf.infile ); - final Hashtable t = LuaJC.getInstance().compileAll(fis, inf.luachunkname, inf.srcfilename); + final Hashtable t = LuaJC.getInstance().compileAll(fis, inf.luachunkname, inf.srcfilename, genmain); fis.close(); // write out the chunk diff --git a/src/jse/org/luaj/vm2/lib/jse/JsePlatform.java b/src/jse/org/luaj/vm2/lib/jse/JsePlatform.java index f346ef9d..12ecbd74 100644 --- a/src/jse/org/luaj/vm2/lib/jse/JsePlatform.java +++ b/src/jse/org/luaj/vm2/lib/jse/JsePlatform.java @@ -25,6 +25,7 @@ import org.luaj.vm2.Globals; import org.luaj.vm2.LuaTable; import org.luaj.vm2.LuaThread; import org.luaj.vm2.LuaValue; +import org.luaj.vm2.Varargs; import org.luaj.vm2.compiler.LuaC; import org.luaj.vm2.lib.Bit32Lib; import org.luaj.vm2.lib.CoroutineLib; @@ -120,4 +121,22 @@ public class JsePlatform { _G.load(new DebugLib()); return _G; } + + + /** Simple wrapper for invoking a lua function with command line arguments. + * The supplied function is first given a new Globals object, + * then the program is run with arguments. + */ + public static void luaMain(LuaValue mainChunk, String[] args) { + Globals g = standardGlobals(); + int n = args.length; + LuaValue[] vargs = new LuaValue[args.length]; + for (int i = 0; i < n; ++i) + vargs[i] = LuaValue.valueOf(args[i]); + LuaTable arg = LuaValue.listOf(vargs); + arg.set("n", n); + g.set("arg", arg); + mainChunk.initupvalue1(g); + mainChunk.invoke(LuaValue.varargsOf(vargs)); + } } diff --git a/src/jse/org/luaj/vm2/luajc/JavaBuilder.java b/src/jse/org/luaj/vm2/luajc/JavaBuilder.java index 1cbd4b01..cd6cf132 100644 --- a/src/jse/org/luaj/vm2/luajc/JavaBuilder.java +++ b/src/jse/org/luaj/vm2/luajc/JavaBuilder.java @@ -77,6 +77,7 @@ public class JavaBuilder { 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 String STR_JSEPLATFORM = "org.luaj.vm2.lib.jse.JsePlatform"; private static final ObjectType TYPE_VARARGS = new ObjectType(STR_VARARGS); private static final ObjectType TYPE_LUAVALUE = new ObjectType(STR_LUAVALUE); @@ -86,10 +87,11 @@ public class JavaBuilder { 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 ObjectType TYPE_STRING = new ObjectType(STR_STRING); 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 ArrayType TYPE_LUAVALUEARRAY = new ArrayType( TYPE_LUAVALUE, 1 ); + private static final ArrayType TYPE_STRINGARRAY = new ArrayType( TYPE_STRING, 1 ); private static final String STR_FUNCV = VarArgFunction.class.getName(); @@ -116,6 +118,8 @@ public class JavaBuilder { private static final Type[] ARG_TYPES_INT_INT = { Type.INT, Type.INT }; private static final Type[] ARG_TYPES_LUAVALUE = { TYPE_LUAVALUE }; private static final Type[] ARG_TYPES_BUFFER = { TYPE_BUFFER }; + private static final Type[] ARG_TYPES_STRINGARRAY = { TYPE_STRINGARRAY }; + private static final Type[] ARG_TYPES_LUAVALUE_STRINGARRAY = { TYPE_LUAVALUE, TYPE_STRINGARRAY }; // names, arg types for main prototype classes private static final String[] SUPER_NAME_N = { STR_FUNC0, STR_FUNC1, STR_FUNC2, STR_FUNC3, STR_FUNCV, }; @@ -257,7 +261,7 @@ public class JavaBuilder { } } - public byte[] completeClass() { + public byte[] completeClass(boolean genmain) { // add class initializer if ( ! init.isEmpty() ) { @@ -303,6 +307,26 @@ public class JavaBuilder { main.dispose(); } + // add main function so class is invokable from the java command line + if (genmain) { + MethodGen mg = new MethodGen( Constants.ACC_PUBLIC | Constants.ACC_STATIC, // access flags + Type.VOID, // return type + ARG_TYPES_STRINGARRAY, // argument types + new String[] { "arg" }, // arg names + "main", + classname, // method, defining class + main, cp); + append(factory.createNew(classname)); + append(InstructionConstants.DUP); + append(factory.createInvoke(classname, Constants.CONSTRUCTOR_NAME, Type.VOID, ARG_TYPES_NONE, Constants.INVOKESPECIAL)); + append(new ALOAD(0)); + append(factory.createInvoke(STR_JSEPLATFORM, "luaMain", Type.VOID, ARG_TYPES_LUAVALUE_STRINGARRAY, Constants.INVOKESTATIC)); + append(InstructionConstants.RETURN); + mg.setMaxStack(); + cg.addMethod(mg.getMethod()); + main.dispose(); + } + // convert to class bytes try { diff --git a/src/jse/org/luaj/vm2/luajc/JavaGen.java b/src/jse/org/luaj/vm2/luajc/JavaGen.java index ab493348..4e2d2bd6 100644 --- a/src/jse/org/luaj/vm2/luajc/JavaGen.java +++ b/src/jse/org/luaj/vm2/luajc/JavaGen.java @@ -37,11 +37,11 @@ public class JavaGen { public final byte[] bytecode; public final JavaGen[] inners; - public JavaGen( Prototype p, String classname, String filename ) { - this( new ProtoInfo(p,classname), classname, filename ); + public JavaGen( Prototype p, String classname, String filename, boolean genmain ) { + this( new ProtoInfo(p,classname), classname, filename, genmain ); } - private JavaGen( ProtoInfo pi, String classname, String filename ) { + private JavaGen( ProtoInfo pi, String classname, String filename, boolean genmain ) { this.classname = classname; // build this class @@ -51,14 +51,14 @@ public class JavaGen { LocVars l = pi.prototype.locvars[i]; builder.setVarStartEnd(i, l.startpc, l.endpc, l.varname.tojstring()); } - this.bytecode = builder.completeClass(); + this.bytecode = builder.completeClass(genmain); // build sub-prototypes if ( pi.subprotos != null ) { int n = pi.subprotos.length; inners = new JavaGen[n]; for ( int i=0; i