2 // rootcontext.cs: keeps track of our tree representation, and assemblies loaded.
4 // Author: Miguel de Icaza (miguel@ximian.com)
6 // Licensed under the terms of the GNU GPL
8 // (C) 2001 Ximian, Inc (http://www.ximian.com)
11 using System.Collections;
12 using System.Reflection;
13 using System.Reflection.Emit;
14 using System.Diagnostics;
18 public class RootContext {
21 // Contains the parsed tree
26 // Contains loaded assemblies and our generated code as we go.
28 public TypeManager TypeManager;
31 // The System.Reflection.Emit CodeGenerator
36 // The module builder pointer
41 // Whether we are being linked against the standard libraries.
42 // This is only used to tell whether `System.Object' should
43 // have a parent or not.
48 // This keeps track of the order in which classes were defined
49 // so that we can poulate them in that order.
51 // Order is important, because we need to be able to tell by
52 // examining the parent's list of methods which ones are virtual
53 // or abstract as well as the parent names (to implement new,
56 ArrayList type_container_resolve_order;
57 ArrayList interface_resolve_order;
61 tree = new Tree (this);
62 TypeManager = new TypeManager ();
71 public CodeGen CodeGen {
78 // Temporary hack, we should probably
79 // intialize `cg' rather than depending on
80 // external initialization of it.
83 mb = cg.ModuleBuilder;
88 // Returns the Type that represents the interface whose name
92 Type GetInterfaceTypeByName (string name)
95 Type t = TypeManager.LookupType (name);
105 cause = "is a struct";
107 cause = "is a class";
109 cause = "Should not happen.";
111 Report.Error (527, "`"+name+"' " + cause + ", need an interface instead");
116 parent = (Interface) tree.Interfaces [name];
118 string cause = "is undefined";
120 if (tree.Classes [name] != null)
121 cause = "is a class";
122 else if (tree.Structs [name] != null)
123 cause = "is a struct";
125 Report.Error (527, "`"+name+"' " + cause + ", need an interface instead");
129 t = CreateInterface ((Interface) parent);
132 "Inherited interface `"+name+"' is circular");
140 // Returns the list of interfaces that this interface implements
141 // Or null if it does not implement any interface.
143 // Sets the error boolean accoringly.
145 Type [] GetInterfaceBases (Interface iface, out bool error)
147 ArrayList bases = iface.Bases;
155 tbases = new Type [bases.Count];
158 foreach (string name in iface.Bases){
161 t = GetInterfaceTypeByName (name);
174 // Creates the Interface @iface using the ModuleBuilder
177 // Rework the way we recurse, because for recursive
178 // definitions of interfaces (A:B and B:A) we report the
179 // error twice, rather than once.
181 TypeBuilder CreateInterface (Interface iface)
183 TypeBuilder tb = iface.TypeBuilder;
194 iface.InTransit = true;
198 ifaces = GetInterfaceBases (iface, out error);
203 tb = mb.DefineType (name,
204 TypeAttributes.Interface |
205 iface.InterfaceAttr |
206 TypeAttributes.Abstract,
209 iface.TypeBuilder = tb;
211 interface_resolve_order.Add (iface);
213 TypeManager.AddUserInterface (name, tb, iface);
215 iface.InTransit = false;
220 string MakeFQN (string nsn, string name)
222 string prefix = (nsn == "" ? "" : nsn + ".");
224 return prefix + name;
227 Type LookupInterfaceOrClass (string ns, string name, bool is_class, out bool error)
229 TypeContainer parent;
233 name = MakeFQN (ns, name);
235 t = TypeManager.LookupType (name);
240 parent = (Class) tree.Classes [name];
242 parent = (Struct) tree.Structs [name];
246 t = CreateType (parent, is_class);
248 Report.Error (146, "Class definition is circular: `"+name+"'");
260 // returns the type for an interface or a class, this will recursively
261 // try to define the types that it depends on.
263 Type GetInterfaceOrClass (TypeContainer tc, string name, bool is_class)
269 // Attempt to lookup the class on our namespace
271 t = LookupInterfaceOrClass (tc.Namespace.Name, name, is_class, out error);
279 // Attempt to lookup the class on any of the `using'
283 for (Namespace ns = tc.Namespace; ns != null; ns = ns.Parent){
284 ArrayList using_list = ns.UsingTable;
286 if (using_list == null)
289 foreach (string n in using_list){
290 t = LookupInterfaceOrClass (n, name, is_class, out error);
299 Report.Error (246, "Can not find type `"+name+"'");
304 // This function computes the Base class and also the
305 // list of interfaces that the class or struct @c implements.
307 // The return value is an array (might be null) of
308 // interfaces implemented (as Types).
310 // The @parent argument is set to the parent object or null
311 // if this is `System.Object'.
313 Type [] GetClassBases (TypeContainer tc, bool is_class, out Type parent, out bool error)
315 ArrayList bases = tc.Bases;
324 parent = TypeManager.value_type;
329 parent = TypeManager.object_type;
330 else if (tc.Name != "System.Object")
331 parent = TypeManager.object_type;
334 // If we are compiling our runtime,
335 // and we are defining ValueType, then our
336 // parent is `System.Object'.
338 if (!stdlib && tc. Name == "System.ValueType")
339 parent = TypeManager.object_type;
346 // Bases should be null if there are no bases at all
349 Debug.Assert (count > 0);
352 string name = (string) bases [0];
353 Type first = GetInterfaceOrClass (tc, name, is_class);
364 parent = TypeManager.object_type;
371 Type [] ifaces = new Type [count-start];
373 for (i = start, j = 0; i < count; i++, j++){
374 string name = (string) bases [i];
375 Type t = GetInterfaceOrClass (tc, name, is_class);
382 if (is_class == false && !t.IsInterface){
383 Report.Error (527, "In Struct `"+tc.Name+"', type `"+
384 name+"' is not an interface");
393 detail = " (a class can not inherit from a struct)";
395 Report.Error (509, "class `"+tc.Name+
396 "': Cannot inherit from sealed class `"+
397 bases [i]+"'"+detail);
404 Report.Error (527, "In Class `"+tc.Name+"', type `"+
405 name+"' is not an interface");
418 // Creates the TypeBuilder for the TypeContainer @tc (a Class or a Struct)
421 TypeBuilder CreateType (TypeContainer tc, bool is_class)
423 TypeBuilder tb = tc.TypeBuilder;
438 ifaces = GetClassBases (tc, is_class, out parent, out error);
443 type_container_resolve_order.Add (tc);
447 tc.TypeAttr | TypeAttributes.Class,
453 TypeManager.AddUserType (name, tb, tc);
454 tc.InTransit = false;
460 // This function is used to resolve the hierarchy tree.
461 // It processes interfaces, structs and classes in that order.
463 // It creates the TypeBuilder's as it processes the user defined
466 public void ResolveTree ()
468 Hashtable ifaces, classes, structs;
470 type_container_resolve_order = new ArrayList ();
473 // Interfaces are processed first, as classes and
474 // structs might inherit from an object or implement
475 // a set of interfaces, we need to be able to tell
476 // them appart by just using the TypeManager.
478 ifaces = tree.Interfaces;
480 interface_resolve_order = new ArrayList ();
482 foreach (DictionaryEntry de in ifaces)
483 CreateInterface ((Interface) de.Value);
487 // Process structs and classes next. Our code assumes
488 // this order (just for error reporting purposes).
490 structs = tree.Structs;
491 if (structs != null){
492 foreach (DictionaryEntry de in structs)
493 CreateType ((Struct) de.Value, false);
496 classes = tree.Classes;
497 if (classes != null){
498 foreach (DictionaryEntry de in classes)
499 CreateType ((Class) de.Value, true);
504 // Closes all open types
508 // We usually use TypeBuilder types. When we are done
509 // creating the type (which will happen after we have added
510 // methods, fields, etc) we need to "Define" them before we
511 // can save the Assembly
513 public void CloseTypes ()
515 foreach (TypeBuilder t in TypeManager.UserTypes){
518 } catch (Exception e){
519 Console.WriteLine ("Caught Exception while creating type for " + t);
520 Console.WriteLine (e);
526 // Public function used to locate types, this can only
527 // be used after the ResolveTree function has been invoked.
529 // Returns: Type or null if they type can not be found.
531 public Type LookupType (TypeContainer tc, string name, bool silent)
535 t = TypeManager.LookupType (MakeFQN (tc.Namespace.Name, name));
539 // It's possible that name already is fully qualified. So we do
540 // a simple direct lookup without adding any namespace names
542 t = TypeManager.LookupType (name);
546 for (Namespace ns = tc.Namespace; ns != null; ns = ns.Parent){
547 ArrayList using_list = ns.UsingTable;
549 if (using_list == null)
552 foreach (string n in using_list){
553 t = TypeManager.LookupType (MakeFQN (n, name));
560 Report.Error (246, "Cannot find type `"+name+"'");
565 public Type LookupType (TypeContainer tc, string name)
567 return LookupType (tc, name, true);
570 public bool IsNamespace (string name)
574 if (tree.Namespaces != null){
575 ns = (Namespace) tree.Namespaces [name];
585 // Populates the structs and classes with fields and methods
588 // This is invoked after all interfaces, structs and classes
589 // have been defined through `ResolveTree'
590 public void PopulateTypes ()
592 if (interface_resolve_order != null)
593 foreach (Interface iface in interface_resolve_order)
596 if (type_container_resolve_order != null)
597 foreach (TypeContainer tc in type_container_resolve_order)
601 public void EmitCode ()
603 Hashtable classes, structs;
605 if ((classes = tree.Classes) != null){
606 foreach (DictionaryEntry de in classes){
607 TypeContainer tc = (TypeContainer) de.Value;
613 if ((structs = tree.Structs) != null){
614 foreach (DictionaryEntry de in structs){
615 TypeContainer tc = (TypeContainer) de.Value;
623 // Compiling against Standard Libraries property.
636 // Public Field, used to track which method is the public entry
639 public MethodInfo EntryPoint;