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