Exemplo n.º 1
0
        /// <summary>
        /// Compiles a rule context transformation.
        /// </summary>
        /// <param name="transformation">The transformation.</param>
        /// <param name="builder">The builder.</param>
        /// <param name="glyphIdToRuleIndexCallback">The callback used to resolve rule index from glyph IDs.</param>
        /// <param name="createTransitionCallback">The callback used to create transitions.</param>
        /// <exception cref="System.InvalidOperationException">Transformations in transformation set don't share LookupFlags.</exception>
        private void CompileChainingRuleContextTransformation(
            IGlyphTransformationTable transformation,
            IStateMachineBuilder builder, Func <ushort, ushort> glyphIdToRuleIndexCallback,
            CreateContextTransformationTransitionDelegate <ushort> createTransitionCallback)
        {
            var table = (ChainingRuleContextTransformationTableBase)transformation;

            // Flatten the collection of rules and associate each rule with glyph received from the coverage table
            var rulesWithFirstGlyph = table
                                      .TransformationRules
                                      .Zip(table.Coverage.CoveredGlyphIds.Values)
                                      .SelectMany(ruleSetWithFirstGlyph => ruleSetWithFirstGlyph.Item1.Select(rule => Tuple.Create(rule, glyphIdToRuleIndexCallback(ruleSetWithFirstGlyph.Item2))));

            foreach (var ruleTuple in rulesWithFirstGlyph)
            {
                foreach (var transformationSet in ruleTuple.Item1.TransformationSets)
                {
                    var completeInputContext =
                        ruleTuple.Item1.Context
                        .Prepend(ruleTuple.Item2)
                        .ToList();

                    this.CompileSingleContextTransformation(
                        table,
                        builder,
                        transformationSet,
                        createTransitionCallback,
                        completeInputContext,
                        ruleTuple.Item1.Lookback,
                        ruleTuple.Item1.Lookahead);
                }
            }
        }
        /// <summary>
        /// Compacts transitions by eliminating trailing null tansitions.
        /// I.e if the last couple characters in the alphabet, for one state don't lead to another state, these cells can be
        /// eliminated from the table.
        /// Transitions that point to a later state are adjusted by the amount of eliminated cells.
        /// </summary>
        public TransitionCompacter(IStateMachineBuilder builder)
        {
            // Build a set of indices that can be skipped and a table of offsets for adjusting the remaining transitions.
            var skippedIndices = new HashSet <int>();
            var offsetMap      = new int[builder.Transitions.Count];
            var skipTotal      = 0;

            for (var i = 0; i < builder.Transitions.Count; i += builder.AlphabetSize)
            {
                // Count the trailing nulls.
                var transitionsToKeep = builder.AlphabetSize;
                for (; transitionsToKeep > 0; transitionsToKeep--)
                {
                    var transition = i + transitionsToKeep - 1;
                    if (!builder.IsNull(transition) || builder.IsResult(transition))
                    // Results and normal transitions can't be skipped.
                    {
                        break;
                    }
                    skippedIndices.Add(transition);
                }
                // Build the set and table.
                var toSkip = builder.AlphabetSize - transitionsToKeep;
                skipTotal += toSkip;
                for (var j = 0; j < builder.AlphabetSize; ++j)
                {
                    var index = i + builder.AlphabetSize + j;
                    if (index >= offsetMap.Length)
                    {
                        break;
                    }
                    offsetMap[index] = skipTotal;
                }
            }

            // Adjust the remaining transitions.
            var clone = builder.Transitions.ToList();

            for (var i = 0; i < clone.Count; ++i)
            {
                if (builder.IsNull(i) || builder.IsResult(i)) // nulls and results are not adjusted.
                {
                    continue;
                }

                clone[i] -= offsetMap[clone[i]];
            }

            // Copy into a new list while skipping eliminated cells.
            Transitions = clone.Where((t, i) => !skippedIndices.Contains(i)).ToList();

            // Create offsets.
            var offsets = new List <int>();

            for (var i = 0; i < builder.Transitions.Count; i += builder.AlphabetSize)
            {
                offsets.Add(offsetMap[i]);
            }
            Offsets = offsets;
        }
        static DocStateMachineBuilder()
        {
            var dll = typeof(DocStateMachineBuilder).Assembly;

            using (var stream = dll.GetManifestResourceStream("DocManager.Resources.Doc.csv"))
            {
                realBuilder = CsvStateMachineBuilder <DocStates, DocActions> .FromStream(stream);
            }
        }
        private static IReadOnlyList <int> GetMinOffsets(IStateMachineBuilder builder, TransitionCompacter compacter,
                                                         int wordLength)
        {
            var alphabet   = Enumerable.Range(0, builder.AlphabetSize).ToList();
            var minOffsets = new int[wordLength];
            var maxOffsets = new int[wordLength];
            var transitionsInCurrentLevel        = new HashSet <int>(builder.EntryStates.Select(e => e * builder.AlphabetSize));
            var compactTransitionsInCurrentLevel =
                new HashSet <int>(builder.EntryStates.Select(e => e * builder.AlphabetSize - compacter.Offsets[e]));

            for (var i = 0; i < wordLength; ++i)
            {
                var transitionsInPreviousLevel        = transitionsInCurrentLevel;
                var compactTransitionsInPreviousLevel = compactTransitionsInCurrentLevel;
                transitionsInCurrentLevel        = new HashSet <int>();
                compactTransitionsInCurrentLevel = new HashSet <int>();
                var orderedPrevious        = transitionsInPreviousLevel.OrderBy(x => x).ToList();
                var orderedCompactPrevious = compactTransitionsInPreviousLevel.OrderBy(x => x).ToList();
                for (var j = 0; j < orderedPrevious.Count; ++j)
                {
                    var previous        = orderedPrevious[j];
                    var compactPrevious = orderedCompactPrevious[j];
                    foreach (var c in alphabet)
                    {
                        if (builder.IsNull(previous + c))
                        {
                            continue;
                        }
                        var n = builder.Transitions[previous + c];
                        var m = compacter.Transitions[compactPrevious + c];
                        transitionsInCurrentLevel.Add(n);
                        compactTransitionsInCurrentLevel.Add(m);
                    }
                }
                minOffsets[i] = compactTransitionsInCurrentLevel.Min();
                maxOffsets[i] = compactTransitionsInCurrentLevel.Max();
            }
            if (maxOffsets.Max() < ushort.MaxValue)
            {
                return(Enumerable.Repeat(0, wordLength).ToList());
            }
            var largestDistance = Enumerable.Range(0, wordLength).Max(i => maxOffsets[i] - minOffsets[i]);

            for (var i = 0; i < wordLength; ++i)
            {
                if (maxOffsets[i] < largestDistance)
                {
                    minOffsets[i] = 0;
                }
            }
            return(minOffsets);
        }
            public void BuildStateMachine(IStateMachineBuilder <PhilisopherState, PhilisopherTrigger> machine)
            {
                machine.State(PhilisopherState.Thinking)
                .SetAsInitial()
                .OnTrigger(PhilisopherTrigger.Hungry).TransitionTo(PhilisopherState.AcquiringForks);

                machine.State(PhilisopherState.AcquiringForks)
                .OnTrigger(PhilisopherTrigger.GotForks).TransitionTo(PhilisopherState.Eating)
                .OnTrigger(PhilisopherTrigger.Deadlocked).TransitionTo(PhilisopherState.Thinking);

                machine.State(PhilisopherState.Eating)
                .OnTrigger(PhilisopherTrigger.Full).TransitionTo(PhilisopherState.Thinking);
            }
