protected internal PredictionTreeBranch(IList <PredictionTreeLeaf> baseList, int depth = 0, bool chop = false, bool passAlong = true, short[] deviations = null, int[] epsilonState = null, int minDepth = 0) : base(baseList) { this.epsilonDerivations = epsilonState ?? new int[(baseList.Count + (sizeof(SlotType) - 1)) / sizeof(SlotType)]; this.MinDepth = minDepth; this.Depth = depth; this.SetDeviations(deviations ?? new short[0]); if (passAlong) { if (!chop && depth > 0) { if (depth == this.Count - 1) { baseList[depth].AddPath(this); } else { var addedPath = new PredictionTreeBranch(this.Take(depth + 1).ToList(), depth, true, false); addedPath.SetDeviations(this.deviations); baseList[depth].AddPath(addedPath); } } } this.Validate(); }
private bool IsSafeToExpand(PredictionTreeBranch nPath) { Dictionary <IOilexerGrammarProductionRuleEntry, int> counts = new Dictionary <IOilexerGrammarProductionRuleEntry, int>(); //var currentRoot = nPath.CurrentNode.RootLeaf; //int currentCount = 1; for (int i = nPath.Depth - 1; i >= 0; i--) { var currentNode = nPath[i]; if (currentNode.RootLeaf != currentNode) { return(true); } if (counts.ContainsKey(currentNode.Rule)) { var value = ++counts[currentNode.Rule]; if (value > 2) { return(false); } } else { counts[currentNode.Rule] = 1; } //if (currentNode.RootLeaf == currentRoot) // currentCount++; } return(true); //return currentCount <= 2; }
public bool Equals(PredictionTreeBranch other) { if (other == null) { return(false); } if (other.Depth != this.Depth || other.MinDepth != this.MinDepth) { return(false); } if (this.CurrentNode != other.CurrentNode) { return(false); } if (this.Count != other.Count) { return(false); } for (int i = 0; i < this.Count; i++) { if (this[i] != other[i]) { return(false); } } return(true); }
public TransitionRequest(GrammarVocabulary transition, PredictionTreeBranch path, bool usePrevious, bool isReduction) { this.path = path; this.transitionRequirement = transition; this.usePrevious = usePrevious; this.isReduction = isReduction; }
private PredictionTreeBranch GetEpsilonTransitionPath(PredictionTreeBranch path) { short[] deviations = this.GetDeviationsUpTo(this.Depth);//IncrementDeviations(this.Depth, false); var result = new PredictionTreeBranch(this.Take(this.Depth).Concat(path).ToArray(), this.Depth, passAlong: false, deviations: deviations, epsilonState: this.epsilonDerivations.ToList().ToArray()); result.SetEpsilonDerived(result.Depth); return(result); }
internal PredictionTreeBranch GetTransitionPath(PredictionTreeBranch targetPath, PredictionTreeLeaf[] previousNodes, PredictionTreeLeaf currentNode, Dictionary <IOilexerGrammarProductionRuleEntry, GrammarVocabulary> ruleLookup, bool usePrevious, bool isEpsilonTransition = false, bool incrementDeviations = true) { if (previousNodes.Length > 0) { Debug.Assert(previousNodes[previousNodes.Length - 1].Veins.DFAOriginState.OutTransitions.Keys.Any(k => !k.Intersect(ruleLookup[currentNode.Rule]).IsEmpty)); } short[] deviations = incrementDeviations ? IncrementDeviations(previousNodes.Length, isEpsilonTransition) : this.GetDeviationsUpTo(previousNodes.Length); var result = new PredictionTreeBranch(previousNodes.Concat(new[] { currentNode }).ToArray(), targetPath.Depth, passAlong: false, deviations: deviations); result.MinDepth = targetPath.MinDepth; return(result); }
private static IEnumerable <PredictionTreeBranch> PushIntersection( PredictionTreeBranch sourceMasterPath, FiniteAutomataMultiTargetTransitionTable <GrammarVocabulary, Tuple <int, PredictionTreeBranch> > transitionTableResult, Stack <Tuple <int, PredictionTreeBranch> > toProcess, HashSet <PredictionTreeBranch> seen, Tuple <int, PredictionTreeBranch> currentPathTuple, PredictionTreeBranch currentPath, PredictionTreeBranch path, GrammarVocabulary intersection, GrammarVocabulary transitionKey = null) { /* * * * * * * * * * * * * * * * * * * * * * * * * *\ * Construct the transition table with the matching * * paths. * * * * * * * * * * * * * * * * * * * * * * * * * * */ var intersectingCurrent = from key in currentPath.CurrentNode.Veins.Keys let intersect = key.Intersect(intersection) where !intersect.IsEmpty let subPathSet = currentPath.CurrentNode.Veins[key] from subPath in subPathSet.UnalteredOriginals let rPath = new PredictionTreeBranch(sourceMasterPath.Take(currentPath.Depth).Concat(subPath).ToList(), currentPath.Depth + subPath.Depth, true, false, currentPath.GetDeviationsUpTo(currentPath.Depth), minDepth: currentPath.Depth) where rPath.Valid select rPath; var set = new List <Tuple <int, PredictionTreeBranch> >(from ip in intersectingCurrent select Tuple.Create(currentPathTuple.Item1, ip)) { Tuple.Create(currentPathTuple.Item1 + 1, new PredictionTreeBranch(path.baseList, path.Depth, false, false, minDepth: path.Depth)) }; var distinctNodeArray = (from element in set select element.Item2).Distinct().ToArray(); foreach (var element in distinctNodeArray) { yield return(element); } transitionTableResult.Add(transitionKey ?? intersection, set); /* * * * * * * * * * * * * * * * * * * * * * * * * * * *\ * If the current point is an edge, walk further * * up the parse tree to see what else lies in store. * * * * * * * * * * * * * * * * * * * * * * * * * * * * ** * Further ambiguities might result in additional look- * * ahead being necessary. * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ if (seen.Add(path) && path.CurrentNode.Veins.DFAOriginState.IsEdge) { toProcess.Push(Tuple.Create(currentPathTuple.Item1 + 1, path)); } }
/// <summary> /// Returns the <see cref="PredictionTreeBranch"/> which is /// one level above. /// </summary> /// <returns>A <see cref="PredictionTreeBranch"/> instance /// which represents a single level above /// the path chain.</returns> /// <remarks><seealso cref="Depth"/>.</remarks> /// <exception cref="System.InvalidOperationException">thrown when /// <see cref="Depth"/> is equal to <see cref="MinDepth"/>.</exception> public PredictionTreeBranch DecreaseDepth(bool passAlong = true) { if (this.Depth <= MinDepth) { throw new InvalidOperationException(); } if (this.previous == null) { this.previous = new PredictionTreeBranch(this.baseList, this.Depth - 1, passAlong: passAlong, deviations: this.deviations, epsilonState: this.epsilonDerivations) { next = this } } ; return(this.previous); }
/// <summary> /// Returns the <see cref="PredictionTreeBranch"/> which is /// one level deeper. /// </summary> /// <returns>A <see cref="PredictionTreeBranch"/> instance /// which represents a single level deeper within /// the path chain.</returns> /// <remarks><seealso cref="Depth"/>.</remarks> /// <exception cref="System.InvalidOperationException">thrown when /// <see cref="Depth"/> is equal to <see cref="IControlledCollection{T}.Count"/> - 1.</exception> public PredictionTreeBranch IncreaseDepth(bool passAlong = true) { if (Depth >= Count - 1) { throw new InvalidOperationException(); } if (this.next == null) { this.next = new PredictionTreeBranch(this.baseList, this.Depth + 1, passAlong: passAlong, deviations: this.deviations, epsilonState: this.epsilonDerivations) { previous = this } } ; return(this.next); }
private void ObtainTerminalAmbiguitiesOnPath( PredictionTreeBranch sourceMasterPath, Dictionary <SyntacticalDFAState, PredictionTreeLeaf> fullSeries, ControlledDictionary <IOilexerGrammarProductionRuleEntry, SyntacticalDFARootState> ruleDFAs, Dictionary <IOilexerGrammarProductionRuleEntry, GrammarVocabulary> ruleLookup, FiniteAutomataMultiTargetTransitionTable <GrammarVocabulary, Tuple <int, PredictionTreeBranch> > transitionTableResult, GrammarSymbolSet grammarSymbols) { var ambiguousSymbols = grammarSymbols.AmbiguousSymbols.ToList(); Stack <Tuple <int, PredictionTreeBranch> > toProcess = new Stack <Tuple <int, PredictionTreeBranch> >(); var fullCheck = this.Veins.Keys.Aggregate(GrammarVocabulary.UnionAggregateDelegate); /* * * * * * * * * * * * * * * * * * * * * * * * * * * *\ * Kick things off with the master path, this is derived * * from the incoming states from the parent rule. * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ toProcess.Push(Tuple.Create(0, sourceMasterPath)); //foreach (var transition in this.Value.Keys) // foreach (var target in this.Value[transition]) // toProcess.Push(new PredictionTreeBranch(sourceMasterPath.Take(sourceMasterPath.Depth).Concat(target).ToList(), sourceMasterPath.Depth, true, false, sourceMasterPath.GetDeviationsUpTo(sourceMasterPath.Depth))); HashSet <PredictionTreeBranch> seen = new HashSet <PredictionTreeBranch>(); while (toProcess.Count > 0) { var currentPathTuple = toProcess.Pop(); var currentPath = currentPathTuple.Item2; if (currentPath.Depth == 0) { continue; } if (currentPath.CurrentNode.Veins.Keys.Aggregate(GrammarVocabulary.UnionAggregateDelegate).Intersect(fullCheck).IsEmpty) { continue; } /* * * Walk up the tree one level into the state that * follows the current rule in whatever the current * calling rule might be. * */ var incomingTransitions = currentPath.FollowTransition(fullSeries, ruleLookup[currentPath.CurrentNode.Veins.Rule], ruleLookup, true, false, true, true); /* * * Aggregate the transitions from our previously * calculated LL(1) look-ahead information. * */ /* * * On the state following this rule, gather up the * targets which do overlap one or more of our * transitions. * */ var fullAmbiguityContext = incomingTransitions.FullCheck | fullCheck; var intersectionPoints = (from t in incomingTransitions.Keys let intersection = t.Intersect(fullCheck) where !intersection.IsEmpty from path in incomingTransitions[t] select new { Intersection = intersection, Path = path }).ToArray(); var overlap = GrammarVocabulary.NullInst; if ((fullAmbiguityContext != null && !fullAmbiguityContext.IsEmpty) && grammarSymbols.IsGrammarPotentiallyAmbiguous(fullAmbiguityContext)) { foreach (var ambiguity in ambiguousSymbols) { var localIntersect = fullCheck & ambiguity.AmbiguityKey; var incomingIntersect = incomingTransitions.FullCheck & ambiguity.AmbiguityKey; if (localIntersect.IsEmpty || incomingIntersect.IsEmpty) { /* If the intersection isn't present on one or the other sides; then, for the purposes of * this follow check, the union would not be relevant, it would likely be identified within the * prediction upon the state itself. */ continue; } var aggregateIntersect = fullAmbiguityContext & ambiguity.AmbiguityKey; var overlapIntersect = overlap & ambiguity.AmbiguityKey; if (aggregateIntersect.Equals(ambiguity.AmbiguityKey) && !overlapIntersect.Equals(ambiguity.AmbiguityKey)) { /* */ var ambiguityIntersection = (from t in incomingTransitions.Keys let intersection = t.Intersect(incomingIntersect) where !intersection.IsEmpty from path in incomingTransitions[t] select new { Intersection = intersection, Path = path }).ToArray(); var ambiguityVocabulary = new GrammarVocabulary(grammarSymbols, ambiguity); foreach (var intersectingPoint in ambiguityIntersection) { var path = intersectingPoint.Path; var intersection = localIntersect; if (path.Equals(currentPath)) { continue; } /* Notify the nodes of the ambiguities so their state-machines can be patched up. * This is done explicitly to avoid the ambiguity cropping up and allowing it everywhere, * which is incorrect. If it shows up where it's not supposed to, we have a logic error * somwehere. */ foreach (var node in (from ambigPath in PushIntersection(sourceMasterPath, transitionTableResult, toProcess, seen, currentPathTuple, currentPath, path, intersection, ambiguityVocabulary) select ambigPath.CurrentNode).Distinct().ToArray()) { node.DenoteLexicalAmbiguity(ambiguity); } } ambiguity.Occurrences++; overlap |= aggregateIntersect; } } } foreach (var intersectingPoint in intersectionPoints) { var path = intersectingPoint.Path; var intersection = intersectingPoint.Intersection; if (path.Equals(currentPath)) { continue; } PushIntersection(sourceMasterPath, transitionTableResult, toProcess, seen, currentPathTuple, currentPath, path, intersection).ToArray(); } } }
internal MultikeyedDictionary <GrammarVocabulary, int, List <Tuple <Tuple <int[], PredictionTree>[], int[]> > > ObtainTerminalAmbiguities( Dictionary <SyntacticalDFAState, PredictionTreeLeaf> fullSeries, ControlledDictionary <IOilexerGrammarProductionRuleEntry, SyntacticalDFARootState> ruleDFAs, Dictionary <IOilexerGrammarProductionRuleEntry, GrammarVocabulary> ruleLookup, GrammarSymbolSet grammarSymbols) { if (!this.Veins.DFAOriginState.IsEdge) { return(new MultikeyedDictionary <GrammarVocabulary, int, List <Tuple <Tuple <int[], PredictionTree>[], int[]> > >()); } var tempDictionary = new MultikeyedDictionary <PredictionTreeBranch, GrammarVocabulary, Tuple <int[], PredictionTree> >(); var rootNode = fullSeries[ruleDFAs[this.Rule]]; var currentIncoming = new List <PredictionTreeBranch>(rootNode.incoming); var reductions = rootNode.PointsOfReduction.ToArray(); if (reductions.Length > 0) { } var totalIncoming = new HashSet <PredictionTreeBranch>(); Dictionary <PredictionTree, PredictionTree> uniqueSet = new Dictionary <PredictionTree, PredictionTree>(); foreach (var path in currentIncoming) { var transitionTableResult = new FiniteAutomataMultiTargetTransitionTable <GrammarVocabulary, Tuple <int, PredictionTreeBranch> >(); var masterPathChop = new PredictionTreeBranch(path.Take(path.Depth).Concat(new[] { this }).ToArray(), path.Depth, false, false); masterPathChop.SetDeviations(path.GetDeviationsUpTo(path.Depth)); ObtainTerminalAmbiguitiesOnPath(masterPathChop, fullSeries, ruleDFAs, ruleLookup, transitionTableResult, grammarSymbols); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * \ * Construct the sequence of Path->Grammar->PathSets based * * off of the table provided by the ObtainTerminalAmbiguitiesOnPath. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * **/ foreach (var transition in transitionTableResult.Keys) { var epDepthLookup = (from entry in transitionTableResult[transition] group entry.Item1 by entry.Item2).ToDictionary(k => k.Key, v => v.ToArray()); //int minDepth; //var uniqueCurrent = GetUniqueDPathSet(uniqueSet, transitionTableResult, transition, epDepthLookup); //var subPath = new PredictionTreeBranch(path.Skip(minDepth).ToList(), path.Depth - minDepth, minDepth: path.MinDepth); tempDictionary.TryAdd(path, transition, Tuple.Create((from epDepth in transitionTableResult[transition] select epDepth.Item1).ToArray(), GetFollowDPathSet(transitionTableResult, transition, epDepthLookup))); } } var regrouping = (from ksvp in tempDictionary group new { Path = ksvp.Keys.Key1, Set = ksvp.Value } by ksvp.Keys.Key2).ToDictionary(k => k.Key, v => v.ToArray()); /* * foreach (var pathSet in from key in regrouping.Keys * let value = regrouping[key] * from r in value * select r.Set) * pathSet.Item2.FixAllPaths();//*/ var comparisons = (from key in regrouping.Keys let value = regrouping[key] let kRewrite = from r in value select r.Set let commonalities = PredictionTree.GetCompoundRightSideSimilarities(kRewrite) select new { Commonalities = commonalities, Transition = key }).ToDictionary(k => k.Transition, v => v.Commonalities); var resultDictionary = new MultikeyedDictionary <GrammarVocabulary, int, List <Tuple <Tuple <int[], PredictionTree>[], int[]> > >(); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * \ * Once we're done, we need to rebuild the paths with the MinDepth set to * * their current Depth. This is to ensure that it the PathSets don't try * * to reduce more than necessary. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Then we take that set and perform a right-hand-side comparison between * * the elements. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * This will be used later to reduce the walking necessary to isolate the * * proper machine to use to disambiguate the look-ahead. * \ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * **/ foreach (var comparison in comparisons.Keys) { var comparisonElements = comparisons[comparison]; foreach (var memberCount in comparisonElements.Keys) { var comparisonElement = comparisonElements[memberCount]; resultDictionary.Add(comparison, memberCount, comparisonElement); } } return(resultDictionary); }
internal void AddPath(PredictionTreeBranch path) { lock (incoming) incoming.Add(path); }
private static TransitionRequest PushTransitionRequest(GrammarVocabulary transition, PredictionTreeBranch path, bool usePrevious, bool isReduction) { var fKey = Tuple.Create(usePrevious, isReduction); lock (transitionRequests) { List <TransitionRequest> resultSet; if (!transitionRequests.TryGetValue(fKey, transition, path, out resultSet)) { transitionRequests.Add(fKey, transition, path, resultSet = new List <TransitionRequest>()); } lock (resultSet) { TransitionRequest result = resultSet.FirstOrDefault(p => p.DeviationDetail.SequenceEqual(path.deviations)); if (result == null) { resultSet.Add(result = new TransitionRequest(transition, path, usePrevious, isReduction)); } return(result); } } }
private static TransitionRequest GetTransitionRequest(GrammarVocabulary transition, PredictionTreeBranch path, bool usePrevious, bool isReduction) { List <TransitionRequest> result; var fKey = Tuple.Create(usePrevious, isReduction); lock (transitionRequests) if (transitionRequests.TryGetValue(fKey, transition, path, out result)) { lock (result) return(result.FirstOrDefault(p => p.DeviationDetail.SequenceEqual(path.deviations))); } return(null); }
private void HandleLeftRecursiveInjection(Dictionary <SyntacticalDFAState, PredictionTreeLeaf> fullSeries, Dictionary <IOilexerGrammarProductionRuleEntry, GrammarVocabulary> ruleLookup, bool usePrevious, bool isEpsilonTransition, bool silentlyFail, List <Tuple <GrammarVocabulary, PredictionTreeBranch> > result, PredictionTreeBranch targetPath, PredictionTreeLeaf targetNodeOfTransition, PredictionTreeLeaf[] previousNodes) { if (targetNodeOfTransition.RootLeaf.Veins.LeftRecursionType != ProductionRuleLeftRecursionType.None && targetNodeOfTransition.RootLeaf.Veins.LeftRecursionType != ProductionRuleLeftRecursionType.Direct /* && !isReduction*/) { var sPaths = targetNodeOfTransition.RootLeaf.IncomingPaths.Where(k => k.Depth > 0 && k.CurrentNode == targetNodeOfTransition.RootLeaf && k.MinDepth == targetPath.MinDepth && k[0] == targetNodeOfTransition.RootLeaf).ToArray(); var transitionPaths = (from p in sPaths let nPath = GetTransitionPath(targetPath, previousNodes, p, ruleLookup, usePrevious, isEpsilonTransition, false) where IsSafeToExpand(nPath) select nPath).ToArray(); foreach (var nPath in transitionPaths) { result.AddRange(nPath.FollowTransitionInternal(fullSeries, ruleLookup[targetNodeOfTransition.Rule], ruleLookup, true, isEpsilonTransition: isEpsilonTransition, silentlyFail: silentlyFail)); } } }
FollowTransitionInternal( Dictionary <SyntacticalDFAState, PredictionTreeLeaf> fullSeries, GrammarVocabulary transitionKey, Dictionary <IOilexerGrammarProductionRuleEntry, GrammarVocabulary> ruleLookup, bool usePrevious, bool isEpsilonTransition = false, bool silentlyFail = false, bool isReduction = false) { if (transitionKey.IsEmpty) { return(new Tuple <GrammarVocabulary, PredictionTreeBranch> [0]); } List <Tuple <GrammarVocabulary, PredictionTreeBranch> > result = new List <Tuple <GrammarVocabulary, PredictionTreeBranch> >(); /* * * The transition was broken up earlier to yield * subsets that overlapped on a portion of the * transition. * */ var ambiguityVocabulary = transitionKey.DisambiguateVocabulary(); short[] deviationsToPass = this.deviations; if (isReduction) { deviationsToPass = this.IncrementDeviations(this.Depth, false); } var targetPath = usePrevious ? this.Depth == this.MinDepth && this.Depth > 0 ? new PredictionTreeBranch(this.baseList, this.Depth - 1, false, false, deviationsToPass, this.epsilonDerivations, this.MinDepth - 1) : this.DecreaseDepth(false) : this; if (isReduction) { targetPath = new PredictionTreeBranch(targetPath.baseList, targetPath.Depth, false, false, deviationsToPass, this.epsilonDerivations, targetPath.MinDepth); } var fullTransitionKey = targetPath.CurrentNode.Veins.DFAOriginState.OutTransitions.Keys.FirstOrDefault(v => !v.Intersect(transitionKey.DisambiguateVocabulary()).IsEmpty); var cachedRequest = GetTransitionRequest(transitionKey, targetPath, usePrevious, isReduction); if (cachedRequest != null) { return(cachedRequest.Detail); } if (fullTransitionKey == null && !silentlyFail) { Debug.Assert(fullTransitionKey != null); } else if (fullTransitionKey == null && silentlyFail) { return(result); } var targetOfTransition = targetPath.CurrentNode.Veins.DFAOriginState.OutTransitions[fullTransitionKey]; var targetNodeOfTransition = fullSeries[targetOfTransition]; PredictionTreeLeaf[] previousNodes = null; if (targetPath.Depth > 0) { previousNodes = targetPath.Take(targetPath.Depth).ToArray(); } else { previousNodes = new PredictionTreeLeaf[0]; } if (targetNodeOfTransition.Veins.Keys.Count > 0) { foreach (var key in targetNodeOfTransition.Veins.Keys) { var tokenVar = key.GetTokenVariant(); var originalSet = key.GetRuleVariant().GetSymbols().Select(k => (IGrammarRuleSymbol)k).Select(k => new { Node = fullSeries.GetRuleNodeFromFullSeries(k.Source), Symbol = k }).Where(k => k.Node.HasBeenReduced).ToArray(); var reducedRules = originalSet.Where(k => NodeIsRelevantToThis(k.Node, targetNodeOfTransition)).Select(k => k.Symbol).ToArray(); var ruleVar = new GrammarVocabulary(key.symbols, reducedRules); foreach (var path in targetNodeOfTransition.Veins[key].UnalteredOriginals) { var currentSubPath = path; /* * * The transition is derived from the parent node's transitions because the current node is omittable. * */ while (!currentSubPath.CurrentNode.Veins.Keys.Any(k => !k.Intersect(key).IsEmpty) && currentSubPath.Depth > 0) { currentSubPath = currentSubPath.DecreaseDepth(false); } if (!tokenVar.IsEmpty) { result.Add(Tuple.Create(tokenVar, GetTransitionPath(targetPath, previousNodes, currentSubPath, ruleLookup, usePrevious, isEpsilonTransition))); } if (!ruleVar.IsEmpty) { result.Add(Tuple.Create(ruleVar, GetTransitionPath(targetPath, previousNodes, currentSubPath, ruleLookup, usePrevious, isEpsilonTransition))); } } } if (targetOfTransition.IsEdge) { HandleLeftRecursiveInjection(fullSeries, ruleLookup, usePrevious, isEpsilonTransition, silentlyFail, result, targetPath, targetNodeOfTransition, previousNodes); var result2 = result.ToArray().ToList(); if (previousNodes.Length > 0) { result.AddRange(GetTransitionPath(targetPath, previousNodes, targetNodeOfTransition, ruleLookup, usePrevious, isEpsilonTransition, false).FollowTransitionInternal(fullSeries, ruleLookup[targetNodeOfTransition.Veins.Rule], ruleLookup, true, isEpsilonTransition: isEpsilonTransition)); } else { result.Add(Tuple.Create(GrammarVocabulary.NullInst, new PredictionTreeBranch(new[] { targetNodeOfTransition }, passAlong: false))); } } } else if (targetOfTransition.IsEdge && previousNodes.Length > 0) { HandleLeftRecursiveInjection(fullSeries, ruleLookup, usePrevious, isEpsilonTransition, silentlyFail, result, targetPath, targetNodeOfTransition, previousNodes); result.AddRange(targetPath.FollowTransitionInternal(fullSeries, ruleLookup[targetNodeOfTransition.Veins.Rule], ruleLookup, true, isEpsilonTransition: isEpsilonTransition)); } else if (targetOfTransition.IsEdge && previousNodes.Length == 0 /* && includeRootEdges*/) { result.Add(Tuple.Create(GrammarVocabulary.NullInst, new PredictionTreeBranch(new[] { targetNodeOfTransition }, passAlong: false))); } var transitionDetail = PushTransitionRequest(transitionKey, targetPath, usePrevious, isReduction); if (transitionDetail.Detail == null) { transitionDetail.Detail = result; } return(result); }