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;
44 using System.Collections.Generic;
47 internal class CSharpCodeGenerator
51 IDictionary <string, string> providerOptions;
54 // It is used for beautiful "for" syntax
55 bool dont_write_semicolon;
60 public CSharpCodeGenerator()
62 dont_write_semicolon = false;
66 public CSharpCodeGenerator (IDictionary <string, string> providerOptions)
68 this.providerOptions = providerOptions;
71 protected IDictionary <string, string> ProviderOptions {
72 get { return providerOptions; }
79 protected override string NullToken {
89 protected override void GenerateArrayCreateExpression (CodeArrayCreateExpression expression)
92 // This tries to replicate MS behavior as good as
95 // The Code-Array stuff in ms.net seems to be broken
96 // anyways, or I'm too stupid to understand it.
98 // I'm sick of it. If you try to develop array
99 // creations, test them on windows. If it works there
100 // but not in mono, drop me a note. I'd be especially
101 // interested in jagged-multidimensional combinations
102 // with proper initialization :}
105 TextWriter output = Output;
107 output.Write ("new ");
109 CodeExpressionCollection initializers = expression.Initializers;
110 CodeTypeReference createType = expression.CreateType;
112 if (initializers.Count > 0) {
114 OutputType (createType);
116 if (expression.CreateType.ArrayRank == 0) {
122 OutputExpressionList (initializers, true);
126 CodeTypeReference arrayType = createType.ArrayElementType;
127 while (arrayType != null) {
128 createType = arrayType;
129 arrayType = arrayType.ArrayElementType;
132 OutputType (createType);
136 CodeExpression size = expression.SizeExpression;
138 GenerateExpression (size);
140 output.Write (expression.Size);
146 protected override void GenerateBaseReferenceExpression (CodeBaseReferenceExpression expression)
148 Output.Write ("base");
151 protected override void GenerateCastExpression (CodeCastExpression expression)
153 TextWriter output = Output;
155 OutputType (expression.TargetType);
157 GenerateExpression (expression.Expression);
162 protected override void GenerateCompileUnitStart (CodeCompileUnit compileUnit)
164 GenerateComment (new CodeComment ("------------------------------------------------------------------------------"));
165 GenerateComment (new CodeComment (" <autogenerated>"));
166 GenerateComment (new CodeComment (" This code was generated by a tool."));
167 GenerateComment (new CodeComment (" Mono Runtime Version: " + System.Environment.Version));
168 GenerateComment (new CodeComment (""));
169 GenerateComment (new CodeComment (" Changes to this file may cause incorrect behavior and will be lost if "));
170 GenerateComment (new CodeComment (" the code is regenerated."));
171 GenerateComment (new CodeComment (" </autogenerated>"));
172 GenerateComment (new CodeComment ("------------------------------------------------------------------------------"));
174 base.GenerateCompileUnitStart (compileUnit);
177 protected override void GenerateCompileUnit (CodeCompileUnit compileUnit)
179 GenerateCompileUnitStart (compileUnit);
181 if (compileUnit.AssemblyCustomAttributes.Count > 0) {
182 OutputAttributes (compileUnit.AssemblyCustomAttributes,
183 "assembly: ", false);
184 Output.WriteLine ("");
187 foreach (CodeNamespace ns in compileUnit.Namespaces)
188 GenerateNamespace (ns);
190 GenerateCompileUnitEnd (compileUnit);
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));
276 if (expression.TypeArguments.Count > 0)
277 Output.Write (GetTypeArguments (expression.TypeArguments));
281 protected override void GenerateEventReferenceExpression (CodeEventReferenceExpression expression)
283 if (expression.TargetObject != null) {
284 GenerateExpression (expression.TargetObject);
287 Output.Write (GetSafeName (expression.EventName));
290 protected override void GenerateDelegateInvokeExpression (CodeDelegateInvokeExpression expression)
292 if (expression.TargetObject != null)
293 GenerateExpression (expression.TargetObject);
295 OutputExpressionList (expression.Parameters);
299 protected override void GenerateObjectCreateExpression (CodeObjectCreateExpression expression)
301 Output.Write ("new ");
302 OutputType (expression.CreateType);
304 OutputExpressionList (expression.Parameters);
308 protected override void GeneratePropertyReferenceExpression (CodePropertyReferenceExpression expression)
310 CodeExpression targetObject = expression.TargetObject;
311 if (targetObject != null) {
312 GenerateExpression (targetObject);
315 Output.Write (GetSafeName (expression.PropertyName ));
318 protected override void GeneratePropertySetValueReferenceExpression (CodePropertySetValueReferenceExpression expression)
320 Output.Write ("value");
323 protected override void GenerateThisReferenceExpression (CodeThisReferenceExpression expression)
325 Output.Write ("this");
328 protected override void GenerateExpressionStatement (CodeExpressionStatement statement)
330 GenerateExpression (statement.Expression);
331 if (dont_write_semicolon)
333 Output.WriteLine(';');
336 protected override void GenerateIterationStatement (CodeIterationStatement statement)
338 TextWriter output = Output;
340 dont_write_semicolon = true;
341 output.Write ("for (");
342 GenerateStatement (statement.InitStatement);
344 GenerateExpression (statement.TestExpression);
346 GenerateStatement (statement.IncrementStatement);
348 dont_write_semicolon = false;
351 GenerateStatements (statement.Statements);
353 output.WriteLine ('}');
356 protected override void GenerateThrowExceptionStatement (CodeThrowExceptionStatement statement)
358 Output.Write ("throw");
359 if (statement.ToThrow != null) {
361 GenerateExpression (statement.ToThrow);
363 Output.WriteLine (";");
366 protected override void GenerateComment (CodeComment comment)
368 TextWriter output = Output;
370 string commentChars = null;
372 if (comment.DocComment) {
373 commentChars = "///";
378 output.Write (commentChars);
380 string text = comment.Text;
382 for (int i = 0; i < text.Length; i++) {
383 output.Write (text[i]);
384 if (text[i] == '\r') {
385 if (i < (text.Length - 1) && text[i + 1] == '\n') {
388 output.Write (commentChars);
389 } else if (text[i] == '\n') {
390 output.Write (commentChars);
397 protected override void GenerateMethodReturnStatement (CodeMethodReturnStatement statement)
399 TextWriter output = Output;
401 if (statement.Expression != null) {
402 output.Write ("return ");
403 GenerateExpression (statement.Expression);
404 output.WriteLine (";");
406 output.WriteLine ("return;");
410 protected override void GenerateConditionStatement (CodeConditionStatement statement)
412 TextWriter output = Output;
413 output.Write ("if (");
414 GenerateExpression (statement.Condition);
419 GenerateStatements (statement.TrueStatements);
422 CodeStatementCollection falses = statement.FalseStatements;
423 if (falses.Count > 0) {
425 if (Options.ElseOnClosing)
429 output.Write ("else");
432 GenerateStatements (falses);
435 output.WriteLine ('}');
438 protected override void GenerateTryCatchFinallyStatement (CodeTryCatchFinallyStatement statement)
440 TextWriter output = Output;
441 CodeGeneratorOptions options = Options;
443 output.Write ("try");
446 GenerateStatements (statement.TryStatements);
449 foreach (CodeCatchClause clause in statement.CatchClauses) {
451 if (options.ElseOnClosing)
455 output.Write ("catch (");
456 OutputTypeNamePair (clause.CatchExceptionType, GetSafeName(clause.LocalName));
460 GenerateStatements (clause.Statements);
464 CodeStatementCollection finallies = statement.FinallyStatements;
465 if (finallies.Count > 0) {
467 if (options.ElseOnClosing)
471 output.Write ("finally");
474 GenerateStatements (finallies);
478 output.WriteLine('}');
481 protected override void GenerateAssignStatement (CodeAssignStatement statement)
483 TextWriter output = Output;
484 GenerateExpression (statement.Left);
485 output.Write (" = ");
486 GenerateExpression (statement.Right);
487 if (dont_write_semicolon)
489 output.WriteLine (';');
492 protected override void GenerateAttachEventStatement (CodeAttachEventStatement statement)
494 TextWriter output = Output;
496 GenerateEventReferenceExpression (statement.Event);
497 output.Write (" += ");
498 GenerateExpression (statement.Listener);
499 output.WriteLine (';');
502 protected override void GenerateRemoveEventStatement (CodeRemoveEventStatement statement)
504 TextWriter output = Output;
505 GenerateEventReferenceExpression (statement.Event);
506 output.Write (" -= ");
507 GenerateExpression (statement.Listener);
508 output.WriteLine (';');
511 protected override void GenerateGotoStatement (CodeGotoStatement statement)
513 TextWriter output = Output;
515 output.Write ("goto ");
516 output.Write (GetSafeName (statement.Label));
517 output.WriteLine (";");
520 protected override void GenerateLabeledStatement (CodeLabeledStatement statement)
523 Output.Write (statement.Label);
524 Output.WriteLine (":");
527 if (statement.Statement != null) {
528 GenerateStatement (statement.Statement);
532 protected override void GenerateVariableDeclarationStatement (CodeVariableDeclarationStatement statement)
534 TextWriter output = Output;
536 OutputTypeNamePair (statement.Type, GetSafeName (statement.Name));
538 CodeExpression initExpression = statement.InitExpression;
539 if (initExpression != null) {
540 output.Write (" = ");
541 GenerateExpression (initExpression);
544 if (!dont_write_semicolon) {
545 output.WriteLine (';');
549 protected override void GenerateLinePragmaStart (CodeLinePragma linePragma)
552 Output.Write ("#line ");
553 Output.Write (linePragma.LineNumber);
554 Output.Write (" \"");
555 Output.Write (linePragma.FileName);
560 protected override void GenerateLinePragmaEnd (CodeLinePragma linePragma)
563 Output.WriteLine ("#line default");
565 Output.WriteLine ("#line hidden");
569 protected override void GenerateEvent (CodeMemberEvent eventRef, CodeTypeDeclaration declaration)
571 if (IsCurrentDelegate || IsCurrentEnum) {
575 OutputAttributes (eventRef.CustomAttributes, null, false);
577 if (eventRef.PrivateImplementationType == null) {
578 OutputMemberAccessModifier (eventRef.Attributes);
581 Output.Write ("event ");
583 if (eventRef.PrivateImplementationType != null) {
584 OutputTypeNamePair (eventRef.Type,
585 eventRef.PrivateImplementationType.BaseType + "." +
588 OutputTypeNamePair (eventRef.Type, GetSafeName (eventRef.Name));
590 Output.WriteLine (';');
593 protected override void GenerateField (CodeMemberField field)
595 if (IsCurrentDelegate || IsCurrentInterface) {
599 TextWriter output = Output;
601 OutputAttributes (field.CustomAttributes, null, false);
604 Output.Write (GetSafeName (field.Name));
606 MemberAttributes attributes = field.Attributes;
607 OutputMemberAccessModifier (attributes);
608 OutputVTableModifier (attributes);
609 OutputFieldScopeModifier (attributes);
611 OutputTypeNamePair (field.Type, GetSafeName (field.Name));
614 CodeExpression initExpression = field.InitExpression;
615 if (initExpression != null) {
616 output.Write (" = ");
617 GenerateExpression (initExpression);
621 output.WriteLine (',');
623 output.WriteLine (';');
626 protected override void GenerateSnippetMember (CodeSnippetTypeMember member)
628 Output.Write (member.Text);
631 protected override void GenerateEntryPointMethod (CodeEntryPointMethod method,
632 CodeTypeDeclaration declaration)
635 OutputAttributes (method.CustomAttributes, null, false);
638 Output.Write ("public static ");
640 OutputType (method.ReturnType);
642 Output.Write ("void");
644 Output.Write (" Main()");
647 GenerateStatements (method.Statements);
649 Output.WriteLine ("}");
652 protected override void GenerateMethod (CodeMemberMethod method,
653 CodeTypeDeclaration declaration)
655 if (IsCurrentDelegate || IsCurrentEnum) {
659 TextWriter output = Output;
661 OutputAttributes (method.CustomAttributes, null, false);
663 OutputAttributes (method.ReturnTypeCustomAttributes,
666 MemberAttributes attributes = method.Attributes;
668 if (!IsCurrentInterface) {
669 if (method.PrivateImplementationType == null) {
670 OutputMemberAccessModifier (attributes);
671 OutputVTableModifier (attributes);
672 OutputMemberScopeModifier (attributes);
675 OutputVTableModifier (attributes);
678 OutputType (method.ReturnType);
681 CodeTypeReference privateType = method.PrivateImplementationType;
682 if (privateType != null) {
683 output.Write (privateType.BaseType);
686 output.Write (GetSafeName (method.Name));
689 GenerateGenericsParameters (method.TypeParameters);
693 OutputParameters (method.Parameters);
697 GenerateGenericsConstraints (method.TypeParameters);
700 if (IsAbstract (attributes) || declaration.IsInterface)
701 output.WriteLine (';');
705 GenerateStatements (method.Statements);
707 output.WriteLine ('}');
711 static bool IsAbstract (MemberAttributes attributes)
713 return (attributes & MemberAttributes.ScopeMask) == MemberAttributes.Abstract;
716 protected override void GenerateProperty (CodeMemberProperty property,
717 CodeTypeDeclaration declaration)
719 if (IsCurrentDelegate || IsCurrentEnum) {
723 TextWriter output = Output;
725 OutputAttributes (property.CustomAttributes, null, false);
727 MemberAttributes attributes = property.Attributes;
729 if (!IsCurrentInterface) {
730 if (property.PrivateImplementationType == null) {
731 OutputMemberAccessModifier (attributes);
732 OutputVTableModifier (attributes);
733 OutputMemberScopeModifier (attributes);
736 OutputVTableModifier (attributes);
739 OutputType (property.Type);
742 if (!IsCurrentInterface && property.PrivateImplementationType != null) {
743 output.Write (property.PrivateImplementationType.BaseType);
747 // only consider property indexer if name is Item (case-insensitive
748 // comparison) AND property has parameters
749 if (string.Compare(property.Name, "Item", true, CultureInfo.InvariantCulture) == 0 && property.Parameters.Count > 0) {
750 output.Write ("this[");
751 OutputParameters(property.Parameters);
754 output.Write (GetSafeName (property.Name));
759 if (declaration.IsInterface || IsAbstract (property.Attributes))
761 if (property.HasGet) output.WriteLine("get;");
762 if (property.HasSet) output.WriteLine("set;");
768 output.Write ("get");
772 GenerateStatements (property.GetStatements);
775 output.WriteLine ('}');
780 output.Write ("set");
784 GenerateStatements (property.SetStatements);
787 output.WriteLine ('}');
792 output.WriteLine ('}');
795 protected override void GenerateConstructor (CodeConstructor constructor, CodeTypeDeclaration declaration)
797 if (IsCurrentDelegate || IsCurrentEnum || IsCurrentInterface) {
801 OutputAttributes (constructor.CustomAttributes, null, false);
803 OutputMemberAccessModifier (constructor.Attributes);
804 Output.Write (GetSafeName (CurrentTypeName) + "(");
805 OutputParameters (constructor.Parameters);
807 if (constructor.BaseConstructorArgs.Count > 0) {
808 Output.WriteLine (" : ");
810 Output.Write ("base(");
811 OutputExpressionList (constructor.BaseConstructorArgs);
815 if (constructor.ChainedConstructorArgs.Count > 0) {
816 Output.WriteLine (" : ");
818 Output.Write("this(");
819 OutputExpressionList (constructor.ChainedConstructorArgs);
825 GenerateStatements (constructor.Statements);
827 Output.WriteLine ('}');
830 protected override void GenerateTypeConstructor (CodeTypeConstructor constructor)
832 if (IsCurrentDelegate || IsCurrentEnum || IsCurrentInterface) {
837 OutputAttributes (constructor.CustomAttributes, null, false);
840 Output.Write ("static " + GetSafeName (CurrentTypeName) + "()");
843 GenerateStatements (constructor.Statements);
845 Output.WriteLine ('}');
848 protected override void GenerateTypeStart(CodeTypeDeclaration declaration)
850 TextWriter output = Output;
852 OutputAttributes (declaration.CustomAttributes, null, false);
854 if (!IsCurrentDelegate) {
855 OutputTypeAttributes (declaration);
857 output.Write (GetSafeName (declaration.Name));
860 GenerateGenericsParameters (declaration.TypeParameters);
863 IEnumerator enumerator = declaration.BaseTypes.GetEnumerator ();
864 if (enumerator.MoveNext ()) {
865 CodeTypeReference type = (CodeTypeReference) enumerator.Current;
867 output.Write (" : ");
870 while (enumerator.MoveNext ()) {
871 type = (CodeTypeReference) enumerator.Current;
879 GenerateGenericsConstraints (declaration.TypeParameters);
884 if ((declaration.TypeAttributes & TypeAttributes.VisibilityMask) == TypeAttributes.Public) {
885 output.Write ("public ");
888 CodeTypeDelegate delegateDecl = (CodeTypeDelegate) declaration;
889 output.Write ("delegate ");
890 OutputType (delegateDecl.ReturnType);
892 output.Write (GetSafeName (declaration.Name));
894 OutputParameters (delegateDecl.Parameters);
895 output.WriteLine (");");
899 protected override void GenerateTypeEnd (CodeTypeDeclaration declaration)
901 if (!IsCurrentDelegate) {
903 Output.WriteLine ("}");
907 protected override void GenerateNamespaceStart (CodeNamespace ns)
909 TextWriter output = Output;
911 string name = ns.Name;
912 if (name != null && name.Length != 0) {
913 output.Write ("namespace ");
914 output.Write (GetSafeName (name));
920 protected override void GenerateNamespaceEnd (CodeNamespace ns)
922 string name = ns.Name;
923 if (name != null && name.Length != 0) {
925 Output.WriteLine ("}");
929 protected override void GenerateNamespaceImport (CodeNamespaceImport import)
931 TextWriter output = Output;
933 output.Write ("using ");
934 output.Write (GetSafeName (import.Namespace));
935 output.WriteLine (';');
938 protected override void GenerateAttributeDeclarationsStart (CodeAttributeDeclarationCollection attributes)
943 protected override void GenerateAttributeDeclarationsEnd (CodeAttributeDeclarationCollection attributes)
948 private void OutputStartBrace ()
950 if (Options.BracingStyle == "C") {
951 Output.WriteLine ("");
952 Output.WriteLine ("{");
954 Output.WriteLine (" {");
958 private void OutputAttributes (CodeAttributeDeclarationCollection attributes, string prefix, bool inline)
961 bool params_set = false;
964 foreach (CodeAttributeDeclaration att in attributes) {
966 if (att.Name == "System.ParamArrayAttribute") {
972 GenerateAttributeDeclarationsStart (attributes);
973 if (prefix != null) {
974 Output.Write (prefix);
976 OutputAttributeDeclaration (att);
977 GenerateAttributeDeclarationsEnd (attributes);
988 Output.Write (prefix);
989 Output.Write ("params");
998 private void OutputAttributeDeclaration (CodeAttributeDeclaration attribute)
1000 Output.Write (attribute.Name.Replace ('+', '.'));
1002 IEnumerator enumerator = attribute.Arguments.GetEnumerator ();
1003 if (enumerator.MoveNext ()) {
1004 CodeAttributeArgument argument = (CodeAttributeArgument) enumerator.Current;
1005 OutputAttributeArgument (argument);
1007 while (enumerator.MoveNext ()) {
1008 Output.Write (", ");
1009 argument = (CodeAttributeArgument) enumerator.Current;
1010 OutputAttributeArgument (argument);
1016 protected override void OutputType (CodeTypeReference type)
1018 Output.Write (GetTypeOutput (type));
1021 private void OutputVTableModifier (MemberAttributes attributes)
1023 if ((attributes & MemberAttributes.VTableMask) == MemberAttributes.New) {
1024 Output.Write ("new ");
1028 protected override void OutputFieldScopeModifier (MemberAttributes attributes)
1030 switch (attributes & MemberAttributes.ScopeMask) {
1031 case MemberAttributes.Static:
1032 Output.Write ("static ");
1034 case MemberAttributes.Const:
1035 Output.Write ("const ");
1042 // Note: this method should in fact be private as in .NET 2.0, the
1043 // CSharpCodeGenerator no longer derives from CodeGenerator but we
1044 // still need to make this change.
1045 protected override void OutputMemberAccessModifier (MemberAttributes attributes)
1047 switch (attributes & MemberAttributes.AccessMask) {
1048 case MemberAttributes.Assembly:
1049 case MemberAttributes.FamilyAndAssembly:
1050 Output.Write ("internal ");
1052 case MemberAttributes.Family:
1053 Output.Write ("protected ");
1055 case MemberAttributes.FamilyOrAssembly:
1056 Output.Write ("protected internal ");
1058 case MemberAttributes.Private:
1059 Output.Write ("private ");
1061 case MemberAttributes.Public:
1062 Output.Write ("public ");
1067 // Note: this method should in fact be private as in .NET 2.0, the
1068 // CSharpCodeGenerator no longer derives from CodeGenerator but we
1069 // still need to make this change.
1070 protected override void OutputMemberScopeModifier (MemberAttributes attributes)
1072 switch (attributes & MemberAttributes.ScopeMask) {
1073 case MemberAttributes.Abstract:
1074 Output.Write ("abstract ");
1076 case MemberAttributes.Final:
1079 case MemberAttributes.Static:
1080 Output.Write ("static ");
1082 case MemberAttributes.Override:
1083 Output.Write ("override ");
1086 MemberAttributes access = attributes & MemberAttributes.AccessMask;
1087 if (access == MemberAttributes.Assembly || access == MemberAttributes.Family || access == MemberAttributes.Public) {
1088 Output.Write ("virtual ");
1095 private void OutputTypeAttributes (CodeTypeDeclaration declaration)
1097 TextWriter output = Output;
1098 TypeAttributes attributes = declaration.TypeAttributes;
1100 switch (attributes & TypeAttributes.VisibilityMask) {
1101 case TypeAttributes.Public:
1102 case TypeAttributes.NestedPublic:
1103 output.Write ("public ");
1105 case TypeAttributes.NestedPrivate:
1106 output.Write ("private ");
1109 case TypeAttributes.NotPublic:
1110 case TypeAttributes.NestedFamANDAssem:
1111 case TypeAttributes.NestedAssembly:
1112 output.Write ("internal ");
1114 case TypeAttributes.NestedFamily:
1115 output.Write ("protected ");
1117 case TypeAttributes.NestedFamORAssem:
1118 output.Write ("protected internal ");
1123 if (declaration.IsStruct) {
1125 if (declaration.IsPartial) {
1126 output.Write ("partial ");
1129 output.Write ("struct ");
1130 } else if (declaration.IsEnum) {
1131 output.Write ("enum ");
1133 if ((attributes & TypeAttributes.Interface) != 0) {
1135 if (declaration.IsPartial) {
1136 output.Write ("partial ");
1139 output.Write ("interface ");
1141 if ((attributes & TypeAttributes.Sealed) != 0)
1142 output.Write ("sealed ");
1143 if ((attributes & TypeAttributes.Abstract) != 0)
1144 output.Write ("abstract ");
1146 if (declaration.IsPartial) {
1147 output.Write ("partial ");
1150 output.Write ("class ");
1155 [MonoTODO ("Implement missing special characters")]
1156 protected override string QuoteSnippetString (string value)
1158 // FIXME: this is weird, but works.
1159 string output = value.Replace ("\\", "\\\\");
1160 output = output.Replace ("\"", "\\\"");
1161 output = output.Replace ("\t", "\\t");
1162 output = output.Replace ("\r", "\\r");
1163 output = output.Replace ("\n", "\\n");
1165 return "\"" + output + "\"";
1168 protected override void GeneratePrimitiveExpression(CodePrimitiveExpression e)
1170 if (e.Value is char) {
1171 this.GenerateCharValue ((char) e.Value);
1173 } else if (e.Value is ushort) {
1174 ushort uc = (ushort) e.Value;
1175 Output.Write (uc.ToString(CultureInfo.InvariantCulture));
1176 } else if (e.Value is uint) {
1177 uint ui = (uint) e.Value;
1178 Output.Write (ui.ToString(CultureInfo.InvariantCulture));
1180 } else if (e.Value is ulong) {
1181 ulong ul = (ulong) e.Value;
1182 Output.Write (ul.ToString(CultureInfo.InvariantCulture));
1183 Output.Write ("ul");
1184 } else if (e.Value is sbyte) {
1185 sbyte sb = (sbyte) e.Value;
1186 Output.Write (sb.ToString(CultureInfo.InvariantCulture));
1189 base.GeneratePrimitiveExpression (e);
1193 private void GenerateCharValue (char c)
1195 Output.Write ('\'');
1199 Output.Write ("\\0");
1202 Output.Write ("\\t");
1205 Output.Write ("\\n");
1208 Output.Write ("\\r");
1211 Output.Write ("\\\"");
1214 Output.Write ("\\'");
1217 Output.Write ("\\\\");
1220 Output.Write ("\\u");
1222 Output.Write (((int) c).ToString ("X4", CultureInfo.InvariantCulture));
1224 Output.Write (((int) c).ToString (CultureInfo.InvariantCulture));
1228 Output.Write ("\\u");
1230 Output.Write (((int) c).ToString ("X4", CultureInfo.InvariantCulture));
1232 Output.Write (((int) c).ToString (CultureInfo.InvariantCulture));
1240 Output.Write ('\'');
1243 protected override void GenerateSingleFloatValue (float f)
1245 base.GenerateSingleFloatValue (f);
1246 base.Output.Write ('F');
1249 protected override void GenerateDecimalValue (decimal d)
1251 base.GenerateDecimalValue (d);
1252 base.Output.Write ('m');
1255 protected override void GenerateParameterDeclarationExpression (CodeParameterDeclarationExpression e)
1257 OutputAttributes (e.CustomAttributes, null, true);
1258 OutputDirection (e.Direction);
1259 OutputType (e.Type);
1261 Output.Write (GetSafeName (e.Name));
1264 protected override void GenerateTypeOfExpression (CodeTypeOfExpression e)
1266 Output.Write ("typeof(");
1267 OutputType (e.Type);
1275 protected override string CreateEscapedIdentifier (string value)
1278 throw new NullReferenceException ("Argument identifier is null.");
1279 return GetSafeName (value);
1282 protected override string CreateValidIdentifier (string value)
1285 throw new NullReferenceException ();
1287 if (keywordsTable == null)
1288 FillKeywordTable ();
1290 if (keywordsTable.Contains (value))
1296 protected override string GetTypeOutput (CodeTypeReference type)
1299 if ((type.Options & CodeTypeReferenceOptions.GenericTypeParameter) != 0)
1300 return type.BaseType;
1303 string typeOutput = null;
1305 if (type.ArrayElementType != null) {
1306 typeOutput = GetTypeOutput (type.ArrayElementType);
1308 typeOutput = DetermineTypeOutput (type);
1311 int rank = type.ArrayRank;
1314 for (--rank; rank > 0; --rank) {
1323 private string DetermineTypeOutput (CodeTypeReference type)
1325 string typeOutput = null;
1326 string baseType = type.BaseType;
1328 switch (baseType.ToLower (System.Globalization.CultureInfo.InvariantCulture)) {
1329 case "system.int32":
1332 case "system.int64":
1333 typeOutput = "long";
1335 case "system.int16":
1336 typeOutput = "short";
1338 case "system.boolean":
1339 typeOutput = "bool";
1342 typeOutput = "char";
1344 case "system.string":
1345 typeOutput = "string";
1347 case "system.object":
1348 typeOutput = "object";
1351 typeOutput = "void";
1355 typeOutput = "byte";
1357 case "system.sbyte":
1358 typeOutput = "sbyte";
1360 case "system.decimal":
1361 typeOutput = "decimal";
1363 case "system.double":
1364 typeOutput = "double";
1366 case "system.single":
1367 typeOutput = "float";
1369 case "system.uint16":
1370 typeOutput = "ushort";
1372 case "system.uint32":
1373 typeOutput = "uint";
1375 case "system.uint64":
1376 typeOutput = "ulong";
1381 StringBuilder sb = new StringBuilder (baseType.Length);
1382 if (type.Options == CodeTypeReferenceOptions.GlobalReference) {
1383 sb.Append ("global::");
1386 int lastProcessedChar = 0;
1387 for (int i = 0; i < baseType.Length; i++) {
1388 char currentChar = baseType[i];
1389 if (currentChar != '+' && currentChar != '.') {
1390 if (currentChar == '`') {
1391 sb.Append (CreateEscapedIdentifier (baseType.Substring (
1392 lastProcessedChar, i - lastProcessedChar)));
1395 // determine number of type arguments to output
1396 int typeArgCount = baseType[i] - '0';
1397 // output type arguments
1398 OutputTypeArguments (type.TypeArguments, sb, typeArgCount);
1399 // skip type argument indicator
1401 // if next character is . or +, then append .
1402 if ((i < baseType.Length) && ((baseType[i] == '+') || (baseType[i] == '.'))) {
1404 // skip character that we just processed
1407 // save postion of last processed character
1408 lastProcessedChar = i;
1411 sb.Append (CreateEscapedIdentifier (baseType.Substring (
1412 lastProcessedChar, i - lastProcessedChar)));
1416 // save postion of last processed character
1417 lastProcessedChar = i;
1421 // add characters that have not yet been processed
1422 if (lastProcessedChar < baseType.Length) {
1423 sb.Append (CreateEscapedIdentifier (baseType.Substring (lastProcessedChar)));
1426 typeOutput = sb.ToString ();
1428 typeOutput = GetSafeName (baseType);
1429 typeOutput = typeOutput.Replace ('+', '.');
1436 static bool is_identifier_start_character (char c)
1438 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == '@' || Char.IsLetter (c);
1441 static bool is_identifier_part_character (char c)
1443 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= '0' && c <= '9') || Char.IsLetter (c)
1447 protected override bool IsValidIdentifier (string identifier)
1449 if (identifier == null || identifier.Length == 0)
1452 if (keywordsTable == null)
1453 FillKeywordTable ();
1455 if (keywordsTable.Contains (identifier))
1458 if (!is_identifier_start_character (identifier [0]))
1461 for (int i = 1; i < identifier.Length; i ++)
1462 if (! is_identifier_part_character (identifier [i]))
1468 protected override bool Supports (GeneratorSupport supports)
1474 protected override void GenerateDirectives (CodeDirectiveCollection directives)
1476 foreach (CodeDirective d in directives) {
1477 if (d is CodeChecksumPragma) {
1478 GenerateCodeChecksumPragma ((CodeChecksumPragma)d);
1481 if (d is CodeRegionDirective) {
1482 GenerateCodeRegionDirective ((CodeRegionDirective)d);
1485 throw new NotImplementedException ("Unknown CodeDirective");
1489 void GenerateCodeChecksumPragma (CodeChecksumPragma pragma)
1491 Output.Write ("#pragma checksum \"");
1492 Output.Write (pragma.FileName);
1493 Output.Write ("\" \"");
1494 Output.Write (pragma.ChecksumAlgorithmId.ToString ("B"));
1495 Output.Write ("\" \"");
1496 if (pragma.ChecksumData != null) {
1497 foreach (byte b in pragma.ChecksumData) {
1498 Output.Write (b.ToString ("X2"));
1501 Output.WriteLine ("\"");
1504 void GenerateCodeRegionDirective (CodeRegionDirective region)
1506 switch (region.RegionMode) {
1507 case CodeRegionMode.Start:
1508 Output.Write ("#region ");
1509 Output.WriteLine (region.RegionText);
1511 case CodeRegionMode.End:
1512 Output.WriteLine ("#endregion");
1517 void GenerateGenericsParameters (CodeTypeParameterCollection parameters)
1519 int count = parameters.Count;
1524 for (int i = 0; i < count - 1; ++i) {
1525 Output.Write (parameters [i].Name);
1526 Output.Write (", ");
1528 Output.Write (parameters [count - 1].Name);
1532 void GenerateGenericsConstraints (CodeTypeParameterCollection parameters)
1534 int count = parameters.Count;
1538 bool indented = false;
1540 for (int i = 0; i < count; i++) {
1541 CodeTypeParameter p = parameters [i];
1542 bool hasConstraints = (p.Constraints.Count != 0);
1543 Output.WriteLine ();
1544 if (!hasConstraints && !p.HasConstructorConstraint)
1552 Output.Write ("where ");
1553 Output.Write (p.Name);
1554 Output.Write (" : ");
1556 for (int j = 0; j < p.Constraints.Count; j++) {
1558 Output.Write (", ");
1559 OutputType (p.Constraints [j]);
1562 if (p.HasConstructorConstraint) {
1564 Output.Write (", ");
1565 Output.Write ("new");
1568 Output.Write ("()");
1576 string GetTypeArguments (CodeTypeReferenceCollection collection)
1578 StringBuilder sb = new StringBuilder (" <");
1579 foreach (CodeTypeReference r in collection) {
1580 sb.Append (GetTypeOutput (r));
1584 sb [sb.Length - 1] = '>';
1585 return sb.ToString ();
1588 private void OutputTypeArguments (CodeTypeReferenceCollection typeArguments, StringBuilder sb, int count)
1592 } else if (typeArguments.Count == 0) {
1593 // generic type definition
1600 // write first type argument
1601 sb.Append (GetTypeOutput (typeArguments[0]));
1602 // subsequent type argument are prefixed by ', ' separator
1603 for (int i = 1; i < count; i++) {
1605 sb.Append (GetTypeOutput (typeArguments[i]));
1614 public override void ValidateIdentifier (string identifier)
1619 private string GetSafeName (string id)
1621 if (keywordsTable == null) {
1622 FillKeywordTable ();
1624 if (keywordsTable.Contains (id)) {
1631 static void FillKeywordTable ()
1633 keywordsTable = new Hashtable ();
1634 foreach (string keyword in keywords) {
1635 keywordsTable.Add (keyword, keyword);
1639 private static Hashtable keywordsTable;
1640 private static string[] keywords = new string[] {
1641 "abstract","event","new","struct","as","explicit","null","switch","base","extern",
1642 "this","false","operator","throw","break","finally","out","true",
1643 "fixed","override","try","case","params","typeof","catch","for",
1644 "private","foreach","protected","checked","goto","public",
1645 "unchecked","class","if","readonly","unsafe","const","implicit","ref",
1646 "continue","in","return","using","virtual","default",
1647 "interface","sealed","volatile","delegate","internal","do","is",
1648 "sizeof","while","lock","stackalloc","else","static","enum",
1650 "object","bool","byte","float","uint","char","ulong","ushort",
1651 "decimal","int","sbyte","short","double","long","string","void",
1653 "partial", "yield", "where"