From 85068dae60db02b168a29ffd75e1408e30d279e1 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Sat, 27 Sep 2008 05:31:43 +0000 Subject: Add friendly error messages to both engines. --- .../ScriptEngine/DotNetEngine/EventQueueManager.cs | 7 + .../DotNetEngine/EventQueueThreadClass.cs | 92 ++++++--- .../ScriptEngine/DotNetEngine/ScriptManager.cs | 5 +- .../Region/ScriptEngine/Interfaces/ICompiler.cs | 5 +- .../ScriptEngine/Interfaces/IScriptInstance.cs | 3 + .../Shared/CodeTools/CSCodeGenerator.cs | 19 +- .../ScriptEngine/Shared/CodeTools/Compiler.cs | 225 ++++++++++++++------- .../ScriptEngine/Shared/Instance/ScriptInstance.cs | 51 ++++- OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | 5 +- 9 files changed, 303 insertions(+), 109 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs index 634a12b..4a094e2 100644 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs +++ b/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueManager.cs @@ -139,6 +139,8 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine public string functionName; public DetectParams[] llDetectParams; public object[] param; + public Dictionary,KeyValuePair> + LineMap; } #endregion @@ -349,6 +351,9 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine return false; } + InstanceData id = m_ScriptEngine.m_ScriptManager.GetScript( + localID, itemID); + // Create a structure and add data QueueItemStruct QIS = new QueueItemStruct(); QIS.localID = localID; @@ -356,6 +361,8 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine QIS.functionName = FunctionName; QIS.llDetectParams = qParams; QIS.param = param; + if (id != null) + QIS.LineMap = id.LineMap; // Add it to queue eventQueue.Enqueue(QIS); diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueThreadClass.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueThreadClass.cs index 2d60ed5..16dafdc 100644 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueThreadClass.cs +++ b/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueThreadClass.cs @@ -27,6 +27,7 @@ using System; using System.Collections; +using System.Collections.Generic; using System.Reflection; using System.Text.RegularExpressions; using System.Threading; @@ -37,6 +38,7 @@ using OpenSim.Framework; using OpenSim.Region.Environment.Scenes; using OpenSim.Region.Environment.Scenes.Scripting; using OpenSim.Region.ScriptEngine.Shared; +using OpenSim.Region.ScriptEngine.Shared.CodeTools; namespace OpenSim.Region.ScriptEngine.DotNetEngine { @@ -198,10 +200,6 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine } catch (Exception e) { - if (lastScriptEngine != null) - lastScriptEngine.Log.Error("[" + ScriptEngineName + - "]: Exception in EventQueueThreadLoop: " + - e.ToString()); } } } @@ -290,32 +288,32 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine catch (Exception e) { InExecution = false; + string text = FormatException(e, QIS.LineMap); + // DISPLAY ERROR INWORLD - string text = "Error executing script function \"" + - QIS.functionName + "\":\r\n"; - if (e.InnerException != null) - { - // Send inner exception - string line = " (unknown line)"; - Regex rx = new Regex(@"SecondLife\.Script\..+[\s:](?\d+)\.?\r?$", RegexOptions.Compiled); - if (rx.Match(e.InnerException.ToString()).Success) - line = " (line " + rx.Match(e.InnerException.ToString()).Result("${line}") + ")"; - text += e.InnerException.Message.ToString() + line; - } - else - { - text += "\r\n"; - // Send normal - text += e.Message.ToString(); - } - if (KillCurrentScript) - text += "\r\nScript will be deactivated!"; +// if (e.InnerException != null) +// { +// // Send inner exception +// string line = " (unknown line)"; +// Regex rx = new Regex(@"SecondLife\.Script\..+[\s:](?\d+)\.?\r?$", RegexOptions.Compiled); +// if (rx.Match(e.InnerException.ToString()).Success) +// line = " (line " + rx.Match(e.InnerException.ToString()).Result("${line}") + ")"; +// text += e.InnerException.Message.ToString() + line; +// } +// else +// { +// text += "\r\n"; +// // Send normal +// text += e.Message.ToString(); +// } +// if (KillCurrentScript) +// text += "\r\nScript will be deactivated!"; try { - if (text.Length > 1500) - text = text.Substring(0, 1500); + if (text.Length >= 1100) + text = text.Substring(0, 1099); IScriptHost m_host = m_ScriptEngine.World.GetSceneObjectPart(QIS.localID); m_ScriptEngine.World.SimChat( @@ -343,10 +341,6 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine QIS.localID, QIS.itemID); } } - - // Pass it on so it's displayed on the console - // and in the logs (mikem 2008.06.02). - throw e.InnerException; } finally { @@ -358,5 +352,45 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine } } } + + string FormatException(Exception e, Dictionary, + KeyValuePair> LineMap) + { + string message = "Runtime error:\n" + e.InnerException.StackTrace; + string[] lines = message.Split(new char[] {'\n'}); + + foreach (string line in lines) + { + if (line.Contains("SecondLife.Script")) + { + int idx = line.IndexOf(':'); + if (idx != -1) + { + string val = line.Substring(idx+1); + int lineNum = 0; + if (int.TryParse(val, out lineNum)) + { + KeyValuePair pos = + Compiler.FindErrorPosition( + lineNum, 0, LineMap); + + int scriptLine = pos.Key; + int col = pos.Value; + if (scriptLine == 0) + scriptLine++; + if (col == 0) + col++; + message = string.Format("Runtime error:\n" + + "Line ({0}): {1}", scriptLine - 1, + e.InnerException.Message); + + return message; + } + } + } + } + + return message; + } } } diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs index 8329805..1c1dcf3 100644 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs +++ b/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs @@ -53,6 +53,8 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine public int StartParam; public AppDomain AppDomain; public Dictionary Apis; + public Dictionary, KeyValuePair> + LineMap; } public class ScriptManager @@ -159,6 +161,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine m_scriptEngine.m_AppDomainManager.LoadScript( CompiledScriptFile, out id.AppDomain); + id.LineMap = LSLCompiler.LineMap(); id.Script = CompiledScript; id.Source = Script; id.StartParam = startParam; @@ -212,7 +215,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine try { // DISPLAY ERROR INWORLD - string text = "Error compiling script:\r\n" + + string text = "Error compiling script:\n" + e.Message.ToString(); if (text.Length > 1100) text = text.Substring(0, 1099); diff --git a/OpenSim/Region/ScriptEngine/Interfaces/ICompiler.cs b/OpenSim/Region/ScriptEngine/Interfaces/ICompiler.cs index efb05d3..6273da9 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/ICompiler.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/ICompiler.cs @@ -33,7 +33,8 @@ namespace OpenSim.Region.ScriptEngine.Interfaces { public interface ICompiler { - void Configure(IConfig configSource); - void Compile(string text, string outFile, List apiList); + string PerformScriptCompile(string source, string asset); + Dictionary, KeyValuePair> + LineMap(); } } diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs index 0c807a8..dee7970 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs @@ -96,5 +96,8 @@ namespace OpenSim.Region.ScriptEngine.Interfaces void DestroyScriptInstance(); IScriptApi GetApi(string name); + + Dictionary, KeyValuePair> LineMap + { get; set; } } } diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs index 86d6188..e8f2b71 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs @@ -89,7 +89,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools ResetCounters(); Parser p = new LSLSyntax(new yyLSLSyntax(), new ErrorHandler(true)); // Obviously this needs to be in a try/except block. - LSL2CSCodeTransformer codeTransformer = new LSL2CSCodeTransformer(p.Parse(script)); + LSL2CSCodeTransformer codeTransformer; + try + { + codeTransformer = new LSL2CSCodeTransformer(p.Parse(script)); + } + catch (CSToolsException e) + { + string message; + + // LL start numbering lines at 0 - geeks! + // + message = String.Format("Line ({0},{1}) {2}", + e.slInfo.lineNumber - 1, + e.slInfo.charPosition - 1, e.Message); + + throw new Exception(message); + } + m_astRoot = codeTransformer.Transform(); string retstr = String.Empty; diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs index ec864e1..c6026fb 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs @@ -38,7 +38,7 @@ using OpenSim.Region.ScriptEngine.Interfaces; namespace OpenSim.Region.ScriptEngine.Shared.CodeTools { - public class Compiler + public class Compiler : ICompiler { // private static readonly log4net.ILog m_log // = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); @@ -255,18 +255,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools /// Filename to .dll assembly public string PerformScriptCompile(string Script, string asset) { + m_positionMap = null; + string OutFile = Path.Combine(ScriptEnginesPath, Path.Combine( m_scriptEngine.World.RegionInfo.RegionID.ToString(), FilePrefix + "_compiled_" + asset + ".dll")); // string OutFile = Path.Combine(ScriptEnginesPath, // FilePrefix + "_compiled_" + asset + ".dll"); - if (File.Exists(OutFile)) - { - m_scriptEngine.Log.DebugFormat("[Compiler] Returning existing assembly for {0}", asset); - return OutFile; - } - if (!Directory.Exists(ScriptEnginesPath)) { try @@ -327,38 +323,26 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools compileScript = LSL_Converter.Convert(Script); m_positionMap = ((CSCodeGenerator) LSL_Converter).PositionMap; + } - l = enumCompileType.cs; + // Check this late so the map is generated on sim start + // + if (File.Exists(OutFile)) + { + m_scriptEngine.Log.DebugFormat("[Compiler] Returning existing assembly for {0}", asset); + return OutFile; } if (l == enumCompileType.yp) { // Its YP, convert it to C# compileScript = YP_Converter.Convert(Script); - // We have our own processor now - //l = enumCompileType.cs; - } - - // Insert additional assemblies here - - //ADAM: Disabled for the moment until it's working right. - bool enableCommanderLSL = false; - - if (enableCommanderLSL == true && ((l == enumCompileType.cs) || (l == enumCompileType.yp))) - { - foreach (KeyValuePair com - in m_scriptEngine.World.GetCommanders()) - { - compileScript = com.Value.GenerateRuntimeAPI() + compileScript; - } } - // End of insert - switch (l) { case enumCompileType.cs: + case enumCompileType.lsl: compileScript = CreateCSCompilerScript(compileScript); break; case enumCompileType.vb: @@ -372,10 +356,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools break; } -// m_log.Debug("[ScriptEngine.DotNetEngine]: Preparing to compile the following LSL to C# translated code"); -// m_log.Debug(""); -// m_log.Debug(compileScript); - return CompileFromDotNetText(compileScript, l, asset); } @@ -442,26 +422,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools // Output assembly name scriptCompileCounter++; string OutFile = Path.Combine(ScriptEnginesPath, Path.Combine( - m_scriptEngine.World.RegionInfo.RegionID.ToString(), - FilePrefix + "_compiled_" + asset + ".dll")); -#if DEBUG -// m_scriptEngine.Log.Debug("[Compiler]: Starting compile of \"" + OutFile + "\"."); -#endif + m_scriptEngine.World.RegionInfo.RegionID.ToString(), + FilePrefix + "_compiled_" + asset + ".dll")); try { File.Delete(OutFile); } - catch (Exception e) // NOTLEGIT - Should be just catching FileIOException + catch (Exception e) // NOTLEGIT - Should be just FileIOException { - //m_scriptEngine.Log.Error("[Compiler]: Unable to delete old existring script-file before writing new. Compile aborted: " + e.ToString()); - throw new Exception("Unable to delete old existring script-file before writing new. Compile aborted: " + e.ToString()); + throw new Exception("Unable to delete old existing "+ + "script-file before writing new. Compile aborted: " + + e.ToString()); } - //string OutFile = Path.Combine("ScriptEngines", "SecondLife.Script.dll"); // DEBUG - write source to disk if (WriteScriptSourceToDebugFile) { - string srcFileName = FilePrefix + "_source_" + Path.GetFileNameWithoutExtension(OutFile) + ext; + string srcFileName = FilePrefix + "_source_" + + Path.GetFileNameWithoutExtension(OutFile) + ext; try { File.WriteAllText(Path.Combine(Path.Combine( @@ -469,9 +447,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools m_scriptEngine.World.RegionInfo.RegionID.ToString()), srcFileName), Script); } - catch (Exception ex) // NOTLEGIT - Should be just catching FileIOException + catch (Exception ex) //NOTLEGIT - Should be just FileIOException { - m_scriptEngine.Log.Error("[Compiler]: Exception while trying to write script source to file \"" + srcFileName + "\": " + ex.ToString()); + m_scriptEngine.Log.Error("[Compiler]: Exception while "+ + "trying to write script source to file \"" + + srcFileName + "\": " + ex.ToString()); } } @@ -480,22 +460,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools parameters.IncludeDebugInformation = true; - // Add all available assemblies -// foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) -// { -// Console.WriteLine("Adding assembly: " + asm.Location); -// parameters.ReferencedAssemblies.Add(asm.Location); -// } + string rootPath = + Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory); - string rootPath = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory); - // string rootPathSE = Path.GetDirectoryName(GetType().Assembly.Location); - //Console.WriteLine("Assembly location: " + rootPath); - parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, "OpenSim.Region.ScriptEngine.Shared.dll")); - parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, "OpenSim.Region.ScriptEngine.Shared.Api.Runtime.dll")); + parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, + "OpenSim.Region.ScriptEngine.Shared.dll")); + parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, + "OpenSim.Region.ScriptEngine.Shared.Api.Runtime.dll")); if (lang == enumCompileType.yp) { - parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, "OpenSim.Region.ScriptEngine.Shared.YieldProlog.dll")); + parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, + "OpenSim.Region.ScriptEngine.Shared.YieldProlog.dll")); } parameters.GenerateExecutable = false; @@ -504,24 +480,29 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools //parameters.WarningLevel = 1; // Should be 4? parameters.TreatWarningsAsErrors = false; -//Console.WriteLine(Script); CompilerResults results; switch (lang) { case enumCompileType.vb: - results = VBcodeProvider.CompileAssemblyFromSource(parameters, Script); + results = VBcodeProvider.CompileAssemblyFromSource( + parameters, Script); break; case enumCompileType.cs: - results = CScodeProvider.CompileAssemblyFromSource(parameters, Script); + case enumCompileType.lsl: + results = CScodeProvider.CompileAssemblyFromSource( + parameters, Script); break; case enumCompileType.js: - results = JScodeProvider.CompileAssemblyFromSource(parameters, Script); + results = JScodeProvider.CompileAssemblyFromSource( + parameters, Script); break; case enumCompileType.yp: - results = YPcodeProvider.CompileAssemblyFromSource(parameters, Script); + results = YPcodeProvider.CompileAssemblyFromSource( + parameters, Script); break; default: - throw new Exception("Compiler is not able to recongnize language type \"" + lang.ToString() + "\""); + throw new Exception("Compiler is not able to recongnize "+ + "language type \"" + lang.ToString() + "\""); } // Check result @@ -530,11 +511,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools // // WARNINGS AND ERRORS // + int display = 5; if (results.Errors.Count > 0) { string errtext = String.Empty; foreach (CompilerError CompErr in results.Errors) { + // Show 5 errors max + // + if (display <= 0) + break; + display--; + string severity = "Error"; if ( CompErr.IsWarning ) { @@ -543,22 +531,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools KeyValuePair lslPos; - try - { - lslPos = m_positionMap[new KeyValuePair(CompErr.Line, CompErr.Column)]; - } - catch (KeyNotFoundException) // we don't have this line/column mapped - { - m_scriptEngine.Log.Debug(String.Format("[Compiler]: Lookup of C# line {0}, column {1} failed.", CompErr.Line, CompErr.Column)); - lslPos = new KeyValuePair(-CompErr.Line, -CompErr.Column); - } + lslPos = FindErrorPosition(CompErr.Line, CompErr.Column); + + string text = CompErr.ErrorText; + + // Use LSL type names + if (lang == enumCompileType.lsl) + text = ReplaceTypes(CompErr.ErrorText); // The Second Life viewer's script editor begins // countingn lines and columns at 0, so we subtract 1. - errtext += String.Format("Line {0}, column {1}, {4} Number: {2}, '{3}'\r\n", lslPos.Key - 1, lslPos.Value - 1, CompErr.ErrorNumber, CompErr.ErrorText, severity); + errtext += String.Format("Line ({0},{1}): {4} {2}: {3}\n", + lslPos.Key - 1, lslPos.Value - 1, + CompErr.ErrorNumber, text, severity); } - Console.WriteLine("[COMPILER MESSAGES]: " + errtext); if (!File.Exists(OutFile)) { throw new Exception(errtext); @@ -574,8 +561,100 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools errtext += "No compile error. But not able to locate compiled file."; throw new Exception(errtext); } - m_scriptEngine.Log.DebugFormat("[Compiler] Compiled new assembly for {0}", asset); + m_scriptEngine.Log.DebugFormat("[Compiler] Compiled new assembly "+ + "for {0}", asset); return OutFile; } + + public KeyValuePair FindErrorPosition(int line, int col) + { + return FindErrorPosition(line, col, m_positionMap); + } + + private class kvpSorter : IComparer> + { + public int Compare(KeyValuePair a, + KeyValuePair b) + { + return a.Key.CompareTo(b.Key); + } + } + + public static KeyValuePair FindErrorPosition(int line, + int col, Dictionary, + KeyValuePair> positionMap) + { + if (positionMap == null || positionMap.Count == 0) + return new KeyValuePair(line, col); + + KeyValuePair ret = new KeyValuePair(); + + if (positionMap.TryGetValue(new KeyValuePair(line, col), + out ret)) + return ret; + + List> sorted = + new List>(positionMap.Keys); + + sorted.Sort(new kvpSorter()); + + int l = 1; + int c = 1; + + foreach (KeyValuePair cspos in sorted) + { + if (cspos.Key >= line) + { + if (cspos.Key > line) + return new KeyValuePair(l, c); + if (cspos.Value > col) + return new KeyValuePair(l, c); + c = cspos.Value; + if (c == 0) + c++; + } + else + { + l = cspos.Key; + } + } + return new KeyValuePair(l, c); + } + + string ReplaceTypes(string message) + { + message = message.Replace( + "OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString", + "string"); + + message = message.Replace( + "OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger", + "integer"); + + message = message.Replace( + "OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat", + "float"); + + message = message.Replace( + "OpenSim.Region.ScriptEngine.Shared.LSL_Types.list", + "list"); + + return message; + } + + public Dictionary, KeyValuePair> + LineMap() + { + if (m_positionMap == null) + return null; + + Dictionary, KeyValuePair> ret = + new Dictionary, KeyValuePair>(); + + foreach (KeyValuePair kvp in m_positionMap.Keys) + ret.Add(kvp, m_positionMap[kvp]); + + return ret; + } } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index c8d60af..aa9ace4 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs @@ -80,6 +80,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance private int m_ControlEventsInQueue = 0; private int m_LastControlLevel = 0; private bool m_CollisionInQueue = false; + private Dictionary, KeyValuePair> + m_LineMap; + + public Dictionary, KeyValuePair> + LineMap + { + get { return m_LineMap; } + set { m_LineMap = value; } + } private Dictionary m_Apis = new Dictionary(); @@ -628,7 +637,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance try { // DISPLAY ERROR INWORLD - string text = "Runtime error:\n" + e.InnerException.ToString(); + string text = FormatException(e); + if (text.Length > 1000) text = text.Substring(0, 1000); m_Engine.World.SimChat(Utils.StringToBytes(text), @@ -812,5 +822,44 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance { return String.Format("{0} {1} on {2}", m_ScriptName, m_ItemID, m_PrimName); } + + string FormatException(Exception e) + { + string message = "Runtime error:\n" + e.InnerException.StackTrace; + string[] lines = message.Split(new char[] {'\n'}); + + foreach (string line in lines) + { + if (line.Contains("SecondLife.Script")) + { + int idx = line.IndexOf(':'); + if (idx != -1) + { + string val = line.Substring(idx+1); + int lineNum = 0; + if (int.TryParse(val, out lineNum)) + { + KeyValuePair pos = + Compiler.FindErrorPosition( + lineNum, 0, LineMap); + + int scriptLine = pos.Key; + int col = pos.Value; + if (scriptLine == 0) + scriptLine++; + if (col == 0) + col++; + message = string.Format("Runtime error:\n" + + "Line ({0}): {1}", scriptLine - 1, + e.InnerException.Message); + + return message; + } + } + } + } + + return message; + } } } diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index a37cbb4..6bafd69 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -59,7 +59,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine private int m_MaxScriptQueue; private Scene m_Scene; private IConfig m_ScriptConfig; - private Compiler m_Compiler; + private ICompiler m_Compiler; private int m_MinThreads; private int m_MaxThreads ; private int m_IdleTimeout; @@ -510,7 +510,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine try { // DISPLAY ERROR INWORLD - string text = "Error compiling script:\r\n" + e.Message.ToString(); + string text = "Error compiling script:\n" + e.ToString(); if (text.Length > 1000) text = text.Substring(0, 1000); World.SimChat(Utils.StringToBytes(text), @@ -585,6 +585,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine part.ParentGroup.RootPart.Name, item.Name); instance.AppDomain = appDomain; + instance.LineMap = m_Compiler.LineMap(); m_Scripts[itemID] = instance; } -- cgit v1.1