2 // rootcontext.cs: keeps track of our tree representation, and assemblies loaded.
\r
4 // Author: Miguel de Icaza (miguel@ximian.com)
\r
5 // Ravi Pratap (ravi@ximian.com)
\r
7 // Licensed under the terms of the GNU GPL
\r
9 // (C) 2001 Ximian, Inc (http://www.ximian.com)
\r
12 using System.Collections;
\r
13 using System.Reflection;
\r
14 using System.Reflection.Emit;
\r
15 using System.Diagnostics;
\r
17 namespace Mono.MonoBASIC {
\r
19 public class RootContext {
\r
22 // Contains the parsed tree
\r
27 // Tracks Imported namespaces
29 static SourceBeingCompiled sourceBeingCompiled = new SourceBeingCompiled();
32 // This hashtable contains all of the #definitions across the source code
\r
33 // it is used by the ConditionalAttribute handler.
\r
35 public static Hashtable AllDefines = new Hashtable ();
\r
38 // The list of global attributes (those that target the assembly)
\r
40 static Hashtable global_attributes = new Hashtable ();
\r
43 // Whether we are being linked against the standard libraries.
\r
44 // This is only used to tell whether `System.Object' should
\r
45 // have a parent or not.
\r
47 public static bool StdLib = true;
\r
50 // This keeps track of the order in which classes were defined
\r
51 // so that we can poulate them in that order.
\r
53 // Order is important, because we need to be able to tell by
\r
54 // examining the parent's list of methods which ones are virtual
\r
55 // or abstract as well as the parent names (to implement new,
\r
58 static ArrayList type_container_resolve_order;
\r
59 static ArrayList interface_resolve_order;
\r
60 static ArrayList attribute_types;
\r
63 // Holds a reference to the Private Implementation Details
\r
66 static TypeBuilder impl_details_class;
\r
68 public static int WarningLevel = 2;
\r
73 static RootContext ()
\r
76 interface_resolve_order = new ArrayList ();
\r
77 type_container_resolve_order = new ArrayList ();
\r
80 static public Tree Tree {
\r
86 static public string MainClass;
\r
88 public static void RegisterOrder (Interface iface)
\r
90 interface_resolve_order.Add (iface);
\r
93 public static void RegisterOrder (TypeContainer tc)
\r
95 type_container_resolve_order.Add (tc);
\r
98 public static void RegisterAttribute (TypeContainer tc)
\r
100 if (attribute_types == null)
\r
101 attribute_types = new ArrayList ();
\r
103 attribute_types.Add (tc);
\r
106 public static void InitializeImports(ArrayList ImportsList)
108 sourceBeingCompiled.InitializeImports (ImportsList);
111 public static SourceBeingCompiled SourceBeingCompiled
113 get { return sourceBeingCompiled; }
116 public static void VerifyImports()
118 sourceBeingCompiled.VerifyImports();
122 // The default compiler checked state
\r
124 static public bool Checked = false;
\r
127 // Whether to allow Unsafe code
\r
129 static public bool Unsafe = false;
\r
131 // Root namespace name (implicit namespace)
\r
132 static public string RootNamespace = "";
\r
134 static string MakeFQN (string nsn, string name)
\r
136 string prefix = (nsn == "" ? "" : nsn + ".");
\r
138 return prefix + name;
\r
142 // This function is used to resolve the hierarchy tree.
\r
143 // It processes interfaces, structs and classes in that order.
\r
145 // It creates the TypeBuilder's as it processes the user defined
\r
148 static public void ResolveTree ()
\r
151 // Process the attribute types separately and before anything else
\r
153 if (attribute_types != null)
\r
154 foreach (TypeContainer tc in attribute_types)
\r
158 // Interfaces are processed next, as classes and
\r
159 // structs might inherit from an object or implement
\r
160 // a set of interfaces, we need to be able to tell
\r
161 // them appart by just using the TypeManager.
\r
163 TypeContainer root = Tree.Types;
\r
165 ArrayList ifaces = root.Interfaces;
\r
166 if (ifaces != null){
\r
167 foreach (Interface i in ifaces)
\r
172 foreach (TypeContainer tc in root.Types)
\r
175 if (root.Delegates != null)
\r
176 foreach (Delegate d in root.Delegates)
\r
179 if (root.Enums != null)
\r
180 foreach (Enum e in root.Enums)
\r
185 static void Error_TypeConflict (string name, Location loc)
\r
188 520, loc, "`" + name + "' conflicts with a predefined type");
\r
191 static void Error_TypeConflict (string name)
\r
194 520, "`" + name + "' conflicts with a predefined type");
\r
198 // Resolves a single class during the corlib bootstrap process
\r
200 static TypeBuilder BootstrapCorlib_ResolveClass (TypeContainer root, string name)
\r
202 object o = root.GetDefinition (name);
\r
204 Report.Error (518, "The predefined type `" + name + "' is not defined");
\r
208 if (!(o is Class)){
\r
209 if (o is DeclSpace){
\r
210 DeclSpace d = (DeclSpace) o;
\r
212 Error_TypeConflict (name, d.Location);
\r
214 Error_TypeConflict (name);
\r
219 return ((DeclSpace) o).DefineType ();
\r
223 // Resolves a struct during the corlib bootstrap process
\r
225 static void BootstrapCorlib_ResolveStruct (TypeContainer root, string name)
\r
227 object o = root.GetDefinition (name);
\r
229 Report.Error (518, "The predefined type `" + name + "' is not defined");
\r
233 if (!(o is Struct)){
\r
234 if (o is DeclSpace){
\r
235 DeclSpace d = (DeclSpace) o;
\r
237 Error_TypeConflict (name, d.Location);
\r
239 Error_TypeConflict (name);
\r
244 ((DeclSpace) o).DefineType ();
\r
248 // Resolves a struct during the corlib bootstrap process
\r
250 static void BootstrapCorlib_ResolveInterface (TypeContainer root, string name)
\r
252 object o = root.GetDefinition (name);
\r
254 Report.Error (518, "The predefined type `" + name + "' is not defined");
\r
258 if (!(o is Interface)){
\r
259 if (o is DeclSpace){
\r
260 DeclSpace d = (DeclSpace) o;
\r
262 Error_TypeConflict (name, d.Location);
\r
264 Error_TypeConflict (name);
\r
269 ((DeclSpace) o).DefineType ();
\r
273 // Resolves a delegate during the corlib bootstrap process
\r
275 static void BootstrapCorlib_ResolveDelegate (TypeContainer root, string name)
\r
277 object o = root.GetDefinition (name);
\r
279 Report.Error (518, "The predefined type `" + name + "' is not defined");
\r
280 Environment.Exit (0);
\r
283 if (!(o is Delegate)){
\r
284 Error_TypeConflict (name);
\r
288 ((DeclSpace) o).DefineType ();
\r
293 /// Resolves the core types in the compiler when compiling with --nostdlib
\r
295 static public void ResolveCore ()
\r
297 TypeContainer root = Tree.Types;
\r
299 TypeManager.object_type = BootstrapCorlib_ResolveClass (root, "System.Object");
\r
300 TypeManager.value_type = BootstrapCorlib_ResolveClass (root, "System.ValueType");
\r
301 TypeManager.attribute_type = BootstrapCorlib_ResolveClass (root, "System.Attribute");
\r
303 string [] interfaces_first_stage = {
\r
304 "System.IComparable", "System.ICloneable",
\r
305 "System.IConvertible",
\r
307 "System.Collections.IEnumerable",
\r
308 "System.Collections.ICollection",
\r
309 "System.Collections.IEnumerator",
\r
310 "System.Collections.IList",
\r
311 "System.IAsyncResult",
\r
312 "System.IDisposable",
\r
314 "System.Runtime.Serialization.ISerializable",
\r
316 "System.Reflection.IReflect",
\r
317 "System.Reflection.ICustomAttributeProvider"
\r
320 foreach (string iname in interfaces_first_stage)
\r
321 BootstrapCorlib_ResolveInterface (root, iname);
\r
324 // These are the base value types
\r
326 string [] structs_first_stage = {
\r
327 "System.Byte", "System.SByte",
\r
328 "System.Int16", "System.UInt16",
\r
329 "System.Int32", "System.UInt32",
\r
330 "System.Int64", "System.UInt64",
\r
333 foreach (string cname in structs_first_stage)
\r
334 BootstrapCorlib_ResolveStruct (root, cname);
\r
337 // Now, we can load the enumerations, after this point,
\r
338 // we can use enums.
\r
340 TypeManager.InitEnumUnderlyingTypes ();
\r
342 string [] structs_second_stage = {
\r
343 "System.Single", "System.Double",
\r
344 "System.Char", "System.Boolean",
\r
345 "System.Decimal", "System.Void",
\r
346 "System.RuntimeFieldHandle",
\r
347 "System.RuntimeTypeHandle",
\r
351 foreach (string cname in structs_second_stage)
\r
352 BootstrapCorlib_ResolveStruct (root, cname);
\r
355 // These are classes that depends on the core interfaces
\r
357 string [] classes_second_stage = {
\r
358 "System.Reflection.MemberInfo",
\r
360 "System.Exception",
\r
363 // These are not really important in the order, but they
\r
364 // are used by the compiler later on (typemanager/CoreLookupType-d)
\r
366 "System.Runtime.CompilerServices.RuntimeHelpers",
\r
367 "System.Reflection.DefaultMemberAttribute",
\r
368 "System.Threading.Monitor",
\r
370 "System.AttributeUsageAttribute",
\r
371 "System.Runtime.InteropServices.DllImportAttribute",
\r
372 "System.Runtime.CompilerServices.MethodImplAttribute",
\r
373 "System.Runtime.InteropServices.MarshalAsAttribute",
\r
374 "System.Diagnostics.ConditionalAttribute",
\r
375 "System.ObsoleteAttribute",
\r
376 "System.ParamArrayAttribute",
\r
377 "System.Security.UnverifiableCodeAttribute",
\r
378 "System.Runtime.CompilerServices.IndexerNameAttribute",
\r
381 // We must store them here before calling BootstrapCorlib_ResolveDelegate.
\r
382 TypeManager.string_type = BootstrapCorlib_ResolveClass (root, "System.String");
\r
383 TypeManager.enum_type = BootstrapCorlib_ResolveClass (root, "System.Enum");
\r
384 TypeManager.array_type = BootstrapCorlib_ResolveClass (root, "System.Array");
\r
385 TypeManager.multicast_delegate_type = BootstrapCorlib_ResolveClass (root, "System.MulticastDelegate");
\r
386 TypeManager.delegate_type = BootstrapCorlib_ResolveClass (root, "System.Delegate");
\r
388 foreach (string cname in classes_second_stage)
\r
389 BootstrapCorlib_ResolveClass (root, cname);
\r
391 BootstrapCorlib_ResolveDelegate (root, "System.AsyncCallback");
\r
395 // Closes all open types
\r
399 // We usually use TypeBuilder types. When we are done
\r
400 // creating the type (which will happen after we have added
\r
401 // methods, fields, etc) we need to "Define" them before we
\r
402 // can save the Assembly
\r
404 static public void CloseTypes ()
\r
406 TypeContainer root = Tree.Types;
\r
408 ArrayList ifaces = root.Interfaces;
\r
410 if (root.Enums != null)
\r
411 foreach (Enum en in root.Enums)
\r
414 if (attribute_types != null)
\r
415 foreach (TypeContainer tc in attribute_types)
\r
418 foreach (Interface iface in interface_resolve_order)
\r
419 iface.CloseType ();
\r
422 // We do this in two passes, first we close the structs,
\r
423 // then the classes, because it seems the code needs it this
\r
424 // way. If this is really what is going on, we should probably
\r
425 // make sure that we define the structs in order as well.
\r
427 foreach (TypeContainer tc in type_container_resolve_order){
\r
428 if (tc is Struct && tc.Parent == tree.Types){
\r
433 foreach (TypeContainer tc in type_container_resolve_order){
\r
434 if (!(tc is Struct && tc.Parent == tree.Types))
\r
438 if (root.Delegates != null)
\r
439 foreach (Delegate d in root.Delegates)
\r
444 // If we have a <PrivateImplementationDetails> class, close it
\r
446 if (impl_details_class != null){
\r
447 impl_details_class.CreateType ();
\r
452 // This idea is from Felix Arrese-Igor
\r
454 // Returns : the implicit parent of a composite namespace string
\r
455 // eg. Implicit parent of A.B is A
\r
457 static public string ImplicitParent (string ns)
\r
459 int i = ns.LastIndexOf (".");
\r
463 return ns.Substring (0, i);
\r
466 static Type NamespaceLookup (Namespace curr_ns, string name, Location loc)
\r
471 // Try in the current namespace and all its implicit parents
\r
473 for (string ns = curr_ns.Name; ns != null; ns = ImplicitParent (ns)) {
\r
474 t = TypeManager.LookupType (MakeFQN (ns, name));
\r
480 // It's possible that name already is fully qualified. So we do
\r
481 // a simple direct lookup without adding any namespace names
\r
483 t = TypeManager.LookupType (name);
\r
488 // Try the aliases in the current namespace
\r
490 string alias = sourceBeingCompiled.LookupAlias (name);
\r
492 if (alias != null) {
\r
493 t = TypeManager.LookupType (alias);
\r
497 t = TypeManager.LookupType (MakeFQN (alias, name));
\r
502 for (Namespace ns = curr_ns; ns != null; ns = ns.Parent) {
\r
504 // Look in the namespace ns
\r
506 t = TypeManager.LookupType (MakeFQN (ns.Name, name));
\r
511 // Then try with the using clauses
\r
514 ICollection imports_list = sourceBeingCompiled.ImportsTable;
\r
516 if (imports_list == null)
\r
520 foreach (SourceBeingCompiled.ImportsEntry ue in imports_list) {
521 //TODO: deal with standard modules
\r
522 match = TypeManager.LookupType (MakeFQN (ue.Name, name));
\r
523 if (match != null){
\r
525 DeclSpace.Error_AmbiguousTypeReference (loc, name, t, match);
\r
537 // Try with aliases
\r
539 string a = sourceBeingCompiled.LookupAlias (name);
\r
541 t = TypeManager.LookupType (a);
\r
545 t = TypeManager.LookupType (MakeFQN (a, name));
\r
555 // Public function used to locate types, this can only
\r
556 // be used after the ResolveTree function has been invoked.
\r
558 // Returns: Type or null if they type can not be found.
\r
560 // Come to think of it, this should be a DeclSpace
\r
562 static public Type LookupType (DeclSpace ds, string name, bool silent, Location loc)
\r
566 if (ds.Cache.Contains (name)){
\r
567 t = (Type) ds.Cache [name];
\r
572 // For the case the type we are looking for is nested within this one
\r
573 // or is in any base class
\r
575 DeclSpace containing_ds = ds;
\r
576 while (containing_ds != null){
\r
577 Type current_type = containing_ds.TypeBuilder;
\r
579 while (current_type != null) {
\r
583 t = TypeManager.LookupType (current_type.FullName + "." + name);
\r
585 ds.Cache [name] = t;
\r
589 current_type = current_type.BaseType;
\r
592 containing_ds = containing_ds.Parent;
\r
595 t = NamespaceLookup (ds.Namespace, name, loc);
\r
597 ds.Cache [name] = t;
\r
603 Report.Error (246, loc, "Cannot find type `"+name+"'");
\r
609 // This is the silent version of LookupType, you can use this
\r
610 // to `probe' for a type
\r
612 static public Type LookupType (TypeContainer tc, string name, Location loc)
\r
614 return LookupType (tc, name, true, loc);
\r
617 static public bool IsNamespace (string name)
\r
621 if (tree.Namespaces != null){
\r
622 ns = (Namespace) tree.Namespaces [name];
\r
631 static void Report1530 (Location loc)
\r
633 Report.Error (1530, loc, "Keyword new not allowed for namespace elements");
\r
636 static public void PopulateCoreType (TypeContainer root, string name)
\r
638 DeclSpace ds = (DeclSpace) root.GetDefinition (name);
\r
640 ds.DefineMembers (root);
\r
644 static public void BootCorlib_PopulateCoreTypes ()
\r
646 TypeContainer root = tree.Types;
\r
648 PopulateCoreType (root, "System.Object");
\r
649 PopulateCoreType (root, "System.ValueType");
\r
650 PopulateCoreType (root, "System.Attribute");
\r
654 // Populates the structs and classes with fields and methods
\r
657 // This is invoked after all interfaces, structs and classes
\r
658 // have been defined through `ResolveTree'
\r
659 static public void PopulateTypes ()
\r
661 TypeContainer root = Tree.Types;
\r
663 if (attribute_types != null)
\r
664 foreach (TypeContainer tc in attribute_types)
\r
665 tc.DefineMembers (root);
\r
667 if (interface_resolve_order != null){
\r
668 foreach (Interface iface in interface_resolve_order)
\r
669 if ((iface.ModFlags & Modifiers.NEW) == 0)
\r
670 iface.DefineMembers (root);
\r
672 Report1530 (iface.Location);
\r
676 if (type_container_resolve_order != null){
\r
677 foreach (TypeContainer tc in type_container_resolve_order) {
\r
678 // When compiling corlib, these types have already been
\r
679 // populated from BootCorlib_PopulateCoreTypes ().
\r
680 if (!RootContext.StdLib &&
\r
681 ((tc.Name == "System.Object") ||
\r
682 (tc.Name == "System.Attribute") ||
\r
683 (tc.Name == "System.ValueType")))
\r
686 if ((tc.ModFlags & Modifiers.NEW) == 0)
\r
687 tc.DefineMembers (root);
\r
689 Report1530 (tc.Location);
\r
693 ArrayList delegates = root.Delegates;
\r
694 if (delegates != null){
\r
695 foreach (Delegate d in delegates)
\r
696 if ((d.ModFlags & Modifiers.NEW) == 0)
\r
697 d.DefineMembers (root);
\r
699 Report1530 (d.Location);
\r
702 ArrayList enums = root.Enums;
\r
703 if (enums != null){
\r
704 foreach (Enum en in enums)
\r
705 if ((en.ModFlags & Modifiers.NEW) == 0)
\r
706 en.DefineMembers (root);
\r
708 Report1530 (en.Location);
\r
712 static public void DefineTypes ()
\r
714 TypeContainer root = Tree.Types;
\r
716 if (attribute_types != null)
\r
717 foreach (TypeContainer tc in attribute_types)
\r
720 if (interface_resolve_order != null){
\r
721 foreach (Interface iface in interface_resolve_order)
\r
722 if ((iface.ModFlags & Modifiers.NEW) == 0)
\r
723 iface.Define (root);
\r
727 if (type_container_resolve_order != null){
\r
728 foreach (TypeContainer tc in type_container_resolve_order) {
\r
729 // When compiling corlib, these types have already been
\r
730 // populated from BootCorlib_PopulateCoreTypes ().
\r
731 if (!RootContext.StdLib &&
\r
732 ((tc.Name == "System.Object") ||
\r
733 (tc.Name == "System.Attribute") ||
\r
734 (tc.Name == "System.ValueType")))
\r
737 if ((tc.ModFlags & Modifiers.NEW) == 0)
\r
742 ArrayList delegates = root.Delegates;
\r
743 if (delegates != null){
\r
744 foreach (Delegate d in delegates)
\r
745 if ((d.ModFlags & Modifiers.NEW) == 0)
\r
749 ArrayList enums = root.Enums;
\r
750 if (enums != null){
\r
751 foreach (Enum en in enums)
\r
752 if ((en.ModFlags & Modifiers.NEW) == 0)
\r
757 static public void EmitCode ()
\r
760 // Because of the strange way in which we do things, global
\r
761 // attributes must be processed first.
\r
763 if (global_attributes.Count > 0){
\r
764 AssemblyBuilder ab = CodeGen.AssemblyBuilder;
\r
765 TypeContainer dummy = new TypeContainer (null, "", new Location (-1, 0));
\r
766 EmitContext temp_ec = new EmitContext (
\r
767 dummy, Mono.MonoBASIC.Location.Null, null, null, 0, false);
\r
769 foreach (DictionaryEntry de in global_attributes){
\r
770 Namespace ns = (Namespace) de.Key;
\r
771 Attributes attrs = (Attributes) de.Value;
\r
773 dummy.Namespace = ns;
\r
774 Attribute.ApplyAttributes (temp_ec, ab, ab, attrs, attrs.Location);
\r
778 if (attribute_types != null)
\r
779 foreach (TypeContainer tc in attribute_types)
\r
782 if (type_container_resolve_order != null) {
\r
783 foreach (TypeContainer tc in type_container_resolve_order)
\r
784 tc.EmitConstants ();
\r
786 foreach (TypeContainer tc in type_container_resolve_order)
\r
791 if (TypeManager.unverifiable_code_ctor == null) {
\r
792 Console.WriteLine ("Internal error ! Cannot set unverifiable code attribute.");
\r
796 CustomAttributeBuilder cb = new CustomAttributeBuilder (TypeManager.unverifiable_code_ctor, new object [0]);
\r
797 CodeGen.ModuleBuilder.SetCustomAttribute (cb);
\r
802 // Public Field, used to track which method is the public entry
\r
805 static public MethodInfo EntryPoint;
\r
808 // Track the location of the entry point.
\r
810 static public Location EntryPointLocation;
\r
813 // These are used to generate unique names on the structs and fields.
\r
815 static int field_count;
\r
818 // Makes an initialized struct, returns the field builder that
\r
819 // references the data. Thanks go to Sergey Chaban for researching
\r
820 // how to do this. And coming up with a shorter mechanism than I
\r
821 // was able to figure out.
\r
823 // This works but makes an implicit public struct $ArrayType$SIZE and
\r
824 // makes the fields point to it. We could get more control if we did
\r
827 // 1. DefineNestedType on the impl_details_class with our struct.
\r
829 // 2. Define the field on the impl_details_class
\r
831 static public FieldBuilder MakeStaticData (byte [] data)
\r
834 int size = data.Length;
\r
836 if (impl_details_class == null)
\r
837 impl_details_class = CodeGen.ModuleBuilder.DefineType (
\r
838 "<PrivateImplementationDetails>", TypeAttributes.NotPublic, TypeManager.object_type);
\r
840 fb = impl_details_class.DefineInitializedData (
\r
841 "$$field-" + (field_count++), data,
\r
842 FieldAttributes.Static | FieldAttributes.Assembly);
\r
848 // Adds a global attribute that was declared in `container',
\r
849 // the attribute is in `attr', and it was defined at `loc'
\r
851 static public void AddGlobalAttribute (TypeContainer container,
\r
852 AttributeSection attr, Location loc)
\r
854 Namespace ns = container.Namespace;
\r
855 Attributes a = (Attributes) global_attributes [ns];
\r
858 global_attributes [ns] = new Attributes (attr, loc);
\r
860 a.AddAttribute (attr);
\r
864 // Adds a global attribute that was declared in `container',
\r
865 // the attribute is in `attr', and it was defined at `loc'
\r
867 static public void AddGlobalAttributeSection (TypeContainer container, AttributeSection attr)
\r
869 Namespace ns = container.Namespace;
\r
870 Attributes a = (Attributes) global_attributes [ns];
\r
873 global_attributes [ns] = new Attributes (attr, Location.Null);
\r
875 a.AddAttributeSection (attr);
\r