* CodeGeneratorFromCompileUnitTest.cs: enabled test for bug #75190.
[mono.git] / mcs / class / System / System.CodeDom.Compiler / CodeGenerator.cs
1 //
2 // System.CodeDom.Compiler.CodeGenerator.cs
3 //
4 // Authors:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Daniel Stodden (stodden@in.tum.de)
7 //   Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 //   Andreas Nahr (ClassDevelopment@A-SoftTech.com)
9 //   Marek Safar (marek.safar@seznam.cz)
10 //
11 // (C) 2001-2003 Ximian, Inc.
12 //
13
14 //
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 //
34
35 using System.Globalization;
36 using System.CodeDom;
37 using System.Reflection;
38 using System.IO;
39 using System.Collections;
40         
41 namespace System.CodeDom.Compiler {
42
43         public abstract class CodeGenerator : ICodeGenerator
44         {
45                 private IndentedTextWriter output;
46                 private CodeGeneratorOptions options;
47                 private CodeTypeMember currentMember;
48                 private CodeTypeDeclaration currentType;
49
50                 //
51                 // Constructors
52                 //
53                 protected CodeGenerator()
54                 {
55                 }
56
57                 //
58                 // Properties
59                 //
60                 protected CodeTypeMember CurrentMember {
61                         get {
62                                 return currentMember;
63                         }
64                 }
65                 
66                 protected string CurrentMemberName {
67                         get {
68                                 if (currentType == null)
69                                         return null;
70                                 return currentMember.Name;
71                         }
72                 }
73
74                 protected string CurrentTypeName {
75                         get {
76                                 if (currentType == null)
77                                         return null;
78                                 return currentType.Name;
79                         }
80                 }
81                 
82                 protected int Indent {
83                         get {
84                                 return output.Indent;
85                         }
86                         set {
87                                 output.Indent = value;
88                         }
89                 }
90                 
91                 protected bool IsCurrentClass {
92                         get {
93                                 if (currentType == null)
94                                         return false;
95                                 return currentType.IsClass;
96                         }
97                 }
98
99                 protected bool IsCurrentDelegate {
100                         get {
101                                 return currentType is CodeTypeDelegate;
102                         }
103                 }
104
105                 protected bool IsCurrentEnum {
106                         get {
107                                 if (currentType == null)
108                                         return false;
109                                 return currentType.IsEnum;
110                         }
111                 }
112
113                 protected bool IsCurrentInterface {
114                         get {
115                                 if (currentType == null)
116                                         return false;
117                                 return currentType.IsInterface;
118                         }
119                 }
120
121                 protected bool IsCurrentStruct {
122                         get {
123                                 if (currentType == null)
124                                         return false;
125                                 return currentType.IsStruct;
126                         }
127                 }
128
129                 protected abstract string NullToken {
130                         get;
131                 }
132                 
133                 
134                 protected CodeGeneratorOptions Options {
135                         get {
136                                 return options;
137                         }
138                 }
139                         
140                 protected TextWriter Output {
141                         get {
142                                 return output;
143                         }
144                 }
145
146                 //
147                 // Methods
148                 //
149                 protected virtual void ContinueOnNewLine (string st)
150                 {
151                         output.WriteLine (st);
152                 }
153
154                 /*
155                  * Code Generation methods
156                  */
157                 protected abstract void GenerateArgumentReferenceExpression (CodeArgumentReferenceExpression e);
158                 protected abstract void GenerateArrayCreateExpression (CodeArrayCreateExpression e);
159                 protected abstract void GenerateArrayIndexerExpression (CodeArrayIndexerExpression e);
160                 protected abstract void GenerateAssignStatement (CodeAssignStatement s);
161                 protected abstract void GenerateAttachEventStatement (CodeAttachEventStatement s);
162                 protected abstract void GenerateAttributeDeclarationsStart (CodeAttributeDeclarationCollection attributes);
163                 protected abstract void GenerateAttributeDeclarationsEnd (CodeAttributeDeclarationCollection attributes);
164                 protected abstract void GenerateBaseReferenceExpression (CodeBaseReferenceExpression e);
165
166                 protected virtual void GenerateBinaryOperatorExpression (CodeBinaryOperatorExpression e)
167                 {
168                         output.Write ('(');
169                         GenerateExpression (e.Left);
170                         output.Write (' ');
171                         OutputOperator (e.Operator);
172                         output.Write (' ');
173                         GenerateExpression (e.Right);
174                         output.Write (')');
175                 }
176
177                 protected abstract void GenerateCastExpression (CodeCastExpression e);
178                 protected abstract void GenerateComment (CodeComment comment);
179
180                 protected virtual void GenerateCommentStatement (CodeCommentStatement statement)
181                 {
182                         GenerateComment (statement.Comment);
183                 }
184
185                 protected virtual void GenerateCommentStatements (CodeCommentStatementCollection statements)
186                 {
187                         foreach (CodeCommentStatement comment in statements)
188                                 GenerateCommentStatement (comment);
189                 }
190
191                 protected virtual void GenerateCompileUnit (CodeCompileUnit compileUnit)
192                 {
193                         GenerateCompileUnitStart (compileUnit);
194
195                         CodeAttributeDeclarationCollection attributes = compileUnit.AssemblyCustomAttributes;
196                         if (attributes.Count != 0) {
197                                 foreach (CodeAttributeDeclaration att in attributes) {
198                                         GenerateAttributeDeclarationsStart (attributes);
199                                         output.Write ("assembly: ");
200                                         OutputAttributeDeclaration (att);
201                                         GenerateAttributeDeclarationsEnd (attributes);
202                                 }
203                                 output.WriteLine ();
204                         }
205
206                         foreach (CodeNamespace ns in compileUnit.Namespaces)
207                                 GenerateNamespace (ns);
208
209                         GenerateCompileUnitEnd (compileUnit);
210                 }
211
212                 protected virtual void GenerateCompileUnitEnd (CodeCompileUnit compileUnit)
213                 {
214 #if NET_2_0
215                         if (compileUnit.EndDirectives.Count > 0)
216                                 GenerateDirectives (compileUnit.EndDirectives);
217 #endif
218                 }
219
220                 protected virtual void GenerateCompileUnitStart (CodeCompileUnit compileUnit)
221                 {
222 #if NET_2_0
223                         if (compileUnit.StartDirectives.Count > 0) {
224                                 GenerateDirectives (compileUnit.StartDirectives);
225                                 Output.WriteLine ();
226                         }
227 #endif
228                 }
229
230                 protected abstract void GenerateConditionStatement (CodeConditionStatement s);
231                 protected abstract void GenerateConstructor (CodeConstructor x, CodeTypeDeclaration d);
232
233                 protected virtual void GenerateDecimalValue (Decimal d)
234                 {
235                         Output.Write (d.ToString (CultureInfo.InvariantCulture));
236                 }
237
238                 protected abstract void GenerateDelegateCreateExpression (CodeDelegateCreateExpression e);
239                 protected abstract void GenerateDelegateInvokeExpression (CodeDelegateInvokeExpression e);
240
241                 protected virtual void GenerateDirectionExpression (CodeDirectionExpression e)
242                 {
243                         OutputDirection (e.Direction);
244                         output.Write (' ');
245                         GenerateExpression (e.Expression);
246                 }
247
248                 protected virtual void GenerateDoubleValue (Double d)
249                 {
250                         Output.Write (d.ToString (CultureInfo.InvariantCulture));
251                 }
252
253                 protected abstract void GenerateEntryPointMethod (CodeEntryPointMethod m, CodeTypeDeclaration d);
254                 protected abstract void GenerateEvent (CodeMemberEvent ev, CodeTypeDeclaration d);
255                 protected abstract void GenerateEventReferenceExpression (CodeEventReferenceExpression e);
256
257                 protected void GenerateExpression (CodeExpression e)
258                 {
259                         if (e == null)
260                                 throw new ArgumentNullException ("Value cannot be null.");
261
262                         CodeArgumentReferenceExpression argref = e as CodeArgumentReferenceExpression;
263                         if (argref != null) {
264                                 GenerateArgumentReferenceExpression (argref);
265                                 return;
266                         }
267                         CodeArrayCreateExpression mkarray = e as CodeArrayCreateExpression;
268                         if (mkarray != null) {
269                                 GenerateArrayCreateExpression (mkarray);
270                                 return;
271                         }
272                         CodeArrayIndexerExpression arrayidx = e as CodeArrayIndexerExpression;
273                         if (arrayidx != null) {
274                                 GenerateArrayIndexerExpression (arrayidx);
275                                 return;
276                         }
277                         CodeBaseReferenceExpression baseref = e as CodeBaseReferenceExpression;
278                         if (baseref != null) {
279                                 GenerateBaseReferenceExpression (baseref);
280                                 return;
281                         }
282                         CodeBinaryOperatorExpression binary = e as CodeBinaryOperatorExpression;
283                         if (binary != null) {
284                                 GenerateBinaryOperatorExpression (binary);
285                                 return;
286                         }
287                         CodeCastExpression cast = e as CodeCastExpression;
288                         if (cast != null) {
289                                 GenerateCastExpression (cast);
290                                 return;
291                         }
292                         CodeDelegateCreateExpression mkdel = e as CodeDelegateCreateExpression;
293                         if (mkdel != null) {
294                                 GenerateDelegateCreateExpression (mkdel);
295                                 return;
296                         }
297                         CodeDelegateInvokeExpression delinvoke = e as CodeDelegateInvokeExpression;
298                         if (delinvoke != null) {
299                                 GenerateDelegateInvokeExpression (delinvoke);
300                                 return;
301                         }
302                         CodeDirectionExpression direction = e as CodeDirectionExpression;
303                         if (direction != null) {
304                                 GenerateDirectionExpression (direction);
305                                 return;
306                         }
307                         CodeEventReferenceExpression eventref = e as CodeEventReferenceExpression;
308                         if ( eventref != null ) {
309                                 GenerateEventReferenceExpression( eventref );
310                                 return;
311                         }
312                         CodeFieldReferenceExpression fieldref = e as CodeFieldReferenceExpression;
313                         if (fieldref != null) {
314                                 GenerateFieldReferenceExpression (fieldref);
315                                 return;
316                         }
317                         CodeIndexerExpression idx = e as CodeIndexerExpression;
318                         if (idx != null) {
319                                 GenerateIndexerExpression (idx);
320                                 return;
321                         }
322                         CodeMethodInvokeExpression methodinv = e as CodeMethodInvokeExpression;
323                         if (methodinv != null) {
324                                 GenerateMethodInvokeExpression (methodinv);
325                                 return;
326                         }
327                         CodeMethodReferenceExpression methodref = e as CodeMethodReferenceExpression;
328                         if (methodref != null) {
329                                 GenerateMethodReferenceExpression (methodref);
330                                 return;
331                         }
332                         CodeObjectCreateExpression objref = e as CodeObjectCreateExpression;
333                         if (objref != null) {
334                                 GenerateObjectCreateExpression (objref);
335                                 return;
336                         }
337                         CodeParameterDeclarationExpression param = e as CodeParameterDeclarationExpression;
338                         if (param != null) {
339                                 GenerateParameterDeclarationExpression (param);
340                                 return;
341                         }
342                         CodePrimitiveExpression primitive = e as CodePrimitiveExpression;
343                         if (primitive != null) {
344                                 GeneratePrimitiveExpression (primitive);
345                                 return;
346                         }
347                         CodePropertyReferenceExpression propref = e as CodePropertyReferenceExpression;
348                         if (propref != null) {
349                                 GeneratePropertyReferenceExpression (propref);
350                                 return;
351                         }
352                         CodePropertySetValueReferenceExpression propset = e as CodePropertySetValueReferenceExpression;
353                         if (propset != null) {
354                                 GeneratePropertySetValueReferenceExpression (propset);
355                                 return;
356                         }
357                         CodeSnippetExpression snippet = e as CodeSnippetExpression;
358                         if (snippet != null) {
359                                 GenerateSnippetExpression (snippet);
360                                 return;
361                         }
362                         CodeThisReferenceExpression thisref = e as CodeThisReferenceExpression;
363                         if (thisref != null) {
364                                 GenerateThisReferenceExpression (thisref);
365                                 return;
366                         }
367                         CodeTypeOfExpression typeOf = e as CodeTypeOfExpression;
368                         if (typeOf != null) {
369                                 GenerateTypeOfExpression (typeOf);
370                                 return;
371                         }
372                         CodeTypeReferenceExpression typeref = e as CodeTypeReferenceExpression;
373                         if (typeref != null) {
374                                 GenerateTypeReferenceExpression (typeref);
375                                 return;
376                         }
377                         CodeVariableReferenceExpression varref = e as CodeVariableReferenceExpression;
378                         if (varref != null) {
379                                 GenerateVariableReferenceExpression (varref);
380                                 return;
381                         }
382
383                         throw new ArgumentException ("Element type " + e + " is not supported.");
384                 }
385
386                 protected abstract void GenerateExpressionStatement (CodeExpressionStatement statement);
387                 protected abstract void GenerateField (CodeMemberField f);
388                 protected abstract void GenerateFieldReferenceExpression (CodeFieldReferenceExpression e);
389                 protected abstract void GenerateGotoStatement (CodeGotoStatement statement);
390                 protected abstract void GenerateIndexerExpression (CodeIndexerExpression e);
391                 protected abstract void GenerateIterationStatement (CodeIterationStatement s);
392                 protected abstract void GenerateLabeledStatement (CodeLabeledStatement statement);
393                 protected abstract void GenerateLinePragmaStart (CodeLinePragma p);
394                 protected abstract void GenerateLinePragmaEnd (CodeLinePragma p);
395                 protected abstract void GenerateMethod (CodeMemberMethod m, CodeTypeDeclaration d);
396                 protected abstract void GenerateMethodInvokeExpression (CodeMethodInvokeExpression e);
397                 protected abstract void GenerateMethodReferenceExpression (CodeMethodReferenceExpression e);
398                 protected abstract void GenerateMethodReturnStatement (CodeMethodReturnStatement e);
399
400                 protected virtual void GenerateNamespace (CodeNamespace ns)
401                 {
402                         foreach (CodeCommentStatement statement in ns.Comments)
403                                 GenerateCommentStatement (statement);
404
405                         GenerateNamespaceStart (ns);
406
407                         foreach (CodeNamespaceImport import in ns.Imports) {
408                                 if (import.LinePragma != null)
409                                         GenerateLinePragmaStart (import.LinePragma);
410
411                                 GenerateNamespaceImport (import);
412
413                                 if (import.LinePragma != null)
414                                         GenerateLinePragmaEnd (import.LinePragma);
415                         }
416
417                         output.WriteLine();
418
419                         foreach (CodeTypeDeclaration type in ns.Types) {
420                                 GenerateType (type);
421                                 output.WriteLine();
422                         }
423
424                         GenerateNamespaceEnd (ns);
425                 }
426
427                 protected abstract void GenerateNamespaceStart (CodeNamespace ns);
428                 protected abstract void GenerateNamespaceEnd (CodeNamespace ns);
429                 protected abstract void GenerateNamespaceImport (CodeNamespaceImport i);
430                 protected void GenerateNamespaceImports (CodeNamespace e)
431                 {
432                         foreach (CodeNamespaceImport import in e.Imports) {
433                                 if (import.LinePragma != null)
434                                         GenerateLinePragmaStart (import.LinePragma);
435
436                                 GenerateNamespaceImport (import);
437
438                                 if (import.LinePragma != null)
439                                         GenerateLinePragmaEnd (import.LinePragma);
440                         }
441                 }
442
443                 protected void GenerateNamespaces (CodeCompileUnit e)
444                 {
445                         foreach (CodeNamespace ns in e.Namespaces)
446                                 GenerateNamespace (ns);
447                 }
448
449                 protected abstract void GenerateObjectCreateExpression (CodeObjectCreateExpression e);
450
451                 protected virtual void GenerateParameterDeclarationExpression (CodeParameterDeclarationExpression e)
452                 {
453                         if (e.CustomAttributes != null && e.CustomAttributes.Count > 0)
454                                 OutputAttributeDeclarations (e.CustomAttributes);
455                         OutputDirection (e.Direction);
456                         OutputType (e.Type);
457                         output.Write (' ');
458                         output.Write (e.Name);
459                 }
460
461                 protected virtual void GeneratePrimitiveExpression (CodePrimitiveExpression e)
462                 {
463                         if (e.Value == null) {
464                                 output.Write (NullToken);
465                                 return;
466                         }\r
467 \r
468                         Console.Write (e.Value.GetType ());
469                         Type type = e.Value.GetType ();
470                         if (type == typeof (bool)) {
471                                 output.Write (e.Value.ToString ().ToLower (CultureInfo.InvariantCulture));
472                         } else if (type == typeof (char)) {
473                                 output.Write ("'" + e.Value.ToString () + "'");
474                         } else if (type == typeof (string)) {
475                                 output.Write (QuoteSnippetString ((string) e.Value));
476                         } else if (type == typeof (byte) || type == typeof (sbyte) || type == typeof (short) ||
477                                    type == typeof (int) || type == typeof (long) || type == typeof (float) ||
478                                    type == typeof (double) || type == typeof (decimal)) {
479                                 // All of these should be IFormatable, I am just being safe/slow 
480                                 IFormattable formattable = e.Value as IFormattable;
481                                 if (formattable != null)
482                                         output.Write (formattable.ToString (null, CultureInfo.InvariantCulture));
483                                 else
484                                         output.Write (e.Value.ToString ());
485                                         
486                                 if (type == typeof (float))
487                                         output.Write ("f");
488                         } else {
489                                 throw new ArgumentException ("Value type (" + type + ") is not a primitive type");
490                         }
491                 }
492
493                 protected abstract void GenerateProperty (CodeMemberProperty p, CodeTypeDeclaration d);
494                 protected abstract void GeneratePropertyReferenceExpression (CodePropertyReferenceExpression e);
495                 protected abstract void GeneratePropertySetValueReferenceExpression (CodePropertySetValueReferenceExpression e);
496                 protected abstract void GenerateRemoveEventStatement (CodeRemoveEventStatement statement);
497
498                 protected virtual void GenerateSingleFloatValue (Single s)
499                 {
500                         output.Write (s.ToString(CultureInfo.InvariantCulture));
501                 }
502
503                 protected virtual void GenerateSnippetCompileUnit (CodeSnippetCompileUnit e)
504                 {
505                         if (e.LinePragma != null)
506                                 GenerateLinePragmaStart (e.LinePragma);
507
508                         output.WriteLine (e.Value);
509
510                         if (e.LinePragma != null)
511                                 GenerateLinePragmaEnd (e.LinePragma);
512
513                 }
514
515                 protected abstract void GenerateSnippetExpression (CodeSnippetExpression e);
516                 protected abstract void GenerateSnippetMember (CodeSnippetTypeMember m);
517                 protected virtual void GenerateSnippetStatement (CodeSnippetStatement s)
518                 {
519                         output.WriteLine (s.Value);
520                 }
521
522                 protected void GenerateStatement (CodeStatement s)
523                 {
524                         bool handled = false;
525
526 #if NET_2_0
527                         if (s.StartDirectives.Count > 0)
528                                 GenerateDirectives (s.StartDirectives);
529 #endif
530                         if (s.LinePragma != null)
531                                 GenerateLinePragmaStart (s.LinePragma);
532
533                         CodeAssignStatement assign = s as CodeAssignStatement;
534                         if (assign != null) {
535                                 GenerateAssignStatement (assign);
536                                 handled = true;
537                         }
538                         CodeAttachEventStatement attach = s as CodeAttachEventStatement;
539                         if (attach != null) {
540                                 GenerateAttachEventStatement (attach);
541                                 handled = true;
542                         }
543                         CodeCommentStatement comment = s as CodeCommentStatement;
544                         if (comment != null) {
545                                 GenerateCommentStatement (comment);
546                                 handled = true;
547                         }
548                         CodeConditionStatement condition = s as CodeConditionStatement;
549                         if (condition != null) {
550                                 GenerateConditionStatement (condition);
551                                 handled = true;
552                         }
553                         CodeExpressionStatement expression = s as CodeExpressionStatement;
554                         if (expression != null) {
555                                 GenerateExpressionStatement (expression);
556                                 handled = true;
557                         }
558                         CodeGotoStatement gotostmt = s as CodeGotoStatement;
559                         if (gotostmt != null) {
560                                 GenerateGotoStatement (gotostmt);
561                                 handled = true;
562                         }
563                         CodeIterationStatement iteration = s as CodeIterationStatement;
564                         if (iteration != null) {
565                                 GenerateIterationStatement (iteration);
566                                 handled = true;
567                         }
568                         CodeLabeledStatement label = s as CodeLabeledStatement;
569                         if (label != null) {
570                                 GenerateLabeledStatement (label);
571                                 handled = true;
572                         }
573                         CodeMethodReturnStatement returnstmt = s as CodeMethodReturnStatement;
574                         if (returnstmt != null) {
575                                 GenerateMethodReturnStatement (returnstmt);
576                                 handled = true;
577                         }
578                         CodeRemoveEventStatement remove = s as CodeRemoveEventStatement;
579                         if (remove != null) {
580                                 GenerateRemoveEventStatement (remove);
581                                 handled = true;
582                         }
583                         CodeSnippetStatement snippet = s as CodeSnippetStatement;
584                         if (snippet != null) {
585                                 GenerateSnippetStatement (snippet);
586                                 handled = true;
587                         }
588                         CodeThrowExceptionStatement exception = s as CodeThrowExceptionStatement;
589                         if (exception != null) {
590                                 GenerateThrowExceptionStatement (exception);
591                                 handled = true;
592                         }
593                         CodeTryCatchFinallyStatement trycatch = s as CodeTryCatchFinallyStatement;
594                         if (trycatch != null) {
595                                 GenerateTryCatchFinallyStatement (trycatch);
596                                 handled = true;
597                         }
598                         CodeVariableDeclarationStatement declaration = s as CodeVariableDeclarationStatement;
599                         if (declaration != null) {
600                                 GenerateVariableDeclarationStatement (declaration);
601                                 handled = true;
602                         }
603
604                         if (!handled)
605                                 throw new ArgumentException ("Element type " + s + " is not supported.");
606
607                         if (s.LinePragma != null)
608                                 GenerateLinePragmaEnd (s.LinePragma);
609
610 #if NET_2_0
611                         if (s.EndDirectives.Count > 0)
612                                 GenerateDirectives (s.EndDirectives);
613 #endif                  
614                 }
615
616                 protected void GenerateStatements (CodeStatementCollection c)
617                 {
618                         foreach (CodeStatement statement in c)
619                                 GenerateStatement (statement);
620                 }
621
622                 protected abstract void GenerateThisReferenceExpression (CodeThisReferenceExpression e);
623                 protected abstract void GenerateThrowExceptionStatement (CodeThrowExceptionStatement s);
624                 protected abstract void GenerateTryCatchFinallyStatement (CodeTryCatchFinallyStatement s);
625                 protected abstract void GenerateTypeEnd (CodeTypeDeclaration declaration);
626                 protected abstract void GenerateTypeConstructor (CodeTypeConstructor constructor);
627
628                 protected virtual void GenerateTypeOfExpression (CodeTypeOfExpression e)
629                 {
630                         output.Write ("typeof(");
631                         OutputType (e.Type);
632                         output.Write (")");
633                 }
634
635                 protected virtual void GenerateTypeReferenceExpression (CodeTypeReferenceExpression e)
636                 {
637                         OutputType (e.Type);
638                 }
639
640                 protected void GenerateTypes (CodeNamespace e)
641                 {
642                         foreach (CodeTypeDeclaration type in e.Types)
643                                 GenerateType (type);
644                 }
645
646                 protected abstract void GenerateTypeStart (CodeTypeDeclaration declaration);
647                 protected abstract void GenerateVariableDeclarationStatement (CodeVariableDeclarationStatement e);
648                 protected abstract void GenerateVariableReferenceExpression (CodeVariableReferenceExpression e);
649
650                 //
651                 // Other members
652                 //
653                 
654                 /*
655                  * Output Methods
656                  */
657                 protected virtual void OutputAttributeArgument (CodeAttributeArgument argument)
658                 {
659                         string name = argument.Name;
660                         if (name != null) {
661                                 output.Write (name);
662                                 output.Write ('=');
663                         }
664                         GenerateExpression (argument.Value);
665                 }
666
667                 private void OutputAttributeDeclaration (CodeAttributeDeclaration attribute)
668                 {
669                         output.Write (attribute.Name.Replace ('+', '.'));
670                         output.Write ('(');
671                         IEnumerator enumerator = attribute.Arguments.GetEnumerator();
672                         if (enumerator.MoveNext()) {
673                                 CodeAttributeArgument argument = (CodeAttributeArgument)enumerator.Current;
674                                 OutputAttributeArgument (argument);
675                                 
676                                 while (enumerator.MoveNext()) {
677                                         output.Write (',');
678                                         argument = (CodeAttributeArgument)enumerator.Current;
679                                         OutputAttributeArgument (argument);
680                                 }
681                         }
682                         output.Write (')');
683                 }
684
685                 protected virtual void OutputAttributeDeclarations (CodeAttributeDeclarationCollection attributes)
686                 {
687                         GenerateAttributeDeclarationsStart (attributes);
688                         
689                         IEnumerator enumerator = attributes.GetEnumerator();
690                         if (enumerator.MoveNext()) {
691                                 CodeAttributeDeclaration attribute = (CodeAttributeDeclaration)enumerator.Current;
692
693                                 OutputAttributeDeclaration (attribute);
694                                 
695                                 while (enumerator.MoveNext()) {
696                                         attribute = (CodeAttributeDeclaration)enumerator.Current;
697
698                                         output.WriteLine (',');
699                                         OutputAttributeDeclaration (attribute);
700                                 }
701                         }
702
703                         GenerateAttributeDeclarationsEnd (attributes);
704                 }
705
706                 protected virtual void OutputDirection (FieldDirection direction)
707                 {
708                         switch (direction) {
709                         case FieldDirection.In:
710                                 //output.Write ("in ");
711                                 break;
712                         case FieldDirection.Out:
713                                 output.Write ("out ");
714                                 break;
715                         case FieldDirection.Ref:
716                                 output.Write ("ref ");
717                                 break;
718                         }
719                 }
720
721                 protected virtual void OutputExpressionList (CodeExpressionCollection expressions)
722                 {
723                         OutputExpressionList (expressions, false);
724                 }
725
726                 protected virtual void OutputExpressionList (CodeExpressionCollection expressions,
727                                                              bool newLineBetweenItems)
728                 {
729                         IEnumerator enumerator = expressions.GetEnumerator();
730                         if (enumerator.MoveNext()) {
731                                 CodeExpression expression = (CodeExpression)enumerator.Current;
732
733                                 GenerateExpression (expression);
734                                 
735                                 while (enumerator.MoveNext()) {
736                                         expression = (CodeExpression)enumerator.Current;
737                                         
738                                         output.Write (',');
739                                         if (newLineBetweenItems)
740                                                 output.WriteLine ();
741                                         else
742                                                 output.Write (' ');
743                                         
744                                         GenerateExpression (expression);
745                                 }
746                         }
747                 }
748
749                 protected virtual void OutputFieldScopeModifier (MemberAttributes attributes)
750                 {
751                         if ((attributes & MemberAttributes.VTableMask) == MemberAttributes.New)
752                                 output.Write ("new ");
753
754                         switch (attributes & MemberAttributes.ScopeMask) {
755                         case MemberAttributes.Static:
756                                 output.Write ("static ");
757                                 break;
758                         case MemberAttributes.Const:
759                                 output.Write ("const ");
760                                 break;
761                         }
762                 }
763
764                 protected virtual void OutputIdentifier (string ident)
765                 {
766                         output.Write (ident);
767                 }
768
769                 protected virtual void OutputMemberAccessModifier (MemberAttributes attributes)
770                 {
771                         switch (attributes & MemberAttributes.AccessMask) {
772                         case MemberAttributes.Assembly:
773                                 output.Write ("internal ");
774                                 break;
775                         case MemberAttributes.FamilyAndAssembly:
776                                 output.Write ("/* FamAndAssem */ internal "); 
777                                 break;
778                         case MemberAttributes.Family:
779                                 output.Write ("protected ");
780                                 break;
781                         case MemberAttributes.FamilyOrAssembly:
782                                 output.Write ("protected internal ");
783                                 break;
784                         case MemberAttributes.Private:
785                                 output.Write ("private ");
786                                 break;
787                         case MemberAttributes.Public:
788                                 output.Write ("public ");
789                                 break;
790                         }
791                 }
792
793                 protected virtual void OutputMemberScopeModifier (MemberAttributes attributes)
794                 {
795                         if ((attributes & MemberAttributes.VTableMask) == MemberAttributes.New)
796                                 output.Write( "new " );
797
798                         switch (attributes & MemberAttributes.ScopeMask) {
799                         case MemberAttributes.Abstract:
800                                 output.Write ("abstract ");
801                                 break;
802                         case MemberAttributes.Final:
803                                 // Do nothing
804                                 break;
805                         case MemberAttributes.Static:
806                                 output.Write ("static ");
807                                 break;
808                         case MemberAttributes.Override:
809                                 output.Write ("override ");
810                                 break;
811                         default:
812                                 //
813                                 // FUNNY! if the scope value is
814                                 // rubbish (0 or >Const), and access
815                                 // is public or protected, make it
816                                 // "virtual".
817                                 //
818                                 // i'm not sure whether this is 100%
819                                 // correct, but it seems to be MS
820                                 // behavior. 
821                                 //
822                                 MemberAttributes access = attributes & MemberAttributes.AccessMask;
823                                 if (access == MemberAttributes.Public || 
824                                      access == MemberAttributes.Family)
825                                         output.Write ("virtual ");
826                                 break;
827                         }
828                 }
829                                 
830                 protected virtual void OutputOperator (CodeBinaryOperatorType op)
831                 {
832                         switch (op) {
833                         case CodeBinaryOperatorType.Add:
834                                 output.Write ("+");
835                                 break;
836                         case CodeBinaryOperatorType.Subtract:
837                                 output.Write ("-");
838                                 break;
839                         case CodeBinaryOperatorType.Multiply:
840                                 output.Write ("*");
841                                 break;
842                         case CodeBinaryOperatorType.Divide:
843                                 output.Write ("/");
844                                 break;
845                         case CodeBinaryOperatorType.Modulus:
846                                 output.Write ("%");
847                                 break;
848                         case CodeBinaryOperatorType.Assign:
849                                 output.Write ("=");
850                                 break;
851                         case CodeBinaryOperatorType.IdentityInequality:
852                                 output.Write ("!=");
853                                 break;
854                         case CodeBinaryOperatorType.IdentityEquality:
855                                 output.Write ("==");
856                                 break;
857                         case CodeBinaryOperatorType.ValueEquality:
858                                 output.Write ("==");
859                                 break;
860                         case CodeBinaryOperatorType.BitwiseOr:
861                                 output.Write ("|");
862                                 break;
863                         case CodeBinaryOperatorType.BitwiseAnd:
864                                 output.Write ("&");
865                                 break;
866                         case CodeBinaryOperatorType.BooleanOr:
867                                 output.Write ("||");
868                                 break;
869                         case CodeBinaryOperatorType.BooleanAnd:
870                                 output.Write ("&&");
871                                 break;
872                         case CodeBinaryOperatorType.LessThan:
873                                 output.Write ("<");
874                                 break;
875                         case CodeBinaryOperatorType.LessThanOrEqual:
876                                 output.Write ("<=");
877                                 break;
878                         case CodeBinaryOperatorType.GreaterThan:
879                                 output.Write (">");
880                                 break;
881                         case CodeBinaryOperatorType.GreaterThanOrEqual:
882                                 output.Write (">=");
883                                 break;
884                         }
885                 }
886
887                 protected virtual void OutputParameters (CodeParameterDeclarationExpressionCollection parameters)
888                 {
889                         bool first = true;
890                         foreach (CodeParameterDeclarationExpression expr in parameters) {
891                                 if (first)
892                                         first = false;
893                                 else
894                                         output.Write (", ");
895                                 GenerateExpression (expr);
896                         }
897                 }
898
899                 protected abstract void OutputType (CodeTypeReference t);
900
901                 protected virtual void OutputTypeAttributes (TypeAttributes attributes,
902                                                              bool isStruct,
903                                                              bool isEnum)
904                 {
905                         switch (attributes & TypeAttributes.VisibilityMask) {
906                         case TypeAttributes.NotPublic:
907                                 // private by default
908                                 break; 
909
910                         case TypeAttributes.Public:
911                         case TypeAttributes.NestedPublic:
912                                 output.Write ("public ");
913                                 break;
914
915                         case TypeAttributes.NestedPrivate:
916                                 output.Write ("private ");
917                                 break;
918                         }
919
920                         if (!IsCurrentClass)
921                                 OutputExtraTypeAttribute (currentType);
922
923                         if (isStruct)
924                                 output.Write ("struct ");
925
926                         else if (isEnum)
927                                 output.Write ("enum ");
928                         else {
929                                 if ((attributes & TypeAttributes.Interface) != 0) 
930                                         output.Write ("interface ");
931                                 else if (currentType is CodeTypeDelegate)
932                                         output.Write ("delegate ");
933                                 else {
934                                         if ((attributes & TypeAttributes.Sealed) != 0)
935                                                 output.Write ("sealed ");
936                                         if ((attributes & TypeAttributes.Abstract) != 0)
937                                                 output.Write ("abstract ");
938                                         
939                                         OutputExtraTypeAttribute (currentType);
940                                         output.Write ("class ");
941                                 }
942                         }
943                 }
944
945                 internal virtual void OutputExtraTypeAttribute (CodeTypeDeclaration type)
946                 {
947                 }
948                 
949                 protected virtual void OutputTypeNamePair (CodeTypeReference type,
950                                                            string name)
951                 {
952                         OutputType (type);
953                         output.Write (' ');
954                         output.Write (name);
955                 }
956
957                 protected abstract string QuoteSnippetString (string value);
958
959                 /*
960                  * ICodeGenerator
961                  */
962                 protected abstract string CreateEscapedIdentifier (string value);
963                 string ICodeGenerator.CreateEscapedIdentifier (string value)
964                 {
965                         return CreateEscapedIdentifier (value);
966                 }
967
968                 protected abstract string CreateValidIdentifier (string value);
969                 string ICodeGenerator.CreateValidIdentifier (string value)
970                 {
971                         return CreateValidIdentifier (value);
972                 }
973
974                 private void InitOutput (TextWriter output, CodeGeneratorOptions options)
975                 {
976                         if (options == null)
977                                 options = new CodeGeneratorOptions ();
978                                 
979                         this.output = new IndentedTextWriter (output, options.IndentString);
980                         this.options = options;
981                 }
982
983                 void ICodeGenerator.GenerateCodeFromCompileUnit (CodeCompileUnit compileUnit,
984                                                                  TextWriter output,
985                                                                  CodeGeneratorOptions options)
986                 {
987                         InitOutput (output, options);
988
989                         if (compileUnit is CodeSnippetCompileUnit) {
990                                 GenerateSnippetCompileUnit ((CodeSnippetCompileUnit) compileUnit);
991                         } else {
992                                 GenerateCompileUnit (compileUnit);
993                         }
994                 }
995
996                 void ICodeGenerator.GenerateCodeFromExpression (CodeExpression expression,
997                                                                 TextWriter output,
998                                                                 CodeGeneratorOptions options)
999                 {
1000                         InitOutput (output, options);
1001                         GenerateExpression (expression);
1002                 }
1003
1004                 void ICodeGenerator.GenerateCodeFromNamespace (CodeNamespace ns,
1005                                                                TextWriter output, 
1006                                                                CodeGeneratorOptions options)
1007                 {
1008                         InitOutput (output, options);
1009                         GenerateNamespace (ns);
1010                 }
1011
1012                 void ICodeGenerator.GenerateCodeFromStatement (CodeStatement statement,
1013                                                                TextWriter output, 
1014                                                                CodeGeneratorOptions options)
1015                 {
1016                         InitOutput (output, options);
1017                         GenerateStatement (statement);
1018                 }
1019
1020                 void ICodeGenerator.GenerateCodeFromType (CodeTypeDeclaration type,
1021                                                           TextWriter output,
1022                                                           CodeGeneratorOptions options)
1023                 {
1024                         InitOutput (output, options);
1025                         GenerateType (type);
1026                 }
1027
1028                 private void GenerateType (CodeTypeDeclaration type)
1029                 {
1030 #if NET_2_0
1031                         if (type.StartDirectives.Count > 0)
1032                                 GenerateDirectives (type.StartDirectives);
1033 #endif
1034                         foreach (CodeCommentStatement statement in type.Comments)
1035                                 GenerateCommentStatement (statement);
1036
1037                         if (type.LinePragma != null)
1038                                 GenerateLinePragmaStart (type.LinePragma);
1039
1040                         CodeTypeDelegate del = type as CodeTypeDelegate;
1041                         if (del != null)
1042                                 GenerateDelegate (del);
1043                         else
1044                                 GenerateNonDelegateType (type);
1045
1046                         if (type.LinePragma != null)
1047                                 GenerateLinePragmaEnd (type.LinePragma);
1048
1049 #if NET_2_0
1050                         if (type.EndDirectives.Count > 0)
1051                                 GenerateDirectives (type.EndDirectives);
1052 #endif
1053                 }
1054
1055                 private void GenerateDelegate (CodeTypeDelegate type)
1056                 {
1057                         CodeTypeDeclaration prevType = this.currentType;
1058                         this.currentType = type;
1059
1060                         GenerateTypeStart (type);
1061
1062                         OutputParameters (type.Parameters);
1063
1064                         GenerateTypeEnd (type);
1065                         this.currentType = prevType;
1066                 }
1067                 
1068                 private void GenerateNonDelegateType (CodeTypeDeclaration type)
1069                 {
1070                         CodeTypeDeclaration prevType = this.currentType;
1071                         this.currentType = type;
1072
1073                         GenerateTypeStart (type);
1074
1075                         CodeTypeMember [] members = new CodeTypeMember [type.Members.Count];
1076                         type.Members.CopyTo (members, 0);
1077
1078 #if NET_2_0
1079                         if (!Options.VerbatimOrder)
1080 #endif
1081                         {
1082                                 int[] order = new int[members.Length];
1083                                 for (int n=0; n<members.Length; n++)
1084                                         order[n] = Array.IndexOf(memberTypes, members[n].GetType()) * members.Length + n;
1085
1086                                 Array.Sort (order, members);
1087                         }
1088                         
1089                         // WARNING: if anything is missing in the foreach loop and you add it, add the type in
1090                         // its corresponding place in CodeTypeMemberComparer class (below)
1091
1092                         CodeTypeDeclaration subtype = null;
1093                         foreach (CodeTypeMember member in members) 
1094                         {
1095                                 CodeTypeMember prevMember = this.currentMember;
1096                                 this.currentMember = member;
1097
1098                                 if (prevMember != null && subtype == null) {
1099                                         if (prevMember.LinePragma != null)
1100                                                 GenerateLinePragmaEnd (prevMember.LinePragma);
1101 #if NET_2_0
1102                                         if (prevMember.EndDirectives.Count > 0)
1103                                                 GenerateDirectives (prevMember.EndDirectives);
1104 #endif
1105                                 }
1106
1107                                 if (options.BlankLinesBetweenMembers)
1108                                         output.WriteLine ();
1109
1110                                 subtype = member as CodeTypeDeclaration;
1111                                 if (subtype != null) {
1112                                         GenerateType (subtype);
1113                                         continue;
1114                                 }
1115
1116 #if NET_2_0
1117                                 if (currentMember.StartDirectives.Count > 0)
1118                                         GenerateDirectives (currentMember.StartDirectives);
1119 #endif
1120                                 foreach (CodeCommentStatement statement in member.Comments)
1121                                         GenerateCommentStatement (statement);
1122
1123                                 if (member.LinePragma != null)
1124                                         GenerateLinePragmaStart (member.LinePragma);
1125
1126                                 CodeMemberEvent eventm = member as CodeMemberEvent;
1127                                 if (eventm != null) 
1128                                 {
1129                                         GenerateEvent (eventm, type);
1130                                         continue;
1131                                 }
1132                                 CodeMemberField field = member as CodeMemberField;
1133                                 if (field != null) 
1134                                 {
1135                                         GenerateField (field);
1136                                         continue;
1137                                 }
1138                                 CodeEntryPointMethod epmethod = member as CodeEntryPointMethod;
1139                                 if (epmethod != null) 
1140                                 {
1141                                         GenerateEntryPointMethod (epmethod, type);
1142                                         continue;
1143                                 }
1144                                 CodeTypeConstructor typeCtor = member as CodeTypeConstructor;
1145                                 if (typeCtor != null) 
1146                                 {
1147                                         GenerateTypeConstructor (typeCtor);
1148                                         continue;
1149                                 }
1150                                 CodeConstructor ctor = member as CodeConstructor;
1151                                 if (ctor != null) 
1152                                 {
1153                                         GenerateConstructor (ctor, type);
1154                                         continue;
1155                                 }
1156                                 CodeMemberMethod method = member as CodeMemberMethod;
1157                                 if (method != null) 
1158                                 {
1159                                         GenerateMethod (method, type);
1160                                         continue;
1161                                 }
1162                                 CodeMemberProperty property = member as CodeMemberProperty;
1163                                 if (property != null) 
1164                                 {
1165                                         GenerateProperty (property, type);
1166                                         continue;
1167                                 }
1168                                 CodeSnippetTypeMember snippet = member as CodeSnippetTypeMember;
1169                                 if (snippet != null) 
1170                                 {
1171                                         GenerateSnippetMember (snippet);
1172                                         continue;
1173                                 }
1174                                 
1175                                 this.currentMember = prevMember;
1176                         }
1177
1178                         // Hack because of previous continue usage
1179                         if (currentMember != null && !(currentMember is CodeTypeDeclaration)) {
1180                                 if (currentMember.LinePragma != null)
1181                                         GenerateLinePragmaEnd (currentMember.LinePragma);
1182 #if NET_2_0
1183                                 if (currentMember.EndDirectives.Count > 0)
1184                                         GenerateDirectives (currentMember.EndDirectives);
1185 #endif
1186                         }
1187                                 
1188                         GenerateTypeEnd (type);
1189                         this.currentType = prevType;
1190                 }
1191
1192                 protected abstract string GetTypeOutput (CodeTypeReference type);
1193
1194                 string ICodeGenerator.GetTypeOutput (CodeTypeReference type)
1195                 {
1196                         return GetTypeOutput (type);
1197                 }
1198
1199                 protected abstract bool IsValidIdentifier (string value);
1200
1201                 bool ICodeGenerator.IsValidIdentifier (string value)
1202                 {
1203                         return IsValidIdentifier (value);
1204                 }
1205
1206                 public static bool IsValidLanguageIndependentIdentifier (string value)
1207                 {
1208                         if (value == null)
1209                                 return false;
1210                         if (value.Equals (string.Empty))
1211                                 return false;
1212                         switch (char.GetUnicodeCategory (value[0]))
1213                         {
1214                                 case UnicodeCategory.LetterNumber:
1215                                 case UnicodeCategory.LowercaseLetter:
1216                                 case UnicodeCategory.TitlecaseLetter:
1217                                 case UnicodeCategory.UppercaseLetter:
1218                                 case UnicodeCategory.OtherLetter:
1219                                 case UnicodeCategory.ModifierLetter:
1220                                 case UnicodeCategory.ConnectorPunctuation:
1221                                         if (value.Length > 1)
1222                                         {
1223                                                 for (int x = 0; x < value.Length; x++)
1224                                                 {
1225                                                         switch (char.GetUnicodeCategory (value[x]))
1226                                                         {
1227                                                                 case UnicodeCategory.LetterNumber:
1228                                                                 case UnicodeCategory.LowercaseLetter:
1229                                                                 case UnicodeCategory.TitlecaseLetter:
1230                                                                 case UnicodeCategory.UppercaseLetter:
1231                                                                 case UnicodeCategory.OtherLetter:
1232                                                                 case UnicodeCategory.ModifierLetter:
1233                                                                 case UnicodeCategory.ConnectorPunctuation:
1234                                                                 case UnicodeCategory.DecimalDigitNumber:
1235                                                                 case UnicodeCategory.NonSpacingMark:
1236                                                                 case UnicodeCategory.SpacingCombiningMark:
1237                                                                 case UnicodeCategory.Format:
1238                                                                         return true;
1239                                                         }
1240                                                         return false;
1241                                                 }
1242                                         }
1243                                         else
1244                                                 return true;
1245                                         break;
1246                         }
1247                         return false;
1248                 }
1249
1250                 protected abstract bool Supports (GeneratorSupport supports);
1251
1252                 bool ICodeGenerator.Supports (GeneratorSupport value)
1253                 {
1254                         return Supports (value);
1255                 }
1256
1257                 protected virtual void ValidateIdentifier (string value)
1258                 {
1259                         if (!(IsValidIdentifier (value)))
1260                                 throw new ArgumentException ("Identifier is invalid", "value");
1261                 }
1262
1263                 [MonoTODO]
1264                 public static void ValidateIdentifiers (CodeObject e)
1265                 {
1266                         throw new NotImplementedException();
1267                 }
1268
1269                 void ICodeGenerator.ValidateIdentifier (string value)
1270                 {
1271                         ValidateIdentifier (value);
1272                 }
1273
1274                 // The position in the array determines the order in which those
1275                 // kind of CodeTypeMembers are generated. Less is more ;-)
1276                 static Type [] memberTypes = {  typeof (CodeMemberField),
1277                                                 typeof (CodeSnippetTypeMember),
1278                                                 typeof (CodeTypeConstructor),
1279                                                 typeof (CodeConstructor),
1280                                                 typeof (CodeMemberProperty),
1281                                                 typeof (CodeMemberEvent),
1282                                                 typeof (CodeMemberMethod),
1283                                                 typeof (CodeTypeDeclaration),
1284                                                 typeof (CodeEntryPointMethod)
1285                                         };
1286
1287
1288 #if NET_2_0
1289                 protected virtual void GenerateDirectives (CodeDirectiveCollection directives)
1290                 {
1291                 }
1292 #endif
1293
1294         }
1295 }