Getting Started with LuaJ

James Roseborough, Ian Farmer, Version 2.0

Copyright © 2009-2010 Luaj.org. Freely available under the terms of the Luaj license.


introduction · examples · concepts · libraries · luaj api · building · downloads · release notes

1 - Introduction

Goals of Luaj

Luaj is a lua interpreter based on the 5.1.x version of lua with the following goals in mind:

Differences with 1.0

In addition to the basic goals of luaj, version 2.0 is aimed at improving on the 1.0 vm in the following aspects.

2 - Simple Examples

Run a lua script in Java SE

From the main distribution directory line type:

	java -cp lib/luaj-jse-2.0.jar lua examples/lua/hello.lua

You should see the following output:

	hello, world

Compile lua source to lua bytecode

From the main distribution directory line type:

	java -cp lib/luaj-jse-2.0.jar luac examples/lua/hello.lua
	java -cp lib/luaj-jse-2.0.jar lua luac.out

The compiled output "luac.out" is lua bytecode and should run and produce the same result.

Compile lua source to java source

Luaj can compile to lua source code to Java source code:

	java -cp lib/luaj-jse-2.0.jar lua2java -s examples/lua -d . hello.lua
	javac -cp lib/luaj-jse-2.0.jar hello.java
	java -cp "lib/luaj-jse-2.0.jar;." lua -l hello

The output hello.java is Java source, that implements the logic in hello.lua directly. Once hello.java is compiled into hello.class it can be required and used in place of the original lua script, but with better performance. There are no additional dependencies for compiling or running source-to-source compiled lua.

Compile lua bytecode to java bytecode

Luaj can compile lua sources or binaries directly to java bytecode if the bcel library is on the class path. From the main distribution directory line type:

	ant bcel-lib
	java -cp "lib/luaj-jse-2.0.jar;lib/bcel-5.2.jar" luajc -s examples/lua -d . hello.lua
	java -cp "lib/luaj-jse-2.0.jar;." lua -l hello

The output hello.class is Java bytecode, should run and produce the same result. There is no runtime dependency on the bcel library, but the compiled classes must be in the class path at runtime, unless runtime jit-compiling via luajc and bcel are desired (see later sections).



Run a script in a Java Application

The following pattern is used within Java SE

	import org.luaj.vm2.*;
	import org.luaj.vm2.lib.jse.*;

	String script = "examples/lua/hello.lua";
	LuaValue _G = JsePlatform.standardGlobals();
	_G.get("dofile").call( LuaValue.valueOf(script) );

A simple example may be found in

	examples/jse/SampleJseMain.java

You must include the library lib/luaj-jse-2.0.jar in your class path.

Run a script in a MIDlet

The for MIDlets the JmePlatform is used instead:

	import org.luaj.vm2.*;
	import org.luaj.vm2.lib.jme.*;

	String script = "examples/lua/hello.lua";
	LuaValue _G = JmePlatform.standardGlobals();
	_G.get("dofile").call( LuaValue.valueOf(script) );

The file must be a resource within within the midlet jar for dofile() to find it. Any files included via require() must also be part of the midlet resources.

A simple example may be found in

	examples/jme/SampleMIDlet.java

You must include the library lib/luaj-jme-2.0.jar in your midlet jar.

An ant script to build and run the midlet is in

	build-midlet.xml

You must install the wireless toolkit and define WTK_HOME for this script to work.

Run a script using JSR-233 Dynamic Scripting

The standard use of JSR-233 scripting engines may be used:

	ScriptEngineManager mgr = new ScriptEngineManager();
	ScriptEngine e = mgr.getEngineByExtension(".lua");
	e.put("x", 25);
	e.eval("y = math.sqrt(x)");
	System.out.println( "y="+e.get("y") );

All standard aspects of script engines including compiled statements should be supported.

You must include the library lib/luaj-jse-2.0.jar in your class path.

A working example may be found in

	examples/jse/ScriptEngineSample.java

Excluding the lua bytecode compiler

By default, the compiler is included whenever standardGlobals() or debugGlobals() are called. Without a compiler, files can still be executed, but they must be compiled elsewhere beforehand. The "luac" utility is provided in the jse jar for this purpose, or a standard lua compiler can be used.

