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