Skip to content

Commit 90ac054

Browse files
mikewallstedtblickly
mikewallstedt
authored andcommitted
Modify the AST to double link children nodes. This makes operations that require finding the left sibling of a node O(1), as opposed to O(n), at the expense of keeping an extra pointer per node.
Note that for a 64-bit JVM with compressed ops that align to 8 bytes, this should not actually increase memory consumption. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=126707949
1 parent e74ca62 commit 90ac054

File tree

2 files changed

+127
-44
lines changed

2 files changed

+127
-44
lines changed

src/com/google/javascript/rhino/Node.java

+96-44
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)