Merge pull request #498 from Unroll-Me/master
[mono.git] / mcs / tools / monkeydoc / Monkeydoc.Ecma / EcmaDesc.cs
1 using System;
2 using System.Linq;
3 using System.Text;
4 using System.Collections.Generic;
5
6 namespace Monkeydoc.Ecma
7 {
8         /* Some properties might not be filled/meaningful depending on kind
9          * like a namespace EcmaUrl won't have a valid TypeName
10          */
11         public class EcmaDesc : IEquatable<EcmaDesc>
12         {
13                 public enum Kind
14                 {
15                         Type,
16                         Constructor,
17                         Method,
18                         Namespace,
19                         Field,
20                         Property,
21                         Event,
22                         Operator
23                 }
24
25                 public enum Mod
26                 {
27                         Normal,
28                         Pointer,
29                         Ref,
30                         Out
31                 }
32
33                 public enum Format
34                 {
35                         WithArgs,
36                         WithoutArgs
37                 }
38
39                 public Kind DescKind {
40                         get;
41                         set;
42                 }
43
44                 public Mod DescModifier {
45                         get;
46                         set;
47                 }
48
49                 public string Namespace {
50                         get;
51                         set;
52                 }
53
54                 public string TypeName {
55                         get;
56                         set;
57                 }
58
59                 public string MemberName {
60                         get;
61                         set;
62                 }
63
64                 public EcmaDesc NestedType {
65                         get;
66                         set;
67                 }
68
69                 /* A list of the array dimensions attached to this type.
70                  * The list count corresponds to the number of recursive
71                  * array definition (jagged arrays) the value of the
72                  * corresponding list item is the number of dimension
73                  * attached to that array definition instance
74                  */
75                 public IList<int> ArrayDimensions {
76                         get;
77                         set;
78                 }
79
80                 /* Depending on the form of the url, we might not have the type
81                  * of the argument but only how many the type/member has i.e.
82                  * when such number is specified with a backtick
83                  */
84                 public IList<EcmaDesc> GenericTypeArguments {
85                         get;
86                         set;
87                 }
88
89                 public IList<EcmaDesc> GenericMemberArguments {
90                         get;
91                         set;
92                 }
93
94                 public IList<EcmaDesc> MemberArguments {
95                         get;
96                         set;
97                 }
98
99                 /* This indicates that we actually want an inner part of the ecmadesc
100                  * i.e. in case of T: we could want the members (*), ctor (C), methods (M), ...
101                  */
102                 public char Etc {
103                         get;
104                         set;
105                 }
106
107                 public bool IsEtc {
108                         get {
109                                 return Etc != (char)0;
110                         }
111                 }
112
113                 /* EtcFilter is only valid in some case of IsEtc when the inner part needs
114                  * to be further filtered e.g. in case we want a listing of the type overloads
115                  * Equals
116                  */
117                 public string EtcFilter {
118                         get;
119                         set;
120                 }
121
122                 /* When a member is an explicit implementation of an interface member, we register
123                  * the member EcmaDesc with its interface parent here
124                  */
125                 public EcmaDesc ExplicitImplMember {
126                         get;
127                         set;
128                 }
129
130                 // Returns the TypeName and the generic/inner type information if existing
131                 public string ToCompleteTypeName (char innerTypeSeparator = '.')
132                 {
133                         var result = TypeName;
134                         if (GenericTypeArguments != null)
135                                 result += FormatGenericArgs (GenericTypeArguments);
136                         if (NestedType != null)
137                                 result += innerTypeSeparator + NestedType.ToCompleteTypeName ();
138                         if (ArrayDimensions != null && ArrayDimensions.Count > 0)
139                                 result += ArrayDimensions.Select (dim => "[" + new string (',', dim - 1) + "]").Aggregate (string.Concat);
140
141                         return result;
142                 }
143
144                 // Returns the member name with its generic types if existing
145                 public string ToCompleteMemberName (Format format)
146                 {
147                         /* We special process two cases:
148                          *   - Explicit member implementation which append a full type specification
149                          *   - Conversion operator which are exposed as normal method but have specific captioning in the end
150                          */
151                         if (ExplicitImplMember != null) {
152                                 var impl = ExplicitImplMember;
153                                 return impl.FormattedNamespace + impl.ToCompleteTypeName () + "." + impl.ToCompleteMemberName (format);
154                         } else if (format == Format.WithArgs && DescKind == Kind.Operator && MemberName.EndsWith ("Conversion")) {
155                                 var type1 = MemberArguments[0].FormattedNamespace + MemberArguments[0].ToCompleteTypeName () + ModToString (MemberArguments[0]);
156                                 var type2 = MemberArguments[1].FormattedNamespace + MemberArguments[1].ToCompleteTypeName () + ModToString (MemberArguments[1]);
157                                 return type1 + " to " + type2;
158                         }
159
160                         var result = IsEtc && !string.IsNullOrEmpty (EtcFilter) ? EtcFilter : MemberName;
161
162                         // Temporary hack for monodoc produced inner type ctor
163                         //if (DescKind == Kind.Constructor && NestedType != null)
164                                 //result = ToCompleteTypeName ();
165
166                         if (GenericMemberArguments != null)
167                                 result += FormatGenericArgs (GenericMemberArguments);
168
169                         if (format == Format.WithArgs) {
170                                 result += '(';
171                                 if (MemberArguments != null && MemberArguments.Count > 0) {
172                                         var args = MemberArguments.Select (a => FormatNamespace (a) + a.ToCompleteTypeName ('+') + ModToString (a));
173                                         result += string.Join (",", args);
174                                 }
175                                 result += ')';
176                         }
177
178                         return result;
179                 }
180
181                 public string ToEcmaCref ()
182                 {
183                         var sb = new StringBuilder ();
184                         // Cref type
185                         sb.Append (DescKind.ToString ()[0]);
186                         // Create the rest
187                         ConstructCRef (sb);
188
189                         return sb.ToString ();
190                 }
191
192                 void ConstructCRef (StringBuilder sb)
193                 {
194                         sb.Append (Namespace);
195                         if (DescKind == Kind.Namespace)
196                                 return;
197
198                         sb.Append ('.');
199                         sb.Append (TypeName);
200                         if (GenericTypeArguments != null) {
201                                 sb.Append ('<');
202                                 foreach (var t in GenericTypeArguments)
203                                         t.ConstructCRef (sb);
204                                 sb.Append ('>');
205                         }
206                         if (NestedType != null) {
207                                 sb.Append ('+');
208                                 NestedType.ConstructCRef (sb);
209                         }
210                         if (ArrayDimensions != null && ArrayDimensions.Count > 0) {
211                                 for (int i = 0; i < ArrayDimensions.Count; i++) {
212                                         sb.Append ('[');
213                                         sb.Append (new string (',', ArrayDimensions[i] - 1));
214                                         sb.Append (']');
215                                 }
216                         }
217                         if (DescKind == Kind.Type)
218                                 return;
219
220                         if (MemberArguments != null) {
221                                 
222                         }
223                 }
224
225                 public override string ToString ()
226                 {
227                         return string.Format ("({8}) {0}::{1}{2}{3}{7} {4}{5}{6} {9} {10}",
228                                               Namespace,
229                                               TypeName,
230                                               FormatGenericArgsFull (GenericTypeArguments),
231                                               NestedType != null ? "+" + NestedType.ToString () : string.Empty,
232                                               MemberName ?? string.Empty,
233                                               FormatGenericArgsFull (GenericMemberArguments),
234                                               MemberArguments != null ? "(" + string.Join (",", MemberArguments.Select (m => m.ToString ())) + ")" : string.Empty,
235                                               ArrayDimensions != null && ArrayDimensions.Count > 0 ? ArrayDimensions.Select (dim => "[" + new string (',', dim - 1) + "]").Aggregate (string.Concat) : string.Empty,
236                                               DescKind.ToString ()[0],
237                                               Etc != 0 ? '(' + Etc.ToString () + ')' : string.Empty,
238                                               ExplicitImplMember != null ? "$" + ExplicitImplMember.ToString () : string.Empty);
239                                               
240                 }
241
242                 public override bool Equals (object other)
243                 {
244                         var otherDesc = other as EcmaDesc;
245                         return otherDesc != null && Equals (otherDesc);
246                 }
247
248                 public bool Equals (EcmaDesc other)
249                 {
250                         if (other == null)
251                                 return false;
252
253                         if (NestedType == null ^ other.NestedType == null
254                             || ArrayDimensions == null ^ other.ArrayDimensions == null
255                             || GenericTypeArguments == null ^ other.GenericTypeArguments == null
256                             || GenericMemberArguments == null ^ other.GenericMemberArguments == null
257                             || MemberArguments == null ^ other.MemberArguments == null
258                             || ExplicitImplMember == null ^ other.ExplicitImplMember == null)
259                                 return false;
260
261                         return other != null
262                                 && DescKind == other.DescKind
263                                 && TypeName == other.TypeName
264                                 && Namespace == other.Namespace
265                                 && MemberName == other.MemberName
266                                 && (NestedType == null || NestedType.Equals (other.NestedType))
267                                 && (ArrayDimensions == null || ArrayDimensions.SequenceEqual (other.ArrayDimensions))
268                                 && (GenericTypeArguments == null || GenericTypeArguments.SequenceEqual (other.GenericTypeArguments))
269                                 && (GenericMemberArguments == null || GenericMemberArguments.SequenceEqual (other.GenericMemberArguments))
270                                 && (MemberArguments == null || MemberArguments.SequenceEqual (other.MemberArguments))
271                                 && Etc == other.Etc
272                                 && EtcFilter == other.EtcFilter
273                                 && (ExplicitImplMember == null || ExplicitImplMember.Equals (other.ExplicitImplMember));
274                 }
275
276                 public override int GetHashCode ()
277                 {
278                         return DescKind.GetHashCode ()
279                                 ^ TypeName.GetHashCode ()
280                                 ^ Namespace.GetHashCode ()
281                                 ^ MemberName.GetHashCode ();
282                 }
283
284                 bool What (bool input)
285                 {
286                         if (!input)
287                                 throw new Exception ("Not equal");
288                         return input;
289                 }
290
291                 bool WhatT (bool input)
292                 {
293                         if (input)
294                                 throw new Exception ("Not equal");
295                         return input;
296                 }
297
298                 string FormatNamespace (EcmaDesc desc)
299                 {
300                         return string.IsNullOrEmpty (desc.Namespace) ? string.Empty : desc.Namespace + ".";
301                 }
302
303                 string FormatGenericArgs (IEnumerable<EcmaDesc> genericArgs)
304                 {
305                         return genericArgs != null ? "<" + string.Join (",", genericArgs.Select (t => FormatNamespace (t) + t.ToCompleteTypeName ())) + ">" : string.Empty;
306                 }
307
308                 string FormatGenericArgsFull (IEnumerable<EcmaDesc> genericArgs)
309                 {
310                         return genericArgs != null ? "<" + string.Join (",", genericArgs.Select (t => t.ToString ())) + ">" : string.Empty;
311                 }
312
313                 string ModToString (EcmaDesc desc)
314                 {
315                         switch (desc.DescModifier) {
316                         case Mod.Pointer:
317                                 return "*";
318                         case Mod.Ref:
319                                 return "&";
320                         case Mod.Out:
321                                 return "@";
322                         default:
323                                 return string.Empty;
324                         }
325                 }
326
327                 string FormattedNamespace {
328                         get {
329                                 return !string.IsNullOrEmpty (Namespace) ? Namespace + "." : string.Empty;
330                         }
331                 }
332         }
333 }