remove experimental code in #if false .. #endif
[mono.git] / mcs / mcs / support.cs
old mode 100755 (executable)
new mode 100644 (file)
index bcdd58c..85ede8b
@@ -8,59 +8,99 @@
 // (C) 2001 Ximian, Inc (http://www.ximian.com)
 //
 
-using System.Reflection.Emit;
-using System.Reflection;
 using System;
+using System.IO;
 using System.Text;
+using System.Reflection;
+using System.Collections;
+using System.Reflection.Emit;
+using System.Globalization;
 
 namespace Mono.CSharp {
 
        public interface ParameterData {
                Type ParameterType (int pos);
                int  Count { get; }
+               bool HasParams { get; }
+               string ParameterName (int pos);
                string ParameterDesc (int pos);
                Parameter.Modifier ParameterModifier (int pos);
        }
 
        public class ReflectionParameters : ParameterData {
                ParameterInfo [] pi;
-               bool last_arg_is_params;
+               bool last_arg_is_params = false;
+               bool is_varargs = false;
                
-               public ReflectionParameters (ParameterInfo [] pi)
+               public ReflectionParameters (MethodBase mb)
                {
-                       object [] a;
+                       object [] attrs;
+
+                       ParameterInfo [] pi = mb.GetParameters ();
+                       is_varargs = (mb.CallingConvention & CallingConventions.VarArgs) != 0;
                        
                        this.pi = pi;
-
                        int count = pi.Length-1;
-                       if (count > 0) {
-                               a = pi [count-1].GetCustomAttributes (TypeManager.param_array_type, false);
-                       
-                               if (a != null)
-                                       if (a.Length != 0)
-                                               last_arg_is_params = true;
-                       } 
+
+                       if (count >= 0) {
+                               attrs = pi [count].GetCustomAttributes (TypeManager.param_array_type, true);
+
+                               if (attrs == null)
+                                       return;
+                               
+                               if (attrs.Length == 0)
+                                       return;
+
+                               last_arg_is_params = true;
+                       }
                }
                       
                public Type ParameterType (int pos)
                {
-                       return pi [pos].ParameterType;
+                       if (last_arg_is_params && pos >= pi.Length - 1)
+                               return pi [pi.Length - 1].ParameterType;
+                       else if (is_varargs && pos >= pi.Length)
+                               return TypeManager.runtime_argument_handle_type;
+                       else {
+                               Type t = pi [pos].ParameterType;
+
+                               return t;
+                       }
+               }
+
+               public string ParameterName (int pos)
+               {
+                       if (last_arg_is_params && pos >= pi.Length - 1)
+                               return pi [pi.Length - 1].Name;
+                       else if (is_varargs && pos >= pi.Length)
+                               return "__arglist";
+                       else 
+                               return pi [pos].Name;
                }
 
                public string ParameterDesc (int pos)
                {
-                       StringBuilder sb = new StringBuilder ();
+                       if (is_varargs && pos >= pi.Length)
+                               return "";                      
 
-                       if (pi [pos].IsOut)
-                               sb.Append ("out ");
+                       StringBuilder sb = new StringBuilder ();
 
                        if (pi [pos].IsIn)
                                sb.Append ("in ");
 
-                       if (pos == pi.Length - 1)
+                       Type partype = ParameterType (pos);
+                       if (partype.IsByRef){
+                               partype = TypeManager.GetElementType (partype);
+                               if (pi [pos].IsOut)
+                                       sb.Append ("out ");
+                               else
+                                       sb.Append ("ref ");
+                       } 
+
+                       if (pos >= pi.Length - 1 && last_arg_is_params)
                                sb.Append ("params ");
                        
-                       sb.Append (TypeManager.CSharpName (ParameterType (pos)));
+                       sb.Append (TypeManager.CSharpName (partype));
 
                        return sb.ToString ();
                        
@@ -68,19 +108,31 @@ namespace Mono.CSharp {
 
                public Parameter.Modifier ParameterModifier (int pos)
                {
-                       if (pi [pos].IsOut)
-                               return Parameter.Modifier.OUT;
-
-                       if (pos == pi.Length-1) 
-                               if (last_arg_is_params)
-                                       return Parameter.Modifier.PARAMS;
-
+                       if (last_arg_is_params && pos >= pi.Length - 1)
+                               return Parameter.Modifier.PARAMS;
+                       else if (is_varargs && pos >= pi.Length)
+                               return Parameter.Modifier.ARGLIST;
+                       
+                       Type t = pi [pos].ParameterType;
+                       if (t.IsByRef){
+                               if ((pi [pos].Attributes & ParameterAttributes.Out) != 0)
+                                       return Parameter.Modifier.ISBYREF | Parameter.Modifier.OUT;
+                               else
+                                       return Parameter.Modifier.ISBYREF | Parameter.Modifier.REF;
+                       }
+                       
                        return Parameter.Modifier.NONE;
                }
 
                public int Count {
                        get {
-                               return pi.Length;
+                               return is_varargs ? pi.Length + 1 : pi.Length;
+                       }
+               }
+
+               public bool HasParams {
+                       get {
+                               return this.last_arg_is_params;
                        }
                }
                
@@ -88,60 +140,83 @@ namespace Mono.CSharp {
 
        public class InternalParameters : ParameterData {
                Type [] param_types;
+               bool has_varargs;
+               int count;
 
-               Parameters parameters;
+               public readonly Parameters Parameters;
                
-               public InternalParameters (TypeContainer tc, Parameters parameters)
+               public InternalParameters (Type [] param_types, Parameters parameters)
                {
-                       this.param_types = parameters.GetParameterInfo (tc);
-                       this.parameters = parameters;
+                       this.param_types = param_types;
+                       this.Parameters = parameters;
+
+                       has_varargs = parameters.HasArglist;
+
+                       if (param_types == null)
+                               count = 0;
+                       else
+                               count = param_types.Length;
                }
 
                public int Count {
                        get {
-                               if (param_types == null)
-                                       return 0;
+                               return has_varargs ? count + 1 : count;
+                       }
+               }
 
-                               return param_types.Length;
+               public bool HasParams {
+                       get {
+                               return Parameters.ArrayParameter != null;
+                       }
+               }
+
+               Parameter GetParameter (int pos)
+               {
+                       Parameter [] fixed_pars = Parameters.FixedParameters;
+                       if (fixed_pars != null){
+                               int len = fixed_pars.Length;
+                               if (pos < len)
+                                       return Parameters.FixedParameters [pos];
                        }
+
+                       return Parameters.ArrayParameter;
                }
 
                public Type ParameterType (int pos)
                {
+                       if (has_varargs && pos >= count)
+                               return TypeManager.runtime_argument_handle_type;
+
                        if (param_types == null)
                                return null;
 
-                       int len = parameters.FixedParameters.Length;
-                       Parameter p;
+                       return GetParameter (pos).ExternalType ();
+               }
 
-                       if (pos == len)
-                               p = parameters.ArrayParameter;
-                       else if (pos < len)
-                               p = parameters.FixedParameters [pos];
-                       else {
-                               p = parameters.ArrayParameter;
-                               pos = len;
-                       }
 
-                       //
-                       // Return the internal type.
-                       //
-                       return p.ParameterType;
+               public string ParameterName (int pos)
+               {
+                       if (has_varargs && pos >= count)
+                               return "__arglist";
+
+                       return GetParameter (pos).Name;
                }
 
                public string ParameterDesc (int pos)
                {
-                       string tmp = null;
-                       Parameter p;
+                       if (has_varargs && pos >= count)
+                               return "__arglist";
 
-                       if (pos >= parameters.FixedParameters.Length)
-                               p = parameters.ArrayParameter;
-                       else
-                               p = parameters.FixedParameters [pos];
-                       
-                       if (p.ModFlags == Parameter.Modifier.REF)
+                       string tmp = String.Empty;
+                       Parameter p = GetParameter (pos);
+
+                       //
+                       // We need to and for REF/OUT, because if either is set the
+                       // extra flag ISBYREF will be set as well
+                       //
+                       if ((p.ModFlags & Parameter.Modifier.REF) != 0)
                                tmp = "ref ";
-                       else if (p.ModFlags == Parameter.Modifier.OUT)
+                       else if ((p.ModFlags & Parameter.Modifier.OUT) != 0)
                                tmp = "out ";
                        else if (p.ModFlags == Parameter.Modifier.PARAMS)
                                tmp = "params ";
@@ -153,11 +228,303 @@ namespace Mono.CSharp {
 
                public Parameter.Modifier ParameterModifier (int pos)
                {
-                       if (pos >= parameters.FixedParameters.Length)
-                               return parameters.ArrayParameter.ModFlags;
-                       else
-                               return parameters.FixedParameters [pos].ModFlags;
+                       if (has_varargs && pos >= count)
+                               return Parameter.Modifier.ARGLIST;
+
+                       Parameter.Modifier mod = GetParameter (pos).ModFlags;
+
+                       if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0)
+                               mod |= Parameter.Modifier.ISBYREF;
+
+                       return mod;
                }
                
        }
+
+       class PtrHashtable : Hashtable {
+               sealed class PtrComparer : IComparer {
+                       private PtrComparer () {}
+                       
+                       public static PtrComparer Instance = new PtrComparer ();
+                       
+                       public int Compare (object x, object y)
+                       {
+                               if (x == y)
+                                       return 0;
+                               else
+                                       return 1;
+                       }
+               }
+               
+               public PtrHashtable ()
+               {
+                       comparer = PtrComparer.Instance;
+               }
+       }
+
+       /*
+        * Hashtable whose keys are character arrays with the same length
+        */
+       class CharArrayHashtable : Hashtable {
+               sealed class ArrComparer : IComparer {
+                       private int len;
+
+                       public ArrComparer (int len) {
+                               this.len = len;
+                       }
+
+                       public int Compare (object x, object y)
+                       {
+                               char[] a = (char[])x;
+                               char[] b = (char[])y;
+
+                               for (int i = 0; i < len; ++i)
+                                       if (a [i] != b [i])
+                                               return 1;
+                               return 0;
+                       }
+               }
+
+               private int len;
+
+               protected override int GetHash (Object key)
+               {
+                       char[] arr = (char[])key;
+                       int h = 0;
+
+                       for (int i = 0; i < len; ++i)
+                               h = (h << 5) - h + arr [i];
+
+                       return h;
+               }
+
+               public CharArrayHashtable (int len)
+               {
+                       this.len = len;
+                       comparer = new ArrComparer (len);
+               }
+       }                       
+
+       struct Pair {
+               public object First;
+               public object Second;
+               
+               public Pair (object f, object s)
+               {
+                       First = f;
+                       Second = s;
+               }
+       }
+
+       /// <summary>
+       ///   This is a wrapper around StreamReader which is seekable.
+       /// </summary>
+       public class SeekableStreamReader
+       {
+               public SeekableStreamReader (StreamReader reader)
+               {
+                       this.reader = reader;
+                       this.buffer = new char [DefaultCacheSize];
+                       
+                       // Compute the preamble size
+                       
+                       // Let the StreamWriter autodetect the encoder
+                       reader.Peek ();
+                       
+                       reader.BaseStream.Position = 0;
+                       Encoding enc = reader.CurrentEncoding;
+                       // First of all, get at least a char
+                       
+                       byte[] auxb = new byte [50];
+                       int num_bytes = 0;
+                       int num_chars = 0;
+                       int br = 0;
+                       do {
+                               br = reader.BaseStream.Read (auxb, num_bytes, auxb.Length - num_bytes);
+                               num_bytes += br;
+                               num_chars = enc.GetCharCount (auxb, 0, num_bytes);
+                       }
+                       while (num_chars == 0 && br > 0);
+                       
+                       if (num_chars != 0)
+                       {
+                               // Now, check which bytes at the beginning have no effect in the
+                               // char count
+                               
+                               int p = 0;
+                               while (enc.GetCharCount (auxb, p, num_bytes-p) >= num_chars)
+                                       p++;
+                               
+                               preamble_size = p - 1;
+                               reader.BaseStream.Position = 0;
+                               reader.DiscardBufferedData ();
+                               
+                               buffer_start = preamble_size;
+                       }
+               }
+
+               public SeekableStreamReader (Stream stream, Encoding encoding, bool detect_encoding_from_bytemarks)
+                       : this (new StreamReader (stream, encoding, detect_encoding_from_bytemarks))
+               { }
+
+               StreamReader reader;
+
+               private const int DefaultCacheSize = 1024;
+
+               char[] buffer;
+               int buffer_start;       // in bytes
+               int buffer_size;        // in bytes
+               int char_count;         // count buffer[] valid characters
+               int pos;                // index into buffer[]
+               int preamble_size;
+
+               /// <remarks>
+               ///   The difference to the StreamReader's BaseStream.Position is that this one is reliable; ie. it
+               //    always reports the correct position and if it's modified, it also takes care of the buffered data.
+               /// </remarks>
+               public int Position {
+                       get {
+                               return buffer_start + reader.CurrentEncoding.GetByteCount (buffer, 0, pos);
+                       }
+
+                       set {
+                               // This one is easy: we're modifying the position within our current
+                               // buffer.
+                               if ((value >= buffer_start) && (value < buffer_start + buffer_size)) {
+                                       int byte_offset = value - buffer_start;
+
+                                       // pos is an index into a char
+                                       // buffer so it might be
+                                       // greater than the buffer
+                                       // length now, if the buffer
+                                       // contains multibyte chars
+                                       pos = byte_offset;
+                                       
+                                       // encoded characters can take
+                                       // more than 1 byte length.
+                                       while ((pos > buffer.Length) ||
+                                              reader.CurrentEncoding.GetByteCount (buffer, 0, pos) > byte_offset) {
+                                               pos--;
+                                       }
+                                       
+                                       return;
+                               }
+                               
+                               if (value == 0) // Skip preamble
+                                       value = preamble_size;
+
+                               // Ok, now we need to seek.
+                               reader.DiscardBufferedData ();
+                               reader.BaseStream.Position = buffer_start = value;
+                               char_count = buffer_size = pos = 0;
+                       }
+               }
+
+               private bool ReadBuffer ()
+               {
+                       pos = 0;
+                       buffer_start += buffer_size;
+                       char_count = reader.Read (buffer, 0, buffer.Length);
+                       buffer_size = reader.CurrentEncoding.GetByteCount (buffer, 0, char_count);
+                       return buffer_size > 0;
+               }
+
+               public int Peek ()
+               {
+                       if ((pos >= char_count) && !ReadBuffer ())
+                               return -1;
+
+                       return buffer [pos];
+               }
+
+               public int Read ()
+               {
+                       if ((pos >= char_count) && !ReadBuffer ())
+                               return -1;
+
+                       return buffer [pos++];
+               }
+       }
+
+       public class DoubleHash {
+               const int DEFAULT_INITIAL_BUCKETS = 100;
+               
+               public DoubleHash () : this (DEFAULT_INITIAL_BUCKETS) {}
+               
+               public DoubleHash (int size)
+               {
+                       count = size;
+                       buckets = new Entry [size];
+               }
+               
+               int count;
+               Entry [] buckets;
+               int size = 0;
+               
+               class Entry {
+                       public object key1;
+                       public object key2;
+                       public int hash;
+                       public object value;
+                       public Entry next;
+       
+                       public Entry (object key1, object key2, int hash, object value, Entry next)
+                       {
+                               this.key1 = key1;
+                               this.key2 = key2;
+                               this.hash = hash;
+                               this.next = next;
+                               this.value = value;
+                       }
+               }
+
+               public bool Lookup (object a, object b, out object res)
+               {
+                       int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
+                       
+                       for (Entry e = buckets [h % count]; e != null; e = e.next) {
+                               if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b)) {
+                                       res = e.value;
+                                       return true;
+                               }
+                       }
+                       res = null;
+                       return false;
+               }
+
+               public void Insert (object a, object b, object value)
+               {
+                       // Is it an existing one?
+               
+                       int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
+                       
+                       for (Entry e = buckets [h % count]; e != null; e = e.next) {
+                               if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b))
+                                       e.value = value;
+                       }
+                       
+                       int bucket = h % count;
+                       buckets [bucket] = new Entry (a, b, h, value, buckets [bucket]);
+                       
+                       // Grow whenever we double in size
+                       if (size++ == count) {
+                               count <<= 1;
+                               count ++;
+                               
+                               Entry [] newBuckets = new Entry [count];
+                               foreach (Entry root in buckets) {
+                                       Entry e = root;
+                                       while (e != null) {
+                                               int newLoc = e.hash % count;
+                                               Entry n = e.next;
+                                               e.next = newBuckets [newLoc];
+                                               newBuckets [newLoc] = e;
+                                               e = n;
+                                       }
+                               }
+
+                               buckets = newBuckets;
+                       }
+               }
+       }
 }