2 // Mono.CSharp CSharpCodeProvider Class implementation
5 // Daniel Stodden (stodden@in.tum.de)
6 // Marek Safar (marek.safar@seznam.cz)
7 // Ilker Cetinkaya (mail@ilker.de)
9 // (C) 2002 Ximian, Inc.
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 using System.CodeDom.Compiler;
38 using System.Globalization;
40 using System.Reflection;
41 using System.Collections;
43 using System.Collections.Generic;
45 internal class CSharpCodeGenerator
48 IDictionary <string, string> providerOptions;
50 // It is used for beautiful "for" syntax
51 bool dont_write_semicolon;
56 public CSharpCodeGenerator()
58 dont_write_semicolon = false;
61 public CSharpCodeGenerator (IDictionary <string, string> providerOptions)
63 this.providerOptions = providerOptions;
66 protected IDictionary <string, string> ProviderOptions {
67 get { return providerOptions; }
73 protected override string NullToken {
83 protected override void GenerateArrayCreateExpression (CodeArrayCreateExpression expression)
86 // This tries to replicate MS behavior as good as
89 // The Code-Array stuff in ms.net seems to be broken
90 // anyways, or I'm too stupid to understand it.
92 // I'm sick of it. If you try to develop array
93 // creations, test them on windows. If it works there
94 // but not in mono, drop me a note. I'd be especially
95 // interested in jagged-multidimensional combinations
96 // with proper initialization :}
99 TextWriter output = Output;
101 output.Write ("new ");
103 CodeExpressionCollection initializers = expression.Initializers;
104 CodeTypeReference createType = expression.CreateType;
106 if (initializers.Count > 0) {
108 OutputType (createType);
110 if (expression.CreateType.ArrayRank == 0) {
116 OutputExpressionList (initializers, true);
120 CodeTypeReference arrayType = createType.ArrayElementType;
121 while (arrayType != null) {
122 createType = arrayType;
123 arrayType = arrayType.ArrayElementType;
126 OutputType (createType);
130 CodeExpression size = expression.SizeExpression;
132 GenerateExpression (size);
134 output.Write (expression.Size);
140 protected override void GenerateBaseReferenceExpression (CodeBaseReferenceExpression expression)
142 Output.Write ("base");
145 protected override void GenerateCastExpression (CodeCastExpression expression)
147 TextWriter output = Output;
149 OutputType (expression.TargetType);
151 GenerateExpression (expression.Expression);
156 protected override void GenerateCompileUnitStart (CodeCompileUnit compileUnit)
158 GenerateComment (new CodeComment ("------------------------------------------------------------------------------"));
159 GenerateComment (new CodeComment (" <autogenerated>"));
160 GenerateComment (new CodeComment (" This code was generated by a tool."));
161 GenerateComment (new CodeComment (" Mono Runtime Version: " + System.Environment.Version));
162 GenerateComment (new CodeComment (""));
163 GenerateComment (new CodeComment (" Changes to this file may cause incorrect behavior and will be lost if "));
164 GenerateComment (new CodeComment (" the code is regenerated."));
165 GenerateComment (new CodeComment (" </autogenerated>"));
166 GenerateComment (new CodeComment ("------------------------------------------------------------------------------"));
168 base.GenerateCompileUnitStart (compileUnit);
171 protected override void GenerateCompileUnit (CodeCompileUnit compileUnit)
173 GenerateCompileUnitStart (compileUnit);
175 List<CodeNamespaceImport> imports = null;
176 foreach (CodeNamespace codeNamespace in compileUnit.Namespaces) {
177 if (!string.IsNullOrEmpty (codeNamespace.Name))
180 if (codeNamespace.Imports.Count == 0)
184 imports = new List<CodeNamespaceImport> ();
186 foreach (CodeNamespaceImport i in codeNamespace.Imports)
190 if (imports != null) {
191 imports.Sort ((a, b) => a.Namespace.CompareTo (b.Namespace));
192 foreach (var import in imports)
193 GenerateNamespaceImport (import);
198 if (compileUnit.AssemblyCustomAttributes.Count > 0) {
199 OutputAttributes (compileUnit.AssemblyCustomAttributes,
200 "assembly: ", false);
201 Output.WriteLine ("");
204 CodeNamespaceImportCollection global_imports = null;
205 foreach (CodeNamespace codeNamespace in compileUnit.Namespaces) {
206 if (string.IsNullOrEmpty (codeNamespace.Name)) {
207 global_imports = codeNamespace.Imports;
208 codeNamespace.Imports.Clear ();
211 GenerateNamespace (codeNamespace);
213 if (global_imports != null) {
214 codeNamespace.Imports.Clear ();
215 foreach (CodeNamespaceImport ns in global_imports)
216 codeNamespace.Imports.Add (ns);
217 global_imports = null;
221 GenerateCompileUnitEnd (compileUnit);
224 protected override void GenerateDefaultValueExpression (CodeDefaultValueExpression e)
226 Output.Write ("default(");
231 protected override void GenerateDelegateCreateExpression (CodeDelegateCreateExpression expression)
233 TextWriter output = Output;
235 output.Write ("new ");
236 OutputType (expression.DelegateType);
239 CodeExpression targetObject = expression.TargetObject;
240 if (targetObject != null) {
241 GenerateExpression (targetObject);
244 output.Write (GetSafeName (expression.MethodName));
249 protected override void GenerateFieldReferenceExpression (CodeFieldReferenceExpression expression)
251 CodeExpression targetObject = expression.TargetObject;
252 if (targetObject != null) {
253 GenerateExpression (targetObject);
256 Output.Write (GetSafeName (expression.FieldName));
259 protected override void GenerateArgumentReferenceExpression (CodeArgumentReferenceExpression expression)
261 Output.Write (GetSafeName (expression.ParameterName));
264 protected override void GenerateVariableReferenceExpression (CodeVariableReferenceExpression expression)
266 Output.Write (GetSafeName (expression.VariableName));
269 protected override void GenerateIndexerExpression (CodeIndexerExpression expression)
271 TextWriter output = Output;
273 GenerateExpression (expression.TargetObject);
275 OutputExpressionList (expression.Indices);
279 protected override void GenerateArrayIndexerExpression (CodeArrayIndexerExpression expression)
281 TextWriter output = Output;
283 GenerateExpression (expression.TargetObject);
285 OutputExpressionList (expression.Indices);
289 protected override void GenerateSnippetExpression (CodeSnippetExpression expression)
291 Output.Write (expression.Value);
294 protected override void GenerateMethodInvokeExpression (CodeMethodInvokeExpression expression)
296 TextWriter output = Output;
298 GenerateMethodReferenceExpression (expression.Method);
301 OutputExpressionList (expression.Parameters);
305 protected override void GenerateMethodReferenceExpression (CodeMethodReferenceExpression expression)
307 if (expression.TargetObject != null)
309 GenerateExpression (expression.TargetObject);
312 Output.Write (GetSafeName (expression.MethodName));
313 if (expression.TypeArguments.Count > 0)
314 Output.Write (GetTypeArguments (expression.TypeArguments));
317 protected override void GenerateEventReferenceExpression (CodeEventReferenceExpression expression)
319 if (expression.TargetObject != null) {
320 GenerateExpression (expression.TargetObject);
323 Output.Write (GetSafeName (expression.EventName));
326 protected override void GenerateDelegateInvokeExpression (CodeDelegateInvokeExpression expression)
328 if (expression.TargetObject != null)
329 GenerateExpression (expression.TargetObject);
331 OutputExpressionList (expression.Parameters);
335 protected override void GenerateObjectCreateExpression (CodeObjectCreateExpression expression)
337 Output.Write ("new ");
338 OutputType (expression.CreateType);
340 OutputExpressionList (expression.Parameters);
344 protected override void GeneratePropertyReferenceExpression (CodePropertyReferenceExpression expression)
346 CodeExpression targetObject = expression.TargetObject;
347 if (targetObject != null) {
348 GenerateExpression (targetObject);
351 Output.Write (GetSafeName (expression.PropertyName ));
354 protected override void GeneratePropertySetValueReferenceExpression (CodePropertySetValueReferenceExpression expression)
356 Output.Write ("value");
359 protected override void GenerateThisReferenceExpression (CodeThisReferenceExpression expression)
361 Output.Write ("this");
364 protected override void GenerateExpressionStatement (CodeExpressionStatement statement)
366 GenerateExpression (statement.Expression);
367 if (dont_write_semicolon)
369 Output.WriteLine(';');
372 protected override void GenerateIterationStatement (CodeIterationStatement statement)
374 TextWriter output = Output;
376 dont_write_semicolon = true;
377 output.Write ("for (");
378 GenerateStatement (statement.InitStatement);
380 GenerateExpression (statement.TestExpression);
382 GenerateStatement (statement.IncrementStatement);
384 dont_write_semicolon = false;
387 GenerateStatements (statement.Statements);
389 output.WriteLine ('}');
392 protected override void GenerateThrowExceptionStatement (CodeThrowExceptionStatement statement)
394 Output.Write ("throw");
395 if (statement.ToThrow != null) {
397 GenerateExpression (statement.ToThrow);
399 Output.WriteLine (";");
402 protected override void GenerateComment (CodeComment comment)
404 TextWriter output = Output;
406 string commentChars = null;
408 if (comment.DocComment) {
409 commentChars = "///";
414 output.Write (commentChars);
416 string text = comment.Text;
418 for (int i = 0; i < text.Length; i++) {
419 output.Write (text[i]);
420 if (text[i] == '\r') {
421 if (i < (text.Length - 1) && text[i + 1] == '\n') {
424 output.Write (commentChars);
425 } else if (text[i] == '\n') {
426 output.Write (commentChars);
433 protected override void GenerateMethodReturnStatement (CodeMethodReturnStatement statement)
435 TextWriter output = Output;
437 if (statement.Expression != null) {
438 output.Write ("return ");
439 GenerateExpression (statement.Expression);
440 output.WriteLine (";");
442 output.WriteLine ("return;");
446 protected override void GenerateConditionStatement (CodeConditionStatement statement)
448 TextWriter output = Output;
449 output.Write ("if (");
450 GenerateExpression (statement.Condition);
455 GenerateStatements (statement.TrueStatements);
458 CodeStatementCollection falses = statement.FalseStatements;
459 if (falses.Count > 0) {
461 if (Options.ElseOnClosing)
465 output.Write ("else");
468 GenerateStatements (falses);
471 output.WriteLine ('}');
474 protected override void GenerateTryCatchFinallyStatement (CodeTryCatchFinallyStatement statement)
476 TextWriter output = Output;
477 CodeGeneratorOptions options = Options;
479 output.Write ("try");
482 GenerateStatements (statement.TryStatements);
485 foreach (CodeCatchClause clause in statement.CatchClauses) {
487 if (options.ElseOnClosing)
491 output.Write ("catch (");
492 OutputTypeNamePair (clause.CatchExceptionType, GetSafeName(clause.LocalName));
496 GenerateStatements (clause.Statements);
500 CodeStatementCollection finallies = statement.FinallyStatements;
501 if (finallies.Count > 0) {
503 if (options.ElseOnClosing)
507 output.Write ("finally");
510 GenerateStatements (finallies);
514 output.WriteLine('}');
517 protected override void GenerateAssignStatement (CodeAssignStatement statement)
519 TextWriter output = Output;
520 GenerateExpression (statement.Left);
521 output.Write (" = ");
522 GenerateExpression (statement.Right);
523 if (dont_write_semicolon)
525 output.WriteLine (';');
528 protected override void GenerateAttachEventStatement (CodeAttachEventStatement statement)
530 TextWriter output = Output;
532 GenerateEventReferenceExpression (statement.Event);
533 output.Write (" += ");
534 GenerateExpression (statement.Listener);
535 output.WriteLine (';');
538 protected override void GenerateRemoveEventStatement (CodeRemoveEventStatement statement)
540 TextWriter output = Output;
541 GenerateEventReferenceExpression (statement.Event);
542 output.Write (" -= ");
543 GenerateExpression (statement.Listener);
544 output.WriteLine (';');
547 protected override void GenerateGotoStatement (CodeGotoStatement statement)
549 TextWriter output = Output;
551 output.Write ("goto ");
552 output.Write (GetSafeName (statement.Label));
553 output.WriteLine (";");
556 protected override void GenerateLabeledStatement (CodeLabeledStatement statement)
559 Output.Write (statement.Label);
560 Output.WriteLine (":");
563 if (statement.Statement != null) {
564 GenerateStatement (statement.Statement);
568 protected override void GenerateVariableDeclarationStatement (CodeVariableDeclarationStatement statement)
570 TextWriter output = Output;
572 OutputTypeNamePair (statement.Type, GetSafeName (statement.Name));
574 CodeExpression initExpression = statement.InitExpression;
575 if (initExpression != null) {
576 output.Write (" = ");
577 GenerateExpression (initExpression);
580 if (!dont_write_semicolon) {
581 output.WriteLine (';');
585 protected override void GenerateLinePragmaStart (CodeLinePragma linePragma)
588 Output.Write ("#line ");
589 Output.Write (linePragma.LineNumber);
590 Output.Write (" \"");
591 Output.Write (linePragma.FileName);
596 protected override void GenerateLinePragmaEnd (CodeLinePragma linePragma)
599 Output.WriteLine ("#line default");
600 Output.WriteLine ("#line hidden");
603 protected override void GenerateEvent (CodeMemberEvent eventRef, CodeTypeDeclaration declaration)
605 if (IsCurrentDelegate || IsCurrentEnum) {
609 OutputAttributes (eventRef.CustomAttributes, null, false);
611 if (eventRef.PrivateImplementationType == null) {
612 OutputMemberAccessModifier (eventRef.Attributes);
615 Output.Write ("event ");
617 if (eventRef.PrivateImplementationType != null) {
618 OutputTypeNamePair (eventRef.Type,
619 eventRef.PrivateImplementationType.BaseType + "." +
622 OutputTypeNamePair (eventRef.Type, GetSafeName (eventRef.Name));
624 Output.WriteLine (';');
627 protected override void GenerateField (CodeMemberField field)
629 if (IsCurrentDelegate || IsCurrentInterface) {
633 TextWriter output = Output;
635 OutputAttributes (field.CustomAttributes, null, false);
638 Output.Write (GetSafeName (field.Name));
640 MemberAttributes attributes = field.Attributes;
641 OutputMemberAccessModifier (attributes);
642 OutputVTableModifier (attributes);
643 OutputFieldScopeModifier (attributes);
645 OutputTypeNamePair (field.Type, GetSafeName (field.Name));
648 CodeExpression initExpression = field.InitExpression;
649 if (initExpression != null) {
650 output.Write (" = ");
651 GenerateExpression (initExpression);
655 output.WriteLine (',');
657 output.WriteLine (';');
660 protected override void GenerateSnippetMember (CodeSnippetTypeMember member)
662 Output.Write (member.Text);
665 protected override void GenerateEntryPointMethod (CodeEntryPointMethod method,
666 CodeTypeDeclaration declaration)
668 OutputAttributes (method.CustomAttributes, null, false);
670 Output.Write ("public static ");
671 OutputType (method.ReturnType);
672 Output.Write (" Main()");
675 GenerateStatements (method.Statements);
677 Output.WriteLine ("}");
680 protected override void GenerateMethod (CodeMemberMethod method,
681 CodeTypeDeclaration declaration)
683 if (IsCurrentDelegate || IsCurrentEnum) {
687 TextWriter output = Output;
689 OutputAttributes (method.CustomAttributes, null, false);
691 OutputAttributes (method.ReturnTypeCustomAttributes,
694 MemberAttributes attributes = method.Attributes;
696 if (!IsCurrentInterface) {
697 if (method.PrivateImplementationType == null) {
698 OutputMemberAccessModifier (attributes);
699 OutputVTableModifier (attributes);
700 OutputMemberScopeModifier (attributes);
703 OutputVTableModifier (attributes);
706 OutputType (method.ReturnType);
709 CodeTypeReference privateType = method.PrivateImplementationType;
710 if (privateType != null) {
711 output.Write (privateType.BaseType);
714 output.Write (GetSafeName (method.Name));
716 GenerateGenericsParameters (method.TypeParameters);
719 OutputParameters (method.Parameters);
722 GenerateGenericsConstraints (method.TypeParameters);
724 if (IsAbstract (attributes) || declaration.IsInterface)
725 output.WriteLine (';');
729 GenerateStatements (method.Statements);
731 output.WriteLine ('}');
735 static bool IsAbstract (MemberAttributes attributes)
737 return (attributes & MemberAttributes.ScopeMask) == MemberAttributes.Abstract;
740 protected override void GenerateProperty (CodeMemberProperty property,
741 CodeTypeDeclaration declaration)
743 if (IsCurrentDelegate || IsCurrentEnum) {
747 TextWriter output = Output;
749 OutputAttributes (property.CustomAttributes, null, false);
751 MemberAttributes attributes = property.Attributes;
753 if (!IsCurrentInterface) {
754 if (property.PrivateImplementationType == null) {
755 OutputMemberAccessModifier (attributes);
756 OutputVTableModifier (attributes);
757 OutputMemberScopeModifier (attributes);
760 OutputVTableModifier (attributes);
763 OutputType (property.Type);
766 if (!IsCurrentInterface && property.PrivateImplementationType != null) {
767 output.Write (property.PrivateImplementationType.BaseType);
771 // only consider property indexer if name is Item (case-insensitive
772 // comparison) AND property has parameters
773 if (string.Compare(property.Name, "Item", true, CultureInfo.InvariantCulture) == 0 && property.Parameters.Count > 0) {
774 output.Write ("this[");
775 OutputParameters(property.Parameters);
778 output.Write (GetSafeName (property.Name));
783 if (declaration.IsInterface || IsAbstract (property.Attributes))
785 if (property.HasGet) output.WriteLine("get;");
786 if (property.HasSet) output.WriteLine("set;");
792 output.Write ("get");
796 GenerateStatements (property.GetStatements);
799 output.WriteLine ('}');
804 output.Write ("set");
808 GenerateStatements (property.SetStatements);
811 output.WriteLine ('}');
816 output.WriteLine ('}');
819 protected override void GenerateConstructor (CodeConstructor constructor, CodeTypeDeclaration declaration)
821 if (IsCurrentDelegate || IsCurrentEnum || IsCurrentInterface) {
825 OutputAttributes (constructor.CustomAttributes, null, false);
827 OutputMemberAccessModifier (constructor.Attributes);
828 Output.Write (GetSafeName (CurrentTypeName) + "(");
829 OutputParameters (constructor.Parameters);
831 if (constructor.BaseConstructorArgs.Count > 0) {
832 Output.WriteLine (" : ");
834 Output.Write ("base(");
835 OutputExpressionList (constructor.BaseConstructorArgs);
839 if (constructor.ChainedConstructorArgs.Count > 0) {
840 Output.WriteLine (" : ");
842 Output.Write("this(");
843 OutputExpressionList (constructor.ChainedConstructorArgs);
849 GenerateStatements (constructor.Statements);
851 Output.WriteLine ('}');
854 protected override void GenerateTypeConstructor (CodeTypeConstructor constructor)
856 if (IsCurrentDelegate || IsCurrentEnum || IsCurrentInterface) {
860 OutputAttributes (constructor.CustomAttributes, null, false);
862 Output.Write ("static " + GetSafeName (CurrentTypeName) + "()");
865 GenerateStatements (constructor.Statements);
867 Output.WriteLine ('}');
870 protected override void GenerateTypeStart(CodeTypeDeclaration declaration)
872 TextWriter output = Output;
874 OutputAttributes (declaration.CustomAttributes, null, false);
876 if (!IsCurrentDelegate) {
877 OutputTypeAttributes (declaration);
879 output.Write (GetSafeName (declaration.Name));
881 GenerateGenericsParameters (declaration.TypeParameters);
883 IEnumerator enumerator = declaration.BaseTypes.GetEnumerator ();
884 if (enumerator.MoveNext ()) {
885 CodeTypeReference type = (CodeTypeReference) enumerator.Current;
887 output.Write (" : ");
890 while (enumerator.MoveNext ()) {
891 type = (CodeTypeReference) enumerator.Current;
898 GenerateGenericsConstraints (declaration.TypeParameters);
902 if ((declaration.TypeAttributes & TypeAttributes.VisibilityMask) == TypeAttributes.Public) {
903 output.Write ("public ");
906 CodeTypeDelegate delegateDecl = (CodeTypeDelegate) declaration;
907 output.Write ("delegate ");
908 OutputType (delegateDecl.ReturnType);
910 output.Write (GetSafeName (declaration.Name));
912 OutputParameters (delegateDecl.Parameters);
913 output.WriteLine (");");
917 protected override void GenerateTypeEnd (CodeTypeDeclaration declaration)
919 if (!IsCurrentDelegate) {
921 Output.WriteLine ("}");
925 protected override void GenerateNamespaceStart (CodeNamespace ns)
927 TextWriter output = Output;
929 string name = ns.Name;
930 if (name != null && name.Length != 0) {
931 output.Write ("namespace ");
932 output.Write (GetSafeName (name));
938 protected override void GenerateNamespaceEnd (CodeNamespace ns)
940 string name = ns.Name;
941 if (name != null && name.Length != 0) {
943 Output.WriteLine ("}");
947 protected override void GenerateNamespaceImport (CodeNamespaceImport import)
949 TextWriter output = Output;
951 output.Write ("using ");
952 output.Write (GetSafeName (import.Namespace));
953 output.WriteLine (';');
956 protected override void GenerateAttributeDeclarationsStart (CodeAttributeDeclarationCollection attributes)
961 protected override void GenerateAttributeDeclarationsEnd (CodeAttributeDeclarationCollection attributes)
966 private void OutputStartBrace ()
968 if (Options.BracingStyle == "C") {
969 Output.WriteLine ("");
970 Output.WriteLine ("{");
972 Output.WriteLine (" {");
976 private void OutputAttributes (CodeAttributeDeclarationCollection attributes, string prefix, bool inline)
978 bool params_set = false;
980 foreach (CodeAttributeDeclaration att in attributes) {
981 if (att.Name == "System.ParamArrayAttribute") {
986 GenerateAttributeDeclarationsStart (attributes);
987 if (prefix != null) {
988 Output.Write (prefix);
990 OutputAttributeDeclaration (att);
991 GenerateAttributeDeclarationsEnd (attributes);
1001 Output.Write (prefix);
1002 Output.Write ("params");
1006 Output.WriteLine ();
1010 private void OutputAttributeDeclaration (CodeAttributeDeclaration attribute)
1012 Output.Write (attribute.Name.Replace ('+', '.'));
1014 IEnumerator enumerator = attribute.Arguments.GetEnumerator ();
1015 if (enumerator.MoveNext ()) {
1016 CodeAttributeArgument argument = (CodeAttributeArgument) enumerator.Current;
1017 OutputAttributeArgument (argument);
1019 while (enumerator.MoveNext ()) {
1020 Output.Write (", ");
1021 argument = (CodeAttributeArgument) enumerator.Current;
1022 OutputAttributeArgument (argument);
1028 protected override void OutputType (CodeTypeReference type)
1030 Output.Write (GetTypeOutput (type));
1033 private void OutputVTableModifier (MemberAttributes attributes)
1035 if ((attributes & MemberAttributes.VTableMask) == MemberAttributes.New) {
1036 Output.Write ("new ");
1040 protected override void OutputFieldScopeModifier (MemberAttributes attributes)
1042 switch (attributes & MemberAttributes.ScopeMask) {
1043 case MemberAttributes.Static:
1044 Output.Write ("static ");
1046 case MemberAttributes.Const:
1047 Output.Write ("const ");
1053 // Note: this method should in fact be private as in .NET 2.0, the
1054 // CSharpCodeGenerator no longer derives from CodeGenerator but we
1055 // still need to make this change.
1056 protected override void OutputMemberAccessModifier (MemberAttributes attributes)
1058 switch (attributes & MemberAttributes.AccessMask) {
1059 case MemberAttributes.Assembly:
1060 case MemberAttributes.FamilyAndAssembly:
1061 Output.Write ("internal ");
1063 case MemberAttributes.Family:
1064 Output.Write ("protected ");
1066 case MemberAttributes.FamilyOrAssembly:
1067 Output.Write ("protected internal ");
1069 case MemberAttributes.Private:
1070 Output.Write ("private ");
1072 case MemberAttributes.Public:
1073 Output.Write ("public ");
1078 // Note: this method should in fact be private as in .NET 2.0, the
1079 // CSharpCodeGenerator no longer derives from CodeGenerator but we
1080 // still need to make this change.
1081 protected override void OutputMemberScopeModifier (MemberAttributes attributes)
1083 switch (attributes & MemberAttributes.ScopeMask) {
1084 case MemberAttributes.Abstract:
1085 Output.Write ("abstract ");
1087 case MemberAttributes.Final:
1090 case MemberAttributes.Static:
1091 Output.Write ("static ");
1093 case MemberAttributes.Override:
1094 Output.Write ("override ");
1097 MemberAttributes access = attributes & MemberAttributes.AccessMask;
1098 if (access == MemberAttributes.Assembly || access == MemberAttributes.Family || access == MemberAttributes.Public) {
1099 Output.Write ("virtual ");
1105 private void OutputTypeAttributes (CodeTypeDeclaration declaration)
1107 TextWriter output = Output;
1108 TypeAttributes attributes = declaration.TypeAttributes;
1110 switch (attributes & TypeAttributes.VisibilityMask) {
1111 case TypeAttributes.Public:
1112 case TypeAttributes.NestedPublic:
1113 output.Write ("public ");
1115 case TypeAttributes.NestedPrivate:
1116 output.Write ("private ");
1118 case TypeAttributes.NotPublic:
1119 case TypeAttributes.NestedFamANDAssem:
1120 case TypeAttributes.NestedAssembly:
1121 output.Write ("internal ");
1123 case TypeAttributes.NestedFamily:
1124 output.Write ("protected ");
1126 case TypeAttributes.NestedFamORAssem:
1127 output.Write ("protected internal ");
1131 if ((declaration.Attributes & MemberAttributes.New) != 0)
1132 output.Write ("new ");
1134 if (declaration.IsStruct) {
1135 if (declaration.IsPartial) {
1136 output.Write ("partial ");
1138 output.Write ("struct ");
1139 } else if (declaration.IsEnum) {
1140 output.Write ("enum ");
1142 if ((attributes & TypeAttributes.Interface) != 0) {
1143 if (declaration.IsPartial) {
1144 output.Write ("partial ");
1146 output.Write ("interface ");
1148 if ((attributes & TypeAttributes.Sealed) != 0)
1149 output.Write ("sealed ");
1150 if ((attributes & TypeAttributes.Abstract) != 0)
1151 output.Write ("abstract ");
1152 if (declaration.IsPartial) {
1153 output.Write ("partial ");
1155 output.Write ("class ");
1160 [MonoTODO ("Implement missing special characters")]
1161 protected override string QuoteSnippetString (string value)
1163 // FIXME: this is weird, but works.
1164 string output = value.Replace ("\\", "\\\\");
1165 output = output.Replace ("\"", "\\\"");
1166 output = output.Replace ("\t", "\\t");
1167 output = output.Replace ("\r", "\\r");
1168 output = output.Replace ("\n", "\\n");
1170 return "\"" + output + "\"";
1173 protected override void GeneratePrimitiveExpression(CodePrimitiveExpression e)
1175 if (e.Value is char) {
1176 this.GenerateCharValue ((char) e.Value);
1177 } else if (e.Value is ushort) {
1178 ushort uc = (ushort) e.Value;
1179 Output.Write (uc.ToString(CultureInfo.InvariantCulture));
1180 } else if (e.Value is uint) {
1181 uint ui = (uint) e.Value;
1182 Output.Write (ui.ToString(CultureInfo.InvariantCulture));
1184 } else if (e.Value is ulong) {
1185 ulong ul = (ulong) e.Value;
1186 Output.Write (ul.ToString(CultureInfo.InvariantCulture));
1187 Output.Write ("ul");
1188 } else if (e.Value is sbyte) {
1189 sbyte sb = (sbyte) e.Value;
1190 Output.Write (sb.ToString(CultureInfo.InvariantCulture));
1192 base.GeneratePrimitiveExpression (e);
1196 private void GenerateCharValue (char c)
1198 Output.Write ('\'');
1202 Output.Write ("\\0");
1205 Output.Write ("\\t");
1208 Output.Write ("\\n");
1211 Output.Write ("\\r");
1214 Output.Write ("\\\"");
1217 Output.Write ("\\'");
1220 Output.Write ("\\\\");
1223 Output.Write ("\\u");
1224 Output.Write (((int) c).ToString ("X4", CultureInfo.InvariantCulture));
1227 Output.Write ("\\u");
1228 Output.Write (((int) c).ToString ("X4", CultureInfo.InvariantCulture));
1235 Output.Write ('\'');
1238 protected override void GenerateSingleFloatValue (float f)
1240 base.GenerateSingleFloatValue (f);
1241 base.Output.Write ('F');
1244 protected override void GenerateDecimalValue (decimal d)
1246 base.GenerateDecimalValue (d);
1247 base.Output.Write ('m');
1250 protected override void GenerateParameterDeclarationExpression (CodeParameterDeclarationExpression e)
1252 OutputAttributes (e.CustomAttributes, null, true);
1253 OutputDirection (e.Direction);
1254 OutputType (e.Type);
1256 Output.Write (GetSafeName (e.Name));
1259 protected override void GenerateTypeOfExpression (CodeTypeOfExpression e)
1261 Output.Write ("typeof(");
1262 OutputType (e.Type);
1270 protected override string CreateEscapedIdentifier (string value)
1273 throw new NullReferenceException ("Argument identifier is null.");
1274 return GetSafeName (value);
1277 protected override string CreateValidIdentifier (string value)
1280 throw new NullReferenceException ();
1282 if (keywordsTable == null)
1283 FillKeywordTable ();
1285 if (keywordsTable.Contains (value))
1291 protected override string GetTypeOutput (CodeTypeReference type)
1293 if ((type.Options & CodeTypeReferenceOptions.GenericTypeParameter) != 0)
1294 return type.BaseType;
1296 string typeOutput = null;
1298 if (type.ArrayElementType != null) {
1299 typeOutput = GetTypeOutput (type.ArrayElementType);
1301 typeOutput = DetermineTypeOutput (type);
1304 int rank = type.ArrayRank;
1307 for (--rank; rank > 0; --rank) {
1316 private string DetermineTypeOutput (CodeTypeReference type)
1318 string typeOutput = null;
1319 string baseType = type.BaseType;
1321 switch (baseType.ToLower (System.Globalization.CultureInfo.InvariantCulture)) {
1322 case "system.int32":
1325 case "system.int64":
1326 typeOutput = "long";
1328 case "system.int16":
1329 typeOutput = "short";
1331 case "system.boolean":
1332 typeOutput = "bool";
1335 typeOutput = "char";
1337 case "system.string":
1338 typeOutput = "string";
1340 case "system.object":
1341 typeOutput = "object";
1344 typeOutput = "void";
1347 typeOutput = "byte";
1349 case "system.sbyte":
1350 typeOutput = "sbyte";
1352 case "system.decimal":
1353 typeOutput = "decimal";
1355 case "system.double":
1356 typeOutput = "double";
1358 case "system.single":
1359 typeOutput = "float";
1361 case "system.uint16":
1362 typeOutput = "ushort";
1364 case "system.uint32":
1365 typeOutput = "uint";
1367 case "system.uint64":
1368 typeOutput = "ulong";
1371 StringBuilder sb = new StringBuilder (baseType.Length);
1372 if ((type.Options & CodeTypeReferenceOptions.GlobalReference) != 0) {
1373 sb.Append ("global::");
1376 int lastProcessedChar = 0;
1377 for (int i = 0; i < baseType.Length; i++) {
1378 char currentChar = baseType[i];
1379 if (currentChar != '+' && currentChar != '.') {
1380 if (currentChar == '`') {
1381 sb.Append (CreateEscapedIdentifier (baseType.Substring (
1382 lastProcessedChar, i - lastProcessedChar)));
1385 // determine number of type arguments to output
1387 while (end < baseType.Length && Char.IsDigit (baseType [end]))
1389 int typeArgCount = Int32.Parse (baseType.Substring (i, end - i));
1390 // output type arguments
1391 OutputTypeArguments (type.TypeArguments, sb, typeArgCount);
1392 // skip type argument indicator
1394 // if next character is . or +, then append .
1395 if ((i < baseType.Length) && ((baseType[i] == '+') || (baseType[i] == '.'))) {
1397 // skip character that we just processed
1400 // save postion of last processed character
1401 lastProcessedChar = i;
1404 sb.Append (CreateEscapedIdentifier (baseType.Substring (
1405 lastProcessedChar, i - lastProcessedChar)));
1409 // save postion of last processed character
1410 lastProcessedChar = i;
1414 // add characters that have not yet been processed
1415 if (lastProcessedChar < baseType.Length) {
1416 sb.Append (CreateEscapedIdentifier (baseType.Substring (lastProcessedChar)));
1419 typeOutput = sb.ToString ();
1425 static bool is_identifier_start_character (char c)
1427 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == '@' || Char.IsLetter (c);
1430 static bool is_identifier_part_character (char c)
1432 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= '0' && c <= '9') || Char.IsLetter (c);
1435 protected override bool IsValidIdentifier (string identifier)
1437 if (identifier == null || identifier.Length == 0)
1440 if (keywordsTable == null)
1441 FillKeywordTable ();
1443 if (keywordsTable.Contains (identifier))
1446 if (!is_identifier_start_character (identifier [0]))
1449 for (int i = 1; i < identifier.Length; i ++)
1450 if (! is_identifier_part_character (identifier [i]))
1456 protected override bool Supports (GeneratorSupport supports)
1461 protected override void GenerateDirectives (CodeDirectiveCollection directives)
1463 foreach (CodeDirective d in directives) {
1464 if (d is CodeChecksumPragma) {
1465 GenerateCodeChecksumPragma ((CodeChecksumPragma)d);
1468 if (d is CodeRegionDirective) {
1469 GenerateCodeRegionDirective ((CodeRegionDirective)d);
1472 throw new NotImplementedException ("Unknown CodeDirective");
1476 void GenerateCodeChecksumPragma (CodeChecksumPragma pragma)
1478 Output.Write ("#pragma checksum ");
1479 Output.Write (QuoteSnippetString (pragma.FileName));
1480 Output.Write (" \"");
1481 Output.Write (pragma.ChecksumAlgorithmId.ToString ("B"));
1482 Output.Write ("\" \"");
1483 if (pragma.ChecksumData != null) {
1484 foreach (byte b in pragma.ChecksumData) {
1485 Output.Write (b.ToString ("X2"));
1488 Output.WriteLine ("\"");
1491 void GenerateCodeRegionDirective (CodeRegionDirective region)
1493 switch (region.RegionMode) {
1494 case CodeRegionMode.Start:
1495 Output.Write ("#region ");
1496 Output.WriteLine (region.RegionText);
1498 case CodeRegionMode.End:
1499 Output.WriteLine ("#endregion");
1504 void GenerateGenericsParameters (CodeTypeParameterCollection parameters)
1506 int count = parameters.Count;
1511 for (int i = 0; i < count - 1; ++i) {
1512 Output.Write (parameters [i].Name);
1513 Output.Write (", ");
1515 Output.Write (parameters [count - 1].Name);
1519 void GenerateGenericsConstraints (CodeTypeParameterCollection parameters)
1521 int count = parameters.Count;
1525 bool indented = false;
1527 for (int i = 0; i < count; i++) {
1528 CodeTypeParameter p = parameters [i];
1529 bool hasConstraints = (p.Constraints.Count != 0);
1530 Output.WriteLine ();
1531 if (!hasConstraints && !p.HasConstructorConstraint)
1539 Output.Write ("where ");
1540 Output.Write (p.Name);
1541 Output.Write (" : ");
1543 for (int j = 0; j < p.Constraints.Count; j++) {
1545 Output.Write (", ");
1546 OutputType (p.Constraints [j]);
1549 if (p.HasConstructorConstraint) {
1551 Output.Write (", ");
1552 Output.Write ("new");
1555 Output.Write ("()");
1563 string GetTypeArguments (CodeTypeReferenceCollection collection)
1565 StringBuilder sb = new StringBuilder (" <");
1566 foreach (CodeTypeReference r in collection) {
1567 sb.Append (GetTypeOutput (r));
1571 sb [sb.Length - 1] = '>';
1572 return sb.ToString ();
1575 private void OutputTypeArguments (CodeTypeReferenceCollection typeArguments, StringBuilder sb, int count)
1579 } else if (typeArguments.Count == 0) {
1580 // generic type definition
1587 // write first type argument
1588 sb.Append (GetTypeOutput (typeArguments[0]));
1589 // subsequent type argument are prefixed by ', ' separator
1590 for (int i = 1; i < count; i++) {
1592 sb.Append (GetTypeOutput (typeArguments[i]));
1600 public override void ValidateIdentifier (string identifier)
1605 private string GetSafeName (string id)
1607 if (keywordsTable == null) {
1608 FillKeywordTable ();
1610 if (keywordsTable.Contains (id)) {
1617 static void FillKeywordTable ()
1620 if (keywordsTable == null) {
1621 keywordsTable = new Hashtable ();
1622 foreach (string keyword in keywords) {
1623 keywordsTable.Add (keyword, keyword);
1629 private static Hashtable keywordsTable;
1630 private static string[] keywords = new string[] {
1631 "abstract","event","new","struct","as","explicit","null","switch","base","extern",
1632 "this","false","operator","throw","break","finally","out","true",
1633 "fixed","override","try","case","params","typeof","catch","for",
1634 "private","foreach","protected","checked","goto","public",
1635 "unchecked","class","if","readonly","unsafe","const","implicit","ref",
1636 "continue","in","return","using","virtual","default",
1637 "interface","sealed","volatile","delegate","internal","do","is",
1638 "sizeof","while","lock","stackalloc","else","static","enum",
1640 "object","bool","byte","float","uint","char","ulong","ushort",
1641 "decimal","int","sbyte","short","double","long","string","void",
1642 "partial", "yield", "where"