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 _extractValues = new Dictionary(); 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; } } }