2005-07-13 Maverson Eduardo Schulze Rosa <maverson@gmail.com>
[mono.git] / mcs / mbas / parameter.cs
1 //
2 // parameter.cs: Parameter definition.
3 //
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 //
6 // Licensed under the terms of the GNU GPL
7 //
8 // (C) 2001 Ximian, Inc (http://www.ximian.com)
9 //
10 //
11 //
12 using System;
13 using System.Reflection;
14 using System.Reflection.Emit;
15 using System.Collections;
16
17 namespace Mono.MonoBASIC {
18
19
20         /// <summary>
21         ///   Represents a single method parameter
22         /// </summary>
23         public class Parameter : Attributable {
24                 ParameterBuilder builder;
25                 
26                 [Flags]
27                 public enum Modifier : byte {
28                         NONE    = 0,
29                         VAL     = 0,
30                         REF     = 1,
31 //                      OUT     = 2,
32                         PARAMS  = 4,
33                         // This is a flag which says that it's either REF or OUT.
34                         ISBYREF = 8,
35                         OPTIONAL = 16
36                 }
37
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;
44
45                 public Parameter (Expression type, string name, Modifier mod, Attributes attrs)
46                         : base (attrs)
47                 {
48                         Name = name;
49                         ModFlags = mod;
50                         TypeName = type;
51                         ParameterInitializer = null;
52                         IsOptional = false;
53                 }
54
55                 public Parameter (Expression type, string name, Modifier mod, Attributes attrs, Expression pi)
56                         : base (attrs)
57                 {
58                         Name = name;
59                         ModFlags = mod;
60                         TypeName = type;
61                         ParameterInitializer = pi;
62                         IsOptional = false;
63                 }
64
65                 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb)
66                 {
67                         if (a.Type == TypeManager.marshal_as_attr_type) {
68                                 UnmanagedMarshal marshal = UnmanagedMarshal.DefineUnmanagedMarshal (a.UnmanagedType);
69                                 builder.SetMarshal (marshal);
70                         } else 
71                                 builder.SetCustomAttribute (cb);
72                 }
73
74                 public Parameter (Expression type, string name, Modifier mod, Attributes attrs, Expression pi, bool opt)
75                         : base (attrs)
76                 {
77                         Name = name;
78                         ModFlags = mod;
79                         TypeName = type;
80                         ParameterInitializer = pi;
81                         IsOptional = opt;
82                 }
83
84                 public override AttributeTargets AttributeTargets {
85                         get {
86                                 return AttributeTargets.Parameter;
87                         }
88                 }
89                 
90                 // <summary>
91                 //   Resolve is used in method definitions
92                 // </summary>
93                 public bool Resolve (DeclSpace ds, Location l)
94                 {
95                         parameter_type = ds.ResolveType (TypeName, false, l);
96
97                         if (parameter_type == TypeManager.void_type){
98                                 Report.Error (1536, l, "`void' parameter is not permitted");
99                                 return false;
100                         }
101                         
102                         return parameter_type != null;
103                 }
104
105                 public Type ExternalType (DeclSpace ds, Location l)
106                 {
107                         if ((ModFlags & Parameter.Modifier.ISBYREF) != 0){
108                                 string n = parameter_type.FullName + "&";
109
110                                 Type t = RootContext.LookupType (ds, n, false, l);
111
112                                 return t;
113                         }
114                         
115                         return parameter_type;
116                 }
117
118                 public Type ParameterType {
119                         get {
120                                 return parameter_type;
121                         }
122                 }
123                 
124                 public ParameterAttributes Attributes {
125                         get {
126                                 int flags = ((int) ModFlags) & ~((int) Parameter.Modifier.ISBYREF | (int) Parameter.Modifier.REF);
127                                 switch ((Modifier) flags) {
128                                 case Modifier.NONE:
129                                         return ParameterAttributes.None;
130                                 case Modifier.REF:
131                                         return ParameterAttributes.None;
132 /*
133                                 case Modifier.OUT:
134                                         return ParameterAttributes.Out;
135 */
136                                 case Modifier.OPTIONAL:
137                                         return ParameterAttributes.Optional;
138                                 case Modifier.PARAMS:
139                                         return 0;
140                                 }
141                                 
142                                 return ParameterAttributes.None;
143                         }
144                 }
145                 
146                 /// <summary>
147                 ///   Returns the signature for this parameter evaluating it on the
148                 ///   @tc context
149                 /// </summary>
150                 public string GetSignature (DeclSpace ds, Location loc)
151                 {
152                         if (parameter_type == null){
153                                 if (!Resolve (ds, loc))
154                                         return null;
155                         }
156
157                         return ExternalType (ds, loc).FullName;
158                 }
159
160                 public bool DefineParameter (EmitContext ec, MethodBuilder mb, ConstructorBuilder cb, int index, Location loc)
161                 {
162                         if (mb == null)
163                                 builder = cb.DefineParameter (index, Attributes, Name);
164                         else 
165                                 builder = mb.DefineParameter (index, Attributes, Name);
166
167                         if (ParameterInitializer != null) {
168                                 if (ParameterInitializer is MemberAccess) {
169                                         MemberAccess ma = ParameterInitializer as MemberAccess;
170
171                                         ParameterInitializer = ma.Resolve(ec);
172                                 } else 
173                                         ParameterInitializer = ParameterInitializer.Resolve (ec);
174
175                                 if (ParameterInitializer == null) {
176                                         Report.Error(-1, "Internal error - Non supported argument type in optional parameter");
177                                         return false;
178                                 }
179
180                                 if (parameter_type != ParameterInitializer.Type) {
181                                         Expression conv = Expression.ConvertImplicit (ec, ParameterInitializer, parameter_type, loc);
182                                         if (conv == null) {
183                                                 Report.Error (30439, loc, "Constant expression '" + ParameterInitializer + "' not representable in type '" + parameter_type + "'");
184                                                 return false;
185                                         }
186                                         ParameterInitializer = conv;
187                                 }
188
189                                 if (!(ParameterInitializer is Constant)) {
190                                         Report.Error (30059, loc, "Constant expression is required");
191                                         return false;
192                                 }
193
194                                 builder.SetConstant (((Constant) ParameterInitializer).GetValue());
195
196                         }
197
198                         if (OptAttributes != null)
199                                 OptAttributes.Emit (ec, this);
200                         return true;
201                 }
202         }
203
204         /// <summary>
205         ///   Represents the methods parameters
206         /// </summary>
207         public class Parameters {
208                 public Parameter [] FixedParameters;
209                 public readonly Parameter ArrayParameter;
210                 string signature;
211                 Type [] types;
212                 Location loc;
213                 
214                 static Parameters empty_parameters;
215                 
216                 public Parameters (Parameter [] fixed_parameters, Parameter array_parameter, Location l)
217                 {
218                         FixedParameters = fixed_parameters;
219                         ArrayParameter  = array_parameter;
220                         loc = l;
221                 }
222         
223                 /// <summary>
224                 ///   This is used to reuse a set of empty parameters, because they
225                 ///   are common
226                 /// </summary>
227                 public static Parameters EmptyReadOnlyParameters {
228                         get {
229                                 if (empty_parameters == null)
230                                         empty_parameters = new Parameters (null, null, Location.Null);
231                         
232                                 return empty_parameters;
233                         }
234                 }
235                 
236                 public bool HasOptional()
237                 {
238                         bool res = false;
239
240                         foreach (Parameter p in FixedParameters) 
241                         {
242                                 if (p.IsOptional) 
243                                 {
244                                         res = true;
245                                         break;
246                                 }
247                         }
248                         return (res);
249                 }
250                 
251                 /// <summary>
252                 ///   Returns the number of standard (i.e. non-optional) parameters
253                 /// </summary>          
254                 public int CountStandardParams()
255                 {
256                         int res = 0;
257                         if (FixedParameters == null)
258                                 return 0;
259
260                         foreach (Parameter p in FixedParameters) {
261                                 if (!p.IsOptional)
262                                         res++;
263                         }
264                         return (res);
265                 }
266                 
267                 /// <summary>
268                 ///   Returns the number of optional parameters
269                 /// </summary>          
270                 public int CountOptionalParams()
271                 {
272                         int res = 0;
273                         if (FixedParameters == null)
274                                 return 0;
275                                                         
276                         foreach (Parameter p in FixedParameters) {
277                                 if (p.IsOptional)
278                                         res++;
279                         }
280                         return (res);
281                 }               
282
283                 public Expression GetDefaultValue (int i)
284                 {
285                         Parameter p = FixedParameters[i];
286                         if (p.IsOptional)
287                                 return p.ParameterInitializer;
288                         else
289                                 return null;
290                 }
291
292                 public void AppendParameter (Parameter p)
293                 {
294                         if (FixedParameters != null) 
295                         {
296                                 Parameter [] pa = new Parameter [FixedParameters.Length+1];
297                                 FixedParameters.CopyTo (pa, 0);
298                                 pa[FixedParameters.Length] = p;
299                                 FixedParameters = pa;           
300                         }
301                         else
302                         {
303                                 FixedParameters = new Parameter [1];
304                                 FixedParameters[0] = p;
305                         }
306                 }
307
308                 public void PrependParameter (Parameter p)
309                 {
310                         Parameter [] pa = new Parameter [FixedParameters.Length+1];
311                         FixedParameters.CopyTo (pa, 1);
312                         pa[0] = p;
313                         FixedParameters = pa;           
314                 }
315                 
316                 public Parameters Copy (Location l)
317                 {
318                         Parameters p = new Parameters (null, null, l);
319                         p.FixedParameters = new Parameter[this.FixedParameters.Length];
320                         this.FixedParameters.CopyTo (p.FixedParameters, 0);
321                         
322                         return (p);
323                         
324                 }
325                 
326                 public bool Empty {
327                         get {
328                                 return (FixedParameters == null) && (ArrayParameter == null);
329                         }
330                 }
331                 
332                 public void ComputeSignature (DeclSpace ds)
333                 {
334                         signature = "";
335                         if (FixedParameters != null){
336                                 for (int i = 0; i < FixedParameters.Length; i++){
337                                         Parameter par = FixedParameters [i];
338                                         
339                                         signature += par.GetSignature (ds, loc);
340                                 }
341                         }
342                         //
343                         // Note: as per the spec, the `params' arguments (ArrayParameter)
344                         // are not used in the signature computation for a method
345                         //
346                 }
347
348                 static void Error_DuplicateParameterName (string name)
349                 {
350                         Report.Error (
351                                 100, "The parameter name `" + name + "' is a duplicate");
352                 }
353                 
354                 public bool VerifyArgs ()
355                 {
356                         int count;
357                         int i, j;
358
359                         if (FixedParameters == null)
360                                 return true;
361                         
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;
366                                 
367                                 for (j = i + 1; j < count; j++){
368                                         if (base_name.ToLower () != FixedParameters [j].Name.ToLower ())
369                                                 continue;
370                                         Error_DuplicateParameterName (base_name);
371                                         return false;
372                                 }
373
374                                 if ((array_par_name != null) && (base_name.ToLower () == array_par_name.ToLower ())) {
375                                         Error_DuplicateParameterName (base_name);
376                                         return false;
377                                 }
378                         }
379                         return true;
380                 }
381                 
382                 /// <summary>
383                 ///    Returns the signature of the Parameters evaluated in
384                 ///    the @tc environment
385                 /// </summary>
386                 public string GetSignature (DeclSpace ds)
387                 {
388                         if (signature == null){
389                                 VerifyArgs ();
390                                 ComputeSignature (ds);
391                         }
392                         
393                         return signature;
394                 }
395                 
396                 /// <summary>
397                 ///    Returns the paramenter information based on the name
398                 /// </summary>
399                 public Parameter GetParameterByName (string name, out int idx)
400                 {
401                         idx = 0;
402                         int i = 0;
403
404                         if (FixedParameters != null){
405                                 foreach (Parameter par in FixedParameters){
406                                         if (par.Name.ToLower() == name.ToLower()) {
407                                                 idx = i;
408                                                 return par;
409                                         }
410                                         i++;
411                                 }
412                         }
413
414                         if (ArrayParameter != null){
415                                 if (name.ToLower () == ArrayParameter.Name.ToLower ()) {
416                                         idx = i;
417                                         return ArrayParameter;
418                                 }
419                         }
420                         
421                         return null;
422                 }
423
424                 bool ComputeParameterTypes (DeclSpace ds)
425                 {
426                         int extra = (ArrayParameter != null) ? 1 : 0;
427                         int i = 0;
428                         int pc;
429
430                         if (FixedParameters == null)
431                                 pc = extra;
432                         else
433                                 pc = extra + FixedParameters.Length;
434
435                         types = new Type [pc];
436                         
437                         if (!VerifyArgs ()){
438                                 FixedParameters = null;
439                                 return false;
440                         }
441
442                         bool failed = false;
443                         if (FixedParameters != null){
444                                 foreach (Parameter p in FixedParameters){
445                                         Type t = null;
446                                         
447                                         if (p.Resolve (ds, loc))
448                                                 t = p.ExternalType (ds, loc);
449                                         else
450                                                 failed = true;
451                                         
452                                         types [i] = t;
453                                         i++;
454                                 }
455                         }
456                         
457                         if (extra > 0){
458                                 if (ArrayParameter.Resolve (ds, loc))
459                                         types [i] = ArrayParameter.ExternalType (ds, loc);
460                                 else 
461                                         failed = true;
462                         }
463
464                         if (failed){
465                                 types = null;
466                                 return false;
467                         }
468
469                         return true;
470                 }
471
472                 //
473                 // This variant is used by Delegates, because they need to
474                 // resolve/define names, instead of the plain LookupType
475                 //
476                 public bool ComputeAndDefineParameterTypes (DeclSpace ds)
477                 {
478                         int extra = (ArrayParameter != null) ? 1 : 0;
479                         int i = 0;
480                         int pc;
481
482                         if (FixedParameters == null)
483                                 pc = extra;
484                         else
485                                 pc = extra + FixedParameters.Length;
486                         
487                         types = new Type [pc];
488                         
489                         if (!VerifyArgs ()){
490                                 FixedParameters = null;
491                                 return false;
492                         }
493
494                         bool ok_flag = true;
495                         
496                         if (FixedParameters != null){
497                                 foreach (Parameter p in FixedParameters){
498                                         Type t = null;
499                                         
500                                         if (p.Resolve (ds, loc))
501                                                 t = p.ExternalType (ds, loc);
502                                         else
503                                                 ok_flag = false;
504                                         
505                                         types [i] = t;
506                                         i++;
507                                 }
508                         }
509                         
510                         if (extra > 0){
511                                 if (ArrayParameter.Resolve (ds, loc))
512                                         types [i] = ArrayParameter.ExternalType (ds, loc);
513                                 else
514                                         ok_flag = false;
515                         }
516
517                         //
518                         // invalidate the cached types
519                         //
520                         if (!ok_flag){
521                                 types = null;
522                         }
523                         
524                         return ok_flag;
525                 }
526                 
527                 /// <summary>
528                 ///   Returns the argument types as an array
529                 /// </summary>
530                 static Type [] no_types = new Type [0];
531                 
532                 public Type [] GetParameterInfo (DeclSpace ds)
533                 {
534                         if (types != null)
535                                 return types;
536                         
537                         if (FixedParameters == null && ArrayParameter == null)
538                                 return no_types;
539
540                         if (ComputeParameterTypes (ds) == false){
541                                 types = null;
542                                 return null;
543                         }
544
545                         return types;
546                 }
547
548                 /// <summary>
549                 ///   Returns the type of a given parameter, and stores in the `is_out'
550                 ///   boolean whether this is an out or ref parameter.
551                 ///
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&"
554                 /// </summary>
555                 public Type GetParameterInfo (DeclSpace ds, int idx, out Parameter.Modifier mod)
556                 {
557                         mod = Parameter.Modifier.NONE;
558                         
559                         if (!VerifyArgs ()){
560                                 FixedParameters = null;
561                                 return null;
562                         }
563
564                         if (FixedParameters == null && ArrayParameter == null)
565                                 return null;
566                         
567                         if (types == null)
568                                 if (ComputeParameterTypes (ds) == false)
569                                         return null;
570
571                         //
572                         // If this is a request for the variable lenght arg.
573                         //
574                         int array_idx = (FixedParameters != null ? FixedParameters.Length : 0);
575                         if (idx == array_idx)
576                                 return types [idx];
577
578                         //
579                         // Otherwise, it is a fixed parameter
580                         //
581                         Parameter p = FixedParameters [idx];
582                         mod = p.ModFlags;
583
584                         if ((mod & (Parameter.Modifier.REF )) != 0)
585                                 mod |= Parameter.Modifier.ISBYREF;
586
587                         return p.ParameterType;
588                 }
589
590                 public CallingConventions GetCallingConvention ()
591                 {
592                         // For now this is the only correc thing to do
593                         return CallingConventions.Standard;
594                 }
595                 
596                 public void LabelParameters (EmitContext ec, MethodBase builder, Location loc)
597                 {
598                         //
599                         // Define each type attribute (in/out/ref) and
600                         // the argument names.
601                         //
602                         Parameter [] p = FixedParameters;
603                         int i = 0;
604                         
605                         MethodBuilder mb = null;
606                         ConstructorBuilder cb = null;
607
608                         if (builder is MethodBuilder)
609                                 mb = (MethodBuilder) builder;
610                         else
611                                 cb = (ConstructorBuilder) builder;
612                         
613                         if (p != null){
614                                 for (i = 0; i < p.Length; i++) {
615                                         p [i].DefineParameter (ec, mb, cb, i + 1, loc);
616                                 }
617                         }
618
619                         if (ArrayParameter != null) {
620                                 ParameterBuilder pb;
621                                 Parameter array_param = ArrayParameter;
622                                 
623                                 if (mb == null)
624                                         pb = cb.DefineParameter (i + 1, array_param.Attributes, array_param.Name);
625                                 else
626                                         pb = mb.DefineParameter (i + 1, array_param.Attributes, array_param.Name);
627                                         
628                                 CustomAttributeBuilder a = new CustomAttributeBuilder (TypeManager.cons_param_array_attribute, new object [0]);
629                                 pb.SetCustomAttribute (a);
630                         }
631                 }
632                 
633         }
634 }