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