aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/XEngine/Compiler.cs
diff options
context:
space:
mode:
authorTeravus Ovares2008-05-30 12:27:06 +0000
committerTeravus Ovares2008-05-30 12:27:06 +0000
commit1a47ff8094ee414a47aebd310826906d89428a09 (patch)
tree0e90b3a33f43ff8617a077bb57b86d6b28e63e71 /OpenSim/Region/ScriptEngine/XEngine/Compiler.cs
parent* Fixed a dangling event hook that I added. (diff)
downloadopensim-SC-1a47ff8094ee414a47aebd310826906d89428a09.zip
opensim-SC-1a47ff8094ee414a47aebd310826906d89428a09.tar.gz
opensim-SC-1a47ff8094ee414a47aebd310826906d89428a09.tar.bz2
opensim-SC-1a47ff8094ee414a47aebd310826906d89428a09.tar.xz
* This is Melanie's XEngine script engine. I've not tested this real well, however, it's confirmed to compile and OpenSimulator to run successfully without this script engine active.
Diffstat (limited to 'OpenSim/Region/ScriptEngine/XEngine/Compiler.cs')
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/Compiler.cs515
1 files changed, 515 insertions, 0 deletions
diff --git a/OpenSim/Region/ScriptEngine/XEngine/Compiler.cs b/OpenSim/Region/ScriptEngine/XEngine/Compiler.cs
new file mode 100644
index 0000000..980d9e6
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/XEngine/Compiler.cs
@@ -0,0 +1,515 @@
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 return OutFile;
261
262 if (!Directory.Exists(ScriptEnginesPath))
263 {
264 try
265 {
266 Directory.CreateDirectory(ScriptEnginesPath);
267 }
268 catch (Exception ex)
269 {
270 }
271 }
272
273 if (!Directory.Exists(Path.Combine(ScriptEnginesPath,
274 m_scriptEngine.World.RegionInfo.RegionID.ToString())))
275 {
276 try
277 {
278 Directory.CreateDirectory(ScriptEnginesPath);
279 }
280 catch (Exception ex)
281 {
282 }
283 }
284
285 enumCompileType l = DefaultCompileLanguage;
286
287
288 if (Script.StartsWith("//c#", true, CultureInfo.InvariantCulture))
289 l = enumCompileType.cs;
290 if (Script.StartsWith("//vb", true, CultureInfo.InvariantCulture))
291 {
292 l = enumCompileType.vb;
293 // We need to remove //vb, it won't compile with that
294
295 Script = Script.Substring(4, Script.Length - 4);
296 }
297 if (Script.StartsWith("//lsl", true, CultureInfo.InvariantCulture))
298 l = enumCompileType.lsl;
299
300 if (Script.StartsWith("//js", true, CultureInfo.InvariantCulture))
301 l = enumCompileType.js;
302
303 if (!AllowedCompilers.ContainsKey(l.ToString()))
304 {
305 // Not allowed to compile to this language!
306 string errtext = String.Empty;
307 errtext += "The compiler for language \"" + l.ToString() + "\" is not in list of allowed compilers. Script will not be executed!";
308 throw new Exception(errtext);
309 }
310
311 string compileScript = Script;
312
313 if (l == enumCompileType.lsl)
314 {
315 // Its LSL, convert it to C#
316 compileScript = LSL_Converter.Convert(Script);
317 l = enumCompileType.cs;
318 }
319
320 // Insert additional assemblies here
321
322 //ADAM: Disabled for the moment until it's working right.
323 bool enableCommanderLSL = false;
324
325 if (enableCommanderLSL == true && l == enumCompileType.cs)
326 {
327 foreach (KeyValuePair<string,
328 ICommander> com
329 in m_scriptEngine.World.GetCommanders())
330 {
331 compileScript = com.Value.GenerateRuntimeAPI() + compileScript;
332 }
333 }
334
335 // End of insert
336
337
338 switch (l)
339 {
340 case enumCompileType.cs:
341 compileScript = CreateCSCompilerScript(compileScript);
342 break;
343 case enumCompileType.vb:
344 compileScript = CreateVBCompilerScript(compileScript);
345 break;
346 case enumCompileType.js:
347 compileScript = CreateJSCompilerScript(compileScript);
348 break;
349 }
350
351// m_log.Debug("[ScriptEngine.DotNetEngine]: Preparing to compile the following LSL to C# translated code");
352// m_log.Debug("");
353// m_log.Debug(compileScript);
354
355 return CompileFromDotNetText(compileScript, l, asset);
356 }
357
358 private static string CreateJSCompilerScript(string compileScript)
359 {
360 compileScript = String.Empty +
361 "import OpenSim.Region.ScriptEngine.XEngine.Script; import System.Collections.Generic;\r\n" +
362 "package SecondLife {\r\n" +
363 "class Script extends OpenSim.Region.ScriptEngine.XEngine.Script.BuiltIn_Commands_BaseClass { \r\n" +
364 compileScript +
365 "} }\r\n";
366 return compileScript;
367 }
368
369 private static string CreateCSCompilerScript(string compileScript)
370 {
371
372
373 compileScript = String.Empty +
374 "using OpenSim.Region.ScriptEngine.XEngine.Script; using System.Collections.Generic;\r\n" +
375 String.Empty + "namespace SecondLife { " +
376 String.Empty + "public class Script : OpenSim.Region.ScriptEngine.XEngine.Script.BuiltIn_Commands_BaseClass { \r\n" +
377 @"public Script() { } " +
378 compileScript +
379 "} }\r\n";
380 return compileScript;
381 }
382
383 private static string CreateVBCompilerScript(string compileScript)
384 {
385 compileScript = String.Empty +
386 "Imports OpenSim.Region.ScriptEngine.XEngine.Script: Imports System.Collections.Generic: " +
387 String.Empty + "NameSpace SecondLife:" +
388 String.Empty + "Public Class Script: Inherits OpenSim.Region.ScriptEngine.XEngine.Script.BuiltIn_Commands_BaseClass: " +
389 "\r\nPublic Sub New()\r\nEnd Sub: " +
390 compileScript +
391 ":End Class :End Namespace\r\n";
392 return compileScript;
393 }
394
395 /// <summary>
396 /// Compile .NET script to .Net assembly (.dll)
397 /// </summary>
398 /// <param name="Script">CS script</param>
399 /// <returns>Filename to .dll assembly</returns>
400 internal string CompileFromDotNetText(string Script, enumCompileType lang, string asset)
401 {
402 string ext = "." + lang.ToString();
403
404 // Output assembly name
405 scriptCompileCounter++;
406 string OutFile = Path.Combine(ScriptEnginesPath, Path.Combine(
407 m_scriptEngine.World.RegionInfo.RegionID.ToString(),
408 FilePrefix + "_compiled_" + asset + ".dll"));
409#if DEBUG
410// m_scriptEngine.Log.Debug("[" + m_scriptEngine.ScriptEngineName + "]: Starting compile of \"" + OutFile + "\".");
411#endif
412 try
413 {
414 File.Delete(OutFile);
415 }
416 catch (Exception e) // NOTLEGIT - Should be just catching FileIOException
417 {
418 //m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Unable to delete old existring script-file before writing new. Compile aborted: " + e.ToString());
419 throw new Exception("Unable to delete old existring script-file before writing new. Compile aborted: " + e.ToString());
420 }
421 //string OutFile = Path.Combine("ScriptEngines", "SecondLife.Script.dll");
422
423 // DEBUG - write source to disk
424 if (WriteScriptSourceToDebugFile)
425 {
426 string srcFileName = FilePrefix + "_source_" + Path.GetFileNameWithoutExtension(OutFile) + ext;
427 try
428 {
429 File.WriteAllText(
430 Path.Combine("ScriptEngines", srcFileName),
431 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 //
504 // NO ERRORS, BUT NO COMPILED FILE
505 //
506 if (!File.Exists(OutFile))
507 {
508 string errtext = String.Empty;
509 errtext += "No compile error. But not able to locate compiled file.";
510 throw new Exception(errtext);
511 }
512 return OutFile;
513 }
514 }
515}