//
// Mono.ILASM.ClassTable.cs
//
// Author(s):
// Jackson Harper (Jackson@LatitudeGeo.com)
//
// (C) 2003 Jackson Harper, All rights reserved
//
using PEAPI;
using System;
using System.Collections;
namespace Mono.ILASM {
public class ClassTable {
private class ClassTableItem {
private static readonly int DefinedFlag = 2;
private int flags;
public ArrayList LocationList;
public ClassDef Class;
public MethodTable method_table;
public FieldTable field_table;
public ClassTableItem (ClassDef klass, Location location)
{
flags = 0;
Class = klass;
LocationList = new ArrayList ();
LocationList.Add (location);
method_table = new MethodTable (klass);
field_table = new FieldTable (klass);
}
public bool Defined {
get { return ((flags & DefinedFlag) != 0); }
set {
if (value)
flags |= DefinedFlag;
else
flags ^= DefinedFlag;
}
}
public bool CheckDefined ()
{
if (!Defined)
return false;
if (!FieldTable.CheckDefined ())
return false;
if (!MethodTable.CheckDefined ())
return false;
return true;
}
public MethodTable MethodTable {
get { return method_table; }
}
public FieldTable FieldTable {
get { return field_table; }
}
}
protected readonly TypeAttr DefaultAttr;
protected Hashtable table;
protected PEFile pefile;
public ClassTable (PEFile pefile)
{
DefaultAttr = TypeAttr.Public;
this.pefile = pefile;
table = new Hashtable ();
}
public Class Get (string full_name)
{
ClassTableItem item = table[full_name] as ClassTableItem;
if (item == null)
return null;
return item.Class;
}
public Class GetReference (string full_name, Location location)
{
ClassTableItem item = table[full_name] as ClassTableItem;
if (item != null) {
item.LocationList.Add (location);
return item.Class;
}
string name_space, name;
GetNameAndNamespace (full_name, out name_space, out name);
ClassDef klass = pefile.AddClass (DefaultAttr, name_space, name);
AddReference (full_name, klass, location);
return klass;
}
public MethodTable GetMethodTable (string full_name, Location location)
{
ClassTableItem item = table[full_name] as ClassTableItem;
if (item == null) {
GetReference (full_name, location);
return GetMethodTable (full_name, location);
}
return item.MethodTable;
}
public FieldTable GetFieldTable (string full_name, Location location)
{
ClassTableItem item = table[full_name] as ClassTableItem;
if (item == null) {
GetReference (full_name, location);
return GetFieldTable (full_name, location);
}
return item.FieldTable;
}
public ClassDef AddDefinition (string name_space, string name,
TypeAttr attr, Location location)
{
string full_name;
if (name_space != null)
full_name = String.Format ("{0}.{1}", name_space, name);
else
full_name = name;
ClassTableItem item = (ClassTableItem) table[full_name];
if (item == null) {
ClassDef klass = pefile.AddClass (attr, name_space, name);
AddDefined (full_name, klass, location);
return klass;
}
item.Class.AddAttribute (attr);
item.Defined = true;
return item.Class;
}
public ClassDef AddDefinition (string name_space, string name,
TypeAttr attr, Class parent, Location location)
{
string full_name;
if (name_space != null)
full_name = String.Format ("{0}.{1}", name_space, name);
else
full_name = name;
ClassTableItem item = (ClassTableItem) table[full_name];
if (item == null) {
ClassDef klass = pefile.AddClass (attr, name_space, name, parent);
AddDefined (full_name, klass, location);
return klass;
}
/// TODO: Need to set parent, will need to modify PEAPI for this.
item.Class.AddAttribute (attr);
item.Defined = true;
return item.Class;
}
///
/// When there is no code left to compile, check to make sure referenced types where defined
/// TODO: Proper error reporting
///
public void CheckForUndefined ()
{
foreach (DictionaryEntry dic_entry in table) {
ClassTableItem table_item = (ClassTableItem) dic_entry.Value;
if (table_item.CheckDefined ())
continue;
throw new Exception (String.Format ("Type: {0} is not defined.", dic_entry.Key));
}
}
///
/// If a type is allready defined throw an Error
///
protected void CheckExists (string full_name)
{
ClassTableItem item = table[full_name] as ClassTableItem;
if ((item != null) && (item.Defined)) {
throw new Exception (String.Format ("Class: {0} defined in multiple locations.",
full_name));
}
}
protected void AddDefined (string full_name, ClassDef klass, Location location)
{
if (table.Contains (full_name))
return;
ClassTableItem item = new ClassTableItem (klass, location);
item.Defined = true;
table[full_name] = item;
}
protected void AddReference (string full_name, ClassDef klass, Location location)
{
if (table.Contains (full_name))
return;
ClassTableItem item = new ClassTableItem (klass, location);
table[full_name] = item;
}
public static void GetNameAndNamespace (string full_name,
out string name_space, out string name) {
int last_dot = full_name.LastIndexOf ('.');
if (last_dot < 0) {
name_space = String.Empty;
name = full_name;
return;
}
name_space = full_name.Substring (0, last_dot);
name = full_name.Substring (last_dot + 1);
}
}
}