public void TestCounter(int expectedCount, string input)
        {
            // Define the state machine
            var root = new StateSwitchBuilder <char, char, int>();

            root.On('\n', i => false);
            root.On((i, ctx) => false);
            root.On('\n').Do(i => i + 1).Yield(root);
            root.Default.Yield(root);
            // Compile the state machine
            var emitter = new StateMachineEmitter <char, char>(root, EquatableConditionEmitter <char> .Default);

            emitter.OnEnter <object>((i, d) => this.output.WriteLine("+"));
            emitter.OnLeave <object>((i, d) => this.output.WriteLine("-"));
            var stateExpr = emitter.Emit();

            this.output.WriteLine(stateExpr.ToReadableString());
            var stateFn = stateExpr.Compile();
            // Run the state machine for some input
            var    state   = 0;
            object context = 0;

            foreach (var ch in input)
            {
                stateFn(ch, ref state, ref context);
            }
            // The context is now an integer with the number of newlines
            this.output.WriteLine(context.ToString());
            Assert.Equal(expectedCount, (int)context);
            Assert.True(state >= 0);
        }
        public void TestMergeOptimization()
        {
            // Define the state machine
            var root = new StateSwitchBuilder <char, char, int>();

            root.On('x', i => false).Yield(root);
            root.On('a').Yield(root);
            root.On('x').Yield(root);
            root.On('b').Yield(root);
            // Compile the state machine
            var emitter   = new StateMachineEmitter <char, char>(root, EquatableConditionEmitter <char> .Default);
            var stateExpr = emitter.Emit();

            this.output.WriteLine(stateExpr.ToReadableString());
        }
 /// <summary>When a given input sequence is matched, consume the input except for the last one.</summary>
 /// <exception cref="InvalidOperationException">Thrown when the requested operation is invalid.</exception>
 /// <typeparam name="TComparand">Type of the comparand.</typeparam>
 /// <typeparam name="TInput">Type of the input.</typeparam>
 /// <typeparam name="TContext">Type of the context.</typeparam>
 /// <param name="that">The builder to act on.</param>
 /// <param name="inputs">The inputs.</param>
 /// <returns>A StatePerformBuilder&lt;TInput,TData&gt;</returns>
 public static StatePerformBuilder <TComparand, TInput, TContext> OnSequence <TComparand, TInput, TContext>(this StateSwitchBuilder <TComparand, TInput, TContext> that, IEnumerable <TComparand> inputs)
     where TComparand : IEquatable <TComparand>
 {
     using (var enumerator = inputs.GetEnumerator()) {
         if (!enumerator.MoveNext())
         {
             throw new InvalidOperationException("Empty input not allowed");
         }
         var result = that.On(enumerator.Current);
         while (enumerator.MoveNext())
         {
             result = result.Yield().On(enumerator.Current);
         }
         return(result);
     }
 }
        public void TestRangeSet(bool accept, string input)
        {
            var root    = new StateSwitchBuilder <RangeSet <char>, char, ITestOutputHelper>();
            var emitter = new StateMachineEmitter <RangeSet <char>, char>(root, RangesConditionEmitter <RangeSet <char>, char> .Default);

            root.OnSequence("test").Do(o => o.WriteLine("Done")).Yield(-2);
            root.On(new RangeSet <char>(" \t\r\n")).Yield(o => (int)root);
            var    stateExpr = emitter.Emit();
            var    stateFn   = stateExpr.Compile();
            var    state     = 0;
            object context   = this.output;

            foreach (var ch in input)
            {
                this.output.WriteLine(stateFn(ch, ref state, ref context).ToString());
            }
            Assert.Equal(accept, state == -2);
        }
 /// <summary>When a given input is matched, consume it and proceed.</summary>
 /// <typeparam name="TComparand">Type of the comparand.</typeparam>
 /// <typeparam name="TInput">Type of the input.</typeparam>
 /// <typeparam name="TContext">Type of the context.</typeparam>
 /// <param name="that">The builder to act on.</param>
 /// <param name="input">The input.</param>
 /// <returns>A StateSwitchBuilder&lt;TInput,TData&gt;</returns>
 public static StateSwitchBuilder <TComparand, TInput, TContext> Take <TComparand, TInput, TContext>(this StateSwitchBuilder <TComparand, TInput, TContext> that, TComparand input)
     where TComparand : IEquatable <TComparand>
 {
     return(that.On(input).Yield());
 }