Пример #1
0
        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);
        }
Пример #2
0
 /// <summary>Gets the state ID associated with a builder.</summary>
 /// <param name="switchState">Builder to look-up.</param>
 /// <returns>The state ID of the builder.</returns>
 public int GetIdForBuilder(StateSwitchBuilder <TComparand, TInput> switchState)
 {
     if (!this.switchStates.TryGetValue(switchState, out var value))
     {
         value = this.switchStates.Count;
         this.switchStates.Add(switchState, value);
         this.switchStateIds.Add(value, switchState);
     }
     return(value);
 }
Пример #3
0
 /// <summary>Constructor.</summary>
 /// <exception cref="ArgumentNullException">Thrown when one or more required arguments are <c>null</c></exception>
 /// <exception cref="InvalidOperationException">Thrown when the requested operation is invalid.</exception>
 /// <param name="root">The root.</param>
 /// <param name="conditionEmitter">The condition emitter.</param>
 /// <param name="contextType">Type of the context.</param>
 public StateMachineEmitter([NotNull] StateSwitchBuilder <TComparand, TInput> root, [NotNull] IConditionEmitter <TComparand, TInput> conditionEmitter, Type contextType)
 {
     this.Root             = root ?? throw new ArgumentNullException(nameof(root));
     this.ConditionEmitter = conditionEmitter ?? throw new ArgumentNullException(nameof(conditionEmitter));
     this.InputParameter   = Expression.Parameter(typeof(TInput), "input");
     this.StateParameter   = Expression.Parameter(typeof(int).MakeByRefType(), "state");
     this.ContextParameter = Expression.Parameter(contextType ?? typeof(object).MakeByRefType(), "context");
     this.StartLabel       = Expression.Label("start");
     if (this.GetIdForBuilder(this.Root) != 0)
     {
         throw new InvalidOperationException("Internal error: Unexpected root ID");
     }
 }
Пример #4
0
        public void ExpressionReplaceTest()
        {
            var root    = new StateSwitchBuilder <bool, bool, ITestOutputHelper>();
            var emitter = new StateMachineEmitter <bool, bool>(root, EquatableConditionEmitter <bool> .Default);

            root.Default.Do(o => o.WriteLine(((int)root).ToString()));
            var    stateExpr = emitter.Emit();
            var    stateFn   = stateExpr.Compile();
            var    state     = 0;
            object context   = this.output;

            Assert.False(stateFn(true, ref state, ref context));
        }
Пример #5
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());
        }
Пример #6
0
        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);
        }
Пример #7
0
 /// <summary>Constructor.</summary>
 /// <exception cref="ArgumentNullException">Thrown when one or more required arguments are <c>null</c></exception>
 /// <exception cref="InvalidOperationException">Thrown when the requested operation is invalid.</exception>
 /// <param name="root">The root.</param>
 /// <param name="conditionEmitter">The condition emitter.</param>
 public StateMachineEmitter([NotNull] StateSwitchBuilder <TComparand, TInput> root, [NotNull] IConditionEmitter <TComparand, TInput> conditionEmitter) : this(root, conditionEmitter, null)
 {
 }
Пример #8
0
 public PerformStatic(StateSwitchBuilder <TComparand, TInput, TContext> target, bool yield)
 {
     this.Yield  = yield;
     this.Target = target;
 }
 /// <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="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 <RangeSet <TInput>, TInput, TContext> OnSequence <TInput, TContext>(this StateSwitchBuilder <RangeSet <TInput>, TInput, TContext> that, IEnumerable <TInput> inputs)
     where TInput : IComparable <TInput>
 {
     return(OnSequence(that, inputs.Select(i => new RangeSet <TInput>(i))));
 }
 /// <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);
     }
 }
 /// <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());
 }