2026-02-03 02:44:58 +08:00
|
|
|
|
|
|
|
|
namespace UniLua
|
|
|
|
|
{
|
|
|
|
|
using System;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Xml.Linq;
|
|
|
|
|
using Cosmos.HAL.Drivers.Video.SVGAII;
|
|
|
|
|
|
|
|
|
|
public struct NameFuncPair
|
|
|
|
|
{
|
|
|
|
|
public string Name;
|
|
|
|
|
public CSharpFunctionDelegate Func;
|
|
|
|
|
|
|
|
|
|
public NameFuncPair( string name, CSharpFunctionDelegate func )
|
|
|
|
|
{
|
|
|
|
|
Name = name;
|
|
|
|
|
Func = func;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public interface ILuaAuxLib
|
|
|
|
|
{
|
|
|
|
|
void L_Where( int level );
|
|
|
|
|
int L_Error( string fmt, params object[] args );
|
|
|
|
|
void L_CheckStack( int size, string msg );
|
|
|
|
|
void L_CheckAny( int narg );
|
|
|
|
|
void L_CheckType( int index, LuaType t );
|
|
|
|
|
double L_CheckNumber( int narg );
|
|
|
|
|
UInt64 L_CheckUInt64( int narg );
|
|
|
|
|
int L_CheckInteger( int narg );
|
|
|
|
|
string L_CheckString( int narg );
|
|
|
|
|
uint L_CheckUnsigned( int narg );
|
|
|
|
|
void L_ArgCheck( bool cond, int narg, string extraMsg );
|
|
|
|
|
int L_ArgError( int narg, string extraMsg );
|
|
|
|
|
string L_TypeName( int index );
|
|
|
|
|
|
|
|
|
|
string L_ToString( int index );
|
|
|
|
|
bool L_GetMetaField( int index, string method );
|
|
|
|
|
int L_GetSubTable( int index, string fname );
|
|
|
|
|
|
|
|
|
|
void L_RequireF( string moduleName, CSharpFunctionDelegate openFunc, bool global );
|
|
|
|
|
void L_OpenLibs();
|
|
|
|
|
void L_NewLibTable( NameFuncPair[] define );
|
|
|
|
|
void L_NewLib( NameFuncPair[] define );
|
|
|
|
|
void L_SetFuncs( NameFuncPair[] define, int nup );
|
|
|
|
|
|
|
|
|
|
int L_Opt(int n, int def);
|
|
|
|
|
|
|
|
|
|
int L_OptInt( int narg, int def );
|
|
|
|
|
string L_OptString( int narg, string def );
|
|
|
|
|
bool L_CallMeta( int obj, string name );
|
|
|
|
|
void L_Traceback( ILuaState otherLua, string msg, int level );
|
|
|
|
|
int L_Len( int index );
|
|
|
|
|
|
|
|
|
|
ThreadStatus L_LoadBuffer( string s, string name );
|
|
|
|
|
ThreadStatus L_LoadBufferX( string s, string name, string mode );
|
|
|
|
|
ThreadStatus L_LoadFile( string filename );
|
|
|
|
|
ThreadStatus L_LoadFileX( string filename, string mode );
|
|
|
|
|
|
|
|
|
|
ThreadStatus L_LoadString( string s );
|
|
|
|
|
ThreadStatus L_LoadBytes( byte[] bytes, string name);
|
|
|
|
|
ThreadStatus L_DoByteArray(byte[] file, string name);
|
|
|
|
|
ThreadStatus L_DoString( string s );
|
|
|
|
|
ThreadStatus L_DoFile( string filename );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
string L_Gsub( string src, string pattern, string rep );
|
|
|
|
|
|
|
|
|
|
// reference system
|
|
|
|
|
int L_Ref( int t );
|
|
|
|
|
void L_Unref( int t, int reference );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class StringLoadInfo : ILoadInfo
|
|
|
|
|
{
|
|
|
|
|
public StringLoadInfo(string s )
|
|
|
|
|
{
|
|
|
|
|
Str = s;
|
|
|
|
|
Pos = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int ReadByte()
|
|
|
|
|
{
|
|
|
|
|
if( Pos >= Str.Length )
|
|
|
|
|
return -1;
|
|
|
|
|
else
|
|
|
|
|
return Str[Pos++];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int PeekByte()
|
|
|
|
|
{
|
|
|
|
|
if( Pos >= Str.Length )
|
|
|
|
|
return -1;
|
|
|
|
|
else
|
|
|
|
|
return Str[Pos];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string Str;
|
|
|
|
|
private int Pos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class BytesLoadInfo : ILoadInfo
|
|
|
|
|
{
|
|
|
|
|
public BytesLoadInfo( byte[] bytes )
|
|
|
|
|
{
|
|
|
|
|
Bytes = bytes;
|
|
|
|
|
Pos = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int ReadByte()
|
|
|
|
|
{
|
|
|
|
|
if( Pos >= Bytes.Length )
|
|
|
|
|
return -1;
|
|
|
|
|
else
|
|
|
|
|
return Bytes[Pos++];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int PeekByte()
|
|
|
|
|
{
|
|
|
|
|
if( Pos >= Bytes.Length )
|
|
|
|
|
return -1;
|
|
|
|
|
else
|
|
|
|
|
return Bytes[Pos];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private byte[] Bytes;
|
|
|
|
|
private int Pos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public partial class LuaState
|
|
|
|
|
{
|
|
|
|
|
private const int LEVELS1 = 12; // size of the first part of the stack
|
|
|
|
|
private const int LEVELS2 = 10; // size of the second part of the stack
|
|
|
|
|
|
|
|
|
|
public void L_Where( int level )
|
|
|
|
|
{
|
|
|
|
|
LuaDebug ar = new LuaDebug();
|
|
|
|
|
if( API.GetStack( level, ar ) ) // check function at level
|
|
|
|
|
{
|
|
|
|
|
GetInfo( "Sl", ar ); // get info about it
|
|
|
|
|
if( ar.CurrentLine > 0 ) // is there info?
|
|
|
|
|
{
|
|
|
|
|
API.PushString( string.Format( "{0}:{1}: ", ar.ShortSrc, ar.CurrentLine ) );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
API.PushString( "" ); // else, no information available...
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int L_Error( string fmt, params object[] args )
|
|
|
|
|
{
|
|
|
|
|
L_Where( 1 );
|
|
|
|
|
API.PushString( string.Format( fmt, args ) );
|
|
|
|
|
API.Concat( 2 );
|
|
|
|
|
return API.Error();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void L_CheckStack( int size, string msg )
|
|
|
|
|
{
|
|
|
|
|
// keep some extra space to run error routines, if needed
|
|
|
|
|
if(!API.CheckStack(size + LuaDef.LUA_MINSTACK)) {
|
|
|
|
|
if(msg != null)
|
|
|
|
|
{ L_Error(string.Format("stack overflow ({0})", msg)); }
|
|
|
|
|
else
|
|
|
|
|
{ L_Error("stack overflow"); }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void L_CheckAny( int narg )
|
|
|
|
|
{
|
|
|
|
|
if( API.Type( narg ) == LuaType.LUA_TNONE )
|
|
|
|
|
L_ArgError( narg, "value expected" );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public double L_CheckNumber( int narg )
|
|
|
|
|
{
|
|
|
|
|
bool isnum;
|
|
|
|
|
double d = API.ToNumberX( narg, out isnum );
|
|
|
|
|
if( !isnum )
|
|
|
|
|
TagError( narg, LuaType.LUA_TNUMBER );
|
|
|
|
|
return d;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public UInt64 L_CheckUInt64( int narg )
|
|
|
|
|
{
|
|
|
|
|
bool isnum;
|
|
|
|
|
UInt64 v = API.ToUInt64X( narg, out isnum );
|
|
|
|
|
if( !isnum )
|
|
|
|
|
TagError( narg, LuaType.LUA_TUINT64 );
|
|
|
|
|
return v;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int L_CheckInteger( int narg )
|
|
|
|
|
{
|
|
|
|
|
bool isnum;
|
|
|
|
|
int d = API.ToIntegerX( narg, out isnum );
|
|
|
|
|
if( !isnum )
|
|
|
|
|
TagError( narg, LuaType.LUA_TNUMBER );
|
|
|
|
|
return d;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string L_CheckString( int narg )
|
|
|
|
|
{
|
|
|
|
|
string s = API.ToString( narg );
|
|
|
|
|
if( s == null ) TagError( narg, LuaType.LUA_TSTRING );
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public uint L_CheckUnsigned( int narg )
|
|
|
|
|
{
|
|
|
|
|
bool isnum;
|
|
|
|
|
uint d = API.ToUnsignedX( narg, out isnum );
|
|
|
|
|
if( !isnum )
|
|
|
|
|
TagError( narg, LuaType.LUA_TNUMBER );
|
|
|
|
|
return d;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int L_Opt(int n, int def)
|
|
|
|
|
{
|
|
|
|
|
LuaType t = API.Type(n);
|
|
|
|
|
if (t == LuaType.LUA_TNONE || t == LuaType.LUA_TNIL)
|
|
|
|
|
{
|
|
|
|
|
return def;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return L_CheckInteger(n);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int L_OptInt( int narg, int def )
|
|
|
|
|
{
|
|
|
|
|
LuaType t = API.Type( narg );
|
|
|
|
|
if( t == LuaType.LUA_TNONE ||
|
|
|
|
|
t == LuaType.LUA_TNIL )
|
|
|
|
|
{
|
|
|
|
|
return def;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return L_CheckInteger( narg );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string L_OptString( int narg, string def )
|
|
|
|
|
{
|
|
|
|
|
LuaType t = API.Type( narg );
|
|
|
|
|
if( t == LuaType.LUA_TNONE ||
|
|
|
|
|
t == LuaType.LUA_TNIL )
|
|
|
|
|
{
|
|
|
|
|
return def;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return L_CheckString( narg );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private int TypeError( int index, string typeName )
|
|
|
|
|
{
|
|
|
|
|
string msg = string.Format( "{0} expected, got {1}",
|
|
|
|
|
typeName, L_TypeName( index ) );
|
|
|
|
|
API.PushString( msg );
|
|
|
|
|
return L_ArgError( index, msg );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void TagError( int index, LuaType t )
|
|
|
|
|
{
|
|
|
|
|
TypeError( index, API.TypeName( t ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void L_CheckType( int index, LuaType t )
|
|
|
|
|
{
|
|
|
|
|
if( API.Type( index ) != t )
|
|
|
|
|
TagError( index, t );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void L_ArgCheck( bool cond, int narg, string extraMsg )
|
|
|
|
|
{
|
|
|
|
|
if( !cond )
|
|
|
|
|
L_ArgError( narg, extraMsg );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int L_ArgError( int narg, string extraMsg )
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
LuaDebug ar = new LuaDebug();
|
|
|
|
|
if( !API.GetStack( 0, ar ) ) // no stack frame ?
|
|
|
|
|
return L_Error( "bad argument {0} ({1})", narg, extraMsg );
|
|
|
|
|
|
|
|
|
|
GetInfo( "n", ar );
|
|
|
|
|
if( ar.NameWhat == "method" )
|
|
|
|
|
{
|
|
|
|
|
narg--; // do not count 'self'
|
|
|
|
|
if( narg == 0 ) // error is in the self argument itself?
|
|
|
|
|
return L_Error( "calling '{0}' on bad self", ar.Name );
|
|
|
|
|
}
|
|
|
|
|
if( ar.Name == null )
|
|
|
|
|
ar.Name = PushGlobalFuncName( ar ) ? API.ToString(-1) : "?";
|
|
|
|
|
return L_Error( "bad argument {0} to '{1}' ({2})",
|
|
|
|
|
narg, ar.Name, extraMsg );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string L_TypeName( int index )
|
|
|
|
|
{
|
|
|
|
|
return API.TypeName( API.Type( index ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool L_GetMetaField( int obj, string name )
|
|
|
|
|
{
|
|
|
|
|
if( !API.GetMetaTable(obj) ) // no metatable?
|
|
|
|
|
return false;
|
|
|
|
|
API.PushString( name );
|
|
|
|
|
API.RawGet( -2 );
|
|
|
|
|
if( API.IsNil( -1 ) )
|
|
|
|
|
{
|
|
|
|
|
API.Pop( 2 );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
API.Remove( -2 );
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool L_CallMeta( int obj, string name )
|
|
|
|
|
{
|
|
|
|
|
obj = API.AbsIndex( obj );
|
|
|
|
|
if( !L_GetMetaField( obj, name ) ) // no metafield?
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
API.PushValue( obj );
|
|
|
|
|
API.Call( 1, 1 );
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void PushFuncName( LuaDebug ar )
|
|
|
|
|
{
|
|
|
|
|
if( ar.NameWhat.Length > 0 && ar.NameWhat[0] != '\0' ) // is there a name?
|
|
|
|
|
API.PushString( string.Format( "function '{0}'", ar.Name ) );
|
|
|
|
|
else if( ar.What.Length > 0 && ar.What[0] == 'm' ) // main?
|
|
|
|
|
API.PushString( "main chunk" );
|
|
|
|
|
else if( ar.What.Length > 0 && ar.What[0] == 'C' )
|
|
|
|
|
{
|
|
|
|
|
if( PushGlobalFuncName( ar ) )
|
|
|
|
|
{
|
|
|
|
|
API.PushString( string.Format( "function '{0}'", API.ToString(-1) ) );
|
|
|
|
|
API.Remove( -2 ); //remove name
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
API.PushString( "?" );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
API.PushString( string.Format( "function <{0}:{1}>", ar.ShortSrc, ar.LineDefined ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private int CountLevels()
|
|
|
|
|
{
|
|
|
|
|
LuaDebug ar = new LuaDebug();
|
|
|
|
|
int li = 1;
|
|
|
|
|
int le = 1;
|
|
|
|
|
// find an upper bound
|
|
|
|
|
while( API.GetStack(le, ar) )
|
|
|
|
|
{
|
|
|
|
|
li = le;
|
|
|
|
|
le *= 2;
|
|
|
|
|
}
|
|
|
|
|
// do a binary search
|
|
|
|
|
while(li < le)
|
|
|
|
|
{
|
|
|
|
|
int m = (li + le)/2;
|
|
|
|
|
if( API.GetStack( m, ar ) )
|
|
|
|
|
li = m + 1;
|
|
|
|
|
else
|
|
|
|
|
le = m;
|
|
|
|
|
}
|
|
|
|
|
return le - 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void L_Traceback( ILuaState otherLua, string msg, int level )
|
|
|
|
|
{
|
|
|
|
|
LuaState oLua = otherLua as LuaState;
|
|
|
|
|
LuaDebug ar = new LuaDebug();
|
|
|
|
|
int top = API.GetTop();
|
|
|
|
|
int numLevels = oLua.CountLevels();
|
|
|
|
|
int mark = (numLevels > LEVELS1 + LEVELS2) ? LEVELS1 : 0;
|
|
|
|
|
if( msg != null )
|
|
|
|
|
API.PushString( string.Format( "{0}\n", msg ) );
|
|
|
|
|
API.PushString( "stack traceback:" );
|
|
|
|
|
while( otherLua.GetStack( level++, ar ) )
|
|
|
|
|
{
|
|
|
|
|
if( level == mark ) // too many levels?
|
|
|
|
|
{
|
|
|
|
|
API.PushString( "\n\t..." );
|
|
|
|
|
level = numLevels - LEVELS2; // and skip to last ones
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
oLua.GetInfo( "Slnt", ar );
|
|
|
|
|
API.PushString( string.Format( "\n\t{0}:", ar.ShortSrc ) );
|
|
|
|
|
if( ar.CurrentLine > 0 )
|
|
|
|
|
API.PushString( string.Format( "{0}:", ar.CurrentLine ) );
|
|
|
|
|
API.PushString(" in ");
|
|
|
|
|
PushFuncName( ar );
|
|
|
|
|
if( ar.IsTailCall )
|
|
|
|
|
API.PushString( "\n\t(...tail calls...)" );
|
|
|
|
|
API.Concat( API.GetTop() - top );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
API.Concat( API.GetTop() - top );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int L_Len( int index )
|
|
|
|
|
{
|
|
|
|
|
API.Len( index );
|
|
|
|
|
|
|
|
|
|
bool isnum;
|
|
|
|
|
int l = (int)API.ToIntegerX( -1, out isnum );
|
|
|
|
|
if( !isnum )
|
|
|
|
|
L_Error( "object length is not a number" );
|
|
|
|
|
API.Pop( 1 );
|
|
|
|
|
return l;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ThreadStatus L_LoadBuffer( string s, string name )
|
|
|
|
|
{
|
|
|
|
|
return L_LoadBufferX( s, name, null );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ThreadStatus L_LoadBufferX( string s, string name, string mode )
|
|
|
|
|
{
|
|
|
|
|
var loadinfo = new StringLoadInfo( s );
|
|
|
|
|
return API.Load( loadinfo, name, mode );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ThreadStatus L_LoadBytes( byte[] bytes, string name)
|
|
|
|
|
{
|
|
|
|
|
LuaFile.VirtualFiles.Add(name, bytes);
|
|
|
|
|
|
|
|
|
|
var loadinfo = new BytesLoadInfo( bytes );
|
|
|
|
|
return API.Load( loadinfo, name, null );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private ThreadStatus ErrFile( string what, int fnameindex )
|
|
|
|
|
{
|
|
|
|
|
return ThreadStatus.LUA_ERRFILE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ThreadStatus L_LoadFile( string filename )
|
|
|
|
|
{
|
|
|
|
|
return L_LoadFileX( filename, null );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ThreadStatus L_LoadFileX( string filename, string mode )
|
|
|
|
|
{
|
|
|
|
|
var status = ThreadStatus.LUA_OK;
|
|
|
|
|
if( filename == null )
|
|
|
|
|
{
|
|
|
|
|
// stdin
|
|
|
|
|
throw new System.NotImplementedException();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int fnameindex = API.GetTop() + 1;
|
|
|
|
|
API.PushString( "@" + filename );
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var loadinfo = LuaFile.OpenFile(filename);
|
|
|
|
|
|
|
|
|
|
if (loadinfo.GetType() == typeof(FileLoadInfo))
|
|
|
|
|
{
|
|
|
|
|
((FileLoadInfo)loadinfo).SkipComment();
|
|
|
|
|
status = API.Load(((FileLoadInfo)loadinfo), API.ToString(-1), mode);
|
|
|
|
|
((FileLoadInfo)loadinfo).Dispose();
|
|
|
|
|
}
|
|
|
|
|
else if (loadinfo.GetType() == typeof(BytesLoadInfo))
|
|
|
|
|
{
|
|
|
|
|
status = API.Load(loadinfo, filename, null);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch( LuaRuntimeException e )
|
|
|
|
|
{
|
|
|
|
|
API.PushString( string.Format( "cannot open {0}: {1}",
|
|
|
|
|
filename, e.Message ) );
|
|
|
|
|
return ThreadStatus.LUA_ERRFILE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
API.Remove( fnameindex );
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ThreadStatus L_LoadString( string s )
|
|
|
|
|
{
|
|
|
|
|
return L_LoadBuffer( s, s );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ThreadStatus L_DoByteArray(byte[] file, string name)
|
|
|
|
|
{
|
|
|
|
|
var status = L_LoadBytes(file, name);
|
|
|
|
|
if (status != ThreadStatus.LUA_OK)
|
|
|
|
|
return status;
|
|
|
|
|
return API.PCall(0, LuaDef.LUA_MULTRET, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ThreadStatus L_DoString( string s )
|
|
|
|
|
{
|
|
|
|
|
var status = L_LoadString( s );
|
|
|
|
|
if( status != ThreadStatus.LUA_OK )
|
|
|
|
|
return status;
|
|
|
|
|
return API.PCall( 0, LuaDef.LUA_MULTRET, 0 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ThreadStatus L_DoFile( string filename )
|
|
|
|
|
{
|
|
|
|
|
var status = L_LoadFile( filename );
|
|
|
|
|
if( status != ThreadStatus.LUA_OK )
|
|
|
|
|
return status;
|
|
|
|
|
return API.PCall( 0, LuaDef.LUA_MULTRET, 0 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string L_Gsub( string src, string pattern, string rep )
|
|
|
|
|
{
|
|
|
|
|
string res = src.Replace(pattern, rep);
|
|
|
|
|
API.PushString( res );
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string L_ToString( int index )
|
|
|
|
|
{
|
|
|
|
|
if( !L_CallMeta( index, "__tostring" ) ) // no metafield? // TODO L_CallMeta
|
|
|
|
|
{
|
|
|
|
|
switch( API.Type(index) )
|
|
|
|
|
{
|
|
|
|
|
case LuaType.LUA_TNUMBER:
|
|
|
|
|
case LuaType.LUA_TSTRING:
|
|
|
|
|
API.PushValue( index );
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case LuaType.LUA_TBOOLEAN:
|
|
|
|
|
API.PushString( API.ToBoolean( index ) ? "true" : "false" );
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case LuaType.LUA_TNIL:
|
|
|
|
|
API.PushString( "nil" );
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
API.PushString( string.Format("{0}: {1:X}"
|
|
|
|
|
, L_TypeName( index )
|
|
|
|
|
, API.ToObject( index ).GetHashCode()
|
|
|
|
|
) );
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return API.ToString( -1 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// private static class LibLoadInfo
|
|
|
|
|
// {
|
|
|
|
|
// public static List<NameFuncPair> Items;
|
|
|
|
|
|
|
|
|
|
// static LibLoadInfo()
|
|
|
|
|
// {
|
|
|
|
|
// Items = new List<NameFuncPair>();
|
|
|
|
|
// Add( "_G", LuaState.LuaOpen_Base );
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// private static void Add( string name, CSharpFunctionDelegate loadFunc )
|
|
|
|
|
// {
|
|
|
|
|
// Items.Add( new NameFuncPair { Name=name, LoadFunc=loadFunc } );
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
public void L_OpenLibs()
|
|
|
|
|
{
|
|
|
|
|
NameFuncPair[] define = new NameFuncPair[]
|
|
|
|
|
{
|
|
|
|
|
new NameFuncPair( "_G", LuaBaseLib.OpenLib ),
|
|
|
|
|
new NameFuncPair( LuaPkgLib.LIB_NAME, LuaPkgLib.OpenLib ),
|
|
|
|
|
new NameFuncPair( LuaCoroLib.LIB_NAME, LuaCoroLib.OpenLib ),
|
|
|
|
|
new NameFuncPair( LuaTableLib.LIB_NAME, LuaTableLib.OpenLib ),
|
|
|
|
|
new NameFuncPair( LuaIOLib.LIB_NAME, LuaIOLib.OpenLib ),
|
|
|
|
|
new NameFuncPair( LuaOSLib.LIB_NAME, LuaOSLib.OpenLib ),
|
|
|
|
|
// {LUA_OSLIBNAME, luaopen_os},
|
|
|
|
|
new NameFuncPair( LuaStrLib.LIB_NAME, LuaStrLib.OpenLib ),
|
|
|
|
|
new NameFuncPair( LuaBitLib.LIB_NAME, LuaBitLib.OpenLib ),
|
|
|
|
|
new NameFuncPair( LuaMathLib.LIB_NAME, LuaMathLib.OpenLib ),
|
|
|
|
|
new NameFuncPair( LuaDebugLib.LIB_NAME, LuaDebugLib.OpenLib ),
|
|
|
|
|
new NameFuncPair( LuaEncLib.LIB_NAME, LuaEncLib.OpenLib ),
|
2026-02-04 17:15:18 +08:00
|
|
|
new NameFuncPair( LuaJsonLib.LIB_NAME, LuaJsonLib.OpenLib ),
|
2026-02-03 02:44:58 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for( var i=0; i<define.Length; ++i)
|
|
|
|
|
{
|
|
|
|
|
L_RequireF( define[i].Name, define[i].Func, true );
|
|
|
|
|
API.Pop( 1 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// LuaBaseLib.LuaOpen_Base( this );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void L_RequireF( string moduleName, CSharpFunctionDelegate openFunc, bool global )
|
|
|
|
|
{
|
|
|
|
|
API.PushCSharpFunction( openFunc );
|
|
|
|
|
API.PushString( moduleName );
|
|
|
|
|
API.Call( 1, 1 );
|
|
|
|
|
L_GetSubTable( LuaDef.LUA_REGISTRYINDEX, "_LOADED" );
|
|
|
|
|
API.PushValue( -2 );
|
|
|
|
|
API.SetField( -2, moduleName );
|
|
|
|
|
API.Pop( 1 );
|
|
|
|
|
if( global )
|
|
|
|
|
{
|
|
|
|
|
API.PushValue( -1 );
|
|
|
|
|
API.SetGlobal( moduleName );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int L_GetSubTable( int index, string fname )
|
|
|
|
|
{
|
|
|
|
|
API.GetField( index, fname );
|
|
|
|
|
if( API.IsTable( -1 ) )
|
|
|
|
|
return 1;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
API.Pop( 1 );
|
|
|
|
|
index = API.AbsIndex( index );
|
|
|
|
|
API.NewTable();
|
|
|
|
|
API.PushValue( -1 );
|
|
|
|
|
API.SetField( index, fname );
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void L_NewLibTable( NameFuncPair[] define )
|
|
|
|
|
{
|
|
|
|
|
API.CreateTable( 0, define.Length );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void L_NewLib( NameFuncPair[] define )
|
|
|
|
|
{
|
|
|
|
|
L_NewLibTable( define );
|
|
|
|
|
L_SetFuncs( define, 0 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void L_SetFuncs( NameFuncPair[] define, int nup )
|
|
|
|
|
{
|
|
|
|
|
// TODO: Check Version
|
|
|
|
|
L_CheckStack(nup, "too many upvalues");
|
|
|
|
|
for( var j=0; j<define.Length; ++j )
|
|
|
|
|
{
|
|
|
|
|
for( int i=0; i<nup; ++i )
|
|
|
|
|
API.PushValue( -nup );
|
|
|
|
|
API.PushCSharpClosure( define[j].Func, nup );
|
|
|
|
|
API.SetField( -(nup + 2), define[j].Name );
|
|
|
|
|
}
|
|
|
|
|
API.Pop( nup );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool FindField( int objIndex, int level )
|
|
|
|
|
{
|
|
|
|
|
if( level == 0 || !API.IsTable(-1) )
|
|
|
|
|
return false; // not found
|
|
|
|
|
|
|
|
|
|
API.PushNil(); // start 'next' loop
|
|
|
|
|
while( API.Next(-2) ) // for each pair in table
|
|
|
|
|
{
|
|
|
|
|
if( API.Type(-2) == LuaType.LUA_TSTRING ) // ignore non-string keys
|
|
|
|
|
{
|
|
|
|
|
if( API.RawEqual( objIndex, -1 ) ) // found object?
|
|
|
|
|
{
|
|
|
|
|
API.Pop(1); // remove value (but keep name)
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else if( FindField( objIndex, level-1 ) ) // try recursively
|
|
|
|
|
{
|
|
|
|
|
API.Remove( -2 ); // remove table (but keep name)
|
|
|
|
|
API.PushString( "." );
|
|
|
|
|
API.Insert( -2 ); // place '.' between the two names
|
|
|
|
|
API.Concat( 3 );
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
API.Pop(1); // remove value
|
|
|
|
|
}
|
|
|
|
|
return false; // not found
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool PushGlobalFuncName( LuaDebug ar )
|
|
|
|
|
{
|
|
|
|
|
int top = API.GetTop();
|
|
|
|
|
GetInfo( "f", ar );
|
|
|
|
|
API.PushGlobalTable();
|
|
|
|
|
if( FindField( top+1, 2 ) )
|
|
|
|
|
{
|
|
|
|
|
API.Copy( -1, top+1 );
|
|
|
|
|
API.Pop( 2 );
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
API.SetTop( top ); // remove function and global table
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private const int FreeList = 0;
|
|
|
|
|
|
|
|
|
|
public int L_Ref( int t )
|
|
|
|
|
{
|
|
|
|
|
if( API.IsNil(-1) )
|
|
|
|
|
{
|
|
|
|
|
API.Pop(1); // remove from stack
|
|
|
|
|
return LuaConstants.LUA_REFNIL; // `nil' has a unique fixed reference
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
t = API.AbsIndex(t);
|
|
|
|
|
API.RawGetI(t, FreeList); // get first free element
|
|
|
|
|
int reference = API.ToInteger(-1); // ref = t[freelist]
|
|
|
|
|
API.Pop(1); // remove it from stack
|
|
|
|
|
if( reference != 0 ) // any free element?
|
|
|
|
|
{
|
|
|
|
|
API.RawGetI(t, reference); // remove it from list
|
|
|
|
|
API.RawSetI(t, FreeList); // t[freelist] = t[ref]
|
|
|
|
|
}
|
|
|
|
|
else // no free elements
|
|
|
|
|
reference = API.RawLen(t) + 1; // get a new reference
|
|
|
|
|
API.RawSetI(t, reference);
|
|
|
|
|
return reference;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void L_Unref( int t, int reference )
|
|
|
|
|
{
|
|
|
|
|
if( reference >= 0 )
|
|
|
|
|
{
|
|
|
|
|
t = API.AbsIndex(t);
|
|
|
|
|
API.RawGetI(t, FreeList);
|
|
|
|
|
API.RawSetI(t, reference); // t[ref] = t[freelist]
|
|
|
|
|
API.PushInteger(reference);
|
|
|
|
|
API.RawSetI(t, FreeList); // t[freelist] = ref
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if UNITY_IPHONE
|
|
|
|
|
public void FEED_AOT_FOR_IOS(LuaState lua)
|
|
|
|
|
{
|
|
|
|
|
lua.L_Opt( lua.L_CheckInteger, 1, 1);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|