1 //------------------------------------------------------------------------------
2 // <copyright file="CodeGenerator.cs" company="Microsoft">
4 // <OWNER>Microsoft</OWNER>
5 // Copyright (c) Microsoft Corporation. All rights reserved.
7 //------------------------------------------------------------------------------
9 namespace System.CodeDom.Compiler {
10 using System.Runtime.Remoting;
11 using System.Runtime.InteropServices;
13 using System.Diagnostics;
15 using Microsoft.Win32;
17 using System.Collections;
18 using System.Reflection;
19 using System.Globalization;
21 using System.Security.Permissions;
25 /// <para>Provides a base class for code generators.</para>
27 [PermissionSet(SecurityAction.LinkDemand, Name="FullTrust")]
28 [PermissionSet(SecurityAction.InheritanceDemand, Name="FullTrust")]
29 public abstract class CodeGenerator : ICodeGenerator {
30 private const int ParameterMultilineThreshold = 15;
31 private IndentedTextWriter output;
32 private CodeGeneratorOptions options;
34 private CodeTypeDeclaration currentClass;
35 private CodeTypeMember currentMember;
37 private bool inNestedBinary = false;
41 /// Gets the current class.
44 protected CodeTypeDeclaration CurrentClass {
52 /// Gets or sets the current class name.
55 protected string CurrentTypeName {
57 if (currentClass != null) {
58 return currentClass.Name;
60 return "<% unknown %>";
66 /// Gets or sets the current member of the class.
69 protected CodeTypeMember CurrentMember {
77 /// Gets or sets the current member name.
80 protected string CurrentMemberName {
82 if (currentMember != null) {
83 return currentMember.Name;
85 return "<% unknown %>";
91 /// Gets or sets a value indicating whether the current object being
92 /// generated is an interface.
95 protected bool IsCurrentInterface {
97 if (currentClass != null && !(currentClass is CodeTypeDelegate)) {
98 return currentClass.IsInterface;
106 /// Gets or sets a value indicating whether the current object being generated
110 protected bool IsCurrentClass {
112 if (currentClass != null && !(currentClass is CodeTypeDelegate)) {
113 return currentClass.IsClass;
121 /// Gets or sets a value indicating whether the current object being generated
125 protected bool IsCurrentStruct {
127 if (currentClass != null && !(currentClass is CodeTypeDelegate)) {
128 return currentClass.IsStruct;
136 /// Gets or sets a value indicating whether the current object being generated
137 /// is an enumeration.
140 protected bool IsCurrentEnum {
142 if (currentClass != null && !(currentClass is CodeTypeDelegate)) {
143 return currentClass.IsEnum;
151 /// Gets or sets a value indicating whether the current object being generated
155 protected bool IsCurrentDelegate {
157 if (currentClass != null && currentClass is CodeTypeDelegate) {
166 /// Gets or sets the amount of spaces to indent.
169 protected int Indent {
171 return output.Indent;
174 output.Indent = value;
180 /// Gets the token that represents <see langword='null'/>.
183 protected abstract string NullToken { get; }
187 /// Gets or sets the System.IO.TextWriter
188 /// to use for output.
191 protected TextWriter Output {
198 /// <para>[To be supplied.]</para>
200 protected CodeGeneratorOptions Options {
206 private void GenerateType(CodeTypeDeclaration e) {
209 if (e.StartDirectives.Count > 0) {
210 GenerateDirectives(e.StartDirectives);
213 GenerateCommentStatements(e.Comments);
215 if (e.LinePragma != null) GenerateLinePragmaStart(e.LinePragma);
217 GenerateTypeStart(e);
219 if (Options.VerbatimOrder) {
220 foreach (CodeTypeMember member in e.Members) {
221 GenerateTypeMember(member, e);
228 GenerateSnippetMembers(e);
230 GenerateTypeConstructors(e);
232 GenerateConstructors(e);
234 GenerateProperties(e);
240 GenerateNestedTypes(e);
242 // Nested types clobber the current class, so reset it.
246 if (e.LinePragma != null) GenerateLinePragmaEnd(e.LinePragma);
248 if (e.EndDirectives.Count > 0) {
249 GenerateDirectives(e.EndDirectives);
254 protected virtual void GenerateDirectives(CodeDirectiveCollection directives) {
257 private void GenerateTypeMember(CodeTypeMember member, CodeTypeDeclaration declaredType) {
259 if (options.BlankLinesBetweenMembers) {
263 if (member is CodeTypeDeclaration) {
264 ((ICodeGenerator)this).GenerateCodeFromType((CodeTypeDeclaration)member, output.InnerWriter, options);
266 // Nested types clobber the current class, so reset it.
267 currentClass = declaredType;
269 // For nested types, comments and line pragmas are handled separately, so return here
273 if (member.StartDirectives.Count > 0) {
274 GenerateDirectives(member.StartDirectives);
277 GenerateCommentStatements(member.Comments);
279 if (member.LinePragma != null) {
280 GenerateLinePragmaStart(member.LinePragma);
283 if (member is CodeMemberField) {
284 GenerateField((CodeMemberField)member);
286 else if (member is CodeMemberProperty) {
287 GenerateProperty((CodeMemberProperty)member, declaredType);
289 else if (member is CodeMemberMethod) {
290 if (member is CodeConstructor) {
291 GenerateConstructor((CodeConstructor)member, declaredType);
293 else if (member is CodeTypeConstructor) {
294 GenerateTypeConstructor((CodeTypeConstructor) member);
296 else if (member is CodeEntryPointMethod) {
297 GenerateEntryPointMethod((CodeEntryPointMethod)member, declaredType);
300 GenerateMethod((CodeMemberMethod)member, declaredType);
303 else if (member is CodeMemberEvent) {
304 GenerateEvent((CodeMemberEvent)member, declaredType);
306 else if (member is CodeSnippetTypeMember) {
308 // Don't indent snippets, in order to preserve the column
309 // information from the original code. This improves the debugging
311 int savedIndent = Indent;
314 GenerateSnippetMember((CodeSnippetTypeMember)member);
316 // Restore the indent
319 // Generate an extra new line at the end of the snippet.
320 // If the snippet is comment and this type only contains comments.
321 // The generated code will not compile.
325 if (member.LinePragma != null) {
326 GenerateLinePragmaEnd(member.LinePragma);
329 if (member.EndDirectives.Count > 0) {
330 GenerateDirectives(member.EndDirectives);
334 private void GenerateTypeConstructors(CodeTypeDeclaration e) {
335 IEnumerator en = e.Members.GetEnumerator();
336 while (en.MoveNext()) {
337 if (en.Current is CodeTypeConstructor) {
338 currentMember = (CodeTypeMember)en.Current;
340 if (options.BlankLinesBetweenMembers) {
343 if (currentMember.StartDirectives.Count > 0) {
344 GenerateDirectives(currentMember.StartDirectives);
346 GenerateCommentStatements(currentMember.Comments);
347 CodeTypeConstructor imp = (CodeTypeConstructor)en.Current;
348 if (imp.LinePragma != null) GenerateLinePragmaStart(imp.LinePragma);
349 GenerateTypeConstructor(imp);
350 if (imp.LinePragma != null) GenerateLinePragmaEnd(imp.LinePragma);
351 if (currentMember.EndDirectives.Count > 0) {
352 GenerateDirectives(currentMember.EndDirectives);
359 /// <para> Generates code for the namepsaces in the specifield CodeDom compile unit.
362 protected void GenerateNamespaces(CodeCompileUnit e) {
363 foreach (CodeNamespace n in e.Namespaces) {
364 ((ICodeGenerator)this).GenerateCodeFromNamespace(n, output.InnerWriter, options);
369 /// <para> Generates code for the specified CodeDom namespace representation and the classes it
372 protected void GenerateTypes(CodeNamespace e) {
373 foreach (CodeTypeDeclaration c in e.Types) {
374 if (options.BlankLinesBetweenMembers) {
377 ((ICodeGenerator)this).GenerateCodeFromType(c, output.InnerWriter, options);
382 bool ICodeGenerator.Supports(GeneratorSupport support) {
383 return this.Supports(support);
387 void ICodeGenerator.GenerateCodeFromType(CodeTypeDeclaration e, TextWriter w, CodeGeneratorOptions o) {
388 bool setLocal = false;
389 if (output != null && w != output.InnerWriter) {
390 throw new InvalidOperationException(SR.GetString(SR.CodeGenOutputWriter));
392 if (output == null) {
394 options = (o == null) ? new CodeGeneratorOptions() : o;
395 output = new IndentedTextWriter(w, options.IndentString);
410 void ICodeGenerator.GenerateCodeFromExpression(CodeExpression e, TextWriter w, CodeGeneratorOptions o) {
411 bool setLocal = false;
412 if (output != null && w != output.InnerWriter) {
413 throw new InvalidOperationException(SR.GetString(SR.CodeGenOutputWriter));
415 if (output == null) {
417 options = (o == null) ? new CodeGeneratorOptions() : o;
418 output = new IndentedTextWriter(w, options.IndentString);
422 GenerateExpression(e);
433 void ICodeGenerator.GenerateCodeFromCompileUnit(CodeCompileUnit e, TextWriter w, CodeGeneratorOptions o) {
434 bool setLocal = false;
435 if (output != null && w != output.InnerWriter) {
436 throw new InvalidOperationException(SR.GetString(SR.CodeGenOutputWriter));
438 if (output == null) {
440 options = (o == null) ? new CodeGeneratorOptions() : o;
441 output = new IndentedTextWriter(w, options.IndentString);
445 if (e is CodeSnippetCompileUnit) {
446 GenerateSnippetCompileUnit((CodeSnippetCompileUnit) e);
449 GenerateCompileUnit(e);
461 void ICodeGenerator.GenerateCodeFromNamespace(CodeNamespace e, TextWriter w, CodeGeneratorOptions o) {
462 bool setLocal = false;
463 if (output != null && w != output.InnerWriter) {
464 throw new InvalidOperationException(SR.GetString(SR.CodeGenOutputWriter));
466 if (output == null) {
468 options = (o == null) ? new CodeGeneratorOptions() : o;
469 output = new IndentedTextWriter(w, options.IndentString);
473 GenerateNamespace(e);
484 void ICodeGenerator.GenerateCodeFromStatement(CodeStatement e, TextWriter w, CodeGeneratorOptions o) {
485 bool setLocal = false;
486 if (output != null && w != output.InnerWriter) {
487 throw new InvalidOperationException(SR.GetString(SR.CodeGenOutputWriter));
489 if (output == null) {
491 options = (o == null) ? new CodeGeneratorOptions() : o;
492 output = new IndentedTextWriter(w, options.IndentString);
496 GenerateStatement(e);
506 public virtual void GenerateCodeFromMember(CodeTypeMember member, TextWriter writer, CodeGeneratorOptions options) {
507 if (this.output != null) {
508 throw new InvalidOperationException(SR.GetString(SR.CodeGenReentrance));
510 this.options = (options == null) ? new CodeGeneratorOptions() : options;
511 this.output = new IndentedTextWriter(writer, this.options.IndentString);
514 CodeTypeDeclaration dummyClass = new CodeTypeDeclaration();
515 this.currentClass = dummyClass;
516 GenerateTypeMember(member, dummyClass);
519 this.currentClass = null;
527 bool ICodeGenerator.IsValidIdentifier(string value) {
528 return this.IsValidIdentifier(value);
531 void ICodeGenerator.ValidateIdentifier(string value) {
532 this.ValidateIdentifier(value);
536 string ICodeGenerator.CreateEscapedIdentifier(string value) {
537 return this.CreateEscapedIdentifier(value);
541 string ICodeGenerator.CreateValidIdentifier(string value) {
542 return this.CreateValidIdentifier(value);
546 string ICodeGenerator.GetTypeOutput(CodeTypeReference type) {
547 return this.GetTypeOutput(type);
550 private void GenerateConstructors(CodeTypeDeclaration e) {
551 IEnumerator en = e.Members.GetEnumerator();
552 while (en.MoveNext()) {
553 if (en.Current is CodeConstructor) {
554 currentMember = (CodeTypeMember)en.Current;
556 if (options.BlankLinesBetweenMembers) {
559 if (currentMember.StartDirectives.Count > 0) {
560 GenerateDirectives(currentMember.StartDirectives);
562 GenerateCommentStatements(currentMember.Comments);
563 CodeConstructor imp = (CodeConstructor)en.Current;
564 if (imp.LinePragma != null) GenerateLinePragmaStart(imp.LinePragma);
565 GenerateConstructor(imp, e);
566 if (imp.LinePragma != null) GenerateLinePragmaEnd(imp.LinePragma);
567 if (currentMember.EndDirectives.Count > 0) {
568 GenerateDirectives(currentMember.EndDirectives);
574 private void GenerateEvents(CodeTypeDeclaration e) {
575 IEnumerator en = e.Members.GetEnumerator();
576 while (en.MoveNext()) {
577 if (en.Current is CodeMemberEvent) {
578 currentMember = (CodeTypeMember)en.Current;
580 if (options.BlankLinesBetweenMembers) {
583 if (currentMember.StartDirectives.Count > 0) {
584 GenerateDirectives(currentMember.StartDirectives);
586 GenerateCommentStatements(currentMember.Comments);
587 CodeMemberEvent imp = (CodeMemberEvent)en.Current;
588 if (imp.LinePragma != null) GenerateLinePragmaStart(imp.LinePragma);
589 GenerateEvent(imp, e);
590 if (imp.LinePragma != null) GenerateLinePragmaEnd(imp.LinePragma);
591 if (currentMember.EndDirectives.Count > 0) {
592 GenerateDirectives(currentMember.EndDirectives);
599 /// <para>Generates code for the specified CodeDom code expression representation.</para>
601 protected void GenerateExpression(CodeExpression e) {
602 if (e is CodeArrayCreateExpression) {
603 GenerateArrayCreateExpression((CodeArrayCreateExpression)e);
605 else if (e is CodeBaseReferenceExpression) {
606 GenerateBaseReferenceExpression((CodeBaseReferenceExpression)e);
608 else if (e is CodeBinaryOperatorExpression) {
609 GenerateBinaryOperatorExpression((CodeBinaryOperatorExpression)e);
611 else if (e is CodeCastExpression) {
612 GenerateCastExpression((CodeCastExpression)e);
614 else if (e is CodeDelegateCreateExpression) {
615 GenerateDelegateCreateExpression((CodeDelegateCreateExpression)e);
617 else if (e is CodeFieldReferenceExpression) {
618 GenerateFieldReferenceExpression((CodeFieldReferenceExpression)e);
620 else if (e is CodeArgumentReferenceExpression) {
621 GenerateArgumentReferenceExpression((CodeArgumentReferenceExpression)e);
623 else if (e is CodeVariableReferenceExpression) {
624 GenerateVariableReferenceExpression((CodeVariableReferenceExpression)e);
626 else if (e is CodeIndexerExpression) {
627 GenerateIndexerExpression((CodeIndexerExpression)e);
629 else if (e is CodeArrayIndexerExpression) {
630 GenerateArrayIndexerExpression((CodeArrayIndexerExpression)e);
632 else if (e is CodeSnippetExpression) {
633 GenerateSnippetExpression((CodeSnippetExpression)e);
635 else if (e is CodeMethodInvokeExpression) {
636 GenerateMethodInvokeExpression((CodeMethodInvokeExpression)e);
638 else if (e is CodeMethodReferenceExpression) {
639 GenerateMethodReferenceExpression((CodeMethodReferenceExpression)e);
641 else if (e is CodeEventReferenceExpression) {
642 GenerateEventReferenceExpression((CodeEventReferenceExpression)e);
644 else if (e is CodeDelegateInvokeExpression) {
645 GenerateDelegateInvokeExpression((CodeDelegateInvokeExpression)e);
647 else if (e is CodeObjectCreateExpression) {
648 GenerateObjectCreateExpression((CodeObjectCreateExpression)e);
650 else if (e is CodeParameterDeclarationExpression) {
651 GenerateParameterDeclarationExpression((CodeParameterDeclarationExpression)e);
653 else if (e is CodeDirectionExpression) {
654 GenerateDirectionExpression((CodeDirectionExpression)e);
656 else if (e is CodePrimitiveExpression) {
657 GeneratePrimitiveExpression((CodePrimitiveExpression)e);
659 else if (e is CodePropertyReferenceExpression) {
660 GeneratePropertyReferenceExpression((CodePropertyReferenceExpression)e);
662 else if (e is CodePropertySetValueReferenceExpression) {
663 GeneratePropertySetValueReferenceExpression((CodePropertySetValueReferenceExpression)e);
665 else if (e is CodeThisReferenceExpression) {
666 GenerateThisReferenceExpression((CodeThisReferenceExpression)e);
668 else if (e is CodeTypeReferenceExpression) {
669 GenerateTypeReferenceExpression((CodeTypeReferenceExpression)e);
671 else if (e is CodeTypeOfExpression) {
672 GenerateTypeOfExpression((CodeTypeOfExpression)e);
674 else if (e is CodeDefaultValueExpression) {
675 GenerateDefaultValueExpression((CodeDefaultValueExpression)e);
679 throw new ArgumentNullException("e");
682 throw new ArgumentException(SR.GetString(SR.InvalidElementType, e.GetType().FullName), "e");
687 private void GenerateFields(CodeTypeDeclaration e) {
688 IEnumerator en = e.Members.GetEnumerator();
689 while (en.MoveNext()) {
690 if (en.Current is CodeMemberField) {
691 currentMember = (CodeTypeMember)en.Current;
693 if (options.BlankLinesBetweenMembers) {
696 if (currentMember.StartDirectives.Count > 0) {
697 GenerateDirectives(currentMember.StartDirectives);
699 GenerateCommentStatements(currentMember.Comments);
700 CodeMemberField imp = (CodeMemberField)en.Current;
701 if (imp.LinePragma != null) GenerateLinePragmaStart(imp.LinePragma);
703 if (imp.LinePragma != null) GenerateLinePragmaEnd(imp.LinePragma);
704 if (currentMember.EndDirectives.Count > 0) {
705 GenerateDirectives(currentMember.EndDirectives);
711 private void GenerateSnippetMembers(CodeTypeDeclaration e) {
712 IEnumerator en = e.Members.GetEnumerator();
713 bool hasSnippet = false;
714 while (en.MoveNext()) {
715 if (en.Current is CodeSnippetTypeMember) {
717 currentMember = (CodeTypeMember)en.Current;
719 if (options.BlankLinesBetweenMembers) {
722 if (currentMember.StartDirectives.Count > 0) {
723 GenerateDirectives(currentMember.StartDirectives);
725 GenerateCommentStatements(currentMember.Comments);
726 CodeSnippetTypeMember imp = (CodeSnippetTypeMember)en.Current;
727 if (imp.LinePragma != null) GenerateLinePragmaStart(imp.LinePragma);
729 // Don't indent snippets, in order to preserve the column
730 // information from the original code. This improves the debugging
732 int savedIndent = Indent;
735 GenerateSnippetMember(imp);
737 // Restore the indent
740 if (imp.LinePragma != null) GenerateLinePragmaEnd(imp.LinePragma);
741 if (currentMember.EndDirectives.Count > 0) {
742 GenerateDirectives(currentMember.EndDirectives);
747 // Generate an extra new line at the end of the snippet.
748 // If the snippet is comment and this type only contains comments.
749 // The generated code will not compile.
756 /// <para> Generates code for the specified snippet code block
759 protected virtual void GenerateSnippetCompileUnit(CodeSnippetCompileUnit e) {
761 GenerateDirectives(e.StartDirectives);
763 if (e.LinePragma != null) GenerateLinePragmaStart(e.LinePragma);
764 Output.WriteLine(e.Value);
765 if (e.LinePragma != null) GenerateLinePragmaEnd(e.LinePragma);
767 if (e.EndDirectives.Count > 0) {
768 GenerateDirectives(e.EndDirectives);
772 private void GenerateMethods(CodeTypeDeclaration e) {
773 IEnumerator en = e.Members.GetEnumerator();
774 while (en.MoveNext()) {
775 if (en.Current is CodeMemberMethod
776 && !(en.Current is CodeTypeConstructor)
777 && !(en.Current is CodeConstructor)) {
778 currentMember = (CodeTypeMember)en.Current;
780 if (options.BlankLinesBetweenMembers) {
783 if (currentMember.StartDirectives.Count > 0) {
784 GenerateDirectives(currentMember.StartDirectives);
786 GenerateCommentStatements(currentMember.Comments);
787 CodeMemberMethod imp = (CodeMemberMethod)en.Current;
788 if (imp.LinePragma != null) GenerateLinePragmaStart(imp.LinePragma);
789 if (en.Current is CodeEntryPointMethod) {
790 GenerateEntryPointMethod((CodeEntryPointMethod)en.Current, e);
793 GenerateMethod(imp, e);
795 if (imp.LinePragma != null) GenerateLinePragmaEnd(imp.LinePragma);
796 if (currentMember.EndDirectives.Count > 0) {
797 GenerateDirectives(currentMember.EndDirectives);
803 private void GenerateNestedTypes(CodeTypeDeclaration e) {
804 IEnumerator en = e.Members.GetEnumerator();
805 while (en.MoveNext()) {
806 if (en.Current is CodeTypeDeclaration) {
807 if (options.BlankLinesBetweenMembers) {
810 CodeTypeDeclaration currentClass = (CodeTypeDeclaration)en.Current;
811 ((ICodeGenerator)this).GenerateCodeFromType(currentClass, output.InnerWriter, options);
817 /// <para> Generates code for the specified CodeDom
818 /// compile unit representation.</para>
820 protected virtual void GenerateCompileUnit(CodeCompileUnit e) {
821 GenerateCompileUnitStart(e);
822 GenerateNamespaces(e);
823 GenerateCompileUnitEnd(e);
827 /// <para> Generates code for the specified CodeDom
828 /// namespace representation.</para>
830 protected virtual void GenerateNamespace(CodeNamespace e) {
831 GenerateCommentStatements(e.Comments);
832 GenerateNamespaceStart(e);
834 GenerateNamespaceImports(e);
835 Output.WriteLine("");
838 GenerateNamespaceEnd(e);
843 /// Generates code for the specified CodeDom based namespace import
847 protected void GenerateNamespaceImports(CodeNamespace e) {
848 IEnumerator en = e.Imports.GetEnumerator();
849 while (en.MoveNext()) {
850 CodeNamespaceImport imp = (CodeNamespaceImport)en.Current;
851 if (imp.LinePragma != null) GenerateLinePragmaStart(imp.LinePragma);
852 GenerateNamespaceImport(imp);
853 if (imp.LinePragma != null) GenerateLinePragmaEnd(imp.LinePragma);
857 private void GenerateProperties(CodeTypeDeclaration e) {
858 IEnumerator en = e.Members.GetEnumerator();
859 while (en.MoveNext()) {
860 if (en.Current is CodeMemberProperty) {
861 currentMember = (CodeTypeMember)en.Current;
863 if (options.BlankLinesBetweenMembers) {
866 if (currentMember.StartDirectives.Count > 0) {
867 GenerateDirectives(currentMember.StartDirectives);
869 GenerateCommentStatements(currentMember.Comments);
870 CodeMemberProperty imp = (CodeMemberProperty)en.Current;
871 if (imp.LinePragma != null) GenerateLinePragmaStart(imp.LinePragma);
872 GenerateProperty(imp, e);
873 if (imp.LinePragma != null) GenerateLinePragmaEnd(imp.LinePragma);
874 if (currentMember.EndDirectives.Count > 0) {
875 GenerateDirectives(currentMember.EndDirectives);
883 /// Generates code for
884 /// the specified CodeDom based statement representation.
887 protected void GenerateStatement(CodeStatement e) {
888 if (e.StartDirectives.Count > 0) {
889 GenerateDirectives(e.StartDirectives);
892 if (e.LinePragma != null) {
893 GenerateLinePragmaStart(e.LinePragma);
896 if (e is CodeCommentStatement) {
897 GenerateCommentStatement((CodeCommentStatement)e);
899 else if (e is CodeMethodReturnStatement) {
900 GenerateMethodReturnStatement((CodeMethodReturnStatement)e);
902 else if (e is CodeConditionStatement) {
903 GenerateConditionStatement((CodeConditionStatement)e);
905 else if (e is CodeTryCatchFinallyStatement) {
906 GenerateTryCatchFinallyStatement((CodeTryCatchFinallyStatement)e);
908 else if (e is CodeAssignStatement) {
909 GenerateAssignStatement((CodeAssignStatement)e);
911 else if (e is CodeExpressionStatement) {
912 GenerateExpressionStatement((CodeExpressionStatement)e);
914 else if (e is CodeIterationStatement) {
915 GenerateIterationStatement((CodeIterationStatement)e);
917 else if (e is CodeThrowExceptionStatement) {
918 GenerateThrowExceptionStatement((CodeThrowExceptionStatement)e);
920 else if (e is CodeSnippetStatement) {
921 // Don't indent snippet statements, in order to preserve the column
922 // information from the original code. This improves the debugging
924 int savedIndent = Indent;
927 GenerateSnippetStatement((CodeSnippetStatement)e);
929 // Restore the indent
932 else if (e is CodeVariableDeclarationStatement) {
933 GenerateVariableDeclarationStatement((CodeVariableDeclarationStatement)e);
935 else if (e is CodeAttachEventStatement) {
936 GenerateAttachEventStatement((CodeAttachEventStatement)e);
938 else if (e is CodeRemoveEventStatement) {
939 GenerateRemoveEventStatement((CodeRemoveEventStatement)e);
941 else if (e is CodeGotoStatement) {
942 GenerateGotoStatement((CodeGotoStatement)e);
944 else if (e is CodeLabeledStatement) {
945 GenerateLabeledStatement((CodeLabeledStatement)e);
948 throw new ArgumentException(SR.GetString(SR.InvalidElementType, e.GetType().FullName), "e");
951 if (e.LinePragma != null) {
952 GenerateLinePragmaEnd(e.LinePragma);
954 if (e.EndDirectives.Count > 0) {
955 GenerateDirectives(e.EndDirectives);
961 /// Generates code for the specified CodeDom based statement representations.
964 protected void GenerateStatements(CodeStatementCollection stms) {
965 IEnumerator en = stms.GetEnumerator();
966 while (en.MoveNext()) {
967 ((ICodeGenerator)this).GenerateCodeFromStatement((CodeStatement)en.Current, output.InnerWriter, options);
973 /// Generates code for the specified System.CodeDom.CodeAttributeBlock.
976 protected virtual void OutputAttributeDeclarations(CodeAttributeDeclarationCollection attributes) {
977 if (attributes.Count == 0) return;
978 GenerateAttributeDeclarationsStart(attributes);
980 IEnumerator en = attributes.GetEnumerator();
981 while (en.MoveNext()) {
986 ContinueOnNewLine(", ");
989 CodeAttributeDeclaration current = (CodeAttributeDeclaration)en.Current;
990 Output.Write(current.Name);
993 bool firstArg = true;
994 foreach (CodeAttributeArgument arg in current.Arguments) {
1002 OutputAttributeArgument(arg);
1008 GenerateAttributeDeclarationsEnd(attributes);
1014 /// Outputs an argument in a attribute block.
1017 protected virtual void OutputAttributeArgument(CodeAttributeArgument arg) {
1018 if (arg.Name != null && arg.Name.Length > 0) {
1019 OutputIdentifier(arg.Name);
1022 ((ICodeGenerator)this).GenerateCodeFromExpression(arg.Value, output.InnerWriter, options);
1027 /// Generates code for the specified System.CodeDom.FieldDirection.
1030 protected virtual void OutputDirection(FieldDirection dir) {
1032 case FieldDirection.In:
1034 case FieldDirection.Out:
1035 Output.Write("out ");
1037 case FieldDirection.Ref:
1038 Output.Write("ref ");
1044 /// <para>[To be supplied.]</para>
1046 protected virtual void OutputFieldScopeModifier(MemberAttributes attributes) {
1047 switch (attributes & MemberAttributes.VTableMask) {
1048 case MemberAttributes.New:
1049 Output.Write("new ");
1053 switch (attributes & MemberAttributes.ScopeMask) {
1054 case MemberAttributes.Final:
1056 case MemberAttributes.Static:
1057 Output.Write("static ");
1059 case MemberAttributes.Const:
1060 Output.Write("const ");
1069 /// Generates code for the specified member access modifier.
1072 protected virtual void OutputMemberAccessModifier(MemberAttributes attributes) {
1073 switch (attributes & MemberAttributes.AccessMask) {
1074 case MemberAttributes.Assembly:
1075 Output.Write("internal ");
1077 case MemberAttributes.FamilyAndAssembly:
1078 Output.Write("internal "); /*FamANDAssem*/
1080 case MemberAttributes.Family:
1081 Output.Write("protected ");
1083 case MemberAttributes.FamilyOrAssembly:
1084 Output.Write("protected internal ");
1086 case MemberAttributes.Private:
1087 Output.Write("private ");
1089 case MemberAttributes.Public:
1090 Output.Write("public ");
1097 /// Generates code for the specified member scope modifier.
1100 protected virtual void OutputMemberScopeModifier(MemberAttributes attributes) {
1101 switch (attributes & MemberAttributes.VTableMask) {
1102 case MemberAttributes.New:
1103 Output.Write("new ");
1107 switch (attributes & MemberAttributes.ScopeMask) {
1108 case MemberAttributes.Abstract:
1109 Output.Write("abstract ");
1111 case MemberAttributes.Final:
1114 case MemberAttributes.Static:
1115 Output.Write("static ");
1117 case MemberAttributes.Override:
1118 Output.Write("override ");
1121 switch (attributes & MemberAttributes.AccessMask) {
1122 case MemberAttributes.Family:
1123 case MemberAttributes.Public:
1124 Output.Write("virtual ");
1136 /// Generates code for the specified type.
1139 protected abstract void OutputType(CodeTypeReference typeRef);
1143 /// Generates code for the specified type attributes.
1146 protected virtual void OutputTypeAttributes(TypeAttributes attributes, bool isStruct, bool isEnum) {
1147 switch(attributes & TypeAttributes.VisibilityMask) {
1148 case TypeAttributes.Public:
1149 case TypeAttributes.NestedPublic:
1150 Output.Write("public ");
1152 case TypeAttributes.NestedPrivate:
1153 Output.Write("private ");
1158 Output.Write("struct ");
1161 Output.Write("enum ");
1164 switch (attributes & TypeAttributes.ClassSemanticsMask) {
1165 case TypeAttributes.Class:
1166 if ((attributes & TypeAttributes.Sealed) == TypeAttributes.Sealed) {
1167 Output.Write("sealed ");
1169 if ((attributes & TypeAttributes.Abstract) == TypeAttributes.Abstract) {
1170 Output.Write("abstract ");
1172 Output.Write("class ");
1174 case TypeAttributes.Interface:
1175 Output.Write("interface ");
1183 /// Generates code for the specified object type and name pair.
1186 protected virtual void OutputTypeNamePair(CodeTypeReference typeRef, string name) {
1187 OutputType(typeRef);
1189 OutputIdentifier(name);
1193 /// <para>[To be supplied.]</para>
1195 protected virtual void OutputIdentifier(string ident) {
1196 Output.Write(ident);
1201 /// Generates code for the specified expression list.
1204 protected virtual void OutputExpressionList(CodeExpressionCollection expressions) {
1205 OutputExpressionList(expressions, false /*newlineBetweenItems*/);
1210 /// Generates code for the specified expression list.
1213 protected virtual void OutputExpressionList(CodeExpressionCollection expressions, bool newlineBetweenItems) {
1215 IEnumerator en = expressions.GetEnumerator();
1217 while (en.MoveNext()) {
1222 if (newlineBetweenItems)
1223 ContinueOnNewLine(",");
1227 ((ICodeGenerator)this).GenerateCodeFromExpression((CodeExpression)en.Current, output.InnerWriter, options);
1234 /// Generates code for the specified operator.
1237 protected virtual void OutputOperator(CodeBinaryOperatorType op) {
1239 case CodeBinaryOperatorType.Add:
1242 case CodeBinaryOperatorType.Subtract:
1245 case CodeBinaryOperatorType.Multiply:
1248 case CodeBinaryOperatorType.Divide:
1251 case CodeBinaryOperatorType.Modulus:
1254 case CodeBinaryOperatorType.Assign:
1257 case CodeBinaryOperatorType.IdentityInequality:
1260 case CodeBinaryOperatorType.IdentityEquality:
1263 case CodeBinaryOperatorType.ValueEquality:
1266 case CodeBinaryOperatorType.BitwiseOr:
1269 case CodeBinaryOperatorType.BitwiseAnd:
1272 case CodeBinaryOperatorType.BooleanOr:
1275 case CodeBinaryOperatorType.BooleanAnd:
1278 case CodeBinaryOperatorType.LessThan:
1281 case CodeBinaryOperatorType.LessThanOrEqual:
1284 case CodeBinaryOperatorType.GreaterThan:
1287 case CodeBinaryOperatorType.GreaterThanOrEqual:
1295 /// Generates code for the specified parameters.
1298 protected virtual void OutputParameters(CodeParameterDeclarationExpressionCollection parameters) {
1300 bool multiline = parameters.Count > ParameterMultilineThreshold;
1304 IEnumerator en = parameters.GetEnumerator();
1305 while (en.MoveNext()) {
1306 CodeParameterDeclarationExpression current = (CodeParameterDeclarationExpression)en.Current;
1314 ContinueOnNewLine("");
1316 GenerateExpression(current);
1325 /// Generates code for the specified CodeDom based array creation expression
1329 protected abstract void GenerateArrayCreateExpression(CodeArrayCreateExpression e);
1332 /// Generates code for the specified CodeDom based base reference expression
1336 protected abstract void GenerateBaseReferenceExpression(CodeBaseReferenceExpression e);
1340 /// Generates code for the specified CodeDom based binary operator
1341 /// expression representation.
1344 protected virtual void GenerateBinaryOperatorExpression(CodeBinaryOperatorExpression e) {
1345 bool indentedExpression = false;
1348 GenerateExpression(e.Left);
1351 if (e.Left is CodeBinaryOperatorExpression || e.Right is CodeBinaryOperatorExpression) {
1352 // In case the line gets too long with nested binary operators, we need to output them on
1353 // different lines. However we want to indent them to maintain readability, but this needs
1354 // to be done only once;
1355 if (!inNestedBinary) {
1356 indentedExpression = true;
1357 inNestedBinary = true;
1360 ContinueOnNewLine("");
1363 OutputOperator(e.Operator);
1366 GenerateExpression(e.Right);
1369 if (indentedExpression) {
1371 inNestedBinary = false;
1376 /// <para>[To be supplied.]</para>
1378 protected virtual void ContinueOnNewLine(string st) {
1379 Output.WriteLine(st);
1384 /// Generates code for the specified CodeDom based cast expression
1388 protected abstract void GenerateCastExpression(CodeCastExpression e);
1391 /// Generates code for the specified CodeDom based delegate creation expression
1395 protected abstract void GenerateDelegateCreateExpression(CodeDelegateCreateExpression e);
1398 /// Generates code for the specified CodeDom based field reference
1399 /// expression representation.
1402 protected abstract void GenerateFieldReferenceExpression(CodeFieldReferenceExpression e);
1405 /// <para>[To be supplied.]</para>
1407 protected abstract void GenerateArgumentReferenceExpression(CodeArgumentReferenceExpression e);
1410 /// <para>[To be supplied.]</para>
1412 protected abstract void GenerateVariableReferenceExpression(CodeVariableReferenceExpression e);
1416 /// Generates code for the specified CodeDom based indexer expression
1420 protected abstract void GenerateIndexerExpression(CodeIndexerExpression e);
1423 /// <para>[To be supplied.]</para>
1425 protected abstract void GenerateArrayIndexerExpression(CodeArrayIndexerExpression e);
1429 /// Generates code for the specified CodeDom based snippet
1430 /// expression representation.
1433 protected abstract void GenerateSnippetExpression(CodeSnippetExpression e);
1436 /// Generates code for the specified CodeDom based method invoke expression
1440 protected abstract void GenerateMethodInvokeExpression(CodeMethodInvokeExpression e);
1443 /// <para>[To be supplied.]</para>
1445 protected abstract void GenerateMethodReferenceExpression(CodeMethodReferenceExpression e);
1448 /// <para>[To be supplied.]</para>
1450 protected abstract void GenerateEventReferenceExpression(CodeEventReferenceExpression e);
1454 /// Generates code for the specified CodeDom based delegate invoke expression
1458 protected abstract void GenerateDelegateInvokeExpression(CodeDelegateInvokeExpression e);
1461 /// Generates code for the specified CodeDom
1462 /// based object creation expression representation.
1465 protected abstract void GenerateObjectCreateExpression(CodeObjectCreateExpression e);
1469 /// Generates code for the specified CodeDom
1470 /// based parameter declaration expression representation.
1473 protected virtual void GenerateParameterDeclarationExpression(CodeParameterDeclarationExpression e) {
1474 if (e.CustomAttributes.Count > 0) {
1475 OutputAttributeDeclarations(e.CustomAttributes);
1479 OutputDirection(e.Direction);
1480 OutputTypeNamePair(e.Type, e.Name);
1484 /// <para>[To be supplied.]</para>
1486 protected virtual void GenerateDirectionExpression(CodeDirectionExpression e) {
1487 OutputDirection(e.Direction);
1488 GenerateExpression(e.Expression);
1494 /// Generates code for the specified CodeDom based primitive expression
1498 protected virtual void GeneratePrimitiveExpression(CodePrimitiveExpression e) {
1499 if (e.Value == null) {
1500 Output.Write(NullToken);
1502 else if (e.Value is string) {
1503 Output.Write(QuoteSnippetString((string)e.Value));
1505 else if (e.Value is char) {
1506 Output.Write("'" + e.Value.ToString() + "'");
1508 else if (e.Value is byte) {
1509 Output.Write(((byte)e.Value).ToString(CultureInfo.InvariantCulture));
1511 else if (e.Value is Int16) {
1512 Output.Write(((Int16)e.Value).ToString(CultureInfo.InvariantCulture));
1514 else if (e.Value is Int32) {
1515 Output.Write(((Int32)e.Value).ToString(CultureInfo.InvariantCulture));
1517 else if (e.Value is Int64) {
1518 Output.Write(((Int64)e.Value).ToString(CultureInfo.InvariantCulture));
1520 else if (e.Value is Single) {
1521 GenerateSingleFloatValue((Single)e.Value);
1523 else if (e.Value is Double) {
1524 GenerateDoubleValue((Double)e.Value);
1526 else if (e.Value is Decimal) {
1527 GenerateDecimalValue((Decimal)e.Value);
1529 else if (e.Value is bool) {
1530 if ((bool)e.Value) {
1531 Output.Write("true");
1534 Output.Write("false");
1538 throw new ArgumentException(SR.GetString(SR.InvalidPrimitiveType, e.Value.GetType().ToString()));
1543 /// <para>[To be supplied.]</para>
1545 protected virtual void GenerateSingleFloatValue(Single s) {
1546 Output.Write(s.ToString("R", CultureInfo.InvariantCulture));
1550 /// <para>[To be supplied.]</para>
1552 protected virtual void GenerateDoubleValue(Double d) {
1553 Output.Write(d.ToString("R", CultureInfo.InvariantCulture));
1557 /// <para>[To be supplied.]</para>
1559 protected virtual void GenerateDecimalValue(Decimal d) {
1560 Output.Write(d.ToString(CultureInfo.InvariantCulture));
1564 protected virtual void GenerateDefaultValueExpression(CodeDefaultValueExpression e) {
1569 /// Generates code for the specified CodeDom based property reference
1570 /// expression representation.
1573 protected abstract void GeneratePropertyReferenceExpression(CodePropertyReferenceExpression e);
1576 /// <para>[To be supplied.]</para>
1578 protected abstract void GeneratePropertySetValueReferenceExpression(CodePropertySetValueReferenceExpression e);
1582 /// Generates code for the specified CodeDom based this reference expression
1586 protected abstract void GenerateThisReferenceExpression(CodeThisReferenceExpression e);
1590 /// Generates code for the specified CodeDom based type reference expression
1594 protected virtual void GenerateTypeReferenceExpression(CodeTypeReferenceExpression e) {
1600 /// Generates code for the specified CodeDom based type of expression
1604 protected virtual void GenerateTypeOfExpression(CodeTypeOfExpression e) {
1605 Output.Write("typeof(");
1612 /// Generates code for the specified CodeDom based method
1613 /// invoke statement representation.
1616 protected abstract void GenerateExpressionStatement(CodeExpressionStatement e);
1619 /// Generates code for the specified CodeDom based for loop statement
1623 protected abstract void GenerateIterationStatement(CodeIterationStatement e);
1626 /// Generates code for the specified CodeDom based throw exception statement
1630 protected abstract void GenerateThrowExceptionStatement(CodeThrowExceptionStatement e);
1633 /// Generates code for the specified CodeDom based comment statement
1637 protected virtual void GenerateCommentStatement(CodeCommentStatement e) {
1638 if(e.Comment == null)
1639 throw new ArgumentException(SR.GetString(SR.Argument_NullComment, "e"), "e");
1640 GenerateComment(e.Comment);
1644 /// <para>[To be supplied.]</para>
1646 protected virtual void GenerateCommentStatements(CodeCommentStatementCollection e) {
1647 foreach (CodeCommentStatement comment in e) {
1648 GenerateCommentStatement(comment);
1653 /// <para>[To be supplied.]</para>
1655 protected abstract void GenerateComment(CodeComment e);
1659 /// Generates code for the specified CodeDom based method return statement
1663 protected abstract void GenerateMethodReturnStatement(CodeMethodReturnStatement e);
1666 /// Generates code for the specified CodeDom based if statement representation.
1669 protected abstract void GenerateConditionStatement(CodeConditionStatement e);
1672 /// Generates code for the specified CodeDom based try catch finally
1673 /// statement representation.
1676 protected abstract void GenerateTryCatchFinallyStatement(CodeTryCatchFinallyStatement e);
1679 /// Generates code for the specified CodeDom based assignment statement
1683 protected abstract void GenerateAssignStatement(CodeAssignStatement e);
1686 /// Generates code for the specified CodeDom based attach event statement
1690 protected abstract void GenerateAttachEventStatement(CodeAttachEventStatement e);
1693 /// Generates code for the specified CodeDom based detach event statement
1697 protected abstract void GenerateRemoveEventStatement(CodeRemoveEventStatement e);
1700 /// <para>[To be supplied.]</para>
1702 protected abstract void GenerateGotoStatement(CodeGotoStatement e);
1705 /// <para>[To be supplied.]</para>
1707 protected abstract void GenerateLabeledStatement(CodeLabeledStatement e);
1711 /// Generates code for the specified CodeDom based snippet statement
1715 protected virtual void GenerateSnippetStatement(CodeSnippetStatement e) {
1716 Output.WriteLine(e.Value);
1721 /// Generates code for the specified CodeDom based variable declaration statement
1725 protected abstract void GenerateVariableDeclarationStatement(CodeVariableDeclarationStatement e);
1729 /// Generates code for the specified CodeDom based line pragma start
1733 protected abstract void GenerateLinePragmaStart(CodeLinePragma e);
1736 /// Generates code for the specified CodeDom based line pragma end
1740 protected abstract void GenerateLinePragmaEnd(CodeLinePragma e);
1743 /// Generates code for the specified CodeDom based event
1747 protected abstract void GenerateEvent(CodeMemberEvent e, CodeTypeDeclaration c);
1750 /// Generates code for the specified CodeDom based member field
1754 protected abstract void GenerateField(CodeMemberField e);
1757 /// Generates code for the specified CodeDom based snippet class member
1761 protected abstract void GenerateSnippetMember(CodeSnippetTypeMember e);
1764 /// <para>[To be supplied.]</para>
1766 protected abstract void GenerateEntryPointMethod(CodeEntryPointMethod e, CodeTypeDeclaration c);
1770 /// Generates code for the specified CodeDom based method
1774 protected abstract void GenerateMethod(CodeMemberMethod e, CodeTypeDeclaration c);
1777 /// Generates code for the specified CodeDom based property
1781 protected abstract void GenerateProperty(CodeMemberProperty e, CodeTypeDeclaration c);
1784 /// Generates code for the specified CodeDom based constructor
1788 protected abstract void GenerateConstructor(CodeConstructor e, CodeTypeDeclaration c);
1791 /// Generates code for the specified CodeDom based class constructor
1795 protected abstract void GenerateTypeConstructor(CodeTypeConstructor e);
1798 /// Generates code for the specified CodeDom based start class representation.
1801 protected abstract void GenerateTypeStart(CodeTypeDeclaration e);
1804 /// Generates code for the specified CodeDom based end class representation.
1807 protected abstract void GenerateTypeEnd(CodeTypeDeclaration e);
1810 /// Generates code for the specified CodeDom based compile unit start
1814 protected virtual void GenerateCompileUnitStart(CodeCompileUnit e) {
1815 if (e.StartDirectives.Count > 0) {
1816 GenerateDirectives(e.StartDirectives);
1821 /// Generates code for the specified CodeDom based compile unit end
1825 protected virtual void GenerateCompileUnitEnd(CodeCompileUnit e) {
1826 if (e.EndDirectives.Count > 0) {
1827 GenerateDirectives(e.EndDirectives);
1832 /// Generates code for the specified CodeDom based namespace start
1836 protected abstract void GenerateNamespaceStart(CodeNamespace e);
1839 /// Generates code for the specified CodeDom based namespace end
1843 protected abstract void GenerateNamespaceEnd(CodeNamespace e);
1846 /// Generates code for the specified CodeDom based namespace import
1850 protected abstract void GenerateNamespaceImport(CodeNamespaceImport e);
1853 /// Generates code for the specified CodeDom based attribute block start
1857 protected abstract void GenerateAttributeDeclarationsStart(CodeAttributeDeclarationCollection attributes);
1860 /// Generates code for the specified CodeDom based attribute block end
1864 protected abstract void GenerateAttributeDeclarationsEnd(CodeAttributeDeclarationCollection attributes);
1867 /// <para>[To be supplied.]</para>
1869 protected abstract bool Supports(GeneratorSupport support);
1873 /// Gets or sets whether the specified value is a value identifier.
1876 protected abstract bool IsValidIdentifier(string value);
1879 /// Gets whether the specified identifier is valid.
1882 protected virtual void ValidateIdentifier(string value) {
1883 if (!IsValidIdentifier(value)) {
1884 throw new ArgumentException(SR.GetString(SR.InvalidIdentifier, value));
1889 /// <para>[To be supplied.]</para>
1891 protected abstract string CreateEscapedIdentifier(string value);
1894 /// <para>[To be supplied.]</para>
1896 protected abstract string CreateValidIdentifier(string value);
1899 /// <para>[To be supplied.]</para>
1901 protected abstract string GetTypeOutput(CodeTypeReference value);
1905 /// Provides conversion to formatting with escape codes.
1908 protected abstract string QuoteSnippetString(string value);
1912 /// Gets a value indicating whether the specified value is a valid language
1913 /// independent identifier.
1916 public static bool IsValidLanguageIndependentIdentifier(string value)
1918 return IsValidTypeNameOrIdentifier(value, false);
1921 internal static bool IsValidLanguageIndependentTypeName(string value)
1923 return IsValidTypeNameOrIdentifier(value, true);
1926 private static bool IsValidTypeNameOrIdentifier(string value, bool isTypeName) {
1927 bool nextMustBeStartChar = true;
1929 if (value.Length == 0)
1932 // each char must be Lu, Ll, Lt, Lm, Lo, Nd, Mn, Mc, Pc
1934 for(int i = 0; i < value.Length; i++) {
1936 UnicodeCategory uc = Char.GetUnicodeCategory(ch);
1938 case UnicodeCategory.UppercaseLetter: // Lu
1939 case UnicodeCategory.LowercaseLetter: // Ll
1940 case UnicodeCategory.TitlecaseLetter: // Lt
1941 case UnicodeCategory.ModifierLetter: // Lm
1942 case UnicodeCategory.LetterNumber: // Lm
1943 case UnicodeCategory.OtherLetter: // Lo
1944 nextMustBeStartChar = false;
1947 case UnicodeCategory.NonSpacingMark: // Mn
1948 case UnicodeCategory.SpacingCombiningMark: // Mc
1949 case UnicodeCategory.ConnectorPunctuation: // Pc
1950 case UnicodeCategory.DecimalDigitNumber: // Nd
1951 // Underscore is a valid starting character, even though it is a ConnectorPunctuation.
1952 if (nextMustBeStartChar && ch != '_')
1955 nextMustBeStartChar = false;
1958 // We only check the special Type chars for type names.
1959 if (isTypeName && IsSpecialTypeChar(ch, ref nextMustBeStartChar)) {
1970 // This can be a special character like a separator that shows up in a type name
1971 // This is an odd set of characters. Some come from characters that are allowed by C++, like < and >.
1972 // Others are characters that are specified in the type and assembly name grammer.
1973 private static bool IsSpecialTypeChar(char ch, ref bool nextMustBeStartChar) {
1987 nextMustBeStartChar = true;
1998 /// Validates a tree to check if all the types and idenfier names follow the rules of an identifier
1999 /// in a langauge independent manner.
2002 public static void ValidateIdentifiers(CodeObject e) {
2003 CodeValidator codeValidator = new CodeValidator(); // This has internal state and hence is not static
2004 codeValidator.ValidateIdentifiers(e);