private IEnumerable <IPgnSymbol> ChildTerminalSymbolsInRange(int start, int length) { // Find the first child node that intersects with the given range. // Can safely call GetChildIndexAfter because of invariant: start < this.Length int childIndex = GetChildIndexAfter(0 <= start ? start : 0); int childEndPosition = GetChildStartPosition(childIndex); while (childIndex < ChildCount && childEndPosition < start + length) { int childStartPosition = childEndPosition; childEndPosition = GetChildStartOrEndPosition(childIndex + 1); // Skip empty child nodes. if (childStartPosition < childEndPosition) { PgnSyntax childNode = GetChild(childIndex); if (childNode.IsTerminalSymbol(out IPgnSymbol pgnTerminalSymbol)) { yield return(pgnTerminalSymbol); } else { // Translate to relative child position by subtracting childStartPosition. foreach (var descendant in childNode.ChildTerminalSymbolsInRange(start - childStartPosition, length)) { yield return(descendant); } } } childIndex++; } }
/// <summary> /// Initializes as empty. /// </summary> public SafeLazyChildSyntaxOrEmpty(PgnSyntax parent, int start) { lazyNodeIfNonEmpty = default; nodeIfEmpty = new PgnEmptySyntax(parent, start); }
internal PgnEmptySyntax(PgnSyntax parentSyntax, int start) { ParentSyntax = parentSyntax; Start = start; }