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;
43 internal class CSharpCodeGenerator
46 // It is used for beautiful "for" syntax
47 bool dont_write_semicolon;
52 public CSharpCodeGenerator()
54 dont_write_semicolon = false;
60 protected override string NullToken {
70 protected override void GenerateArrayCreateExpression (CodeArrayCreateExpression expression)
73 // This tries to replicate MS behavior as good as
76 // The Code-Array stuff in ms.net seems to be broken
77 // anyways, or I'm too stupid to understand it.
79 // I'm sick of it. If you try to develop array
80 // creations, test them on windows. If it works there
81 // but not in mono, drop me a note. I'd be especially
82 // interested in jagged-multidimensional combinations
83 // with proper initialization :}
86 TextWriter output = Output;
88 output.Write ("new ");
90 CodeExpressionCollection initializers = expression.Initializers;
91 CodeTypeReference createType = expression.CreateType;
93 if (initializers.Count > 0) {
95 OutputType (createType);
97 if (expression.CreateType.ArrayRank == 0) {
103 OutputExpressionList (initializers, true);
107 CodeTypeReference arrayType = createType.ArrayElementType;
108 while (arrayType != null) {
109 createType = arrayType;
110 arrayType = arrayType.ArrayElementType;
113 OutputType (createType);
117 CodeExpression size = expression.SizeExpression;
119 GenerateExpression (size);
121 output.Write (expression.Size);
127 protected override void GenerateBaseReferenceExpression (CodeBaseReferenceExpression expression)
129 Output.Write ("base");
132 protected override void GenerateCastExpression (CodeCastExpression expression)
134 TextWriter output = Output;
136 OutputType (expression.TargetType);
138 GenerateExpression (expression.Expression);
143 protected override void GenerateCompileUnitStart (CodeCompileUnit compileUnit)
145 GenerateComment (new CodeComment ("------------------------------------------------------------------------------"));
146 GenerateComment (new CodeComment (" <autogenerated>"));
147 GenerateComment (new CodeComment (" This code was generated by a tool."));
148 GenerateComment (new CodeComment (" Mono Runtime Version: " + System.Environment.Version));
149 GenerateComment (new CodeComment (""));
150 GenerateComment (new CodeComment (" Changes to this file may cause incorrect behavior and will be lost if "));
151 GenerateComment (new CodeComment (" the code is regenerated."));
152 GenerateComment (new CodeComment (" </autogenerated>"));
153 GenerateComment (new CodeComment ("------------------------------------------------------------------------------"));
155 base.GenerateCompileUnitStart (compileUnit);
158 protected override void GenerateCompileUnit (CodeCompileUnit compileUnit)
160 GenerateCompileUnitStart (compileUnit);
162 if (compileUnit.AssemblyCustomAttributes.Count > 0) {
163 OutputAttributes (compileUnit.AssemblyCustomAttributes,
164 "assembly: ", false);
165 Output.WriteLine ("");
168 foreach (CodeNamespace ns in compileUnit.Namespaces)
169 GenerateNamespace (ns);
171 GenerateCompileUnitEnd (compileUnit);
174 protected override void GenerateDelegateCreateExpression (CodeDelegateCreateExpression expression)
176 TextWriter output = Output;
178 output.Write ("new ");
179 OutputType (expression.DelegateType);
182 CodeExpression targetObject = expression.TargetObject;
183 if (targetObject != null) {
184 GenerateExpression (targetObject);
187 output.Write (GetSafeName (expression.MethodName));
192 protected override void GenerateFieldReferenceExpression (CodeFieldReferenceExpression expression)
194 CodeExpression targetObject = expression.TargetObject;
195 if (targetObject != null) {
196 GenerateExpression (targetObject);
199 Output.Write (GetSafeName (expression.FieldName));
202 protected override void GenerateArgumentReferenceExpression (CodeArgumentReferenceExpression expression)
204 Output.Write (GetSafeName (expression.ParameterName));
207 protected override void GenerateVariableReferenceExpression (CodeVariableReferenceExpression expression)
209 Output.Write (GetSafeName (expression.VariableName));
212 protected override void GenerateIndexerExpression (CodeIndexerExpression expression)
214 TextWriter output = Output;
216 GenerateExpression (expression.TargetObject);
218 OutputExpressionList (expression.Indices);
222 protected override void GenerateArrayIndexerExpression (CodeArrayIndexerExpression expression)
224 TextWriter output = Output;
226 GenerateExpression (expression.TargetObject);
228 OutputExpressionList (expression.Indices);
232 protected override void GenerateSnippetExpression (CodeSnippetExpression expression)
234 Output.Write (expression.Value);
237 protected override void GenerateMethodInvokeExpression (CodeMethodInvokeExpression expression)
239 TextWriter output = Output;
241 GenerateMethodReferenceExpression (expression.Method);
244 OutputExpressionList (expression.Parameters);
248 protected override void GenerateMethodReferenceExpression (CodeMethodReferenceExpression expression)
250 if (expression.TargetObject != null)
252 GenerateExpression (expression.TargetObject);
255 Output.Write (GetSafeName (expression.MethodName));
257 if (expression.TypeArguments.Count > 0)
258 Output.Write (GetTypeArguments (expression.TypeArguments));
262 protected override void GenerateEventReferenceExpression (CodeEventReferenceExpression expression)
264 GenerateExpression (expression.TargetObject);
266 Output.Write (GetSafeName (expression.EventName));
269 protected override void GenerateDelegateInvokeExpression (CodeDelegateInvokeExpression expression)
271 GenerateExpression (expression.TargetObject);
273 OutputExpressionList (expression.Parameters);
277 protected override void GenerateObjectCreateExpression (CodeObjectCreateExpression expression)
279 Output.Write ("new ");
280 OutputType (expression.CreateType);
282 OutputExpressionList (expression.Parameters);
286 protected override void GeneratePropertyReferenceExpression (CodePropertyReferenceExpression expression)
288 CodeExpression targetObject = expression.TargetObject;
289 if (targetObject != null) {
290 GenerateExpression (targetObject);
293 Output.Write (GetSafeName (expression.PropertyName ));
296 protected override void GeneratePropertySetValueReferenceExpression (CodePropertySetValueReferenceExpression expression)
298 Output.Write ("value");
301 protected override void GenerateThisReferenceExpression (CodeThisReferenceExpression expression)
303 Output.Write ("this");
306 protected override void GenerateExpressionStatement (CodeExpressionStatement statement)
308 GenerateExpression (statement.Expression);
309 if (dont_write_semicolon)
311 Output.WriteLine(';');
314 protected override void GenerateIterationStatement (CodeIterationStatement statement)
316 TextWriter output = Output;
318 dont_write_semicolon = true;
319 output.Write ("for (");
320 GenerateStatement (statement.InitStatement);
322 GenerateExpression (statement.TestExpression);
324 GenerateStatement (statement.IncrementStatement);
326 dont_write_semicolon = false;
329 GenerateStatements (statement.Statements);
331 output.WriteLine ('}');
334 protected override void GenerateThrowExceptionStatement (CodeThrowExceptionStatement statement)
336 Output.Write ("throw");
337 if (statement.ToThrow != null) {
339 GenerateExpression (statement.ToThrow);
341 Output.WriteLine (";");
344 protected override void GenerateComment (CodeComment comment)
346 TextWriter output = Output;
347 string[] lines = comment.Text.Split ('\n');
349 foreach (string line in lines){
350 if (comment.DocComment)
351 output.Write ("///");
358 output.WriteLine (line);
362 protected override void GenerateMethodReturnStatement (CodeMethodReturnStatement statement)
364 TextWriter output = Output;
366 if (statement.Expression != null) {
367 output.Write ("return ");
368 GenerateExpression (statement.Expression);
369 output.WriteLine (";");
371 output.WriteLine ("return;");
375 protected override void GenerateConditionStatement (CodeConditionStatement statement)
377 TextWriter output = Output;
378 output.Write ("if (");
379 GenerateExpression (statement.Condition);
384 GenerateStatements (statement.TrueStatements);
387 CodeStatementCollection falses = statement.FalseStatements;
388 if (falses.Count > 0) {
390 if (Options.ElseOnClosing)
394 output.WriteLine ("else");
397 GenerateStatements (falses);
400 output.WriteLine ('}');
403 protected override void GenerateTryCatchFinallyStatement (CodeTryCatchFinallyStatement statement)
405 TextWriter output = Output;
406 CodeGeneratorOptions options = Options;
408 output.WriteLine ("try");
411 GenerateStatements (statement.TryStatements);
415 foreach (CodeCatchClause clause in statement.CatchClauses) {
416 if (options.ElseOnClosing)
420 output.Write ("catch (");
421 OutputTypeNamePair (clause.CatchExceptionType, GetSafeName(clause.LocalName));
422 output.WriteLine (")");
425 GenerateStatements (clause.Statements);
430 CodeStatementCollection finallies = statement.FinallyStatements;
431 if (finallies.Count > 0) {
432 if (options.ElseOnClosing)
436 output.WriteLine ("finally");
439 GenerateStatements (finallies);
441 output.WriteLine ('}');
447 protected override void GenerateAssignStatement (CodeAssignStatement statement)
449 TextWriter output = Output;
450 GenerateExpression (statement.Left);
451 output.Write (" = ");
452 GenerateExpression (statement.Right);
453 if (dont_write_semicolon)
455 output.WriteLine (';');
458 protected override void GenerateAttachEventStatement (CodeAttachEventStatement statement)
460 TextWriter output = Output;
462 GenerateEventReferenceExpression (statement.Event);
463 output.Write (" += ");
464 GenerateExpression (statement.Listener);
465 output.WriteLine (';');
468 protected override void GenerateRemoveEventStatement (CodeRemoveEventStatement statement)
470 TextWriter output = Output;
471 GenerateEventReferenceExpression (statement.Event);
472 Output.Write (" -= ");
473 GenerateExpression (statement.Listener);
474 output.WriteLine (';');
477 protected override void GenerateGotoStatement (CodeGotoStatement statement)
479 TextWriter output = Output;
481 output.Write ("goto ");
482 output.Write (GetSafeName (statement.Label));
486 protected override void GenerateLabeledStatement (CodeLabeledStatement statement)
488 Output.Write (String.Concat (GetSafeName (statement.Label), ": "));
490 if (statement.Statement != null)
491 GenerateStatement (statement.Statement);
494 protected override void GenerateVariableDeclarationStatement (CodeVariableDeclarationStatement statement)
496 TextWriter output = Output;
498 OutputTypeNamePair (statement.Type, GetSafeName (statement.Name));
500 CodeExpression initExpression = statement.InitExpression;
501 if (initExpression != null) {
502 output.Write (" = ");
503 GenerateExpression (initExpression);
506 output.WriteLine (';');
509 protected override void GenerateLinePragmaStart (CodeLinePragma linePragma)
512 Output.Write ("#line ");
513 Output.Write (linePragma.LineNumber);
514 Output.Write (" \"");
515 Output.Write (linePragma.FileName);
520 protected override void GenerateLinePragmaEnd (CodeLinePragma linePragma)
523 Output.WriteLine ("#line default");
526 protected override void GenerateEvent (CodeMemberEvent eventRef, CodeTypeDeclaration declaration)
528 if (IsCurrentDelegate || IsCurrentEnum) {
532 OutputAttributes (eventRef.CustomAttributes, null, false);
534 if (eventRef.PrivateImplementationType == null) {
535 OutputMemberAccessModifier (eventRef.Attributes);
538 Output.Write ("event ");
540 if (eventRef.PrivateImplementationType != null) {
541 OutputTypeNamePair (eventRef.Type,
542 eventRef.PrivateImplementationType.BaseType + "." +
545 OutputTypeNamePair (eventRef.Type, GetSafeName (eventRef.Name));
547 Output.WriteLine (';');
550 protected override void GenerateField (CodeMemberField field)
552 if (IsCurrentDelegate || IsCurrentInterface) {
556 TextWriter output = Output;
558 OutputAttributes (field.CustomAttributes, null, false);
561 Output.Write (GetSafeName (field.Name));
563 MemberAttributes attributes = field.Attributes;
564 OutputMemberAccessModifier (attributes);
565 OutputVTableModifier (attributes);
566 OutputFieldScopeModifier (attributes);
568 OutputTypeNamePair (field.Type, GetSafeName (field.Name));
571 CodeExpression initExpression = field.InitExpression;
572 if (initExpression != null) {
573 output.Write (" = ");
574 GenerateExpression (initExpression);
578 output.WriteLine (',');
580 output.WriteLine (';');
583 protected override void GenerateSnippetMember (CodeSnippetTypeMember member)
585 Output.Write (member.Text);
588 protected override void GenerateEntryPointMethod (CodeEntryPointMethod method,
589 CodeTypeDeclaration declaration)
592 OutputAttributes (method.CustomAttributes, null, false);
595 Output.Write ("public static ");
597 OutputType (method.ReturnType);
599 Output.Write ("void");
601 Output.Write (" Main()");
604 GenerateStatements (method.Statements);
606 Output.WriteLine ("}");
609 protected override void GenerateMethod (CodeMemberMethod method,
610 CodeTypeDeclaration declaration)
612 if (IsCurrentDelegate || IsCurrentEnum) {
616 TextWriter output = Output;
618 OutputAttributes (method.CustomAttributes, null, false);
620 OutputAttributes (method.ReturnTypeCustomAttributes,
623 MemberAttributes attributes = method.Attributes;
625 if (!IsCurrentInterface) {
626 if (method.PrivateImplementationType == null) {
627 OutputMemberAccessModifier (attributes);
628 OutputVTableModifier (attributes);
629 OutputMemberScopeModifier (attributes);
632 OutputVTableModifier (attributes);
635 OutputType (method.ReturnType);
638 CodeTypeReference privateType = method.PrivateImplementationType;
639 if (privateType != null) {
640 output.Write (privateType.BaseType);
643 output.Write (GetSafeName (method.Name));
646 GenerateGenericsParameters (method.TypeParameters);
650 OutputParameters (method.Parameters);
654 GenerateGenericsConstraints (method.TypeParameters);
657 if ((attributes & MemberAttributes.ScopeMask) == MemberAttributes.Abstract || declaration.IsInterface)
658 output.WriteLine (';');
662 GenerateStatements (method.Statements);
664 output.WriteLine ('}');
668 protected override void GenerateProperty (CodeMemberProperty property,
669 CodeTypeDeclaration declaration)
671 if (IsCurrentDelegate || IsCurrentEnum) {
675 TextWriter output = Output;
677 OutputAttributes (property.CustomAttributes, null, false);
679 MemberAttributes attributes = property.Attributes;
681 if (!IsCurrentInterface) {
682 if (property.PrivateImplementationType == null) {
683 OutputMemberAccessModifier (attributes);
684 OutputVTableModifier (attributes);
685 OutputMemberScopeModifier (attributes);
688 OutputVTableModifier (attributes);
691 OutputType (property.Type);
694 if (!IsCurrentInterface && property.PrivateImplementationType != null) {
695 output.Write (property.PrivateImplementationType.BaseType);
699 // only consider property indexer if name is Item (case-insensitive
700 // comparison) AND property has parameters
701 if (string.Compare(property.Name, "Item", true, CultureInfo.InvariantCulture) == 0 && property.Parameters.Count > 0) {
702 output.Write ("this[");
703 OutputParameters(property.Parameters);
706 output.Write (property.Name);
711 if (declaration.IsInterface)
713 if (property.HasGet) output.WriteLine("get;");
714 if (property.HasSet) output.WriteLine("set;");
720 output.Write ("get");
724 GenerateStatements (property.GetStatements);
727 output.WriteLine ('}');
732 output.Write ("set");
736 GenerateStatements (property.SetStatements);
739 output.WriteLine ('}');
744 output.WriteLine ('}');
747 protected override void GenerateConstructor (CodeConstructor constructor, CodeTypeDeclaration declaration)
749 if (IsCurrentDelegate || IsCurrentEnum || IsCurrentInterface) {
753 OutputAttributes (constructor.CustomAttributes, null, false);
755 OutputMemberAccessModifier (constructor.Attributes);
756 Output.Write (GetSafeName (CurrentTypeName) + "(");
757 OutputParameters (constructor.Parameters);
759 if (constructor.BaseConstructorArgs.Count > 0) {
760 Output.WriteLine (" : ");
762 Output.Write ("base(");
763 OutputExpressionList (constructor.BaseConstructorArgs);
767 if (constructor.ChainedConstructorArgs.Count > 0) {
768 Output.WriteLine (" : ");
770 Output.Write("this(");
771 OutputExpressionList (constructor.ChainedConstructorArgs);
777 GenerateStatements (constructor.Statements);
779 Output.WriteLine ('}');
782 protected override void GenerateTypeConstructor (CodeTypeConstructor constructor)
784 if (IsCurrentDelegate || IsCurrentEnum || IsCurrentInterface) {
789 OutputAttributes (constructor.CustomAttributes, null, false);
792 Output.Write ("static " + GetSafeName (CurrentTypeName) + "()");
795 GenerateStatements (constructor.Statements);
797 Output.WriteLine ('}');
800 protected override void GenerateTypeStart(CodeTypeDeclaration declaration)
802 TextWriter output = Output;
804 OutputAttributes (declaration.CustomAttributes, null, false);
806 if (!IsCurrentDelegate) {
807 OutputTypeAttributes (declaration);
809 output.Write (GetSafeName (declaration.Name));
812 GenerateGenericsParameters (declaration.TypeParameters);
815 IEnumerator enumerator = declaration.BaseTypes.GetEnumerator ();
816 if (enumerator.MoveNext ()) {
817 CodeTypeReference type = (CodeTypeReference) enumerator.Current;
819 output.Write (" : ");
822 while (enumerator.MoveNext ()) {
823 type = (CodeTypeReference) enumerator.Current;
831 GenerateGenericsConstraints (declaration.TypeParameters);
836 if ((declaration.TypeAttributes & TypeAttributes.VisibilityMask) == TypeAttributes.Public) {
837 output.Write ("public ");
840 CodeTypeDelegate delegateDecl = (CodeTypeDelegate) declaration;
841 output.Write ("delegate ");
842 OutputType (delegateDecl.ReturnType);
844 output.Write (GetSafeName (declaration.Name));
846 OutputParameters (delegateDecl.Parameters);
847 output.WriteLine (");");
851 protected override void GenerateTypeEnd (CodeTypeDeclaration declaration)
853 if (!IsCurrentDelegate) {
855 Output.WriteLine ("}");
859 protected override void GenerateNamespaceStart (CodeNamespace ns)
861 TextWriter output = Output;
863 string name = ns.Name;
864 if (name != null && name.Length != 0) {
865 output.Write ("namespace ");
866 output.Write (GetSafeName (name));
872 protected override void GenerateNamespaceEnd (CodeNamespace ns)
874 string name = ns.Name;
875 if (name != null && name.Length != 0) {
877 Output.WriteLine ("}");
881 protected override void GenerateNamespaceImport (CodeNamespaceImport import)
883 TextWriter output = Output;
885 output.Write ("using ");
886 output.Write (GetSafeName (import.Namespace));
887 output.WriteLine (';');
890 protected override void GenerateAttributeDeclarationsStart (CodeAttributeDeclarationCollection attributes)
895 protected override void GenerateAttributeDeclarationsEnd (CodeAttributeDeclarationCollection attributes)
900 private void OutputStartBrace ()
902 if (Options.BracingStyle == "C") {
903 Output.WriteLine ("");
904 Output.WriteLine ("{");
906 Output.WriteLine (" {");
910 private void OutputAttributes (CodeAttributeDeclarationCollection attributes, string prefix, bool inline)
912 foreach (CodeAttributeDeclaration att in attributes) {
913 GenerateAttributeDeclarationsStart (attributes);
914 if (prefix != null) {
915 Output.Write (prefix);
917 OutputAttributeDeclaration (att);
918 GenerateAttributeDeclarationsEnd (attributes);
927 private void OutputAttributeDeclaration (CodeAttributeDeclaration attribute)
929 Output.Write (attribute.Name.Replace ('+', '.'));
931 IEnumerator enumerator = attribute.Arguments.GetEnumerator ();
932 if (enumerator.MoveNext ()) {
933 CodeAttributeArgument argument = (CodeAttributeArgument) enumerator.Current;
934 OutputAttributeArgument (argument);
936 while (enumerator.MoveNext ()) {
938 argument = (CodeAttributeArgument) enumerator.Current;
939 OutputAttributeArgument (argument);
945 protected override void OutputType (CodeTypeReference type)
947 Output.Write (GetTypeOutput (type));
950 private void OutputVTableModifier (MemberAttributes attributes)
952 if ((attributes & MemberAttributes.VTableMask) == MemberAttributes.New) {
953 Output.Write ("new ");
957 protected override void OutputFieldScopeModifier (MemberAttributes attributes)
959 switch (attributes & MemberAttributes.ScopeMask) {
960 case MemberAttributes.Static:
961 Output.Write ("static ");
963 case MemberAttributes.Const:
964 Output.Write ("const ");
971 // Note: this method should in fact be private as in .NET 2.0, the
972 // CSharpCodeGenerator no longer derives from CodeGenerator but we
973 // still need to make this change.
974 protected override void OutputMemberAccessModifier (MemberAttributes attributes)
976 switch (attributes & MemberAttributes.AccessMask) {
977 case MemberAttributes.Assembly:
978 case MemberAttributes.FamilyAndAssembly:
979 Output.Write ("internal ");
981 case MemberAttributes.Family:
982 Output.Write ("protected ");
984 case MemberAttributes.FamilyOrAssembly:
985 Output.Write ("protected internal ");
987 case MemberAttributes.Private:
988 Output.Write ("private ");
990 case MemberAttributes.Public:
991 Output.Write ("public ");
996 // Note: this method should in fact be private as in .NET 2.0, the
997 // CSharpCodeGenerator no longer derives from CodeGenerator but we
998 // still need to make this change.
999 protected override void OutputMemberScopeModifier (MemberAttributes attributes)
1001 switch (attributes & MemberAttributes.ScopeMask) {
1002 case MemberAttributes.Abstract:
1003 Output.Write ("abstract ");
1005 case MemberAttributes.Final:
1008 case MemberAttributes.Static:
1009 Output.Write ("static ");
1011 case MemberAttributes.Override:
1012 Output.Write ("override ");
1015 MemberAttributes access = attributes & MemberAttributes.AccessMask;
1016 if (access == MemberAttributes.Assembly || access == MemberAttributes.Family || access == MemberAttributes.Public) {
1017 Output.Write ("virtual ");
1024 private void OutputTypeAttributes (CodeTypeDeclaration declaration)
1026 TextWriter output = Output;
1027 TypeAttributes attributes = declaration.TypeAttributes;
1029 switch (attributes & TypeAttributes.VisibilityMask) {
1030 case TypeAttributes.Public:
1031 case TypeAttributes.NestedPublic:
1032 output.Write ("public ");
1034 case TypeAttributes.NestedPrivate:
1035 output.Write ("private ");
1038 case TypeAttributes.NotPublic:
1039 case TypeAttributes.NestedFamANDAssem:
1040 case TypeAttributes.NestedAssembly:
1041 output.Write ("internal ");
1043 case TypeAttributes.NestedFamily:
1044 output.Write ("protected ");
1046 case TypeAttributes.NestedFamORAssem:
1047 output.Write ("protected internal ");
1052 if (declaration.IsStruct) {
1054 if (declaration.IsPartial) {
1055 output.Write ("partial ");
1058 output.Write ("struct ");
1059 } else if (declaration.IsEnum) {
1060 output.Write ("enum ");
1062 if ((attributes & TypeAttributes.Interface) != 0) {
1064 if (declaration.IsPartial) {
1065 output.Write ("partial ");
1068 output.Write ("interface ");
1070 if ((attributes & TypeAttributes.Sealed) != 0)
1071 output.Write ("sealed ");
1072 if ((attributes & TypeAttributes.Abstract) != 0)
1073 output.Write ("abstract ");
1075 if (declaration.IsPartial) {
1076 output.Write ("partial ");
1079 output.Write ("class ");
1084 [MonoTODO ("Implement missing special characters")]
1085 protected override string QuoteSnippetString (string value)
1087 // FIXME: this is weird, but works.
1088 string output = value.Replace ("\\", "\\\\");
1089 output = output.Replace ("\"", "\\\"");
1090 output = output.Replace ("\t", "\\t");
1091 output = output.Replace ("\r", "\\r");
1092 output = output.Replace ("\n", "\\n");
1094 return "\"" + output + "\"";
1097 protected override void GenerateParameterDeclarationExpression (CodeParameterDeclarationExpression e)
1099 OutputAttributes (e.CustomAttributes, null, true);
1100 OutputDirection (e.Direction);
1101 OutputType (e.Type);
1103 Output.Write (GetSafeName (e.Name));
1106 protected override void GenerateTypeOfExpression (CodeTypeOfExpression e)
1108 Output.Write ("typeof(");
1109 OutputType (e.Type);
1117 protected override string CreateEscapedIdentifier (string value)
1120 throw new NullReferenceException ("Argument identifier is null.");
1121 return GetSafeName (value);
1124 protected override string CreateValidIdentifier (string value)
1127 throw new NullReferenceException ();
1129 if (keywordsTable == null)
1130 FillKeywordTable ();
1132 if (keywordsTable.Contains (value))
1138 protected override string GetTypeOutput (CodeTypeReference type)
1140 string typeOutput = null;
1142 if (type.ArrayElementType != null) {
1143 typeOutput = GetTypeOutput (type.ArrayElementType);
1145 typeOutput = DetermineTypeOutput (type);
1148 int rank = type.ArrayRank;
1151 for (--rank; rank > 0; --rank) {
1159 private string DetermineTypeOutput (CodeTypeReference type)
1161 string typeOutput = null;
1162 string baseType = type.BaseType;
1164 switch (baseType.ToLower (System.Globalization.CultureInfo.InvariantCulture)) {
1165 case "system.int32":
1168 case "system.int64":
1169 typeOutput = "long";
1171 case "system.int16":
1172 typeOutput = "short";
1174 case "system.boolean":
1175 typeOutput = "bool";
1178 typeOutput = "char";
1180 case "system.string":
1181 typeOutput = "string";
1183 case "system.object":
1184 typeOutput = "object";
1187 typeOutput = "void";
1191 typeOutput = "byte";
1193 case "system.sbyte":
1194 typeOutput = "sbyte";
1196 case "system.decimal":
1197 typeOutput = "decimal";
1199 case "system.double":
1200 typeOutput = "double";
1202 case "system.single":
1203 typeOutput = "float";
1205 case "system.uint16":
1206 typeOutput = "ushort";
1208 case "system.uint32":
1209 typeOutput = "uint";
1211 case "system.uint64":
1212 typeOutput = "ulong";
1217 StringBuilder sb = new StringBuilder (baseType.Length);
1218 if (type.Options == CodeTypeReferenceOptions.GlobalReference) {
1219 sb.Append ("global::");
1222 int lastProcessedChar = 0;
1223 for (int i = 0; i < baseType.Length; i++) {
1224 char currentChar = baseType[i];
1225 if (currentChar != '+' && currentChar != '.') {
1226 if (currentChar == '`') {
1227 sb.Append (CreateEscapedIdentifier (baseType.Substring (
1228 lastProcessedChar, i - lastProcessedChar)));
1231 // determine number of type arguments to output
1232 int typeArgCount = baseType[i] - '0';
1233 // output type arguments
1234 OutputTypeArguments (type.TypeArguments, sb, typeArgCount);
1235 // skip type argument indicator
1237 // if next character is . or +, then append .
1238 if ((i < baseType.Length) && ((baseType[i] == '+') || (baseType[i] == '.'))) {
1240 // skip character that we just processed
1243 // save postion of last processed character
1244 lastProcessedChar = i;
1247 sb.Append (CreateEscapedIdentifier (baseType.Substring (
1248 lastProcessedChar, i - lastProcessedChar)));
1252 // save postion of last processed character
1253 lastProcessedChar = i;
1257 // add characters that have not yet been processed
1258 if (lastProcessedChar < baseType.Length) {
1259 sb.Append (CreateEscapedIdentifier (baseType.Substring (lastProcessedChar)));
1262 typeOutput = sb.ToString ();
1264 typeOutput = GetSafeName (baseType);
1265 typeOutput = typeOutput.Replace ('+', '.');
1272 protected override bool IsValidIdentifier (string identifier)
1274 if (keywordsTable == null)
1275 FillKeywordTable ();
1277 return !keywordsTable.Contains (identifier);
1280 protected override bool Supports (GeneratorSupport supports)
1286 protected override void GenerateDirectives (CodeDirectiveCollection directives)
1288 foreach (CodeDirective d in directives) {
1289 if (d is CodeChecksumPragma) {
1290 GenerateCodeChecksumPragma ((CodeChecksumPragma)d);
1293 if (d is CodeRegionDirective) {
1294 GenerateCodeRegionDirective ((CodeRegionDirective)d);
1297 throw new NotImplementedException ("Unknown CodeDirective");
1301 void GenerateCodeChecksumPragma (CodeChecksumPragma pragma)
1303 Output.Write ("#pragma checksum \"");
1304 Output.Write (pragma.FileName);
1305 Output.Write ("\" \"");
1306 Output.Write (pragma.ChecksumAlgorithmId.ToString ("B"));
1307 Output.Write ("\" \"");
1308 if (pragma.ChecksumData != null) {
1309 foreach (byte b in pragma.ChecksumData) {
1310 Output.Write (b.ToString ("X2"));
1313 Output.WriteLine ("\"");
1316 void GenerateCodeRegionDirective (CodeRegionDirective region)
1318 switch (region.RegionMode) {
1319 case CodeRegionMode.Start:
1320 Output.Write ("#region ");
1321 Output.WriteLine (region.RegionText);
1323 case CodeRegionMode.End:
1324 Output.WriteLine ("#endregion");
1329 void GenerateGenericsParameters (CodeTypeParameterCollection parameters)
1331 int count = parameters.Count;
1336 for (int i = 0; i < count - 1; ++i) {
1337 Output.Write (parameters [i].Name);
1338 Output.Write (", ");
1340 Output.Write (parameters [count - 1].Name);
1344 void GenerateGenericsConstraints (CodeTypeParameterCollection parameters)
1346 int count = parameters.Count;
1351 foreach (CodeTypeParameter p in parameters) {
1352 if (p.Constraints.Count == 0)
1354 Output.WriteLine ();
1355 Output.Write ("where ");
1356 Output.Write (p.Name);
1357 Output.Write (" : ");
1359 bool is_first = true;
1360 foreach (CodeTypeReference r in p.Constraints) {
1364 Output.Write (", ");
1367 if (p.HasConstructorConstraint) {
1369 Output.Write (", ");
1370 Output.Write ("new ()");
1377 string GetTypeArguments (CodeTypeReferenceCollection collection)
1379 StringBuilder sb = new StringBuilder (" <");
1380 foreach (CodeTypeReference r in collection) {
1381 sb.Append (GetTypeOutput (r));
1385 sb [sb.Length - 1] = '>';
1386 return sb.ToString ();
1389 private void OutputTypeArguments (CodeTypeReferenceCollection typeArguments, StringBuilder sb, int count)
1397 // write first type argument
1398 sb.Append (GetTypeOutput (typeArguments[0]));
1399 // subsequent type argument are prefixed by ', ' separator
1400 for (int i = 1; i < count; i++) {
1402 sb.Append (GetTypeOutput (typeArguments[i]));
1411 public override void ValidateIdentifier (string identifier)
1416 private string GetSafeName (string id)
1418 if (keywordsTable == null) {
1419 FillKeywordTable ();
1421 if (keywordsTable.Contains (id)) {
1428 static void FillKeywordTable ()
1430 keywordsTable = new Hashtable ();
1431 foreach (string keyword in keywords) {
1432 keywordsTable.Add (keyword, keyword);
1436 private static Hashtable keywordsTable;
1437 private static string[] keywords = new string[] {
1438 "abstract","event","new","struct","as","explicit","null","switch","base","extern",
1439 "this","false","operator","throw","break","finally","out","true",
1440 "fixed","override","try","case","params","typeof","catch","for",
1441 "private","foreach","protected","checked","goto","public",
1442 "unchecked","class","if","readonly","unsafe","const","implicit","ref",
1443 "continue","in","return","using","virtual","default",
1444 "interface","sealed","volatile","delegate","internal","do","is",
1445 "sizeof","while","lock","stackalloc","else","static","enum",
1447 "object","bool","byte","float","uint","char","ulong","ushort",
1448 "decimal","int","sbyte","short","double","long","string","void",
1450 "partial", "yield", "where"