LSLEditor/trunk/Helpers/LSL2CSharp.cs
dimentox 3151e1e342 proper import
git-svn-id: https://lsleditor.svn.sourceforge.net/svnroot/lsleditor@9 3f4676ac-adda-40fd-8265-58d1435b1672
2010-04-29 07:47:27 +00:00

642 lines
15 KiB
C#

// /**
// ********
// *
// * ORIGIONAL CODE BASE IS Copyright (C) 2006-2010 by Alphons van der Heijden
// * The code was donated on 4/28/2010 by Alphons van der Heijden
// * To Brandon'Dimentox Travanti' Husbands & Malcolm J. Kudra which in turn Liscense under the GPLv2.
// * In agreement to Alphons van der Heijden wishes.
// *
// * The community would like to thank Alphons for all of his hard work, blood sweat and tears.
// * Without his work the community would be stuck with crappy editors.
// *
// * The source code in this file ("Source Code") is provided by The LSLEditor Group
// * to you under the terms of the GNU General Public License, version 2.0
// * ("GPL"), unless you have obtained a separate licensing agreement
// * ("Other License"), formally executed by you and The LSLEditor Group. Terms of
// * the GPL can be found in the gplv2.txt document.
// *
// ********
// * GPLv2 Header
// ********
// * LSLEditor, a External editor for the LSL Language.
// * Copyright (C) 2010 The LSLEditor Group.
//
// * This program is free software; you can redistribute it and/or
// * modify it under the terms of the GNU General Public License
// * as published by the Free Software Foundation; either version 2
// * of the License, or (at your option) any later version.
// *
// * This program is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// * GNU General Public License for more details.
// *
// * You should have received a copy of the GNU General Public License
// * along with this program; if not, write to the Free Software
// * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
// ********
// *
// * The above copyright notice and this permission notice shall be included in all
// * copies or substantial portions of the Software.
// *
// ********
// */
using System;
using System.Xml;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace LSLEditor
{
class LSL2CSharp
{
public List<string> States;
private XmlDocument xml;
public LSL2CSharp(XmlDocument xml)
{
this.xml = xml;
this.States = new List<string>();
}
private string CorrectGlobalEvaluator(Match m)
{
string strPrefix = m.Groups["prefix"].Value;
string strPublic = m.Groups["public"].Value;
string strPostfix = m.Groups["postfix"].Value;
if (strPublic.EndsWith(";"))
return strPrefix + "public static " + strPublic + strPostfix;
// has to be static,
// because the vars must keep their values between state changes
// 22 june 2007, added
Regex regex = new Regex(@"\w*", RegexOptions.IgnorePatternWhitespace );
int intCount=0;
for (Match pm = regex.Match(strPublic); pm.Success; pm = pm.NextMatch())
{
if (pm.Value.Length > 0)
intCount++;
if (intCount > 1)
break;
}
if(intCount==1)
return strPrefix + "public void " + strPublic + strPostfix;
else
return strPrefix + "public " + strPublic + strPostfix;
}
private string CorrectGlobal(string strC)
{
Regex regex = new Regex(
@"(?<prefix>\s*)
(?:
(?<public>[^{};]*;)
|
(?<public>[^{;(]*)
(?<postfix>
\( [^{]* \) \s*
\{
(?>
[^{}]+
| \{ (?<number>)
| \} (?<-number>)
)*
(?(number)(?!))
\}
)
)",
RegexOptions.IgnorePatternWhitespace);
return regex.Replace(strC, new MatchEvaluator(CorrectGlobalEvaluator));
}
private string RemoveComments(string strC)
{
if (Properties.Settings.Default.CommentCStyle)
{
int intI = strC.IndexOf("/*");
while (intI > 0)
{
int intJ = strC.IndexOf("*" + "/", intI);
if (intJ < 0)
break;
strC = strC.Remove(intI, intJ - intI + 2);
intI = strC.IndexOf("/*");
}
}
return AutoFormatter.RemoveCommentsFromLines(strC);
}
private string CorrectStates(string strC,string strGlobalClass)
{
Regex regex;
// Default state
regex = new Regex(@"^\s*(default)(\W)",
RegexOptions.Multiline
| RegexOptions.IgnorePatternWhitespace
| RegexOptions.Compiled);
strC = regex.Replace(strC, @"class State_$1 : " + strGlobalClass + "$2");
// Other states
regex = new Regex(
@"^state\s+([^\s]*)(\s*\{)",
RegexOptions.Multiline
| RegexOptions.IgnorePatternWhitespace
| RegexOptions.Compiled
);
Match m = regex.Match(strC);
while (m.Success)
{
string strStateName = m.Groups[1].ToString();
this.States.Add(strStateName);
m = m.NextMatch();
}
strC = regex.Replace(strC, "class State_$1 : " + strGlobalClass + "$2");
string strGlobal = "";
if (Properties.Settings.Default.StatesInGlobalFunctions)
{
// do nothing!
}
else
{
int intDefault = strC.IndexOf("class State_default");
if (intDefault >= 0)
{
strGlobal = strC.Substring(0, intDefault);
strC = strC.Substring(intDefault);
}
}
// State change, excluding global functions
regex = new Regex(
@"(\s+)state\s+(\w*)(\s*;)",
RegexOptions.IgnorePatternWhitespace
| RegexOptions.Compiled
);
return strGlobal + regex.Replace(strC, @"$1state(""$2"")$3");
}
private string PreCorrectReservedWords(string strC)
{
#region All PreCorrect reserved C# words
Regex regex = new Regex(@"(\b)(public
| class
| override
| namespace
| void
| SecondLife
| GlobalClass
| static
| goto
| String
| Float
)(\b)",
RegexOptions.IgnorePatternWhitespace
| RegexOptions.Compiled
);
#endregion
return regex.Replace(strC, "$1_$2$3");
}
private string CorrectReservedWords(string strC)
{
#region All reserved C# words
Regex regex = new Regex(@"(\b)(new
| abstract
| as
| base
| bool
| break
| byte
| case
| catch
| char
| checked
| const
| continue
| decimal
| delegate
| double
| enum
| event
| explicit
| extern
| false
| finally
| fixed
| foreach
| implicit
| in
| int
| interface
| internal
| is
| lock
| long
| new
| null
| object
| operator
| out
| params
| private
| protected
| readonly
| ref
| sbyte
| sealed
| short
| sizeof
| stackalloc
| struct
| switch
| this
| throw
| true
| try
| typeof
| uint
| ulong
| unchecked
| unsafe
| ushort
| using
| virtual
)(\b)",
RegexOptions.IgnorePatternWhitespace
| RegexOptions.Compiled
);
#endregion
return regex.Replace(strC, "$1_$2$3");
}
private string CorrectEvent(string strC, string strName)
{
Regex regex = new Regex(
@"([^\w_])" + strName + @"(\s*)\(",
RegexOptions.IgnorePatternWhitespace
| RegexOptions.Compiled
);
return regex.Replace(strC, "$1public override void " + strName + "$2(");
}
private string CorrectEvents(string strC)
{
XmlNode words = xml.SelectSingleNode("//Words[@name='Appendix B. Events']");
foreach (XmlNode xmlNode in words.SelectNodes(".//Word"))
{
string strName = xmlNode.Attributes["name"].InnerText;
strC = CorrectEvent(strC, strName);
}
return strC;
}
// old vector parser
// <([^<>,;]*),([^<>,;]*),([^<>,;]*)>
private string CorrectVector(string strC)
{
Regex regex = new Regex(@"
<
(?<vector_x>
(?>
[^=(),>]+
| \( (?<nr>)
| \) (?<-nr>)
| ,
)*
(?(nr)(?!))
)
,
(?<vector_y>
(?>
[^=(),>]+
| \( (?<nr>)
| \) (?<-nr>)
| ,
)*
(?(nr)(?!))
)
,
(?<vector_z>
(?>
[^=()>]+
| \( (?<nr>)
| \) (?<-nr>)
| ,
)*
(?(nr)(?!))
)
>
",
RegexOptions.IgnorePatternWhitespace
| RegexOptions.Compiled
);
return regex.Replace(strC, "new vector(${vector_x},${vector_y},${vector_z})");
}
// old rotation
// <([^<>,;]*),([^<>,;]*),([^<>,;]*),([^<>,;]*)>
private string CorrectRotation(string strC)
{
Regex regex = new Regex(@"
<
(?<rotation_x>
(?>
[^=(),>]+
| \( (?<nr>)
| \) (?<-nr>)
| ,
)*
(?(nr)(?!))
)
,
(?<rotation_y>
(?>
[^=(),>]+
| \( (?<nr>)
| \) (?<-nr>)
| ,
)*
(?(nr)(?!))
)
,
(?<rotation_z>
(?>
[^=(),>]+
| \( (?<nr>)
| \) (?<-nr>)
| ,
)*
(?(nr)(?!))
)
,
(?<rotation_s>
(?>
[^=()>]+
| \( (?<nr>)
| \) (?<-nr>)
| ,
)*
(?(nr)(?!))
)
>
",
RegexOptions.IgnorePatternWhitespace
| RegexOptions.Compiled
);
return regex.Replace(strC, "new rotation(${rotation_x},${rotation_y},${rotation_z},${rotation_s})");
}
private string CorrectQuaternion(string strC)
{
Regex regex = new Regex(
@"(\b)quaternion(\b)",
RegexOptions.Compiled
| RegexOptions.IgnorePatternWhitespace
);
return regex.Replace(strC, "$1rotation$2");
}
private string CorrectListsEvaluator(Match m)
{
string strValue = m.Value;
return "new list(new object[] {" + CorrectLists(strValue.Substring(1, strValue.Length - 2)) + "})";
}
private string CorrectLists(string strC)
{
Regex regex = new Regex(
@"
\[
(?>
[^\[\]]+
| \[ (?<number>)
| \] (?<-number>)
)*
(?(number)(?!))
\]
",
RegexOptions.IgnorePatternWhitespace
| RegexOptions.Compiled);
return regex.Replace(strC, new MatchEvaluator(CorrectListsEvaluator));
}
// changed 16 aug 2007
private string CorrectJump(string strC)
{
// jump -> goto
Regex regex = new Regex(
@"(\b)jump(\s+)([^;]*;)",
RegexOptions.Compiled
| RegexOptions.IgnorePatternWhitespace
);
strC = regex.Replace(strC, "$1goto$2_$3");
// @label; -> label:;
regex = new Regex(
@"@\s*([a-z0-9_]+)\s*;",
RegexOptions.Compiled
| RegexOptions.IgnoreCase
| RegexOptions.IgnorePatternWhitespace
);
return regex.Replace(strC, "_$1:;");
}
private string RemoveQuotedStrings(string strC, out List<string> h)
{
h = new List<string>();
StringBuilder sb = new StringBuilder();
StringBuilder QuotedString = null;
for (int intI = 0; intI < strC.Length; intI++)
{
char chrC = strC[intI];
if (chrC == '"')
{
if (QuotedString != null)
{
// end of a quoted string
sb.Append('"');
sb.Append(h.Count.ToString());
sb.Append('"');
h.Add(QuotedString.ToString());
QuotedString = null;
continue;
}
else
{
if (chrC == '"')
{
// start of a new quoted string
QuotedString = new StringBuilder();
continue;
}
// it was just a newline char, and not in a string
}
}
if (QuotedString == null)
sb.Append(chrC);
else
{
if (chrC == '\n')
{
QuotedString.Append('\\');
chrC = 'n';
}
if (chrC != '\\')
{
QuotedString.Append(chrC);
}
else // it is a backslash
{
intI++;
chrC = strC[intI];
if (chrC == 't') // tabs are 4 spaces in SL world!!
{
QuotedString.Append(" ");
}
else // nope, it is no tab, just output it all
{
QuotedString.Append('\\');
QuotedString.Append(chrC);
}
}
}
}
return sb.ToString();
}
private string InsertQuotedStrings(string strC, List<string> h)
{
StringBuilder sb = new StringBuilder();
StringBuilder QuotedString = null;
for (int intI = 0; intI < strC.Length; intI++)
{
char chrC = strC[intI];
if (chrC == '"')
{
if (QuotedString == null)
{
QuotedString = new StringBuilder();
}
else
{
sb.Append('"');
int intNumber;
// State("default") is not a number, result of 'CorrectStates'
if (int.TryParse(QuotedString.ToString(), out intNumber))
sb.Append(h[intNumber]);
else
sb.Append(QuotedString.ToString());
sb.Append('"');
QuotedString = null;
}
continue;
}
if (QuotedString == null)
sb.Append(chrC);
else
QuotedString.Append(chrC);
}
return sb.ToString();
}
private string MakeGlobalAndLocal(string strC)
{
Regex regexDefault = new Regex(@"^\s*(default)\W",
RegexOptions.IgnorePatternWhitespace
| RegexOptions.Multiline
| RegexOptions.Compiled);
Match matchDefault = regexDefault.Match(strC);
string strGlobal;
int intDefaultIndex;
if (matchDefault.Groups.Count == 2)
{
States.Add("default");
intDefaultIndex = matchDefault.Groups[1].Index;
strGlobal = CorrectGlobal(strC.Substring(0, intDefaultIndex));
}
else
{
intDefaultIndex = 0;
strGlobal = "";
}
return "class GlobalClass : SecondLife\n{\n" + strGlobal + "}\n" + strC.Substring(intDefaultIndex);
}
private string Capitalize(string strC, string strName)
{
Regex regex = new Regex(@"(\W)"+strName+@"(\W)",
RegexOptions.IgnorePatternWhitespace
| RegexOptions.Multiline
| RegexOptions.Compiled);
string strCap = strName[0].ToString().ToUpper() + strName.Substring(1);
return regex.Replace(strC, "$1"+strCap+"$2");
}
private string RemoveSingleQuotes(string strC)
{
if (Properties.Settings.Default.SingleQuote)
return strC.Replace("'", "");
else
return strC;
}
/// <summary>
/// This Class translates LSL script into CSharp code
/// </summary>
/// <param name="strLSLCode">LSL scripting code</param>
/// <returns>CSHarp code</returns>
public string Parse(string strLSLCode)
{
List<string> quotedStrings;
string strGlobalClass = "GlobalClass";
string strC = strLSLCode;
strC = RemoveComments(strC);
strC = RemoveQuotedStrings(strC, out quotedStrings);
strC = RemoveSingleQuotes(strC);
strC = PreCorrectReservedWords(strC); // Experimental
strC = MakeGlobalAndLocal(strC);
strC = CorrectJump(strC);
strC = CorrectEvents(strC);
strC = Capitalize(strC, "float");
strC = Capitalize(strC, "string"); // llList2string is also translated
strC = CorrectStates(strC, strGlobalClass);
strC = CorrectReservedWords(strC); // Experimental
strC = CorrectRotation(strC);
strC = CorrectQuaternion(strC);
strC = CorrectVector(strC);
strC = CorrectLists(strC);
strC = InsertQuotedStrings(strC, quotedStrings);
return strC;
}
}
}