Exemplo n.º 6
0
        /// <summary>
        /// Counts the number of null transitions per character in the alphabet.
        /// </summary>
        private static IEnumerable <int> CountNullTransitions(IStateMachineBuilder builder)
        {
            var nullTransitions = new int[builder.AlphabetSize];

            for (var i = 0; i < builder.Transitions.Count; i++)
            {
                if (builder.IsResult(i))
                {
                    continue;
                }
                if (builder.IsNull(i))
                {
                    nullTransitions[i % builder.AlphabetSize] += 1;
                }
            }
            return(nullTransitions);
        }
        public void BuildStateMachine(IStateMachineBuilder builder)
        {
            if (builder == null)
            {
                throw new ArgumentNullException("builder");
            }

            StateMachine       = builder;
            PendingTransitions = new List <TransitionDef>();

            Prepare();

            //We have to add transitions to a temporary cache and apply them last
            //because in the definition of the state machine states may specify
            //transitions to states not specified yet in the file, and circular references
            //are allowed, so we need to collect all states and then configure transitions
            //between them.
            CommitPendingTransitions();
        }
            //-------------------------------------------------------------------------------------------------------------------------------------------------

            public void BuildStateMachine(IStateMachineBuilder <PhilisopherState, PhilisopherTrigger> machine)
            {
                machine.State(PhilisopherState.Thinking)
                .SetAsInitial()
                .OnEntered(ThinkingEntered)
                .OnLeaving(ThinkingLeaving)
                .OnTrigger(PhilisopherTrigger.Hungry).TransitionTo(PhilisopherState.AcquiringForks, TransitioningFromThinkingToAcquiringForks);

                machine.State(PhilisopherState.AcquiringForks)
                .OnEntered(AcquiringForksEntered)
                .OnLeaving(AcquiringForksLeaving)
                .OnTrigger(PhilisopherTrigger.GotForks).TransitionTo(PhilisopherState.Eating, TransitioningFromAcquiringForksToEating)
                .OnTrigger(PhilisopherTrigger.Deadlocked).TransitionTo(PhilisopherState.Thinking, TransitioningFromAcquiringForksToThinking);

                machine.State(PhilisopherState.Eating)
                .OnEntered(EatingEntered)
                .OnLeaving(EatingLeaving)
                .OnTrigger(PhilisopherTrigger.Full).TransitionTo(PhilisopherState.Thinking, TransitioningFromEatingToThinking);
            }
