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;
private static final int STATUS_INITIAL = 0;
private static final int STATUS_SUSPENDED = 1;
private static final int STATUS_RUNNING = 2;
private static final int STATUS_NORMAL = 3;
private static final int STATUS_DEAD = 4;
private static final String[] STATUS_NAMES = {
public static final int STATUS_INITIAL = 0;
public static final int STATUS_SUSPENDED = 1;
public static final int STATUS_RUNNING = 2;
public static final int STATUS_NORMAL = 3;
public static final int STATUS_DEAD = 4;
public static final String[] STATUS_NAMES = {
"suspended",
"suspended",
"running",
"normal",
"dead",};
private final State state;
public final State state;
/** Field to hold state of error condition during debug hook function calls. */
public LuaValue err;
@@ -153,14 +153,6 @@ public class LuaThread extends LuaValue {
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
* @param function Function being called
@@ -217,13 +209,13 @@ public class LuaThread extends LuaValue {
return state.lua_resume(this, args);
}
static class State implements Runnable {
public static class State implements Runnable {
final WeakReference lua_thread;
final LuaValue function;
public final LuaValue function;
Varargs args = LuaValue.NONE;
Varargs result = LuaValue.NONE;
String error = null;
int status = LuaThread.STATUS_INITIAL;
public int status = LuaThread.STATUS_INITIAL;
State(LuaThread lua_thread, LuaValue function) {
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;
try {
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 {
this.result = args;
this.status = STATUS_SUSPENDED;
@@ -336,4 +328,8 @@ public class LuaThread extends LuaValue {
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;
import org.luaj.vm2.LuaError;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaThread;
import org.luaj.vm2.LuaValue;
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}
@@ -54,77 +57,94 @@ import org.luaj.vm2.Varargs;
* @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>
*/
public class CoroutineLib extends VarArgFunction {
public class CoroutineLib extends OneArgFunction {
private static final int INIT = 0;
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;
static long thread_orphan_check_interval = 30000;
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) {
this.t = t;
}
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 create extends LibFunction {
public LuaValue call(LuaValue f) {
return new LuaThread(f.checkfunction());
}
}
final class resume extends VarArgFunction {
public Varargs invoke(Varargs args) {
switch ( opcode ) {
case INIT: {
return init(args.arg1());
if (!(args.arg1() instanceof LuaThread)) argerror(1, "thread");
final LuaThread t = (LuaThread) 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);
return t.resume( args.subargs(2) );
}
case RUNNING: {
final class running extends VarArgFunction {
public Varargs invoke(Varargs args) {
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);
CoroutineLib cl = new CoroutineLib(thread);
cl.name = "wrapped";
cl.opcode = WRAPPED;
return cl;
return new wrapper(thread);
}
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() ) {
return result.subargs(2);
} 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);
}
}