To exclude the lua-to-lua-bytecode compiler, do not call standardGlobals() or debugGlobals() but instead initialize globals with including only those libraries that are needed and omitting the line:

	org.luaj.vm2.compiler.LuaC.install();

Including the lua-source-to-Java-source compiler

To compile from lua sources to Java sources for all lua loaded at runtime, install the Lua2Java compiler after globals have been created using:

	org.luaj.vm2.jse.lua2java.Lua2Java.install();
This uses the system Java compiler to compile from Java source to Java bytecode, and cannot compile lua binary files containing lua bytecode at runtime.

Including the lua-bytecode-to-Java-bytecode compiler

To compile from lua to Java bytecode for all lua loaded at runtime, install the LuaJC compiler after globals have been created using:

	org.luaj.vm2.jse.luajc.LuaJC.install();

This will compile all lua bytecode into Java bytecode, regardless of if they are loaded as lua source or lua binary files.

The bcel library must be on the class path for this to work.

3 - Concepts

Globals

The old notion of platform has been replaced with creation of globals. Two classes are provided to encapsulate common combinations of libraries.

JsePlatform

This class can be used as a factory for globals in a typical Java SE application. All standard libraries are included, as well as the luajava library. The default search path is the current directory, and the math operations include all those supported by Java SE.

JmePlatform

This class can be used to set up the basic environment for a Java ME application. The default search path is limited to the jar resources, and the math operations are limited to those supported by Java ME. All libraries are included except luajava, and the os, io, and math libraries are limited to those functions that can be supported on that platform.

4 - Libraries

Standard Libraries

Libraries are coded to closely match the behavior specified in See standard lua documentation for details on the library API's

The following libraries are loaded by both JsePlatform.standardGlobals() and JmePlatform.standardGlobals():

	base
	coroutine
	io
	math
	os
	package
	string
	table

The JsePlatform.standardGlobals() globals also include:

	luajava 

The JsePlatform.debugGlobals() and JsePlatform.debugGlobals() functions produce globals that include:

	debug

I/O Library

The implementation of the io library differs by platform owing to platform limitations.

The JmePlatform.standardGlobals() instantiated the io library io in

	src/jme/org/luaj/vm2/lib/jme/JmeIoLib.java
The JsePlatform.standardGlobals() includes support for random access and is in
	src/jse/org/luaj/vm2/lib/jse/JseIoLib.java

OS Library

The implementation of the os library also differs per platform.

The basic os library implementation us used by JmePlatform and is in:

	src/core/org/luaj/lib/OsLib.java
A richer version for use by JsePlatform is :
	src/jse/org/luaj/vm2/lib/jse/JseOsLib.java
Time is a represented as number of milliseconds since the epoch, and most time and date formatting, locales, and other features are not implemented.

Debug Library

The debug library is not included by default by JmePlatform.standardGlobals() or JsePlatform.standardGlobsls() . The functions JmePlatform.debugGlobals() and JsePlatform.debugGlobsls() create globals that contain the debug library in addition to the other standard libraries. To install dynamically from lua use java-class-based require::
	require 'org.luaj.vm2.lib.DebugLib'
The lua command line utility includes the debug library by default.

The Luajava Library

The JsePlatform.standardGlobals() includes the luajava library, which simplifies binding to Java classes and methods. It is patterned after the original luajava project.

The following lua script will open a swiing frame on Java SE:

	jframe = luajava.bindClass( "javax.swing.JFrame" )
	frame = luajava.newInstance( "javax.swing.JFrame", "Texts" );
	frame:setDefaultCloseOperation(jframe.EXIT_ON_CLOSE)
	frame:setSize(300,400)
	frame:setVisible(true)

See a longer sample in src/test/res/swingapp.lua for details, or try running it using:

	java -cp lib/luaj-jse-2.0.jar lua src/test/res/swingapp.lua

The Java ME platform does not include this library, and it cannot be made to work because of the lack of a reflection API in Java SE.

The lua connand line tool includes luajava.

5 - LuaJ API

API Javadoc

The distribution now contains javadoc for the main classes in the LuaJ API.
	 docs/api/index.html

LuaValue and Varargs

All lua value manipulation is now organized around LuaValue which exposes the majority of interfaces used for lua computation.
	 org.luaj.vm2.LuaValue

Common Functions

