start populating the new System.Web.Configuration_2.0 dir
[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                 bool HasParams { get; }
25                 string ParameterName (int pos);
26                 string ParameterDesc (int pos);
27                 Parameter.Modifier ParameterModifier (int pos);
28                 string GetSignatureForError ();
29         }
30
31         public class ReflectionParameters : ParameterData {
32                 ParameterInfo [] pi;
33                 bool last_arg_is_params = false;
34                 bool is_varargs = false;
35                 
36                 public ReflectionParameters (MethodBase mb)
37                 {
38                         object [] attrs;
39
40                         ParameterInfo [] pi = mb.GetParameters ();
41                         is_varargs = (mb.CallingConvention & CallingConventions.VarArgs) != 0;
42                         
43                         this.pi = pi;
44                         int count = pi.Length-1;
45
46                         if (count >= 0) {
47                                 attrs = pi [count].GetCustomAttributes (TypeManager.param_array_type, true);
48
49                                 if (attrs == null)
50                                         return;
51                                 
52                                 if (attrs.Length == 0)
53                                         return;
54
55                                 last_arg_is_params = true;
56                         }
57                 }
58                 
59                 public string GetSignatureForError ()
60                 {
61                         StringBuilder sb = new StringBuilder ("(");
62                         for (int i = 0; i < pi.Length; ++i) {
63                                 if (i != 0)
64                                         sb.Append (", ");
65                                 sb.Append (ParameterDesc (i));
66                         }
67                         if (is_varargs) {
68                                 if (pi.Length > 0)
69                                         sb.Append (", ");
70                                 sb.Append ("__arglist");
71                         }
72                         sb.Append (')');
73                         return sb.ToString ();
74                 }
75
76                 public Type ParameterType (int pos)
77                 {
78                         if (last_arg_is_params && pos >= pi.Length - 1)
79                                 return pi [pi.Length - 1].ParameterType;
80                         else if (is_varargs && pos >= pi.Length)
81                                 return TypeManager.runtime_argument_handle_type;
82                         else {
83                                 Type t = pi [pos].ParameterType;
84
85                                 return t;
86                         }
87                 }
88
89                 public string ParameterName (int pos)
90                 {
91                         if (last_arg_is_params && pos >= pi.Length - 1)
92                                 return pi [pi.Length - 1].Name;
93                         else if (is_varargs && pos >= pi.Length)
94                                 return "__arglist";
95                         else 
96                                 return pi [pos].Name;
97                 }
98
99                 public string ParameterDesc (int pos)
100                 {
101                         if (is_varargs && pos >= pi.Length)
102                                 return "";                      
103
104                         StringBuilder sb = new StringBuilder ();
105
106                         if (pi [pos].IsIn)
107                                 sb.Append ("in ");
108
109                         Type partype = ParameterType (pos);
110                         if (partype.IsByRef){
111                                 partype = TypeManager.GetElementType (partype);
112                                 if (pi [pos].IsOut)
113                                         sb.Append ("out ");
114                                 else
115                                         sb.Append ("ref ");
116                         } 
117
118                         if (pos >= pi.Length - 1 && last_arg_is_params)
119                                 sb.Append ("params ");
120
121                         sb.Append (TypeManager.CSharpName (partype).Replace ("&", ""));
122
123                         return sb.ToString ();
124                         
125                 }
126
127                 public Parameter.Modifier ParameterModifier (int pos)
128                 {
129                         if (last_arg_is_params && pos >= pi.Length - 1)
130                                 return Parameter.Modifier.PARAMS;
131                         else if (is_varargs && pos >= pi.Length)
132                                 return Parameter.Modifier.ARGLIST;
133                         
134                         Type t = pi [pos].ParameterType;
135                         if (t.IsByRef){
136                                 if ((pi [pos].Attributes & (ParameterAttributes.Out|ParameterAttributes.In)) == ParameterAttributes.Out)
137                                         return Parameter.Modifier.ISBYREF | Parameter.Modifier.OUT;
138                                 else
139                                         return Parameter.Modifier.ISBYREF | Parameter.Modifier.REF;
140                         }
141                         
142                         return Parameter.Modifier.NONE;
143                 }
144
145                 public int Count {
146                         get {
147                                 return is_varargs ? pi.Length + 1 : pi.Length;
148                         }
149                 }
150
151                 public bool HasParams {
152                         get {
153                                 return this.last_arg_is_params;
154                         }
155                 }
156                 
157         }
158
159         public class InternalParameters : ParameterData {
160                 Type [] param_types;
161                 bool has_varargs;
162                 int count;
163
164                 public readonly Parameters Parameters;
165                 
166                 public InternalParameters (Type [] param_types, Parameters parameters)
167                 {
168                         this.param_types = param_types;
169                         this.Parameters = parameters;
170
171                         has_varargs = parameters.HasArglist;
172
173                         if (param_types == null)
174                                 count = 0;
175                         else
176                                 count = param_types.Length;
177                 }
178
179                 public int Count {
180                         get {
181                                 return has_varargs ? count + 1 : count;
182                         }
183                 }
184
185                 public bool HasParams {
186                         get {
187                                 return Parameters.ArrayParameter != null;
188                         }
189                 }
190
191                 Parameter GetParameter (int pos)
192                 {
193                         Parameter [] fixed_pars = Parameters.FixedParameters;
194                         if (fixed_pars != null){
195                                 int len = fixed_pars.Length;
196                                 if (pos < len)
197                                         return Parameters.FixedParameters [pos];
198                         }
199
200                         return Parameters.ArrayParameter;
201                 }
202
203                 public string GetSignatureForError ()
204                 {
205                         StringBuilder sb = new StringBuilder ("(");
206                         for (int i = 0; i < count; ++i) {
207                                 if (i != 0)
208                                         sb.Append (", ");
209                                 sb.Append (ParameterDesc (i));
210                         }
211                         if (has_varargs) {
212                                 if (count > 0)
213                                         sb.Append (", ");
214                                 sb.Append ("__arglist");
215                         }
216                         sb.Append (')');
217                         return sb.ToString ();
218                 }
219
220                 public Type ParameterType (int pos)
221                 {
222                         if (has_varargs && pos >= count)
223                                 return TypeManager.runtime_argument_handle_type;
224
225                         if (param_types == null)
226                                 return null;
227
228                         return GetParameter (pos).ExternalType ();
229                 }
230
231
232                 public string ParameterName (int pos)
233                 {
234                         if (has_varargs && pos >= count)
235                                 return "__arglist";
236
237                         return GetParameter (pos).Name;
238                 }
239
240                 public string ParameterDesc (int pos)
241                 {
242                         if (has_varargs && pos >= count)
243                                 return "__arglist";
244
245                         Type t = ParameterType (pos);
246                         return (ModifierDesc (pos) + " " + TypeManager.CSharpName (t).Replace ("&", "")).TrimStart ();
247                 }
248
249                 public string ModifierDesc (int pos)
250                 {
251                         Parameter p = GetParameter (pos);
252
253                         //
254                         // We need to and for REF/OUT, because if either is set the
255                         // extra flag ISBYREF will be set as well
256                         //
257                         if ((p.ModFlags & Parameter.Modifier.REF) != 0)
258                                 return "ref";
259                         if ((p.ModFlags & Parameter.Modifier.OUT) != 0)
260                                 return "out";
261                         if (p.ModFlags == Parameter.Modifier.PARAMS)
262                                 return "params";
263                         return "";
264                 }
265
266                 public Parameter.Modifier ParameterModifier (int pos)
267                 {
268                         if (has_varargs && pos >= count)
269                                 return Parameter.Modifier.ARGLIST;
270
271                         Parameter.Modifier mod = GetParameter (pos).ModFlags;
272
273                         if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0)
274                                 mod |= Parameter.Modifier.ISBYREF;
275
276                         return mod;
277                 }
278                 
279         }
280
281         class PtrHashtable : Hashtable {
282                 sealed class PtrComparer : IComparer {
283                         private PtrComparer () {}
284                         
285                         public static PtrComparer Instance = new PtrComparer ();
286                         
287                         public int Compare (object x, object y)
288                         {
289                                 if (x == y)
290                                         return 0;
291                                 else
292                                         return 1;
293                         }
294                 }
295                 
296                 public PtrHashtable ()
297                 {
298                         comparer = PtrComparer.Instance;
299                 }
300         }
301
302         /*
303          * Hashtable whose keys are character arrays with the same length
304          */
305         class CharArrayHashtable : Hashtable {
306                 sealed class ArrComparer : IComparer {
307                         private int len;
308
309                         public ArrComparer (int len) {
310                                 this.len = len;
311                         }
312
313                         public int Compare (object x, object y)
314                         {
315                                 char[] a = (char[])x;
316                                 char[] b = (char[])y;
317
318                                 for (int i = 0; i < len; ++i)
319                                         if (a [i] != b [i])
320                                                 return 1;
321                                 return 0;
322                         }
323                 }
324
325                 private int len;
326
327                 protected override int GetHash (Object key)
328                 {
329                         char[] arr = (char[])key;
330                         int h = 0;
331
332                         for (int i = 0; i < len; ++i)
333                                 h = (h << 5) - h + arr [i];
334
335                         return h;
336                 }
337
338                 public CharArrayHashtable (int len)
339                 {
340                         this.len = len;
341                         comparer = new ArrComparer (len);
342                 }
343         }                       
344
345         struct Pair {
346                 public object First;
347                 public object Second;
348                 
349                 public Pair (object f, object s)
350                 {
351                         First = f;
352                         Second = s;
353                 }
354         }
355
356         /// <summary>
357         ///   This is a wrapper around StreamReader which is seekable backwards
358         ///   within a window of around 2048 chars.
359         /// </summary>
360         public class SeekableStreamReader
361         {
362                 public SeekableStreamReader (StreamReader reader)
363                 {
364                         this.reader = reader;
365                         this.buffer = new char [AverageReadLength * 3];
366
367                         // Let the StreamWriter autodetect the encoder
368                         reader.Peek ();
369                 }
370
371                 public SeekableStreamReader (Stream stream, Encoding encoding)
372                         : this (new StreamReader (stream, encoding, true))
373                 { }
374
375                 StreamReader reader;
376
377                 private const int AverageReadLength = 1024;
378
379                 char[] buffer;
380                 int buffer_start;       // in chars
381                 int char_count;         // count buffer[] valid characters
382                 int pos;                // index into buffer[]
383
384                 /// <remarks>
385                 ///   This value corresponds to the current position in a stream of characters.
386                 ///   The StreamReader hides its manipulation of the underlying byte stream and all
387                 ///   character set/decoding issues.  Thus, we cannot use this position to guess at
388                 ///   the corresponding position in the underlying byte stream even though there is
389                 ///   a correlation between them.
390                 /// </remarks>
391                 public int Position {
392                         get { return buffer_start + pos; }
393
394                         set {
395                                 if (value < buffer_start || value > buffer_start + char_count)
396                                         throw new InternalErrorException ("can't seek that far back: " + (pos - value));
397                                 pos = value - buffer_start;
398                         }
399                 }
400
401                 private bool ReadBuffer ()
402                 {
403                         int slack = buffer.Length - char_count;
404                         if (slack <= AverageReadLength / 2) {
405                                 // shift the buffer to make room for AverageReadLength number of characters
406                                 int shift = AverageReadLength - slack;
407                                 Array.Copy (buffer, shift, buffer, 0, char_count - shift);
408                                 pos -= shift;
409                                 char_count -= shift;
410                                 buffer_start += shift;
411                                 slack += shift;         // slack == AverageReadLength
412                         }
413
414                         int chars_read = reader.Read (buffer, char_count, slack);
415                         char_count += chars_read;
416
417                         return pos < char_count;
418                 }
419
420                 public int Peek ()
421                 {
422                         if ((pos >= char_count) && !ReadBuffer ())
423                                 return -1;
424
425                         return buffer [pos];
426                 }
427
428                 public int Read ()
429                 {
430                         if ((pos >= char_count) && !ReadBuffer ())
431                                 return -1;
432
433                         return buffer [pos++];
434                 }
435         }
436
437         public class DoubleHash {
438                 const int DEFAULT_INITIAL_BUCKETS = 100;
439                 
440                 public DoubleHash () : this (DEFAULT_INITIAL_BUCKETS) {}
441                 
442                 public DoubleHash (int size)
443                 {
444                         count = size;
445                         buckets = new Entry [size];
446                 }
447                 
448                 int count;
449                 Entry [] buckets;
450                 int size = 0;
451                 
452                 class Entry {
453                         public object key1;
454                         public object key2;
455                         public int hash;
456                         public object value;
457                         public Entry next;
458         
459                         public Entry (object key1, object key2, int hash, object value, Entry next)
460                         {
461                                 this.key1 = key1;
462                                 this.key2 = key2;
463                                 this.hash = hash;
464                                 this.next = next;
465                                 this.value = value;
466                         }
467                 }
468
469                 public bool Lookup (object a, object b, out object res)
470                 {
471                         int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
472                         
473                         for (Entry e = buckets [h % count]; e != null; e = e.next) {
474                                 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b)) {
475                                         res = e.value;
476                                         return true;
477                                 }
478                         }
479                         res = null;
480                         return false;
481                 }
482
483                 public void Insert (object a, object b, object value)
484                 {
485                         // Is it an existing one?
486                 
487                         int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
488                         
489                         for (Entry e = buckets [h % count]; e != null; e = e.next) {
490                                 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b))
491                                         e.value = value;
492                         }
493                         
494                         int bucket = h % count;
495                         buckets [bucket] = new Entry (a, b, h, value, buckets [bucket]);
496                         
497                         // Grow whenever we double in size
498                         if (size++ == count) {
499                                 count <<= 1;
500                                 count ++;
501                                 
502                                 Entry [] newBuckets = new Entry [count];
503                                 foreach (Entry root in buckets) {
504                                         Entry e = root;
505                                         while (e != null) {
506                                                 int newLoc = e.hash % count;
507                                                 Entry n = e.next;
508                                                 e.next = newBuckets [newLoc];
509                                                 newBuckets [newLoc] = e;
510                                                 e = n;
511                                         }
512                                 }
513
514                                 buckets = newBuckets;
515                         }
516                 }
517         }
518 }