From 23190aa19c819d8795e8e672b0cdec141ac837e7 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Mon, 21 Feb 2011 01:45:24 +0100 Subject: [PATCH] NRefactory AST: Add 'Repeat' pattern which matches an arbitrary number of nodes. --- .../CSharp/Ast/AstNodeCollection.cs | 14 +++-- .../CSharp/Ast/PatternMatching/Pattern.cs | 7 +++ .../CSharp/Ast/PatternMatching/Repeat.cs | 51 +++++++++++++++++++ .../CSharp/Ast/Statements/BlockStatement.cs | 22 +++++--- .../CSharp/Ast/Statements/ForStatement.cs | 9 +++- .../CSharp/Ast/Statements/UsingStatement.cs | 8 ++- .../ICSharpCode.NRefactory.csproj | 1 + 7 files changed, 101 insertions(+), 11 deletions(-) create mode 100644 ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Repeat.cs diff --git a/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs b/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs index 6eca8d993c..5a5218773b 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs @@ -165,10 +165,18 @@ namespace ICSharpCode.NRefactory.CSharp cur2 = cur2.NextSibling; if (cur1 == null || cur2 == null) break; - if (!cur1.DoMatch(cur2, match)) - return false; + 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; - cur2 = cur2.NextSibling; } return cur1 == null && cur2 == null; } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs index 2e08092a91..ab5efbe8dc 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs @@ -14,6 +14,13 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching get { return NodeType.Pattern; } } + protected internal virtual bool DoMatchCollection(Role role, ref AstNode other, Match match) + { + bool result = DoMatch(other, match); + other = other.NextSibling; + return result; + } + public override S AcceptVisitor(IAstVisitor visitor, T data) { return default(S); diff --git a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Repeat.cs b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Repeat.cs new file mode 100644 index 0000000000..3c2bc56530 --- /dev/null +++ b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Repeat.cs @@ -0,0 +1,51 @@ +// 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; +using System.Diagnostics; + +namespace ICSharpCode.NRefactory.CSharp.PatternMatching +{ + /// + /// Represents an optional node. + /// + public class Repeat : Pattern + { + public static readonly Role ElementRole = new Role("Element", AstNode.Null); + public int MinCount; + public int MaxCount = int.MaxValue; + + public Repeat(AstNode childNode) + { + AddChild(childNode, ElementRole); + } + + protected internal override bool DoMatchCollection(Role role, ref AstNode other, Match match) + { + Debug.Assert(other != null && other.Role == role); + int matchCount = 0; + var lastValidCheckpoint = match.CheckPoint(); + AstNode element = GetChildByRole(ElementRole); + AstNode pos = other; + while (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; + } + match.RestoreCheckPoint(lastValidCheckpoint); // restote old checkpoint after failed match + return matchCount >= MinCount && matchCount <= MaxCount; + } + + protected internal override bool DoMatch(AstNode other, Match match) + { + if (other == null || other.IsNull) + return this.MinCount <= 0; + else + return GetChildByRole(ElementRole).DoMatch(other, match); + } + } +} diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/BlockStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/BlockStatement.cs index 57865e586c..d43a0d538a 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/BlockStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/BlockStatement.cs @@ -31,7 +31,7 @@ namespace ICSharpCode.NRefactory.CSharp /// /// { Statements } /// - public class BlockStatement : Statement + public class BlockStatement : Statement, IEnumerable { public static readonly Role StatementRole = new Role("Statement", Statement.Null); @@ -81,17 +81,17 @@ namespace ICSharpCode.NRefactory.CSharp } #region Builder methods - public void AddStatement(Statement statement) + public void Add(Statement statement) { AddChild(statement, StatementRole); } - public void AddStatement(Expression expression) + public void Add(Expression expression) { AddChild(new ExpressionStatement { Expression = expression }, StatementRole); } - public void AddStatements(IEnumerable statements) + public void AddRange(IEnumerable statements) { foreach (Statement st in statements) AddChild(st, StatementRole); @@ -99,13 +99,23 @@ namespace ICSharpCode.NRefactory.CSharp public void AddAssignment(Expression left, Expression right) { - AddStatement(new AssignmentExpression { Left = left, Operator = AssignmentOperatorType.Assign, Right = right }); + Add(new AssignmentExpression { Left = left, Operator = AssignmentOperatorType.Assign, Right = right }); } public void AddReturnStatement(Expression expression) { - AddStatement(new ReturnStatement { Expression = expression }); + Add(new ReturnStatement { Expression = expression }); } #endregion + + IEnumerator IEnumerable.GetEnumerator() + { + return this.Statements.GetEnumerator(); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return this.Statements.GetEnumerator(); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/ForStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/ForStatement.cs index d50b0d3ff5..ebbe44022b 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/ForStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/ForStatement.cs @@ -1,6 +1,6 @@ // // ForStatement.cs -// +// // Author: // Mike Krüger // @@ -75,5 +75,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitForStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + ForStatement o = other as ForStatement; + return o != null && this.Initializers.DoMatch(o.Initializers, match) && this.Condition.DoMatch(o.Condition, match) + && this.Iterators.DoMatch(o.Iterators, match) && this.EmbeddedStatement.DoMatch(o.EmbeddedStatement, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/UsingStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/UsingStatement.cs index d694875633..27714d61bf 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/UsingStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/UsingStatement.cs @@ -1,4 +1,4 @@ -// +// // UsingStatement.cs // // Author: @@ -62,5 +62,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitUsingStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + UsingStatement o = other as UsingStatement; + return o != null && this.ResourceAcquisition.DoMatch(o.ResourceAcquisition, match) && this.EmbeddedStatement.DoMatch(o.EmbeddedStatement, match); + } } } diff --git a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj index f750893d9e..fa406661c3 100644 --- a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj +++ b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj @@ -100,6 +100,7 @@ +