public static JsNode FixParenthesis(this JsNode node) { var visitor = new JsParensFixingVisitor(); node.AcceptVisitor(visitor); return(node); }
protected virtual void DefaultVisit(JsNode node) { foreach (var c in node.Children) { c.AcceptVisitor(this); } }
/// <summary> /// Removes this node from its parent. /// </summary> public JsNode Remove() { if (parent != null) { ThrowIfFrozen(); 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; } return(this); }
public void InsertChildBefore <T>(JsNode nextSibling, T child, JsTreeRole <T> role) where T : JsNode { if (role == null) { throw new ArgumentNullException("role"); } if (nextSibling == null) { AddChild(child, role); return; } if (child == null) { return; } ThrowIfFrozen(); if (child.parent != null) { throw new ArgumentException("Node is already used in another tree.", "child"); } if (child.IsFrozen) { throw new ArgumentException("Cannot add a frozen node.", "child"); } if (nextSibling.parent != this) { throw new ArgumentException("NextSibling is not a child of this node.", "nextSibling"); } // No need to test for "Cannot add children to null nodes", // as there isn't any valid nextSibling in null nodes. InsertChildBeforeUnsafe(nextSibling, child, role); }
public static ParametrizedCode FormatParametrizedScript(this JsNode node, bool niceMode = false, string indent = "\t") { node.FixParenthesis(); var visitor = new JsFormattingVisitor(niceMode, indent); node.AcceptVisitor(visitor); return(visitor.GetResult(JsParensFixingVisitor.GetOperatorPrecedence(node as JsExpression))); }
public static string FormatScript(this JsNode node, bool niceMode = false, string indent = "\t", bool isDebugString = false) { node.FixParenthesis(); var visitor = new JsFormattingVisitor(niceMode, indent); node.AcceptVisitor(visitor); return(isDebugString ? visitor.ToString() : visitor.GetParameterlessResult()); }
public JsNodeCollection(JsNode node, JsTreeRole <T> role) { if (node == null) { throw new ArgumentNullException("node"); } if (role == null) { throw new ArgumentNullException("role"); } this.node = node; this.role = role; }
/// <summary> /// Adds a child without performing any safety checks. /// </summary> internal void AddChildUnsafe(JsNode child, JsTreeRole role) { child.parent = this; child.role = role; if (firstChild == null) { lastChild = firstChild = child; } else { lastChild.nextSibling = child; child.prevSibling = lastChild; lastChild = child; } }
/// <summary> /// Applies the <paramref name="visitor"/> to all nodes in this collection. /// </summary> public void AcceptVisitor(IJsNodeVisitor visitor) { JsNode next; for (JsNode cur = node.FirstChild; cur != null; cur = next) { Debug.Assert(cur.Parent == node); // Remember next before yielding cur. // This allows removing/replacing nodes while iterating through the list. next = cur.NextSibling; if (cur.Role == role) { cur.AcceptVisitor(visitor); } } }
public IEnumerator <T> GetEnumerator() { JsNode next; for (JsNode cur = node.FirstChild; cur != null; cur = next) { Debug.Assert(cur.Parent == node); // 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); } } }
public JsNode ReplaceWith(Func <JsNode, JsNode> replaceFunction) { if (replaceFunction == null) { throw new ArgumentNullException("replaceFunction"); } if (parent == null) { throw new InvalidOperationException("Cannot replace the root node"); } var oldParent = parent; var oldSuccessor = nextSibling; var oldRole = this.Role; Remove(); JsNode replacement = replaceFunction(this); if (oldSuccessor != null && oldSuccessor.parent != oldParent) { throw new InvalidOperationException("replace function changed nextSibling of node being replaced?"); } if (replacement != null) { 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); }
internal void InsertChildBeforeUnsafe(JsNode nextSibling, JsNode child, JsTreeRole role) { 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 AddChildWithExistingRole(JsNode child) { if (child == null) { return; } ThrowIfFrozen(); if (child == this) { throw new ArgumentException("Cannot add a node to itself as a child.", "child"); } if (child.parent != null) { throw new ArgumentException("Node is already used in another tree.", "child"); } if (child.IsFrozen) { throw new ArgumentException("Cannot add a frozen node.", "child"); } AddChildUnsafe(child, child.Role); }
/// <summary> /// Clones the whole subtree starting at this AST node. /// </summary> /// <remarks>Annotations are copied over to the new nodes; and any annotations implementing ICloneable will be cloned.</remarks> public JsNode Clone() { JsNode copy = (JsNode)this.MemberwiseClone(); // First, reset the shallow pointer copies copy.parent = null; copy.firstChild = null; copy.lastChild = null; copy.prevSibling = null; copy.nextSibling = null; copy.isFrozen = false; // Then perform a deep copy: for (JsNode cur = firstChild; cur != null; cur = cur.nextSibling) { copy.AddChildUnsafe(cur.Clone(), cur.Role); } // Finally, clone the annotation, if necessary copy.CloneAnnotations(); return(copy); }
/// <summary> /// Replaces this node with the new node. /// </summary> public void ReplaceWith(JsNode newNode) { if (newNode == null) { Remove(); return; } if (newNode == this) { return; // nothing to do... } if (parent == null) { throw new InvalidOperationException("Cannot replace the root node"); } ThrowIfFrozen(); // Because this method doesn't statically check the new node's type with the role, // we perform a runtime test: if (!this.Role.IsValid(newNode)) { throw new ArgumentException($"The new node '{newNode.GetType().Name}' is not valid in the role {this.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"); } } if (newNode.IsFrozen) { throw new ArgumentException("Cannot add a frozen node.", "newNode"); } newNode.parent = parent; newNode.role = this.Role; newNode.prevSibling = prevSibling; newNode.nextSibling = nextSibling; 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; }
public void InsertChildAfter <T>(JsNode prevSibling, T child, JsTreeRole <T> role) where T : JsNode { InsertChildBefore(prevSibling == null ? firstChild : prevSibling.nextSibling, child, role); }