2008-08-07 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System / Microsoft.CSharp / CSharpCodeGenerator.cs
index cc1c3dccea9eaa62d9d02e69b7e25d1db4b72cc5..b91480a1fa30872ad9b7ad12933ea67de8c13527 100644 (file)
@@ -40,9 +40,17 @@ namespace Mono.CSharp
        using System.Collections;
        using System.Text;
 
+#if NET_2_0
+       using System.Collections.Generic;
+#endif
+       
        internal class CSharpCodeGenerator
                : CodeGenerator
        {
+#if NET_2_0
+               IDictionary <string, string> providerOptions;
+#endif
+               
                // It is used for beautiful "for" syntax
                bool dont_write_semicolon;
 
@@ -54,6 +62,17 @@ namespace Mono.CSharp
                        dont_write_semicolon = false;
                }
 
+#if NET_2_0
+               public CSharpCodeGenerator (IDictionary <string, string> providerOptions)
+               {
+                       this.providerOptions = providerOptions;
+               }
+
+               protected IDictionary <string, string> ProviderOptions {
+                       get { return providerOptions; }
+               }
+#endif
+               
                //
                // Properties
                //
@@ -261,14 +280,17 @@ namespace Mono.CSharp
 
                protected override void GenerateEventReferenceExpression (CodeEventReferenceExpression expression)
                {
-                       GenerateExpression (expression.TargetObject);
-                       Output.Write ('.');
+                       if (expression.TargetObject != null) {
+                               GenerateExpression (expression.TargetObject);
+                               Output.Write ('.');
+                       }
                        Output.Write (GetSafeName (expression.EventName));
                }
 
                protected override void GenerateDelegateInvokeExpression (CodeDelegateInvokeExpression expression)
                {
-                       GenerateExpression (expression.TargetObject);
+                       if (expression.TargetObject != null)
+                               GenerateExpression (expression.TargetObject);
                        Output.Write ('(');
                        OutputExpressionList (expression.Parameters);
                        Output.Write (')');
@@ -322,7 +344,7 @@ namespace Mono.CSharp
                        GenerateExpression (statement.TestExpression);
                        output.Write ("; ");
                        GenerateStatement (statement.IncrementStatement);
-                       output.Write (") ");
+                       output.Write (")");
                        dont_write_semicolon = false;
                        OutputStartBrace ();
                        ++Indent;
@@ -344,19 +366,32 @@ namespace Mono.CSharp
                protected override void GenerateComment (CodeComment comment)
                {
                        TextWriter output = Output;
-                       string[] lines = comment.Text.Split ('\n');
-                       bool first = true;
-                       foreach (string line in lines){
-                               if (comment.DocComment)
-                                       output.Write ("///");
-                               else
-                                       output.Write ("//");
-                               if (first) {
-                                       output.Write (' ');
-                                       first = false;
+
+                       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 (line);
                        }
+
+                       output.WriteLine ();
                }
 
                protected override void GenerateMethodReturnStatement (CodeMethodReturnStatement statement)
@@ -391,7 +426,7 @@ namespace Mono.CSharp
                                        output.Write (' ');
                                else
                                        output.WriteLine ();
-                               output.WriteLine ("else");
+                               output.Write ("else");
                                OutputStartBrace ();
                                ++Indent;
                                GenerateStatements (falses);
@@ -405,43 +440,42 @@ namespace Mono.CSharp
                        TextWriter output = Output;
                        CodeGeneratorOptions options = Options;
 
-                       output.WriteLine ("try");
+                       output.Write ("try");
                        OutputStartBrace ();
                        ++Indent;
                        GenerateStatements (statement.TryStatements);
                        --Indent;
-                       output.Write ('}');
                        
                        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.WriteLine (")");
+                               output.Write (")");
                                OutputStartBrace ();
                                ++Indent;
                                GenerateStatements (clause.Statements);
                                --Indent;
-                               output.Write ('}');
                        }
 
                        CodeStatementCollection finallies = statement.FinallyStatements;
                        if (finallies.Count > 0) {
+                               output.Write ('}');
                                if (options.ElseOnClosing)
                                        output.Write (' ');
                                else
                                        output.WriteLine ();
-                               output.WriteLine ("finally");
+                               output.Write ("finally");
                                OutputStartBrace ();
                                ++Indent;
                                GenerateStatements (finallies);
                                --Indent;
-                               output.WriteLine ('}');
                        }
 
-                       output.WriteLine();
+                       output.WriteLine('}');
                }
 
                protected override void GenerateAssignStatement (CodeAssignStatement statement)
