// // interface.cs: Interface handler // // Author: Miguel de Icaza (miguel@gnu.org) // // Licensed under the terms of the GNU GPL // // (C) 2001 Ximian, Inc (http://www.ximian.com) // using System.Collections; using System; using System.IO; using System.Reflection; using System.Reflection.Emit; namespace CIR { public class Interface : DeclSpace { const MethodAttributes interface_method_attributes = MethodAttributes.Public | MethodAttributes.Abstract | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual; const MethodAttributes property_attributes = MethodAttributes.Public | MethodAttributes.Abstract | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.SpecialName | MethodAttributes.Virtual; ArrayList bases; int mod_flags; ArrayList defined_method; ArrayList defined_indexer; ArrayList defined_events; ArrayList defined_properties; ArrayList method_builders; TypeContainer parent; Attributes OptAttributes; public readonly RootContext RootContext; // These will happen after the semantic analysis // Hashtable defined_indexers; // Hashtable defined_methods; // // Modifiers allowed in a class declaration // public const int AllowedModifiers = Modifiers.NEW | Modifiers.PUBLIC | Modifiers.PROTECTED | Modifiers.INTERNAL | Modifiers.PRIVATE; public Interface (RootContext rc, TypeContainer parent, string name, int mod, Attributes attrs, Location l) : base (name, l) { this.mod_flags = Modifiers.Check (AllowedModifiers, mod, Modifiers.PUBLIC); this.parent = parent; OptAttributes = attrs; RootContext = rc; method_builders = new ArrayList (); } public AdditionResult AddMethod (InterfaceMethod imethod) { string name = imethod.Name; Object value = defined_names [name]; if (value != null){ if (!(value is InterfaceMethod)) return AdditionResult.NameExists; } if (defined_method == null) defined_method = new ArrayList (); defined_method.Add (imethod); if (value == null) DefineName (name, imethod); return AdditionResult.Success; } public AdditionResult AddProperty (InterfaceProperty iprop) { AdditionResult res; string name = iprop.Name; if ((res = IsValid (name)) != AdditionResult.Success) return res; DefineName (name, iprop); if (defined_properties == null) defined_properties = new ArrayList (); defined_properties.Add (iprop); return AdditionResult.Success; } public AdditionResult AddEvent (InterfaceEvent ievent) { string name = ievent.Name; AdditionResult res; if ((res = IsValid (name)) != AdditionResult.Success) return res; DefineName (name, ievent); if (defined_events == null) defined_events = new ArrayList (); defined_events.Add (ievent); return AdditionResult.Success; } public bool AddIndexer (InterfaceIndexer iindexer) { if (defined_indexer == null) defined_indexer = new ArrayList (); defined_indexer.Add (iindexer); return true; } public ArrayList InterfaceMethods { get { return defined_method; } } public ArrayList InterfaceProperties { get { return defined_properties; } } public ArrayList InterfaceEvents { get { return defined_events; } } public ArrayList InterfaceIndexers { get { return defined_indexer; } } public int ModFlags { get { return mod_flags; } } public ArrayList Bases { get { return bases; } set { bases = value; } } public bool IsTopLevel { get { if (parent != null){ if (parent.Parent == null) return true; } return false; } } public virtual TypeAttributes InterfaceAttr { get { TypeAttributes x = 0; if ((mod_flags & Modifiers.PUBLIC) != 0) x |= TypeAttributes.Public; else if ((mod_flags & Modifiers.PRIVATE) != 0) x |= TypeAttributes.NotPublic; if (IsTopLevel == false) { if ((mod_flags & Modifiers.PROTECTED) != 0 && (mod_flags & Modifiers.INTERNAL) != 0) x |= TypeAttributes.NestedFamORAssem; if ((mod_flags & Modifiers.PROTECTED) != 0) x |= TypeAttributes.NestedFamily; if ((mod_flags & Modifiers.INTERNAL) != 0) x |= TypeAttributes.NestedAssembly; } if ((mod_flags & Modifiers.ABSTRACT) != 0) x |= TypeAttributes.Abstract; if ((mod_flags & Modifiers.SEALED) != 0) x |= TypeAttributes.Sealed; return x; } } void Error111 (InterfaceMethod im) { Report.Error ( 111, "Interface `" + Name + "' already contains a definition with the " + "same return value and paramenter types for method `" + im.Name + "'"); } void RegisterMethod (MethodBase mb, Type [] types) { TypeManager.RegisterMethod (mb, types); method_builders.Add (mb); } public MethodInfo [] GetMethods () { int n = method_builders.Count; MethodInfo [] mi = new MethodInfo [n]; method_builders.CopyTo (mi, 0); return mi; } // // Populates the methods in the interface // void PopulateMethod (InterfaceMethod im) { Type return_type = parent.LookupType (im.ReturnType, true); Type [] arg_types = im.ParameterTypes (parent); MethodBuilder mb; Parameter [] p; int i; // // Create the method // mb = TypeBuilder.DefineMethod ( im.Name, interface_method_attributes, return_type, arg_types); RegisterMethod (mb, arg_types); // // Define each type attribute (in/out/ref) and // the argument names. // p = im.Parameters.FixedParameters; if (p != null){ for (i = 0; i < p.Length; i++) mb.DefineParameter (i + 1, p [i].Attributes, p [i].Name); if (i != arg_types.Length) Console.WriteLine ("Implement the type definition for params"); } } // // Populates the properties in the interface // void PopulateProperty (InterfaceProperty ip) { PropertyBuilder pb; MethodBuilder mb; Type prop_type = parent.LookupType (ip.Type, true); Type [] setter_args = new Type [1]; setter_args [0] = prop_type; // // FIXME: properties are missing the following // flags: hidebysig newslot specialname // pb = TypeBuilder.DefineProperty ( ip.Name, PropertyAttributes.None, prop_type, null); if (ip.HasGet){ mb = TypeBuilder.DefineMethod ( "get_" + ip.Name, property_attributes , prop_type, null); // // HACK because System.Reflection.Emit is lame // RegisterMethod (mb, null); pb.SetGetMethod (mb); } if (ip.HasSet){ setter_args [0] = prop_type; mb = TypeBuilder.DefineMethod ( "set_" + ip.Name, property_attributes, null, setter_args); mb.DefineParameter (1, ParameterAttributes.None, "value"); pb.SetSetMethod (mb); // // HACK because System.Reflection.Emit is lame // RegisterMethod (mb, setter_args); } } // // Populates the events in the interface // void PopulateEvent (InterfaceEvent ie) { // // FIXME: We need to do this after delegates have been // declared or we declare them recursively. // } // // Populates the indexers in the interface // void PopulateIndexer (InterfaceIndexer ii) { PropertyBuilder pb; Type prop_type = parent.LookupType (ii.Type, true); Type [] arg_types = ii.ParameterTypes (parent); Type [] value_arg_types; // // Sets up the extra invisible `value' argument for setters. // if (arg_types != null){ int count = arg_types.Length; value_arg_types = new Type [count + 1]; arg_types.CopyTo (value_arg_types, 0); value_arg_types [count] = prop_type; } else { value_arg_types = new Type [1]; value_arg_types [1] = prop_type; } pb = TypeBuilder.DefineProperty ( "Item", PropertyAttributes.None, prop_type, arg_types); if (ii.HasGet){ MethodBuilder get_item; Parameter [] p = ii.Parameters.FixedParameters; get_item = TypeBuilder.DefineMethod ( "get_Item", property_attributes, prop_type, arg_types); pb.SetGetMethod (get_item); // // HACK because System.Reflection.Emit is lame // RegisterMethod (get_item, arg_types); if (p != null){ for (int i = 0; i < p.Length; i++) get_item.DefineParameter ( i + 1, p [i].Attributes, p [i].Name); } } if (ii.HasSet){ Parameter [] p = ii.Parameters.FixedParameters; MethodBuilder set_item; int i = 0; set_item = TypeBuilder.DefineMethod ( "set_Item", property_attributes, null, value_arg_types); pb.SetSetMethod (set_item); // // HACK because System.Reflection.Emit is lame // RegisterMethod (set_item, value_arg_types); if (p != null){ for (; i < p.Length; i++) set_item.DefineParameter ( i + 1, p [i].Attributes, p [i].Name); } set_item.DefineParameter (i + 1, ParameterAttributes.None, "value"); } } // // Performs the semantic analysis for all the interface members // that were declared // bool SemanticAnalysis () { Hashtable methods = new Hashtable (); if (defined_method != null){ foreach (InterfaceMethod im in defined_method){ string sig = im.GetSignature (parent); // // If there was an undefined Type on the signatures // if (sig == null) continue; if (methods [sig] != null){ Error111 (im); return false; } } } // // FIXME: Here I should check i // return true; } // // Returns the Type that represents the interface whose name // is `name'. // Type GetInterfaceTypeByName (object builder, string name) { Interface parent; Type t = RootContext.TypeManager.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; } Tree tree = RootContext.Tree; 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 = parent.DefineInterface (builder); 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 (object builder, out bool error) { Type [] tbases; int i; error = false; if (Bases == null) return null; tbases = new Type [Bases.Count]; i = 0; foreach (string name in Bases){ Type t; t = GetInterfaceTypeByName (builder, name); if (t == null){ error = true; return null; } tbases [i++] = t; } return tbases; } // // // Defines the Interface in the appropriate ModuleBuilder or TypeBuilder // // 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. public TypeBuilder DefineInterface (object parent_builder) { Type [] ifaces; bool error; if (InTransit) return null; InTransit = true; ifaces = GetInterfaceBases (parent_builder, out error); if (error) return null; if (parent_builder is ModuleBuilder) { ModuleBuilder builder = (ModuleBuilder) parent_builder; TypeBuilder = builder.DefineType (Name, TypeAttributes.Interface | InterfaceAttr | TypeAttributes.Abstract, null, // Parent Type ifaces); } else { TypeBuilder builder = (TypeBuilder) parent_builder; TypeBuilder = builder.DefineNestedType (Name, TypeAttributes.Interface | InterfaceAttr | TypeAttributes.Abstract, null, // Parent Type ifaces); } RootContext.TypeManager.AddUserInterface (Name, TypeBuilder, this); InTransit = false; return TypeBuilder; } // // Performs semantic analysis, and then generates the IL interfaces // public void Populate () { if (!SemanticAnalysis ()) return; if (defined_method != null){ foreach (InterfaceMethod im in defined_method) PopulateMethod (im); } if (defined_properties != null){ foreach (InterfaceProperty ip in defined_properties) PopulateProperty (ip); } if (defined_events != null) foreach (InterfaceEvent ie in defined_events) PopulateEvent (ie); if (defined_indexer != null) foreach (InterfaceIndexer ii in defined_indexer) PopulateIndexer (ii); } public void CloseType () { TypeBuilder.CreateType (); } } public class InterfaceMemberBase { public readonly string Name; public readonly bool IsNew; public Attributes OptAttributes; public InterfaceMemberBase (string name, bool is_new, Attributes attrs) { Name = name; IsNew = is_new; OptAttributes = attrs; } } public class InterfaceProperty : InterfaceMemberBase { public readonly bool HasSet; public readonly bool HasGet; public readonly string Type; public readonly string type; public InterfaceProperty (string type, string name, bool is_new, bool has_get, bool has_set, Attributes attrs) : base (name, is_new, attrs) { Type = type; HasGet = has_get; HasSet = has_set; } } public class InterfaceEvent : InterfaceMemberBase { public readonly string Type; public InterfaceEvent (string type, string name, bool is_new, Attributes attrs) : base (name, is_new, attrs) { Type = type; } } public class InterfaceMethod : InterfaceMemberBase { public readonly string ReturnType; public readonly Parameters Parameters; public InterfaceMethod (string return_type, string name, bool is_new, Parameters args, Attributes attrs) : base (name, is_new, attrs) { this.ReturnType = return_type; this.Parameters = args; } // // Returns the signature for this interface method // public string GetSignature (TypeContainer tc) { Type ret = tc.LookupType (ReturnType, false); string args = Parameters.GetSignature (tc); if ((ret == null) || (args == null)) return null; return (IsNew ? "new-" : "") + ret.FullName + "(" + args + ")"; } public Type [] ParameterTypes (TypeContainer tc) { return Parameters.GetParameterInfo (tc); } } public class InterfaceIndexer : InterfaceMemberBase { public readonly bool HasGet, HasSet; public readonly Parameters Parameters; public readonly string Type; public InterfaceIndexer (string type, Parameters args, bool do_get, bool do_set, bool is_new, Attributes attrs) : base ("", is_new, attrs) { Type = type; Parameters = args; HasGet = do_get; HasSet = do_set; } public Type [] ParameterTypes (TypeContainer tc) { return Parameters.GetParameterInfo (tc); } } }