/// <summary> /// internal indexer that does not verify index. /// Used when caller has already ensured that index is within bounds. /// </summary> internal static SyntaxNode ItemInternalAsNode(SyntaxNode node, int index) { GreenNode greenChild; var green = node.GreenNode; var idx = index; var slotIndex = 0; // find a slot that contains the node or its parent list (if node is in a list) // we will be skipping whole slots here so we will not loop for long // the max possible number of slots is 11 (TypeDeclarationSyntax) // and typically much less than that // // at the end of this loop we will have // 1) slot index - slotIdx // 2) if the slot is a list, node index in the list - idx while (true) { greenChild = green.GetSlot(slotIndex); if (greenChild != null) { int currentOccupancy = Occupancy(greenChild); if (idx < currentOccupancy) { break; } idx -= currentOccupancy; } slotIndex++; } // get node that represents this slot var red = node.GetNodeSlot(slotIndex); if (greenChild.IsList && red != null) { // it is a red list of nodes (separated or not), most common case return(red.GetNodeSlot(idx)); } // this is a single node or token return(red); }
public static int VisitRecursive( SyntaxNode node, int windowStart, int windowLength, Action <int, int, SyntaxNode, XmlClassificationTypes> resultCollector, int start = 0) { if (node == null) { return(0); } XmlClassificationTypes[] childTypes = null; kindMap.TryGetValue(node.Kind, out childTypes); int visitedCount = 0; int windowEnd = windowStart + windowLength; var targetOffset = windowStart - start; int offset; int index; node.GetIndexAndOffset(targetOffset, out index, out offset); start += offset; for (int i = index; i < node.SlotCount; i++) { if (start > windowEnd) { break; } var child = node.GetNodeSlot(i); visitedCount++; if (child == null) { continue; } var currentStart = Math.Max(start, windowStart); var currentLength = Math.Min(windowEnd, start + child.FullWidth) - currentStart; if (currentLength >= 0) { var childType = childTypes == null ? XmlClassificationTypes.None : childTypes[i]; if (childType == XmlClassificationTypes.None) { if (child.Kind == SyntaxKind.XmlTextLiteralToken) { childType = XmlClassificationTypes.XmlText; } else if (child.Kind == SyntaxKind.XmlEntityLiteralToken) { childType = XmlClassificationTypes.XmlEntityReference; } } if (childType == XmlClassificationTypes.None) { visitedCount += VisitRecursive(child, windowStart, windowLength, resultCollector, start); } else { if (currentLength > 0) { resultCollector(currentStart, currentLength, child, childType); } } } start += child.FullWidth; } return(visitedCount); }
/// <summary> /// internal indexer that does not verify index. /// Used when caller has already ensured that index is within bounds. /// </summary> internal static SyntaxNode ItemInternal(SyntaxNode node, int index) { GreenNode greenChild; var green = node.GreenNode; var idx = index; var slotIndex = 0; var position = node.Start; // find a slot that contains the node or its parent list (if node is in a list) // we will be skipping whole slots here so we will not loop for long // the max possible number of slots is 11 (TypeDeclarationSyntax) // and typically much less than that // // at the end of this loop we will have // 1) slot index - slotIdx // 2) if the slot is a list, node index in the list - idx // 3) slot position - position while (true) { greenChild = green.GetSlot(slotIndex); if (greenChild != null) { int currentOccupancy = Occupancy(greenChild); if (idx < currentOccupancy) { break; } idx -= currentOccupancy; position += greenChild.FullWidth; } slotIndex++; } // get node that represents this slot var red = node.GetNodeSlot(slotIndex); if (!greenChild.IsList) { // this is a single node or token // if it is a node, we are done // otherwise will have to make a token with current gChild and position if (red != null) { return(red); } } else if (red != null) { // it is a red list of nodes (separated or not), most common case var redChild = red.GetNodeSlot(idx); if (redChild != null) { // this is our node return(redChild); } // must be a separator // update gChild and position and let it be handled as a token greenChild = greenChild.GetSlot(idx); position = red.GetChildPosition(idx); } else { // it is a token from a token list, uncommon case // update gChild and position and let it be handled as a token position += greenChild.GetSlotOffset(idx); greenChild = greenChild.GetSlot(idx); } return(node); }
/// <summary> /// Locate the node or token that is a child of the given <see cref="SyntaxNode"/> and contains the given position. /// </summary> /// <param name="node">The <see cref="SyntaxNode"/> to search.</param> /// <param name="targetPosition">The position.</param> /// <returns>The node or token that spans the given position.</returns> /// <remarks> /// Assumes that <paramref name="targetPosition"/> is within the span of <paramref name="node"/>. /// </remarks> internal static SyntaxNode ChildThatContainsPosition(SyntaxNode node, int targetPosition) { // The targetPosition must already be within this node Debug.Assert(node.FullSpan.Contains(targetPosition)); var green = node.GreenNode; var position = node.Start; var index = 0; Debug.Assert(!green.IsList); // Find the green node that spans the target position. // We will be skipping whole slots here so we will not loop for long // The max possible number of slots is 11 (TypeDeclarationSyntax) // and typically much less than that int slot; for (slot = 0; ; slot++) { GreenNode greenChild = green.GetSlot(slot); if (greenChild != null) { var endPosition = position + greenChild.FullWidth; if (targetPosition < endPosition) { // Descend into the child element green = greenChild; break; } position = endPosition; index += Occupancy(greenChild); } } // Realize the red node (if any) var red = node.GetNodeSlot(slot); if (!green.IsList) { // This is a single node or token. // If it is a node, we are done. if (red != null) { return(red); } // Otherwise will have to make a token with current green and position } else { slot = green.FindSlotIndexContainingOffset(targetPosition - position); // Realize the red node (if any) if (red != null) { // It is a red list of nodes (separated or not) red = red.GetNodeSlot(slot); if (red != null) { return(red); } // Must be a separator } // Otherwise we have a token. position += green.GetSlotOffset(slot); green = green.GetSlot(slot); // Since we can't have "lists of lists", the Occupancy calculation for // child elements in a list is simple. index += slot; } // Make a token with current child and position. return(node); }
private static SyntaxNode GetNodeAt(SyntaxNode node, int i) { Debug.Assert(node.IsList || (i == 0 && !node.IsList)); return(node.IsList ? node.GetNodeSlot(i) : node); }
public static SyntaxNode FindNode( this SyntaxNode node, int position, Func <SyntaxNode, bool> descendIntoChildren = null, bool includeTrivia = true, bool excludeTerminal = false) { if (node == null) { throw new ArgumentNullException(nameof(node)); } int offset = position; bool searchChildren = true; while (searchChildren) { if (descendIntoChildren?.Invoke(node) == false) { break; } // set to false, so loop will only continue if explicitly // specified in a later stage searchChildren = false; int index; node.GetIndexAndOffset(offset, out index, out offset); if (index > 0) { index--; } var slotCount = includeTrivia ? node.GetSlotCountIncludingTrivia() : node.SlotCount; for (int i = index; i < slotCount; i++) { var child = includeTrivia ? node.GetSlotIncludingTrivia(i) : node.GetNodeSlot(i); if (child != null) { if (child.Start > position) { // child is after position break; } else if ((child.Start + child.FullWidth) <= position) { // child ends before position, go to next child continue; } else { // We have hit a terminal, maybe we should be returning its non-terminal parent if (child.SlotCount == 0 && excludeTerminal) { return(node); } node = child; searchChildren = true; break; } } } } return(node); }