In Microsoft.Build.BuildEngine:
[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                 public Expression ()
43                 {
44                         this.expressionCollection = new ExpressionCollection ();
45                 }
46
47                 public void Parse (string expression)
48                 {
49                         expression = expression.Replace ('/', Path.DirectorySeparatorChar);
50                         expression = expression.Replace ('\\', Path.DirectorySeparatorChar);
51                 
52                         string [] parts = expression.Split (';');
53
54                         List <ArrayList> p1 = new List <ArrayList> (parts.Length);
55                         List <ArrayList> p2 = new List <ArrayList> (parts.Length);
56                         List <ArrayList> p3 = new List <ArrayList> (parts.Length);
57
58                         Prepare (p1, parts.Length);
59                         Prepare (p2, parts.Length);
60                         Prepare (p3, parts.Length);
61
62                         for (int i = 0; i < parts.Length; i++) {
63                                 p1 [i] = SplitItems (parts [i]);
64                         }
65
66                         for (int i = 0; i < parts.Length; i++) {
67                                 p2 [i] = new ArrayList ();
68                                 foreach (object o in p1 [i]) {
69                                         if (o is string)
70                                                 p2 [i].AddRange (SplitProperties ((string) o));
71                                         else
72                                                 p2 [i].Add (o);
73                                 }
74                         }
75
76                         for (int i = 0; i < parts.Length; i++) {
77                                 p3 [i] = new ArrayList ();
78                                 foreach (object o in p2 [i]) {
79                                         if (o is string)
80                                                 p3 [i].AddRange (SplitMetadata ((string) o));
81                                         else
82                                                 p3 [i].Add (o);
83                                 }
84                         }
85
86                         CopyToExpressionCollection (p3);
87                 }
88
89                 void Prepare (List <ArrayList> l, int length)
90                 {
91                         for (int i = 0; i < length; i++)
92                                 l.Add (null);
93                 }
94                 
95                 void CopyToExpressionCollection (List <ArrayList> lists)
96                 {
97                         for (int i = 0; i < lists.Count; i++) {
98                                 foreach (object o in lists [i]) {
99                                         if (o is string)
100                                                 expressionCollection.Add (Utilities.Unescape ((string) o));
101                                         else if (o is ItemReference)
102                                                 expressionCollection.Add ((ItemReference) o);
103                                         else if (o is PropertyReference)
104                                                 expressionCollection.Add ((PropertyReference) o);
105                                         else if (o is MetadataReference)
106                                                 expressionCollection.Add ((MetadataReference) o);
107                                 }
108                                 if (i < lists.Count - 1)
109                                         expressionCollection.Add (";");
110                         }
111                 }
112
113                 ArrayList SplitItems (string text)
114                 {
115                         ArrayList phase1 = new ArrayList ();
116                         Match m;
117                         Regex item = new Regex (
118                                 @"@\(\s*"
119                                 + @"(?<itemname>[_A-Za-z][_0-9a-zA-Z]*)"
120                                 + @"(?<has_transform>\s*->\s*'(?<transform>[^']*)')?"
121                                 + @"(?<has_separator>\s*,\s*'(?<separator>[^']*)')?"
122                                 + @"\s*\)");
123                         m = item.Match (text);
124
125                         while (m.Success) {
126                                 string name = null, transform = null, separator = null;
127                                 ItemReference ir;
128                                 
129                                 name = m.Groups [item.GroupNumberFromName ("itemname")].Value;
130                                 
131                                 if (m.Groups [item.GroupNumberFromName ("has_transform")].Success)
132                                         transform = m.Groups [item.GroupNumberFromName ("transform")].Value;
133                                 
134                                 if (m.Groups [item.GroupNumberFromName ("has_separator")].Success)
135                                         separator = m.Groups [item.GroupNumberFromName ("separator")].Value;
136
137                                 ir = new ItemReference (name, transform, separator, m.Groups [0].Index, m.Groups [0].Length);
138                                 phase1.Add (ir);
139                                 m = m.NextMatch ();
140                         }
141
142                         ArrayList phase2 = new ArrayList ();
143                         int last_end = -1;
144                         int end = text.Length - 1;
145
146                         foreach (ItemReference ir in phase1) {
147                                 int a,b;
148
149                                 a = last_end;
150                                 b = ir.Start;
151
152                                 if (b - a - 1 > 0) {
153                                         phase2.Add (text.Substring (a + 1, b - a - 1));
154                                 }
155
156                                 last_end = ir.End;
157                                 phase2.Add (ir);
158                         }
159
160                         if (last_end < end)
161                                 phase2.Add (text.Substring (last_end + 1, end - last_end));
162
163                         return phase2;
164                 }
165
166                 ArrayList SplitProperties (string text)
167                 {
168                         ArrayList phase1 = new ArrayList ();
169                         Match m;
170                         Regex property = new Regex (
171                                 @"\$\(\s*"
172                                 + @"(?<name>[_a-zA-Z][_0-9a-zA-Z]*)"
173                                 + @"\s*\)");
174                         m = property.Match (text);
175
176                         while (m.Success) {
177                                 string name = null;
178                                 PropertyReference pr;
179                                 
180                                 name = m.Groups [property.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                         Regex metadata = new Regex (
216                                 @"%\(\s*"
217                                 + @"((?<name>[_a-zA-Z][_0-9a-zA-Z]*)\.)?"
218                                 + @"(?<meta>[_a-zA-Z][_0-9a-zA-Z]*)"
219                                 + @"\s*\)");
220                         m = metadata.Match (text);
221
222                         while (m.Success) {
223                                 string name = null, meta = null;
224                                 MetadataReference mr;
225                                 
226                                 if (m.Groups [metadata.GroupNumberFromName ("name")].Success)
227                                         name = m.Groups [metadata.GroupNumberFromName ("name")].Value;
228                                 
229                                 meta = m.Groups [metadata.GroupNumberFromName ("meta")].Value;
230                                 
231                                 mr = new MetadataReference (name, meta, m.Groups [0].Index, m.Groups [0].Length);
232                                 phase1.Add (mr);
233                                 m = m.NextMatch ();
234                         }
235
236                         ArrayList phase2 = new ArrayList ();
237                         int last_end = -1;
238                         int end = text.Length - 1;
239
240                         foreach (MetadataReference mr in phase1) {
241                                 int a,b;
242
243                                 a = last_end;
244                                 b = mr.Start;
245
246                                 if (b - a - 1> 0) {
247                                         phase2.Add (text.Substring (a + 1, b - a - 1));
248                                 }
249
250                                 last_end = mr.End;
251                                 phase2.Add (mr);
252                         }
253
254                         if (last_end < end)
255                                 phase2.Add (text.Substring (last_end + 1, end - last_end));
256
257                         return phase2;
258                 }
259                 
260                 public object ConvertTo (Project project, Type type)
261                 {
262                         return expressionCollection.ConvertTo (project, type);
263                 }
264
265                 public ExpressionCollection Collection {
266                         get { return expressionCollection; }
267                 }
268         }
269 }
270
271 #endif