LuaValue exposes functions for each of the operations in LuaJ. Some commonly used functions and constants include:
	call();               // invoke the function with no arguments
	call(LuaValue arg1);  // call the function with 1 argument
	invoke(Varargs arg);  // call the function with variable arguments, variable return values
	get(int index);       // get a table entry using an integer key
	get(LuaValue key);    // get a table entry using an arbitrary key, may be a LuaInteger
	rawget(int index);    // raw get without metatable calls
	valueOf(int i);       // return LuaValue corresponding to an integer
	valueOf(String s);    // return LuaValue corresponding to a String
	toint();              // return value as a Java int
	tojstring();          // return value as a Java String
	isnil();              // is the value nil
	NIL;                  // the value nil
	NONE;                 // a Varargs instance with no values	 

Varargs

The interface Varargs provides an abstraction for both a variable argument list and multiple return values. For convenience, LuaValue implements Varargs so a single value can be supplied anywhere variable arguments are expected.
	 org.luaj.vm2.Varargs

Common Functions

Varargs exposes functions for accessing elements, and coercing them to specific types:
	narg();                 // return number of arguments
	arg1();                 // return the first argument
	arg(int n);             // return the nth argument
	isnil(int n);           // true if the nth argument is nil
	checktable(int n);      // return table or throw error
	optlong(int n,long d);  // return n if a long, d if no argument, or error if not a long
See the Varargs API for a complete list.

LibFunction

The simplest way to implement a function is to choose a base class based on the number of arguments to the function. LuaJ provides 5 base classes for this purpose, depending if the function has 0, 1, 2, 3 or variable arguments, and if it provide multiple return values.
	 org.luaj.vm2.lib.ZeroArgFunction
	 org.luaj.vm2.lib.OneArgFunction
	 org.luaj.vm2.lib.TwoArgFunction
	 org.luaj.vm2.lib.ThreeArgFunction
	 org.luaj.vm2.lib.VarArgFunction
Each of these functions has an abstract method that must be implemented, and argument fixup is done automatically by the classes as each Java function is invoked.

For example, to implement a "hello, world" function, we could supply:

	pubic class hello extends ZeroArgFunction {
		public LuaValue call() {
			env.get("print").call(valueOf("hello, world"));
		}
	}
The value env is the environment of the function, and is normally supplied by the instantiating object whenever default loading is used.

Calling this function from lua could be done by:

 
	require( 'hello' )()
while calling this function from Java would look like:
 
	new hello().call();
Note that in both the lua and Java case, extra arguments will be ignored, and the function will be called. Also, no virtual machine instance is necessary to call the function. To allow for arguments, or return multiple values, extend one of the other base classes.

Closures

Closures still exist in this framework, but are optional, and are only used to implement lua bytecode execution.

6 - Building and Testing

Building the jars

An ant file is included in the root directory which builds the libraries by default.

Other targets exist for creating distribution file an measuring code coverage of unit tests.

Unit tests

The main luaj JUnit tests are organized into a JUnit 3 suite:

	test/junit/org/luaj/vm2/AllTests.lua

Unit test scripts can be found in these locations

	test/lua/*.lua
	test/junit/org/luaj/vm2/compiler/lua5.1-tests.zip
	test/junit/org/luaj/vm2/compiler/regressions.zip
	test/junit/org/luaj/vm2/vm1/luajvm1-tests.zip

Code coverage

A build script for running unit tests and producing code coverage statistics is in

	build-coverage.xml
It relies on the cobertura code coverage library.

7 - Downloads

Downloads and Project Pages

Downloads for version 1.0.3 are currently hosted on SourceForge. Downloads of built packages for 2.0 are not yet available. Sources are available via sourceforge.net
	SourceForge Luaj Project Page
	SourceForge Luaj Download Area

and LuaForge:

	LuaForge Luaj Project Page
	LuaForge Luaj Project Area

8 - Release Notes

Main Changes by Version

  2.0
  • Initial release of 2.0 version

Known Issues

  • debug code may not be completely removed by some obfuscators
  • tail calls are not tracked in debug information
  • using both version 1 and 2 libraries together in the same java vm has not been tested
  • module() and setfenv() only partially supported for lau2java or luajc compiled lua
  • values associated with weak keys may linger longer than expected