merge -r 53370:58178
[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                         foreach (CodeTypeDeclaration type in ns.Types) {
441                                 GenerateType (type);
442                                 output.WriteLine();
443                         }
444
445                         GenerateNamespaceEnd (ns);
446                 }
447
448                 protected abstract void GenerateNamespaceStart (CodeNamespace ns);
449                 protected abstract void GenerateNamespaceEnd (CodeNamespace ns);
450                 protected abstract void GenerateNamespaceImport (CodeNamespaceImport i);
451                 protected void GenerateNamespaceImports (CodeNamespace e)
452                 {
453                         foreach (CodeNamespaceImport import in e.Imports) {
454                                 if (import.LinePragma != null)
455                                         GenerateLinePragmaStart (import.LinePragma);
456
457                                 GenerateNamespaceImport (import);
458
459                                 if (import.LinePragma != null)
460                                         GenerateLinePragmaEnd (import.LinePragma);
461                         }
462                 }
463
464                 protected void GenerateNamespaces (CodeCompileUnit e)
465                 {
466                         foreach (CodeNamespace ns in e.Namespaces)
467                                 GenerateNamespace (ns);
468                 }
469
470                 protected abstract void GenerateObjectCreateExpression (CodeObjectCreateExpression e);
471
472                 protected virtual void GenerateParameterDeclarationExpression (CodeParameterDeclarationExpression e)
473                 {
474                         if (e.CustomAttributes != null && e.CustomAttributes.Count > 0)
475                                 OutputAttributeDeclarations (e.CustomAttributes);
476                         OutputDirection (e.Direction);
477                         OutputType (e.Type);
478                         output.Write (' ');
479                         output.Write (e.Name);
480                 }
481
482                 protected virtual void GeneratePrimitiveExpression (CodePrimitiveExpression e)
483                 {
484                         if (e.Value == null) {
485                                 output.Write (NullToken);
486                                 return;
487                         }
488
489                         Type type = e.Value.GetType ();
490                         if (type == typeof (bool)) {
491                                 output.Write (e.Value.ToString ().ToLower (CultureInfo.InvariantCulture));
492                         } else if (type == typeof (char)) {
493                                 output.Write ("'" + e.Value.ToString () + "'");
494                         } else if (type == typeof (string)) {
495                                 output.Write (QuoteSnippetString ((string) e.Value));
496                         } else if (type == typeof (byte) || type == typeof (sbyte) || type == typeof (short) ||
497                                    type == typeof (int) || type == typeof (long) || type == typeof (float) ||
498                                    type == typeof (double) || type == typeof (decimal)) {
499                                 // All of these should be IFormatable, I am just being safe/slow 
500                                 IFormattable formattable = e.Value as IFormattable;
501                                 if (formattable != null)
502                                         output.Write (formattable.ToString (null, CultureInfo.InvariantCulture));
503                                 else
504                                         output.Write (e.Value.ToString ());
505                                         
506                                 if (type == typeof (float))
507                                         output.Write ("f");
508                         } else {
509                                 throw new ArgumentException ("Value type (" + type + ") is not a primitive type");
510                         }
511                 }
512
513                 protected abstract void GenerateProperty (CodeMemberProperty p, CodeTypeDeclaration d);
514                 protected abstract void GeneratePropertyReferenceExpression (CodePropertyReferenceExpression e);
515                 protected abstract void GeneratePropertySetValueReferenceExpression (CodePropertySetValueReferenceExpression e);
516                 protected abstract void GenerateRemoveEventStatement (CodeRemoveEventStatement statement);
517
518                 protected virtual void GenerateSingleFloatValue (Single s)
519                 {
520                         output.Write (s.ToString(CultureInfo.InvariantCulture));
521                 }
522
523                 protected virtual void GenerateSnippetCompileUnit (CodeSnippetCompileUnit e)
524                 {
525                         if (e.LinePragma != null)
526                                 GenerateLinePragmaStart (e.LinePragma);
527
528                         output.WriteLine (e.Value);
529
530                         if (e.LinePragma != null)
531                                 GenerateLinePragmaEnd (e.LinePragma);
532
533                 }
534
535                 protected abstract void GenerateSnippetExpression (CodeSnippetExpression e);
536                 protected abstract void GenerateSnippetMember (CodeSnippetTypeMember m);
537                 protected virtual void GenerateSnippetStatement (CodeSnippetStatement s)
538                 {
539                         output.WriteLine (s.Value);
540                 }
541
542                 protected void GenerateStatement (CodeStatement s)
543                 {
544                         bool handled = false;
545
546 #if NET_2_0
547                         if (s.StartDirectives.Count > 0)
548                                 GenerateDirectives (s.StartDirectives);
549 #endif
550                         if (s.LinePragma != null)
551                                 GenerateLinePragmaStart (s.LinePragma);
552
553                         CodeAssignStatement assign = s as CodeAssignStatement;
554                         if (assign != null) {
555                                 GenerateAssignStatement (assign);
556                                 handled = true;
557                         }
558                         CodeAttachEventStatement attach = s as CodeAttachEventStatement;
559                         if (attach != null) {
560                                 GenerateAttachEventStatement (attach);
561                                 handled = true;
562                         }
563                         CodeCommentStatement comment = s as CodeCommentStatement;
564                         if (comment != null) {
565                                 GenerateCommentStatement (comment);
566                                 handled = true;
567                         }
568                         CodeConditionStatement condition = s as CodeConditionStatement;
569                         if (condition != null) {
570                                 GenerateConditionStatement (condition);
571                                 handled = true;
572                         }
573                         CodeExpressionStatement expression = s as CodeExpressionStatement;
574                         if (expression != null) {
575                                 GenerateExpressionStatement (expression);
576                                 handled = true;
577                         }
578                         CodeGotoStatement gotostmt = s as CodeGotoStatement;
579                         if (gotostmt != null) {
580                                 GenerateGotoStatement (gotostmt);
581                                 handled = true;
582                         }
583                         CodeIterationStatement iteration = s as CodeIterationStatement;
584                         if (iteration != null) {
585                                 GenerateIterationStatement (iteration);
586                                 handled = true;
587                         }
588                         CodeLabeledStatement label = s as CodeLabeledStatement;
589                         if (label != null) {
590                                 GenerateLabeledStatement (label);
591                                 handled = true;
592                         }
593                         CodeMethodReturnStatement returnstmt = s as CodeMethodReturnStatement;
594                         if (returnstmt != null) {
595                                 GenerateMethodReturnStatement (returnstmt);
596                                 handled = true;
597                         }
598                         CodeRemoveEventStatement remove = s as CodeRemoveEventStatement;
599                         if (remove != null) {
600                                 GenerateRemoveEventStatement (remove);
601                                 handled = true;
602                         }
603                         CodeSnippetStatement snippet = s as CodeSnippetStatement;
604                         if (snippet != null) {
605                                 GenerateSnippetStatement (snippet);
606                                 handled = true;
607                         }
608                         CodeThrowExceptionStatement exception = s as CodeThrowExceptionStatement;
609                         if (exception != null) {
610                                 GenerateThrowExceptionStatement (exception);
611                                 handled = true;
612                         }
613                         CodeTryCatchFinallyStatement trycatch = s as CodeTryCatchFinallyStatement;
614                         if (trycatch != null) {
615                                 GenerateTryCatchFinallyStatement (trycatch);
616                                 handled = true;
617                         }
618                         CodeVariableDeclarationStatement declaration = s as CodeVariableDeclarationStatement;
619                         if (declaration != null) {
620                                 GenerateVariableDeclarationStatement (declaration);
621                                 handled = true;
622                         }
623
624                         if (!handled)
625                                 throw new ArgumentException ("Element type " + s + " is not supported.");
626
627                         if (s.LinePragma != null)
628                                 GenerateLinePragmaEnd (s.LinePragma);
629
630 #if NET_2_0
631                         if (s.EndDirectives.Count > 0)
632                                 GenerateDirectives (s.EndDirectives);
633 #endif                  
634                 }
635
636                 protected void GenerateStatements (CodeStatementCollection c)
637                 {
638                         foreach (CodeStatement statement in c)
639                                 GenerateStatement (statement);
640                 }
641
642                 protected abstract void GenerateThisReferenceExpression (CodeThisReferenceExpression e);
643                 protected abstract void GenerateThrowExceptionStatement (CodeThrowExceptionStatement s);
644                 protected abstract void GenerateTryCatchFinallyStatement (CodeTryCatchFinallyStatement s);
645                 protected abstract void GenerateTypeEnd (CodeTypeDeclaration declaration);
646                 protected abstract void GenerateTypeConstructor (CodeTypeConstructor constructor);
647
648                 protected virtual void GenerateTypeOfExpression (CodeTypeOfExpression e)
649                 {
650                         output.Write ("typeof(");
651                         OutputType (e.Type);
652                         output.Write (")");
653                 }
654
655                 protected virtual void GenerateTypeReferenceExpression (CodeTypeReferenceExpression e)
656                 {
657                         OutputType (e.Type);
658                 }
659
660                 protected void GenerateTypes (CodeNamespace e)
661                 {
662                         foreach (CodeTypeDeclaration type in e.Types)
663                                 GenerateType (type);
664                 }
665
666                 protected abstract void GenerateTypeStart (CodeTypeDeclaration declaration);
667                 protected abstract void GenerateVariableDeclarationStatement (CodeVariableDeclarationStatement e);
668                 protected abstract void GenerateVariableReferenceExpression (CodeVariableReferenceExpression e);
669
670                 //
671                 // Other members
672                 //
673                 
674                 /*
675                  * Output Methods
676                  */
677                 protected virtual void OutputAttributeArgument (CodeAttributeArgument argument)
678                 {
679                         string name = argument.Name;
680                         if ((name != null) && (name.Length > 0)) {
681                                 output.Write (name);
682                                 output.Write ('=');
683                         }
684                         GenerateExpression (argument.Value);
685                 }
686
687                 private void OutputAttributeDeclaration (CodeAttributeDeclaration attribute)
688                 {
689                         output.Write (attribute.Name.Replace ('+', '.'));
690                         output.Write ('(');
691                         IEnumerator enumerator = attribute.Arguments.GetEnumerator();
692                         if (enumerator.MoveNext()) {
693                                 CodeAttributeArgument argument = (CodeAttributeArgument)enumerator.Current;
694                                 OutputAttributeArgument (argument);
695                                 
696                                 while (enumerator.MoveNext()) {
697                                         output.Write (',');
698                                         argument = (CodeAttributeArgument)enumerator.Current;
699                                         OutputAttributeArgument (argument);
700                                 }
701                         }
702                         output.Write (')');
703                 }
704
705                 protected virtual void OutputAttributeDeclarations (CodeAttributeDeclarationCollection attributes)
706                 {
707                         GenerateAttributeDeclarationsStart (attributes);
708                         
709                         IEnumerator enumerator = attributes.GetEnumerator();
710                         if (enumerator.MoveNext()) {
711                                 CodeAttributeDeclaration attribute = (CodeAttributeDeclaration)enumerator.Current;
712
713                                 OutputAttributeDeclaration (attribute);
714                                 
715                                 while (enumerator.MoveNext()) {
716                                         attribute = (CodeAttributeDeclaration)enumerator.Current;
717
718                                         output.WriteLine (',');
719                                         OutputAttributeDeclaration (attribute);
720                                 }
721                         }
722
723                         GenerateAttributeDeclarationsEnd (attributes);
724                 }
725
726                 protected virtual void OutputDirection (FieldDirection direction)
727                 {
728                         switch (direction) {
729                         case FieldDirection.In:
730                                 //output.Write ("in ");
731                                 break;
732                         case FieldDirection.Out:
733                                 output.Write ("out ");
734                                 break;
735                         case FieldDirection.Ref:
736                                 output.Write ("ref ");
737                                 break;
738                         }
739                 }
740
741                 protected virtual void OutputExpressionList (CodeExpressionCollection expressions)
742                 {
743                         OutputExpressionList (expressions, false);
744                 }
745
746                 protected virtual void OutputExpressionList (CodeExpressionCollection expressions,
747                                                              bool newLineBetweenItems)
748                 {
749                         IEnumerator enumerator = expressions.GetEnumerator();
750                         if (enumerator.MoveNext()) {
751                                 CodeExpression expression = (CodeExpression)enumerator.Current;
752
753                                 GenerateExpression (expression);
754                                 
755                                 while (enumerator.MoveNext()) {
756                                         expression = (CodeExpression)enumerator.Current;
757                                         
758                                         output.Write (',');
759                                         if (newLineBetweenItems)
760                                                 output.WriteLine ();
761                                         else
762                                                 output.Write (' ');
763                                         
764                                         GenerateExpression (expression);
765                                 }
766                         }
767                 }
768
769                 protected virtual void OutputFieldScopeModifier (MemberAttributes attributes)
770                 {
771                         if ((attributes & MemberAttributes.VTableMask) == MemberAttributes.New)
772                                 output.Write ("new ");
773
774                         switch (attributes & MemberAttributes.ScopeMask) {
775                         case MemberAttributes.Static:
776                                 output.Write ("static ");
777                                 break;
778                         case MemberAttributes.Const:
779                                 output.Write ("const ");
780                                 break;
781                         }
782                 }
783
784                 protected virtual void OutputIdentifier (string ident)
785                 {
786                         output.Write (ident);
787                 }
788
789                 protected virtual void OutputMemberAccessModifier (MemberAttributes attributes)
790                 {
791                         switch (attributes & MemberAttributes.AccessMask) {
792                                 case MemberAttributes.Assembly:
793                                         output.Write ("internal ");
794                                         break;
795                                 case MemberAttributes.FamilyAndAssembly:
796 #if NET_2_0
797                                         output.Write ("internal "); 
798 #else
799                                         output.Write ("/*FamANDAssem*/ internal "); 
800 #endif
801                                         break;
802                                 case MemberAttributes.Family:
803                                         output.Write ("protected ");
804                                         break;
805                                 case MemberAttributes.FamilyOrAssembly:
806                                         output.Write ("protected internal ");
807                                         break;
808                                 case MemberAttributes.Private:
809                                         output.Write ("private ");
810                                         break;
811                                 case MemberAttributes.Public:
812                                         output.Write ("public ");
813                                         break;
814                         }
815                 }
816
817                 protected virtual void OutputMemberScopeModifier (MemberAttributes attributes)
818                 {
819 #if NET_2_0
820                         if ((attributes & MemberAttributes.VTableMask) == MemberAttributes.New)
821                                 output.Write( "new " );
822 #endif
823
824                         switch (attributes & MemberAttributes.ScopeMask) {
825                                 case MemberAttributes.Abstract:
826                                         output.Write ("abstract ");
827                                         break;
828                                 case MemberAttributes.Final:
829                                         // Do nothing
830                                         break;
831                                 case MemberAttributes.Static:
832                                         output.Write ("static ");
833                                         break;
834                                 case MemberAttributes.Override:
835                                         output.Write ("override ");
836                                         break;
837                                 default:
838                                         //
839                                         // FUNNY! if the scope value is
840                                         // rubbish (0 or >Const), and access
841                                         // is public or protected, make it
842                                         // "virtual".
843                                         //
844                                         // i'm not sure whether this is 100%
845                                         // correct, but it seems to be MS
846                                         // behavior.
847                                         //
848                                         // On .NET 2.0, internal members
849                                         // are also marked "virtual".
850                                         //
851                                         MemberAttributes access = attributes & MemberAttributes.AccessMask;
852                                         if (access == MemberAttributes.Public || access == MemberAttributes.Family)
853                                                 output.Write ("virtual ");
854                                         break;
855                         }
856                 }
857                                 
858                 protected virtual void OutputOperator (CodeBinaryOperatorType op)
859                 {
860                         switch (op) {
861                         case CodeBinaryOperatorType.Add:
862                                 output.Write ("+");
863                                 break;
864                         case CodeBinaryOperatorType.Subtract:
865                                 output.Write ("-");
866                                 break;
867                         case CodeBinaryOperatorType.Multiply:
868                                 output.Write ("*");
869                                 break;
870                         case CodeBinaryOperatorType.Divide:
871                                 output.Write ("/");
872                                 break;
873                         case CodeBinaryOperatorType.Modulus:
874                                 output.Write ("%");
875                                 break;
876                         case CodeBinaryOperatorType.Assign:
877                                 output.Write ("=");
878                                 break;
879                         case CodeBinaryOperatorType.IdentityInequality:
880                                 output.Write ("!=");
881                                 break;
882                         case CodeBinaryOperatorType.IdentityEquality:
883                                 output.Write ("==");
884                                 break;
885                         case CodeBinaryOperatorType.ValueEquality:
886                                 output.Write ("==");
887                                 break;
888                         case CodeBinaryOperatorType.BitwiseOr:
889                                 output.Write ("|");
890                                 break;
891                         case CodeBinaryOperatorType.BitwiseAnd:
892                                 output.Write ("&");
893                                 break;
894                         case CodeBinaryOperatorType.BooleanOr:
895                                 output.Write ("||");
896                                 break;
897                         case CodeBinaryOperatorType.BooleanAnd:
898                                 output.Write ("&&");
899                                 break;
900                         case CodeBinaryOperatorType.LessThan:
901                                 output.Write ("<");
902                                 break;
903                         case CodeBinaryOperatorType.LessThanOrEqual:
904                                 output.Write ("<=");
905                                 break;
906                         case CodeBinaryOperatorType.GreaterThan:
907                                 output.Write (">");
908                                 break;
909                         case CodeBinaryOperatorType.GreaterThanOrEqual:
910                                 output.Write (">=");
911                                 break;
912                         }
913                 }
914
915                 protected virtual void OutputParameters (CodeParameterDeclarationExpressionCollection parameters)
916                 {
917                         bool first = true;
918                         foreach (CodeParameterDeclarationExpression expr in parameters) {
919                                 if (first)
920                                         first = false;
921                                 else
922                                         output.Write (", ");
923                                 GenerateExpression (expr);
924                         }
925                 }
926
927                 protected abstract void OutputType (CodeTypeReference t);
928
929                 protected virtual void OutputTypeAttributes (TypeAttributes attributes,
930                                                              bool isStruct,
931                                                              bool isEnum)
932                 {
933                         switch (attributes & TypeAttributes.VisibilityMask) {
934                         case TypeAttributes.NotPublic:
935                                 // private by default
936                                 break; 
937
938                         case TypeAttributes.Public:
939                         case TypeAttributes.NestedPublic:
940                                 output.Write ("public ");
941                                 break;
942
943                         case TypeAttributes.NestedPrivate:
944                                 output.Write ("private ");
945                                 break;
946                         }
947
948                         if (isStruct)
949                                 output.Write ("struct ");
950
951                         else if (isEnum)
952                                 output.Write ("enum ");
953                         else {
954                                 if ((attributes & TypeAttributes.Interface) != 0) 
955                                         output.Write ("interface ");
956                                 else if (currentType is CodeTypeDelegate)
957                                         output.Write ("delegate ");
958                                 else {
959                                         if ((attributes & TypeAttributes.Sealed) != 0)
960                                                 output.Write ("sealed ");
961                                         if ((attributes & TypeAttributes.Abstract) != 0)
962                                                 output.Write ("abstract ");
963                                         
964                                         output.Write ("class ");
965                                 }
966                         }
967                 }
968
969                 protected virtual void OutputTypeNamePair (CodeTypeReference type,
970                                                            string name)
971                 {
972                         OutputType (type);
973                         output.Write (' ');
974                         output.Write (name);
975                 }
976
977                 protected abstract string QuoteSnippetString (string value);
978
979                 /*
980                  * ICodeGenerator
981                  */
982                 protected abstract string CreateEscapedIdentifier (string value);
983                 string ICodeGenerator.CreateEscapedIdentifier (string value)
984                 {
985                         return CreateEscapedIdentifier (value);
986                 }
987
988                 protected abstract string CreateValidIdentifier (string value);
989                 string ICodeGenerator.CreateValidIdentifier (string value)
990                 {
991                         return CreateValidIdentifier (value);
992                 }
993
994                 private void InitOutput (TextWriter output, CodeGeneratorOptions options)
995                 {
996                         if (options == null)
997                                 options = new CodeGeneratorOptions ();
998                                 
999                         this.output = new IndentedTextWriter (output, options.IndentString);
1000                         this.options = options;
1001                 }
1002
1003                 void ICodeGenerator.GenerateCodeFromCompileUnit (CodeCompileUnit compileUnit,
1004                                                                  TextWriter output,
1005                                                                  CodeGeneratorOptions options)
1006                 {
1007                         InitOutput (output, options);
1008
1009                         if (compileUnit is CodeSnippetCompileUnit) {
1010                                 GenerateSnippetCompileUnit ((CodeSnippetCompileUnit) compileUnit);
1011                         } else {
1012                                 GenerateCompileUnit (compileUnit);
1013                         }
1014                 }
1015
1016                 void ICodeGenerator.GenerateCodeFromExpression (CodeExpression expression,
1017                                                                 TextWriter output,
1018                                                                 CodeGeneratorOptions options)
1019                 {
1020                         InitOutput (output, options);
1021                         GenerateExpression (expression);
1022                 }
1023
1024                 void ICodeGenerator.GenerateCodeFromNamespace (CodeNamespace ns,
1025                                                                TextWriter output, 
1026                                                                CodeGeneratorOptions options)
1027                 {
1028                         InitOutput (output, options);
1029                         GenerateNamespace (ns);
1030                 }
1031
1032                 void ICodeGenerator.GenerateCodeFromStatement (CodeStatement statement,
1033                                                                TextWriter output, 
1034                                                                CodeGeneratorOptions options)
1035                 {
1036                         InitOutput (output, options);
1037                         GenerateStatement (statement);
1038                 }
1039
1040                 void ICodeGenerator.GenerateCodeFromType (CodeTypeDeclaration type,
1041                                                           TextWriter output,
1042                                                           CodeGeneratorOptions options)
1043                 {
1044                         InitOutput (output, options);
1045                         GenerateType (type);
1046                 }
1047
1048                 private void GenerateType (CodeTypeDeclaration type)
1049                 {
1050                         this.currentType = type;
1051
1052 #if NET_2_0
1053                         if (type.StartDirectives.Count > 0)
1054                                 GenerateDirectives (type.StartDirectives);
1055 #endif
1056                         foreach (CodeCommentStatement statement in type.Comments)
1057                                 GenerateCommentStatement (statement);
1058
1059                         if (type.LinePragma != null)
1060                                 GenerateLinePragmaStart (type.LinePragma);
1061
1062                         GenerateTypeStart (type);
1063
1064                         CodeTypeMember[] members = new CodeTypeMember[type.Members.Count];
1065                         type.Members.CopyTo (members, 0);
1066
1067 #if NET_2_0
1068                         if (!Options.VerbatimOrder)
1069 #endif
1070  {
1071                                 int[] order = new int[members.Length];
1072                                 for (int n = 0; n < members.Length; n++)
1073                                         order[n] = Array.IndexOf (memberTypes, members[n].GetType ()) * members.Length + n;
1074
1075                                 Array.Sort (order, members);
1076                         }
1077
1078                         // WARNING: if anything is missing in the foreach loop and you add it, add the type in
1079                         // its corresponding place in CodeTypeMemberComparer class (below)
1080
1081                         CodeTypeDeclaration subtype = null;
1082                         foreach (CodeTypeMember member in members) {
1083                                 CodeTypeMember prevMember = this.currentMember;
1084                                 this.currentMember = member;
1085
1086                                 if (prevMember != null && subtype == null) {
1087                                         if (prevMember.LinePragma != null)
1088                                                 GenerateLinePragmaEnd (prevMember.LinePragma);
1089 #if NET_2_0
1090                                         if (prevMember.EndDirectives.Count > 0)
1091                                                 GenerateDirectives (prevMember.EndDirectives);
1092 #endif
1093                                 }
1094
1095                                 if (options.BlankLinesBetweenMembers)
1096                                         output.WriteLine ();
1097
1098                                 subtype = member as CodeTypeDeclaration;
1099                                 if (subtype != null) {
1100                                         GenerateType (subtype);
1101                                         this.currentType = type;
1102                                         continue;
1103                                 }
1104
1105 #if NET_2_0
1106                                 if (currentMember.StartDirectives.Count > 0)
1107                                         GenerateDirectives (currentMember.StartDirectives);
1108 #endif
1109                                 foreach (CodeCommentStatement statement in member.Comments)
1110                                         GenerateCommentStatement (statement);
1111
1112                                 if (member.LinePragma != null)
1113                                         GenerateLinePragmaStart (member.LinePragma);
1114
1115                                 CodeMemberEvent eventm = member as CodeMemberEvent;
1116                                 if (eventm != null) {
1117                                         GenerateEvent (eventm, type);
1118                                         continue;
1119                                 }
1120                                 CodeMemberField field = member as CodeMemberField;
1121                                 if (field != null) {
1122                                         GenerateField (field);
1123                                         continue;
1124                                 }
1125                                 CodeEntryPointMethod epmethod = member as CodeEntryPointMethod;
1126                                 if (epmethod != null) {
1127                                         GenerateEntryPointMethod (epmethod, type);
1128                                         continue;
1129                                 }
1130                                 CodeTypeConstructor typeCtor = member as CodeTypeConstructor;
1131                                 if (typeCtor != null) {
1132                                         GenerateTypeConstructor (typeCtor);
1133                                         continue;
1134                                 }
1135                                 CodeConstructor ctor = member as CodeConstructor;
1136                                 if (ctor != null) {
1137                                         GenerateConstructor (ctor, type);
1138                                         continue;
1139                                 }
1140                                 CodeMemberMethod method = member as CodeMemberMethod;
1141                                 if (method != null) {
1142                                         GenerateMethod (method, type);
1143                                         continue;
1144                                 }
1145                                 CodeMemberProperty property = member as CodeMemberProperty;
1146                                 if (property != null) {
1147                                         GenerateProperty (property, type);
1148                                         continue;
1149                                 }
1150                                 CodeSnippetTypeMember snippet = member as CodeSnippetTypeMember;
1151                                 if (snippet != null) {
1152                                         GenerateSnippetMember (snippet);
1153                                         continue;
1154                                 }
1155
1156                                 this.currentMember = prevMember;
1157                         }
1158
1159                         // Hack because of previous continue usage
1160                         if (currentMember != null && !(currentMember is CodeTypeDeclaration)) {
1161                                 if (currentMember.LinePragma != null)
1162                                         GenerateLinePragmaEnd (currentMember.LinePragma);
1163 #if NET_2_0
1164                                 if (currentMember.EndDirectives.Count > 0)
1165                                         GenerateDirectives (currentMember.EndDirectives);
1166 #endif
1167                         }
1168
1169                         this.currentType = type;
1170                         GenerateTypeEnd (type);
1171
1172                         if (type.LinePragma != null)
1173                                 GenerateLinePragmaEnd (type.LinePragma);
1174
1175 #if NET_2_0
1176                         if (type.EndDirectives.Count > 0)
1177                                 GenerateDirectives (type.EndDirectives);
1178 #endif
1179                 }
1180
1181                 protected abstract string GetTypeOutput (CodeTypeReference type);
1182
1183                 string ICodeGenerator.GetTypeOutput (CodeTypeReference type)
1184                 {
1185                         return GetTypeOutput (type);
1186                 }
1187
1188                 protected abstract bool IsValidIdentifier (string value);
1189
1190                 bool ICodeGenerator.IsValidIdentifier (string value)
1191                 {
1192                         return IsValidIdentifier (value);
1193                 }
1194
1195                 public static bool IsValidLanguageIndependentIdentifier (string value)
1196                 {
1197                         if (value == null)
1198                                 return false;
1199                         if (value.Equals (string.Empty))
1200                                 return false;
1201                         switch (char.GetUnicodeCategory (value[0]))
1202                         {
1203                                 case UnicodeCategory.LetterNumber:
1204                                 case UnicodeCategory.LowercaseLetter:
1205                                 case UnicodeCategory.TitlecaseLetter:
1206                                 case UnicodeCategory.UppercaseLetter:
1207                                 case UnicodeCategory.OtherLetter:
1208                                 case UnicodeCategory.ModifierLetter:
1209                                 case UnicodeCategory.ConnectorPunctuation:
1210                                         if (value.Length > 1)
1211                                         {
1212                                                 for (int x = 0; x < value.Length; x++)
1213                                                 {
1214                                                         switch (char.GetUnicodeCategory (value[x]))
1215                                                         {
1216                                                                 case UnicodeCategory.LetterNumber:
1217                                                                 case UnicodeCategory.LowercaseLetter:
1218                                                                 case UnicodeCategory.TitlecaseLetter:
1219                                                                 case UnicodeCategory.UppercaseLetter:
1220                                                                 case UnicodeCategory.OtherLetter:
1221                                                                 case UnicodeCategory.ModifierLetter:
1222                                                                 case UnicodeCategory.ConnectorPunctuation:
1223                                                                 case UnicodeCategory.DecimalDigitNumber:
1224                                                                 case UnicodeCategory.NonSpacingMark:
1225                                                                 case UnicodeCategory.SpacingCombiningMark:
1226                                                                 case UnicodeCategory.Format:
1227                                                                         return true;
1228                                                         }
1229                                                         return false;
1230                                                 }
1231                                         }
1232                                         else
1233                                                 return true;
1234                                         break;
1235                         }
1236                         return false;
1237                 }
1238
1239                 protected abstract bool Supports (GeneratorSupport supports);
1240
1241                 bool ICodeGenerator.Supports (GeneratorSupport value)
1242                 {
1243                         return Supports (value);
1244                 }
1245
1246                 protected virtual void ValidateIdentifier (string value)
1247                 {
1248                         if (!(IsValidIdentifier (value)))
1249                                 throw new ArgumentException ("Identifier is invalid", "value");
1250                 }
1251
1252                 [MonoTODO]
1253                 public static void ValidateIdentifiers (CodeObject e)
1254                 {
1255                         throw new NotImplementedException();
1256                 }
1257
1258                 void ICodeGenerator.ValidateIdentifier (string value)
1259                 {
1260                         ValidateIdentifier (value);
1261                 }
1262
1263                 // The position in the array determines the order in which those
1264                 // kind of CodeTypeMembers are generated. Less is more ;-)
1265                 static Type [] memberTypes = {  typeof (CodeMemberField),
1266                                                 typeof (CodeSnippetTypeMember),
1267                                                 typeof (CodeTypeConstructor),
1268                                                 typeof (CodeConstructor),
1269                                                 typeof (CodeMemberProperty),
1270                                                 typeof (CodeMemberEvent),
1271                                                 typeof (CodeMemberMethod),
1272                                                 typeof (CodeTypeDeclaration),
1273                                                 typeof (CodeEntryPointMethod)
1274                                         };
1275
1276 #if NET_2_0
1277                 protected virtual void GenerateDirectives (CodeDirectiveCollection directives)
1278                 {
1279                 }
1280 #endif
1281         }
1282 }