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