| File: Internal\SrgsCompiler\Item.cs | Web Access |
| Project: src\runtime\src\libraries\System.Speech\src\System.Speech.csproj (System.Speech) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Speech.Internal.SrgsParser; namespace System.Speech.Internal.SrgsCompiler { internal sealed class Item : ParseElementCollection, IItem { #region Constructors internal Item(Backend backend, Rule rule, int minRepeat, int maxRepeat, float repeatProbability, float weight) : base(backend, rule) { // Validated by the caller _minRepeat = minRepeat; _maxRepeat = maxRepeat; _repeatProbability = repeatProbability; } #endregion #region Internal Method /// <summary> /// Process the '/item' element. /// </summary> void IElement.PostParse(IElement parentElement) { // Special case of no words but only tags. Returns an error as the result is ambiguous // <tag>var res= 1;</tag> // <item repeat="2-2"> // <tag>res= res * 2;</tag> // </item> // Should the result be 2 or 4 if (_maxRepeat != _minRepeat && _startArc != null && _startArc == _endArc && _endArc.IsEpsilonTransition && !_endArc.IsPropertylessTransition) { XmlParser.ThrowSrgsException((SRID.InvalidTagInAnEmptyItem)); } // empty <item> or repeat count == 0 if (_startArc == null || _maxRepeat == 0) { // Special Case: _maxRepeat = 0 => Epsilon transition. if (_maxRepeat == 0 && _startArc != null && _startArc.End != null) { // Delete contents of Item. Otherwise, we will end up with states disconnected to the rest of the rule. State endState = _startArc.End; _startArc.End = null; _backend.DeleteSubGraph(endState); } // empty item, just add an epsilon transition. _startArc = _endArc = _backend.EpsilonTransition(_repeatProbability); } else { // Hard case if repeat count is not one if (_minRepeat != 1 || _maxRepeat != 1) { // Duplicate the states/transitions graph as many times as repeat count //Add a state before the start to be able to duplicate the graph _startArc = InsertState(_startArc, _repeatProbability, Position.Before); State? startState = _startArc.End; // If _maxRepeat = Infinite, add epsilon transition loop back to the start of this if (_maxRepeat == int.MaxValue && _minRepeat == 1) { _endArc = InsertState(_endArc!, 1.0f, Position.After); AddEpsilonTransition(_endArc.Start, startState, 1 - _repeatProbability); } else { State? currentStartState = startState; // For each additional repeat count, clone a new subgraph and connect with appropriate transitions. for (uint cnt = 1; cnt < _maxRepeat && cnt < 255; cnt++) { // Prepare to clone a new subgraph matching the <item> content. System.Diagnostics.Debug.Assert(_endArc?.Start != null); State newStartState = _backend.CreateNewState(_endArc.Start.Rule); // Clone subgraphs and update CurrentEndState. State newEndState = _backend.CloneSubGraph(currentStartState!, _endArc.Start, newStartState); // Connect the last state with the first state //_endArc.Start.OutArcs.Add (_endArc); _endArc.End = newStartState; // reset the _endArc System.Diagnostics.Debug.Assert(newEndState.OutArcs.CountIsOne && Arc.CompareContent(_endArc, newEndState.OutArcs.First) == 0); _endArc = newEndState.OutArcs.First; if (_maxRepeat == int.MaxValue) { // If we are beyond _minRepeat, add epsilon transition from startState with (1-_repeatProbability). if (cnt == _minRepeat - 1) { // Create a new state and attach the last Arc to add _endArc = InsertState(_endArc, 1.0f, Position.After); AddEpsilonTransition(_endArc.Start, newStartState, 1 - _repeatProbability); break; } } else if (cnt <= _maxRepeat - _minRepeat) { // If we are beyond _minRepeat, add epsilon transition from startState with (1-_repeatProbability). AddEpsilonTransition(startState, newStartState, 1 - _repeatProbability); } // reset the current start state currentStartState = newStartState; } } // If _minRepeat == 0, add epsilon transition from currentEndState to FinalState with (1-_repeatProbability). // but do not do it if the only transition is an epsilon if (_minRepeat == 0 && (_startArc != _endArc || !_startArc.IsEpsilonTransition)) { System.Diagnostics.Debug.Assert(_endArc != null); if (!_endArc.IsEpsilonTransition || _endArc.SemanticTagCount > 0) { _endArc = InsertState(_endArc, 1.0f, Position.After); } AddEpsilonTransition(startState, _endArc.Start, 1 - _repeatProbability); } // Remove the added startState if possible _startArc = TrimStart(_startArc, _backend); } } // Add this item to the parent list base.PostParse((ParseElementCollection)parentElement); } #endregion #region Private Methods private void AddEpsilonTransition(State? start, State? end, float weight) { Arc epsilon = _backend.EpsilonTransition(weight); epsilon.Start = start; epsilon.End = end; } #endregion #region Private Fields private float _repeatProbability = 0.5f; private int _minRepeat = NotSet; private int _maxRepeat = NotSet; private const int NotSet = -1; #endregion } }