diff --git a/README.html b/README.html index 6b480d73..0e25e618 100644 --- a/README.html +++ b/README.html @@ -16,7 +16,7 @@ Getting Started with LuaJ -James Roseborough, Ian Farmer, Version 3.0-alpha1 +James Roseborough, Ian Farmer, Version 3.0-alpha2
Copyright © 2009-2012 Luaj.org.
@@ -117,7 +117,7 @@ in comparison with the standard C distribution.
@@ -195,7 +195,7 @@ You should see the following output:
To see how luaj can be used to acccess most Java API's including swing, try:
@@ -219,8 +219,8 @@ Luaj can compile lua sources or binaries directly to java bytecode if the bcel l
@@ -231,7 +231,7 @@ but the compiled classes must be in the class path at runtime, unless runtime ji
Lua scripts can also be run directly in this mode without precompiling using the lua command with the -b option and providing the bcel library in the class path:
-You must include the library lib/luaj-jse-3.0-alpha1.jar in your class path.
+You must include the library lib/luaj-jse-3.0-alpha2.jar in your class path.
-You must include the library lib/luaj-jme-3.0-alpha1.jar in your midlet jar.
+You must include the library lib/luaj-jme-3.0-alpha2.jar in your midlet jar.
An ant script to build and run the midlet is in
@@ -311,7 +311,7 @@ The standard use of JSR-223 scripting engines may be used:
All standard aspects of script engines including compiled statements should be supported.
-You must include the library lib/luaj-jse-3.0-alpha1.jar in your class path.
+You must include the library lib/luaj-jse-3.0-alpha2.jar in your class path.
A working example may be found in
@@ -323,7 +323,7 @@ To compile and run it using Java 1.6 or higher:
@@ -574,11 +574,11 @@ 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:
+An example of a function with no arguments but a useful return value might be:
Calling this function from lua could be done by:
+If luaj can find a class that meets these critera, it will instantiate it, cast it to LuaFunction
+then call() the instance with two arguments:
+the modname used in the call to require(), and the environment for that function.
+The Java may use these values however it wishes. A typical case is to create named functions
+in the environment that can be called from lua.
+
+
+A complete example of Java code for a simple toy library is in examples/jse/hyperbolic.java
+
+The lua script used to load and test it is in examples/lua/hyperbolicapp.lua
+
+See the org.luaj.vm2.LuaClosure
+javadoc for details on using that class directly.
* For example, the following code will implement a library called "hyperbolic"
* with two functions, "sinh", and "cosh":
- *
* To test it, a script such as this can be used:
*
* See the source code in any of the library functions
- * such as {@link BaseLib} or {@link TableLib} for specific examples.
+ * such as {@link BaseLib} or {@link TableLib} for other examples.
*/
abstract public class LibFunction extends LuaFunction {
diff --git a/src/core/org/luaj/vm2/lib/PackageLib.java b/src/core/org/luaj/vm2/lib/PackageLib.java
index 6b1b299d..4e50ac94 100644
--- a/src/core/org/luaj/vm2/lib/PackageLib.java
+++ b/src/core/org/luaj/vm2/lib/PackageLib.java
@@ -148,28 +148,29 @@ public class PackageLib extends OneArgFunction {
/**
* require (modname)
*
- * Loads the given module. The function starts by looking into the package.loaded table to
- * determine whether modname is already loaded. If it is, then require returns the value
+ * Loads the given module. The function starts by looking into the package.loaded table
+ * to determine whether modname is already loaded. If it is, then require returns the value
* stored at package.loaded[modname]. Otherwise, it tries to find a loader for the module.
*
- * To find a loader, require is guided by the package.loaders array. By changing this array,
- * we can change how require looks for a module. The following explanation is based on the
- * default configuration for package.loaders.
- *
+ * To find a loader, require is guided by the package.searchers sequence.
+ * By changing this sequence, we can change how require looks for a module.
+ * The following explanation is based on the default configuration for package.searchers.
+ *
* First require queries package.preload[modname]. If it has a value, this value
- * (which should be a function) is the loader. Otherwise require searches for a Lua loader
- * using the path stored in package.path. If that also fails, it searches for a C loader
- * using the path stored in package.cpath. If that also fails, it tries an all-in-one loader
- * (see package.loaders).
+ * (which should be a function) is the loader. Otherwise require searches for a Lua loader using
+ * the path stored in package.path. If that also fails, it searches for a Java loader using
+ * the classpath, using the public default constructor, and casting the instance to LuaFunction.
*
- * Once a loader is found, require calls the loader with a single argument, modname.
- * If the loader returns any value, require assigns the returned value to package.loaded[modname].
- * If the loader returns no value and has not assigned any value to package.loaded[modname],
- * then require assigns true to this entry. In any case, require returns the final value of
- * package.loaded[modname].
- *
- * If there is any error loading or running the module, or if it cannot find any loader for
- * the module, then require signals an error.
+ * Once a loader is found, require calls the loader with two arguments: modname and an extra value
+ * dependent on how it got the loader. If the loader came from a file, this extra value is the file name.
+ * If the loader is a Java instance of LuaFunction, this extra value is the environment.
+ * If the loader returns any non-nil value, require assigns the returned value to package.loaded[modname].
+ * If the loader does not return a non-nil value and has not assigned any value to package.loaded[modname],
+ * then require assigns true to this entry.
+ * In any case, require returns the final value of package.loaded[modname].
+ *
+ * If there is any error loading or running the module, or if it cannot find any loader for the module,
+ * then require raises an error.
*/
public class require extends OneArgFunction {
public LuaValue call( LuaValue arg ) {
@@ -184,24 +185,24 @@ public class PackageLib extends OneArgFunction {
/* else must load it; iterate over available loaders */
LuaTable tbl = PackageLib.this.searchers.checktable();
StringBuffer sb = new StringBuffer();
- LuaValue chunk = null;
+ Varargs loader = null;
for ( int i=1; true; i++ ) {
- LuaValue loader = tbl.get(i);
- if ( loader.isnil() ) {
+ LuaValue searcher = tbl.get(i);
+ if ( searcher.isnil() ) {
error( "module '"+name+"' not found: "+name+sb );
}
/* call loader with module name as argument */
- chunk = loader.call(name);
- if ( chunk.isfunction() )
+ loader = searcher.invoke(name);
+ if ( loader.isfunction(1) )
break;
- if ( chunk.isstring() )
- sb.append( chunk.tojstring() );
+ if ( loader.isstring(1) )
+ sb.append( loader.tojstring(1) );
}
// load the module using the loader
loaded.set(name, _SENTINEL);
- result = chunk.call(name);
+ result = loader.arg1().call(name, loader.arg(2));
if ( ! result.isnil() )
loaded.set( name, result );
else if ( (result = PackageLib.this.loaded.get(name)) == _SENTINEL )
@@ -309,7 +310,7 @@ public class PackageLib extends OneArgFunction {
v = (LuaValue) c.newInstance();
if (v.isfunction())
((LuaFunction)v).initupvalue1(globals);
- return v;
+ return varargsOf(v, globals);
} catch ( ClassNotFoundException cnfe ) {
return valueOf("\n\tno class '"+classname+"'" );
} catch ( Exception e ) {
diff --git a/version.properties b/version.properties
index 634a0024..b9b99bf4 100644
--- a/version.properties
+++ b/version.properties
@@ -1 +1 @@
-version: 3.0-alpha1
\ No newline at end of file
+version: 3.0-alpha2
\ No newline at end of file
16.794
11.274
Java
- java -cp luaj-jse-3.0-alpha1.jar;bcel-5.2.jar lua -b fannkuch.lua 10
+ java -cp luaj-jse-3.0-alpha2.jar;bcel-5.2.jar lua -b fannkuch.lua 10
+
@@ -127,7 +127,7 @@ in comparison with the standard C distribution.
36.894
15.163
- java -cp luaj-jse-3.0-alpha1.jar lua -n fannkuch.lua 10 java -cp luaj-jse-3.0-alpha2.jar lua -n fannkuch.lua 10
lua
5.1.4
@@ -183,7 +183,7 @@ It is also faster than Java-lua implementations Jill, Kahlua, and Mochalua for a
From the main distribution directory line type:
- java -cp lib/luaj-jse-3.0-alpha1.jar lua examples/lua/hello.lua
+ java -cp lib/luaj-jse-3.0-alpha2.jar lua examples/lua/hello.lua
- java -cp lib/luaj-jse-3.0-alpha1.jar lua examples/lua/swingapp.lua
+ java -cp lib/luaj-jse-3.0-alpha2.jar lua examples/lua/swingapp.lua
Compile lua source to lua bytecode
@@ -204,8 +204,8 @@ To see how luaj can be used to acccess most Java API's including swing, try:
From the main distribution directory line type:
- java -cp lib/luaj-jse-3.0-alpha1.jar luac examples/lua/hello.lua
- java -cp lib/luaj-jse-3.0-alpha1.jar lua luac.out
+ java -cp lib/luaj-jse-3.0-alpha2.jar luac examples/lua/hello.lua
+ java -cp lib/luaj-jse-3.0-alpha2.jar lua luac.out
ant bcel-lib
- java -cp "lib/luaj-jse-3.0-alpha1.jar;lib/bcel-5.2.jar" luajc -s examples/lua -d . hello.lua
- java -cp "lib/luaj-jse-3.0-alpha1.jar;." lua -l hello
+ java -cp "lib/luaj-jse-3.0-alpha2.jar;lib/bcel-5.2.jar" luajc -s examples/lua -d . hello.lua
+ java -cp "lib/luaj-jse-3.0-alpha2.jar;." lua -l hello
- java -cp "lib/luaj-jse-3.0-alpha1.jar;lib/bcel-5.2.jar" lua -b examples/lua/hello.lua
+ java -cp "lib/luaj-jse-3.0-alpha2.jar;lib/bcel-5.2.jar" lua -b examples/lua/hello.lua
@@ -256,7 +256,7 @@ A simple example may be found in
Run a script in a MIDlet
@@ -283,7 +283,7 @@ A simple example may be found in
javac examples/jse/ScriptEngineSample.java
- java -cp "lib/luaj-jse-3.0-alpha1.jar;examples/jse" ScriptEngineSample
+ java -cp "lib/luaj-jse-3.0-alpha2.jar;examples/jse" ScriptEngineSample
Excluding the lua bytecode compiler
@@ -487,7 +487,7 @@ The following lua script will open a swing frame on Java SE:
See a longer sample in examples/lua/swingapp.lua for details, including a simple animation loop, rendering graphics, mouse and key handling, and image loading.
Or try running it using:
- java -cp lib/luaj-jse-3.0-alpha1.jar lua examples/lua/swingapp.lua
+ java -cp lib/luaj-jse-3.0-alpha2.jar lua examples/lua/swingapp.lua
- pubic class hello extends ZeroArgFunction {
+ pubic class hostname extends ZeroArgFunction {
public LuaValue call() {
- env.get("print").call(valueOf("hello, world"));
+ return valueOf(java.net.InetAddress.getLocalHost().getHostName());
}
}
@@ -589,20 +589,90 @@ by the instantiating object whenever default loading is used.
- require( 'hello' )()
+ local hostname = require( 'hostname' )
while calling this function from Java would look like:
- new hello().call();
+ new hostname().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.
+
+Libraries of Java Functions
+When require() is called, it will first attempt to load the module as a Java class that implements LuaFunction.
+To succeed, the following requirements must be met:
+
+
+
+
+import org.luaj.vm2.LuaValue;
+import org.luaj.vm2.lib.*;
+
+public class hyperbolic extends TwoArgFunction {
+
+ public hyperbolic() {}
+
+ public LuaValue call(LuaValue modname, LuaValue env) {
+ LuaValue library = tableOf();
+ library.set( "sinh", new sinh() );
+ library.set( "cosh", new cosh() );
+ env.set( "hyperbolic", library );
+ return library;
+ }
+
+ static class sinh extends OneArgFunction {
+ public LuaValue call(LuaValue x) {
+ return LuaValue.valueOf(Math.sinh(x.checkdouble()));
+ }
+ }
+
+ static class cosh extends OneArgFunction {
+ public LuaValue call(LuaValue x) {
+ return LuaValue.valueOf(Math.cosh(x.checkdouble()));
+ }
+ }
+}
+
+
+In this case the call to require invokes the library itself to initialize it. The library implementation
+puts entries into a table, and stores this table in the environment.
+
+
+ require 'hyperbolic'
+
+ print('hyperbolic', hyperbolic)
+ print('hyperbolic.sinh', hyperbolic.sinh)
+ print('hyperbolic.cosh', hyperbolic.cosh)
+
+ print('sinh(0.5)', hyperbolic.sinh(0.5))
+ print('cosh(0.5)', hyperbolic.cosh(0.5))
+
+
+For this example to work the code in hyperbolic.java must be compiled and put on the class path.
Closures
-Closures still exist in this framework, but are optional, and are only used to implement lua bytecode execution.
+Closures still exist in this framework, but are optional, and are only used to implement lua bytecode execution,
+and is generally not directly manipulated by the user of luaj.
+6 - Parser
@@ -712,11 +782,13 @@ and LuaForge:
+
2.0
+
2.0.1
2.0.2
3.0-alpha1
+
+
2.0.3
diff --git a/examples/jse/hyperbolic.java b/examples/jse/hyperbolic.java
new file mode 100644
index 00000000..d637e98a
--- /dev/null
+++ b/examples/jse/hyperbolic.java
@@ -0,0 +1,65 @@
+import org.luaj.vm2.LuaValue;
+import org.luaj.vm2.lib.OneArgFunction;
+import org.luaj.vm2.lib.TwoArgFunction;
+
+/**
+ * Sample library that can be called via luaj's require() implementation.
+ *
+ * This library, when loaded, creates a lua package called "hyperbolic"
+ * which has two functions, "sinh()" and "cosh()".
+ *
+ * Because the class is in the default Java package, it can be called using
+ * lua code such as:
+ *
+ 3.0-alpha1
+
3.0-alpha2
+
{@code
+ * require 'hyperbolic'
+ * print('sinh', hyperbolic.sinh)
+ * print('sinh(1.0)', hyperbolic.sinh(1.0))
+ * }
+ *
+ * When require() loads the code, two things happen: 1) the public constructor
+ * is called to construct a library instance, and 2) the instance is invoked
+ * as a java call with no arguments. This invocation should be used to initialize
+ * the library, and add any values to globals that are desired.
+ */
+public class hyperbolic extends TwoArgFunction {
+
+ /** Public constructor. To be loaded via require(), the library class
+ * must have a public constructor.
+ */
+ public hyperbolic() {}
+
+ /** The implementation of the TwoArgFunction interface.
+ * This will be called once when the library is loaded via require().
+ * @param modname LuaString containing the name used in the call to require().
+ * @param env LuaValue containing the environment for this function.
+ * @return Value that will be returned in the require() call. In this case,
+ * it is the library itself.
+ */
+ public LuaValue call(LuaValue modname, LuaValue env) {
+ LuaValue library = tableOf();
+ library.set( "sinh", new sinh() );
+ library.set( "cosh", new cosh() );
+ env.set( "hyperbolic", library );
+ return library;
+ }
+
+ /* Each library function is coded as a specific LibFunction based on the
+ * arguments it expects and returns. By using OneArgFunction, rather than
+ * LibFunction directly, the number of arguments supplied will be coerced
+ * to match what the implementation expects. */
+
+ /** Mathematical sinh function provided as a OneArgFunction. */
+ static class sinh extends OneArgFunction {
+ public LuaValue call(LuaValue x) {
+ return LuaValue.valueOf(Math.sinh(x.checkdouble()));
+ }
+ }
+
+ /** Mathematical cosh function provided as a OneArgFunction. */
+ static class cosh extends OneArgFunction {
+ public LuaValue call(LuaValue x) {
+ return LuaValue.valueOf(Math.cosh(x.checkdouble()));
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/lua/hyperbolicapp.lua b/examples/lua/hyperbolicapp.lua
new file mode 100644
index 00000000..ea10389a
--- /dev/null
+++ b/examples/lua/hyperbolicapp.lua
@@ -0,0 +1,19 @@
+-- Sample luaj code to try loading and executing the 'hyperbolic' sample library
+--
+-- The sample library source is in examples/jse/hyperbolic.java.
+-- For this sample to work, that source must be compiled, and the class must
+-- be on the class path.
+--
+-- First load the library via require(). This will call the public constructor
+-- for the class named 'hyperbolic' if it exists, and then initialize the
+-- library by invoking LuaValue.call('hyperbolic') on that instance
+require 'hyperbolic'
+
+-- Test that the table is in the globals, and the functions exist.
+print('hyperbolic', hyperbolic)
+print('hyperbolic.sinh', hyperbolic.sinh)
+print('hyperbolic.cosh', hyperbolic.cosh)
+
+-- Try exercising the functions.
+print('sinh(0.5)', hyperbolic.sinh(0.5))
+print('cosh(0.5)', hyperbolic.cosh(0.5))
diff --git a/src/core/org/luaj/vm2/lib/LibFunction.java b/src/core/org/luaj/vm2/lib/LibFunction.java
index a1d26aaa..1585285b 100644
--- a/src/core/org/luaj/vm2/lib/LibFunction.java
+++ b/src/core/org/luaj/vm2/lib/LibFunction.java
@@ -57,40 +57,43 @@ import org.luaj.vm2.Varargs;
* {@code
+
+ * The default constructor is used to instantiate the library
+ * in response to {@code require 'hyperbolic'} statement,
+ * provided it is on Java"s class path.
+ * This instance is then invoked with 2 arguments: the name supplied to require(),
+ * and the environment for this function. The library may ignore these, or use
+ * them to leave side effects in the global environment, for example.
+ * In the previous example, two functions are created, 'sinh', and 'cosh', and placed
+ * into a global table called 'hyperbolic' using the supplied 'env' argument.
* {@code
* import org.luaj.vm2.LuaValue;
- * public class hyperbolic extends org.luaj.vm2.lib.OneArgFunction {
- * public hyperbolic() {}
- * public LuaValue call(LuaValue arg) {
- * switch ( opcode ) {
- * case 0: {
- * LuaValue t = tableOf();
- * this.bind(t, hyperbolic.class, new String[] { "sinh", "cosh" }, 1 );
- * env.set("hyperbolic", t);
- * return t;
- * }
- * case 1: return valueOf(Math.sinh(arg.todouble()));
- * case 2: return valueOf(Math.cosh(arg.todouble()));
- * default: return error("bad opcode: "+opcode);
- * }
- * }
- * }
- * }
- * The default constructor is both to instantiate the library
- * in response to {@code require 'hyperbolic'} statement,
- * provided it is on Javas class path,
- * and to instantiate copies of the {@code hyperbolic}
- * class when initializing library instances. .
- * The instance returned by the default constructor will be invoked
- * as part of library loading.
- * In response, it creates two more instances, one for each library function,
- * in the body of the {@code switch} statement {@code case 0}
- * via the {@link #bind(LuaValue, Class, String[], int)} utility method.
- * It also registers the table in the globals via the {@link #env}
- * local variable, which should be the global environment unless
- * it has been changed.
- * {@code case 1} and {@code case 2} will be called when {@code hyperbolic.sinh}
- * {@code hyperbolic.sinh} and {@code hyperbolic.cosh} are invoked.
+ * import org.luaj.vm2.lib.*;
+ *
+ * public class hyperbolic extends TwoArgFunction {
+ *
+ * public hyperbolic() {}
+ *
+ * public LuaValue call(LuaValue modname, LuaValue env) {
+ * LuaValue library = tableOf();
+ * library.set( "sinh", new sinh() );
+ * library.set( "cosh", new cosh() );
+ * env.set( "hyperbolic", library );
+ * return library;
+ * }
+ *
+ * static class sinh extends OneArgFunction {
+ * public LuaValue call(LuaValue x) {
+ * return LuaValue.valueOf(Math.sinh(x.checkdouble()));
+ * }
+ * }
+ *
+ * static class cosh extends OneArgFunction {
+ * public LuaValue call(LuaValue x) {
+ * return LuaValue.valueOf(Math.cosh(x.checkdouble()));
+ * }
+ * }
+ *}
+ *} {@code
@@ -108,14 +111,14 @@ import org.luaj.vm2.Varargs;
* {@code
* t table: 3dbbd23f
* hyperbolic table: 3dbbd23f
- * k,v cosh cosh
- * k,v sinh sinh
+ * k,v cosh function: 3dbbd128
+ * k,v sinh function: 3dbbd242
* sinh(.5) 0.5210953
* cosh(.5) 1.127626
* }
*