BizHawk/LuaInterface/LuaInterface/CheckType.cs

338 lines
12 KiB
C#

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Reflection;
using Lua511;
namespace LuaInterface
{
/*
* Type checking and conversion functions.
*
* Author: Fabio Mascarenhas
* Version: 1.0
*/
class CheckType
{
private ObjectTranslator translator;
ExtractValue extractNetObject;
Dictionary<long, ExtractValue> extractValues = new Dictionary<long, ExtractValue>();
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));
extractValues.Add(typeof(Color).TypeHandle.Value.ToInt64(), new ExtractValue(getAsColor));
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();
if(extractValues.ContainsKey(runtimeHandleValue))
return extractValues[runtimeHandleValue];
else
return extractNetObject;
}
internal ExtractValue checkType(IntPtr luaState,int stackPos,Type paramType)
{
LuaTypes luatype = LuaDLL.lua_type(luaState, stackPos);
if(paramType.IsByRef) paramType=paramType.GetElementType();
Type underlyingType = Nullable.GetUnderlyingType(paramType);
if (underlyingType != null)
{
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.LUA_TBOOLEAN)
return extractValues[typeof(bool).TypeHandle.Value.ToInt64()];
else if (luatype == LuaTypes.LUA_TSTRING)
return extractValues[typeof(string).TypeHandle.Value.ToInt64()];
else if (luatype == LuaTypes.LUA_TTABLE)
return extractValues[typeof(LuaTable).TypeHandle.Value.ToInt64()];
else if (luatype == LuaTypes.LUA_TUSERDATA)
return extractValues[typeof(object).TypeHandle.Value.ToInt64()];
else if (luatype == LuaTypes.LUA_TFUNCTION)
return extractValues[typeof(LuaFunction).TypeHandle.Value.ToInt64()];
else if (luatype == LuaTypes.LUA_TNUMBER)
return extractValues[typeof(double).TypeHandle.Value.ToInt64()];
else
;//an unsupported type was encountered
}
if (LuaDLL.lua_isnumber(luaState, stackPos))
return extractValues[runtimeHandleValue];
if (paramType == typeof(bool))
{
if (LuaDLL.lua_isboolean(luaState, stackPos))
return extractValues[runtimeHandleValue];
}
else if (paramType == typeof(Color))
{
return extractValues[runtimeHandleValue];
}
else if (paramType == typeof(string) || paramType == typeof(char[]))
{
if (LuaDLL.lua_isstring(luaState, stackPos))
return extractValues[runtimeHandleValue];
else if (luatype == LuaTypes.LUA_TNIL)
return extractNetObject; // kevinh - silently convert nil to a null string pointer
}
else if (paramType == typeof(LuaTable))
{
if (luatype == LuaTypes.LUA_TTABLE)
return extractValues[runtimeHandleValue];
}
else if (paramType == typeof(LuaUserData))
{
if (luatype == LuaTypes.LUA_TUSERDATA)
return extractValues[runtimeHandleValue];
}
else if (paramType == typeof(LuaFunction))
{
if (luatype == LuaTypes.LUA_TFUNCTION)
return extractValues[runtimeHandleValue];
}
else if (typeof(Delegate).IsAssignableFrom(paramType) && luatype == LuaTypes.LUA_TFUNCTION)
{
return new ExtractValue(new DelegateGenerator(translator, paramType).extractGenerated);
}
else if (paramType.IsInterface && luatype == LuaTypes.LUA_TTABLE)
{
return new ExtractValue(new ClassGenerator(translator, paramType).extractGenerated);
}
else if ((paramType.IsInterface || paramType.IsClass) && luatype == LuaTypes.LUA_TNIL)
{
// kevinh - allow nil to be silently converted to null - extractNetObject will return null when the item ain't found
return extractNetObject;
}
else if (LuaDLL.lua_type(luaState, stackPos) == LuaTypes.LUA_TTABLE)
{
if (LuaDLL.luaL_getmetafield(luaState, stackPos, "__index"))
{
object obj = translator.getNetObject(luaState, -1);
LuaDLL.lua_settop(luaState, -2);
if (obj != null && paramType.IsAssignableFrom(obj.GetType()))
return extractNetObject;
}
else
return null;
}
else
{
object obj = translator.getNetObject(luaState, stackPos);
if (obj != null && 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(IntPtr luaState,int stackPos)
{
sbyte retVal=(sbyte)LuaDLL.lua_tonumber(luaState,stackPos);
if(retVal==0 && !LuaDLL.lua_isnumber(luaState,stackPos)) return null;
return retVal;
}
private object getAsByte(IntPtr luaState,int stackPos)
{
byte retVal=(byte)LuaDLL.lua_tonumber(luaState,stackPos);
if(retVal==0 && !LuaDLL.lua_isnumber(luaState,stackPos)) return null;
return retVal;
}
private object getAsShort(IntPtr luaState,int stackPos)
{
short retVal=(short)LuaDLL.lua_tonumber(luaState,stackPos);
if(retVal==0 && !LuaDLL.lua_isnumber(luaState,stackPos)) return null;
return retVal;
}
private object getAsUshort(IntPtr luaState,int stackPos)
{
ushort retVal=(ushort)LuaDLL.lua_tonumber(luaState,stackPos);
if(retVal==0 && !LuaDLL.lua_isnumber(luaState,stackPos)) return null;
return retVal;
}
private object getAsInt(IntPtr luaState,int stackPos)
{
int retVal=(int)LuaDLL.lua_tonumber(luaState,stackPos);
if(retVal==0 && !LuaDLL.lua_isnumber(luaState,stackPos)) return null;
return retVal;
}
private object getAsUint(IntPtr luaState,int stackPos)
{
uint retVal=(uint)LuaDLL.lua_tonumber(luaState,stackPos);
if(retVal==0 && !LuaDLL.lua_isnumber(luaState,stackPos)) return null;
return retVal;
}
private object getAsLong(IntPtr luaState,int stackPos)
{
long retVal=(long)LuaDLL.lua_tonumber(luaState,stackPos);
if(retVal==0 && !LuaDLL.lua_isnumber(luaState,stackPos)) return null;
return retVal;
}
private object getAsUlong(IntPtr luaState,int stackPos)
{
ulong retVal=(ulong)LuaDLL.lua_tonumber(luaState,stackPos);
if(retVal==0 && !LuaDLL.lua_isnumber(luaState,stackPos)) return null;
return retVal;
}
private object getAsDouble(IntPtr luaState,int stackPos)
{
double retVal=LuaDLL.lua_tonumber(luaState,stackPos);
if(retVal==0 && !LuaDLL.lua_isnumber(luaState,stackPos)) return null;
return retVal;
}
private object getAsChar(IntPtr luaState,int stackPos)
{
char retVal=(char)LuaDLL.lua_tonumber(luaState,stackPos);
if(retVal==0 && !LuaDLL.lua_isnumber(luaState,stackPos)) return null;
return retVal;
}
private object getAsFloat(IntPtr luaState,int stackPos)
{
float retVal=(float)LuaDLL.lua_tonumber(luaState,stackPos);
if(retVal==0 && !LuaDLL.lua_isnumber(luaState,stackPos)) return null;
return retVal;
}
private object getAsDecimal(IntPtr luaState,int stackPos)
{
decimal retVal=(decimal)LuaDLL.lua_tonumber(luaState,stackPos);
if(retVal==0 && !LuaDLL.lua_isnumber(luaState,stackPos)) return null;
return retVal;
}
private object getAsBoolean(IntPtr luaState,int stackPos)
{
return LuaDLL.lua_toboolean(luaState,stackPos);
}
private object getAsString(IntPtr luaState,int stackPos)
{
string retVal=LuaDLL.lua_tostring(luaState,stackPos);
if(retVal=="" && !LuaDLL.lua_isstring(luaState,stackPos)) return null;
return retVal;
}
private object getAsColor(IntPtr luaState, int stackPos)
{
try
{
if (LuaDLL.lua_isnumber(luaState, stackPos))
{
Color retVal = Color.FromArgb((int)(long)LuaDLL.lua_tonumber(luaState, stackPos));
return retVal;
}
else if (LuaDLL.lua_isstring(luaState, stackPos))
{
Color retVal = Color.FromName(LuaDLL.lua_tostring(luaState, stackPos));
return retVal;
}
return null;
}
catch (Exception)
{
return null;
}
}
private object getAsTable(IntPtr luaState,int stackPos)
{
return translator.getTable(luaState,stackPos);
}
private object getAsFunction(IntPtr luaState,int stackPos)
{
return translator.getFunction(luaState,stackPos);
}
private object getAsUserdata(IntPtr luaState,int stackPos)
{
return translator.getUserData(luaState,stackPos);
}
public object getAsObject(IntPtr luaState,int stackPos)
{
if(LuaDLL.lua_type(luaState,stackPos)==LuaTypes.LUA_TTABLE)
{
if(LuaDLL.luaL_getmetafield(luaState,stackPos,"__index"))
{
if(LuaDLL.luaL_checkmetatable(luaState,-1))
{
LuaDLL.lua_insert(luaState,stackPos);
LuaDLL.lua_remove(luaState,stackPos+1);
}
else
{
LuaDLL.lua_settop(luaState,-2);
}
}
}
object obj=translator.getObject(luaState,stackPos);
return obj;
}
public object getAsNetObject(IntPtr luaState,int stackPos)
{
object obj=translator.getNetObject(luaState,stackPos);
if(obj==null && LuaDLL.lua_type(luaState,stackPos)==LuaTypes.LUA_TTABLE)
{
if(LuaDLL.luaL_getmetafield(luaState,stackPos,"__index"))
{
if(LuaDLL.luaL_checkmetatable(luaState,-1))
{
LuaDLL.lua_insert(luaState,stackPos);
LuaDLL.lua_remove(luaState,stackPos+1);
obj=translator.getNetObject(luaState,stackPos);
}
else
{
LuaDLL.lua_settop(luaState,-2);
}
}
}
return obj;
}
}
}