#region License /* ********************************************************************************** * This source code is subject to terms and conditions of the MIT License * for Irony. A copy of the license can be found in the License.txt file * at the root of this distribution. * By using this source code in any fashion, you are agreeing to be bound by the terms of the * MIT License. * You must not remove this notice from this software. * **********************************************************************************/ #endregion //Authors: Roman Ivantsov, Philipp Serr using System; using System.Collections.Generic; using System.Text; using System.Globalization; namespace Irony.Compiler { public static class TerminalFactory { public static StringLiteral CreateCSharpString(string name) { StringLiteral term = new StringLiteral(name, TermOptions.None); term.AddStartEnd("\"", ScanFlags.AllowAllEscapes); term.AddPrefixFlag("@", ScanFlags.DisableEscapes | ScanFlags.AllowLineBreak | ScanFlags.AllowDoubledQuote); return term; } public static StringLiteral CreateCSharpChar(string name) { StringLiteral term = new StringLiteral(name, TermOptions.None); term.AddStartEnd("'", ScanFlags.IsChar); return term; } public static StringLiteral CreateVbString(string name) { StringLiteral term = new StringLiteral(name, TermOptions.SpecialIgnoreCase); term.AddStartEnd("\"", ScanFlags.DisableEscapes | ScanFlags.AllowDoubledQuote); term.AddSuffixCodes("$", TypeCode.String); term.AddSuffixCodes("c", TypeCode.Char); return term; } public static StringLiteral CreatePythonString(string name) { StringLiteral term = new StringLiteral(name, TermOptions.SpecialIgnoreCase); term.AddStartEnd("'", ScanFlags.AllowAllEscapes); term.AddStartEnd("'''", ScanFlags.AllowAllEscapes | ScanFlags.AllowLineBreak); term.AddStartEnd("\"", ScanFlags.AllowAllEscapes); term.AddStartEnd("\"\"\"", ScanFlags.AllowAllEscapes | ScanFlags.AllowLineBreak); term.AddPrefixFlag("u", ScanFlags.AllowAllEscapes); term.AddPrefixFlag("r", ScanFlags.DisableEscapes ); term.AddPrefixFlag("ur", ScanFlags.DisableEscapes); return term; } //http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-334.pdf section 9.4.4 public static NumberLiteral CreateCSharpNumber(string name) { NumberLiteral term = new NumberLiteral(name, TermOptions.EnableQuickParse | TermOptions.SpecialIgnoreCase); term.DefaultIntTypes = new TypeCode[] { TypeCode.Int32, TypeCode.UInt32, TypeCode.Int64, TypeCode.UInt64 }; term.DefaultFloatType = TypeCode.Double; term.AddPrefixFlag("0x", ScanFlags.Hex); term.AddSuffixCodes("u", TypeCode.UInt32, TypeCode.UInt64); term.AddSuffixCodes("l", TypeCode.Int64, TypeCode.UInt64); term.AddSuffixCodes("ul", TypeCode.UInt64); term.AddSuffixCodes("f", TypeCode.Single); term.AddSuffixCodes("d", TypeCode.Double); term.AddSuffixCodes("m", TypeCode.Decimal); return term; } //http://www.microsoft.com/downloads/details.aspx?FamilyId=6D50D709-EAA4-44D7-8AF3-E14280403E6E&displaylang=en section 2 public static NumberLiteral CreateVbNumber(string name) { NumberLiteral term = new NumberLiteral(name, TermOptions.EnableQuickParse | TermOptions.SpecialIgnoreCase); term.DefaultIntTypes = new TypeCode[] { TypeCode.Int32, TypeCode.Int64 }; //term.DefaultFloatType = TypeCode.Double; it is default term.AddPrefixFlag("&H", ScanFlags.Hex); term.AddPrefixFlag("&O", ScanFlags.Octal); term.AddSuffixCodes("S", TypeCode.Int16); term.AddSuffixCodes("I", TypeCode.Int32); term.AddSuffixCodes("%", TypeCode.Int32); term.AddSuffixCodes("L", TypeCode.Int64); term.AddSuffixCodes("&", TypeCode.Int64); term.AddSuffixCodes("D", TypeCode.Decimal); term.AddSuffixCodes("@", TypeCode.Decimal); term.AddSuffixCodes("F", TypeCode.Single); term.AddSuffixCodes("!", TypeCode.Single); term.AddSuffixCodes("R", TypeCode.Double); term.AddSuffixCodes("#", TypeCode.Double); term.AddSuffixCodes("US", TypeCode.UInt16); term.AddSuffixCodes("UI", TypeCode.UInt32); term.AddSuffixCodes("UL", TypeCode.UInt64); return term; } //http://docs.python.org/ref/numbers.html public static NumberLiteral CreatePythonNumber(string name) { NumberLiteral term = new NumberLiteral(name, TermOptions.EnableQuickParse | TermOptions.SpecialIgnoreCase | TermOptions.NumberAllowStartEndDot); //default int types are Integer (32bit) -> LongInteger (BigInt); Try Int64 before BigInt: Better performance? term.DefaultIntTypes = new TypeCode[] { TypeCode.Int32, TypeCode.Int64, NumberLiteral.TypeCodeBigInt }; // term.DefaultFloatType = TypeCode.Double; -- it is default //float type is implementation specific, thus try decimal first (higher precision) //term.DefaultFloatTypes = new TypeCode[] { TypeCode.Decimal, TypeCode.Double }; term.AddPrefixFlag("0x", ScanFlags.Hex); term.AddPrefixFlag("0", ScanFlags.Octal); term.AddSuffixCodes("L", TypeCode.Int64, NumberLiteral.TypeCodeBigInt); term.AddSuffixCodes("J", NumberLiteral.TypeCodeImaginary); return term; } //Note - this is incomplete implementation; need to add functionality to NumberTerminal class to support type detection based // on exponent symbol. // From R6RS: // ... representations of number objects may be written with an exponent marker that indicates the desired precision // of the inexact representation. The letters s, f, d, and l specify the use of short, single, double, and long precision, respectively. public static NumberLiteral CreateSchemeNumber(string name) { NumberLiteral term = new NumberLiteral(name, TermOptions.EnableQuickParse | TermOptions.SpecialIgnoreCase); term.DefaultIntTypes = new TypeCode[] { TypeCode.Int32, TypeCode.Int64, NumberLiteral.TypeCodeBigInt }; term.DefaultFloatType = TypeCode.Double; // it is default term.ExponentSymbols = "sfdl"; term.AddPrefixFlag("#b", ScanFlags.Binary); term.AddPrefixFlag("#o", ScanFlags.Octal); term.AddPrefixFlag("#x", ScanFlags.Hex); term.AddPrefixFlag("#d", ScanFlags.None); term.AddPrefixFlag("#i", ScanFlags.None); // inexact prefix, has no effect term.AddPrefixFlag("#e", ScanFlags.None); // exact prefix, has no effect term.AddSuffixCodes("J", NumberLiteral.TypeCodeImaginary); return term; } public static IdentifierTerminal CreateCSharpIdentifier(string name) { IdentifierTerminal id = new IdentifierTerminal(name); id.SetOption(TermOptions.CanStartWithEscape); string strKeywords = "abstract as base bool break byte case catch char checked " + "class const continue decimal default delegate do double else enum event explicit extern false finally " + "fixed float for foreach goto if implicit in int interface internal is lock long namespace " + "new null object operator out override params private protected public " + "readonly ref return sbyte sealed short sizeof stackalloc static string " + "struct switch this throw true try typeof uint ulong unchecked unsafe ushort using virtual void " + "volatile while"; id.AddKeywordList(strKeywords); id.AddPrefixFlag("@", ScanFlags.IsNotKeyword | ScanFlags.DisableEscapes); //From spec: //Start char is "_" or letter-character, which is a Unicode character of classes Lu, Ll, Lt, Lm, Lo, or Nl id.StartCharCategories.AddRange(new UnicodeCategory[] { UnicodeCategory.UppercaseLetter, //Ul UnicodeCategory.LowercaseLetter, //Ll UnicodeCategory.TitlecaseLetter, //Lt UnicodeCategory.ModifierLetter, //Lm UnicodeCategory.OtherLetter, //Lo UnicodeCategory.LetterNumber //Nl }); //Internal chars /* From spec: identifier-part-character: letter-character | decimal-digit-character | connecting-character | combining-character | formatting-character */ id.CharCategories.AddRange(id.StartCharCategories); //letter-character categories id.CharCategories.AddRange(new UnicodeCategory[] { UnicodeCategory.DecimalDigitNumber, //Nd UnicodeCategory.ConnectorPunctuation, //Pc UnicodeCategory.SpacingCombiningMark, //Mc UnicodeCategory.NonSpacingMark, //Mn UnicodeCategory.Format //Cf }); //Chars to remove from final identifier id.CharsToRemoveCategories.Add(UnicodeCategory.Format); return id; } public static IdentifierTerminal CreatePythonIdentifier(string name) { IdentifierTerminal id = new IdentifierTerminal("Identifier"); //defaults are OK id.AddKeywords("and", "del", "from", "not", "while", "as", "elif", "global", "or", "with", "assert", "else", "if", "pass", "yield", "break", "except", "import", "print", "class", "exec", "in", "raise", "continue", "finally", "is", "return", "def", "for", "lambda", "try"); return id; } }//class }//namespace