Merge pull request #409 from Alkarex/patch-1
[mono.git] / mcs / class / Microsoft.Build.Engine / Microsoft.Build.BuildEngine / GroupingCollection.cs
1 //
2 // GroupingCollection.cs: Represents group of BuildItemGroup,
3 // BuildPropertyGroup and BuildChoose.
4 //
5 // Author:
6 //   Marek Sieradzki (marek.sieradzki@gmail.com)
7 // 
8 // (C) 2005 Marek Sieradzki
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
29 using System;
30 using System.Collections;
31 using System.Collections.Generic;
32
33 namespace Microsoft.Build.BuildEngine {
34         internal class GroupingCollection : IEnumerable {
35                 
36                 int     imports;
37                 int     itemGroups;
38                 Project project;
39                 int     propertyGroups;
40                 int     chooses;
41
42                 LinkedList <object>     list;
43                 LinkedListNode <object> add_iterator;
44         
45                 public GroupingCollection (Project project)
46                 {
47                         list = new LinkedList <object> ();
48                         add_iterator = null;
49                         this.project = project;
50                 }
51
52                 public IEnumerator GetChooseEnumerator ()
53                 {
54                         foreach (object o in list)
55                                 if (o is BuildChoose)
56                                         yield return o;
57                 }
58
59                 public IEnumerator GetEnumerator ()
60                 {
61                         return list.GetEnumerator ();
62                 }
63
64                 public IEnumerator GetImportEnumerator ()
65                 {
66                         foreach (object o in list)
67                                 if (o is Import)
68                                         yield return o;
69                 }
70
71                 public IEnumerator GetItemGroupAndChooseEnumerator ()
72                 {
73                         foreach (object o in list)
74                                 if (o is BuildItemGroup || o is BuildPropertyGroup)
75                                         yield return o;
76                 }
77
78                 public IEnumerator GetItemGroupEnumerator ()
79                 {
80                         foreach (object o in list)
81                                 if (o is BuildItemGroup)
82                                         yield return o;
83                 }
84
85                 public IEnumerator GetPropertyGroupAndChooseEnumerator ()
86                 {
87                         foreach (object o in list)
88                                 if (o is BuildPropertyGroup || o is BuildChoose)
89                                         yield return o;
90                 }
91
92                 public IEnumerator GetPropertyGroupEnumerator ()
93                 {
94                         foreach (object o in list)
95                                 if (o is BuildPropertyGroup)
96                                         yield return o;
97                 }
98                 
99                 internal void Add (BuildPropertyGroup bpg)
100                 {
101                         bpg.GroupingCollection = this;
102                         propertyGroups++;
103                         if (add_iterator == null)
104                                 list.AddLast (bpg);
105                         else {
106                                 list.AddAfter (add_iterator, bpg);
107                                 add_iterator = add_iterator.Next;
108                         }
109                 }
110                 
111                 internal void Add (BuildItemGroup big)
112                 {
113                         itemGroups++;
114                         if (add_iterator == null)
115                                 list.AddLast (big);
116                         else {
117                                 list.AddAfter (add_iterator, big);
118                                 add_iterator = add_iterator.Next;
119                         }
120                 }
121                 
122                 internal void Add (BuildChoose bc)
123                 {
124                         chooses++;
125                         if (add_iterator == null)
126                                 list.AddLast (bc);
127                         else {
128                                 list.AddAfter (add_iterator, bc);
129                                 add_iterator = add_iterator.Next;
130                         }
131                 }
132
133                 internal void Add (Import import)
134                 {
135                         imports++;
136                         if (add_iterator == null)
137                                 list.AddLast (import);
138                         else {
139                                 list.AddAfter (add_iterator, import);
140                                 add_iterator = add_iterator.Next;
141                         }
142                 }
143
144                 internal void Remove (BuildItemGroup big)
145                 {
146                         if (big.ParentProject != project)
147                                 throw new InvalidOperationException (
148                                         "The \"BuildItemGroup\" object specified does not belong to the correct \"Project\" object.");
149
150                         big.Detach ();
151                         list.Remove (big);
152                 }
153
154                 internal void Remove (BuildPropertyGroup bpg)
155                 {
156                         // FIXME: add bpg.Detach ();
157                         bpg.XmlElement.ParentNode.RemoveChild (bpg.XmlElement);
158                         list.Remove (bpg);
159                 }
160
161                 internal void Evaluate ()
162                 {
163                         Evaluate (EvaluationType.Property);
164                         Evaluate (EvaluationType.Item);
165                         Evaluate (EvaluationType.Choose);
166                 }
167
168                 internal void Evaluate (EvaluationType type)
169                 {
170                         BuildItemGroup big;
171                         BuildPropertyGroup bpg;
172                         LinkedListNode <object> evaluate_iterator;
173
174                         if (type == EvaluationType.Property) {
175                                 evaluate_iterator = list.First;
176                                 add_iterator = list.First;
177
178                                 while (evaluate_iterator != null) {
179                                         if (evaluate_iterator.Value is BuildPropertyGroup) {
180                                                 bpg = (BuildPropertyGroup) evaluate_iterator.Value;
181                                                 project.PushThisFileProperty (bpg.DefinedInFileName);
182                                                 try {
183                                                         if (ConditionParser.ParseAndEvaluate (bpg.Condition, project))
184                                                                 bpg.Evaluate ();
185                                                 } finally {
186                                                         project.PopThisFileProperty ();
187                                                 }
188                                         }
189
190                                         // if it wasn't moved by adding anything because of evaluating a Import shift it
191                                         if (add_iterator == evaluate_iterator)
192                                                 add_iterator = add_iterator.Next;
193
194                                         evaluate_iterator = evaluate_iterator.Next;
195                                 }
196                         } else if (type == EvaluationType.Item) {
197                                 evaluate_iterator = list.First;
198                                 add_iterator = list.First;
199
200                                 while (evaluate_iterator != null) {
201                                         if (evaluate_iterator.Value is BuildItemGroup) {
202                                                 big = (BuildItemGroup) evaluate_iterator.Value;
203                                                 project.PushThisFileProperty (big.DefinedInFileName);
204                                                 try {
205                                                         if (ConditionParser.ParseAndEvaluate (big.Condition, project))
206                                                                 big.Evaluate ();
207                                                 } finally {
208                                                         project.PopThisFileProperty ();
209                                                 }
210                                         }
211
212                                         evaluate_iterator = evaluate_iterator.Next;
213                                 }
214                         } else if (type == EvaluationType.Choose) {
215                                 evaluate_iterator = list.First;
216                                 add_iterator = list.First;
217
218                                 while (evaluate_iterator != null) {
219                                         if (evaluate_iterator.Value is BuildChoose) {
220                                                 BuildChoose bc = (BuildChoose)evaluate_iterator.Value;
221                                                 project.PushThisFileProperty (bc.DefinedInFileName);
222                                                 try {
223                                                         bool whenUsed = false;
224                                                         foreach (BuildWhen bw in bc.Whens) {
225                                                                 if (ConditionParser.ParseAndEvaluate (bw.Condition, project)) {
226                                                                         bw.Evaluate ();
227                                                                         whenUsed = true;
228                                                                         break;
229                                                                 }
230                                                         }
231                                                         if (!whenUsed && bc.Otherwise != null &&
232                                                                 ConditionParser.ParseAndEvaluate (bc.Otherwise.Condition, project)) {
233                                                                 bc.Otherwise.Evaluate ();
234                                                         }
235                                                 } finally {
236                                                         project.PopThisFileProperty ();
237                                                 }
238                                         }
239
240                                         evaluate_iterator = evaluate_iterator.Next;
241                                 }
242                         }
243
244                         add_iterator = null;
245                 }
246
247                 internal int Imports {
248                         get { return this.imports; }
249                 }
250                 
251                 internal int ItemGroups {
252                         get { return this.itemGroups; }
253                 }
254                 
255                 internal int PropertyGroups {
256                         get { return this.propertyGroups; }
257                 }
258                 
259                 internal int Chooses {
260                         get { return this.chooses; }
261                 } 
262         }
263
264         enum EvaluationType {
265                 Property,
266                 Item,
267                 Choose
268         }
269 }