aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/XEngine/LSL2CSConverter.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ScriptEngine/XEngine/LSL2CSConverter.cs')
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/LSL2CSConverter.cs363
1 files changed, 363 insertions, 0 deletions
diff --git a/OpenSim/Region/ScriptEngine/XEngine/LSL2CSConverter.cs b/OpenSim/Region/ScriptEngine/XEngine/LSL2CSConverter.cs
new file mode 100644
index 0000000..9c59108
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/XEngine/LSL2CSConverter.cs
@@ -0,0 +1,363 @@
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*/
28
29using System;
30using System.Collections.Generic;
31using System.Text.RegularExpressions;
32
33namespace OpenSim.Region.ScriptEngine.XEngine
34{
35 public class LSL2CSConverter
36 {
37 // Uses regex to convert LSL code to C# code.
38
39 //private Regex rnw = new Regex(@"[a-zA-Z0-9_\-]", RegexOptions.Compiled);
40 private Dictionary<string, string> dataTypes = new Dictionary<string, string>();
41 private Dictionary<string, string> quotes = new Dictionary<string, string>();
42 // c Style
43 private Regex cstylecomments = new Regex(@"/\*(.|[\r\n])*?\*/", RegexOptions.Compiled | RegexOptions.Multiline);
44 // c# one liners
45 private Regex nonCommentFwsl = new Regex("\"[a-zA-Z0-9.,:/\\n ]+//[^\"+]+([\\\\\\\"+]+)?(\\s+)?[\"+](\\s+)?(;)?", RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline);
46 private Regex conelinecomments = new Regex(@"[^:].?([\/]{2}[^\n]*)|([\n]{1,}[\/]{2}[^\n]*)", RegexOptions.Compiled | RegexOptions.Multiline);
47 // ([^\"])((?:[a-zA-Z])\.[a-zA-Z].?)([^\"])
48
49 // value we're looking for: (?:[a-zA-Z])\.[a-zA-Z]
50 public LSL2CSConverter()
51 {
52 // Only the types we need to convert
53 dataTypes.Add("void", "void");
54 dataTypes.Add("integer", "LSL_Types.LSLInteger");
55 dataTypes.Add("float", "double");
56 dataTypes.Add("string", "LSL_Types.LSLString");
57 dataTypes.Add("key", "LSL_Types.LSLString");
58 dataTypes.Add("vector", "LSL_Types.Vector3");
59 dataTypes.Add("rotation", "LSL_Types.Quaternion");
60 dataTypes.Add("list", "LSL_Types.list");
61 dataTypes.Add("null", "null");
62 }
63
64 public string Convert(string Script)
65 {
66 quotes.Clear();
67 string Return = String.Empty;
68 Script = " \r\n" + Script;
69
70 //
71 // Prepare script for processing
72 //
73
74 // Clean up linebreaks
75 Script = Regex.Replace(Script, @"\r\n", "\n");
76 Script = Regex.Replace(Script, @"\n", "\r\n");
77
78 // QUOTE REPLACEMENT
79 // temporarily replace quotes so we can work our magic on the script without
80 // always considering if we are inside our outside quotes's
81 // TODO: Does this work on half-quotes in strings? ;)
82 string _Script = String.Empty;
83 string C;
84 bool in_quote = false;
85 bool quote_replaced = false;
86 string quote_replacement_string = "Q_U_O_T_E_REPLACEMENT_";
87 string quote = String.Empty;
88 bool last_was_escape = false;
89 int quote_replaced_count = 0;
90
91 string removefwnoncomments = nonCommentFwsl.Replace(Script, "\"\";");
92
93 string removecomments = conelinecomments.Replace(removefwnoncomments, "");
94 removecomments = cstylecomments.Replace(removecomments, "");
95 string[] localscript = removecomments.Split('"');
96 string checkscript = String.Empty;
97 bool flip = true;
98
99 for (int p = 0; p < localscript.Length; p++)
100 {
101 //if (localscript[p].Length >= 1)
102 //{
103 if (!localscript[p].EndsWith(@"\"))
104 {
105 flip = !flip;
106 //System.Console.WriteLine("Flip:" + flip.ToString() + " - " + localscript[p] + " ! " + localscript[p].EndsWith(@"\").ToString());
107 }
108 //}
109 //else
110 //{
111 // flip = !flip;
112 // System.Console.WriteLine("Flip:" + flip.ToString() + " - " + localscript[p]);
113 //}
114 if (!flip)
115 checkscript += localscript[p];
116 }
117
118 //System.Console.WriteLine("SCRIPT:" + checkscript);
119
120 // checks for alpha.alpha way of referring to objects in C#
121 // ignores alpha.x alpha.y, alpha.z for refering to vector components
122 Match SecurityM;
123
124 // BROKEN: this check is very wrong. It block's any url in strings.
125 SecurityM = Regex.Match(checkscript, @"(?:[a-zA-Z])\.(?:[a-wA-Z]|[a-zA-Z][a-zA-Z])", RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline);
126
127 if (SecurityM.Success)
128 throw new Exception("CS0103: 'The . symbol cannot be used in LSL except in float values or vector components'. Detected around: " + SecurityM.Captures[0].Value);
129
130 SecurityM = Regex.Match(checkscript, @"typeof\s", RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline);
131 if (SecurityM.Success)
132 throw new Exception("CS0103: 'The object.typeof method isn't allowed in LSL'");
133
134 SecurityM = Regex.Match(checkscript, @"GetType\(", RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline);
135 if (SecurityM.Success)
136 throw new Exception("CS0103: 'The object.GetType method isn't allowed in LSL'");
137
138 for (int p = 0; p < Script.Length; p++)
139 {
140 C = Script.Substring(p, 1);
141 while (true)
142 {
143 // found " and last was not \ so this is not an escaped \"
144 if (C == "\"" && last_was_escape == false)
145 {
146 // Toggle inside/outside quote
147 in_quote = !in_quote;
148 if (in_quote)
149 {
150 quote_replaced_count++;
151 }
152 else
153 {
154 if (quote == String.Empty)
155 {
156 // We didn't replace quote, probably because of empty string?
157 _Script += quote_replacement_string +
158 quote_replaced_count.ToString().PadLeft(5, "0".ToCharArray()[0]);
159 }
160 // We just left a quote
161 quotes.Add(
162 quote_replacement_string +
163 quote_replaced_count.ToString().PadLeft(5, "0".ToCharArray()[0]), quote);
164 quote = String.Empty;
165 }
166 break;
167 }
168
169 if (!in_quote)
170 {
171 // We are not inside a quote
172 quote_replaced = false;
173 }
174 else
175 {
176 // We are inside a quote
177 if (!quote_replaced)
178 {
179 // Replace quote
180 _Script += quote_replacement_string +
181 quote_replaced_count.ToString().PadLeft(5, "0".ToCharArray()[0]);
182 quote_replaced = true;
183 }
184 quote += C;
185 break;
186 }
187 _Script += C;
188 break;
189 }
190 last_was_escape = false;
191 if (C == @"\")
192 {
193 last_was_escape = true;
194 }
195 }
196 Script = _Script;
197 //
198 // END OF QUOTE REPLACEMENT
199 //
200
201 //
202 // PROCESS STATES
203 // Remove state definitions and add state names to start of each event within state
204 //
205 int ilevel = 0;
206 int lastlevel = 0;
207 string ret = String.Empty;
208 string cache = String.Empty;
209 bool in_state = false;
210 string current_statename = String.Empty;
211 for (int p = 0; p < Script.Length; p++)
212 {
213 C = Script.Substring(p, 1);
214 while (true)
215 {
216 // inc / dec level
217 if (C == @"{")
218 ilevel++;
219 if (C == @"}")
220 ilevel--;
221 if (ilevel < 0)
222 ilevel = 0;
223 cache += C;
224
225 // if level == 0, add to return
226 if (ilevel == 1 && lastlevel == 0)
227 {
228 // 0 => 1: Get last
229 Match m =
230 //Regex.Match(cache, @"(?![a-zA-Z_]+)\s*([a-zA-Z_]+)[^a-zA-Z_\(\)]*{",
231 Regex.Match(cache, @"(?![a-zA-Z_]+)\s*(state\s+)?(?<statename>[a-zA-Z_][a-zA-Z_0-9]*)[^a-zA-Z_0-9\(\)]*{",
232
233 RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline);
234
235 in_state = false;
236 if (m.Success)
237 {
238 // Go back to level 0, this is not a state
239 in_state = true;
240 current_statename = m.Groups["statename"].Captures[0].Value;
241 //Console.WriteLine("Current statename: " + current_statename);
242 cache =
243 //@"(?<s1>(?![a-zA-Z_]+)\s*)" + @"([a-zA-Z_]+)(?<s2>[^a-zA-Z_\(\)]*){",
244 Regex.Replace(cache,
245 @"(?<s1>(?![a-zA-Z_]+)\s*)" + @"(state\s+)?([a-zA-Z_][a-zA-Z_0-9]*)(?<s2>[^a-zA-Z_0-9\(\)]*){",
246 "${s1}${s2}",
247 RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.IgnoreCase);
248 }
249 ret += cache;
250 cache = String.Empty;
251 }
252 if (ilevel == 0 && lastlevel == 1)
253 {
254 // 1 => 0: Remove last }
255 if (in_state == true)
256 {
257 cache = cache.Remove(cache.Length - 1, 1);
258 //cache = Regex.Replace(cache, "}$", String.Empty, RegexOptions.Multiline | RegexOptions.Singleline);
259
260 //Replace function names
261 // void dataserver(key query_id, string data) {
262 //cache = Regex.Replace(cache, @"([^a-zA-Z_]\s*)((?!if|switch|for)[a-zA-Z_]+\s*\([^\)]*\)[^{]*{)", "$1" + "<STATE>" + "$2", RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline);
263 //Console.WriteLine("Replacing using statename: " + current_statename);
264 cache =
265 Regex.Replace(cache,
266 @"^(\s*)((?!(if|switch|for|while)[^a-zA-Z0-9_])[a-zA-Z0-9_]*\s*\([^\)]*\)[^;]*\{)",
267 @"$1public " + current_statename + "_event_$2",
268 RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.IgnoreCase);
269 }
270
271 ret += cache;
272 cache = String.Empty;
273 in_state = true;
274 current_statename = String.Empty;
275 }
276
277 break;
278 }
279 lastlevel = ilevel;
280 }
281 ret += cache;
282 cache = String.Empty;
283
284 Script = ret;
285 ret = String.Empty;
286
287 foreach (string key in dataTypes.Keys)
288 {
289 string val;
290 dataTypes.TryGetValue(key, out val);
291
292 // Replace CAST - (integer) with (int)
293 Script =
294 Regex.Replace(Script, @"\(" + key + @"\)", @"(" + val + ")",
295 RegexOptions.Compiled | RegexOptions.Multiline);
296 // Replace return types and function variables - integer a() and f(integer a, integer a)
297 Script =
298 Regex.Replace(Script, @"(^|;|}|[\(,])(\s*)" + key + @"(\s+)", @"$1$2" + val + "$3",
299 RegexOptions.Compiled | RegexOptions.Multiline);
300 Script =
301 Regex.Replace(Script, @"(^|;|}|[\(,])(\s*)" + key + @"(\s*)[,]", @"$1$2" + val + "$3,",
302 RegexOptions.Compiled | RegexOptions.Multiline);
303 }
304
305 // Add "void" in front of functions that needs it
306 Script =
307 Regex.Replace(Script,
308 @"^(\s*public\s+)?((?!(if|switch|for)[^a-zA-Z0-9_])[a-zA-Z0-9_]*\s*\([^\)]*\)[^;]*\{)",
309 @"$1void $2", RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline);
310
311 // Replace <x,y,z> and <x,y,z,r>
312 Script =
313 Regex.Replace(Script, @"<([^,>;]*,[^,>;]*,[^,>;]*,[^,>;]*)>", @"new LSL_Types.Quaternion($1)",
314 RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline);
315 Script =
316 Regex.Replace(Script, @"<([^,>;)]*,[^,>;]*,[^,>;]*)>", @"new LSL_Types.Vector3($1)",
317 RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline);
318
319 // Replace List []'s
320 Script =
321 Regex.Replace(Script, @"\[([^\]]*)\]", @"new LSL_Types.list($1)",
322 RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline);
323
324 // Replace (string) to .ToString() //
325 Script =
326 Regex.Replace(Script, @"\(string\)\s*([a-zA-Z0-9_.]+(\s*\([^\)]*\))?)", @"$1.ToString()",
327 RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline);
328 Script =
329 Regex.Replace(Script, @"\((float|int)\)\s*([a-zA-Z0-9_.]+(\s*\([^\)]*\))?)", @"$1.Parse($2)",
330 RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline);
331
332 // Replace "state STATENAME" with "state("statename")"
333 Script =
334 Regex.Replace(Script, @"(state)\s+([^;\n\r]+)(;[\r\n\s])", "$1(\"$2\")$3",
335 RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.IgnoreCase);
336
337 // REPLACE BACK QUOTES
338 foreach (string key in quotes.Keys)
339 {
340 string val;
341 quotes.TryGetValue(key, out val);
342 Script = Script.Replace(key, "\"" + val + "\"");
343 }
344
345 //System.Console.WriteLine(Script);
346 Return = String.Empty;// +
347 //"using OpenSim.Region.ScriptEngine.Common; using System.Collections.Generic;";
348
349 //Return += String.Empty +
350 // "namespace SecondLife { ";
351 //Return += String.Empty +
352 // //"[Serializable] " +
353 // "public class Script : OpenSim.Region.ScriptEngine.Common.LSL_BaseClass { ";
354 //Return += @"public Script() { } ";
355 Return += Script;
356 //Return += "} }\r\n";
357
358 quotes.Clear();
359
360 return Return;
361 }
362 }
363}