PageRenderTime 50ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Boo.Lang.Compiler/Ast/NodeCollection.cs

http://github.com/bamboo/boo
C# | 445 lines | 348 code | 66 blank | 31 comment | 53 complexity | af7a4f3338fd00e2ad47f78bbb22d851 MD5 | raw file
Possible License(s): GPL-2.0
  1. #region license
  2. // Copyright (c) 2004, Rodrigo B. de Oliveira (rbo@acm.org)
  3. // All rights reserved.
  4. //
  5. // Redistribution and use in source and binary forms, with or without modification,
  6. // are permitted provided that the following conditions are met:
  7. //
  8. // * Redistributions of source code must retain the above copyright notice,
  9. // this list of conditions and the following disclaimer.
  10. // * Redistributions in binary form must reproduce the above copyright notice,
  11. // this list of conditions and the following disclaimer in the documentation
  12. // and/or other materials provided with the distribution.
  13. // * Neither the name of Rodrigo B. de Oliveira nor the names of its
  14. // contributors may be used to endorse or promote products derived from this
  15. // software without specific prior written permission.
  16. //
  17. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  18. // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  19. // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  20. // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
  21. // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  23. // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  24. // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  25. // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26. // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. #endregion
  28. using System;
  29. using System.Collections;
  30. using System.Collections.Generic;
  31. namespace Boo.Lang.Compiler.Ast
  32. {
  33. /// <summary>
  34. /// Node collection base class.
  35. /// </summary>
  36. public class NodeCollection<T> : ICollection<T>, ICollection, ICloneable, IEquatable<NodeCollection<T>>
  37. where T : Node
  38. {
  39. private Node _parent;
  40. private readonly List<T> _list;
  41. protected NodeCollection()
  42. {
  43. _list = new List<T>();
  44. }
  45. protected NodeCollection(Node parent)
  46. {
  47. _parent = parent;
  48. _list = new List<T>();
  49. }
  50. protected NodeCollection(Node parent, IEnumerable<T> list)
  51. {
  52. if (null == list) throw new ArgumentNullException("list");
  53. _parent = parent;
  54. _list = new List<T>(list);
  55. }
  56. public T this[int index]
  57. {
  58. get { return _list[index]; }
  59. set
  60. {
  61. if (_list[index] == value)
  62. return;
  63. _list[index] = value;
  64. OnChanged();
  65. }
  66. }
  67. public IEnumerator<T> GetEnumerator()
  68. {
  69. return _list.GetEnumerator();
  70. }
  71. public Node ParentNode
  72. {
  73. get { return _parent; }
  74. }
  75. public bool IsEmpty
  76. {
  77. get { return 0 == _list.Count; }
  78. }
  79. public int Count
  80. {
  81. get { return _list.Count; }
  82. }
  83. public int IndexOf(T item)
  84. {
  85. return _list.IndexOf(item);
  86. }
  87. public bool IsReadOnly
  88. {
  89. get { return false; }
  90. }
  91. public bool IsSynchronized
  92. {
  93. get { return false; }
  94. }
  95. public object SyncRoot
  96. {
  97. get { return this; }
  98. }
  99. public void CopyTo(Array array, int index)
  100. {
  101. ((ICollection)_list).CopyTo(array, index);
  102. }
  103. public void CopyTo(T[] array, int index)
  104. {
  105. _list.CopyTo(array, index);
  106. }
  107. IEnumerator IEnumerable.GetEnumerator()
  108. {
  109. return _list.GetEnumerator();
  110. }
  111. public void Clear()
  112. {
  113. _list.Clear();
  114. OnChanged();
  115. }
  116. public T[] ToArray()
  117. {
  118. return _list.ToArray();
  119. }
  120. public TOut[] ToArray<TOut>(Function<T, TOut> selector)
  121. {
  122. return _list.ToArray(selector);
  123. }
  124. public T[] ToReverseArray()
  125. {
  126. T[] array = ToArray();
  127. Array.Reverse(array);
  128. return array;
  129. }
  130. public IEnumerable<T> Except<UnwantedNodeType>() where UnwantedNodeType : T
  131. {
  132. foreach (T node in _list)
  133. if (!(node is UnwantedNodeType))
  134. yield return node;
  135. }
  136. public IEnumerable<T> Except<UnwantedNodeType,UnwantedNodeType2>()
  137. where UnwantedNodeType : T
  138. where UnwantedNodeType2 : T
  139. {
  140. foreach (T node in _list)
  141. if (!(node is UnwantedNodeType) && !(node is UnwantedNodeType2))
  142. yield return node;
  143. }
  144. protected IEnumerable InternalPopRange(int begin)
  145. {
  146. OnChanged();
  147. return _list.PopRange(begin);
  148. }
  149. public bool Contains(T node)
  150. {
  151. foreach (T n in _list)
  152. if (n == node) return true;
  153. return false;
  154. }
  155. [Obsolete("Use Contains(T node) instead.")]
  156. public bool ContainsNode(T node)
  157. {
  158. return Contains(node);
  159. }
  160. public bool Contains(Predicate<T> condition)
  161. {
  162. return _list.Contains(condition);
  163. }
  164. public bool ContainsEntity(TypeSystem.IEntity entity)
  165. {
  166. foreach (T node in _list)
  167. if (entity == node.Entity)
  168. return true;
  169. return false;
  170. }
  171. public Node RemoveByEntity(TypeSystem.IEntity entity)
  172. {
  173. if (null == entity)
  174. throw new ArgumentNullException("entity");
  175. for (int i = 0; i < _list.Count; ++i)
  176. {
  177. Node node = _list[i];
  178. if (entity == node.Entity)
  179. {
  180. RemoveAt(i);
  181. return node;
  182. }
  183. }
  184. return null;
  185. }
  186. public virtual object Clone()
  187. {
  188. var clone = (NodeCollection<T>)Activator.CreateInstance(GetType());
  189. var cloneList = clone._list;
  190. foreach (T node in _list)
  191. cloneList.Add((T)node.CloneNode());
  192. return clone;
  193. }
  194. public void ClearTypeSystemBindings()
  195. {
  196. foreach (T node in _list)
  197. node.ClearTypeSystemBindings();
  198. }
  199. internal List<T> InnerList
  200. {
  201. get { return _list; }
  202. }
  203. internal void InitializeParent(Node parent)
  204. {
  205. _parent = parent;
  206. foreach (T node in _list)
  207. node.InitializeParent(_parent);
  208. }
  209. public void Reject(Predicate<T> condition)
  210. {
  211. if (null == condition)
  212. throw new ArgumentNullException("condition");
  213. var index = 0;
  214. foreach (T node in ToArray())
  215. if (condition(node))
  216. RemoveAt(index);
  217. else
  218. ++index;
  219. }
  220. public void RemoveAt(int index)
  221. {
  222. //Node existing = (Node)InnerList[index];
  223. //existing.InitializeParent(null);
  224. _list.RemoveAt(index);
  225. OnChanged();
  226. }
  227. public void ExtendWithClones(IEnumerable<T> items)
  228. {
  229. foreach (T item in items)
  230. Add((T)item.CloneNode());
  231. }
  232. public void ReplaceAt(int i, T newItem)
  233. {
  234. Initialize(newItem);
  235. _list[i] = newItem;
  236. OnChanged();
  237. }
  238. public void Add(T item)
  239. {
  240. Initialize(item);
  241. _list.Add(item);
  242. OnChanged();
  243. }
  244. [Obsolete("Use AddRange")]
  245. public void Extend(IEnumerable<T> items)
  246. {
  247. AddRange(items);
  248. }
  249. public void AddRange(IEnumerable<T> items)
  250. {
  251. AssertNotNull("items", items);
  252. foreach (T item in items)
  253. Add(item);
  254. }
  255. public bool Replace(T existing, T newItem)
  256. {
  257. AssertNotNull("existing", existing);
  258. for (int i = 0; i < _list.Count; ++i)
  259. {
  260. if (this[i] == existing)
  261. {
  262. if (null == newItem)
  263. RemoveAt(i);
  264. else
  265. ReplaceAt(i, newItem);
  266. return true;
  267. }
  268. }
  269. return false;
  270. }
  271. public void Insert(int index, T item)
  272. {
  273. Initialize(item);
  274. _list.Insert(index, item);
  275. OnChanged();
  276. }
  277. public bool Remove(T item)
  278. {
  279. if (((ICollection<T>)_list).Remove(item))
  280. {
  281. OnChanged();
  282. return true;
  283. }
  284. return false;
  285. }
  286. public event EventHandler Changed;
  287. private void OnChanged()
  288. {
  289. var changed = Changed;
  290. if (changed != null)
  291. changed(this, EventArgs.Empty);
  292. }
  293. override public int GetHashCode()
  294. {
  295. return _list.GetHashCode();
  296. }
  297. override public bool Equals(object other)
  298. {
  299. return Equals(other as NodeCollection<T>);
  300. }
  301. public bool Equals(NodeCollection<T> other)
  302. {
  303. if (null == other) return false;
  304. if (this == other) return true;
  305. if (InnerList.Count != other.Count) return false;
  306. IEnumerator<T> enumerator = other.GetEnumerator();
  307. foreach (T mine in this)
  308. {
  309. if (!enumerator.MoveNext()) return false;
  310. if (!mine.Equals(enumerator.Current)) return false;
  311. }
  312. return true;
  313. }
  314. void Initialize(Node item)
  315. {
  316. AssertNotNull("item", item);
  317. if (null != _parent)
  318. item.InitializeParent(_parent);
  319. }
  320. private static void AssertNotNull(string descrip, object o)
  321. {
  322. if (o == null)
  323. throw new ArgumentException(String.Format("null reference for: {0}", descrip));
  324. }
  325. public NodeCollection<TNew> Cast<TNew>() where TNew : Node
  326. {
  327. return Cast<TNew>(0);
  328. }
  329. public NodeCollection<TNew> Cast<TNew>(int index) where TNew : Node
  330. {
  331. if (index < 0 || index > Count)
  332. throw new ArgumentOutOfRangeException("index");
  333. if (0 == (Count - index)) //empty or no item to cast
  334. return Empty<TNew>(ParentNode);
  335. NodeCollection<TNew> nodes = new NodeCollection<TNew>(ParentNode);
  336. int i = -1;
  337. foreach (T node in _list)
  338. {
  339. ++i;
  340. if (i < index)
  341. continue;
  342. TNew cnode = node as TNew;
  343. if (null == cnode)
  344. {
  345. ExpressionStatement es = node as ExpressionStatement;
  346. if (null != es)
  347. cnode = es.Expression as TNew;
  348. }
  349. if (null == cnode)
  350. throw new InvalidCastException(
  351. string.Format("Cannot cast item #{0} from `{1}` to `{2}`",
  352. i+1, node.GetType(), typeof(TNew)));
  353. nodes.Add(cnode);
  354. }
  355. return nodes;
  356. }
  357. public static NodeCollection<TNode> Empty<TNode>(Node parent) where TNode : Node
  358. {
  359. //TODO: cache?
  360. return new NodeCollection<TNode>(parent);
  361. }
  362. public bool StartsWith<TNode>() where TNode : T
  363. {
  364. return !IsEmpty && (First is TNode);
  365. }
  366. public bool EndsWith<TNode>() where TNode : T
  367. {
  368. return !IsEmpty && (Last is TNode);
  369. }
  370. public T First
  371. {
  372. get { return (IsEmpty ? null : _list[0]); }
  373. }
  374. public T Last
  375. {
  376. get { return (IsEmpty ? null : _list[Count - 1]); }
  377. }
  378. }
  379. }