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 Dictionary <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 (Dictionary <string, string> providerOptions)
68 this.providerOptions = providerOptions;
71 protected Dictionary <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");
566 protected override void GenerateEvent (CodeMemberEvent eventRef, CodeTypeDeclaration declaration)
568 if (IsCurrentDelegate || IsCurrentEnum) {
572 OutputAttributes (eventRef.CustomAttributes, null, false);
574 if (eventRef.PrivateImplementationType == null) {
575 OutputMemberAccessModifier (eventRef.Attributes);
578 Output.Write ("event ");
580 if (eventRef.PrivateImplementationType != null) {
581 OutputTypeNamePair (eventRef.Type,
582 eventRef.PrivateImplementationType.BaseType + "." +
585 OutputTypeNamePair (eventRef.Type, GetSafeName (eventRef.Name));
587 Output.WriteLine (';');
590 protected override void GenerateField (CodeMemberField field)
592 if (IsCurrentDelegate || IsCurrentInterface) {
596 TextWriter output = Output;
598 OutputAttributes (field.CustomAttributes, null, false);
601 Output.Write (GetSafeName (field.Name));
603 MemberAttributes attributes = field.Attributes;
604 OutputMemberAccessModifier (attributes);
605 OutputVTableModifier (attributes);
606 OutputFieldScopeModifier (attributes);
608 OutputTypeNamePair (field.Type, GetSafeName (field.Name));
611 CodeExpression initExpression = field.InitExpression;
612 if (initExpression != null) {
613 output.Write (" = ");
614 GenerateExpression (initExpression);
618 output.WriteLine (',');
620 output.WriteLine (';');
623 protected override void GenerateSnippetMember (CodeSnippetTypeMember member)
625 Output.Write (member.Text);
628 protected override void GenerateEntryPointMethod (CodeEntryPointMethod method,
629 CodeTypeDeclaration declaration)
632 OutputAttributes (method.CustomAttributes, null, false);
635 Output.Write ("public static ");
637 OutputType (method.ReturnType);
639 Output.Write ("void");
641 Output.Write (" Main()");
644 GenerateStatements (method.Statements);
646 Output.WriteLine ("}");
649 protected override void GenerateMethod (CodeMemberMethod method,
650 CodeTypeDeclaration declaration)
652 if (IsCurrentDelegate || IsCurrentEnum) {
656 TextWriter output = Output;
658 OutputAttributes (method.CustomAttributes, null, false);
660 OutputAttributes (method.ReturnTypeCustomAttributes,
663 MemberAttributes attributes = method.Attributes;
665 if (!IsCurrentInterface) {
666 if (method.PrivateImplementationType == null) {
667 OutputMemberAccessModifier (attributes);
668 OutputVTableModifier (attributes);
669 OutputMemberScopeModifier (attributes);
672 OutputVTableModifier (attributes);
675 OutputType (method.ReturnType);
678 CodeTypeReference privateType = method.PrivateImplementationType;
679 if (privateType != null) {
680 output.Write (privateType.BaseType);
683 output.Write (GetSafeName (method.Name));
686 GenerateGenericsParameters (method.TypeParameters);
690 OutputParameters (method.Parameters);
694 GenerateGenericsConstraints (method.TypeParameters);
697 if ((attributes & MemberAttributes.ScopeMask) == MemberAttributes.Abstract || declaration.IsInterface)
698 output.WriteLine (';');
702 GenerateStatements (method.Statements);
704 output.WriteLine ('}');
708 static bool IsAbstract (MemberAttributes attributes)
710 return (attributes & MemberAttributes.Abstract) == MemberAttributes.Abstract;
713 protected override void GenerateProperty (CodeMemberProperty property,
714 CodeTypeDeclaration declaration)
716 if (IsCurrentDelegate || IsCurrentEnum) {
720 TextWriter output = Output;
722 OutputAttributes (property.CustomAttributes, null, false);
724 MemberAttributes attributes = property.Attributes;
726 if (!IsCurrentInterface) {
727 if (property.PrivateImplementationType == null) {
728 OutputMemberAccessModifier (attributes);
729 OutputVTableModifier (attributes);
730 OutputMemberScopeModifier (attributes);
733 OutputVTableModifier (attributes);
736 OutputType (property.Type);
739 if (!IsCurrentInterface && property.PrivateImplementationType != null) {
740 output.Write (property.PrivateImplementationType.BaseType);
744 // only consider property indexer if name is Item (case-insensitive
745 // comparison) AND property has parameters
746 if (string.Compare(property.Name, "Item", true, CultureInfo.InvariantCulture) == 0 && property.Parameters.Count > 0) {
747 output.Write ("this[");
748 OutputParameters(property.Parameters);
751 output.Write (GetSafeName (property.Name));
756 if (declaration.IsInterface || IsAbstract (property.Attributes))
758 if (property.HasGet) output.WriteLine("get;");
759 if (property.HasSet) output.WriteLine("set;");
765 output.Write ("get");
769 GenerateStatements (property.GetStatements);
772 output.WriteLine ('}');
777 output.Write ("set");
781 GenerateStatements (property.SetStatements);
784 output.WriteLine ('}');
789 output.WriteLine ('}');
792 protected override void GenerateConstructor (CodeConstructor constructor, CodeTypeDeclaration declaration)
794 if (IsCurrentDelegate || IsCurrentEnum || IsCurrentInterface) {
798 OutputAttributes (constructor.CustomAttributes, null, false);
800 OutputMemberAccessModifier (constructor.Attributes);
801 Output.Write (GetSafeName (CurrentTypeName) + "(");
802 OutputParameters (constructor.Parameters);
804 if (constructor.BaseConstructorArgs.Count > 0) {
805 Output.WriteLine (" : ");
807 Output.Write ("base(");
808 OutputExpressionList (constructor.BaseConstructorArgs);
812 if (constructor.ChainedConstructorArgs.Count > 0) {
813 Output.WriteLine (" : ");
815 Output.Write("this(");
816 OutputExpressionList (constructor.ChainedConstructorArgs);
822 GenerateStatements (constructor.Statements);
824 Output.WriteLine ('}');
827 protected override void GenerateTypeConstructor (CodeTypeConstructor constructor)
829 if (IsCurrentDelegate || IsCurrentEnum || IsCurrentInterface) {
834 OutputAttributes (constructor.CustomAttributes, null, false);
837 Output.Write ("static " + GetSafeName (CurrentTypeName) + "()");
840 GenerateStatements (constructor.Statements);
842 Output.WriteLine ('}');
845 protected override void GenerateTypeStart(CodeTypeDeclaration declaration)
847 TextWriter output = Output;
849 OutputAttributes (declaration.CustomAttributes, null, false);
851 if (!IsCurrentDelegate) {
852 OutputTypeAttributes (declaration);
854 output.Write (GetSafeName (declaration.Name));
857 GenerateGenericsParameters (declaration.TypeParameters);
860 IEnumerator enumerator = declaration.BaseTypes.GetEnumerator ();
861 if (enumerator.MoveNext ()) {
862 CodeTypeReference type = (CodeTypeReference) enumerator.Current;
864 output.Write (" : ");
867 while (enumerator.MoveNext ()) {
868 type = (CodeTypeReference) enumerator.Current;
876 GenerateGenericsConstraints (declaration.TypeParameters);
881 if ((declaration.TypeAttributes & TypeAttributes.VisibilityMask) == TypeAttributes.Public) {
882 output.Write ("public ");
885 CodeTypeDelegate delegateDecl = (CodeTypeDelegate) declaration;
886 output.Write ("delegate ");
887 OutputType (delegateDecl.ReturnType);
889 output.Write (GetSafeName (declaration.Name));
891 OutputParameters (delegateDecl.Parameters);
892 output.WriteLine (");");
896 protected override void GenerateTypeEnd (CodeTypeDeclaration declaration)
898 if (!IsCurrentDelegate) {
900 Output.WriteLine ("}");
904 protected override void GenerateNamespaceStart (CodeNamespace ns)
906 TextWriter output = Output;
908 string name = ns.Name;
909 if (name != null && name.Length != 0) {
910 output.Write ("namespace ");
911 output.Write (GetSafeName (name));
917 protected override void GenerateNamespaceEnd (CodeNamespace ns)
919 string name = ns.Name;
920 if (name != null && name.Length != 0) {
922 Output.WriteLine ("}");
926 protected override void GenerateNamespaceImport (CodeNamespaceImport import)
928 TextWriter output = Output;
930 output.Write ("using ");
931 output.Write (GetSafeName (import.Namespace));
932 output.WriteLine (';');
935 protected override void GenerateAttributeDeclarationsStart (CodeAttributeDeclarationCollection attributes)
940 protected override void GenerateAttributeDeclarationsEnd (CodeAttributeDeclarationCollection attributes)
945 private void OutputStartBrace ()
947 if (Options.BracingStyle == "C") {
948 Output.WriteLine ("");
949 Output.WriteLine ("{");
951 Output.WriteLine (" {");
955 private void OutputAttributes (CodeAttributeDeclarationCollection attributes, string prefix, bool inline)
957 foreach (CodeAttributeDeclaration att in attributes) {
958 GenerateAttributeDeclarationsStart (attributes);
959 if (prefix != null) {
960 Output.Write (prefix);
962 OutputAttributeDeclaration (att);
963 GenerateAttributeDeclarationsEnd (attributes);
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 ");
1016 // Note: this method should in fact be private as in .NET 2.0, the
1017 // CSharpCodeGenerator no longer derives from CodeGenerator but we
1018 // still need to make this change.
1019 protected override void OutputMemberAccessModifier (MemberAttributes attributes)
1021 switch (attributes & MemberAttributes.AccessMask) {
1022 case MemberAttributes.Assembly:
1023 case MemberAttributes.FamilyAndAssembly:
1024 Output.Write ("internal ");
1026 case MemberAttributes.Family:
1027 Output.Write ("protected ");
1029 case MemberAttributes.FamilyOrAssembly:
1030 Output.Write ("protected internal ");
1032 case MemberAttributes.Private:
1033 Output.Write ("private ");
1035 case MemberAttributes.Public:
1036 Output.Write ("public ");
1041 // Note: this method should in fact be private as in .NET 2.0, the
1042 // CSharpCodeGenerator no longer derives from CodeGenerator but we
1043 // still need to make this change.
1044 protected override void OutputMemberScopeModifier (MemberAttributes attributes)
1046 switch (attributes & MemberAttributes.ScopeMask) {
1047 case MemberAttributes.Abstract:
1048 Output.Write ("abstract ");
1050 case MemberAttributes.Final:
1053 case MemberAttributes.Static:
1054 Output.Write ("static ");
1056 case MemberAttributes.Override:
1057 Output.Write ("override ");
1060 MemberAttributes access = attributes & MemberAttributes.AccessMask;
1061 if (access == MemberAttributes.Assembly || access == MemberAttributes.Family || access == MemberAttributes.Public) {
1062 Output.Write ("virtual ");
1069 private void OutputTypeAttributes (CodeTypeDeclaration declaration)
1071 TextWriter output = Output;
1072 TypeAttributes attributes = declaration.TypeAttributes;
1074 switch (attributes & TypeAttributes.VisibilityMask) {
1075 case TypeAttributes.Public:
1076 case TypeAttributes.NestedPublic:
1077 output.Write ("public ");
1079 case TypeAttributes.NestedPrivate:
1080 output.Write ("private ");
1083 case TypeAttributes.NotPublic:
1084 case TypeAttributes.NestedFamANDAssem:
1085 case TypeAttributes.NestedAssembly:
1086 output.Write ("internal ");
1088 case TypeAttributes.NestedFamily:
1089 output.Write ("protected ");
1091 case TypeAttributes.NestedFamORAssem:
1092 output.Write ("protected internal ");
1097 if (declaration.IsStruct) {
1099 if (declaration.IsPartial) {
1100 output.Write ("partial ");
1103 output.Write ("struct ");
1104 } else if (declaration.IsEnum) {
1105 output.Write ("enum ");
1107 if ((attributes & TypeAttributes.Interface) != 0) {
1109 if (declaration.IsPartial) {
1110 output.Write ("partial ");
1113 output.Write ("interface ");
1115 if ((attributes & TypeAttributes.Sealed) != 0)
1116 output.Write ("sealed ");
1117 if ((attributes & TypeAttributes.Abstract) != 0)
1118 output.Write ("abstract ");
1120 if (declaration.IsPartial) {
1121 output.Write ("partial ");
1124 output.Write ("class ");
1129 [MonoTODO ("Implement missing special characters")]
1130 protected override string QuoteSnippetString (string value)
1132 // FIXME: this is weird, but works.
1133 string output = value.Replace ("\\", "\\\\");
1134 output = output.Replace ("\"", "\\\"");
1135 output = output.Replace ("\t", "\\t");
1136 output = output.Replace ("\r", "\\r");
1137 output = output.Replace ("\n", "\\n");
1139 return "\"" + output + "\"";
1142 protected override void GeneratePrimitiveExpression(CodePrimitiveExpression e)
1144 if (e.Value is char) {
1145 this.GenerateCharValue ((char) e.Value);
1147 } else if (e.Value is ushort) {
1148 ushort uc = (ushort) e.Value;
1149 Output.Write (uc.ToString(CultureInfo.InvariantCulture));
1150 } else if (e.Value is uint) {
1151 uint ui = (uint) e.Value;
1152 Output.Write (ui.ToString(CultureInfo.InvariantCulture));
1154 } else if (e.Value is ulong) {
1155 ulong ul = (ulong) e.Value;
1156 Output.Write (ul.ToString(CultureInfo.InvariantCulture));
1157 Output.Write ("ul");
1158 } else if (e.Value is sbyte) {
1159 sbyte sb = (sbyte) e.Value;
1160 Output.Write (sb.ToString(CultureInfo.InvariantCulture));
1163 base.GeneratePrimitiveExpression (e);
1167 private void GenerateCharValue (char c)
1169 Output.Write ('\'');
1173 Output.Write ("\\0");
1176 Output.Write ("\\t");
1179 Output.Write ("\\n");
1182 Output.Write ("\\r");
1185 Output.Write ("\\\"");
1188 Output.Write ("\\'");
1191 Output.Write ("\\\\");
1194 Output.Write ("\\u");
1196 Output.Write (((int) c).ToString ("X4", CultureInfo.InvariantCulture));
1198 Output.Write (((int) c).ToString (CultureInfo.InvariantCulture));
1202 Output.Write ("\\u");
1204 Output.Write (((int) c).ToString ("X4", CultureInfo.InvariantCulture));
1206 Output.Write (((int) c).ToString (CultureInfo.InvariantCulture));
1214 Output.Write ('\'');
1217 protected override void GenerateSingleFloatValue (float f)
1219 base.GenerateSingleFloatValue (f);
1220 base.Output.Write ('F');
1223 protected override void GenerateDecimalValue (decimal d)
1225 base.GenerateDecimalValue (d);
1226 base.Output.Write ('m');
1229 protected override void GenerateParameterDeclarationExpression (CodeParameterDeclarationExpression e)
1231 OutputAttributes (e.CustomAttributes, null, true);
1232 OutputDirection (e.Direction);
1233 OutputType (e.Type);
1235 Output.Write (GetSafeName (e.Name));
1238 protected override void GenerateTypeOfExpression (CodeTypeOfExpression e)
1240 Output.Write ("typeof(");
1241 OutputType (e.Type);
1249 protected override string CreateEscapedIdentifier (string value)
1252 throw new NullReferenceException ("Argument identifier is null.");
1253 return GetSafeName (value);
1256 protected override string CreateValidIdentifier (string value)
1259 throw new NullReferenceException ();
1261 if (keywordsTable == null)
1262 FillKeywordTable ();
1264 if (keywordsTable.Contains (value))
1270 protected override string GetTypeOutput (CodeTypeReference type)
1273 if ((type.Options & CodeTypeReferenceOptions.GenericTypeParameter) != 0)
1274 return type.BaseType;
1277 string typeOutput = null;
1279 if (type.ArrayElementType != null) {
1280 typeOutput = GetTypeOutput (type.ArrayElementType);
1282 typeOutput = DetermineTypeOutput (type);
1285 int rank = type.ArrayRank;
1288 for (--rank; rank > 0; --rank) {
1297 private string DetermineTypeOutput (CodeTypeReference type)
1299 string typeOutput = null;
1300 string baseType = type.BaseType;
1302 switch (baseType.ToLower (System.Globalization.CultureInfo.InvariantCulture)) {
1303 case "system.int32":
1306 case "system.int64":
1307 typeOutput = "long";
1309 case "system.int16":
1310 typeOutput = "short";
1312 case "system.boolean":
1313 typeOutput = "bool";
1316 typeOutput = "char";
1318 case "system.string":
1319 typeOutput = "string";
1321 case "system.object":
1322 typeOutput = "object";
1325 typeOutput = "void";
1329 typeOutput = "byte";
1331 case "system.sbyte":
1332 typeOutput = "sbyte";
1334 case "system.decimal":
1335 typeOutput = "decimal";
1337 case "system.double":
1338 typeOutput = "double";
1340 case "system.single":
1341 typeOutput = "float";
1343 case "system.uint16":
1344 typeOutput = "ushort";
1346 case "system.uint32":
1347 typeOutput = "uint";
1349 case "system.uint64":
1350 typeOutput = "ulong";
1355 StringBuilder sb = new StringBuilder (baseType.Length);
1356 if (type.Options == CodeTypeReferenceOptions.GlobalReference) {
1357 sb.Append ("global::");
1360 int lastProcessedChar = 0;
1361 for (int i = 0; i < baseType.Length; i++) {
1362 char currentChar = baseType[i];
1363 if (currentChar != '+' && currentChar != '.') {
1364 if (currentChar == '`') {
1365 sb.Append (CreateEscapedIdentifier (baseType.Substring (
1366 lastProcessedChar, i - lastProcessedChar)));
1369 // determine number of type arguments to output
1370 int typeArgCount = baseType[i] - '0';
1371 // output type arguments
1372 OutputTypeArguments (type.TypeArguments, sb, typeArgCount);
1373 // skip type argument indicator
1375 // if next character is . or +, then append .
1376 if ((i < baseType.Length) && ((baseType[i] == '+') || (baseType[i] == '.'))) {
1378 // skip character that we just processed
1381 // save postion of last processed character
1382 lastProcessedChar = i;
1385 sb.Append (CreateEscapedIdentifier (baseType.Substring (
1386 lastProcessedChar, i - lastProcessedChar)));
1390 // save postion of last processed character
1391 lastProcessedChar = i;
1395 // add characters that have not yet been processed
1396 if (lastProcessedChar < baseType.Length) {
1397 sb.Append (CreateEscapedIdentifier (baseType.Substring (lastProcessedChar)));
1400 typeOutput = sb.ToString ();
1402 typeOutput = GetSafeName (baseType);
1403 typeOutput = typeOutput.Replace ('+', '.');
1410 static bool is_identifier_start_character (char c)
1412 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == '@' || Char.IsLetter (c);
1415 static bool is_identifier_part_character (char c)
1417 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= '0' && c <= '9') || Char.IsLetter (c)
1421 protected override bool IsValidIdentifier (string identifier)
1423 if (identifier == null || identifier.Length == 0)
1426 if (keywordsTable == null)
1427 FillKeywordTable ();
1429 if (keywordsTable.Contains (identifier))
1432 if (!is_identifier_start_character (identifier [0]))
1435 for (int i = 1; i < identifier.Length; i ++)
1436 if (! is_identifier_part_character (identifier [i]))
1442 protected override bool Supports (GeneratorSupport supports)
1448 protected override void GenerateDirectives (CodeDirectiveCollection directives)
1450 foreach (CodeDirective d in directives) {
1451 if (d is CodeChecksumPragma) {
1452 GenerateCodeChecksumPragma ((CodeChecksumPragma)d);
1455 if (d is CodeRegionDirective) {
1456 GenerateCodeRegionDirective ((CodeRegionDirective)d);
1459 throw new NotImplementedException ("Unknown CodeDirective");
1463 void GenerateCodeChecksumPragma (CodeChecksumPragma pragma)
1465 Output.Write ("#pragma checksum \"");
1466 Output.Write (pragma.FileName);
1467 Output.Write ("\" \"");
1468 Output.Write (pragma.ChecksumAlgorithmId.ToString ("B"));
1469 Output.Write ("\" \"");
1470 if (pragma.ChecksumData != null) {
1471 foreach (byte b in pragma.ChecksumData) {
1472 Output.Write (b.ToString ("X2"));
1475 Output.WriteLine ("\"");
1478 void GenerateCodeRegionDirective (CodeRegionDirective region)
1480 switch (region.RegionMode) {
1481 case CodeRegionMode.Start:
1482 Output.Write ("#region ");
1483 Output.WriteLine (region.RegionText);
1485 case CodeRegionMode.End:
1486 Output.WriteLine ("#endregion");
1491 void GenerateGenericsParameters (CodeTypeParameterCollection parameters)
1493 int count = parameters.Count;
1498 for (int i = 0; i < count - 1; ++i) {
1499 Output.Write (parameters [i].Name);
1500 Output.Write (", ");
1502 Output.Write (parameters [count - 1].Name);
1506 void GenerateGenericsConstraints (CodeTypeParameterCollection parameters)
1508 int count = parameters.Count;
1512 bool indented = false;
1514 for (int i = 0; i < count; i++) {
1515 CodeTypeParameter p = parameters [i];
1516 bool hasConstraints = (p.Constraints.Count != 0);
1517 Output.WriteLine ();
1518 if (!hasConstraints && !p.HasConstructorConstraint)
1526 Output.Write ("where ");
1527 Output.Write (p.Name);
1528 Output.Write (" : ");
1530 for (int j = 0; j < p.Constraints.Count; j++) {
1532 Output.Write (", ");
1533 OutputType (p.Constraints [j]);
1536 if (p.HasConstructorConstraint) {
1538 Output.Write (", ");
1539 Output.Write ("new");
1542 Output.Write ("()");
1550 string GetTypeArguments (CodeTypeReferenceCollection collection)
1552 StringBuilder sb = new StringBuilder (" <");
1553 foreach (CodeTypeReference r in collection) {
1554 sb.Append (GetTypeOutput (r));
1558 sb [sb.Length - 1] = '>';
1559 return sb.ToString ();
1562 private void OutputTypeArguments (CodeTypeReferenceCollection typeArguments, StringBuilder sb, int count)
1566 } else if (typeArguments.Count == 0) {
1567 // generic type definition
1574 // write first type argument
1575 sb.Append (GetTypeOutput (typeArguments[0]));
1576 // subsequent type argument are prefixed by ', ' separator
1577 for (int i = 1; i < count; i++) {
1579 sb.Append (GetTypeOutput (typeArguments[i]));
1588 public override void ValidateIdentifier (string identifier)
1593 private string GetSafeName (string id)
1595 if (keywordsTable == null) {
1596 FillKeywordTable ();
1598 if (keywordsTable.Contains (id)) {
1605 static void FillKeywordTable ()
1607 keywordsTable = new Hashtable ();
1608 foreach (string keyword in keywords) {
1609 keywordsTable.Add (keyword, keyword);
1613 private static Hashtable keywordsTable;
1614 private static string[] keywords = new string[] {
1615 "abstract","event","new","struct","as","explicit","null","switch","base","extern",
1616 "this","false","operator","throw","break","finally","out","true",
1617 "fixed","override","try","case","params","typeof","catch","for",
1618 "private","foreach","protected","checked","goto","public",
1619 "unchecked","class","if","readonly","unsafe","const","implicit","ref",
1620 "continue","in","return","using","virtual","default",
1621 "interface","sealed","volatile","delegate","internal","do","is",
1622 "sizeof","while","lock","stackalloc","else","static","enum",
1624 "object","bool","byte","float","uint","char","ulong","ushort",
1625 "decimal","int","sbyte","short","double","long","string","void",
1627 "partial", "yield", "where"