Refactor base library for lua 5.2 compatibility

This commit is contained in:
James Roseborough
2012-09-11 06:20:51 +00:00
parent 84fec1ae67
commit a9c5c64e0f
2 changed files with 294 additions and 208 deletions

View File

@@ -86,39 +86,6 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
*/ */
public static ResourceFinder FINDER; public static ResourceFinder FINDER;
private LuaValue next;
private LuaValue inext;
private static final String[] LIB1_KEYS = {
"getmetatable", // ( object ) -> table
"rawlen", // (v) -> value
"tostring", // (e) -> value
"type", // (v) -> value
};
private static final String[] LIB2_KEYS = {
"collectgarbage", // ( opt [,arg] ) -> value
"error", // ( message [,level] ) -> ERR
"rawequal", // (v1, v2) -> boolean
"rawget", // (table, index) -> value
};
private static final String[] LIBV_KEYS = {
"assert", // ( v [,message] ) -> v, message | ERR
"dofile", // ( filename ) -> result1, ...
"load", // ( ld [, source [, mode [, env]]] ) -> chunk | nil, msg
"loadfile", // ( [filename [, mode [, env]]] ) -> chunk | nil, msg
"pcall", // (f, arg1, ...) -> status, result1, ...
"xpcall", // (f, err) -> result1, ...
"print", // (...) -> void
"select", // (f, ...) -> value1, ...
"rawset", // (table, index, value) -> table
"setmetatable", // (table, metatable) -> table
"tonumber", // (e [,base]) -> value
"pairs", // "pairs" (t) -> iter-func, t, nil
"ipairs", // "ipairs", // (t) -> iter-func, t, 0
"next", // "next" ( table, [index] ) -> next-index, next-value
"__inext", // "inext" ( table, [int-index] ) -> next-index, next-value
};
/** /**
* Construct a base libarary instance. * Construct a base libarary instance.
*/ */
@@ -129,17 +96,30 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
public LuaValue call(LuaValue env) { public LuaValue call(LuaValue env) {
env.set( "_G", env ); env.set( "_G", env );
env.set( "_VERSION", Lua._VERSION ); env.set( "_VERSION", Lua._VERSION );
bind( env, BaseLib1.class, LIB1_KEYS ); env.set("assert", new _assert());
bind( env, BaseLib2.class, LIB2_KEYS ); env.set("collectgarbage", new collectgarbage());
bind( env, BaseLibV.class, LIBV_KEYS ); env.set("dofile", new dofile(this));
env.set("error", new error());
env.set("getmetatable", new getmetatable());
env.set("load", new load());
env.set("loadfile", new loadfile(this));
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());
// remember next, and inext for use in pairs and ipairs next next;
next = env.get("next"); env.set("next", next = new next());
inext = env.get("__inext"); env.set("pairs", new pairs(next));
env.set("ipairs", new ipairs());
// inject base lib int vararg instances
for ( int i=0; i<LIBV_KEYS.length; i++ )
((BaseLibV) env.get(LIBV_KEYS[i])).baselib = this;
// set the default resource finder if not set already // set the default resource finder if not set already
if ( FINDER == null ) if ( FINDER == null )
@@ -149,56 +129,34 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
/** ResourceFinder implementation /** ResourceFinder implementation
* *
* Tries to open the file as a resource, which can work for . * Tries to open the file as a resource, which can work for JSE and JME.
*/ */
public InputStream findResource(String filename) { public InputStream findResource(String filename) {
Class c = getClass(); Class c = getClass();
return c.getResourceAsStream(filename.startsWith("/")? filename: "/"+filename); return c.getResourceAsStream(filename.startsWith("/")? filename: "/"+filename);
} }
static final class BaseLib1 extends OneArgFunction {
public LuaValue call(LuaValue arg) { // "assert", // ( v [,message] ) -> v, message | ERR
switch ( opcode ) { static final class _assert extends VarArgFunction {
case 0: // "getmetatable", // ( object ) -> table public Varargs invoke(Varargs args) {
{ if ( !args.arg1().toboolean() )
LuaValue mt = arg.getmetatable(); error( args.narg()>1? args.optjstring(2,"assertion failed!"): "assertion failed!" );
return mt!=null? mt.rawget(METATABLE).optvalue(mt): NIL; return args;
}
case 1: // "rawlen", // (v) -> value
{
return valueOf(arg.rawlen());
}
case 2: // "tostring", // (e) -> value
{
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());
}
case 3: // "type", // (v) -> value
{
return valueOf(arg.typename());
}
}
return NIL;
} }
} }
static final class BaseLib2 extends TwoArgFunction { // "collectgarbage", // ( opt [,arg] ) -> value
public LuaValue call(LuaValue arg1, LuaValue arg2) { static final class collectgarbage extends VarArgFunction {
switch ( opcode ) { public Varargs invoke(Varargs args) {
case 0: // "collectgarbage", // ( opt [,arg] ) -> value String s = args.checkjstring(1);
String s = arg1.checkjstring();
if ( "collect".equals(s) ) { if ( "collect".equals(s) ) {
System.gc(); System.gc();
return ZERO; return ZERO;
} else if ( "count".equals(s) ) { } else if ( "count".equals(s) ) {
Runtime rt = Runtime.getRuntime(); Runtime rt = Runtime.getRuntime();
long used = rt.totalMemory() - rt.freeMemory(); long used = rt.totalMemory() - rt.freeMemory();
return valueOf(used/1024.); return varargsOf(valueOf(used/1024.), valueOf(used%1024));
} else if ( "step".equals(s) ) { } else if ( "step".equals(s) ) {
System.gc(); System.gc();
return LuaValue.TRUE; return LuaValue.TRUE;
@@ -206,27 +164,16 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
this.argerror("gc op"); this.argerror("gc op");
} }
return NIL; return NIL;
case 1: // "error", // ( message [,level] ) -> ERR
throw new LuaError( arg1.isnil()? null: arg1.tojstring(), arg2.optint(1) );
case 2: // "rawequal", // (v1, v2) -> boolean
return valueOf(arg1.raweq(arg2));
case 3: // "rawget", // (table, index) -> value
return arg1.rawget(arg2);
}
return NIL;
} }
} }
static final class BaseLibV extends VarArgFunction { // "dofile", // ( filename ) -> result1, ...
public BaseLib baselib; static final class dofile extends VarArgFunction {
final BaseLib baselib;
dofile(BaseLib baselib) {
this.baselib = baselib;
}
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
switch ( opcode ) {
case 0: // "assert", // ( v [,message] ) -> v, message | ERR
if ( !args.arg1().toboolean() )
error( args.narg()>1? args.optjstring(2,"assertion failed!"): "assertion failed!" );
return args;
case 1: // "dofile", // ( filename ) -> result1, ...
{
args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or nil"); 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 filename = args.isstring(1)? args.tojstring(1): null;
Varargs v = filename == null? Varargs v = filename == null?
@@ -234,8 +181,28 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
BaseLib.loadFile( args.checkjstring(1), "bt",LuaValue._G ); BaseLib.loadFile( args.checkjstring(1), "bt",LuaValue._G );
return v.isnil(1)? error(v.tojstring(2)): v.arg1().invoke(); return v.isnil(1)? error(v.tojstring(2)): v.arg1().invoke();
} }
case 2: // "load", // ( ld [, source [, mode [, env]]] ) -> chunk | nil, msg }
{
// "error", // ( message [,level] ) -> ERR
static final class error extends TwoArgFunction {
public LuaValue call(LuaValue arg1, LuaValue arg2) {
throw new LuaError( arg1.isnil()? null: arg1.tojstring(), arg2.optint(1) );
}
}
// "getmetatable", // ( object ) -> table
static final class getmetatable extends LibFunction {
public LuaValue call() {
return argerror(1, "value");
}
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
static final class load extends VarArgFunction {
public Varargs invoke(Varargs args) {
LuaValue ld = args.arg1(); LuaValue ld = args.arg1();
args.argcheck(ld.isstring() || ld.isfunction(), 1, "ld must be string or function"); args.argcheck(ld.isstring() || ld.isfunction(), 1, "ld must be string or function");
String source = args.optjstring(2, ld.isstring()? ld.tojstring(): "=(load)"); String source = args.optjstring(2, ld.isstring()? ld.tojstring(): "=(load)");
@@ -244,8 +211,15 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
return BaseLib.loadStream(ld.isstring()? ld.strvalue().toInputStream(): return BaseLib.loadStream(ld.isstring()? ld.strvalue().toInputStream():
new StringInputStream(ld.checkfunction()), source, mode, env); new StringInputStream(ld.checkfunction()), source, mode, env);
} }
case 3: // "loadfile", // ( [filename [, mode [, env]]] ) -> chunk | nil, msg }
{
// "loadfile", // ( [filename [, mode [, env]]] ) -> chunk | nil, msg
static final class loadfile extends VarArgFunction {
final BaseLib baselib;
loadfile(BaseLib baselib) {
this.baselib = baselib;
}
public Varargs invoke(Varargs args) {
args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or nil"); 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 filename = args.isstring(1)? args.tojstring(1): null;
String mode = args.optjstring(2, "bt"); String mode = args.optjstring(2, "bt");
@@ -254,8 +228,11 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
BaseLib.loadStream( baselib.STDIN, "=stdin", mode, env ): BaseLib.loadStream( baselib.STDIN, "=stdin", mode, env ):
BaseLib.loadFile( filename, mode, env ); BaseLib.loadFile( filename, mode, env );
} }
case 4: // "pcall", // (f, arg1, ...) -> status, result1, ... }
{
// "pcall", // (f, arg1, ...) -> status, result1, ...
static final class pcall extends VarArgFunction {
public Varargs invoke(Varargs args) {
LuaValue func = args.checkvalue(1); LuaValue func = args.checkvalue(1);
LuaThread.CallStack cs = LuaThread.onCall(this); LuaThread.CallStack cs = LuaThread.onCall(this);
try { try {
@@ -264,17 +241,15 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
cs.onReturn(); cs.onReturn();
} }
} }
case 5: // "xpcall", // (f, err) -> result1, ...
{
LuaThread.CallStack cs = LuaThread.onCall(this);
try {
return pcall(args.arg1(),NONE,args.checkvalue(2));
} finally {
cs.onReturn();
} }
// "print", // (...) -> void
static final class print extends VarArgFunction {
final BaseLib baselib;
print(BaseLib baselib) {
this.baselib = baselib;
} }
case 6: // "print", // (...) -> void public Varargs invoke(Varargs args) {
{
LuaValue tostring =LuaValue._G.get("tostring"); LuaValue tostring =LuaValue._G.get("tostring");
for ( int i=1, n=args.narg(); i<=n; i++ ) { for ( int i=1, n=args.narg(); i<=n; i++ ) {
if ( i>1 ) baselib.STDOUT.write( '\t' ); if ( i>1 ) baselib.STDOUT.write( '\t' );
@@ -285,8 +260,61 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
baselib.STDOUT.println(); baselib.STDOUT.println();
return NONE; return NONE;
} }
case 7: // "select", // (f, ...) -> value1, ... }
{
// "rawequal", // (v1, v2) -> boolean
static final class rawequal extends LibFunction {
public LuaValue call() {
return argerror(1, "value");
}
public LuaValue call(LuaValue arg) {
return argerror(2, "value");
}
public LuaValue call(LuaValue arg1, LuaValue arg2) {
return valueOf(arg1.raweq(arg2));
}
}
// "rawget", // (table, index) -> value
static final class rawget extends LibFunction {
public LuaValue call() {
return argerror(1, "value");
}
public LuaValue call(LuaValue arg) {
return argerror(2, "value");
}
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 LibFunction {
public LuaValue call(LuaValue table) {
return argerror(2,"value");
}
public LuaValue call(LuaValue table, LuaValue index) {
return argerror(3,"value");
}
public LuaValue call(LuaValue table, LuaValue index, LuaValue value) {
LuaTable t = table.checktable();
t.rawset(index.checknotnil(), value);
return t;
}
}
// "select", // (f, ...) -> value1, ...
static final class select extends VarArgFunction {
public Varargs invoke(Varargs args) {
int n = args.narg()-1; int n = args.narg()-1;
if ( args.arg1().equals(valueOf("#")) ) if ( args.arg1().equals(valueOf("#")) )
return valueOf(n); return valueOf(n);
@@ -295,40 +323,98 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
argerror(1,"index out of range"); argerror(1,"index out of range");
return args.subargs(i<0? n+i+2: i+1); return args.subargs(i<0? n+i+2: i+1);
} }
case 8: { // "rawset", // (table, index, value) -> table
LuaTable t = args.checktable(1);
t.rawset(args.checknotnil(2), args.checkvalue(3));
return t;
} }
case 9: { // "setmetatable", // (table, metatable) -> table
final LuaValue t = args.arg1(); // "setmetatable", // (table, metatable) -> table
final LuaValue mt0 = t.getmetatable(); static final class setmetatable extends LibFunction {
public LuaValue call(LuaValue table) {
return argerror(2,"value");
}
public LuaValue call(LuaValue table, LuaValue metatable) {
final LuaValue mt0 = table.getmetatable();
if ( mt0!=null && !mt0.rawget(METATABLE).isnil() ) if ( mt0!=null && !mt0.rawget(METATABLE).isnil() )
error("cannot change a protected metatable"); error("cannot change a protected metatable");
final LuaValue mt = args.checkvalue(2); return table.setmetatable(metatable.isnil()? null: metatable.checktable());
return t.setmetatable(mt.isnil()? null: mt.checktable());
} }
case 10: { // "tonumber", // (e [,base]) -> value }
LuaValue arg1 = args.checkvalue(1);
final int base = args.optint(2,10); // "tonumber", // (e [,base]) -> value
if (base == 10) { /* standard conversion */ static final class tonumber extends LibFunction {
return arg1.tonumber(); public LuaValue call(LuaValue e) {
} else { return e.tonumber();
if ( base < 2 || base > 36 ) }
public LuaValue call(LuaValue e, LuaValue base) {
if (base.isnil())
return e.tonumber();
final int b = base.optint(10);
if ( b < 2 || b > 36 )
argerror(2, "base out of range"); argerror(2, "base out of range");
return arg1.checkstring().tonumber(base); return e.checkstring().tonumber(b);
} }
} }
case 11: // "pairs" (t) -> iter-func, t, nil
return varargsOf( baselib.next, args.checktable(1), NIL ); // "tostring", // (e) -> value
case 12: // "ipairs", // (t) -> iter-func, t, 0 static final class tostring extends LibFunction {
return varargsOf( baselib.inext, args.checktable(1), ZERO ); public LuaValue call(LuaValue arg) {
case 13: // "next" ( table, [index] ) -> next-index, next-value 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, ...
static final class xpcall extends VarArgFunction {
public Varargs invoke(Varargs args) {
LuaThread.CallStack cs = LuaThread.onCall(this);
try {
return pcall(args.arg1(),NONE,args.checkvalue(2));
} finally {
cs.onReturn();
}
}
}
// "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)); return args.checktable(1).next(args.arg(2));
case 14: // "inext" ( table, [int-index] ) -> next-index, next-value
return args.checktable(1).inext(args.arg(2));
} }
return NONE; }
// "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));
} }
} }

View File

@@ -193,7 +193,7 @@ abstract public class LibFunction extends LuaFunction {
} }
public LuaValue call() { public LuaValue call() {
return typerror("value"); return argerror(1,"value");
} }
public LuaValue call(LuaValue a) { public LuaValue call(LuaValue a) {
return call(); return call();