@@ -469,7 +503,7 @@ namespace Mono.CSharp
                {
                        TextWriter output = Output;
                        GenerateEventReferenceExpression (statement.Event);
-                       Output.Write (" -= ");
+                       output.Write (" -= ");
                        GenerateExpression (statement.Listener);
                        output.WriteLine (';');
                }
@@ -480,15 +514,19 @@ namespace Mono.CSharp
 
                        output.Write ("goto ");
                        output.Write (GetSafeName (statement.Label));
-                       output.Write (";");
+                       output.WriteLine (";");
                }
                
                protected override void GenerateLabeledStatement (CodeLabeledStatement statement)
                {
-                       Output.Write (String.Concat (GetSafeName (statement.Label), ": "));
+                       Indent--;
+                       Output.Write (statement.Label);
+                       Output.WriteLine (":");
+                       Indent++;
 
-                       if (statement.Statement != null)
+                       if (statement.Statement != null) {
                                GenerateStatement (statement.Statement);
+                       }
                }
 
                protected override void GenerateVariableDeclarationStatement (CodeVariableDeclarationStatement statement)
@@ -503,7 +541,9 @@ namespace Mono.CSharp
                                GenerateExpression (initExpression);
                        }
 
-                       output.WriteLine (';');
+                       if (!dont_write_semicolon) {
+                               output.WriteLine (';');
+                       }
                }
 
                protected override void GenerateLinePragmaStart (CodeLinePragma linePragma)
@@ -521,6 +561,9 @@ namespace Mono.CSharp
                {
                        Output.WriteLine ();
                        Output.WriteLine ("#line default");
+#if NET_2_0
+                       Output.WriteLine ("#line hidden");
+#endif
                }
 
                protected override void GenerateEvent (CodeMemberEvent eventRef, CodeTypeDeclaration declaration)
@@ -654,7 +697,7 @@ namespace Mono.CSharp
                        GenerateGenericsConstraints (method.TypeParameters);
 #endif
 
-                       if ((attributes & MemberAttributes.ScopeMask) == MemberAttributes.Abstract || declaration.IsInterface)
+                       if (IsAbstract (attributes) || declaration.IsInterface)
                                output.WriteLine (';');
                        else {
                                OutputStartBrace ();
@@ -665,6 +708,11 @@ namespace Mono.CSharp
                        }
                }
 
+               static bool IsAbstract (MemberAttributes attributes)
+               {
+                       return (attributes & MemberAttributes.ScopeMask) == MemberAttributes.Abstract;
+               }
+
                protected override void GenerateProperty (CodeMemberProperty property,
                                                          CodeTypeDeclaration declaration)
                {
@@ -703,12 +751,12 @@ namespace Mono.CSharp
                                OutputParameters(property.Parameters);
                                output.Write(']');
                        } else {
-                               output.Write (property.Name);
+                               output.Write (GetSafeName (property.Name));
                        }
                        OutputStartBrace ();
                        ++Indent;
 
-                       if (declaration.IsInterface)
+                       if (declaration.IsInterface || IsAbstract (property.Attributes))
                        {
                                if (property.HasGet) output.WriteLine("get;");
                                if (property.HasSet) output.WriteLine("set;");
@@ -778,7 +826,7 @@ namespace Mono.CSharp
                        Indent--;
                        Output.WriteLine ('}');
                }