Exemplo n.º 9
0
            //-------------------------------------------------------------------------------------------------------------------------------------------------

            public void BuildStateMachine(IStateMachineBuilder <MicroserviceState, MicroserviceTrigger> machine)
            {
                machine.State(MicroserviceState.Down)
                .SetAsInitial()
                .OnTrigger(MicroserviceTrigger.Configure).TransitionTo(MicroserviceState.Configuring);

                machine.State(MicroserviceState.Configuring)
                .OnTrigger(MicroserviceTrigger.Failed).TransitionTo(MicroserviceState.Down)
                .OnTrigger(MicroserviceTrigger.OK).TransitionTo(MicroserviceState.Configured)
                .OnEntered(ConfiguringEntered);

                machine.State(MicroserviceState.Configured)
                .OnTrigger(MicroserviceTrigger.Unload).TransitionTo(MicroserviceState.Down)
                .OnTrigger(MicroserviceTrigger.Load).TransitionTo(MicroserviceState.Loading);

                machine.State(MicroserviceState.Loading)
                .OnTrigger(MicroserviceTrigger.Failed).TransitionTo(MicroserviceState.Down)
                .OnTrigger(MicroserviceTrigger.OK).TransitionTo(MicroserviceState.Standby)
                .OnEntered(LoadingEntered);

                machine.State(MicroserviceState.Standby)
                .OnTrigger(MicroserviceTrigger.Unload).TransitionTo(MicroserviceState.Unloading)
                .OnTrigger(MicroserviceTrigger.Activate).TransitionTo(MicroserviceState.Activating);

                machine.State(MicroserviceState.Activating)
                .OnTrigger(MicroserviceTrigger.Failed).TransitionTo(MicroserviceState.Unloading)
                .OnTrigger(MicroserviceTrigger.OK).TransitionTo(MicroserviceState.Active)
                .OnEntered(ActivatingEntered);

                machine.State(MicroserviceState.Active)
                .OnTrigger(MicroserviceTrigger.Deactivate).TransitionTo(MicroserviceState.Deactivating);

                machine.State(MicroserviceState.Deactivating)
                .OnTrigger(MicroserviceTrigger.Failed).TransitionTo(MicroserviceState.Unloading)
                .OnTrigger(MicroserviceTrigger.OK).TransitionTo(MicroserviceState.Standby)
                .OnEntered(DeactivatingEntered);

                machine.State(MicroserviceState.Unloading)
                .OnTrigger(MicroserviceTrigger.Done).TransitionTo(MicroserviceState.Down)
                .OnEntered(UnloadingEntered);
            }
        private static IEnumerable <int> SubtractOffsets(IStateMachineBuilder builder, TransitionCompacter compacter,
                                                         IReadOnlyList <int> minOffsets, int wordLength)
        {
            var alphabet = Enumerable.Range(0, builder.AlphabetSize).ToList();
            var transitionsInCurrentLevel        = new HashSet <int>(builder.EntryStates.Select(e => e * builder.AlphabetSize));
            var compactTransitionsInCurrentLevel =
                new HashSet <int>(builder.EntryStates.Select(e => e * builder.AlphabetSize - compacter.Offsets[e]));
            var transitionsWithMinOffsets = new int[compacter.Transitions.Count];

            Array.Fill(transitionsWithMinOffsets, -1);
            for (var i = 0; i < wordLength; ++i)
            {
                var statesInPreviousLevel        = transitionsInCurrentLevel;
                var compactStatesInPreviousLevel = compactTransitionsInCurrentLevel;
                transitionsInCurrentLevel        = new HashSet <int>();
                compactTransitionsInCurrentLevel = new HashSet <int>();
                var orderedPrevious        = statesInPreviousLevel.OrderBy(x => x).ToList();
                var orderedCompactPrevious = compactStatesInPreviousLevel.OrderBy(x => x).ToList();
                for (var j = 0; j < orderedPrevious.Count; ++j)
                {
                    var previous        = orderedPrevious[j];
                    var compactPrevious = orderedCompactPrevious[j];
                    foreach (var c in alphabet)
                    {
                        if (builder.IsNull(previous + c))
                        {
                            continue;
                        }
                        var n = builder.Transitions[previous + c];
                        var m = compacter.Transitions[compactPrevious + c];
                        transitionsInCurrentLevel.Add(n);
                        compactTransitionsInCurrentLevel.Add(m);

                        transitionsWithMinOffsets[compactPrevious + c] = m - minOffsets[i];
                    }
                }
            }
            return(transitionsWithMinOffsets);
        }
