mirror of https://github.com/icsharpcode/ILSpy.git
Browse Source
2200240 InsertParenthesesVisitor: don't insert parentheses for "a && b && c" 5a34a9c Fix output of checked and unchecked expressions. 695138d Add visitor support to pattern nodes (IPatternAstVisitor). Add pattern support to output visitor (makes debugging easier if you can print out patterns) 38faf84 Add support for 'any' operator and fix a bug in pattern matching. eeb4ea5 Add simple backtracking support to pattern matching. e6c0091 Implement pattern matching for statements. 93cc19d Determine loop condition from CFG 23190aa NRefactory AST: Add 'Repeat' pattern which matches an arbitrary number of nodes. 379063a OutputVisitor bugfix: show return type for custom events. bce9881 Add some improvements to pattern matching. f5e89bf Add Choice pattern. 84a5ace OutputVisitor: allow writing constructor declarations without writing their parent type declaration. 13c6417 Add some documentation comments. 7e03cf8 Fix output of using statement when the resource acquisition is a VariableDeclarationStatement. 9d5390c Add pattern matching support to the NRefactory C# AST. 1af927c Fix lambda expression output bug. 904b05f NRefactory: remove collection setters from AST; expose AstNodeCollection<T> instead. 0fa2fd6 Fix missing dot in namespace declarations. 8641726 Escape surrogates in string literals. f1ce3e9 Fix order of modifiers. cd9efb5 Fixed infinite loop in AstComparer 3e02950 Merge commit '814b8b3bf3553c719c84be7b0aa71c946731e36a' 7c23366 Merge in the latest NRefactory (8db1fe252f6539e9cde8c9fb5f59aa60e4089d8f) git-subtree-dir: NRefactory git-subtree-split: 2200240ef60fc49f32b89eb85c9f3a8ba796b08dpull/129/head
108 changed files with 1801 additions and 341 deletions
@ -1,42 +0,0 @@
@@ -1,42 +0,0 @@
|
||||
// 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.Collections.Generic; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp |
||||
{ |
||||
/// <summary>
|
||||
/// Compares whether two ASTs are structurally identical.
|
||||
/// </summary>
|
||||
public static class AstComparer |
||||
{ |
||||
static HashSet<Type> nodeTypesWithoutExtraInfo = new HashSet<Type> { |
||||
typeof(IdentifierExpression) |
||||
}; |
||||
|
||||
public static bool? AreEqual(AstNode node1, AstNode node2) |
||||
{ |
||||
if (node1 == node2) |
||||
return true; |
||||
if (node1 == null || node1.IsNull || node2 == null || node2.IsNull) |
||||
return false; |
||||
Type nodeType = node1.GetType(); |
||||
if (nodeType != node2.GetType()) |
||||
return false; |
||||
if (node1.Role != node2.Role) |
||||
return false; |
||||
AstNode child1 = node1.FirstChild; |
||||
AstNode child2 = node2.FirstChild; |
||||
bool? result = true; |
||||
while (result != false && (child1 != null || child2 != null)) { |
||||
result &= AreEqual(child1, child2); |
||||
} |
||||
if (nodeTypesWithoutExtraInfo.Contains(nodeType)) |
||||
return result; |
||||
if (nodeType == typeof(Identifier)) |
||||
return ((Identifier)node1).Name == ((Identifier)node2).Name; |
||||
return null; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,201 @@
@@ -0,0 +1,201 @@
|
||||
// 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.Collections; |
||||
using System.Collections.Generic; |
||||
using System.Diagnostics; |
||||
using System.Linq; |
||||
using ICSharpCode.NRefactory.CSharp.PatternMatching; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp |
||||
{ |
||||
/// <summary>
|
||||
/// Represents the children of an AstNode that have a specific role.
|
||||
/// </summary>
|
||||
public class AstNodeCollection<T> : ICollection<T> where T : AstNode |
||||
{ |
||||
readonly AstNode node; |
||||
readonly Role<T> role; |
||||
|
||||
public AstNodeCollection(AstNode node, Role<T> role) |
||||
{ |
||||
if (node == null) |
||||
throw new ArgumentNullException("node"); |
||||
if (role == null) |
||||
throw new ArgumentNullException("role"); |
||||
this.node = node; |
||||
this.role = role; |
||||
} |
||||
|
||||
public int Count { |
||||
get { |
||||
var e = GetEnumerator(); |
||||
int count = 0; |
||||
while (e.MoveNext()) |
||||
count++; |
||||
return count; |
||||
} |
||||
} |
||||
|
||||
public void Add(T element) |
||||
{ |
||||
node.AddChild(element, role); |
||||
} |
||||
|
||||
public void AddRange(IEnumerable<T> nodes) |
||||
{ |
||||
// Evaluate 'nodes' first, since it might change when we add the new children
|
||||
// Example: collection.AddRange(collection);
|
||||
if (nodes != null) { |
||||
foreach (T node in nodes.ToList()) |
||||
Add(node); |
||||
} |
||||
} |
||||
|
||||
public void AddRange(T[] nodes) |
||||
{ |
||||
// Fast overload for arrays - we don't need to create a copy
|
||||
if (nodes != null) { |
||||
foreach (T node in nodes) |
||||
Add(node); |
||||
} |
||||
} |
||||
|
||||
public void ReplaceWith(IEnumerable<T> nodes) |
||||
{ |
||||
// Evaluate 'nodes' first, since it might change when we call Clear()
|
||||
// Example: collection.ReplaceWith(collection);
|
||||
if (nodes != null) |
||||
nodes = nodes.ToList(); |
||||
Clear(); |
||||
foreach (T node in nodes) |
||||
Add(node); |
||||
} |
||||
|
||||
public void MoveTo(ICollection<T> targetCollection) |
||||
{ |
||||
foreach (T node in this) { |
||||
node.Remove(); |
||||
targetCollection.Add(node); |
||||
} |
||||
} |
||||
|
||||
public bool Contains(T element) |
||||
{ |
||||
return element != null && element.Parent == node && element.Role == role; |
||||
} |
||||
|
||||
public bool Remove(T element) |
||||
{ |
||||
if (Contains(element)) { |
||||
element.Remove(); |
||||
return true; |
||||
} else { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
public void CopyTo(T[] array, int arrayIndex) |
||||
{ |
||||
foreach (T item in this) |
||||
array[arrayIndex++] = item; |
||||
} |
||||
|
||||
public void Clear() |
||||
{ |
||||
foreach (T item in this) |
||||
item.Remove(); |
||||
} |
||||
|
||||
bool ICollection<T>.IsReadOnly { |
||||
get { return false; } |
||||
} |
||||
|
||||
public IEnumerator<T> GetEnumerator() |
||||
{ |
||||
AstNode next; |
||||
for (AstNode cur = node.FirstChild; cur != null; cur = next) { |
||||
// Remember next before yielding cur.
|
||||
// This allows removing/replacing nodes while iterating through the list.
|
||||
next = cur.NextSibling; |
||||
if (cur.Role == role) |
||||
yield return (T)cur; |
||||
} |
||||
} |
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() |
||||
{ |
||||
return GetEnumerator(); |
||||
} |
||||
|
||||
#region Equals and GetHashCode implementation
|
||||
public override bool Equals(object obj) |
||||
{ |
||||
if (obj is AstNodeCollection<T>) { |
||||
return ((AstNodeCollection<T>)obj) == this; |
||||
} else { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
public override int GetHashCode() |
||||
{ |
||||
return node.GetHashCode() ^ role.GetHashCode(); |
||||
} |
||||
|
||||
public static bool operator ==(AstNodeCollection<T> left, AstNodeCollection<T> right) |
||||
{ |
||||
return left.role == right.role && left.node == right.node; |
||||
} |
||||
|
||||
public static bool operator !=(AstNodeCollection<T> left, AstNodeCollection<T> right) |
||||
{ |
||||
return !(left.role == right.role && left.node == right.node); |
||||
} |
||||
#endregion
|
||||
|
||||
internal bool DoMatch(AstNodeCollection<T> other, Match match) |
||||
{ |
||||
Stack<AstNode> patternStack = new Stack<AstNode>(); |
||||
Stack<Pattern.PossibleMatch> stack = new Stack<Pattern.PossibleMatch>(); |
||||
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.Placeholder) |
||||
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; |
||||
if (cur2 != null) |
||||
cur2 = cur2.NextSibling; |
||||
} |
||||
while (cur2 != null && cur2.Role != role) |
||||
cur2 = cur2.NextSibling; |
||||
if (success && cur2 == null) |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,35 @@
@@ -0,0 +1,35 @@
|
||||
// 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 |
||||
{ |
||||
/// <summary>
|
||||
/// Matches any node.
|
||||
/// </summary>
|
||||
public class AnyNode : Pattern |
||||
{ |
||||
readonly string groupName; |
||||
|
||||
public string GroupName { |
||||
get { return groupName; } |
||||
} |
||||
|
||||
public AnyNode(string groupName = null) |
||||
{ |
||||
this.groupName = groupName; |
||||
} |
||||
|
||||
protected internal override bool DoMatch(AstNode other, Match match) |
||||
{ |
||||
match.Add(this.groupName, other); |
||||
return other != null && !other.IsNull; |
||||
} |
||||
|
||||
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data) |
||||
{ |
||||
return ((IPatternAstVisitor<T, S>)visitor).VisitAnyNode(this, data); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,70 @@
@@ -0,0 +1,70 @@
|
||||
// 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.Linq; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.PatternMatching |
||||
{ |
||||
/// <summary>
|
||||
/// Matches the last entry in the specified named group.
|
||||
/// </summary>
|
||||
public class Backreference : Pattern |
||||
{ |
||||
readonly string referencedGroupName; |
||||
|
||||
public string ReferencedGroupName { |
||||
get { return referencedGroupName; } |
||||
} |
||||
|
||||
public Backreference(string referencedGroupName) |
||||
{ |
||||
if (referencedGroupName == null) |
||||
throw new ArgumentNullException("referencedGroupName"); |
||||
this.referencedGroupName = referencedGroupName; |
||||
} |
||||
|
||||
protected internal override bool DoMatch(AstNode other, Match match) |
||||
{ |
||||
return match.Get(referencedGroupName).Last().Match(other) != null; |
||||
} |
||||
|
||||
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data) |
||||
{ |
||||
return ((IPatternAstVisitor<T, S>)visitor).VisitBackreference(this, data); |
||||
} |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Matches identifier expressions that have the same identifier as the referenced variable/type definition/method definition.
|
||||
/// </summary>
|
||||
public class IdentifierExpressionBackreference : Pattern |
||||
{ |
||||
readonly string referencedGroupName; |
||||
|
||||
public string ReferencedGroupName { |
||||
get { return 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; |
||||
} |
||||
|
||||
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data) |
||||
{ |
||||
return ((IPatternAstVisitor<T, S>)visitor).VisitIdentifierExpressionBackreference(this, data); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,54 @@
@@ -0,0 +1,54 @@
|
||||
// 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.Collections; |
||||
using System.Collections.Generic; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.PatternMatching |
||||
{ |
||||
/// <summary>
|
||||
/// Matches one of several alternatives.
|
||||
/// </summary>
|
||||
public class Choice : Pattern, IEnumerable<AstNode> |
||||
{ |
||||
public static readonly Role<AstNode> AlternativeRole = new Role<AstNode>("Alternative", AstNode.Null); |
||||
|
||||
public void Add(string name, AstNode alternative) |
||||
{ |
||||
AddChild(new NamedNode(name, alternative), AlternativeRole); |
||||
} |
||||
|
||||
public void Add(AstNode alternative) |
||||
{ |
||||
AddChild(alternative, AlternativeRole); |
||||
} |
||||
|
||||
protected internal override bool DoMatch(AstNode other, Match match) |
||||
{ |
||||
var checkPoint = match.CheckPoint(); |
||||
foreach (AstNode alt in GetChildrenByRole(AlternativeRole)) { |
||||
if (alt.DoMatch(other, match)) |
||||
return true; |
||||
else |
||||
match.RestoreCheckPoint(checkPoint); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
IEnumerator<AstNode> IEnumerable<AstNode>.GetEnumerator() |
||||
{ |
||||
return GetChildrenByRole(AlternativeRole).GetEnumerator(); |
||||
} |
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() |
||||
{ |
||||
return GetChildrenByRole(AlternativeRole).GetEnumerator(); |
||||
} |
||||
|
||||
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data) |
||||
{ |
||||
return ((IPatternAstVisitor<T, S>)visitor).VisitChoice(this, data); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,22 @@
@@ -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 |
||||
{ |
||||
/// <summary>
|
||||
/// Extended AST visitor that works for patterns.
|
||||
/// </summary>
|
||||
public interface IPatternAstVisitor<in T, out S> : IAstVisitor<T, S> |
||||
{ |
||||
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); |
||||
} |
||||
} |
@ -0,0 +1,59 @@
@@ -0,0 +1,59 @@
|
||||
// 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.Collections.Generic; |
||||
using System.Linq; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.PatternMatching |
||||
{ |
||||
/// <summary>
|
||||
/// Represents the result of a pattern matching operation.
|
||||
/// </summary>
|
||||
public sealed class Match |
||||
{ |
||||
List<KeyValuePair<string, AstNode>> results = new List<KeyValuePair<string, AstNode>>(); |
||||
|
||||
internal int CheckPoint() |
||||
{ |
||||
return results.Count; |
||||
} |
||||
|
||||
internal void RestoreCheckPoint(int checkPoint) |
||||
{ |
||||
results.RemoveRange(checkPoint, results.Count - checkPoint); |
||||
} |
||||
|
||||
public IEnumerable<AstNode> Get(string groupName) |
||||
{ |
||||
foreach (var pair in results) { |
||||
if (pair.Key == groupName) |
||||
yield return pair.Value; |
||||
} |
||||
} |
||||
|
||||
public IEnumerable<T> Get<T>(string groupName) where T : AstNode |
||||
{ |
||||
foreach (var pair in results) { |
||||
if (pair.Key == groupName) |
||||
yield return (T)pair.Value; |
||||
} |
||||
} |
||||
|
||||
public bool Has(string groupName) |
||||
{ |
||||
foreach (var pair in results) { |
||||
if (pair.Key == groupName) |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
public void Add(string groupName, AstNode node) |
||||
{ |
||||
if (groupName != null && node != null) { |
||||
results.Add(new KeyValuePair<string, AstNode>(groupName, node)); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,38 @@
@@ -0,0 +1,38 @@
|
||||
// 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 |
||||
{ |
||||
/// <summary>
|
||||
/// Represents a named node within a pattern.
|
||||
/// </summary>
|
||||
public class NamedNode : Pattern |
||||
{ |
||||
public static readonly Role<AstNode> ElementRole = new Role<AstNode>("Element", AstNode.Null); |
||||
|
||||
readonly string groupName; |
||||
|
||||
public string GroupName { |
||||
get { return groupName; } |
||||
} |
||||
|
||||
public NamedNode(string groupName, AstNode childNode) |
||||
{ |
||||
this.groupName = groupName; |
||||
AddChild(childNode, ElementRole); |
||||
} |
||||
|
||||
protected internal override bool DoMatch(AstNode other, Match match) |
||||
{ |
||||
match.Add(this.groupName, other); |
||||
return GetChildByRole(ElementRole).DoMatch(other, match); |
||||
} |
||||
|
||||
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data) |
||||
{ |
||||
return ((IPatternAstVisitor<T, S>)visitor).VisitNamedNode(this, data); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,70 @@
@@ -0,0 +1,70 @@
|
||||
// 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.Collections.Generic; |
||||
using System.Diagnostics; |
||||
using System.IO; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.PatternMatching |
||||
{ |
||||
/// <summary>
|
||||
/// Base class for all patterns.
|
||||
/// </summary>
|
||||
public abstract class Pattern : AstNode |
||||
{ |
||||
public override NodeType NodeType { |
||||
get { return NodeType.Pattern; } |
||||
} |
||||
|
||||
internal struct PossibleMatch |
||||
{ |
||||
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<PossibleMatch> backtrackingStack) |
||||
{ |
||||
return DoMatch(pos, match); |
||||
} |
||||
|
||||
public AstType ToType() |
||||
{ |
||||
return new TypePlaceholder(this); |
||||
} |
||||
|
||||
public Expression ToExpression() |
||||
{ |
||||
return new ExpressionPlaceholder(this); |
||||
} |
||||
|
||||
public Statement ToStatement() |
||||
{ |
||||
return new StatementPlaceholder(this); |
||||
} |
||||
|
||||
public BlockStatement ToBlock() |
||||
{ |
||||
return new BlockStatementPlaceholder(this); |
||||
} |
||||
|
||||
public VariableInitializer ToVariable() |
||||
{ |
||||
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(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,119 @@
@@ -0,0 +1,119 @@
|
||||
// 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 |
||||
{ |
||||
sealed class TypePlaceholder : AstType |
||||
{ |
||||
public static readonly Role<AstNode> ChildRole = new Role<AstNode>("Child", AstNode.Null); |
||||
|
||||
public TypePlaceholder(AstNode child) |
||||
{ |
||||
AddChild(child, TypePlaceholder.ChildRole); |
||||
} |
||||
|
||||
public override NodeType NodeType { |
||||
get { return NodeType.Placeholder; } |
||||
} |
||||
|
||||
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data) |
||||
{ |
||||
return ((IPatternAstVisitor<T, S>)visitor).VisitPlaceholder(this, GetChildByRole(TypePlaceholder.ChildRole), data); |
||||
} |
||||
|
||||
protected internal override bool DoMatch(AstNode other, Match match) |
||||
{ |
||||
return GetChildByRole(TypePlaceholder.ChildRole).DoMatch(other, match); |
||||
} |
||||
} |
||||
|
||||
sealed class ExpressionPlaceholder : Expression |
||||
{ |
||||
public ExpressionPlaceholder(AstNode child) |
||||
{ |
||||
AddChild(child, TypePlaceholder.ChildRole); |
||||
} |
||||
|
||||
public override NodeType NodeType { |
||||
get { return NodeType.Placeholder; } |
||||
} |
||||
|
||||
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data) |
||||
{ |
||||
return ((IPatternAstVisitor<T, S>)visitor).VisitPlaceholder(this, GetChildByRole(TypePlaceholder.ChildRole), data); |
||||
} |
||||
|
||||
protected internal override bool DoMatch(AstNode other, Match match) |
||||
{ |
||||
return GetChildByRole(TypePlaceholder.ChildRole).DoMatch(other, match); |
||||
} |
||||
} |
||||
|
||||
sealed class StatementPlaceholder : Statement |
||||
{ |
||||
public StatementPlaceholder(AstNode child) |
||||
{ |
||||
AddChild(child, TypePlaceholder.ChildRole); |
||||
} |
||||
|
||||
public override NodeType NodeType { |
||||
get { return NodeType.Placeholder; } |
||||
} |
||||
|
||||
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data) |
||||
{ |
||||
return ((IPatternAstVisitor<T, S>)visitor).VisitPlaceholder(this, GetChildByRole(TypePlaceholder.ChildRole), data); |
||||
} |
||||
|
||||
protected internal override bool DoMatch(AstNode other, Match match) |
||||
{ |
||||
return GetChildByRole(TypePlaceholder.ChildRole).DoMatch(other, match); |
||||
} |
||||
} |
||||
|
||||
sealed class BlockStatementPlaceholder : BlockStatement |
||||
{ |
||||
public BlockStatementPlaceholder(AstNode child) |
||||
{ |
||||
AddChild(child, TypePlaceholder.ChildRole); |
||||
} |
||||
|
||||
public override NodeType NodeType { |
||||
get { return NodeType.Placeholder; } |
||||
} |
||||
|
||||
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data) |
||||
{ |
||||
return ((IPatternAstVisitor<T, S>)visitor).VisitPlaceholder(this, GetChildByRole(TypePlaceholder.ChildRole), data); |
||||
} |
||||
|
||||
protected internal override bool DoMatch(AstNode other, Match match) |
||||
{ |
||||
return GetChildByRole(TypePlaceholder.ChildRole).DoMatch(other, match); |
||||
} |
||||
} |
||||
|
||||
sealed class VariablePlaceholder : VariableInitializer |
||||
{ |
||||
public VariablePlaceholder(AstNode child) |
||||
{ |
||||
AddChild(child, TypePlaceholder.ChildRole); |
||||
} |
||||
|
||||
public override NodeType NodeType { |
||||
get { return NodeType.Placeholder; } |
||||
} |
||||
|
||||
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data) |
||||
{ |
||||
return ((IPatternAstVisitor<T, S>)visitor).VisitPlaceholder(this, GetChildByRole(TypePlaceholder.ChildRole), data); |
||||
} |
||||
|
||||
protected internal override bool DoMatch(AstNode other, Match match) |
||||
{ |
||||
return GetChildByRole(TypePlaceholder.ChildRole).DoMatch(other, match); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,55 @@
@@ -0,0 +1,55 @@
|
||||
// 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.Collections.Generic; |
||||
using System.Diagnostics; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.PatternMatching |
||||
{ |
||||
/// <summary>
|
||||
/// Represents an optional node.
|
||||
/// </summary>
|
||||
public class Repeat : Pattern |
||||
{ |
||||
public static readonly Role<AstNode> ElementRole = new Role<AstNode>("Element", AstNode.Null); |
||||
public int MinCount; |
||||
public int MaxCount = int.MaxValue; |
||||
|
||||
public Repeat(AstNode childNode) |
||||
{ |
||||
AddChild(childNode, ElementRole); |
||||
} |
||||
|
||||
internal override bool DoMatchCollection(Role role, AstNode pos, Match match, Stack<Pattern.PossibleMatch> backtrackingStack) |
||||
{ |
||||
Debug.Assert(pos == null || pos.Role == role); |
||||
int matchCount = 0; |
||||
if (this.MinCount <= 0) |
||||
backtrackingStack.Push(new PossibleMatch(pos, match.CheckPoint())); |
||||
AstNode element = GetChildByRole(ElementRole); |
||||
while (matchCount < this.MaxCount && pos != null && element.DoMatch(pos, match)) { |
||||
matchCount++; |
||||
do { |
||||
pos = pos.NextSibling; |
||||
} while (pos != null && pos.Role != role); |
||||
if (matchCount >= this.MinCount) |
||||
backtrackingStack.Push(new PossibleMatch(pos, match.CheckPoint())); |
||||
} |
||||
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) |
||||
{ |
||||
if (other == null || other.IsNull) |
||||
return this.MinCount <= 0; |
||||
else |
||||
return this.MaxCount >= 1 && GetChildByRole(ElementRole).DoMatch(other, match); |
||||
} |
||||
|
||||
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data) |
||||
{ |
||||
return ((IPatternAstVisitor<T, S>)visitor).VisitRepeat(this, data); |
||||
} |
||||
} |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue