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