Exemplo n.º 11
0
        /// <inheritdoc />
        public override void CompileTransformation(IGlyphTransformationTable transformation, IStateMachineBuilder builder)
        {
            if (transformation is ConstantPositioningTable)
            {
                var table = transformation as ConstantPositioningTable;

                var paths = table.Coverage.CoveredGlyphIds.Values.Select(glyphId => new[]
                {
                    new SimpleTransition {
                        GlyphId     = glyphId,
                        HeadShift   = 1,
                        LookupFlags = table.LookupFlags,
                        Action      = new PositioningAdjustmentAction
                        {
                            PositionChanges = new[] { table.PositionChange }
                        }
                    }
                });

                foreach (var path in paths)
                {
                    builder.AddPath(path);
                }
            }
            else if (transformation is IndividualChangePositioningTable)
            {
                var table = transformation as IndividualChangePositioningTable;

                var paths = table.Coverage.CoveredGlyphIds.Zip(
                    table.PositionChanges,
                    (coveragePair, positioningChange) => new[]
                {
                    new SimpleTransition {
                        GlyphId     = coveragePair.Value,
                        HeadShift   = 1,
                        LookupFlags = table.LookupFlags,
                        Action      = new PositioningAdjustmentAction
                        {
                            PositionChanges = new[] { positioningChange },
                        }
                    }
                });

                foreach (var path in paths)
                {
                    builder.AddPath(path);
                }
            }
            else if (transformation is GlyphPairPositioningTable)
            {
                var table = transformation as GlyphPairPositioningTable;

                var coverageDictionary = table.Coverage.CoveredGlyphIds;

                var paths =
                    table.PairSets.SelectMany(
                        (pairSet, coverageIndex) => pairSet.Select(
                            pair => new[]
                {
                    // First state just checks first glyph of the pair.
                    new SimpleTransition {
                        GlyphId     = coverageDictionary[(ushort)coverageIndex],
                        HeadShift   = 1,
                        LookupFlags = table.LookupFlags
                    },

                    // Seconds state checks the second glyph and does the positioning.
                    new SimpleTransition {
                        GlyphId     = pair.SecondGlyphID,
                        LookupFlags = table.LookupFlags,
                        HeadShift   = 0,           // TODO: 0?
                        Action      = new PositioningAdjustmentAction
                        {
                            PositionChanges = new[] { pair.FirstGlyphPositionChange, pair.SecondGlyphPositionChange },
                        }
                    }
                }));

                foreach (var path in paths)
                {
                    builder.AddPath(path);
                }
            }
            else if (transformation is ClassPairPositioningTable)
            {
                var table = transformation as ClassPairPositioningTable;

                var paths =
                    table
                    .PairSets
                    .Zip(table.FirstClassDef.ClassAssignments)
                    .SelectMany(
                        pairSetTuple => pairSetTuple
                        .Item1
                        .Zip(table.SecondClassDef.ClassAssignments)
                        .Select(pairTuple => new[]
                {
                    new SetTransition {
                        GlyphIdSet  = new HashSet <ushort>(pairSetTuple.Item2),
                        HeadShift   = 1,
                        LookupFlags = table.LookupFlags
                    },
                    new SetTransition
                    {
                        GlyphIdSet  = new HashSet <ushort>(pairTuple.Item2),
                        HeadShift   = 0,
                        LookupFlags = table.LookupFlags,
                        Action      = new PositioningAdjustmentAction
                        {
                            PositionChanges = new[] { pairTuple.Item1.Item1, pairTuple.Item1.Item2 }
                        }
                    }
                }));

                foreach (var path in paths)
                {
                    builder.AddPath(path);
                }
            }
            else if (transformation is CursivePositioningTable)
            {
                var table = transformation as CursivePositioningTable;

                var glyphsWithEntryExits = table.Coverage.CoveredGlyphIds.Zip(table.EntryExitRecords, (coveragePair, entryExit) => new
                {
                    GlyphId          = coveragePair.Value,
                    EntryAnchorPoint = entryExit.Item1,
                    ExitAnchorPoint  = entryExit.Item2
                }).ToList();

                // Only pairs where the first glyph has exit anchor and the second glyph has entry anchor are valid
                var paths =
                    from firstGlyph in glyphsWithEntryExits
                    where firstGlyph.ExitAnchorPoint != null
                    from secondGlyph in glyphsWithEntryExits
                    where secondGlyph.EntryAnchorPoint != null
                    select new []
                {
                    // First state just checks first glyph of the pair.
                    new SimpleTransition {
                        GlyphId     = firstGlyph.GlyphId,
                        HeadShift   = 1,
                        LookupFlags = table.LookupFlags
                    },

                    // Seconds state checks the second glyph and does the positioning.
                    new SimpleTransition {
                        GlyphId     = secondGlyph.GlyphId,
                        LookupFlags = table.LookupFlags,
                        HeadShift   = 0,
                        Action      = new AnchorPointToAnchorPointAction
                        {
                            PreviousGlyphAnchorPoint = firstGlyph.ExitAnchorPoint,
                            CurrentGlyphAnchorPoint  = secondGlyph.EntryAnchorPoint
                        }
                    }
                };

                foreach (var path in paths)
                {
                    builder.AddPath(path);
                }
            }
            else if (transformation is MarkToBasePositioningTable)
            {
                var table = transformation as MarkToBasePositioningTable;

                /*var glyphIdWithMarkEntry = table.MarkCoverage.CoveredGlyphIds.Zip(
                 *  table.MarkAnchorPoints,
                 *  (coveragePair, markArrayEntry) => new KeyValuePair<ushort, Tuple<uushort, AnchorPoint>>(coveragePair.Value, markArrayEntry)).ToDictionary();
                 *
                 * var glyphIdWithBaseEntry = table.MarkCoverage.CoveredGlyphIds.Zip(
                 *  table.BaseAnchorPoints,
                 *  (coveragePair, baseArrayEntry) => new KeyValuePair<ushort, IEnumerable<AnchorPoint>>(coveragePair.Value, baseArrayEntry)).ToDictionary();
                 */

                var glyphIdWithMarkEntry = table.MarkCoverage.CoveredGlyphIds.Zip(
                    table.MarkAnchorPoints,
                    (coveragePair, markArrayEntry) => new {
                    GlyphId     = coveragePair.Value,
                    ClassId     = markArrayEntry.Item1,
                    AnchorPoint = markArrayEntry.Item2
                });

                var glyphIdWithBaseEntry = table.BaseCoverage.CoveredGlyphIds.Zip(
                    table.BaseAnchorPoints,
                    (coveragePair, baseArrayEntry) => new
                {
                    GlyphId = coveragePair.Value,
                    AnchorPointByClassId = baseArrayEntry.ToList()
                });

                var paths =
                    from baseGlyph in glyphIdWithBaseEntry
                    from markGlyph in glyphIdWithMarkEntry
                    select new []
                {
                    new SimpleTransition
                    {
                        GlyphId     = baseGlyph.GlyphId,
                        HeadShift   = 1,
                        LookupFlags = table.LookupFlags
                    },
                    new SimpleTransition
                    {
                        GlyphId     = markGlyph.GlyphId,
                        HeadShift   = 1,
                        LookupFlags = table.LookupFlags,
                        Action      = new AnchorPointToAnchorPointAction
                        {
                            PreviousGlyphAnchorPoint = baseGlyph.AnchorPointByClassId[markGlyph.ClassId],
                            CurrentGlyphAnchorPoint  = markGlyph.AnchorPoint
                        }
                    }
                };

                foreach (var path in paths)
                {
                    builder.AddPath(path);
                }
            }
        }
 public static IStateMachineEvent AddNewEvent(this IStateMachineBuilder stateMachine, string eventName)
 {
     return(stateMachine.AddNewEvent(eventName, eventName));
 }
