|  | /******************************************************************************* | 
|  | * Copyright (c) 2007-2011 LuaJ. All rights reserved. | 
|  | * | 
|  | * Permission is hereby granted, free of charge, to any person obtaining a copy | 
|  | * of this software and associated documentation files (the "Software"), to deal | 
|  | * in the Software without restriction, including without limitation the rights | 
|  | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | 
|  | * copies of the Software, and to permit persons to whom the Software is | 
|  | * furnished to do so, subject to the following conditions: | 
|  | * | 
|  | * The above copyright notice and this permission notice shall be included in | 
|  | * all copies or substantial portions of the Software. | 
|  | * | 
|  | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
|  | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
|  | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | 
|  | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 
|  | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | 
|  | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | 
|  | * THE SOFTWARE. | 
|  | ******************************************************************************/ | 
|  | package org.luaj.vm2.lib; | 
|  |  | 
|  | import org.luaj.vm2.Globals; | 
|  | import org.luaj.vm2.LuaTable; | 
|  | import org.luaj.vm2.LuaThread; | 
|  | import org.luaj.vm2.LuaValue; | 
|  | import org.luaj.vm2.Varargs; | 
|  |  | 
|  | /** | 
|  | * Subclass of {@link LibFunction} which implements the lua standard {@code coroutine} | 
|  | * library. | 
|  | * <p> | 
|  | * The coroutine library in luaj has the same behavior as the | 
|  | * coroutine library in C, but is implemented using Java Threads to maintain | 
|  | * the call state between invocations.  Therefore it can be yielded from anywhere, | 
|  | * similar to the "Coco" yield-from-anywhere patch available for C-based lua. | 
|  | * However, coroutines that are yielded but never resumed to complete their execution | 
|  | * may not be collected by the garbage collector. | 
|  | * <p> | 
|  | * Typically, this library is included as part of a call to either | 
|  | * {@link JsePlatform#standardGlobals()} or {@link JmePlatform#standardGlobals()} | 
|  | * <pre> {@code | 
|  | * Globals globals = JsePlatform.standardGlobals(); | 
|  | * System.out.println( globals.get("coroutine").get("running").call() ); | 
|  | * } </pre> | 
|  | * <p> | 
|  | * To instantiate and use it directly, | 
|  | * link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as: | 
|  | * <pre> {@code | 
|  | * Globals globals = new Globals(); | 
|  | * globals.load(new JseBaseLib()); | 
|  | * globals.load(new PackageLib()); | 
|  | * globals.load(new CoroutineLib()); | 
|  | * System.out.println( globals.get("coroutine").get("running").call() ); | 
|  | * } </pre> | 
|  | * <p> | 
|  | * @see LibFunction | 
|  | * @see JsePlatform | 
|  | * @see JmePlatform | 
|  | * @see <a href="http://www.lua.org/manual/5.2/manual.html#6.2">Lua 5.2 Coroutine Lib Reference</a> | 
|  | */ | 
|  | public class CoroutineLib extends TwoArgFunction { | 
|  |  | 
|  | static long thread_orphan_check_interval = 30000; | 
|  |  | 
|  | static int coroutine_count = 0; | 
|  |  | 
|  | Globals globals; | 
|  |  | 
|  | public LuaValue call(LuaValue modname, LuaValue env) { | 
|  | globals = env.checkglobals(); | 
|  | 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", coroutine); | 
|  | return coroutine; | 
|  | } | 
|  |  | 
|  | final class create extends LibFunction { | 
|  | public LuaValue call(LuaValue f) { | 
|  | return new LuaThread(globals, f.checkfunction()); | 
|  | } | 
|  | } | 
|  |  | 
|  | final class resume extends VarArgFunction { | 
|  | public Varargs invoke(Varargs args) { | 
|  | final LuaThread t = args.checkthread(1); | 
|  | return t.resume( args.subargs(2) ); | 
|  | } | 
|  | } | 
|  |  | 
|  | final class running extends VarArgFunction { | 
|  | public Varargs invoke(Varargs args) { | 
|  | final LuaThread r = globals.running; | 
|  | return varargsOf(r, valueOf(r.isMainThread())); | 
|  | } | 
|  | } | 
|  |  | 
|  | static final class status extends LibFunction { | 
|  | public LuaValue call(LuaValue t) { | 
|  | LuaThread lt = t.checkthread(); | 
|  | return valueOf( lt.getStatus() ); | 
|  | } | 
|  | } | 
|  |  | 
|  | final class yield extends VarArgFunction { | 
|  | public Varargs invoke(Varargs args) { | 
|  | return globals.yield( args ); | 
|  | } | 
|  | } | 
|  |  | 
|  | final class wrap extends LibFunction { | 
|  | public LuaValue call(LuaValue f) { | 
|  | final LuaValue func = f.checkfunction(); | 
|  | final LuaThread thread = new LuaThread(globals, func); | 
|  | return new wrapper(thread); | 
|  | } | 
|  | } | 
|  |  | 
|  | final class wrapper extends VarArgFunction { | 
|  | final LuaThread luathread; | 
|  | wrapper(LuaThread luathread) { | 
|  | this.luathread = luathread; | 
|  | } | 
|  | public Varargs invoke(Varargs args) { | 
|  | final Varargs result = luathread.resume(args); | 
|  | if ( result.arg1().toboolean() ) { | 
|  | return result.subargs(2); | 
|  | } else { | 
|  | return error( result.arg(2).tojstring() ); | 
|  | } | 
|  | } | 
|  | } | 
|  | } |