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.
164 lines
5.3 KiB
164 lines
5.3 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.Collections.Generic; |
|
using System.Linq; |
|
|
|
using ICSharpCode.Decompiler.CSharp.Syntax; |
|
|
|
namespace ICSharpCode.Decompiler.CSharp.OutputVisitor |
|
{ |
|
class InsertMissingTokensDecorator : DecoratingTokenWriter |
|
{ |
|
readonly Stack<List<AstNode>> nodes = new Stack<List<AstNode>>(); |
|
List<AstNode> currentList; |
|
readonly ILocatable locationProvider; |
|
|
|
public InsertMissingTokensDecorator(TokenWriter writer, ILocatable locationProvider) |
|
: base(writer) |
|
{ |
|
this.locationProvider = locationProvider; |
|
currentList = new List<AstNode>(); |
|
} |
|
|
|
public override void StartNode(AstNode node) |
|
{ |
|
// ignore whitespace: these don't need to be processed. |
|
// StartNode/EndNode is only called for them to support folding of comments. |
|
if (node.NodeType != NodeType.Whitespace) |
|
{ |
|
currentList.Add(node); |
|
nodes.Push(currentList); |
|
currentList = new List<AstNode>(); |
|
} |
|
else if (node is Comment comment) |
|
{ |
|
comment.SetStartLocation(locationProvider.Location); |
|
} |
|
if (node is ErrorExpression error) |
|
{ |
|
error.Location = locationProvider.Location; |
|
} |
|
base.StartNode(node); |
|
} |
|
|
|
public override void EndNode(AstNode node) |
|
{ |
|
// ignore whitespace: these don't need to be processed. |
|
// StartNode/EndNode is only called for them to support folding of comments. |
|
if (node.NodeType != NodeType.Whitespace) |
|
{ |
|
System.Diagnostics.Debug.Assert(currentList != null); |
|
foreach (var removable in node.Children.Where(n => n is CSharpTokenNode)) |
|
{ |
|
removable.Remove(); |
|
} |
|
foreach (var child in currentList) |
|
{ |
|
System.Diagnostics.Debug.Assert(child.Parent == null || node == child.Parent); |
|
child.Remove(); |
|
node.AddChildWithExistingRole(child); |
|
} |
|
currentList = nodes.Pop(); |
|
} |
|
else if (node is Comment comment) |
|
{ |
|
comment.SetEndLocation(locationProvider.Location); |
|
} |
|
base.EndNode(node); |
|
} |
|
|
|
public override void WriteToken(Role role, string token) |
|
{ |
|
switch (nodes.Peek().LastOrDefault()) |
|
{ |
|
case EmptyStatement emptyStatement: |
|
emptyStatement.Location = locationProvider.Location; |
|
break; |
|
case ErrorExpression errorExpression: |
|
errorExpression.Location = locationProvider.Location; |
|
break; |
|
default: |
|
CSharpTokenNode t = new CSharpTokenNode(locationProvider.Location, (TokenRole)role); |
|
t.Role = role; |
|
currentList.Add(t); |
|
break; |
|
} |
|
base.WriteToken(role, token); |
|
} |
|
|
|
public override void WriteKeyword(Role role, string keyword) |
|
{ |
|
TextLocation start = locationProvider.Location; |
|
CSharpTokenNode t = null; |
|
if (role is TokenRole) |
|
t = new CSharpTokenNode(start, (TokenRole)role); |
|
else if (role == EntityDeclaration.ModifierRole) |
|
t = new CSharpModifierToken(start, CSharpModifierToken.GetModifierValue(keyword)); |
|
else if (keyword == "this") |
|
{ |
|
ThisReferenceExpression node = nodes.Peek().LastOrDefault() as ThisReferenceExpression; |
|
if (node != null) |
|
node.Location = start; |
|
} |
|
else if (keyword == "base") |
|
{ |
|
BaseReferenceExpression node = nodes.Peek().LastOrDefault() as BaseReferenceExpression; |
|
if (node != null) |
|
node.Location = start; |
|
} |
|
if (t != null) |
|
{ |
|
currentList.Add(t); |
|
t.Role = role; |
|
} |
|
base.WriteKeyword(role, keyword); |
|
} |
|
|
|
public override void WriteIdentifier(Identifier identifier) |
|
{ |
|
if (!identifier.IsNull) |
|
identifier.SetStartLocation(locationProvider.Location); |
|
currentList.Add(identifier); |
|
base.WriteIdentifier(identifier); |
|
} |
|
|
|
public override void WritePrimitiveValue(object value, LiteralFormat format = LiteralFormat.None) |
|
{ |
|
Expression node = nodes.Peek().LastOrDefault() as Expression; |
|
var startLocation = locationProvider.Location; |
|
base.WritePrimitiveValue(value, format); |
|
if (node is PrimitiveExpression) |
|
{ |
|
((PrimitiveExpression)node).SetLocation(startLocation, locationProvider.Location); |
|
} |
|
if (node is NullReferenceExpression) |
|
{ |
|
((NullReferenceExpression)node).SetStartLocation(startLocation); |
|
} |
|
} |
|
|
|
public override void WritePrimitiveType(string type) |
|
{ |
|
PrimitiveType node = nodes.Peek().LastOrDefault() as PrimitiveType; |
|
if (node != null) |
|
node.SetStartLocation(locationProvider.Location); |
|
base.WritePrimitiveType(type); |
|
} |
|
} |
|
}
|
|
|