163ad3c866d9af02cfb5fc20c0d70c34952f0e04
[mono.git] / mcs / mbas / codegen.cs
1 //
2 // codegen.cs: The code generator
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //
7 // (C) 2001 Ximian, Inc.
8 //
9
10 using System;
11 using System.IO;
12 using System.Collections;
13 using System.Reflection;
14 using System.Reflection.Emit;
15 using System.Diagnostics.SymbolStore;
16
17 namespace Mono.MonoBASIC {
18
19         /// <summary>
20         ///    Code generator class.
21         /// </summary>
22         public class CodeGen {
23                 static AppDomain current_domain;
24
25                 public static AssemblyBuilder AssemblyBuilder {
26                         get { 
27                                 return Assembly.Builder;
28                         }                               
29
30                         set {
31                                 Assembly.Builder = value;
32                         }                               
33                 }
34
35                 public static ModuleBuilder ModuleBuilder {
36                         get { 
37                                 return Module.Builder;
38                         }                               
39
40                         set {
41                                 Module.Builder = value;
42                         }                               
43                 }
44
45                 public static AssemblyClass Assembly;
46                 public static ModuleClass Module;
47                 public static ArrayList ArrListVersion = new ArrayList();//keeps the version's 4 numbers
48
49                 static public ISymbolWriter SymbolWriter;
50
51                 static CodeGen ()
52                 {
53                         Assembly = new AssemblyClass ();
54                         Module = new ModuleClass ();
55                 }
56
57                 public static string Basename (string name)
58                 {
59                         int pos = name.LastIndexOf ("/");
60
61                         if (pos != -1)
62                                 return name.Substring (pos + 1);
63
64                         pos = name.LastIndexOf ("\\");
65                         if (pos != -1)
66                                 return name.Substring (pos + 1);
67
68                         return name;
69                 }
70
71                 public static string Dirname (string name)
72                 {
73                         int pos = name.LastIndexOf ("/");
74
75                         if (pos != -1)
76                                 return name.Substring (0, pos);
77
78                         pos = name.LastIndexOf ("\\");
79                         if (pos != -1)
80                                 return name.Substring (0, pos);
81
82                         return ".";
83                 }
84
85                 static string TrimExt (string name)
86                 {
87                         int pos = name.LastIndexOf (".");
88
89                         return name.Substring (0, pos);
90                 }
91
92                 static public string FileName;
93
94                 //
95                 // This routine initializes the Mono runtime SymbolWriter.
96                 //
97                 static bool InitMonoSymbolWriter (string basename, string symbol_output,
98                                                   string exe_output_file, string[] debug_args)
99                 {
100                         Type itype = SymbolWriter.GetType ();
101                         if (itype == null)
102                                 return false;
103
104                         Type[] arg_types = new Type [3];
105                         arg_types [0] = typeof (string);
106                         arg_types [1] = typeof (string);
107                         arg_types [2] = typeof (string[]);
108
109                         MethodInfo initialize = itype.GetMethod ("Initialize", arg_types);
110                         if (initialize == null)
111                                 return false;
112
113                         object[] args = new object [3];
114                         args [0] = exe_output_file;
115                         args [1] = symbol_output;
116                         args [2] = debug_args;
117
118                         initialize.Invoke (SymbolWriter, args);
119                         return true;
120                 }
121
122                 //
123                 // Initializes the symbol writer
124                 //
125                 static void InitializeSymbolWriter (string basename, string symbol_output,
126                                                     string exe_output_file, string[] args)
127                 {
128                         SymbolWriter = ModuleBuilder.GetSymWriter ();
129
130                         //
131                         // If we got an ISymbolWriter instance, initialize it.
132                         //
133                         if (SymbolWriter == null) {
134                                 Report.Warning (
135                                         -18, "Cannot find any symbol writer");
136                                 return;
137                         }
138                         
139                         //
140                         // Due to lacking documentation about the first argument of the
141                         // Initialize method, we cannot use Microsoft's default symbol
142                         // writer yet.
143                         //
144                         // If we're using the mono symbol writer, the SymbolWriter object
145                         // is of type MonoSymbolWriter - but that's defined in a dynamically
146                         // loaded DLL - that's why we're doing a comparision based on the type
147                         // name here instead of using `SymbolWriter is MonoSymbolWriter'.
148                         //
149                         Type sym_type = ((object) SymbolWriter).GetType ();
150                         
151                         switch (sym_type.Name){
152                         case "MonoSymbolWriter":
153                                 if (!InitMonoSymbolWriter (basename, symbol_output,
154                                                            exe_output_file, args))
155                                         Report.Warning (
156                                                 -18, "Cannot initialize the symbol writer");
157                                 break;
158
159                         default:
160                                 Report.Warning (
161                                         -18, "Cannot generate debugging information on this platform");
162                                 break;
163                         }
164                 }
165
166                 //
167                 // Initializes the code generator variables
168                 //
169                 static public void Init (string name, string output, bool want_debugging_support,
170                                          string[] debug_args)
171                 {
172                         AssemblyName an;
173
174                         FileName = output;
175                         an = new AssemblyName ();
176                         an.Name = TrimExt (Basename (name));
177                         current_domain = AppDomain.CurrentDomain;
178                         
179                         if (ArrListVersion.Count < 4)//4 -> Major, Minor,Version, Build
180                         for(int i=ArrListVersion.Count-1;i<4;i++)
181                                 ArrListVersion.Add(0);
182                         an.Version = new Version (Convert.ToInt32(ArrListVersion[0]), Convert.ToInt32(ArrListVersion[1]), Convert.ToInt32(ArrListVersion[2]), Convert.ToInt32(ArrListVersion[3]));
183         
184                         AssemblyBuilder = current_domain.DefineDynamicAssembly (
185                                 an, AssemblyBuilderAccess.RunAndSave, Dirname (name));
186
187                         //
188                         // Pass a path-less name to DefineDynamicModule.  Wonder how
189                         // this copes with output in different directories then.
190                         // FIXME: figure out how this copes with --output /tmp/blah
191                         //
192                         // If the third argument is true, the ModuleBuilder will dynamically
193                         // load the default symbol writer.
194                         //
195                         
196                         ModuleBuilder = AssemblyBuilder.DefineDynamicModule (
197                                 Basename (name), Basename (output), want_debugging_support);
198
199                         int pos = output.LastIndexOf (".");
200
201                         string basename;
202                         if (pos > 0)
203                                 basename = output.Substring (0, pos);
204                         else
205                                 basename = output;
206
207                         string symbol_output = basename + ".dbg";
208
209                         if (want_debugging_support)
210                                 InitializeSymbolWriter (basename, symbol_output, output, debug_args);
211                         else {
212                                 try {
213                                         File.Delete (symbol_output);
214                                 } catch {
215                                         // Ignore errors.
216                                 }
217                         }
218                 }
219
220                 static public void Save (string name)
221                 {
222                         try {
223                                 AssemblyBuilder.Save (Basename (name));
224                         } catch (System.IO.IOException io){
225                                 Report.Error (16, "Coult not write to file `"+name+"', cause: " + io.Message);
226                         }
227                 }
228
229                 static public void SaveSymbols ()
230                 {
231                         if (SymbolWriter != null) {
232                                 // If we have a symbol writer, call its Close() method to write
233                                 // the symbol file to disk.
234                                 //
235                                 // When using Mono's default symbol writer, the Close() method must
236                                 // be called after the assembly has already been written to disk since
237                                 // it opens the assembly and reads its metadata.
238                                 SymbolWriter.Close ();
239                         }
240                 }
241
242                 public static void AddGlobalAttributes (ArrayList attrs)
243                 {
244                         foreach (Attribute attr in attrs) {
245                                 if (attr.IsAssemblyAttribute)
246                                 {
247                                         Assembly.AddAttribute (attr);
248                                 }
249                                 else if (attr.IsModuleAttribute)
250                                 {
251                                         Module.AddAttribute (attr);
252                                 }
253                         }
254                 }
255
256                 public static void EmitGlobalAttributes ()
257                 {
258                         //Assembly.Emit (Tree.Types);
259                         //Module.Emit (Tree.Types);
260                         
261
262                 }
263         }
264
265         /// <summary>
266         ///   An Emit Context is created for each body of code (from methods,
267         ///   properties bodies, indexer bodies or constructor bodies)
268         /// </summary>
269         public class EmitContext {
270                 
271                 public DeclSpace DeclSpace;
272                 public TypeContainer TypeContainer;
273                 public ILGenerator   ig;
274         
275
276                 /// <summary>
277                 ///   This variable tracks the `checked' state of the compilation,
278                 ///   it controls whether we should generate code that does overflow
279                 ///   checking, or if we generate code that ignores overflows.
280                 ///
281                 ///   The default setting comes from the command line option to generate
282                 ///   checked or unchecked code plus any source code changes using the
283                 ///   checked/unchecked statements or expressions.   Contrast this with
284                 ///   the ConstantCheckState flag.
285                 /// </summary>
286                 
287                 public bool CheckState;
288
289                 /// <summary>
290                 ///   The constant check state is always set to `true' and cant be changed
291                 ///   from the command line.  The source code can change this setting with
292                 ///   the `checked' and `unchecked' statements and expressions. 
293                 /// </summary>
294                 public bool ConstantCheckState;
295
296                 /// <summary>
297                 ///   Whether we are emitting code inside a static or instance method
298                 /// </summary>
299                 public bool IsStatic;
300
301                 /// <summary>
302                 ///   Whether we are emitting a field initializer
303                 /// </summary>
304                 public bool IsFieldInitializer;
305
306                 /// <summary>
307                 ///   The value that is allowed to be returned or NULL if there is no
308                 ///   return type.
309                 /// </summary>
310                 public Type ReturnType;
311
312                 /// <summary>
313                 ///   Points to the Type (extracted from the TypeContainer) that
314                 ///   declares this body of code
315                 /// </summary>
316                 public Type ContainerType;
317                 
318                 /// <summary>
319                 ///   Whether this is generating code for a constructor
320                 /// </summary>
321                 public bool IsConstructor;
322
323                 /// <summary>
324                 ///   Whether we're control flow analysis enabled
325                 /// </summary>
326                 public bool DoFlowAnalysis;
327                 
328                 /// <summary>
329                 ///   Keeps track of the Type to LocalBuilder temporary storage created
330                 ///   to store structures (used to compute the address of the structure
331                 ///   value on structure method invocations)
332                 /// </summary>
333                 public Hashtable temporary_storage;
334
335                 public Block CurrentBlock;
336
337                 /// <summary>
338                 ///   The location where we store the return value.
339                 /// </summary>
340                 LocalBuilder return_value;
341
342                 /// <summary>
343                 ///   The location where return has to jump to return the
344                 ///   value
345                 /// </summary>
346                 public Label ReturnLabel;
347
348                 /// <summary>
349                 ///   If we already defined the ReturnLabel
350                 /// </summary>
351                 public bool HasReturnLabel;
352
353                 /// <summary>
354                 ///   The location where to exit
355                 /// </summary>
356                 public Label ExitLabel;
357
358                 /// <summary>
359                 ///   If we already defined the ExitLabel
360                 /// </summary>
361                 public bool HasExitLabel;
362
363                 /// <summary>
364                 ///   Whether we are in a Finally block
365                 /// </summary>
366                 public bool InFinally;
367
368                 /// <summary>
369                 ///   Whether we are in a Try block
370                 /// </summary>
371                 public bool InTry;
372
373                 /// <summary>
374                 ///   Whether we are in a Catch block
375                 /// </summary>
376                 public bool InCatch;
377
378                 /// <summary>
379                 ///  Whether we are inside an unsafe block
380                 /// </summary>
381                 public bool InUnsafe;
382                 
383                 /// <summary>
384                 ///  Whether we are inside an unsafe block
385                 /// </summary>
386                 public bool InvokingOwnOverload;                
387
388                 /// <summary>
389                 ///   Location for this EmitContext
390                 /// </summary>
391                 public Location loc;
392
393                 /// <summary>
394                 ///   Used to flag that it is ok to define types recursively, as the
395                 ///   expressions are being evaluated as part of the type lookup
396                 ///   during the type resolution process
397                 /// </summary>
398                 public bool ResolvingTypeTree;
399                 
400                 /// <summary>
401                 ///   Inside an enum definition, we do not resolve enumeration values
402                 ///   to their enumerations, but rather to the underlying type/value
403                 ///   This is so EnumVal + EnumValB can be evaluated.
404                 ///
405                 ///   There is no "E operator + (E x, E y)", so during an enum evaluation
406                 ///   we relax the rules
407                 /// </summary>
408                 public bool InEnumContext;
409                 
410                 public string BlockName;
411
412                 protected Stack FlowStack;
413                 
414                 public EmitContext (TypeContainer parent, DeclSpace ds, Location l, ILGenerator ig,
415                                     Type return_type, int code_flags, bool is_constructor)
416                 {
417                         this.ig = ig;
418                         TypeContainer = parent;
419                         DeclSpace = ds;
420                         CheckState = RootContext.Checked;
421                         ConstantCheckState = true;
422                         
423                         IsStatic = (code_flags & Modifiers.STATIC) != 0;
424                         ReturnType = return_type;
425                         IsConstructor = is_constructor;
426                         CurrentBlock = null;
427                         BlockName = "";
428                         InvokingOwnOverload = false;
429                         
430                         if (parent != null){
431                                 // Can only be null for the ResolveType contexts.
432                                 ContainerType = parent.TypeBuilder;
433                                 if (parent.UnsafeContext)
434                                         InUnsafe = true;
435                                 else
436                                         InUnsafe = (code_flags & Modifiers.UNSAFE) != 0;
437                         }
438                         loc = l;
439
440                         FlowStack = new Stack ();
441                         
442                         if (ReturnType == TypeManager.void_type)
443                                 ReturnType = null;
444                 }
445
446                 public EmitContext (TypeContainer tc, Location l, ILGenerator ig,
447                                     Type return_type, int code_flags, bool is_constructor)
448                         : this (tc, tc, l, ig, return_type, code_flags, is_constructor)
449                 {
450                 }
451
452                 public EmitContext (TypeContainer tc, Location l, ILGenerator ig,
453                                     Type return_type, int code_flags)
454                         : this (tc, tc, l, ig, return_type, code_flags, false)
455                 {
456                 }
457
458                 public FlowBranching CurrentBranching {
459                         get {
460                                 return (FlowBranching) FlowStack.Peek ();
461                         }
462                 }
463
464                 // <summary>
465                 //   Starts a new code branching.  This inherits the state of all local
466                 //   variables and parameters from the current branching.
467                 // </summary>
468                 public FlowBranching StartFlowBranching (FlowBranchingType type, Location loc)
469                 {
470                         FlowBranching cfb = new FlowBranching (CurrentBranching, type, null, loc);
471
472                         FlowStack.Push (cfb);
473
474                         return cfb;
475                 }
476
477                 // <summary>
478                 //   Starts a new code branching for block `block'.
479                 // </summary>
480                 public FlowBranching StartFlowBranching (Block block)
481                 {
482                         FlowBranching cfb;
483                         FlowBranchingType type;
484
485                         if (CurrentBranching.Type == FlowBranchingType.SWITCH)
486                                 type = FlowBranchingType.SWITCH_SECTION;
487                         else
488                                 type = FlowBranchingType.BLOCK;
489
490                         cfb = new FlowBranching (CurrentBranching, type, block, block.StartLocation);
491
492                         FlowStack.Push (cfb);
493
494                         return cfb;
495                 }
496
497                 // <summary>
498                 //   Ends a code branching.  Merges the state of locals and parameters
499                 //   from all the children of the ending branching.
500                 // </summary>
501                 public FlowReturns EndFlowBranching ()
502                 {
503                         FlowBranching cfb = (FlowBranching) FlowStack.Pop ();
504
505                         return CurrentBranching.MergeChild (cfb);
506                 }
507
508                 // <summary>
509                 //   Kills the current code branching.  This throws away any changed state
510                 //   information and should only be used in case of an error.
511                 // </summary>
512                 public void KillFlowBranching ()
513                 {
514                         /*FlowBranching cfb = (FlowBranching)*/ FlowStack.Pop ();
515                 }
516
517                 // <summary>
518                 //   Checks whether the local variable `vi' is already initialized
519                 //   at the current point of the method's control flow.
520                 //   If this method returns false, the caller must report an
521                 //   error 165.
522                 // </summary>
523                 public bool IsVariableAssigned (VariableInfo vi)
524                 {
525                         if (DoFlowAnalysis)
526                                 return CurrentBranching.IsVariableAssigned (vi);
527                         else
528                                 return true;
529                 }
530
531                 // <summary>
532                 //   Marks the local variable `vi' as being initialized at the current
533                 //   current point of the method's control flow.
534                 // </summary>
535                 public void SetVariableAssigned (VariableInfo vi)
536                 {
537                         if (DoFlowAnalysis)
538                                 CurrentBranching.SetVariableAssigned (vi);
539                 }
540
541                 // <summary>
542                 //   Checks whether the parameter `number' is already initialized
543                 //   at the current point of the method's control flow.
544                 //   If this method returns false, the caller must report an
545                 //   error 165.  This is only necessary for `out' parameters and the
546                 //   call will always succeed for non-`out' parameters.
547                 // </summary>
548                 public bool IsParameterAssigned (int number)
549                 {
550                         if (DoFlowAnalysis)
551                                 return CurrentBranching.IsParameterAssigned (number);
552                         else
553                                 return true;
554                 }
555
556                 // <summary>
557                 //   Marks the parameter `number' as being initialized at the current
558                 //   current point of the method's control flow.  This is only necessary
559                 //   for `out' parameters.
560                 // </summary>
561                 public void SetParameterAssigned (int number)
562                 {
563                         if (DoFlowAnalysis)
564                                 CurrentBranching.SetParameterAssigned (number);
565                 }
566
567                 // These are two overloaded methods for EmitTopBlock
568                 // since in MonoBasic functions we need the Function name
569                 // along with its top block, in order to be able to
570                 // retrieve the return value when there is no explicit 
571                 // 'Return' statement
572                 public void EmitTopBlock (Block block, InternalParameters ip, Location loc)
573                 {
574                         EmitTopBlock (block, "", ip, loc);
575                 }
576
577                 public void EmitTopBlock (Block block, string bname, InternalParameters ip, Location loc)
578                 {
579                         bool has_ret = false;
580
581                         //Console.WriteLine ("Emitting: '{0}", bname);
582                         BlockName = bname;
583                         if (CodeGen.SymbolWriter != null)
584                                 Mark (loc);
585
586                         if (block != null){
587                                 int errors = Report.Errors;
588
589                                 block.EmitMeta (this, block);
590
591                                 if (Report.Errors == errors){
592                                         bool old_do_flow_analysis = DoFlowAnalysis;
593                                         DoFlowAnalysis = true;
594
595                                         FlowBranching cfb = new FlowBranching (block, ip, loc);
596                                         FlowStack.Push (cfb);
597
598                                         if (!block.Resolve (this)) {
599                                                 FlowStack.Pop ();
600                                                 DoFlowAnalysis = old_do_flow_analysis;
601                                                 return;
602                                         }
603
604                                         cfb = (FlowBranching) FlowStack.Pop ();
605                                         FlowReturns returns = cfb.MergeTopBlock ();
606
607                                         DoFlowAnalysis = old_do_flow_analysis;
608
609                                         has_ret = block.Emit (this);
610
611                                         if ((returns == FlowReturns.ALWAYS) ||
612                                             (returns == FlowReturns.EXCEPTION) ||
613                                             (returns == FlowReturns.UNREACHABLE))
614                                                 has_ret = true;
615
616                                         if (Report.Errors == errors){
617                                                 if (RootContext.WarningLevel >= 3)
618                                                         block.UsageWarning ();
619                                         }
620                                 }
621                         }
622
623                         if (HasReturnLabel)
624                                 ig.MarkLabel (ReturnLabel);
625                         if (return_value != null){
626                                 ig.Emit (OpCodes.Ldloc, return_value);
627                                 ig.Emit (OpCodes.Ret);
628                                 return;
629                         }
630
631                         if (ReturnType != null && !has_ret){
632                                 //
633                                 // mcs here would report an error (and justly so), but functions without
634                                 // an explicit return value are perfectly legal in MonoBasic
635                                 //
636                                 
637                                 VariableInfo vi = block.GetVariableInfo (bname);
638                                 if (vi != null) 
639                                 {
640                                         ig.Emit (OpCodes.Ldloc, vi.LocalBuilder);
641                                         ig.Emit (OpCodes.Ret);
642                                 }
643                                 else
644                                         Report.Error (-200, "This is not supposed to happen !");
645                                 return;
646                         }
647
648                         if (!InTry){
649                                 if (!has_ret)
650                                         ig.Emit (OpCodes.Ret);
651                                 else if (ReturnType == null)
652                                         ig.Emit (OpCodes.Ret);
653                         }
654                 }
655
656                 /// <summary>
657                 ///   This is called immediately before emitting an IL opcode to tell the symbol
658                 ///   writer to which source line this opcode belongs.
659                 /// </summary>
660                 public void Mark (Location loc)
661                 {
662                         if ((CodeGen.SymbolWriter != null) && !Location.IsNull (loc)) {
663                                 ISymbolDocumentWriter doc = loc.SymbolDocument;
664
665                                 if (doc != null)
666                                         ig.MarkSequencePoint (doc, loc.Row, 0,  loc.Row, 0);
667                         }
668                 }
669
670                 /// <summary>
671                 ///   Returns a temporary storage for a variable of type t as 
672                 ///   a local variable in the current body.
673                 /// </summary>
674                 public LocalBuilder GetTemporaryStorage (Type t)
675                 {
676                         LocalBuilder location;
677                         
678                         if (temporary_storage != null){
679                                 location = (LocalBuilder) temporary_storage [t];
680                                 if (location != null)
681                                         return location;
682                         }
683                         
684                         location = ig.DeclareLocal (t);
685                         
686                         return location;
687                 }
688
689                 public void FreeTemporaryStorage (LocalBuilder b)
690                 {
691                         // Empty for now.
692                 }
693
694                 /// <summary>
695                 ///   Current loop begin and end labels.
696                 /// </summary>
697                 public Label LoopBegin, LoopEnd;
698
699                 /// <summary>
700                 ///   Whether we are inside a loop and break/continue are possible.
701                 /// </summary>
702                 public bool  InLoop;
703
704                 /// <summary>
705                 ///   This is incremented each time we enter a try/catch block and
706                 ///   decremented if we leave it.
707                 /// </summary>
708                 public int   TryCatchLevel;
709
710                 /// <summary>
711                 ///   The TryCatchLevel at the begin of the current loop.
712                 /// </summary>
713                 public int   LoopBeginTryCatchLevel;
714
715                 /// <summary>
716                 ///   Default target in a switch statement.   Only valid if
717                 ///   InSwitch is true
718                 /// </summary>
719                 public Label DefaultTarget;
720
721                 /// <summary>
722                 ///   If this is non-null, points to the current switch statement
723                 /// </summary>
724                 public Switch Switch;
725
726                 /// <summary>
727                 ///   ReturnValue creates on demand the LocalBuilder for the
728                 ///   return value from the function.  By default this is not
729                 ///   used.  This is only required when returns are found inside
730                 ///   Try or Catch statements.
731                 /// </summary>
732                 public LocalBuilder TemporaryReturn ()
733                 {
734                         if (return_value == null){
735                                 return_value = ig.DeclareLocal (ReturnType);
736                                 ReturnLabel = ig.DefineLabel ();
737                                 HasReturnLabel = true;
738                         }
739
740                         return return_value;
741                 }
742
743                 /// <summary>
744                 ///   A dynamic This that is shared by all variables in a emitcontext.
745                 ///   Created on demand.
746                 /// </summary>
747                 public Expression my_this;
748                 public Expression This {
749                         get {
750                                 if (my_this == null) {
751                                         if (CurrentBlock != null)
752                                                 my_this = new This (CurrentBlock, loc);
753                                         else
754                                                 my_this = new This (loc);
755
756                                         my_this = my_this.Resolve (this);
757                                 }
758
759                                 return my_this;
760                         }
761                 }
762         }
763
764         
765         public abstract class CommonAssemblyModulClass: Attributable {
766                 protected CommonAssemblyModulClass ():
767                         base (null)
768                 {
769                 }
770
771                 public void AddAttribute (Attribute attr)
772                 {
773                         if (OptAttributes == null) {
774                                 OptAttributes = new Attributes (attr);
775                         } else {
776                                 OptAttributes.Add (attr);
777                         }
778                 }
779
780                 public virtual void Emit (TypeContainer tc) 
781                 {
782                         if (OptAttributes == null)
783                                 return;
784                         EmitContext ec = new EmitContext (tc, Location.Null, null, null, 0, false);
785                         
786                         if (OptAttributes != null)
787                                 OptAttributes.Emit (ec, this);
788                 }
789                 
790                 
791         }
792
793         public class AssemblyClass: CommonAssemblyModulClass 
794         {
795                 public AssemblyBuilder Builder;
796
797                 public override AttributeTargets AttributeTargets {
798                         get {
799                                 return AttributeTargets.Assembly;
800                         }
801                 }
802                 
803                 public override void Emit (TypeContainer tc)
804                 {
805                         base.Emit (tc);
806                 }
807
808                 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder customBuilder)
809                 {
810                         Builder.SetCustomAttribute (customBuilder);
811                 }
812
813         }
814         
815         public class ModuleClass: CommonAssemblyModulClass 
816         {
817                 public ModuleBuilder Builder;
818
819                 public ModuleClass ()
820                 {
821                 }
822
823                 public override void Emit (TypeContainer tc)
824                 {
825                         base.Emit (tc);
826                 }
827         
828                 public override AttributeTargets AttributeTargets {
829                         get {
830                                 return AttributeTargets.Module;
831                         }
832                 }
833
834                 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder customBuilder)
835                 {
836                         Builder.SetCustomAttribute (customBuilder);
837                 }
838         }
839 }
840
841