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