2002-07-22 Peter Williams <peterw@ximian.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.CSharp {
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                         REF    = 1,
28                         OUT    = 2,
29                         PARAMS = 4,
30                 }
31
32                 public readonly string   TypeName;
33                 public readonly string   Name;
34                 public readonly Modifier ModFlags;
35                 public Attributes OptAttributes;
36                 public Type parameter_type;
37                 
38                 public Parameter (string type, string name, Modifier mod, Attributes attrs)
39                 {
40                         Name = name;
41                         ModFlags = mod;
42                         TypeName = type;
43                         OptAttributes = attrs;
44                 }
45
46                 // <summary>
47                 //   Resolve is used in method definitions
48                 // </summary>
49                 public bool Resolve (DeclSpace ds, Location l)
50                 {
51                         parameter_type = RootContext.LookupType (ds, TypeName, false, l);
52                         return parameter_type != null;
53                 }
54
55                 // <summary>
56                 //   ResolveAndDefine is used by delegate declarations, because
57                 //   they happen during the initial tree resolution process
58                 // </summary>
59                 public bool ResolveAndDefine (DeclSpace ds)
60                 {
61                         parameter_type = ds.FindType (TypeName);
62                         return parameter_type != null;
63                 }
64                 
65                 public Type ExternalType (DeclSpace ds, Location l)
66                 {
67                         if ((ModFlags & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0){
68                                 string n = parameter_type.FullName + "&";
69
70                                 Type t = RootContext.LookupType (ds, n, false, l);
71
72                                 return t;
73                         }
74                         
75                         return parameter_type;
76                 }
77
78                 public Type ParameterType {
79                         get {
80                                 return parameter_type;
81                         }
82                 }
83                 
84                 public ParameterAttributes Attributes {
85                         get {
86                                 switch (ModFlags){
87                                 case Modifier.NONE:
88                                         return ParameterAttributes.None;
89                                 case Modifier.REF:
90                                         return ParameterAttributes.None;
91                                 case Modifier.OUT:
92                                         return ParameterAttributes.Out;
93                                 case Modifier.PARAMS:
94                                         return 0;
95                                 }
96                                 
97                                 return ParameterAttributes.None;
98                         }
99                 }
100                 
101                 /// <summary>
102                 ///   Returns the signature for this parameter evaluating it on the
103                 ///   @tc context
104                 /// </summary>
105                 public string GetSignature (DeclSpace ds, Location loc)
106                 {
107                         if (parameter_type == null){
108                                 if (!Resolve (ds, loc))
109                                         return null;
110                         }
111
112                         return ExternalType (ds, loc).FullName;
113                 }
114         }
115
116         /// <summary>
117         ///   Represents the methods parameters
118         /// </summary>
119         public class Parameters {
120                 public Parameter [] FixedParameters;
121                 public readonly Parameter ArrayParameter;
122                 string signature;
123                 Type [] types;
124                 Location loc;
125                 
126                 static Parameters empty_parameters;
127                 
128                 public Parameters (Parameter [] fixed_parameters, Parameter array_parameter, Location l)
129                 {
130                         FixedParameters = fixed_parameters;
131                         ArrayParameter  = array_parameter;
132                         loc = l;
133                 }
134
135                 /// <summary>
136                 ///   This is used to reuse a set of empty parameters, because they
137                 ///   are common
138                 /// </summary>
139                 public static Parameters GetEmptyReadOnlyParameters ()
140                 {
141                         if (empty_parameters == null)
142                                 empty_parameters = new Parameters (null, null, Location.Null);
143                         
144                         return empty_parameters;
145                 }
146                 
147                 public bool Empty {
148                         get {
149                                 return (FixedParameters == null) && (ArrayParameter == null);
150                         }
151                 }
152                 
153                 public void ComputeSignature (DeclSpace ds)
154                 {
155                         signature = "";
156                         if (FixedParameters != null){
157                                 for (int i = 0; i < FixedParameters.Length; i++){
158                                         Parameter par = FixedParameters [i];
159                                         
160                                         signature += par.GetSignature (ds, loc);
161                                 }
162                         }
163                         //
164                         // Note: as per the spec, the `params' arguments (ArrayParameter)
165                         // are not used in the signature computation for a method
166                         //
167                 }
168
169                 static void error100 (string name)
170                 {
171                         Report.Error (
172                                 100, "The parameter name `" + name + "' is a duplicate");
173                 }
174                 
175                 public bool VerifyArgs ()
176                 {
177                         int count;
178                         int i, j;
179
180                         if (FixedParameters == null)
181                                 return true;
182                         
183                         count = FixedParameters.Length;
184                         string array_par_name = ArrayParameter != null ? ArrayParameter.Name : null;
185                         for (i = 0; i < count; i++){
186                                 string base_name = FixedParameters [i].Name;
187                                 
188                                 for (j = i + 1; j < count; j++){
189                                         if (base_name != FixedParameters [j].Name)
190                                                 continue;
191                                         error100 (base_name);
192                                         return false;
193                                 }
194
195                                 if (base_name == array_par_name){
196                                         error100 (base_name);
197                                         return false;
198                                 }
199                         }
200                         return true;
201                 }
202                 
203                 /// <summary>
204                 ///    Returns the signature of the Parameters evaluated in
205                 ///    the @tc environment
206                 /// </summary>
207                 public string GetSignature (DeclSpace ds)
208                 {
209                         if (signature == null){
210                                 VerifyArgs ();
211                                 ComputeSignature (ds);
212                         }
213                         
214                         return signature;
215                 }
216                 
217                 /// <summary>
218                 ///    Returns the paramenter information based on the name
219                 /// </summary>
220                 public Parameter GetParameterByName (string name, out int idx)
221                 {
222                         idx = 0;
223                         int i = 0;
224
225                         if (FixedParameters != null){
226                                 foreach (Parameter par in FixedParameters){
227                                         if (par.Name == name){
228                                                 idx = i;
229                                                 return par;
230                                         }
231                                         i++;
232                                 }
233                         }
234
235                         if (ArrayParameter != null){
236                                 if (name == ArrayParameter.Name){
237                                         idx = i;
238                                         return ArrayParameter;
239                                 }
240                         }
241                         
242                         return null;
243                 }
244
245                 bool ComputeParameterTypes (DeclSpace ds)
246                 {
247                         int extra = (ArrayParameter != null) ? 1 : 0;
248                         int i = 0;
249                         int pc;
250
251                         if (FixedParameters == null)
252                                 pc = extra;
253                         else
254                                 pc = extra + FixedParameters.Length;
255
256                         types = new Type [pc];
257                         
258                         if (!VerifyArgs ()){
259                                 FixedParameters = null;
260                                 return false;
261                         }
262
263                         bool failed = false;
264                         if (FixedParameters != null){
265                                 foreach (Parameter p in FixedParameters){
266                                         Type t = null;
267                                         
268                                         if (p.Resolve (ds, loc))
269                                                 t = p.ExternalType (ds, loc);
270                                         else
271                                                 failed = true;
272                                         
273                                         types [i] = t;
274                                         i++;
275                                 }
276                         }
277                         
278                         if (failed)
279                                 types = null;
280                         
281                         if (extra > 0){
282                                 if (ArrayParameter.Resolve (ds, loc))
283                                         types [i] = ArrayParameter.ExternalType (ds, loc);
284                                 else
285                                         return false;
286                         }
287
288                         return true;
289                 }
290
291                 //
292                 // This variant is used by Delegates, because they need to
293                 // resolve/define names, instead of the plain LookupType
294                 //
295                 public bool ComputeAndDefineParameterTypes (DeclSpace ds)
296                 {
297                         int extra = (ArrayParameter != null) ? 1 : 0;
298                         int i = 0;
299                         int pc;
300
301                         if (FixedParameters == null)
302                                 pc = extra;
303                         else
304                                 pc = extra + FixedParameters.Length;
305                         
306                         types = new Type [pc];
307                         
308                         if (!VerifyArgs ()){
309                                 FixedParameters = null;
310                                 return false;
311                         }
312
313                         bool ok_flag = true;
314                         
315                         if (FixedParameters != null){
316                                 foreach (Parameter p in FixedParameters){
317                                         Type t = null;
318                                         
319                                         if (p.ResolveAndDefine (ds))
320                                                 t = p.ExternalType (ds, loc);
321                                         else
322                                                 ok_flag = false;
323                                         
324                                         types [i] = t;
325                                         i++;
326                                 }
327                         }
328                         
329                         if (extra > 0){
330                                 if (ArrayParameter.ResolveAndDefine (ds))
331                                         types [i] = ArrayParameter.ExternalType (ds, loc);
332                                 else
333                                         ok_flag = false;
334                         }
335
336                         //
337                         // invalidate the cached types
338                         //
339                         if (!ok_flag){
340                                 types = null;
341                         }
342                         
343                         return ok_flag;
344                 }
345                 
346                 /// <summary>
347                 ///   Returns the argument types as an array
348                 /// </summary>
349                 static Type [] no_types = new Type [0];
350                 
351                 public Type [] GetParameterInfo (DeclSpace ds)
352                 {
353                         if (types != null)
354                                 return types;
355                         
356                         if (FixedParameters == null && ArrayParameter == null)
357                                 return no_types;
358
359                         if (ComputeParameterTypes (ds) == false){
360                                 types = null;
361                                 return null;
362                         }
363
364                         return types;
365                 }
366
367                 /// <summary>
368                 ///   Returns the type of a given parameter, and stores in the `is_out'
369                 ///   boolean whether this is an out or ref parameter.
370                 ///
371                 ///   Note that the returned type will not contain any dereference in this
372                 ///   case (ie, you get "int" for a ref int instead of "int&"
373                 /// </summary>
374                 public Type GetParameterInfo (DeclSpace ds, int idx, out bool is_out)
375                 {
376                         is_out = false;
377                         
378                         if (!VerifyArgs ()){
379                                 FixedParameters = null;
380                                 return null;
381                         }
382
383                         if (FixedParameters == null && ArrayParameter == null)
384                                 return null;
385                         
386                         if (types == null)
387                                 if (ComputeParameterTypes (ds) == false){
388                                         is_out = false;
389                                         return null;
390                                 }
391
392                         //
393                         // If this is a request for the variable lenght arg.
394                         //
395                         int array_idx = (FixedParameters != null ? FixedParameters.Length : 0);
396                         if (idx == array_idx){
397                                 is_out = false;
398                                 return types [idx];
399                         } 
400
401                         //
402                         // Otherwise, it is a fixed parameter
403                         //
404                         Parameter p = FixedParameters [idx];
405                         is_out = ((p.ModFlags & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0);
406
407                         return p.ParameterType;
408                 }
409
410                 public CallingConventions GetCallingConvention ()
411                 {
412                         // For now this is the only correc thing to do
413                         return CallingConventions.Standard;
414                 }
415         }
416 }
417                 
418         
419