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;
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.
*/
@@ -129,17 +96,30 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
public LuaValue call(LuaValue env) {
env.set( "_G", env );
env.set( "_VERSION", Lua._VERSION );
bind( env, BaseLib1.class, LIB1_KEYS );
bind( env, BaseLib2.class, LIB2_KEYS );
bind( env, BaseLibV.class, LIBV_KEYS );
// remember next, and inext for use in pairs and ipairs
next = env.get("next");
inext = env.get("__inext");
// inject base lib int vararg instances
for ( int i=0; i<LIBV_KEYS.length; i++ )
((BaseLibV) env.get(LIBV_KEYS[i])).baselib = this;
env.set("assert", new _assert());
env.set("collectgarbage", new collectgarbage());
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());
next next;
env.set("next", next = new next());
env.set("pairs", new pairs(next));
env.set("ipairs", new ipairs());
// set the default resource finder if not set already
if ( FINDER == null )
@@ -149,188 +129,294 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
/** 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) {
Class c = getClass();
return c.getResourceAsStream(filename.startsWith("/")? filename: "/"+filename);
}
static final class BaseLib1 extends OneArgFunction {
public LuaValue call(LuaValue arg) {
switch ( opcode ) {
case 0: // "getmetatable", // ( object ) -> table
{
LuaValue mt = arg.getmetatable();
return mt!=null? mt.rawget(METATABLE).optvalue(mt): NIL;
}
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;
// "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;
}
}
static final class BaseLib2 extends TwoArgFunction {
public LuaValue call(LuaValue arg1, LuaValue arg2) {
switch ( opcode ) {
case 0: // "collectgarbage", // ( opt [,arg] ) -> value
String s = arg1.checkjstring();
if ( "collect".equals(s) ) {
System.gc();
return ZERO;
} else if ( "count".equals(s) ) {
Runtime rt = Runtime.getRuntime();
long used = rt.totalMemory() - rt.freeMemory();
return valueOf(used/1024.);
} else if ( "step".equals(s) ) {
System.gc();
return LuaValue.TRUE;
} else {
this.argerror("gc op");
}
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);
// "collectgarbage", // ( opt [,arg] ) -> value
static final class collectgarbage extends VarArgFunction {
public Varargs invoke(Varargs args) {
String s = args.checkjstring(1);
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 {
this.argerror("gc op");
}
return NIL;
}
}
static final class BaseLibV extends VarArgFunction {
public BaseLib baselib;
// "dofile", // ( filename ) -> result1, ...
static final class dofile extends VarArgFunction {
final BaseLib baselib;
dofile(BaseLib baselib) {
this.baselib = baselib;
}
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");
String filename = args.isstring(1)? args.tojstring(1): null;
Varargs v = filename == null?
BaseLib.loadStream( baselib.STDIN, "=stdin", "bt",LuaValue._G ):
BaseLib.loadFile( args.checkjstring(1), "bt",LuaValue._G );
return v.isnil(1)? error(v.tojstring(2)): v.arg1().invoke();
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?
BaseLib.loadStream( baselib.STDIN, "=stdin", "bt",LuaValue._G ):
BaseLib.loadFile( args.checkjstring(1), "bt",LuaValue._G );
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) {
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();
args.argcheck(ld.isstring() || ld.isfunction(), 1, "ld must be string or function");
String source = args.optjstring(2, ld.isstring()? ld.tojstring(): "=(load)");
String mode = args.optjstring(3, "bt");
LuaValue env = args.optvalue(4,LuaValue._G);
return BaseLib.loadStream(ld.isstring()? ld.strvalue().toInputStream():
new StringInputStream(ld.checkfunction()), source, mode, env);
}
}
// "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");
String filename = args.isstring(1)? args.tojstring(1): null;
String mode = args.optjstring(2, "bt");
LuaValue env = args.optvalue(3,LuaValue._G);
return filename == null?
BaseLib.loadStream( baselib.STDIN, "=stdin", mode, env ):
BaseLib.loadFile( filename, mode, env );
}
}
// "pcall", // (f, arg1, ...) -> status, result1, ...
static final class pcall extends VarArgFunction {
public Varargs invoke(Varargs args) {
LuaValue func = args.checkvalue(1);
LuaThread.CallStack cs = LuaThread.onCall(this);
try {
return pcall(func,args.subargs(2),null);
} finally {
cs.onReturn();
}
case 2: // "load", // ( ld [, source [, mode [, env]]] ) -> chunk | nil, msg
{
LuaValue ld = args.arg1();
args.argcheck(ld.isstring() || ld.isfunction(), 1, "ld must be string or function");
String source = args.optjstring(2, ld.isstring()? ld.tojstring(): "=(load)");
String mode = args.optjstring(3, "bt");
LuaValue env = args.optvalue(4,LuaValue._G);
return BaseLib.loadStream(ld.isstring()? ld.strvalue().toInputStream():
new StringInputStream(ld.checkfunction()), source, mode, env);
}
case 3: // "loadfile", // ( [filename [, mode [, env]]] ) -> chunk | nil, msg
{
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,LuaValue._G);
return filename == null?
BaseLib.loadStream( baselib.STDIN, "=stdin", mode, env ):
BaseLib.loadFile( filename, mode, env );
}
case 4: // "pcall", // (f, arg1, ...) -> status, result1, ...
{
LuaValue func = args.checkvalue(1);
LuaThread.CallStack cs = LuaThread.onCall(this);
try {
return pcall(func,args.subargs(2),null);
} finally {
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();
}
}
case 6: // "print", // (...) -> void
{
LuaValue tostring =LuaValue._G.get("tostring");
for ( int i=1, n=args.narg(); i<=n; i++ ) {
if ( i>1 ) baselib.STDOUT.write( '\t' );
LuaString s = tostring.call( args.arg(i) ).strvalue();
int z = s.indexOf((byte)0, 0);
baselib.STDOUT.write( s.m_bytes, s.m_offset, z>=0? z: s.m_length );
}
baselib.STDOUT.println();
return NONE;
}
case 7: // "select", // (f, ...) -> value1, ...
{
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);
}
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();
final LuaValue mt0 = t.getmetatable();
if ( mt0!=null && !mt0.rawget(METATABLE).isnil() )
error("cannot change a protected metatable");
final LuaValue mt = args.checkvalue(2);
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);
if (base == 10) { /* standard conversion */
return arg1.tonumber();
} else {
if ( base < 2 || base > 36 )
argerror(2, "base out of range");
return arg1.checkstring().tonumber(base);
}
}
case 11: // "pairs" (t) -> iter-func, t, nil
return varargsOf( baselib.next, args.checktable(1), NIL );
case 12: // "ipairs", // (t) -> iter-func, t, 0
return varargsOf( baselib.inext, args.checktable(1), ZERO );
case 13: // "next" ( table, [index] ) -> next-index, next-value
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));
}
}
// "print", // (...) -> void
static final class print extends VarArgFunction {
final BaseLib baselib;
print(BaseLib baselib) {
this.baselib = baselib;
}
public Varargs invoke(Varargs args) {
LuaValue tostring =LuaValue._G.get("tostring");
for ( int i=1, n=args.narg(); i<=n; i++ ) {
if ( i>1 ) baselib.STDOUT.write( '\t' );
LuaString s = tostring.call( args.arg(i) ).strvalue();
int z = s.indexOf((byte)0, 0);
baselib.STDOUT.write( s.m_bytes, s.m_offset, z>=0? z: s.m_length );
}
baselib.STDOUT.println();
return NONE;
}
}
// "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;
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 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() )
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.optint(10);
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, ...
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));
}
}
// "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));
}
}
public static Varargs pcall(LuaValue func, Varargs args, LuaValue errfunc) {
LuaValue olderr = LuaThread.setErrorFunc(errfunc);

View File

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