2007-01-23 Marek Sieradzki <marek.sieradzki@gmail.com>
[mono.git] / mcs / class / Microsoft.Build.Engine / Microsoft.Build.BuildEngine / Expression.cs
1 //
2 // Expression.cs: Stores references to items or properties.
3 //
4 // Author:
5 //   Marek Sieradzki (marek.sieradzki@gmail.com)
6 // 
7 // (C) 2005 Marek Sieradzki
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
28 #if NET_2_0
29
30 using System;
31 using System.IO;
32 using System.Collections;
33 using System.Collections.Generic;
34 using System.Text;
35 using System.Text.RegularExpressions;
36
37 namespace Microsoft.Build.BuildEngine {
38         internal class Expression {
39         
40                 ExpressionCollection expressionCollection;
41
42                 static Regex item_regex;
43                 static Regex property_regex;
44                 static Regex metadata_regex;
45         
46                 public Expression ()
47                 {
48                         this.expressionCollection = new ExpressionCollection ();
49                 }
50
51                 public void Parse (string expression, bool allowItems)
52                 {
53                         expression = expression.Replace ('/', Path.DirectorySeparatorChar);
54                         expression = expression.Replace ('\\', Path.DirectorySeparatorChar);
55                 
56                         string [] parts = expression.Split (';');
57
58                         List <ArrayList> p1 = new List <ArrayList> (parts.Length);
59                         List <ArrayList> p2 = new List <ArrayList> (parts.Length);
60                         List <ArrayList> p3 = new List <ArrayList> (parts.Length);
61
62                         Prepare (p1, parts.Length);
63                         Prepare (p2, parts.Length);
64                         Prepare (p3, parts.Length);
65
66                         for (int i = 0; i < parts.Length; i++)
67                                 p1 [i] = SplitItems (parts [i], allowItems);
68
69                         for (int i = 0; i < parts.Length; i++) {
70                                 p2 [i] = new ArrayList ();
71                                 foreach (object o in p1 [i]) {
72                                         if (o is string)
73                                                 p2 [i].AddRange (SplitProperties ((string) o));
74                                         else
75                                                 p2 [i].Add (o);
76                                 }
77                         }
78
79                         for (int i = 0; i < parts.Length; i++) {
80                                 p3 [i] = new ArrayList ();
81                                 foreach (object o in p2 [i]) {
82                                         if (o is string)
83                                                 p3 [i].AddRange (SplitMetadata ((string) o));
84                                         else
85                                                 p3 [i].Add (o);
86                                 }
87                         }
88
89                         CopyToExpressionCollection (p3);
90                 }
91
92                 void Prepare (List <ArrayList> l, int length)
93                 {
94                         for (int i = 0; i < length; i++)
95                                 l.Add (null);
96                 }
97                 
98                 void CopyToExpressionCollection (List <ArrayList> lists)
99                 {
100                         for (int i = 0; i < lists.Count; i++) {
101                                 foreach (object o in lists [i]) {
102                                         if (o is string)
103                                                 expressionCollection.Add (Utilities.Unescape ((string) o));
104                                         else if (o is ItemReference)
105                                                 expressionCollection.Add ((ItemReference) o);
106                                         else if (o is PropertyReference)
107                                                 expressionCollection.Add ((PropertyReference) o);
108                                         else if (o is MetadataReference)
109                                                 expressionCollection.Add ((MetadataReference) o);
110                                 }
111                                 if (i < lists.Count - 1)
112                                         expressionCollection.Add (";");
113                         }
114                 }
115
116                 ArrayList SplitItems (string text, bool allowItems)
117                 {
118                         if (!allowItems) {
119                                 // FIXME: it's probably larger than 1
120                                 ArrayList l = new ArrayList ();
121                                 l.Add (text);
122                                 return l;
123                         }
124
125                         ArrayList phase1 = new ArrayList ();
126                         Match m;
127                         m = ItemRegex.Match (text);
128
129                         while (m.Success) {
130                                 string name = null, transform = null, separator = null;
131                                 ItemReference ir;
132                                 
133                                 name = m.Groups [ItemRegex.GroupNumberFromName ("itemname")].Value;
134                                 
135                                 if (m.Groups [ItemRegex.GroupNumberFromName ("has_transform")].Success)
136                                         transform = m.Groups [ItemRegex.GroupNumberFromName ("transform")].Value;
137                                 
138                                 if (m.Groups [ItemRegex.GroupNumberFromName ("has_separator")].Success)
139                                         separator = m.Groups [ItemRegex.GroupNumberFromName ("separator")].Value;
140
141                                 ir = new ItemReference (name, transform, separator, m.Groups [0].Index, m.Groups [0].Length);
142                                 phase1.Add (ir);
143                                 m = m.NextMatch ();
144                         }
145
146                         ArrayList phase2 = new ArrayList ();
147                         int last_end = -1;
148                         int end = text.Length - 1;
149
150                         foreach (ItemReference ir in phase1) {
151                                 int a,b;
152
153                                 a = last_end;
154                                 b = ir.Start;
155
156                                 if (b - a - 1 > 0) {
157                                         phase2.Add (text.Substring (a + 1, b - a - 1));
158                                 }
159
160                                 last_end = ir.End;
161                                 phase2.Add (ir);
162                         }
163
164                         if (last_end < end)
165                                 phase2.Add (text.Substring (last_end + 1, end - last_end));
166
167                         return phase2;
168                 }
169
170                 ArrayList SplitProperties (string text)
171                 {
172                         ArrayList phase1 = new ArrayList ();
173                         Match m;
174                         m = PropertyRegex.Match (text);
175
176                         while (m.Success) {
177                                 string name = null;
178                                 PropertyReference pr;
179                                 
180                                 name = m.Groups [PropertyRegex.GroupNumberFromName ("name")].Value;
181                                 
182                                 pr = new PropertyReference (name, m.Groups [0].Index, m.Groups [0].Length);
183                                 phase1.Add (pr);
184                                 m = m.NextMatch ();
185                         }
186
187                         ArrayList phase2 = new ArrayList ();
188                         int last_end = -1;
189                         int end = text.Length - 1;
190
191                         foreach (PropertyReference pr in phase1) {
192                                 int a,b;
193
194                                 a = last_end;
195                                 b = pr.Start;
196
197                                 if (b - a - 1 > 0) {
198                                         phase2.Add (text.Substring (a + 1, b - a - 1));
199                                 }
200
201                                 last_end = pr.End;
202                                 phase2.Add (pr);
203                         }
204
205                         if (last_end < end)
206                                 phase2.Add (text.Substring (last_end + 1, end - last_end));
207
208                         return phase2;
209                 }
210
211                 ArrayList SplitMetadata (string text)
212                 {
213                         ArrayList phase1 = new ArrayList ();
214                         Match m;
215                         m = MetadataRegex.Match (text);
216
217                         while (m.Success) {
218                                 string name = null, meta = null;
219                                 MetadataReference mr;
220                                 
221                                 if (m.Groups [MetadataRegex.GroupNumberFromName ("name")].Success)
222                                         name = m.Groups [MetadataRegex.GroupNumberFromName ("name")].Value;
223                                 
224                                 meta = m.Groups [MetadataRegex.GroupNumberFromName ("meta")].Value;
225                                 
226                                 mr = new MetadataReference (name, meta, m.Groups [0].Index, m.Groups [0].Length);
227                                 phase1.Add (mr);
228                                 m = m.NextMatch ();
229                         }
230
231                         ArrayList phase2 = new ArrayList ();
232                         int last_end = -1;
233                         int end = text.Length - 1;
234
235                         foreach (MetadataReference mr in phase1) {
236                                 int a,b;
237
238                                 a = last_end;
239                                 b = mr.Start;
240
241                                 if (b - a - 1> 0) {
242                                         phase2.Add (text.Substring (a + 1, b - a - 1));
243                                 }
244
245                                 last_end = mr.End;
246                                 phase2.Add (mr);
247                         }
248
249                         if (last_end < end)
250                                 phase2.Add (text.Substring (last_end + 1, end - last_end));
251
252                         return phase2;
253                 }
254                 
255                 public object ConvertTo (Project project, Type type)
256                 {
257                         return expressionCollection.ConvertTo (project, type);
258                 }
259
260                 public ExpressionCollection Collection {
261                         get { return expressionCollection; }
262                 }
263
264                 static Regex ItemRegex {
265                         get {
266                                 if (item_regex == null)
267                                         item_regex = new Regex (
268                                                 @"@\(\s*"
269                                                 + @"(?<itemname>[_A-Za-z][_0-9a-zA-Z]*)"
270                                                 + @"(?<has_transform>\s*->\s*'(?<transform>[^']*)')?"
271                                                 + @"(?<has_separator>\s*,\s*'(?<separator>[^']*)')?"
272                                                 + @"\s*\)");
273                                 return item_regex;
274                         }
275                 }
276
277                 static Regex PropertyRegex {
278                         get {
279                                 if (property_regex == null)
280                                         property_regex = new Regex (
281                                                 @"\$\(\s*"
282                                                 + @"(?<name>[_a-zA-Z][_0-9a-zA-Z]*)"
283                                                 + @"\s*\)");
284                                 return property_regex;
285                         }
286                 }
287
288                 static Regex MetadataRegex {
289                         get {
290                                 if (metadata_regex == null)
291                                         metadata_regex = new Regex (
292                                                 @"%\(\s*"
293                                                 + @"((?<name>[_a-zA-Z][_0-9a-zA-Z]*)\.)?"
294                                                 + @"(?<meta>[_a-zA-Z][_0-9a-zA-Z]*)"
295                                                 + @"\s*\)");
296                                 return metadata_regex;
297                         }
298                 }
299         }
300 }
301
302 #endif