First version of position mapping between LSL <-> C# implemented.

0.6.0-stable
Mike Mazur 2008-07-23 02:51:45 +00:00
parent f18b80741a
commit ba17b0df27
5 changed files with 623 additions and 234 deletions

View File

@ -35,56 +35,89 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
public class CSCodeGenerator public class CSCodeGenerator
{ {
private SYMBOL m_astRoot = null; private SYMBOL m_astRoot = null;
private int m_braceCount; // for indentation private Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> m_positionMap;
private int m_indentWidth = 4; // for indentation
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
/// <summary> /// <summary>
/// Pass the new CodeGenerator a string containing the LSL source. /// Creates an 'empty' CSCodeGenerator instance.
/// </summary> /// </summary>
/// <param name="script">String containing LSL source.</param> public CSCodeGenerator()
public CSCodeGenerator(string script)
{ {
Parser p = new LSLSyntax(new yyLSLSyntax(), new ErrorHandler(true)); ResetCounters();
// Obviously this needs to be in a try/except block.
LSL2CSCodeTransformer codeTransformer = new LSL2CSCodeTransformer(p.Parse(script));
m_astRoot = codeTransformer.Transform();
} }
/// <summary> /// <summary>
/// Pass the new CodeGenerator an abstract syntax tree. /// Get the mapping between LSL and C# line/column number.
/// </summary> /// </summary>
/// <param name="astRoot">The root node of the AST.</param> /// <returns>Dictionary\<KeyValuePair\<int, int\>, KeyValuePair\<int, int\>\>.</returns>
public CSCodeGenerator(SYMBOL astRoot) 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; }
}
/// <summary>
/// Resets various counters and metadata.
/// </summary>
private void ResetCounters()
{ {
m_braceCount = 0; m_braceCount = 0;
m_astRoot = astRoot; m_CSharpLine = 0;
m_CSharpCol = 1;
m_positionMap = new Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>();
m_astRoot = null;
} }
/// <summary> /// <summary>
/// Generate the code from the AST we have. /// Generate the code from the AST we have.
/// </summary> /// </summary>
/// <param name="script">The LSL source as a string.</param>
/// <returns>String containing the generated C# code.</returns> /// <returns>String containing the generated C# code.</returns>
public string Generate() public string Convert(string script)
{ {
ResetCounters();
Parser p = new LSLSyntax(new yyLSLSyntax(), new ErrorHandler(true));
// Obviously this needs to be in a try/except block.
LSL2CSCodeTransformer codeTransformer = new LSL2CSCodeTransformer(p.Parse(script));
m_astRoot = codeTransformer.Transform();
string retstr = String.Empty; string retstr = String.Empty;
// standard preamble // standard preamble
//retstr = "using OpenSim.Region.ScriptEngine.Common;\n"; //retstr = GenerateLine("using OpenSim.Region.ScriptEngine.Common;");
//retstr += "using System.Collections.Generic;\n\n"; //retstr += GenerateLine("using System.Collections.Generic;");
//retstr += "namespace SecondLife\n"; //retstr += GenerateLine("");
//retstr += "{\n"; //retstr += GenerateLine("namespace SecondLife");
//retstr += " public class Script : OpenSim.Region.ScriptEngine.Common\n"; //retstr += GenerateLine("{");
//retstr += " {\n"; m_braceCount++;
//retstr += GenerateIndentedLine("public class Script : OpenSim.Region.ScriptEngine.Common");
//retstr += GenerateIndentedLine("{");
m_braceCount++;
// line number
m_CSharpLine += 3;
// here's the payload // here's the payload
m_braceCount += 2; retstr += GenerateLine();
retstr += "\n";
foreach (SYMBOL s in m_astRoot.kids) foreach (SYMBOL s in m_astRoot.kids)
retstr += GenerateNode(s); retstr += GenerateNode(s);
// close braces! // close braces!
//retstr += " }\n"; m_braceCount--;
//retstr += "}\n"; //retstr += GenerateIndentedLine("}");
m_braceCount -= 2; m_braceCount--;
//retstr += GenerateLine("}");
return retstr; return retstr;
} }
@ -155,11 +188,11 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
else if (s is Constant) else if (s is Constant)
retstr += GenerateConstant((Constant) s); retstr += GenerateConstant((Constant) s);
else if (s is IdentDotExpression) else if (s is IdentDotExpression)
retstr += ((IdentDotExpression) s).Name + "." + ((IdentDotExpression) s).Member; retstr += Generate(((IdentDotExpression) s).Name + "." + ((IdentDotExpression) s).Member, s);
else if (s is IdentExpression) else if (s is IdentExpression)
retstr += ((IdentExpression) s).Name; retstr += Generate(((IdentExpression) s).Name, s);
else if (s is IDENT) else if (s is IDENT)
retstr += ((TOKEN) s).yytext; retstr += Generate(((TOKEN) s).yytext, s);
else else
{ {
foreach (SYMBOL kid in s.kids) foreach (SYMBOL kid in s.kids)
@ -188,13 +221,13 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
else else
remainingKids.Add(kid); remainingKids.Add(kid);
retstr += WriteIndented(String.Format("{0} {1}(", gf.ReturnType, gf.Name)); retstr += GenerateIndented(String.Format("{0} {1}(", gf.ReturnType, gf.Name), gf);
// print the state arguments, if any // print the state arguments, if any
foreach (SYMBOL kid in argumentDeclarationListKids) foreach (SYMBOL kid in argumentDeclarationListKids)
retstr += GenerateArgumentDeclarationList((ArgumentDeclarationList) kid); retstr += GenerateArgumentDeclarationList((ArgumentDeclarationList) kid);
retstr += ")\n"; retstr += GenerateLine(")");
foreach (SYMBOL kid in remainingKids) foreach (SYMBOL kid in remainingKids)
retstr += GenerateNode(kid); retstr += GenerateNode(kid);
@ -215,7 +248,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
{ {
retstr += Indent(); retstr += Indent();
retstr += GenerateNode(s); retstr += GenerateNode(s);
retstr += ";\n"; retstr += GenerateLine(";");
} }
return retstr; return retstr;
@ -233,8 +266,6 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
foreach (SYMBOL kid in s.kids) foreach (SYMBOL kid in s.kids)
if (kid is StateEvent) if (kid is StateEvent)
retstr += GenerateStateEvent((StateEvent) kid, s.Name); retstr += GenerateStateEvent((StateEvent) kid, s.Name);
else
retstr += String.Format("ERROR: State '{0}' contains a '{1}\n", s.Name, kid.GetType());
return retstr; return retstr;
} }
@ -260,13 +291,13 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
remainingKids.Add(kid); remainingKids.Add(kid);
// "state" (function) declaration // "state" (function) declaration
retstr += WriteIndented(String.Format("public void {0}_event_{1}(", parentStateName, se.Name)); retstr += GenerateIndented(String.Format("public void {0}_event_{1}(", parentStateName, se.Name), se);
// print the state arguments, if any // print the state arguments, if any
foreach (SYMBOL kid in argumentDeclarationListKids) foreach (SYMBOL kid in argumentDeclarationListKids)
retstr += GenerateArgumentDeclarationList((ArgumentDeclarationList) kid); retstr += GenerateArgumentDeclarationList((ArgumentDeclarationList) kid);
retstr += ")\n"; retstr += GenerateLine(")");
foreach (SYMBOL kid in remainingKids) foreach (SYMBOL kid in remainingKids)
retstr += GenerateNode(kid); retstr += GenerateNode(kid);
@ -278,7 +309,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
/// Generates the code for an ArgumentDeclarationList node. /// Generates the code for an ArgumentDeclarationList node.
/// </summary> /// </summary>
/// <param name="adl">The ArgumentDeclarationList node.</param> /// <param name="adl">The ArgumentDeclarationList node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for ArgumentDeclarationList adl.</returns>
private string GenerateArgumentDeclarationList(ArgumentDeclarationList adl) private string GenerateArgumentDeclarationList(ArgumentDeclarationList adl)
{ {
string retstr = String.Empty; string retstr = String.Empty;
@ -287,9 +318,9 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
foreach (Declaration d in adl.kids) foreach (Declaration d in adl.kids)
{ {
retstr += String.Format("{0} {1}", d.Datatype, d.Id); retstr += Generate(String.Format("{0} {1}", d.Datatype, d.Id), d);
if (0 < comma--) if (0 < comma--)
retstr += ", "; retstr += Generate(", ");
} }
return retstr; return retstr;
@ -299,7 +330,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
/// Generates the code for an ArgumentList node. /// Generates the code for an ArgumentList node.
/// </summary> /// </summary>
/// <param name="al">The ArgumentList node.</param> /// <param name="al">The ArgumentList node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for ArgumentList al.</returns>
private string GenerateArgumentList(ArgumentList al) private string GenerateArgumentList(ArgumentList al)
{ {
string retstr = String.Empty; string retstr = String.Empty;
@ -310,7 +341,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
{ {
retstr += GenerateNode(s); retstr += GenerateNode(s);
if (0 < comma--) if (0 < comma--)
retstr += ", "; retstr += Generate(", ");
} }
return retstr; return retstr;
@ -320,13 +351,13 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
/// Generates the code for a CompoundStatement node. /// Generates the code for a CompoundStatement node.
/// </summary> /// </summary>
/// <param name="cs">The CompoundStatement node.</param> /// <param name="cs">The CompoundStatement node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for CompoundStatement cs.</returns>
private string GenerateCompoundStatement(CompoundStatement cs) private string GenerateCompoundStatement(CompoundStatement cs)
{ {
string retstr = String.Empty; string retstr = String.Empty;
// opening brace // opening brace
retstr += WriteIndentedLine("{"); retstr += GenerateIndentedLine("{");
m_braceCount++; m_braceCount++;
foreach (SYMBOL kid in cs.kids) foreach (SYMBOL kid in cs.kids)
@ -334,7 +365,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
// closing brace // closing brace
m_braceCount--; m_braceCount--;
retstr += WriteIndentedLine("}"); retstr += GenerateIndentedLine("}");
return retstr; return retstr;
} }
@ -343,17 +374,17 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
/// Generates the code for a Declaration node. /// Generates the code for a Declaration node.
/// </summary> /// </summary>
/// <param name="d">The Declaration node.</param> /// <param name="d">The Declaration node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for Declaration d.</returns>
private string GenerateDeclaration(Declaration d) private string GenerateDeclaration(Declaration d)
{ {
return String.Format("{0} {1}", d.Datatype, d.Id); return Generate(String.Format("{0} {1}", d.Datatype, d.Id), d);
} }
/// <summary> /// <summary>
/// Generates the code for a Statement node. /// Generates the code for a Statement node.
/// </summary> /// </summary>
/// <param name="s">The Statement node.</param> /// <param name="s">The Statement node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for Statement s.</returns>
private string GenerateStatement(Statement s) private string GenerateStatement(Statement s)
{ {
string retstr = String.Empty; string retstr = String.Empty;
@ -367,7 +398,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
retstr += GenerateNode(kid); retstr += GenerateNode(kid);
if (printSemicolon) if (printSemicolon)
retstr += ";\n"; retstr += GenerateLine(";");
return retstr; return retstr;
} }
@ -376,13 +407,13 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
/// Generates the code for an Assignment node. /// Generates the code for an Assignment node.
/// </summary> /// </summary>
/// <param name="a">The Assignment node.</param> /// <param name="a">The Assignment node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for Assignment a.</returns>
private string GenerateAssignment(Assignment a) private string GenerateAssignment(Assignment a)
{ {
string retstr = String.Empty; string retstr = String.Empty;
retstr += GenerateNode((SYMBOL) a.kids.Pop()); retstr += GenerateNode((SYMBOL) a.kids.Pop());
retstr +=String.Format(" {0} ", a.AssignmentType); retstr += Generate(String.Format(" {0} ", a.AssignmentType), a);
foreach (SYMBOL kid in a.kids) foreach (SYMBOL kid in a.kids)
retstr += GenerateNode(kid); retstr += GenerateNode(kid);
@ -393,12 +424,12 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
/// Generates the code for a ReturnStatement node. /// Generates the code for a ReturnStatement node.
/// </summary> /// </summary>
/// <param name="rs">The ReturnStatement node.</param> /// <param name="rs">The ReturnStatement node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for ReturnStatement rs.</returns>
private string GenerateReturnStatement(ReturnStatement rs) private string GenerateReturnStatement(ReturnStatement rs)
{ {
string retstr = String.Empty; string retstr = String.Empty;
retstr += "return "; retstr += Generate("return ", rs);
foreach (SYMBOL kid in rs.kids) foreach (SYMBOL kid in rs.kids)
retstr += GenerateNode(kid); retstr += GenerateNode(kid);
@ -410,34 +441,34 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
/// Generates the code for a JumpLabel node. /// Generates the code for a JumpLabel node.
/// </summary> /// </summary>
/// <param name="jl">The JumpLabel node.</param> /// <param name="jl">The JumpLabel node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for JumpLabel jl.</returns>
private string GenerateJumpLabel(JumpLabel jl) private string GenerateJumpLabel(JumpLabel jl)
{ {
return String.Format("{0}:\n", jl.LabelName); return Generate(String.Format("{0}:\n", jl.LabelName), jl);
} }
/// <summary> /// <summary>
/// Generates the code for a JumpStatement node. /// Generates the code for a JumpStatement node.
/// </summary> /// </summary>
/// <param name="js">The JumpStatement node.</param> /// <param name="js">The JumpStatement node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for JumpStatement js.</returns>
private string GenerateJumpStatement(JumpStatement js) private string GenerateJumpStatement(JumpStatement js)
{ {
return String.Format("goto {0}", js.TargetName); return Generate(String.Format("goto {0}", js.TargetName), js);
} }
/// <summary> /// <summary>
/// Generates the code for a IfStatement node. /// Generates the code for an IfStatement node.
/// </summary> /// </summary>
/// <param name="ifs">The IfStatement node.</param> /// <param name="ifs">The IfStatement node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for IfStatement ifs.</returns>
private string GenerateIfStatement(IfStatement ifs) private string GenerateIfStatement(IfStatement ifs)
{ {
string retstr = String.Empty; string retstr = String.Empty;
retstr += WriteIndented("if ("); retstr += GenerateIndented("if (", ifs);
retstr += GenerateNode((SYMBOL) ifs.kids.Pop()); retstr += GenerateNode((SYMBOL) ifs.kids.Pop());
retstr += ")\n"; retstr += GenerateLine(")");
// CompoundStatement handles indentation itself but we need to do it // CompoundStatement handles indentation itself but we need to do it
// otherwise. // otherwise.
@ -448,7 +479,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
if (0 < ifs.kids.Count) // do it again for an else if (0 < ifs.kids.Count) // do it again for an else
{ {
retstr += WriteIndentedLine("else"); retstr += GenerateIndentedLine("else", ifs);
indentHere = ifs.kids.Top is Statement; indentHere = ifs.kids.Top is Statement;
if (indentHere) m_braceCount++; if (indentHere) m_braceCount++;
@ -463,24 +494,24 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
/// Generates the code for a StateChange node. /// Generates the code for a StateChange node.
/// </summary> /// </summary>
/// <param name="sc">The StateChange node.</param> /// <param name="sc">The StateChange node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for StateChange sc.</returns>
private string GenerateStateChange(StateChange sc) private string GenerateStateChange(StateChange sc)
{ {
return String.Format("state(\"{0}\")", sc.NewState); return Generate(String.Format("state(\"{0}\")", sc.NewState), sc);
} }
/// <summary> /// <summary>
/// Generates the code for a WhileStatement node. /// Generates the code for a WhileStatement node.
/// </summary> /// </summary>
/// <param name="ws">The WhileStatement node.</param> /// <param name="ws">The WhileStatement node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for WhileStatement ws.</returns>
private string GenerateWhileStatement(WhileStatement ws) private string GenerateWhileStatement(WhileStatement ws)
{ {
string retstr = String.Empty; string retstr = String.Empty;
retstr += WriteIndented("while ("); retstr += GenerateIndented("while (", ws);
retstr += GenerateNode((SYMBOL) ws.kids.Pop()); retstr += GenerateNode((SYMBOL) ws.kids.Pop());
retstr += ")\n"; retstr += GenerateLine(")");
// CompoundStatement handles indentation itself but we need to do it // CompoundStatement handles indentation itself but we need to do it
// otherwise. // otherwise.
@ -496,12 +527,12 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
/// Generates the code for a DoWhileStatement node. /// Generates the code for a DoWhileStatement node.
/// </summary> /// </summary>
/// <param name="dws">The DoWhileStatement node.</param> /// <param name="dws">The DoWhileStatement node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for DoWhileStatement dws.</returns>
private string GenerateDoWhileStatement(DoWhileStatement dws) private string GenerateDoWhileStatement(DoWhileStatement dws)
{ {
string retstr = String.Empty; string retstr = String.Empty;
retstr += WriteIndentedLine("do"); retstr += GenerateIndentedLine("do", dws);
// CompoundStatement handles indentation itself but we need to do it // CompoundStatement handles indentation itself but we need to do it
// otherwise. // otherwise.
@ -510,9 +541,9 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
retstr += GenerateNode((SYMBOL) dws.kids.Pop()); retstr += GenerateNode((SYMBOL) dws.kids.Pop());
if (indentHere) m_braceCount--; if (indentHere) m_braceCount--;
retstr += WriteIndented("while ("); retstr += GenerateIndented("while (", dws);
retstr += GenerateNode((SYMBOL) dws.kids.Pop()); retstr += GenerateNode((SYMBOL) dws.kids.Pop());
retstr += ");\n"; retstr += GenerateLine(");");
return retstr; return retstr;
} }
@ -521,25 +552,25 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
/// Generates the code for a ForLoop node. /// Generates the code for a ForLoop node.
/// </summary> /// </summary>
/// <param name="fl">The ForLoop node.</param> /// <param name="fl">The ForLoop node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for ForLoop fl.</returns>
private string GenerateForLoop(ForLoop fl) private string GenerateForLoop(ForLoop fl)
{ {
string retstr = String.Empty; string retstr = String.Empty;
retstr += WriteIndented("for ("); retstr += GenerateIndented("for (", fl);
// for ( x = 0 ; x < 10 ; x++ ) // for ( x = 0 ; x < 10 ; x++ )
// ^^^^^^^ // ^^^^^^^
retstr += GenerateForLoopStatement((ForLoopStatement) fl.kids.Pop()); retstr += GenerateForLoopStatement((ForLoopStatement) fl.kids.Pop());
retstr += "; "; retstr += Generate("; ");
// for ( x = 0 ; x < 10 ; x++ ) // for ( x = 0 ; x < 10 ; x++ )
// ^^^^^^^^ // ^^^^^^^^
retstr += GenerateNode((SYMBOL) fl.kids.Pop()); retstr += GenerateNode((SYMBOL) fl.kids.Pop());
retstr += "; "; retstr += Generate("; ");
// for ( x = 0 ; x < 10 ; x++ ) // for ( x = 0 ; x < 10 ; x++ )
// ^^^^^ // ^^^^^
retstr += GenerateForLoopStatement((ForLoopStatement) fl.kids.Pop()); retstr += GenerateForLoopStatement((ForLoopStatement) fl.kids.Pop());
retstr += ")\n"; retstr += GenerateLine(")");
// CompoundStatement handles indentation itself but we need to do it // CompoundStatement handles indentation itself but we need to do it
// otherwise. // otherwise.
@ -555,7 +586,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
/// Generates the code for a ForLoopStatement node. /// Generates the code for a ForLoopStatement node.
/// </summary> /// </summary>
/// <param name="fls">The ForLoopStatement node.</param> /// <param name="fls">The ForLoopStatement node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for ForLoopStatement fls.</returns>
private string GenerateForLoopStatement(ForLoopStatement fls) private string GenerateForLoopStatement(ForLoopStatement fls)
{ {
string retstr = String.Empty; string retstr = String.Empty;
@ -566,7 +597,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
{ {
retstr += GenerateNode(s); retstr += GenerateNode(s);
if (0 < comma--) if (0 < comma--)
retstr += ", "; retstr += Generate(", ");
} }
return retstr; return retstr;
@ -576,13 +607,13 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
/// Generates the code for a BinaryExpression node. /// Generates the code for a BinaryExpression node.
/// </summary> /// </summary>
/// <param name="be">The BinaryExpression node.</param> /// <param name="be">The BinaryExpression node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for BinaryExpression be.</returns>
private string GenerateBinaryExpression(BinaryExpression be) private string GenerateBinaryExpression(BinaryExpression be)
{ {
string retstr = String.Empty; string retstr = String.Empty;
retstr += GenerateNode((SYMBOL) be.kids.Pop()); retstr += GenerateNode((SYMBOL) be.kids.Pop());
retstr += String.Format(" {0} ", be.ExpressionSymbol); retstr += Generate(String.Format(" {0} ", be.ExpressionSymbol), be);
foreach (SYMBOL kid in be.kids) foreach (SYMBOL kid in be.kids)
retstr += GenerateNode(kid); retstr += GenerateNode(kid);
@ -593,12 +624,12 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
/// Generates the code for a UnaryExpression node. /// Generates the code for a UnaryExpression node.
/// </summary> /// </summary>
/// <param name="ue">The UnaryExpression node.</param> /// <param name="ue">The UnaryExpression node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for UnaryExpression ue.</returns>
private string GenerateUnaryExpression(UnaryExpression ue) private string GenerateUnaryExpression(UnaryExpression ue)
{ {
string retstr = String.Empty; string retstr = String.Empty;
retstr += ue.UnarySymbol; retstr += Generate(ue.UnarySymbol, ue);
retstr += GenerateNode((SYMBOL) ue.kids.Pop()); retstr += GenerateNode((SYMBOL) ue.kids.Pop());
return retstr; return retstr;
@ -608,15 +639,15 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
/// Generates the code for a ParenthesisExpression node. /// Generates the code for a ParenthesisExpression node.
/// </summary> /// </summary>
/// <param name="pe">The ParenthesisExpression node.</param> /// <param name="pe">The ParenthesisExpression node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for ParenthesisExpression pe.</returns>
private string GenerateParenthesisExpression(ParenthesisExpression pe) private string GenerateParenthesisExpression(ParenthesisExpression pe)
{ {
string retstr = String.Empty; string retstr = String.Empty;
retstr += "("; retstr += Generate("(");
foreach (SYMBOL kid in pe.kids) foreach (SYMBOL kid in pe.kids)
retstr += GenerateNode(kid); retstr += GenerateNode(kid);
retstr += ")"; retstr += Generate(")");
return retstr; return retstr;
} }
@ -625,7 +656,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
/// Generates the code for a IncrementDecrementExpression node. /// Generates the code for a IncrementDecrementExpression node.
/// </summary> /// </summary>
/// <param name="ide">The IncrementDecrementExpression node.</param> /// <param name="ide">The IncrementDecrementExpression node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for IncrementDecrementExpression ide.</returns>
private string GenerateIncrementDecrementExpression(IncrementDecrementExpression ide) private string GenerateIncrementDecrementExpression(IncrementDecrementExpression ide)
{ {
string retstr = String.Empty; string retstr = String.Empty;
@ -633,10 +664,10 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
if (0 < ide.kids.Count) if (0 < ide.kids.Count)
{ {
IdentDotExpression dot = (IdentDotExpression) ide.kids.Top; IdentDotExpression dot = (IdentDotExpression) ide.kids.Top;
retstr += String.Format("{0}", ide.PostOperation ? dot.Name + "." + dot.Member + ide.Operation : ide.Operation + dot.Name + "." + dot.Member); retstr += Generate(String.Format("{0}", ide.PostOperation ? dot.Name + "." + dot.Member + ide.Operation : ide.Operation + dot.Name + "." + dot.Member), ide);
} }
else else
retstr += String.Format("{0}", ide.PostOperation ? ide.Name + ide.Operation : ide.Operation + ide.Name); retstr += Generate(String.Format("{0}", ide.PostOperation ? ide.Name + ide.Operation : ide.Operation + ide.Name), ide);
return retstr; return retstr;
} }
@ -645,15 +676,15 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
/// Generates the code for a TypecastExpression node. /// Generates the code for a TypecastExpression node.
/// </summary> /// </summary>
/// <param name="te">The TypecastExpression node.</param> /// <param name="te">The TypecastExpression node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for TypecastExpression te.</returns>
private string GenerateTypecastExpression(TypecastExpression te) private string GenerateTypecastExpression(TypecastExpression te)
{ {
string retstr = String.Empty; string retstr = String.Empty;
// we wrap all typecasted statements in parentheses // we wrap all typecasted statements in parentheses
retstr += String.Format("({0}) (", te.TypecastType); retstr += Generate(String.Format("({0}) (", te.TypecastType), te);
retstr += GenerateNode((SYMBOL) te.kids.Pop()); retstr += GenerateNode((SYMBOL) te.kids.Pop());
retstr += ")"; retstr += Generate(")");
return retstr; return retstr;
} }
@ -662,17 +693,17 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
/// Generates the code for a FunctionCall node. /// Generates the code for a FunctionCall node.
/// </summary> /// </summary>
/// <param name="fc">The FunctionCall node.</param> /// <param name="fc">The FunctionCall node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for FunctionCall fc.</returns>
private string GenerateFunctionCall(FunctionCall fc) private string GenerateFunctionCall(FunctionCall fc)
{ {
string retstr = String.Empty; string retstr = String.Empty;
retstr += String.Format("{0}(", fc.Id); retstr += Generate(String.Format("{0}(", fc.Id), fc);
foreach (SYMBOL kid in fc.kids) foreach (SYMBOL kid in fc.kids)
retstr += GenerateNode(kid); retstr += GenerateNode(kid);
retstr += ")"; retstr += Generate(")");
return retstr; return retstr;
} }
@ -681,7 +712,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
/// Generates the code for a Constant node. /// Generates the code for a Constant node.
/// </summary> /// </summary>
/// <param name="c">The Constant node.</param> /// <param name="c">The Constant node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for Constant c.</returns>
private string GenerateConstant(Constant c) private string GenerateConstant(Constant c)
{ {
string retstr = String.Empty; string retstr = String.Empty;
@ -697,10 +728,10 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
// need to quote strings // need to quote strings
if ("LSL_Types.LSLString" == c.Type) if ("LSL_Types.LSLString" == c.Type)
retstr += "\""; retstr += Generate("\"");
retstr += c.Value; retstr += Generate(c.Value, c);
if ("LSL_Types.LSLString" == c.Type) if ("LSL_Types.LSLString" == c.Type)
retstr += "\""; retstr += Generate("\"");
return retstr; return retstr;
} }
@ -709,18 +740,18 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
/// Generates the code for a VectorConstant node. /// Generates the code for a VectorConstant node.
/// </summary> /// </summary>
/// <param name="vc">The VectorConstant node.</param> /// <param name="vc">The VectorConstant node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for VectorConstant vc.</returns>
private string GenerateVectorConstant(VectorConstant vc) private string GenerateVectorConstant(VectorConstant vc)
{ {
string retstr = String.Empty; string retstr = String.Empty;
retstr += String.Format("new {0}(", vc.Type); retstr += Generate(String.Format("new {0}(", vc.Type), vc);
retstr += GenerateNode((SYMBOL) vc.kids.Pop()); retstr += GenerateNode((SYMBOL) vc.kids.Pop());
retstr += ", "; retstr += Generate(", ");
retstr += GenerateNode((SYMBOL) vc.kids.Pop()); retstr += GenerateNode((SYMBOL) vc.kids.Pop());
retstr += ", "; retstr += Generate(", ");
retstr += GenerateNode((SYMBOL) vc.kids.Pop()); retstr += GenerateNode((SYMBOL) vc.kids.Pop());
retstr += ")"; retstr += Generate(")");
return retstr; return retstr;
} }
@ -729,20 +760,20 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
/// Generates the code for a RotationConstant node. /// Generates the code for a RotationConstant node.
/// </summary> /// </summary>
/// <param name="rc">The RotationConstant node.</param> /// <param name="rc">The RotationConstant node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for RotationConstant rc.</returns>
private string GenerateRotationConstant(RotationConstant rc) private string GenerateRotationConstant(RotationConstant rc)
{ {
string retstr = String.Empty; string retstr = String.Empty;
retstr += String.Format("new {0}(", rc.Type); retstr += Generate(String.Format("new {0}(", rc.Type), rc);
retstr += GenerateNode((SYMBOL) rc.kids.Pop()); retstr += GenerateNode((SYMBOL) rc.kids.Pop());
retstr += ", "; retstr += Generate(", ");
retstr += GenerateNode((SYMBOL) rc.kids.Pop()); retstr += GenerateNode((SYMBOL) rc.kids.Pop());
retstr += ", "; retstr += Generate(", ");
retstr += GenerateNode((SYMBOL) rc.kids.Pop()); retstr += GenerateNode((SYMBOL) rc.kids.Pop());
retstr += ", "; retstr += Generate(", ");
retstr += GenerateNode((SYMBOL) rc.kids.Pop()); retstr += GenerateNode((SYMBOL) rc.kids.Pop());
retstr += ")"; retstr += Generate(")");
return retstr; return retstr;
} }
@ -751,51 +782,155 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
/// Generates the code for a ListConstant node. /// Generates the code for a ListConstant node.
/// </summary> /// </summary>
/// <param name="lc">The ListConstant node.</param> /// <param name="lc">The ListConstant node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for ListConstant lc.</returns>
private string GenerateListConstant(ListConstant lc) private string GenerateListConstant(ListConstant lc)
{ {
string retstr = String.Empty; string retstr = String.Empty;
retstr += String.Format("new {0}(", lc.Type); retstr += Generate(String.Format("new {0}(", lc.Type), lc);
foreach (SYMBOL kid in lc.kids) foreach (SYMBOL kid in lc.kids)
retstr += GenerateNode(kid); retstr += GenerateNode(kid);
retstr += ")"; retstr += Generate(")");
return retstr; return retstr;
} }
/// <summary>
/// Prints a newline.
/// </summary>
/// <returns>A newline.</returns>
private string GenerateLine()
{
return GenerateLine("");
}
/// <summary>
/// Prints text, followed by a newline.
/// </summary>
/// <param name="s">String of text to print.</param>
/// <returns>String s followed by newline.</returns>
private string GenerateLine(string s)
{
return GenerateLine(s, null);
}
/// <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>
private string GenerateLine(string s, SYMBOL sym)
{
string retstr = Generate(s, sym) + "\n";
m_CSharpLine++;
m_CSharpCol = 1;
return retstr;
}
/// <summary>
/// Prints text.
/// </summary>
/// <param name="s">String of text to print.</param>
/// <returns>String s.</returns>
private string Generate(string s)
{
return Generate(s, null);
}
/// <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>
private string Generate(string s, SYMBOL sym)
{
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;
return s;
}
/// <summary> /// <summary>
/// Prints text correctly indented, followed by a newline. /// Prints text correctly indented, followed by a newline.
/// </summary> /// </summary>
/// <param name="s">String of text to print.</param> /// <param name="s">String of text to print.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>Properly indented string s followed by newline.</returns>
private string WriteIndentedLine(string s) private string GenerateIndentedLine(string s)
{ {
return WriteIndented(s) + "\n"; return GenerateIndentedLine(s, null);
}
/// <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>
private string GenerateIndentedLine(string s, SYMBOL sym)
{
string retstr = GenerateIndented(s, sym) + "\n";
m_CSharpLine++;
m_CSharpCol = 1;
return retstr;
} }
/// <summary> /// <summary>
/// Prints text correctly indented. /// Prints text correctly indented.
/// </summary> /// </summary>
/// <param name="s">String of text to print.</param> /// <param name="s">String of text to print.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>Properly indented string s.</returns>
private string WriteIndented(string s) //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>
private string GenerateIndented(string s, SYMBOL sym)
{ {
return Indent() + s; string retstr = Indent() + s;
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;
return retstr;
} }
/// <summary> /// <summary>
/// Prints correct indentation. /// Prints correct indentation.
/// </summary> /// </summary>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>Indentation based on brace count.</returns>
private string Indent() private string Indent()
{ {
string retstr = String.Empty; string retstr = String.Empty;
for (int i = 0; i < m_braceCount; i++) for (int i = 0; i < m_braceCount; i++)
retstr += " "; for (int j = 0; j < m_indentWidth; j++)
{
retstr += " ";
m_CSharpCol++;
}
return retstr; return retstr;
} }

View File

@ -73,7 +73,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
private string ScriptEnginesPath = "ScriptEngines"; private string ScriptEnginesPath = "ScriptEngines";
private static LSL2CSConverter LSL_Converter = new LSL2CSConverter(); private static LSL2CSConverter LSL_Converter = new LSL2CSConverter();
//private static CSCodeGenerator LSL_Converter; //private static CSCodeGenerator LSL_Converter = new CSCodeGenerator();
private static CSharpCodeProvider CScodeProvider = new CSharpCodeProvider(); private static CSharpCodeProvider CScodeProvider = new CSharpCodeProvider();
private static VBCodeProvider VBcodeProvider = new VBCodeProvider(); private static VBCodeProvider VBcodeProvider = new VBCodeProvider();
private static JScriptCodeProvider JScodeProvider = new JScriptCodeProvider(); private static JScriptCodeProvider JScodeProvider = new JScriptCodeProvider();
@ -276,8 +276,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL
{ {
// Its LSL, convert it to C# // Its LSL, convert it to C#
compileScript = LSL_Converter.Convert(Script); compileScript = LSL_Converter.Convert(Script);
//LSL_Converter = new CSCodeGenerator(Script); //compileScript = LSL_Converter.Convert(Script);
//compileScript = LSL_Converter.Generate();
l = enumCompileType.cs; l = enumCompileType.cs;
} }

View File

@ -35,56 +35,89 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
public class CSCodeGenerator : ICodeConverter public class CSCodeGenerator : ICodeConverter
{ {
private SYMBOL m_astRoot = null; private SYMBOL m_astRoot = null;
private int m_braceCount; // for indentation private Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> m_positionMap;
private int m_indentWidth = 4; // for indentation
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
/// <summary> /// <summary>
/// Pass the new CodeGenerator a string containing the LSL source. /// Creates an 'empty' CSCodeGenerator instance.
/// </summary> /// </summary>
/// <param name="script">String containing LSL source.</param>
public CSCodeGenerator() public CSCodeGenerator()
{ {
ResetCounters();
} }
/// <summary> /// <summary>
/// Pass the new CodeGenerator an abstract syntax tree. /// Get the mapping between LSL and C# line/column number.
/// </summary> /// </summary>
/// <param name="astRoot">The root node of the AST.</param> /// <returns>Dictionary\<KeyValuePair\<int, int\>, KeyValuePair\<int, int\>\>.</returns>
public CSCodeGenerator(SYMBOL astRoot) 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; }
}
/// <summary>
/// Resets various counters and metadata.
/// </summary>
private void ResetCounters()
{ {
m_braceCount = 0; m_braceCount = 0;
m_astRoot = astRoot; m_CSharpLine = 0;
m_CSharpCol = 1;
m_positionMap = new Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>();
m_astRoot = null;
} }
/// <summary> /// <summary>
/// Generate the code from the AST we have. /// Generate the code from the AST we have.
/// </summary> /// </summary>
/// <param name="script">The LSL source as a string.</param>
/// <returns>String containing the generated C# code.</returns> /// <returns>String containing the generated C# code.</returns>
public string Convert(string script) public string Convert(string script)
{ {
ResetCounters();
Parser p = new LSLSyntax(new yyLSLSyntax(), new ErrorHandler(true)); Parser p = new LSLSyntax(new yyLSLSyntax(), new ErrorHandler(true));
// Obviously this needs to be in a try/except block. // Obviously this needs to be in a try/except block.
LSL2CSCodeTransformer codeTransformer = new LSL2CSCodeTransformer(p.Parse(script)); LSL2CSCodeTransformer codeTransformer = new LSL2CSCodeTransformer(p.Parse(script));
m_astRoot = codeTransformer.Transform(); m_astRoot = codeTransformer.Transform();
string retstr = String.Empty; string retstr = String.Empty;
// standard preamble // standard preamble
//retstr = "using OpenSim.Region.ScriptEngine.Common;\n"; //retstr = GenerateLine("using OpenSim.Region.ScriptEngine.Common;");
//retstr += "using System.Collections.Generic;\n\n"; //retstr += GenerateLine("using System.Collections.Generic;");
//retstr += "namespace SecondLife\n"; //retstr += GenerateLine("");
//retstr += "{\n"; //retstr += GenerateLine("namespace SecondLife");
//retstr += " public class Script : OpenSim.Region.ScriptEngine.Common\n"; //retstr += GenerateLine("{");
//retstr += " {\n"; m_braceCount++;
//retstr += GenerateIndentedLine("public class Script : OpenSim.Region.ScriptEngine.Common");
//retstr += GenerateIndentedLine("{");
m_braceCount++;
// line number
m_CSharpLine += 3;
// here's the payload // here's the payload
m_braceCount += 2; retstr += GenerateLine();
retstr += "\n";
foreach (SYMBOL s in m_astRoot.kids) foreach (SYMBOL s in m_astRoot.kids)
retstr += GenerateNode(s); retstr += GenerateNode(s);
// close braces! // close braces!
//retstr += " }\n"; m_braceCount--;
//retstr += "}\n"; //retstr += GenerateIndentedLine("}");
m_braceCount -= 2; m_braceCount--;
//retstr += GenerateLine("}");
return retstr; return retstr;
} }
@ -155,11 +188,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
else if (s is Constant) else if (s is Constant)
retstr += GenerateConstant((Constant) s); retstr += GenerateConstant((Constant) s);
else if (s is IdentDotExpression) else if (s is IdentDotExpression)
retstr += ((IdentDotExpression) s).Name + "." + ((IdentDotExpression) s).Member; retstr += Generate(((IdentDotExpression) s).Name + "." + ((IdentDotExpression) s).Member, s);
else if (s is IdentExpression) else if (s is IdentExpression)
retstr += ((IdentExpression) s).Name; retstr += Generate(((IdentExpression) s).Name, s);
else if (s is IDENT) else if (s is IDENT)
retstr += ((TOKEN) s).yytext; retstr += Generate(((TOKEN) s).yytext, s);
else else
{ {
foreach (SYMBOL kid in s.kids) foreach (SYMBOL kid in s.kids)
@ -188,13 +221,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
else else
remainingKids.Add(kid); remainingKids.Add(kid);
retstr += WriteIndented(String.Format("{0} {1}(", gf.ReturnType, gf.Name)); retstr += GenerateIndented(String.Format("{0} {1}(", gf.ReturnType, gf.Name), gf);
// print the state arguments, if any // print the state arguments, if any
foreach (SYMBOL kid in argumentDeclarationListKids) foreach (SYMBOL kid in argumentDeclarationListKids)
retstr += GenerateArgumentDeclarationList((ArgumentDeclarationList) kid); retstr += GenerateArgumentDeclarationList((ArgumentDeclarationList) kid);
retstr += ")\n"; retstr += GenerateLine(")");
foreach (SYMBOL kid in remainingKids) foreach (SYMBOL kid in remainingKids)
retstr += GenerateNode(kid); retstr += GenerateNode(kid);
@ -215,7 +248,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
{ {
retstr += Indent(); retstr += Indent();
retstr += GenerateNode(s); retstr += GenerateNode(s);
retstr += ";\n"; retstr += GenerateLine(";");
} }
return retstr; return retstr;
@ -233,8 +266,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
foreach (SYMBOL kid in s.kids) foreach (SYMBOL kid in s.kids)
if (kid is StateEvent) if (kid is StateEvent)
retstr += GenerateStateEvent((StateEvent) kid, s.Name); retstr += GenerateStateEvent((StateEvent) kid, s.Name);
else
retstr += String.Format("ERROR: State '{0}' contains a '{1}\n", s.Name, kid.GetType());
return retstr; return retstr;
} }
@ -260,13 +291,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
remainingKids.Add(kid); remainingKids.Add(kid);
// "state" (function) declaration // "state" (function) declaration
retstr += WriteIndented(String.Format("public void {0}_event_{1}(", parentStateName, se.Name)); retstr += GenerateIndented(String.Format("public void {0}_event_{1}(", parentStateName, se.Name), se);
// print the state arguments, if any // print the state arguments, if any
foreach (SYMBOL kid in argumentDeclarationListKids) foreach (SYMBOL kid in argumentDeclarationListKids)
retstr += GenerateArgumentDeclarationList((ArgumentDeclarationList) kid); retstr += GenerateArgumentDeclarationList((ArgumentDeclarationList) kid);
retstr += ")\n"; retstr += GenerateLine(")");
foreach (SYMBOL kid in remainingKids) foreach (SYMBOL kid in remainingKids)
retstr += GenerateNode(kid); retstr += GenerateNode(kid);
@ -278,7 +309,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
/// Generates the code for an ArgumentDeclarationList node. /// Generates the code for an ArgumentDeclarationList node.
/// </summary> /// </summary>
/// <param name="adl">The ArgumentDeclarationList node.</param> /// <param name="adl">The ArgumentDeclarationList node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for ArgumentDeclarationList adl.</returns>
private string GenerateArgumentDeclarationList(ArgumentDeclarationList adl) private string GenerateArgumentDeclarationList(ArgumentDeclarationList adl)
{ {
string retstr = String.Empty; string retstr = String.Empty;
@ -287,9 +318,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
foreach (Declaration d in adl.kids) foreach (Declaration d in adl.kids)
{ {
retstr += String.Format("{0} {1}", d.Datatype, d.Id); retstr += Generate(String.Format("{0} {1}", d.Datatype, d.Id), d);
if (0 < comma--) if (0 < comma--)
retstr += ", "; retstr += Generate(", ");
} }
return retstr; return retstr;
@ -299,7 +330,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
/// Generates the code for an ArgumentList node. /// Generates the code for an ArgumentList node.
/// </summary> /// </summary>
/// <param name="al">The ArgumentList node.</param> /// <param name="al">The ArgumentList node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for ArgumentList al.</returns>
private string GenerateArgumentList(ArgumentList al) private string GenerateArgumentList(ArgumentList al)
{ {
string retstr = String.Empty; string retstr = String.Empty;
@ -310,7 +341,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
{ {
retstr += GenerateNode(s); retstr += GenerateNode(s);
if (0 < comma--) if (0 < comma--)
retstr += ", "; retstr += Generate(", ");
} }
return retstr; return retstr;
@ -320,13 +351,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
/// Generates the code for a CompoundStatement node. /// Generates the code for a CompoundStatement node.
/// </summary> /// </summary>
/// <param name="cs">The CompoundStatement node.</param> /// <param name="cs">The CompoundStatement node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for CompoundStatement cs.</returns>
private string GenerateCompoundStatement(CompoundStatement cs) private string GenerateCompoundStatement(CompoundStatement cs)
{ {
string retstr = String.Empty; string retstr = String.Empty;
// opening brace // opening brace
retstr += WriteIndentedLine("{"); retstr += GenerateIndentedLine("{");
m_braceCount++; m_braceCount++;
foreach (SYMBOL kid in cs.kids) foreach (SYMBOL kid in cs.kids)
@ -334,7 +365,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
// closing brace // closing brace
m_braceCount--; m_braceCount--;
retstr += WriteIndentedLine("}"); retstr += GenerateIndentedLine("}");
return retstr; return retstr;
} }
@ -343,17 +374,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
/// Generates the code for a Declaration node. /// Generates the code for a Declaration node.
/// </summary> /// </summary>
/// <param name="d">The Declaration node.</param> /// <param name="d">The Declaration node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for Declaration d.</returns>
private string GenerateDeclaration(Declaration d) private string GenerateDeclaration(Declaration d)
{ {
return String.Format("{0} {1}", d.Datatype, d.Id); return Generate(String.Format("{0} {1}", d.Datatype, d.Id), d);
} }
/// <summary> /// <summary>
/// Generates the code for a Statement node. /// Generates the code for a Statement node.
/// </summary> /// </summary>
/// <param name="s">The Statement node.</param> /// <param name="s">The Statement node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for Statement s.</returns>
private string GenerateStatement(Statement s) private string GenerateStatement(Statement s)
{ {
string retstr = String.Empty; string retstr = String.Empty;
@ -367,7 +398,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
retstr += GenerateNode(kid); retstr += GenerateNode(kid);
if (printSemicolon) if (printSemicolon)
retstr += ";\n"; retstr += GenerateLine(";");
return retstr; return retstr;
} }
@ -376,13 +407,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
/// Generates the code for an Assignment node. /// Generates the code for an Assignment node.
/// </summary> /// </summary>
/// <param name="a">The Assignment node.</param> /// <param name="a">The Assignment node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for Assignment a.</returns>
private string GenerateAssignment(Assignment a) private string GenerateAssignment(Assignment a)
{ {
string retstr = String.Empty; string retstr = String.Empty;
retstr += GenerateNode((SYMBOL) a.kids.Pop()); retstr += GenerateNode((SYMBOL) a.kids.Pop());
retstr +=String.Format(" {0} ", a.AssignmentType); retstr += Generate(String.Format(" {0} ", a.AssignmentType), a);
foreach (SYMBOL kid in a.kids) foreach (SYMBOL kid in a.kids)
retstr += GenerateNode(kid); retstr += GenerateNode(kid);
@ -393,12 +424,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
/// Generates the code for a ReturnStatement node. /// Generates the code for a ReturnStatement node.
/// </summary> /// </summary>
/// <param name="rs">The ReturnStatement node.</param> /// <param name="rs">The ReturnStatement node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for ReturnStatement rs.</returns>
private string GenerateReturnStatement(ReturnStatement rs) private string GenerateReturnStatement(ReturnStatement rs)
{ {
string retstr = String.Empty; string retstr = String.Empty;
retstr += "return "; retstr += Generate("return ", rs);
foreach (SYMBOL kid in rs.kids) foreach (SYMBOL kid in rs.kids)
retstr += GenerateNode(kid); retstr += GenerateNode(kid);
@ -410,34 +441,34 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
/// Generates the code for a JumpLabel node. /// Generates the code for a JumpLabel node.
/// </summary> /// </summary>
/// <param name="jl">The JumpLabel node.</param> /// <param name="jl">The JumpLabel node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for JumpLabel jl.</returns>
private string GenerateJumpLabel(JumpLabel jl) private string GenerateJumpLabel(JumpLabel jl)
{ {
return String.Format("{0}:\n", jl.LabelName); return Generate(String.Format("{0}:\n", jl.LabelName), jl);
} }
/// <summary> /// <summary>
/// Generates the code for a JumpStatement node. /// Generates the code for a JumpStatement node.
/// </summary> /// </summary>
/// <param name="js">The JumpStatement node.</param> /// <param name="js">The JumpStatement node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for JumpStatement js.</returns>
private string GenerateJumpStatement(JumpStatement js) private string GenerateJumpStatement(JumpStatement js)
{ {
return String.Format("goto {0}", js.TargetName); return Generate(String.Format("goto {0}", js.TargetName), js);
} }
/// <summary> /// <summary>
/// Generates the code for a IfStatement node. /// Generates the code for an IfStatement node.
/// </summary> /// </summary>
/// <param name="ifs">The IfStatement node.</param> /// <param name="ifs">The IfStatement node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for IfStatement ifs.</returns>
private string GenerateIfStatement(IfStatement ifs) private string GenerateIfStatement(IfStatement ifs)
{ {
string retstr = String.Empty; string retstr = String.Empty;
retstr += WriteIndented("if ("); retstr += GenerateIndented("if (", ifs);
retstr += GenerateNode((SYMBOL) ifs.kids.Pop()); retstr += GenerateNode((SYMBOL) ifs.kids.Pop());
retstr += ")\n"; retstr += GenerateLine(")");
// CompoundStatement handles indentation itself but we need to do it // CompoundStatement handles indentation itself but we need to do it
// otherwise. // otherwise.
@ -448,7 +479,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
if (0 < ifs.kids.Count) // do it again for an else if (0 < ifs.kids.Count) // do it again for an else
{ {
retstr += WriteIndentedLine("else"); retstr += GenerateIndentedLine("else", ifs);
indentHere = ifs.kids.Top is Statement; indentHere = ifs.kids.Top is Statement;
if (indentHere) m_braceCount++; if (indentHere) m_braceCount++;
@ -463,24 +494,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
/// Generates the code for a StateChange node. /// Generates the code for a StateChange node.
/// </summary> /// </summary>
/// <param name="sc">The StateChange node.</param> /// <param name="sc">The StateChange node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for StateChange sc.</returns>
private string GenerateStateChange(StateChange sc) private string GenerateStateChange(StateChange sc)
{ {
return String.Format("state(\"{0}\")", sc.NewState); return Generate(String.Format("state(\"{0}\")", sc.NewState), sc);
} }
/// <summary> /// <summary>
/// Generates the code for a WhileStatement node. /// Generates the code for a WhileStatement node.
/// </summary> /// </summary>
/// <param name="ws">The WhileStatement node.</param> /// <param name="ws">The WhileStatement node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for WhileStatement ws.</returns>
private string GenerateWhileStatement(WhileStatement ws) private string GenerateWhileStatement(WhileStatement ws)
{ {
string retstr = String.Empty; string retstr = String.Empty;
retstr += WriteIndented("while ("); retstr += GenerateIndented("while (", ws);
retstr += GenerateNode((SYMBOL) ws.kids.Pop()); retstr += GenerateNode((SYMBOL) ws.kids.Pop());
retstr += ")\n"; retstr += GenerateLine(")");
// CompoundStatement handles indentation itself but we need to do it // CompoundStatement handles indentation itself but we need to do it
// otherwise. // otherwise.
@ -496,12 +527,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
/// Generates the code for a DoWhileStatement node. /// Generates the code for a DoWhileStatement node.
/// </summary> /// </summary>
/// <param name="dws">The DoWhileStatement node.</param> /// <param name="dws">The DoWhileStatement node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for DoWhileStatement dws.</returns>
private string GenerateDoWhileStatement(DoWhileStatement dws) private string GenerateDoWhileStatement(DoWhileStatement dws)
{ {
string retstr = String.Empty; string retstr = String.Empty;
retstr += WriteIndentedLine("do"); retstr += GenerateIndentedLine("do", dws);
// CompoundStatement handles indentation itself but we need to do it // CompoundStatement handles indentation itself but we need to do it
// otherwise. // otherwise.
@ -510,9 +541,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
retstr += GenerateNode((SYMBOL) dws.kids.Pop()); retstr += GenerateNode((SYMBOL) dws.kids.Pop());
if (indentHere) m_braceCount--; if (indentHere) m_braceCount--;
retstr += WriteIndented("while ("); retstr += GenerateIndented("while (", dws);
retstr += GenerateNode((SYMBOL) dws.kids.Pop()); retstr += GenerateNode((SYMBOL) dws.kids.Pop());
retstr += ");\n"; retstr += GenerateLine(");");
return retstr; return retstr;
} }
@ -521,25 +552,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
/// Generates the code for a ForLoop node. /// Generates the code for a ForLoop node.
/// </summary> /// </summary>
/// <param name="fl">The ForLoop node.</param> /// <param name="fl">The ForLoop node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for ForLoop fl.</returns>
private string GenerateForLoop(ForLoop fl) private string GenerateForLoop(ForLoop fl)
{ {
string retstr = String.Empty; string retstr = String.Empty;
retstr += WriteIndented("for ("); retstr += GenerateIndented("for (", fl);
// for ( x = 0 ; x < 10 ; x++ ) // for ( x = 0 ; x < 10 ; x++ )
// ^^^^^^^ // ^^^^^^^
retstr += GenerateForLoopStatement((ForLoopStatement) fl.kids.Pop()); retstr += GenerateForLoopStatement((ForLoopStatement) fl.kids.Pop());
retstr += "; "; retstr += Generate("; ");
// for ( x = 0 ; x < 10 ; x++ ) // for ( x = 0 ; x < 10 ; x++ )
// ^^^^^^^^ // ^^^^^^^^
retstr += GenerateNode((SYMBOL) fl.kids.Pop()); retstr += GenerateNode((SYMBOL) fl.kids.Pop());
retstr += "; "; retstr += Generate("; ");
// for ( x = 0 ; x < 10 ; x++ ) // for ( x = 0 ; x < 10 ; x++ )
// ^^^^^ // ^^^^^
retstr += GenerateForLoopStatement((ForLoopStatement) fl.kids.Pop()); retstr += GenerateForLoopStatement((ForLoopStatement) fl.kids.Pop());
retstr += ")\n"; retstr += GenerateLine(")");
// CompoundStatement handles indentation itself but we need to do it // CompoundStatement handles indentation itself but we need to do it
// otherwise. // otherwise.
@ -555,7 +586,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
/// Generates the code for a ForLoopStatement node. /// Generates the code for a ForLoopStatement node.
/// </summary> /// </summary>
/// <param name="fls">The ForLoopStatement node.</param> /// <param name="fls">The ForLoopStatement node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for ForLoopStatement fls.</returns>
private string GenerateForLoopStatement(ForLoopStatement fls) private string GenerateForLoopStatement(ForLoopStatement fls)
{ {
string retstr = String.Empty; string retstr = String.Empty;
@ -566,7 +597,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
{ {
retstr += GenerateNode(s); retstr += GenerateNode(s);
if (0 < comma--) if (0 < comma--)
retstr += ", "; retstr += Generate(", ");
} }
return retstr; return retstr;
@ -576,13 +607,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
/// Generates the code for a BinaryExpression node. /// Generates the code for a BinaryExpression node.
/// </summary> /// </summary>
/// <param name="be">The BinaryExpression node.</param> /// <param name="be">The BinaryExpression node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for BinaryExpression be.</returns>
private string GenerateBinaryExpression(BinaryExpression be) private string GenerateBinaryExpression(BinaryExpression be)
{ {
string retstr = String.Empty; string retstr = String.Empty;
retstr += GenerateNode((SYMBOL) be.kids.Pop()); retstr += GenerateNode((SYMBOL) be.kids.Pop());
retstr += String.Format(" {0} ", be.ExpressionSymbol); retstr += Generate(String.Format(" {0} ", be.ExpressionSymbol), be);
foreach (SYMBOL kid in be.kids) foreach (SYMBOL kid in be.kids)
retstr += GenerateNode(kid); retstr += GenerateNode(kid);
@ -593,12 +624,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
/// Generates the code for a UnaryExpression node. /// Generates the code for a UnaryExpression node.
/// </summary> /// </summary>
/// <param name="ue">The UnaryExpression node.</param> /// <param name="ue">The UnaryExpression node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for UnaryExpression ue.</returns>
private string GenerateUnaryExpression(UnaryExpression ue) private string GenerateUnaryExpression(UnaryExpression ue)
{ {
string retstr = String.Empty; string retstr = String.Empty;
retstr += ue.UnarySymbol; retstr += Generate(ue.UnarySymbol, ue);
retstr += GenerateNode((SYMBOL) ue.kids.Pop()); retstr += GenerateNode((SYMBOL) ue.kids.Pop());
return retstr; return retstr;
@ -608,15 +639,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
/// Generates the code for a ParenthesisExpression node. /// Generates the code for a ParenthesisExpression node.
/// </summary> /// </summary>
/// <param name="pe">The ParenthesisExpression node.</param> /// <param name="pe">The ParenthesisExpression node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for ParenthesisExpression pe.</returns>
private string GenerateParenthesisExpression(ParenthesisExpression pe) private string GenerateParenthesisExpression(ParenthesisExpression pe)
{ {
string retstr = String.Empty; string retstr = String.Empty;
retstr += "("; retstr += Generate("(");
foreach (SYMBOL kid in pe.kids) foreach (SYMBOL kid in pe.kids)
retstr += GenerateNode(kid); retstr += GenerateNode(kid);
retstr += ")"; retstr += Generate(")");
return retstr; return retstr;
} }
@ -625,7 +656,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
/// Generates the code for a IncrementDecrementExpression node. /// Generates the code for a IncrementDecrementExpression node.
/// </summary> /// </summary>
/// <param name="ide">The IncrementDecrementExpression node.</param> /// <param name="ide">The IncrementDecrementExpression node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for IncrementDecrementExpression ide.</returns>
private string GenerateIncrementDecrementExpression(IncrementDecrementExpression ide) private string GenerateIncrementDecrementExpression(IncrementDecrementExpression ide)
{ {
string retstr = String.Empty; string retstr = String.Empty;
@ -633,10 +664,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
if (0 < ide.kids.Count) if (0 < ide.kids.Count)
{ {
IdentDotExpression dot = (IdentDotExpression) ide.kids.Top; IdentDotExpression dot = (IdentDotExpression) ide.kids.Top;
retstr += String.Format("{0}", ide.PostOperation ? dot.Name + "." + dot.Member + ide.Operation : ide.Operation + dot.Name + "." + dot.Member); retstr += Generate(String.Format("{0}", ide.PostOperation ? dot.Name + "." + dot.Member + ide.Operation : ide.Operation + dot.Name + "." + dot.Member), ide);
} }
else else
retstr += String.Format("{0}", ide.PostOperation ? ide.Name + ide.Operation : ide.Operation + ide.Name); retstr += Generate(String.Format("{0}", ide.PostOperation ? ide.Name + ide.Operation : ide.Operation + ide.Name), ide);
return retstr; return retstr;
} }
@ -645,15 +676,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
/// Generates the code for a TypecastExpression node. /// Generates the code for a TypecastExpression node.
/// </summary> /// </summary>
/// <param name="te">The TypecastExpression node.</param> /// <param name="te">The TypecastExpression node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for TypecastExpression te.</returns>
private string GenerateTypecastExpression(TypecastExpression te) private string GenerateTypecastExpression(TypecastExpression te)
{ {
string retstr = String.Empty; string retstr = String.Empty;
// we wrap all typecasted statements in parentheses // we wrap all typecasted statements in parentheses
retstr += String.Format("({0}) (", te.TypecastType); retstr += Generate(String.Format("({0}) (", te.TypecastType), te);
retstr += GenerateNode((SYMBOL) te.kids.Pop()); retstr += GenerateNode((SYMBOL) te.kids.Pop());
retstr += ")"; retstr += Generate(")");
return retstr; return retstr;
} }
@ -662,17 +693,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
/// Generates the code for a FunctionCall node. /// Generates the code for a FunctionCall node.
/// </summary> /// </summary>
/// <param name="fc">The FunctionCall node.</param> /// <param name="fc">The FunctionCall node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for FunctionCall fc.</returns>
private string GenerateFunctionCall(FunctionCall fc) private string GenerateFunctionCall(FunctionCall fc)
{ {
string retstr = String.Empty; string retstr = String.Empty;
retstr += String.Format("{0}(", fc.Id); retstr += Generate(String.Format("{0}(", fc.Id), fc);
foreach (SYMBOL kid in fc.kids) foreach (SYMBOL kid in fc.kids)
retstr += GenerateNode(kid); retstr += GenerateNode(kid);
retstr += ")"; retstr += Generate(")");
return retstr; return retstr;
} }
@ -681,7 +712,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
/// Generates the code for a Constant node. /// Generates the code for a Constant node.
/// </summary> /// </summary>
/// <param name="c">The Constant node.</param> /// <param name="c">The Constant node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for Constant c.</returns>
private string GenerateConstant(Constant c) private string GenerateConstant(Constant c)
{ {
string retstr = String.Empty; string retstr = String.Empty;
@ -697,10 +728,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
// need to quote strings // need to quote strings
if ("LSL_Types.LSLString" == c.Type) if ("LSL_Types.LSLString" == c.Type)
retstr += "\""; retstr += Generate("\"");
retstr += c.Value; retstr += Generate(c.Value, c);
if ("LSL_Types.LSLString" == c.Type) if ("LSL_Types.LSLString" == c.Type)
retstr += "\""; retstr += Generate("\"");
return retstr; return retstr;
} }
@ -709,18 +740,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
/// Generates the code for a VectorConstant node. /// Generates the code for a VectorConstant node.
/// </summary> /// </summary>
/// <param name="vc">The VectorConstant node.</param> /// <param name="vc">The VectorConstant node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for VectorConstant vc.</returns>
private string GenerateVectorConstant(VectorConstant vc) private string GenerateVectorConstant(VectorConstant vc)
{ {
string retstr = String.Empty; string retstr = String.Empty;
retstr += String.Format("new {0}(", vc.Type); retstr += Generate(String.Format("new {0}(", vc.Type), vc);
retstr += GenerateNode((SYMBOL) vc.kids.Pop()); retstr += GenerateNode((SYMBOL) vc.kids.Pop());
retstr += ", "; retstr += Generate(", ");
retstr += GenerateNode((SYMBOL) vc.kids.Pop()); retstr += GenerateNode((SYMBOL) vc.kids.Pop());
retstr += ", "; retstr += Generate(", ");
retstr += GenerateNode((SYMBOL) vc.kids.Pop()); retstr += GenerateNode((SYMBOL) vc.kids.Pop());
retstr += ")"; retstr += Generate(")");
return retstr; return retstr;
} }
@ -729,20 +760,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
/// Generates the code for a RotationConstant node. /// Generates the code for a RotationConstant node.
/// </summary> /// </summary>
/// <param name="rc">The RotationConstant node.</param> /// <param name="rc">The RotationConstant node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for RotationConstant rc.</returns>
private string GenerateRotationConstant(RotationConstant rc) private string GenerateRotationConstant(RotationConstant rc)
{ {
string retstr = String.Empty; string retstr = String.Empty;
retstr += String.Format("new {0}(", rc.Type); retstr += Generate(String.Format("new {0}(", rc.Type), rc);
retstr += GenerateNode((SYMBOL) rc.kids.Pop()); retstr += GenerateNode((SYMBOL) rc.kids.Pop());
retstr += ", "; retstr += Generate(", ");
retstr += GenerateNode((SYMBOL) rc.kids.Pop()); retstr += GenerateNode((SYMBOL) rc.kids.Pop());
retstr += ", "; retstr += Generate(", ");
retstr += GenerateNode((SYMBOL) rc.kids.Pop()); retstr += GenerateNode((SYMBOL) rc.kids.Pop());
retstr += ", "; retstr += Generate(", ");
retstr += GenerateNode((SYMBOL) rc.kids.Pop()); retstr += GenerateNode((SYMBOL) rc.kids.Pop());
retstr += ")"; retstr += Generate(")");
return retstr; return retstr;
} }
@ -751,51 +782,155 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
/// Generates the code for a ListConstant node. /// Generates the code for a ListConstant node.
/// </summary> /// </summary>
/// <param name="lc">The ListConstant node.</param> /// <param name="lc">The ListConstant node.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>String containing C# code for ListConstant lc.</returns>
private string GenerateListConstant(ListConstant lc) private string GenerateListConstant(ListConstant lc)
{ {
string retstr = String.Empty; string retstr = String.Empty;
retstr += String.Format("new {0}(", lc.Type); retstr += Generate(String.Format("new {0}(", lc.Type), lc);
foreach (SYMBOL kid in lc.kids) foreach (SYMBOL kid in lc.kids)
retstr += GenerateNode(kid); retstr += GenerateNode(kid);
retstr += ")"; retstr += Generate(")");
return retstr; return retstr;
} }
/// <summary>
/// Prints a newline.
/// </summary>
/// <returns>A newline.</returns>
private string GenerateLine()
{
return GenerateLine("");
}
/// <summary>
/// Prints text, followed by a newline.
/// </summary>
/// <param name="s">String of text to print.</param>
/// <returns>String s followed by newline.</returns>
private string GenerateLine(string s)
{
return GenerateLine(s, null);
}
/// <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>
private string GenerateLine(string s, SYMBOL sym)
{
string retstr = Generate(s, sym) + "\n";
m_CSharpLine++;
m_CSharpCol = 1;
return retstr;
}
/// <summary>
/// Prints text.
/// </summary>
/// <param name="s">String of text to print.</param>
/// <returns>String s.</returns>
private string Generate(string s)
{
return Generate(s, null);
}
/// <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>
private string Generate(string s, SYMBOL sym)
{
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;
return s;
}
/// <summary> /// <summary>
/// Prints text correctly indented, followed by a newline. /// Prints text correctly indented, followed by a newline.
/// </summary> /// </summary>
/// <param name="s">String of text to print.</param> /// <param name="s">String of text to print.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>Properly indented string s followed by newline.</returns>
private string WriteIndentedLine(string s) private string GenerateIndentedLine(string s)
{ {
return WriteIndented(s) + "\n"; return GenerateIndentedLine(s, null);
}
/// <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>
private string GenerateIndentedLine(string s, SYMBOL sym)
{
string retstr = GenerateIndented(s, sym) + "\n";
m_CSharpLine++;
m_CSharpCol = 1;
return retstr;
} }
/// <summary> /// <summary>
/// Prints text correctly indented. /// Prints text correctly indented.
/// </summary> /// </summary>
/// <param name="s">String of text to print.</param> /// <param name="s">String of text to print.</param>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>Properly indented string s.</returns>
private string WriteIndented(string s) //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>
private string GenerateIndented(string s, SYMBOL sym)
{ {
return Indent() + s; string retstr = Indent() + s;
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;
return retstr;
} }
/// <summary> /// <summary>
/// Prints correct indentation. /// Prints correct indentation.
/// </summary> /// </summary>
/// <returns>String containing C# code for SYMBOL s.</returns> /// <returns>Indentation based on brace count.</returns>
private string Indent() private string Indent()
{ {
string retstr = String.Empty; string retstr = String.Empty;
for (int i = 0; i < m_braceCount; i++) for (int i = 0; i < m_braceCount; i++)
retstr += " "; for (int j = 0; j < m_indentWidth; j++)
{
retstr += " ";
m_CSharpCol++;
}
return retstr; return retstr;
} }

View File

@ -38,7 +38,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools.Tests
/// The generated C# code is compared against the expected C# code. /// The generated C# code is compared against the expected C# code.
/// </summary> /// </summary>
[TestFixture] [TestFixture]
public class LSLCompilerTest public class CSCodeGeneratorTest
{ {
[Test] [Test]
public void TestDefaultState() public void TestDefaultState()
@ -685,7 +685,7 @@ default
integer x = 1; integer x = 1;
if(x) llSay(0, ""Hello""); if(x) llSay(0, ""Hello"");
if(1) if(1)
{ {
llSay(0, ""Hi""); llSay(0, ""Hi"");
integer r = 3; integer r = 3;
@ -791,7 +791,7 @@ default
integer y = 0; integer y = 0;
if(x && y) llSay(0, ""Hello""); if(x && y) llSay(0, ""Hello"");
if(x || y) if(x || y)
{ {
llSay(0, ""Hi""); llSay(0, ""Hi"");
integer r = 3; integer r = 3;

View File

@ -0,0 +1,120 @@
/*
* 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.
* * Neither the name of the OpenSim Project nor the
* 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.IO;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using Microsoft.CSharp;
using NUnit.Framework;
using OpenSim.Region.ScriptEngine.Shared.CodeTools;
namespace OpenSim.Region.ScriptEngine.Shared.CodeTools.Tests
{
/// <summary>
/// Tests the LSL compiler. Among other things, test that error messages
/// generated by the C# compiler can be mapped to prper lines/columns in
/// the LSL source.
/// </summary>
[TestFixture]
public class CompilerTest
{
private string m_testDir;
private CSharpCodeProvider m_CSCodeProvider;
private CompilerParameters m_compilerParameters;
private CompilerResults m_compilerResults;
/// <summary>
/// Creates a temporary directory where build artifacts are stored.
/// </summary>
[TestFixtureSetUp]
public void Init()
{
m_testDir = Path.Combine(Path.GetTempPath(), "opensim_compilerTest_" + Path.GetRandomFileName());
if (!Directory.Exists(m_testDir))
{
// Create the temporary directory for housing build artifacts.
Directory.CreateDirectory(m_testDir);
}
// Create a CSCodeProvider and CompilerParameters.
m_CSCodeProvider = new CSharpCodeProvider();
m_compilerParameters = new CompilerParameters();
string rootPath = Path.Combine(Path.GetDirectoryName(System.AppDomain.CurrentDomain.BaseDirectory), "bin");
m_compilerParameters.ReferencedAssemblies.Add(Path.Combine(rootPath, "OpenSim.Region.ScriptEngine.Shared.dll"));
m_compilerParameters.ReferencedAssemblies.Add(Path.Combine(rootPath, "OpenSim.Region.ScriptEngine.Shared.Api.Runtime.dll"));
m_compilerParameters.GenerateExecutable = false;
}
/// <summary>
/// Removes the temporary build directory and any build artifacts
/// inside it.
/// </summary>
[TestFixtureTearDown]
public void CleanUp()
{
if (Directory.Exists(m_testDir))
{
// Blow away the temporary directory with artifacts.
Directory.Delete(m_testDir, true);
}
}
[Test]
/// <summary>
/// Test the C# compiler error message can be mapped to the correct
/// line/column in the LSL source when an undeclared variable is used.
/// </summary>
public void TestUseUndeclaredVariable()
{
m_compilerParameters.OutputAssembly = Path.Combine(m_testDir, Path.GetRandomFileName() + ".dll");
string input = @"default
{
state_entry()
{
integer y = x + 3;
}
}";
CSCodeGenerator cg = new CSCodeGenerator();
string output = "using OpenSim.Region.ScriptEngine.Shared; using System.Collections.Generic;\n" +
"namespace SecondLife { " +
"public class Script : OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass {\n" +
"public Script() { } " +
cg.Convert(input) +
"} }\n";
Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> positionMap = cg.PositionMap;
m_compilerResults = m_CSCodeProvider.CompileAssemblyFromSource(m_compilerParameters, output);
Assert.AreEqual(new KeyValuePair<int, int>(5, 21),
positionMap[new KeyValuePair<int, int>(m_compilerResults.Errors[0].Line, m_compilerResults.Errors[0].Column)]);
}
}
}