public AstNode ReplaceWith(Func <AstNode, AstNode> replaceFunction) { if (replaceFunction == null) { throw new ArgumentNullException("replaceFunction"); } if (parent == null) { throw new InvalidOperationException(this.IsNull ? "Cannot replace the null nodes" : "Cannot replace the root node"); } AstNode oldParent = parent; AstNode oldSuccessor = nextSibling; Role oldRole = role; Remove(); AstNode replacement = replaceFunction(this); if (oldSuccessor != null && oldSuccessor.parent != oldParent) { throw new InvalidOperationException("replace function changed nextSibling of node being replaced?"); } if (!(replacement == null || replacement.IsNull)) { if (replacement.parent != null) { throw new InvalidOperationException("replace function must return the root of a tree"); } if (!oldRole.IsValid(replacement)) { throw new InvalidOperationException(string.Format("The new node '{0}' is not valid in the role {1}", replacement.GetType().Name, oldRole.ToString())); } if (oldSuccessor != null) { oldParent.InsertChildBeforeUnsafe(oldSuccessor, replacement, oldRole); } else { oldParent.AddChildUnsafe(replacement, oldRole); } } return(replacement); }
/// <summary> /// Replaces this node with the new node. /// </summary> public void ReplaceWith(AstNode newNode) { if (newNode == null || newNode.IsNull) { Remove(); return; } if (newNode == this) { return; // nothing to do... } if (parent == null) { throw new InvalidOperationException(this.IsNull ? "Cannot replace the null nodes" : "Cannot replace the root node"); } // Because this method doesn't statically check the new node's type with the role, // we perform a runtime test: if (!role.IsValid(newNode)) { throw new ArgumentException(string.Format("The new node '{0}' is not valid in the role {1}", newNode.GetType().Name, role.ToString()), "newNode"); } if (newNode.parent != null) { // newNode is used within this tree? if (newNode.Ancestors.Contains(this)) { // e.g. "parenthesizedExpr.ReplaceWith(parenthesizedExpr.Expression);" // enable automatic removal newNode.Remove(); } else { 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; role = Roles.Root; } }