CSCodeGenerator.cs 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248
  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. using System;
  28. using System.IO;
  29. using System.Collections.Generic;
  30. using System.Reflection;
  31. using log4net;
  32. using Tools;
  33. using OpenSim.Region.Framework.Interfaces;
  34. namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
  35. {
  36. public class CSCodeGenerator : ICodeConverter
  37. {
  38. // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  39. private SYMBOL m_astRoot = null;
  40. private Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> m_positionMap;
  41. private int m_indentWidth = 4; // for indentation
  42. private int m_braceCount; // for indentation
  43. private int m_CSharpLine; // the current line of generated C# code
  44. private int m_CSharpCol; // the current column of generated C# code
  45. private List<string> m_warnings = new List<string>();
  46. private IScriptModuleComms m_comms = null;
  47. private bool m_insertCoopTerminationChecks;
  48. private static string m_coopTerminationCheck = "opensim_reserved_CheckForCoopTermination();";
  49. /// <summary>
  50. /// Keep a record of the previous node when we do the parsing.
  51. /// </summary>
  52. /// <remarks>
  53. /// We do this here because the parser generated by CSTools does not retain a reference to its parent node.
  54. /// The previous node is required so we can correctly insert co-op termination checks when required.
  55. /// </remarks>
  56. // private SYMBOL m_previousNode;
  57. /// <summary>
  58. /// Creates an 'empty' CSCodeGenerator instance.
  59. /// </summary>
  60. public CSCodeGenerator()
  61. {
  62. m_comms = null;
  63. ResetCounters();
  64. }
  65. public CSCodeGenerator(IScriptModuleComms comms, bool insertCoopTerminationChecks)
  66. {
  67. m_comms = comms;
  68. m_insertCoopTerminationChecks = insertCoopTerminationChecks;
  69. ResetCounters();
  70. }
  71. /// <summary>
  72. /// Get the mapping between LSL and C# line/column number.
  73. /// </summary>
  74. /// <returns>Dictionary\<KeyValuePair\<int, int\>, KeyValuePair\<int, int\>\>.</returns>
  75. public Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> PositionMap
  76. {
  77. get { return m_positionMap; }
  78. }
  79. /// <summary>
  80. /// Get the mapping between LSL and C# line/column number.
  81. /// </summary>
  82. /// <returns>SYMBOL pointing to root of the abstract syntax tree.</returns>
  83. public SYMBOL ASTRoot
  84. {
  85. get { return m_astRoot; }
  86. }
  87. /// <summary>
  88. /// Resets various counters and metadata.
  89. /// </summary>
  90. private void ResetCounters()
  91. {
  92. m_braceCount = 0;
  93. m_CSharpLine = 0;
  94. m_CSharpCol = 1;
  95. m_positionMap = new Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>();
  96. m_astRoot = null;
  97. }
  98. /// <summary>
  99. /// Generate the code from the AST we have.
  100. /// </summary>
  101. /// <param name="script">The LSL source as a string.</param>
  102. /// <returns>String containing the generated C# code.</returns>
  103. public string Convert(string script)
  104. {
  105. // m_log.DebugFormat("[CS CODE GENERATOR]: Converting to C#\n{0}", script);
  106. m_warnings.Clear();
  107. ResetCounters();
  108. Parser p = new LSLSyntax(new yyLSLSyntax(), new ErrorHandler(true));
  109. LSL2CSCodeTransformer codeTransformer;
  110. try
  111. {
  112. codeTransformer = new LSL2CSCodeTransformer(p.Parse(script));
  113. }
  114. catch (CSToolsException e)
  115. {
  116. string message;
  117. // LL start numbering lines at 0 - geeks!
  118. // Also need to subtract one line we prepend!
  119. //
  120. string emessage = e.Message;
  121. string slinfo = e.slInfo.ToString();
  122. // Remove wrong line number info
  123. //
  124. if (emessage.StartsWith(slinfo+": "))
  125. emessage = emessage.Substring(slinfo.Length+2);
  126. message = String.Format("({0},{1}) {2}",
  127. e.slInfo.lineNumber - 1,
  128. e.slInfo.charPosition - 1, emessage);
  129. throw new Exception(message);
  130. }
  131. m_astRoot = codeTransformer.Transform();
  132. string retstr = String.Empty;
  133. // standard preamble
  134. //retstr = GenerateLine("using OpenSim.Region.ScriptEngine.Common;");
  135. //retstr += GenerateLine("using System.Collections.Generic;");
  136. //retstr += GenerateLine("");
  137. //retstr += GenerateLine("namespace SecondLife");
  138. //retstr += GenerateLine("{");
  139. m_braceCount++;
  140. //retstr += GenerateIndentedLine("public class Script : OpenSim.Region.ScriptEngine.Common");
  141. //retstr += GenerateIndentedLine("{");
  142. m_braceCount++;
  143. // line number
  144. m_CSharpLine += 9;
  145. // here's the payload
  146. retstr += GenerateLine();
  147. foreach (SYMBOL s in m_astRoot.kids)
  148. retstr += GenerateNode(m_astRoot, s);
  149. // close braces!
  150. m_braceCount--;
  151. //retstr += GenerateIndentedLine("}");
  152. m_braceCount--;
  153. //retstr += GenerateLine("}");
  154. // Removes all carriage return characters which may be generated in Windows platform. Is there
  155. // cleaner way of doing this?
  156. retstr = retstr.Replace("\r", "");
  157. return retstr;
  158. }
  159. /// <summary>
  160. /// Get the set of warnings generated during compilation.
  161. /// </summary>
  162. /// <returns></returns>
  163. public string[] GetWarnings()
  164. {
  165. return m_warnings.ToArray();
  166. }
  167. private void AddWarning(string warning)
  168. {
  169. if (!m_warnings.Contains(warning))
  170. {
  171. m_warnings.Add(warning);
  172. }
  173. }
  174. /// <summary>
  175. /// Recursively called to generate each type of node. Will generate this
  176. /// node, then all it's children.
  177. /// </summary>
  178. /// <param name="previousSymbol">The parent node.</param>
  179. /// <param name="s">The current node to generate code for.</param>
  180. /// <returns>String containing C# code for SYMBOL s.</returns>
  181. private string GenerateNode(SYMBOL previousSymbol, SYMBOL s)
  182. {
  183. string retstr = String.Empty;
  184. // make sure to put type lower in the inheritance hierarchy first
  185. // ie: since IdentArgument and ExpressionArgument inherit from
  186. // Argument, put IdentArgument and ExpressionArgument before Argument
  187. if (s is GlobalFunctionDefinition)
  188. retstr += GenerateGlobalFunctionDefinition((GlobalFunctionDefinition) s);
  189. else if (s is GlobalVariableDeclaration)
  190. retstr += GenerateGlobalVariableDeclaration((GlobalVariableDeclaration) s);
  191. else if (s is State)
  192. retstr += GenerateState((State) s);
  193. else if (s is CompoundStatement)
  194. retstr += GenerateCompoundStatement(previousSymbol, (CompoundStatement) s);
  195. else if (s is Declaration)
  196. retstr += GenerateDeclaration((Declaration) s);
  197. else if (s is Statement)
  198. retstr += GenerateStatement(previousSymbol, (Statement) s);
  199. else if (s is ReturnStatement)
  200. retstr += GenerateReturnStatement((ReturnStatement) s);
  201. else if (s is JumpLabel)
  202. retstr += GenerateJumpLabel((JumpLabel) s);
  203. else if (s is JumpStatement)
  204. retstr += GenerateJumpStatement((JumpStatement) s);
  205. else if (s is StateChange)
  206. retstr += GenerateStateChange((StateChange) s);
  207. else if (s is IfStatement)
  208. retstr += GenerateIfStatement((IfStatement) s);
  209. else if (s is WhileStatement)
  210. retstr += GenerateWhileStatement((WhileStatement) s);
  211. else if (s is DoWhileStatement)
  212. retstr += GenerateDoWhileStatement((DoWhileStatement) s);
  213. else if (s is ForLoop)
  214. retstr += GenerateForLoop((ForLoop) s);
  215. else if (s is ArgumentList)
  216. retstr += GenerateArgumentList((ArgumentList) s);
  217. else if (s is Assignment)
  218. retstr += GenerateAssignment((Assignment) s);
  219. else if (s is BinaryExpression)
  220. retstr += GenerateBinaryExpression((BinaryExpression) s);
  221. else if (s is ParenthesisExpression)
  222. retstr += GenerateParenthesisExpression((ParenthesisExpression) s);
  223. else if (s is UnaryExpression)
  224. retstr += GenerateUnaryExpression((UnaryExpression) s);
  225. else if (s is IncrementDecrementExpression)
  226. retstr += GenerateIncrementDecrementExpression((IncrementDecrementExpression) s);
  227. else if (s is TypecastExpression)
  228. retstr += GenerateTypecastExpression((TypecastExpression) s);
  229. else if (s is FunctionCall)
  230. retstr += GenerateFunctionCall((FunctionCall) s);
  231. else if (s is VectorConstant)
  232. retstr += GenerateVectorConstant((VectorConstant) s);
  233. else if (s is RotationConstant)
  234. retstr += GenerateRotationConstant((RotationConstant) s);
  235. else if (s is ListConstant)
  236. retstr += GenerateListConstant((ListConstant) s);
  237. else if (s is Constant)
  238. retstr += GenerateConstant((Constant) s);
  239. else if (s is IdentDotExpression)
  240. retstr += Generate(CheckName(((IdentDotExpression) s).Name) + "." + ((IdentDotExpression) s).Member, s);
  241. else if (s is IdentExpression)
  242. retstr += GenerateIdentifier(((IdentExpression) s).Name, s);
  243. else if (s is IDENT)
  244. retstr += Generate(CheckName(((TOKEN) s).yytext), s);
  245. else
  246. {
  247. foreach (SYMBOL kid in s.kids)
  248. retstr += GenerateNode(s, kid);
  249. }
  250. return retstr;
  251. }
  252. /// <summary>
  253. /// Generates the code for a GlobalFunctionDefinition node.
  254. /// </summary>
  255. /// <param name="gf">The GlobalFunctionDefinition node.</param>
  256. /// <returns>String containing C# code for GlobalFunctionDefinition gf.</returns>
  257. private string GenerateGlobalFunctionDefinition(GlobalFunctionDefinition gf)
  258. {
  259. string retstr = String.Empty;
  260. // we need to separate the argument declaration list from other kids
  261. List<SYMBOL> argumentDeclarationListKids = new List<SYMBOL>();
  262. List<SYMBOL> remainingKids = new List<SYMBOL>();
  263. foreach (SYMBOL kid in gf.kids)
  264. if (kid is ArgumentDeclarationList)
  265. argumentDeclarationListKids.Add(kid);
  266. else
  267. remainingKids.Add(kid);
  268. retstr += GenerateIndented(String.Format("{0} {1}(", gf.ReturnType, CheckName(gf.Name)), gf);
  269. // print the state arguments, if any
  270. foreach (SYMBOL kid in argumentDeclarationListKids)
  271. retstr += GenerateArgumentDeclarationList((ArgumentDeclarationList) kid);
  272. retstr += GenerateLine(")");
  273. foreach (SYMBOL kid in remainingKids)
  274. retstr += GenerateNode(gf, kid);
  275. return retstr;
  276. }
  277. /// <summary>
  278. /// Generates the code for a GlobalVariableDeclaration node.
  279. /// </summary>
  280. /// <param name="gv">The GlobalVariableDeclaration node.</param>
  281. /// <returns>String containing C# code for GlobalVariableDeclaration gv.</returns>
  282. private string GenerateGlobalVariableDeclaration(GlobalVariableDeclaration gv)
  283. {
  284. string retstr = String.Empty;
  285. foreach (SYMBOL s in gv.kids)
  286. {
  287. retstr += Indent();
  288. retstr += GenerateNode(gv, s);
  289. retstr += GenerateLine(";");
  290. }
  291. return retstr;
  292. }
  293. /// <summary>
  294. /// Generates the code for a State node.
  295. /// </summary>
  296. /// <param name="s">The State node.</param>
  297. /// <returns>String containing C# code for State s.</returns>
  298. private string GenerateState(State s)
  299. {
  300. string retstr = String.Empty;
  301. foreach (SYMBOL kid in s.kids)
  302. if (kid is StateEvent)
  303. retstr += GenerateStateEvent((StateEvent) kid, s.Name);
  304. return retstr;
  305. }
  306. /// <summary>
  307. /// Generates the code for a StateEvent node.
  308. /// </summary>
  309. /// <param name="se">The StateEvent node.</param>
  310. /// <param name="parentStateName">The name of the parent state.</param>
  311. /// <returns>String containing C# code for StateEvent se.</returns>
  312. private string GenerateStateEvent(StateEvent se, string parentStateName)
  313. {
  314. string retstr = String.Empty;
  315. // we need to separate the argument declaration list from other kids
  316. List<SYMBOL> argumentDeclarationListKids = new List<SYMBOL>();
  317. List<SYMBOL> remainingKids = new List<SYMBOL>();
  318. foreach (SYMBOL kid in se.kids)
  319. if (kid is ArgumentDeclarationList)
  320. argumentDeclarationListKids.Add(kid);
  321. else
  322. remainingKids.Add(kid);
  323. // "state" (function) declaration
  324. retstr += GenerateIndented(String.Format("public void {0}_event_{1}(", parentStateName, se.Name), se);
  325. // print the state arguments, if any
  326. foreach (SYMBOL kid in argumentDeclarationListKids)
  327. retstr += GenerateArgumentDeclarationList((ArgumentDeclarationList) kid);
  328. retstr += GenerateLine(")");
  329. foreach (SYMBOL kid in remainingKids)
  330. retstr += GenerateNode(se, kid);
  331. return retstr;
  332. }
  333. /// <summary>
  334. /// Generates the code for an ArgumentDeclarationList node.
  335. /// </summary>
  336. /// <param name="adl">The ArgumentDeclarationList node.</param>
  337. /// <returns>String containing C# code for ArgumentDeclarationList adl.</returns>
  338. private string GenerateArgumentDeclarationList(ArgumentDeclarationList adl)
  339. {
  340. string retstr = String.Empty;
  341. int comma = adl.kids.Count - 1; // tells us whether to print a comma
  342. foreach (Declaration d in adl.kids)
  343. {
  344. retstr += Generate(String.Format("{0} {1}", d.Datatype, CheckName(d.Id)), d);
  345. if (0 < comma--)
  346. retstr += Generate(", ");
  347. }
  348. return retstr;
  349. }
  350. /// <summary>
  351. /// Generates the code for an ArgumentList node.
  352. /// </summary>
  353. /// <param name="al">The ArgumentList node.</param>
  354. /// <returns>String containing C# code for ArgumentList al.</returns>
  355. private string GenerateArgumentList(ArgumentList al)
  356. {
  357. string retstr = String.Empty;
  358. int comma = al.kids.Count - 1; // tells us whether to print a comma
  359. foreach (SYMBOL s in al.kids)
  360. {
  361. retstr += GenerateNode(al, s);
  362. if (0 < comma--)
  363. retstr += Generate(", ");
  364. }
  365. return retstr;
  366. }
  367. /// <summary>
  368. /// Generates the code for a CompoundStatement node.
  369. /// </summary>
  370. /// <param name="cs">The CompoundStatement node.</param>
  371. /// <returns>String containing C# code for CompoundStatement cs.</returns>
  372. private string GenerateCompoundStatement(SYMBOL previousSymbol, CompoundStatement cs)
  373. {
  374. string retstr = String.Empty;
  375. // opening brace
  376. retstr += GenerateIndentedLine("{");
  377. m_braceCount++;
  378. if (m_insertCoopTerminationChecks)
  379. {
  380. // We have to check in event functions as well because the user can manually call these.
  381. if (previousSymbol is GlobalFunctionDefinition
  382. || previousSymbol is WhileStatement
  383. || previousSymbol is DoWhileStatement
  384. || previousSymbol is ForLoop
  385. || previousSymbol is StateEvent)
  386. retstr += GenerateIndentedLine(m_coopTerminationCheck);
  387. }
  388. foreach (SYMBOL kid in cs.kids)
  389. retstr += GenerateNode(cs, kid);
  390. // closing brace
  391. m_braceCount--;
  392. retstr += GenerateIndentedLine("}");
  393. return retstr;
  394. }
  395. /// <summary>
  396. /// Generates the code for a Declaration node.
  397. /// </summary>
  398. /// <param name="d">The Declaration node.</param>
  399. /// <returns>String containing C# code for Declaration d.</returns>
  400. private string GenerateDeclaration(Declaration d)
  401. {
  402. return Generate(String.Format("{0} {1}", d.Datatype, CheckName(d.Id)), d);
  403. }
  404. /// <summary>
  405. /// Generates the code for a Statement node.
  406. /// </summary>
  407. /// <param name="s">The Statement node.</param>
  408. /// <returns>String containing C# code for Statement s.</returns>
  409. private string GenerateStatement(SYMBOL previousSymbol, Statement s)
  410. {
  411. string retstr = String.Empty;
  412. bool printSemicolon = true;
  413. bool transformToBlock = false;
  414. if (m_insertCoopTerminationChecks)
  415. {
  416. // A non-braced single line do while structure cannot contain multiple statements.
  417. // So to insert the termination check we change this to a braced control structure instead.
  418. if (previousSymbol is WhileStatement
  419. || previousSymbol is DoWhileStatement
  420. || previousSymbol is ForLoop)
  421. {
  422. transformToBlock = true;
  423. // FIXME: This will be wrongly indented because the previous for/while/dowhile will have already indented.
  424. retstr += GenerateIndentedLine("{");
  425. retstr += GenerateIndentedLine(m_coopTerminationCheck);
  426. }
  427. }
  428. retstr += Indent();
  429. if (0 < s.kids.Count)
  430. {
  431. // Jump label prints its own colon, we don't need a semicolon.
  432. printSemicolon = !(s.kids.Top is JumpLabel);
  433. // If we encounter a lone Ident, we skip it, since that's a C#
  434. // (MONO) error.
  435. if (!(s.kids.Top is IdentExpression && 1 == s.kids.Count))
  436. foreach (SYMBOL kid in s.kids)
  437. retstr += GenerateNode(s, kid);
  438. }
  439. if (printSemicolon)
  440. retstr += GenerateLine(";");
  441. if (transformToBlock)
  442. {
  443. // FIXME: This will be wrongly indented because the for/while/dowhile is currently handling the unindent
  444. retstr += GenerateIndentedLine("}");
  445. }
  446. return retstr;
  447. }
  448. /// <summary>
  449. /// Generates the code for an Assignment node.
  450. /// </summary>
  451. /// <param name="a">The Assignment node.</param>
  452. /// <returns>String containing C# code for Assignment a.</returns>
  453. private string GenerateAssignment(Assignment a)
  454. {
  455. string retstr = String.Empty;
  456. List<string> identifiers = new List<string>();
  457. checkForMultipleAssignments(identifiers, a);
  458. retstr += GenerateNode(a, (SYMBOL) a.kids.Pop());
  459. retstr += Generate(String.Format(" {0} ", a.AssignmentType), a);
  460. foreach (SYMBOL kid in a.kids)
  461. retstr += GenerateNode(a, kid);
  462. return retstr;
  463. }
  464. // This code checks for LSL of the following forms, and generates a
  465. // warning if it finds them.
  466. //
  467. // list l = [ "foo" ];
  468. // l = (l=[]) + l + ["bar"];
  469. // (produces l=["foo","bar"] in SL but l=["bar"] in OS)
  470. //
  471. // integer i;
  472. // integer j;
  473. // i = (j = 3) + (j = 4) + (j = 5);
  474. // (produces j=3 in SL but j=5 in OS)
  475. //
  476. // Without this check, that code passes compilation, but does not do what
  477. // the end user expects, because LSL in SL evaluates right to left instead
  478. // of left to right.
  479. //
  480. // The theory here is that producing an error and alerting the end user that
  481. // something needs to change is better than silently generating incorrect code.
  482. private void checkForMultipleAssignments(List<string> identifiers, SYMBOL s)
  483. {
  484. if (s is Assignment)
  485. {
  486. Assignment a = (Assignment)s;
  487. string newident = null;
  488. if (a.kids[0] is Declaration)
  489. {
  490. newident = ((Declaration)a.kids[0]).Id;
  491. }
  492. else if (a.kids[0] is IDENT)
  493. {
  494. newident = ((IDENT)a.kids[0]).yytext;
  495. }
  496. else if (a.kids[0] is IdentDotExpression)
  497. {
  498. newident = ((IdentDotExpression)a.kids[0]).Name; // +"." + ((IdentDotExpression)a.kids[0]).Member;
  499. }
  500. else
  501. {
  502. 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));
  503. }
  504. if (identifiers.Contains(newident))
  505. {
  506. 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));
  507. }
  508. identifiers.Add(newident);
  509. }
  510. int index;
  511. for (index = 0; index < s.kids.Count; index++)
  512. {
  513. checkForMultipleAssignments(identifiers, (SYMBOL) s.kids[index]);
  514. }
  515. }
  516. /// <summary>
  517. /// Generates the code for a ReturnStatement node.
  518. /// </summary>
  519. /// <param name="rs">The ReturnStatement node.</param>
  520. /// <returns>String containing C# code for ReturnStatement rs.</returns>
  521. private string GenerateReturnStatement(ReturnStatement rs)
  522. {
  523. string retstr = String.Empty;
  524. retstr += Generate("return ", rs);
  525. foreach (SYMBOL kid in rs.kids)
  526. retstr += GenerateNode(rs, kid);
  527. return retstr;
  528. }
  529. /// <summary>
  530. /// Generates the code for a JumpLabel node.
  531. /// </summary>
  532. /// <param name="jl">The JumpLabel node.</param>
  533. /// <returns>String containing C# code for JumpLabel jl.</returns>
  534. private string GenerateJumpLabel(JumpLabel jl)
  535. {
  536. string labelStatement;
  537. if (m_insertCoopTerminationChecks)
  538. labelStatement = m_coopTerminationCheck;
  539. else
  540. labelStatement = "NoOp();";
  541. return GenerateLine(String.Format("{0}: {1}", CheckName(jl.LabelName), labelStatement), jl);
  542. }
  543. /// <summary>
  544. /// Generates the code for a JumpStatement node.
  545. /// </summary>
  546. /// <param name="js">The JumpStatement node.</param>
  547. /// <returns>String containing C# code for JumpStatement js.</returns>
  548. private string GenerateJumpStatement(JumpStatement js)
  549. {
  550. return Generate(String.Format("goto {0}", CheckName(js.TargetName)), js);
  551. }
  552. /// <summary>
  553. /// Generates the code for an IfStatement node.
  554. /// </summary>
  555. /// <param name="ifs">The IfStatement node.</param>
  556. /// <returns>String containing C# code for IfStatement ifs.</returns>
  557. private string GenerateIfStatement(IfStatement ifs)
  558. {
  559. string retstr = String.Empty;
  560. retstr += GenerateIndented("if (", ifs);
  561. retstr += GenerateNode(ifs, (SYMBOL) ifs.kids.Pop());
  562. retstr += GenerateLine(")");
  563. // CompoundStatement handles indentation itself but we need to do it
  564. // otherwise.
  565. bool indentHere = ifs.kids.Top is Statement;
  566. if (indentHere) m_braceCount++;
  567. retstr += GenerateNode(ifs, (SYMBOL) ifs.kids.Pop());
  568. if (indentHere) m_braceCount--;
  569. if (0 < ifs.kids.Count) // do it again for an else
  570. {
  571. retstr += GenerateIndentedLine("else", ifs);
  572. indentHere = ifs.kids.Top is Statement;
  573. if (indentHere) m_braceCount++;
  574. retstr += GenerateNode(ifs, (SYMBOL) ifs.kids.Pop());
  575. if (indentHere) m_braceCount--;
  576. }
  577. return retstr;
  578. }
  579. /// <summary>
  580. /// Generates the code for a StateChange node.
  581. /// </summary>
  582. /// <param name="sc">The StateChange node.</param>
  583. /// <returns>String containing C# code for StateChange sc.</returns>
  584. private string GenerateStateChange(StateChange sc)
  585. {
  586. return Generate(String.Format("state(\"{0}\")", sc.NewState), sc);
  587. }
  588. /// <summary>
  589. /// Generates the code for a WhileStatement node.
  590. /// </summary>
  591. /// <param name="ws">The WhileStatement node.</param>
  592. /// <returns>String containing C# code for WhileStatement ws.</returns>
  593. private string GenerateWhileStatement(WhileStatement ws)
  594. {
  595. string retstr = String.Empty;
  596. retstr += GenerateIndented("while (", ws);
  597. retstr += GenerateNode(ws, (SYMBOL) ws.kids.Pop());
  598. retstr += GenerateLine(")");
  599. // CompoundStatement handles indentation itself but we need to do it
  600. // otherwise.
  601. bool indentHere = ws.kids.Top is Statement;
  602. if (indentHere) m_braceCount++;
  603. retstr += GenerateNode(ws, (SYMBOL) ws.kids.Pop());
  604. if (indentHere) m_braceCount--;
  605. return retstr;
  606. }
  607. /// <summary>
  608. /// Generates the code for a DoWhileStatement node.
  609. /// </summary>
  610. /// <param name="dws">The DoWhileStatement node.</param>
  611. /// <returns>String containing C# code for DoWhileStatement dws.</returns>
  612. private string GenerateDoWhileStatement(DoWhileStatement dws)
  613. {
  614. string retstr = String.Empty;
  615. retstr += GenerateIndentedLine("do", dws);
  616. // CompoundStatement handles indentation itself but we need to do it
  617. // otherwise.
  618. bool indentHere = dws.kids.Top is Statement;
  619. if (indentHere) m_braceCount++;
  620. retstr += GenerateNode(dws, (SYMBOL) dws.kids.Pop());
  621. if (indentHere) m_braceCount--;
  622. retstr += GenerateIndented("while (", dws);
  623. retstr += GenerateNode(dws, (SYMBOL) dws.kids.Pop());
  624. retstr += GenerateLine(");");
  625. return retstr;
  626. }
  627. /// <summary>
  628. /// Generates the code for a ForLoop node.
  629. /// </summary>
  630. /// <param name="fl">The ForLoop node.</param>
  631. /// <returns>String containing C# code for ForLoop fl.</returns>
  632. private string GenerateForLoop(ForLoop fl)
  633. {
  634. string retstr = String.Empty;
  635. retstr += GenerateIndented("for (", fl);
  636. // It's possible that we don't have an assignment, in which case
  637. // the child will be null and we only print the semicolon.
  638. // for (x = 0; x < 10; x++)
  639. // ^^^^^
  640. ForLoopStatement s = (ForLoopStatement) fl.kids.Pop();
  641. if (null != s)
  642. {
  643. retstr += GenerateForLoopStatement(s);
  644. }
  645. retstr += Generate("; ");
  646. // for (x = 0; x < 10; x++)
  647. // ^^^^^^
  648. retstr += GenerateNode(fl, (SYMBOL) fl.kids.Pop());
  649. retstr += Generate("; ");
  650. // for (x = 0; x < 10; x++)
  651. // ^^^
  652. retstr += GenerateForLoopStatement((ForLoopStatement) fl.kids.Pop());
  653. retstr += GenerateLine(")");
  654. // CompoundStatement handles indentation itself but we need to do it
  655. // otherwise.
  656. bool indentHere = fl.kids.Top is Statement;
  657. if (indentHere) m_braceCount++;
  658. retstr += GenerateNode(fl, (SYMBOL) fl.kids.Pop());
  659. if (indentHere) m_braceCount--;
  660. return retstr;
  661. }
  662. /// <summary>
  663. /// Generates the code for a ForLoopStatement node.
  664. /// </summary>
  665. /// <param name="fls">The ForLoopStatement node.</param>
  666. /// <returns>String containing C# code for ForLoopStatement fls.</returns>
  667. private string GenerateForLoopStatement(ForLoopStatement fls)
  668. {
  669. string retstr = String.Empty;
  670. int comma = fls.kids.Count - 1; // tells us whether to print a comma
  671. // It's possible that all we have is an empty Ident, for example:
  672. //
  673. // for (x; x < 10; x++) { ... }
  674. //
  675. // Which is illegal in C# (MONO). We'll skip it.
  676. if (fls.kids.Top is IdentExpression && 1 == fls.kids.Count)
  677. return retstr;
  678. for (int i = 0; i < fls.kids.Count; i++)
  679. {
  680. SYMBOL s = (SYMBOL)fls.kids[i];
  681. // Statements surrounded by parentheses in for loops
  682. //
  683. // e.g. for ((i = 0), (j = 7); (i < 10); (++i))
  684. //
  685. // are legal in LSL but not in C# so we need to discard the parentheses
  686. //
  687. // The following, however, does not appear to be legal in LLS
  688. //
  689. // for ((i = 0, j = 7); (i < 10); (++i))
  690. //
  691. // As of Friday 20th November 2009, the Linden Lab simulators appear simply never to compile or run this
  692. // script but with no debug or warnings at all! Therefore, we won't deal with this yet (which looks
  693. // like it would be considerably more complicated to handle).
  694. while (s is ParenthesisExpression)
  695. s = (SYMBOL)s.kids.Pop();
  696. retstr += GenerateNode(fls, s);
  697. if (0 < comma--)
  698. retstr += Generate(", ");
  699. }
  700. return retstr;
  701. }
  702. /// <summary>
  703. /// Generates the code for a BinaryExpression node.
  704. /// </summary>
  705. /// <param name="be">The BinaryExpression node.</param>
  706. /// <returns>String containing C# code for BinaryExpression be.</returns>
  707. private string GenerateBinaryExpression(BinaryExpression be)
  708. {
  709. string retstr = String.Empty;
  710. if (be.ExpressionSymbol.Equals("&&") || be.ExpressionSymbol.Equals("||"))
  711. {
  712. // special case handling for logical and/or, see Mantis 3174
  713. retstr += "((bool)(";
  714. retstr += GenerateNode(be, (SYMBOL)be.kids.Pop());
  715. retstr += "))";
  716. retstr += Generate(String.Format(" {0} ", be.ExpressionSymbol.Substring(0,1)), be);
  717. retstr += "((bool)(";
  718. foreach (SYMBOL kid in be.kids)
  719. retstr += GenerateNode(be, kid);
  720. retstr += "))";
  721. }
  722. else
  723. {
  724. retstr += GenerateNode(be, (SYMBOL)be.kids.Pop());
  725. retstr += Generate(String.Format(" {0} ", be.ExpressionSymbol), be);
  726. foreach (SYMBOL kid in be.kids)
  727. retstr += GenerateNode(be, kid);
  728. }
  729. return retstr;
  730. }
  731. /// <summary>
  732. /// Generates the code for a UnaryExpression node.
  733. /// </summary>
  734. /// <param name="ue">The UnaryExpression node.</param>
  735. /// <returns>String containing C# code for UnaryExpression ue.</returns>
  736. private string GenerateUnaryExpression(UnaryExpression ue)
  737. {
  738. string retstr = String.Empty;
  739. retstr += Generate(ue.UnarySymbol, ue);
  740. retstr += GenerateNode(ue, (SYMBOL) ue.kids.Pop());
  741. return retstr;
  742. }
  743. /// <summary>
  744. /// Generates the code for a ParenthesisExpression node.
  745. /// </summary>
  746. /// <param name="pe">The ParenthesisExpression node.</param>
  747. /// <returns>String containing C# code for ParenthesisExpression pe.</returns>
  748. private string GenerateParenthesisExpression(ParenthesisExpression pe)
  749. {
  750. string retstr = String.Empty;
  751. retstr += Generate("(");
  752. foreach (SYMBOL kid in pe.kids)
  753. retstr += GenerateNode(pe, kid);
  754. retstr += Generate(")");
  755. return retstr;
  756. }
  757. /// <summary>
  758. /// Generates the code for a IncrementDecrementExpression node.
  759. /// </summary>
  760. /// <param name="ide">The IncrementDecrementExpression node.</param>
  761. /// <returns>String containing C# code for IncrementDecrementExpression ide.</returns>
  762. private string GenerateIncrementDecrementExpression(IncrementDecrementExpression ide)
  763. {
  764. string retstr = String.Empty;
  765. if (0 < ide.kids.Count)
  766. {
  767. IdentDotExpression dot = (IdentDotExpression) ide.kids.Top;
  768. retstr += Generate(String.Format("{0}", ide.PostOperation ? CheckName(dot.Name) + "." + dot.Member + ide.Operation : ide.Operation + CheckName(dot.Name) + "." + dot.Member), ide);
  769. }
  770. else
  771. retstr += Generate(String.Format("{0}", ide.PostOperation ? CheckName(ide.Name) + ide.Operation : ide.Operation + CheckName(ide.Name)), ide);
  772. return retstr;
  773. }
  774. /// <summary>
  775. /// Generates the code for a TypecastExpression node.
  776. /// </summary>
  777. /// <param name="te">The TypecastExpression node.</param>
  778. /// <returns>String containing C# code for TypecastExpression te.</returns>
  779. private string GenerateTypecastExpression(TypecastExpression te)
  780. {
  781. string retstr = String.Empty;
  782. // we wrap all typecasted statements in parentheses
  783. retstr += Generate(String.Format("({0}) (", te.TypecastType), te);
  784. retstr += GenerateNode(te, (SYMBOL) te.kids.Pop());
  785. retstr += Generate(")");
  786. return retstr;
  787. }
  788. /// <summary>
  789. /// Generates the code for an identifier
  790. /// </summary>
  791. /// <param name="id">The symbol name</param>
  792. /// <param name="s">The Symbol node.</param>
  793. /// <returns>String containing C# code for identifier reference.</returns>
  794. private string GenerateIdentifier(string id, SYMBOL s)
  795. {
  796. if (m_comms != null)
  797. {
  798. object value = m_comms.LookupModConstant(id);
  799. if (value != null)
  800. {
  801. string retval = null;
  802. if (value is int)
  803. retval = String.Format("new LSL_Types.LSLInteger({0})",((int)value).ToString());
  804. else if (value is float)
  805. retval = String.Format("new LSL_Types.LSLFloat({0})",((float)value).ToString());
  806. else if (value is string)
  807. retval = String.Format("new LSL_Types.LSLString(\"{0}\")",((string)value));
  808. else if (value is OpenMetaverse.UUID)
  809. retval = String.Format("new LSL_Types.key(\"{0}\")",((OpenMetaverse.UUID)value).ToString());
  810. else if (value is OpenMetaverse.Vector3)
  811. retval = String.Format("new LSL_Types.Vector3(\"{0}\")",((OpenMetaverse.Vector3)value).ToString());
  812. else if (value is OpenMetaverse.Quaternion)
  813. retval = String.Format("new LSL_Types.Quaternion(\"{0}\")",((OpenMetaverse.Quaternion)value).ToString());
  814. else retval = id;
  815. return Generate(retval, s);
  816. }
  817. }
  818. return Generate(CheckName(id), s);
  819. }
  820. /// <summary>
  821. /// Generates the code for a FunctionCall node.
  822. /// </summary>
  823. /// <param name="fc">The FunctionCall node.</param>
  824. /// <returns>String containing C# code for FunctionCall fc.</returns>
  825. private string GenerateFunctionCall(FunctionCall fc)
  826. {
  827. string retstr = String.Empty;
  828. string modinvoke = null;
  829. if (m_comms != null)
  830. modinvoke = m_comms.LookupModInvocation(fc.Id);
  831. if (modinvoke != null)
  832. {
  833. if (fc.kids[0] is ArgumentList)
  834. {
  835. if ((fc.kids[0] as ArgumentList).kids.Count == 0)
  836. retstr += Generate(String.Format("{0}(\"{1}\"",modinvoke,fc.Id), fc);
  837. else
  838. retstr += Generate(String.Format("{0}(\"{1}\",",modinvoke,fc.Id), fc);
  839. }
  840. }
  841. else
  842. {
  843. retstr += Generate(String.Format("{0}(", CheckName(fc.Id)), fc);
  844. }
  845. foreach (SYMBOL kid in fc.kids)
  846. retstr += GenerateNode(fc, kid);
  847. retstr += Generate(")");
  848. return retstr;
  849. }
  850. /// <summary>
  851. /// Generates the code for a Constant node.
  852. /// </summary>
  853. /// <param name="c">The Constant node.</param>
  854. /// <returns>String containing C# code for Constant c.</returns>
  855. private string GenerateConstant(Constant c)
  856. {
  857. string retstr = String.Empty;
  858. // Supprt LSL's weird acceptance of floats with no trailing digits
  859. // after the period. Turn float x = 10.; into float x = 10.0;
  860. if ("LSL_Types.LSLFloat" == c.Type)
  861. {
  862. int dotIndex = c.Value.IndexOf('.') + 1;
  863. if (0 < dotIndex && (dotIndex == c.Value.Length || !Char.IsDigit(c.Value[dotIndex])))
  864. c.Value = c.Value.Insert(dotIndex, "0");
  865. c.Value = "new LSL_Types.LSLFloat("+c.Value+")";
  866. }
  867. else if ("LSL_Types.LSLInteger" == c.Type)
  868. {
  869. c.Value = "new LSL_Types.LSLInteger("+c.Value+")";
  870. }
  871. else if ("LSL_Types.LSLString" == c.Type)
  872. {
  873. c.Value = "new LSL_Types.LSLString(\""+c.Value+"\")";
  874. }
  875. retstr += Generate(c.Value, c);
  876. return retstr;
  877. }
  878. /// <summary>
  879. /// Generates the code for a VectorConstant node.
  880. /// </summary>
  881. /// <param name="vc">The VectorConstant node.</param>
  882. /// <returns>String containing C# code for VectorConstant vc.</returns>
  883. private string GenerateVectorConstant(VectorConstant vc)
  884. {
  885. string retstr = String.Empty;
  886. retstr += Generate(String.Format("new {0}(", vc.Type), vc);
  887. retstr += GenerateNode(vc, (SYMBOL) vc.kids.Pop());
  888. retstr += Generate(", ");
  889. retstr += GenerateNode(vc, (SYMBOL) vc.kids.Pop());
  890. retstr += Generate(", ");
  891. retstr += GenerateNode(vc, (SYMBOL) vc.kids.Pop());
  892. retstr += Generate(")");
  893. return retstr;
  894. }
  895. /// <summary>
  896. /// Generates the code for a RotationConstant node.
  897. /// </summary>
  898. /// <param name="rc">The RotationConstant node.</param>
  899. /// <returns>String containing C# code for RotationConstant rc.</returns>
  900. private string GenerateRotationConstant(RotationConstant rc)
  901. {
  902. string retstr = String.Empty;
  903. retstr += Generate(String.Format("new {0}(", rc.Type), rc);
  904. retstr += GenerateNode(rc, (SYMBOL) rc.kids.Pop());
  905. retstr += Generate(", ");
  906. retstr += GenerateNode(rc, (SYMBOL) rc.kids.Pop());
  907. retstr += Generate(", ");
  908. retstr += GenerateNode(rc, (SYMBOL) rc.kids.Pop());
  909. retstr += Generate(", ");
  910. retstr += GenerateNode(rc, (SYMBOL) rc.kids.Pop());
  911. retstr += Generate(")");
  912. return retstr;
  913. }
  914. /// <summary>
  915. /// Generates the code for a ListConstant node.
  916. /// </summary>
  917. /// <param name="lc">The ListConstant node.</param>
  918. /// <returns>String containing C# code for ListConstant lc.</returns>
  919. private string GenerateListConstant(ListConstant lc)
  920. {
  921. string retstr = String.Empty;
  922. retstr += Generate(String.Format("new {0}(", lc.Type), lc);
  923. foreach (SYMBOL kid in lc.kids)
  924. retstr += GenerateNode(lc, kid);
  925. retstr += Generate(")");
  926. return retstr;
  927. }
  928. /// <summary>
  929. /// Prints a newline.
  930. /// </summary>
  931. /// <returns>A newline.</returns>
  932. private string GenerateLine()
  933. {
  934. return GenerateLine("");
  935. }
  936. /// <summary>
  937. /// Prints text, followed by a newline.
  938. /// </summary>
  939. /// <param name="s">String of text to print.</param>
  940. /// <returns>String s followed by newline.</returns>
  941. private string GenerateLine(string s)
  942. {
  943. return GenerateLine(s, null);
  944. }
  945. /// <summary>
  946. /// Prints text, followed by a newline.
  947. /// </summary>
  948. /// <param name="s">String of text to print.</param>
  949. /// <param name="sym">Symbol being generated to extract original line
  950. /// number and column from.</param>
  951. /// <returns>String s followed by newline.</returns>
  952. private string GenerateLine(string s, SYMBOL sym)
  953. {
  954. string retstr = Generate(s, sym) + "\n";
  955. m_CSharpLine++;
  956. m_CSharpCol = 1;
  957. return retstr;
  958. }
  959. /// <summary>
  960. /// Prints text.
  961. /// </summary>
  962. /// <param name="s">String of text to print.</param>
  963. /// <returns>String s.</returns>
  964. private string Generate(string s)
  965. {
  966. return Generate(s, null);
  967. }
  968. /// <summary>
  969. /// Prints text.
  970. /// </summary>
  971. /// <param name="s">String of text to print.</param>
  972. /// <param name="sym">Symbol being generated to extract original line
  973. /// number and column from.</param>
  974. /// <returns>String s.</returns>
  975. private string Generate(string s, SYMBOL sym)
  976. {
  977. if (null != sym)
  978. m_positionMap.Add(new KeyValuePair<int, int>(m_CSharpLine, m_CSharpCol), new KeyValuePair<int, int>(sym.Line, sym.Position));
  979. m_CSharpCol += s.Length;
  980. return s;
  981. }
  982. /// <summary>
  983. /// Prints text correctly indented, followed by a newline.
  984. /// </summary>
  985. /// <param name="s">String of text to print.</param>
  986. /// <returns>Properly indented string s followed by newline.</returns>
  987. private string GenerateIndentedLine(string s)
  988. {
  989. return GenerateIndentedLine(s, null);
  990. }
  991. /// <summary>
  992. /// Prints text correctly indented, followed by a newline.
  993. /// </summary>
  994. /// <param name="s">String of text to print.</param>
  995. /// <param name="sym">Symbol being generated to extract original line
  996. /// number and column from.</param>
  997. /// <returns>Properly indented string s followed by newline.</returns>
  998. private string GenerateIndentedLine(string s, SYMBOL sym)
  999. {
  1000. string retstr = GenerateIndented(s, sym) + "\n";
  1001. m_CSharpLine++;
  1002. m_CSharpCol = 1;
  1003. return retstr;
  1004. }
  1005. /// <summary>
  1006. /// Prints text correctly indented.
  1007. /// </summary>
  1008. /// <param name="s">String of text to print.</param>
  1009. /// <returns>Properly indented string s.</returns>
  1010. //private string GenerateIndented(string s)
  1011. //{
  1012. // return GenerateIndented(s, null);
  1013. //}
  1014. // THIS FUNCTION IS COMMENTED OUT TO SUPPRESS WARNINGS
  1015. /// <summary>
  1016. /// Prints text correctly indented.
  1017. /// </summary>
  1018. /// <param name="s">String of text to print.</param>
  1019. /// <param name="sym">Symbol being generated to extract original line
  1020. /// number and column from.</param>
  1021. /// <returns>Properly indented string s.</returns>
  1022. private string GenerateIndented(string s, SYMBOL sym)
  1023. {
  1024. string retstr = Indent() + s;
  1025. if (null != sym)
  1026. m_positionMap.Add(new KeyValuePair<int, int>(m_CSharpLine, m_CSharpCol), new KeyValuePair<int, int>(sym.Line, sym.Position));
  1027. m_CSharpCol += s.Length;
  1028. return retstr;
  1029. }
  1030. /// <summary>
  1031. /// Prints correct indentation.
  1032. /// </summary>
  1033. /// <returns>Indentation based on brace count.</returns>
  1034. private string Indent()
  1035. {
  1036. string retstr = String.Empty;
  1037. for (int i = 0; i < m_braceCount; i++)
  1038. for (int j = 0; j < m_indentWidth; j++)
  1039. {
  1040. retstr += " ";
  1041. m_CSharpCol++;
  1042. }
  1043. return retstr;
  1044. }
  1045. /// <summary>
  1046. /// Returns the passed name with an underscore prepended if that name is a reserved word in C#
  1047. /// and not resevered in LSL otherwise it just returns the passed name.
  1048. ///
  1049. /// This makes no attempt to cache the results to minimise future lookups. For a non trivial
  1050. /// scripts the number of unique identifiers could easily grow to the size of the reserved word
  1051. /// list so maintaining a list or dictionary and doing the lookup there firstwould probably not
  1052. /// give any real speed advantage.
  1053. ///
  1054. /// I believe there is a class Microsoft.CSharp.CSharpCodeProvider that has a function
  1055. /// CreateValidIdentifier(str) that will return either the value of str if it is not a C#
  1056. /// key word or "_"+str if it is. But availability under Mono?
  1057. /// </summary>
  1058. private string CheckName(string s)
  1059. {
  1060. if (CSReservedWords.IsReservedWord(s))
  1061. return "@" + s;
  1062. else
  1063. return s;
  1064. }
  1065. }
  1066. }