New test.
[mono.git] / mcs / ilasm / codegen / ExternTable.cs
1 //
2 // Mono.ILASM.ExternTable.cs
3 //
4 // Author(s):
5 //  Jackson Harper (Jackson@LatitudeGeo.com)
6 //
7 // (C) 2003 Jackson Harper, All rights reserved
8 //
9
10 using System;
11 using System.Collections;
12 using System.Reflection;
13 using System.Security;
14 using System.Globalization;
15
16 namespace Mono.ILASM {
17
18         public interface IScope {
19                 ExternTypeRef GetTypeRef (string full_name, bool is_valuetype);
20                 PEAPI.ClassRef GetType (string full_name, bool is_valuetype);
21                 string FullName { get; }
22         }
23         
24         public abstract class ExternRef : ICustomAttrTarget, IScope {
25
26                 protected string name;
27                 protected Hashtable class_table;
28                 protected Hashtable typeref_table;
29                 protected ArrayList customattr_list;
30                 protected bool is_resolved;
31
32                 public abstract void Resolve (CodeGen codegen);
33                 public abstract PEAPI.IExternRef GetExternRef ();
34
35                 public ExternRef (string name)
36                 {
37                         this.name = name;
38                         typeref_table = new Hashtable ();
39                         class_table = new Hashtable ();
40                 }
41
42                 public string Name {
43                         get { return name; }
44                 }
45
46                 public virtual string FullName {
47                         get { return name; }
48                 }
49
50                 public void AddCustomAttribute (CustomAttr customattr)
51                 {
52                         if (customattr_list == null)
53                                 customattr_list = new ArrayList ();
54
55                         customattr_list.Add (customattr);
56                 }
57
58                 public ExternTypeRef GetTypeRef (string full_name, bool is_valuetype)
59                 {
60                         string first= full_name;
61                         string rest = "";
62                         int slash = full_name.IndexOf ('/');
63                         if (slash > 0) {
64                                 first = full_name.Substring (0, slash);
65                                 rest = full_name.Substring (slash + 1);
66                         }
67                                 
68                         ExternTypeRef type_ref = typeref_table [first] as ExternTypeRef;
69                         
70                         if (type_ref != null) {
71                                 if (is_valuetype && rest == "")
72                                         type_ref.MakeValueClass ();
73                         } else {
74                                 type_ref = new ExternTypeRef (this, first, is_valuetype);
75                                 typeref_table [first] = type_ref;
76                         }
77
78                         return (rest == "" ? type_ref : type_ref.GetTypeRef (rest, is_valuetype));
79                 }
80
81                 public PEAPI.ClassRef GetType (string full_name, bool is_valuetype)
82                 {
83                         PEAPI.ClassRef klass = class_table[full_name] as PEAPI.ClassRef;
84                         
85                         if (klass != null)
86                                 return klass;
87
88                         string name_space, name;
89                         ExternTable.GetNameAndNamespace (full_name, out name_space, out name);
90
91                         if (is_valuetype)
92                                 klass = (PEAPI.ClassRef) GetExternRef ().AddValueClass (name_space, name);
93                         else        
94                                 klass = (PEAPI.ClassRef) GetExternRef ().AddClass (name_space, name);
95
96                         class_table [full_name] = klass;
97                         return klass;
98                 }
99
100         }
101
102         public class ExternModule : ExternRef {
103
104                 public PEAPI.ModuleRef ModuleRef;
105
106                 public ExternModule (string name) : base (name)
107                 {
108                 }
109
110                 public override string FullName {
111                         get { 
112                                 //'name' field should not contain the [.module ]
113                                 //as its used for resolving
114                                 return String.Format ("[.module {0}]", name); 
115                         }
116                 }
117
118                 public override void Resolve (CodeGen codegen)
119                 {
120                         if (is_resolved)
121                                 return;
122
123                         ModuleRef = codegen.PEFile.AddExternModule (name);
124                         if (customattr_list != null)
125                                 foreach (CustomAttr customattr in customattr_list)
126                                         customattr.AddTo (codegen, ModuleRef);
127
128                         is_resolved = true;
129                 }
130
131                 
132                 public override PEAPI.IExternRef GetExternRef ()
133                 {
134                         return ModuleRef;
135                 }
136         }
137
138         public class ExternAssembly : ExternRef, IDeclSecurityTarget {
139                         
140                 public PEAPI.AssemblyRef AssemblyRef;
141
142                 private int major, minor, build, revision;
143                 private byte [] public_key;
144                 private byte [] public_key_token;
145                 private string locale;
146                 private byte [] hash;
147                 private DeclSecurity decl_sec;
148                 private AssemblyName asmb_name;
149                 //flags
150                 private PEAPI.AssemAttr attr;
151
152                 public ExternAssembly (string name, AssemblyName asmb_name, PEAPI.AssemAttr attr) : base (name)
153                 {
154                         this.name = name;
155                         this.asmb_name = asmb_name;
156                         this.attr = attr;
157                         major = minor = build = revision = -1;
158                 }
159
160                 public override string FullName {
161                         get { 
162                                 //'name' field should not contain the []
163                                 //as its used for resolving
164                                 return String.Format ("[{0}]", name); 
165                         }
166                 }
167
168                 public AssemblyName AssemblyName {
169                         get { return asmb_name; }
170                 }
171
172                 public DeclSecurity DeclSecurity {
173                         get {
174                                 if (decl_sec == null)
175                                         decl_sec = new DeclSecurity ();
176                                 return decl_sec;
177                         }
178                 }
179
180                 public override void Resolve (CodeGen code_gen)
181                 {
182                         if (is_resolved)
183                                 return;
184
185                         AssemblyRef = code_gen.PEFile.AddExternAssembly (name);
186                         AssemblyRef.AddAssemblyAttr (attr);
187                         if (major != -1)
188                                 AssemblyRef.AddVersionInfo (major, minor, build, revision);
189                         if (public_key != null)
190                                 AssemblyRef.AddKey (public_key);
191                         if (public_key_token != null)
192                                 AssemblyRef.AddKeyToken (public_key_token);
193                         if (locale != null)
194                                 AssemblyRef.AddCulture (locale);
195                         if (hash != null)
196                                 AssemblyRef.AddHash (hash);
197
198                         if (customattr_list != null)
199                                 foreach (CustomAttr customattr in customattr_list)
200                                         customattr.AddTo (code_gen, AssemblyRef);
201                                         
202                         if (decl_sec != null)
203                                 decl_sec.AddTo (code_gen, AssemblyRef);
204
205                         class_table = new Hashtable ();
206
207                         is_resolved = true;
208                 }
209
210                 public override PEAPI.IExternRef GetExternRef ()
211                 {
212                         return AssemblyRef;
213                 }
214                 
215                 public void SetVersion (int major, int minor, int build, int revision)
216                 {
217                         this.major = major;
218                         this.minor = minor;
219                         this.build = build;
220                         this.revision = revision;
221                         asmb_name.Version = new Version (major, minor, build, revision);
222                 }
223
224                 public void SetPublicKey (byte [] public_key)
225                 {
226                         this.public_key = public_key;
227                         asmb_name.SetPublicKey (public_key);
228                 }
229
230                 public void SetPublicKeyToken (byte [] public_key_token)
231                 {
232                         this.public_key_token = public_key_token;
233                         asmb_name.SetPublicKey (public_key);
234                 }
235
236                 public void SetLocale (string locale)
237                 {
238                         this.locale = locale;
239                         //FIXME: is this correct?
240                         asmb_name.CultureInfo = new CultureInfo (locale);
241                 }
242
243                 public void SetHash (byte [] hash)
244                 {
245                         this.hash = hash;
246                 }
247
248         }
249
250         
251         public class ExternTable {
252
253                 Hashtable assembly_table;
254                 Hashtable module_table;
255                 bool is_resolved;
256                 
257                 public void AddCorlib ()
258                 {
259                         // Add mscorlib
260                         string mscorlib_name = "mscorlib";
261                         AssemblyName mscorlib = new AssemblyName ();
262                         mscorlib.Name = mscorlib_name;
263                         AddAssembly (mscorlib_name, mscorlib, 0);
264
265                         // Also need to alias corlib, normally corlib and
266                         // mscorlib are used interchangably
267                         assembly_table["corlib"] = assembly_table["mscorlib"];
268                 }
269
270                 public ExternAssembly AddAssembly (string name, AssemblyName asmb_name, PEAPI.AssemAttr attr)
271                 {
272                         ExternAssembly ea = null;
273
274                         if (assembly_table == null) {
275                                 assembly_table = new Hashtable ();
276                         } else {
277                                 ea = assembly_table [name] as ExternAssembly;
278                                 if (ea != null)
279                                         return ea;
280                         }
281
282                         ea = new ExternAssembly (name, asmb_name, attr);
283
284                         assembly_table [name] = ea;
285
286                         return ea;
287                 }
288
289                 public ExternModule AddModule (string name)
290                 {
291                         ExternModule em = null;
292
293                         if (module_table == null) {
294                                 module_table = new Hashtable ();
295                         } else {
296                                 em = module_table [name] as ExternModule;
297                                 if (em != null)
298                                         return em;
299                         }
300
301                         em = new ExternModule (name);
302
303                         module_table [name] = em;
304
305                         return em;
306                 }
307
308                 public void Resolve (CodeGen code_gen)
309                 {
310                         if (is_resolved)
311                                 return;
312
313                         if (assembly_table != null)
314                                 foreach (ExternAssembly ext in assembly_table.Values)
315                                         ext.Resolve (code_gen);
316                         if (module_table == null)
317                                 return;
318                         foreach (ExternModule ext in module_table.Values)
319                                 ext.Resolve (code_gen);
320
321                         is_resolved = true;     
322                 }
323
324                 public ExternTypeRef GetTypeRef (string asmb_name, string full_name, bool is_valuetype)
325                 {
326                         ExternAssembly ext_asmb = null;
327                         if (assembly_table == null && (asmb_name == "mscorlib" || asmb_name == "corlib")) {
328                                 /* AddCorlib if mscorlib is being referenced but
329                                    we haven't encountered a ".assembly 'name'" as yet. */
330                                 Report.Warning (String.Format ("Reference to undeclared extern assembly '{0}', adding.", asmb_name));
331                                 AddCorlib ();
332                         }
333                         if (assembly_table != null)
334                                 ext_asmb = assembly_table[asmb_name] as ExternAssembly;
335
336                         if (ext_asmb == null) {
337                                 System.Reflection.AssemblyName asmname = new System.Reflection.AssemblyName ();
338                                 asmname.Name = asmb_name;
339
340                                 Report.Warning (String.Format ("Reference to undeclared extern assembly '{0}', adding.", asmb_name));
341                                 ext_asmb = AddAssembly (asmb_name, asmname, 0);
342                         }
343
344                         return ext_asmb.GetTypeRef (full_name, is_valuetype);
345                 }
346
347                 public ExternTypeRef GetModuleTypeRef (string mod_name, string full_name, bool is_valuetype)
348                 {
349                         ExternModule mod = null;
350                         if (module_table != null)
351                                 mod = module_table [mod_name] as ExternModule;
352
353                         if (mod == null)
354                                 Report.Error ("Module " + mod_name + " not defined.");
355
356                         return mod.GetTypeRef (full_name, is_valuetype);
357                 }
358
359                 public static void GetNameAndNamespace (string full_name,
360                         out string name_space, out string name) {
361
362                         int last_dot = full_name.LastIndexOf ('.');
363
364                         if (last_dot < 0) {
365                                 name_space = String.Empty;
366                                 name = full_name;
367                                 return;
368                         }
369
370                         name_space = full_name.Substring (0, last_dot);
371                         name = full_name.Substring (last_dot + 1);
372                 }
373
374         }
375 }
376