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