MParser/Parser/ChildNodesAndTokensList.cs

145 lines
3.9 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using Parser.Internal;
namespace Parser
{
public class ChildNodesAndTokensList : IReadOnlyList<SyntaxNodeOrToken>
{
private readonly SyntaxNode _node;
private readonly int _count;
internal ChildNodesAndTokensList(SyntaxNode node)
{
_node = node;
_count = CountChildNodes(node._green);
}
private int CountChildNodes(GreenNode green)
{
var counter = 0;
for (var i = 0; i < green.Slots; i++)
{
var child = green.GetSlot(i);
if (child == null)
{
continue;
}
if (child.IsList)
{
counter += child.Slots;
}
else
{
counter++;
}
}
return counter;
}
public IEnumerator<SyntaxNodeOrToken> GetEnumerator()
{
return new Enumerator(this);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public int Count => _count;
public SyntaxNodeOrToken this[int index]
{
get
{
if (index < 0 || index >= Count)
{
throw new IndexOutOfRangeException();
}
return ThisInternal(index);
}
}
internal SyntaxNodeOrToken ThisInternal(int index)
{
var currentSlotIndex = 0;
GreenNode currentSlot = null;
while (true)
{
currentSlot = _node._green.GetSlot(currentSlotIndex);
if (currentSlot == null)
{
currentSlotIndex++;
continue;
}
var nodesInCurrentSlot = currentSlot.IsList ? currentSlot.Slots : 1;
if (index < nodesInCurrentSlot)
{
if (currentSlot.IsList)
{
var listSlot = _node.GetNode(currentSlotIndex);
var red = listSlot.GetNode(index);
if (red != null)
{
return red;
}
// this is a token
return new SyntaxToken(listSlot, listSlot._green.GetSlot(index));
}
else
{
var red = _node.GetNode(currentSlotIndex);
if (red != null)
{
return red;
}
// this is a token
return new SyntaxToken(_node, _node._green.GetSlot(currentSlotIndex));
}
}
index -= nodesInCurrentSlot;
currentSlotIndex++;
}
}
private struct Enumerator : IEnumerator<SyntaxNodeOrToken>
{
private int _index;
private readonly ChildNodesAndTokensList _list;
private readonly int _count;
internal Enumerator(ChildNodesAndTokensList list)
{
_index = -1;
_list = list;
_count = _list.Count;
}
public bool MoveNext()
{
_index++;
return _index < _count;
}
public void Reset()
{
throw new NotImplementedException();
}
public SyntaxNodeOrToken Current => _list[_index];
object IEnumerator.Current => Current;
public void Dispose()
{
}
}
}
}