New tests.
[mono.git] / mcs / class / System.Xaml / System.Xaml.Schema / XamlTypeName.cs
1 //
2 // Copyright (C) 2010 Novell Inc. http://novell.com
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
11 // 
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
14 // 
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 //
23 using System;
24 using System.Collections.Generic;
25 using System.Linq;
26
27 namespace System.Xaml.Schema
28 {
29         public class XamlTypeName
30         {
31                 public static XamlTypeName Parse (string typeName, IXamlNamespaceResolver namespaceResolver)
32                 {
33                         XamlTypeName n;
34                         if (!TryParse (typeName, namespaceResolver, out n))
35                                 throw new FormatException (String.Format ("Invalid typeName: '{0}'", typeName));
36                         return n;
37                 }
38
39                 public static bool TryParse (string typeName, IXamlNamespaceResolver namespaceResolver, out XamlTypeName result)
40                 {
41                         if (typeName == null)
42                                 throw new ArgumentNullException ("typeName");
43                         if (namespaceResolver == null)
44                                 throw new ArgumentNullException ("namespaceResolver");
45
46                         result = null;
47                         IList<XamlTypeName> args = null;
48
49                         int idx = typeName.IndexOf ('(');
50                         if (idx >= 0) {
51                                 if (typeName [typeName.Length - 1] != ')')
52                                         return false;
53                                 if (!TryParseList (typeName.Substring (idx + 1, typeName.Length - idx - 2), namespaceResolver, out args))
54                                         return false;
55                                 typeName = typeName.Substring (0, idx);
56                         }
57
58                         idx = typeName.IndexOf (':');
59                         string prefix, local;
60                         if (idx < 0) {
61                                 prefix = String.Empty;
62                                 local = typeName;
63                         } else {
64                                 prefix = typeName.Substring (0, idx);
65                                 local = typeName.Substring (idx + 1);
66                                 if (!XamlLanguage.IsValidXamlName (prefix))
67                                         return false;
68                         }
69                         if (!XamlLanguage.IsValidXamlName (local))
70                                 return false;
71                         string ns = namespaceResolver.GetNamespace (prefix);
72                         if (ns == null)
73                                 return false;
74
75                         result = new XamlTypeName (ns, local, args);
76                         return true;
77                 }
78
79                 static readonly char [] commas = {','};
80
81                 public static IList<XamlTypeName> ParseList (string typeNameList, IXamlNamespaceResolver namespaceResolver)
82                 {
83                         IList<XamlTypeName> list;
84                         if (!TryParseList (typeNameList, namespaceResolver, out list))
85                                 throw new FormatException (String.Format ("Invalid type name list: '{0}'", typeNameList));
86                         return list;
87                 }
88
89                 public static bool TryParseList (string typeNameList, IXamlNamespaceResolver namespaceResolver, out IList<XamlTypeName> list)
90                 {
91                         if (typeNameList == null)
92                                 throw new ArgumentNullException ("typeNameList");
93                         if (namespaceResolver == null)
94                                 throw new ArgumentNullException ("namespaceResolver");
95
96                         list = null;
97                         var split = typeNameList.Split (commas);
98                         if (split.Length == 0)
99                                 return false;
100
101                         var arr = new XamlTypeName [split.Length];
102
103                         for (int i = 0; i < split.Length; i++) {
104                                 var s = split [i].Trim ();
105                                 XamlTypeName tn;
106                                 if (!TryParse (s, namespaceResolver, out tn))
107                                         return false;
108                                 arr [i] = tn;
109                         }
110
111                         list = arr;
112                         return true;
113                 }
114
115                 public static string ToString (IList<XamlTypeName> typeNameList, INamespacePrefixLookup prefixLookup)
116                 {
117                         if (typeNameList == null)
118                                 throw new ArgumentNullException ("typeNameList");
119                         if (prefixLookup == null)
120                                 throw new ArgumentNullException ("prefixLookup");
121
122                         return DoToString (typeNameList, prefixLookup);
123                 }
124
125                 static string DoToString (IList<XamlTypeName> typeNameList, INamespacePrefixLookup prefixLookup)
126                 {
127                         bool comma = false;
128                         string ret = "";
129                         foreach (var ta in typeNameList) {
130                                 if (comma)
131                                         ret += ", ";
132                                 else
133                                         comma = true;
134                                 ret += ta.ToString (prefixLookup);
135                         }
136                         return ret;
137                 }
138
139                 // instance members
140
141                 public XamlTypeName ()
142                 {
143                 }
144
145                 static readonly XamlTypeName [] empty_type_args = new XamlTypeName [0];
146
147                 public XamlTypeName (XamlType xamlType)
148                 {
149                         if (xamlType == null)
150                                 throw new ArgumentNullException ("xamlType");
151                         Namespace = xamlType.PreferredXamlNamespace;
152                         Name = xamlType.Name;
153                         if (xamlType.TypeArguments != null && xamlType.TypeArguments.Count > 0) {
154                                 var l = new List<XamlTypeName> ();
155                                 l.AddRange (from x in xamlType.TypeArguments.AsQueryable () select new XamlTypeName (x));
156                                 TypeArguments = l;
157                         }
158                         else
159                                 TypeArguments = empty_type_args;
160                 }
161                 
162                 public XamlTypeName (string xamlNamespace, string name)
163                         : this (xamlNamespace, name, null)
164                 {
165                 }
166
167                 public XamlTypeName (string xamlNamespace, string name, IEnumerable<XamlTypeName> typeArguments)
168                 {
169                         Namespace = xamlNamespace;
170                         Name = name;
171                         if (typeArguments != null) {
172                                 if (typeArguments.Any (t => t == null))
173                                         throw new ArgumentNullException ("typeArguments", "typeArguments array contains one or more null XamlTypeName");
174                                 var l = new List<XamlTypeName> ();
175                                 l.AddRange (typeArguments);
176                                 TypeArguments = l;
177                         }
178                         else
179                                 TypeArguments = empty_type_args;
180                 }
181
182                 public string Name { get; set; }
183                 public string Namespace { get; set; }
184                 public IList<XamlTypeName> TypeArguments { get; private set; }
185
186                 public override string ToString ()
187                 {
188                         return ToString (null);
189                 }
190
191                 public string ToString (INamespacePrefixLookup prefixLookup)
192                 {
193                         if (Namespace == null)
194                                 throw new InvalidOperationException ("Namespace must be set before calling ToString method.");
195                         if (Name == null)
196                                 throw new InvalidOperationException ("Name must be set before calling ToString method.");
197
198                         string ret;
199                         if (prefixLookup == null)
200                                 ret = String.Concat ("{", Namespace, "}", Name);
201                         else {
202                                 string p = prefixLookup.LookupPrefix (Namespace);
203                                 if (p == null)
204                                         throw new InvalidOperationException (String.Format ("Could not lookup prefix for namespace '{0}'", Namespace));
205                                 ret = p.Length == 0 ? Name : p + ":" + Name;
206                         }
207
208                         if (TypeArguments.Count > 0)
209                                 ret += String.Concat ("(", DoToString (TypeArguments, prefixLookup), ")");
210
211                         return ret;
212                 }
213         }
214 }