-               
+
                protected override void GenerateTypeConstructor (CodeTypeConstructor constructor)
                {
                        if (IsCurrentDelegate || IsCurrentEnum || IsCurrentInterface) {
@@ -909,7 +957,18 @@ namespace Mono.CSharp
 
                private void OutputAttributes (CodeAttributeDeclarationCollection attributes, string prefix, bool inline)
                {
+#if NET_2_0
+                       bool params_set = false;
+#endif
+
                        foreach (CodeAttributeDeclaration att in attributes) {
+#if NET_2_0
+                               if (att.Name == "System.ParamArrayAttribute") {
+                                       params_set = true;
+                                       continue;
+                               }
+#endif
+
                                GenerateAttributeDeclarationsStart (attributes);
                                if (prefix != null) {
                                        Output.Write (prefix);
@@ -922,6 +981,18 @@ namespace Mono.CSharp
                                        Output.WriteLine ();
                                }
                        }
+
+#if NET_2_0
+                       if (params_set) {
+                               if (prefix != null)
+                                       Output.Write (prefix);
+                               Output.Write ("params");
+                               if (inline)
+                                       Output.Write (" ");
+                               else
+                                       Output.WriteLine ();
+                       }
+#endif
                }
 
                private void OutputAttributeDeclaration (CodeAttributeDeclaration attribute)
@@ -1094,6 +1165,93 @@ namespace Mono.CSharp
                        return "\"" + output + "\"";
                }
 
+               protected override void GeneratePrimitiveExpression(CodePrimitiveExpression e)
+               {
+                       if (e.Value is char) {
+                               this.GenerateCharValue ((char) e.Value);
+#if NET_2_0
+                       } 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));
+#endif
+                       } 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");
+#if NET_2_0
+                                       Output.Write (((int) c).ToString ("X4", CultureInfo.InvariantCulture));
+#else
+                                       Output.Write (((int) c).ToString (CultureInfo.InvariantCulture));
+#endif
+                                       break;
+                               case '\u2029':
+                                       Output.Write ("\\u");
+#if NET_2_0
+                                       Output.Write (((int) c).ToString ("X4", CultureInfo.InvariantCulture));
+#else
+                                       Output.Write (((int) c).ToString (CultureInfo.InvariantCulture));
+#endif
+                                       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);
@@ -1137,6 +1295,11 @@ namespace Mono.CSharp
     
                protected override string GetTypeOutput (CodeTypeReference type)
                {
+#if NET_2_0
+                       if ((type.Options & CodeTypeReferenceOptions.GenericTypeParameter) != 0)
+                               return type.BaseType;
+#endif
+
                        string typeOutput = null;
 
                        if (type.ArrayElementType != null) {
@@ -1153,6 +1316,7 @@ namespace Mono.CSharp
                                }
                                typeOutput += ']';
                        }
+
                        return typeOutput;
                }
 
@@ -1229,11 +1393,14 @@ namespace Mono.CSharp
                                                                // skip ` character
                                                                i++;
                                                                // determine number of type arguments to output
-                                                               int typeArgCount = baseType[i] - '0';
+                                                               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++;
+                                                               i = end;
                                                                // if next character is . or +, then append .
                                                                if ((i < baseType.Length) && ((baseType[i] == '+') || (baseType[i] == '.'))) {
                                                                        sb.Append ('.');
@@ -1269,12 +1436,36 @@ namespace Mono.CSharp
                        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 ();
 
-                       return !keywordsTable.Contains (identifier);
+                       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)
@@ -1347,31 +1538,42 @@ namespace Mono.CSharp
                        if (count == 0)
                                return;
 
-                       ++Indent;
-                       foreach (CodeTypeParameter p in parameters) {
-                               if (p.Constraints.Count == 0)
-                                       continue;
+                       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 (" : ");
 
-                               bool is_first = true;
-                               foreach (CodeTypeReference r in p.Constraints) {
-                                       if (is_first)
-                                               is_first = false;
-                                       else
+                               for (int j = 0; j < p.Constraints.Count; j++) {
+                                       if (j > 0)
                                                Output.Write (", ");
-                                       OutputType (r);
+                                       OutputType (p.Constraints [j]);
                                }
+
                                if (p.HasConstructorConstraint) {
-                                       if (!is_first)
+                                       if (hasConstraints)
                                                Output.Write (", ");
-                                       Output.Write ("new ()");
+                                       Output.Write ("new");
+                                       if (hasConstraints)
+                                               Output.Write (" ");
+                                       Output.Write ("()");
                                }
-
                        }
-                       --Indent;
+
+                       if (indented)
+                               --Indent;
                }
 
                string GetTypeArguments (CodeTypeReferenceCollection collection)
@@ -1390,6 +1592,10 @@ namespace Mono.CSharp
                {
                        if (count == 0) {
                                return;
+                       } else if (typeArguments.Count == 0) {
+                               // generic type definition
+                               sb.Append ("<>");
+                               return;
                        }
 
                        sb.Append ('<');