private bool AddRecursivePopTransitions([NotNull] HashSet <State> visited, [NotNull] State currentState, Transition effectiveTransition, [NotNull] List <int> contexts, StateOptimizer optimizer) { Debug.Assert(visited != null); Debug.Assert(currentState != null); Debug.Assert(contexts != null); bool foundRecursive = false; foreach (var transition in currentState.OutgoingTransitions.Where(i => !i.IsRecursive && (i.IsEpsilon || (i is PopContextTransition))).ToArray()) { ContextTransition contextTransition = transition as ContextTransition; try { if (contextTransition != null) { contexts.AddRange(contextTransition.ContextIdentifiers); } if (transition.TargetState == this) { foundRecursive = true; if (contexts.Count == 0) { Trace.WriteLine(string.Format("State {0} is self-recursive.", this.Id)); continue; } PopContextTransition recursive = new PopContextTransition(this, contexts); recursive.IsRecursive = true; AddTransitionInternal(recursive, optimizer); continue; } if (!visited.Add(transition.TargetState)) { continue; } try { AddRecursivePopTransitions(visited, transition.TargetState, MergeTransitions(effectiveTransition, transition), contexts, optimizer); } finally { visited.Remove(transition.TargetState); } } finally { if (contextTransition != null) { contexts.RemoveRange(contexts.Count - contextTransition.ContextIdentifiers.Count, contextTransition.ContextIdentifiers.Count); } } } return(foundRecursive); }
public static Nfa Rule(RuleBinding ruleBinding) { State startState = new State(); State endState = new State(); PushContextTransition push = new PushContextTransition(ruleBinding.StartState, startState.Id); PopContextTransition pop = new PopContextTransition(endState, startState.Id); startState.AddTransition(push); ruleBinding.EndState.AddTransition(pop); return(new Nfa(startState, endState)); }
internal void RemoveTransition(Transition transition) { Contract.Requires <ArgumentNullException>(transition != null, "transition"); RemoveReachableTransition(transition); PushContextTransition pushContextTransition = transition as PushContextTransition; if (pushContextTransition != null) { int context = pushContextTransition.ContextIdentifiers[0]; HashSet <PushContextTransition> transitions = _pushContextTransitions[context]; transitions.Remove(pushContextTransition); } PopContextTransition popContextTransition = transition as PopContextTransition; if (popContextTransition != null) { int context = popContextTransition.ContextIdentifiers.Last(); HashSet <PopContextTransition> transitions = _popContextTransitions[context]; transitions.Remove(popContextTransition); } }
internal void AddTransition(Transition transition) { Contract.Requires <ArgumentNullException>(transition != null, "transition"); AddReachableTransition(transition); PushContextTransition pushContextTransition = transition as PushContextTransition; if (pushContextTransition != null) { int context = pushContextTransition.ContextIdentifiers[0]; HashSet <PushContextTransition> transitions; if (!_pushContextTransitions.TryGetValue(context, out transitions)) { transitions = new HashSet <PushContextTransition>(ObjectReferenceEqualityComparer <Transition> .Default); _pushContextTransitions[context] = transitions; } transitions.Add(pushContextTransition); } PopContextTransition popContextTransition = transition as PopContextTransition; if (popContextTransition != null) { int context = popContextTransition.ContextIdentifiers.Last(); HashSet <PopContextTransition> transitions; if (!_popContextTransitions.TryGetValue(context, out transitions)) { transitions = new HashSet <PopContextTransition>(ObjectReferenceEqualityComparer <Transition> .Default); _popContextTransitions[context] = transitions; } transitions.Add(popContextTransition); } }
internal void RemoveTransition([NotNull] Transition transition) { Requires.NotNull(transition, nameof(transition)); RemoveReachableTransition(transition); PushContextTransition pushContextTransition = transition as PushContextTransition; if (pushContextTransition != null) { int context = pushContextTransition.ContextIdentifiers[0]; HashSet <PushContextTransition> transitions = _pushContextTransitions[context]; transitions.Remove(pushContextTransition); } PopContextTransition popContextTransition = transition as PopContextTransition; if (popContextTransition != null) { int context = popContextTransition.ContextIdentifiers.Last(); HashSet <PopContextTransition> transitions = _popContextTransitions[context]; transitions.Remove(popContextTransition); } }
private Transition MergeTransitions(Transition first, Transition second) { Contract.Requires(first != null); Contract.Requires(second != null); Contract.Ensures(Contract.Result <Transition>().SourceState == null); Contract.Ensures(Contract.Result <Transition>().IsRecursive == second.IsRecursive); Contract.Assert(!first.IsRecursive); Contract.Assert(first.IsEpsilon || !second.IsRecursive); if (first.IsMatch) { if (!second.IsEpsilon) { throw new InvalidOperationException(); } MatchRangeTransition matchRangeTransition = first as MatchRangeTransition; if (matchRangeTransition != null) { return(new MatchRangeTransition(second.TargetState, matchRangeTransition.Range)); } throw new NotImplementedException("Unknown match transition type."); } if (first.IsEpsilon) { if (second.IsEpsilon) { return(new EpsilonTransition(second.TargetState)); } MatchRangeTransition matchRangeTransition = second as MatchRangeTransition; if (matchRangeTransition != null) { return(new MatchRangeTransition(second.TargetState, matchRangeTransition.Range)); } PopContextTransition popContextTransition = second as PopContextTransition; if (popContextTransition != null) { var transition = new PopContextTransition(second.TargetState, popContextTransition.ContextIdentifiers); //transition.PushTransitions.UnionWith(popContextTransition.PushTransitions); //Contract.Assert(Contract.ForAll(transition.PushTransitions, i => i.SourceState != null)); return(transition); } PushContextTransition pushContextTransition = second as PushContextTransition; if (pushContextTransition != null) { var transition = new PushContextTransition(second.TargetState, pushContextTransition.ContextIdentifiers); //transition.PopTransitions.UnionWith(pushContextTransition.PopTransitions); //Contract.Assert(Contract.ForAll(transition.PopTransitions, i => i.SourceState != null)); return(transition); } throw new NotSupportedException(); } PopContextTransition popFirst = first as PopContextTransition; if (popFirst != null) { if (second.IsEpsilon) { var transition = new PopContextTransition(second.TargetState, popFirst.ContextIdentifiers); //transition.PushTransitions.UnionWith(popFirst.PushTransitions); //Contract.Assert(Contract.ForAll(transition.PushTransitions, i => i.SourceState != null)); return(transition); } PopContextTransition popSecond = second as PopContextTransition; if (popSecond != null) { var transition = new PopContextTransition(popSecond.TargetState, popFirst.ContextIdentifiers.Concat(popSecond.ContextIdentifiers)); ////transition.PushTransitions.UnionWith(popFirst.PushTransitions); //transition.PushTransitions.UnionWith(popSecond.PushTransitions); //Contract.Assert(Contract.ForAll(transition.PushTransitions, i => i.SourceState != null)); return(transition); } if (second is PushContextTransition) { throw new InvalidOperationException(); } if (second.IsMatch) { throw new NotSupportedException(); } throw new NotImplementedException(); } PushContextTransition pushFirst = first as PushContextTransition; if (pushFirst != null) { if (second.IsEpsilon) { var transition = new PushContextTransition(second.TargetState, pushFirst.ContextIdentifiers); //transition.PopTransitions.UnionWith(pushFirst.PopTransitions); //Contract.Assert(Contract.ForAll(transition.PopTransitions, i => i.SourceState != null)); return(transition); } PushContextTransition pushSecond = second as PushContextTransition; if (pushSecond != null) { var transition = new PushContextTransition(pushSecond.TargetState, pushFirst.ContextIdentifiers.Concat(pushSecond.ContextIdentifiers)); //transition.PopTransitions.UnionWith(pushFirst.PopTransitions); ////transition.PopTransitions.UnionWith(pushSecond.PopTransitions); //Contract.Assert(Contract.ForAll(transition.PopTransitions, i => i.SourceState != null)); return(transition); } if (second is PopContextTransition) { throw new InvalidOperationException(); } if (second.IsMatch) { throw new NotSupportedException(); } throw new NotImplementedException(); } throw new NotImplementedException(); }
internal void AddTransitionInternal(Transition transition, StateOptimizer optimizer) { Contract.Requires(transition != null); Contract.Requires(transition.SourceState == null); #if ALL_CHECKS Contract.Requires(!OutgoingTransitions.Contains(transition)); Contract.Requires(!transition.TargetState.IncomingTransitions.Contains(transition)); #endif if (IsRecursiveAnalysisComplete && !transition.IsMatch && transition.TargetState == this && !transition.IsRecursive) { throw new InvalidOperationException(); } PopContextTransition popContextTransition = transition as PopContextTransition; PushContextTransition pushContextTransition = transition as PushContextTransition; #if false if (popContextTransition != null && !transition.IsRecursive) { foreach (var recursive in OutgoingTransitions.OfType <PopContextTransition>().Where(i => i.IsRecursive)) { if (popContextTransition.ContextIdentifiers.Take(recursive.ContextIdentifiers.Count).SequenceEqual(recursive.ContextIdentifiers)) { if (popContextTransition.ContextIdentifiers.Count > recursive.ContextIdentifiers.Count) { throw new InvalidOperationException(); } } } } #endif if (_outgoingTransitions.Count > 10 && !(_outgoingTransitions is ISet <Transition>)) { _outgoingTransitions = new HashSet <Transition>(_outgoingTransitions, ObjectReferenceEqualityComparer <Transition> .Default); } #if false if (transition.IsContext && transition.IsRecursive) { PopContextTransition first = transition as PopContextTransition; if (first != null) { foreach (var existing in OutgoingTransitions.OfType <PopContextTransition>().ToArray()) { if (existing.TargetState != transition.TargetState) { continue; } if (first.ContextIdentifiers.Take(existing.ContextIdentifiers.Count).SequenceEqual(existing.ContextIdentifiers)) { RemoveTransitionInternal(existing, optimizer); } } } PushContextTransition second = transition as PushContextTransition; if (second != null) { foreach (var existing in OutgoingTransitions.OfType <PushContextTransition>().ToArray()) { if (existing.TargetState != transition.TargetState) { continue; } if (second.ContextIdentifiers.Take(existing.ContextIdentifiers.Count).SequenceEqual(existing.ContextIdentifiers)) { RemoveTransitionInternal(existing, optimizer); } } } } #endif OutgoingTransitions.Add(transition); if (transition.TargetState.IncomingTransitions.Count > 10 && !(transition.TargetState.IncomingTransitions is ISet <Transition>)) { transition.TargetState._incomingTransitions = new HashSet <Transition>(transition.TargetState._incomingTransitions, ObjectReferenceEqualityComparer <Transition> .Default); } transition.TargetState.IncomingTransitions.Add(transition); transition.SourceState = this; if (optimizer != null) { optimizer.AddTransition(transition); } if (popContextTransition != null) { //if (optimizer != null) // popContextTransition.PushTransitions.UnionWith(optimizer.GetPushContextTransitions(popContextTransition.ContextIdentifiers.Last())); //foreach (var pushTransition in popContextTransition.PushTransitions) //{ // Contract.Assert(pushTransition.ContextIdentifiers.First() == popContextTransition.ContextIdentifiers.Last()); // Contract.Assert(pushTransition.SourceState != null); // pushTransition.PopTransitions.Add(popContextTransition); //} #if ALL_CHECKS Contract.Assert(Contract.ForAll(OutgoingTransitions.OfType <PushContextTransition>(), i => i.ContextIdentifiers.Last() != popContextTransition.ContextIdentifiers.First() || popContextTransition.PushTransitions.Contains(i))); #endif } else if (pushContextTransition != null) { //if (optimizer != null) // pushContextTransition.PopTransitions.UnionWith(optimizer.GetPopContextTransitions(pushContextTransition.ContextIdentifiers[0])); //foreach (var popTransition in pushContextTransition.PopTransitions) //{ // Contract.Assert(popTransition.ContextIdentifiers.Last() == pushContextTransition.ContextIdentifiers.First()); // Contract.Assert(popTransition.SourceState != null); // popTransition.PushTransitions.Add(pushContextTransition); //} #if ALL_CHECKS Contract.Assert(Contract.ForAll(OutgoingTransitions.OfType <PopContextTransition>(), i => i.ContextIdentifiers.Last() != pushContextTransition.ContextIdentifiers.First() || pushContextTransition.PopTransitions.Contains(i))); #endif } _followSet = null; _isForwardRecursive = null; transition.TargetState._sourceSet = null; transition.TargetState._isBackwardRecursive = null; }
public static Nfa Rule(RuleBinding ruleBinding) { State startState = new State(); State endState = new State(); PushContextTransition push = new PushContextTransition(ruleBinding.StartState, startState.Id); PopContextTransition pop = new PopContextTransition(endState, startState.Id); startState.AddTransition(push); ruleBinding.EndState.AddTransition(pop); return new Nfa(startState, endState); }
internal IEnumerable <PushContextTransition> GetPushContextTransitions(PopContextTransition popContextTransition) { Contract.Requires <ArgumentNullException>(popContextTransition != null, "popContextTransition"); Contract.Ensures(Contract.Result <IEnumerable <PushContextTransition> >() != null); return(GetPushContextTransitions(popContextTransition.ContextIdentifiers.Last())); }
internal IEnumerable<PushContextTransition> GetPushContextTransitions(PopContextTransition popContextTransition) { Contract.Requires<ArgumentNullException>(popContextTransition != null, "popContextTransition"); Contract.Ensures(Contract.Result<IEnumerable<PushContextTransition>>() != null); return GetPushContextTransitions(popContextTransition.ContextIdentifiers.Last()); }
internal IEnumerable <PushContextTransition> GetPushContextTransitions([NotNull] PopContextTransition popContextTransition) { Requires.NotNull(popContextTransition, nameof(popContextTransition)); return(GetPushContextTransitions(popContextTransition.ContextIdentifiers.Last())); }