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 @@ @@ -1,6 +1,6 @@
//
//
// AstNode.cs
//
//
// Author:
// Mike Krüger <mkrueger@novell.com>
//
@ -26,13 +26,15 @@ @@ -26,13 +26,15 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace ICSharpCode.NRefactory.CSharp
{
public abstract class DomNode
{
#region Null
public static readonly DomNode Null = new NullAstNode ();
class NullAstNode : DomNode
sealed class NullAstNode : DomNode
{
public override NodeType NodeType {
get {
@ -51,6 +53,14 @@ namespace ICSharpCode.NRefactory.CSharp @@ -51,6 +53,14 @@ namespace ICSharpCode.NRefactory.CSharp
return default (S);
}
}
#endregion
DomNode parent;
DomNode prevSibling;
DomNode nextSibling;
DomNode firstChild;
DomNode lastChild;
int role;
public abstract NodeType NodeType {
get;
@ -63,8 +73,8 @@ namespace ICSharpCode.NRefactory.CSharp @@ -63,8 +73,8 @@ namespace ICSharpCode.NRefactory.CSharp
}
public virtual DomLocation StartLocation {
get {
var child = FirstChild;
get {
var child = firstChild;
if (child == null)
return DomLocation.Empty;
return child.StartLocation;
@ -72,8 +82,8 @@ namespace ICSharpCode.NRefactory.CSharp @@ -72,8 +82,8 @@ namespace ICSharpCode.NRefactory.CSharp
}
public virtual DomLocation EndLocation {
get {
var child = LastChild;
get {
var child = lastChild;
if (child == null)
return DomLocation.Empty;
return child.EndLocation;
@ -81,107 +91,166 @@ namespace ICSharpCode.NRefactory.CSharp @@ -81,107 +91,166 @@ namespace ICSharpCode.NRefactory.CSharp
}
public DomNode Parent {
get;
set;
get { return parent; }
}
public int Role {
get;
set;
get { return role; }
}
public DomNode NextSibling {
get;
set;
get { return nextSibling; }
}
public DomNode PrevSibling {
get;
set;
get { return prevSibling; }
}
public DomNode FirstChild {
get;
set;
get { return firstChild; }
}
public DomNode LastChild {
get;
set;
get { return lastChild; }
}
public IEnumerable<DomNode> Children {
get {
var cur = FirstChild;
var cur = firstChild;
while (cur != null) {
yield return cur;
cur = cur.NextSibling;
cur = cur.nextSibling;
}
}
}
public DomNode GetChildByRole (int role)
{
var cur = FirstChild;
var cur = firstChild;
while (cur != null) {
if (cur.Role == role)
if (cur.role == role)
return cur;
cur = cur.NextSibling;
cur = cur.nextSibling;
}
return null;
}
public IEnumerable<DomNode> GetChildrenByRole (int role)
{
var cur = FirstChild;
var cur = firstChild;
while (cur != null) {
if (cur.Role == role)
if (cur.role == role)
yield return cur;
cur = cur.NextSibling;
cur = cur.nextSibling;
}
}
public void AddChild (DomNode child)
public void AddChild (DomNode child, int role)
{
if (child == null)
return;
child.Parent = this;
if (FirstChild == null) {
LastChild = FirstChild = child;
if (child.parent != null)
throw new ArgumentException ("Node is already used in another tree.", "child");
child.parent = this;
child.role = role;
if (firstChild == null) {
lastChild = firstChild = child;
} else {
LastChild.NextSibling = child;
child.PrevSibling = LastChild;
LastChild = child;
lastChild.nextSibling = child;
child.prevSibling = lastChild;
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)
return;
child.Role = role;
AddChild (child);
if (child.parent != null)
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)
return;
if (FirstChild == null || nextSibling == null) {
AddChild (child, role);
if (parent != null) {
if (prevSibling != null) {
Debug.Assert(prevSibling.nextSibling == this);
prevSibling.nextSibling = nextSibling;
} 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;
}
child.Parent = this;
child.Role = role;
child.NextSibling = nextSibling;
if (nextSibling.PrevSibling != null) {
child.PrevSibling = nextSibling.PrevSibling;
nextSibling.PrevSibling.NextSibling = child;
if (newNode.parent != null)
throw new ArgumentException ("Node is already used in another tree.", "newNode");
newNode.parent = parent;
newNode.role = role;
newNode.prevSibling = prevSibling;
newNode.nextSibling = nextSibling;
if (parent != null) {
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);
@ -205,7 +274,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -205,7 +274,7 @@ namespace ICSharpCode.NRefactory.CSharp
public const int TargetExpression = 14;
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 RPar = 51; // )

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

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

Loading…
Cancel
Save