2001-09-27 Miguel de Icaza <miguel@ximian.com>
[mono.git] / mcs / mcs / interface.cs
1 //
2 // interface.cs: Interface handler
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 using System.Collections;
12 using System;
13 using System.IO;
14 using System.Reflection;
15 using System.Reflection.Emit;
16
17 namespace CIR {
18
19         public class Interface : DeclSpace {
20                 const MethodAttributes interface_method_attributes =
21                         MethodAttributes.Public |
22                         MethodAttributes.Abstract |
23                         MethodAttributes.HideBySig |
24                         MethodAttributes.NewSlot |
25                         MethodAttributes.Virtual;
26
27                 const MethodAttributes property_attributes =
28                         MethodAttributes.Public |
29                         MethodAttributes.Abstract |
30                         MethodAttributes.HideBySig |
31                         MethodAttributes.NewSlot |
32                         MethodAttributes.SpecialName |
33                         MethodAttributes.Virtual;
34                 
35                 ArrayList bases;
36                 int mod_flags;
37                 
38                 ArrayList defined_method;
39                 ArrayList defined_indexer;
40                 ArrayList defined_events;
41                 ArrayList defined_properties;
42
43                 TypeContainer parent;
44
45                 Attributes OptAttributes;
46                 
47                 // These will happen after the semantic analysis
48                 
49                 // Hashtable defined_indexers;
50                 // Hashtable defined_methods;
51                 
52                 // <summary>
53                 //   Modifiers allowed in a class declaration
54                 // </summary>
55                 public const int AllowedModifiers =
56                         Modifiers.NEW |
57                         Modifiers.PUBLIC |
58                         Modifiers.PROTECTED |
59                         Modifiers.INTERNAL |
60                         Modifiers.PRIVATE;
61
62                 public Interface (TypeContainer parent, string name, int mod, Attributes attrs) : base (name)
63                 {
64                         this.mod_flags = Modifiers.Check (AllowedModifiers, mod, Modifiers.PUBLIC);
65                         this.parent = parent;
66                         OptAttributes = attrs;
67                 }
68
69                 public AdditionResult AddMethod (InterfaceMethod imethod)
70                 {
71                         string name = imethod.Name;
72                         Object value = defined_names [name];
73
74                         if (value != null){
75                                 if (!(value is InterfaceMethod))
76                                         return AdditionResult.NameExists;
77                         } 
78
79                         if (defined_method == null)
80                                 defined_method = new ArrayList ();
81
82                         defined_method.Add (imethod);
83                         if (value == null)
84                                 DefineName (name, imethod);
85                         
86                         return AdditionResult.Success;
87                 }
88
89                 public AdditionResult AddProperty (InterfaceProperty iprop)
90                 {
91                         AdditionResult res;
92                         string name = iprop.Name;
93
94                         if ((res = IsValid (name)) != AdditionResult.Success)
95                                 return res;
96
97                         DefineName (name, iprop);
98
99                         if (defined_properties == null)
100                                 defined_properties = new ArrayList ();
101
102                         defined_properties.Add (iprop);
103                         return AdditionResult.Success;
104                 }
105
106                 public AdditionResult AddEvent (InterfaceEvent ievent)
107                 {
108                         string name = ievent.Name;
109                         AdditionResult res;
110                         
111                         if ((res = IsValid (name)) != AdditionResult.Success)
112                                 return res;
113
114                         DefineName (name, ievent);
115
116                         if (defined_events == null)
117                                 defined_events = new ArrayList ();
118
119                         defined_events.Add (ievent);
120                         return AdditionResult.Success;
121                 }
122
123                 public bool AddIndexer (InterfaceIndexer iindexer)
124                 {
125                         if (defined_indexer == null)
126                                 defined_indexer = new ArrayList ();
127                         
128                         defined_indexer.Add (iindexer);
129                         return true;
130                 }
131                 
132                 public ArrayList InterfaceMethods {
133                         get {
134                                 return defined_method;
135                         }
136                 }
137
138                 public ArrayList InterfaceProperties {
139                         get {
140                                 return defined_properties;
141                         }
142                 }
143
144                 public ArrayList InterfaceEvents {
145                         get {
146                                 return defined_events;
147                         }
148                 }
149
150                 public ArrayList InterfaceIndexers {
151                         get {
152                                 return defined_indexer;
153                         }
154                 }
155
156                 public int ModFlags {
157                         get {
158                                 return mod_flags;
159                         }
160                 }
161                 
162                 public ArrayList Bases {
163                         get {
164                                 return bases;
165                         }
166
167                         set {
168                                 bases = value;
169                         }
170                 }
171
172                 public bool IsTopLevel {
173                         get {
174                                 if (parent != null){
175                                         if (parent.Parent == null)
176                                                 return true;
177                                 }
178                                 return false;
179                         }
180                 }
181
182                 public virtual TypeAttributes InterfaceAttr {
183                         get {
184                                 TypeAttributes x = 0;
185
186                                 if ((mod_flags & Modifiers.PUBLIC) != 0)
187                                         x |= TypeAttributes.Public;
188
189                                 if ((mod_flags & Modifiers.PRIVATE) != 0)
190                                         x |= TypeAttributes.NotPublic;
191
192                                 if (IsTopLevel == false) {
193                                         
194                                         if ((mod_flags & Modifiers.PROTECTED) != 0
195                                             && (mod_flags & Modifiers.INTERNAL) != 0)
196                                                 x |= TypeAttributes.NestedFamORAssem;
197                                         
198                                         if ((mod_flags & Modifiers.PROTECTED) != 0)
199                                                 x |= TypeAttributes.NestedFamily;
200                                         
201                                         if ((mod_flags & Modifiers.INTERNAL) != 0)
202                                                 x |= TypeAttributes.NestedAssembly;
203                                         
204                                 }
205                                 
206                                 if ((mod_flags & Modifiers.ABSTRACT) != 0)
207                                         x |= TypeAttributes.Abstract;
208                                 
209                                 if ((mod_flags & Modifiers.SEALED) != 0)
210                                         x |= TypeAttributes.Sealed;
211
212                                 return x;
213                         }
214                 }
215                 
216                 void Error111 (InterfaceMethod im)
217                 {
218                         parent.RootContext.Report.Error (
219                                 111,
220                                 "Interface `" + Name + "' already contains a definition with the " +
221                                 "same return value and paramenter types for method `" + im.Name + "'");
222                 }
223
224                 //
225                 // Populates the methods in the interface
226                 //
227                 void PopulateMethod (InterfaceMethod im)
228                 {
229                         Type return_type = parent.LookupType (im.ReturnType, true);
230                         Type [] arg_types = im.ParameterTypes (parent);
231                         MethodBuilder mb;
232                         Parameter [] p;
233                         int i;
234                         
235                         //
236                         // Create the method
237                         //
238                         mb = TypeBuilder.DefineMethod (
239                                 im.Name, interface_method_attributes,
240                                 return_type, arg_types);
241                         
242                         //
243                         // Define each type attribute (in/out/ref) and
244                         // the argument names.
245                         //
246                         p = im.Parameters.FixedParameters;
247                         if (p != null){
248                                 for (i = 0; i < p.Length; i++)
249                                         mb.DefineParameter (i + 1, p [i].Attributes, p [i].Name);
250
251                                 if (i != arg_types.Length)
252                                         Console.WriteLine ("Implement the type definition for params");
253                         }
254                 }
255
256                 //
257                 // Populates the properties in the interface
258                 //
259                 void PopulateProperty (InterfaceProperty ip)
260                 {
261                         PropertyBuilder pb;
262                         MethodBuilder mb;
263                         Type prop_type = parent.LookupType (ip.Type, true);
264                         Type [] setter_args = new Type [1];
265
266                         setter_args [0] = prop_type;
267
268                         //
269                         // FIXME: properties are missing the following
270                         // flags: hidebysig newslot specialname
271                         // 
272                         pb = TypeBuilder.DefineProperty (
273                                 ip.Name, PropertyAttributes.None,
274                                 prop_type, null);
275
276                         if (ip.HasGet){
277                                 mb = TypeBuilder.DefineMethod (
278                                         "get_" + ip.Name, property_attributes ,
279                                         prop_type, null);
280
281                                 pb.SetGetMethod (mb);
282                         }
283
284                         if (ip.HasSet){
285                                 setter_args [0] = prop_type;
286
287                                 mb = TypeBuilder.DefineMethod (
288                                         "set_" + ip.Name, property_attributes,
289                                         null, setter_args);
290
291                                 mb.DefineParameter (1, ParameterAttributes.None, "value");
292                                 pb.SetSetMethod (mb);
293                         }
294                 }
295
296                 //
297                 // Populates the events in the interface
298                 //
299                 void PopulateEvent (InterfaceEvent ie)
300                 {
301                         //
302                         // FIXME: We need to do this after delegates have been
303                         // declared or we declare them recursively.
304                         //
305                 }
306
307                 //
308                 // Populates the indexers in the interface
309                 //
310                 void PopulateIndexer (InterfaceIndexer ii)
311                 {
312                         PropertyBuilder pb;
313                         Type prop_type = parent.LookupType (ii.Type, true);
314                         Type [] arg_types = ii.ParameterTypes (parent);
315                         Type [] value_arg_types;
316
317                         //
318                         // Sets up the extra invisible `value' argument for setters.
319                         // 
320                         if (arg_types != null){
321                                 int count = arg_types.Length;
322                                 value_arg_types = new Type [count + 1];
323
324                                 arg_types.CopyTo (value_arg_types, 0);
325                                 value_arg_types [count] = prop_type;
326                         } else {
327                                 value_arg_types = new Type [1];
328
329                                 value_arg_types [1] = prop_type;
330                         }
331
332                         pb = TypeBuilder.DefineProperty (
333                                 "Item", PropertyAttributes.None,
334                                 prop_type, arg_types);
335
336                         if (ii.HasGet){
337                                 MethodBuilder get_item;
338                                 Parameter [] p = ii.Parameters.FixedParameters;
339                                 
340                                 get_item = TypeBuilder.DefineMethod (
341                                         "get_Item", property_attributes, prop_type, arg_types);
342                                 pb.SetGetMethod (get_item);
343
344                                 if (p != null){
345                                         for (int i = 0; i < p.Length; i++)
346                                                 get_item.DefineParameter (
347                                                         i + 1,
348                                                         p [i].Attributes, p [i].Name);
349                                 }
350                         }
351
352                         if (ii.HasSet){
353                                 Parameter [] p = ii.Parameters.FixedParameters;
354                                 MethodBuilder set_item;
355                                 int i = 0;
356                                 
357                                 set_item = TypeBuilder.DefineMethod (
358                                         "set_Item", property_attributes, null, value_arg_types);
359                                 pb.SetSetMethod (set_item);
360
361                                 if (p != null){
362                                         for (; i < p.Length; i++)
363                                                 set_item.DefineParameter (
364                                                         i + 1,
365                                                         p [i].Attributes, p [i].Name);
366                                 }
367                                 set_item.DefineParameter (i + 1, ParameterAttributes.None, "value");
368                         }
369                 }
370
371                 // <summary>
372                 //   Performs the semantic analysis for all the interface members
373                 //   that were declared
374                 // </summary>
375                 bool SemanticAnalysis ()
376                 {
377                         Hashtable methods = new Hashtable ();
378
379                         
380                         if (defined_method != null){
381                                 foreach (InterfaceMethod im in defined_method){
382                                         string sig = im.GetSignature (parent);
383                                         
384                                         //
385                                         // If there was an undefined Type on the signatures
386                                         // 
387                                         if (sig == null)
388                                                 continue;
389                                         
390                                         if (methods [sig] != null){
391                                                 Error111 (im);
392                                                 return false;
393                                         }
394                                 }
395                         }
396
397                         //
398                         // FIXME: Here I should check i
399                         // 
400                         return true;
401                 }
402
403                 // <summary>
404                 //   Performs semantic analysis, and then generates the IL interfaces
405                 // </summary>
406                 public void Populate ()
407                 {
408                         if (!SemanticAnalysis ())
409                                 return;
410
411                         if (defined_method != null){
412                                 foreach (InterfaceMethod im in defined_method)
413                                         PopulateMethod (im);
414                         }
415
416                         if (defined_properties != null){
417                                 foreach (InterfaceProperty ip in defined_properties)
418                                         PopulateProperty (ip);
419                         }
420
421                         if (defined_events != null)
422                                 foreach (InterfaceEvent ie in defined_events)
423                                         PopulateEvent (ie);
424
425                         if (defined_indexer != null)
426                                 foreach (InterfaceIndexer ii in defined_indexer)
427                                         PopulateIndexer (ii);
428                 }
429         }
430
431         public class InterfaceMemberBase {
432                 public readonly string Name;
433                 public readonly bool IsNew;
434                 public Attributes OptAttributes;
435                 
436                 public InterfaceMemberBase (string name, bool is_new, Attributes attrs)
437                 {
438                         Name = name;
439                         IsNew = is_new;
440                         OptAttributes = attrs;
441                 }
442         }
443         
444         public class InterfaceProperty : InterfaceMemberBase {
445                 public readonly bool HasSet;
446                 public readonly bool HasGet;
447                 public readonly string Type;
448                 public readonly string type;
449                 
450                 public InterfaceProperty (string type, string name,
451                                           bool is_new, bool has_get, bool has_set, Attributes attrs)
452                         : base (name, is_new, attrs)
453                 {
454                         Type = type;
455                         HasGet = has_get;
456                         HasSet = has_set;
457                 }
458         }
459
460         public class InterfaceEvent : InterfaceMemberBase {
461                 public readonly string Type;
462                 
463                 public InterfaceEvent (string type, string name, bool is_new, Attributes attrs)
464                         : base (name, is_new, attrs)
465                 {
466                         Type = type;
467                 }
468         }
469         
470         public class InterfaceMethod : InterfaceMemberBase {
471                 public readonly string     ReturnType;
472                 public readonly Parameters Parameters;
473                 
474                 public InterfaceMethod (string return_type, string name, bool is_new, Parameters args, Attributes attrs)
475                         : base (name, is_new, attrs)
476                 {
477                         this.ReturnType = return_type;
478                         this.Parameters = args;
479                 }
480
481                 // <summary>
482                 //   Returns the signature for this interface method
483                 // </summary>
484                 public string GetSignature (TypeContainer tc)
485                 {
486                         Type ret = tc.LookupType (ReturnType, false);
487                         string args = Parameters.GetSignature (tc);
488
489                         if ((ret == null) || (args == null))
490                                 return null;
491                         
492                         return (IsNew ? "new-" : "") + ret.FullName + "(" + args + ")";
493                 }
494
495                 public Type [] ParameterTypes (TypeContainer tc)
496                 {
497                         return Parameters.GetParameterInfo (tc);
498                 }
499         }
500
501         public class InterfaceIndexer : InterfaceMemberBase {
502                 public readonly bool HasGet, HasSet;
503                 public readonly Parameters Parameters;
504                 public readonly string Type;
505                 
506                 public InterfaceIndexer (string type, Parameters args, bool do_get, bool do_set, bool is_new,
507                                          Attributes attrs)
508                         : base ("", is_new, attrs)
509                 {
510                         Type = type;
511                         Parameters = args;
512                         HasGet = do_get;
513                         HasSet = do_set;
514                 }
515
516                 public Type [] ParameterTypes (TypeContainer tc)
517                 {
518                         return Parameters.GetParameterInfo (tc);
519                 }
520         }
521 }