Xamarin Public Jenkins 6992685b86 Imported Upstream version 4.2.0.179
Former-commit-id: 0a113cb3a6feb7873f632839b1307cc6033cd595
2015-11-10 14:54:39 +00:00

1646 lines
43 KiB
C#

//
// 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 <string, string> providerOptions;
// It is used for beautiful "for" syntax
bool dont_write_semicolon;
//
// Constructors
//
public CSharpCodeGenerator()
{
dont_write_semicolon = false;
}
public CSharpCodeGenerator (IDictionary <string, string> providerOptions)
{
this.providerOptions = providerOptions;
}
protected IDictionary <string, string> 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 (" <autogenerated>"));
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 (" </autogenerated>"));
GenerateComment (new CodeComment ("------------------------------------------------------------------------------"));
Output.WriteLine ();
base.GenerateCompileUnitStart (compileUnit);
}
protected override void GenerateCompileUnit (CodeCompileUnit compileUnit)
{
GenerateCompileUnitStart (compileUnit);
List<CodeNamespaceImport> imports = null;
foreach (CodeNamespace codeNamespace in compileUnit.Namespaces) {
if (!string.IsNullOrEmpty (codeNamespace.Name))
continue;
if (codeNamespace.Imports.Count == 0)
continue;
if (imports == null)
imports = new List<CodeNamespaceImport> ();
foreach (CodeNamespaceImport i in codeNamespace.Imports)
imports.Add (i);
}
if (imports != null) {
imports.Sort ((a, b) => a.Namespace.CompareTo (b.Namespace));
foreach (var import in imports)
GenerateNamespaceImport (import);
Output.WriteLine ();
}
if (compileUnit.AssemblyCustomAttributes.Count > 0) {
OutputAttributes (compileUnit.AssemblyCustomAttributes,
"assembly: ", false);
Output.WriteLine ("");
}
CodeNamespaceImportCollection global_imports = null;
foreach (CodeNamespace codeNamespace in compileUnit.Namespaces) {
if (string.IsNullOrEmpty (codeNamespace.Name)) {
global_imports = codeNamespace.Imports;
codeNamespace.Imports.Clear ();
}
GenerateNamespace (codeNamespace);
if (global_imports != null) {
codeNamespace.Imports.Clear ();
foreach (CodeNamespaceImport ns in global_imports)
codeNamespace.Imports.Add (ns);
global_imports = null;
}
}
GenerateCompileUnitEnd (compileUnit);
}
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 ()
{
lock (keywords) {
if (keywordsTable == null) {
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"
};
}
}