示例#1
0
        public static JsNode FixParenthesis(this JsNode node)
        {
            var visitor = new JsParensFixingVisitor();

            node.AcceptVisitor(visitor);
            return(node);
        }
示例#2
0
 protected virtual void DefaultVisit(JsNode node)
 {
     foreach (var c in node.Children)
     {
         c.AcceptVisitor(this);
     }
 }
示例#3
0
 /// <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);
 }
示例#4
0
        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);
        }
示例#5
0
        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)));
        }
示例#6
0
        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());
        }
示例#7
0
 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;
 }
示例#8
0
 /// <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;
     }
 }
示例#9
0
        /// <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);
                }
            }
        }
示例#10
0
        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);
                }
            }
        }
示例#11
0
        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);
        }
示例#12
0
        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;
        }
示例#13
0
 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);
 }
示例#14
0
        /// <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);
        }
示例#15
0
        /// <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;
        }
示例#16
0
 public void InsertChildAfter <T>(JsNode prevSibling, T child, JsTreeRole <T> role) where T : JsNode
 {
     InsertChildBefore(prevSibling == null ? firstChild : prevSibling.nextSibling, child, role);
 }