mirror of https://github.com/icsharpcode/ILSpy.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
220 lines
6.1 KiB
220 lines
6.1 KiB
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team |
|
// |
|
// 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. |
|
|
|
using System; |
|
|
|
using ICSharpCode.Decompiler.CSharp.Syntax; |
|
|
|
namespace ICSharpCode.Decompiler.CSharp.OutputVisitor |
|
{ |
|
class InsertRequiredSpacesDecorator : DecoratingTokenWriter |
|
{ |
|
/// <summary> |
|
/// Used to insert the minimal amount of spaces so that the lexer recognizes the tokens that were written. |
|
/// </summary> |
|
LastWritten lastWritten; |
|
|
|
enum LastWritten |
|
{ |
|
Whitespace, |
|
Other, |
|
KeywordOrIdentifier, |
|
Plus, |
|
Minus, |
|
Ampersand, |
|
QuestionMark, |
|
Division |
|
} |
|
|
|
public InsertRequiredSpacesDecorator(TokenWriter writer) |
|
: base(writer) |
|
{ |
|
} |
|
|
|
public override void WriteIdentifier(Identifier identifier) |
|
{ |
|
if (identifier.IsVerbatim || CSharpOutputVisitor.IsKeyword(identifier.Name, identifier)) |
|
{ |
|
if (lastWritten == LastWritten.KeywordOrIdentifier) |
|
{ |
|
// this space is not strictly required, so we call Space() |
|
Space(); |
|
} |
|
} |
|
else if (lastWritten == LastWritten.KeywordOrIdentifier) |
|
{ |
|
// this space is strictly required, so we directly call the formatter |
|
base.Space(); |
|
} |
|
base.WriteIdentifier(identifier); |
|
lastWritten = LastWritten.KeywordOrIdentifier; |
|
} |
|
|
|
public override void WriteKeyword(Role role, string keyword) |
|
{ |
|
if (lastWritten == LastWritten.KeywordOrIdentifier) |
|
{ |
|
Space(); |
|
} |
|
base.WriteKeyword(role, keyword); |
|
lastWritten = LastWritten.KeywordOrIdentifier; |
|
} |
|
|
|
public override void WriteToken(Role role, string token) |
|
{ |
|
// Avoid that two +, - or ? tokens are combined into a ++, -- or ?? token. |
|
// Note that we don't need to handle tokens like = because there's no valid |
|
// C# program that contains the single token twice in a row. |
|
// (for +, - and &, this can happen with unary operators; |
|
// for ?, this can happen in "a is int? ? b : c" or "a as int? ?? 0"; |
|
// and for /, this can happen with "1/ *ptr" or "1/ //comment".) |
|
if (lastWritten == LastWritten.Plus && token[0] == '+' || |
|
lastWritten == LastWritten.Minus && token[0] == '-' || |
|
lastWritten == LastWritten.Ampersand && token[0] == '&' || |
|
lastWritten == LastWritten.QuestionMark && token[0] == '?' || |
|
lastWritten == LastWritten.Division && token[0] == '*') |
|
{ |
|
base.Space(); |
|
} |
|
base.WriteToken(role, token); |
|
if (token == "+") |
|
{ |
|
lastWritten = LastWritten.Plus; |
|
} |
|
else if (token == "-") |
|
{ |
|
lastWritten = LastWritten.Minus; |
|
} |
|
else if (token == "&") |
|
{ |
|
lastWritten = LastWritten.Ampersand; |
|
} |
|
else if (token == "?") |
|
{ |
|
lastWritten = LastWritten.QuestionMark; |
|
} |
|
else if (token == "/") |
|
{ |
|
lastWritten = LastWritten.Division; |
|
} |
|
else |
|
{ |
|
lastWritten = LastWritten.Other; |
|
} |
|
} |
|
|
|
public override void Space() |
|
{ |
|
base.Space(); |
|
lastWritten = LastWritten.Whitespace; |
|
} |
|
|
|
public override void NewLine() |
|
{ |
|
base.NewLine(); |
|
lastWritten = LastWritten.Whitespace; |
|
} |
|
|
|
public override void WriteComment(CommentType commentType, string content) |
|
{ |
|
if (lastWritten == LastWritten.Division) |
|
{ |
|
// When there's a comment starting after a division operator |
|
// "1.0 / /*comment*/a", then we need to insert a space in front of the comment. |
|
base.Space(); |
|
} |
|
base.WriteComment(commentType, content); |
|
lastWritten = LastWritten.Whitespace; |
|
} |
|
|
|
public override void WritePreProcessorDirective(PreProcessorDirectiveType type, string argument) |
|
{ |
|
base.WritePreProcessorDirective(type, argument); |
|
lastWritten = LastWritten.Whitespace; |
|
} |
|
|
|
public override void WritePrimitiveValue(object value, LiteralFormat format = LiteralFormat.None) |
|
{ |
|
if (lastWritten == LastWritten.KeywordOrIdentifier) |
|
{ |
|
Space(); |
|
} |
|
base.WritePrimitiveValue(value, format); |
|
if (value == null || value is bool) |
|
return; |
|
if (value is string) |
|
{ |
|
if (format == LiteralFormat.VerbatimStringLiteral) |
|
lastWritten = LastWritten.KeywordOrIdentifier; |
|
else |
|
lastWritten = LastWritten.Other; |
|
} |
|
else if (value is char) |
|
{ |
|
lastWritten = LastWritten.Other; |
|
} |
|
else if (value is decimal) |
|
{ |
|
lastWritten = LastWritten.Other; |
|
} |
|
else if (value is float) |
|
{ |
|
float f = (float)value; |
|
if (float.IsInfinity(f) || float.IsNaN(f)) |
|
return; |
|
lastWritten = LastWritten.Other; |
|
} |
|
else if (value is double) |
|
{ |
|
double f = (double)value; |
|
if (double.IsInfinity(f) || double.IsNaN(f)) |
|
return; |
|
// needs space if identifier follows number; |
|
// this avoids mistaking the following identifier as type suffix |
|
lastWritten = LastWritten.KeywordOrIdentifier; |
|
} |
|
else if (value is IFormattable) |
|
{ |
|
// needs space if identifier follows number; |
|
// this avoids mistaking the following identifier as type suffix |
|
lastWritten = LastWritten.KeywordOrIdentifier; |
|
} |
|
else |
|
{ |
|
lastWritten = LastWritten.Other; |
|
} |
|
} |
|
|
|
public override void WritePrimitiveType(string type) |
|
{ |
|
if (lastWritten == LastWritten.KeywordOrIdentifier) |
|
{ |
|
Space(); |
|
} |
|
base.WritePrimitiveType(type); |
|
if (type == "new") |
|
{ |
|
lastWritten = LastWritten.Other; |
|
} |
|
else |
|
{ |
|
lastWritten = LastWritten.KeywordOrIdentifier; |
|
} |
|
} |
|
} |
|
} |