From d4c98ddffc7b6ac25cd08f57f9f67a33bff91683 Mon Sep 17 00:00:00 2001 From: Alan M Webb Date: Wed, 16 Sep 2009 10:00:00 -0400 Subject: [PATCH] This fix adds a stand-alone compilation environment for OpenSIm scripts. It makes it very easy to address coding issues before going in-world to try a script out. This is a HUGE time saver if you're doing anything significant with scripts. Signed-off-by: dr scofield (aka dirk husemann) --- OpenSim/Tools/Compiler/Program.cs | 287 ++++++++++++++++++++++++++++++ prebuild.xml | 27 +++ 2 files changed, 314 insertions(+) create mode 100644 OpenSim/Tools/Compiler/Program.cs diff --git a/OpenSim/Tools/Compiler/Program.cs b/OpenSim/Tools/Compiler/Program.cs new file mode 100644 index 0000000000..0141f48d4f --- /dev/null +++ b/OpenSim/Tools/Compiler/Program.cs @@ -0,0 +1,287 @@ + +using System; +using System.Collections.Generic; +using System.IO; +using Microsoft.CSharp; +using OpenSim.Region.ScriptEngine.Shared.CodeTools; +using System.CodeDom.Compiler; + +namespace OpenSim.Tools.LSL.Compiler +{ + class Program + { + private static Dictionary, KeyValuePair> m_positionMap; + private static CSharpCodeProvider CScodeProvider = new CSharpCodeProvider(); + + static void Main(string[] args) + { + string source = null; + + if(args.Length == 0) + { + Console.WriteLine("No input file specified"); + Environment.Exit(1); + } + + if(!File.Exists(args[0])) + { + Console.WriteLine("Input file does not exist"); + Environment.Exit(1); + } + + try + { + ICodeConverter cvt = (ICodeConverter) new CSCodeGenerator(); + source = cvt.Convert(File.ReadAllText(args[0])); + } + catch(Exception e) + { + Console.WriteLine("Conversion failed:\n"+e.Message); + Environment.Exit(1); + } + + source = CreateCSCompilerScript(source); + + try + { + Console.WriteLine(CompileFromDotNetText(source,"a.out")); + } + catch(Exception e) + { + Console.WriteLine("Conversion failed: "+e.Message); + Environment.Exit(1); + } + + Environment.Exit(0); + } + + private static string CreateCSCompilerScript(string compileScript) + { + compileScript = String.Empty + + "using OpenSim.Region.ScriptEngine.Shared; using System.Collections.Generic;\r\n" + + String.Empty + "namespace SecondLife { " + + String.Empty + "public class Script : OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass { \r\n" + + @"public Script() { } " + + compileScript + + "} }\r\n"; + return compileScript; + } + + private static string CompileFromDotNetText(string Script, string asset) + { + + string OutFile = asset; + string disp ="OK"; + + try + { + File.Delete(OutFile); + } + catch (Exception e) // NOTLEGIT - Should be just FileIOException + { + throw new Exception("Unable to delete old existing "+ + "script-file before writing new. Compile aborted: " + + e.ToString()); + } + + // Do actual compile + CompilerParameters parameters = new CompilerParameters(); + + parameters.IncludeDebugInformation = true; + + string rootPath = + Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory); + + 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.GenerateExecutable = false; + parameters.OutputAssembly = OutFile; + parameters.IncludeDebugInformation = true; + parameters.WarningLevel = 1; + parameters.TreatWarningsAsErrors = false; + + CompilerResults results = CScodeProvider.CompileAssemblyFromSource(parameters, Script); + + if (results.Errors.Count > 0) + { + string errtext = String.Empty; + foreach (CompilerError CompErr in results.Errors) + { + string severity = "Error"; + if ( CompErr.IsWarning ) + { + severity = "Warning"; + } + + KeyValuePair lslPos; + + lslPos = FindErrorPosition(CompErr.Line, CompErr.Column); + + string text = CompErr.ErrorText; + + 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},{1}): {4} {2}: {3}\n", + lslPos.Key - 1, lslPos.Value - 1, + CompErr.ErrorNumber, text, severity); + } + + disp = "Completed with errors"; + + if (!File.Exists(OutFile)) + { + throw new Exception(errtext); + } + } + + if (!File.Exists(OutFile)) + { + string errtext = String.Empty; + errtext += "No compile error. But not able to locate compiled file."; + throw new Exception(errtext); + } + + // Because windows likes to perform exclusive locks, we simply + // write out a textual representation of the file here + // + // Read the binary file into a buffer + // + FileInfo fi = new FileInfo(OutFile); + + if (fi == null) + { + string errtext = String.Empty; + errtext += "No compile error. But not able to stat file."; + throw new Exception(errtext); + } + + Byte[] data = new Byte[fi.Length]; + + try + { + FileStream fs = File.Open(OutFile, FileMode.Open, FileAccess.Read); + fs.Read(data, 0, data.Length); + fs.Close(); + } + catch (Exception) + { + string errtext = String.Empty; + errtext += "No compile error. But not able to open file."; + throw new Exception(errtext); + } + + // Convert to base64 + // + string filetext = System.Convert.ToBase64String(data); + + System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); + + Byte[] buf = enc.GetBytes(filetext); + + FileStream sfs = File.Create(OutFile+".text"); + sfs.Write(buf, 0, buf.Length); + sfs.Close(); + + string posmap = String.Empty; + if (m_positionMap != null) + { + foreach (KeyValuePair, KeyValuePair> kvp in m_positionMap) + { + KeyValuePair k = kvp.Key; + KeyValuePair v = kvp.Value; + posmap += String.Format("{0},{1},{2},{3}\n", + k.Key, k.Value, v.Key, v.Value); + } + } + + buf = enc.GetBytes(posmap); + + FileStream mfs = File.Create(OutFile+".map"); + mfs.Write(buf, 0, buf.Length); + mfs.Close(); + + return disp; + } + + private static 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; + } + + private static 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); + } + } +} diff --git a/prebuild.xml b/prebuild.xml index baa54a1dd5..87925eaf66 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -3196,6 +3196,33 @@ + + + + ../../../bin/ + + + + + ../../../bin/ + + + + ../../../bin/ + + + + + + + + + + + + + +