Refactor coroutine lib for lua 5.2 compatibility

This commit is contained in:
James Roseborough
2012-09-12 05:36:50 +00:00
parent a9c5c64e0f
commit 56a66ed933
2 changed files with 105 additions and 89 deletions

View File

@@ -70,19 +70,19 @@ public class LuaThread extends LuaValue {
*/ */
static long thread_orphan_check_interval = 30000; static long thread_orphan_check_interval = 30000;
private static final int STATUS_INITIAL = 0; public static final int STATUS_INITIAL = 0;
private static final int STATUS_SUSPENDED = 1; public static final int STATUS_SUSPENDED = 1;
private static final int STATUS_RUNNING = 2; public static final int STATUS_RUNNING = 2;
private static final int STATUS_NORMAL = 3; public static final int STATUS_NORMAL = 3;
private static final int STATUS_DEAD = 4; public static final int STATUS_DEAD = 4;
private static final String[] STATUS_NAMES = { public static final String[] STATUS_NAMES = {
"suspended", "suspended",
"suspended", "suspended",
"running", "running",
"normal", "normal",
"dead",}; "dead",};
private final State state; public final State state;
/** Field to hold state of error condition during debug hook function calls. */ /** Field to hold state of error condition during debug hook function calls. */
public LuaValue err; public LuaValue err;
@@ -153,14 +153,6 @@ public class LuaThread extends LuaValue {
return running_thread; return running_thread;
} }
/**
* Test if this is the main thread
* @return true if this is the main thread
*/
public static boolean isMainThread(LuaThread r) {
return r == main_thread;
}
/** /**
* Callback used at the beginning of a call to prepare for possible getfenv/setfenv calls * Callback used at the beginning of a call to prepare for possible getfenv/setfenv calls
* @param function Function being called * @param function Function being called
@@ -217,13 +209,13 @@ public class LuaThread extends LuaValue {
return state.lua_resume(this, args); return state.lua_resume(this, args);
} }
static class State implements Runnable { public static class State implements Runnable {
final WeakReference lua_thread; final WeakReference lua_thread;
final LuaValue function; public final LuaValue function;
Varargs args = LuaValue.NONE; Varargs args = LuaValue.NONE;
Varargs result = LuaValue.NONE; Varargs result = LuaValue.NONE;
String error = null; String error = null;
int status = LuaThread.STATUS_INITIAL; public int status = LuaThread.STATUS_INITIAL;
State(LuaThread lua_thread, LuaValue function) { State(LuaThread lua_thread, LuaValue function) {
this.lua_thread = new WeakReference(lua_thread); this.lua_thread = new WeakReference(lua_thread);
@@ -243,7 +235,7 @@ public class LuaThread extends LuaValue {
} }
} }
synchronized Varargs lua_resume(LuaThread new_thread, Varargs args) { public synchronized Varargs lua_resume(LuaThread new_thread, Varargs args) {
LuaThread previous_thread = LuaThread.running_thread; LuaThread previous_thread = LuaThread.running_thread;
try { try {
LuaThread.running_thread = new_thread; LuaThread.running_thread = new_thread;
@@ -271,7 +263,7 @@ public class LuaThread extends LuaValue {
} }
} }
synchronized Varargs lua_yield(Varargs args) { public synchronized Varargs lua_yield(Varargs args) {
try { try {
this.result = args; this.result = args;
this.status = STATUS_SUSPENDED; this.status = STATUS_SUSPENDED;
@@ -336,4 +328,8 @@ public class LuaThread extends LuaValue {
return level>0 && level<=calls? functions[calls-level]: null; return level>0 && level<=calls? functions[calls-level]: null;
} }
} }
public boolean isMainThread() {
return this.state.function == null;
}
} }

View File

@@ -21,10 +21,13 @@
******************************************************************************/ ******************************************************************************/
package org.luaj.vm2.lib; package org.luaj.vm2.lib;
import org.luaj.vm2.LuaError;
import org.luaj.vm2.LuaTable; import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaThread; import org.luaj.vm2.LuaThread;
import org.luaj.vm2.LuaValue; import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs; import org.luaj.vm2.Varargs;
import org.luaj.vm2.lib.jme.JmePlatform;
import org.luaj.vm2.lib.jse.JsePlatform;
/** /**
* Subclass of {@link LibFunction} which implements the lua standard {@code coroutine} * Subclass of {@link LibFunction} which implements the lua standard {@code coroutine}
@@ -54,77 +57,94 @@ import org.luaj.vm2.Varargs;
* @see JmePlatform * @see JmePlatform
* @see <a href="http://www.lua.org/manual/5.1/manual.html#5.2">http://www.lua.org/manual/5.1/manual.html#5.2</a> * @see <a href="http://www.lua.org/manual/5.1/manual.html#5.2">http://www.lua.org/manual/5.1/manual.html#5.2</a>
*/ */
public class CoroutineLib extends VarArgFunction { public class CoroutineLib extends OneArgFunction {
private static final int INIT = 0; static long thread_orphan_check_interval = 30000;
private static final int CREATE = 1;
private static final int RESUME = 2;
private static final int RUNNING = 3;
private static final int STATUS = 4;
private static final int YIELD = 5;
private static final int WRAP = 6;
private static final int WRAPPED = 7;
private LuaThread t; static int coroutine_count = 0;
public CoroutineLib() { public LuaValue call(LuaValue env) {
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);
env.get("package").get("loaded").set("coroutine", TRUE);
return coroutine;
} }
private CoroutineLib(LuaThread t) { final class create extends LibFunction {
this.t = t; public LuaValue call(LuaValue f) {
} return new LuaThread(f.checkfunction());
}
private LuaTable init(LuaValue env) {
LuaTable t = new LuaTable();
bind(t, CoroutineLib.class, new String[] {
"create", "resume", "running", "status", "yield", "wrap" },
CREATE);
env.set("coroutine", t);
PackageLib.instance.LOADED.set("coroutine", t);
return t;
} }
final class resume extends VarArgFunction {
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
switch ( opcode ) { if (!(args.arg1() instanceof LuaThread)) argerror(1, "thread");
case INIT: { final LuaThread t = (LuaThread) args.arg1();
return init(args.arg1()); return resume( t, args.subargs(2) );
} }
case CREATE: {
final LuaValue func = args.checkfunction(1);
return new LuaThread(func);
} }
case RESUME: {
final LuaThread t = args.checkthread(1); final class running extends VarArgFunction {
return t.resume( args.subargs(2) ); public Varargs invoke(Varargs args) {
}
case RUNNING: {
final LuaThread r = LuaThread.getRunning(); final LuaThread r = LuaThread.getRunning();
return LuaThread.isMainThread(r)? NIL: r; return varargsOf(r, valueOf(r.isMainThread()));
} }
case STATUS: {
return valueOf( args.checkthread(1).getStatus() );
} }
case YIELD: {
return LuaThread.yield( args ); static final class status extends LibFunction {
public LuaValue call(LuaValue t) {
LuaThread lt = t.checkthread();
return valueOf( lt.getStatus() );
} }
case WRAP: { }
final LuaValue func = args.checkfunction(1);
final class yield extends VarArgFunction {
public Varargs invoke(Varargs args) {
return yield( args );
}
}
final class wrap extends LibFunction {
public LuaValue call(LuaValue f) {
final LuaValue func = f.checkfunction();
final LuaThread thread = new LuaThread(func); final LuaThread thread = new LuaThread(func);
CoroutineLib cl = new CoroutineLib(thread); return new wrapper(thread);
cl.name = "wrapped";
cl.opcode = WRAPPED;
return cl;
} }
case WRAPPED: { }
final Varargs result = t.resume( args );
final class wrapper extends VarArgFunction {
final LuaThread luathread;
wrapper(LuaThread luathread) {
this.luathread = luathread;
}
public Varargs invoke(Varargs args) {
final Varargs result = resume(luathread, args);
if ( result.arg1().toboolean() ) { if ( result.arg1().toboolean() ) {
return result.subargs(2); return result.subargs(2);
} else { } else {
error( result.arg(2).tojstring() ); return error( result.arg(2).tojstring() );
} }
} }
default:
return NONE;
} }
Varargs yield(Varargs args) {
final LuaThread.State s = LuaThread.getRunning().state;
if (s.function == null)
throw new LuaError("cannot yield main thread");
return s.lua_yield(args);
}
Varargs resume(LuaThread t, Varargs args) {
final LuaThread.State s = t.state;
if (s.status > LuaThread.STATUS_SUSPENDED)
return LuaValue.varargsOf(LuaValue.FALSE,
LuaValue.valueOf("cannot resume "+(s.status==LuaThread.STATUS_DEAD? "dead": "non-suspended")+" coroutine"));
return s.lua_resume(t, args);
} }
} }