Refactor lib bindings.
This commit is contained in:
@@ -215,7 +215,7 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
|
||||
case 2: // "load", // ( func [,chunkname] ) -> chunk | nil, msg
|
||||
try {
|
||||
LuaValue func = args.checkfunction(1);
|
||||
String chunkname = args.optString(2, "function");
|
||||
String chunkname = args.optjstring(2, "function");
|
||||
return LoadState.load(new StringInputStream(func), chunkname, LuaThread.getGlobals());
|
||||
} catch ( Exception e ) {
|
||||
return varargsOf(NIL, valueOf(e.getMessage()));
|
||||
@@ -232,7 +232,7 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
|
||||
case 4: // "loadstring", // ( string [,chunkname] ) -> chunk | nil, msg
|
||||
try {
|
||||
LuaString script = args.checkstring(1);
|
||||
String chunkname = args.optString(2, "string");
|
||||
String chunkname = args.optjstring(2, "string");
|
||||
return LoadState.load(script.toInputStream(),chunkname,LuaThread.getGlobals());
|
||||
} catch ( Exception e ) {
|
||||
return varargsOf(NIL, valueOf(e.getMessage()));
|
||||
|
||||
@@ -40,16 +40,19 @@ public class CoroutineLib extends VarArgFunction {
|
||||
public CoroutineLib() {
|
||||
}
|
||||
|
||||
private LuaTable init() {
|
||||
LuaTable t = new LuaTable();
|
||||
bind(t, CoroutineLib.class, new String[] {
|
||||
"create", "resume", "running", "status", "yield", "wrap" },
|
||||
CREATE);
|
||||
env.set("coroutine", t);
|
||||
return t;
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs args) {
|
||||
switch ( opcode ) {
|
||||
case INIT: {
|
||||
LuaTable t = new LuaTable();
|
||||
bind(t, CoroutineLib.class, new String[] {
|
||||
"create", "resume", "running", "status", "yield", "wrap" },
|
||||
CREATE);
|
||||
env.set("coroutine", t);
|
||||
return t;
|
||||
|
||||
return init();
|
||||
}
|
||||
case CREATE: {
|
||||
final LuaValue func = args.checkfunction(1);
|
||||
|
||||
@@ -36,7 +36,7 @@ import org.luaj.vm2.Print;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
public class DebugLib extends OneArgFunction {
|
||||
public class DebugLib extends VarArgFunction {
|
||||
public static final boolean CALLS = (null != System.getProperty("CALLS"));
|
||||
public static final boolean TRACE = (null != System.getProperty("TRACE"));
|
||||
|
||||
@@ -61,20 +61,21 @@ public class DebugLib extends OneArgFunction {
|
||||
"traceback",
|
||||
};
|
||||
|
||||
private static final int DEBUG = 0;
|
||||
private static final int GETFENV = 1;
|
||||
private static final int GETHOOK = 2;
|
||||
private static final int GETINFO = 3;
|
||||
private static final int GETLOCAL = 4;
|
||||
private static final int GETMETATABLE = 5;
|
||||
private static final int GETREGISTRY = 6;
|
||||
private static final int GETUPVALUE = 7;
|
||||
private static final int SETFENV = 8;
|
||||
private static final int SETHOOK = 9;
|
||||
private static final int SETLOCAL = 10;
|
||||
private static final int SETMETATABLE = 11;
|
||||
private static final int SETUPVALUE = 12;
|
||||
private static final int TRACEBACK = 13;
|
||||
private static final int INIT = 0;
|
||||
private static final int DEBUG = 1;
|
||||
private static final int GETFENV = 2;
|
||||
private static final int GETHOOK = 3;
|
||||
private static final int GETINFO = 4;
|
||||
private static final int GETLOCAL = 5;
|
||||
private static final int GETMETATABLE = 6;
|
||||
private static final int GETREGISTRY = 7;
|
||||
private static final int GETUPVALUE = 8;
|
||||
private static final int SETFENV = 9;
|
||||
private static final int SETHOOK = 10;
|
||||
private static final int SETLOCAL = 11;
|
||||
private static final int SETMETATABLE = 12;
|
||||
private static final int SETUPVALUE = 13;
|
||||
private static final int TRACEBACK = 14;
|
||||
|
||||
/* maximum stack for a Lua function */
|
||||
private static final int MAXSTACK = 250;
|
||||
@@ -106,36 +107,34 @@ public class DebugLib extends OneArgFunction {
|
||||
private static final LuaString ACTIVELINES = valueOf("activelines");
|
||||
|
||||
public DebugLib() {
|
||||
DEBUG_ENABLED = true;
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg) {
|
||||
private LuaTable init() {
|
||||
DEBUG_ENABLED = true;
|
||||
LuaTable t = new LuaTable();
|
||||
bind(t, DebugLibV.class, NAMES);
|
||||
bind(t, DebugLib.class, NAMES, DEBUG);
|
||||
env.set("debug", t);
|
||||
return t;
|
||||
}
|
||||
|
||||
public static final class DebugLibV extends VarArgFunction {
|
||||
protected DebugLib debuglib;
|
||||
public Varargs invoke(Varargs args) {
|
||||
switch ( opcode ) {
|
||||
case DEBUG: return _debug(args);
|
||||
case GETFENV: return _getfenv(args);
|
||||
case GETHOOK: return _gethook(args);
|
||||
case GETINFO: return _getinfo(args,this);
|
||||
case GETLOCAL: return _getlocal(args);
|
||||
case GETMETATABLE: return _getmetatable(args);
|
||||
case GETREGISTRY: return _getregistry(args);
|
||||
case GETUPVALUE: return _getupvalue(args);
|
||||
case SETFENV: return _setfenv(args);
|
||||
case SETHOOK: return _sethook(args);
|
||||
case SETLOCAL: return _setlocal(args);
|
||||
case SETMETATABLE: return _setmetatable(args);
|
||||
case SETUPVALUE: return _setupvalue(args);
|
||||
case TRACEBACK: return _traceback(args);
|
||||
default: return NONE;
|
||||
}
|
||||
public Varargs invoke(Varargs args) {
|
||||
switch ( opcode ) {
|
||||
case INIT: return init();
|
||||
case DEBUG: return _debug(args);
|
||||
case GETFENV: return _getfenv(args);
|
||||
case GETHOOK: return _gethook(args);
|
||||
case GETINFO: return _getinfo(args,this);
|
||||
case GETLOCAL: return _getlocal(args);
|
||||
case GETMETATABLE: return _getmetatable(args);
|
||||
case GETREGISTRY: return _getregistry(args);
|
||||
case GETUPVALUE: return _getupvalue(args);
|
||||
case SETFENV: return _setfenv(args);
|
||||
case SETHOOK: return _sethook(args);
|
||||
case SETLOCAL: return _setlocal(args);
|
||||
case SETMETATABLE: return _setmetatable(args);
|
||||
case SETUPVALUE: return _setupvalue(args);
|
||||
case TRACEBACK: return _traceback(args);
|
||||
default: return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -383,7 +382,7 @@ public class DebugLib extends OneArgFunction {
|
||||
int a=1;
|
||||
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();
|
||||
LuaValue func = args.optfunction(a++, null);
|
||||
String str = args.optString(a++,"");
|
||||
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++ )
|
||||
@@ -413,7 +412,7 @@ public class DebugLib extends OneArgFunction {
|
||||
int a=1;
|
||||
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();
|
||||
LuaValue func = args.arg(a++);
|
||||
String what = args.optString(a++, "nSluf");
|
||||
String what = args.optjstring(a++, "nSluf");
|
||||
|
||||
// find the stack info
|
||||
DebugState ds = getDebugState( thread );
|
||||
@@ -600,7 +599,7 @@ public class DebugLib extends OneArgFunction {
|
||||
private static LuaValue _traceback(Varargs args) {
|
||||
int a=1;
|
||||
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();
|
||||
String message = args.optString(a++, "stack traceback:");
|
||||
String message = args.optjstring(a++, "stack traceback:");
|
||||
int level = args.optint(a++,1);
|
||||
String tb = DebugLib.traceback(thread, level);
|
||||
return valueOf(message+"\n"+tb);
|
||||
|
||||
@@ -172,114 +172,210 @@ public class IoLib extends OneArgFunction {
|
||||
|
||||
LuaTable filemethods;
|
||||
|
||||
public IoLib() {}
|
||||
public IoLib() {
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg) {
|
||||
|
||||
// io lib functions
|
||||
LuaTable t = new LuaTable();
|
||||
bindv(t, IO_NAMES );
|
||||
bind(t, IoLibV.class, IO_NAMES );
|
||||
|
||||
// create file methods table
|
||||
filemethods = new LuaTable();
|
||||
bind(filemethods, FILE_NAMES, -1, FILE_CLOSE );
|
||||
bind(filemethods, IoLibV.class, FILE_NAMES, FILE_CLOSE );
|
||||
|
||||
// set up file metatable
|
||||
LuaTable mt = tableOf( new LuaValue[] { INDEX, bindv("__index",IO_INDEX) });
|
||||
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);
|
||||
return t;
|
||||
}
|
||||
|
||||
protected Varargs oncallv(int opcode, Varargs args) {
|
||||
File f;
|
||||
int n;
|
||||
LuaValue v;
|
||||
try {
|
||||
switch ( opcode ) {
|
||||
case IO_FLUSH: // io.flush() -> bool
|
||||
checkopen(output());
|
||||
outfile.flush();
|
||||
return LuaValue.TRUE;
|
||||
case IO_TMPFILE: // io.tmpfile() -> file
|
||||
return tmpFile();
|
||||
case IO_CLOSE: // io.close([file]) -> void
|
||||
f = args.arg1().isnil()? output(): checkfile(args.arg1());
|
||||
checkopen(f);
|
||||
return ioclose(f);
|
||||
case IO_INPUT: // io.input([file]) -> file
|
||||
infile = args.arg1().isnil()? input(): args.arg1().isstring()?
|
||||
ioopenfile(args.checkjstring(1),"r"):
|
||||
checkfile(args.arg1());
|
||||
return infile;
|
||||
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;
|
||||
}
|
||||
|
||||
case IO_OUTPUT: // io.output(filename) -> file
|
||||
outfile = args.arg1().isnil()? output(): args.arg1().isstring()?
|
||||
ioopenfile(args.checkjstring(1),"w"):
|
||||
checkfile(args.arg1());
|
||||
return outfile;
|
||||
case IO_TYPE: // io.type(obj) -> "file" | "closed file" | nil
|
||||
if ( (f=optfile(args.arg1())) != null )
|
||||
return f.isclosed()? CLOSED_FILE: FILE;
|
||||
return NIL;
|
||||
case IO_POPEN: // io.popen(prog, [mode]) -> file
|
||||
return openProgram(args.checkjstring(1),args.optString(2,"r"));
|
||||
case IO_OPEN: // io.open(filename, [mode]) -> file | nil,err
|
||||
return rawopenfile(args.checkjstring(1), args.optString(2,"r"));
|
||||
case IO_LINES: // io.lines(filename) -> iterator
|
||||
infile = args.arg1().isnil()? input(): ioopenfile(args.checkjstring(1),"r");
|
||||
checkopen(infile);
|
||||
return lines(infile);
|
||||
case IO_READ: // io.read(...) -> (...)
|
||||
checkopen(infile);
|
||||
return ioread(infile,args);
|
||||
case IO_WRITE: // io.write(...) -> void
|
||||
checkopen(output());
|
||||
return iowrite(outfile,args);
|
||||
|
||||
case FILE_CLOSE: // file:close() -> void
|
||||
return ioclose(checkfile(args.arg1()));
|
||||
case FILE_FLUSH: // file:flush() -> void
|
||||
checkfile(args.arg1()).flush();
|
||||
return LuaValue.TRUE;
|
||||
case FILE_SETVBUF: // file:setvbuf(mode,[size]) -> void
|
||||
f = checkfile(args.arg1());
|
||||
f.setvbuf(args.checkjstring(2),args.optint(3, 1024));
|
||||
return LuaValue.TRUE;
|
||||
case FILE_LINES: // file:lines() -> iterator
|
||||
return lines(checkfile(args.arg1()));
|
||||
case FILE_READ: // file:read(...) -> (...)
|
||||
f = checkfile(args.arg1());
|
||||
return ioread(f,args.subargs(2));
|
||||
case FILE_SEEK: // file:seek([whence][,offset]) -> pos | nil,error
|
||||
f = checkfile(args.arg1());
|
||||
n = f.seek(args.optString(2,"cur"),args.optint(3,0));
|
||||
return valueOf(n);
|
||||
case FILE_WRITE: // file:write(...) -> void
|
||||
f = checkfile(args.arg1());
|
||||
return iowrite(f,args.subargs(2));
|
||||
|
||||
case IO_INDEX: // __index, returns a field
|
||||
v = args.arg(2);
|
||||
return v.equals(STDOUT)?output():
|
||||
v.equals(STDIN)? input():
|
||||
v.equals(STDERR)? errput(): NIL;
|
||||
case LINES_ITER: // lines iterator(s,var) -> var'
|
||||
f = checkfile(env);
|
||||
return freadline(f);
|
||||
}
|
||||
} catch ( IOException ioe ) {
|
||||
return errorresult(ioe);
|
||||
public static final class IoLibV extends VarArgFunction {
|
||||
public IoLib iolib;
|
||||
public IoLibV() {
|
||||
}
|
||||
public IoLibV(LuaValue env, String name, int opcode, IoLib iolib) {
|
||||
super();
|
||||
this.env = env;
|
||||
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.arg1());
|
||||
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,1024));
|
||||
case FILE_LINES: return iolib._file_lines(args.arg1());
|
||||
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(env);
|
||||
}
|
||||
} catch ( IOException ioe ) {
|
||||
return errorresult(ioe);
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
|
||||
private File input() {
|
||||
return infile!=null? infile: (infile=ioopenfile("-","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(file.checkjstring(),"r"):
|
||||
checkfile(file);
|
||||
return infile;
|
||||
}
|
||||
|
||||
// io.output(filename) -> file
|
||||
public Varargs _io_output(LuaValue filename) {
|
||||
outfile = filename.isnil()? output():
|
||||
filename.isstring()? ioopenfile(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 {
|
||||
return openProgram(prog, mode);
|
||||
}
|
||||
|
||||
// io.open(filename, [mode]) -> file | nil,err
|
||||
public Varargs _io_open(String filename, String mode) throws IOException {
|
||||
return rawopenfile(filename, mode);
|
||||
}
|
||||
|
||||
// io.lines(filename) -> iterator
|
||||
public Varargs _io_lines(LuaValue filename) {
|
||||
infile = filename.isnil()? input(): ioopenfile(filename.checkjstring(),"r");
|
||||
checkopen(infile);
|
||||
return lines(infile);
|
||||
}
|
||||
|
||||
// io.read(...) -> (...)
|
||||
public Varargs _io_read(Varargs args) throws IOException {
|
||||
checkopen(infile);
|
||||
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) {
|
||||
checkfile(file).setvbuf(mode,size);
|
||||
return LuaValue.TRUE;
|
||||
}
|
||||
|
||||
// file:lines() -> iterator
|
||||
public Varargs _file_lines(LuaValue file) {
|
||||
return lines(checkfile(file));
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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) throws IOException {
|
||||
return freadline(checkfile(file));
|
||||
}
|
||||
|
||||
private File output() {
|
||||
return outfile!=null? outfile: (outfile=ioopenfile("-","w"));
|
||||
}
|
||||
@@ -321,9 +417,7 @@ public class IoLib extends OneArgFunction {
|
||||
|
||||
private Varargs lines(final File f) {
|
||||
try {
|
||||
IoLib iter = (IoLib) getClass().newInstance();
|
||||
iter.setfenv(f);
|
||||
return iter.bindv("lnext",LINES_ITER);
|
||||
return new IoLibV(f,"lnext",LINES_ITER,this);
|
||||
} catch ( Exception e ) {
|
||||
return error("lines: "+e);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ package org.luaj.vm2.lib;
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaFunction;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
abstract public class LibFunction extends LuaFunction {
|
||||
|
||||
@@ -56,253 +55,6 @@ abstract public class LibFunction extends LuaFunction {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void bind0(LuaValue env, String[] names) {
|
||||
bind(env, names, 0, 0);
|
||||
}
|
||||
protected void bind1(LuaValue env, String[] names) {
|
||||
bind(env, names, 1, 0);
|
||||
}
|
||||
protected void bind2(LuaValue env, String[] names) {
|
||||
bind(env, names, 2, 0);
|
||||
}
|
||||
protected void bind3(LuaValue env, String[] names) {
|
||||
bind(env, names, 3, 0);
|
||||
}
|
||||
protected void bindv(LuaValue env, String[] names) {
|
||||
bind(env, names, -1, 0);
|
||||
}
|
||||
protected void bind(LuaValue env, String[] names, int numargs, int firstopcode ) {
|
||||
for ( int i=0, n=names.length; i<n; i++ ) {
|
||||
int opcode = firstopcode + i;
|
||||
String name = names[i];
|
||||
LibFunction binding;
|
||||
switch( numargs ) {
|
||||
case 0: binding = bind0(name, opcode); break;
|
||||
case 1: binding = bind1(name, opcode); break;
|
||||
case 2: binding = bind2(name, opcode); break;
|
||||
case 3: binding = bind3(name, opcode); break;
|
||||
default: binding = bindv(name, opcode); break;
|
||||
}
|
||||
env.set(names[i], binding);
|
||||
}
|
||||
}
|
||||
|
||||
protected LibFunction bind0(String name, int opcode) {
|
||||
return new ZeroArgBinding(name, opcode, this);
|
||||
}
|
||||
protected LibFunction bind1(String name, int opcode) {
|
||||
return new OneArgBinding(name, opcode, this);
|
||||
}
|
||||
protected LibFunction bind2(String name, int opcode) {
|
||||
return new TwoArgBinding(name, opcode, this);
|
||||
}
|
||||
protected LibFunction bind3(String name, int opcode) {
|
||||
return new ThreeArgBinding(name, opcode, this);
|
||||
}
|
||||
protected LibFunction bindv(String name, int opcode) {
|
||||
return new VarArgBinding(name, opcode, this);
|
||||
}
|
||||
|
||||
/** called when a zero-arg function is invoked */
|
||||
protected LuaValue oncall0(int opcode) {
|
||||
return NIL;
|
||||
}
|
||||
|
||||
/** called when a one-arg function is invoked */
|
||||
protected LuaValue oncall1(int opcode, LuaValue arg) {
|
||||
return NIL;
|
||||
}
|
||||
/** called when a two-arg function is invoked */
|
||||
protected LuaValue oncall2(int opcode, LuaValue arg1, LuaValue arg2) {
|
||||
return NIL;
|
||||
}
|
||||
/** called when a three-arg function is invoked */
|
||||
protected LuaValue oncall3(int opcode, LuaValue arg1, LuaValue arg2, LuaValue arg3) {
|
||||
return NIL;
|
||||
}
|
||||
/** called when a var-arg function is invoked */
|
||||
protected Varargs oncallv(int opcode, Varargs args) {
|
||||
return NONE;
|
||||
}
|
||||
|
||||
/** Binding to a one-arg function */
|
||||
private static class ZeroArgBinding extends LibFunction {
|
||||
private final LibFunction delegate;
|
||||
|
||||
private ZeroArgBinding(String name, int opcode, LibFunction delegate) {
|
||||
this.name = name;
|
||||
this.opcode = opcode;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public String tojstring() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public LuaValue call() {
|
||||
return delegate.oncall0(opcode);
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return delegate.oncall0(opcode);
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return delegate.oncall0(opcode);
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
|
||||
return delegate.oncall0(opcode);
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs varargs) {
|
||||
return delegate.oncall0(opcode);
|
||||
}
|
||||
}
|
||||
|
||||
/** Binding to a one-arg function */
|
||||
private static class OneArgBinding extends LibFunction {
|
||||
private final LibFunction delegate;
|
||||
|
||||
private OneArgBinding(String name, int opcode, LibFunction delegate) {
|
||||
this.name = name;
|
||||
this.opcode = opcode;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public String tojstring() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public LuaValue call() {
|
||||
return delegate.oncall1(opcode,NIL);
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return delegate.oncall1(opcode,arg);
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return delegate.oncall1(opcode,arg1);
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
|
||||
return delegate.oncall1(opcode,arg1);
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs varargs) {
|
||||
return delegate.oncall1(opcode,varargs.arg1());
|
||||
}
|
||||
}
|
||||
|
||||
/** Binding to a two-arg function */
|
||||
private static class TwoArgBinding extends LibFunction {
|
||||
private final LibFunction delegate;
|
||||
|
||||
private TwoArgBinding(String name, int opcode, LibFunction delegate) {
|
||||
this.name = name;
|
||||
this.opcode = opcode;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public String tojstring() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public LuaValue call() {
|
||||
return delegate.oncall2(opcode,NIL,NIL);
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return delegate.oncall2(opcode,arg,NIL);
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return delegate.oncall2(opcode,arg1,arg2);
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
|
||||
return delegate.oncall2(opcode,arg1,arg2);
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs varargs) {
|
||||
return delegate.oncall2(opcode,varargs.arg1(),varargs.arg(2));
|
||||
}
|
||||
}
|
||||
|
||||
/** Binding to a three-arg function */
|
||||
private static class ThreeArgBinding extends LibFunction {
|
||||
private final LibFunction delegate;
|
||||
|
||||
private ThreeArgBinding(String name, int opcode, LibFunction delegate) {
|
||||
this.name = name;
|
||||
this.opcode = opcode;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public String tojstring() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public LuaValue call() {
|
||||
return delegate.oncall3(opcode,NIL,NIL,NIL);
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return delegate.oncall3(opcode,arg,NIL,NIL);
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return delegate.oncall3(opcode,arg1,arg2,NIL);
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
|
||||
return delegate.oncall3(opcode,arg1,arg2,arg3);
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs varargs) {
|
||||
return delegate.oncall3(opcode,varargs.arg1(),varargs.arg(2),varargs.arg(3));
|
||||
}
|
||||
}
|
||||
|
||||
/** Binding to a var-arg function */
|
||||
private static class VarArgBinding extends LibFunction {
|
||||
private final LibFunction delegate;
|
||||
|
||||
private VarArgBinding(String name, int opcode, LibFunction delegate) {
|
||||
this.name = name;
|
||||
this.opcode = opcode;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public String tojstring() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public LuaValue call() {
|
||||
return delegate.oncallv(opcode,NONE).arg1();
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return delegate.oncallv(opcode,arg).arg1();
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return delegate.oncallv(opcode,varargsOf(arg1,arg2)).arg1();
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
|
||||
return delegate.oncallv(opcode,varargsOf(arg1,arg2,arg3)).arg1();
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs varargs) {
|
||||
return delegate.oncallv(opcode,varargs);
|
||||
}
|
||||
}
|
||||
|
||||
// -------- code generation helper functions --------
|
||||
|
||||
// allocate storage for upvalue, leave it empty
|
||||
protected static LuaValue[] newupe() {
|
||||
return new LuaValue[1];
|
||||
|
||||
@@ -30,13 +30,13 @@ import org.luaj.vm2.Varargs;
|
||||
/**
|
||||
* Base implementation of OsLib, with simplified stub functions
|
||||
* for library functions that cannot be implemented uniformly
|
||||
* on J2se and J2me.
|
||||
* on Jse and Jme.
|
||||
*
|
||||
* <p>
|
||||
* This can be installed as-is on either platform, or extended
|
||||
* and refined to be used in a complete J2se implementation.
|
||||
* and refined to be used in a complete Jse implementation.
|
||||
*
|
||||
* <p>Contains limited implementations of features not supported well on J2me:
|
||||
* <p>Contains limited implementations of features not supported well on Jme:
|
||||
* <bl>
|
||||
* <li>execute()</li>
|
||||
* <li>remove()</li>
|
||||
@@ -46,21 +46,22 @@ import org.luaj.vm2.Varargs;
|
||||
*
|
||||
* @see org.luaj.vm2.lib.jse.JseOsLib
|
||||
*/
|
||||
public class OsLib extends OneArgFunction {
|
||||
public class OsLib extends VarArgFunction {
|
||||
public static String TMP_PREFIX = ".luaj";
|
||||
public static 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 int INIT = 0;
|
||||
private static final int CLOCK = 1;
|
||||
private static final int DATE = 2;
|
||||
private static final int DIFFTIME = 3;
|
||||
private static final int EXECUTE = 4;
|
||||
private static final int EXIT = 5;
|
||||
private static final int GETENV = 6;
|
||||
private static final int REMOVE = 7;
|
||||
private static final int RENAME = 8;
|
||||
private static final int SETLOCALE = 9;
|
||||
private static final int TIME = 10;
|
||||
private static final int TMPNAME = 11;
|
||||
|
||||
private static final String[] NAMES = {
|
||||
"clock",
|
||||
@@ -85,27 +86,29 @@ public class OsLib extends OneArgFunction {
|
||||
public OsLib() {
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg) {
|
||||
public LuaValue init() {
|
||||
LuaTable t = new LuaTable();
|
||||
bindv(t, NAMES);
|
||||
bind(t, this.getClass(), NAMES, CLOCK);
|
||||
env.set("os", t);
|
||||
return t;
|
||||
}
|
||||
|
||||
protected Varargs oncallv(int opcode, Varargs args) {
|
||||
public Varargs invoke(Varargs args) {
|
||||
try {
|
||||
switch ( opcode ) {
|
||||
case INIT:
|
||||
return init();
|
||||
case CLOCK:
|
||||
return valueOf(clock());
|
||||
case DATE: {
|
||||
String s = args.optString(1, null);
|
||||
String s = args.optjstring(1, null);
|
||||
double t = args.optdouble(2,-1);
|
||||
return valueOf( date(s, t==-1? System.currentTimeMillis()/1000.: t) );
|
||||
}
|
||||
case DIFFTIME:
|
||||
return valueOf(difftime(args.checkdouble(1),args.checkdouble(2)));
|
||||
case EXECUTE:
|
||||
return valueOf(execute(args.optString(1, null)));
|
||||
return valueOf(execute(args.optjstring(1, null)));
|
||||
case EXIT:
|
||||
exit(args.optint(1, 0));
|
||||
return NONE;
|
||||
@@ -120,7 +123,7 @@ public class OsLib extends OneArgFunction {
|
||||
rename(args.checkjstring(1), args.checkjstring(2));
|
||||
return LuaValue.TRUE;
|
||||
case SETLOCALE: {
|
||||
String s = setlocale(args.optString(1,null), args.optString(2, "all"));
|
||||
String s = setlocale(args.optjstring(1,null), args.optjstring(2, "all"));
|
||||
return s!=null? valueOf(s): NIL;
|
||||
}
|
||||
case TIME:
|
||||
@@ -284,6 +287,8 @@ public class OsLib extends OneArgFunction {
|
||||
* @return String filename to use
|
||||
*/
|
||||
protected String tmpname() {
|
||||
return TMP_PREFIX+(tmpnames++)+TMP_SUFFIX;
|
||||
synchronized ( OsLib.class ) {
|
||||
return TMP_PREFIX+(tmpnames++)+TMP_SUFFIX;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,6 @@ public class PackageLib extends OneArgFunction {
|
||||
private static final LuaString _PRELOAD = valueOf("preload");
|
||||
private static final LuaString _PATH = valueOf("path");
|
||||
private static final LuaString _SEEALL = valueOf("seeall");
|
||||
private static final LuaString _LOADFILE = valueOf("loadfile");
|
||||
private static final LuaString _SENTINEL = valueOf("\u0001");
|
||||
|
||||
private static final int MODULE = 0;
|
||||
@@ -67,55 +66,73 @@ public class PackageLib extends OneArgFunction {
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg) {
|
||||
env.set("require", bind1("require",REQUIRE));
|
||||
env.set("module", bindv("module",MODULE));
|
||||
env.set("require", new PkgLib1(env,"require",REQUIRE,this));
|
||||
env.set("module", new PkgLibV(env,"module",MODULE,this));
|
||||
env.set( "package", PACKAGE=tableOf( new LuaValue[] {
|
||||
_LOADED, LOADED=tableOf(),
|
||||
_PRELOAD, tableOf(),
|
||||
_PATH, valueOf(DEFAULT_LUA_PATH),
|
||||
_LOADLIB, bindv("loadlib",LOADLIB),
|
||||
_SEEALL, bind1("seeall",SEEALL),
|
||||
_LOADLIB, new PkgLibV(env,"loadlib",LOADLIB,this),
|
||||
_SEEALL, new PkgLib1(env,"seeall",SEEALL,this),
|
||||
_LOADERS, listOf(new LuaValue[] {
|
||||
bindv("preload_loader", PRELOAD_LOADER),
|
||||
bindv("lua_loader", LUA_LOADER),
|
||||
bindv("java_loader", JAVA_LOADER),
|
||||
new PkgLibV(env,"preload_loader", PRELOAD_LOADER,this),
|
||||
new PkgLibV(env,"lua_loader", LUA_LOADER,this),
|
||||
new PkgLibV(env,"java_loader", JAVA_LOADER,this),
|
||||
}) }) );
|
||||
return env;
|
||||
}
|
||||
|
||||
protected LuaValue oncall1(int opcode, LuaValue arg) {
|
||||
switch ( opcode ) {
|
||||
case REQUIRE:
|
||||
return require(arg);
|
||||
case SEEALL: {
|
||||
LuaTable t = arg.checktable();
|
||||
LuaValue m = t.getmetatable();
|
||||
if ( m == null )
|
||||
t.setmetatable(m=tableOf());
|
||||
m.set( INDEX, LuaThread.getGlobals() );
|
||||
return NONE;
|
||||
public static final class PkgLib1 extends OneArgFunction {
|
||||
PackageLib lib;
|
||||
public PkgLib1(LuaValue env,String name, int opcode, PackageLib lib) {
|
||||
this.env = env;
|
||||
this.name = name;
|
||||
this.opcode = opcode;
|
||||
this.lib = lib;
|
||||
}
|
||||
public LuaValue call(LuaValue arg) {
|
||||
switch ( opcode ) {
|
||||
case REQUIRE:
|
||||
return lib.require(arg);
|
||||
case SEEALL: {
|
||||
LuaTable t = arg.checktable();
|
||||
LuaValue m = t.getmetatable();
|
||||
if ( m == null )
|
||||
t.setmetatable(m=tableOf());
|
||||
m.set( INDEX, LuaThread.getGlobals() );
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
|
||||
protected Varargs oncallv(int opcode, Varargs args) {
|
||||
switch ( opcode ) {
|
||||
case MODULE:
|
||||
return module(args);
|
||||
case LOADLIB:
|
||||
return loadlib(args);
|
||||
case PRELOAD_LOADER: {
|
||||
return loader_preload(args);
|
||||
public static final class PkgLibV extends VarArgFunction {
|
||||
PackageLib lib;
|
||||
public PkgLibV(LuaValue env,String name, int opcode, PackageLib lib) {
|
||||
this.env = env;
|
||||
this.name = name;
|
||||
this.opcode = opcode;
|
||||
this.lib = lib;
|
||||
}
|
||||
case LUA_LOADER: {
|
||||
return loader_Lua(args);
|
||||
public Varargs invoke(Varargs args) {
|
||||
switch ( opcode ) {
|
||||
case MODULE:
|
||||
return lib.module(args);
|
||||
case LOADLIB:
|
||||
return loadlib(args);
|
||||
case PRELOAD_LOADER: {
|
||||
return lib.loader_preload(args);
|
||||
}
|
||||
case LUA_LOADER: {
|
||||
return lib.loader_Lua(args);
|
||||
}
|
||||
case JAVA_LOADER: {
|
||||
return lib.loader_Java(args);
|
||||
}
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
case JAVA_LOADER: {
|
||||
return loader_Java(args);
|
||||
}
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
|
||||
/** Allow packages to mark themselves as loaded */
|
||||
|
||||
@@ -30,32 +30,25 @@ public class TableLib extends OneArgFunction {
|
||||
public TableLib() {
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg) {
|
||||
private LuaTable init() {
|
||||
LuaTable t = new LuaTable();
|
||||
bind(t, TableLib1.class, new String[] {
|
||||
"getn", // (table) -> number
|
||||
"maxn", // (table) -> number
|
||||
} );
|
||||
bind(t, TableLib.class, new String[] { "getn", "maxn", }, 1 );
|
||||
bind(t, TableLibV.class, new String[] {
|
||||
"remove", // (table [, pos]) -> removed-ele
|
||||
"concat", // (table [, sep [, i [, j]]]) -> string
|
||||
"insert", // (table, [pos,] value) -> prev-ele
|
||||
"sort", // (table [, comp]) -> void
|
||||
"foreach", // (table, func) -> void
|
||||
"foreachi", // (table, func) -> void
|
||||
} );
|
||||
"remove", "concat", "insert", "sort", "foreach", "foreachi", } );
|
||||
env.set("table", t);
|
||||
return t;
|
||||
}
|
||||
|
||||
public static final class TableLib1 extends OneArgFunction {
|
||||
public LuaValue call(LuaValue arg) {
|
||||
switch ( opcode ) {
|
||||
case 0: return arg.checktable().getn();
|
||||
case 1: return valueOf( arg.checktable().maxn());
|
||||
}
|
||||
return NIL;
|
||||
public LuaValue call(LuaValue arg) {
|
||||
switch ( opcode ) {
|
||||
case 0: // init library
|
||||
return init();
|
||||
case 1: // "getn" (table) -> number
|
||||
return arg.checktable().getn();
|
||||
case 2: // "maxn" (table) -> number
|
||||
return valueOf( arg.checktable().maxn());
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
|
||||
public static final class TableLibV extends VarArgFunction {
|
||||
|
||||
@@ -43,25 +43,28 @@ import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaUserdata;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.lib.BaseLib;
|
||||
import org.luaj.vm2.lib.OneArgFunction;
|
||||
import org.luaj.vm2.lib.ThreeArgFunction;
|
||||
import org.luaj.vm2.lib.TwoArgFunction;
|
||||
import org.luaj.vm2.lib.VarArgFunction;
|
||||
|
||||
public class LuajavaLib extends OneArgFunction {
|
||||
public class LuajavaLib extends VarArgFunction {
|
||||
|
||||
private static final int BINDCLASS = 0;
|
||||
private static final int NEWINSTANCE = 1;
|
||||
private static final int NEW = 2;
|
||||
private static final int CREATEPROXY = 3;
|
||||
private static final int LOADLIB = 4;
|
||||
private static final int INIT = 0;
|
||||
private static final int BINDCLASS = 1;
|
||||
private static final int NEWINSTANCE = 2;
|
||||
private static final int NEW = 3;
|
||||
private static final int CREATEPROXY = 4;
|
||||
private static final int LOADLIB = 5;
|
||||
|
||||
private static final String[] NAMES = {
|
||||
"bindClass",
|
||||
"newInstance",
|
||||
"new",
|
||||
"createProxy",
|
||||
"loadLib" };
|
||||
"loadLib",
|
||||
};
|
||||
|
||||
private static final Map classMetatables = new HashMap();
|
||||
|
||||
@@ -76,16 +79,15 @@ public class LuajavaLib extends OneArgFunction {
|
||||
public LuajavaLib() {
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg) {
|
||||
LuaTable t = new LuaTable();
|
||||
bindv( t, NAMES );
|
||||
env.set("luajava", t);
|
||||
return t;
|
||||
}
|
||||
|
||||
protected Varargs oncallv(int opcode, Varargs args) {
|
||||
public Varargs invoke(Varargs args) {
|
||||
try {
|
||||
switch ( opcode ) {
|
||||
case INIT: {
|
||||
LuaTable t = new LuaTable();
|
||||
bind( t, LuajavaLib.class, NAMES, BINDCLASS );
|
||||
env.set("luajava", t);
|
||||
return t;
|
||||
}
|
||||
case BINDCLASS: {
|
||||
final Class clazz = Class.forName(args.checkjstring(1));
|
||||
return toUserdata( clazz, clazz );
|
||||
|
||||
@@ -765,22 +765,22 @@ public class TypeTest extends TestCase {
|
||||
public void testOptJavaString() {
|
||||
assertEquals( "xyz", somenil.optjstring("xyz") );
|
||||
assertEquals( null, somenil.optjstring(null) );
|
||||
throwsError( sometrue, "optString", String.class, "xyz" );
|
||||
throwsError( somefalse, "optString", String.class, "xyz" );
|
||||
throwsError( sometrue, "optjstring", String.class, "xyz" );
|
||||
throwsError( somefalse, "optjstring", String.class, "xyz" );
|
||||
assertEquals( String.valueOf(zero), zero.optjstring("xyz") );
|
||||
assertEquals( String.valueOf(intint), intint.optjstring("xyz") );
|
||||
assertEquals( String.valueOf(longdouble), longdouble.optjstring("xyz") );
|
||||
assertEquals( String.valueOf(doubledouble), doubledouble.optjstring("xyz") );
|
||||
throwsError( somefunc, "optString", String.class, "xyz" );
|
||||
throwsError( someclosure, "optString", String.class, "xyz" );
|
||||
throwsError( somefunc, "optjstring", String.class, "xyz" );
|
||||
throwsError( someclosure, "optjstring", String.class, "xyz" );
|
||||
assertEquals( samplestringstring, stringstring.optjstring("xyz") );
|
||||
assertEquals( samplestringint, stringint.optjstring("xyz") );
|
||||
assertEquals( samplestringlong, stringlong.optjstring("xyz") );
|
||||
assertEquals( samplestringdouble, stringdouble.optjstring("xyz") );
|
||||
throwsError( thread, "optString", String.class, "xyz" );
|
||||
throwsError( table, "optString", String.class, "xyz" );
|
||||
throwsError( userdataobj, "optString", String.class, "xyz" );
|
||||
throwsError( userdatacls, "optString", String.class, "xyz" );
|
||||
throwsError( thread, "optjstring", String.class, "xyz" );
|
||||
throwsError( table, "optjstring", String.class, "xyz" );
|
||||
throwsError( userdataobj, "optjstring", String.class, "xyz" );
|
||||
throwsError( userdatacls, "optjstring", String.class, "xyz" );
|
||||
}
|
||||
|
||||
public void testOptLuaString() {
|
||||
|
||||
Reference in New Issue
Block a user