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