2008-07-08 03:02:11 +00:00
/ *
* Copyright ( c ) Contributors , http : //opensimulator.org/
* See CONTRIBUTORS . TXT for a full list of copyright holders .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions are met :
* * Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* * Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
2009-06-01 06:37:14 +00:00
* * Neither the name of the OpenSimulator Project nor the
2008-07-08 03:02:11 +00:00
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ` ` AS IS ' ' AND ANY
* EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED . IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES
* ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ;
* LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
* /
using System ;
2016-08-31 08:15:08 +00:00
using System.Text ;
2008-07-08 03:02:11 +00:00
using System.IO ;
using System.Collections.Generic ;
2012-02-07 17:44:37 +00:00
using System.Reflection ;
using log4net ;
2008-07-08 03:02:11 +00:00
using Tools ;
2012-03-15 20:16:02 +00:00
using OpenSim.Region.Framework.Interfaces ;
2008-07-08 03:02:11 +00:00
namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
{
2008-07-12 01:34:36 +00:00
public class CSCodeGenerator : ICodeConverter
2008-07-08 03:02:11 +00:00
{
2012-07-31 17:45:37 +00:00
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
2012-02-07 17:44:37 +00:00
2016-08-31 08:15:08 +00:00
private static yyLSLSyntax yyLSL = new yyLSLSyntax ( ) ;
2008-07-08 03:02:11 +00:00
private SYMBOL m_astRoot = null ;
2008-07-23 02:51:45 +00:00
private Dictionary < KeyValuePair < int , int > , KeyValuePair < int , int > > m_positionMap ;
private int m_braceCount ; // for indentation
private int m_CSharpLine ; // the current line of generated C# code
private int m_CSharpCol ; // the current column of generated C# code
2009-02-23 02:43:51 +00:00
private List < string > m_warnings = new List < string > ( ) ;
2012-03-15 20:16:02 +00:00
private IScriptModuleComms m_comms = null ;
2008-07-08 03:02:11 +00:00
2013-01-17 23:39:09 +00:00
private bool m_insertCoopTerminationChecks ;
private static string m_coopTerminationCheck = "opensim_reserved_CheckForCoopTermination();" ;
/// <summary>
/// Keep a record of the previous node when we do the parsing.
/// </summary>
/// <remarks>
/// We do this here because the parser generated by CSTools does not retain a reference to its parent node.
/// The previous node is required so we can correctly insert co-op termination checks when required.
/// </remarks>
// private SYMBOL m_previousNode;
2008-07-08 03:02:11 +00:00
/// <summary>
2008-07-23 02:51:45 +00:00
/// Creates an 'empty' CSCodeGenerator instance.
2008-07-08 03:02:11 +00:00
/// </summary>
2008-07-12 01:34:36 +00:00
public CSCodeGenerator ( )
2008-07-08 03:02:11 +00:00
{
2012-03-15 20:16:02 +00:00
m_comms = null ;
ResetCounters ( ) ;
}
2013-01-17 23:39:09 +00:00
public CSCodeGenerator ( IScriptModuleComms comms , bool insertCoopTerminationChecks )
2012-03-15 20:16:02 +00:00
{
m_comms = comms ;
2013-01-17 23:39:09 +00:00
m_insertCoopTerminationChecks = insertCoopTerminationChecks ;
2008-07-23 02:51:45 +00:00
ResetCounters ( ) ;
2008-07-08 03:02:11 +00:00
}
/// <summary>
2008-07-23 02:51:45 +00:00
/// Get the mapping between LSL and C# line/column number.
2008-07-08 03:02:11 +00:00
/// </summary>
2008-07-23 02:51:45 +00:00
/// <returns>Dictionary\<KeyValuePair\<int, int\>, KeyValuePair\<int, int\>\>.</returns>
public Dictionary < KeyValuePair < int , int > , KeyValuePair < int , int > > PositionMap
{
get { return m_positionMap ; }
}
/// <summary>
/// Get the mapping between LSL and C# line/column number.
/// </summary>
/// <returns>SYMBOL pointing to root of the abstract syntax tree.</returns>
public SYMBOL ASTRoot
{
get { return m_astRoot ; }
}
2016-08-31 08:15:08 +00:00
public void Clear ( )
{
m_astRoot . kids = null ;
m_astRoot . yylx = null ;
m_astRoot . yyps = null ;
m_astRoot = null ;
m_positionMap = null ;
m_warnings . Clear ( ) ;
m_comms = null ;
}
2008-07-23 02:51:45 +00:00
/// <summary>
/// Resets various counters and metadata.
/// </summary>
private void ResetCounters ( )
2008-07-08 03:02:11 +00:00
{
m_braceCount = 0 ;
2008-07-23 02:51:45 +00:00
m_CSharpLine = 0 ;
m_CSharpCol = 1 ;
m_positionMap = new Dictionary < KeyValuePair < int , int > , KeyValuePair < int , int > > ( ) ;
m_astRoot = null ;
2008-07-08 03:02:11 +00:00
}
2016-08-31 08:15:08 +00:00
public string Convert ( string script )
{
StringBuilder sb = new StringBuilder ( 4096 ) ;
Convert ( script , sb ) ;
return sb . ToString ( ) ;
}
2008-07-08 03:02:11 +00:00
/// <summary>
/// Generate the code from the AST we have.
/// </summary>
2008-07-23 02:51:45 +00:00
/// <param name="script">The LSL source as a string.</param>
2008-07-08 03:02:11 +00:00
/// <returns>String containing the generated C# code.</returns>
2016-08-31 08:15:08 +00:00
public void Convert ( string script , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
2012-02-07 17:44:37 +00:00
// m_log.DebugFormat("[CS CODE GENERATOR]: Converting to C#\n{0}", script);
2009-02-25 04:29:02 +00:00
m_warnings . Clear ( ) ;
2008-07-23 02:51:45 +00:00
ResetCounters ( ) ;
2016-08-31 08:15:08 +00:00
ErrorHandler errorHandler = new ErrorHandler ( true ) ;
Parser p = new LSLSyntax ( yyLSL , errorHandler ) ;
2009-06-07 10:22:55 +00:00
2008-09-27 05:31:43 +00:00
LSL2CSCodeTransformer codeTransformer ;
try
{
codeTransformer = new LSL2CSCodeTransformer ( p . Parse ( script ) ) ;
}
catch ( CSToolsException e )
{
string message ;
// LL start numbering lines at 0 - geeks!
2008-10-07 21:59:56 +00:00
// Also need to subtract one line we prepend!
2008-09-27 05:31:43 +00:00
/ /
2008-10-07 21:59:56 +00:00
string emessage = e . Message ;
string slinfo = e . slInfo . ToString ( ) ;
// Remove wrong line number info
/ /
if ( emessage . StartsWith ( slinfo + ": " ) )
emessage = emessage . Substring ( slinfo . Length + 2 ) ;
2009-12-22 09:24:01 +00:00
message = String . Format ( "({0},{1}) {2}" ,
2012-03-06 02:01:47 +00:00
e . slInfo . lineNumber - 1 ,
2008-10-07 21:59:56 +00:00
e . slInfo . charPosition - 1 , emessage ) ;
2008-09-27 05:31:43 +00:00
throw new Exception ( message ) ;
}
2008-07-12 01:34:36 +00:00
m_astRoot = codeTransformer . Transform ( ) ;
2008-07-23 02:51:45 +00:00
2008-07-08 03:02:11 +00:00
// standard preamble
2016-08-31 13:36:07 +00:00
2008-07-23 02:51:45 +00:00
m_braceCount + + ;
m_braceCount + + ;
// line number
2016-08-31 13:36:07 +00:00
m_CSharpLine + = 10 ;
2008-07-08 03:02:11 +00:00
// here's the payload
2016-08-31 08:15:08 +00:00
sb . Append ( "\n" ) ;
2008-07-08 03:02:11 +00:00
foreach ( SYMBOL s in m_astRoot . kids )
2016-08-31 08:15:08 +00:00
GenerateNodeToSB ( m_astRoot , s , sb ) ;
codeTransformer = null ;
p . m_lexer . m_buf = null ;
p . m_lexer . yytext = null ;
p . m_lexer = null ;
p . m_symbols = null ;
p = null ;
errorHandler = null ;
2008-07-08 03:02:11 +00:00
// close braces!
2016-08-31 08:15:08 +00:00
// m_braceCount--;
2008-07-23 02:51:45 +00:00
//retstr += GenerateIndentedLine("}");
2016-08-31 08:15:08 +00:00
// m_braceCount--;
2008-07-23 02:51:45 +00:00
//retstr += GenerateLine("}");
2008-07-08 03:02:11 +00:00
2009-02-09 00:59:02 +00:00
// Removes all carriage return characters which may be generated in Windows platform. Is there
// cleaner way of doing this?
2016-08-31 08:15:08 +00:00
// sb.Replace("\r", "");
2008-07-08 03:02:11 +00:00
}
2009-02-23 02:43:51 +00:00
/// <summary>
/// Get the set of warnings generated during compilation.
/// </summary>
/// <returns></returns>
public string [ ] GetWarnings ( )
{
return m_warnings . ToArray ( ) ;
}
private void AddWarning ( string warning )
{
if ( ! m_warnings . Contains ( warning ) )
{
m_warnings . Add ( warning ) ;
}
}
2008-07-08 03:02:11 +00:00
/// <summary>
/// Recursively called to generate each type of node. Will generate this
/// node, then all it's children.
/// </summary>
2013-01-17 23:39:09 +00:00
/// <param name="previousSymbol">The parent node.</param>
2008-07-08 03:02:11 +00:00
/// <param name="s">The current node to generate code for.</param>
/// <returns>String containing C# code for SYMBOL s.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateNodeToSB ( SYMBOL previousSymbol , SYMBOL s , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
// make sure to put type lower in the inheritance hierarchy first
// ie: since IdentArgument and ExpressionArgument inherit from
// Argument, put IdentArgument and ExpressionArgument before Argument
if ( s is GlobalFunctionDefinition )
2016-08-31 08:15:08 +00:00
GenerateGlobalFunctionDefinition ( ( GlobalFunctionDefinition ) s , sb ) ;
2008-07-08 03:02:11 +00:00
else if ( s is GlobalVariableDeclaration )
2016-08-31 08:15:08 +00:00
GenerateGlobalVariableDeclaration ( ( GlobalVariableDeclaration ) s , sb ) ;
2008-07-08 03:02:11 +00:00
else if ( s is State )
2016-08-31 08:15:08 +00:00
GenerateState ( ( State ) s , sb ) ;
2008-07-08 03:02:11 +00:00
else if ( s is CompoundStatement )
2016-08-31 08:15:08 +00:00
GenerateCompoundStatement ( previousSymbol , ( CompoundStatement ) s , sb ) ;
2008-07-08 03:02:11 +00:00
else if ( s is Declaration )
2016-08-31 08:15:08 +00:00
GenerateDeclaration ( ( Declaration ) s , sb ) ;
2008-07-08 03:02:11 +00:00
else if ( s is Statement )
2016-08-31 08:15:08 +00:00
GenerateStatement ( previousSymbol , ( Statement ) s , sb ) ;
2008-07-08 03:02:11 +00:00
else if ( s is ReturnStatement )
2016-08-31 08:15:08 +00:00
GenerateReturnStatement ( ( ReturnStatement ) s , sb ) ;
2008-07-08 03:02:11 +00:00
else if ( s is JumpLabel )
2016-08-31 08:15:08 +00:00
GenerateJumpLabel ( ( JumpLabel ) s , sb ) ;
2008-07-08 03:02:11 +00:00
else if ( s is JumpStatement )
2016-08-31 08:15:08 +00:00
GenerateJumpStatement ( ( JumpStatement ) s , sb ) ;
2008-07-08 03:02:11 +00:00
else if ( s is StateChange )
2016-08-31 08:15:08 +00:00
GenerateStateChange ( ( StateChange ) s , sb ) ;
2008-07-08 03:02:11 +00:00
else if ( s is IfStatement )
2016-08-31 08:15:08 +00:00
GenerateIfStatement ( ( IfStatement ) s , sb ) ;
2008-07-08 03:02:11 +00:00
else if ( s is WhileStatement )
2016-08-31 08:15:08 +00:00
GenerateWhileStatement ( ( WhileStatement ) s , sb ) ;
2008-07-08 03:02:11 +00:00
else if ( s is DoWhileStatement )
2016-08-31 08:15:08 +00:00
GenerateDoWhileStatement ( ( DoWhileStatement ) s , sb ) ;
2008-07-08 03:02:11 +00:00
else if ( s is ForLoop )
2016-08-31 08:15:08 +00:00
GenerateForLoop ( ( ForLoop ) s , sb ) ;
2008-07-08 03:02:11 +00:00
else if ( s is ArgumentList )
2016-08-31 08:15:08 +00:00
GenerateArgumentList ( ( ArgumentList ) s , sb ) ;
2008-07-08 03:02:11 +00:00
else if ( s is Assignment )
2016-08-31 08:15:08 +00:00
GenerateAssignment ( ( Assignment ) s , sb ) ;
2008-07-08 03:02:11 +00:00
else if ( s is BinaryExpression )
2016-08-31 08:15:08 +00:00
GenerateBinaryExpression ( ( BinaryExpression ) s , sb ) ;
2008-07-08 03:02:11 +00:00
else if ( s is ParenthesisExpression )
2016-08-31 08:15:08 +00:00
GenerateParenthesisExpression ( ( ParenthesisExpression ) s , sb ) ;
2008-07-08 03:02:11 +00:00
else if ( s is UnaryExpression )
2016-08-31 08:15:08 +00:00
GenerateUnaryExpression ( ( UnaryExpression ) s , sb ) ;
2008-07-08 03:02:11 +00:00
else if ( s is IncrementDecrementExpression )
2016-08-31 08:15:08 +00:00
GenerateIncrementDecrementExpression ( ( IncrementDecrementExpression ) s , sb ) ;
2008-07-08 03:02:11 +00:00
else if ( s is TypecastExpression )
2016-08-31 08:15:08 +00:00
GenerateTypecastExpression ( ( TypecastExpression ) s , sb ) ;
2008-07-08 03:02:11 +00:00
else if ( s is FunctionCall )
2016-08-31 08:15:08 +00:00
GenerateFunctionCall ( ( FunctionCall ) s , sb ) ;
2008-07-08 03:02:11 +00:00
else if ( s is VectorConstant )
2016-08-31 08:15:08 +00:00
GenerateVectorConstant ( ( VectorConstant ) s , sb ) ;
2008-07-08 03:02:11 +00:00
else if ( s is RotationConstant )
2016-08-31 08:15:08 +00:00
GenerateRotationConstant ( ( RotationConstant ) s , sb ) ;
2008-07-08 03:02:11 +00:00
else if ( s is ListConstant )
2016-08-31 08:15:08 +00:00
GenerateListConstant ( ( ListConstant ) s , sb ) ;
2008-07-08 03:02:11 +00:00
else if ( s is Constant )
2016-08-31 08:15:08 +00:00
GenerateConstant ( ( Constant ) s , sb ) ;
2008-07-08 03:02:11 +00:00
else if ( s is IdentDotExpression )
2016-08-31 08:15:08 +00:00
Generate ( CheckName ( ( ( IdentDotExpression ) s ) . Name ) + "." + ( ( IdentDotExpression ) s ) . Member , s , sb ) ;
2008-07-08 03:02:11 +00:00
else if ( s is IdentExpression )
2016-08-31 08:15:08 +00:00
GenerateIdentifier ( ( ( IdentExpression ) s ) . Name , s , sb ) ;
2008-07-08 03:02:11 +00:00
else if ( s is IDENT )
2016-08-31 08:15:08 +00:00
Generate ( CheckName ( ( ( TOKEN ) s ) . yytext ) , s , sb ) ;
2008-07-08 03:02:11 +00:00
else
{
foreach ( SYMBOL kid in s . kids )
2016-08-31 08:15:08 +00:00
GenerateNodeToSB ( s , kid , sb ) ;
2008-07-08 03:02:11 +00:00
}
2016-08-31 08:15:08 +00:00
return ;
2008-07-08 03:02:11 +00:00
}
/// <summary>
/// Generates the code for a GlobalFunctionDefinition node.
/// </summary>
/// <param name="gf">The GlobalFunctionDefinition node.</param>
/// <returns>String containing C# code for GlobalFunctionDefinition gf.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateGlobalFunctionDefinition ( GlobalFunctionDefinition gf , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
// we need to separate the argument declaration list from other kids
List < SYMBOL > argumentDeclarationListKids = new List < SYMBOL > ( ) ;
List < SYMBOL > remainingKids = new List < SYMBOL > ( ) ;
foreach ( SYMBOL kid in gf . kids )
if ( kid is ArgumentDeclarationList )
argumentDeclarationListKids . Add ( kid ) ;
else
remainingKids . Add ( kid ) ;
2016-08-31 08:15:08 +00:00
GenerateIndented ( String . Format ( "{0} {1}(" , gf . ReturnType , CheckName ( gf . Name ) ) , gf , sb ) ;
2008-07-08 03:02:11 +00:00
// print the state arguments, if any
foreach ( SYMBOL kid in argumentDeclarationListKids )
2016-08-31 08:15:08 +00:00
GenerateArgumentDeclarationList ( ( ArgumentDeclarationList ) kid , sb ) ;
2008-07-08 03:02:11 +00:00
2016-08-31 08:15:08 +00:00
GenerateLine ( ")" , sb ) ;
2008-07-08 03:02:11 +00:00
foreach ( SYMBOL kid in remainingKids )
2016-08-31 08:15:08 +00:00
GenerateNodeToSB ( gf , kid , sb ) ;
2008-07-08 03:02:11 +00:00
}
/// <summary>
/// Generates the code for a GlobalVariableDeclaration node.
/// </summary>
/// <param name="gv">The GlobalVariableDeclaration node.</param>
/// <returns>String containing C# code for GlobalVariableDeclaration gv.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateGlobalVariableDeclaration ( GlobalVariableDeclaration gv , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
foreach ( SYMBOL s in gv . kids )
{
2016-08-31 08:15:08 +00:00
Indent ( sb ) ;
GenerateNodeToSB ( gv , s , sb ) ;
GenerateLine ( ";" , sb ) ;
2008-07-08 03:02:11 +00:00
}
}
/// <summary>
/// Generates the code for a State node.
/// </summary>
/// <param name="s">The State node.</param>
/// <returns>String containing C# code for State s.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateState ( State s , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
foreach ( SYMBOL kid in s . kids )
if ( kid is StateEvent )
2016-08-31 08:15:08 +00:00
GenerateStateEvent ( ( StateEvent ) kid , s . Name , sb ) ;
2008-07-08 03:02:11 +00:00
}
/// <summary>
/// Generates the code for a StateEvent node.
/// </summary>
/// <param name="se">The StateEvent node.</param>
/// <param name="parentStateName">The name of the parent state.</param>
/// <returns>String containing C# code for StateEvent se.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateStateEvent ( StateEvent se , string parentStateName , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
// we need to separate the argument declaration list from other kids
List < SYMBOL > argumentDeclarationListKids = new List < SYMBOL > ( ) ;
List < SYMBOL > remainingKids = new List < SYMBOL > ( ) ;
foreach ( SYMBOL kid in se . kids )
if ( kid is ArgumentDeclarationList )
argumentDeclarationListKids . Add ( kid ) ;
else
remainingKids . Add ( kid ) ;
// "state" (function) declaration
2016-08-31 08:15:08 +00:00
GenerateIndented ( String . Format ( "public void {0}_event_{1}(" , parentStateName , se . Name ) , se , sb ) ;
2008-07-08 03:02:11 +00:00
// print the state arguments, if any
foreach ( SYMBOL kid in argumentDeclarationListKids )
2016-08-31 08:15:08 +00:00
GenerateArgumentDeclarationList ( ( ArgumentDeclarationList ) kid , sb ) ;
2008-07-08 03:02:11 +00:00
2016-08-31 08:15:08 +00:00
GenerateLine ( ")" , sb ) ;
2008-07-08 03:02:11 +00:00
foreach ( SYMBOL kid in remainingKids )
2016-08-31 08:15:08 +00:00
GenerateNodeToSB ( se , kid , sb ) ;
2008-07-08 03:02:11 +00:00
}
/// <summary>
/// Generates the code for an ArgumentDeclarationList node.
/// </summary>
/// <param name="adl">The ArgumentDeclarationList node.</param>
2008-07-23 02:51:45 +00:00
/// <returns>String containing C# code for ArgumentDeclarationList adl.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateArgumentDeclarationList ( ArgumentDeclarationList adl , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
int comma = adl . kids . Count - 1 ; // tells us whether to print a comma
foreach ( Declaration d in adl . kids )
{
2016-08-31 08:15:08 +00:00
Generate ( String . Format ( "{0} {1}" , d . Datatype , CheckName ( d . Id ) ) , d , sb ) ;
2008-07-08 03:02:11 +00:00
if ( 0 < comma - - )
2016-08-31 08:15:08 +00:00
Generate ( ", " , sb ) ;
2008-07-08 03:02:11 +00:00
}
}
/// <summary>
/// Generates the code for an ArgumentList node.
/// </summary>
/// <param name="al">The ArgumentList node.</param>
2008-07-23 02:51:45 +00:00
/// <returns>String containing C# code for ArgumentList al.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateArgumentList ( ArgumentList al , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
int comma = al . kids . Count - 1 ; // tells us whether to print a comma
foreach ( SYMBOL s in al . kids )
{
2016-08-31 08:15:08 +00:00
GenerateNodeToSB ( al , s , sb ) ;
2008-07-08 03:02:11 +00:00
if ( 0 < comma - - )
2016-08-31 08:15:08 +00:00
Generate ( ", " , sb ) ;
2008-07-08 03:02:11 +00:00
}
}
/// <summary>
/// Generates the code for a CompoundStatement node.
/// </summary>
/// <param name="cs">The CompoundStatement node.</param>
2008-07-23 02:51:45 +00:00
/// <returns>String containing C# code for CompoundStatement cs.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateCompoundStatement ( SYMBOL previousSymbol , CompoundStatement cs , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
// opening brace
2016-08-31 08:15:08 +00:00
GenerateIndentedLine ( "{" , sb ) ;
2008-07-08 03:02:11 +00:00
m_braceCount + + ;
2013-01-17 23:39:09 +00:00
if ( m_insertCoopTerminationChecks )
{
// We have to check in event functions as well because the user can manually call these.
if ( previousSymbol is GlobalFunctionDefinition
| | previousSymbol is WhileStatement
| | previousSymbol is DoWhileStatement
2013-01-22 01:23:10 +00:00
| | previousSymbol is ForLoop
2013-01-17 23:39:09 +00:00
| | previousSymbol is StateEvent )
2016-08-31 08:15:08 +00:00
GenerateIndentedLine ( m_coopTerminationCheck , sb ) ;
2013-01-17 23:39:09 +00:00
}
2008-07-08 03:02:11 +00:00
foreach ( SYMBOL kid in cs . kids )
2016-08-31 08:15:08 +00:00
GenerateNodeToSB ( cs , kid , sb ) ;
2008-07-08 03:02:11 +00:00
// closing brace
m_braceCount - - ;
2016-08-31 08:15:08 +00:00
GenerateIndentedLine ( "}" , sb ) ;
2008-07-08 03:02:11 +00:00
}
/// <summary>
/// Generates the code for a Declaration node.
/// </summary>
/// <param name="d">The Declaration node.</param>
2008-07-23 02:51:45 +00:00
/// <returns>String containing C# code for Declaration d.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateDeclaration ( Declaration d , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
2016-08-31 08:15:08 +00:00
Generate ( String . Format ( "{0} {1}" , d . Datatype , CheckName ( d . Id ) ) , d , sb ) ;
2008-07-08 03:02:11 +00:00
}
/// <summary>
/// Generates the code for a Statement node.
/// </summary>
/// <param name="s">The Statement node.</param>
2008-07-23 02:51:45 +00:00
/// <returns>String containing C# code for Statement s.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateStatement ( SYMBOL previousSymbol , Statement s , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
string retstr = String . Empty ;
2008-07-31 01:27:33 +00:00
bool printSemicolon = true ;
2013-01-30 03:44:56 +00:00
bool transformToBlock = false ;
2008-07-08 03:02:11 +00:00
2013-01-17 23:39:09 +00:00
if ( m_insertCoopTerminationChecks )
{
2013-01-30 03:44:56 +00:00
// A non-braced single line do while structure cannot contain multiple statements.
// So to insert the termination check we change this to a braced control structure instead.
if ( previousSymbol is WhileStatement
2013-01-17 23:39:09 +00:00
| | previousSymbol is DoWhileStatement
2013-01-30 03:44:56 +00:00
| | previousSymbol is ForLoop )
{
transformToBlock = true ;
// FIXME: This will be wrongly indented because the previous for/while/dowhile will have already indented.
2016-08-31 08:15:08 +00:00
GenerateIndentedLine ( "{" , sb ) ;
2013-01-30 03:44:56 +00:00
2016-08-31 08:15:08 +00:00
GenerateIndentedLine ( m_coopTerminationCheck , sb ) ;
2013-01-30 03:44:56 +00:00
}
2013-01-17 23:39:09 +00:00
}
2016-08-31 08:15:08 +00:00
Indent ( sb ) ;
2013-01-30 03:44:56 +00:00
2008-07-31 01:27:33 +00:00
if ( 0 < s . kids . Count )
{
// Jump label prints its own colon, we don't need a semicolon.
printSemicolon = ! ( s . kids . Top is JumpLabel ) ;
2009-06-07 10:22:55 +00:00
// If we encounter a lone Ident, we skip it, since that's a C#
// (MONO) error.
if ( ! ( s . kids . Top is IdentExpression & & 1 = = s . kids . Count ) )
foreach ( SYMBOL kid in s . kids )
2016-08-31 08:15:08 +00:00
GenerateNodeToSB ( s , kid , sb ) ;
2008-07-31 01:27:33 +00:00
}
2008-07-08 03:02:11 +00:00
if ( printSemicolon )
2016-08-31 08:15:08 +00:00
GenerateLine ( ";" , sb ) ;
2008-07-08 03:02:11 +00:00
2013-01-30 03:44:56 +00:00
if ( transformToBlock )
{
// FIXME: This will be wrongly indented because the for/while/dowhile is currently handling the unindent
2016-08-31 08:15:08 +00:00
GenerateIndentedLine ( "}" , sb ) ;
2013-01-30 03:44:56 +00:00
}
2008-07-08 03:02:11 +00:00
}
/// <summary>
/// Generates the code for an Assignment node.
/// </summary>
/// <param name="a">The Assignment node.</param>
2008-07-23 02:51:45 +00:00
/// <returns>String containing C# code for Assignment a.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateAssignment ( Assignment a , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
2009-02-23 02:43:51 +00:00
List < string > identifiers = new List < string > ( ) ;
checkForMultipleAssignments ( identifiers , a ) ;
2016-08-31 08:15:08 +00:00
GenerateNodeToSB ( a , ( SYMBOL ) a . kids . Pop ( ) , sb ) ;
Generate ( String . Format ( " {0} " , a . AssignmentType ) , a , sb ) ;
2008-07-08 03:02:11 +00:00
foreach ( SYMBOL kid in a . kids )
2016-08-31 08:15:08 +00:00
GenerateNodeToSB ( a , kid , sb ) ;
2008-07-08 03:02:11 +00:00
}
2009-02-23 02:43:51 +00:00
// This code checks for LSL of the following forms, and generates a
// warning if it finds them.
/ /
// list l = [ "foo" ];
// l = (l=[]) + l + ["bar"];
// (produces l=["foo","bar"] in SL but l=["bar"] in OS)
/ /
// integer i;
// integer j;
// i = (j = 3) + (j = 4) + (j = 5);
// (produces j=3 in SL but j=5 in OS)
/ /
// Without this check, that code passes compilation, but does not do what
// the end user expects, because LSL in SL evaluates right to left instead
// of left to right.
/ /
// The theory here is that producing an error and alerting the end user that
// something needs to change is better than silently generating incorrect code.
private void checkForMultipleAssignments ( List < string > identifiers , SYMBOL s )
{
if ( s is Assignment )
{
Assignment a = ( Assignment ) s ;
string newident = null ;
if ( a . kids [ 0 ] is Declaration )
{
newident = ( ( Declaration ) a . kids [ 0 ] ) . Id ;
}
else if ( a . kids [ 0 ] is IDENT )
{
newident = ( ( IDENT ) a . kids [ 0 ] ) . yytext ;
}
else if ( a . kids [ 0 ] is IdentDotExpression )
{
newident = ( ( IdentDotExpression ) a . kids [ 0 ] ) . Name ; // +"." + ((IdentDotExpression)a.kids[0]).Member;
}
else
{
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 ) ) ;
}
if ( identifiers . Contains ( newident ) )
{
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 ) ) ;
}
identifiers . Add ( newident ) ;
}
int index ;
for ( index = 0 ; index < s . kids . Count ; index + + )
{
checkForMultipleAssignments ( identifiers , ( SYMBOL ) s . kids [ index ] ) ;
}
}
2008-07-08 03:02:11 +00:00
/// <summary>
/// Generates the code for a ReturnStatement node.
/// </summary>
/// <param name="rs">The ReturnStatement node.</param>
2008-07-23 02:51:45 +00:00
/// <returns>String containing C# code for ReturnStatement rs.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateReturnStatement ( ReturnStatement rs , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
2016-08-31 08:15:08 +00:00
Generate ( "return " , rs , sb ) ;
2008-07-08 03:02:11 +00:00
foreach ( SYMBOL kid in rs . kids )
2016-08-31 08:15:08 +00:00
GenerateNodeToSB ( rs , kid , sb ) ;
2008-07-08 03:02:11 +00:00
}
/// <summary>
/// Generates the code for a JumpLabel node.
/// </summary>
/// <param name="jl">The JumpLabel node.</param>
2008-07-23 02:51:45 +00:00
/// <returns>String containing C# code for JumpLabel jl.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateJumpLabel ( JumpLabel jl , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
2013-01-17 23:39:09 +00:00
string labelStatement ;
if ( m_insertCoopTerminationChecks )
2014-06-18 21:20:25 +00:00
labelStatement = m_coopTerminationCheck ;
2013-01-17 23:39:09 +00:00
else
2014-06-18 21:20:25 +00:00
labelStatement = "NoOp();" ;
2013-01-17 23:39:09 +00:00
2016-08-31 08:15:08 +00:00
GenerateLine ( String . Format ( "{0}: {1}" , CheckName ( jl . LabelName ) , labelStatement ) , jl , sb ) ;
2008-07-08 03:02:11 +00:00
}
/// <summary>
/// Generates the code for a JumpStatement node.
/// </summary>
/// <param name="js">The JumpStatement node.</param>
2008-07-23 02:51:45 +00:00
/// <returns>String containing C# code for JumpStatement js.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateJumpStatement ( JumpStatement js , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
2016-08-31 08:15:08 +00:00
Generate ( String . Format ( "goto {0}" , CheckName ( js . TargetName ) ) , js , sb ) ;
2008-07-08 03:02:11 +00:00
}
/// <summary>
2008-07-23 02:51:45 +00:00
/// Generates the code for an IfStatement node.
2008-07-08 03:02:11 +00:00
/// </summary>
/// <param name="ifs">The IfStatement node.</param>
2008-07-23 02:51:45 +00:00
/// <returns>String containing C# code for IfStatement ifs.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateIfStatement ( IfStatement ifs , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
2016-08-31 08:15:08 +00:00
GenerateIndented ( "if (" , ifs , sb ) ;
GenerateNodeToSB ( ifs , ( SYMBOL ) ifs . kids . Pop ( ) , sb ) ;
GenerateLine ( ")" , sb ) ;
2008-07-08 03:02:11 +00:00
// CompoundStatement handles indentation itself but we need to do it
// otherwise.
bool indentHere = ifs . kids . Top is Statement ;
if ( indentHere ) m_braceCount + + ;
2016-08-31 08:15:08 +00:00
GenerateNodeToSB ( ifs , ( SYMBOL ) ifs . kids . Pop ( ) , sb ) ;
2008-07-08 03:02:11 +00:00
if ( indentHere ) m_braceCount - - ;
if ( 0 < ifs . kids . Count ) // do it again for an else
{
2016-08-31 08:15:08 +00:00
GenerateIndentedLine ( "else" , ifs , sb ) ;
2008-07-08 03:02:11 +00:00
indentHere = ifs . kids . Top is Statement ;
if ( indentHere ) m_braceCount + + ;
2016-08-31 08:15:08 +00:00
GenerateNodeToSB ( ifs , ( SYMBOL ) ifs . kids . Pop ( ) , sb ) ;
2008-07-08 03:02:11 +00:00
if ( indentHere ) m_braceCount - - ;
}
}
/// <summary>
/// Generates the code for a StateChange node.
/// </summary>
/// <param name="sc">The StateChange node.</param>
2008-07-23 02:51:45 +00:00
/// <returns>String containing C# code for StateChange sc.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateStateChange ( StateChange sc , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
2016-08-31 08:15:08 +00:00
Generate ( String . Format ( "state(\"{0}\")" , sc . NewState ) , sc , sb ) ;
2008-07-08 03:02:11 +00:00
}
/// <summary>
/// Generates the code for a WhileStatement node.
/// </summary>
/// <param name="ws">The WhileStatement node.</param>
2008-07-23 02:51:45 +00:00
/// <returns>String containing C# code for WhileStatement ws.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateWhileStatement ( WhileStatement ws , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
2016-08-31 08:15:08 +00:00
GenerateIndented ( "while (" , ws , sb ) ;
GenerateNodeToSB ( ws , ( SYMBOL ) ws . kids . Pop ( ) , sb ) ;
GenerateLine ( ")" , sb ) ;
2008-07-08 03:02:11 +00:00
// CompoundStatement handles indentation itself but we need to do it
// otherwise.
bool indentHere = ws . kids . Top is Statement ;
if ( indentHere ) m_braceCount + + ;
2016-08-31 08:15:08 +00:00
GenerateNodeToSB ( ws , ( SYMBOL ) ws . kids . Pop ( ) , sb ) ;
2008-07-08 03:02:11 +00:00
if ( indentHere ) m_braceCount - - ;
}
/// <summary>
/// Generates the code for a DoWhileStatement node.
/// </summary>
/// <param name="dws">The DoWhileStatement node.</param>
2008-07-23 02:51:45 +00:00
/// <returns>String containing C# code for DoWhileStatement dws.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateDoWhileStatement ( DoWhileStatement dws , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
2016-08-31 08:15:08 +00:00
GenerateIndentedLine ( "do" , dws , sb ) ;
2008-07-08 03:02:11 +00:00
// CompoundStatement handles indentation itself but we need to do it
// otherwise.
bool indentHere = dws . kids . Top is Statement ;
if ( indentHere ) m_braceCount + + ;
2016-08-31 08:15:08 +00:00
GenerateNodeToSB ( dws , ( SYMBOL ) dws . kids . Pop ( ) , sb ) ;
2008-07-08 03:02:11 +00:00
if ( indentHere ) m_braceCount - - ;
2016-08-31 08:15:08 +00:00
GenerateIndented ( "while (" , dws , sb ) ;
GenerateNodeToSB ( dws , ( SYMBOL ) dws . kids . Pop ( ) , sb ) ;
GenerateLine ( ");" , sb ) ;
2008-07-08 03:02:11 +00:00
}
/// <summary>
/// Generates the code for a ForLoop node.
/// </summary>
/// <param name="fl">The ForLoop node.</param>
2008-07-23 02:51:45 +00:00
/// <returns>String containing C# code for ForLoop fl.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateForLoop ( ForLoop fl , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
2016-08-31 08:15:08 +00:00
GenerateIndented ( "for (" , fl , sb ) ;
2008-07-08 03:02:11 +00:00
2009-06-07 10:22:41 +00:00
// It's possible that we don't have an assignment, in which case
// the child will be null and we only print the semicolon.
2009-06-10 04:28:56 +00:00
// for (x = 0; x < 10; x++)
// ^^^^^
2009-06-07 10:22:41 +00:00
ForLoopStatement s = ( ForLoopStatement ) fl . kids . Pop ( ) ;
if ( null ! = s )
{
2016-08-31 08:15:08 +00:00
GenerateForLoopStatement ( s , sb ) ;
2009-06-07 10:22:41 +00:00
}
2016-08-31 08:15:08 +00:00
Generate ( "; " , sb ) ;
2009-06-10 04:28:56 +00:00
// for (x = 0; x < 10; x++)
// ^^^^^^
2016-08-31 08:15:08 +00:00
GenerateNodeToSB ( fl , ( SYMBOL ) fl . kids . Pop ( ) , sb ) ;
Generate ( "; " , sb ) ;
2009-06-10 04:28:56 +00:00
// for (x = 0; x < 10; x++)
// ^^^
2016-08-31 08:15:08 +00:00
GenerateForLoopStatement ( ( ForLoopStatement ) fl . kids . Pop ( ) , sb ) ;
GenerateLine ( ")" , sb ) ;
2008-07-08 03:02:11 +00:00
// CompoundStatement handles indentation itself but we need to do it
// otherwise.
bool indentHere = fl . kids . Top is Statement ;
if ( indentHere ) m_braceCount + + ;
2016-08-31 08:15:08 +00:00
GenerateNodeToSB ( fl , ( SYMBOL ) fl . kids . Pop ( ) , sb ) ;
2008-07-08 03:02:11 +00:00
if ( indentHere ) m_braceCount - - ;
}
/// <summary>
/// Generates the code for a ForLoopStatement node.
/// </summary>
/// <param name="fls">The ForLoopStatement node.</param>
2008-07-23 02:51:45 +00:00
/// <returns>String containing C# code for ForLoopStatement fls.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateForLoopStatement ( ForLoopStatement fls , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
int comma = fls . kids . Count - 1 ; // tells us whether to print a comma
2009-06-07 10:22:55 +00:00
// It's possible that all we have is an empty Ident, for example:
/ /
// for (x; x < 10; x++) { ... }
/ /
// Which is illegal in C# (MONO). We'll skip it.
if ( fls . kids . Top is IdentExpression & & 1 = = fls . kids . Count )
2016-08-31 08:15:08 +00:00
return ;
2009-06-07 10:22:55 +00:00
2009-11-20 18:39:39 +00:00
for ( int i = 0 ; i < fls . kids . Count ; i + + )
2008-07-08 03:02:11 +00:00
{
2009-11-20 18:39:39 +00:00
SYMBOL s = ( SYMBOL ) fls . kids [ i ] ;
// Statements surrounded by parentheses in for loops
/ /
// e.g. for ((i = 0), (j = 7); (i < 10); (++i))
/ /
// are legal in LSL but not in C# so we need to discard the parentheses
/ /
// The following, however, does not appear to be legal in LLS
/ /
// for ((i = 0, j = 7); (i < 10); (++i))
/ /
// As of Friday 20th November 2009, the Linden Lab simulators appear simply never to compile or run this
// script but with no debug or warnings at all! Therefore, we won't deal with this yet (which looks
// like it would be considerably more complicated to handle).
while ( s is ParenthesisExpression )
s = ( SYMBOL ) s . kids . Pop ( ) ;
2016-08-31 08:15:08 +00:00
GenerateNodeToSB ( fls , s , sb ) ;
2008-07-08 03:02:11 +00:00
if ( 0 < comma - - )
2016-08-31 08:15:08 +00:00
Generate ( ", " , sb ) ;
2008-07-08 03:02:11 +00:00
}
}
/// <summary>
/// Generates the code for a BinaryExpression node.
/// </summary>
/// <param name="be">The BinaryExpression node.</param>
2008-07-23 02:51:45 +00:00
/// <returns>String containing C# code for BinaryExpression be.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateBinaryExpression ( BinaryExpression be , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
2009-02-20 07:40:36 +00:00
if ( be . ExpressionSymbol . Equals ( "&&" ) | | be . ExpressionSymbol . Equals ( "||" ) )
{
// special case handling for logical and/or, see Mantis 3174
2016-08-31 08:15:08 +00:00
sb . Append ( "((bool)(" ) ;
GenerateNodeToSB ( be , ( SYMBOL ) be . kids . Pop ( ) , sb ) ;
sb . Append ( "))" ) ;
Generate ( String . Format ( " {0} " , be . ExpressionSymbol . Substring ( 0 , 1 ) ) , be , sb ) ;
sb . Append ( "((bool)(" ) ;
2009-02-20 07:40:36 +00:00
foreach ( SYMBOL kid in be . kids )
2016-08-31 08:15:08 +00:00
GenerateNodeToSB ( be , kid , sb ) ;
sb . Append ( "))" ) ;
2009-02-20 07:40:36 +00:00
}
else
{
2016-08-31 08:15:08 +00:00
GenerateNodeToSB ( be , ( SYMBOL ) be . kids . Pop ( ) , sb ) ;
Generate ( String . Format ( " {0} " , be . ExpressionSymbol ) , be , sb ) ;
2009-02-20 07:40:36 +00:00
foreach ( SYMBOL kid in be . kids )
2016-08-31 08:15:08 +00:00
GenerateNodeToSB ( be , kid , sb ) ;
2009-02-20 07:40:36 +00:00
}
2008-07-08 03:02:11 +00:00
}
/// <summary>
/// Generates the code for a UnaryExpression node.
/// </summary>
/// <param name="ue">The UnaryExpression node.</param>
2008-07-23 02:51:45 +00:00
/// <returns>String containing C# code for UnaryExpression ue.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateUnaryExpression ( UnaryExpression ue , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
2016-08-31 08:15:08 +00:00
Generate ( ue . UnarySymbol , ue , sb ) ;
GenerateNodeToSB ( ue , ( SYMBOL ) ue . kids . Pop ( ) , sb ) ;
2008-07-08 03:02:11 +00:00
}
/// <summary>
/// Generates the code for a ParenthesisExpression node.
/// </summary>
/// <param name="pe">The ParenthesisExpression node.</param>
2008-07-23 02:51:45 +00:00
/// <returns>String containing C# code for ParenthesisExpression pe.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateParenthesisExpression ( ParenthesisExpression pe , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
string retstr = String . Empty ;
2016-08-31 08:15:08 +00:00
Generate ( "(" , sb ) ;
2008-07-08 03:02:11 +00:00
foreach ( SYMBOL kid in pe . kids )
2016-08-31 08:15:08 +00:00
GenerateNodeToSB ( pe , kid , sb ) ;
Generate ( ")" , sb ) ;
2008-07-08 03:02:11 +00:00
}
/// <summary>
/// Generates the code for a IncrementDecrementExpression node.
/// </summary>
/// <param name="ide">The IncrementDecrementExpression node.</param>
2008-07-23 02:51:45 +00:00
/// <returns>String containing C# code for IncrementDecrementExpression ide.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateIncrementDecrementExpression ( IncrementDecrementExpression ide , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
if ( 0 < ide . kids . Count )
{
IdentDotExpression dot = ( IdentDotExpression ) ide . kids . Top ;
2016-08-31 08:15:08 +00:00
Generate ( String . Format ( "{0}" , ide . PostOperation ? CheckName ( dot . Name ) + "." + dot . Member + ide . Operation : ide . Operation + CheckName ( dot . Name ) + "." + dot . Member ) , ide , sb ) ;
2008-07-08 03:02:11 +00:00
}
else
2016-08-31 08:15:08 +00:00
Generate ( String . Format ( "{0}" , ide . PostOperation ? CheckName ( ide . Name ) + ide . Operation : ide . Operation + CheckName ( ide . Name ) ) , ide , sb ) ;
2008-07-08 03:02:11 +00:00
}
/// <summary>
/// Generates the code for a TypecastExpression node.
/// </summary>
/// <param name="te">The TypecastExpression node.</param>
2008-07-23 02:51:45 +00:00
/// <returns>String containing C# code for TypecastExpression te.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateTypecastExpression ( TypecastExpression te , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
2009-02-09 00:59:02 +00:00
// we wrap all typecasted statements in parentheses
2016-08-31 08:15:08 +00:00
Generate ( String . Format ( "({0}) (" , te . TypecastType ) , te , sb ) ;
GenerateNodeToSB ( te , ( SYMBOL ) te . kids . Pop ( ) , sb ) ;
Generate ( ")" , sb ) ;
2008-07-08 03:02:11 +00:00
}
2012-07-31 17:45:37 +00:00
/// <summary>
/// Generates the code for an identifier
/// </summary>
/// <param name="id">The symbol name</param>
/// <param name="s">The Symbol node.</param>
/// <returns>String containing C# code for identifier reference.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateIdentifier ( string id , SYMBOL s , StringBuilder sb )
2012-07-31 17:45:37 +00:00
{
if ( m_comms ! = null )
{
object value = m_comms . LookupModConstant ( id ) ;
if ( value ! = null )
{
string retval = null ;
if ( value is int )
2013-08-02 16:44:01 +00:00
retval = String . Format ( "new LSL_Types.LSLInteger({0})" , ( ( int ) value ) . ToString ( ) ) ;
2012-07-31 17:45:37 +00:00
else if ( value is float )
retval = String . Format ( "new LSL_Types.LSLFloat({0})" , ( ( float ) value ) . ToString ( ) ) ;
else if ( value is string )
retval = String . Format ( "new LSL_Types.LSLString(\"{0}\")" , ( ( string ) value ) ) ;
else if ( value is OpenMetaverse . UUID )
retval = String . Format ( "new LSL_Types.key(\"{0}\")" , ( ( OpenMetaverse . UUID ) value ) . ToString ( ) ) ;
else if ( value is OpenMetaverse . Vector3 )
retval = String . Format ( "new LSL_Types.Vector3(\"{0}\")" , ( ( OpenMetaverse . Vector3 ) value ) . ToString ( ) ) ;
else if ( value is OpenMetaverse . Quaternion )
retval = String . Format ( "new LSL_Types.Quaternion(\"{0}\")" , ( ( OpenMetaverse . Quaternion ) value ) . ToString ( ) ) ;
else retval = id ;
2016-08-31 08:15:08 +00:00
Generate ( retval , s , sb ) ;
return ;
2012-07-31 17:45:37 +00:00
}
}
2016-08-31 08:15:08 +00:00
Generate ( CheckName ( id ) , s , sb ) ;
return ;
2012-07-31 17:45:37 +00:00
}
2008-07-08 03:02:11 +00:00
/// <summary>
/// Generates the code for a FunctionCall node.
/// </summary>
/// <param name="fc">The FunctionCall node.</param>
2008-07-23 02:51:45 +00:00
/// <returns>String containing C# code for FunctionCall fc.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateFunctionCall ( FunctionCall fc , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
2012-03-15 20:37:43 +00:00
string modinvoke = null ;
if ( m_comms ! = null )
modinvoke = m_comms . LookupModInvocation ( fc . Id ) ;
2012-03-15 20:16:02 +00:00
if ( modinvoke ! = null )
{
if ( fc . kids [ 0 ] is ArgumentList )
{
if ( ( fc . kids [ 0 ] as ArgumentList ) . kids . Count = = 0 )
2016-08-31 08:15:08 +00:00
Generate ( String . Format ( "{0}(\"{1}\"" , modinvoke , fc . Id ) , fc , sb ) ;
2012-03-15 20:16:02 +00:00
else
2016-08-31 08:15:08 +00:00
Generate ( String . Format ( "{0}(\"{1}\"," , modinvoke , fc . Id ) , fc , sb ) ;
2012-03-15 20:16:02 +00:00
}
}
else
{
2016-08-31 08:15:08 +00:00
Generate ( String . Format ( "{0}(" , CheckName ( fc . Id ) ) , fc , sb ) ;
2012-03-15 20:16:02 +00:00
}
2008-07-08 03:02:11 +00:00
foreach ( SYMBOL kid in fc . kids )
2016-08-31 08:15:08 +00:00
GenerateNodeToSB ( fc , kid , sb ) ;
2008-07-08 03:02:11 +00:00
2016-08-31 08:15:08 +00:00
Generate ( ")" , sb ) ;
2008-07-08 03:02:11 +00:00
}
/// <summary>
/// Generates the code for a Constant node.
/// </summary>
/// <param name="c">The Constant node.</param>
2008-07-23 02:51:45 +00:00
/// <returns>String containing C# code for Constant c.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateConstant ( Constant c , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
// Supprt LSL's weird acceptance of floats with no trailing digits
// after the period. Turn float x = 10.; into float x = 10.0;
if ( "LSL_Types.LSLFloat" = = c . Type )
{
int dotIndex = c . Value . IndexOf ( '.' ) + 1 ;
if ( 0 < dotIndex & & ( dotIndex = = c . Value . Length | | ! Char . IsDigit ( c . Value [ dotIndex ] ) ) )
c . Value = c . Value . Insert ( dotIndex , "0" ) ;
2008-09-23 13:28:17 +00:00
c . Value = "new LSL_Types.LSLFloat(" + c . Value + ")" ;
}
2008-09-23 23:14:00 +00:00
else if ( "LSL_Types.LSLInteger" = = c . Type )
2008-09-23 13:28:17 +00:00
{
c . Value = "new LSL_Types.LSLInteger(" + c . Value + ")" ;
}
2008-09-23 23:14:00 +00:00
else if ( "LSL_Types.LSLString" = = c . Type )
2008-09-23 13:28:17 +00:00
{
c . Value = "new LSL_Types.LSLString(\"" + c . Value + "\")" ;
2008-07-08 03:02:11 +00:00
}
2016-09-21 13:04:23 +00:00
else if ( "LSL_Types.key" = = c . Type )
{
c . Value = "new LSL_Types.key(\"" + c . Value + "\")" ;
}
2008-07-08 03:02:11 +00:00
2016-08-31 08:15:08 +00:00
Generate ( c . Value , c , sb ) ;
2008-07-08 03:02:11 +00:00
}
/// <summary>
/// Generates the code for a VectorConstant node.
/// </summary>
/// <param name="vc">The VectorConstant node.</param>
2008-07-23 02:51:45 +00:00
/// <returns>String containing C# code for VectorConstant vc.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateVectorConstant ( VectorConstant vc , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
2016-08-31 08:15:08 +00:00
Generate ( String . Format ( "new {0}(" , vc . Type ) , vc , sb ) ;
GenerateNodeToSB ( vc , ( SYMBOL ) vc . kids . Pop ( ) , sb ) ;
Generate ( ", " , sb ) ;
GenerateNodeToSB ( vc , ( SYMBOL ) vc . kids . Pop ( ) , sb ) ;
Generate ( ", " , sb ) ;
GenerateNodeToSB ( vc , ( SYMBOL ) vc . kids . Pop ( ) , sb ) ;
Generate ( ")" , sb ) ;
2008-07-08 03:02:11 +00:00
}
/// <summary>
/// Generates the code for a RotationConstant node.
/// </summary>
/// <param name="rc">The RotationConstant node.</param>
2008-07-23 02:51:45 +00:00
/// <returns>String containing C# code for RotationConstant rc.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateRotationConstant ( RotationConstant rc , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
2016-08-31 08:15:08 +00:00
Generate ( String . Format ( "new {0}(" , rc . Type ) , rc , sb ) ;
GenerateNodeToSB ( rc , ( SYMBOL ) rc . kids . Pop ( ) , sb ) ;
Generate ( ", " , sb ) ;
GenerateNodeToSB ( rc , ( SYMBOL ) rc . kids . Pop ( ) , sb ) ;
Generate ( ", " , sb ) ;
GenerateNodeToSB ( rc , ( SYMBOL ) rc . kids . Pop ( ) , sb ) ;
Generate ( ", " , sb ) ;
GenerateNodeToSB ( rc , ( SYMBOL ) rc . kids . Pop ( ) , sb ) ;
Generate ( ")" , sb ) ;
2008-07-08 03:02:11 +00:00
}
/// <summary>
/// Generates the code for a ListConstant node.
/// </summary>
/// <param name="lc">The ListConstant node.</param>
2008-07-23 02:51:45 +00:00
/// <returns>String containing C# code for ListConstant lc.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateListConstant ( ListConstant lc , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
2016-08-31 08:15:08 +00:00
Generate ( String . Format ( "new {0}(" , lc . Type ) , lc , sb ) ;
2008-07-08 03:02:11 +00:00
foreach ( SYMBOL kid in lc . kids )
2016-08-31 08:15:08 +00:00
GenerateNodeToSB ( lc , kid , sb ) ;
2008-07-23 02:51:45 +00:00
2016-08-31 08:15:08 +00:00
Generate ( ")" , sb ) ;
2008-07-23 02:51:45 +00:00
}
/// <summary>
/// Prints a newline.
/// </summary>
/// <returns>A newline.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateLine ( StringBuilder sb )
2008-07-23 02:51:45 +00:00
{
2016-08-31 08:15:08 +00:00
sb . Append ( "\n" ) ;
2016-08-31 09:39:01 +00:00
m_CSharpLine + + ;
m_CSharpCol = 1 ;
2008-07-23 02:51:45 +00:00
}
/// <summary>
/// Prints text, followed by a newline.
/// </summary>
/// <param name="s">String of text to print.</param>
/// <returns>String s followed by newline.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateLine ( string s , StringBuilder sb )
2008-07-23 02:51:45 +00:00
{
2016-08-31 08:15:08 +00:00
sb . Append ( s ) ;
sb . Append ( "\n" ) ;
2016-08-31 09:39:01 +00:00
m_CSharpLine + + ;
m_CSharpCol = 1 ;
2008-07-23 02:51:45 +00:00
}
/// <summary>
/// Prints text, followed by a newline.
/// </summary>
/// <param name="s">String of text to print.</param>
/// <param name="sym">Symbol being generated to extract original line
/// number and column from.</param>
/// <returns>String s followed by newline.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateLine ( string s , SYMBOL sym , StringBuilder sb )
2008-07-23 02:51:45 +00:00
{
2016-08-31 08:15:08 +00:00
Generate ( s , sym , sb ) ;
sb . Append ( "\n" ) ;
2008-07-23 02:51:45 +00:00
m_CSharpLine + + ;
m_CSharpCol = 1 ;
2008-07-08 03:02:11 +00:00
}
2008-07-23 02:51:45 +00:00
/// <summary>
/// Prints text.
/// </summary>
/// <param name="s">String of text to print.</param>
/// <returns>String s.</returns>
2016-08-31 08:15:08 +00:00
private void Generate ( string s , StringBuilder sb )
2008-07-23 02:51:45 +00:00
{
2016-08-31 08:15:08 +00:00
sb . Append ( s ) ;
m_CSharpCol + = s . Length ;
2008-07-23 02:51:45 +00:00
}
/// <summary>
/// Prints text.
/// </summary>
/// <param name="s">String of text to print.</param>
/// <param name="sym">Symbol being generated to extract original line
/// number and column from.</param>
/// <returns>String s.</returns>
2016-08-31 08:15:08 +00:00
private void Generate ( string s , SYMBOL sym , StringBuilder sb )
2008-07-23 02:51:45 +00:00
{
2016-08-31 08:15:08 +00:00
sb . Append ( s ) ;
2008-07-23 02:51:45 +00:00
if ( null ! = sym )
m_positionMap . Add ( new KeyValuePair < int , int > ( m_CSharpLine , m_CSharpCol ) , new KeyValuePair < int , int > ( sym . Line , sym . Position ) ) ;
m_CSharpCol + = s . Length ;
}
2008-07-08 03:02:11 +00:00
/// <summary>
/// Prints text correctly indented, followed by a newline.
/// </summary>
/// <param name="s">String of text to print.</param>
2008-07-23 02:51:45 +00:00
/// <returns>Properly indented string s followed by newline.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateIndentedLine ( string s , StringBuilder sb )
2008-07-23 02:51:45 +00:00
{
2016-08-31 08:15:08 +00:00
GenerateIndentedLine ( s , null , sb ) ;
2008-07-23 02:51:45 +00:00
}
/// <summary>
/// Prints text correctly indented, followed by a newline.
/// </summary>
/// <param name="s">String of text to print.</param>
/// <param name="sym">Symbol being generated to extract original line
/// number and column from.</param>
/// <returns>Properly indented string s followed by newline.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateIndentedLine ( string s , SYMBOL sym , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
2016-08-31 08:15:08 +00:00
GenerateIndented ( s , sym , sb ) ;
sb . Append ( "\n" ) ;
2008-07-23 02:51:45 +00:00
m_CSharpLine + + ;
m_CSharpCol = 1 ;
2008-07-08 03:02:11 +00:00
}
/// <summary>
/// Prints text correctly indented.
/// </summary>
/// <param name="s">String of text to print.</param>
2008-07-23 02:51:45 +00:00
/// <returns>Properly indented string s.</returns>
//private string GenerateIndented(string s)
//{
// return GenerateIndented(s, null);
//}
// THIS FUNCTION IS COMMENTED OUT TO SUPPRESS WARNINGS
/// <summary>
/// Prints text correctly indented.
/// </summary>
/// <param name="s">String of text to print.</param>
/// <param name="sym">Symbol being generated to extract original line
/// number and column from.</param>
/// <returns>Properly indented string s.</returns>
2016-08-31 08:15:08 +00:00
private void GenerateIndented ( string s , SYMBOL sym , StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
2016-08-31 08:15:08 +00:00
Indent ( sb ) ;
sb . Append ( s ) ;
2008-07-23 02:51:45 +00:00
if ( null ! = sym )
m_positionMap . Add ( new KeyValuePair < int , int > ( m_CSharpLine , m_CSharpCol ) , new KeyValuePair < int , int > ( sym . Line , sym . Position ) ) ;
m_CSharpCol + = s . Length ;
2008-07-08 03:02:11 +00:00
}
/// <summary>
/// Prints correct indentation.
/// </summary>
2008-07-23 02:51:45 +00:00
/// <returns>Indentation based on brace count.</returns>
2016-08-31 08:15:08 +00:00
private void Indent ( StringBuilder sb )
2008-07-08 03:02:11 +00:00
{
2016-08-31 08:42:03 +00:00
for ( int i = 0 ; i < m_braceCount ; i + + )
2016-08-31 09:25:19 +00:00
{
2016-08-31 08:42:03 +00:00
sb . Append ( " " ) ;
2016-08-31 09:25:19 +00:00
m_CSharpCol + = 4 ;
}
2008-07-08 03:02:11 +00:00
}
2008-11-01 23:50:19 +00:00
/// <summary>
/// Returns the passed name with an underscore prepended if that name is a reserved word in C#
/// and not resevered in LSL otherwise it just returns the passed name.
2009-02-09 00:59:02 +00:00
///
2008-11-01 23:50:19 +00:00
/// This makes no attempt to cache the results to minimise future lookups. For a non trivial
/// scripts the number of unique identifiers could easily grow to the size of the reserved word
/// list so maintaining a list or dictionary and doing the lookup there firstwould probably not
/// give any real speed advantage.
2009-02-09 00:59:02 +00:00
///
2008-11-01 23:50:19 +00:00
/// I believe there is a class Microsoft.CSharp.CSharpCodeProvider that has a function
/// CreateValidIdentifier(str) that will return either the value of str if it is not a C#
/// key word or "_"+str if it is. But availability under Mono?
/// </summary>
private string CheckName ( string s )
{
if ( CSReservedWords . IsReservedWord ( s ) )
2008-11-04 01:30:39 +00:00
return "@" + s ;
2008-11-01 23:50:19 +00:00
else
return s ;
}
2008-07-08 03:02:11 +00:00
}
}