OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
CSCodeGenerator.cs
Go to the documentation of this file.
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 OpenSimulator 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 System.Reflection;
32 using log4net;
33 using Tools;
34 using OpenSim.Region.Framework.Interfaces;
35 
36 namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
37 {
39  {
40 // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
41 
42  private SYMBOL m_astRoot = null;
43  private Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> m_positionMap;
44  private int m_indentWidth = 4; // for indentation
45  private int m_braceCount; // for indentation
46  private int m_CSharpLine; // the current line of generated C# code
47  private int m_CSharpCol; // the current column of generated C# code
48  private List<string> m_warnings = new List<string>();
49  private IScriptModuleComms m_comms = null;
50 
51  private bool m_insertCoopTerminationChecks;
52  private static string m_coopTerminationCheck = "opensim_reserved_CheckForCoopTermination();";
53 
61 // private SYMBOL m_previousNode;
62 
66  public CSCodeGenerator()
67  {
68  m_comms = null;
69  ResetCounters();
70  }
71 
72  public CSCodeGenerator(IScriptModuleComms comms, bool insertCoopTerminationChecks)
73  {
74  m_comms = comms;
75  m_insertCoopTerminationChecks = insertCoopTerminationChecks;
76  ResetCounters();
77  }
78 
83  public Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> PositionMap
84  {
85  get { return m_positionMap; }
86  }
87 
92  public SYMBOL ASTRoot
93  {
94  get { return m_astRoot; }
95  }
96 
100  private void ResetCounters()
101  {
102  m_braceCount = 0;
103  m_CSharpLine = 0;
104  m_CSharpCol = 1;
105  m_positionMap = new Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>();
106  m_astRoot = null;
107  }
108 
114  public string Convert(string script)
115  {
116 // m_log.DebugFormat("[CS CODE GENERATOR]: Converting to C#\n{0}", script);
117 
118  m_warnings.Clear();
119  ResetCounters();
120  Parser p = new LSLSyntax(new yyLSLSyntax(), new ErrorHandler(true));
121 
122  LSL2CSCodeTransformer codeTransformer;
123  try
124  {
125  codeTransformer = new LSL2CSCodeTransformer(p.Parse(script));
126  }
127  catch (CSToolsException e)
128  {
129  string message;
130 
131  // LL start numbering lines at 0 - geeks!
132  // Also need to subtract one line we prepend!
133  //
134  string emessage = e.Message;
135  string slinfo = e.slInfo.ToString();
136 
137  // Remove wrong line number info
138  //
139  if (emessage.StartsWith(slinfo+": "))
140  emessage = emessage.Substring(slinfo.Length+2);
141 
142  message = String.Format("({0},{1}) {2}",
143  e.slInfo.lineNumber - 1,
144  e.slInfo.charPosition - 1, emessage);
145 
146  throw new Exception(message);
147  }
148 
149  m_astRoot = codeTransformer.Transform();
150 
151  string retstr = String.Empty;
152 
153  // standard preamble
154  //retstr = GenerateLine("using OpenSim.Region.ScriptEngine.Common;");
155  //retstr += GenerateLine("using System.Collections.Generic;");
156  //retstr += GenerateLine("");
157  //retstr += GenerateLine("namespace SecondLife");
158  //retstr += GenerateLine("{");
159  m_braceCount++;
160  //retstr += GenerateIndentedLine("public class Script : OpenSim.Region.ScriptEngine.Common");
161  //retstr += GenerateIndentedLine("{");
162  m_braceCount++;
163 
164  // line number
165  m_CSharpLine += 9;
166 
167  // here's the payload
168  retstr += GenerateLine();
169  foreach (SYMBOL s in m_astRoot.kids)
170  retstr += GenerateNode(m_astRoot, s);
171 
172  // close braces!
173  m_braceCount--;
174  //retstr += GenerateIndentedLine("}");
175  m_braceCount--;
176  //retstr += GenerateLine("}");
177 
178  // Removes all carriage return characters which may be generated in Windows platform. Is there
179  // cleaner way of doing this?
180  retstr = retstr.Replace("\r", "");
181 
182  return retstr;
183  }
184 
189  public string[] GetWarnings()
190  {
191  return m_warnings.ToArray();
192  }
193 
194  private void AddWarning(string warning)
195  {
196  if (!m_warnings.Contains(warning))
197  {
198  m_warnings.Add(warning);
199  }
200  }
201 
209  private string GenerateNode(SYMBOL previousSymbol, SYMBOL s)
210  {
211  string retstr = String.Empty;
212 
213  // make sure to put type lower in the inheritance hierarchy first
214  // ie: since IdentArgument and ExpressionArgument inherit from
215  // Argument, put IdentArgument and ExpressionArgument before Argument
216  if (s is GlobalFunctionDefinition)
217  retstr += GenerateGlobalFunctionDefinition((GlobalFunctionDefinition) s);
218  else if (s is GlobalVariableDeclaration)
219  retstr += GenerateGlobalVariableDeclaration((GlobalVariableDeclaration) s);
220  else if (s is State)
221  retstr += GenerateState((State) s);
222  else if (s is CompoundStatement)
223  retstr += GenerateCompoundStatement(previousSymbol, (CompoundStatement) s);
224  else if (s is Declaration)
225  retstr += GenerateDeclaration((Declaration) s);
226  else if (s is Statement)
227  retstr += GenerateStatement(previousSymbol, (Statement) s);
228  else if (s is ReturnStatement)
229  retstr += GenerateReturnStatement((ReturnStatement) s);
230  else if (s is JumpLabel)
231  retstr += GenerateJumpLabel((JumpLabel) s);
232  else if (s is JumpStatement)
233  retstr += GenerateJumpStatement((JumpStatement) s);
234  else if (s is StateChange)
235  retstr += GenerateStateChange((StateChange) s);
236  else if (s is IfStatement)
237  retstr += GenerateIfStatement((IfStatement) s);
238  else if (s is WhileStatement)
239  retstr += GenerateWhileStatement((WhileStatement) s);
240  else if (s is DoWhileStatement)
241  retstr += GenerateDoWhileStatement((DoWhileStatement) s);
242  else if (s is ForLoop)
243  retstr += GenerateForLoop((ForLoop) s);
244  else if (s is ArgumentList)
245  retstr += GenerateArgumentList((ArgumentList) s);
246  else if (s is Assignment)
247  retstr += GenerateAssignment((Assignment) s);
248  else if (s is BinaryExpression)
249  retstr += GenerateBinaryExpression((BinaryExpression) s);
250  else if (s is ParenthesisExpression)
251  retstr += GenerateParenthesisExpression((ParenthesisExpression) s);
252  else if (s is UnaryExpression)
253  retstr += GenerateUnaryExpression((UnaryExpression) s);
254  else if (s is IncrementDecrementExpression)
255  retstr += GenerateIncrementDecrementExpression((IncrementDecrementExpression) s);
256  else if (s is TypecastExpression)
257  retstr += GenerateTypecastExpression((TypecastExpression) s);
258  else if (s is FunctionCall)
259  retstr += GenerateFunctionCall((FunctionCall) s);
260  else if (s is VectorConstant)
261  retstr += GenerateVectorConstant((VectorConstant) s);
262  else if (s is RotationConstant)
263  retstr += GenerateRotationConstant((RotationConstant) s);
264  else if (s is ListConstant)
265  retstr += GenerateListConstant((ListConstant) s);
266  else if (s is Constant)
267  retstr += GenerateConstant((Constant) s);
268  else if (s is IdentDotExpression)
269  retstr += Generate(CheckName(((IdentDotExpression) s).Name) + "." + ((IdentDotExpression) s).Member, s);
270  else if (s is IdentExpression)
271  retstr += GenerateIdentifier(((IdentExpression) s).Name, s);
272  else if (s is IDENT)
273  retstr += Generate(CheckName(((TOKEN) s).yytext), s);
274  else
275  {
276  foreach (SYMBOL kid in s.kids)
277  retstr += GenerateNode(s, kid);
278  }
279 
280  return retstr;
281  }
282 
288  private string GenerateGlobalFunctionDefinition(GlobalFunctionDefinition gf)
289  {
290  string retstr = String.Empty;
291 
292  // we need to separate the argument declaration list from other kids
293  List<SYMBOL> argumentDeclarationListKids = new List<SYMBOL>();
294  List<SYMBOL> remainingKids = new List<SYMBOL>();
295 
296  foreach (SYMBOL kid in gf.kids)
297  if (kid is ArgumentDeclarationList)
298  argumentDeclarationListKids.Add(kid);
299  else
300  remainingKids.Add(kid);
301 
302  retstr += GenerateIndented(String.Format("{0} {1}(", gf.ReturnType, CheckName(gf.Name)), gf);
303 
304  // print the state arguments, if any
305  foreach (SYMBOL kid in argumentDeclarationListKids)
306  retstr += GenerateArgumentDeclarationList((ArgumentDeclarationList) kid);
307 
308  retstr += GenerateLine(")");
309 
310  foreach (SYMBOL kid in remainingKids)
311  retstr += GenerateNode(gf, kid);
312 
313  return retstr;
314  }
315 
321  private string GenerateGlobalVariableDeclaration(GlobalVariableDeclaration gv)
322  {
323  string retstr = String.Empty;
324 
325  foreach (SYMBOL s in gv.kids)
326  {
327  retstr += Indent();
328  retstr += GenerateNode(gv, s);
329  retstr += GenerateLine(";");
330  }
331 
332  return retstr;
333  }
334 
340  private string GenerateState(State s)
341  {
342  string retstr = String.Empty;
343 
344  foreach (SYMBOL kid in s.kids)
345  if (kid is StateEvent)
346  retstr += GenerateStateEvent((StateEvent) kid, s.Name);
347 
348  return retstr;
349  }
350 
357  private string GenerateStateEvent(StateEvent se, string parentStateName)
358  {
359  string retstr = String.Empty;
360 
361  // we need to separate the argument declaration list from other kids
362  List<SYMBOL> argumentDeclarationListKids = new List<SYMBOL>();
363  List<SYMBOL> remainingKids = new List<SYMBOL>();
364 
365  foreach (SYMBOL kid in se.kids)
366  if (kid is ArgumentDeclarationList)
367  argumentDeclarationListKids.Add(kid);
368  else
369  remainingKids.Add(kid);
370 
371  // "state" (function) declaration
372  retstr += GenerateIndented(String.Format("public void {0}_event_{1}(", parentStateName, se.Name), se);
373 
374  // print the state arguments, if any
375  foreach (SYMBOL kid in argumentDeclarationListKids)
376  retstr += GenerateArgumentDeclarationList((ArgumentDeclarationList) kid);
377 
378  retstr += GenerateLine(")");
379 
380  foreach (SYMBOL kid in remainingKids)
381  retstr += GenerateNode(se, kid);
382 
383  return retstr;
384  }
385 
391  private string GenerateArgumentDeclarationList(ArgumentDeclarationList adl)
392  {
393  string retstr = String.Empty;
394 
395  int comma = adl.kids.Count - 1; // tells us whether to print a comma
396 
397  foreach (Declaration d in adl.kids)
398  {
399  retstr += Generate(String.Format("{0} {1}", d.Datatype, CheckName(d.Id)), d);
400  if (0 < comma--)
401  retstr += Generate(", ");
402  }
403 
404  return retstr;
405  }
406 
412  private string GenerateArgumentList(ArgumentList al)
413  {
414  string retstr = String.Empty;
415 
416  int comma = al.kids.Count - 1; // tells us whether to print a comma
417 
418  foreach (SYMBOL s in al.kids)
419  {
420  retstr += GenerateNode(al, s);
421  if (0 < comma--)
422  retstr += Generate(", ");
423  }
424 
425  return retstr;
426  }
427 
433  private string GenerateCompoundStatement(SYMBOL previousSymbol, CompoundStatement cs)
434  {
435  string retstr = String.Empty;
436 
437  // opening brace
438  retstr += GenerateIndentedLine("{");
439  m_braceCount++;
440 
441  if (m_insertCoopTerminationChecks)
442  {
443  // We have to check in event functions as well because the user can manually call these.
444  if (previousSymbol is GlobalFunctionDefinition
445  || previousSymbol is WhileStatement
446  || previousSymbol is DoWhileStatement
447  || previousSymbol is ForLoop
448  || previousSymbol is StateEvent)
449  retstr += GenerateIndentedLine(m_coopTerminationCheck);
450  }
451 
452  foreach (SYMBOL kid in cs.kids)
453  retstr += GenerateNode(cs, kid);
454 
455  // closing brace
456  m_braceCount--;
457  retstr += GenerateIndentedLine("}");
458 
459  return retstr;
460  }
461 
467  private string GenerateDeclaration(Declaration d)
468  {
469  return Generate(String.Format("{0} {1}", d.Datatype, CheckName(d.Id)), d);
470  }
471 
477  private string GenerateStatement(SYMBOL previousSymbol, Statement s)
478  {
479  string retstr = String.Empty;
480  bool printSemicolon = true;
481  bool transformToBlock = false;
482 
483  if (m_insertCoopTerminationChecks)
484  {
485  // A non-braced single line do while structure cannot contain multiple statements.
486  // So to insert the termination check we change this to a braced control structure instead.
487  if (previousSymbol is WhileStatement
488  || previousSymbol is DoWhileStatement
489  || previousSymbol is ForLoop)
490  {
491  transformToBlock = true;
492 
493  // FIXME: This will be wrongly indented because the previous for/while/dowhile will have already indented.
494  retstr += GenerateIndentedLine("{");
495 
496  retstr += GenerateIndentedLine(m_coopTerminationCheck);
497  }
498  }
499 
500  retstr += Indent();
501 
502  if (0 < s.kids.Count)
503  {
504  // Jump label prints its own colon, we don't need a semicolon.
505  printSemicolon = !(s.kids.Top is JumpLabel);
506 
507  // If we encounter a lone Ident, we skip it, since that's a C#
508  // (MONO) error.
509  if (!(s.kids.Top is IdentExpression && 1 == s.kids.Count))
510  foreach (SYMBOL kid in s.kids)
511  retstr += GenerateNode(s, kid);
512  }
513 
514  if (printSemicolon)
515  retstr += GenerateLine(";");
516 
517  if (transformToBlock)
518  {
519  // FIXME: This will be wrongly indented because the for/while/dowhile is currently handling the unindent
520  retstr += GenerateIndentedLine("}");
521  }
522 
523  return retstr;
524  }
525 
531  private string GenerateAssignment(Assignment a)
532  {
533  string retstr = String.Empty;
534 
535  List<string> identifiers = new List<string>();
536  checkForMultipleAssignments(identifiers, a);
537 
538  retstr += GenerateNode(a, (SYMBOL) a.kids.Pop());
539  retstr += Generate(String.Format(" {0} ", a.AssignmentType), a);
540  foreach (SYMBOL kid in a.kids)
541  retstr += GenerateNode(a, kid);
542 
543  return retstr;
544  }
545 
546  // This code checks for LSL of the following forms, and generates a
547  // warning if it finds them.
548  //
549  // list l = [ "foo" ];
550  // l = (l=[]) + l + ["bar"];
551  // (produces l=["foo","bar"] in SL but l=["bar"] in OS)
552  //
553  // integer i;
554  // integer j;
555  // i = (j = 3) + (j = 4) + (j = 5);
556  // (produces j=3 in SL but j=5 in OS)
557  //
558  // Without this check, that code passes compilation, but does not do what
559  // the end user expects, because LSL in SL evaluates right to left instead
560  // of left to right.
561  //
562  // The theory here is that producing an error and alerting the end user that
563  // something needs to change is better than silently generating incorrect code.
564  private void checkForMultipleAssignments(List<string> identifiers, SYMBOL s)
565  {
566  if (s is Assignment)
567  {
568  Assignment a = (Assignment)s;
569  string newident = null;
570 
571  if (a.kids[0] is Declaration)
572  {
573  newident = ((Declaration)a.kids[0]).Id;
574  }
575  else if (a.kids[0] is IDENT)
576  {
577  newident = ((IDENT)a.kids[0]).yytext;
578  }
579  else if (a.kids[0] is IdentDotExpression)
580  {
581  newident = ((IdentDotExpression)a.kids[0]).Name; // +"." + ((IdentDotExpression)a.kids[0]).Member;
582  }
583  else
584  {
585  AddWarning(String.Format("Multiple assignments checker internal error '{0}' at line {1} column {2}.", a.kids[0].GetType(), ((SYMBOL)a.kids[0]).Line - 1, ((SYMBOL)a.kids[0]).Position));
586  }
587 
588  if (identifiers.Contains(newident))
589  {
590  AddWarning(String.Format("Multiple assignments to '{0}' at line {1} column {2}; results may differ between LSL and OSSL.", newident, ((SYMBOL)a.kids[0]).Line - 1, ((SYMBOL)a.kids[0]).Position));
591  }
592  identifiers.Add(newident);
593  }
594 
595  int index;
596  for (index = 0; index < s.kids.Count; index++)
597  {
598  checkForMultipleAssignments(identifiers, (SYMBOL) s.kids[index]);
599  }
600  }
601 
607  private string GenerateReturnStatement(ReturnStatement rs)
608  {
609  string retstr = String.Empty;
610 
611  retstr += Generate("return ", rs);
612 
613  foreach (SYMBOL kid in rs.kids)
614  retstr += GenerateNode(rs, kid);
615 
616  return retstr;
617  }
618 
624  private string GenerateJumpLabel(JumpLabel jl)
625  {
626  string labelStatement;
627 
628  if (m_insertCoopTerminationChecks)
629  labelStatement = m_coopTerminationCheck;
630  else
631  labelStatement = "NoOp();";
632 
633  return GenerateLine(String.Format("{0}: {1}", CheckName(jl.LabelName), labelStatement), jl);
634  }
635 
641  private string GenerateJumpStatement(JumpStatement js)
642  {
643  return Generate(String.Format("goto {0}", CheckName(js.TargetName)), js);
644  }
645 
651  private string GenerateIfStatement(IfStatement ifs)
652  {
653  string retstr = String.Empty;
654 
655  retstr += GenerateIndented("if (", ifs);
656  retstr += GenerateNode(ifs, (SYMBOL) ifs.kids.Pop());
657  retstr += GenerateLine(")");
658 
659  // CompoundStatement handles indentation itself but we need to do it
660  // otherwise.
661  bool indentHere = ifs.kids.Top is Statement;
662  if (indentHere) m_braceCount++;
663  retstr += GenerateNode(ifs, (SYMBOL) ifs.kids.Pop());
664  if (indentHere) m_braceCount--;
665 
666  if (0 < ifs.kids.Count) // do it again for an else
667  {
668  retstr += GenerateIndentedLine("else", ifs);
669 
670  indentHere = ifs.kids.Top is Statement;
671  if (indentHere) m_braceCount++;
672  retstr += GenerateNode(ifs, (SYMBOL) ifs.kids.Pop());
673  if (indentHere) m_braceCount--;
674  }
675 
676  return retstr;
677  }
678 
684  private string GenerateStateChange(StateChange sc)
685  {
686  return Generate(String.Format("state(\"{0}\")", sc.NewState), sc);
687  }
688 
694  private string GenerateWhileStatement(WhileStatement ws)
695  {
696  string retstr = String.Empty;
697 
698  retstr += GenerateIndented("while (", ws);
699  retstr += GenerateNode(ws, (SYMBOL) ws.kids.Pop());
700  retstr += GenerateLine(")");
701 
702  // CompoundStatement handles indentation itself but we need to do it
703  // otherwise.
704  bool indentHere = ws.kids.Top is Statement;
705  if (indentHere) m_braceCount++;
706  retstr += GenerateNode(ws, (SYMBOL) ws.kids.Pop());
707  if (indentHere) m_braceCount--;
708 
709  return retstr;
710  }
711 
717  private string GenerateDoWhileStatement(DoWhileStatement dws)
718  {
719  string retstr = String.Empty;
720 
721  retstr += GenerateIndentedLine("do", dws);
722 
723  // CompoundStatement handles indentation itself but we need to do it
724  // otherwise.
725  bool indentHere = dws.kids.Top is Statement;
726  if (indentHere) m_braceCount++;
727  retstr += GenerateNode(dws, (SYMBOL) dws.kids.Pop());
728  if (indentHere) m_braceCount--;
729 
730  retstr += GenerateIndented("while (", dws);
731  retstr += GenerateNode(dws, (SYMBOL) dws.kids.Pop());
732  retstr += GenerateLine(");");
733 
734  return retstr;
735  }
736 
742  private string GenerateForLoop(ForLoop fl)
743  {
744  string retstr = String.Empty;
745 
746  retstr += GenerateIndented("for (", fl);
747 
748  // It's possible that we don't have an assignment, in which case
749  // the child will be null and we only print the semicolon.
750  // for (x = 0; x < 10; x++)
751  // ^^^^^
752  ForLoopStatement s = (ForLoopStatement) fl.kids.Pop();
753  if (null != s)
754  {
755  retstr += GenerateForLoopStatement(s);
756  }
757  retstr += Generate("; ");
758  // for (x = 0; x < 10; x++)
759  // ^^^^^^
760  retstr += GenerateNode(fl, (SYMBOL) fl.kids.Pop());
761  retstr += Generate("; ");
762  // for (x = 0; x < 10; x++)
763  // ^^^
764  retstr += GenerateForLoopStatement((ForLoopStatement) fl.kids.Pop());
765  retstr += GenerateLine(")");
766 
767  // CompoundStatement handles indentation itself but we need to do it
768  // otherwise.
769  bool indentHere = fl.kids.Top is Statement;
770  if (indentHere) m_braceCount++;
771  retstr += GenerateNode(fl, (SYMBOL) fl.kids.Pop());
772  if (indentHere) m_braceCount--;
773 
774  return retstr;
775  }
776 
782  private string GenerateForLoopStatement(ForLoopStatement fls)
783  {
784  string retstr = String.Empty;
785 
786  int comma = fls.kids.Count - 1; // tells us whether to print a comma
787 
788  // It's possible that all we have is an empty Ident, for example:
789  //
790  // for (x; x < 10; x++) { ... }
791  //
792  // Which is illegal in C# (MONO). We'll skip it.
793  if (fls.kids.Top is IdentExpression && 1 == fls.kids.Count)
794  return retstr;
795 
796  for (int i = 0; i < fls.kids.Count; i++)
797  {
798  SYMBOL s = (SYMBOL)fls.kids[i];
799 
800  // Statements surrounded by parentheses in for loops
801  //
802  // e.g. for ((i = 0), (j = 7); (i < 10); (++i))
803  //
804  // are legal in LSL but not in C# so we need to discard the parentheses
805  //
806  // The following, however, does not appear to be legal in LLS
807  //
808  // for ((i = 0, j = 7); (i < 10); (++i))
809  //
810  // As of Friday 20th November 2009, the Linden Lab simulators appear simply never to compile or run this
811  // script but with no debug or warnings at all! Therefore, we won't deal with this yet (which looks
812  // like it would be considerably more complicated to handle).
813  while (s is ParenthesisExpression)
814  s = (SYMBOL)s.kids.Pop();
815 
816  retstr += GenerateNode(fls, s);
817  if (0 < comma--)
818  retstr += Generate(", ");
819  }
820 
821  return retstr;
822  }
823 
829  private string GenerateBinaryExpression(BinaryExpression be)
830  {
831  string retstr = String.Empty;
832 
833  if (be.ExpressionSymbol.Equals("&&") || be.ExpressionSymbol.Equals("||"))
834  {
835  // special case handling for logical and/or, see Mantis 3174
836  retstr += "((bool)(";
837  retstr += GenerateNode(be, (SYMBOL)be.kids.Pop());
838  retstr += "))";
839  retstr += Generate(String.Format(" {0} ", be.ExpressionSymbol.Substring(0,1)), be);
840  retstr += "((bool)(";
841  foreach (SYMBOL kid in be.kids)
842  retstr += GenerateNode(be, kid);
843  retstr += "))";
844  }
845  else
846  {
847  retstr += GenerateNode(be, (SYMBOL)be.kids.Pop());
848  retstr += Generate(String.Format(" {0} ", be.ExpressionSymbol), be);
849  foreach (SYMBOL kid in be.kids)
850  retstr += GenerateNode(be, kid);
851  }
852 
853  return retstr;
854  }
855 
861  private string GenerateUnaryExpression(UnaryExpression ue)
862  {
863  string retstr = String.Empty;
864 
865  retstr += Generate(ue.UnarySymbol, ue);
866  retstr += GenerateNode(ue, (SYMBOL) ue.kids.Pop());
867 
868  return retstr;
869  }
870 
876  private string GenerateParenthesisExpression(ParenthesisExpression pe)
877  {
878  string retstr = String.Empty;
879 
880  retstr += Generate("(");
881  foreach (SYMBOL kid in pe.kids)
882  retstr += GenerateNode(pe, kid);
883  retstr += Generate(")");
884 
885  return retstr;
886  }
887 
893  private string GenerateIncrementDecrementExpression(IncrementDecrementExpression ide)
894  {
895  string retstr = String.Empty;
896 
897  if (0 < ide.kids.Count)
898  {
899  IdentDotExpression dot = (IdentDotExpression) ide.kids.Top;
900  retstr += Generate(String.Format("{0}", ide.PostOperation ? CheckName(dot.Name) + "." + dot.Member + ide.Operation : ide.Operation + CheckName(dot.Name) + "." + dot.Member), ide);
901  }
902  else
903  retstr += Generate(String.Format("{0}", ide.PostOperation ? CheckName(ide.Name) + ide.Operation : ide.Operation + CheckName(ide.Name)), ide);
904 
905  return retstr;
906  }
907 
913  private string GenerateTypecastExpression(TypecastExpression te)
914  {
915  string retstr = String.Empty;
916 
917  // we wrap all typecasted statements in parentheses
918  retstr += Generate(String.Format("({0}) (", te.TypecastType), te);
919  retstr += GenerateNode(te, (SYMBOL) te.kids.Pop());
920  retstr += Generate(")");
921 
922  return retstr;
923  }
924 
931  private string GenerateIdentifier(string id, SYMBOL s)
932  {
933  if (m_comms != null)
934  {
935  object value = m_comms.LookupModConstant(id);
936  if (value != null)
937  {
938  string retval = null;
939  if (value is int)
940  retval = String.Format("new LSL_Types.LSLInteger({0})",((int)value).ToString());
941  else if (value is float)
942  retval = String.Format("new LSL_Types.LSLFloat({0})",((float)value).ToString());
943  else if (value is string)
944  retval = String.Format("new LSL_Types.LSLString(\"{0}\")",((string)value));
945  else if (value is OpenMetaverse.UUID)
946  retval = String.Format("new LSL_Types.key(\"{0}\")",((OpenMetaverse.UUID)value).ToString());
947  else if (value is OpenMetaverse.Vector3)
948  retval = String.Format("new LSL_Types.Vector3(\"{0}\")",((OpenMetaverse.Vector3)value).ToString());
949  else if (value is OpenMetaverse.Quaternion)
950  retval = String.Format("new LSL_Types.Quaternion(\"{0}\")",((OpenMetaverse.Quaternion)value).ToString());
951  else retval = id;
952 
953  return Generate(retval, s);
954  }
955  }
956 
957  return Generate(CheckName(id), s);
958  }
959 
965  private string GenerateFunctionCall(FunctionCall fc)
966  {
967  string retstr = String.Empty;
968 
969  string modinvoke = null;
970  if (m_comms != null)
971  modinvoke = m_comms.LookupModInvocation(fc.Id);
972 
973  if (modinvoke != null)
974  {
975  if (fc.kids[0] is ArgumentList)
976  {
977  if ((fc.kids[0] as ArgumentList).kids.Count == 0)
978  retstr += Generate(String.Format("{0}(\"{1}\"",modinvoke,fc.Id), fc);
979  else
980  retstr += Generate(String.Format("{0}(\"{1}\",",modinvoke,fc.Id), fc);
981  }
982  }
983  else
984  {
985  retstr += Generate(String.Format("{0}(", CheckName(fc.Id)), fc);
986  }
987 
988  foreach (SYMBOL kid in fc.kids)
989  retstr += GenerateNode(fc, kid);
990 
991  retstr += Generate(")");
992 
993  return retstr;
994  }
995 
1001  private string GenerateConstant(Constant c)
1002  {
1003  string retstr = String.Empty;
1004 
1005  // Supprt LSL's weird acceptance of floats with no trailing digits
1006  // after the period. Turn float x = 10.; into float x = 10.0;
1007  if ("LSL_Types.LSLFloat" == c.Type)
1008  {
1009  int dotIndex = c.Value.IndexOf('.') + 1;
1010  if (0 < dotIndex && (dotIndex == c.Value.Length || !Char.IsDigit(c.Value[dotIndex])))
1011  c.Value = c.Value.Insert(dotIndex, "0");
1012  c.Value = "new LSL_Types.LSLFloat("+c.Value+")";
1013  }
1014  else if ("LSL_Types.LSLInteger" == c.Type)
1015  {
1016  c.Value = "new LSL_Types.LSLInteger("+c.Value+")";
1017  }
1018  else if ("LSL_Types.LSLString" == c.Type)
1019  {
1020  c.Value = "new LSL_Types.LSLString(\""+c.Value+"\")";
1021  }
1022 
1023  retstr += Generate(c.Value, c);
1024 
1025  return retstr;
1026  }
1027 
1033  private string GenerateVectorConstant(VectorConstant vc)
1034  {
1035  string retstr = String.Empty;
1036 
1037  retstr += Generate(String.Format("new {0}(", vc.Type), vc);
1038  retstr += GenerateNode(vc, (SYMBOL) vc.kids.Pop());
1039  retstr += Generate(", ");
1040  retstr += GenerateNode(vc, (SYMBOL) vc.kids.Pop());
1041  retstr += Generate(", ");
1042  retstr += GenerateNode(vc, (SYMBOL) vc.kids.Pop());
1043  retstr += Generate(")");
1044 
1045  return retstr;
1046  }
1047 
1053  private string GenerateRotationConstant(RotationConstant rc)
1054  {
1055  string retstr = String.Empty;
1056 
1057  retstr += Generate(String.Format("new {0}(", rc.Type), rc);
1058  retstr += GenerateNode(rc, (SYMBOL) rc.kids.Pop());
1059  retstr += Generate(", ");
1060  retstr += GenerateNode(rc, (SYMBOL) rc.kids.Pop());
1061  retstr += Generate(", ");
1062  retstr += GenerateNode(rc, (SYMBOL) rc.kids.Pop());
1063  retstr += Generate(", ");
1064  retstr += GenerateNode(rc, (SYMBOL) rc.kids.Pop());
1065  retstr += Generate(")");
1066 
1067  return retstr;
1068  }
1069 
1075  private string GenerateListConstant(ListConstant lc)
1076  {
1077  string retstr = String.Empty;
1078 
1079  retstr += Generate(String.Format("new {0}(", lc.Type), lc);
1080 
1081  foreach (SYMBOL kid in lc.kids)
1082  retstr += GenerateNode(lc, kid);
1083 
1084  retstr += Generate(")");
1085 
1086  return retstr;
1087  }
1088 
1093  private string GenerateLine()
1094  {
1095  return GenerateLine("");
1096  }
1097 
1103  private string GenerateLine(string s)
1104  {
1105  return GenerateLine(s, null);
1106  }
1107 
1115  private string GenerateLine(string s, SYMBOL sym)
1116  {
1117  string retstr = Generate(s, sym) + "\n";
1118 
1119  m_CSharpLine++;
1120  m_CSharpCol = 1;
1121 
1122  return retstr;
1123  }
1124 
1130  private string Generate(string s)
1131  {
1132  return Generate(s, null);
1133  }
1134 
1142  private string Generate(string s, SYMBOL sym)
1143  {
1144  if (null != sym)
1145  m_positionMap.Add(new KeyValuePair<int, int>(m_CSharpLine, m_CSharpCol), new KeyValuePair<int, int>(sym.Line, sym.Position));
1146 
1147  m_CSharpCol += s.Length;
1148 
1149  return s;
1150  }
1151 
1157  private string GenerateIndentedLine(string s)
1158  {
1159  return GenerateIndentedLine(s, null);
1160  }
1161 
1169  private string GenerateIndentedLine(string s, SYMBOL sym)
1170  {
1171  string retstr = GenerateIndented(s, sym) + "\n";
1172 
1173  m_CSharpLine++;
1174  m_CSharpCol = 1;
1175 
1176  return retstr;
1177  }
1178 
1184  //private string GenerateIndented(string s)
1185  //{
1186  // return GenerateIndented(s, null);
1187  //}
1188  // THIS FUNCTION IS COMMENTED OUT TO SUPPRESS WARNINGS
1189 
1197  private string GenerateIndented(string s, SYMBOL sym)
1198  {
1199  string retstr = Indent() + s;
1200 
1201  if (null != sym)
1202  m_positionMap.Add(new KeyValuePair<int, int>(m_CSharpLine, m_CSharpCol), new KeyValuePair<int, int>(sym.Line, sym.Position));
1203 
1204  m_CSharpCol += s.Length;
1205 
1206  return retstr;
1207  }
1208 
1213  private string Indent()
1214  {
1215  string retstr = String.Empty;
1216 
1217  for (int i = 0; i < m_braceCount; i++)
1218  for (int j = 0; j < m_indentWidth; j++)
1219  {
1220  retstr += " ";
1221  m_CSharpCol++;
1222  }
1223 
1224  return retstr;
1225  }
1226 
1240  private string CheckName(string s)
1241  {
1242  if (CSReservedWords.IsReservedWord(s))
1243  return "@" + s;
1244  else
1245  return s;
1246  }
1247  }
1248 }
string Convert(string script)
Generate the code from the AST we have.
string[] GetWarnings()
Get the set of warnings generated during compilation.
Interface for communication between OpenSim modules and in-world scripts
CSCodeGenerator()
Keep a record of the previous node when we do the parsing.
CSCodeGenerator(IScriptModuleComms comms, bool insertCoopTerminationChecks)