├── jnlua
├── native
│ ├── Win32-x64
│ │ ├── javavm.dll
│ │ └── jnlua52.dll
│ └── Win32-x86
│ │ ├── javavm.dll
│ │ └── jnlua52.dll
├── src
│ ├── main
│ │ ├── resources
│ │ │ └── META-INF
│ │ │ │ └── services
│ │ │ │ └── javax.script.ScriptEngineFactory
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── naef
│ │ │ │ └── jnlua
│ │ │ │ ├── console
│ │ │ │ ├── package.html
│ │ │ │ └── LuaConsole.java
│ │ │ │ ├── util
│ │ │ │ ├── package.html
│ │ │ │ ├── AbstractTableList.java
│ │ │ │ └── AbstractTableMap.java
│ │ │ │ ├── script
│ │ │ │ ├── package.html
│ │ │ │ ├── CompiledLuaScript.java
│ │ │ │ ├── LuaBindings.java
│ │ │ │ ├── LuaScriptEngineFactory.java
│ │ │ │ └── LuaScriptEngine.java
│ │ │ │ ├── package.html
│ │ │ │ ├── NamedJavaFunction.java
│ │ │ │ ├── LuaValueProxy.java
│ │ │ │ ├── JavaFunction.java
│ │ │ │ ├── LuaSyntaxException.java
│ │ │ │ ├── LuaMemoryAllocationException.java
│ │ │ │ ├── LuaMessageHandlerException.java
│ │ │ │ ├── LuaType.java
│ │ │ │ ├── LuaGcMetamethodException.java
│ │ │ │ ├── LuaException.java
│ │ │ │ ├── LuaError.java
│ │ │ │ ├── TypedJavaObject.java
│ │ │ │ ├── Converter.java
│ │ │ │ ├── NativeSupport.java
│ │ │ │ ├── JavaReflector.java
│ │ │ │ ├── LuaRuntimeException.java
│ │ │ │ ├── LuaStackTraceElement.java
│ │ │ │ ├── DefaultConverter.java
│ │ │ │ └── JavaModule.java
│ │ ├── c
│ │ │ ├── javavm.h
│ │ │ ├── MacOSX
│ │ │ │ └── Makefile
│ │ │ ├── Linux
│ │ │ │ └── Makefile
│ │ │ ├── Win32
│ │ │ │ └── Makefile
│ │ │ └── javavm.c
│ │ └── assembly
│ │ │ └── native.xml
│ └── test
│ │ ├── java
│ │ └── com
│ │ │ └── naef
│ │ │ └── jnlua
│ │ │ └── test
│ │ │ ├── JavaReflectionTest.java
│ │ │ ├── LuaConsoleTest.java
│ │ │ ├── JavaFunctionTest.java
│ │ │ ├── JavaModuleTest.java
│ │ │ ├── AbstractLuaTest.java
│ │ │ ├── CollectionTest.java
│ │ │ ├── fixture
│ │ │ └── TestObject.java
│ │ │ ├── LuaExceptionTest.java
│ │ │ ├── LuaScriptEngineTest.java
│ │ │ └── LuaStateErrorTest.java
│ │ └── resources
│ │ └── com
│ │ └── naef
│ │ └── jnlua
│ │ └── test
│ │ ├── Reflection.lua
│ │ └── JavaModule.lua
├── .settings
│ ├── org.eclipse.m2e.core.prefs
│ ├── org.eclipse.ltk.core.refactoring.prefs
│ ├── org.eclipse.pde.core.prefs
│ ├── org.eclipse.jdt.core.prefs
│ └── org.maven.ide.eclipse.prefs
├── .classpath
├── .project
└── pom.xml
├── LICENSE.txt
├── README.md
└── CHANGES.md
/jnlua/native/Win32-x64/javavm.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antag99/jnlua/HEAD/jnlua/native/Win32-x64/javavm.dll
--------------------------------------------------------------------------------
/jnlua/native/Win32-x64/jnlua52.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antag99/jnlua/HEAD/jnlua/native/Win32-x64/jnlua52.dll
--------------------------------------------------------------------------------
/jnlua/native/Win32-x86/javavm.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antag99/jnlua/HEAD/jnlua/native/Win32-x86/javavm.dll
--------------------------------------------------------------------------------
/jnlua/native/Win32-x86/jnlua52.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antag99/jnlua/HEAD/jnlua/native/Win32-x86/jnlua52.dll
--------------------------------------------------------------------------------
/jnlua/src/main/resources/META-INF/services/javax.script.ScriptEngineFactory:
--------------------------------------------------------------------------------
1 | # List of script engine factories in this JAR
2 | com.naef.jnlua.script.LuaScriptEngineFactory
--------------------------------------------------------------------------------
/jnlua/.settings/org.eclipse.m2e.core.prefs:
--------------------------------------------------------------------------------
1 | #Mon Jan 02 21:14:51 CET 2012
2 | activeProfiles=
3 | eclipse.preferences.version=1
4 | resolveWorkspaceProjects=true
5 | version=1
6 |
--------------------------------------------------------------------------------
/jnlua/.settings/org.eclipse.ltk.core.refactoring.prefs:
--------------------------------------------------------------------------------
1 | #Sat Feb 20 14:18:59 CET 2010
2 | eclipse.preferences.version=1
3 | org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false
4 |
--------------------------------------------------------------------------------
/jnlua/.settings/org.eclipse.pde.core.prefs:
--------------------------------------------------------------------------------
1 | #Sat Feb 20 19:46:39 CET 2010
2 | eclipse.preferences.version=1
3 | pluginProject.equinox=false
4 | pluginProject.extensions=false
5 | selfhosting.binExcludes=/jnlua/target/test-classes,/jnlua/target/test-classes
6 |
--------------------------------------------------------------------------------
/jnlua/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | #Sat Feb 20 18:56:33 CET 2010
2 | eclipse.preferences.version=1
3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
4 | org.eclipse.jdt.core.compiler.compliance=1.6
5 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
6 | org.eclipse.jdt.core.compiler.source=1.6
7 |
--------------------------------------------------------------------------------
/jnlua/src/main/java/com/naef/jnlua/console/package.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Provides the JNLua console.
7 |
8 |
9 |
--------------------------------------------------------------------------------
/jnlua/src/main/java/com/naef/jnlua/util/package.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Provides the JNLua utility classes.
7 |
8 |
9 |
--------------------------------------------------------------------------------
/jnlua/.settings/org.maven.ide.eclipse.prefs:
--------------------------------------------------------------------------------
1 | #Sat Feb 20 13:40:37 CET 2010
2 | activeProfiles=
3 | eclipse.preferences.version=1
4 | fullBuildGoals=process-test-resources
5 | includeModules=false
6 | resolveWorkspaceProjects=true
7 | resourceFilterGoals=process-resources resources\:testResources
8 | skipCompilerPlugin=true
9 | version=1
10 |
--------------------------------------------------------------------------------
/jnlua/src/main/java/com/naef/jnlua/script/package.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Provides the JNLua provider for JSR 223: Scripting for the Java platform.
7 |
8 |
9 |
--------------------------------------------------------------------------------
/jnlua/src/main/java/com/naef/jnlua/package.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Provides the JNLua core types, such as the Lua state class and the core interfaces.
7 |
8 |
9 |
--------------------------------------------------------------------------------
/jnlua/src/main/java/com/naef/jnlua/NamedJavaFunction.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua;
7 |
8 | /**
9 | * Provides a named Java function.
10 | */
11 | public interface NamedJavaFunction extends JavaFunction {
12 | /**
13 | * Returns the name of this Java function.
14 | *
15 | * @return the Java function name
16 | */
17 | public String getName();
18 | }
19 |
--------------------------------------------------------------------------------
/jnlua/src/main/c/javavm.h:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * Provides the Java VM module. See LICENSE.txt for license terms.
4 | */
5 |
6 | #ifndef JNLUA_JAVAVM_INCLUDED
7 | #define JNLUA_JAVAVM_INCLUDED
8 |
9 | #include
10 |
11 | /**
12 | * Opens the Java VM module in a Lua state.
13 | *
14 | * @param L the Lua state
15 | * @return the number of results
16 | */
17 | LUALIB_API int luaopen_javavm (lua_State *L);
18 |
19 | #endif /* JNLUA_JAVAVM_INCLUDED */
20 |
--------------------------------------------------------------------------------
/jnlua/src/test/java/com/naef/jnlua/test/JavaReflectionTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua.test;
7 |
8 | import org.junit.Test;
9 |
10 | /**
11 | * Contains unit tests for Java reflection.
12 | */
13 | public class JavaReflectionTest extends AbstractLuaTest {
14 | // -- Test cases
15 | /**
16 | * Tests Java reflection from Lua.
17 | */
18 | @Test
19 | public void testReflection() throws Exception {
20 | runTest("com/naef/jnlua/test/Reflection.lua", "Reflection");
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/jnlua/src/main/c/MacOSX/Makefile:
--------------------------------------------------------------------------------
1 | # Paths
2 | JDK_DIR=/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0
3 | LUA_LIB_DIR=/usr/lib
4 | LUA_INC_DIR=/usr/include/lua
5 | VERSION=5.1
6 |
7 | # Tools
8 | CC=gcc
9 | LD=gcc
10 |
11 | # Default arguments
12 | CFLAGS=-c -fno-strict-aliasing -m64 -fPIC -O2 -Wall -DNDEBUG -D_REENTRANT -DLUA_USE_LINUX
13 | LDFLAGS=-dynamiclib -m64
14 |
15 | # Description blocks
16 | all: libjnlua$(VERSION).jnilib
17 |
18 | libjnlua$(VERSION).jnilib: jnlua.o
19 | $(LD) $(LDFLAGS) -o libjnlua$(VERSION).jnilib -L$(LUA_LIB_DIR) -lc -llua$(VERSION) jnlua.o
20 |
21 | jnlua.o: ../jnlua.c
22 | $(CC) $(CFLAGS) -I$(JDK_DIR)/Headers -I$(LUA_INC_DIR) ../jnlua.c
23 |
24 | clean:
25 | -rm libjnlua$(VERSION).jnilib jnlua.o
26 |
--------------------------------------------------------------------------------
/jnlua/src/main/java/com/naef/jnlua/LuaValueProxy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua;
7 |
8 | /**
9 | * Provides proxy access to a Lua value from Java. Lua value proxies are
10 | * acquired by invoking one of the getProxy() methods on the Lua
11 | * state.
12 | *
13 | * @see LuaState#getProxy(int)
14 | * @see LuaState#getProxy(int, Class)
15 | * @see LuaState#getProxy(int, Class[])
16 | */
17 | public interface LuaValueProxy {
18 | /**
19 | * Returns the Lua state of this proxy.
20 | *
21 | * @return the Lua state
22 | */
23 | public LuaState getLuaState();
24 |
25 | /**
26 | * Pushes the proxied Lua value on the stack of the Lua state.
27 | */
28 | public void pushValue();
29 | }
30 |
--------------------------------------------------------------------------------
/jnlua/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/jnlua/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | jnlua
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 | org.maven.ide.eclipse.maven2Builder
15 |
16 |
17 |
18 |
19 | org.eclipse.m2e.core.maven2Builder
20 |
21 |
22 |
23 |
24 |
25 | org.eclipse.m2e.core.maven2Nature
26 | org.eclipse.jdt.core.javanature
27 | org.maven.ide.eclipse.maven2Nature
28 |
29 |
30 |
--------------------------------------------------------------------------------
/jnlua/src/main/java/com/naef/jnlua/JavaFunction.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua;
7 |
8 | /**
9 | * Provides a Lua function implemented in Java.
10 | */
11 | public interface JavaFunction {
12 | /**
13 | * Invokes this Java function. The function arguments are on the stack. The
14 | * method returns the number of values on the stack which constitute the
15 | * return values of this function.
16 | *
17 | *
18 | * Java functions should indicate application errors by returning
19 | * appropriate error codes to the caller. Programming errors should be
20 | * indicated by throwing a runtime exception.
21 | *
22 | *
23 | * @param luaState
24 | * the Lua state this function has been invoked on
25 | * @return the number of return values
26 | */
27 | public int invoke(LuaState luaState);
28 | }
29 |
--------------------------------------------------------------------------------
/jnlua/src/main/assembly/native.xml:
--------------------------------------------------------------------------------
1 |
6 | native
7 |
8 | zip
9 |
10 |
11 |
12 | ${project.basedir}
13 |
14 | README*
15 | LICENSE*
16 | NOTICE*
17 |
18 | true
19 | /
20 |
21 |
22 | ${project.basedir}/native
23 | true
24 | /
25 |
26 |
27 |
--------------------------------------------------------------------------------
/jnlua/src/main/java/com/naef/jnlua/LuaSyntaxException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua;
7 |
8 | /**
9 | * Indicates a Lua syntax error.
10 | *
11 | *
12 | * This exception is thrown if the syntax of a Lua chunk is incorrect.
13 | *
14 | */
15 | public class LuaSyntaxException extends LuaException {
16 | // -- Static
17 | private static final long serialVersionUID = 1L;
18 |
19 | // -- Construction
20 | /**
21 | * Creates a new instance.
22 | *
23 | * @param msg
24 | * the message
25 | */
26 | public LuaSyntaxException(String msg) {
27 | super(msg);
28 | }
29 |
30 | /**
31 | * Creates a new instance.
32 | *
33 | * @param msg
34 | * the message
35 | * @param cause
36 | * the cause of this exception
37 | */
38 | public LuaSyntaxException(String msg, Throwable cause) {
39 | super(msg, cause);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/jnlua/src/main/java/com/naef/jnlua/LuaMemoryAllocationException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua;
7 |
8 | /**
9 | * Indicates a Lua memory allocation error.
10 | *
11 | *
12 | * The exception is thrown if the Lua memory allocator runs out of memory or if
13 | * a JNI allocation fails.
14 | *
15 | */
16 | public class LuaMemoryAllocationException extends LuaException {
17 | // -- Static
18 | private static final long serialVersionUID = 1L;
19 |
20 | // -- Construction
21 | /**
22 | * Creates a new instance.
23 | *
24 | * @param msg
25 | * the message
26 | */
27 | public LuaMemoryAllocationException(String msg) {
28 | super(msg);
29 | }
30 |
31 | /**
32 | * Creates a new instance.
33 | *
34 | * @param msg
35 | * the message
36 | * @param cause
37 | * the cause of this exception
38 | */
39 | public LuaMemoryAllocationException(String msg, Throwable cause) {
40 | super(msg, cause);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/jnlua/src/main/java/com/naef/jnlua/LuaMessageHandlerException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua;
7 |
8 | /**
9 | * Indicates a Lua message handler error.
10 | *
11 | *
12 | * This exception is thrown if an error occurs running the message handler of a
13 | * protected call.
14 | *
15 | *
16 | * @since JNLua 1.0.0
17 | */
18 | public class LuaMessageHandlerException extends LuaException {
19 | // -- Static
20 | private static final long serialVersionUID = 1L;
21 |
22 | // -- Construction
23 | /**
24 | * Creates a new instance.
25 | *
26 | * @param msg
27 | * the message
28 | */
29 | public LuaMessageHandlerException(String msg) {
30 | super(msg);
31 | }
32 |
33 | /**
34 | * Creates a new instance.
35 | *
36 | * @param msg
37 | * the message
38 | * @param cause
39 | * the cause of this exception
40 | */
41 | public LuaMessageHandlerException(String msg, Throwable cause) {
42 | super(msg, cause);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/jnlua/src/main/java/com/naef/jnlua/LuaType.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua;
7 |
8 | /**
9 | * Represents a Lua type.
10 | */
11 | public enum LuaType {
12 | // -- Values
13 | /**
14 | * Nil.
15 | */
16 | NIL,
17 |
18 | /**
19 | * Boolean.
20 | */
21 | BOOLEAN,
22 |
23 | /**
24 | * Light user data (pointer).
25 | */
26 | LIGHTUSERDATA,
27 |
28 | /**
29 | * Number.
30 | */
31 | NUMBER,
32 |
33 | /**
34 | * String.
35 | */
36 | STRING,
37 |
38 | /**
39 | * Table.
40 | */
41 | TABLE,
42 |
43 | /**
44 | * Function.
45 | */
46 | FUNCTION,
47 |
48 | /**
49 | * User data.
50 | */
51 | USERDATA,
52 |
53 | /**
54 | * Thread.
55 | */
56 | THREAD;
57 |
58 | // -- Properties
59 | /**
60 | * Returns the display text of this Lua type. The display text is the type
61 | * name in lower case.
62 | *
63 | * @return the display text
64 | */
65 | public String displayText() {
66 | return toString().toLowerCase();
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/jnlua/src/main/java/com/naef/jnlua/LuaGcMetamethodException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua;
7 |
8 | /**
9 | * Indicates a Lua garbage collection metamethod error.
10 | *
11 | *
12 | * This exception is thrown if an error occurs running a __gc
13 | * metamethod during garbage collection.
14 | *
15 | *
16 | * @since JNLua 1.0.0
17 | */
18 | public class LuaGcMetamethodException extends LuaException {
19 | // -- Static
20 | private static final long serialVersionUID = 1L;
21 |
22 | // -- Construction
23 | /**
24 | * Creates a new instance.
25 | *
26 | * @param msg
27 | * the message
28 | */
29 | public LuaGcMetamethodException(String msg) {
30 | super(msg);
31 | }
32 |
33 | /**
34 | * Creates a new instance.
35 | *
36 | * @param msg
37 | * the message
38 | * @param cause
39 | * the cause of this exception
40 | */
41 | public LuaGcMetamethodException(String msg, Throwable cause) {
42 | super(msg, cause);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/jnlua/src/main/c/Linux/Makefile:
--------------------------------------------------------------------------------
1 | # Paths
2 | JDK_DIR=/usr/lib/jvm/java-6-openjdk-i386
3 | LUA_LIB_DIR=/usr/lib
4 | LUA_INC_DIR=/usr/include/lua5.2
5 | LUA_VERSION=5.2
6 | VERSION=52
7 | ARCH=amd64
8 |
9 | # Tools
10 | CC=gcc
11 | LD=gcc
12 |
13 | # Default arguments
14 | CFLAGS=-c -fno-strict-aliasing -fPIC -O2 -Wall -DNDEBUG -D_REENTRANT -DLUA_USE_LINUX
15 | LDFLAGS=-shared
16 |
17 | # Description blocks
18 | all: libjnlua$(VERSION).so javavm.so
19 |
20 | libjnlua$(VERSION).so: jnlua.o
21 | $(LD) $(LDFLAGS) -Wl,-soname=libjnlua$(VERSION).so -olibjnlua$(VERSION).so -L$(LUA_LIB_DIR) jnlua.o -lc -llua$(LUA_VERSION)
22 |
23 | jnlua.o: ../jnlua.c
24 | $(CC) $(CFLAGS) -I$(JDK_DIR)/include -I$(JDK_DIR)/include/linux -I$(LUA_INC_DIR) ../jnlua.c
25 |
26 | javavm.so: javavm.o
27 | $(LD) $(LDFLAGS) -Wl,-soname=javavm.so -ojavavm.so -L$(LUA_LIB_DIR) -L$(JDK_DIR)/jre/lib/$(ARCH)/server javavm.o -llua$(LUA_VERSION) -ljvm
28 |
29 | javavm.o: ../javavm.c ../javavm.h
30 | $(CC) $(CFLAGS) -I$(JDK_DIR)/include -I$(JDK_DIR)/include/linux -I$(LUA_INC_DIR) ../javavm.c
31 |
32 | clean:
33 | -rm libjnlua$(VERSION).so jnlua.o
34 | -rm javavm.so javavm.o
35 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (C) 2008, 2012 Andre Naef
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/jnlua/src/main/java/com/naef/jnlua/LuaException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua;
7 |
8 | /**
9 | * Abstract base class for Lua error conditions. Lua exceptions are unchecked
10 | * runtime exceptions.
11 | */
12 | public abstract class LuaException extends RuntimeException {
13 | // -- Static
14 | private static final long serialVersionUID = 1L;
15 |
16 | // -- Construction
17 | /**
18 | * Creates a new instance.
19 | *
20 | * @param msg
21 | * the message
22 | */
23 | public LuaException(String msg) {
24 | super(msg);
25 | }
26 |
27 | /**
28 | * Creates a new instance.
29 | *
30 | * @param msg
31 | * the message
32 | * @param cause
33 | * the cause of this exception
34 | */
35 | public LuaException(String msg, Throwable cause) {
36 | super(msg, cause);
37 | }
38 |
39 | /**
40 | * Creates a new instance.
41 | *
42 | * @param cause
43 | * the cause of this exception
44 | */
45 | public LuaException(Throwable cause) {
46 | super(cause);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/jnlua/src/test/java/com/naef/jnlua/test/LuaConsoleTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id: AbstractLuaTest.java 38 2012-01-04 22:44:15Z andre@naef.com $
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua.test;
7 |
8 | import static org.junit.Assert.assertEquals;
9 | import static org.junit.Assert.assertNotNull;
10 | import static org.junit.Assert.assertTrue;
11 |
12 | import org.junit.Test;
13 |
14 | import com.naef.jnlua.LuaState;
15 | import com.naef.jnlua.console.LuaConsole;
16 |
17 | /**
18 | * Contains tests for the Lua console.
19 | */
20 | public class LuaConsoleTest {
21 | // -- Test cases
22 | /**
23 | * Tests the Lua console.
24 | */
25 | @Test
26 | public void testLuaConsole ()
27 | {
28 | LuaConsole luaConsole = new LuaConsole(new String[] { "a", "b" });
29 | LuaState luaState = luaConsole.getLuaState();
30 | assertNotNull(luaState);
31 | assertTrue(luaState.isOpen());
32 | luaState.getGlobal("argv");
33 | assertTrue(luaState.isTable(1));
34 | assertEquals(2, luaState.rawLen(1));
35 | luaState.rawGet(1, 1);
36 | assertTrue(luaState.isString(2));
37 | assertEquals("a", luaState.toString(2));
38 | luaState.pop(2);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/jnlua/src/main/c/Win32/Makefile:
--------------------------------------------------------------------------------
1 | # Paths
2 | JDK_DIR=C:\Program Files\Java\jdk1.6.0_19
3 | LUA_DIR=C:\Users\Public\Apps\Lua\5.2\lib64
4 | LUA_VERSION=52
5 | VERSION=52
6 |
7 | # Tools
8 | CC=cl
9 | LD=link
10 | MT=mt
11 |
12 | # Default arguments
13 | CFLAGS=/nologo /c /O2 /GL /W3 /DNDEBUG
14 | LDFLAGS=/nologo /DLL /LTCG
15 | MTFLAGS=-nologo
16 |
17 | # Description blocks
18 | all: jnlua$(VERSION).dll javavm.dll
19 |
20 | jnlua$(VERSION).dll: jnlua.obj
21 | $(LD) $(LDFLAGS) /OUT:jnlua$(VERSION).dll /LIBPATH:"$(LUA_DIR)" jnlua.obj lua$(LUA_VERSION).lib
22 |
23 | jnlua.obj: ..\jnlua.c
24 | $(CC) $(CFLAGS) /MD /DLUA_BUILD_AS_DLL /I"$(JDK_DIR)\include" /I"$(JDK_DIR)\include\win32" /I"$(LUA_DIR)\include" ..\jnlua.c
25 |
26 | javavm.dll: javavm.obj
27 | $(LD) $(LDFLAGS) /OUT:javavm.dll /LIBPATH:"$(LUA_DIR)" /LIBPATH:"$(JDK_DIR)\lib" javavm.obj lua$(LUA_VERSION).lib jvm.lib
28 |
29 | javavm.obj: ..\javavm.c ..\javavm.h
30 | $(CC) $(CFLAGS) /MD /DLUA_BUILD_AS_DLL /DLUA_LIB /I"$(JDK_DIR)\include" /I"$(JDK_DIR)\include\win32" /I"$(LUA_DIR)\include" ..\javavm.c
31 |
32 | clean:
33 | -del jnlua$(VERSION).dll jnlua$(VERSION).dll.manifest jnlua$(VERSION).exp jnlua$(VERSION).lib jnlua.obj
34 | -del javavm.dll javavm.dll.manifest javavm.exp javavm.lib javavm.obj
35 |
--------------------------------------------------------------------------------
/jnlua/src/main/java/com/naef/jnlua/script/CompiledLuaScript.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua.script;
7 |
8 | import java.io.ByteArrayInputStream;
9 |
10 | import javax.script.CompiledScript;
11 | import javax.script.ScriptContext;
12 | import javax.script.ScriptEngine;
13 | import javax.script.ScriptException;
14 |
15 | /**
16 | * Compiled script implementation conforming to JSR 223: Scripting for the Java
17 | * Platform.
18 | */
19 | class CompiledLuaScript extends CompiledScript {
20 | // -- State
21 | private LuaScriptEngine engine;
22 | private byte[] script;
23 |
24 | // -- Construction
25 | /**
26 | * Creates a new instance.
27 | */
28 | public CompiledLuaScript(LuaScriptEngine engine, byte[] script) {
29 | this.engine = engine;
30 | this.script = script;
31 | }
32 |
33 | // -- CompiledScript methods
34 | @Override
35 | public Object eval(ScriptContext context) throws ScriptException {
36 | synchronized (engine.getLuaState()) {
37 | engine.loadChunk(new ByteArrayInputStream(script), context, "b");
38 | return engine.callChunk(context);
39 | }
40 | }
41 |
42 | @Override
43 | public ScriptEngine getEngine() {
44 | return engine;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/jnlua/src/test/java/com/naef/jnlua/test/JavaFunctionTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua.test;
7 |
8 | import static org.junit.Assert.assertEquals;
9 |
10 | import org.junit.Test;
11 |
12 | import com.naef.jnlua.JavaFunction;
13 | import com.naef.jnlua.LuaState;
14 |
15 | /**
16 | * Contains unit tests for Java functions.
17 | */
18 | public class JavaFunctionTest extends AbstractLuaTest {
19 | // -- Test cases
20 | /**
21 | * Tests the call of a Lua function implemented in Java.
22 | */
23 | @Test
24 | public void testJavaFunction() throws Exception {
25 | // Push function
26 | luaState.pushJavaFunction(new Add());
27 |
28 | // Push arguments
29 | luaState.pushNumber(1);
30 | luaState.pushNumber(1);
31 | luaState.call(2, 1);
32 |
33 | // Test result
34 | assertEquals(2.0, luaState.toNumber(1), 0.0);
35 | luaState.pop(1);
36 |
37 | // Finish
38 | assertEquals(0, luaState.getTop());
39 | }
40 |
41 | // -- Private classes
42 | /**
43 | * A simple Lua function.
44 | */
45 | private static class Add implements JavaFunction {
46 | public int invoke(LuaState luaState) {
47 | double a = luaState.toNumber(1);
48 | double b = luaState.toNumber(2);
49 | luaState.setTop(0);
50 | luaState.pushNumber(a + b);
51 | return 1;
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/jnlua/src/test/java/com/naef/jnlua/test/JavaModuleTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua.test;
7 |
8 | import static org.junit.Assert.assertEquals;
9 |
10 | import java.util.ArrayList;
11 | import java.util.HashMap;
12 | import java.util.List;
13 | import java.util.Map;
14 |
15 | import org.junit.Test;
16 |
17 | import com.naef.jnlua.JavaModule;
18 |
19 | /**
20 | * Contains unit tests for the Java module.
21 | */
22 | public class JavaModuleTest extends AbstractLuaTest {
23 | // ---- Test cases
24 | /**
25 | * Tests the toTable method.
26 | */
27 | @Test
28 | public void testToTable() {
29 | // Map
30 | Map map = new HashMap();
31 | luaState.pushJavaObject(JavaModule.getInstance().toTable(map));
32 | luaState.setGlobal("map");
33 | luaState.load("map.x = 1", "=testToTable");
34 | luaState.call(0, 0);
35 | assertEquals(Double.valueOf(1.0), map.get("x"));
36 |
37 | // List
38 | List list = new ArrayList();
39 | luaState.pushJavaObject(JavaModule.getInstance().toTable(list));
40 | luaState.setGlobal("list");
41 | luaState.load("list[1] = 1", "=testToList");
42 | luaState.call(0, 0);
43 | assertEquals(Double.valueOf(1.0), list.get(0));
44 | }
45 |
46 | /**
47 | * Tests the Java module from Lua.
48 | */
49 | @Test
50 | public void testJavaModule() throws Exception {
51 | runTest("com/naef/jnlua/test/JavaModule.lua", "JavaModule");
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/jnlua/src/main/java/com/naef/jnlua/LuaError.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua;
7 |
8 | /**
9 | * Contains information about a Lua error condition. This object is created in
10 | * the native library.
11 | */
12 | class LuaError {
13 | // -- State
14 | private String message;
15 | private LuaStackTraceElement[] luaStackTrace;
16 | private Throwable cause;
17 |
18 | // -- Construction
19 | /**
20 | * Creates a new instance.
21 | */
22 | public LuaError(String message, Throwable cause) {
23 | this.message = message;
24 | this.cause = cause;
25 | }
26 |
27 | // -- Properties
28 | /**
29 | * Returns the message.
30 | */
31 | public String getMessage() {
32 | return message;
33 | }
34 |
35 | /**
36 | * Returns the Lua stack trace.
37 | */
38 | public LuaStackTraceElement[] getLuaStackTrace() {
39 | return luaStackTrace;
40 | }
41 |
42 | /**
43 | * Returns the cause.
44 | */
45 | public Throwable getCause() {
46 | return cause;
47 | }
48 |
49 | // -- Object methods
50 | @Override
51 | public String toString() {
52 | StringBuffer sb = new StringBuffer();
53 | if (message != null) {
54 | sb.append(message);
55 | }
56 | if (cause != null) {
57 | sb.append(cause);
58 | }
59 | return sb.toString();
60 | }
61 |
62 | // -- Package private methods
63 | /**
64 | * Sets the Lua stack trace.
65 | */
66 | void setLuaStackTrace(LuaStackTraceElement[] luaStackTrace) {
67 | this.luaStackTrace = luaStackTrace;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/jnlua/src/test/java/com/naef/jnlua/test/AbstractLuaTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua.test;
7 |
8 | import java.io.InputStream;
9 |
10 | import org.junit.After;
11 | import org.junit.Before;
12 |
13 | import com.naef.jnlua.LuaState;
14 |
15 | /**
16 | * Abstract base class for JNLua unit tests.
17 | */
18 | public abstract class AbstractLuaTest {
19 | // -- State
20 | protected LuaState luaState;
21 |
22 | // -- Setup
23 | /**
24 | * Performs setup.
25 | */
26 | @Before
27 | public void setup() throws Exception {
28 | luaState = new LuaState();
29 | }
30 |
31 | /**
32 | * Performs teardown.
33 | */
34 | @After
35 | public void teardown() throws Throwable {
36 | if (luaState != null) {
37 | try {
38 | luaState.close();
39 | } catch (Throwable e) {
40 | e.printStackTrace();
41 | throw e;
42 | }
43 | }
44 | }
45 |
46 | // -- Protected method
47 | /**
48 | * Runs a Lua-based test.
49 | */
50 | protected void runTest(String source, String moduleName) throws Exception {
51 | // Open libraries
52 | luaState.openLibs();
53 |
54 | // Load
55 | InputStream inputStream = getClass().getClassLoader()
56 | .getResourceAsStream(source);
57 | luaState.load(inputStream, "=" + moduleName, "t");
58 | luaState.pushString(moduleName);
59 | luaState.call(1, 0);
60 |
61 | // Run all module functions beginning with "test"
62 | luaState.getGlobal(moduleName);
63 | luaState.pushNil();
64 | while (luaState.next(1)) {
65 | String key = luaState.toString(-2);
66 | if (key.startsWith("test") && luaState.isFunction(-1)) {
67 | luaState.call(0, 0);
68 | } else {
69 | luaState.pop(1);
70 | }
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/jnlua/src/main/java/com/naef/jnlua/TypedJavaObject.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua;
7 |
8 | /**
9 | * Represents a Java object with an explicit type.
10 | *
11 | *
12 | * The interface is implemented by objects needing to specify an explicit type
13 | * for a wrapped object. This typically occurs in casting situations. Such typed
14 | * Java object are considered weak since they have no representative
15 | * value of their own. Weak typed Java objects always convert to wrapped object.
16 | *
17 | *
18 | *
19 | * The interface is also implemented by objects wrapping another object and
20 | * offering transparent conversion to the wrapped object if needed. This
21 | * situation for example occurs when an object implements the
22 | * {@link com.naef.jnlua.JavaReflector} interface to provide custom Java
23 | * reflection for a wrapped object and at the same time wants to ensure
24 | * transparent conversion to the wrapped object if needed. Such typed Java
25 | * objects are considered strong since they have a representative value
26 | * of their own. Strong typed Java objects convert to wrapped object only if
27 | * this is required to satisfy a type conversion.
28 | *
29 | */
30 | public interface TypedJavaObject {
31 | /**
32 | * Returns the object.
33 | *
34 | * @return the object
35 | */
36 | public Object getObject();
37 |
38 | /**
39 | * Returns the type.
40 | *
41 | * @return the type
42 | */
43 | public Class> getType();
44 |
45 | /**
46 | * Returns whether this is a strong typed Java object.
47 | *
48 | * @return true if this typed Java object is strong, and
49 | * false if it is weak
50 | */
51 | public boolean isStrong();
52 | }
53 |
--------------------------------------------------------------------------------
/jnlua/src/main/java/com/naef/jnlua/script/LuaBindings.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua.script;
7 |
8 | import javax.script.Bindings;
9 |
10 | import com.naef.jnlua.LuaState;
11 | import com.naef.jnlua.util.AbstractTableMap;
12 |
13 | /**
14 | * Lua bindings implementation conforming to JSR 223: Scripting for the Java
15 | * Platform.
16 | */
17 | class LuaBindings extends AbstractTableMap implements Bindings {
18 | // -- State
19 | private LuaScriptEngine scriptEngine;
20 |
21 | // -- Construction
22 | public LuaBindings(LuaScriptEngine scriptEngine) {
23 | this.scriptEngine = scriptEngine;
24 | }
25 |
26 | // -- AbstractTableMap methods
27 | @Override
28 | protected void checkKey(Object key) {
29 | super.checkKey(key);
30 | if (!(key instanceof String)) {
31 | throw new IllegalArgumentException("key must be a string");
32 | }
33 | if (((String) key).length() == 0) {
34 | throw new IllegalArgumentException("key must not be empty");
35 | }
36 | }
37 |
38 | @Override
39 | protected boolean filterKeys() {
40 | return true;
41 | }
42 |
43 | @Override
44 | protected boolean acceptKey(int index) {
45 | return getLuaState().isString(index)
46 | && getLuaState().toString(index).length() > 0;
47 | }
48 |
49 | @Override
50 | protected String convertKey(int index) {
51 | return getLuaState().toString(index);
52 | }
53 |
54 | // -- LuaProxy methods
55 | @Override
56 | public LuaState getLuaState() {
57 | return scriptEngine.getLuaState();
58 | }
59 |
60 | @Override
61 | public void pushValue() {
62 | getLuaState().rawGet(LuaState.REGISTRYINDEX, LuaState.RIDX_GLOBALS);
63 | }
64 |
65 | // -- Package-private methods
66 | /**
67 | * Returns the script engine.
68 | */
69 | LuaScriptEngine getScriptEngine() {
70 | return scriptEngine;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/jnlua/src/main/java/com/naef/jnlua/Converter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua;
7 |
8 | /**
9 | * Converts between Lua values and Java objects.
10 | */
11 | public interface Converter {
12 | /**
13 | * Returns the type distance between a Lua value and a formal Java type.
14 | * Distances are comparable for the same Lua value only. If a Lua value
15 | * cannot be converted to the specified formal type, the method returns
16 | * Integer.MAX_VALUE.
17 | *
18 | * @param luaState
19 | * the Lua state
20 | * @param index
21 | * the stack index containing the value
22 | * @param formalType
23 | * the formal Java type
24 | * @return the type distance, or Integer.MAX_VALUE if the
25 | * conversion is not supported
26 | */
27 | public int getTypeDistance(LuaState luaState, int index, Class> formalType);
28 |
29 | /**
30 | * Converts a Lua value to a Java object of the specified formal type.
31 | *
32 | *
33 | * If the Lua value is nil, the method returns
34 | * null.
35 | *
36 | *
37 | * @param luaState
38 | * the Lua state
39 | * @param index
40 | * the stack index containing the value
41 | * @return the Java object, or null
42 | * @param formalType
43 | * the formal Java type
44 | * @throws ClassCastException
45 | * if the conversion is not possible
46 | */
47 | public T convertLuaValue(LuaState luaState, int index,
48 | Class formalType);
49 |
50 | /**
51 | * Converts a Java object to a Lua value and pushes that value on the stack.
52 | *
53 | *
54 | * If the object is null, the method pushes nil.
55 | *
56 | *
57 | * @param luaState
58 | * the Lua state
59 | * @param object
60 | * the Java object, or null
61 | */
62 | public void convertJavaObject(LuaState luaState, Object object);
63 | }
64 |
--------------------------------------------------------------------------------
/jnlua/src/main/java/com/naef/jnlua/NativeSupport.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua;
7 |
8 | /**
9 | * Loads the JNLua native library.
10 | *
11 | * The class provides and configures a default loader implementation that loads
12 | * the JNLua native library by means of the System.loadLibrary
13 | * method. In some situations, you may want to override this behavior. For
14 | * example, when using JNLua as an OSGi bundle, the native library is loaded by
15 | * the OSGi runtime. Therefore, the OSGi bundle activator replaces the loader by
16 | * a no-op implementaion. Note that the loader must be configured before
17 | * LuaState is accessed.
18 | */
19 | public final class NativeSupport {
20 | // -- Static
21 | private static final NativeSupport INSTANCE = new NativeSupport();
22 |
23 | // -- State
24 | private Loader loader = new DefaultLoader();
25 |
26 | /**
27 | * Returns the instance.
28 | *
29 | * @return the instance
30 | */
31 | public static NativeSupport getInstance() {
32 | return INSTANCE;
33 | }
34 |
35 | // -- Construction
36 | /**
37 | * Private constructor to prevent external instantiation.
38 | */
39 | private NativeSupport() {
40 | }
41 |
42 | // -- Properties
43 | /**
44 | * Return the native library loader.
45 | *
46 | * @return the loader
47 | */
48 | public Loader getLoader() {
49 | return loader;
50 | }
51 |
52 | /**
53 | * Sets the native library loader.
54 | *
55 | * @param loader
56 | * the loader
57 | */
58 | public void setLoader(Loader loader) {
59 | if (loader == null) {
60 | throw new NullPointerException("loader must not be null");
61 | }
62 | this.loader = loader;
63 | }
64 |
65 | // -- Member types
66 | /**
67 | * Loads the library.
68 | */
69 | public interface Loader {
70 | public void load();
71 | }
72 |
73 | private class DefaultLoader implements Loader {
74 | @Override
75 | public void load() {
76 | System.loadLibrary("jnlua52");
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/jnlua/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 | com.naef
5 | jnlua
6 | 1.0.4
7 | jar
8 | JNLua
9 | Java Native Lua
10 | http://code.google.com/p/jnlua/
11 |
12 | scm:svn:http://jnlua.googlecode.com/svn/trunk/
13 | http://jnlua.googlecode.com/svn/trunk/
14 |
15 |
16 |
17 | MIT License
18 | /LICENSE.txt
19 | manual
20 |
21 |
22 |
23 | André Naef
24 | http://www.naef.com/
25 |
26 |
27 |
28 | junit
29 | junit
30 | 4.7
31 | jar
32 | test
33 |
34 |
35 |
36 |
37 |
38 | org.apache.maven.plugins
39 | maven-compiler-plugin
40 |
41 | 1.6
42 | 1.6
43 |
44 |
45 |
46 | org.apache.maven.plugins
47 | maven-surefire-plugin
48 |
49 |
50 | **/*Test.java
51 |
52 |
53 |
54 |
55 | org.apache.maven.plugins
56 | maven-javadoc-plugin
57 |
58 |
59 |
60 |
61 | org.apache.maven.plugins
62 | maven-assembly-plugin
63 |
64 |
65 | bin
66 | src
67 |
68 |
69 | src/main/assembly/native.xml
70 |
71 |
72 |
73 |
74 | make-assembly
75 | package
76 |
77 | single
78 |
79 |
80 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/jnlua/src/main/java/com/naef/jnlua/util/AbstractTableList.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua.util;
7 |
8 | import java.util.AbstractList;
9 | import java.util.RandomAccess;
10 |
11 | import com.naef.jnlua.LuaState;
12 | import com.naef.jnlua.LuaValueProxy;
13 |
14 | /**
15 | * Abstract list implementation backed by a Lua table.
16 | */
17 | public abstract class AbstractTableList extends AbstractList implements
18 | RandomAccess, LuaValueProxy {
19 | // -- Construction
20 | /**
21 | * Creates a new instance.
22 | */
23 | public AbstractTableList() {
24 | }
25 |
26 | // -- List methods
27 | @Override
28 | public void add(int index, Object element) {
29 | LuaState luaState = getLuaState();
30 | synchronized (luaState) {
31 | int size = size();
32 | if (index < 0 || index > size) {
33 | throw new IndexOutOfBoundsException("index: " + index
34 | + ", size: " + size);
35 | }
36 | pushValue();
37 | luaState.tableMove(-1, index + 1, index + 2, size - index);
38 | luaState.pushJavaObject(element);
39 | luaState.rawSet(-2, index + 1);
40 | luaState.pop(1);
41 | }
42 | }
43 |
44 | @Override
45 | public Object get(int index) {
46 | LuaState luaState = getLuaState();
47 | synchronized (luaState) {
48 | int size = size();
49 | if (index < 0 || index >= size) {
50 | throw new IndexOutOfBoundsException("index: " + index
51 | + ", size: " + size);
52 | }
53 | pushValue();
54 | luaState.rawGet(-1, index + 1);
55 | try {
56 | return luaState.toJavaObject(-1, Object.class);
57 | } finally {
58 | luaState.pop(2);
59 | }
60 | }
61 | }
62 |
63 | @Override
64 | public Object remove(int index) {
65 | LuaState luaState = getLuaState();
66 | synchronized (luaState) {
67 | int size = size();
68 | if (index < 0 || index >= size) {
69 | throw new IndexOutOfBoundsException("index: " + index
70 | + ", size: " + size);
71 | }
72 | Object oldValue = get(index);
73 | pushValue();
74 | luaState.tableMove(-1, index + 2, index + 1, size - index - 1);
75 | luaState.pushNil();
76 | luaState.rawSet(-2, size);
77 | luaState.pop(1);
78 | return oldValue;
79 | }
80 | }
81 |
82 | @Override
83 | public Object set(int index, Object element) {
84 | LuaState luaState = getLuaState();
85 | synchronized (luaState) {
86 | int size = size();
87 | if (index < 0 || index >= size) {
88 | throw new IndexOutOfBoundsException("index: " + index
89 | + ", size: " + size);
90 | }
91 | Object oldValue = get(index);
92 | pushValue();
93 | luaState.pushJavaObject(element);
94 | luaState.rawSet(-2, index + 1);
95 | luaState.pop(1);
96 | return oldValue;
97 | }
98 | }
99 |
100 | @Override
101 | public int size() {
102 | LuaState luaState = getLuaState();
103 | synchronized (luaState) {
104 | pushValue();
105 | try {
106 | return luaState.rawLen(-1);
107 | } finally {
108 | luaState.pop(1);
109 | }
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/jnlua/src/main/java/com/naef/jnlua/JavaReflector.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua;
7 |
8 | /**
9 | * Reflects Java objects for access from Lua.
10 | *
11 | *
12 | * The interface can be implemented to provide a generic Java reflector that is
13 | * then configured in a Lua state. It can also be implemented by individual Java
14 | * classes to provide class-specific Java reflection. If an object implements
15 | * the Java reflector interface, its own Java reflector is queried first for a
16 | * requested metamethod. Only if the metamethod requested is not supported, the
17 | * Java reflector configured in the Lua state is queried.
18 | *
19 | */
20 | public interface JavaReflector {
21 | /**
22 | * Returns the metamethod implementation of this Java reflector for the
23 | * specified metamethod. If this reflector does not support the metamethod,
24 | * the method returns null.
25 | *
26 | * @param metamethod
27 | * the metamethod
28 | * @return the implementation, or null if this Java reflector
29 | * does not support the metamethod
30 | */
31 | public JavaFunction getMetamethod(Metamethod metamethod);
32 |
33 | // -- Nested types
34 | /**
35 | * Lua metamethod.
36 | */
37 | public enum Metamethod {
38 | /**
39 | * __index metamethod.
40 | */
41 | INDEX,
42 |
43 | /**
44 | * __newindex metamethod.
45 | */
46 | NEWINDEX,
47 |
48 | /**
49 | * __len metamethod.
50 | */
51 | LEN,
52 |
53 | /**
54 | * __eq metamethod.
55 | */
56 | EQ,
57 |
58 | /**
59 | * __lt metamethod.
60 | */
61 | LT,
62 |
63 | /**
64 | * __le metamethod.
65 | */
66 | LE,
67 |
68 | /**
69 | * __unm metamethod.
70 | */
71 | UNM,
72 |
73 | /**
74 | * __add metamethod.
75 | */
76 | ADD,
77 |
78 | /**
79 | * __sub metamethod.
80 | */
81 | SUB,
82 |
83 | /**
84 | * __mul metamethod.
85 | */
86 | MUL,
87 |
88 | /**
89 | * __div metamethod.
90 | */
91 | DIV,
92 |
93 | /**
94 | * __mod metamethod.
95 | */
96 | MOD,
97 |
98 | /**
99 | * __pow metamethod.
100 | */
101 | POW,
102 |
103 | /**
104 | * __concat metamethod.
105 | */
106 | CONCAT,
107 |
108 | /**
109 | * __call metamethod.
110 | */
111 | CALL,
112 |
113 | /**
114 | * __tostring metamethod.
115 | */
116 | TOSTRING,
117 |
118 | /**
119 | * __pairs metamethod,
120 | */
121 | PAIRS,
122 |
123 | /**
124 | * __ipairs metamethod,
125 | */
126 | IPAIRS,
127 |
128 | /**
129 | * __javafields metamethod.
130 | */
131 | JAVAFIELDS,
132 |
133 | /**
134 | * __javamethods metamethod.
135 | */
136 | JAVAMETHODS,
137 |
138 | /**
139 | * __javaproperties metamethod.
140 | */
141 | JAVAPROPERTIES;
142 |
143 | // -- Operations
144 | /**
145 | * Returns the Lua metamethod name.
146 | *
147 | * @return the metamethod name
148 | */
149 | public String getMetamethodName() {
150 | return "__" + toString().toLowerCase();
151 | }
152 | };
153 | }
154 |
--------------------------------------------------------------------------------
/jnlua/src/main/java/com/naef/jnlua/LuaRuntimeException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua;
7 |
8 | import java.io.PrintStream;
9 | import java.io.PrintWriter;
10 |
11 | /**
12 | * Indicates a Lua runtime error.
13 | *
14 | *
15 | * This exception is thrown if a Lua runtime error occurs. The class provides
16 | * access to the Lua stack trace by means of the {@link #getLuaStackTrace()}
17 | * method.
18 | *
19 | */
20 | public class LuaRuntimeException extends LuaException {
21 | // -- Static
22 | private static final long serialVersionUID = 1L;
23 | private static final LuaStackTraceElement[] EMPTY_LUA_STACK_TRACE = new LuaStackTraceElement[0];
24 |
25 | // -- State
26 | private LuaStackTraceElement[] luaStackTrace;
27 |
28 | // -- Construction
29 | /**
30 | * Creates a new instance. The instance is created with an empty Lua stack
31 | * trace.
32 | *
33 | * @param msg
34 | * the message
35 | */
36 | public LuaRuntimeException(String msg) {
37 | super(msg);
38 | luaStackTrace = EMPTY_LUA_STACK_TRACE;
39 | }
40 |
41 | /**
42 | * Creates a new instance. The instance is created with an empty Lua stack
43 | * trace.
44 | *
45 | * @param msg
46 | * the message
47 | * @param cause
48 | * the cause of this exception
49 | */
50 | public LuaRuntimeException(String msg, Throwable cause) {
51 | super(msg, cause);
52 | luaStackTrace = EMPTY_LUA_STACK_TRACE;
53 | }
54 |
55 | /**
56 | * Creates a new instance. The instance is created with an empty Lua stack
57 | * trace.
58 | *
59 | * @param cause
60 | * the cause of this exception
61 | */
62 | public LuaRuntimeException(Throwable cause) {
63 | super(cause);
64 | luaStackTrace = EMPTY_LUA_STACK_TRACE;
65 | }
66 |
67 | // -- Properties
68 | /**
69 | * Returns the Lua stack trace of this runtime exception.
70 | */
71 | public LuaStackTraceElement[] getLuaStackTrace() {
72 | return luaStackTrace.clone();
73 | }
74 |
75 | // -- Operations
76 | /**
77 | * Prints this exception and its Lua stack trace to the standard error
78 | * stream.
79 | */
80 | public void printLuaStackTrace() {
81 | printLuaStackTrace(System.err);
82 | }
83 |
84 | /**
85 | * Prints this exception and its Lua stack trace to the specified print
86 | * stream.
87 | *
88 | * @param s
89 | * the print stream
90 | */
91 | public void printLuaStackTrace(PrintStream s) {
92 | synchronized (s) {
93 | s.println(this);
94 | for (int i = 0; i < luaStackTrace.length; i++) {
95 | s.println("\tat " + luaStackTrace[i]);
96 | }
97 | }
98 | }
99 |
100 | /**
101 | * Prints this exception and its Lua stack trace to the specified print
102 | * writer.
103 | *
104 | * @param s
105 | * the print writer
106 | */
107 | public void printLuaStackTrace(PrintWriter s) {
108 | synchronized (s) {
109 | s.println(this);
110 | for (int i = 0; i < luaStackTrace.length; i++) {
111 | s.println("\tat " + luaStackTrace[i]);
112 | }
113 | }
114 | }
115 |
116 | // -- Package private methods
117 | /**
118 | * Sets the Lua error in this exception. The method in invoked from the
119 | * native library.
120 | */
121 | void setLuaError(LuaError luaError) {
122 | initCause(luaError.getCause());
123 | luaStackTrace = luaError.getLuaStackTrace();
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/jnlua/src/main/java/com/naef/jnlua/LuaStackTraceElement.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua;
7 |
8 | /**
9 | * Represents an execution point in a Lua stack trace.
10 | */
11 | public class LuaStackTraceElement {
12 | // -- State
13 | private String functionName;
14 | private String sourceName;
15 | private int lineNumber;
16 |
17 | // -- Construction
18 | /**
19 | * Creates a new instance.
20 | *
21 | * @param sourceName
22 | * the source name, or null if unavailable
23 | * @param functionName
24 | * the function name, or null if unavailable
25 | * @param lineNumber
26 | * the line number, or a negative number if unavailable
27 | */
28 | public LuaStackTraceElement(String functionName, String sourceName,
29 | int lineNumber) {
30 | this.functionName = functionName;
31 | this.sourceName = sourceName;
32 | this.lineNumber = lineNumber;
33 | }
34 |
35 | // -- Properties
36 | /**
37 | * Returns the name of the function containing the execution point
38 | * represented by this stack trace element. If there is no function name for
39 | * the execution point, the method returns null.
40 | *
41 | * @return the name of the function containing the execution point
42 | * represented by this stack trace element, or null
43 | */
44 | public String getFunctionName() {
45 | return functionName;
46 | }
47 |
48 | /**
49 | * Returns the name of the source containing the execution point represented
50 | * by this this stack trace element. The source name is passed to the Lua
51 | * state when the Lua source code is loaded. If there is no source name for
52 | * the execution point, the method returns null.
53 | *
54 | * @return the source name, or null
55 | * @see LuaState#load(java.io.InputStream, String, String)
56 | * @see LuaState#load(String, String)
57 | */
58 | public String getSourceName() {
59 | return sourceName;
60 | }
61 |
62 | /**
63 | * Returns the line number in the source containing the execution point
64 | * represented by this stack trace element. If there is no line number for
65 | * the execution point, the method returns a negative number.
66 | *
67 | * @return the line number, or a negative number if there is no line number
68 | */
69 | public int getLineNumber() {
70 | return lineNumber;
71 | }
72 |
73 | // Object methods
74 | @Override
75 | public int hashCode() {
76 | int result = functionName != null ? functionName.hashCode() : 0;
77 | result = result * 65599 + sourceName != null ? sourceName.hashCode()
78 | : 0;
79 | result = result * 65599 + lineNumber;
80 | return result;
81 | }
82 |
83 | @Override
84 | public boolean equals(Object obj) {
85 | if (obj == this) {
86 | return true;
87 | }
88 | if (!(obj instanceof LuaStackTraceElement)) {
89 | return false;
90 | }
91 | LuaStackTraceElement other = (LuaStackTraceElement) obj;
92 | return safeEquals(functionName, other.functionName)
93 | && safeEquals(sourceName, other.sourceName)
94 | && lineNumber == other.lineNumber;
95 | }
96 |
97 | @Override
98 | public String toString() {
99 | StringBuffer sb = new StringBuffer();
100 | if (functionName != null) {
101 | sb.append(functionName);
102 | } else {
103 | sb.append("(Unknown Function)");
104 | }
105 | sb.append(" (");
106 | if (sourceName != null) {
107 | sb.append(sourceName);
108 | if (lineNumber >= 0) {
109 | sb.append(':');
110 | sb.append(lineNumber);
111 | }
112 | } else {
113 | sb.append("External Function");
114 | }
115 | sb.append(')');
116 | return sb.toString();
117 | }
118 |
119 | // -- Private methods
120 | /**
121 | * Returns whether two objects are equal, handling null.
122 | */
123 | private boolean safeEquals(Object a, Object b) {
124 | return a == b || a != null && a.equals(b);
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/jnlua/src/test/java/com/naef/jnlua/test/CollectionTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua.test;
7 |
8 | import static org.junit.Assert.assertEquals;
9 | import static org.junit.Assert.assertFalse;
10 | import static org.junit.Assert.assertNull;
11 | import static org.junit.Assert.assertTrue;
12 |
13 | import java.util.ArrayList;
14 | import java.util.HashMap;
15 | import java.util.Iterator;
16 | import java.util.List;
17 | import java.util.Map;
18 |
19 | import org.junit.Test;
20 |
21 | /**
22 | * Contains unit tests for collections backed by Lua tables.
23 | */
24 | public class CollectionTest extends AbstractLuaTest {
25 | // -- Test cases
26 | /**
27 | * Tests the map.
28 | */
29 | @SuppressWarnings("unchecked")
30 | @Test
31 | public void testMap() throws Exception {
32 | // Get a map backed by Lua
33 | luaState.newTable();
34 | Map map = luaState.toJavaObject(-1, Map.class);
35 |
36 | // isEmpty(), size()
37 | assertTrue(map.isEmpty());
38 | assertEquals(0, map.size());
39 |
40 | // put()
41 | map.put("t", "test");
42 | assertFalse(map.isEmpty());
43 | assertEquals(1, map.size());
44 | luaState.getField(-1, "t");
45 | assertEquals("test", luaState.toString(-1));
46 | luaState.pop(1);
47 |
48 | // containsKey()
49 | assertTrue(map.containsKey("t"));
50 |
51 | // containsValue()
52 | assertTrue(map.containsValue("test"));
53 |
54 | // get()
55 | assertEquals("test", map.get("t"));
56 |
57 | // putAll()
58 | Map map2 = new HashMap();
59 | map2.put("v", "test2");
60 | map.putAll(map2);
61 | assertEquals("test2", map.get("v"));
62 | luaState.getField(-1, "v");
63 | assertEquals("test2", luaState.toString(-1));
64 | luaState.pop(1);
65 |
66 | // remove()
67 | map.remove("v");
68 | assertNull(map.get("v"));
69 | luaState.getField(-1, "v");
70 | assertTrue(luaState.isNil(-1));
71 | luaState.pop(1);
72 |
73 | // entrySet()
74 | int count = 0;
75 | for (Map.Entry entry : map.entrySet()) {
76 | if (entry.getKey() != null) {
77 | count++;
78 | }
79 | }
80 | assertEquals(map.size(), count);
81 |
82 | // values()
83 | boolean found = false;
84 | for (Object object : map.values()) {
85 | if (object.equals("test")) {
86 | found = true;
87 | break;
88 | }
89 | }
90 | assertTrue(found);
91 |
92 | // keySet()
93 | assertTrue(map.keySet().contains("t"));
94 | Iterator iterator = map.keySet().iterator();
95 | while (iterator.hasNext()) {
96 | if (iterator.next().equals("t")) {
97 | iterator.remove();
98 | }
99 | }
100 | assertFalse(map.containsKey("t"));
101 |
102 | // clear()
103 | map.clear();
104 | assertEquals(0, map.size());
105 | assertTrue(map.isEmpty());
106 |
107 | // Finish
108 | luaState.pop(1);
109 | assertEquals(0, luaState.getTop());
110 | }
111 |
112 | /**
113 | * Tests the list.
114 | */
115 | @SuppressWarnings("unchecked")
116 | @Test
117 | public void testList() throws Exception {
118 | // Get a list backed by Lua
119 | luaState.newTable();
120 | List list = luaState.toJavaObject(-1, List.class);
121 |
122 | // isEmpty(), size()
123 | assertTrue(list.isEmpty());
124 | assertEquals(0, list.size());
125 |
126 | // add()
127 | list.add("test");
128 | assertFalse(list.isEmpty());
129 | assertEquals(1, list.size());
130 | luaState.rawGet(-1, 1);
131 | assertEquals("test", luaState.toString(-1));
132 | luaState.pop(1);
133 |
134 | // contains()
135 | assertTrue(list.contains("test"));
136 |
137 | // get()
138 | assertEquals("test", list.get(0));
139 |
140 | // addAll()
141 | List list2 = new ArrayList();
142 | list2.add("test2");
143 | list.addAll(0, list2);
144 | assertEquals("test2", list.get(0));
145 | luaState.rawGet(-1, 1);
146 | assertEquals("test2", luaState.toString(-1));
147 | luaState.pop(1);
148 |
149 | // remove()
150 | list.remove(0);
151 | assertEquals(1, list.size());
152 | assertEquals(1, luaState.rawLen(-1));
153 | luaState.rawGet(-1, 1);
154 | assertEquals("test", luaState.toString(-1));
155 | luaState.pop(1);
156 |
157 | // iterator()
158 | int count = 0;
159 | for (Object object : list) {
160 | assertEquals("test", object);
161 | count++;
162 | }
163 | assertEquals(list.size(), count);
164 |
165 | // clear()
166 | list.clear();
167 | assertEquals(0, list.size());
168 | assertTrue(list.isEmpty());
169 |
170 | // Finish
171 | luaState.pop(1);
172 | assertEquals(0, luaState.getTop());
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/jnlua/src/test/java/com/naef/jnlua/test/fixture/TestObject.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua.test.fixture;
7 |
8 | import java.math.BigDecimal;
9 | import java.math.BigInteger;
10 |
11 | /**
12 | * A test object for reflection testing.
13 | */
14 | public class TestObject implements Comparable {
15 | // -- Static
16 | /**
17 | * A public static field.
18 | */
19 | public static String TEST_FIELD = "test";
20 |
21 | /*
22 | * Public test fields for all types.
23 | */
24 | public boolean booleanField;
25 | public byte byteField;
26 | public byte[] byteArrayField;
27 | public short shortField;
28 | public int intField;
29 | public long longField;
30 | public float floatField;
31 | public double doubleField;
32 | public BigInteger bigIntegerField;
33 | public BigDecimal bigDecimalField;
34 | public char charField;
35 | public String stringField;
36 |
37 | /**
38 | * A private field.
39 | */
40 | private String foo;
41 |
42 | /**
43 | * The value of this object.
44 | */
45 | private int value;
46 |
47 | // -- Static methods
48 | /**
49 | * A public static method.
50 | */
51 | public static String testStatic() {
52 | return "test";
53 | }
54 |
55 | // -- State
56 | /**
57 | * A public field.
58 | */
59 | public String testField = "test";
60 |
61 | // -- Construction
62 | /**
63 | * Creates a new instance.
64 | */
65 | public TestObject() {
66 | }
67 |
68 | /**
69 | * Creates a new instance.
70 | */
71 | public TestObject(int value) {
72 | this.value = value;
73 | }
74 |
75 | // -- Methods
76 | /**
77 | * A public method.
78 | */
79 | public String test() {
80 | return "test";
81 | }
82 |
83 | // -- Properties
84 | /**
85 | * A property reader.
86 | */
87 | public String getFoo() {
88 | return foo;
89 | }
90 |
91 | /**
92 | * A property writer.
93 | */
94 | public void setFoo(String foo) {
95 | this.foo = foo;
96 | }
97 |
98 | /**
99 | * Returns the value of this object.
100 | */
101 | public int getValue() {
102 | return value;
103 | }
104 |
105 | /**
106 | * Sets the value of this object.
107 | */
108 | public void setValue(int value) {
109 | this.value = value;
110 | }
111 |
112 | // -- Overloaded methods
113 | /**
114 | * Overloaded method dispatch test method.
115 | */
116 | public String overloadedSub(TestObject testObject) {
117 | return "super";
118 | }
119 |
120 | /**
121 | * Overloaded method dispatch test method.
122 | */
123 | public String overloadedSub(Sub sub) {
124 | return "sub";
125 | }
126 |
127 | /**
128 | * Overloaded method dispatch test method.
129 | */
130 | public String overloadedSibling(B b) {
131 | return "b";
132 | }
133 |
134 | /**
135 | * Overloaded method dispatch test method.
136 | */
137 | public String overloadedSibling(C c) {
138 | return "c";
139 | }
140 |
141 | /**
142 | * Overloaded method dispatch test method.
143 | */
144 | public String overloadedParentChild(A a) {
145 | return "a";
146 | }
147 |
148 | /**
149 | * Overloaded method dispatch test method.
150 | */
151 | public String overloadedParentChild(B c) {
152 | return "b";
153 | }
154 |
155 | // -- Object methods
156 | @Override
157 | public int hashCode() {
158 | return value;
159 | }
160 |
161 | @Override
162 | public boolean equals(Object obj) {
163 | if (!(obj instanceof TestObject)) {
164 | return false;
165 | }
166 | TestObject other = (TestObject) obj;
167 | return value == other.value;
168 | }
169 |
170 | @Override
171 | public String toString() {
172 | return String.valueOf(value);
173 | }
174 |
175 | // -- Comparable methods
176 | @Override
177 | public int compareTo(TestObject o) {
178 | if (value < o.value) {
179 | return -1;
180 | }
181 | if (value > o.value) {
182 | return 1;
183 | }
184 | return 0;
185 | }
186 |
187 | // -- Nested classes
188 | /**
189 | * Subclass for method dispatch testing.
190 | */
191 | public static class Sub extends TestObject {
192 | }
193 |
194 | /**
195 | * Class for method dispatch testing.
196 | */
197 | public static class AB implements A, B {
198 | }
199 |
200 | /**
201 | * Class for method dispatch testing.
202 | */
203 | public static class AC implements A, C {
204 | }
205 |
206 | /**
207 | * Class for method dispatch testing.
208 | */
209 | public static class BC implements B, C {
210 | }
211 |
212 | // -- Nested interfaces
213 | /**
214 | * Overloaded method dispatch test interface.
215 | */
216 | public interface A {
217 | }
218 |
219 | /**
220 | * Overloaded method dispatch test interface.
221 | */
222 | public interface B extends A {
223 | }
224 |
225 | /**
226 | * Overloaded method dispatch test interface.
227 | */
228 | public interface C extends A {
229 | }
230 | }
231 |
--------------------------------------------------------------------------------
/jnlua/src/test/resources/com/naef/jnlua/test/Reflection.lua:
--------------------------------------------------------------------------------
1 | --[[
2 | $Id$
3 | See LICENSE.txt for license terms.
4 | ]]
5 |
6 | module(..., package.seeall)
7 |
8 | -- General reflection test
9 | function testReflection ()
10 | -- Static field
11 | local TestObject = java.require("com.naef.jnlua.test.fixture.TestObject")
12 | assert(TestObject.TEST_FIELD == "test")
13 | TestObject.TEST_FIELD = ""
14 | assert(TestObject.TEST_FIELD == "")
15 | TestObject.TEST_FIELD = "test"
16 |
17 | -- Static method
18 | assert(TestObject:testStatic() == "test")
19 |
20 | -- Field
21 | local testObject = TestObject:new()
22 | assert(testObject.testField == "test")
23 | testObject.testField = ""
24 | assert(testObject.testField == "")
25 |
26 | -- Method
27 | assert(testObject:test() == "test")
28 |
29 | -- Property
30 | assert(testObject.foo == nil)
31 | testObject.foo = "bar"
32 | assert(testObject.foo == "bar")
33 | end
34 |
35 | -- Type test
36 | function testTypes ()
37 | -- Create
38 | local TestObject = java.require("com.naef.jnlua.test.fixture.TestObject")
39 | local testObject = TestObject:new()
40 |
41 | -- Test
42 | testObject.booleanField = true
43 | assert(testObject.booleanField)
44 | testObject.byteField = 1
45 | assert(testObject.byteField == 1)
46 | testObject.byteArrayField = "test"
47 | assert(testObject.byteArrayField == "test")
48 | testObject.shortField = 1
49 | assert(testObject.shortField == 1)
50 | testObject.intField = 1
51 | assert(testObject.intField == 1)
52 | testObject.longField = 1
53 | assert(testObject.longField == 1)
54 | testObject.floatField = 1
55 | assert(testObject.floatField == 1)
56 | testObject.doubleField = 1
57 | assert(testObject.doubleField == 1)
58 | testObject.bigIntegerField = 1
59 | assert(testObject.bigIntegerField == 1)
60 | testObject.bigDecimalField = 1
61 | assert(testObject.bigDecimalField == 1)
62 | testObject.charField = 1
63 | assert(testObject.charField == 1)
64 | testObject.stringField = "test"
65 | assert(testObject.stringField == "test")
66 | end
67 |
68 | -- Meta test
69 | function testMeta ()
70 | -- Create
71 | local TestObject = java.require("com.naef.jnlua.test.fixture.TestObject")
72 | local testObject1 = TestObject:new(1)
73 | local testObject2 = TestObject:new(2)
74 |
75 | -- __index
76 | local int = java.require("int")
77 | local intArray = java.new(int, 2)
78 | assert(intArray[1] == 0)
79 | assert(intArray[2] == 0)
80 |
81 | -- __newindex
82 | intArray[1] = 1
83 | assert(intArray[1] == 1)
84 |
85 | -- __len
86 | assert(#intArray == 2)
87 |
88 | -- __eq
89 | assert(testObject1 ~= testObject2)
90 | testObject2.value = 1
91 | assert(testObject1 == testObject2)
92 | testObject2.value = 2
93 |
94 | -- __lt, __le
95 | assert(testObject1 < testObject2)
96 | assert(testObject2 <= testObject2)
97 | testObject1.value = 2
98 | testObject2.value = 1
99 | assert(testObject1 > testObject2)
100 | assert(testObject2 >= testObject2)
101 | testObject1.value = 1
102 | testObject2.value = 2
103 |
104 | -- __tostring
105 | assert(tostring(testObject1) == "1")
106 | assert(tostring(testObject2) == "2")
107 |
108 | -- __pairs
109 | local HashMap = java.require("java.util.HashMap")
110 | local hashMap = HashMap:new()
111 | hashMap:put("k", "v")
112 | local cnt = 0
113 | for k, v in pairs(hashMap) do
114 | if k == "k" and v == "v" then cnt = cnt + 1 end
115 | end
116 | assert(cnt == 1)
117 |
118 | -- ipairs
119 | cnt = 0
120 | for i, j in ipairs(intArray) do
121 | cnt = cnt + 1
122 | end
123 | assert(cnt == 2)
124 | end
125 |
126 | -- Overloaded method dispatch test
127 | function testMethodDispatch ()
128 | -- Subclass test
129 | local TestObject = java.require("com.naef.jnlua.test.fixture.TestObject")
130 | local testObject = TestObject:new()
131 | local Sub = java.require("com.naef.jnlua.test.fixture.TestObject$Sub")
132 | local sub = Sub:new()
133 | assert(testObject:overloadedSub(testObject) == "super")
134 | assert(testObject:overloadedSub(sub) == "sub")
135 |
136 | -- Subinterface test
137 | local AB = java.require("com.naef.jnlua.test.fixture.TestObject$AB")
138 | local ab = AB:new()
139 | local AC = java.require("com.naef.jnlua.test.fixture.TestObject$AC")
140 | local ac = AC:new()
141 | local BC = java.require("com.naef.jnlua.test.fixture.TestObject$BC")
142 | local bc = BC:new()
143 | assert(testObject:overloadedSibling(ab) == "b")
144 | assert(testObject:overloadedSibling(ac) == "c")
145 | local status, msg = pcall(testObject.overloadedSibling, testObject, bc)
146 | assert(not status)
147 | assert(string.find(tostring(msg), "ambivalent"))
148 | assert(testObject:overloadedParentChild(ab) == "b")
149 | assert(testObject:overloadedParentChild(ac) == "a")
150 | assert(testObject:overloadedParentChild(bc) == "b")
151 | assert(testObject:overloadedParentChild(bc) == "b")
152 | end
153 |
154 | -- VarArgs method test
155 | function testVarargs ()
156 | local String = java.require("java.lang.String")
157 | assert(String:format("%s%.0f", "test", 1) == "test1")
158 | assert(true)
159 | end
160 |
--------------------------------------------------------------------------------
/jnlua/src/main/java/com/naef/jnlua/script/LuaScriptEngineFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua.script;
7 |
8 | import java.util.ArrayList;
9 | import java.util.Collections;
10 | import java.util.List;
11 |
12 | import javax.script.ScriptEngine;
13 | import javax.script.ScriptEngineFactory;
14 |
15 | import com.naef.jnlua.LuaState;
16 |
17 | /**
18 | * Lua script engine factory implementation conforming to JSR 223: Scripting for
19 | * the Java Platform.
20 | */
21 | public class LuaScriptEngineFactory implements ScriptEngineFactory {
22 | // -- Static
23 | private static final String ENGINE_NAME = "JNLua";
24 | private static final String LANGUAGE_NAME = "Lua";
25 | private static final List EXTENSIONS;
26 | private static final List MIME_TYPES;
27 | private static final List NAMES;
28 | static {
29 | // Extensions
30 | List extensions = new ArrayList();
31 | extensions.add("lua");
32 | EXTENSIONS = Collections.unmodifiableList(extensions);
33 |
34 | // MIME types
35 | List mimeTypes = new ArrayList();
36 | mimeTypes.add("application/x-lua");
37 | mimeTypes.add("text/x-lua");
38 | MIME_TYPES = Collections.unmodifiableList(mimeTypes);
39 |
40 | // Names
41 | List names = new ArrayList();
42 | names.add("lua");
43 | names.add("Lua");
44 | names.add("jnlua");
45 | names.add("JNLua");
46 | NAMES = Collections.unmodifiableList(names);
47 | }
48 |
49 | // -- Construction
50 | /**
51 | * Creates a new instance.
52 | */
53 | public LuaScriptEngineFactory() {
54 | }
55 |
56 | // -- ScriptEngineFactory methods
57 | @Override
58 | public String getEngineName() {
59 | return ENGINE_NAME;
60 | }
61 |
62 | @Override
63 | public String getEngineVersion() {
64 | return LuaState.VERSION;
65 | }
66 |
67 | @Override
68 | public List getExtensions() {
69 | return EXTENSIONS;
70 | }
71 |
72 | @Override
73 | public List getMimeTypes() {
74 | return MIME_TYPES;
75 | }
76 |
77 | @Override
78 | public List getNames() {
79 | return NAMES;
80 | }
81 |
82 | @Override
83 | public String getLanguageName() {
84 | return LANGUAGE_NAME;
85 | }
86 |
87 | @Override
88 | public String getLanguageVersion() {
89 | return LuaState.LUA_VERSION;
90 | }
91 |
92 | @Override
93 | public Object getParameter(String key) {
94 | if (key.equals(ScriptEngine.ENGINE)) {
95 | return getEngineName();
96 | }
97 | if (key.equals(ScriptEngine.ENGINE_VERSION)) {
98 | return getEngineVersion();
99 | }
100 | if (key.equals(ScriptEngine.NAME)) {
101 | return getNames().get(0);
102 | }
103 | if (key.equals(ScriptEngine.LANGUAGE)) {
104 | return getLanguageName();
105 | }
106 | if (key.equals(ScriptEngine.LANGUAGE_VERSION)) {
107 | return getLanguageVersion();
108 | }
109 | if (key.equals("THREADING")) {
110 | return "MULTITHREADED";
111 | }
112 | return null;
113 | }
114 |
115 | @Override
116 | public String getMethodCallSyntax(String obj, String m, String... args) {
117 | StringBuffer sb = new StringBuffer();
118 | sb.append(obj);
119 | sb.append(':');
120 | sb.append(m);
121 | sb.append('(');
122 | for (int i = 0; i < args.length; i++) {
123 | if (i > 0) {
124 | sb.append(", ");
125 | }
126 | sb.append(args[i]);
127 | }
128 | sb.append(')');
129 | return sb.toString();
130 | }
131 |
132 | @Override
133 | public String getOutputStatement(String toDisplay) {
134 | StringBuffer sb = new StringBuffer();
135 | sb.append("print(");
136 | quoteString(sb, toDisplay);
137 | sb.append(')');
138 | return sb.toString();
139 | }
140 |
141 | @Override
142 | public String getProgram(String... statements) {
143 | StringBuffer sb = new StringBuffer();
144 | for (int i = 0; i < statements.length; i++) {
145 | sb.append(statements[i]);
146 | sb.append("\n");
147 | }
148 | return sb.toString();
149 | }
150 |
151 | @Override
152 | public ScriptEngine getScriptEngine() {
153 | return new LuaScriptEngine(this);
154 | }
155 |
156 | // --Private methods
157 | /**
158 | * Quotes a string in double quotes.
159 | */
160 | private void quoteString(StringBuffer sb, String s) {
161 | sb.append('"');
162 | for (int i = 0; i < s.length(); i++) {
163 | switch (s.charAt(i)) {
164 | case '\u0007':
165 | sb.append("\\a");
166 | break;
167 | case '\b':
168 | sb.append("\\b");
169 | break;
170 | case '\f':
171 | sb.append("\\f");
172 | break;
173 | case '\n':
174 | sb.append("\\n");
175 | break;
176 | case '\r':
177 | sb.append("\\r");
178 | break;
179 | case '\t':
180 | sb.append("\\t");
181 | break;
182 | case '\u000b':
183 | sb.append("\\v");
184 | break;
185 | case '\\':
186 | sb.append("\\\\");
187 | break;
188 | case '"':
189 | sb.append("\\\"");
190 | break;
191 | default:
192 | sb.append(s.charAt(i));
193 | }
194 | }
195 | sb.append('"');
196 | }
197 | }
198 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | JNLua (Java Native Lua) integrates the [Lua Scripting Language](http://www.lua.org/) into Java. The integration is based on the original implementation of Lua which is written in ANSI C. The Lua C code is integrated into Java using the Java Native API (JNI).
2 |
3 | ### Features ###
4 |
5 | JNLua provides the following features:
6 |
7 | - **Full Lua support with full Java type-safety.** JNLua provides the full functionality of Lua C API including large parts of the Lua Auxiliary Library. All Lua Standard Libraries are supported, including the coroutine functions. At the same time, JNLua maintains the type-safety of the Java VM by performing rigorous checks in its native library.
8 | - **Two-way integration.** With JNLua, you can access Java from Lua and Lua from Java. From Lua, JNLua provides full Java object access with intuitive syntax and the abilitiy to implement Java interfaces in Lua. From Java, JNLua provides full Lua access including the ability to implement Lua functions in Java. The integration works transparently in both directions and on each end conforms to the common principles of the respective platform.
9 | - **Dual bootstrapping.** JNLua can be started from both the Java and the Lua side. If started from the Java side, a Lua state is attached to the calling Java virtual machine; if started from the Lua side, a Java virtual machine is attached to the calling Lua process.
10 | - **Extensive language bindings.** The bindings between Lua and Java are abstracted into the domains of *Java reflection* and *conversion*. The *default Java reflector* supports field, method and property access on Java classes and objects. For overloaded methods, it provides a dispatch logic that mimics the behavior described in Java Language Specification. The *default converter* handles the bidirectional conversion of primitive types, such as numbers and strings. For complex types, it supports the bidirectional mapping of Lua tables to Java maps, lists and arrays. These mappings are generally implemented with proxy objects, that is, they work by *reference*. Both the Java reflector and converter can be specialized to fit custom needs.
11 | - **Java module.** The JNLua Java module provides a small but comprehensive set of Lua functions providing Java language support for Lua.
12 | - **Java VM module.** The Java VM module is a Lua module written in C that allows a Lua process to create a Java Virtual Machine and run Java code in that machine.
13 | - **Transparent error handling.** Java does error handling by exceptions; Lua uses mechanics such as `error()` and `pcall()`. JNLua ensures a seamless translation of error conditions between the two domains. Lua errors are reported as exceptions to Java. Java exceptions generate errors on the Lua side.
14 | - **JSR 223: Scripting for the Java Platform provider.** JNLua includes a provider that conforms to the [JSR 223: Scripting for the Java Platform](http://www.jcp.org/en/jsr/detail?id=223) specification. This allows the use of Lua as a scripting language for Java in a standardized way. The JSR 223 provider also supports the optional Compilable and Invocable interfaces.
15 | - **JNLua Console.** A simple console implemented in Java for experimenting with JNLua.
16 |
17 |
18 | ### Design Goals ###
19 |
20 | The following goals drive the design of JNLua:
21 |
22 | - **Stability.** Both Java and Lua are mature and stable platforms. However, the underlying Java VM is a type-safe in a way that ANSI C is not. When loading C code into the Java VM, one must be careful not to corrupt the type-safety of the VM. JNLua achieves this goal by rigorous argument checking, stack checking and a sufficient amount of internal synchronization.
23 | - **Performance.** Lua has a reputation of being a very fast scripting language. Basically, JNLua simply tries not to get into the way of that performance ;) In support of good performance, JNLua avoids copying values between Java and Lua. Instead, JNLua uses proxy objects where possible.
24 | - **Simplicity.** JNLua aims at being simple and easy to learn by adhering to well-known patterns in both the Java and the Lua world. Lua provides a large spectrum of flexibility with relatively few, but well-designed features. JNLua tries to adhere to that spirit.
25 |
26 |
27 | ### Architecture ###
28 |
29 | The figure below depicts the architecture of JNLua:
30 | 
31 |
32 | When JNLua is bootstrapped from Java, the Java code calls the JNLua Java library. The JNLua Java library invokes the JNLua native library via JNI, and the JNLua native library calls the Lua C API. Lua code can use the JNLua Java module to access Java functionality.
33 |
34 | When JNLua is bootstrapped from Lua, the Lua code uses the JNLua Java VM module to create a Java virtual machine with the JNLua Java library, and then calls the JNLua Java module to access Java functionality.
35 | Requirements
36 |
37 | JNLua 0.9 is based on the Java 6 Platform (JDK 1.6) and Lua 5.1.
38 |
39 | JNLua 1.0 is based on the Java 6 Platform (JDK 1.6) and Lua 5.2.
40 |
41 | Max Raskin has done a port of JNLua for the [Android platform](https://code.google.com/p/jnlua-android).
42 |
43 | ### Documentation ###
44 |
45 | Documentation is provided in the [wiki](https://github.com/Antag99/jnlua/wiki/) as well as in the form of generated Javadoc.
46 |
47 | ### License ###
48 |
49 | JNLua is licensed under the MIT license which at the time of this writing is the same license as the one of Lua.
50 |
--------------------------------------------------------------------------------
/CHANGES.md:
--------------------------------------------------------------------------------
1 |
2 | ### Release 1.0.5 ###
3 |
4 | - Corrected an issue where an array access error message would fail to format.
5 |
6 |
7 | ### Release 1.0.4 (2013-07-28) ###
8 |
9 | - Corrected an issue where method dispatch would enter an endless loop on
10 | non-public superclasses.
11 |
12 |
13 | ### Release 1.0.3 (2012-10-09) ###
14 |
15 | - Added transparent conversion between Lua strings and Java byte arrays.
16 | This may break existing code that passes byte arrays between Java and Lua.
17 | A compatibility property, com.naef.jnlua.rawByteArray=true, has been provided.
18 |
19 | - Fixed an issue where method dispatch would incorrectly fail on public
20 | methods found on non-public classes with public superclasses. Thanks
21 | Ignazio Di Napoli for the analysis.
22 |
23 |
24 | ### Release 1.0.2 (2012-01-29) ###
25 |
26 | - Added toIntegerX and toNumberX methods to LuaState.
27 |
28 | - Added a 'new' method to interfaces in the default Java reflector. The method
29 | accepts a table providing the methods of the interface and returns a proxy
30 | that implements the interface.
31 |
32 | - Changed the absIndex method in LuaState to accept non-valid indexes.
33 |
34 | - Changed the rawEqual method to return false on non-valid indexes.
35 |
36 | - Changed the setMetatable method in LuaState to no longer return a value,
37 | adapting to the Lua 5.2 API.
38 |
39 | - Improved the diagnostics in the javavm module. In case of JNI errors, the
40 | Java exception string is now included in the error message.
41 |
42 | - Refactored the error handling in the JNLua native library.
43 |
44 |
45 | ### Release 1.0.1 (2012-01-12) ###
46 |
47 | - Added a javavm module, allowing to create a Java VM from Lua.
48 |
49 | - Javadoc corrections.
50 |
51 | - Corrected an issue where the native library would pass an invalid handle to
52 | the ReleaseStringUTFChars function.
53 |
54 | - Corrected an issue where the native library would not properly catch Lua
55 | errors, leading to uncontrolled transitions between Java code and native code.
56 |
57 | - Corrected an issue where the native library would exit incorrectly from the
58 | lua_tojavafunction function.
59 |
60 |
61 | ### Release 1.0.0 (2012-01-05) ###
62 |
63 | - Adapted to Lua 5.2.
64 |
65 | - Added the RIDX_MAINTHREAD and RIDX_GLOBALS constants to LuaState.
66 |
67 | - Added a compare method to LuaState, and deprecated the equal and lessThan methods.
68 |
69 | - Added a rawLen method to LuaState, and deprecated the length method.
70 |
71 | - Added an absIndex method to LuaState.
72 |
73 | - Added an arith method to LuaState.
74 |
75 | - Added a copy method to LuaState.
76 |
77 | - Added a len method to LuaState.
78 |
79 | - Added support for the bit32 library in both the openLib and openLibs methods
80 | of LuaState.
81 |
82 | - Added support for additional garbage collection actions, allowing to query
83 | whether the collector is running and choosing the collector mode.
84 |
85 | - Added the exception classes LuaGcMetamethodException and
86 | LuaMessageHandlerException, indicating errors running the __gc metamethod
87 | during garbage collection and errors running the message handler function in a
88 | protected call.
89 |
90 | - Added support for the __pairs and __ipairs metamethods on Java objects. The
91 | behavior is equivalent to the pairs and ipairs functions provided by the Java
92 | module.
93 |
94 | - Removed the GLOBALSINDEX and ENVIRONINDEX constants from LuaState. You can
95 | use the getGlobal and setGlobal methods, or call rawget(REGISTRYINDEX,
96 | RIDX_GLOBALS) to push the global environment onto the stack.
97 |
98 | - Removed the checkBoolean methods from LuaState. You can use the toBoolean
99 | method to evaluate any value in a boolean context. Also changed the toBoolean
100 | method to accept non-valid stack indexes.
101 |
102 | - Removed the setFEnv and getFEnv methods from LuaState.
103 |
104 | - Changed the input stream based load method in LuaState to accept an
105 | additional mode argument. Also, the source (aka chunkname) argument is
106 | no longer auto-prefixed with an equals sign.
107 |
108 | - Changed the behavior of the library opening methods. The openLib method
109 | in LuaState and the open method in JavaModule now leave the loaded module on
110 | the stack.
111 |
112 | - Changed the behavior of the register method in LuaState to follow that of
113 | luaL_requiref, no longer specifically supporting dots in module names. An
114 | optional boolean argument now controls whether a global variable with the
115 | module name is created.
116 |
117 | - Changed the argument checking methods in LuaState to call the Lua standard
118 | implementations, reducing the number of native transitions and taking advantage
119 | of tonumberx and tointegerx improvements. Also changed the checkOption
120 | methods to return an integer index instead of a string and added checkEnum
121 | methods suitable for use with Java enums.
122 |
123 | - Corrected an issue where the type method in LuaState would not return null
124 | for non-valid stack indexes.
125 |
126 | - Corrected an issue where the default converter would not properly handle
127 | non-valid stack indexes.
128 |
129 | - Corrected an issue where the setJavaReflector method in LuaState would allow
130 | a null value to be set.
131 |
132 |
133 | ### Release 0.9.1 Beta (2010-04-05) ###
134 |
135 | - Added NativeSupport for more explicit control over the native library
136 | loading process.
137 |
138 | - Migrated build system to Maven.
139 |
140 |
141 | ### Release 0.9.0 Beta (2008-10-27) ###
142 |
143 | - Initial public release.
144 |
--------------------------------------------------------------------------------
/jnlua/src/test/java/com/naef/jnlua/test/LuaExceptionTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua.test;
7 |
8 | import static org.junit.Assert.assertEquals;
9 | import static org.junit.Assert.assertNotNull;
10 | import static org.junit.Assert.assertTrue;
11 |
12 | import org.junit.Test;
13 |
14 | import com.naef.jnlua.JavaFunction;
15 | import com.naef.jnlua.LuaGcMetamethodException;
16 | import com.naef.jnlua.LuaRuntimeException;
17 | import com.naef.jnlua.LuaStackTraceElement;
18 | import com.naef.jnlua.LuaState;
19 | import com.naef.jnlua.LuaSyntaxException;
20 | import com.naef.jnlua.LuaState.Library;
21 |
22 | /**
23 | * Contains unit tests for Lua exceptions.
24 | */
25 | public class LuaExceptionTest extends AbstractLuaTest {
26 | // -- Test cases
27 | /**
28 | * Tests the call of a Lua function which invokes the Lua error function.
29 | */
30 | @Test
31 | public void testLuaError() throws Exception {
32 | // Load program
33 | luaState.openLibs();
34 | StringBuffer sb = new StringBuffer();
35 | sb.append("function A ()\n");
36 | sb.append(" B()\n");
37 | sb.append("end\n");
38 | sb.append("\n");
39 | sb.append("function B ()\n");
40 | sb.append(" C()\n");
41 | sb.append("end\n");
42 | sb.append("\n");
43 | sb.append("function C ()\n");
44 | sb.append(" error(\"msg\")\n");
45 | sb.append("end\n");
46 | sb.append("\n");
47 | sb.append("A()\n");
48 | luaState.load(sb.toString(), "=testLuaError");
49 |
50 | // Run
51 | LuaRuntimeException luaRuntimeException = null;
52 | try {
53 | luaState.call(0, 0);
54 | } catch (LuaRuntimeException e) {
55 | luaRuntimeException = e;
56 | }
57 | assertTrue(luaRuntimeException.getMessage().endsWith("msg"));
58 | LuaStackTraceElement[] luaStackTrace = luaRuntimeException
59 | .getLuaStackTrace();
60 | assertEquals(5, luaStackTrace.length);
61 | assertEquals(new LuaStackTraceElement("error", null, -1),
62 | luaStackTrace[0]);
63 | assertEquals(new LuaStackTraceElement("C", "testLuaError", 10),
64 | luaStackTrace[1]);
65 | assertEquals(new LuaStackTraceElement("B", "testLuaError", 6), luaStackTrace[2]);
66 | assertEquals(new LuaStackTraceElement("A", "testLuaError", 2), luaStackTrace[3]);
67 | assertEquals(new LuaStackTraceElement(null, "testLuaError", 13),
68 | luaStackTrace[4]);
69 | }
70 |
71 | /**
72 | * Tests the call of a Java function which throws a Java runtime exception.
73 | */
74 | @Test
75 | public void testRuntimeException() throws Exception {
76 | // Push function
77 | luaState.pushJavaFunction(new RuntimeExceptionFunction());
78 |
79 | // Push arguments
80 | LuaRuntimeException luaRuntimeException = null;
81 | try {
82 | luaState.call(0, 0);
83 | } catch (LuaRuntimeException e) {
84 | luaRuntimeException = e;
85 | }
86 | assertNotNull(luaRuntimeException);
87 | Throwable cause = luaRuntimeException.getCause();
88 | assertNotNull(cause);
89 | assertTrue(cause instanceof ArithmeticException);
90 | }
91 |
92 | /**
93 | * Tests the call of a Java function which throws a Lua runtime exception.
94 | */
95 | @Test
96 | public void testLuaRuntimeException() throws Exception {
97 | // Push function
98 | luaState.pushJavaFunction(new LuaRuntimeExceptionFunction());
99 |
100 | // Push arguments
101 | LuaRuntimeException luaRuntimeException = null;
102 | try {
103 | luaState.call(0, 0);
104 | } catch (LuaRuntimeException e) {
105 | luaRuntimeException = e;
106 | }
107 | assertNotNull(luaRuntimeException);
108 | Throwable cause = luaRuntimeException.getCause();
109 | assertNotNull(cause);
110 | assertTrue(cause instanceof LuaRuntimeException);
111 | }
112 |
113 | /**
114 | * Tests the generation of a Lua syntax exception on Lua code with invalid
115 | * syntax.
116 | */
117 | @Test
118 | public void testLuaSyntaxException() throws Exception {
119 | LuaSyntaxException luaSyntaxException = null;
120 | try {
121 | luaState.load("An invalid chunk of Lua.", "=testLuaSyntaxException");
122 | } catch (LuaSyntaxException e) {
123 | luaSyntaxException = e;
124 | }
125 | assertNotNull(luaSyntaxException);
126 | }
127 |
128 | /**
129 | * Tests the generation of a Lua GC metamethod exception on a Lua value
130 | * raising an error in its __gc metamethod.
131 | */
132 | @Test
133 | public void testLuaGcMetamethodException() throws Exception {
134 | LuaGcMetamethodException luaGcMetamethodException = null;
135 | luaState.openLib(Library.BASE);
136 | luaState.pop(1);
137 | luaState.load(
138 | "setmetatable({}, { __gc = function() error(\"gc\") end })\n"
139 | + "collectgarbage()", "=testLuaGcMetamethodException");
140 | try {
141 | luaState.call(0, 0);
142 | } catch (LuaGcMetamethodException e) {
143 | luaGcMetamethodException = e;
144 | }
145 | assertNotNull(luaGcMetamethodException);
146 | }
147 |
148 | // -- Private classes
149 | /**
150 | * Provides a function throwing a Java runtime exception.
151 | */
152 | private class RuntimeExceptionFunction implements JavaFunction {
153 | public int invoke(LuaState luaState) throws LuaRuntimeException {
154 | @SuppressWarnings("unused")
155 | int a = 0 / 0;
156 | return 0;
157 | }
158 | }
159 |
160 | /**
161 | * Provides a function throwing a Lua runtime exception with a cause.
162 | */
163 | private class LuaRuntimeExceptionFunction implements JavaFunction {
164 | public int invoke(LuaState luaState) throws LuaRuntimeException {
165 | try {
166 | @SuppressWarnings("unused")
167 | int a = 0 / 0;
168 | } catch (ArithmeticException e) {
169 | throw new LuaRuntimeException(e.getMessage(), e);
170 | }
171 | return 0;
172 | }
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/jnlua/src/main/java/com/naef/jnlua/console/LuaConsole.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua.console;
7 |
8 | import java.io.BufferedReader;
9 | import java.io.ByteArrayInputStream;
10 | import java.io.ByteArrayOutputStream;
11 | import java.io.IOException;
12 | import java.io.InputStream;
13 | import java.io.InputStreamReader;
14 | import java.io.OutputStreamWriter;
15 |
16 | import com.naef.jnlua.LuaException;
17 | import com.naef.jnlua.LuaRuntimeException;
18 | import com.naef.jnlua.LuaState;
19 |
20 | /**
21 | * A simple Lua console.
22 | *
23 | *
24 | * The console collects input until a line with the sole content of the word
25 | * go is encountered. At that point, the collected input is run as a Lua
26 | * chunk. If the Lua chunk loads and runs successfully, the console displays the
27 | * returned values of the chunk as well as the execution time based on a
28 | * System.nanoTime() measurement. Otherwise, the console shows the
29 | * error that has occurred.
30 | *
31 | *
32 | *
33 | * Expressions can be printed by prepending = to the expression at the
34 | * beginning of a chunk. The console translates = into
35 | * return followed by a space and executes the chunk immediately.
36 | * No separate go is required. Therefore, expressions printed this way
37 | * must be entered on a single line.
38 | *
39 | */
40 | public class LuaConsole {
41 | // -- Static
42 | private static final String[] EMPTY_ARGS = new String[0];
43 |
44 | /**
45 | * Main routine.
46 | *
47 | * @param args
48 | * the command line arguments
49 | */
50 | public static void main(String[] args) {
51 | LuaConsole luaConsole = new LuaConsole(args);
52 | luaConsole.run();
53 | System.exit(0);
54 | }
55 |
56 | // -- State
57 | private LuaState luaState;
58 |
59 | // -- Construction
60 | /**
61 | * Creates a new instance.
62 | */
63 | public LuaConsole() {
64 | this(EMPTY_ARGS);
65 | }
66 |
67 | /**
68 | * Creates a new instance with the specified command line arguments. The
69 | * arguments are passed to Lua as the argv global variable.
70 | *
71 | * @param args
72 | */
73 | public LuaConsole(String[] args) {
74 | luaState = new LuaState();
75 |
76 | // Process arguments
77 | luaState.newTable(args.length, 0);
78 | for (int i = 0; i < args.length; i++) {
79 | luaState.pushString(args[i]);
80 | luaState.rawSet(-2, i + 1);
81 | }
82 | luaState.setGlobal("argv");
83 |
84 | // Open standard libraries
85 | luaState.openLibs();
86 |
87 | // Set buffer mode
88 | luaState.load("io.stdout:setvbuf(\"no\")", "=consoleInitStdout");
89 | luaState.call(0, 0);
90 | luaState.load("io.stderr:setvbuf(\"no\")", "=consoleInitStderr");
91 | luaState.call(0, 0);
92 | }
93 |
94 | // -- Properties
95 | /**
96 | * Returns the Lua state of this console.
97 | *
98 | * @return the Lua state
99 | */
100 | public LuaState getLuaState() {
101 | return luaState;
102 | }
103 |
104 | // -- Operations
105 | /**
106 | * Runs the console.
107 | */
108 | public void run() {
109 | // Banner
110 | System.out.println(String.format("JNLua %s Console using Lua %s.",
111 | LuaState.VERSION, LuaState.LUA_VERSION));
112 | System.out.print("Type 'go' on an empty line to evaluate a chunk. ");
113 | System.out.println("Type = to print an expression.");
114 |
115 | // Prepare reader
116 | BufferedReader bufferedReader = new BufferedReader(
117 | new InputStreamReader(System.in));
118 | try {
119 | // Process chunks
120 | chunk: while (true) {
121 | ByteArrayOutputStream out = new ByteArrayOutputStream();
122 | OutputStreamWriter outWriter = new OutputStreamWriter(out,
123 | "UTF-8");
124 | boolean firstLine = true;
125 |
126 | // Process lines
127 | while (true) {
128 | String line = bufferedReader.readLine();
129 | if (line == null) {
130 | break chunk;
131 | }
132 | if (line.equals("go")) {
133 | outWriter.flush();
134 | InputStream in = new ByteArrayInputStream(out
135 | .toByteArray());
136 | runChunk(in);
137 | continue chunk;
138 | }
139 | if (firstLine && line.startsWith("=")) {
140 | outWriter.write("return " + line.substring(1));
141 | outWriter.flush();
142 | InputStream in = new ByteArrayInputStream(out
143 | .toByteArray());
144 | runChunk(in);
145 | continue chunk;
146 | }
147 | outWriter.write(line);
148 | outWriter.write('\n');
149 | firstLine = false;
150 | }
151 | }
152 | } catch (IOException e) {
153 | System.out.print("IO error: ");
154 | System.out.print(e.getMessage());
155 | System.out.println();
156 | }
157 | }
158 |
159 | /**
160 | * Runs a chunk of Lua code from an input stream.
161 | */
162 | protected void runChunk(InputStream in) throws IOException {
163 | try {
164 | long start = System.nanoTime();
165 | luaState.setTop(0);
166 | luaState.load(in, "=console", "t");
167 | luaState.call(0, LuaState.MULTRET);
168 | long stop = System.nanoTime();
169 | for (int i = 1; i <= luaState.getTop(); i++) {
170 | if (i > 1) {
171 | System.out.print(", ");
172 | }
173 | switch (luaState.type(i)) {
174 | case BOOLEAN:
175 | System.out.print(Boolean.valueOf(luaState.toBoolean(i)));
176 | break;
177 | case NUMBER:
178 | case STRING:
179 | System.out.print(luaState.toString(i));
180 | break;
181 | default:
182 | System.out.print(luaState.typeName(i));
183 | }
184 | }
185 | System.out.print("\t#msec=");
186 | System.out.print(String.format("%.3f", (stop - start) / 1000000.0));
187 | System.out.println();
188 | } catch (LuaRuntimeException e) {
189 | e.printLuaStackTrace();
190 | } catch (LuaException e) {
191 | System.err.println(e.getMessage());
192 | }
193 | }
194 | }
195 |
--------------------------------------------------------------------------------
/jnlua/src/test/resources/com/naef/jnlua/test/JavaModule.lua:
--------------------------------------------------------------------------------
1 | --[[
2 | $Id$
3 | See LICENSE.txt for license terms.
4 | ]]
5 |
6 | module(..., package.seeall)
7 |
8 | -- java.require()
9 | function testRequire ()
10 | -- No import
11 | local class, imported = java.require("java.lang.System")
12 | assert(class)
13 | assert(not imported)
14 |
15 | -- Import
16 | class, imported = java.require("java.lang.System", true)
17 | assert(class)
18 | assert(class == java.lang.System)
19 | assert(imported)
20 |
21 | -- Primitive type, no import
22 | class, imported = java.require("byte")
23 | assert(class)
24 | assert(not imported)
25 |
26 | -- Primitive type, import
27 | class, imported = java.require("byte", true)
28 | assert(class)
29 | assert(class == byte)
30 | assert(imported)
31 | end
32 |
33 | -- java.new
34 | function testNew ()
35 | local byte = java.require("byte")
36 | assert(byte)
37 |
38 | -- Simple byte array
39 | local byteArray = java.new(byte, 10)
40 | assert(#byteArray == 10)
41 | local byteArray = java.new("byte", 10)
42 | assert(#byteArray == 10)
43 |
44 | -- Multi-dimensional byte array
45 | byteArray = java.new(byte, 10, 10)
46 | assert(#byteArray == 10)
47 | assert(#byteArray[1] == 10)
48 | end
49 |
50 | -- java.instanceof
51 | function testInstanceOf ()
52 | local TestObject = java.require("com.naef.jnlua.test.fixture.TestObject")
53 | local testObject = TestObject:new()
54 | assert(java.instanceof(testObject, TestObject))
55 | assert(java.instanceof(testObject, "com.naef.jnlua.test.fixture.TestObject"))
56 | assert(not java.instanceof(testObject, "java.lang.System"))
57 | end
58 |
59 | -- java.cast
60 | function testCast ()
61 | local StringBuilder = java.require("java.lang.StringBuilder")
62 | local sb = StringBuilder:new()
63 | sb:append(java.cast(1, "int"))
64 | assert(sb:toString() == "1")
65 | end
66 |
67 | -- java.proxy
68 | function testProxy ()
69 | local privilegedAction = { hasRun = false }
70 | function privilegedAction:run()
71 | self.hasRun = true
72 | end
73 | local proxy = java.proxy(privilegedAction, "java.security.PrivilegedAction")
74 | assert(not privilegedAction.hasRun)
75 | local AccessController = java.require("java.security.AccessController")
76 | AccessController:doPrivileged(proxy)
77 | assert(privilegedAction.hasRun)
78 | end
79 |
80 | -- java.pairs
81 | function testPairs ()
82 | -- Create map
83 | local HashMap = java.require("java.util.HashMap")
84 | local hashMap = HashMap:new()
85 | hashMap:put("k", "v")
86 |
87 | -- Iterate
88 | local count = 0
89 | for k, v in java.pairs(hashMap) do
90 | assert(k == "k")
91 | assert(v == "v")
92 | count = count + 1
93 | end
94 | assert(count == 1)
95 |
96 | -- Create map (navigable)
97 | local TreeMap = java.require("java.util.TreeMap")
98 | local treeMap = TreeMap:new()
99 | treeMap:put("k", "v")
100 |
101 | -- Iterate
102 | local count = 0
103 | for k, v in java.pairs(treeMap) do
104 | assert(k == "k")
105 | assert(v == "v")
106 | count = count + 1
107 | end
108 | assert(count == 1)
109 | end
110 |
111 | -- java.ipairs
112 | function testIPairs ()
113 | -- Create list
114 | local list = java.new("java.util.ArrayList")
115 | for i = 1, 10 do
116 | list:add(i)
117 | end
118 |
119 | -- Iterate
120 | local count = 0
121 | local sum = 0
122 | for k, v in java.ipairs(list) do
123 | count = count + 1
124 | assert(k == count)
125 | sum = sum + v
126 | end
127 | assert(count == 10)
128 | assert(sum == 55)
129 |
130 | -- Create array
131 | local array = java.new("int", 10)
132 | for i = 1, 10 do
133 | array[i] = i
134 | end
135 |
136 | -- Iterate
137 | local count = 0
138 | local sum = 0
139 | for k, v in java.ipairs(array) do
140 | count = count + 1
141 | assert(k == count)
142 | sum = sum + v
143 | end
144 | assert(count == 10)
145 | assert(sum == 55)
146 | end
147 |
148 | -- java.tottable
149 | function testToTable ()
150 | -- Test list
151 | local arrayList = java.new("java.util.ArrayList")
152 | local list = java.totable(arrayList)
153 | for i = 1, 10 do
154 | list[i] = i
155 | end
156 | for i = 1, 10 do
157 | assert(arrayList:get(i - 1) == i)
158 | end
159 | assert(#list == 10)
160 | local count = 0
161 | for k, v in java.ipairs(list) do
162 | count = count + 1
163 | end
164 | assert(count == 10)
165 |
166 | -- Test map
167 | local hashMap = java.new("java.util.HashMap")
168 | local map = java.totable(hashMap)
169 | map["k"] = "v"
170 | assert(hashMap:get("k") == "v")
171 | local count = 0
172 | for k, v in java.pairs(map) do
173 | count = count + 1
174 | end
175 | assert(count == 1)
176 | end
177 |
178 | -- java.elements
179 | function testElements()
180 | local set = java.new("java.util.HashSet")
181 | for i = 1, 10 do
182 | set:add(i)
183 | end
184 | sum = 0
185 | for value in java.elements(set) do
186 | sum = sum + value
187 | end
188 | assert(sum == 55)
189 | end
190 |
191 | -- java.fields
192 | function testFields()
193 | -- Static
194 | local TestObject = java.require("com.naef.jnlua.test.fixture.TestObject")
195 | local fields = {}
196 | local count = 0
197 | for k, v in java.fields(TestObject) do
198 | count = count + 1
199 | fields[k] = v
200 | end
201 | assert(fields["TEST_FIELD"])
202 | assert(count == 1)
203 |
204 | -- Non-static
205 | local testObject = java.new(TestObject)
206 | fields = {}
207 | count = 0
208 | for k, v in java.fields(testObject) do
209 | count = count + 1
210 | fields[k] = v
211 | end
212 | assert(fields["testField"])
213 | assert(count == 13)
214 | end
215 |
216 | -- java.methods
217 | function testMethods()
218 | -- Static
219 | local TestObject = java.require("com.naef.jnlua.test.fixture.TestObject")
220 | local methods = {}
221 | local count = 0
222 | for k, v in java.methods(TestObject) do
223 | count = count + 1
224 | methods[k] = v
225 | end
226 | assert(methods["testStatic"])
227 | assert(count == 2)
228 |
229 | -- Non-static
230 | local testObject = java.new(TestObject)
231 | methods = {}
232 | count = 0
233 | for k, v in java.methods(testObject) do
234 | count = count + 1
235 | methods[k] = v
236 | end
237 | assert(methods["test"])
238 | assert(count == 16)
239 | end
240 |
241 | -- java.properties
242 | function testProperties()
243 | local TestObject = java.require("com.naef.jnlua.test.fixture.TestObject")
244 | local testObject = java.new(TestObject)
245 | local properties = {}
246 | local count = 0
247 | for k, v in java.properties(testObject) do
248 | count = count + 1
249 | properties[k] = v
250 | end
251 | assert(properties["value"])
252 | assert(count == 3)
253 | end
254 |
--------------------------------------------------------------------------------
/jnlua/src/main/c/javavm.c:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * Provides the Java VM module. See LICENSE.txt for license terms.
4 | */
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 | #ifdef LUA_WIN
11 | #include
12 | #pragma warning(disable : 4996)
13 | #endif
14 | #ifdef LUA_USE_POSIX
15 | #include
16 | #endif
17 | #include "javavm.h"
18 |
19 | /*
20 | * Java VM parameters.
21 | */
22 | #define JAVAVM_METATABLE "javavm.metatable"
23 | #define JAVAVM_VM "javavm.vm"
24 | #define JAVAVM_MAXOPTIONS 128
25 | #define JAVAVM_JNIVERSION JNI_VERSION_1_6
26 |
27 | /*
28 | * VM record.
29 | */
30 | typedef struct vm_rec {
31 | JavaVM *vm;
32 | jobject luastate;
33 | int num_options;
34 | JavaVMOption options[JAVAVM_MAXOPTIONS];
35 | } vm_rec;
36 |
37 | /*
38 | * Raises an error from JNI.
39 | */
40 | static int error (lua_State *L, JNIEnv *env, const char *msg) {
41 | jthrowable throwable;
42 | jclass throwable_class;
43 | jmethodID tostring_id;
44 | jstring string;
45 | const char *extramsg = NULL;
46 |
47 | throwable = (*env)->ExceptionOccurred(env);
48 | if (throwable) {
49 | throwable_class = (*env)->GetObjectClass(env, throwable);
50 | if ((tostring_id = (*env)->GetMethodID(env, throwable_class, "toString", "()Ljava/lang/String;"))) {
51 | string = (*env)->CallObjectMethod(env, throwable, tostring_id);
52 | if (string) {
53 | extramsg = (*env)->GetStringUTFChars(env, string, NULL);
54 | }
55 | }
56 | }
57 | if (extramsg) {
58 | lua_pushfstring(L, "%s (%s)", msg, extramsg);
59 | (*env)->ReleaseStringUTFChars(env, string, extramsg);
60 | } else {
61 | lua_pushstring(L, msg);
62 | }
63 | return luaL_error(L, lua_tostring(L, -1));
64 | }
65 |
66 | /*
67 | * Releases a VM.
68 | */
69 | static int release_vm (lua_State *L) {
70 | vm_rec *vm;
71 | jclass luastate_class;
72 | jmethodID close_id;
73 | JNIEnv *env;
74 | int res;
75 | int i;
76 |
77 | /* Get VM */
78 | vm = luaL_checkudata(L, 1, JAVAVM_METATABLE);
79 |
80 | /* Already released? */
81 | if (!vm->vm) {
82 | return 0;
83 | }
84 |
85 | /* Check thread */
86 | if ((*vm->vm)->GetEnv(vm->vm, (void **) &env, JAVAVM_JNIVERSION) != JNI_OK) {
87 | return luaL_error(L, "invalid thread");
88 | }
89 |
90 | /* Close the Lua state in the Java VM */
91 | if (vm->luastate) {
92 | luastate_class = (*env)->GetObjectClass(env, vm->luastate);
93 | if (!(close_id = (*env)->GetMethodID(env, luastate_class, "close", "()V"))) {
94 | return error(L, env, "close method not found");
95 | }
96 | (*env)->CallVoidMethod(env, vm->luastate, close_id);
97 | (*env)->DeleteGlobalRef(env, vm->luastate);
98 | vm->luastate = NULL;
99 | }
100 |
101 | /* Destroy the Java VM */
102 | res = (*vm->vm)->DestroyJavaVM(vm->vm);
103 | if (res < 0) {
104 | return luaL_error(L, "error destroying Java VM: %d", res);
105 | }
106 | vm->vm = NULL;
107 |
108 | /* Free options */
109 | for (i = 0; i < vm->num_options; i++) {
110 | free(vm->options[i].optionString);
111 | vm->options[i].optionString = NULL;
112 | }
113 | vm->num_options = 0;
114 |
115 | return 0;
116 | }
117 |
118 | /*
119 | * Returns a string representation of a VM.
120 | */
121 | static int tostring_vm (lua_State *L) {
122 | vm_rec *vm;
123 | int i;
124 |
125 | vm = luaL_checkudata(L, 1, JAVAVM_METATABLE);
126 | lua_pushfstring(L, "Java VM (%p)", vm->vm);
127 | luaL_checkstack(L, vm->num_options, NULL);
128 | for (i = 0; i < vm->num_options; i++) {
129 | lua_pushfstring(L, "\n\t%s", vm->options[i].optionString);
130 | }
131 | lua_concat(L, vm->num_options + 1);
132 | return 1;
133 | }
134 |
135 | /*
136 | * Creates a VM.
137 | */
138 | static int create_vm (lua_State *L) {
139 | vm_rec *vm;
140 | int i;
141 | const char *option;
142 | JavaVMInitArgs vm_args;
143 | int res;
144 | JNIEnv *env;
145 | jclass luastate_class, library_class;
146 | jmethodID init_id, openlib_id;
147 | jfieldID java_id;
148 | jobject luastate, java;
149 |
150 | /* Check for existing VM */
151 | lua_getfield(L, LUA_REGISTRYINDEX, JAVAVM_VM);
152 | if (!lua_isnil(L, -1)) {
153 | return luaL_error(L, "VM already created");
154 | }
155 | lua_pop(L, 1);
156 |
157 | /* Create VM */
158 | vm = lua_newuserdata(L, sizeof(vm_rec));
159 | memset(vm, 0, sizeof(vm_rec));
160 | luaL_getmetatable(L, JAVAVM_METATABLE);
161 | lua_setmetatable(L, -2);
162 |
163 | /* Process options */
164 | vm->num_options = lua_gettop(L) - 1;
165 | if (vm->num_options > JAVAVM_MAXOPTIONS) {
166 | return luaL_error(L, "%d options limit, got %d", JAVAVM_MAXOPTIONS, vm->num_options);
167 | }
168 | for (i = 1; i <= vm->num_options; i++) {
169 | option = luaL_checkstring(L, i);
170 | if (strcmp(option, "vfprintf") == 0
171 | || strcmp(option, "exit") == 0
172 | || strcmp(option, "abort") == 0) {
173 | return luaL_error(L, "unsupported option '%s'", option);
174 | }
175 | vm->options[i - 1].optionString = strdup(option);
176 | if (!vm->options[i - 1].optionString) {
177 | return luaL_error(L, "out of memory");
178 | }
179 | }
180 |
181 | /* Create Java VM */
182 | vm_args.version = JAVAVM_JNIVERSION;
183 | vm_args.options = vm->options;
184 | vm_args.nOptions = vm->num_options;
185 | vm_args.ignoreUnrecognized = JNI_TRUE;
186 | res = JNI_CreateJavaVM(&vm->vm, (void**) &env, &vm_args);
187 | if (res < 0) {
188 | return luaL_error(L, "error creating Java VM: %d", res);
189 | }
190 |
191 | /* Create a LuaState in the Java VM */
192 | if (!(luastate_class = (*env)->FindClass(env, "com/naef/jnlua/LuaState"))
193 | || !(init_id = (*env)->GetMethodID(env, luastate_class, "", "(J)V"))) {
194 | return error(L, env, "JNLua not found");
195 | }
196 | luastate = (*env)->NewObject(env, luastate_class, init_id, (jlong) (uintptr_t) L);
197 | if (!luastate) {
198 | return error(L, env, "error creating LuaState");
199 | }
200 | vm->luastate = (*env)->NewGlobalRef(env, luastate);
201 | if (!vm->luastate) {
202 | return luaL_error(L, "error referencing LuaState");
203 | }
204 |
205 | /* Load the Java module */
206 | if (!(library_class = (*env)->FindClass(env, "com/naef/jnlua/LuaState$Library"))
207 | || !(openlib_id = (*env)->GetMethodID(env, luastate_class, "openLib", "(Lcom/naef/jnlua/LuaState$Library;)V"))
208 | || !(java_id = (*env)->GetStaticFieldID(env, library_class, "JAVA", "Lcom/naef/jnlua/LuaState$Library;"))
209 | || !(java = (*env)->GetStaticObjectField(env, library_class, java_id))) {
210 | return error(L, env, "Java module not found");
211 | }
212 | (*env)->CallVoidMethod(env, luastate, openlib_id, java);
213 | if ((*env)->ExceptionCheck(env)) {
214 | return error(L, env, "error loading Java module");
215 | }
216 | lua_pop(L, 1);
217 |
218 | /* Store VM */
219 | lua_pushvalue(L, -1);
220 | lua_setfield(L, LUA_REGISTRYINDEX, JAVAVM_VM);
221 |
222 | return 1;
223 | }
224 |
225 | /*
226 | * Destroys the VM.
227 | */
228 | static int destroy_vm (lua_State *L) {
229 | /* Release VM, if any */
230 | lua_pushcfunction(L, release_vm);
231 | lua_getfield(L, LUA_REGISTRYINDEX, JAVAVM_VM);
232 | if (lua_isnil(L, -1)) {
233 | /* No VM to destroy */
234 | lua_pushboolean(L, 0);
235 | return 1;
236 | }
237 | lua_call(L, 1, 0);
238 |
239 | /* Clear VM */
240 | lua_pushnil(L);
241 | lua_setfield(L, LUA_REGISTRYINDEX, JAVAVM_VM);
242 |
243 | /* Success */
244 | lua_pushboolean(L, 1);
245 | return 1;
246 | }
247 |
248 | /*
249 | * Returns the VM, if any.
250 | */
251 | static int get_vm (lua_State *L) {
252 | lua_getfield(L, LUA_REGISTRYINDEX, JAVAVM_VM);
253 | return 1;
254 | }
255 |
256 | /*
257 | * Java VM module functions.
258 | */
259 | static const luaL_Reg functions[] = {
260 | { "create", create_vm },
261 | { "destroy", destroy_vm },
262 | { "get", get_vm },
263 | { NULL, NULL }
264 | };
265 |
266 | /*
267 | * Exported functions.
268 | */
269 |
270 | LUALIB_API int luaopen_javavm (lua_State *L) {
271 | /* Create module */
272 | luaL_newlib(L, functions);
273 |
274 | /* Create metatable */
275 | luaL_newmetatable(L, JAVAVM_METATABLE);
276 | lua_pushcfunction(L, release_vm);
277 | lua_setfield(L, -2, "__gc");
278 | lua_pushcfunction(L, tostring_vm);
279 | lua_setfield(L, -2, "__tostring");
280 | lua_pop(L, 1);
281 |
282 | return 1;
283 | }
284 |
--------------------------------------------------------------------------------
/jnlua/src/main/java/com/naef/jnlua/util/AbstractTableMap.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua.util;
7 |
8 | import java.util.AbstractMap;
9 | import java.util.AbstractSet;
10 | import java.util.Iterator;
11 | import java.util.Map;
12 | import java.util.NoSuchElementException;
13 | import java.util.Set;
14 |
15 | import com.naef.jnlua.LuaState;
16 | import com.naef.jnlua.LuaValueProxy;
17 |
18 | /**
19 | * Abstract map implementation backed by a Lua table.
20 | */
21 | public abstract class AbstractTableMap extends AbstractMap
22 | implements LuaValueProxy {
23 | // -- State
24 | private Set> entrySet;
25 |
26 | // -- Construction
27 | /**
28 | * Creates a new instance.
29 | */
30 | public AbstractTableMap() {
31 | }
32 |
33 | // -- Map methods
34 | @Override
35 | public Set> entrySet() {
36 | if (entrySet == null) {
37 | entrySet = new EntrySet();
38 | }
39 | return entrySet;
40 | }
41 |
42 | @Override
43 | public boolean isEmpty() {
44 | return entrySet().isEmpty();
45 | }
46 |
47 | @Override
48 | public boolean containsKey(Object key) {
49 | checkKey(key);
50 | LuaState luaState = getLuaState();
51 | synchronized (luaState) {
52 | pushValue();
53 | luaState.pushJavaObject(key);
54 | luaState.getTable(-2);
55 | try {
56 | return !luaState.isNil(-1);
57 | } finally {
58 | luaState.pop(2);
59 | }
60 | }
61 | }
62 |
63 | @Override
64 | public Object get(Object key) {
65 | checkKey(key);
66 | LuaState luaState = getLuaState();
67 | synchronized (luaState) {
68 | pushValue();
69 | luaState.pushJavaObject(key);
70 | luaState.getTable(-2);
71 | try {
72 | return luaState.toJavaObject(-1, Object.class);
73 | } finally {
74 | luaState.pop(2);
75 | }
76 | }
77 | }
78 |
79 | @Override
80 | public Object put(K key, Object value) {
81 | checkKey(key);
82 | LuaState luaState = getLuaState();
83 | synchronized (luaState) {
84 | Object oldValue = get(key);
85 | pushValue();
86 | luaState.pushJavaObject(key);
87 | luaState.pushJavaObject(value);
88 | luaState.setTable(-3);
89 | luaState.pop(1);
90 | return oldValue;
91 | }
92 | }
93 |
94 | @Override
95 | public Object remove(Object key) {
96 | checkKey(key);
97 | LuaState luaState = getLuaState();
98 | synchronized (luaState) {
99 | Object oldValue = get(key);
100 | pushValue();
101 | luaState.pushJavaObject(key);
102 | luaState.pushNil();
103 | luaState.setTable(-3);
104 | luaState.pop(1);
105 | return oldValue;
106 | }
107 | }
108 |
109 | // -- Protected methods
110 | /**
111 | * Checks a key for validity. If the key is not valid, the method throws an
112 | * appropriate runtime exception. The method is invoked for all input keys.
113 | *
114 | *
115 | * This implementation checks that the key is not null. Lua
116 | * does not allow nil as a table key. Subclasses may implement
117 | * more restrictive checks.
118 | *
119 | *
120 | * @param key
121 | * the key
122 | * @throws NullPointerException
123 | * if the key is null
124 | */
125 | protected void checkKey(Object key) {
126 | if (key == null) {
127 | throw new NullPointerException("key must not be null");
128 | }
129 | }
130 |
131 | /**
132 | * Indicates if this table map filters keys from the Lua table. If the
133 | * method returns true, the table map invokes
134 | * {@link #acceptKey(int)} on each key retrieved from the underlying table
135 | * to determine whether the key is accepted or rejected.
136 | *
137 | *
138 | * This implementation returns false. Subclasses may override
139 | * the method alongside {@link #acceptKey(int)} to implement key filtering.
140 | *
141 | *
142 | * @return whether this table map filters keys from the Lua table
143 | */
144 | protected boolean filterKeys() {
145 | return false;
146 | }
147 |
148 | /**
149 | * Accepts or rejects a key from the Lua table. Only table keys that are
150 | * accepted are processed. The method allows subclasses to filter the Lua
151 | * table. The method is called only if {@link #filterKeys()} returns
152 | * true.
153 | *
154 | *
155 | * This implementation returns true regardless of the input,
156 | * thus accepting all keys. Subclasses may override the method alongside
157 | * {@link #filterKeys()} to implement key filtering.
158 | *
159 | *
160 | * @param index
161 | * the stack index containing the candidate key
162 | * @return whether the key is accepted
163 | */
164 | protected boolean acceptKey(int index) {
165 | return true;
166 | }
167 |
168 | /**
169 | * Converts the key at the specified stack index to a Java object. If this
170 | * table maps performs key filtering, the method is invoked only for keys it
171 | * has accepted.
172 | *
173 | * @param index
174 | * the stack index containing the key
175 | * @return the Java object representing the key
176 | * @see #filterKeys()
177 | * @see #acceptKey(int)
178 | */
179 | protected abstract K convertKey(int index);
180 |
181 | // -- Nested types
182 | /**
183 | * Lua table entry set.
184 | */
185 | private class EntrySet extends AbstractSet> {
186 | // -- Set methods
187 | @Override
188 | public Iterator> iterator() {
189 | return new EntryIterator();
190 | }
191 |
192 | @Override
193 | public boolean isEmpty() {
194 | LuaState luaState = getLuaState();
195 | synchronized (luaState) {
196 | pushValue();
197 | luaState.pushNil();
198 | while (luaState.next(-2)) {
199 | if (!filterKeys() || acceptKey(-2)) {
200 | luaState.pop(3);
201 | return false;
202 | }
203 | }
204 | luaState.pop(1);
205 | return true;
206 | }
207 | }
208 |
209 | @Override
210 | public int size() {
211 | LuaState luaState = getLuaState();
212 | synchronized (luaState) {
213 | int count = 0;
214 | pushValue();
215 | if (filterKeys()) {
216 | luaState.pushNil();
217 | while (luaState.next(-2)) {
218 | if (acceptKey(-2)) {
219 | count++;
220 | }
221 | luaState.pop(1);
222 | }
223 | } else {
224 | count = luaState.tableSize(-1);
225 | }
226 | luaState.pop(1);
227 | return count;
228 | }
229 | }
230 |
231 | @Override
232 | public boolean contains(Object object) {
233 | checkKey(object);
234 | if (!(object instanceof AbstractTableMap>.Entry)) {
235 | return false;
236 | }
237 | @SuppressWarnings("unchecked")
238 | Entry luaTableEntry = (Entry) object;
239 | if (luaTableEntry.getLuaState() != getLuaState()) {
240 | return false;
241 | }
242 | return containsKey(luaTableEntry.key);
243 | }
244 |
245 | @Override
246 | public boolean remove(Object object) {
247 | if (!(object instanceof AbstractTableMap>.Entry)) {
248 | return false;
249 | }
250 | @SuppressWarnings("unchecked")
251 | Entry luaTableEntry = (Entry) object;
252 | if (luaTableEntry.getLuaState() != getLuaState()) {
253 | return false;
254 | }
255 | LuaState luaState = getLuaState();
256 | synchronized (luaState) {
257 | pushValue();
258 | luaState.pushJavaObject(object);
259 | luaState.getTable(-2);
260 | boolean contains = !luaState.isNil(-1);
261 | luaState.pop(1);
262 | if (contains) {
263 | luaState.pushJavaObject(object);
264 | luaState.pushNil();
265 | luaState.setTable(-3);
266 | }
267 | luaState.pop(1);
268 | return contains;
269 | }
270 | }
271 | }
272 |
273 | /**
274 | * Lua table iterator.
275 | */
276 | private class EntryIterator implements Iterator> {
277 | // -- State
278 | private K key;
279 |
280 | // -- Iterator methods
281 | @Override
282 | public boolean hasNext() {
283 | LuaState luaState = getLuaState();
284 | synchronized (luaState) {
285 | pushValue();
286 | luaState.pushJavaObject(key);
287 | while (luaState.next(-2)) {
288 | if (!filterKeys() || acceptKey(-2)) {
289 | luaState.pop(3);
290 | return true;
291 | }
292 | }
293 | luaState.pop(1);
294 | return false;
295 | }
296 | }
297 |
298 | @Override
299 | public Map.Entry next() {
300 | LuaState luaState = getLuaState();
301 | synchronized (luaState) {
302 | pushValue();
303 | luaState.pushJavaObject(key);
304 | while (luaState.next(-2)) {
305 | if (!filterKeys() || acceptKey(-2)) {
306 | key = convertKey(-2);
307 | luaState.pop(3);
308 | return new Entry(key);
309 | }
310 | }
311 | luaState.pop(1);
312 | throw new NoSuchElementException();
313 | }
314 | }
315 |
316 | @Override
317 | public void remove() {
318 | LuaState luaState = getLuaState();
319 | synchronized (luaState) {
320 | pushValue();
321 | luaState.pushJavaObject(key);
322 | luaState.pushNil();
323 | luaState.setTable(-3);
324 | luaState.pop(1);
325 | }
326 | }
327 | }
328 |
329 | /**
330 | * Bindings entry.
331 | */
332 | private class Entry implements Map.Entry {
333 | // -- State
334 | private K key;
335 |
336 | // -- Construction
337 | /**
338 | * Creates a new instance.
339 | */
340 | public Entry(K key) {
341 | this.key = key;
342 | }
343 |
344 | // -- Map.Entry methods
345 | @Override
346 | public K getKey() {
347 | return key;
348 | }
349 |
350 | @Override
351 | public Object getValue() {
352 | return get(key);
353 | }
354 |
355 | @Override
356 | public Object setValue(Object value) {
357 | return put(key, value);
358 | }
359 |
360 | // -- Object methods
361 | @Override
362 | public boolean equals(Object obj) {
363 | if (!(obj instanceof AbstractTableMap>.Entry)) {
364 | return false;
365 | }
366 | @SuppressWarnings("unchecked")
367 | Entry other = (Entry) obj;
368 | return getLuaState() == other.getLuaState()
369 | && key.equals(other.key);
370 | }
371 |
372 | @Override
373 | public int hashCode() {
374 | return getLuaState().hashCode() * 65599 + key.hashCode();
375 | }
376 |
377 | @Override
378 | public String toString() {
379 | return key.toString();
380 | }
381 |
382 | // -- Private methods
383 | /**
384 | * Returns the Lua script engine.
385 | */
386 | private LuaState getLuaState() {
387 | return AbstractTableMap.this.getLuaState();
388 | }
389 | }
390 | }
--------------------------------------------------------------------------------
/jnlua/src/test/java/com/naef/jnlua/test/LuaScriptEngineTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua.test;
7 |
8 | import static org.junit.Assert.assertEquals;
9 | import static org.junit.Assert.assertNotNull;
10 | import static org.junit.Assert.assertNull;
11 | import static org.junit.Assert.assertSame;
12 | import static org.junit.Assert.assertTrue;
13 |
14 | import java.io.StringReader;
15 | import java.util.List;
16 |
17 | import javax.script.Bindings;
18 | import javax.script.Compilable;
19 | import javax.script.CompiledScript;
20 | import javax.script.Invocable;
21 | import javax.script.ScriptContext;
22 | import javax.script.ScriptEngine;
23 | import javax.script.ScriptEngineFactory;
24 | import javax.script.ScriptEngineManager;
25 | import javax.script.ScriptException;
26 | import javax.script.SimpleBindings;
27 | import javax.script.SimpleScriptContext;
28 |
29 | import org.junit.Before;
30 | import org.junit.Test;
31 |
32 | public class LuaScriptEngineTest {
33 | // -- State
34 | private ScriptEngineManager scriptEngineManager;
35 | private ScriptEngine scriptEngine;
36 |
37 | // -- Setup
38 | /**
39 | * Performs setup.
40 | */
41 | @Before
42 | public void setup() throws Exception {
43 | scriptEngineManager = new ScriptEngineManager();
44 | scriptEngine = scriptEngineManager.getEngineByName("Lua");
45 | }
46 |
47 | // -- Test cases
48 | /**
49 | * Tests the acquisition of the Lua script engine from the manager.
50 | */
51 | @Test
52 | public void testAcquisition() {
53 | assertNotNull(scriptEngineManager.getEngineByExtension("lua"));
54 | assertNotNull(scriptEngineManager
55 | .getEngineByMimeType("application/x-lua"));
56 | assertNotNull(scriptEngineManager.getEngineByMimeType("text/x-lua"));
57 | assertNotNull(scriptEngineManager.getEngineByName("lua"));
58 | assertNotNull(scriptEngineManager.getEngineByName("Lua"));
59 | assertNotNull(scriptEngineManager.getEngineByName("jnlua"));
60 | assertNotNull(scriptEngineManager.getEngineByName("JNLua"));
61 | }
62 |
63 | /**
64 | * Tests the Lua script engine factory.
65 | */
66 | @Test
67 | public void testScriptEngineFactory() {
68 | // Get factory
69 | ScriptEngineFactory factory = scriptEngine.getFactory();
70 |
71 | // getEngineName()
72 | assertEquals("JNLua", factory.getEngineName());
73 |
74 | // getEngineVersion()
75 | assertEquals("1.0", factory.getEngineVersion());
76 |
77 | // getNames()
78 | List names = factory.getNames();
79 | assertTrue(names.contains("lua"));
80 | assertTrue(names.contains("Lua"));
81 | assertTrue(names.contains("jnlua"));
82 | assertTrue(names.contains("JNLua"));
83 |
84 | // getLanguageName()
85 | assertEquals("Lua", factory.getLanguageName());
86 |
87 | // getLanguageVersion()
88 | assertEquals("5.2", factory.getLanguageVersion());
89 |
90 | // getExtensions()
91 | List extensions = factory.getExtensions();
92 | assertTrue(extensions.contains("lua"));
93 |
94 | // getMimeTypes()
95 | List mimeTypes = factory.getMimeTypes();
96 | assertTrue(mimeTypes.contains("application/x-lua"));
97 | assertTrue(mimeTypes.contains("text/x-lua"));
98 |
99 | // getParameter()
100 | assertEquals(factory.getEngineName(), factory
101 | .getParameter(ScriptEngine.ENGINE));
102 | assertEquals(factory.getEngineVersion(), factory
103 | .getParameter(ScriptEngine.ENGINE_VERSION));
104 | assertTrue(factory.getNames().contains(
105 | factory.getParameter(ScriptEngine.NAME)));
106 | assertEquals(factory.getLanguageName(), factory
107 | .getParameter(ScriptEngine.LANGUAGE));
108 | assertEquals(factory.getLanguageVersion(), factory
109 | .getParameter(ScriptEngine.LANGUAGE_VERSION));
110 |
111 | // getScriptEngine()
112 | assertNotNull(factory.getScriptEngine());
113 |
114 | // getMethodCallSyntax()
115 | assertEquals("process:execute(a, b)", factory.getMethodCallSyntax(
116 | "process", "execute", "a", "b"));
117 |
118 | // getOutputStatement()
119 | assertEquals("print(\"test\")", factory.getOutputStatement("test"));
120 | assertEquals("print(\"\\\"quoted\\\"\")", factory
121 | .getOutputStatement("\"quoted\""));
122 |
123 | // getProgram()
124 | assertEquals("a = 1\nreturn b\n", factory.getProgram("a = 1",
125 | "return b"));
126 | }
127 |
128 | /**
129 | * Tests the Lua script engine.
130 | */
131 | @Test
132 | public void testScriptEngine() throws Exception {
133 | // eval(String)
134 | assertEquals(Double.valueOf(1.0), scriptEngine.eval("return 1"));
135 |
136 | // eval(Reader)
137 | assertEquals(Double.valueOf(1.0), scriptEngine.eval(new StringReader(
138 | "return 1")));
139 |
140 | // createBindings()
141 | Bindings bindings = scriptEngine.createBindings();
142 | assertNotNull(bindings);
143 |
144 | // eval(String, Bindings)
145 | bindings.put("t", "test1");
146 | assertEquals("test1", scriptEngine.eval("return t", bindings));
147 |
148 | // eval(Reader, Bindings)
149 | bindings.put("t", "test2");
150 | assertEquals("test2", scriptEngine.eval(new StringReader("return t"),
151 | bindings));
152 |
153 | // eval(String, ScriptContext)
154 | ScriptContext context = new SimpleScriptContext();
155 | context.setBindings(new SimpleBindings(), ScriptContext.GLOBAL_SCOPE);
156 | context.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
157 | bindings.put("t", "test3");
158 | assertEquals("test3", scriptEngine.eval("return t", context));
159 |
160 | // eval(Reader, ScriptContext)
161 | bindings.put("t", "test4");
162 | assertEquals("test4", scriptEngine.eval("return t", context));
163 |
164 | // getBindings(), setBindings()
165 | scriptEngine.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
166 | assertSame(bindings, scriptEngine
167 | .getBindings(ScriptContext.ENGINE_SCOPE));
168 | scriptEngine.getBindings(ScriptContext.ENGINE_SCOPE).put("t", "test5");
169 | assertEquals("test5", scriptEngine.eval("return t"));
170 |
171 | // get(), put()
172 | scriptEngine.put("t", "test6");
173 | assertEquals("test6", scriptEngine.get("t"));
174 | assertEquals("test6", bindings.get("t"));
175 | assertEquals("test6", scriptEngine.eval("return t"));
176 |
177 | // getContext(), setContext()
178 | scriptEngine.setContext(context);
179 | assertSame(context, scriptEngine.getContext());
180 | context.setAttribute("t", "test7", ScriptContext.GLOBAL_SCOPE);
181 | context.removeAttribute("t", ScriptContext.ENGINE_SCOPE);
182 | assertEquals("test7", scriptEngine.eval("return t"));
183 |
184 | // getFactory()
185 | assertNotNull(scriptEngine.getFactory());
186 |
187 | // Special variables
188 | scriptEngine.put(ScriptEngine.ARGV, new Object[] { "test8" });
189 | assertEquals("test8", scriptEngine.eval("return ..."));
190 | assertSame(context.getReader(), scriptEngine.eval("return reader"));
191 | assertSame(context.getWriter(), scriptEngine.eval("return writer"));
192 | assertSame(context.getErrorWriter(), scriptEngine
193 | .eval("return errorWriter"));
194 |
195 | // Syntax error diagnostics
196 | scriptEngine.put(ScriptEngine.FILENAME, "test9");
197 | ScriptException scriptException = null;
198 | try {
199 | scriptEngine.eval("a bad script");
200 | } catch (ScriptException e) {
201 | scriptException = e;
202 | }
203 | assertNotNull(scriptException);
204 | assertEquals("test9", scriptException.getFileName());
205 | assertEquals(1, scriptException.getLineNumber());
206 |
207 | // Runtime error diagnostics
208 | scriptException = null;
209 | try {
210 | scriptEngine.eval("error(\"error\")");
211 | } catch (ScriptException e) {
212 | scriptException = e;
213 | }
214 | assertNotNull(scriptException);
215 | assertEquals("test9", scriptException.getFileName());
216 | assertEquals(1, scriptException.getLineNumber());
217 | }
218 |
219 | /**
220 | * Tests the compilable interface.
221 | */
222 | @Test
223 | public void testCompilable() throws Exception {
224 | // Check
225 | assertTrue(scriptEngine instanceof Compilable);
226 | Compilable compilable = (Compilable) scriptEngine;
227 |
228 | // Setup
229 | Bindings bindings = new SimpleBindings();
230 | bindings.put("t", Double.valueOf(2.0));
231 | ScriptContext scriptContext = new SimpleScriptContext();
232 | scriptContext.setBindings(new SimpleBindings(),
233 | ScriptContext.GLOBAL_SCOPE);
234 | scriptContext.setAttribute("t", Double.valueOf(3.0),
235 | ScriptContext.GLOBAL_SCOPE);
236 |
237 | // Compile(String)
238 | CompiledScript compiledScript = compilable.compile("return t");
239 | scriptEngine.put("t", Double.valueOf(1.0));
240 | assertEquals(Double.valueOf(1.0), compiledScript.eval());
241 | assertEquals(Double.valueOf(2.0), compiledScript.eval(bindings));
242 | assertEquals(Double.valueOf(3.0), compiledScript.eval(scriptContext));
243 |
244 | // Compile(Reader)
245 | compiledScript = compilable.compile(new StringReader("return t"));
246 | scriptEngine.put("t", Double.valueOf(1.0));
247 | assertEquals(Double.valueOf(1.0), compiledScript.eval());
248 | assertEquals(Double.valueOf(2.0), compiledScript.eval(bindings));
249 | assertEquals(Double.valueOf(3.0), compiledScript.eval(scriptContext));
250 | }
251 |
252 | /**
253 | * Tests the invocable interface.
254 | */
255 | @Test
256 | public void testIncocable() throws Exception {
257 | // Check
258 | assertTrue(scriptEngine instanceof Invocable);
259 | Invocable invocable = (Invocable) scriptEngine;
260 |
261 | // Setup
262 | scriptEngine.eval("function echo(s) return s end");
263 | scriptEngine.eval("function run() hasRun = true end");
264 | scriptEngine.eval("runnable = { run = run }");
265 |
266 | // invokeFunction()
267 | assertEquals("test", invocable.invokeFunction("echo",
268 | new Object[] { "test" }));
269 |
270 | // invokeMethod()
271 | scriptEngine.put("hasRun", Boolean.FALSE);
272 | assertEquals(Boolean.FALSE, scriptEngine.get("hasRun"));
273 | Object runnableObj = scriptEngine.get("runnable");
274 | invocable.invokeMethod(runnableObj, "run", new Object[0]);
275 | assertEquals(Boolean.TRUE, scriptEngine.get("hasRun"));
276 |
277 | // getInterface()
278 | scriptEngine.put("hasRun", Boolean.FALSE);
279 | assertEquals(Boolean.FALSE, scriptEngine.get("hasRun"));
280 | Runnable runnable = invocable.getInterface(Runnable.class);
281 | Thread thread = new Thread(runnable);
282 | thread.start();
283 | thread.join();
284 | assertEquals(Boolean.TRUE, scriptEngine.get("hasRun"));
285 |
286 | // getInterface(Object)
287 | scriptEngine.put("hasRun", Boolean.FALSE);
288 | assertEquals(Boolean.FALSE, scriptEngine.get("hasRun"));
289 | runnable = invocable.getInterface(runnableObj, Runnable.class);
290 | thread = new Thread(runnable);
291 | thread.start();
292 | thread.join();
293 | assertEquals(Boolean.TRUE, scriptEngine.get("hasRun"));
294 | }
295 |
296 | /**
297 | * Tests the bindings.
298 | */
299 | @Test
300 | public void testBindings() throws Exception {
301 | // Get bindings
302 | Bindings bindings = scriptEngine
303 | .getBindings(ScriptContext.ENGINE_SCOPE);
304 |
305 | // Put
306 | bindings.put("t", "test");
307 | assertEquals("test", scriptEngine.eval("return t"));
308 |
309 | // Get
310 | scriptEngine.eval("t = \"test2\"");
311 | assertEquals("test2", bindings.get("t"));
312 |
313 | // Remove
314 | bindings.remove("t");
315 | assertNull(scriptEngine.eval("return t"));
316 | }
317 | }
318 |
--------------------------------------------------------------------------------
/jnlua/src/main/java/com/naef/jnlua/script/LuaScriptEngine.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua.script;
7 |
8 | import java.io.ByteArrayOutputStream;
9 | import java.io.IOException;
10 | import java.io.InputStream;
11 | import java.io.OutputStream;
12 | import java.io.Reader;
13 | import java.nio.ByteBuffer;
14 | import java.nio.CharBuffer;
15 | import java.nio.charset.Charset;
16 | import java.nio.charset.CharsetEncoder;
17 | import java.util.Map;
18 | import java.util.regex.Matcher;
19 | import java.util.regex.Pattern;
20 |
21 | import javax.script.AbstractScriptEngine;
22 | import javax.script.Bindings;
23 | import javax.script.Compilable;
24 | import javax.script.CompiledScript;
25 | import javax.script.Invocable;
26 | import javax.script.ScriptContext;
27 | import javax.script.ScriptEngineFactory;
28 | import javax.script.ScriptException;
29 |
30 | import com.naef.jnlua.LuaException;
31 | import com.naef.jnlua.LuaState;
32 |
33 | /**
34 | * Lua script engine implementation conforming to JSR 223: Scripting for the
35 | * Java Platform.
36 | */
37 | class LuaScriptEngine extends AbstractScriptEngine implements Compilable,
38 | Invocable {
39 | // -- Static
40 | private static final String READER = "reader";
41 | private static final String WRITER = "writer";
42 | private static final String ERROR_WRITER = "errorWriter";
43 | private static final Pattern LUA_ERROR_MESSAGE = Pattern
44 | .compile("^(.+):(\\d+):");
45 |
46 | // -- State
47 | private LuaScriptEngineFactory factory;
48 | private LuaState luaState;
49 |
50 | // -- Construction
51 | /**
52 | * Creates a new instance.
53 | */
54 | LuaScriptEngine(LuaScriptEngineFactory factory) {
55 | super();
56 | this.factory = factory;
57 | luaState = new LuaState();
58 |
59 | // Configuration
60 | context.setBindings(createBindings(), ScriptContext.ENGINE_SCOPE);
61 | luaState.openLibs();
62 | }
63 |
64 | // -- ScriptEngine methods
65 | @Override
66 | public Bindings createBindings() {
67 | return new LuaBindings(this);
68 | }
69 |
70 | @Override
71 | public Object eval(String script, ScriptContext context)
72 | throws ScriptException {
73 | synchronized (luaState) {
74 | loadChunk(script, context);
75 | return callChunk(context);
76 | }
77 | }
78 |
79 | @Override
80 | public Object eval(Reader reader, ScriptContext context)
81 | throws ScriptException {
82 | synchronized (luaState) {
83 | loadChunk(reader, context);
84 | return callChunk(context);
85 | }
86 | }
87 |
88 | @Override
89 | public ScriptEngineFactory getFactory() {
90 | return factory;
91 | }
92 |
93 | // -- Compilable method
94 | @Override
95 | public CompiledScript compile(String script) throws ScriptException {
96 | ByteArrayOutputStream out = new ByteArrayOutputStream();
97 | synchronized (luaState) {
98 | loadChunk(script, null);
99 | try {
100 | dumpChunk(out);
101 | } finally {
102 | luaState.pop(1);
103 | }
104 | }
105 | return new CompiledLuaScript(this, out.toByteArray());
106 | }
107 |
108 | @Override
109 | public CompiledScript compile(Reader script) throws ScriptException {
110 | ByteArrayOutputStream out = new ByteArrayOutputStream();
111 | synchronized (luaState) {
112 | loadChunk(script, null);
113 | try {
114 | dumpChunk(out);
115 | } finally {
116 | luaState.pop(1);
117 | }
118 | }
119 | return new CompiledLuaScript(this, out.toByteArray());
120 | }
121 |
122 | // -- Invocable methods
123 | @Override
124 | public T getInterface(Class clasz) {
125 | synchronized (luaState) {
126 | getLuaState().rawGet(LuaState.REGISTRYINDEX, LuaState.RIDX_GLOBALS);
127 | try {
128 | return luaState.getProxy(-1, clasz);
129 | } finally {
130 | luaState.pop(1);
131 | }
132 | }
133 | }
134 |
135 | @Override
136 | public T getInterface(Object thiz, Class clasz) {
137 | synchronized (luaState) {
138 | luaState.pushJavaObject(thiz);
139 | try {
140 | if (!luaState.isTable(-1)) {
141 | throw new IllegalArgumentException("object is not a table");
142 | }
143 | return luaState.getProxy(-1, clasz);
144 | } finally {
145 | luaState.pop(1);
146 | }
147 | }
148 | }
149 |
150 | @Override
151 | public Object invokeFunction(String name, Object... args)
152 | throws ScriptException, NoSuchMethodException {
153 | synchronized (luaState) {
154 | luaState.getGlobal(name);
155 | if (!luaState.isFunction(-1)) {
156 | luaState.pop(1);
157 | throw new NoSuchMethodException(String.format(
158 | "function '%s' is undefined", name));
159 | }
160 | for (int i = 0; i < args.length; i++) {
161 | luaState.pushJavaObject(args[i]);
162 | }
163 | luaState.call(args.length, 1);
164 | try {
165 | return luaState.toJavaObject(-1, Object.class);
166 | } finally {
167 | luaState.pop(1);
168 | }
169 | }
170 | }
171 |
172 | @Override
173 | public Object invokeMethod(Object thiz, String name, Object... args)
174 | throws ScriptException, NoSuchMethodException {
175 | synchronized (luaState) {
176 | luaState.pushJavaObject(thiz);
177 | try {
178 | if (!luaState.isTable(-1)) {
179 | throw new IllegalArgumentException("object is not a table");
180 | }
181 | luaState.getField(-1, name);
182 | if (!luaState.isFunction(-1)) {
183 | luaState.pop(1);
184 | throw new NoSuchMethodException(String.format(
185 | "method '%s' is undefined", name));
186 | }
187 | luaState.pushValue(-2);
188 | for (int i = 0; i < args.length; i++) {
189 | luaState.pushJavaObject(args[i]);
190 | }
191 | luaState.call(args.length + 1, 1);
192 | try {
193 | return luaState.toJavaObject(-1, Object.class);
194 | } finally {
195 | luaState.pop(1);
196 | }
197 | } finally {
198 | luaState.pop(1);
199 | }
200 | }
201 | }
202 |
203 | // -- Package private methods
204 | /**
205 | * Returns the Lua state.
206 | */
207 | LuaState getLuaState() {
208 | return luaState;
209 | }
210 |
211 | /**
212 | * Loads a chunk from a string.
213 | */
214 | void loadChunk(String string, ScriptContext scriptContext)
215 | throws ScriptException {
216 | try {
217 | luaState.load(string, getChunkName(scriptContext));
218 | } catch (LuaException e) {
219 | throw getScriptException(e);
220 | }
221 | }
222 |
223 | /**
224 | * Loads a chunk from a reader.
225 | */
226 | void loadChunk(Reader reader, ScriptContext scriptContext)
227 | throws ScriptException {
228 | loadChunk(new ReaderInputStream(reader), scriptContext, "t");
229 | }
230 |
231 | /**
232 | * Loads a chunk from an input stream.
233 | */
234 | void loadChunk(InputStream inputStream, ScriptContext scriptContext,
235 | String mode) throws ScriptException {
236 | try {
237 | luaState.load(inputStream, getChunkName(scriptContext), mode);
238 | } catch (LuaException e) {
239 | throw getScriptException(e);
240 | } catch (IOException e) {
241 | throw new ScriptException(e);
242 | }
243 | }
244 |
245 | /**
246 | * Calls a loaded chunk.
247 | */
248 | Object callChunk(ScriptContext context) throws ScriptException {
249 | try {
250 | // Apply context
251 | Object[] argv;
252 | if (context != null) {
253 | // Global bindings
254 | Bindings bindings;
255 | bindings = context.getBindings(ScriptContext.GLOBAL_SCOPE);
256 | if (bindings != null) {
257 | applyBindings(bindings);
258 | }
259 |
260 | // Engine bindings
261 | bindings = context.getBindings(ScriptContext.ENGINE_SCOPE);
262 | if (bindings != null) {
263 | if (bindings instanceof LuaBindings
264 | && ((LuaBindings) bindings).getScriptEngine() == this) {
265 | // No need to apply our own live bindings
266 | } else {
267 | applyBindings(bindings);
268 | }
269 | }
270 |
271 | // Readers and writers
272 | put(READER, context.getReader());
273 | put(WRITER, context.getWriter());
274 | put(ERROR_WRITER, context.getErrorWriter());
275 |
276 | // Arguments
277 | argv = (Object[]) context.getAttribute(ARGV);
278 | } else {
279 | argv = null;
280 | }
281 |
282 | // Push arguments
283 | int argCount = argv != null ? argv.length : 0;
284 | for (int i = 0; i < argCount; i++) {
285 | luaState.pushJavaObject(argv[i]);
286 | }
287 |
288 | // Call
289 | luaState.call(argCount, 1);
290 |
291 | // Return
292 | try {
293 | return luaState.toJavaObject(1, Object.class);
294 | } finally {
295 | luaState.pop(1);
296 | }
297 | } catch (LuaException e) {
298 | throw getScriptException(e);
299 | }
300 | }
301 |
302 | /**
303 | * Dumps a loaded chunk into an output stream. The chunk is left on the
304 | * stack.
305 | */
306 | void dumpChunk(OutputStream out) throws ScriptException {
307 | try {
308 | luaState.dump(out);
309 | } catch (LuaException e) {
310 | throw new ScriptException(e);
311 | } catch (IOException e) {
312 | throw new ScriptException(e);
313 | }
314 |
315 | }
316 |
317 | // -- Private methods
318 | /**
319 | * Sets a single binding in a Lua state.
320 | */
321 | private void applyBindings(Bindings bindings) {
322 | for (Map.Entry binding : bindings.entrySet()) {
323 | luaState.pushJavaObject(binding.getValue());
324 | String variableName = binding.getKey();
325 | int lastDotIndex = variableName.lastIndexOf('.');
326 | if (lastDotIndex >= 0) {
327 | variableName = variableName.substring(lastDotIndex + 1);
328 | }
329 | luaState.setGlobal(variableName);
330 | }
331 | }
332 |
333 | /**
334 | * Returns the Lua chunk name from a script context.
335 | */
336 | private String getChunkName(ScriptContext context) {
337 | if (context != null) {
338 | Object fileName = context.getAttribute(FILENAME);
339 | if (fileName != null) {
340 | return "@" + fileName.toString();
341 | }
342 | }
343 | return "=null";
344 | }
345 |
346 | /**
347 | * Returns a script exception for a Lua exception.
348 | */
349 | private ScriptException getScriptException(LuaException e) {
350 | Matcher matcher = LUA_ERROR_MESSAGE.matcher(e.getMessage());
351 | if (matcher.find()) {
352 | String fileName = matcher.group(1);
353 | int lineNumber = Integer.parseInt(matcher.group(2));
354 | return new ScriptException(e.getMessage(), fileName, lineNumber);
355 | } else {
356 | return new ScriptException(e);
357 | }
358 | }
359 |
360 | // -- Private classes
361 | /**
362 | * Provides an UTF-8 input stream based on a reader.
363 | */
364 | private static class ReaderInputStream extends InputStream {
365 | // -- Static
366 | private static final Charset UTF8 = Charset.forName("UTF-8");
367 |
368 | // -- State
369 | private Reader reader;
370 | private CharsetEncoder encoder;
371 | private boolean flushed;
372 | private CharBuffer charBuffer = CharBuffer.allocate(1024);
373 | private ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
374 |
375 | /**
376 | * Creates a new instance.
377 | */
378 | public ReaderInputStream(Reader reader) {
379 | this.reader = reader;
380 | encoder = UTF8.newEncoder();
381 | charBuffer.limit(0);
382 | byteBuffer.limit(0);
383 | }
384 |
385 | @Override
386 | public int read() throws IOException {
387 | if (!byteBuffer.hasRemaining()) {
388 | if (!charBuffer.hasRemaining()) {
389 | charBuffer.clear();
390 | reader.read(charBuffer);
391 | charBuffer.flip();
392 | }
393 | byteBuffer.clear();
394 | if (charBuffer.hasRemaining()) {
395 | if (encoder.encode(charBuffer, byteBuffer, false).isError()) {
396 | throw new IOException("Encoding error");
397 | }
398 | } else {
399 | if (!flushed) {
400 | if (encoder.encode(charBuffer, byteBuffer, true)
401 | .isError()) {
402 | throw new IOException("Encoding error");
403 | }
404 | if (encoder.flush(byteBuffer).isError()) {
405 | throw new IOException("Encoding error");
406 | }
407 | flushed = true;
408 | }
409 | }
410 | byteBuffer.flip();
411 | if (!byteBuffer.hasRemaining()) {
412 | return -1;
413 | }
414 | }
415 | return byteBuffer.get();
416 | }
417 | }
418 | }
419 |
--------------------------------------------------------------------------------
/jnlua/src/main/java/com/naef/jnlua/DefaultConverter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua;
7 |
8 | import java.lang.reflect.Array;
9 | import java.math.BigDecimal;
10 | import java.math.BigInteger;
11 | import java.util.HashMap;
12 | import java.util.List;
13 | import java.util.Map;
14 |
15 | import com.naef.jnlua.util.AbstractTableList;
16 | import com.naef.jnlua.util.AbstractTableMap;
17 |
18 | /**
19 | * Default implementation of the Converter interface.
20 | */
21 | public class DefaultConverter implements Converter {
22 | // -- Static
23 | /**
24 | * Raw byte array.
25 | */
26 | private static final boolean RAW_BYTE_ARRAY = Boolean.parseBoolean(System
27 | .getProperty(DefaultConverter.class.getPackage().getName()
28 | + ".rawByteArray"));
29 |
30 | /**
31 | * Static instance.
32 | */
33 | private static final DefaultConverter INSTANCE = new DefaultConverter();
34 |
35 | /**
36 | * Boolean distance map.
37 | */
38 | private static final Map, Integer> BOOLEAN_DISTANCE_MAP = new HashMap, Integer>();
39 | static {
40 | BOOLEAN_DISTANCE_MAP.put(Boolean.class, new Integer(1));
41 | BOOLEAN_DISTANCE_MAP.put(Boolean.TYPE, new Integer(1));
42 | BOOLEAN_DISTANCE_MAP.put(Object.class, new Integer(2));
43 | }
44 |
45 | /**
46 | * Number distance map.
47 | */
48 | private static final Map, Integer> NUMBER_DISTANCE_MAP = new HashMap, Integer>();
49 | static {
50 | NUMBER_DISTANCE_MAP.put(Byte.class, new Integer(1));
51 | NUMBER_DISTANCE_MAP.put(Byte.TYPE, new Integer(1));
52 | NUMBER_DISTANCE_MAP.put(Short.class, new Integer(1));
53 | NUMBER_DISTANCE_MAP.put(Short.TYPE, new Integer(1));
54 | NUMBER_DISTANCE_MAP.put(Integer.class, new Integer(1));
55 | NUMBER_DISTANCE_MAP.put(Integer.TYPE, new Integer(1));
56 | NUMBER_DISTANCE_MAP.put(Long.class, new Integer(1));
57 | NUMBER_DISTANCE_MAP.put(Long.TYPE, new Integer(1));
58 | NUMBER_DISTANCE_MAP.put(Float.class, new Integer(1));
59 | NUMBER_DISTANCE_MAP.put(Float.TYPE, new Integer(1));
60 | NUMBER_DISTANCE_MAP.put(Double.class, new Integer(1));
61 | NUMBER_DISTANCE_MAP.put(Double.TYPE, new Integer(1));
62 | NUMBER_DISTANCE_MAP.put(BigInteger.class, new Integer(1));
63 | NUMBER_DISTANCE_MAP.put(BigDecimal.class, new Integer(1));
64 | NUMBER_DISTANCE_MAP.put(Character.class, new Integer(1));
65 | NUMBER_DISTANCE_MAP.put(Character.TYPE, new Integer(1));
66 | NUMBER_DISTANCE_MAP.put(Object.class, new Integer(2));
67 | NUMBER_DISTANCE_MAP.put(String.class, new Integer(3));
68 | if (!RAW_BYTE_ARRAY) {
69 | NUMBER_DISTANCE_MAP.put(byte[].class, new Integer(3));
70 | }
71 | }
72 |
73 | /**
74 | * String distance map.
75 | */
76 | private static final Map, Integer> STRING_DISTANCE_MAP = new HashMap, Integer>();
77 | static {
78 | STRING_DISTANCE_MAP.put(String.class, new Integer(1));
79 | if (!RAW_BYTE_ARRAY) {
80 | STRING_DISTANCE_MAP.put(byte[].class, new Integer(1));
81 | }
82 | STRING_DISTANCE_MAP.put(Object.class, new Integer(2));
83 | STRING_DISTANCE_MAP.put(Byte.class, new Integer(3));
84 | STRING_DISTANCE_MAP.put(Byte.TYPE, new Integer(3));
85 | STRING_DISTANCE_MAP.put(Short.class, new Integer(3));
86 | STRING_DISTANCE_MAP.put(Short.TYPE, new Integer(3));
87 | STRING_DISTANCE_MAP.put(Integer.class, new Integer(3));
88 | STRING_DISTANCE_MAP.put(Integer.TYPE, new Integer(3));
89 | STRING_DISTANCE_MAP.put(Long.class, new Integer(3));
90 | STRING_DISTANCE_MAP.put(Long.TYPE, new Integer(3));
91 | STRING_DISTANCE_MAP.put(Float.class, new Integer(3));
92 | STRING_DISTANCE_MAP.put(Float.TYPE, new Integer(3));
93 | STRING_DISTANCE_MAP.put(Double.class, new Integer(3));
94 | STRING_DISTANCE_MAP.put(Double.TYPE, new Integer(3));
95 | STRING_DISTANCE_MAP.put(BigInteger.class, new Integer(3));
96 | STRING_DISTANCE_MAP.put(BigDecimal.class, new Integer(3));
97 | STRING_DISTANCE_MAP.put(Character.class, new Integer(3));
98 | STRING_DISTANCE_MAP.put(Character.TYPE, new Integer(3));
99 | }
100 |
101 | /**
102 | * Function distance map.
103 | */
104 | private static final Map, Integer> FUNCTION_DISTANCE_MAP = new HashMap, Integer>();
105 | static {
106 | FUNCTION_DISTANCE_MAP.put(JavaFunction.class, new Integer(1));
107 | FUNCTION_DISTANCE_MAP.put(Object.class, new Integer(2));
108 | }
109 |
110 | /**
111 | * Lua value converters.
112 | */
113 | private static final Map, LuaValueConverter>> LUA_VALUE_CONVERTERS = new HashMap, LuaValueConverter>>();
114 | static {
115 | LuaValueConverter booleanConverter = new LuaValueConverter() {
116 | @Override
117 | public Boolean convert(LuaState luaState, int index) {
118 | return Boolean.valueOf(luaState.toBoolean(index));
119 | }
120 | };
121 | LUA_VALUE_CONVERTERS.put(Boolean.class, booleanConverter);
122 | LUA_VALUE_CONVERTERS.put(Boolean.TYPE, booleanConverter);
123 |
124 | LuaValueConverter byteConverter = new LuaValueConverter() {
125 | @Override
126 | public Byte convert(LuaState luaState, int index) {
127 | return Byte.valueOf((byte) luaState.toInteger(index));
128 | }
129 | };
130 | LUA_VALUE_CONVERTERS.put(Byte.class, byteConverter);
131 | LUA_VALUE_CONVERTERS.put(Byte.TYPE, byteConverter);
132 | LuaValueConverter shortConverter = new LuaValueConverter() {
133 | @Override
134 | public Short convert(LuaState luaState, int index) {
135 | return Short.valueOf((short) luaState.toInteger(index));
136 | }
137 | };
138 | LUA_VALUE_CONVERTERS.put(Short.class, shortConverter);
139 | LUA_VALUE_CONVERTERS.put(Short.TYPE, shortConverter);
140 | LuaValueConverter integerConverter = new LuaValueConverter() {
141 | @Override
142 | public Integer convert(LuaState luaState, int index) {
143 | return Integer.valueOf(luaState.toInteger(index));
144 | }
145 | };
146 | LUA_VALUE_CONVERTERS.put(Integer.class, integerConverter);
147 | LUA_VALUE_CONVERTERS.put(Integer.TYPE, integerConverter);
148 | LuaValueConverter longConverter = new LuaValueConverter() {
149 | @Override
150 | public Long convert(LuaState luaState, int index) {
151 | return Long.valueOf((long) luaState.toNumber(index));
152 | }
153 | };
154 | LUA_VALUE_CONVERTERS.put(Long.class, longConverter);
155 | LUA_VALUE_CONVERTERS.put(Long.TYPE, longConverter);
156 | LuaValueConverter floatConverter = new LuaValueConverter() {
157 | @Override
158 | public Float convert(LuaState luaState, int index) {
159 | return Float.valueOf((float) luaState.toNumber(index));
160 | }
161 | };
162 | LUA_VALUE_CONVERTERS.put(Float.class, floatConverter);
163 | LUA_VALUE_CONVERTERS.put(Float.TYPE, floatConverter);
164 | LuaValueConverter doubleConverter = new LuaValueConverter() {
165 | @Override
166 | public Double convert(LuaState luaState, int index) {
167 | return Double.valueOf(luaState.toNumber(index));
168 | }
169 | };
170 | LUA_VALUE_CONVERTERS.put(Double.class, doubleConverter);
171 | LUA_VALUE_CONVERTERS.put(Double.TYPE, doubleConverter);
172 | LuaValueConverter bigIntegerConverter = new LuaValueConverter() {
173 | @Override
174 | public BigInteger convert(LuaState luaState, int index) {
175 | return BigDecimal.valueOf(luaState.toNumber(index))
176 | .setScale(0, BigDecimal.ROUND_HALF_EVEN).toBigInteger();
177 | }
178 | };
179 | LUA_VALUE_CONVERTERS.put(BigInteger.class, bigIntegerConverter);
180 | LuaValueConverter bigDecimalConverter = new LuaValueConverter() {
181 | @Override
182 | public BigDecimal convert(LuaState luaState, int index) {
183 | return BigDecimal.valueOf(luaState.toNumber(index));
184 | }
185 | };
186 | LUA_VALUE_CONVERTERS.put(BigDecimal.class, bigDecimalConverter);
187 | LuaValueConverter characterConverter = new LuaValueConverter() {
188 | @Override
189 | public Character convert(LuaState luaState, int index) {
190 | return Character.valueOf((char) luaState.toInteger(index));
191 | }
192 | };
193 | LUA_VALUE_CONVERTERS.put(Character.class, characterConverter);
194 | LUA_VALUE_CONVERTERS.put(Character.TYPE, characterConverter);
195 | LuaValueConverter stringConverter = new LuaValueConverter() {
196 | @Override
197 | public String convert(LuaState luaState, int index) {
198 | return luaState.toString(index);
199 | }
200 | };
201 | LUA_VALUE_CONVERTERS.put(String.class, stringConverter);
202 | if (!RAW_BYTE_ARRAY) {
203 | LuaValueConverter byteArrayConverter = new LuaValueConverter() {
204 | @Override
205 | public byte[] convert(LuaState luaState, int index) {
206 | return luaState.toByteArray(index);
207 | }
208 | };
209 | LUA_VALUE_CONVERTERS.put(byte[].class, byteArrayConverter);
210 | }
211 | }
212 |
213 | /**
214 | * Java object converters.
215 | */
216 | private static final Map, JavaObjectConverter>> JAVA_OBJECT_CONVERTERS = new HashMap, JavaObjectConverter>>();
217 | static {
218 | JavaObjectConverter booleanConverter = new JavaObjectConverter() {
219 | @Override
220 | public void convert(LuaState luaState, Boolean booleanValue) {
221 | luaState.pushBoolean(booleanValue.booleanValue());
222 | }
223 | };
224 | JAVA_OBJECT_CONVERTERS.put(Boolean.class, booleanConverter);
225 | JAVA_OBJECT_CONVERTERS.put(Boolean.TYPE, booleanConverter);
226 | JavaObjectConverter numberConverter = new JavaObjectConverter() {
227 | @Override
228 | public void convert(LuaState luaState, Number number) {
229 | luaState.pushNumber(number.doubleValue());
230 | }
231 | };
232 | JAVA_OBJECT_CONVERTERS.put(Byte.class, numberConverter);
233 | JAVA_OBJECT_CONVERTERS.put(Byte.TYPE, numberConverter);
234 | JAVA_OBJECT_CONVERTERS.put(Short.class, numberConverter);
235 | JAVA_OBJECT_CONVERTERS.put(Short.TYPE, numberConverter);
236 | JAVA_OBJECT_CONVERTERS.put(Integer.class, numberConverter);
237 | JAVA_OBJECT_CONVERTERS.put(Integer.TYPE, numberConverter);
238 | JAVA_OBJECT_CONVERTERS.put(Long.class, numberConverter);
239 | JAVA_OBJECT_CONVERTERS.put(Long.TYPE, numberConverter);
240 | JAVA_OBJECT_CONVERTERS.put(Float.class, numberConverter);
241 | JAVA_OBJECT_CONVERTERS.put(Float.TYPE, numberConverter);
242 | JAVA_OBJECT_CONVERTERS.put(Double.class, numberConverter);
243 | JAVA_OBJECT_CONVERTERS.put(Double.TYPE, numberConverter);
244 | JAVA_OBJECT_CONVERTERS.put(BigInteger.class, numberConverter);
245 | JAVA_OBJECT_CONVERTERS.put(BigDecimal.class, numberConverter);
246 | JavaObjectConverter characterConverter = new JavaObjectConverter() {
247 | @Override
248 | public void convert(LuaState luaState, Character character) {
249 | luaState.pushInteger(character.charValue());
250 | }
251 | };
252 | JAVA_OBJECT_CONVERTERS.put(Character.class, characterConverter);
253 | JAVA_OBJECT_CONVERTERS.put(Character.TYPE, characterConverter);
254 | JavaObjectConverter stringConverter = new JavaObjectConverter() {
255 | @Override
256 | public void convert(LuaState luaState, String string) {
257 | luaState.pushString(string);
258 | }
259 | };
260 | JAVA_OBJECT_CONVERTERS.put(String.class, stringConverter);
261 | if (!RAW_BYTE_ARRAY) {
262 | JavaObjectConverter byteArrayConverter = new JavaObjectConverter() {
263 | @Override
264 | public void convert(LuaState luaState, byte[] byteArray) {
265 | luaState.pushByteArray(byteArray);
266 | }
267 | };
268 | JAVA_OBJECT_CONVERTERS.put(byte[].class, byteArrayConverter);
269 | }
270 | }
271 |
272 | // -- Static methods
273 | /**
274 | * Returns the instance of this class.
275 | *
276 | * @return the instance
277 | */
278 | public static DefaultConverter getInstance() {
279 | return INSTANCE;
280 | }
281 |
282 | // -- Construction
283 | /**
284 | * Singleton.
285 | */
286 | private DefaultConverter() {
287 | }
288 |
289 | // -- Java converter methods
290 | @Override
291 | public int getTypeDistance(LuaState luaState, int index, Class> formalType) {
292 | // Handle none
293 | LuaType luaType = luaState.type(index);
294 | if (luaType == null) {
295 | return Integer.MAX_VALUE;
296 | }
297 |
298 | // Handle void
299 | if (formalType == Void.TYPE) {
300 | return Integer.MAX_VALUE;
301 | }
302 |
303 | // Handle Lua value proxy
304 | if (formalType == LuaValueProxy.class) {
305 | return 0;
306 | }
307 |
308 | // Handle Lua types
309 | switch (luaType) {
310 | case NIL:
311 | return 1;
312 | case BOOLEAN:
313 | Integer distance = BOOLEAN_DISTANCE_MAP.get(formalType);
314 | if (distance != null) {
315 | return distance.intValue();
316 | }
317 | break;
318 | case NUMBER:
319 | distance = NUMBER_DISTANCE_MAP.get(formalType);
320 | if (distance != null) {
321 | return distance.intValue();
322 | }
323 | break;
324 | case STRING:
325 | distance = STRING_DISTANCE_MAP.get(formalType);
326 | if (distance != null) {
327 | return distance.intValue();
328 | }
329 | break;
330 | case TABLE:
331 | if (formalType == Map.class || formalType == List.class
332 | || formalType.isArray()) {
333 | return 1;
334 | }
335 | if (formalType == Object.class) {
336 | return 2;
337 | }
338 | break;
339 | case FUNCTION:
340 | if (luaState.isJavaFunction(index)) {
341 | distance = FUNCTION_DISTANCE_MAP.get(formalType);
342 | if (distance != null) {
343 | return distance.intValue();
344 | }
345 | }
346 | break;
347 | case USERDATA:
348 | Object object = luaState.toJavaObjectRaw(index);
349 | if (object != null) {
350 | Class> type;
351 | if (object instanceof TypedJavaObject) {
352 | TypedJavaObject typedJavaObject = (TypedJavaObject) object;
353 | if (typedJavaObject.isStrong()) {
354 | if (formalType.isAssignableFrom(typedJavaObject
355 | .getClass())) {
356 | return 1;
357 | }
358 | }
359 | type = typedJavaObject.getType();
360 | } else {
361 | type = object.getClass();
362 | }
363 | if (formalType.isAssignableFrom(type)) {
364 | return 1;
365 | }
366 | }
367 | break;
368 | }
369 |
370 | // Handle object
371 | if (formalType == Object.class) {
372 | return Integer.MAX_VALUE - 1;
373 | }
374 |
375 | // Unsupported conversion
376 | return Integer.MAX_VALUE;
377 | }
378 |
379 | @SuppressWarnings("unchecked")
380 | @Override
381 | public T convertLuaValue(LuaState luaState, int index,
382 | Class formalType) {
383 | // Handle none
384 | LuaType luaType = luaState.type(index);
385 | if (luaType == null) {
386 | throw new IllegalArgumentException("undefined index: " + index);
387 | }
388 |
389 | // Handle void
390 | if (formalType == Void.TYPE) {
391 | throw new ClassCastException(String.format(
392 | "cannot convert %s to %s", luaState.typeName(index),
393 | formalType.getCanonicalName()));
394 | }
395 |
396 | // Handle Lua value proxy
397 | if (formalType == LuaValueProxy.class) {
398 | return (T) luaState.getProxy(index);
399 | }
400 |
401 | // Handle Lua types
402 | switch (luaType) {
403 | case NIL:
404 | return null;
405 | case BOOLEAN:
406 | LuaValueConverter> luaValueConverter;
407 | luaValueConverter = LUA_VALUE_CONVERTERS.get(formalType);
408 | if (luaValueConverter != null) {
409 | return (T) luaValueConverter.convert(luaState, index);
410 | }
411 | if (formalType == Object.class) {
412 | return (T) Boolean.valueOf(luaState.toBoolean(index));
413 | }
414 | break;
415 | case NUMBER:
416 | luaValueConverter = LUA_VALUE_CONVERTERS.get(formalType);
417 | if (luaValueConverter != null) {
418 | return (T) luaValueConverter.convert(luaState, index);
419 | }
420 | if (formalType == Object.class) {
421 | return (T) Double.valueOf(luaState.toNumber(index));
422 | }
423 | break;
424 | case STRING:
425 | luaValueConverter = LUA_VALUE_CONVERTERS.get(formalType);
426 | if (luaValueConverter != null) {
427 | return (T) luaValueConverter.convert(luaState, index);
428 | }
429 | if (formalType == Object.class) {
430 | return (T) luaState.toString(index);
431 | }
432 | break;
433 | case TABLE:
434 | if (formalType == Map.class || formalType == Object.class) {
435 | final LuaValueProxy luaValueProxy = luaState.getProxy(index);
436 | return (T) new AbstractTableMap() {
437 | @Override
438 | protected Object convertKey(int index) {
439 | return getLuaState().toJavaObject(index, Object.class);
440 | }
441 |
442 | @Override
443 | public LuaState getLuaState() {
444 | return luaValueProxy.getLuaState();
445 | }
446 |
447 | @Override
448 | public void pushValue() {
449 | luaValueProxy.pushValue();
450 | }
451 | };
452 | }
453 | if (formalType == List.class) {
454 | final LuaValueProxy luaValueProxy = luaState.getProxy(index);
455 | return (T) new AbstractTableList() {
456 | @Override
457 | public LuaState getLuaState() {
458 | return luaValueProxy.getLuaState();
459 | }
460 |
461 | @Override
462 | public void pushValue() {
463 | luaValueProxy.pushValue();
464 | }
465 | };
466 | }
467 | if (formalType.isArray()) {
468 | int length = luaState.rawLen(index);
469 | Class> componentType = formalType.getComponentType();
470 | Object array = Array.newInstance(formalType.getComponentType(),
471 | length);
472 | for (int i = 0; i < length; i++) {
473 | luaState.rawGet(index, i + 1);
474 | try {
475 | Array.set(array, i,
476 | convertLuaValue(luaState, -1, componentType));
477 | } finally {
478 | luaState.pop(1);
479 | }
480 | }
481 | return (T) array;
482 | }
483 | break;
484 | case FUNCTION:
485 | if (luaState.isJavaFunction(index)) {
486 | if (formalType == JavaFunction.class
487 | || formalType == Object.class) {
488 | return (T) luaState.toJavaFunction(index);
489 | }
490 | }
491 | break;
492 | case USERDATA:
493 | Object object = luaState.toJavaObjectRaw(index);
494 | if (object != null) {
495 | if (object instanceof TypedJavaObject) {
496 | TypedJavaObject typedJavaObject = (TypedJavaObject) object;
497 | if (typedJavaObject.isStrong()) {
498 | if (formalType.isAssignableFrom(typedJavaObject
499 | .getClass())) {
500 | return (T) typedJavaObject;
501 | }
502 | }
503 | return (T) ((TypedJavaObject) object).getObject();
504 | } else {
505 | return (T) object;
506 | }
507 | }
508 | break;
509 | }
510 |
511 | // Handle object
512 | if (formalType == Object.class) {
513 | return (T) luaState.getProxy(index);
514 | }
515 |
516 | // Unsupported conversion
517 | throw new ClassCastException(String.format("cannot convert %s to %s",
518 | luaState.typeName(index), formalType.getCanonicalName()));
519 | }
520 |
521 | @SuppressWarnings("unchecked")
522 | @Override
523 | public void convertJavaObject(LuaState luaState, Object object) {
524 | // Handle null
525 | if (object == null) {
526 | luaState.pushNil();
527 | return;
528 | }
529 |
530 | // Handle known Java types
531 | JavaObjectConverter javaObjectConverter = (JavaObjectConverter) JAVA_OBJECT_CONVERTERS
532 | .get(object.getClass());
533 | if (javaObjectConverter != null) {
534 | javaObjectConverter.convert(luaState, object);
535 | return;
536 | }
537 | if (object instanceof JavaFunction) {
538 | luaState.pushJavaFunction((JavaFunction) object);
539 | return;
540 | }
541 | if (object instanceof LuaValueProxy) {
542 | LuaValueProxy luaValueProxy = (LuaValueProxy) object;
543 | if (!luaValueProxy.getLuaState().equals(luaState)) {
544 | throw new IllegalArgumentException(
545 | "Lua value proxy is from a different Lua state");
546 | }
547 | luaValueProxy.pushValue();
548 | return;
549 | }
550 |
551 | // Push as is
552 | luaState.pushJavaObjectRaw(object);
553 | }
554 |
555 | // -- Nested types
556 | /**
557 | * Converts Lua values.
558 | */
559 | private interface LuaValueConverter {
560 | /**
561 | * Converts a Lua value to a Java object.
562 | */
563 | public T convert(LuaState luaState, int index);
564 | }
565 |
566 | /**
567 | * Converts Java object.
568 | */
569 | private interface JavaObjectConverter {
570 | /**
571 | * Converts a Java object to a Lua value.
572 | */
573 | public void convert(LuaState luaState, T object);
574 | }
575 | }
576 |
--------------------------------------------------------------------------------
/jnlua/src/main/java/com/naef/jnlua/JavaModule.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua;
7 |
8 | import java.lang.reflect.Array;
9 | import java.util.HashMap;
10 | import java.util.Iterator;
11 | import java.util.List;
12 | import java.util.Map;
13 |
14 | import com.naef.jnlua.JavaReflector.Metamethod;
15 |
16 | /**
17 | * Provides the Java module for Lua. The Java module contains Java functions for
18 | * using Java in Lua.
19 | */
20 | public class JavaModule {
21 | // -- Static
22 | private static final JavaModule INSTANCE = new JavaModule();
23 | private static final Map> PRIMITIVE_TYPES = new HashMap>();
24 | static {
25 | PRIMITIVE_TYPES.put("boolean", Boolean.TYPE);
26 | PRIMITIVE_TYPES.put("byte", Byte.TYPE);
27 | PRIMITIVE_TYPES.put("char", Character.TYPE);
28 | PRIMITIVE_TYPES.put("double", Double.TYPE);
29 | PRIMITIVE_TYPES.put("float", Float.TYPE);
30 | PRIMITIVE_TYPES.put("int", Integer.TYPE);
31 | PRIMITIVE_TYPES.put("long", Long.TYPE);
32 | PRIMITIVE_TYPES.put("short", Short.TYPE);
33 | PRIMITIVE_TYPES.put("void", Void.TYPE);
34 | }
35 |
36 | // -- State
37 | private final NamedJavaFunction[] functions = { new Require(), new New(),
38 | new InstanceOf(), new Cast(), new Proxy(), new Pairs(),
39 | new IPairs(), new ToTable(), new Elements(), new Fields(),
40 | new Methods(), new Properties() };
41 |
42 | // -- Static methods
43 | /**
44 | * Returns the instance of the Java module.
45 | *
46 | * @return the instance
47 | */
48 | public static JavaModule getInstance() {
49 | return INSTANCE;
50 | }
51 |
52 | // -- Construction
53 | /**
54 | * Singleton.
55 | */
56 | private JavaModule() {
57 | }
58 |
59 | // -- Operations
60 | /**
61 | * Opens this module in a Lua state. The method is invoked by
62 | * {@link LuaState#openLibs()} or by
63 | * {@link LuaState#openLib(com.naef.jnlua.LuaState.Library)} if
64 | * {@link LuaState.Library#JAVA} is passed. The module is pushed onto the
65 | * stack.
66 | *
67 | * @param luaState
68 | * the Lua state to open in
69 | */
70 | public void open(LuaState luaState) {
71 | luaState.register("java", functions, true);
72 | }
73 |
74 | /**
75 | * Returns a table-like Lua value for the specified map. The returned value
76 | * corresponds to the return value of the totable() function
77 | * provided by this Java module.
78 | *
79 | * @param map
80 | * the map
81 | * @return the table-like Lua value
82 | */
83 | public TypedJavaObject toTable(Map, ?> map) {
84 | return ToTable.toTable(map);
85 | }
86 |
87 | /**
88 | * Returns a table-like Lua value for the specified list. The returned value
89 | * corresponds to the return value of the totable() function
90 | * provided by this Java module.
91 | *
92 | * @param list
93 | * the list
94 | * @return the table-like Lua value
95 | */
96 | public TypedJavaObject toTable(List> list) {
97 | return ToTable.toTable(list);
98 | }
99 |
100 | // -- Private methods
101 | /**
102 | * Loads a type. The named type is a primitive type or a class.
103 | */
104 | private static Class> loadType(LuaState luaState, String typeName) {
105 | Class> clazz;
106 | if ((clazz = PRIMITIVE_TYPES.get(typeName)) != null) {
107 | return clazz;
108 | }
109 | try {
110 | clazz = luaState.getClassLoader().loadClass(typeName);
111 | return clazz;
112 | } catch (ClassNotFoundException e) {
113 | throw new RuntimeException(e);
114 | }
115 | }
116 |
117 | // -- Nested types
118 | /**
119 | * Imports a Java class into the Lua namespace. Returns the class and a
120 | * status code. The status code indicates if the class was stored in the Lua
121 | * namespace. Primitive types and classes without a package are not stored
122 | * in the Lua namespace.
123 | */
124 | private static class Require implements NamedJavaFunction {
125 | // -- JavaFunction methods
126 | @Override
127 | public int invoke(LuaState luaState) {
128 | // Check arguments
129 | String className = luaState.checkString(1);
130 | boolean doImport = luaState.toBoolean(2);
131 |
132 | // Load
133 | Class> clazz = loadType(luaState, className);
134 | luaState.pushJavaObject(clazz);
135 |
136 | // Import
137 | if (doImport) {
138 | luaState.rawGet(LuaState.REGISTRYINDEX, LuaState.RIDX_GLOBALS);
139 | String name = clazz.getName();
140 | int index = name.indexOf('.');
141 | while (index >= 0) {
142 | String part = name.substring(0, index);
143 | luaState.getField(-1, part);
144 | if (!luaState.isTable(-1)) {
145 | luaState.pop(1);
146 | luaState.newTable();
147 | luaState.pushValue(-1);
148 | luaState.setField(-3, part);
149 | }
150 | luaState.remove(-2);
151 | name = name.substring(index + 1);
152 | index = name.indexOf('.');
153 | }
154 | luaState.pushValue(-2);
155 | luaState.setField(-2, name);
156 | luaState.pop(1);
157 | }
158 | luaState.pushBoolean(doImport);
159 |
160 | // Return
161 | return 2;
162 | }
163 |
164 | @Override
165 | public String getName() {
166 | return "require";
167 | }
168 | }
169 |
170 | /**
171 | * Creates and returns a new Java object or array thereof. The first
172 | * argument designates the type to instantiate, either as a class or a
173 | * string. The remaining arguments are the dimensions.
174 | */
175 | private static class New implements NamedJavaFunction {
176 | // -- JavaFunction methods
177 | @Override
178 | public int invoke(LuaState luaState) {
179 | // Find class
180 | Class> clazz;
181 | if (luaState.isJavaObject(1, Class.class)) {
182 | clazz = luaState.checkJavaObject(1, Class.class);
183 | } else {
184 | String className = luaState.checkString(1);
185 | clazz = loadType(luaState, className);
186 | }
187 |
188 | // Instantiate
189 | Object object;
190 | int dimensionCount = luaState.getTop() - 1;
191 | switch (dimensionCount) {
192 | case 0:
193 | try {
194 | object = clazz.newInstance();
195 | } catch (InstantiationException e) {
196 | throw new RuntimeException(e);
197 | } catch (IllegalAccessException e) {
198 | throw new RuntimeException(e);
199 | }
200 | break;
201 | case 1:
202 | object = Array.newInstance(clazz, luaState.checkInteger(2));
203 | break;
204 | default:
205 | int[] dimensions = new int[dimensionCount];
206 | for (int i = 0; i < dimensionCount; i++) {
207 | dimensions[i] = luaState.checkInteger(i + 2);
208 | }
209 | object = Array.newInstance(clazz, dimensions);
210 | }
211 |
212 | // Return
213 | luaState.pushJavaObject(object);
214 | return 1;
215 | }
216 |
217 | @Override
218 | public String getName() {
219 | return "new";
220 | }
221 | }
222 |
223 | /**
224 | * Returns whether an object is an instance of a type. The object is given
225 | * as the first argument. the type is given as the second argument, either
226 | * as a class or as a type name.
227 | */
228 | private static class InstanceOf implements NamedJavaFunction {
229 | // -- JavaFunction methods
230 | @Override
231 | public int invoke(LuaState luaState) {
232 | // Get the object
233 | Object object = luaState.checkJavaObject(1, Object.class);
234 |
235 | // Find class
236 | Class> clazz;
237 | if (luaState.isJavaObject(2, Class.class)) {
238 | clazz = luaState.checkJavaObject(2, Class.class);
239 | } else {
240 | String className = luaState.checkString(2);
241 | clazz = loadType(luaState, className);
242 | }
243 |
244 | // Type check
245 | luaState.pushBoolean(clazz.isInstance(object));
246 | return 1;
247 | }
248 |
249 | @Override
250 | public String getName() {
251 | return "instanceof";
252 | }
253 | }
254 |
255 | /**
256 | * Creates a typed Java object.
257 | */
258 | private static class Cast implements NamedJavaFunction {
259 | // -- NamedJavaFunction methods
260 | @Override
261 | public int invoke(LuaState luaState) {
262 | // Find class
263 | final Class> clazz;
264 | if (luaState.isJavaObject(2, Class.class)) {
265 | clazz = luaState.checkJavaObject(2, Class.class);
266 | } else {
267 | String className = luaState.checkString(2);
268 | clazz = loadType(luaState, className);
269 | }
270 |
271 | // Get the object
272 | final Object object = luaState.checkJavaObject(1, clazz);
273 |
274 | // Push result
275 | luaState.pushJavaObject(new TypedJavaObject() {
276 | @Override
277 | public Object getObject() {
278 | return object;
279 | }
280 |
281 | @Override
282 | public Class> getType() {
283 | return clazz;
284 | }
285 |
286 | @Override
287 | public boolean isStrong() {
288 | return false;
289 | }
290 | });
291 | return 1;
292 | }
293 |
294 | @Override
295 | public String getName() {
296 | return "cast";
297 | }
298 | }
299 |
300 | /**
301 | * Creates a dynamic proxy object the implements a set of Java interfaces in
302 | * Lua.
303 | */
304 | private static class Proxy implements NamedJavaFunction {
305 | // -- JavaFunction methods
306 | @Override
307 | public int invoke(LuaState luaState) {
308 | // Check table
309 | luaState.checkType(1, LuaType.TABLE);
310 |
311 | // Get interfaces
312 | int interfaceCount = luaState.getTop() - 1;
313 | luaState.checkArg(2, interfaceCount > 0, "no interface specified");
314 | Class>[] interfaces = new Class>[interfaceCount];
315 | for (int i = 0; i < interfaceCount; i++) {
316 | if (luaState.isJavaObject(i + 2, Class.class)) {
317 | interfaces[i] = luaState
318 | .checkJavaObject(i + 2, Class.class);
319 | } else {
320 | String interfaceName = luaState.checkString(i + 2);
321 | interfaces[i] = loadType(luaState, interfaceName);
322 | }
323 | }
324 |
325 | // Create proxy
326 | luaState.pushJavaObjectRaw(luaState.getProxy(1, interfaces));
327 | return 1;
328 | }
329 |
330 | @Override
331 | public String getName() {
332 | return "proxy";
333 | }
334 | }
335 |
336 | /**
337 | * Provides the pairs iterator from the Java reflector.
338 | */
339 | private static class Pairs implements NamedJavaFunction {
340 | // -- NamedJavaFunction methods
341 | @Override
342 | public int invoke(LuaState luaState) {
343 | luaState.checkArg(
344 | 1,
345 | luaState.isJavaObjectRaw(1),
346 | String.format("Java object expected, got %s",
347 | luaState.typeName(1)));
348 | JavaFunction metamethod = luaState.getMetamethod(
349 | luaState.toJavaObjectRaw(1), Metamethod.PAIRS);
350 | return metamethod.invoke(luaState);
351 | }
352 |
353 | @Override
354 | public String getName() {
355 | return "pairs";
356 | }
357 | }
358 |
359 | /**
360 | * Provides the ipairs iterator from the Java reflector.
361 | */
362 | private static class IPairs implements NamedJavaFunction {
363 | // -- NamedJavaFunction methods
364 | @Override
365 | public int invoke(LuaState luaState) {
366 | luaState.checkArg(
367 | 1,
368 | luaState.isJavaObjectRaw(1),
369 | String.format("Java object expected, got %s",
370 | luaState.typeName(1)));
371 | JavaFunction metamethod = luaState.getMetamethod(
372 | luaState.toJavaObjectRaw(1), Metamethod.IPAIRS);
373 | return metamethod.invoke(luaState);
374 | }
375 |
376 | @Override
377 | public String getName() {
378 | return "ipairs";
379 | }
380 | }
381 |
382 | /**
383 | * Provides a wrapper object for table-like map and list access from Lua.
384 | */
385 | private static class ToTable implements NamedJavaFunction {
386 | // -- Static methods
387 | /**
388 | * Returns a table-like Lua value for the specified map.
389 | */
390 | @SuppressWarnings("unchecked")
391 | public static TypedJavaObject toTable(Map, ?> map) {
392 | return new LuaMap((Map) map);
393 | }
394 |
395 | /**
396 | * Returns a table-list Lua value for the specified list.
397 | */
398 | @SuppressWarnings("unchecked")
399 | public static TypedJavaObject toTable(List> list) {
400 | return new LuaList((List) list);
401 | }
402 |
403 | // -- JavaFunction methods
404 | @SuppressWarnings("unchecked")
405 | @Override
406 | public int invoke(LuaState luaState) {
407 | if (luaState.isJavaObject(1, Map.class)) {
408 | Map map = luaState.toJavaObject(1, Map.class);
409 | luaState.pushJavaObject(new LuaMap(map));
410 | } else if (luaState.isJavaObject(1, List.class)) {
411 | List list = luaState.toJavaObject(1, List.class);
412 | luaState.pushJavaObject(new LuaList(list));
413 | } else {
414 | luaState.checkArg(
415 | 1,
416 | false,
417 | String.format("expected map or list, got %s",
418 | luaState.typeName(1)));
419 | }
420 | return 1;
421 | }
422 |
423 | @Override
424 | public String getName() {
425 | return "totable";
426 | }
427 |
428 | // -- Member types
429 | /**
430 | * Provides table-like access in Lua to a Java map.
431 | */
432 | private static class LuaMap implements JavaReflector, TypedJavaObject {
433 | // -- Static
434 | private static final JavaFunction INDEX = new Index();
435 | private static final JavaFunction NEW_INDEX = new NewIndex();
436 |
437 | // -- State
438 | private Map map;
439 |
440 | // -- Construction
441 | /**
442 | * Creates a new instance.
443 | */
444 | public LuaMap(Map map) {
445 | this.map = map;
446 | }
447 |
448 | // -- Properties
449 | /**
450 | * Returns the map.
451 | */
452 | public Map getMap() {
453 | return map;
454 | }
455 |
456 | // -- JavaReflector methods
457 | @Override
458 | public JavaFunction getMetamethod(Metamethod metamethod) {
459 | switch (metamethod) {
460 | case INDEX:
461 | return INDEX;
462 | case NEWINDEX:
463 | return NEW_INDEX;
464 | default:
465 | return null;
466 | }
467 | }
468 |
469 | // -- TypedJavaObject methods
470 | @Override
471 | public Object getObject() {
472 | return map;
473 | }
474 |
475 | @Override
476 | public Class> getType() {
477 | return Map.class;
478 | }
479 |
480 | @Override
481 | public boolean isStrong() {
482 | return true;
483 | }
484 |
485 | // -- Member types
486 | /**
487 | * __index implementation for maps.
488 | */
489 | private static class Index implements JavaFunction {
490 | // -- JavaFunction methods
491 | @Override
492 | public int invoke(LuaState luaState) {
493 | LuaMap luaMap = (LuaMap) luaState.toJavaObjectRaw(1);
494 | Object key = luaState.toJavaObject(2, Object.class);
495 | if (key == null) {
496 | throw new LuaRuntimeException(String.format(
497 | "attempt to read map with %s accessor",
498 | luaState.typeName(2)));
499 | }
500 | luaState.pushJavaObject(luaMap.getMap().get(key));
501 | return 1;
502 | }
503 | }
504 |
505 | /**
506 | * __newindex implementation for maps.
507 | */
508 | private static class NewIndex implements JavaFunction {
509 | // -- JavaFunction methods
510 | @Override
511 | public int invoke(LuaState luaState) {
512 | LuaMap luaMap = (LuaMap) luaState.toJavaObjectRaw(1);
513 | Object key = luaState.toJavaObject(2, Object.class);
514 | if (key == null) {
515 | throw new LuaRuntimeException(String.format(
516 | "attempt to write map with %s accessor",
517 | luaState.typeName(2)));
518 | }
519 | Object value = luaState.toJavaObject(3, Object.class);
520 | if (value != null) {
521 | luaMap.getMap().put(key, value);
522 | } else {
523 | luaMap.getMap().remove(key);
524 | }
525 | return 0;
526 | }
527 | }
528 | }
529 |
530 | /**
531 | * Provides table-like access in Lua to a Java list.
532 | */
533 | private static class LuaList implements JavaReflector, TypedJavaObject {
534 | // -- Static
535 | private static final JavaFunction INDEX = new Index();
536 | private static final JavaFunction NEW_INDEX = new NewIndex();
537 | private static final JavaFunction LENGTH = new Length();
538 |
539 | // -- State
540 | private List list;
541 |
542 | // -- Construction
543 | /**
544 | * Creates a new instance.
545 | */
546 | public LuaList(List list) {
547 | this.list = list;
548 | }
549 |
550 | // -- Properties
551 | /**
552 | * Returns the map.
553 | */
554 | public List getList() {
555 | return list;
556 | }
557 |
558 | // -- JavaReflector methods
559 | @Override
560 | public JavaFunction getMetamethod(Metamethod metamethod) {
561 | switch (metamethod) {
562 | case INDEX:
563 | return INDEX;
564 | case NEWINDEX:
565 | return NEW_INDEX;
566 | case LEN:
567 | return LENGTH;
568 | default:
569 | return null;
570 | }
571 | }
572 |
573 | // -- TypedJavaObject methods
574 | @Override
575 | public Object getObject() {
576 | return list;
577 | }
578 |
579 | @Override
580 | public Class> getType() {
581 | return List.class;
582 | }
583 |
584 | @Override
585 | public boolean isStrong() {
586 | return true;
587 | }
588 |
589 | // -- Member types
590 | /**
591 | * __index implementation for lists.
592 | */
593 | private static class Index implements JavaFunction {
594 | // -- JavaFunction methods
595 | @Override
596 | public int invoke(LuaState luaState) {
597 | LuaList luaList = (LuaList) luaState.toJavaObjectRaw(1);
598 | if (!luaState.isNumber(2)) {
599 | throw new LuaRuntimeException(String.format(
600 | "attempt to read list with %s accessor",
601 | luaState.typeName(2)));
602 | }
603 | int index = luaState.toInteger(2);
604 | luaState.pushJavaObject(luaList.getList().get(index - 1));
605 | return 1;
606 | }
607 | }
608 |
609 | /**
610 | * __newindex implementation for lists.
611 | */
612 | private static class NewIndex implements JavaFunction {
613 | // -- JavaFunction methods
614 | @Override
615 | public int invoke(LuaState luaState) {
616 | LuaList luaList = (LuaList) luaState.toJavaObjectRaw(1);
617 | if (!luaState.isNumber(2)) {
618 | throw new LuaRuntimeException(String.format(
619 | "attempt to write list with %s accessor",
620 | luaState.typeName(2)));
621 | }
622 | int index = luaState.toInteger(2);
623 | Object value = luaState.toJavaObject(3, Object.class);
624 | if (value != null) {
625 | int size = luaList.getList().size();
626 | if (index - 1 != size) {
627 | luaList.getList().set(index - 1, value);
628 | } else {
629 | luaList.getList().add(value);
630 | }
631 | } else {
632 | luaList.getList().remove(index - 1);
633 | }
634 | return 0;
635 | }
636 | }
637 |
638 | /**
639 | * __len implementation for lists.
640 | */
641 | private static class Length implements JavaFunction {
642 | // -- JavaFunction methods
643 | @Override
644 | public int invoke(LuaState luaState) {
645 | LuaList luaList = (LuaList) luaState.toJavaObjectRaw(1);
646 | luaState.pushInteger(luaList.getList().size());
647 | return 1;
648 | }
649 | }
650 | }
651 | }
652 |
653 | /**
654 | * Provides an iterator for Iterable objects.
655 | */
656 | private static class Elements implements NamedJavaFunction {
657 | // -- NamedJavaFunction methods
658 | @Override
659 | public int invoke(LuaState luaState) {
660 | Iterable> iterable = luaState.checkJavaObject(1, Iterable.class);
661 | luaState.pushJavaObject(new ElementIterator(iterable.iterator()));
662 | luaState.pushJavaObject(iterable);
663 | luaState.pushNil();
664 | return 3;
665 | }
666 |
667 | @Override
668 | public String getName() {
669 | return "elements";
670 | }
671 |
672 | // -- Member types
673 | private static class ElementIterator implements JavaFunction {
674 | // -- State
675 | private Iterator> iterator;
676 |
677 | // -- Construction
678 | /**
679 | * Creates a new instance.
680 | */
681 | public ElementIterator(Iterator> iterator) {
682 | this.iterator = iterator;
683 | }
684 |
685 | // -- JavaFunction methods
686 | @Override
687 | public int invoke(LuaState luaState) {
688 | if (iterator.hasNext()) {
689 | luaState.pushJavaObject(iterator.next());
690 | } else {
691 | luaState.pushNil();
692 | }
693 | return 1;
694 | }
695 | }
696 | }
697 |
698 | /**
699 | * Provides an iterator for Java object fields.
700 | */
701 | private static class Fields implements NamedJavaFunction {
702 | // -- NamedJavaFunction methods
703 | @Override
704 | public int invoke(LuaState luaState) {
705 | luaState.checkArg(
706 | 1,
707 | luaState.isJavaObjectRaw(1),
708 | String.format("expected Java object, got %s",
709 | luaState.typeName(1)));
710 | JavaFunction metamethod = luaState.getMetamethod(
711 | luaState.toJavaObjectRaw(1), Metamethod.JAVAFIELDS);
712 | return metamethod.invoke(luaState);
713 | }
714 |
715 | @Override
716 | public String getName() {
717 | return "fields";
718 | }
719 | }
720 |
721 | /**
722 | * Provides an iterator for Java methods.
723 | */
724 | private static class Methods implements NamedJavaFunction {
725 | // -- NamedJavaFunction methods
726 | @Override
727 | public int invoke(LuaState luaState) {
728 | luaState.checkArg(
729 | 1,
730 | luaState.isJavaObjectRaw(1),
731 | String.format("expected Java object, got %s",
732 | luaState.typeName(1)));
733 | JavaFunction metamethod = luaState.getMetamethod(
734 | luaState.toJavaObjectRaw(1), Metamethod.JAVAMETHODS);
735 | return metamethod.invoke(luaState);
736 | }
737 |
738 | @Override
739 | public String getName() {
740 | return "methods";
741 | }
742 | }
743 |
744 | /**
745 | * Provides an iterator for Java object properties.
746 | */
747 | private static class Properties implements NamedJavaFunction {
748 | // -- NamedJavaFunction methods
749 | @Override
750 | public int invoke(LuaState luaState) {
751 | luaState.checkArg(
752 | 1,
753 | luaState.isJavaObjectRaw(1),
754 | String.format("expected Java object, got %s",
755 | luaState.typeName(1)));
756 | JavaFunction metamethod = luaState.getMetamethod(
757 | luaState.toJavaObjectRaw(1), Metamethod.JAVAPROPERTIES);
758 | return metamethod.invoke(luaState);
759 | }
760 |
761 | @Override
762 | public String getName() {
763 | return "properties";
764 | }
765 | }
766 | }
767 |
--------------------------------------------------------------------------------
/jnlua/src/test/java/com/naef/jnlua/test/LuaStateErrorTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | * See LICENSE.txt for license terms.
4 | */
5 |
6 | package com.naef.jnlua.test;
7 |
8 | import static org.junit.Assert.assertEquals;
9 |
10 | import java.io.ByteArrayInputStream;
11 | import java.io.ByteArrayOutputStream;
12 | import java.io.IOException;
13 | import java.io.InputStream;
14 | import java.io.OutputStream;
15 |
16 | import org.junit.Test;
17 |
18 | import com.naef.jnlua.JavaFunction;
19 | import com.naef.jnlua.LuaRuntimeException;
20 | import com.naef.jnlua.LuaState;
21 | import com.naef.jnlua.LuaState.ArithOperator;
22 | import com.naef.jnlua.LuaState.GcAction;
23 | import com.naef.jnlua.LuaState.Library;
24 | import com.naef.jnlua.LuaState.RelOperator;
25 | import com.naef.jnlua.LuaValueProxy;
26 | import com.naef.jnlua.NamedJavaFunction;
27 |
28 | /**
29 | * Throws illegal arguments at the Lua state for error testing.
30 | */
31 | public class LuaStateErrorTest extends AbstractLuaTest {
32 | // -- Properties tests
33 | /**
34 | * setClassLodaer(ClassLoader) with null class loader.
35 | */
36 | @Test(expected = NullPointerException.class)
37 | public void setNullClassLoader() {
38 | luaState.setClassLoader(null);
39 | }
40 |
41 | /**
42 | * setJavaReflector(JavaReflector) with null Java reflector.
43 | */
44 | @Test(expected = NullPointerException.class)
45 | public void setNullJavaReflector() {
46 | luaState.setJavaReflector(null);
47 | }
48 |
49 | /**
50 | * getMetamethod(Object, Metamethod) with null metamethod.
51 | */
52 | @Test(expected = NullPointerException.class)
53 | public void testNullGetMetamethod() {
54 | luaState.getMetamethod(null, null);
55 | }
56 |
57 | /**
58 | * setConverter(Converter) with null converter.
59 | */
60 | @Test(expected = NullPointerException.class)
61 | public void setNullConverter() {
62 | luaState.setConverter(null);
63 | }
64 |
65 | // -- Life cycle tests
66 | /**
67 | * Tests closing the Lua state while running.
68 | */
69 | @Test(expected = LuaRuntimeException.class)
70 | public void testIllegalClose() {
71 | luaState.pushJavaFunction(new JavaFunction() {
72 | @Override
73 | public int invoke(LuaState luaState) {
74 | luaState.close();
75 | return 0;
76 | }
77 | });
78 | luaState.call(0, 0);
79 | }
80 |
81 | /**
82 | * Tests invoking a method after the Lua state has been closed.
83 | */
84 | @Test(expected = IllegalStateException.class)
85 | public void testPostClose() {
86 | luaState.close();
87 | luaState.pushInteger(1);
88 | }
89 |
90 | /**
91 | * gc(GcAction, int) null action.
92 | */
93 | @Test(expected = NullPointerException.class)
94 | public void testNullGc() {
95 | luaState.gc(null, 0);
96 | }
97 |
98 | // -- Registration tests
99 | /**
100 | * openLib(Library) with null library.
101 | */
102 | @Test(expected = NullPointerException.class)
103 | public void testNullOpenLib() {
104 | luaState.openLib(null);
105 | }
106 |
107 | /**
108 | * register(JavaFunction[]) with null function.
109 | */
110 | @Test(expected = NullPointerException.class)
111 | public void testNullFunctionRegister() {
112 | luaState.register(null);
113 | }
114 |
115 | /**
116 | * register(String, JavaFunction[]) with null string.
117 | */
118 | @Test(expected = NullPointerException.class)
119 | public void testNullNameRegister() {
120 | luaState.register(null, new NamedJavaFunction[0], true);
121 | }
122 |
123 | /**
124 | * register(String, JavaFunction[]) with null functions.
125 | */
126 | @Test(expected = NullPointerException.class)
127 | public void testNullFunctionsRegister() {
128 | luaState.register("", null, true);
129 | }
130 |
131 | // -- Load and dump tests
132 | /**
133 | * load(InputStream, String) with null input stream.
134 | */
135 | @Test(expected = NullPointerException.class)
136 | public void testNullStreamLoad() throws Exception {
137 | luaState.load((InputStream) null, "=testNullStreamLoad", "bt");
138 | }
139 |
140 | /**
141 | * load(InputStream, String) with null string.
142 | */
143 | @Test(expected = NullPointerException.class)
144 | public void testNullChunkLoad1() throws Exception {
145 | luaState.load(new ByteArrayInputStream(new byte[0]), null, "bt");
146 | }
147 |
148 | /**
149 | * load(String, String) with null string 1.
150 | */
151 | @Test(expected = NullPointerException.class)
152 | public void testNullStringLoad() throws Exception {
153 | luaState.load((String) null, "=testNullStringLoad");
154 | }
155 |
156 | /**
157 | * load(String, String) with null string 2.
158 | */
159 | @Test(expected = NullPointerException.class)
160 | public void testNullChunkLoad2() throws Exception {
161 | luaState.load("", null);
162 | }
163 |
164 | /**
165 | * load(InputStream, String) with input stream throwing IO exception.
166 | */
167 | @Test(expected = IOException.class)
168 | public void testIoExceptionLoad() throws Exception {
169 | luaState.load(new InputStream() {
170 | @Override
171 | public int read() throws IOException {
172 | throw new IOException();
173 | }
174 | }, "=testIoExceptionLoad", "bt");
175 | }
176 |
177 | /**
178 | * dump(OutputStream) with null output stream.
179 | */
180 | @Test(expected = NullPointerException.class)
181 | public void testNullDump() throws Exception {
182 | luaState.load("return 0", "=testNullDump");
183 | luaState.dump(null);
184 | }
185 |
186 | /**
187 | * dump(OutputStream) with an output stream throwing a IO exception.
188 | */
189 | @Test(expected = IOException.class)
190 | public void testIoExceptionDump() throws Exception {
191 | luaState.load("return 0", "=testIoExceptionDump");
192 | luaState.dump(new OutputStream() {
193 | @Override
194 | public void write(int b) throws IOException {
195 | throw new IOException();
196 | }
197 | });
198 | }
199 |
200 | /**
201 | * dump(OutputStream) with insufficient arguments.
202 | */
203 | @Test(expected = IllegalStateException.class)
204 | public void testUnderflowDump() throws Exception {
205 | luaState.dump(new ByteArrayOutputStream());
206 | }
207 |
208 | // -- Call tests
209 | /**
210 | * Call(int, int) with insufficient arguments.
211 | */
212 | @Test(expected = IllegalStateException.class)
213 | public void testUnderflowCall() {
214 | luaState.openLibs();
215 | luaState.getGlobal("print");
216 | luaState.call(1, 1);
217 | }
218 |
219 | /**
220 | * Call(int, int) with an extremely high number of returns.
221 | */
222 | @Test(expected = IllegalStateException.class)
223 | public void testOverflowCall() {
224 | luaState.openLibs();
225 | luaState.getGlobal("print");
226 | luaState.pushString("");
227 | luaState.call(1, Integer.MAX_VALUE);
228 | }
229 |
230 | /**
231 | * Call(int, int) with an illegal number of arguments.
232 | */
233 | @Test(expected = IllegalArgumentException.class)
234 | public void testIllegalCall1() {
235 | luaState.openLibs();
236 | luaState.getGlobal("print");
237 | luaState.call(-1, 1);
238 | }
239 |
240 | /**
241 | * Call(int, int) with an illegal number of returns.
242 | */
243 | @Test(expected = IllegalArgumentException.class)
244 | public void testIllegalCall2() {
245 | luaState.openLibs();
246 | luaState.getGlobal("print");
247 | luaState.pushString("");
248 | luaState.call(1, -2);
249 | assertEquals(0, luaState.getTop());
250 | }
251 |
252 | // -- Global tests
253 | /**
254 | * getGlobal(String) with null.
255 | */
256 | @Test(expected = NullPointerException.class)
257 | public void testNullGetGlobal() {
258 | luaState.getGlobal(null);
259 | }
260 |
261 | /**
262 | * setGlobal(String) with null.
263 | */
264 | @Test(expected = NullPointerException.class)
265 | public void testNullSetGlobal() {
266 | luaState.pushNumber(0.0);
267 | luaState.setGlobal(null);
268 | }
269 |
270 | /**
271 | * setGlobal(String) with insufficient arguments.
272 | */
273 | @Test(expected = IllegalStateException.class)
274 | public void testUnderflowSetGlobal() {
275 | luaState.setGlobal("global");
276 | }
277 |
278 | /**
279 | * setGlobal(String) with insufficient arguments.
280 | */
281 | @Test(expected = IllegalStateException.class)
282 | public void testIllegalSetGlobal() {
283 | luaState.setGlobal("illegal");
284 | }
285 |
286 | // -- Stack push tests
287 | /**
288 | * pushJavaFunction(JavaFunction) with null argument.
289 | */
290 | @Test(expected = NullPointerException.class)
291 | public void testNullPushJavaFunction() {
292 | luaState.pushJavaFunction(null);
293 | }
294 |
295 | /**
296 | * pushJavaObjectRaw(Object) with null argument.
297 | */
298 | @Test(expected = NullPointerException.class)
299 | public void testNullPushJavaObjectRaw() {
300 | luaState.pushJavaObjectRaw(null);
301 | }
302 |
303 | /**
304 | * pushString(String) with null argument.
305 | */
306 | @Test(expected = NullPointerException.class)
307 | public void testNullPushString() {
308 | luaState.pushString(null);
309 | }
310 |
311 | /**
312 | * pushNumber(Double) until stack overflow.
313 | */
314 | @Test(expected = IllegalStateException.class)
315 | public void testStackOverflow() {
316 | for (int i = 0; i < Integer.MAX_VALUE; i++) {
317 | luaState.pushNumber(0.0);
318 | }
319 | }
320 |
321 | // -- Stack query tests
322 | /**
323 | * compare(int, int, RelOperator) with number and nil for less than.
324 | */
325 | @Test(expected = LuaRuntimeException.class)
326 | public void testIllegalCompareLt() {
327 | luaState.pushNumber(1);
328 | luaState.pushNil();
329 | luaState.compare(1, 2, RelOperator.LT);
330 | }
331 |
332 | /**
333 | * compare(int, int, RelOperator) with number and nil for less or equal.
334 | */
335 | @Test(expected = LuaRuntimeException.class)
336 | public void testIllegalCompareLe() {
337 | luaState.pushNumber(1);
338 | luaState.pushNil();
339 | luaState.compare(1, 2, RelOperator.LE);
340 | }
341 |
342 | /**
343 | * rawLen(int) with illegal index.
344 | */
345 | @Test(expected = IllegalArgumentException.class)
346 | public void testIllegalRawLen() {
347 | luaState.rawLen(getIllegalIndex());
348 | }
349 |
350 | /**
351 | * toInteger(int) with illegal index.
352 | */
353 | @Test(expected = IllegalArgumentException.class)
354 | public void testIllegalToInteger() {
355 | luaState.toInteger(getIllegalIndex());
356 | }
357 |
358 | /**
359 | * toJavaFunction(int) with illegal index.
360 | */
361 | @Test(expected = IllegalArgumentException.class)
362 | public void testIllegalToIJavaFunction() {
363 | luaState.toJavaFunction(getIllegalIndex());
364 | }
365 |
366 | /**
367 | * toJavaObject(int) with illegal index and LuaValueProxy type.
368 | */
369 | @Test(expected = IllegalArgumentException.class)
370 | public void testIllegalToIJavaObject() {
371 | luaState.toJavaObject(getIllegalIndex(), LuaValueProxy.class);
372 | }
373 |
374 | /**
375 | * toJavaObjectRaw(int) with illegal index.
376 | */
377 | @Test(expected = IllegalArgumentException.class)
378 | public void testIllegalToIJavaObjectRaw() {
379 | luaState.toJavaObjectRaw(getIllegalIndex());
380 | }
381 |
382 | /**
383 | * toNumber(int) with illegal index.
384 | */
385 | @Test(expected = IllegalArgumentException.class)
386 | public void testIllegalToNumber() {
387 | luaState.toNumber(getIllegalIndex());
388 | }
389 |
390 | /**
391 | * toNumber(int) with maximum index.
392 | */
393 | @Test(expected = IllegalArgumentException.class)
394 | public void testMaxToNumber() {
395 | luaState.toNumber(Integer.MAX_VALUE);
396 | }
397 |
398 | /**
399 | * toNumber(int) with minimum index.
400 | */
401 | @Test(expected = IllegalArgumentException.class)
402 | public void testMinToNumbern() {
403 | luaState.toNumber(Integer.MIN_VALUE);
404 | }
405 |
406 | /**
407 | * toPointer(int) with illegal index.
408 | */
409 | @Test(expected = IllegalArgumentException.class)
410 | public void testIllegalToPointer() {
411 | luaState.toPointer(getIllegalIndex());
412 | }
413 |
414 | /**
415 | * toString(int) with illegal index.
416 | */
417 | @Test(expected = IllegalArgumentException.class)
418 | public void testIllegalToString() {
419 | luaState.toString(getIllegalIndex());
420 | }
421 |
422 | // -- Stack operation test
423 | /**
424 | * arith(ArithOperator) with two missing arguments for addition.
425 | */
426 | @Test(expected = IllegalStateException.class)
427 | public void testUnderflowArith1() {
428 | luaState.arith(ArithOperator.ADD);
429 | }
430 |
431 | /**
432 | * arith(ArithOperator) with one missing argument for addition.
433 | */
434 | @Test(expected = IllegalStateException.class)
435 | public void testUnderflowArith2() {
436 | luaState.pushNumber(1);
437 | luaState.arith(ArithOperator.ADD);
438 | }
439 |
440 | /**
441 | * arith(ArithOperator) with one missing argument for mathematical negation.
442 | */
443 | @Test(expected = IllegalStateException.class)
444 | public void testUnderflowArith3() {
445 | luaState.arith(ArithOperator.UNM);
446 | }
447 |
448 | /**
449 | * concat(int) with insufficient arguments.
450 | */
451 | @Test(expected = IllegalStateException.class)
452 | public void testUnderflowConcat1() {
453 | luaState.concat(1);
454 | }
455 |
456 | /**
457 | * concat(int) with insufficient arguments.
458 | */
459 | @Test(expected = IllegalStateException.class)
460 | public void testUnderflowConcat2() {
461 | luaState.pushString("");
462 | luaState.pushString("");
463 | luaState.concat(3);
464 | }
465 |
466 | /**
467 | * concat(int) with an illegal number of arguments.
468 | */
469 | @Test(expected = IllegalArgumentException.class)
470 | public void testIllegalConcat() {
471 | luaState.concat(-1);
472 | }
473 |
474 | /**
475 | * copy(int, int) with two illegal indexes.
476 | */
477 | @Test(expected = IllegalArgumentException.class)
478 | public void testIllegalCopy1() {
479 | luaState.copy(getIllegalIndex(), getIllegalIndex());
480 | }
481 |
482 | /**
483 | * copy(int, int) with one illegal index.
484 | */
485 | @Test(expected = IllegalArgumentException.class)
486 | public void testIllegalCopy2() {
487 | luaState.pushInteger(1);
488 | luaState.copy(1, getIllegalIndex());
489 | }
490 |
491 | /**
492 | * len(int) with illegal index.
493 | */
494 | @Test(expected = IllegalArgumentException.class)
495 | public void testIllegalLen() {
496 | luaState.len(getIllegalIndex());
497 | }
498 |
499 | /**
500 | * insert(int) with illegal index.
501 | */
502 | @Test(expected = IllegalArgumentException.class)
503 | public void testIllegalInsert() {
504 | luaState.insert(getIllegalIndex());
505 | }
506 |
507 | /**
508 | * pop(int) with insufficient arguments.
509 | */
510 | @Test(expected = IllegalArgumentException.class)
511 | public void testUnderflowPop() {
512 | luaState.pop(1);
513 | }
514 |
515 | /**
516 | * pop(int) with an illegal number of arguments.
517 | */
518 | @Test(expected = IllegalArgumentException.class)
519 | public void testIllegalPop() {
520 | luaState.pop(-1);
521 | }
522 |
523 | /**
524 | * pushValue(int) with illegal index.
525 | */
526 | @Test(expected = IllegalArgumentException.class)
527 | public void testIllegalPushValue() {
528 | luaState.pushValue(getIllegalIndex());
529 | }
530 |
531 | /**
532 | * remove(int) with illegal index.
533 | */
534 | @Test(expected = IllegalArgumentException.class)
535 | public void testIllegalRemove() {
536 | luaState.remove(getIllegalIndex());
537 | }
538 |
539 | /**
540 | * replace(int) with illegal index.
541 | */
542 | @Test(expected = IllegalArgumentException.class)
543 | public void testIllegalReplace() {
544 | luaState.replace(getIllegalIndex());
545 | }
546 |
547 | /**
548 | * setTop(int) with an illegal argument.
549 | */
550 | @Test(expected = IllegalArgumentException.class)
551 | public void testIllegalSetTop() {
552 | luaState.setTop(-1);
553 | }
554 |
555 | // -- Table tests
556 | /**
557 | * getTable(int) with illegal index.
558 | */
559 | @Test(expected = IllegalArgumentException.class)
560 | public void testIllegalGetTable1() {
561 | luaState.pushString("");
562 | luaState.getTable(getIllegalIndex());
563 | }
564 |
565 | /**
566 | * getTable(int) with invalid table.
567 | */
568 | @Test(expected = IllegalArgumentException.class)
569 | public void testIllegalGetTable2() {
570 | luaState.pushNumber(0.0);
571 | luaState.pushString("");
572 | luaState.getTable(1);
573 | }
574 |
575 | /**
576 | * getField(int, String) with illegal index.
577 | */
578 | @Test(expected = IllegalArgumentException.class)
579 | public void testIllegalGetField1() {
580 | luaState.getField(getIllegalIndex(), "");
581 | }
582 |
583 | /**
584 | * getField(int, String) with invalid table.
585 | */
586 | @Test(expected = IllegalArgumentException.class)
587 | public void testIllegalGetField2() {
588 | luaState.pushNumber(0.0);
589 | luaState.getField(1, "");
590 | }
591 |
592 | /**
593 | * newTable(int, int) with negative array count.
594 | */
595 | @Test(expected = IllegalArgumentException.class)
596 | public void testIllegalNewTable1() {
597 | luaState.newTable(-1, 0);
598 | }
599 |
600 | /**
601 | * newTable(int, int) with negative record count.
602 | */
603 | @Test(expected = IllegalArgumentException.class)
604 | public void testIllegalNewTable2() {
605 | luaState.newTable(0, -1);
606 | }
607 |
608 | /**
609 | * next(int) with illegal index.
610 | */
611 | @Test(expected = IllegalArgumentException.class)
612 | public void testIllegalNext1() {
613 | luaState.pushNil();
614 | luaState.next(getIllegalIndex());
615 | }
616 |
617 | /**
618 | * next(int) with invalid table.
619 | */
620 | @Test(expected = IllegalArgumentException.class)
621 | public void testIllegalNext2() {
622 | luaState.pushNumber(0.0);
623 | luaState.pushNil();
624 | luaState.next(1);
625 | }
626 |
627 | /**
628 | * rawGet(int) with illegal index.
629 | */
630 | @Test(expected = IllegalArgumentException.class)
631 | public void testIllegalRawGet1() {
632 | luaState.rawGet(getIllegalIndex());
633 | }
634 |
635 | /**
636 | * rawGet(int) with invalid table.
637 | */
638 | @Test(expected = IllegalArgumentException.class)
639 | public void testIllegalRawGet2() {
640 | luaState.pushNumber(0.0);
641 | luaState.pushString("");
642 | luaState.rawGet(1);
643 | }
644 |
645 | /**
646 | * rawGet(int, int) with illegal index.
647 | */
648 | @Test(expected = IllegalArgumentException.class)
649 | public void testIllegalRawGet3() {
650 | luaState.rawGet(getIllegalIndex(), 1);
651 | }
652 |
653 | /**
654 | * rawGet(int, int) with invalid table.
655 | */
656 | @Test(expected = IllegalArgumentException.class)
657 | public void testIllegalRawGet4() {
658 | luaState.pushNumber(0.0);
659 | luaState.rawGet(1, 1);
660 | }
661 |
662 | /**
663 | * rawSet(int) with insufficient arguments.
664 | */
665 | @Test(expected = IllegalStateException.class)
666 | public void testUnderflowRawSet() {
667 | luaState.newTable();
668 | luaState.rawSet(1);
669 | }
670 |
671 | /**
672 | * rawSet(int) with nil index.
673 | */
674 | @Test(expected = LuaRuntimeException.class)
675 | public void testNilRawSet() {
676 | luaState.newTable();
677 | luaState.pushNil();
678 | luaState.pushString("value");
679 | luaState.rawSet(1);
680 | }
681 |
682 | /**
683 | * rawSet(int) with illegal index.
684 | */
685 | @Test(expected = IllegalArgumentException.class)
686 | public void testIllegalRawSet1() {
687 | luaState.pushString("key");
688 | luaState.pushString("value");
689 | luaState.rawSet(getIllegalIndex());
690 | }
691 |
692 | /**
693 | * rawSet(int) with invalid table.
694 | */
695 | @Test(expected = IllegalArgumentException.class)
696 | public void testIllegalRawSet2() {
697 | luaState.pushNumber(0.0);
698 | luaState.pushString("key");
699 | luaState.pushString("value");
700 | luaState.rawSet(1);
701 | }
702 |
703 | /**
704 | * rawSet(int, int) with invalid table.
705 | */
706 | @Test(expected = IllegalArgumentException.class)
707 | public void testIllegalRawSet3() {
708 | luaState.pushNumber(0.0);
709 | luaState.pushString("value");
710 | luaState.rawSet(1, 1);
711 | }
712 |
713 | /**
714 | * setTable(int) with insufficient arguments.
715 | */
716 | @Test(expected = IllegalStateException.class)
717 | public void testUnderflowSetTable() {
718 | luaState.newTable();
719 | luaState.setTable(1);
720 | }
721 |
722 | /**
723 | * setTable(int) with nil index.
724 | */
725 | @Test(expected = LuaRuntimeException.class)
726 | public void testNilSetTable() {
727 | luaState.newTable();
728 | luaState.pushNil();
729 | luaState.pushString("");
730 | luaState.setTable(1);
731 | }
732 |
733 | /**
734 | * setTable(int) with illegal index.
735 | */
736 | @Test(expected = IllegalArgumentException.class)
737 | public void testIllegalSetTable() {
738 | luaState.pushNil();
739 | luaState.pushString("");
740 | luaState.setTable(getIllegalIndex());
741 | }
742 |
743 | /**
744 | * setField(int, String) with null key.
745 | */
746 | @Test(expected = NullPointerException.class)
747 | public void testNullSetField() {
748 | luaState.newTable();
749 | luaState.pushString("value");
750 | luaState.setField(1, null);
751 | }
752 |
753 | /**
754 | * setField(int, String) with illegal index.
755 | */
756 | @Test(expected = IllegalArgumentException.class)
757 | public void testIllegalSetField1() {
758 | luaState.pushString("");
759 | luaState.setField(getIllegalIndex(), "key");
760 | }
761 |
762 | /**
763 | * setField(int, String) with invalid table.
764 | */
765 | @Test(expected = IllegalArgumentException.class)
766 | public void testIllegalSetField2() {
767 | luaState.pushNumber(0.0);
768 | luaState.pushString("");
769 | luaState.setField(1, "key");
770 | }
771 |
772 | // -- Metatable tests
773 | /**
774 | * setMetatable(int) with invalid table.
775 | */
776 | @Test(expected = IllegalArgumentException.class)
777 | public void testIllegalSetMetatable() {
778 | luaState.newTable();
779 | luaState.pushNumber(0.0);
780 | luaState.setMetatable(1);
781 | }
782 |
783 | // -- Thread tests
784 | /**
785 | * resume(int, int) with insufficient arguments.
786 | */
787 | @Test(expected = IllegalStateException.class)
788 | public void testUnderflowResume() {
789 | luaState.openLibs();
790 | luaState.getGlobal("print");
791 | luaState.newThread();
792 | luaState.resume(1, 1);
793 | }
794 |
795 | /**
796 | * resume(int, int) with invalid thread.
797 | */
798 | @Test(expected = IllegalArgumentException.class)
799 | public void testIllegalResume1() {
800 | luaState.pushNumber(0.0);
801 | luaState.resume(1, 0);
802 | }
803 |
804 | /**
805 | * resume(int, int) with an illegal number of returns.
806 | */
807 | @Test(expected = IllegalArgumentException.class)
808 | public void testIllegalResume2() {
809 | luaState.openLibs();
810 | luaState.getGlobal("print");
811 | luaState.newThread();
812 | luaState.resume(1, -1);
813 | }
814 |
815 | /**
816 | * status(int) with illegal thread.
817 | */
818 | @Test(expected = IllegalArgumentException.class)
819 | public void testIllegalStatus() {
820 | luaState.pushNumber(0.0);
821 | luaState.status(1);
822 | }
823 |
824 | /**
825 | * yield(int) with no running thread.
826 | */
827 | @Test(expected = LuaRuntimeException.class)
828 | public void testIllegalYield1() {
829 | luaState.register(new NamedJavaFunction() {
830 | @Override
831 | public int invoke(LuaState luaState) {
832 | return luaState.yield(0);
833 | }
834 |
835 | @Override
836 | public String getName() {
837 | return "yieldfunc";
838 | }
839 | });
840 | luaState.load("return yieldfunc()", "=testIllegalYield1");
841 | luaState.call(0, 0);
842 | }
843 |
844 | /**
845 | * yield across C-call boundary.
846 | */
847 | @Test(expected=LuaRuntimeException.class)
848 | public void testIllegalYield2() {
849 | luaState.openLib(Library.COROUTINE);
850 | luaState.pop(1);
851 | JavaFunction yieldFunction = new JavaFunction() {
852 | @Override
853 | public int invoke(LuaState luaState) {
854 | luaState.load("return coroutine.yield()", "=testIllegalYield2");
855 | luaState.call(0, 0);
856 | return 0;
857 | }
858 | };
859 | luaState.pushJavaFunction(yieldFunction);
860 | luaState.newThread();
861 | luaState.resume(1, 0);
862 | }
863 |
864 | /**
865 | * yield(int) with insufficient arguments.
866 | */
867 | @Test(expected = LuaRuntimeException.class)
868 | public void testUnderflowYield() {
869 | luaState.register(new NamedJavaFunction() {
870 | @Override
871 | public int invoke(LuaState luaState) {
872 | return luaState.yield(1);
873 | }
874 |
875 | @Override
876 | public String getName() {
877 | return "yieldfunc";
878 | }
879 | });
880 | luaState.load("yieldfunc()", "=testUnderflowYield");
881 | luaState.newThread();
882 | luaState.resume(1, 0);
883 | }
884 |
885 | // -- Reference tests
886 | /**
887 | * ref(int) with illegal index.
888 | */
889 | @Test(expected = IllegalArgumentException.class)
890 | public void testIllegalRef1() {
891 | luaState.pushNumber(0.0);
892 | luaState.ref(getIllegalIndex());
893 | }
894 |
895 | /**
896 | * ref(int) with illegal table.
897 | */
898 | @Test(expected = IllegalArgumentException.class)
899 | public void testIllegalRef2() {
900 | luaState.pushNumber(0.0);
901 | luaState.pushNumber(0.0);
902 | luaState.ref(1);
903 | }
904 |
905 | /**
906 | * unref(int, int) with illegal index.
907 | */
908 | @Test(expected = IllegalArgumentException.class)
909 | public void testIllegalUnref1() {
910 | luaState.newTable();
911 | luaState.pushNumber(0.0);
912 | int reference = luaState.ref(1);
913 | luaState.unref(getIllegalIndex(), reference);
914 | }
915 |
916 | /**
917 | * unref(int, int) with illegal table.
918 | */
919 | @Test(expected = IllegalArgumentException.class)
920 | public void testIllegalUnref2() {
921 | luaState.pushNumber(0.0);
922 | luaState.pushNumber(0.0);
923 | luaState.unref(1, 1);
924 | }
925 |
926 | // -- Optimization tests
927 | /**
928 | * tableSize(int) with illegal table.
929 | */
930 | @Test(expected = IllegalArgumentException.class)
931 | public void testIllegalTableSize1() {
932 | luaState.pushNumber(0.0);
933 | luaState.tableSize(1);
934 | }
935 |
936 | /**
937 | * tableSize(int) with illegal index.
938 | */
939 | @Test(expected = IllegalArgumentException.class)
940 | public void testIllegalTableSize2() {
941 | luaState.tableSize(1);
942 | }
943 |
944 | /**
945 | * tableMove(int, int, int, int) with illegal index.
946 | */
947 | @Test(expected = IllegalArgumentException.class)
948 | public void testIllegalTableMove1() {
949 | luaState.tableMove(getIllegalIndex(), 1, 1, 0);
950 | }
951 |
952 | /**
953 | * tableMove(int, int, int, int) with illegal count.
954 | */
955 | @Test(expected = IllegalArgumentException.class)
956 | public void testIllegalTableMove2() {
957 | luaState.newTable();
958 | luaState.tableMove(1, 1, 1, -1);
959 | }
960 |
961 | // -- Argument checking tests
962 | /**
963 | * checkArg(int, boolean, String) with false condition.
964 | */
965 | @Test(expected = LuaRuntimeException.class)
966 | public void testIllegalCheckArg() {
967 | luaState.pushBoolean(false);
968 | luaState.checkArg(1, false, "");
969 | }
970 |
971 | /**
972 | * checkEnum(int, T[]) with null values.
973 | */
974 | @Test(expected = NullPointerException.class)
975 | public void testNullCheckEnum1() {
976 | luaState.pushString("");
977 | luaState.checkEnum(1, (GcAction[]) null);
978 | }
979 |
980 | /**
981 | * checkEnum(int, T[], T) with null values.
982 | */
983 | @Test(expected = NullPointerException.class)
984 | public void testNullCheckEnum2() {
985 | luaState.pushString("");
986 | luaState.checkEnum(1, null, GcAction.STOP);
987 | }
988 |
989 | /**
990 | * checkEnum(int, T[]) with illegal argument.
991 | */
992 | @Test(expected = LuaRuntimeException.class)
993 | public void testIllegalCheckEnum1() {
994 | luaState.pushBoolean(false);
995 | luaState.checkEnum(1, GcAction.values());
996 | }
997 |
998 | /**
999 | * checkEnum(int, T[], T) with illegal argument.
1000 | */
1001 | @Test(expected = LuaRuntimeException.class)
1002 | public void testIllegalCheckEnum2() {
1003 | luaState.pushBoolean(false);
1004 | luaState.checkEnum(1, GcAction.values(), GcAction.STOP);
1005 | }
1006 |
1007 | /**
1008 | * checkInteger(int) with illegal argument.
1009 | */
1010 | @Test(expected = LuaRuntimeException.class)
1011 | public void testIllegalCheckInteger1() {
1012 | luaState.pushBoolean(false);
1013 | luaState.checkInteger(1);
1014 | }
1015 |
1016 | /**
1017 | * checkInteger(int, int) with illegal argument.
1018 | */
1019 | @Test(expected = LuaRuntimeException.class)
1020 | public void testIllegalCheckInteger2() {
1021 | luaState.pushBoolean(false);
1022 | luaState.checkInteger(1, 2);
1023 | }
1024 |
1025 | /**
1026 | * checkJavaObject(int) with illegal argument.
1027 | */
1028 | @Test(expected = LuaRuntimeException.class)
1029 | public void testIllegalCheckJavaObject1() {
1030 | luaState.pushBoolean(false);
1031 | luaState.checkJavaObject(1, Integer.class);
1032 | }
1033 |
1034 | /**
1035 | * checkJavaObject(int, int) with illegal argument.
1036 | */
1037 | @Test(expected = LuaRuntimeException.class)
1038 | public void testIllegalCheckJavaFunction2() {
1039 | luaState.pushBoolean(false);
1040 | luaState.checkJavaObject(1, Integer.class, Integer.valueOf(0));
1041 | }
1042 |
1043 | /**
1044 | * checkNumber(int) with illegal argument.
1045 | */
1046 | @Test(expected = LuaRuntimeException.class)
1047 | public void testIllegalCheckNumber1() {
1048 | luaState.pushBoolean(false);
1049 | luaState.checkNumber(1);
1050 | }
1051 |
1052 | /**
1053 | * checkNumber(int, double) with illegal argument.
1054 | */
1055 | @Test(expected = LuaRuntimeException.class)
1056 | public void testIllegalCheckNumber2() {
1057 | luaState.pushBoolean(false);
1058 | luaState.checkNumber(1, 2.0);
1059 | }
1060 |
1061 | /**
1062 | * checkOption(int, String[]) with null values.
1063 | */
1064 | @Test(expected = NullPointerException.class)
1065 | public void testNullCheckOption1() {
1066 | luaState.pushInteger(1);
1067 | luaState.checkOption(1, null);
1068 | }
1069 |
1070 | /**
1071 | * checkOption(int, String[], String) with null values.
1072 | */
1073 | @Test(expected = NullPointerException.class)
1074 | public void testNullCheckOption2() {
1075 | luaState.pushInteger(1);
1076 | luaState.checkOption(1, null, "");
1077 | }
1078 |
1079 | /**
1080 | * checkOption(int, String[]) with illegal argument.
1081 | */
1082 | @Test(expected = LuaRuntimeException.class)
1083 | public void testIllegalCheckOption1() {
1084 | luaState.pushInteger(1);
1085 | luaState.checkOption(1, new String[] { "test" });
1086 | }
1087 |
1088 | /**
1089 | * checkOption(int, String[], String) with illegal argument.
1090 | */
1091 | @Test(expected = LuaRuntimeException.class)
1092 | public void testIllegalCheckOption2() {
1093 | luaState.pushInteger(1);
1094 | luaState.checkOption(1, new String[] { "test" }, "test");
1095 | }
1096 |
1097 | /**
1098 | * checkOption(int, String[], String) with illegal default option.
1099 | */
1100 | @Test(expected = LuaRuntimeException.class)
1101 | public void testIllegalCheckOption3() {
1102 | luaState.checkOption(1, new String[] { "test" }, "");
1103 | }
1104 |
1105 | /**
1106 | * checkString(int) with illegal argument.
1107 | */
1108 | @Test(expected = LuaRuntimeException.class)
1109 | public void testIllegalCheckString1() {
1110 | luaState.pushBoolean(false);
1111 | luaState.checkString(1);
1112 | }
1113 |
1114 | /**
1115 | * checkString(int, String) with illegal argument.
1116 | */
1117 | @Test(expected = LuaRuntimeException.class)
1118 | public void testIllegalCheckString2() {
1119 | luaState.pushBoolean(false);
1120 | luaState.checkString(1, "");
1121 | }
1122 |
1123 | // -- Proxy tests
1124 | /**
1125 | * getProxy(int, Class[]) with null interface.
1126 | */
1127 | @Test(expected = NullPointerException.class)
1128 | public void testNullGetProxy() {
1129 | luaState.newTable();
1130 | luaState.getProxy(1, new Class>[] { null });
1131 | }
1132 |
1133 | /**
1134 | * getProxy(int) with illegal index.
1135 | */
1136 | @Test(expected = IllegalArgumentException.class)
1137 | public void testIllegalGetProxy1() {
1138 | luaState.getProxy(getIllegalIndex());
1139 | }
1140 |
1141 | /**
1142 | * getProxy(int, Class>) with illegal index.
1143 | */
1144 | @Test(expected = IllegalArgumentException.class)
1145 | public void testIllegalGetProxy2() {
1146 | luaState.getProxy(getIllegalIndex(), Runnable.class);
1147 | }
1148 |
1149 | /**
1150 | * getProxy(int, Class>) with illegal table.
1151 | */
1152 | @Test(expected = IllegalArgumentException.class)
1153 | public void testIllegalGetProxy3() {
1154 | luaState.pushNumber(0.0);
1155 | luaState.getProxy(1, Runnable.class);
1156 | }
1157 |
1158 | /**
1159 | * getProxy(int, Class>[]) with illegal index.
1160 | */
1161 | @Test(expected = IllegalArgumentException.class)
1162 | public void testIllegalGetProxy4() {
1163 | luaState.getProxy(getIllegalIndex(), new Class>[] { Runnable.class });
1164 | }
1165 |
1166 | /**
1167 | * getProxy(int, Class>[]) with illegal table.
1168 | */
1169 | @Test(expected = IllegalArgumentException.class)
1170 | public void testIllegalGetProxy5() {
1171 | luaState.pushNumber(0.0);
1172 | luaState.getProxy(1, new Class>[] { Runnable.class });
1173 | }
1174 |
1175 | // -- Private methods
1176 | /**
1177 | * Returns an illegal index.
1178 | */
1179 | private int getIllegalIndex() {
1180 | return luaState.getTop() + 1;
1181 | }
1182 | }
1183 |
--------------------------------------------------------------------------------