mirror of
https://github.com/Leonmmcoset/CMLeonOS.git
synced 2026-03-03 15:30:27 +00:00
153 lines
3.5 KiB
C#
153 lines
3.5 KiB
C#
|
|
namespace UniLua
|
|
{
|
|
|
|
internal class LuaCoroLib
|
|
{
|
|
public const string LIB_NAME = "coroutine";
|
|
|
|
public static int OpenLib( ILuaState lua )
|
|
{
|
|
NameFuncPair[] define = new NameFuncPair[]
|
|
{
|
|
new NameFuncPair( "create", CO_Create ),
|
|
new NameFuncPair( "resume", CO_Resume ),
|
|
new NameFuncPair( "running", CO_Running ),
|
|
new NameFuncPair( "status", CO_Status ),
|
|
new NameFuncPair( "wrap", CO_Wrap ),
|
|
new NameFuncPair( "yield", CO_Yield ),
|
|
};
|
|
|
|
lua.L_NewLib( define );
|
|
return 1;
|
|
}
|
|
|
|
private static int CO_Create( ILuaState lua )
|
|
{
|
|
lua.L_CheckType( 1, LuaType.LUA_TFUNCTION );
|
|
ILuaState newLua = lua.NewThread();
|
|
lua.PushValue( 1 ); // move function to top
|
|
lua.XMove( newLua, 1 ); // move function from lua to newLua
|
|
return 1;
|
|
}
|
|
|
|
private static int AuxResume( ILuaState lua, ILuaState co, int narg )
|
|
{
|
|
if(!co.CheckStack(narg)) {
|
|
lua.PushString("too many arguments to resume");
|
|
return -1; // error flag
|
|
}
|
|
if( co.Status == ThreadStatus.LUA_OK && co.GetTop() == 0 )
|
|
{
|
|
lua.PushString( "cannot resume dead coroutine" );
|
|
return -1; // error flag
|
|
}
|
|
lua.XMove( co, narg );
|
|
ThreadStatus status = co.Resume( lua, narg );
|
|
if( status == ThreadStatus.LUA_OK || status == ThreadStatus.LUA_YIELD )
|
|
{
|
|
int nres = co.GetTop();
|
|
if(!lua.CheckStack(nres+1)) {
|
|
co.Pop(nres); // remove results anyway;
|
|
lua.PushString("too many results to resume");
|
|
return -1; // error flag
|
|
}
|
|
co.XMove( lua, nres ); // move yielded values
|
|
return nres;
|
|
}
|
|
else
|
|
{
|
|
co.XMove( lua, 1 ); // move error message
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
private static int CO_Resume( ILuaState lua )
|
|
{
|
|
ILuaState co = lua.ToThread( 1 );
|
|
lua.L_ArgCheck( co != null, 1, "coroutine expected" );
|
|
int r = AuxResume( lua, co, lua.GetTop() - 1 );
|
|
if( r < 0 )
|
|
{
|
|
lua.PushBoolean( false );
|
|
lua.Insert( -2 );
|
|
return 2; // return false + error message
|
|
}
|
|
else
|
|
{
|
|
lua.PushBoolean( true );
|
|
lua.Insert( -(r+1) );
|
|
return r+1; // return true + `resume' returns
|
|
}
|
|
}
|
|
|
|
private static int CO_Running( ILuaState lua )
|
|
{
|
|
bool isMain = lua.PushThread();
|
|
lua.PushBoolean( isMain );
|
|
return 2;
|
|
}
|
|
|
|
private static int CO_Status( ILuaState lua )
|
|
{
|
|
ILuaState co = lua.ToThread( 1 );
|
|
lua.L_ArgCheck( co != null, 1, "coroutine expected" );
|
|
if( (LuaState)lua == (LuaState)co )
|
|
lua.PushString( "running" );
|
|
else switch( co.Status )
|
|
{
|
|
case ThreadStatus.LUA_YIELD:
|
|
lua.PushString( "suspended" );
|
|
break;
|
|
case ThreadStatus.LUA_OK:
|
|
{
|
|
LuaDebug ar = new LuaDebug();
|
|
if( co.GetStack( 0, ar ) ) // does it have frames?
|
|
lua.PushString( "normal" );
|
|
else if( co.GetTop() == 0 )
|
|
lua.PushString( "dead" );
|
|
else
|
|
lua.PushString( "suspended" );
|
|
break;
|
|
}
|
|
default: // some error occurred
|
|
lua.PushString( "dead" );
|
|
break;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
private static int CO_AuxWrap( ILuaState lua )
|
|
{
|
|
ILuaState co = lua.ToThread( lua.UpvalueIndex(1) );
|
|
int r = AuxResume( lua, co, lua.GetTop() );
|
|
if( r < 0 )
|
|
{
|
|
if( lua.IsString( -1 ) ) // error object is a string?
|
|
{
|
|
lua.L_Where( 1 ); // add extra info
|
|
lua.Insert( -2 );
|
|
lua.Concat( 2 );
|
|
}
|
|
lua.Error();
|
|
}
|
|
return r;
|
|
}
|
|
|
|
private static int CO_Wrap( ILuaState lua )
|
|
{
|
|
CO_Create( lua );
|
|
lua.PushCSharpClosure( CO_AuxWrap, 1 );
|
|
return 1;
|
|
}
|
|
|
|
private static int CO_Yield( ILuaState lua )
|
|
{
|
|
return lua.Yield( lua.GetTop() );
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|