[runtime] Overwrite stacktrace for exception on re-throw. Fixes #1856.
[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                                         if (!Options.VerbatimOrder && prevMember is CodeSnippetTypeMember && !(member is CodeSnippetTypeMember))
919                                                 output.WriteLine ();
920                                 }
921
922                                 if (options.BlankLinesBetweenMembers)
923                                         output.WriteLine ();
924
925                                 subtype = member as CodeTypeDeclaration;
926                                 if (subtype != null) {
927                                         GenerateType (subtype);
928                                         this.currentType = type;
929                                         continue;
930                                 }
931
932                                 if (currentMember.StartDirectives.Count > 0)
933                                         GenerateDirectives (currentMember.StartDirectives);
934                                 foreach (CodeCommentStatement statement in member.Comments)
935                                         GenerateCommentStatement (statement);
936
937                                 if (member.LinePragma != null)
938                                         GenerateLinePragmaStart (member.LinePragma);
939
940                                 try {
941                                         member.Accept (visitor);
942                                 } catch (NotImplementedException) {
943                                         throw new ArgumentException ("Element type " + member.GetType () + " is not supported.");
944                                 }
945                         }
946
947                         // Hack because of previous continue usage
948                         if (currentMember != null && !(currentMember is CodeTypeDeclaration)) {
949                                 if (currentMember.LinePragma != null)
950                                         GenerateLinePragmaEnd (currentMember.LinePragma);
951                                 if (currentMember.EndDirectives.Count > 0)
952                                         GenerateDirectives (currentMember.EndDirectives);
953                                 if (!Options.VerbatimOrder && currentMember is CodeSnippetTypeMember)
954                                         output.WriteLine ();
955                         }
956
957                         this.currentType = type;
958                         GenerateTypeEnd (type);
959
960                         if (type.LinePragma != null)
961                                 GenerateLinePragmaEnd (type.LinePragma);
962
963                         if (type.EndDirectives.Count > 0)
964                                 GenerateDirectives (type.EndDirectives);
965                 }
966
967                 protected abstract string GetTypeOutput (CodeTypeReference type);
968
969                 string ICodeGenerator.GetTypeOutput (CodeTypeReference type)
970                 {
971                         return GetTypeOutput (type);
972                 }
973
974                 protected abstract bool IsValidIdentifier (string value);
975
976                 bool ICodeGenerator.IsValidIdentifier (string value)
977                 {
978                         return IsValidIdentifier (value);
979                 }
980
981                 public static bool IsValidLanguageIndependentIdentifier (string value)
982                 {
983                         if (value == null)
984                                 return false;
985                         if (value.Equals (string.Empty))
986                                 return false;
987
988                         switch (char.GetUnicodeCategory (value[0])) {
989                         case UnicodeCategory.LetterNumber:
990                         case UnicodeCategory.LowercaseLetter:
991                         case UnicodeCategory.TitlecaseLetter:
992                         case UnicodeCategory.UppercaseLetter:
993                         case UnicodeCategory.OtherLetter:
994                         case UnicodeCategory.ModifierLetter:
995                         case UnicodeCategory.ConnectorPunctuation:
996                                 break;
997                         default:
998                                 return false;
999                         }
1000
1001                         for (int x = 1; x < value.Length; ++x) {
1002                                 switch (char.GetUnicodeCategory (value[x])) {
1003                                 case UnicodeCategory.LetterNumber:
1004                                 case UnicodeCategory.LowercaseLetter:
1005                                 case UnicodeCategory.TitlecaseLetter:
1006                                 case UnicodeCategory.UppercaseLetter:
1007                                 case UnicodeCategory.OtherLetter:
1008                                 case UnicodeCategory.ModifierLetter:
1009                                 case UnicodeCategory.ConnectorPunctuation:
1010                                 case UnicodeCategory.DecimalDigitNumber:
1011                                 case UnicodeCategory.NonSpacingMark:
1012                                 case UnicodeCategory.SpacingCombiningMark:
1013                                 case UnicodeCategory.Format:
1014                                         break;
1015                                 default:
1016                                         return false;
1017                                 }
1018                         }
1019
1020                         return true;
1021                 }
1022
1023                 protected abstract bool Supports (GeneratorSupport supports);
1024
1025                 bool ICodeGenerator.Supports (GeneratorSupport value)
1026                 {
1027                         return Supports (value);
1028                 }
1029
1030                 protected virtual void ValidateIdentifier (string value)
1031                 {
1032                         if (!(IsValidIdentifier (value)))
1033                                 throw new ArgumentException ("Identifier is invalid", "value");
1034                 }
1035
1036                 [MonoTODO]
1037                 public static void ValidateIdentifiers (CodeObject e)
1038                 {
1039                         throw new NotImplementedException();
1040                 }
1041
1042                 void ICodeGenerator.ValidateIdentifier (string value)
1043                 {
1044                         ValidateIdentifier (value);
1045                 }
1046
1047                 // The position in the array determines the order in which those
1048                 // kind of CodeTypeMembers are generated. Less is more ;-)
1049                 static readonly Type [] memberTypes = { typeof (CodeMemberField),
1050                                                 typeof (CodeSnippetTypeMember),
1051                                                 typeof (CodeTypeConstructor),
1052                                                 typeof (CodeConstructor),
1053                                                 typeof (CodeMemberProperty),
1054                                                 typeof (CodeMemberEvent),
1055                                                 typeof (CodeMemberMethod),
1056                                                 typeof (CodeTypeDeclaration),
1057                                                 typeof (CodeEntryPointMethod)
1058                                         };
1059
1060                 protected virtual void GenerateDirectives (CodeDirectiveCollection directives)
1061                 {
1062                 }
1063
1064                 internal class Visitor : ICodeDomVisitor {
1065                         CodeGenerator g;
1066
1067                         public Visitor (CodeGenerator generator)
1068                         {
1069                                 this.g = generator;
1070                         }
1071
1072                         // CodeExpression
1073                                 
1074                         public void Visit (CodeArgumentReferenceExpression o)
1075                         {
1076                                 g.GenerateArgumentReferenceExpression (o);
1077                         }
1078         
1079                         public void Visit (CodeArrayCreateExpression o)
1080                         {
1081                                 g.GenerateArrayCreateExpression (o);
1082                         }
1083         
1084                         public void Visit (CodeArrayIndexerExpression o)
1085                         {
1086                                 g.GenerateArrayIndexerExpression (o);
1087                         }
1088         
1089                         public void Visit (CodeBaseReferenceExpression o)
1090                         {
1091                                 g.GenerateBaseReferenceExpression (o);
1092                         }
1093         
1094                         public void Visit (CodeBinaryOperatorExpression o)
1095                         {
1096                                 g.GenerateBinaryOperatorExpression (o);
1097                         }
1098         
1099                         public void Visit (CodeCastExpression o)
1100                         {
1101                                 g.GenerateCastExpression (o);
1102                         }
1103         
1104                         public void Visit (CodeDefaultValueExpression o)
1105                         {
1106                                 g.GenerateDefaultValueExpression (o);
1107                         }
1108         
1109                         public void Visit (CodeDelegateCreateExpression o)
1110                         {
1111                                 g.GenerateDelegateCreateExpression (o);
1112                         }
1113         
1114                         public void Visit (CodeDelegateInvokeExpression o)
1115                         {
1116                                 g.GenerateDelegateInvokeExpression (o);
1117                         }
1118         
1119                         public void Visit (CodeDirectionExpression o)
1120                         {
1121                                 g.GenerateDirectionExpression (o);
1122                         }
1123         
1124                         public void Visit (CodeEventReferenceExpression o)
1125                         {
1126                                 g.GenerateEventReferenceExpression (o);
1127                         }
1128         
1129                         public void Visit (CodeFieldReferenceExpression o)
1130                         {
1131                                 g.GenerateFieldReferenceExpression (o);
1132                         }
1133         
1134                         public void Visit (CodeIndexerExpression o)
1135                         {
1136                                 g.GenerateIndexerExpression (o);
1137                         }
1138         
1139                         public void Visit (CodeMethodInvokeExpression o)
1140                         {
1141                                 g.GenerateMethodInvokeExpression (o);
1142                         }
1143         
1144                         public void Visit (CodeMethodReferenceExpression o)
1145                         {
1146                                 g.GenerateMethodReferenceExpression (o);
1147                         }
1148         
1149                         public void Visit (CodeObjectCreateExpression o)
1150                         {
1151                                 g.GenerateObjectCreateExpression (o);
1152                         }
1153         
1154                         public void Visit (CodeParameterDeclarationExpression o)
1155                         {
1156                                 g.GenerateParameterDeclarationExpression (o);
1157                         }
1158         
1159                         public void Visit (CodePrimitiveExpression o)
1160                         {
1161                                 g.GeneratePrimitiveExpression (o);
1162                         }
1163         
1164                         public void Visit (CodePropertyReferenceExpression o)
1165                         {
1166                                 g.GeneratePropertyReferenceExpression (o);
1167                         }
1168         
1169                         public void Visit (CodePropertySetValueReferenceExpression o)
1170                         {
1171                                 g.GeneratePropertySetValueReferenceExpression (o);
1172                         }
1173         
1174                         public void Visit (CodeSnippetExpression o)
1175                         {
1176                                 g.GenerateSnippetExpression (o);
1177                         }
1178         
1179                         public void Visit (CodeThisReferenceExpression o)
1180                         {
1181                                 g.GenerateThisReferenceExpression (o);
1182                         }
1183         
1184                         public void Visit (CodeTypeOfExpression o)
1185                         {
1186                                 g.GenerateTypeOfExpression (o);
1187                         }
1188         
1189                         public void Visit (CodeTypeReferenceExpression o)
1190                         {
1191                                 g.GenerateTypeReferenceExpression (o);
1192                         }
1193                         
1194                         public void Visit (CodeVariableReferenceExpression o)
1195                         {
1196                                 g.GenerateVariableReferenceExpression (o);
1197                         }
1198                         
1199                         // CodeStatement
1200
1201                         public void Visit (CodeAssignStatement o)
1202                         {
1203                                 g.GenerateAssignStatement (o);
1204                         }
1205
1206                         public void Visit (CodeAttachEventStatement o)
1207                         {
1208                                 g.GenerateAttachEventStatement (o);
1209                         }
1210
1211                         public void Visit (CodeCommentStatement o)
1212                         {
1213                                 g.GenerateCommentStatement (o);
1214                         }
1215
1216                         public void Visit (CodeConditionStatement o)
1217                         {
1218                                 g.GenerateConditionStatement (o);
1219                         }
1220
1221                         public void Visit (CodeExpressionStatement o)
1222                         {
1223                                 g.GenerateExpressionStatement (o);
1224                         }
1225
1226                         public void Visit (CodeGotoStatement o)
1227                         {
1228                                 g.GenerateGotoStatement (o);
1229                         }
1230
1231                         public void Visit (CodeIterationStatement o)
1232                         {
1233                                 g.GenerateIterationStatement (o);
1234                         }
1235
1236                         public void Visit (CodeLabeledStatement o)
1237                         {
1238                                 g.GenerateLabeledStatement (o);
1239                         }
1240
1241                         public void Visit (CodeMethodReturnStatement o)
1242                         {
1243                                 g.GenerateMethodReturnStatement (o);
1244                         }
1245
1246                         public void Visit (CodeRemoveEventStatement o)
1247                         {
1248                                 g.GenerateRemoveEventStatement (o);
1249                         }
1250
1251                         public void Visit (CodeThrowExceptionStatement o)
1252                         {
1253                                 g.GenerateThrowExceptionStatement (o);
1254                         }
1255
1256                         public void Visit (CodeTryCatchFinallyStatement o)
1257                         {
1258                                 g.GenerateTryCatchFinallyStatement (o);
1259                         }
1260
1261                         public void Visit (CodeVariableDeclarationStatement o)
1262                         {
1263                                 g.GenerateVariableDeclarationStatement (o);
1264                         }
1265                 
1266                         // CodeTypeMember
1267                         
1268                         public void Visit (CodeConstructor o)
1269                         {
1270                                 g.GenerateConstructor (o, g.CurrentClass);
1271                         }
1272                         
1273                         public void Visit (CodeEntryPointMethod o)
1274                         {
1275                                 g.GenerateEntryPointMethod (o, g.CurrentClass);
1276                         }
1277         
1278                         public void Visit (CodeMemberEvent o)
1279                         {
1280                                 g.GenerateEvent (o, g.CurrentClass);
1281                         }
1282         
1283                         public void Visit (CodeMemberField o)
1284                         {
1285                                 g.GenerateField (o);
1286                         }
1287                         
1288                         public void Visit (CodeMemberMethod o)
1289                         {
1290                                 g.GenerateMethod (o, g.CurrentClass);
1291                         }
1292         
1293                         public void Visit (CodeMemberProperty o)
1294                         {
1295                                 g.GenerateProperty (o, g.CurrentClass);         
1296                         }
1297         
1298                         public void Visit (CodeSnippetTypeMember o)
1299                         {
1300                                 var indent = g.Indent;
1301                                 g.Indent = 0;
1302                                 g.GenerateSnippetMember (o);
1303
1304                                 if (g.Options.VerbatimOrder)
1305                                         g.Output.WriteLine ();
1306
1307                                 g.Indent = indent;
1308                         }
1309         
1310                         public void Visit (CodeTypeConstructor o)
1311                         {
1312                                 g.GenerateTypeConstructor (o);
1313                         }
1314                 }
1315         }
1316 }