Browse Source

DomNode: enforce tree invariants, fix bug in InsertChildBefore, and add Remove/Replace methods.

newNRvisualizers
Daniel Grunwald 15 years ago
parent
commit
ebcfe909bd
  1. 175
      ICSharpCode.NRefactory/CSharp/Dom/DomNode.cs
  2. 14
      ICSharpCode.NRefactory/CSharp/Parser/CSharpParser.cs

175
ICSharpCode.NRefactory/CSharp/Dom/DomNode.cs

@ -1,6 +1,6 @@
// //
// AstNode.cs // AstNode.cs
// //
// Author: // Author:
// Mike Krüger <mkrueger@novell.com> // Mike Krüger <mkrueger@novell.com>
// //
@ -26,13 +26,15 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
namespace ICSharpCode.NRefactory.CSharp namespace ICSharpCode.NRefactory.CSharp
{ {
public abstract class DomNode public abstract class DomNode
{ {
#region Null
public static readonly DomNode Null = new NullAstNode (); public static readonly DomNode Null = new NullAstNode ();
class NullAstNode : DomNode sealed class NullAstNode : DomNode
{ {
public override NodeType NodeType { public override NodeType NodeType {
get { get {
@ -51,6 +53,14 @@ namespace ICSharpCode.NRefactory.CSharp
return default (S); return default (S);
} }
} }
#endregion
DomNode parent;
DomNode prevSibling;
DomNode nextSibling;
DomNode firstChild;
DomNode lastChild;
int role;
public abstract NodeType NodeType { public abstract NodeType NodeType {
get; get;
@ -63,8 +73,8 @@ namespace ICSharpCode.NRefactory.CSharp
} }
public virtual DomLocation StartLocation { public virtual DomLocation StartLocation {
get { get {
var child = FirstChild; var child = firstChild;
if (child == null) if (child == null)
return DomLocation.Empty; return DomLocation.Empty;
return child.StartLocation; return child.StartLocation;
@ -72,8 +82,8 @@ namespace ICSharpCode.NRefactory.CSharp
} }
public virtual DomLocation EndLocation { public virtual DomLocation EndLocation {
get { get {
var child = LastChild; var child = lastChild;
if (child == null) if (child == null)
return DomLocation.Empty; return DomLocation.Empty;
return child.EndLocation; return child.EndLocation;
@ -81,107 +91,166 @@ namespace ICSharpCode.NRefactory.CSharp
} }
public DomNode Parent { public DomNode Parent {
get; get { return parent; }
set;
} }
public int Role { public int Role {
get; get { return role; }
set;
} }
public DomNode NextSibling { public DomNode NextSibling {
get; get { return nextSibling; }
set;
} }
public DomNode PrevSibling { public DomNode PrevSibling {
get; get { return prevSibling; }
set;
} }
public DomNode FirstChild { public DomNode FirstChild {
get; get { return firstChild; }
set;
} }
public DomNode LastChild { public DomNode LastChild {
get; get { return lastChild; }
set;
} }
public IEnumerable<DomNode> Children { public IEnumerable<DomNode> Children {
get { get {
var cur = FirstChild; var cur = firstChild;
while (cur != null) { while (cur != null) {
yield return cur; yield return cur;
cur = cur.NextSibling; cur = cur.nextSibling;
} }
} }
} }
public DomNode GetChildByRole (int role) public DomNode GetChildByRole (int role)
{ {
var cur = FirstChild; var cur = firstChild;
while (cur != null) { while (cur != null) {
if (cur.Role == role) if (cur.role == role)
return cur; return cur;
cur = cur.NextSibling; cur = cur.nextSibling;
} }
return null; return null;
} }
public IEnumerable<DomNode> GetChildrenByRole (int role) public IEnumerable<DomNode> GetChildrenByRole (int role)
{ {
var cur = FirstChild; var cur = firstChild;
while (cur != null) { while (cur != null) {
if (cur.Role == role) if (cur.role == role)
yield return cur; yield return cur;
cur = cur.NextSibling; cur = cur.nextSibling;
} }
} }
public void AddChild (DomNode child) public void AddChild (DomNode child, int role)
{ {
if (child == null) if (child == null)
return; return;
child.Parent = this; if (child.parent != null)
if (FirstChild == null) { throw new ArgumentException ("Node is already used in another tree.", "child");
LastChild = FirstChild = child; child.parent = this;
child.role = role;
if (firstChild == null) {
lastChild = firstChild = child;
} else { } else {
LastChild.NextSibling = child; lastChild.nextSibling = child;
child.PrevSibling = LastChild; child.prevSibling = lastChild;
LastChild = child; lastChild = child;
} }
} }
public void AddChild (DomNode child, int role) public void InsertChildBefore (DomNode nextSibling, DomNode child, int role)
{ {
if (nextSibling == null) {
AddChild (child, role);
return;
}
if (child == null) if (child == null)
return; return;
child.Role = role; if (child.parent != null)
AddChild (child); throw new ArgumentException ("Node is already used in another tree.", "child");
if (nextSibling.parent != this)
throw new ArgumentException ("NextSibling is not a child of this node.", "nextSibling");
child.parent = this;
child.role = role;
child.nextSibling = nextSibling;
child.prevSibling = nextSibling.prevSibling;
if (nextSibling.prevSibling != null) {
Debug.Assert(nextSibling.prevSibling.nextSibling == nextSibling);
nextSibling.prevSibling.nextSibling = child;
} else {
Debug.Assert(firstChild == nextSibling);
firstChild = child;
}
nextSibling.prevSibling = child;
} }
public void InsertChildBefore (DomNode nextSibling, DomNode child, int role) /// <summary>
/// Removes this node from its parent.
/// </summary>
public void Remove()
{ {
if (child == null) if (parent != null) {
return; if (prevSibling != null) {
Debug.Assert(prevSibling.nextSibling == this);
if (FirstChild == null || nextSibling == null) { prevSibling.nextSibling = nextSibling;
AddChild (child, role); } else {
Debug.Assert(parent.firstChild == this);
parent.firstChild = nextSibling;
}
if (nextSibling != null) {
Debug.Assert(nextSibling.prevSibling == this);
nextSibling.prevSibling = prevSibling;
} else {
Debug.Assert(parent.lastChild == this);
parent.lastChild = prevSibling;
}
parent = null;
prevSibling = null;
nextSibling = null;
}
}
/// <summary>
/// Replaces this node with the new node.
/// </summary>
public void Replace(DomNode newNode)
{
if (newNode == null) {
Remove();
return; return;
} }
child.Parent = this; if (newNode.parent != null)
child.Role = role; throw new ArgumentException ("Node is already used in another tree.", "newNode");
newNode.parent = parent;
child.NextSibling = nextSibling; newNode.role = role;
newNode.prevSibling = prevSibling;
if (nextSibling.PrevSibling != null) { newNode.nextSibling = nextSibling;
child.PrevSibling = nextSibling.PrevSibling; if (parent != null) {
nextSibling.PrevSibling.NextSibling = child; if (prevSibling != null) {
Debug.Assert(prevSibling.nextSibling == this);
prevSibling.nextSibling = newNode;
} else {
Debug.Assert(parent.firstChild == this);
parent.firstChild = newNode;
}
if (nextSibling != null) {
Debug.Assert(nextSibling.prevSibling == this);
nextSibling.prevSibling = newNode;
} else {
Debug.Assert(parent.lastChild == this);
parent.lastChild = newNode;
}
parent = null;
prevSibling = null;
nextSibling = null;
} }
nextSibling.PrevSibling = child;
} }
public abstract S AcceptVisitor<T, S> (DomVisitor<T, S> visitor, T data); public abstract S AcceptVisitor<T, S> (DomVisitor<T, S> visitor, T data);
@ -205,7 +274,7 @@ namespace ICSharpCode.NRefactory.CSharp
public const int TargetExpression = 14; public const int TargetExpression = 14;
public const int Member = 15; public const int Member = 15;
// some pre defined constants for most used punctuation // some pre defined constants for most used punctuation
public const int LPar = 50; // ( public const int LPar = 50; // (
public const int RPar = 51; // ) public const int RPar = 51; // )

14
ICSharpCode.NRefactory/CSharp/Parser/CSharpParser.cs

@ -260,7 +260,7 @@ namespace ICSharpCode.NRefactory.CSharp
if (namespaceStack.Count > 0) { if (namespaceStack.Count > 0) {
namespaceStack.Peek ().AddChild (child, NamespaceDeclaration.Roles.Member); namespaceStack.Peek ().AddChild (child, NamespaceDeclaration.Roles.Member);
} else { } else {
unit.AddChild (child); unit.AddChild (child, CompilationUnit.Roles.Member);
} }
} }
@ -2224,7 +2224,7 @@ namespace ICSharpCode.NRefactory.CSharp
NewAnonymousType aType = l.Expr as NewAnonymousType; NewAnonymousType aType = l.Expr as NewAnonymousType;
AnonymousTypeParameter param = ((AnonymousTypeParameter)aType.Parameters[1]); AnonymousTypeParameter param = ((AnonymousTypeParameter)aType.Parameters[1]);
result.AddChild (new Identifier (param.Name, Convert (param.Location))); result.AddChild (new Identifier (param.Name, Convert (param.Location)), Identifier.Roles.Identifier);
if (location != null) if (location != null)
result.AddChild (new CSharpTokenNode (Convert (location[1]), 1), QueryExpressionWhereClause.Roles.Assign); result.AddChild (new CSharpTokenNode (Convert (location[1]), 1), QueryExpressionWhereClause.Roles.Assign);
@ -2250,7 +2250,7 @@ namespace ICSharpCode.NRefactory.CSharp
if (location != null) if (location != null)
result.AddChild (new CSharpTokenNode (Convert (location[0]), "join".Length), QueryExpressionJoinClause.JoinKeywordRole); result.AddChild (new CSharpTokenNode (Convert (location[0]), "join".Length), QueryExpressionJoinClause.JoinKeywordRole);
result.AddChild (new Identifier (join.JoinVariable.Name, Convert (join.JoinVariable.Location))); result.AddChild (new Identifier (join.JoinVariable.Name, Convert (join.JoinVariable.Location)), Identifier.Roles.Identifier);
if (location != null) if (location != null)
result.AddChild (new CSharpTokenNode (Convert (location[1]), "in".Length), QueryExpressionJoinClause.InKeywordRole); result.AddChild (new CSharpTokenNode (Convert (location[1]), "in".Length), QueryExpressionJoinClause.InKeywordRole);
@ -2275,7 +2275,7 @@ namespace ICSharpCode.NRefactory.CSharp
if (location != null) if (location != null)
result.AddChild (new CSharpTokenNode (Convert (location[0]), "join".Length), QueryExpressionJoinClause.JoinKeywordRole); result.AddChild (new CSharpTokenNode (Convert (location[0]), "join".Length), QueryExpressionJoinClause.JoinKeywordRole);
result.AddChild (new Identifier (groupJoin.JoinVariable.Name, Convert (groupJoin.JoinVariable.Location))); result.AddChild (new Identifier (groupJoin.JoinVariable.Name, Convert (groupJoin.JoinVariable.Location)), Identifier.Roles.Identifier);
if (location != null) if (location != null)
result.AddChild (new CSharpTokenNode (Convert (location[1]), "in".Length), QueryExpressionJoinClause.InKeywordRole); result.AddChild (new CSharpTokenNode (Convert (location[1]), "in".Length), QueryExpressionJoinClause.InKeywordRole);
@ -2293,7 +2293,7 @@ namespace ICSharpCode.NRefactory.CSharp
if (location != null) if (location != null)
result.AddChild (new CSharpTokenNode (Convert (location[4]), "into".Length), QueryExpressionJoinClause.IntoKeywordRole); result.AddChild (new CSharpTokenNode (Convert (location[4]), "into".Length), QueryExpressionJoinClause.IntoKeywordRole);
result.AddChild (new Identifier (groupJoin.JoinVariable.Name, Convert (groupJoin.JoinVariable.Location))); result.AddChild (new Identifier (groupJoin.JoinVariable.Name, Convert (groupJoin.JoinVariable.Location)), Identifier.Roles.Identifier);
return result; return result;
} }
@ -2352,7 +2352,7 @@ namespace ICSharpCode.NRefactory.CSharp
void InsertComment (DomNode node, Comment comment) void InsertComment (DomNode node, Comment comment)
{ {
if (node.EndLocation < comment.StartLocation) { if (node.EndLocation < comment.StartLocation) {
node.AddChild (comment); node.AddChild (comment, DomNode.Roles.Comment);
return; return;
} }
@ -2367,7 +2367,7 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
node.AddChild (comment); node.AddChild (comment, DomNode.Roles.Comment);
} }
void InsertComments (CompilerCompilationUnit top, ConversionVisitor conversionVisitor) void InsertComments (CompilerCompilationUnit top, ConversionVisitor conversionVisitor)

Loading…
Cancel
Save