diff options
author | Johan Berntsson | 2008-07-08 03:02:11 +0000 |
---|---|---|
committer | Johan Berntsson | 2008-07-08 03:02:11 +0000 |
commit | a73e3b4e3fdb6b563dddaa7f67d5fe69e65ca752 (patch) | |
tree | 920460cb6108ee9ecb2504f39a0cbf2e86ea2477 /OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs | |
parent | llscript compiler patch from Mike: adds LSL jumps and implicit variable initi... (diff) | |
download | opensim-SC-a73e3b4e3fdb6b563dddaa7f67d5fe69e65ca752.zip opensim-SC-a73e3b4e3fdb6b563dddaa7f67d5fe69e65ca752.tar.gz opensim-SC-a73e3b4e3fdb6b563dddaa7f67d5fe69e65ca752.tar.bz2 opensim-SC-a73e3b4e3fdb6b563dddaa7f67d5fe69e65ca752.tar.xz |
another patch from Mike: the llscript compiler is now available in XEngine as well. Thanks Mike
Diffstat (limited to 'OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs')
-rw-r--r-- | OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs | 803 |
1 files changed, 803 insertions, 0 deletions
diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs new file mode 100644 index 0000000..78c636e --- /dev/null +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs | |||
@@ -0,0 +1,803 @@ | |||
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 | using System; | ||
29 | using System.IO; | ||
30 | using System.Collections.Generic; | ||
31 | using Tools; | ||
32 | |||
33 | namespace OpenSim.Region.ScriptEngine.Shared.CodeTools | ||
34 | { | ||
35 | public class CSCodeGenerator | ||
36 | { | ||
37 | private SYMBOL m_astRoot = null; | ||
38 | private int m_braceCount; // for indentation | ||
39 | |||
40 | /// <summary> | ||
41 | /// Pass the new CodeGenerator a string containing the LSL source. | ||
42 | /// </summary> | ||
43 | /// <param name="script">String containing LSL source.</param> | ||
44 | public CSCodeGenerator(string script) | ||
45 | { | ||
46 | Parser p = new LSLSyntax(); | ||
47 | // Obviously this needs to be in a try/except block. | ||
48 | LSL2CSCodeTransformer codeTransformer = new LSL2CSCodeTransformer(p.Parse(script)); | ||
49 | m_astRoot = codeTransformer.Transform(); | ||
50 | } | ||
51 | |||
52 | /// <summary> | ||
53 | /// Pass the new CodeGenerator an abstract syntax tree. | ||
54 | /// </summary> | ||
55 | /// <param name="astRoot">The root node of the AST.</param> | ||
56 | public CSCodeGenerator(SYMBOL astRoot) | ||
57 | { | ||
58 | m_braceCount = 0; | ||
59 | m_astRoot = astRoot; | ||
60 | } | ||
61 | |||
62 | /// <summary> | ||
63 | /// Generate the code from the AST we have. | ||
64 | /// </summary> | ||
65 | /// <returns>String containing the generated C# code.</returns> | ||
66 | public string Generate() | ||
67 | { | ||
68 | string retstr = String.Empty; | ||
69 | |||
70 | // standard preamble | ||
71 | //retstr = "using OpenSim.Region.ScriptEngine.Common;\n"; | ||
72 | //retstr += "using System.Collections.Generic;\n\n"; | ||
73 | //retstr += "namespace SecondLife\n"; | ||
74 | //retstr += "{\n"; | ||
75 | //retstr += " public class Script : OpenSim.Region.ScriptEngine.Common\n"; | ||
76 | //retstr += " {\n"; | ||
77 | |||
78 | // here's the payload | ||
79 | m_braceCount += 2; | ||
80 | retstr += "\n"; | ||
81 | foreach (SYMBOL s in m_astRoot.kids) | ||
82 | retstr += GenerateNode(s); | ||
83 | |||
84 | // close braces! | ||
85 | //retstr += " }\n"; | ||
86 | //retstr += "}\n"; | ||
87 | m_braceCount -= 2; | ||
88 | |||
89 | return retstr; | ||
90 | } | ||
91 | |||
92 | /// <summary> | ||
93 | /// Recursively called to generate each type of node. Will generate this | ||
94 | /// node, then all it's children. | ||
95 | /// </summary> | ||
96 | /// <param name="s">The current node to generate code for.</param> | ||
97 | /// <returns>String containing C# code for SYMBOL s.</returns> | ||
98 | private string GenerateNode(SYMBOL s) | ||
99 | { | ||
100 | string retstr = String.Empty; | ||
101 | |||
102 | // make sure to put type lower in the inheritance hierarchy first | ||
103 | // ie: since IdentArgument and ExpressionArgument inherit from | ||
104 | // Argument, put IdentArgument and ExpressionArgument before Argument | ||
105 | if (s is GlobalFunctionDefinition) | ||
106 | retstr += GenerateGlobalFunctionDefinition((GlobalFunctionDefinition) s); | ||
107 | else if (s is GlobalVariableDeclaration) | ||
108 | retstr += GenerateGlobalVariableDeclaration((GlobalVariableDeclaration) s); | ||
109 | else if (s is State) | ||
110 | retstr += GenerateState((State) s); | ||
111 | else if (s is CompoundStatement) | ||
112 | retstr += GenerateCompoundStatement((CompoundStatement) s); | ||
113 | else if (s is Declaration) | ||
114 | retstr += GenerateDeclaration((Declaration) s); | ||
115 | else if (s is Statement) | ||
116 | retstr += GenerateStatement((Statement) s); | ||
117 | else if (s is ReturnStatement) | ||
118 | retstr += GenerateReturnStatement((ReturnStatement) s); | ||
119 | else if (s is JumpLabel) | ||
120 | retstr += GenerateJumpLabel((JumpLabel) s); | ||
121 | else if (s is JumpStatement) | ||
122 | retstr += GenerateJumpStatement((JumpStatement) s); | ||
123 | else if (s is StateChange) | ||
124 | retstr += GenerateStateChange((StateChange) s); | ||
125 | else if (s is IfStatement) | ||
126 | retstr += GenerateIfStatement((IfStatement) s); | ||
127 | else if (s is WhileStatement) | ||
128 | retstr += GenerateWhileStatement((WhileStatement) s); | ||
129 | else if (s is DoWhileStatement) | ||
130 | retstr += GenerateDoWhileStatement((DoWhileStatement) s); | ||
131 | else if (s is ForLoop) | ||
132 | retstr += GenerateForLoop((ForLoop) s); | ||
133 | else if (s is ArgumentList) | ||
134 | retstr += GenerateArgumentList((ArgumentList) s); | ||
135 | else if (s is Assignment) | ||
136 | retstr += GenerateAssignment((Assignment) s); | ||
137 | else if (s is BinaryExpression) | ||
138 | retstr += GenerateBinaryExpression((BinaryExpression) s); | ||
139 | else if (s is ParenthesisExpression) | ||
140 | retstr += GenerateParenthesisExpression((ParenthesisExpression) s); | ||
141 | else if (s is UnaryExpression) | ||
142 | retstr += GenerateUnaryExpression((UnaryExpression) s); | ||
143 | else if (s is IncrementDecrementExpression) | ||
144 | retstr += GenerateIncrementDecrementExpression((IncrementDecrementExpression) s); | ||
145 | else if (s is TypecastExpression) | ||
146 | retstr += GenerateTypecastExpression((TypecastExpression) s); | ||
147 | else if (s is FunctionCall) | ||
148 | retstr += GenerateFunctionCall((FunctionCall) s); | ||
149 | else if (s is VectorConstant) | ||
150 | retstr += GenerateVectorConstant((VectorConstant) s); | ||
151 | else if (s is RotationConstant) | ||
152 | retstr += GenerateRotationConstant((RotationConstant) s); | ||
153 | else if (s is ListConstant) | ||
154 | retstr += GenerateListConstant((ListConstant) s); | ||
155 | else if (s is Constant) | ||
156 | retstr += GenerateConstant((Constant) s); | ||
157 | else if (s is IdentDotExpression) | ||
158 | retstr += ((IdentDotExpression) s).Name + "." + ((IdentDotExpression) s).Member; | ||
159 | else if (s is IdentExpression) | ||
160 | retstr += ((IdentExpression) s).Name; | ||
161 | else if (s is IDENT) | ||
162 | retstr += ((TOKEN) s).yytext; | ||
163 | else | ||
164 | { | ||
165 | foreach (SYMBOL kid in s.kids) | ||
166 | retstr += GenerateNode(kid); | ||
167 | } | ||
168 | |||
169 | return retstr; | ||
170 | } | ||
171 | |||
172 | /// <summary> | ||
173 | /// Generates the code for a GlobalFunctionDefinition node. | ||
174 | /// </summary> | ||
175 | /// <param name="gf">The GlobalFunctionDefinition node.</param> | ||
176 | /// <returns>String containing C# code for GlobalFunctionDefinition gf.</returns> | ||
177 | private string GenerateGlobalFunctionDefinition(GlobalFunctionDefinition gf) | ||
178 | { | ||
179 | string retstr = String.Empty; | ||
180 | |||
181 | // we need to separate the argument declaration list from other kids | ||
182 | List<SYMBOL> argumentDeclarationListKids = new List<SYMBOL>(); | ||
183 | List<SYMBOL> remainingKids = new List<SYMBOL>(); | ||
184 | |||
185 | foreach (SYMBOL kid in gf.kids) | ||
186 | if (kid is ArgumentDeclarationList) | ||
187 | argumentDeclarationListKids.Add(kid); | ||
188 | else | ||
189 | remainingKids.Add(kid); | ||
190 | |||
191 | retstr += WriteIndented(String.Format("{0} {1}(", gf.ReturnType, gf.Name)); | ||
192 | |||
193 | // print the state arguments, if any | ||
194 | foreach (SYMBOL kid in argumentDeclarationListKids) | ||
195 | retstr += GenerateArgumentDeclarationList((ArgumentDeclarationList) kid); | ||
196 | |||
197 | retstr += ")\n"; | ||
198 | |||
199 | foreach (SYMBOL kid in remainingKids) | ||
200 | retstr += GenerateNode(kid); | ||
201 | |||
202 | return retstr; | ||
203 | } | ||
204 | |||
205 | /// <summary> | ||
206 | /// Generates the code for a GlobalVariableDeclaration node. | ||
207 | /// </summary> | ||
208 | /// <param name="gv">The GlobalVariableDeclaration node.</param> | ||
209 | /// <returns>String containing C# code for GlobalVariableDeclaration gv.</returns> | ||
210 | private string GenerateGlobalVariableDeclaration(GlobalVariableDeclaration gv) | ||
211 | { | ||
212 | string retstr = String.Empty; | ||
213 | |||
214 | foreach (SYMBOL s in gv.kids) | ||
215 | { | ||
216 | retstr += Indent(); | ||
217 | retstr += GenerateNode(s); | ||
218 | retstr += ";\n"; | ||
219 | } | ||
220 | |||
221 | return retstr; | ||
222 | } | ||
223 | |||
224 | /// <summary> | ||
225 | /// Generates the code for a State node. | ||
226 | /// </summary> | ||
227 | /// <param name="s">The State node.</param> | ||
228 | /// <returns>String containing C# code for State s.</returns> | ||
229 | private string GenerateState(State s) | ||
230 | { | ||
231 | string retstr = String.Empty; | ||
232 | |||
233 | foreach (SYMBOL kid in s.kids) | ||
234 | if (kid is StateEvent) | ||
235 | retstr += GenerateStateEvent((StateEvent) kid, s.Name); | ||
236 | else | ||
237 | retstr += String.Format("ERROR: State '{0}' contains a '{1}\n", s.Name, kid.GetType()); | ||
238 | |||
239 | return retstr; | ||
240 | } | ||
241 | |||
242 | /// <summary> | ||
243 | /// Generates the code for a StateEvent node. | ||
244 | /// </summary> | ||
245 | /// <param name="se">The StateEvent node.</param> | ||
246 | /// <param name="parentStateName">The name of the parent state.</param> | ||
247 | /// <returns>String containing C# code for StateEvent se.</returns> | ||
248 | private string GenerateStateEvent(StateEvent se, string parentStateName) | ||
249 | { | ||
250 | string retstr = String.Empty; | ||
251 | |||
252 | // we need to separate the argument declaration list from other kids | ||
253 | List<SYMBOL> argumentDeclarationListKids = new List<SYMBOL>(); | ||
254 | List<SYMBOL> remainingKids = new List<SYMBOL>(); | ||
255 | |||
256 | foreach (SYMBOL kid in se.kids) | ||
257 | if (kid is ArgumentDeclarationList) | ||
258 | argumentDeclarationListKids.Add(kid); | ||
259 | else | ||
260 | remainingKids.Add(kid); | ||
261 | |||
262 | // "state" (function) declaration | ||
263 | retstr += WriteIndented(String.Format("public void {0}_event_{1}(", parentStateName, se.Name)); | ||
264 | |||
265 | // print the state arguments, if any | ||
266 | foreach (SYMBOL kid in argumentDeclarationListKids) | ||
267 | retstr += GenerateArgumentDeclarationList((ArgumentDeclarationList) kid); | ||
268 | |||
269 | retstr += ")\n"; | ||
270 | |||
271 | foreach (SYMBOL kid in remainingKids) | ||
272 | retstr += GenerateNode(kid); | ||
273 | |||
274 | return retstr; | ||
275 | } | ||
276 | |||
277 | /// <summary> | ||
278 | /// Generates the code for an ArgumentDeclarationList node. | ||
279 | /// </summary> | ||
280 | /// <param name="adl">The ArgumentDeclarationList node.</param> | ||
281 | /// <returns>String containing C# code for SYMBOL s.</returns> | ||
282 | private string GenerateArgumentDeclarationList(ArgumentDeclarationList adl) | ||
283 | { | ||
284 | string retstr = String.Empty; | ||
285 | |||
286 | int comma = adl.kids.Count - 1; // tells us whether to print a comma | ||
287 | |||
288 | foreach (Declaration d in adl.kids) | ||
289 | { | ||
290 | retstr += String.Format("{0} {1}", d.Datatype, d.Id); | ||
291 | if (0 < comma--) | ||
292 | retstr += ", "; | ||
293 | } | ||
294 | |||
295 | return retstr; | ||
296 | } | ||
297 | |||
298 | /// <summary> | ||
299 | /// Generates the code for an ArgumentList node. | ||
300 | /// </summary> | ||
301 | /// <param name="al">The ArgumentList node.</param> | ||
302 | /// <returns>String containing C# code for SYMBOL s.</returns> | ||
303 | private string GenerateArgumentList(ArgumentList al) | ||
304 | { | ||
305 | string retstr = String.Empty; | ||
306 | |||
307 | int comma = al.kids.Count - 1; // tells us whether to print a comma | ||
308 | |||
309 | foreach (SYMBOL s in al.kids) | ||
310 | { | ||
311 | retstr += GenerateNode(s); | ||
312 | if (0 < comma--) | ||
313 | retstr += ", "; | ||
314 | } | ||
315 | |||
316 | return retstr; | ||
317 | } | ||
318 | |||
319 | /// <summary> | ||
320 | /// Generates the code for a CompoundStatement node. | ||
321 | /// </summary> | ||
322 | /// <param name="cs">The CompoundStatement node.</param> | ||
323 | /// <returns>String containing C# code for SYMBOL s.</returns> | ||
324 | private string GenerateCompoundStatement(CompoundStatement cs) | ||
325 | { | ||
326 | string retstr = String.Empty; | ||
327 | |||
328 | // opening brace | ||
329 | retstr += WriteIndentedLine("{"); | ||
330 | m_braceCount++; | ||
331 | |||
332 | foreach (SYMBOL kid in cs.kids) | ||
333 | retstr += GenerateNode(kid); | ||
334 | |||
335 | // closing brace | ||
336 | m_braceCount--; | ||
337 | retstr += WriteIndentedLine("}"); | ||
338 | |||
339 | return retstr; | ||
340 | } | ||
341 | |||
342 | /// <summary> | ||
343 | /// Generates the code for a Declaration node. | ||
344 | /// </summary> | ||
345 | /// <param name="d">The Declaration node.</param> | ||
346 | /// <returns>String containing C# code for SYMBOL s.</returns> | ||
347 | private string GenerateDeclaration(Declaration d) | ||
348 | { | ||
349 | return String.Format("{0} {1}", d.Datatype, d.Id); | ||
350 | } | ||
351 | |||
352 | /// <summary> | ||
353 | /// Generates the code for a Statement node. | ||
354 | /// </summary> | ||
355 | /// <param name="s">The Statement node.</param> | ||
356 | /// <returns>String containing C# code for SYMBOL s.</returns> | ||
357 | private string GenerateStatement(Statement s) | ||
358 | { | ||
359 | string retstr = String.Empty; | ||
360 | |||
361 | // Jump label prints its own colon, we don't need a semicolon. | ||
362 | bool printSemicolon = !(s.kids.Top is JumpLabel); | ||
363 | |||
364 | retstr += Indent(); | ||
365 | |||
366 | foreach (SYMBOL kid in s.kids) | ||
367 | retstr += GenerateNode(kid); | ||
368 | |||
369 | if (printSemicolon) | ||
370 | retstr += ";\n"; | ||
371 | |||
372 | return retstr; | ||
373 | } | ||
374 | |||
375 | /// <summary> | ||
376 | /// Generates the code for an Assignment node. | ||
377 | /// </summary> | ||
378 | /// <param name="a">The Assignment node.</param> | ||
379 | /// <returns>String containing C# code for SYMBOL s.</returns> | ||
380 | private string GenerateAssignment(Assignment a) | ||
381 | { | ||
382 | string retstr = String.Empty; | ||
383 | |||
384 | retstr += GenerateNode((SYMBOL) a.kids.Pop()); | ||
385 | retstr +=String.Format(" {0} ", a.AssignmentType); | ||
386 | foreach (SYMBOL kid in a.kids) | ||
387 | retstr += GenerateNode(kid); | ||
388 | |||
389 | return retstr; | ||
390 | } | ||
391 | |||
392 | /// <summary> | ||
393 | /// Generates the code for a ReturnStatement node. | ||
394 | /// </summary> | ||
395 | /// <param name="rs">The ReturnStatement node.</param> | ||
396 | /// <returns>String containing C# code for SYMBOL s.</returns> | ||
397 | private string GenerateReturnStatement(ReturnStatement rs) | ||
398 | { | ||
399 | string retstr = String.Empty; | ||
400 | |||
401 | retstr += "return "; | ||
402 | |||
403 | foreach (SYMBOL kid in rs.kids) | ||
404 | retstr += GenerateNode(kid); | ||
405 | |||
406 | return retstr; | ||
407 | } | ||
408 | |||
409 | /// <summary> | ||
410 | /// Generates the code for a JumpLabel node. | ||
411 | /// </summary> | ||
412 | /// <param name="jl">The JumpLabel node.</param> | ||
413 | /// <returns>String containing C# code for SYMBOL s.</returns> | ||
414 | private string GenerateJumpLabel(JumpLabel jl) | ||
415 | { | ||
416 | return String.Format("{0}:\n", jl.LabelName); | ||
417 | } | ||
418 | |||
419 | /// <summary> | ||
420 | /// Generates the code for a JumpStatement node. | ||
421 | /// </summary> | ||
422 | /// <param name="js">The JumpStatement node.</param> | ||
423 | /// <returns>String containing C# code for SYMBOL s.</returns> | ||
424 | private string GenerateJumpStatement(JumpStatement js) | ||
425 | { | ||
426 | return String.Format("goto {0}", js.TargetName); | ||
427 | } | ||
428 | |||
429 | /// <summary> | ||
430 | /// Generates the code for a IfStatement node. | ||
431 | /// </summary> | ||
432 | /// <param name="ifs">The IfStatement node.</param> | ||
433 | /// <returns>String containing C# code for SYMBOL s.</returns> | ||
434 | private string GenerateIfStatement(IfStatement ifs) | ||
435 | { | ||
436 | string retstr = String.Empty; | ||
437 | |||
438 | retstr += WriteIndented("if ("); | ||
439 | retstr += GenerateNode((SYMBOL) ifs.kids.Pop()); | ||
440 | retstr += ")\n"; | ||
441 | |||
442 | // CompoundStatement handles indentation itself but we need to do it | ||
443 | // otherwise. | ||
444 | bool indentHere = ifs.kids.Top is Statement; | ||
445 | if (indentHere) m_braceCount++; | ||
446 | retstr += GenerateNode((SYMBOL) ifs.kids.Pop()); | ||
447 | if (indentHere) m_braceCount--; | ||
448 | |||
449 | if (0 < ifs.kids.Count) // do it again for an else | ||
450 | { | ||
451 | retstr += WriteIndentedLine("else"); | ||
452 | |||
453 | indentHere = ifs.kids.Top is Statement; | ||
454 | if (indentHere) m_braceCount++; | ||
455 | retstr += GenerateNode((SYMBOL) ifs.kids.Pop()); | ||
456 | if (indentHere) m_braceCount--; | ||
457 | } | ||
458 | |||
459 | return retstr; | ||
460 | } | ||
461 | |||
462 | /// <summary> | ||
463 | /// Generates the code for a StateChange node. | ||
464 | /// </summary> | ||
465 | /// <param name="sc">The StateChange node.</param> | ||
466 | /// <returns>String containing C# code for SYMBOL s.</returns> | ||
467 | private string GenerateStateChange(StateChange sc) | ||
468 | { | ||
469 | return String.Format("state(\"{0}\")", sc.NewState); | ||
470 | } | ||
471 | |||
472 | /// <summary> | ||
473 | /// Generates the code for a WhileStatement node. | ||
474 | /// </summary> | ||
475 | /// <param name="ws">The WhileStatement node.</param> | ||
476 | /// <returns>String containing C# code for SYMBOL s.</returns> | ||
477 | private string GenerateWhileStatement(WhileStatement ws) | ||
478 | { | ||
479 | string retstr = String.Empty; | ||
480 | |||
481 | retstr += WriteIndented("while ("); | ||
482 | retstr += GenerateNode((SYMBOL) ws.kids.Pop()); | ||
483 | retstr += ")\n"; | ||
484 | |||
485 | // CompoundStatement handles indentation itself but we need to do it | ||
486 | // otherwise. | ||
487 | bool indentHere = ws.kids.Top is Statement; | ||
488 | if (indentHere) m_braceCount++; | ||
489 | retstr += GenerateNode((SYMBOL) ws.kids.Pop()); | ||
490 | if (indentHere) m_braceCount--; | ||
491 | |||
492 | return retstr; | ||
493 | } | ||
494 | |||
495 | /// <summary> | ||
496 | /// Generates the code for a DoWhileStatement node. | ||
497 | /// </summary> | ||
498 | /// <param name="dws">The DoWhileStatement node.</param> | ||
499 | /// <returns>String containing C# code for SYMBOL s.</returns> | ||
500 | private string GenerateDoWhileStatement(DoWhileStatement dws) | ||
501 | { | ||
502 | string retstr = String.Empty; | ||
503 | |||
504 | retstr += WriteIndentedLine("do"); | ||
505 | |||
506 | // CompoundStatement handles indentation itself but we need to do it | ||
507 | // otherwise. | ||
508 | bool indentHere = dws.kids.Top is Statement; | ||
509 | if (indentHere) m_braceCount++; | ||
510 | retstr += GenerateNode((SYMBOL) dws.kids.Pop()); | ||
511 | if (indentHere) m_braceCount--; | ||
512 | |||
513 | retstr += WriteIndented("while ("); | ||
514 | retstr += GenerateNode((SYMBOL) dws.kids.Pop()); | ||
515 | retstr += ");\n"; | ||
516 | |||
517 | return retstr; | ||
518 | } | ||
519 | |||
520 | /// <summary> | ||
521 | /// Generates the code for a ForLoop node. | ||
522 | /// </summary> | ||
523 | /// <param name="fl">The ForLoop node.</param> | ||
524 | /// <returns>String containing C# code for SYMBOL s.</returns> | ||
525 | private string GenerateForLoop(ForLoop fl) | ||
526 | { | ||
527 | string retstr = String.Empty; | ||
528 | |||
529 | retstr += WriteIndented("for ("); | ||
530 | |||
531 | // for ( x = 0 ; x < 10 ; x++ ) | ||
532 | // ^^^^^^^ | ||
533 | retstr += GenerateForLoopStatement((ForLoopStatement) fl.kids.Pop()); | ||
534 | retstr += "; "; | ||
535 | // for ( x = 0 ; x < 10 ; x++ ) | ||
536 | // ^^^^^^^^ | ||
537 | retstr += GenerateNode((SYMBOL) fl.kids.Pop()); | ||
538 | retstr += "; "; | ||
539 | // for ( x = 0 ; x < 10 ; x++ ) | ||
540 | // ^^^^^ | ||
541 | retstr += GenerateForLoopStatement((ForLoopStatement) fl.kids.Pop()); | ||
542 | retstr += ")\n"; | ||
543 | |||
544 | // CompoundStatement handles indentation itself but we need to do it | ||
545 | // otherwise. | ||
546 | bool indentHere = fl.kids.Top is Statement; | ||
547 | if (indentHere) m_braceCount++; | ||
548 | retstr += GenerateNode((SYMBOL) fl.kids.Pop()); | ||
549 | if (indentHere) m_braceCount--; | ||
550 | |||
551 | return retstr; | ||
552 | } | ||
553 | |||
554 | /// <summary> | ||
555 | /// Generates the code for a ForLoopStatement node. | ||
556 | /// </summary> | ||
557 | /// <param name="fls">The ForLoopStatement node.</param> | ||
558 | /// <returns>String containing C# code for SYMBOL s.</returns> | ||
559 | private string GenerateForLoopStatement(ForLoopStatement fls) | ||
560 | { | ||
561 | string retstr = String.Empty; | ||
562 | |||
563 | int comma = fls.kids.Count - 1; // tells us whether to print a comma | ||
564 | |||
565 | foreach (SYMBOL s in fls.kids) | ||
566 | { | ||
567 | retstr += GenerateNode(s); | ||
568 | if (0 < comma--) | ||
569 | retstr += ", "; | ||
570 | } | ||
571 | |||
572 | return retstr; | ||
573 | } | ||
574 | |||
575 | /// <summary> | ||
576 | /// Generates the code for a BinaryExpression node. | ||
577 | /// </summary> | ||
578 | /// <param name="be">The BinaryExpression node.</param> | ||
579 | /// <returns>String containing C# code for SYMBOL s.</returns> | ||
580 | private string GenerateBinaryExpression(BinaryExpression be) | ||
581 | { | ||
582 | string retstr = String.Empty; | ||
583 | |||
584 | retstr += GenerateNode((SYMBOL) be.kids.Pop()); | ||
585 | retstr += String.Format(" {0} ", be.ExpressionSymbol); | ||
586 | foreach (SYMBOL kid in be.kids) | ||
587 | retstr += GenerateNode(kid); | ||
588 | |||
589 | return retstr; | ||
590 | } | ||
591 | |||
592 | /// <summary> | ||
593 | /// Generates the code for a UnaryExpression node. | ||
594 | /// </summary> | ||
595 | /// <param name="ue">The UnaryExpression node.</param> | ||
596 | /// <returns>String containing C# code for SYMBOL s.</returns> | ||
597 | private string GenerateUnaryExpression(UnaryExpression ue) | ||
598 | { | ||
599 | string retstr = String.Empty; | ||
600 | |||
601 | retstr += ue.UnarySymbol; | ||
602 | retstr += GenerateNode((SYMBOL) ue.kids.Pop()); | ||
603 | |||
604 | return retstr; | ||
605 | } | ||
606 | |||
607 | /// <summary> | ||
608 | /// Generates the code for a ParenthesisExpression node. | ||
609 | /// </summary> | ||
610 | /// <param name="pe">The ParenthesisExpression node.</param> | ||
611 | /// <returns>String containing C# code for SYMBOL s.</returns> | ||
612 | private string GenerateParenthesisExpression(ParenthesisExpression pe) | ||
613 | { | ||
614 | string retstr = String.Empty; | ||
615 | |||
616 | retstr += "("; | ||
617 | foreach (SYMBOL kid in pe.kids) | ||
618 | retstr += GenerateNode(kid); | ||
619 | retstr += ")"; | ||
620 | |||
621 | return retstr; | ||
622 | } | ||
623 | |||
624 | /// <summary> | ||
625 | /// Generates the code for a IncrementDecrementExpression node. | ||
626 | /// </summary> | ||
627 | /// <param name="ide">The IncrementDecrementExpression node.</param> | ||
628 | /// <returns>String containing C# code for SYMBOL s.</returns> | ||
629 | private string GenerateIncrementDecrementExpression(IncrementDecrementExpression ide) | ||
630 | { | ||
631 | string retstr = String.Empty; | ||
632 | |||
633 | if (0 < ide.kids.Count) | ||
634 | { | ||
635 | IdentDotExpression dot = (IdentDotExpression) ide.kids.Top; | ||
636 | retstr += String.Format("{0}", ide.PostOperation ? dot.Name + "." + dot.Member + ide.Operation : ide.Operation + dot.Name + "." + dot.Member); | ||
637 | } | ||
638 | else | ||
639 | retstr += String.Format("{0}", ide.PostOperation ? ide.Name + ide.Operation : ide.Operation + ide.Name); | ||
640 | |||
641 | return retstr; | ||
642 | } | ||
643 | |||
644 | /// <summary> | ||
645 | /// Generates the code for a TypecastExpression node. | ||
646 | /// </summary> | ||
647 | /// <param name="te">The TypecastExpression node.</param> | ||
648 | /// <returns>String containing C# code for SYMBOL s.</returns> | ||
649 | private string GenerateTypecastExpression(TypecastExpression te) | ||
650 | { | ||
651 | string retstr = String.Empty; | ||
652 | |||
653 | // we wrap all typecasted statements in parentheses | ||
654 | retstr += String.Format("({0}) (", te.TypecastType); | ||
655 | retstr += GenerateNode((SYMBOL) te.kids.Pop()); | ||
656 | retstr += ")"; | ||
657 | |||
658 | return retstr; | ||
659 | } | ||
660 | |||
661 | /// <summary> | ||
662 | /// Generates the code for a FunctionCall node. | ||
663 | /// </summary> | ||
664 | /// <param name="fc">The FunctionCall node.</param> | ||
665 | /// <returns>String containing C# code for SYMBOL s.</returns> | ||
666 | private string GenerateFunctionCall(FunctionCall fc) | ||
667 | { | ||
668 | string retstr = String.Empty; | ||
669 | |||
670 | retstr += String.Format("{0}(", fc.Id); | ||
671 | |||
672 | foreach (SYMBOL kid in fc.kids) | ||
673 | retstr += GenerateNode(kid); | ||
674 | |||
675 | retstr += ")"; | ||
676 | |||
677 | return retstr; | ||
678 | } | ||
679 | |||
680 | /// <summary> | ||
681 | /// Generates the code for a Constant node. | ||
682 | /// </summary> | ||
683 | /// <param name="c">The Constant node.</param> | ||
684 | /// <returns>String containing C# code for SYMBOL s.</returns> | ||
685 | private string GenerateConstant(Constant c) | ||
686 | { | ||
687 | string retstr = String.Empty; | ||
688 | |||
689 | // Supprt LSL's weird acceptance of floats with no trailing digits | ||
690 | // after the period. Turn float x = 10.; into float x = 10.0; | ||
691 | if ("LSL_Types.LSLFloat" == c.Type) | ||
692 | { | ||
693 | int dotIndex = c.Value.IndexOf('.') + 1; | ||
694 | if (0 < dotIndex && (dotIndex == c.Value.Length || !Char.IsDigit(c.Value[dotIndex]))) | ||
695 | c.Value = c.Value.Insert(dotIndex, "0"); | ||
696 | } | ||
697 | |||
698 | // need to quote strings | ||
699 | if ("LSL_Types.LSLString" == c.Type) | ||
700 | retstr += "\""; | ||
701 | retstr += c.Value; | ||
702 | if ("LSL_Types.LSLString" == c.Type) | ||
703 | retstr += "\""; | ||
704 | |||
705 | return retstr; | ||
706 | } | ||
707 | |||
708 | /// <summary> | ||
709 | /// Generates the code for a VectorConstant node. | ||
710 | /// </summary> | ||
711 | /// <param name="vc">The VectorConstant node.</param> | ||
712 | /// <returns>String containing C# code for SYMBOL s.</returns> | ||
713 | private string GenerateVectorConstant(VectorConstant vc) | ||
714 | { | ||
715 | string retstr = String.Empty; | ||
716 | |||
717 | retstr += String.Format("new {0}(", vc.Type); | ||
718 | retstr += GenerateNode((SYMBOL) vc.kids.Pop()); | ||
719 | retstr += ", "; | ||
720 | retstr += GenerateNode((SYMBOL) vc.kids.Pop()); | ||
721 | retstr += ", "; | ||
722 | retstr += GenerateNode((SYMBOL) vc.kids.Pop()); | ||
723 | retstr += ")"; | ||
724 | |||
725 | return retstr; | ||
726 | } | ||
727 | |||
728 | /// <summary> | ||
729 | /// Generates the code for a RotationConstant node. | ||
730 | /// </summary> | ||
731 | /// <param name="rc">The RotationConstant node.</param> | ||
732 | /// <returns>String containing C# code for SYMBOL s.</returns> | ||
733 | private string GenerateRotationConstant(RotationConstant rc) | ||
734 | { | ||
735 | string retstr = String.Empty; | ||
736 | |||
737 | retstr += String.Format("new {0}(", rc.Type); | ||
738 | retstr += GenerateNode((SYMBOL) rc.kids.Pop()); | ||
739 | retstr += ", "; | ||
740 | retstr += GenerateNode((SYMBOL) rc.kids.Pop()); | ||
741 | retstr += ", "; | ||
742 | retstr += GenerateNode((SYMBOL) rc.kids.Pop()); | ||
743 | retstr += ", "; | ||
744 | retstr += GenerateNode((SYMBOL) rc.kids.Pop()); | ||
745 | retstr += ")"; | ||
746 | |||
747 | return retstr; | ||
748 | } | ||
749 | |||
750 | /// <summary> | ||
751 | /// Generates the code for a ListConstant node. | ||
752 | /// </summary> | ||
753 | /// <param name="lc">The ListConstant node.</param> | ||
754 | /// <returns>String containing C# code for SYMBOL s.</returns> | ||
755 | private string GenerateListConstant(ListConstant lc) | ||
756 | { | ||
757 | string retstr = String.Empty; | ||
758 | |||
759 | retstr += String.Format("new {0}(", lc.Type); | ||
760 | |||
761 | foreach (SYMBOL kid in lc.kids) | ||
762 | retstr += GenerateNode(kid); | ||
763 | |||
764 | retstr += ")"; | ||
765 | |||
766 | return retstr; | ||
767 | } | ||
768 | |||
769 | /// <summary> | ||
770 | /// Prints text correctly indented, followed by a newline. | ||
771 | /// </summary> | ||
772 | /// <param name="s">String of text to print.</param> | ||
773 | /// <returns>String containing C# code for SYMBOL s.</returns> | ||
774 | private string WriteIndentedLine(string s) | ||
775 | { | ||
776 | return WriteIndented(s) + "\n"; | ||
777 | } | ||
778 | |||
779 | /// <summary> | ||
780 | /// Prints text correctly indented. | ||
781 | /// </summary> | ||
782 | /// <param name="s">String of text to print.</param> | ||
783 | /// <returns>String containing C# code for SYMBOL s.</returns> | ||
784 | private string WriteIndented(string s) | ||
785 | { | ||
786 | return Indent() + s; | ||
787 | } | ||
788 | |||
789 | /// <summary> | ||
790 | /// Prints correct indentation. | ||
791 | /// </summary> | ||
792 | /// <returns>String containing C# code for SYMBOL s.</returns> | ||
793 | private string Indent() | ||
794 | { | ||
795 | string retstr = String.Empty; | ||
796 | |||
797 | for (int i = 0; i < m_braceCount; i++) | ||
798 | retstr += " "; | ||
799 | |||
800 | return retstr; | ||
801 | } | ||
802 | } | ||
803 | } | ||