private int Test <TLetter>(string pattern, bool caseSensitive, IUnicodeMapper <TLetter> mapper, TLetter?eof, RangeSet <TLetter> validRanges, out AlphabetBuilder <TLetter> builder) where TLetter : struct, IEquatable <TLetter>, IComparable <TLetter> { this.output.WriteLine("Input regex (Case Sensitive: {0}, EOF letter: {1}):", caseSensitive, eof.HasValue); this.output.WriteLine(pattern); var provider = new UnicodeCharSetProvider(); var regex = RegexParser.Parse(pattern, null).ToInvariant(mapper, provider, caseSensitive); this.output.WriteLine(""); this.output.WriteLine("{0} regex:", typeof(TLetter).Name); this.output.WriteLine(regex.ToString()); builder = new AlphabetBuilder <TLetter>(regex, eof, validRanges); this.output.WriteLine(""); this.output.WriteLine("Generated letter mapping:"); foreach (var pair in builder.AlphabetById) { this.output.WriteLine("{0}: {1} ({2})", pair.Key, pair.Value, pair.Value.Count); } this.output.WriteLine(""); this.output.WriteLine("Letter Regex:"); this.output.WriteLine(builder.Expression.ToString()); this.output.WriteLine(""); this.output.WriteLine("Mapping function pseudocode:"); var inSwitch = false; foreach (var grouping in builder .AlphabetById .SelectMany(p => p.Value.Select(r => new KeyValuePair <Range <TLetter>, LetterId>(r, p.Key))) .GroupBy(p => new { Range = (!typeof(TLetter).IsPrimitive) || p.Key.Expand().Skip(2).Any(), LetterId = p.Value }, p => p.Key) .OrderBy(p => p.Key.Range) .ThenBy(p => p.Key.LetterId)) { if (grouping.Key.Range) { if (inSwitch) { this.output.WriteLine("}"); inSwitch = false; } this.output.WriteLine("if ({0}) return {1}", string.Join(" ||" + Environment.NewLine + " ", grouping.OrderBy(r => r.From).Select(r => r.From.CompareTo(r.To) == 0 ? $"(v == '{r.From}')" : $"(v >= '{r.From}' && v <= '{r.To}')")), grouping.Key.LetterId); } else { if (!inSwitch) { this.output.WriteLine("switch (v) {"); inSwitch = true; } this.output.WriteLine("{0}" + Environment.NewLine + " return {1}", string.Join(Environment.NewLine, grouping.SelectMany(g => g.Expand()).OrderBy(r => r).Select(r => $" case '{r}':")), grouping.Key.LetterId); } } if (inSwitch) { this.output.WriteLine("}"); } return(builder.AlphabetById.Count); }
public static Expression <Func <TLetter, LetterId> > CreateExpression(AlphabetBuilder <TLetter> builder, LetterId?defaultLetter = null) { var ranges = builder.AlphabetById.SelectMany(p => p.Value.Select(r => new KeyValuePair <Range <TLetter>, LetterId>(r, p.Key))).Where(p => p.Value != defaultLetter).OrderBy(p => p.Key.From).ToList(); var paramValue = Expression.Parameter(typeof(TLetter), "value"); var defaultExpression = defaultLetter.HasValue ? (Expression)Expression.Constant(defaultLetter.Value.ToInt32()) : Expression.Throw( Expression.New( Reflect.GetConstructor(() => new InvalidOperationException())), typeof(int)); var body = Expression.New(LetterId_Ctor, BinaryCompare(ranges, 0, ranges.Count, paramValue, defaultExpression)); return(Expression.Lambda <Func <TLetter, LetterId> >(body, paramValue)); }