public IntervalSet GetFollowSet(PreventContextType preventContextType) { if (_followSet != null && _followSet[(int)preventContextType] != null) { return(_followSet[(int)preventContextType]); } IntervalSet[] sets = _followSet ?? new IntervalSet[Enum.GetValues(typeof(PreventContextType)).Cast <int>().Max() + 1]; IntervalSet set = new IntervalSet(); var queue = new Queue <Tuple <Transition, PreventContextType> >(OutgoingTransitions.Select(i => Tuple.Create(i, preventContextType))); var comparer = new TupleEqualityComparer <Transition, PreventContextType>(ObjectReferenceEqualityComparer <Transition> .Default, null); var visited = new HashSet <Tuple <Transition, PreventContextType> >(queue, comparer); while (queue.Count > 0) { var pair = queue.Dequeue(); Transition transition = pair.Item1; PreventContextType nextPreventContextType = pair.Item2; if (transition.IsContext) { switch (nextPreventContextType) { case PreventContextType.Pop: if (!transition.IsRecursive && transition is PopContextTransition) { continue; } break; case PreventContextType.PopRecursive: if (transition.IsRecursive && (transition is PopContextTransition)) { continue; } break; case PreventContextType.Push: if (!transition.IsRecursive && transition is PushContextTransition) { continue; } break; case PreventContextType.PushRecursive: if (transition.IsRecursive && (transition is PushContextTransition)) { continue; } break; default: break; } } if (transition.IsEpsilon || transition.IsContext) { // the preventContextType can only change if we're following a another context transition if (transition.IsContext) { nextPreventContextType = PreventContextType.None; if (transition.SourceState.IsOptimized) { if (transition is PushContextTransition) { nextPreventContextType = transition.IsRecursive ? PreventContextType.PushRecursive : PreventContextType.Push; } else if (transition is PopContextTransition) { nextPreventContextType = transition.IsRecursive ? PreventContextType.PopRecursive : PreventContextType.Pop; } } } if (transition.TargetState._followSet != null && transition.TargetState._followSet[(int)nextPreventContextType] != null) { set.UnionWith(transition.TargetState._followSet[(int)nextPreventContextType]); } else { foreach (var outgoing in transition.TargetState.OutgoingTransitions) { var nextPair = Tuple.Create(outgoing, nextPreventContextType); if (visited.Add(nextPair)) { queue.Enqueue(Tuple.Create(outgoing, nextPreventContextType)); } } } } else { set.UnionWith(transition.MatchSet); } } _followSet = sets; _followSet[(int)preventContextType] = set; return(set); }
private void AddOptimizedTransitions(StateOptimizer optimizer, HashSet <Transition> visited, Transition transition, PreventContextType preventContextType) { Contract.Requires(optimizer != null); Contract.Requires(visited != null); Contract.Requires(transition != null); Contract.Requires(transition.SourceState == null); Contract.Requires(preventContextType != PreventContextType.PushRecursive && preventContextType != PreventContextType.PopRecursive); Contract.Ensures(visited.Count == Contract.OldValue(visited.Count)); List <Transition> addedTransitions = null; if (transition.TargetState == this) { return; } try { while (true) { /* Done when we find: * - a match transition * - a recursive transition (which should already be analyzed) */ if (transition.IsMatch || transition.TargetState.OutgoingTransitions.Count == 0 || transition.IsRecursive) { //if (!transition.IsMatch && transition.TargetState.OutgoingTransitions.Count > 0) //{ // // must be here because it's a recursive state // transition.IsRecursive = true; //} AddTransitionInternal(transition, optimizer); return; } // inline merge of single epsilon transitions if (transition.TargetState.OutgoingTransitions.Count == 1 && transition.TargetState.OutgoingTransitions.First().IsEpsilon) { if (!visited.Add(transition.TargetState.OutgoingTransitions.First())) { throw new InvalidOperationException(); } addedTransitions = addedTransitions ?? new List <Transition>(); addedTransitions.Add(transition.TargetState.OutgoingTransitions.First()); transition = MergeTransitions(transition, transition.TargetState.OutgoingTransitions.First()); continue; } break; } bool added = false; foreach (var nextTransition in transition.TargetState.OutgoingTransitions.ToArray()) { bool preventMerge = nextTransition.IsRecursive; if (!nextTransition.IsRecursive) { switch (preventContextType) { case PreventContextType.Pop: if (transition is PopContextTransition) { preventMerge = true; } break; case PreventContextType.Push: if (transition is PushContextTransition) { preventMerge = true; } break; default: break; } } if (transition.IsEpsilon) { if (preventMerge && !added) { AddTransitionInternal(transition, optimizer); added = true; continue; } if (!visited.Add(nextTransition)) { continue; } try { Contract.Assert(!preventMerge); AddOptimizedTransitions(optimizer, visited, MergeTransitions(transition, nextTransition), preventContextType); } finally { visited.Remove(nextTransition); } } else if (transition.IsContext) { PreventContextType nextPreventContextType = PreventContextType.None; if (!preventMerge && transition.TargetState.IsOptimized) { if (nextTransition is PushContextTransition) { nextPreventContextType = PreventContextType.Push; } else if (nextTransition is PopContextTransition) { nextPreventContextType = PreventContextType.Pop; } } bool canMerge = !preventMerge && !nextTransition.IsMatch; if (canMerge && nextTransition.IsContext) { canMerge = (transition is PopContextTransition && nextTransition is PopContextTransition) || (transition is PushContextTransition && nextTransition is PushContextTransition); #if false if (canMerge) { bool recursive = ((ContextTransition)transition).ContextIdentifiers.Any(((ContextTransition)nextTransition).ContextIdentifiers.Contains); if (recursive) { transition.IsRecursive = true; canMerge = false; } } #endif } if (canMerge) { if (!visited.Add(nextTransition)) { continue; } try { AddOptimizedTransitions(optimizer, visited, MergeTransitions(transition, nextTransition), nextPreventContextType); } finally { visited.Remove(nextTransition); } } else if (!added) { AddTransitionInternal(transition, optimizer); added = true; } } } } finally { if (addedTransitions != null) { visited.ExceptWith(addedTransitions); } } }