Exemplo n.º 13
0
 public static IStateMachine <int, TData> Build <TData>(this IStateMachineBuilder <int, TData> builder, TData data)
 {
     return(builder.Build(0, data));
 }
Exemplo n.º 14
0
        /// <inheritdoc />
        public override void CompileTransformation(IGlyphTransformationTable transformation, IStateMachineBuilder builder)
        {
            if (transformation is SimpleReplacementSubstitutionTable)
            {
                var table = transformation as SimpleReplacementSubstitutionTable;

                var paths = table.Coverage.CoveredGlyphIds.Zip(
                    table.ReplacementGlyphIds,
                    (coveragePair, replacementGlyphId) => new[]
                {
                    new SimpleTransition {
                        GlyphId     = coveragePair.Value,
                        HeadShift   = 1,
                        LookupFlags = table.LookupFlags,
                        Action      = new SubstitutionAction
                        {
                            ReplacementGlyphIds = new[] { replacementGlyphId },
                            ReplacedGlyphCount  = 1
                        }
                    }
                });

                foreach (var path in paths)
                {
                    builder.AddPath(path);
                }
            }
            else if (transformation is DeltaSubstitutionTable)
            {
                var table = transformation as DeltaSubstitutionTable;

                var paths =
                    from coveragePair in table.Coverage.CoveredGlyphIds
                    select
                    new[]
                {
                    new SimpleTransition
                    {
                        GlyphId     = coveragePair.Value,
                        HeadShift   = 1,
                        LookupFlags = table.LookupFlags,
                        Action      = new SubstitutionAction
                        {
                            ReplacementGlyphIds = new[] { (ushort)(coveragePair.Value + table.GlyphIdDelta) },
                            ReplacedGlyphCount  = 1
                        }
                    }
                };

                foreach (var path in paths)
                {
                    builder.AddPath(path);
                }
            }
            else if (transformation is LigatureSubstitutionTable)
            {
                var table = transformation as LigatureSubstitutionTable;

                var ligatureSetInfos = table.Coverage.CoveredGlyphIds.Zip(
                    table.LigatureSets,
                    (coveragePair, ligatureSet) => new { CoveredGlyphId = coveragePair.Value, LigatureSet = ligatureSet });

                var paths =
                    from ligatureSetInfo in ligatureSetInfos
                    from ligature in ligatureSetInfo.LigatureSet
                    select this.ConvertLigatureToPath(ligatureSetInfo.CoveredGlyphId, ligature, table.LookupFlags).ToList();

                foreach (var path in paths)
                {
                    builder.AddPath(path);
                }
            }
            else if (transformation is MultipleSubstitutionTable)
            {
                var table = transformation as MultipleSubstitutionTable;

                var paths = table.Coverage.CoveredGlyphIds.Zip(
                    table.ReplacementSequences,
                    (coveragePair, replacementSequence) =>
                {
                    var list = replacementSequence.ToList();
                    return(new[]
                    {
                        new SimpleTransition
                        {
                            GlyphId = coveragePair.Value,
                            HeadShift = 1,
                            LookupFlags = table.LookupFlags,
                            Action = new SubstitutionAction
                            {
                                ReplacementGlyphIds = list,
                                ReplacedGlyphCount = 1
                            }
                        }
                    });
                });

                foreach (var path in paths)
                {
                    builder.AddPath(path);
                }
            }
            else if (transformation is ReverseChainingContextSubstitutionTable)
            {
                var table = transformation as ReverseChainingContextSubstitutionTable;

                builder.SetProcessingDirection(ProcessingDirection.EndToStart);

                // The entire machine is executed from the end of the string towards its start
                var lookbackCoveragesList = table.LookbackCoverages.ToList();
                var completeContext       = (((IEnumerable <ICoverageTable>)lookbackCoveragesList)
                                             .Reverse()
                                             .Append(table.Coverage)
                                             .Append(table.LookaheadCoverages)
                                             ).Reverse().ToList();

                var contextCheckPathSeqment = completeContext
                                              .Take(completeContext.Count - 1)
                                              .Select(coverage => (ITransition) new SetTransition
                {
                    GlyphIdSet  = new HashSet <ushort>(coverage.CoveredGlyphIds.Select(p => p.Value)),
                    HeadShift   = -1,
                    LookupFlags = table.LookupFlags
                })
                                              .Append(new SetTransition
                {
                    GlyphIdSet  = new HashSet <ushort>(completeContext.Last().CoveredGlyphIds.Select(p => p.Value)),
                    HeadShift   = lookbackCoveragesList.Count,
                    LookupFlags = table.LookupFlags
                }).ToList();

                int i = 0;
                var replacementGlyphIds = table.SubstituteGlyphIds.ToList();
                foreach (var coveredGlyphId in table.Coverage.CoveredGlyphIds.Values)
                {
                    var transition = new SimpleTransition
                    {
                        GlyphId     = coveredGlyphId,
                        HeadShift   = lookbackCoveragesList.Count,
                        LookupFlags = table.LookupFlags,
                        Action      = new SubstitutionAction
                        {
                            ReplacedGlyphCount  = 1,
                            ReplacementGlyphIds = new [] { replacementGlyphIds[i] }
                        }
                    };

                    builder.AddPath(contextCheckPathSeqment.Append(transition));

                    i++;
                }

                builder.AddPath(contextCheckPathSeqment.Append(new AlwaysTransition
                {
                    HeadShift   = lookbackCoveragesList.Count,
                    LookupFlags = table.LookupFlags
                }));
            }
            else
            {
                base.CompileTransformation(transformation, builder);
            }
        }
