// // Mono.CSharp CSharpCodeProvider Class implementation // // Author: // Daniel Stodden (stodden@in.tum.de) // Marek Safar (marek.safar@seznam.cz) // Ilker Cetinkaya (mail@ilker.de) // // (C) 2002 Ximian, Inc. // // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // namespace Mono.CSharp { using System; using System.CodeDom; using System.CodeDom.Compiler; using System.Globalization; using System.IO; using System.Reflection; using System.Collections; using System.Text; using System.Collections.Generic; internal class CSharpCodeGenerator : CodeGenerator { IDictionary providerOptions; // It is used for beautiful "for" syntax bool dont_write_semicolon; // // Constructors // public CSharpCodeGenerator() { dont_write_semicolon = false; } public CSharpCodeGenerator (IDictionary providerOptions) { this.providerOptions = providerOptions; } protected IDictionary ProviderOptions { get { return providerOptions; } } // // Properties // protected override string NullToken { get { return "null"; } } // // Methods // protected override void GenerateArrayCreateExpression (CodeArrayCreateExpression expression) { // // This tries to replicate MS behavior as good as // possible. // // The Code-Array stuff in ms.net seems to be broken // anyways, or I'm too stupid to understand it. // // I'm sick of it. If you try to develop array // creations, test them on windows. If it works there // but not in mono, drop me a note. I'd be especially // interested in jagged-multidimensional combinations // with proper initialization :} // TextWriter output = Output; output.Write ("new "); CodeExpressionCollection initializers = expression.Initializers; CodeTypeReference createType = expression.CreateType; if (initializers.Count > 0) { OutputType (createType); if (expression.CreateType.ArrayRank == 0) { output.Write ("[]"); } OutputStartBrace (); ++Indent; OutputExpressionList (initializers, true); --Indent; output.Write ("}"); } else { CodeTypeReference arrayType = createType.ArrayElementType; while (arrayType != null) { createType = arrayType; arrayType = arrayType.ArrayElementType; } OutputType (createType); output.Write ('['); CodeExpression size = expression.SizeExpression; if (size != null) GenerateExpression (size); else output.Write (expression.Size); output.Write(']'); } } protected override void GenerateBaseReferenceExpression (CodeBaseReferenceExpression expression) { Output.Write ("base"); } protected override void GenerateCastExpression (CodeCastExpression expression) { TextWriter output = Output; output.Write ("(("); OutputType (expression.TargetType); output.Write (")("); GenerateExpression (expression.Expression); output.Write ("))"); } protected override void GenerateCompileUnitStart (CodeCompileUnit compileUnit) { GenerateComment (new CodeComment ("------------------------------------------------------------------------------")); GenerateComment (new CodeComment (" ")); GenerateComment (new CodeComment (" This code was generated by a tool.")); GenerateComment (new CodeComment (" Mono Runtime Version: " + System.Environment.Version)); GenerateComment (new CodeComment ("")); GenerateComment (new CodeComment (" Changes to this file may cause incorrect behavior and will be lost if ")); GenerateComment (new CodeComment (" the code is regenerated.")); GenerateComment (new CodeComment (" ")); GenerateComment (new CodeComment ("------------------------------------------------------------------------------")); Output.WriteLine (); base.GenerateCompileUnitStart (compileUnit); } protected override void GenerateCompileUnit (CodeCompileUnit compileUnit) { GenerateCompileUnitStart (compileUnit); GenerateGlobalNamespace (compileUnit); if (compileUnit.AssemblyCustomAttributes.Count > 0) { OutputAttributes (compileUnit.AssemblyCustomAttributes, "assembly: ", false); Output.WriteLine (""); } GenerateLocalNamespaces (compileUnit); GenerateCompileUnitEnd (compileUnit); } private void GenerateGlobalNamespace (CodeCompileUnit compileUnit) { CodeNamespace globalNamespace = null; foreach (CodeNamespace codeNamespace in compileUnit.Namespaces) if (string.IsNullOrEmpty (codeNamespace.Name)) globalNamespace = codeNamespace; if (globalNamespace != null) GenerateNamespace (globalNamespace); } private void GenerateLocalNamespaces (CodeCompileUnit compileUnit) { foreach (CodeNamespace codeNamespace in compileUnit.Namespaces) if (!string.IsNullOrEmpty (codeNamespace.Name)) GenerateNamespace (codeNamespace); } protected override void GenerateDefaultValueExpression (CodeDefaultValueExpression e) { Output.Write ("default("); OutputType (e.Type); Output.Write (')'); } protected override void GenerateDelegateCreateExpression (CodeDelegateCreateExpression expression) { TextWriter output = Output; output.Write ("new "); OutputType (expression.DelegateType); output.Write ('('); CodeExpression targetObject = expression.TargetObject; if (targetObject != null) { GenerateExpression (targetObject); Output.Write ('.'); } output.Write (GetSafeName (expression.MethodName)); output.Write (')'); } protected override void GenerateFieldReferenceExpression (CodeFieldReferenceExpression expression) { CodeExpression targetObject = expression.TargetObject; if (targetObject != null) { GenerateExpression (targetObject); Output.Write ('.'); } Output.Write (GetSafeName (expression.FieldName)); } protected override void GenerateArgumentReferenceExpression (CodeArgumentReferenceExpression expression) { Output.Write (GetSafeName (expression.ParameterName)); } protected override void GenerateVariableReferenceExpression (CodeVariableReferenceExpression expression) { Output.Write (GetSafeName (expression.VariableName)); } protected override void GenerateIndexerExpression (CodeIndexerExpression expression) { TextWriter output = Output; GenerateExpression (expression.TargetObject); output.Write ('['); OutputExpressionList (expression.Indices); output.Write (']'); } protected override void GenerateArrayIndexerExpression (CodeArrayIndexerExpression expression) { TextWriter output = Output; GenerateExpression (expression.TargetObject); output.Write ('['); OutputExpressionList (expression.Indices); output.Write (']'); } protected override void GenerateSnippetExpression (CodeSnippetExpression expression) { Output.Write (expression.Value); } protected override void GenerateMethodInvokeExpression (CodeMethodInvokeExpression expression) { TextWriter output = Output; GenerateMethodReferenceExpression (expression.Method); output.Write ('('); OutputExpressionList (expression.Parameters); output.Write (')'); } protected override void GenerateMethodReferenceExpression (CodeMethodReferenceExpression expression) { if (expression.TargetObject != null) { GenerateExpression (expression.TargetObject); Output.Write ('.'); }; Output.Write (GetSafeName (expression.MethodName)); if (expression.TypeArguments.Count > 0) Output.Write (GetTypeArguments (expression.TypeArguments)); } protected override void GenerateEventReferenceExpression (CodeEventReferenceExpression expression) { if (expression.TargetObject != null) { GenerateExpression (expression.TargetObject); Output.Write ('.'); } Output.Write (GetSafeName (expression.EventName)); } protected override void GenerateDelegateInvokeExpression (CodeDelegateInvokeExpression expression) { if (expression.TargetObject != null) GenerateExpression (expression.TargetObject); Output.Write ('('); OutputExpressionList (expression.Parameters); Output.Write (')'); } protected override void GenerateObjectCreateExpression (CodeObjectCreateExpression expression) { Output.Write ("new "); OutputType (expression.CreateType); Output.Write ('('); OutputExpressionList (expression.Parameters); Output.Write (')'); } protected override void GeneratePropertyReferenceExpression (CodePropertyReferenceExpression expression) { CodeExpression targetObject = expression.TargetObject; if (targetObject != null) { GenerateExpression (targetObject); Output.Write ('.'); } Output.Write (GetSafeName (expression.PropertyName )); } protected override void GeneratePropertySetValueReferenceExpression (CodePropertySetValueReferenceExpression expression) { Output.Write ("value"); } protected override void GenerateThisReferenceExpression (CodeThisReferenceExpression expression) { Output.Write ("this"); } protected override void GenerateExpressionStatement (CodeExpressionStatement statement) { GenerateExpression (statement.Expression); if (dont_write_semicolon) return; Output.WriteLine(';'); } protected override void GenerateIterationStatement (CodeIterationStatement statement) { TextWriter output = Output; dont_write_semicolon = true; output.Write ("for ("); GenerateStatement (statement.InitStatement); output.Write ("; "); GenerateExpression (statement.TestExpression); output.Write ("; "); GenerateStatement (statement.IncrementStatement); output.Write (")"); dont_write_semicolon = false; OutputStartBrace (); ++Indent; GenerateStatements (statement.Statements); --Indent; output.WriteLine ('}'); } protected override void GenerateThrowExceptionStatement (CodeThrowExceptionStatement statement) { Output.Write ("throw"); if (statement.ToThrow != null) { Output.Write (' '); GenerateExpression (statement.ToThrow); } Output.WriteLine (";"); } protected override void GenerateComment (CodeComment comment) { TextWriter output = Output; string commentChars = null; if (comment.DocComment) { commentChars = "///"; } else { commentChars = "//"; } output.Write (commentChars); output.Write (' '); string text = comment.Text; for (int i = 0; i < text.Length; i++) { output.Write (text[i]); if (text[i] == '\r') { if (i < (text.Length - 1) && text[i + 1] == '\n') { continue; } output.Write (commentChars); } else if (text[i] == '\n') { output.Write (commentChars); } } output.WriteLine (); } protected override void GenerateMethodReturnStatement (CodeMethodReturnStatement statement) { TextWriter output = Output; if (statement.Expression != null) { output.Write ("return "); GenerateExpression (statement.Expression); output.WriteLine (";"); } else { output.WriteLine ("return;"); } } protected override void GenerateConditionStatement (CodeConditionStatement statement) { TextWriter output = Output; output.Write ("if ("); GenerateExpression (statement.Condition); output.Write (")"); OutputStartBrace (); ++Indent; GenerateStatements (statement.TrueStatements); --Indent; CodeStatementCollection falses = statement.FalseStatements; if (falses.Count > 0) { output.Write ('}'); if (Options.ElseOnClosing) output.Write (' '); else output.WriteLine (); output.Write ("else"); OutputStartBrace (); ++Indent; GenerateStatements (falses); --Indent; } output.WriteLine ('}'); } protected override void GenerateTryCatchFinallyStatement (CodeTryCatchFinallyStatement statement) { TextWriter output = Output; CodeGeneratorOptions options = Options; output.Write ("try"); OutputStartBrace (); ++Indent; GenerateStatements (statement.TryStatements); --Indent; foreach (CodeCatchClause clause in statement.CatchClauses) { output.Write ('}'); if (options.ElseOnClosing) output.Write (' '); else output.WriteLine (); output.Write ("catch ("); OutputTypeNamePair (clause.CatchExceptionType, GetSafeName(clause.LocalName)); output.Write (")"); OutputStartBrace (); ++Indent; GenerateStatements (clause.Statements); --Indent; } CodeStatementCollection finallies = statement.FinallyStatements; if (finallies.Count > 0) { output.Write ('}'); if (options.ElseOnClosing) output.Write (' '); else output.WriteLine (); output.Write ("finally"); OutputStartBrace (); ++Indent; GenerateStatements (finallies); --Indent; } output.WriteLine('}'); } protected override void GenerateAssignStatement (CodeAssignStatement statement) { TextWriter output = Output; GenerateExpression (statement.Left); output.Write (" = "); GenerateExpression (statement.Right); if (dont_write_semicolon) return; output.WriteLine (';'); } protected override void GenerateAttachEventStatement (CodeAttachEventStatement statement) { TextWriter output = Output; GenerateEventReferenceExpression (statement.Event); output.Write (" += "); GenerateExpression (statement.Listener); output.WriteLine (';'); } protected override void GenerateRemoveEventStatement (CodeRemoveEventStatement statement) { TextWriter output = Output; GenerateEventReferenceExpression (statement.Event); output.Write (" -= "); GenerateExpression (statement.Listener); output.WriteLine (';'); } protected override void GenerateGotoStatement (CodeGotoStatement statement) { TextWriter output = Output; output.Write ("goto "); output.Write (GetSafeName (statement.Label)); output.WriteLine (";"); } protected override void GenerateLabeledStatement (CodeLabeledStatement statement) { Indent--; Output.Write (statement.Label); Output.WriteLine (":"); Indent++; if (statement.Statement != null) { GenerateStatement (statement.Statement); } } protected override void GenerateVariableDeclarationStatement (CodeVariableDeclarationStatement statement) { TextWriter output = Output; OutputTypeNamePair (statement.Type, GetSafeName (statement.Name)); CodeExpression initExpression = statement.InitExpression; if (initExpression != null) { output.Write (" = "); GenerateExpression (initExpression); } if (!dont_write_semicolon) { output.WriteLine (';'); } } protected override void GenerateLinePragmaStart (CodeLinePragma linePragma) { Output.WriteLine (); Output.Write ("#line "); Output.Write (linePragma.LineNumber); Output.Write (" \""); Output.Write (linePragma.FileName); Output.Write ("\""); Output.WriteLine (); } protected override void GenerateLinePragmaEnd (CodeLinePragma linePragma) { Output.WriteLine (); Output.WriteLine ("#line default"); Output.WriteLine ("#line hidden"); } protected override void GenerateEvent (CodeMemberEvent eventRef, CodeTypeDeclaration declaration) { if (IsCurrentDelegate || IsCurrentEnum) { return; } OutputAttributes (eventRef.CustomAttributes, null, false); if (eventRef.PrivateImplementationType == null) { OutputMemberAccessModifier (eventRef.Attributes); } Output.Write ("event "); if (eventRef.PrivateImplementationType != null) { OutputTypeNamePair (eventRef.Type, eventRef.PrivateImplementationType.BaseType + "." + eventRef.Name); } else { OutputTypeNamePair (eventRef.Type, GetSafeName (eventRef.Name)); } Output.WriteLine (';'); } protected override void GenerateField (CodeMemberField field) { if (IsCurrentDelegate || IsCurrentInterface) { return; } TextWriter output = Output; OutputAttributes (field.CustomAttributes, null, false); if (IsCurrentEnum) { Output.Write (GetSafeName (field.Name)); } else { MemberAttributes attributes = field.Attributes; OutputMemberAccessModifier (attributes); OutputVTableModifier (attributes); OutputFieldScopeModifier (attributes); OutputTypeNamePair (field.Type, GetSafeName (field.Name)); } CodeExpression initExpression = field.InitExpression; if (initExpression != null) { output.Write (" = "); GenerateExpression (initExpression); } if (IsCurrentEnum) output.WriteLine (','); else output.WriteLine (';'); } protected override void GenerateSnippetMember (CodeSnippetTypeMember member) { Output.Write (member.Text); } protected override void GenerateEntryPointMethod (CodeEntryPointMethod method, CodeTypeDeclaration declaration) { OutputAttributes (method.CustomAttributes, null, false); Output.Write ("public static "); OutputType (method.ReturnType); Output.Write (" Main()"); OutputStartBrace (); Indent++; GenerateStatements (method.Statements); Indent--; Output.WriteLine ("}"); } protected override void GenerateMethod (CodeMemberMethod method, CodeTypeDeclaration declaration) { if (IsCurrentDelegate || IsCurrentEnum) { return; } TextWriter output = Output; OutputAttributes (method.CustomAttributes, null, false); OutputAttributes (method.ReturnTypeCustomAttributes, "return: ", false); MemberAttributes attributes = method.Attributes; if (!IsCurrentInterface) { if (method.PrivateImplementationType == null) { OutputMemberAccessModifier (attributes); OutputVTableModifier (attributes); OutputMemberScopeModifier (attributes); } } else { OutputVTableModifier (attributes); } OutputType (method.ReturnType); output.Write (' '); CodeTypeReference privateType = method.PrivateImplementationType; if (privateType != null) { output.Write (privateType.BaseType); output.Write ('.'); } output.Write (GetSafeName (method.Name)); GenerateGenericsParameters (method.TypeParameters); output.Write ('('); OutputParameters (method.Parameters); output.Write (')'); GenerateGenericsConstraints (method.TypeParameters); if (IsAbstract (attributes) || declaration.IsInterface) output.WriteLine (';'); else { OutputStartBrace (); ++Indent; GenerateStatements (method.Statements); --Indent; output.WriteLine ('}'); } } static bool IsAbstract (MemberAttributes attributes) { return (attributes & MemberAttributes.ScopeMask) == MemberAttributes.Abstract; } protected override void GenerateProperty (CodeMemberProperty property, CodeTypeDeclaration declaration) { if (IsCurrentDelegate || IsCurrentEnum) { return; } TextWriter output = Output; OutputAttributes (property.CustomAttributes, null, false); MemberAttributes attributes = property.Attributes; if (!IsCurrentInterface) { if (property.PrivateImplementationType == null) { OutputMemberAccessModifier (attributes); OutputVTableModifier (attributes); OutputMemberScopeModifier (attributes); } } else { OutputVTableModifier (attributes); } OutputType (property.Type); output.Write (' '); if (!IsCurrentInterface && property.PrivateImplementationType != null) { output.Write (property.PrivateImplementationType.BaseType); output.Write ('.'); } // only consider property indexer if name is Item (case-insensitive // comparison) AND property has parameters if (string.Compare(property.Name, "Item", true, CultureInfo.InvariantCulture) == 0 && property.Parameters.Count > 0) { output.Write ("this["); OutputParameters(property.Parameters); output.Write(']'); } else { output.Write (GetSafeName (property.Name)); } OutputStartBrace (); ++Indent; if (declaration.IsInterface || IsAbstract (property.Attributes)) { if (property.HasGet) output.WriteLine("get;"); if (property.HasSet) output.WriteLine("set;"); } else { if (property.HasGet) { output.Write ("get"); OutputStartBrace (); ++Indent; GenerateStatements (property.GetStatements); --Indent; output.WriteLine ('}'); } if (property.HasSet) { output.Write ("set"); OutputStartBrace (); ++Indent; GenerateStatements (property.SetStatements); --Indent; output.WriteLine ('}'); } } --Indent; output.WriteLine ('}'); } protected override void GenerateConstructor (CodeConstructor constructor, CodeTypeDeclaration declaration) { if (IsCurrentDelegate || IsCurrentEnum || IsCurrentInterface) { return; } OutputAttributes (constructor.CustomAttributes, null, false); OutputMemberAccessModifier (constructor.Attributes); Output.Write (GetSafeName (CurrentTypeName) + "("); OutputParameters (constructor.Parameters); Output.Write (")"); if (constructor.BaseConstructorArgs.Count > 0) { Output.WriteLine (" : "); Indent += 2; Output.Write ("base("); OutputExpressionList (constructor.BaseConstructorArgs); Output.Write (')'); Indent -= 2; } if (constructor.ChainedConstructorArgs.Count > 0) { Output.WriteLine (" : "); Indent += 2; Output.Write("this("); OutputExpressionList (constructor.ChainedConstructorArgs); Output.Write(')'); Indent -= 2; } OutputStartBrace (); Indent++; GenerateStatements (constructor.Statements); Indent--; Output.WriteLine ('}'); } protected override void GenerateTypeConstructor (CodeTypeConstructor constructor) { if (IsCurrentDelegate || IsCurrentEnum || IsCurrentInterface) { return; } OutputAttributes (constructor.CustomAttributes, null, false); Output.Write ("static " + GetSafeName (CurrentTypeName) + "()"); OutputStartBrace (); Indent++; GenerateStatements (constructor.Statements); Indent--; Output.WriteLine ('}'); } protected override void GenerateTypeStart(CodeTypeDeclaration declaration) { TextWriter output = Output; OutputAttributes (declaration.CustomAttributes, null, false); if (!IsCurrentDelegate) { OutputTypeAttributes (declaration); output.Write (GetSafeName (declaration.Name)); GenerateGenericsParameters (declaration.TypeParameters); IEnumerator enumerator = declaration.BaseTypes.GetEnumerator (); if (enumerator.MoveNext ()) { CodeTypeReference type = (CodeTypeReference) enumerator.Current; output.Write (" : "); OutputType (type); while (enumerator.MoveNext ()) { type = (CodeTypeReference) enumerator.Current; output.Write (", "); OutputType (type); } } GenerateGenericsConstraints (declaration.TypeParameters); OutputStartBrace (); ++Indent; } else { if ((declaration.TypeAttributes & TypeAttributes.VisibilityMask) == TypeAttributes.Public) { output.Write ("public "); } CodeTypeDelegate delegateDecl = (CodeTypeDelegate) declaration; output.Write ("delegate "); OutputType (delegateDecl.ReturnType); output.Write (" "); output.Write (GetSafeName (declaration.Name)); output.Write ("("); OutputParameters (delegateDecl.Parameters); output.WriteLine (");"); } } protected override void GenerateTypeEnd (CodeTypeDeclaration declaration) { if (!IsCurrentDelegate) { --Indent; Output.WriteLine ("}"); } } protected override void GenerateNamespaceStart (CodeNamespace ns) { TextWriter output = Output; string name = ns.Name; if (name != null && name.Length != 0) { output.Write ("namespace "); output.Write (GetSafeName (name)); OutputStartBrace (); ++Indent; } } protected override void GenerateNamespaceEnd (CodeNamespace ns) { string name = ns.Name; if (name != null && name.Length != 0) { --Indent; Output.WriteLine ("}"); } } protected override void GenerateNamespaceImport (CodeNamespaceImport import) { TextWriter output = Output; output.Write ("using "); output.Write (GetSafeName (import.Namespace)); output.WriteLine (';'); } protected override void GenerateAttributeDeclarationsStart (CodeAttributeDeclarationCollection attributes) { Output.Write ('['); } protected override void GenerateAttributeDeclarationsEnd (CodeAttributeDeclarationCollection attributes) { Output.Write (']'); } private void OutputStartBrace () { if (Options.BracingStyle == "C") { Output.WriteLine (""); Output.WriteLine ("{"); } else { Output.WriteLine (" {"); } } private void OutputAttributes (CodeAttributeDeclarationCollection attributes, string prefix, bool inline) { bool params_set = false; foreach (CodeAttributeDeclaration att in attributes) { if (att.Name == "System.ParamArrayAttribute") { params_set = true; continue; } GenerateAttributeDeclarationsStart (attributes); if (prefix != null) { Output.Write (prefix); } OutputAttributeDeclaration (att); GenerateAttributeDeclarationsEnd (attributes); if (inline) { Output.Write (" "); } else { Output.WriteLine (); } } if (params_set) { if (prefix != null) Output.Write (prefix); Output.Write ("params"); if (inline) Output.Write (" "); else Output.WriteLine (); } } private void OutputAttributeDeclaration (CodeAttributeDeclaration attribute) { Output.Write (attribute.Name.Replace ('+', '.')); Output.Write ('('); IEnumerator enumerator = attribute.Arguments.GetEnumerator (); if (enumerator.MoveNext ()) { CodeAttributeArgument argument = (CodeAttributeArgument) enumerator.Current; OutputAttributeArgument (argument); while (enumerator.MoveNext ()) { Output.Write (", "); argument = (CodeAttributeArgument) enumerator.Current; OutputAttributeArgument (argument); } } Output.Write (')'); } protected override void OutputType (CodeTypeReference type) { Output.Write (GetTypeOutput (type)); } private void OutputVTableModifier (MemberAttributes attributes) { if ((attributes & MemberAttributes.VTableMask) == MemberAttributes.New) { Output.Write ("new "); } } protected override void OutputFieldScopeModifier (MemberAttributes attributes) { switch (attributes & MemberAttributes.ScopeMask) { case MemberAttributes.Static: Output.Write ("static "); break; case MemberAttributes.Const: Output.Write ("const "); break; } } // Note: this method should in fact be private as in .NET 2.0, the // CSharpCodeGenerator no longer derives from CodeGenerator but we // still need to make this change. protected override void OutputMemberAccessModifier (MemberAttributes attributes) { switch (attributes & MemberAttributes.AccessMask) { case MemberAttributes.Assembly: case MemberAttributes.FamilyAndAssembly: Output.Write ("internal "); break; case MemberAttributes.Family: Output.Write ("protected "); break; case MemberAttributes.FamilyOrAssembly: Output.Write ("protected internal "); break; case MemberAttributes.Private: Output.Write ("private "); break; case MemberAttributes.Public: Output.Write ("public "); break; } } // Note: this method should in fact be private as in .NET 2.0, the // CSharpCodeGenerator no longer derives from CodeGenerator but we // still need to make this change. protected override void OutputMemberScopeModifier (MemberAttributes attributes) { switch (attributes & MemberAttributes.ScopeMask) { case MemberAttributes.Abstract: Output.Write ("abstract "); break; case MemberAttributes.Final: // do nothing break; case MemberAttributes.Static: Output.Write ("static "); break; case MemberAttributes.Override: Output.Write ("override "); break; default: MemberAttributes access = attributes & MemberAttributes.AccessMask; if (access == MemberAttributes.Assembly || access == MemberAttributes.Family || access == MemberAttributes.Public) { Output.Write ("virtual "); } break; } } private void OutputTypeAttributes (CodeTypeDeclaration declaration) { TextWriter output = Output; TypeAttributes attributes = declaration.TypeAttributes; switch (attributes & TypeAttributes.VisibilityMask) { case TypeAttributes.Public: case TypeAttributes.NestedPublic: output.Write ("public "); break; case TypeAttributes.NestedPrivate: output.Write ("private "); break; case TypeAttributes.NotPublic: case TypeAttributes.NestedFamANDAssem: case TypeAttributes.NestedAssembly: output.Write ("internal "); break; case TypeAttributes.NestedFamily: output.Write ("protected "); break; case TypeAttributes.NestedFamORAssem: output.Write ("protected internal "); break; } if ((declaration.Attributes & MemberAttributes.New) != 0) output.Write ("new "); if (declaration.IsStruct) { if (declaration.IsPartial) { output.Write ("partial "); } output.Write ("struct "); } else if (declaration.IsEnum) { output.Write ("enum "); } else { if ((attributes & TypeAttributes.Interface) != 0) { if (declaration.IsPartial) { output.Write ("partial "); } output.Write ("interface "); } else { if ((attributes & TypeAttributes.Sealed) != 0) output.Write ("sealed "); if ((attributes & TypeAttributes.Abstract) != 0) output.Write ("abstract "); if (declaration.IsPartial) { output.Write ("partial "); } output.Write ("class "); } } } [MonoTODO ("Implement missing special characters")] protected override string QuoteSnippetString (string value) { // FIXME: this is weird, but works. string output = value.Replace ("\\", "\\\\"); output = output.Replace ("\"", "\\\""); output = output.Replace ("\t", "\\t"); output = output.Replace ("\r", "\\r"); output = output.Replace ("\n", "\\n"); return "\"" + output + "\""; } protected override void GeneratePrimitiveExpression(CodePrimitiveExpression e) { if (e.Value is char) { this.GenerateCharValue ((char) e.Value); } else if (e.Value is ushort) { ushort uc = (ushort) e.Value; Output.Write (uc.ToString(CultureInfo.InvariantCulture)); } else if (e.Value is uint) { uint ui = (uint) e.Value; Output.Write (ui.ToString(CultureInfo.InvariantCulture)); Output.Write ("u"); } else if (e.Value is ulong) { ulong ul = (ulong) e.Value; Output.Write (ul.ToString(CultureInfo.InvariantCulture)); Output.Write ("ul"); } else if (e.Value is sbyte) { sbyte sb = (sbyte) e.Value; Output.Write (sb.ToString(CultureInfo.InvariantCulture)); } else { base.GeneratePrimitiveExpression (e); } } private void GenerateCharValue (char c) { Output.Write ('\''); switch (c) { case '\0': Output.Write ("\\0"); break; case '\t': Output.Write ("\\t"); break; case '\n': Output.Write ("\\n"); break; case '\r': Output.Write ("\\r"); break; case '"': Output.Write ("\\\""); break; case '\'': Output.Write ("\\'"); break; case '\\': Output.Write ("\\\\"); break; case '\u2028': Output.Write ("\\u"); Output.Write (((int) c).ToString ("X4", CultureInfo.InvariantCulture)); break; case '\u2029': Output.Write ("\\u"); Output.Write (((int) c).ToString ("X4", CultureInfo.InvariantCulture)); break; default: Output.Write (c); break; } Output.Write ('\''); } protected override void GenerateSingleFloatValue (float f) { base.GenerateSingleFloatValue (f); base.Output.Write ('F'); } protected override void GenerateDecimalValue (decimal d) { base.GenerateDecimalValue (d); base.Output.Write ('m'); } protected override void GenerateParameterDeclarationExpression (CodeParameterDeclarationExpression e) { OutputAttributes (e.CustomAttributes, null, true); OutputDirection (e.Direction); OutputType (e.Type); Output.Write (' '); Output.Write (GetSafeName (e.Name)); } protected override void GenerateTypeOfExpression (CodeTypeOfExpression e) { Output.Write ("typeof("); OutputType (e.Type); Output.Write (")"); } /* * ICodeGenerator */ protected override string CreateEscapedIdentifier (string value) { if (value == null) throw new NullReferenceException ("Argument identifier is null."); return GetSafeName (value); } protected override string CreateValidIdentifier (string value) { if (value == null) throw new NullReferenceException (); if (keywordsTable == null) FillKeywordTable (); if (keywordsTable.Contains (value)) return "_" + value; else return value; } protected override string GetTypeOutput (CodeTypeReference type) { if ((type.Options & CodeTypeReferenceOptions.GenericTypeParameter) != 0) return type.BaseType; string typeOutput = null; if (type.ArrayElementType != null) { typeOutput = GetTypeOutput (type.ArrayElementType); } else { typeOutput = DetermineTypeOutput (type); } int rank = type.ArrayRank; if (rank > 0) { typeOutput += '['; for (--rank; rank > 0; --rank) { typeOutput += ','; } typeOutput += ']'; } return typeOutput; } private string DetermineTypeOutput (CodeTypeReference type) { string typeOutput = null; string baseType = type.BaseType; switch (baseType.ToLower (System.Globalization.CultureInfo.InvariantCulture)) { case "system.int32": typeOutput = "int"; break; case "system.int64": typeOutput = "long"; break; case "system.int16": typeOutput = "short"; break; case "system.boolean": typeOutput = "bool"; break; case "system.char": typeOutput = "char"; break; case "system.string": typeOutput = "string"; break; case "system.object": typeOutput = "object"; break; case "system.void": typeOutput = "void"; break; case "system.byte": typeOutput = "byte"; break; case "system.sbyte": typeOutput = "sbyte"; break; case "system.decimal": typeOutput = "decimal"; break; case "system.double": typeOutput = "double"; break; case "system.single": typeOutput = "float"; break; case "system.uint16": typeOutput = "ushort"; break; case "system.uint32": typeOutput = "uint"; break; case "system.uint64": typeOutput = "ulong"; break; default: StringBuilder sb = new StringBuilder (baseType.Length); if ((type.Options & CodeTypeReferenceOptions.GlobalReference) != 0) { sb.Append ("global::"); } int lastProcessedChar = 0; for (int i = 0; i < baseType.Length; i++) { char currentChar = baseType[i]; if (currentChar != '+' && currentChar != '.') { if (currentChar == '`') { sb.Append (CreateEscapedIdentifier (baseType.Substring ( lastProcessedChar, i - lastProcessedChar))); // skip ` character i++; // determine number of type arguments to output int end = i; while (end < baseType.Length && Char.IsDigit (baseType [end])) end++; int typeArgCount = Int32.Parse (baseType.Substring (i, end - i)); // output type arguments OutputTypeArguments (type.TypeArguments, sb, typeArgCount); // skip type argument indicator i = end; // if next character is . or +, then append . if ((i < baseType.Length) && ((baseType[i] == '+') || (baseType[i] == '.'))) { sb.Append ('.'); // skip character that we just processed i++; } // save postion of last processed character lastProcessedChar = i; } } else { sb.Append (CreateEscapedIdentifier (baseType.Substring ( lastProcessedChar, i - lastProcessedChar))); sb.Append ('.'); // skip separator i++; // save postion of last processed character lastProcessedChar = i; } } // add characters that have not yet been processed if (lastProcessedChar < baseType.Length) { sb.Append (CreateEscapedIdentifier (baseType.Substring (lastProcessedChar))); } typeOutput = sb.ToString (); break; } return typeOutput; } static bool is_identifier_start_character (char c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == '@' || Char.IsLetter (c); } static bool is_identifier_part_character (char c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= '0' && c <= '9') || Char.IsLetter (c); } protected override bool IsValidIdentifier (string identifier) { if (identifier == null || identifier.Length == 0) return false; if (keywordsTable == null) FillKeywordTable (); if (keywordsTable.Contains (identifier)) return false; if (!is_identifier_start_character (identifier [0])) return false; for (int i = 1; i < identifier.Length; i ++) if (! is_identifier_part_character (identifier [i])) return false; return true; } protected override bool Supports (GeneratorSupport supports) { return true; } protected override void GenerateDirectives (CodeDirectiveCollection directives) { foreach (CodeDirective d in directives) { if (d is CodeChecksumPragma) { GenerateCodeChecksumPragma ((CodeChecksumPragma)d); continue; } if (d is CodeRegionDirective) { GenerateCodeRegionDirective ((CodeRegionDirective)d); continue; } throw new NotImplementedException ("Unknown CodeDirective"); } } void GenerateCodeChecksumPragma (CodeChecksumPragma pragma) { Output.Write ("#pragma checksum "); Output.Write (QuoteSnippetString (pragma.FileName)); Output.Write (" \""); Output.Write (pragma.ChecksumAlgorithmId.ToString ("B")); Output.Write ("\" \""); if (pragma.ChecksumData != null) { foreach (byte b in pragma.ChecksumData) { Output.Write (b.ToString ("X2")); } } Output.WriteLine ("\""); } void GenerateCodeRegionDirective (CodeRegionDirective region) { switch (region.RegionMode) { case CodeRegionMode.Start: Output.Write ("#region "); Output.WriteLine (region.RegionText); return; case CodeRegionMode.End: Output.WriteLine ("#endregion"); return; } } void GenerateGenericsParameters (CodeTypeParameterCollection parameters) { int count = parameters.Count; if (count == 0) return; Output.Write ('<'); for (int i = 0; i < count - 1; ++i) { Output.Write (parameters [i].Name); Output.Write (", "); } Output.Write (parameters [count - 1].Name); Output.Write ('>'); } void GenerateGenericsConstraints (CodeTypeParameterCollection parameters) { int count = parameters.Count; if (count == 0) return; bool indented = false; for (int i = 0; i < count; i++) { CodeTypeParameter p = parameters [i]; bool hasConstraints = (p.Constraints.Count != 0); Output.WriteLine (); if (!hasConstraints && !p.HasConstructorConstraint) continue; if (!indented) { ++Indent; indented = true; } Output.Write ("where "); Output.Write (p.Name); Output.Write (" : "); for (int j = 0; j < p.Constraints.Count; j++) { if (j > 0) Output.Write (", "); OutputType (p.Constraints [j]); } if (p.HasConstructorConstraint) { if (hasConstraints) Output.Write (", "); Output.Write ("new"); if (hasConstraints) Output.Write (" "); Output.Write ("()"); } } if (indented) --Indent; } string GetTypeArguments (CodeTypeReferenceCollection collection) { StringBuilder sb = new StringBuilder (" <"); foreach (CodeTypeReference r in collection) { sb.Append (GetTypeOutput (r)); sb.Append (", "); } sb.Length--; sb [sb.Length - 1] = '>'; return sb.ToString (); } private void OutputTypeArguments (CodeTypeReferenceCollection typeArguments, StringBuilder sb, int count) { if (count == 0) { return; } else if (typeArguments.Count == 0) { // generic type definition sb.Append ("<>"); return; } sb.Append ('<'); // write first type argument sb.Append (GetTypeOutput (typeArguments[0])); // subsequent type argument are prefixed by ', ' separator for (int i = 1; i < count; i++) { sb.Append (", "); sb.Append (GetTypeOutput (typeArguments[i])); } sb.Append ('>'); } #if false //[MonoTODO] public override void ValidateIdentifier (string identifier) { } #endif private string GetSafeName (string id) { if (keywordsTable == null) { FillKeywordTable (); } if (keywordsTable.Contains (id)) { return "@" + id; } else { return id; } } static void FillKeywordTable () { keywordsTable = new Hashtable (); foreach (string keyword in keywords) { keywordsTable.Add (keyword, keyword); } } private static Hashtable keywordsTable; private static string[] keywords = new string[] { "abstract","event","new","struct","as","explicit","null","switch","base","extern", "this","false","operator","throw","break","finally","out","true", "fixed","override","try","case","params","typeof","catch","for", "private","foreach","protected","checked","goto","public", "unchecked","class","if","readonly","unsafe","const","implicit","ref", "continue","in","return","using","virtual","default", "interface","sealed","volatile","delegate","internal","do","is", "sizeof","while","lock","stackalloc","else","static","enum", "namespace", "object","bool","byte","float","uint","char","ulong","ushort", "decimal","int","sbyte","short","double","long","string","void", "partial", "yield", "where" }; } }