Example #1
0
        protected override IEnumerable <ParseStep> GetSuccessParseStep(IRegexEngine engine, State initialState)
        {
            var matchedText = engine.Input.Substring(initialState.Index, engine.State.Index - initialState.Index);

            IList <IList <ParenCapture> > captureSet = new List <IList <ParenCapture> >();

            foreach (CapturingParens capturingParen in Children.FindBy(node => node is CapturingParens))
            {
                var captures = engine.GetCaptures(capturingParen.Number);
                captureSet.Add(new ReadOnlyCollection <ParenCapture>(captures.ToList()));
                engine.PopCapture(capturingParen.Number);
            }

            yield return(ParseStep.Match(this, initialState, matchedText, new ReadOnlyCollection <IList <ParenCapture> >(captureSet)));

            if (initialState.Index == engine.State.Index)
            {
                // If we had a successful match, and the engine didn't move, we need to move it ourselves now.
                engine.State = engine.State.Advance();
                yield return(ParseStep.AdvanceIndex(this, engine.State));
            }

            yield return(ParseStep.BeginParse(this, engine.State));
        }
        internal override IEnumerable <ParseStep> Parse(IRegexEngine engine)
        {
            yield return(ParseStep.BeginParse(this, engine.State));

            var        savedStates = new Stack <SavedState>();
            SavedState savedState  = null;

            // Attempt the regex at every location in the input, starting at the beginning and going until just past the last position.
            while (engine.State.Index <= engine.Input.Length)
            {
                var   initialState      = engine.State;
                var   matchSuccess      = true;
                State failedState       = null;
                var   skipAdvanceOnFail = false;

                // For this location in the input, try every child node.
                for (var item = savedState == null ? Children.First : savedState.Item; item != null;)
                {
                    var node = item.Value;
                    var nodeResultEnumerator = savedState == null?node.Parse(engine).GetEnumerator() : savedState.Enumerator;

                    savedState = null;

                    var nodeSuccess = false;

                    // Get all the reported results from this child node.
                    while (nodeResultEnumerator.MoveNext())
                    {
                        var result = nodeResultEnumerator.Current;

                        if (result.Type == ParseStepType.StateSaved)
                        {
                            // If decendent said it's saved its state - we need to do the same.
                            var state = new SavedState(nodeResultEnumerator, item, result.CurrentState);
                            engine.AddSavedState(state);
                            savedStates.Push(state);
                        }

                        if (ReferenceEquals(node, result.Node)) // We only pay attention to our children's results
                        {
                            if (result.Type == ParseStepType.Pass)
                            {
                                // If our child told us it was successful, note it.
                                nodeSuccess = true;
                            }
                            else if (result.Type == ParseStepType.Break)
                            {
                                // If our child told us to break, do so. (this indicates that the child was done, regardless of success or failure
                                break;
                            }
                            else if (result.Type == ParseStepType.Fail)
                            {
                                failedState       = result.CurrentState;
                                skipAdvanceOnFail = result.SkipAdvanceOnFail;
                            }
                        }

                        // Pass our children's results up.
                        yield return(result);
                    }

                    if (!nodeSuccess)
                    {
                        if (savedStates.Count > 0)
                        {
                            // If our child told us that it backtracked, begin backtracking.
                            savedState = savedStates.Pop();
                            foreach (var capture in savedState.PopCaptures(engine))
                            {
                                yield return(ParseStep.CaptureDiscarded(savedState.Item.Value, capture.Value, capture.Number));
                            }
                            item = savedState.Item;
                        }
                        else
                        {
                            // If we're here, we either ran out of saved states, or didn't have any to begin with. Our current
                            // node had no way of passing, so we'll fail at this index location in the input string.
                            matchSuccess = false;
                            break;
                        }
                    }
                    else
                    {
                        item = item.Next;
                    }
                }

                if (matchSuccess)
                {
                    // Yay! We've matched the whole group!
                    // However, we want to know if we're yielding an actual 'Match' - if we are, we need to clear our saved states.
                    bool isMatch = false;
                    foreach (var successStep in GetSuccessParseStep(engine, initialState))
                    {
                        if (successStep.Type == ParseStepType.Match)
                        {
                            isMatch = true;
                        }

                        yield return(successStep);
                    }

                    if (isMatch)
                    {
                        savedStates.Clear();
                    }

                    // ...but if we're here, our enumerator has been started up again, indicating that we're backtracking. Oblige.
                    if (savedStates.Count > 0)
                    {
                        // If our child told us that it backtracked, begin backtracking.
                        savedState = savedStates.Pop();
                        foreach (var capture in savedState.PopCaptures(engine))
                        {
                            yield return(ParseStep.CaptureDiscarded(savedState.Item.Value, capture.Value, capture.Number));
                        }
                        engine.State = savedState.CurrentState;
                    }
                }
                else
                {
                    // We failed at this index location. Advance the engine and start all over again.
                    Debug.Assert(failedState != null);
                    foreach (var failStep in GetFailParseSteps(engine, initialState, failedState, skipAdvanceOnFail))
                    {
                        yield return(failStep);
                    }
                }
            }

            // We always get here, regardless of success or failure.
            foreach (var endOfStringStep in GetEndOfStringSteps(engine))
            {
                yield return(endOfStringStep);
            }
        }