//
static ArrayList soft_references;
+ //
+ // External aliases for assemblies.
+ //
+ static Hashtable external_aliases;
+
//
// Modules to be linked
//
}
static public void LoadAssembly (string assembly, bool soft)
+ {
+ LoadAssembly (assembly, null, soft);
+ }
+
+ static public void LoadAssembly (string assembly, string alias, bool soft)
{
Assembly a;
string total_log = "";
ass = assembly.Substring (0, assembly.Length - 4);
a = Assembly.Load (ass);
}
- TypeManager.AddAssembly (a);
+ // Extern aliased refs require special handling
+ if (alias == null)
+ TypeManager.AddAssembly (a);
+ else
+ TypeManager.AddExternAlias (alias, a);
} catch (FileNotFoundException){
foreach (string dir in link_paths){
try {
a = Assembly.LoadFrom (full_path);
- TypeManager.AddAssembly (a);
+ if (alias == null)
+ TypeManager.AddAssembly (a);
+ else
+ TypeManager.AddExternAlias (alias, a);
return;
} catch (FileNotFoundException ff) {
total_log += ff.FusionLog;
foreach (string r in soft_references)
LoadAssembly (r, true);
+
+ foreach (DictionaryEntry entry in external_aliases)
+ LoadAssembly ((string) entry.Value, (string) entry.Key, false);
return;
}
Environment.Exit (1);
}
- references.Add (args [++i]);
+ string val = args [++i];
+ int idx = val.IndexOf ('=');
+ if (idx > -1) {
+ string alias = val.Substring (0, idx);
+ string assembly = val.Substring (idx + 1);
+ AddExternAlias (alias, assembly);
+ return true;
+ }
+
+ references.Add (val);
return true;
case "-L":
string [] refs = value.Split (new char [] { ';', ',' });
foreach (string r in refs){
- references.Add (r);
+ string val = r;
+ int index = val.IndexOf ("=");
+ if (index > -1) {
+ string alias = r.Substring (0, index);
+ string assembly = r.Substring (index + 1);
+ AddExternAlias (alias, assembly);
+ return true;
+ }
+
+ references.Add (val);
}
return true;
}
return new_args;
}
+
+ static void AddExternAlias (string identifier, string assembly)
+ {
+ if (assembly.Length == 0) {
+ Report.Error (1680, "Invalid reference alias '" + identifier + "='. Missing filename");
+ return;
+ }
+
+ if (!IsExternAliasValid (identifier)) {
+ Report.Error (1679, "Invalid extern alias for /reference. Alias '" + identifier + "' is not a valid identifier");
+ return;
+ }
+
+ // Could here hashtable throw an exception?
+ external_aliases [identifier] = assembly;
+ }
+
+ static bool IsExternAliasValid (string identifier)
+ {
+ if (identifier.Length == 0)
+ return false;
+ if (identifier [0] != '_' && !Char.IsLetter (identifier [0]))
+ return false;
+
+ for (int i = 1; i < identifier.Length; i++) {
+ char c = identifier [i];
+ if (Char.IsLetter (c) || Char.IsDigit (c))
+ continue;
+
+ UnicodeCategory category = Char.GetUnicodeCategory (c);
+ if (category != UnicodeCategory.Format || category != UnicodeCategory.NonSpacingMark ||
+ category != UnicodeCategory.SpacingCombiningMark ||
+ category != UnicodeCategory.ConnectorPunctuation)
+ return false;
+ }
+
+ return true;
+ }
/// <summary>
/// Parses the arguments, and drives the compilation
encoding = default_encoding;
references = new ArrayList ();
+ external_aliases = new Hashtable ();
soft_references = new ArrayList ();
modules = new ArrayList ();
link_paths = new ArrayList ();
//
// Verify using aliases now
//
- Namespace.VerifyUsing ();
+ GlobalRootNamespace.VerifyUsingForAll ();
if (Report.Errors > 0){
return false;
Report.Reset ();
TypeManager.Reset ();
TypeHandle.Reset ();
- Namespace.Reset ();
+ GlobalRootNamespace.Reset ();
CodeGen.Reset ();
}
}
using System;
using System.Collections;
using System.Collections.Specialized;
+using System.Reflection;
namespace Mono.CSharp {
+ public class RootNamespace : Namespace
+ {
+ static MethodInfo get_namespaces_method;
+
+ Assembly referenced_assembly;
+ Hashtable cached_namespaces;
+
+ static RootNamespace ()
+ {
+ get_namespaces_method = typeof (Assembly).GetMethod ("GetNamespaces", BindingFlags.Instance | BindingFlags.NonPublic);
+ }
+
+ //
+ // We access GlobalRoot here to beautify the code
+ //
+ public static GlobalRootNamespace Global {
+ get {
+ return GlobalRootNamespace.GlobalRoot;
+ }
+ }
+
+ public RootNamespace (Assembly assembly) : base (null, String.Empty)
+ {
+ this.referenced_assembly = assembly;
+ this.cached_namespaces = new Hashtable ();
+ this.cached_namespaces.Add ("", null);
+
+ if (this.referenced_assembly != null)
+ ComputeNamespacesForAssembly (this.referenced_assembly);
+ }
+
+ public virtual Type LookupTypeReflection (string name, Location loc)
+ {
+ return GetTypeInAssembly (referenced_assembly, name);
+ }
+
+ public virtual void RegisterNamespace (Namespace ns)
+ {
+ // Do nothing.
+ }
+
+ protected void ComputeNamespacesForAssembly (Assembly assembly)
+ {
+ if (get_namespaces_method != null) {
+ string [] namespaces = (string []) get_namespaces_method.Invoke (assembly, null);
+ foreach (string ns in namespaces) {
+ if (ns.Length == 0)
+ continue;
+
+ // Method from parent class Namespace
+ GetNamespace (ns, true);
+ }
+ } else {
+ //cached_namespaces.Add ("", null);
+ foreach (Type t in assembly.GetExportedTypes ()) {
+ string ns = t.Namespace;
+ if (ns == null || cached_namespaces.Contains (ns))
+ continue;
+
+ // Method from parent class Namespace
+ GetNamespace (ns, true);
+ cached_namespaces.Add (ns, null);
+ }
+ }
+ }
+
+ protected Type GetTypeInAssembly (Assembly assembly, string name)
+ {
+ Type t = assembly.GetType (name);
+ if (t == null)
+ return null;
+
+ if (t.IsPointer)
+ throw new InternalErrorException ("Use GetPointerType() to get a pointer");
+
+ TypeAttributes ta = t.Attributes & TypeAttributes.VisibilityMask;
+ if (ta != TypeAttributes.NotPublic && ta != TypeAttributes.NestedPrivate &&
+ ta != TypeAttributes.NestedAssembly && ta != TypeAttributes.NestedFamANDAssem)
+ return t;
+
+ return null;
+ }
+
+ protected Hashtable CachedNamespaces {
+ get {
+ return cached_namespaces;
+ }
+ }
+
+ }
+
+ public class GlobalRootNamespace : RootNamespace
+ {
+ static ArrayList all_namespaces;
+ static Hashtable namespaces_map;
+ static Hashtable root_namespaces;
+ internal static GlobalRootNamespace GlobalRoot;
+
+ Assembly [] assemblies;
+ Module [] modules;
+
+ public static void Reset ()
+ {
+ all_namespaces = new ArrayList ();
+ namespaces_map = new Hashtable ();
+ root_namespaces = new Hashtable ();
+ GlobalRoot = new GlobalRootNamespace ();
+ }
+
+ static GlobalRootNamespace ()
+ {
+ Reset ();
+ }
+
+ public GlobalRootNamespace () : base (null)
+ {
+ assemblies = new Assembly [0];
+ modules = new Module [0];
+ }
+
+ public void AddAssemblyReference (Assembly assembly)
+ {
+ Assembly [] tmp = new Assembly [assemblies.Length + 1];
+ Array.Copy (assemblies, 0, tmp, 0, assemblies.Length);
+ tmp [assemblies.Length] = assembly;
+
+ assemblies = tmp;
+ ComputeNamespacesForAssembly (assembly);
+ }
+
+ public void AddModuleReference (Module module)
+ {
+ Module [] tmp = new Module [modules.Length + 1];
+ Array.Copy (modules, 0, tmp, 0, modules.Length);
+ tmp [modules.Length] = module;
+
+ modules = tmp;
+
+ if (module != CodeGen.Module.Builder)
+ ComputeNamespacesForModule (module);
+ }
+
+ void ComputeNamespacesForModule (Module module)
+ {
+ foreach (Type t in module.GetTypes ()) {
+ string ns = t.Namespace;
+ if (ns == null || CachedNamespaces.Contains (ns))
+ continue;
+
+ GetNamespace (ns, true);
+ CachedNamespaces.Add (ns, null);
+ }
+ }
+
+ public override Type LookupTypeReflection (string name, Location loc)
+ {
+ Type found_type = null;
+
+ foreach (Assembly a in assemblies) {
+ Type t = GetTypeInAssembly (a, name);
+ if (t == null)
+ continue;
+
+ if (found_type == null) {
+ found_type = t;
+ continue;
+ }
+
+ Report.SymbolRelatedToPreviousError (found_type);
+ Report.SymbolRelatedToPreviousError (t);
+ Report.Error (433, loc, "The imported type `{0}' is defined multiple times", name);
+
+ return found_type;
+ }
+
+ foreach (Module module in modules) {
+ Type t = module.GetType (name);
+ if (t == null)
+ continue;
+
+ if (found_type == null) {
+ found_type = t;
+ continue;
+ }
+
+ Report.SymbolRelatedToPreviousError (t);
+ Report.SymbolRelatedToPreviousError (found_type);
+ Report.Warning (436, 2, loc, "Ignoring imported type `{0}' since the current assembly already has a declaration with the same name",
+ TypeManager.CSharpName (t));
+ return t;
+ }
+
+ return found_type;
+ }
+
+ public override void RegisterNamespace (Namespace child)
+ {
+ all_namespaces.Add (child);
+ if (namespaces_map.Contains (child.Name))
+ return;
+ namespaces_map [child.Name] = true;
+ }
+
+ public static RootNamespace DefineRootNamespace (string name, Assembly assembly)
+ {
+ RootNamespace retval = (RootNamespace) root_namespaces [name];
+ if (retval != null)
+ return retval;
+
+ retval = new RootNamespace (assembly);
+ return retval;
+ }
+
+ public static bool IsNamespace (string name)
+ {
+ return namespaces_map [name] != null;
+ }
+
+ public static ArrayList UserDefinedNamespaces {
+ get { return all_namespaces; }
+ }
+
+ public static void VerifyUsingForAll ()
+ {
+ foreach (Namespace ns in all_namespaces)
+ ns.VerifyUsing ();
+ }
+
+ public static void DefineNamespacesForAll (SymbolWriter symwriter)
+ {
+ foreach (Namespace ns in all_namespaces)
+ ns.DefineNamespaces (symwriter);
+ }
+
+ public override string ToString ()
+ {
+ return "Namespace (<root>)";
+ }
+
+ public override string GetSignatureForError ()
+ {
+ return "global::";
+ }
+
+ }
+
/// <summary>
/// Keeps track of the namespaces defined in the C# code.
///
/// compiler parse/intermediate tree during name resolution.
/// </summary>
public class Namespace : FullNamedExpression {
- static ArrayList all_namespaces;
- static Hashtable namespaces_map;
Namespace parent;
string fullname;
Hashtable namespaces;
IDictionary declspaces;
Hashtable cached_types;
+ RootNamespace root;
public readonly MemberName MemberName;
- public static Namespace Root;
-
- static Namespace ()
- {
- Reset ();
- }
-
- public static void Reset ()
- {
- all_namespaces = new ArrayList ();
- namespaces_map = new Hashtable ();
-
- Root = new Namespace (null, "");
- }
-
/// <summary>
/// Constructor Takes the current namespace and the
/// name. This is bootstrapped with parent == null
this.parent = parent;
+ if (parent != null)
+ this.root = parent.root;
+ else
+ this.root = this as RootNamespace;
+
+ if (this.root == null)
+ throw new InternalErrorException ("Root namespaces must be created using RootNamespace");
+
string pname = parent != null ? parent.Name : "";
if (pname == "")
namespaces = new Hashtable ();
cached_types = new Hashtable ();
- all_namespaces.Add (this);
- if (namespaces_map.Contains (fullname))
- return;
- namespaces_map [fullname] = true;
+ root.RegisterNamespace (this);
}
public override Expression DoResolve (EmitContext ec)
throw new InternalErrorException ("Expression tree referenced namespace " + fullname + " during Emit ()");
}
- public static bool IsNamespace (string name)
- {
- return namespaces_map [name] != null;
- }
-
public override string GetSignatureForError ()
{
- return Name.Length == 0 ? "::global" : Name;
+ return Name;
}
public Namespace GetNamespace (string name, bool create)
return ns;
}
- public static Namespace LookupNamespace (string name, bool create)
- {
- return Root.GetNamespace (name, create);
- }
-
TypeExpr LookupType (string name, Location loc)
{
if (cached_types.Contains (name))
}
}
string lookup = t != null ? t.FullName : (fullname == "" ? name : fullname + "." + name);
- Type rt = TypeManager.LookupTypeReflection (lookup, loc);
+ Type rt = root.LookupTypeReflection (lookup, loc);
if (t == null)
t = rt;
declspaces.Add (name, ds);
}
- static public ArrayList UserDefinedNamespaces {
- get { return all_namespaces; }
+ /// <summary>
+ /// Used to validate that all the using clauses are correct
+ /// after we are finished parsing all the files.
+ /// </summary>
+ public void VerifyUsing ()
+ {
+ foreach (NamespaceEntry entry in entries)
+ entry.VerifyUsing ();
+ }
+
+ public void DefineNamespaces (SymbolWriter symwriter)
+ {
+ foreach (NamespaceEntry entry in entries)
+ entry.DefineNamespace (symwriter);
}
/// <summary>
get { return parent; }
}
- public static void DefineNamespaces (SymbolWriter symwriter)
- {
- foreach (Namespace ns in all_namespaces) {
- foreach (NamespaceEntry entry in ns.entries)
- entry.DefineNamespace (symwriter);
- }
- }
-
- /// <summary>
- /// Used to validate that all the using clauses are correct
- /// after we are finished parsing all the files.
- /// </summary>
- public static void VerifyUsing ()
- {
- foreach (Namespace ns in all_namespaces) {
- foreach (NamespaceEntry entry in ns.entries)
- entry.VerifyUsing ();
- }
- }
-
public override string ToString ()
{
- if (this == Root)
- return "Namespace (<root>)";
- else
- return String.Format ("Namespace ({0})", Name);
+ return String.Format ("Namespace ({0})", Name);
}
}
Hashtable aliases;
ArrayList using_clauses;
public bool DeclarationFound = false;
+ public bool UsingFound = false;
//
// This class holds the location where a using definition is
}
}
- public class AliasEntry {
+ public abstract class AliasEntry {
public readonly string Name;
- public readonly Expression Alias;
public readonly NamespaceEntry NamespaceEntry;
public readonly Location Location;
- public AliasEntry (NamespaceEntry entry, string name, MemberName alias, Location loc)
+ protected AliasEntry (NamespaceEntry entry, string name, Location loc)
{
Name = name;
- Alias = alias.GetTypeExpression ();
NamespaceEntry = entry;
Location = loc;
}
+
+ protected FullNamedExpression resolved;
- FullNamedExpression resolved;
+ public abstract FullNamedExpression Resolve ();
+ }
+
+ public class LocalAliasEntry : AliasEntry
+ {
+ public readonly Expression Alias;
+
+ public LocalAliasEntry (NamespaceEntry entry, string name, MemberName alias, Location loc) :
+ base (entry, name, loc)
+ {
+ Alias = alias.GetTypeExpression ();
+ }
- public FullNamedExpression Resolve ()
+ public override FullNamedExpression Resolve ()
{
if (resolved != null)
return resolved;
}
}
+ public class ExternAliasEntry : AliasEntry
+ {
+ public ExternAliasEntry (NamespaceEntry entry, string name, Location loc) :
+ base (entry, name, loc)
+ {
+ }
+
+ public override FullNamedExpression Resolve ()
+ {
+ if (resolved != null)
+ return resolved;
+
+ resolved = TypeManager.ComputeNamespacesForAlias (Name);
+ if (resolved == null) {
+ Report.Error (430, Location, "The extern alias '" + Name +
+ "' was not specified in a /reference option");
+ }
+
+ return resolved;
+ }
+ }
+
public NamespaceEntry (NamespaceEntry parent, SourceFile file, string name, Location loc)
{
this.parent = parent;
if (parent != null)
ns = parent.NS.GetNamespace (name, true);
else if (name != null)
- ns = Namespace.LookupNamespace (name, true);
+ ns = RootNamespace.Global.GetNamespace (name, true);
else
- ns = Namespace.Root;
+ ns = RootNamespace.Global;
+
ns.AddNamespaceEntry (this);
}
Report.Warning (440, loc, "An alias named `global' will not be used when resolving 'global::';" +
" the global namespace will be used instead");
- aliases [name] = new AliasEntry (Doppelganger, name, alias, loc);
+ aliases [name] = new LocalAliasEntry (Doppelganger, name, alias, loc);
+ }
+
+ public void UsingExternalAlias (string name, Location loc)
+ {
+ if (UsingFound || DeclarationFound) {
+ Report.Error (439, loc, "An extern alias declaration must precede all other elements");
+ return;
+ }
+
+ if (aliases == null)
+ aliases = new Hashtable ();
+
+ if (aliases.Contains (name)) {
+ AliasEntry ae = (AliasEntry) aliases [name];
+ Report.SymbolRelatedToPreviousError (ae.Location, ae.Name);
+ Report.Error (1537, loc, "The using alias `" + name +
+ "' appeared previously in this namespace");
+ return;
+ }
+
+ if (name == "global") {
+ Report.Error (1681, loc, "You cannot redefine the global extern alias");
+ return;
+ }
+
+ aliases [name] = new ExternAliasEntry (Doppelganger, name, loc);
}
public FullNamedExpression LookupNamespaceOrType (DeclSpace ds, string name, Location loc, bool ignore_cs0104)
foreach (DictionaryEntry de in aliases) {
AliasEntry alias = (AliasEntry) de.Value;
if (alias.Resolve () == null)
- Error_NamespaceNotFound (alias.Location, alias.Alias.ToString ());
+ if (alias is LocalAliasEntry) {
+ LocalAliasEntry local = alias as LocalAliasEntry;
+ Error_NamespaceNotFound (local.Location, local.Alias.ToString ());
+ }
}
}
}
public string GetSignatureForError ()
{
- if (NS == Namespace.Root)
- return "::global";
- else
- return ns.Name;
+ return ns.GetSignatureForError ();
}
public override string ToString ()
{
- if (NS == Namespace.Root)
- return "NamespaceEntry (<root>)";
- else
- return String.Format ("NamespaceEntry ({0},{1},{2})", ns.Name, IsImplicit, ID);
+ return ns.ToString ();
}
}
}
// </remarks>
static Assembly [] assemblies;
+ static Hashtable external_aliases;
+
// <remarks>
// Keeps a list of modules. We used this to do lookups
// on the module using GetType -- needed for arrays
// Lets get everything clean so that we can collect before generating code
assemblies = null;
modules = null;
+ external_aliases = null;
builder_to_declspace = null;
builder_to_member_cache = null;
builder_to_ifaces = null;
assemblies = new Assembly [0];
modules = null;
+ external_aliases = new Hashtable ();
builder_to_declspace = new PtrHashtable ();
builder_to_member_cache = new PtrHashtable ();
builder_to_method = new PtrHashtable ();
assemblies = n;
}
+ public static void AddExternAlias (string alias, Assembly a)
+ {
+ // Keep the new as the chosen one
+ external_aliases [alias] = a;
+ }
+
public static Assembly [] GetAssemblies ()
{
return assemblies;
}
+ public static Assembly GetExternAlias (string alias)
+ {
+ return (Assembly) external_aliases [alias];
+ }
+
/// <summary>
/// Registers a module builder to lookup types from
/// </summary>
return (Type) ret;
}
- public static Type LookupTypeReflection (string name, Location loc)
- {
- Type found_type = null;
-
- foreach (Assembly a in assemblies) {
- Type t = a.GetType (name);
- if (t == null)
- continue;
-
- if (t.IsPointer)
- throw new InternalErrorException ("Use GetPointerType() to get a pointer");
-
- TypeAttributes ta = t.Attributes & TypeAttributes.VisibilityMask;
- if (ta != TypeAttributes.NotPublic && ta != TypeAttributes.NestedPrivate &&
- ta != TypeAttributes.NestedAssembly && ta != TypeAttributes.NestedFamANDAssem) {
- if (found_type == null) {
- found_type = t;
- continue;
- }
-
- Report.SymbolRelatedToPreviousError (found_type);
- Report.SymbolRelatedToPreviousError (t);
- Report.Error (433, loc, "The imported type `{0}' is defined multiple times", name);
- return found_type;
- }
- }
-
- foreach (Module mb in modules) {
- Type t = mb.GetType (name);
- if (t == null)
- continue;
-
- if (found_type == null) {
- found_type = t;
- continue;
- }
-
- Report.SymbolRelatedToPreviousError (t);
- Report.SymbolRelatedToPreviousError (found_type);
- Report.Warning (436, 2, loc, "Ignoring imported type `{0}' since the current assembly already has a declaration with the same name",
- TypeManager.CSharpName (t));
- return t;
- }
-
- return found_type;
- }
-
/// <summary>
/// Computes the namespaces that we import from the assemblies we reference.
/// </summary>
public static void ComputeNamespaces ()
{
- MethodInfo assembly_get_namespaces = typeof (Assembly).GetMethod ("GetNamespaces", BindingFlags.Instance|BindingFlags.NonPublic);
-
- Hashtable cache = null;
-
- //
- // First add the assembly namespaces
- //
- if (assembly_get_namespaces != null){
- int count = assemblies.Length;
-
- for (int i = 0; i < count; i++){
- Assembly a = assemblies [i];
- string [] namespaces = (string []) assembly_get_namespaces.Invoke (a, null);
- foreach (string ns in namespaces){
- if (ns.Length == 0)
- continue;
- Namespace.LookupNamespace (ns, true);
- }
- }
- } else {
- cache = new Hashtable ();
- cache.Add ("", null);
- foreach (Assembly a in assemblies) {
- foreach (Type t in a.GetExportedTypes ()) {
- string ns = t.Namespace;
- if (ns == null || cache.Contains (ns))
- continue;
+ foreach (Assembly assembly in assemblies)
+ RootNamespace.Global.AddAssemblyReference (assembly);
+
+ foreach (Module m in modules)
+ RootNamespace.Global.AddModuleReference (m);
- Namespace.LookupNamespace (ns, true);
- cache.Add (ns, null);
- }
- }
- }
+ }
- //
- // Then add module namespaces
- //
- foreach (Module m in modules) {
- if (m == CodeGen.Module.Builder)
- continue;
- if (cache == null) {
- cache = new Hashtable ();
- cache.Add ("", null);
- }
- foreach (Type t in m.GetTypes ()) {
- string ns = t.Namespace;
- if (ns == null || cache.Contains (ns))
- continue;
- Namespace.LookupNamespace (ns, true);
- cache.Add (ns, null);
- }
- }
+ public static Namespace ComputeNamespacesForAlias (string name)
+ {
+ Assembly assembly = (Assembly) external_aliases [name];
+ if (assembly == null)
+ return null;
+
+ return GlobalRootNamespace.DefineRootNamespace (name, assembly);
}
/// <summary>
public static bool NamespaceClash (string name, Location loc)
{
- if (Namespace.LookupNamespace (name, false) == null)
+ if (RootNamespace.Global.GetNamespace (name, false) == null)
return false;
Report.Error (519, loc, String.Format ("`{0}' clashes with a predefined namespace", name));
/// </summary>
static Type CoreLookupType (string ns_name, string name)
{
- Namespace ns = Namespace.LookupNamespace (ns_name, true);
+ Namespace ns = RootNamespace.Global.GetNamespace (ns_name, true);
FullNamedExpression fne = ns.Lookup (RootContext.Tree.Types, name, Location.Null);
Type t = fne == null ? null : fne.Type;
if (t == null)