| File: Language\Syntax\GreenNode.Enumerator.cs | Web Access |
| Project: src\roslyn\src\Razor\src\Compiler\Microsoft.CodeAnalysis.Razor.Compiler\src\Microsoft.CodeAnalysis.Razor.Compiler.csproj (Microsoft.CodeAnalysis.Razor.Compiler) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. namespace Microsoft.AspNetCore.Razor.Language.Syntax; internal abstract partial class GreenNode { /// <summary> /// Provides a depth-first enumerator for traversing <see cref="GreenNode"/> syntax trees. /// List nodes are treated as "transparent" and are not returned during enumeration, /// only their children are processed. /// </summary> /// <remarks> /// This enumerator uses a stack-based approach to traverse the syntax tree without recursion. /// It pushes child nodes in reverse order to maintain correct left-to-right traversal order. /// The enumerator must be disposed to release the underlying stack resources. /// </remarks> public ref struct Enumerator { private MemoryBuilder<GreenNode> _stack; private GreenNode? _current; public Enumerator(GreenNode node) { // MemoryBuilder<T> uses ArrayPool<T>.Shared to acquire an array. // So, we set an initial capacity of 256 to avoid unnecessary growth. // In addition, because the arrays used by MemoryBuilder<T> will be // returned to the pool, we clear them to ensure that GreenNodes aren't // kept in memory. _stack = new(initialCapacity: 256, clearArray: true); _stack.Push(node); } public void Dispose() { _stack.Dispose(); } public readonly GreenNode Current => _current!; public bool MoveNext() { while (_stack.TryPop(out var node)) { // Push children onto the stack in reverse order for correct traversal order. for (var i = node.SlotCount - 1; i >= 0; i--) { var child = node.GetSlot(i); if (child != null) { _stack.Push(child); } } // If this is not a list node, return it as the current item. // List nodes are "transparent" - we push their children but don't return the list itself. if (!node.IsList) { _current = node; return true; } } // Stack is empty, no more nodes to process _current = null; return false; } } }