aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/XEngine/Compiler.cs
diff options
context:
space:
mode:
authorlbsa712008-06-24 21:09:49 +0000
committerlbsa712008-06-24 21:09:49 +0000
commit6b7930104bdb845d3b9c085dc04f52b6446f23b1 (patch)
tree05ee45781a455817fa400bb99f30f4d19d4eb1f8 /OpenSim/Region/ScriptEngine/XEngine/Compiler.cs
parentbased on positive feedback on performance of making keys fixed length (diff)
downloadopensim-SC_OLD-6b7930104bdb845d3b9c085dc04f52b6446f23b1.zip
opensim-SC_OLD-6b7930104bdb845d3b9c085dc04f52b6446f23b1.tar.gz
opensim-SC_OLD-6b7930104bdb845d3b9c085dc04f52b6446f23b1.tar.bz2
opensim-SC_OLD-6b7930104bdb845d3b9c085dc04f52b6446f23b1.tar.xz
* Applied patch from Melanie, mantis issue #1581 - "Refactor LSL language, api and compiler out of XEngine"
"First stage in a major Script Engine refactor, that will result in the LSL implementaions ebing reconverged. Not there yet, but one major part is done." Thank you, Melanie!
Diffstat (limited to 'OpenSim/Region/ScriptEngine/XEngine/Compiler.cs')
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/Compiler.cs515
1 files changed, 0 insertions, 515 deletions
diff --git a/OpenSim/Region/ScriptEngine/XEngine/Compiler.cs b/OpenSim/Region/ScriptEngine/XEngine/Compiler.cs
deleted file mode 100644
index 68fb1dd..0000000
--- a/OpenSim/Region/ScriptEngine/XEngine/Compiler.cs
+++ /dev/null
@@ -1,515 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.CodeDom.Compiler;
30using System.Collections.Generic;
31using System.Globalization;
32using System.IO;
33using Microsoft.CSharp;
34using Microsoft.JScript;
35using Microsoft.VisualBasic;
36using OpenSim.Region.Environment.Interfaces;
37
38namespace OpenSim.Region.ScriptEngine.XEngine
39{
40 public class Compiler
41 {
42 private static readonly log4net.ILog m_log
43 = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
44
45 // * Uses "LSL2Converter" to convert LSL to C# if necessary.
46 // * Compiles C#-code into an assembly
47 // * Returns assembly name ready for AppDomain load.
48 //
49 // Assembly is compiled using LSL_BaseClass as base. Look at debug C# code file created when LSL script is compiled for full details.
50 //
51
52 internal enum enumCompileType
53 {
54 lsl = 0,
55 cs = 1,
56 vb = 2,
57 js = 3
58 }
59
60 /// <summary>
61 /// This contains number of lines WE use for header when compiling script. User will get error in line x-LinesToRemoveOnError when error occurs.
62 /// </summary>
63 public int LinesToRemoveOnError = 3;
64 private enumCompileType DefaultCompileLanguage;
65 private bool WriteScriptSourceToDebugFile;
66 private bool CompileWithDebugInformation;
67 private Dictionary<string, bool> AllowedCompilers = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase);
68 private Dictionary<string, enumCompileType> LanguageMapping = new Dictionary<string, enumCompileType>(StringComparer.CurrentCultureIgnoreCase);
69
70 private string FilePrefix;
71 private string ScriptEnginesPath = "ScriptEngines";
72
73 private static LSL2CSConverter LSL_Converter = new LSL2CSConverter();
74 private static CSharpCodeProvider CScodeProvider = new CSharpCodeProvider();
75 private static VBCodeProvider VBcodeProvider = new VBCodeProvider();
76 private static JScriptCodeProvider JScodeProvider = new JScriptCodeProvider();
77
78 private static int instanceID = new Random().Next(0, int.MaxValue); // Unique number to use on our compiled files
79 private static UInt64 scriptCompileCounter = 0; // And a counter
80
81 public XEngine m_scriptEngine;
82 public Compiler(XEngine scriptEngine)
83 {
84 m_scriptEngine = scriptEngine;
85 ReadConfig();
86 }
87 public bool in_startup = true;
88 public void ReadConfig()
89 {
90
91 // Get some config
92 WriteScriptSourceToDebugFile = m_scriptEngine.ScriptConfigSource.GetBoolean("WriteScriptSourceToDebugFile", true);
93 CompileWithDebugInformation = m_scriptEngine.ScriptConfigSource.GetBoolean("CompileWithDebugInformation", true);
94
95 // Get file prefix from scriptengine name and make it file system safe:
96 FilePrefix = m_scriptEngine.ScriptEngineName;
97 foreach (char c in Path.GetInvalidFileNameChars())
98 {
99 FilePrefix = FilePrefix.Replace(c, '_');
100 }
101
102 // First time we start? Delete old files
103 if (in_startup)
104 {
105 in_startup = false;
106 DeleteOldFiles();
107 }
108
109 // Map name and enum type of our supported languages
110 LanguageMapping.Add(enumCompileType.cs.ToString(), enumCompileType.cs);
111 LanguageMapping.Add(enumCompileType.vb.ToString(), enumCompileType.vb);
112 LanguageMapping.Add(enumCompileType.lsl.ToString(), enumCompileType.lsl);
113 LanguageMapping.Add(enumCompileType.js.ToString(), enumCompileType.js);
114
115 // Allowed compilers
116 string allowComp = m_scriptEngine.ScriptConfigSource.GetString("AllowedCompilers", "lsl,cs,vb,js");
117 AllowedCompilers.Clear();
118
119#if DEBUG
120 m_scriptEngine.Log.Debug("[" + m_scriptEngine.ScriptEngineName + "]: Allowed languages: " + allowComp);
121#endif
122
123
124 foreach (string strl in allowComp.Split(','))
125 {
126 string strlan = strl.Trim(" \t".ToCharArray()).ToLower();
127 if (!LanguageMapping.ContainsKey(strlan))
128 {
129 m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Config error. Compiler is unable to recognize language type \"" + strlan + "\" specified in \"AllowedCompilers\".");
130 }
131 else
132 {
133#if DEBUG
134 //m_scriptEngine.Log.Debug("[" + m_scriptEngine.ScriptEngineName + "]: Config OK. Compiler recognized language type \"" + strlan + "\" specified in \"AllowedCompilers\".");
135#endif
136 }
137 AllowedCompilers.Add(strlan, true);
138 }
139 if (AllowedCompilers.Count == 0)
140 m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Config error. Compiler could not recognize any language in \"AllowedCompilers\". Scripts will not be executed!");
141
142 // Default language
143 string defaultCompileLanguage = m_scriptEngine.ScriptConfigSource.GetString("DefaultCompileLanguage", "lsl").ToLower();
144
145 // Is this language recognized at all?
146 if (!LanguageMapping.ContainsKey(defaultCompileLanguage))
147 {
148 m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: " +
149 "Config error. Default language \"" + defaultCompileLanguage + "\" specified in \"DefaultCompileLanguage\" is not recognized as a valid language. Changing default to: \"lsl\".");
150 defaultCompileLanguage = "lsl";
151 }
152
153 // Is this language in allow-list?
154 if (!AllowedCompilers.ContainsKey(defaultCompileLanguage))
155 {
156 m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: " +
157 "Config error. Default language \"" + defaultCompileLanguage + "\"specified in \"DefaultCompileLanguage\" is not in list of \"AllowedCompilers\". Scripts may not be executed!");
158 }
159 else
160 {
161#if DEBUG
162// m_scriptEngine.Log.Debug("[" + m_scriptEngine.ScriptEngineName + "]: " +
163// "Config OK. Default language \"" + defaultCompileLanguage + "\" specified in \"DefaultCompileLanguage\" is recognized as a valid language.");
164#endif
165 // LANGUAGE IS IN ALLOW-LIST
166 DefaultCompileLanguage = LanguageMapping[defaultCompileLanguage];
167 }
168
169 // We now have an allow-list, a mapping list, and a default language
170
171 }
172
173 /// <summary>
174 /// Delete old script files
175 /// </summary>
176 private void DeleteOldFiles()
177 {
178
179 // CREATE FOLDER IF IT DOESNT EXIST
180 if (!Directory.Exists(ScriptEnginesPath))
181 {
182 try
183 {
184 Directory.CreateDirectory(ScriptEnginesPath);
185 }
186 catch (Exception ex)
187 {
188 m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Exception trying to create ScriptEngine directory \"" + ScriptEnginesPath + "\": " + ex.ToString());
189 }
190 }
191
192 if (!Directory.Exists(Path.Combine(ScriptEnginesPath,
193 m_scriptEngine.World.RegionInfo.RegionID.ToString())))
194 {
195 try
196 {
197 Directory.CreateDirectory(Path.Combine(ScriptEnginesPath,
198 m_scriptEngine.World.RegionInfo.RegionID.ToString()));
199 }
200 catch (Exception ex)
201 {
202 m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Exception trying to create ScriptEngine directory \"" + Path.Combine(ScriptEnginesPath,
203 m_scriptEngine.World.RegionInfo.RegionID.ToString())+ "\": " + ex.ToString());
204 }
205 }
206
207 foreach (string file in Directory.GetFiles(Path.Combine(ScriptEnginesPath,
208 m_scriptEngine.World.RegionInfo.RegionID.ToString())))
209 {
210 //m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: FILE FOUND: " + file);
211
212 if (file.ToLower().StartsWith(FilePrefix + "_compiled_") ||
213 file.ToLower().StartsWith(FilePrefix + "_source_"))
214 {
215 try
216 {
217 File.Delete(file);
218 }
219 catch (Exception ex)
220 {
221 m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Exception trying delete old script file \"" + file + "\": " + ex.ToString());
222 }
223
224 }
225 }
226
227 }
228
229 ////private ICodeCompiler icc = codeProvider.CreateCompiler();
230 //public string CompileFromFile(string LSOFileName)
231 //{
232 // switch (Path.GetExtension(LSOFileName).ToLower())
233 // {
234 // case ".txt":
235 // case ".lsl":
236 // Common.ScriptEngineBase.Common.SendToDebug("Source code is LSL, converting to CS");
237 // return CompileFromLSLText(File.ReadAllText(LSOFileName));
238 // case ".cs":
239 // Common.ScriptEngineBase.Common.SendToDebug("Source code is CS");
240 // return CompileFromCSText(File.ReadAllText(LSOFileName));
241 // default:
242 // throw new Exception("Unknown script type.");
243 // }
244 //}
245
246 /// <summary>
247 /// Converts script from LSL to CS and calls CompileFromCSText
248 /// </summary>
249 /// <param name="Script">LSL script</param>
250 /// <returns>Filename to .dll assembly</returns>
251 public string PerformScriptCompile(string Script, string asset)
252 {
253 string OutFile = Path.Combine(ScriptEnginesPath, Path.Combine(
254 m_scriptEngine.World.RegionInfo.RegionID.ToString(),
255 FilePrefix + "_compiled_" + asset + ".dll"));
256// string OutFile = Path.Combine(ScriptEnginesPath,
257// FilePrefix + "_compiled_" + asset + ".dll");
258
259 if (File.Exists(OutFile))
260 {
261 m_scriptEngine.Log.DebugFormat("[XEngine] Returning existing assembly for {0}", asset);
262 return OutFile;
263 }
264
265 if (!Directory.Exists(ScriptEnginesPath))
266 {
267 try
268 {
269 Directory.CreateDirectory(ScriptEnginesPath);
270 }
271 catch (Exception ex)
272 {
273 }
274 }
275
276 if (!Directory.Exists(Path.Combine(ScriptEnginesPath,
277 m_scriptEngine.World.RegionInfo.RegionID.ToString())))
278 {
279 try
280 {
281 Directory.CreateDirectory(ScriptEnginesPath);
282 }
283 catch (Exception ex)
284 {
285 }
286 }
287
288 enumCompileType l = DefaultCompileLanguage;
289
290 if (Script.StartsWith("//c#", true, CultureInfo.InvariantCulture))
291 l = enumCompileType.cs;
292 if (Script.StartsWith("//vb", true, CultureInfo.InvariantCulture))
293 {
294 l = enumCompileType.vb;
295 // We need to remove //vb, it won't compile with that
296
297 Script = Script.Substring(4, Script.Length - 4);
298 }
299 if (Script.StartsWith("//lsl", true, CultureInfo.InvariantCulture))
300 l = enumCompileType.lsl;
301
302 if (Script.StartsWith("//js", true, CultureInfo.InvariantCulture))
303 l = enumCompileType.js;
304
305 if (!AllowedCompilers.ContainsKey(l.ToString()))
306 {
307 // Not allowed to compile to this language!
308 string errtext = String.Empty;
309 errtext += "The compiler for language \"" + l.ToString() + "\" is not in list of allowed compilers. Script will not be executed!";
310 throw new Exception(errtext);
311 }
312
313 string compileScript = Script;
314
315 if (l == enumCompileType.lsl)
316 {
317 // Its LSL, convert it to C#
318 compileScript = LSL_Converter.Convert(Script);
319 l = enumCompileType.cs;
320 }
321
322 // Insert additional assemblies here
323
324 //ADAM: Disabled for the moment until it's working right.
325 bool enableCommanderLSL = false;
326
327 if (enableCommanderLSL == true && l == enumCompileType.cs)
328 {
329 foreach (KeyValuePair<string,
330 ICommander> com
331 in m_scriptEngine.World.GetCommanders())
332 {
333 compileScript = com.Value.GenerateRuntimeAPI() + compileScript;
334 }
335 }
336
337 // End of insert
338
339 switch (l)
340 {
341 case enumCompileType.cs:
342 compileScript = CreateCSCompilerScript(compileScript);
343 break;
344 case enumCompileType.vb:
345 compileScript = CreateVBCompilerScript(compileScript);
346 break;
347 case enumCompileType.js:
348 compileScript = CreateJSCompilerScript(compileScript);
349 break;
350 }
351
352// m_log.Debug("[ScriptEngine.DotNetEngine]: Preparing to compile the following LSL to C# translated code");
353// m_log.Debug("");
354// m_log.Debug(compileScript);
355
356 return CompileFromDotNetText(compileScript, l, asset);
357 }
358
359 private static string CreateJSCompilerScript(string compileScript)
360 {
361 compileScript = String.Empty +
362 "import OpenSim.Region.ScriptEngine.XEngine.Script; import System.Collections.Generic;\r\n" +
363 "package SecondLife {\r\n" +
364 "class Script extends OpenSim.Region.ScriptEngine.XEngine.Script.BuiltIn_Commands_BaseClass { \r\n" +
365 compileScript +
366 "} }\r\n";
367 return compileScript;
368 }
369
370 private static string CreateCSCompilerScript(string compileScript)
371 {
372 compileScript = String.Empty +
373 "using OpenSim.Region.ScriptEngine.XEngine.Script; using System.Collections.Generic;\r\n" +
374 String.Empty + "namespace SecondLife { " +
375 String.Empty + "public class Script : OpenSim.Region.ScriptEngine.XEngine.Script.BuiltIn_Commands_BaseClass { \r\n" +
376 @"public Script() { } " +
377 compileScript +
378 "} }\r\n";
379 return compileScript;
380 }
381
382 private static string CreateVBCompilerScript(string compileScript)
383 {
384 compileScript = String.Empty +
385 "Imports OpenSim.Region.ScriptEngine.XEngine.Script: Imports System.Collections.Generic: " +
386 String.Empty + "NameSpace SecondLife:" +
387 String.Empty + "Public Class Script: Inherits OpenSim.Region.ScriptEngine.XEngine.Script.BuiltIn_Commands_BaseClass: " +
388 "\r\nPublic Sub New()\r\nEnd Sub: " +
389 compileScript +
390 ":End Class :End Namespace\r\n";
391 return compileScript;
392 }
393
394 /// <summary>
395 /// Compile .NET script to .Net assembly (.dll)
396 /// </summary>
397 /// <param name="Script">CS script</param>
398 /// <returns>Filename to .dll assembly</returns>
399 internal string CompileFromDotNetText(string Script, enumCompileType lang, string asset)
400 {
401 string ext = "." + lang.ToString();
402
403 // Output assembly name
404 scriptCompileCounter++;
405 string OutFile = Path.Combine(ScriptEnginesPath, Path.Combine(
406 m_scriptEngine.World.RegionInfo.RegionID.ToString(),
407 FilePrefix + "_compiled_" + asset + ".dll"));
408#if DEBUG
409// m_scriptEngine.Log.Debug("[" + m_scriptEngine.ScriptEngineName + "]: Starting compile of \"" + OutFile + "\".");
410#endif
411 try
412 {
413 File.Delete(OutFile);
414 }
415 catch (Exception e) // NOTLEGIT - Should be just catching FileIOException
416 {
417 //m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Unable to delete old existring script-file before writing new. Compile aborted: " + e.ToString());
418 throw new Exception("Unable to delete old existring script-file before writing new. Compile aborted: " + e.ToString());
419 }
420 //string OutFile = Path.Combine("ScriptEngines", "SecondLife.Script.dll");
421
422 // DEBUG - write source to disk
423 if (WriteScriptSourceToDebugFile)
424 {
425 string srcFileName = FilePrefix + "_source_" + Path.GetFileNameWithoutExtension(OutFile) + ext;
426 try
427 {
428 File.WriteAllText(Path.Combine(Path.Combine(
429 ScriptEnginesPath,
430 m_scriptEngine.World.RegionInfo.RegionID.ToString()),
431 srcFileName), Script);
432 }
433 catch (Exception ex) // NOTLEGIT - Should be just catching FileIOException
434 {
435 m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Exception while trying to write script source to file \"" + srcFileName + "\": " + ex.ToString());
436 }
437 }
438
439 // Do actual compile
440 CompilerParameters parameters = new CompilerParameters();
441
442 parameters.IncludeDebugInformation = true;
443
444 // Add all available assemblies
445// foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
446// {
447// Console.WriteLine("Adding assembly: " + asm.Location);
448// parameters.ReferencedAssemblies.Add(asm.Location);
449// }
450
451 string rootPath = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory);
452 string rootPathSE = Path.GetDirectoryName(GetType().Assembly.Location);
453 //Console.WriteLine("Assembly location: " + rootPath);
454 parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, "OpenSim.Region.ScriptEngine.XEngine.Script.dll"));
455// parameters.ReferencedAssemblies.Add(Path.Combine(rootPathSE, "OpenSim.Region.ScriptEngine.XEngine.dll"));
456
457 //parameters.ReferencedAssemblies.Add("OpenSim.Region.Environment");
458 parameters.GenerateExecutable = false;
459 parameters.OutputAssembly = OutFile;
460 parameters.IncludeDebugInformation = CompileWithDebugInformation;
461 //parameters.WarningLevel = 1; // Should be 4?
462 parameters.TreatWarningsAsErrors = false;
463
464//Console.WriteLine(Script);
465 CompilerResults results;
466 switch (lang)
467 {
468 case enumCompileType.vb:
469 results = VBcodeProvider.CompileAssemblyFromSource(parameters, Script);
470 break;
471 case enumCompileType.cs:
472 results = CScodeProvider.CompileAssemblyFromSource(parameters, Script);
473 break;
474 case enumCompileType.js:
475 results = JScodeProvider.CompileAssemblyFromSource(parameters, Script);
476 break;
477 default:
478 throw new Exception("Compiler is not able to recongnize language type \"" + lang.ToString() + "\"");
479 }
480
481 // Check result
482 // Go through errors
483
484 //
485 // WARNINGS AND ERRORS
486 //
487 if (results.Errors.Count > 0)
488 {
489 string errtext = String.Empty;
490 foreach (CompilerError CompErr in results.Errors)
491 {
492 errtext += "Line number " + (CompErr.Line - LinesToRemoveOnError) +
493 ", Error Number: " + CompErr.ErrorNumber +
494 ", '" + CompErr.ErrorText + "'\r\n";
495 }
496 if (!File.Exists(OutFile))
497 {
498 throw new Exception(errtext);
499 }
500 }
501
502 //
503 // NO ERRORS, BUT NO COMPILED FILE
504 //
505 if (!File.Exists(OutFile))
506 {
507 string errtext = String.Empty;
508 errtext += "No compile error. But not able to locate compiled file.";
509 throw new Exception(errtext);
510 }
511 m_scriptEngine.Log.DebugFormat("[XEngine] Compiled new assembly for {0}", asset);
512 return OutFile;
513 }
514 }
515}