File: Language\Syntax\SyntaxTokenList.Enumerator.cs
Web Access
Project: src\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.
 
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
 
namespace Microsoft.AspNetCore.Razor.Language.Syntax;
 
internal readonly partial struct SyntaxTokenList
{
    public struct Enumerator
    {
        // This enumerator allows us to enumerate through two types of lists.
        // either it looks like:
        //
        //   Parent
        //   |
        //   List
        //   |   \
        //   c1  c2
        //
        // or
        //
        //   Parent
        //   |
        //   c1
        //
        // I.e. in the single child case, we optimize and store the child
        // directly (without any list parent).
        //
        // Enumerating over the single child case is simple.  We just 
        // return it and we're done.
        //
        // In the multi child case, things are a bit more difficult.  We need
        // to return the children in order, while also keeping their offset
        // correct.
 
        private readonly SyntaxNode? _parent;
        private readonly GreenNode? _singleNodeOrList;
        private readonly int _baseIndex;
        private readonly int _count;
 
        private int _index;
        private GreenNode? _current;
        private int _position;
 
        internal Enumerator(in SyntaxTokenList list)
        {
            _parent = list._parent;
            _singleNodeOrList = list.Node;
            _baseIndex = list._index;
            _count = list.Count;
 
            _index = -1;
            _current = null;
            _position = list.Position;
        }
 
        /// <summary>
        /// Advances the enumerator to the next token in the collection.
        /// </summary>
        /// <returns>true if the enumerator was successfully advanced to the next element; false if the enumerator
        /// has passed the end of the collection.</returns>
        public bool MoveNext()
        {
            if (_count == 0 || _count <= _index + 1)
            {
                // invalidate iterator
                _current = null;
                return false;
            }
 
            _index++;
 
            // Add the length of the previous node to the offset so that
            // the next node's offset is reported correctly.
            if (_current != null)
            {
                _position += _current.Width;
            }
 
            Debug.Assert(_singleNodeOrList != null);
            _current = GetGreenNodeAt(_singleNodeOrList, _index);
            Debug.Assert(_current != null);
 
            return true;
        }
 
        /// <summary>
        /// Gets the current element in the collection.
        /// </summary>
        public readonly SyntaxToken Current
        {
            get
            {
                if (_current == null)
                {
                    throw new InvalidOperationException();
                }
 
                // In both the list and the single node case we want to 
                // return the original root parent as the parent of this
                // token.
                return new SyntaxToken(_parent, _current, _position, _baseIndex + _index);
            }
        }
 
        public override readonly bool Equals(object? obj)
            => throw new NotSupportedException();
 
        public override readonly int GetHashCode()
            => throw new NotSupportedException();
    }
 
    private sealed class EnumeratorImpl : IEnumerator<SyntaxToken>
    {
        private Enumerator _enumerator;
 
        // SyntaxTriviaList is a relatively big struct so is passed by ref
        internal EnumeratorImpl(in SyntaxTokenList list)
        {
            _enumerator = new Enumerator(in list);
        }
 
        public SyntaxToken Current => _enumerator.Current;
 
        object IEnumerator.Current => _enumerator.Current;
 
        public bool MoveNext() => _enumerator.MoveNext();
 
        public void Reset() => throw new NotSupportedException();
 
        public void Dispose()
        {
        }
    }
}