Free cookie consent management tool by TermsFeed Policy Generator

source: branches/WebJobManager/HeuristicLab.ExtLibs/HeuristicLab.NRefactory/5.5.0/NRefactory.CSharp-5.5.0/OutputVisitor/TextWriterOutputFormatter.cs

Last change on this file was 11700, checked in by jkarder, 10 years ago

#2077: created branch and added first version

File size: 11.5 KB
Line 
1// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy of this
4// software and associated documentation files (the "Software"), to deal in the Software
5// without restriction, including without limitation the rights to use, copy, modify, merge,
6// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7// to whom the Software is furnished to do so, subject to the following conditions:
8//
9// The above copyright notice and this permission notice shall be included in all copies or
10// substantial portions of the Software.
11//
12// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
15// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17// DEALINGS IN THE SOFTWARE.
18
19using System;
20using System.Globalization;
21using System.IO;
22using System.Text;
23
24namespace ICSharpCode.NRefactory.CSharp
25{
26  /// <summary>
27  /// Writes C# code into a TextWriter.
28  /// </summary>
29  public class TextWriterTokenWriter : TokenWriter, ILocatable
30  {
31    readonly TextWriter textWriter;
32    int indentation;
33    bool needsIndent = true;
34    bool isAtStartOfLine = true;
35    int line, column;
36
37    public int Indentation {
38      get { return this.indentation; }
39      set { this.indentation = value; }
40    }
41   
42    public TextLocation Location {
43      get { return new TextLocation(line, column + (needsIndent ? indentation * IndentationString.Length : 0)); }
44    }
45   
46    public string IndentationString { get; set; }
47   
48    public TextWriterTokenWriter(TextWriter textWriter)
49    {
50      if (textWriter == null)
51        throw new ArgumentNullException("textWriter");
52      this.textWriter = textWriter;
53      this.IndentationString = "\t";
54      this.line = 1;
55      this.column = 1;
56    }
57   
58    public override void WriteIdentifier(Identifier identifier)
59    {
60      WriteIndentation();
61      if (identifier.IsVerbatim || CSharpOutputVisitor.IsKeyword(identifier.Name, identifier)) {
62        textWriter.Write('@');
63        column++;
64      }
65      textWriter.Write(identifier.Name);
66      column += identifier.Name.Length;
67      isAtStartOfLine = false;
68    }
69   
70    public override void WriteKeyword(Role role, string keyword)
71    {
72      WriteIndentation();
73      column += keyword.Length;
74      textWriter.Write(keyword);
75      isAtStartOfLine = false;
76    }
77   
78    public override void WriteToken(Role role, string token)
79    {
80      WriteIndentation();
81      column += token.Length;
82      textWriter.Write(token);
83      isAtStartOfLine = false;
84    }
85   
86    public override void Space()
87    {
88      WriteIndentation();
89      column++;
90      textWriter.Write(' ');
91    }
92   
93    protected void WriteIndentation()
94    {
95      if (needsIndent) {
96        needsIndent = false;
97        for (int i = 0; i < indentation; i++) {
98          textWriter.Write(this.IndentationString);
99        }
100        column += indentation * IndentationString.Length;
101      }
102    }
103   
104    public override void NewLine()
105    {
106      textWriter.WriteLine();
107      column = 1;
108      line++;
109      needsIndent = true;
110      isAtStartOfLine = true;
111    }
112   
113    public override void Indent()
114    {
115      indentation++;
116    }
117   
118    public override void Unindent()
119    {
120      indentation--;
121    }
122   
123    public override void WriteComment(CommentType commentType, string content)
124    {
125      WriteIndentation();
126      switch (commentType) {
127        case CommentType.SingleLine:
128          textWriter.Write("//");
129          textWriter.WriteLine(content);
130          column += 2 + content.Length;
131          needsIndent = true;
132          isAtStartOfLine = true;
133          break;
134        case CommentType.MultiLine:
135          textWriter.Write("/*");
136          textWriter.Write(content);
137          textWriter.Write("*/");
138          column += 2;
139          UpdateEndLocation(content, ref line, ref column);
140          column += 2;
141          isAtStartOfLine = false;
142          break;
143        case CommentType.Documentation:
144          textWriter.Write("///");
145          textWriter.WriteLine(content);
146          column += 3 + content.Length;
147          needsIndent = true;
148          isAtStartOfLine = true;
149          break;
150        case CommentType.MultiLineDocumentation:
151          textWriter.Write("/**");
152          textWriter.Write(content);
153          textWriter.Write("*/");
154          column += 3;
155          UpdateEndLocation(content, ref line, ref column);
156          column += 2;
157          isAtStartOfLine = false;
158          break;
159        default:
160          textWriter.Write(content);
161          column += content.Length;
162          break;
163      }
164    }
165   
166    static void UpdateEndLocation(string content, ref int line, ref int column)
167    {
168      if (string.IsNullOrEmpty(content))
169        return;
170      for (int i = 0; i < content.Length; i++) {
171        char ch = content[i];
172        switch (ch) {
173          case '\r':
174            if (i + 1 < content.Length && content[i + 1] == '\n')
175              i++;
176            goto case '\n';
177          case '\n':
178            line++;
179            column = 0;
180            break;
181        }
182        column++;
183      }
184    }
185   
186    public override void WritePreProcessorDirective(PreProcessorDirectiveType type, string argument)
187    {
188      // pre-processor directive must start on its own line
189      if (!isAtStartOfLine)
190        NewLine();
191      WriteIndentation();
192      textWriter.Write('#');
193      string directive = type.ToString().ToLowerInvariant();
194      textWriter.Write(directive);
195      column += 1 + directive.Length;
196      if (!string.IsNullOrEmpty(argument)) {
197        textWriter.Write(' ');
198        textWriter.Write(argument);
199        column += 1 + argument.Length;
200      }
201      NewLine();
202    }
203   
204    public static string PrintPrimitiveValue(object value)
205    {
206      TextWriter writer = new StringWriter();
207      TextWriterTokenWriter tokenWriter = new TextWriterTokenWriter(writer);
208      tokenWriter.WritePrimitiveValue(value);
209      return writer.ToString();
210    }
211   
212    public override void WritePrimitiveValue(object value, string literalValue = null)
213    {
214      if (literalValue != null) {
215        textWriter.Write(literalValue);
216        column += literalValue.Length;
217        return;
218      }
219     
220      if (value == null) {
221        // usually NullReferenceExpression should be used for this, but we'll handle it anyways
222        textWriter.Write("null");
223        column += 4;
224        return;
225      }
226     
227      if (value is bool) {
228        if ((bool)value) {
229          textWriter.Write("true");
230          column += 4;
231        } else {
232          textWriter.Write("false");
233          column += 5;
234        }
235        return;
236      }
237     
238      if (value is string) {
239        string tmp = "\"" + ConvertString(value.ToString()) + "\"";
240        column += tmp.Length;
241        textWriter.Write(tmp);
242      } else if (value is char) {
243        string tmp = "'" + ConvertCharLiteral((char)value) + "'";
244        column += tmp.Length;
245        textWriter.Write(tmp);
246      } else if (value is decimal) {
247        string str = ((decimal)value).ToString(NumberFormatInfo.InvariantInfo) + "m";
248        column += str.Length;
249        textWriter.Write(str);
250      } else if (value is float) {
251        float f = (float)value;
252        if (float.IsInfinity(f) || float.IsNaN(f)) {
253          // Strictly speaking, these aren't PrimitiveExpressions;
254          // but we still support writing these to make life easier for code generators.
255          textWriter.Write("float");
256          column += 5;
257          WriteToken(Roles.Dot, ".");
258          if (float.IsPositiveInfinity(f)) {
259            textWriter.Write("PositiveInfinity");
260            column += "PositiveInfinity".Length;
261          } else if (float.IsNegativeInfinity(f)) {
262            textWriter.Write("NegativeInfinity");
263            column += "NegativeInfinity".Length;
264          } else {
265            textWriter.Write("NaN");
266            column += 3;
267          }
268          return;
269        }
270        if (f == 0 && 1 / f == float.NegativeInfinity) {
271          // negative zero is a special case
272          // (again, not a primitive expression, but it's better to handle
273          // the special case here than to do it in all code generators)
274          textWriter.Write("-");
275          column++;
276        }
277        var str = f.ToString("R", NumberFormatInfo.InvariantInfo) + "f";
278        column += str.Length;
279        textWriter.Write(str);
280      } else if (value is double) {
281        double f = (double)value;
282        if (double.IsInfinity(f) || double.IsNaN(f)) {
283          // Strictly speaking, these aren't PrimitiveExpressions;
284          // but we still support writing these to make life easier for code generators.
285          textWriter.Write("double");
286          column += 6;
287          WriteToken(Roles.Dot, ".");
288          if (double.IsPositiveInfinity(f)) {
289            textWriter.Write("PositiveInfinity");
290            column += "PositiveInfinity".Length;
291          } else if (double.IsNegativeInfinity(f)) {
292            textWriter.Write("NegativeInfinity");
293            column += "NegativeInfinity".Length;
294          } else {
295            textWriter.Write("NaN");
296            column += 3;
297          }
298          return;
299        }
300        if (f == 0 && 1 / f == double.NegativeInfinity) {
301          // negative zero is a special case
302          // (again, not a primitive expression, but it's better to handle
303          // the special case here than to do it in all code generators)
304          textWriter.Write("-");
305        }
306        string number = f.ToString("R", NumberFormatInfo.InvariantInfo);
307        if (number.IndexOf('.') < 0 && number.IndexOf('E') < 0) {
308          number += ".0";
309        }
310        textWriter.Write(number);
311      } else if (value is IFormattable) {
312        StringBuilder b = new StringBuilder ();
313//        if (primitiveExpression.LiteralFormat == LiteralFormat.HexadecimalNumber) {
314//          b.Append("0x");
315//          b.Append(((IFormattable)val).ToString("x", NumberFormatInfo.InvariantInfo));
316//        } else {
317          b.Append(((IFormattable)value).ToString(null, NumberFormatInfo.InvariantInfo));
318//        }
319        if (value is uint || value is ulong) {
320          b.Append("u");
321        }
322        if (value is long || value is ulong) {
323          b.Append("L");
324        }
325        textWriter.Write(b.ToString());
326        column += b.Length;
327      } else {
328        textWriter.Write(value.ToString());
329        column += value.ToString().Length;
330      }
331    }
332   
333    /// <summary>
334    /// Gets the escape sequence for the specified character within a char literal.
335    /// Does not include the single quotes surrounding the char literal.
336    /// </summary>
337    public static string ConvertCharLiteral(char ch)
338    {
339      if (ch == '\'') {
340        return "\\'";
341      }
342      return ConvertChar(ch);
343    }
344   
345    /// <summary>
346    /// Gets the escape sequence for the specified character.
347    /// </summary>
348    /// <remarks>This method does not convert ' or ".</remarks>
349    static string ConvertChar(char ch)
350    {
351      switch (ch) {
352        case '\\':
353          return "\\\\";
354        case '\0':
355          return "\\0";
356        case '\a':
357          return "\\a";
358        case '\b':
359          return "\\b";
360        case '\f':
361          return "\\f";
362        case '\n':
363          return "\\n";
364        case '\r':
365          return "\\r";
366        case '\t':
367          return "\\t";
368        case '\v':
369          return "\\v";
370        default:
371          if (char.IsControl(ch) || char.IsSurrogate(ch) ||
372              // print all uncommon white spaces as numbers
373              (char.IsWhiteSpace(ch) && ch != ' ')) {
374            return "\\u" + ((int)ch).ToString("x4");
375          } else {
376            return ch.ToString();
377          }
378      }
379    }
380   
381    /// <summary>
382    /// Converts special characters to escape sequences within the given string.
383    /// </summary>
384    public static string ConvertString(string str)
385    {
386      StringBuilder sb = new StringBuilder ();
387      foreach (char ch in str) {
388        if (ch == '"') {
389          sb.Append("\\\"");
390        } else {
391          sb.Append(ConvertChar(ch));
392        }
393      }
394      return sb.ToString();
395    }
396   
397    public override void WritePrimitiveType(string type)
398    {
399      textWriter.Write(type);
400      column += type.Length;
401      if (type == "new") {
402        textWriter.Write("()");
403        column += 2;
404      }
405    }
406   
407    public override void StartNode(AstNode node)
408    {
409      // Write out the indentation, so that overrides of this method
410      // can rely use the current output length to identify the position of the node
411      // in the output.
412      WriteIndentation();
413    }
414   
415    public override void EndNode(AstNode node)
416    {
417    }
418  }
419}
Note: See TracBrowser for help on using the repository browser.