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.
60 // This keeps track of the order in which classes were defined
61 // so that we can poulate them in that order.
63 // Order is important, because we need to be able to tell by
64 // examining the parent's list of methods which ones are virtual
65 // or abstract as well as the parent names (to implement new,
68 ArrayList type_container_resolve_order;
69 ArrayList interface_resolve_order;
73 tree = new Tree (this);
74 TypeManager = new TypeManager ();
75 report = new Report ();
77 object_type = System.Type.GetType ("System.Object");
78 value_type = System.Type.GetType ("System.ValueType");
87 public CodeGen CodeGen {
94 // Temporary hack, we should probably
95 // intialize `cg' rather than depending on
96 // external initialization of it.
99 mb = cg.ModuleBuilder;
104 // Returns the Type that represents the interface whose name
108 Type GetInterfaceTypeByName (string name)
111 Type t = TypeManager.LookupType (name);
121 cause = "is a struct";
123 cause = "is a class";
125 cause = "Should not happen.";
127 report.Error (527, "`"+name+"' " + cause + ", need an interface instead");
132 parent = (Interface) tree.Interfaces [name];
134 string cause = "is undefined";
136 if (tree.Classes [name] != null)
137 cause = "is a class";
138 else if (tree.Structs [name] != null)
139 cause = "is a struct";
141 report.Error (527, "`"+name+"' " + cause + ", need an interface instead");
145 t = CreateInterface ((Interface) parent);
148 "Inherited interface `"+name+"' is circular");
156 // Returns the list of interfaces that this interface implements
157 // Or null if it does not implement any interface.
159 // Sets the error boolean accoringly.
161 Type [] GetInterfaceBases (Interface iface, out bool error)
163 ArrayList bases = iface.Bases;
171 tbases = new Type [bases.Count];
174 foreach (string name in iface.Bases){
177 t = GetInterfaceTypeByName (name);
190 // Creates the Interface @iface using the ModuleBuilder
193 // Rework the way we recurse, because for recursive
194 // definitions of interfaces (A:B and B:A) we report the
195 // error twice, rather than once.
197 TypeBuilder CreateInterface (Interface iface)
199 TypeBuilder tb = iface.TypeBuilder;
210 iface.InTransit = true;
214 ifaces = GetInterfaceBases (iface, out error);
219 tb = mb.DefineType (name,
220 TypeAttributes.Interface |
221 iface.InterfaceAttr |
222 TypeAttributes.Abstract,
225 iface.TypeBuilder = tb;
227 interface_resolve_order.Add (iface);
229 TypeManager.AddUserType (name, tb);
231 iface.InTransit = false;
235 string MakeFQN (string nsn, string name)
237 string prefix = (nsn == "" ? "" : nsn + ".");
239 return prefix + name;
242 Type LookupInterfaceOrClass (string ns, string name, bool is_class, out bool error)
244 TypeContainer parent;
248 name = MakeFQN (ns, name);
250 t = TypeManager.LookupType (name);
255 parent = (Class) tree.Classes [name];
257 parent = (Struct) tree.Structs [name];
261 t = CreateType (parent, is_class);
263 report.Error (146, "Class definition is circular: `"+name+"'");
275 // returns the type for an interface or a class, this will recursively
276 // try to define the types that it depends on.
278 Type GetInterfaceOrClass (TypeContainer tc, string name, bool is_class)
284 // Attempt to lookup the class on our namespace
286 t = LookupInterfaceOrClass (tc.Namespace.Name, name, is_class, out error);
294 // Attempt to lookup the class on any of the `using'
298 for (Namespace ns = tc.Namespace; ns != null; ns = ns.Parent){
299 ArrayList using_list = ns.UsingTable;
301 if (using_list == null)
304 foreach (string n in using_list){
305 t = LookupInterfaceOrClass (n, name, is_class, out error);
314 report.Error (246, "Can not find type `"+name+"'");
319 // This function computes the Base class and also the
320 // list of interfaces that the class or struct @c implements.
322 // The return value is an array (might be null) of
323 // interfaces implemented (as Types).
325 // The @parent argument is set to the parent object or null
326 // if this is `System.Object'.
328 Type [] GetClassBases (TypeContainer tc, bool is_class, out Type parent, out bool error)
330 ArrayList bases = tc.Bases;
344 parent = object_type;
345 else if (tc.Name != "System.Object")
346 parent = object_type;
349 // If we are compiling our runtime,
350 // and we are defining ValueType, then our
351 // parent is `System.Object'.
353 if (!stdlib && tc. Name == "System.ValueType")
354 parent = object_type;
361 // Bases should be null if there are no bases at all
364 Debug.Assert (count > 0);
367 string name = (string) bases [0];
368 Type first = GetInterfaceOrClass (tc, name, is_class);
379 parent = object_type;
386 Type [] ifaces = new Type [count-start];
388 for (i = start, j = 0; i < count; i++, j++){
389 string name = (string) bases [i];
390 Type t = GetInterfaceOrClass (tc, name, is_class);
397 if (is_class == false && !t.IsInterface){
398 report.Error (527, "In Struct `"+tc.Name+"', type `"+
399 name+"' is not an interface");
408 detail = " (a class can not inherit from a struct)";
410 report.Error (509, "class `"+tc.Name+
411 "': Cannot inherit from sealed class `"+
412 bases [i]+"'"+detail);
419 report.Error (527, "In Class `"+tc.Name+"', type `"+
420 name+"' is not an interface");
433 // Creates the TypeBuilder for the TypeContainer @tc (a Class or a Struct)
436 TypeBuilder CreateType (TypeContainer tc, bool is_class)
438 TypeBuilder tb = tc.TypeBuilder;
453 ifaces = GetClassBases (tc, is_class, out parent, out error);
458 type_container_resolve_order.Add (tc);
460 tb = mb.DefineType (name,
461 tc.TypeAttr | TypeAttributes.Class,
466 TypeManager.AddUserType (name, tb, tc);
467 tc.InTransit = false;
473 // This function is used to resolve the hierarchy tree.
474 // It processes interfaces, structs and classes in that order.
476 // It creates the TypeBuilder's as it processes the user defined
479 public void ResolveTree ()
481 Hashtable ifaces, classes, structs;
483 type_container_resolve_order = new ArrayList ();
486 // Interfaces are processed first, as classes and
487 // structs might inherit from an object or implement
488 // a set of interfaces, we need to be able to tell
489 // them appart by just using the TypeManager.
491 ifaces = tree.Interfaces;
493 interface_resolve_order = new ArrayList ();
495 foreach (DictionaryEntry de in ifaces)
496 CreateInterface ((Interface) de.Value);
500 // Process structs and classes next. Our code assumes
501 // this order (just for error reporting purposes).
503 structs = tree.Structs;
504 if (structs != null){
505 foreach (DictionaryEntry de in structs)
506 CreateType ((Struct) de.Value, false);
509 classes = tree.Classes;
510 if (classes != null){
511 foreach (DictionaryEntry de in classes)
512 CreateType ((Class) de.Value, true);
517 // Closes all open types
521 // We usually use TypeBuilder types. When we are done
522 // creating the type (which will happen after we have added
523 // methods, fields, etc) we need to "Define" them before we
524 // can save the Assembly
526 public void CloseTypes ()
528 foreach (TypeBuilder t in TypeManager.UserTypes){
531 } catch (Exception e){
532 Console.WriteLine ("Caught Exception while creating type for " + t);
533 Console.WriteLine (e);
539 // Public function used to locate types, this can only
540 // be used after the ResolveTree function has been invoked.
542 // Returns: Type or null if they type can not be found.
544 public Type LookupType (TypeContainer tc, string name, bool silent)
548 t = TypeManager.LookupType (MakeFQN (tc.Namespace.Name, name));
552 // It's possible that name already is fully qualified. So we do
553 // a simple direct lookup without adding any namespace names
555 t = TypeManager.LookupType (name);
559 for (Namespace ns = tc.Namespace; ns != null; ns = ns.Parent){
560 ArrayList using_list = ns.UsingTable;
562 if (using_list == null)
565 foreach (string n in using_list){
566 t = TypeManager.LookupType (MakeFQN (n, name));
573 report.Error (246, "Cannot find type `"+name+"'");
578 public Type LookupType (TypeContainer tc, string name)
580 return LookupType (tc, name, true);
583 public bool IsNamespace (string name)
587 if (tree.Namespaces != null){
588 ns = (Namespace) tree.Namespaces [name];
598 // Populates the structs and classes with fields and methods
601 // This is invoked after all interfaces, structs and classes
602 // have been defined through `ResolveTree'
603 public void PopulateTypes ()
605 if (interface_resolve_order != null)
606 foreach (Interface iface in interface_resolve_order)
609 if (type_container_resolve_order != null)
610 foreach (TypeContainer tc in type_container_resolve_order)
614 public void EmitCode ()
616 Hashtable classes, structs;
618 if ((classes = tree.Classes) != null){
619 foreach (DictionaryEntry de in classes){
620 TypeContainer tc = (TypeContainer) de.Value;
626 if ((structs = tree.Structs) != null){
627 foreach (DictionaryEntry de in structs){
628 TypeContainer tc = (TypeContainer) de.Value;
636 // Compiling against Standard Libraries property.
648 public Report Report {
655 // Public Field, used to track which method is the public entry
658 public MethodInfo EntryPoint;