From f7924efc170fc43028534399821837d791c0381d Mon Sep 17 00:00:00 2001 From: Alex Fowler Date: Mon, 7 Sep 2020 09:58:43 +0300 Subject: [PATCH 1/6] + initial fork commit, + some better vm initialization, + better debug output, + update readme --- LICENSE.meta | 7 + LuaVM.cs | 419 +++++++++++++++++++++++-------------------------- README.md | 4 + README.md.meta | 7 + 4 files changed, 215 insertions(+), 222 deletions(-) create mode 100644 LICENSE.meta create mode 100644 README.md.meta diff --git a/LICENSE.meta b/LICENSE.meta new file mode 100644 index 0000000..eed889d --- /dev/null +++ b/LICENSE.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c269fcba2e4729541bc07d36eca7c5e3 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/LuaVM.cs b/LuaVM.cs index ebc38e3..8b6822e 100644 --- a/LuaVM.cs +++ b/LuaVM.cs @@ -5,83 +5,82 @@ using MoonSharp.Interpreter.Loaders; using System.Linq; using System.Reflection; +using System.Text; +using MoonSharp.Interpreter.Debugging; +using UnityEditor; +using UnityEngine; /// /// Wrapper around the Moonsharp API. /// Implements heavy error checking and logging for end users /// -public class LuaVM -{ +public class LuaVM { /// /// The Moonsharp script object /// - private readonly Script m_LuaScript = null; - private static Type[] m_APITypeList = null; - private LuaAPIBase[] m_APIList = null; - private static DynValue m_EnumTables = null; - + private readonly Script m_LuaScript = null; + + private static Type[] m_APITypeList = null; + private LuaAPIBase[] m_APIList = null; + private static DynValue m_EnumTables = null; + /// /// Settings to control the behaviour of the VM /// [Flags] - public enum VMSettings : uint - { + public enum VMSettings : uint { /// /// No custom code will be attached /// - None = 0, - + None = 0, + /// /// We'll attach anything deriving from LuaAPIBase /// - AttachAPIs = 1 << 0, - + AttachAPIs = 1 << 0, + /// /// We'll attach any enum with the LuaApiEnum attribute /// - AttachEnums = 1 << 1, - + AttachEnums = 1 << 1, + /// /// Attach everything we know about /// - AttachAll = ~0u, + AttachAll = ~0u, } /// /// The Moonsharp remote debugger service /// - private static MoonSharpVsCodeDebugServer s_RemoteDebugger = null; - + private static MoonSharpVsCodeDebugServer s_RemoteDebugger = null; + /// /// Default to attaching all apis and enums /// - public LuaVM() - : this(VMSettings.AttachAll) - { - } + public LuaVM(CoreModules initialModulesSetup) + : this(VMSettings.AttachAll, initialModulesSetup, new FileSystemScriptLoader()) { } + public LuaVM(CoreModules initialModulesSetup, IScriptLoader scriptLoader) + : this(VMSettings.AttachAll, initialModulesSetup, scriptLoader) { } + /// /// Default settings are a soft sandbox and setting up the file system script loader /// - public LuaVM(VMSettings vmSettings) - { + public LuaVM(VMSettings vmSettings, CoreModules initialModulesSetup, IScriptLoader scriptLoader) { m_LuaScript = - new Script(CoreModules.Preset_SoftSandbox) - { - Options = - { - ScriptLoader = new FileSystemScriptLoader(), - DebugPrint = log => Logger.Log (Channel.LuaNative, log), + new Script(initialModulesSetup) { + Options = { + ScriptLoader = scriptLoader,//new FileSystemScriptLoader(), + DebugPrint = log => Logger.Log(Channel.LuaNative, log), } }; - if ((vmSettings & VMSettings.AttachAPIs) == VMSettings.AttachAPIs) - { + if ((vmSettings & VMSettings.AttachAPIs) == VMSettings.AttachAPIs) { AttachAPIS(); } - - if ((vmSettings & VMSettings.AttachEnums) == VMSettings.AttachEnums) - { + + if ((vmSettings & VMSettings.AttachEnums) == VMSettings.AttachEnums) { AttachLuaEnums(); } } @@ -91,16 +90,13 @@ public LuaVM(VMSettings vmSettings) /// /// /// - public Table AddGlobalTable(string tableName) - { + public Table AddGlobalTable(string tableName) { Table table = null; - if(SetGlobal(tableName, DynValue.NewTable(m_LuaScript))) - { + if (SetGlobal(tableName, DynValue.NewTable(m_LuaScript))) { table = GetGlobal(tableName).Table; } - else - { + else { Logger.Log(Channel.Lua, Priority.FatalError, "Failed to add global Lua table {0}", tableName); } @@ -113,18 +109,16 @@ public Table AddGlobalTable(string tableName) /// /// /// true if value was set successfully - public bool SetGlobal(string key, object value) - { + public bool SetGlobal(string key, object value) { bool didSet = false; - try - { + try { m_LuaScript.Globals[key] = value; didSet = true; } - catch (InterpreterException ex) - { + catch (InterpreterException ex) { Logger.Log(Channel.Lua, Priority.FatalError, "Lua SetGlobal error: {0}", ex.DecoratedMessage); } + return didSet; } @@ -133,94 +127,81 @@ public bool SetGlobal(string key, object value) /// /// /// null if failure occurs, else the requested value as a DynValue - public DynValue GetGlobal(string key) - { + public DynValue GetGlobal(string key) { DynValue result = DynValue.Nil; - try - { + try { result = m_LuaScript.Globals.Get(key); } - catch - { + catch { Logger.Log(Channel.Lua, Priority.FatalError, "Failed to get Lua global {0}", key); } return result; } - /// - /// Attempts to retrive a value from the Lua globals, allowing the user to pass parent and children names in - /// - /// The global. - /// Keys. - public DynValue GetGlobal(params object[] keys) - { + /// + /// Attempts to retrive a value from the Lua globals, allowing the user to pass parent and children names in + /// + /// The global. + /// Keys. + public DynValue GetGlobal(params object[] keys) { DynValue result = DynValue.Nil; - try - { - result = m_LuaScript.Globals.Get(keys); - } - catch - { - Logger.Log(Channel.Lua, Priority.FatalError, "Failed to get Lua global at '{0}'", - string.Join(", ", Array.ConvertAll(keys, input => input.ToString()))); - } - - return result; - } - - /// - /// Attempts to retrive a table from the Lua globals - /// - /// The global table. - /// Key. - public Table GetGlobalTable(string key) - { - Table result = null; - DynValue tableDyn = GetGlobal (key); - if (tableDyn != null) - { - if(tableDyn.Type == DataType.Table) - { - result = tableDyn.Table; - } - else - { - Logger.Log(Channel.Lua, Priority.FatalError, "Lua global {0} is not type table, has type {1}", key, tableDyn.Type.ToString()); - } - } - return result; - } - - /// - /// Attempts to retrive a table from the Lua globals, allowing the user to pass parent and children names in - /// - /// The global table. - /// Key. - public Table GetGlobalTable(params object[] keys) - { - Table result = null; - DynValue tableDyn = GetGlobal (keys); - if (tableDyn != null) - { - if(tableDyn.Type == DataType.Table) - { - result = tableDyn.Table; - } - else - { - Logger.Log(Channel.Lua, Priority.FatalError, "Lua global {0} is not type table, has type {1}", keys, tableDyn.Type.ToString()); - } - } - return result; - } + try { + result = m_LuaScript.Globals.Get(keys); + } + catch { + Logger.Log(Channel.Lua, Priority.FatalError, "Failed to get Lua global at '{0}'", + string.Join(", ", Array.ConvertAll(keys, input => input.ToString()))); + } + + return result; + } + + /// + /// Attempts to retrive a table from the Lua globals + /// + /// The global table. + /// Key. + public Table GetGlobalTable(string key) { + Table result = null; + DynValue tableDyn = GetGlobal(key); + if (tableDyn != null) { + if (tableDyn.Type == DataType.Table) { + result = tableDyn.Table; + } + else { + Logger.Log(Channel.Lua, Priority.FatalError, "Lua global {0} is not type table, has type {1}", key, tableDyn.Type.ToString()); + } + } + + return result; + } + + /// + /// Attempts to retrive a table from the Lua globals, allowing the user to pass parent and children names in + /// + /// The global table. + /// Key. + public Table GetGlobalTable(params object[] keys) { + Table result = null; + DynValue tableDyn = GetGlobal(keys); + if (tableDyn != null) { + if (tableDyn.Type == DataType.Table) { + result = tableDyn.Table; + } + else { + Logger.Log(Channel.Lua, Priority.FatalError, "Lua global {0} is not type table, has type {1}", keys, tableDyn.Type.ToString()); + } + } + + return result; + } /// /// Return the global table for this vm /// /// - public Table GetGlobalsTable() - { + public Table GetGlobalsTable() { return m_LuaScript.Globals; } @@ -229,16 +210,13 @@ public Table GetGlobalsTable() /// /// /// Null if an error occured otherwise will return the result of the executed lua code - public DynValue ExecuteString(string command) - { + public DynValue ExecuteString(string command) { DynValue result = DynValue.Nil; - try - { + try { result = m_LuaScript.DoString(command); } - catch (InterpreterException ex) - { + catch (InterpreterException ex) { Logger.Log(Channel.Lua, Priority.FatalError, "Lua ExecuteString error: {0}", ex.DecoratedMessage); } @@ -250,21 +228,18 @@ public DynValue ExecuteString(string command) /// /// /// Null if an error occured otherwise will return the result of the executed lua code - public DynValue ExecuteScript(string filePath) - { + public DynValue ExecuteScript(string filePath) { DynValue result = DynValue.Nil; - try - { + try { result = m_LuaScript.DoFile(filePath); } - catch (InterpreterException ex) - { + catch (InterpreterException ex) { Logger.Log(Channel.Lua, Priority.FatalError, "Lua ExecuteScript error: {0}", ex.DecoratedMessage); } - catch (Exception ex) - { + catch (Exception ex) { Logger.Log(Channel.Lua, Priority.FatalError, "System ExecuteScript error: {0}", ex.Message); + Debug.LogException(ex); } return result; @@ -275,50 +250,51 @@ public DynValue ExecuteScript(string filePath) /// /// /// Null if an error occured otherwise will return the DynValue of the script. This can be passed to Call() - public DynValue LoadScript(string filePath) - { + public DynValue LoadScript(string filePath) { DynValue result = DynValue.Nil; - try - { + try { result = m_LuaScript.LoadFile(filePath); } - catch (InterpreterException ex) - { + catch (InterpreterException ex) { Logger.Log(Channel.Lua, Priority.FatalError, "Lua ExecuteString error: {0}", ex.DecoratedMessage); } - catch (Exception ex) - { + catch (Exception ex) { Logger.Log(Channel.Lua, Priority.FatalError, "System ExecuteString error: {0}", ex.Message); } return result; } - + /// /// Attemps to load a string containing lua code /// /// /// Null if an error occured otherwise will return the DynValue of the script. This can be passed to Call() - public DynValue LoadString(string luaString) - { + public DynValue LoadString(string luaString, Table globalTable = null, string codeFriendlyName = null) { DynValue result = DynValue.Nil; - try - { - result = m_LuaScript.LoadString(luaString); + try { + result = m_LuaScript.LoadString(luaString, globalTable, codeFriendlyName); } - catch (InterpreterException ex) - { + catch (InterpreterException ex) { Logger.Log(Channel.Lua, Priority.FatalError, "Lua ExecuteString error: {0}", ex.DecoratedMessage); } - catch (Exception ex) - { + catch (Exception ex) { Logger.Log(Channel.Lua, Priority.FatalError, "System ExecuteString error: {0}", ex.Message); } return result; } + + /// + /// Attemps to load a string containing lua code + /// + /// + /// Null if an error occured otherwise will return the DynValue of the script. This can be passed to Call() + public DynValue LoadString(string luaString, string codeFriendlyName) { + return LoadString(luaString, m_LuaScript.Globals, codeFriendlyName); + } /// /// Call a lua function via DynValue @@ -326,105 +302,113 @@ public DynValue LoadString(string luaString) /// /// /// Null if call fails of function is invalid, else the result of the function - public DynValue Call(DynValue luaFunc, params object[] args) - { + public DynValue Call(DynValue luaFunc, params object[] args) { DynValue result = DynValue.Nil; - if (luaFunc.IsNotNil() && luaFunc.Type == DataType.Function) - { - try - { + if (luaFunc.IsNotNil() && luaFunc.Type == DataType.Function) { + try { result = m_LuaScript.Call(luaFunc, args); } - catch (ScriptRuntimeException ex) - { + catch (ScriptRuntimeException ex) { Logger.Log(Channel.Lua, Priority.FatalError, "Lua Call error: {0}", ex.DecoratedMessage); } } - else - { + else { Logger.Log(Channel.Lua, Priority.FatalError, "Invalid lua function passed to LuaVM::Call"); } return result; } + string StringifyStacktrace(IList callstack) { + StringBuilder sb = new StringBuilder(); + + foreach (WatchItem wi in callstack) + { + string name; + + if (wi.Name == null) + if (wi.RetAddress < 0) + name = "main chunk"; + else + name = "?"; + else + name = "function '" + wi.Name + "'"; + + string loc = wi.Location != null ? wi.Location.FormatLocation(m_LuaScript) : "[clr]"; + sb.AppendFormat("\t{0}: in {1}\n", loc, name); + } + + return sb.ToString(); + } + /// /// Call a lua function via name /// /// Function name. /// Arguments. - public DynValue Call(string functionName, params object[] args) - { + public DynValue Call(string functionName, params object[] args) { DynValue result = DynValue.Nil; - if (!string.IsNullOrEmpty(functionName)) - { + if (!string.IsNullOrEmpty(functionName)) { DynValue func = GetGlobal(functionName); - if (func.Type == DataType.Function) - { - try - { + if (func.Type == DataType.Function) { + try { + //Debug.Log($"<><><><><> ECS = {m_LuaScript.Globals["ecs"]}"); result = m_LuaScript.Call(func, args); } - catch (InterpreterException ex) - { - Logger.Log(Channel.Lua, Priority.FatalError, "Lua error calling function {0}: {1}", functionName, ex.DecoratedMessage); + catch (InterpreterException ex) { + Logger.Log(Channel.Lua, Priority.FatalError, "Lua error calling function '{0}': {1}:\n--------- CLR ---------\n{2}\n --------- LUA ---------\n{3}", functionName, ex.DecoratedMessage, ex.InnerException?.StackTrace, StringifyStacktrace(ex.CallStack)); + throw; } + //catch (Exception ex) { + //Logger.Log(Channel.Lua, Priority.FatalError, "Exception calling function '{0}': {1}", functionName, ex.); + //} } - else - { + else { Logger.Log(Channel.Lua, Priority.FatalError, "Failed to find lua function '{0}'", functionName); } } + return result; } /// /// Starts the remote debugger and opens the interface in the users browser /// - public static void StartRemoteDebugger() - { - if (s_RemoteDebugger == null) - { - s_RemoteDebugger = new MoonSharpVsCodeDebugServer(); - s_RemoteDebugger.Start (); + public static void StartRemoteDebugger() { + if (s_RemoteDebugger == null) { + s_RemoteDebugger = new MoonSharpVsCodeDebugServer(); + s_RemoteDebugger.Start(); } } /// /// Attaches to the remove debugger service /// - public void AttachDebugger() - { - if(s_RemoteDebugger != null) - { - s_RemoteDebugger.AttachToScript (m_LuaScript, "Lua script"); + public void AttachDebugger() { + if (s_RemoteDebugger != null) { + s_RemoteDebugger.AttachToScript(m_LuaScript, "Lua script"); } - else - { + else { Logger.Log(Channel.Lua, Priority.Error, "Tried to attach script to debugger before debugger was started"); } } - + /// /// Return the current script object /// - public Script GetScriptObject() - { + public Script GetScriptObject() { return m_LuaScript; } /// /// Create static api list and attach to this VM /// - private void AttachAPIS() - { - if (m_APITypeList == null) - { + private void AttachAPIS() { + if (m_APITypeList == null) { List apiTypeList = new List(); - foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) - { + foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) { apiTypeList.AddRange(assembly.GetTypes() .Where(type => type.IsSubclassOf(typeof(LuaAPIBase)))); } @@ -434,14 +418,12 @@ private void AttachAPIS() m_APIList = new LuaAPIBase[m_APITypeList.Length]; - for (int i = 0; i < m_APITypeList.Length; ++i) - { + for (int i = 0; i < m_APITypeList.Length; ++i) { m_APIList[i] = Activator.CreateInstance(m_APITypeList[i]) as LuaAPIBase; } - + // Iterate apis and tell them to update this lua vm - foreach (LuaAPIBase api in m_APIList) - { + foreach (LuaAPIBase api in m_APIList) { api.AddAPIToLuaInstance(this); } } @@ -449,52 +431,45 @@ private void AttachAPIS() /// /// Create the reusable enum prime table and attach to this VM /// - private void AttachLuaEnums() - { - if (m_EnumTables == null) - { + private void AttachLuaEnums() { + if (m_EnumTables == null) { // Create a new prime table // Prime tables can be shared between scripts m_EnumTables = DynValue.NewPrimeTable(); - + // Get all enums with the lua attribute List luaEnumList = new List(); - foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) - { + foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) { luaEnumList.AddRange((assembly.GetTypes() .Where(luaEnumType => Attribute.IsDefined(luaEnumType, typeof(LuaApiEnum))))); } - - foreach (Type enumType in luaEnumList) - { + + foreach (Type enumType in luaEnumList) { // Get the attribute LuaApiEnum apiEnumAttrib = (LuaApiEnum) enumType.GetCustomAttributes(typeof(LuaApiEnum), false)[0]; // Create the table for this enum and get a reference to it m_EnumTables.Table.Set(apiEnumAttrib.name, DynValue.NewPrimeTable()); Table enumTable = m_EnumTables.Table.Get(apiEnumAttrib.name).Table; - + // Foreach value in the enum list - foreach (var enumValue in Enum.GetValues(enumType)) - { + foreach (var enumValue in Enum.GetValues(enumType)) { var memberInfo = enumType.GetMember(enumValue.ToString()); var attribute = memberInfo[0].GetCustomAttributes(typeof(LuaApiEnumValue), false); // Double check they've not been flagged as hidden - if (attribute.Length > 0 && ((LuaApiEnumValue) attribute[0]).hidden) - { + if (attribute.Length > 0 && ((LuaApiEnumValue) attribute[0]).hidden) { continue; } - + enumTable.Set(enumValue.ToString(), DynValue.NewNumber((int) enumValue)); } } } - + // Iterate through the enum cache and copy the values into our globals - foreach (var enumPair in m_EnumTables.Table.Pairs) - { + foreach (var enumPair in m_EnumTables.Table.Pairs) { m_LuaScript.Globals.Set(enumPair.Key, enumPair.Value); } } -} +} \ No newline at end of file diff --git a/README.md b/README.md index e76cc29..813fcfa 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ +# What's different in this fork + +Added custom code for better VM initialization, debug output and maybe some other stuff. + # Unity-Lua A wrapper around MoonSharp that allows easy development of moddable Unity games diff --git a/README.md.meta b/README.md.meta new file mode 100644 index 0000000..d0ebb91 --- /dev/null +++ b/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 84e0ce185044f6e4ba1ccb9d511276fa +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From ce26ef780414d2a8774001777516f980f9882224 Mon Sep 17 00:00:00 2001 From: Alex Fowler Date: Mon, 15 Feb 2021 17:54:32 +0300 Subject: [PATCH 2/6] + better error message --- LuaVM.cs | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/LuaVM.cs b/LuaVM.cs index 8b6822e..6db6295 100644 --- a/LuaVM.cs +++ b/LuaVM.cs @@ -358,7 +358,7 @@ public DynValue Call(string functionName, params object[] args) { result = m_LuaScript.Call(func, args); } catch (InterpreterException ex) { - Logger.Log(Channel.Lua, Priority.FatalError, "Lua error calling function '{0}': {1}:\n--------- CLR ---------\n{2}\n --------- LUA ---------\n{3}", functionName, ex.DecoratedMessage, ex.InnerException?.StackTrace, StringifyStacktrace(ex.CallStack)); + LogException(functionName, ex); throw; } //catch (Exception ex) { @@ -373,6 +373,71 @@ public DynValue Call(string functionName, params object[] args) { return result; } + public void LogException(string functionName, InterpreterException ex) { + if (ex.InnerException != null) { + var inner = ex.InnerException; + if (inner.InnerException != null) { + Logger.Log(Channel.Lua, Priority.FatalError, + "Lua error A calling function '{0}':\n\n" + + "message = {1}\n" + + "decorated = {2}\n\n" + + "--------- CLR 1 ---------\n\n" + + "inner message = {3}\n\n" + + "inner stack trace:\n{4}\n\n" + + "--------- CLR 2 ---------\n\n" + + "inner message 2x = {5}\n\n" + + "inner stack trace 2x:\n{6}\n\n" + + " --------- LUA ---------\n" + + "{7}", + functionName, + ex.Message, + ex.DecoratedMessage, + /* -- clr 1 -- */ + ex.InnerException?.Message, + ex.InnerException?.StackTrace, + /* -- clr 2 -- */ + ex.InnerException?.InnerException?.Message, + ex.InnerException?.InnerException?.StackTrace, + + StringifyStacktrace(ex.CallStack)); + } + else { + Logger.Log(Channel.Lua, Priority.FatalError, + "Lua error B calling function '{0}':\n\n" + + "message = {1}\n" + + "decorated = {2}\n\n" + + "--------- CLR ---------\n\n" + + "inner message = {3}\n\n" + + "inner stack trace:\n{4}\n\n" + + " --------- LUA ---------\n" + + "{5}", + functionName, + ex.Message, + ex.DecoratedMessage, + ex.InnerException?.Message, + ex.InnerException?.StackTrace, + StringifyStacktrace(ex.CallStack)); + } + } + else { + Logger.Log(Channel.Lua, Priority.FatalError, + "Lua error C calling function '{0}':\n\n" + + "message = {1}\n" + + "decorated = {2}\n\n" + + "--------- CLR ---------\n\n" + + "message = {3}\n\n" + + "stack trace:\n{4}\n\n" + + " --------- LUA ---------\n" + + "{5}", + functionName, + ex.Message, + ex.DecoratedMessage, + ex.Message, + ex.StackTrace, + StringifyStacktrace(ex.CallStack)); + } + } + /// /// Starts the remote debugger and opens the interface in the users browser /// From a8b5dd1557a5e4b27eb1a59df9ab47d83a34ce1d Mon Sep 17 00:00:00 2001 From: Alex Fowler Date: Wed, 10 Mar 2021 00:16:31 +0300 Subject: [PATCH 3/6] + small improvement to debug output --- LuaVM.cs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/LuaVM.cs b/LuaVM.cs index 6db6295..996d5bc 100644 --- a/LuaVM.cs +++ b/LuaVM.cs @@ -314,12 +314,29 @@ public DynValue Call(DynValue luaFunc, params object[] args) { } } else { - Logger.Log(Channel.Lua, Priority.FatalError, "Invalid lua function passed to LuaVM::Call"); + string description; + if (luaFunc.Type == DataType.Table) { + description = $"{luaFunc.Type} / {luaFunc.ToDebugPrintString()} / {PrintDebug(luaFunc.Table)}"; + } + else { + description = $"{luaFunc.Type} / {luaFunc.ToDebugPrintString()}"; + } + Logger.Log(Channel.Lua, Priority.FatalError, $"Invalid lua function passed to LuaVM::Call: [{description}]"); } return result; } + public static string PrintDebug(Table table) { + var maybePr = table.OwnerScript.Globals.Get("pr"); + if (maybePr.Type == DataType.Table) { + return maybePr.Table.Get("table").Function.Call(table).String; + } + else { + return "[..pr.table() is not available..]"; + } + } + string StringifyStacktrace(IList callstack) { StringBuilder sb = new StringBuilder(); From 2b4f491dcce671fa71c8f61abb1cc28ab2b45990 Mon Sep 17 00:00:00 2001 From: Alex Fowler Date: Tue, 29 Jun 2021 23:28:55 +0300 Subject: [PATCH 4/6] much better error logging for some cases when a lua function is called from csharp --- LuaVM.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/LuaVM.cs b/LuaVM.cs index 996d5bc..d026449 100644 --- a/LuaVM.cs +++ b/LuaVM.cs @@ -310,7 +310,13 @@ public DynValue Call(DynValue luaFunc, params object[] args) { result = m_LuaScript.Call(luaFunc, args); } catch (ScriptRuntimeException ex) { - Logger.Log(Channel.Lua, Priority.FatalError, "Lua Call error: {0}", ex.DecoratedMessage); + Logger.Log(Channel.Lua, Priority.FatalError, "[ScriptRuntimeException] Lua Call error: [EXCEPTION] Message: {0}\n CallStack:{1}\n\n Stack trace:\n{2}\n\n [SOURCE] Message: {3}\n Stack trace:\n{4}", ex.DecoratedMessage, StringifyStacktrace(ex.CallStack), ex.StackTrace, ex.InnerException?.Message, ex.InnerException?.StackTrace); + } + catch (CSharpException ex) { + Logger.Log(Channel.Lua, Priority.FatalError, "[CSharpException] Lua Call error: [EXCEPTION] Message: {0}\n CallStack:{1}\n\n Stack trace:\n{2}\n\n [SOURCE] Message: {3}\n Stack trace:\n{4}", ex.DecoratedMessage, StringifyStacktrace(ex.CallStack), ex.StackTrace, ex.InnerException?.Message, ex.InnerException?.StackTrace); + } + catch (Exception ex) { + Logger.Log(Channel.Lua, Priority.FatalError, $"[{ex.GetType()}] Lua Call error: [EXCEPTION] Message: {0}\n Stack trace:\n{1}\n\n [SOURCE] Message: {2}\n Stack trace:\n{3}", ex.Message, ex.StackTrace, ex.InnerException?.Message, ex.InnerException?.StackTrace); } } else { From 6cf0a27e752fb85cdcf75cae7d807b91f95a4764 Mon Sep 17 00:00:00 2001 From: Alex Fowler Date: Mon, 6 Sep 2021 12:22:01 +0300 Subject: [PATCH 5/6] + added methods GetGlobalTableOrNull() and GetOrAddGlobalTable() for convenience and flexibility, + now also re-throwing exceptions from scripts (why was it not there before??? :thinking:) --- LuaVM.cs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/LuaVM.cs b/LuaVM.cs index d026449..679ceac 100644 --- a/LuaVM.cs +++ b/LuaVM.cs @@ -176,6 +176,29 @@ public Table GetGlobalTable(string key) { return result; } + + public Table GetGlobalTableOrNull(string key) { + Table result = null; + DynValue tableDyn = GetGlobal(key); + if (tableDyn != null) { + if (tableDyn.Type == DataType.Table) { + result = tableDyn.Table; + } + else if (tableDyn == DynValue.Nil) { + return null; + } + else { + Logger.Log(Channel.Lua, Priority.FatalError, "Lua global {0} is not type table, has type {1}", key, tableDyn.Type.ToString()); + } + } + + return result; + } + + public Table GetOrAddGlobalTable(string key) { + Table table = GetGlobalTableOrNull(key); + return table ?? AddGlobalTable(key); + } /// /// Attempts to retrive a table from the Lua globals, allowing the user to pass parent and children names in @@ -311,12 +334,15 @@ public DynValue Call(DynValue luaFunc, params object[] args) { } catch (ScriptRuntimeException ex) { Logger.Log(Channel.Lua, Priority.FatalError, "[ScriptRuntimeException] Lua Call error: [EXCEPTION] Message: {0}\n CallStack:{1}\n\n Stack trace:\n{2}\n\n [SOURCE] Message: {3}\n Stack trace:\n{4}", ex.DecoratedMessage, StringifyStacktrace(ex.CallStack), ex.StackTrace, ex.InnerException?.Message, ex.InnerException?.StackTrace); + throw; } catch (CSharpException ex) { Logger.Log(Channel.Lua, Priority.FatalError, "[CSharpException] Lua Call error: [EXCEPTION] Message: {0}\n CallStack:{1}\n\n Stack trace:\n{2}\n\n [SOURCE] Message: {3}\n Stack trace:\n{4}", ex.DecoratedMessage, StringifyStacktrace(ex.CallStack), ex.StackTrace, ex.InnerException?.Message, ex.InnerException?.StackTrace); + throw; } catch (Exception ex) { Logger.Log(Channel.Lua, Priority.FatalError, $"[{ex.GetType()}] Lua Call error: [EXCEPTION] Message: {0}\n Stack trace:\n{1}\n\n [SOURCE] Message: {2}\n Stack trace:\n{3}", ex.Message, ex.StackTrace, ex.InnerException?.Message, ex.InnerException?.StackTrace); + throw; } } else { From 9e122bc0150f816be7324db5f8231533b003435d Mon Sep 17 00:00:00 2001 From: noncom Date: Tue, 22 Nov 2022 20:46:27 +0100 Subject: [PATCH 6/6] + fix NRE in exception handling for when there's no callstack (can happen when calling a Lua function DynValue from CSharp and it fails with argument coercion, for example) --- Documentation/LuaDocGenerator.cs | 10 +++--- LuaAPIBase.cs | 2 +- LuaVM.cs | 56 +++++++++++++++++--------------- 3 files changed, 36 insertions(+), 32 deletions(-) diff --git a/Documentation/LuaDocGenerator.cs b/Documentation/LuaDocGenerator.cs index d0c5927..5798c41 100644 --- a/Documentation/LuaDocGenerator.cs +++ b/Documentation/LuaDocGenerator.cs @@ -174,7 +174,7 @@ private static List GetAllEnums() [MenuItem("Lua/Docs/Generate MediaWiki Docs")] private static void GenerateMediaWikiDocs() { - Logger.Log (Channel.Lua, "Beginning Lua doc generation for MediaWiki"); + LuaLogger.Log (Channel.Lua, "Beginning Lua doc generation for MediaWiki"); string documentationPath = EditorUtility.OpenFolderPanel("Choose a location to place wiki files", string.Empty, string.Empty); @@ -191,7 +191,7 @@ private static void GenerateMediaWikiDocs() StreamWriter documentation = File.CreateText(apiDocPath); - Logger.Log(Channel.Lua, "Generating documentation for api: {0}", luaApiDetails.luaName); + LuaLogger.Log(Channel.Lua, "Generating documentation for api: {0}", luaApiDetails.luaName); documentation.WriteLine("= {0} =", luaApiDetails.luaName); @@ -215,7 +215,7 @@ private static void GenerateMediaWikiDocs() // Grab the LuaApiFunction if it exists LuaApiFunction luaMethodDetails = method.Attribute; - Logger.Log(Channel.Lua, "\t {0}", luaMethodDetails.name); + LuaLogger.Log(Channel.Lua, "\t {0}", luaMethodDetails.name); documentation.WriteLine("=== {0} ===", luaMethodDetails.name); @@ -335,7 +335,7 @@ private static void GenerateMediaWikiDocs() enumDocumentation.Close(); } - Logger.Log (Channel.Lua, "Completed Lua doc generation"); + LuaLogger.Log (Channel.Lua, "Completed Lua doc generation"); } private class VSCodeSnippet @@ -591,7 +591,7 @@ private static string GetCleanTypeName(Type type) } else { - Logger.Log (Channel.Lua, Priority.Error, "Failed to convert type {0} to cleaner name", type.ToString ()); + LuaLogger.Log (Channel.Lua, Priority.Error, "Failed to convert type {0} to cleaner name", type.ToString ()); result = type.ToString (); } diff --git a/LuaAPIBase.cs b/LuaAPIBase.cs index 74ca436..e7d45b8 100644 --- a/LuaAPIBase.cs +++ b/LuaAPIBase.cs @@ -62,7 +62,7 @@ public void AddAPIToLuaInstance(LuaVM luaInstance) } else { - Logger.Log (Channel.Lua, "Failed to Initilise API {0}", m_APIName); + LuaLogger.Log (Channel.Lua, "Failed to Initilise API {0}", m_APIName); } } } diff --git a/LuaVM.cs b/LuaVM.cs index 679ceac..6cba4d9 100644 --- a/LuaVM.cs +++ b/LuaVM.cs @@ -72,7 +72,7 @@ public LuaVM(VMSettings vmSettings, CoreModules initialModulesSetup, IScriptLoad new Script(initialModulesSetup) { Options = { ScriptLoader = scriptLoader,//new FileSystemScriptLoader(), - DebugPrint = log => Logger.Log(Channel.LuaNative, log), + DebugPrint = log => LuaLogger.Log(Channel.LuaNative, log), } }; @@ -97,7 +97,7 @@ public Table AddGlobalTable(string tableName) { table = GetGlobal(tableName).Table; } else { - Logger.Log(Channel.Lua, Priority.FatalError, "Failed to add global Lua table {0}", tableName); + LuaLogger.Log(Channel.Lua, Priority.FatalError, "Failed to add global Lua table {0}", tableName); } return table; @@ -116,7 +116,7 @@ public bool SetGlobal(string key, object value) { didSet = true; } catch (InterpreterException ex) { - Logger.Log(Channel.Lua, Priority.FatalError, "Lua SetGlobal error: {0}", ex.DecoratedMessage); + LuaLogger.Log(Channel.Lua, Priority.FatalError, "Lua SetGlobal error: {0}", ex.DecoratedMessage); } return didSet; @@ -133,7 +133,7 @@ public DynValue GetGlobal(string key) { result = m_LuaScript.Globals.Get(key); } catch { - Logger.Log(Channel.Lua, Priority.FatalError, "Failed to get Lua global {0}", key); + LuaLogger.Log(Channel.Lua, Priority.FatalError, "Failed to get Lua global {0}", key); } return result; @@ -150,7 +150,7 @@ public DynValue GetGlobal(params object[] keys) { result = m_LuaScript.Globals.Get(keys); } catch { - Logger.Log(Channel.Lua, Priority.FatalError, "Failed to get Lua global at '{0}'", + LuaLogger.Log(Channel.Lua, Priority.FatalError, "Failed to get Lua global at '{0}'", string.Join(", ", Array.ConvertAll(keys, input => input.ToString()))); } @@ -170,7 +170,7 @@ public Table GetGlobalTable(string key) { result = tableDyn.Table; } else { - Logger.Log(Channel.Lua, Priority.FatalError, "Lua global {0} is not type table, has type {1}", key, tableDyn.Type.ToString()); + LuaLogger.Log(Channel.Lua, Priority.FatalError, "Lua global {0} is not type table, has type {1}", key, tableDyn.Type.ToString()); } } @@ -188,7 +188,7 @@ public Table GetGlobalTableOrNull(string key) { return null; } else { - Logger.Log(Channel.Lua, Priority.FatalError, "Lua global {0} is not type table, has type {1}", key, tableDyn.Type.ToString()); + LuaLogger.Log(Channel.Lua, Priority.FatalError, "Lua global {0} is not type table, has type {1}", key, tableDyn.Type.ToString()); } } @@ -213,7 +213,7 @@ public Table GetGlobalTable(params object[] keys) { result = tableDyn.Table; } else { - Logger.Log(Channel.Lua, Priority.FatalError, "Lua global {0} is not type table, has type {1}", keys, tableDyn.Type.ToString()); + LuaLogger.Log(Channel.Lua, Priority.FatalError, "Lua global {0} is not type table, has type {1}", keys, tableDyn.Type.ToString()); } } @@ -240,7 +240,7 @@ public DynValue ExecuteString(string command) { result = m_LuaScript.DoString(command); } catch (InterpreterException ex) { - Logger.Log(Channel.Lua, Priority.FatalError, "Lua ExecuteString error: {0}", ex.DecoratedMessage); + LuaLogger.Log(Channel.Lua, Priority.FatalError, "Lua ExecuteString error: {0}", ex.DecoratedMessage); } return result; @@ -258,10 +258,10 @@ public DynValue ExecuteScript(string filePath) { result = m_LuaScript.DoFile(filePath); } catch (InterpreterException ex) { - Logger.Log(Channel.Lua, Priority.FatalError, "Lua ExecuteScript error: {0}", ex.DecoratedMessage); + LuaLogger.Log(Channel.Lua, Priority.FatalError, "Lua ExecuteScript error: {0}", ex.DecoratedMessage); } catch (Exception ex) { - Logger.Log(Channel.Lua, Priority.FatalError, "System ExecuteScript error: {0}", ex.Message); + LuaLogger.Log(Channel.Lua, Priority.FatalError, "System ExecuteScript error: {0}", ex.Message); Debug.LogException(ex); } @@ -280,10 +280,10 @@ public DynValue LoadScript(string filePath) { result = m_LuaScript.LoadFile(filePath); } catch (InterpreterException ex) { - Logger.Log(Channel.Lua, Priority.FatalError, "Lua ExecuteString error: {0}", ex.DecoratedMessage); + LuaLogger.Log(Channel.Lua, Priority.FatalError, "Lua ExecuteString error: {0}", ex.DecoratedMessage); } catch (Exception ex) { - Logger.Log(Channel.Lua, Priority.FatalError, "System ExecuteString error: {0}", ex.Message); + LuaLogger.Log(Channel.Lua, Priority.FatalError, "System ExecuteString error: {0}", ex.Message); } return result; @@ -301,10 +301,10 @@ public DynValue LoadString(string luaString, Table globalTable = null, string co result = m_LuaScript.LoadString(luaString, globalTable, codeFriendlyName); } catch (InterpreterException ex) { - Logger.Log(Channel.Lua, Priority.FatalError, "Lua ExecuteString error: {0}", ex.DecoratedMessage); + LuaLogger.Log(Channel.Lua, Priority.FatalError, "Lua ExecuteString error: {0}", ex.DecoratedMessage); } catch (Exception ex) { - Logger.Log(Channel.Lua, Priority.FatalError, "System ExecuteString error: {0}", ex.Message); + LuaLogger.Log(Channel.Lua, Priority.FatalError, "System ExecuteString error: {0}", ex.Message); } return result; @@ -328,20 +328,20 @@ public DynValue LoadString(string luaString, string codeFriendlyName) { public DynValue Call(DynValue luaFunc, params object[] args) { DynValue result = DynValue.Nil; - if (luaFunc.IsNotNil() && luaFunc.Type == DataType.Function) { + if (luaFunc.IsNotNil() && (luaFunc.Type == DataType.Function || luaFunc.Type == DataType.ClrFunction)) { try { result = m_LuaScript.Call(luaFunc, args); } catch (ScriptRuntimeException ex) { - Logger.Log(Channel.Lua, Priority.FatalError, "[ScriptRuntimeException] Lua Call error: [EXCEPTION] Message: {0}\n CallStack:{1}\n\n Stack trace:\n{2}\n\n [SOURCE] Message: {3}\n Stack trace:\n{4}", ex.DecoratedMessage, StringifyStacktrace(ex.CallStack), ex.StackTrace, ex.InnerException?.Message, ex.InnerException?.StackTrace); + LuaLogger.Log(Channel.Lua, Priority.FatalError, "[ScriptRuntimeException] Lua Call error: [EXCEPTION] Message: {0}\n CallStack:{1}\n\n Stack trace:\n{2}\n\n [SOURCE] Message: {3}\n Stack trace:\n{4}", ex.DecoratedMessage, StringifyStacktrace(ex.CallStack), ex.StackTrace, ex.InnerException?.Message, ex.InnerException?.StackTrace); throw; } catch (CSharpException ex) { - Logger.Log(Channel.Lua, Priority.FatalError, "[CSharpException] Lua Call error: [EXCEPTION] Message: {0}\n CallStack:{1}\n\n Stack trace:\n{2}\n\n [SOURCE] Message: {3}\n Stack trace:\n{4}", ex.DecoratedMessage, StringifyStacktrace(ex.CallStack), ex.StackTrace, ex.InnerException?.Message, ex.InnerException?.StackTrace); + LuaLogger.Log(Channel.Lua, Priority.FatalError, "[CSharpException] Lua Call error: [EXCEPTION] Message: {0}\n CallStack:{1}\n\n Stack trace:\n{2}\n\n [SOURCE] Message: {3}\n Stack trace:\n{4}", ex.DecoratedMessage, StringifyStacktrace(ex.CallStack), ex.StackTrace, ex.InnerException?.Message, ex.InnerException?.StackTrace); throw; } catch (Exception ex) { - Logger.Log(Channel.Lua, Priority.FatalError, $"[{ex.GetType()}] Lua Call error: [EXCEPTION] Message: {0}\n Stack trace:\n{1}\n\n [SOURCE] Message: {2}\n Stack trace:\n{3}", ex.Message, ex.StackTrace, ex.InnerException?.Message, ex.InnerException?.StackTrace); + LuaLogger.Log(Channel.Lua, Priority.FatalError, $"[{ex.GetType()}] Lua Call error: [EXCEPTION] Message: {0}\n Stack trace:\n{1}\n\n [SOURCE] Message: {2}\n Stack trace:\n{3}", ex.Message, ex.StackTrace, ex.InnerException?.Message, ex.InnerException?.StackTrace); throw; } } @@ -353,7 +353,7 @@ public DynValue Call(DynValue luaFunc, params object[] args) { else { description = $"{luaFunc.Type} / {luaFunc.ToDebugPrintString()}"; } - Logger.Log(Channel.Lua, Priority.FatalError, $"Invalid lua function passed to LuaVM::Call: [{description}]"); + LuaLogger.Log(Channel.Lua, Priority.FatalError, $"Invalid lua function passed to LuaVM::Call: [{description}]"); } return result; @@ -370,8 +370,12 @@ public static string PrintDebug(Table table) { } string StringifyStacktrace(IList callstack) { - StringBuilder sb = new StringBuilder(); + if (callstack == null) { + return ""; + } + StringBuilder sb = new StringBuilder(); + foreach (WatchItem wi in callstack) { string name; @@ -415,7 +419,7 @@ public DynValue Call(string functionName, params object[] args) { //} } else { - Logger.Log(Channel.Lua, Priority.FatalError, "Failed to find lua function '{0}'", functionName); + LuaLogger.Log(Channel.Lua, Priority.FatalError, "Failed to find lua function '{0}'", functionName); } } @@ -426,7 +430,7 @@ public void LogException(string functionName, InterpreterException ex) { if (ex.InnerException != null) { var inner = ex.InnerException; if (inner.InnerException != null) { - Logger.Log(Channel.Lua, Priority.FatalError, + LuaLogger.Log(Channel.Lua, Priority.FatalError, "Lua error A calling function '{0}':\n\n" + "message = {1}\n" + "decorated = {2}\n\n" + @@ -451,7 +455,7 @@ public void LogException(string functionName, InterpreterException ex) { StringifyStacktrace(ex.CallStack)); } else { - Logger.Log(Channel.Lua, Priority.FatalError, + LuaLogger.Log(Channel.Lua, Priority.FatalError, "Lua error B calling function '{0}':\n\n" + "message = {1}\n" + "decorated = {2}\n\n" + @@ -469,7 +473,7 @@ public void LogException(string functionName, InterpreterException ex) { } } else { - Logger.Log(Channel.Lua, Priority.FatalError, + LuaLogger.Log(Channel.Lua, Priority.FatalError, "Lua error C calling function '{0}':\n\n" + "message = {1}\n" + "decorated = {2}\n\n" + @@ -505,7 +509,7 @@ public void AttachDebugger() { s_RemoteDebugger.AttachToScript(m_LuaScript, "Lua script"); } else { - Logger.Log(Channel.Lua, Priority.Error, "Tried to attach script to debugger before debugger was started"); + LuaLogger.Log(Channel.Lua, Priority.Error, "Tried to attach script to debugger before debugger was started"); } }