407 lines
14 KiB
C#
407 lines
14 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using KeraLua;
|
|
using NLua.Method;
|
|
using NLua.Extensions;
|
|
|
|
namespace NLua
|
|
{
|
|
using LuaState = KeraLua.Lua;
|
|
sealed class CheckType
|
|
{
|
|
readonly Dictionary<Type, ExtractValue> _extractValues = new Dictionary<Type, ExtractValue>();
|
|
readonly ExtractValue _extractNetObject;
|
|
readonly ObjectTranslator _translator;
|
|
|
|
public CheckType(ObjectTranslator translator)
|
|
{
|
|
_translator = translator;
|
|
_extractValues.Add(typeof(object), GetAsObject);
|
|
_extractValues.Add(typeof(sbyte), GetAsSbyte);
|
|
_extractValues.Add(typeof(byte), GetAsByte);
|
|
_extractValues.Add(typeof(short), GetAsShort);
|
|
_extractValues.Add(typeof(ushort), GetAsUshort);
|
|
_extractValues.Add(typeof(int), GetAsInt);
|
|
_extractValues.Add(typeof(uint), GetAsUint);
|
|
_extractValues.Add(typeof(long), GetAsLong);
|
|
_extractValues.Add(typeof(ulong), GetAsUlong);
|
|
_extractValues.Add(typeof(double), GetAsDouble);
|
|
_extractValues.Add(typeof(char), GetAsChar);
|
|
_extractValues.Add(typeof(float), GetAsFloat);
|
|
_extractValues.Add(typeof(decimal), GetAsDecimal);
|
|
_extractValues.Add(typeof(bool), GetAsBoolean);
|
|
_extractValues.Add(typeof(string), GetAsString);
|
|
_extractValues.Add(typeof(char[]), GetAsCharArray);
|
|
_extractValues.Add(typeof(byte[]), GetAsByteArray);
|
|
_extractValues.Add(typeof(LuaFunction), GetAsFunction);
|
|
_extractValues.Add(typeof(LuaTable), GetAsTable);
|
|
_extractValues.Add(typeof(LuaUserData), GetAsUserdata);
|
|
_extractNetObject = 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(ProxyType paramType)
|
|
{
|
|
return GetExtractor(paramType.UnderlyingSystemType);
|
|
}
|
|
|
|
internal ExtractValue GetExtractor(Type paramType)
|
|
{
|
|
if (paramType.IsByRef)
|
|
paramType = paramType.GetElementType();
|
|
|
|
return _extractValues.ContainsKey(paramType) ? _extractValues[paramType] : _extractNetObject;
|
|
}
|
|
|
|
internal ExtractValue CheckLuaType(LuaState luaState, int stackPos, Type paramType)
|
|
{
|
|
LuaType luatype = luaState.Type(stackPos);
|
|
|
|
if (paramType.IsByRef)
|
|
paramType = paramType.GetElementType();
|
|
|
|
var underlyingType = Nullable.GetUnderlyingType(paramType);
|
|
|
|
if (underlyingType != null)
|
|
{
|
|
paramType = underlyingType; // Silently convert nullable types to their non null requics
|
|
}
|
|
|
|
|
|
bool netParamIsNumeric = paramType == typeof(int) ||
|
|
paramType == typeof(uint) ||
|
|
paramType == typeof(long) ||
|
|
paramType == typeof(ulong) ||
|
|
paramType == typeof(short) ||
|
|
paramType == typeof(ushort) ||
|
|
paramType == typeof(float) ||
|
|
paramType == typeof(double) ||
|
|
paramType == typeof(decimal) ||
|
|
paramType == typeof(byte);
|
|
|
|
// If it is a nullable
|
|
if (underlyingType != null)
|
|
{
|
|
// null can always be assigned to nullable
|
|
if (luatype == LuaType.Nil)
|
|
{
|
|
// Return the correct extractor anyways
|
|
if (netParamIsNumeric || paramType == typeof(bool))
|
|
return _extractValues[paramType];
|
|
return _extractNetObject;
|
|
}
|
|
}
|
|
|
|
if (paramType == typeof(object))
|
|
return _extractValues[paramType];
|
|
|
|
//CP: Added support for generic parameters
|
|
if (paramType.IsGenericParameter)
|
|
{
|
|
if (luatype == LuaType.Boolean)
|
|
return _extractValues[typeof(bool)];
|
|
if (luatype == LuaType.String)
|
|
return _extractValues[typeof(string)];
|
|
if (luatype == LuaType.Table)
|
|
return _extractValues[typeof(LuaTable)];
|
|
if (luatype == LuaType.UserData)
|
|
return _extractValues[typeof(object)];
|
|
if (luatype == LuaType.Function)
|
|
return _extractValues[typeof(LuaFunction)];
|
|
if (luatype == LuaType.Number)
|
|
return _extractValues[typeof(double)];
|
|
}
|
|
bool netParamIsString = paramType == typeof(string) || paramType == typeof(char[]) || paramType == typeof(byte[]);
|
|
|
|
if (netParamIsNumeric)
|
|
{
|
|
if (luaState.IsNumber(stackPos) && !netParamIsString)
|
|
return _extractValues[paramType];
|
|
}
|
|
else if (paramType == typeof(bool))
|
|
{
|
|
if (luaState.IsBoolean(stackPos))
|
|
return _extractValues[paramType];
|
|
}
|
|
else if (netParamIsString)
|
|
{
|
|
if (luaState.IsString(stackPos))
|
|
return _extractValues[paramType];
|
|
if (luatype == LuaType.Nil)
|
|
return _extractNetObject; // kevinh - silently convert nil to a null string pointer
|
|
}
|
|
else if (paramType == typeof(LuaTable))
|
|
{
|
|
if (luatype == LuaType.Table || luatype == LuaType.Nil)
|
|
return _extractValues[paramType];
|
|
}
|
|
else if (paramType == typeof(LuaUserData))
|
|
{
|
|
if (luatype == LuaType.UserData || luatype == LuaType.Nil)
|
|
return _extractValues[paramType];
|
|
}
|
|
else if (paramType == typeof(LuaFunction))
|
|
{
|
|
if (luatype == LuaType.Function || luatype == LuaType.Nil)
|
|
return _extractValues[paramType];
|
|
}
|
|
else if (typeof(Delegate).IsAssignableFrom(paramType) && luatype == LuaType.Function && paramType.GetMethod("Invoke") != null)
|
|
return new DelegateGenerator(_translator, paramType).ExtractGenerated;
|
|
else if (paramType.IsInterface && luatype == LuaType.Table)
|
|
return new ClassGenerator(_translator, paramType).ExtractGenerated;
|
|
else if ((paramType.IsInterface || paramType.IsClass) && luatype == LuaType.Nil)
|
|
{
|
|
// kevinh - allow nil to be silently converted to null - extractNetObject will return null when the item ain't found
|
|
return _extractNetObject;
|
|
}
|
|
else if (luaState.Type(stackPos) == LuaType.Table)
|
|
{
|
|
if (luaState.GetMetaField(stackPos, "__index") != LuaType.Nil)
|
|
{
|
|
object obj = _translator.GetNetObject(luaState, -1);
|
|
luaState.SetTop(-2);
|
|
if (obj != null && paramType.IsInstanceOfType(obj))
|
|
return _extractNetObject;
|
|
}
|
|
else
|
|
return null;
|
|
}
|
|
else
|
|
{
|
|
object obj = _translator.GetNetObject(luaState, stackPos);
|
|
if (obj != null && paramType.IsInstanceOfType(obj))
|
|
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(LuaState luaState, int stackPos)
|
|
{
|
|
if (!luaState.IsNumericType(stackPos))
|
|
return null;
|
|
|
|
if (luaState.IsInteger(stackPos))
|
|
return (sbyte)luaState.ToInteger(stackPos);
|
|
|
|
return (sbyte)luaState.ToNumber(stackPos);
|
|
}
|
|
|
|
private object GetAsByte(LuaState luaState, int stackPos)
|
|
{
|
|
if (!luaState.IsNumericType(stackPos))
|
|
return null;
|
|
|
|
if (luaState.IsInteger(stackPos))
|
|
return (byte)luaState.ToInteger(stackPos);
|
|
|
|
return (byte)luaState.ToNumber(stackPos);
|
|
}
|
|
|
|
private object GetAsShort(LuaState luaState, int stackPos)
|
|
{
|
|
if (!luaState.IsNumericType(stackPos))
|
|
return null;
|
|
|
|
if (luaState.IsInteger(stackPos))
|
|
return (short)luaState.ToInteger(stackPos);
|
|
|
|
return (short)luaState.ToNumber(stackPos);
|
|
}
|
|
|
|
private object GetAsUshort(LuaState luaState, int stackPos)
|
|
{
|
|
if (!luaState.IsNumericType(stackPos))
|
|
return null;
|
|
|
|
if (luaState.IsInteger(stackPos))
|
|
return (ushort)luaState.ToInteger(stackPos);
|
|
|
|
return (ushort)luaState.ToNumber(stackPos);
|
|
}
|
|
|
|
private object GetAsInt(LuaState luaState, int stackPos)
|
|
{
|
|
if (!luaState.IsNumericType(stackPos))
|
|
return null;
|
|
|
|
if (luaState.IsInteger(stackPos))
|
|
return (int)luaState.ToInteger(stackPos);
|
|
|
|
return (int)luaState.ToNumber(stackPos);
|
|
}
|
|
|
|
private object GetAsUint(LuaState luaState, int stackPos)
|
|
{
|
|
if (!luaState.IsNumericType(stackPos))
|
|
return null;
|
|
|
|
if (luaState.IsInteger(stackPos))
|
|
return (uint)luaState.ToInteger(stackPos);
|
|
|
|
return (uint)luaState.ToNumber(stackPos);
|
|
}
|
|
|
|
private object GetAsLong(LuaState luaState, int stackPos)
|
|
{
|
|
if (!luaState.IsNumericType(stackPos))
|
|
return null;
|
|
|
|
if (luaState.IsInteger(stackPos))
|
|
return luaState.ToInteger(stackPos);
|
|
|
|
return (long)luaState.ToNumber(stackPos);
|
|
}
|
|
|
|
private object GetAsUlong(LuaState luaState, int stackPos)
|
|
{
|
|
if (!luaState.IsNumericType(stackPos))
|
|
return null;
|
|
|
|
if (luaState.IsInteger(stackPos))
|
|
return (ulong)luaState.ToInteger(stackPos);
|
|
|
|
return (ulong)luaState.ToNumber(stackPos);
|
|
}
|
|
|
|
private object GetAsDouble(LuaState luaState, int stackPos)
|
|
{
|
|
if (!luaState.IsNumericType(stackPos))
|
|
return null;
|
|
|
|
if (luaState.IsInteger(stackPos))
|
|
return (double)luaState.ToInteger(stackPos);
|
|
|
|
return luaState.ToNumber(stackPos);
|
|
}
|
|
|
|
private object GetAsChar(LuaState luaState, int stackPos)
|
|
{
|
|
if (!luaState.IsNumericType(stackPos))
|
|
return null;
|
|
|
|
if (luaState.IsInteger(stackPos))
|
|
return (char)luaState.ToInteger(stackPos);
|
|
|
|
return (char)luaState.ToNumber(stackPos);
|
|
}
|
|
|
|
private object GetAsFloat(LuaState luaState, int stackPos)
|
|
{
|
|
if (!luaState.IsNumericType(stackPos))
|
|
return null;
|
|
|
|
if (luaState.IsInteger(stackPos))
|
|
return (float)luaState.ToInteger(stackPos);
|
|
|
|
return (float)luaState.ToNumber(stackPos);
|
|
}
|
|
|
|
private object GetAsDecimal(LuaState luaState, int stackPos)
|
|
{
|
|
if (!luaState.IsNumericType(stackPos))
|
|
return null;
|
|
|
|
if (luaState.IsInteger(stackPos))
|
|
return (decimal)luaState.ToInteger(stackPos);
|
|
|
|
return (decimal)luaState.ToNumber(stackPos);
|
|
}
|
|
|
|
private object GetAsBoolean(LuaState luaState, int stackPos)
|
|
{
|
|
return luaState.ToBoolean(stackPos);
|
|
}
|
|
|
|
private object GetAsCharArray(LuaState luaState, int stackPos)
|
|
{
|
|
if (!luaState.IsString(stackPos))
|
|
return null;
|
|
string retVal = luaState.ToString(stackPos, false);
|
|
return retVal.ToCharArray();
|
|
}
|
|
|
|
private object GetAsByteArray(LuaState luaState, int stackPos)
|
|
{
|
|
if (!luaState.IsString(stackPos))
|
|
return null;
|
|
|
|
byte [] retVal = luaState.ToBuffer(stackPos, false);
|
|
return retVal;
|
|
}
|
|
|
|
private object GetAsString(LuaState luaState, int stackPos)
|
|
{
|
|
if (!luaState.IsString(stackPos))
|
|
return null;
|
|
return luaState.ToString(stackPos, false);
|
|
}
|
|
|
|
private object GetAsTable(LuaState luaState, int stackPos)
|
|
{
|
|
return _translator.GetTable(luaState, stackPos);
|
|
}
|
|
|
|
private object GetAsFunction(LuaState luaState, int stackPos)
|
|
{
|
|
return _translator.GetFunction(luaState, stackPos);
|
|
}
|
|
|
|
private object GetAsUserdata(LuaState luaState, int stackPos)
|
|
{
|
|
return _translator.GetUserData(luaState, stackPos);
|
|
}
|
|
|
|
public object GetAsObject(LuaState luaState, int stackPos)
|
|
{
|
|
if (luaState.Type(stackPos) == LuaType.Table)
|
|
{
|
|
if (luaState.GetMetaField(stackPos, "__index") != LuaType.Nil)
|
|
{
|
|
if (luaState.CheckMetaTable(-1, _translator.Tag))
|
|
{
|
|
luaState.Insert(stackPos);
|
|
luaState.Remove(stackPos + 1);
|
|
}
|
|
else
|
|
luaState.SetTop(-2);
|
|
}
|
|
}
|
|
|
|
object obj = _translator.GetObject(luaState, stackPos);
|
|
return obj;
|
|
}
|
|
|
|
public object GetAsNetObject(LuaState luaState, int stackPos)
|
|
{
|
|
object obj = _translator.GetNetObject(luaState, stackPos);
|
|
|
|
if (obj != null || luaState.Type(stackPos) != LuaType.Table)
|
|
return obj;
|
|
|
|
if (luaState.GetMetaField(stackPos, "__index") == LuaType.Nil)
|
|
return null;
|
|
|
|
if (luaState.CheckMetaTable(-1, _translator.Tag))
|
|
{
|
|
luaState.Insert(stackPos);
|
|
luaState.Remove(stackPos + 1);
|
|
obj = _translator.GetNetObject(luaState, stackPos);
|
|
}
|
|
else
|
|
luaState.SetTop(-2);
|
|
|
|
return obj;
|
|
}
|
|
}
|
|
}
|