Added missed Classes
This commit is contained in:
485
core/src/main/java/org/luaj/vm2/libs/BaseLib.java
Normal file
485
core/src/main/java/org/luaj/vm2/libs/BaseLib.java
Normal file
@@ -0,0 +1,485 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaThread;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/**
|
||||
* Subclass of {@link LibFunction} which implements the lua basic library functions.
|
||||
* <p>
|
||||
* This contains all library functions listed as "basic functions" in the lua documentation for JME.
|
||||
* The functions dofile and loadfile use the
|
||||
* {@link Globals#finder} instance to find resource files.
|
||||
* Since JME has no file system by default, {@link BaseLib} implements
|
||||
* {@link ResourceFinder} using {@link Class#getResource(String)},
|
||||
* which is the closest equivalent on JME.
|
||||
* The default loader chain in {@link PackageLib} will use these as well.
|
||||
* <p>
|
||||
* To use basic library functions that include a {@link ResourceFinder} based on
|
||||
* directory lookup, use {@link org.luaj.vm2.libs.jse.JseBaseLib} instead.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* {@link org.luaj.vm2.libs.jse.JsePlatform#standardGlobals()} or
|
||||
* {@link org.luaj.vm2.libs.jme.JmePlatform#standardGlobals()}
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.standardGlobals();
|
||||
* globals.get("print").call(LuaValue.valueOf("hello, world"));
|
||||
* } </pre>
|
||||
* <p>
|
||||
* For special cases where the smallest possible footprint is desired,
|
||||
* a minimal set of libraries could be loaded
|
||||
* directly via {@link Globals#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* Globals globals = new Globals();
|
||||
* globals.load(new JseBaseLib());
|
||||
* globals.get("print").call(LuaValue.valueOf("hello, world"));
|
||||
* } </pre>
|
||||
* Doing so will ensure the library is properly initialized
|
||||
* and loaded into the globals table.
|
||||
* <p>
|
||||
* This is a direct port of the corresponding library in C.
|
||||
* @see org.luaj.vm2.libs.jse.JseBaseLib
|
||||
* @see ResourceFinder
|
||||
* @see Globals#finder
|
||||
* @see LibFunction
|
||||
* @see org.luaj.vm2.libs.jse.JsePlatform
|
||||
* @see org.luaj.vm2.libs.jme.JmePlatform
|
||||
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.1">Lua 5.2 Base Lib Reference</a>
|
||||
*/
|
||||
public class BaseLib extends TwoArgFunction implements ResourceFinder {
|
||||
|
||||
Globals globals;
|
||||
|
||||
|
||||
/** Perform one-time initialization on the library by adding base functions
|
||||
* to the supplied environment, and returning it as the return value.
|
||||
* @param modname the module name supplied if this is loaded via 'require'.
|
||||
* @param env the environment to load into, which must be a Globals instance.
|
||||
*/
|
||||
public LuaValue call(LuaValue modname, LuaValue env) {
|
||||
globals = env.checkglobals();
|
||||
globals.finder = this;
|
||||
globals.baselib = this;
|
||||
env.set( "_G", env );
|
||||
env.set( "_VERSION", Lua._VERSION );
|
||||
env.set("assert", new _assert());
|
||||
env.set("collectgarbage", new collectgarbage());
|
||||
env.set("dofile", new dofile());
|
||||
env.set("error", new error());
|
||||
env.set("getmetatable", new getmetatable());
|
||||
env.set("load", new load());
|
||||
env.set("loadfile", new loadfile());
|
||||
env.set("pcall", new pcall());
|
||||
env.set("print", new print(this));
|
||||
env.set("rawequal", new rawequal());
|
||||
env.set("rawget", new rawget());
|
||||
env.set("rawlen", new rawlen());
|
||||
env.set("rawset", new rawset());
|
||||
env.set("select", new select());
|
||||
env.set("setmetatable", new setmetatable());
|
||||
env.set("tonumber", new tonumber());
|
||||
env.set("tostring", new tostring());
|
||||
env.set("type", new type());
|
||||
env.set("xpcall", new xpcall());
|
||||
|
||||
next next;
|
||||
env.set("next", next = new next());
|
||||
env.set("pairs", new pairs(next));
|
||||
env.set("ipairs", new ipairs());
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
/** ResourceFinder implementation
|
||||
*
|
||||
* Tries to open the file as a resource, which can work for JSE and JME.
|
||||
*/
|
||||
public InputStream findResource(String filename) {
|
||||
return getClass().getResourceAsStream(filename.startsWith("/")? filename: "/"+filename);
|
||||
}
|
||||
|
||||
|
||||
// "assert", // ( v [,message] ) -> v, message | ERR
|
||||
static final class _assert extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
if ( !args.arg1().toboolean() )
|
||||
error( args.narg()>1? args.optjstring(2,"assertion failed!"): "assertion failed!" );
|
||||
return args;
|
||||
}
|
||||
}
|
||||
|
||||
// "collectgarbage", // ( opt [,arg] ) -> value
|
||||
static final class collectgarbage extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
String s = args.optjstring(1, "collect");
|
||||
if ( "collect".equals(s) ) {
|
||||
System.gc();
|
||||
return ZERO;
|
||||
} else if ( "count".equals(s) ) {
|
||||
Runtime rt = Runtime.getRuntime();
|
||||
long used = rt.totalMemory() - rt.freeMemory();
|
||||
return varargsOf(valueOf(used/1024.), valueOf(used%1024));
|
||||
} else if ( "step".equals(s) ) {
|
||||
System.gc();
|
||||
return LuaValue.TRUE;
|
||||
} else {
|
||||
argerror(1, "invalid option '" + s + "'");
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
// "dofile", // ( filename ) -> result1, ...
|
||||
final class dofile extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or nil");
|
||||
String filename = args.isstring(1)? args.tojstring(1): null;
|
||||
Varargs v = filename == null?
|
||||
loadStream( globals.STDIN, "=stdin", "bt", globals ):
|
||||
loadFile( args.checkjstring(1), "bt", globals );
|
||||
return v.isnil(1)? error(v.tojstring(2)): v.arg1().invoke();
|
||||
}
|
||||
}
|
||||
|
||||
// "error", // ( message [,level] ) -> ERR
|
||||
static final class error extends TwoArgFunction {
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
if (arg1.isnil()) throw new LuaError(NIL);
|
||||
if (!arg1.isstring() || arg2.optint(1) == 0) throw new LuaError(arg1);
|
||||
throw new LuaError(arg1.tojstring(), arg2.optint(1));
|
||||
}
|
||||
}
|
||||
|
||||
// "getmetatable", // ( object ) -> table
|
||||
static final class getmetatable extends LibFunction {
|
||||
public LuaValue call() {
|
||||
return argerror(1, "value expected");
|
||||
}
|
||||
public LuaValue call(LuaValue arg) {
|
||||
LuaValue mt = arg.getmetatable();
|
||||
return mt!=null? mt.rawget(METATABLE).optvalue(mt): NIL;
|
||||
}
|
||||
}
|
||||
// "load", // ( ld [, source [, mode [, env]]] ) -> chunk | nil, msg
|
||||
final class load extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaValue ld = args.arg1();
|
||||
if (!ld.isstring() && !ld.isfunction()) {
|
||||
throw new LuaError("bad argument #1 to 'load' (string or function expected, got " + ld.typename() + ")");
|
||||
}
|
||||
String source = args.optjstring(2, ld.isstring()? ld.tojstring(): "=(load)");
|
||||
String mode = args.optjstring(3, "bt");
|
||||
LuaValue env = args.optvalue(4, globals);
|
||||
return loadStream(ld.isstring()? ld.strvalue().toInputStream():
|
||||
new StringInputStream(ld.checkfunction()), source, mode, env);
|
||||
}
|
||||
}
|
||||
|
||||
// "loadfile", // ( [filename [, mode [, env]]] ) -> chunk | nil, msg
|
||||
final class loadfile extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or nil");
|
||||
String filename = args.isstring(1)? args.tojstring(1): null;
|
||||
String mode = args.optjstring(2, "bt");
|
||||
LuaValue env = args.optvalue(3, globals);
|
||||
return filename == null?
|
||||
loadStream( globals.STDIN, "=stdin", mode, env ):
|
||||
loadFile( filename, mode, env );
|
||||
}
|
||||
}
|
||||
|
||||
// "pcall", // (f, arg1, ...) -> status, result1, ...
|
||||
final class pcall extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaValue func = args.checkvalue(1);
|
||||
if (globals != null && globals.debuglib != null)
|
||||
globals.debuglib.onCall(this);
|
||||
try {
|
||||
return varargsOf(TRUE, func.invoke(args.subargs(2)));
|
||||
} catch ( LuaError le ) {
|
||||
final LuaValue m = le.getMessageObject();
|
||||
return varargsOf(FALSE, m!=null? m: NIL);
|
||||
} catch ( Exception e ) {
|
||||
final String m = e.getMessage();
|
||||
return varargsOf(FALSE, valueOf(m!=null? m: e.toString()));
|
||||
} finally {
|
||||
if (globals != null && globals.debuglib != null)
|
||||
globals.debuglib.onReturn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// "print", // (...) -> void
|
||||
final class print extends VarArgFunction {
|
||||
final BaseLib baselib;
|
||||
print(BaseLib baselib) {
|
||||
this.baselib = baselib;
|
||||
}
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaValue tostring = globals.get("tostring");
|
||||
for ( int i=1, n=args.narg(); i<=n; i++ ) {
|
||||
if ( i>1 ) globals.STDOUT.print( '\t' );
|
||||
LuaString s = tostring.call( args.arg(i) ).strvalue();
|
||||
globals.STDOUT.print(s.tojstring());
|
||||
}
|
||||
globals.STDOUT.print('\n');
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// "rawequal", // (v1, v2) -> boolean
|
||||
static final class rawequal extends LibFunction {
|
||||
public LuaValue call() {
|
||||
return argerror(1, "value expected");
|
||||
}
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return argerror(2, "value expected");
|
||||
}
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return valueOf(arg1.raweq(arg2));
|
||||
}
|
||||
}
|
||||
|
||||
// "rawget", // (table, index) -> value
|
||||
static final class rawget extends TableLibFunction {
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return argerror(2, "value expected");
|
||||
}
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return arg1.checktable().rawget(arg2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// "rawlen", // (v) -> value
|
||||
static final class rawlen extends LibFunction {
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return valueOf(arg.rawlen());
|
||||
}
|
||||
}
|
||||
|
||||
// "rawset", // (table, index, value) -> table
|
||||
static final class rawset extends TableLibFunction {
|
||||
public LuaValue call(LuaValue table) {
|
||||
return argerror(2,"value expected");
|
||||
}
|
||||
public LuaValue call(LuaValue table, LuaValue index) {
|
||||
return argerror(3,"value expected");
|
||||
}
|
||||
public LuaValue call(LuaValue table, LuaValue index, LuaValue value) {
|
||||
LuaTable t = table.checktable();
|
||||
if (!index.isvalidkey()) argerror(2, "table index is nil");
|
||||
t.rawset(index, value);
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
// "select", // (f, ...) -> value1, ...
|
||||
static final class select extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
int n = args.narg()-1;
|
||||
if ( args.arg1().equals(valueOf("#")) )
|
||||
return valueOf(n);
|
||||
int i = args.checkint(1);
|
||||
if ( i == 0 || i < -n )
|
||||
argerror(1,"index out of range");
|
||||
return args.subargs(i<0? n+i+2: i+1);
|
||||
}
|
||||
}
|
||||
|
||||
// "setmetatable", // (table, metatable) -> table
|
||||
static final class setmetatable extends TableLibFunction {
|
||||
public LuaValue call(LuaValue table) {
|
||||
return argerror(2,"nil or table expected");
|
||||
}
|
||||
public LuaValue call(LuaValue table, LuaValue metatable) {
|
||||
final LuaValue mt0 = table.checktable().getmetatable();
|
||||
if ( mt0!=null && !mt0.rawget(METATABLE).isnil() )
|
||||
error("cannot change a protected metatable");
|
||||
return table.setmetatable(metatable.isnil()? null: metatable.checktable());
|
||||
}
|
||||
}
|
||||
|
||||
// "tonumber", // (e [,base]) -> value
|
||||
static final class tonumber extends LibFunction {
|
||||
public LuaValue call(LuaValue e) {
|
||||
return e.tonumber();
|
||||
}
|
||||
public LuaValue call(LuaValue e, LuaValue base) {
|
||||
if (base.isnil())
|
||||
return e.tonumber();
|
||||
final int b = base.checkint();
|
||||
if ( b < 2 || b > 36 )
|
||||
argerror(2, "base out of range");
|
||||
return e.checkstring().tonumber(b);
|
||||
}
|
||||
}
|
||||
|
||||
// "tostring", // (e) -> value
|
||||
static final class tostring extends LibFunction {
|
||||
public LuaValue call(LuaValue arg) {
|
||||
LuaValue h = arg.metatag(TOSTRING);
|
||||
if ( ! h.isnil() )
|
||||
return h.call(arg);
|
||||
LuaValue v = arg.tostring();
|
||||
if ( ! v.isnil() )
|
||||
return v;
|
||||
return valueOf(arg.tojstring());
|
||||
}
|
||||
}
|
||||
|
||||
// "type", // (v) -> value
|
||||
static final class type extends LibFunction {
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return valueOf(arg.typename());
|
||||
}
|
||||
}
|
||||
|
||||
// "xpcall", // (f, err) -> result1, ...
|
||||
final class xpcall extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
final LuaThread t = globals.running;
|
||||
final LuaValue preverror = t.errorfunc;
|
||||
t.errorfunc = args.checkvalue(2);
|
||||
try {
|
||||
if (globals != null && globals.debuglib != null)
|
||||
globals.debuglib.onCall(this);
|
||||
try {
|
||||
return varargsOf(TRUE, args.arg1().invoke(args.subargs(3)));
|
||||
} catch ( LuaError le ) {
|
||||
final LuaValue m = le.getMessageObject();
|
||||
return varargsOf(FALSE, m!=null? m: NIL);
|
||||
} catch ( Exception e ) {
|
||||
final String m = e.getMessage();
|
||||
return varargsOf(FALSE, valueOf(m!=null? m: e.toString()));
|
||||
} finally {
|
||||
if (globals != null && globals.debuglib != null)
|
||||
globals.debuglib.onReturn();
|
||||
}
|
||||
} finally {
|
||||
t.errorfunc = preverror;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// "pairs" (t) -> iter-func, t, nil
|
||||
static final class pairs extends VarArgFunction {
|
||||
final next next;
|
||||
pairs(next next) {
|
||||
this.next = next;
|
||||
}
|
||||
public Varargs invoke(Varargs args) {
|
||||
return varargsOf( next, args.checktable(1), NIL );
|
||||
}
|
||||
}
|
||||
|
||||
// // "ipairs", // (t) -> iter-func, t, 0
|
||||
static final class ipairs extends VarArgFunction {
|
||||
inext inext = new inext();
|
||||
public Varargs invoke(Varargs args) {
|
||||
return varargsOf( inext, args.checktable(1), ZERO );
|
||||
}
|
||||
}
|
||||
|
||||
// "next" ( table, [index] ) -> next-index, next-value
|
||||
static final class next extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
return args.checktable(1).next(args.arg(2));
|
||||
}
|
||||
}
|
||||
|
||||
// "inext" ( table, [int-index] ) -> next-index, next-value
|
||||
static final class inext extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
return args.checktable(1).inext(args.arg(2));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load from a named file, returning the chunk or nil,error of can't load
|
||||
* @param env
|
||||
* @param mode
|
||||
* @return Varargs containing chunk, or NIL,error-text on error
|
||||
*/
|
||||
public Varargs loadFile(String filename, String mode, LuaValue env) {
|
||||
InputStream is = globals.finder.findResource(filename);
|
||||
if ( is == null )
|
||||
return varargsOf(NIL, valueOf("cannot open "+filename+": No such file or directory"));
|
||||
try {
|
||||
return loadStream(is, "@"+filename, mode, env);
|
||||
} finally {
|
||||
try {
|
||||
is.close();
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Varargs loadStream(InputStream is, String chunkname, String mode, LuaValue env) {
|
||||
try {
|
||||
if ( is == null )
|
||||
return varargsOf(NIL, valueOf("not found: "+chunkname));
|
||||
return globals.load(is, chunkname, mode, env);
|
||||
} catch (Exception e) {
|
||||
return varargsOf(NIL, valueOf(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class StringInputStream extends InputStream {
|
||||
final LuaValue func;
|
||||
byte[] bytes;
|
||||
int offset, remaining = 0;
|
||||
StringInputStream(LuaValue func) {
|
||||
this.func = func;
|
||||
}
|
||||
public int read() throws IOException {
|
||||
if ( remaining < 0 )
|
||||
return -1;
|
||||
if ( remaining == 0 ) {
|
||||
LuaValue s = func.call();
|
||||
if ( s.isnil() )
|
||||
return remaining = -1;
|
||||
LuaString ls = s.strvalue();
|
||||
bytes = ls.m_bytes;
|
||||
offset = ls.m_offset;
|
||||
remaining = ls.m_length;
|
||||
if (remaining <= 0)
|
||||
return -1;
|
||||
}
|
||||
--remaining;
|
||||
return 0xFF&bytes[offset++];
|
||||
}
|
||||
}
|
||||
}
|
||||
224
core/src/main/java/org/luaj/vm2/libs/Bit32Lib.java
Normal file
224
core/src/main/java/org/luaj/vm2/libs/Bit32Lib.java
Normal file
@@ -0,0 +1,224 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs;
|
||||
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/**
|
||||
* Subclass of LibFunction that implements the Lua standard {@code bit32} library.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* {@link org.luaj.vm2.libs.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.libs.jme.JmePlatform#standardGlobals()}
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.standardGlobals();
|
||||
* System.out.println( globals.get("bit32").get("bnot").call( LuaValue.valueOf(2) ) );
|
||||
* } </pre>
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* Globals globals = new Globals();
|
||||
* globals.load(new JseBaseLib());
|
||||
* globals.load(new PackageLib());
|
||||
* globals.load(new Bit32Lib());
|
||||
* System.out.println( globals.get("bit32").get("bnot").call( LuaValue.valueOf(2) ) );
|
||||
* } </pre>
|
||||
* <p>
|
||||
* This has been implemented to match as closely as possible the behavior in the corresponding library in C.
|
||||
* @see LibFunction
|
||||
* @see org.luaj.vm2.libs.jse.JsePlatform
|
||||
* @see org.luaj.vm2.libs.jme.JmePlatform
|
||||
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.7">Lua 5.2 Bitwise Operation Lib Reference</a>
|
||||
*/
|
||||
public class Bit32Lib extends TwoArgFunction {
|
||||
|
||||
public Bit32Lib() {
|
||||
}
|
||||
|
||||
/** Perform one-time initialization on the library by creating a table
|
||||
* containing the library functions, adding that table to the supplied environment,
|
||||
* adding the table to package.loaded, and returning table as the return value.
|
||||
* @param modname the module name supplied if this is loaded via 'require'.
|
||||
* @param env the environment to load into, which must be a Globals instance.
|
||||
*/
|
||||
public LuaValue call(LuaValue modname, LuaValue env) {
|
||||
LuaTable t = new LuaTable();
|
||||
bind(t, Bit32LibV.class, new String[] {
|
||||
"band", "bnot", "bor", "btest", "bxor", "extract", "replace"
|
||||
});
|
||||
bind(t, Bit32Lib2.class, new String[] {
|
||||
"arshift", "lrotate", "lshift", "rrotate", "rshift"
|
||||
});
|
||||
env.set("bit32", t);
|
||||
if (!env.get("package").isnil()) env.get("package").get("loaded").set("bit32", t);
|
||||
return t;
|
||||
}
|
||||
|
||||
static final class Bit32LibV extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
switch ( opcode ) {
|
||||
case 0: return Bit32Lib.band( args );
|
||||
case 1: return Bit32Lib.bnot( args );
|
||||
case 2: return Bit32Lib.bor( args );
|
||||
case 3: return Bit32Lib.btest( args );
|
||||
case 4: return Bit32Lib.bxor( args );
|
||||
case 5:
|
||||
return Bit32Lib.extract( args.checkint(1), args.checkint(2), args.optint(3, 1) );
|
||||
case 6:
|
||||
return Bit32Lib.replace( args.checkint(1), args.checkint(2),
|
||||
args.checkint(3), args.optint(4, 1) );
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
static final class Bit32Lib2 extends TwoArgFunction {
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
switch ( opcode ) {
|
||||
case 0: return Bit32Lib.arshift(arg1.checkint(), arg2.checkint());
|
||||
case 1: return Bit32Lib.lrotate(arg1.checkint(), arg2.checkint());
|
||||
case 2: return Bit32Lib.lshift(arg1.checkint(), arg2.checkint());
|
||||
case 3: return Bit32Lib.rrotate(arg1.checkint(), arg2.checkint());
|
||||
case 4: return Bit32Lib.rshift(arg1.checkint(), arg2.checkint());
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static LuaValue arshift(int x, int disp) {
|
||||
if (disp >= 0) {
|
||||
return bitsToValue(x >> disp);
|
||||
} else {
|
||||
return bitsToValue(x << -disp);
|
||||
}
|
||||
}
|
||||
|
||||
static LuaValue rshift(int x, int disp) {
|
||||
if (disp >= 32 || disp <= -32) {
|
||||
return ZERO;
|
||||
} else if (disp >= 0) {
|
||||
return bitsToValue(x >>> disp);
|
||||
} else {
|
||||
return bitsToValue(x << -disp);
|
||||
}
|
||||
}
|
||||
|
||||
static LuaValue lshift(int x, int disp) {
|
||||
if (disp >= 32 || disp <= -32) {
|
||||
return ZERO;
|
||||
} else if (disp >= 0) {
|
||||
return bitsToValue(x << disp);
|
||||
} else {
|
||||
return bitsToValue(x >>> -disp);
|
||||
}
|
||||
}
|
||||
|
||||
static Varargs band( Varargs args ) {
|
||||
int result = -1;
|
||||
for ( int i = 1; i <= args.narg(); i++ ) {
|
||||
result &= args.checkint(i);
|
||||
}
|
||||
return bitsToValue( result );
|
||||
}
|
||||
|
||||
static Varargs bnot( Varargs args ) {
|
||||
return bitsToValue( ~args.checkint(1) );
|
||||
}
|
||||
|
||||
static Varargs bor( Varargs args ) {
|
||||
int result = 0;
|
||||
for ( int i = 1; i <= args.narg(); i++ ) {
|
||||
result |= args.checkint(i);
|
||||
}
|
||||
return bitsToValue( result );
|
||||
}
|
||||
|
||||
static Varargs btest( Varargs args ) {
|
||||
int bits = -1;
|
||||
for ( int i = 1; i <= args.narg(); i++ ) {
|
||||
bits &= args.checkint(i);
|
||||
}
|
||||
return valueOf( bits != 0 );
|
||||
}
|
||||
|
||||
static Varargs bxor( Varargs args ) {
|
||||
int result = 0;
|
||||
for ( int i = 1; i <= args.narg(); i++ ) {
|
||||
result ^= args.checkint(i);
|
||||
}
|
||||
return bitsToValue( result );
|
||||
}
|
||||
|
||||
static LuaValue lrotate(int x, int disp) {
|
||||
if (disp < 0) {
|
||||
return rrotate(x, -disp);
|
||||
} else {
|
||||
disp = disp & 31;
|
||||
return bitsToValue((x << disp) | (x >>> (32 - disp)));
|
||||
}
|
||||
}
|
||||
|
||||
static LuaValue rrotate(int x, int disp) {
|
||||
if (disp < 0) {
|
||||
return lrotate(x, -disp);
|
||||
} else {
|
||||
disp = disp & 31;
|
||||
return bitsToValue((x >>> disp) | (x << (32 - disp)));
|
||||
}
|
||||
}
|
||||
|
||||
static LuaValue extract(int n, int field, int width) {
|
||||
if (field < 0) {
|
||||
argerror(2, "field cannot be negative");
|
||||
}
|
||||
if (width < 0) {
|
||||
argerror(3, "width must be postive");
|
||||
}
|
||||
if (field + width > 32) {
|
||||
error("trying to access non-existent bits");
|
||||
}
|
||||
return bitsToValue((n >>> field) & (-1 >>> (32 - width)));
|
||||
}
|
||||
|
||||
static LuaValue replace(int n, int v, int field, int width) {
|
||||
if (field < 0) {
|
||||
argerror(3, "field cannot be negative");
|
||||
}
|
||||
if (width < 0) {
|
||||
argerror(4, "width must be postive");
|
||||
}
|
||||
if (field + width > 32) {
|
||||
error("trying to access non-existent bits");
|
||||
}
|
||||
int mask = (-1 >>> (32 - width)) << field;
|
||||
n = (n & ~mask) | ((v << field) & mask);
|
||||
return bitsToValue(n);
|
||||
}
|
||||
|
||||
private static LuaValue bitsToValue( int x ) {
|
||||
return ( x < 0 ) ? valueOf((double) ((long) x & 0xFFFFFFFFL)) : valueOf(x);
|
||||
}
|
||||
}
|
||||
144
core/src/main/java/org/luaj/vm2/libs/CoroutineLib.java
Normal file
144
core/src/main/java/org/luaj/vm2/libs/CoroutineLib.java
Normal file
@@ -0,0 +1,144 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2007-2011 LuaJ. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaThread;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/**
|
||||
* Subclass of {@link LibFunction} which implements the lua standard {@code coroutine}
|
||||
* library.
|
||||
* <p>
|
||||
* The coroutine library in luaj has the same behavior as the
|
||||
* coroutine library in C, but is implemented using Java Threads to maintain
|
||||
* the call state between invocations. Therefore it can be yielded from anywhere,
|
||||
* similar to the "Coco" yield-from-anywhere patch available for C-based lua.
|
||||
* However, coroutines that are yielded but never resumed to complete their execution
|
||||
* may not be collected by the garbage collector.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* {@link org.luaj.vm2.libs.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.libs.jme.JmePlatform#standardGlobals()}
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.standardGlobals();
|
||||
* System.out.println( globals.get("coroutine").get("running").call() );
|
||||
* } </pre>
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* Globals globals = new Globals();
|
||||
* globals.load(new JseBaseLib());
|
||||
* globals.load(new PackageLib());
|
||||
* globals.load(new CoroutineLib());
|
||||
* System.out.println( globals.get("coroutine").get("running").call() );
|
||||
* } </pre>
|
||||
* <p>
|
||||
* @see LibFunction
|
||||
* @see org.luaj.vm2.libs.jse.JsePlatform
|
||||
* @see org.luaj.vm2.libs.jme.JmePlatform
|
||||
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.2">Lua 5.2 Coroutine Lib Reference</a>
|
||||
*/
|
||||
public class CoroutineLib extends TwoArgFunction {
|
||||
|
||||
static int coroutine_count = 0;
|
||||
|
||||
Globals globals;
|
||||
|
||||
/** Perform one-time initialization on the library by creating a table
|
||||
* containing the library functions, adding that table to the supplied environment,
|
||||
* adding the table to package.loaded, and returning table as the return value.
|
||||
* @param modname the module name supplied if this is loaded via 'require'.
|
||||
* @param env the environment to load into, which must be a Globals instance.
|
||||
*/
|
||||
public LuaValue call(LuaValue modname, LuaValue env) {
|
||||
globals = env.checkglobals();
|
||||
LuaTable coroutine = new LuaTable();
|
||||
coroutine.set("create", new Create());
|
||||
coroutine.set("resume", new Resume());
|
||||
coroutine.set("running", new Running());
|
||||
coroutine.set("status", new Status());
|
||||
coroutine.set("yield", new Yield());
|
||||
coroutine.set("wrap", new Wrap());
|
||||
env.set("coroutine", coroutine);
|
||||
if (!env.get("package").isnil()) env.get("package").get("loaded").set("coroutine", coroutine);
|
||||
return coroutine;
|
||||
}
|
||||
|
||||
final class Create extends LibFunction {
|
||||
public LuaValue call(LuaValue f) {
|
||||
return new LuaThread(globals, f.checkfunction());
|
||||
}
|
||||
}
|
||||
|
||||
static final class Resume extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
final LuaThread t = args.checkthread(1);
|
||||
return t.resume( args.subargs(2) );
|
||||
}
|
||||
}
|
||||
|
||||
final class Running extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
final LuaThread r = globals.running;
|
||||
return varargsOf(r, valueOf(r.isMainThread()));
|
||||
}
|
||||
}
|
||||
|
||||
static final class Status extends LibFunction {
|
||||
public LuaValue call(LuaValue t) {
|
||||
LuaThread lt = t.checkthread();
|
||||
return valueOf( lt.getStatus() );
|
||||
}
|
||||
}
|
||||
|
||||
private final class Yield extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
return globals.yield( args );
|
||||
}
|
||||
}
|
||||
|
||||
final class Wrap extends LibFunction {
|
||||
public LuaValue call(LuaValue f) {
|
||||
final LuaValue func = f.checkfunction();
|
||||
final LuaThread thread = new LuaThread(globals, func);
|
||||
return new wrapper(thread);
|
||||
}
|
||||
}
|
||||
|
||||
static final class wrapper extends VarArgFunction {
|
||||
final LuaThread luathread;
|
||||
wrapper(LuaThread luathread) {
|
||||
this.luathread = luathread;
|
||||
}
|
||||
public Varargs invoke(Varargs args) {
|
||||
final Varargs result = luathread.resume(args);
|
||||
if ( result.arg1().toboolean() ) {
|
||||
return result.subargs(2);
|
||||
} else {
|
||||
return error( result.arg(2).tojstring() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
954
core/src/main/java/org/luaj/vm2/libs/DebugLib.java
Normal file
954
core/src/main/java/org/luaj/vm2/libs/DebugLib.java
Normal file
@@ -0,0 +1,954 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs;
|
||||
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.LuaBoolean;
|
||||
import org.luaj.vm2.LuaClosure;
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaFunction;
|
||||
import org.luaj.vm2.LuaNil;
|
||||
import org.luaj.vm2.LuaNumber;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaThread;
|
||||
import org.luaj.vm2.LuaUserdata;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Print;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/**
|
||||
* Subclass of {@link LibFunction} which implements the lua standard {@code debug}
|
||||
* library.
|
||||
* <p>
|
||||
* The debug library in luaj tries to emulate the behavior of the corresponding C-based lua library.
|
||||
* To do this, it must maintain a separate stack of calls to {@link LuaClosure} and {@link LibFunction}
|
||||
* instances.
|
||||
* Especially when lua-to-java bytecode compiling is being used
|
||||
* via a {@link org.luaj.vm2.Globals.Compiler} such as {@link org.luaj.vm2.luajc.LuaJC},
|
||||
* this cannot be done in all cases.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* {@link org.luaj.vm2.libs.jse.JsePlatform#debugGlobals()} or
|
||||
* {@link org.luaj.vm2.libs.jme.JmePlatform#debugGlobals()}
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.debugGlobals();
|
||||
* System.out.println( globals.get("debug").get("traceback").call() );
|
||||
* } </pre>
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* Globals globals = new Globals();
|
||||
* globals.load(new JseBaseLib());
|
||||
* globals.load(new PackageLib());
|
||||
* globals.load(new DebugLib());
|
||||
* System.out.println( globals.get("debug").get("traceback").call() );
|
||||
* } </pre>
|
||||
* <p>
|
||||
* This library exposes the entire state of lua code, and provides method to see and modify
|
||||
* all underlying lua values within a Java VM so should not be exposed to client code
|
||||
* in a shared server environment.
|
||||
*
|
||||
* @see LibFunction
|
||||
* @see org.luaj.vm2.libs.jse.JsePlatform
|
||||
* @see org.luaj.vm2.libs.jme.JmePlatform
|
||||
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.10">Lua 5.2 Debug Lib Reference</a>
|
||||
*/
|
||||
public class DebugLib extends TwoArgFunction {
|
||||
public static boolean CALLS;
|
||||
public static boolean TRACE;
|
||||
static {
|
||||
try { CALLS = (null != System.getProperty("CALLS")); } catch (Exception e) {}
|
||||
try { TRACE = (null != System.getProperty("TRACE")); } catch (Exception e) {}
|
||||
}
|
||||
|
||||
static final LuaString LUA = valueOf("Lua");
|
||||
private static final LuaString QMARK = valueOf("?");
|
||||
private static final LuaString CALL = valueOf("call");
|
||||
private static final LuaString LINE = valueOf("line");
|
||||
private static final LuaString COUNT = valueOf("count");
|
||||
private static final LuaString RETURN = valueOf("return");
|
||||
|
||||
static final LuaString FUNC = valueOf("func");
|
||||
static final LuaString ISTAILCALL = valueOf("istailcall");
|
||||
static final LuaString ISVARARG = valueOf("isvararg");
|
||||
static final LuaString NUPS = valueOf("nups");
|
||||
static final LuaString NPARAMS = valueOf("nparams");
|
||||
static final LuaString NAME = valueOf("name");
|
||||
static final LuaString NAMEWHAT = valueOf("namewhat");
|
||||
static final LuaString WHAT = valueOf("what");
|
||||
static final LuaString SOURCE = valueOf("source");
|
||||
static final LuaString SHORT_SRC = valueOf("short_src");
|
||||
static final LuaString LINEDEFINED = valueOf("linedefined");
|
||||
static final LuaString LASTLINEDEFINED = valueOf("lastlinedefined");
|
||||
static final LuaString CURRENTLINE = valueOf("currentline");
|
||||
static final LuaString ACTIVELINES = valueOf("activelines");
|
||||
|
||||
Globals globals;
|
||||
|
||||
/** Perform one-time initialization on the library by creating a table
|
||||
* containing the library functions, adding that table to the supplied environment,
|
||||
* adding the table to package.loaded, and returning table as the return value.
|
||||
* @param modname the module name supplied if this is loaded via 'require'.
|
||||
* @param env the environment to load into, which must be a Globals instance.
|
||||
*/
|
||||
public LuaValue call(LuaValue modname, LuaValue env) {
|
||||
globals = env.checkglobals();
|
||||
globals.debuglib = this;
|
||||
LuaTable debug = new LuaTable();
|
||||
debug.set("debug", new debug());
|
||||
debug.set("gethook", new gethook());
|
||||
debug.set("getinfo", new getinfo());
|
||||
debug.set("getlocal", new getlocal());
|
||||
debug.set("getmetatable", new getmetatable());
|
||||
debug.set("getregistry", new getregistry());
|
||||
debug.set("getupvalue", new getupvalue());
|
||||
debug.set("getuservalue", new getuservalue());
|
||||
debug.set("sethook", new sethook());
|
||||
debug.set("setlocal", new setlocal());
|
||||
debug.set("setmetatable", new setmetatable());
|
||||
debug.set("setupvalue", new setupvalue());
|
||||
debug.set("setuservalue", new setuservalue());
|
||||
debug.set("traceback", new traceback());
|
||||
debug.set("upvalueid", new upvalueid());
|
||||
debug.set("upvaluejoin", new upvaluejoin());
|
||||
env.set("debug", debug);
|
||||
if (!env.get("package").isnil()) env.get("package").get("loaded").set("debug", debug);
|
||||
return debug;
|
||||
}
|
||||
|
||||
// debug.debug()
|
||||
static final class debug extends ZeroArgFunction {
|
||||
public LuaValue call() {
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
// debug.gethook ([thread])
|
||||
final class gethook extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaThread t = args.narg() > 0 ? args.checkthread(1): globals.running;
|
||||
LuaThread.State s = t.state;
|
||||
return varargsOf(
|
||||
s.hookfunc != null? s.hookfunc: NIL,
|
||||
valueOf((s.hookcall?"c":"")+(s.hookline?"l":"")+(s.hookrtrn?"r":"")),
|
||||
valueOf(s.hookcount));
|
||||
}
|
||||
}
|
||||
|
||||
// debug.getinfo ([thread,] f [, what])
|
||||
final class getinfo extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
int a=1;
|
||||
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running;
|
||||
LuaValue func = args.arg(a++);
|
||||
String what = args.optjstring(a++, "flnStu");
|
||||
DebugLib.CallStack callstack = callstack(thread);
|
||||
|
||||
// find the stack info
|
||||
DebugLib.CallFrame frame;
|
||||
if ( func.isnumber() ) {
|
||||
frame = callstack.getCallFrame(func.toint());
|
||||
if (frame == null)
|
||||
return NONE;
|
||||
func = frame.f;
|
||||
} else if ( func.isfunction() ) {
|
||||
frame = callstack.findCallFrame(func);
|
||||
} else {
|
||||
return argerror(a-2, "function or level");
|
||||
}
|
||||
|
||||
// start a table
|
||||
DebugInfo ar = callstack.auxgetinfo(what, (LuaFunction) func, frame);
|
||||
LuaTable info = new LuaTable();
|
||||
if (what.indexOf('S') >= 0) {
|
||||
info.set(WHAT, LUA);
|
||||
info.set(SOURCE, valueOf(ar.source));
|
||||
info.set(SHORT_SRC, valueOf(ar.short_src));
|
||||
info.set(LINEDEFINED, valueOf(ar.linedefined));
|
||||
info.set(LASTLINEDEFINED, valueOf(ar.lastlinedefined));
|
||||
}
|
||||
if (what.indexOf('l') >= 0) {
|
||||
info.set( CURRENTLINE, valueOf(ar.currentline) );
|
||||
}
|
||||
if (what.indexOf('u') >= 0) {
|
||||
info.set(NUPS, valueOf(ar.nups));
|
||||
info.set(NPARAMS, valueOf(ar.nparams));
|
||||
info.set(ISVARARG, ar.isvararg? ONE: ZERO);
|
||||
}
|
||||
if (what.indexOf('n') >= 0) {
|
||||
info.set(NAME, LuaValue.valueOf(ar.name!=null? ar.name: "?"));
|
||||
info.set(NAMEWHAT, LuaValue.valueOf(ar.namewhat));
|
||||
}
|
||||
if (what.indexOf('t') >= 0) {
|
||||
info.set(ISTAILCALL, ZERO);
|
||||
}
|
||||
if (what.indexOf('L') >= 0) {
|
||||
LuaTable lines = new LuaTable();
|
||||
info.set(ACTIVELINES, lines);
|
||||
DebugLib.CallFrame cf;
|
||||
for (int l = 1; (cf=callstack.getCallFrame(l)) != null; ++l)
|
||||
if (cf.f == func)
|
||||
lines.insert(-1, valueOf(cf.currentline()));
|
||||
}
|
||||
if (what.indexOf('f') >= 0) {
|
||||
if (func != null)
|
||||
info.set( FUNC, func );
|
||||
}
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
// debug.getlocal ([thread,] f, local)
|
||||
final class getlocal extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
int a=1;
|
||||
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running;
|
||||
int level = args.checkint(a++);
|
||||
int local = args.checkint(a++);
|
||||
CallFrame f = callstack(thread).getCallFrame(level);
|
||||
return f != null? f.getLocal(local): NONE;
|
||||
}
|
||||
}
|
||||
|
||||
// debug.getmetatable (value)
|
||||
static final class getmetatable extends LibFunction {
|
||||
public LuaValue call(LuaValue v) {
|
||||
LuaValue mt = v.getmetatable();
|
||||
return mt != null? mt: NIL;
|
||||
}
|
||||
}
|
||||
|
||||
// debug.getregistry ()
|
||||
final class getregistry extends ZeroArgFunction {
|
||||
public LuaValue call() {
|
||||
return globals;
|
||||
}
|
||||
}
|
||||
|
||||
// debug.getupvalue (f, up)
|
||||
static final class getupvalue extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaValue func = args.checkfunction(1);
|
||||
int up = args.checkint(2);
|
||||
if ( func instanceof LuaClosure ) {
|
||||
LuaClosure c = (LuaClosure) func;
|
||||
LuaString name = findupvalue(c, up);
|
||||
if ( name != null ) {
|
||||
return varargsOf(name, c.upValues[up-1].getValue() );
|
||||
}
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
// debug.getuservalue (u)
|
||||
static final class getuservalue extends LibFunction {
|
||||
public LuaValue call(LuaValue u) {
|
||||
return u.isuserdata()? u: NIL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// debug.sethook ([thread,] hook, mask [, count])
|
||||
final class sethook extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
int a=1;
|
||||
LuaThread t = args.isthread(a)? args.checkthread(a++): globals.running;
|
||||
LuaValue func = args.optfunction(a++, null);
|
||||
String str = args.optjstring(a++,"");
|
||||
int count = args.optint(a++,0);
|
||||
boolean call=false,line=false,rtrn=false;
|
||||
for ( int i=0; i<str.length(); i++ )
|
||||
switch ( str.charAt(i) ) {
|
||||
case 'c': call=true; break;
|
||||
case 'l': line=true; break;
|
||||
case 'r': rtrn=true; break;
|
||||
}
|
||||
LuaThread.State s = t.state;
|
||||
s.hookfunc = func;
|
||||
s.hookcall = call;
|
||||
s.hookline = line;
|
||||
s.hookcount = count;
|
||||
s.hookrtrn = rtrn;
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
// debug.setlocal ([thread,] level, local, value)
|
||||
final class setlocal extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
int a=1;
|
||||
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running;
|
||||
int level = args.checkint(a++);
|
||||
int local = args.checkint(a++);
|
||||
LuaValue value = args.arg(a++);
|
||||
CallFrame f = callstack(thread).getCallFrame(level);
|
||||
return f != null? f.setLocal(local, value): NONE;
|
||||
}
|
||||
}
|
||||
|
||||
// debug.setmetatable (value, table)
|
||||
static final class setmetatable extends TwoArgFunction {
|
||||
public LuaValue call(LuaValue value, LuaValue table) {
|
||||
LuaValue mt = table.opttable(null);
|
||||
switch ( value.type() ) {
|
||||
case TNIL: LuaNil.s_metatable = mt; break;
|
||||
case TNUMBER: LuaNumber.s_metatable = mt; break;
|
||||
case TBOOLEAN: LuaBoolean.s_metatable = mt; break;
|
||||
case TSTRING: LuaString.s_metatable = mt; break;
|
||||
case TFUNCTION: LuaFunction.s_metatable = mt; break;
|
||||
case TTHREAD: LuaThread.s_metatable = mt; break;
|
||||
default: value.setmetatable( mt );
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
// debug.setupvalue (f, up, value)
|
||||
static final class setupvalue extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaValue func = args.checkfunction(1);
|
||||
int up = args.checkint(2);
|
||||
LuaValue value = args.arg(3);
|
||||
if ( func instanceof LuaClosure ) {
|
||||
LuaClosure c = (LuaClosure) func;
|
||||
LuaString name = findupvalue(c, up);
|
||||
if ( name != null ) {
|
||||
c.upValues[up-1].setValue(value);
|
||||
return name;
|
||||
}
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
// debug.setuservalue (udata, value)
|
||||
static final class setuservalue extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
Object o = args.checkuserdata(1);
|
||||
LuaValue v = args.checkvalue(2);
|
||||
LuaUserdata u = (LuaUserdata) args.arg1();
|
||||
u.m_instance = v.checkuserdata();
|
||||
u.m_metatable = v.getmetatable();
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
// debug.traceback ([thread,] [message [, level]])
|
||||
final class traceback extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
int a=1;
|
||||
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running;
|
||||
String message = args.optjstring(a++, null);
|
||||
int level = args.optint(a++,1);
|
||||
String tb = callstack(thread).traceback(level);
|
||||
return valueOf(message!=null? message+"\n"+tb: tb);
|
||||
}
|
||||
}
|
||||
|
||||
// debug.upvalueid (f, n)
|
||||
static final class upvalueid extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaValue func = args.checkfunction(1);
|
||||
int up = args.checkint(2);
|
||||
if ( func instanceof LuaClosure ) {
|
||||
LuaClosure c = (LuaClosure) func;
|
||||
if ( c.upValues != null && up > 0 && up <= c.upValues.length ) {
|
||||
return valueOf(c.upValues[up-1].hashCode());
|
||||
}
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
// debug.upvaluejoin (f1, n1, f2, n2)
|
||||
static final class upvaluejoin extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaClosure f1 = args.checkclosure(1);
|
||||
int n1 = args.checkint(2);
|
||||
LuaClosure f2 = args.checkclosure(3);
|
||||
int n2 = args.checkint(4);
|
||||
if (n1 < 1 || n1 > f1.upValues.length)
|
||||
argerror("index out of range");
|
||||
if (n2 < 1 || n2 > f2.upValues.length)
|
||||
argerror("index out of range");
|
||||
f1.upValues[n1-1] = f2.upValues[n2-1];
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
public void onCall(LuaFunction f) {
|
||||
LuaThread.State s = globals.running.state;
|
||||
if (s.inhook) return;
|
||||
callstack().onCall(f);
|
||||
if (s.hookcall) callHook(s, CALL, NIL);
|
||||
}
|
||||
|
||||
public void onCall(LuaClosure c, Varargs varargs, LuaValue[] stack) {
|
||||
LuaThread.State s = globals.running.state;
|
||||
if (s.inhook) return;
|
||||
callstack().onCall(c, varargs, stack);
|
||||
if (s.hookcall) callHook(s, CALL, NIL);
|
||||
}
|
||||
|
||||
public void onInstruction(int pc, Varargs v, int top) {
|
||||
LuaThread.State s = globals.running.state;
|
||||
if (s.inhook) return;
|
||||
callstack().onInstruction(pc, v, top);
|
||||
if (s.hookfunc == null) return;
|
||||
if (s.hookcount > 0)
|
||||
if (++s.bytecodes % s.hookcount == 0)
|
||||
callHook(s, COUNT, NIL);
|
||||
if (s.hookline) {
|
||||
int newline = callstack().currentline();
|
||||
if ( newline != s.lastline ) {
|
||||
s.lastline = newline;
|
||||
callHook(s, LINE, LuaValue.valueOf(newline));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onReturn() {
|
||||
LuaThread.State s = globals.running.state;
|
||||
if (s.inhook) return;
|
||||
callstack().onReturn();
|
||||
if (s.hookrtrn) callHook(s, RETURN, NIL);
|
||||
}
|
||||
|
||||
public String traceback(int level) {
|
||||
return callstack().traceback(level);
|
||||
}
|
||||
|
||||
public CallFrame getCallFrame(int level) {
|
||||
return callstack().getCallFrame(level);
|
||||
}
|
||||
|
||||
void callHook(LuaThread.State s, LuaValue type, LuaValue arg) {
|
||||
if (s.inhook || s.hookfunc == null) return;
|
||||
s.inhook = true;
|
||||
try {
|
||||
s.hookfunc.call(type, arg);
|
||||
} catch (LuaError e) {
|
||||
throw e;
|
||||
} catch (RuntimeException e) {
|
||||
throw new LuaError(e);
|
||||
} finally {
|
||||
s.inhook = false;
|
||||
}
|
||||
}
|
||||
|
||||
CallStack callstack() {
|
||||
return callstack(globals.running);
|
||||
}
|
||||
|
||||
CallStack callstack(LuaThread t) {
|
||||
if (t.callstack == null)
|
||||
t.callstack = new CallStack();
|
||||
return (CallStack) t.callstack;
|
||||
}
|
||||
|
||||
static class DebugInfo {
|
||||
String name; /* (n) */
|
||||
String namewhat; /* (n) 'global', 'local', 'field', 'method' */
|
||||
String what; /* (S) 'Lua', 'C', 'main', 'tail' */
|
||||
String source; /* (S) */
|
||||
int currentline; /* (l) */
|
||||
int linedefined; /* (S) */
|
||||
int lastlinedefined; /* (S) */
|
||||
short nups; /* (u) number of upvalues */
|
||||
short nparams;/* (u) number of parameters */
|
||||
boolean isvararg; /* (u) */
|
||||
boolean istailcall; /* (t) */
|
||||
String short_src; /* (S) */
|
||||
CallFrame cf; /* active function */
|
||||
|
||||
public void funcinfo(LuaFunction f) {
|
||||
if (f.isclosure()) {
|
||||
Prototype p = f.checkclosure().p;
|
||||
this.source = p.source != null ? p.source.tojstring() : "=?";
|
||||
this.linedefined = p.linedefined;
|
||||
this.lastlinedefined = p.lastlinedefined;
|
||||
this.what = (this.linedefined == 0) ? "main" : "Lua";
|
||||
this.short_src = p.shortsource();
|
||||
} else {
|
||||
this.source = "=[Java]";
|
||||
this.linedefined = -1;
|
||||
this.lastlinedefined = -1;
|
||||
this.what = "Java";
|
||||
this.short_src = f.name();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class CallStack {
|
||||
final static CallFrame[] EMPTY = {};
|
||||
CallFrame[] frame = EMPTY;
|
||||
int calls = 0;
|
||||
Lock lock = new ReentrantLock();
|
||||
|
||||
CallStack() {}
|
||||
|
||||
int currentline() {
|
||||
lock.lock();
|
||||
try {
|
||||
return calls > 0? frame[calls-1].currentline(): -1;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private CallFrame pushcall() {
|
||||
lock.lock();
|
||||
try {
|
||||
if (calls >= frame.length) {
|
||||
int n = Math.max(4, frame.length * 3 / 2);
|
||||
CallFrame[] f = new CallFrame[n];
|
||||
System.arraycopy(frame, 0, f, 0, frame.length);
|
||||
for (int i = frame.length; i < n; ++i)
|
||||
f[i] = new CallFrame();
|
||||
frame = f;
|
||||
for (int i = 1; i < n; ++i)
|
||||
f[i].previous = f[i-1];
|
||||
}
|
||||
return frame[calls++];
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
final void onCall(LuaFunction function) {
|
||||
lock.lock();
|
||||
try {
|
||||
pushcall().set(function);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
final void onCall(LuaClosure function, Varargs varargs, LuaValue[] stack) {
|
||||
lock.lock();
|
||||
try {
|
||||
pushcall().set(function, varargs, stack);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
final void onReturn() {
|
||||
lock.lock();
|
||||
try {
|
||||
if (calls > 0)
|
||||
frame[--calls].reset();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
final void onInstruction(int pc, Varargs v, int top) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (calls > 0)
|
||||
frame[calls-1].instr(pc, v, top);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the traceback starting at a specific level.
|
||||
* @param level
|
||||
* @return String containing the traceback.
|
||||
*/
|
||||
String traceback(int level) {
|
||||
lock.lock();
|
||||
try {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append( "stack traceback:" );
|
||||
for (DebugLib.CallFrame c; (c = getCallFrame(level++)) != null; ) {
|
||||
sb.append("\n\t");
|
||||
sb.append( c.shortsource() );
|
||||
sb.append( ':' );
|
||||
if (c.currentline() > 0)
|
||||
sb.append( c.currentline()+":" );
|
||||
sb.append( " in " );
|
||||
DebugInfo ar = auxgetinfo("n", c.f, c);
|
||||
if (c.linedefined() == 0)
|
||||
sb.append("main chunk");
|
||||
else if ( ar.name != null ) {
|
||||
sb.append( "function '" );
|
||||
sb.append( ar.name );
|
||||
sb.append( '\'' );
|
||||
} else {
|
||||
sb.append( "function <" );
|
||||
sb.append( c.shortsource() );
|
||||
sb.append( ':' );
|
||||
sb.append( c.linedefined() );
|
||||
sb.append( '>' );
|
||||
}
|
||||
}
|
||||
sb.append("\n\t[Java]: in ?");
|
||||
return sb.toString();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DebugLib.CallFrame getCallFrame(int level) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (level < 1 || level > calls)
|
||||
return null;
|
||||
return frame[calls-level];
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
DebugLib.CallFrame findCallFrame(LuaValue func) {
|
||||
lock.lock();
|
||||
try {
|
||||
for (int i = 1; i <= calls; ++i)
|
||||
if (frame[calls-i].f == func)
|
||||
return frame[i];
|
||||
return null;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DebugInfo auxgetinfo(String what, LuaFunction f, CallFrame ci) {
|
||||
lock.lock();
|
||||
try {
|
||||
DebugInfo ar = new DebugInfo();
|
||||
for (int i = 0, n = what.length(); i < n; ++i) {
|
||||
switch (what.charAt(i)) {
|
||||
case 'S':
|
||||
ar.funcinfo(f);
|
||||
break;
|
||||
case 'l':
|
||||
ar.currentline = ci != null && ci.f.isclosure()? ci.currentline(): -1;
|
||||
break;
|
||||
case 'u':
|
||||
if (f != null && f.isclosure()) {
|
||||
Prototype p = f.checkclosure().p;
|
||||
ar.nups = (short) p.upvalues.length;
|
||||
ar.nparams = (short) p.numparams;
|
||||
ar.isvararg = p.is_vararg != 0;
|
||||
} else {
|
||||
ar.nups = 0;
|
||||
ar.isvararg = true;
|
||||
ar.nparams = 0;
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
ar.istailcall = false;
|
||||
break;
|
||||
case 'n': {
|
||||
/* calling function is a known Lua function? */
|
||||
if (ci != null && ci.previous != null) {
|
||||
if (ci.previous.f.isclosure()) {
|
||||
NameWhat nw = getfuncname(ci.previous);
|
||||
if (nw != null) {
|
||||
ar.name = nw.name;
|
||||
ar.namewhat = nw.namewhat;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ar.namewhat == null) {
|
||||
ar.namewhat = ""; /* not found */
|
||||
ar.name = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'L':
|
||||
case 'f':
|
||||
break;
|
||||
default:
|
||||
// TODO: return bad status.
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ar;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class CallFrame {
|
||||
LuaFunction f;
|
||||
int pc;
|
||||
int top;
|
||||
Varargs v;
|
||||
LuaValue[] stack;
|
||||
CallFrame previous;
|
||||
void set(LuaClosure function, Varargs varargs, LuaValue[] stack) {
|
||||
this.f = function;
|
||||
this.v = varargs;
|
||||
this.stack = stack;
|
||||
}
|
||||
public String shortsource() {
|
||||
return f.isclosure()? f.checkclosure().p.shortsource(): "[Java]";
|
||||
}
|
||||
void set(LuaFunction function) {
|
||||
this.f = function;
|
||||
}
|
||||
void reset() {
|
||||
this.f = null;
|
||||
this.v = null;
|
||||
this.stack = null;
|
||||
}
|
||||
void instr(int pc, Varargs v, int top) {
|
||||
this.pc = pc;
|
||||
this.v = v;
|
||||
this.top = top;
|
||||
if (TRACE)
|
||||
Print.printState(f.checkclosure(), pc, stack, top, v);
|
||||
}
|
||||
Varargs getLocal(int i) {
|
||||
LuaString name = getlocalname(i);
|
||||
if ( i >= 1 && i <= stack.length && stack[i-1] != null )
|
||||
return varargsOf( name == null ? NIL : name, stack[i-1] );
|
||||
else
|
||||
return NIL;
|
||||
}
|
||||
Varargs setLocal(int i, LuaValue value) {
|
||||
LuaString name = getlocalname(i);
|
||||
if ( i >= 1 && i <= stack.length && stack[i-1] != null ) {
|
||||
stack[i-1] = value;
|
||||
return name == null ? NIL : name;
|
||||
} else {
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
public int currentline() {
|
||||
if ( !f.isclosure() ) return -1;
|
||||
int[] li = f.checkclosure().p.lineinfo;
|
||||
return li==null || pc<0 || pc>=li.length? -1: li[pc];
|
||||
}
|
||||
String sourceline() {
|
||||
if ( !f.isclosure() ) return f.tojstring();
|
||||
return f.checkclosure().p.shortsource() + ":" + currentline();
|
||||
}
|
||||
int linedefined() {
|
||||
return f.isclosure()? f.checkclosure().p.linedefined: -1;
|
||||
}
|
||||
LuaString getlocalname(int index) {
|
||||
if ( !f.isclosure() ) return null;
|
||||
return f.checkclosure().p.getlocalname(index, pc);
|
||||
}
|
||||
}
|
||||
|
||||
static LuaString findupvalue(LuaClosure c, int up) {
|
||||
if ( c.upValues != null && up > 0 && up <= c.upValues.length ) {
|
||||
if ( c.p.upvalues != null && up <= c.p.upvalues.length )
|
||||
return c.p.upvalues[up-1].name;
|
||||
else
|
||||
return LuaString.valueOf( "."+up );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static void lua_assert(boolean x) {
|
||||
if (!x) throw new RuntimeException("lua_assert failed");
|
||||
}
|
||||
|
||||
static class NameWhat {
|
||||
final String name;
|
||||
final String namewhat;
|
||||
NameWhat(String name, String namewhat) {
|
||||
this.name = name;
|
||||
this.namewhat = namewhat;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the name info if found, or null if no useful information could be found.
|
||||
static NameWhat getfuncname(DebugLib.CallFrame frame) {
|
||||
if (!frame.f.isclosure())
|
||||
return new NameWhat(frame.f.classnamestub(), "Java");
|
||||
Prototype p = frame.f.checkclosure().p;
|
||||
int pc = frame.pc;
|
||||
int i = p.code[pc]; /* calling instruction */
|
||||
LuaString tm;
|
||||
switch (Lua.GET_OPCODE(i)) {
|
||||
case Lua.OP_CALL:
|
||||
case Lua.OP_TAILCALL: /* get function name */
|
||||
return getobjname(p, pc, Lua.GETARG_A(i));
|
||||
case Lua.OP_TFORCALL: /* for iterator */
|
||||
return new NameWhat("(for iterator)", "(for iterator");
|
||||
/* all other instructions can call only through metamethods */
|
||||
case Lua.OP_SELF:
|
||||
case Lua.OP_GETTABUP:
|
||||
case Lua.OP_GETTABLE: tm = LuaValue.INDEX; break;
|
||||
case Lua.OP_SETTABUP:
|
||||
case Lua.OP_SETTABLE: tm = LuaValue.NEWINDEX; break;
|
||||
case Lua.OP_EQ: tm = LuaValue.EQ; break;
|
||||
case Lua.OP_ADD: tm = LuaValue.ADD; break;
|
||||
case Lua.OP_SUB: tm = LuaValue.SUB; break;
|
||||
case Lua.OP_MUL: tm = LuaValue.MUL; break;
|
||||
case Lua.OP_DIV: tm = LuaValue.DIV; break;
|
||||
case Lua.OP_MOD: tm = LuaValue.MOD; break;
|
||||
case Lua.OP_POW: tm = LuaValue.POW; break;
|
||||
case Lua.OP_UNM: tm = LuaValue.UNM; break;
|
||||
case Lua.OP_LEN: tm = LuaValue.LEN; break;
|
||||
case Lua.OP_LT: tm = LuaValue.LT; break;
|
||||
case Lua.OP_LE: tm = LuaValue.LE; break;
|
||||
case Lua.OP_CONCAT: tm = LuaValue.CONCAT; break;
|
||||
default:
|
||||
return null; /* else no useful name can be found */
|
||||
}
|
||||
return new NameWhat( tm.tojstring(), "metamethod" );
|
||||
}
|
||||
|
||||
// return NameWhat if found, null if not
|
||||
public static NameWhat getobjname(Prototype p, int lastpc, int reg) {
|
||||
int pc = lastpc; // currentpc(L, ci);
|
||||
LuaString name = p.getlocalname(reg + 1, pc);
|
||||
if (name != null) /* is a local? */
|
||||
return new NameWhat( name.tojstring(), "local" );
|
||||
|
||||
/* else try symbolic execution */
|
||||
pc = findsetreg(p, lastpc, reg);
|
||||
if (pc != -1) { /* could find instruction? */
|
||||
int i = p.code[pc];
|
||||
switch (Lua.GET_OPCODE(i)) {
|
||||
case Lua.OP_MOVE: {
|
||||
int a = Lua.GETARG_A(i);
|
||||
int b = Lua.GETARG_B(i); /* move from `b' to `a' */
|
||||
if (b < a)
|
||||
return getobjname(p, pc, b); /* get name for `b' */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_GETTABUP:
|
||||
case Lua.OP_GETTABLE: {
|
||||
int k = Lua.GETARG_C(i); /* key index */
|
||||
int t = Lua.GETARG_B(i); /* table index */
|
||||
LuaString vn = (Lua.GET_OPCODE(i) == Lua.OP_GETTABLE) /* name of indexed variable */
|
||||
? p.getlocalname(t + 1, pc)
|
||||
: (t < p.upvalues.length ? p.upvalues[t].name : QMARK);
|
||||
String jname = kname(p, pc, k);
|
||||
return new NameWhat( jname, vn != null && vn.eq_b(ENV)? "global": "field" );
|
||||
}
|
||||
case Lua.OP_GETUPVAL: {
|
||||
int u = Lua.GETARG_B(i); /* upvalue index */
|
||||
name = u < p.upvalues.length ? p.upvalues[u].name : QMARK;
|
||||
return name == null ? null : new NameWhat( name.tojstring(), "upvalue" );
|
||||
}
|
||||
case Lua.OP_LOADK:
|
||||
case Lua.OP_LOADKX: {
|
||||
int b = (Lua.GET_OPCODE(i) == Lua.OP_LOADK) ? Lua.GETARG_Bx(i)
|
||||
: Lua.GETARG_Ax(p.code[pc + 1]);
|
||||
if (p.k[b].isstring()) {
|
||||
name = p.k[b].strvalue();
|
||||
return new NameWhat( name.tojstring(), "constant" );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Lua.OP_SELF: {
|
||||
int k = Lua.GETARG_C(i); /* key index */
|
||||
String jname = kname(p, pc, k);
|
||||
return new NameWhat( jname, "method" );
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return null; /* no useful name found */
|
||||
}
|
||||
|
||||
static String kname(Prototype p, int pc, int c) {
|
||||
if (Lua.ISK(c)) { /* is 'c' a constant? */
|
||||
LuaValue k = p.k[Lua.INDEXK(c)];
|
||||
if (k.isstring()) { /* literal constant? */
|
||||
return k.tojstring(); /* it is its own name */
|
||||
} /* else no reasonable name found */
|
||||
} else { /* 'c' is a register */
|
||||
NameWhat what = getobjname(p, pc, c); /* search for 'c' */
|
||||
if (what != null && "constant".equals(what.namewhat)) { /* found a constant name? */
|
||||
return what.name; /* 'name' already filled */
|
||||
}
|
||||
/* else no reasonable name found */
|
||||
}
|
||||
return "?"; /* no reasonable name found */
|
||||
}
|
||||
|
||||
/*
|
||||
** try to find last instruction before 'lastpc' that modified register 'reg'
|
||||
*/
|
||||
static int findsetreg (Prototype p, int lastpc, int reg) {
|
||||
int pc;
|
||||
int setreg = -1; /* keep last instruction that changed 'reg' */
|
||||
for (pc = 0; pc < lastpc; pc++) {
|
||||
int i = p.code[pc];
|
||||
int op = Lua.GET_OPCODE(i);
|
||||
int a = Lua.GETARG_A(i);
|
||||
switch (op) {
|
||||
case Lua.OP_LOADNIL: {
|
||||
int b = Lua.GETARG_B(i);
|
||||
if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */
|
||||
setreg = pc;
|
||||
break;
|
||||
}
|
||||
case Lua.OP_TFORCALL: {
|
||||
if (reg >= a + 2) setreg = pc; /* affect all regs above its base */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_CALL:
|
||||
case Lua.OP_TAILCALL: {
|
||||
if (reg >= a) setreg = pc; /* affect all registers above base */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_JMP: {
|
||||
int b = Lua.GETARG_sBx(i);
|
||||
int dest = pc + 1 + b;
|
||||
/* jump is forward and do not skip `lastpc'? */
|
||||
if (pc < dest && dest <= lastpc)
|
||||
pc += b; /* do the jump */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_TEST: {
|
||||
if (reg == a) setreg = pc; /* jumped code can change 'a' */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_SETLIST: { // Lua.testAMode(Lua.OP_SETLIST) == false
|
||||
if ( ((i>>14)&0x1ff) == 0 ) pc++; // if c == 0 then c stored in next op -> skip
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (Lua.testAMode(op) && reg == a) /* any instruction that set A */
|
||||
setreg = pc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return setreg;
|
||||
}
|
||||
}
|
||||
688
core/src/main/java/org/luaj/vm2/libs/IoLib.java
Normal file
688
core/src/main/java/org/luaj/vm2/libs/IoLib.java
Normal file
@@ -0,0 +1,688 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/**
|
||||
* Abstract base class extending {@link LibFunction} which implements the
|
||||
* core of the lua standard {@code io} library.
|
||||
* <p>
|
||||
* It contains the implementation of the io library support that is common to
|
||||
* the JSE and JME platforms.
|
||||
* In practice on of the concrete IOLib subclasses is chosen:
|
||||
* {@link org.luaj.vm2.libs.jse.JseIoLib} for the JSE platform, and
|
||||
* {@link org.luaj.vm2.libs.jme.JmeIoLib} for the JME platform.
|
||||
* <p>
|
||||
* The JSE implementation conforms almost completely to the C-based lua library,
|
||||
* while the JME implementation follows closely except in the area of random-access files,
|
||||
* which are difficult to support properly on JME.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* {@link org.luaj.vm2.libs.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.libs.jme.JmePlatform#standardGlobals()}
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.standardGlobals();
|
||||
* globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
|
||||
* } </pre>
|
||||
* In this example the platform-specific {@link org.luaj.vm2.libs.jse.JseIoLib} library will be loaded, which will include
|
||||
* the base functionality provided by this class, whereas the {@link org.luaj.vm2.libs.jse.JsePlatform} would load the
|
||||
* {@link org.luaj.vm2.libs.jse.JseIoLib}.
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* Globals globals = new Globals();
|
||||
* globals.load(new JseBaseLib());
|
||||
* globals.load(new PackageLib());
|
||||
* globals.load(new OsLib());
|
||||
* globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
|
||||
* } </pre>
|
||||
* <p>
|
||||
* This has been implemented to match as closely as possible the behavior in the corresponding library in C.
|
||||
* @see LibFunction
|
||||
* @see org.luaj.vm2.libs.jse.JsePlatform
|
||||
* @see org.luaj.vm2.libs.jme.JmePlatform
|
||||
* @see org.luaj.vm2.libs.jse.JseIoLib
|
||||
* @see org.luaj.vm2.libs.jme.JmeIoLib
|
||||
* @see <a href="http://www.lua.org/manual/5.1/manual.html#5.7">http://www.lua.org/manual/5.1/manual.html#5.7</a>
|
||||
*/
|
||||
abstract
|
||||
public class IoLib extends TwoArgFunction {
|
||||
|
||||
abstract
|
||||
protected class File extends LuaValue{
|
||||
abstract public void write( LuaString string ) throws IOException;
|
||||
abstract public void flush() throws IOException;
|
||||
abstract public boolean isstdfile();
|
||||
abstract public void close() throws IOException;
|
||||
abstract public boolean isclosed();
|
||||
// returns new position
|
||||
abstract public int seek(String option, int bytecount) throws IOException;
|
||||
abstract public void setvbuf(String mode, int size);
|
||||
// get length remaining to read
|
||||
abstract public int remaining() throws IOException;
|
||||
// peek ahead one character
|
||||
abstract public int peek() throws IOException, EOFException;
|
||||
// return char if read, -1 if eof, throw IOException on other exception
|
||||
abstract public int read() throws IOException, EOFException;
|
||||
// return number of bytes read if positive, false if eof, throw IOException on other exception
|
||||
abstract public int read(byte[] bytes, int offset, int length) throws IOException;
|
||||
|
||||
public boolean eof() throws IOException {
|
||||
try {
|
||||
return peek() < 0;
|
||||
} catch (EOFException e) { return true; }
|
||||
}
|
||||
|
||||
// delegate method access to file methods table
|
||||
public LuaValue get( LuaValue key ) {
|
||||
return filemethods.get(key);
|
||||
}
|
||||
|
||||
// essentially a userdata instance
|
||||
public int type() {
|
||||
return LuaValue.TUSERDATA;
|
||||
}
|
||||
public String typename() {
|
||||
return "userdata";
|
||||
}
|
||||
|
||||
// displays as "file" type
|
||||
public String tojstring() {
|
||||
return "file: " + Integer.toHexString(hashCode());
|
||||
}
|
||||
|
||||
public void finalize() throws Throwable {
|
||||
try {
|
||||
if (!isclosed()) {
|
||||
try {
|
||||
close();
|
||||
} catch (IOException ignore) {}
|
||||
}
|
||||
} finally {
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Enumerated value representing stdin */
|
||||
protected static final int FTYPE_STDIN = 0;
|
||||
/** Enumerated value representing stdout */
|
||||
protected static final int FTYPE_STDOUT = 1;
|
||||
/** Enumerated value representing stderr */
|
||||
protected static final int FTYPE_STDERR = 2;
|
||||
/** Enumerated value representing a file type for a named file */
|
||||
protected static final int FTYPE_NAMED = 3;
|
||||
|
||||
/**
|
||||
* Wrap the standard input.
|
||||
* @return File
|
||||
* @throws IOException
|
||||
*/
|
||||
abstract protected File wrapStdin() throws IOException;
|
||||
|
||||
/**
|
||||
* Wrap the standard output.
|
||||
* @return File
|
||||
* @throws IOException
|
||||
*/
|
||||
abstract protected File wrapStdout() throws IOException;
|
||||
|
||||
/**
|
||||
* Wrap the standard error output.
|
||||
* @return File
|
||||
* @throws IOException
|
||||
*/
|
||||
abstract protected File wrapStderr() throws IOException;
|
||||
|
||||
/**
|
||||
* Open a file in a particular mode.
|
||||
* @param filename
|
||||
* @param readMode true if opening in read mode
|
||||
* @param appendMode true if opening in append mode
|
||||
* @param updateMode true if opening in update mode
|
||||
* @param binaryMode true if opening in binary mode
|
||||
* @return File object if successful
|
||||
* @throws IOException if could not be opened
|
||||
*/
|
||||
abstract protected File openFile( String filename, boolean readMode, boolean appendMode, boolean updateMode, boolean binaryMode ) throws IOException;
|
||||
|
||||
/**
|
||||
* Open a temporary file.
|
||||
* @return File object if successful
|
||||
* @throws IOException if could not be opened
|
||||
*/
|
||||
abstract protected File tmpFile() throws IOException;
|
||||
|
||||
/**
|
||||
* Start a new process and return a file for input or output
|
||||
* @param prog the program to execute
|
||||
* @param mode "r" to read, "w" to write
|
||||
* @return File to read to or write from
|
||||
* @throws IOException if an i/o exception occurs
|
||||
*/
|
||||
abstract protected File openProgram(String prog, String mode) throws IOException;
|
||||
|
||||
private File infile = null;
|
||||
private File outfile = null;
|
||||
private File errfile = null;
|
||||
|
||||
private static final LuaValue STDIN = valueOf("stdin");
|
||||
private static final LuaValue STDOUT = valueOf("stdout");
|
||||
private static final LuaValue STDERR = valueOf("stderr");
|
||||
private static final LuaValue FILE = valueOf("file");
|
||||
private static final LuaValue CLOSED_FILE = valueOf("closed file");
|
||||
|
||||
private static final int IO_CLOSE = 0;
|
||||
private static final int IO_FLUSH = 1;
|
||||
private static final int IO_INPUT = 2;
|
||||
private static final int IO_LINES = 3;
|
||||
private static final int IO_OPEN = 4;
|
||||
private static final int IO_OUTPUT = 5;
|
||||
private static final int IO_POPEN = 6;
|
||||
private static final int IO_READ = 7;
|
||||
private static final int IO_TMPFILE = 8;
|
||||
private static final int IO_TYPE = 9;
|
||||
private static final int IO_WRITE = 10;
|
||||
|
||||
private static final int FILE_CLOSE = 11;
|
||||
private static final int FILE_FLUSH = 12;
|
||||
private static final int FILE_LINES = 13;
|
||||
private static final int FILE_READ = 14;
|
||||
private static final int FILE_SEEK = 15;
|
||||
private static final int FILE_SETVBUF = 16;
|
||||
private static final int FILE_WRITE = 17;
|
||||
|
||||
private static final int IO_INDEX = 18;
|
||||
private static final int LINES_ITER = 19;
|
||||
|
||||
public static final String[] IO_NAMES = {
|
||||
"close",
|
||||
"flush",
|
||||
"input",
|
||||
"lines",
|
||||
"open",
|
||||
"output",
|
||||
"popen",
|
||||
"read",
|
||||
"tmpfile",
|
||||
"type",
|
||||
"write",
|
||||
};
|
||||
|
||||
public static final String[] FILE_NAMES = {
|
||||
"close",
|
||||
"flush",
|
||||
"lines",
|
||||
"read",
|
||||
"seek",
|
||||
"setvbuf",
|
||||
"write",
|
||||
};
|
||||
|
||||
LuaTable filemethods;
|
||||
|
||||
protected Globals globals;
|
||||
|
||||
public LuaValue call(LuaValue modname, LuaValue env) {
|
||||
globals = env.checkglobals();
|
||||
|
||||
// io lib functions
|
||||
LuaTable t = new LuaTable();
|
||||
bind(t, IoLibV.class, IO_NAMES );
|
||||
|
||||
// create file methods table
|
||||
filemethods = new LuaTable();
|
||||
bind(filemethods, IoLibV.class, FILE_NAMES, FILE_CLOSE );
|
||||
|
||||
// set up file metatable
|
||||
LuaTable mt = new LuaTable();
|
||||
bind(mt, IoLibV.class, new String[] { "__index" }, IO_INDEX );
|
||||
t.setmetatable( mt );
|
||||
|
||||
// all functions link to library instance
|
||||
setLibInstance( t );
|
||||
setLibInstance( filemethods );
|
||||
setLibInstance( mt );
|
||||
|
||||
// return the table
|
||||
env.set("io", t);
|
||||
if (!env.get("package").isnil()) env.get("package").get("loaded").set("io", t);
|
||||
return t;
|
||||
}
|
||||
|
||||
private void setLibInstance(LuaTable t) {
|
||||
LuaValue[] k = t.keys();
|
||||
for ( int i=0, n=k.length; i<n; i++ )
|
||||
((IoLibV) t.get(k[i])).iolib = this;
|
||||
}
|
||||
|
||||
static final class IoLibV extends VarArgFunction {
|
||||
private File f;
|
||||
public IoLib iolib;
|
||||
private boolean toclose;
|
||||
private Varargs args;
|
||||
public IoLibV() {
|
||||
}
|
||||
public IoLibV(File f, String name, int opcode, IoLib iolib, boolean toclose, Varargs args) {
|
||||
this(f, name, opcode, iolib);
|
||||
this.toclose = toclose;
|
||||
this.args = args.dealias();
|
||||
}
|
||||
public IoLibV(File f, String name, int opcode, IoLib iolib) {
|
||||
super();
|
||||
this.f = f;
|
||||
this.name = name;
|
||||
this.opcode = opcode;
|
||||
this.iolib = iolib;
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs args) {
|
||||
try {
|
||||
switch ( opcode ) {
|
||||
case IO_FLUSH: return iolib._io_flush();
|
||||
case IO_TMPFILE: return iolib._io_tmpfile();
|
||||
case IO_CLOSE: return iolib._io_close(args.arg1());
|
||||
case IO_INPUT: return iolib._io_input(args.arg1());
|
||||
case IO_OUTPUT: return iolib._io_output(args.arg1());
|
||||
case IO_TYPE: return iolib._io_type(args.arg1());
|
||||
case IO_POPEN: return iolib._io_popen(args.checkjstring(1),args.optjstring(2,"r"));
|
||||
case IO_OPEN: return iolib._io_open(args.checkjstring(1), args.optjstring(2,"r"));
|
||||
case IO_LINES: return iolib._io_lines(args);
|
||||
case IO_READ: return iolib._io_read(args);
|
||||
case IO_WRITE: return iolib._io_write(args);
|
||||
|
||||
case FILE_CLOSE: return iolib._file_close(args.arg1());
|
||||
case FILE_FLUSH: return iolib._file_flush(args.arg1());
|
||||
case FILE_SETVBUF: return iolib._file_setvbuf(args.arg1(),args.checkjstring(2),args.optint(3,8192));
|
||||
case FILE_LINES: return iolib._file_lines(args);
|
||||
case FILE_READ: return iolib._file_read(args.arg1(),args.subargs(2));
|
||||
case FILE_SEEK: return iolib._file_seek(args.arg1(),args.optjstring(2,"cur"),args.optint(3,0));
|
||||
case FILE_WRITE: return iolib._file_write(args.arg1(),args.subargs(2));
|
||||
|
||||
case IO_INDEX: return iolib._io_index(args.arg(2));
|
||||
case LINES_ITER: return iolib._lines_iter(f, toclose, this.args);
|
||||
}
|
||||
} catch ( IOException ioe ) {
|
||||
if (opcode == LINES_ITER) {
|
||||
String s = ioe.getMessage();
|
||||
error(s != null ? s : ioe.toString());
|
||||
}
|
||||
return errorresult(ioe);
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
private File input() {
|
||||
return infile!=null? infile: (infile=ioopenfile(FTYPE_STDIN, "-","r"));
|
||||
}
|
||||
|
||||
// io.flush() -> bool
|
||||
public Varargs _io_flush() throws IOException {
|
||||
checkopen(output());
|
||||
outfile.flush();
|
||||
return LuaValue.TRUE;
|
||||
}
|
||||
|
||||
// io.tmpfile() -> file
|
||||
public Varargs _io_tmpfile() throws IOException {
|
||||
return tmpFile();
|
||||
}
|
||||
|
||||
// io.close([file]) -> void
|
||||
public Varargs _io_close(LuaValue file) throws IOException {
|
||||
File f = file.isnil()? output(): checkfile(file);
|
||||
checkopen(f);
|
||||
return ioclose(f);
|
||||
}
|
||||
|
||||
// io.input([file]) -> file
|
||||
public Varargs _io_input(LuaValue file) {
|
||||
infile = file.isnil()? input():
|
||||
file.isstring()? ioopenfile(FTYPE_NAMED, file.checkjstring(),"r"):
|
||||
checkfile(file);
|
||||
return infile;
|
||||
}
|
||||
|
||||
// io.output(filename) -> file
|
||||
public Varargs _io_output(LuaValue filename) {
|
||||
outfile = filename.isnil()? output():
|
||||
filename.isstring()? ioopenfile(FTYPE_NAMED, filename.checkjstring(),"w"):
|
||||
checkfile(filename);
|
||||
return outfile;
|
||||
}
|
||||
|
||||
// io.type(obj) -> "file" | "closed file" | nil
|
||||
public Varargs _io_type(LuaValue obj) {
|
||||
File f = optfile(obj);
|
||||
return f!=null?
|
||||
f.isclosed()? CLOSED_FILE: FILE:
|
||||
NIL;
|
||||
}
|
||||
|
||||
// io.popen(prog, [mode]) -> file
|
||||
public Varargs _io_popen(String prog, String mode) throws IOException {
|
||||
if (!"r".equals(mode) && !"w".equals(mode)) argerror(2, "invalid value: '" + mode + "'; must be one of 'r' or 'w'");
|
||||
return openProgram(prog, mode);
|
||||
}
|
||||
|
||||
// io.open(filename, [mode]) -> file | nil,err
|
||||
public Varargs _io_open(String filename, String mode) throws IOException {
|
||||
return rawopenfile(FTYPE_NAMED, filename, mode);
|
||||
}
|
||||
|
||||
// io.lines(filename, ...) -> iterator
|
||||
public Varargs _io_lines(Varargs args) {
|
||||
String filename = args.optjstring(1, null);
|
||||
File infile = filename==null? input(): ioopenfile(FTYPE_NAMED, filename,"r");
|
||||
checkopen(infile);
|
||||
return lines(infile, filename != null, args.subargs(2));
|
||||
}
|
||||
|
||||
// io.read(...) -> (...)
|
||||
public Varargs _io_read(Varargs args) throws IOException {
|
||||
checkopen(input());
|
||||
return ioread(infile,args);
|
||||
}
|
||||
|
||||
// io.write(...) -> void
|
||||
public Varargs _io_write(Varargs args) throws IOException {
|
||||
checkopen(output());
|
||||
return iowrite(outfile,args);
|
||||
}
|
||||
|
||||
// file:close() -> void
|
||||
public Varargs _file_close(LuaValue file) throws IOException {
|
||||
return ioclose(checkfile(file));
|
||||
}
|
||||
|
||||
// file:flush() -> void
|
||||
public Varargs _file_flush(LuaValue file) throws IOException {
|
||||
checkfile(file).flush();
|
||||
return LuaValue.TRUE;
|
||||
}
|
||||
|
||||
// file:setvbuf(mode,[size]) -> void
|
||||
public Varargs _file_setvbuf(LuaValue file, String mode, int size) {
|
||||
if ("no".equals(mode)) {
|
||||
} else if ("full".equals(mode)) {
|
||||
} else if ("line".equals(mode)) {
|
||||
} else {
|
||||
argerror(1, "invalid value: '" + mode + "'; must be one of 'no', 'full' or 'line'");
|
||||
}
|
||||
checkfile(file).setvbuf(mode,size);
|
||||
return LuaValue.TRUE;
|
||||
}
|
||||
|
||||
// file:lines(...) -> iterator
|
||||
public Varargs _file_lines(Varargs args) {
|
||||
return lines(checkfile(args.arg1()), false, args.subargs(2));
|
||||
}
|
||||
|
||||
// file:read(...) -> (...)
|
||||
public Varargs _file_read(LuaValue file, Varargs subargs) throws IOException {
|
||||
return ioread(checkfile(file),subargs);
|
||||
}
|
||||
|
||||
// file:seek([whence][,offset]) -> pos | nil,error
|
||||
public Varargs _file_seek(LuaValue file, String whence, int offset) throws IOException {
|
||||
if ("set".equals(whence)) {
|
||||
} else if ("end".equals(whence)) {
|
||||
} else if ("cur".equals(whence)) {
|
||||
} else {
|
||||
argerror(1, "invalid value: '" + whence + "'; must be one of 'set', 'cur' or 'end'");
|
||||
}
|
||||
return valueOf( checkfile(file).seek(whence,offset) );
|
||||
}
|
||||
|
||||
// file:write(...) -> void
|
||||
public Varargs _file_write(LuaValue file, Varargs subargs) throws IOException {
|
||||
return iowrite(checkfile(file),subargs);
|
||||
}
|
||||
|
||||
// __index, returns a field
|
||||
public Varargs _io_index(LuaValue v) {
|
||||
return v.equals(STDOUT)?output():
|
||||
v.equals(STDIN)? input():
|
||||
v.equals(STDERR)? errput(): NIL;
|
||||
}
|
||||
|
||||
// lines iterator(s,var) -> var'
|
||||
public Varargs _lines_iter(LuaValue file, boolean toclose, Varargs args) throws IOException {
|
||||
File f = optfile(file);
|
||||
if ( f == null ) argerror(1, "not a file: " + file);
|
||||
if ( f.isclosed() ) error("file is already closed");
|
||||
Varargs ret = ioread(f, args);
|
||||
if (toclose && ret.isnil(1) && f.eof()) f.close();
|
||||
return ret;
|
||||
}
|
||||
|
||||
private File output() {
|
||||
return outfile!=null? outfile: (outfile=ioopenfile(FTYPE_STDOUT,"-","w"));
|
||||
}
|
||||
|
||||
private File errput() {
|
||||
return errfile!=null? errfile: (errfile=ioopenfile(FTYPE_STDERR,"-","w"));
|
||||
}
|
||||
|
||||
private File ioopenfile(int filetype, String filename, String mode) {
|
||||
try {
|
||||
return rawopenfile(filetype, filename, mode);
|
||||
} catch ( Exception e ) {
|
||||
error("io error: "+e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static Varargs ioclose(File f) throws IOException {
|
||||
if ( f.isstdfile() )
|
||||
return errorresult("cannot close standard file");
|
||||
else {
|
||||
f.close();
|
||||
return successresult();
|
||||
}
|
||||
}
|
||||
|
||||
private static Varargs successresult() {
|
||||
return LuaValue.TRUE;
|
||||
}
|
||||
|
||||
static Varargs errorresult(Exception ioe) {
|
||||
String s = ioe.getMessage();
|
||||
return errorresult("io error: "+(s!=null? s: ioe.toString()));
|
||||
}
|
||||
|
||||
private static Varargs errorresult(String errortext) {
|
||||
return varargsOf(NIL, valueOf(errortext));
|
||||
}
|
||||
|
||||
private Varargs lines(final File f, boolean toclose, Varargs args) {
|
||||
try {
|
||||
return new IoLibV(f,"lnext",LINES_ITER,this,toclose,args);
|
||||
} catch ( Exception e ) {
|
||||
return error("lines: "+e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Varargs iowrite(File f, Varargs args) throws IOException {
|
||||
for ( int i=1, n=args.narg(); i<=n; i++ )
|
||||
f.write( args.checkstring(i) );
|
||||
return f;
|
||||
}
|
||||
|
||||
private Varargs ioread(File f, Varargs args) throws IOException {
|
||||
int i,n=args.narg();
|
||||
if (n == 0) return freadline(f,false);
|
||||
LuaValue[] v = new LuaValue[n];
|
||||
LuaValue ai,vi;
|
||||
LuaString fmt;
|
||||
for ( i=0; i<n; ) {
|
||||
item: switch ( (ai = args.arg(i+1)).type() ) {
|
||||
case LuaValue.TNUMBER:
|
||||
vi = freadbytes(f,ai.toint());
|
||||
break item;
|
||||
case LuaValue.TSTRING:
|
||||
fmt = ai.checkstring();
|
||||
if ( fmt.m_length >= 2 && fmt.m_bytes[fmt.m_offset] == '*' ) {
|
||||
switch ( fmt.m_bytes[fmt.m_offset+1] ) {
|
||||
case 'n': vi = freadnumber(f); break item;
|
||||
case 'l': vi = freadline(f,false); break item;
|
||||
case 'L': vi = freadline(f,true); break item;
|
||||
case 'a': vi = freadall(f); break item;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return argerror( i+1, "(invalid format)" );
|
||||
}
|
||||
if ( (v[i++] = vi).isnil() )
|
||||
break;
|
||||
}
|
||||
return i==0? NIL: varargsOf(v, 0, i);
|
||||
}
|
||||
|
||||
private static File checkfile(LuaValue val) {
|
||||
File f = optfile(val);
|
||||
if ( f == null )
|
||||
argerror(1,"file");
|
||||
checkopen( f );
|
||||
return f;
|
||||
}
|
||||
|
||||
private static File optfile(LuaValue val) {
|
||||
return (val instanceof File)? (File) val: null;
|
||||
}
|
||||
|
||||
private static File checkopen(File file) {
|
||||
if ( file.isclosed() )
|
||||
error("attempt to use a closed file");
|
||||
return file;
|
||||
}
|
||||
|
||||
private File rawopenfile(int filetype, String filename, String mode) throws IOException {
|
||||
int len = mode.length();
|
||||
for (int i = 0; i < len; i++) { // [rwa][+]?b*
|
||||
char ch = mode.charAt(i);
|
||||
if (i == 0 && "rwa".indexOf(ch) >= 0) continue;
|
||||
if (i == 1 && ch == '+') continue;
|
||||
if (i >= 1 && ch == 'b') continue;
|
||||
len = -1;
|
||||
break;
|
||||
}
|
||||
if (len <= 0) argerror(2, "invalid mode: '" + mode + "'");
|
||||
|
||||
switch (filetype) {
|
||||
case FTYPE_STDIN: return wrapStdin();
|
||||
case FTYPE_STDOUT: return wrapStdout();
|
||||
case FTYPE_STDERR: return wrapStderr();
|
||||
}
|
||||
boolean isreadmode = mode.startsWith("r");
|
||||
boolean isappend = mode.startsWith("a");
|
||||
boolean isupdate = mode.indexOf('+') > 0;
|
||||
boolean isbinary = mode.endsWith("b");
|
||||
return openFile( filename, isreadmode, isappend, isupdate, isbinary );
|
||||
}
|
||||
|
||||
|
||||
// ------------- file reading utilitied ------------------
|
||||
|
||||
public static LuaValue freadbytes(File f, int count) throws IOException {
|
||||
if (count == 0) return f.eof() ? NIL : EMPTYSTRING;
|
||||
byte[] b = new byte[count];
|
||||
int r;
|
||||
if ( ( r = f.read(b,0,b.length) ) < 0 )
|
||||
return NIL;
|
||||
return LuaString.valueUsing(b, 0, r);
|
||||
}
|
||||
public static LuaValue freaduntil(File f,boolean lineonly,boolean withend) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
int c;
|
||||
try {
|
||||
if ( lineonly ) {
|
||||
loop: while ( (c = f.read()) >= 0 ) {
|
||||
switch ( c ) {
|
||||
case '\r': if (withend) baos.write(c); break;
|
||||
case '\n': if (withend) baos.write(c); break loop;
|
||||
default: baos.write(c); break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while ( (c = f.read()) >= 0 )
|
||||
baos.write(c);
|
||||
}
|
||||
} catch ( EOFException e ) {
|
||||
c = -1;
|
||||
}
|
||||
return ( c < 0 && baos.size() == 0 )?
|
||||
(LuaValue) NIL:
|
||||
(LuaValue) LuaString.valueUsing(baos.toByteArray());
|
||||
}
|
||||
public static LuaValue freadline(File f,boolean withend) throws IOException {
|
||||
return freaduntil(f,true,withend);
|
||||
}
|
||||
public static LuaValue freadall(File f) throws IOException {
|
||||
int n = f.remaining();
|
||||
if ( n >= 0 ) {
|
||||
return n == 0 ? EMPTYSTRING : freadbytes(f, n);
|
||||
} else {
|
||||
return freaduntil(f,false,false);
|
||||
}
|
||||
}
|
||||
public static LuaValue freadnumber(File f) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
freadchars(f," \t\r\n",null);
|
||||
freadchars(f,"-+",baos);
|
||||
//freadchars(f,"0",baos);
|
||||
//freadchars(f,"xX",baos);
|
||||
freadchars(f,"0123456789",baos);
|
||||
freadchars(f,".",baos);
|
||||
freadchars(f,"0123456789",baos);
|
||||
//freadchars(f,"eEfFgG",baos);
|
||||
// freadchars(f,"+-",baos);
|
||||
//freadchars(f,"0123456789",baos);
|
||||
String s = baos.toString();
|
||||
return s.length()>0? valueOf( Double.parseDouble(s) ): NIL;
|
||||
}
|
||||
private static void freadchars(File f, String chars, ByteArrayOutputStream baos) throws IOException {
|
||||
int c;
|
||||
while ( true ) {
|
||||
c = f.peek();
|
||||
if ( chars.indexOf(c) < 0 ) {
|
||||
return;
|
||||
}
|
||||
f.read();
|
||||
if ( baos != null )
|
||||
baos.write( c );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
222
core/src/main/java/org/luaj/vm2/libs/LibFunction.java
Normal file
222
core/src/main/java/org/luaj/vm2/libs/LibFunction.java
Normal file
@@ -0,0 +1,222 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs;
|
||||
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaFunction;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/**
|
||||
* Subclass of {@link LuaFunction} common to Java functions exposed to lua.
|
||||
* <p>
|
||||
* To provide for common implementations in JME and JSE,
|
||||
* library functions are typically grouped on one or more library classes
|
||||
* and an opcode per library function is defined and used to key the switch
|
||||
* to the correct function within the library.
|
||||
* <p>
|
||||
* Since lua functions can be called with too few or too many arguments,
|
||||
* and there are overloaded {@link LuaValue#call()} functions with varying
|
||||
* number of arguments, a Java function exposed in lua needs to handle the
|
||||
* argument fixup when a function is called with a number of arguments
|
||||
* differs from that expected.
|
||||
* <p>
|
||||
* To simplify the creation of library functions,
|
||||
* there are 5 direct subclasses to handle common cases based on number of
|
||||
* argument values and number of return return values.
|
||||
* <ul>
|
||||
* <li>{@link ZeroArgFunction}</li>
|
||||
* <li>{@link OneArgFunction}</li>
|
||||
* <li>{@link TwoArgFunction}</li>
|
||||
* <li>{@link ThreeArgFunction}</li>
|
||||
* <li>{@link VarArgFunction}</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* To be a Java library that can be loaded via {@code require}, it should have
|
||||
* a public constructor that returns a {@link LuaValue} that, when executed,
|
||||
* initializes the library.
|
||||
* <p>
|
||||
* For example, the following code will implement a library called "hyperbolic"
|
||||
* with two functions, "sinh", and "cosh":
|
||||
<pre> {@code
|
||||
* import org.luaj.vm2.LuaValue;
|
||||
* import org.luaj.vm2.lib.*;
|
||||
*
|
||||
* public class hyperbolic extends TwoArgFunction {
|
||||
*
|
||||
* public hyperbolic() {}
|
||||
*
|
||||
* public LuaValue call(LuaValue modname, LuaValue env) {
|
||||
* LuaValue library = tableOf();
|
||||
* library.set( "sinh", new sinh() );
|
||||
* library.set( "cosh", new cosh() );
|
||||
* env.set( "hyperbolic", library );
|
||||
* return library;
|
||||
* }
|
||||
*
|
||||
* static class sinh extends OneArgFunction {
|
||||
* public LuaValue call(LuaValue x) {
|
||||
* return LuaValue.valueOf(Math.sinh(x.checkdouble()));
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* static class cosh extends OneArgFunction {
|
||||
* public LuaValue call(LuaValue x) {
|
||||
* return LuaValue.valueOf(Math.cosh(x.checkdouble()));
|
||||
* }
|
||||
* }
|
||||
*}
|
||||
*}</pre>
|
||||
* The default constructor is used to instantiate the library
|
||||
* in response to {@code require 'hyperbolic'} statement,
|
||||
* provided it is on Java"s class path.
|
||||
* This instance is then invoked with 2 arguments: the name supplied to require(),
|
||||
* and the environment for this function. The library may ignore these, or use
|
||||
* them to leave side effects in the global environment, for example.
|
||||
* In the previous example, two functions are created, 'sinh', and 'cosh', and placed
|
||||
* into a global table called 'hyperbolic' using the supplied 'env' argument.
|
||||
* <p>
|
||||
* To test it, a script such as this can be used:
|
||||
* <pre> {@code
|
||||
* local t = require('hyperbolic')
|
||||
* print( 't', t )
|
||||
* print( 'hyperbolic', hyperbolic )
|
||||
* for k,v in pairs(t) do
|
||||
* print( 'k,v', k,v )
|
||||
* end
|
||||
* print( 'sinh(.5)', hyperbolic.sinh(.5) )
|
||||
* print( 'cosh(.5)', hyperbolic.cosh(.5) )
|
||||
* }</pre>
|
||||
* <p>
|
||||
* It should produce something like:
|
||||
* <pre> {@code
|
||||
* t table: 3dbbd23f
|
||||
* hyperbolic table: 3dbbd23f
|
||||
* k,v cosh function: 3dbbd128
|
||||
* k,v sinh function: 3dbbd242
|
||||
* sinh(.5) 0.5210953
|
||||
* cosh(.5) 1.127626
|
||||
* }</pre>
|
||||
* <p>
|
||||
* See the source code in any of the library functions
|
||||
* such as {@link BaseLib} or {@link TableLib} for other examples.
|
||||
*/
|
||||
abstract public class LibFunction extends LuaFunction {
|
||||
|
||||
/** User-defined opcode to differentiate between instances of the library function class.
|
||||
* <p>
|
||||
* Subclass will typicall switch on this value to provide the specific behavior for each function.
|
||||
*/
|
||||
protected int opcode;
|
||||
|
||||
/** The common name for this function, useful for debugging.
|
||||
* <p>
|
||||
* Binding functions initialize this to the name to which it is bound.
|
||||
*/
|
||||
protected String name;
|
||||
|
||||
/** Default constructor for use by subclasses */
|
||||
protected LibFunction() {
|
||||
}
|
||||
|
||||
public String tojstring() {
|
||||
return name != null ? "function: " + name : super.tojstring();
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind a set of library functions.
|
||||
* <p>
|
||||
* An array of names is provided, and the first name is bound
|
||||
* with opcode = 0, second with 1, etc.
|
||||
* @param env The environment to apply to each bound function
|
||||
* @param factory the Class to instantiate for each bound function
|
||||
* @param names array of String names, one for each function.
|
||||
* @see #bind(LuaValue, Class, String[], int)
|
||||
*/
|
||||
protected void bind(LuaValue env, Class factory, String[] names ) {
|
||||
bind( env, factory, names, 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind a set of library functions, with an offset
|
||||
* <p>
|
||||
* An array of names is provided, and the first name is bound
|
||||
* with opcode = {@code firstopcode}, second with {@code firstopcode+1}, etc.
|
||||
* @param env The environment to apply to each bound function
|
||||
* @param factory the Class to instantiate for each bound function
|
||||
* @param names array of String names, one for each function.
|
||||
* @param firstopcode the first opcode to use
|
||||
* @see #bind(LuaValue, Class, String[])
|
||||
*/
|
||||
protected void bind(LuaValue env, Class factory, String[] names, int firstopcode ) {
|
||||
try {
|
||||
for ( int i=0, n=names.length; i<n; i++ ) {
|
||||
LibFunction f = (LibFunction) factory.newInstance();
|
||||
f.opcode = firstopcode + i;
|
||||
f.name = names[i];
|
||||
env.set(f.name, f);
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
throw new LuaError( "bind failed: "+e );
|
||||
}
|
||||
}
|
||||
|
||||
/** Java code generation utility to allocate storage for upvalue, leave it empty */
|
||||
protected static LuaValue[] newupe() {
|
||||
return new LuaValue[1];
|
||||
}
|
||||
|
||||
/** Java code generation utility to allocate storage for upvalue, initialize with nil */
|
||||
protected static LuaValue[] newupn() {
|
||||
return new LuaValue[] { NIL };
|
||||
}
|
||||
|
||||
/** Java code generation utility to allocate storage for upvalue, initialize with value */
|
||||
protected static LuaValue[] newupl(LuaValue v) {
|
||||
return new LuaValue[] { v };
|
||||
}
|
||||
|
||||
public LuaValue call() {
|
||||
return argerror(1,"value expected");
|
||||
}
|
||||
public LuaValue call(LuaValue a) {
|
||||
return call();
|
||||
}
|
||||
public LuaValue call(LuaValue a, LuaValue b) {
|
||||
return call(a);
|
||||
}
|
||||
public LuaValue call(LuaValue a, LuaValue b, LuaValue c) {
|
||||
return call(a,b);
|
||||
}
|
||||
public LuaValue call(LuaValue a, LuaValue b, LuaValue c, LuaValue d) {
|
||||
return call(a,b,c);
|
||||
}
|
||||
public Varargs invoke(Varargs args) {
|
||||
switch(args.narg()) {
|
||||
case 0: return call();
|
||||
case 1: return call(args.arg1());
|
||||
case 2: return call(args.arg1(),args.arg(2));
|
||||
case 3: return call(args.arg1(),args.arg(2),args.arg(3));
|
||||
default: return call(args.arg1(),args.arg(2),args.arg(3),args.arg(4));
|
||||
}
|
||||
}
|
||||
}
|
||||
306
core/src/main/java/org/luaj/vm2/libs/MathLib.java
Normal file
306
core/src/main/java/org/luaj/vm2/libs/MathLib.java
Normal file
@@ -0,0 +1,306 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import org.luaj.vm2.LuaDouble;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/**
|
||||
* Subclass of {@link LibFunction} which implements the lua standard {@code math}
|
||||
* library.
|
||||
* <p>
|
||||
* It contains only the math library support that is possible on JME.
|
||||
* For a more complete implementation based on math functions specific to JSE
|
||||
* use {@link org.luaj.vm2.libs.jse.JseMathLib}.
|
||||
* In Particular the following math functions are <b>not</b> implemented by this library:
|
||||
* <ul>
|
||||
* <li>acos</li>
|
||||
* <li>asin</li>
|
||||
* <li>atan</li>
|
||||
* <li>cosh</li>
|
||||
* <li>log</li>
|
||||
* <li>sinh</li>
|
||||
* <li>tanh</li>
|
||||
* <li>atan2</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* The implementations of {@code exp()} and {@code pow()} are constructed by
|
||||
* hand for JME, so will be slower and less accurate than when executed on the JSE platform.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* {@link org.luaj.vm2.libs.jse.JsePlatform#standardGlobals()} or
|
||||
* {@link org.luaj.vm2.libs.jme.JmePlatform#standardGlobals()}
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.standardGlobals();
|
||||
* System.out.println( globals.get("math").get("sqrt").call( LuaValue.valueOf(2) ) );
|
||||
* } </pre>
|
||||
* When using {@link org.luaj.vm2.libs.jse.JsePlatform} as in this example,
|
||||
* the subclass {@link org.luaj.vm2.libs.jse.JseMathLib} will
|
||||
* be included, which also includes this base functionality.
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* Globals globals = new Globals();
|
||||
* globals.load(new JseBaseLib());
|
||||
* globals.load(new PackageLib());
|
||||
* globals.load(new MathLib());
|
||||
* System.out.println( globals.get("math").get("sqrt").call( LuaValue.valueOf(2) ) );
|
||||
* } </pre>
|
||||
* Doing so will ensure the library is properly initialized
|
||||
* and loaded into the globals table.
|
||||
* <p>
|
||||
* This has been implemented to match as closely as possible the behavior in the corresponding library in C.
|
||||
* @see LibFunction
|
||||
* @see org.luaj.vm2.libs.jse.JsePlatform
|
||||
* @see org.luaj.vm2.libs.jme.JmePlatform
|
||||
* @see org.luaj.vm2.libs.jse.JseMathLib
|
||||
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.6">Lua 5.2 Math Lib Reference</a>
|
||||
*/
|
||||
public class MathLib extends TwoArgFunction {
|
||||
|
||||
/** Pointer to the latest MathLib instance, used only to dispatch
|
||||
* math.exp to tha correct platform math library.
|
||||
*/
|
||||
public static MathLib MATHLIB = null;
|
||||
|
||||
/** Construct a MathLib, which can be initialized by calling it with a
|
||||
* modname string, and a global environment table as arguments using
|
||||
* {@link #call(LuaValue, LuaValue)}. */
|
||||
public MathLib() {
|
||||
MATHLIB = this;
|
||||
}
|
||||
|
||||
/** Perform one-time initialization on the library by creating a table
|
||||
* containing the library functions, adding that table to the supplied environment,
|
||||
* adding the table to package.loaded, and returning table as the return value.
|
||||
* @param modname the module name supplied if this is loaded via 'require'.
|
||||
* @param env the environment to load into, typically a Globals instance.
|
||||
*/
|
||||
public LuaValue call(LuaValue modname, LuaValue env) {
|
||||
LuaTable math = new LuaTable(0,30);
|
||||
math.set("abs", new abs());
|
||||
math.set("ceil", new ceil());
|
||||
math.set("cos", new cos());
|
||||
math.set("deg", new deg());
|
||||
math.set("exp", new exp(this));
|
||||
math.set("floor", new floor());
|
||||
math.set("fmod", new fmod());
|
||||
math.set("frexp", new frexp());
|
||||
math.set("huge", LuaDouble.POSINF );
|
||||
math.set("ldexp", new ldexp());
|
||||
math.set("max", new max());
|
||||
math.set("min", new min());
|
||||
math.set("modf", new modf());
|
||||
math.set("pi", Math.PI );
|
||||
math.set("pow", new pow());
|
||||
random r;
|
||||
math.set("random", r = new random());
|
||||
math.set("randomseed", new randomseed(r));
|
||||
math.set("rad", new rad());
|
||||
math.set("sin", new sin());
|
||||
math.set("sqrt", new sqrt());
|
||||
math.set("tan", new tan());
|
||||
env.set("math", math);
|
||||
if (!env.get("package").isnil()) env.get("package").get("loaded").set("math", math);
|
||||
return math;
|
||||
}
|
||||
|
||||
abstract protected static class UnaryOp extends OneArgFunction {
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return valueOf(call(arg.checkdouble()));
|
||||
}
|
||||
abstract protected double call(double d);
|
||||
}
|
||||
|
||||
abstract protected static class BinaryOp extends TwoArgFunction {
|
||||
public LuaValue call(LuaValue x, LuaValue y) {
|
||||
return valueOf(call(x.checkdouble(), y.checkdouble()));
|
||||
}
|
||||
abstract protected double call(double x, double y);
|
||||
}
|
||||
|
||||
static final class abs extends UnaryOp { protected double call(double d) { return Math.abs(d); } }
|
||||
static final class ceil extends UnaryOp { protected double call(double d) { return Math.ceil(d); } }
|
||||
static final class cos extends UnaryOp { protected double call(double d) { return Math.cos(d); } }
|
||||
static final class deg extends UnaryOp { protected double call(double d) { return Math.toDegrees(d); } }
|
||||
static final class floor extends UnaryOp { protected double call(double d) { return Math.floor(d); } }
|
||||
static final class rad extends UnaryOp { protected double call(double d) { return Math.toRadians(d); } }
|
||||
static final class sin extends UnaryOp { protected double call(double d) { return Math.sin(d); } }
|
||||
static final class sqrt extends UnaryOp { protected double call(double d) { return Math.sqrt(d); } }
|
||||
static final class tan extends UnaryOp { protected double call(double d) { return Math.tan(d); } }
|
||||
|
||||
static final class exp extends UnaryOp {
|
||||
final MathLib mathlib;
|
||||
exp(MathLib mathlib) {
|
||||
this.mathlib = mathlib;
|
||||
}
|
||||
protected double call(double d) {
|
||||
return mathlib.dpow_lib(Math.E,d);
|
||||
}
|
||||
}
|
||||
|
||||
static final class fmod extends TwoArgFunction {
|
||||
public LuaValue call(LuaValue xv, LuaValue yv) {
|
||||
if (xv.islong() && yv.islong()) {
|
||||
return valueOf(xv.tolong() % yv.tolong());
|
||||
}
|
||||
return valueOf(xv.checkdouble() % yv.checkdouble());
|
||||
}
|
||||
}
|
||||
static final class ldexp extends BinaryOp {
|
||||
protected double call(double x, double y) {
|
||||
// This is the behavior on os-x, windows differs in rounding behavior.
|
||||
return x * Double.longBitsToDouble((((long) y) + 1023) << 52);
|
||||
}
|
||||
}
|
||||
static final class pow extends BinaryOp {
|
||||
protected double call(double x, double y) {
|
||||
return MathLib.dpow_default(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
static class frexp extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
double x = args.checkdouble(1);
|
||||
if ( x == 0 ) return varargsOf(ZERO,ZERO);
|
||||
long bits = Double.doubleToLongBits( x );
|
||||
double m = ((bits & (~(-1L<<52))) + (1L<<52)) * ((bits >= 0)? (.5 / (1L<<52)): (-.5 / (1L<<52)));
|
||||
double e = (((int) (bits >> 52)) & 0x7ff) - 1022;
|
||||
return varargsOf( valueOf(m), valueOf(e) );
|
||||
}
|
||||
}
|
||||
|
||||
static class max extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaValue m = args.checkvalue(1);
|
||||
for ( int i=2,n=args.narg(); i<=n; ++i ) {
|
||||
LuaValue v = args.checkvalue(i);
|
||||
if (m.lt_b(v)) m = v;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
||||
static class min extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaValue m = args.checkvalue(1);
|
||||
for ( int i=2,n=args.narg(); i<=n; ++i ) {
|
||||
LuaValue v = args.checkvalue(i);
|
||||
if (v.lt_b(m)) m = v;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
||||
static class modf extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaValue n = args.arg1();
|
||||
/* number is its own integer part, no fractional part */
|
||||
if (n.islong()) return varargsOf(n, valueOf(0.0));
|
||||
double x = n.checkdouble();
|
||||
/* integer part (rounds toward zero) */
|
||||
double intPart = ( x > 0 ) ? Math.floor( x ) : Math.ceil( x );
|
||||
/* fractional part (test needed for inf/-inf) */
|
||||
double fracPart = x == intPart ? 0.0 : x - intPart;
|
||||
return varargsOf( valueOf(intPart), valueOf(fracPart) );
|
||||
}
|
||||
}
|
||||
|
||||
static class random extends LibFunction {
|
||||
Random random = new Random();
|
||||
public LuaValue call() {
|
||||
return valueOf( random.nextDouble() );
|
||||
}
|
||||
public LuaValue call(LuaValue a) {
|
||||
int m = a.checkint();
|
||||
if (m<1) argerror(1, "interval is empty");
|
||||
return valueOf( 1 + random.nextInt(m) );
|
||||
}
|
||||
public LuaValue call(LuaValue a, LuaValue b) {
|
||||
int m = a.checkint();
|
||||
int n = b.checkint();
|
||||
if (n<m) argerror(2, "interval is empty");
|
||||
return valueOf( m + random.nextInt(n+1-m) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class randomseed extends OneArgFunction {
|
||||
final random random;
|
||||
randomseed(random random) {
|
||||
this.random = random;
|
||||
}
|
||||
public LuaValue call(LuaValue arg) {
|
||||
long seed = arg.checklong();
|
||||
random.random = new Random(seed);
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/** compute power using installed math library, or default if there is no math library installed */
|
||||
public static LuaValue dpow(double a, double b) {
|
||||
return LuaDouble.valueOf(
|
||||
MATHLIB!=null?
|
||||
MATHLIB.dpow_lib(a,b):
|
||||
dpow_default(a,b) );
|
||||
}
|
||||
public static double dpow_d(double a, double b) {
|
||||
return MATHLIB!=null?
|
||||
MATHLIB.dpow_lib(a,b):
|
||||
dpow_default(a,b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to override default dpow behavior with faster implementation.
|
||||
*/
|
||||
public double dpow_lib(double a, double b) {
|
||||
return dpow_default(a,b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default JME version computes using longhand heuristics.
|
||||
*/
|
||||
protected static double dpow_default(double a, double b) {
|
||||
if ( b < 0 )
|
||||
return 1 / dpow_default( a, -b );
|
||||
double p = 1;
|
||||
int whole = (int) b;
|
||||
for ( double v=a; whole > 0; whole>>=1, v*=v )
|
||||
if ( (whole & 1) != 0 )
|
||||
p *= v;
|
||||
if ( (b -= whole) > 0 ) {
|
||||
int frac = (int) (0x10000 * b);
|
||||
for ( ; (frac&0xffff)!=0; frac<<=1 ) {
|
||||
a = Math.sqrt(a);
|
||||
if ( (frac & 0x8000) != 0 )
|
||||
p *= a;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
}
|
||||
72
core/src/main/java/org/luaj/vm2/libs/OneArgFunction.java
Normal file
72
core/src/main/java/org/luaj/vm2/libs/OneArgFunction.java
Normal file
@@ -0,0 +1,72 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/** Abstract base class for Java function implementations that take one argument and
|
||||
* return one value.
|
||||
* <p>
|
||||
* Subclasses need only implement {@link LuaValue#call(LuaValue)} to complete this class,
|
||||
* simplifying development.
|
||||
* All other uses of {@link #call()}, {@link #invoke(Varargs)},etc,
|
||||
* are routed through this method by this class,
|
||||
* dropping or extending arguments with {@code nil} values as required.
|
||||
* <p>
|
||||
* If more than one argument are required, or no arguments are required,
|
||||
* or variable argument or variable return values,
|
||||
* then use one of the related function
|
||||
* {@link ZeroArgFunction}, {@link TwoArgFunction}, {@link ThreeArgFunction}, or {@link VarArgFunction}.
|
||||
* <p>
|
||||
* See {@link LibFunction} for more information on implementation libraries and library functions.
|
||||
* @see #call(LuaValue)
|
||||
* @see LibFunction
|
||||
* @see ZeroArgFunction
|
||||
* @see TwoArgFunction
|
||||
* @see ThreeArgFunction
|
||||
* @see VarArgFunction
|
||||
*/
|
||||
abstract public class OneArgFunction extends LibFunction {
|
||||
|
||||
abstract public LuaValue call(LuaValue arg);
|
||||
|
||||
/** Default constructor */
|
||||
public OneArgFunction() {
|
||||
}
|
||||
|
||||
public final LuaValue call() {
|
||||
return call(NIL);
|
||||
}
|
||||
|
||||
public final LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return call(arg1);
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
|
||||
return call(arg1);
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs varargs) {
|
||||
return call(varargs.arg1());
|
||||
}
|
||||
}
|
||||
524
core/src/main/java/org/luaj/vm2/libs/OsLib.java
Normal file
524
core/src/main/java/org/luaj/vm2/libs/OsLib.java
Normal file
@@ -0,0 +1,524 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
import org.luaj.vm2.Buffer;
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/**
|
||||
* Subclass of {@link LibFunction} which implements the standard lua {@code os} library.
|
||||
* <p>
|
||||
* It is a usable base with simplified stub functions
|
||||
* for library functions that cannot be implemented uniformly
|
||||
* on Jse and Jme.
|
||||
* <p>
|
||||
* This can be installed as-is on either platform, or extended
|
||||
* and refined to be used in a complete Jse implementation.
|
||||
* <p>
|
||||
* Because the nature of the {@code os} library is to encapsulate
|
||||
* os-specific features, the behavior of these functions varies considerably
|
||||
* from their counterparts in the C platform.
|
||||
* <p>
|
||||
* The following functions have limited implementations of features
|
||||
* that are not supported well on Jme:
|
||||
* <ul>
|
||||
* <li>{@code execute()}</li>
|
||||
* <li>{@code remove()}</li>
|
||||
* <li>{@code rename()}</li>
|
||||
* <li>{@code tmpname()}</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* {@link org.luaj.vm2.libs.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.libs.jme.JmePlatform#standardGlobals()}
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.standardGlobals();
|
||||
* System.out.println( globals.get("os").get("time").call() );
|
||||
* } </pre>
|
||||
* In this example the platform-specific {@link org.luaj.vm2.libs.jse.JseOsLib} library will be loaded, which will include
|
||||
* the base functionality provided by this class.
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* Globals globals = new Globals();
|
||||
* globals.load(new JseBaseLib());
|
||||
* globals.load(new PackageLib());
|
||||
* globals.load(new OsLib());
|
||||
* System.out.println( globals.get("os").get("time").call() );
|
||||
* } </pre>
|
||||
* <p>
|
||||
* @see LibFunction
|
||||
* @see org.luaj.vm2.libs.jse.JseOsLib
|
||||
* @see org.luaj.vm2.libs.jse.JsePlatform
|
||||
* @see org.luaj.vm2.libs.jme.JmePlatform
|
||||
* @see <a href="http://www.lua.org/manual/5.1/manual.html#5.8">http://www.lua.org/manual/5.1/manual.html#5.8</a>
|
||||
*/
|
||||
public class OsLib extends TwoArgFunction {
|
||||
public static final String TMP_PREFIX = ".luaj";
|
||||
public static final String TMP_SUFFIX = "tmp";
|
||||
|
||||
private static final int CLOCK = 0;
|
||||
private static final int DATE = 1;
|
||||
private static final int DIFFTIME = 2;
|
||||
private static final int EXECUTE = 3;
|
||||
private static final int EXIT = 4;
|
||||
private static final int GETENV = 5;
|
||||
private static final int REMOVE = 6;
|
||||
private static final int RENAME = 7;
|
||||
private static final int SETLOCALE = 8;
|
||||
private static final int TIME = 9;
|
||||
private static final int TMPNAME = 10;
|
||||
|
||||
private static final String[] NAMES = {
|
||||
"clock",
|
||||
"date",
|
||||
"difftime",
|
||||
"execute",
|
||||
"exit",
|
||||
"getenv",
|
||||
"remove",
|
||||
"rename",
|
||||
"setlocale",
|
||||
"time",
|
||||
"tmpname",
|
||||
};
|
||||
|
||||
private static final long t0 = System.currentTimeMillis();
|
||||
private static long tmpnames = t0;
|
||||
|
||||
protected Globals globals;
|
||||
|
||||
/**
|
||||
* Create and OsLib instance.
|
||||
*/
|
||||
public OsLib() {
|
||||
}
|
||||
|
||||
/** Perform one-time initialization on the library by creating a table
|
||||
* containing the library functions, adding that table to the supplied environment,
|
||||
* adding the table to package.loaded, and returning table as the return value.
|
||||
* @param modname the module name supplied if this is loaded via 'require'.
|
||||
* @param env the environment to load into, typically a Globals instance.
|
||||
*/
|
||||
public LuaValue call(LuaValue modname, LuaValue env) {
|
||||
globals = env.checkglobals();
|
||||
LuaTable os = new LuaTable();
|
||||
for (int i = 0; i < NAMES.length; ++i)
|
||||
os.set(NAMES[i], new OsLibFunc(i, NAMES[i]));
|
||||
env.set("os", os);
|
||||
if (!env.get("package").isnil()) env.get("package").get("loaded").set("os", os);
|
||||
return os;
|
||||
}
|
||||
|
||||
class OsLibFunc extends VarArgFunction {
|
||||
public OsLibFunc(int opcode, String name) {
|
||||
this.opcode = opcode;
|
||||
this.name = name;
|
||||
}
|
||||
public Varargs invoke(Varargs args) {
|
||||
try {
|
||||
switch ( opcode ) {
|
||||
case CLOCK:
|
||||
return valueOf(clock());
|
||||
case DATE: {
|
||||
String s = args.optjstring(1, "%c");
|
||||
double t = args.isnumber(2)? args.todouble(2): time(null);
|
||||
if (s.equals("*t")) {
|
||||
Calendar d = Calendar.getInstance();
|
||||
d.setTime(new Date((long)(t*1000)));
|
||||
LuaTable tbl = LuaValue.tableOf();
|
||||
tbl.set("year", LuaValue.valueOf(d.get(Calendar.YEAR)));
|
||||
tbl.set("month", LuaValue.valueOf(d.get(Calendar.MONTH)+1));
|
||||
tbl.set("day", LuaValue.valueOf(d.get(Calendar.DAY_OF_MONTH)));
|
||||
tbl.set("hour", LuaValue.valueOf(d.get(Calendar.HOUR_OF_DAY)));
|
||||
tbl.set("min", LuaValue.valueOf(d.get(Calendar.MINUTE)));
|
||||
tbl.set("sec", LuaValue.valueOf(d.get(Calendar.SECOND)));
|
||||
tbl.set("wday", LuaValue.valueOf(d.get(Calendar.DAY_OF_WEEK)));
|
||||
tbl.set("yday", LuaValue.valueOf(d.get(0x6))); // Day of year
|
||||
tbl.set("isdst", LuaValue.valueOf(isDaylightSavingsTime(d)));
|
||||
return tbl;
|
||||
}
|
||||
return valueOf( date(s, t==-1? time(null): t) );
|
||||
}
|
||||
case DIFFTIME:
|
||||
return valueOf(difftime(args.checkdouble(1),args.checkdouble(2)));
|
||||
case EXECUTE:
|
||||
return execute(args.optjstring(1, null));
|
||||
case EXIT:
|
||||
exit(args.optint(1, 0));
|
||||
return NONE;
|
||||
case GETENV: {
|
||||
final String val = getenv(args.checkjstring(1));
|
||||
return val!=null? valueOf(val): NIL;
|
||||
}
|
||||
case REMOVE:
|
||||
remove(args.checkjstring(1));
|
||||
return LuaValue.TRUE;
|
||||
case RENAME:
|
||||
rename(args.checkjstring(1), args.checkjstring(2));
|
||||
return LuaValue.TRUE;
|
||||
case SETLOCALE: {
|
||||
String s = setlocale(args.optjstring(1,null), args.optjstring(2, "all"));
|
||||
return s!=null? valueOf(s): NIL;
|
||||
}
|
||||
case TIME:
|
||||
return valueOf(time(args.opttable(1, null)));
|
||||
case TMPNAME:
|
||||
return valueOf(tmpname());
|
||||
}
|
||||
return NONE;
|
||||
} catch ( IOException e ) {
|
||||
return varargsOf(NIL, valueOf(e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an approximation of the amount in seconds of CPU time used by
|
||||
* the program. For luaj this simple returns the elapsed time since the
|
||||
* OsLib class was loaded.
|
||||
*/
|
||||
protected double clock() {
|
||||
return (System.currentTimeMillis()-t0) / 1000.;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of seconds from time t1 to time t2.
|
||||
* In POSIX, Windows, and some other systems, this value is exactly t2-t1.
|
||||
* @param t2
|
||||
* @param t1
|
||||
* @return diffeence in time values, in seconds
|
||||
*/
|
||||
protected double difftime(double t2, double t1) {
|
||||
return t2 - t1;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the time argument is present, this is the time to be formatted
|
||||
* (see the os.time function for a description of this value).
|
||||
* Otherwise, date formats the current time.
|
||||
*
|
||||
* Date returns the date as a string,
|
||||
* formatted according to the same rules as ANSII strftime, but without
|
||||
* support for %g, %G, or %V.
|
||||
*
|
||||
* When called without arguments, date returns a reasonable date and
|
||||
* time representation that depends on the host system and on the
|
||||
* current locale (that is, os.date() is equivalent to os.date("%c")).
|
||||
*
|
||||
* @param format
|
||||
* @param time time since epoch, or -1 if not supplied
|
||||
* @return a LString or a LTable containing date and time,
|
||||
* formatted according to the given string format.
|
||||
*/
|
||||
public String date(String format, double time) {
|
||||
Calendar d = Calendar.getInstance();
|
||||
d.setTime(new Date((long)(time*1000)));
|
||||
if (format.startsWith("!")) {
|
||||
time -= timeZoneOffset(d);
|
||||
d.setTime(new Date((long)(time*1000)));
|
||||
format = format.substring(1);
|
||||
}
|
||||
byte[] fmt = format.getBytes();
|
||||
final int n = fmt.length;
|
||||
Buffer result = new Buffer(n);
|
||||
byte c;
|
||||
for ( int i = 0; i < n; ) {
|
||||
switch ( c = fmt[i++ ] ) {
|
||||
case '\n':
|
||||
result.append( "\n" );
|
||||
break;
|
||||
default:
|
||||
result.append( c );
|
||||
break;
|
||||
case '%':
|
||||
if (i >= n) break;
|
||||
switch ( c = fmt[i++ ] ) {
|
||||
default:
|
||||
LuaValue.argerror(1, "invalid conversion specifier '%"+c+"'");
|
||||
break;
|
||||
case '%':
|
||||
result.append( (byte)'%' );
|
||||
break;
|
||||
case 'a':
|
||||
result.append(WeekdayNameAbbrev[d.get(Calendar.DAY_OF_WEEK)-1]);
|
||||
break;
|
||||
case 'A':
|
||||
result.append(WeekdayName[d.get(Calendar.DAY_OF_WEEK)-1]);
|
||||
break;
|
||||
case 'b':
|
||||
result.append(MonthNameAbbrev[d.get(Calendar.MONTH)]);
|
||||
break;
|
||||
case 'B':
|
||||
result.append(MonthName[d.get(Calendar.MONTH)]);
|
||||
break;
|
||||
case 'c':
|
||||
result.append(date("%a %b %d %H:%M:%S %Y", time));
|
||||
break;
|
||||
case 'd':
|
||||
result.append(String.valueOf(100+d.get(Calendar.DAY_OF_MONTH)).substring(1));
|
||||
break;
|
||||
case 'H':
|
||||
result.append(String.valueOf(100+d.get(Calendar.HOUR_OF_DAY)).substring(1));
|
||||
break;
|
||||
case 'I':
|
||||
result.append(String.valueOf(100+(d.get(Calendar.HOUR_OF_DAY)%12)).substring(1));
|
||||
break;
|
||||
case 'j': { // day of year.
|
||||
Calendar y0 = beginningOfYear(d);
|
||||
int dayOfYear = (int) ((d.getTime().getTime() - y0.getTime().getTime()) / (24 * 3600L * 1000L));
|
||||
result.append(String.valueOf(1001+dayOfYear).substring(1));
|
||||
break;
|
||||
}
|
||||
case 'm':
|
||||
result.append(String.valueOf(101+d.get(Calendar.MONTH)).substring(1));
|
||||
break;
|
||||
case 'M':
|
||||
result.append(String.valueOf(100+d.get(Calendar.MINUTE)).substring(1));
|
||||
break;
|
||||
case 'p':
|
||||
result.append(d.get(Calendar.HOUR_OF_DAY) < 12? "AM": "PM");
|
||||
break;
|
||||
case 'S':
|
||||
result.append(String.valueOf(100+d.get(Calendar.SECOND)).substring(1));
|
||||
break;
|
||||
case 'U':
|
||||
result.append(String.valueOf(weekNumber(d, 0)));
|
||||
break;
|
||||
case 'w':
|
||||
result.append(String.valueOf((d.get(Calendar.DAY_OF_WEEK)+6)%7));
|
||||
break;
|
||||
case 'W':
|
||||
result.append(String.valueOf(weekNumber(d, 1)));
|
||||
break;
|
||||
case 'x':
|
||||
result.append(date("%m/%d/%y", time));
|
||||
break;
|
||||
case 'X':
|
||||
result.append(date("%H:%M:%S", time));
|
||||
break;
|
||||
case 'y':
|
||||
result.append(String.valueOf(d.get(Calendar.YEAR)).substring(2));
|
||||
break;
|
||||
case 'Y':
|
||||
result.append(String.valueOf(d.get(Calendar.YEAR)));
|
||||
break;
|
||||
case 'z': {
|
||||
final int tzo = timeZoneOffset(d) / 60;
|
||||
final int a = Math.abs(tzo);
|
||||
final String h = String.valueOf(100 + a / 60).substring(1);
|
||||
final String m = String.valueOf(100 + a % 60).substring(1);
|
||||
result.append((tzo>=0? "+": "-") + h + m);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.tojstring();
|
||||
}
|
||||
|
||||
private static final String[] WeekdayNameAbbrev = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
|
||||
private static final String[] WeekdayName = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
|
||||
private static final String[] MonthNameAbbrev = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
|
||||
private static final String[] MonthName = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
|
||||
|
||||
private Calendar beginningOfYear(Calendar d) {
|
||||
Calendar y0 = Calendar.getInstance();
|
||||
y0.setTime(d.getTime());
|
||||
y0.set(Calendar.MONTH, 0);
|
||||
y0.set(Calendar.DAY_OF_MONTH, 1);
|
||||
y0.set(Calendar.HOUR_OF_DAY, 0);
|
||||
y0.set(Calendar.MINUTE, 0);
|
||||
y0.set(Calendar.SECOND, 0);
|
||||
y0.set(Calendar.MILLISECOND, 0);
|
||||
return y0;
|
||||
}
|
||||
|
||||
private int weekNumber(Calendar d, int startDay) {
|
||||
Calendar y0 = beginningOfYear(d);
|
||||
y0.set(Calendar.DAY_OF_MONTH, 1 + (startDay + 8 - y0.get(Calendar.DAY_OF_WEEK)) % 7);
|
||||
if (y0.after(d)) {
|
||||
y0.set(Calendar.YEAR, y0.get(Calendar.YEAR) - 1);
|
||||
y0.set(Calendar.DAY_OF_MONTH, 1 + (startDay + 8 - y0.get(Calendar.DAY_OF_WEEK)) % 7);
|
||||
}
|
||||
long dt = d.getTime().getTime() - y0.getTime().getTime();
|
||||
return 1 + (int) (dt / (7L * 24L * 3600L * 1000L));
|
||||
}
|
||||
|
||||
private int timeZoneOffset(Calendar d) {
|
||||
int localStandarTimeMillis = (
|
||||
d.get(Calendar.HOUR_OF_DAY) * 3600 +
|
||||
d.get(Calendar.MINUTE) * 60 +
|
||||
d.get(Calendar.SECOND)) * 1000;
|
||||
return d.getTimeZone().getOffset(
|
||||
1,
|
||||
d.get(Calendar.YEAR),
|
||||
d.get(Calendar.MONTH),
|
||||
d.get(Calendar.DAY_OF_MONTH),
|
||||
d.get(Calendar.DAY_OF_WEEK),
|
||||
localStandarTimeMillis) / 1000;
|
||||
}
|
||||
|
||||
private boolean isDaylightSavingsTime(Calendar d) {
|
||||
return timeZoneOffset(d) != d.getTimeZone().getRawOffset() / 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is equivalent to the C function system.
|
||||
* It passes command to be executed by an operating system shell.
|
||||
* It returns a status code, which is system-dependent.
|
||||
* If command is absent, then it returns nonzero if a shell
|
||||
* is available and zero otherwise.
|
||||
* @param command command to pass to the system
|
||||
*/
|
||||
protected Varargs execute(String command) {
|
||||
return varargsOf(NIL, valueOf("exit"), ONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the C function exit, with an optional code, to terminate the host program.
|
||||
* @param code
|
||||
*/
|
||||
protected void exit(int code) {
|
||||
System.exit(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the process environment variable varname,
|
||||
* or the System property value for varname,
|
||||
* or null if the variable is not defined in either environment.
|
||||
*
|
||||
* The default implementation, which is used by the JmePlatform,
|
||||
* only queryies System.getProperty().
|
||||
*
|
||||
* The JsePlatform overrides this behavior and returns the
|
||||
* environment variable value using System.getenv() if it exists,
|
||||
* or the System property value if it does not.
|
||||
*
|
||||
* A SecurityException may be thrown if access is not allowed
|
||||
* for 'varname'.
|
||||
* @param varname
|
||||
* @return String value, or null if not defined
|
||||
*/
|
||||
protected String getenv(String varname) {
|
||||
return System.getProperty(varname);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the file or directory with the given name.
|
||||
* Directories must be empty to be removed.
|
||||
* If this function fails, it throws and IOException
|
||||
*
|
||||
* @param filename
|
||||
* @throws IOException if it fails
|
||||
*/
|
||||
protected void remove(String filename) throws IOException {
|
||||
throw new IOException( "not implemented" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames file or directory named oldname to newname.
|
||||
* If this function fails,it throws and IOException
|
||||
*
|
||||
* @param oldname old file name
|
||||
* @param newname new file name
|
||||
* @throws IOException if it fails
|
||||
*/
|
||||
protected void rename(String oldname, String newname) throws IOException {
|
||||
throw new IOException( "not implemented" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current locale of the program. locale is a string specifying
|
||||
* a locale; category is an optional string describing which category to change:
|
||||
* "all", "collate", "ctype", "monetary", "numeric", or "time"; the default category
|
||||
* is "all".
|
||||
*
|
||||
* If locale is the empty string, the current locale is set to an implementation-
|
||||
* defined native locale. If locale is the string "C", the current locale is set
|
||||
* to the standard C locale.
|
||||
*
|
||||
* When called with null as the first argument, this function only returns the
|
||||
* name of the current locale for the given category.
|
||||
*
|
||||
* @param locale
|
||||
* @param category
|
||||
* @return the name of the new locale, or null if the request
|
||||
* cannot be honored.
|
||||
*/
|
||||
protected String setlocale(String locale, String category) {
|
||||
return "C";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current time when called without arguments,
|
||||
* or a time representing the date and time specified by the given table.
|
||||
* This table must have fields year, month, and day,
|
||||
* and may have fields hour, min, sec, and isdst
|
||||
* (for a description of these fields, see the os.date function).
|
||||
* @param table
|
||||
* @return long value for the time
|
||||
*/
|
||||
protected double time(LuaTable table) {
|
||||
Date d;
|
||||
if (table == null) {
|
||||
d = new Date();
|
||||
} else {
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.set(Calendar.YEAR, table.get("year").checkint());
|
||||
c.set(Calendar.MONTH, table.get("month").checkint()-1);
|
||||
c.set(Calendar.DAY_OF_MONTH, table.get("day").checkint());
|
||||
c.set(Calendar.HOUR_OF_DAY, table.get("hour").optint(12));
|
||||
c.set(Calendar.MINUTE, table.get("min").optint(0));
|
||||
c.set(Calendar.SECOND, table.get("sec").optint(0));
|
||||
c.set(Calendar.MILLISECOND, 0);
|
||||
d = c.getTime();
|
||||
}
|
||||
return d.getTime() / 1000.;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string with a file name that can be used for a temporary file.
|
||||
* The file must be explicitly opened before its use and explicitly removed
|
||||
* when no longer needed.
|
||||
*
|
||||
* On some systems (POSIX), this function also creates a file with that name,
|
||||
* to avoid security risks. (Someone else might create the file with wrong
|
||||
* permissions in the time between getting the name and creating the file.)
|
||||
* You still have to open the file to use it and to remove it (even if you
|
||||
* do not use it).
|
||||
*
|
||||
* @return String filename to use
|
||||
*/
|
||||
protected String tmpname() {
|
||||
synchronized ( OsLib.class ) {
|
||||
return TMP_PREFIX+(tmpnames++)+TMP_SUFFIX;
|
||||
}
|
||||
}
|
||||
}
|
||||
381
core/src/main/java/org/luaj/vm2/libs/PackageLib.java
Normal file
381
core/src/main/java/org/luaj/vm2/libs/PackageLib.java
Normal file
@@ -0,0 +1,381 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2010-2011 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaFunction;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/**
|
||||
* Subclass of {@link LibFunction} which implements the lua standard package and module
|
||||
* library functions.
|
||||
*
|
||||
* <h3>Lua Environment Variables</h3>
|
||||
* The following variables are available to lua scrips when this library has been loaded:
|
||||
* <ul>
|
||||
* <li><code>"package.loaded"</code> Lua table of loaded modules.
|
||||
* <li><code>"package.path"</code> Search path for lua scripts.
|
||||
* <li><code>"package.preload"</code> Lua table of uninitialized preload functions.
|
||||
* <li><code>"package.searchers"</code> Lua table of functions that search for object to load.
|
||||
* </ul>
|
||||
*
|
||||
* <h3>Java Environment Variables</h3>
|
||||
* These Java environment variables affect the library behavior:
|
||||
* <ul>
|
||||
* <li><code>"luaj.package.path"</code> Initial value for <code>"package.path"</code>. Default value is <code>"?.lua"</code>
|
||||
* </ul>
|
||||
*
|
||||
* <h3>Loading</h3>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* {@link org.luaj.vm2.libs.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.libs.jme.JmePlatform#standardGlobals()}
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.standardGlobals();
|
||||
* System.out.println( globals.get("require").call"foo") );
|
||||
* } </pre>
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* Globals globals = new Globals();
|
||||
* globals.load(new JseBaseLib());
|
||||
* globals.load(new PackageLib());
|
||||
* System.out.println( globals.get("require").call("foo") );
|
||||
* } </pre>
|
||||
* <h3>Limitations</h3>
|
||||
* This library has been implemented to match as closely as possible the behavior in the corresponding library in C.
|
||||
* However, the default filesystem search semantics are different and delegated to the bas library
|
||||
* as outlined in the {@link BaseLib} and {@link org.luaj.vm2.libs.jse.JseBaseLib} documentation.
|
||||
* <p>
|
||||
* @see LibFunction
|
||||
* @see BaseLib
|
||||
* @see org.luaj.vm2.libs.jse.JseBaseLib
|
||||
* @see org.luaj.vm2.libs.jse.JsePlatform
|
||||
* @see org.luaj.vm2.libs.jme.JmePlatform
|
||||
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.3">Lua 5.2 Package Lib Reference</a>
|
||||
*/
|
||||
public class PackageLib extends TwoArgFunction {
|
||||
|
||||
/** The default value to use for package.path. This can be set with the system property
|
||||
* <code>"luaj.package.path"</code>, and is <code>"?.lua"</code> by default. */
|
||||
public static final String DEFAULT_LUA_PATH;
|
||||
static {
|
||||
String path = null;
|
||||
try {
|
||||
path = System.getProperty("luaj.package.path");
|
||||
} catch (Exception e) {
|
||||
System.out.println(e.toString());
|
||||
}
|
||||
if (path == null) {
|
||||
path = "?.lua";
|
||||
}
|
||||
DEFAULT_LUA_PATH = path;
|
||||
}
|
||||
|
||||
static final LuaString _LOADED = valueOf("loaded");
|
||||
private static final LuaString _LOADLIB = valueOf("loadlib");
|
||||
static final LuaString _PRELOAD = valueOf("preload");
|
||||
static final LuaString _PATH = valueOf("path");
|
||||
static final LuaString _SEARCHPATH = valueOf("searchpath");
|
||||
static final LuaString _SEARCHERS = valueOf("searchers");
|
||||
|
||||
/** The globals that were used to load this library. */
|
||||
Globals globals;
|
||||
|
||||
/** The table for this package. */
|
||||
LuaTable package_;
|
||||
|
||||
/** Loader that loads from {@code preload} table if found there */
|
||||
public preload_searcher preload_searcher;
|
||||
|
||||
/** Loader that loads as a lua script using the lua path currently in {@link path} */
|
||||
public lua_searcher lua_searcher;
|
||||
|
||||
/** Loader that loads as a Java class. Class must have public constructor and be a LuaValue. */
|
||||
public java_searcher java_searcher;
|
||||
|
||||
private static final LuaString _SENTINEL = valueOf("\u0001");
|
||||
|
||||
private static final String FILE_SEP = System.getProperty("file.separator");
|
||||
|
||||
public PackageLib() {}
|
||||
|
||||
/** Perform one-time initialization on the library by adding package functions
|
||||
* to the supplied environment, and returning it as the return value.
|
||||
* It also creates the package.preload and package.loaded tables for use by
|
||||
* other libraries.
|
||||
* @param modname the module name supplied if this is loaded via 'require'.
|
||||
* @param env the environment to load into, typically a Globals instance.
|
||||
*/
|
||||
public LuaValue call(LuaValue modname, LuaValue env) {
|
||||
globals = env.checkglobals();
|
||||
globals.set("require", new require());
|
||||
package_ = new LuaTable();
|
||||
package_.set(_LOADED, new LuaTable());
|
||||
package_.set(_PRELOAD, new LuaTable());
|
||||
package_.set(_PATH, LuaValue.valueOf(DEFAULT_LUA_PATH));
|
||||
package_.set(_LOADLIB, new loadlib());
|
||||
package_.set(_SEARCHPATH, new searchpath());
|
||||
LuaTable searchers = new LuaTable();
|
||||
searchers.set(1, preload_searcher = new preload_searcher());
|
||||
searchers.set(2, lua_searcher = new lua_searcher());
|
||||
searchers.set(3, java_searcher = new java_searcher());
|
||||
package_.set(_SEARCHERS, searchers);
|
||||
package_.set("config", FILE_SEP + "\n;\n?\n!\n-\n");
|
||||
package_.get(_LOADED).set("package", package_);
|
||||
env.set("package", package_);
|
||||
globals.package_ = this;
|
||||
return env;
|
||||
}
|
||||
|
||||
/** Allow packages to mark themselves as loaded */
|
||||
public void setIsLoaded(String name, LuaTable value) {
|
||||
package_.get(_LOADED).set(name, value);
|
||||
}
|
||||
|
||||
|
||||
/** Set the lua path used by this library instance to a new value.
|
||||
* Merely sets the value of {@link path} to be used in subsequent searches. */
|
||||
public void setLuaPath( String newLuaPath ) {
|
||||
package_.set(_PATH, LuaValue.valueOf(newLuaPath));
|
||||
}
|
||||
|
||||
public String tojstring() {
|
||||
return "package";
|
||||
}
|
||||
|
||||
// ======================== Package loading =============================
|
||||
|
||||
/**
|
||||
* require (modname)
|
||||
*
|
||||
* Loads the given module. The function starts by looking into the package.loaded table
|
||||
* to determine whether modname is already loaded. If it is, then require returns the value
|
||||
* stored at package.loaded[modname]. Otherwise, it tries to find a loader for the module.
|
||||
*
|
||||
* To find a loader, require is guided by the package.searchers sequence.
|
||||
* By changing this sequence, we can change how require looks for a module.
|
||||
* The following explanation is based on the default configuration for package.searchers.
|
||||
*
|
||||
* First require queries package.preload[modname]. If it has a value, this value
|
||||
* (which should be a function) is the loader. Otherwise require searches for a Lua loader using
|
||||
* the path stored in package.path. If that also fails, it searches for a Java loader using
|
||||
* the classpath, using the public default constructor, and casting the instance to LuaFunction.
|
||||
*
|
||||
* Once a loader is found, require calls the loader with two arguments: modname and an extra value
|
||||
* dependent on how it got the loader. If the loader came from a file, this extra value is the file name.
|
||||
* If the loader is a Java instance of LuaFunction, this extra value is the environment.
|
||||
* If the loader returns any non-nil value, require assigns the returned value to package.loaded[modname].
|
||||
* If the loader does not return a non-nil value and has not assigned any value to package.loaded[modname],
|
||||
* then require assigns true to this entry.
|
||||
* In any case, require returns the final value of package.loaded[modname].
|
||||
*
|
||||
* If there is any error loading or running the module, or if it cannot find any loader for the module,
|
||||
* then require raises an error.
|
||||
*/
|
||||
public class require extends OneArgFunction {
|
||||
public LuaValue call( LuaValue arg ) {
|
||||
LuaString name = arg.checkstring();
|
||||
LuaValue loaded = package_.get(_LOADED);
|
||||
LuaValue result = loaded.get(name);
|
||||
if ( result.toboolean() ) {
|
||||
if ( result == _SENTINEL )
|
||||
error("loop or previous error loading module '"+name+"'");
|
||||
return result;
|
||||
}
|
||||
|
||||
/* else must load it; iterate over available loaders */
|
||||
LuaTable tbl = package_.get(_SEARCHERS).checktable();
|
||||
StringBuffer sb = new StringBuffer();
|
||||
Varargs loader = null;
|
||||
for ( int i=1; true; i++ ) {
|
||||
LuaValue searcher = tbl.get(i);
|
||||
if ( searcher.isnil() ) {
|
||||
error( "module '"+name+"' not found: "+name+sb );
|
||||
}
|
||||
|
||||
/* call loader with module name as argument */
|
||||
loader = searcher.invoke(name);
|
||||
if ( loader.isfunction(1) )
|
||||
break;
|
||||
if ( loader.isstring(1) )
|
||||
sb.append( loader.tojstring(1) );
|
||||
}
|
||||
|
||||
// load the module using the loader
|
||||
loaded.set(name, _SENTINEL);
|
||||
result = loader.arg1().call(name, loader.arg(2));
|
||||
if ( ! result.isnil() )
|
||||
loaded.set( name, result );
|
||||
else if ( (result = loaded.get(name)) == _SENTINEL )
|
||||
loaded.set( name, result = LuaValue.TRUE );
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public static class loadlib extends VarArgFunction {
|
||||
public Varargs invoke( Varargs args ) {
|
||||
args.checkstring(1);
|
||||
return varargsOf(NIL, valueOf("dynamic libraries not enabled"), valueOf("absent"));
|
||||
}
|
||||
}
|
||||
|
||||
public class preload_searcher extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaString name = args.checkstring(1);
|
||||
LuaValue val = package_.get(_PRELOAD).get(name);
|
||||
return val.isnil()?
|
||||
valueOf("\n\tno field package.preload['"+name+"']"):
|
||||
val;
|
||||
}
|
||||
}
|
||||
|
||||
public class lua_searcher extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaString name = args.checkstring(1);
|
||||
|
||||
// get package path
|
||||
LuaValue path = package_.get(_PATH);
|
||||
if ( ! path.isstring() )
|
||||
return valueOf("package.path is not a string");
|
||||
|
||||
// get the searchpath function.
|
||||
Varargs v = package_.get(_SEARCHPATH).invoke(varargsOf(name, path));
|
||||
|
||||
// Did we get a result?
|
||||
if (!v.isstring(1))
|
||||
return v.arg(2).tostring();
|
||||
LuaString filename = v.arg1().strvalue();
|
||||
|
||||
// Try to load the file.
|
||||
v = globals.loadfile(filename.tojstring());
|
||||
if ( v.arg1().isfunction() )
|
||||
return LuaValue.varargsOf(v.arg1(), filename);
|
||||
|
||||
// report error
|
||||
return varargsOf(NIL, valueOf("'"+filename+"': "+v.arg(2).tojstring()));
|
||||
}
|
||||
}
|
||||
|
||||
public class searchpath extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
String name = args.checkjstring(1);
|
||||
String path = args.checkjstring(2);
|
||||
String sep = args.optjstring(3, ".");
|
||||
String rep = args.optjstring(4, FILE_SEP);
|
||||
|
||||
// check the path elements
|
||||
int e = -1;
|
||||
int n = path.length();
|
||||
StringBuffer sb = null;
|
||||
name = name.replace(sep.charAt(0), rep.charAt(0));
|
||||
while ( e < n ) {
|
||||
|
||||
// find next template
|
||||
int b = e+1;
|
||||
e = path.indexOf(';',b);
|
||||
if ( e < 0 )
|
||||
e = path.length();
|
||||
String template = path.substring(b,e);
|
||||
|
||||
// create filename
|
||||
int q = template.indexOf('?');
|
||||
String filename = template;
|
||||
if ( q >= 0 ) {
|
||||
filename = template.substring(0,q) + name + template.substring(q+1);
|
||||
}
|
||||
|
||||
// try opening the file
|
||||
InputStream is = globals.finder.findResource(filename);
|
||||
if (is != null) {
|
||||
try { is.close(); } catch ( java.io.IOException ioe ) {}
|
||||
return valueOf(filename);
|
||||
}
|
||||
|
||||
// report error
|
||||
if ( sb == null )
|
||||
sb = new StringBuffer();
|
||||
sb.append( "\n\t"+filename );
|
||||
}
|
||||
return varargsOf(NIL, valueOf(sb.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
public class java_searcher extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
String name = args.checkjstring(1);
|
||||
String classname = toClassname( name );
|
||||
Class c = null;
|
||||
LuaValue v = null;
|
||||
try {
|
||||
c = Class.forName(classname);
|
||||
v = (LuaValue) c.newInstance();
|
||||
if (v.isfunction())
|
||||
((LuaFunction)v).initupvalue1(globals);
|
||||
return varargsOf(v, globals);
|
||||
} catch ( ClassNotFoundException cnfe ) {
|
||||
return valueOf("\n\tno class '"+classname+"'" );
|
||||
} catch ( Exception e ) {
|
||||
return valueOf("\n\tjava load failed on '"+classname+"', "+e );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Convert lua filename to valid class name */
|
||||
public static final String toClassname( String filename ) {
|
||||
int n=filename.length();
|
||||
int j=n;
|
||||
if ( filename.endsWith(".lua") )
|
||||
j -= 4;
|
||||
for ( int k=0; k<j; k++ ) {
|
||||
char c = filename.charAt(k);
|
||||
if ( (!isClassnamePart(c)) || (c=='/') || (c=='\\') ) {
|
||||
StringBuffer sb = new StringBuffer(j);
|
||||
for ( int i=0; i<j; i++ ) {
|
||||
c = filename.charAt(i);
|
||||
sb.append(
|
||||
(isClassnamePart(c))? c:
|
||||
((c=='/') || (c=='\\'))? '.': '_' );
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
return n==j? filename: filename.substring(0,j);
|
||||
}
|
||||
|
||||
private static final boolean isClassnamePart(char c) {
|
||||
if ( (c>='a'&&c<='z') || (c>='A'&&c<='Z') || (c>='0'&&c<='9') )
|
||||
return true;
|
||||
switch ( c ) {
|
||||
case '.':
|
||||
case '$':
|
||||
case '_':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
59
core/src/main/java/org/luaj/vm2/libs/ResourceFinder.java
Normal file
59
core/src/main/java/org/luaj/vm2/libs/ResourceFinder.java
Normal file
@@ -0,0 +1,59 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
|
||||
/**
|
||||
* Interface for opening application resource files such as scripts sources.
|
||||
* <p>
|
||||
* This is used by required to load files that are part of
|
||||
* the application, and implemented by BaseLib
|
||||
* for both the Jme and Jse platforms.
|
||||
* <p>
|
||||
* The Jme version of base lib {@link BaseLib}
|
||||
* implements {@link Globals#finder} via {@link Class#getResourceAsStream(String)},
|
||||
* while the Jse version {@link org.luaj.vm2.libs.jse.JseBaseLib} implements it using {@link java.io.File#File(String)}.
|
||||
* <p>
|
||||
* The io library does not use this API for file manipulation.
|
||||
* <p>
|
||||
* @see BaseLib
|
||||
* @see Globals#finder
|
||||
* @see org.luaj.vm2.libs.jse.JseBaseLib
|
||||
* @see org.luaj.vm2.libs.jme.JmePlatform
|
||||
* @see org.luaj.vm2.libs.jse.JsePlatform
|
||||
*/
|
||||
public interface ResourceFinder {
|
||||
|
||||
/**
|
||||
* Try to open a file, or return null if not found.
|
||||
*
|
||||
* @see BaseLib
|
||||
* @see org.luaj.vm2.libs.jse.JseBaseLib
|
||||
*
|
||||
* @param filename
|
||||
* @return InputStream, or null if not found.
|
||||
*/
|
||||
public InputStream findResource( String filename );
|
||||
}
|
||||
1223
core/src/main/java/org/luaj/vm2/libs/StringLib.java
Normal file
1223
core/src/main/java/org/luaj/vm2/libs/StringLib.java
Normal file
File diff suppressed because it is too large
Load Diff
158
core/src/main/java/org/luaj/vm2/libs/TableLib.java
Normal file
158
core/src/main/java/org/luaj/vm2/libs/TableLib.java
Normal file
@@ -0,0 +1,158 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs;
|
||||
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/**
|
||||
* Subclass of {@link LibFunction} which implements the lua standard {@code table}
|
||||
* library.
|
||||
*
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* {@link org.luaj.vm2.libs.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.libs.jme.JmePlatform#standardGlobals()}
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.standardGlobals();
|
||||
* System.out.println( globals.get("table").get("length").call( LuaValue.tableOf() ) );
|
||||
* } </pre>
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* Globals globals = new Globals();
|
||||
* globals.load(new JseBaseLib());
|
||||
* globals.load(new PackageLib());
|
||||
* globals.load(new TableLib());
|
||||
* System.out.println( globals.get("table").get("length").call( LuaValue.tableOf() ) );
|
||||
* } </pre>
|
||||
* <p>
|
||||
* This has been implemented to match as closely as possible the behavior in the corresponding library in C.
|
||||
* @see LibFunction
|
||||
* @see org.luaj.vm2.libs.jse.JsePlatform
|
||||
* @see org.luaj.vm2.libs.jme.JmePlatform
|
||||
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.5">Lua 5.2 Table Lib Reference</a>
|
||||
*/
|
||||
public class TableLib extends TwoArgFunction {
|
||||
|
||||
/** Perform one-time initialization on the library by creating a table
|
||||
* containing the library functions, adding that table to the supplied environment,
|
||||
* adding the table to package.loaded, and returning table as the return value.
|
||||
* @param modname the module name supplied if this is loaded via 'require'.
|
||||
* @param env the environment to load into, typically a Globals instance.
|
||||
*/
|
||||
public LuaValue call(LuaValue modname, LuaValue env) {
|
||||
LuaTable table = new LuaTable();
|
||||
table.set("concat", new concat());
|
||||
table.set("insert", new insert());
|
||||
table.set("pack", new pack());
|
||||
table.set("remove", new remove());
|
||||
table.set("sort", new sort());
|
||||
table.set("unpack", new unpack());
|
||||
env.set("table", table);
|
||||
if (!env.get("package").isnil()) env.get("package").get("loaded").set("table", table);
|
||||
return NIL;
|
||||
}
|
||||
|
||||
// "concat" (table [, sep [, i [, j]]]) -> string
|
||||
static class concat extends TableLibFunction {
|
||||
public LuaValue call(LuaValue list) {
|
||||
return list.checktable().concat(EMPTYSTRING,1,list.length());
|
||||
}
|
||||
public LuaValue call(LuaValue list, LuaValue sep) {
|
||||
return list.checktable().concat(sep.checkstring(),1,list.length());
|
||||
}
|
||||
public LuaValue call(LuaValue list, LuaValue sep, LuaValue i) {
|
||||
return list.checktable().concat(sep.checkstring(),i.checkint(),list.length());
|
||||
}
|
||||
public LuaValue call(LuaValue list, LuaValue sep, LuaValue i, LuaValue j) {
|
||||
return list.checktable().concat(sep.checkstring(),i.checkint(),j.checkint());
|
||||
}
|
||||
}
|
||||
|
||||
// "insert" (table, [pos,] value)
|
||||
static class insert extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
switch (args.narg()) {
|
||||
case 2: {
|
||||
LuaTable table = args.checktable(1);
|
||||
table.insert(table.length()+1,args.arg(2));
|
||||
return NONE;
|
||||
}
|
||||
case 3: {
|
||||
LuaTable table = args.checktable(1);
|
||||
int pos = args.checkint(2);
|
||||
int max = table.length() + 1;
|
||||
if (pos < 1 || pos > max) argerror(2, "position out of bounds: " + pos + " not between 1 and " + max);
|
||||
table.insert(pos, args.arg(3));
|
||||
return NONE;
|
||||
}
|
||||
default: {
|
||||
return error("wrong number of arguments to 'table.insert': " + args.narg() + " (must be 2 or 3)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// "pack" (...) -> table
|
||||
static class pack extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaValue t = tableOf(args, 1);
|
||||
t.set("n", args.narg());
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
// "remove" (table [, pos]) -> removed-ele
|
||||
static class remove extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaTable table = args.checktable(1);
|
||||
int size = table.length();
|
||||
int pos = args.optint(2, size);
|
||||
if (pos != size && (pos < 1 || pos > size + 1)) {
|
||||
argerror(2, "position out of bounds: " + pos + " not between 1 and " + (size + 1));
|
||||
}
|
||||
return table.remove(pos);
|
||||
}
|
||||
}
|
||||
|
||||
// "sort" (table [, comp])
|
||||
static class sort extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
args.checktable(1).sort(
|
||||
args.isnil(2)? NIL: args.checkfunction(2));
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// "unpack", // (list [,i [,j]]) -> result1, ...
|
||||
static class unpack extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaTable t = args.checktable(1);
|
||||
// do not waste resource for calc rawlen if arg3 is not nil
|
||||
int len = args.arg(3).isnil() ? t.length() : 0;
|
||||
return t.unpack(args.optint(2, 1), args.optint(3, len));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.luaj.vm2.libs;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
class TableLibFunction extends LibFunction {
|
||||
public LuaValue call() {
|
||||
return argerror(1, "table expected, got no value");
|
||||
}
|
||||
}
|
||||
73
core/src/main/java/org/luaj/vm2/libs/ThreeArgFunction.java
Normal file
73
core/src/main/java/org/luaj/vm2/libs/ThreeArgFunction.java
Normal file
@@ -0,0 +1,73 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/** Abstract base class for Java function implementations that take two arguments and
|
||||
* return one value.
|
||||
* <p>
|
||||
* Subclasses need only implement {@link LuaValue#call(LuaValue,LuaValue,LuaValue)} to complete this class,
|
||||
* simplifying development.
|
||||
* All other uses of {@link #call()}, {@link #invoke(Varargs)},etc,
|
||||
* are routed through this method by this class,
|
||||
* dropping or extending arguments with {@code nil} values as required.
|
||||
* <p>
|
||||
* If more or less than three arguments are required,
|
||||
* or variable argument or variable return values,
|
||||
* then use one of the related function
|
||||
* {@link ZeroArgFunction}, {@link OneArgFunction}, {@link TwoArgFunction}, or {@link VarArgFunction}.
|
||||
* <p>
|
||||
* See {@link LibFunction} for more information on implementation libraries and library functions.
|
||||
* @see #call(LuaValue,LuaValue,LuaValue)
|
||||
* @see LibFunction
|
||||
* @see ZeroArgFunction
|
||||
* @see OneArgFunction
|
||||
* @see TwoArgFunction
|
||||
* @see VarArgFunction
|
||||
*/
|
||||
abstract public class ThreeArgFunction extends LibFunction {
|
||||
|
||||
abstract public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3);
|
||||
|
||||
/** Default constructor */
|
||||
public ThreeArgFunction() {
|
||||
}
|
||||
|
||||
public final LuaValue call() {
|
||||
return call(NIL, NIL, NIL);
|
||||
}
|
||||
|
||||
public final LuaValue call(LuaValue arg) {
|
||||
return call(arg, NIL, NIL);
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return call(arg1, arg2, NIL);
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs varargs) {
|
||||
return call(varargs.arg1(),varargs.arg(2),varargs.arg(3));
|
||||
}
|
||||
|
||||
}
|
||||
73
core/src/main/java/org/luaj/vm2/libs/TwoArgFunction.java
Normal file
73
core/src/main/java/org/luaj/vm2/libs/TwoArgFunction.java
Normal file
@@ -0,0 +1,73 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/** Abstract base class for Java function implementations that take two arguments and
|
||||
* return one value.
|
||||
* <p>
|
||||
* Subclasses need only implement {@link LuaValue#call(LuaValue,LuaValue)} to complete this class,
|
||||
* simplifying development.
|
||||
* All other uses of {@link #call()}, {@link #invoke(Varargs)},etc,
|
||||
* are routed through this method by this class,
|
||||
* dropping or extending arguments with {@code nil} values as required.
|
||||
* <p>
|
||||
* If more or less than two arguments are required,
|
||||
* or variable argument or variable return values,
|
||||
* then use one of the related function
|
||||
* {@link ZeroArgFunction}, {@link OneArgFunction}, {@link ThreeArgFunction}, or {@link VarArgFunction}.
|
||||
* <p>
|
||||
* See {@link LibFunction} for more information on implementation libraries and library functions.
|
||||
* @see #call(LuaValue,LuaValue)
|
||||
* @see LibFunction
|
||||
* @see ZeroArgFunction
|
||||
* @see OneArgFunction
|
||||
* @see ThreeArgFunction
|
||||
* @see VarArgFunction
|
||||
*/
|
||||
abstract public class TwoArgFunction extends LibFunction {
|
||||
|
||||
abstract public LuaValue call(LuaValue arg1, LuaValue arg2);
|
||||
|
||||
/** Default constructor */
|
||||
public TwoArgFunction() {
|
||||
}
|
||||
|
||||
public final LuaValue call() {
|
||||
return call(NIL, NIL);
|
||||
}
|
||||
|
||||
public final LuaValue call(LuaValue arg) {
|
||||
return call(arg, NIL);
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
|
||||
return call(arg1, arg2);
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs varargs) {
|
||||
return call(varargs.arg1(),varargs.arg(2));
|
||||
}
|
||||
|
||||
}
|
||||
83
core/src/main/java/org/luaj/vm2/libs/VarArgFunction.java
Normal file
83
core/src/main/java/org/luaj/vm2/libs/VarArgFunction.java
Normal file
@@ -0,0 +1,83 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/** Abstract base class for Java function implementations that takes varaiable arguments and
|
||||
* returns multiple return values.
|
||||
* <p>
|
||||
* Subclasses need only implement {@link LuaValue#invoke(Varargs)} to complete this class,
|
||||
* simplifying development.
|
||||
* All other uses of {@link #call(LuaValue)}, {@link #invoke()},etc,
|
||||
* are routed through this method by this class,
|
||||
* converting arguments to {@link Varargs} and
|
||||
* dropping or extending return values with {@code nil} values as required.
|
||||
* <p>
|
||||
* If between one and three arguments are required, and only one return value is returned,
|
||||
* {@link ZeroArgFunction}, {@link OneArgFunction}, {@link TwoArgFunction}, or {@link ThreeArgFunction}.
|
||||
* <p>
|
||||
* See {@link LibFunction} for more information on implementation libraries and library functions.
|
||||
* @see #invoke(Varargs)
|
||||
* @see LibFunction
|
||||
* @see ZeroArgFunction
|
||||
* @see OneArgFunction
|
||||
* @see TwoArgFunction
|
||||
* @see ThreeArgFunction
|
||||
*/
|
||||
abstract public class VarArgFunction extends LibFunction {
|
||||
|
||||
public VarArgFunction() {
|
||||
}
|
||||
|
||||
public LuaValue call() {
|
||||
return invoke(NONE).arg1();
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return invoke(arg).arg1();
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return invoke(varargsOf(arg1,arg2)).arg1();
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
|
||||
return invoke(varargsOf(arg1,arg2,arg3)).arg1();
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclass responsibility.
|
||||
* May not have expected behavior for tail calls.
|
||||
* Should not be used if:
|
||||
* - function has a possibility of returning a TailcallVarargs
|
||||
* @param args the arguments to the function call.
|
||||
*/
|
||||
public Varargs invoke(Varargs args) {
|
||||
return onInvoke(args).eval();
|
||||
}
|
||||
|
||||
public Varargs onInvoke(Varargs args) {
|
||||
return invoke(args);
|
||||
}
|
||||
}
|
||||
70
core/src/main/java/org/luaj/vm2/libs/ZeroArgFunction.java
Normal file
70
core/src/main/java/org/luaj/vm2/libs/ZeroArgFunction.java
Normal file
@@ -0,0 +1,70 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/** Abstract base class for Java function implementations that take no arguments and
|
||||
* return one value.
|
||||
* <p>
|
||||
* Subclasses need only implement {@link LuaValue#call()} to complete this class,
|
||||
* simplifying development.
|
||||
* All other uses of {@link #call(LuaValue)}, {@link #invoke(Varargs)},etc,
|
||||
* are routed through this method by this class.
|
||||
* <p>
|
||||
* If one or more arguments are required, or variable argument or variable return values,
|
||||
* then use one of the related function
|
||||
* {@link OneArgFunction}, {@link TwoArgFunction}, {@link ThreeArgFunction}, or {@link VarArgFunction}.
|
||||
* <p>
|
||||
* See {@link LibFunction} for more information on implementation libraries and library functions.
|
||||
* @see #call()
|
||||
* @see LibFunction
|
||||
* @see OneArgFunction
|
||||
* @see TwoArgFunction
|
||||
* @see ThreeArgFunction
|
||||
* @see VarArgFunction
|
||||
*/
|
||||
abstract public class ZeroArgFunction extends LibFunction {
|
||||
|
||||
abstract public LuaValue call();
|
||||
|
||||
/** Default constructor */
|
||||
public ZeroArgFunction() {
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return call();
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return call();
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
|
||||
return call();
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs varargs) {
|
||||
return call();
|
||||
}
|
||||
}
|
||||
230
jme/src/main/java/org/luaj/vm2/libs/jme/JmeIoLib.java
Normal file
230
jme/src/main/java/org/luaj/vm2/libs/jme/JmeIoLib.java
Normal file
@@ -0,0 +1,230 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs.jme;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import javax.microedition.io.Connector;
|
||||
import javax.microedition.io.StreamConnection;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.libs.IoLib;
|
||||
import org.luaj.vm2.libs.LibFunction;
|
||||
|
||||
/**
|
||||
* Subclass of {@link IoLib} and therefore {@link LibFunction} which implements the lua standard {@code io}
|
||||
* library for the JSE platform.
|
||||
* <p>
|
||||
* The implementation of the is based on CLDC 1.0 and StreamConnection.
|
||||
* However, seek is not supported.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to
|
||||
* {@link JmePlatform#standardGlobals()}
|
||||
* <pre> {@code
|
||||
* Globals globals = JmePlatform.standardGlobals();
|
||||
* globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
|
||||
* } </pre>
|
||||
* <p>
|
||||
* For special cases where the smallest possible footprint is desired,
|
||||
* a minimal set of libraries could be loaded
|
||||
* directly via {@link Globals#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* Globals globals = new Globals();
|
||||
* globals.load(new JmeBaseLib());
|
||||
* globals.load(new PackageLib());
|
||||
* globals.load(new JmeIoLib());
|
||||
* globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
|
||||
* } </pre>
|
||||
* <p>However, other libraries such as <em>MathLib</em> are not loaded in this case.
|
||||
* <p>
|
||||
* This has been implemented to match as closely as possible the behavior in the corresponding library in C.
|
||||
* @see LibFunction
|
||||
* @see org.luaj.vm2.libs.jse.JsePlatform
|
||||
* @see JmePlatform
|
||||
* @see IoLib
|
||||
* @see org.luaj.vm2.libs.jse.JseIoLib
|
||||
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.8">Lua 5.2 I/O Lib Reference</a>
|
||||
*/
|
||||
public class JmeIoLib extends IoLib {
|
||||
|
||||
protected File wrapStdin() throws IOException {
|
||||
return new FileImpl(globals.STDIN);
|
||||
}
|
||||
|
||||
protected File wrapStdout() throws IOException {
|
||||
return new FileImpl(globals.STDOUT);
|
||||
}
|
||||
|
||||
protected File wrapStderr() throws IOException {
|
||||
return new FileImpl(globals.STDERR);
|
||||
}
|
||||
|
||||
protected File openFile( String filename, boolean readMode, boolean appendMode, boolean updateMode, boolean binaryMode ) throws IOException {
|
||||
String url = "file:///" + filename;
|
||||
int mode = readMode? Connector.READ: Connector.READ_WRITE;
|
||||
StreamConnection conn = (StreamConnection) Connector.open( url, mode );
|
||||
File f = readMode?
|
||||
new FileImpl(conn, conn.openInputStream(), null):
|
||||
new FileImpl(conn, conn.openInputStream(), conn.openOutputStream());
|
||||
/*
|
||||
if ( appendMode ) {
|
||||
f.seek("end",0);
|
||||
} else {
|
||||
if ( ! readMode )
|
||||
conn.truncate(0);
|
||||
}
|
||||
*/
|
||||
return f;
|
||||
}
|
||||
|
||||
private static void notimplemented() throws IOException {
|
||||
throw new IOException("not implemented");
|
||||
}
|
||||
|
||||
protected File openProgram(String prog, String mode) throws IOException {
|
||||
notimplemented();
|
||||
return null;
|
||||
}
|
||||
|
||||
protected File tmpFile() throws IOException {
|
||||
notimplemented();
|
||||
return null;
|
||||
}
|
||||
|
||||
private final class FileImpl extends File {
|
||||
private final StreamConnection conn;
|
||||
private final InputStream is;
|
||||
private final OutputStream os;
|
||||
private boolean closed = false;
|
||||
private boolean nobuffer = false;
|
||||
private int lookahead = -1;
|
||||
private FileImpl( StreamConnection conn, InputStream is, OutputStream os ) {
|
||||
this.conn = conn;
|
||||
this.is = is;
|
||||
this.os = os;
|
||||
}
|
||||
private FileImpl( InputStream i ) {
|
||||
this( null, i, null );
|
||||
}
|
||||
private FileImpl( OutputStream o ) {
|
||||
this( null, null, o );
|
||||
}
|
||||
public String tojstring() {
|
||||
return "file ("+this.hashCode()+")";
|
||||
}
|
||||
public boolean isstdfile() {
|
||||
return conn == null;
|
||||
}
|
||||
public void close() throws IOException {
|
||||
closed = true;
|
||||
if ( conn != null ) {
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
public void flush() throws IOException {
|
||||
if ( os != null )
|
||||
os.flush();
|
||||
}
|
||||
public void write(LuaString s) throws IOException {
|
||||
if ( os != null )
|
||||
os.write( s.m_bytes, s.m_offset, s.m_length );
|
||||
else
|
||||
notimplemented();
|
||||
if ( nobuffer )
|
||||
flush();
|
||||
}
|
||||
public boolean isclosed() {
|
||||
return closed;
|
||||
}
|
||||
public int seek(String option, int pos) throws IOException {
|
||||
/*
|
||||
if ( conn != null ) {
|
||||
if ( "set".equals(option) ) {
|
||||
conn.seek(pos);
|
||||
return (int) conn.getFilePointer();
|
||||
} else if ( "end".equals(option) ) {
|
||||
conn.seek(conn.length()+1+pos);
|
||||
return (int) conn.length()+1;
|
||||
} else {
|
||||
conn.seek(conn.getFilePointer()+pos);
|
||||
return (int) conn.getFilePointer();
|
||||
}
|
||||
}
|
||||
*/
|
||||
notimplemented();
|
||||
return 0;
|
||||
}
|
||||
public void setvbuf(String mode, int size) {
|
||||
nobuffer = "no".equals(mode);
|
||||
}
|
||||
|
||||
// get length remaining to read
|
||||
public int remaining() throws IOException {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// peek ahead one character
|
||||
public int peek() throws IOException {
|
||||
if ( lookahead < 0 )
|
||||
lookahead = is.read();
|
||||
return lookahead;
|
||||
}
|
||||
|
||||
// return char if read, -1 if eof, throw IOException on other exception
|
||||
public int read() throws IOException {
|
||||
if ( lookahead >= 0 ) {
|
||||
int c = lookahead;
|
||||
lookahead = -1;
|
||||
return c;
|
||||
}
|
||||
if ( is != null )
|
||||
return is.read();
|
||||
notimplemented();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// return number of bytes read if positive, -1 if eof, throws IOException
|
||||
public int read(byte[] bytes, int offset, int length) throws IOException {
|
||||
int n,i=0;
|
||||
if (is!=null) {
|
||||
if ( length > 0 && lookahead >= 0 ) {
|
||||
bytes[offset] = (byte) lookahead;
|
||||
lookahead = -1;
|
||||
i += 1;
|
||||
}
|
||||
for ( ; i<length; ) {
|
||||
n = is.read(bytes, offset+i, length-i);
|
||||
if ( n < 0 )
|
||||
return ( i > 0 ? i : -1 );
|
||||
i += n;
|
||||
}
|
||||
} else {
|
||||
notimplemented();
|
||||
}
|
||||
return length;
|
||||
}
|
||||
}
|
||||
}
|
||||
133
jme/src/main/java/org/luaj/vm2/libs/jme/JmePlatform.java
Normal file
133
jme/src/main/java/org/luaj/vm2/libs/jme/JmePlatform.java
Normal file
@@ -0,0 +1,133 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs.jme;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LoadState;
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
import org.luaj.vm2.libs.BaseLib;
|
||||
import org.luaj.vm2.libs.Bit32Lib;
|
||||
import org.luaj.vm2.libs.CoroutineLib;
|
||||
import org.luaj.vm2.libs.DebugLib;
|
||||
import org.luaj.vm2.libs.MathLib;
|
||||
import org.luaj.vm2.libs.OsLib;
|
||||
import org.luaj.vm2.libs.PackageLib;
|
||||
import org.luaj.vm2.libs.ResourceFinder;
|
||||
import org.luaj.vm2.libs.StringLib;
|
||||
import org.luaj.vm2.libs.TableLib;
|
||||
|
||||
/** The {@link JmePlatform} class is a convenience class to standardize
|
||||
* how globals tables are initialized for the JME platform.
|
||||
* <p>
|
||||
* The JME platform, being limited, cannot implement all libraries in all aspects. The main limitations are
|
||||
* <ul>
|
||||
* <li>Some math functions are not implemented, see {@link MathLib} for details</li>
|
||||
* <li>Scripts are loaded via Class.getResourceAsStream(), see {@link BaseLib} for details</li>
|
||||
* <li>OS functions execute(), remove(), rename(), and tmpname() vary, see {@link OsLib} for details</li>
|
||||
* <li>I/O seek is not implemented, see {@link JmeIoLib} for details</li>
|
||||
* <li>luajava is not available, see {@link org.luaj.vm2.libs.jse.LuajavaLib} for details</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* It is used to allocate either a set of standard globals using
|
||||
* {@link #standardGlobals()} or debug globals using {@link #debugGlobals()}
|
||||
* <p>
|
||||
* A simple example of initializing globals and using them from Java is:
|
||||
* <pre> {@code
|
||||
* Globals global = JmePlatform.standardGlobals();
|
||||
* global.get("print").call(LuaValue.valueOf("hello, world"));
|
||||
* } </pre>
|
||||
* <p>
|
||||
* Once globals are created, a simple way to load and run a script is:
|
||||
* <pre> {@code
|
||||
* LoadState.load( getClass().getResourceAsStream("main.lua"), "main.lua", globals ).call();
|
||||
* } </pre>
|
||||
* <p>
|
||||
* although {@code require} could also be used:
|
||||
* <pre> {@code
|
||||
* globals.get("require").call(LuaValue.valueOf("main"));
|
||||
* } </pre>
|
||||
* For this to succeed, the file "main.lua" must be a resource in the class path.
|
||||
* See {@link BaseLib} for details on finding scripts using {@link ResourceFinder}.
|
||||
* <p>
|
||||
* The standard globals will contain all standard libraries in their JME flavors:
|
||||
* <ul>
|
||||
* <li>{@link Globals}</li>
|
||||
* <li>{@link BaseLib}</li>
|
||||
* <li>{@link PackageLib}</li>
|
||||
* <li>{@link Bit32Lib}</li>
|
||||
* <li>{@link TableLib}</li>
|
||||
* <li>{@link StringLib}</li>
|
||||
* <li>{@link CoroutineLib}</li>
|
||||
* <li>{@link MathLib}</li>
|
||||
* <li>{@link JmeIoLib}</li>
|
||||
* <li>{@link OsLib}</li>
|
||||
* </ul>
|
||||
* In addition, the {@link LuaC} compiler is installed so lua files may be loaded in their source form.
|
||||
* <p>
|
||||
* The debug globals are simply the standard globals plus the {@code debug} library {@link DebugLib}.
|
||||
* <p>
|
||||
* <p>
|
||||
* The class ensures that initialization is done in the correct order.
|
||||
*
|
||||
* @see Globals
|
||||
* @see org.luaj.vm2.libs.jse.JsePlatform
|
||||
*/
|
||||
public class JmePlatform {
|
||||
|
||||
/**
|
||||
* Create a standard set of globals for JME including all the libraries.
|
||||
*
|
||||
* @return Table of globals initialized with the standard JME libraries
|
||||
* @see #debugGlobals()
|
||||
* @see org.luaj.vm2.libs.jse.JsePlatform
|
||||
* @see JmePlatform
|
||||
*/
|
||||
public static Globals standardGlobals() {
|
||||
Globals globals = new Globals();
|
||||
globals.load(new BaseLib());
|
||||
globals.load(new PackageLib());
|
||||
globals.load(new Bit32Lib());
|
||||
globals.load(new OsLib());
|
||||
globals.load(new MathLib());
|
||||
globals.load(new TableLib());
|
||||
globals.load(new StringLib());
|
||||
globals.load(new CoroutineLib());
|
||||
globals.load(new JmeIoLib());
|
||||
LoadState.install(globals);
|
||||
LuaC.install(globals);
|
||||
return globals;
|
||||
}
|
||||
|
||||
/** Create standard globals including the {@link DebugLib} library.
|
||||
*
|
||||
* @return Table of globals initialized with the standard JSE and debug libraries
|
||||
* @see #standardGlobals()
|
||||
* @see org.luaj.vm2.libs.jse.JsePlatform
|
||||
* @see JmePlatform
|
||||
* @see DebugLib
|
||||
*/
|
||||
public static Globals debugGlobals() {
|
||||
Globals globals = standardGlobals();
|
||||
globals.load(new DebugLib());
|
||||
return globals;
|
||||
}
|
||||
}
|
||||
196
jse/src/main/java/org/luaj/vm2/libs/jse/CoerceJavaToLua.java
Normal file
196
jse/src/main/java/org/luaj/vm2/libs/jse/CoerceJavaToLua.java
Normal file
@@ -0,0 +1,196 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs.jse;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.luaj.vm2.LuaDouble;
|
||||
import org.luaj.vm2.LuaInteger;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaUserdata;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
/**
|
||||
* Helper class to coerce values from Java to lua within the luajava library.
|
||||
* <p>
|
||||
* This class is primarily used by the {@link LuajavaLib},
|
||||
* but can also be used directly when working with Java/lua bindings.
|
||||
* <p>
|
||||
* To coerce scalar types, the various, generally the {@code valueOf(type)} methods
|
||||
* on {@link LuaValue} may be used:
|
||||
* <ul>
|
||||
* <li>{@link LuaValue#valueOf(boolean)}</li>
|
||||
* <li>{@link LuaValue#valueOf(byte[])}</li>
|
||||
* <li>{@link LuaValue#valueOf(double)}</li>
|
||||
* <li>{@link LuaValue#valueOf(int)}</li>
|
||||
* <li>{@link LuaValue#valueOf(String)}</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* To coerce arrays of objects and lists, the {@code listOf(..)} and {@code tableOf(...)} methods
|
||||
* on {@link LuaValue} may be used:
|
||||
* <ul>
|
||||
* <li>{@link LuaValue#listOf(LuaValue[])}</li>
|
||||
* <li>{@link LuaValue#listOf(LuaValue[], org.luaj.vm2.Varargs)}</li>
|
||||
* <li>{@link LuaValue#tableOf(LuaValue[])}</li>
|
||||
* <li>{@link LuaValue#tableOf(LuaValue[], LuaValue[], org.luaj.vm2.Varargs)}</li>
|
||||
* </ul>
|
||||
* The method {@link CoerceJavaToLua#coerce(Object)} looks as the type and dimesioning
|
||||
* of the argument and tries to guess the best fit for corrsponding lua scalar,
|
||||
* table, or table of tables.
|
||||
*
|
||||
* @see CoerceJavaToLua#coerce(Object)
|
||||
* @see LuajavaLib
|
||||
*/
|
||||
public class CoerceJavaToLua {
|
||||
|
||||
static interface Coercion {
|
||||
public LuaValue coerce( Object javaValue );
|
||||
};
|
||||
|
||||
private static final class BoolCoercion implements Coercion {
|
||||
public LuaValue coerce( Object javaValue ) {
|
||||
Boolean b = (Boolean) javaValue;
|
||||
return b.booleanValue()? LuaValue.TRUE: LuaValue.FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class IntCoercion implements Coercion {
|
||||
public LuaValue coerce( Object javaValue ) {
|
||||
Number n = (Number) javaValue;
|
||||
return LuaInteger.valueOf( n.intValue() );
|
||||
}
|
||||
}
|
||||
|
||||
private static final class CharCoercion implements Coercion {
|
||||
public LuaValue coerce( Object javaValue ) {
|
||||
Character c = (Character) javaValue;
|
||||
return LuaInteger.valueOf( c.charValue() );
|
||||
}
|
||||
}
|
||||
|
||||
private static final class DoubleCoercion implements Coercion {
|
||||
public LuaValue coerce( Object javaValue ) {
|
||||
Number n = (Number) javaValue;
|
||||
return LuaDouble.valueOf( n.doubleValue() );
|
||||
}
|
||||
}
|
||||
|
||||
private static final class StringCoercion implements Coercion {
|
||||
public LuaValue coerce( Object javaValue ) {
|
||||
return LuaString.valueOf( javaValue.toString() );
|
||||
}
|
||||
}
|
||||
|
||||
private static final class BytesCoercion implements Coercion {
|
||||
public LuaValue coerce( Object javaValue ) {
|
||||
return LuaValue.valueOf((byte[]) javaValue);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ClassCoercion implements Coercion {
|
||||
public LuaValue coerce( Object javaValue ) {
|
||||
return JavaClass.forClass((Class) javaValue);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class InstanceCoercion implements Coercion {
|
||||
public LuaValue coerce(Object javaValue) {
|
||||
return new JavaInstance(javaValue);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ArrayCoercion implements Coercion {
|
||||
public LuaValue coerce(Object javaValue) {
|
||||
// should be userdata?
|
||||
return new JavaArray(javaValue);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class LuaCoercion implements Coercion {
|
||||
public LuaValue coerce( Object javaValue ) {
|
||||
return (LuaValue) javaValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static final Map COERCIONS = Collections.synchronizedMap(new HashMap());
|
||||
|
||||
static {
|
||||
Coercion boolCoercion = new BoolCoercion() ;
|
||||
Coercion intCoercion = new IntCoercion() ;
|
||||
Coercion charCoercion = new CharCoercion() ;
|
||||
Coercion doubleCoercion = new DoubleCoercion() ;
|
||||
Coercion stringCoercion = new StringCoercion() ;
|
||||
Coercion bytesCoercion = new BytesCoercion() ;
|
||||
Coercion classCoercion = new ClassCoercion() ;
|
||||
COERCIONS.put( Boolean.class, boolCoercion );
|
||||
COERCIONS.put( Byte.class, intCoercion );
|
||||
COERCIONS.put( Character.class, charCoercion );
|
||||
COERCIONS.put( Short.class, intCoercion );
|
||||
COERCIONS.put( Integer.class, intCoercion );
|
||||
COERCIONS.put( Long.class, doubleCoercion );
|
||||
COERCIONS.put( Float.class, doubleCoercion );
|
||||
COERCIONS.put( Double.class, doubleCoercion );
|
||||
COERCIONS.put( String.class, stringCoercion );
|
||||
COERCIONS.put( byte[].class, bytesCoercion );
|
||||
COERCIONS.put( Class.class, classCoercion );
|
||||
}
|
||||
|
||||
/**
|
||||
* Coerse a Java object to a corresponding lua value.
|
||||
* <p>
|
||||
* Integral types {@code boolean}, {@code byte}, {@code char}, and {@code int}
|
||||
* will become {@link LuaInteger};
|
||||
* {@code long}, {@code float}, and {@code double} will become {@link LuaDouble};
|
||||
* {@code String} and {@code byte[]} will become {@link LuaString};
|
||||
* types inheriting from {@link LuaValue} will be returned without coercion;
|
||||
* other types will become {@link LuaUserdata}.
|
||||
* @param o Java object needing conversion
|
||||
* @return {@link LuaValue} corresponding to the supplied Java value.
|
||||
* @see LuaValue
|
||||
* @see LuaInteger
|
||||
* @see LuaDouble
|
||||
* @see LuaString
|
||||
* @see LuaUserdata
|
||||
*/
|
||||
public static LuaValue coerce(Object o) {
|
||||
if ( o == null )
|
||||
return LuaValue.NIL;
|
||||
Class clazz = o.getClass();
|
||||
Coercion c = (Coercion) COERCIONS.get( clazz );
|
||||
if ( c == null ) {
|
||||
c = clazz.isArray()? arrayCoercion:
|
||||
o instanceof LuaValue ? luaCoercion:
|
||||
instanceCoercion;
|
||||
COERCIONS.put( clazz, c );
|
||||
}
|
||||
return c.coerce(o);
|
||||
}
|
||||
|
||||
static final Coercion instanceCoercion = new InstanceCoercion();
|
||||
|
||||
static final Coercion arrayCoercion = new ArrayCoercion();
|
||||
|
||||
static final Coercion luaCoercion = new LuaCoercion() ;
|
||||
}
|
||||
372
jse/src/main/java/org/luaj/vm2/libs/jse/CoerceLuaToJava.java
Normal file
372
jse/src/main/java/org/luaj/vm2/libs/jse/CoerceLuaToJava.java
Normal file
@@ -0,0 +1,372 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs.jse;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
/**
|
||||
* Helper class to coerce values from lua to Java within the luajava library.
|
||||
* <p>
|
||||
* This class is primarily used by the {@link LuajavaLib},
|
||||
* but can also be used directly when working with Java/lua bindings.
|
||||
* <p>
|
||||
* To coerce to specific Java values, generally the {@code toType()} methods
|
||||
* on {@link LuaValue} may be used:
|
||||
* <ul>
|
||||
* <li>{@link LuaValue#toboolean()}</li>
|
||||
* <li>{@link LuaValue#tobyte()}</li>
|
||||
* <li>{@link LuaValue#tochar()}</li>
|
||||
* <li>{@link LuaValue#toshort()}</li>
|
||||
* <li>{@link LuaValue#toint()}</li>
|
||||
* <li>{@link LuaValue#tofloat()}</li>
|
||||
* <li>{@link LuaValue#todouble()}</li>
|
||||
* <li>{@link LuaValue#tojstring()}</li>
|
||||
* <li>{@link LuaValue#touserdata()}</li>
|
||||
* <li>{@link LuaValue#touserdata(Class)}</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* For data in lua tables, the various methods on {@link LuaTable} can be used directly
|
||||
* to convert data to something more useful.
|
||||
*
|
||||
* @see LuajavaLib
|
||||
* @see CoerceJavaToLua
|
||||
*/
|
||||
public class CoerceLuaToJava {
|
||||
|
||||
static int SCORE_NULL_VALUE = 0x10;
|
||||
static int SCORE_WRONG_TYPE = 0x100;
|
||||
static int SCORE_UNCOERCIBLE = 0x10000;
|
||||
|
||||
static interface Coercion {
|
||||
public int score( LuaValue value );
|
||||
public Object coerce( LuaValue value );
|
||||
};
|
||||
|
||||
/**
|
||||
* Coerce a LuaValue value to a specified java class
|
||||
* @param value LuaValue to coerce
|
||||
* @param clazz Class to coerce into
|
||||
* @return Object of type clazz (or a subclass) with the corresponding value.
|
||||
*/
|
||||
public static Object coerce(LuaValue value, Class clazz) {
|
||||
return getCoercion(clazz).coerce(value);
|
||||
}
|
||||
|
||||
static final Map COERCIONS = Collections.synchronizedMap(new HashMap());
|
||||
|
||||
static final class BoolCoercion implements Coercion {
|
||||
public String toString() {
|
||||
return "BoolCoercion()";
|
||||
}
|
||||
public int score( LuaValue value ) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TBOOLEAN:
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
public Object coerce(LuaValue value) {
|
||||
return value.toboolean()? Boolean.TRUE: Boolean.FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static final class NumericCoercion implements Coercion {
|
||||
static final int TARGET_TYPE_BYTE = 0;
|
||||
static final int TARGET_TYPE_CHAR = 1;
|
||||
static final int TARGET_TYPE_SHORT = 2;
|
||||
static final int TARGET_TYPE_INT = 3;
|
||||
static final int TARGET_TYPE_LONG = 4;
|
||||
static final int TARGET_TYPE_FLOAT = 5;
|
||||
static final int TARGET_TYPE_DOUBLE = 6;
|
||||
static final String[] TYPE_NAMES = { "byte", "char", "short", "int", "long", "float", "double" };
|
||||
final int targetType;
|
||||
public String toString() {
|
||||
return "NumericCoercion("+TYPE_NAMES[targetType]+")";
|
||||
}
|
||||
NumericCoercion(int targetType) {
|
||||
this.targetType = targetType;
|
||||
}
|
||||
public int score( LuaValue value ) {
|
||||
int fromStringPenalty = 0;
|
||||
if ( value.type() == LuaValue.TSTRING ) {
|
||||
value = value.tonumber();
|
||||
if ( value.isnil() ) {
|
||||
return SCORE_UNCOERCIBLE;
|
||||
}
|
||||
fromStringPenalty = 4;
|
||||
}
|
||||
if ( value.isint() ) {
|
||||
switch ( targetType ) {
|
||||
case TARGET_TYPE_BYTE: {
|
||||
int i = value.toint();
|
||||
return fromStringPenalty + ((i==(byte)i)? 0: SCORE_WRONG_TYPE);
|
||||
}
|
||||
case TARGET_TYPE_CHAR: {
|
||||
int i = value.toint();
|
||||
return fromStringPenalty + ((i==(byte)i)? 1: (i==(char)i)? 0: SCORE_WRONG_TYPE);
|
||||
}
|
||||
case TARGET_TYPE_SHORT: {
|
||||
int i = value.toint();
|
||||
return fromStringPenalty +
|
||||
((i==(byte)i)? 1: (i==(short)i)? 0: SCORE_WRONG_TYPE);
|
||||
}
|
||||
case TARGET_TYPE_INT: {
|
||||
int i = value.toint();
|
||||
return fromStringPenalty +
|
||||
((i==(byte)i)? 2: ((i==(char)i) || (i==(short)i))? 1: 0);
|
||||
}
|
||||
case TARGET_TYPE_FLOAT: return fromStringPenalty + 1;
|
||||
case TARGET_TYPE_LONG: return fromStringPenalty + 1;
|
||||
case TARGET_TYPE_DOUBLE: return fromStringPenalty + 2;
|
||||
default: return SCORE_WRONG_TYPE;
|
||||
}
|
||||
} else if ( value.isnumber() ) {
|
||||
switch ( targetType ) {
|
||||
case TARGET_TYPE_BYTE: return SCORE_WRONG_TYPE;
|
||||
case TARGET_TYPE_CHAR: return SCORE_WRONG_TYPE;
|
||||
case TARGET_TYPE_SHORT: return SCORE_WRONG_TYPE;
|
||||
case TARGET_TYPE_INT: return SCORE_WRONG_TYPE;
|
||||
case TARGET_TYPE_LONG: {
|
||||
double d = value.todouble();
|
||||
return fromStringPenalty + ((d==(long)d)? 0: SCORE_WRONG_TYPE);
|
||||
}
|
||||
case TARGET_TYPE_FLOAT: {
|
||||
double d = value.todouble();
|
||||
return fromStringPenalty + ((d==(float)d)? 0: SCORE_WRONG_TYPE);
|
||||
}
|
||||
case TARGET_TYPE_DOUBLE: {
|
||||
double d = value.todouble();
|
||||
return fromStringPenalty + (((d==(long)d) || (d==(float)d))? 1: 0);
|
||||
}
|
||||
default: return SCORE_WRONG_TYPE;
|
||||
}
|
||||
} else {
|
||||
return SCORE_UNCOERCIBLE;
|
||||
}
|
||||
}
|
||||
|
||||
public Object coerce(LuaValue value) {
|
||||
switch ( targetType ) {
|
||||
case TARGET_TYPE_BYTE: return Byte.valueOf( (byte) value.toint() );
|
||||
case TARGET_TYPE_CHAR: return Character.valueOf( (char) value.toint() );
|
||||
case TARGET_TYPE_SHORT: return Short.valueOf( (short) value.toint() );
|
||||
case TARGET_TYPE_INT: return Integer.valueOf( (int) value.toint() );
|
||||
case TARGET_TYPE_LONG: return Long.valueOf( (long) value.todouble() );
|
||||
case TARGET_TYPE_FLOAT: return Float.valueOf( (float) value.todouble() );
|
||||
case TARGET_TYPE_DOUBLE: return Double.valueOf( (double) value.todouble() );
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static final class StringCoercion implements Coercion {
|
||||
public static final int TARGET_TYPE_STRING = 0;
|
||||
public static final int TARGET_TYPE_BYTES = 1;
|
||||
final int targetType;
|
||||
public StringCoercion(int targetType) {
|
||||
this.targetType = targetType;
|
||||
}
|
||||
public String toString() {
|
||||
return "StringCoercion("+(targetType==TARGET_TYPE_STRING? "String": "byte[]")+")";
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TSTRING:
|
||||
return value.checkstring().isValidUtf8()?
|
||||
(targetType==TARGET_TYPE_STRING? 0: 1):
|
||||
(targetType==TARGET_TYPE_BYTES? 0: SCORE_WRONG_TYPE);
|
||||
case LuaValue.TNIL:
|
||||
return SCORE_NULL_VALUE;
|
||||
default:
|
||||
return targetType == TARGET_TYPE_STRING? SCORE_WRONG_TYPE: SCORE_UNCOERCIBLE;
|
||||
}
|
||||
}
|
||||
public Object coerce(LuaValue value) {
|
||||
if ( value.isnil() )
|
||||
return null;
|
||||
if ( targetType == TARGET_TYPE_STRING )
|
||||
return value.tojstring();
|
||||
LuaString s = value.checkstring();
|
||||
byte[] b = new byte[s.m_length];
|
||||
s.copyInto(0, b, 0, b.length);
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
static final class ArrayCoercion implements Coercion {
|
||||
final Class componentType;
|
||||
final Coercion componentCoercion;
|
||||
public ArrayCoercion(Class componentType) {
|
||||
this.componentType = componentType;
|
||||
this.componentCoercion = getCoercion(componentType);
|
||||
}
|
||||
public String toString() {
|
||||
return "ArrayCoercion("+componentType.getName()+")";
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TTABLE:
|
||||
return value.length()==0? 0: componentCoercion.score( value.get(1) );
|
||||
case LuaValue.TUSERDATA:
|
||||
return inheritanceLevels( componentType, value.touserdata().getClass().getComponentType() );
|
||||
case LuaValue.TNIL:
|
||||
return SCORE_NULL_VALUE;
|
||||
default:
|
||||
return SCORE_UNCOERCIBLE;
|
||||
}
|
||||
}
|
||||
public Object coerce(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TTABLE: {
|
||||
int n = value.length();
|
||||
Object a = Array.newInstance(componentType, n);
|
||||
for ( int i=0; i<n; i++ )
|
||||
Array.set(a, i, componentCoercion.coerce(value.get(i+1)));
|
||||
return a;
|
||||
}
|
||||
case LuaValue.TUSERDATA:
|
||||
return value.touserdata();
|
||||
case LuaValue.TNIL:
|
||||
return null;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine levels of inheritance between a base class and a subclass
|
||||
* @param baseclass base class to look for
|
||||
* @param subclass class from which to start looking
|
||||
* @return number of inheritance levels between subclass and baseclass,
|
||||
* or SCORE_UNCOERCIBLE if not a subclass
|
||||
*/
|
||||
static final int inheritanceLevels( Class baseclass, Class subclass ) {
|
||||
if ( subclass == null )
|
||||
return SCORE_UNCOERCIBLE;
|
||||
if ( baseclass == subclass )
|
||||
return 0;
|
||||
int min = Math.min( SCORE_UNCOERCIBLE, inheritanceLevels( baseclass, subclass.getSuperclass() ) + 1 );
|
||||
Class[] ifaces = subclass.getInterfaces();
|
||||
for ( int i=0; i<ifaces.length; i++ )
|
||||
min = Math.min(min, inheritanceLevels(baseclass, ifaces[i]) + 1 );
|
||||
return min;
|
||||
}
|
||||
|
||||
static final class ObjectCoercion implements Coercion {
|
||||
final Class targetType;
|
||||
ObjectCoercion(Class targetType) {
|
||||
this.targetType = targetType;
|
||||
}
|
||||
public String toString() {
|
||||
return "ObjectCoercion("+targetType.getName()+")";
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TNUMBER:
|
||||
return inheritanceLevels( targetType, value.isint()? Integer.class: Double.class );
|
||||
case LuaValue.TBOOLEAN:
|
||||
return inheritanceLevels( targetType, Boolean.class );
|
||||
case LuaValue.TSTRING:
|
||||
return inheritanceLevels( targetType, String.class );
|
||||
case LuaValue.TUSERDATA:
|
||||
return inheritanceLevels( targetType, value.touserdata().getClass() );
|
||||
case LuaValue.TNIL:
|
||||
return SCORE_NULL_VALUE;
|
||||
default:
|
||||
return inheritanceLevels( targetType, value.getClass() );
|
||||
}
|
||||
}
|
||||
public Object coerce(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TNUMBER:
|
||||
return value.isint()? (Object) Integer.valueOf(value.toint()): (Object) Double.valueOf(value.todouble());
|
||||
case LuaValue.TBOOLEAN:
|
||||
return value.toboolean()? Boolean.TRUE: Boolean.FALSE;
|
||||
case LuaValue.TSTRING:
|
||||
return value.tojstring();
|
||||
case LuaValue.TUSERDATA:
|
||||
return value.optuserdata(targetType, null);
|
||||
case LuaValue.TNIL:
|
||||
return null;
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
Coercion boolCoercion = new BoolCoercion();
|
||||
Coercion byteCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_BYTE);
|
||||
Coercion charCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_CHAR);
|
||||
Coercion shortCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_SHORT);
|
||||
Coercion intCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_INT);
|
||||
Coercion longCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_LONG);
|
||||
Coercion floatCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_FLOAT);
|
||||
Coercion doubleCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_DOUBLE);
|
||||
Coercion stringCoercion = new StringCoercion(StringCoercion.TARGET_TYPE_STRING);
|
||||
Coercion bytesCoercion = new StringCoercion(StringCoercion.TARGET_TYPE_BYTES);
|
||||
|
||||
COERCIONS.put( Boolean.TYPE, boolCoercion );
|
||||
COERCIONS.put( Boolean.class, boolCoercion );
|
||||
COERCIONS.put( Byte.TYPE, byteCoercion );
|
||||
COERCIONS.put( Byte.class, byteCoercion );
|
||||
COERCIONS.put( Character.TYPE, charCoercion );
|
||||
COERCIONS.put( Character.class, charCoercion );
|
||||
COERCIONS.put( Short.TYPE, shortCoercion );
|
||||
COERCIONS.put( Short.class, shortCoercion );
|
||||
COERCIONS.put( Integer.TYPE, intCoercion );
|
||||
COERCIONS.put( Integer.class, intCoercion );
|
||||
COERCIONS.put( Long.TYPE, longCoercion );
|
||||
COERCIONS.put( Long.class, longCoercion );
|
||||
COERCIONS.put( Float.TYPE, floatCoercion );
|
||||
COERCIONS.put( Float.class, floatCoercion );
|
||||
COERCIONS.put( Double.TYPE, doubleCoercion );
|
||||
COERCIONS.put( Double.class, doubleCoercion );
|
||||
COERCIONS.put( String.class, stringCoercion );
|
||||
COERCIONS.put( byte[].class, bytesCoercion );
|
||||
}
|
||||
|
||||
static Coercion getCoercion(Class c) {
|
||||
Coercion co = (Coercion) COERCIONS.get( c );
|
||||
if ( co != null ) {
|
||||
return co;
|
||||
}
|
||||
if ( c.isArray() ) {
|
||||
Class typ = c.getComponentType();
|
||||
co = new ArrayCoercion(c.getComponentType());
|
||||
} else {
|
||||
co = new ObjectCoercion(c);
|
||||
}
|
||||
COERCIONS.put( c, co );
|
||||
return co;
|
||||
}
|
||||
}
|
||||
86
jse/src/main/java/org/luaj/vm2/libs/jse/JavaArray.java
Normal file
86
jse/src/main/java/org/luaj/vm2/libs/jse/JavaArray.java
Normal file
@@ -0,0 +1,86 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2011 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs.jse;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaUserdata;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.libs.OneArgFunction;
|
||||
|
||||
/**
|
||||
* LuaValue that represents a Java instance of array type.
|
||||
* <p>
|
||||
* Can get elements by their integer key index, as well as the length.
|
||||
* <p>
|
||||
* This class is not used directly.
|
||||
* It is returned by calls to {@link CoerceJavaToLua#coerce(Object)}
|
||||
* when an array is supplied.
|
||||
* @see CoerceJavaToLua
|
||||
* @see CoerceLuaToJava
|
||||
*/
|
||||
class JavaArray extends LuaUserdata {
|
||||
|
||||
private static final class LenFunction extends OneArgFunction {
|
||||
public LuaValue call(LuaValue u) {
|
||||
return LuaValue.valueOf(Array.getLength(((LuaUserdata)u).m_instance));
|
||||
}
|
||||
}
|
||||
|
||||
static final LuaValue LENGTH = valueOf("length");
|
||||
|
||||
static final LuaTable array_metatable;
|
||||
static {
|
||||
array_metatable = new LuaTable();
|
||||
array_metatable.rawset(LuaValue.LEN, new LenFunction());
|
||||
}
|
||||
|
||||
JavaArray(Object instance) {
|
||||
super(instance);
|
||||
setmetatable(array_metatable);
|
||||
}
|
||||
|
||||
public LuaValue get(LuaValue key) {
|
||||
if ( key.equals(LENGTH) )
|
||||
return valueOf(Array.getLength(m_instance));
|
||||
if ( key.isint() ) {
|
||||
int i = key.toint() - 1;
|
||||
return i>=0 && i<Array.getLength(m_instance)?
|
||||
CoerceJavaToLua.coerce(Array.get(m_instance,key.toint()-1)):
|
||||
NIL;
|
||||
}
|
||||
return super.get(key);
|
||||
}
|
||||
|
||||
public void set(LuaValue key, LuaValue value) {
|
||||
if ( key.isint() ) {
|
||||
int i = key.toint() - 1;
|
||||
if ( i>=0 && i<Array.getLength(m_instance) )
|
||||
Array.set(m_instance,i,CoerceLuaToJava.coerce(value, m_instance.getClass().getComponentType()));
|
||||
else if ( m_metatable==null || ! settable(this,key,value) )
|
||||
error("array index out of bounds");
|
||||
}
|
||||
else
|
||||
super.set(key, value);
|
||||
}
|
||||
}
|
||||
153
jse/src/main/java/org/luaj/vm2/libs/jse/JavaClass.java
Normal file
153
jse/src/main/java/org/luaj/vm2/libs/jse/JavaClass.java
Normal file
@@ -0,0 +1,153 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2011 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs.jse;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
/**
|
||||
* LuaValue that represents a Java class.
|
||||
* <p>
|
||||
* Will respond to get() and set() by returning field values, or java methods.
|
||||
* <p>
|
||||
* This class is not used directly.
|
||||
* It is returned by calls to {@link CoerceJavaToLua#coerce(Object)}
|
||||
* when a Class is supplied.
|
||||
* @see CoerceJavaToLua
|
||||
* @see CoerceLuaToJava
|
||||
*/
|
||||
class JavaClass extends JavaInstance implements CoerceJavaToLua.Coercion {
|
||||
|
||||
static final Map classes = Collections.synchronizedMap(new HashMap());
|
||||
|
||||
static final LuaValue NEW = valueOf("new");
|
||||
|
||||
Map fields;
|
||||
Map methods;
|
||||
Map innerclasses;
|
||||
|
||||
static JavaClass forClass(Class c) {
|
||||
JavaClass j = (JavaClass) classes.get(c);
|
||||
if ( j == null )
|
||||
classes.put( c, j = new JavaClass(c) );
|
||||
return j;
|
||||
}
|
||||
|
||||
JavaClass(Class c) {
|
||||
super(c);
|
||||
this.jclass = this;
|
||||
}
|
||||
|
||||
public LuaValue coerce(Object javaValue) {
|
||||
return this;
|
||||
}
|
||||
|
||||
Field getField(LuaValue key) {
|
||||
if ( fields == null ) {
|
||||
Map m = new HashMap();
|
||||
Field[] f = ((Class)m_instance).getFields();
|
||||
for ( int i=0; i<f.length; i++ ) {
|
||||
Field fi = f[i];
|
||||
if ( Modifier.isPublic(fi.getModifiers()) ) {
|
||||
m.put(LuaValue.valueOf(fi.getName()), fi);
|
||||
try {
|
||||
if (!fi.isAccessible())
|
||||
fi.setAccessible(true);
|
||||
} catch (SecurityException s) {
|
||||
}
|
||||
}
|
||||
}
|
||||
fields = m;
|
||||
}
|
||||
return (Field) fields.get(key);
|
||||
}
|
||||
|
||||
LuaValue getMethod(LuaValue key) {
|
||||
if ( methods == null ) {
|
||||
Map namedlists = new HashMap();
|
||||
Method[] m = ((Class)m_instance).getMethods();
|
||||
for ( int i=0; i<m.length; i++ ) {
|
||||
Method mi = m[i];
|
||||
if ( Modifier.isPublic( mi.getModifiers()) ) {
|
||||
String name = mi.getName();
|
||||
List list = (List) namedlists.get(name);
|
||||
if ( list == null )
|
||||
namedlists.put(name, list = new ArrayList());
|
||||
list.add( JavaMethod.forMethod(mi) );
|
||||
}
|
||||
}
|
||||
Map map = new HashMap();
|
||||
Constructor[] c = ((Class)m_instance).getConstructors();
|
||||
List list = new ArrayList();
|
||||
for ( int i=0; i<c.length; i++ )
|
||||
if ( Modifier.isPublic(c[i].getModifiers()) )
|
||||
list.add( JavaConstructor.forConstructor(c[i]) );
|
||||
switch ( list.size() ) {
|
||||
case 0: break;
|
||||
case 1: map.put(NEW, list.get(0)); break;
|
||||
default: map.put(NEW, JavaConstructor.forConstructors( (JavaConstructor[])list.toArray(new JavaConstructor[list.size()]) ) ); break;
|
||||
}
|
||||
|
||||
for ( Iterator it=namedlists.entrySet().iterator(); it.hasNext(); ) {
|
||||
Entry e = (Entry) it.next();
|
||||
String name = (String) e.getKey();
|
||||
List methods = (List) e.getValue();
|
||||
map.put( LuaValue.valueOf(name),
|
||||
methods.size()==1?
|
||||
methods.get(0):
|
||||
JavaMethod.forMethods( (JavaMethod[])methods.toArray(new JavaMethod[methods.size()])) );
|
||||
}
|
||||
methods = map;
|
||||
}
|
||||
return (LuaValue) methods.get(key);
|
||||
}
|
||||
|
||||
Class getInnerClass(LuaValue key) {
|
||||
if ( innerclasses == null ) {
|
||||
Map m = new HashMap();
|
||||
Class[] c = ((Class)m_instance).getClasses();
|
||||
for ( int i=0; i<c.length; i++ ) {
|
||||
Class ci = c[i];
|
||||
String name = ci.getName();
|
||||
String stub = name.substring(Math.max(name.lastIndexOf('$'), name.lastIndexOf('.'))+1);
|
||||
m.put(LuaValue.valueOf(stub), ci);
|
||||
}
|
||||
innerclasses = m;
|
||||
}
|
||||
return (Class) innerclasses.get(key);
|
||||
}
|
||||
|
||||
public LuaValue getConstructor() {
|
||||
return getMethod(NEW);
|
||||
}
|
||||
}
|
||||
116
jse/src/main/java/org/luaj/vm2/libs/jse/JavaConstructor.java
Normal file
116
jse/src/main/java/org/luaj/vm2/libs/jse/JavaConstructor.java
Normal file
@@ -0,0 +1,116 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2011 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs.jse;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.libs.VarArgFunction;
|
||||
|
||||
/**
|
||||
* LuaValue that represents a particular public Java constructor.
|
||||
* <p>
|
||||
* May be called with arguments to return a JavaInstance
|
||||
* created by calling the constructor.
|
||||
* <p>
|
||||
* This class is not used directly.
|
||||
* It is returned by calls to {@link JavaClass#new(LuaValue key)}
|
||||
* when the value of key is "new".
|
||||
* @see CoerceJavaToLua
|
||||
* @see CoerceLuaToJava
|
||||
*/
|
||||
class JavaConstructor extends JavaMember {
|
||||
|
||||
static final Map constructors = Collections.synchronizedMap(new HashMap());
|
||||
|
||||
static JavaConstructor forConstructor(Constructor c) {
|
||||
JavaConstructor j = (JavaConstructor) constructors.get(c);
|
||||
if ( j == null )
|
||||
constructors.put( c, j = new JavaConstructor(c) );
|
||||
return j;
|
||||
}
|
||||
|
||||
public static LuaValue forConstructors(JavaConstructor[] array) {
|
||||
return new Overload(array);
|
||||
}
|
||||
|
||||
final Constructor constructor;
|
||||
|
||||
private JavaConstructor(Constructor c) {
|
||||
super( c.getParameterTypes(), c.getModifiers() );
|
||||
this.constructor = c;
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs args) {
|
||||
Object[] a = convertArgs(args);
|
||||
try {
|
||||
return CoerceJavaToLua.coerce( constructor.newInstance(a) );
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new LuaError(e.getTargetException());
|
||||
} catch (Exception e) {
|
||||
return LuaValue.error("coercion error "+e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* LuaValue that represents an overloaded Java constructor.
|
||||
* <p>
|
||||
* On invocation, will pick the best method from the list, and invoke it.
|
||||
* <p>
|
||||
* This class is not used directly.
|
||||
* It is returned by calls to calls to {@link JavaClass#get(LuaValue key)}
|
||||
* when key is "new" and there is more than one public constructor.
|
||||
*/
|
||||
static class Overload extends VarArgFunction {
|
||||
final JavaConstructor[] constructors;
|
||||
public Overload(JavaConstructor[] c) {
|
||||
this.constructors = c;
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs args) {
|
||||
JavaConstructor best = null;
|
||||
int score = CoerceLuaToJava.SCORE_UNCOERCIBLE;
|
||||
for ( int i=0; i<constructors.length; i++ ) {
|
||||
int s = constructors[i].score(args);
|
||||
if ( s < score ) {
|
||||
score = s;
|
||||
best = constructors[i];
|
||||
if ( score == 0 )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// any match?
|
||||
if ( best == null )
|
||||
LuaValue.error("no coercible public method");
|
||||
|
||||
// invoke it
|
||||
return best.invoke(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
82
jse/src/main/java/org/luaj/vm2/libs/jse/JavaInstance.java
Normal file
82
jse/src/main/java/org/luaj/vm2/libs/jse/JavaInstance.java
Normal file
@@ -0,0 +1,82 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2011 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs.jse;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaUserdata;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
/**
|
||||
* LuaValue that represents a Java instance.
|
||||
* <p>
|
||||
* Will respond to get() and set() by returning field values or methods.
|
||||
* <p>
|
||||
* This class is not used directly.
|
||||
* It is returned by calls to {@link CoerceJavaToLua#coerce(Object)}
|
||||
* when a subclass of Object is supplied.
|
||||
* @see CoerceJavaToLua
|
||||
* @see CoerceLuaToJava
|
||||
*/
|
||||
class JavaInstance extends LuaUserdata {
|
||||
|
||||
JavaClass jclass;
|
||||
|
||||
JavaInstance(Object instance) {
|
||||
super(instance);
|
||||
}
|
||||
|
||||
public LuaValue get(LuaValue key) {
|
||||
if ( jclass == null )
|
||||
jclass = JavaClass.forClass(m_instance.getClass());
|
||||
Field f = jclass.getField(key);
|
||||
if ( f != null )
|
||||
try {
|
||||
return CoerceJavaToLua.coerce(f.get(m_instance));
|
||||
} catch (Exception e) {
|
||||
throw new LuaError(e);
|
||||
}
|
||||
LuaValue m = jclass.getMethod(key);
|
||||
if ( m != null )
|
||||
return m;
|
||||
Class c = jclass.getInnerClass(key);
|
||||
if ( c != null )
|
||||
return JavaClass.forClass(c);
|
||||
return super.get(key);
|
||||
}
|
||||
|
||||
public void set(LuaValue key, LuaValue value) {
|
||||
if ( jclass == null )
|
||||
jclass = JavaClass.forClass(m_instance.getClass());
|
||||
Field f = jclass.getField(key);
|
||||
if ( f != null )
|
||||
try {
|
||||
f.set(m_instance, CoerceLuaToJava.coerce(value, f.getType()));
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
throw new LuaError(e);
|
||||
}
|
||||
super.set(key, value);
|
||||
}
|
||||
|
||||
}
|
||||
84
jse/src/main/java/org/luaj/vm2/libs/jse/JavaMember.java
Normal file
84
jse/src/main/java/org/luaj/vm2/libs/jse/JavaMember.java
Normal file
@@ -0,0 +1,84 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2011 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs.jse;
|
||||
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.libs.VarArgFunction;
|
||||
import org.luaj.vm2.libs.jse.CoerceLuaToJava.Coercion;
|
||||
|
||||
/**
|
||||
* Java method or constructor.
|
||||
* <p>
|
||||
* Primarily handles argument coercion for parameter lists including scoring of compatibility and
|
||||
* java varargs handling.
|
||||
* <p>
|
||||
* This class is not used directly.
|
||||
* It is an abstract base class for {@link JavaConstructor} and {@link JavaMethod}.
|
||||
* @see JavaConstructor
|
||||
* @see JavaMethod
|
||||
* @see CoerceJavaToLua
|
||||
* @see CoerceLuaToJava
|
||||
*/
|
||||
abstract
|
||||
class JavaMember extends VarArgFunction {
|
||||
|
||||
static final int METHOD_MODIFIERS_VARARGS = 0x80;
|
||||
|
||||
final Coercion[] fixedargs;
|
||||
final Coercion varargs;
|
||||
|
||||
protected JavaMember(Class[] params, int modifiers) {
|
||||
boolean isvarargs = ((modifiers & METHOD_MODIFIERS_VARARGS) != 0);
|
||||
fixedargs = new Coercion[isvarargs? params.length-1: params.length];
|
||||
for ( int i=0; i<fixedargs.length; i++ )
|
||||
fixedargs[i] = CoerceLuaToJava.getCoercion( params[i] );
|
||||
varargs = isvarargs? CoerceLuaToJava.getCoercion( params[params.length-1] ): null;
|
||||
}
|
||||
|
||||
int score(Varargs args) {
|
||||
int n = args.narg();
|
||||
int s = n>fixedargs.length? CoerceLuaToJava.SCORE_WRONG_TYPE * (n-fixedargs.length): 0;
|
||||
for ( int j=0; j<fixedargs.length; j++ )
|
||||
s += fixedargs[j].score( args.arg(j+1) );
|
||||
if ( varargs != null )
|
||||
for ( int k=fixedargs.length; k<n; k++ )
|
||||
s += varargs.score( args.arg(k+1) );
|
||||
return s;
|
||||
}
|
||||
|
||||
protected Object[] convertArgs(Varargs args) {
|
||||
Object[] a;
|
||||
if ( varargs == null ) {
|
||||
a = new Object[fixedargs.length];
|
||||
for ( int i=0; i<a.length; i++ )
|
||||
a[i] = fixedargs[i].coerce( args.arg(i+1) );
|
||||
} else {
|
||||
int n = Math.max(fixedargs.length,args.narg());
|
||||
a = new Object[n];
|
||||
for ( int i=0; i<fixedargs.length; i++ )
|
||||
a[i] = fixedargs[i].coerce( args.arg(i+1) );
|
||||
for ( int i=fixedargs.length; i<n; i++ )
|
||||
a[i] = varargs.coerce( args.arg(i+1) );
|
||||
}
|
||||
return a;
|
||||
}
|
||||
}
|
||||
163
jse/src/main/java/org/luaj/vm2/libs/jse/JavaMethod.java
Normal file
163
jse/src/main/java/org/luaj/vm2/libs/jse/JavaMethod.java
Normal file
@@ -0,0 +1,163 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2011 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs.jse;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaFunction;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/**
|
||||
* LuaValue that represents a Java method.
|
||||
* <p>
|
||||
* Can be invoked via call(LuaValue...) and related methods.
|
||||
* <p>
|
||||
* This class is not used directly.
|
||||
* It is returned by calls to calls to {@link JavaInstance#get(LuaValue key)}
|
||||
* when a method is named.
|
||||
* @see CoerceJavaToLua
|
||||
* @see CoerceLuaToJava
|
||||
*/
|
||||
class JavaMethod extends JavaMember {
|
||||
|
||||
static final Map methods = Collections.synchronizedMap(new HashMap());
|
||||
|
||||
static JavaMethod forMethod(Method m) {
|
||||
JavaMethod j = (JavaMethod) methods.get(m);
|
||||
if ( j == null )
|
||||
methods.put( m, j = new JavaMethod(m) );
|
||||
return j;
|
||||
}
|
||||
|
||||
static LuaFunction forMethods(JavaMethod[] m) {
|
||||
return new Overload(m);
|
||||
}
|
||||
|
||||
final Method method;
|
||||
|
||||
private JavaMethod(Method m) {
|
||||
super( m.getParameterTypes(), m.getModifiers() );
|
||||
this.method = m;
|
||||
try {
|
||||
if (!m.isAccessible())
|
||||
m.setAccessible(true);
|
||||
} catch (SecurityException s) {
|
||||
}
|
||||
}
|
||||
|
||||
public LuaValue call() {
|
||||
return error("method cannot be called without instance");
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return invokeMethod(arg.checkuserdata(), LuaValue.NONE);
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return invokeMethod(arg1.checkuserdata(), arg2);
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
|
||||
return invokeMethod(arg1.checkuserdata(), LuaValue.varargsOf(arg2, arg3));
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs args) {
|
||||
return invokeMethod(args.checkuserdata(1), args.subargs(2));
|
||||
}
|
||||
|
||||
LuaValue invokeMethod(Object instance, Varargs args) {
|
||||
Object[] a = convertArgs(args);
|
||||
try {
|
||||
return CoerceJavaToLua.coerce( method.invoke(instance, a) );
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new LuaError(e.getTargetException());
|
||||
} catch (Exception e) {
|
||||
return LuaValue.error("coercion error "+e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* LuaValue that represents an overloaded Java method.
|
||||
* <p>
|
||||
* On invocation, will pick the best method from the list, and invoke it.
|
||||
* <p>
|
||||
* This class is not used directly.
|
||||
* It is returned by calls to calls to {@link JavaInstance#get(LuaValue key)}
|
||||
* when an overloaded method is named.
|
||||
*/
|
||||
static class Overload extends LuaFunction {
|
||||
|
||||
final JavaMethod[] methods;
|
||||
|
||||
Overload(JavaMethod[] methods) {
|
||||
this.methods = methods;
|
||||
}
|
||||
|
||||
public LuaValue call() {
|
||||
return error("method cannot be called without instance");
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return invokeBestMethod(arg.checkuserdata(), LuaValue.NONE);
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return invokeBestMethod(arg1.checkuserdata(), arg2);
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
|
||||
return invokeBestMethod(arg1.checkuserdata(), LuaValue.varargsOf(arg2, arg3));
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs args) {
|
||||
return invokeBestMethod(args.checkuserdata(1), args.subargs(2));
|
||||
}
|
||||
|
||||
private LuaValue invokeBestMethod(Object instance, Varargs args) {
|
||||
JavaMethod best = null;
|
||||
int score = CoerceLuaToJava.SCORE_UNCOERCIBLE;
|
||||
for ( int i=0; i<methods.length; i++ ) {
|
||||
int s = methods[i].score(args);
|
||||
if ( s < score ) {
|
||||
score = s;
|
||||
best = methods[i];
|
||||
if ( score == 0 )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// any match?
|
||||
if ( best == null )
|
||||
LuaValue.error("no coercible public method");
|
||||
|
||||
// invoke it
|
||||
return best.invokeMethod(instance, args);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
116
jse/src/main/java/org/luaj/vm2/libs/jse/JseBaseLib.java
Normal file
116
jse/src/main/java/org/luaj/vm2/libs/jse/JseBaseLib.java
Normal file
@@ -0,0 +1,116 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs.jse;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.libs.BaseLib;
|
||||
import org.luaj.vm2.libs.LibFunction;
|
||||
import org.luaj.vm2.libs.ResourceFinder;
|
||||
|
||||
/**
|
||||
* Subclass of {@link BaseLib} and {@link LibFunction} which implements the lua basic library functions
|
||||
* and provides a directory based {@link ResourceFinder} as the {@link Globals#finder}.
|
||||
* <p>
|
||||
* Since JME has no file system by default, {@link BaseLib} implements
|
||||
* {@link ResourceFinder} using {@link Class#getResource(String)}.
|
||||
* The {@link JseBaseLib} implements {@link Globals#finder} by scanning the current directory
|
||||
* first, then falling back to {@link Class#getResource(String)} if that fails.
|
||||
* Otherwise, the behavior is the same as that of {@link BaseLib}.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to
|
||||
* {@link JsePlatform#standardGlobals()}
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.standardGlobals();
|
||||
* globals.get("print").call(LuaValue.valueOf("hello, world"));
|
||||
* } </pre>
|
||||
* <p>
|
||||
* For special cases where the smallest possible footprint is desired,
|
||||
* a minimal set of libraries could be loaded
|
||||
* directly via {@link Globals#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* Globals globals = new Globals();
|
||||
* globals.load(new JseBaseLib());
|
||||
* globals.get("print").call(LuaValue.valueOf("hello, world"));
|
||||
* } </pre>
|
||||
* <p>However, other libraries such as <em>PackageLib</em> are not loaded in this case.
|
||||
* <p>
|
||||
* This is a direct port of the corresponding library in C.
|
||||
* @see Globals
|
||||
* @see BaseLib
|
||||
* @see ResourceFinder
|
||||
* @see Globals#finder
|
||||
* @see LibFunction
|
||||
* @see JsePlatform
|
||||
* @see org.luaj.vm2.libs.jme.JmePlatform
|
||||
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.1">Lua 5.2 Base Lib Reference</a>
|
||||
*/
|
||||
|
||||
public class JseBaseLib extends BaseLib {
|
||||
|
||||
|
||||
/** Perform one-time initialization on the library by creating a table
|
||||
* containing the library functions, adding that table to the supplied environment,
|
||||
* adding the table to package.loaded, and returning table as the return value.
|
||||
* <P>Specifically, extend the library loading to set the default value for {@link Globals#STDIN}
|
||||
* @param modname the module name supplied if this is loaded via 'require'.
|
||||
* @param env the environment to load into, which must be a Globals instance.
|
||||
*/
|
||||
public LuaValue call(LuaValue modname, LuaValue env) {
|
||||
super.call(modname, env);
|
||||
env.checkglobals().STDIN = System.in;
|
||||
return env;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Try to open a file in the current working directory,
|
||||
* or fall back to base opener if not found.
|
||||
*
|
||||
* This implementation attempts to open the file using new File(filename).
|
||||
* It falls back to the base implementation that looks it up as a resource
|
||||
* in the class path if not found as a plain file.
|
||||
*
|
||||
* @see BaseLib
|
||||
* @see ResourceFinder
|
||||
*
|
||||
* @param filename
|
||||
* @return InputStream, or null if not found.
|
||||
*/
|
||||
public InputStream findResource(String filename) {
|
||||
File f = new File(filename);
|
||||
if ( ! f.exists() )
|
||||
return super.findResource(filename);
|
||||
try {
|
||||
return new BufferedInputStream(new FileInputStream(f));
|
||||
} catch ( IOException ioe ) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
343
jse/src/main/java/org/luaj/vm2/libs/jse/JseIoLib.java
Normal file
343
jse/src/main/java/org/luaj/vm2/libs/jse/JseIoLib.java
Normal file
@@ -0,0 +1,343 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs.jse;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.libs.IoLib;
|
||||
import org.luaj.vm2.libs.LibFunction;
|
||||
|
||||
/**
|
||||
* Subclass of {@link IoLib} and therefore {@link LibFunction} which implements the lua standard {@code io}
|
||||
* library for the JSE platform.
|
||||
* <p>
|
||||
* It uses RandomAccessFile to implement seek on files.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to
|
||||
* {@link JsePlatform#standardGlobals()}
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.standardGlobals();
|
||||
* globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
|
||||
* } </pre>
|
||||
* <p>
|
||||
* For special cases where the smallest possible footprint is desired,
|
||||
* a minimal set of libraries could be loaded
|
||||
* directly via {@link Globals#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* Globals globals = new Globals();
|
||||
* globals.load(new JseBaseLib());
|
||||
* globals.load(new PackageLib());
|
||||
* globals.load(new JseIoLib());
|
||||
* globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
|
||||
* } </pre>
|
||||
* <p>However, other libraries such as <em>MathLib</em> are not loaded in this case.
|
||||
* <p>
|
||||
* This has been implemented to match as closely as possible the behavior in the corresponding library in C.
|
||||
* @see LibFunction
|
||||
* @see JsePlatform
|
||||
* @see org.luaj.vm2.libs.jme.JmePlatform
|
||||
* @see IoLib
|
||||
* @see org.luaj.vm2.libs.jme.JmeIoLib
|
||||
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.8">Lua 5.2 I/O Lib Reference</a>
|
||||
*/
|
||||
public class JseIoLib extends IoLib {
|
||||
|
||||
protected File wrapStdin() throws IOException {
|
||||
return new StdinFile();
|
||||
}
|
||||
|
||||
protected File wrapStdout() throws IOException {
|
||||
return new StdoutFile(FTYPE_STDOUT);
|
||||
}
|
||||
|
||||
protected File wrapStderr() throws IOException {
|
||||
return new StdoutFile(FTYPE_STDERR);
|
||||
}
|
||||
|
||||
protected File openFile( String filename, boolean readMode, boolean appendMode, boolean updateMode, boolean binaryMode ) throws IOException {
|
||||
RandomAccessFile f = new RandomAccessFile(filename,readMode? "r": "rw");
|
||||
if ( appendMode ) {
|
||||
f.seek(f.length());
|
||||
} else {
|
||||
if ( ! readMode )
|
||||
f.setLength(0);
|
||||
}
|
||||
return new FileImpl( f );
|
||||
}
|
||||
|
||||
protected File openProgram(String prog, String mode) throws IOException {
|
||||
final Process p = Runtime.getRuntime().exec(prog);
|
||||
return "w".equals(mode)?
|
||||
new FileImpl( p.getOutputStream() ):
|
||||
new FileImpl( p.getInputStream() );
|
||||
}
|
||||
|
||||
protected File tmpFile() throws IOException {
|
||||
java.io.File f = java.io.File.createTempFile(".luaj","bin");
|
||||
f.deleteOnExit();
|
||||
return new FileImpl( new RandomAccessFile(f,"rw") );
|
||||
}
|
||||
|
||||
private static void notimplemented() {
|
||||
throw new LuaError("not implemented");
|
||||
}
|
||||
|
||||
|
||||
private final class FileImpl extends File {
|
||||
private final RandomAccessFile file;
|
||||
private final InputStream is;
|
||||
private final OutputStream os;
|
||||
private boolean closed = false;
|
||||
private boolean nobuffer = false;
|
||||
private FileImpl( RandomAccessFile file, InputStream is, OutputStream os ) {
|
||||
this.file = file;
|
||||
this.is = is!=null? is.markSupported()? is: new BufferedInputStream(is): null;
|
||||
this.os = os;
|
||||
}
|
||||
private FileImpl( RandomAccessFile f ) {
|
||||
this( f, null, null );
|
||||
}
|
||||
private FileImpl( InputStream i ) {
|
||||
this( null, i, null );
|
||||
}
|
||||
private FileImpl( OutputStream o ) {
|
||||
this( null, null, o );
|
||||
}
|
||||
public String tojstring() {
|
||||
return "file (" + (this.closed ? "closed" : String.valueOf(this.hashCode())) + ")";
|
||||
}
|
||||
public boolean isstdfile() {
|
||||
return file == null;
|
||||
}
|
||||
public void close() throws IOException {
|
||||
closed = true;
|
||||
if ( file != null ) {
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
public void flush() throws IOException {
|
||||
if ( os != null )
|
||||
os.flush();
|
||||
}
|
||||
public void write(LuaString s) throws IOException {
|
||||
if ( os != null )
|
||||
os.write( s.m_bytes, s.m_offset, s.m_length );
|
||||
else if ( file != null )
|
||||
file.write( s.m_bytes, s.m_offset, s.m_length );
|
||||
else
|
||||
notimplemented();
|
||||
if ( nobuffer )
|
||||
flush();
|
||||
}
|
||||
public boolean isclosed() {
|
||||
return closed;
|
||||
}
|
||||
public int seek(String option, int pos) throws IOException {
|
||||
if ( file != null ) {
|
||||
if ( "set".equals(option) ) {
|
||||
file.seek(pos);
|
||||
} else if ( "end".equals(option) ) {
|
||||
file.seek(file.length()+pos);
|
||||
} else {
|
||||
file.seek(file.getFilePointer()+pos);
|
||||
}
|
||||
return (int) file.getFilePointer();
|
||||
}
|
||||
notimplemented();
|
||||
return 0;
|
||||
}
|
||||
public void setvbuf(String mode, int size) {
|
||||
nobuffer = "no".equals(mode);
|
||||
}
|
||||
|
||||
// get length remaining to read
|
||||
public int remaining() throws IOException {
|
||||
return file!=null? (int) (file.length()-file.getFilePointer()): -1;
|
||||
}
|
||||
|
||||
// peek ahead one character
|
||||
public int peek() throws IOException {
|
||||
if ( is != null ) {
|
||||
is.mark(1);
|
||||
int c = is.read();
|
||||
is.reset();
|
||||
return c;
|
||||
} else if ( file != null ) {
|
||||
long fp = file.getFilePointer();
|
||||
int c = file.read();
|
||||
file.seek(fp);
|
||||
return c;
|
||||
}
|
||||
notimplemented();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// return char if read, -1 if eof, throw IOException on other exception
|
||||
public int read() throws IOException {
|
||||
if ( is != null )
|
||||
return is.read();
|
||||
else if ( file != null ) {
|
||||
return file.read();
|
||||
}
|
||||
notimplemented();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// return number of bytes read if positive, -1 if eof, throws IOException
|
||||
public int read(byte[] bytes, int offset, int length) throws IOException {
|
||||
if (file!=null) {
|
||||
return file.read(bytes, offset, length);
|
||||
} else if (is!=null) {
|
||||
return is.read(bytes, offset, length);
|
||||
} else {
|
||||
notimplemented();
|
||||
}
|
||||
return length;
|
||||
}
|
||||
}
|
||||
|
||||
private final class StdoutFile extends File {
|
||||
private final int file_type;
|
||||
|
||||
private StdoutFile(int file_type) {
|
||||
this.file_type = file_type;
|
||||
}
|
||||
|
||||
public String tojstring() {
|
||||
return "file ("+this.hashCode()+")";
|
||||
}
|
||||
|
||||
private final PrintStream getPrintStream() {
|
||||
return file_type == FTYPE_STDERR?
|
||||
globals.STDERR:
|
||||
globals.STDOUT;
|
||||
}
|
||||
|
||||
public void write(LuaString string) throws IOException {
|
||||
getPrintStream().write(string.m_bytes, string.m_offset, string.m_length);
|
||||
}
|
||||
|
||||
public void flush() throws IOException {
|
||||
getPrintStream().flush();
|
||||
}
|
||||
|
||||
public boolean isstdfile() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
// do not close std files.
|
||||
}
|
||||
|
||||
public boolean isclosed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public int seek(String option, int bytecount) throws IOException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setvbuf(String mode, int size) {
|
||||
}
|
||||
|
||||
public int remaining() throws IOException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int peek() throws IOException, EOFException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int read() throws IOException, EOFException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int read(byte[] bytes, int offset, int length)
|
||||
throws IOException {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private final class StdinFile extends File {
|
||||
private StdinFile() {
|
||||
}
|
||||
|
||||
public String tojstring() {
|
||||
return "file ("+this.hashCode()+")";
|
||||
}
|
||||
|
||||
public void write(LuaString string) throws IOException {
|
||||
}
|
||||
|
||||
public void flush() throws IOException {
|
||||
}
|
||||
|
||||
public boolean isstdfile() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
// do not close std files.
|
||||
}
|
||||
|
||||
public boolean isclosed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public int seek(String option, int bytecount) throws IOException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setvbuf(String mode, int size) {
|
||||
}
|
||||
|
||||
public int remaining() throws IOException {
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int peek() throws IOException, EOFException {
|
||||
globals.STDIN.mark(1);
|
||||
int c = globals.STDIN.read();
|
||||
globals.STDIN.reset();
|
||||
return c;
|
||||
}
|
||||
|
||||
public int read() throws IOException, EOFException {
|
||||
return globals.STDIN.read();
|
||||
}
|
||||
|
||||
public int read(byte[] bytes, int offset, int length)
|
||||
throws IOException {
|
||||
return globals.STDIN.read(bytes, offset, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
120
jse/src/main/java/org/luaj/vm2/libs/jse/JseMathLib.java
Normal file
120
jse/src/main/java/org/luaj/vm2/libs/jse/JseMathLib.java
Normal file
@@ -0,0 +1,120 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs.jse;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.libs.LibFunction;
|
||||
import org.luaj.vm2.libs.TwoArgFunction;
|
||||
|
||||
/**
|
||||
* Subclass of {@link LibFunction} which implements the lua standard {@code math}
|
||||
* library.
|
||||
* <p>
|
||||
* It contains all lua math functions, including those not available on the JME platform.
|
||||
* See {@link org.luaj.vm2.libs.MathLib} for the exception list.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to
|
||||
* {@link JsePlatform#standardGlobals()}
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.standardGlobals();
|
||||
* System.out.println( globals.get("math").get("sqrt").call( LuaValue.valueOf(2) ) );
|
||||
* } </pre>
|
||||
* <p>
|
||||
* For special cases where the smallest possible footprint is desired,
|
||||
* a minimal set of libraries could be loaded
|
||||
* directly via {@link Globals#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* Globals globals = new Globals();
|
||||
* globals.load(new JseBaseLib());
|
||||
* globals.load(new PackageLib());
|
||||
* globals.load(new JseMathLib());
|
||||
* System.out.println( globals.get("math").get("sqrt").call( LuaValue.valueOf(2) ) );
|
||||
* } </pre>
|
||||
* <p>However, other libraries such as <em>CoroutineLib</em> are not loaded in this case.
|
||||
* <p>
|
||||
* This has been implemented to match as closely as possible the behavior in the corresponding library in C.
|
||||
* @see LibFunction
|
||||
* @see JsePlatform
|
||||
* @see org.luaj.vm2.libs.jme.JmePlatform
|
||||
* @see JseMathLib
|
||||
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.6">Lua 5.2 Math Lib Reference</a>
|
||||
*/
|
||||
public class JseMathLib extends org.luaj.vm2.libs.MathLib {
|
||||
|
||||
public JseMathLib() {}
|
||||
|
||||
|
||||
/** Perform one-time initialization on the library by creating a table
|
||||
* containing the library functions, adding that table to the supplied environment,
|
||||
* adding the table to package.loaded, and returning table as the return value.
|
||||
* <P>Specifically, adds all library functions that can be implemented directly
|
||||
* in JSE but not JME: acos, asin, atan, atan2, cosh, exp, log, pow, sinh, and tanh.
|
||||
* @param modname the module name supplied if this is loaded via 'require'.
|
||||
* @param env the environment to load into, which must be a Globals instance.
|
||||
*/
|
||||
public LuaValue call(LuaValue modname, LuaValue env) {
|
||||
super.call(modname, env);
|
||||
LuaValue math = env.get("math");
|
||||
math.set("acos", new acos());
|
||||
math.set("asin", new asin());
|
||||
LuaValue atan = new atan2();
|
||||
math.set("atan", atan);
|
||||
math.set("atan2", atan);
|
||||
math.set("cosh", new cosh());
|
||||
math.set("exp", new exp());
|
||||
math.set("log", new log());
|
||||
math.set("pow", new pow());
|
||||
math.set("sinh", new sinh());
|
||||
math.set("tanh", new tanh());
|
||||
return math;
|
||||
}
|
||||
|
||||
static final class acos extends UnaryOp { protected double call(double d) { return Math.acos(d); } }
|
||||
static final class asin extends UnaryOp { protected double call(double d) { return Math.asin(d); } }
|
||||
static final class atan2 extends TwoArgFunction {
|
||||
public LuaValue call(LuaValue x, LuaValue y) {
|
||||
return valueOf(Math.atan2(x.checkdouble(), y.optdouble(1)));
|
||||
}
|
||||
}
|
||||
static final class cosh extends UnaryOp { protected double call(double d) { return Math.cosh(d); } }
|
||||
static final class exp extends UnaryOp { protected double call(double d) { return Math.exp(d); } }
|
||||
static final class log extends TwoArgFunction {
|
||||
public LuaValue call(LuaValue x, LuaValue base) {
|
||||
double nat = Math.log(x.checkdouble());
|
||||
double b = base.optdouble(Math.E);
|
||||
if (b != Math.E) nat /= Math.log(b);
|
||||
return valueOf(nat);
|
||||
}
|
||||
}
|
||||
static final class pow extends BinaryOp { protected double call(double x, double y) { return Math.pow(x, y); } }
|
||||
static final class sinh extends UnaryOp { protected double call(double d) { return Math.sinh(d); } }
|
||||
static final class tanh extends UnaryOp { protected double call(double d) { return Math.tanh(d); } }
|
||||
|
||||
/** Faster, better version of pow() used by arithmetic operator ^ */
|
||||
public double dpow_lib(double a, double b) {
|
||||
return Math.pow(a, b);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
135
jse/src/main/java/org/luaj/vm2/libs/jse/JseOsLib.java
Normal file
135
jse/src/main/java/org/luaj/vm2/libs/jse/JseOsLib.java
Normal file
@@ -0,0 +1,135 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs.jse;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.libs.LibFunction;
|
||||
import org.luaj.vm2.libs.OsLib;
|
||||
|
||||
/**
|
||||
* Subclass of {@link LibFunction} which implements the standard lua {@code os} library.
|
||||
* <p>
|
||||
* This contains more complete implementations of the following functions
|
||||
* using features that are specific to JSE:
|
||||
* <ul>
|
||||
* <li>{@code execute()}</li>
|
||||
* <li>{@code remove()}</li>
|
||||
* <li>{@code rename()}</li>
|
||||
* <li>{@code tmpname()}</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Because the nature of the {@code os} library is to encapsulate
|
||||
* os-specific features, the behavior of these functions varies considerably
|
||||
* from their counterparts in the C platform.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to
|
||||
* {@link JsePlatform#standardGlobals()}
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.standardGlobals();
|
||||
* System.out.println( globals.get("os").get("time").call() );
|
||||
* } </pre>
|
||||
* <p>
|
||||
* For special cases where the smallest possible footprint is desired,
|
||||
* a minimal set of libraries could be loaded
|
||||
* directly via {@link Globals#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* Globals globals = new Globals();
|
||||
* globals.load(new JseBaseLib());
|
||||
* globals.load(new PackageLib());
|
||||
* globals.load(new JseOsLib());
|
||||
* System.out.println( globals.get("os").get("time").call() );
|
||||
* } </pre>
|
||||
* <p>However, other libraries such as <em>MathLib</em> are not loaded in this case.
|
||||
* <p>
|
||||
* @see LibFunction
|
||||
* @see OsLib
|
||||
* @see JsePlatform
|
||||
* @see org.luaj.vm2.libs.jme.JmePlatform
|
||||
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.9">Lua 5.2 OS Lib Reference</a>
|
||||
*/
|
||||
public class JseOsLib extends OsLib {
|
||||
|
||||
/** return code indicating the execute() threw an I/O exception */
|
||||
public static final int EXEC_IOEXCEPTION = 1;
|
||||
|
||||
/** return code indicating the execute() was interrupted */
|
||||
public static final int EXEC_INTERRUPTED = -2;
|
||||
|
||||
/** return code indicating the execute() threw an unknown exception */
|
||||
public static final int EXEC_ERROR = -3;
|
||||
|
||||
/** public constructor */
|
||||
public JseOsLib() {
|
||||
}
|
||||
|
||||
protected String getenv(String varname) {
|
||||
String s = System.getenv(varname);
|
||||
return s != null? s : System.getProperty(varname);
|
||||
}
|
||||
|
||||
protected Varargs execute(String command) {
|
||||
int exitValue;
|
||||
try {
|
||||
exitValue = new JseProcess(command, null, globals.STDOUT, globals.STDERR).waitFor();
|
||||
} catch (IOException ioe) {
|
||||
exitValue = EXEC_IOEXCEPTION;
|
||||
} catch (InterruptedException e) {
|
||||
exitValue = EXEC_INTERRUPTED;
|
||||
} catch (Throwable t) {
|
||||
exitValue = EXEC_ERROR;
|
||||
}
|
||||
if (exitValue == 0)
|
||||
return varargsOf(TRUE, valueOf("exit"), ZERO);
|
||||
return varargsOf(NIL, valueOf("signal"), valueOf(exitValue));
|
||||
}
|
||||
|
||||
protected void remove(String filename) throws IOException {
|
||||
File f = new File(filename);
|
||||
if ( ! f.exists() )
|
||||
throw new IOException("No such file or directory");
|
||||
if ( ! f.delete() )
|
||||
throw new IOException("Failed to delete");
|
||||
}
|
||||
|
||||
protected void rename(String oldname, String newname) throws IOException {
|
||||
File f = new File(oldname);
|
||||
if ( ! f.exists() )
|
||||
throw new IOException("No such file or directory");
|
||||
if ( ! f.renameTo(new File(newname)) )
|
||||
throw new IOException("Failed to rename");
|
||||
}
|
||||
|
||||
protected String tmpname() {
|
||||
try {
|
||||
File f = File.createTempFile(TMP_PREFIX ,TMP_SUFFIX);
|
||||
return f.getAbsolutePath();
|
||||
} catch ( IOException ioe ) {
|
||||
return super.tmpname();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
143
jse/src/main/java/org/luaj/vm2/libs/jse/JsePlatform.java
Normal file
143
jse/src/main/java/org/luaj/vm2/libs/jse/JsePlatform.java
Normal file
@@ -0,0 +1,143 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs.jse;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LoadState;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
import org.luaj.vm2.libs.Bit32Lib;
|
||||
import org.luaj.vm2.libs.CoroutineLib;
|
||||
import org.luaj.vm2.libs.DebugLib;
|
||||
import org.luaj.vm2.libs.PackageLib;
|
||||
import org.luaj.vm2.libs.ResourceFinder;
|
||||
import org.luaj.vm2.libs.StringLib;
|
||||
import org.luaj.vm2.libs.TableLib;
|
||||
|
||||
/** The {@link JsePlatform} class is a convenience class to standardize
|
||||
* how globals tables are initialized for the JSE platform.
|
||||
* <p>
|
||||
* It is used to allocate either a set of standard globals using
|
||||
* {@link #standardGlobals()} or debug globals using {@link #debugGlobals()}
|
||||
* <p>
|
||||
* A simple example of initializing globals and using them from Java is:
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.standardGlobals();
|
||||
* globals.get("print").call(LuaValue.valueOf("hello, world"));
|
||||
* } </pre>
|
||||
* <p>
|
||||
* Once globals are created, a simple way to load and run a script is:
|
||||
* <pre> {@code
|
||||
* globals.load( new FileInputStream("main.lua"), "main.lua" ).call();
|
||||
* } </pre>
|
||||
* <p>
|
||||
* although {@code require} could also be used:
|
||||
* <pre> {@code
|
||||
* globals.get("require").call(LuaValue.valueOf("main"));
|
||||
* } </pre>
|
||||
* For this to succeed, the file "main.lua" must be in the current directory or a resource.
|
||||
* See {@link JseBaseLib} for details on finding scripts using {@link ResourceFinder}.
|
||||
* <p>
|
||||
* The standard globals will contain all standard libraries plus {@code luajava}:
|
||||
* <ul>
|
||||
* <li>{@link Globals}</li>
|
||||
* <li>{@link JseBaseLib}</li>
|
||||
* <li>{@link PackageLib}</li>
|
||||
* <li>{@link Bit32Lib}</li>
|
||||
* <li>{@link TableLib}</li>
|
||||
* <li>{@link StringLib}</li>
|
||||
* <li>{@link CoroutineLib}</li>
|
||||
* <li>{@link JseMathLib}</li>
|
||||
* <li>{@link JseIoLib}</li>
|
||||
* <li>{@link JseOsLib}</li>
|
||||
* <li>{@link LuajavaLib}</li>
|
||||
* </ul>
|
||||
* In addition, the {@link LuaC} compiler is installed so lua files may be loaded in their source form.
|
||||
* <p>
|
||||
* The debug globals are simply the standard globals plus the {@code debug} library {@link DebugLib}.
|
||||
* <p>
|
||||
* The class ensures that initialization is done in the correct order.
|
||||
*
|
||||
* @see Globals
|
||||
* @see org.luaj.vm2.libs.jme.JmePlatform
|
||||
*/
|
||||
public class JsePlatform {
|
||||
|
||||
/**
|
||||
* Create a standard set of globals for JSE including all the libraries.
|
||||
*
|
||||
* @return Table of globals initialized with the standard JSE libraries
|
||||
* @see #debugGlobals()
|
||||
* @see JsePlatform
|
||||
* @see org.luaj.vm2.libs.jme.JmePlatform
|
||||
*/
|
||||
public static Globals standardGlobals() {
|
||||
Globals globals = new Globals();
|
||||
globals.load(new JseBaseLib());
|
||||
globals.load(new PackageLib());
|
||||
globals.load(new Bit32Lib());
|
||||
globals.load(new TableLib());
|
||||
globals.load(new JseStringLib());
|
||||
globals.load(new CoroutineLib());
|
||||
globals.load(new JseMathLib());
|
||||
globals.load(new JseIoLib());
|
||||
globals.load(new JseOsLib());
|
||||
globals.load(new LuajavaLib());
|
||||
LoadState.install(globals);
|
||||
LuaC.install(globals);
|
||||
return globals;
|
||||
}
|
||||
|
||||
/** Create standard globals including the {@link DebugLib} library.
|
||||
*
|
||||
* @return Table of globals initialized with the standard JSE and debug libraries
|
||||
* @see #standardGlobals()
|
||||
* @see JsePlatform
|
||||
* @see org.luaj.vm2.libs.jme.JmePlatform
|
||||
* @see DebugLib
|
||||
*/
|
||||
public static Globals debugGlobals() {
|
||||
Globals globals = standardGlobals();
|
||||
globals.load(new DebugLib());
|
||||
return globals;
|
||||
}
|
||||
|
||||
|
||||
/** Simple wrapper for invoking a lua function with command line arguments.
|
||||
* The supplied function is first given a new Globals object as its environment
|
||||
* then the program is run with arguments.
|
||||
* @return {@link Varargs} containing any values returned by mainChunk.
|
||||
*/
|
||||
public static Varargs luaMain(LuaValue mainChunk, String[] args) {
|
||||
Globals g = standardGlobals();
|
||||
int n = args.length;
|
||||
LuaValue[] vargs = new LuaValue[args.length];
|
||||
for (int i = 0; i < n; ++i)
|
||||
vargs[i] = LuaValue.valueOf(args[i]);
|
||||
LuaValue arg = LuaValue.listOf(vargs);
|
||||
arg.set("n", n);
|
||||
g.set("arg", arg);
|
||||
mainChunk.initupvalue1(g);
|
||||
return mainChunk.invoke(LuaValue.varargsOf(vargs));
|
||||
}
|
||||
}
|
||||
132
jse/src/main/java/org/luaj/vm2/libs/jse/JseProcess.java
Normal file
132
jse/src/main/java/org/luaj/vm2/libs/jse/JseProcess.java
Normal file
@@ -0,0 +1,132 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2012 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs.jse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/** Analog of Process that pipes input and output to client-specified streams.
|
||||
*/
|
||||
public class JseProcess {
|
||||
|
||||
final Process process;
|
||||
final Thread input,output,error;
|
||||
|
||||
/** Construct a process around a command, with specified streams to redirect input and output to.
|
||||
*
|
||||
* @param cmd The command to execute, including arguments, if any
|
||||
* @param stdin Optional InputStream to read from as process input, or null if input is not needed.
|
||||
* @param stdout Optional OutputStream to copy process output to, or null if output is ignored.
|
||||
* @param stderr Optinoal OutputStream to copy process stderr output to, or null if output is ignored.
|
||||
* @throws IOException If the system process could not be created.
|
||||
* @see Process
|
||||
*/
|
||||
public JseProcess(String[] cmd, InputStream stdin, OutputStream stdout, OutputStream stderr) throws IOException {
|
||||
this(Runtime.getRuntime().exec(cmd), stdin, stdout, stderr);
|
||||
}
|
||||
|
||||
/** Construct a process around a command, with specified streams to redirect input and output to.
|
||||
*
|
||||
* @param cmd The command to execute, including arguments, if any
|
||||
* @param stdin Optional InputStream to read from as process input, or null if input is not needed.
|
||||
* @param stdout Optional OutputStream to copy process output to, or null if output is ignored.
|
||||
* @param stderr Optinoal OutputStream to copy process stderr output to, or null if output is ignored.
|
||||
* @throws IOException If the system process could not be created.
|
||||
* @see Process
|
||||
*/
|
||||
public JseProcess(String cmd, InputStream stdin, OutputStream stdout, OutputStream stderr) throws IOException {
|
||||
this(Runtime.getRuntime().exec(cmd), stdin, stdout, stderr);
|
||||
}
|
||||
|
||||
private JseProcess(Process process, InputStream stdin, OutputStream stdout, OutputStream stderr) {
|
||||
this.process = process;
|
||||
input = stdin == null? null: copyBytes(stdin, process.getOutputStream(), null, process.getOutputStream());
|
||||
output = stdout == null? null: copyBytes(process.getInputStream(), stdout, process.getInputStream(), null);
|
||||
error = stderr == null? null: copyBytes(process.getErrorStream(), stderr, process.getErrorStream(), null);
|
||||
}
|
||||
|
||||
/** Get the exit value of the process. */
|
||||
public int exitValue() {
|
||||
return process.exitValue();
|
||||
}
|
||||
|
||||
/** Wait for the process to complete, and all pending output to finish.
|
||||
* @return The exit status.
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public int waitFor() throws InterruptedException {
|
||||
int r = process.waitFor();
|
||||
if (input != null)
|
||||
input.join();
|
||||
if (output != null)
|
||||
output.join();
|
||||
if (error != null)
|
||||
error.join();
|
||||
process.destroy();
|
||||
return r;
|
||||
}
|
||||
|
||||
/** Create a thread to copy bytes from input to output. */
|
||||
private Thread copyBytes(final InputStream input,
|
||||
final OutputStream output, final InputStream ownedInput,
|
||||
final OutputStream ownedOutput) {
|
||||
Thread t = (new CopyThread(output, ownedOutput, ownedInput, input));
|
||||
t.start();
|
||||
return t;
|
||||
}
|
||||
|
||||
private static final class CopyThread extends Thread {
|
||||
private final OutputStream output;
|
||||
private final OutputStream ownedOutput;
|
||||
private final InputStream ownedInput;
|
||||
private final InputStream input;
|
||||
|
||||
private CopyThread(OutputStream output, OutputStream ownedOutput,
|
||||
InputStream ownedInput, InputStream input) {
|
||||
this.output = output;
|
||||
this.ownedOutput = ownedOutput;
|
||||
this.ownedInput = ownedInput;
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
byte[] buf = new byte[1024];
|
||||
int r;
|
||||
try {
|
||||
while ((r = input.read(buf)) >= 0) {
|
||||
output.write(buf, 0, r);
|
||||
}
|
||||
} finally {
|
||||
if (ownedInput != null)
|
||||
ownedInput.close();
|
||||
if (ownedOutput != null)
|
||||
ownedOutput.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
39
jse/src/main/java/org/luaj/vm2/libs/jse/JseStringLib.java
Normal file
39
jse/src/main/java/org/luaj/vm2/libs/jse/JseStringLib.java
Normal file
@@ -0,0 +1,39 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs.jse;
|
||||
|
||||
public class JseStringLib extends org.luaj.vm2.libs.StringLib {
|
||||
|
||||
/** public constructor */
|
||||
public JseStringLib() {
|
||||
}
|
||||
|
||||
protected String format(String src, double x) {
|
||||
String out;
|
||||
try {
|
||||
out = String.format(src, new Object[] {Double.valueOf(x)});
|
||||
} catch (Throwable e) {
|
||||
out = super.format(src, x);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
214
jse/src/main/java/org/luaj/vm2/libs/jse/LuajavaLib.java
Normal file
214
jse/src/main/java/org/luaj/vm2/libs/jse/LuajavaLib.java
Normal file
@@ -0,0 +1,214 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.libs.jse;
|
||||
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
import org.luaj.vm2.libs.LibFunction;
|
||||
import org.luaj.vm2.libs.VarArgFunction;
|
||||
|
||||
/**
|
||||
* Subclass of {@link LibFunction} which implements the features of the luajava package.
|
||||
* <p>
|
||||
* Luajava is an approach to mixing lua and java using simple functions that bind
|
||||
* java classes and methods to lua dynamically. The API is documented on the
|
||||
* <a href="http://www.keplerproject.org/luajava/">luajava</a> documentation pages.
|
||||
*
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to
|
||||
* {@link JsePlatform#standardGlobals()}
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.standardGlobals();
|
||||
* System.out.println( globals.get("luajava").get("bindClass").call( LuaValue.valueOf("java.lang.System") ).invokeMethod("currentTimeMillis") );
|
||||
* } </pre>
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link Globals#load} using code such as:
|
||||
* <pre> {@code
|
||||
* Globals globals = new Globals();
|
||||
* globals.load(new JseBaseLib());
|
||||
* globals.load(new PackageLib());
|
||||
* globals.load(new LuajavaLib());
|
||||
* globals.load(
|
||||
* "sys = luajava.bindClass('java.lang.System')\n"+
|
||||
* "print ( sys:currentTimeMillis() )\n", "main.lua" ).call();
|
||||
* } </pre>
|
||||
* <p>
|
||||
*
|
||||
* The {@code luajava} library is available
|
||||
* on all JSE platforms via the call to {@link JsePlatform#standardGlobals()}
|
||||
* and the luajava api's are simply invoked from lua.
|
||||
* Because it makes extensive use of Java's reflection API, it is not available
|
||||
* on JME, but can be used in Android applications.
|
||||
* <p>
|
||||
* This has been implemented to match as closely as possible the behavior in the corresponding library in C.
|
||||
*
|
||||
* @see LibFunction
|
||||
* @see JsePlatform
|
||||
* @see org.luaj.vm2.libs.jme.JmePlatform
|
||||
* @see LuaC
|
||||
* @see CoerceJavaToLua
|
||||
* @see CoerceLuaToJava
|
||||
* @see <a href="http://www.keplerproject.org/luajava/manual.html#luareference">http://www.keplerproject.org/luajava/manual.html#luareference</a>
|
||||
*/
|
||||
public class LuajavaLib extends VarArgFunction {
|
||||
|
||||
static final int INIT = 0;
|
||||
static final int BINDCLASS = 1;
|
||||
static final int NEWINSTANCE = 2;
|
||||
static final int NEW = 3;
|
||||
static final int CREATEPROXY = 4;
|
||||
static final int LOADLIB = 5;
|
||||
|
||||
static final String[] NAMES = {
|
||||
"bindClass",
|
||||
"newInstance",
|
||||
"new",
|
||||
"createProxy",
|
||||
"loadLib",
|
||||
};
|
||||
|
||||
static final int METHOD_MODIFIERS_VARARGS = 0x80;
|
||||
|
||||
public LuajavaLib() {
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs args) {
|
||||
try {
|
||||
switch ( opcode ) {
|
||||
case INIT: {
|
||||
// LuaValue modname = args.arg1();
|
||||
LuaValue env = args.arg(2);
|
||||
LuaTable t = new LuaTable();
|
||||
bind( t, this.getClass(), NAMES, BINDCLASS );
|
||||
env.set("luajava", t);
|
||||
if (!env.get("package").isnil()) env.get("package").get("loaded").set("luajava", t);
|
||||
return t;
|
||||
}
|
||||
case BINDCLASS: {
|
||||
final Class clazz = classForName(args.checkjstring(1));
|
||||
return JavaClass.forClass(clazz);
|
||||
}
|
||||
case NEWINSTANCE:
|
||||
case NEW: {
|
||||
// get constructor
|
||||
final LuaValue c = args.checkvalue(1);
|
||||
final Class clazz = (opcode==NEWINSTANCE? classForName(c.tojstring()): (Class) c.checkuserdata(Class.class));
|
||||
final Varargs consargs = args.subargs(2);
|
||||
return JavaClass.forClass(clazz).getConstructor().invoke(consargs);
|
||||
}
|
||||
|
||||
case CREATEPROXY: {
|
||||
final int niface = args.narg()-1;
|
||||
if ( niface <= 0 )
|
||||
throw new LuaError("no interfaces");
|
||||
final LuaValue lobj = args.checktable(niface+1);
|
||||
|
||||
// get the interfaces
|
||||
final Class[] ifaces = new Class[niface];
|
||||
for ( int i=0; i<niface; i++ )
|
||||
ifaces[i] = classForName(args.checkjstring(i+1));
|
||||
|
||||
// create the invocation handler
|
||||
InvocationHandler handler = new ProxyInvocationHandler(lobj);
|
||||
|
||||
// create the proxy object
|
||||
Object proxy = Proxy.newProxyInstance(getClass().getClassLoader(), ifaces, handler);
|
||||
|
||||
// return the proxy
|
||||
return LuaValue.userdataOf( proxy );
|
||||
}
|
||||
case LOADLIB: {
|
||||
// get constructor
|
||||
String classname = args.checkjstring(1);
|
||||
String methodname = args.checkjstring(2);
|
||||
Class clazz = classForName(classname);
|
||||
Method method = clazz.getMethod(methodname, new Class[] {});
|
||||
Object result = method.invoke(clazz, new Object[] {});
|
||||
if ( result instanceof LuaValue ) {
|
||||
return (LuaValue) result;
|
||||
} else {
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw new LuaError("not yet supported: "+this);
|
||||
}
|
||||
} catch (LuaError e) {
|
||||
throw e;
|
||||
} catch (InvocationTargetException ite) {
|
||||
throw new LuaError(ite.getTargetException());
|
||||
} catch (Exception e) {
|
||||
throw new LuaError(e);
|
||||
}
|
||||
}
|
||||
|
||||
// load classes using app loader to allow luaj to be used as an extension
|
||||
protected Class classForName(String name) throws ClassNotFoundException {
|
||||
return Class.forName(name, true, ClassLoader.getSystemClassLoader());
|
||||
}
|
||||
|
||||
private static final class ProxyInvocationHandler implements InvocationHandler {
|
||||
private final LuaValue lobj;
|
||||
|
||||
private ProxyInvocationHandler(LuaValue lobj) {
|
||||
this.lobj = lobj;
|
||||
}
|
||||
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
String name = method.getName();
|
||||
LuaValue func = lobj.get(name);
|
||||
if ( func.isnil() )
|
||||
return null;
|
||||
boolean isvarargs = ((method.getModifiers() & METHOD_MODIFIERS_VARARGS) != 0);
|
||||
int n = args!=null? args.length: 0;
|
||||
LuaValue[] v;
|
||||
if ( isvarargs ) {
|
||||
Object o = args[--n];
|
||||
int m = Array.getLength( o );
|
||||
v = new LuaValue[n+m];
|
||||
for ( int i=0; i<n; i++ )
|
||||
v[i] = CoerceJavaToLua.coerce(args[i]);
|
||||
for ( int i=0; i<m; i++ )
|
||||
v[i+n] = CoerceJavaToLua.coerce(Array.get(o,i));
|
||||
} else {
|
||||
v = new LuaValue[n];
|
||||
for ( int i=0; i<n; i++ )
|
||||
v[i] = CoerceJavaToLua.coerce(args[i]);
|
||||
}
|
||||
LuaValue result = func.invoke(v).arg1();
|
||||
return CoerceLuaToJava.coerce(result, method.getReturnType());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
21
jse/src/test/java/org/luaj/vm2/libs/jse/JsePlatformTest.java
Normal file
21
jse/src/test/java/org/luaj/vm2/libs/jse/JsePlatformTest.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package org.luaj.vm2.libs.jse;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
|
||||
public class JsePlatformTest extends TestCase {
|
||||
public void testLuaMainPassesArguments() {
|
||||
Globals globals = JsePlatform.standardGlobals();
|
||||
LuaValue chunk = globals.load("return #arg, arg.n, arg[2], arg[1]");
|
||||
Varargs results = JsePlatform.luaMain(chunk, new String[] { "aaa", "bbb" });
|
||||
assertEquals(results.narg(), 4);
|
||||
assertEquals(results.arg(1), LuaValue.valueOf(2));
|
||||
assertEquals(results.arg(2), LuaValue.valueOf(2));
|
||||
assertEquals(results.arg(3), LuaValue.valueOf("bbb"));
|
||||
assertEquals(results.arg(4), LuaValue.valueOf("aaa"));
|
||||
}
|
||||
}
|
||||
446
jse/src/test/java/org/luaj/vm2/libs/jse/LuaJavaCoercionTest.java
Normal file
446
jse/src/test/java/org/luaj/vm2/libs/jse/LuaJavaCoercionTest.java
Normal file
@@ -0,0 +1,446 @@
|
||||
package org.luaj.vm2.libs.jse;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaInteger;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.libs.jse2.JavaArray;
|
||||
|
||||
public class LuaJavaCoercionTest extends TestCase {
|
||||
|
||||
private static LuaValue globals;
|
||||
private static LuaValue ZERO = LuaValue.ZERO;
|
||||
private static LuaValue ONE = LuaValue.ONE;
|
||||
private static LuaValue TWO = LuaValue.valueOf(2);
|
||||
private static LuaValue THREE = LuaValue.valueOf(3);
|
||||
private static LuaString LENGTH = LuaString.valueOf("length");
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
globals = JsePlatform.standardGlobals();
|
||||
}
|
||||
|
||||
public void testJavaIntToLuaInt() {
|
||||
Integer i = Integer.valueOf(777);
|
||||
LuaValue v = CoerceJavaToLua.coerce(i);
|
||||
assertEquals( LuaInteger.class, v.getClass() );
|
||||
assertEquals( 777, v.toint() );
|
||||
}
|
||||
|
||||
public void testLuaIntToJavaInt() {
|
||||
LuaInteger i = LuaInteger.valueOf(777);
|
||||
Object o = CoerceLuaToJava.coerce(i, int.class);
|
||||
assertEquals( Integer.class, o.getClass() );
|
||||
assertEquals( 777, ((Number)o).intValue() );
|
||||
o = CoerceLuaToJava.coerce(i, Integer.class);
|
||||
assertEquals( Integer.class, o.getClass() );
|
||||
assertEquals( new Integer(777), o );
|
||||
}
|
||||
|
||||
public void testJavaStringToLuaString() {
|
||||
String s = new String("777");
|
||||
LuaValue v = CoerceJavaToLua.coerce(s);
|
||||
assertEquals( LuaString.class, v.getClass() );
|
||||
assertEquals( "777", v.toString() );
|
||||
}
|
||||
|
||||
public void testLuaStringToJavaString() {
|
||||
LuaString s = LuaValue.valueOf("777");
|
||||
Object o = CoerceLuaToJava.coerce(s, String.class);
|
||||
assertEquals( String.class, o.getClass() );
|
||||
assertEquals( "777", o );
|
||||
}
|
||||
|
||||
public void testJavaClassToLuaUserdata() {
|
||||
LuaValue va = CoerceJavaToLua.coerce(ClassA.class);
|
||||
LuaValue va1 = CoerceJavaToLua.coerce(ClassA.class);
|
||||
LuaValue vb = CoerceJavaToLua.coerce(ClassB.class);
|
||||
assertSame(va, va1);
|
||||
assertNotSame(va, vb);
|
||||
LuaValue vi = CoerceJavaToLua.coerce(new ClassA());
|
||||
assertNotSame(va, vi);
|
||||
assertTrue(vi.isuserdata());
|
||||
assertTrue(vi.isuserdata(ClassA.class));
|
||||
assertFalse(vi.isuserdata(ClassB.class));
|
||||
LuaValue vj = CoerceJavaToLua.coerce(new ClassB());
|
||||
assertNotSame(vb, vj);
|
||||
assertTrue(vj.isuserdata());
|
||||
assertFalse(vj.isuserdata(ClassA.class));
|
||||
assertTrue(vj.isuserdata(ClassB.class));
|
||||
}
|
||||
|
||||
static class ClassA {
|
||||
}
|
||||
|
||||
static class ClassB {
|
||||
}
|
||||
|
||||
public void testJavaIntArrayToLuaTable() {
|
||||
int[] i = { 222, 333 };
|
||||
LuaValue v = CoerceJavaToLua.coerce(i);
|
||||
assertEquals( JavaArray.class, v.getClass() );
|
||||
assertEquals( LuaInteger.valueOf(222), v.get(ONE) );
|
||||
assertEquals( LuaInteger.valueOf(333), v.get(TWO) );
|
||||
assertEquals( TWO, v.get(LENGTH));
|
||||
assertEquals( LuaValue.NIL, v.get(THREE) );
|
||||
assertEquals( LuaValue.NIL, v.get(ZERO) );
|
||||
v.set(ONE, LuaInteger.valueOf(444));
|
||||
v.set(TWO, LuaInteger.valueOf(555));
|
||||
assertEquals( 444, i[0] );
|
||||
assertEquals( 555, i[1] );
|
||||
assertEquals( LuaInteger.valueOf(444), v.get(ONE) );
|
||||
assertEquals( LuaInteger.valueOf(555), v.get(TWO) );
|
||||
try {
|
||||
v.set(ZERO, LuaInteger.valueOf(777));
|
||||
fail( "array bound exception not thrown" );
|
||||
} catch ( LuaError lee ) {
|
||||
// expected
|
||||
}
|
||||
try {
|
||||
v.set(THREE, LuaInteger.valueOf(777));
|
||||
fail( "array bound exception not thrown" );
|
||||
} catch ( LuaError lee ) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
public void testLuaTableToJavaIntArray() {
|
||||
LuaTable t = new LuaTable();
|
||||
t.set(1, LuaInteger.valueOf(222) );
|
||||
t.set(2, LuaInteger.valueOf(333) );
|
||||
int[] i = null;
|
||||
Object o = CoerceLuaToJava.coerce(t, int[].class);
|
||||
assertEquals( int[].class, o.getClass() );
|
||||
i = (int[]) o;
|
||||
assertEquals( 2, i.length );
|
||||
assertEquals( 222, i[0] );
|
||||
assertEquals( 333, i[1] );
|
||||
}
|
||||
|
||||
public void testIntArrayScoringTables() {
|
||||
int a = 5;
|
||||
LuaValue la = LuaInteger.valueOf(a);
|
||||
LuaTable tb = new LuaTable();
|
||||
tb.set( 1, la );
|
||||
LuaTable tc = new LuaTable();
|
||||
tc.set( 1, tb );
|
||||
|
||||
int saa = CoerceLuaToJava.getCoercion(int.class).score(la);
|
||||
int sab = CoerceLuaToJava.getCoercion(int[].class).score(la);
|
||||
int sac = CoerceLuaToJava.getCoercion(int[][].class).score(la);
|
||||
assertTrue( saa < sab );
|
||||
assertTrue( saa < sac );
|
||||
int sba = CoerceLuaToJava.getCoercion(int.class).score(tb);
|
||||
int sbb = CoerceLuaToJava.getCoercion(int[].class).score(tb);
|
||||
int sbc = CoerceLuaToJava.getCoercion(int[][].class).score(tb);
|
||||
assertTrue( sbb < sba );
|
||||
assertTrue( sbb < sbc );
|
||||
int sca = CoerceLuaToJava.getCoercion(int.class).score(tc);
|
||||
int scb = CoerceLuaToJava.getCoercion(int[].class).score(tc);
|
||||
int scc = CoerceLuaToJava.getCoercion(int[][].class).score(tc);
|
||||
assertTrue( scc < sca );
|
||||
assertTrue( scc < scb );
|
||||
}
|
||||
|
||||
public void testIntArrayScoringUserdata() {
|
||||
int a = 5;
|
||||
int[] b = { 44, 66 };
|
||||
int[][] c = { { 11, 22 }, { 33, 44 } };
|
||||
LuaValue va = CoerceJavaToLua.coerce(a);
|
||||
LuaValue vb = CoerceJavaToLua.coerce(b);
|
||||
LuaValue vc = CoerceJavaToLua.coerce(c);
|
||||
|
||||
int vaa = CoerceLuaToJava.getCoercion(int.class).score(va);
|
||||
int vab = CoerceLuaToJava.getCoercion(int[].class).score(va);
|
||||
int vac = CoerceLuaToJava.getCoercion(int[][].class).score(va);
|
||||
assertTrue( vaa < vab );
|
||||
assertTrue( vaa < vac );
|
||||
int vba = CoerceLuaToJava.getCoercion(int.class).score(vb);
|
||||
int vbb = CoerceLuaToJava.getCoercion(int[].class).score(vb);
|
||||
int vbc = CoerceLuaToJava.getCoercion(int[][].class).score(vb);
|
||||
assertTrue( vbb < vba );
|
||||
assertTrue( vbb < vbc );
|
||||
int vca = CoerceLuaToJava.getCoercion(int.class).score(vc);
|
||||
int vcb = CoerceLuaToJava.getCoercion(int[].class).score(vc);
|
||||
int vcc = CoerceLuaToJava.getCoercion(int[][].class).score(vc);
|
||||
assertTrue( vcc < vca );
|
||||
assertTrue( vcc < vcb );
|
||||
}
|
||||
|
||||
public static class SampleClass {
|
||||
public String sample() { return "void-args"; }
|
||||
public String sample(int a) { return "int-args "+a; }
|
||||
public String sample(int[] a) { return "int-array-args "+a[0]+","+a[1]; }
|
||||
public String sample(int[][] a) { return "int-array-array-args "+a[0][0]+","+a[0][1]+","+a[1][0]+","+a[1][1]; }
|
||||
}
|
||||
|
||||
public void testMatchVoidArgs() {
|
||||
LuaValue v = CoerceJavaToLua.coerce(new SampleClass());
|
||||
LuaValue result = v.method("sample");
|
||||
assertEquals( "void-args", result.toString() );
|
||||
}
|
||||
|
||||
public void testMatchIntArgs() {
|
||||
LuaValue v = CoerceJavaToLua.coerce(new SampleClass());
|
||||
LuaValue arg = CoerceJavaToLua.coerce(new Integer(123));
|
||||
LuaValue result = v.method("sample",arg);
|
||||
assertEquals( "int-args 123", result.toString() );
|
||||
}
|
||||
|
||||
public void testMatchIntArrayArgs() {
|
||||
LuaValue v = CoerceJavaToLua.coerce(new SampleClass());
|
||||
LuaValue arg = CoerceJavaToLua.coerce(new int[]{345,678});
|
||||
LuaValue result = v.method("sample",arg);
|
||||
assertEquals( "int-array-args 345,678", result.toString() );
|
||||
}
|
||||
|
||||
public void testMatchIntArrayArrayArgs() {
|
||||
LuaValue v = CoerceJavaToLua.coerce(new SampleClass());
|
||||
LuaValue arg = CoerceJavaToLua.coerce(new int[][]{{22,33},{44,55}});
|
||||
LuaValue result = v.method("sample",arg);
|
||||
assertEquals( "int-array-array-args 22,33,44,55", result.toString() );
|
||||
}
|
||||
|
||||
public static final class SomeException extends RuntimeException {
|
||||
public SomeException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class SomeClass {
|
||||
public static void someMethod() {
|
||||
throw new SomeException( "this is some message" );
|
||||
}
|
||||
}
|
||||
|
||||
public void testExceptionMessage() {
|
||||
String script = "local c = luajava.bindClass( \""+SomeClass.class.getName()+"\" )\n" +
|
||||
"return pcall( c.someMethod, c )";
|
||||
Varargs vresult = globals.get("load").call(LuaValue.valueOf(script)).invoke(LuaValue.NONE);
|
||||
LuaValue status = vresult.arg1();
|
||||
LuaValue message = vresult.arg(2);
|
||||
assertEquals( LuaValue.FALSE, status );
|
||||
int index = message.toString().indexOf( "this is some message" );
|
||||
assertTrue( "bad message: "+message, index>=0 );
|
||||
}
|
||||
|
||||
public void testLuaErrorCause() {
|
||||
String script = "luajava.bindClass( \""+SomeClass.class.getName()+"\"):someMethod()";
|
||||
LuaValue chunk = globals.get("load").call(LuaValue.valueOf(script));
|
||||
try {
|
||||
chunk.invoke(LuaValue.NONE);
|
||||
fail( "call should not have succeeded" );
|
||||
} catch ( LuaError lee ) {
|
||||
Throwable c = lee.getCause();
|
||||
assertEquals( SomeException.class, c.getClass() );
|
||||
}
|
||||
}
|
||||
|
||||
public interface VarArgsInterface {
|
||||
public String varargsMethod( String a, String ... v );
|
||||
public String arrayargsMethod( String a, String[] v );
|
||||
}
|
||||
|
||||
public void testVarArgsProxy() {
|
||||
String script = "return luajava.createProxy( \""+VarArgsInterface.class.getName()+"\", \n"+
|
||||
"{\n" +
|
||||
" varargsMethod = function(a,...)\n" +
|
||||
" return table.concat({a,...},'-')\n" +
|
||||
" end,\n" +
|
||||
" arrayargsMethod = function(a,array)\n" +
|
||||
" return tostring(a)..(array and \n" +
|
||||
" ('-'..tostring(array.length)\n" +
|
||||
" ..'-'..tostring(array[1])\n" +
|
||||
" ..'-'..tostring(array[2])\n" +
|
||||
" ) or '-nil')\n" +
|
||||
" end,\n" +
|
||||
"} )\n";
|
||||
Varargs chunk = globals.get("load").call(LuaValue.valueOf(script));
|
||||
if ( ! chunk.arg1().toboolean() )
|
||||
fail( chunk.arg(2).toString() );
|
||||
LuaValue result = chunk.arg1().call();
|
||||
Object u = result.touserdata();
|
||||
VarArgsInterface v = (VarArgsInterface) u;
|
||||
assertEquals( "foo", v.varargsMethod("foo") );
|
||||
assertEquals( "foo-bar", v.varargsMethod("foo", "bar") );
|
||||
assertEquals( "foo-bar-etc", v.varargsMethod("foo", "bar", "etc") );
|
||||
assertEquals( "foo-0-nil-nil", v.arrayargsMethod("foo", new String[0]) );
|
||||
assertEquals( "foo-1-bar-nil", v.arrayargsMethod("foo", new String[] {"bar"}) );
|
||||
assertEquals( "foo-2-bar-etc", v.arrayargsMethod("foo", new String[] {"bar","etc"}) );
|
||||
assertEquals( "foo-3-bar-etc", v.arrayargsMethod("foo", new String[] {"bar","etc","etc"}) );
|
||||
assertEquals( "foo-nil", v.arrayargsMethod("foo", null) );
|
||||
}
|
||||
|
||||
public void testBigNum() {
|
||||
String script =
|
||||
"bigNumA = luajava.newInstance('java.math.BigDecimal','12345678901234567890');\n" +
|
||||
"bigNumB = luajava.newInstance('java.math.BigDecimal','12345678901234567890');\n" +
|
||||
"bigNumC = bigNumA:multiply(bigNumB);\n" +
|
||||
//"print(bigNumA:toString())\n" +
|
||||
//"print(bigNumB:toString())\n" +
|
||||
//"print(bigNumC:toString())\n" +
|
||||
"return bigNumA:toString(), bigNumB:toString(), bigNumC:toString()";
|
||||
Varargs chunk = globals.get("load").call(LuaValue.valueOf(script));
|
||||
if ( ! chunk.arg1().toboolean() )
|
||||
fail( chunk.arg(2).toString() );
|
||||
Varargs results = chunk.arg1().invoke();
|
||||
int nresults = results.narg();
|
||||
String sa = results.tojstring(1);
|
||||
String sb = results.tojstring(2);
|
||||
String sc = results.tojstring(3);
|
||||
assertEquals( 3, nresults );
|
||||
assertEquals( "12345678901234567890", sa );
|
||||
assertEquals( "12345678901234567890", sb );
|
||||
assertEquals( "152415787532388367501905199875019052100", sc );
|
||||
}
|
||||
|
||||
public interface IA {}
|
||||
public interface IB extends IA {}
|
||||
public interface IC extends IB {}
|
||||
|
||||
public static class A implements IA {
|
||||
}
|
||||
public static class B extends A implements IB {
|
||||
public String set( Object x ) { return "set(Object) "; }
|
||||
public String set( String x ) { return "set(String) "+x; }
|
||||
public String set( A x ) { return "set(A) "; }
|
||||
public String set( B x ) { return "set(B) "; }
|
||||
public String set( C x ) { return "set(C) "; }
|
||||
public String set( byte x ) { return "set(byte) "+x; }
|
||||
public String set( char x ) { return "set(char) "+(int)x; }
|
||||
public String set( short x ) { return "set(short) "+x; }
|
||||
public String set( int x ) { return "set(int) "+x; }
|
||||
public String set( long x ) { return "set(long) "+x; }
|
||||
public String set( float x ) { return "set(float) "+x; }
|
||||
public String set( double x ) { return "set(double) "+x; }
|
||||
|
||||
public String setr( double x ) { return "setr(double) "+x; }
|
||||
public String setr( float x ) { return "setr(float) "+x; }
|
||||
public String setr( long x ) { return "setr(long) "+x; }
|
||||
public String setr( int x ) { return "setr(int) "+x; }
|
||||
public String setr( short x ) { return "setr(short) "+x; }
|
||||
public String setr( char x ) { return "setr(char) "+(int)x; }
|
||||
public String setr( byte x ) { return "setr(byte) "+x; }
|
||||
public String setr( C x ) { return "setr(C) "; }
|
||||
public String setr( B x ) { return "setr(B) "; }
|
||||
public String setr( A x ) { return "setr(A) "; }
|
||||
public String setr( String x ) { return "setr(String) "+x; }
|
||||
public String setr( Object x ) { return "setr(Object) "; }
|
||||
|
||||
public Object getObject() { return new Object(); }
|
||||
public String getString() { return "abc"; }
|
||||
public byte[] getbytearray() { return new byte[] { 1, 2, 3 }; }
|
||||
public A getA() { return new A(); }
|
||||
public B getB() { return new B(); }
|
||||
public C getC() { return new C(); }
|
||||
public byte getbyte() { return 1; }
|
||||
public char getchar() { return 65000; }
|
||||
public short getshort() { return -32000; }
|
||||
public int getint() { return 100000; }
|
||||
public long getlong() { return 50000000000L; }
|
||||
public float getfloat() { return 6.5f; }
|
||||
public double getdouble() { return Math.PI; }
|
||||
}
|
||||
public static class C extends B implements IC {
|
||||
}
|
||||
public static class D extends C implements IA {
|
||||
}
|
||||
|
||||
public void testOverloadedJavaMethodObject() { doOverloadedMethodTest( "Object", "" ); }
|
||||
public void testOverloadedJavaMethodString() { doOverloadedMethodTest( "String", "abc" ); }
|
||||
public void testOverloadedJavaMethodA() { doOverloadedMethodTest( "A", "" ); }
|
||||
public void testOverloadedJavaMethodB() { doOverloadedMethodTest( "B", "" ); }
|
||||
public void testOverloadedJavaMethodC() { doOverloadedMethodTest( "C", "" ); }
|
||||
public void testOverloadedJavaMethodByte() { doOverloadedMethodTest( "byte", "1" ); }
|
||||
public void testOverloadedJavaMethodChar() { doOverloadedMethodTest( "char", "65000" ); }
|
||||
public void testOverloadedJavaMethodShort() { doOverloadedMethodTest( "short", "-32000" ); }
|
||||
public void testOverloadedJavaMethodInt() { doOverloadedMethodTest( "int", "100000" ); }
|
||||
public void testOverloadedJavaMethodLong() { doOverloadedMethodTest( "long", "50000000000" ); }
|
||||
public void testOverloadedJavaMethodFloat() { doOverloadedMethodTest( "float", "6.5" ); }
|
||||
public void testOverloadedJavaMethodDouble() { doOverloadedMethodTest( "double", "3.141592653589793" ); }
|
||||
|
||||
private void doOverloadedMethodTest( String typename, String value ) {
|
||||
String script =
|
||||
"local a = luajava.newInstance('"+B.class.getName()+"');\n" +
|
||||
"local b = a:set(a:get"+typename+"())\n" +
|
||||
"local c = a:setr(a:get"+typename+"())\n" +
|
||||
"return b,c";
|
||||
Varargs chunk = globals.get("load").call(LuaValue.valueOf(script));
|
||||
if ( ! chunk.arg1().toboolean() )
|
||||
fail( chunk.arg(2).toString() );
|
||||
Varargs results = chunk.arg1().invoke();
|
||||
int nresults = results.narg();
|
||||
assertEquals( 2, nresults );
|
||||
LuaValue b = results.arg(1);
|
||||
LuaValue c = results.arg(2);
|
||||
String sb = b.tojstring();
|
||||
String sc = c.tojstring();
|
||||
assertEquals( "set("+typename+") "+value, sb );
|
||||
assertEquals( "setr("+typename+") "+value, sc );
|
||||
}
|
||||
|
||||
public void testClassInheritanceLevels() {
|
||||
assertEquals( 0, CoerceLuaToJava.inheritanceLevels(Object.class, Object.class) );
|
||||
assertEquals( 1, CoerceLuaToJava.inheritanceLevels(Object.class, String.class) );
|
||||
assertEquals( 1, CoerceLuaToJava.inheritanceLevels(Object.class, A.class) );
|
||||
assertEquals( 2, CoerceLuaToJava.inheritanceLevels(Object.class, B.class) );
|
||||
assertEquals( 3, CoerceLuaToJava.inheritanceLevels(Object.class, C.class) );
|
||||
|
||||
assertEquals( CoerceLuaToJava.SCORE_UNCOERCIBLE, CoerceLuaToJava.inheritanceLevels(A.class, Object.class) );
|
||||
assertEquals( CoerceLuaToJava.SCORE_UNCOERCIBLE, CoerceLuaToJava.inheritanceLevels(A.class, String.class) );
|
||||
assertEquals( 0, CoerceLuaToJava.inheritanceLevels(A.class, A.class) );
|
||||
assertEquals( 1, CoerceLuaToJava.inheritanceLevels(A.class, B.class) );
|
||||
assertEquals( 2, CoerceLuaToJava.inheritanceLevels(A.class, C.class) );
|
||||
|
||||
assertEquals( CoerceLuaToJava.SCORE_UNCOERCIBLE, CoerceLuaToJava.inheritanceLevels(B.class, Object.class) );
|
||||
assertEquals( CoerceLuaToJava.SCORE_UNCOERCIBLE, CoerceLuaToJava.inheritanceLevels(B.class, String.class) );
|
||||
assertEquals( CoerceLuaToJava.SCORE_UNCOERCIBLE, CoerceLuaToJava.inheritanceLevels(B.class, A.class) );
|
||||
assertEquals( 0, CoerceLuaToJava.inheritanceLevels(B.class, B.class) );
|
||||
assertEquals( 1, CoerceLuaToJava.inheritanceLevels(B.class, C.class) );
|
||||
|
||||
assertEquals( CoerceLuaToJava.SCORE_UNCOERCIBLE, CoerceLuaToJava.inheritanceLevels(C.class, Object.class) );
|
||||
assertEquals( CoerceLuaToJava.SCORE_UNCOERCIBLE, CoerceLuaToJava.inheritanceLevels(C.class, String.class) );
|
||||
assertEquals( CoerceLuaToJava.SCORE_UNCOERCIBLE, CoerceLuaToJava.inheritanceLevels(C.class, A.class) );
|
||||
assertEquals( CoerceLuaToJava.SCORE_UNCOERCIBLE, CoerceLuaToJava.inheritanceLevels(C.class, B.class) );
|
||||
assertEquals( 0, CoerceLuaToJava.inheritanceLevels(C.class, C.class) );
|
||||
}
|
||||
|
||||
public void testInterfaceInheritanceLevels() {
|
||||
assertEquals( 1, CoerceLuaToJava.inheritanceLevels(IA.class, A.class) );
|
||||
assertEquals( 1, CoerceLuaToJava.inheritanceLevels(IB.class, B.class) );
|
||||
assertEquals( 2, CoerceLuaToJava.inheritanceLevels(IA.class, B.class) );
|
||||
assertEquals( 1, CoerceLuaToJava.inheritanceLevels(IC.class, C.class) );
|
||||
assertEquals( 2, CoerceLuaToJava.inheritanceLevels(IB.class, C.class) );
|
||||
assertEquals( 3, CoerceLuaToJava.inheritanceLevels(IA.class, C.class) );
|
||||
assertEquals( 1, CoerceLuaToJava.inheritanceLevels(IA.class, D.class) );
|
||||
assertEquals( 2, CoerceLuaToJava.inheritanceLevels(IC.class, D.class) );
|
||||
assertEquals( 3, CoerceLuaToJava.inheritanceLevels(IB.class, D.class) );
|
||||
|
||||
assertEquals( CoerceLuaToJava.SCORE_UNCOERCIBLE, CoerceLuaToJava.inheritanceLevels(IB.class, A.class) );
|
||||
assertEquals( CoerceLuaToJava.SCORE_UNCOERCIBLE, CoerceLuaToJava.inheritanceLevels(IC.class, A.class) );
|
||||
assertEquals( CoerceLuaToJava.SCORE_UNCOERCIBLE, CoerceLuaToJava.inheritanceLevels(IC.class, B.class) );
|
||||
assertEquals( CoerceLuaToJava.SCORE_UNCOERCIBLE, CoerceLuaToJava.inheritanceLevels(IB.class, IA.class) );
|
||||
assertEquals( 1, CoerceLuaToJava.inheritanceLevels(IA.class, IB.class) );
|
||||
}
|
||||
|
||||
public void testCoerceJavaToLuaLuaValue() {
|
||||
assertSame(LuaValue.NIL, CoerceJavaToLua.coerce(LuaValue.NIL));
|
||||
assertSame(LuaValue.ZERO, CoerceJavaToLua.coerce(LuaValue.ZERO));
|
||||
assertSame(LuaValue.ONE, CoerceJavaToLua.coerce(LuaValue.ONE));
|
||||
assertSame(LuaValue.INDEX, CoerceJavaToLua.coerce(LuaValue.INDEX));
|
||||
LuaTable table = LuaValue.tableOf();
|
||||
assertSame(table, CoerceJavaToLua.coerce(table));
|
||||
}
|
||||
|
||||
public void testCoerceJavaToLuaByeArray() {
|
||||
byte[] bytes = "abcd".getBytes();
|
||||
LuaValue value = CoerceJavaToLua.coerce(bytes);
|
||||
assertEquals(LuaString.class, value.getClass());
|
||||
assertEquals(LuaValue.valueOf("abcd"), value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package org.luaj.vm2.libs.jse;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
public class LuajavaAccessibleMembersTest extends TestCase {
|
||||
|
||||
private Globals globals;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
globals = JsePlatform.standardGlobals();
|
||||
}
|
||||
|
||||
private String invokeScript(String script) {
|
||||
try {
|
||||
LuaValue c = globals.load(script, "script");
|
||||
return c.call().tojstring();
|
||||
} catch ( Exception e ) {
|
||||
fail("exception: "+e );
|
||||
return "failed";
|
||||
}
|
||||
}
|
||||
|
||||
public void testAccessFromPrivateClassImplementedMethod() {
|
||||
assertEquals("privateImpl-aaa-interface_method(bar)", invokeScript(
|
||||
"b = luajava.newInstance('"+TestClass.class.getName()+"');" +
|
||||
"a = b:create_PrivateImpl('aaa');" +
|
||||
"return a:interface_method('bar');"));
|
||||
}
|
||||
|
||||
public void testAccessFromPrivateClassPublicMethod() {
|
||||
assertEquals("privateImpl-aaa-public_method", invokeScript(
|
||||
"b = luajava.newInstance('"+TestClass.class.getName()+"');" +
|
||||
"a = b:create_PrivateImpl('aaa');" +
|
||||
"return a:public_method();"));
|
||||
}
|
||||
|
||||
public void testAccessFromPrivateClassGetPublicField() {
|
||||
assertEquals("aaa", invokeScript(
|
||||
"b = luajava.newInstance('"+TestClass.class.getName()+"');" +
|
||||
"a = b:create_PrivateImpl('aaa');" +
|
||||
"return a.public_field;"));
|
||||
}
|
||||
|
||||
public void testAccessFromPrivateClassSetPublicField() {
|
||||
assertEquals("foo", invokeScript(
|
||||
"b = luajava.newInstance('"+TestClass.class.getName()+"');" +
|
||||
"a = b:create_PrivateImpl('aaa');" +
|
||||
"a.public_field = 'foo';" +
|
||||
"return a.public_field;"));
|
||||
}
|
||||
|
||||
public void testAccessFromPrivateClassPublicConstructor() {
|
||||
assertEquals("privateImpl-constructor", invokeScript(
|
||||
"b = luajava.newInstance('"+TestClass.class.getName()+"');" +
|
||||
"c = b:get_PrivateImplClass();" +
|
||||
"return luajava.new(c);"));
|
||||
}
|
||||
|
||||
public void testAccessPublicEnum() {
|
||||
assertEquals("class org.luaj.vm2.lib.jse.TestClass$SomeEnum", invokeScript(
|
||||
"b = luajava.newInstance('"+TestClass.class.getName()+"');" +
|
||||
"return b.SomeEnum"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
package org.luaj.vm2.libs.jse;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
public class LuajavaClassMembersTest extends TestCase {
|
||||
public static class A {
|
||||
protected A() {}
|
||||
}
|
||||
public static class B extends A {
|
||||
public byte m_byte_field;
|
||||
public int m_int_field;
|
||||
public double m_double_field;
|
||||
public String m_string_field;
|
||||
|
||||
protected B() {}
|
||||
public B(int i) { m_int_field = i; }
|
||||
|
||||
public String setString( String x ) { return "setString(String) "+x; }
|
||||
public String getString() { return "abc"; }
|
||||
public int getint() { return 100000; }
|
||||
|
||||
public String uniq() { return "uniq()"; }
|
||||
public String uniqs(String s) { return "uniqs(string:"+s+")"; }
|
||||
public String uniqi(int i) { return "uniqi(int:"+i+")"; }
|
||||
public String uniqsi(String s, int i) { return "uniqsi(string:"+s+",int:"+i+")"; }
|
||||
public String uniqis(int i, String s) { return "uniqis(int:"+i+",string:"+s+")"; }
|
||||
|
||||
public String pick() { return "pick()"; }
|
||||
public String pick(String s) { return "pick(string:"+s+")"; }
|
||||
public String pick(int i) { return "pick(int:"+i+")"; }
|
||||
public String pick(String s, int i) { return "pick(string:"+s+",int:"+i+")"; }
|
||||
public String pick(int i, String s) { return "pick(int:"+i+",string:"+s+")"; }
|
||||
|
||||
public static String staticpick() { return "static-pick()"; }
|
||||
public static String staticpick(String s) { return "static-pick(string:"+s+")"; }
|
||||
public static String staticpick(int i) { return "static-pick(int:"+i+")"; }
|
||||
public static String staticpick(String s, int i) { return "static-pick(string:"+s+",int:"+i+")"; }
|
||||
public static String staticpick(int i, String s) { return "static-pick(int:"+i+",string:"+s+")"; }
|
||||
}
|
||||
public static class C extends B {
|
||||
public C() {}
|
||||
public C(String s) { m_string_field = s; }
|
||||
public C(int i) { m_int_field = i; }
|
||||
public C(String s, int i) { m_string_field = s; m_int_field = i; }
|
||||
public int getint() { return 200000; }
|
||||
|
||||
public String pick(String s) { return "class-c-pick(string:"+s+")"; }
|
||||
public String pick(int i) { return "class-c-pick(int:"+i+")"; }
|
||||
public static class D {
|
||||
public static String name() { return "name-of-D"; }
|
||||
}
|
||||
}
|
||||
|
||||
static LuaValue ZERO = LuaValue.ZERO;
|
||||
static LuaValue ONE = LuaValue.ONE;
|
||||
static LuaValue PI = LuaValue.valueOf(Math.PI);
|
||||
static LuaValue THREE = LuaValue.valueOf(3);
|
||||
static LuaValue NUMS = LuaValue.valueOf(123);
|
||||
static LuaValue ABC = LuaValue.valueOf("abc");
|
||||
static LuaValue SOMEA = CoerceJavaToLua.coerce(new A());
|
||||
static LuaValue SOMEB = CoerceJavaToLua.coerce(new B());
|
||||
static LuaValue SOMEC = CoerceJavaToLua.coerce(new C());
|
||||
|
||||
public void testSetByteField() {
|
||||
B b = new B();
|
||||
JavaInstance i = new JavaInstance(b);
|
||||
i.set("m_byte_field", ONE ); assertEquals( 1, b.m_byte_field ); assertEquals( ONE, i.get("m_byte_field") );
|
||||
i.set("m_byte_field", PI ); assertEquals( 3, b.m_byte_field ); assertEquals( THREE, i.get("m_byte_field") );
|
||||
i.set("m_byte_field", ABC ); assertEquals( 0, b.m_byte_field ); assertEquals( ZERO, i.get("m_byte_field") );
|
||||
}
|
||||
public void testSetDoubleField() {
|
||||
B b = new B();
|
||||
JavaInstance i = new JavaInstance(b);
|
||||
i.set("m_double_field", ONE ); assertEquals( 1., b.m_double_field ); assertEquals( ONE, i.get("m_double_field") );
|
||||
i.set("m_double_field", PI ); assertEquals( Math.PI, b.m_double_field ); assertEquals( PI, i.get("m_double_field") );
|
||||
i.set("m_double_field", ABC ); assertEquals( 0., b.m_double_field ); assertEquals( ZERO, i.get("m_double_field") );
|
||||
}
|
||||
public void testNoFactory() {
|
||||
JavaClass c = JavaClass.forClass(A.class);
|
||||
try {
|
||||
c.call();
|
||||
fail( "did not throw lua error as expected" );
|
||||
} catch ( LuaError e ) {
|
||||
}
|
||||
}
|
||||
public void testUniqueFactoryCoercible() {
|
||||
JavaClass c = JavaClass.forClass(B.class);
|
||||
assertEquals( JavaClass.class, c.getClass() );
|
||||
LuaValue constr = c.get("new");
|
||||
assertEquals( JavaConstructor.class, constr.getClass() );
|
||||
LuaValue v = constr.call(NUMS);
|
||||
Object b = v.touserdata();
|
||||
assertEquals( B.class, b.getClass() );
|
||||
assertEquals( 123, ((B)b).m_int_field );
|
||||
Object b0 = constr.call().touserdata();
|
||||
assertEquals( B.class, b0.getClass() );
|
||||
assertEquals( 0, ((B)b0).m_int_field );
|
||||
}
|
||||
public void testUniqueFactoryUncoercible() {
|
||||
JavaClass f = JavaClass.forClass(B.class);
|
||||
LuaValue constr = f.get("new");
|
||||
assertEquals( JavaConstructor.class, constr.getClass() );
|
||||
try {
|
||||
LuaValue v = constr.call(LuaValue.userdataOf(new Object()));
|
||||
Object b = v.touserdata();
|
||||
// fail( "did not throw lua error as expected" );
|
||||
assertEquals( 0, ((B)b).m_int_field );
|
||||
} catch ( LuaError e ) {
|
||||
}
|
||||
}
|
||||
public void testOverloadedFactoryCoercible() {
|
||||
JavaClass f = JavaClass.forClass(C.class);
|
||||
LuaValue constr = f.get("new");
|
||||
assertEquals( JavaConstructor.Overload.class, constr.getClass() );
|
||||
Object c = constr.call().touserdata();
|
||||
Object ci = constr.call(LuaValue.valueOf(123)).touserdata();
|
||||
Object cs = constr.call(LuaValue.valueOf("abc")).touserdata();
|
||||
Object csi = constr.call( LuaValue.valueOf("def"), LuaValue.valueOf(456) ).touserdata();
|
||||
assertEquals( C.class, c.getClass() );
|
||||
assertEquals( C.class, ci.getClass() );
|
||||
assertEquals( C.class, cs.getClass() );
|
||||
assertEquals( C.class, csi.getClass() );
|
||||
assertEquals( null, ((C)c).m_string_field );
|
||||
assertEquals( 0, ((C)c).m_int_field );
|
||||
assertEquals( "abc", ((C)cs).m_string_field );
|
||||
assertEquals( 0, ((C)cs).m_int_field );
|
||||
assertEquals( null, ((C)ci).m_string_field );
|
||||
assertEquals( 123, ((C)ci).m_int_field );
|
||||
assertEquals( "def", ((C)csi).m_string_field );
|
||||
assertEquals( 456, ((C)csi).m_int_field );
|
||||
}
|
||||
public void testOverloadedFactoryUncoercible() {
|
||||
JavaClass f = JavaClass.forClass(C.class);
|
||||
try {
|
||||
Object c = f.call(LuaValue.userdataOf(new Object()));
|
||||
// fail( "did not throw lua error as expected" );
|
||||
assertEquals( 0, ((C)c).m_int_field );
|
||||
assertEquals( null, ((C)c).m_string_field );
|
||||
} catch ( LuaError e ) {
|
||||
}
|
||||
}
|
||||
|
||||
public void testNoAttribute() {
|
||||
JavaClass f = JavaClass.forClass(A.class);
|
||||
LuaValue v = f.get("bogus");
|
||||
assertEquals( v, LuaValue.NIL );
|
||||
try {
|
||||
f.set("bogus",ONE);
|
||||
fail( "did not throw lua error as expected" );
|
||||
} catch ( LuaError e ) {}
|
||||
}
|
||||
public void testFieldAttributeCoercible() {
|
||||
JavaInstance i = new JavaInstance(new B());
|
||||
i.set("m_int_field", ONE ); assertEquals( 1, i.get("m_int_field").toint() );
|
||||
i.set("m_int_field", THREE ); assertEquals( 3, i.get("m_int_field").toint() );
|
||||
i = new JavaInstance(new C());
|
||||
i.set("m_int_field", ONE ); assertEquals( 1, i.get("m_int_field").toint() );
|
||||
i.set("m_int_field", THREE ); assertEquals( 3, i.get("m_int_field").toint() );
|
||||
}
|
||||
public void testUniqueMethodAttributeCoercible() {
|
||||
B b = new B();
|
||||
JavaInstance ib = new JavaInstance(b);
|
||||
LuaValue b_getString = ib.get("getString");
|
||||
LuaValue b_getint = ib.get("getint");
|
||||
assertEquals( JavaMethod.class, b_getString.getClass() );
|
||||
assertEquals( JavaMethod.class, b_getint.getClass() );
|
||||
assertEquals( "abc", b_getString.call(SOMEB).tojstring() );
|
||||
assertEquals( 100000, b_getint.call(SOMEB).toint());
|
||||
assertEquals( "abc", b_getString.call(SOMEC).tojstring() );
|
||||
assertEquals( 200000, b_getint.call(SOMEC).toint());
|
||||
}
|
||||
public void testUniqueMethodAttributeArgsCoercible() {
|
||||
B b = new B();
|
||||
JavaInstance ib = new JavaInstance(b);
|
||||
LuaValue uniq = ib.get("uniq");
|
||||
LuaValue uniqs = ib.get("uniqs");
|
||||
LuaValue uniqi = ib.get("uniqi");
|
||||
LuaValue uniqsi = ib.get("uniqsi");
|
||||
LuaValue uniqis = ib.get("uniqis");
|
||||
assertEquals( JavaMethod.class, uniq.getClass() );
|
||||
assertEquals( JavaMethod.class, uniqs.getClass() );
|
||||
assertEquals( JavaMethod.class, uniqi.getClass() );
|
||||
assertEquals( JavaMethod.class, uniqsi.getClass() );
|
||||
assertEquals( JavaMethod.class, uniqis.getClass() );
|
||||
assertEquals( "uniq()", uniq.call(SOMEB).tojstring() );
|
||||
assertEquals( "uniqs(string:abc)", uniqs.call(SOMEB,ABC).tojstring() );
|
||||
assertEquals( "uniqi(int:1)", uniqi.call(SOMEB,ONE).tojstring() );
|
||||
assertEquals( "uniqsi(string:abc,int:1)", uniqsi.call(SOMEB,ABC,ONE).tojstring() );
|
||||
assertEquals( "uniqis(int:1,string:abc)", uniqis.call(SOMEB,ONE,ABC).tojstring() );
|
||||
assertEquals( "uniqis(int:1,string:abc)", uniqis.invoke(LuaValue.varargsOf(new LuaValue[] {SOMEB,ONE,ABC,ONE})).arg1().tojstring() );
|
||||
}
|
||||
public void testOverloadedMethodAttributeCoercible() {
|
||||
B b = new B();
|
||||
JavaInstance ib = new JavaInstance(b);
|
||||
LuaValue p = ib.get("pick");
|
||||
assertEquals( "pick()", p.call(SOMEB).tojstring() );
|
||||
assertEquals( "pick(string:abc)", p.call(SOMEB,ABC).tojstring() );
|
||||
assertEquals( "pick(int:1)", p.call(SOMEB,ONE).tojstring() );
|
||||
assertEquals( "pick(string:abc,int:1)", p.call(SOMEB,ABC,ONE).tojstring() );
|
||||
assertEquals( "pick(int:1,string:abc)", p.call(SOMEB,ONE,ABC).tojstring() );
|
||||
assertEquals( "pick(int:1,string:abc)", p.invoke(LuaValue.varargsOf(new LuaValue[] {SOMEB,ONE,ABC,ONE})).arg1().tojstring() );
|
||||
}
|
||||
public void testUnboundOverloadedMethodAttributeCoercible() {
|
||||
B b = new B();
|
||||
JavaInstance ib = new JavaInstance(b);
|
||||
LuaValue p = ib.get("pick");
|
||||
assertEquals( JavaMethod.Overload.class, p.getClass() );
|
||||
assertEquals( "pick()", p.call(SOMEC).tojstring() );
|
||||
assertEquals( "class-c-pick(string:abc)", p.call(SOMEC,ABC).tojstring() );
|
||||
assertEquals( "class-c-pick(int:1)", p.call(SOMEC,ONE).tojstring() );
|
||||
assertEquals( "pick(string:abc,int:1)", p.call(SOMEC,ABC,ONE).tojstring() );
|
||||
assertEquals( "pick(int:1,string:abc)", p.call(SOMEC,ONE,ABC).tojstring() );
|
||||
assertEquals( "pick(int:1,string:abc)", p.invoke(LuaValue.varargsOf(new LuaValue[] {SOMEC,ONE,ABC,ONE})).arg1().tojstring() );
|
||||
}
|
||||
public void testOverloadedStaticMethodAttributeCoercible() {
|
||||
B b = new B();
|
||||
JavaInstance ib = new JavaInstance(b);
|
||||
LuaValue p = ib.get("staticpick");
|
||||
assertEquals( "static-pick()", p.call(SOMEB).tojstring() );
|
||||
assertEquals( "static-pick(string:abc)", p.call(SOMEB,ABC).tojstring() );
|
||||
assertEquals( "static-pick(int:1)", p.call(SOMEB,ONE).tojstring() );
|
||||
assertEquals( "static-pick(string:abc,int:1)", p.call(SOMEB,ABC,ONE).tojstring() );
|
||||
assertEquals( "static-pick(int:1,string:abc)", p.call(SOMEB,ONE,ABC).tojstring() );
|
||||
assertEquals( "static-pick(int:1,string:abc)", p.invoke(LuaValue.varargsOf(new LuaValue[] {SOMEB,ONE,ABC,ONE})).arg1().tojstring() );
|
||||
}
|
||||
public void testGetInnerClass() {
|
||||
C c = new C();
|
||||
JavaInstance ic = new JavaInstance(c);
|
||||
LuaValue d = ic.get("D");
|
||||
assertFalse(d.isnil());
|
||||
assertSame(d, JavaClass.forClass(C.D.class));
|
||||
LuaValue e = ic.get("E");
|
||||
assertTrue(e.isnil());
|
||||
}
|
||||
}
|
||||
77
jse/src/test/java/org/luaj/vm2/libs/jse/OsLibTest.java
Normal file
77
jse/src/test/java/org/luaj/vm2/libs/jse/OsLibTest.java
Normal file
@@ -0,0 +1,77 @@
|
||||
package org.luaj.vm2.libs.jse;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.libs.jme.JmePlatform;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class OsLibTest extends TestCase {
|
||||
|
||||
LuaValue jme_lib;
|
||||
LuaValue jse_lib;
|
||||
double time;
|
||||
|
||||
public void setUp() {
|
||||
jse_lib = JsePlatform.standardGlobals().get("os");;
|
||||
jme_lib = JmePlatform.standardGlobals().get("os");;
|
||||
time = new java.util.Date(2001-1900, 7, 23, 14, 55, 02).getTime() / 1000.0;
|
||||
}
|
||||
|
||||
void t(String format, String expected) {
|
||||
String actual = jme_lib.get("date").call(LuaValue.valueOf(format), LuaValue.valueOf(time)).tojstring();
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
public void testStringDateChars() { t("foo", "foo"); }
|
||||
public void testStringDate_a() { t("%a", "Thu"); }
|
||||
public void testStringDate_A() { t("%A", "Thursday"); }
|
||||
public void testStringDate_b() { t("%b", "Aug"); }
|
||||
public void testStringDate_B() { t("%B", "August"); }
|
||||
public void testStringDate_c() { t("%c", "Thu Aug 23 14:55:02 2001"); }
|
||||
public void testStringDate_d() { t("%d", "23"); }
|
||||
public void testStringDate_H() { t("%H", "14"); }
|
||||
public void testStringDate_I() { t("%I", "02"); }
|
||||
public void testStringDate_j() { t("%j", "235"); }
|
||||
public void testStringDate_m() { t("%m", "08"); }
|
||||
public void testStringDate_M() { t("%M", "55"); }
|
||||
public void testStringDate_p() { t("%p", "PM"); }
|
||||
public void testStringDate_S() { t("%S", "02"); }
|
||||
public void testStringDate_U() { t("%U", "33"); }
|
||||
public void testStringDate_w() { t("%w", "4"); }
|
||||
public void testStringDate_W() { t("%W", "34"); }
|
||||
public void testStringDate_x() { t("%x", "08/23/01"); }
|
||||
public void testStringDate_X() { t("%X", "14:55:02"); }
|
||||
public void testStringDate_y() { t("%y", "01"); }
|
||||
public void testStringDate_Y() { t("%Y", "2001"); }
|
||||
public void testStringDate_Pct() { t("%%", "%"); }
|
||||
|
||||
static final double DAY = 24. * 3600.;
|
||||
public void testStringDate_UW_neg4() { time-=4*DAY; t("%c %U %W", "Sun Aug 19 14:55:02 2001 33 33"); }
|
||||
public void testStringDate_UW_neg3() { time-=3*DAY; t("%c %U %W", "Mon Aug 20 14:55:02 2001 33 34"); }
|
||||
public void testStringDate_UW_neg2() { time-=2*DAY; t("%c %U %W", "Tue Aug 21 14:55:02 2001 33 34"); }
|
||||
public void testStringDate_UW_neg1() { time-=DAY; t("%c %U %W", "Wed Aug 22 14:55:02 2001 33 34"); }
|
||||
public void testStringDate_UW_pos0() { time+=0; t("%c %U %W", "Thu Aug 23 14:55:02 2001 33 34"); }
|
||||
public void testStringDate_UW_pos1() { time+=DAY; t("%c %U %W", "Fri Aug 24 14:55:02 2001 33 34"); }
|
||||
public void testStringDate_UW_pos2() { time+=2*DAY; t("%c %U %W", "Sat Aug 25 14:55:02 2001 33 34"); }
|
||||
public void testStringDate_UW_pos3() { time+=3*DAY; t("%c %U %W", "Sun Aug 26 14:55:02 2001 34 34"); }
|
||||
public void testStringDate_UW_pos4() { time+=4*DAY; t("%c %U %W", "Mon Aug 27 14:55:02 2001 34 35"); }
|
||||
|
||||
public void testJseOsGetenvForEnvVariables() {
|
||||
LuaValue USER = LuaValue.valueOf("USER");
|
||||
LuaValue jse_user = jse_lib.get("getenv").call(USER);
|
||||
LuaValue jme_user = jme_lib.get("getenv").call(USER);
|
||||
assertFalse(jse_user.isnil());
|
||||
assertTrue(jme_user.isnil());
|
||||
System.out.println("User: " + jse_user);
|
||||
}
|
||||
|
||||
public void testJseOsGetenvForSystemProperties() {
|
||||
System.setProperty("test.key.foo", "test.value.bar");
|
||||
LuaValue key = LuaValue.valueOf("test.key.foo");
|
||||
LuaValue value = LuaValue.valueOf("test.value.bar");
|
||||
LuaValue jse_value = jse_lib.get("getenv").call(key);
|
||||
LuaValue jme_value = jme_lib.get("getenv").call(key);
|
||||
assertEquals(value, jse_value);
|
||||
assertEquals(value, jme_value);
|
||||
}
|
||||
}
|
||||
22
jse/src/test/java/org/luaj/vm2/libs/jse/TestClass.java
Normal file
22
jse/src/test/java/org/luaj/vm2/libs/jse/TestClass.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package org.luaj.vm2.libs.jse;
|
||||
|
||||
public class TestClass {
|
||||
private static class PrivateImpl implements TestInterface {
|
||||
public String public_field;
|
||||
public PrivateImpl() {
|
||||
this.public_field = "privateImpl-constructor";
|
||||
}
|
||||
PrivateImpl(String f) {
|
||||
this.public_field = f;
|
||||
}
|
||||
public String public_method() { return "privateImpl-"+public_field+"-public_method"; }
|
||||
public String interface_method(String x) { return "privateImpl-"+public_field+"-interface_method("+x+")"; }
|
||||
public String toString() { return public_field; }
|
||||
}
|
||||
public TestInterface create_PrivateImpl(String f) { return new PrivateImpl(f); }
|
||||
public Class get_PrivateImplClass() { return PrivateImpl.class; }
|
||||
public enum SomeEnum {
|
||||
ValueOne,
|
||||
ValueTwo,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package org.luaj.vm2.libs.jse;
|
||||
|
||||
public interface TestInterface {
|
||||
String interface_method(String x);
|
||||
}
|
||||
Reference in New Issue
Block a user