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<TInput,TData></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<TInput,TData></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()); }