2 // rootcontext.cs: keeps track of our tree representation, and assemblies loaded.
4 // Author: Miguel de Icaza (miguel@ximian.com)
5 // Ravi Pratap (ravi@ximian.com)
7 // Licensed under the terms of the GNU GPL
9 // (C) 2001 Ximian, Inc (http://www.ximian.com)
12 using System.Collections;
13 using System.Reflection;
14 using System.Reflection.Emit;
15 using System.Diagnostics;
17 namespace Mono.CSharp {
19 public class RootContext {
22 // Contains the parsed tree
26 static public bool Optimize;
29 // If this value is `true', then calls to the Trace class are disabled
31 static public bool DisableTrace = true;
34 // If this value is `true', then calls to the Debug class are disabled
36 static public bool DisableDebug = true;
39 // The list of global attributes (those that target the assembly)
41 static Hashtable global_attributes = new Hashtable ();
44 // Whether we are being linked against the standard libraries.
45 // This is only used to tell whether `System.Object' should
46 // have a parent or not.
48 public static bool StdLib = true;
51 // This keeps track of the order in which classes were defined
52 // so that we can poulate them in that order.
54 // Order is important, because we need to be able to tell by
55 // examining the parent's list of methods which ones are virtual
56 // or abstract as well as the parent names (to implement new,
59 static ArrayList type_container_resolve_order;
60 static ArrayList interface_resolve_order;
61 static ArrayList attribute_types;
64 // Holds a reference to the Private Implementation Details
67 static TypeBuilder impl_details_class;
69 public static int WarningLevel = 2;
77 interface_resolve_order = new ArrayList ();
78 type_container_resolve_order = new ArrayList ();
81 static public Tree Tree {
87 static public string MainClass;
89 public static void RegisterOrder (Interface iface)
91 interface_resolve_order.Add (iface);
94 public static void RegisterOrder (TypeContainer tc)
96 type_container_resolve_order.Add (tc);
99 public static void RegisterAttribute (TypeContainer tc)
101 if (attribute_types == null)
102 attribute_types = new ArrayList ();
104 attribute_types.Add (tc);
108 // The default compiler checked state
110 static public bool Checked = false;
113 // Whether to allow Unsafe code
115 static public bool Unsafe = false;
117 static string MakeFQN (string nsn, string name)
119 string prefix = (nsn == "" ? "" : nsn + ".");
121 return prefix + name;
125 // This function is used to resolve the hierarchy tree.
126 // It processes interfaces, structs and classes in that order.
128 // It creates the TypeBuilder's as it processes the user defined
131 static public void ResolveTree ()
134 // Process the attribute types separately and before anything else
136 if (attribute_types != null)
137 foreach (TypeContainer tc in attribute_types)
141 // Interfaces are processed next, as classes and
142 // structs might inherit from an object or implement
143 // a set of interfaces, we need to be able to tell
144 // them appart by just using the TypeManager.
146 TypeContainer root = Tree.Types;
148 ArrayList ifaces = root.Interfaces;
150 foreach (Interface i in ifaces)
155 foreach (TypeContainer tc in root.Types)
158 if (root.Delegates != null)
159 foreach (Delegate d in root.Delegates)
162 if (root.Enums != null)
163 foreach (Enum e in root.Enums)
168 static void Error_TypeConflict (string name, Location loc)
171 520, loc, "`" + name + "' conflicts with a predefined type");
174 static void Error_TypeConflict (string name)
177 520, "`" + name + "' conflicts with a predefined type");
181 // Resolves a single class during the corlib bootstrap process
183 static TypeBuilder BootstrapCorlib_ResolveClass (TypeContainer root, string name)
185 object o = root.GetDefinition (name);
187 Report.Error (518, "The predefined type `" + name + "' is not defined");
193 DeclSpace d = (DeclSpace) o;
195 Error_TypeConflict (name, d.Location);
197 Error_TypeConflict (name);
202 return ((DeclSpace) o).DefineType ();
206 // Resolves a struct during the corlib bootstrap process
208 static void BootstrapCorlib_ResolveStruct (TypeContainer root, string name)
210 object o = root.GetDefinition (name);
212 Report.Error (518, "The predefined type `" + name + "' is not defined");
218 DeclSpace d = (DeclSpace) o;
220 Error_TypeConflict (name, d.Location);
222 Error_TypeConflict (name);
227 ((DeclSpace) o).DefineType ();
231 // Resolves a struct during the corlib bootstrap process
233 static void BootstrapCorlib_ResolveInterface (TypeContainer root, string name)
235 object o = root.GetDefinition (name);
237 Report.Error (518, "The predefined type `" + name + "' is not defined");
241 if (!(o is Interface)){
243 DeclSpace d = (DeclSpace) o;
245 Error_TypeConflict (name, d.Location);
247 Error_TypeConflict (name);
252 ((DeclSpace) o).DefineType ();
256 // Resolves a delegate during the corlib bootstrap process
258 static void BootstrapCorlib_ResolveDelegate (TypeContainer root, string name)
260 object o = root.GetDefinition (name);
262 Report.Error (518, "The predefined type `" + name + "' is not defined");
263 Environment.Exit (0);
266 if (!(o is Delegate)){
267 Error_TypeConflict (name);
271 ((DeclSpace) o).DefineType ();
276 /// Resolves the core types in the compiler when compiling with --nostdlib
278 static public void ResolveCore ()
280 TypeContainer root = Tree.Types;
282 TypeManager.object_type = BootstrapCorlib_ResolveClass (root, "System.Object");
283 TypeManager.value_type = BootstrapCorlib_ResolveClass (root, "System.ValueType");
284 TypeManager.attribute_type = BootstrapCorlib_ResolveClass (root, "System.Attribute");
286 string [] interfaces_first_stage = {
287 "System.IComparable", "System.ICloneable",
288 "System.IConvertible",
290 "System.Collections.IEnumerable",
291 "System.Collections.ICollection",
292 "System.Collections.IEnumerator",
293 "System.Collections.IList",
294 "System.IAsyncResult",
295 "System.IDisposable",
297 "System.Runtime.Serialization.ISerializable",
299 "System.Reflection.IReflect",
300 "System.Reflection.ICustomAttributeProvider"
303 foreach (string iname in interfaces_first_stage)
304 BootstrapCorlib_ResolveInterface (root, iname);
307 // These are the base value types
309 string [] structs_first_stage = {
310 "System.Byte", "System.SByte",
311 "System.Int16", "System.UInt16",
312 "System.Int32", "System.UInt32",
313 "System.Int64", "System.UInt64",
316 foreach (string cname in structs_first_stage)
317 BootstrapCorlib_ResolveStruct (root, cname);
320 // Now, we can load the enumerations, after this point,
323 TypeManager.InitEnumUnderlyingTypes ();
325 string [] structs_second_stage = {
326 "System.Single", "System.Double",
327 "System.Char", "System.Boolean",
328 "System.Decimal", "System.Void",
329 "System.RuntimeFieldHandle",
330 "System.RuntimeTypeHandle",
334 foreach (string cname in structs_second_stage)
335 BootstrapCorlib_ResolveStruct (root, cname);
338 // These are classes that depends on the core interfaces
340 string [] classes_second_stage = {
341 "System.String", "System.Enum",
342 "System.Array", "System.MulticastDelegate",
345 "System.Reflection.MemberInfo",
349 // These are not really important in the order, but they
350 // are used by the compiler later on (typemanager/CoreLookupType-d)
352 "System.Runtime.CompilerServices.RuntimeHelpers",
353 "System.Reflection.DefaultMemberAttribute",
354 "System.Threading.Monitor",
356 "System.AttributeUsageAttribute",
357 "System.Runtime.InteropServices.DllImportAttribute",
358 "System.Runtime.CompilerServices.MethodImplAttribute",
359 "System.Runtime.InteropServices.MarshalAsAttribute",
360 "System.ParamArrayAttribute",
361 "System.Security.UnverifiableCodeAttribute",
364 foreach (string cname in classes_second_stage)
365 BootstrapCorlib_ResolveClass (root, cname);
367 BootstrapCorlib_ResolveDelegate (root, "System.AsyncCallback");
371 // Closes all open types
375 // We usually use TypeBuilder types. When we are done
376 // creating the type (which will happen after we have added
377 // methods, fields, etc) we need to "Define" them before we
378 // can save the Assembly
380 static public void CloseTypes ()
382 TypeContainer root = Tree.Types;
384 ArrayList ifaces = root.Interfaces;
386 if (root.Enums != null)
387 foreach (Enum en in root.Enums)
390 if (attribute_types != null)
391 foreach (TypeContainer tc in attribute_types)
394 foreach (Interface iface in interface_resolve_order)
398 // We do this in two passes, first we close the structs,
399 // then the classes, because it seems the code needs it this
400 // way. If this is really what is going on, we should probably
401 // make sure that we define the structs in order as well.
403 foreach (TypeContainer tc in type_container_resolve_order){
404 if (tc is Struct && tc.Parent == tree.Types){
409 foreach (TypeContainer tc in type_container_resolve_order){
410 if (!(tc is Struct && tc.Parent == tree.Types))
414 if (root.Delegates != null)
415 foreach (Delegate d in root.Delegates)
420 // If we have a <PrivateImplementationDetails> class, close it
422 if (impl_details_class != null){
423 impl_details_class.CreateType ();
428 // This idea is from Felix Arrese-Igor
430 // Returns : the implicit parent of a composite namespace string
431 // eg. Implicit parent of A.B is A
433 static public string ImplicitParent (string ns)
435 int i = ns.LastIndexOf (".");
439 return ns.Substring (0, i);
442 static Type NamespaceLookup (Namespace curr_ns, string name)
447 // Try in the current namespace and all its implicit parents
449 for (string ns = curr_ns.Name; ns != null; ns = ImplicitParent (ns)) {
450 t = TypeManager.LookupType (MakeFQN (ns, name));
456 // It's possible that name already is fully qualified. So we do
457 // a simple direct lookup without adding any namespace names
459 t = TypeManager.LookupType (name);
464 // Try the aliases in the current namespace
466 string alias = curr_ns.LookupAlias (name);
469 t = TypeManager.LookupType (alias);
473 t = TypeManager.LookupType (MakeFQN (alias, name));
478 for (Namespace ns = curr_ns; ns != null; ns = ns.Parent) {
480 // Look in the namespace ns
482 t = TypeManager.LookupType (MakeFQN (ns.Name, name));
487 // Then try with the using clauses
489 ArrayList using_list = ns.UsingTable;
491 if (using_list == null)
494 foreach (string n in using_list) {
495 t = TypeManager.LookupType (MakeFQN (n, name));
503 string a = ns.LookupAlias (name);
505 t = TypeManager.LookupType (a);
509 t = TypeManager.LookupType (MakeFQN (a, name));
519 // Public function used to locate types, this can only
520 // be used after the ResolveTree function has been invoked.
522 // Returns: Type or null if they type can not be found.
524 // Come to think of it, this should be a DeclSpace
526 static public Type LookupType (DeclSpace ds, string name, bool silent, Location loc)
530 if (ds.Cache.Contains (name)){
531 t = (Type) ds.Cache [name];
536 // For the case the type we are looking for is nested within this one
537 // or is in any base class
539 DeclSpace containing_ds = ds;
540 while (containing_ds != null){
541 Type current_type = containing_ds.TypeBuilder;
543 while (current_type != null) {
547 t = TypeManager.LookupType (current_type.FullName + "+" + name);
553 current_type = current_type.BaseType;
556 containing_ds = containing_ds.Parent;
559 t = NamespaceLookup (ds.Namespace, name);
567 Report.Error (246, loc, "Cannot find type `"+name+"'");
573 // This is the silent version of LookupType, you can use this
574 // to `probe' for a type
576 static public Type LookupType (TypeContainer tc, string name, Location loc)
578 return LookupType (tc, name, true, loc);
581 static public bool IsNamespace (string name)
585 if (tree.Namespaces != null){
586 ns = (Namespace) tree.Namespaces [name];
595 static void Report1530 (Location loc)
597 Report.Error (1530, loc, "Keyword new not allowed for namespace elements");
600 static public void PopulateCoreType (TypeContainer root, string name)
602 DeclSpace ds = (DeclSpace) root.GetDefinition (name);
607 static public void BootCorlib_PopulateCoreTypes ()
609 TypeContainer root = tree.Types;
611 PopulateCoreType (root, "System.Object");
612 PopulateCoreType (root, "System.ValueType");
613 PopulateCoreType (root, "System.Attribute");
617 // Populates the structs and classes with fields and methods
620 // This is invoked after all interfaces, structs and classes
621 // have been defined through `ResolveTree'
622 static public void PopulateTypes ()
624 TypeContainer root = Tree.Types;
626 if (attribute_types != null)
627 foreach (TypeContainer tc in attribute_types)
630 if (interface_resolve_order != null){
631 foreach (Interface iface in interface_resolve_order)
632 if ((iface.ModFlags & Modifiers.NEW) == 0)
635 Report1530 (iface.Location);
639 if (type_container_resolve_order != null){
640 foreach (TypeContainer tc in type_container_resolve_order)
641 if ((tc.ModFlags & Modifiers.NEW) == 0)
644 Report1530 (tc.Location);
647 ArrayList delegates = root.Delegates;
648 if (delegates != null){
649 foreach (Delegate d in delegates)
650 if ((d.ModFlags & Modifiers.NEW) == 0)
653 Report1530 (d.Location);
656 ArrayList enums = root.Enums;
658 foreach (Enum en in enums)
659 if ((en.ModFlags & Modifiers.NEW) == 0)
662 Report1530 (en.Location);
666 static public void EmitCode ()
669 // Because of the strange way in which we do things, global
670 // attributes must be processed first.
672 if (global_attributes.Count > 0){
673 AssemblyBuilder ab = CodeGen.AssemblyBuilder;
674 TypeContainer dummy = new TypeContainer (null, "", new Location (-1));
675 EmitContext temp_ec = new EmitContext (
676 dummy, Mono.CSharp.Location.Null, null, null, 0, false);
678 foreach (DictionaryEntry de in global_attributes){
679 Namespace ns = (Namespace) de.Key;
680 Attributes attrs = (Attributes) de.Value;
682 dummy.Namespace = ns;
683 Attribute.ApplyAttributes (temp_ec, ab, ab, attrs, attrs.Location);
687 if (attribute_types != null)
688 foreach (TypeContainer tc in attribute_types)
691 if (type_container_resolve_order != null) {
692 foreach (TypeContainer tc in type_container_resolve_order)
695 foreach (TypeContainer tc in type_container_resolve_order)
700 ConstructorInfo ci = TypeManager.unverifiable_code_type.GetConstructor (new Type [0]);
703 Console.WriteLine ("Internal error !");
707 CustomAttributeBuilder cb = new CustomAttributeBuilder (ci, new object [0]);
708 CodeGen.ModuleBuilder.SetCustomAttribute (cb);
713 // Public Field, used to track which method is the public entry
716 static public MethodInfo EntryPoint;
719 // Track the location of the entry point.
721 static public Location EntryPointLocation;
724 // These are used to generate unique names on the structs and fields.
726 static int field_count;
729 // Makes an initialized struct, returns the field builder that
730 // references the data. Thanks go to Sergey Chaban for researching
731 // how to do this. And coming up with a shorter mechanism than I
732 // was able to figure out.
734 // This works but makes an implicit public struct $ArrayType$SIZE and
735 // makes the fields point to it. We could get more control if we did
738 // 1. DefineNestedType on the impl_details_class with our struct.
740 // 2. Define the field on the impl_details_class
742 static public FieldBuilder MakeStaticData (byte [] data)
745 int size = data.Length;
747 if (impl_details_class == null)
748 impl_details_class = CodeGen.ModuleBuilder.DefineType (
749 "<PrivateImplementationDetails>", TypeAttributes.NotPublic);
751 fb = impl_details_class.DefineInitializedData (
752 "$$field-" + (field_count++), data,
753 FieldAttributes.Static | FieldAttributes.Assembly);
759 // Adds a global attribute that was declared in `container',
760 // the attribute is in `attr', and it was defined at `loc'
762 static public void AddGlobalAttribute (TypeContainer container,
763 AttributeSection attr, Location loc)
765 Namespace ns = container.Namespace;
766 Attributes a = (Attributes) global_attributes [ns];
769 global_attributes [ns] = new Attributes (attr, loc);
771 a.AddAttribute (attr);