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