diff --git a/ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs b/ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs index 204d54251..f3f08646b 100644 --- a/ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs +++ b/ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs @@ -980,8 +980,44 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor isAfterSpace = false; EndNode(primitiveExpression); } + + public virtual void VisitInterpolatedStringExpression(InterpolatedStringExpression interpolatedStringExpression) + { + StartNode(interpolatedStringExpression); + + writer.WriteToken(Roles.Error, "$\""); + foreach (var element in interpolatedStringExpression.Content) { + element.AcceptVisitor(this); + } + writer.WriteToken(Roles.Error, "\""); + isAfterSpace = false; + + EndNode(interpolatedStringExpression); + } + + public virtual void VisitInterpolation(Interpolation interpolation) + { + StartNode(interpolation); + + writer.WriteToken(Roles.LBrace, "{"); + interpolation.Expression.AcceptVisitor(this); + if (interpolation.Suffix != null) { + writer.WriteToken(Roles.Colon, ":"); + writer.WritePrimitiveValue("", interpolation.Suffix); + } + writer.WriteToken(Roles.RBrace, "}"); + + EndNode(interpolation); + } + + public virtual void VisitInterpolatedStringText(InterpolatedStringText interpolatedStringText) + { + StartNode(interpolatedStringText); + writer.WritePrimitiveValue("", TextWriterTokenWriter.ConvertString(interpolatedStringText.Text)); + EndNode(interpolatedStringText); + } #endregion - + public virtual void VisitSizeOfExpression(SizeOfExpression sizeOfExpression) { StartNode(sizeOfExpression); diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/DepthFirstAstVisitor.cs b/ICSharpCode.Decompiler/CSharp/Syntax/DepthFirstAstVisitor.cs index 7ec1f288b..043105b6f 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/DepthFirstAstVisitor.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/DepthFirstAstVisitor.cs @@ -445,7 +445,22 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax { VisitChildren (indexerExpression); } - + + public virtual void VisitInterpolatedStringExpression(InterpolatedStringExpression interpolatedStringExpression) + { + VisitChildren(interpolatedStringExpression); + } + + public virtual void VisitInterpolation(Interpolation interpolation) + { + VisitChildren(interpolation); + } + + public virtual void VisitInterpolatedStringText(InterpolatedStringText interpolatedStringText) + { + VisitChildren(interpolatedStringText); + } + public virtual void VisitInvocationExpression (InvocationExpression invocationExpression) { VisitChildren (invocationExpression); @@ -1062,7 +1077,22 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax { return VisitChildren (indexerExpression); } - + + public virtual T VisitInterpolatedStringExpression(InterpolatedStringExpression interpolatedStringExpression) + { + return VisitChildren(interpolatedStringExpression); + } + + public virtual T VisitInterpolation(Interpolation interpolation) + { + return VisitChildren(interpolation); + } + + public virtual T VisitInterpolatedStringText(InterpolatedStringText interpolatedStringText) + { + return VisitChildren(interpolatedStringText); + } + public virtual T VisitInvocationExpression (InvocationExpression invocationExpression) { return VisitChildren (invocationExpression); @@ -1679,7 +1709,22 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax { return VisitChildren (indexerExpression, data); } - + + public virtual S VisitInterpolatedStringExpression(InterpolatedStringExpression interpolatedStringExpression, T data) + { + return VisitChildren(interpolatedStringExpression, data); + } + + public virtual S VisitInterpolation(Interpolation interpolation, T data) + { + return VisitChildren(interpolation, data); + } + + public virtual S VisitInterpolatedStringText(InterpolatedStringText interpolatedStringText, T data) + { + return VisitChildren(interpolatedStringText, data); + } + public virtual S VisitInvocationExpression (InvocationExpression invocationExpression, T data) { return VisitChildren (invocationExpression, data); diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/InterpolatedStringExpression.cs b/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/InterpolatedStringExpression.cs new file mode 100644 index 000000000..e9f38747b --- /dev/null +++ b/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/InterpolatedStringExpression.cs @@ -0,0 +1,169 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching; + +namespace ICSharpCode.Decompiler.CSharp.Syntax +{ + public class InterpolatedStringExpression : Expression + { + public AstNodeCollection Content { + get { return GetChildrenByRole(InterpolatedStringContent.Role); } + } + + public InterpolatedStringExpression() + { + + } + + public override void AcceptVisitor(IAstVisitor visitor) + { + visitor.VisitInterpolatedStringExpression(this); + } + + public override T AcceptVisitor(IAstVisitor visitor) + { + return visitor.VisitInterpolatedStringExpression(this); + } + + public override S AcceptVisitor(IAstVisitor visitor, T data) + { + return visitor.VisitInterpolatedStringExpression(this, data); + } + + protected internal override bool DoMatch(AstNode other, Match match) + { + InterpolatedStringExpression o = other as InterpolatedStringExpression; + return o != null && !o.IsNull && this.Content.DoMatch(o.Content, match); + } + } + + public abstract class InterpolatedStringContent : AstNode + { + #region Null + public new static readonly InterpolatedStringContent Null = new NullInterpolatedStringContent(); + + sealed class NullInterpolatedStringContent : InterpolatedStringContent + { + public override bool IsNull { + get { + return true; + } + } + + public override void AcceptVisitor(IAstVisitor visitor) + { + visitor.VisitNullNode(this); + } + + public override T AcceptVisitor(IAstVisitor visitor) + { + return visitor.VisitNullNode(this); + } + + public override S AcceptVisitor(IAstVisitor visitor, T data) + { + return visitor.VisitNullNode(this, data); + } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + return other == null || other.IsNull; + } + } + #endregion + + public new static readonly Role Role = new Role("InterpolatedStringContent", Syntax.InterpolatedStringContent.Null); + + public override NodeType NodeType => NodeType.Unknown; + } + + /// + /// { Expression } + /// + public class Interpolation : InterpolatedStringContent + { + public CSharpTokenNode LBraceToken { + get { return GetChildByRole(Roles.LBrace); } + } + + public Expression Expression { + get { return GetChildByRole(Roles.Expression); } + set { SetChildByRole(Roles.Expression, value); } + } + + public string Suffix { get; } + + public CSharpTokenNode RBraceToken { + get { return GetChildByRole(Roles.RBrace); } + } + + public Interpolation() + { + + } + + public Interpolation(Expression expression, string suffix = null) + { + Expression = expression; + Suffix = suffix; + } + + public override void AcceptVisitor(IAstVisitor visitor) + { + visitor.VisitInterpolation(this); + } + + public override T AcceptVisitor(IAstVisitor visitor) + { + return visitor.VisitInterpolation(this); + } + + public override S AcceptVisitor(IAstVisitor visitor, T data) + { + return visitor.VisitInterpolation(this, data); + } + + protected internal override bool DoMatch(AstNode other, Match match) + { + Interpolation o = other as Interpolation; + return o != null && this.Expression.DoMatch(o.Expression, match); + } + } + + public class InterpolatedStringText : InterpolatedStringContent + { + public string Text { get; set; } + + public InterpolatedStringText() + { + + } + + public InterpolatedStringText(string text) + { + Text = text; + } + + public override void AcceptVisitor(IAstVisitor visitor) + { + visitor.VisitInterpolatedStringText(this); + } + + public override T AcceptVisitor(IAstVisitor visitor) + { + return visitor.VisitInterpolatedStringText(this); + } + + public override S AcceptVisitor(IAstVisitor visitor, T data) + { + return visitor.VisitInterpolatedStringText(this, data); + } + + protected internal override bool DoMatch(AstNode other, Match match) + { + InterpolatedStringText o = other as InterpolatedStringText; + return o != null && o.Text == this.Text; + } + } +} diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/IAstVisitor.cs b/ICSharpCode.Decompiler/CSharp/Syntax/IAstVisitor.cs index 18f199761..24b8857a6 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/IAstVisitor.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/IAstVisitor.cs @@ -39,6 +39,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax void VisitDirectionExpression(DirectionExpression directionExpression); void VisitIdentifierExpression(IdentifierExpression identifierExpression); void VisitIndexerExpression(IndexerExpression indexerExpression); + void VisitInterpolatedStringExpression(InterpolatedStringExpression interpolatedStringExpression); void VisitInvocationExpression(InvocationExpression invocationExpression); void VisitIsExpression(IsExpression isExpression); void VisitLambdaExpression(LambdaExpression lambdaExpression); @@ -147,6 +148,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax void VisitConstraint(Constraint constraint); void VisitCSharpTokenNode(CSharpTokenNode cSharpTokenNode); void VisitIdentifier(Identifier identifier); + + void VisitInterpolation(Interpolation interpolation); + void VisitInterpolatedStringText(InterpolatedStringText interpolatedStringText); void VisitNullNode(AstNode nullNode); void VisitErrorNode(AstNode errorNode); @@ -173,6 +177,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax S VisitDirectionExpression(DirectionExpression directionExpression); S VisitIdentifierExpression(IdentifierExpression identifierExpression); S VisitIndexerExpression(IndexerExpression indexerExpression); + S VisitInterpolatedStringExpression(InterpolatedStringExpression interpolatedStringExpression); S VisitInvocationExpression(InvocationExpression invocationExpression); S VisitIsExpression(IsExpression isExpression); S VisitLambdaExpression(LambdaExpression lambdaExpression); @@ -281,7 +286,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax S VisitConstraint(Constraint constraint); S VisitCSharpTokenNode(CSharpTokenNode cSharpTokenNode); S VisitIdentifier(Identifier identifier); - + + S VisitInterpolation(Interpolation interpolation); + S VisitInterpolatedStringText(InterpolatedStringText interpolatedStringText); + S VisitNullNode(AstNode nullNode); S VisitErrorNode(AstNode errorNode); S VisitPatternPlaceholder(AstNode placeholder, PatternMatching.Pattern pattern); @@ -307,6 +315,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax S VisitDirectionExpression(DirectionExpression directionExpression, T data); S VisitIdentifierExpression(IdentifierExpression identifierExpression, T data); S VisitIndexerExpression(IndexerExpression indexerExpression, T data); + S VisitInterpolatedStringExpression(InterpolatedStringExpression interpolatedStringExpression, T data); S VisitInvocationExpression(InvocationExpression invocationExpression, T data); S VisitIsExpression(IsExpression isExpression, T data); S VisitLambdaExpression(LambdaExpression lambdaExpression, T data); @@ -415,7 +424,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax S VisitConstraint(Constraint constraint, T data); S VisitCSharpTokenNode(CSharpTokenNode cSharpTokenNode, T data); S VisitIdentifier(Identifier identifier, T data); - + + S VisitInterpolation(Interpolation interpolation, T data); + S VisitInterpolatedStringText(InterpolatedStringText interpolatedStringText, T data); + S VisitNullNode(AstNode nullNode, T data); S VisitErrorNode(AstNode errorNode, T data); S VisitPatternPlaceholder(AstNode placeholder, PatternMatching.Pattern pattern, T data); diff --git a/ICSharpCode.Decompiler/DecompilerSettings.cs b/ICSharpCode.Decompiler/DecompilerSettings.cs index 77e7f9e4d..38df55930 100644 --- a/ICSharpCode.Decompiler/DecompilerSettings.cs +++ b/ICSharpCode.Decompiler/DecompilerSettings.cs @@ -318,6 +318,21 @@ namespace ICSharpCode.Decompiler } } + bool stringInterpolation = true; + + /// + /// Gets/Sets whether to use C# 6.0 string interpolation + /// + public bool StringInterpolation { + get { return stringInterpolation; } + set { + if (stringInterpolation != value) { + stringInterpolation = value; + OnPropertyChanged(); + } + } + } + bool showXmlDocumentation = true; /// diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index 40bfd51dc..f2e6eb7f0 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -88,6 +88,7 @@ +