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 GenerateGlobalNamespace (compileUnit);
177 if (compileUnit.AssemblyCustomAttributes.Count > 0) {
178 OutputAttributes (compileUnit.AssemblyCustomAttributes,
179 "assembly: ", false);
180 Output.WriteLine ("");
183 GenerateLocalNamespaces (compileUnit);
185 GenerateCompileUnitEnd (compileUnit);
188 private void GenerateGlobalNamespace (CodeCompileUnit compileUnit) {
189 CodeNamespace globalNamespace = null;
191 foreach (CodeNamespace codeNamespace in compileUnit.Namespaces)
192 if (string.IsNullOrEmpty (codeNamespace.Name))
193 globalNamespace = codeNamespace;
195 if (globalNamespace != null)
196 GenerateNamespace (globalNamespace);
199 private void GenerateLocalNamespaces (CodeCompileUnit compileUnit) {
200 foreach (CodeNamespace codeNamespace in compileUnit.Namespaces)
201 if (!string.IsNullOrEmpty (codeNamespace.Name))
202 GenerateNamespace (codeNamespace);
205 protected override void GenerateDefaultValueExpression (CodeDefaultValueExpression e)
207 Output.Write ("default(");
212 protected override void GenerateDelegateCreateExpression (CodeDelegateCreateExpression expression)
214 TextWriter output = Output;
216 output.Write ("new ");
217 OutputType (expression.DelegateType);
220 CodeExpression targetObject = expression.TargetObject;
221 if (targetObject != null) {
222 GenerateExpression (targetObject);
225 output.Write (GetSafeName (expression.MethodName));
230 protected override void GenerateFieldReferenceExpression (CodeFieldReferenceExpression expression)
232 CodeExpression targetObject = expression.TargetObject;
233 if (targetObject != null) {
234 GenerateExpression (targetObject);
237 Output.Write (GetSafeName (expression.FieldName));
240 protected override void GenerateArgumentReferenceExpression (CodeArgumentReferenceExpression expression)
242 Output.Write (GetSafeName (expression.ParameterName));
245 protected override void GenerateVariableReferenceExpression (CodeVariableReferenceExpression expression)
247 Output.Write (GetSafeName (expression.VariableName));
250 protected override void GenerateIndexerExpression (CodeIndexerExpression expression)
252 TextWriter output = Output;
254 GenerateExpression (expression.TargetObject);
256 OutputExpressionList (expression.Indices);
260 protected override void GenerateArrayIndexerExpression (CodeArrayIndexerExpression expression)
262 TextWriter output = Output;
264 GenerateExpression (expression.TargetObject);
266 OutputExpressionList (expression.Indices);
270 protected override void GenerateSnippetExpression (CodeSnippetExpression expression)
272 Output.Write (expression.Value);
275 protected override void GenerateMethodInvokeExpression (CodeMethodInvokeExpression expression)
277 TextWriter output = Output;
279 GenerateMethodReferenceExpression (expression.Method);
282 OutputExpressionList (expression.Parameters);
286 protected override void GenerateMethodReferenceExpression (CodeMethodReferenceExpression expression)
288 if (expression.TargetObject != null)
290 GenerateExpression (expression.TargetObject);
293 Output.Write (GetSafeName (expression.MethodName));
294 if (expression.TypeArguments.Count > 0)
295 Output.Write (GetTypeArguments (expression.TypeArguments));
298 protected override void GenerateEventReferenceExpression (CodeEventReferenceExpression expression)
300 if (expression.TargetObject != null) {
301 GenerateExpression (expression.TargetObject);
304 Output.Write (GetSafeName (expression.EventName));
307 protected override void GenerateDelegateInvokeExpression (CodeDelegateInvokeExpression expression)
309 if (expression.TargetObject != null)
310 GenerateExpression (expression.TargetObject);
312 OutputExpressionList (expression.Parameters);
316 protected override void GenerateObjectCreateExpression (CodeObjectCreateExpression expression)
318 Output.Write ("new ");
319 OutputType (expression.CreateType);
321 OutputExpressionList (expression.Parameters);
325 protected override void GeneratePropertyReferenceExpression (CodePropertyReferenceExpression expression)
327 CodeExpression targetObject = expression.TargetObject;
328 if (targetObject != null) {
329 GenerateExpression (targetObject);
332 Output.Write (GetSafeName (expression.PropertyName ));
335 protected override void GeneratePropertySetValueReferenceExpression (CodePropertySetValueReferenceExpression expression)
337 Output.Write ("value");
340 protected override void GenerateThisReferenceExpression (CodeThisReferenceExpression expression)
342 Output.Write ("this");
345 protected override void GenerateExpressionStatement (CodeExpressionStatement statement)
347 GenerateExpression (statement.Expression);
348 if (dont_write_semicolon)
350 Output.WriteLine(';');
353 protected override void GenerateIterationStatement (CodeIterationStatement statement)
355 TextWriter output = Output;
357 dont_write_semicolon = true;
358 output.Write ("for (");
359 GenerateStatement (statement.InitStatement);
361 GenerateExpression (statement.TestExpression);
363 GenerateStatement (statement.IncrementStatement);
365 dont_write_semicolon = false;
368 GenerateStatements (statement.Statements);
370 output.WriteLine ('}');
373 protected override void GenerateThrowExceptionStatement (CodeThrowExceptionStatement statement)
375 Output.Write ("throw");
376 if (statement.ToThrow != null) {
378 GenerateExpression (statement.ToThrow);
380 Output.WriteLine (";");
383 protected override void GenerateComment (CodeComment comment)
385 TextWriter output = Output;
387 string commentChars = null;
389 if (comment.DocComment) {
390 commentChars = "///";
395 output.Write (commentChars);
397 string text = comment.Text;
399 for (int i = 0; i < text.Length; i++) {
400 output.Write (text[i]);
401 if (text[i] == '\r') {
402 if (i < (text.Length - 1) && text[i + 1] == '\n') {
405 output.Write (commentChars);
406 } else if (text[i] == '\n') {
407 output.Write (commentChars);
414 protected override void GenerateMethodReturnStatement (CodeMethodReturnStatement statement)
416 TextWriter output = Output;
418 if (statement.Expression != null) {
419 output.Write ("return ");
420 GenerateExpression (statement.Expression);
421 output.WriteLine (";");
423 output.WriteLine ("return;");
427 protected override void GenerateConditionStatement (CodeConditionStatement statement)
429 TextWriter output = Output;
430 output.Write ("if (");
431 GenerateExpression (statement.Condition);
436 GenerateStatements (statement.TrueStatements);
439 CodeStatementCollection falses = statement.FalseStatements;
440 if (falses.Count > 0) {
442 if (Options.ElseOnClosing)
446 output.Write ("else");
449 GenerateStatements (falses);
452 output.WriteLine ('}');
455 protected override void GenerateTryCatchFinallyStatement (CodeTryCatchFinallyStatement statement)
457 TextWriter output = Output;
458 CodeGeneratorOptions options = Options;
460 output.Write ("try");
463 GenerateStatements (statement.TryStatements);
466 foreach (CodeCatchClause clause in statement.CatchClauses) {
468 if (options.ElseOnClosing)
472 output.Write ("catch (");
473 OutputTypeNamePair (clause.CatchExceptionType, GetSafeName(clause.LocalName));
477 GenerateStatements (clause.Statements);
481 CodeStatementCollection finallies = statement.FinallyStatements;
482 if (finallies.Count > 0) {
484 if (options.ElseOnClosing)
488 output.Write ("finally");
491 GenerateStatements (finallies);
495 output.WriteLine('}');
498 protected override void GenerateAssignStatement (CodeAssignStatement statement)
500 TextWriter output = Output;
501 GenerateExpression (statement.Left);
502 output.Write (" = ");
503 GenerateExpression (statement.Right);
504 if (dont_write_semicolon)
506 output.WriteLine (';');
509 protected override void GenerateAttachEventStatement (CodeAttachEventStatement statement)
511 TextWriter output = Output;
513 GenerateEventReferenceExpression (statement.Event);
514 output.Write (" += ");
515 GenerateExpression (statement.Listener);
516 output.WriteLine (';');
519 protected override void GenerateRemoveEventStatement (CodeRemoveEventStatement statement)
521 TextWriter output = Output;
522 GenerateEventReferenceExpression (statement.Event);
523 output.Write (" -= ");
524 GenerateExpression (statement.Listener);
525 output.WriteLine (';');
528 protected override void GenerateGotoStatement (CodeGotoStatement statement)
530 TextWriter output = Output;
532 output.Write ("goto ");
533 output.Write (GetSafeName (statement.Label));
534 output.WriteLine (";");
537 protected override void GenerateLabeledStatement (CodeLabeledStatement statement)
540 Output.Write (statement.Label);
541 Output.WriteLine (":");
544 if (statement.Statement != null) {
545 GenerateStatement (statement.Statement);
549 protected override void GenerateVariableDeclarationStatement (CodeVariableDeclarationStatement statement)
551 TextWriter output = Output;
553 OutputTypeNamePair (statement.Type, GetSafeName (statement.Name));
555 CodeExpression initExpression = statement.InitExpression;
556 if (initExpression != null) {
557 output.Write (" = ");
558 GenerateExpression (initExpression);
561 if (!dont_write_semicolon) {
562 output.WriteLine (';');
566 protected override void GenerateLinePragmaStart (CodeLinePragma linePragma)
569 Output.Write ("#line ");
570 Output.Write (linePragma.LineNumber);
571 Output.Write (" \"");
572 Output.Write (linePragma.FileName);
577 protected override void GenerateLinePragmaEnd (CodeLinePragma linePragma)
580 Output.WriteLine ("#line default");
581 Output.WriteLine ("#line hidden");
584 protected override void GenerateEvent (CodeMemberEvent eventRef, CodeTypeDeclaration declaration)
586 if (IsCurrentDelegate || IsCurrentEnum) {
590 OutputAttributes (eventRef.CustomAttributes, null, false);
592 if (eventRef.PrivateImplementationType == null) {
593 OutputMemberAccessModifier (eventRef.Attributes);
596 Output.Write ("event ");
598 if (eventRef.PrivateImplementationType != null) {
599 OutputTypeNamePair (eventRef.Type,
600 eventRef.PrivateImplementationType.BaseType + "." +
603 OutputTypeNamePair (eventRef.Type, GetSafeName (eventRef.Name));
605 Output.WriteLine (';');
608 protected override void GenerateField (CodeMemberField field)
610 if (IsCurrentDelegate || IsCurrentInterface) {
614 TextWriter output = Output;
616 OutputAttributes (field.CustomAttributes, null, false);
619 Output.Write (GetSafeName (field.Name));
621 MemberAttributes attributes = field.Attributes;
622 OutputMemberAccessModifier (attributes);
623 OutputVTableModifier (attributes);
624 OutputFieldScopeModifier (attributes);
626 OutputTypeNamePair (field.Type, GetSafeName (field.Name));
629 CodeExpression initExpression = field.InitExpression;
630 if (initExpression != null) {
631 output.Write (" = ");
632 GenerateExpression (initExpression);
636 output.WriteLine (',');
638 output.WriteLine (';');
641 protected override void GenerateSnippetMember (CodeSnippetTypeMember member)
643 Output.Write (member.Text);
646 protected override void GenerateEntryPointMethod (CodeEntryPointMethod method,
647 CodeTypeDeclaration declaration)
649 OutputAttributes (method.CustomAttributes, null, false);
651 Output.Write ("public static ");
652 OutputType (method.ReturnType);
653 Output.Write (" Main()");
656 GenerateStatements (method.Statements);
658 Output.WriteLine ("}");
661 protected override void GenerateMethod (CodeMemberMethod method,
662 CodeTypeDeclaration declaration)
664 if (IsCurrentDelegate || IsCurrentEnum) {
668 TextWriter output = Output;
670 OutputAttributes (method.CustomAttributes, null, false);
672 OutputAttributes (method.ReturnTypeCustomAttributes,
675 MemberAttributes attributes = method.Attributes;
677 if (!IsCurrentInterface) {
678 if (method.PrivateImplementationType == null) {
679 OutputMemberAccessModifier (attributes);
680 OutputVTableModifier (attributes);
681 OutputMemberScopeModifier (attributes);
684 OutputVTableModifier (attributes);
687 OutputType (method.ReturnType);
690 CodeTypeReference privateType = method.PrivateImplementationType;
691 if (privateType != null) {
692 output.Write (privateType.BaseType);
695 output.Write (GetSafeName (method.Name));
697 GenerateGenericsParameters (method.TypeParameters);
700 OutputParameters (method.Parameters);
703 GenerateGenericsConstraints (method.TypeParameters);
705 if (IsAbstract (attributes) || declaration.IsInterface)
706 output.WriteLine (';');
710 GenerateStatements (method.Statements);
712 output.WriteLine ('}');
716 static bool IsAbstract (MemberAttributes attributes)
718 return (attributes & MemberAttributes.ScopeMask) == MemberAttributes.Abstract;
721 protected override void GenerateProperty (CodeMemberProperty property,
722 CodeTypeDeclaration declaration)
724 if (IsCurrentDelegate || IsCurrentEnum) {
728 TextWriter output = Output;
730 OutputAttributes (property.CustomAttributes, null, false);
732 MemberAttributes attributes = property.Attributes;
734 if (!IsCurrentInterface) {
735 if (property.PrivateImplementationType == null) {
736 OutputMemberAccessModifier (attributes);
737 OutputVTableModifier (attributes);
738 OutputMemberScopeModifier (attributes);
741 OutputVTableModifier (attributes);
744 OutputType (property.Type);
747 if (!IsCurrentInterface && property.PrivateImplementationType != null) {
748 output.Write (property.PrivateImplementationType.BaseType);
752 // only consider property indexer if name is Item (case-insensitive
753 // comparison) AND property has parameters
754 if (string.Compare(property.Name, "Item", true, CultureInfo.InvariantCulture) == 0 && property.Parameters.Count > 0) {
755 output.Write ("this[");
756 OutputParameters(property.Parameters);
759 output.Write (GetSafeName (property.Name));
764 if (declaration.IsInterface || IsAbstract (property.Attributes))
766 if (property.HasGet) output.WriteLine("get;");
767 if (property.HasSet) output.WriteLine("set;");
773 output.Write ("get");
777 GenerateStatements (property.GetStatements);
780 output.WriteLine ('}');
785 output.Write ("set");
789 GenerateStatements (property.SetStatements);
792 output.WriteLine ('}');
797 output.WriteLine ('}');
800 protected override void GenerateConstructor (CodeConstructor constructor, CodeTypeDeclaration declaration)
802 if (IsCurrentDelegate || IsCurrentEnum || IsCurrentInterface) {
806 OutputAttributes (constructor.CustomAttributes, null, false);
808 OutputMemberAccessModifier (constructor.Attributes);
809 Output.Write (GetSafeName (CurrentTypeName) + "(");
810 OutputParameters (constructor.Parameters);
812 if (constructor.BaseConstructorArgs.Count > 0) {
813 Output.WriteLine (" : ");
815 Output.Write ("base(");
816 OutputExpressionList (constructor.BaseConstructorArgs);
820 if (constructor.ChainedConstructorArgs.Count > 0) {
821 Output.WriteLine (" : ");
823 Output.Write("this(");
824 OutputExpressionList (constructor.ChainedConstructorArgs);
830 GenerateStatements (constructor.Statements);
832 Output.WriteLine ('}');
835 protected override void GenerateTypeConstructor (CodeTypeConstructor constructor)
837 if (IsCurrentDelegate || IsCurrentEnum || IsCurrentInterface) {
841 OutputAttributes (constructor.CustomAttributes, null, false);
843 Output.Write ("static " + GetSafeName (CurrentTypeName) + "()");
846 GenerateStatements (constructor.Statements);
848 Output.WriteLine ('}');
851 protected override void GenerateTypeStart(CodeTypeDeclaration declaration)
853 TextWriter output = Output;
855 OutputAttributes (declaration.CustomAttributes, null, false);
857 if (!IsCurrentDelegate) {
858 OutputTypeAttributes (declaration);
860 output.Write (GetSafeName (declaration.Name));
862 GenerateGenericsParameters (declaration.TypeParameters);
864 IEnumerator enumerator = declaration.BaseTypes.GetEnumerator ();
865 if (enumerator.MoveNext ()) {
866 CodeTypeReference type = (CodeTypeReference) enumerator.Current;
868 output.Write (" : ");
871 while (enumerator.MoveNext ()) {
872 type = (CodeTypeReference) enumerator.Current;
879 GenerateGenericsConstraints (declaration.TypeParameters);
883 if ((declaration.TypeAttributes & TypeAttributes.VisibilityMask) == TypeAttributes.Public) {
884 output.Write ("public ");
887 CodeTypeDelegate delegateDecl = (CodeTypeDelegate) declaration;
888 output.Write ("delegate ");
889 OutputType (delegateDecl.ReturnType);
891 output.Write (GetSafeName (declaration.Name));
893 OutputParameters (delegateDecl.Parameters);
894 output.WriteLine (");");
898 protected override void GenerateTypeEnd (CodeTypeDeclaration declaration)
900 if (!IsCurrentDelegate) {
902 Output.WriteLine ("}");
906 protected override void GenerateNamespaceStart (CodeNamespace ns)
908 TextWriter output = Output;
910 string name = ns.Name;
911 if (name != null && name.Length != 0) {
912 output.Write ("namespace ");
913 output.Write (GetSafeName (name));
919 protected override void GenerateNamespaceEnd (CodeNamespace ns)
921 string name = ns.Name;
922 if (name != null && name.Length != 0) {
924 Output.WriteLine ("}");
928 protected override void GenerateNamespaceImport (CodeNamespaceImport import)
930 TextWriter output = Output;
932 output.Write ("using ");
933 output.Write (GetSafeName (import.Namespace));
934 output.WriteLine (';');
937 protected override void GenerateAttributeDeclarationsStart (CodeAttributeDeclarationCollection attributes)
942 protected override void GenerateAttributeDeclarationsEnd (CodeAttributeDeclarationCollection attributes)
947 private void OutputStartBrace ()
949 if (Options.BracingStyle == "C") {
950 Output.WriteLine ("");
951 Output.WriteLine ("{");
953 Output.WriteLine (" {");
957 private void OutputAttributes (CodeAttributeDeclarationCollection attributes, string prefix, bool inline)
959 bool params_set = false;
961 foreach (CodeAttributeDeclaration att in attributes) {
962 if (att.Name == "System.ParamArrayAttribute") {
967 GenerateAttributeDeclarationsStart (attributes);
968 if (prefix != null) {
969 Output.Write (prefix);
971 OutputAttributeDeclaration (att);
972 GenerateAttributeDeclarationsEnd (attributes);
982 Output.Write (prefix);
983 Output.Write ("params");
991 private void OutputAttributeDeclaration (CodeAttributeDeclaration attribute)
993 Output.Write (attribute.Name.Replace ('+', '.'));
995 IEnumerator enumerator = attribute.Arguments.GetEnumerator ();
996 if (enumerator.MoveNext ()) {
997 CodeAttributeArgument argument = (CodeAttributeArgument) enumerator.Current;
998 OutputAttributeArgument (argument);
1000 while (enumerator.MoveNext ()) {
1001 Output.Write (", ");
1002 argument = (CodeAttributeArgument) enumerator.Current;
1003 OutputAttributeArgument (argument);
1009 protected override void OutputType (CodeTypeReference type)
1011 Output.Write (GetTypeOutput (type));
1014 private void OutputVTableModifier (MemberAttributes attributes)
1016 if ((attributes & MemberAttributes.VTableMask) == MemberAttributes.New) {
1017 Output.Write ("new ");
1021 protected override void OutputFieldScopeModifier (MemberAttributes attributes)
1023 switch (attributes & MemberAttributes.ScopeMask) {
1024 case MemberAttributes.Static:
1025 Output.Write ("static ");
1027 case MemberAttributes.Const:
1028 Output.Write ("const ");
1034 // Note: this method should in fact be private as in .NET 2.0, the
1035 // CSharpCodeGenerator no longer derives from CodeGenerator but we
1036 // still need to make this change.
1037 protected override void OutputMemberAccessModifier (MemberAttributes attributes)
1039 switch (attributes & MemberAttributes.AccessMask) {
1040 case MemberAttributes.Assembly:
1041 case MemberAttributes.FamilyAndAssembly:
1042 Output.Write ("internal ");
1044 case MemberAttributes.Family:
1045 Output.Write ("protected ");
1047 case MemberAttributes.FamilyOrAssembly:
1048 Output.Write ("protected internal ");
1050 case MemberAttributes.Private:
1051 Output.Write ("private ");
1053 case MemberAttributes.Public:
1054 Output.Write ("public ");
1059 // Note: this method should in fact be private as in .NET 2.0, the
1060 // CSharpCodeGenerator no longer derives from CodeGenerator but we
1061 // still need to make this change.
1062 protected override void OutputMemberScopeModifier (MemberAttributes attributes)
1064 switch (attributes & MemberAttributes.ScopeMask) {
1065 case MemberAttributes.Abstract:
1066 Output.Write ("abstract ");
1068 case MemberAttributes.Final:
1071 case MemberAttributes.Static:
1072 Output.Write ("static ");
1074 case MemberAttributes.Override:
1075 Output.Write ("override ");
1078 MemberAttributes access = attributes & MemberAttributes.AccessMask;
1079 if (access == MemberAttributes.Assembly || access == MemberAttributes.Family || access == MemberAttributes.Public) {
1080 Output.Write ("virtual ");
1086 private void OutputTypeAttributes (CodeTypeDeclaration declaration)
1088 TextWriter output = Output;
1089 TypeAttributes attributes = declaration.TypeAttributes;
1091 switch (attributes & TypeAttributes.VisibilityMask) {
1092 case TypeAttributes.Public:
1093 case TypeAttributes.NestedPublic:
1094 output.Write ("public ");
1096 case TypeAttributes.NestedPrivate:
1097 output.Write ("private ");
1099 case TypeAttributes.NotPublic:
1100 case TypeAttributes.NestedFamANDAssem:
1101 case TypeAttributes.NestedAssembly:
1102 output.Write ("internal ");
1104 case TypeAttributes.NestedFamily:
1105 output.Write ("protected ");
1107 case TypeAttributes.NestedFamORAssem:
1108 output.Write ("protected internal ");
1112 if ((declaration.Attributes & MemberAttributes.New) != 0)
1113 output.Write ("new ");
1115 if (declaration.IsStruct) {
1116 if (declaration.IsPartial) {
1117 output.Write ("partial ");
1119 output.Write ("struct ");
1120 } else if (declaration.IsEnum) {
1121 output.Write ("enum ");
1123 if ((attributes & TypeAttributes.Interface) != 0) {
1124 if (declaration.IsPartial) {
1125 output.Write ("partial ");
1127 output.Write ("interface ");
1129 if ((attributes & TypeAttributes.Sealed) != 0)
1130 output.Write ("sealed ");
1131 if ((attributes & TypeAttributes.Abstract) != 0)
1132 output.Write ("abstract ");
1133 if (declaration.IsPartial) {
1134 output.Write ("partial ");
1136 output.Write ("class ");
1141 [MonoTODO ("Implement missing special characters")]
1142 protected override string QuoteSnippetString (string value)
1144 // FIXME: this is weird, but works.
1145 string output = value.Replace ("\\", "\\\\");
1146 output = output.Replace ("\"", "\\\"");
1147 output = output.Replace ("\t", "\\t");
1148 output = output.Replace ("\r", "\\r");
1149 output = output.Replace ("\n", "\\n");
1151 return "\"" + output + "\"";
1154 protected override void GeneratePrimitiveExpression(CodePrimitiveExpression e)
1156 if (e.Value is char) {
1157 this.GenerateCharValue ((char) e.Value);
1158 } else if (e.Value is ushort) {
1159 ushort uc = (ushort) e.Value;
1160 Output.Write (uc.ToString(CultureInfo.InvariantCulture));
1161 } else if (e.Value is uint) {
1162 uint ui = (uint) e.Value;
1163 Output.Write (ui.ToString(CultureInfo.InvariantCulture));
1165 } else if (e.Value is ulong) {
1166 ulong ul = (ulong) e.Value;
1167 Output.Write (ul.ToString(CultureInfo.InvariantCulture));
1168 Output.Write ("ul");
1169 } else if (e.Value is sbyte) {
1170 sbyte sb = (sbyte) e.Value;
1171 Output.Write (sb.ToString(CultureInfo.InvariantCulture));
1173 base.GeneratePrimitiveExpression (e);
1177 private void GenerateCharValue (char c)
1179 Output.Write ('\'');
1183 Output.Write ("\\0");
1186 Output.Write ("\\t");
1189 Output.Write ("\\n");
1192 Output.Write ("\\r");
1195 Output.Write ("\\\"");
1198 Output.Write ("\\'");
1201 Output.Write ("\\\\");
1204 Output.Write ("\\u");
1205 Output.Write (((int) c).ToString ("X4", CultureInfo.InvariantCulture));
1208 Output.Write ("\\u");
1209 Output.Write (((int) c).ToString ("X4", CultureInfo.InvariantCulture));
1216 Output.Write ('\'');
1219 protected override void GenerateSingleFloatValue (float f)
1221 base.GenerateSingleFloatValue (f);
1222 base.Output.Write ('F');
1225 protected override void GenerateDecimalValue (decimal d)
1227 base.GenerateDecimalValue (d);
1228 base.Output.Write ('m');
1231 protected override void GenerateParameterDeclarationExpression (CodeParameterDeclarationExpression e)
1233 OutputAttributes (e.CustomAttributes, null, true);
1234 OutputDirection (e.Direction);
1235 OutputType (e.Type);
1237 Output.Write (GetSafeName (e.Name));
1240 protected override void GenerateTypeOfExpression (CodeTypeOfExpression e)
1242 Output.Write ("typeof(");
1243 OutputType (e.Type);
1251 protected override string CreateEscapedIdentifier (string value)
1254 throw new NullReferenceException ("Argument identifier is null.");
1255 return GetSafeName (value);
1258 protected override string CreateValidIdentifier (string value)
1261 throw new NullReferenceException ();
1263 if (keywordsTable == null)
1264 FillKeywordTable ();
1266 if (keywordsTable.Contains (value))
1272 protected override string GetTypeOutput (CodeTypeReference type)
1274 if ((type.Options & CodeTypeReferenceOptions.GenericTypeParameter) != 0)
1275 return type.BaseType;
1277 string typeOutput = null;
1279 if (type.ArrayElementType != null) {
1280 typeOutput = GetTypeOutput (type.ArrayElementType);
1282 typeOutput = DetermineTypeOutput (type);
1285 int rank = type.ArrayRank;
1288 for (--rank; rank > 0; --rank) {
1297 private string DetermineTypeOutput (CodeTypeReference type)
1299 string typeOutput = null;
1300 string baseType = type.BaseType;
1302 switch (baseType.ToLower (System.Globalization.CultureInfo.InvariantCulture)) {
1303 case "system.int32":
1306 case "system.int64":
1307 typeOutput = "long";
1309 case "system.int16":
1310 typeOutput = "short";
1312 case "system.boolean":
1313 typeOutput = "bool";
1316 typeOutput = "char";
1318 case "system.string":
1319 typeOutput = "string";
1321 case "system.object":
1322 typeOutput = "object";
1325 typeOutput = "void";
1328 typeOutput = "byte";
1330 case "system.sbyte":
1331 typeOutput = "sbyte";
1333 case "system.decimal":
1334 typeOutput = "decimal";
1336 case "system.double":
1337 typeOutput = "double";
1339 case "system.single":
1340 typeOutput = "float";
1342 case "system.uint16":
1343 typeOutput = "ushort";
1345 case "system.uint32":
1346 typeOutput = "uint";
1348 case "system.uint64":
1349 typeOutput = "ulong";
1352 StringBuilder sb = new StringBuilder (baseType.Length);
1353 if ((type.Options & CodeTypeReferenceOptions.GlobalReference) != 0) {
1354 sb.Append ("global::");
1357 int lastProcessedChar = 0;
1358 for (int i = 0; i < baseType.Length; i++) {
1359 char currentChar = baseType[i];
1360 if (currentChar != '+' && currentChar != '.') {
1361 if (currentChar == '`') {
1362 sb.Append (CreateEscapedIdentifier (baseType.Substring (
1363 lastProcessedChar, i - lastProcessedChar)));
1366 // determine number of type arguments to output
1368 while (end < baseType.Length && Char.IsDigit (baseType [end]))
1370 int typeArgCount = Int32.Parse (baseType.Substring (i, end - i));
1371 // output type arguments
1372 OutputTypeArguments (type.TypeArguments, sb, typeArgCount);
1373 // skip type argument indicator
1375 // if next character is . or +, then append .
1376 if ((i < baseType.Length) && ((baseType[i] == '+') || (baseType[i] == '.'))) {
1378 // skip character that we just processed
1381 // save postion of last processed character
1382 lastProcessedChar = i;
1385 sb.Append (CreateEscapedIdentifier (baseType.Substring (
1386 lastProcessedChar, i - lastProcessedChar)));
1390 // save postion of last processed character
1391 lastProcessedChar = i;
1395 // add characters that have not yet been processed
1396 if (lastProcessedChar < baseType.Length) {
1397 sb.Append (CreateEscapedIdentifier (baseType.Substring (lastProcessedChar)));
1400 typeOutput = sb.ToString ();
1406 static bool is_identifier_start_character (char c)
1408 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == '@' || Char.IsLetter (c);
1411 static bool is_identifier_part_character (char c)
1413 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= '0' && c <= '9') || Char.IsLetter (c);
1416 protected override bool IsValidIdentifier (string identifier)
1418 if (identifier == null || identifier.Length == 0)
1421 if (keywordsTable == null)
1422 FillKeywordTable ();
1424 if (keywordsTable.Contains (identifier))
1427 if (!is_identifier_start_character (identifier [0]))
1430 for (int i = 1; i < identifier.Length; i ++)
1431 if (! is_identifier_part_character (identifier [i]))
1437 protected override bool Supports (GeneratorSupport supports)
1442 protected override void GenerateDirectives (CodeDirectiveCollection directives)
1444 foreach (CodeDirective d in directives) {
1445 if (d is CodeChecksumPragma) {
1446 GenerateCodeChecksumPragma ((CodeChecksumPragma)d);
1449 if (d is CodeRegionDirective) {
1450 GenerateCodeRegionDirective ((CodeRegionDirective)d);
1453 throw new NotImplementedException ("Unknown CodeDirective");
1457 void GenerateCodeChecksumPragma (CodeChecksumPragma pragma)
1459 Output.Write ("#pragma checksum ");
1460 Output.Write (QuoteSnippetString (pragma.FileName));
1461 Output.Write (" \"");
1462 Output.Write (pragma.ChecksumAlgorithmId.ToString ("B"));
1463 Output.Write ("\" \"");
1464 if (pragma.ChecksumData != null) {
1465 foreach (byte b in pragma.ChecksumData) {
1466 Output.Write (b.ToString ("X2"));
1469 Output.WriteLine ("\"");
1472 void GenerateCodeRegionDirective (CodeRegionDirective region)
1474 switch (region.RegionMode) {
1475 case CodeRegionMode.Start:
1476 Output.Write ("#region ");
1477 Output.WriteLine (region.RegionText);
1479 case CodeRegionMode.End:
1480 Output.WriteLine ("#endregion");
1485 void GenerateGenericsParameters (CodeTypeParameterCollection parameters)
1487 int count = parameters.Count;
1492 for (int i = 0; i < count - 1; ++i) {
1493 Output.Write (parameters [i].Name);
1494 Output.Write (", ");
1496 Output.Write (parameters [count - 1].Name);
1500 void GenerateGenericsConstraints (CodeTypeParameterCollection parameters)
1502 int count = parameters.Count;
1506 bool indented = false;
1508 for (int i = 0; i < count; i++) {
1509 CodeTypeParameter p = parameters [i];
1510 bool hasConstraints = (p.Constraints.Count != 0);
1511 Output.WriteLine ();
1512 if (!hasConstraints && !p.HasConstructorConstraint)
1520 Output.Write ("where ");
1521 Output.Write (p.Name);
1522 Output.Write (" : ");
1524 for (int j = 0; j < p.Constraints.Count; j++) {
1526 Output.Write (", ");
1527 OutputType (p.Constraints [j]);
1530 if (p.HasConstructorConstraint) {
1532 Output.Write (", ");
1533 Output.Write ("new");
1536 Output.Write ("()");
1544 string GetTypeArguments (CodeTypeReferenceCollection collection)
1546 StringBuilder sb = new StringBuilder (" <");
1547 foreach (CodeTypeReference r in collection) {
1548 sb.Append (GetTypeOutput (r));
1552 sb [sb.Length - 1] = '>';
1553 return sb.ToString ();
1556 private void OutputTypeArguments (CodeTypeReferenceCollection typeArguments, StringBuilder sb, int count)
1560 } else if (typeArguments.Count == 0) {
1561 // generic type definition
1568 // write first type argument
1569 sb.Append (GetTypeOutput (typeArguments[0]));
1570 // subsequent type argument are prefixed by ', ' separator
1571 for (int i = 1; i < count; i++) {
1573 sb.Append (GetTypeOutput (typeArguments[i]));
1581 public override void ValidateIdentifier (string identifier)
1586 private string GetSafeName (string id)
1588 if (keywordsTable == null) {
1589 FillKeywordTable ();
1591 if (keywordsTable.Contains (id)) {
1598 static void FillKeywordTable ()
1600 keywordsTable = new Hashtable ();
1601 foreach (string keyword in keywords) {
1602 keywordsTable.Add (keyword, keyword);
1606 private static Hashtable keywordsTable;
1607 private static string[] keywords = new string[] {
1608 "abstract","event","new","struct","as","explicit","null","switch","base","extern",
1609 "this","false","operator","throw","break","finally","out","true",
1610 "fixed","override","try","case","params","typeof","catch","for",
1611 "private","foreach","protected","checked","goto","public",
1612 "unchecked","class","if","readonly","unsafe","const","implicit","ref",
1613 "continue","in","return","using","virtual","default",
1614 "interface","sealed","volatile","delegate","internal","do","is",
1615 "sizeof","while","lock","stackalloc","else","static","enum",
1617 "object","bool","byte","float","uint","char","ulong","ushort",
1618 "decimal","int","sbyte","short","double","long","string","void",
1619 "partial", "yield", "where"