diff options
author | Alan M Webb | 2009-09-16 10:00:00 -0400 |
---|---|---|
committer | dr scofield (aka dirk husemann) | 2009-09-16 16:43:51 +0200 |
commit | d4c98ddffc7b6ac25cd08f57f9f67a33bff91683 (patch) | |
tree | d30710d0b87a035fea6cef4a1f79007643f0801d /OpenSim/Tools | |
parent | This fixes a boundary case error in the strided list (diff) | |
download | opensim-SC-d4c98ddffc7b6ac25cd08f57f9f67a33bff91683.zip opensim-SC-d4c98ddffc7b6ac25cd08f57f9f67a33bff91683.tar.gz opensim-SC-d4c98ddffc7b6ac25cd08f57f9f67a33bff91683.tar.bz2 opensim-SC-d4c98ddffc7b6ac25cd08f57f9f67a33bff91683.tar.xz |
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) <drscofield@xyzzyxyzzy.net>
Diffstat (limited to 'OpenSim/Tools')
-rw-r--r-- | OpenSim/Tools/Compiler/Program.cs | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/OpenSim/Tools/Compiler/Program.cs b/OpenSim/Tools/Compiler/Program.cs new file mode 100644 index 0000000..0141f48 --- /dev/null +++ b/OpenSim/Tools/Compiler/Program.cs | |||
@@ -0,0 +1,287 @@ | |||
1 | |||
2 | using System; | ||
3 | using System.Collections.Generic; | ||
4 | using System.IO; | ||
5 | using Microsoft.CSharp; | ||
6 | using OpenSim.Region.ScriptEngine.Shared.CodeTools; | ||
7 | using System.CodeDom.Compiler; | ||
8 | |||
9 | namespace OpenSim.Tools.LSL.Compiler | ||
10 | { | ||
11 | class Program | ||
12 | { | ||
13 | private static Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> m_positionMap; | ||
14 | private static CSharpCodeProvider CScodeProvider = new CSharpCodeProvider(); | ||
15 | |||
16 | static void Main(string[] args) | ||
17 | { | ||
18 | string source = null; | ||
19 | |||
20 | if(args.Length == 0) | ||
21 | { | ||
22 | Console.WriteLine("No input file specified"); | ||
23 | Environment.Exit(1); | ||
24 | } | ||
25 | |||
26 | if(!File.Exists(args[0])) | ||
27 | { | ||
28 | Console.WriteLine("Input file does not exist"); | ||
29 | Environment.Exit(1); | ||
30 | } | ||
31 | |||
32 | try | ||
33 | { | ||
34 | ICodeConverter cvt = (ICodeConverter) new CSCodeGenerator(); | ||
35 | source = cvt.Convert(File.ReadAllText(args[0])); | ||
36 | } | ||
37 | catch(Exception e) | ||
38 | { | ||
39 | Console.WriteLine("Conversion failed:\n"+e.Message); | ||
40 | Environment.Exit(1); | ||
41 | } | ||
42 | |||
43 | source = CreateCSCompilerScript(source); | ||
44 | |||
45 | try | ||
46 | { | ||
47 | Console.WriteLine(CompileFromDotNetText(source,"a.out")); | ||
48 | } | ||
49 | catch(Exception e) | ||
50 | { | ||
51 | Console.WriteLine("Conversion failed: "+e.Message); | ||
52 | Environment.Exit(1); | ||
53 | } | ||
54 | |||
55 | Environment.Exit(0); | ||
56 | } | ||
57 | |||
58 | private static string CreateCSCompilerScript(string compileScript) | ||
59 | { | ||
60 | compileScript = String.Empty + | ||
61 | "using OpenSim.Region.ScriptEngine.Shared; using System.Collections.Generic;\r\n" + | ||
62 | String.Empty + "namespace SecondLife { " + | ||
63 | String.Empty + "public class Script : OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass { \r\n" + | ||
64 | @"public Script() { } " + | ||
65 | compileScript + | ||
66 | "} }\r\n"; | ||
67 | return compileScript; | ||
68 | } | ||
69 | |||
70 | private static string CompileFromDotNetText(string Script, string asset) | ||
71 | { | ||
72 | |||
73 | string OutFile = asset; | ||
74 | string disp ="OK"; | ||
75 | |||
76 | try | ||
77 | { | ||
78 | File.Delete(OutFile); | ||
79 | } | ||
80 | catch (Exception e) // NOTLEGIT - Should be just FileIOException | ||
81 | { | ||
82 | throw new Exception("Unable to delete old existing "+ | ||
83 | "script-file before writing new. Compile aborted: " + | ||
84 | e.ToString()); | ||
85 | } | ||
86 | |||
87 | // Do actual compile | ||
88 | CompilerParameters parameters = new CompilerParameters(); | ||
89 | |||
90 | parameters.IncludeDebugInformation = true; | ||
91 | |||
92 | string rootPath = | ||
93 | Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory); | ||
94 | |||
95 | parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, | ||
96 | "OpenSim.Region.ScriptEngine.Shared.dll")); | ||
97 | parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, | ||
98 | "OpenSim.Region.ScriptEngine.Shared.Api.Runtime.dll")); | ||
99 | |||
100 | parameters.GenerateExecutable = false; | ||
101 | parameters.OutputAssembly = OutFile; | ||
102 | parameters.IncludeDebugInformation = true; | ||
103 | parameters.WarningLevel = 1; | ||
104 | parameters.TreatWarningsAsErrors = false; | ||
105 | |||
106 | CompilerResults results = CScodeProvider.CompileAssemblyFromSource(parameters, Script); | ||
107 | |||
108 | if (results.Errors.Count > 0) | ||
109 | { | ||
110 | string errtext = String.Empty; | ||
111 | foreach (CompilerError CompErr in results.Errors) | ||
112 | { | ||
113 | string severity = "Error"; | ||
114 | if ( CompErr.IsWarning ) | ||
115 | { | ||
116 | severity = "Warning"; | ||
117 | } | ||
118 | |||
119 | KeyValuePair<int, int> lslPos; | ||
120 | |||
121 | lslPos = FindErrorPosition(CompErr.Line, CompErr.Column); | ||
122 | |||
123 | string text = CompErr.ErrorText; | ||
124 | |||
125 | text = ReplaceTypes(CompErr.ErrorText); | ||
126 | |||
127 | // The Second Life viewer's script editor begins | ||
128 | // countingn lines and columns at 0, so we subtract 1. | ||
129 | errtext += String.Format("Line ({0},{1}): {4} {2}: {3}\n", | ||
130 | lslPos.Key - 1, lslPos.Value - 1, | ||
131 | CompErr.ErrorNumber, text, severity); | ||
132 | } | ||
133 | |||
134 | disp = "Completed with errors"; | ||
135 | |||
136 | if (!File.Exists(OutFile)) | ||
137 | { | ||
138 | throw new Exception(errtext); | ||
139 | } | ||
140 | } | ||
141 | |||
142 | if (!File.Exists(OutFile)) | ||
143 | { | ||
144 | string errtext = String.Empty; | ||
145 | errtext += "No compile error. But not able to locate compiled file."; | ||
146 | throw new Exception(errtext); | ||
147 | } | ||
148 | |||
149 | // Because windows likes to perform exclusive locks, we simply | ||
150 | // write out a textual representation of the file here | ||
151 | // | ||
152 | // Read the binary file into a buffer | ||
153 | // | ||
154 | FileInfo fi = new FileInfo(OutFile); | ||
155 | |||
156 | if (fi == null) | ||
157 | { | ||
158 | string errtext = String.Empty; | ||
159 | errtext += "No compile error. But not able to stat file."; | ||
160 | throw new Exception(errtext); | ||
161 | } | ||
162 | |||
163 | Byte[] data = new Byte[fi.Length]; | ||
164 | |||
165 | try | ||
166 | { | ||
167 | FileStream fs = File.Open(OutFile, FileMode.Open, FileAccess.Read); | ||
168 | fs.Read(data, 0, data.Length); | ||
169 | fs.Close(); | ||
170 | } | ||
171 | catch (Exception) | ||
172 | { | ||
173 | string errtext = String.Empty; | ||
174 | errtext += "No compile error. But not able to open file."; | ||
175 | throw new Exception(errtext); | ||
176 | } | ||
177 | |||
178 | // Convert to base64 | ||
179 | // | ||
180 | string filetext = System.Convert.ToBase64String(data); | ||
181 | |||
182 | System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); | ||
183 | |||
184 | Byte[] buf = enc.GetBytes(filetext); | ||
185 | |||
186 | FileStream sfs = File.Create(OutFile+".text"); | ||
187 | sfs.Write(buf, 0, buf.Length); | ||
188 | sfs.Close(); | ||
189 | |||
190 | string posmap = String.Empty; | ||
191 | if (m_positionMap != null) | ||
192 | { | ||
193 | foreach (KeyValuePair<KeyValuePair<int, int>, KeyValuePair<int, int>> kvp in m_positionMap) | ||
194 | { | ||
195 | KeyValuePair<int, int> k = kvp.Key; | ||
196 | KeyValuePair<int, int> v = kvp.Value; | ||
197 | posmap += String.Format("{0},{1},{2},{3}\n", | ||
198 | k.Key, k.Value, v.Key, v.Value); | ||
199 | } | ||
200 | } | ||
201 | |||
202 | buf = enc.GetBytes(posmap); | ||
203 | |||
204 | FileStream mfs = File.Create(OutFile+".map"); | ||
205 | mfs.Write(buf, 0, buf.Length); | ||
206 | mfs.Close(); | ||
207 | |||
208 | return disp; | ||
209 | } | ||
210 | |||
211 | private static string ReplaceTypes(string message) | ||
212 | { | ||
213 | message = message.Replace( | ||
214 | "OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString", | ||
215 | "string"); | ||
216 | |||
217 | message = message.Replace( | ||
218 | "OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger", | ||
219 | "integer"); | ||
220 | |||
221 | message = message.Replace( | ||
222 | "OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat", | ||
223 | "float"); | ||
224 | |||
225 | message = message.Replace( | ||
226 | "OpenSim.Region.ScriptEngine.Shared.LSL_Types.list", | ||
227 | "list"); | ||
228 | |||
229 | return message; | ||
230 | } | ||
231 | |||
232 | private static KeyValuePair<int, int> FindErrorPosition(int line, int col) | ||
233 | { | ||
234 | return FindErrorPosition(line, col, m_positionMap); | ||
235 | } | ||
236 | |||
237 | private class kvpSorter : IComparer<KeyValuePair<int,int>> | ||
238 | { | ||
239 | public int Compare(KeyValuePair<int,int> a, | ||
240 | KeyValuePair<int,int> b) | ||
241 | { | ||
242 | return a.Key.CompareTo(b.Key); | ||
243 | } | ||
244 | } | ||
245 | |||
246 | public static KeyValuePair<int, int> FindErrorPosition(int line, | ||
247 | int col, Dictionary<KeyValuePair<int, int>, | ||
248 | KeyValuePair<int, int>> positionMap) | ||
249 | { | ||
250 | if (positionMap == null || positionMap.Count == 0) | ||
251 | return new KeyValuePair<int, int>(line, col); | ||
252 | |||
253 | KeyValuePair<int, int> ret = new KeyValuePair<int, int>(); | ||
254 | |||
255 | if (positionMap.TryGetValue(new KeyValuePair<int, int>(line, col), | ||
256 | out ret)) | ||
257 | return ret; | ||
258 | |||
259 | List<KeyValuePair<int,int>> sorted = | ||
260 | new List<KeyValuePair<int,int>>(positionMap.Keys); | ||
261 | |||
262 | sorted.Sort(new kvpSorter()); | ||
263 | |||
264 | int l = 1; | ||
265 | int c = 1; | ||
266 | |||
267 | foreach (KeyValuePair<int, int> cspos in sorted) | ||
268 | { | ||
269 | if (cspos.Key >= line) | ||
270 | { | ||
271 | if (cspos.Key > line) | ||
272 | return new KeyValuePair<int, int>(l, c); | ||
273 | if (cspos.Value > col) | ||
274 | return new KeyValuePair<int, int>(l, c); | ||
275 | c = cspos.Value; | ||
276 | if (c == 0) | ||
277 | c++; | ||
278 | } | ||
279 | else | ||
280 | { | ||
281 | l = cspos.Key; | ||
282 | } | ||
283 | } | ||
284 | return new KeyValuePair<int, int>(l, c); | ||
285 | } | ||
286 | } | ||
287 | } | ||