Work to get foreach working and analyzed.
[mono.git] / mcs / mcs / rootcontext.cs
1 //
2 // rootcontext.cs: keeps track of our tree representation, and assemblies loaded.
3 //
4 // Author: Miguel de Icaza (miguel@ximian.com)
5 //
6 // Licensed under the terms of the GNU GPL
7 //
8 // (C) 2001 Ximian, Inc (http://www.ximian.com)
9
10 using System;
11 using System.Collections;
12 using System.Reflection;
13 using System.Reflection.Emit;
14 using System.Diagnostics;
15
16 namespace CIR {
17
18         public class RootContext {
19
20                 //
21                 // Contains the parsed tree
22                 //
23                 Tree tree;
24
25                 //
26                 // Contains loaded assemblies and our generated code as we go.
27                 //
28                 public TypeManager TypeManager;
29
30                 //
31                 // The System.Reflection.Emit CodeGenerator
32                 //
33                 CodeGen cg;
34
35                 //
36                 // The module builder pointer
37                 //
38                 ModuleBuilder mb;
39
40                 //
41                 // Whether we are being linked against the standard libraries.
42                 // This is only used to tell whether `System.Object' should
43                 // have a parent or not.
44                 //
45                 bool stdlib = true;
46
47                 //
48                 // This keeps track of the order in which classes were defined
49                 // so that we can poulate them in that order.
50                 //
51                 // Order is important, because we need to be able to tell by
52                 // examining the parent's list of methods which ones are virtual
53                 // or abstract as well as the parent names (to implement new, 
54                 // override).
55                 //
56                 ArrayList type_container_resolve_order;
57                 ArrayList interface_resolve_order;
58                 
59                 public RootContext ()
60                 {
61                         tree = new Tree (this);
62                         TypeManager = new TypeManager ();
63                 }
64
65                 public Tree Tree {
66                         get {
67                                 return tree;
68                         }
69                 }
70
71                 public CodeGen CodeGen {
72                         get {
73                                 return cg;
74                         }
75
76                         set {
77                                 //
78                                 // Temporary hack, we should probably
79                                 // intialize `cg' rather than depending on
80                                 // external initialization of it.
81                                 //
82                                 cg = value;
83                                 mb = cg.ModuleBuilder;
84                         }
85                 }
86
87                 //
88                 // Returns the Type that represents the interface whose name
89                 // is `name'.
90                 //
91                 
92                 Type GetInterfaceTypeByName (string name)
93                 {
94                         Interface parent;
95                         Type t = TypeManager.LookupType (name);
96
97                         if (t != null) {
98
99                                 if (t.IsInterface)
100                                         return t;
101                                 
102                                 string cause;
103                                 
104                                 if (t.IsValueType)
105                                         cause = "is a struct";
106                                 else if (t.IsClass) 
107                                         cause = "is a class";
108                                 else
109                                         cause = "Should not happen.";
110
111                                 Report.Error (527, "`"+name+"' " + cause + ", need an interface instead");
112                                 
113                                 return null;
114                         }
115
116                         parent = (Interface) tree.Interfaces [name];
117                         if (parent == null){
118                                 string cause = "is undefined";
119                                 
120                                 if (tree.Classes [name] != null)
121                                         cause = "is a class";
122                                 else if (tree.Structs [name] != null)
123                                         cause = "is a struct";
124                                 
125                                 Report.Error (527, "`"+name+"' " + cause + ", need an interface instead");
126                                 return null;
127                         }
128
129                         t = CreateInterface ((Interface) parent);
130                         if (t == null){
131                                 Report.Error (529,
132                                               "Inherited interface `"+name+"' is circular");
133                                 return null;
134                         }
135
136                         return t;
137                 }
138                 
139                 //
140                 // Returns the list of interfaces that this interface implements
141                 // Or null if it does not implement any interface.
142                 //
143                 // Sets the error boolean accoringly.
144                 //
145                 Type [] GetInterfaceBases (Interface iface, out bool error)
146                 {
147                         ArrayList bases = iface.Bases;
148                         Type [] tbases;
149                         int i;
150
151                         error = false;
152                         if (bases == null)
153                                 return null;
154                         
155                         tbases = new Type [bases.Count];
156                         i = 0;
157
158                         foreach (string name in iface.Bases){
159                                 Type t;
160
161                                 t = GetInterfaceTypeByName (name);
162                                 if (t == null){
163                                         error = true;
164                                         return null;
165                                 }
166                                 
167                                 tbases [i++] = t;
168                         }
169
170                         return tbases;
171                 }
172                 
173                 //
174                 // Creates the Interface @iface using the ModuleBuilder
175                 //
176                 // TODO:
177                 //   Rework the way we recurse, because for recursive
178                 //   definitions of interfaces (A:B and B:A) we report the
179                 //   error twice, rather than once.  
180                 //
181                 TypeBuilder CreateInterface (Interface iface)
182                 {
183                         TypeBuilder tb = iface.TypeBuilder;
184                         Type [] ifaces;
185                         string name;
186                         bool error;
187
188                         if (tb != null)
189                                 return tb;
190                         
191                         if (iface.InTransit)
192                                 return null;
193                         
194                         iface.InTransit = true;
195
196                         name = iface.Name;
197
198                         ifaces = GetInterfaceBases (iface, out error);
199
200                         if (error)
201                                 return null;
202
203                         tb = mb.DefineType (name,
204                                             TypeAttributes.Interface |
205                                             iface.InterfaceAttr |
206                                             TypeAttributes.Abstract,
207                                             null,   // Parent Type
208                                             ifaces);
209                         iface.TypeBuilder = tb;
210
211                         interface_resolve_order.Add (iface);
212                         
213                         TypeManager.AddUserInterface (name, tb, iface);
214
215                         iface.InTransit = false;
216
217                         return tb;
218                 }
219
220                 string MakeFQN (string nsn, string name)
221                 {
222                         string prefix = (nsn == "" ? "" : nsn + ".");
223
224                         return prefix + name;
225                 }
226                        
227                 Type LookupInterfaceOrClass (string ns, string name, bool is_class, out bool error)
228                 {
229                         TypeContainer parent;
230                         Type t;
231
232                         error = false;
233                         name = MakeFQN (ns, name);
234                         
235                         t  = TypeManager.LookupType (name);
236                         if (t != null)
237                                 return t;
238
239                         if (is_class){
240                                 parent = (Class) tree.Classes [name];
241                         } else {
242                                 parent = (Struct) tree.Structs [name];
243                         }
244
245                         if (parent != null){
246                                 t = CreateType (parent, is_class);
247                                 if (t == null){
248                                         Report.Error (146, "Class definition is circular: `"+name+"'");
249                                         error = true;
250                                         return null;
251                                 }
252
253                                 return t;
254                         }
255
256                         return null;
257                 }
258                 
259                 //
260                 // returns the type for an interface or a class, this will recursively
261                 // try to define the types that it depends on.
262                 //
263                 Type GetInterfaceOrClass (TypeContainer tc, string name, bool is_class)
264                 {
265                         Type t;
266                         bool error;
267
268                         //
269                         // Attempt to lookup the class on our namespace
270                         //
271                         t = LookupInterfaceOrClass (tc.Namespace.Name, name, is_class, out error);
272                         if (error)
273                                 return null;
274                         
275                         if (t != null) 
276                                 return t;
277
278                         //
279                         // Attempt to lookup the class on any of the `using'
280                         // namespaces
281                         //
282
283                         for (Namespace ns = tc.Namespace; ns != null; ns = ns.Parent){
284                                 ArrayList using_list = ns.UsingTable;
285
286                                 if (using_list == null)
287                                         continue;
288
289                                 foreach (string n in using_list){
290                                         t = LookupInterfaceOrClass (n, name, is_class, out error);
291                                         if (error)
292                                                 return null;
293
294                                         if (t != null)
295                                                 return t;
296                                 }
297                                 
298                         }
299                         Report.Error (246, "Can not find type `"+name+"'");
300                         return null;
301                 }
302
303                 //
304                 // This function computes the Base class and also the
305                 // list of interfaces that the class or struct @c implements.
306                 //
307                 // The return value is an array (might be null) of
308                 // interfaces implemented (as Types).
309                 //
310                 // The @parent argument is set to the parent object or null
311                 // if this is `System.Object'. 
312                 //
313                 Type [] GetClassBases (TypeContainer tc, bool is_class, out Type parent, out bool error)
314                 {
315                         ArrayList bases = tc.Bases;
316                         int count;
317                         int start, j, i;
318                         
319                         error = false;
320
321                         if (is_class)
322                                 parent = null;
323                         else
324                                 parent = TypeManager.value_type;
325
326                         if (bases == null){
327                                 if (is_class){
328                                         if (stdlib)
329                                                 parent = TypeManager.object_type;
330                                         else if (tc.Name != "System.Object")
331                                                 parent = TypeManager.object_type;
332                                 } else {
333                                         //
334                                         // If we are compiling our runtime,
335                                         // and we are defining ValueType, then our
336                                         // parent is `System.Object'.
337                                         //
338                                         if (!stdlib && tc. Name == "System.ValueType")
339                                                 parent = TypeManager.object_type;
340                                 }
341
342                                 return null;
343                         }
344
345                         //
346                         // Bases should be null if there are no bases at all
347                         //
348                         count = bases.Count;
349                         Debug.Assert (count > 0);
350
351                         if (is_class){
352                                 string name = (string) bases [0];
353                                 Type first = GetInterfaceOrClass (tc, name, is_class);
354
355                                 if (first == null){
356                                         error = true;
357                                         return null;
358                                 }
359                                 
360                                 if (first.IsClass){
361                                         parent = first;
362                                         start = 1;
363                                 } else {
364                                         parent = TypeManager.object_type;
365                                         start = 0;
366                                 }
367                         } else {
368                                 start = 0;
369                         }
370
371                         Type [] ifaces = new Type [count-start];
372                         
373                         for (i = start, j = 0; i < count; i++, j++){
374                                 string name = (string) bases [i];
375                                 Type t = GetInterfaceOrClass (tc, name, is_class);
376
377                                 if (t == null){
378                                         error = true;
379                                         return null;
380                                 }
381
382                                 if (is_class == false && !t.IsInterface){
383                                         Report.Error (527, "In Struct `"+tc.Name+"', type `"+
384                                                       name+"' is not an interface");
385                                         error = true;
386                                         return null;
387                                 }
388                                 
389                                 if (t.IsSealed) {
390                                         string detail = "";
391                                         
392                                         if (t.IsValueType)
393                                                 detail = " (a class can not inherit from a struct)";
394                                                         
395                                         Report.Error (509, "class `"+tc.Name+
396                                                       "': Cannot inherit from sealed class `"+
397                                                       bases [i]+"'"+detail);
398                                         error = true;
399                                         return null;
400                                 }
401
402                                 if (t.IsClass) {
403                                         if (parent != null){
404                                                 Report.Error (527, "In Class `"+tc.Name+"', type `"+
405                                                               name+"' is not an interface");
406                                                 error = true;
407                                                 return null;
408                                         }
409                                 }
410                                 
411                                 ifaces [j] = t;
412                         }
413
414                         return ifaces;
415                 }
416
417                 // <remarks>
418                 //   Creates the TypeBuilder for the TypeContainer @tc (a Class or a Struct)
419                 // </remarks>
420                 //
421                 TypeBuilder CreateType (TypeContainer tc, bool is_class)
422                 {
423                         TypeBuilder tb = tc.TypeBuilder;
424                         Type parent;
425                         Type [] ifaces;
426                         bool error;
427                         string name;
428                         
429                         if (tb != null)
430                                 return tb;
431
432                         if (tc.InTransit)
433                                 return null;
434                         tc.InTransit = true;
435
436                         name = tc.Name;
437
438                         ifaces = GetClassBases (tc, is_class, out parent, out error); 
439
440                         if (error)
441                                 return null;
442
443                         type_container_resolve_order.Add (tc);
444
445                         tb = mb.DefineType (
446                                 name,
447                                 tc.TypeAttr | TypeAttributes.Class,
448                                 parent,
449                                 ifaces);
450                         
451                         tc.TypeBuilder = tb;
452
453                         TypeManager.AddUserType (name, tb, tc);
454                         tc.InTransit = false;
455                         
456                         return tb;
457                 }
458
459                 // <remarks>
460                 //   This function is used to resolve the hierarchy tree.
461                 //   It processes interfaces, structs and classes in that order.
462                 //
463                 //   It creates the TypeBuilder's as it processes the user defined
464                 //   types.  
465                 // </remarks>
466                 public void ResolveTree ()
467                 {
468                         Hashtable ifaces, classes, structs;
469
470                         type_container_resolve_order = new ArrayList ();
471                         
472                         //
473                         // Interfaces are processed first, as classes and
474                         // structs might inherit from an object or implement
475                         // a set of interfaces, we need to be able to tell
476                         // them appart by just using the TypeManager.
477                         //
478                         ifaces = tree.Interfaces;
479                         if (ifaces != null){
480                                 interface_resolve_order = new ArrayList ();
481                                 
482                                 foreach (DictionaryEntry de in ifaces)
483                                         CreateInterface ((Interface) de.Value);
484                         }
485
486                         //
487                         // Process structs and classes next.  Our code assumes
488                         // this order (just for error reporting purposes).
489                         //
490                         structs = tree.Structs;
491                         if (structs != null){
492                                 foreach (DictionaryEntry de in structs)
493                                         CreateType ((Struct) de.Value, false);
494                         }
495
496                         classes = tree.Classes;
497                         if (classes != null){
498                                 foreach (DictionaryEntry de in classes)
499                                         CreateType ((Class) de.Value, true);
500                         }
501                 }
502                         
503                 // <summary>
504                 //   Closes all open types
505                 // </summary>
506                 //
507                 // <remarks>
508                 //   We usually use TypeBuilder types.  When we are done
509                 //   creating the type (which will happen after we have added
510                 //   methods, fields, etc) we need to "Define" them before we
511                 //   can save the Assembly
512                 // </remarks>
513                 public void CloseTypes ()
514                 {
515                         foreach (TypeBuilder t in TypeManager.UserTypes){
516                                 try {
517                                         t.CreateType ();
518                                 } catch (Exception e){
519                                         Console.WriteLine ("Caught Exception while creating type for " + t);
520                                         Console.WriteLine (e);
521                                 }
522                         }
523                 }
524
525                 //
526                 // Public function used to locate types, this can only
527                 // be used after the ResolveTree function has been invoked.
528                 //
529                 // Returns: Type or null if they type can not be found.
530                 //
531                 public Type LookupType (TypeContainer tc, string name, bool silent)
532                 {
533                         Type t;
534
535                         t = TypeManager.LookupType (MakeFQN (tc.Namespace.Name, name));
536                         if (t != null)
537                                 return t;
538
539                         // It's possible that name already is fully qualified. So we do
540                         // a simple direct lookup without adding any namespace names
541
542                         t = TypeManager.LookupType (name); 
543                         if (t != null)
544                                 return t;
545                         
546                         for (Namespace ns = tc.Namespace; ns != null; ns = ns.Parent){
547                                 ArrayList using_list = ns.UsingTable;
548
549                                 if (using_list == null)
550                                         continue;
551
552                                 foreach (string n in using_list){
553                                         t = TypeManager.LookupType (MakeFQN (n, name));
554                                         if (t != null)
555                                                 return t;
556                                 }
557                         }
558
559                         if (!silent)
560                                 Report.Error (246, "Cannot find type `"+name+"'");
561                         
562                         return null;
563                 }
564
565                 public Type LookupType (TypeContainer tc, string name)
566                 {
567                         return LookupType (tc, name, true);
568                 }
569
570                 public bool IsNamespace (string name)
571                 {
572                         Namespace ns;
573
574                         if (tree.Namespaces != null){
575                                 ns = (Namespace) tree.Namespaces [name];
576
577                                 if (ns != null)
578                                         return true;
579                         }
580
581                         return false;
582                 }
583
584                 // <summary>
585                 //   Populates the structs and classes with fields and methods
586                 // </summary>
587                 //
588                 // This is invoked after all interfaces, structs and classes
589                 // have been defined through `ResolveTree' 
590                 public void PopulateTypes ()
591                 {
592                         if (interface_resolve_order != null)
593                                 foreach (Interface iface in interface_resolve_order)
594                                         iface.Populate ();
595
596                         if (type_container_resolve_order != null)
597                                 foreach (TypeContainer tc in type_container_resolve_order)
598                                         tc.Populate ();
599                 }
600
601                 public void EmitCode ()
602                 {
603                         Hashtable classes, structs;
604                         
605                         if ((classes = tree.Classes) != null){
606                                 foreach (DictionaryEntry de in classes){
607                                         TypeContainer tc = (TypeContainer) de.Value;
608
609                                         tc.Emit ();
610                                 }
611                         }
612
613                         if ((structs = tree.Structs) != null){
614                                 foreach (DictionaryEntry de in structs){
615                                         TypeContainer tc = (TypeContainer) de.Value;
616
617                                         tc.Emit ();
618                                 }
619                         }
620                 }
621                 
622                 // <summary>
623                 //   Compiling against Standard Libraries property.
624                 // </summary>
625                 public bool StdLib {
626                         get {
627                                 return stdlib;
628                         }
629
630                         set {
631                                 stdlib = value;
632                         }
633                 }
634
635                 //
636                 // Public Field, used to track which method is the public entry
637                 // point.
638                 //
639                 public MethodInfo EntryPoint;
640         }
641 }
642