Exemplo n.º 15
0
 public StateMachineBuilder()
 {
     _builder = Machine <TState, TImpl, TInput> .GetBuilder();
 }
Exemplo n.º 16
0
        /// <summary>
        /// Compiles a single transformation.
        /// </summary>
        /// <param name="transformation">The transformation.</param>
        /// <param name="builder">The builder.</param>
        public virtual void CompileTransformation(IGlyphTransformationTable transformation, IStateMachineBuilder builder)
        {
            if (transformation is GlyphContextTransformationTable)
            {
                this.CompileRuleContextTransformation(
                    transformation,
                    builder,
                    glyphId => glyphId,
                    (glyphId, headShift, lookupFlags, action, zone) => new SimpleTransition {
                    GlyphId     = glyphId,
                    HeadShift   = headShift,
                    LookupFlags = lookupFlags,
                    Action      = action
                });
            }
            else if (transformation is ClassContextTransformationTable)
            {
                var table            = transformation as ClassContextTransformationTable;
                var classAssignments = table.ClassDefinitions.ClassAssignments;

                /* Here is slight difference from spec - first transition of each "rule" state chain used to recognize the context
                 * will alway be a set transition where glyph set will be defined by appropriate class definition. Instead, only glyps
                 * which are mentioned in the coverage table should be recognized by the first transition. */
                this.CompileRuleContextTransformation(
                    transformation,
                    builder,
                    glyphId => table.ClassDefinitions.ClassAssignments.Single(classAssignment => classAssignment.Contains(glyphId)).Key,
                    (classId, headShift, lookupFlags, action, zone) => new SetTransition {
                    GlyphIdSet  = new HashSet <ushort>(classAssignments[classId]),
                    HeadShift   = headShift,
                    LookupFlags = lookupFlags,
                    Action      = action
                });
            }
            else if (transformation is CoverageContextTransformationTable)
            {
                var table = transformation as CoverageContextTransformationTable;

                foreach (var transformationSet in table.TransformationSets)
                {
                    this.CompileSingleContextTransformation(
                        table,
                        builder,
                        transformationSet,
                        (coverageTable, headShift, lookupFlags, action, zone) => new SetTransition {
                        GlyphIdSet  = new HashSet <ushort>(coverageTable.CoveredGlyphIds.Values),
                        HeadShift   = headShift,
                        LookupFlags = lookupFlags,
                        Action      = action
                    },
                        table.Coverages);
                }
            }
            else if (transformation is ChainingGlyphContextTransformationTable)
            {
                this.CompileChainingRuleContextTransformation(
                    transformation,
                    builder,
                    glyphId => glyphId,
                    (glyphId, headShift, lookupFlags, action, zone) => new SimpleTransition
                {
                    GlyphId     = glyphId,
                    HeadShift   = headShift,
                    LookupFlags = lookupFlags,
                    Action      = action
                });
            }
            else if (transformation is ChainingClassContextTransformationTable)
            {
                var table = transformation as ChainingClassContextTransformationTable;
                var contextClassAssignments   = table.ContextClassDefinitions.ClassAssignments;
                var lookbackClassAssignments  = table.LookbackClassDefinition.ClassAssignments;
                var lookaheadClassAssignments = table.LookaheadClassDefinition.ClassAssignments;

                var zoneToClassesMap = new Dictionary <ContextZone, ILookup <ushort, ushort> >
                {
                    { ContextZone.Context, contextClassAssignments },
                    { ContextZone.Lookback, lookbackClassAssignments },
                    { ContextZone.Lookahead, lookaheadClassAssignments }
                };

                this.CompileChainingRuleContextTransformation(
                    transformation,
                    builder,
                    glyphId => contextClassAssignments.Single(classAssignment => classAssignment.Contains(glyphId)).Key,
                    (classId, headShift, lookupFlags, action, zone) => new SetTransition {
                    GlyphIdSet  = new HashSet <ushort>((IEnumerable <ushort>)zoneToClassesMap[zone].SingleOrDefault(p => p.Key == classId) ?? new List <ushort>()),
                    HeadShift   = headShift,
                    LookupFlags = lookupFlags,
                    Action      = action
                });
            }
            else if (transformation is ChainingCoverageContextSubstitutionTable)
            {
                var table = transformation as ChainingCoverageContextSubstitutionTable;

                foreach (var transformationSet in table.TransformationSets)
                {
                    this.CompileSingleContextTransformation(
                        table,
                        builder,
                        transformationSet,
                        (coverageTable, headShift, lookupFlags, action, zone) => new SetTransition {
                        GlyphIdSet  = new HashSet <ushort>(coverageTable.CoveredGlyphIds.Values),
                        HeadShift   = headShift,
                        LookupFlags = lookupFlags,
                        Action      = action
                    },
                        table.ContextCoverages,
                        table.LookbackCoverages,
                        table.LookaheadCoverages);
                }
            }
            else
            {
                throw new ArgumentOutOfRangeException("transformation");
            }
        }
