// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) // This code is distributed under MIT X11 license (for details please see \doc\license.txt) using System; using System.Collections; using System.Collections.Generic; using System.Linq; using ICSharpCode.NRefactory.CSharp.PatternMatching; namespace ICSharpCode.NRefactory.CSharp { /// /// Represents the children of an AstNode that have a specific role. /// public class AstNodeCollection : ICollection where T : AstNode { readonly AstNode node; readonly Role role; public AstNodeCollection(AstNode node, Role role) { if (node == null) throw new ArgumentNullException("node"); if (role == null) throw new ArgumentNullException("role"); this.node = node; this.role = role; } public int Count { get { var e = GetEnumerator(); int count = 0; while (e.MoveNext()) count++; return count; } } public void Add(T element) { node.AddChild(element, role); } public void AddRange(IEnumerable nodes) { // Evaluate 'nodes' first, since it might change when we add the new children // Example: collection.AddRange(collection); if (nodes != null) { foreach (T node in nodes.ToList()) Add(node); } } public void AddRange(T[] nodes) { // Fast overload for arrays - we don't need to create a copy if (nodes != null) { foreach (T node in nodes) Add(node); } } public void ReplaceWith(IEnumerable nodes) { // Evaluate 'nodes' first, since it might change when we call Clear() // Example: collection.ReplaceWith(collection); if (nodes != null) nodes = nodes.ToList(); Clear(); foreach (T node in nodes) Add(node); } public void MoveTo(ICollection targetCollection) { foreach (T node in this) { node.Remove(); targetCollection.Add(node); } } public bool Contains(T element) { return element != null && element.Parent == node && element.Role == role; } public bool Remove(T element) { if (Contains(element)) { element.Remove(); return true; } else { return false; } } public void CopyTo(T[] array, int arrayIndex) { foreach (T item in this) array[arrayIndex++] = item; } public void Clear() { foreach (T item in this) item.Remove(); } bool ICollection.IsReadOnly { get { return false; } } public IEnumerator GetEnumerator() { AstNode next; for (AstNode cur = node.FirstChild; cur != null; cur = next) { // Remember next before yielding cur. // This allows removing/replacing nodes while iterating through the list. next = cur.NextSibling; if (cur.Role == role) yield return (T)cur; } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } #region Equals and GetHashCode implementation public override bool Equals(object obj) { if (obj is AstNodeCollection) { return ((AstNodeCollection)obj) == this; } else { return false; } } public override int GetHashCode() { return node.GetHashCode() ^ role.GetHashCode(); } public static bool operator ==(AstNodeCollection left, AstNodeCollection right) { return left.role == right.role && left.node == right.node; } public static bool operator !=(AstNodeCollection left, AstNodeCollection right) { return !(left.role == right.role && left.node == right.node); } #endregion internal bool DoMatch(AstNodeCollection other, Match match) { AstNode cur1 = this.node.FirstChild; AstNode cur2 = other.node.FirstChild; while (true) { while (cur1 != null && cur1.Role != role) cur1 = cur1.NextSibling; while (cur2 != null && cur2.Role != role) cur2 = cur2.NextSibling; if (cur1 == null || cur2 == null) break; if (!cur1.DoMatch(cur2, match)) return false; cur1 = cur1.NextSibling; cur2 = cur2.NextSibling; } return cur1 == null && cur2 == null; } } }