2002-02-21 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                 static Tree tree;
24
25                 //
26                 // Contains loaded assemblies and our generated code as we go.
27                 //
28                 static public TypeManager TypeManager;
29
30                 //
31                 // The System.Reflection.Emit CodeGenerator
32                 //
33                 static CodeGen cg;
34
35                 static public bool Optimize;
36                 
37                 //
38                 // The module builder pointer.
39                 //
40                 static ModuleBuilder mb;
41
42                 //
43                 // The list of global attributes (those that target the assembly)
44                 //
45                 static Attributes global_attributes;
46                 
47                 //
48                 // Whether we are being linked against the standard libraries.
49                 // This is only used to tell whether `System.Object' should
50                 // have a parent or not.
51                 //
52                 public static bool StdLib = true;
53
54                 //
55                 // This keeps track of the order in which classes were defined
56                 // so that we can poulate them in that order.
57                 //
58                 // Order is important, because we need to be able to tell by
59                 // examining the parent's list of methods which ones are virtual
60                 // or abstract as well as the parent names (to implement new, 
61                 // override).
62                 //
63                 static ArrayList type_container_resolve_order;
64                 static ArrayList interface_resolve_order;
65
66                 //
67                 // Holds a reference to the Private Implementation Details
68                 // class.
69                 //
70                 static TypeBuilder impl_details_class;
71
72                 public static int WarningLevel = 2;
73                 
74                 //
75                 // Constructor
76                 //
77                 static RootContext ()
78                 {
79                         tree = new Tree ();
80                         TypeManager = new TypeManager ();
81                 }
82
83                 static public Tree Tree {
84                         get {
85                                 return tree;
86                         }
87                 }
88
89                 static public string MainClass;
90                 
91                 static public CodeGen CodeGen {
92                         get {
93                                 return cg;
94                         }
95
96                         set {
97                                 //
98                                 // Temporary hack, we should probably
99                                 // intialize `cg' rather than depending on
100                                 // external initialization of it.
101                                 //
102                                 cg = value;
103                                 mb = cg.ModuleBuilder;
104                         }
105                 }
106
107                 public static void RegisterOrder (Interface iface)
108                 {
109                         interface_resolve_order.Add (iface);
110                 }
111                 
112                 public static void RegisterOrder (TypeContainer tc)
113                 {
114                         type_container_resolve_order.Add (tc);
115                 }
116                 
117                 // 
118                 // The default compiler checked state
119                 //
120                 static public bool Checked = false;
121
122                 //
123                 // Whether to allow Unsafe code
124                 //
125                 static public bool Unsafe = false;
126                 
127                 static string MakeFQN (string nsn, string name)
128                 {
129                         string prefix = (nsn == "" ? "" : nsn + ".");
130
131                         return prefix + name;
132                 }
133                        
134                 // <remarks>
135                 //   This function is used to resolve the hierarchy tree.
136                 //   It processes interfaces, structs and classes in that order.
137                 //
138                 //   It creates the TypeBuilder's as it processes the user defined
139                 //   types.  
140                 // </remarks>
141                 static public void ResolveTree ()
142                 {
143                         //
144                         // Interfaces are processed first, as classes and
145                         // structs might inherit from an object or implement
146                         // a set of interfaces, we need to be able to tell
147                         // them appart by just using the TypeManager.
148                         //
149
150                         TypeContainer root = Tree.Types;
151
152                         ArrayList ifaces = root.Interfaces;
153                         if (ifaces != null){
154                                 interface_resolve_order = new ArrayList ();
155                                 
156                                 foreach (Interface i in ifaces) 
157                                         i.DefineInterface (mb);
158                         }
159                                                 
160                         type_container_resolve_order = new ArrayList ();
161                         
162                         foreach (TypeContainer tc in root.Types) 
163                                 tc.DefineType (mb);
164
165                         if (root.Delegates != null)
166                                 foreach (Delegate d in root.Delegates) 
167                                         d.DefineDelegate (mb);
168
169                         if (root.Enums != null)
170                                 foreach (Enum e in root.Enums)
171                                         e.DefineEnum (mb);
172                         
173                 }
174                         
175                 // <summary>
176                 //   Closes all open types
177                 // </summary>
178                 //
179                 // <remarks>
180                 //   We usually use TypeBuilder types.  When we are done
181                 //   creating the type (which will happen after we have added
182                 //   methods, fields, etc) we need to "Define" them before we
183                 //   can save the Assembly
184                 // </remarks>
185                 static public void CloseTypes ()
186                 {
187                         TypeContainer root = Tree.Types;
188                         
189                         ArrayList ifaces = root.Interfaces;
190
191                         if (root.Enums != null)
192                                 foreach (Enum en in root.Enums)
193                                         en.CloseType ();
194
195                         if (interface_resolve_order != null){
196                                 foreach (Interface iface in interface_resolve_order)
197                                         iface.CloseType ();
198                         }
199
200                         //
201                         // We do this in two passes, first we close the structs,
202                         // then the classes, because it seems the code needs it this
203                         // way.  If this is really what is going on, we should probably
204                         // make sure that we define the structs in order as well.
205                         //
206                         if (type_container_resolve_order != null){
207                                 foreach (TypeContainer tc in type_container_resolve_order){
208                                         if (tc is Struct && tc.Parent == tree.Types){
209                                                 tc.CloseType ();
210                                         }
211                                 }
212
213                                 foreach (TypeContainer tc in type_container_resolve_order){
214                                         if (!(tc is Struct && tc.Parent == tree.Types))
215                                                 tc.CloseType ();                                        
216                                 }
217                         }
218                         
219                         if (root.Delegates != null)
220                                 foreach (Delegate d in root.Delegates)
221                                         d.CloseDelegate ();
222
223
224                         //
225                         // If we have a <PrivateImplementationDetails> class, close it
226                         //
227                         if (impl_details_class != null){
228                                 impl_details_class.CreateType ();
229                         }
230                 }
231                 
232                 //
233                 // Public function used to locate types, this can only
234                 // be used after the ResolveTree function has been invoked.
235                 //
236                 // Returns: Type or null if they type can not be found.
237                 //
238                 static public Type LookupType (DeclSpace ds, string name, bool silent, Location loc)
239                 {
240                         Type t;
241
242                         //
243                         // For the case the type we are looking for is nested within this one
244                         // or any base class
245                         //
246                         DeclSpace containing_ds = ds;
247                         while (containing_ds != null){
248                                 Type current_type = containing_ds.TypeBuilder;
249
250                                 while (current_type != null) {
251                                         t = TypeManager.LookupType (current_type.FullName + "+" + name);
252                                         if (t != null)
253                                                 return t;
254                                         current_type = current_type.BaseType;
255                                 }
256
257                                 containing_ds = containing_ds.Parent;
258                         }
259
260                         t = TypeManager.LookupType (MakeFQN (ds.Namespace.Name, name));
261                         if (t != null)
262                                 return t;
263
264                         // It's possible that name already is fully qualified. So we do
265                         // a simple direct lookup without adding any namespace names
266
267                         t = TypeManager.LookupType (name); 
268                         if (t != null)
269                                 return t;
270                         
271                         for (Namespace ns = ds.Namespace; ns != null; ns = ns.Parent){
272                                 ArrayList using_list = ns.UsingTable;
273
274                                 if (using_list == null)
275                                         continue;
276
277                                 foreach (string n in using_list){
278                                         t = TypeManager.LookupType (MakeFQN (n, name));
279                                         if (t != null)
280                                                 return t;
281                                 }
282                         }
283
284                         if (!silent)
285                                 Report.Error (246, loc, "Cannot find type `"+name+"'");
286                         
287                         return null;
288                 }
289
290                 // <summary>
291                 //   This is the silent version of LookupType, you can use this
292                 //   to `probe' for a type
293                 // </summary>
294                 static public Type LookupType (TypeContainer tc, string name, Location loc)
295                 {
296                         return LookupType (tc, name, true, loc);
297                 }
298
299                 static public bool IsNamespace (string name)
300                 {
301                         Namespace ns;
302
303                         if (tree.Namespaces != null){
304                                 ns = (Namespace) tree.Namespaces [name];
305
306                                 if (ns != null)
307                                         return true;
308                         }
309
310                         return false;
311                 }
312
313                 static void Report1530 (Location loc)
314                 {
315                         Report.Error (1530, loc, "Keyword new not allowed for namespace elements");
316                 }
317                 
318                 // <summary>
319                 //   Populates the structs and classes with fields and methods
320                 // </summary>
321                 //
322                 // This is invoked after all interfaces, structs and classes
323                 // have been defined through `ResolveTree' 
324                 static public void PopulateTypes ()
325                 {
326                         TypeContainer root = Tree.Types;
327
328                         if (interface_resolve_order != null){
329                                 foreach (Interface iface in interface_resolve_order)
330                                         if ((iface.ModFlags & Modifiers.NEW) == 0)
331                                                 iface.Define (root);
332                                         else
333                                                 Report1530 (iface.Location);
334                         }
335
336
337                         if (type_container_resolve_order != null){
338                                 foreach (TypeContainer tc in type_container_resolve_order)
339                                         if ((tc.ModFlags & Modifiers.NEW) == 0)
340                                                 tc.Define (root);
341                                         else
342                                                 Report1530 (tc.Location);
343                         }
344
345                         ArrayList delegates = root.Delegates;
346                         if (delegates != null){
347                                 foreach (Delegate d in delegates)
348                                         if ((d.ModFlags & Modifiers.NEW) == 0)
349                                                 d.Define (root);
350                                         else
351                                                 Report1530 (d.Location);
352                         }
353
354                         ArrayList enums = root.Enums;
355                         if (enums != null){
356                                 foreach (Enum en in enums)
357                                         if ((en.ModFlags & Modifiers.NEW) == 0)
358                                                 en.Define (root);
359                                         else
360                                                 Report1530 (en.Location);
361                         }
362                 }
363
364                 static public void EmitCode ()
365                 {
366                         if (type_container_resolve_order != null){
367                                 foreach (TypeContainer tc in type_container_resolve_order)
368                                         tc.EmitConstants ();
369                                 
370                                 foreach (TypeContainer tc in type_container_resolve_order)
371                                         tc.Emit ();
372                         }
373
374                         if (global_attributes != null){
375                                 EmitContext ec = new EmitContext (
376                                         tree.Types, Mono.CSharp.Location.Null, null, null, 0, false);
377                                 AssemblyBuilder ab = cg.AssemblyBuilder;
378
379                                 Attribute.ApplyAttributes (ec, ab, ab, global_attributes,
380                                                            global_attributes.Location);
381                         } 
382
383                         if (Unsafe) {
384                                 ConstructorInfo ci = TypeManager.unverifiable_code_type.GetConstructor (new Type [0]);
385                                         
386                                 if (ci == null) {
387                                         Console.WriteLine ("Internal error !");
388                                         return;
389                                 }
390                                 
391                                 CustomAttributeBuilder cb = new CustomAttributeBuilder (ci, new object [0]);
392                                 mb.SetCustomAttribute (cb);
393                         }
394                 }
395                 
396                 static public ModuleBuilder ModuleBuilder {
397                         get {
398                                 return mb;
399                         }
400                 }
401
402                 //
403                 // Public Field, used to track which method is the public entry
404                 // point.
405                 //
406                 static public MethodInfo EntryPoint;
407
408                 //
409                 // These are used to generate unique names on the structs and fields.
410                 //
411                 static int field_count;
412                 
413                 //
414                 // Makes an initialized struct, returns the field builder that
415                 // references the data.  Thanks go to Sergey Chaban for researching
416                 // how to do this.  And coming up with a shorter mechanism than I
417                 // was able to figure out.
418                 //
419                 // This works but makes an implicit public struct $ArrayType$SIZE and
420                 // makes the fields point to it.  We could get more control if we did
421                 // use instead:
422                 //
423                 // 1. DefineNestedType on the impl_details_class with our struct.
424                 //
425                 // 2. Define the field on the impl_details_class
426                 //
427                 static public FieldBuilder MakeStaticData (byte [] data)
428                 {
429                         FieldBuilder fb;
430                         int size = data.Length;
431                         
432                         if (impl_details_class == null)
433                                 impl_details_class = mb.DefineType (
434                                         "<PrivateImplementationDetails>", TypeAttributes.NotPublic);
435
436                         fb = impl_details_class.DefineInitializedData (
437                                 "$$field-" + (field_count++), data,
438                                 FieldAttributes.Static | FieldAttributes.Assembly);
439                         
440                         return fb;
441                 }
442
443                 static public void AddGlobalAttributes (AttributeSection sect, Location loc)
444                 {
445                         if (global_attributes == null)
446                                 global_attributes = new Attributes (sect, loc);
447
448                         global_attributes.AddAttribute (sect);
449                 }
450         }
451 }
452               
453