aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ScriptEngine/DotNetEngine/Compiler')
-rw-r--r--OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/LSL/Compiler.cs255
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
29using System; 29using System;
30using System.CodeDom.Compiler; 30using System.CodeDom.Compiler;
31using System.Collections.Generic;
32using System.Globalization;
31using System.IO; 33using System.IO;
32using System.Reflection; 34using System.Reflection;
33using Microsoft.CSharp; 35using Microsoft.CSharp;
36using Microsoft.VisualBasic;
34 37
35namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL 38namespace 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 }