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