Commit 2271a771 authored by Vinicius Jarina's avatar Vinicius Jarina
Browse files

Fixed test on iOS (device)

parent bf8c5fe6
Subproject commit 31271cd6f1b77768e6f70b4848e22fbc96b17338
Subproject commit 980e734233b9273426ba853b7078fddbc1f07549
Subproject commit f6a5029fb6650fe1cb763de1adf0df2f76a2fab6
Subproject commit ed5b8b89e20a6e230e12da1059918f6609bde2eb
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
using System.Reflection;
using System.Collections.Generic;
using LuaInterface.Method;
using LuaInterface.Extensions;
namespace LuaInterface
{
using LuaCore = KeraLua.Lua;
/*
* Type checking and conversion functions.
*
* Author: Fabio Mascarenhas
* Version: 1.0
*/
class CheckType
{
private Dictionary<long, ExtractValue> extractValues = new Dictionary<long, ExtractValue> ();
private ExtractValue extractNetObject;
private ObjectTranslator translator;
public CheckType (ObjectTranslator translator)
{
this.translator = translator;
extractValues.Add (typeof(object).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsObject));
extractValues.Add (typeof(sbyte).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsSbyte));
extractValues.Add (typeof(byte).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsByte));
extractValues.Add (typeof(short).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsShort));
extractValues.Add (typeof(ushort).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsUshort));
extractValues.Add (typeof(int).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsInt));
extractValues.Add (typeof(uint).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsUint));
extractValues.Add (typeof(long).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsLong));
extractValues.Add (typeof(ulong).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsUlong));
extractValues.Add (typeof(double).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsDouble));
extractValues.Add (typeof(char).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsChar));
extractValues.Add (typeof(float).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsFloat));
extractValues.Add (typeof(decimal).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsDecimal));
extractValues.Add (typeof(bool).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsBoolean));
extractValues.Add (typeof(string).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsString));
extractValues.Add (typeof(LuaFunction).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsFunction));
extractValues.Add (typeof(LuaTable).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsTable));
extractValues.Add (typeof(LuaUserData).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsUserdata));
extractNetObject = new ExtractValue (getAsNetObject);
}
/*
* Checks if the value at Lua stack index stackPos matches paramType,
* returning a conversion function if it does and null otherwise.
*/
internal ExtractValue getExtractor (IReflect paramType)
{
return getExtractor (paramType.UnderlyingSystemType);
}
internal ExtractValue getExtractor (Type paramType)
{
if (paramType.IsByRef)
paramType = paramType.GetElementType ();
long runtimeHandleValue = paramType.TypeHandle.Value.ToInt64 ();
return extractValues.ContainsKey (runtimeHandleValue) ? extractValues [runtimeHandleValue] : extractNetObject;
}
internal ExtractValue checkType (LuaCore.lua_State luaState, int stackPos, Type paramType)
{
var luatype = LuaLib.lua_type (luaState, stackPos);
if (paramType.IsByRef)
paramType = paramType.GetElementType ();
var underlyingType = Nullable.GetUnderlyingType (paramType);
if (!underlyingType.IsNull ())
paramType = underlyingType; // Silently convert nullable types to their non null requics
long runtimeHandleValue = paramType.TypeHandle.Value.ToInt64 ();
if (paramType.Equals (typeof(object)))
return extractValues [runtimeHandleValue];
//CP: Added support for generic parameters
if (paramType.IsGenericParameter) {
if (luatype == LuaTypes.Boolean)
return extractValues [typeof(bool).TypeHandle.Value.ToInt64 ()];
else if (luatype == LuaTypes.String)
return extractValues [typeof(string).TypeHandle.Value.ToInt64 ()];
else if (luatype == LuaTypes.Table)
return extractValues [typeof(LuaTable).TypeHandle.Value.ToInt64 ()];
else if (luatype == LuaTypes.UserData)
return extractValues [typeof(object).TypeHandle.Value.ToInt64 ()];
else if (luatype == LuaTypes.Function)
return extractValues [typeof(LuaFunction).TypeHandle.Value.ToInt64 ()];
else if (luatype == LuaTypes.Number)
return extractValues [typeof(double).TypeHandle.Value.ToInt64 ()];
//else
//;//an unsupported type was encountered
}
if (LuaLib.lua_isnumber (luaState, stackPos))
return extractValues [runtimeHandleValue];
if (paramType == typeof(bool)) {
if (LuaLib.lua_isboolean (luaState, stackPos))
return extractValues [runtimeHandleValue];
} else if (paramType == typeof(string)) {
if (LuaLib.lua_isstring (luaState, stackPos))
return extractValues [runtimeHandleValue];
else if (luatype == LuaTypes.Nil)
return extractNetObject; // kevinh - silently convert nil to a null string pointer
} else if (paramType == typeof(LuaTable)) {
if (luatype == LuaTypes.Table)
return extractValues [runtimeHandleValue];
} else if (paramType == typeof(LuaUserData)) {
if (luatype == LuaTypes.UserData)
return extractValues [runtimeHandleValue];
} else if (paramType == typeof(LuaFunction)) {
if (luatype == LuaTypes.Function)
return extractValues [runtimeHandleValue];
} else if (typeof(Delegate).IsAssignableFrom (paramType) && luatype == LuaTypes.Function)
return new ExtractValue (new DelegateGenerator (translator, paramType).extractGenerated);
else if (paramType.IsInterface && luatype == LuaTypes.Table)
return new ExtractValue (new ClassGenerator (translator, paramType).extractGenerated);
else if ((paramType.IsInterface || paramType.IsClass) && luatype == LuaTypes.Nil) {
// kevinh - allow nil to be silently converted to null - extractNetObject will return null when the item ain't found
return extractNetObject;
} else if (LuaLib.lua_type (luaState, stackPos) == LuaTypes.Table) {
if (LuaLib.luaL_getmetafield (luaState, stackPos, "__index")) {
object obj = translator.getNetObject (luaState, -1);
LuaLib.lua_settop (luaState, -2);
if (!obj.IsNull () && paramType.IsAssignableFrom (obj.GetType ()))
return extractNetObject;
} else
return null;
} else {
object obj = translator.getNetObject (luaState, stackPos);
if (!obj.IsNull () && paramType.IsAssignableFrom (obj.GetType ()))
return extractNetObject;
}
return null;
}
/*
* The following functions return the value in the Lua stack
* index stackPos as the desired type if it can, or null
* otherwise.
*/
private object getAsSbyte (LuaCore.lua_State luaState, int stackPos)
{
sbyte retVal = (sbyte)LuaLib.lua_tonumber (luaState, stackPos);
if (retVal == 0 && !LuaLib.lua_isnumber (luaState, stackPos))
return null;
return retVal;
}
private object getAsByte (LuaCore.lua_State luaState, int stackPos)
{
byte retVal = (byte)LuaLib.lua_tonumber (luaState, stackPos);
if (retVal == 0 && !LuaLib.lua_isnumber (luaState, stackPos))
return null;
return retVal;
}
private object getAsShort (LuaCore.lua_State luaState, int stackPos)
{
short retVal = (short)LuaLib.lua_tonumber (luaState, stackPos);
if (retVal == 0 && !LuaLib.lua_isnumber (luaState, stackPos))
return null;
return retVal;
}
private object getAsUshort (LuaCore.lua_State luaState, int stackPos)
{
ushort retVal = (ushort)LuaLib.lua_tonumber (luaState, stackPos);
if (retVal == 0 && !LuaLib.lua_isnumber (luaState, stackPos))
return null;
return retVal;
}
private object getAsInt (LuaCore.lua_State luaState, int stackPos)
{
int retVal = (int)LuaLib.lua_tonumber (luaState, stackPos);
if (retVal == 0 && !LuaLib.lua_isnumber (luaState, stackPos))
return null;
return retVal;
}
private object getAsUint (LuaCore.lua_State luaState, int stackPos)
{
uint retVal = (uint)LuaLib.lua_tonumber (luaState, stackPos);
if (retVal == 0 && !LuaLib.lua_isnumber (luaState, stackPos))
return null;
return retVal;
}
private object getAsLong (LuaCore.lua_State luaState, int stackPos)
{
long retVal = (long)LuaLib.lua_tonumber (luaState, stackPos);
if (retVal == 0 && !LuaLib.lua_isnumber (luaState, stackPos))
return null;
return retVal;
}
private object getAsUlong (LuaCore.lua_State luaState, int stackPos)
{
ulong retVal = (ulong)LuaLib.lua_tonumber (luaState, stackPos);
if (retVal == 0 && !LuaLib.lua_isnumber (luaState, stackPos))
return null;
return retVal;
}
private object getAsDouble (LuaCore.lua_State luaState, int stackPos)
{
double retVal = LuaLib.lua_tonumber (luaState, stackPos);
if (retVal == 0 && !LuaLib.lua_isnumber (luaState, stackPos))
return null;
return retVal;
}
private object getAsChar (LuaCore.lua_State luaState, int stackPos)
{
char retVal = (char)LuaLib.lua_tonumber (luaState, stackPos);
if (retVal == 0 && !LuaLib.lua_isnumber (luaState, stackPos))
return null;
return retVal;
}
private object getAsFloat (LuaCore.lua_State luaState, int stackPos)
{
float retVal = (float)LuaLib.lua_tonumber (luaState, stackPos);
if (retVal == 0 && !LuaLib.lua_isnumber (luaState, stackPos))
return null;
return retVal;
}
private object getAsDecimal (LuaCore.lua_State luaState, int stackPos)
{
decimal retVal = (decimal)LuaLib.lua_tonumber (luaState, stackPos);
if (retVal == 0 && !LuaLib.lua_isnumber (luaState, stackPos))
return null;
return retVal;
}
private object getAsBoolean (LuaCore.lua_State luaState, int stackPos)
{
return LuaLib.lua_toboolean (luaState, stackPos);
}
private object getAsString (LuaCore.lua_State luaState, int stackPos)
{
string retVal = LuaLib.lua_tostring (luaState, stackPos).ToString ();
if (retVal == string.Empty && !LuaLib.lua_isstring (luaState, stackPos))
return null;
return retVal;
}
private object getAsTable (LuaCore.lua_State luaState, int stackPos)
{
return translator.getTable (luaState, stackPos);
}
private object getAsFunction (LuaCore.lua_State luaState, int stackPos)
{
return translator.getFunction (luaState, stackPos);
}
private object getAsUserdata (LuaCore.lua_State luaState, int stackPos)
{
return translator.getUserData (luaState, stackPos);
}
public object getAsObject (LuaCore.lua_State luaState, int stackPos)
{
if (LuaLib.lua_type (luaState, stackPos) == LuaTypes.Table) {
if (LuaLib.luaL_getmetafield (luaState, stackPos, "__index")) {
if (LuaLib.luaL_checkmetatable (luaState, -1)) {
LuaLib.lua_insert (luaState, stackPos);
LuaLib.lua_remove (luaState, stackPos + 1);
} else
LuaLib.lua_settop (luaState, -2);
}
}
object obj = translator.getObject (luaState, stackPos);
return obj;
}
public object getAsNetObject (LuaCore.lua_State luaState, int stackPos)
{
object obj = translator.getNetObject (luaState, stackPos);
if (obj.IsNull () && LuaLib.lua_type (luaState, stackPos) == LuaTypes.Table) {
if (LuaLib.luaL_getmetafield (luaState, stackPos, "__index")) {
if (LuaLib.luaL_checkmetatable (luaState, -1)) {
LuaLib.lua_insert (luaState, stackPos);
LuaLib.lua_remove (luaState, stackPos + 1);
obj = translator.getNetObject (luaState, stackPos);
} else
LuaLib.lua_settop (luaState, -2);
}
}
return obj;
}
}
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
using System.Reflection;
using System.Collections.Generic;
using LuaInterface.Method;
using LuaInterface.Extensions;
namespace LuaInterface
{
#if USE_KOPILUA
using LuaCore = KopiLua.Lua;
#else
using LuaCore = KeraLua.Lua;
#endif
/*
* Type checking and conversion functions.
*
* Author: Fabio Mascarenhas
* Version: 1.0
*/
class CheckType
{
private Dictionary<long, ExtractValue> extractValues = new Dictionary<long, ExtractValue> ();
private ExtractValue extractNetObject;
private ObjectTranslator translator;
public CheckType (ObjectTranslator translator)
{
this.translator = translator;
extractValues.Add (typeof(object).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsObject));
extractValues.Add (typeof(sbyte).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsSbyte));
extractValues.Add (typeof(byte).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsByte));
extractValues.Add (typeof(short).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsShort));
extractValues.Add (typeof(ushort).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsUshort));
extractValues.Add (typeof(int).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsInt));
extractValues.Add (typeof(uint).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsUint));
extractValues.Add (typeof(long).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsLong));
extractValues.Add (typeof(ulong).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsUlong));
extractValues.Add (typeof(double).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsDouble));
extractValues.Add (typeof(char).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsChar));
extractValues.Add (typeof(float).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsFloat));
extractValues.Add (typeof(decimal).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsDecimal));
extractValues.Add (typeof(bool).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsBoolean));
extractValues.Add (typeof(string).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsString));
extractValues.Add (typeof(LuaFunction).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsFunction));
extractValues.Add (typeof(LuaTable).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsTable));
extractValues.Add (typeof(LuaUserData).TypeHandle.Value.ToInt64 (), new ExtractValue (getAsUserdata));
extractNetObject = new ExtractValue (getAsNetObject);
}
/*
* Checks if the value at Lua stack index stackPos matches paramType,
* returning a conversion function if it does and null otherwise.
*/
internal ExtractValue getExtractor (IReflect paramType)
{
return getExtractor (paramType.UnderlyingSystemType);
}
internal ExtractValue getExtractor (Type paramType)
{
if (paramType.IsByRef)
paramType = paramType.GetElementType ();
long runtimeHandleValue = paramType.TypeHandle.Value.ToInt64 ();
return extractValues.ContainsKey (runtimeHandleValue) ? extractValues [runtimeHandleValue] : extractNetObject;
}
internal ExtractValue checkType (LuaCore.lua_State luaState, int stackPos, Type paramType)
{
var luatype = LuaLib.lua_type (luaState, stackPos);
if (paramType.IsByRef)
paramType = paramType.GetElementType ();
var underlyingType = Nullable.GetUnderlyingType (paramType);
if (!underlyingType.IsNull ())
paramType = underlyingType; // Silently convert nullable types to their non null requics
long runtimeHandleValue = paramType.TypeHandle.Value.ToInt64 ();
if (paramType.Equals (typeof(object)))
return extractValues [runtimeHandleValue];
//CP: Added support for generic parameters
if (paramType.IsGenericParameter) {
if (luatype == LuaTypes.Boolean)
return extractValues [typeof(bool).TypeHandle.Value.ToInt64 ()];
else if (luatype == LuaTypes.String)
return extractValues [typeof(string).TypeHandle.Value.ToInt64 ()];
else if (luatype == LuaTypes.Table)
return extractValues [typeof(LuaTable).TypeHandle.Value.ToInt64 ()];
else if (luatype == LuaTypes.UserData)
return extractValues [typeof(object).TypeHandle.Value.ToInt64 ()];
else if (luatype == LuaTypes.Function)
return extractValues [typeof(LuaFunction).TypeHandle.Value.ToInt64 ()];
else if (luatype == LuaTypes.Number)
return extractValues [typeof(double).TypeHandle.Value.ToInt64 ()];
//else
//;//an unsupported type was encountered
}
if (LuaLib.lua_isnumber (luaState, stackPos))
return extractValues [runtimeHandleValue];
if (paramType == typeof(bool)) {
if (LuaLib.lua_isboolean (luaState, stackPos))
return extractValues [runtimeHandleValue];
} else if (paramType == typeof(string)) {
if (LuaLib.lua_isstring (luaState, stackPos))
return extractValues [runtimeHandleValue];
else if (luatype == LuaTypes.Nil)
return extractNetObject; // kevinh - silently convert nil to a null string pointer
} else if (paramType == typeof(LuaTable)) {
if (luatype == LuaTypes.Table)
return extractValues [runtimeHandleValue];
} else if (paramType == typeof(LuaUserData)) {
if (luatype == LuaTypes.UserData)
return extractValues [runtimeHandleValue];
} else if (paramType == typeof(LuaFunction)) {
if (luatype == LuaTypes.Function)
return extractValues [runtimeHandleValue];
} else if (typeof(Delegate).IsAssignableFrom (paramType) && luatype == LuaTypes.Function)
return new ExtractValue (new DelegateGenerator (translator, paramType).extractGenerated);
else if (paramType.IsInterface && luatype == LuaTypes.Table)
return new ExtractValue (new ClassGenerator (translator, paramType).extractGenerated);
else if ((paramType.IsInterface || paramType.IsClass) && luatype == LuaTypes.Nil) {
// kevinh - allow nil to be silently converted to null - extractNetObject will return null when the item ain't found
return extractNetObject;
} else if (LuaLib.lua_type (luaState, stackPos) == LuaTypes.Table) {
if (LuaLib.luaL_getmetafield (luaState, stackPos, "__index")) {
object obj = translator.getNetObject (luaState, -1);
LuaLib.lua_settop (luaState, -2);
if (!obj.IsNull () && paramType.IsAssignableFrom (obj.GetType ()))
return extractNetObject;
} else
return null;
} else {
object obj = translator.getNetObject (luaState, stackPos);
if (!obj.IsNull () && paramType.IsAssignableFrom (obj.GetType ()))
return extractNetObject;
}
return null;
}
/*
* The following functions return the value in the Lua stack
* index stackPos as the desired type if it can, or null
* otherwise.
*/
private object getAsSbyte (LuaCore.lua_State luaState, int stackPos)
{
sbyte retVal = (sbyte)LuaLib.lua_tonumber (luaState, stackPos);
if (retVal == 0 && !LuaLib.lua_isnumber (luaState, stackPos))
return null;
return retVal;
}
private object getAsByte (LuaCore.lua_State luaState, int stackPos)
{
byte retVal = (byte)LuaLib.lua_tonumber (luaState, stackPos);
if (retVal == 0 && !LuaLib.lua_isnumber (luaState, stackPos))
return null;
return retVal;
}
private object getAsShort (LuaCore.lua_State luaState, int stackPos)
{
short retVal = (short)LuaLib.lua_tonumber (luaState, stackPos);
if (retVal == 0 && !LuaLib.lua_isnumber (luaState, stackPos))
return null;
return retVal;
}
private object getAsUshort (LuaCore.lua_State luaState, int stackPos)
{
ushort retVal = (ushort)LuaLib.lua_tonumber (luaState, stackPos);
if (retVal == 0 && !LuaLib.lua_isnumber (luaState, stackPos))
return null;
return retVal;
}
private object getAsInt (LuaCore.lua_State luaState, int stackPos)
{
int retVal = (int)LuaLib.lua_tonumber (luaState, stackPos);
if (retVal == 0 && !LuaLib.lua_isnumber (luaState, stackPos))
return null;
return retVal;
}
private object getAsUint (LuaCore.lua_State luaState, int stackPos)
{
uint retVal = (uint)LuaLib.lua_tonumber (luaState, stackPos);
if (retVal == 0 && !LuaLib.lua_isnumber (luaState, stackPos))
return null;
return retVal;
}
private object getAsLong (LuaCore.lua_State luaState, int stackPos)
{
long retVal = (long)LuaLib.lua_tonumber (luaState, stackPos);
if (retVal == 0 && !LuaLib.lua_isnumber (luaState, stackPos))
return null;
return retVal;
}
private object getAsUlong (LuaCore.lua_State luaState, int stackPos)
{
ulong retVal = (ulong)LuaLib.lua_tonumber (luaState, stackPos);
if (retVal == 0 && !LuaLib.lua_isnumber (luaState, stackPos))
return null;
return retVal;
}
private object getAsDouble (LuaCore.lua_State luaState, int stackPos)
{
double retVal = LuaLib.lua_tonumber (luaState, stackPos);
if (retVal == 0 && !LuaLib.lua_isnumber (luaState, stackPos))
return null;
return retVal;
}
private object getAsChar (LuaCore.lua_State luaState, int stackPos)
{
char retVal = (char)LuaLib.lua_tonumber (luaState, stackPos);
if (retVal == 0 && !LuaLib.lua_isnumber (luaState, stackPos))
return null;
return retVal;
}
private object getAsFloat (LuaCore.lua_State luaState, int stackPos)
{
float retVal = (float)LuaLib.lua_tonumber (luaState, stackPos);
if (retVal == 0 && !LuaLib.lua_isnumber (luaState, stackPos))
return null;
return retVal;
}
private object getAsDecimal (LuaCore.lua_State luaState, int stackPos)
{
decimal retVal = (decimal)LuaLib.lua_tonumber (luaState, stackPos);
if (retVal == 0 && !LuaLib.lua_isnumber (luaState, stackPos))
return null;
return retVal;
}
private object getAsBoolean (LuaCore.lua_State luaState, int stackPos)
{
return LuaLib.lua_toboolean (luaState, stackPos);
}
private object getAsString (LuaCore.lua_State luaState, int stackPos)
{
string retVal = LuaLib.lua_tostring (luaState, stackPos).ToString ();
if (retVal == string.Empty && !LuaLib.lua_isstring (luaState, stackPos))
return null;
return retVal;
}
private object getAsTable (LuaCore.lua_State luaState, int stackPos)
{
return translator.getTable (luaState, stackPos);
}
private object getAsFunction (LuaCore.lua_State luaState, int stackPos)
{
return translator.getFunction (luaState, stackPos);
}
private object getAsUserdata (LuaCore.lua_State luaState, int stackPos)
{
return translator.getUserData (luaState, stackPos);
}
public object getAsObject (LuaCore.lua_State luaState, int stackPos)
{
if (LuaLib.lua_type (luaState, stackPos) == LuaTypes.Table) {
if (LuaLib.luaL_getmetafield (luaState, stackPos, "__index")) {
if (LuaLib.luaL_checkmetatable (luaState, -1)) {
LuaLib.lua_insert (luaState, stackPos);
LuaLib.lua_remove (luaState, stackPos + 1);
} else
LuaLib.lua_settop (luaState, -2);
}
}
object obj = translator.getObject (luaState, stackPos);
return obj;
}
public object getAsNetObject (LuaCore.lua_State luaState, int stackPos)
{
object obj = translator.getNetObject (luaState, stackPos);
if (obj.IsNull () && LuaLib.lua_type (luaState, stackPos) == LuaTypes.Table) {
if (LuaLib.luaL_getmetafield (luaState, stackPos, "__index")) {
if (LuaLib.luaL_checkmetatable (luaState, -1)) {
LuaLib.lua_insert (luaState, stackPos);
LuaLib.lua_remove (luaState, stackPos + 1);
obj = translator.getNetObject (luaState, stackPos);
} else
LuaLib.lua_settop (luaState, -2);
}
}
return obj;
}
}
}
\ No newline at end of file
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
namespace LuaInterface.Event
{
using LuaCore = KeraLua.Lua;
/// <summary>
/// Event args for hook callback event
/// </summary>
/// <author>Reinhard Ostermeier</author>
public class DebugHookEventArgs : EventArgs
{
private readonly LuaCore.lua_Debug luaDebug;
public DebugHookEventArgs (LuaCore.lua_Debug luaDebug)
{
this.luaDebug = luaDebug;
}
public LuaCore.lua_Debug LuaDebug {
get { return luaDebug; }
}
}
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
namespace LuaInterface.Event
{
#if USE_KOPILUA
using LuaCore = KopiLua.Lua;
#else
using LuaCore = KeraLua.Lua;
#endif
/// <summary>
/// Event args for hook callback event
/// </summary>
/// <author>Reinhard Ostermeier</author>
public class DebugHookEventArgs : EventArgs
{
private readonly LuaCore.lua_Debug luaDebug;
public DebugHookEventArgs (LuaCore.lua_Debug luaDebug)
{
this.luaDebug = luaDebug;
}
public LuaCore.lua_Debug LuaDebug {
get { return luaDebug; }
}
}
}
\ No newline at end of file
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
namespace LuaInterface.Extensions
{
/// <summary>
/// Some random extension stuff.
/// </summary>
static class GeneralExtensions
{
/// <summary>
/// Determines whether the specified obj is null.
/// </summary>
/// <param name="obj">The obj.</param>
/// <returns>
/// <c>true</c> if the specified obj is null; otherwise, <c>false</c>.
/// </returns>
public static bool IsNull (this object obj)
{
return (obj == null);
}
public static bool IsNull (this IntPtr ptr)
{
return (ptr == null || ptr.Equals (IntPtr.Zero));
}
}
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
namespace LuaInterface.Extensions
{
/// <summary>
/// Some random extension stuff.
/// </summary>
static class GeneralExtensions
{
/// <summary>
/// Determines whether the specified obj is null.
/// </summary>
/// <param name="obj">The obj.</param>
/// <returns>
/// <c>true</c> if the specified obj is null; otherwise, <c>false</c>.
/// </returns>
public static bool IsNull (this object obj)
{
return (obj == null);
}
public static bool IsNull (this IntPtr ptr)
{
return (ptr.Equals (IntPtr.Zero));
}
}
}
\ No newline at end of file
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
namespace LuaInterface
{
using LuaCore = KeraLua.Lua;
/*
* Class used for generating delegates that get a table from the Lua
* stack as a an object of a specific type.
*
* Author: Fabio Mascarenhas
* Version: 1.0
*/
class ClassGenerator
{
private ObjectTranslator translator;
private Type klass;
public ClassGenerator (ObjectTranslator translator, Type klass)
{
this.translator = translator;
this.klass = klass;
}
public object extractGenerated (LuaCore.lua_State luaState, int stackPos)
{
return CodeGeneration.Instance.GetClassInstance (klass, translator.getTable (luaState, stackPos));
}
}
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
namespace LuaInterface
{
#if USE_KOPILUA
using LuaCore = KopiLua.Lua;
#else
using LuaCore = KeraLua.Lua;
#endif
/*
* Class used for generating delegates that get a table from the Lua
* stack as a an object of a specific type.
*
* Author: Fabio Mascarenhas
* Version: 1.0
*/
class ClassGenerator
{
private ObjectTranslator translator;
private Type klass;
public ClassGenerator (ObjectTranslator translator, Type klass)
{
this.translator = translator;
this.klass = klass;
}
public object extractGenerated (LuaCore.lua_State luaState, int stackPos)
{
return CodeGeneration.Instance.GetClassInstance (klass, translator.getTable (luaState, stackPos));
}
}
}
\ No newline at end of file
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
namespace LuaInterface
{
using LuaCore = KeraLua.Lua;
/*
* Class used for generating delegates that get a function from the Lua
* stack as a delegate of a specific type.
*
* Author: Fabio Mascarenhas
* Version: 1.0
*/
class DelegateGenerator
{
private ObjectTranslator translator;
private Type delegateType;
public DelegateGenerator (ObjectTranslator translator, Type delegateType)
{
this.translator = translator;
this.delegateType = delegateType;
}
public object extractGenerated (LuaCore.lua_State luaState, int stackPos)
{
return CodeGeneration.Instance.GetDelegate (delegateType, translator.getFunction (luaState, stackPos));
}
}
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
namespace LuaInterface
{
#if USE_KOPILUA
using LuaCore = KopiLua.Lua;
#else
using LuaCore = KeraLua.Lua;
#endif
/*
* Class used for generating delegates that get a function from the Lua
* stack as a delegate of a specific type.
*
* Author: Fabio Mascarenhas
* Version: 1.0
*/
class DelegateGenerator
{
private ObjectTranslator translator;
private Type delegateType;
public DelegateGenerator (ObjectTranslator translator, Type delegateType)
{
this.translator = translator;
this.delegateType = delegateType;
}
public object extractGenerated (LuaCore.lua_State luaState, int stackPos)
{
return CodeGeneration.Instance.GetDelegate (delegateType, translator.getFunction (luaState, stackPos));
}
}
}
\ No newline at end of file
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
using System.IO;
using System.Threading;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using LuaInterface.Event;
using LuaInterface.Method;
using LuaInterface.Exceptions;
using LuaInterface.Extensions;
namespace LuaInterface
{
using LuaCore = KeraLua.Lua;
/*
* Main class of LuaInterface
* Object-oriented wrapper to Lua API
*
* Author: Fabio Mascarenhas
* Version: 1.0
*
* // steffenj: important changes in Lua class:
* - removed all Open*Lib() functions
* - all libs automatically open in the Lua class constructor (just assign nil to unwanted libs)
* */
[CLSCompliant(true)]
public class Lua : IDisposable
{
#region lua debug functions
/// <summary>
/// Event that is raised when an exception occures during a hook call.
/// </summary>
/// <author>Reinhard Ostermeier</author>
public event EventHandler<HookExceptionEventArgs> HookException;
/// <summary>
/// Event when lua hook callback is called
/// </summary>
/// <remarks>
/// Is only raised if SetDebugHook is called before.
/// </remarks>
/// <author>Reinhard Ostermeier</author>
public event EventHandler<DebugHookEventArgs> DebugHook;
/// <summary>
/// lua hook calback delegate
/// </summary>
/// <author>Reinhard Ostermeier</author>
private LuaCore.lua_Hook hookCallback = null;
#endregion
#region Globals auto-complete
private readonly List<string> globals = new List<string> ();
private bool globalsSorted;
#endregion
private /*readonly */ LuaCore.lua_State luaState;
/// <summary>
/// True while a script is being executed
/// </summary>
public bool IsExecuting { get { return executing; } }
private LuaCore.lua_CFunction panicCallback;
private ObjectTranslator translator;
/// <summary>
/// Used to ensure multiple .net threads all get serialized by this single lock for access to the lua stack/objects
/// </summary>
//private object luaLock = new object();
private bool _StatePassed;
private bool executing;
static string init_luanet =
"local metatable = {} \n" +
"local import_type = luanet.import_type \n" +
"local load_assembly = luanet.load_assembly \n" +
" \n" +
"-- Lookup a .NET identifier component. \n" +
"function metatable:__index(key) -- key is e.g. \"Form\" \n" +
" -- Get the fully-qualified name, e.g. \"System.Windows.Forms.Form\" \n" +
" local fqn = ((rawget(self, \".fqn\") and rawget(self, \".fqn\") .. \n" +
" \".\") or \"\") .. key \n" +
" \n" +
" -- Try to find either a luanet function or a CLR type \n" +
" local obj = rawget(luanet, key) or import_type(fqn) \n" +
" \n" +
" -- If key is neither a luanet function or a CLR type, then it is simply \n" +
" -- an identifier component. \n" +
" if obj == nil then \n" +
" -- It might be an assembly, so we load it too. \n" +
" load_assembly(fqn) \n" +
" obj = { [\".fqn\"] = fqn } \n" +
" setmetatable(obj, metatable) \n" +
" end \n" +
" \n" +
" -- Cache this lookup \n" +
" rawset(self, key, obj) \n" +
" return obj \n" +
"end \n" +
" \n" +
"-- A non-type has been called; e.g. foo = System.Foo() \n" +
"function metatable:__call(...) \n" +
" error(\"No such type: \" .. rawget(self, \".fqn\"), 2) \n" +
"end \n" +
" \n" +
"-- This is the root of the .NET namespace \n" +
"luanet[\".fqn\"] = false \n" +
"setmetatable(luanet, metatable) \n" +
" \n" +
"-- Preload the mscorlib assembly \n" +
"luanet.load_assembly(\"mscorlib\") \n";
#region Globals auto-complete
/// <summary>
/// An alphabetically sorted list of all globals (objects, methods, etc.) externally added to this Lua instance
/// </summary>
/// <remarks>Members of globals are also listed. The formatting is optimized for text input auto-completion.</remarks>
public IEnumerable<string> Globals {
get {
// Only sort list when necessary
if (!globalsSorted) {
globals.Sort ();
globalsSorted = true;
}
return globals;
}
}
#endregion
public Lua ()
{
luaState = LuaLib.luaL_newstate (); // steffenj: Lua 5.1.1 API change (lua_open is gone)
//LuaLib.luaopen_base(luaState); // steffenj: luaopen_* no longer used
LuaLib.luaL_openlibs (luaState); // steffenj: Lua 5.1.1 API change (luaopen_base is gone, just open all libs right here)
LuaLib.lua_pushstring (luaState, "LUAINTERFACE LOADED");
LuaLib.lua_pushboolean (luaState, true);
LuaLib.lua_settable (luaState, (int)LuaIndexes.Registry);
LuaLib.lua_newtable (luaState);
LuaLib.lua_setglobal (luaState, "luanet");
LuaLib.lua_pushvalue (luaState, (int)LuaIndexes.Globals);
LuaLib.lua_getglobal (luaState, "luanet");
LuaLib.lua_pushstring (luaState, "getmetatable");
LuaLib.lua_getglobal (luaState, "getmetatable");
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_replace (luaState, (int)LuaIndexes.Globals);
translator = new ObjectTranslator (this, luaState);
LuaLib.lua_replace (luaState, (int)LuaIndexes.Globals);
LuaLib.luaL_dostring (luaState, Lua.init_luanet); // steffenj: lua_dostring renamed to luaL_dostring
// We need to keep this in a managed reference so the delegate doesn't get garbage collected
panicCallback = new LuaCore.lua_CFunction (PanicCallback);
LuaLib.lua_atpanic (luaState, panicCallback);
//LuaLib.lua_atlock(luaState, lockCallback = new LuaCore.lua_CFunction(LockCallback));
//LuaLib.lua_atunlock(luaState, unlockCallback = new LuaCore.lua_CFunction(UnlockCallback));
}
/*
* CAUTION: LuaInterface.Lua instances can't share the same lua state!
*/
public Lua (LuaCore.lua_State lState)
{
LuaLib.lua_pushstring (lState, "LUAINTERFACE LOADED");
LuaLib.lua_gettable (lState, (int)LuaIndexes.Registry);
if (LuaLib.lua_toboolean (lState, -1)) {
LuaLib.lua_settop (lState, -2);
throw new LuaException ("There is already a LuaInterface.Lua instance associated with this Lua state");
} else {
LuaLib.lua_settop (lState, -2);
LuaLib.lua_pushstring (lState, "LUAINTERFACE LOADED");
LuaLib.lua_pushboolean (lState, true);
LuaLib.lua_settable (lState, (int)LuaIndexes.Registry);
luaState = lState;
LuaLib.lua_pushvalue (lState, (int)LuaIndexes.Globals);
LuaLib.lua_getglobal (lState, "luanet");
LuaLib.lua_pushstring (lState, "getmetatable");
LuaLib.lua_getglobal (lState, "getmetatable");
LuaLib.lua_settable (lState, -3);
LuaLib.lua_replace (lState, (int)LuaIndexes.Globals);
translator = new ObjectTranslator (this, luaState);
LuaLib.lua_replace (lState, (int)LuaIndexes.Globals);
LuaLib.luaL_dostring (lState, Lua.init_luanet); // steffenj: lua_dostring renamed to luaL_dostring
}
_StatePassed = true;
}
/// <summary>
/// Called for each lua_lock call
/// </summary>
/// <param name = "luaState"></param>
/// Not yet used
/*int LockCallback(LuaCore.lua_State luaState)
{
// Monitor.Enter(luaLock);
return 0;
}*/
/// <summary>
/// Called for each lua_unlock call
/// </summary>
/// <param name = "luaState"></param>
/// Not yet used
/*int UnlockCallback(LuaCore.lua_State luaState)
{
// Monitor.Exit(luaLock);
return 0;
}*/
public void Close ()
{
if (_StatePassed)
return;
////// if(luaState != LuaCore.lua_State.Zero)
if (!luaState.IsNull ())
LuaCore.lua_close (luaState);
//luaState = LuaCore.lua_State.Zero; <- suggested by Christopher Cebulski http://luaforge.net/forum/forum.php?thread_id = 44593&forum_id = 146
}
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
using System.IO;
using System.Threading;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using LuaInterface.Event;
using LuaInterface.Method;
using LuaInterface.Exceptions;
using LuaInterface.Extensions;
namespace LuaInterface
{
#if USE_KOPILUA
using LuaCore = KopiLua.Lua;
#else
using LuaCore = KeraLua.Lua;
#endif
/*
* Main class of LuaInterface
* Object-oriented wrapper to Lua API
*
* Author: Fabio Mascarenhas
* Version: 1.0
*
* // steffenj: important changes in Lua class:
* - removed all Open*Lib() functions
* - all libs automatically open in the Lua class constructor (just assign nil to unwanted libs)
* */
[CLSCompliant(true)]
public class Lua : IDisposable
{
#region lua debug functions
/// <summary>
/// Event that is raised when an exception occures during a hook call.
/// </summary>
/// <author>Reinhard Ostermeier</author>
public event EventHandler<HookExceptionEventArgs> HookException;
/// <summary>
/// Event when lua hook callback is called
/// </summary>
/// <remarks>
/// Is only raised if SetDebugHook is called before.
/// </remarks>
/// <author>Reinhard Ostermeier</author>
public event EventHandler<DebugHookEventArgs> DebugHook;
/// <summary>
/// lua hook calback delegate
/// </summary>
/// <author>Reinhard Ostermeier</author>
private LuaCore.lua_Hook hookCallback = null;
#endregion
#region Globals auto-complete
private readonly List<string> globals = new List<string> ();
private bool globalsSorted;
#endregion
private /*readonly */ LuaCore.lua_State luaState;
/// <summary>
/// True while a script is being executed
/// </summary>
public bool IsExecuting { get { return executing; } }
private LuaCore.lua_CFunction panicCallback;
private ObjectTranslator translator;
/// <summary>
/// Used to ensure multiple .net threads all get serialized by this single lock for access to the lua stack/objects
/// </summary>
//private object luaLock = new object();
private bool _StatePassed;
private bool executing;
static string init_luanet =
"local metatable = {} \n" +
"local import_type = luanet.import_type \n" +
"local load_assembly = luanet.load_assembly \n" +
" \n" +
"-- Lookup a .NET identifier component. \n" +
"function metatable:__index(key) -- key is e.g. \"Form\" \n" +
" -- Get the fully-qualified name, e.g. \"System.Windows.Forms.Form\" \n" +
" local fqn = ((rawget(self, \".fqn\") and rawget(self, \".fqn\") .. \n" +
" \".\") or \"\") .. key \n" +
" \n" +
" -- Try to find either a luanet function or a CLR type \n" +
" local obj = rawget(luanet, key) or import_type(fqn) \n" +
" \n" +
" -- If key is neither a luanet function or a CLR type, then it is simply \n" +
" -- an identifier component. \n" +
" if obj == nil then \n" +
" -- It might be an assembly, so we load it too. \n" +
" load_assembly(fqn) \n" +
" obj = { [\".fqn\"] = fqn } \n" +
" setmetatable(obj, metatable) \n" +
" end \n" +
" \n" +
" -- Cache this lookup \n" +
" rawset(self, key, obj) \n" +
" return obj \n" +
"end \n" +
" \n" +
"-- A non-type has been called; e.g. foo = System.Foo() \n" +
"function metatable:__call(...) \n" +
" error(\"No such type: \" .. rawget(self, \".fqn\"), 2) \n" +
"end \n" +
" \n" +
"-- This is the root of the .NET namespace \n" +
"luanet[\".fqn\"] = false \n" +
"setmetatable(luanet, metatable) \n" +
" \n" +
"-- Preload the mscorlib assembly \n" +
"luanet.load_assembly(\"mscorlib\") \n";
#region Globals auto-complete
/// <summary>
/// An alphabetically sorted list of all globals (objects, methods, etc.) externally added to this Lua instance
/// </summary>
/// <remarks>Members of globals are also listed. The formatting is optimized for text input auto-completion.</remarks>
public IEnumerable<string> Globals {
get {
// Only sort list when necessary
if (!globalsSorted) {
globals.Sort ();
globalsSorted = true;
}
return globals;
}
}
#endregion
public Lua ()
{
luaState = LuaLib.luaL_newstate (); // steffenj: Lua 5.1.1 API change (lua_open is gone)
//LuaLib.luaopen_base(luaState); // steffenj: luaopen_* no longer used
LuaLib.luaL_openlibs (luaState); // steffenj: Lua 5.1.1 API change (luaopen_base is gone, just open all libs right here)
LuaLib.lua_pushstring (luaState, "LUAINTERFACE LOADED");
LuaLib.lua_pushboolean (luaState, true);
LuaLib.lua_settable (luaState, (int)LuaIndexes.Registry);
LuaLib.lua_newtable (luaState);
LuaLib.lua_setglobal (luaState, "luanet");
LuaLib.lua_pushvalue (luaState, (int)LuaIndexes.Globals);
LuaLib.lua_getglobal (luaState, "luanet");
LuaLib.lua_pushstring (luaState, "getmetatable");
LuaLib.lua_getglobal (luaState, "getmetatable");
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_replace (luaState, (int)LuaIndexes.Globals);
translator = new ObjectTranslator (this, luaState);
ObjectTranslatorPool.Instance.Add (luaState, translator);
LuaLib.lua_replace (luaState, (int)LuaIndexes.Globals);
LuaLib.luaL_dostring (luaState, Lua.init_luanet); // steffenj: lua_dostring renamed to luaL_dostring
// We need to keep this in a managed reference so the delegate doesn't get garbage collected
panicCallback = new LuaCore.lua_CFunction (PanicCallback);
LuaLib.lua_atpanic (luaState, panicCallback);
//LuaLib.lua_atlock(luaState, lockCallback = new LuaCore.lua_CFunction(LockCallback));
//LuaLib.lua_atunlock(luaState, unlockCallback = new LuaCore.lua_CFunction(UnlockCallback));
}
/*
* CAUTION: LuaInterface.Lua instances can't share the same lua state!
*/
public Lua (LuaCore.lua_State lState)
{
LuaLib.lua_pushstring (lState, "LUAINTERFACE LOADED");
LuaLib.lua_gettable (lState, (int)LuaIndexes.Registry);
if (LuaLib.lua_toboolean (lState, -1)) {
LuaLib.lua_settop (lState, -2);
throw new LuaException ("There is already a LuaInterface.Lua instance associated with this Lua state");
} else {
LuaLib.lua_settop (lState, -2);
LuaLib.lua_pushstring (lState, "LUAINTERFACE LOADED");
LuaLib.lua_pushboolean (lState, true);
LuaLib.lua_settable (lState, (int)LuaIndexes.Registry);
luaState = lState;
LuaLib.lua_pushvalue (lState, (int)LuaIndexes.Globals);
LuaLib.lua_getglobal (lState, "luanet");
LuaLib.lua_pushstring (lState, "getmetatable");
LuaLib.lua_getglobal (lState, "getmetatable");
LuaLib.lua_settable (lState, -3);
LuaLib.lua_replace (lState, (int)LuaIndexes.Globals);
translator = new ObjectTranslator (this, luaState);
ObjectTranslatorPool.Instance.Add (luaState, translator);
LuaLib.lua_replace (lState, (int)LuaIndexes.Globals);
LuaLib.luaL_dostring (lState, Lua.init_luanet); // steffenj: lua_dostring renamed to luaL_dostring
}
_StatePassed = true;
}
/// <summary>
/// Called for each lua_lock call
/// </summary>
/// <param name = "luaState"></param>
/// Not yet used
/*int LockCallback(LuaCore.lua_State luaState)
{
// Monitor.Enter(luaLock);
return 0;
}*/
/// <summary>
/// Called for each lua_unlock call
/// </summary>
/// <param name = "luaState"></param>
/// Not yet used
/*int UnlockCallback(LuaCore.lua_State luaState)
{
// Monitor.Exit(luaLock);
return 0;
}*/
public void Close ()
{
if (_StatePassed)
return;
////// if(luaState != LuaCore.lua_State.Zero)
if (!luaState.IsNull ()) {
LuaCore.lua_close (luaState);
ObjectTranslatorPool.Instance.Remove (luaState);
}
//luaState = LuaCore.lua_State.Zero; <- suggested by Christopher Cebulski http://luaforge.net/forum/forum.php?thread_id = 44593&forum_id = 146
}
#if MONOTOUCH
[MonoTouch.MonoPInvokeCallback (typeof (LuaCore.lua_CFunction))]
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
static int PanicCallback (LuaCore.lua_State luaState)
{
// string desc = LuaLib.lua_tostring(luaState, 1);
string reason = string.Format ("unprotected error in call to Lua API ({0})", LuaLib.lua_tostring (luaState, -1));
// lua_tostring(L, -1);
throw new LuaException (reason);
}
/// <summary>
/// Assuming we have a Lua error string sitting on the stack, throw a C# exception out to the user's app
/// </summary>
/// <exception cref = "LuaScriptException">Thrown if the script caused an exception</exception>
private void ThrowExceptionFromError (int oldTop)
{
object err = translator.getObject (luaState, -1);
LuaLib.lua_settop (luaState, oldTop);
// A pre-wrapped exception - just rethrow it (stack trace of InnerException will be preserved)
var luaEx = err as LuaScriptException;
if (!luaEx.IsNull ())
throw luaEx;
// A non-wrapped Lua error (best interpreted as a string) - wrap it and throw it
if (err.IsNull ())
err = "Unknown Lua Error";
throw new LuaScriptException (err.ToString (), string.Empty);
}
/// <summary>
/// Convert C# exceptions into Lua errors
/// </summary>
/// <returns>num of things on stack</returns>
/// <param name = "e">null for no pending exception</param>
internal int SetPendingException (Exception e)
{
var caughtExcept = e;
if (!caughtExcept.IsNull ()) {
translator.throwError (luaState, caughtExcept);
LuaLib.lua_pushnil (luaState);
return 1;
} else
return 0;
}
/// <summary>
///
/// </summary>
/// <param name = "chunk"></param>
/// <param name = "name"></param>
/// <returns></returns>
public LuaFunction LoadString (string chunk, string name)
{
int oldTop = LuaLib.lua_gettop (luaState);
executing = true;
try {
if (LuaLib.luaL_loadbuffer (luaState, chunk, name) != 0)
ThrowExceptionFromError (oldTop);
} finally {
executing = false;
}
var result = translator.getFunction (luaState, -1);
translator.popValues (luaState, oldTop);
return result;
}
/// <summary>
///
/// </summary>
/// <param name = "fileName"></param>
/// <returns></returns>
public LuaFunction LoadFile (string fileName)
{
int oldTop = LuaLib.lua_gettop (luaState);
if (LuaLib.luaL_loadfile (luaState, fileName) != 0)
ThrowExceptionFromError (oldTop);
var result = translator.getFunction (luaState, -1);
translator.popValues (luaState, oldTop);
return result;
}
/*
* Excutes a Lua chunk and returns all the chunk's return
* values in an array
*/
public object[] DoString (string chunk)
{
int oldTop = LuaLib.lua_gettop (luaState);
if (LuaLib.luaL_loadbuffer (luaState, chunk, "chunk") == 0) {
executing = true;
try {
if (LuaLib.lua_pcall (luaState, 0, -1, 0) == 0)
return translator.popValues (luaState, oldTop);
else
ThrowExceptionFromError (oldTop);
} finally {
executing = false;
}
} else
ThrowExceptionFromError (oldTop);
return null; // Never reached - keeps compiler happy
}
/// <summary>
/// Executes a Lua chnk and returns all the chunk's return values in an array.
/// </summary>
/// <param name = "chunk">Chunk to execute</param>
/// <param name = "chunkName">Name to associate with the chunk</param>
/// <returns></returns>
public object[] DoString (string chunk, string chunkName)
{
int oldTop = LuaLib.lua_gettop (luaState);
executing = true;
if (LuaLib.luaL_loadbuffer (luaState, chunk, chunkName) == 0) {
try {
if (LuaLib.lua_pcall (luaState, 0, -1, 0) == 0)
return translator.popValues (luaState, oldTop);
else
ThrowExceptionFromError (oldTop);
} finally {
executing = false;
}
} else
ThrowExceptionFromError (oldTop);
return null; // Never reached - keeps compiler happy
}
/*
* Excutes a Lua file and returns all the chunk's return
* values in an array
*/
public object[] DoFile (string fileName)
{
int oldTop = LuaLib.lua_gettop (luaState);
if (LuaLib.luaL_loadfile (luaState, fileName) == 0) {
executing = true;
try {
if (LuaLib.lua_pcall (luaState, 0, -1, 0) == 0)
return translator.popValues (luaState, oldTop);
else
ThrowExceptionFromError (oldTop);
} finally {
executing = false;
}
} else
ThrowExceptionFromError (oldTop);
return null; // Never reached - keeps compiler happy
}
/*
* Indexer for global variables from the LuaInterpreter
* Supports navigation of tables by using . operator
*/
public object this [string fullPath] {
get {
object returnValue = null;
int oldTop = LuaLib.lua_gettop (luaState);
string[] path = fullPath.Split (new char[] { '.' });
LuaLib.lua_getglobal (luaState, path [0]);
returnValue = translator.getObject (luaState, -1);
if (path.Length > 1) {
string[] remainingPath = new string[path.Length - 1];
Array.Copy (path, 1, remainingPath, 0, path.Length - 1);
returnValue = getObject (remainingPath);
}
LuaLib.lua_settop (luaState, oldTop);
return returnValue;
}
set {
int oldTop = LuaLib.lua_gettop (luaState);
string[] path = fullPath.Split (new char[] { '.' });
if (path.Length == 1) {
translator.push (luaState, value);
LuaLib.lua_setglobal (luaState, fullPath);
} else {
LuaLib.lua_getglobal (luaState, path [0]);
string[] remainingPath = new string[path.Length - 1];
Array.Copy (path, 1, remainingPath, 0, path.Length - 1);
setObject (remainingPath, value);
}
LuaLib.lua_settop (luaState, oldTop);
// Globals auto-complete
if (value.IsNull ()) {
// Remove now obsolete entries
globals.Remove (fullPath);
} else {
// Add new entries
if (!globals.Contains (fullPath))
registerGlobal (fullPath, value.GetType (), 0);
}
}
}
#region Globals auto-complete
/// <summary>
/// Adds an entry to <see cref = "globals"/> (recursivley handles 2 levels of members)
/// </summary>
/// <param name = "path">The index accessor path ot the entry</param>
/// <param name = "type">The type of the entry</param>
/// <param name = "recursionCounter">How deep have we gone with recursion?</param>
private void registerGlobal (string path, Type type, int recursionCounter)
{
// If the type is a global method, list it directly
if (type == typeof(LuaCore.lua_CFunction)) {
// Format for easy method invocation
globals.Add (path + "(");
}
// If the type is a class or an interface and recursion hasn't been running too long, list the members
else if ((type.IsClass || type.IsInterface) && type != typeof(string) && recursionCounter < 2) {
#region Methods
foreach (var method in type.GetMethods(BindingFlags.Public | BindingFlags.Instance)) {
if (
// Check that the LuaHideAttribute and LuaGlobalAttribute were not applied
(method.GetCustomAttributes (typeof(LuaHideAttribute), false).Length == 0) &&
(method.GetCustomAttributes (typeof(LuaGlobalAttribute), false).Length == 0) &&
// Exclude some generic .NET methods that wouldn't be very usefull in Lua
method.Name != "GetType" && method.Name != "GetHashCode" && method.Name != "Equals" &&
method.Name != "ToString" && method.Name != "Clone" && method.Name != "Dispose" &&
method.Name != "GetEnumerator" && method.Name != "CopyTo" &&
!method.Name.StartsWith ("get_", StringComparison.Ordinal) &&
!method.Name.StartsWith ("set_", StringComparison.Ordinal) &&
!method.Name.StartsWith ("add_", StringComparison.Ordinal) &&
!method.Name.StartsWith ("remove_", StringComparison.Ordinal)) {
// Format for easy method invocation
string command = path + ":" + method.Name + "(";
if (method.GetParameters ().Length == 0)
command += ")";
globals.Add (command);
}
}
#endregion
#region Fields
foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.Instance)) {
if (
// Check that the LuaHideAttribute and LuaGlobalAttribute were not applied
(field.GetCustomAttributes (typeof(LuaHideAttribute), false).Length == 0) &&
(field.GetCustomAttributes (typeof(LuaGlobalAttribute), false).Length == 0)) {
// Go into recursion for members
registerGlobal (path + "." + field.Name, field.FieldType, recursionCounter + 1);
}
}
#endregion
#region Properties
foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)) {
if (
// Check that the LuaHideAttribute and LuaGlobalAttribute were not applied
(property.GetCustomAttributes (typeof(LuaHideAttribute), false).Length == 0) &&
(property.GetCustomAttributes (typeof(LuaGlobalAttribute), false).Length == 0)
// Exclude some generic .NET properties that wouldn't be very usefull in Lua
&& property.Name != "Item") {
// Go into recursion for members
registerGlobal (path + "." + property.Name, property.PropertyType, recursionCounter + 1);
}
}
#endregion
} else
globals.Add (path); // Otherwise simply add the element to the list
// List will need to be sorted on next access
globalsSorted = false;
}
#endregion
/*
* Navigates a table in the top of the stack, returning
* the value of the specified field
*/
internal object getObject (string[] remainingPath)
{
object returnValue = null;
for (int i = 0; i < remainingPath.Length; i++) {
LuaLib.lua_pushstring (luaState, remainingPath [i]);
LuaLib.lua_gettable (luaState, -2);
returnValue = translator.getObject (luaState, -1);
if (returnValue.IsNull ())
break;
}
return returnValue;
}
/*
* Gets a numeric global variable
*/
public double GetNumber (string fullPath)
{
return (double)this [fullPath];
}
/*
* Gets a string global variable
*/
public string GetString (string fullPath)
{
return this [fullPath].ToString ();
}
/*
* Gets a table global variable
*/
public LuaTable GetTable (string fullPath)
{
return (LuaTable)this [fullPath];
}
/*
* Gets a table global variable as an object implementing
* the interfaceType interface
*/
public object GetTable (Type interfaceType, string fullPath)
{
return CodeGeneration.Instance.GetClassInstance (interfaceType, GetTable (fullPath));
}
/*
* Gets a function global variable
*/
public LuaFunction GetFunction (string fullPath)
{
object obj = this [fullPath];
return (obj is LuaCore.lua_CFunction ? new LuaFunction ((LuaCore.lua_CFunction)obj, this) : (LuaFunction)obj);
}
/*
* Register a delegate type to be used to convert Lua funcitions to C# delegates (useful for iOS where there is no dynamic code generation)
* type delegateType
*/
public void RegisterLuaDelegateType (Type delegateType, Type luaDelegateType)
{
CodeGeneration.Instance.RegisterLuaDelegateType (delegateType, luaDelegateType);
}
public void RegisterLuaClassType (Type klass, Type luaClass)
{
CodeGeneration.Instance.RegisterLuaClassType (klass, luaClass);
}
/*
* Gets a function global variable as a delegate of
* type delegateType
*/
public Delegate GetFunction (Type delegateType, string fullPath)
{
return CodeGeneration.Instance.GetDelegate (delegateType, GetFunction (fullPath));
}
/*
* Calls the object as a function with the provided arguments,
* returning the function's returned values inside an array
*/
internal object[] callFunction (object function, object[] args)
{
return callFunction (function, args, null);
}
/*
* Calls the object as a function with the provided arguments and
* casting returned values to the types in returnTypes before returning
* them in an array
*/
internal object[] callFunction (object function, object[] args, Type[] returnTypes)
{
int nArgs = 0;
int oldTop = LuaLib.lua_gettop (luaState);
if (!LuaLib.lua_checkstack (luaState, args.Length + 6))
throw new LuaException ("Lua stack overflow");
translator.push (luaState, function);
if (!args.IsNull ()) {
nArgs = args.Length;
for (int i = 0; i < args.Length; i++)
translator.push (luaState, args [i]);
}
executing = true;
try {
int error = LuaLib.lua_pcall (luaState, nArgs, -1, 0);
if (error != 0)
ThrowExceptionFromError (oldTop);
} finally {
executing = false;
}
return !returnTypes.IsNull () ? translator.popValues (luaState, oldTop, returnTypes) : translator.popValues (luaState, oldTop);
}
/*
* Navigates a table to set the value of one of its fields
*/
internal void setObject (string[] remainingPath, object val)
{
for (int i = 0; i < remainingPath.Length-1; i++) {
LuaLib.lua_pushstring (luaState, remainingPath [i]);
LuaLib.lua_gettable (luaState, -2);
}
LuaLib.lua_pushstring (luaState, remainingPath [remainingPath.Length - 1]);
translator.push (luaState, val);
LuaLib.lua_settable (luaState, -3);
}
/*
* Creates a new table as a global variable or as a field
* inside an existing table
*/
public void NewTable (string fullPath)
{
string[] path = fullPath.Split (new char[] { '.' });
int oldTop = LuaLib.lua_gettop (luaState);
if (path.Length == 1) {
LuaLib.lua_newtable (luaState);
LuaLib.lua_setglobal (luaState, fullPath);
} else {
LuaLib.lua_getglobal (luaState, path [0]);
for (int i = 1; i < path.Length-1; i++) {
LuaLib.lua_pushstring (luaState, path [i]);
LuaLib.lua_gettable (luaState, -2);
}
LuaLib.lua_pushstring (luaState, path [path.Length - 1]);
LuaLib.lua_newtable (luaState);
LuaLib.lua_settable (luaState, -3);
}
LuaLib.lua_settop (luaState, oldTop);
}
public ListDictionary GetTableDict (LuaTable table)
{
var dict = new ListDictionary ();
int oldTop = LuaLib.lua_gettop (luaState);
translator.push (luaState, table);
LuaLib.lua_pushnil (luaState);
while (LuaLib.lua_next(luaState, -2) != 0) {
dict [translator.getObject (luaState, -2)] = translator.getObject (luaState, -1);
LuaLib.lua_settop (luaState, -2);
}
LuaLib.lua_settop (luaState, oldTop);
return dict;
}
/*
* Lets go of a previously allocated reference to a table, function
* or userdata
*/
#region lua debug functions
/// <summary>
/// Activates the debug hook
/// </summary>
/// <param name = "mask">Mask</param>
/// <param name = "count">Count</param>
/// <returns>see lua docs. -1 if hook is already set</returns>
/// <author>Reinhard Ostermeier</author>
public int SetDebugHook (EventMasks mask, int count)
{
if (hookCallback.IsNull ()) {
hookCallback = new LuaCore.lua_Hook (DebugHookCallback);
return LuaCore.lua_sethook (luaState, hookCallback, (int)mask, count);
}
return -1;
}
/// <summary>
/// Removes the debug hook
/// </summary>
/// <returns>see lua docs</returns>
/// <author>Reinhard Ostermeier</author>
public int RemoveDebugHook ()
{
hookCallback = null;
return LuaCore.lua_sethook (luaState, null, 0, 0);
}
/// <summary>
/// Gets the hook mask.
/// </summary>
/// <returns>hook mask</returns>
/// <author>Reinhard Ostermeier</author>
public EventMasks GetHookMask ()
{
return (EventMasks)LuaCore.lua_gethookmask (luaState);
}
/// <summary>
/// Gets the hook count
/// </summary>
/// <returns>see lua docs</returns>
/// <author>Reinhard Ostermeier</author>
public int GetHookCount ()
{
return LuaCore.lua_gethookcount (luaState);
}
/// <summary>
/// Gets the stack entry on a given level
/// </summary>
/// <param name = "level">level</param>
/// <param name = "luaDebug">lua debug structure</param>
/// <returns>Returns true if level was allowed, false if level was invalid.</returns>
/// <author>Reinhard Ostermeier</author>
/*public bool GetStack(int level, out LuaCore.lua_Debug luaDebug)
{
luaDebug = new LuaDebug();
LuaCore.lua_State ld = System.Runtime.InteropServices.Marshal.AllocHGlobal(System.Runtime.InteropServices.Marshal.SizeOf(luaDebug));
System.Runtime.InteropServices.Marshal.StructureToPtr(luaDebug, ld, false);
try
{
return LuaLib.lua_getstack(luaState, level, luaDebug) != 0;
}
finally
{
luaDebug = (LuaDebug)System.Runtime.InteropServices.Marshal.PtrToStructure(ld, typeof(LuaDebug));
System.Runtime.InteropServices.Marshal.FreeHGlobal(ld);
}
}*/
/// <summary>
/// Gets info (see lua docs)
/// </summary>
/// <param name = "what">what (see lua docs)</param>
/// <param name = "luaDebug">lua debug structure</param>
/// <returns>see lua docs</returns>
/// <author>Reinhard Ostermeier</author>
/*public int GetInfo(String what, ref LuaCore.lua_Debug luaDebug)
{
LuaCore.lua_State ld = System.Runtime.InteropServices.Marshal.AllocHGlobal(System.Runtime.InteropServices.Marshal.SizeOf(luaDebug));
System.Runtime.InteropServices.Marshal.StructureToPtr(luaDebug, ld, false);
try
{
return LuaLib.lua_getinfo(luaState, what, ld);
}
finally
{
luaDebug = (LuaDebug)System.Runtime.InteropServices.Marshal.PtrToStructure(ld, typeof(LuaDebug));
System.Runtime.InteropServices.Marshal.FreeHGlobal(ld);
}
}*/
/// <summary>
/// Gets local (see lua docs)
/// </summary>
/// <param name = "luaDebug">lua debug structure</param>
/// <param name = "n">see lua docs</param>
/// <returns>see lua docs</returns>
/// <author>Reinhard Ostermeier</author>
public string GetLocal (LuaCore.lua_Debug luaDebug, int n)
{
return LuaCore.lua_getlocal (luaState, luaDebug, n).ToString ();
}
/// <summary>
/// Sets local (see lua docs)
/// </summary>
/// <param name = "luaDebug">lua debug structure</param>
/// <param name = "n">see lua docs</param>
/// <returns>see lua docs</returns>
/// <author>Reinhard Ostermeier</author>
public string SetLocal (LuaCore.lua_Debug luaDebug, int n)
{
return LuaCore.lua_setlocal (luaState, luaDebug, n).ToString ();
}
/// <summary>
/// Gets up value (see lua docs)
/// </summary>
/// <param name = "funcindex">see lua docs</param>
/// <param name = "n">see lua docs</param>
/// <returns>see lua docs</returns>
/// <author>Reinhard Ostermeier</author>
public string GetUpValue (int funcindex, int n)
{
return LuaCore.lua_getupvalue (luaState, funcindex, n).ToString ();
}
/// <summary>
/// Sets up value (see lua docs)
/// </summary>
/// <param name = "funcindex">see lua docs</param>
/// <param name = "n">see lua docs</param>
/// <returns>see lua docs</returns>
/// <author>Reinhard Ostermeier</author>
public string SetUpValue (int funcindex, int n)
{
return LuaCore.lua_setupvalue (luaState, funcindex, n).ToString ();
}
/// <summary>
/// Delegate that is called on lua hook callback
/// </summary>
/// <param name = "luaState">lua state</param>
/// <param name = "luaDebug">Pointer to LuaDebug (lua_debug) structure</param>
/// <author>Reinhard Ostermeier</author>
///
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
static int PanicCallback (LuaCore.lua_State luaState)
{
// string desc = LuaLib.lua_tostring(luaState, 1);
string reason = string.Format ("unprotected error in call to Lua API ({0})", LuaLib.lua_tostring (luaState, -1));
// lua_tostring(L, -1);
throw new LuaException (reason);
}
/// <summary>
/// Assuming we have a Lua error string sitting on the stack, throw a C# exception out to the user's app
/// </summary>
/// <exception cref = "LuaScriptException">Thrown if the script caused an exception</exception>
private void ThrowExceptionFromError (int oldTop)
{
object err = translator.getObject (luaState, -1);
LuaLib.lua_settop (luaState, oldTop);
// A pre-wrapped exception - just rethrow it (stack trace of InnerException will be preserved)
var luaEx = err as LuaScriptException;
if (!luaEx.IsNull ())
throw luaEx;
// A non-wrapped Lua error (best interpreted as a string) - wrap it and throw it
if (err.IsNull ())
err = "Unknown Lua Error";
throw new LuaScriptException (err.ToString (), string.Empty);
}
/// <summary>
/// Convert C# exceptions into Lua errors
/// </summary>
/// <returns>num of things on stack</returns>
/// <param name = "e">null for no pending exception</param>
internal int SetPendingException (Exception e)
{
var caughtExcept = e;
if (!caughtExcept.IsNull ()) {
translator.throwError (luaState, caughtExcept);
LuaLib.lua_pushnil (luaState);
return 1;
} else
return 0;
}
/// <summary>
///
/// </summary>
/// <param name = "chunk"></param>
/// <param name = "name"></param>
/// <returns></returns>
public LuaFunction LoadString (string chunk, string name)
{
int oldTop = LuaLib.lua_gettop (luaState);
executing = true;
try {
if (LuaLib.luaL_loadbuffer (luaState, chunk, name) != 0)
ThrowExceptionFromError (oldTop);
} finally {
executing = false;
}
var result = translator.getFunction (luaState, -1);
translator.popValues (luaState, oldTop);
return result;
}
/// <summary>
///
/// </summary>
/// <param name = "fileName"></param>
/// <returns></returns>
public LuaFunction LoadFile (string fileName)
{
int oldTop = LuaLib.lua_gettop (luaState);
if (LuaLib.luaL_loadfile (luaState, fileName) != 0)
ThrowExceptionFromError (oldTop);
var result = translator.getFunction (luaState, -1);
translator.popValues (luaState, oldTop);
return result;
}
/*
* Excutes a Lua chunk and returns all the chunk's return
* values in an array
*/
public object[] DoString (string chunk)
{
int oldTop = LuaLib.lua_gettop (luaState);
if (LuaLib.luaL_loadbuffer (luaState, chunk, "chunk") == 0) {
executing = true;
try {
if (LuaLib.lua_pcall (luaState, 0, -1, 0) == 0)
return translator.popValues (luaState, oldTop);
else
ThrowExceptionFromError (oldTop);
} finally {
executing = false;
}
} else
ThrowExceptionFromError (oldTop);
return null; // Never reached - keeps compiler happy
}
/// <summary>
/// Executes a Lua chnk and returns all the chunk's return values in an array.
/// </summary>
/// <param name = "chunk">Chunk to execute</param>
/// <param name = "chunkName">Name to associate with the chunk</param>
/// <returns></returns>
public object[] DoString (string chunk, string chunkName)
{
int oldTop = LuaLib.lua_gettop (luaState);
executing = true;
if (LuaLib.luaL_loadbuffer (luaState, chunk, chunkName) == 0) {
try {
if (LuaLib.lua_pcall (luaState, 0, -1, 0) == 0)
return translator.popValues (luaState, oldTop);
else
ThrowExceptionFromError (oldTop);
} finally {
executing = false;
}
} else
ThrowExceptionFromError (oldTop);
return null; // Never reached - keeps compiler happy
}
/*
* Excutes a Lua file and returns all the chunk's return
* values in an array
*/
public object[] DoFile (string fileName)
{
int oldTop = LuaLib.lua_gettop (luaState);
if (LuaLib.luaL_loadfile (luaState, fileName) == 0) {
executing = true;
try {
if (LuaLib.lua_pcall (luaState, 0, -1, 0) == 0)
return translator.popValues (luaState, oldTop);
else
ThrowExceptionFromError (oldTop);
} finally {
executing = false;
}
} else
ThrowExceptionFromError (oldTop);
return null; // Never reached - keeps compiler happy
}
/*
* Indexer for global variables from the LuaInterpreter
* Supports navigation of tables by using . operator
*/
public object this [string fullPath] {
get {
object returnValue = null;
int oldTop = LuaLib.lua_gettop (luaState);
string[] path = fullPath.Split (new char[] { '.' });
LuaLib.lua_getglobal (luaState, path [0]);
returnValue = translator.getObject (luaState, -1);
if (path.Length > 1) {
string[] remainingPath = new string[path.Length - 1];
Array.Copy (path, 1, remainingPath, 0, path.Length - 1);
returnValue = getObject (remainingPath);
}
LuaLib.lua_settop (luaState, oldTop);
return returnValue;
}
set {
int oldTop = LuaLib.lua_gettop (luaState);
string[] path = fullPath.Split (new char[] { '.' });
if (path.Length == 1) {
translator.push (luaState, value);
LuaLib.lua_setglobal (luaState, fullPath);
} else {
LuaLib.lua_getglobal (luaState, path [0]);
string[] remainingPath = new string[path.Length - 1];
Array.Copy (path, 1, remainingPath, 0, path.Length - 1);
setObject (remainingPath, value);
}
LuaLib.lua_settop (luaState, oldTop);
// Globals auto-complete
if (value.IsNull ()) {
// Remove now obsolete entries
globals.Remove (fullPath);
} else {
// Add new entries
if (!globals.Contains (fullPath))
registerGlobal (fullPath, value.GetType (), 0);
}
}
}
#region Globals auto-complete
/// <summary>
/// Adds an entry to <see cref = "globals"/> (recursivley handles 2 levels of members)
/// </summary>
/// <param name = "path">The index accessor path ot the entry</param>
/// <param name = "type">The type of the entry</param>
/// <param name = "recursionCounter">How deep have we gone with recursion?</param>
private void registerGlobal (string path, Type type, int recursionCounter)
{
// If the type is a global method, list it directly
if (type == typeof(LuaCore.lua_CFunction)) {
// Format for easy method invocation
globals.Add (path + "(");
}
// If the type is a class or an interface and recursion hasn't been running too long, list the members
else if ((type.IsClass || type.IsInterface) && type != typeof(string) && recursionCounter < 2) {
#region Methods
foreach (var method in type.GetMethods(BindingFlags.Public | BindingFlags.Instance)) {
if (
// Check that the LuaHideAttribute and LuaGlobalAttribute were not applied
(method.GetCustomAttributes (typeof(LuaHideAttribute), false).Length == 0) &&
(method.GetCustomAttributes (typeof(LuaGlobalAttribute), false).Length == 0) &&
// Exclude some generic .NET methods that wouldn't be very usefull in Lua
method.Name != "GetType" && method.Name != "GetHashCode" && method.Name != "Equals" &&
method.Name != "ToString" && method.Name != "Clone" && method.Name != "Dispose" &&
method.Name != "GetEnumerator" && method.Name != "CopyTo" &&
!method.Name.StartsWith ("get_", StringComparison.Ordinal) &&
!method.Name.StartsWith ("set_", StringComparison.Ordinal) &&
!method.Name.StartsWith ("add_", StringComparison.Ordinal) &&
!method.Name.StartsWith ("remove_", StringComparison.Ordinal)) {
// Format for easy method invocation
string command = path + ":" + method.Name + "(";
if (method.GetParameters ().Length == 0)
command += ")";
globals.Add (command);
}
}
#endregion
#region Fields
foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.Instance)) {
if (
// Check that the LuaHideAttribute and LuaGlobalAttribute were not applied
(field.GetCustomAttributes (typeof(LuaHideAttribute), false).Length == 0) &&
(field.GetCustomAttributes (typeof(LuaGlobalAttribute), false).Length == 0)) {
// Go into recursion for members
registerGlobal (path + "." + field.Name, field.FieldType, recursionCounter + 1);
}
}
#endregion
#region Properties
foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)) {
if (
// Check that the LuaHideAttribute and LuaGlobalAttribute were not applied
(property.GetCustomAttributes (typeof(LuaHideAttribute), false).Length == 0) &&
(property.GetCustomAttributes (typeof(LuaGlobalAttribute), false).Length == 0)
// Exclude some generic .NET properties that wouldn't be very usefull in Lua
&& property.Name != "Item") {
// Go into recursion for members
registerGlobal (path + "." + property.Name, property.PropertyType, recursionCounter + 1);
}
}
#endregion
} else
globals.Add (path); // Otherwise simply add the element to the list
// List will need to be sorted on next access
globalsSorted = false;
}
#endregion
/*
* Navigates a table in the top of the stack, returning
* the value of the specified field
*/
internal object getObject (string[] remainingPath)
{
object returnValue = null;
for (int i = 0; i < remainingPath.Length; i++) {
LuaLib.lua_pushstring (luaState, remainingPath [i]);
LuaLib.lua_gettable (luaState, -2);
returnValue = translator.getObject (luaState, -1);
if (returnValue.IsNull ())
break;
}
return returnValue;
}
/*
* Gets a numeric global variable
*/
public double GetNumber (string fullPath)
{
return (double)this [fullPath];
}
/*
* Gets a string global variable
*/
public string GetString (string fullPath)
{
return this [fullPath].ToString ();
}
/*
* Gets a table global variable
*/
public LuaTable GetTable (string fullPath)
{
return (LuaTable)this [fullPath];
}
/*
* Gets a table global variable as an object implementing
* the interfaceType interface
*/
public object GetTable (Type interfaceType, string fullPath)
{
return CodeGeneration.Instance.GetClassInstance (interfaceType, GetTable (fullPath));
}
/*
* Gets a function global variable
*/
public LuaFunction GetFunction (string fullPath)
{
object obj = this [fullPath];
return (obj is LuaCore.lua_CFunction ? new LuaFunction ((LuaCore.lua_CFunction)obj, this) : (LuaFunction)obj);
}
/*
* Register a delegate type to be used to convert Lua funcitions to C# delegates (useful for iOS where there is no dynamic code generation)
* type delegateType
*/
public void RegisterLuaDelegateType (Type delegateType, Type luaDelegateType)
{
CodeGeneration.Instance.RegisterLuaDelegateType (delegateType, luaDelegateType);
}
public void RegisterLuaClassType (Type klass, Type luaClass)
{
CodeGeneration.Instance.RegisterLuaClassType (klass, luaClass);
}
/*
* Gets a function global variable as a delegate of
* type delegateType
*/
public Delegate GetFunction (Type delegateType, string fullPath)
{
return CodeGeneration.Instance.GetDelegate (delegateType, GetFunction (fullPath));
}
/*
* Calls the object as a function with the provided arguments,
* returning the function's returned values inside an array
*/
internal object[] callFunction (object function, object[] args)
{
return callFunction (function, args, null);
}
/*
* Calls the object as a function with the provided arguments and
* casting returned values to the types in returnTypes before returning
* them in an array
*/
internal object[] callFunction (object function, object[] args, Type[] returnTypes)
{
int nArgs = 0;
int oldTop = LuaLib.lua_gettop (luaState);
if (!LuaLib.lua_checkstack (luaState, args.Length + 6))
throw new LuaException ("Lua stack overflow");
translator.push (luaState, function);
if (!args.IsNull ()) {
nArgs = args.Length;
for (int i = 0; i < args.Length; i++)
translator.push (luaState, args [i]);
}
executing = true;
try {
int error = LuaLib.lua_pcall (luaState, nArgs, -1, 0);
if (error != 0)
ThrowExceptionFromError (oldTop);
} finally {
executing = false;
}
return !returnTypes.IsNull () ? translator.popValues (luaState, oldTop, returnTypes) : translator.popValues (luaState, oldTop);
}
/*
* Navigates a table to set the value of one of its fields
*/
internal void setObject (string[] remainingPath, object val)
{
for (int i = 0; i < remainingPath.Length-1; i++) {
LuaLib.lua_pushstring (luaState, remainingPath [i]);
LuaLib.lua_gettable (luaState, -2);
}
LuaLib.lua_pushstring (luaState, remainingPath [remainingPath.Length - 1]);
translator.push (luaState, val);
LuaLib.lua_settable (luaState, -3);
}
/*
* Creates a new table as a global variable or as a field
* inside an existing table
*/
public void NewTable (string fullPath)
{
string[] path = fullPath.Split (new char[] { '.' });
int oldTop = LuaLib.lua_gettop (luaState);
if (path.Length == 1) {
LuaLib.lua_newtable (luaState);
LuaLib.lua_setglobal (luaState, fullPath);
} else {
LuaLib.lua_getglobal (luaState, path [0]);
for (int i = 1; i < path.Length-1; i++) {
LuaLib.lua_pushstring (luaState, path [i]);
LuaLib.lua_gettable (luaState, -2);
}
LuaLib.lua_pushstring (luaState, path [path.Length - 1]);
LuaLib.lua_newtable (luaState);
LuaLib.lua_settable (luaState, -3);
}
LuaLib.lua_settop (luaState, oldTop);
}
public ListDictionary GetTableDict (LuaTable table)
{
var dict = new ListDictionary ();
int oldTop = LuaLib.lua_gettop (luaState);
translator.push (luaState, table);
LuaLib.lua_pushnil (luaState);
while (LuaLib.lua_next(luaState, -2) != 0) {
dict [translator.getObject (luaState, -2)] = translator.getObject (luaState, -1);
LuaLib.lua_settop (luaState, -2);
}
LuaLib.lua_settop (luaState, oldTop);
return dict;
}
/*
* Lets go of a previously allocated reference to a table, function
* or userdata
*/
#region lua debug functions
/// <summary>
/// Activates the debug hook
/// </summary>
/// <param name = "mask">Mask</param>
/// <param name = "count">Count</param>
/// <returns>see lua docs. -1 if hook is already set</returns>
/// <author>Reinhard Ostermeier</author>
public int SetDebugHook (EventMasks mask, int count)
{
if (hookCallback.IsNull ()) {
hookCallback = new LuaCore.lua_Hook (Lua.DebugHookCallback);
return LuaCore.lua_sethook (luaState, hookCallback, (int)mask, count);
}
return -1;
}
/// <summary>
/// Removes the debug hook
/// </summary>
/// <returns>see lua docs</returns>
/// <author>Reinhard Ostermeier</author>
public int RemoveDebugHook ()
{
hookCallback = null;
return LuaCore.lua_sethook (luaState, null, 0, 0);
}
/// <summary>
/// Gets the hook mask.
/// </summary>
/// <returns>hook mask</returns>
/// <author>Reinhard Ostermeier</author>
public EventMasks GetHookMask ()
{
return (EventMasks)LuaCore.lua_gethookmask (luaState);
}
/// <summary>
/// Gets the hook count
/// </summary>
/// <returns>see lua docs</returns>
/// <author>Reinhard Ostermeier</author>
public int GetHookCount ()
{
return LuaCore.lua_gethookcount (luaState);
}
/// <summary>
/// Gets the stack entry on a given level
/// </summary>
/// <param name = "level">level</param>
/// <param name = "luaDebug">lua debug structure</param>
/// <returns>Returns true if level was allowed, false if level was invalid.</returns>
/// <author>Reinhard Ostermeier</author>
/*public bool GetStack(int level, out LuaCore.lua_Debug luaDebug)
{
luaDebug = new LuaDebug();
LuaCore.lua_State ld = System.Runtime.InteropServices.Marshal.AllocHGlobal(System.Runtime.InteropServices.Marshal.SizeOf(luaDebug));
System.Runtime.InteropServices.Marshal.StructureToPtr(luaDebug, ld, false);
try
{
return LuaLib.lua_getstack(luaState, level, luaDebug) != 0;
}
finally
{
luaDebug = (LuaDebug)System.Runtime.InteropServices.Marshal.PtrToStructure(ld, typeof(LuaDebug));
System.Runtime.InteropServices.Marshal.FreeHGlobal(ld);
}
}*/
/// <summary>
/// Gets info (see lua docs)
/// </summary>
/// <param name = "what">what (see lua docs)</param>
/// <param name = "luaDebug">lua debug structure</param>
/// <returns>see lua docs</returns>
/// <author>Reinhard Ostermeier</author>
/*public int GetInfo(String what, ref LuaCore.lua_Debug luaDebug)
{
LuaCore.lua_State ld = System.Runtime.InteropServices.Marshal.AllocHGlobal(System.Runtime.InteropServices.Marshal.SizeOf(luaDebug));
System.Runtime.InteropServices.Marshal.StructureToPtr(luaDebug, ld, false);
try
{
return LuaLib.lua_getinfo(luaState, what, ld);
}
finally
{
luaDebug = (LuaDebug)System.Runtime.InteropServices.Marshal.PtrToStructure(ld, typeof(LuaDebug));
System.Runtime.InteropServices.Marshal.FreeHGlobal(ld);
}
}*/
/// <summary>
/// Gets local (see lua docs)
/// </summary>
/// <param name = "luaDebug">lua debug structure</param>
/// <param name = "n">see lua docs</param>
/// <returns>see lua docs</returns>
/// <author>Reinhard Ostermeier</author>
public string GetLocal (LuaCore.lua_Debug luaDebug, int n)
{
return LuaCore.lua_getlocal (luaState, luaDebug, n).ToString ();
}
/// <summary>
/// Sets local (see lua docs)
/// </summary>
/// <param name = "luaDebug">lua debug structure</param>
/// <param name = "n">see lua docs</param>
/// <returns>see lua docs</returns>
/// <author>Reinhard Ostermeier</author>
public string SetLocal (LuaCore.lua_Debug luaDebug, int n)
{
return LuaCore.lua_setlocal (luaState, luaDebug, n).ToString ();
}
/// <summary>
/// Gets up value (see lua docs)
/// </summary>
/// <param name = "funcindex">see lua docs</param>
/// <param name = "n">see lua docs</param>
/// <returns>see lua docs</returns>
/// <author>Reinhard Ostermeier</author>
public string GetUpValue (int funcindex, int n)
{
return LuaCore.lua_getupvalue (luaState, funcindex, n).ToString ();
}
/// <summary>
/// Sets up value (see lua docs)
/// </summary>
/// <param name = "funcindex">see lua docs</param>
/// <param name = "n">see lua docs</param>
/// <returns>see lua docs</returns>
/// <author>Reinhard Ostermeier</author>
public string SetUpValue (int funcindex, int n)
{
return LuaCore.lua_setupvalue (luaState, funcindex, n).ToString ();
}
/// <summary>
/// Delegate that is called on lua hook callback
/// </summary>
/// <param name = "luaState">lua state</param>
/// <param name = "luaDebug">Pointer to LuaDebug (lua_debug) structure</param>
/// <author>Reinhard Ostermeier</author>
///
#if MONOTOUCH
[MonoTouch.MonoPInvokeCallback (typeof (LuaCore.lua_Hook))]
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private void DebugHookCallback (LuaCore.lua_State luaState, LuaCore.lua_Debug luaDebug)
{
try {
var temp = DebugHook;
if (!temp.IsNull ())
temp (this, new DebugHookEventArgs (luaDebug));
} catch (Exception ex) {
OnHookException (new HookExceptionEventArgs (ex));
}
}
private void OnHookException (HookExceptionEventArgs e)
{
var temp = HookException;
if (!temp.IsNull ())
temp (this, e);
}
/// <summary>
/// Pops a value from the lua stack.
/// </summary>
/// <returns>Returns the top value from the lua stack.</returns>
/// <author>Reinhard Ostermeier</author>
public object Pop ()
{
int top = LuaLib.lua_gettop (luaState);
return translator.popValues (luaState, top - 1) [0];
}
/// <summary>
/// Pushes a value onto the lua stack.
/// </summary>
/// <param name = "value">Value to push.</param>
/// <author>Reinhard Ostermeier</author>
public void Push (object value)
{
translator.push (luaState, value);
}
#endregion
internal void dispose (int reference)
{
if (!luaState.IsNull ()) //Fix submitted by Qingrui Li
LuaLib.lua_unref (luaState, reference);
}
/*
* Gets a field of the table corresponding to the provided reference
* using rawget (do not use metatables)
*/
internal object rawGetObject (int reference, string field)
{
int oldTop = LuaLib.lua_gettop (luaState);
LuaLib.lua_getref (luaState, reference);
LuaLib.lua_pushstring (luaState, field);
LuaLib.lua_rawget (luaState, -2);
object obj = translator.getObject (luaState, -1);
LuaLib.lua_settop (luaState, oldTop);
return obj;
}
/*
* Gets a field of the table or userdata corresponding to the provided reference
*/
internal object getObject (int reference, string field)
{
int oldTop = LuaLib.lua_gettop (luaState);
LuaLib.lua_getref (luaState, reference);
object returnValue = getObject (field.Split (new char[] {'.'}));
LuaLib.lua_settop (luaState, oldTop);
return returnValue;
}
/*
* Gets a numeric field of the table or userdata corresponding the the provided reference
*/
internal object getObject (int reference, object field)
{
int oldTop = LuaLib.lua_gettop (luaState);
LuaLib.lua_getref (luaState, reference);
translator.push (luaState, field);
LuaLib.lua_gettable (luaState, -2);
object returnValue = translator.getObject (luaState, -1);
LuaLib.lua_settop (luaState, oldTop);
return returnValue;
}
/*
* Sets a field of the table or userdata corresponding the the provided reference
* to the provided value
*/
internal void setObject (int reference, string field, object val)
{
int oldTop = LuaLib.lua_gettop (luaState);
LuaLib.lua_getref (luaState, reference);
setObject (field.Split (new char[] {'.'}), val);
LuaLib.lua_settop (luaState, oldTop);
}
/*
* Sets a numeric field of the table or userdata corresponding the the provided reference
* to the provided value
*/
internal void setObject (int reference, object field, object val)
{
int oldTop = LuaLib.lua_gettop (luaState);
LuaLib.lua_getref (luaState, reference);
translator.push (luaState, field);
translator.push (luaState, val);
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_settop (luaState, oldTop);
}
/*
* Registers an object's method as a Lua function (global or table field)
* The method may have any signature
*/
public LuaFunction RegisterFunction (string path, object target, MethodBase function /*MethodInfo function*/) //CP: Fix for struct constructor by Alexander Kappner (link: http://luaforge.net/forum/forum.php?thread_id = 2859&forum_id = 145)
{
// We leave nothing on the stack when we are done
int oldTop = LuaLib.lua_gettop (luaState);
var wrapper = new LuaMethodWrapper (translator, target, function.DeclaringType, function);
translator.push (luaState, new LuaCore.lua_CFunction (wrapper.invokeFunction));
this [path] = translator.getObject (luaState, -1);
var f = GetFunction (path);
LuaLib.lua_settop (luaState, oldTop);
return f;
}
/*
* Compares the two values referenced by ref1 and ref2 for equality
*/
internal bool compareRef (int ref1, int ref2)
{
int top = LuaLib.lua_gettop (luaState);
LuaLib.lua_getref (luaState, ref1);
LuaLib.lua_getref (luaState, ref2);
int equal = LuaLib.lua_equal (luaState, -1, -2);
LuaLib.lua_settop (luaState, top);
return (equal != 0);
}
internal void pushCSFunction (LuaCore.lua_CFunction function)
{
translator.pushFunction (luaState, function);
}
#region IDisposable Members
public virtual void Dispose ()
{
if (!translator.IsNull ()) {
translator.pendingEvents.Dispose ();
translator = null;
}
this.Close ();
GC.Collect ();
GC.WaitForPendingFinalizers ();
}
#endregion
}
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private static void DebugHookCallback (LuaCore.lua_State luaState, LuaCore.lua_Debug luaDebug)
{
var translator = ObjectTranslatorPool.Instance.Find (luaState);
var lua = translator.Interpreter;
lua.DebugHookCallbackInternal (luaState, luaDebug);
}
private void DebugHookCallbackInternal (LuaCore.lua_State luaState, LuaCore.lua_Debug luaDebug)
{
try {
var temp = DebugHook;
if (!temp.IsNull ())
temp (this, new DebugHookEventArgs (luaDebug));
} catch (Exception ex) {
OnHookException (new HookExceptionEventArgs (ex));
}
}
private void OnHookException (HookExceptionEventArgs e)
{
var temp = HookException;
if (!temp.IsNull ())
temp (this, e);
}
/// <summary>
/// Pops a value from the lua stack.
/// </summary>
/// <returns>Returns the top value from the lua stack.</returns>
/// <author>Reinhard Ostermeier</author>
public object Pop ()
{
int top = LuaLib.lua_gettop (luaState);
return translator.popValues (luaState, top - 1) [0];
}
/// <summary>
/// Pushes a value onto the lua stack.
/// </summary>
/// <param name = "value">Value to push.</param>
/// <author>Reinhard Ostermeier</author>
public void Push (object value)
{
translator.push (luaState, value);
}
#endregion
internal void dispose (int reference)
{
if (!luaState.IsNull ()) //Fix submitted by Qingrui Li
LuaLib.lua_unref (luaState, reference);
}
/*
* Gets a field of the table corresponding to the provided reference
* using rawget (do not use metatables)
*/
internal object rawGetObject (int reference, string field)
{
int oldTop = LuaLib.lua_gettop (luaState);
LuaLib.lua_getref (luaState, reference);
LuaLib.lua_pushstring (luaState, field);
LuaLib.lua_rawget (luaState, -2);
object obj = translator.getObject (luaState, -1);
LuaLib.lua_settop (luaState, oldTop);
return obj;
}
/*
* Gets a field of the table or userdata corresponding to the provided reference
*/
internal object getObject (int reference, string field)
{
int oldTop = LuaLib.lua_gettop (luaState);
LuaLib.lua_getref (luaState, reference);
object returnValue = getObject (field.Split (new char[] {'.'}));
LuaLib.lua_settop (luaState, oldTop);
return returnValue;
}
/*
* Gets a numeric field of the table or userdata corresponding the the provided reference
*/
internal object getObject (int reference, object field)
{
int oldTop = LuaLib.lua_gettop (luaState);
LuaLib.lua_getref (luaState, reference);
translator.push (luaState, field);
LuaLib.lua_gettable (luaState, -2);
object returnValue = translator.getObject (luaState, -1);
LuaLib.lua_settop (luaState, oldTop);
return returnValue;
}
/*
* Sets a field of the table or userdata corresponding the the provided reference
* to the provided value
*/
internal void setObject (int reference, string field, object val)
{
int oldTop = LuaLib.lua_gettop (luaState);
LuaLib.lua_getref (luaState, reference);
setObject (field.Split (new char[] {'.'}), val);
LuaLib.lua_settop (luaState, oldTop);
}
/*
* Sets a numeric field of the table or userdata corresponding the the provided reference
* to the provided value
*/
internal void setObject (int reference, object field, object val)
{
int oldTop = LuaLib.lua_gettop (luaState);
LuaLib.lua_getref (luaState, reference);
translator.push (luaState, field);
translator.push (luaState, val);
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_settop (luaState, oldTop);
}
/*
* Registers an object's method as a Lua function (global or table field)
* The method may have any signature
*/
public LuaFunction RegisterFunction (string path, object target, MethodBase function /*MethodInfo function*/) //CP: Fix for struct constructor by Alexander Kappner (link: http://luaforge.net/forum/forum.php?thread_id = 2859&forum_id = 145)
{
// We leave nothing on the stack when we are done
int oldTop = LuaLib.lua_gettop (luaState);
var wrapper = new LuaMethodWrapper (translator, target, function.DeclaringType, function);
translator.push (luaState, new LuaCore.lua_CFunction (wrapper.invokeFunction));
this [path] = translator.getObject (luaState, -1);
var f = GetFunction (path);
LuaLib.lua_settop (luaState, oldTop);
return f;
}
/*
* Compares the two values referenced by ref1 and ref2 for equality
*/
internal bool compareRef (int ref1, int ref2)
{
int top = LuaLib.lua_gettop (luaState);
LuaLib.lua_getref (luaState, ref1);
LuaLib.lua_getref (luaState, ref2);
int equal = LuaLib.lua_equal (luaState, -1, -2);
LuaLib.lua_settop (luaState, top);
return (equal != 0);
}
internal void pushCSFunction (LuaCore.lua_CFunction function)
{
translator.pushFunction (luaState, function);
}
#region IDisposable Members
public virtual void Dispose ()
{
if (!translator.IsNull ()) {
translator.pendingEvents.Dispose ();
translator = null;
}
this.Close ();
GC.Collect ();
GC.WaitForPendingFinalizers ();
}
#endregion
}
}
\ No newline at end of file
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
using System.Text;
using System.Collections.Generic;
namespace LuaInterface
{
using LuaCore = KeraLua.Lua;
public class LuaFunction : LuaBase
{
internal LuaCore.lua_CFunction function;
public LuaFunction (int reference, Lua interpreter)
{
_Reference = reference;
this.function = null;
_Interpreter = interpreter;
}
public LuaFunction (LuaCore.lua_CFunction function, Lua interpreter)
{
_Reference = 0;
this.function = function;
_Interpreter = interpreter;
}
/*
* Calls the function casting return values to the types
* in returnTypes
*/
internal object[] call (object[] args, Type[] returnTypes)
{
return _Interpreter.callFunction (this, args, returnTypes);
}
/*
* Calls the function and returns its return values inside
* an array
*/
public object[] Call (params object[] args)
{
return _Interpreter.callFunction (this, args);
}
/*
* Pushes the function into the Lua stack
*/
internal void push (LuaCore.lua_State luaState)
{
if (_Reference != 0)
LuaLib.lua_getref (luaState, _Reference);
else
_Interpreter.pushCSFunction (function);
}
public override string ToString ()
{
return "function";
}
public override bool Equals (object o)
{
if (o is LuaFunction) {
var l = (LuaFunction)o;
if (this._Reference != 0 && l._Reference != 0)
return _Interpreter.compareRef (l._Reference, this._Reference);
else
return this.function == l.function;
} else
return false;
}
public override int GetHashCode ()
{
return _Reference != 0 ? _Reference : function.GetHashCode ();
}
}
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
using System.Text;
using System.Collections.Generic;
namespace LuaInterface
{
#if USE_KOPILUA
using LuaCore = KopiLua.Lua;
#else
using LuaCore = KeraLua.Lua;
#endif
public class LuaFunction : LuaBase
{
internal LuaCore.lua_CFunction function;
public LuaFunction (int reference, Lua interpreter)
{
_Reference = reference;
this.function = null;
_Interpreter = interpreter;
}
public LuaFunction (LuaCore.lua_CFunction function, Lua interpreter)
{
_Reference = 0;
this.function = function;
_Interpreter = interpreter;
}
/*
* Calls the function casting return values to the types
* in returnTypes
*/
internal object[] call (object[] args, Type[] returnTypes)
{
return _Interpreter.callFunction (this, args, returnTypes);
}
/*
* Calls the function and returns its return values inside
* an array
*/
public object[] Call (params object[] args)
{
return _Interpreter.callFunction (this, args);
}
/*
* Pushes the function into the Lua stack
*/
internal void push (LuaCore.lua_State luaState)
{
if (_Reference != 0)
LuaLib.lua_getref (luaState, _Reference);
else
_Interpreter.pushCSFunction (function);
}
public override string ToString ()
{
return "function";
}
public override bool Equals (object o)
{
if (o is LuaFunction) {
var l = (LuaFunction)o;
if (this._Reference != 0 && l._Reference != 0)
return _Interpreter.compareRef (l._Reference, this._Reference);
else
return this.function == l.function;
} else
return false;
}
public override int GetHashCode ()
{
return _Reference != 0 ? _Reference : function.GetHashCode ();
}
}
}
\ No newline at end of file
......@@ -17,7 +17,7 @@
<DebugType>full</DebugType>
<Optimize>False</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;MONOTOUCH</DefineConstants>
<DefineConstants>DEBUG;MONOTOUCH;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>False</ConsolePause>
......@@ -29,7 +29,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>False</ConsolePause>
<DefineConstants>MONOTOUCH</DefineConstants>
<DefineConstants>MONOTOUCH;</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
......@@ -91,6 +91,7 @@
<Compile Include="Metatables.cs" />
<Compile Include="ObjectTranslator.cs" />
<Compile Include="ProxyType.cs" />
<Compile Include="ObjectTranslatorPool.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\KeraLua\KeraLua.iOS.csproj">
......
......@@ -12,7 +12,6 @@
<AssemblyName>LuaInterface</AssemblyName>
<ReleaseVersion>2.x</ReleaseVersion>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>True</DebugSymbols>
......@@ -79,6 +78,7 @@
<Compile Include="LuaLib\GCOptions.cs" />
<Compile Include="LuaLib\LuaLib.cs" />
<Compile Include="Config\LuaInterfaceConfig.cs" />
<Compile Include="ObjectTranslatorPool.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
......@@ -90,7 +90,7 @@
-->
<ItemGroup>
<ProjectReference Include="..\KeraLua\KeraLua.csproj">
<Project>{47153754-10f5-44d8-b578-f5a32b69061a}</Project>
<Project>{47153754-10F5-44D8-B578-F5A32B69061A}</Project>
<Name>KeraLua</Name>
</ProjectReference>
<ProjectReference Include="..\KopiLua\KopiLua.csproj">
......
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2009 Joshua Simmons <simmons.44@gmail.com>
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
using System.IO;
using LuaInterface.Extensions;
namespace LuaInterface
{
using LuaCore = KeraLua.Lua;
public class LuaLib
{
// steffenj: BEGIN additional Lua API functions new in Lua 5.1
public static int lua_gc (LuaCore.lua_State luaState, GCOptions what, int data)
{
return LuaCore.lua_gc (luaState, (int)what, data);
}
public static string lua_typename (LuaCore.lua_State luaState, LuaTypes type)
{
return LuaCore.lua_typename (luaState, (int)type).ToString ();
}
public static string luaL_typename (LuaCore.lua_State luaState, int stackPos)
{
return lua_typename (luaState, lua_type (luaState, stackPos));
}
public static void luaL_error (LuaCore.lua_State luaState, string message)
{
LuaCore.luaL_error (luaState, message);
}
public static void luaL_where (LuaCore.lua_State luaState, int level)
{
LuaCore.luaL_where (luaState, level);
}
// steffenj: BEGIN Lua 5.1.1 API change (lua_open replaced by luaL_newstate)
public static LuaCore.lua_State luaL_newstate ()
{
return LuaCore.luaL_newstate ();
}
// steffenj: BEGIN Lua 5.1.1 API change (new function luaL_openlibs)
public static void luaL_openlibs (LuaCore.lua_State luaState)
{
LuaCore.luaL_openlibs (luaState);
}
// steffenj: END Lua 5.1.1 API change (lua_strlen is now lua_objlen)
// steffenj: BEGIN Lua 5.1.1 API change (lua_dostring is now a macro luaL_dostring)
public static int luaL_loadstring (LuaCore.lua_State luaState, string chunk)
{
return LuaCore.luaL_loadstring (luaState, chunk);
}
public static int luaL_dostring (LuaCore.lua_State luaState, string chunk)
{
int result = luaL_loadstring (luaState, chunk);
if (result != 0)
return result;
return lua_pcall (luaState, 0, -1, 0);
}
/// <summary>DEPRECATED - use luaL_dostring(LuaCore.lua_State luaState, string chunk) instead!</summary>
public static int lua_dostring (LuaCore.lua_State luaState, string chunk)
{
return luaL_dostring (luaState, chunk);
}
// steffenj: END Lua 5.1.1 API change (lua_dostring is now a macro luaL_dostring)
// steffenj: BEGIN Lua 5.1.1 API change (lua_newtable is gone, lua_createtable is new)
public static void lua_createtable (LuaCore.lua_State luaState, int narr, int nrec)
{
LuaCore.lua_createtable (luaState, narr, nrec);
}
public static void lua_newtable (LuaCore.lua_State luaState)
{
lua_createtable (luaState, 0, 0);
}
// steffenj: END Lua 5.1.1 API change (lua_newtable is gone, lua_createtable is new)
// steffenj: BEGIN Lua 5.1.1 API change (lua_dofile now in LuaLib as luaL_dofile macro)
public static int luaL_dofile (LuaCore.lua_State luaState, string fileName)
{
int result = LuaCore.luaL_loadfile (luaState, fileName);
if (result != 0)
return result;
return LuaCore.lua_pcall (luaState, 0, -1, 0);
}
// steffenj: END Lua 5.1.1 API change (lua_dofile now in LuaLib as luaL_dofile)
public static void lua_getglobal (LuaCore.lua_State luaState, string name)
{
lua_pushstring (luaState, name);
LuaCore.lua_gettable (luaState, (int)LuaIndexes.Globals);
}
public static void lua_setglobal (LuaCore.lua_State luaState, string name)
{
lua_pushstring (luaState, name);
lua_insert (luaState, -2);
lua_settable (luaState, (int)LuaIndexes.Globals);
}
public static void lua_settop (LuaCore.lua_State luaState, int newTop)
{
LuaCore.lua_settop (luaState, newTop);
}
public static void lua_pop (LuaCore.lua_State luaState, int amount)
{
lua_settop (luaState, -(amount) - 1);
}
public static void lua_insert (LuaCore.lua_State luaState, int newTop)
{
LuaCore.lua_insert (luaState, newTop);
}
public static void lua_remove (LuaCore.lua_State luaState, int index)
{
LuaCore.lua_remove (luaState, index);
}
public static void lua_gettable (LuaCore.lua_State luaState, int index)
{
LuaCore.lua_gettable (luaState, index);
}
public static void lua_rawget (LuaCore.lua_State luaState, int index)
{
LuaCore.lua_rawget (luaState, index);
}
public static void lua_settable (LuaCore.lua_State luaState, int index)
{
LuaCore.lua_settable (luaState, index);
}
public static void lua_rawset (LuaCore.lua_State luaState, int index)
{
LuaCore.lua_rawset (luaState, index);
}
public static void lua_setmetatable (LuaCore.lua_State luaState, int objIndex)
{
LuaCore.lua_setmetatable (luaState, objIndex);
}
public static int lua_getmetatable (LuaCore.lua_State luaState, int objIndex)
{
return LuaCore.lua_getmetatable (luaState, objIndex);
}
public static int lua_equal (LuaCore.lua_State luaState, int index1, int index2)
{
return LuaCore.lua_equal (luaState, index1, index2);
}
public static void lua_pushvalue (LuaCore.lua_State luaState, int index)
{
LuaCore.lua_pushvalue (luaState, index);
}
public static void lua_replace (LuaCore.lua_State luaState, int index)
{
LuaCore.lua_replace (luaState, index);
}
public static int lua_gettop (LuaCore.lua_State luaState)
{
return LuaCore.lua_gettop (luaState);
}
public static LuaTypes lua_type (LuaCore.lua_State luaState, int index)
{
return (LuaTypes)LuaCore.lua_type (luaState, index);
}
public static bool lua_isnil (LuaCore.lua_State luaState, int index)
{
return lua_type (luaState, index) == LuaTypes.Nil;
}
public static bool lua_isnumber (LuaCore.lua_State luaState, int index)
{
return lua_type (luaState, index) == LuaTypes.Number;
}
public static bool lua_isboolean (LuaCore.lua_State luaState, int index)
{
return lua_type (luaState, index) == LuaTypes.Boolean;
}
public static int luaL_ref (LuaCore.lua_State luaState, int registryIndex)
{
return LuaCore.luaL_ref (luaState, registryIndex);
}
public static int lua_ref (LuaCore.lua_State luaState, int lockRef)
{
return lockRef != 0 ? luaL_ref (luaState, (int)LuaIndexes.Registry) : 0;
}
public static void lua_rawgeti (LuaCore.lua_State luaState, int tableIndex, int index)
{
LuaCore.lua_rawgeti (luaState, tableIndex, index);
}
public static void lua_rawseti (LuaCore.lua_State luaState, int tableIndex, int index)
{
LuaCore.lua_rawseti (luaState, tableIndex, index);
}
public static object lua_newuserdata (LuaCore.lua_State luaState, int size)
{
return LuaCore.lua_newuserdata (luaState, (uint)size);
}
public static object lua_touserdata (LuaCore.lua_State luaState, int index)
{
return LuaCore.lua_touserdata (luaState, index);
}
public static void lua_getref (LuaCore.lua_State luaState, int reference)
{
lua_rawgeti (luaState, (int)LuaIndexes.Registry, reference);
}
public static void lua_unref (LuaCore.lua_State luaState, int reference)
{
LuaCore.luaL_unref (luaState, (int)LuaIndexes.Registry, reference);
}
public static bool lua_isstring (LuaCore.lua_State luaState, int index)
{
return LuaCore.lua_isstring (luaState, index) != 0;
}
public static bool lua_iscfunction (LuaCore.lua_State luaState, int index)
{
return LuaCore.lua_iscfunction (luaState, index);
}
public static void lua_pushnil (LuaCore.lua_State luaState)
{
LuaCore.lua_pushnil (luaState);
}
public static void lua_call (LuaCore.lua_State luaState, int nArgs, int nResults)
{
LuaCore.lua_call (luaState, nArgs, nResults);
}
public static void lua_pushstdcallcfunction (LuaCore.lua_State luaState, LuaCore.lua_CFunction function)
{
LuaCore.lua_pushcfunction (luaState, function);
}
public static int lua_pcall (LuaCore.lua_State luaState, int nArgs, int nResults, int errfunc)
{
return LuaCore.lua_pcall (luaState, nArgs, nResults, errfunc);
}
public static LuaCore.lua_CFunction lua_tocfunction (LuaCore.lua_State luaState, int index)
{
return LuaCore.lua_tocfunction (luaState, index);
}
public static double lua_tonumber (LuaCore.lua_State luaState, int index)
{
return LuaCore.lua_tonumber (luaState, index);
}
public static bool lua_toboolean (LuaCore.lua_State luaState, int index)
{
return LuaCore.lua_toboolean (luaState, index) != 0;
}
public static string lua_tostring (LuaCore.lua_State luaState, int index)
{
#if true
// FIXME use the same format string as lua i.e. LUA_NUMBER_FMT
var t = lua_type (luaState, index);
if (t == LuaTypes.Number)
return string.Format ("{0}", lua_tonumber (luaState, index));
else if (t == LuaTypes.String) {
uint strlen;
return LuaCore.lua_tolstring (luaState, index, out strlen).ToString ();
} else if (t == LuaTypes.Nil)
return null; // treat lua nulls to as C# nulls
else
return "0"; // Because luaV_tostring does this
#else
size_t strlen;
// Note! This method will _change_ the representation of the object on the stack to a string.
// We do not want this behavior so we do the conversion ourselves
const char *str = LuaCore.lua_tolstring(luaState, index, &strlen);
if (str)
return Marshal::PtrToStringAnsi(IntPtr((char *) str), strlen);
else
return nullptr; // treat lua nulls to as C# nulls
#endif
}
public static void lua_atpanic (LuaCore.lua_State luaState, LuaCore.lua_CFunction panicf)
{
LuaCore.lua_atpanic (luaState, (LuaCore.lua_CFunction)panicf);
}
public static void lua_pushnumber (LuaCore.lua_State luaState, double number)
{
LuaCore.lua_pushnumber (luaState, number);
}
public static void lua_pushboolean (LuaCore.lua_State luaState, bool value)
{
LuaCore.lua_pushboolean (luaState, value ? 1 : 0);
}
public static void lua_pushstring (LuaCore.lua_State luaState, string str)
{
LuaCore.lua_pushstring (luaState, str);
}
public static int luaL_newmetatable (LuaCore.lua_State luaState, string meta)
{
return LuaCore.luaL_newmetatable (luaState, meta);
}
// steffenj: BEGIN Lua 5.1.1 API change (luaL_getmetatable is now a macro using lua_getfield)
public static void lua_getfield (LuaCore.lua_State luaState, int stackPos, string meta)
{
LuaCore.lua_getfield (luaState, stackPos, meta);
}
public static void luaL_getmetatable (LuaCore.lua_State luaState, string meta)
{
lua_getfield (luaState, (int)LuaIndexes.Registry, meta);
}
public static object luaL_checkudata (LuaCore.lua_State luaState, int stackPos, string meta)
{
return LuaCore.luaL_checkudata (luaState, stackPos, meta);
}
public static bool luaL_getmetafield (LuaCore.lua_State luaState, int stackPos, string field)
{
return LuaCore.luaL_getmetafield (luaState, stackPos, field) != 0;
}
public static int luaL_loadbuffer (LuaCore.lua_State luaState, string buff, string name)
{
return LuaCore.luaL_loadbuffer (luaState, buff, (uint)buff.Length, name);
}
public static int luaL_loadfile (LuaCore.lua_State luaState, string filename)
{
return LuaCore.luaL_loadfile (luaState, filename);
}
public static bool luaL_checkmetatable (LuaCore.lua_State luaState, int index)
{
return LuaCore.luaL_checkmetatable (luaState, index);
}
public static int luanet_tonetobject (LuaCore.lua_State luaState, int index)
{
return LuaCore.luanet_tonetobject (luaState, index);
}
public static void luanet_newudata (LuaCore.lua_State luaState, int val)
{
LuaCore.luanet_newudata (luaState, val);
}
public static int luanet_rawnetobj (LuaCore.lua_State luaState, int obj)
{
return LuaCore.luanet_rawnetobj (luaState, obj);
}
public static int luanet_checkudata (LuaCore.lua_State luaState, int ud, string tname)
{
return LuaCore.luanet_checkudata (luaState, ud, tname);
}
public static void lua_error (LuaCore.lua_State luaState)
{
LuaCore.lua_error (luaState);
}
public static bool lua_checkstack (LuaCore.lua_State luaState, int extra)
{
return LuaCore.lua_checkstack (luaState, extra) != 0;
}
public static int lua_next (LuaCore.lua_State luaState, int index)
{
return LuaCore.lua_next (luaState, index);
}
public static void lua_pushlightuserdata (LuaCore.lua_State luaState, LuaCore.LuaTag udata)
{
LuaCore.lua_pushlightuserdata (luaState, udata.Tag);
}
public static LuaCore.LuaTag luanet_gettag ()
{
return LuaCore.luanet_gettag ();
}
}
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2009 Joshua Simmons <simmons.44@gmail.com>
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
using System.IO;
using LuaInterface.Extensions;
namespace LuaInterface
{
#if USE_KOPILUA
using LuaCore = KopiLua.Lua;
#else
using LuaCore = KeraLua.Lua;
#endif
public class LuaLib
{
// steffenj: BEGIN additional Lua API functions new in Lua 5.1
public static int lua_gc (LuaCore.lua_State luaState, GCOptions what, int data)
{
return LuaCore.lua_gc (luaState, (int)what, data);
}
public static string lua_typename (LuaCore.lua_State luaState, LuaTypes type)
{
return LuaCore.lua_typename (luaState, (int)type).ToString ();
}
public static string luaL_typename (LuaCore.lua_State luaState, int stackPos)
{
return lua_typename (luaState, lua_type (luaState, stackPos));
}
public static void luaL_error (LuaCore.lua_State luaState, string message)
{
LuaCore.luaL_error (luaState, message);
}
public static void luaL_where (LuaCore.lua_State luaState, int level)
{
LuaCore.luaL_where (luaState, level);
}
// steffenj: BEGIN Lua 5.1.1 API change (lua_open replaced by luaL_newstate)
public static LuaCore.lua_State luaL_newstate ()
{
return LuaCore.luaL_newstate ();
}
// steffenj: BEGIN Lua 5.1.1 API change (new function luaL_openlibs)
public static void luaL_openlibs (LuaCore.lua_State luaState)
{
LuaCore.luaL_openlibs (luaState);
}
// steffenj: END Lua 5.1.1 API change (lua_strlen is now lua_objlen)
// steffenj: BEGIN Lua 5.1.1 API change (lua_dostring is now a macro luaL_dostring)
public static int luaL_loadstring (LuaCore.lua_State luaState, string chunk)
{
return LuaCore.luaL_loadstring (luaState, chunk);
}
public static int luaL_dostring (LuaCore.lua_State luaState, string chunk)
{
int result = luaL_loadstring (luaState, chunk);
if (result != 0)
return result;
return lua_pcall (luaState, 0, -1, 0);
}
/// <summary>DEPRECATED - use luaL_dostring(LuaCore.lua_State luaState, string chunk) instead!</summary>
public static int lua_dostring (LuaCore.lua_State luaState, string chunk)
{
return luaL_dostring (luaState, chunk);
}
// steffenj: END Lua 5.1.1 API change (lua_dostring is now a macro luaL_dostring)
// steffenj: BEGIN Lua 5.1.1 API change (lua_newtable is gone, lua_createtable is new)
public static void lua_createtable (LuaCore.lua_State luaState, int narr, int nrec)
{
LuaCore.lua_createtable (luaState, narr, nrec);
}
public static void lua_newtable (LuaCore.lua_State luaState)
{
lua_createtable (luaState, 0, 0);
}
// steffenj: END Lua 5.1.1 API change (lua_newtable is gone, lua_createtable is new)
// steffenj: BEGIN Lua 5.1.1 API change (lua_dofile now in LuaLib as luaL_dofile macro)
public static int luaL_dofile (LuaCore.lua_State luaState, string fileName)
{
int result = LuaCore.luaL_loadfile (luaState, fileName);
if (result != 0)
return result;
return LuaCore.lua_pcall (luaState, 0, -1, 0);
}
// steffenj: END Lua 5.1.1 API change (lua_dofile now in LuaLib as luaL_dofile)
public static void lua_getglobal (LuaCore.lua_State luaState, string name)
{
lua_pushstring (luaState, name);
LuaCore.lua_gettable (luaState, (int)LuaIndexes.Globals);
}
public static void lua_setglobal (LuaCore.lua_State luaState, string name)
{
lua_pushstring (luaState, name);
lua_insert (luaState, -2);
lua_settable (luaState, (int)LuaIndexes.Globals);
}
public static void lua_settop (LuaCore.lua_State luaState, int newTop)
{
LuaCore.lua_settop (luaState, newTop);
}
public static void lua_pop (LuaCore.lua_State luaState, int amount)
{
lua_settop (luaState, -(amount) - 1);
}
public static void lua_insert (LuaCore.lua_State luaState, int newTop)
{
LuaCore.lua_insert (luaState, newTop);
}
public static void lua_remove (LuaCore.lua_State luaState, int index)
{
LuaCore.lua_remove (luaState, index);
}
public static void lua_gettable (LuaCore.lua_State luaState, int index)
{
LuaCore.lua_gettable (luaState, index);
}
public static void lua_rawget (LuaCore.lua_State luaState, int index)
{
LuaCore.lua_rawget (luaState, index);
}
public static void lua_settable (LuaCore.lua_State luaState, int index)
{
LuaCore.lua_settable (luaState, index);
}
public static void lua_rawset (LuaCore.lua_State luaState, int index)
{
LuaCore.lua_rawset (luaState, index);
}
public static void lua_setmetatable (LuaCore.lua_State luaState, int objIndex)
{
LuaCore.lua_setmetatable (luaState, objIndex);
}
public static int lua_getmetatable (LuaCore.lua_State luaState, int objIndex)
{
return LuaCore.lua_getmetatable (luaState, objIndex);
}
public static int lua_equal (LuaCore.lua_State luaState, int index1, int index2)
{
return LuaCore.lua_equal (luaState, index1, index2);
}
public static void lua_pushvalue (LuaCore.lua_State luaState, int index)
{
LuaCore.lua_pushvalue (luaState, index);
}
public static void lua_replace (LuaCore.lua_State luaState, int index)
{
LuaCore.lua_replace (luaState, index);
}
public static int lua_gettop (LuaCore.lua_State luaState)
{
return LuaCore.lua_gettop (luaState);
}
public static LuaTypes lua_type (LuaCore.lua_State luaState, int index)
{
return (LuaTypes)LuaCore.lua_type (luaState, index);
}
public static bool lua_isnil (LuaCore.lua_State luaState, int index)
{
return lua_type (luaState, index) == LuaTypes.Nil;
}
public static bool lua_isnumber (LuaCore.lua_State luaState, int index)
{
return lua_type (luaState, index) == LuaTypes.Number;
}
public static bool lua_isboolean (LuaCore.lua_State luaState, int index)
{
return lua_type (luaState, index) == LuaTypes.Boolean;
}
public static int luaL_ref (LuaCore.lua_State luaState, int registryIndex)
{
return LuaCore.luaL_ref (luaState, registryIndex);
}
public static int lua_ref (LuaCore.lua_State luaState, int lockRef)
{
return lockRef != 0 ? luaL_ref (luaState, (int)LuaIndexes.Registry) : 0;
}
public static void lua_rawgeti (LuaCore.lua_State luaState, int tableIndex, int index)
{
LuaCore.lua_rawgeti (luaState, tableIndex, index);
}
public static void lua_rawseti (LuaCore.lua_State luaState, int tableIndex, int index)
{
LuaCore.lua_rawseti (luaState, tableIndex, index);
}
public static object lua_newuserdata (LuaCore.lua_State luaState, int size)
{
return LuaCore.lua_newuserdata (luaState, (uint)size);
}
public static object lua_touserdata (LuaCore.lua_State luaState, int index)
{
return LuaCore.lua_touserdata (luaState, index);
}
public static void lua_getref (LuaCore.lua_State luaState, int reference)
{
lua_rawgeti (luaState, (int)LuaIndexes.Registry, reference);
}
public static void lua_unref (LuaCore.lua_State luaState, int reference)
{
LuaCore.luaL_unref (luaState, (int)LuaIndexes.Registry, reference);
}
public static bool lua_isstring (LuaCore.lua_State luaState, int index)
{
return LuaCore.lua_isstring (luaState, index) != 0;
}
public static bool lua_iscfunction (LuaCore.lua_State luaState, int index)
{
return LuaCore.lua_iscfunction (luaState, index);
}
public static void lua_pushnil (LuaCore.lua_State luaState)
{
LuaCore.lua_pushnil (luaState);
}
public static void lua_call (LuaCore.lua_State luaState, int nArgs, int nResults)
{
LuaCore.lua_call (luaState, nArgs, nResults);
}
public static void lua_pushstdcallcfunction (LuaCore.lua_State luaState, LuaCore.lua_CFunction function)
{
LuaCore.lua_pushcfunction (luaState, function);
}
public static int lua_pcall (LuaCore.lua_State luaState, int nArgs, int nResults, int errfunc)
{
return LuaCore.lua_pcall (luaState, nArgs, nResults, errfunc);
}
public static LuaCore.lua_CFunction lua_tocfunction (LuaCore.lua_State luaState, int index)
{
return LuaCore.lua_tocfunction (luaState, index);
}
public static double lua_tonumber (LuaCore.lua_State luaState, int index)
{
return LuaCore.lua_tonumber (luaState, index);
}
public static bool lua_toboolean (LuaCore.lua_State luaState, int index)
{
return LuaCore.lua_toboolean (luaState, index) != 0;
}
public static string lua_tostring (LuaCore.lua_State luaState, int index)
{
#if true
// FIXME use the same format string as lua i.e. LUA_NUMBER_FMT
var t = lua_type (luaState, index);
if (t == LuaTypes.Number)
return string.Format ("{0}", lua_tonumber (luaState, index));
else if (t == LuaTypes.String) {
uint strlen;
return LuaCore.lua_tolstring (luaState, index, out strlen).ToString ();
} else if (t == LuaTypes.Nil)
return null; // treat lua nulls to as C# nulls
else
return "0"; // Because luaV_tostring does this
#else
size_t strlen;
// Note! This method will _change_ the representation of the object on the stack to a string.
// We do not want this behavior so we do the conversion ourselves
const char *str = LuaCore.lua_tolstring(luaState, index, &strlen);
if (str)
return Marshal::PtrToStringAnsi(IntPtr((char *) str), strlen);
else
return nullptr; // treat lua nulls to as C# nulls
#endif
}
public static void lua_atpanic (LuaCore.lua_State luaState, LuaCore.lua_CFunction panicf)
{
LuaCore.lua_atpanic (luaState, (LuaCore.lua_CFunction)panicf);
}
public static void lua_pushnumber (LuaCore.lua_State luaState, double number)
{
LuaCore.lua_pushnumber (luaState, number);
}
public static void lua_pushboolean (LuaCore.lua_State luaState, bool value)
{
LuaCore.lua_pushboolean (luaState, value ? 1 : 0);
}
public static void lua_pushstring (LuaCore.lua_State luaState, string str)
{
LuaCore.lua_pushstring (luaState, str);
}
public static int luaL_newmetatable (LuaCore.lua_State luaState, string meta)
{
return LuaCore.luaL_newmetatable (luaState, meta);
}
// steffenj: BEGIN Lua 5.1.1 API change (luaL_getmetatable is now a macro using lua_getfield)
public static void lua_getfield (LuaCore.lua_State luaState, int stackPos, string meta)
{
LuaCore.lua_getfield (luaState, stackPos, meta);
}
public static void luaL_getmetatable (LuaCore.lua_State luaState, string meta)
{
lua_getfield (luaState, (int)LuaIndexes.Registry, meta);
}
public static object luaL_checkudata (LuaCore.lua_State luaState, int stackPos, string meta)
{
return LuaCore.luaL_checkudata (luaState, stackPos, meta);
}
public static bool luaL_getmetafield (LuaCore.lua_State luaState, int stackPos, string field)
{
return LuaCore.luaL_getmetafield (luaState, stackPos, field) != 0;
}
public static int luaL_loadbuffer (LuaCore.lua_State luaState, string buff, string name)
{
return LuaCore.luaL_loadbuffer (luaState, buff, (uint)buff.Length, name);
}
public static int luaL_loadfile (LuaCore.lua_State luaState, string filename)
{
return LuaCore.luaL_loadfile (luaState, filename);
}
public static bool luaL_checkmetatable (LuaCore.lua_State luaState, int index)
{
return LuaCore.luaL_checkmetatable (luaState, index);
}
public static int luanet_tonetobject (LuaCore.lua_State luaState, int index)
{
return LuaCore.luanet_tonetobject (luaState, index);
}
public static void luanet_newudata (LuaCore.lua_State luaState, int val)
{
LuaCore.luanet_newudata (luaState, val);
}
public static int luanet_rawnetobj (LuaCore.lua_State luaState, int obj)
{
return LuaCore.luanet_rawnetobj (luaState, obj);
}
public static int luanet_checkudata (LuaCore.lua_State luaState, int ud, string tname)
{
return LuaCore.luanet_checkudata (luaState, ud, tname);
}
public static void lua_error (LuaCore.lua_State luaState)
{
LuaCore.lua_error (luaState);
}
public static bool lua_checkstack (LuaCore.lua_State luaState, int extra)
{
return LuaCore.lua_checkstack (luaState, extra) != 0;
}
public static int lua_next (LuaCore.lua_State luaState, int index)
{
return LuaCore.lua_next (luaState, index);
}
public static void lua_pushlightuserdata (LuaCore.lua_State luaState, LuaCore.LuaTag udata)
{
LuaCore.lua_pushlightuserdata (luaState, udata.Tag);
}
public static LuaCore.LuaTag luanet_gettag ()
{
return LuaCore.luanet_gettag ();
}
}
}
\ No newline at end of file
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
using System.Text;
using System.Collections;
using System.Collections.Generic;
namespace LuaInterface
{
using LuaCore = KeraLua.Lua;
/*
* Wrapper class for Lua tables
*
* Author: Fabio Mascarenhas
* Version: 1.0
*/
public class LuaTable : LuaBase
{
public LuaTable (int reference, Lua interpreter)
{
_Reference = reference;
_Interpreter = interpreter;
}
/*
* Indexer for string fields of the table
*/
public object this [string field] {
get {
return _Interpreter.getObject (_Reference, field);
}
set {
_Interpreter.setObject (_Reference, field, value);
}
}
/*
* Indexer for numeric fields of the table
*/
public object this [object field] {
get {
return _Interpreter.getObject (_Reference, field);
}
set {
_Interpreter.setObject (_Reference, field, value);
}
}
public System.Collections.IDictionaryEnumerator GetEnumerator ()
{
return _Interpreter.GetTableDict (this).GetEnumerator ();
}
public ICollection Keys {
get { return _Interpreter.GetTableDict (this).Keys; }
}
public ICollection Values {
get { return _Interpreter.GetTableDict (this).Values; }
}
/*
* Gets an string fields of a table ignoring its metatable,
* if it exists
*/
internal object rawget (string field)
{
return _Interpreter.rawGetObject (_Reference, field);
}
internal object rawgetFunction (string field)
{
object obj = _Interpreter.rawGetObject (_Reference, field);
if (obj is LuaCore.lua_CFunction)
return new LuaFunction ((LuaCore.lua_CFunction)obj, _Interpreter);
else
return obj;
}
/*
* Pushes this table into the Lua stack
*/
internal void push (LuaCore.lua_State luaState)
{
LuaLib.lua_getref (luaState, _Reference);
}
public override string ToString ()
{
return "table";
}
}
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
using System.Text;
using System.Collections;
using System.Collections.Generic;
namespace LuaInterface
{
#if USE_KOPILUA
using LuaCore = KopiLua.Lua;
#else
using LuaCore = KeraLua.Lua;
#endif
/*
* Wrapper class for Lua tables
*
* Author: Fabio Mascarenhas
* Version: 1.0
*/
public class LuaTable : LuaBase
{
public LuaTable (int reference, Lua interpreter)
{
_Reference = reference;
_Interpreter = interpreter;
}
/*
* Indexer for string fields of the table
*/
public object this [string field] {
get {
return _Interpreter.getObject (_Reference, field);
}
set {
_Interpreter.setObject (_Reference, field, value);
}
}
/*
* Indexer for numeric fields of the table
*/
public object this [object field] {
get {
return _Interpreter.getObject (_Reference, field);
}
set {
_Interpreter.setObject (_Reference, field, value);
}
}
public System.Collections.IDictionaryEnumerator GetEnumerator ()
{
return _Interpreter.GetTableDict (this).GetEnumerator ();
}
public ICollection Keys {
get { return _Interpreter.GetTableDict (this).Keys; }
}
public ICollection Values {
get { return _Interpreter.GetTableDict (this).Values; }
}
/*
* Gets an string fields of a table ignoring its metatable,
* if it exists
*/
internal object rawget (string field)
{
return _Interpreter.rawGetObject (_Reference, field);
}
internal object rawgetFunction (string field)
{
object obj = _Interpreter.rawGetObject (_Reference, field);
if (obj is LuaCore.lua_CFunction)
return new LuaFunction ((LuaCore.lua_CFunction)obj, _Interpreter);
else
return obj;
}
/*
* Pushes this table into the Lua stack
*/
internal void push (LuaCore.lua_State luaState)
{
LuaLib.lua_getref (luaState, _Reference);
}
public override string ToString ()
{
return "table";
}
}
}
\ No newline at end of file
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
using System.Text;
using System.Collections.Generic;
namespace LuaInterface
{
using LuaCore = KeraLua.Lua;
public class LuaUserData : LuaBase
{
public LuaUserData (int reference, Lua interpreter)
{
_Reference = reference;
_Interpreter = interpreter;
}
/*
* Indexer for string fields of the userdata
*/
public object this [string field] {
get {
return _Interpreter.getObject (_Reference, field);
}
set {
_Interpreter.setObject (_Reference, field, value);
}
}
/*
* Indexer for numeric fields of the userdata
*/
public object this [object field] {
get {
return _Interpreter.getObject (_Reference, field);
}
set {
_Interpreter.setObject (_Reference, field, value);
}
}
/*
* Calls the userdata and returns its return values inside
* an array
*/
public object[] Call (params object[] args)
{
return _Interpreter.callFunction (this, args);
}
/*
* Pushes the userdata into the Lua stack
*/
internal void push (LuaCore.lua_State luaState)
{
LuaLib.lua_getref (luaState, _Reference);
}
public override string ToString ()
{
return "userdata";
}
}
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
using System.Text;
using System.Collections.Generic;
namespace LuaInterface
{
#if USE_KOPILUA
using LuaCore = KopiLua.Lua;
#else
using LuaCore = KeraLua.Lua;
#endif
public class LuaUserData : LuaBase
{
public LuaUserData (int reference, Lua interpreter)
{
_Reference = reference;
_Interpreter = interpreter;
}
/*
* Indexer for string fields of the userdata
*/
public object this [string field] {
get {
return _Interpreter.getObject (_Reference, field);
}
set {
_Interpreter.setObject (_Reference, field, value);
}
}
/*
* Indexer for numeric fields of the userdata
*/
public object this [object field] {
get {
return _Interpreter.getObject (_Reference, field);
}
set {
_Interpreter.setObject (_Reference, field, value);
}
}
/*
* Calls the userdata and returns its return values inside
* an array
*/
public object[] Call (params object[] args)
{
return _Interpreter.callFunction (this, args);
}
/*
* Pushes the userdata into the Lua stack
*/
internal void push (LuaCore.lua_State luaState)
{
LuaLib.lua_getref (luaState, _Reference);
}
public override string ToString ()
{
return "userdata";
}
}
}
\ No newline at end of file
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
using System.IO;
using System.Collections;
using System.Reflection;
using System.Diagnostics;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using LuaInterface.Method;
using LuaInterface.Extensions;
namespace LuaInterface
{
using LuaCore = KeraLua.Lua;
/*
* Functions used in the metatables of userdata representing
* CLR objects
*
* Author: Fabio Mascarenhas
* Version: 1.0
*/
class MetaFunctions
{
internal LuaCore.lua_CFunction gcFunction, indexFunction, newindexFunction, baseIndexFunction,
classIndexFunction, classNewindexFunction, execDelegateFunction, callConstructorFunction, toStringFunction;
private Hashtable memberCache = new Hashtable ();
private ObjectTranslator translator;
/*
* __index metafunction for CLR objects. Implemented in Lua.
*/
internal static string luaIndexFunction =
"local function index(obj,name) \n" +
" local meta=getmetatable(obj) \n" +
" local cached=meta.cache[name] \n" +
" if cached~=nil then \n" +
" return cached \n" +
" else \n" +
" local value,isFunc=get_object_member(obj,name) \n" +
" if isFunc then \n" +
" meta.cache[name]=value \n" +
" end \n" +
" return value \n" +
" end \n" +
"end \n" +
"return index ";
public MetaFunctions (ObjectTranslator translator)
{
this.translator = translator;
gcFunction = new LuaCore.lua_CFunction (this.collectObject);
toStringFunction = new LuaCore.lua_CFunction (this.toString);
indexFunction = new LuaCore.lua_CFunction (this.getMethod);
newindexFunction = new LuaCore.lua_CFunction (this.setFieldOrProperty);
baseIndexFunction = new LuaCore.lua_CFunction (this.getBaseMethod);
callConstructorFunction = new LuaCore.lua_CFunction (this.callConstructor);
classIndexFunction = new LuaCore.lua_CFunction (this.getClassMethod);
classNewindexFunction = new LuaCore.lua_CFunction (this.setClassFieldOrProperty);
execDelegateFunction = new LuaCore.lua_CFunction (this.runFunctionDelegate);
}
/*
* __call metafunction of CLR delegates, retrieves and calls the delegate.
*/
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
using System.IO;
using System.Collections;
using System.Reflection;
using System.Diagnostics;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using LuaInterface.Method;
using LuaInterface.Extensions;
namespace LuaInterface
{
#if USE_KOPILUA
using LuaCore = KopiLua.Lua;
#else
using LuaCore = KeraLua.Lua;
#endif
/*
* Functions used in the metatables of userdata representing
* CLR objects
*
* Author: Fabio Mascarenhas
* Version: 1.0
*/
public class MetaFunctions
{
internal LuaCore.lua_CFunction gcFunction, indexFunction, newindexFunction, baseIndexFunction,
classIndexFunction, classNewindexFunction, execDelegateFunction, callConstructorFunction, toStringFunction;
private Hashtable memberCache = new Hashtable ();
private ObjectTranslator translator;
/*
* __index metafunction for CLR objects. Implemented in Lua.
*/
internal static string luaIndexFunction =
"local function index(obj,name) \n" +
" local meta=getmetatable(obj) \n" +
" local cached=meta.cache[name] \n" +
" if cached~=nil then \n" +
" return cached \n" +
" else \n" +
" local value,isFunc=get_object_member(obj,name) \n" +
" if isFunc then \n" +
" meta.cache[name]=value \n" +
" end \n" +
" return value \n" +
" end \n" +
"end \n" +
"return index ";
public MetaFunctions (ObjectTranslator translator)
{
this.translator = translator;
gcFunction = new LuaCore.lua_CFunction (MetaFunctions.collectObject);
toStringFunction = new LuaCore.lua_CFunction (MetaFunctions.toString);
indexFunction = new LuaCore.lua_CFunction (MetaFunctions.getMethod);
newindexFunction = new LuaCore.lua_CFunction (MetaFunctions.setFieldOrProperty);
baseIndexFunction = new LuaCore.lua_CFunction (MetaFunctions.getBaseMethod);
callConstructorFunction = new LuaCore.lua_CFunction (MetaFunctions.callConstructor);
classIndexFunction = new LuaCore.lua_CFunction (MetaFunctions.getClassMethod);
classNewindexFunction = new LuaCore.lua_CFunction (MetaFunctions.setClassFieldOrProperty);
execDelegateFunction = new LuaCore.lua_CFunction (MetaFunctions.runFunctionDelegate);
}
/*
* __call metafunction of CLR delegates, retrieves and calls the delegate.
*/
#if MONOTOUCH
[MonoTouch.MonoPInvokeCallback (typeof (LuaCore.lua_CFunction))]
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private int runFunctionDelegate (LuaCore.lua_State luaState)
{
LuaCore.lua_CFunction func = (LuaCore.lua_CFunction)translator.getRawNetObject (luaState, 1);
LuaLib.lua_remove (luaState, 1);
return func (luaState);
}
/*
* __gc metafunction of CLR objects.
*/
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private static int runFunctionDelegate (LuaCore.lua_State luaState)
{
var translator = ObjectTranslatorPool.Instance.Find (luaState);
return runFunctionDelegate (luaState, translator);
}
private static int runFunctionDelegate (LuaCore.lua_State luaState, ObjectTranslator translator)
{
LuaCore.lua_CFunction func = (LuaCore.lua_CFunction)translator.getRawNetObject (luaState, 1);
LuaLib.lua_remove (luaState, 1);
return func (luaState);
}
/*
* __gc metafunction of CLR objects.
*/
#if MONOTOUCH
[MonoTouch.MonoPInvokeCallback (typeof (LuaCore.lua_CFunction))]
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private int collectObject (LuaCore.lua_State luaState)
{
int udata = LuaLib.luanet_rawnetobj (luaState, 1);
if (udata != -1)
translator.collectObject (udata);
else {
// Debug.WriteLine("not found: " + udata);
}
return 0;
}
/*
* __tostring metafunction of CLR objects.
*/
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private static int collectObject (LuaCore.lua_State luaState)
{
var translator = ObjectTranslatorPool.Instance.Find (luaState);
return collectObject (luaState, translator);
}
private static int collectObject (LuaCore.lua_State luaState, ObjectTranslator translator)
{
int udata = LuaLib.luanet_rawnetobj (luaState, 1);
if (udata != -1)
translator.collectObject (udata);
return 0;
}
/*
* __tostring metafunction of CLR objects.
*/
#if MONOTOUCH
[MonoTouch.MonoPInvokeCallback (typeof (LuaCore.lua_CFunction))]
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private int toString (LuaCore.lua_State luaState)
{
object obj = translator.getRawNetObject (luaState, 1);
if (!obj.IsNull ())
translator.push (luaState, obj.ToString () + ": " + obj.GetHashCode ());
else
LuaLib.lua_pushnil (luaState);
return 1;
}
/// <summary>
/// Debug tool to dump the lua stack
/// </summary>
/// FIXME, move somewhere else
public static void dumpStack (ObjectTranslator translator, LuaCore.lua_State luaState)
{
int depth = LuaLib.lua_gettop (luaState);
Debug.WriteLine ("lua stack depth: " + depth);
for (int i = 1; i <= depth; i++) {
var type = LuaLib.lua_type (luaState, i);
// we dump stacks when deep in calls, calling typename while the stack is in flux can fail sometimes, so manually check for key types
string typestr = (type == LuaTypes.Table) ? "table" : LuaLib.lua_typename (luaState, type);
string strrep = LuaLib.lua_tostring (luaState, i).ToString ();
if (type == LuaTypes.UserData) {
object obj = translator.getRawNetObject (luaState, i);
strrep = obj.ToString ();
}
Debug.Print ("{0}: ({1}) {2}", i, typestr, strrep);
}
}
/*
* Called by the __index metafunction of CLR objects in case the
* method is not cached or it is a field/property/event.
* Receives the object and the member name as arguments and returns
* either the value of the member or a delegate to call it.
* If the member does not exist returns nil.
*/
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private static int toString (LuaCore.lua_State luaState)
{
var translator = ObjectTranslatorPool.Instance.Find (luaState);
return toString (luaState, translator);
}
private static int toString (LuaCore.lua_State luaState, ObjectTranslator translator)
{
object obj = translator.getRawNetObject (luaState, 1);
if (!obj.IsNull ())
translator.push (luaState, obj.ToString () + ": " + obj.GetHashCode ());
else
LuaLib.lua_pushnil (luaState);
return 1;
}
/// <summary>
/// Debug tool to dump the lua stack
/// </summary>
/// FIXME, move somewhere else
public static void dumpStack (ObjectTranslator translator, LuaCore.lua_State luaState)
{
int depth = LuaLib.lua_gettop (luaState);
Debug.WriteLine ("lua stack depth: " + depth);
for (int i = 1; i <= depth; i++) {
var type = LuaLib.lua_type (luaState, i);
// we dump stacks when deep in calls, calling typename while the stack is in flux can fail sometimes, so manually check for key types
string typestr = (type == LuaTypes.Table) ? "table" : LuaLib.lua_typename (luaState, type);
string strrep = LuaLib.lua_tostring (luaState, i).ToString ();
if (type == LuaTypes.UserData) {
object obj = translator.getRawNetObject (luaState, i);
strrep = obj.ToString ();
}
Debug.Print ("{0}: ({1}) {2}", i, typestr, strrep);
}
}
/*
* Called by the __index metafunction of CLR objects in case the
* method is not cached or it is a field/property/event.
* Receives the object and the member name as arguments and returns
* either the value of the member or a delegate to call it.
* If the member does not exist returns nil.
*/
#if MONOTOUCH
[MonoTouch.MonoPInvokeCallback (typeof (LuaCore.lua_CFunction))]
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private int getMethod (LuaCore.lua_State luaState)
{
object obj = translator.getRawNetObject (luaState, 1);
if (obj.IsNull ()) {
translator.throwError (luaState, "trying to index an invalid object reference");
LuaLib.lua_pushnil (luaState);
return 1;
}
object index = translator.getObject (luaState, 2);
//var indexType = index.GetType();
string methodName = index as string; // will be null if not a string arg
var objType = obj.GetType ();
// Handle the most common case, looking up the method by name.
// CP: This will fail when using indexers and attempting to get a value with the same name as a property of the object,
// ie: xmlelement['item'] <- item is a property of xmlelement
try {
if (!methodName.IsNull () && isMemberPresent (objType, methodName))
return getMember (luaState, objType, obj, methodName, BindingFlags.Instance | BindingFlags.IgnoreCase);
} catch {
}
// Try to access by array if the type is right and index is an int (lua numbers always come across as double)
if (objType.IsArray && index is double) {
int intIndex = (int)((double)index);
if (objType.UnderlyingSystemType == typeof(float[])) {
float[] arr = ((float[])obj);
translator.push (luaState, arr [intIndex]);
} else if (objType.UnderlyingSystemType == typeof(double[])) {
double[] arr = ((double[])obj);
translator.push (luaState, arr [intIndex]);
} else if (objType.UnderlyingSystemType == typeof(int[])) {
int[] arr = ((int[])obj);
translator.push (luaState, arr [intIndex]);
} else {
object[] arr = (object[])obj;
translator.push (luaState, arr [intIndex]);
}
} else {
// Try to use get_Item to index into this .net object
//MethodInfo getter = objType.GetMethod("get_Item");
var methods = objType.GetMethods ();
foreach (var mInfo in methods) {
if (mInfo.Name == "get_Item") {
//check if the signature matches the input
if (mInfo.GetParameters ().Length == 1) {
var getter = mInfo;
var actualParms = (!getter.IsNull ()) ? getter.GetParameters () : null;
if (actualParms.IsNull () || actualParms.Length != 1) {
translator.throwError (luaState, "method not found (or no indexer): " + index);
LuaLib.lua_pushnil (luaState);
} else {
// Get the index in a form acceptable to the getter
index = translator.getAsType (luaState, 2, actualParms [0].ParameterType);
object[] args = new object[1];
// Just call the indexer - if out of bounds an exception will happen
args [0] = index;
try {
object result = getter.Invoke (obj, args);
translator.push (luaState, result);
} catch (TargetInvocationException e) {
// Provide a more readable description for the common case of key not found
if (e.InnerException is KeyNotFoundException)
translator.throwError (luaState, "key '" + index + "' not found ");
else
translator.throwError (luaState, "exception indexing '" + index + "' " + e.Message);
LuaLib.lua_pushnil (luaState);
}
}
}
}
}
}
LuaLib.lua_pushboolean (luaState, false);
return 2;
}
/*
* __index metafunction of base classes (the base field of Lua tables).
* Adds a prefix to the method name to call the base version of the method.
*/
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private static int getMethod (LuaCore.lua_State luaState)
{
var translator = ObjectTranslatorPool.Instance.Find (luaState);
var instance = translator.MetaFunctionsInstance;
return instance.getMethodInternal (luaState);
}
private int getMethodInternal (LuaCore.lua_State luaState)
{
object obj = translator.getRawNetObject (luaState, 1);
if (obj.IsNull ()) {
translator.throwError (luaState, "trying to index an invalid object reference");
LuaLib.lua_pushnil (luaState);
return 1;
}
object index = translator.getObject (luaState, 2);
//var indexType = index.GetType();
string methodName = index as string; // will be null if not a string arg
var objType = obj.GetType ();
// Handle the most common case, looking up the method by name.
// CP: This will fail when using indexers and attempting to get a value with the same name as a property of the object,
// ie: xmlelement['item'] <- item is a property of xmlelement
try {
if (!methodName.IsNull () && isMemberPresent (objType, methodName))
return getMember (luaState, objType, obj, methodName, BindingFlags.Instance | BindingFlags.IgnoreCase);
} catch {
}
// Try to access by array if the type is right and index is an int (lua numbers always come across as double)
if (objType.IsArray && index is double) {
int intIndex = (int)((double)index);
if (objType.UnderlyingSystemType == typeof(float[])) {
float[] arr = ((float[])obj);
translator.push (luaState, arr [intIndex]);
} else if (objType.UnderlyingSystemType == typeof(double[])) {
double[] arr = ((double[])obj);
translator.push (luaState, arr [intIndex]);
} else if (objType.UnderlyingSystemType == typeof(int[])) {
int[] arr = ((int[])obj);
translator.push (luaState, arr [intIndex]);
} else {
object[] arr = (object[])obj;
translator.push (luaState, arr [intIndex]);
}
} else {
// Try to use get_Item to index into this .net object
//MethodInfo getter = objType.GetMethod("get_Item");
var methods = objType.GetMethods ();
foreach (var mInfo in methods) {
if (mInfo.Name == "get_Item") {
//check if the signature matches the input
if (mInfo.GetParameters ().Length == 1) {
var getter = mInfo;
var actualParms = (!getter.IsNull ()) ? getter.GetParameters () : null;
if (actualParms.IsNull () || actualParms.Length != 1) {
translator.throwError (luaState, "method not found (or no indexer): " + index);
LuaLib.lua_pushnil (luaState);
} else {
// Get the index in a form acceptable to the getter
index = translator.getAsType (luaState, 2, actualParms [0].ParameterType);
object[] args = new object[1];
// Just call the indexer - if out of bounds an exception will happen
args [0] = index;
try {
object result = getter.Invoke (obj, args);
translator.push (luaState, result);
} catch (TargetInvocationException e) {
// Provide a more readable description for the common case of key not found
if (e.InnerException is KeyNotFoundException)
translator.throwError (luaState, "key '" + index + "' not found ");
else
translator.throwError (luaState, "exception indexing '" + index + "' " + e.Message);
LuaLib.lua_pushnil (luaState);
}
}
}
}
}
}
LuaLib.lua_pushboolean (luaState, false);
return 2;
}
/*
* __index metafunction of base classes (the base field of Lua tables).
* Adds a prefix to the method name to call the base version of the method.
*/
#if MONOTOUCH
[MonoTouch.MonoPInvokeCallback (typeof (LuaCore.lua_CFunction))]
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private int getBaseMethod (LuaCore.lua_State luaState)
{
object obj = translator.getRawNetObject (luaState, 1);
if (obj.IsNull ()) {
translator.throwError (luaState, "trying to index an invalid object reference");
LuaLib.lua_pushnil (luaState);
LuaLib.lua_pushboolean (luaState, false);
return 2;
}
string methodName = LuaLib.lua_tostring (luaState, 2).ToString ();
if (methodName.IsNull ()) {
LuaLib.lua_pushnil (luaState);
LuaLib.lua_pushboolean (luaState, false);
return 2;
}
getMember (luaState, obj.GetType (), obj, "__luaInterface_base_" + methodName, BindingFlags.Instance | BindingFlags.IgnoreCase);
LuaLib.lua_settop (luaState, -2);
if (LuaLib.lua_type (luaState, -1) == LuaTypes.Nil) {
LuaLib.lua_settop (luaState, -2);
return getMember (luaState, obj.GetType (), obj, methodName, BindingFlags.Instance | BindingFlags.IgnoreCase);
}
LuaLib.lua_pushboolean (luaState, false);
return 2;
}
/// <summary>
/// Does this method exist as either an instance or static?
/// </summary>
/// <param name="objType"></param>
/// <param name="methodName"></param>
/// <returns></returns>
bool isMemberPresent (IReflect objType, string methodName)
{
object cachedMember = checkMemberCache (memberCache, objType, methodName);
if (!cachedMember.IsNull ())
return true;
//CP: Removed NonPublic binding search
var members = objType.GetMember (methodName, BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase/* | BindingFlags.NonPublic*/);
return (members.Length > 0);
}
/*
* Pushes the value of a member or a delegate to call it, depending on the type of
* the member. Works with static or instance members.
* Uses reflection to find members, and stores the reflected MemberInfo object in
* a cache (indexed by the type of the object and the name of the member).
*/
private int getMember (LuaCore.lua_State luaState, IReflect objType, object obj, string methodName, BindingFlags bindingType)
{
bool implicitStatic = false;
MemberInfo member = null;
object cachedMember = checkMemberCache (memberCache, objType, methodName);
//object cachedMember=null;
if (cachedMember is LuaCore.lua_CFunction) {
translator.pushFunction (luaState, (LuaCore.lua_CFunction)cachedMember);
translator.push (luaState, true);
return 2;
} else if (!cachedMember.IsNull ())
member = (MemberInfo)cachedMember;
else {
//CP: Removed NonPublic binding search
var members = objType.GetMember (methodName, bindingType | BindingFlags.Public | BindingFlags.IgnoreCase/*| BindingFlags.NonPublic*/);
if (members.Length > 0)
member = members [0];
else {
// If we can't find any suitable instance members, try to find them as statics - but we only want to allow implicit static
// lookups for fields/properties/events -kevinh
//CP: Removed NonPublic binding search and made case insensitive
members = objType.GetMember (methodName, bindingType | BindingFlags.Static | BindingFlags.Public | BindingFlags.IgnoreCase/*| BindingFlags.NonPublic*/);
if (members.Length > 0) {
member = members [0];
implicitStatic = true;
}
}
}
if (!member.IsNull ()) {
if (member.MemberType == MemberTypes.Field) {
var field = (FieldInfo)member;
if (cachedMember.IsNull ())
setMemberCache (memberCache, objType, methodName, member);
try {
translator.push (luaState, field.GetValue (obj));
} catch {
LuaLib.lua_pushnil (luaState);
}
} else if (member.MemberType == MemberTypes.Property) {
var property = (PropertyInfo)member;
if (cachedMember.IsNull ())
setMemberCache (memberCache, objType, methodName, member);
try {
object val = property.GetValue (obj, null);
translator.push (luaState, val);
} catch (ArgumentException) {
// If we can't find the getter in our class, recurse up to the base class and see
// if they can help.
if (objType is Type && !(((Type)objType) == typeof(object)))
return getMember (luaState, ((Type)objType).BaseType, obj, methodName, bindingType);
else
LuaLib.lua_pushnil (luaState);
} catch (TargetInvocationException e) { // Convert this exception into a Lua error
ThrowError (luaState, e);
LuaLib.lua_pushnil (luaState);
}
} else if (member.MemberType == MemberTypes.Event) {
var eventInfo = (EventInfo)member;
if (cachedMember.IsNull ())
setMemberCache (memberCache, objType, methodName, member);
translator.push (luaState, new RegisterEventHandler (translator.pendingEvents, obj, eventInfo));
} else if (!implicitStatic) {
if (member.MemberType == MemberTypes.NestedType) {
// kevinh - added support for finding nested types
// cache us
if (cachedMember.IsNull ())
setMemberCache (memberCache, objType, methodName, member);
// Find the name of our class
string name = member.Name;
var dectype = member.DeclaringType;
// Build a new long name and try to find the type by name
string longname = dectype.FullName + "+" + name;
var nestedType = translator.FindType (longname);
translator.pushType (luaState, nestedType);
} else {
// Member type must be 'method'
var wrapper = new LuaCore.lua_CFunction ((new LuaMethodWrapper (translator, objType, methodName, bindingType)).invokeFunction);
if (cachedMember.IsNull ())
setMemberCache (memberCache, objType, methodName, wrapper);
translator.pushFunction (luaState, wrapper);
translator.push (luaState, true);
return 2;
}
} else {
// If we reach this point we found a static method, but can't use it in this context because the user passed in an instance
translator.throwError (luaState, "can't pass instance to static method " + methodName);
LuaLib.lua_pushnil (luaState);
}
} else {
// kevinh - we want to throw an exception because meerly returning 'nil' in this case
// is not sufficient. valid data members may return nil and therefore there must be some
// way to know the member just doesn't exist.
translator.throwError (luaState, "unknown member name " + methodName);
LuaLib.lua_pushnil (luaState);
}
// push false because we are NOT returning a function (see luaIndexFunction)
translator.push (luaState, false);
return 2;
}
/*
* Checks if a MemberInfo object is cached, returning it or null.
*/
private object checkMemberCache (Hashtable memberCache, IReflect objType, string memberName)
{
var members = (Hashtable)memberCache [objType];
return !members.IsNull () ? members [memberName] : null;
}
/*
* Stores a MemberInfo object in the member cache.
*/
private void setMemberCache (Hashtable memberCache, IReflect objType, string memberName, object member)
{
var members = (Hashtable)memberCache [objType];
if (members.IsNull ()) {
members = new Hashtable ();
memberCache [objType] = members;
}
members [memberName] = member;
}
/*
* __newindex metafunction of CLR objects. Receives the object,
* the member name and the value to be stored as arguments. Throws
* and error if the assignment is invalid.
*/
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private static int getBaseMethod (LuaCore.lua_State luaState)
{
var translator = ObjectTranslatorPool.Instance.Find (luaState);
var instance = translator.MetaFunctionsInstance;
return instance.getBaseMethodInternal (luaState);
}
private int getBaseMethodInternal (LuaCore.lua_State luaState)
{
object obj = translator.getRawNetObject (luaState, 1);
if (obj.IsNull ()) {
translator.throwError (luaState, "trying to index an invalid object reference");
LuaLib.lua_pushnil (luaState);
LuaLib.lua_pushboolean (luaState, false);
return 2;
}
string methodName = LuaLib.lua_tostring (luaState, 2).ToString ();
if (methodName.IsNull ()) {
LuaLib.lua_pushnil (luaState);
LuaLib.lua_pushboolean (luaState, false);
return 2;
}
getMember (luaState, obj.GetType (), obj, "__luaInterface_base_" + methodName, BindingFlags.Instance | BindingFlags.IgnoreCase);
LuaLib.lua_settop (luaState, -2);
if (LuaLib.lua_type (luaState, -1) == LuaTypes.Nil) {
LuaLib.lua_settop (luaState, -2);
return getMember (luaState, obj.GetType (), obj, methodName, BindingFlags.Instance | BindingFlags.IgnoreCase);
}
LuaLib.lua_pushboolean (luaState, false);
return 2;
}
/// <summary>
/// Does this method exist as either an instance or static?
/// </summary>
/// <param name="objType"></param>
/// <param name="methodName"></param>
/// <returns></returns>
bool isMemberPresent (IReflect objType, string methodName)
{
object cachedMember = checkMemberCache (memberCache, objType, methodName);
if (!cachedMember.IsNull ())
return true;
//CP: Removed NonPublic binding search
var members = objType.GetMember (methodName, BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase/* | BindingFlags.NonPublic*/);
return (members.Length > 0);
}
/*
* Pushes the value of a member or a delegate to call it, depending on the type of
* the member. Works with static or instance members.
* Uses reflection to find members, and stores the reflected MemberInfo object in
* a cache (indexed by the type of the object and the name of the member).
*/
private int getMember (LuaCore.lua_State luaState, IReflect objType, object obj, string methodName, BindingFlags bindingType)
{
bool implicitStatic = false;
MemberInfo member = null;
object cachedMember = checkMemberCache (memberCache, objType, methodName);
//object cachedMember=null;
if (cachedMember is LuaCore.lua_CFunction) {
translator.pushFunction (luaState, (LuaCore.lua_CFunction)cachedMember);
translator.push (luaState, true);
return 2;
} else if (!cachedMember.IsNull ())
member = (MemberInfo)cachedMember;
else {
//CP: Removed NonPublic binding search
var members = objType.GetMember (methodName, bindingType | BindingFlags.Public | BindingFlags.IgnoreCase/*| BindingFlags.NonPublic*/);
if (members.Length > 0)
member = members [0];
else {
// If we can't find any suitable instance members, try to find them as statics - but we only want to allow implicit static
// lookups for fields/properties/events -kevinh
//CP: Removed NonPublic binding search and made case insensitive
members = objType.GetMember (methodName, bindingType | BindingFlags.Static | BindingFlags.Public | BindingFlags.IgnoreCase/*| BindingFlags.NonPublic*/);
if (members.Length > 0) {
member = members [0];
implicitStatic = true;
}
}
}
if (!member.IsNull ()) {
if (member.MemberType == MemberTypes.Field) {
var field = (FieldInfo)member;
if (cachedMember.IsNull ())
setMemberCache (memberCache, objType, methodName, member);
try {
translator.push (luaState, field.GetValue (obj));
} catch {
LuaLib.lua_pushnil (luaState);
}
} else if (member.MemberType == MemberTypes.Property) {
var property = (PropertyInfo)member;
if (cachedMember.IsNull ())
setMemberCache (memberCache, objType, methodName, member);
try {
object val = property.GetValue (obj, null);
translator.push (luaState, val);
} catch (ArgumentException) {
// If we can't find the getter in our class, recurse up to the base class and see
// if they can help.
if (objType is Type && !(((Type)objType) == typeof(object)))
return getMember (luaState, ((Type)objType).BaseType, obj, methodName, bindingType);
else
LuaLib.lua_pushnil (luaState);
} catch (TargetInvocationException e) { // Convert this exception into a Lua error
ThrowError (luaState, e);
LuaLib.lua_pushnil (luaState);
}
} else if (member.MemberType == MemberTypes.Event) {
var eventInfo = (EventInfo)member;
if (cachedMember.IsNull ())
setMemberCache (memberCache, objType, methodName, member);
translator.push (luaState, new RegisterEventHandler (translator.pendingEvents, obj, eventInfo));
} else if (!implicitStatic) {
if (member.MemberType == MemberTypes.NestedType) {
// kevinh - added support for finding nested types
// cache us
if (cachedMember.IsNull ())
setMemberCache (memberCache, objType, methodName, member);
// Find the name of our class
string name = member.Name;
var dectype = member.DeclaringType;
// Build a new long name and try to find the type by name
string longname = dectype.FullName + "+" + name;
var nestedType = translator.FindType (longname);
translator.pushType (luaState, nestedType);
} else {
// Member type must be 'method'
var wrapper = new LuaCore.lua_CFunction ((new LuaMethodWrapper (translator, objType, methodName, bindingType)).invokeFunction);
if (cachedMember.IsNull ())
setMemberCache (memberCache, objType, methodName, wrapper);
translator.pushFunction (luaState, wrapper);
translator.push (luaState, true);
return 2;
}
} else {
// If we reach this point we found a static method, but can't use it in this context because the user passed in an instance
translator.throwError (luaState, "can't pass instance to static method " + methodName);
LuaLib.lua_pushnil (luaState);
}
} else {
// kevinh - we want to throw an exception because meerly returning 'nil' in this case
// is not sufficient. valid data members may return nil and therefore there must be some
// way to know the member just doesn't exist.
translator.throwError (luaState, "unknown member name " + methodName);
LuaLib.lua_pushnil (luaState);
}
// push false because we are NOT returning a function (see luaIndexFunction)
translator.push (luaState, false);
return 2;
}
/*
* Checks if a MemberInfo object is cached, returning it or null.
*/
private object checkMemberCache (Hashtable memberCache, IReflect objType, string memberName)
{
var members = (Hashtable)memberCache [objType];
return !members.IsNull () ? members [memberName] : null;
}
/*
* Stores a MemberInfo object in the member cache.
*/
private void setMemberCache (Hashtable memberCache, IReflect objType, string memberName, object member)
{
var members = (Hashtable)memberCache [objType];
if (members.IsNull ()) {
members = new Hashtable ();
memberCache [objType] = members;
}
members [memberName] = member;
}
/*
* __newindex metafunction of CLR objects. Receives the object,
* the member name and the value to be stored as arguments. Throws
* and error if the assignment is invalid.
*/
#if MONOTOUCH
[MonoTouch.MonoPInvokeCallback (typeof (LuaCore.lua_CFunction))]
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private int setFieldOrProperty (LuaCore.lua_State luaState)
{
object target = translator.getRawNetObject (luaState, 1);
if (target.IsNull ()) {
translator.throwError (luaState, "trying to index and invalid object reference");
return 0;
}
var type = target.GetType ();
// First try to look up the parameter as a property name
string detailMessage;
bool didMember = trySetMember (luaState, type, target, BindingFlags.Instance | BindingFlags.IgnoreCase, out detailMessage);
if (didMember)
return 0; // Must have found the property name
// We didn't find a property name, now see if we can use a [] style this accessor to set array contents
try {
if (type.IsArray && LuaLib.lua_isnumber (luaState, 2)) {
int index = (int)LuaLib.lua_tonumber (luaState, 2);
var arr = (Array)target;
object val = translator.getAsType (luaState, 3, arr.GetType ().GetElementType ());
arr.SetValue (val, index);
} else {
// Try to see if we have a this[] accessor
var setter = type.GetMethod ("set_Item");
if (!setter.IsNull ()) {
var args = setter.GetParameters ();
var valueType = args [1].ParameterType;
// The new val ue the user specified
object val = translator.getAsType (luaState, 3, valueType);
var indexType = args [0].ParameterType;
object index = translator.getAsType (luaState, 2, indexType);
object[] methodArgs = new object[2];
// Just call the indexer - if out of bounds an exception will happen
methodArgs [0] = index;
methodArgs [1] = val;
setter.Invoke (target, methodArgs);
} else
translator.throwError (luaState, detailMessage); // Pass the original message from trySetMember because it is probably best
}
} catch (SEHException) {
// If we are seeing a C++ exception - this must actually be for Lua's private use. Let it handle it
throw;
} catch (Exception e) {
ThrowError (luaState, e);
}
return 0;
}
/// <summary>
/// Tries to set a named property or field
/// </summary>
/// <param name="luaState"></param>
/// <param name="targetType"></param>
/// <param name="target"></param>
/// <param name="bindingType"></param>
/// <returns>false if unable to find the named member, true for success</returns>
private bool trySetMember (LuaCore.lua_State luaState, IReflect targetType, object target, BindingFlags bindingType, out string detailMessage)
{
detailMessage = null; // No error yet
// If not already a string just return - we don't want to call tostring - which has the side effect of
// changing the lua typecode to string
// Note: We don't use isstring because the standard lua C isstring considers either strings or numbers to
// be true for isstring.
if (LuaLib.lua_type (luaState, 2) != LuaTypes.String) {
detailMessage = "property names must be strings";
return false;
}
// We only look up property names by string
string fieldName = LuaLib.lua_tostring (luaState, 2).ToString ();
if (fieldName.IsNull () || fieldName.Length < 1 || !(char.IsLetter (fieldName [0]) || fieldName [0] == '_')) {
detailMessage = "invalid property name";
return false;
}
// Find our member via reflection or the cache
var member = (MemberInfo)checkMemberCache (memberCache, targetType, fieldName);
if (member.IsNull ()) {
//CP: Removed NonPublic binding search and made case insensitive
var members = targetType.GetMember (fieldName, bindingType | BindingFlags.Public | BindingFlags.IgnoreCase/*| BindingFlags.NonPublic*/);
if (members.Length > 0) {
member = members [0];
setMemberCache (memberCache, targetType, fieldName, member);
} else {
detailMessage = "field or property '" + fieldName + "' does not exist";
return false;
}
}
if (member.MemberType == MemberTypes.Field) {
var field = (FieldInfo)member;
object val = translator.getAsType (luaState, 3, field.FieldType);
try {
field.SetValue (target, val);
} catch (Exception e) {
ThrowError (luaState, e);
}
// We did a call
return true;
} else if (member.MemberType == MemberTypes.Property) {
var property = (PropertyInfo)member;
object val = translator.getAsType (luaState, 3, property.PropertyType);
try {
property.SetValue (target, val, null);
} catch (Exception e) {
ThrowError (luaState, e);
}
// We did a call
return true;
}
detailMessage = "'" + fieldName + "' is not a .net field or property";
return false;
}
/*
* Writes to fields or properties, either static or instance. Throws an error
* if the operation is invalid.
*/
private int setMember (LuaCore.lua_State luaState, IReflect targetType, object target, BindingFlags bindingType)
{
string detail;
bool success = trySetMember (luaState, targetType, target, bindingType, out detail);
if (!success)
translator.throwError (luaState, detail);
return 0;
}
/// <summary>
/// Convert a C# exception into a Lua error
/// </summary>
/// <param name="e"></param>
/// We try to look into the exception to give the most meaningful description
void ThrowError (LuaCore.lua_State luaState, Exception e)
{
// If we got inside a reflection show what really happened
var te = e as TargetInvocationException;
if (!te.IsNull ())
e = te.InnerException;
translator.throwError (luaState, e);
}
/*
* __index metafunction of type references, works on static members.
*/
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private static int setFieldOrProperty (LuaCore.lua_State luaState)
{
var translator = ObjectTranslatorPool.Instance.Find (luaState);
var instance = translator.MetaFunctionsInstance;
return instance.setFieldOrPropertyInternal (luaState);
}
private int setFieldOrPropertyInternal (LuaCore.lua_State luaState)
{
object target = translator.getRawNetObject (luaState, 1);
if (target.IsNull ()) {
translator.throwError (luaState, "trying to index and invalid object reference");
return 0;
}
var type = target.GetType ();
// First try to look up the parameter as a property name
string detailMessage;
bool didMember = trySetMember (luaState, type, target, BindingFlags.Instance | BindingFlags.IgnoreCase, out detailMessage);
if (didMember)
return 0; // Must have found the property name
// We didn't find a property name, now see if we can use a [] style this accessor to set array contents
try {
if (type.IsArray && LuaLib.lua_isnumber (luaState, 2)) {
int index = (int)LuaLib.lua_tonumber (luaState, 2);
var arr = (Array)target;
object val = translator.getAsType (luaState, 3, arr.GetType ().GetElementType ());
arr.SetValue (val, index);
} else {
// Try to see if we have a this[] accessor
var setter = type.GetMethod ("set_Item");
if (!setter.IsNull ()) {
var args = setter.GetParameters ();
var valueType = args [1].ParameterType;
// The new val ue the user specified
object val = translator.getAsType (luaState, 3, valueType);
var indexType = args [0].ParameterType;
object index = translator.getAsType (luaState, 2, indexType);
object[] methodArgs = new object[2];
// Just call the indexer - if out of bounds an exception will happen
methodArgs [0] = index;
methodArgs [1] = val;
setter.Invoke (target, methodArgs);
} else
translator.throwError (luaState, detailMessage); // Pass the original message from trySetMember because it is probably best
}
} catch (SEHException) {
// If we are seeing a C++ exception - this must actually be for Lua's private use. Let it handle it
throw;
} catch (Exception e) {
ThrowError (luaState, e);
}
return 0;
}
/// <summary>
/// Tries to set a named property or field
/// </summary>
/// <param name="luaState"></param>
/// <param name="targetType"></param>
/// <param name="target"></param>
/// <param name="bindingType"></param>
/// <returns>false if unable to find the named member, true for success</returns>
private bool trySetMember (LuaCore.lua_State luaState, IReflect targetType, object target, BindingFlags bindingType, out string detailMessage)
{
detailMessage = null; // No error yet
// If not already a string just return - we don't want to call tostring - which has the side effect of
// changing the lua typecode to string
// Note: We don't use isstring because the standard lua C isstring considers either strings or numbers to
// be true for isstring.
if (LuaLib.lua_type (luaState, 2) != LuaTypes.String) {
detailMessage = "property names must be strings";
return false;
}
// We only look up property names by string
string fieldName = LuaLib.lua_tostring (luaState, 2).ToString ();
if (fieldName.IsNull () || fieldName.Length < 1 || !(char.IsLetter (fieldName [0]) || fieldName [0] == '_')) {
detailMessage = "invalid property name";
return false;
}
// Find our member via reflection or the cache
var member = (MemberInfo)checkMemberCache (memberCache, targetType, fieldName);
if (member.IsNull ()) {
//CP: Removed NonPublic binding search and made case insensitive
var members = targetType.GetMember (fieldName, bindingType | BindingFlags.Public | BindingFlags.IgnoreCase/*| BindingFlags.NonPublic*/);
if (members.Length > 0) {
member = members [0];
setMemberCache (memberCache, targetType, fieldName, member);
} else {
detailMessage = "field or property '" + fieldName + "' does not exist";
return false;
}
}
if (member.MemberType == MemberTypes.Field) {
var field = (FieldInfo)member;
object val = translator.getAsType (luaState, 3, field.FieldType);
try {
field.SetValue (target, val);
} catch (Exception e) {
ThrowError (luaState, e);
}
// We did a call
return true;
} else if (member.MemberType == MemberTypes.Property) {
var property = (PropertyInfo)member;
object val = translator.getAsType (luaState, 3, property.PropertyType);
try {
property.SetValue (target, val, null);
} catch (Exception e) {
ThrowError (luaState, e);
}
// We did a call
return true;
}
detailMessage = "'" + fieldName + "' is not a .net field or property";
return false;
}
/*
* Writes to fields or properties, either static or instance. Throws an error
* if the operation is invalid.
*/
private int setMember (LuaCore.lua_State luaState, IReflect targetType, object target, BindingFlags bindingType)
{
string detail;
bool success = trySetMember (luaState, targetType, target, bindingType, out detail);
if (!success)
translator.throwError (luaState, detail);
return 0;
}
/// <summary>
/// Convert a C# exception into a Lua error
/// </summary>
/// <param name="e"></param>
/// We try to look into the exception to give the most meaningful description
void ThrowError (LuaCore.lua_State luaState, Exception e)
{
// If we got inside a reflection show what really happened
var te = e as TargetInvocationException;
if (!te.IsNull ())
e = te.InnerException;
translator.throwError (luaState, e);
}
/*
* __index metafunction of type references, works on static members.
*/
#if MONOTOUCH
[MonoTouch.MonoPInvokeCallback (typeof (LuaCore.lua_CFunction))]
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private int getClassMethod (LuaCore.lua_State luaState)
{
IReflect klass;
object obj = translator.getRawNetObject (luaState, 1);
if (obj.IsNull () || !(obj is IReflect)) {
translator.throwError (luaState, "trying to index an invalid type reference");
LuaLib.lua_pushnil (luaState);
return 1;
} else
klass = (IReflect)obj;
if (LuaLib.lua_isnumber (luaState, 2)) {
int size = (int)LuaLib.lua_tonumber (luaState, 2);
translator.push (luaState, Array.CreateInstance (klass.UnderlyingSystemType, size));
return 1;
} else {
string methodName = LuaLib.lua_tostring (luaState, 2).ToString ();
if (methodName.IsNull ()) {
LuaLib.lua_pushnil (luaState);
return 1;
} //CP: Ignore case
else
return getMember (luaState, klass, null, methodName, BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.IgnoreCase);
}
}
/*
* __newindex function of type references, works on static members.
*/
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private static int getClassMethod (LuaCore.lua_State luaState)
{
var translator = ObjectTranslatorPool.Instance.Find (luaState);
var instance = translator.MetaFunctionsInstance;
return instance.getClassMethodInternal (luaState);
}
private int getClassMethodInternal (LuaCore.lua_State luaState)
{
IReflect klass;
object obj = translator.getRawNetObject (luaState, 1);
if (obj.IsNull () || !(obj is IReflect)) {
translator.throwError (luaState, "trying to index an invalid type reference");
LuaLib.lua_pushnil (luaState);
return 1;
} else
klass = (IReflect)obj;
if (LuaLib.lua_isnumber (luaState, 2)) {
int size = (int)LuaLib.lua_tonumber (luaState, 2);
translator.push (luaState, Array.CreateInstance (klass.UnderlyingSystemType, size));
return 1;
} else {
string methodName = LuaLib.lua_tostring (luaState, 2).ToString ();
if (methodName.IsNull ()) {
LuaLib.lua_pushnil (luaState);
return 1;
} //CP: Ignore case
else
return getMember (luaState, klass, null, methodName, BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.IgnoreCase);
}
}
/*
* __newindex function of type references, works on static members.
*/
#if MONOTOUCH
[MonoTouch.MonoPInvokeCallback (typeof (LuaCore.lua_CFunction))]
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private int setClassFieldOrProperty (LuaCore.lua_State luaState)
{
IReflect target;
object obj = translator.getRawNetObject (luaState, 1);
if (obj.IsNull () || !(obj is IReflect)) {
translator.throwError (luaState, "trying to index an invalid type reference");
return 0;
} else
target = (IReflect)obj;
return setMember (luaState, target, null, BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.IgnoreCase);
}
/*
* __call metafunction of type references. Searches for and calls
* a constructor for the type. Returns nil if the constructor is not
* found or if the arguments are invalid. Throws an error if the constructor
* generates an exception.
*/
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private static int setClassFieldOrProperty (LuaCore.lua_State luaState)
{
var translator = ObjectTranslatorPool.Instance.Find (luaState);
var instance = translator.MetaFunctionsInstance;
return instance.setClassFieldOrPropertyInternal (luaState);
}
private int setClassFieldOrPropertyInternal (LuaCore.lua_State luaState)
{
IReflect target;
object obj = translator.getRawNetObject (luaState, 1);
if (obj.IsNull () || !(obj is IReflect)) {
translator.throwError (luaState, "trying to index an invalid type reference");
return 0;
} else
target = (IReflect)obj;
return setMember (luaState, target, null, BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.IgnoreCase);
}
/*
* __call metafunction of type references. Searches for and calls
* a constructor for the type. Returns nil if the constructor is not
* found or if the arguments are invalid. Throws an error if the constructor
* generates an exception.
*/
#if MONOTOUCH
[MonoTouch.MonoPInvokeCallback (typeof (LuaCore.lua_CFunction))]
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private int callConstructor (LuaCore.lua_State luaState)
{
var validConstructor = new MethodCache ();
IReflect klass;
object obj = translator.getRawNetObject (luaState, 1);
if (obj.IsNull () || !(obj is IReflect)) {
translator.throwError (luaState, "trying to call constructor on an invalid type reference");
LuaLib.lua_pushnil (luaState);
return 1;
} else
klass = (IReflect)obj;
LuaLib.lua_remove (luaState, 1);
var constructors = klass.UnderlyingSystemType.GetConstructors ();
foreach (var constructor in constructors) {
bool isConstructor = matchParameters (luaState, constructor, ref validConstructor);
if (isConstructor) {
try {
translator.push (luaState, constructor.Invoke (validConstructor.args));
} catch (TargetInvocationException e) {
ThrowError (luaState, e);
LuaLib.lua_pushnil (luaState);
} catch {
LuaLib.lua_pushnil (luaState);
}
return 1;
}
}
string constructorName = (constructors.Length == 0) ? "unknown" : constructors [0].Name;
translator.throwError (luaState, String.Format ("{0} does not contain constructor({1}) argument match",
klass.UnderlyingSystemType, constructorName));
LuaLib.lua_pushnil (luaState);
return 1;
}
/*
* Matches a method against its arguments in the Lua stack. Returns
* if the match was succesful. It it was also returns the information
* necessary to invoke the method.
*/
internal bool matchParameters (LuaCore.lua_State luaState, MethodBase method, ref MethodCache methodCache)
{
ExtractValue extractValue;
bool isMethod = true;
var paramInfo = method.GetParameters ();
int currentLuaParam = 1;
int nLuaParams = LuaLib.lua_gettop (luaState);
var paramList = new ArrayList ();
var outList = new List<int> ();
var argTypes = new List<MethodArgs> ();
foreach (var currentNetParam in paramInfo) {
if (!currentNetParam.IsIn && currentNetParam.IsOut) // Skips out params
outList.Add (paramList.Add (null));
else if (currentLuaParam > nLuaParams) { // Adds optional parameters
if (currentNetParam.IsOptional)
paramList.Add (currentNetParam.DefaultValue);
else {
isMethod = false;
break;
}
} else if (_IsTypeCorrect (luaState, currentLuaParam, currentNetParam, out extractValue)) { // Type checking
int index = paramList.Add (extractValue (luaState, currentLuaParam));
var methodArg = new MethodArgs ();
methodArg.index = index;
methodArg.extractValue = extractValue;
argTypes.Add (methodArg);
if (currentNetParam.ParameterType.IsByRef)
outList.Add (index);
currentLuaParam++;
} // Type does not match, ignore if the parameter is optional
else if (_IsParamsArray (luaState, currentLuaParam, currentNetParam, out extractValue)) {
object luaParamValue = extractValue (luaState, currentLuaParam);
var paramArrayType = currentNetParam.ParameterType.GetElementType ();
Array paramArray;
if (luaParamValue is LuaTable) {
var table = (LuaTable)luaParamValue;
var tableEnumerator = table.GetEnumerator ();
paramArray = Array.CreateInstance (paramArrayType, table.Values.Count);
tableEnumerator.Reset ();
int paramArrayIndex = 0;
while (tableEnumerator.MoveNext()) {
paramArray.SetValue (Convert.ChangeType (tableEnumerator.Value, currentNetParam.ParameterType.GetElementType ()), paramArrayIndex);
paramArrayIndex++;
}
} else {
paramArray = Array.CreateInstance (paramArrayType, 1);
paramArray.SetValue (luaParamValue, 0);
}
int index = paramList.Add (paramArray);
var methodArg = new MethodArgs ();
methodArg.index = index;
methodArg.extractValue = extractValue;
methodArg.isParamsArray = true;
methodArg.paramsArrayType = paramArrayType;
argTypes.Add (methodArg);
currentLuaParam++;
} else if (currentNetParam.IsOptional)
paramList.Add (currentNetParam.DefaultValue);
else { // No match
isMethod = false;
break;
}
}
if (currentLuaParam != nLuaParams + 1) // Number of parameters does not match
isMethod = false;
if (isMethod) {
methodCache.args = paramList.ToArray ();
methodCache.cachedMethod = method;
methodCache.outList = outList.ToArray ();
methodCache.argTypes = argTypes.ToArray ();
}
return isMethod;
}
/// <summary>
/// CP: Fix for operator overloading failure
/// Returns true if the type is set and assigns the extract value
/// </summary>
/// <param name="luaState"></param>
/// <param name="currentLuaParam"></param>
/// <param name="currentNetParam"></param>
/// <param name="extractValue"></param>
/// <returns></returns>
private bool _IsTypeCorrect (LuaCore.lua_State luaState, int currentLuaParam, ParameterInfo currentNetParam, out ExtractValue extractValue)
{
try {
return (extractValue = translator.typeChecker.checkType (luaState, currentLuaParam, currentNetParam.ParameterType)) != null;
} catch {
extractValue = null;
Debug.WriteLine ("Type wasn't correct");
return false;
}
}
private bool _IsParamsArray (LuaCore.lua_State luaState, int currentLuaParam, ParameterInfo currentNetParam, out ExtractValue extractValue)
{
extractValue = null;
if (currentNetParam.GetCustomAttributes (typeof(ParamArrayAttribute), false).Length > 0) {
LuaTypes luaType;
try {
luaType = LuaLib.lua_type (luaState, currentLuaParam);
} catch (Exception ex) {
Debug.WriteLine ("Could not retrieve lua type while attempting to determine params Array Status.");
Debug.WriteLine (ex.Message);
extractValue = null;
return false;
}
if (luaType == LuaTypes.Table) {
try {
extractValue = translator.typeChecker.getExtractor (typeof(LuaTable));
} catch (Exception/* ex*/) {
Debug.WriteLine ("An error occurred during an attempt to retrieve a LuaTable extractor while checking for params array status.");
}
if (!extractValue.IsNull ()) {
return true;
}
} else {
var paramElementType = currentNetParam.ParameterType.GetElementType ();
try {
extractValue = translator.typeChecker.checkType (luaState, currentLuaParam, paramElementType);
} catch (Exception/* ex*/) {
Debug.WriteLine (string.Format ("An error occurred during an attempt to retrieve an extractor ({0}) while checking for params array status.", paramElementType.FullName));
}
if (!extractValue.IsNull ()) {
return true;
}
}
}
Debug.WriteLine ("Type wasn't Params object.");
return false;
}
}
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private static int callConstructor (LuaCore.lua_State luaState)
{
var translator = ObjectTranslatorPool.Instance.Find (luaState);
var instance = translator.MetaFunctionsInstance;
return instance.callConstructorInternal (luaState);
}
private int callConstructorInternal (LuaCore.lua_State luaState)
{
var validConstructor = new MethodCache ();
IReflect klass;
object obj = translator.getRawNetObject (luaState, 1);
if (obj.IsNull () || !(obj is IReflect)) {
translator.throwError (luaState, "trying to call constructor on an invalid type reference");
LuaLib.lua_pushnil (luaState);
return 1;
} else
klass = (IReflect)obj;
LuaLib.lua_remove (luaState, 1);
var constructors = klass.UnderlyingSystemType.GetConstructors ();
foreach (var constructor in constructors) {
bool isConstructor = matchParameters (luaState, constructor, ref validConstructor);
if (isConstructor) {
try {
translator.push (luaState, constructor.Invoke (validConstructor.args));
} catch (TargetInvocationException e) {
ThrowError (luaState, e);
LuaLib.lua_pushnil (luaState);
} catch {
LuaLib.lua_pushnil (luaState);
}
return 1;
}
}
string constructorName = (constructors.Length == 0) ? "unknown" : constructors [0].Name;
translator.throwError (luaState, String.Format ("{0} does not contain constructor({1}) argument match",
klass.UnderlyingSystemType, constructorName));
LuaLib.lua_pushnil (luaState);
return 1;
}
/*
* Matches a method against its arguments in the Lua stack. Returns
* if the match was succesful. It it was also returns the information
* necessary to invoke the method.
*/
internal bool matchParameters (LuaCore.lua_State luaState, MethodBase method, ref MethodCache methodCache)
{
ExtractValue extractValue;
bool isMethod = true;
var paramInfo = method.GetParameters ();
int currentLuaParam = 1;
int nLuaParams = LuaLib.lua_gettop (luaState);
var paramList = new ArrayList ();
var outList = new List<int> ();
var argTypes = new List<MethodArgs> ();
foreach (var currentNetParam in paramInfo) {
if (!currentNetParam.IsIn && currentNetParam.IsOut) // Skips out params
outList.Add (paramList.Add (null));
else if (currentLuaParam > nLuaParams) { // Adds optional parameters
if (currentNetParam.IsOptional)
paramList.Add (currentNetParam.DefaultValue);
else {
isMethod = false;
break;
}
} else if (_IsTypeCorrect (luaState, currentLuaParam, currentNetParam, out extractValue)) { // Type checking
int index = paramList.Add (extractValue (luaState, currentLuaParam));
var methodArg = new MethodArgs ();
methodArg.index = index;
methodArg.extractValue = extractValue;
argTypes.Add (methodArg);
if (currentNetParam.ParameterType.IsByRef)
outList.Add (index);
currentLuaParam++;
} // Type does not match, ignore if the parameter is optional
else if (_IsParamsArray (luaState, currentLuaParam, currentNetParam, out extractValue)) {
object luaParamValue = extractValue (luaState, currentLuaParam);
var paramArrayType = currentNetParam.ParameterType.GetElementType ();
Array paramArray;
if (luaParamValue is LuaTable) {
var table = (LuaTable)luaParamValue;
var tableEnumerator = table.GetEnumerator ();
paramArray = Array.CreateInstance (paramArrayType, table.Values.Count);
tableEnumerator.Reset ();
int paramArrayIndex = 0;
while (tableEnumerator.MoveNext()) {
paramArray.SetValue (Convert.ChangeType (tableEnumerator.Value, currentNetParam.ParameterType.GetElementType ()), paramArrayIndex);
paramArrayIndex++;
}
} else {
paramArray = Array.CreateInstance (paramArrayType, 1);
paramArray.SetValue (luaParamValue, 0);
}
int index = paramList.Add (paramArray);
var methodArg = new MethodArgs ();
methodArg.index = index;
methodArg.extractValue = extractValue;
methodArg.isParamsArray = true;
methodArg.paramsArrayType = paramArrayType;
argTypes.Add (methodArg);
currentLuaParam++;
} else if (currentNetParam.IsOptional)
paramList.Add (currentNetParam.DefaultValue);
else { // No match
isMethod = false;
break;
}
}
if (currentLuaParam != nLuaParams + 1) // Number of parameters does not match
isMethod = false;
if (isMethod) {
methodCache.args = paramList.ToArray ();
methodCache.cachedMethod = method;
methodCache.outList = outList.ToArray ();
methodCache.argTypes = argTypes.ToArray ();
}
return isMethod;
}
/// <summary>
/// CP: Fix for operator overloading failure
/// Returns true if the type is set and assigns the extract value
/// </summary>
/// <param name="luaState"></param>
/// <param name="currentLuaParam"></param>
/// <param name="currentNetParam"></param>
/// <param name="extractValue"></param>
/// <returns></returns>
private bool _IsTypeCorrect (LuaCore.lua_State luaState, int currentLuaParam, ParameterInfo currentNetParam, out ExtractValue extractValue)
{
try {
return (extractValue = translator.typeChecker.checkType (luaState, currentLuaParam, currentNetParam.ParameterType)) != null;
} catch {
extractValue = null;
Debug.WriteLine ("Type wasn't correct");
return false;
}
}
private bool _IsParamsArray (LuaCore.lua_State luaState, int currentLuaParam, ParameterInfo currentNetParam, out ExtractValue extractValue)
{
extractValue = null;
if (currentNetParam.GetCustomAttributes (typeof(ParamArrayAttribute), false).Length > 0) {
LuaTypes luaType;
try {
luaType = LuaLib.lua_type (luaState, currentLuaParam);
} catch (Exception ex) {
Debug.WriteLine ("Could not retrieve lua type while attempting to determine params Array Status.");
Debug.WriteLine (ex.Message);
extractValue = null;
return false;
}
if (luaType == LuaTypes.Table) {
try {
extractValue = translator.typeChecker.getExtractor (typeof(LuaTable));
} catch (Exception/* ex*/) {
Debug.WriteLine ("An error occurred during an attempt to retrieve a LuaTable extractor while checking for params array status.");
}
if (!extractValue.IsNull ()) {
return true;
}
} else {
var paramElementType = currentNetParam.ParameterType.GetElementType ();
try {
extractValue = translator.typeChecker.checkType (luaState, currentLuaParam, paramElementType);
} catch (Exception/* ex*/) {
Debug.WriteLine (string.Format ("An error occurred during an attempt to retrieve an extractor ({0}) while checking for params array status.", paramElementType.FullName));
}
if (!extractValue.IsNull ()) {
return true;
}
}
}
Debug.WriteLine ("Type wasn't Params object.");
return false;
}
}
}
\ No newline at end of file
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
using System.Reflection;
using System.Collections.Generic;
using LuaInterface.Exceptions;
using LuaInterface.Extensions;
namespace LuaInterface.Method
{
using LuaCore = KeraLua.Lua;
/*
* Argument extraction with type-conversion function
*/
delegate object ExtractValue (LuaCore.lua_State luaState, int stackPos);
/*
* Wrapper class for methods/constructors accessed from Lua.
*
* Author: Fabio Mascarenhas
* Version: 1.0
*/
class LuaMethodWrapper
{
internal LuaCore.lua_CFunction invokeFunction;
private ObjectTranslator _Translator;
private MethodBase _Method;
private MethodCache _LastCalledMethod = new MethodCache ();
private string _MethodName;
private MemberInfo[] _Members;
private ExtractValue _ExtractTarget;
private object _Target;
private BindingFlags _BindingType;
/*
* Constructs the wrapper for a known MethodBase instance
*/
public LuaMethodWrapper (ObjectTranslator translator, object target, IReflect targetType, MethodBase method)
{
invokeFunction = new LuaCore.lua_CFunction (this.call);
_Translator = translator;
_Target = target;
if (!targetType.IsNull ())
_ExtractTarget = translator.typeChecker.getExtractor (targetType);
_Method = method;
_MethodName = method.Name;
if (method.IsStatic)
_BindingType = BindingFlags.Static;
else
_BindingType = BindingFlags.Instance;
}
/*
* Constructs the wrapper for a known method name
*/
public LuaMethodWrapper (ObjectTranslator translator, IReflect targetType, string methodName, BindingFlags bindingType)
{
invokeFunction = new LuaCore.lua_CFunction (this.call);
_Translator = translator;
_MethodName = methodName;
if (!targetType.IsNull ())
_ExtractTarget = translator.typeChecker.getExtractor (targetType);
_BindingType = bindingType;
//CP: Removed NonPublic binding search and added IgnoreCase
_Members = targetType.UnderlyingSystemType.GetMember (methodName, MemberTypes.Method, bindingType | BindingFlags.Public | BindingFlags.IgnoreCase/*|BindingFlags.NonPublic*/);
}
/// <summary>
/// Convert C# exceptions into Lua errors
/// </summary>
/// <returns>num of things on stack</returns>
/// <param name="e">null for no pending exception</param>
int SetPendingException (Exception e)
{
return _Translator.interpreter.SetPendingException (e);
}
/*
* Calls the method. Receives the arguments from the Lua stack
* and returns values in it.
*/
#if MONOTOUCH
[MonoTouch.MonoPInvokeCallback (typeof (LuaCore.lua_CFunction))]
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
int call (LuaCore.lua_State luaState)
{
var methodToCall = _Method;
object targetObject = _Target;
bool failedCall = true;
int nReturnValues = 0;
if (!LuaLib.lua_checkstack (luaState, 5))
throw new LuaException ("Lua stack overflow");
bool isStatic = (_BindingType & BindingFlags.Static) == BindingFlags.Static;
SetPendingException (null);
if (methodToCall.IsNull ()) { // Method from name
if (isStatic)
targetObject = null;
else
targetObject = _ExtractTarget (luaState, 1);
//LuaLib.lua_remove(luaState,1); // Pops the receiver
if (!_LastCalledMethod.cachedMethod.IsNull ()) { // Cached?
int numStackToSkip = isStatic ? 0 : 1; // If this is an instance invoe we will have an extra arg on the stack for the targetObject
int numArgsPassed = LuaLib.lua_gettop (luaState) - numStackToSkip;
if (numArgsPassed == _LastCalledMethod.argTypes.Length) { // No. of args match?
if (!LuaLib.lua_checkstack (luaState, _LastCalledMethod.outList.Length + 6))
throw new LuaException ("Lua stack overflow");
try {
for (int i = 0; i < _LastCalledMethod.argTypes.Length; i++) {
if (_LastCalledMethod.argTypes [i].isParamsArray) {
object luaParamValue = _LastCalledMethod.argTypes [i].extractValue (luaState, i + 1 + numStackToSkip);
var paramArrayType = _LastCalledMethod.argTypes [i].paramsArrayType;
Array paramArray;
if (luaParamValue is LuaTable) {
var table = (LuaTable)luaParamValue;
paramArray = Array.CreateInstance (paramArrayType, table.Values.Count);
for (int x = 1; x <= table.Values.Count; x++)
paramArray.SetValue (Convert.ChangeType (table [x], paramArrayType), x - 1);
} else {
paramArray = Array.CreateInstance (paramArrayType, 1);
paramArray.SetValue (luaParamValue, 0);
}
_LastCalledMethod.args [_LastCalledMethod.argTypes [i].index] = paramArray;
} else {
_LastCalledMethod.args [_LastCalledMethod.argTypes [i].index] =
_LastCalledMethod.argTypes [i].extractValue (luaState, i + 1 + numStackToSkip);
}
if (_LastCalledMethod.args [_LastCalledMethod.argTypes [i].index] == null &&
!LuaLib.lua_isnil (luaState, i + 1 + numStackToSkip))
throw new LuaException ("argument number " + (i + 1) + " is invalid");
}
if ((_BindingType & BindingFlags.Static) == BindingFlags.Static)
_Translator.push (luaState, _LastCalledMethod.cachedMethod.Invoke (null, _LastCalledMethod.args));
else {
if (_LastCalledMethod.cachedMethod.IsConstructor)
_Translator.push (luaState, ((ConstructorInfo)_LastCalledMethod.cachedMethod).Invoke (_LastCalledMethod.args));
else
_Translator.push (luaState, _LastCalledMethod.cachedMethod.Invoke (targetObject, _LastCalledMethod.args));
}
failedCall = false;
} catch (TargetInvocationException e) {
// Failure of method invocation
return SetPendingException (e.GetBaseException ());
} catch (Exception e) {
if (_Members.Length == 1) // Is the method overloaded?
// No, throw error
return SetPendingException (e);
}
}
}
// Cache miss
if (failedCall) {
// System.Diagnostics.Debug.WriteLine("cache miss on " + methodName);
// If we are running an instance variable, we can now pop the targetObject from the stack
if (!isStatic) {
if (targetObject.IsNull ()) {
_Translator.throwError (luaState, String.Format ("instance method '{0}' requires a non null target object", _MethodName));
LuaLib.lua_pushnil (luaState);
return 1;
}
LuaLib.lua_remove (luaState, 1); // Pops the receiver
}
bool hasMatch = false;
string candidateName = null;
foreach (var member in _Members) {
candidateName = member.ReflectedType.Name + "." + member.Name;
var m = (MethodInfo)member;
bool isMethod = _Translator.matchParameters (luaState, m, ref _LastCalledMethod);
if (isMethod) {
hasMatch = true;
break;
}
}
if (!hasMatch) {
string msg = (candidateName == null) ? "invalid arguments to method call" : ("invalid arguments to method: " + candidateName);
_Translator.throwError (luaState, msg);
LuaLib.lua_pushnil (luaState);
return 1;
}
}
} else { // Method from MethodBase instance
if (methodToCall.ContainsGenericParameters) {
/*bool isMethod = */
_Translator.matchParameters (luaState, methodToCall, ref _LastCalledMethod);
if (methodToCall.IsGenericMethodDefinition) {
//need to make a concrete type of the generic method definition
var typeArgs = new List<Type> ();
foreach (object arg in _LastCalledMethod.args)
typeArgs.Add (arg.GetType ());
var concreteMethod = (methodToCall as MethodInfo).MakeGenericMethod (typeArgs.ToArray ());
_Translator.push (luaState, concreteMethod.Invoke (targetObject, _LastCalledMethod.args));
failedCall = false;
} else if (methodToCall.ContainsGenericParameters) {
_Translator.throwError (luaState, "unable to invoke method on generic class as the current method is an open generic method");
LuaLib.lua_pushnil (luaState);
return 1;
}
} else {
if (!methodToCall.IsStatic && !methodToCall.IsConstructor && targetObject == null) {
targetObject = _ExtractTarget (luaState, 1);
LuaLib.lua_remove (luaState, 1); // Pops the receiver
}
if (!_Translator.matchParameters (luaState, methodToCall, ref _LastCalledMethod)) {
_Translator.throwError (luaState, "invalid arguments to method call");
LuaLib.lua_pushnil (luaState);
return 1;
}
}
}
if (failedCall) {
if (!LuaLib.lua_checkstack (luaState, _LastCalledMethod.outList.Length + 6))
throw new LuaException ("Lua stack overflow");
try {
if (isStatic)
_Translator.push (luaState, _LastCalledMethod.cachedMethod.Invoke (null, _LastCalledMethod.args));
else {
if (_LastCalledMethod.cachedMethod.IsConstructor)
_Translator.push (luaState, ((ConstructorInfo)_LastCalledMethod.cachedMethod).Invoke (_LastCalledMethod.args));
else
_Translator.push (luaState, _LastCalledMethod.cachedMethod.Invoke (targetObject, _LastCalledMethod.args));
}
} catch (TargetInvocationException e) {
return SetPendingException (e.GetBaseException ());
} catch (Exception e) {
return SetPendingException (e);
}
}
// Pushes out and ref return values
for (int index = 0; index < _LastCalledMethod.outList.Length; index++) {
nReturnValues++;
//for(int i=0;i<lastCalledMethod.outList.Length;i++)
_Translator.push (luaState, _LastCalledMethod.args [_LastCalledMethod.outList [index]]);
}
//by isSingle 2010-09-10 11:26:31
//Desc:
// if not return void,we need add 1,
// or we will lost the function's return value
// when call dotnet function like "int foo(arg1,out arg2,out arg3)" in lua code
if (!_LastCalledMethod.IsReturnVoid && nReturnValues > 0)
nReturnValues++;
return nReturnValues < 1 ? 1 : nReturnValues;
}
}
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
using System.Reflection;
using System.Collections.Generic;
using LuaInterface.Exceptions;
using LuaInterface.Extensions;
namespace LuaInterface.Method
{
#if USE_KOPILUA
using LuaCore = KopiLua.Lua;
#else
using LuaCore = KeraLua.Lua;
#endif
/*
* Argument extraction with type-conversion function
*/
delegate object ExtractValue (LuaCore.lua_State luaState, int stackPos);
/*
* Wrapper class for methods/constructors accessed from Lua.
*
* Author: Fabio Mascarenhas
* Version: 1.0
*/
class LuaMethodWrapper
{
internal LuaCore.lua_CFunction invokeFunction;
private ObjectTranslator _Translator;
private MethodBase _Method;
private MethodCache _LastCalledMethod = new MethodCache ();
private string _MethodName;
private MemberInfo[] _Members;
private ExtractValue _ExtractTarget;
private object _Target;
private BindingFlags _BindingType;
/*
* Constructs the wrapper for a known MethodBase instance
*/
public LuaMethodWrapper (ObjectTranslator translator, object target, IReflect targetType, MethodBase method)
{
invokeFunction = new LuaCore.lua_CFunction (this.call);
_Translator = translator;
_Target = target;
if (!targetType.IsNull ())
_ExtractTarget = translator.typeChecker.getExtractor (targetType);
_Method = method;
_MethodName = method.Name;
if (method.IsStatic)
_BindingType = BindingFlags.Static;
else
_BindingType = BindingFlags.Instance;
}
/*
* Constructs the wrapper for a known method name
*/
public LuaMethodWrapper (ObjectTranslator translator, IReflect targetType, string methodName, BindingFlags bindingType)
{
invokeFunction = new LuaCore.lua_CFunction (this.call);
_Translator = translator;
_MethodName = methodName;
if (!targetType.IsNull ())
_ExtractTarget = translator.typeChecker.getExtractor (targetType);
_BindingType = bindingType;
//CP: Removed NonPublic binding search and added IgnoreCase
_Members = targetType.UnderlyingSystemType.GetMember (methodName, MemberTypes.Method, bindingType | BindingFlags.Public | BindingFlags.IgnoreCase/*|BindingFlags.NonPublic*/);
}
/// <summary>
/// Convert C# exceptions into Lua errors
/// </summary>
/// <returns>num of things on stack</returns>
/// <param name="e">null for no pending exception</param>
int SetPendingException (Exception e)
{
return _Translator.interpreter.SetPendingException (e);
}
/*
* Calls the method. Receives the arguments from the Lua stack
* and returns values in it.
*/
int call (LuaCore.lua_State luaState)
{
var methodToCall = _Method;
object targetObject = _Target;
bool failedCall = true;
int nReturnValues = 0;
if (!LuaLib.lua_checkstack (luaState, 5))
throw new LuaException ("Lua stack overflow");
bool isStatic = (_BindingType & BindingFlags.Static) == BindingFlags.Static;
SetPendingException (null);
if (methodToCall.IsNull ()) { // Method from name
if (isStatic)
targetObject = null;
else
targetObject = _ExtractTarget (luaState, 1);
//LuaLib.lua_remove(luaState,1); // Pops the receiver
if (!_LastCalledMethod.cachedMethod.IsNull ()) { // Cached?
int numStackToSkip = isStatic ? 0 : 1; // If this is an instance invoe we will have an extra arg on the stack for the targetObject
int numArgsPassed = LuaLib.lua_gettop (luaState) - numStackToSkip;
if (numArgsPassed == _LastCalledMethod.argTypes.Length) { // No. of args match?
if (!LuaLib.lua_checkstack (luaState, _LastCalledMethod.outList.Length + 6))
throw new LuaException ("Lua stack overflow");
try {
for (int i = 0; i < _LastCalledMethod.argTypes.Length; i++) {
if (_LastCalledMethod.argTypes [i].isParamsArray) {
object luaParamValue = _LastCalledMethod.argTypes [i].extractValue (luaState, i + 1 + numStackToSkip);
var paramArrayType = _LastCalledMethod.argTypes [i].paramsArrayType;
Array paramArray;
if (luaParamValue is LuaTable) {
var table = (LuaTable)luaParamValue;
paramArray = Array.CreateInstance (paramArrayType, table.Values.Count);
for (int x = 1; x <= table.Values.Count; x++)
paramArray.SetValue (Convert.ChangeType (table [x], paramArrayType), x - 1);
} else {
paramArray = Array.CreateInstance (paramArrayType, 1);
paramArray.SetValue (luaParamValue, 0);
}
_LastCalledMethod.args [_LastCalledMethod.argTypes [i].index] = paramArray;
} else {
_LastCalledMethod.args [_LastCalledMethod.argTypes [i].index] =
_LastCalledMethod.argTypes [i].extractValue (luaState, i + 1 + numStackToSkip);
}
if (_LastCalledMethod.args [_LastCalledMethod.argTypes [i].index] == null &&
!LuaLib.lua_isnil (luaState, i + 1 + numStackToSkip))
throw new LuaException ("argument number " + (i + 1) + " is invalid");
}
if ((_BindingType & BindingFlags.Static) == BindingFlags.Static)
_Translator.push (luaState, _LastCalledMethod.cachedMethod.Invoke (null, _LastCalledMethod.args));
else {
if (_LastCalledMethod.cachedMethod.IsConstructor)
_Translator.push (luaState, ((ConstructorInfo)_LastCalledMethod.cachedMethod).Invoke (_LastCalledMethod.args));
else
_Translator.push (luaState, _LastCalledMethod.cachedMethod.Invoke (targetObject, _LastCalledMethod.args));
}
failedCall = false;
} catch (TargetInvocationException e) {
// Failure of method invocation
return SetPendingException (e.GetBaseException ());
} catch (Exception e) {
if (_Members.Length == 1) // Is the method overloaded?
// No, throw error
return SetPendingException (e);
}
}
}
// Cache miss
if (failedCall) {
// System.Diagnostics.Debug.WriteLine("cache miss on " + methodName);
// If we are running an instance variable, we can now pop the targetObject from the stack
if (!isStatic) {
if (targetObject.IsNull ()) {
_Translator.throwError (luaState, String.Format ("instance method '{0}' requires a non null target object", _MethodName));
LuaLib.lua_pushnil (luaState);
return 1;
}
LuaLib.lua_remove (luaState, 1); // Pops the receiver
}
bool hasMatch = false;
string candidateName = null;
foreach (var member in _Members) {
candidateName = member.ReflectedType.Name + "." + member.Name;
var m = (MethodInfo)member;
bool isMethod = _Translator.matchParameters (luaState, m, ref _LastCalledMethod);
if (isMethod) {
hasMatch = true;
break;
}
}
if (!hasMatch) {
string msg = (candidateName == null) ? "invalid arguments to method call" : ("invalid arguments to method: " + candidateName);
_Translator.throwError (luaState, msg);
LuaLib.lua_pushnil (luaState);
return 1;
}
}
} else { // Method from MethodBase instance
if (methodToCall.ContainsGenericParameters) {
/*bool isMethod = */
_Translator.matchParameters (luaState, methodToCall, ref _LastCalledMethod);
if (methodToCall.IsGenericMethodDefinition) {
//need to make a concrete type of the generic method definition
var typeArgs = new List<Type> ();
foreach (object arg in _LastCalledMethod.args)
typeArgs.Add (arg.GetType ());
var concreteMethod = (methodToCall as MethodInfo).MakeGenericMethod (typeArgs.ToArray ());
_Translator.push (luaState, concreteMethod.Invoke (targetObject, _LastCalledMethod.args));
failedCall = false;
} else if (methodToCall.ContainsGenericParameters) {
_Translator.throwError (luaState, "unable to invoke method on generic class as the current method is an open generic method");
LuaLib.lua_pushnil (luaState);
return 1;
}
} else {
if (!methodToCall.IsStatic && !methodToCall.IsConstructor && targetObject == null) {
targetObject = _ExtractTarget (luaState, 1);
LuaLib.lua_remove (luaState, 1); // Pops the receiver
}
if (!_Translator.matchParameters (luaState, methodToCall, ref _LastCalledMethod)) {
_Translator.throwError (luaState, "invalid arguments to method call");
LuaLib.lua_pushnil (luaState);
return 1;
}
}
}
if (failedCall) {
if (!LuaLib.lua_checkstack (luaState, _LastCalledMethod.outList.Length + 6))
throw new LuaException ("Lua stack overflow");
try {
if (isStatic)
_Translator.push (luaState, _LastCalledMethod.cachedMethod.Invoke (null, _LastCalledMethod.args));
else {
if (_LastCalledMethod.cachedMethod.IsConstructor)
_Translator.push (luaState, ((ConstructorInfo)_LastCalledMethod.cachedMethod).Invoke (_LastCalledMethod.args));
else
_Translator.push (luaState, _LastCalledMethod.cachedMethod.Invoke (targetObject, _LastCalledMethod.args));
}
} catch (TargetInvocationException e) {
return SetPendingException (e.GetBaseException ());
} catch (Exception e) {
return SetPendingException (e);
}
}
// Pushes out and ref return values
for (int index = 0; index < _LastCalledMethod.outList.Length; index++) {
nReturnValues++;
//for(int i=0;i<lastCalledMethod.outList.Length;i++)
_Translator.push (luaState, _LastCalledMethod.args [_LastCalledMethod.outList [index]]);
}
//by isSingle 2010-09-10 11:26:31
//Desc:
// if not return void,we need add 1,
// or we will lost the function's return value
// when call dotnet function like "int foo(arg1,out arg2,out arg3)" in lua code
if (!_LastCalledMethod.IsReturnVoid && nReturnValues > 0)
nReturnValues++;
return nReturnValues < 1 ? 1 : nReturnValues;
}
}
}
\ No newline at end of file
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
using System.IO;
using System.Reflection;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
using LuaInterface.Method;
using LuaInterface.Exceptions;
using LuaInterface.Extensions;
namespace LuaInterface
{
using LuaCore = KeraLua.Lua;
/*
* Passes objects from the CLR to Lua and vice-versa
*
* Author: Fabio Mascarenhas
* Version: 1.0
*/
public class ObjectTranslator
{
private LuaCore.lua_CFunction registerTableFunction, unregisterTableFunction, getMethodSigFunction,
getConstructorSigFunction, importTypeFunction, loadAssemblyFunction;
// object to object #
public readonly Dictionary<object, int> objectsBackMap = new Dictionary<object, int> ();
// object # to object (FIXME - it should be possible to get object address as an object #)
public readonly Dictionary<int, object> objects = new Dictionary<int, object> ();
internal EventHandlerContainer pendingEvents = new EventHandlerContainer ();
private MetaFunctions metaFunctions;
private List<Assembly> assemblies;
internal CheckType typeChecker;
internal Lua interpreter;
/// <summary>
/// We want to ensure that objects always have a unique ID
/// </summary>
private int nextObj = 0;
public ObjectTranslator (Lua interpreter, LuaCore.lua_State luaState)
{
this.interpreter = interpreter;
typeChecker = new CheckType (this);
metaFunctions = new MetaFunctions (this);
assemblies = new List<Assembly> ();
importTypeFunction = new LuaCore.lua_CFunction (this.importType);
loadAssemblyFunction = new LuaCore.lua_CFunction (this.loadAssembly);
registerTableFunction = new LuaCore.lua_CFunction (this.registerTable);
unregisterTableFunction = new LuaCore.lua_CFunction (this.unregisterTable);
getMethodSigFunction = new LuaCore.lua_CFunction (this.getMethodSignature);
getConstructorSigFunction = new LuaCore.lua_CFunction (this.getConstructorSignature);
createLuaObjectList (luaState);
createIndexingMetaFunction (luaState);
createBaseClassMetatable (luaState);
createClassMetatable (luaState);
createFunctionMetatable (luaState);
setGlobalFunctions (luaState);
}
/*
* Sets up the list of objects in the Lua side
*/
private void createLuaObjectList (LuaCore.lua_State luaState)
{
LuaLib.lua_pushstring (luaState, "luaNet_objects");
LuaLib.lua_newtable (luaState);
LuaLib.lua_newtable (luaState);
LuaLib.lua_pushstring (luaState, "__mode");
LuaLib.lua_pushstring (luaState, "v");
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_setmetatable (luaState, -2);
LuaLib.lua_settable (luaState, (int)LuaIndexes.Registry);
}
/*
* Registers the indexing function of CLR objects
* passed to Lua
*/
private void createIndexingMetaFunction (LuaCore.lua_State luaState)
{
LuaLib.lua_pushstring (luaState, "luaNet_indexfunction");
LuaLib.luaL_dostring (luaState, MetaFunctions.luaIndexFunction); // steffenj: lua_dostring renamed to luaL_dostring
//LuaLib.lua_pushstdcallcfunction(luaState, indexFunction);
LuaLib.lua_rawset (luaState, (int)LuaIndexes.Registry);
}
/*
* Creates the metatable for superclasses (the base
* field of registered tables)
*/
private void createBaseClassMetatable (LuaCore.lua_State luaState)
{
LuaLib.luaL_newmetatable (luaState, "luaNet_searchbase");
LuaLib.lua_pushstring (luaState, "__gc");
LuaLib.lua_pushstdcallcfunction (luaState, metaFunctions.gcFunction);
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_pushstring (luaState, "__tostring");
LuaLib.lua_pushstdcallcfunction (luaState, metaFunctions.toStringFunction);
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_pushstring (luaState, "__index");
LuaLib.lua_pushstdcallcfunction (luaState, metaFunctions.baseIndexFunction);
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_pushstring (luaState, "__newindex");
LuaLib.lua_pushstdcallcfunction (luaState, metaFunctions.newindexFunction);
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_settop (luaState, -2);
}
/*
* Creates the metatable for type references
*/
private void createClassMetatable (LuaCore.lua_State luaState)
{
LuaLib.luaL_newmetatable (luaState, "luaNet_class");
LuaLib.lua_pushstring (luaState, "__gc");
LuaLib.lua_pushstdcallcfunction (luaState, metaFunctions.gcFunction);
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_pushstring (luaState, "__tostring");
LuaLib.lua_pushstdcallcfunction (luaState, metaFunctions.toStringFunction);
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_pushstring (luaState, "__index");
LuaLib.lua_pushstdcallcfunction (luaState, metaFunctions.classIndexFunction);
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_pushstring (luaState, "__newindex");
LuaLib.lua_pushstdcallcfunction (luaState, metaFunctions.classNewindexFunction);
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_pushstring (luaState, "__call");
LuaLib.lua_pushstdcallcfunction (luaState, metaFunctions.callConstructorFunction);
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_settop (luaState, -2);
}
/*
* Registers the global functions used by LuaInterface
*/
private void setGlobalFunctions (LuaCore.lua_State luaState)
{
LuaLib.lua_pushstdcallcfunction (luaState, metaFunctions.indexFunction);
LuaLib.lua_setglobal (luaState, "get_object_member");
LuaLib.lua_pushstdcallcfunction (luaState, importTypeFunction);
LuaLib.lua_setglobal (luaState, "import_type");
LuaLib.lua_pushstdcallcfunction (luaState, loadAssemblyFunction);
LuaLib.lua_setglobal (luaState, "load_assembly");
LuaLib.lua_pushstdcallcfunction (luaState, registerTableFunction);
LuaLib.lua_setglobal (luaState, "make_object");
LuaLib.lua_pushstdcallcfunction (luaState, unregisterTableFunction);
LuaLib.lua_setglobal (luaState, "free_object");
LuaLib.lua_pushstdcallcfunction (luaState, getMethodSigFunction);
LuaLib.lua_setglobal (luaState, "get_method_bysig");
LuaLib.lua_pushstdcallcfunction (luaState, getConstructorSigFunction);
LuaLib.lua_setglobal (luaState, "get_constructor_bysig");
}
/*
* Creates the metatable for delegates
*/
private void createFunctionMetatable (LuaCore.lua_State luaState)
{
LuaLib.luaL_newmetatable (luaState, "luaNet_function");
LuaLib.lua_pushstring (luaState, "__gc");
LuaLib.lua_pushstdcallcfunction (luaState, metaFunctions.gcFunction);
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_pushstring (luaState, "__call");
LuaLib.lua_pushstdcallcfunction (luaState, metaFunctions.execDelegateFunction);
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_settop (luaState, -2);
}
/*
* Passes errors (argument e) to the Lua interpreter
*/
internal void throwError (LuaCore.lua_State luaState, object e)
{
// We use this to remove anything pushed by luaL_where
int oldTop = LuaLib.lua_gettop (luaState);
// Stack frame #1 is our C# wrapper, so not very interesting to the user
// Stack frame #2 must be the lua code that called us, so that's what we want to use
LuaLib.luaL_where (luaState, 1);
var curlev = popValues (luaState, oldTop);
// Determine the position in the script where the exception was triggered
string errLocation = string.Empty;
if (curlev.Length > 0)
errLocation = curlev [0].ToString ();
string message = e as string;
if (!message.IsNull ()) {
// Wrap Lua error (just a string) and store the error location
e = new LuaScriptException (message, errLocation);
} else {
var ex = e as Exception;
if (!ex.IsNull ()) {
// Wrap generic .NET exception as an InnerException and store the error location
e = new LuaScriptException (ex, errLocation);
}
}
push (luaState, e);
LuaLib.lua_error (luaState);
}
/*
* Implementation of load_assembly. Throws an error
* if the assembly is not found.
*/
/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax <http://megax.yeahunter.hu/>
*
* 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.
*/
using System;
using System.IO;
using System.Reflection;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
using LuaInterface.Method;
using LuaInterface.Exceptions;
using LuaInterface.Extensions;
namespace LuaInterface
{
#if USE_KOPILUA
using LuaCore = KopiLua.Lua;
#else
using LuaCore = KeraLua.Lua;
#endif
/*
* Passes objects from the CLR to Lua and vice-versa
*
* Author: Fabio Mascarenhas
* Version: 1.0
*/
public class ObjectTranslator
{
private LuaCore.lua_CFunction registerTableFunction, unregisterTableFunction, getMethodSigFunction,
getConstructorSigFunction, importTypeFunction, loadAssemblyFunction;
// object to object #
public readonly Dictionary<object, int> objectsBackMap = new Dictionary<object, int> ();
// object # to object (FIXME - it should be possible to get object address as an object #)
public readonly Dictionary<int, object> objects = new Dictionary<int, object> ();
internal EventHandlerContainer pendingEvents = new EventHandlerContainer ();
private MetaFunctions metaFunctions;
private List<Assembly> assemblies;
internal CheckType typeChecker;
internal Lua interpreter;
/// <summary>
/// We want to ensure that objects always have a unique ID
/// </summary>
private int nextObj = 0;
public MetaFunctions MetaFunctionsInstance {
get {
return metaFunctions;
}
}
public Lua Interpreter {
get {
return interpreter;
}
}
public ObjectTranslator (Lua interpreter, LuaCore.lua_State luaState)
{
this.interpreter = interpreter;
typeChecker = new CheckType (this);
metaFunctions = new MetaFunctions (this);
assemblies = new List<Assembly> ();
importTypeFunction = new LuaCore.lua_CFunction (ObjectTranslator.importType);
loadAssemblyFunction = new LuaCore.lua_CFunction (ObjectTranslator.loadAssembly);
registerTableFunction = new LuaCore.lua_CFunction (ObjectTranslator.registerTable);
unregisterTableFunction = new LuaCore.lua_CFunction (ObjectTranslator.unregisterTable);
getMethodSigFunction = new LuaCore.lua_CFunction (ObjectTranslator.getMethodSignature);
getConstructorSigFunction = new LuaCore.lua_CFunction (ObjectTranslator.getConstructorSignature);
createLuaObjectList (luaState);
createIndexingMetaFunction (luaState);
createBaseClassMetatable (luaState);
createClassMetatable (luaState);
createFunctionMetatable (luaState);
setGlobalFunctions (luaState);
}
/*
* Sets up the list of objects in the Lua side
*/
private void createLuaObjectList (LuaCore.lua_State luaState)
{
LuaLib.lua_pushstring (luaState, "luaNet_objects");
LuaLib.lua_newtable (luaState);
LuaLib.lua_newtable (luaState);
LuaLib.lua_pushstring (luaState, "__mode");
LuaLib.lua_pushstring (luaState, "v");
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_setmetatable (luaState, -2);
LuaLib.lua_settable (luaState, (int)LuaIndexes.Registry);
}
/*
* Registers the indexing function of CLR objects
* passed to Lua
*/
private void createIndexingMetaFunction (LuaCore.lua_State luaState)
{
LuaLib.lua_pushstring (luaState, "luaNet_indexfunction");
LuaLib.luaL_dostring (luaState, MetaFunctions.luaIndexFunction); // steffenj: lua_dostring renamed to luaL_dostring
//LuaLib.lua_pushstdcallcfunction(luaState, indexFunction);
LuaLib.lua_rawset (luaState, (int)LuaIndexes.Registry);
}
/*
* Creates the metatable for superclasses (the base
* field of registered tables)
*/
private void createBaseClassMetatable (LuaCore.lua_State luaState)
{
LuaLib.luaL_newmetatable (luaState, "luaNet_searchbase");
LuaLib.lua_pushstring (luaState, "__gc");
LuaLib.lua_pushstdcallcfunction (luaState, metaFunctions.gcFunction);
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_pushstring (luaState, "__tostring");
LuaLib.lua_pushstdcallcfunction (luaState, metaFunctions.toStringFunction);
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_pushstring (luaState, "__index");
LuaLib.lua_pushstdcallcfunction (luaState, metaFunctions.baseIndexFunction);
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_pushstring (luaState, "__newindex");
LuaLib.lua_pushstdcallcfunction (luaState, metaFunctions.newindexFunction);
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_settop (luaState, -2);
}
/*
* Creates the metatable for type references
*/
private void createClassMetatable (LuaCore.lua_State luaState)
{
LuaLib.luaL_newmetatable (luaState, "luaNet_class");
LuaLib.lua_pushstring (luaState, "__gc");
LuaLib.lua_pushstdcallcfunction (luaState, metaFunctions.gcFunction);
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_pushstring (luaState, "__tostring");
LuaLib.lua_pushstdcallcfunction (luaState, metaFunctions.toStringFunction);
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_pushstring (luaState, "__index");
LuaLib.lua_pushstdcallcfunction (luaState, metaFunctions.classIndexFunction);
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_pushstring (luaState, "__newindex");
LuaLib.lua_pushstdcallcfunction (luaState, metaFunctions.classNewindexFunction);
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_pushstring (luaState, "__call");
LuaLib.lua_pushstdcallcfunction (luaState, metaFunctions.callConstructorFunction);
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_settop (luaState, -2);
}
/*
* Registers the global functions used by LuaInterface
*/
private void setGlobalFunctions (LuaCore.lua_State luaState)
{
LuaLib.lua_pushstdcallcfunction (luaState, metaFunctions.indexFunction);
LuaLib.lua_setglobal (luaState, "get_object_member");
LuaLib.lua_pushstdcallcfunction (luaState, importTypeFunction);
LuaLib.lua_setglobal (luaState, "import_type");
LuaLib.lua_pushstdcallcfunction (luaState, loadAssemblyFunction);
LuaLib.lua_setglobal (luaState, "load_assembly");
LuaLib.lua_pushstdcallcfunction (luaState, registerTableFunction);
LuaLib.lua_setglobal (luaState, "make_object");
LuaLib.lua_pushstdcallcfunction (luaState, unregisterTableFunction);
LuaLib.lua_setglobal (luaState, "free_object");
LuaLib.lua_pushstdcallcfunction (luaState, getMethodSigFunction);
LuaLib.lua_setglobal (luaState, "get_method_bysig");
LuaLib.lua_pushstdcallcfunction (luaState, getConstructorSigFunction);
LuaLib.lua_setglobal (luaState, "get_constructor_bysig");
}
/*
* Creates the metatable for delegates
*/
private void createFunctionMetatable (LuaCore.lua_State luaState)
{
LuaLib.luaL_newmetatable (luaState, "luaNet_function");
LuaLib.lua_pushstring (luaState, "__gc");
LuaLib.lua_pushstdcallcfunction (luaState, metaFunctions.gcFunction);
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_pushstring (luaState, "__call");
LuaLib.lua_pushstdcallcfunction (luaState, metaFunctions.execDelegateFunction);
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_settop (luaState, -2);
}
/*
* Passes errors (argument e) to the Lua interpreter
*/
internal void throwError (LuaCore.lua_State luaState, object e)
{
// We use this to remove anything pushed by luaL_where
int oldTop = LuaLib.lua_gettop (luaState);
// Stack frame #1 is our C# wrapper, so not very interesting to the user
// Stack frame #2 must be the lua code that called us, so that's what we want to use
LuaLib.luaL_where (luaState, 1);
var curlev = popValues (luaState, oldTop);
// Determine the position in the script where the exception was triggered
string errLocation = string.Empty;
if (curlev.Length > 0)
errLocation = curlev [0].ToString ();
string message = e as string;
if (!message.IsNull ()) {
// Wrap Lua error (just a string) and store the error location
e = new LuaScriptException (message, errLocation);
} else {
var ex = e as Exception;
if (!ex.IsNull ()) {
// Wrap generic .NET exception as an InnerException and store the error location
e = new LuaScriptException (ex, errLocation);
}
}
push (luaState, e);
LuaLib.lua_error (luaState);
}
/*
* Implementation of load_assembly. Throws an error
* if the assembly is not found.
*/
#if MONOTOUCH
[MonoTouch.MonoPInvokeCallback (typeof (LuaCore.lua_CFunction))]
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private int loadAssembly (LuaCore.lua_State luaState)
{
try {
string assemblyName = LuaLib.lua_tostring (luaState, 1).ToString ();
Assembly assembly = null;
try {
assembly = Assembly.Load (assemblyName);
} catch (BadImageFormatException) {
// The assemblyName was invalid. It is most likely a path.
}
if (assembly.IsNull ())
assembly = Assembly.Load (AssemblyName.GetAssemblyName (assemblyName));
if (!assembly.IsNull () && !assemblies.Contains (assembly))
assemblies.Add (assembly);
} catch (Exception e) {
throwError (luaState, e);
}
return 0;
}
internal Type FindType (string className)
{
foreach (var assembly in assemblies) {
var klass = assembly.GetType (className);
if (!klass.IsNull ())
return klass;
}
return null;
}
/*
* Implementation of import_type. Returns nil if the
* type is not found.
*/
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private static int loadAssembly (LuaCore.lua_State luaState)
{
var translator = ObjectTranslatorPool.Instance.Find (luaState);
return translator.loadAssemblyInternal (luaState);
}
private int loadAssemblyInternal (LuaCore.lua_State luaState)
{
try {
string assemblyName = LuaLib.lua_tostring (luaState, 1).ToString ();
Assembly assembly = null;
try {
assembly = Assembly.Load (assemblyName);
} catch (BadImageFormatException) {
// The assemblyName was invalid. It is most likely a path.
}
if (assembly.IsNull ())
assembly = Assembly.Load (AssemblyName.GetAssemblyName (assemblyName));
if (!assembly.IsNull () && !assemblies.Contains (assembly))
assemblies.Add (assembly);
} catch (Exception e) {
throwError (luaState, e);
}
return 0;
}
internal Type FindType (string className)
{
foreach (var assembly in assemblies) {
var klass = assembly.GetType (className);
if (!klass.IsNull ())
return klass;
}
return null;
}
/*
* Implementation of import_type. Returns nil if the
* type is not found.
*/
#if MONOTOUCH
[MonoTouch.MonoPInvokeCallback (typeof (LuaCore.lua_CFunction))]
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private int importType (LuaCore.lua_State luaState)
{
string className = LuaLib.lua_tostring (luaState, 1).ToString ();
var klass = FindType (className);
if (!klass.IsNull ())
pushType (luaState, klass);
else
LuaLib.lua_pushnil (luaState);
return 1;
}
/*
* Implementation of make_object. Registers a table (first
* argument in the stack) as an object subclassing the
* type passed as second argument in the stack.
*/
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private static int importType (LuaCore.lua_State luaState)
{
var translator = ObjectTranslatorPool.Instance.Find (luaState);
return translator.importTypeInternal (luaState);
}
private int importTypeInternal (LuaCore.lua_State luaState)
{
string className = LuaLib.lua_tostring (luaState, 1).ToString ();
var klass = FindType (className);
if (!klass.IsNull ())
pushType (luaState, klass);
else
LuaLib.lua_pushnil (luaState);
return 1;
}
/*
* Implementation of make_object. Registers a table (first
* argument in the stack) as an object subclassing the
* type passed as second argument in the stack.
*/
#if MONOTOUCH
[MonoTouch.MonoPInvokeCallback (typeof (LuaCore.lua_CFunction))]
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private int registerTable (LuaCore.lua_State luaState)
{
if (LuaLib.lua_type (luaState, 1) == LuaTypes.Table) {
var luaTable = getTable (luaState, 1);
string superclassName = LuaLib.lua_tostring (luaState, 2).ToString ();
if (!superclassName.IsNull ()) {
var klass = FindType (superclassName);
if (!klass.IsNull ()) {
// Creates and pushes the object in the stack, setting
// it as the metatable of the first argument
object obj = CodeGeneration.Instance.GetClassInstance (klass, luaTable);
pushObject (luaState, obj, "luaNet_metatable");
LuaLib.lua_newtable (luaState);
LuaLib.lua_pushstring (luaState, "__index");
LuaLib.lua_pushvalue (luaState, -3);
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_pushstring (luaState, "__newindex");
LuaLib.lua_pushvalue (luaState, -3);
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_setmetatable (luaState, 1);
// Pushes the object again, this time as the base field
// of the table and with the luaNet_searchbase metatable
LuaLib.lua_pushstring (luaState, "base");
int index = addObject (obj);
pushNewObject (luaState, obj, index, "luaNet_searchbase");
LuaLib.lua_rawset (luaState, 1);
} else
throwError (luaState, "register_table: can not find superclass '" + superclassName + "'");
} else
throwError (luaState, "register_table: superclass name can not be null");
} else
throwError (luaState, "register_table: first arg is not a table");
return 0;
}
/*
* Implementation of free_object. Clears the metatable and the
* base field, freeing the created object for garbage-collection
*/
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private static int registerTable (LuaCore.lua_State luaState)
{
var translator = ObjectTranslatorPool.Instance.Find (luaState);
return translator.registerTableInternal (luaState);
}
private int registerTableInternal (LuaCore.lua_State luaState)
{
if (LuaLib.lua_type (luaState, 1) == LuaTypes.Table) {
var luaTable = getTable (luaState, 1);
string superclassName = LuaLib.lua_tostring (luaState, 2).ToString ();
if (!superclassName.IsNull ()) {
var klass = FindType (superclassName);
if (!klass.IsNull ()) {
// Creates and pushes the object in the stack, setting
// it as the metatable of the first argument
object obj = CodeGeneration.Instance.GetClassInstance (klass, luaTable);
pushObject (luaState, obj, "luaNet_metatable");
LuaLib.lua_newtable (luaState);
LuaLib.lua_pushstring (luaState, "__index");
LuaLib.lua_pushvalue (luaState, -3);
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_pushstring (luaState, "__newindex");
LuaLib.lua_pushvalue (luaState, -3);
LuaLib.lua_settable (luaState, -3);
LuaLib.lua_setmetatable (luaState, 1);
// Pushes the object again, this time as the base field
// of the table and with the luaNet_searchbase metatable
LuaLib.lua_pushstring (luaState, "base");
int index = addObject (obj);
pushNewObject (luaState, obj, index, "luaNet_searchbase");
LuaLib.lua_rawset (luaState, 1);
} else
throwError (luaState, "register_table: can not find superclass '" + superclassName + "'");
} else
throwError (luaState, "register_table: superclass name can not be null");
} else
throwError (luaState, "register_table: first arg is not a table");
return 0;
}
/*
* Implementation of free_object. Clears the metatable and the
* base field, freeing the created object for garbage-collection
*/
#if MONOTOUCH
[MonoTouch.MonoPInvokeCallback (typeof (LuaCore.lua_CFunction))]
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private int unregisterTable (LuaCore.lua_State luaState)
{
try {
if (LuaLib.lua_getmetatable (luaState, 1) != 0) {
LuaLib.lua_pushstring (luaState, "__index");
LuaLib.lua_gettable (luaState, -2);
object obj = getRawNetObject (luaState, -1);
if (obj.IsNull ())
throwError (luaState, "unregister_table: arg is not valid table");
var luaTableField = obj.GetType ().GetField ("__luaInterface_luaTable");
if (luaTableField.IsNull ())
throwError (luaState, "unregister_table: arg is not valid table");
luaTableField.SetValue (obj, null);
LuaLib.lua_pushnil (luaState);
LuaLib.lua_setmetatable (luaState, 1);
LuaLib.lua_pushstring (luaState, "base");
LuaLib.lua_pushnil (luaState);
LuaLib.lua_settable (luaState, 1);
} else
throwError (luaState, "unregister_table: arg is not valid table");
} catch (Exception e) {
throwError (luaState, e.Message);
}
return 0;
}
/*
* Implementation of get_method_bysig. Returns nil
* if no matching method is not found.
*/
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private static int unregisterTable (LuaCore.lua_State luaState)
{
var translator = ObjectTranslatorPool.Instance.Find (luaState);
return translator.unregisterTableInternal (luaState);
}
private int unregisterTableInternal (LuaCore.lua_State luaState)
{
try {
if (LuaLib.lua_getmetatable (luaState, 1) != 0) {
LuaLib.lua_pushstring (luaState, "__index");
LuaLib.lua_gettable (luaState, -2);
object obj = getRawNetObject (luaState, -1);
if (obj.IsNull ())
throwError (luaState, "unregister_table: arg is not valid table");
var luaTableField = obj.GetType ().GetField ("__luaInterface_luaTable");
if (luaTableField.IsNull ())
throwError (luaState, "unregister_table: arg is not valid table");
luaTableField.SetValue (obj, null);
LuaLib.lua_pushnil (luaState);
LuaLib.lua_setmetatable (luaState, 1);
LuaLib.lua_pushstring (luaState, "base");
LuaLib.lua_pushnil (luaState);
LuaLib.lua_settable (luaState, 1);
} else
throwError (luaState, "unregister_table: arg is not valid table");
} catch (Exception e) {
throwError (luaState, e.Message);
}
return 0;
}
/*
* Implementation of get_method_bysig. Returns nil
* if no matching method is not found.
*/
#if MONOTOUCH
[MonoTouch.MonoPInvokeCallback (typeof (LuaCore.lua_CFunction))]
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private int getMethodSignature (LuaCore.lua_State luaState)
{
IReflect klass;
object target;
int udata = LuaLib.luanet_checkudata (luaState, 1, "luaNet_class");
if (udata != -1) {
klass = (IReflect)objects [udata];
target = null;
} else {
target = getRawNetObject (luaState, 1);
if (target.IsNull ()) {
throwError (luaState, "get_method_bysig: first arg is not type or object reference");
LuaLib.lua_pushnil (luaState);
return 1;
}
klass = target.GetType ();
}
string methodName = LuaLib.lua_tostring (luaState, 2).ToString ();
var signature = new Type[LuaLib.lua_gettop (luaState) - 2];
for (int i = 0; i < signature.Length; i++)
signature [i] = FindType (LuaLib.lua_tostring (luaState, i + 3).ToString ());
try {
//CP: Added ignore case
var method = klass.GetMethod (methodName, BindingFlags.Public | BindingFlags.Static |
BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.IgnoreCase, null, signature, null);
pushFunction (luaState, new LuaCore.lua_CFunction ((new LuaMethodWrapper (this, target, klass, method)).invokeFunction));
} catch (Exception e) {
throwError (luaState, e);
LuaLib.lua_pushnil (luaState);
}
return 1;
}
/*
* Implementation of get_constructor_bysig. Returns nil
* if no matching constructor is found.
*/
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private static int getMethodSignature (LuaCore.lua_State luaState)
{
var translator = ObjectTranslatorPool.Instance.Find (luaState);
return translator.getMethodSignatureInternal (luaState);
}
private int getMethodSignatureInternal (LuaCore.lua_State luaState)
{
IReflect klass;
object target;
int udata = LuaLib.luanet_checkudata (luaState, 1, "luaNet_class");
if (udata != -1) {
klass = (IReflect)objects [udata];
target = null;
} else {
target = getRawNetObject (luaState, 1);
if (target.IsNull ()) {
throwError (luaState, "get_method_bysig: first arg is not type or object reference");
LuaLib.lua_pushnil (luaState);
return 1;
}
klass = target.GetType ();
}
string methodName = LuaLib.lua_tostring (luaState, 2).ToString ();
var signature = new Type[LuaLib.lua_gettop (luaState) - 2];
for (int i = 0; i < signature.Length; i++)
signature [i] = FindType (LuaLib.lua_tostring (luaState, i + 3).ToString ());
try {
//CP: Added ignore case
var method = klass.GetMethod (methodName, BindingFlags.Public | BindingFlags.Static |
BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.IgnoreCase, null, signature, null);
pushFunction (luaState, new LuaCore.lua_CFunction ((new LuaMethodWrapper (this, target, klass, method)).invokeFunction));
} catch (Exception e) {
throwError (luaState, e);
LuaLib.lua_pushnil (luaState);
}
return 1;
}
/*
* Implementation of get_constructor_bysig. Returns nil
* if no matching constructor is found.
*/
#if MONOTOUCH
[MonoTouch.MonoPInvokeCallback (typeof (LuaCore.lua_CFunction))]
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private int getConstructorSignature (LuaCore.lua_State luaState)
{
IReflect klass = null;
int udata = LuaLib.luanet_checkudata (luaState, 1, "luaNet_class");
if (udata != -1)
klass = (IReflect)objects [udata];
if (klass.IsNull ())
throwError (luaState, "get_constructor_bysig: first arg is invalid type reference");
var signature = new Type[LuaLib.lua_gettop (luaState) - 1];
for (int i = 0; i < signature.Length; i++)
signature [i] = FindType (LuaLib.lua_tostring (luaState, i + 2).ToString ());
try {
ConstructorInfo constructor = klass.UnderlyingSystemType.GetConstructor (signature);
pushFunction (luaState, new LuaCore.lua_CFunction ((new LuaMethodWrapper (this, null, klass, constructor)).invokeFunction));
} catch (Exception e) {
throwError (luaState, e);
LuaLib.lua_pushnil (luaState);
}
return 1;
}
/*
* Pushes a type reference into the stack
*/
internal void pushType (LuaCore.lua_State luaState, Type t)
{
pushObject (luaState, new ProxyType (t), "luaNet_class");
}
/*
* Pushes a delegate into the stack
*/
internal void pushFunction (LuaCore.lua_State luaState, LuaCore.lua_CFunction func)
{
pushObject (luaState, func, "luaNet_function");
}
/*
* Pushes a CLR object into the Lua stack as an userdata
* with the provided metatable
*/
internal void pushObject (LuaCore.lua_State luaState, object o, string metatable)
{
int index = -1;
// Pushes nil
if (o.IsNull ()) {
LuaLib.lua_pushnil (luaState);
return;
}
// Object already in the list of Lua objects? Push the stored reference.
bool found = objectsBackMap.TryGetValue (o, out index);
if (found) {
LuaLib.luaL_getmetatable (luaState, "luaNet_objects");
LuaLib.lua_rawgeti (luaState, -1, index);
// Note: starting with lua5.1 the garbage collector may remove weak reference items (such as our luaNet_objects values) when the initial GC sweep
// occurs, but the actual call of the __gc finalizer for that object may not happen until a little while later. During that window we might call
// this routine and find the element missing from luaNet_objects, but collectObject() has not yet been called. In that case, we go ahead and call collect
// object here
// did we find a non nil object in our table? if not, we need to call collect object
var type = LuaLib.lua_type (luaState, -1);
if (type != LuaTypes.Nil) {
LuaLib.lua_remove (luaState, -2); // drop the metatable - we're going to leave our object on the stack
return;
}
// MetaFunctions.dumpStack(this, luaState);
LuaLib.lua_remove (luaState, -1); // remove the nil object value
LuaLib.lua_remove (luaState, -1); // remove the metatable
collectObject (o, index); // Remove from both our tables and fall out to get a new ID
}
index = addObject (o);
pushNewObject (luaState, o, index, metatable);
}
/*
* Pushes a new object into the Lua stack with the provided
* metatable
*/
private void pushNewObject (LuaCore.lua_State luaState, object o, int index, string metatable)
{
if (metatable == "luaNet_metatable") {
// Gets or creates the metatable for the object's type
LuaLib.luaL_getmetatable (luaState, o.GetType ().AssemblyQualifiedName);
if (LuaLib.lua_isnil (luaState, -1)) {
LuaLib.lua_settop (luaState, -2);
LuaLib.luaL_newmetatable (luaState, o.GetType ().AssemblyQualifiedName);
LuaLib.lua_pushstring (luaState, "cache");
LuaLib.lua_newtable (luaState);
LuaLib.lua_rawset (luaState, -3);
LuaLib.lua_pushlightuserdata (luaState, LuaLib.luanet_gettag ());
LuaLib.lua_pushnumber (luaState, 1);
LuaLib.lua_rawset (luaState, -3);
LuaLib.lua_pushstring (luaState, "__index");
LuaLib.lua_pushstring (luaState, "luaNet_indexfunction");
LuaLib.lua_rawget (luaState, (int)LuaIndexes.Registry);
LuaLib.lua_rawset (luaState, -3);
LuaLib.lua_pushstring (luaState, "__gc");
LuaLib.lua_pushstdcallcfunction (luaState, metaFunctions.gcFunction);
LuaLib.lua_rawset (luaState, -3);
LuaLib.lua_pushstring (luaState, "__tostring");
LuaLib.lua_pushstdcallcfunction (luaState, metaFunctions.toStringFunction);
LuaLib.lua_rawset (luaState, -3);
LuaLib.lua_pushstring (luaState, "__newindex");
LuaLib.lua_pushstdcallcfunction (luaState, metaFunctions.newindexFunction);
LuaLib.lua_rawset (luaState, -3);
}
} else
LuaLib.luaL_getmetatable (luaState, metatable);
// Stores the object index in the Lua list and pushes the
// index into the Lua stack
LuaLib.luaL_getmetatable (luaState, "luaNet_objects");
LuaLib.luanet_newudata (luaState, index);
LuaLib.lua_pushvalue (luaState, -3);
LuaLib.lua_remove (luaState, -4);
LuaLib.lua_setmetatable (luaState, -2);
LuaLib.lua_pushvalue (luaState, -1);
LuaLib.lua_rawseti (luaState, -3, index);
LuaLib.lua_remove (luaState, -2);
}
/*
* Gets an object from the Lua stack with the desired type, if it matches, otherwise
* returns null.
*/
internal object getAsType (LuaCore.lua_State luaState, int stackPos, Type paramType)
{
var extractor = typeChecker.checkType (luaState, stackPos, paramType);
return !extractor.IsNull () ? extractor (luaState, stackPos) : null;
}
/// <summary>
/// Given the Lua int ID for an object remove it from our maps
/// </summary>
/// <param name = "udata"></param>
internal void collectObject (int udata)
{
object o;
bool found = objects.TryGetValue (udata, out o);
// The other variant of collectObject might have gotten here first, in that case we will silently ignore the missing entry
if (found) {
// Debug.WriteLine("Removing " + o.ToString() + " @ " + udata);
objects.Remove (udata);
objectsBackMap.Remove (o);
}
}
/// <summary>
/// Given an object reference, remove it from our maps
/// </summary>
/// <param name = "udata"></param>
private void collectObject (object o, int udata)
{
// Debug.WriteLine("Removing " + o.ToString() + " @ " + udata);
objects.Remove (udata);
objectsBackMap.Remove (o);
}
private int addObject (object obj)
{
// New object: inserts it in the list
int index = nextObj++;
// Debug.WriteLine("Adding " + obj.ToString() + " @ " + index);
objects [index] = obj;
objectsBackMap [obj] = index;
return index;
}
/*
* Gets an object from the Lua stack according to its Lua type.
*/
internal object getObject (LuaCore.lua_State luaState, int index)
{
var type = LuaLib.lua_type (luaState, index);
switch (type) {
case LuaTypes.Number:
{
return LuaLib.lua_tonumber (luaState, index);
}
case LuaTypes.String:
{
return LuaLib.lua_tostring (luaState, index);
}
case LuaTypes.Boolean:
{
return LuaLib.lua_toboolean (luaState, index);
}
case LuaTypes.Table:
{
return getTable (luaState, index);
}
case LuaTypes.Function:
{
return getFunction (luaState, index);
}
case LuaTypes.UserData:
{
int udata = LuaLib.luanet_tonetobject (luaState, index);
return udata != -1 ? objects [udata] : getUserData (luaState, index);
}
default:
return null;
}
}
/*
* Gets the table in the index positon of the Lua stack.
*/
internal LuaTable getTable (LuaCore.lua_State luaState, int index)
{
LuaLib.lua_pushvalue (luaState, index);
return new LuaTable (LuaLib.lua_ref (luaState, 1), interpreter);
}
/*
* Gets the userdata in the index positon of the Lua stack.
*/
internal LuaUserData getUserData (LuaCore.lua_State luaState, int index)
{
LuaLib.lua_pushvalue (luaState, index);
return new LuaUserData (LuaLib.lua_ref (luaState, 1), interpreter);
}
/*
* Gets the function in the index positon of the Lua stack.
*/
internal LuaFunction getFunction (LuaCore.lua_State luaState, int index)
{
LuaLib.lua_pushvalue (luaState, index);
return new LuaFunction (LuaLib.lua_ref (luaState, 1), interpreter);
}
/*
* Gets the CLR object in the index positon of the Lua stack. Returns
* delegates as Lua functions.
*/
internal object getNetObject (LuaCore.lua_State luaState, int index)
{
int idx = LuaLib.luanet_tonetobject (luaState, index);
return idx != -1 ? objects [idx] : null;
}
/*
* Gets the CLR object in the index positon of the Lua stack. Returns
* delegates as is.
*/
internal object getRawNetObject (LuaCore.lua_State luaState, int index)
{
int udata = LuaLib.luanet_rawnetobj (luaState, index);
return udata != -1 ? objects [udata] : null;
}
/*
* Pushes the entire array into the Lua stack and returns the number
* of elements pushed.
*/
internal int returnValues (LuaCore.lua_State luaState, object[] returnValues)
{
if (LuaLib.lua_checkstack (luaState, returnValues.Length + 5)) {
for (int i = 0; i < returnValues.Length; i++)
push (luaState, returnValues [i]);
return returnValues.Length;
} else
return 0;
}
/*
* Gets the values from the provided index to
* the top of the stack and returns them in an array.
*/
internal object[] popValues (LuaCore.lua_State luaState, int oldTop)
{
int newTop = LuaLib.lua_gettop (luaState);
if (oldTop == newTop)
return null;
else {
var returnValues = new ArrayList ();
for (int i = oldTop+1; i <= newTop; i++)
returnValues.Add (getObject (luaState, i));
LuaLib.lua_settop (luaState, oldTop);
return returnValues.ToArray ();
}
}
/*
* Gets the values from the provided index to
* the top of the stack and returns them in an array, casting
* them to the provided types.
*/
internal object[] popValues (LuaCore.lua_State luaState, int oldTop, Type[] popTypes)
{
int newTop = LuaLib.lua_gettop (luaState);
if (oldTop == newTop)
return null;
else {
int iTypes;
var returnValues = new ArrayList ();
if (popTypes [0] == typeof(void))
iTypes = 1;
else
iTypes = 0;
for (int i = oldTop+1; i <= newTop; i++) {
returnValues.Add (getAsType (luaState, i, popTypes [iTypes]));
iTypes++;
}
LuaLib.lua_settop (luaState, oldTop);
return returnValues.ToArray ();
}
}
// kevinh - the following line doesn't work for remoting proxies - they always return a match for 'is'
// else if(o is ILuaGeneratedType)
private static bool IsILua (object o)
{
if (o is ILuaGeneratedType) {
// Make sure we are _really_ ILuaGenerated
var typ = o.GetType ();
return (!typ.GetInterface ("ILuaGeneratedType").IsNull ());
} else
return false;
}
/*
* Pushes the object into the Lua stack according to its type.
*/
internal void push (LuaCore.lua_State luaState, object o)
{
if (o.IsNull ())
LuaLib.lua_pushnil (luaState);
else if (o is sbyte || o is byte || o is short || o is ushort ||
o is int || o is uint || o is long || o is float ||
o is ulong || o is decimal || o is double) {
double d = Convert.ToDouble (o);
LuaLib.lua_pushnumber (luaState, d);
} else if (o is char) {
double d = (char)o;
LuaLib.lua_pushnumber (luaState, d);
} else if (o is string) {
string str = (string)o;
LuaLib.lua_pushstring (luaState, str);
} else if (o is bool) {
bool b = (bool)o;
LuaLib.lua_pushboolean (luaState, b);
} else if (IsILua (o))
(((ILuaGeneratedType)o).__luaInterface_getLuaTable ()).push (luaState);
else if (o is LuaTable)
((LuaTable)o).push (luaState);
else if (o is LuaCore.lua_CFunction)
pushFunction (luaState, (LuaCore.lua_CFunction)o);
else if (o is LuaFunction)
((LuaFunction)o).push (luaState);
else
pushObject (luaState, o, "luaNet_metatable");
}
/*
* Checks if the method matches the arguments in the Lua stack, getting
* the arguments if it does.
*/
internal bool matchParameters (LuaCore.lua_State luaState, MethodBase method, ref MethodCache methodCache)
{
return metaFunctions.matchParameters (luaState, method, ref methodCache);
}
}
#endif
[System.Runtime.InteropServices.AllowReversePInvokeCalls]
private static int getConstructorSignature (LuaCore.lua_State luaState)
{
var translator = ObjectTranslatorPool.Instance.Find (luaState);
return translator.getConstructorSignatureInternal (luaState);
}
private int getConstructorSignatureInternal (LuaCore.lua_State luaState)
{
IReflect klass = null;
int udata = LuaLib.luanet_checkudata (luaState, 1, "luaNet_class");
if (udata != -1)
klass = (IReflect)objects [udata];
if (klass.IsNull ())
throwError (luaState, "get_constructor_bysig: first arg is invalid type reference");
var signature = new Type[LuaLib.lua_gettop (luaState) - 1];
for (int i = 0; i < signature.Length; i++)
signature [i] = FindType (LuaLib.lua_tostring (luaState, i + 2).ToString ());
try {
ConstructorInfo constructor = klass.UnderlyingSystemType.GetConstructor (signature);
pushFunction (luaState, new LuaCore.lua_CFunction ((new LuaMethodWrapper (this, null, klass, constructor)).invokeFunction));
} catch (Exception e) {
throwError (luaState, e);
LuaLib.lua_pushnil (luaState);
}
return 1;
}
/*
* Pushes a type reference into the stack
*/
internal void pushType (LuaCore.lua_State luaState, Type t)
{
pushObject (luaState, new ProxyType (t), "luaNet_class");
}
/*
* Pushes a delegate into the stack
*/
internal void pushFunction (LuaCore.lua_State luaState, LuaCore.lua_CFunction func)
{
pushObject (luaState, func, "luaNet_function");
}
/*
* Pushes a CLR object into the Lua stack as an userdata
* with the provided metatable
*/
internal void pushObject (LuaCore.lua_State luaState, object o, string metatable)
{
int index = -1;
// Pushes nil
if (o.IsNull ()) {
LuaLib.lua_pushnil (luaState);
return;
}
// Object already in the list of Lua objects? Push the stored reference.
bool found = objectsBackMap.TryGetValue (o, out index);
if (found) {
LuaLib.luaL_getmetatable (luaState, "luaNet_objects");
LuaLib.lua_rawgeti (luaState, -1, index);
// Note: starting with lua5.1 the garbage collector may remove weak reference items (such as our luaNet_objects values) when the initial GC sweep
// occurs, but the actual call of the __gc finalizer for that object may not happen until a little while later. During that window we might call
// this routine and find the element missing from luaNet_objects, but collectObject() has not yet been called. In that case, we go ahead and call collect
// object here
// did we find a non nil object in our table? if not, we need to call collect object
var type = LuaLib.lua_type (luaState, -1);
if (type != LuaTypes.Nil) {
LuaLib.lua_remove (luaState, -2); // drop the metatable - we're going to leave our object on the stack
return;
}
// MetaFunctions.dumpStack(this, luaState);
LuaLib.lua_remove (luaState, -1); // remove the nil object value
LuaLib.lua_remove (luaState, -1); // remove the metatable
collectObject (o, index); // Remove from both our tables and fall out to get a new ID
}
index = addObject (o);
pushNewObject (luaState, o, index, metatable);
}
/*
* Pushes a new object into the Lua stack with the provided
* metatable
*/
private void pushNewObject (LuaCore.lua_State luaState, object o, int index, string metatable)
{
if (metatable == "luaNet_metatable") {
// Gets or creates the metatable for the object's type
LuaLib.luaL_getmetatable (luaState, o.GetType ().AssemblyQualifiedName);
if (LuaLib.lua_isnil (luaState, -1)) {
LuaLib.lua_settop (luaState, -2);
LuaLib.luaL_newmetatable (luaState, o.GetType ().AssemblyQualifiedName);
LuaLib.lua_pushstring (luaState, "cache");
LuaLib.lua_newtable (luaState);
LuaLib.lua_rawset (luaState, -3);
LuaLib.lua_pushlightuserdata (luaState, LuaLib.luanet_gettag ());
LuaLib.lua_pushnumber (luaState, 1);
LuaLib.lua_rawset (luaState, -3);
LuaLib.lua_pushstring (luaState, "__index");
LuaLib.lua_pushstring (luaState, "luaNet_indexfunction");
LuaLib.lua_rawget (luaState, (int)LuaIndexes.Registry);
LuaLib.lua_rawset (luaState, -3);
LuaLib.lua_pushstring (luaState, "__gc");
LuaLib.lua_pushstdcallcfunction (luaState, metaFunctions.gcFunction);
LuaLib.lua_rawset (luaState, -3);
LuaLib.lua_pushstring (luaState, "__tostring");
LuaLib.lua_pushstdcallcfunction (luaState, metaFunctions.toStringFunction);
LuaLib.lua_rawset (luaState, -3);
LuaLib.lua_pushstring (luaState, "__newindex");
LuaLib.lua_pushstdcallcfunction (luaState, metaFunctions.newindexFunction);
LuaLib.lua_rawset (luaState, -3);
}
} else
LuaLib.luaL_getmetatable (luaState, metatable);
// Stores the object index in the Lua list and pushes the
// index into the Lua stack
LuaLib.luaL_getmetatable (luaState, "luaNet_objects");
LuaLib.luanet_newudata (luaState, index);
LuaLib.lua_pushvalue (luaState, -3);
LuaLib.lua_remove (luaState, -4);
LuaLib.lua_setmetatable (luaState, -2);
LuaLib.lua_pushvalue (luaState, -1);
LuaLib.lua_rawseti (luaState, -3, index);
LuaLib.lua_remove (luaState, -2);
}
/*
* Gets an object from the Lua stack with the desired type, if it matches, otherwise
* returns null.
*/
internal object getAsType (LuaCore.lua_State luaState, int stackPos, Type paramType)
{
var extractor = typeChecker.checkType (luaState, stackPos, paramType);
return !extractor.IsNull () ? extractor (luaState, stackPos) : null;
}
/// <summary>
/// Given the Lua int ID for an object remove it from our maps
/// </summary>
/// <param name = "udata"></param>
internal void collectObject (int udata)
{
object o;
bool found = objects.TryGetValue (udata, out o);
// The other variant of collectObject might have gotten here first, in that case we will silently ignore the missing entry
if (found) {
// Debug.WriteLine("Removing " + o.ToString() + " @ " + udata);
objects.Remove (udata);
objectsBackMap.Remove (o);
}
}
/// <summary>
/// Given an object reference, remove it from our maps
/// </summary>
/// <param name = "udata"></param>
private void collectObject (object o, int udata)
{
// Debug.WriteLine("Removing " + o.ToString() + " @ " + udata);
objects.Remove (udata);
objectsBackMap.Remove (o);
}
private int addObject (object obj)
{
// New object: inserts it in the list
int index = nextObj++;
// Debug.WriteLine("Adding " + obj.ToString() + " @ " + index);
objects [index] = obj;
objectsBackMap [obj] = index;
return index;
}
/*
* Gets an object from the Lua stack according to its Lua type.
*/
internal object getObject (LuaCore.lua_State luaState, int index)
{
var type = LuaLib.lua_type (luaState, index);
switch (type) {
case LuaTypes.Number:
{
return LuaLib.lua_tonumber (luaState, index);
}
case LuaTypes.String:
{
return LuaLib.lua_tostring (luaState, index);
}
case LuaTypes.Boolean:
{
return LuaLib.lua_toboolean (luaState, index);
}
case LuaTypes.Table:
{
return getTable (luaState, index);
}
case LuaTypes.Function:
{
return getFunction (luaState, index);
}
case LuaTypes.UserData:
{
int udata = LuaLib.luanet_tonetobject (luaState, index);
return udata != -1 ? objects [udata] : getUserData (luaState, index);
}
default:
return null;
}
}
/*
* Gets the table in the index positon of the Lua stack.
*/
internal LuaTable getTable (LuaCore.lua_State luaState, int index)
{
LuaLib.lua_pushvalue (luaState, index);
return new LuaTable (LuaLib.lua_ref (luaState, 1), interpreter);
}
/*
* Gets the userdata in the index positon of the Lua stack.
*/
internal LuaUserData getUserData (LuaCore.lua_State luaState, int index)
{
LuaLib.lua_pushvalue (luaState, index);
return new LuaUserData (LuaLib.lua_ref (luaState, 1), interpreter);
}
/*
* Gets the function in the index positon of the Lua stack.
*/
internal LuaFunction getFunction (LuaCore.lua_State luaState, int index)
{
LuaLib.lua_pushvalue (luaState, index);
return new LuaFunction (LuaLib.lua_ref (luaState, 1), interpreter);
}
/*
* Gets the CLR object in the index positon of the Lua stack. Returns
* delegates as Lua functions.
*/
internal object getNetObject (LuaCore.lua_State luaState, int index)
{
int idx = LuaLib.luanet_tonetobject (luaState, index);
return idx != -1 ? objects [idx] : null;
}
/*
* Gets the CLR object in the index positon of the Lua stack. Returns
* delegates as is.
*/
internal object getRawNetObject (LuaCore.lua_State luaState, int index)
{
int udata = LuaLib.luanet_rawnetobj (luaState, index);
return udata != -1 ? objects [udata] : null;
}
/*
* Pushes the entire array into the Lua stack and returns the number
* of elements pushed.
*/
internal int returnValues (LuaCore.lua_State luaState, object[] returnValues)
{
if (LuaLib.lua_checkstack (luaState, returnValues.Length + 5)) {
for (int i = 0; i < returnValues.Length; i++)
push (luaState, returnValues [i]);
return returnValues.Length;
} else
return 0;
}
/*
* Gets the values from the provided index to
* the top of the stack and returns them in an array.
*/
internal object[] popValues (LuaCore.lua_State luaState, int oldTop)
{
int newTop = LuaLib.lua_gettop (luaState);
if (oldTop == newTop)
return null;
else {
var returnValues = new ArrayList ();
for (int i = oldTop+1; i <= newTop; i++)
returnValues.Add (getObject (luaState, i));
LuaLib.lua_settop (luaState, oldTop);
return returnValues.ToArray ();
}
}
/*
* Gets the values from the provided index to
* the top of the stack and returns them in an array, casting
* them to the provided types.
*/
internal object[] popValues (LuaCore.lua_State luaState, int oldTop, Type[] popTypes)
{
int newTop = LuaLib.lua_gettop (luaState);
if (oldTop == newTop)
return null;
else {
int iTypes;
var returnValues = new ArrayList ();
if (popTypes [0] == typeof(void))
iTypes = 1;
else
iTypes = 0;
for (int i = oldTop+1; i <= newTop; i++) {
returnValues.Add (getAsType (luaState, i, popTypes [iTypes]));
iTypes++;
}
LuaLib.lua_settop (luaState, oldTop);
return returnValues.ToArray ();
}
}
// kevinh - the following line doesn't work for remoting proxies - they always return a match for 'is'
// else if(o is ILuaGeneratedType)
private static bool IsILua (object o)
{
if (o is ILuaGeneratedType) {
// Make sure we are _really_ ILuaGenerated
var typ = o.GetType ();
return (!typ.GetInterface ("ILuaGeneratedType").IsNull ());
} else
return false;
}
/*
* Pushes the object into the Lua stack according to its type.
*/
internal void push (LuaCore.lua_State luaState, object o)
{
if (o.IsNull ())
LuaLib.lua_pushnil (luaState);
else if (o is sbyte || o is byte || o is short || o is ushort ||
o is int || o is uint || o is long || o is float ||
o is ulong || o is decimal || o is double) {
double d = Convert.ToDouble (o);
LuaLib.lua_pushnumber (luaState, d);
} else if (o is char) {
double d = (char)o;
LuaLib.lua_pushnumber (luaState, d);
} else if (o is string) {
string str = (string)o;
LuaLib.lua_pushstring (luaState, str);
} else if (o is bool) {
bool b = (bool)o;
LuaLib.lua_pushboolean (luaState, b);
} else if (IsILua (o))
(((ILuaGeneratedType)o).__luaInterface_getLuaTable ()).push (luaState);
else if (o is LuaTable)
((LuaTable)o).push (luaState);
else if (o is LuaCore.lua_CFunction)
pushFunction (luaState, (LuaCore.lua_CFunction)o);
else if (o is LuaFunction)
((LuaFunction)o).push (luaState);
else
pushObject (luaState, o, "luaNet_metatable");
}
/*
* Checks if the method matches the arguments in the Lua stack, getting
* the arguments if it does.
*/
internal bool matchParameters (LuaCore.lua_State luaState, MethodBase method, ref MethodCache methodCache)
{
return metaFunctions.matchParameters (luaState, method, ref methodCache);
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
namespace LuaInterface
{
#if USE_KOPILUA
using LuaCore = KopiLua.Lua;
#else
using LuaCore = KeraLua.Lua;
#endif
internal class ObjectTranslatorPool
{
private static volatile ObjectTranslatorPool instance = new ObjectTranslatorPool ();
private static object syncRoot = new object ();
private Dictionary<LuaCore.lua_State, ObjectTranslator> translators = new Dictionary<LuaCore.lua_State, ObjectTranslator>();
public static ObjectTranslatorPool Instance
{
get
{
return instance;
}
}
public ObjectTranslatorPool ()
{
syncRoot = new Dictionary<LuaCore.lua_State, ObjectTranslator> ();
}
public void Add (LuaCore.lua_State luaState, ObjectTranslator translator)
{
translators.Add(luaState , translator);
}
public ObjectTranslator Find (LuaCore.lua_State luaState)
{
if (!translators.ContainsKey(luaState))
return null;
return translators [luaState];
}
public void Remove (LuaCore.lua_State luaState)
{
if (!translators.ContainsKey (luaState))
return;
translators.Remove (luaState);
}
}
}
......@@ -64,7 +64,9 @@
<IpaPackageName />
<MtouchI18n />
<MtouchArch>ARMv7</MtouchArch>
<MtouchLink>Full</MtouchLink>
<MtouchLink>None</MtouchLink>
<MtouchUseLlvm>true</MtouchUseLlvm>
<MtouchUseThumb>true</MtouchUseThumb>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Ad-Hoc|iPhone' ">
<DebugType>none</DebugType>
......
......@@ -348,6 +348,16 @@ namespace LuaInterfaceTest
//lua.RegisterFunction("regularMethod", genericClass, typeof(TestClassGeneric<>).GetMethod("RegularMethod"));
using (Lua lua = new Lua ()) {
TestClassWithGenericMethod classWithGenericMethod = new TestClassWithGenericMethod ();
////////////////////////////////////////////////////////////////////////////
/// ////////////////////////////////////////////////////////////////////////
/// IMPORTANT: Use generic method with the type you will call or generic methods will fail with iOS
/// ////////////////////////////////////////////////////////////////////////
classWithGenericMethod.GenericMethod<double>(99.0);
classWithGenericMethod.GenericMethod<TestClass>(new TestClass (99));
////////////////////////////////////////////////////////////////////////////
/// ////////////////////////////////////////////////////////////////////////
lua.RegisterFunction ("genericMethod2", classWithGenericMethod, typeof(TestClassWithGenericMethod).GetMethod ("GenericMethod"));
try {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment