/* * Copyright (c) 2003-2008 The University of Wroclaw. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the University may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN * NO EVENT SHALL THE UNIVERSITY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ using Nemerle.Assertions; using Nemerle.Collections; using Nemerle.Compiler.Typedtree; using Nemerle.IO; using Nemerle.Late; using Nemerle.Utility; using System.IO; using PT = Nemerle.Compiler.Parsetree; using SR = System.Reflection; using SRE = System.Reflection.Emit; using SCG = System.Collections.Generic; namespace Nemerle.Compiler { /** * The library reference exception is typically thrown * when unable to load an assembly file. */ public class LibraryReferenceException : System.Exception { } /** * LibRefManager for the referenced libraries */ [ManagerAccess] public class LibraryReferenceManager { public NameTree : NamespaceTree; // a little hack to prevent AddBuildins() calling in NetType internal mutable add_buildins : bool = false; /* -- CONSTRUCTORS ----------------------------------------------------- */ /** * constructor. Always load the Framework core library. */ public this (man : ManagerClass, [NotNull] lib_paths : list [string]) { this.NameTree = man.NameTree; Manager = man; def assembly_dir (t) { DirectoryOfCodebase (getAssemblyLocation(t.Assembly)); }; // include current directory and directories where // mscorlib.dll, System.dll and Nemerle.dll reside _lib_path = assembly_dir (typeof (Nemerle.Core.AssertionException)) :: System.Environment.CurrentDirectory :: assembly_dir (typeof (System.Text.RegularExpressions.Match)) :: assembly_dir (typeof (LibraryReferenceManager)) :: assembly_dir (typeof (System.Object)) :: lib_paths; } /* -- PUBLIC METHODS --------------------------------------------------- */ /** * Stores the referenced library for later lookup by the namespaces. Also * add transitive closure of libraries needed by given assembly. */ public AddLibrary (name : string) : void { def assembly = match (name) { | "mscorlib" when Manager.Options.UseLoadedCorlib => typeof (System.Object).Assembly | "System" when Manager.Options.UseLoadedCorlib => typeof (System.Text.RegularExpressions.Match).Assembly | name => LookupAssembly (name) }; if (assembly == null) { Message.Error ("cannot find assembly `" + name + "'"); throw AssemblyFindException () } else if (_loaded_assemblies_by_name.Contains (assembly.FullName)) { when (_assemblies_loaded_by_hand.Contains (assembly.FullName) && !Manager.Options.PersistentLibraries) Message.Warning ("assembly `" + name + "' already loaded"); _assemblies_loaded_by_hand [assembly.FullName] = null; } else { _assemblies_loaded_by_hand [assembly.FullName] = null; AddAssembly (assembly) } } public AddAssembly (assembly : SR.Assembly) : void { unless (_loaded_assemblies_by_name.Contains (assembly.FullName)) { _loaded_assemblies_by_name [assembly.FullName] = LibraryReference (this, assembly); // store the pre-loaded reference when (Manager.Options.GreedyReferences) { def refs = assembly.GetReferencedAssemblies (); foreach (name : SR.AssemblyName in refs) { def asm = try { assemblyLoad (name) } catch { _ is FileNotFoundException => try { assemblyLoadFrom (name.CodeBase) } catch { _ is System.Exception => LookupAssembly (name.Name) } }; when (asm != null) AddAssembly (asm) } } } } public GetExtensionMethods (name : string, env : GlobalEnv, for_completion : bool) : SCG.IEnumerable [IMethod] { if (for_completion) foreach (ex in _extension_methods.Keys) when (ex.StartsWith (name, System.StringComparison.InvariantCultureIgnoreCase)) foreach (meth in GetExtensionMethods (ex, env, false)) yield meth; else { def methods = _extension_methods.GetValueOrDefault (name); when (methods != null) foreach (meth in methods) when (env.IsOpenNamespace (meth.DeclaringType.NamespaceNode.Parent)) yield meth; } } public AddExtensionMethod (m : IMethod) : void { def methods = _extension_methods.GetValueOrDefault (m.Name); if (methods == null) { def methods = SCG.List(); methods.Add(m); _extension_methods [m.Name] = methods; } else methods.Add(m); match (m) { | m is MethodBuilder => m.IsExtension = true; | m is LibraryReference.MethodInfo => m.IsExtension = true; | m is BuiltinMethod => m.IsExtension = true; | _ => (); } } /** * Remove assembly file name from URL returned by Assembly.CodeBase. */ public static DirectoryOfCodebase (mutable path : string) : string { path = Path.GetDirectoryName (path); // hack for mono returning location in the GAC def mono_gac = path.IndexOf ("mono/gac"); path = if (mono_gac != -1) if (path.LastIndexOf ("Nemerle") > mono_gac) path.Substring (0, mono_gac + 5) + "nemerle/" else if (path.LastIndexOf ("/2.0.") > mono_gac) path.Substring (0, mono_gac + 5) + "2.0/" else path.Substring (0, mono_gac + 5) + "1.0/" else path; path } protected virtual assemblyLoad (name : string) : SR.Assembly { SR.Assembly.Load (name) } protected virtual assemblyLoad (name : SR.AssemblyName) : SR.Assembly { SR.Assembly.Load (name) } protected virtual assemblyLoadFrom (path : string) : SR.Assembly { try { SR.Assembly.LoadFrom (path) } catch { /* Somebody gave us a 32-bit reference on 64-bit system or vice-versa. */ | _ is System.BadImageFormatException => assemblyLoad (SR.AssemblyName.GetAssemblyName (path).FullName); }; } public virtual getAssemblyLocation (assembly : SR.Assembly) : string { System.Uri(assembly.CodeBase).LocalPath } /* -- PRIVATE METHODS -------------------------------------------------- */ private LookupAssembly (name : string) : SR.Assembly { def assembly_by_name (path : string) { try { def ext = Path.GetExtension (path); def path = match (ext.ToLower ()) { | ".dll" | ".exe" => path | _ => path + ".dll" } if (File.Exists(path)) assemblyLoadFrom (path) else null } catch { | _ is FileNotFoundException => null | _ is System.ArgumentException => null }; }; match (name) { | x when x.IndexOf ('/') != -1 || x.IndexOf ('\\') != -1 => assembly_by_name (x) | x when x.IndexOf (',') != -1 => try { assemblyLoad (x) } catch { | _ is FileNotFoundException => null | _ is System.BadImageFormatException => Message.Error ("passed strong name is invalid or assembly was not found"); null } | _ => def lookup (libs) { | lib :: libs => def ret = assembly_by_name (Path.Combine (lib, name)); if (ret == null) lookup (libs) else ret | [] => null }; lookup (_lib_path); } } private load_macro (lib : SR.Assembly, macro_name : string) : void { def macro_type = lib.GetType (macro_name.Replace ("&", "\\&")); if (macro_type == null) { Message.Warning ($"failed to lookup macro `$(macro_name)' in assembly $(lib.FullName)"); } else { def ctor = macro_type.GetConstructor (System.Type.EmptyTypes); if (ctor == null) { Message.Warning ("failed to lookup constructor in macro `" + macro_name + "' from assembly " + lib.FullName); } else { match (ctor.Invoke (null)) { | null => Message.Warning ("failed to construct instance of macro `" + macro_name + "' from assembly " + lib.FullName); | casted_macro is IMacro => def ns = casted_macro.GetNamespace (); when (namespace_nodes.Get (ns).IsNone) _ = cache_namespace_node (ns); Manager.MacrosRegistry.RegisterMacro (casted_macro); | _ => Message.Warning ("instance of macro `" + macro_name + "' from assembly " + lib.FullName + " does not implement IMacro interface"); } } } } internal LoadLibrariesContents () : void { foreach ((key, lib) when lib != null in _loaded_assemblies_by_name.KeyValuePairs) { lib.LoadContents (); _loaded_assemblies_by_name [key] = null; } } public LoadMacrosFrom (lib : SR.Assembly) : void { assert (lib != null); // if we already loaded the assembly, then macros are also loaded // this might happen when referencing lib, like Nemerle.Macros match (_loaded_assemblies_by_name.Get (lib.FullName)) { | Some (null) => Nemerle.Imperative.Return (); // library was already loaded and processed, together with its macros | _ => () } // Message.Debug ($"loading macro from $lib"); def macroDefs = lib.GetCustomAttributes(false).Filter(t => t.GetType().FullName == "Nemerle.Internal.ContainsMacroAttribute"); def operDefs = lib.GetCustomAttributes(false).Filter(t => t.GetType().FullName == "Nemerle.Internal.OperatorAttribute"); try { foreach (definition in macroDefs) load_macro (lib, late (definition.GetName()) :> string); foreach (definition :> Nemerle.Internal.OperatorAttribute in operDefs) { def node = NameTree.ExactPath (NString.Split (definition.env, '.')); def od = OperatorDefinition (node, definition.name, definition.left, definition.right, definition.IsUnary); Manager.MacrosRegistry.AddOperatorDefinition (od); } } catch { | e is System.TypeLoadException => Message.Error ($"cannot load types from macroassembly `$(lib.FullName)' ($(lib.CodeBase)): $(e.Message)") } } public LoadMacrosFrom (name : string, strongPart : string = null) : void { mutable assembly = LookupAssembly (name); when (assembly == null && strongPart != null) assembly = assemblyLoad (name + strongPart); if (assembly == null) Message.Error ("cannot load assembly with macros `" + name + "'") else LoadMacrosFrom (assembly); } /* -- PRIVATE VARIABLES ------------------------------------------------ */ /** * List of directories we look for assemblies in. */ private _lib_path : list [string]; // the non-null values are not-yet processed references, which still need to load contents (types and macros) private _loaded_assemblies_by_name : Hashtable [string, LibraryReference] = Hashtable (20); private _assemblies_loaded_by_hand : Hashtable [string, object] = Hashtable (20); private namespace_nodes : Hashtable [string, NamespaceTree.Node] = Hashtable (300); private mutable _construct_right_away : list [NamespaceTree.Node] = []; // extension method name -> list of extension methods private _extension_methods : Hashtable [string, SCG.List [IMethod]] = Hashtable (); /// Remove extension methods defined in code (not external). public RemoveInternalExtensionMethods() : void { foreach ((name, lst) when lst.Exists(_ is MethodBuilder) in _extension_methods.KeyValuePairs) { _ = lst.RemoveAll(x => !(x is MethodBuilder)); when (lst.Count == 0) _ = _extension_methods.Remove (name); } } /* -- TYPE CACHE ----- */ internal LoadExtensions () : void { foreach (n in _construct_right_away) _ = n.LookupValue (); _construct_right_away = []; } public IsExtension (attrsProvider : System.Reflection.ICustomAttributeProvider) : bool { SystemTypeCache.ExtensionAttribute != null && attrsProvider.IsDefined (SystemTypeCache.ExtensionAttribute, false) || SystemTypeCache.SQ_ExtensionAttribute != null && attrsProvider.IsDefined (SystemTypeCache.SQ_ExtensionAttribute, false) } internal LoadTypesFrom (lib : LibraryReference) : void { def assembly = lib.Assembly; try { def types = assembly.GetExportedTypes (); for (mutable i = 0; i < types.Length; ++i) { def t = types[i]; // Message.Debug (name); def e = ExternalType (t, lib, null); def (ns_node, path_to_type) = framework_nesting (t); def mainnode = ns_node.Path (path_to_type); when (IsExtension (t)) _construct_right_away ::= mainnode; mutable tinfo_cache = null; // check if we have met such type before match (mainnode.Value) { | NotLoaded (x) => tinfo_cache = NamespaceTree.TypeInfoCache.NotLoadedList ([e, x]); | NotLoadedList (xs) => tinfo_cache = NamespaceTree.TypeInfoCache.NotLoadedList (e :: xs); | _ => tinfo_cache = NamespaceTree.TypeInfoCache.NotLoaded (e); } // assign wrappers for future loading of typecons mainnode.Value = tinfo_cache; } } catch { | e => Message.Error ($"Can't load types from '$assembly'. Error: $(e.Message)."); } } internal static CacheTypeInfo (t : System.Type, tc : TypeInfo, node : NamespaceTree.Node) : void { match (node.Value) { | NamespaceTree.TypeInfoCache.NotLoaded (e) => e.tycon = tc; | NamespaceTree.TypeInfoCache.NotLoadedList (es) => brk: { foreach (e in es) when (e.system_type.Equals (t)) { e.tycon = tc; brk (); } } // this happens when we load external protected type in GetInternalType // we need to cache to prevent looping | NamespaceTree.TypeInfoCache.No => node.Value = NamespaceTree.TypeInfoCache.Cached (tc) | NamespaceReference | MacroCall => Util.ice ("wanted to cache in wrong place - value " + t.TypeFullName ()) | Cached | CachedAmbiguous => Util.ice ("wanted to cache cached value " + t.TypeFullName ()) } } internal static GetInternalType (lib : LibraryReference, t : System.Type, node : NamespaceTree.Node) : TypeInfo { match (node.Value) { | NamespaceTree.TypeInfoCache.Cached (tc) => tc | NamespaceTree.TypeInfoCache.No => lib.ConstructTypeInfo (t, node); | _ => Util.ice ("not loaded internal type... " + t.Assembly.CodeBase + ":" + t.TypeFullName ()) } } internal cache_namespace_node (namespc : string) : NamespaceTree.Node { def nd = NameTree.ExactPath (NString.Split (namespc, array ['.'])); mutable assigned = nd; while (assigned != null) { when (assigned.Value is NamespaceTree.TypeInfoCache.No) assigned.Value = NamespaceTree.TypeInfoCache.NamespaceReference (); assigned = assigned.Parent; } namespace_nodes.Add (namespc, nd); nd } internal framework_nesting (t : System.Type) : NamespaceTree.Node * list [string] { def loop (t : System.Type, acc) { def dt = t.DeclaringType; if (dt != null) loop (dt, Util.StripGenericMark (dt.Name) :: acc) else { def namespc = if (t.Namespace != null) t.Namespace else ""; match (namespace_nodes.Get (namespc)) { | Some (nd) => (nd, acc) | None => (cache_namespace_node (namespc), acc) } } } // workaround mono bug #63768 if (t.IsPointer) { def find_name (acc, t : System.Type) { if (t.IsPointer) find_name (acc + "*", t.GetElementType ()) else loop (t, [t.Name + acc]) } find_name ("", t) } else { loop (t, [Util.StripGenericMark (t.Name)]) } } } [Record] public class ExternalType { [Accessor] internal system_type : System.Type; internal library : LibraryReference; internal mutable tycon : TypeInfo; internal ConstructTypeInfo (node : NamespaceTree.Node, fix_node : bool) : void { when (tycon == null) tycon = library.ConstructTypeInfo (system_type, node); when (fix_node) node.Value = NamespaceTree.TypeInfoCache.Cached (tycon); } } enum NumericKind { | Signed | Unsigned | Float | Char } /** * This class stores information extracted from a referenced external library. */ [ManagerAccess] public class LibraryReference { /** * The assembly associated with this object */ [Accessor (Assembly)] private _library : SR.Assembly; /** * The location of this library */ private mutable _location : Location; /** * If set to true, the current assembly declares itself * to be generated by the Nemerle compiler. */ _is_generated_by_nemerle : bool; LibRefManager : LibraryReferenceManager; private static load_attr_from (assembly : SR.Assembly, attr_name : string, attr : ref System.Type, attr_loc : ref string) : void { def ext = assembly.GetType (attr_name); when (ext != null && attr != null) { Message.Warning ($"$attr_name attribute from $assembly is ignored"); Message.HintOnce ($"$attr_name is first defined in $attr_loc"); } when (ext != null && attr == null) { attr = ext; attr_loc = assembly.ToString (); } } /** * Load an assembly. Extracts and processes the custom attributes array. */ internal this (mgr : LibraryReferenceManager, assembly : SR.Assembly) { LibRefManager = mgr; Manager = mgr.Manager; _library = assembly; _location = Location (Location.GetFileIndex (mgr.getAssemblyLocation(assembly)), 0, 0); _location.MarkAsGenerated(); // Scans the assembly custom attributes looking for something interesting... foreach (x :> SR.AssemblyConfigurationAttribute in _library.GetCustomAttributes (typeof (SR.AssemblyConfigurationAttribute), false)) { _is_generated_by_nemerle = _is_generated_by_nemerle || x.Configuration == "ContainsNemerleTypes"; } load_attr_from (assembly, "Nemerle.Internal.ExtensionAttribute", ref SystemTypeCache.ExtensionAttribute, ref SystemTypeCache.ExtensionAttributeAssembly); load_attr_from (assembly, "System.Runtime.CompilerServices.ExtensionAttribute", ref SystemTypeCache.SQ_ExtensionAttribute, ref SystemTypeCache.SQ_ExtensionAttributeAssembly); } internal LoadContents () : void { LibRefManager.LoadTypesFrom (this); LibRefManager.LoadMacrosFrom (_library); } /** * Turns a Framework type into something edible by Nemerle's type system */ internal TypeOfType (_tenv : Map [string, StaticTyVar], framework_type : System.Type) : MType { // Message.Debug (framework_type.ToString ()); if (framework_type.Equals (SystemTypeCache.Void)) InternalType.Void else if (framework_type.IsArray) MType.Array (TypeOfType (_tenv, framework_type.GetElementType ()), framework_type.GetArrayRank ()) else if (framework_type.IsByRef) { Message.Error ($ "ref type referenced $framework_type"); TypeOfType (_tenv, framework_type.GetElementType ()) } else if (framework_type.IsGenericParameter) { match (_tenv.Find (framework_type.Name)) { | Some (tv) => MType.TyVarRef (tv) | None => // _tenv.Iter (fun (x,y) { Message.Debug ($"$x - $y") }); Util.ice ($"$framework_type from $(framework_type.DeclaringType)") } } else { def tc = TypeInfoOfType (framework_type); // Message.Debug ($"tinfo $tc contains generic framework_type.ToString ()); def parms = if (framework_type.IsGenericType) List.MapFromArray (framework_type.GetGenericArguments (), fun (t) { TypeOfType (_tenv, t) }); else []; if (framework_type.Namespace == "Nemerle.Builtins") { def make_tupl (l) { | [x] => x | [] => InternalType.Void | _ => MType.Tuple (l) } if (tc.Name == "Tuple") MType.Tuple (parms) else if (tc.Name == "FunctionVoid") MType.Fun (make_tupl (parms), InternalType.Void) else { def (front, last) = parms.DivideLast (); MType.Fun (make_tupl (front), last) } } else MType.Class (tc, parms); } } internal TypeInfoOfType (framework_type : System.Type) : TypeInfo { def (ns_node, path_to_type) = LibRefManager.framework_nesting (framework_type); def ns_node = ns_node.Path (path_to_type); match (ns_node.LookupType ([], framework_type.GetGenericArguments ().Length)) { | Some (tc) => tc // protected external types are not fetched automatically from external assembly // so sometimes we must load them by hand | None => LibraryReferenceManager.GetInternalType (this, framework_type, ns_node) } } /** * Construct TypeInfo object from given type in current assembly. */ internal ConstructTypeInfo (reflected_type : System.Type, ns_node : NamespaceTree.Node) : TypeInfo { if (_is_generated_by_nemerle && reflected_type.IsDefined (SystemTypeCache.NemerleAttribute, false)) NetTypeInfo (this, reflected_type, ns_node) else { if (reflected_type.IsPrimitive) PrimitiveNetType (this, reflected_type, ns_node) else NetType (this, reflected_type, ns_node) } } /** * Looks for type named [name] that is internal to current assembly. Used * by type attribute decoder. */ internal LookupInternalType (name : string) : option [TypeInfo] { // Message.Debug ($"looking `$(name)'"); def st = _library.GetType (name); if (st == null) None () else { def (ns_node, path_to_type) = LibRefManager.framework_nesting (st); def ns = ns_node.Path (path_to_type); Some (LibraryReferenceManager.GetInternalType (this, st, ns)) } } private MethodOfMethodInfo (tenv : Map [string, StaticTyVar], meth : SR.MethodInfo) : MethodInfo { if (meth == null) null else MethodInfo (tenv, this, meth) } /* ----------------------------------------------------------------- * .NET types * ----------------------------------------------------------------- */ internal class NetType : TypeInfo { protected library : LibraryReference; internal tenv : Map [string, StaticTyVar] = Map (); protected direct_supertypes : list [MType.Class]; protected supertypes : list [MType.Class]; protected supertype_map : Map [TypeInfo, MType.Class] = Map (); public this (lib : LibraryReference, h : System.Type, ns_node : NamespaceTree.Node) { base (ns_node, lib.Manager, Util.StripGenericMark (h.TypeFullName ().Replace ('+', '.').TrimStart('.'))); // first cache ourself to avoid loops LibraryReferenceManager.CacheTypeInfo (h, this, ns_node); library = lib; system_type = h; when (system_type.IsGenericType && !system_type.IsGenericTypeDefinition) system_type = system_type.GetGenericTypeDefinition (); when (system_type.DeclaringType != null) tenv = (lib.TypeInfoOfType (system_type.DeclaringType) :> NetType).tenv; // init typarms and self_type (typarms, tenv, direct_supertypes, supertypes) = TyCodec.ReflectTypeBuilder (library, tenv, system_type); when (h.Namespace == "Nemerle.Builtins" && h.Name.StartsWith ("Array")) { direct_supertypes = [InternalType.Array]; supertypes ::= InternalType.Array; } foreach (t in supertypes) supertype_map = supertype_map.Add (t.tycon, t); def parms = List.Map (typarms, fun (x) { MType.TyVarRef (x) }); self_type = MType.Class (this, parms); TyCodec.ReflectConstraints(library, tenv, system_type, self_type, typarms); attributes = NemerleAttributes.None; when (system_type.IsAbstract) attributes |= NemerleAttributes.Abstract; when (system_type.IsSealed) attributes |= NemerleAttributes.Sealed; when (system_type.IsValueType) attributes |= NemerleAttributes.Struct; when (system_type.IsSpecialName) attributes |= NemerleAttributes.SpecialName; if (system_type.DeclaringType == null) { if (system_type.IsPublic) attributes |= NemerleAttributes.Public else attributes |= NemerleAttributes.Internal; } else { when (system_type.IsNestedPrivate) attributes |= NemerleAttributes.Private; when (system_type.IsNestedPublic) attributes |= NemerleAttributes.Public; when (system_type.IsNestedFamily) attributes |= NemerleAttributes.Protected; when (system_type.IsNestedAssembly) attributes |= NemerleAttributes.Internal; } def attrs = system_type.GetCustomAttributes ( SystemTypeCache.Reflection_DefaultMemberAttribute, true); default_indexer = if (attrs.Length > 0) { def dma = attrs [0] :> System.Reflection.DefaultMemberAttribute; dma.MemberName } else // there can be indexer in the base type, let DefaultIndexer // property handle it null; when (lib.LibRefManager.add_buildins) AddBuiltins (); // else Message.Debug ($"omiititng $FullName"); decode_extension_methods (lib.LibRefManager); when (InternalType.Obsolete_tc != null) is_obsolete = HasAttribute (InternalType.Obsolete_tc); } #region Special numeric overloads internal static numeric_types : Hashtable [string, NumericKind]; static this () { numeric_types = Hashtable (); numeric_types.Add ("SByte", NumericKind.Signed); numeric_types.Add ("Int16", NumericKind.Signed); numeric_types.Add ("Int32", NumericKind.Signed); numeric_types.Add ("Int64", NumericKind.Signed); numeric_types.Add ("Byte", NumericKind.Unsigned); numeric_types.Add ("UInt16", NumericKind.Unsigned); numeric_types.Add ("UInt32", NumericKind.Unsigned); numeric_types.Add ("UInt64", NumericKind.Unsigned); numeric_types.Add ("Single", NumericKind.Float); numeric_types.Add ("Double", NumericKind.Float); numeric_types.Add ("Char", NumericKind.Char); } FixupEquality (name : string) : void { FixupCompare (name); #if 0 match (special_members [name]) { | [elem : IMethod] => def tv = StaticTyVar ("'a"); tv.Constraints = []; def hd = elem.GetHeader (); hd.typarms = [tv]; match (hd.parms) { | [parm1, parm2] => parm1.ty = MType.TyVarRef (tv); parm2.ty = MType.TyVarRef (tv); | _ => assert (false) } | _ => assert (false) } #endif } FixupShift (name : string) : void { match (special_members [name]) { | [elem is IMethod] => match (elem.GetParameters ()) { | [_, parm2] => assert (InternalType.Int32 != null); parm2.ty = InternalType.Int32; | _ => assert (false) } | _ => assert (false) } } internal AddBuiltins () : void { InitBuiltinMembers (); when (system_type.IsPrimitive || system_type.Equals (SystemTypeCache.Object) || system_type.Equals (SystemTypeCache.String)) { def name = system_type.Name; if (name == "String") { // == and != are surprisingly properly overloaded // and this is done in LookupMemberImpl, because otherwise // we would use uninitialized InternalType.String_Concat // AddBuiltin ("op_Addition", InternalType.String_Concat); } else if (name == "Boolean") { AddBuiltin ("op_LogicalNot", "bool.!"); MakeSingleParm ("op_LogicalNot"); AddBuiltin ("op_Equality", "=="); AddBuiltin ("op_Inequality", "!="); // FixupEquality not needed here -- return type is already correct // and InternalType.Boolean is here null } else if (name == "Object") { AddBuiltin ("op_Equality", "==.ref"); AddBuiltin ("op_Inequality", "!=.ref"); FixupEquality ("op_Equality"); FixupEquality ("op_Inequality"); } else if (numeric_types.Contains (name)) { def kind = numeric_types [name]; def suff = match (kind) { | NumericKind.Float => ".f" | NumericKind.Char | NumericKind.Signed => ".s" | NumericKind.Unsigned => ".u" } def is_small_type = name == "SByte" || name == "Byte" || name == "Int16" || name == "UInt16"; unless (kind == NumericKind.Char) { // checked/unchecked: AddBuiltin ("op_Addition", "+" + suff, "+.f"); AddBuiltin ("op_Subtraction", "-" + suff, "-.f"); AddBuiltin ("op_Multiply", "*" + suff, "*.f"); // no checked version: AddBuiltin ("op_Division", "/" + suff); AddBuiltin ("op_Modulus", "%" + suff); // unary AddBuiltin ("op_UnaryPlus", "unary.+" + suff); MakeSingleParm ("op_UnaryPlus"); when (is_small_type) { ForceIntType ("op_Addition"); ForceIntType ("op_Subtraction"); ForceIntType ("op_Multiply"); ForceIntType ("op_Division"); ForceIntType ("op_Modulus"); ForceIntType ("op_UnaryPlus"); } def one_size = if (name == "Int64" || name == "UInt64") "i8" else if (name == "Float") "r4" else if (name == "Double") "r8" else "i4"; def incdec_suff = match (name) { | "Byte" => ".u.i1" | "SByte" => ".s.i1" | "Int16" => ".s.i2" | "UInt16" => ".u.i2" | _ => suff } AddBuiltin ("op_Increment", "++." + one_size + incdec_suff, "++." + one_size + ".f"); AddBuiltin ("op_Decrement", "--." + one_size + incdec_suff, "--." + one_size + ".f"); MakeSingleParm ("op_Increment"); MakeSingleParm ("op_Decrement"); } when (kind == NumericKind.Signed || kind == NumericKind.Unsigned) { AddBuiltin ("op_BitwiseAnd", "&" + suff); AddBuiltin ("op_BitwiseOr", "|" + suff); AddBuiltin ("op_ExclusiveOr", "^" + suff); AddBuiltin ("op_LeftShift", "<<" + suff); AddBuiltin ("op_RightShift", ">>" + suff); when (Name != "Int32") { FixupShift ("op_LeftShift"); FixupShift ("op_RightShift"); } when (is_small_type) { ForceIntType ("op_LeftShift"); ForceIntType ("op_RightShift"); ForceIntType ("op_BitwiseAnd"); ForceIntType ("op_BitwiseOr"); ForceIntType ("op_ExclusiveOr"); } AddBuiltin ("op_OnesComplement", "unary.~" + suff); MakeSingleParm ("op_OnesComplement"); when (is_small_type) ForceIntType ("op_OnesComplement"); } unless (kind == NumericKind.Unsigned || kind == NumericKind.Char) { AddBuiltin ("op_UnaryNegation", "unary.-" + suff, "unary.-.f"); MakeSingleParm ("op_UnaryNegation"); when (is_small_type) ForceIntType ("op_UnaryNegation"); } // comparisions AddBuiltin ("op_Equality", "=="); AddBuiltin ("op_Inequality", "!="); AddBuiltin ("op_LessThan", "<" + suff); AddBuiltin ("op_LessThanOrEqual", "<=" + suff); AddBuiltin ("op_GreaterThan", ">" + suff); AddBuiltin ("op_GreaterThanOrEqual", ">=" + suff); FixupCompare ("op_Equality"); FixupCompare ("op_Inequality"); FixupCompare ("op_LessThan"); FixupCompare ("op_LessThanOrEqual"); FixupCompare ("op_GreaterThan"); FixupCompare ("op_GreaterThanOrEqual"); } else {} } } #endregion /** Checks if underlying .NET type is value type */ public override IsValueType : bool { get { system_type.IsValueType } } public override IsInterface : bool { get { system_type.IsInterface } } public override Name : string { [Nemerle.Memoize (InvalidValue = null)] get { Util.StripGenericMark (system_type.Name) } } internal override GetLibraryReference () : LibraryReference { library } public override IsDelegate : bool { [Nemerle.Memoize] get { system_type.IsSubclassOf (SystemTypeCache.MulticastDelegate) } } public override GetConstantObject () : IField { null } public override DeclaringType : TypeInfo { [Nemerle.Memoize] get { if (system_type.DeclaringType == null) null else library.TypeInfoOfType (system_type.DeclaringType) } } public override Location : Location { get { library._location } } public override GetModifiers () : Modifiers { Util.ice ("GetModifiers not supported on external entities") } public override AttributeTargets : System.AttributeTargets { get { def usage = system_type.GetCustomAttributes (typeof (System.AttributeUsageAttribute), false); if (usage.Length > 0) { assert (usage.Length == 1); (usage[0] :> System.AttributeUsageAttribute).ValidOn } else System.AttributeTargets.All } } public override HasAttribute (attribute : TypeInfo) : bool { def t = attribute.SystemType; system_type.IsDefined (t, false) } public override Accessibility : Accessibility { get { match (system_type.Attributes %& SR.TypeAttributes.VisibilityMask) { | SR.TypeAttributes.NestedAssembly => Accessibility.Internal | SR.TypeAttributes.NestedFamANDAssem => Accessibility.ProtectedAndInternal | SR.TypeAttributes.NestedFamily => Accessibility.Protected | SR.TypeAttributes.NestedFamORAssem => Accessibility.ProtectedOrInternal | SR.TypeAttributes.Public | SR.TypeAttributes.NestedPublic => Accessibility.Public | SR.TypeAttributes.NestedPrivate | SR.TypeAttributes.NotPublic => Accessibility.Private | _ => Util.ice ("system type returned invalid attributes") } } } public override IsExternallyAccessible : bool { // if it wasn't, we wouldn't have reflected it? get { true } } public override GetTydecl () : TypeDeclaration { if (system_type.IsInterface) TypeDeclaration.Interface () else if (system_type.IsEnum) TypeDeclaration.Enum () else TypeDeclaration.Class () } public override GetSuperTypes () : list [MType.Class] { supertypes } public override GetDirectSuperTypes () : list [MType.Class] { direct_supertypes } public override SuperType (tc : TypeInfo) : option [list [MType]] { if (tc : object == this) Some (Solver.FixedValues (self_type.args)) else if (tc : object == InternalType.Object_tc) Some ([]) else match (supertype_map.Find (tc)) { | Some (ti) => Some (Solver.FixedValues (ti.args)) | None => None () } } public override SubtypingSubst (tc : TypeInfo) : Subst { if (this.Equals (tc)) Subst () // current type, no substitution else tc.MakeSubst1 (Option.UnSome (SuperType (tc))); } public override BaseType : TypeInfo { [Nemerle.Memoize] get { if (system_type.BaseType == null) null else library.TypeInfoOfType (system_type.BaseType) } } public override SuperClass () : option [TypeInfo] { match (direct_supertypes) { | MType.Class (tc, _) :: _ => Some (tc) | [] => None () | _ => Util.ice () } } public override GetMembers () : list [IMember] { LookupMemberImpl ("") } public override GetMembers (bindingAttr : BindingFlags) : list [IMember] { def check (x : IMember) { if (bindingAttr %&& BindingFlags.DeclaredOnly) this.Equals (x.DeclaringType) && TypeBuilder.constrain_member (x, bindingAttr) else TypeBuilder.constrain_member (x, bindingAttr) }; List.RevFilter (GetMembers (), check) } static constrain_with_membertype [MT] (memType : MemberKinds) : IMember * list [MT] -> list [MT] where MT : IMember { (x, acc) => if (x.MemberKind == memType) x :> MT :: acc else acc } public override GetFields (bindingAttr : BindingFlags) : list [IField] { GetMembers (bindingAttr).FoldLeft ([], constrain_with_membertype (MemberKinds.Field)) } public override GetConstructors (bindingAttr : BindingFlags) : list [IMethod] { GetMembers (bindingAttr).FoldLeft ([], constrain_with_membertype (MemberKinds.Constructor)) } private static is_internal (m : SR.MemberInfo) : bool { def x = m.MemberType; if (x %&& (MemberKinds.Constructor | MemberKinds.Method)) { def meth = m :> SR.MethodBase; meth.IsPrivate || meth.IsAssembly || meth.IsFamilyAndAssembly || meth.CallingConvention == SR.CallingConventions.VarArgs } else if (x %&& MemberKinds.Field) { def field = m :> SR.FieldInfo; field.IsPrivate || field.IsAssembly || field.IsFamilyAndAssembly } else if (x %&& MemberKinds.Property) { def prop = m :> SR.PropertyInfo; def accessors = prop.GetAccessors (true); def propMeth = NArray.Fold (accessors, null, fun (x : SR.MethodInfo, acc) { if (x == null || x.IsPrivate || x.IsAssembly || x.IsFamilyAndAssembly) acc else x }); propMeth == null } else if (x %&& MemberKinds.NestedType) { def ty = m :> System.Type; ty.IsNestedAssembly || ty.IsNestedPrivate || ty.IsNestedFamANDAssem } else if (x %&& MemberKinds.Event) { // we lookup nonpublic method here, because it can be protected and we want to // access it from derived class // (I just hope it won't trigger any authorization exceptions) def evMeth = (m :> SR.EventInfo).GetAddMethod (true); evMeth == null || evMeth.IsPrivate || evMeth.IsAssembly || evMeth.IsFamilyAndAssembly } else true } protected imember_of_memberinfo (m : SR.MemberInfo) : IMember { match (m.MemberType) { | MemberKinds.Constructor | MemberKinds.Method => MethodInfo (tenv, library, m :> SR.MethodBase) : IMember | MemberKinds.Field => FieldInfo (tenv, library, m :> SR.FieldInfo) | MemberKinds.Property => NetProperty (tenv, library, m :> SR.PropertyInfo) | MemberKinds.Event => NetEvent (library, m :> SR.EventInfo) | MemberKinds.NestedType => library.TypeInfoOfType (m :> System.Type) | _ => null } } private collect_members () : void { member_map = Hashtable (); def flags = SR.BindingFlags.Public | SR.BindingFlags.NonPublic | SR.BindingFlags.Static | SR.BindingFlags.Instance | SR.BindingFlags.DeclaredOnly; def member_array = system_type.GetMembers (flags); //Message.Debug ($"{collect_members, '$name' in $this len=$(member_array.Length)"); mutable collected_now = []; for (mutable i = member_array.Length - 1; i >= 0; i--) { def m = member_array [i]; // Message.Debug ($"adding $m from $this $(this.GetHashCode ())"); if (is_internal (m)) {} else { // Message.Debug ($ "add_member: $m to $(this) [$(GetHashCode ())]"); match (imember_of_memberinfo (m)) { | null => () | r => // Message.Debug ($ "add_member: $r to $(this) [$(GetHashCode ())]"); collected_now ::= r; add_member_by_name (r); } } } def res = if (IsInterface) { def supertypes = GetDirectSuperTypes (); (if (supertypes.IsEmpty) [InternalType.Object_tc.GetMembers ()] else supertypes.Map (fun (t) { t.tycon.GetMembers () })) + [collected_now] } else match (SuperClass ()) { | Some (ti) => [ti.GetMembers (), collected_now] | None => [collected_now] } collected_now = RemoveHiddenMembers (res); member_map [""] = collected_now; } public override LookupMemberImpl (name : string) : list [IMember] { if (this.Equals (InternalType.String_tc) && name == "op_Addition") { assert (InternalType.String_Concat != null); AddBuiltin ("op_Addition", InternalType.String_Concat); LookupMember (name) } else { when (member_map == null) collect_members (); if (member_map.Contains (name)) member_map [name] else { member_map [name] = []; [] } } } public override CanAccess (source : TypeInfo) : bool { system_type.IsPublic || system_type.IsNestedPublic || (system_type.DeclaringType != null && Option.IsSome (source.SuperType (DeclaringType)) && (system_type.IsNestedFamily || system_type.IsNestedFamORAssem)) } public override UnderlyingType : TypeInfo { [Nemerle.Memoize (InvalidValue = null)] get { assert (system_type.IsEnum); library.TypeInfoOfType (system_type.GetField ("value__").FieldType) } } decode_extension_methods (mgr : LibraryReferenceManager) : void { when (mgr.IsExtension (system_type)) foreach (m is IMethod in GetMembers ()) when (m.IsStatic && mgr.IsExtension (m.GetHandle ())) mgr.AddExtensionMethod (m); } internal override GetObsoletionDetails () : string * bool { def cust = System.Attribute.GetCustomAttribute ( system_type, library.Manager.InternalType.Obsolete_tc.SystemType, false) :> System.ObsoleteAttribute; assert (cust != null); (cust.Message, cust.IsError) } public override GlobalEnv : GlobalEnv { get { library.Manager.CoreEnv } } } internal class PrimitiveNetType : NetType { mutable implicit_conversion : list [TypeInfo]; is_longsize : bool; is_floating : bool; public this (lib : LibraryReference, h : System.Type, ns_node : NamespaceTree.Node) { base (lib, h, ns_node); is_longsize = Name.EndsWith ("64"); is_floating = Name == "Double" || Name == "Single"; } public override LookupMemberImpl (name : string) : list [IMember] { if (implicit_conversion == null) { AddConversions (); LookupMember (name); } else base.LookupMemberImpl (name); } public CanOmmitConversionTo (target : PrimitiveNetType) : bool { if (target.Equals (this)) true else if (is_longsize != target.is_longsize || is_floating != target.is_floating) false else { when (implicit_conversion == null) AddConversions (); implicit_conversion.Contains (target) || Equals (InternalType.Char_tc) && (InternalType.UInt16_tc :> PrimitiveNetType).CanOmmitConversionTo (target) } } protected AddConversions () : void { mutable is_numeric = true; def name = system_type.Name; implicit_conversion = match (name) { | "SByte" => [InternalType.Int16_tc, InternalType.Int32_tc, InternalType.Int64_tc, InternalType.Single_tc, InternalType.Double_tc] | "Int16" => [InternalType.Int32_tc, InternalType.Int64_tc, InternalType.Single_tc, InternalType.Double_tc] | "Int32" => [InternalType.Int64_tc, InternalType.Single_tc, InternalType.Double_tc] | "Int64" => [InternalType.Single_tc, InternalType.Double_tc] | "Byte" => [InternalType.Int16_tc, InternalType.Int32_tc, InternalType.Int64_tc, InternalType.UInt16_tc, InternalType.UInt32_tc, InternalType.UInt64_tc, InternalType.Single_tc, InternalType.Double_tc] | "UInt16" => [InternalType.Int32_tc, InternalType.Int64_tc, InternalType.UInt32_tc, InternalType.UInt64_tc, InternalType.Single_tc, InternalType.Double_tc] | "UInt32" => [InternalType.Int64_tc, InternalType.UInt64_tc, InternalType.Single_tc, InternalType.Double_tc] | "UInt64" => [InternalType.Single_tc, InternalType.Double_tc] | "Char" => [InternalType.UInt16_tc, InternalType.Int32_tc, InternalType.UInt32_tc, InternalType.Int64_tc, InternalType.UInt64_tc, InternalType.Single_tc, InternalType.Double_tc] | "Single" => [InternalType.Double_tc] | "Double" => [] | _ => is_numeric = false; [] } when (is_numeric) { foreach (target in implicit_conversion) AddConversion ("op_Implicit", target); // add remaining as explicit foreach (target in numeric_types.Keys) { def t = library.LibRefManager.NameTree.LookupInternalType (["System", target]); when (!Equals (t) && !List.Contains (implicit_conversion, t)) AddConversion ("op_Explicit", t); } } } } internal abstract class ExternalMemberInfo : MemberInfo { protected library : LibraryReference; protected id : int; protected InternalType : InternalTypeClass { get { library.Manager.InternalType } } protected SystemTypeCache : SystemTypeClass { get { library.Manager.SystemTypeCache } } public this (lib : LibraryReference) { library = lib; id = Util.next_id (lib.Manager); when (lib.Manager.InternalType.Obsolete_tc != null) is_obsolete = HasAttribute (InternalType.Obsolete_tc); } internal override GetObsoletionDetails () : string * bool { def cust = System.Attribute.GetCustomAttribute ( GetHandle (), InternalType.Obsolete_tc.SystemType, false) :> System.ObsoleteAttribute; assert (cust != null); (cust.Message, cust.IsError) } public HasAttribute (attribute : TypeInfo) : bool { def t = attribute.SystemType; GetHandle ().IsDefined (t, false) } public Location : Location { get { library._location } } public abstract GetHandle () : SR.MemberInfo; public override GlobalEnv : GlobalEnv { get { library.Manager.CoreEnv } } public override GetModifiers () : Modifiers { Util.ice ("GetModifiers not supported on external entities") } [Nemerle.OverrideObjectEquals] public Equals (o : ExternalMemberInfo) : bool { id == o.id || GetHandle ().Equals (o.GetHandle ()) } public override GetHashCode () : int { id } } private class FieldInfo : ExternalMemberInfo, IField { protected handle : SR.FieldInfo; protected tt_type : MType; public this (tenv : Map [string, StaticTyVar], lib : LibraryReference, h : SR.FieldInfo) { handle = h; base (lib); tt_type = library.TypeOfType (tenv, handle.FieldType); set_attributes (); } set_attributes () : void { attributes = NemerleAttributes.None; unless (handle.IsInitOnly || handle.IsLiteral) attributes |= NemerleAttributes.Mutable; when (handle.IsStatic) attributes |= NemerleAttributes.Static; when (handle.IsSpecialName) attributes |= NemerleAttributes.SpecialName; when (handle.IsPrivate) attributes |= NemerleAttributes.Private; when (handle.IsPublic) attributes |= NemerleAttributes.Public; when (handle.IsFamily) attributes |= NemerleAttributes.Protected; when (handle.IsAssembly) attributes |= NemerleAttributes.Internal; when (handle.IsFamilyAndAssembly) attributes |= NemerleAttributes.Internal %| NemerleAttributes.Protected; when (!handle.IsInitOnly && !handle.IsLiteral && handle.IsDefined (typeof (Nemerle.Internal.ImmutableAttribute), false)) attributes |= NemerleAttributes.CompilerMutable; } public DeclaringType : TypeInfo { [Nemerle.Memoize (InvalidValue = null)] get { library.TypeInfoOfType (handle.DeclaringType) } } public Name : string { get { handle.Name } } public override ToString () : string { MemberBuilder.DescribeMember (this) } public MemberKind : MemberKinds { get { MemberKinds.Field } } public GetFieldInfo () : SR.FieldInfo { handle } public override GetHandle () : SR.MemberInfo { handle } public GetMemType () : MType { tt_type } public HasBeenAssigned : bool { get { true } set { base.HasBeenUsed = value } } public IsLiteral : bool { get { handle.IsLiteral } } public GetValue () : Literal { assert (IsLiteral); def fval = handle.GetValue (null); def lit = match (fval) { | val is ulong => Literal.Integer (val, false, null).WithProperType () | val is double => Literal.Double (val) | val is float => Literal.Float (val) | val is string => Literal.String (val) | val is char => Literal.Char (val) | val is bool => Literal.Bool (val) | val => def val = System.Convert.ToInt64 (val); if (val == long.MinValue) Literal.Integer (0x8000000000000000UL, true, InternalType.Int64) else Literal.Integer (System.Math.Abs (val) :> ulong, val < 0, null).WithProperType () } if (handle.FieldType.IsEnum) Literal.Enum (lit :> Literal.Integer, library.TypeInfoOfType (handle.DeclaringType), this) else lit } public IsMutable : bool { get { !handle.IsInitOnly && !handle.IsLiteral && !handle.IsDefined (typeof (Nemerle.Internal.ImmutableAttribute), false) } } public IsVolatile : bool { get { handle.IsDefined (typeof (System.Runtime.CompilerServices.IsVolatile), false) || handle.IsDefined (typeof (Nemerle.Internal.VolatileModifier), false); } } public CanAccess (source : TypeInfo) : bool { handle.IsPublic || (Option.IsSome (source.SuperType (DeclaringType)) && (handle.IsFamily || handle.IsFamilyOrAssembly)) } } class NetEvent : ExternalMemberInfo, IEvent { protected handle : SR.EventInfo; protected adder : MethodInfo; protected remover : MethodInfo; protected mem_type : MType; public this (lib : LibraryReference, h : SR.EventInfo) { handle = h; base (lib); def add_method = handle.GetAddMethod (true); def remove_method = handle.GetRemoveMethod (true); def tenv = (DeclaringType :> NetType).tenv; adder = library.MethodOfMethodInfo (tenv, add_method); remover = library.MethodOfMethodInfo (tenv, remove_method); assert (adder != null); assert (remover != null); match (adder.GetMemType ()) { | MType.Fun (t, _) => mem_type = t.FixedValue } attributes = adder.Attributes; } public DeclaringType : TypeInfo { [Nemerle.Memoize (InvalidValue = null)] get { library.TypeInfoOfType (handle.DeclaringType) } } public Name : string { get { handle.Name } } public override ToString () : string { MemberBuilder.DescribeMember (this) } public MemberKind : MemberKinds { get { MemberKinds.Event } } public GetAdder () : IMethod { adder } public GetRemover () : IMethod { remover } public GetEventInfo () : SR.EventInfo { handle } public override GetHandle () : SR.MemberInfo { handle } public GetMemType () : MType { mem_type } public CanAccess (_source : TypeInfo) : bool { // FIXME: this is broken... we need to check method attributes true } } class NetProperty : ExternalMemberInfo, IProperty { protected handle : SR.PropertyInfo; protected getter : MethodInfo; protected setter : MethodInfo; protected any_method : MethodInfo; protected mem_type : MType; public this (tenv : Map [string, StaticTyVar], lib : LibraryReference, h : SR.PropertyInfo) { handle = h; base (lib); def get_method = handle.GetGetMethod (true); def set_method = handle.GetSetMethod (true); getter = library.MethodOfMethodInfo (tenv, get_method); setter = library.MethodOfMethodInfo (tenv, set_method); if (getter == null) any_method = setter; else any_method = getter; assert (any_method != null); def ret_type = library.TypeOfType (tenv, handle.PropertyType); def (args, ret_type) = if (getter != null) match (getter.GetMemType ()) { | MType.Fun (t, r) => (t.FixedValue.GetFunctionArguments (), r.FixedValue) } else if (setter != null) match (setter.GetMemType ()) { | MType.Fun (t, _) => def (args, r) = List.DivideLast (t.FixedValue.GetFunctionArguments ()); (args, r) } else ([], ret_type); if (args.IsEmpty) mem_type = ret_type else mem_type = MType.ConstructFunctionType (args, ret_type); attributes = any_method.Attributes; } public DeclaringType : TypeInfo { [Nemerle.Memoize (InvalidValue = null)] get { library.TypeInfoOfType (handle.DeclaringType) } } public Name : string { get { handle.Name } } public MemberKind : MemberKinds { get { MemberKinds.Property } } public override ToString () : string { MemberBuilder.DescribeMember (this) } public GetGetter () : IMethod { getter } public GetSetter () : IMethod { setter } public GetPropertyInfo () : SR.PropertyInfo { handle } public override GetHandle () : SR.MemberInfo { handle } public GetMemType () : MType { mem_type } public IsMutable : bool { get { handle.CanWrite } } public CanAccess (source : TypeInfo) : bool { any_method.CanAccess (source) } public IsIndexer : bool { [Nemerle.Memoize] get { def index_parms = handle.GetIndexParameters (); index_parms.Length > 0 } } } internal class MethodInfo : ExternalMemberInfo, IMethod { protected handle : SR.MethodBase; [Accessor (Header)] protected fun_header : Fun_header; protected is_var_args : bool; public this (tenv : Map [string, StaticTyVar], lib : LibraryReference, h : SR.MethodBase) { handle = h; base(lib); def (tyvars, tenv) = TyCodec.ReflectTyparms (lib, tenv, h); def ret_type = match (handle) { | m is SR.MethodInfo => library.TypeOfType (tenv, m.ReturnType) | _ => InternalType.Void // it is ctor } def parms = handle.GetParameters (); when (parms.Length > 0) { is_var_args = parms [parms.Length - 1].IsDefined (SystemTypeCache.ParamArrayAttribute, false); } mutable fparms = []; for (mutable i = parms.Length - 1; i >= 0; i--) { def p = parms [i]; def (parmkind, ty) = if (p.ParameterType.IsByRef) { def ty = library.TypeOfType (tenv, p.ParameterType.GetElementType ()); if (p.IsOut) (ParmKind.Out, MType.Out (ty)) else (ParmKind.Ref, MType.Ref (ty)) } else (ParmKind.Normal, library.TypeOfType (tenv, p.ParameterType)); def fp = Fun_parm ( loc = lib._location, name = p.Name, nameLocation = Location.Default, color = 0, ty = ty, typeLocation = lib._location, kind = parmkind, modifiers = Modifiers () // FIXME? ); def deflt = p.DefaultValue; when (deflt != System.DBNull.Value) { fp.default_value = if (deflt != System.Reflection.Missing.Value) { def lit = Literal.FromObject (deflt); Some (TExpr.Literal (ty, lit)); } else { if (InternalType.Object.Equals (ty)) Some (TExpr.StaticRef (ty, InternalType.Reflection_Missing, InternalType.Reflection_Missing.tycon.LookupMember ("Value").Head, [])) else Some (TExpr.DefaultValue (ty)) } } fparms ::= fp; }; fun_header = Fun_header ( loc = library._location, name = Name, ret_type = ret_type, ret_type_loc = library._location, parms = fparms, typarms = tyvars, tenv = null ); attributes = NemerleAttributes.None; when (handle.IsAbstract) attributes |= NemerleAttributes.Abstract; when (handle.IsVirtual) attributes |= NemerleAttributes.Virtual; when (handle.IsFinal) attributes |= NemerleAttributes.Sealed; when (handle.IsStatic) attributes |= NemerleAttributes.Static; when (handle.IsSpecialName) attributes |= NemerleAttributes.SpecialName; when (handle.IsPrivate) attributes |= NemerleAttributes.Private; when (handle.IsPublic) attributes |= NemerleAttributes.Public; when (handle.IsFamily || handle.IsFamilyOrAssembly) attributes |= NemerleAttributes.Protected; } public DeclaringType : TypeInfo { [Nemerle.Memoize (InvalidValue = null)] get { library.TypeInfoOfType (handle.DeclaringType) } } public Name : string { get { handle.Name } } public MemberKind : MemberKinds { get { handle.MemberType } } public override ToString () : string { MemberBuilder.DescribeMember (this) } public IsVarArgs : bool { get { is_var_args } } public IsExtension : bool { mutable is_extension : bool; public get { is_extension } internal set { is_extension = value } } public GetMethodBase () : SR.MethodBase { handle } public override GetHandle () : SR.MemberInfo { handle } [Nemerle.Memoize (InvalidValue = null)] public GetMemType () : MType.Fun { MType.ConstructFunctionType (GetHeader ()) } public IsFinal : bool { get { handle.IsFinal } } public GetFreshType () : MType * list [TyVar] { if (fun_header.typarms.IsEmpty) (GetMemType (), []) else { def (subst, vars) = Subst.Fresh (fun_header.typarms); (subst.MonoApply (GetMemType ()), vars) } } public GetConstructorInfo () : SR.ConstructorInfo { assert (handle.IsConstructor); (handle :> SR.ConstructorInfo) } public GetMethodInfo () : SR.MethodInfo { assert (!handle.IsConstructor); (handle :> SR.MethodInfo) } public GetHeader () : Fun_header { fun_header } public GetParameters () : list [Fun_parm] { fun_header.parms } public ReturnType : TyVar { get { fun_header.ret_type } } public CanAccess (source : TypeInfo) : bool { handle.IsPublic || (Option.IsSome (source.SuperType (DeclaringType)) && (handle.IsFamily || handle.IsFamilyOrAssembly)) } public BuiltinKind : BuiltinMethodKind { get { BuiltinMethodKind.NotBuiltin () } } } /* ----------------------------------------------------------------- * External Nemerle types * ----------------------------------------------------------------- */ private static get_string_attribute (defined_on : System.Type, attr_type : System.Type, meth_name : string) : string { def attr_obj = defined_on.GetCustomAttributes (attr_type, false) [0]; def meth = attr_type.GetMethod (meth_name); meth.Invoke (attr_obj, null) :> string } private get_variant_options (system_type : System.Type) : list [string] { def str = get_string_attribute (system_type, SystemTypeCache.VariantAttribute, "GetVariantOptions"); NString.Split (str, array [',']) } private class NetTypeInfo : NetType { tydecl : TypeDeclaration; constant_object : IField; public this (lib : LibraryReference, h : System.Type, ns_node : NamespaceTree.Node) { base (lib, h, ns_node); //when (h.FullName == "Nemerle.Compiler.Parsetree.PExpr") //{ // System.Diagnostics.Debug.Assert(false); //} if (system_type.IsDefined (SystemTypeCache.VariantAttribute, false)) { def names = lib.get_variant_options (system_type); def get_opt (name : string) { match (lib.LibRefManager.NameTree.LookupExactType (NString.Split (name, array ['.', '+']))) { | Some (tc) => tc | None => System.Diagnostics.Debug.Assert(false); Util.ice ("cannot find variant option named " + name) } }; tydecl = TypeDeclaration.Variant (List.Map (names, get_opt)) } else if (system_type.IsDefined (SystemTypeCache.VariantOptionAttribute, false)) { tydecl = TypeDeclaration.VariantOption () } else if (system_type.IsDefined (SystemTypeCache.ConstantVariantOptionAttribute, false)) { tydecl = TypeDeclaration.VariantOption (); match (LookupMember ("_N_constant_object")) { | [fld] => constant_object = fld :> IField | _ => Util.ice ("cannot find _N_constant_object") } } else if (system_type.IsDefined (SystemTypeCache.TypeAliasAttribute, false)) { def type_string = get_string_attribute (system_type, SystemTypeCache.TypeAliasAttribute, "GetAliasedType"); tydecl = TypeDeclaration.Alias (TyCodec.DecodeType (lib, tenv, type_string)) } else if (system_type.IsInterface) tydecl = TypeDeclaration.Interface () else if (system_type.IsEnum) tydecl = TypeDeclaration.Enum () else tydecl = TypeDeclaration.Class (); decode_extension_patterns (); } public override GetTydecl () : TypeDeclaration { tydecl } public override GetConstantObject () : IField { constant_object } decode_extension_patterns () : void { def t = SystemTypeCache.ExtensionPatternEncodingAttribute; def attrs = system_type.GetCustomAttributes (t, false); when (attrs.Length > 0) { def get_ids = t.GetMethod ("get_Identifiers"); def get_pat = t.GetMethod ("get_Pattern"); def get_name = t.GetMethod ("get_Name"); foreach (attr_obj in attrs) { def ids = get_ids.Invoke (attr_obj, null) :> string; def pat = get_pat.Invoke (attr_obj, null) :> string; def name = get_name.Invoke (attr_obj, null) :> string; def ext = ExtensionPattern (parent = this, identifiers = NString.Split (ids, [',']), pattern = MainParser.ParseExpr (Manager.CoreEnv, pat), name = name); AddExtensionPattern (ext); } } } } } } /* namespace */