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
150                 public ExternAssembly (string name, AssemblyName asmb_name) : base (name)
151                 {
152                         this.name = name;
153                         this.asmb_name = asmb_name;
154                         major = minor = build = revision = -1;
155                 }
156
157                 public override string FullName {
158                         get { 
159                                 //'name' field should not contain the []
160                                 //as its used for resolving
161                                 return String.Format ("[{0}]", name); 
162                         }
163                 }
164
165                 public AssemblyName AssemblyName {
166                         get { return asmb_name; }
167                 }
168
169                 public DeclSecurity DeclSecurity {
170                         get {
171                                 if (decl_sec == null)
172                                         decl_sec = new DeclSecurity ();
173                                 return decl_sec;
174                         }
175                 }
176
177                 public override void Resolve (CodeGen code_gen)
178                 {
179                         if (is_resolved)
180                                 return;
181
182                         AssemblyRef = code_gen.PEFile.AddExternAssembly (name);
183                         if (major != -1)
184                                 AssemblyRef.AddVersionInfo (major, minor, build, revision);
185                         if (public_key != null)
186                                 AssemblyRef.AddKey (public_key);
187                         if (public_key_token != null)
188                                 AssemblyRef.AddKeyToken (public_key_token);
189                         if (locale != null)
190                                 AssemblyRef.AddCulture (locale);
191                         if (hash != null)
192                                 AssemblyRef.AddHash (hash);
193
194                         if (customattr_list != null)
195                                 foreach (CustomAttr customattr in customattr_list)
196                                         customattr.AddTo (code_gen, AssemblyRef);
197                                         
198                         if (decl_sec != null)
199                                 decl_sec.AddTo (code_gen, AssemblyRef);
200
201                         class_table = new Hashtable ();
202
203                         is_resolved = true;
204                 }
205
206                 public override PEAPI.IExternRef GetExternRef ()
207                 {
208                         return AssemblyRef;
209                 }
210                 
211                 public void SetVersion (int major, int minor, int build, int revision)
212                 {
213                         this.major = major;
214                         this.minor = minor;
215                         this.build = build;
216                         this.revision = revision;
217                         asmb_name.Version = new Version (major, minor, build, revision);
218                 }
219
220                 public void SetPublicKey (byte [] public_key)
221                 {
222                         this.public_key = public_key;
223                         asmb_name.SetPublicKey (public_key);
224                 }
225
226                 public void SetPublicKeyToken (byte [] public_key_token)
227                 {
228                         this.public_key_token = public_key_token;
229                         asmb_name.SetPublicKey (public_key);
230                 }
231
232                 public void SetLocale (string locale)
233                 {
234                         this.locale = locale;
235                         //FIXME: is this correct?
236                         asmb_name.CultureInfo = new CultureInfo (locale);
237                 }
238
239                 public void SetHash (byte [] hash)
240                 {
241                         this.hash = hash;
242                 }
243
244         }
245
246         
247         public class ExternTable {
248
249                 Hashtable assembly_table;
250                 Hashtable module_table;
251                 bool is_resolved;
252                 
253                 public void AddCorlib ()
254                 {
255                         // Add mscorlib
256                         string mscorlib_name = "mscorlib";
257                         AssemblyName mscorlib = new AssemblyName ();
258                         mscorlib.Name = mscorlib_name;
259                         AddAssembly (mscorlib_name, mscorlib);
260
261                         // Also need to alias corlib, normally corlib and
262                         // mscorlib are used interchangably
263                         assembly_table["corlib"] = assembly_table["mscorlib"];
264                 }
265
266                 public ExternAssembly AddAssembly (string name, AssemblyName asmb_name)
267                 {
268                         ExternAssembly ea = null;
269
270                         if (assembly_table == null) {
271                                 assembly_table = new Hashtable ();
272                         } else {
273                                 ea = assembly_table [name] as ExternAssembly;
274                                 if (ea != null)
275                                         return ea;
276                         }
277
278                         ea = new ExternAssembly (name, asmb_name);
279
280                         assembly_table [name] = ea;
281
282                         return ea;
283                 }
284
285                 public ExternModule AddModule (string name)
286                 {
287                         ExternModule em = null;
288
289                         if (module_table == null) {
290                                 module_table = new Hashtable ();
291                         } else {
292                                 em = module_table [name] as ExternModule;
293                                 if (em != null)
294                                         return em;
295                         }
296
297                         em = new ExternModule (name);
298
299                         module_table [name] = em;
300
301                         return em;
302                 }
303
304                 public void Resolve (CodeGen code_gen)
305                 {
306                         if (is_resolved)
307                                 return;
308
309                         if (assembly_table != null)
310                                 foreach (ExternAssembly ext in assembly_table.Values)
311                                         ext.Resolve (code_gen);
312                         if (module_table == null)
313                                 return;
314                         foreach (ExternModule ext in module_table.Values)
315                                 ext.Resolve (code_gen);
316
317                         is_resolved = true;     
318                 }
319
320                 public ExternTypeRef GetTypeRef (string asmb_name, string full_name, bool is_valuetype)
321                 {
322                         ExternAssembly ext_asmb = null;
323                         if (assembly_table == null && (asmb_name == "mscorlib" || asmb_name == "corlib")) {
324                                 /* AddCorlib if mscorlib is being referenced but
325                                    we haven't encountered a ".assembly 'name'" as yet. */
326                                 Report.Warning (String.Format ("Reference to undeclared extern assembly '{0}', adding.", asmb_name));
327                                 AddCorlib ();
328                         }
329                         if (assembly_table != null)
330                                 ext_asmb = assembly_table[asmb_name] as ExternAssembly;
331
332                         if (ext_asmb == null) {
333                                 System.Reflection.AssemblyName asmname = new System.Reflection.AssemblyName ();
334                                 asmname.Name = asmb_name;
335
336                                 Report.Warning (String.Format ("Reference to undeclared extern assembly '{0}', adding.", asmb_name));
337                                 ext_asmb = AddAssembly (asmb_name, asmname);
338                         }
339
340                         return ext_asmb.GetTypeRef (full_name, is_valuetype);
341                 }
342
343                 public ExternTypeRef GetModuleTypeRef (string mod_name, string full_name, bool is_valuetype)
344                 {
345                         ExternModule mod = null;
346                         if (module_table != null)
347                                 mod = module_table [mod_name] as ExternModule;
348
349                         if (mod == null)
350                                 Report.Error ("Module " + mod_name + " not defined.");
351
352                         return mod.GetTypeRef (full_name, is_valuetype);
353                 }
354
355                 public static void GetNameAndNamespace (string full_name,
356                         out string name_space, out string name) {
357
358                         int last_dot = full_name.LastIndexOf ('.');
359
360                         if (last_dot < 0) {
361                                 name_space = String.Empty;
362                                 name = full_name;
363                                 return;
364                         }
365
366                         name_space = full_name.Substring (0, last_dot);
367                         name = full_name.Substring (last_dot + 1);
368                 }
369
370         }
371 }
372