2001-12-15 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 Mono.CSharp {
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                 static public bool Optimize;
36                 
37                 //
38                 // The module builder pointer.
39                 //
40                 static ModuleBuilder mb;
41
42                 //
43                 // Whether we are being linked against the standard libraries.
44                 // This is only used to tell whether `System.Object' should
45                 // have a parent or not.
46                 //
47                 static bool stdlib = true;
48
49                 //
50                 // This keeps track of the order in which classes were defined
51                 // so that we can poulate them in that order.
52                 //
53                 // Order is important, because we need to be able to tell by
54                 // examining the parent's list of methods which ones are virtual
55                 // or abstract as well as the parent names (to implement new, 
56                 // override).
57                 //
58                 ArrayList type_container_resolve_order;
59                 ArrayList interface_resolve_order;
60                 
61                 //
62                 // Holds a reference to the Private Implementation Details
63                 // class.
64                 //
65                 TypeBuilder impl_details_class;
66
67                 //
68                 // Constructor
69                 //
70                 public RootContext ()
71                 {
72                         tree = new Tree (this);
73                         TypeManager = new TypeManager ();
74                 }
75
76                 public Tree Tree {
77                         get {
78                                 return tree;
79                         }
80                 }
81
82                 public CodeGen CodeGen {
83                         get {
84                                 return cg;
85                         }
86
87                         set {
88                                 //
89                                 // Temporary hack, we should probably
90                                 // intialize `cg' rather than depending on
91                                 // external initialization of it.
92                                 //
93                                 cg = value;
94                                 mb = cg.ModuleBuilder;
95                         }
96                 }
97
98                 // 
99                 // The default compiler checked state
100                 //
101                 public bool Checked = false;
102
103                 string MakeFQN (string nsn, string name)
104                 {
105                         string prefix = (nsn == "" ? "" : nsn + ".");
106
107                         return prefix + name;
108                 }
109                        
110                 // <remarks>
111                 //   This function is used to resolve the hierarchy tree.
112                 //   It processes interfaces, structs and classes in that order.
113                 //
114                 //   It creates the TypeBuilder's as it processes the user defined
115                 //   types.  
116                 // </remarks>
117                 public void ResolveTree ()
118                 {
119                         //
120                         // Interfaces are processed first, as classes and
121                         // structs might inherit from an object or implement
122                         // a set of interfaces, we need to be able to tell
123                         // them appart by just using the TypeManager.
124                         //
125
126                         TypeContainer root = Tree.Types;
127
128                         ArrayList ifaces = root.Interfaces;
129                         if (ifaces != null){
130                                 interface_resolve_order = new ArrayList ();
131                                 
132                                 foreach (Interface i in ifaces) {
133                                         Type t = i.DefineInterface (mb);
134                                         if (t != null)
135                                                 interface_resolve_order.Add (i);
136                                 }
137                         }
138                                                 
139                         type_container_resolve_order = new ArrayList ();
140                         
141                         foreach (TypeContainer tc in root.Types) {
142                                 Type t = tc.DefineType (mb);
143                                 if (t != null)
144                                         type_container_resolve_order.Add (tc);
145                         }
146
147                         if (root.Delegates != null)
148                                 foreach (Delegate d in root.Delegates) 
149                                         d.DefineDelegate (mb);
150
151                         if (root.Enums != null)
152                                 foreach (Enum e in root.Enums)
153                                         e.DefineEnum (mb);
154                         
155                 }
156                         
157                 // <summary>
158                 //   Closes all open types
159                 // </summary>
160                 //
161                 // <remarks>
162                 //   We usually use TypeBuilder types.  When we are done
163                 //   creating the type (which will happen after we have added
164                 //   methods, fields, etc) we need to "Define" them before we
165                 //   can save the Assembly
166                 // </remarks>
167                 public void CloseTypes ()
168                 {
169                         TypeContainer root = Tree.Types;
170                         
171                         ArrayList ifaces = root.Interfaces;
172
173                         if (ifaces != null)
174                                 foreach (Interface i in ifaces) 
175                                         i.CloseType ();
176                         
177                         foreach (TypeContainer tc in root.Types)
178                                 tc.CloseType ();
179
180                         if (root.Delegates != null)
181                                 foreach (Delegate d in root.Delegates)
182                                         d.CloseDelegate ();
183
184                         if (root.Enums != null)
185                                 foreach (Enum en in root.Enums)
186                                         en.CloseEnum ();
187                         
188
189                         //
190                         // If we have a <PrivateImplementationDetails> class, close it
191                         //
192                         if (impl_details_class != null){
193                                 impl_details_class.CreateType ();
194                         }
195                 }
196                 
197                 //
198                 // Public function used to locate types, this can only
199                 // be used after the ResolveTree function has been invoked.
200                 //
201                 // Returns: Type or null if they type can not be found.
202                 //
203                 public Type LookupType (DeclSpace ds, string name, bool silent)
204                 {
205                         Type t;
206
207                         t = TypeManager.LookupType (MakeFQN (ds.Namespace.Name, name));
208                         if (t != null)
209                                 return t;
210
211                         // It's possible that name already is fully qualified. So we do
212                         // a simple direct lookup without adding any namespace names
213
214                         t = TypeManager.LookupType (name); 
215                         if (t != null)
216                                 return t;
217                         
218                         for (Namespace ns = ds.Namespace; ns != null; ns = ns.Parent){
219                                 ArrayList using_list = ns.UsingTable;
220
221                                 if (using_list == null)
222                                         continue;
223
224                                 foreach (string n in using_list){
225                                         t = TypeManager.LookupType (MakeFQN (n, name));
226                                         if (t != null)
227                                                 return t;
228                                 }
229                         }
230
231                         // For the case the type we are looking for is nested within this one.
232                         t = TypeManager.LookupType (ds.Name + "." + name);
233                         if (t != null)
234                                 return t;
235                         
236                         if (!silent)
237                                 Report.Error (246, "Cannot find type `"+name+"'");
238                         
239                         return null;
240                 }
241
242                 // <summary>
243                 //   This is the silent version of LookupType, you can use this
244                 //   to `probe' for a type
245                 // </summary>
246                 public Type LookupType (TypeContainer tc, string name)
247                 {
248                         return LookupType (tc, name, true);
249                 }
250
251                 public bool IsNamespace (string name)
252                 {
253                         Namespace ns;
254
255                         if (tree.Namespaces != null){
256                                 ns = (Namespace) tree.Namespaces [name];
257
258                                 if (ns != null)
259                                         return true;
260                         }
261
262                         return false;
263                 }
264
265                 // <summary>
266                 //   Populates the structs and classes with fields and methods
267                 // </summary>
268                 //
269                 // This is invoked after all interfaces, structs and classes
270                 // have been defined through `ResolveTree' 
271                 public void PopulateTypes ()
272                 {
273                         if (interface_resolve_order != null)
274                                 foreach (Interface iface in interface_resolve_order)
275                                         iface.Populate ();
276
277                         if (type_container_resolve_order != null)
278                                 foreach (TypeContainer tc in type_container_resolve_order)
279                                         tc.Populate ();
280
281                         TypeContainer root = Tree.Types;
282
283                         ArrayList delegates = root.Delegates;
284                         if (delegates != null)
285                                 foreach (Delegate d in delegates)
286                                         d.Populate (root);
287
288                         ArrayList enums = root.Enums;
289                         if (enums != null)
290                                 foreach (Enum en in enums)
291                                         en.Populate (root);
292                         
293                 }
294
295                 public void EmitCode ()
296                 {
297                         if (type_container_resolve_order != null)
298                                 foreach (TypeContainer tc in type_container_resolve_order)
299                                         tc.Emit ();
300                 }
301                 
302                 // <summary>
303                 //   Compiling against Standard Libraries property.
304                 // </summary>
305                 public bool StdLib {
306                         get {
307                                 return stdlib;
308                         }
309
310                         set {
311                                 stdlib = value;
312                         }
313                 }
314
315                 public static ModuleBuilder ModuleBuilder {
316                         get {
317                                 return mb;
318                         }
319                 }
320
321                 //
322                 // Public Field, used to track which method is the public entry
323                 // point.
324                 //
325                 public MethodInfo EntryPoint;
326
327                 //
328                 // These are used to generate unique names on the structs and fields.
329                 //
330                 int field_count;
331                 
332                 //
333                 // Makes an initialized struct, returns the field builder that
334                 // references the data.  Thanks go to Sergey Chaban for researching
335                 // how to do this.  And coming up with a shorter mechanism than I
336                 // was able to figure out.
337                 //
338                 // This works but makes an implicit public struct $ArrayType$SIZE and
339                 // makes the fields point to it.  We could get more control if we did
340                 // use instead:
341                 //
342                 // 1. DefineNestedType on the impl_details_class with our struct.
343                 //
344                 // 2. Define the field on the impl_details_class
345                 //
346                 public FieldBuilder MakeStaticData (byte [] data)
347                 {
348                         FieldBuilder fb;
349                         int size = data.Length;
350                         
351                         if (impl_details_class == null)
352                                 impl_details_class = mb.DefineType (
353                                         "<PrivateImplementationDetails>", TypeAttributes.NotPublic);
354
355                         fb = impl_details_class.DefineInitializedData (
356                                 "$$field-" + (field_count++), data,
357                                 FieldAttributes.Static | FieldAttributes.Assembly);
358                         
359                         return fb;
360                 }
361         }
362 }
363               
364