2 // Mono.CSharp CSharpCodeProvider Class implementation
5 // Daniel Stodden (stodden@in.tum.de)
6 // Marek Safar (marek.safar@seznam.cz)
8 // (C) 2002 Ximian, Inc.
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:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
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.
36 using System.CodeDom.Compiler;
37 using System.Globalization;
39 using System.Reflection;
40 using System.Collections;
42 using System.Collections.Generic;
44 internal class CSharpCodeGenerator
47 IDictionary <string, string> providerOptions;
49 // It is used for beautiful "for" syntax
50 bool dont_write_semicolon;
55 public CSharpCodeGenerator()
57 dont_write_semicolon = false;
60 public CSharpCodeGenerator (IDictionary <string, string> providerOptions)
62 this.providerOptions = providerOptions;
65 protected IDictionary <string, string> ProviderOptions {
66 get { return providerOptions; }
72 protected override string NullToken {
82 protected override void GenerateArrayCreateExpression (CodeArrayCreateExpression expression)
85 // This tries to replicate MS behavior as good as
88 // The Code-Array stuff in ms.net seems to be broken
89 // anyways, or I'm too stupid to understand it.
91 // I'm sick of it. If you try to develop array
92 // creations, test them on windows. If it works there
93 // but not in mono, drop me a note. I'd be especially
94 // interested in jagged-multidimensional combinations
95 // with proper initialization :}
98 TextWriter output = Output;
100 output.Write ("new ");
102 CodeExpressionCollection initializers = expression.Initializers;
103 CodeTypeReference createType = expression.CreateType;
105 if (initializers.Count > 0) {
107 OutputType (createType);
109 if (expression.CreateType.ArrayRank == 0) {
115 OutputExpressionList (initializers, true);
119 CodeTypeReference arrayType = createType.ArrayElementType;
120 while (arrayType != null) {
121 createType = arrayType;
122 arrayType = arrayType.ArrayElementType;
125 OutputType (createType);
129 CodeExpression size = expression.SizeExpression;
131 GenerateExpression (size);
133 output.Write (expression.Size);
139 protected override void GenerateBaseReferenceExpression (CodeBaseReferenceExpression expression)
141 Output.Write ("base");
144 protected override void GenerateCastExpression (CodeCastExpression expression)
146 TextWriter output = Output;
148 OutputType (expression.TargetType);
150 GenerateExpression (expression.Expression);
155 protected override void GenerateCompileUnitStart (CodeCompileUnit compileUnit)
157 GenerateComment (new CodeComment ("------------------------------------------------------------------------------"));
158 GenerateComment (new CodeComment (" <autogenerated>"));
159 GenerateComment (new CodeComment (" This code was generated by a tool."));
160 GenerateComment (new CodeComment (" Mono Runtime Version: " + System.Environment.Version));
161 GenerateComment (new CodeComment (""));
162 GenerateComment (new CodeComment (" Changes to this file may cause incorrect behavior and will be lost if "));
163 GenerateComment (new CodeComment (" the code is regenerated."));
164 GenerateComment (new CodeComment (" </autogenerated>"));
165 GenerateComment (new CodeComment ("------------------------------------------------------------------------------"));
167 base.GenerateCompileUnitStart (compileUnit);
170 protected override void GenerateCompileUnit (CodeCompileUnit compileUnit)
172 GenerateCompileUnitStart (compileUnit);
174 if (compileUnit.AssemblyCustomAttributes.Count > 0) {
175 OutputAttributes (compileUnit.AssemblyCustomAttributes,
176 "assembly: ", false);
177 Output.WriteLine ("");
180 foreach (CodeNamespace ns in compileUnit.Namespaces)
181 GenerateNamespace (ns);
183 GenerateCompileUnitEnd (compileUnit);
186 protected override void GenerateDefaultValueExpression (CodeDefaultValueExpression e)
188 Output.Write ("default(");
193 protected override void GenerateDelegateCreateExpression (CodeDelegateCreateExpression expression)
195 TextWriter output = Output;
197 output.Write ("new ");
198 OutputType (expression.DelegateType);
201 CodeExpression targetObject = expression.TargetObject;
202 if (targetObject != null) {
203 GenerateExpression (targetObject);
206 output.Write (GetSafeName (expression.MethodName));
211 protected override void GenerateFieldReferenceExpression (CodeFieldReferenceExpression expression)
213 CodeExpression targetObject = expression.TargetObject;
214 if (targetObject != null) {
215 GenerateExpression (targetObject);
218 Output.Write (GetSafeName (expression.FieldName));
221 protected override void GenerateArgumentReferenceExpression (CodeArgumentReferenceExpression expression)
223 Output.Write (GetSafeName (expression.ParameterName));
226 protected override void GenerateVariableReferenceExpression (CodeVariableReferenceExpression expression)
228 Output.Write (GetSafeName (expression.VariableName));
231 protected override void GenerateIndexerExpression (CodeIndexerExpression expression)
233 TextWriter output = Output;
235 GenerateExpression (expression.TargetObject);
237 OutputExpressionList (expression.Indices);
241 protected override void GenerateArrayIndexerExpression (CodeArrayIndexerExpression expression)
243 TextWriter output = Output;
245 GenerateExpression (expression.TargetObject);
247 OutputExpressionList (expression.Indices);
251 protected override void GenerateSnippetExpression (CodeSnippetExpression expression)
253 Output.Write (expression.Value);
256 protected override void GenerateMethodInvokeExpression (CodeMethodInvokeExpression expression)
258 TextWriter output = Output;
260 GenerateMethodReferenceExpression (expression.Method);
263 OutputExpressionList (expression.Parameters);
267 protected override void GenerateMethodReferenceExpression (CodeMethodReferenceExpression expression)
269 if (expression.TargetObject != null)
271 GenerateExpression (expression.TargetObject);
274 Output.Write (GetSafeName (expression.MethodName));
275 if (expression.TypeArguments.Count > 0)
276 Output.Write (GetTypeArguments (expression.TypeArguments));
279 protected override void GenerateEventReferenceExpression (CodeEventReferenceExpression expression)
281 if (expression.TargetObject != null) {
282 GenerateExpression (expression.TargetObject);
285 Output.Write (GetSafeName (expression.EventName));
288 protected override void GenerateDelegateInvokeExpression (CodeDelegateInvokeExpression expression)
290 if (expression.TargetObject != null)
291 GenerateExpression (expression.TargetObject);
293 OutputExpressionList (expression.Parameters);
297 protected override void GenerateObjectCreateExpression (CodeObjectCreateExpression expression)
299 Output.Write ("new ");
300 OutputType (expression.CreateType);
302 OutputExpressionList (expression.Parameters);
306 protected override void GeneratePropertyReferenceExpression (CodePropertyReferenceExpression expression)
308 CodeExpression targetObject = expression.TargetObject;
309 if (targetObject != null) {
310 GenerateExpression (targetObject);
313 Output.Write (GetSafeName (expression.PropertyName ));
316 protected override void GeneratePropertySetValueReferenceExpression (CodePropertySetValueReferenceExpression expression)
318 Output.Write ("value");
321 protected override void GenerateThisReferenceExpression (CodeThisReferenceExpression expression)
323 Output.Write ("this");
326 protected override void GenerateExpressionStatement (CodeExpressionStatement statement)
328 GenerateExpression (statement.Expression);
329 if (dont_write_semicolon)
331 Output.WriteLine(';');
334 protected override void GenerateIterationStatement (CodeIterationStatement statement)
336 TextWriter output = Output;
338 dont_write_semicolon = true;
339 output.Write ("for (");
340 GenerateStatement (statement.InitStatement);
342 GenerateExpression (statement.TestExpression);
344 GenerateStatement (statement.IncrementStatement);
346 dont_write_semicolon = false;
349 GenerateStatements (statement.Statements);
351 output.WriteLine ('}');
354 protected override void GenerateThrowExceptionStatement (CodeThrowExceptionStatement statement)
356 Output.Write ("throw");
357 if (statement.ToThrow != null) {
359 GenerateExpression (statement.ToThrow);
361 Output.WriteLine (";");
364 protected override void GenerateComment (CodeComment comment)
366 TextWriter output = Output;
368 string commentChars = null;
370 if (comment.DocComment) {
371 commentChars = "///";
376 output.Write (commentChars);
378 string text = comment.Text;
380 for (int i = 0; i < text.Length; i++) {
381 output.Write (text[i]);
382 if (text[i] == '\r') {
383 if (i < (text.Length - 1) && text[i + 1] == '\n') {
386 output.Write (commentChars);
387 } else if (text[i] == '\n') {
388 output.Write (commentChars);
395 protected override void GenerateMethodReturnStatement (CodeMethodReturnStatement statement)
397 TextWriter output = Output;
399 if (statement.Expression != null) {
400 output.Write ("return ");
401 GenerateExpression (statement.Expression);
402 output.WriteLine (";");
404 output.WriteLine ("return;");
408 protected override void GenerateConditionStatement (CodeConditionStatement statement)
410 TextWriter output = Output;
411 output.Write ("if (");
412 GenerateExpression (statement.Condition);
417 GenerateStatements (statement.TrueStatements);
420 CodeStatementCollection falses = statement.FalseStatements;
421 if (falses.Count > 0) {
423 if (Options.ElseOnClosing)
427 output.Write ("else");
430 GenerateStatements (falses);
433 output.WriteLine ('}');
436 protected override void GenerateTryCatchFinallyStatement (CodeTryCatchFinallyStatement statement)
438 TextWriter output = Output;
439 CodeGeneratorOptions options = Options;
441 output.Write ("try");
444 GenerateStatements (statement.TryStatements);
447 foreach (CodeCatchClause clause in statement.CatchClauses) {
449 if (options.ElseOnClosing)
453 output.Write ("catch (");
454 OutputTypeNamePair (clause.CatchExceptionType, GetSafeName(clause.LocalName));
458 GenerateStatements (clause.Statements);
462 CodeStatementCollection finallies = statement.FinallyStatements;
463 if (finallies.Count > 0) {
465 if (options.ElseOnClosing)
469 output.Write ("finally");
472 GenerateStatements (finallies);
476 output.WriteLine('}');
479 protected override void GenerateAssignStatement (CodeAssignStatement statement)
481 TextWriter output = Output;
482 GenerateExpression (statement.Left);
483 output.Write (" = ");
484 GenerateExpression (statement.Right);
485 if (dont_write_semicolon)
487 output.WriteLine (';');
490 protected override void GenerateAttachEventStatement (CodeAttachEventStatement statement)
492 TextWriter output = Output;
494 GenerateEventReferenceExpression (statement.Event);
495 output.Write (" += ");
496 GenerateExpression (statement.Listener);
497 output.WriteLine (';');
500 protected override void GenerateRemoveEventStatement (CodeRemoveEventStatement statement)
502 TextWriter output = Output;
503 GenerateEventReferenceExpression (statement.Event);
504 output.Write (" -= ");
505 GenerateExpression (statement.Listener);
506 output.WriteLine (';');
509 protected override void GenerateGotoStatement (CodeGotoStatement statement)
511 TextWriter output = Output;
513 output.Write ("goto ");
514 output.Write (GetSafeName (statement.Label));
515 output.WriteLine (";");
518 protected override void GenerateLabeledStatement (CodeLabeledStatement statement)
521 Output.Write (statement.Label);
522 Output.WriteLine (":");
525 if (statement.Statement != null) {
526 GenerateStatement (statement.Statement);
530 protected override void GenerateVariableDeclarationStatement (CodeVariableDeclarationStatement statement)
532 TextWriter output = Output;
534 OutputTypeNamePair (statement.Type, GetSafeName (statement.Name));
536 CodeExpression initExpression = statement.InitExpression;
537 if (initExpression != null) {
538 output.Write (" = ");
539 GenerateExpression (initExpression);
542 if (!dont_write_semicolon) {
543 output.WriteLine (';');
547 protected override void GenerateLinePragmaStart (CodeLinePragma linePragma)
550 Output.Write ("#line ");
551 Output.Write (linePragma.LineNumber);
552 Output.Write (" \"");
553 Output.Write (linePragma.FileName);
558 protected override void GenerateLinePragmaEnd (CodeLinePragma linePragma)
561 Output.WriteLine ("#line default");
562 Output.WriteLine ("#line hidden");
565 protected override void GenerateEvent (CodeMemberEvent eventRef, CodeTypeDeclaration declaration)
567 if (IsCurrentDelegate || IsCurrentEnum) {
571 OutputAttributes (eventRef.CustomAttributes, null, false);
573 if (eventRef.PrivateImplementationType == null) {
574 OutputMemberAccessModifier (eventRef.Attributes);
577 Output.Write ("event ");
579 if (eventRef.PrivateImplementationType != null) {
580 OutputTypeNamePair (eventRef.Type,
581 eventRef.PrivateImplementationType.BaseType + "." +
584 OutputTypeNamePair (eventRef.Type, GetSafeName (eventRef.Name));
586 Output.WriteLine (';');
589 protected override void GenerateField (CodeMemberField field)
591 if (IsCurrentDelegate || IsCurrentInterface) {
595 TextWriter output = Output;
597 OutputAttributes (field.CustomAttributes, null, false);
600 Output.Write (GetSafeName (field.Name));
602 MemberAttributes attributes = field.Attributes;
603 OutputMemberAccessModifier (attributes);
604 OutputVTableModifier (attributes);
605 OutputFieldScopeModifier (attributes);
607 OutputTypeNamePair (field.Type, GetSafeName (field.Name));
610 CodeExpression initExpression = field.InitExpression;
611 if (initExpression != null) {
612 output.Write (" = ");
613 GenerateExpression (initExpression);
617 output.WriteLine (',');
619 output.WriteLine (';');
622 protected override void GenerateSnippetMember (CodeSnippetTypeMember member)
624 Output.Write (member.Text);
627 protected override void GenerateEntryPointMethod (CodeEntryPointMethod method,
628 CodeTypeDeclaration declaration)
630 OutputAttributes (method.CustomAttributes, null, false);
632 Output.Write ("public static ");
633 OutputType (method.ReturnType);
634 Output.Write (" Main()");
637 GenerateStatements (method.Statements);
639 Output.WriteLine ("}");
642 protected override void GenerateMethod (CodeMemberMethod method,
643 CodeTypeDeclaration declaration)
645 if (IsCurrentDelegate || IsCurrentEnum) {
649 TextWriter output = Output;
651 OutputAttributes (method.CustomAttributes, null, false);
653 OutputAttributes (method.ReturnTypeCustomAttributes,
656 MemberAttributes attributes = method.Attributes;
658 if (!IsCurrentInterface) {
659 if (method.PrivateImplementationType == null) {
660 OutputMemberAccessModifier (attributes);
661 OutputVTableModifier (attributes);
662 OutputMemberScopeModifier (attributes);
665 OutputVTableModifier (attributes);
668 OutputType (method.ReturnType);
671 CodeTypeReference privateType = method.PrivateImplementationType;
672 if (privateType != null) {
673 output.Write (privateType.BaseType);
676 output.Write (GetSafeName (method.Name));
678 GenerateGenericsParameters (method.TypeParameters);
681 OutputParameters (method.Parameters);
684 GenerateGenericsConstraints (method.TypeParameters);
686 if (IsAbstract (attributes) || declaration.IsInterface)
687 output.WriteLine (';');
691 GenerateStatements (method.Statements);
693 output.WriteLine ('}');
697 static bool IsAbstract (MemberAttributes attributes)
699 return (attributes & MemberAttributes.ScopeMask) == MemberAttributes.Abstract;
702 protected override void GenerateProperty (CodeMemberProperty property,
703 CodeTypeDeclaration declaration)
705 if (IsCurrentDelegate || IsCurrentEnum) {
709 TextWriter output = Output;
711 OutputAttributes (property.CustomAttributes, null, false);
713 MemberAttributes attributes = property.Attributes;
715 if (!IsCurrentInterface) {
716 if (property.PrivateImplementationType == null) {
717 OutputMemberAccessModifier (attributes);
718 OutputVTableModifier (attributes);
719 OutputMemberScopeModifier (attributes);
722 OutputVTableModifier (attributes);
725 OutputType (property.Type);
728 if (!IsCurrentInterface && property.PrivateImplementationType != null) {
729 output.Write (property.PrivateImplementationType.BaseType);
733 // only consider property indexer if name is Item (case-insensitive
734 // comparison) AND property has parameters
735 if (string.Compare(property.Name, "Item", true, CultureInfo.InvariantCulture) == 0 && property.Parameters.Count > 0) {
736 output.Write ("this[");
737 OutputParameters(property.Parameters);
740 output.Write (GetSafeName (property.Name));
745 if (declaration.IsInterface || IsAbstract (property.Attributes))
747 if (property.HasGet) output.WriteLine("get;");
748 if (property.HasSet) output.WriteLine("set;");
754 output.Write ("get");
758 GenerateStatements (property.GetStatements);
761 output.WriteLine ('}');
766 output.Write ("set");
770 GenerateStatements (property.SetStatements);
773 output.WriteLine ('}');
778 output.WriteLine ('}');
781 protected override void GenerateConstructor (CodeConstructor constructor, CodeTypeDeclaration declaration)
783 if (IsCurrentDelegate || IsCurrentEnum || IsCurrentInterface) {
787 OutputAttributes (constructor.CustomAttributes, null, false);
789 OutputMemberAccessModifier (constructor.Attributes);
790 Output.Write (GetSafeName (CurrentTypeName) + "(");
791 OutputParameters (constructor.Parameters);
793 if (constructor.BaseConstructorArgs.Count > 0) {
794 Output.WriteLine (" : ");
796 Output.Write ("base(");
797 OutputExpressionList (constructor.BaseConstructorArgs);
801 if (constructor.ChainedConstructorArgs.Count > 0) {
802 Output.WriteLine (" : ");
804 Output.Write("this(");
805 OutputExpressionList (constructor.ChainedConstructorArgs);
811 GenerateStatements (constructor.Statements);
813 Output.WriteLine ('}');
816 protected override void GenerateTypeConstructor (CodeTypeConstructor constructor)
818 if (IsCurrentDelegate || IsCurrentEnum || IsCurrentInterface) {
822 OutputAttributes (constructor.CustomAttributes, null, false);
824 Output.Write ("static " + GetSafeName (CurrentTypeName) + "()");
827 GenerateStatements (constructor.Statements);
829 Output.WriteLine ('}');
832 protected override void GenerateTypeStart(CodeTypeDeclaration declaration)
834 TextWriter output = Output;
836 OutputAttributes (declaration.CustomAttributes, null, false);
838 if (!IsCurrentDelegate) {
839 OutputTypeAttributes (declaration);
841 output.Write (GetSafeName (declaration.Name));
843 GenerateGenericsParameters (declaration.TypeParameters);
845 IEnumerator enumerator = declaration.BaseTypes.GetEnumerator ();
846 if (enumerator.MoveNext ()) {
847 CodeTypeReference type = (CodeTypeReference) enumerator.Current;
849 output.Write (" : ");
852 while (enumerator.MoveNext ()) {
853 type = (CodeTypeReference) enumerator.Current;
860 GenerateGenericsConstraints (declaration.TypeParameters);
864 if ((declaration.TypeAttributes & TypeAttributes.VisibilityMask) == TypeAttributes.Public) {
865 output.Write ("public ");
868 CodeTypeDelegate delegateDecl = (CodeTypeDelegate) declaration;
869 output.Write ("delegate ");
870 OutputType (delegateDecl.ReturnType);
872 output.Write (GetSafeName (declaration.Name));
874 OutputParameters (delegateDecl.Parameters);
875 output.WriteLine (");");
879 protected override void GenerateTypeEnd (CodeTypeDeclaration declaration)
881 if (!IsCurrentDelegate) {
883 Output.WriteLine ("}");
887 protected override void GenerateNamespaceStart (CodeNamespace ns)
889 TextWriter output = Output;
891 string name = ns.Name;
892 if (name != null && name.Length != 0) {
893 output.Write ("namespace ");
894 output.Write (GetSafeName (name));
900 protected override void GenerateNamespaceEnd (CodeNamespace ns)
902 string name = ns.Name;
903 if (name != null && name.Length != 0) {
905 Output.WriteLine ("}");
909 protected override void GenerateNamespaceImport (CodeNamespaceImport import)
911 TextWriter output = Output;
913 output.Write ("using ");
914 output.Write (GetSafeName (import.Namespace));
915 output.WriteLine (';');
918 protected override void GenerateAttributeDeclarationsStart (CodeAttributeDeclarationCollection attributes)
923 protected override void GenerateAttributeDeclarationsEnd (CodeAttributeDeclarationCollection attributes)
928 private void OutputStartBrace ()
930 if (Options.BracingStyle == "C") {
931 Output.WriteLine ("");
932 Output.WriteLine ("{");
934 Output.WriteLine (" {");
938 private void OutputAttributes (CodeAttributeDeclarationCollection attributes, string prefix, bool inline)
940 bool params_set = false;
942 foreach (CodeAttributeDeclaration att in attributes) {
943 if (att.Name == "System.ParamArrayAttribute") {
948 GenerateAttributeDeclarationsStart (attributes);
949 if (prefix != null) {
950 Output.Write (prefix);
952 OutputAttributeDeclaration (att);
953 GenerateAttributeDeclarationsEnd (attributes);
963 Output.Write (prefix);
964 Output.Write ("params");
972 private void OutputAttributeDeclaration (CodeAttributeDeclaration attribute)
974 Output.Write (attribute.Name.Replace ('+', '.'));
976 IEnumerator enumerator = attribute.Arguments.GetEnumerator ();
977 if (enumerator.MoveNext ()) {
978 CodeAttributeArgument argument = (CodeAttributeArgument) enumerator.Current;
979 OutputAttributeArgument (argument);
981 while (enumerator.MoveNext ()) {
983 argument = (CodeAttributeArgument) enumerator.Current;
984 OutputAttributeArgument (argument);
990 protected override void OutputType (CodeTypeReference type)
992 Output.Write (GetTypeOutput (type));
995 private void OutputVTableModifier (MemberAttributes attributes)
997 if ((attributes & MemberAttributes.VTableMask) == MemberAttributes.New) {
998 Output.Write ("new ");
1002 protected override void OutputFieldScopeModifier (MemberAttributes attributes)
1004 switch (attributes & MemberAttributes.ScopeMask) {
1005 case MemberAttributes.Static:
1006 Output.Write ("static ");
1008 case MemberAttributes.Const:
1009 Output.Write ("const ");
1015 // Note: this method should in fact be private as in .NET 2.0, the
1016 // CSharpCodeGenerator no longer derives from CodeGenerator but we
1017 // still need to make this change.
1018 protected override void OutputMemberAccessModifier (MemberAttributes attributes)
1020 switch (attributes & MemberAttributes.AccessMask) {
1021 case MemberAttributes.Assembly:
1022 case MemberAttributes.FamilyAndAssembly:
1023 Output.Write ("internal ");
1025 case MemberAttributes.Family:
1026 Output.Write ("protected ");
1028 case MemberAttributes.FamilyOrAssembly:
1029 Output.Write ("protected internal ");
1031 case MemberAttributes.Private:
1032 Output.Write ("private ");
1034 case MemberAttributes.Public:
1035 Output.Write ("public ");
1040 // Note: this method should in fact be private as in .NET 2.0, the
1041 // CSharpCodeGenerator no longer derives from CodeGenerator but we
1042 // still need to make this change.
1043 protected override void OutputMemberScopeModifier (MemberAttributes attributes)
1045 switch (attributes & MemberAttributes.ScopeMask) {
1046 case MemberAttributes.Abstract:
1047 Output.Write ("abstract ");
1049 case MemberAttributes.Final:
1052 case MemberAttributes.Static:
1053 Output.Write ("static ");
1055 case MemberAttributes.Override:
1056 Output.Write ("override ");
1059 MemberAttributes access = attributes & MemberAttributes.AccessMask;
1060 if (access == MemberAttributes.Assembly || access == MemberAttributes.Family || access == MemberAttributes.Public) {
1061 Output.Write ("virtual ");
1067 private void OutputTypeAttributes (CodeTypeDeclaration declaration)
1069 TextWriter output = Output;
1070 TypeAttributes attributes = declaration.TypeAttributes;
1072 switch (attributes & TypeAttributes.VisibilityMask) {
1073 case TypeAttributes.Public:
1074 case TypeAttributes.NestedPublic:
1075 output.Write ("public ");
1077 case TypeAttributes.NestedPrivate:
1078 output.Write ("private ");
1080 case TypeAttributes.NotPublic:
1081 case TypeAttributes.NestedFamANDAssem:
1082 case TypeAttributes.NestedAssembly:
1083 output.Write ("internal ");
1085 case TypeAttributes.NestedFamily:
1086 output.Write ("protected ");
1088 case TypeAttributes.NestedFamORAssem:
1089 output.Write ("protected internal ");
1093 if ((declaration.Attributes & MemberAttributes.New) != 0)
1094 output.Write ("new ");
1096 if (declaration.IsStruct) {
1097 if (declaration.IsPartial) {
1098 output.Write ("partial ");
1100 output.Write ("struct ");
1101 } else if (declaration.IsEnum) {
1102 output.Write ("enum ");
1104 if ((attributes & TypeAttributes.Interface) != 0) {
1105 if (declaration.IsPartial) {
1106 output.Write ("partial ");
1108 output.Write ("interface ");
1110 if ((attributes & TypeAttributes.Sealed) != 0)
1111 output.Write ("sealed ");
1112 if ((attributes & TypeAttributes.Abstract) != 0)
1113 output.Write ("abstract ");
1114 if (declaration.IsPartial) {
1115 output.Write ("partial ");
1117 output.Write ("class ");
1122 [MonoTODO ("Implement missing special characters")]
1123 protected override string QuoteSnippetString (string value)
1125 // FIXME: this is weird, but works.
1126 string output = value.Replace ("\\", "\\\\");
1127 output = output.Replace ("\"", "\\\"");
1128 output = output.Replace ("\t", "\\t");
1129 output = output.Replace ("\r", "\\r");
1130 output = output.Replace ("\n", "\\n");
1132 return "\"" + output + "\"";
1135 protected override void GeneratePrimitiveExpression(CodePrimitiveExpression e)
1137 if (e.Value is char) {
1138 this.GenerateCharValue ((char) e.Value);
1139 } else if (e.Value is ushort) {
1140 ushort uc = (ushort) e.Value;
1141 Output.Write (uc.ToString(CultureInfo.InvariantCulture));
1142 } else if (e.Value is uint) {
1143 uint ui = (uint) e.Value;
1144 Output.Write (ui.ToString(CultureInfo.InvariantCulture));
1146 } else if (e.Value is ulong) {
1147 ulong ul = (ulong) e.Value;
1148 Output.Write (ul.ToString(CultureInfo.InvariantCulture));
1149 Output.Write ("ul");
1150 } else if (e.Value is sbyte) {
1151 sbyte sb = (sbyte) e.Value;
1152 Output.Write (sb.ToString(CultureInfo.InvariantCulture));
1154 base.GeneratePrimitiveExpression (e);
1158 private void GenerateCharValue (char c)
1160 Output.Write ('\'');
1164 Output.Write ("\\0");
1167 Output.Write ("\\t");
1170 Output.Write ("\\n");
1173 Output.Write ("\\r");
1176 Output.Write ("\\\"");
1179 Output.Write ("\\'");
1182 Output.Write ("\\\\");
1185 Output.Write ("\\u");
1186 Output.Write (((int) c).ToString ("X4", CultureInfo.InvariantCulture));
1189 Output.Write ("\\u");
1190 Output.Write (((int) c).ToString ("X4", CultureInfo.InvariantCulture));
1197 Output.Write ('\'');
1200 protected override void GenerateSingleFloatValue (float f)
1202 base.GenerateSingleFloatValue (f);
1203 base.Output.Write ('F');
1206 protected override void GenerateDecimalValue (decimal d)
1208 base.GenerateDecimalValue (d);
1209 base.Output.Write ('m');
1212 protected override void GenerateParameterDeclarationExpression (CodeParameterDeclarationExpression e)
1214 OutputAttributes (e.CustomAttributes, null, true);
1215 OutputDirection (e.Direction);
1216 OutputType (e.Type);
1218 Output.Write (GetSafeName (e.Name));
1221 protected override void GenerateTypeOfExpression (CodeTypeOfExpression e)
1223 Output.Write ("typeof(");
1224 OutputType (e.Type);
1232 protected override string CreateEscapedIdentifier (string value)
1235 throw new NullReferenceException ("Argument identifier is null.");
1236 return GetSafeName (value);
1239 protected override string CreateValidIdentifier (string value)
1242 throw new NullReferenceException ();
1244 if (keywordsTable == null)
1245 FillKeywordTable ();
1247 if (keywordsTable.Contains (value))
1253 protected override string GetTypeOutput (CodeTypeReference type)
1255 if ((type.Options & CodeTypeReferenceOptions.GenericTypeParameter) != 0)
1256 return type.BaseType;
1258 string typeOutput = null;
1260 if (type.ArrayElementType != null) {
1261 typeOutput = GetTypeOutput (type.ArrayElementType);
1263 typeOutput = DetermineTypeOutput (type);
1266 int rank = type.ArrayRank;
1269 for (--rank; rank > 0; --rank) {
1278 private string DetermineTypeOutput (CodeTypeReference type)
1280 string typeOutput = null;
1281 string baseType = type.BaseType;
1283 switch (baseType.ToLower (System.Globalization.CultureInfo.InvariantCulture)) {
1284 case "system.int32":
1287 case "system.int64":
1288 typeOutput = "long";
1290 case "system.int16":
1291 typeOutput = "short";
1293 case "system.boolean":
1294 typeOutput = "bool";
1297 typeOutput = "char";
1299 case "system.string":
1300 typeOutput = "string";
1302 case "system.object":
1303 typeOutput = "object";
1306 typeOutput = "void";
1309 typeOutput = "byte";
1311 case "system.sbyte":
1312 typeOutput = "sbyte";
1314 case "system.decimal":
1315 typeOutput = "decimal";
1317 case "system.double":
1318 typeOutput = "double";
1320 case "system.single":
1321 typeOutput = "float";
1323 case "system.uint16":
1324 typeOutput = "ushort";
1326 case "system.uint32":
1327 typeOutput = "uint";
1329 case "system.uint64":
1330 typeOutput = "ulong";
1333 StringBuilder sb = new StringBuilder (baseType.Length);
1334 if ((type.Options & CodeTypeReferenceOptions.GlobalReference) != 0) {
1335 sb.Append ("global::");
1338 int lastProcessedChar = 0;
1339 for (int i = 0; i < baseType.Length; i++) {
1340 char currentChar = baseType[i];
1341 if (currentChar != '+' && currentChar != '.') {
1342 if (currentChar == '`') {
1343 sb.Append (CreateEscapedIdentifier (baseType.Substring (
1344 lastProcessedChar, i - lastProcessedChar)));
1347 // determine number of type arguments to output
1349 while (end < baseType.Length && Char.IsDigit (baseType [end]))
1351 int typeArgCount = Int32.Parse (baseType.Substring (i, end - i));
1352 // output type arguments
1353 OutputTypeArguments (type.TypeArguments, sb, typeArgCount);
1354 // skip type argument indicator
1356 // if next character is . or +, then append .
1357 if ((i < baseType.Length) && ((baseType[i] == '+') || (baseType[i] == '.'))) {
1359 // skip character that we just processed
1362 // save postion of last processed character
1363 lastProcessedChar = i;
1366 sb.Append (CreateEscapedIdentifier (baseType.Substring (
1367 lastProcessedChar, i - lastProcessedChar)));
1371 // save postion of last processed character
1372 lastProcessedChar = i;
1376 // add characters that have not yet been processed
1377 if (lastProcessedChar < baseType.Length) {
1378 sb.Append (CreateEscapedIdentifier (baseType.Substring (lastProcessedChar)));
1381 typeOutput = sb.ToString ();
1387 static bool is_identifier_start_character (char c)
1389 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == '@' || Char.IsLetter (c);
1392 static bool is_identifier_part_character (char c)
1394 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= '0' && c <= '9') || Char.IsLetter (c);
1397 protected override bool IsValidIdentifier (string identifier)
1399 if (identifier == null || identifier.Length == 0)
1402 if (keywordsTable == null)
1403 FillKeywordTable ();
1405 if (keywordsTable.Contains (identifier))
1408 if (!is_identifier_start_character (identifier [0]))
1411 for (int i = 1; i < identifier.Length; i ++)
1412 if (! is_identifier_part_character (identifier [i]))
1418 protected override bool Supports (GeneratorSupport supports)
1423 protected override void GenerateDirectives (CodeDirectiveCollection directives)
1425 foreach (CodeDirective d in directives) {
1426 if (d is CodeChecksumPragma) {
1427 GenerateCodeChecksumPragma ((CodeChecksumPragma)d);
1430 if (d is CodeRegionDirective) {
1431 GenerateCodeRegionDirective ((CodeRegionDirective)d);
1434 throw new NotImplementedException ("Unknown CodeDirective");
1438 void GenerateCodeChecksumPragma (CodeChecksumPragma pragma)
1440 Output.Write ("#pragma checksum ");
1441 Output.Write (QuoteSnippetString (pragma.FileName));
1442 Output.Write (" \"");
1443 Output.Write (pragma.ChecksumAlgorithmId.ToString ("B"));
1444 Output.Write ("\" \"");
1445 if (pragma.ChecksumData != null) {
1446 foreach (byte b in pragma.ChecksumData) {
1447 Output.Write (b.ToString ("X2"));
1450 Output.WriteLine ("\"");
1453 void GenerateCodeRegionDirective (CodeRegionDirective region)
1455 switch (region.RegionMode) {
1456 case CodeRegionMode.Start:
1457 Output.Write ("#region ");
1458 Output.WriteLine (region.RegionText);
1460 case CodeRegionMode.End:
1461 Output.WriteLine ("#endregion");
1466 void GenerateGenericsParameters (CodeTypeParameterCollection parameters)
1468 int count = parameters.Count;
1473 for (int i = 0; i < count - 1; ++i) {
1474 Output.Write (parameters [i].Name);
1475 Output.Write (", ");
1477 Output.Write (parameters [count - 1].Name);
1481 void GenerateGenericsConstraints (CodeTypeParameterCollection parameters)
1483 int count = parameters.Count;
1487 bool indented = false;
1489 for (int i = 0; i < count; i++) {
1490 CodeTypeParameter p = parameters [i];
1491 bool hasConstraints = (p.Constraints.Count != 0);
1492 Output.WriteLine ();
1493 if (!hasConstraints && !p.HasConstructorConstraint)
1501 Output.Write ("where ");
1502 Output.Write (p.Name);
1503 Output.Write (" : ");
1505 for (int j = 0; j < p.Constraints.Count; j++) {
1507 Output.Write (", ");
1508 OutputType (p.Constraints [j]);
1511 if (p.HasConstructorConstraint) {
1513 Output.Write (", ");
1514 Output.Write ("new");
1517 Output.Write ("()");
1525 string GetTypeArguments (CodeTypeReferenceCollection collection)
1527 StringBuilder sb = new StringBuilder (" <");
1528 foreach (CodeTypeReference r in collection) {
1529 sb.Append (GetTypeOutput (r));
1533 sb [sb.Length - 1] = '>';
1534 return sb.ToString ();
1537 private void OutputTypeArguments (CodeTypeReferenceCollection typeArguments, StringBuilder sb, int count)
1541 } else if (typeArguments.Count == 0) {
1542 // generic type definition
1549 // write first type argument
1550 sb.Append (GetTypeOutput (typeArguments[0]));
1551 // subsequent type argument are prefixed by ', ' separator
1552 for (int i = 1; i < count; i++) {
1554 sb.Append (GetTypeOutput (typeArguments[i]));
1562 public override void ValidateIdentifier (string identifier)
1567 private string GetSafeName (string id)
1569 if (keywordsTable == null) {
1570 FillKeywordTable ();
1572 if (keywordsTable.Contains (id)) {
1579 static void FillKeywordTable ()
1581 keywordsTable = new Hashtable ();
1582 foreach (string keyword in keywords) {
1583 keywordsTable.Add (keyword, keyword);
1587 private static Hashtable keywordsTable;
1588 private static string[] keywords = new string[] {
1589 "abstract","event","new","struct","as","explicit","null","switch","base","extern",
1590 "this","false","operator","throw","break","finally","out","true",
1591 "fixed","override","try","case","params","typeof","catch","for",
1592 "private","foreach","protected","checked","goto","public",
1593 "unchecked","class","if","readonly","unsafe","const","implicit","ref",
1594 "continue","in","return","using","virtual","default",
1595 "interface","sealed","volatile","delegate","internal","do","is",
1596 "sizeof","while","lock","stackalloc","else","static","enum",
1598 "object","bool","byte","float","uint","char","ulong","ushort",
1599 "decimal","int","sbyte","short","double","long","string","void",
1600 "partial", "yield", "where"