diff --git a/KeraLua.dll b/KeraLua.dll new file mode 100644 index 0000000..3209548 Binary files /dev/null and b/KeraLua.dll differ diff --git a/NLua.dll b/NLua.dll new file mode 100644 index 0000000..f9ff4e4 Binary files /dev/null and b/NLua.dll differ diff --git a/lua54.dll b/lua54.dll new file mode 100644 index 0000000..27a5f1d Binary files /dev/null and b/lua54.dll differ diff --git a/prebuild.xml b/prebuild.xml index 5cfeaba..76a0ca4 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -30,6 +30,10 @@ + + + + diff --git a/src/LUA/CheckType.cs b/src/LUA/CheckType.cs deleted file mode 100644 index 67d3234..0000000 --- a/src/LUA/CheckType.cs +++ /dev/null @@ -1,406 +0,0 @@ -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; - } - } -} diff --git a/src/LUA/Event/DebugHookEventArgs.cs b/src/LUA/Event/DebugHookEventArgs.cs deleted file mode 100644 index 6c75583..0000000 --- a/src/LUA/Event/DebugHookEventArgs.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using KeraLua; - -namespace NLua.Event -{ - /// - /// Event args for hook callback event - /// - public class DebugHookEventArgs : EventArgs - { - public DebugHookEventArgs(LuaDebug luaDebug) - { - LuaDebug = luaDebug; - } - - /// - /// Lua Debug Information - /// - public LuaDebug LuaDebug { get; } - } -} \ No newline at end of file diff --git a/src/LUA/Event/HookExceptionEventArgs.cs b/src/LUA/Event/HookExceptionEventArgs.cs deleted file mode 100644 index a38b11a..0000000 --- a/src/LUA/Event/HookExceptionEventArgs.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -namespace NLua.Event -{ - public class HookExceptionEventArgs : EventArgs - { - public Exception Exception { get; } - - public HookExceptionEventArgs(Exception ex) - { - Exception = ex; - } - } -} \ No newline at end of file diff --git a/src/LUA/Exceptions/LuaException.cs b/src/LUA/Exceptions/LuaException.cs deleted file mode 100644 index a157f68..0000000 --- a/src/LUA/Exceptions/LuaException.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; - -namespace NLua.Exceptions -{ - /// - /// Exceptions thrown by the Lua runtime - /// - [Serializable] - public class LuaException : Exception - { - public LuaException (string message) : base(message) - { - } - - public LuaException (string message, Exception innerException) : base(message, innerException) - { - } - - } -} \ No newline at end of file diff --git a/src/LUA/Exceptions/LuaScriptException.cs b/src/LUA/Exceptions/LuaScriptException.cs deleted file mode 100644 index 1045ca6..0000000 --- a/src/LUA/Exceptions/LuaScriptException.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; - -namespace NLua.Exceptions -{ - /// - /// Exceptions thrown by the Lua runtime because of errors in the script - /// - /// - [Serializable] - public class LuaScriptException : LuaException - { - /// - /// Returns true if the exception has occured as the result of a .NET exception in user code - /// - public bool IsNetException { get; } - - private readonly string _source; - - /// - /// The position in the script where the exception was triggered. - /// - public override string Source => _source; - - /// - /// Creates a new Lua-only exception. - /// - /// The message that describes the error. - /// The position in the script where the exception was triggered. - public LuaScriptException(string message, string source) : base(message) - { - _source = source; - } - - /// - /// Creates a new .NET wrapping exception. - /// - /// The .NET exception triggered by user-code. - /// The position in the script where the exception was triggered. - public LuaScriptException(Exception innerException, string source) - : base("A .NET exception occured in user-code", innerException) - { - _source = source; - IsNetException = true; - } - - public override string ToString() - { - // Prepend the error source - return GetType().FullName + ": " + _source + Message; - } - } -} \ No newline at end of file diff --git a/src/LUA/Extensions/LuaExtensions.cs b/src/LUA/Extensions/LuaExtensions.cs deleted file mode 100644 index 92ae177..0000000 --- a/src/LUA/Extensions/LuaExtensions.cs +++ /dev/null @@ -1,122 +0,0 @@ - -using System; -using System.Runtime.InteropServices; -using KeraLua; -using LuaState=KeraLua.Lua; - -namespace NLua.Extensions -{ - static class LuaExtensions - { - public static bool CheckMetaTable(this LuaState state, int index, IntPtr tag) - { - if (!state.GetMetaTable(index)) - return false; - - state.PushLightUserData(tag); - state.RawGet(-2); - bool isNotNil = !state.IsNil(-1); - state.SetTop(-3); - return isNotNil; - } - - public static void PopGlobalTable(this LuaState luaState) - { - luaState.RawSetInteger(LuaRegistry.Index, (long) LuaRegistryIndex.Globals); - } - - public static void GetRef (this LuaState luaState, int reference) - { - luaState.RawGetInteger(LuaRegistry.Index, reference); - } - - // ReSharper disable once IdentifierTypo - public static void Unref (this LuaState luaState, int reference) - { - luaState.Unref(LuaRegistry.Index, reference); - } - - public static bool AreEqual(this LuaState luaState, int ref1, int ref2) - { - return luaState.Compare(ref1, ref2, LuaCompare.Equal); - } - - public static IntPtr CheckUData(this LuaState state, int ud, string name) - { - IntPtr p = state.ToUserData(ud); - if (p == IntPtr.Zero) - return IntPtr.Zero; - if (!state.GetMetaTable(ud)) - return IntPtr.Zero; - - state.GetField(LuaRegistry.Index, name); - - bool isEqual = state.RawEqual(-1, -2); - - state.Pop(2); - - if (isEqual) - return p; - - return IntPtr.Zero; - } - - public static int ToNetObject(this LuaState state, int index, IntPtr tag) - { - if (state.Type(index) != LuaType.UserData) - return -1; - - IntPtr userData; - - if (state.CheckMetaTable(index, tag)) - { - userData = state.ToUserData(index); - if (userData != IntPtr.Zero) - return Marshal.ReadInt32(userData); - } - - userData = state.CheckUData(index, "luaNet_class"); - if (userData != IntPtr.Zero) - return Marshal.ReadInt32(userData); - - userData = state.CheckUData(index, "luaNet_searchbase"); - if (userData != IntPtr.Zero) - return Marshal.ReadInt32(userData); - - userData = state.CheckUData(index, "luaNet_function"); - if (userData != IntPtr.Zero) - return Marshal.ReadInt32(userData); - - return -1; - } - - public static void NewUData(this LuaState state, int val) - { - IntPtr pointer = state.NewUserData(Marshal.SizeOf(typeof(int))); - Marshal.WriteInt32(pointer, val); - } - - public static int RawNetObj(this LuaState state, int index) - { - IntPtr pointer = state.ToUserData(index); - if (pointer == IntPtr.Zero) - return -1; - - return Marshal.ReadInt32(pointer); - } - - public static int CheckUObject(this LuaState state, int index, string name) - { - IntPtr udata = state.CheckUData(index, name); - if (udata == IntPtr.Zero) - return -1; - - return Marshal.ReadInt32(udata); - } - - public static bool IsNumericType(this LuaState state, int index) - { - return state.Type(index) == LuaType.Number; - } - } -} diff --git a/src/LUA/Extensions/StringExtensions.cs b/src/LUA/Extensions/StringExtensions.cs deleted file mode 100644 index 0f74189..0000000 --- a/src/LUA/Extensions/StringExtensions.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Collections.Generic; - -namespace NLua.Extensions -{ - static class StringExtensions - { - public static IEnumerable SplitWithEscape(this string input, char separator, char escapeCharacter) - { - int start = 0; - int index = 0; - while (index < input.Length) - { - index = input.IndexOf(separator, index); - if (index == -1) - break; - - if (input[index - 1] == escapeCharacter) - { - input = input.Remove(index - 1, 1); - continue; - } - - - yield return input.Substring(start, index - start); - index++; - start = index; - } - yield return input.Substring(start); - } - } -} \ No newline at end of file diff --git a/src/LUA/Extensions/TypeExtensions.cs b/src/LUA/Extensions/TypeExtensions.cs deleted file mode 100644 index b88e5bf..0000000 --- a/src/LUA/Extensions/TypeExtensions.cs +++ /dev/null @@ -1,137 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Runtime.CompilerServices; - -namespace NLua.Extensions -{ - static class TypeExtensions - { - public static bool HasMethod(this Type t, string name) - { - var op = t.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static); - return op.Any(m => m.Name == name); - } - - public static bool HasAdditionOperator(this Type t) - { - if (t.IsPrimitive) - return true; - - return t.HasMethod("op_Addition"); - } - - public static bool HasSubtractionOperator(this Type t) - { - if (t.IsPrimitive) - return true; - - return t.HasMethod("op_Subtraction"); - } - - public static bool HasMultiplyOperator(this Type t) - { - if (t.IsPrimitive) - return true; - - return t.HasMethod("op_Multiply"); - } - - public static bool HasDivisionOperator(this Type t) - { - if (t.IsPrimitive) - return true; - - return t.HasMethod("op_Division"); - } - - public static bool HasModulusOperator(this Type t) - { - if (t.IsPrimitive) - return true; - - return t.HasMethod("op_Modulus"); - } - - public static bool HasUnaryNegationOperator(this Type t) - { - if (t.IsPrimitive) - return true; - // Unary - will always have only one version. - var op = t.GetMethod("op_UnaryNegation", BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static); - return op != null; - } - - public static bool HasEqualityOperator(this Type t) - { - if (t.IsPrimitive) - return true; - return t.HasMethod("op_Equality"); - } - - public static bool HasLessThanOperator(this Type t) - { - if (t.IsPrimitive) - return true; - - return t.HasMethod("op_LessThan"); - } - - public static bool HasLessThanOrEqualOperator(this Type t) - { - if (t.IsPrimitive) - return true; - return t.HasMethod("op_LessThanOrEqual"); - } - - public static MethodInfo[] GetMethods(this Type t, string name, BindingFlags flags) - { - return t.GetMethods(flags).Where(m => m.Name == name).ToArray(); - } - - public static MethodInfo[] GetExtensionMethods(this Type type, string name, IEnumerable assemblies = null) - { - var types = new List(); - - types.AddRange(type.Assembly.GetTypes().Where(t => t.IsPublic)); - - if (assemblies != null) - { - foreach (Assembly item in assemblies) - { - if (item == type.Assembly) - continue; - types.AddRange(item.GetTypes().Where(t => t.IsPublic && t.IsClass && t.IsSealed && t.IsAbstract && !t.IsNested)); - } - } - - var query = types - .SelectMany(extensionType => extensionType.GetMethods(name, BindingFlags.Static | BindingFlags.Public), - (extensionType, method) => new {extensionType, method}) - .Where(t => t.method.IsDefined(typeof(ExtensionAttribute), false)) - .Where(t => - t.method.GetParameters()[0].ParameterType == type || - t.method.GetParameters()[0].ParameterType.IsAssignableFrom(type) || - type.GetInterfaces().Contains(t.method.GetParameters()[0].ParameterType)) - .Select(t => t.method); - - return query.ToArray(); - } - - /// - /// Extends the System.Type-type to search for a given extended MethodeName. - /// - /// - /// - /// - /// - public static MethodInfo GetExtensionMethod(this Type t, string name, IEnumerable assemblies = null) - { - var mi = t.GetExtensionMethods(name, assemblies).ToArray(); - if (mi.Length == 0) - return null; - return mi[0]; - } - } -} \ No newline at end of file diff --git a/src/LUA/GenerateEventAssembly/ClassGenerator.cs b/src/LUA/GenerateEventAssembly/ClassGenerator.cs deleted file mode 100644 index 4e78279..0000000 --- a/src/LUA/GenerateEventAssembly/ClassGenerator.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using LuaState = KeraLua.Lua; - -namespace NLua -{ - class ClassGenerator - { - private readonly ObjectTranslator _translator; - private readonly Type _klass; - - public ClassGenerator(ObjectTranslator objTranslator, Type typeClass) - { - _translator = objTranslator; - _klass = typeClass; - } - - public object ExtractGenerated(LuaState luaState, int stackPos) - { - return CodeGeneration.Instance.GetClassInstance(_klass, _translator.GetTable(luaState, stackPos)); - } - } -} \ No newline at end of file diff --git a/src/LUA/GenerateEventAssembly/CodeGeneration.cs b/src/LUA/GenerateEventAssembly/CodeGeneration.cs deleted file mode 100644 index 8cac7ac..0000000 --- a/src/LUA/GenerateEventAssembly/CodeGeneration.cs +++ /dev/null @@ -1,752 +0,0 @@ -using System; -using System.Threading; -using System.Reflection; - -using System.Reflection.Emit; -using System.Collections.Generic; -using NLua.Method; - -namespace NLua -{ - class CodeGeneration - { - private readonly Dictionary _classCollection = new Dictionary(); - private readonly Dictionary _delegateCollection = new Dictionary(); - -#if !NETSTANDARD && !WINDOWS_UWP - private Dictionary eventHandlerCollection = new Dictionary(); - private Type eventHandlerParent = typeof(LuaEventHandler); - private Type delegateParent = typeof(LuaDelegate); - private Type classHelper = typeof(LuaClassHelper); - private AssemblyBuilder newAssembly; - private ModuleBuilder newModule; - private int luaClassNumber = 1; -#endif - - static CodeGeneration() - { - } - - private CodeGeneration() - { - // Create an assembly name - var assemblyName = new AssemblyName(); - assemblyName.Name = "NLua_generatedcode"; - // Create a new assembly with one module. -#if NETCOREAPP - newAssembly = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); - newModule = newAssembly.DefineDynamicModule("NLua_generatedcode"); -#elif !NETSTANDARD && !WINDOWS_UWP - newAssembly = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); - newModule = newAssembly.DefineDynamicModule("NLua_generatedcode"); -#endif - } - - /* - * Singleton instance of the class - */ - public static CodeGeneration Instance { get; } = new CodeGeneration(); - - /* - * Generates an event handler that calls a Lua function - */ - private Type GenerateEvent(Type eventHandlerType) - { -#if NETSTANDARD || WINDOWS_UWP - throw new NotImplementedException(" Emit not available on .NET Standard "); -#else - string typeName; - lock (this) - { - typeName = "LuaGeneratedClass" + luaClassNumber; - luaClassNumber++; - } - - // Define a public class in the assembly, called typeName - var myType = newModule.DefineType(typeName, TypeAttributes.Public, eventHandlerParent); - - // Defines the handler method. Its signature is void(object, ) - var paramTypes = new Type[2]; - paramTypes[0] = typeof(object); - paramTypes[1] = eventHandlerType; - var returnType = typeof(void); - var handleMethod = myType.DefineMethod("HandleEvent", MethodAttributes.Public | MethodAttributes.HideBySig, returnType, paramTypes); - - // Emits the IL for the method. It loads the arguments - // and calls the handleEvent method of the base class - ILGenerator generator = handleMethod.GetILGenerator(); - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldarg_1); - generator.Emit(OpCodes.Ldarg_2); - var miGenericEventHandler = eventHandlerParent.GetMethod("HandleEvent"); - generator.Emit(OpCodes.Call, miGenericEventHandler); - // returns - generator.Emit(OpCodes.Ret); - // creates the new type - return myType.CreateType(); -#endif - } - - /* - * Generates a type that can be used for instantiating a delegate - * of the provided type, given a Lua function. - */ - private Type GenerateDelegate(Type delegateType) - { -#if NETSTANDARD || WINDOWS_UWP - throw new NotImplementedException("GenerateDelegate is not available on Windows Store, please register your LuaDelegate type with Lua.RegisterLuaDelegateType( yourDelegate, theLuaDelegateHandler) "); -#else - string typeName; - lock (this) - { - typeName = "LuaGeneratedClass" + luaClassNumber; - luaClassNumber++; - } - - // Define a public class in the assembly, called typeName - var myType = newModule.DefineType(typeName, TypeAttributes.Public, delegateParent); - - // Defines the delegate method with the same signature as the - // Invoke method of delegateType - var invokeMethod = delegateType.GetMethod("Invoke"); - var paramInfo = invokeMethod.GetParameters(); - var paramTypes = new Type[paramInfo.Length]; - var returnType = invokeMethod.ReturnType; - - // Counts out and ref params, for use later - int nOutParams = 0; - int nOutAndRefParams = 0; - - for (int i = 0; i < paramTypes.Length; i++) - { - paramTypes[i] = paramInfo[i].ParameterType; - - if ((!paramInfo[i].IsIn) && paramInfo[i].IsOut) - nOutParams++; - - if (paramTypes[i].IsByRef) - nOutAndRefParams++; - } - - int[] refArgs = new int[nOutAndRefParams]; - var delegateMethod = myType.DefineMethod("CallFunction", invokeMethod.Attributes, returnType, paramTypes); - - // Generates the IL for the method - ILGenerator generator = delegateMethod.GetILGenerator(); - generator.DeclareLocal(typeof(object[])); // original arguments - generator.DeclareLocal(typeof(object[])); // with out-only arguments removed - generator.DeclareLocal(typeof(int[])); // indexes of out and ref arguments - - if (!(returnType == typeof(void))) // return value - generator.DeclareLocal(returnType); - else - generator.DeclareLocal(typeof(object)); - - // Initializes local variables - generator.Emit(OpCodes.Ldc_I4, paramTypes.Length); - generator.Emit(OpCodes.Newarr, typeof(object)); - generator.Emit(OpCodes.Stloc_0); - generator.Emit(OpCodes.Ldc_I4, paramTypes.Length - nOutParams); - generator.Emit(OpCodes.Newarr, typeof(object)); - generator.Emit(OpCodes.Stloc_1); - generator.Emit(OpCodes.Ldc_I4, nOutAndRefParams); - generator.Emit(OpCodes.Newarr, typeof(int)); - generator.Emit(OpCodes.Stloc_2); - - // Stores the arguments in the local variables - for (int iArgs = 0, iInArgs = 0, iOutArgs = 0; iArgs < paramTypes.Length; iArgs++) - { - generator.Emit(OpCodes.Ldloc_0); - generator.Emit(OpCodes.Ldc_I4, iArgs); - generator.Emit(OpCodes.Ldarg, iArgs + 1); - - if (paramTypes[iArgs].IsByRef) - { - if (paramTypes[iArgs].GetElementType().IsValueType) - { - generator.Emit(OpCodes.Ldobj, paramTypes[iArgs].GetElementType()); - generator.Emit(OpCodes.Box, paramTypes[iArgs].GetElementType()); - } - else - generator.Emit(OpCodes.Ldind_Ref); - } - else - { - if (paramTypes[iArgs].IsValueType) - generator.Emit(OpCodes.Box, paramTypes[iArgs]); - } - - generator.Emit(OpCodes.Stelem_Ref); - - if (paramTypes[iArgs].IsByRef) - { - generator.Emit(OpCodes.Ldloc_2); - generator.Emit(OpCodes.Ldc_I4, iOutArgs); - generator.Emit(OpCodes.Ldc_I4, iArgs); - generator.Emit(OpCodes.Stelem_I4); - refArgs[iOutArgs] = iArgs; - iOutArgs++; - } - - if (paramInfo[iArgs].IsIn || (!paramInfo[iArgs].IsOut)) - { - generator.Emit(OpCodes.Ldloc_1); - generator.Emit(OpCodes.Ldc_I4, iInArgs); - generator.Emit(OpCodes.Ldarg, iArgs + 1); - - if (paramTypes[iArgs].IsByRef) - { - if (paramTypes[iArgs].GetElementType().IsValueType) - { - generator.Emit(OpCodes.Ldobj, paramTypes[iArgs].GetElementType()); - generator.Emit(OpCodes.Box, paramTypes[iArgs].GetElementType()); - } - else - generator.Emit(OpCodes.Ldind_Ref); - } - else - { - if (paramTypes[iArgs].IsValueType) - generator.Emit(OpCodes.Box, paramTypes[iArgs]); - } - - generator.Emit(OpCodes.Stelem_Ref); - iInArgs++; - } - } - - // Calls the callFunction method of the base class - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldloc_0); - generator.Emit(OpCodes.Ldloc_1); - generator.Emit(OpCodes.Ldloc_2); - var miGenericEventHandler = delegateParent.GetMethod("CallFunction"); - generator.Emit(OpCodes.Call, miGenericEventHandler); - - // Stores return value - if (returnType == typeof(void)) - { - generator.Emit(OpCodes.Pop); - generator.Emit(OpCodes.Ldnull); - } - else if (returnType.IsValueType) - { - generator.Emit(OpCodes.Unbox, returnType); - generator.Emit(OpCodes.Ldobj, returnType); - } - else - generator.Emit(OpCodes.Castclass, returnType); - - generator.Emit(OpCodes.Stloc_3); - - // Stores new value of out and ref params - for (int i = 0; i < refArgs.Length; i++) - { - generator.Emit(OpCodes.Ldarg, refArgs[i] + 1); - generator.Emit(OpCodes.Ldloc_0); - generator.Emit(OpCodes.Ldc_I4, refArgs[i]); - generator.Emit(OpCodes.Ldelem_Ref); - - if (paramTypes[refArgs[i]].GetElementType().IsValueType) - { - generator.Emit(OpCodes.Unbox, paramTypes[refArgs[i]].GetElementType()); - generator.Emit(OpCodes.Ldobj, paramTypes[refArgs[i]].GetElementType()); - generator.Emit(OpCodes.Stobj, paramTypes[refArgs[i]].GetElementType()); - } - else - { - generator.Emit(OpCodes.Castclass, paramTypes[refArgs[i]].GetElementType()); - generator.Emit(OpCodes.Stind_Ref); - } - } - - // Returns - if (!(returnType == typeof(void))) - generator.Emit(OpCodes.Ldloc_3); - - generator.Emit(OpCodes.Ret); - return myType.CreateType(); // creates the new type -#endif - } - - void GetReturnTypesFromClass(Type klass, out Type[][] returnTypes) - { - var classMethods = klass.GetMethods(); - returnTypes = new Type[classMethods.Length][]; - - int i = 0; - - foreach (var method in classMethods) - { - if (klass.IsInterface) - { - GetReturnTypesFromMethod(method, out returnTypes[i]); - i++; - } - else if (!method.IsPrivate && !method.IsFinal && method.IsVirtual) - { - GetReturnTypesFromMethod(method, out returnTypes[i]); - i++; - } - } - } - - /* - * Generates an implementation of klass, if it is an interface, or - * a subclass of klass that delegates its virtual methods to a Lua table. - */ - public void GenerateClass(Type klass, out Type newType, out Type[][] returnTypes) - { - -#if NETSTANDARD || WINDOWS_UWP - throw new NotImplementedException (" Emit not available on .NET Standard "); -#else - string typeName; - lock (this) - { - typeName = "LuaGeneratedClass" + luaClassNumber; - luaClassNumber++; - } - - TypeBuilder myType; - // Define a public class in the assembly, called typeName - if (klass.IsInterface) - myType = newModule.DefineType(typeName, TypeAttributes.Public, typeof(object), new Type[] { - klass, - typeof(ILuaGeneratedType) - }); - else - myType = newModule.DefineType(typeName, TypeAttributes.Public, klass, new Type[] { typeof(ILuaGeneratedType) }); - - // Field that stores the Lua table - var luaTableField = myType.DefineField("__luaInterface_luaTable", typeof(LuaTable), FieldAttributes.Public); - // Field that stores the return types array - var returnTypesField = myType.DefineField("__luaInterface_returnTypes", typeof(Type[][]), FieldAttributes.Public); - // Generates the constructor for the new type, it takes a Lua table and an array - // of return types and stores them in the respective fields - var constructor = myType.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { - typeof(LuaTable), - typeof(Type[][]) - }); - ILGenerator generator = constructor.GetILGenerator(); - generator.Emit(OpCodes.Ldarg_0); - - if (klass.IsInterface) - generator.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes)); - else - generator.Emit(OpCodes.Call, klass.GetConstructor(Type.EmptyTypes)); - - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldarg_1); - generator.Emit(OpCodes.Stfld, luaTableField); - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldarg_2); - generator.Emit(OpCodes.Stfld, returnTypesField); - generator.Emit(OpCodes.Ret); - // Generates overriden versions of the klass' public virtual methods - var classMethods = klass.GetMethods(); - returnTypes = new Type[classMethods.Length][]; - int i = 0; - - foreach (var method in classMethods) - { - if (klass.IsInterface) - { - GenerateMethod(myType, method, MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.NewSlot, - i, luaTableField, returnTypesField, false, out returnTypes[i]); - i++; - } - else - { - if (!method.IsPrivate && !method.IsFinal && method.IsVirtual) - { - GenerateMethod(myType, method, (method.Attributes | MethodAttributes.NewSlot) ^ MethodAttributes.NewSlot, i, - luaTableField, returnTypesField, true, out returnTypes[i]); - i++; - } - } - } - - // Generates an implementation of the luaInterfaceGetLuaTable method - var returnTableMethod = myType.DefineMethod("LuaInterfaceGetLuaTable", - MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual, typeof(LuaTable), new Type[0]); - myType.DefineMethodOverride(returnTableMethod, typeof(ILuaGeneratedType).GetMethod("LuaInterfaceGetLuaTable")); - generator = returnTableMethod.GetILGenerator(); - generator.Emit(OpCodes.Ldfld, luaTableField); - generator.Emit(OpCodes.Ret); - newType = myType.CreateType(); // Creates the type -#endif - } - - void GetReturnTypesFromMethod(MethodInfo method, out Type[] returnTypes) - { - var paramInfo = method.GetParameters(); - var paramTypes = new Type[paramInfo.Length]; - var returnTypesList = new List(); - - // Counts out and ref parameters, for later use, - // and creates the list of return types - int nOutParams = 0; - int nOutAndRefParams = 0; - var returnType = method.ReturnType; - returnTypesList.Add(returnType); - - for (int i = 0; i < paramTypes.Length; i++) - { - paramTypes[i] = paramInfo[i].ParameterType; - - if (!paramInfo[i].IsIn && paramInfo[i].IsOut) - { - nOutParams++; - } - - if (paramTypes[i].IsByRef) - { - returnTypesList.Add(paramTypes[i].GetElementType()); - nOutAndRefParams++; - } - } - - returnTypes = returnTypesList.ToArray(); - } - -#if !NETSTANDARD && !WINDOWS_UWP - - /* - * Generates an overriden implementation of method inside myType that delegates - * to a function in a Lua table with the same name, if the function exists. If it - * doesn't the method calls the base method (or does nothing, in case of interface - * implementations). - */ - private void GenerateMethod(TypeBuilder myType, MethodInfo method, MethodAttributes attributes, int methodIndex, - FieldInfo luaTableField, FieldInfo returnTypesField, bool generateBase, out Type[] returnTypes) - { - var paramInfo = method.GetParameters(); - var paramTypes = new Type[paramInfo.Length]; - var returnTypesList = new List(); - - // Counts out and ref parameters, for later use, - // and creates the list of return types - int nOutParams = 0; - int nOutAndRefParams = 0; - var returnType = method.ReturnType; - returnTypesList.Add(returnType); - - for (int i = 0; i < paramTypes.Length; i++) - { - paramTypes[i] = paramInfo[i].ParameterType; - if (!paramInfo[i].IsIn && paramInfo[i].IsOut) - nOutParams++; - - if (paramTypes[i].IsByRef) - { - returnTypesList.Add(paramTypes[i].GetElementType()); - nOutAndRefParams++; - } - } - - int[] refArgs = new int[nOutAndRefParams]; - returnTypes = returnTypesList.ToArray(); - - // Generates a version of the method that calls the base implementation - // directly, for use by the base field of the table - if (generateBase) - { - var baseMethod = myType.DefineMethod("__luaInterface_base_" + method.Name, - MethodAttributes.Private | MethodAttributes.NewSlot | MethodAttributes.HideBySig, - returnType, paramTypes); - ILGenerator generatorBase = baseMethod.GetILGenerator(); - generatorBase.Emit(OpCodes.Ldarg_0); - - for (int i = 0; i < paramTypes.Length; i++) - generatorBase.Emit(OpCodes.Ldarg, i + 1); - - generatorBase.Emit(OpCodes.Call, method); - - if (returnType == typeof(void)) - generatorBase.Emit(OpCodes.Pop); - - generatorBase.Emit(OpCodes.Ret); - } - - // Defines the method - var methodImpl = myType.DefineMethod(method.Name, attributes, returnType, paramTypes); - - // If it's an implementation of an interface tells what method it - // is overriding - if (myType.BaseType.Equals(typeof(object))) - myType.DefineMethodOverride(methodImpl, method); - - ILGenerator generator = methodImpl.GetILGenerator(); - generator.DeclareLocal(typeof(object[])); // original arguments - generator.DeclareLocal(typeof(object[])); // with out-only arguments removed - generator.DeclareLocal(typeof(int[])); // indexes of out and ref arguments - - if (!(returnType == typeof(void))) // return value - generator.DeclareLocal(returnType); - else - generator.DeclareLocal(typeof(object)); - - // Initializes local variables - generator.Emit(OpCodes.Ldc_I4, paramTypes.Length); - generator.Emit(OpCodes.Newarr, typeof(object)); - generator.Emit(OpCodes.Stloc_0); - generator.Emit(OpCodes.Ldc_I4, paramTypes.Length - nOutParams + 1); - generator.Emit(OpCodes.Newarr, typeof(object)); - generator.Emit(OpCodes.Stloc_1); - generator.Emit(OpCodes.Ldc_I4, nOutAndRefParams); - generator.Emit(OpCodes.Newarr, typeof(int)); - generator.Emit(OpCodes.Stloc_2); - generator.Emit(OpCodes.Ldloc_1); - generator.Emit(OpCodes.Ldc_I4_0); - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldfld, luaTableField); - generator.Emit(OpCodes.Stelem_Ref); - - // Stores the arguments into the local variables, as needed - for (int iArgs = 0, iInArgs = 1, iOutArgs = 0; iArgs < paramTypes.Length; iArgs++) - { - generator.Emit(OpCodes.Ldloc_0); - generator.Emit(OpCodes.Ldc_I4, iArgs); - generator.Emit(OpCodes.Ldarg, iArgs + 1); - - if (paramTypes[iArgs].IsByRef) - { - if (paramTypes[iArgs].GetElementType().IsValueType) - { - generator.Emit(OpCodes.Ldobj, paramTypes[iArgs].GetElementType()); - generator.Emit(OpCodes.Box, paramTypes[iArgs].GetElementType()); - } - else - generator.Emit(OpCodes.Ldind_Ref); - } - else - { - if (paramTypes[iArgs].IsValueType) - generator.Emit(OpCodes.Box, paramTypes[iArgs]); - } - - generator.Emit(OpCodes.Stelem_Ref); - - if (paramTypes[iArgs].IsByRef) - { - generator.Emit(OpCodes.Ldloc_2); - generator.Emit(OpCodes.Ldc_I4, iOutArgs); - generator.Emit(OpCodes.Ldc_I4, iArgs); - generator.Emit(OpCodes.Stelem_I4); - refArgs[iOutArgs] = iArgs; - iOutArgs++; - } - - if (paramInfo[iArgs].IsIn || (!paramInfo[iArgs].IsOut)) - { - generator.Emit(OpCodes.Ldloc_1); - generator.Emit(OpCodes.Ldc_I4, iInArgs); - generator.Emit(OpCodes.Ldarg, iArgs + 1); - - if (paramTypes[iArgs].IsByRef) - { - if (paramTypes[iArgs].GetElementType().IsValueType) - { - generator.Emit(OpCodes.Ldobj, paramTypes[iArgs].GetElementType()); - generator.Emit(OpCodes.Box, paramTypes[iArgs].GetElementType()); - } - else - generator.Emit(OpCodes.Ldind_Ref); - } - else - { - if (paramTypes[iArgs].IsValueType) - generator.Emit(OpCodes.Box, paramTypes[iArgs]); - } - - generator.Emit(OpCodes.Stelem_Ref); - iInArgs++; - } - } - - // Gets the function the method will delegate to by calling - // the getTableFunction method of class LuaClassHelper - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldfld, luaTableField); - generator.Emit(OpCodes.Ldstr, method.Name); - generator.Emit(OpCodes.Call, classHelper.GetMethod("GetTableFunction")); - var lab1 = generator.DefineLabel(); - generator.Emit(OpCodes.Dup); - generator.Emit(OpCodes.Brtrue_S, lab1); - // Function does not exist, call base method - generator.Emit(OpCodes.Pop); - - if (!method.IsAbstract) - { - generator.Emit(OpCodes.Ldarg_0); - - for (int i = 0; i < paramTypes.Length; i++) - generator.Emit(OpCodes.Ldarg, i + 1); - - generator.Emit(OpCodes.Call, method); - - if (returnType == typeof(void)) - generator.Emit(OpCodes.Pop); - - generator.Emit(OpCodes.Ret); - generator.Emit(OpCodes.Ldnull); - } - else - generator.Emit(OpCodes.Ldnull); - - var lab2 = generator.DefineLabel(); - generator.Emit(OpCodes.Br_S, lab2); - generator.MarkLabel(lab1); - // Function exists, call using method callFunction of LuaClassHelper - generator.Emit(OpCodes.Ldloc_0); - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldfld, returnTypesField); - generator.Emit(OpCodes.Ldc_I4, methodIndex); - generator.Emit(OpCodes.Ldelem_Ref); - generator.Emit(OpCodes.Ldloc_1); - generator.Emit(OpCodes.Ldloc_2); - generator.Emit(OpCodes.Call, classHelper.GetMethod("CallFunction")); - generator.MarkLabel(lab2); - - // Stores the function return value - if (returnType == typeof(void)) - { - generator.Emit(OpCodes.Pop); - generator.Emit(OpCodes.Ldnull); - } - else if (returnType.IsValueType) - { - generator.Emit(OpCodes.Unbox, returnType); - generator.Emit(OpCodes.Ldobj, returnType); - } - else - generator.Emit(OpCodes.Castclass, returnType); - - generator.Emit(OpCodes.Stloc_3); - - // Sets return values of out and ref parameters - for (int i = 0; i < refArgs.Length; i++) - { - generator.Emit(OpCodes.Ldarg, refArgs[i] + 1); - generator.Emit(OpCodes.Ldloc_0); - generator.Emit(OpCodes.Ldc_I4, refArgs[i]); - generator.Emit(OpCodes.Ldelem_Ref); - - if (paramTypes[refArgs[i]].GetElementType().IsValueType) - { - generator.Emit(OpCodes.Unbox, paramTypes[refArgs[i]].GetElementType()); - generator.Emit(OpCodes.Ldobj, paramTypes[refArgs[i]].GetElementType()); - generator.Emit(OpCodes.Stobj, paramTypes[refArgs[i]].GetElementType()); - } - else - { - generator.Emit(OpCodes.Castclass, paramTypes[refArgs[i]].GetElementType()); - generator.Emit(OpCodes.Stind_Ref); - } - } - - // Returns - if (!(returnType == typeof(void))) - generator.Emit(OpCodes.Ldloc_3); - - generator.Emit(OpCodes.Ret); - } -#endif - /* - * Gets an event handler for the event type that delegates to the eventHandler Lua function. - * Caches the generated type. - */ - public LuaEventHandler GetEvent(Type eventHandlerType, LuaFunction eventHandler) - { -#if NETSTANDARD || WINDOWS_UWP - throw new NotImplementedException (" Emit not available on .NET Standard "); -#else - Type eventConsumerType; - - if (eventHandlerCollection.ContainsKey(eventHandlerType)) - eventConsumerType = eventHandlerCollection[eventHandlerType]; - else - { - eventConsumerType = GenerateEvent(eventHandlerType); - eventHandlerCollection[eventHandlerType] = eventConsumerType; - } - - var luaEventHandler = (LuaEventHandler)Activator.CreateInstance(eventConsumerType); - luaEventHandler.Handler = eventHandler; - return luaEventHandler; -#endif - } - - public void RegisterLuaDelegateType(Type delegateType, Type luaDelegateType) - { - _delegateCollection[delegateType] = luaDelegateType; - } - - public void RegisterLuaClassType(Type klass, Type luaClass) - { - var luaClassType = new LuaClassType(); - luaClassType.klass = luaClass; - GetReturnTypesFromClass(klass, out luaClassType.returnTypes); - _classCollection[klass] = luaClassType; - } - /* - * Gets a delegate with delegateType that calls the luaFunc Lua function - * Caches the generated type. - */ - public Delegate GetDelegate(Type delegateType, LuaFunction luaFunc) - { - var returnTypes = new List(); - Type luaDelegateType; - - if (_delegateCollection.ContainsKey(delegateType)) - { - luaDelegateType = _delegateCollection[delegateType]; - } - else - { - luaDelegateType = GenerateDelegate(delegateType); - _delegateCollection[delegateType] = luaDelegateType; - } - - var methodInfo = delegateType.GetMethod("Invoke"); - returnTypes.Add(methodInfo.ReturnType); - - foreach (ParameterInfo paramInfo in methodInfo.GetParameters()) - { - if (paramInfo.ParameterType.IsByRef) - returnTypes.Add(paramInfo.ParameterType); - } - - var luaDelegate = (LuaDelegate)Activator.CreateInstance(luaDelegateType); - luaDelegate.Function = luaFunc; - luaDelegate.ReturnTypes = returnTypes.ToArray(); - return Delegate.CreateDelegate(delegateType, luaDelegate, "CallFunction"); - } - - /* - * Gets an instance of an implementation of the klass interface or - * subclass of klass that delegates public virtual methods to the - * luaTable table. - * Caches the generated type. - */ - public object GetClassInstance(Type klass, LuaTable luaTable) - { - LuaClassType luaClassType; - - if (_classCollection.ContainsKey(klass)) - luaClassType = _classCollection[klass]; - else - { - luaClassType = new LuaClassType(); - GenerateClass(klass, out luaClassType.klass, out luaClassType.returnTypes); - _classCollection[klass] = luaClassType; - } - - return Activator.CreateInstance(luaClassType.klass, new object[] { - luaTable, - luaClassType.returnTypes - }); - } - } -} diff --git a/src/LUA/GenerateEventAssembly/DelegateGenerator.cs b/src/LUA/GenerateEventAssembly/DelegateGenerator.cs deleted file mode 100644 index 62ad271..0000000 --- a/src/LUA/GenerateEventAssembly/DelegateGenerator.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using LuaState = KeraLua.Lua; - -namespace NLua -{ - class DelegateGenerator - { - private readonly ObjectTranslator _translator; - private readonly Type _delegateType; - - public DelegateGenerator(ObjectTranslator objectTranslator, Type type) - { - _translator = objectTranslator; - _delegateType = type; - } - - public object ExtractGenerated(LuaState luaState, int stackPos) - { - return CodeGeneration.Instance.GetDelegate(_delegateType, _translator.GetFunction(luaState, stackPos)); - } - } -} \ No newline at end of file diff --git a/src/LUA/GenerateEventAssembly/ILuaGeneratedType.cs b/src/LUA/GenerateEventAssembly/ILuaGeneratedType.cs deleted file mode 100644 index 37499e1..0000000 --- a/src/LUA/GenerateEventAssembly/ILuaGeneratedType.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace NLua -{ - /* - * Common interface for types generated from tables. The method - * returns the table that overrides some or all of the type's methods. - */ - public interface ILuaGeneratedType - { - LuaTable LuaInterfaceGetLuaTable(); - } -} \ No newline at end of file diff --git a/src/LUA/GenerateEventAssembly/LuaClassType.cs b/src/LUA/GenerateEventAssembly/LuaClassType.cs deleted file mode 100644 index 8b861d7..0000000 --- a/src/LUA/GenerateEventAssembly/LuaClassType.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace NLua -{ - /* - * Structure to store a type and the return types of - * its methods (the type of the returned value and out/ref - * parameters). - */ - struct LuaClassType - { - public Type klass; - public Type[][] returnTypes; - } -} \ No newline at end of file diff --git a/src/LUA/Lua.cs b/src/LUA/Lua.cs deleted file mode 100644 index 00c288d..0000000 --- a/src/LUA/Lua.cs +++ /dev/null @@ -1,1262 +0,0 @@ -using System; -using System.Linq; -using System.Reflection; -using System.Collections.Generic; -using System.Runtime.InteropServices; -using KeraLua; - -using NLua.Event; -using NLua.Method; -using NLua.Exceptions; -using NLua.Extensions; - -#if __IOS__ || __TVOS__ || __WATCHOS__ - using ObjCRuntime; -#endif - -using LuaState = KeraLua.Lua; -using LuaNativeFunction = KeraLua.LuaFunction; - - -namespace NLua -{ - public class Lua : IDisposable - { - #region lua debug functions - /// - /// Event that is raised when an exception occures during a hook call. - /// - public event EventHandler HookException; - /// - /// Event when lua hook callback is called - /// - /// - /// Is only raised if SetDebugHook is called before. - /// - public event EventHandler DebugHook; - /// - /// lua hook calback delegate - /// - private LuaHookFunction _hookCallback; - #endregion - #region Globals auto-complete - private readonly List _globals = new List(); - private bool _globalsSorted; - #endregion - private LuaState _luaState; - /// - /// True while a script is being executed - /// - public bool IsExecuting => _executing; - - public LuaState State => _luaState; - - private ObjectTranslator _translator; - - /// - /// Used to ensure multiple .net threads all get serialized by this single lock for access to the lua stack/objects - /// - //private object luaLock = new object(); - private bool _StatePassed; - private bool _executing; - - // The commented code bellow is the initLua, the code assigned here is minified for size/performance reasons. - private const string InitLuanet = @"local a={}local rawget=rawget;local b=luanet.import_type;local c=luanet.load_assembly;luanet.error,luanet.type=error,type;function a:__index(d)local e=rawget(self,'.fqn')e=(e and e..'.'or'')..d;local f=rawget(luanet,d)or b(e)if f==nil then pcall(c,e)f={['.fqn']=e}setmetatable(f,a)end;rawset(self,d,f)return f end;function a:__call(...)error('No such type: '..rawget(self,'.fqn'),2)end;luanet['.fqn']=false;setmetatable(luanet,a)luanet.load_assembly('mscorlib')"; - //@"local metatable = {} - // local rawget = rawget - // local import_type = luanet.import_type - // local load_assembly = luanet.load_assembly - // luanet.error, luanet.type = error, type - // -- Lookup a .NET identifier component. - // function metatable:__index(key) -- key is e.g. 'Form' - // -- Get the fully-qualified name, e.g. 'System.Windows.Forms.Form' - // local fqn = rawget(self,'.fqn') - // fqn = ((fqn and fqn .. '.') or '') .. key - - // -- Try to find either a luanet function or a CLR type - // local obj = rawget(luanet,key) or import_type(fqn) - - // -- If key is neither a luanet function or a CLR type, then it is simply - // -- an identifier component. - // if obj == nil then - // -- It might be an assembly, so we load it too. - // pcall(load_assembly,fqn) - // obj = { ['.fqn'] = fqn } - // setmetatable(obj, metatable) - // end - - // -- Cache this lookup - // rawset(self, key, obj) - // return obj - // end - - // -- A non-type has been called; e.g. foo = System.Foo() - // function metatable:__call(...) - // error('No such type: ' .. rawget(self,'.fqn'), 2) - // end - - // -- This is the root of the .NET namespace - // luanet['.fqn'] = false - // setmetatable(luanet, metatable) - - // -- Preload the mscorlib assembly - // luanet.load_assembly('mscorlib')"; - - private const string ClrPackage = @"if not luanet then require'luanet'end;local a,b=luanet.import_type,luanet.load_assembly;local c={__index=function(d,e)local f=rawget(d,e)if f==nil then f=a(d.packageName.."".""..e)if f==nil then f=a(e)end;d[e]=f end;return f end}function luanet.namespace(g)if type(g)=='table'then local h={}for i=1,#g do h[i]=luanet.namespace(g[i])end;return unpack(h)end;local j={packageName=g}setmetatable(j,c)return j end;local k,l;local function m()l={}k={__index=function(n,e)for i,d in ipairs(l)do local f=d[e]if f then _G[e]=f;return f end end end}setmetatable(_G,k)end;function CLRPackage(o,p)p=p or o;local q=pcall(b,o)return luanet.namespace(p)end;function import(o,p)if not k then m()end;if not p then local i=o:find('%.dll$')if i then p=o:sub(1,i-1)else p=o end end;local j=CLRPackage(o,p)table.insert(l,j)return j end;function luanet.make_array(r,s)local t=r[#s]for i,u in ipairs(s)do t:SetValue(u,i-1)end;return t end;function luanet.each(v)local w=v:GetEnumerator()return function()if w:MoveNext()then return w.Current end end end"; -//@"--- -//--- This lua module provides auto importing of .net classes into a named package. -//--- Makes for super easy use of LuaInterface glue -//--- -//--- example: -//--- Threading = CLRPackage(""System"", ""System.Threading"") -//--- Threading.Thread.Sleep(100) -//--- -//--- Extensions: -//--- import() is a version of CLRPackage() which puts the package into a list which is used by a global __index lookup, -//--- and thus works rather like C#'s using statement. It also recognizes the case where one is importing a local -//--- assembly, which must end with an explicit .dll extension. - -//--- Alternatively, luanet.namespace can be used for convenience without polluting the global namespace: -//--- local sys,sysi = luanet.namespace {'System','System.IO'} -//-- sys.Console.WriteLine(""we are at {0}"",sysi.Directory.GetCurrentDirectory()) - - -//-- LuaInterface hosted with stock Lua interpreter will need to explicitly require this... -//if not luanet then require 'luanet' end - -//local import_type, load_assembly = luanet.import_type, luanet.load_assembly - -//local mt = { -// --- Lookup a previously unfound class and add it to our table -// __index = function(package, classname) -// local class = rawget(package, classname) -// if class == nil then -// class = import_type(package.packageName .. ""."" .. classname) -// if class == nil then class = import_type(classname) end -// package[classname] = class -- keep what we found around, so it will be shared -// end -// return class -// end -//} - -//function luanet.namespace(ns) -// if type(ns) == 'table' then -// local res = {} -// for i = 1,#ns do -// res[i] = luanet.namespace(ns[i]) -// end -// return unpack(res) -// end -// -- FIXME - table.packageName could instead be a private index (see Lua 13.4.4) -// local t = { packageName = ns } -// setmetatable(t,mt) -// return t -//end - -//local globalMT, packages - -//local function set_global_mt() -// packages = {} -// globalMT = { -// __index = function(T,classname) -// for i,package in ipairs(packages) do -// local class = package[classname] -// if class then -// _G[classname] = class -// return class -// end -// end -// end -// } -// setmetatable(_G, globalMT) -//end - -//--- Create a new Package class -//function CLRPackage(assemblyName, packageName) -// -- a sensible default... -// packageName = packageName or assemblyName -// local ok = pcall(load_assembly,assemblyName) -- Make sure our assembly is loaded -// return luanet.namespace(packageName) -//end - -//function import (assemblyName, packageName) -// if not globalMT then -// set_global_mt() -// end -// if not packageName then -// local i = assemblyName:find('%.dll$') -// if i then packageName = assemblyName:sub(1,i-1) -// else packageName = assemblyName end -// end -// local t = CLRPackage(assemblyName,packageName) -// table.insert(packages,t) -// return t -//end - - -//function luanet.make_array (tp,tbl) -// local arr = tp[#tbl] -// for i,v in ipairs(tbl) do -// arr:SetValue(v,i-1) -// end -// return arr -//end - -//function luanet.each(o) -// local e = o:GetEnumerator() -// return function() -// if e:MoveNext() then -// return e.Current -// end -// end -//end -//"; - public bool UseTraceback { get; set; } = false; - - /// - /// The maximum number of recursive steps to take when adding global reference variables. Defaults to 2. - /// - public int MaximumRecursion { get; set; } = 2; - - #region Globals auto-complete - /// - /// An alphabetically sorted list of all globals (objects, methods, etc.) externally added to this Lua instance - /// - /// Members of globals are also listed. The formatting is optimized for text input auto-completion. - public IEnumerable Globals { - get - { - // Only sort list when necessary - if (!_globalsSorted) - { - _globals.Sort(); - _globalsSorted = true; - } - - return _globals; - } - } - #endregion - - public Lua() - { - _luaState = new LuaState(); - Init(); - // We need to keep this in a managed reference so the delegate doesn't get garbage collected - _luaState.AtPanic(PanicCallback); - } - - /* - * CAUTION: NLua.Lua instances can't share the same lua state! - */ - public Lua(LuaState luaState) - { - luaState.PushString("NLua_Loaded"); - luaState.GetTable((int)LuaRegistry.Index); - - if (luaState.ToBoolean(-1)) - { - luaState.SetTop(-2); - throw new LuaException("There is already a NLua.Lua instance associated with this Lua state"); - } - - _luaState = luaState; - _StatePassed = true; - luaState.SetTop(-2); - Init(); - } - - void Init() - { - _luaState.PushString("NLua_Loaded"); - _luaState.PushBoolean(true); - _luaState.SetTable((int)LuaRegistry.Index); - if (_StatePassed == false) - { - _luaState.NewTable(); - _luaState.SetGlobal("luanet"); - } - _luaState.PushGlobalTable(); - _luaState.GetGlobal("luanet"); - _luaState.PushString("getmetatable"); - _luaState.GetGlobal("getmetatable"); - _luaState.SetTable(-3); - _luaState.PopGlobalTable(); - _translator = new ObjectTranslator(this, _luaState); - - ObjectTranslatorPool.Instance.Add(_luaState, _translator); - - _luaState.PopGlobalTable(); - _luaState.DoString(InitLuanet); - } - - public void Close() - { - if (_StatePassed || _luaState == null) - return; - - _luaState.Close(); - ObjectTranslatorPool.Instance.Remove(_luaState); - _luaState = null; - } - -#if __IOS__ || __TVOS__ || __WATCHOS__ - [MonoPInvokeCallback(typeof(LuaNativeFunction))] -#endif - static int PanicCallback(IntPtr state) - { - var luaState = LuaState.FromIntPtr(state); - string reason = string.Format("Unprotected error in call to Lua API ({0})", luaState.ToString(-1, false)); - throw new LuaException(reason); - } - - /// - /// Assuming we have a Lua error string sitting on the stack, throw a C# exception out to the user's app - /// - /// Thrown if the script caused an exception - private void ThrowExceptionFromError(int oldTop) - { - object err = _translator.GetObject(_luaState, -1); - _luaState.SetTop(oldTop); - - // A pre-wrapped exception - just rethrow it (stack trace of InnerException will be preserved) - var luaEx = err as LuaScriptException; - - if (luaEx != null) - throw luaEx; - - // A non-wrapped Lua error (best interpreted as a string) - wrap it and throw it - if (err == null) - err = "Unknown Lua Error"; - - throw new LuaScriptException(err.ToString(), string.Empty); - } - - /// - /// Push a debug.traceback reference onto the stack, for a pcall function to use as error handler. (Remember to increment any top-of-stack markers!) - /// - private static int PushDebugTraceback(LuaState luaState, int argCount) - { - luaState.GetGlobal("debug"); - luaState.GetField(-1, "traceback"); - luaState.Remove(-2); - int errIndex = -argCount - 2; - luaState.Insert(errIndex); - return errIndex; - } - - /// - /// Return a debug.traceback() call result (a multi-line string, containing a full stack trace, including C calls. - /// Note: it won't return anything unless the interpreter is in the middle of execution - that is, it only makes sense to call it from a method called from Lua, or during a coroutine yield. - /// - public string GetDebugTraceback() - { - int oldTop = _luaState.GetTop(); - _luaState.GetGlobal("debug"); // stack: debug - _luaState.GetField(-1, "traceback"); // stack: debug,traceback - _luaState.Remove(-2); // stack: traceback - _luaState.PCall(0, -1, 0); - return _translator.PopValues(_luaState, oldTop)[0] as string; - } - - /// - /// Convert C# exceptions into Lua errors - /// - /// num of things on stack - /// null for no pending exception - internal int SetPendingException(Exception e) - { - var caughtExcept = e; - - if (caughtExcept == null) - return 0; - - _translator.ThrowError(_luaState, caughtExcept); - return 1; - } - - /// - /// - /// - /// - /// - /// - public LuaFunction LoadString(string chunk, string name) - { - int oldTop = _luaState.GetTop(); - _executing = true; - - try - { - if (_luaState.LoadString(chunk, name) != LuaStatus.OK) - ThrowExceptionFromError(oldTop); - } - finally - { - _executing = false; - } - - var result = _translator.GetFunction(_luaState, -1); - _translator.PopValues(_luaState, oldTop); - return result; - } - - /// - /// - /// - /// - /// - /// - public LuaFunction LoadString(byte[] chunk, string name) - { - int oldTop = _luaState.GetTop(); - _executing = true; - - try - { - if (_luaState.LoadBuffer(chunk, name) != LuaStatus.OK) - ThrowExceptionFromError(oldTop); - } - finally - { - _executing = false; - } - - var result = _translator.GetFunction(_luaState, -1); - _translator.PopValues(_luaState, oldTop); - return result; - } - - /// - /// Load a File on, and return a LuaFunction to execute the file loaded (useful to see if the syntax of a file is ok) - /// - /// - /// - public LuaFunction LoadFile(string fileName) - { - int oldTop = _luaState.GetTop(); - - if (_luaState.LoadFile(fileName) != LuaStatus.OK) - ThrowExceptionFromError(oldTop); - - var result = _translator.GetFunction(_luaState, -1); - _translator.PopValues(_luaState, oldTop); - return result; - } - - /// - /// Executes a Lua chunk and returns all the chunk's return values in an array. - /// - /// Chunk to execute - /// Name to associate with the chunk. Defaults to "chunk". - /// - public object[] DoString(byte[] chunk, string chunkName = "chunk") - { - int oldTop = _luaState.GetTop(); - _executing = true; - - if (_luaState.LoadBuffer(chunk, chunkName) != LuaStatus.OK) - ThrowExceptionFromError(oldTop); - - int errorFunctionIndex = 0; - - if (UseTraceback) - { - errorFunctionIndex = PushDebugTraceback(_luaState, 0); - oldTop++; - } - - try - { - if (_luaState.PCall(0, -1, errorFunctionIndex) != LuaStatus.OK) - ThrowExceptionFromError(oldTop); - - return _translator.PopValues(_luaState, oldTop); - } - finally - { - _executing = false; - } - } - - /// - /// Executes a Lua chunk and returns all the chunk's return values in an array. - /// - /// Chunk to execute - /// Name to associate with the chunk. Defaults to "chunk". - /// - public object[] DoString(string chunk, string chunkName = "chunk") - { - int oldTop = _luaState.GetTop(); - _executing = true; - - if (_luaState.LoadString(chunk, chunkName) != LuaStatus.OK) - ThrowExceptionFromError(oldTop); - - int errorFunctionIndex = 0; - - if (UseTraceback) - { - errorFunctionIndex = PushDebugTraceback(_luaState, 0); - oldTop++; - } - - try - { - if (_luaState.PCall(0, -1, errorFunctionIndex) != LuaStatus.OK) - ThrowExceptionFromError(oldTop); - - return _translator.PopValues(_luaState, oldTop); - } - finally - { - _executing = false; - } - } - - /* - * Executes a Lua file and returns all the chunk's return - * values in an array - */ - public object[] DoFile(string fileName) - { - int oldTop = _luaState.GetTop(); - - if (_luaState.LoadFile(fileName) != LuaStatus.OK) - ThrowExceptionFromError(oldTop); - - _executing = true; - - int errorFunctionIndex = 0; - if (UseTraceback) - { - errorFunctionIndex = PushDebugTraceback(_luaState, 0); - oldTop++; - } - - try - { - if (_luaState.PCall(0, -1, errorFunctionIndex) != LuaStatus.OK) - ThrowExceptionFromError(oldTop); - - return _translator.PopValues(_luaState, oldTop); - } - finally - { - _executing = false; - } - } - - public object GetObjectFromPath(string fullPath) - { - int oldTop = _luaState.GetTop(); - string[] path = FullPathToArray(fullPath); - _luaState.GetGlobal(path[0]); - object returnValue = _translator.GetObject(_luaState, -1); - - if (path.Length > 1) - { - var dispose = returnValue as LuaBase; - string[] remainingPath = new string[path.Length - 1]; - Array.Copy(path, 1, remainingPath, 0, path.Length - 1); - returnValue = GetObject(remainingPath); - dispose?.Dispose(); - } - - _luaState.SetTop(oldTop); - return returnValue; - } - - public void SetObjectToPath(string fullPath, object value) - { - int oldTop = _luaState.GetTop(); - string[] path = FullPathToArray(fullPath); - - if (path.Length == 1) - { - _translator.Push(_luaState, value); - _luaState.SetGlobal(fullPath); - } - else - { - _luaState.GetGlobal(path[0]); - string[] remainingPath = new string[path.Length - 1]; - Array.Copy(path, 1, remainingPath, 0, path.Length - 1); - SetObject(remainingPath, value); - } - - _luaState.SetTop(oldTop); - - // Globals auto-complete - if (value == null) - { - // Remove now obsolete entries - _globals.Remove(fullPath); - } - else - { - // Add new entries - if (!_globals.Contains(fullPath)) - RegisterGlobal(fullPath, value.GetType(), 0); - } - } - /* - * Indexer for global variables from the LuaInterpreter - * Supports navigation of tables by using . operator - */ - public object this[string fullPath] { - get - { - // Silently convert Lua integer to double for backward compatibility with index[] operator - object obj = GetObjectFromPath(fullPath); - if (obj is long l) - return (double)l; - return obj; - } - set - { - SetObjectToPath(fullPath, value); - } - } - - #region Globals auto-complete - /// - /// Adds an entry to (recursivley handles 2 levels of members) - /// - /// The index accessor path ot the entry - /// The type of the entry - /// How deep have we gone with recursion? - private void RegisterGlobal(string path, Type type, int recursionCounter) - { - // If the type is a global method, list it directly - if (type == typeof(LuaFunction)) - { - // 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 < MaximumRecursion) - { - #region Methods - foreach (var method in type.GetMethods(BindingFlags.Public | BindingFlags.Instance)) - { - string name = method.Name; - if ( - // Check that the LuaHideAttribute and LuaGlobalAttribute were not applied - (!method.GetCustomAttributes(typeof(LuaHideAttribute), false).Any()) && - (!method.GetCustomAttributes(typeof(LuaGlobalAttribute), false).Any()) && - // Exclude some generic .NET methods that wouldn't be very usefull in Lua - name != "GetType" && name != "GetHashCode" && name != "Equals" && - name != "ToString" && name != "Clone" && name != "Dispose" && - name != "GetEnumerator" && name != "CopyTo" && - !name.StartsWith("get_", StringComparison.Ordinal) && - !name.StartsWith("set_", StringComparison.Ordinal) && - !name.StartsWith("add_", StringComparison.Ordinal) && - !name.StartsWith("remove_", StringComparison.Ordinal)) - { - // Format for easy method invocation - string command = path + ":" + 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).Any()) && - (!field.GetCustomAttributes(typeof(LuaGlobalAttribute), false).Any())) - { - // 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).Any()) && - (!property.GetCustomAttributes(typeof(LuaGlobalAttribute), false).Any()) - // Exclude some generic .NET properties that wouldn't be very useful 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 - */ - object GetObject(string[] remainingPath) - { - object returnValue = null; - - for (int i = 0; i < remainingPath.Length; i++) - { - _luaState.PushString(remainingPath[i]); - _luaState.GetTable(-2); - returnValue = _translator.GetObject(_luaState, -1); - - if (returnValue == null) - break; - } - - return returnValue; - } - - /* - * Gets a numeric global variable - */ - public double GetNumber(string fullPath) - { - // Silently convert Lua integer to double for backward compatibility with GetNumber method - object obj = GetObjectFromPath(fullPath); - if (obj is long l) - return l; - return (double)obj; - } - - public int GetInteger(string fullPath) - { - return (int)(long)GetObjectFromPath(fullPath); - } - - public long GetLong(string fullPath) - { - return (long)GetObjectFromPath(fullPath); - } - - /* - * Gets a string global variable - */ - public string GetString(string fullPath) - { - object obj = GetObjectFromPath(fullPath); - return obj.ToString(); - } - - /* - * Gets a table global variable - */ - public LuaTable GetTable(string fullPath) - { - return (LuaTable)GetObjectFromPath(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 = GetObjectFromPath(fullPath); - var luaFunction = obj as LuaFunction; - if (luaFunction != null) - return luaFunction; - - luaFunction = new LuaFunction((LuaNativeFunction) obj, this); - return luaFunction; - } - - /* - * Register a delegate type to be used to convert Lua functions 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); - } - - // ReSharper disable once InconsistentNaming - public void LoadCLRPackage() - { - _luaState.DoString(ClrPackage); - } - /* - * 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 = _luaState.GetTop(); - - if (!_luaState.CheckStack(args.Length + 6)) - throw new LuaException("Lua stack overflow"); - - _translator.Push(_luaState, function); - - if (args.Length > 0) - { - nArgs = args.Length; - - for (int i = 0; i < args.Length; i++) - _translator.Push(_luaState, args[i]); - } - - _executing = true; - - try - { - int errfunction = 0; - if (UseTraceback) - { - errfunction = PushDebugTraceback(_luaState, nArgs); - oldTop++; - } - - LuaStatus error = _luaState.PCall(nArgs, -1, errfunction); - if (error != LuaStatus.OK) - ThrowExceptionFromError(oldTop); - } - finally - { - _executing = false; - } - - if (returnTypes != null) - return _translator.PopValues(_luaState, oldTop, returnTypes); - - return _translator.PopValues(_luaState, oldTop); - } - - /* - * Navigates a table to set the value of one of its fields - */ - void SetObject(string[] remainingPath, object val) - { - for (int i = 0; i < remainingPath.Length - 1; i++) - { - _luaState.PushString(remainingPath[i]); - _luaState.GetTable(-2); - } - - _luaState.PushString(remainingPath[remainingPath.Length - 1]); - _translator.Push(_luaState, val); - _luaState.SetTable(-3); - } - - string[] FullPathToArray(string fullPath) - { - return fullPath.SplitWithEscape('.', '\\').ToArray(); - } - /* - * Creates a new table as a global variable or as a field - * inside an existing table - */ - public void NewTable(string fullPath) - { - string[] path = FullPathToArray(fullPath); - int oldTop = _luaState.GetTop(); - - if (path.Length == 1) - { - _luaState.NewTable(); - _luaState.SetGlobal(fullPath); - } - else - { - _luaState.GetGlobal(path[0]); - - for (int i = 1; i < path.Length - 1; i++) - { - _luaState.PushString(path[i]); - _luaState.GetTable(-2); - } - - _luaState.PushString(path[path.Length - 1]); - _luaState.NewTable(); - _luaState.SetTable(-3); - } - - _luaState.SetTop( oldTop); - } - - public Dictionary GetTableDict(LuaTable table) - { - if (table == null) - throw new ArgumentNullException(nameof(table)); - - var dict = new Dictionary(); - int oldTop = _luaState.GetTop(); - _translator.Push(_luaState, table); - _luaState.PushNil(); - - while (_luaState.Next(-2)) - { - dict[_translator.GetObject(_luaState, -2)] = _translator.GetObject(_luaState, -1); - _luaState.SetTop(-2); - } - - _luaState.SetTop(oldTop); - return dict; - } - - /* - * Lets go of a previously allocated reference to a table, function - * or userdata - */ - #region lua debug functions - /// - /// Activates the debug hook - /// - /// Mask - /// Count - /// see lua docs. -1 if hook is already set - public int SetDebugHook(LuaHookMask mask, int count) - { - if (_hookCallback == null) - { - _hookCallback = DebugHookCallback; - _luaState.SetHook(_hookCallback, mask, count); - } - - return -1; - } - - /// - /// Removes the debug hook - /// - /// see lua docs - public void RemoveDebugHook() - { - _hookCallback = null; - _luaState.SetHook(null, LuaHookMask.Disabled, 0); - } - - /// - /// Gets the hook mask. - /// - /// hook mask - public LuaHookMask GetHookMask() - { - return _luaState.HookMask; - } - - /// - /// Gets the hook count - /// - /// see lua docs - public int GetHookCount() - { - return _luaState.HookCount; - } - - - /// - /// Gets local (see lua docs) - /// - /// lua debug structure - /// see lua docs - /// see lua docs - public string GetLocal(LuaDebug luaDebug, int n) - { - return _luaState.GetLocal(luaDebug, n); - } - - /// - /// Sets local (see lua docs) - /// - /// lua debug structure - /// see lua docs - /// see lua docs - public string SetLocal(LuaDebug luaDebug, int n) - { - return _luaState.SetLocal(luaDebug, n); - } - - public int GetStack(int level, ref LuaDebug ar) - { - return _luaState.GetStack(level, ref ar); - } - - public bool GetInfo(string what, ref LuaDebug ar) - { - return _luaState.GetInfo(what, ref ar); - } - - /// - /// Gets up value (see lua docs) - /// - /// see lua docs - /// see lua docs - /// see lua docs - public string GetUpValue(int funcindex, int n) - { - return _luaState.GetUpValue(funcindex, n); - } - - /// - /// Sets up value (see lua docs) - /// - /// see lua docs - /// see lua docs - /// see lua docs - public string SetUpValue(int funcindex, int n) - { - return _luaState.SetUpValue(funcindex, n); - } - - /// - /// Delegate that is called on lua hook callback - /// - /// lua state - /// Pointer to LuaDebug (lua_debug) structure - /// -#if __IOS__ || __TVOS__ || __WATCHOS__ - [MonoPInvokeCallback(typeof(LuaHookFunction))] -#endif - static void DebugHookCallback(IntPtr luaState, IntPtr luaDebug) - { - var state = LuaState.FromIntPtr(luaState); - - state.GetStack(0, luaDebug); - - if (!state.GetInfo("Snlu", luaDebug)) - return; - - var debug = LuaDebug.FromIntPtr(luaDebug); - - ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(state); - Lua lua = translator.Interpreter; - lua.DebugHookCallbackInternal(debug); - } - - private void DebugHookCallbackInternal(LuaDebug luaDebug) - { - try - { - var temp = DebugHook; - - if (temp != null) - temp(this, new DebugHookEventArgs(luaDebug)); - } - catch (Exception ex) - { - OnHookException(new HookExceptionEventArgs(ex)); - } - } - - private void OnHookException(HookExceptionEventArgs e) - { - var temp = HookException; - if (temp != null) - temp(this, e); - } - - /// - /// Pops a value from the lua stack. - /// - /// Returns the top value from the lua stack. - public object Pop() - { - int top = _luaState.GetTop(); - return _translator.PopValues(_luaState, top - 1)[0]; - } - - /// - /// Pushes a value onto the lua stack. - /// - /// Value to push. - public void Push(object value) - { - _translator.Push(_luaState, value); - } - #endregion - - internal void DisposeInternal(int reference, bool finalized) - { - if (finalized && _translator != null) - { - _translator.AddFinalizedReference(reference); - return; - } - - if (_luaState != null && !finalized) - _luaState.Unref(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 = _luaState.GetTop(); - _luaState.GetRef(reference); - _luaState.PushString(field); - _luaState.RawGet(-2); - object obj = _translator.GetObject(_luaState, -1); - _luaState.SetTop(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 = _luaState.GetTop(); - _luaState.GetRef(reference); - object returnValue = GetObject(FullPathToArray(field)); - _luaState.SetTop(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 = _luaState.GetTop(); - _luaState.GetRef(reference); - _translator.Push(_luaState, field); - _luaState.GetTable(-2); - object returnValue = _translator.GetObject(_luaState, -1); - _luaState.SetTop(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 = _luaState.GetTop(); - _luaState.GetRef(reference); - SetObject(FullPathToArray(field), val); - _luaState.SetTop(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 = _luaState.GetTop(); - _luaState.GetRef(reference); - _translator.Push(_luaState, field); - _translator.Push(_luaState, val); - _luaState.SetTable(-3); - _luaState.SetTop(oldTop); - } - - public LuaFunction RegisterFunction(string path, MethodBase function) - { - return RegisterFunction(path, null, function); - } - - /* - * 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) - { - // We leave nothing on the stack when we are done - int oldTop = _luaState.GetTop(); - var wrapper = new LuaMethodWrapper(_translator, target, new ProxyType(function.DeclaringType), function); - - _translator.Push(_luaState, new LuaNativeFunction(wrapper.InvokeFunction)); - - object value = _translator.GetObject(_luaState, -1); - SetObjectToPath(path, value); - - LuaFunction f = GetFunction(path); - _luaState.SetTop(oldTop); - return f; - } - - /* - * Compares the two values referenced by ref1 and ref2 for equality - */ - internal bool CompareRef(int ref1, int ref2) - { - int top = _luaState.GetTop(); - _luaState.GetRef(ref1); - _luaState.GetRef(ref2); - bool equal = _luaState.AreEqual(-1, -2); - _luaState.SetTop(top); - return equal; - } - - // ReSharper disable once InconsistentNaming - internal void PushCSFunction(LuaNativeFunction function) - { - _translator.PushFunction(_luaState, function); - } - - #region IDisposable Members - - ~Lua() - { - Dispose(); - } - public virtual void Dispose() - { - if (_translator != null) - { - _translator.PendingEvents.Dispose(); - if (_translator.Tag != IntPtr.Zero) - Marshal.FreeHGlobal(_translator.Tag); - _translator = null; - } - - Close(); - GC.SuppressFinalize(this); - } - #endregion - } -} diff --git a/src/LUA/LuaBase.cs b/src/LUA/LuaBase.cs deleted file mode 100644 index 75a5441..0000000 --- a/src/LUA/LuaBase.cs +++ /dev/null @@ -1,86 +0,0 @@ -using System; - -namespace NLua -{ - /// - /// Base class to provide consistent disposal flow across lua objects. Uses code provided by Yves Duhoux and suggestions by Hans Schmeidenbacher and Qingrui Li - /// - public abstract class LuaBase : IDisposable - { - private bool _disposed; - protected readonly int _Reference; - Lua _lua; - - protected bool TryGet(out Lua lua) - { - if (_lua.State == null) - { - lua = null; - return false; - } - - lua = _lua; - return true; - } - protected LuaBase(int reference, Lua lua) - { - _lua = lua; - _Reference = reference; - } - - ~LuaBase() - { - Dispose(false); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - void DisposeLuaReference(bool finalized) - { - if (_lua == null) - return; - Lua lua; - if (!TryGet(out lua)) - return; - - lua.DisposeInternal(_Reference, finalized); - } - public virtual void Dispose(bool disposeManagedResources) - { - if (_disposed) - return; - - bool finalized = !disposeManagedResources; - - if (_Reference != 0) - { - DisposeLuaReference(finalized); - } - - _lua = null; - _disposed = true; - } - - public override bool Equals(object o) - { - var reference = o as LuaBase; - if (reference == null) - return false; - - Lua lua; - if (!TryGet(out lua)) - return false; - - return lua.CompareRef(reference._Reference, _Reference); - } - - public override int GetHashCode() - { - return _Reference; - } - } -} \ No newline at end of file diff --git a/src/LUA/LuaFunction.cs b/src/LUA/LuaFunction.cs deleted file mode 100644 index 9e2674f..0000000 --- a/src/LUA/LuaFunction.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using KeraLua; - -using LuaState = KeraLua.Lua; -using LuaNativeFunction = KeraLua.LuaFunction; - -namespace NLua -{ - public class LuaFunction : LuaBase - { - internal readonly LuaNativeFunction function; - - public LuaFunction(int reference, Lua interpreter):base(reference, interpreter) - { - function = null; - } - - public LuaFunction(LuaNativeFunction nativeFunction, Lua interpreter):base (0, interpreter) - { - function = nativeFunction; - } - - /* - * Calls the function casting return values to the types - * in returnTypes - */ - internal object[] Call(object[] args, Type[] returnTypes) - { - Lua lua; - if (!TryGet(out lua)) - return null; - - return lua.CallFunction(this, args, returnTypes); - } - - /* - * Calls the function and returns its return values inside - * an array - */ - public object[] Call(params object[] args) - { - Lua lua; - if (!TryGet(out lua)) - return null; - - return lua.CallFunction(this, args); - } - - /* - * Pushes the function into the Lua stack - */ - internal void Push(LuaState luaState) - { - Lua lua; - if (!TryGet(out lua)) - return; - - if (_Reference != 0) - luaState.RawGetInteger(LuaRegistry.Index, _Reference); - else - lua.PushCSFunction(function); - } - - public override string ToString() - { - return "function"; - } - - public override bool Equals(object o) - { - var l = o as LuaFunction; - - if (l == null) - return false; - - Lua lua; - if (!TryGet(out lua)) - return false; - - if (_Reference != 0 && l._Reference != 0) - return lua.CompareRef(l._Reference, _Reference); - - return function == l.function; - } - - public override int GetHashCode() - { - return _Reference != 0 ? _Reference : function.GetHashCode(); - } - } -} \ No newline at end of file diff --git a/src/LUA/LuaGlobalAttribute.cs b/src/LUA/LuaGlobalAttribute.cs deleted file mode 100644 index 27e6393..0000000 --- a/src/LUA/LuaGlobalAttribute.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; - -namespace NLua -{ - /// - /// Marks a method for global usage in Lua scripts - /// - /// - /// - [AttributeUsage(AttributeTargets.Method)] - public sealed class LuaGlobalAttribute : Attribute - { - /// - /// An alternative name to use for calling the function in Lua - leave empty for CLR name - /// - public string Name { get; set; } - - /// - /// A description of the function - /// - public string Description { get; set; } - } -} \ No newline at end of file diff --git a/src/LUA/LuaHideAttribute.cs b/src/LUA/LuaHideAttribute.cs deleted file mode 100644 index c5840fd..0000000 --- a/src/LUA/LuaHideAttribute.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace NLua -{ - /// - /// Marks a method, field or property to be hidden from Lua auto-completion - /// - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] - public sealed class LuaHideAttribute : Attribute - { - } -} \ No newline at end of file diff --git a/src/LUA/LuaRegistrationHelper.cs b/src/LUA/LuaRegistrationHelper.cs deleted file mode 100644 index eca12a9..0000000 --- a/src/LUA/LuaRegistrationHelper.cs +++ /dev/null @@ -1,98 +0,0 @@ -using System; -using System.Reflection; -using System.Diagnostics.CodeAnalysis; - -namespace NLua -{ - public static class LuaRegistrationHelper - { - #region Tagged instance methods - /// - /// Registers all public instance methods in an object tagged with as Lua global functions - /// - /// The Lua VM to add the methods to - /// The object to get the methods from - public static void TaggedInstanceMethods(Lua lua, object o) - { - #region Sanity checks - if (lua == null) - throw new ArgumentNullException(nameof(lua)); - - if (o == null) - throw new ArgumentNullException(nameof(o)); - #endregion - - foreach (var method in o.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public)) - { - foreach (LuaGlobalAttribute attribute in method.GetCustomAttributes(typeof(LuaGlobalAttribute), true)) - { - if (string.IsNullOrEmpty(attribute.Name)) - lua.RegisterFunction(method.Name, o, method); // CLR name - else - lua.RegisterFunction(attribute.Name, o, method); // Custom name - } - } - } - #endregion - - #region Tagged static methods - /// - /// Registers all public static methods in a class tagged with as Lua global functions - /// - /// The Lua VM to add the methods to - /// The class type to get the methods from - public static void TaggedStaticMethods(Lua lua, Type type) - { - #region Sanity checks - if (lua == null) - throw new ArgumentNullException(nameof(lua)); - - if (type == null) - throw new ArgumentNullException(nameof(type)); - - if (!type.IsClass) - throw new ArgumentException("The type must be a class!", nameof(type)); - #endregion - - foreach (var method in type.GetMethods(BindingFlags.Static | BindingFlags.Public)) - { - foreach (LuaGlobalAttribute attribute in method.GetCustomAttributes(typeof(LuaGlobalAttribute), false)) - { - if (string.IsNullOrEmpty(attribute.Name)) - lua.RegisterFunction(method.Name, null, method); // CLR name - else - lua.RegisterFunction(attribute.Name, null, method); // Custom name - } - } - } - #endregion - - /// - /// Registers an enumeration's values for usage as a Lua variable table - /// - /// The enum type to register - /// The Lua VM to add the enum to - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "The type parameter is used to select an enum type")] - public static void Enumeration(Lua lua) - { - if (lua == null) - throw new ArgumentNullException(nameof(lua)); - - Type type = typeof(T); - - if (!type.IsEnum) - throw new ArgumentException("The type must be an enumeration!"); - - - string[] names = Enum.GetNames(type); - var values = (T[])Enum.GetValues(type); - lua.NewTable(type.Name); - - for (int i = 0; i < names.Length; i++) - { - string path = type.Name + "." + names[i]; - lua.SetObjectToPath(path, values[i]); - } - } - } -} diff --git a/src/LUA/LuaTable.cs b/src/LUA/LuaTable.cs deleted file mode 100644 index 8fff2e9..0000000 --- a/src/LUA/LuaTable.cs +++ /dev/null @@ -1,120 +0,0 @@ - -using System; -using System.Collections; - -using NLua.Extensions; - -using LuaState = KeraLua.Lua; - -namespace NLua -{ - public class LuaTable : LuaBase - { - public LuaTable(int reference, Lua interpreter): base(reference, interpreter) - { - } - - /* - * Indexer for string fields of the table - */ - public object this[string field] { - get - { - Lua lua; - if (!TryGet(out lua)) - return null; - return lua.GetObject(_Reference, field); - } - set - { - Lua lua; - if (!TryGet(out lua)) - return; - lua.SetObject(_Reference, field, value); - } - } - - /* - * Indexer for numeric fields of the table - */ - public object this[object field] { - get - { - Lua lua; - if (!TryGet(out lua)) - return null; - - return lua.GetObject(_Reference, field); - } - set - { - Lua lua; - if (!TryGet(out lua)) - return; - - lua.SetObject(_Reference, field, value); - } - } - - public IDictionaryEnumerator GetEnumerator() - { - Lua lua; - if (!TryGet(out lua)) - return null; - - return lua.GetTableDict(this).GetEnumerator(); - } - - public ICollection Keys - { - get - { - Lua lua; - if (!TryGet(out lua)) - return null; - - return lua.GetTableDict(this).Keys; - } - } - - - public ICollection Values - { - get - { - Lua lua; - if (!TryGet(out lua)) - return null; - - return lua.GetTableDict(this).Values; - } - } - - - /* - * Gets an string fields of a table ignoring its metatable, - * if it exists - */ - internal object RawGet(string field) - { - Lua lua; - if (!TryGet(out lua)) - return null; - - return lua.RawGetObject(_Reference, field); - } - - /* - * Pushes this table into the Lua stack - */ - internal void Push(LuaState luaState) - { - luaState.GetRef(_Reference); - } - - public override string ToString() - { - return "table"; - } - } -} \ No newline at end of file diff --git a/src/LUA/LuaUserData.cs b/src/LUA/LuaUserData.cs deleted file mode 100644 index 147d474..0000000 --- a/src/LUA/LuaUserData.cs +++ /dev/null @@ -1,74 +0,0 @@ - -using System; - -namespace NLua -{ - public class LuaUserData : LuaBase - { - public LuaUserData(int reference, Lua interpreter):base(reference, interpreter) - { - } - - /* - * Indexer for string fields of the userdata - */ - public object this[string field] { - get - { - Lua lua; - if (!TryGet(out lua)) - return null; - - return lua.GetObject(_Reference, field); - } - set - { - Lua lua; - if (!TryGet(out lua)) - return; - - lua.SetObject(_Reference, field, value); - } - } - - /* - * Indexer for numeric fields of the userdata - */ - public object this[object field] { - get - { - Lua lua; - if (!TryGet(out lua)) - return null; - - return lua.GetObject(_Reference, field); - } - set - { - Lua lua; - if (!TryGet(out lua)) - return; - - lua.SetObject(_Reference, field, value); - } - } - - /* - * Calls the userdata and returns its return values inside - * an array - */ - public object[] Call(params object[] args) - { - Lua lua; - if (!TryGet(out lua)) - return null; - - return lua.CallFunction(this, args); - } - - public override string ToString() - { - return "userdata"; - } - } -} \ No newline at end of file diff --git a/src/LUA/Metatables.cs b/src/LUA/Metatables.cs deleted file mode 100644 index a4b9b19..0000000 --- a/src/LUA/Metatables.cs +++ /dev/null @@ -1,1636 +0,0 @@ -using System; -using System.Linq; -using System.Collections; -using System.Reflection; -using System.Diagnostics; -using System.Collections.Generic; -using System.Runtime.InteropServices; - -using KeraLua; - -using NLua.Method; -using NLua.Extensions; - -#if __IOS__ || __TVOS__ || __WATCHOS__ - using ObjCRuntime; -#endif - -using LuaState = KeraLua.Lua; -using LuaNativeFunction = KeraLua.LuaFunction; -using NLua.Exceptions; - -namespace NLua -{ - public class MetaFunctions - { - public static readonly LuaNativeFunction GcFunction = CollectObject; - public static readonly LuaNativeFunction IndexFunction = GetMethod; - public static readonly LuaNativeFunction NewIndexFunction = SetFieldOrProperty; - public static readonly LuaNativeFunction BaseIndexFunction = GetBaseMethod; - public static readonly LuaNativeFunction ClassIndexFunction = GetClassMethod; - public static readonly LuaNativeFunction ClassNewIndexFunction = SetClassFieldOrProperty; - public static readonly LuaNativeFunction ExecuteDelegateFunction = RunFunctionDelegate; - public static readonly LuaNativeFunction CallConstructorFunction = CallConstructor; - public static readonly LuaNativeFunction ToStringFunction = ToStringLua; - public static readonly LuaNativeFunction CallDelegateFunction = CallDelegate; - - public static readonly LuaNativeFunction AddFunction = AddLua; - public static readonly LuaNativeFunction SubtractFunction = SubtractLua; - public static readonly LuaNativeFunction MultiplyFunction = MultiplyLua; - public static readonly LuaNativeFunction DivisionFunction = DivideLua; - public static readonly LuaNativeFunction ModulosFunction = ModLua; - public static readonly LuaNativeFunction UnaryNegationFunction = UnaryNegationLua; - public static readonly LuaNativeFunction EqualFunction = EqualLua; - public static readonly LuaNativeFunction LessThanFunction = LessThanLua; - public static readonly LuaNativeFunction LessThanOrEqualFunction = LessThanOrEqualLua; - - readonly Dictionary> _memberCache = new Dictionary>(); - readonly ObjectTranslator _translator; - - /* - * __index metafunction for CLR objects. Implemented in Lua. - */ - public const string LuaIndexFunction = @"local function a(b,c)local d=getmetatable(b)local e=d.cache[c]if e~=nil then return e else local f,g=get_object_member(b,c)if g then d.cache[c]=f end;return f end end;return a"; - //@"local function index(obj,name) - // local meta = getmetatable(obj) - // local cached = meta.cache[name] - // if cached ~= nil then - // return cached - // else - // local value,isFunc = get_object_member(obj,name) - - // if isFunc then - // meta.cache[name]=value - // end - // return value - // end - //end - //return index"; - - public MetaFunctions(ObjectTranslator translator) - { - _translator = translator; - } - - /* - * __call metafunction of CLR delegates, retrieves and calls the delegate. - */ -#if __IOS__ || __TVOS__ || __WATCHOS__ - [MonoPInvokeCallback(typeof(LuaNativeFunction))] -#endif - private static int RunFunctionDelegate(IntPtr luaState) - { - var state = LuaState.FromIntPtr(luaState); - var translator = ObjectTranslatorPool.Instance.Find(state); - var func = (LuaNativeFunction)translator.GetRawNetObject(state, 1); - state.Remove(1); - int result = func(luaState); - var exception = translator.GetObject(state, -1) as LuaScriptException; - - if (exception != null) - return state.Error(); - return result; - } - - /* - * __gc metafunction of CLR objects. - */ -#if __IOS__ || __TVOS__ || __WATCHOS__ - [MonoPInvokeCallback(typeof(LuaNativeFunction))] -#endif - private static int CollectObject(IntPtr state) - { - var luaState = LuaState.FromIntPtr(state); - var translator = ObjectTranslatorPool.Instance.Find(luaState); - return CollectObject(luaState, translator); - } - - private static int CollectObject(LuaState luaState, ObjectTranslator translator) - { - int udata = luaState.RawNetObj(1); - - if (udata != -1) - translator.CollectObject(udata); - - return 0; - } - - /* - * __tostring metafunction of CLR objects. - */ -#if __IOS__ || __TVOS__ || __WATCHOS__ - [MonoPInvokeCallback(typeof(LuaNativeFunction))] -#endif - private static int ToStringLua(IntPtr state) - { - var luaState = LuaState.FromIntPtr(state); - var translator = ObjectTranslatorPool.Instance.Find(luaState); - return ToStringLua(luaState, translator); - } - - private static int ToStringLua(LuaState luaState, ObjectTranslator translator) - { - object obj = translator.GetRawNetObject(luaState, 1); - - if (obj != null) - translator.Push(luaState, obj + ": " + obj.GetHashCode()); - else - luaState.PushNil(); - - return 1; - } - - - /* - * __add metafunction of CLR objects. - */ -#if __IOS__ || __TVOS__ || __WATCHOS__ - [MonoPInvokeCallback(typeof(LuaNativeFunction))] -#endif - static int AddLua(IntPtr luaState) - { - var state = LuaState.FromIntPtr(luaState); - var translator = ObjectTranslatorPool.Instance.Find(state); - int result = MatchOperator(state, "op_Addition", translator); - var exception = translator.GetObject(state, -1) as LuaScriptException; - - if (exception != null) - return state.Error(); - return result; - } - - /* - * __sub metafunction of CLR objects. - */ -#if __IOS__ || __TVOS__ || __WATCHOS__ - [MonoPInvokeCallback(typeof(LuaNativeFunction))] -#endif - static int SubtractLua(IntPtr luaState) - { - var state = LuaState.FromIntPtr(luaState); - var translator = ObjectTranslatorPool.Instance.Find(state); - int result = MatchOperator(state, "op_Subtraction", translator); - var exception = translator.GetObject(state, -1) as LuaScriptException; - - if (exception != null) - return state.Error(); - return result; - } - - /* - * __mul metafunction of CLR objects. - */ -#if __IOS__ || __TVOS__ || __WATCHOS__ - [MonoPInvokeCallback(typeof(LuaNativeFunction))] -#endif - static int MultiplyLua(IntPtr luaState) - { - var state = LuaState.FromIntPtr(luaState); - var translator = ObjectTranslatorPool.Instance.Find(state); - int result = MatchOperator(state, "op_Multiply", translator); - var exception = translator.GetObject(state, -1) as LuaScriptException; - - if (exception != null) - return state.Error(); - return result; - } - - /* - * __div metafunction of CLR objects. - */ -#if __IOS__ || __TVOS__ || __WATCHOS__ - [MonoPInvokeCallback(typeof(LuaNativeFunction))] -#endif - static int DivideLua(IntPtr luaState) - { - var state = LuaState.FromIntPtr(luaState); - var translator = ObjectTranslatorPool.Instance.Find(state); - int result = MatchOperator(state, "op_Division", translator); - var exception = translator.GetObject(state, -1) as LuaScriptException; - - if (exception != null) - return state.Error(); - return result; - } - - /* - * __mod metafunction of CLR objects. - */ -#if __IOS__ || __TVOS__ || __WATCHOS__ - [MonoPInvokeCallback(typeof(LuaNativeFunction))] -#endif - static int ModLua(IntPtr luaState) - { - var state = LuaState.FromIntPtr(luaState); - var translator = ObjectTranslatorPool.Instance.Find(state); - int result = MatchOperator(state, "op_Modulus", translator); - var exception = translator.GetObject(state, -1) as LuaScriptException; - - if (exception != null) - return state.Error(); - return result; - } - - /* - * __unm metafunction of CLR objects. - */ -#if __IOS__ || __TVOS__ || __WATCHOS__ - [MonoPInvokeCallback(typeof(LuaNativeFunction))] -#endif - static int UnaryNegationLua(IntPtr luaState) - { - var state = LuaState.FromIntPtr(luaState); - var translator = ObjectTranslatorPool.Instance.Find(state); - int result = UnaryNegationLua(state, translator); - var exception = translator.GetObject(state, -1) as LuaScriptException; - - if (exception != null) - return state.Error(); - return result; - } - - static int UnaryNegationLua(LuaState luaState, ObjectTranslator translator) - { - object obj1 = translator.GetRawNetObject(luaState, 1); - - if (obj1 == null) - { - translator.ThrowError(luaState, "Cannot negate a nil object"); - return 1; - } - - Type type = obj1.GetType(); - MethodInfo opUnaryNegation = type.GetMethod("op_UnaryNegation"); - - if (opUnaryNegation == null) - { - translator.ThrowError(luaState, "Cannot negate object (" + type.Name + " does not overload the operator -)"); - return 1; - } - obj1 = opUnaryNegation.Invoke(obj1, new [] { obj1 }); - translator.Push(luaState, obj1); - return 1; - } - - - /* - * __eq metafunction of CLR objects. - */ -#if __IOS__ || __TVOS__ || __WATCHOS__ - [MonoPInvokeCallback(typeof(LuaNativeFunction))] -#endif - static int EqualLua(IntPtr luaState) - { - var state = LuaState.FromIntPtr(luaState); - var translator = ObjectTranslatorPool.Instance.Find(state); - int result = MatchOperator(state, "op_Equality", translator); - var exception = translator.GetObject(state, -1) as LuaScriptException; - - if (exception != null) - return state.Error(); - return result; - } - - /* - * __lt metafunction of CLR objects. - */ -#if __IOS__ || __TVOS__ || __WATCHOS__ - [MonoPInvokeCallback(typeof(LuaNativeFunction))] -#endif - static int LessThanLua(IntPtr luaState) - { - var state = LuaState.FromIntPtr(luaState); - var translator = ObjectTranslatorPool.Instance.Find(state); - int result = MatchOperator(state, "op_LessThan", translator); - var exception = translator.GetObject(state, -1) as LuaScriptException; - - if (exception != null) - return state.Error(); - return result; - } - - /* - * __le metafunction of CLR objects. - */ -#if __IOS__ || __TVOS__ || __WATCHOS__ - [MonoPInvokeCallback(typeof(LuaNativeFunction))] -#endif - static int LessThanOrEqualLua(IntPtr luaState) - { - var state = LuaState.FromIntPtr(luaState); - var translator = ObjectTranslatorPool.Instance.Find(state); - int result = MatchOperator(state, "op_LessThanOrEqual", translator); - var exception = translator.GetObject(state, -1) as LuaScriptException; - - if (exception != null) - return state.Error(); - return result; - } - - /// - /// Debug tool to dump the lua stack - /// - /// FIXME, move somewhere else - public static void DumpStack(ObjectTranslator translator, LuaState luaState) - { - int depth = luaState.GetTop(); - - Debug.WriteLine("lua stack depth: {0}", depth); - - for (int i = 1; i <= depth; i++) - { - var type = luaState.Type(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 == LuaType.Table) ? "table" : luaState.TypeName(type); - string strrep = luaState.ToString(i, false); - - if (type == LuaType.UserData) - { - object obj = translator.GetRawNetObject(luaState, i); - strrep = obj.ToString(); - } - - Debug.WriteLine("{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 __IOS__ || __TVOS__ || __WATCHOS__ - [MonoPInvokeCallback(typeof(LuaNativeFunction))] -#endif - private static int GetMethod(IntPtr state) - { - var luaState = LuaState.FromIntPtr(state); - var translator = ObjectTranslatorPool.Instance.Find(luaState); - var instance = translator.MetaFunctionsInstance; - int result = instance.GetMethodInternal(luaState); - var exception = translator.GetObject(luaState, -1) as LuaScriptException; - - if (exception != null) - return luaState.Error(); - return result; - } - - private int GetMethodInternal(LuaState luaState) - { - object obj = _translator.GetRawNetObject(luaState, 1); - - if (obj == null) - { - _translator.ThrowError(luaState, "Trying to index an invalid object reference"); - return 1; - } - - object index = _translator.GetObject(luaState, 2); - string methodName = index as string; // will be null if not a string arg - var objType = obj.GetType(); - var proxyType = new ProxyType(objType); - - // 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 - - if (!string.IsNullOrEmpty(methodName) && IsMemberPresent(proxyType, methodName)) - return GetMember(luaState, proxyType, obj, methodName, BindingFlags.Instance); - - // Try to access by array if the type is right and index is an int (lua numbers always come across as double) - if (TryAccessByArray(luaState, objType, obj, index)) - return 1; - - int fallback = GetMethodFallback(luaState, objType, obj, index, methodName); - if (fallback != 0) - return fallback; - - if (!string.IsNullOrEmpty(methodName) || index != null) - { - if (string.IsNullOrEmpty(methodName)) - methodName = index.ToString(); - - return PushInvalidMethodCall(luaState, objType, methodName); - } - - luaState.PushBoolean(false); - return 2; - } - - private int PushInvalidMethodCall(LuaState luaState, Type type, string name) - { - SetMemberCache(type, name, null); - - _translator.Push(luaState, null); - _translator.Push(luaState, false); - return 2; - } - - private bool TryAccessByArray(LuaState luaState, - Type objType, - object obj, - object index) - { - if (!objType.IsArray) - return false; - - int intIndex = -1; - if (index is long l) - intIndex = (int)l; - else if (index is double d) - intIndex = (int)d; - - if (intIndex == -1) - return false; - - Type type = objType.UnderlyingSystemType; - - if (type == typeof(long[])) - { - long[] arr = (long[])obj; - _translator.Push(luaState, arr[intIndex]); - return true; - } - if (type == typeof(float[])) - { - float[] arr = (float[])obj; - _translator.Push(luaState, arr[intIndex]); - return true; - } - if (type == typeof(double[])) - { - double[] arr = (double[])obj; - _translator.Push(luaState, arr[intIndex]); - return true; - } - if (type == typeof(int[])) - { - int[] arr = (int[])obj; - _translator.Push(luaState, arr[intIndex]); - return true; - } - if (type == typeof(byte[])) - { - byte[] arr = (byte[])obj; - _translator.Push(luaState, arr[intIndex]); - return true; - } - if (type == typeof(short[])) - { - short[] arr = (short[])obj; - _translator.Push(luaState, arr[intIndex]); - return true; - } - if (type == typeof(ushort[])) - { - ushort[] arr = (ushort[])obj; - _translator.Push(luaState, arr[intIndex]); - return true; - } - if (type == typeof(ulong[])) - { - ulong[] arr = (ulong[])obj; - _translator.Push(luaState, arr[intIndex]); - return true; - } - if (type == typeof(uint[])) - { - uint[] arr = (uint[])obj; - _translator.Push(luaState, arr[intIndex]); - return true; - } - if (type == typeof(sbyte[])) - { - sbyte[] arr = (sbyte[])obj; - _translator.Push(luaState, arr[intIndex]); - return true; - } - - var array = (Array)obj; - object element = array.GetValue(intIndex); - _translator.Push(luaState, element); - return true; - } - - private int GetMethodFallback - (LuaState luaState, - Type objType, - object obj, - object index, - string methodName) - { - object method; - if (!string.IsNullOrEmpty(methodName) && TryGetExtensionMethod(objType, methodName, out method)) - { - return PushExtensionMethod(luaState, objType, obj, methodName, method); - } - // Try to use get_Item to index into this .net object - MethodInfo[] methods = objType.GetMethods(); - - int res = TryIndexMethods(luaState, methods, obj, index); - if (res != 0) - return res; - - // Fallback to GetRuntimeMethods - methods = objType.GetRuntimeMethods().ToArray(); - - res = TryIndexMethods(luaState, methods, obj, index); - if (res != 0) - return res; - - res = TryGetValueForKeyMethods(luaState, methods, obj, index); - if (res != 0) - return res; - - // Try find explicity interface implementation - MethodInfo explicitInterfaceMethod = objType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance). - FirstOrDefault(m => m.Name == methodName && m.IsPrivate && m.IsVirtual && m.IsFinal); - - if (explicitInterfaceMethod != null) - { - var proxyType = new ProxyType(objType); - var methodWrapper = new LuaMethodWrapper(_translator, obj, proxyType, explicitInterfaceMethod); - var invokeDelegate = new LuaNativeFunction(methodWrapper.InvokeFunction); - - SetMemberCache(proxyType, methodName, invokeDelegate); - - _translator.PushFunction(luaState, invokeDelegate); - _translator.Push(luaState, true); - return 2; - } - - return 0; - } - - private int TryGetValueForKeyMethods(LuaState luaState, MethodInfo[] methods, object obj, object index) - { - foreach (MethodInfo methodInfo in methods) - { - if (methodInfo.Name != "TryGetValueForKey") - continue; - - // Check if the signature matches the input - if (methodInfo.GetParameters().Length != 2) - continue; - - ParameterInfo[] actualParams = methodInfo.GetParameters(); - - // Get the index in a form acceptable to the getter - index = _translator.GetAsType(luaState, 2, actualParams[0].ParameterType); - - // If the index type and the parameter doesn't match, just skip it - if (index == null) - break; - - object[] args = new object[2]; - - // Just call the indexer - if out of bounds an exception will happen - args[0] = index; - - try - { - bool found = (bool)methodInfo.Invoke(obj, args); - - if (!found) - { - _translator.ThrowError(luaState, "key not found: " + index); - return 1; - } - - _translator.Push(luaState, args[1]); - return 1; - } - 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); - - return 1; - } - } - return 0; - } - - - private int TryIndexMethods(LuaState luaState, MethodInfo [] methods, object obj, object index) - { - foreach (MethodInfo methodInfo in methods) - { - if (methodInfo.Name != "get_Item") - continue; - - // Check if the signature matches the input - if (methodInfo.GetParameters().Length != 1) - continue; - - ParameterInfo[] actualParams = methodInfo.GetParameters(); - - // Get the index in a form acceptable to the getter - index = _translator.GetAsType(luaState, 2, actualParams[0].ParameterType); - - // If the index type and the parameter doesn't match, just skip it - if (index == null) - continue; - - object[] args = new object[1]; - - // Just call the indexer - if out of bounds an exception will happen - args[0] = index; - - try - { - object result = methodInfo.Invoke(obj, args); - _translator.Push(luaState, result); - return 1; - } - 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); - - return 1; - } - } - return 0; - } - - /* - * __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 __IOS__ || __TVOS__ || __WATCHOS__ - [MonoPInvokeCallback(typeof(LuaNativeFunction))] -#endif - private static int GetBaseMethod(IntPtr state) - { - var luaState = LuaState.FromIntPtr(state); - var translator = ObjectTranslatorPool.Instance.Find(luaState); - var instance = translator.MetaFunctionsInstance; - int result = instance.GetBaseMethodInternal(luaState); - var exception = translator.GetObject(luaState, -1) as LuaScriptException; - - if (exception != null) - return luaState.Error(); - return result; - } - - private int GetBaseMethodInternal(LuaState luaState) - { - object obj = _translator.GetRawNetObject(luaState, 1); - - if (obj == null) - { - _translator.ThrowError(luaState, "Trying to index an invalid object reference"); - return 1; - } - - string methodName = luaState.ToString(2, false); - - if (string.IsNullOrEmpty(methodName)) - { - luaState.PushNil(); - luaState.PushBoolean(false); - return 2; - } - - GetMember(luaState, new ProxyType(obj.GetType()), obj, "__luaInterface_base_" + methodName, BindingFlags.Instance); - luaState.SetTop(-2); - - if (luaState.Type(-1) == LuaType.Nil) - { - luaState.SetTop(-2); - return GetMember(luaState, new ProxyType(obj.GetType()), obj, methodName, BindingFlags.Instance); - } - - luaState.PushBoolean(false); - return 2; - } - - /// - /// Does this method exist as either an instance or static? - /// - /// - /// - /// - bool IsMemberPresent(ProxyType objType, string methodName) - { - object cachedMember = CheckMemberCache(objType, methodName); - - if (cachedMember != null) - return true; - - var members = objType.GetMember(methodName, BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public); - return members.Length > 0; - } - - bool TryGetExtensionMethod(Type type, string name, out object method) - { - object cachedMember = CheckMemberCache(type, name); - - if (cachedMember != null) - { - method = cachedMember; - return true; - } - - MethodInfo methodInfo; - bool found = _translator.TryGetExtensionMethod(type, name, out methodInfo); - method = methodInfo; - return found; - } - - int PushExtensionMethod(LuaState luaState, Type type, object obj, string name, object method) - { - var cachedMember = method as LuaNativeFunction; - - if (cachedMember != null) - { - _translator.PushFunction(luaState, cachedMember); - _translator.Push(luaState, true); - return 2; - } - - var methodInfo = (MethodInfo)method; - var methodWrapper = new LuaMethodWrapper(_translator, obj, new ProxyType(type), methodInfo); - var invokeDelegate = new LuaNativeFunction(methodWrapper.InvokeFunction); - - SetMemberCache(type, name, invokeDelegate); - - _translator.PushFunction(luaState, invokeDelegate); - _translator.Push(luaState, true); - return 2; - } - - /* - * 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). - */ - int GetMember(LuaState luaState, ProxyType objType, object obj, string methodName, BindingFlags bindingType) - { - bool implicitStatic = false; - MemberInfo member = null; - object cachedMember = CheckMemberCache(objType, methodName); - - if (cachedMember is LuaNativeFunction) - { - _translator.PushFunction(luaState, (LuaNativeFunction)cachedMember); - _translator.Push(luaState, true); - return 2; - } - if (cachedMember != null) - member = (MemberInfo)cachedMember; - else - { - var members = objType.GetMember(methodName, bindingType | BindingFlags.Public); - - 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 - members = objType.GetMember(methodName, bindingType | BindingFlags.Static | BindingFlags.Public); - - if (members.Length > 0) - { - member = members[0]; - implicitStatic = true; - } - } - } - - if (member != null) - { - if (member.MemberType == MemberTypes.Field) - { - var field = (FieldInfo)member; - - if (cachedMember == null) - SetMemberCache(objType, methodName, member); - - try - { - var value = field.GetValue(obj); - _translator.Push(luaState, value); - } - catch - { - Debug.WriteLine("[Exception] Fail to get field value"); - luaState.PushNil(); - } - } - else if (member.MemberType == MemberTypes.Property) - { - var property = (PropertyInfo)member; - if (cachedMember == null) - SetMemberCache(objType, methodName, member); - - try - { - object value = property.GetValue(obj, null); - _translator.Push(luaState, value); - } - 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.UnderlyingSystemType != typeof(object)) - return GetMember(luaState, new ProxyType(objType.UnderlyingSystemType.BaseType), obj, methodName, bindingType); - luaState.PushNil(); - } - catch (TargetInvocationException e) - { // Convert this exception into a Lua error - ThrowError(luaState, e); - luaState.PushNil(); - } - } - else if (member.MemberType == MemberTypes.Event) - { - var eventInfo = (EventInfo)member; - if (cachedMember == null) - SetMemberCache(objType, methodName, member); - - _translator.Push(luaState, new RegisterEventHandler(_translator.PendingEvents, obj, eventInfo)); - } - else if (!implicitStatic) - { - if (member.MemberType == MemberTypes.NestedType && member.DeclaringType != null) - { - if (cachedMember == null) - SetMemberCache(objType, methodName, member); - - // Find the name of our class - string name = member.Name; - Type 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 methodWrapper = new LuaMethodWrapper(_translator, objType, methodName, bindingType); - var wrapper = methodWrapper.InvokeFunction; - - if (cachedMember == null) - SetMemberCache(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); - return 1; - } - } - else - { - if (objType.UnderlyingSystemType != typeof(object)) - return GetMember(luaState, new ProxyType(objType.UnderlyingSystemType.BaseType), obj, methodName, bindingType); - - // We want to throw an exception because merely 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); - return 1; - } - - // 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. - */ - object CheckMemberCache(Type objType, string memberName) - { - return CheckMemberCache(new ProxyType(objType), memberName); - } - - object CheckMemberCache(ProxyType objType, string memberName) - { - Dictionary members; - - if (!_memberCache.TryGetValue(objType, out members)) - return null; - - object memberValue; - - if (members == null || !members.TryGetValue(memberName, out memberValue)) - return null; - - return memberValue; - } - - /* - * Stores a MemberInfo object in the member cache. - */ - void SetMemberCache(Type objType, string memberName, object member) - { - SetMemberCache(new ProxyType(objType), memberName, member); - } - - void SetMemberCache(ProxyType objType, string memberName, object member) - { - Dictionary members; - Dictionary memberCacheValue; - - if (_memberCache.TryGetValue(objType, out memberCacheValue)) - { - members = memberCacheValue; - } - else - { - members = new Dictionary(); - _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 __IOS__ || __TVOS__ || __WATCHOS__ - [MonoPInvokeCallback(typeof(LuaNativeFunction))] -#endif - private static int SetFieldOrProperty(IntPtr state) - { - var luaState = LuaState.FromIntPtr(state); - var translator = ObjectTranslatorPool.Instance.Find(luaState); - var instance = translator.MetaFunctionsInstance; - int result = instance.SetFieldOrPropertyInternal(luaState); - var exception = translator.GetObject(luaState, -1) as LuaScriptException; - - if (exception != null) - return luaState.Error(); - return result; - } - - private int SetFieldOrPropertyInternal(LuaState luaState) - { - object target = _translator.GetRawNetObject(luaState, 1); - - if (target == null) - { - _translator.ThrowError(luaState, "trying to index and invalid object reference"); - return 1; - } - - var type = target.GetType(); - - // First try to look up the parameter as a property name - string detailMessage; - bool didMember = TrySetMember(luaState, new ProxyType(type), target, BindingFlags.Instance, 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 && luaState.IsNumber(2)) - { - int index = (int)luaState.ToNumber(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 != null) - { - var args = setter.GetParameters(); - var valueType = args[1].ParameterType; - - // The new value 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 - return 1; - } - } - } - catch (Exception e) - { - ThrowError(luaState, e); - return 1; - } - - return 0; - } - - /// - /// Tries to set a named property or field - /// - /// - /// - /// - /// - /// false if unable to find the named member, true for success - bool TrySetMember(LuaState luaState, ProxyType 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 (luaState.Type(2) != LuaType.String) - { - detailMessage = "property names must be strings"; - return false; - } - - // We only look up property names by string - string fieldName = luaState.ToString(2, false); - if (string.IsNullOrEmpty(fieldName) || !(char.IsLetter(fieldName[0]) || fieldName[0] == '_')) - { - detailMessage = "Invalid property name"; - return false; - } - - // Find our member via reflection or the cache - var member = (MemberInfo)CheckMemberCache(targetType, fieldName); - if (member == null) - { - var members = targetType.GetMember(fieldName, bindingType | BindingFlags.Public); - - if (members.Length <= 0) - { - detailMessage = "field or property '" + fieldName + "' does not exist"; - return false; - } - - member = members[0]; - SetMemberCache(targetType, fieldName, member); - } - - 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) - { - detailMessage = "Error setting field: " + e.Message; - return false; - } - - return true; - } - 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) - { - detailMessage = "Error setting property: " + e.Message; - return false; - } - - 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(LuaState luaState, ProxyType targetType, object target, BindingFlags bindingType) - { - string detail; - bool success = TrySetMember(luaState, targetType, target, bindingType, out detail); - - if (!success) - { - _translator.ThrowError(luaState, detail); - return 1; - } - - return 0; - } - - /// - /// Convert a C# exception into a Lua error - /// - /// - /// - /// We try to look into the exception to give the most meaningful description - void ThrowError(LuaState luaState, Exception e) - { - // If we got inside a reflection show what really happened - var te = e as TargetInvocationException; - - if (te != null) - e = te.InnerException; - - _translator.ThrowError(luaState, e); - } - - /* - * __index metafunction of type references, works on static members. - */ -#if __IOS__ || __TVOS__ || __WATCHOS__ - [MonoPInvokeCallback(typeof(LuaNativeFunction))] -#endif - private static int GetClassMethod(IntPtr state) - { - var luaState = LuaState.FromIntPtr(state); - var translator = ObjectTranslatorPool.Instance.Find(luaState); - var instance = translator.MetaFunctionsInstance; - int result = instance.GetClassMethodInternal(luaState); - var exception = translator.GetObject(luaState, -1) as LuaScriptException; - - if (exception != null) - return luaState.Error(); - return result; - } - - private int GetClassMethodInternal(LuaState luaState) - { - var klass = _translator.GetRawNetObject(luaState, 1) as ProxyType; - - if (klass == null) - { - _translator.ThrowError(luaState, "Trying to index an invalid type reference"); - return 1; - } - - if (luaState.IsNumber(2)) - { - int size = (int)luaState.ToNumber(2); - _translator.Push(luaState, Array.CreateInstance(klass.UnderlyingSystemType, size)); - return 1; - } - - string methodName = luaState.ToString(2, false); - - if (string.IsNullOrEmpty(methodName)) - { - luaState.PushNil(); - return 1; - } - return GetMember(luaState, klass, null, methodName, BindingFlags.Static); - } - - /* - * __newindex function of type references, works on static members. - */ -#if __IOS__ || __TVOS__ || __WATCHOS__ - [MonoPInvokeCallback(typeof(LuaNativeFunction))] -#endif - private static int SetClassFieldOrProperty(IntPtr state) - { - var luaState = LuaState.FromIntPtr(state); - var translator = ObjectTranslatorPool.Instance.Find(luaState); - var instance = translator.MetaFunctionsInstance; - int result = instance.SetClassFieldOrPropertyInternal(luaState); - var exception = translator.GetObject(luaState, -1) as LuaScriptException; - - if (exception != null) - return luaState.Error(); - return result; - } - - private int SetClassFieldOrPropertyInternal(LuaState luaState) - { - var target = _translator.GetRawNetObject(luaState, 1) as ProxyType; - - if (target == null) - { - _translator.ThrowError(luaState, "trying to index an invalid type reference"); - return 1; - } - - return SetMember(luaState, target, null, BindingFlags.Static); - } - - /* - * __call metafunction of Delegates. - */ -#if __IOS__ || __TVOS__ || __WATCHOS__ - [MonoPInvokeCallback(typeof(LuaNativeFunction))] -#endif - static int CallDelegate(IntPtr state) - { - var luaState = LuaState.FromIntPtr(state); - var translator = ObjectTranslatorPool.Instance.Find(luaState); - var instance = translator.MetaFunctionsInstance; - int result = instance.CallDelegateInternal(luaState); - var exception = translator.GetObject(luaState, -1) as LuaScriptException; - - if (exception != null) - return luaState.Error(); - - return result; - } - - int CallDelegateInternal(LuaState luaState) - { - var del = _translator.GetRawNetObject(luaState, 1) as Delegate; - - if (del == null) - { - _translator.ThrowError(luaState, "Trying to invoke a not delegate or callable value"); - return 1; - } - - luaState.Remove(1); - - var validDelegate = new MethodCache(); - MethodBase methodDelegate = del.Method; - bool isOk = MatchParameters(luaState, methodDelegate, validDelegate, 0); - - if (isOk) - { - object result; - - if (methodDelegate.IsStatic) - result = methodDelegate.Invoke(null, validDelegate.args); - else - result = methodDelegate.Invoke(del.Target, validDelegate.args); - - _translator.Push(luaState, result); - return 1; - } - - _translator.ThrowError(luaState, "Cannot invoke delegate (invalid arguments for " + methodDelegate.Name + ")"); - return 1; - } - - /* - * __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 __IOS__ || __TVOS__ || __WATCHOS__ - [MonoPInvokeCallback(typeof(LuaNativeFunction))] -#endif - private static int CallConstructor(IntPtr state) - { - var luaState = LuaState.FromIntPtr(state); - var translator = ObjectTranslatorPool.Instance.Find(luaState); - var instance = translator.MetaFunctionsInstance; - int result = instance.CallConstructorInternal(luaState); - var exception = translator.GetObject(luaState, -1) as LuaScriptException; - - if (exception != null) - return luaState.Error(); - return result; - } - - private static ConstructorInfo[] ReorderConstructors(ConstructorInfo[] constructors) - { - int len = constructors.Length; - - if (len < 2) - return constructors; - - return constructors. - GroupBy(c => c.GetParameters().Length). - SelectMany(g => g.OrderByDescending(ci => ci.ToString())). - ToArray(); - } - - private int CallConstructorInternal(LuaState luaState) - { - var klass = _translator.GetRawNetObject(luaState, 1) as ProxyType; - - if (klass == null) - { - _translator.ThrowError(luaState, "Trying to call constructor on an invalid type reference"); - return 1; - } - - var validConstructor = new MethodCache(); - - luaState.Remove(1); - ConstructorInfo[] constructors = klass.UnderlyingSystemType.GetConstructors(); - constructors = ReorderConstructors(constructors); - foreach (var constructor in constructors) - { - bool isConstructor = MatchParameters(luaState, constructor, validConstructor, 0); - - if (!isConstructor) - continue; - - try - { - _translator.Push(luaState, constructor.Invoke(validConstructor.args)); - } - catch (TargetInvocationException e) - { - ThrowError(luaState, e); - return 1; - } - catch - { - luaState.PushNil(); - } - return 1; - } - - if (klass.UnderlyingSystemType.IsValueType) - { - int numLuaParams = luaState.GetTop(); - if (numLuaParams == 0) - { - _translator.Push(luaState, Activator.CreateInstance(klass.UnderlyingSystemType)); - 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)); - return 1; - } - - static bool IsInteger(double x) - { - return Math.Ceiling(x) == x; - } - - static object GetTargetObject(LuaState luaState, string operation, ObjectTranslator translator) - { - Type t; - object target = translator.GetRawNetObject(luaState, 1); - if (target != null) - { - t = target.GetType(); - if (t.HasMethod(operation)) - return target; - } - target = translator.GetRawNetObject(luaState, 2); - if (target != null) - { - t = target.GetType(); - if (t.HasMethod(operation)) - return target; - } - return null; - } - - static int MatchOperator(LuaState luaState, string operation, ObjectTranslator translator) - { - var validOperator = new MethodCache(); - - object target = GetTargetObject(luaState, operation, translator); - - if (target == null) - { - translator.ThrowError(luaState, "Cannot call " + operation + " on a nil object"); - return 1; - } - - Type type = target.GetType(); - var operators = type.GetMethods(operation, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static); - - foreach (var op in operators) - { - bool isOk = translator.MatchParameters(luaState, op, validOperator, 0); - - if (!isOk) - continue; - - object result; - if (op.IsStatic) - result = op.Invoke(null, validOperator.args); - else - result = op.Invoke(target, validOperator.args); - translator.Push(luaState, result); - return 1; - } - - translator.ThrowError(luaState, "Cannot call (" + operation + ") on object type " + type.Name); - return 1; - } - - internal Array TableToArray(LuaState luaState, ExtractValue extractValue, Type paramArrayType, ref int startIndex, int count) - { - Array paramArray; - - if (count == 0) - return Array.CreateInstance(paramArrayType, 0); - - var luaParamValue = extractValue(luaState, startIndex); - startIndex++; - - if (luaParamValue is LuaTable) - { - LuaTable table = (LuaTable)luaParamValue; - IDictionaryEnumerator tableEnumerator = table.GetEnumerator(); - tableEnumerator.Reset(); - paramArray = Array.CreateInstance(paramArrayType, table.Values.Count); - - int paramArrayIndex = 0; - - while (tableEnumerator.MoveNext()) - { - object value = tableEnumerator.Value; - - if (paramArrayType == typeof(object)) - { - if (value != null && value is double && IsInteger((double)value)) - value = Convert.ToInt32((double)value); - } - - paramArray.SetValue(Convert.ChangeType(value, paramArrayType), paramArrayIndex); - paramArrayIndex++; - } - } - else - { - paramArray = Array.CreateInstance(paramArrayType, count); - - paramArray.SetValue(luaParamValue, 0); - - for (int i = 1; i < count; i++) - { - var value = extractValue(luaState, startIndex); - paramArray.SetValue(value, i); - startIndex++; - } - - } - - return paramArray; - - } - - /* - * Matches a method against its arguments in the Lua stack. Returns - * if the match was successful. It it was also returns the information - * necessary to invoke the method. - */ - internal bool MatchParameters(LuaState luaState, MethodBase method, MethodCache methodCache, int skipParam) - { - var paramInfo = method.GetParameters(); - int currentLuaParam = 1; - int nLuaParams = luaState.GetTop() - skipParam; - var paramList = new List(); - var outList = new List(); - var argTypes = new List(); - - foreach (var currentNetParam in paramInfo) - { - if (!currentNetParam.IsIn && currentNetParam.IsOut) // Skips out params - { - paramList.Add(null); - outList.Add(paramList.Count - 1); - continue; - } // Type does not match, ignore if the parameter is optional - - ExtractValue extractValue; - if (IsParamsArray(luaState, nLuaParams, currentLuaParam, currentNetParam, out extractValue)) - { - int count = (nLuaParams - currentLuaParam) + 1; - Type paramArrayType = currentNetParam.ParameterType.GetElementType(); - - Array paramArray = TableToArray(luaState, extractValue, paramArrayType, ref currentLuaParam, count); - paramList.Add(paramArray); - int index = paramList.LastIndexOf(paramArray); - var methodArg = new MethodArgs(); - methodArg.Index = index; - methodArg.ExtractValue = extractValue; - methodArg.IsParamsArray = true; - methodArg.ParameterType = paramArrayType; - argTypes.Add(methodArg); - continue; - } - - if (currentLuaParam > nLuaParams) - { // Adds optional parameters - if (!currentNetParam.IsOptional) - return false; - paramList.Add(currentNetParam.DefaultValue); - continue; - } - - if (IsTypeCorrect(luaState, currentLuaParam, currentNetParam, out extractValue)) - { // Type checking - var value = extractValue(luaState, currentLuaParam); - paramList.Add(value); - int index = paramList.Count - 1; - var methodArg = new MethodArgs(); - methodArg.Index = index; - methodArg.ExtractValue = extractValue; - methodArg.ParameterType = currentNetParam.ParameterType; - argTypes.Add(methodArg); - - if (currentNetParam.ParameterType.IsByRef) - outList.Add(index); - - currentLuaParam++; - continue; - } - - if (currentNetParam.IsOptional) - { - paramList.Add(currentNetParam.DefaultValue); - continue; - } - - return false; - } - - if (currentLuaParam != nLuaParams + 1) // Number of parameters does not match - return false; - - methodCache.args = paramList.ToArray(); - methodCache.cachedMethod = method; - methodCache.outList = outList.ToArray(); - methodCache.argTypes = argTypes.ToArray(); - - return true; - } - - /// - /// Returns true if the type is set and assigns the extract value - /// - /// - /// - /// - /// - /// - private bool IsTypeCorrect(LuaState luaState, int currentLuaParam, ParameterInfo currentNetParam, out ExtractValue extractValue) - { - extractValue = _translator.typeChecker.CheckLuaType(luaState, currentLuaParam, currentNetParam.ParameterType); - return extractValue != null; - } - - private bool IsParamsArray(LuaState luaState, int nLuaParams, int currentLuaParam, ParameterInfo currentNetParam, out ExtractValue extractValue) - { - extractValue = null; - - if (!currentNetParam.GetCustomAttributes(typeof(ParamArrayAttribute), false).Any()) - return false; - - bool isParamArray = nLuaParams < currentLuaParam; - - LuaType luaType = luaState.Type(currentLuaParam); - - if (luaType == LuaType.Table) - { - extractValue = _translator.typeChecker.GetExtractor(typeof(LuaTable)); - if (extractValue != null) - return true; - } - else - { - Type paramElementType = currentNetParam.ParameterType.GetElementType(); - - extractValue = _translator.typeChecker.CheckLuaType(luaState, currentLuaParam, paramElementType); - - if (extractValue != null) - return true; - } - return isParamArray; - } - } -} diff --git a/src/LUA/Method/EventHandlerContainer.cs b/src/LUA/Method/EventHandlerContainer.cs deleted file mode 100644 index 0d1a9f1..0000000 --- a/src/LUA/Method/EventHandlerContainer.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Diagnostics; -using System.Collections.Generic; - -namespace NLua.Method -{ - /// - /// We keep track of what delegates we have auto attached to an event - to allow us to cleanly exit a NLua session - /// - class EventHandlerContainer : IDisposable - { - private readonly Dictionary _dict = new Dictionary(); - - public void Add(Delegate handler, RegisterEventHandler eventInfo) - { - _dict.Add(handler, eventInfo); - } - - public void Remove(Delegate handler) - { - bool found = _dict.Remove(handler); - Debug.Assert(found); - } - - /// - /// Remove any still registered handlers - /// - public void Dispose() - { - foreach (KeyValuePair pair in _dict) - pair.Value.RemovePending(pair.Key); - - _dict.Clear(); - } - } -} \ No newline at end of file diff --git a/src/LUA/Method/LuaClassHelper.cs b/src/LUA/Method/LuaClassHelper.cs deleted file mode 100644 index 381eb8c..0000000 --- a/src/LUA/Method/LuaClassHelper.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; - -namespace NLua.Method -{ - public class LuaClassHelper - { - /* - * Gets the function called name from the provided table, - * returning null if it does not exist - */ - public static LuaFunction GetTableFunction(LuaTable luaTable, string name) - { - if (luaTable == null) - return null; - - var funcObj = luaTable.RawGet(name) as LuaFunction; - - if (funcObj != null) - return funcObj; - return null; - } - - /* - * Calls the provided function with the provided parameters - */ - public static object CallFunction(LuaFunction function, object[] args, Type[] returnTypes, object[] inArgs, int[] outArgs) - { - // args is the return array of arguments, inArgs is the actual array - // of arguments passed to the function (with in parameters only), outArgs - // has the positions of out parameters - object returnValue; - int iRefArgs; - object[] returnValues = function.Call(inArgs, returnTypes); - - if (returnTypes[0] == typeof(void)) - { - returnValue = null; - iRefArgs = 0; - } - else - { - returnValue = returnValues[0]; - iRefArgs = 1; - } - - for (int i = 0; i < outArgs.Length; i++) - { - args[outArgs[i]] = returnValues[iRefArgs]; - iRefArgs++; - } - - return returnValue; - } - } -} \ No newline at end of file diff --git a/src/LUA/Method/LuaDelegate.cs b/src/LUA/Method/LuaDelegate.cs deleted file mode 100644 index 0d988ff..0000000 --- a/src/LUA/Method/LuaDelegate.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; - -namespace NLua.Method -{ - public class LuaDelegate - { - public LuaFunction Function; - public Type[] ReturnTypes; - - public LuaDelegate() - { - Function = null; - ReturnTypes = null; - } - - public object CallFunction(object[] args, object[] inArgs, int[] outArgs) - { - // args is the return array of arguments, inArgs is the actual array - // of arguments passed to the function (with in parameters only), outArgs - // has the positions of out parameters - object returnValue; - int iRefArgs; - object[] returnValues = Function.Call(inArgs, ReturnTypes); - - if (ReturnTypes[0] == typeof(void)) - { - returnValue = null; - iRefArgs = 0; - } - else - { - returnValue = returnValues[0]; - iRefArgs = 1; - } - - // Sets the value of out and ref parameters (from - // the values returned by the Lua function). - for (int i = 0; i < outArgs.Length; i++) - { - args[outArgs[i]] = returnValues[iRefArgs]; - iRefArgs++; - } - - return returnValue; - } - } -} \ No newline at end of file diff --git a/src/LUA/Method/LuaEventHandler.cs b/src/LUA/Method/LuaEventHandler.cs deleted file mode 100644 index 49538dc..0000000 --- a/src/LUA/Method/LuaEventHandler.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace NLua.Method -{ - public class LuaEventHandler - { - public LuaFunction Handler = null; - - public void HandleEvent(object[] args) - { - Handler.Call(args); - } - } -} \ No newline at end of file diff --git a/src/LUA/Method/LuaMethodWrapper.cs b/src/LUA/Method/LuaMethodWrapper.cs deleted file mode 100644 index 22b5686..0000000 --- a/src/LUA/Method/LuaMethodWrapper.cs +++ /dev/null @@ -1,355 +0,0 @@ -using System; -using System.Reflection; -using System.Collections.Generic; -using System.Linq; - -using NLua.Exceptions; -using NLua.Extensions; - -using LuaState = KeraLua.Lua; -using LuaNativeFunction = KeraLua.LuaFunction; - -namespace NLua.Method -{ - /* - * Argument extraction with type-conversion function - */ - delegate object ExtractValue(LuaState luaState, int stackPos); - - /* - * Wrapper class for methods/constructors accessed from Lua. - * - */ - class LuaMethodWrapper - { - internal LuaNativeFunction InvokeFunction; - - readonly ObjectTranslator _translator; - readonly MethodBase _method; - - readonly ExtractValue _extractTarget; - readonly object _target; - readonly bool _isStatic; - - readonly string _methodName; - readonly MethodInfo[] _members; - - private MethodCache _lastCalledMethod; - - - /* - * Constructs the wrapper for a known MethodBase instance - */ - public LuaMethodWrapper(ObjectTranslator translator, object target, ProxyType targetType, MethodBase method) - { - InvokeFunction = Call; - _translator = translator; - _target = target; - _extractTarget = translator.typeChecker.GetExtractor(targetType); - _lastCalledMethod = new MethodCache(); - - _method = method; - _methodName = method.Name; - _isStatic = method.IsStatic; - - } - - /* - * Constructs the wrapper for a known method name - */ - public LuaMethodWrapper(ObjectTranslator translator, ProxyType targetType, string methodName, BindingFlags bindingType) - { - InvokeFunction = Call; - - _translator = translator; - _methodName = methodName; - _extractTarget = translator.typeChecker.GetExtractor(targetType); - _lastCalledMethod = new MethodCache(); - - _isStatic = (bindingType & BindingFlags.Static) == BindingFlags.Static; - MethodInfo [] methods = GetMethodsRecursively(targetType.UnderlyingSystemType, - methodName, - bindingType | BindingFlags.Public); - _members = ReorderMethods(methods); - } - - private static MethodInfo[] ReorderMethods(MethodInfo[] m) - { - int len = m.Length; - - if (len < 2) - return m; - - return m. - GroupBy(c => c.GetParameters().Length). - SelectMany(g => g.OrderByDescending(ci => ci.ToString())). - ToArray(); - } - - MethodInfo[] GetMethodsRecursively(Type type, string methodName, BindingFlags bindingType) - { - if (type == typeof(object)) - return type.GetMethods(methodName, bindingType); - - var methods = type.GetMethods(methodName, bindingType); - var baseMethods = GetMethodsRecursively(type.BaseType, methodName, bindingType); - - return methods.Concat(baseMethods).ToArray(); - } - - /// - /// Convert C# exceptions into Lua errors - /// - /// num of things on stack - /// null for no pending exception - int SetPendingException(Exception e) - { - return _translator.interpreter.SetPendingException(e); - } - - void FillMethodArguments(LuaState luaState, int numStackToSkip) - { - object[] args = _lastCalledMethod.args; - - - for (int i = 0; i < _lastCalledMethod.argTypes.Length; i++) - { - MethodArgs type = _lastCalledMethod.argTypes[i]; - - int index = i + 1 + numStackToSkip; - - - if (_lastCalledMethod.argTypes[i].IsParamsArray) - { - int count = _lastCalledMethod.argTypes.Length - i; - Array paramArray = _translator.TableToArray(luaState, type.ExtractValue, type.ParameterType, index, count); - args[_lastCalledMethod.argTypes[i].Index] = paramArray; - } - else - { - args[type.Index] = type.ExtractValue(luaState, index); - } - - if (_lastCalledMethod.args[_lastCalledMethod.argTypes[i].Index] == null && - !luaState.IsNil(i + 1 + numStackToSkip)) - throw new LuaException(string.Format("Argument number {0} is invalid", (i + 1))); - } - } - - int PushReturnValue(LuaState luaState) - { - int nReturnValues = 0; - // Pushes out and ref return values - for (int index = 0; index < _lastCalledMethod.outList.Length; index++) - { - nReturnValues++; - _translator.Push(luaState, _lastCalledMethod.args[_lastCalledMethod.outList[index]]); - } - - // 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; - } - - int CallInvoke(LuaState luaState, MethodBase method, object targetObject) - { - if (!luaState.CheckStack(_lastCalledMethod.outList.Length + 6)) - throw new LuaException("Lua stack overflow"); - - try - { - object result; - - if (method.IsConstructor) - result = ((ConstructorInfo)method).Invoke(_lastCalledMethod.args); - else - result = method.Invoke(targetObject, _lastCalledMethod.args); - - _translator.Push(luaState, result); - } - catch (TargetInvocationException e) - { - // Failure of method invocation - if (_translator.interpreter.UseTraceback) - e.GetBaseException().Data["Traceback"] = _translator.interpreter.GetDebugTraceback(); - return SetPendingException(e.GetBaseException()); - } - catch (Exception e) - { - return SetPendingException(e); - } - - return PushReturnValue(luaState); - } - - bool IsMethodCached(LuaState luaState, int numArgsPassed, int skipParams) - { - if (_lastCalledMethod.cachedMethod == null) - return false; - - if (numArgsPassed != _lastCalledMethod.argTypes.Length) - return false; - - // If there is no method overloads, is ok to use the cached method - if (_members.Length == 1) - return true; - - return _translator.MatchParameters(luaState, _lastCalledMethod.cachedMethod, _lastCalledMethod, skipParams); - } - - int CallMethodFromName(LuaState luaState) - { - object targetObject = null; - - if (!_isStatic) - targetObject = _extractTarget(luaState, 1); - - 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 = luaState.GetTop() - numStackToSkip; - - // Cached? - if (IsMethodCached(luaState, numArgsPassed, numStackToSkip)) - { - MethodBase method = _lastCalledMethod.cachedMethod; - - if (!luaState.CheckStack(_lastCalledMethod.outList.Length + 6)) - throw new LuaException("Lua stack overflow"); - - FillMethodArguments(luaState, numStackToSkip); - - return CallInvoke(luaState, method, targetObject); - } - - // If we are running an instance variable, we can now pop the targetObject from the stack - if (!_isStatic) - { - if (targetObject == null) - { - _translator.ThrowError(luaState, - string.Format("instance method '{0}' requires a non null target object", _methodName)); - return 1; - } - - luaState.Remove(1); // Pops the receiver - } - - bool hasMatch = false; - string candidateName = null; - - foreach (var member in _members) - { - if (member.ReflectedType == null) - continue; - - candidateName = member.ReflectedType.Name + "." + member.Name; - bool isMethod = _translator.MatchParameters(luaState, member, _lastCalledMethod, 0); - - 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); - return 1; - } - - if (_lastCalledMethod.cachedMethod.ContainsGenericParameters) - return CallInvokeOnGenericMethod(luaState, (MethodInfo)_lastCalledMethod.cachedMethod, targetObject); - - return CallInvoke(luaState, _lastCalledMethod.cachedMethod, targetObject); - } - - int CallInvokeOnGenericMethod(LuaState luaState, MethodInfo methodToCall, object targetObject) - { - //need to make a concrete type of the generic method definition - var typeArgs = new List(); - - ParameterInfo [] parameters = methodToCall.GetParameters(); - - for (int i = 0; i < parameters.Length; i++) - { - ParameterInfo parameter = parameters[i]; - - if (!parameter.ParameterType.IsGenericParameter) - continue; - - typeArgs.Add(_lastCalledMethod.args[i].GetType()); - } - - MethodInfo concreteMethod = methodToCall.MakeGenericMethod(typeArgs.ToArray()); - - _translator.Push(luaState, concreteMethod.Invoke(targetObject, _lastCalledMethod.args)); - - return PushReturnValue(luaState); - } - - /* - * Calls the method. Receives the arguments from the Lua stack - * and returns values in it. - */ - int Call(IntPtr state) - { - var luaState = LuaState.FromIntPtr(state); - - MethodBase methodToCall = _method; - object targetObject = _target; - - if (!luaState.CheckStack(5)) - throw new LuaException("Lua stack overflow"); - - SetPendingException(null); - - // Method from name - if (methodToCall == null) - return CallMethodFromName(luaState); - - // Method from MethodBase instance - if (!methodToCall.ContainsGenericParameters) - { - if (!methodToCall.IsStatic && !methodToCall.IsConstructor && targetObject == null) - { - targetObject = _extractTarget(luaState, 1); - luaState.Remove(1); // Pops the receiver - } - - if (!_translator.MatchParameters(luaState, methodToCall, _lastCalledMethod, 0)) - { - _translator.ThrowError(luaState, "Invalid arguments to method call"); - return 1; - } - } - else - { - if (!methodToCall.IsGenericMethodDefinition) - { - _translator.ThrowError(luaState, - "Unable to invoke method on generic class as the current method is an open generic method"); - return 1; - } - - _translator.MatchParameters(luaState, methodToCall, _lastCalledMethod, 0); - - return CallInvokeOnGenericMethod(luaState, (MethodInfo) methodToCall, targetObject); - } - - if (_isStatic) - targetObject = null; - - return CallInvoke(luaState, _lastCalledMethod.cachedMethod, targetObject); - } - } -} diff --git a/src/LUA/Method/MethodArgs.cs b/src/LUA/Method/MethodArgs.cs deleted file mode 100644 index 4b7db00..0000000 --- a/src/LUA/Method/MethodArgs.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; - -namespace NLua.Method -{ - /* - * Parameter information - */ - class MethodArgs - { - // Position of parameter - public int Index; - public Type ParameterType; - - // Type-conversion function - public ExtractValue ExtractValue; - public bool IsParamsArray; - } -} \ No newline at end of file diff --git a/src/LUA/Method/MethodCache.cs b/src/LUA/Method/MethodCache.cs deleted file mode 100644 index 74bc5e6..0000000 --- a/src/LUA/Method/MethodCache.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Reflection; -using NLua.Extensions; - -namespace NLua.Method -{ - class MethodCache - { - public MethodCache() - { - args = new object[0]; - argTypes = new MethodArgs[0]; - outList = new int[0]; - } - private MethodBase _cachedMethod; - - public MethodBase cachedMethod { - get - { - return _cachedMethod; - } - set - { - _cachedMethod = value; - var mi = value as MethodInfo; - - if (mi != null) - { - IsReturnVoid = mi.ReturnType == typeof(void); - } - } - } - - public bool IsReturnVoid; - // List or arguments - public object[] args; - // Positions of out parameters - public int[] outList; - // Types of parameters - public MethodArgs[] argTypes; - } -} \ No newline at end of file diff --git a/src/LUA/Method/RegisterEventHandler.cs b/src/LUA/Method/RegisterEventHandler.cs deleted file mode 100644 index 5736062..0000000 --- a/src/LUA/Method/RegisterEventHandler.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Reflection; - -namespace NLua.Method -{ - class RegisterEventHandler - { - private readonly EventHandlerContainer _pendingEvents; - private readonly EventInfo _eventInfo; - private readonly object _target; - - public RegisterEventHandler(EventHandlerContainer pendingEvents, object target, EventInfo eventInfo) - { - _target = target; - _eventInfo = eventInfo; - _pendingEvents = pendingEvents; - } - - /* - * Adds a new event handler - */ - public Delegate Add(LuaFunction function) - { - Delegate handlerDelegate = CodeGeneration.Instance.GetDelegate(_eventInfo.EventHandlerType, function); - return Add(handlerDelegate); - } - - public Delegate Add(Delegate handlerDelegate) - { - _eventInfo.AddEventHandler(_target, handlerDelegate); - _pendingEvents.Add(handlerDelegate, this); - - return handlerDelegate; - } - - /* - * Removes an existing event handler - */ - public void Remove(Delegate handlerDelegate) - { - RemovePending(handlerDelegate); - _pendingEvents.Remove(handlerDelegate); - } - - /* - * Removes an existing event handler (without updating the pending handlers list) - */ - internal void RemovePending(Delegate handlerDelegate) - { - _eventInfo.RemoveEventHandler(_target, handlerDelegate); - } - } -} \ No newline at end of file diff --git a/src/LUA/ObjectTranslator.cs b/src/LUA/ObjectTranslator.cs deleted file mode 100644 index 5d5dfb0..0000000 --- a/src/LUA/ObjectTranslator.cs +++ /dev/null @@ -1,1171 +0,0 @@ -using System; -using System.IO; -using System.Reflection; -using System.Collections.Generic; -using System.Collections.Concurrent; -using System.Runtime.InteropServices; -using KeraLua; - -using NLua.Method; -using NLua.Exceptions; -using NLua.Extensions; - -#if __IOS__ || __TVOS__ || __WATCHOS__ - using ObjCRuntime; -#endif - -using LuaState = KeraLua.Lua; -using LuaNativeFunction = KeraLua.LuaFunction; - -namespace NLua -{ - public class ObjectTranslator - { - // Compare cache entries by exact reference to avoid unwanted aliases - private class ReferenceComparer : IEqualityComparer - { - public new bool Equals(object x, object y) - { - if (x != null && y != null && x.GetType() == y.GetType() && x.GetType().IsValueType && y.GetType().IsValueType) - return x.Equals(y); // Special case for boxed value types - return ReferenceEquals(x, y); - } - - public int GetHashCode(object obj) - { - return obj.GetHashCode(); - } - } - - private static readonly LuaNativeFunction _registerTableFunction = RegisterTable; - private static readonly LuaNativeFunction _unregisterTableFunction = UnregisterTable; - private static readonly LuaNativeFunction _getMethodSigFunction = GetMethodSignature; - private static readonly LuaNativeFunction _getConstructorSigFunction = GetConstructorSignature; - private static readonly LuaNativeFunction _importTypeFunction = ImportType; - private static readonly LuaNativeFunction _loadAssemblyFunction = LoadAssembly; - private static readonly LuaNativeFunction _ctypeFunction = CType; - private static readonly LuaNativeFunction _enumFromIntFunction = EnumFromInt; - - // object to object # - readonly Dictionary _objectsBackMap = new Dictionary(new ReferenceComparer()); - // object # to object (FIXME - it should be possible to get object address as an object #) - readonly Dictionary _objects = new Dictionary(); - - readonly ConcurrentQueue finalizedReferences = new ConcurrentQueue(); - - internal EventHandlerContainer PendingEvents = new EventHandlerContainer(); - MetaFunctions metaFunctions; - List assemblies; - internal CheckType typeChecker; - internal Lua interpreter; - /// - /// We want to ensure that objects always have a unique ID - /// - int _nextObj; - - public MetaFunctions MetaFunctionsInstance => metaFunctions; - public Lua Interpreter => interpreter; - public IntPtr Tag => _tagPtr; - - readonly IntPtr _tagPtr; - - public ObjectTranslator(Lua interpreter, LuaState luaState) - { - _tagPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(int))); - this.interpreter = interpreter; - typeChecker = new CheckType(this); - metaFunctions = new MetaFunctions(this); - assemblies = new List(); - - 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(LuaState luaState) - { - luaState.PushString("luaNet_objects"); - luaState.NewTable(); - luaState.NewTable(); - luaState.PushString("__mode"); - luaState.PushString("v"); - luaState.SetTable(-3); - luaState.SetMetaTable(-2); - luaState.SetTable((int)LuaRegistry.Index); - } - - /* - * Registers the indexing function of CLR objects - * passed to Lua - */ - private void CreateIndexingMetaFunction(LuaState luaState) - { - luaState.PushString("luaNet_indexfunction"); - luaState.DoString(MetaFunctions.LuaIndexFunction); - luaState.RawSet(LuaRegistry.Index); - } - - /* - * Creates the metatable for superclasses (the base - * field of registered tables) - */ - private void CreateBaseClassMetatable(LuaState luaState) - { - luaState.NewMetaTable("luaNet_searchbase"); - luaState.PushString("__gc"); - luaState.PushCFunction(MetaFunctions.GcFunction); - luaState.SetTable(-3); - luaState.PushString("__tostring"); - luaState.PushCFunction(MetaFunctions.ToStringFunction); - luaState.SetTable(-3); - luaState.PushString("__index"); - luaState.PushCFunction(MetaFunctions.BaseIndexFunction); - luaState.SetTable(-3); - luaState.PushString("__newindex"); - luaState.PushCFunction(MetaFunctions.NewIndexFunction); - luaState.SetTable(-3); - luaState.SetTop(-2); - } - - /* - * Creates the metatable for type references - */ - private void CreateClassMetatable(LuaState luaState) - { - luaState.NewMetaTable("luaNet_class"); - luaState.PushString("__gc"); - luaState.PushCFunction(MetaFunctions.GcFunction); - luaState.SetTable(-3); - luaState.PushString("__tostring"); - luaState.PushCFunction(MetaFunctions.ToStringFunction); - luaState.SetTable(-3); - luaState.PushString("__index"); - luaState.PushCFunction(MetaFunctions.ClassIndexFunction); - luaState.SetTable(-3); - luaState.PushString("__newindex"); - luaState.PushCFunction(MetaFunctions.ClassNewIndexFunction); - luaState.SetTable(-3); - luaState.PushString("__call"); - luaState.PushCFunction(MetaFunctions.CallConstructorFunction); - luaState.SetTable(-3); - luaState.SetTop(-2); - } - - /* - * Registers the global functions used by NLua - */ - private void SetGlobalFunctions(LuaState luaState) - { - luaState.PushCFunction(MetaFunctions.IndexFunction); - luaState.SetGlobal("get_object_member"); - luaState.PushCFunction(_importTypeFunction); - luaState.SetGlobal("import_type"); - luaState.PushCFunction(_loadAssemblyFunction); - luaState.SetGlobal("load_assembly"); - luaState.PushCFunction(_registerTableFunction); - luaState.SetGlobal("make_object"); - luaState.PushCFunction(_unregisterTableFunction); - luaState.SetGlobal("free_object"); - luaState.PushCFunction(_getMethodSigFunction); - luaState.SetGlobal("get_method_bysig"); - luaState.PushCFunction(_getConstructorSigFunction); - luaState.SetGlobal("get_constructor_bysig"); - luaState.PushCFunction(_ctypeFunction); - luaState.SetGlobal("ctype"); - luaState.PushCFunction(_enumFromIntFunction); - luaState.SetGlobal("enum"); - } - - /* - * Creates the metatable for delegates - */ - private void CreateFunctionMetatable(LuaState luaState) - { - luaState.NewMetaTable("luaNet_function"); - luaState.PushString("__gc"); - luaState.PushCFunction(MetaFunctions.GcFunction); - luaState.SetTable(-3); - luaState.PushString("__call"); - luaState.PushCFunction(MetaFunctions.ExecuteDelegateFunction); - luaState.SetTable(-3); - luaState.SetTop(-2); - } - - /* - * Passes errors (argument e) to the Lua interpreter - */ - internal void ThrowError(LuaState luaState, object e) - { - // We use this to remove anything pushed by luaL_where - int oldTop = luaState.GetTop(); - - // 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 - luaState.Where(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 != null) - { - // Wrap Lua error (just a string) and store the error location - if (interpreter.UseTraceback) - message += Environment.NewLine + interpreter.GetDebugTraceback(); - e = new LuaScriptException(message, errLocation); - } - else - { - var ex = e as Exception; - - if (ex != null) - { - // Wrap generic .NET exception as an InnerException and store the error location - if (interpreter.UseTraceback) ex.Data["Traceback"] = interpreter.GetDebugTraceback(); - e = new LuaScriptException(ex, errLocation); - } - } - - Push(luaState, e); - } - - /* - * Implementation of load_assembly. Throws an error - * if the assembly is not found. - */ -#if __IOS__ || __TVOS__ || __WATCHOS__ - [MonoPInvokeCallback(typeof(LuaNativeFunction))] -#endif - private static int LoadAssembly(IntPtr luaState) - { - var state = LuaState.FromIntPtr(luaState); - var translator = ObjectTranslatorPool.Instance.Find(state); - int result = translator.LoadAssemblyInternal(state); - var exception = translator.GetObject(state, -1) as LuaScriptException; - - if (exception != null) - return state.Error(); - return result; - } - - private int LoadAssemblyInternal(LuaState luaState) - { - try - { - string assemblyName = luaState.ToString(1, false); - Assembly assembly = null; - Exception exception = null; - - try - { - assembly = Assembly.Load(assemblyName); - } - catch (BadImageFormatException) - { - // The assemblyName was invalid. It is most likely a path. - } - catch (FileNotFoundException e) - { - exception = e; - } - - if (assembly == null) - { - try - { - assembly = Assembly.Load(AssemblyName.GetAssemblyName(assemblyName)); - } - catch (FileNotFoundException e) - { - exception = e; - } - if (assembly == null) - { - AssemblyName mscor = assemblies[0].GetName(); - AssemblyName name = new AssemblyName(); - name.Name = assemblyName; - name.CultureInfo = mscor.CultureInfo; - name.Version = mscor.Version; - name.SetPublicKeyToken(mscor.GetPublicKeyToken()); - name.SetPublicKey(mscor.GetPublicKey()); - assembly = Assembly.Load(name); - - if (assembly != null) - exception = null; - } - if (exception != null) - { - ThrowError(luaState, exception); - return 1; - } - } - if (assembly != null && !assemblies.Contains(assembly)) - assemblies.Add(assembly); - } - catch (Exception e) - { - ThrowError(luaState, e); - return 1; - } - return 0; - } - - internal Type FindType(string className) - { - foreach (var assembly in assemblies) - { - var klass = assembly.GetType(className); - - if (klass != null) - return klass; - } - return null; - } - - public bool TryGetExtensionMethod(Type type, string name, out MethodInfo method) - { - method = GetExtensionMethod(type, name); - return method != null; - } - - public MethodInfo GetExtensionMethod(Type type, string name) - { - return type.GetExtensionMethod(name, assemblies); - } - - /* - * Implementation of import_type. Returns nil if the - * type is not found. - */ -#if __IOS__ || __TVOS__ || __WATCHOS__ - [MonoPInvokeCallback(typeof(LuaNativeFunction))] -#endif - private static int ImportType(IntPtr luaState) - { - var state = LuaState.FromIntPtr(luaState); - var translator = ObjectTranslatorPool.Instance.Find(state); - return translator.ImportTypeInternal(state); - } - - private int ImportTypeInternal(LuaState luaState) - { - string className = luaState.ToString(1, false); - var klass = FindType(className); - - if (klass != null) - PushType(luaState, klass); - else - luaState.PushNil(); - - 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 __IOS__ || __TVOS__ || __WATCHOS__ - [MonoPInvokeCallback(typeof(LuaNativeFunction))] -#endif - private static int RegisterTable(IntPtr luaState) - { - var state = LuaState.FromIntPtr(luaState); - var translator = ObjectTranslatorPool.Instance.Find(state); - int result = translator.RegisterTableInternal(state); - var exception = translator.GetObject(state, -1) as LuaScriptException; - - if (exception != null) - return state.Error(); - return result; - } - - private int RegisterTableInternal(LuaState luaState) - { - if (luaState.Type(1) != LuaType.Table) - { - ThrowError(luaState, "register_table: first arg is not a table"); - return 1; - } - - LuaTable luaTable = GetTable(luaState, 1); - string superclassName = luaState.ToString(2, false); - - if (string.IsNullOrEmpty(superclassName)) - { - ThrowError(luaState, "register_table: superclass name can not be null"); - return 1; - } - - var klass = FindType(superclassName); - - if (klass == null) - { - ThrowError(luaState, "register_table: can not find superclass '" + superclassName + "'"); - return 1; - } - - // 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"); - luaState.NewTable(); - luaState.PushString("__index"); - luaState.PushCopy(-3); - luaState.SetTable(-3); - luaState.PushString("__newindex"); - luaState.PushCopy(-3); - luaState.SetTable(-3); - luaState.SetMetaTable(1); - - // Pushes the object again, this time as the base field - // of the table and with the luaNet_searchbase metatable - luaState.PushString("base"); - int index = AddObject(obj); - PushNewObject(luaState, obj, index, "luaNet_searchbase"); - luaState.RawSet(1); - - return 0; - } - - /* - * Implementation of free_object. Clears the metatable and the - * base field, freeing the created object for garbage-collection - */ -#if __IOS__ || __TVOS__ || __WATCHOS__ - [MonoPInvokeCallback(typeof(LuaNativeFunction))] -#endif - private static int UnregisterTable(IntPtr luaState) - { - var state = LuaState.FromIntPtr(luaState); - var translator = ObjectTranslatorPool.Instance.Find(state); - int result = translator.UnregisterTableInternal(state); - var exception = translator.GetObject(state, -1) as LuaScriptException; - - if (exception != null) - return state.Error(); - return result; - } - - private int UnregisterTableInternal(LuaState luaState) - { - - if (!luaState.GetMetaTable(1)) - { - ThrowError(luaState, "unregister_table: arg is not valid table"); - return 1; - } - - luaState.PushString("__index"); - luaState.GetTable(-2); - object obj = GetRawNetObject(luaState, -1); - - if (obj == null) - { - ThrowError(luaState, "unregister_table: arg is not valid table"); - return 1; - } - - var luaTableField = obj.GetType().GetField("__luaInterface_luaTable"); - - if (luaTableField == null) - { - ThrowError(luaState, "unregister_table: arg is not valid table"); - return 1; - } - - // ReSharper disable once PossibleNullReferenceException - luaTableField.SetValue(obj, null); - luaState.PushNil(); - luaState.SetMetaTable(1); - luaState.PushString("base"); - luaState.PushNil(); - luaState.SetTable(1); - - return 0; - } - - /* - * Implementation of get_method_bysig. Returns nil - * if no matching method is not found. - */ -#if __IOS__ || __TVOS__ || __WATCHOS__ - [MonoPInvokeCallback(typeof(LuaNativeFunction))] -#endif - private static int GetMethodSignature(IntPtr luaState) - { - var state = LuaState.FromIntPtr(luaState); - var translator = ObjectTranslatorPool.Instance.Find(state); - int result = translator.GetMethodSignatureInternal(state); - var exception = translator.GetObject(state, -1) as LuaScriptException; - - if (exception != null) - return state.Error(); - return result; - } - - private int GetMethodSignatureInternal(LuaState luaState) - { - ProxyType klass; - object target; - int udata = luaState.CheckUObject(1, "luaNet_class"); - - if (udata != -1) - { - klass = (ProxyType)_objects[udata]; - target = null; - } - else - { - target = GetRawNetObject(luaState, 1); - - if (target == null) - { - ThrowError(luaState, "get_method_bysig: first arg is not type or object reference"); - return 1; - } - - klass = new ProxyType(target.GetType()); - } - - string methodName = luaState.ToString(2, false); - var signature = new Type[luaState.GetTop() - 2]; - - for (int i = 0; i < signature.Length; i++) - signature[i] = FindType(luaState.ToString(i + 3, false)); - - try - { - var method = klass.GetMethod(methodName, BindingFlags.Public | BindingFlags.Static | - BindingFlags.Instance, signature); - var wrapper = new LuaMethodWrapper(this, target, klass, method); - LuaNativeFunction invokeDelegate = wrapper.InvokeFunction; - PushFunction(luaState, invokeDelegate); - } - catch (Exception e) - { - ThrowError(luaState, e); - } - - return 1; - } - - /* - * Implementation of get_constructor_bysig. Returns nil - * if no matching constructor is found. - */ -#if __IOS__ || __TVOS__ || __WATCHOS__ - [MonoPInvokeCallback(typeof(LuaNativeFunction))] -#endif - private static int GetConstructorSignature(IntPtr luaState) - { - var state = LuaState.FromIntPtr(luaState); - var translator = ObjectTranslatorPool.Instance.Find(state); - int result = translator.GetConstructorSignatureInternal(state); - var exception = translator.GetObject(state, -1) as LuaScriptException; - - if (exception != null) - return state.Error(); - return result; - } - - private int GetConstructorSignatureInternal(LuaState luaState) - { - ProxyType klass = null; - int udata = luaState.CheckUObject(1, "luaNet_class"); - - if (udata != -1) - klass = (ProxyType)_objects[udata]; - - if (klass == null) - { - ThrowError(luaState, "get_constructor_bysig: first arg is invalid type reference"); - return 1; - } - - var signature = new Type[luaState.GetTop() - 1]; - - for (int i = 0; i < signature.Length; i++) - signature[i] = FindType(luaState.ToString(i + 2, false)); - - try - { - ConstructorInfo constructor = klass.UnderlyingSystemType.GetConstructor(signature); - var wrapper = new LuaMethodWrapper(this, null, klass, constructor); - var invokeDelegate = wrapper.InvokeFunction; - PushFunction(luaState, invokeDelegate); - } - catch (Exception e) - { - ThrowError(luaState, e); - } - return 1; - } - - /* - * Pushes a type reference into the stack - */ - internal void PushType(LuaState luaState, Type t) - { - PushObject(luaState, new ProxyType(t), "luaNet_class"); - } - - /* - * Pushes a delegate into the stack - */ - internal void PushFunction(LuaState luaState, LuaNativeFunction func) - { - PushObject(luaState, func, "luaNet_function"); - } - - - /* - * Pushes a CLR object into the Lua stack as an userdata - * with the provided metatable - */ - internal void PushObject(LuaState luaState, object o, string metatable) - { - int index = -1; - - // Pushes nil - if (o == null) - { - luaState.PushNil(); - return; - } - - // Object already in the list of Lua objects? Push the stored reference. - bool found = (!o.GetType().IsValueType || o.GetType().IsEnum) && _objectsBackMap.TryGetValue(o, out index); - - if (found) - { - luaState.GetMetaTable("luaNet_objects"); - luaState.RawGetInteger(-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 = luaState.Type(-1); - if (type != LuaType.Nil) - { - luaState.Remove(-2); // drop the metatable - we're going to leave our object on the stack - return; - } - - // MetaFunctions.dumpStack(this, luaState); - luaState.Remove(-1); // remove the nil object value - luaState.Remove(-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(LuaState luaState, object o, int index, string metatable) - { - if (metatable == "luaNet_metatable") - { - // Gets or creates the metatable for the object's type - luaState.GetMetaTable(o.GetType().AssemblyQualifiedName); - - if (luaState.IsNil(-1)) - { - luaState.SetTop(-2); - luaState.NewMetaTable(o.GetType().AssemblyQualifiedName); - luaState.PushString("cache"); - luaState.NewTable(); - luaState.RawSet(-3); - luaState.PushLightUserData(_tagPtr); - luaState.PushNumber(1); - luaState.RawSet(-3); - luaState.PushString("__index"); - luaState.PushString("luaNet_indexfunction"); - luaState.RawGet(LuaRegistry.Index); - luaState.RawSet(-3); - luaState.PushString("__gc"); - luaState.PushCFunction(MetaFunctions.GcFunction); - luaState.RawSet(-3); - luaState.PushString("__tostring"); - luaState.PushCFunction(MetaFunctions.ToStringFunction); - luaState.RawSet(-3); - luaState.PushString("__newindex"); - luaState.PushCFunction(MetaFunctions.NewIndexFunction); - luaState.RawSet(-3); - // Bind C# operator with Lua metamethods (__add, __sub, __mul) - RegisterOperatorsFunctions(luaState, o.GetType()); - RegisterCallMethodForDelegate(luaState, o); - } - } - else - luaState.GetMetaTable(metatable); - - // Stores the object index in the Lua list and pushes the - // index into the Lua stack - luaState.GetMetaTable("luaNet_objects"); - luaState.NewUData(index); - luaState.PushCopy(-3); - luaState.Remove(-4); - luaState.SetMetaTable(-2); - luaState.PushCopy(-1); - luaState.RawSetInteger(-3, index); - luaState.Remove(-2); - } - - void RegisterCallMethodForDelegate(LuaState luaState, object o) - { - if (!(o is Delegate)) - return; - - luaState.PushString("__call"); - luaState.PushCFunction(MetaFunctions.CallDelegateFunction); - luaState.RawSet(-3); - } - - void RegisterOperatorsFunctions(LuaState luaState, Type type) - { - if (type.HasAdditionOperator()) - { - luaState.PushString("__add"); - luaState.PushCFunction(MetaFunctions.AddFunction); - luaState.RawSet(-3); - } - if (type.HasSubtractionOperator()) - { - luaState.PushString("__sub"); - luaState.PushCFunction(MetaFunctions.SubtractFunction); - luaState.RawSet(-3); - } - if (type.HasMultiplyOperator()) - { - luaState.PushString("__mul"); - luaState.PushCFunction(MetaFunctions.MultiplyFunction); - luaState.RawSet(-3); - } - if (type.HasDivisionOperator()) - { - luaState.PushString("__div"); - luaState.PushCFunction(MetaFunctions.DivisionFunction); - luaState.RawSet(-3); - } - if (type.HasModulusOperator()) - { - luaState.PushString("__mod"); - luaState.PushCFunction(MetaFunctions.ModulosFunction); - luaState.RawSet(-3); - } - if (type.HasUnaryNegationOperator()) - { - luaState.PushString("__unm"); - luaState.PushCFunction(MetaFunctions.UnaryNegationFunction); - luaState.RawSet(-3); - } - if (type.HasEqualityOperator()) - { - luaState.PushString("__eq"); - luaState.PushCFunction(MetaFunctions.EqualFunction); - luaState.RawSet(-3); - } - if (type.HasLessThanOperator()) - { - luaState.PushString("__lt"); - luaState.PushCFunction(MetaFunctions.LessThanFunction); - luaState.RawSet(-3); - } - if (type.HasLessThanOrEqualOperator()) - { - luaState.PushString("__le"); - luaState.PushCFunction(MetaFunctions.LessThanOrEqualFunction); - luaState.RawSet(-3); - } - } - - /* - * Gets an object from the Lua stack with the desired type, if it matches, otherwise - * returns null. - */ - internal object GetAsType(LuaState luaState, int stackPos, Type paramType) - { - var extractor = typeChecker.CheckLuaType(luaState, stackPos, paramType); - return extractor != null ? extractor(luaState, stackPos) : null; - } - - /// - /// Given the Lua int ID for an object remove it from our maps - /// - /// - 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) - CollectObject(o, udata); - } - - /// - /// Given an object reference, remove it from our maps - /// - /// - /// - private void CollectObject(object o, int udata) - { - _objects.Remove(udata); - if (!o.GetType().IsValueType || o.GetType().IsEnum) - _objectsBackMap.Remove(o); - } - - private int AddObject(object obj) - { - // New object: inserts it in the list - int index = _nextObj++; - _objects[index] = obj; - - if (!obj.GetType().IsValueType || obj.GetType().IsEnum) - _objectsBackMap[obj] = index; - - return index; - } - - /* - * Gets an object from the Lua stack according to its Lua type. - */ - internal object GetObject(LuaState luaState, int index) - { - LuaType type = luaState.Type(index); - - switch (type) - { - case LuaType.Number: - { - if (luaState.IsInteger(index)) - return luaState.ToInteger(index); - - return luaState.ToNumber(index); - } - case LuaType.String: - return luaState.ToString(index, false); - case LuaType.Boolean: - return luaState.ToBoolean(index); - case LuaType.Table: - return GetTable(luaState, index); - case LuaType.Function: - return GetFunction(luaState, index); - case LuaType.UserData: - { - int udata = luaState.ToNetObject(index, Tag); - 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(LuaState luaState, int index) - { - // Before create new tables, check if there is any finalized object to clean. - CleanFinalizedReferences(luaState); - - luaState.PushCopy(index); - int reference = luaState.Ref(LuaRegistry.Index); - if (reference == -1) - return null; - return new LuaTable(reference, interpreter); - } - - /* - * Gets the userdata in the index positon of the Lua stack. - */ - internal LuaUserData GetUserData(LuaState luaState, int index) - { - // Before create new tables, check if there is any finalized object to clean. - CleanFinalizedReferences(luaState); - - luaState.PushCopy(index); - int reference = luaState.Ref(LuaRegistry.Index); - if (reference == -1) - return null; - return new LuaUserData(reference, interpreter); - } - - /* - * Gets the function in the index positon of the Lua stack. - */ - internal LuaFunction GetFunction(LuaState luaState, int index) - { - // Before create new tables, check if there is any finalized object to clean. - CleanFinalizedReferences(luaState); - - luaState.PushCopy(index); - int reference = luaState.Ref(LuaRegistry.Index); - if (reference == -1) - return null; - return new LuaFunction(reference, interpreter); - } - - /* - * Gets the CLR object in the index positon of the Lua stack. Returns - * delegates as Lua functions. - */ - internal object GetNetObject(LuaState luaState, int index) - { - int idx = luaState.ToNetObject(index, Tag); - return idx != -1 ? _objects[idx] : null; - } - - /* - * Gets the CLR object in the index position of the Lua stack. Returns - * delegates as is. - */ - internal object GetRawNetObject(LuaState luaState, int index) - { - int udata = luaState.RawNetObj(index); - return udata != -1 ? _objects[udata] : null; - } - - - /* - * Gets the values from the provided index to - * the top of the stack and returns them in an array. - */ - internal object[] PopValues(LuaState luaState, int oldTop) - { - int newTop = luaState.GetTop(); - - if (oldTop == newTop) - return null; - - var returnValues = new List(); - for (int i = oldTop + 1; i <= newTop; i++) - returnValues.Add(GetObject(luaState, i)); - - luaState.SetTop(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(LuaState luaState, int oldTop, Type[] popTypes) - { - int newTop = luaState.GetTop(); - - if (oldTop == newTop) - return null; - - int iTypes; - var returnValues = new List(); - - 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++; - } - - luaState.SetTop(oldTop); - return returnValues.ToArray(); - } - - // 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", true) != null; - } - return false; - } - - /* - * Pushes the object into the Lua stack according to its type. - */ - internal void Push(LuaState luaState, object o) - { - if (o == null) - luaState.PushNil(); - else if (o is sbyte sb) - luaState.PushInteger(sb); - else if(o is byte bt) - luaState.PushInteger(bt); - else if(o is short s) - luaState.PushInteger(s); - else if (o is ushort us) - luaState.PushInteger(us); - else if (o is int i) - luaState.PushInteger(i); - else if (o is uint ui) - luaState.PushInteger(ui); - else if (o is long l) - luaState.PushInteger(l); - else if (o is ulong ul) - luaState.PushInteger((long)ul); - else if (o is char ch) - luaState.PushInteger(ch); - else if (o is float fl) - luaState.PushNumber(fl); - else if(o is decimal dc) - luaState.PushNumber((double)dc); - else if(o is double db) - luaState.PushNumber(db); - else if (o is string str) - luaState.PushString(str); - else if (o is bool b) - luaState.PushBoolean(b); - else if (IsILua(o)) - ((ILuaGeneratedType)o).LuaInterfaceGetLuaTable().Push(luaState); - else if (o is LuaTable table) - table.Push(luaState); - else if (o is LuaNativeFunction nativeFunction) - PushFunction(luaState, nativeFunction); - else if (o is LuaFunction luaFunction) - luaFunction.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(LuaState luaState, MethodBase method, MethodCache methodCache, int skipParam) - { - return metaFunctions.MatchParameters(luaState, method, methodCache, skipParam); - } - - internal Array TableToArray(LuaState luaState, ExtractValue extractValue, Type paramArrayType, int startIndex, int count) - { - return metaFunctions.TableToArray(luaState, extractValue, paramArrayType, ref startIndex, count); - } - - private Type TypeOf(LuaState luaState, int idx) - { - int udata = luaState.CheckUObject(idx, "luaNet_class"); - if (udata == -1) - return null; - - var pt = (ProxyType)_objects[udata]; - return pt.UnderlyingSystemType; - } - - static int PushError(LuaState luaState, string msg) - { - luaState.PushNil(); - luaState.PushString(msg); - return 2; - } - -#if __IOS__ || __TVOS__ || __WATCHOS__ - [MonoPInvokeCallback(typeof(LuaNativeFunction))] -#endif - private static int CType(IntPtr luaState) - { - var state = LuaState.FromIntPtr(luaState); - var translator = ObjectTranslatorPool.Instance.Find(state); - return translator.CTypeInternal(state); - } - - int CTypeInternal(LuaState luaState) - { - Type t = TypeOf(luaState,1); - if (t == null) - return PushError(luaState, "Not a CLR Class"); - - PushObject(luaState, t, "luaNet_metatable"); - return 1; - } - -#if __IOS__ || __TVOS__ || __WATCHOS__ - [MonoPInvokeCallback(typeof(LuaNativeFunction))] -#endif - private static int EnumFromInt(IntPtr luaState) - { - var state = LuaState.FromIntPtr(luaState); - var translator = ObjectTranslatorPool.Instance.Find(state); - return translator.EnumFromIntInternal(state); - } - - int EnumFromIntInternal(LuaState luaState) - { - Type t = TypeOf(luaState, 1); - if (t == null || !t.IsEnum) - return PushError(luaState, "Not an Enum."); - - object res = null; - LuaType lt = luaState.Type(2); - if (lt == LuaType.Number) - { - int ival = (int)luaState.ToNumber(2); - res = Enum.ToObject(t, ival); - } - else if (lt == LuaType.String) - { - string sflags = luaState.ToString(2, false); - string err = null; - try - { - res = Enum.Parse(t, sflags, true); - } - catch (ArgumentException e) - { - err = e.Message; - } - if (err != null) - return PushError(luaState, err); - } - else - { - return PushError(luaState, "Second argument must be a integer or a string."); - } - PushObject(luaState, res, "luaNet_metatable"); - return 1; - } - - internal void AddFinalizedReference(int reference) - { - finalizedReferences.Enqueue(reference); - } - - void CleanFinalizedReferences(LuaState state) - { - if (finalizedReferences.Count == 0) - return; - - int reference; - - while (finalizedReferences.TryDequeue(out reference)) - state.Unref(LuaRegistry.Index, reference); - } - } -} diff --git a/src/LUA/ObjectTranslatorPool.cs b/src/LUA/ObjectTranslatorPool.cs deleted file mode 100644 index 7f1ac25..0000000 --- a/src/LUA/ObjectTranslatorPool.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Collections.Concurrent; - -using LuaState = KeraLua.Lua; - -namespace NLua -{ - internal class ObjectTranslatorPool - { - private static volatile ObjectTranslatorPool _instance = new ObjectTranslatorPool(); - - private ConcurrentDictionary translators = new ConcurrentDictionary(); - - public static ObjectTranslatorPool Instance => _instance; - - - public void Add(LuaState luaState, ObjectTranslator translator) - { - if(!translators.TryAdd(luaState, translator)) - throw new ArgumentException("An item with the same key has already been added. ", "luaState"); - } - - public ObjectTranslator Find(LuaState luaState) - { - ObjectTranslator translator; - - if(!translators.TryGetValue(luaState, out translator)) - { - LuaState main = luaState.MainThread; - - if (!translators.TryGetValue(main, out translator)) - return null; - } - return translator; - } - - public void Remove(LuaState luaState) - { - ObjectTranslator translator; - translators.TryRemove(luaState, out translator); - } - } -} - diff --git a/src/LUA/Properties/AssemblyInfo.cs b/src/LUA/Properties/AssemblyInfo.cs deleted file mode 100644 index befb0a5..0000000 --- a/src/LUA/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.Reflection; - -// Information about this assembly is defined by the following attributes. -// Change them to the values specific to your project. - -#if NETFRAMEWORK -[assembly: AssemblyTitle ("NLua (.NET Framework 4.5)")] -#elif WINDOWS_UWP -[assembly: AssemblyTitle ("NLua (Windows Universal)")] -#elif __ANDROID__ -[assembly: AssemblyTitle ("NLua (Xamarin.Android)")] -#elif NETCOREAPP -[assembly: AssemblyTitle ("NLua (.NET Core)")] -#elif NETSTANDARD -[assembly: AssemblyTitle ("NLua (.NET Standard)")] -#elif __TVOS__ -[assembly: AssemblyTitle ("NLua (Xamarin.tvOS)")] -#elif __WATCHOS__ -[assembly: AssemblyTitle ("NLua (Xamarin.watchOS)")] -#elif __IOS__ -[assembly: AssemblyTitle ("NLua (Xamarin.iOS)")] -#elif __MACOS__ -[assembly: AssemblyTitle ("NLua (Xamarin.Mac)")] -#else -[assembly: AssemblyTitle ("NLua (.NET Framework)")] -#endif - -[assembly: AssemblyDescription ("NLua library")] -[assembly: AssemblyCompany ("NLua.org")] -[assembly: AssemblyProduct ("NLua")] -[assembly: AssemblyCopyright ("Copyright © Vinicius Jarina 2020")] -[assembly: AssemblyCulture ("")] - - -[assembly: AssemblyVersion("1.4.1.0")] -[assembly: AssemblyInformationalVersion("1.0.7+Branch.master.Sha.80a328a64f12ed9032a0f14a75e6ecad967514d0")] -[assembly: AssemblyFileVersion("1.4.1.0")] - - diff --git a/src/LUA/ProxyType.cs b/src/LUA/ProxyType.cs deleted file mode 100644 index 92c0075..0000000 --- a/src/LUA/ProxyType.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Reflection; - -namespace NLua -{ - /// - /// Summary description for ProxyType. - /// - public class ProxyType - { - private readonly Type _proxy; - - public ProxyType(Type proxy) - { - _proxy = proxy; - } - - /// - /// Provide human readable short hand for this proxy object - /// - /// - public override string ToString() - { - return "ProxyType(" + UnderlyingSystemType + ")"; - } - - public Type UnderlyingSystemType => _proxy; - - public override bool Equals(object obj) - { - if (obj is Type) - return _proxy == (Type)obj; - if (obj is ProxyType) - return _proxy == ((ProxyType)obj).UnderlyingSystemType; - return _proxy.Equals(obj); - } - - public override int GetHashCode() - { - return _proxy.GetHashCode(); - } - - public MemberInfo[] GetMember(string name, BindingFlags bindingAttr) - { - return _proxy.GetMember(name, bindingAttr); - } - - public MethodInfo GetMethod(string name, BindingFlags bindingAttr, Type[] signature) - { - return _proxy.GetMethod(name, bindingAttr, null, signature, null); - } - } -} \ No newline at end of file diff --git a/src/LUAEngine.cs b/src/LUAEngine.cs index 91372d9..0184cd0 100644 --- a/src/LUAEngine.cs +++ b/src/LUAEngine.cs @@ -20,42 +20,66 @@ namespace OpenSim.Region.ScriptEngine.Lua [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LUAEngine")] class LUAEngine : INonSharedRegionModule, IScriptModule, IScriptEngine { + private IConfigSource m_config = null; + + private Scene m_scene = null; + + private bool m_enable = true; + private bool m_sandbox = true; + + public event ScriptRemoved OnScriptRemoved; + public event ObjectRemoved OnObjectRemoved; + #region INonSharedRegionModule - public string Name => throw new NotImplementedException(); - - public Type ReplaceableInterface => throw new NotImplementedException(); - - public void AddRegion(Scene scene) + public string Name { - throw new NotImplementedException(); + get { return "LUAEngine"; } } - public void Close() + public Type ReplaceableInterface { - throw new NotImplementedException(); + get { return null; } } public void Initialise(IConfigSource source) { - throw new NotImplementedException(); + if (source.Configs["LUA"] == null) + return; + + m_config = source; + + m_enable = source.Configs["LUA"].GetBoolean("Enable", m_enable); + m_sandbox = source.Configs["LUA"].GetBoolean("Sandbox", m_sandbox); } - public void RegionLoaded(Scene scene) + public void AddRegion(Scene scene) { - throw new NotImplementedException(); + if (m_scene == null) + m_scene = scene; } public void RemoveRegion(Scene scene) { - throw new NotImplementedException(); + m_scene = null; + } + + public void Close() + { + m_scene = null; + } + + public void RegionLoaded(Scene scene) + { + if (m_scene == null) + m_scene = scene; } #endregion #region IScriptModule - public string ScriptEngineName => throw new NotImplementedException(); - - public event ScriptRemoved OnScriptRemoved; - public event ObjectRemoved OnObjectRemoved; + public string ScriptEngineName + { + get { return "LUAEngine"; } + } public Dictionary GetObjectScriptsExecutionTimes() { @@ -125,15 +149,27 @@ namespace OpenSim.Region.ScriptEngine.Lua #endregion #region IScriptEngine - public Scene World => throw new NotImplementedException(); + public Scene World + { + get { return m_scene; } + } public IScriptModule ScriptModule => throw new NotImplementedException(); - public IConfig Config => throw new NotImplementedException(); + public IConfig Config + { + get { return m_config.Configs["LUA"]; } + } - public IConfigSource ConfigSource => throw new NotImplementedException(); + public IConfigSource ConfigSource + { + get { return m_config; } + } - public string ScriptEnginePath => throw new NotImplementedException(); + public string ScriptEnginePath + { + get { return "./LUAScriptEngine"; } + } public string ScriptClassName => throw new NotImplementedException(); diff --git a/src/RunningScript.cs b/src/RunningScript.cs new file mode 100644 index 0000000..d5f4964 --- /dev/null +++ b/src/RunningScript.cs @@ -0,0 +1,23 @@ +using OpenMetaverse; +using OpenSim.Region.Framework.Scenes; +using NLua; + +namespace OpenSim.Region.ScriptEngine.Lua +{ + class RunningScript + { + private SceneObjectPart m_host = null; + private InventoryItem m_item = null; + private Lua m_runtime = null; + + private RunningScript(InventoryItem item, SceneObjectPart host) + { + m_host = host; + m_item = item; + + m_runtime = new Lua(); + } + + + } +}