This commit was manufactured by cvs2svn to create branch 'mono-1-0'.
[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 {
24                 [Flags]
25                 public enum Modifier : byte {
26                         NONE    = 0,
27                         VAL     = 0,
28                         REF     = 1,
29                         OUT     = 2,
30                         PARAMS  = 4,
31                         // This is a flag which says that it's either REF or OUT.
32                         ISBYREF = 8,
33                         OPTIONAL = 16
34                 }
35
36                 public readonly Expression TypeName;
37                 public readonly Modifier ModFlags;
38                 public Attributes OptAttributes;
39                 public readonly string Name;
40                 public Type parameter_type;
41                 public readonly Expression ParameterInitializer;
42                 public readonly bool IsOptional;
43
44                 public Parameter (Expression type, string name, Modifier mod, Attributes attrs)
45                 {
46                         Name = name;
47                         ModFlags = mod;
48                         TypeName = type;
49                         OptAttributes = attrs;
50                         ParameterInitializer = null;
51                         IsOptional = false;
52                 }
53
54                 public Parameter (Expression type, string name, Modifier mod, Attributes attrs, Expression pi)
55                 {
56                         Name = name;
57                         ModFlags = mod;
58                         TypeName = type;
59                         OptAttributes = attrs;
60                         ParameterInitializer = pi;
61                         IsOptional = false;
62                 }
63                 
64                 public Parameter (Expression type, string name, Modifier mod, Attributes attrs, Expression pi, bool opt)
65                 {
66                         Name = name;
67                         ModFlags = mod;
68                         TypeName = type;
69                         OptAttributes = attrs;
70                         ParameterInitializer = pi;
71                         IsOptional = opt;
72                 }
73                 
74
75                 // <summary>
76                 //   Resolve is used in method definitions
77                 // </summary>
78                 public bool Resolve (DeclSpace ds, Location l)
79                 {
80                         parameter_type = ds.ResolveType (TypeName, false, l);
81
82                         if (parameter_type == TypeManager.void_type){
83                                 Report.Error (1536, l, "`void' parameter is not permitted");
84                                 return false;
85                         }
86                         
87                         return parameter_type != null;
88                 }
89
90                 public Type ExternalType (DeclSpace ds, Location l)
91                 {
92                         if ((ModFlags & Parameter.Modifier.ISBYREF) != 0){
93                                 string n = parameter_type.FullName + "&";
94
95                                 Type t = RootContext.LookupType (ds, n, false, l);
96
97                                 return t;
98                         }
99                         
100                         return parameter_type;
101                 }
102
103                 public Type ParameterType {
104                         get {
105                                 return parameter_type;
106                         }
107                 }
108                 
109                 public ParameterAttributes Attributes {
110                         get {
111                                 int flags = ((int) ModFlags) & ~((int) Parameter.Modifier.ISBYREF);
112                                 switch ((Modifier) flags) {
113                                 case Modifier.NONE:
114                                         return ParameterAttributes.None;
115                                 case Modifier.REF:
116                                         return ParameterAttributes.None;
117                                 case Modifier.OUT:
118                                         return ParameterAttributes.Out;
119                                 case Modifier.PARAMS:
120                                         return 0;
121                                 }
122                                 
123                                 return ParameterAttributes.None;
124                         }
125                 }
126                 
127                 /// <summary>
128                 ///   Returns the signature for this parameter evaluating it on the
129                 ///   @tc context
130                 /// </summary>
131                 public string GetSignature (DeclSpace ds, Location loc)
132                 {
133                         if (parameter_type == null){
134                                 if (!Resolve (ds, loc))
135                                         return null;
136                         }
137
138                         return ExternalType (ds, loc).FullName;
139                 }
140         }
141
142         /// <summary>
143         ///   Represents the methods parameters
144         /// </summary>
145         public class Parameters {
146                 public Parameter [] FixedParameters;
147                 public readonly Parameter ArrayParameter;
148                 string signature;
149                 Type [] types;
150                 Location loc;
151                 
152                 static Parameters empty_parameters;
153                 
154                 public Parameters (Parameter [] fixed_parameters, Parameter array_parameter, Location l)
155                 {
156                         FixedParameters = fixed_parameters;
157                         ArrayParameter  = array_parameter;
158                         loc = l;
159                 }
160         
161                 /// <summary>
162                 ///   This is used to reuse a set of empty parameters, because they
163                 ///   are common
164                 /// </summary>
165                 public static Parameters EmptyReadOnlyParameters {
166                         get {
167                                 if (empty_parameters == null)
168                                         empty_parameters = new Parameters (null, null, Location.Null);
169                         
170                                 return empty_parameters;
171                         }
172                 }
173                 
174                 public bool HasOptional()
175                 {
176                         bool res = false;
177
178                         foreach (Parameter p in FixedParameters) 
179                         {
180                                 if (p.IsOptional) 
181                                 {
182                                         res = true;
183                                         break;
184                                 }
185                         }
186                         return (res);
187                 }
188                 
189                 /// <summary>
190                 ///   Returns the number of standard (i.e. non-optional) parameters
191                 /// </summary>          
192                 public int CountStandardParams()
193                 {
194                         int res = 0;
195                         if (FixedParameters == null)
196                                 return 0;
197
198                         foreach (Parameter p in FixedParameters) {
199                                 if (!p.IsOptional)
200                                         res++;
201                         }
202                         return (res);
203                 }
204                 
205                 /// <summary>
206                 ///   Returns the number of optional parameters
207                 /// </summary>          
208                 public int CountOptionalParams()
209                 {
210                         int res = 0;
211                         if (FixedParameters == null)
212                                 return 0;
213                                                         
214                         foreach (Parameter p in FixedParameters) {
215                                 if (p.IsOptional)
216                                         res++;
217                         }
218                         return (res);
219                 }               
220
221                 public Expression GetDefaultValue (int i)
222                 {
223                         Parameter p = FixedParameters[i];
224                         if (p.IsOptional)
225                                 return p.ParameterInitializer;
226                         else
227                                 return null;
228                 }
229
230                 public void AppendParameter (Parameter p)
231                 {
232                         if (FixedParameters != null) 
233                         {
234                                 Parameter [] pa = new Parameter [FixedParameters.Length+1];
235                                 FixedParameters.CopyTo (pa, 0);
236                                 pa[FixedParameters.Length] = p;
237                                 FixedParameters = pa;           
238                         }
239                         else
240                         {
241                                 FixedParameters = new Parameter [1];
242                                 FixedParameters[0] = p;
243                         }
244                 }
245
246                 public void PrependParameter (Parameter p)
247                 {
248                         Parameter [] pa = new Parameter [FixedParameters.Length+1];
249                         FixedParameters.CopyTo (pa, 1);
250                         pa[0] = p;
251                         FixedParameters = pa;           
252                 }
253                 
254                 public Parameters Copy (Location l)
255                 {
256                         Parameters p = new Parameters (null, null, l);
257                         p.FixedParameters = new Parameter[this.FixedParameters.Length];
258                         this.FixedParameters.CopyTo (p.FixedParameters, 0);
259                         
260                         return (p);
261                         
262                 }
263                 
264                 public bool Empty {
265                         get {
266                                 return (FixedParameters == null) && (ArrayParameter == null);
267                         }
268                 }
269                 
270                 public void ComputeSignature (DeclSpace ds)
271                 {
272                         signature = "";
273                         if (FixedParameters != null){
274                                 for (int i = 0; i < FixedParameters.Length; i++){
275                                         Parameter par = FixedParameters [i];
276                                         
277                                         signature += par.GetSignature (ds, loc);
278                                 }
279                         }
280                         //
281                         // Note: as per the spec, the `params' arguments (ArrayParameter)
282                         // are not used in the signature computation for a method
283                         //
284                 }
285
286                 static void Error_DuplicateParameterName (string name)
287                 {
288                         Report.Error (
289                                 100, "The parameter name `" + name + "' is a duplicate");
290                 }
291                 
292                 public bool VerifyArgs ()
293                 {
294                         int count;
295                         int i, j;
296
297                         if (FixedParameters == null)
298                                 return true;
299                         
300                         count = FixedParameters.Length;
301                         string array_par_name = ArrayParameter != null ? ArrayParameter.Name : null;
302                         for (i = 0; i < count; i++){
303                                 string base_name = FixedParameters [i].Name;
304                                 
305                                 for (j = i + 1; j < count; j++){
306                                         if (base_name != FixedParameters [j].Name)
307                                                 continue;
308                                         Error_DuplicateParameterName (base_name);
309                                         return false;
310                                 }
311
312                                 if (base_name == array_par_name){
313                                         Error_DuplicateParameterName (base_name);
314                                         return false;
315                                 }
316                         }
317                         return true;
318                 }
319                 
320                 /// <summary>
321                 ///    Returns the signature of the Parameters evaluated in
322                 ///    the @tc environment
323                 /// </summary>
324                 public string GetSignature (DeclSpace ds)
325                 {
326                         if (signature == null){
327                                 VerifyArgs ();
328                                 ComputeSignature (ds);
329                         }
330                         
331                         return signature;
332                 }
333                 
334                 /// <summary>
335                 ///    Returns the paramenter information based on the name
336                 /// </summary>
337                 public Parameter GetParameterByName (string name, out int idx)
338                 {
339                         idx = 0;
340                         int i = 0;
341
342                         if (FixedParameters != null){
343                                 foreach (Parameter par in FixedParameters){
344                                         if (par.Name == name){
345                                                 idx = i;
346                                                 return par;
347                                         }
348                                         i++;
349                                 }
350                         }
351
352                         if (ArrayParameter != null){
353                                 if (name == ArrayParameter.Name){
354                                         idx = i;
355                                         return ArrayParameter;
356                                 }
357                         }
358                         
359                         return null;
360                 }
361
362                 bool ComputeParameterTypes (DeclSpace ds)
363                 {
364                         int extra = (ArrayParameter != null) ? 1 : 0;
365                         int i = 0;
366                         int pc;
367
368                         if (FixedParameters == null)
369                                 pc = extra;
370                         else
371                                 pc = extra + FixedParameters.Length;
372
373                         types = new Type [pc];
374                         
375                         if (!VerifyArgs ()){
376                                 FixedParameters = null;
377                                 return false;
378                         }
379
380                         bool failed = false;
381                         if (FixedParameters != null){
382                                 foreach (Parameter p in FixedParameters){
383                                         Type t = null;
384                                         
385                                         if (p.Resolve (ds, loc))
386                                                 t = p.ExternalType (ds, loc);
387                                         else
388                                                 failed = true;
389                                         
390                                         types [i] = t;
391                                         i++;
392                                 }
393                         }
394                         
395                         if (extra > 0){
396                                 if (ArrayParameter.Resolve (ds, loc))
397                                         types [i] = ArrayParameter.ExternalType (ds, loc);
398                                 else 
399                                         failed = true;
400                         }
401
402                         if (failed){
403                                 types = null;
404                                 return false;
405                         }
406
407                         return true;
408                 }
409
410                 //
411                 // This variant is used by Delegates, because they need to
412                 // resolve/define names, instead of the plain LookupType
413                 //
414                 public bool ComputeAndDefineParameterTypes (DeclSpace ds)
415                 {
416                         int extra = (ArrayParameter != null) ? 1 : 0;
417                         int i = 0;
418                         int pc;
419
420                         if (FixedParameters == null)
421                                 pc = extra;
422                         else
423                                 pc = extra + FixedParameters.Length;
424                         
425                         types = new Type [pc];
426                         
427                         if (!VerifyArgs ()){
428                                 FixedParameters = null;
429                                 return false;
430                         }
431
432                         bool ok_flag = true;
433                         
434                         if (FixedParameters != null){
435                                 foreach (Parameter p in FixedParameters){
436                                         Type t = null;
437                                         
438                                         if (p.Resolve (ds, loc))
439                                                 t = p.ExternalType (ds, loc);
440                                         else
441                                                 ok_flag = false;
442                                         
443                                         types [i] = t;
444                                         i++;
445                                 }
446                         }
447                         
448                         if (extra > 0){
449                                 if (ArrayParameter.Resolve (ds, loc))
450                                         types [i] = ArrayParameter.ExternalType (ds, loc);
451                                 else
452                                         ok_flag = false;
453                         }
454
455                         //
456                         // invalidate the cached types
457                         //
458                         if (!ok_flag){
459                                 types = null;
460                         }
461                         
462                         return ok_flag;
463                 }
464                 
465                 /// <summary>
466                 ///   Returns the argument types as an array
467                 /// </summary>
468                 static Type [] no_types = new Type [0];
469                 
470                 public Type [] GetParameterInfo (DeclSpace ds)
471                 {
472                         if (types != null)
473                                 return types;
474                         
475                         if (FixedParameters == null && ArrayParameter == null)
476                                 return no_types;
477
478                         if (ComputeParameterTypes (ds) == false){
479                                 types = null;
480                                 return null;
481                         }
482
483                         return types;
484                 }
485
486                 /// <summary>
487                 ///   Returns the type of a given parameter, and stores in the `is_out'
488                 ///   boolean whether this is an out or ref parameter.
489                 ///
490                 ///   Note that the returned type will not contain any dereference in this
491                 ///   case (ie, you get "int" for a ref int instead of "int&"
492                 /// </summary>
493                 public Type GetParameterInfo (DeclSpace ds, int idx, out Parameter.Modifier mod)
494                 {
495                         mod = Parameter.Modifier.NONE;
496                         
497                         if (!VerifyArgs ()){
498                                 FixedParameters = null;
499                                 return null;
500                         }
501
502                         if (FixedParameters == null && ArrayParameter == null)
503                                 return null;
504                         
505                         if (types == null)
506                                 if (ComputeParameterTypes (ds) == false)
507                                         return null;
508
509                         //
510                         // If this is a request for the variable lenght arg.
511                         //
512                         int array_idx = (FixedParameters != null ? FixedParameters.Length : 0);
513                         if (idx == array_idx)
514                                 return types [idx];
515
516                         //
517                         // Otherwise, it is a fixed parameter
518                         //
519                         Parameter p = FixedParameters [idx];
520                         mod = p.ModFlags;
521
522                         if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0)
523                                 mod |= Parameter.Modifier.ISBYREF;
524
525                         return p.ParameterType;
526                 }
527
528                 public CallingConventions GetCallingConvention ()
529                 {
530                         // For now this is the only correc thing to do
531                         return CallingConventions.Standard;
532                 }
533         }
534 }