//
using System;
using System.Collections;
-using Mono.Languages;
namespace Mono.CSharp {
/// <summary>
/// Keeps track of the namespaces defined in the C# code.
+ ///
+ /// This is an Expression to allow it to be referenced in the
+ /// compiler parse/intermediate tree during name resolution.
/// </summary>
- public class Namespace {
+ public class Namespace : FullNamedExpression, IAlias {
static ArrayList all_namespaces = new ArrayList ();
+ static Hashtable namespaces_map = new Hashtable ();
Namespace parent;
- string name;
+ string fullname;
ArrayList entries;
Hashtable namespaces;
+ Hashtable defined_names;
/// <summary>
/// Constructor Takes the current namespace and the
/// </summary>
public Namespace (Namespace parent, string name)
{
- this.name = name;
+ // Expression members.
+ this.eclass = ExprClass.Namespace;
+ this.Type = null;
+ this.loc = Location.Null;
+
this.parent = parent;
+ string pname = parent != null ? parent.Name : "";
+
+ if (pname == "")
+ fullname = name;
+ else
+ fullname = parent.Name + "." + name;
+
entries = new ArrayList ();
namespaces = new Hashtable ();
+ defined_names = new Hashtable ();
all_namespaces.Add (this);
+ if (namespaces_map.Contains (fullname))
+ return;
+ namespaces_map [fullname] = true;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ return this;
}
+ public override void Emit (EmitContext ec)
+ {
+ throw new InternalErrorException ("Expression tree referenced namespace " + fullname + " during Emit ()");
+ }
+
+ public static bool IsNamespace (string name)
+ {
+ return namespaces_map [name] != null;
+ }
+
public static Namespace Root = new Namespace (null, "");
public Namespace GetNamespace (string name, bool create)
return Root.GetNamespace (name, create);
}
+ public FullNamedExpression Lookup (DeclSpace ds, string name, Location loc)
+ {
+ IAlias o = (IAlias) defined_names [name];
+
+ Type t;
+ DeclSpace tdecl = o as DeclSpace;
+ if (tdecl != null) {
+ t = tdecl.DefineType ();
+
+ if ((ds == null) || ds.CheckAccessLevel (t))
+ return new TypeExpression (t, Location.Null);
+ }
+
+ Namespace ns = GetNamespace (name, false);
+ if (ns != null)
+ return ns;
+
+ t = TypeManager.LookupType (DeclSpace.MakeFQN (fullname, name));
+ if ((t == null) || ((ds != null) && !ds.CheckAccessLevel (t)))
+ return null;
+
+ return new TypeExpression (t, Location.Null);
+ }
+
public void AddNamespaceEntry (NamespaceEntry entry)
{
entries.Add (entry);
}
+ public void DefineName (string name, IAlias o)
+ {
+ defined_names.Add (name, o);
+ }
+
static public ArrayList UserDefinedNamespaces {
get {
return all_namespaces;
/// </summary>
public string Name {
get {
- string pname = parent != null ? parent.Name : "";
-
- if (pname == "")
- return name;
- else
- return String.Concat (parent.Name, ".", name);
+ return fullname;
+ }
+ }
+
+ public override string FullName {
+ get {
+ return fullname;
}
}
else
return String.Format ("Namespace ({0})", Name);
}
+
+ bool IAlias.IsType {
+ get { return false; }
+ }
+
+ TypeExpr IAlias.ResolveAsType (EmitContext ec)
+ {
+ throw new InvalidOperationException ();
+ }
}
public class NamespaceEntry
// exist.
//
public class UsingEntry {
- public readonly string Name;
+ public Expression Name;
public readonly NamespaceEntry NamespaceEntry;
public readonly Location Location;
- public UsingEntry (NamespaceEntry entry, string name, Location loc)
+ public UsingEntry (NamespaceEntry entry, Expression name, Location loc)
{
Name = name;
NamespaceEntry = entry;
Location = loc;
}
- Namespace resolved_ns;
+ internal FullNamedExpression resolved;
public Namespace Resolve ()
{
- if (resolved_ns != null)
- return resolved_ns;
-
- Namespace curr_ns = NamespaceEntry.NS;
- while ((curr_ns != null) && (resolved_ns == null)) {
- string full_name = DeclSpace.MakeFQN (curr_ns.Name, Name);
- resolved_ns = curr_ns.GetNamespace (Name, false);
+ if (resolved != null)
+ return resolved as Namespace;
- if (resolved_ns == null)
- curr_ns = curr_ns.Parent;
- }
+ DeclSpace root = RootContext.Tree.Types;
+ root.NamespaceEntry = NamespaceEntry;
+ resolved = Name.ResolveAsTypeStep (root.EmitContext);
+ root.NamespaceEntry = null;
- return resolved_ns;
+ return resolved as Namespace;
}
}
public class AliasEntry {
public readonly string Name;
- public readonly string Alias;
+ public readonly Expression Alias;
public readonly NamespaceEntry NamespaceEntry;
public readonly Location Location;
- public AliasEntry (NamespaceEntry entry, string name, string alias, Location loc)
+ public AliasEntry (NamespaceEntry entry, string name, Expression alias, Location loc)
{
Name = name;
Alias = alias;
Location = loc;
}
- object resolved;
+ FullNamedExpression resolved;
- public object Resolve ()
+ public FullNamedExpression Resolve ()
{
if (resolved != null)
return resolved;
- int pos = Alias.IndexOf ('.');
- if (pos >= 0) {
- string first = Alias.Substring (0, pos);
- }
-
- NamespaceEntry curr_ns = NamespaceEntry;
- while ((curr_ns != null) && (resolved == null)) {
- string full_name = DeclSpace.MakeFQN (curr_ns.Name, Alias);
- resolved = curr_ns.LookupName (Alias);
-
- if (resolved == null)
- curr_ns = curr_ns.Parent;
- }
+ DeclSpace root = RootContext.Tree.Types;
+ root.NamespaceEntry = NamespaceEntry;
+ resolved = Alias.ResolveAsTypeStep (root.EmitContext);
+ root.NamespaceEntry = null;
return resolved;
}
}
- public NamespaceEntry (NamespaceEntry parent, SourceFile file, string name)
- : this (parent, file, name, false)
- { }
-
- protected NamespaceEntry (NamespaceEntry parent, SourceFile file, string name, bool is_implicit)
+ public NamespaceEntry (NamespaceEntry parent, SourceFile file, string name, Location loc)
{
this.parent = parent;
this.file = file;
- this.IsImplicit = is_implicit;
+ this.IsImplicit = false;
this.ID = ++next_id;
if (parent != null)
else
ns = Namespace.Root;
ns.AddNamespaceEntry (this);
-
- if ((parent != null) && (parent.NS != ns.Parent))
- implicit_parent = new NamespaceEntry (parent, file, ns.Parent.Name, true);
- else
- implicit_parent = parent;
+ this.FullName = ns.Name;
}
- static int next_id = 0;
- public readonly int ID;
- public readonly bool IsImplicit;
- public string Name {
+ private NamespaceEntry (NamespaceEntry parent, SourceFile file, Namespace ns)
+ {
+ this.parent = parent;
+ this.file = file;
+ this.IsImplicit = true;
+ this.ID = ++next_id;
+ this.ns = ns;
+ this.FullName = ns.Name;
+ }
+
+ //
+ // According to section 16.3.1 (using-alias-directive), the namespace-or-type-name is
+ // resolved as if the immediately containing namespace body has no using-directives.
+ //
+ // Section 16.3.2 says that the same rule is applied when resolving the namespace-name
+ // in the using-namespace-directive.
+ //
+ // To implement these rules, the expressions in the using directives are resolved using
+ // the "doppelganger" (ghostly bodiless duplicate).
+ //
+ NamespaceEntry doppelganger;
+ NamespaceEntry Doppelganger {
get {
- return ns.Name;
+ if (!IsImplicit && doppelganger == null)
+ doppelganger = new NamespaceEntry (ImplicitParent, file, ns);
+ return doppelganger;
}
}
+ static int next_id = 0;
+ public readonly string FullName;
+ public readonly int ID;
+ public readonly bool IsImplicit;
+
public Namespace NS {
get {
return ns;
public NamespaceEntry ImplicitParent {
get {
+ if (parent == null)
+ return null;
+ if (implicit_parent == null) {
+ implicit_parent = (parent.NS == ns.Parent)
+ ? parent
+ : new NamespaceEntry (parent, file, ns.Parent);
+ }
return implicit_parent;
}
}
+ public void DefineName (string name, IAlias o)
+ {
+ ns.DefineName (name, o);
+ }
+
/// <summary>
/// Records a new namespace for resolving name references
/// </summary>
- public void Using (string ns, Location loc)
+ public void Using (Expression ns, Location loc)
{
+ string name = ns.ToString ();
if (DeclarationFound){
Report.Error (1529, loc, "A using clause must precede all other namespace elements");
return;
}
- if (ns == Name)
+ if (name == FullName)
return;
if (using_clauses == null)
using_clauses = new ArrayList ();
- foreach (UsingEntry old_entry in using_clauses){
- if (old_entry.Name == ns){
- Report.Warning (105, loc, "The using directive for '" + ns +
- "' appeared previously in this namespace");
+ foreach (UsingEntry old_entry in using_clauses) {
+ if (old_entry.Name.ToString () == name) {
+ if (RootContext.WarningLevel >= 3)
+ Report.Warning (105, loc, "The using directive for '{0}' appeared previously in this namespace", name);
return;
}
}
-
- UsingEntry ue = new UsingEntry (this, ns, loc);
+
+
+ UsingEntry ue = new UsingEntry (Doppelganger, ns, loc);
using_clauses.Add (ue);
}
- public void UsingAlias (string alias, string namespace_or_type, Location loc)
+ public void UsingAlias (string name, Expression alias, Location loc)
{
+ if (DeclarationFound){
+ Report.Error (1529, loc, "A using clause must precede all other namespace elements");
+ return;
+ }
+
if (aliases == null)
aliases = new Hashtable ();
- if (aliases.Contains (alias)){
- Report.Error (1537, loc, "The using alias `" + alias +
+ if (aliases.Contains (name)){
+ Report.Error (1537, loc, "The using alias `" + name +
"' appeared previously in this namespace");
return;
}
- aliases [alias] = new AliasEntry (this, alias, namespace_or_type, loc);
+ aliases [name] = new AliasEntry (Doppelganger, name, alias, loc);
}
- protected AliasEntry GetAliasEntry (string alias)
+ public FullNamedExpression LookupAlias (string alias)
{
AliasEntry entry = null;
-
if (aliases != null)
entry = (AliasEntry) aliases [alias];
- if (entry == null && Parent != null)
- entry = Parent.GetAliasEntry (alias);
- return entry;
+ return entry == null ? null : entry.Resolve ();
}
- public string LookupAlias (string alias)
+ public FullNamedExpression LookupNamespaceOrType (DeclSpace ds, string name, Location loc)
{
- AliasEntry entry = GetAliasEntry (alias);
+ FullNamedExpression resolved = null;
+ string rest = null;
- if (entry == null)
- return null;
+ // If name is of the form `N.I', first lookup `N', then search a member `I' in it.
+ int pos = name.IndexOf ('.');
+ if (pos >= 0) {
+ rest = name.Substring (pos + 1);
+ name = name.Substring (0, pos);
+ }
+
+ for (NamespaceEntry curr_ns = this; curr_ns != null; curr_ns = curr_ns.ImplicitParent) {
+ if ((resolved = curr_ns.Lookup (ds, name, loc)) != null)
+ break;
+ }
+
+ if (resolved == null || rest == null)
+ return resolved;
+
+ Namespace ns = resolved as Namespace;
+ if (ns != null)
+ return ns.Lookup (ds, rest, loc);
- object resolved = entry.Resolve ();
- if (resolved == null)
+ Type nested = TypeManager.LookupType (resolved.FullName + "." + rest);
+ if ((nested == null) || ((ds != null) && !ds.CheckAccessLevel (nested)))
return null;
- else if (resolved is Namespace)
- return ((Namespace) resolved).Name;
- else
- return ((Type) resolved).FullName;
+
+ return new TypeExpression (nested, Location.Null);
}
- public object LookupName (string name)
+ private FullNamedExpression Lookup (DeclSpace ds, string name, Location loc)
{
- Namespace ns = Namespace.LookupNamespace (name, false);
- if (ns != null)
- return ns;
+ // Precondition: Only simple names (no dots) will be looked up with this function.
- int pos = name.IndexOf ('.');
- AliasEntry alias = null;
- if (pos >= 0) {
- string first = name.Substring (0, pos);
- string last = name.Substring (pos + 1);
-
- alias = GetAliasEntry (first);
- if (alias != null)
- return LookupName (DeclSpace.MakeFQN (alias.Alias, last));
- }
+ //
+ // Check whether it's in the namespace.
+ //
+ FullNamedExpression o = NS.Lookup (ds, name, loc);
+ if (o != null)
+ return o;
- Type t = TypeManager.LookupType (name);
- if (t != null)
- return t;
+ if (IsImplicit)
+ return null;
- alias = GetAliasEntry (name);
- if (alias != null)
- return LookupName (alias.Alias);
+ //
+ // Check aliases.
+ //
+ o = LookupAlias (name);
+ if (o != null)
+ return o;
+
+ //
+ // Check using entries.
+ //
+ FullNamedExpression t = null, match = null;
+ foreach (Namespace using_ns in GetUsingTable ()) {
+ match = using_ns.Lookup (ds, name, loc);
+ if ((match != null) && (match is TypeExpr)) {
+ if (t != null) {
+ DeclSpace.Error_AmbiguousTypeReference (loc, name, t.FullName, match.FullName);
+ return null;
+ } else {
+ t = match;
+ }
+ }
+ }
- return null;
+ return t;
}
-
+
+ // Our cached computation.
+ Namespace [] namespace_using_table;
public Namespace[] GetUsingTable ()
{
- ArrayList list = new ArrayList ();
+ if (namespace_using_table != null)
+ return namespace_using_table;
- if (using_clauses == null)
- return new Namespace [0];
+ if (using_clauses == null) {
+ namespace_using_table = new Namespace [0];
+ return namespace_using_table;
+ }
+
+ ArrayList list = new ArrayList (using_clauses.Count);
foreach (UsingEntry ue in using_clauses) {
Namespace using_ns = ue.Resolve ();
list.Add (using_ns);
}
- Namespace[] retval = new Namespace [list.Count];
- list.CopyTo (retval, 0);
- return retval;
+ namespace_using_table = new Namespace [list.Count];
+ list.CopyTo (namespace_using_table, 0);
+ return namespace_using_table;
}
public void DefineNamespace (SymbolWriter symwriter)
if (using_clauses != null) {
using_list = new string [using_clauses.Count];
for (int i = 0; i < using_clauses.Count; i++)
- using_list [i] = ((UsingEntry) using_clauses [i]).Name;
+ using_list [i] = ((UsingEntry) using_clauses [i]).Name.ToString ();
} else {
using_list = new string [0];
}
int parent_id = parent != null ? parent.symfile_id : 0;
- symfile_id = symwriter.DefineNamespace (ns.Name, file, using_list, parent_id);
+ if (file.SourceFileEntry == null)
+ return;
+
+ symfile_id = symwriter.DefineNamespace (
+ ns.Name, file.SourceFileEntry, using_list, parent_id);
}
public int SymbolFileID {
}
}
- static void Msgtry (string s)
+ static void MsgtryRef (string s)
{
Console.WriteLine (" Try using -r:" + s);
}
+
+ static void MsgtryPkg (string s)
+ {
+ Console.WriteLine (" Try using -pkg:" + s);
+ }
+
+ protected void error246 (Location loc, string name)
+ {
+ Report.Error (246, loc, "The namespace `" + name +
+ "' can not be found (missing assembly reference?)");
+
+ switch (name) {
+ case "Gtk": case "GtkSharp":
+ MsgtryPkg ("gtk-sharp");
+ break;
+
+ case "Gdk": case "GdkSharp":
+ MsgtryPkg ("gdk-sharp");
+ break;
+
+ case "Glade": case "GladeSharp":
+ MsgtryPkg ("glade-sharp");
+ break;
+
+ case "System.Drawing":
+ case "System.Web.Services":
+ case "System.Web":
+ case "System.Data":
+ case "System.Windows.Forms":
+ MsgtryRef (name);
+ break;
+ }
+ }
/// <summary>
/// Used to validate that all the using clauses are correct
foreach (UsingEntry ue in using_clauses){
if (ue.Resolve () != null)
continue;
-
- Report.Error (246, ue.Location, "The namespace `" + ue.Name +
- "' can not be found (missing assembly reference?)");
-
- switch (ue.Name){
- case "Gtk": case "GtkSharp":
- Msgtry ("gtk-sharp");
- break;
-
- case "Gdk": case "GdkSharp":
- Msgtry ("gdk-sharp");
- break;
-
- case "Glade": case "GladeSharp":
- Msgtry ("glade-sharp");
- break;
-
- case "System.Drawing":
- Msgtry ("System.Drawing");
- break;
-
- case "System.Web.Services":
- Msgtry ("System.Web.Services");
- break;
-
- case "System.Web":
- Msgtry ("System.Web");
- break;
-
- case "System.Data":
- Msgtry ("System.Data");
- break;
-
- case "System.Windows.Forms":
- Msgtry ("System.Windows.Forms");
- break;
- }
+
+ if (ue.resolved == null)
+ error246 (ue.Location, ue.Name.ToString ());
+ else
+ Report.Error (138, ue.Location, "The using keyword only lets you specify a namespace, " +
+ "`" + ue.Name + "' is a class not a namespace.");
+
}
}
if (alias.Resolve () != null)
continue;
-
- Report.Error (246, String.Format (
- "The type or namespace `{0}' could not be found (missing assembly reference?)",
- alias.Alias));
+
+ error246 (alias.Location, alias.Alias.ToString ());
}
}
}
if (NS == Namespace.Root)
return "NamespaceEntry (<root>)";
else
- return String.Format ("NamespaceEntry ({0},{1},{2})", Name, IsImplicit, ID);
+ return String.Format ("NamespaceEntry ({0},{1},{2})", FullName, IsImplicit, ID);
}
}
}