CSCodeGenerator.cs 37 KB

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