2006-08-17 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / mbas / parameter.cs
index ab125da9719db7706f4402dfa288341c340e9fd6..5350497e138d4b29c66f3900f85b5ac8eeeed952 100644 (file)
@@ -14,57 +14,94 @@ using System.Reflection;
 using System.Reflection.Emit;
 using System.Collections;
 
-namespace Mono.CSharp {
+namespace Mono.MonoBASIC {
 
 
        /// <summary>
        ///   Represents a single method parameter
        /// </summary>
-       public class Parameter {
+       public class Parameter : Attributable {
+               ParameterBuilder builder;
+               
                [Flags]
                public enum Modifier : byte {
                        NONE    = 0,
+                       VAL     = 0,
                        REF     = 1,
-                       OUT     = 2,
+//                     OUT     = 2,
                        PARAMS  = 4,
                        // This is a flag which says that it's either REF or OUT.
-                       ISBYREF = 8
+                       ISBYREF = 8,
+                       OPTIONAL = 16
                }
 
                public readonly Expression TypeName;
                public readonly Modifier ModFlags;
-               public Attributes OptAttributes;
                public readonly string Name;
                public Type parameter_type;
-               
+               public Expression ParameterInitializer;
+               public readonly bool IsOptional;
+
                public Parameter (Expression type, string name, Modifier mod, Attributes attrs)
+                       : base (attrs)
+               {
+                       Name = name;
+                       ModFlags = mod;
+                       TypeName = type;
+                       ParameterInitializer = null;
+                       IsOptional = false;
+               }
+
+               public Parameter (Expression type, string name, Modifier mod, Attributes attrs, Expression pi)
+                       : base (attrs)
+               {
+                       Name = name;
+                       ModFlags = mod;
+                       TypeName = type;
+                       ParameterInitializer = pi;
+                       IsOptional = false;
+               }
+
+               public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb)
+               {
+                       if (a.Type == TypeManager.marshal_as_attr_type) {
+                               UnmanagedMarshal marshal = UnmanagedMarshal.DefineUnmanagedMarshal (a.UnmanagedType);
+                               builder.SetMarshal (marshal);
+                       } else 
+                               builder.SetCustomAttribute (cb);
+               }
+
+               public Parameter (Expression type, string name, Modifier mod, Attributes attrs, Expression pi, bool opt)
+                       : base (attrs)
                {
                        Name = name;
                        ModFlags = mod;
                        TypeName = type;
-                       OptAttributes = attrs;
+                       ParameterInitializer = pi;
+                       IsOptional = opt;
                }
 
+               public override AttributeTargets AttributeTargets {
+                       get {
+                               return AttributeTargets.Parameter;
+                       }
+               }
+               
                // <summary>
                //   Resolve is used in method definitions
                // </summary>
                public bool Resolve (DeclSpace ds, Location l)
                {
                        parameter_type = ds.ResolveType (TypeName, false, l);
-                       return parameter_type != null;
-               }
 
-               // <summary>
-               //   ResolveAndDefine is used by delegate declarations, because
-               //   they happen during the initial tree resolution process
-               // </summary>
-               public bool ResolveAndDefine (DeclSpace ds)
-               {
-                       // FIXME: Should use something else instead of Location.Null
-                       parameter_type = ds.ResolveType (TypeName, true, Location.Null);
+                       if (parameter_type == TypeManager.void_type){
+                               Report.Error (1536, l, "`void' parameter is not permitted");
+                               return false;
+                       }
+                       
                        return parameter_type != null;
                }
-               
+
                public Type ExternalType (DeclSpace ds, Location l)
                {
                        if ((ModFlags & Parameter.Modifier.ISBYREF) != 0){
@@ -86,13 +123,18 @@ namespace Mono.CSharp {
                
                public ParameterAttributes Attributes {
                        get {
-                               switch (ModFlags){
+                               int flags = ((int) ModFlags) & ~((int) Parameter.Modifier.ISBYREF | (int) Parameter.Modifier.REF);
+                               switch ((Modifier) flags) {
                                case Modifier.NONE:
                                        return ParameterAttributes.None;
                                case Modifier.REF:
                                        return ParameterAttributes.None;
+/*
                                case Modifier.OUT:
                                        return ParameterAttributes.Out;
+*/
+                               case Modifier.OPTIONAL:
+                                       return ParameterAttributes.Optional;
                                case Modifier.PARAMS:
                                        return 0;
                                }
@@ -114,6 +156,49 @@ namespace Mono.CSharp {
 
                        return ExternalType (ds, loc).FullName;
                }
+
+               public bool DefineParameter (EmitContext ec, MethodBuilder mb, ConstructorBuilder cb, int index, Location loc)
+               {
+                       if (mb == null)
+                               builder = cb.DefineParameter (index, Attributes, Name);
+                       else 
+                               builder = mb.DefineParameter (index, Attributes, Name);
+
+                       if (ParameterInitializer != null) {
+                               if (ParameterInitializer is MemberAccess) {
+                                       MemberAccess ma = ParameterInitializer as MemberAccess;
+
+                                       ParameterInitializer = ma.Resolve(ec);
+                               } else 
+                                       ParameterInitializer = ParameterInitializer.Resolve (ec);
+
+                               if (ParameterInitializer == null) {
+                                       Report.Error(-1, "Internal error - Non supported argument type in optional parameter");
+                                       return false;
+                               }
+
+                               if (parameter_type != ParameterInitializer.Type) {
+                                       Expression conv = Expression.ConvertImplicit (ec, ParameterInitializer, parameter_type, loc);
+                                       if (conv == null) {
+                                               Report.Error (30439, loc, "Constant expression '" + ParameterInitializer + "' not representable in type '" + parameter_type + "'");
+                                               return false;
+                                       }
+                                       ParameterInitializer = conv;
+                               }
+
+                               if (!(ParameterInitializer is Constant)) {
+                                       Report.Error (30059, loc, "Constant expression is required");
+                                       return false;
+                               }
+
+                               builder.SetConstant (((Constant) ParameterInitializer).GetValue());
+
+                       }
+
+                       if (OptAttributes != null)
+                               OptAttributes.Emit (ec, this);
+                       return true;
+               }
        }
 
        /// <summary>
@@ -134,7 +219,7 @@ namespace Mono.CSharp {
                        ArrayParameter  = array_parameter;
                        loc = l;
                }
-
+       
                /// <summary>
                ///   This is used to reuse a set of empty parameters, because they
                ///   are common
@@ -148,6 +233,96 @@ namespace Mono.CSharp {
                        }
                }
                
+               public bool HasOptional()
+               {
+                       bool res = false;
+
+                       foreach (Parameter p in FixedParameters) 
+                       {
+                               if (p.IsOptional) 
+                               {
+                                       res = true;
+                                       break;
+                               }
+                       }
+                       return (res);
+               }
+               
+               /// <summary>
+               ///   Returns the number of standard (i.e. non-optional) parameters
+               /// </summary>          
+               public int CountStandardParams()
+               {
+                       int res = 0;
+                       if (FixedParameters == null)
+                               return 0;
+
+                       foreach (Parameter p in FixedParameters) {
+                               if (!p.IsOptional)
+                                       res++;
+                       }
+                       return (res);
+               }
+               
+               /// <summary>
+               ///   Returns the number of optional parameters
+               /// </summary>          
+               public int CountOptionalParams()
+               {
+                       int res = 0;
+                       if (FixedParameters == null)
+                               return 0;
+                                                       
+                       foreach (Parameter p in FixedParameters) {
+                               if (p.IsOptional)
+                                       res++;
+                       }
+                       return (res);
+               }               
+
+               public Expression GetDefaultValue (int i)
+               {
+                       Parameter p = FixedParameters[i];
+                       if (p.IsOptional)
+                               return p.ParameterInitializer;
+                       else
+                               return null;
+               }
+
+               public void AppendParameter (Parameter p)
+               {
+                       if (FixedParameters != null) 
+                       {
+                               Parameter [] pa = new Parameter [FixedParameters.Length+1];
+                               FixedParameters.CopyTo (pa, 0);
+                               pa[FixedParameters.Length] = p;
+                               FixedParameters = pa;           
+                       }
+                       else
+                       {
+                               FixedParameters = new Parameter [1];
+                               FixedParameters[0] = p;
+                       }
+               }
+
+               public void PrependParameter (Parameter p)
+               {
+                       Parameter [] pa = new Parameter [FixedParameters.Length+1];
+                       FixedParameters.CopyTo (pa, 1);
+                       pa[0] = p;
+                       FixedParameters = pa;           
+               }
+               
+               public Parameters Copy (Location l)
+               {
+                       Parameters p = new Parameters (null, null, l);
+                       p.FixedParameters = new Parameter[this.FixedParameters.Length];
+                       this.FixedParameters.CopyTo (p.FixedParameters, 0);
+                       
+                       return (p);
+                       
+               }
+               
                public bool Empty {
                        get {
                                return (FixedParameters == null) && (ArrayParameter == null);
@@ -170,7 +345,7 @@ namespace Mono.CSharp {
                        //
                }
 
-               static void error100 (string name)
+               static void Error_DuplicateParameterName (string name)
                {
                        Report.Error (
                                100, "The parameter name `" + name + "' is a duplicate");
@@ -190,14 +365,14 @@ namespace Mono.CSharp {
                                string base_name = FixedParameters [i].Name;
                                
                                for (j = i + 1; j < count; j++){
-                                       if (base_name != FixedParameters [j].Name)
+                                       if (base_name.ToLower () != FixedParameters [j].Name.ToLower ())
                                                continue;
-                                       error100 (base_name);
+                                       Error_DuplicateParameterName (base_name);
                                        return false;
                                }
 
-                               if (base_name == array_par_name){
-                                       error100 (base_name);
+                               if ((array_par_name != null) && (base_name.ToLower () == array_par_name.ToLower ())) {
+                                       Error_DuplicateParameterName (base_name);
                                        return false;
                                }
                        }
@@ -228,7 +403,7 @@ namespace Mono.CSharp {
 
                        if (FixedParameters != null){
                                foreach (Parameter par in FixedParameters){
-                                       if (par.Name == name){
+                                       if (par.Name.ToLower() == name.ToLower()) {
                                                idx = i;
                                                return par;
                                        }
@@ -237,7 +412,7 @@ namespace Mono.CSharp {
                        }
 
                        if (ArrayParameter != null){
-                               if (name == ArrayParameter.Name){
+                               if (name.ToLower () == ArrayParameter.Name.ToLower ()) {
                                        idx = i;
                                        return ArrayParameter;
                                }
@@ -279,14 +454,16 @@ namespace Mono.CSharp {
                                }
                        }
                        
-                       if (failed)
-                               types = null;
-                       
                        if (extra > 0){
                                if (ArrayParameter.Resolve (ds, loc))
                                        types [i] = ArrayParameter.ExternalType (ds, loc);
-                               else
-                                       return false;
+                               else 
+                                       failed = true;
+                       }
+
+                       if (failed){
+                               types = null;
+                               return false;
                        }
 
                        return true;
@@ -320,7 +497,7 @@ namespace Mono.CSharp {
                                foreach (Parameter p in FixedParameters){
                                        Type t = null;
                                        
-                                       if (p.ResolveAndDefine (ds))
+                                       if (p.Resolve (ds, loc))
                                                t = p.ExternalType (ds, loc);
                                        else
                                                ok_flag = false;
@@ -331,7 +508,7 @@ namespace Mono.CSharp {
                        }
                        
                        if (extra > 0){
-                               if (ArrayParameter.ResolveAndDefine (ds))
+                               if (ArrayParameter.Resolve (ds, loc))
                                        types [i] = ArrayParameter.ExternalType (ds, loc);
                                else
                                        ok_flag = false;
@@ -404,7 +581,7 @@ namespace Mono.CSharp {
                        Parameter p = FixedParameters [idx];
                        mod = p.ModFlags;
 
-                       if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0)
+                       if ((mod & (Parameter.Modifier.REF )) != 0)
                                mod |= Parameter.Modifier.ISBYREF;
 
                        return p.ParameterType;
@@ -415,8 +592,43 @@ namespace Mono.CSharp {
                        // For now this is the only correc thing to do
                        return CallingConventions.Standard;
                }
-       }
-}
                
-       
+               public void LabelParameters (EmitContext ec, MethodBase builder, Location loc)
+               {
+                       //
+                       // Define each type attribute (in/out/ref) and
+                       // the argument names.
+                       //
+                       Parameter [] p = FixedParameters;
+                       int i = 0;
+                       
+                       MethodBuilder mb = null;
+                       ConstructorBuilder cb = null;
+
+                       if (builder is MethodBuilder)
+                               mb = (MethodBuilder) builder;
+                       else
+                               cb = (ConstructorBuilder) builder;
+                       
+                       if (p != null){
+                               for (i = 0; i < p.Length; i++) {
+                                       p [i].DefineParameter (ec, mb, cb, i + 1, loc);
+                               }
+                       }
 
+                       if (ArrayParameter != null) {
+                               ParameterBuilder pb;
+                               Parameter array_param = ArrayParameter;
+                               
+                               if (mb == null)
+                                       pb = cb.DefineParameter (i + 1, array_param.Attributes, array_param.Name);
+                               else
+                                       pb = mb.DefineParameter (i + 1, array_param.Attributes, array_param.Name);
+                                       
+                               CustomAttributeBuilder a = new CustomAttributeBuilder (TypeManager.cons_param_array_attribute, new object [0]);
+                               pb.SetCustomAttribute (a);
+                       }
+               }
+               
+       }
+}