.NET Decompiler with support for PDB generation, ReadyToRun, Metadata (&more) - cross-platform!
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

// 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;
}
}
}
}