// // ORIGINAL CODE BASE IS Copyright (C) 2006-2010 by Alphons van der Heijden. // The code was donated on 2010-04-28 by Alphons van der Heijden to Brandon 'Dimentox Travanti' Husbands & // Malcolm J. Kudra, who in turn License under the GPLv2 in agreement with Alphons van der Heijden's 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 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 States; private XmlDocument xml; public LSL2CSharp(XmlDocument xml) { this.xml = xml; this.States = new List(); } 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( @"(?\s*) (?: (?[^{};]*;) | (?[^{;(]*) (? \( [^{]* \) \s* \{ (?> [^{}]+ | \{ (?) | \} (?<-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(@" < (? (?> [^=(),>]+ | \( (?) | \) (?<-nr>) | , )* (?(nr)(?!)) ) , (? (?> [^=(),>]+ | \( (?) | \) (?<-nr>) | , )* (?(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(@" < (? (?> [^=(),>]+ | \( (?) | \) (?<-nr>) | , )* (?(nr)(?!)) ) , (? (?> [^=(),>]+ | \( (?) | \) (?<-nr>) | , )* (?(nr)(?!)) ) , (? (?> [^=(),>]+ | \( (?) | \) (?<-nr>) | , )* (?(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)(?!)) \] ", 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 h) { h = new List(); 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 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; } /// /// This Class translates LSL script into CSharp code /// /// LSL scripting code /// CSHarp code public string Parse(string strLSLCode) { List 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; } } }