merge -r 58784:58785
[mono.git] / mcs / class / System / Microsoft.CSharp / CSharpCodeGenerator.cs
1 //
2 // Mono.CSharp CSharpCodeProvider Class implementation
3 //
4 // Author:
5 //   Daniel Stodden (stodden@in.tum.de)
6 //   Marek Safar (marek.safar@seznam.cz)
7 //
8 // (C) 2002 Ximian, Inc.
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 namespace Mono.CSharp
33 {
34         using System;
35         using System.CodeDom;
36         using System.CodeDom.Compiler;
37         using System.Globalization;
38         using System.IO;
39         using System.Reflection;
40         using System.Collections;
41         using System.Text;
42
43         internal class CSharpCodeGenerator
44                 : CodeGenerator
45         {
46                 // It is used for beautiful "for" syntax
47                 bool dont_write_semicolon;
48
49                 //
50                 // Constructors
51                 //
52                 public CSharpCodeGenerator()
53                 {
54                         dont_write_semicolon = false;
55                 }
56
57                 //
58                 // Properties
59                 //
60                 protected override string NullToken {
61                         get {
62                                 return "null";
63                         }
64                 }
65
66                 //
67                 // Methods
68                 //
69
70                 protected override void GenerateArrayCreateExpression (CodeArrayCreateExpression expression)
71                 {
72                         //
73                         // This tries to replicate MS behavior as good as
74                         // possible.
75                         //
76                         // The Code-Array stuff in ms.net seems to be broken
77                         // anyways, or I'm too stupid to understand it.
78                         //
79                         // I'm sick of it. If you try to develop array
80                         // creations, test them on windows. If it works there
81                         // but not in mono, drop me a note.  I'd be especially
82                         // interested in jagged-multidimensional combinations
83                         // with proper initialization :}
84                         //
85
86                         TextWriter output = Output;
87
88                         output.Write ("new ");
89
90                         CodeExpressionCollection initializers = expression.Initializers;
91                         CodeTypeReference createType = expression.CreateType;
92
93                         if (initializers.Count > 0) {
94
95                                 OutputType (createType);
96
97                                 if (expression.CreateType.ArrayRank == 0) {
98                                         output.Write ("[]");
99                                 }
100
101                                 OutputStartBrace ();
102                                 ++Indent;
103                                 OutputExpressionList (initializers, true);
104                                 --Indent;
105                                 output.Write ("}");
106                         } else {
107                                 CodeTypeReference arrayType = createType.ArrayElementType;
108                                 while (arrayType != null) {
109                                         createType = arrayType;
110                                         arrayType = arrayType.ArrayElementType;
111                                 }
112
113                                 OutputType (createType);
114
115                                 output.Write ('[');
116
117                                 CodeExpression size = expression.SizeExpression;
118                                 if (size != null)
119                                         GenerateExpression (size);
120                                 else
121                                         output.Write (expression.Size);
122
123                                 output.Write(']');
124                         }
125                 }
126                 
127                 protected override void GenerateBaseReferenceExpression (CodeBaseReferenceExpression expression)
128                 {
129                         Output.Write ("base");
130                 }
131                 
132                 protected override void GenerateCastExpression (CodeCastExpression expression)
133                 {
134                         TextWriter output = Output;
135                         output.Write ("((");
136                         OutputType (expression.TargetType);
137                         output.Write (")(");
138                         GenerateExpression (expression.Expression);
139                         output.Write ("))");
140                 }
141
142
143                 protected override void GenerateCompileUnitStart (CodeCompileUnit compileUnit)
144                 {
145                         GenerateComment (new CodeComment ("------------------------------------------------------------------------------"));
146                         GenerateComment (new CodeComment (" <autogenerated>"));
147                         GenerateComment (new CodeComment ("     This code was generated by a tool."));
148                         GenerateComment (new CodeComment ("     Mono Runtime Version: " +  System.Environment.Version));
149                         GenerateComment (new CodeComment (""));
150                         GenerateComment (new CodeComment ("     Changes to this file may cause incorrect behavior and will be lost if "));
151                         GenerateComment (new CodeComment ("     the code is regenerated."));
152                         GenerateComment (new CodeComment (" </autogenerated>"));
153                         GenerateComment (new CodeComment ("------------------------------------------------------------------------------"));
154                         Output.WriteLine ();
155                         base.GenerateCompileUnitStart (compileUnit);
156                 }
157
158                 protected override void GenerateCompileUnit (CodeCompileUnit compileUnit)
159                 {
160                         GenerateCompileUnitStart (compileUnit);
161
162                         if (compileUnit.AssemblyCustomAttributes.Count > 0) {
163                                 OutputAttributes (compileUnit.AssemblyCustomAttributes, 
164                                         "assembly: ", false);
165                                 Output.WriteLine ("");
166                         }
167
168                         foreach (CodeNamespace ns in compileUnit.Namespaces)
169                                 GenerateNamespace (ns);
170
171                         GenerateCompileUnitEnd (compileUnit);
172                 }
173
174                 protected override void GenerateDelegateCreateExpression (CodeDelegateCreateExpression expression)
175                 {
176                         TextWriter output = Output;
177
178                         output.Write ("new ");
179                         OutputType (expression.DelegateType);
180                         output.Write ('(');
181
182                         CodeExpression targetObject = expression.TargetObject;
183                         if (targetObject != null) {
184                                 GenerateExpression (targetObject);
185                                 Output.Write ('.');
186                         }
187                         output.Write (GetSafeName (expression.MethodName));
188
189                         output.Write (')');
190                 }
191
192                 protected override void GenerateFieldReferenceExpression (CodeFieldReferenceExpression expression)
193                 {
194                         CodeExpression targetObject = expression.TargetObject;
195                         if (targetObject != null) {
196                                 GenerateExpression (targetObject);
197                                 Output.Write ('.');
198                         }
199                         Output.Write (GetSafeName (expression.FieldName));
200                 }
201                 
202                 protected override void GenerateArgumentReferenceExpression (CodeArgumentReferenceExpression expression)
203                 {
204                         Output.Write (GetSafeName (expression.ParameterName));
205                 }
206
207                 protected override void GenerateVariableReferenceExpression (CodeVariableReferenceExpression expression)
208                 {
209                         Output.Write (GetSafeName (expression.VariableName));
210                 }
211                         
212                 protected override void GenerateIndexerExpression (CodeIndexerExpression expression)
213                 {
214                         TextWriter output = Output;
215
216                         GenerateExpression (expression.TargetObject);
217                         output.Write ('[');
218                         OutputExpressionList (expression.Indices);
219                         output.Write (']');
220                 }
221                 
222                 protected override void GenerateArrayIndexerExpression (CodeArrayIndexerExpression expression)
223                 {
224                         TextWriter output = Output;
225
226                         GenerateExpression (expression.TargetObject);
227                         output.Write ('[');
228                         OutputExpressionList (expression.Indices);
229                         output.Write (']');
230                 }
231                 
232                 protected override void GenerateSnippetExpression (CodeSnippetExpression expression)
233                 {
234                         Output.Write (expression.Value);
235                 }
236                 
237                 protected override void GenerateMethodInvokeExpression (CodeMethodInvokeExpression expression)
238                 {
239                         TextWriter output = Output;
240
241                         GenerateMethodReferenceExpression (expression.Method);
242
243                         output.Write ('(');
244                         OutputExpressionList (expression.Parameters);
245                         output.Write (')');
246                 }
247
248                 protected override void GenerateMethodReferenceExpression (CodeMethodReferenceExpression expression)
249                 {
250                         if (expression.TargetObject != null)
251                         {
252                                 GenerateExpression (expression.TargetObject);
253                                 Output.Write ('.');
254                         };
255                         Output.Write (GetSafeName (expression.MethodName));
256 #if NET_2_0
257                         if (expression.TypeArguments.Count > 0)
258                                 Output.Write (GetTypeArguments (expression.TypeArguments));
259 #endif
260                 }
261
262                 protected override void GenerateEventReferenceExpression (CodeEventReferenceExpression expression)
263                 {
264                         GenerateExpression (expression.TargetObject);
265                         Output.Write ('.');
266                         Output.Write (GetSafeName (expression.EventName));
267                 }
268
269                 protected override void GenerateDelegateInvokeExpression (CodeDelegateInvokeExpression expression)
270                 {
271                         GenerateExpression (expression.TargetObject);
272                         Output.Write ('(');
273                         OutputExpressionList (expression.Parameters);
274                         Output.Write (')');
275                 }
276                 
277                 protected override void GenerateObjectCreateExpression (CodeObjectCreateExpression expression)
278                 {
279                         Output.Write ("new ");
280                         OutputType (expression.CreateType);
281                         Output.Write ('(');
282                         OutputExpressionList (expression.Parameters);
283                         Output.Write (')');
284                 }
285
286                 protected override void GeneratePropertyReferenceExpression (CodePropertyReferenceExpression expression)
287                 {
288                         CodeExpression targetObject = expression.TargetObject;
289                         if (targetObject != null) {
290                                 GenerateExpression (targetObject);
291                                 Output.Write ('.');
292                         }
293                         Output.Write (GetSafeName (expression.PropertyName ));
294                 }
295
296                 protected override void GeneratePropertySetValueReferenceExpression (CodePropertySetValueReferenceExpression expression)
297                 {
298                         Output.Write ("value");
299                 }
300
301                 protected override void GenerateThisReferenceExpression (CodeThisReferenceExpression expression)
302                 {
303                         Output.Write ("this");
304                 }
305
306                 protected override void GenerateExpressionStatement (CodeExpressionStatement statement)
307                 {
308                         GenerateExpression (statement.Expression);
309                         if (dont_write_semicolon)
310                                 return;
311                         Output.WriteLine(';');
312                 }
313
314                 protected override void GenerateIterationStatement (CodeIterationStatement statement)
315                 {
316                         TextWriter output = Output;
317
318                         dont_write_semicolon = true;
319                         output.Write ("for (");
320                         GenerateStatement (statement.InitStatement);
321                         output.Write ("; ");
322                         GenerateExpression (statement.TestExpression);
323                         output.Write ("; ");
324                         GenerateStatement (statement.IncrementStatement);
325                         output.Write (") ");
326                         dont_write_semicolon = false;
327                         OutputStartBrace ();
328                         ++Indent;
329                         GenerateStatements (statement.Statements);
330                         --Indent;
331                         output.WriteLine ('}');
332                 }
333
334                 protected override void GenerateThrowExceptionStatement (CodeThrowExceptionStatement statement)
335                 {
336                         Output.Write ("throw");
337                         if (statement.ToThrow != null) {
338                                 Output.Write (' ');
339                                 GenerateExpression (statement.ToThrow);
340                         }
341                         Output.WriteLine (";");
342                 }
343
344                 protected override void GenerateComment (CodeComment comment)
345                 {
346                         TextWriter output = Output;
347                         string[] lines = comment.Text.Split ('\n');
348                         bool first = true;
349                         foreach (string line in lines){
350                                 if (comment.DocComment)
351                                         output.Write ("///");
352                                 else
353                                         output.Write ("//");
354                                 if (first) {
355                                         output.Write (' ');
356                                         first = false;
357                                 }
358                                 output.WriteLine (line);
359                         }
360                 }
361
362                 protected override void GenerateMethodReturnStatement (CodeMethodReturnStatement statement)
363                 {
364                         TextWriter output = Output;
365
366                         if (statement.Expression != null) {
367                                 output.Write ("return ");
368                                 GenerateExpression (statement.Expression);
369                                 output.WriteLine (";");
370                         } else {
371                                 output.WriteLine ("return;");
372                         }
373                 }
374
375                 protected override void GenerateConditionStatement (CodeConditionStatement statement)
376                 {
377                         TextWriter output = Output;
378                         output.Write ("if (");
379                         GenerateExpression (statement.Condition);
380                         output.Write (")");
381                         OutputStartBrace ();
382
383                         ++Indent;
384                         GenerateStatements (statement.TrueStatements);
385                         --Indent;
386
387                         CodeStatementCollection falses = statement.FalseStatements;
388                         if (falses.Count > 0) {
389                                 output.Write ('}');
390                                 if (Options.ElseOnClosing)
391                                         output.Write (' ');
392                                 else
393                                         output.WriteLine ();
394                                 output.WriteLine ("else");
395                                 OutputStartBrace ();
396                                 ++Indent;
397                                 GenerateStatements (falses);
398                                 --Indent;
399                         }
400                         output.WriteLine ('}');
401                 }
402
403                 protected override void GenerateTryCatchFinallyStatement (CodeTryCatchFinallyStatement statement)
404                 {
405                         TextWriter output = Output;
406                         CodeGeneratorOptions options = Options;
407
408                         output.WriteLine ("try");
409                         OutputStartBrace ();
410                         ++Indent;
411                         GenerateStatements (statement.TryStatements);
412                         --Indent;
413                         output.Write ('}');
414                         
415                         foreach (CodeCatchClause clause in statement.CatchClauses) {
416                                 if (options.ElseOnClosing)
417                                         output.Write (' ');
418                                 else
419                                         output.WriteLine ();
420                                 output.Write ("catch (");
421                                 OutputTypeNamePair (clause.CatchExceptionType, GetSafeName(clause.LocalName));
422                                 output.WriteLine (")");
423                                 OutputStartBrace ();
424                                 ++Indent;
425                                 GenerateStatements (clause.Statements);
426                                 --Indent;
427                                 output.Write ('}');
428                         }
429
430                         CodeStatementCollection finallies = statement.FinallyStatements;
431                         if (finallies.Count > 0) {
432                                 if (options.ElseOnClosing)
433                                         output.Write (' ');
434                                 else
435                                         output.WriteLine ();
436                                 output.WriteLine ("finally");
437                                 OutputStartBrace ();
438                                 ++Indent;
439                                 GenerateStatements (finallies);
440                                 --Indent;
441                                 output.WriteLine ('}');
442                         }
443
444                         output.WriteLine();
445                 }
446
447                 protected override void GenerateAssignStatement (CodeAssignStatement statement)
448                 {
449                         TextWriter output = Output;
450                         GenerateExpression (statement.Left);
451                         output.Write (" = ");
452                         GenerateExpression (statement.Right);
453                         if (dont_write_semicolon)
454                                 return;
455                         output.WriteLine (';');
456                 }
457
458                 protected override void GenerateAttachEventStatement (CodeAttachEventStatement statement)
459                 {
460                         TextWriter output = Output;
461
462                         GenerateEventReferenceExpression (statement.Event);
463                         output.Write (" += ");
464                         GenerateExpression (statement.Listener);
465                         output.WriteLine (';');
466                 }
467
468                 protected override void GenerateRemoveEventStatement (CodeRemoveEventStatement statement)
469                 {
470                         TextWriter output = Output;
471                         GenerateEventReferenceExpression (statement.Event);
472                         Output.Write (" -= ");
473                         GenerateExpression (statement.Listener);
474                         output.WriteLine (';');
475                 }
476
477                 protected override void GenerateGotoStatement (CodeGotoStatement statement)
478                 {
479                         TextWriter output = Output;
480
481                         output.Write ("goto ");
482                         output.Write (GetSafeName (statement.Label));
483                         output.Write (";");
484                 }
485                 
486                 protected override void GenerateLabeledStatement (CodeLabeledStatement statement)
487                 {
488                         Output.Write (String.Concat (GetSafeName (statement.Label), ": "));
489
490                         if (statement.Statement != null)
491                                 GenerateStatement (statement.Statement);
492                 }
493
494                 protected override void GenerateVariableDeclarationStatement (CodeVariableDeclarationStatement statement)
495                 {
496                         TextWriter output = Output;
497
498                         OutputTypeNamePair (statement.Type, GetSafeName (statement.Name));
499
500                         CodeExpression initExpression = statement.InitExpression;
501                         if (initExpression != null) {
502                                 output.Write (" = ");
503                                 GenerateExpression (initExpression);
504                         }
505
506                         output.WriteLine (';');
507                 }
508
509                 protected override void GenerateLinePragmaStart (CodeLinePragma linePragma)
510                 {
511                         Output.WriteLine ();
512                         Output.Write ("#line ");
513                         Output.Write (linePragma.LineNumber);
514                         Output.Write (" \"");
515                         Output.Write (linePragma.FileName);
516                         Output.Write ("\"");
517                         Output.WriteLine ();
518                 }
519
520                 protected override void GenerateLinePragmaEnd (CodeLinePragma linePragma)
521                 {
522                         Output.WriteLine ();
523                         Output.WriteLine ("#line default");
524                 }
525
526                 protected override void GenerateEvent (CodeMemberEvent eventRef, CodeTypeDeclaration declaration)
527                 {
528                         if (IsCurrentDelegate || IsCurrentEnum) {
529                                 return;
530                         }
531
532                         OutputAttributes (eventRef.CustomAttributes, null, false);
533
534                         if (eventRef.PrivateImplementationType == null) {
535                                 OutputMemberAccessModifier (eventRef.Attributes);
536                         }
537
538                         Output.Write ("event ");
539
540                         if (eventRef.PrivateImplementationType != null) {
541                                 OutputTypeNamePair (eventRef.Type,
542                                         eventRef.PrivateImplementationType.BaseType + "." + 
543                                         eventRef.Name);
544                         } else {
545                                 OutputTypeNamePair (eventRef.Type, GetSafeName (eventRef.Name));
546                         }
547                         Output.WriteLine (';');
548                 }
549
550                 protected override void GenerateField (CodeMemberField field)
551                 {
552                         if (IsCurrentDelegate || IsCurrentInterface) {
553                                 return;
554                         }
555
556                         TextWriter output = Output;
557
558                         OutputAttributes (field.CustomAttributes, null, false);
559
560                         if (IsCurrentEnum) {
561                                 Output.Write (GetSafeName (field.Name));
562                         } else {
563                                 MemberAttributes attributes = field.Attributes;
564                                 OutputMemberAccessModifier (attributes);
565                                 OutputVTableModifier (attributes);
566                                 OutputFieldScopeModifier (attributes);
567
568                                 OutputTypeNamePair (field.Type, GetSafeName (field.Name));
569                         }
570
571                         CodeExpression initExpression = field.InitExpression;
572                         if (initExpression != null) {
573                                 output.Write (" = ");
574                                 GenerateExpression (initExpression);
575                         }
576
577                         if (IsCurrentEnum)
578                                 output.WriteLine (',');
579                         else
580                                 output.WriteLine (';');
581                 }
582                 
583                 protected override void GenerateSnippetMember (CodeSnippetTypeMember member)
584                 {
585                         Output.Write (member.Text);
586                 }
587                 
588                 protected override void GenerateEntryPointMethod (CodeEntryPointMethod method, 
589                                                                   CodeTypeDeclaration declaration)
590                 {
591 #if NET_2_0
592                         OutputAttributes (method.CustomAttributes, null, false);
593 #endif
594
595                         Output.Write ("public static ");
596 #if NET_2_0
597                         OutputType (method.ReturnType);
598 #else
599                         Output.Write ("void");
600 #endif
601                         Output.Write (" Main()");
602                         OutputStartBrace ();
603                         Indent++;
604                         GenerateStatements (method.Statements);
605                         Indent--;
606                         Output.WriteLine ("}");
607                 }
608                 
609                 protected override void GenerateMethod (CodeMemberMethod method,
610                                                         CodeTypeDeclaration declaration)
611                 {
612                         if (IsCurrentDelegate || IsCurrentEnum) {
613                                 return;
614                         }
615
616                         TextWriter output = Output;
617
618                         OutputAttributes (method.CustomAttributes, null, false);
619
620                         OutputAttributes (method.ReturnTypeCustomAttributes, 
621                                 "return: ", false);
622
623                         MemberAttributes attributes = method.Attributes;
624
625                         if (!IsCurrentInterface) {
626                                 if (method.PrivateImplementationType == null) {
627                                         OutputMemberAccessModifier (attributes);
628                                         OutputVTableModifier (attributes);
629                                         OutputMemberScopeModifier (attributes);
630                                 }
631                         } else {
632                                 OutputVTableModifier (attributes);
633                         }
634
635                         OutputType (method.ReturnType);
636                         output.Write (' ');
637
638                         CodeTypeReference privateType = method.PrivateImplementationType;
639                         if (privateType != null) {
640                                 output.Write (privateType.BaseType);
641                                 output.Write ('.');
642                         }
643                         output.Write (GetSafeName (method.Name));
644
645 #if NET_2_0
646                         GenerateGenericsParameters (method.TypeParameters);
647 #endif
648
649                         output.Write ('(');
650                         OutputParameters (method.Parameters);
651                         output.Write (')');
652
653 #if NET_2_0
654                         GenerateGenericsConstraints (method.TypeParameters);
655 #endif
656
657                         if ((attributes & MemberAttributes.ScopeMask) == MemberAttributes.Abstract || declaration.IsInterface)
658                                 output.WriteLine (';');
659                         else {
660                                 OutputStartBrace ();
661                                 ++Indent;
662                                 GenerateStatements (method.Statements);
663                                 --Indent;
664                                 output.WriteLine ('}');
665                         }
666                 }
667
668                 protected override void GenerateProperty (CodeMemberProperty property,
669                                                           CodeTypeDeclaration declaration)
670                 {
671                         if (IsCurrentDelegate || IsCurrentEnum) {
672                                 return;
673                         }
674
675                         TextWriter output = Output;
676
677                         OutputAttributes (property.CustomAttributes, null, false);
678
679                         MemberAttributes attributes = property.Attributes;
680
681                         if (!IsCurrentInterface) {
682                                 if (property.PrivateImplementationType == null) {
683                                         OutputMemberAccessModifier (attributes);
684                                         OutputVTableModifier (attributes);
685                                         OutputMemberScopeModifier (attributes);
686                                 }
687                         } else {
688                                 OutputVTableModifier (attributes);
689                         }
690
691                         OutputType (property.Type);
692                         output.Write (' ');
693
694                         if (!IsCurrentInterface && property.PrivateImplementationType != null) {
695                                 output.Write (property.PrivateImplementationType.BaseType);
696                                 output.Write ('.');
697                         }
698
699                         // only consider property indexer if name is Item (case-insensitive 
700                         // comparison) AND property has parameters
701                         if (string.Compare(property.Name, "Item", true, CultureInfo.InvariantCulture) == 0 && property.Parameters.Count > 0) {
702                                 output.Write ("this[");
703                                 OutputParameters(property.Parameters);
704                                 output.Write(']');
705                         } else {
706                                 output.Write (property.Name);
707                         }
708                         OutputStartBrace ();
709                         ++Indent;
710
711                         if (declaration.IsInterface)
712                         {
713                                 if (property.HasGet) output.WriteLine("get;");
714                                 if (property.HasSet) output.WriteLine("set;");
715                         }
716                         else
717                         {
718                                 if (property.HasGet)
719                                 {
720                                         output.Write ("get");
721                                         OutputStartBrace ();
722                                         ++Indent;
723
724                                         GenerateStatements (property.GetStatements);
725
726                                         --Indent;
727                                         output.WriteLine ('}');
728                                 }
729
730                                 if (property.HasSet)
731                                 {
732                                         output.Write ("set");
733                                         OutputStartBrace ();
734                                         ++Indent;
735
736                                         GenerateStatements (property.SetStatements);
737
738                                         --Indent;
739                                         output.WriteLine ('}');
740                                 }
741                         }
742
743                         --Indent;
744                         output.WriteLine ('}');
745                 }
746
747                 protected override void GenerateConstructor (CodeConstructor constructor, CodeTypeDeclaration declaration)
748                 {
749                         if (IsCurrentDelegate || IsCurrentEnum || IsCurrentInterface) {
750                                 return;
751                         }
752
753                         OutputAttributes (constructor.CustomAttributes, null, false);
754
755                         OutputMemberAccessModifier (constructor.Attributes);
756                         Output.Write (GetSafeName (CurrentTypeName) + "(");
757                         OutputParameters (constructor.Parameters);
758                         Output.Write (")");
759                         if (constructor.BaseConstructorArgs.Count > 0) {
760                                 Output.WriteLine (" : ");
761                                 Indent += 2;
762                                 Output.Write ("base(");
763                                 OutputExpressionList (constructor.BaseConstructorArgs);
764                                 Output.Write (')');
765                                 Indent -= 2;
766                         }
767                         if (constructor.ChainedConstructorArgs.Count > 0) {
768                                 Output.WriteLine (" : ");
769                                 Indent += 2;
770                                 Output.Write("this(");
771                                 OutputExpressionList (constructor.ChainedConstructorArgs);
772                                 Output.Write(')');
773                                 Indent -= 2;
774                         }
775                         OutputStartBrace ();
776                         Indent++;
777                         GenerateStatements (constructor.Statements);
778                         Indent--;
779                         Output.WriteLine ('}');
780                 }
781                 
782                 protected override void GenerateTypeConstructor (CodeTypeConstructor constructor)
783                 {
784                         if (IsCurrentDelegate || IsCurrentEnum || IsCurrentInterface) {
785                                 return;
786                         }
787
788 #if NET_2_0
789                         OutputAttributes (constructor.CustomAttributes, null, false);
790 #endif
791
792                         Output.Write ("static " + GetSafeName (CurrentTypeName) + "()");
793                         OutputStartBrace ();
794                         Indent++;
795                         GenerateStatements (constructor.Statements);
796                         Indent--;
797                         Output.WriteLine ('}');
798                 }
799
800                 protected override void GenerateTypeStart(CodeTypeDeclaration declaration)
801                 {
802                         TextWriter output = Output;
803
804                         OutputAttributes (declaration.CustomAttributes, null, false);
805
806                         if (!IsCurrentDelegate) {
807                                 OutputTypeAttributes (declaration);
808
809                                 output.Write (GetSafeName (declaration.Name));
810
811 #if NET_2_0
812                                 GenerateGenericsParameters (declaration.TypeParameters);
813 #endif
814
815                                 IEnumerator enumerator = declaration.BaseTypes.GetEnumerator ();
816                                 if (enumerator.MoveNext ()) {
817                                         CodeTypeReference type = (CodeTypeReference) enumerator.Current;
818
819                                         output.Write (" : ");
820                                         OutputType (type);
821
822                                         while (enumerator.MoveNext ()) {
823                                                 type = (CodeTypeReference) enumerator.Current;
824
825                                                 output.Write (", ");
826                                                 OutputType (type);
827                                         }
828                                 }
829
830 #if NET_2_0
831                                 GenerateGenericsConstraints (declaration.TypeParameters);
832 #endif
833                                 OutputStartBrace ();
834                                 ++Indent;
835                         } else {
836                                 if ((declaration.TypeAttributes & TypeAttributes.VisibilityMask) == TypeAttributes.Public) {
837                                         output.Write ("public ");
838                                 }
839
840                                 CodeTypeDelegate delegateDecl = (CodeTypeDelegate) declaration;
841                                 output.Write ("delegate ");
842                                 OutputType (delegateDecl.ReturnType);
843                                 output.Write (" ");
844                                 output.Write (GetSafeName (declaration.Name));
845                                 output.Write ("(");
846                                 OutputParameters (delegateDecl.Parameters);
847                                 output.WriteLine (");");
848                         }
849                 }
850
851                 protected override void GenerateTypeEnd (CodeTypeDeclaration declaration)
852                 {
853                         if (!IsCurrentDelegate) {
854                                 --Indent;
855                                 Output.WriteLine ("}");
856                         }
857                 }
858
859                 protected override void GenerateNamespaceStart (CodeNamespace ns)
860                 {
861                         TextWriter output = Output;
862                         
863                         string name = ns.Name;
864                         if (name != null && name.Length != 0) {
865                                 output.Write ("namespace ");
866                                 output.Write (GetSafeName (name));
867                                 OutputStartBrace ();
868                                 ++Indent;
869                         }
870                 }
871
872                 protected override void GenerateNamespaceEnd (CodeNamespace ns)
873                 {
874                         string name = ns.Name;
875                         if (name != null && name.Length != 0) {
876                                 --Indent;
877                                 Output.WriteLine ("}");
878                         }
879                 }
880
881                 protected override void GenerateNamespaceImport (CodeNamespaceImport import)
882                 {
883                         TextWriter output = Output;
884
885                         output.Write ("using ");
886                         output.Write (GetSafeName (import.Namespace));
887                         output.WriteLine (';');
888                 }
889                 
890                 protected override void GenerateAttributeDeclarationsStart (CodeAttributeDeclarationCollection attributes)
891                 {
892                         Output.Write ('[');
893                 }
894                 
895                 protected override void GenerateAttributeDeclarationsEnd (CodeAttributeDeclarationCollection attributes)
896                 {
897                         Output.Write (']');
898                 }
899
900                 private void OutputStartBrace ()
901                 {
902                         if (Options.BracingStyle == "C") {
903                                 Output.WriteLine ("");
904                                 Output.WriteLine ("{");
905                         } else {
906                                 Output.WriteLine (" {");
907                         }
908                 }
909
910                 private void OutputAttributes (CodeAttributeDeclarationCollection attributes, string prefix, bool inline)
911                 {
912                         foreach (CodeAttributeDeclaration att in attributes) {
913                                 GenerateAttributeDeclarationsStart (attributes);
914                                 if (prefix != null) {
915                                         Output.Write (prefix);
916                                 }
917                                 OutputAttributeDeclaration (att);
918                                 GenerateAttributeDeclarationsEnd (attributes);
919                                 if (inline) {
920                                         Output.Write (" ");
921                                 } else {
922                                         Output.WriteLine ();
923                                 }
924                         }
925                 }
926
927                 private void OutputAttributeDeclaration (CodeAttributeDeclaration attribute)
928                 {
929                         Output.Write (attribute.Name.Replace ('+', '.'));
930                         Output.Write ('(');
931                         IEnumerator enumerator = attribute.Arguments.GetEnumerator ();
932                         if (enumerator.MoveNext ()) {
933                                 CodeAttributeArgument argument = (CodeAttributeArgument) enumerator.Current;
934                                 OutputAttributeArgument (argument);
935
936                                 while (enumerator.MoveNext ()) {
937                                         Output.Write (", ");
938                                         argument = (CodeAttributeArgument) enumerator.Current;
939                                         OutputAttributeArgument (argument);
940                                 }
941                         }
942                         Output.Write (')');
943                 }
944
945                 protected override void OutputType (CodeTypeReference type)
946                 {
947                         Output.Write (GetTypeOutput (type));
948                 }
949
950                 private void OutputVTableModifier (MemberAttributes attributes)
951                 {
952                         if ((attributes & MemberAttributes.VTableMask) == MemberAttributes.New) {
953                                 Output.Write ("new ");
954                         }
955                 }
956
957                 protected override void OutputFieldScopeModifier (MemberAttributes attributes)
958                 {
959                         switch (attributes & MemberAttributes.ScopeMask) {
960                                 case MemberAttributes.Static:
961                                         Output.Write ("static ");
962                                         break;
963                                 case MemberAttributes.Const:
964                                         Output.Write ("const ");
965                                         break;
966                         }
967                 }
968
969 #if NET_2_0
970
971                 // Note: this method should in fact be private as in .NET 2.0, the 
972                 // CSharpCodeGenerator no longer derives from CodeGenerator but we
973                 // still need to make this change.
974                 protected override void OutputMemberAccessModifier (MemberAttributes attributes)
975                 {
976                         switch (attributes & MemberAttributes.AccessMask) {
977                                 case MemberAttributes.Assembly:
978                                 case MemberAttributes.FamilyAndAssembly:
979                                         Output.Write ("internal "); 
980                                         break;
981                                 case MemberAttributes.Family:
982                                         Output.Write ("protected ");
983                                         break;
984                                 case MemberAttributes.FamilyOrAssembly:
985                                         Output.Write ("protected internal ");
986                                         break;
987                                 case MemberAttributes.Private:
988                                         Output.Write ("private ");
989                                         break;
990                                 case MemberAttributes.Public:
991                                         Output.Write ("public ");
992                                         break;
993                         }
994                 }
995
996                 // Note: this method should in fact be private as in .NET 2.0, the 
997                 // CSharpCodeGenerator no longer derives from CodeGenerator but we
998                 // still need to make this change.
999                 protected override void OutputMemberScopeModifier (MemberAttributes attributes)
1000                 {
1001                         switch (attributes & MemberAttributes.ScopeMask) {
1002                                 case MemberAttributes.Abstract:
1003                                         Output.Write ("abstract ");
1004                                         break;
1005                                 case MemberAttributes.Final:
1006                                         // do nothing
1007                                         break;
1008                                 case MemberAttributes.Static:
1009                                         Output.Write ("static ");
1010                                         break;
1011                                 case MemberAttributes.Override:
1012                                         Output.Write ("override ");
1013                                         break;
1014                                 default:
1015                                         MemberAttributes access = attributes & MemberAttributes.AccessMask;
1016                                         if (access == MemberAttributes.Assembly || access == MemberAttributes.Family || access == MemberAttributes.Public) {
1017                                                 Output.Write ("virtual ");
1018                                         }
1019                                         break;
1020                         }
1021                 }
1022 #endif
1023
1024                 private void OutputTypeAttributes (CodeTypeDeclaration declaration)
1025                 {
1026                         TextWriter output = Output;
1027                         TypeAttributes attributes = declaration.TypeAttributes;
1028
1029                         switch (attributes & TypeAttributes.VisibilityMask) {
1030                                 case TypeAttributes.Public:
1031                                 case TypeAttributes.NestedPublic:
1032                                         output.Write ("public ");
1033                                         break;
1034                                 case TypeAttributes.NestedPrivate:
1035                                         output.Write ("private ");
1036                                         break;
1037 #if NET_2_0
1038                                 case TypeAttributes.NotPublic:
1039                                 case TypeAttributes.NestedFamANDAssem:
1040                                 case TypeAttributes.NestedAssembly:
1041                                         output.Write ("internal ");
1042                                         break; 
1043                                 case TypeAttributes.NestedFamily:
1044                                         output.Write ("protected ");
1045                                         break;
1046                                 case TypeAttributes.NestedFamORAssem:
1047                                         output.Write ("protected internal ");
1048                                         break;
1049 #endif
1050                         }
1051
1052                         if (declaration.IsStruct) {
1053 #if NET_2_0
1054                                 if (declaration.IsPartial) {
1055                                         output.Write ("partial ");
1056                                 }
1057 #endif
1058                                 output.Write ("struct ");
1059                         } else if (declaration.IsEnum) {
1060                                 output.Write ("enum ");
1061                         } else {
1062                                 if ((attributes & TypeAttributes.Interface) != 0) {
1063 #if NET_2_0
1064                                         if (declaration.IsPartial) {
1065                                                 output.Write ("partial ");
1066                                         }
1067 #endif
1068                                         output.Write ("interface ");
1069                                 } else {
1070                                         if ((attributes & TypeAttributes.Sealed) != 0)
1071                                                 output.Write ("sealed ");
1072                                         if ((attributes & TypeAttributes.Abstract) != 0)
1073                                                 output.Write ("abstract ");
1074 #if NET_2_0
1075                                         if (declaration.IsPartial) {
1076                                                 output.Write ("partial ");
1077                                         }
1078 #endif
1079                                         output.Write ("class ");
1080                                 }
1081                         }
1082                 }
1083
1084                 [MonoTODO ("Implement missing special characters")]
1085                 protected override string QuoteSnippetString (string value)
1086                 {
1087                         // FIXME: this is weird, but works.
1088                         string output = value.Replace ("\\", "\\\\");
1089                         output = output.Replace ("\"", "\\\"");
1090                         output = output.Replace ("\t", "\\t");
1091                         output = output.Replace ("\r", "\\r");
1092                         output = output.Replace ("\n", "\\n");
1093
1094                         return "\"" + output + "\"";
1095                 }
1096
1097                 protected override void GenerateParameterDeclarationExpression (CodeParameterDeclarationExpression e)
1098                 {
1099                         OutputAttributes (e.CustomAttributes, null, true);
1100                         OutputDirection (e.Direction);
1101                         OutputType (e.Type);
1102                         Output.Write (' ');
1103                         Output.Write (GetSafeName (e.Name));
1104                 }
1105
1106                 protected override void GenerateTypeOfExpression (CodeTypeOfExpression e)
1107                 {
1108                         Output.Write ("typeof(");
1109                         OutputType (e.Type);
1110                         Output.Write (")");
1111                 }
1112
1113                 /* 
1114                  * ICodeGenerator
1115                  */
1116
1117                 protected override string CreateEscapedIdentifier (string value)
1118                 {
1119                         if (value == null)
1120                                 throw new NullReferenceException ("Argument identifier is null.");
1121                         return GetSafeName (value);
1122                 }
1123
1124                 protected override string CreateValidIdentifier (string value)
1125                 {
1126                         if (value == null)
1127                                 throw new NullReferenceException ();
1128
1129                         if (keywordsTable == null)
1130                                 FillKeywordTable ();
1131
1132                         if (keywordsTable.Contains (value))
1133                                 return "_" + value;
1134                         else
1135                                 return value;
1136                 }
1137     
1138                 protected override string GetTypeOutput (CodeTypeReference type)
1139                 {
1140                         string typeOutput = null;
1141
1142                         if (type.ArrayElementType != null) {
1143                                 typeOutput = GetTypeOutput (type.ArrayElementType);
1144                         } else {
1145                                 typeOutput = DetermineTypeOutput (type);
1146                         }
1147
1148                         int rank = type.ArrayRank;
1149                         if (rank > 0) {
1150                                 typeOutput += '[';
1151                                 for (--rank; rank > 0; --rank) {
1152                                         typeOutput += ',';
1153                                 }
1154                                 typeOutput += ']';
1155                         }
1156                         return typeOutput;
1157                 }
1158
1159                 private string DetermineTypeOutput (CodeTypeReference type)
1160                 {
1161                         string typeOutput = null;
1162                         string baseType = type.BaseType;
1163
1164                         switch (baseType.ToLower (System.Globalization.CultureInfo.InvariantCulture)) {
1165                                 case "system.int32":
1166                                         typeOutput = "int";
1167                                         break;
1168                                 case "system.int64":
1169                                         typeOutput = "long";
1170                                         break;
1171                                 case "system.int16":
1172                                         typeOutput = "short";
1173                                         break;
1174                                 case "system.boolean":
1175                                         typeOutput = "bool";
1176                                         break;
1177                                 case "system.char":
1178                                         typeOutput = "char";
1179                                         break;
1180                                 case "system.string":
1181                                         typeOutput = "string";
1182                                         break;
1183                                 case "system.object":
1184                                         typeOutput = "object";
1185                                         break;
1186                                 case "system.void":
1187                                         typeOutput = "void";
1188                                         break;
1189 #if NET_2_0
1190                                 case "system.byte":
1191                                         typeOutput = "byte";
1192                                         break;
1193                                 case "system.sbyte":
1194                                         typeOutput = "sbyte";
1195                                         break;
1196                                 case "system.decimal":
1197                                         typeOutput = "decimal";
1198                                         break;
1199                                 case "system.double":
1200                                         typeOutput = "double";
1201                                         break;
1202                                 case "system.single":
1203                                         typeOutput = "float";
1204                                         break;
1205                                 case "system.uint16":
1206                                         typeOutput = "ushort";
1207                                         break;
1208                                 case "system.uint32":
1209                                         typeOutput = "uint";
1210                                         break;
1211                                 case "system.uint64":
1212                                         typeOutput = "ulong";
1213                                         break;
1214 #endif
1215                                 default:
1216 #if NET_2_0
1217                                         StringBuilder sb = new StringBuilder (baseType.Length);
1218                                         if (type.Options == CodeTypeReferenceOptions.GlobalReference) {
1219                                                 sb.Append ("global::");
1220                                         }
1221
1222                                         int lastProcessedChar = 0;
1223                                         for (int i = 0; i < baseType.Length; i++) {
1224                                                 char currentChar = baseType[i];
1225                                                 if (currentChar != '+' && currentChar != '.') {
1226                                                         if (currentChar == '`') {
1227                                                                 sb.Append (CreateEscapedIdentifier (baseType.Substring (
1228                                                                         lastProcessedChar, i - lastProcessedChar)));
1229                                                                 // skip ` character
1230                                                                 i++;
1231                                                                 // determine number of type arguments to output
1232                                                                 int typeArgCount = baseType[i] - '0';
1233                                                                 // output type arguments
1234                                                                 OutputTypeArguments (type.TypeArguments, sb, typeArgCount);
1235                                                                 // skip type argument indicator
1236                                                                 i++;
1237                                                                 // if next character is . or +, then append .
1238                                                                 if ((i < baseType.Length) && ((baseType[i] == '+') || (baseType[i] == '.'))) {
1239                                                                         sb.Append ('.');
1240                                                                         // skip character that we just processed
1241                                                                         i++;
1242                                                                 }
1243                                                                 // save postion of last processed character
1244                                                                 lastProcessedChar = i;
1245                                                         }
1246                                                 } else {
1247                                                         sb.Append (CreateEscapedIdentifier (baseType.Substring (
1248                                                                 lastProcessedChar, i - lastProcessedChar)));
1249                                                         sb.Append ('.');
1250                                                         // skip separator
1251                                                         i++;
1252                                                         // save postion of last processed character
1253                                                         lastProcessedChar = i;
1254                                                 }
1255                                         }
1256
1257                                         // add characters that have not yet been processed 
1258                                         if (lastProcessedChar < baseType.Length) {
1259                                                 sb.Append (CreateEscapedIdentifier (baseType.Substring (lastProcessedChar)));
1260                                         }
1261
1262                                         typeOutput = sb.ToString ();
1263 #else
1264                                         typeOutput = GetSafeName (baseType);
1265                                         typeOutput = typeOutput.Replace ('+', '.');
1266 #endif
1267                                         break;
1268                         }
1269                         return typeOutput;
1270                 }
1271
1272                 protected override bool IsValidIdentifier (string identifier)
1273                 {
1274                         if (keywordsTable == null)
1275                                 FillKeywordTable ();
1276
1277                         return !keywordsTable.Contains (identifier);
1278                 }
1279
1280                 protected override bool Supports (GeneratorSupport supports)
1281                 {
1282                         return true;
1283                 }
1284
1285 #if NET_2_0
1286                 protected override void GenerateDirectives (CodeDirectiveCollection directives)
1287                 {
1288                         foreach (CodeDirective d in directives) {
1289                                 if (d is CodeChecksumPragma) {
1290                                         GenerateCodeChecksumPragma ((CodeChecksumPragma)d);
1291                                         continue;
1292                                 }
1293                                 if (d is CodeRegionDirective) {
1294                                         GenerateCodeRegionDirective ((CodeRegionDirective)d);
1295                                         continue;
1296                                 }
1297                                 throw new NotImplementedException ("Unknown CodeDirective");
1298                         }
1299                 }
1300
1301                 void GenerateCodeChecksumPragma (CodeChecksumPragma pragma)
1302                 {
1303                         Output.Write ("#pragma checksum \"");
1304                         Output.Write (pragma.FileName);
1305                         Output.Write ("\" \"");
1306                         Output.Write (pragma.ChecksumAlgorithmId.ToString ("B"));
1307                         Output.Write ("\" \"");
1308                         if (pragma.ChecksumData != null) {
1309                                 foreach (byte b in pragma.ChecksumData) {
1310                                         Output.Write (b.ToString ("X2"));
1311                                 }
1312                         }
1313                         Output.WriteLine ("\"");
1314                 }
1315
1316                 void GenerateCodeRegionDirective (CodeRegionDirective region)
1317                 {
1318                         switch (region.RegionMode) {
1319                                 case CodeRegionMode.Start:
1320                                         Output.Write ("#region ");
1321                                         Output.WriteLine (region.RegionText);
1322                                         return;
1323                                 case CodeRegionMode.End:
1324                                         Output.WriteLine ("#endregion");
1325                                         return;
1326                         }
1327                 }
1328
1329                 void GenerateGenericsParameters (CodeTypeParameterCollection parameters)
1330                 {
1331                         int count = parameters.Count;
1332                         if (count == 0)
1333                                 return;
1334
1335                         Output.Write ('<');
1336                         for (int i = 0; i < count - 1; ++i) {
1337                                 Output.Write (parameters [i].Name);
1338                                 Output.Write (", ");
1339                         }
1340                         Output.Write (parameters [count - 1].Name);
1341                         Output.Write ('>');
1342                 }
1343
1344                 void GenerateGenericsConstraints (CodeTypeParameterCollection parameters)
1345                 {
1346                         int count = parameters.Count;
1347                         if (count == 0)
1348                                 return;
1349
1350                         ++Indent;
1351                         foreach (CodeTypeParameter p in parameters) {
1352                                 if (p.Constraints.Count == 0)
1353                                         continue;
1354                                 Output.WriteLine ();
1355                                 Output.Write ("where ");
1356                                 Output.Write (p.Name);
1357                                 Output.Write (" : ");
1358
1359                                 bool is_first = true;
1360                                 foreach (CodeTypeReference r in p.Constraints) {
1361                                         if (is_first)
1362                                                 is_first = false;
1363                                         else
1364                                                 Output.Write (", ");
1365                                         OutputType (r);
1366                                 }
1367                                 if (p.HasConstructorConstraint) {
1368                                         if (!is_first)
1369                                                 Output.Write (", ");
1370                                         Output.Write ("new ()");
1371                                 }
1372
1373                         }
1374                         --Indent;
1375                 }
1376
1377                 string GetTypeArguments (CodeTypeReferenceCollection collection)
1378                 {
1379                         StringBuilder sb = new StringBuilder (" <");
1380                         foreach (CodeTypeReference r in collection) {
1381                                 sb.Append (GetTypeOutput (r));
1382                                 sb.Append (", ");
1383                         }
1384                         sb.Length--;
1385                         sb [sb.Length - 1] = '>';
1386                         return sb.ToString ();
1387                 }
1388
1389                 private void OutputTypeArguments (CodeTypeReferenceCollection typeArguments, StringBuilder sb, int count)
1390                 {
1391                         if (count == 0) {
1392                                 return;
1393                         }
1394
1395                         sb.Append ('<');
1396
1397                         // write first type argument
1398                         sb.Append (GetTypeOutput (typeArguments[0]));
1399                         // subsequent type argument are prefixed by ', ' separator
1400                         for (int i = 1; i < count; i++) {
1401                                 sb.Append (", ");
1402                                 sb.Append (GetTypeOutput (typeArguments[i]));
1403                         }
1404
1405                         sb.Append ('>');
1406                 }
1407 #endif
1408
1409 #if false
1410                 //[MonoTODO]
1411                 public override void ValidateIdentifier (string identifier)
1412                 {
1413                 }
1414 #endif
1415
1416                 private string GetSafeName (string id)
1417                 {
1418                         if (keywordsTable == null) {
1419                                 FillKeywordTable ();
1420                         }
1421                         if (keywordsTable.Contains (id)) {
1422                                 return "@" + id;
1423                         } else {
1424                                 return id;
1425                         }
1426                 }
1427
1428                 static void FillKeywordTable ()
1429                 {
1430                         keywordsTable = new Hashtable ();
1431                         foreach (string keyword in keywords) {
1432                                 keywordsTable.Add (keyword, keyword);
1433                         }
1434                 }
1435
1436                 private static Hashtable keywordsTable;
1437                 private static string[] keywords = new string[] {
1438                         "abstract","event","new","struct","as","explicit","null","switch","base","extern",
1439                         "this","false","operator","throw","break","finally","out","true",
1440                         "fixed","override","try","case","params","typeof","catch","for",
1441                         "private","foreach","protected","checked","goto","public",
1442                         "unchecked","class","if","readonly","unsafe","const","implicit","ref",
1443                         "continue","in","return","using","virtual","default",
1444                         "interface","sealed","volatile","delegate","internal","do","is",
1445                         "sizeof","while","lock","stackalloc","else","static","enum",
1446                         "namespace",
1447                         "object","bool","byte","float","uint","char","ulong","ushort",
1448                         "decimal","int","sbyte","short","double","long","string","void",
1449 #if NET_2_0
1450                         "partial", "yield", "where"
1451 #endif
1452                 };
1453         }
1454 }