2 // Expression.cs: Stores references to items or properties.
5 // Marek Sieradzki (marek.sieradzki@gmail.com)
7 // (C) 2005 Marek Sieradzki
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
29 using System.Collections;
31 using Microsoft.Build.Framework;
32 using Microsoft.Build.Utilities;
34 namespace Microsoft.Build.BuildEngine {
35 internal class Expression {
39 ItemReference parentItemReference;
41 public Expression (Project project)
43 this.objects = new ArrayList ();
44 this.project = project;
47 public Expression (Project project, string source)
53 public void ParseSource (string source)
55 // FIXME: change StringBuilder to substrings
57 throw new ArgumentNullException ("source");
59 StringBuilder temp = new StringBuilder ();
60 CharEnumerator it = source.GetEnumerator ();
61 EvaluationState eState = EvaluationState.Out;
62 ParenState pState = ParenState.Out;
63 ApostropheState aState = ApostropheState.Out;
67 while (it.MoveNext ()) {
70 case EvaluationState.Out:
73 if (temp.Length > 0) {
74 objects.Add (temp.ToString ());
75 temp = new StringBuilder ();
77 eState = EvaluationState.InItem;
81 if (temp.Length > 0) {
82 objects.Add (temp.ToString ());
83 temp = new StringBuilder ();
85 eState = EvaluationState.InProperty;
89 if (temp.Length > 0) {
90 objects.Add (temp.ToString ());
91 temp = new StringBuilder ();
93 eState = EvaluationState.InMetadata;
97 temp.Append (it.Current);
98 if (current == source.Length - 1)
99 objects.Add (temp.ToString ());
103 case EvaluationState.InItem:
104 switch (it.Current) {
106 if (pState == ParenState.Out && aState == ApostropheState.Out)
107 pState = ParenState.Left;
108 else if (aState == ApostropheState.Out)
109 throw new Exception ("'(' not expected.");
112 if (pState == ParenState.Left && aState == ApostropheState.Out) {
113 objects.Add (new ItemReference (this, source.Substring (start, current - start + 1)));
114 eState = EvaluationState.Out;
115 pState = ParenState.Out;
119 if (aState == ApostropheState.In)
120 aState = ApostropheState.Out;
122 aState = ApostropheState.In;
128 case EvaluationState.InProperty:
129 switch (it.Current) {
131 if (pState == ParenState.Out)
132 pState = ParenState.Left;
134 throw new Exception ("'(' expected.");
137 if (pState == ParenState.Left) {
138 objects.Add (new PropertyReference (this, source.Substring (start, current - start + 1)));
139 eState = EvaluationState.Out;
140 pState = ParenState.Out;
147 case EvaluationState.InMetadata:
148 switch (it.Current) {
150 if (pState == ParenState.Out)
151 pState = ParenState.Left;
154 if (pState == ParenState.Left) {
155 objects.Add (new MetadataReference (this, source.Substring (start, current - start + 1)));
156 eState = EvaluationState.Out;
157 pState = ParenState.Out;
165 throw new Exception ("Invalid evaluation state.");
170 public IEnumerator GetEnumerator ()
172 foreach (object o in objects)
176 public object ToNonArray (Type type)
178 if (type.IsArray == true)
179 throw new ArgumentException ("Type specified can not be array type.");
181 return ToObject (ToString (), type);
184 public object ToArray (Type type)
186 if (type.IsArray == false)
187 throw new ArgumentException ("Type specified can not be element type.");
189 string[] rawTable = ToString ().Split (';');
192 if (type == typeof (bool[])) {
193 bool[] array = new bool [rawTable.Length];
194 foreach (string raw in rawTable)
195 array [i++] = (bool) ToObject (raw, typeof (bool));
197 } else if (type == typeof (string[])) {
198 string[] array = new string [rawTable.Length];
199 foreach (string raw in rawTable)
200 array [i++] = (string) ToObject (raw, typeof (string));
202 } else if (type == typeof (int[])) {
203 int[] array = new int [rawTable.Length];
204 foreach (string raw in rawTable)
205 array [i++] = (int) ToObject (raw, typeof (int));
207 } else if (type == typeof (uint[])) {
208 uint[] array = new uint [rawTable.Length];
209 foreach (string raw in rawTable)
210 array [i++] = (uint) ToObject (raw, typeof (uint));
212 } else if (type == typeof (DateTime[])) {
213 DateTime[] array = new DateTime [rawTable.Length];
214 foreach (string raw in rawTable)
215 array [i++] = (DateTime) ToObject (raw, typeof (DateTime));
217 } else throw new Exception ("Invalid type.");
220 private object ToObject (string raw, Type type)
222 if (type == typeof (bool)) {
223 return Boolean.Parse (raw);
224 } else if (type == typeof (string)) {
226 } else if (type == typeof (int)) {
227 return Int32.Parse (raw);
228 } else if (type == typeof (uint)) {
229 return UInt32.Parse (raw);
230 } else if (type == typeof (DateTime)) {
231 return DateTime.Parse (raw);
233 throw new Exception (String.Format ("Unknown type: {0}", type.ToString ()));
237 private new string ToString ()
239 StringBuilder sb = new StringBuilder ();
241 foreach (object o in this) {
243 sb.Append ((string) o);
244 } else if (o is ItemReference) {
245 sb.Append (((ItemReference)o).ToString ());
246 } else if (o is PropertyReference) {
247 sb.Append (((PropertyReference)o).ToString ());
248 } else if (o is MetadataReference) {
249 // FIXME: we don't handle them yet
251 throw new Exception ("Invalid type in objects collection.");
254 return sb.ToString ();
257 public ITaskItem ToITaskItem ()
262 throw new Exception ("Cannot cast empty expression to ITaskItem.");
264 if (objects [0] is ItemReference) {
265 ItemReference ir = (ItemReference) objects [0];
266 ITaskItem[] array = ir.ToITaskItemArray ();
267 if (array.Length == 1) {
270 throw new Exception ("TaskItem array too long");
273 item = new TaskItem (ToString ());
278 public ITaskItem[] ToITaskItemArray ()
280 ArrayList finalItems = new ArrayList ();
281 ArrayList tempItems = new ArrayList ();
283 ITaskItem[] finalArray;
285 foreach (object o in objects) {
286 if (o is ItemReference) {
288 } else if (o is PropertyReference) {
289 PropertyReference pr = (PropertyReference) o;
290 tempItems.Add (pr.ToString ());
291 } else if (o is MetadataReference) {
292 // FIXME: not handled yet
293 } else if (o is string) {
296 throw new Exception ("Invalid type in objects collection.");
299 foreach (object o in tempItems) {
300 if (o is ItemReference) {
301 ItemReference ir = (ItemReference) o;
302 array = ir.ToITaskItemArray ();
304 foreach (ITaskItem item in array)
305 finalItems.Add (item);
306 } else if (o is string) {
307 string s = (string) o;
308 array = ITaskItemArrayFromString (s);
309 foreach (ITaskItem item in array)
310 finalItems.Add (item);
312 throw new Exception ("Invalid type in tempItems collection.");
316 finalArray = new ITaskItem [finalItems.Count];
318 foreach (ITaskItem item in finalItems)
319 finalArray [i++] = item;
323 // FIXME: quite stupid name
324 private ITaskItem[] ITaskItemArrayFromString (string source)
326 ArrayList tempItems = new ArrayList ();
327 ITaskItem[] finalArray;
328 string[] splittedSource = source.Split (';');
329 foreach (string s in splittedSource) {
330 if (s != String.Empty) {
331 tempItems.Add (new TaskItem (s));
334 finalArray = new ITaskItem [tempItems.Count];
336 foreach (ITaskItem item in tempItems)
337 finalArray [i++] = item;
341 public Project Project {
342 get { return project; }
345 public ItemReference ParentItemReference {
346 get { return parentItemReference; }
350 internal enum EvaluationState {
357 internal enum ParenState {
362 internal enum ApostropheState {
367 internal enum ItemParsingState {