// // rootcontext.cs: keeps track of our tree representation, and assemblies loaded. // // Author: Miguel de Icaza (miguel@ximian.com) // // Licensed under the terms of the GNU GPL // // (C) 2001 Ximian, Inc (http://www.ximian.com) using System; using System.Collections; using System.Reflection; using System.Reflection.Emit; using System.Diagnostics; namespace CIR { public class RootContext { // // Contains the parsed tree // Tree tree; // // Contains loaded assemblies and our generated code as we go. // TypeManager type_manager; // // The System.Reflection.Emit CodeGenerator // CilCodeGen cg; // // The module builder pointer // ModuleBuilder mb; // // Error reporting object // Report report; // // The `System.Object' type, as it is used so often. // Type object_type; // // Whether we are being linked against the standard libraries. // This is only used to tell whether `System.Object' should // have a parent or not. // bool stdlib = true; public RootContext () { tree = new Tree (); type_manager = new TypeManager (); report = new Report (); object_type = System.Type.GetType ("System.Object"); } public TypeManager TypeManager { get { return type_manager; } } public Tree Tree { get { return tree; } } public CilCodeGen CodeGen { get { return cg; } set { // // Temporary hack, we should probably // intialize `cg' rather than depending on // external initialization of it. // cg = value; mb = cg.ModuleBuilder; } } // // Returns the Type that represents the interface whose name // is `name'. // Type GetInterfaceTypeByName (string name) { Interface parent; Type t = type_manager.LookupType (name); if (t != null) { if (t.IsInterface) return t; string cause; if (t.IsValueType) cause = "is a struct"; else if (t.IsClass) cause = "is a class"; else cause = "Should not happen."; report.Error (527, "`"+name+"' " + cause + ", need an interface instead"); return null; } parent = (Interface) tree.Interfaces [name]; if (parent == null){ string cause = "is undefined"; if (tree.Classes [name] != null) cause = "is a class"; else if (tree.Structs [name] != null) cause = "is a struct"; report.Error (527, "`"+name+"' " + cause + ", need an interface instead"); return null; } t = CreateInterface ((Interface) parent); if (t == null){ report.Error (529, "Inherited interface `"+name+"' is circular"); return null; } return t; } // // Returns the list of interfaces that this interface implements // Or null if it does not implement any interface. // // Sets the error boolean accoringly. // Type [] GetInterfaceBases (Interface iface, out bool error) { ArrayList bases = iface.Bases; Type [] tbases; int i; error = false; if (bases == null) return null; tbases = new Type [bases.Count]; i = 0; foreach (string name in iface.Bases){ Type t; t = GetInterfaceTypeByName (name); if (t == null){ error = true; return null; } tbases [i++] = t; } return tbases; } // // Creates the Interface @iface using the ModuleBuilder // // TODO: // Rework the way we recurse, because for recursive // definitions of interfaces (A:B and B:A) we report the // error twice, rather than once. // TypeBuilder CreateInterface (Interface iface) { TypeBuilder tb = iface.Definition; Type [] ifaces; string name; bool error; if (tb != null) return tb; if (iface.InTransit) return null; iface.InTransit = true; name = iface.Name; ifaces = GetInterfaceBases (iface, out error); if (error) return null; tb = mb.DefineType (name, TypeAttributes.Interface | TypeAttributes.Public | TypeAttributes.Abstract, null, // Parent Type ifaces); iface.Definition = tb; type_manager.AddUserType (name, tb); iface.InTransit = false; return tb; } // // Returns the type for an interface or a class // Type GetInterfaceOrClass (string name) { Type t = type_manager.LookupType (name); Class parent; if (t != null) return t; parent = (Class) tree.Classes [name]; if (parent == null){ report.Error (246, "Can not find type `"+name+"'"); return null; } t = CreateClass ((Class) parent); if (t == null){ report.Error (146, "Class definition is circular: `"+name+"'"); return null; } return t; } static bool ugliness_shown = false; // // This function computes the Base class and also the // list of interfaces that the class @c implements. // // The return value is an array (might be null) of // interfaces implemented (as Types). // // The @parent argument is set to the parent object or null // if this is `System.Object'. // Type [] GetClassBases (Class c, out Type parent, out bool error) { ArrayList bases = c.Bases; int count; int start, j, i; error = false; parent = null; if (bases == null){ if (stdlib) parent = object_type; else if (c.Name != "System.Object") parent = object_type; return null; } // // Bases should be null if there are no bases at all // count = bases.Count; Debug.Assert (count > 0); if (!ugliness_shown){ Console.WriteLine ("This is horrid, kill TypeRef and TypeRefManager in type.cs"); ugliness_shown = true; } string name = ((TypeRef) bases [0]).UnresolvedData.Name; Type first = GetInterfaceOrClass (name); if (first == null){ Console.WriteLine ("Handle Struct miguel!"); return null; } if (first.IsClass){ parent = first; start = 1; } else { parent = object_type; start = 0; } // // No interfaces // if (count == 1) return null; Type [] ifaces = new Type [count-start]; for (i = start, j = 0; i < count; i++, j++){ name = ((TypeRef) bases [i]).UnresolvedData.Name; Type t = GetInterfaceOrClass (name); if (t == null){ error = true; return null; } if (t.IsSealed) { string detail = ""; if (t.IsValueType) detail = " (a class can not inherit from a struct)"; report.Error (509, "class `"+c.Name+ "': Cannot inherit from sealed class `"+ bases [i]+"'"+detail); error = true; return null; } if (t.IsClass) { if (parent != null){ report.Error (527, "In Class `"+c.Name+"', type `"+ name+"' is not an interface"); error = true; return null; } } ifaces [j] = t; } return ifaces; } // // Creates the TypeBuilder for the class @c. // // TypeBuilder CreateClass (Class c) { TypeBuilder tb = c.Definition; Type parent; Type [] ifaces; bool error; string name; if (tb != null) return tb; if (c.InTransit) return null; c.InTransit = true; name = c.Name; ifaces = GetClassBases (c, out parent, out error); if (error) return null; tb = mb.DefineType (name, c.TypeAttr | TypeAttributes.Class, parent, ifaces); c.Definition = tb; type_manager.AddUserType (name, tb); c.InTransit = false; return tb; } TypeBuilder CreateStruct (Struct s) { // FIXME: I should really just reuse the code above. // return null; } // // This function is used to resolve the hierarchy tree. // It processes interfaces, structs and classes in that order. // // It creates the TypeBuilder's as it processes the user defined // types. // public void ResolveTree () { Hashtable ifaces, classes, structs; // // Interfaces are processed first, as classes and // structs might inherit from an object or implement // a set of interfaces, we need to be able to tell // them appart by just using the TypeManager. // ifaces = tree.Interfaces; if (ifaces != null){ foreach (DictionaryEntry de in ifaces) CreateInterface ((Interface) de.Value); } // // Process structs and classes next. Our code assumes // this order (just for error reporting purposes). // structs = tree.Structs; if (structs != null){ foreach (DictionaryEntry de in structs) CreateStruct ((Struct) de.Value); } classes = tree.Classes; if (classes != null){ foreach (DictionaryEntry de in classes) CreateClass ((Class) de.Value); } } // // Closes all open types // // // // We usually use TypeBuilder types. When we are done // creating the type (which will happen after we have addded // methods, fields, etc) we need to "Define" them before we // can save the Assembly // public void CloseTypes () { foreach (TypeBuilder t in type_manager.UserTypes){ t.CreateType (); } } // // Compiling against Standard Libraries property. // public bool StdLib { get { return stdlib; } set { stdlib = value; } } public Report Report { get { return report; } } } }