From e6c0091ba29dc2acfaa6635034d1a37805beea1b Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Mon, 21 Feb 2011 14:46:31 +0100 Subject: [PATCH 1/4] Implement pattern matching for statements. --- .../CSharp/Ast/Statements/CheckedStatement.cs | 8 +++- .../Ast/Statements/ContinueStatement.cs | 8 +++- .../CSharp/Ast/Statements/DoWhileStatement.cs | 8 +++- .../CSharp/Ast/Statements/EmptyStatement.cs | 8 +++- .../CSharp/Ast/Statements/FixedStatement.cs | 6 +++ .../CSharp/Ast/Statements/ForeachStatement.cs | 9 ++++- .../CSharp/Ast/Statements/GotoStatement.cs | 38 +++++++++---------- .../CSharp/Ast/Statements/LabelStatement.cs | 12 +++++- .../CSharp/Ast/Statements/LockStatement.cs | 8 +++- .../CSharp/Ast/Statements/ReturnStatement.cs | 8 +++- .../CSharp/Ast/Statements/Statement.cs | 5 --- .../CSharp/Ast/Statements/SwitchStatement.cs | 6 +++ .../CSharp/Ast/Statements/ThrowStatement.cs | 8 +++- .../Ast/Statements/UncheckedStatement.cs | 8 +++- .../CSharp/Ast/Statements/UnsafeStatement.cs | 8 +++- .../CSharp/Ast/Statements/WhileStatement.cs | 8 +++- .../Ast/Statements/YieldBreakStatement.cs | 8 +++- .../CSharp/Ast/Statements/YieldStatement.cs | 8 +++- 18 files changed, 133 insertions(+), 39 deletions(-) diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/CheckedStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/CheckedStatement.cs index 1461a64079..d80dc6d572 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/CheckedStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/CheckedStatement.cs @@ -1,4 +1,4 @@ -// +// // CheckedStatement.cs // // Author: @@ -44,5 +44,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitCheckedStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + CheckedStatement o = other as CheckedStatement; + return o != null && this.Body.DoMatch(o.Body, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/ContinueStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/ContinueStatement.cs index 7dc06c596c..1de6b5d505 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/ContinueStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/ContinueStatement.cs @@ -1,4 +1,4 @@ -// +// // ContinueStatement.cs // // Author: @@ -39,5 +39,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitContinueStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + ContinueStatement o = other as ContinueStatement; + return o != null; + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/DoWhileStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/DoWhileStatement.cs index 51d5f4708e..378fd43ab0 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/DoWhileStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/DoWhileStatement.cs @@ -1,4 +1,4 @@ -// +// // DoWhileStatement.cs // // Author: @@ -68,6 +68,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitDoWhileStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + DoWhileStatement o = other as DoWhileStatement; + return o != null && this.EmbeddedStatement.DoMatch(o.EmbeddedStatement, match) && this.Condition.DoMatch(o.Condition, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/EmptyStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/EmptyStatement.cs index 7a9528b869..3ee53863e5 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/EmptyStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/EmptyStatement.cs @@ -1,4 +1,4 @@ -// +// // EmptyStatement.cs // // Author: @@ -52,5 +52,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitEmptyStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + EmptyStatement o = other as EmptyStatement; + return o != null; + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/FixedStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/FixedStatement.cs index d500c8dbfa..b1b7759f03 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/FixedStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/FixedStatement.cs @@ -63,5 +63,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitFixedStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + FixedStatement o = other as FixedStatement; + return o != null && this.Variables.DoMatch(o.Variables, match) && this.EmbeddedStatement.DoMatch(o.EmbeddedStatement, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/ForeachStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/ForeachStatement.cs index ca75d6d0dc..6caf3883e7 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/ForeachStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/ForeachStatement.cs @@ -1,4 +1,4 @@ -// +// // ForeachStatement.cs // // Author: @@ -75,5 +75,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitForeachStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + ForeachStatement o = other as ForeachStatement; + return o != null && this.VariableType.DoMatch(o.VariableType, match) && MatchString(this.VariableName, o.VariableName) + && this.InExpression.DoMatch(o.InExpression, match) && this.EmbeddedStatement.DoMatch(o.EmbeddedStatement, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/GotoStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/GotoStatement.cs index ee1784ad7a..2eeeb0bc39 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/GotoStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/GotoStatement.cs @@ -56,14 +56,6 @@ namespace ICSharpCode.NRefactory.CSharp } } - /// - /// Used for "goto case LabelExpression;" - /// - public Expression LabelExpression { - get { return GetChildByRole (Roles.Expression); } - set { SetChildByRole (Roles.Expression, value); } - } - public CSharpTokenNode SemicolonToken { get { return GetChildByRole (Roles.Semicolon); } } @@ -72,6 +64,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitGotoStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + GotoStatement o = other as GotoStatement; + return o != null && MatchString(this.Label, o.Label); + } } /// @@ -89,18 +87,6 @@ namespace ICSharpCode.NRefactory.CSharp get { return GetChildByRole (CaseKeywordRole); } } - public string Label { - get { - return GetChildByRole (Roles.Identifier).Name; - } - set { - if (string.IsNullOrEmpty(value)) - SetChildByRole(Roles.Identifier, null); - else - SetChildByRole(Roles.Identifier, new Identifier(value, AstLocation.Empty)); - } - } - /// /// Used for "goto case LabelExpression;" /// @@ -117,6 +103,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitGotoCaseStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + GotoCaseStatement o = other as GotoCaseStatement; + return o != null && this.LabelExpression.DoMatch(o.LabelExpression, match); + } } /// @@ -142,5 +134,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitGotoDefaultStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + GotoDefaultStatement o = other as GotoDefaultStatement; + return o != null; + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/LabelStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/LabelStatement.cs index da9dc52731..3ebdc3302c 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/LabelStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/LabelStatement.cs @@ -1,4 +1,4 @@ -// +// // LabelStatement.cs // // Author: @@ -40,9 +40,19 @@ namespace ICSharpCode.NRefactory.CSharp } } + public CSharpTokenNode Colon { + get { return GetChildByRole (Roles.Colon); } + } + public override S AcceptVisitor (IAstVisitor visitor, T data) { return visitor.VisitLabelStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + LabelStatement o = other as LabelStatement; + return o != null && MatchString(this.Label, o.Label); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/LockStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/LockStatement.cs index 3866dbd174..7298e4f1da 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/LockStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/LockStatement.cs @@ -1,4 +1,4 @@ -// +// // LockStatement.cs // // Author: @@ -57,5 +57,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitLockStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + LockStatement o = other as LockStatement; + return o != null && this.Expression.DoMatch(o.Expression, match) && this.EmbeddedStatement.DoMatch(o.EmbeddedStatement, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/ReturnStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/ReturnStatement.cs index 938fcb6792..d8368d4421 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/ReturnStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/ReturnStatement.cs @@ -1,4 +1,4 @@ -// +// // ReturnStatement.cs // // Author: @@ -48,5 +48,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitReturnStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + ReturnStatement o = other as ReturnStatement; + return o != null && this.Expression.DoMatch(o.Expression, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/Statement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/Statement.cs index 1725255f42..0d678ff59f 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/Statement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/Statement.cs @@ -52,10 +52,5 @@ namespace ICSharpCode.NRefactory.CSharp public override NodeType NodeType { get { return NodeType.Statement; } } - - protected internal override bool DoMatch(AstNode other, ICSharpCode.NRefactory.CSharp.PatternMatching.Match match) - { - throw new NotImplementedException(); - } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/SwitchStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/SwitchStatement.cs index f8218d507e..09b82be631 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/SwitchStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/SwitchStatement.cs @@ -69,6 +69,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitSwitchStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + SwitchStatement o = other as SwitchStatement; + return o != null && this.Expression.DoMatch(o.Expression, match) && this.SwitchSections.DoMatch(o.SwitchSections, match); + } } public class SwitchSection : AstNode diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/ThrowStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/ThrowStatement.cs index 545dc6ac3f..fc9f34237b 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/ThrowStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/ThrowStatement.cs @@ -1,4 +1,4 @@ -// +// // ThrowStatement.cs // // Author: @@ -48,5 +48,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitThrowStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + ThrowStatement o = other as ThrowStatement; + return o != null && this.Expression.DoMatch(o.Expression, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/UncheckedStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/UncheckedStatement.cs index ec55c0cbce..a0bef129eb 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/UncheckedStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/UncheckedStatement.cs @@ -1,4 +1,4 @@ -// +// // UncheckedStatement.cs // // Author: @@ -44,5 +44,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitUncheckedStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + UncheckedStatement o = other as UncheckedStatement; + return o != null && this.Body.DoMatch(o.Body, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/UnsafeStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/UnsafeStatement.cs index d9a45a8602..c5ccb63af3 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/UnsafeStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/UnsafeStatement.cs @@ -1,4 +1,4 @@ -// +// // UnsafeStatement.cs // // Author: @@ -44,5 +44,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitUnsafeStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + UnsafeStatement o = other as UnsafeStatement; + return o != null && this.Body.DoMatch(o.Body, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/WhileStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/WhileStatement.cs index 9eec22b2fe..01470b3ab2 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/WhileStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/WhileStatement.cs @@ -1,4 +1,4 @@ -// +// // WhileStatement.cs // // Author: @@ -59,5 +59,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitWhileStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + WhileStatement o = other as WhileStatement; + return o != null && this.Condition.DoMatch(o.Condition, match) && this.EmbeddedStatement.DoMatch(o.EmbeddedStatement, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/YieldBreakStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/YieldBreakStatement.cs index 2982dbf416..4c572615ad 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/YieldBreakStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/YieldBreakStatement.cs @@ -1,4 +1,4 @@ -// +// // YieldBreakStatement.cs // // Author: @@ -50,5 +50,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitYieldBreakStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + YieldBreakStatement o = other as YieldBreakStatement; + return o != null; + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/YieldStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/YieldStatement.cs index 531d21ec54..001815f3a8 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/YieldStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/YieldStatement.cs @@ -1,4 +1,4 @@ -// +// // YieldStatement.cs // // Author: @@ -55,5 +55,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitYieldStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + YieldStatement o = other as YieldStatement; + return o != null && this.Expression.DoMatch(o.Expression, match); + } } } From eeb4ea5aff89313428190a4bec29ea75c1c5b674 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Mon, 21 Feb 2011 16:22:10 +0100 Subject: [PATCH 2/4] Add simple backtracking support to pattern matching. --- .../CSharp/Ast/AstNodeCollection.cs | 54 ++++++++++++------- .../Ast/PatternMatching/Backreference.cs | 24 +++++++++ .../CSharp/Ast/PatternMatching/Pattern.cs | 20 +++++-- .../CSharp/Ast/PatternMatching/Repeat.cs | 21 ++++---- 4 files changed, 85 insertions(+), 34 deletions(-) diff --git a/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs b/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs index 5a5218773b..0287b2eb2a 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs @@ -4,6 +4,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using ICSharpCode.NRefactory.CSharp.PatternMatching; @@ -156,29 +157,44 @@ namespace ICSharpCode.NRefactory.CSharp internal bool DoMatch(AstNodeCollection other, Match match) { - AstNode cur1 = this.node.FirstChild; - AstNode cur2 = other.node.FirstChild; - while (true) { - while (cur1 != null && cur1.Role != role) + Stack patternStack = new Stack(); + Stack stack = new Stack(); + patternStack.Push(this.node.FirstChild); + stack.Push(new Pattern.PossibleMatch(other.node.FirstChild, match.CheckPoint())); + while (stack.Count > 0) { + AstNode cur1 = patternStack.Pop(); + AstNode cur2 = stack.Peek().NextOther; + match.RestoreCheckPoint(stack.Pop().Checkpoint); + bool success = true; + while (cur1 != null && success) { + while (cur1 != null && cur1.Role != role) + cur1 = cur1.NextSibling; + while (cur2 != null && cur2.Role != role) + cur2 = cur2.NextSibling; + if (cur1 == null) + break; + + Pattern pattern = cur1 as Pattern; + if (pattern == null && cur1.NodeType == NodeType.Pattern) + pattern = cur1.GetChildByRole(TypePlaceholder.ChildRole) as Pattern; + if (pattern != null) { + Debug.Assert(stack.Count == patternStack.Count); + success = pattern.DoMatchCollection(role, cur2, match, stack); + Debug.Assert(stack.Count >= patternStack.Count); + while (stack.Count > patternStack.Count) + patternStack.Push(cur1.NextSibling); + } else { + success = cur1.DoMatch(cur2, match); + } cur1 = cur1.NextSibling; - while (cur2 != null && cur2.Role != role) - cur2 = cur2.NextSibling; - if (cur1 == null || cur2 == null) - break; - Pattern pattern = cur1 as Pattern; - if (pattern == null && cur1.NodeType == NodeType.Pattern) - pattern = cur1.GetChildByRole(TypePlaceholder.ChildRole) as Pattern; - if (pattern != null) { - if (!pattern.DoMatchCollection(role, ref cur2, match)) - return false; - } else { - if (!cur1.DoMatch(cur2, match)) - return false; cur2 = cur2.NextSibling; } - cur1 = cur1.NextSibling; + while (cur2 != null && cur2.Role != role) + cur2 = cur2.NextSibling; + if (success && cur2 == null) + return true; } - return cur1 == null && cur2 == null; + return false; } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Backreference.cs b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Backreference.cs index db3e3ecebf..dd9f2b5aa2 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Backreference.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Backreference.cs @@ -25,4 +25,28 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching return match.Get(referencedGroupName).Last().Match(other) != null; } } + + /// + /// Matches identifier expressions that have the same identifier as the referenced variable/type definition/method definition. + /// + public class IdentifierExpressionBackreference : Pattern + { + readonly string referencedGroupName; + + public IdentifierExpressionBackreference(string referencedGroupName) + { + if (referencedGroupName == null) + throw new ArgumentNullException("referencedGroupName"); + this.referencedGroupName = referencedGroupName; + } + + protected internal override bool DoMatch(AstNode other, Match match) + { + IdentifierExpression ident = other as IdentifierExpression; + if (ident == null || ident.TypeArguments.Any()) + return false; + AstNode referenced = match.Get(referencedGroupName).Last(); + return ident.Identifier == referenced.GetChildByRole(AstNode.Roles.Identifier).Name; + } + } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs index ab5efbe8dc..1c68d670e9 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs @@ -2,6 +2,8 @@ // This code is distributed under MIT X11 license (for details please see \doc\license.txt) using System; +using System.Collections.Generic; +using System.Diagnostics; namespace ICSharpCode.NRefactory.CSharp.PatternMatching { @@ -14,11 +16,21 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching get { return NodeType.Pattern; } } - protected internal virtual bool DoMatchCollection(Role role, ref AstNode other, Match match) + internal struct PossibleMatch { - bool result = DoMatch(other, match); - other = other.NextSibling; - return result; + public readonly AstNode NextOther; // next node after the last matched node + public readonly int Checkpoint; // checkpoint + + public PossibleMatch(AstNode nextOther, int checkpoint) + { + this.NextOther = nextOther; + this.Checkpoint = checkpoint; + } + } + + internal virtual bool DoMatchCollection(Role role, AstNode pos, Match match, Stack backtrackingStack) + { + return DoMatch(pos, match); } public override S AcceptVisitor(IAstVisitor visitor, T data) diff --git a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Repeat.cs b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Repeat.cs index 3c2bc56530..2ec1183da0 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Repeat.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Repeat.cs @@ -2,6 +2,7 @@ // This code is distributed under MIT X11 license (for details please see \doc\license.txt) using System; +using System.Collections.Generic; using System.Diagnostics; namespace ICSharpCode.NRefactory.CSharp.PatternMatching @@ -20,24 +21,22 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching AddChild(childNode, ElementRole); } - protected internal override bool DoMatchCollection(Role role, ref AstNode other, Match match) + internal override bool DoMatchCollection(Role role, AstNode pos, Match match, Stack backtrackingStack) { - Debug.Assert(other != null && other.Role == role); + Debug.Assert(pos == null || pos.Role == role); int matchCount = 0; - var lastValidCheckpoint = match.CheckPoint(); + if (this.MinCount <= 0) + backtrackingStack.Push(new PossibleMatch(pos, match.CheckPoint())); AstNode element = GetChildByRole(ElementRole); - AstNode pos = other; - while (pos != null && element.DoMatch(pos, match)) { + while (matchCount < this.MaxCount && pos != null && element.DoMatch(pos, match)) { matchCount++; - lastValidCheckpoint = match.CheckPoint(); do { pos = pos.NextSibling; } while (pos != null && pos.Role != role); - // set 'other' (=pointer in collection) to the next node after the valid match - other = pos; + if (matchCount >= this.MinCount) + backtrackingStack.Push(new PossibleMatch(pos, match.CheckPoint())); } - match.RestoreCheckPoint(lastValidCheckpoint); // restote old checkpoint after failed match - return matchCount >= MinCount && matchCount <= MaxCount; + return false; // never do a normal (single-element) match; always make the caller look at the results on the back-tracking stack. } protected internal override bool DoMatch(AstNode other, Match match) @@ -45,7 +44,7 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching if (other == null || other.IsNull) return this.MinCount <= 0; else - return GetChildByRole(ElementRole).DoMatch(other, match); + return this.MaxCount >= 1 && GetChildByRole(ElementRole).DoMatch(other, match); } } } From 38faf8415d3fc8ae6e85e483de2253d057cc2b57 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Mon, 21 Feb 2011 17:56:54 +0100 Subject: [PATCH 3/4] Add support for 'any' operator and fix a bug in pattern matching. --- .../CSharp/Ast/AstNodeCollection.cs | 3 ++- .../CSharp/Ast/Expressions/AssignmentExpression.cs | 6 +++++- .../Ast/Expressions/BinaryOperatorExpression.cs | 12 +++++++++--- .../CSharp/Ast/Expressions/PrimitiveExpression.cs | 4 +++- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs b/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs index 0287b2eb2a..8ffc29157b 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs @@ -187,7 +187,8 @@ namespace ICSharpCode.NRefactory.CSharp success = cur1.DoMatch(cur2, match); } cur1 = cur1.NextSibling; - cur2 = cur2.NextSibling; + if (cur2 != null) + cur2 = cur2.NextSibling; } while (cur2 != null && cur2.Role != role) cur2 = cur2.NextSibling; diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/AssignmentExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/AssignmentExpression.cs index f3b31a7508..6db96ec894 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/AssignmentExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/AssignmentExpression.cs @@ -75,7 +75,8 @@ namespace ICSharpCode.NRefactory.CSharp protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) { AssignmentExpression o = other as AssignmentExpression; - return o != null && this.Left.DoMatch(o.Left, match) && this.Operator == o.Operator && this.Right.DoMatch(o.Right, match); + return o != null && (this.Operator == AssignmentOperatorType.Any || this.Operator == o.Operator) + && this.Left.DoMatch(o.Left, match) && this.Right.DoMatch(o.Right, match); } public static string GetOperatorSymbol(AssignmentOperatorType op) @@ -136,5 +137,8 @@ namespace ICSharpCode.NRefactory.CSharp BitwiseOr, /// left ^= right ExclusiveOr, + + /// Any operator (for pattern matching) + Any } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/BinaryOperatorExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/BinaryOperatorExpression.cs index 464699b68c..171e3e31c2 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/BinaryOperatorExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/BinaryOperatorExpression.cs @@ -1,6 +1,6 @@ // // BinaryOperatorExpression.cs -// +// // Author: // Mike Krüger // @@ -75,7 +75,8 @@ namespace ICSharpCode.NRefactory.CSharp protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) { BinaryOperatorExpression o = other as BinaryOperatorExpression; - return o != null && this.Left.DoMatch(o.Left, match) && this.Operator == o.Operator && this.Right.DoMatch(o.Right, match); + return o != null && (this.Operator == BinaryOperatorType.Any || this.Operator == o.Operator) + && this.Left.DoMatch(o.Left, match) && this.Right.DoMatch(o.Right, match); } public static string GetOperatorSymbol(BinaryOperatorType op) @@ -173,6 +174,11 @@ namespace ICSharpCode.NRefactory.CSharp ShiftRight, /// left ?? right - NullCoalescing + NullCoalescing, + + /// + /// Any binary operator (used in pattern matching) + /// + Any } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/PrimitiveExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/PrimitiveExpression.cs index ca1b274434..cc4fbe1c04 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/PrimitiveExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/PrimitiveExpression.cs @@ -31,6 +31,8 @@ namespace ICSharpCode.NRefactory.CSharp /// public class PrimitiveExpression : Expression { + public static readonly object AnyValue = new object(); + AstLocation startLocation; public override AstLocation StartLocation { get { @@ -70,7 +72,7 @@ namespace ICSharpCode.NRefactory.CSharp protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) { PrimitiveExpression o = other as PrimitiveExpression; - return o != null && object.Equals(this.Value, o.Value); + return o != null && (this.Value == AnyValue || object.Equals(this.Value, o.Value)); } } } From 695138d3733ae4feee7523de58d88698ecca553a Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Mon, 21 Feb 2011 19:08:26 +0100 Subject: [PATCH 4/4] Add visitor support to pattern nodes (IPatternAstVisitor). Add pattern support to output visitor (makes debugging easier if you can print out patterns) --- .../CSharp/Ast/AstNodeCollection.cs | 2 +- .../CSharp/Ast/Expressions/Expression.cs | 9 ++ ICSharpCode.NRefactory/CSharp/Ast/NodeType.cs | 3 +- .../CSharp/Ast/PatternMatching/AnyNode.cs | 9 ++ .../Ast/PatternMatching/Backreference.cs | 18 ++++ .../CSharp/Ast/PatternMatching/Choice.cs | 13 ++- .../Ast/PatternMatching/IPatternAstVisitor.cs | 22 +++++ .../{NamedGroup.cs => NamedNode.cs} | 9 ++ .../CSharp/Ast/PatternMatching/Pattern.cs | 14 +-- .../CSharp/Ast/PatternMatching/Placeholder.cs | 20 ++--- .../CSharp/Ast/PatternMatching/Repeat.cs | 5 ++ .../CSharp/OutputVisitor/OutputVisitor.cs | 90 ++++++++++++++++++- .../ICSharpCode.NRefactory.csproj | 3 +- 13 files changed, 197 insertions(+), 20 deletions(-) create mode 100644 ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/IPatternAstVisitor.cs rename ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/{NamedGroup.cs => NamedNode.cs} (78%) diff --git a/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs b/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs index 8ffc29157b..033ad79131 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs @@ -175,7 +175,7 @@ namespace ICSharpCode.NRefactory.CSharp break; Pattern pattern = cur1 as Pattern; - if (pattern == null && cur1.NodeType == NodeType.Pattern) + if (pattern == null && cur1.NodeType == NodeType.Placeholder) pattern = cur1.GetChildByRole(TypePlaceholder.ChildRole) as Pattern; if (pattern != null) { Debug.Assert(stack.Count == patternStack.Count); diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/Expression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/Expression.cs index c83e740c2f..3055ae7fbe 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/Expression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/Expression.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; namespace ICSharpCode.NRefactory.CSharp @@ -50,6 +51,14 @@ namespace ICSharpCode.NRefactory.CSharp return (Expression)base.Clone(); } + // Make debugging easier by giving Expressions a ToString() implementation + public override string ToString() + { + StringWriter w = new StringWriter(); + AcceptVisitor(new OutputVisitor(w, new CSharpFormattingPolicy()), null); + return w.ToString(); + } + public Expression ReplaceWith(Func replaceFunction) { if (replaceFunction == null) diff --git a/ICSharpCode.NRefactory/CSharp/Ast/NodeType.cs b/ICSharpCode.NRefactory/CSharp/Ast/NodeType.cs index 946b838d6b..5d831be04d 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/NodeType.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/NodeType.cs @@ -44,7 +44,8 @@ namespace ICSharpCode.NRefactory.CSharp Expression, Token, QueryClause, - Pattern + Pattern, + Placeholder } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/AnyNode.cs b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/AnyNode.cs index 028e7d7fda..e992da9ce8 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/AnyNode.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/AnyNode.cs @@ -12,6 +12,10 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching { readonly string groupName; + public string GroupName { + get { return groupName; } + } + public AnyNode(string groupName = null) { this.groupName = groupName; @@ -22,5 +26,10 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching match.Add(this.groupName, other); return other != null && !other.IsNull; } + + public override S AcceptVisitor(IAstVisitor visitor, T data) + { + return ((IPatternAstVisitor)visitor).VisitAnyNode(this, data); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Backreference.cs b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Backreference.cs index dd9f2b5aa2..5d30b072e2 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Backreference.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Backreference.cs @@ -13,6 +13,10 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching { readonly string referencedGroupName; + public string ReferencedGroupName { + get { return referencedGroupName; } + } + public Backreference(string referencedGroupName) { if (referencedGroupName == null) @@ -24,6 +28,11 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching { return match.Get(referencedGroupName).Last().Match(other) != null; } + + public override S AcceptVisitor(IAstVisitor visitor, T data) + { + return ((IPatternAstVisitor)visitor).VisitBackreference(this, data); + } } /// @@ -33,6 +42,10 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching { readonly string referencedGroupName; + public string ReferencedGroupName { + get { return referencedGroupName; } + } + public IdentifierExpressionBackreference(string referencedGroupName) { if (referencedGroupName == null) @@ -48,5 +61,10 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching AstNode referenced = match.Get(referencedGroupName).Last(); return ident.Identifier == referenced.GetChildByRole(AstNode.Roles.Identifier).Name; } + + public override S AcceptVisitor(IAstVisitor visitor, T data) + { + return ((IPatternAstVisitor)visitor).VisitIdentifierExpressionBackreference(this, data); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Choice.cs b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Choice.cs index 6435cc3243..b2352e402c 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Choice.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Choice.cs @@ -3,13 +3,14 @@ using System; using System.Collections; +using System.Collections.Generic; namespace ICSharpCode.NRefactory.CSharp.PatternMatching { /// /// Matches one of several alternatives. /// - public class Choice : Pattern, IEnumerable + public class Choice : Pattern, IEnumerable { public static readonly Role AlternativeRole = new Role("Alternative", AstNode.Null); @@ -35,9 +36,19 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching return false; } + IEnumerator IEnumerable.GetEnumerator() + { + return GetChildrenByRole(AlternativeRole).GetEnumerator(); + } + IEnumerator IEnumerable.GetEnumerator() { return GetChildrenByRole(AlternativeRole).GetEnumerator(); } + + public override S AcceptVisitor(IAstVisitor visitor, T data) + { + return ((IPatternAstVisitor)visitor).VisitChoice(this, data); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/IPatternAstVisitor.cs b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/IPatternAstVisitor.cs new file mode 100644 index 0000000000..7b29a00c4f --- /dev/null +++ b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/IPatternAstVisitor.cs @@ -0,0 +1,22 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System; + +namespace ICSharpCode.NRefactory.CSharp.PatternMatching +{ + /// + /// Extended AST visitor that works for patterns. + /// + public interface IPatternAstVisitor : IAstVisitor + { + S VisitPlaceholder(AstNode placeholder, AstNode child, T data); + + S VisitAnyNode(AnyNode anyNode, T data); + S VisitBackreference(Backreference backreference, T data); + S VisitChoice(Choice choice, T data); + S VisitNamedNode(NamedNode namedNode, T data); + S VisitRepeat(Repeat repeat, T data); + S VisitIdentifierExpressionBackreference(IdentifierExpressionBackreference identifierExpressionBackreference, T data); + } +} diff --git a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/NamedGroup.cs b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/NamedNode.cs similarity index 78% rename from ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/NamedGroup.cs rename to ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/NamedNode.cs index 5cf361a6ec..baf9556849 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/NamedGroup.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/NamedNode.cs @@ -14,6 +14,10 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching readonly string groupName; + public string GroupName { + get { return groupName; } + } + public NamedNode(string groupName, AstNode childNode) { this.groupName = groupName; @@ -25,5 +29,10 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching match.Add(this.groupName, other); return GetChildByRole(ElementRole).DoMatch(other, match); } + + public override S AcceptVisitor(IAstVisitor visitor, T data) + { + return ((IPatternAstVisitor)visitor).VisitNamedNode(this, data); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs index 1c68d670e9..073415f519 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; namespace ICSharpCode.NRefactory.CSharp.PatternMatching { @@ -33,11 +34,6 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching return DoMatch(pos, match); } - public override S AcceptVisitor(IAstVisitor visitor, T data) - { - return default(S); - } - public AstType ToType() { return new TypePlaceholder(this); @@ -62,5 +58,13 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching { return new VariablePlaceholder(this); } + + // Make debugging easier by giving Patterns a ToString() implementation + public override string ToString() + { + StringWriter w = new StringWriter(); + AcceptVisitor(new OutputVisitor(w, new CSharpFormattingPolicy()), null); + return w.ToString(); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Placeholder.cs b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Placeholder.cs index f84faaa398..2bac1c6e19 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Placeholder.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Placeholder.cs @@ -15,12 +15,12 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching } public override NodeType NodeType { - get { return GetChildByRole(TypePlaceholder.ChildRole).NodeType; } + get { return NodeType.Placeholder; } } public override S AcceptVisitor(IAstVisitor visitor, T data) { - return GetChildByRole(TypePlaceholder.ChildRole).AcceptVisitor(visitor, data); + return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, GetChildByRole(TypePlaceholder.ChildRole), data); } protected internal override bool DoMatch(AstNode other, Match match) @@ -37,12 +37,12 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching } public override NodeType NodeType { - get { return GetChildByRole(TypePlaceholder.ChildRole).NodeType; } + get { return NodeType.Placeholder; } } public override S AcceptVisitor(IAstVisitor visitor, T data) { - return GetChildByRole(TypePlaceholder.ChildRole).AcceptVisitor(visitor, data); + return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, GetChildByRole(TypePlaceholder.ChildRole), data); } protected internal override bool DoMatch(AstNode other, Match match) @@ -59,12 +59,12 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching } public override NodeType NodeType { - get { return GetChildByRole(TypePlaceholder.ChildRole).NodeType; } + get { return NodeType.Placeholder; } } public override S AcceptVisitor(IAstVisitor visitor, T data) { - return GetChildByRole(TypePlaceholder.ChildRole).AcceptVisitor(visitor, data); + return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, GetChildByRole(TypePlaceholder.ChildRole), data); } protected internal override bool DoMatch(AstNode other, Match match) @@ -81,12 +81,12 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching } public override NodeType NodeType { - get { return GetChildByRole(TypePlaceholder.ChildRole).NodeType; } + get { return NodeType.Placeholder; } } public override S AcceptVisitor(IAstVisitor visitor, T data) { - return GetChildByRole(TypePlaceholder.ChildRole).AcceptVisitor(visitor, data); + return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, GetChildByRole(TypePlaceholder.ChildRole), data); } protected internal override bool DoMatch(AstNode other, Match match) @@ -103,12 +103,12 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching } public override NodeType NodeType { - get { return GetChildByRole(TypePlaceholder.ChildRole).NodeType; } + get { return NodeType.Placeholder; } } public override S AcceptVisitor(IAstVisitor visitor, T data) { - return GetChildByRole(TypePlaceholder.ChildRole).AcceptVisitor(visitor, data); + return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, GetChildByRole(TypePlaceholder.ChildRole), data); } protected internal override bool DoMatch(AstNode other, Match match) diff --git a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Repeat.cs b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Repeat.cs index 2ec1183da0..c968bce454 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Repeat.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Repeat.cs @@ -46,5 +46,10 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching else return this.MaxCount >= 1 && GetChildByRole(ElementRole).DoMatch(other, match); } + + public override S AcceptVisitor(IAstVisitor visitor, T data) + { + return ((IPatternAstVisitor)visitor).VisitRepeat(this, data); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs b/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs index cfa2a8634f..cf880653e6 100644 --- a/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs +++ b/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs @@ -8,6 +8,8 @@ using System.Globalization; using System.IO; using System.Linq; using System.Text; + +using ICSharpCode.NRefactory.CSharp.PatternMatching; using ICSharpCode.NRefactory.TypeSystem; namespace ICSharpCode.NRefactory.CSharp @@ -15,7 +17,7 @@ namespace ICSharpCode.NRefactory.CSharp /// /// Outputs the AST. /// - public class OutputVisitor : IAstVisitor + public class OutputVisitor : IPatternAstVisitor { readonly IOutputFormatter formatter; readonly CSharpFormattingPolicy policy; @@ -1989,5 +1991,91 @@ namespace ICSharpCode.NRefactory.CSharp return EndNode(identifier); } #endregion + + #region Pattern Nodes + object IPatternAstVisitor.VisitPlaceholder(AstNode placeholder, AstNode child, object data) + { + StartNode(placeholder); + child.AcceptVisitor(this, data); + return EndNode(placeholder); + } + + object IPatternAstVisitor.VisitAnyNode(AnyNode anyNode, object data) + { + StartNode(anyNode); + if (!string.IsNullOrEmpty(anyNode.GroupName)) { + WriteIdentifier(anyNode.GroupName); + WriteToken(":", AstNode.Roles.Colon); + } + WriteKeyword("anyNode"); + return EndNode(anyNode); + } + + object IPatternAstVisitor.VisitBackreference(Backreference backreference, object data) + { + StartNode(backreference); + WriteKeyword("backreference"); + LPar(); + WriteIdentifier(backreference.ReferencedGroupName); + RPar(); + return EndNode(backreference); + } + + object IPatternAstVisitor.VisitIdentifierExpressionBackreference(IdentifierExpressionBackreference identifierExpressionBackreference, object data) + { + StartNode(identifierExpressionBackreference); + WriteKeyword("identifierBackreference"); + LPar(); + WriteIdentifier(identifierExpressionBackreference.ReferencedGroupName); + RPar(); + return EndNode(identifierExpressionBackreference); + } + + object IPatternAstVisitor.VisitChoice(Choice choice, object data) + { + StartNode(choice); + WriteKeyword("choice"); + Space(); + LPar(); + NewLine(); + formatter.Indent(); + foreach (AstNode alternative in choice) { + alternative.AcceptVisitor(this, data); + if (alternative != choice.LastChild) + WriteToken(",", AstNode.Roles.Comma); + NewLine(); + } + formatter.Unindent(); + RPar(); + return EndNode(choice); + } + + object IPatternAstVisitor.VisitNamedNode(NamedNode namedNode, object data) + { + StartNode(namedNode); + if (!string.IsNullOrEmpty(namedNode.GroupName)) { + WriteIdentifier(namedNode.GroupName); + WriteToken(":", AstNode.Roles.Colon); + } + namedNode.GetChildByRole(NamedNode.ElementRole).AcceptVisitor(this, data); + return EndNode(namedNode); + } + + object IPatternAstVisitor.VisitRepeat(Repeat repeat, object data) + { + StartNode(repeat); + WriteKeyword("repeat"); + LPar(); + if (repeat.MinCount != 0 || repeat.MaxCount != int.MaxValue) { + WriteIdentifier(repeat.MinCount.ToString()); + WriteToken(",", AstNode.Roles.Comma); + WriteIdentifier(repeat.MaxCount.ToString()); + WriteToken(",", AstNode.Roles.Comma); + } + repeat.GetChildByRole(Repeat.ElementRole).AcceptVisitor(this, data); + RPar(); + return EndNode(repeat); + } + #endregion } } diff --git a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj index fa406661c3..6fdcd0c9f1 100644 --- a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj +++ b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj @@ -98,8 +98,9 @@ + - +