Add setting of The WRAP flag in the Wrap property's set method.
[mono.git] / mcs / mcs / support.cs
1 //
2 // support.cs: Support routines to work around the fact that System.Reflection.Emit
3 // can not introspect types that are being constructed
4 //
5 // Author:
6 //   Miguel de Icaza (miguel@ximian.com)
7 //
8 // (C) 2001 Ximian, Inc (http://www.ximian.com)
9 //
10
11 using System;
12 using System.IO;
13 using System.Text;
14 using System.Reflection;
15 using System.Collections;
16 using System.Reflection.Emit;
17 using System.Globalization;
18
19 namespace Mono.CSharp {
20
21         public interface ParameterData {
22                 Type ParameterType (int pos);
23                 int  Count { get; }
24                 string ParameterName (int pos);
25                 string ParameterDesc (int pos);
26                 Parameter.Modifier ParameterModifier (int pos);
27         }
28
29         public class ReflectionParameters : ParameterData {
30                 ParameterInfo [] pi;
31                 bool last_arg_is_params = false;
32                 
33                 public ReflectionParameters (ParameterInfo [] pi)
34                 {
35                         object [] attrs;
36                         
37                         this.pi = pi;
38                         int count = pi.Length-1;
39
40                         if (count >= 0) {
41                                 attrs = pi [count].GetCustomAttributes (TypeManager.param_array_type, true);
42
43                                 if (attrs == null)
44                                         return;
45                                 
46                                 if (attrs.Length == 0)
47                                         return;
48
49                                 last_arg_is_params = true;
50                         }
51                 }
52                        
53                 public Type ParameterType (int pos)
54                 {
55                         if (last_arg_is_params && pos >= pi.Length - 1)
56                                 return pi [pi.Length - 1].ParameterType;
57                         else {
58                                 Type t = pi [pos].ParameterType;
59
60                                 return t;
61                         }
62                 }
63
64                 public string ParameterName (int pos)
65                 {
66                         if (last_arg_is_params && pos >= pi.Length - 1)
67                                 return pi [pi.Length - 1].Name;
68                         else 
69                                 return pi [pos].Name;
70                 }
71
72                 public string ParameterDesc (int pos)
73                 {
74                         StringBuilder sb = new StringBuilder ();
75
76                         if (pi [pos].IsIn)
77                                 sb.Append ("in ");
78
79                         Type partype = ParameterType (pos);
80                         if (partype.IsByRef){
81                                 partype = TypeManager.GetElementType (partype);
82                                 if (pi [pos].IsOut)
83                                         sb.Append ("out ");
84                                 else
85                                         sb.Append ("ref ");
86                         } 
87
88                         if (pos >= pi.Length - 1 && last_arg_is_params)
89                                 sb.Append ("params ");
90                         
91                         sb.Append (TypeManager.CSharpName (partype));
92
93                         return sb.ToString ();
94                         
95                 }
96
97                 public Parameter.Modifier ParameterModifier (int pos)
98                 {
99                         int len = pi.Length;
100
101                         if (pos >= len - 1)
102                                 if (last_arg_is_params)
103                                         return Parameter.Modifier.PARAMS;
104                         
105                         Type t = pi [pos].ParameterType;
106                         if (t.IsByRef){
107                                 if ((pi [pos].Attributes & ParameterAttributes.Out) != 0)
108                                         return Parameter.Modifier.ISBYREF | Parameter.Modifier.OUT;
109                                 else
110                                         return Parameter.Modifier.ISBYREF | Parameter.Modifier.REF;
111                         }
112                         
113                         return Parameter.Modifier.NONE;
114                 }
115
116                 public int Count {
117                         get {
118                                 return pi.Length;
119                         }
120                 }
121                 
122         }
123
124         public class InternalParameters : ParameterData {
125                 Type [] param_types;
126
127                 public readonly Parameters Parameters;
128                 
129                 public InternalParameters (Type [] param_types, Parameters parameters)
130                 {
131                         this.param_types = param_types;
132                         this.Parameters = parameters;
133                 }
134
135                 public InternalParameters (DeclSpace ds, Parameters parameters)
136                         : this (parameters.GetParameterInfo (ds), parameters)
137                 {
138                 }
139
140                 public int Count {
141                         get {
142                                 if (param_types == null)
143                                         return 0;
144
145                                 return param_types.Length;
146                         }
147                 }
148
149                 Parameter GetParameter (int pos)
150                 {
151                         Parameter [] fixed_pars = Parameters.FixedParameters;
152                         if (fixed_pars != null){
153                                 int len = fixed_pars.Length;
154                                 if (pos < len)
155                                         return Parameters.FixedParameters [pos];
156                         }
157
158                         return Parameters.ArrayParameter;
159                 }
160
161                 public Type ParameterType (int pos)
162                 {
163                         if (param_types == null)
164                                 return null;
165
166                         return GetParameter (pos).ExternalType ();
167                 }
168
169
170                 public string ParameterName (int pos)
171                 {
172                         return GetParameter (pos).Name;
173                 }
174
175                 public string ParameterDesc (int pos)
176                 {
177                         string tmp = String.Empty;
178                         Parameter p = GetParameter (pos);
179
180                         //
181                         // We need to and for REF/OUT, because if either is set the
182                         // extra flag ISBYREF will be set as well
183                         //
184                         if ((p.ModFlags & Parameter.Modifier.REF) != 0)
185                                 tmp = "ref ";
186                         else if ((p.ModFlags & Parameter.Modifier.OUT) != 0)
187                                 tmp = "out ";
188                         else if (p.ModFlags == Parameter.Modifier.PARAMS)
189                                 tmp = "params ";
190
191                         Type t = ParameterType (pos);
192
193                         return tmp + TypeManager.CSharpName (t);
194                 }
195
196                 public Parameter.Modifier ParameterModifier (int pos)
197                 {
198                         Parameter.Modifier mod = GetParameter (pos).ModFlags;
199
200                         if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0)
201                                 mod |= Parameter.Modifier.ISBYREF;
202
203                         return mod;
204                 }
205                 
206         }
207
208         class PtrHashtable : Hashtable {
209                 sealed class PtrComparer : IComparer {
210                         private PtrComparer () {}
211                         
212                         public static PtrComparer Instance = new PtrComparer ();
213                         
214                         public int Compare (object x, object y)
215                         {
216                                 if (x == y)
217                                         return 0;
218                                 else
219                                         return 1;
220                         }
221                 }
222                 
223                 public PtrHashtable ()
224                 {
225                         comparer = PtrComparer.Instance;
226                 }
227         }
228
229         //
230         // Compares member infos based on their name and
231         // also allows one argument to be a string
232         //
233         class MemberInfoCompare : IComparer {
234
235                 public int Compare (object a, object b)
236                 {
237                         if (a == null || b == null){
238                                 Console.WriteLine ("Invalid information passed");
239                                 throw new Exception ();
240                         }
241                         
242                         if (a is string)
243                                 return String.Compare ((string) a, ((MemberInfo)b).Name, false, CultureInfo.InvariantCulture);
244
245                         if (b is string)
246                                 return String.Compare (((MemberInfo)a).Name, (string) b, false, CultureInfo.InvariantCulture);
247
248                         return String.Compare (((MemberInfo)a).Name, ((MemberInfo)b).Name, false, CultureInfo.InvariantCulture);
249                 }
250         }
251
252         struct Pair {
253                 public object First;
254                 public object Second;
255                 
256                 public Pair (object f, object s)
257                 {
258                         First = f;
259                         Second = s;
260                 }
261         }
262
263         /// <summary>
264         ///   This is a wrapper around StreamReader which is seekable.
265         /// </summary>
266         public class SeekableStreamReader
267         {
268                 public SeekableStreamReader (StreamReader reader)
269                 {
270                         this.reader = reader;
271                         this.buffer = new char [DefaultCacheSize];
272                 }
273
274                 public SeekableStreamReader (Stream stream, Encoding encoding, bool detect_encoding_from_bytemarks)
275                         : this (new StreamReader (stream, encoding, detect_encoding_from_bytemarks))
276                 { }
277
278                 StreamReader reader;
279
280                 private const int DefaultCacheSize = 1024;
281
282                 char[] buffer;
283                 int buffer_start;
284                 int buffer_size;
285                 int pos;
286
287                 /// <remarks>
288                 ///   The difference to the StreamReader's BaseStream.Position is that this one is reliable; ie. it
289                 //    always reports the correct position and if it's modified, it also takes care of the buffered data.
290                 /// </remarks>
291                 public int Position {
292                         get {
293                                 return buffer_start + pos;
294                         }
295
296                         set {
297                                 // This one is easy: we're modifying the position within our current
298                                 // buffer.
299                                 if ((value >= buffer_start) && (value < buffer_start + buffer_size)) {
300                                         pos = value - buffer_start;
301                                         return;
302                                 }
303
304                                 // Ok, now we need to seek.
305                                 reader.DiscardBufferedData ();
306                                 reader.BaseStream.Position = buffer_start = value;
307                                 buffer_size = pos = 0;
308                         }
309                 }
310
311                 private bool ReadBuffer ()
312                 {
313                         pos = 0;
314                         buffer_start += buffer_size;
315                         buffer_size = reader.Read (buffer, 0, buffer.Length);
316                         return buffer_size > 0;
317                 }
318
319                 public int Peek ()
320                 {
321                         if ((pos >= buffer_size) && !ReadBuffer ())
322                                 return -1;
323
324                         return buffer [pos];
325                 }
326
327                 public int Read ()
328                 {
329                         if ((pos >= buffer_size) && !ReadBuffer ())
330                                 return -1;
331
332                         return buffer [pos++];
333                 }
334         }
335
336         public class DoubleHash {
337                 Hashtable l = new Hashtable ();
338                 const int DEFAULT_INITIAL_BUCKETS = 100;
339                 
340                 public DoubleHash () : this (DEFAULT_INITIAL_BUCKETS) {}
341                 
342                 public DoubleHash (int size)
343                 {
344                         count = size;
345                         buckets = new Entry [size];
346                 }
347                 
348                 int count;
349                 Entry [] buckets;
350                 int size = 0;
351                 
352                 class Entry {
353                         public object key1;
354                         public object key2;
355                         public int hash;
356                         public object value;
357                         public Entry next;
358         
359                         public Entry (object key1, object key2, int hash, object value, Entry next)
360                         {
361                                 this.key1 = key1;
362                                 this.key2 = key2;
363                                 this.hash = hash;
364                                 this.next = next;
365                                 this.value = value;
366                         }
367                 }
368
369                 public bool Lookup (object a, object b, out object res)
370                 {
371                         int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
372                         
373                         for (Entry e = buckets [h % count]; e != null; e = e.next) {
374                                 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b)) {
375                                         res = e.value;
376                                         return true;
377                                 }
378                         }
379                         res = null;
380                         return false;
381                 }
382
383                 public void Insert (object a, object b, object value)
384                 {
385                         // Is it an existing one?
386                 
387                         int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
388                         
389                         for (Entry e = buckets [h % count]; e != null; e = e.next) {
390                                 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b))
391                                         e.value = value;
392                         }
393                         
394                         int bucket = h % count;
395                         buckets [bucket] = new Entry (a, b, h, value, buckets [bucket]);
396                         
397                         // Grow whenever we double in size
398                         if (size++ == count) {
399                                 count <<= 1;
400                                 count ++;
401                                 
402                                 Entry [] newBuckets = new Entry [count];
403                                 foreach (Entry root in buckets) {
404                                         Entry e = root;
405                                         while (e != null) {
406                                                 int newLoc = e.hash % count;
407                                                 Entry n = e.next;
408                                                 e.next = newBuckets [newLoc];
409                                                 newBuckets [newLoc] = e;
410                                                 e = n;
411                                         }
412                                 }
413
414                                 buckets = newBuckets;
415                         }
416                 }
417         }
418 }