private static void WriteDiagram <TLetter>(ITestOutputHelper output, Dfa <TLetter> dfa)
     where TLetter : struct, IComparable <TLetter>, IEquatable <TLetter>
 {
     output.WriteLine("digraph G {");
     output.WriteLine("graph[rankdir=\"LR\",dpi=65,size=100,forcelabels=true];");
     output.WriteLine("\"{0}\" [peripheries=2,label=\"Accept\"];", Dfa <TLetter> .Accept);
     foreach (var symbolState in dfa.SymbolStates)
     {
         output.WriteLine("\"{0}\" [xlabel=\"{1}\"];", symbolState.Key, symbolState.Value);
     }
     //			output.WriteLine("\"{0}\" [peripheries=2,label=\"Reject\"];", Dfa<TLetter>.Reject);
     //			foreach (var state in dfa.States) {
     //				output.WriteLine("\"{0}\" -> \"{1}\" [style=\"dashed\"];", state.Id, Dfa<TLetter>.Reject);
     //			}
     foreach (var pair in dfa.States.SelectMany(s => s.Transitions.Select(t => new KeyValuePair <DfaState <TLetter>, KeyValuePair <Range <TLetter>, Id <DfaState <TLetter> > > >(s, t))))
     {
         output.WriteLine("\"{0}\" -> \"{1}\" [label=\"{2}\"];", pair.Key.Id, pair.Value.Value, pair.Value.Key);
     }
     output.WriteLine("}");
 }
        private static Expression CreateLetterStateMachine(Dfa <LetterId> dfa, ParameterExpression paramState, Expression exprInput)
        {
            var ctor_IdDfaStateLetter = Reflect.GetConstructor(() => new Id <DfaState <LetterId> >(default(int)));
            var meth_LetterId_ToInt32 = Reflect <LetterId> .GetMethod(i => i.ToInt32());

            var varInput  = Expression.Variable(typeof(int), "input");
            var varResult = Expression.Variable(typeof(SymbolId?), "result");

            return(Expression.Block(
                       typeof(SymbolId?),
                       new[] { varInput, varResult },
                       Expression.Assign(varInput, exprInput is NewExpression exprInputNew && (exprInputNew.Constructor == ctor_LetterId)
                                                        ? exprInputNew.Arguments.Single()
                                                        : Expression.Call(exprInput, meth_LetterId_ToInt32)),
                       Expression.Assign(
                           paramState,
                           Expression.New(ctor_IdDfaStateLetter,
                                          Expression.Switch(
                                              Expression.Call(paramState, Reflect <Id <DfaState <LetterId> > > .GetMethod(i => i.ToInt32())),
                                              Expression.Throw(new_InvalidOperationException, typeof(int)),
                                              dfa.States.OrderBy(s => s.Id).Select(state => Expression.SwitchCase(
                                                                                       Expression.Switch(
                                                                                           varInput,
                                                                                           Expression.Constant(Dfa <LetterId> .Reject.ToInt32()),
                                                                                           state
                                                                                           .Transitions
                                                                                           .GroupBy(p => p.Value.ToInt32(), p => p.Key)
                                                                                           .Select(g => Expression.SwitchCase(dfa.SymbolStates.TryGetValue(new Id <DfaState <LetterId> >(g.Key), out var symbolId)
                                                                                                                                                        ? Expression.Block(
                                                                                                                                  Expression.Assign(varResult, Expression.New(ctor_NullableSymbolId, Expression.New(ctor_SymbolId, Expression.Constant((int)symbolId)))),
                                                                                                                                  Expression.Constant(g.Key))
                                                                                                                                                        : (Expression)Expression.Constant(g.Key),
                                                                                                                              g.SelectMany(r => r.Expand()).Select(i => Expression.Constant(i.ToInt32()))))
                                                                                           .ToArray()),
                                                                                       Expression.Constant(state.Id.ToInt32())
                                                                                       )).ToArray()))),
                       varResult));
        }
        public static Expression <DfaStateMachine <LetterId, TLetter> > CreateExpression <TLetter>(Dfa <LetterId> dfa, Expression <Func <TLetter, LetterId> > inputToLetter)
            where TLetter : struct, IComparable <TLetter>, IEquatable <TLetter>
        {
            var paramState = Expression.Parameter(typeof(Id <DfaState <LetterId> >).MakeByRefType(), "state");
            var paramInput = inputToLetter.Parameters.Single();

            return(Expression.Lambda <DfaStateMachine <LetterId, TLetter> >(CreateLetterStateMachine(dfa, paramState, inputToLetter.Body), "DfaAlphabetStateMachine", new[] { paramState, paramInput }));
        }
        public static Expression <DfaStateMachine <LetterId, LetterId> > CreateExpression(Dfa <LetterId> dfa)
        {
            var paramState = Expression.Parameter(typeof(Id <DfaState <LetterId> >).MakeByRefType(), "state");
            var paramInput = Expression.Parameter(typeof(LetterId), "input");

            return(Expression.Lambda <DfaStateMachine <LetterId, LetterId> >(CreateLetterStateMachine(dfa, paramState, paramInput), "DfaLetterStateMachine", new[] { paramState, paramInput }));
        }