예제 #1
0
        /// <summary>
        /// Tries to match provided rule one time.
        /// </summary>
        /// <param name="context">Parsing context</param>
        /// <returns>
        /// Original branch, if rule doesn't match, otherwise both - original branch and
        /// branch with consumed optional match.
        /// </returns>
        public async Task <IReadOnlyCollection <IParsingContext <TToken> > > Match(IParsingContext <TToken> context)
        {
            var branchesWithOptionalMatch = await rule.Match(context.Clone());

            if (branchesWithOptionalMatch != null && branchesWithOptionalMatch.Count > 0)
            {
                return
                    (new List <IParsingContext <TToken> >(branchesWithOptionalMatch)
                {
                    context
                });
            }

            // Optional rule didn't match, return original parsing context
            return(new[] { context });
        }
예제 #2
0
        /// <summary>
        /// Matches multiple parser rules in parallel and checks.
        /// </summary>
        /// <param name="context">Parsing context</param>
        /// <returns>All matching parsing branches or null.</returns>
        protected override async Task <IReadOnlyCollection <IParsingContext <TToken> > > MatchInternal(
            IParsingContext <TToken> context)
        {
            var activeBranches =
                new List <Task <IReadOnlyCollection <IParsingContext <TToken> > > >(rules.Length);

            var succeededBranches =
                new List <IParsingContext <TToken> >();

            // Run lookahead on all branches in parallel
            for (var ruleIndex = 0; ruleIndex < rules.Length; ++ruleIndex)
            {
                var branchContext = context.Clone();

                TraceDebug(branchContext, "Branch is matching \"{0}\"", rules[ruleIndex]);

                // In case of "any-of" we only need to match global decorators once,
                // so lets hope this rule itself will be decorated, so it's safe
                // to unwrap all alternatives
                var branchTask =
                    GlobalRulesDecoratorRule <TToken>
                    .Unwrap(rules[ruleIndex])
                    .Match(branchContext);

                if (activeBranches.Remove(branchTask))
                {
                    // We got cached task, which means our new task is already completed
                    // with the same result as some other task.
                    // We can process results of both right now and don't need to store them.

                    var branchResult = await branchTask;

                    if (branchResult != null && branchResult.Count > 0)
                    {
                        // Since it is a cached task, we know that both branches completed with the same result
                        succeededBranches.AddRange(branchResult);
                    }
                }
                else
                {
                    activeBranches.Add(branchTask);
                }
            }

            if (activeBranches.Count > 0)
            {
                var branchResults = await Task.WhenAll(activeBranches);

                for (var branchIndex = 0; branchIndex < branchResults.Length; ++branchIndex)
                {
                    var branchResult = branchResults[branchIndex];

                    if (branchResult != null && branchResult.Count > 0)
                    {
                        succeededBranches.AddRange(branchResult);
                    }
                }
            }

            if (succeededBranches.Count <= 0)
            {
                // None of the branches matched successfully
                return(null);
            }

            return(succeededBranches);
        }