diff options
Diffstat (limited to 'OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/LSL/Compiler.cs')
-rw-r--r-- | OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/LSL/Compiler.cs | 255 |
1 files changed, 222 insertions, 33 deletions
diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/LSL/Compiler.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/LSL/Compiler.cs index 2adc060..d3f2873 100644 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/LSL/Compiler.cs +++ b/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/LSL/Compiler.cs | |||
@@ -28,9 +28,12 @@ | |||
28 | 28 | ||
29 | using System; | 29 | using System; |
30 | using System.CodeDom.Compiler; | 30 | using System.CodeDom.Compiler; |
31 | using System.Collections.Generic; | ||
32 | using System.Globalization; | ||
31 | using System.IO; | 33 | using System.IO; |
32 | using System.Reflection; | 34 | using System.Reflection; |
33 | using Microsoft.CSharp; | 35 | using Microsoft.CSharp; |
36 | using Microsoft.VisualBasic; | ||
34 | 37 | ||
35 | namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL | 38 | namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL |
36 | { | 39 | { |
@@ -44,45 +47,192 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL | |||
44 | // Assembly is compiled using LSL_BaseClass as base. Look at debug C# code file created when LSL script is compiled for full details. | 47 | // Assembly is compiled using LSL_BaseClass as base. Look at debug C# code file created when LSL script is compiled for full details. |
45 | // | 48 | // |
46 | 49 | ||
47 | private LSL2CSConverter LSL_Converter = new LSL2CSConverter(); | 50 | internal enum enumCompileType |
48 | private CSharpCodeProvider codeProvider = new CSharpCodeProvider(); | 51 | { |
52 | lsl = 0, | ||
53 | cs = 1, | ||
54 | vb = 2 | ||
55 | } | ||
56 | private enumCompileType DefaultCompileLanguage; | ||
57 | private bool WriteScriptSourceToDebugFile; | ||
58 | private bool CompileWithDebugInformation; | ||
59 | private bool CleanUpOldScriptsOnStartup; | ||
60 | private System.Collections.Generic.Dictionary<string, Boolean> AllowedCompilers = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase); | ||
61 | private System.Collections.Generic.Dictionary<string, enumCompileType> LanguageMapping = new Dictionary<string, enumCompileType>(StringComparer.CurrentCultureIgnoreCase); | ||
62 | |||
63 | private string FilePrefix; | ||
64 | private string ScriptEnginesPath = "ScriptEngines"; | ||
65 | |||
66 | private static LSL2CSConverter LSL_Converter = new LSL2CSConverter(); | ||
67 | private static CSharpCodeProvider CScodeProvider = new CSharpCodeProvider(); | ||
68 | private static VBCodeProvider VBcodeProvider = new VBCodeProvider(); | ||
69 | |||
49 | private static UInt64 scriptCompileCounter = 0; | 70 | private static UInt64 scriptCompileCounter = 0; |
50 | 71 | ||
51 | private static int instanceID = new Random().Next(0, int.MaxValue); | 72 | private static int instanceID = new Random().Next(0, int.MaxValue); |
52 | // Implemented due to peer preassure --- will cause garbage in ScriptEngines folder ;) | 73 | // Implemented due to peer preassure --- will cause garbage in ScriptEngines folder ;) |
53 | 74 | ||
54 | //private ICodeCompiler icc = codeProvider.CreateCompiler(); | 75 | public Common.ScriptEngineBase.ScriptEngine m_scriptEngine; |
55 | public string CompileFromFile(string LSOFileName) | 76 | public Compiler(Common.ScriptEngineBase.ScriptEngine scriptEngine) |
56 | { | 77 | { |
57 | switch (Path.GetExtension(LSOFileName).ToLower()) | 78 | m_scriptEngine = scriptEngine; |
58 | { | 79 | ReadConfig(); |
59 | case ".txt": | 80 | } |
60 | case ".lsl": | 81 | public bool in_startup = true; |
61 | Common.ScriptEngineBase.Common.SendToDebug("Source code is LSL, converting to CS"); | 82 | public void ReadConfig() |
62 | return CompileFromLSLText(File.ReadAllText(LSOFileName)); | 83 | { |
63 | case ".cs": | 84 | WriteScriptSourceToDebugFile = m_scriptEngine.ScriptConfigSource.GetBoolean("WriteScriptSourceToDebugFile", true); |
64 | Common.ScriptEngineBase.Common.SendToDebug("Source code is CS"); | 85 | CompileWithDebugInformation = m_scriptEngine.ScriptConfigSource.GetBoolean("CompileWithDebugInformation", true); |
65 | return CompileFromCSText(File.ReadAllText(LSOFileName)); | 86 | CleanUpOldScriptsOnStartup = m_scriptEngine.ScriptConfigSource.GetBoolean("CleanUpOldScriptsOnStartup", true); |
66 | default: | 87 | |
67 | throw new Exception("Unknown script type."); | 88 | // Get file prefix from scriptengine name and make it file system safe: |
89 | FilePrefix = m_scriptEngine.ScriptEngineName; | ||
90 | foreach (char c in Path.GetInvalidFileNameChars()) | ||
91 | { | ||
92 | FilePrefix = FilePrefix.Replace(c, '_'); | ||
93 | } | ||
94 | // First time we start? | ||
95 | if (in_startup) | ||
96 | { | ||
97 | in_startup = false; | ||
98 | DeleteOldFiles(); | ||
99 | } | ||
100 | |||
101 | LanguageMapping.Add("cs", enumCompileType.cs); | ||
102 | LanguageMapping.Add("vb", enumCompileType.lsl); | ||
103 | LanguageMapping.Add("lsl", enumCompileType.vb); | ||
104 | |||
105 | // Allowed compilers | ||
106 | string allowedCompilers = m_scriptEngine.ScriptConfigSource.GetString("AllowedCompilers", "lsl;cs;vb"); | ||
107 | AllowedCompilers.Clear(); | ||
108 | foreach (string strl in allowedCompilers.Split(';')) | ||
109 | { | ||
110 | string strlan = strl.Trim(" \t".ToCharArray()).ToLower(); | ||
111 | if (!LanguageMapping.ContainsKey(strlan)) | ||
112 | { | ||
113 | m_scriptEngine.Log.Error(m_scriptEngine.ScriptEngineName, "Config error. Compiler is unable to recongnize language type \"" + strl + "\" specified in \"AllowedCompilers\"."); | ||
114 | } | ||
115 | AllowedCompilers.Add(strlan, true); | ||
116 | } | ||
117 | if (AllowedCompilers.Count == 0) | ||
118 | m_scriptEngine.Log.Error(m_scriptEngine.ScriptEngineName, "Config error. Compiler could not recognize any language in \"AllowedCompilers\". Scripts will not be executed!"); | ||
119 | |||
120 | // Default language | ||
121 | string defaultCompileLanguage = m_scriptEngine.ScriptConfigSource.GetString("DefaultCompileLanguage", "lsl").ToLower(); | ||
122 | |||
123 | // Is this language recognized at all? | ||
124 | if (!LanguageMapping.ContainsKey(defaultCompileLanguage)) | ||
125 | m_scriptEngine.Log.Error(m_scriptEngine.ScriptEngineName, "Config error. Default language specified in \"DefaultCompileLanguage\" is not recognized as a valid language. Scripts may not be executed!"); | ||
126 | |||
127 | // Is this language in allow-list? | ||
128 | if (!AllowedCompilers.ContainsKey(defaultCompileLanguage)) | ||
129 | { | ||
130 | m_scriptEngine.Log.Error(m_scriptEngine.ScriptEngineName, | ||
131 | "Config error. Default language \"" + defaultCompileLanguage + "\"specified in \"DefaultCompileLanguage\" is not in list of \"AllowedCompilers\". Scripts may not be executed!"); | ||
132 | } | ||
133 | else | ||
134 | { | ||
135 | // LANGUAGE IS IN ALLOW-LIST | ||
136 | DefaultCompileLanguage = LanguageMapping[defaultCompileLanguage]; | ||
137 | } | ||
138 | |||
139 | // We now have an allow-list, a mapping list, and a default language | ||
140 | |||
141 | } | ||
142 | |||
143 | private void DeleteOldFiles() | ||
144 | { | ||
145 | |||
146 | // CREATE FOLDER IF IT DOESNT EXIST | ||
147 | if (!Directory.Exists(ScriptEnginesPath)) | ||
148 | { | ||
149 | try | ||
150 | { | ||
151 | Directory.CreateDirectory(ScriptEnginesPath); | ||
152 | } | ||
153 | catch (Exception ex) | ||
154 | { | ||
155 | m_scriptEngine.Log.Error(m_scriptEngine.ScriptEngineName, "Exception trying to create ScriptEngine directory \"" + ScriptEnginesPath + "\": " + ex.ToString()); | ||
156 | } | ||
157 | } | ||
158 | |||
159 | foreach (string file in Directory.GetFiles(ScriptEnginesPath)) | ||
160 | { | ||
161 | m_scriptEngine.Log.Error(m_scriptEngine.ScriptEngineName, "FILE FOUND: " + file); | ||
162 | |||
163 | if (file.ToLower().StartsWith(FilePrefix + "_compiled_") || | ||
164 | file.ToLower().StartsWith(FilePrefix + "_source_")) | ||
165 | { | ||
166 | try | ||
167 | { | ||
168 | File.Delete(file); | ||
169 | } | ||
170 | catch (Exception ex) | ||
171 | { | ||
172 | m_scriptEngine.Log.Error(m_scriptEngine.ScriptEngineName, "Exception trying delete old script file \"" + file + "\": " + ex.ToString()); | ||
173 | } | ||
174 | |||
175 | } | ||
68 | } | 176 | } |
177 | |||
69 | } | 178 | } |
70 | 179 | ||
180 | ////private ICodeCompiler icc = codeProvider.CreateCompiler(); | ||
181 | //public string CompileFromFile(string LSOFileName) | ||
182 | //{ | ||
183 | // switch (Path.GetExtension(LSOFileName).ToLower()) | ||
184 | // { | ||
185 | // case ".txt": | ||
186 | // case ".lsl": | ||
187 | // Common.ScriptEngineBase.Common.SendToDebug("Source code is LSL, converting to CS"); | ||
188 | // return CompileFromLSLText(File.ReadAllText(LSOFileName)); | ||
189 | // case ".cs": | ||
190 | // Common.ScriptEngineBase.Common.SendToDebug("Source code is CS"); | ||
191 | // return CompileFromCSText(File.ReadAllText(LSOFileName)); | ||
192 | // default: | ||
193 | // throw new Exception("Unknown script type."); | ||
194 | // } | ||
195 | //} | ||
196 | |||
71 | /// <summary> | 197 | /// <summary> |
72 | /// Converts script from LSL to CS and calls CompileFromCSText | 198 | /// Converts script from LSL to CS and calls CompileFromCSText |
73 | /// </summary> | 199 | /// </summary> |
74 | /// <param name="Script">LSL script</param> | 200 | /// <param name="Script">LSL script</param> |
75 | /// <returns>Filename to .dll assembly</returns> | 201 | /// <returns>Filename to .dll assembly</returns> |
76 | public string CompileFromLSLText(string Script) | 202 | public string PerformScriptCompile(string Script) |
77 | { | 203 | { |
78 | if (Script.Substring(0, 4).ToLower() == "//c#") | 204 | enumCompileType l = DefaultCompileLanguage; |
205 | |||
206 | |||
207 | if (Script.StartsWith("//c#", true, CultureInfo.InvariantCulture)) | ||
208 | l = enumCompileType.cs; | ||
209 | if (Script.StartsWith("//vb", true, CultureInfo.InvariantCulture)) | ||
210 | l = enumCompileType.vb; | ||
211 | if (Script.StartsWith("//lsl", true, CultureInfo.InvariantCulture)) | ||
212 | l = enumCompileType.lsl; | ||
213 | |||
214 | if (!AllowedCompilers.ContainsKey(l.ToString())) | ||
215 | { | ||
216 | // Not allowed to compile to this language! | ||
217 | string errtext = String.Empty; | ||
218 | errtext += "The compiler for language \"" + l.ToString() + "\" is not in list of allowed compilers. Script will not be executed!"; | ||
219 | throw new Exception(errtext); | ||
220 | } | ||
221 | |||
222 | string compileScript; | ||
223 | |||
224 | if (l == enumCompileType.lsl) | ||
79 | { | 225 | { |
80 | return CompileFromCSText(Script); | 226 | // Its LSL, convert it to C# |
227 | compileScript = LSL_Converter.Convert(Script); | ||
228 | l = enumCompileType.cs; | ||
81 | } | 229 | } |
82 | else | 230 | else |
83 | { | 231 | { |
84 | return CompileFromCSText(LSL_Converter.Convert(Script)); | 232 | // We don't need to convert |
233 | compileScript = Script; | ||
85 | } | 234 | } |
235 | return CompileFromCSorVBText(Script, l); | ||
86 | } | 236 | } |
87 | 237 | ||
88 | /// <summary> | 238 | /// <summary> |
@@ -90,36 +240,45 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL | |||
90 | /// </summary> | 240 | /// </summary> |
91 | /// <param name="Script">CS script</param> | 241 | /// <param name="Script">CS script</param> |
92 | /// <returns>Filename to .dll assembly</returns> | 242 | /// <returns>Filename to .dll assembly</returns> |
93 | public string CompileFromCSText(string Script) | 243 | internal string CompileFromCSorVBText(string Script, enumCompileType lang) |
94 | { | 244 | { |
245 | string ext = "." + lang.ToString(); | ||
246 | |||
95 | // Output assembly name | 247 | // Output assembly name |
96 | scriptCompileCounter++; | 248 | scriptCompileCounter++; |
97 | string OutFile = | 249 | string OutFile = |
98 | Path.Combine("ScriptEngines", | 250 | Path.Combine("ScriptEngines", |
99 | "DotNetScript_" + instanceID.ToString() + "_" + scriptCompileCounter.ToString() + ".dll"); | 251 | FilePrefix + "_compiled_" + instanceID.ToString() + "_" + scriptCompileCounter.ToString() + ".dll"); |
100 | try | 252 | try |
101 | { | 253 | { |
102 | File.Delete(OutFile); | 254 | File.Delete(OutFile); |
103 | } | 255 | } |
104 | catch (Exception e) | 256 | catch (Exception e) |
105 | { | 257 | { |
106 | Console.WriteLine("Exception attempting to delete old compiled script: " + e.ToString()); | 258 | //m_scriptEngine.Log.Error(m_scriptEngine.ScriptEngineName, "Unable to delete old existring script-file before writing new. Compile aborted: " + e.ToString()); |
259 | throw new Exception("Unable to delete old existring script-file before writing new. Compile aborted: " + e.ToString()); | ||
107 | } | 260 | } |
108 | //string OutFile = Path.Combine("ScriptEngines", "SecondLife.Script.dll"); | 261 | //string OutFile = Path.Combine("ScriptEngines", "SecondLife.Script.dll"); |
109 | 262 | ||
110 | // DEBUG - write source to disk | 263 | // DEBUG - write source to disk |
111 | try | 264 | if (WriteScriptSourceToDebugFile) |
112 | { | ||
113 | File.WriteAllText( | ||
114 | Path.Combine("ScriptEngines", "debug_" + Path.GetFileNameWithoutExtension(OutFile) + ".cs"), Script); | ||
115 | } | ||
116 | catch | ||
117 | { | 265 | { |
266 | try | ||
267 | { | ||
268 | File.WriteAllText( | ||
269 | Path.Combine("ScriptEngines", FilePrefix + "_source_" + Path.GetFileNameWithoutExtension(OutFile) + ext), | ||
270 | Script); | ||
271 | } | ||
272 | catch | ||
273 | { | ||
274 | } | ||
118 | } | 275 | } |
119 | 276 | ||
120 | // Do actual compile | 277 | // Do actual compile |
121 | CompilerParameters parameters = new CompilerParameters(); | 278 | CompilerParameters parameters = new CompilerParameters(); |
279 | |||
122 | parameters.IncludeDebugInformation = true; | 280 | parameters.IncludeDebugInformation = true; |
281 | |||
123 | // Add all available assemblies | 282 | // Add all available assemblies |
124 | foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) | 283 | foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) |
125 | { | 284 | { |
@@ -136,11 +295,29 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL | |||
136 | //parameters.ReferencedAssemblies.Add("OpenSim.Region.Environment"); | 295 | //parameters.ReferencedAssemblies.Add("OpenSim.Region.Environment"); |
137 | parameters.GenerateExecutable = false; | 296 | parameters.GenerateExecutable = false; |
138 | parameters.OutputAssembly = OutFile; | 297 | parameters.OutputAssembly = OutFile; |
139 | parameters.IncludeDebugInformation = false; | 298 | parameters.IncludeDebugInformation = CompileWithDebugInformation; |
140 | CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters, Script); | 299 | parameters.WarningLevel = 4; |
300 | parameters.TreatWarningsAsErrors = false; | ||
141 | 301 | ||
302 | CompilerResults results; | ||
303 | switch (lang) | ||
304 | { | ||
305 | case enumCompileType.vb: | ||
306 | results = VBcodeProvider.CompileAssemblyFromSource(parameters, Script); | ||
307 | break; | ||
308 | case enumCompileType.cs: | ||
309 | results = CScodeProvider.CompileAssemblyFromSource(parameters, Script); | ||
310 | break; | ||
311 | default: | ||
312 | throw new Exception("Compiler is not able to recongnize language type \"" + lang.ToString() + "\""); | ||
313 | } | ||
314 | |||
315 | // Check result | ||
142 | // Go through errors | 316 | // Go through errors |
143 | // TODO: Return errors to user somehow | 317 | |
318 | // | ||
319 | // WARNINGS AND ERRORS | ||
320 | // | ||
144 | if (results.Errors.Count > 0) | 321 | if (results.Errors.Count > 0) |
145 | { | 322 | { |
146 | string errtext = String.Empty; | 323 | string errtext = String.Empty; |
@@ -150,10 +327,22 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL | |||
150 | ", Error Number: " + CompErr.ErrorNumber + | 327 | ", Error Number: " + CompErr.ErrorNumber + |
151 | ", '" + CompErr.ErrorText + "'\r\n"; | 328 | ", '" + CompErr.ErrorText + "'\r\n"; |
152 | } | 329 | } |
153 | throw new Exception(errtext); | 330 | if (!File.Exists(OutFile)) |
331 | { | ||
332 | throw new Exception(errtext); | ||
333 | } | ||
154 | } | 334 | } |
155 | 335 | ||
156 | 336 | ||
337 | // | ||
338 | // NO ERRORS, BUT NO COMPILED FILE | ||
339 | // | ||
340 | if (!File.Exists(OutFile)) | ||
341 | { | ||
342 | string errtext = String.Empty; | ||
343 | errtext += "No compile error. But not able to locate compiled file."; | ||
344 | throw new Exception(errtext); | ||
345 | } | ||
157 | return OutFile; | 346 | return OutFile; |
158 | } | 347 | } |
159 | } | 348 | } |