From c53cb7c1cb3cf3616edcfcdebd7a992cc7707e08 Mon Sep 17 00:00:00 2001 From: Roman Plotnikov Date: Sun, 10 May 2020 20:43:03 +0300 Subject: [PATCH 1/5] tonumber() support for '0x' values. --- src/MoonSharp.Interpreter/CoreLib/BasicModule.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/MoonSharp.Interpreter/CoreLib/BasicModule.cs b/src/MoonSharp.Interpreter/CoreLib/BasicModule.cs index 980e138c..e8ceb0f8 100755 --- a/src/MoonSharp.Interpreter/CoreLib/BasicModule.cs +++ b/src/MoonSharp.Interpreter/CoreLib/BasicModule.cs @@ -229,8 +229,13 @@ public static DynValue tonumber(ScriptExecutionContext executionContext, Callbac if (e.Type != DataType.String) return DynValue.Nil; - double d; - if (double.TryParse(e.String, NumberStyles.Any, CultureInfo.InvariantCulture, out d)) + if (e.String.StartsWith("0x")) + { + if (long.TryParse(e.String.Substring(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out long l)) + return DynValue.NewNumber(l); + return DynValue.Nil; + } + if (double.TryParse(e.String, NumberStyles.Any, CultureInfo.InvariantCulture, out double d)) { return DynValue.NewNumber(d); } From b86b02e664fb6921eb5fb1816db2e7ce3e4d69b1 Mon Sep 17 00:00:00 2001 From: Roman Plotnikov Date: Sun, 10 May 2020 20:47:46 +0300 Subject: [PATCH 2/5] fix DynValue tuple comparison. --- src/MoonSharp.Interpreter/DataTypes/DynValue.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/MoonSharp.Interpreter/DataTypes/DynValue.cs b/src/MoonSharp.Interpreter/DataTypes/DynValue.cs index 9df80fe0..24a0f1de 100644 --- a/src/MoonSharp.Interpreter/DataTypes/DynValue.cs +++ b/src/MoonSharp.Interpreter/DataTypes/DynValue.cs @@ -650,7 +650,12 @@ public override bool Equals(object obj) return Table == other.Table; case DataType.Tuple: case DataType.TailCallRequest: - return Tuple == other.Tuple; + if (Tuple.Length != other.Tuple.Length) + return false; + for(int i = 0; i < Tuple.Length; i++) + if (!Equals(Tuple[i], other.Tuple[i])) + return false; + return true; case DataType.Thread: return Coroutine == other.Coroutine; case DataType.UserData: @@ -709,6 +714,13 @@ public string CastToString() } else if (rv.Type == DataType.String) { + if (rv.String.StartsWith("0x")) + { + if (long.TryParse(rv.String, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out long value)) + return value; + return null; + } + double num; if (double.TryParse(rv.String, NumberStyles.Any, CultureInfo.InvariantCulture, out num)) return num; From 6000f6bc9c7a022138854d9afe1dd5032dcff98e Mon Sep 17 00:00:00 2001 From: Roman Plotnikov Date: Sun, 10 May 2020 20:52:21 +0300 Subject: [PATCH 3/5] fix: added support of nil value to string.format tweak: better StringModule compatibility --- .../CoreLib/StringLib/KopiLua_StrLib.cs | 4 ++-- .../Interop/LuaStateInterop/LuaBase.cs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/MoonSharp.Interpreter/CoreLib/StringLib/KopiLua_StrLib.cs b/src/MoonSharp.Interpreter/CoreLib/StringLib/KopiLua_StrLib.cs index f9b90cb3..cd51912c 100644 --- a/src/MoonSharp.Interpreter/CoreLib/StringLib/KopiLua_StrLib.cs +++ b/src/MoonSharp.Interpreter/CoreLib/StringLib/KopiLua_StrLib.cs @@ -101,7 +101,7 @@ public class capture_ }; - public const int MAXCCALLS = 200; + public const int MAXCCALLS = 1000; public const char L_ESC = '%'; public const string SPECIALS = "^$*+?.([%-"; @@ -959,7 +959,7 @@ public static int str_format(LuaState L) case 's': { uint l; - CharPtr s = LuaLCheckLString(L, arg, out l); + CharPtr s = LuaLCheckLString(L, arg, out l, true); if ((strchr(form, '.') == null) && l >= 100) { /* no precision and string is too long to be formatted; diff --git a/src/MoonSharp.Interpreter/Interop/LuaStateInterop/LuaBase.cs b/src/MoonSharp.Interpreter/Interop/LuaStateInterop/LuaBase.cs index e62ff92b..1bc2bb2a 100644 --- a/src/MoonSharp.Interpreter/Interop/LuaStateInterop/LuaBase.cs +++ b/src/MoonSharp.Interpreter/Interop/LuaStateInterop/LuaBase.cs @@ -76,10 +76,10 @@ protected static lua_Integer LuaType(LuaState L, lua_Integer p) } } - protected static string LuaLCheckLString(LuaState L, lua_Integer argNum, out uint l) + protected static string LuaLCheckLString(LuaState L, lua_Integer argNum, out uint l, bool allowNil = false) { - string str = ArgAsType(L, argNum, DataType.String, false).String; - l = (uint)str.Length; + string str = ArgAsType(L, argNum, DataType.String, allowNil).String; + l = (uint)(str?.Length ?? 0); return str; } From b819a48a3604a14fb75f5ca5bcd23f854d6ec243 Mon Sep 17 00:00:00 2001 From: Roman Plotnikov Date: Sun, 10 May 2020 20:56:06 +0300 Subject: [PATCH 4/5] fix: local uninitialized values sometimes was initialized with random value from stack instead of nil value (if that stack value was tuple with at least two items, second one was pushed as initialization value). --- .../Tree/Statements/AssignmentStatement.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/MoonSharp.Interpreter/Tree/Statements/AssignmentStatement.cs b/src/MoonSharp.Interpreter/Tree/Statements/AssignmentStatement.cs index a82fe67a..1eaf7e4f 100644 --- a/src/MoonSharp.Interpreter/Tree/Statements/AssignmentStatement.cs +++ b/src/MoonSharp.Interpreter/Tree/Statements/AssignmentStatement.cs @@ -39,7 +39,8 @@ public AssignmentStatement(ScriptLoadingContext lcontext, Token startToken) } else { - m_RValues = new List(); + if (names.Count > 0) + m_RValues = new List(new Expression[] { new LiteralExpression(lcontext, DynValue.Nil) }); } foreach (string name in names) From 9aa7e88fdd3816c9fe88f014e69a815c693d5ed3 Mon Sep 17 00:00:00 2001 From: Roman Plotnikov Date: Sun, 10 May 2020 21:03:08 +0300 Subject: [PATCH 5/5] Some intrusive changes for FactorioModLoader. --- .../CoreLib/BasicModule.cs | 7 +- .../CoreLib/DebugModule.cs | 168 ++++++++++++++---- .../CoreLib/TableIteratorsModule.cs | 2 + .../Errors/InterpreterException.cs | 30 +++- .../Execution/ScriptExecutionContext.cs | 11 ++ .../VM/Processor/Processor_Errors.cs | 9 + .../Interop/LuaStateInterop/CharPtr.cs | 9 +- .../Interop/LuaStateInterop/LuaBase.cs | 5 + .../Interop/LuaStateInterop/LuaState.cs | 5 + src/MoonSharp.Interpreter/Script.cs | 12 ++ 10 files changed, 220 insertions(+), 38 deletions(-) diff --git a/src/MoonSharp.Interpreter/CoreLib/BasicModule.cs b/src/MoonSharp.Interpreter/CoreLib/BasicModule.cs index e8ceb0f8..a93c9647 100755 --- a/src/MoonSharp.Interpreter/CoreLib/BasicModule.cs +++ b/src/MoonSharp.Interpreter/CoreLib/BasicModule.cs @@ -42,10 +42,11 @@ public static DynValue assert(ScriptExecutionContext executionContext, CallbackA if (!v.CastToBool()) { + var cor = executionContext.GetCallingCoroutine(); if (message.IsNil()) - throw new ScriptRuntimeException("assertion failed!"); // { DoNotDecorateMessage = true }; + throw new ScriptRuntimeException("assertion failed!") { CallStack = cor.GetStackTrace(0) }; // { DoNotDecorateMessage = true }; else - throw new ScriptRuntimeException(message.ToPrintString()); // { DoNotDecorateMessage = true }; + throw new ScriptRuntimeException(message.ToPrintString()) { CallStack = cor.GetStackTrace(0) }; // { DoNotDecorateMessage = true }; } return DynValue.NewTupleNested(args.GetArray()); @@ -91,7 +92,7 @@ public static DynValue error(ScriptExecutionContext executionContext, CallbackAr WatchItem[] stacktrace = cor.GetStackTrace(0, executionContext.CallingLocation); - var e = new ScriptRuntimeException(message.String); + var e = new ScriptRuntimeException(message.String) { CallStack = stacktrace }; if (level.IsNil()) { diff --git a/src/MoonSharp.Interpreter/CoreLib/DebugModule.cs b/src/MoonSharp.Interpreter/CoreLib/DebugModule.cs index c61d30ba..b8890f33 100644 --- a/src/MoonSharp.Interpreter/CoreLib/DebugModule.cs +++ b/src/MoonSharp.Interpreter/CoreLib/DebugModule.cs @@ -297,47 +297,153 @@ public static DynValue traceback(ScriptExecutionContext executionContext, Callba //} - //[MoonSharpMethod] - //public static DynValue getinfo(ScriptExecutionContext executionContext, CallbackArguments args) - //{ - // Coroutine cor = executionContext.GetCallingCoroutine(); - // int vfArgIdx = 0; - - // if (args[0].Type == DataType.Thread) - // cor = args[0].Coroutine; + [MoonSharpModuleMethod] + public static DynValue getinfo(ScriptExecutionContext executionContext, CallbackArguments args) + { + Coroutine cor = executionContext.GetCallingCoroutine(); + int vfArgIdx = 0; - // DynValue vf = args[vfArgIdx+0]; - // DynValue vwhat = args[vfArgIdx+1]; + if (args[0].Type == DataType.Thread) + cor = args[0].Coroutine; - // args.AsType(vfArgIdx + 1, "getinfo", DataType.String, true); + DynValue vf = args[vfArgIdx+0]; + DynValue vwhat = args[vfArgIdx+1]; + + //args.AsType(vfArgIdx + 1, "getinfo", DataType.String, true); - // string what = vwhat.CastToString() ?? "nfSlu"; + string what = vwhat.CastToString() ?? "nfSlu"; - // DynValue vt = DynValue.NewTable(executionContext.GetScript()); - // Table t = vt.Table; + DynValue vt = DynValue.NewTable(executionContext.GetScript()); + Table t = vt.Table; + if (vf.Type == DataType.Function || vf.Type == DataType.ClrFunction) + { + GetInfoAboutFunction(t, vf, what, executionContext); + return vt; + } + else if (vf.Type == DataType.Number) + { + var stackTrace = cor.GetStackTrace((int)vf.Number); + if (stackTrace.Length <= 0) + return DynValue.Nil; + var info = stackTrace[0]; + if (what.Contains("S")) + { + var source = executionContext.OwnerScript.GetSourceCode(info.Location.SourceIdx); + if (source != null) + { + t["source"] = source != null ? source.Name : "[C]"; + t["short_src"] = source.Name.Substring(0, Math.Min(source.Name.Length, 60)); + t["what"] = "Lua"; + } + else + { + t["source"] = "[C]"; + t["short_src"] = "[C]"; + t["what"] = "C"; + } + } - // if (vf.Type == DataType.Function) - // { - // Closure f = vf.Function; - // executionContext.GetInfoForFunction - // } - // else if (vf.Type == DataType.ClrFunction) - // { + if (what.Contains("L")) + { - // } - // else if (vf.Type == DataType.Number || vf.Type == DataType.String) - // { + } - // } - // else - // { - // args.AsType(vfArgIdx + 0, "getinfo", DataType.Number, true); - // } + if (what.Contains("n")) + { - // return vt; + } + if (what.Contains("u")) + { - //} + } + t["linedefined"] = info.Location.FromLine; + t["lastlinedefined"] = info.Location.ToLine; + return vt; + } + return DynValue.Nil; + } + + private static void GetInfoAboutFunction(Table infoTable, DynValue function, string what, ScriptExecutionContext executionContext) + { + if (function.Type == DataType.Function) + { + Closure f = function.Function; + var sourceRef = executionContext.GetFunctionSourceCodeRef(f); + var source = executionContext.OwnerScript.GetSourceCode(sourceRef.SourceIdx); + if (what.Contains("S")) + { + infoTable["source"] = source.Name; + infoTable["short_src"] = source.Name.Substring(0, Math.Min(source.Name.Length, 60)); + + infoTable["what"] = "Lua"; + } + + if (what.Contains("L")) + { + var lines = new Table(executionContext.OwnerScript); + for (int i = sourceRef.FromLine; i <= sourceRef.ToLine; i++) + lines.Append(DynValue.NewString(source.Lines[i])); + infoTable["activelines"] = lines; + } + + if (what.Contains("n")) + { + var name = executionContext.GetFunctionName(f); + infoTable["name"] = name; + var symbolRef = executionContext.FindSymbolByName(name); + switch (symbolRef.Type) + { + case SymbolRefType.Global: + infoTable["namewhat"] = "global"; + break; + case SymbolRefType.Local: + infoTable["namewhat"] = "local"; + break; + case SymbolRefType.DefaultEnv: + infoTable["namewhat"] = "field"; + break; + } + } + + if (what.Contains("u")) + { + infoTable["nups"] = f.GetUpvaluesCount(); + } + + infoTable["linedefined"] = sourceRef.FromLine; + infoTable["lastlinedefined"] = sourceRef.ToLine; + } + else if (function.Type == DataType.ClrFunction) + { + CallbackFunction f = function.Callback; + if (what.Contains("S")) + { + infoTable["source"] = "[C]"; + infoTable["short_src"] = "[C]"; + infoTable["what"] = "C"; + } + + if (what.Contains("n")) + { + var symbolRef = executionContext.FindSymbolByName(f.Name); + infoTable["name"] = f.Name; + switch (symbolRef.Type) + { + case SymbolRefType.Global: + infoTable["namewhat"] = "global"; + break; + case SymbolRefType.Local: + infoTable["namewhat"] = "local"; + break; + case SymbolRefType.DefaultEnv: + infoTable["namewhat"] = "field"; + break; + } + } + } + + } } } diff --git a/src/MoonSharp.Interpreter/CoreLib/TableIteratorsModule.cs b/src/MoonSharp.Interpreter/CoreLib/TableIteratorsModule.cs index 6e3b84fe..c6d7efff 100644 --- a/src/MoonSharp.Interpreter/CoreLib/TableIteratorsModule.cs +++ b/src/MoonSharp.Interpreter/CoreLib/TableIteratorsModule.cs @@ -20,6 +20,8 @@ public class TableIteratorsModule public static DynValue ipairs(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue table = args[0]; + if(table == null || table.Type == DataType.Nil) + throw new System.ApplicationException("attempt to index nil"); DynValue meta = executionContext.GetMetamethodTailCall(table, "__ipairs", args.GetArray()); diff --git a/src/MoonSharp.Interpreter/Errors/InterpreterException.cs b/src/MoonSharp.Interpreter/Errors/InterpreterException.cs index a63fe83c..5eac88ba 100755 --- a/src/MoonSharp.Interpreter/Errors/InterpreterException.cs +++ b/src/MoonSharp.Interpreter/Errors/InterpreterException.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Text; using MoonSharp.Interpreter.Debugging; namespace MoonSharp.Interpreter @@ -86,11 +87,36 @@ internal void DecorateMessage(Script script, SourceRef sref, int ip = -1) } else if (sref != null) { - this.DecoratedMessage = string.Format("{0}: {1}", sref.FormatLocation(script), this.Message); + var buffer = new StringBuilder($"{sref.FormatLocation(script)}: {this.Message}"); + if (CallStack != null) + { + buffer.AppendLine(); + foreach (var item in CallStack) + if (item.Location != null) + buffer.AppendLine($"{item.Location.FormatLocation(script)}: {item.Name}"); + else + buffer.AppendLine($"unknown: {item.Name}"); + } + else + new object(); + + this.DecoratedMessage = buffer.ToString(); } else { - this.DecoratedMessage = string.Format("bytecode:{0}: {1}", ip, this.Message); + var buffer = new StringBuilder($"bytecode:{ip}: {this.Message}"); + if (CallStack != null) + { + buffer.AppendLine(); + foreach (var item in CallStack) + if (item.Location != null) + buffer.AppendLine($"{item.Location.FormatLocation(script)}: {item.Name}"); + else + buffer.AppendLine($"unknown: {item.Name}"); + } + else + new object(); + this.DecoratedMessage = buffer.ToString(); } } } diff --git a/src/MoonSharp.Interpreter/Execution/ScriptExecutionContext.cs b/src/MoonSharp.Interpreter/Execution/ScriptExecutionContext.cs index 0a42ccfb..175219d7 100644 --- a/src/MoonSharp.Interpreter/Execution/ScriptExecutionContext.cs +++ b/src/MoonSharp.Interpreter/Execution/ScriptExecutionContext.cs @@ -54,6 +54,17 @@ public object AdditionalData } } + public SourceRef GetFunctionSourceCodeRef(Closure fn) + { + var i = fn.EntryPointByteCodeLocation; + return m_Processor.FindMeta(ref i).SourceCodeRef; + } + + public string GetFunctionName(Closure fn) + { + var i = fn.EntryPointByteCodeLocation; + return m_Processor.FindMeta(ref i).Name; + } /// /// Gets the metatable associated with the given value. diff --git a/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_Errors.cs b/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_Errors.cs index 65e78659..cac0fa7d 100644 --- a/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_Errors.cs +++ b/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_Errors.cs @@ -4,6 +4,15 @@ namespace MoonSharp.Interpreter.Execution.VM { sealed partial class Processor { + public SourceRef GetCurrentSourceRef() + { + if (m_SavedInstructionPtr >= 0 && m_SavedInstructionPtr < m_RootChunk.Code.Count) + { + return m_RootChunk.Code[m_SavedInstructionPtr].SourceCodeRef; + } + + return null; + } private SourceRef GetCurrentSourceRef(int instructionPtr) { if (instructionPtr >= 0 && instructionPtr < m_RootChunk.Code.Count) diff --git a/src/MoonSharp.Interpreter/Interop/LuaStateInterop/CharPtr.cs b/src/MoonSharp.Interpreter/Interop/LuaStateInterop/CharPtr.cs index dc1b2c62..d476cc8e 100644 --- a/src/MoonSharp.Interpreter/Interop/LuaStateInterop/CharPtr.cs +++ b/src/MoonSharp.Interpreter/Interop/LuaStateInterop/CharPtr.cs @@ -134,8 +134,13 @@ public CharPtr(IntPtr ptr) public static CharPtr operator +(CharPtr ptr, uint offset) { return new CharPtr(ptr.chars, ptr.index + (int)offset); } public static CharPtr operator -(CharPtr ptr, uint offset) { return new CharPtr(ptr.chars, ptr.index - (int)offset); } - public void inc() { this.index++; } - public void dec() { this.index--; } + public CharPtr Copy() + { + return new CharPtr(this); + } + + public CharPtr inc() { this.index++; return this; } + public CharPtr dec() { this.index--; return this; } public CharPtr next() { return new CharPtr(this.chars, this.index + 1); } public CharPtr prev() { return new CharPtr(this.chars, this.index - 1); } public CharPtr add(int ofs) { return new CharPtr(this.chars, this.index + ofs); } diff --git a/src/MoonSharp.Interpreter/Interop/LuaStateInterop/LuaBase.cs b/src/MoonSharp.Interpreter/Interop/LuaStateInterop/LuaBase.cs index 1bc2bb2a..c7e947da 100644 --- a/src/MoonSharp.Interpreter/Interop/LuaStateInterop/LuaBase.cs +++ b/src/MoonSharp.Interpreter/Interop/LuaStateInterop/LuaBase.cs @@ -224,6 +224,11 @@ protected static void LuaPop(LuaState L, lua_Integer p) L.Pop(); } + protected static void LuaRemove(LuaState L, lua_Integer p) + { + L.Remove(-p); + } + protected static void LuaGetTable(LuaState L, lua_Integer p) { // DEBT: this should call metamethods, now it performs raw access diff --git a/src/MoonSharp.Interpreter/Interop/LuaStateInterop/LuaState.cs b/src/MoonSharp.Interpreter/Interop/LuaStateInterop/LuaState.cs index 94fbbbcb..6df81bd3 100644 --- a/src/MoonSharp.Interpreter/Interop/LuaStateInterop/LuaState.cs +++ b/src/MoonSharp.Interpreter/Interop/LuaStateInterop/LuaState.cs @@ -59,6 +59,11 @@ public DynValue Pop() return v; } + public void Remove(int idx) + { + m_Stack.RemoveAt(m_Stack.Count - 1); + } + public DynValue[] GetTopArray(int num) { DynValue[] rets = new DynValue[num]; diff --git a/src/MoonSharp.Interpreter/Script.cs b/src/MoonSharp.Interpreter/Script.cs index 6e3bb11a..27f314ef 100755 --- a/src/MoonSharp.Interpreter/Script.cs +++ b/src/MoonSharp.Interpreter/Script.cs @@ -745,5 +745,17 @@ Script IScriptPrivateResource.OwnerScript { get { return this; } } + + public string CurrentSource + { + get + { + var callStack = m_MainProcessor.Debugger_GetCallStack(m_MainProcessor.GetCurrentSourceRef()); + foreach(var item in callStack) + if (item.Location != null && item.Location.SourceIdx >= 1 && item.Location.SourceIdx <= SourceCodeCount) + return m_Sources[item.Location.SourceIdx].Name; + return null; + } + } } }