@@ -488,12 +488,15 @@ public Node(Token nodeType, Node child) {
488488 Preconditions .checkArgument (child .parent == null ,
489489 "new child has existing parent" );
490490 Preconditions .checkArgument (child .next == null ,
491- "new child has existing sibling" );
491+ "new child has existing next sibling" );
492+ Preconditions .checkArgument (child .previous == null ,
493+ "new child has existing previous sibling" );
492494
493495 token = nodeType ;
494496 parent = null ;
495497 first = last = child ;
496498 child .next = null ;
499+ child .previous = null ;
497500 child .parent = this ;
498501 sourcePosition = -1 ;
499502 }
@@ -502,62 +505,82 @@ public Node(Token nodeType, Node left, Node right) {
502505 Preconditions .checkArgument (left .parent == null ,
503506 "first new child has existing parent" );
504507 Preconditions .checkArgument (left .next == null ,
505- "first new child has existing sibling" );
508+ "first new child has existing next sibling" );
509+ Preconditions .checkArgument (left .previous == null ,
510+ "first new child has existing previous sibling" );
506511 Preconditions .checkArgument (right .parent == null ,
507512 "second new child has existing parent" );
508513 Preconditions .checkArgument (right .next == null ,
509- "second new child has existing sibling" );
514+ "second new child has existing next sibling" );
515+ Preconditions .checkArgument (right .previous == null ,
516+ "second new child has existing previous sibling" );
510517 token = nodeType ;
511518 parent = null ;
512519 first = left ;
513520 last = right ;
514521 left .next = right ;
522+ left .previous = null ;
515523 left .parent = this ;
516524 right .next = null ;
525+ right .previous = left ;
517526 right .parent = this ;
518527 sourcePosition = -1 ;
519528 }
520529
521530 public Node (Token nodeType , Node left , Node mid , Node right ) {
522531 Preconditions .checkArgument (left .parent == null );
523532 Preconditions .checkArgument (left .next == null );
533+ Preconditions .checkArgument (left .previous == null );
524534 Preconditions .checkArgument (mid .parent == null );
525535 Preconditions .checkArgument (mid .next == null );
536+ Preconditions .checkArgument (mid .previous == null );
526537 Preconditions .checkArgument (right .parent == null );
527538 Preconditions .checkArgument (right .next == null );
539+ Preconditions .checkArgument (right .previous == null );
528540 token = nodeType ;
529541 parent = null ;
530542 first = left ;
531543 last = right ;
532544 left .next = mid ;
545+ left .previous = null ;
533546 left .parent = this ;
534547 mid .next = right ;
548+ mid .previous = left ;
535549 mid .parent = this ;
536550 right .next = null ;
551+ right .previous = mid ;
537552 right .parent = this ;
538553 sourcePosition = -1 ;
539554 }
540555
541556 Node (Token nodeType , Node left , Node mid , Node mid2 , Node right ) {
542557 Preconditions .checkArgument (left .parent == null );
543558 Preconditions .checkArgument (left .next == null );
559+ Preconditions .checkArgument (left .previous == null );
544560 Preconditions .checkArgument (mid .parent == null );
545561 Preconditions .checkArgument (mid .next == null );
562+ Preconditions .checkArgument (mid .previous == null );
546563 Preconditions .checkArgument (mid2 .parent == null );
547564 Preconditions .checkArgument (mid2 .next == null );
565+ Preconditions .checkArgument (mid2 .previous == null );
548566 Preconditions .checkArgument (right .parent == null );
549567 Preconditions .checkArgument (right .next == null );
568+ Preconditions .checkArgument (right .previous == null );
550569 token = nodeType ;
551570 parent = null ;
552571 first = left ;
553572 last = right ;
554573 left .next = mid ;
574+ left .previous = null ;
555575 left .parent = this ;
556576 mid .next = mid2 ;
577+ mid .previous = left ;
557578 mid .parent = this ;
558579 mid2 .next = right ;
580+ mid2 .previous = mid ;
559581 mid2 .parent = this ;
560582 right .next = null ;
583+ right .previous = mid2 ;
561584 right .parent = this ;
562585 sourcePosition = -1 ;
563586 }
@@ -638,21 +661,7 @@ public Node getNext() {
638661 }
639662
640663 public Node getChildBefore (Node child ) {
641- if (child == first ) {
642- return null ;
643- }
644- Node n = first ;
645- if (n == null ) {
646- throw new RuntimeException ("node is not a child" );
647- }
648-
649- while (n .next != child ) {
650- n = n .next ;
651- if (n == null ) {
652- throw new RuntimeException ("node is not a child" );
653- }
654- }
655- return n ;
664+ return child .previous ;
656665 }
657666
658667 public Node getChildAtIndex (int i ) {
@@ -689,8 +698,12 @@ public Node getLastSibling() {
689698 public void addChildToFront (Node child ) {
690699 Preconditions .checkArgument (child .parent == null );
691700 Preconditions .checkArgument (child .next == null );
701+ Preconditions .checkArgument (child .previous == null );
692702 child .parent = this ;
693703 child .next = first ;
704+ if (first != null ) {
705+ first .previous = child ;
706+ }
694707 first = child ;
695708 if (last == null ) {
696709 last = child ;
@@ -700,8 +713,10 @@ public void addChildToFront(Node child) {
700713 public void addChildToBack (Node child ) {
701714 Preconditions .checkArgument (child .parent == null );
702715 Preconditions .checkArgument (child .next == null );
716+ Preconditions .checkArgument (child .previous == null );
703717 child .parent = this ;
704718 child .next = null ;
719+ child .previous = last ;
705720 if (last == null ) {
706721 first = last = child ;
707722 return ;
@@ -716,7 +731,11 @@ public void addChildrenToFront(Node children) {
716731 child .parent = this ;
717732 }
718733 Node lastSib = children .getLastSibling ();
734+ Preconditions .checkState (lastSib .next == null );
719735 lastSib .next = first ;
736+ if (first != null ) {
737+ first .previous = lastSib ;
738+ }
720739 first = children ;
721740 if (last == null ) {
722741 last = lastSib ;
@@ -734,25 +753,29 @@ public void addChildBefore(Node newChild, Node node) {
734753 Preconditions .checkArgument (node != null && node .parent == this ,
735754 "The existing child node of the parent should not be null." );
736755 Preconditions .checkArgument (newChild .next == null ,
737- "The new child node has siblings." );
756+ "The new child node has next siblings." );
757+ Preconditions .checkArgument (newChild .previous == null ,
758+ "The new child node has previous siblings." );
738759 Preconditions .checkArgument (newChild .parent == null ,
739760 "The new child node already has a parent." );
740761 if (first == node ) {
741762 newChild .parent = this ;
742763 newChild .next = first ;
764+ first .previous = newChild ;
743765 first = newChild ;
744766 return ;
745767 }
746- Node prev = getChildBefore (node );
747- addChildAfter (newChild , prev );
768+ addChildAfter (newChild , node .previous );
748769 }
749770
750771 /**
751772 * Add 'child' after 'node'.
752773 */
753774 public void addChildAfter (Node newChild , Node node ) {
754775 Preconditions .checkArgument (newChild .next == null ,
755- "The new child node has siblings." );
776+ "The new child node has next siblings." );
777+ Preconditions .checkArgument (newChild .previous == null ,
778+ "The new child node has previous siblings." );
756779 addChildrenAfter (newChild , node );
757780 }
758781
@@ -770,14 +793,19 @@ public void addChildrenAfter(Node children, Node node) {
770793 if (node != null ) {
771794 Node oldNext = node .next ;
772795 node .next = children ;
796+ children .previous = node ;
773797 lastSibling .next = oldNext ;
798+ if (oldNext != null ) {
799+ oldNext .previous = lastSibling ;
800+ }
774801 if (node == last ) {
775802 last = lastSibling ;
776803 }
777804 } else {
778805 // Append to the beginning.
779806 if (first != null ) {
780807 lastSibling .next = first ;
808+ first .previous = lastSibling ;
781809 } else {
782810 last = lastSibling ;
783811 }
@@ -789,16 +817,21 @@ public void addChildrenAfter(Node children, Node node) {
789817 * Detach a child from its parent and siblings.
790818 */
791819 public void removeChild (Node child ) {
792- Node prev = getChildBefore (child );
793- if (prev == null ) {
794- first = first .next ;
795- } else {
820+ Node prev = child .previous ;
821+ if (first == child ) {
822+ first = child .next ;
823+ }
824+ if (prev != null ) {
796825 prev .next = child .next ;
797826 }
798- if (child == last ) {
827+ if (last == child ) {
799828 last = prev ;
800829 }
830+ if (child .next != null ) {
831+ child .next .previous = prev ;
832+ }
801833 child .next = null ;
834+ child .previous = null ;
802835 child .parent = null ;
803836 }
804837
@@ -807,49 +840,61 @@ public void removeChild(Node child) {
807840 */
808841 public void replaceChild (Node child , Node newChild ) {
809842 Preconditions .checkArgument (newChild .next == null ,
810- "The new child node has siblings." );
843+ "The new child node has next siblings." );
844+ Preconditions .checkArgument (newChild .previous == null ,
845+ "The new child node has previous siblings." );
811846 Preconditions .checkArgument (newChild .parent == null ,
812847 "The new child node already has a parent." );
813848
814849 // Copy over important information.
815850 newChild .copyInformationFrom (child );
816851
817852 newChild .next = child .next ;
853+ newChild .previous = child .previous ;
818854 newChild .parent = this ;
819855 if (child == first ) {
820856 first = newChild ;
821857 } else {
822- Node prev = getChildBefore (child );
823- prev .next = newChild ;
858+ child .previous .next = newChild ;
824859 }
825860 if (child == last ) {
826861 last = newChild ;
862+ } else {
863+ child .next .previous = newChild ;
827864 }
828865 child .next = null ;
866+ child .previous = null ;
829867 child .parent = null ;
830868 }
831869
832870 public void replaceChildAfter (Node prevChild , Node newChild ) {
833871 Preconditions .checkArgument (prevChild .parent == this ,
834872 "prev is not a child of this node." );
835-
873+ Preconditions .checkArgument (prevChild .next != null ,
874+ "prev is doesn't have a sibling to replace." );
836875 Preconditions .checkArgument (newChild .next == null ,
837- "The new child node has siblings." );
876+ "The new child node has next siblings." );
877+ Preconditions .checkArgument (newChild .previous == null ,
878+ "The new child node has previous siblings." );
838879 Preconditions .checkArgument (newChild .parent == null ,
839880 "The new child node already has a parent." );
840881
841882 // Copy over important information.
842- newChild .copyInformationFrom (prevChild );
883+ newChild .copyInformationFrom (prevChild . next );
843884
844- Node child = prevChild .next ;
845- newChild .next = child .next ;
885+ Node childToReplace = prevChild .next ;
886+ newChild .next = childToReplace .next ;
887+ newChild .previous = prevChild ;
846888 newChild .parent = this ;
847889 prevChild .next = newChild ;
848- if (child == last ) {
890+ if (childToReplace == last ) {
849891 last = newChild ;
892+ } else {
893+ childToReplace .next .previous = newChild ;
850894 }
851- child .next = null ;
852- child .parent = null ;
895+ childToReplace .next = null ;
896+ childToReplace .previous = null ;
897+ childToReplace .parent = null ;
853898 }
854899
855900 /** Detaches the child after the given child, or the first child if prev is null. */
@@ -1163,6 +1208,7 @@ private static void toStringTreeHelper(Node n, int level, Appendable sb)
11631208
11641209 Token token ; // Type of the token of the node; NAME for example
11651210 Node next ; // next sibling
1211+ Node previous ; // previous sibling
11661212 private Node first ; // first element of a linked list of children
11671213 private Node last ; // last element of a linked list of children
11681214
@@ -1977,6 +2023,7 @@ public void detachChildren() {
19772023 Node nextChild = child .getNext ();
19782024 child .parent = null ;
19792025 child .next = null ;
2026+ child .previous = null ;
19802027 child = nextChild ;
19812028 }
19822029 first = null ;
@@ -1989,14 +2036,18 @@ public Node removeChildAfter(Node prev) {
19892036 Preconditions .checkArgument (prev .next != null ,
19902037 "no next sibling." );
19912038
1992- Node child = prev .next ;
1993- prev .next = child .next ;
1994- if (child == last ) {
2039+ Node childToRemove = prev .next ;
2040+ prev .next = childToRemove .next ;
2041+ if (childToRemove == last ) {
19952042 last = prev ;
19962043 }
1997- child .next = null ;
1998- child .parent = null ;
1999- return child ;
2044+ if (childToRemove .next != null ) {
2045+ childToRemove .next .previous = prev ;
2046+ }
2047+ childToRemove .next = null ;
2048+ childToRemove .previous = null ;
2049+ childToRemove .parent = null ;
2050+ return childToRemove ;
20002051 }
20012052
20022053 /** Remove the child after the given child, or the first child if given null. */
@@ -2051,6 +2102,7 @@ public Node cloneTree(boolean cloneTypeExprs) {
20512102 n2clone .parent = result ;
20522103 if (result .last != null ) {
20532104 result .last .next = n2clone ;
2105+ n2clone .previous = result .last ;
20542106 }
20552107 if (result .first == null ) {
20562108 result .first = n2clone ;
0 commit comments