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