X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FMicrosoft.Build.Engine%2FMicrosoft.Build.BuildEngine%2FExpressionCollection.cs;h=eb2929576b01fb0d0a3e73f64abf87a2f0ab0649;hb=d531a7515eaad9fb1c2ca9fff160851fa70aa168;hp=e6cd42410d08f71706654d74639fc68fa550a6ef;hpb=3f72f57672d0ab615c0953063d79b836ceb7c719;p=mono.git diff --git a/mcs/class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine/ExpressionCollection.cs b/mcs/class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine/ExpressionCollection.cs index e6cd42410d0..eb2929576b0 100644 --- a/mcs/class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine/ExpressionCollection.cs +++ b/mcs/class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine/ExpressionCollection.cs @@ -1,10 +1,12 @@ // -// ExpressionCollections.cs +// ExpressionCollection.cs // // Author: // Marek Sieradzki (marek.sieradzki@gmail.com) +// Ankit Jain (jankit@novell.com) // // (C) 2006 Marek Sieradzki +// Copyright 2009 Novell, Inc (http://www.novell.com) // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -29,6 +31,7 @@ using System; using System.Collections; +using System.Collections.Generic; using System.Text; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; @@ -38,25 +41,32 @@ namespace Microsoft.Build.BuildEngine { internal class ExpressionCollection { IList objects; + static Dictionary boolValues; + + static ExpressionCollection () + { + string[] trueValuesArray = new string[] {"true", "on", "yes"}; + string[] falseValuesArray = new string[] {"false", "off", "no"}; + + boolValues = new Dictionary (StringComparer.InvariantCultureIgnoreCase); + foreach (string s in trueValuesArray) + boolValues.Add (s, true); + foreach (string s in falseValuesArray) + boolValues.Add (s, false); + } public ExpressionCollection () { objects = new ArrayList (); } - - public void Add (ItemReference itemReference) - { - objects.Add (itemReference); - } - - public void Add (MetadataReference metadataReference) - { - objects.Add (metadataReference); + + public int Count { + get { return objects.Count; } } - public void Add (PropertyReference propertyReference) + public void Add (IReference reference) { - objects.Add (propertyReference); + objects.Add (reference); } public void Add (string s) @@ -64,18 +74,18 @@ namespace Microsoft.Build.BuildEngine { objects.Add (s); } - public object ConvertTo (Type type) + public object ConvertTo (Project project, Type type) { - if (type.IsArray == true) { + if (type.IsArray) { if (type == typeof (ITaskItem[])) - return ConvertToITaskItemArray (); + return ConvertToITaskItemArray (project); else - return ConvertToArray (type); + return ConvertToArray (project, type); } else { if (type == typeof (ITaskItem)) - return ConvertToITaskItem (); + return ConvertToITaskItem (project); else - return ConvertToNonArray (type); + return ConvertToNonArray (project, type); } } @@ -85,149 +95,201 @@ namespace Microsoft.Build.BuildEngine { yield return o; } - object ConvertToNonArray (Type type) + object ConvertToNonArray (Project project, Type type) { - return ConvertToObject (ConvertToString (), type); + return ConvertToObject (ConvertToString (project), type); } - - object ConvertToArray (Type type) + + object ConvertToArray (Project project, Type type) { - string[] rawTable = ToString ().Split (';'); - int i = 0; - - if (type == typeof (bool[]) || - type == typeof (string[]) || - type == typeof (int[]) || - type == typeof (uint[]) || - type == typeof (DateTime[])) { - - object[] array = new object [rawTable.Length]; - foreach (string raw in rawTable) - array [i++] = ConvertToObject (raw, type.GetElementType ()); - return array; - - } else throw new Exception ("Invalid type."); + ITaskItem[] items = ConvertToITaskItemArray (project); + + Type element_type = type.GetElementType (); + Array arr = Array.CreateInstance (element_type, items.Length); + for (int i = 0; i < arr.Length; i ++) + arr.SetValue (ConvertToObject (items [i].ItemSpec, element_type), i); + return arr; } - + object ConvertToObject (string raw, Type type) { if (type == typeof (bool)) { - return Boolean.Parse (raw); - } else if (type == typeof (string)) { + bool value; + if (boolValues.TryGetValue (raw, out value)) + return value; + else + return false; + } + + if (type == typeof (string)) return raw; - } else if (type == typeof (int)) { + else if (type == typeof (int)) return Int32.Parse (raw); - } else if (type == typeof (uint)) { + else if (type == typeof (uint)) return UInt32.Parse (raw); - } else if (type == typeof (DateTime)) { + else if (type == typeof (DateTime)) return DateTime.Parse (raw); - } else { + else throw new Exception (String.Format ("Unknown type: {0}", type.ToString ())); - } } - - string ConvertToString () + + string ConvertToString (Project project) { StringBuilder sb = new StringBuilder (); foreach (object o in objects) { - if (o is string) { - sb.Append ((string) o); - } else if (o is ItemReference) { - sb.Append (((ItemReference)o).ConvertToString ()); - } else if (o is PropertyReference) { - sb.Append (((PropertyReference)o).ConvertToString ()); - } else if (o is MetadataReference) { - // FIXME: we don't handle them yet - } else { - throw new Exception ("Invalid type in objects collection."); + string s = o as string; + if (s != null) { + sb.Append (s); + continue; } + + IReference br = o as IReference; + if (br != null) + sb.Append (br.ConvertToString (project)); + else + throw new Exception ("BUG: Invalid type in objects collection."); } return sb.ToString (); } - ITaskItem ConvertToITaskItem () + ITaskItem ConvertToITaskItem (Project project) { ITaskItem item; if (objects == null) throw new Exception ("Cannot cast empty expression to ITaskItem."); - - if (objects [0] is ItemReference) { - ItemReference ir = (ItemReference) objects [0]; - ITaskItem[] array = ir.ConvertToITaskItemArray (); - if (array.Length == 1) { - return array [0]; - } else { - throw new Exception ("TaskItem array too long"); - } - } else { - item = new TaskItem (ConvertToString ()); - return item; - } + + ITaskItem[] items = ConvertToITaskItemArray (project); + if (items.Length != 1) + //FIXME: msbuild gives better errors + throw new Exception (String.Format ("Too many items: {0}", items.Length)); + + return items [0]; } - ITaskItem[] ConvertToITaskItemArray () + // Concat rules (deduced) + // - ItemRef can concat only with a string ';' or PropertyRef ending in ';' + // - MetadataRef can concat with anything other than ItemRef + // - PropertyRef cannot be right after a ItemRef + // PropertyRef concats if it doesn't end in ';' + // - string cannot concat with ItemRef unless it is ';'. + // string concats if it ends in ';' + ITaskItem[] ConvertToITaskItemArray (Project project) { - ArrayList finalItems = new ArrayList (); - ArrayList tempItems = new ArrayList (); - ITaskItem[] array; - ITaskItem[] finalArray; + List finalItems = new List (); + object prev = null; + bool prev_can_concat = false; + foreach (object o in objects) { + bool can_concat = prev_can_concat; + + string str = o as string; + if (str != null) { + string trimmed_str = str.Trim (); + if (!IsSemicolon (str) && trimmed_str.Length > 0 && prev != null && prev is ItemReference) + // non-empty, non-semicolon string after item ref + ThrowCantConcatError (prev, str); + + if (trimmed_str.Length == 0 && prev is string && IsSemicolon ((string) prev)) { + // empty string after a ';', ignore it + continue; + } + + // empty string _after_ a itemref, not an error + prev_can_concat = !(str.Length > 0 && str [str.Length - 1] == ';') && trimmed_str.Length > 0; + AddItemsToArray (finalItems, + ConvertToITaskItemArrayFromString (str), + can_concat); + prev = o; + continue; + } + + IReference br = o as IReference; + if (br == null) + throw new Exception ("BUG: Invalid type in objects collection."); + if (o is ItemReference) { - tempItems.Add (o); - } else if (o is PropertyReference) { - PropertyReference pr = (PropertyReference) o; - tempItems.Add (pr.ConvertToString ()); + if (prev != null && !(prev is string && (string)prev == ";")) + ThrowCantConcatError (prev, br); + + prev_can_concat = true; } else if (o is MetadataReference) { - // FIXME: not handled yet - } else if (o is string) { - tempItems.Add (o); - } else { - throw new Exception ("Invalid type in objects collection."); + if (prev != null && prev is ItemReference) + ThrowCantConcatError (prev, br); + + prev_can_concat = true; + } else if (o is PropertyReference) { + if (prev != null && prev is ItemReference) + ThrowCantConcatError (prev, br); + + string value = ((PropertyReference) o).GetValue (project); + prev_can_concat = !(value.Length > 0 && value [value.Length - 1] == ';'); } + + AddItemsToArray (finalItems, br.ConvertToITaskItemArray (project), can_concat); + + prev = o; } - foreach (object o in tempItems) { - if (o is ItemReference) { - ItemReference ir = (ItemReference) o; - array = ir.ConvertToITaskItemArray (); - if (array != null) - foreach (ITaskItem item in array) - finalItems.Add (item); - } else if (o is string) { - string s = (string) o; - array = ConvertToITaskItemArrayFromString (s); - foreach (ITaskItem item in array) - finalItems.Add (item); - } else { - throw new Exception ("Invalid type in tempItems collection."); - } + + // Trim and Remove empty items + List toRemove = new List (); + for (int i = 0; i < finalItems.Count; i ++) { + string s = finalItems [i].ItemSpec.Trim (); + if (s.Length == 0) + toRemove.Add (finalItems [i]); + else + finalItems [i].ItemSpec = s; } + foreach (ITaskItem ti in toRemove) + finalItems.Remove (ti); - finalArray = new ITaskItem [finalItems.Count]; - int i = 0; - foreach (ITaskItem item in finalItems) - finalArray [i++] = item; - return finalArray; + return finalItems.ToArray (); + } + + // concat's first item in @items to last item in @list if @concat is true + // else just adds all @items to @list + void AddItemsToArray (List list, ITaskItem[] items, bool concat) + { + if (items == null || items.Length == 0) + return; + + int start_index = 1; + if (concat && list.Count > 0) + list [list.Count - 1].ItemSpec += items [0].ItemSpec; + else + start_index = 0; + + for (int i = start_index; i < items.Length; i ++) + list.Add (items [i]); } - ITaskItem[] ConvertToITaskItemArrayFromString (string source) - { - ArrayList tempItems = new ArrayList (); - ITaskItem[] finalArray; - string[] splittedSource = source.Split (';'); - foreach (string s in splittedSource) { - if (s != String.Empty) { - tempItems.Add (new TaskItem (s)); - } - } - finalArray = new ITaskItem [tempItems.Count]; - int i = 0; - foreach (ITaskItem item in tempItems) - finalArray [i++] = item; - return finalArray; + ITaskItem [] ConvertToITaskItemArrayFromString (string source) + { + List items = new List (); + string [] splitSource = source.Split (new char [] {';'}, + StringSplitOptions.RemoveEmptyEntries); + + foreach (string s in splitSource) + items.Add (new TaskItem (s)); + + return items.ToArray (); + } + + bool IsSemicolon (string str) + { + return str != null && str.Length == 1 && str [0] == ';'; } + + void ThrowCantConcatError (object first, object second) + { + throw new Exception (String.Format ( + "Can't concatenate Item list with other strings where an item list is " + + "expected ('{0}', '{1}'). Use semi colon to separate items.", + first.ToString (), second.ToString ())); + } + } }