CSCodeGenerator.cs 46 KB

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