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 // Error reporting object
46 // The `System.Object' and `System.ValueType' types, as they
53 // Whether we are being linked against the standard libraries.
54 // This is only used to tell whether `System.Object' should
55 // have a parent or not.
61 tree = new Tree (this);
62 TypeManager = new TypeManager ();
63 report = new Report ();
65 object_type = System.Type.GetType ("System.Object");
66 value_type = System.Type.GetType ("System.ValueType");
75 public CodeGen CodeGen {
82 // Temporary hack, we should probably
83 // intialize `cg' rather than depending on
84 // external initialization of it.
87 mb = cg.ModuleBuilder;
92 // Returns the Type that represents the interface whose name
96 Type GetInterfaceTypeByName (string name)
99 Type t = TypeManager.LookupType (name);
109 cause = "is a struct";
111 cause = "is a class";
113 cause = "Should not happen.";
115 report.Error (527, "`"+name+"' " + cause + ", need an interface instead");
120 parent = (Interface) tree.Interfaces [name];
122 string cause = "is undefined";
124 if (tree.Classes [name] != null)
125 cause = "is a class";
126 else if (tree.Structs [name] != null)
127 cause = "is a struct";
129 report.Error (527, "`"+name+"' " + cause + ", need an interface instead");
133 t = CreateInterface ((Interface) parent);
136 "Inherited interface `"+name+"' is circular");
144 // Returns the list of interfaces that this interface implements
145 // Or null if it does not implement any interface.
147 // Sets the error boolean accoringly.
149 Type [] GetInterfaceBases (Interface iface, out bool error)
151 ArrayList bases = iface.Bases;
159 tbases = new Type [bases.Count];
162 foreach (string name in iface.Bases){
165 t = GetInterfaceTypeByName (name);
178 // Creates the Interface @iface using the ModuleBuilder
181 // Rework the way we recurse, because for recursive
182 // definitions of interfaces (A:B and B:A) we report the
183 // error twice, rather than once.
185 TypeBuilder CreateInterface (Interface iface)
187 TypeBuilder tb = iface.TypeBuilder;
198 iface.InTransit = true;
202 ifaces = GetInterfaceBases (iface, out error);
207 tb = mb.DefineType (name,
208 TypeAttributes.Interface |
209 iface.InterfaceAttr |
210 TypeAttributes.Abstract,
213 iface.TypeBuilder = tb;
215 TypeManager.AddUserType (name, tb);
217 iface.InTransit = false;
221 string MakeFQN (string nsn, string name)
223 string prefix = (nsn == "" ? "" : nsn + ".");
225 return prefix + name;
228 Type LookupInterfaceOrClass (string ns, string name, bool is_class, out bool error)
230 TypeContainer parent;
234 name = MakeFQN (ns, name);
236 t = TypeManager.LookupType (name);
241 parent = (Class) tree.Classes [name];
243 parent = (Struct) tree.Structs [name];
247 t = CreateType (parent, is_class);
249 report.Error (146, "Class definition is circular: `"+name+"'");
261 // returns the type for an interface or a class, this will recursively
262 // try to define the types that it depends on.
264 Type GetInterfaceOrClass (TypeContainer tc, string name, bool is_class)
270 // Attempt to lookup the class on our namespace
272 t = LookupInterfaceOrClass (tc.Namespace.Name, name, is_class, out error);
280 // Attempt to lookup the class on any of the `using'
284 for (Namespace ns = tc.Namespace; ns != null; ns = ns.Parent){
285 ArrayList using_list = ns.UsingTable;
287 if (using_list == null)
290 foreach (string n in using_list){
291 t = LookupInterfaceOrClass (n, name, is_class, out error);
300 report.Error (246, "Can not find type `"+name+"'");
305 // This function computes the Base class and also the
306 // list of interfaces that the class or struct @c implements.
308 // The return value is an array (might be null) of
309 // interfaces implemented (as Types).
311 // The @parent argument is set to the parent object or null
312 // if this is `System.Object'.
314 Type [] GetClassBases (TypeContainer tc, bool is_class, out Type parent, out bool error)
316 ArrayList bases = tc.Bases;
330 parent = object_type;
331 else if (tc.Name != "System.Object")
332 parent = object_type;
335 // If we are compiling our runtime,
336 // and we are defining ValueType, then our
337 // parent is `System.Object'.
339 if (!stdlib && tc. Name == "System.ValueType")
340 parent = object_type;
347 // Bases should be null if there are no bases at all
350 Debug.Assert (count > 0);
353 string name = (string) bases [0];
354 Type first = GetInterfaceOrClass (tc, name, is_class);
365 parent = object_type;
372 Type [] ifaces = new Type [count-start];
374 for (i = start, j = 0; i < count; i++, j++){
375 string name = (string) bases [i];
376 Type t = GetInterfaceOrClass (tc, name, is_class);
383 if (is_class == false && !t.IsInterface){
384 report.Error (527, "In Struct `"+tc.Name+"', type `"+
385 name+"' is not an interface");
394 detail = " (a class can not inherit from a struct)";
396 report.Error (509, "class `"+tc.Name+
397 "': Cannot inherit from sealed class `"+
398 bases [i]+"'"+detail);
405 report.Error (527, "In Class `"+tc.Name+"', type `"+
406 name+"' is not an interface");
419 // Creates the TypeBuilder for the TypeContainer @tc (a Class or a Struct)
422 TypeBuilder CreateType (TypeContainer tc, bool is_class)
424 TypeBuilder tb = tc.TypeBuilder;
439 ifaces = GetClassBases (tc, is_class, out parent, out error);
444 tb = mb.DefineType (name,
445 tc.TypeAttr | TypeAttributes.Class,
450 TypeManager.AddUserType (name, tb, tc);
451 tc.InTransit = false;
457 // This function is used to resolve the hierarchy tree.
458 // It processes interfaces, structs and classes in that order.
460 // It creates the TypeBuilder's as it processes the user defined
463 public void ResolveTree ()
465 Hashtable ifaces, classes, structs;
468 // Interfaces are processed first, as classes and
469 // structs might inherit from an object or implement
470 // a set of interfaces, we need to be able to tell
471 // them appart by just using the TypeManager.
473 ifaces = tree.Interfaces;
475 foreach (DictionaryEntry de in ifaces)
476 CreateInterface ((Interface) de.Value);
480 // Process structs and classes next. Our code assumes
481 // this order (just for error reporting purposes).
483 structs = tree.Structs;
484 if (structs != null){
485 foreach (DictionaryEntry de in structs)
486 CreateType ((Struct) de.Value, false);
489 classes = tree.Classes;
490 if (classes != null){
491 foreach (DictionaryEntry de in classes)
492 CreateType ((Class) de.Value, true);
497 // Closes all open types
501 // We usually use TypeBuilder types. When we are done
502 // creating the type (which will happen after we have added
503 // methods, fields, etc) we need to "Define" them before we
504 // can save the Assembly
506 public void CloseTypes ()
508 foreach (TypeBuilder t in TypeManager.UserTypes){
514 // Public function used to locate types, this can only
515 // be used after the ResolveTree function has been invoked.
517 // Returns: Type or null if they type can not be found.
519 public Type LookupType (TypeContainer tc, string name, bool silent)
523 t = TypeManager.LookupType (MakeFQN (tc.Namespace.Name, name));
527 // It's possible that name already is fully qualified. So we do
528 // a simple direct lookup without adding any namespace names
530 t = TypeManager.LookupType (name);
534 for (Namespace ns = tc.Namespace; ns != null; ns = ns.Parent){
535 ArrayList using_list = ns.UsingTable;
537 if (using_list == null)
540 foreach (string n in using_list){
541 t = TypeManager.LookupType (MakeFQN (n, name));
548 report.Error (246, "Cannot find type `"+name+"'");
553 public Type LookupType (TypeContainer tc, string name)
555 return LookupType (tc, name, true);
558 public bool IsNamespace (string name)
562 if (tree.Namespaces != null){
563 ns = (Namespace) tree.Namespaces [name];
573 // Populates the structs and classes with fields and methods
576 // This is invoked after all interfaces, structs and classes
577 // have been defined through `ResolveTree'
578 public void PopulateTypes ()
580 Hashtable ifaces, classes;
582 if ((ifaces = tree.Interfaces) != null){
583 foreach (DictionaryEntry de in ifaces){
584 Interface iface = (Interface) de.Value;
590 if ((classes = tree.Classes) != null){
591 foreach (DictionaryEntry de in classes){
592 TypeContainer tc = (TypeContainer) de.Value;
599 public void EmitCode ()
603 if ((classes = tree.Classes) != null){
604 foreach (DictionaryEntry de in classes){
605 TypeContainer tc = (TypeContainer) de.Value;
613 // Compiling against Standard Libraries property.
625 public Report Report {
632 // Public Field, used to track which method is the public entry
635 public MethodInfo EntryPoint;