2 // parameter.cs: Parameter definition.
4 // Author: Miguel de Icaza (miguel@gnu.org)
6 // Licensed under the terms of the GNU GPL
8 // (C) 2001 Ximian, Inc (http://www.ximian.com)
13 using System.Reflection;
14 using System.Reflection.Emit;
15 using System.Collections;
17 namespace Mono.MonoBASIC {
21 /// Represents a single method parameter
23 public class Parameter : Attributable {
24 ParameterBuilder builder;
27 public enum Modifier : byte {
33 // This is a flag which says that it's either REF or OUT.
38 public readonly Expression TypeName;
39 public readonly Modifier ModFlags;
40 public readonly string Name;
41 public Type parameter_type;
42 public Expression ParameterInitializer;
43 public readonly bool IsOptional;
45 public Parameter (Expression type, string name, Modifier mod, Attributes attrs)
51 ParameterInitializer = null;
55 public Parameter (Expression type, string name, Modifier mod, Attributes attrs, Expression pi)
61 ParameterInitializer = pi;
65 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb)
67 if (a.Type == TypeManager.marshal_as_attr_type) {
68 UnmanagedMarshal marshal = UnmanagedMarshal.DefineUnmanagedMarshal (a.UnmanagedType);
69 builder.SetMarshal (marshal);
71 builder.SetCustomAttribute (cb);
74 public Parameter (Expression type, string name, Modifier mod, Attributes attrs, Expression pi, bool opt)
80 ParameterInitializer = pi;
84 public override AttributeTargets AttributeTargets {
86 return AttributeTargets.Parameter;
91 // Resolve is used in method definitions
93 public bool Resolve (DeclSpace ds, Location l)
95 parameter_type = ds.ResolveType (TypeName, false, l);
97 if (parameter_type == TypeManager.void_type){
98 Report.Error (1536, l, "`void' parameter is not permitted");
102 return parameter_type != null;
105 public Type ExternalType (DeclSpace ds, Location l)
107 if ((ModFlags & Parameter.Modifier.ISBYREF) != 0){
108 string n = parameter_type.FullName + "&";
110 Type t = RootContext.LookupType (ds, n, false, l);
115 return parameter_type;
118 public Type ParameterType {
120 return parameter_type;
124 public ParameterAttributes Attributes {
126 int flags = ((int) ModFlags) & ~((int) Parameter.Modifier.ISBYREF | (int) Parameter.Modifier.REF);
127 switch ((Modifier) flags) {
129 return ParameterAttributes.None;
131 return ParameterAttributes.None;
134 return ParameterAttributes.Out;
136 case Modifier.OPTIONAL:
137 return ParameterAttributes.Optional;
138 case Modifier.PARAMS:
142 return ParameterAttributes.None;
147 /// Returns the signature for this parameter evaluating it on the
150 public string GetSignature (DeclSpace ds, Location loc)
152 if (parameter_type == null){
153 if (!Resolve (ds, loc))
157 return ExternalType (ds, loc).FullName;
160 public bool DefineParameter (EmitContext ec, MethodBuilder mb, ConstructorBuilder cb, int index, Location loc)
163 builder = cb.DefineParameter (index, Attributes, Name);
165 builder = mb.DefineParameter (index, Attributes, Name);
167 if (ParameterInitializer != null) {
168 if (ParameterInitializer is MemberAccess) {
169 MemberAccess ma = ParameterInitializer as MemberAccess;
171 ParameterInitializer = ma.Resolve(ec);
173 ParameterInitializer = ParameterInitializer.Resolve (ec);
175 if (ParameterInitializer == null) {
176 Report.Error(-1, "Internal error - Non supported argument type in optional parameter");
180 if (parameter_type != ParameterInitializer.Type) {
181 Expression conv = Expression.ConvertImplicit (ec, ParameterInitializer, parameter_type, loc);
183 Report.Error (30439, loc, "Constant expression '" + ParameterInitializer + "' not representable in type '" + parameter_type + "'");
186 ParameterInitializer = conv;
189 if (!(ParameterInitializer is Constant)) {
190 Report.Error (30059, loc, "Constant expression is required");
194 builder.SetConstant (((Constant) ParameterInitializer).GetValue());
198 if (OptAttributes != null)
199 OptAttributes.Emit (ec, this);
205 /// Represents the methods parameters
207 public class Parameters {
208 public Parameter [] FixedParameters;
209 public readonly Parameter ArrayParameter;
214 static Parameters empty_parameters;
216 public Parameters (Parameter [] fixed_parameters, Parameter array_parameter, Location l)
218 FixedParameters = fixed_parameters;
219 ArrayParameter = array_parameter;
224 /// This is used to reuse a set of empty parameters, because they
227 public static Parameters EmptyReadOnlyParameters {
229 if (empty_parameters == null)
230 empty_parameters = new Parameters (null, null, Location.Null);
232 return empty_parameters;
236 public bool HasOptional()
240 foreach (Parameter p in FixedParameters)
252 /// Returns the number of standard (i.e. non-optional) parameters
254 public int CountStandardParams()
257 if (FixedParameters == null)
260 foreach (Parameter p in FixedParameters) {
268 /// Returns the number of optional parameters
270 public int CountOptionalParams()
273 if (FixedParameters == null)
276 foreach (Parameter p in FixedParameters) {
283 public Expression GetDefaultValue (int i)
285 Parameter p = FixedParameters[i];
287 return p.ParameterInitializer;
292 public void AppendParameter (Parameter p)
294 if (FixedParameters != null)
296 Parameter [] pa = new Parameter [FixedParameters.Length+1];
297 FixedParameters.CopyTo (pa, 0);
298 pa[FixedParameters.Length] = p;
299 FixedParameters = pa;
303 FixedParameters = new Parameter [1];
304 FixedParameters[0] = p;
308 public void PrependParameter (Parameter p)
310 Parameter [] pa = new Parameter [FixedParameters.Length+1];
311 FixedParameters.CopyTo (pa, 1);
313 FixedParameters = pa;
316 public Parameters Copy (Location l)
318 Parameters p = new Parameters (null, null, l);
319 p.FixedParameters = new Parameter[this.FixedParameters.Length];
320 this.FixedParameters.CopyTo (p.FixedParameters, 0);
328 return (FixedParameters == null) && (ArrayParameter == null);
332 public void ComputeSignature (DeclSpace ds)
335 if (FixedParameters != null){
336 for (int i = 0; i < FixedParameters.Length; i++){
337 Parameter par = FixedParameters [i];
339 signature += par.GetSignature (ds, loc);
343 // Note: as per the spec, the `params' arguments (ArrayParameter)
344 // are not used in the signature computation for a method
348 static void Error_DuplicateParameterName (string name)
351 100, "The parameter name `" + name + "' is a duplicate");
354 public bool VerifyArgs ()
359 if (FixedParameters == null)
362 count = FixedParameters.Length;
363 string array_par_name = ArrayParameter != null ? ArrayParameter.Name : null;
364 for (i = 0; i < count; i++){
365 string base_name = FixedParameters [i].Name;
367 for (j = i + 1; j < count; j++){
368 if (base_name.ToLower () != FixedParameters [j].Name.ToLower ())
370 Error_DuplicateParameterName (base_name);
374 if ((array_par_name != null) && (base_name.ToLower () == array_par_name.ToLower ())) {
375 Error_DuplicateParameterName (base_name);
383 /// Returns the signature of the Parameters evaluated in
384 /// the @tc environment
386 public string GetSignature (DeclSpace ds)
388 if (signature == null){
390 ComputeSignature (ds);
397 /// Returns the paramenter information based on the name
399 public Parameter GetParameterByName (string name, out int idx)
404 if (FixedParameters != null){
405 foreach (Parameter par in FixedParameters){
406 if (par.Name.ToLower() == name.ToLower()) {
414 if (ArrayParameter != null){
415 if (name.ToLower () == ArrayParameter.Name.ToLower ()) {
417 return ArrayParameter;
424 bool ComputeParameterTypes (DeclSpace ds)
426 int extra = (ArrayParameter != null) ? 1 : 0;
430 if (FixedParameters == null)
433 pc = extra + FixedParameters.Length;
435 types = new Type [pc];
438 FixedParameters = null;
443 if (FixedParameters != null){
444 foreach (Parameter p in FixedParameters){
447 if (p.Resolve (ds, loc))
448 t = p.ExternalType (ds, loc);
458 if (ArrayParameter.Resolve (ds, loc))
459 types [i] = ArrayParameter.ExternalType (ds, loc);
473 // This variant is used by Delegates, because they need to
474 // resolve/define names, instead of the plain LookupType
476 public bool ComputeAndDefineParameterTypes (DeclSpace ds)
478 int extra = (ArrayParameter != null) ? 1 : 0;
482 if (FixedParameters == null)
485 pc = extra + FixedParameters.Length;
487 types = new Type [pc];
490 FixedParameters = null;
496 if (FixedParameters != null){
497 foreach (Parameter p in FixedParameters){
500 if (p.Resolve (ds, loc))
501 t = p.ExternalType (ds, loc);
511 if (ArrayParameter.Resolve (ds, loc))
512 types [i] = ArrayParameter.ExternalType (ds, loc);
518 // invalidate the cached types
528 /// Returns the argument types as an array
530 static Type [] no_types = new Type [0];
532 public Type [] GetParameterInfo (DeclSpace ds)
537 if (FixedParameters == null && ArrayParameter == null)
540 if (ComputeParameterTypes (ds) == false){
549 /// Returns the type of a given parameter, and stores in the `is_out'
550 /// boolean whether this is an out or ref parameter.
552 /// Note that the returned type will not contain any dereference in this
553 /// case (ie, you get "int" for a ref int instead of "int&"
555 public Type GetParameterInfo (DeclSpace ds, int idx, out Parameter.Modifier mod)
557 mod = Parameter.Modifier.NONE;
560 FixedParameters = null;
564 if (FixedParameters == null && ArrayParameter == null)
568 if (ComputeParameterTypes (ds) == false)
572 // If this is a request for the variable lenght arg.
574 int array_idx = (FixedParameters != null ? FixedParameters.Length : 0);
575 if (idx == array_idx)
579 // Otherwise, it is a fixed parameter
581 Parameter p = FixedParameters [idx];
584 if ((mod & (Parameter.Modifier.REF )) != 0)
585 mod |= Parameter.Modifier.ISBYREF;
587 return p.ParameterType;
590 public CallingConventions GetCallingConvention ()
592 // For now this is the only correc thing to do
593 return CallingConventions.Standard;
596 public void LabelParameters (EmitContext ec, MethodBase builder, Location loc)
599 // Define each type attribute (in/out/ref) and
600 // the argument names.
602 Parameter [] p = FixedParameters;
605 MethodBuilder mb = null;
606 ConstructorBuilder cb = null;
608 if (builder is MethodBuilder)
609 mb = (MethodBuilder) builder;
611 cb = (ConstructorBuilder) builder;
614 for (i = 0; i < p.Length; i++) {
615 p [i].DefineParameter (ec, mb, cb, i + 1, loc);
619 if (ArrayParameter != null) {
621 Parameter array_param = ArrayParameter;
624 pb = cb.DefineParameter (i + 1, array_param.Attributes, array_param.Name);
626 pb = mb.DefineParameter (i + 1, array_param.Attributes, array_param.Name);
628 CustomAttributeBuilder a = new CustomAttributeBuilder (TypeManager.cons_param_array_attribute, new object [0]);
629 pb.SetCustomAttribute (a);