Exemplo n.º 17
0
        /// <summary>
        /// Compiles a context transformation for a single context.
        /// </summary>
        /// <typeparam name="TContextItem">The type of items in the context. This is arbitrary - it is only used to construct individual transitions in the context recognition section of the machine.</typeparam>
        /// <param name="transformation">The transformation.</param>
        /// <param name="builder">The builder.</param>
        /// <param name="subTransformationSet">The set of tranformation to execute on the matched context.</param>
        /// <param name="createTransitionCallback">The callback used to create transitions from individual items of the context. </param>
        /// <param name="context">The context.</param>
        /// <param name="lookbackContext">The lookback context (NULL if the transition is not chaining).</param>
        /// <param name="lookaheadContext">The lookahead context (NULL if the transition is not chaining). If lookaheadContext is defined, lookbackContext must be defined as well.</param>
        /// <exception cref="System.InvalidOperationException">Transformations in transformation set don't share LookupFlags.</exception>
        private void CompileSingleContextTransformation <TContextItem>(
            IGlyphTransformationTable transformation,
            IStateMachineBuilder builder,
            ContextTransformationSet subTransformationSet,
            CreateContextTransformationTransitionDelegate <TContextItem> createTransitionCallback,
            IEnumerable <TContextItem> context,
            IEnumerable <TContextItem> lookbackContext  = null,
            IEnumerable <TContextItem> lookaheadContext = null)
        {
            if (!subTransformationSet.Transformations.Any())
            {
                return;
            }

            var contextList          = context.ToList();
            var lookbackContextList  = lookbackContext == null ? new List <TContextItem>() : lookbackContext.Reverse().ToList();
            var lookaheadContextList = lookaheadContext == null ? new List <TContextItem>() : lookaheadContext.ToList();

            var completeContext = lookbackContextList.Append(contextList).Append(lookaheadContextList).ToList();

            var subMachineLookupFlags = subTransformationSet.Transformations.First().LookupFlags;

            // All the transformations in one transformation set must have the same lookup flags (they are supposed to come from
            // a single lookup).
            if (subTransformationSet.Transformations.Any(p => p.LookupFlags != subMachineLookupFlags))
            {
                throw new InvalidOperationException("Transformations in transformation set don't share LookupFlags.");
            }

            // The head must end pointing to the first glyph after end of the context
            var subBuilder = new SubMachineBuilder(subMachineLookupFlags);

            foreach (var subTransformation in subTransformationSet.Transformations)
            {
                this.CompileTransformation(subTransformation, subBuilder);
            }

            /* The path for each rule is constructed as follows:
             *  1) A chain of states which match the context (including lookback and lookahead context).
             *  2) State which positions the head to adhere to first glyph index of the transformation set
             *      and creates the context terminator glyph. The transition checking the last glyph of the context
             *      leads to this state. Additonal state is inserted before this one in case the table has defined a
             *      lookahead
             *  3) The sub-machine to be applied on the context. This state machine is modified to jump to 4 whenever
             *      it encounters context terminator.
             *  4) State which positions the head to end of the context and removes the context terminator. */

            // Part 1. Doesn't include the transition and state checking the last glyph (see part 2).
            var contextMatchPathSegment = completeContext
                                          .Take(completeContext.Count - 1)
                                          .Select(
                (contextMember, index) =>
                createTransitionCallback(
                    contextMember,
                    1,
                    transformation.LookupFlags,
                    null,
                    this.GetContextZoneForGlyphIndex(index, contextList, lookbackContextList, lookaheadContextList))).ToList();

            List <ITransition> subMachineInitializationPathSegment;

            if (lookaheadContextList.Count > 0)
            {
                // Part 2. Sub-machine initialization state.
                subMachineInitializationPathSegment = new List <ITransition>
                {
                    createTransitionCallback(
                        completeContext.Last(),
                        -lookaheadContextList.Count,
                        transformation.LookupFlags,
                        null,
                        this.GetContextZoneForGlyphIndex(completeContext.Count - 1, contextList, lookbackContextList, lookaheadContextList)),
                    new AlwaysTransition
                    {
                        HeadShift   = -contextList.Count,
                        LookupFlags = transformation.LookupFlags,
                        Action      = new SubstitutionAction
                        {
                            ReplacedGlyphCount  = 0,
                            ReplacementGlyphIds = new[] { SubMachineBuilder.ContextTerminatorGlyphId }
                        }
                    }
                };
            }
            else
            {
                // Part 2. Sub-machine initialization state.
                subMachineInitializationPathSegment = new List <ITransition>
                {
                    createTransitionCallback(
                        completeContext.Last(),
                        -contextList.Count,
                        transformation.LookupFlags,
                        new SubstitutionAction
                    {
                        ReplacementGlyphIds = new[] { SubMachineBuilder.ContextTerminatorGlyphId }
                    },
                        this.GetContextZoneForGlyphIndex(completeContext.Count - 1, contextList, lookbackContextList, lookaheadContextList))
                };
            }


            /* Part 3 a 4. Sub-machine iself + deinitialization state.
             * Including its entry state (to which lead all the internal transitions). */
            var subMachinePaths = subBuilder.GetPaths();

            // Assemble the paths and add them into the outer machine builder.
            foreach (var subMachinePath in subMachinePaths)
            {
                var assembledPath = contextMatchPathSegment.Append(subMachineInitializationPathSegment).Append(subMachinePath).ToList();

                builder.AddPath(assembledPath);
            }
        }
Exemplo n.º 18
0
 public static IStateMachineBuilder <TState, TImpl, TInput> AddDefaultStates <TState, TImpl, TInput>(this IStateMachineBuilder <TState, TImpl, TInput> builder,
                                                                                                     Expression <Action <TImpl, TState, TInput> > enter,
                                                                                                     Expression <Action <TImpl, TState, TInput> > error,
                                                                                                     Expression <Action <TImpl, TState, TInput> > leave)
     where TState : struct, Enum where TImpl : class
 {
     return(builder.AddStates(Enum.GetValues(typeof(TState)).Cast <TState>().Select(state => (state, enter, error, leave)).ToArray()));
 }
Exemplo n.º 19
0
 public StateMachineFluentBuilder(IBuilderFactory factory)
 {
     _factory = factory ?? throw new ArgumentNullException(nameof(factory));
     _builder = factory.CreateStateMachineBuilder(null);
     _builder.SetDataModelType(@"runtime");
 }