Skip to content

Commit

Permalink
Modify the AST to double link children nodes. This makes operations t…
Browse files Browse the repository at this point in the history
…hat 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
  • Loading branch information
mikewallstedt authored and blickly committed Jul 7, 2016
1 parent e74ca62 commit 90ac054
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 44 deletions.
140 changes: 96 additions & 44 deletions src/com/google/javascript/rhino/Node.java
Expand Up @@ -488,12 +488,15 @@ public Node(Token nodeType, Node child) {
Preconditions.checkArgument(child.parent == null, Preconditions.checkArgument(child.parent == null,
"new child has existing parent"); "new child has existing parent");
Preconditions.checkArgument(child.next == null, Preconditions.checkArgument(child.next == null,
"new child has existing sibling"); "new child has existing next sibling");
Preconditions.checkArgument(child.previous == null,
"new child has existing previous sibling");


token = nodeType; token = nodeType;
parent = null; parent = null;
first = last = child; first = last = child;
child.next = null; child.next = null;
child.previous = null;
child.parent = this; child.parent = this;
sourcePosition = -1; sourcePosition = -1;
} }
Expand All @@ -502,62 +505,82 @@ public Node(Token nodeType, Node left, Node right) {
Preconditions.checkArgument(left.parent == null, Preconditions.checkArgument(left.parent == null,
"first new child has existing parent"); "first new child has existing parent");
Preconditions.checkArgument(left.next == null, Preconditions.checkArgument(left.next == null,
"first new child has existing sibling"); "first new child has existing next sibling");
Preconditions.checkArgument(left.previous == null,
"first new child has existing previous sibling");
Preconditions.checkArgument(right.parent == null, Preconditions.checkArgument(right.parent == null,
"second new child has existing parent"); "second new child has existing parent");
Preconditions.checkArgument(right.next == null, Preconditions.checkArgument(right.next == null,
"second new child has existing sibling"); "second new child has existing next sibling");
Preconditions.checkArgument(right.previous == null,
"second new child has existing previous sibling");
token = nodeType; token = nodeType;
parent = null; parent = null;
first = left; first = left;
last = right; last = right;
left.next = right; left.next = right;
left.previous = null;
left.parent = this; left.parent = this;
right.next = null; right.next = null;
right.previous = left;
right.parent = this; right.parent = this;
sourcePosition = -1; sourcePosition = -1;
} }


public Node(Token nodeType, Node left, Node mid, Node right) { public Node(Token nodeType, Node left, Node mid, Node right) {
Preconditions.checkArgument(left.parent == null); Preconditions.checkArgument(left.parent == null);
Preconditions.checkArgument(left.next == null); Preconditions.checkArgument(left.next == null);
Preconditions.checkArgument(left.previous == null);
Preconditions.checkArgument(mid.parent == null); Preconditions.checkArgument(mid.parent == null);
Preconditions.checkArgument(mid.next == null); Preconditions.checkArgument(mid.next == null);
Preconditions.checkArgument(mid.previous == null);
Preconditions.checkArgument(right.parent == null); Preconditions.checkArgument(right.parent == null);
Preconditions.checkArgument(right.next == null); Preconditions.checkArgument(right.next == null);
Preconditions.checkArgument(right.previous == null);
token = nodeType; token = nodeType;
parent = null; parent = null;
first = left; first = left;
last = right; last = right;
left.next = mid; left.next = mid;
left.previous = null;
left.parent = this; left.parent = this;
mid.next = right; mid.next = right;
mid.previous = left;
mid.parent = this; mid.parent = this;
right.next = null; right.next = null;
right.previous = mid;
right.parent = this; right.parent = this;
sourcePosition = -1; sourcePosition = -1;
} }


Node(Token nodeType, Node left, Node mid, Node mid2, Node right) { Node(Token nodeType, Node left, Node mid, Node mid2, Node right) {
Preconditions.checkArgument(left.parent == null); Preconditions.checkArgument(left.parent == null);
Preconditions.checkArgument(left.next == null); Preconditions.checkArgument(left.next == null);
Preconditions.checkArgument(left.previous == null);
Preconditions.checkArgument(mid.parent == null); Preconditions.checkArgument(mid.parent == null);
Preconditions.checkArgument(mid.next == null); Preconditions.checkArgument(mid.next == null);
Preconditions.checkArgument(mid.previous == null);
Preconditions.checkArgument(mid2.parent == null); Preconditions.checkArgument(mid2.parent == null);
Preconditions.checkArgument(mid2.next == null); Preconditions.checkArgument(mid2.next == null);
Preconditions.checkArgument(mid2.previous == null);
Preconditions.checkArgument(right.parent == null); Preconditions.checkArgument(right.parent == null);
Preconditions.checkArgument(right.next == null); Preconditions.checkArgument(right.next == null);
Preconditions.checkArgument(right.previous == null);
token = nodeType; token = nodeType;
parent = null; parent = null;
first = left; first = left;
last = right; last = right;
left.next = mid; left.next = mid;
left.previous = null;
left.parent = this; left.parent = this;
mid.next = mid2; mid.next = mid2;
mid.previous = left;
mid.parent = this; mid.parent = this;
mid2.next = right; mid2.next = right;
mid2.previous = mid;
mid2.parent = this; mid2.parent = this;
right.next = null; right.next = null;
right.previous = mid2;
right.parent = this; right.parent = this;
sourcePosition = -1; sourcePosition = -1;
} }
Expand Down Expand Up @@ -638,21 +661,7 @@ public Node getNext() {
} }


public Node getChildBefore(Node child) { public Node getChildBefore(Node child) {
if (child == first) { return child.previous;
return null;
}
Node n = first;
if (n == null) {
throw new RuntimeException("node is not a child");
}

while (n.next != child) {
n = n.next;
if (n == null) {
throw new RuntimeException("node is not a child");
}
}
return n;
} }


public Node getChildAtIndex(int i) { public Node getChildAtIndex(int i) {
Expand Down Expand Up @@ -689,8 +698,12 @@ public Node getLastSibling() {
public void addChildToFront(Node child) { public void addChildToFront(Node child) {
Preconditions.checkArgument(child.parent == null); Preconditions.checkArgument(child.parent == null);
Preconditions.checkArgument(child.next == null); Preconditions.checkArgument(child.next == null);
Preconditions.checkArgument(child.previous == null);
child.parent = this; child.parent = this;
child.next = first; child.next = first;
if (first != null) {
first.previous = child;
}
first = child; first = child;
if (last == null) { if (last == null) {
last = child; last = child;
Expand All @@ -700,8 +713,10 @@ public void addChildToFront(Node child) {
public void addChildToBack(Node child) { public void addChildToBack(Node child) {
Preconditions.checkArgument(child.parent == null); Preconditions.checkArgument(child.parent == null);
Preconditions.checkArgument(child.next == null); Preconditions.checkArgument(child.next == null);
Preconditions.checkArgument(child.previous == null);
child.parent = this; child.parent = this;
child.next = null; child.next = null;
child.previous = last;
if (last == null) { if (last == null) {
first = last = child; first = last = child;
return; return;
Expand All @@ -716,7 +731,11 @@ public void addChildrenToFront(Node children) {
child.parent = this; child.parent = this;
} }
Node lastSib = children.getLastSibling(); Node lastSib = children.getLastSibling();
Preconditions.checkState(lastSib.next == null);
lastSib.next = first; lastSib.next = first;
if (first != null) {
first.previous = lastSib;
}
first = children; first = children;
if (last == null) { if (last == null) {
last = lastSib; last = lastSib;
Expand All @@ -734,25 +753,29 @@ public void addChildBefore(Node newChild, Node node) {
Preconditions.checkArgument(node != null && node.parent == this, Preconditions.checkArgument(node != null && node.parent == this,
"The existing child node of the parent should not be null."); "The existing child node of the parent should not be null.");
Preconditions.checkArgument(newChild.next == null, Preconditions.checkArgument(newChild.next == null,
"The new child node has siblings."); "The new child node has next siblings.");
Preconditions.checkArgument(newChild.previous == null,
"The new child node has previous siblings.");
Preconditions.checkArgument(newChild.parent == null, Preconditions.checkArgument(newChild.parent == null,
"The new child node already has a parent."); "The new child node already has a parent.");
if (first == node) { if (first == node) {
newChild.parent = this; newChild.parent = this;
newChild.next = first; newChild.next = first;
first.previous = newChild;
first = newChild; first = newChild;
return; return;
} }
Node prev = getChildBefore(node); addChildAfter(newChild, node.previous);
addChildAfter(newChild, prev);
} }


/** /**
* Add 'child' after 'node'. * Add 'child' after 'node'.
*/ */
public void addChildAfter(Node newChild, Node node) { public void addChildAfter(Node newChild, Node node) {
Preconditions.checkArgument(newChild.next == null, Preconditions.checkArgument(newChild.next == null,
"The new child node has siblings."); "The new child node has next siblings.");
Preconditions.checkArgument(newChild.previous == null,
"The new child node has previous siblings.");
addChildrenAfter(newChild, node); addChildrenAfter(newChild, node);
} }


Expand All @@ -770,14 +793,19 @@ public void addChildrenAfter(Node children, Node node) {
if (node != null) { if (node != null) {
Node oldNext = node.next; Node oldNext = node.next;
node.next = children; node.next = children;
children.previous = node;
lastSibling.next = oldNext; lastSibling.next = oldNext;
if (oldNext != null) {
oldNext.previous = lastSibling;
}
if (node == last) { if (node == last) {
last = lastSibling; last = lastSibling;
} }
} else { } else {
// Append to the beginning. // Append to the beginning.
if (first != null) { if (first != null) {
lastSibling.next = first; lastSibling.next = first;
first.previous = lastSibling;
} else { } else {
last = lastSibling; last = lastSibling;
} }
Expand All @@ -789,16 +817,21 @@ public void addChildrenAfter(Node children, Node node) {
* Detach a child from its parent and siblings. * Detach a child from its parent and siblings.
*/ */
public void removeChild(Node child) { public void removeChild(Node child) {
Node prev = getChildBefore(child); Node prev = child.previous;
if (prev == null) { if (first == child) {
first = first.next; first = child.next;
} else { }
if (prev != null) {
prev.next = child.next; prev.next = child.next;
} }
if (child == last) { if (last == child) {
last = prev; last = prev;
} }
if (child.next != null) {
child.next.previous = prev;
}
child.next = null; child.next = null;
child.previous = null;
child.parent = null; child.parent = null;
} }


Expand All @@ -807,49 +840,61 @@ public void removeChild(Node child) {
*/ */
public void replaceChild(Node child, Node newChild) { public void replaceChild(Node child, Node newChild) {
Preconditions.checkArgument(newChild.next == null, Preconditions.checkArgument(newChild.next == null,
"The new child node has siblings."); "The new child node has next siblings.");
Preconditions.checkArgument(newChild.previous == null,
"The new child node has previous siblings.");
Preconditions.checkArgument(newChild.parent == null, Preconditions.checkArgument(newChild.parent == null,
"The new child node already has a parent."); "The new child node already has a parent.");


// Copy over important information. // Copy over important information.
newChild.copyInformationFrom(child); newChild.copyInformationFrom(child);


newChild.next = child.next; newChild.next = child.next;
newChild.previous = child.previous;
newChild.parent = this; newChild.parent = this;
if (child == first) { if (child == first) {
first = newChild; first = newChild;
} else { } else {
Node prev = getChildBefore(child); child.previous.next = newChild;
prev.next = newChild;
} }
if (child == last) { if (child == last) {
last = newChild; last = newChild;
} else {
child.next.previous = newChild;
} }
child.next = null; child.next = null;
child.previous = null;
child.parent = null; child.parent = null;
} }


public void replaceChildAfter(Node prevChild, Node newChild) { public void replaceChildAfter(Node prevChild, Node newChild) {
Preconditions.checkArgument(prevChild.parent == this, Preconditions.checkArgument(prevChild.parent == this,
"prev is not a child of this node."); "prev is not a child of this node.");

Preconditions.checkArgument(prevChild.next != null,
"prev is doesn't have a sibling to replace.");
Preconditions.checkArgument(newChild.next == null, Preconditions.checkArgument(newChild.next == null,
"The new child node has siblings."); "The new child node has next siblings.");
Preconditions.checkArgument(newChild.previous == null,
"The new child node has previous siblings.");
Preconditions.checkArgument(newChild.parent == null, Preconditions.checkArgument(newChild.parent == null,
"The new child node already has a parent."); "The new child node already has a parent.");


// Copy over important information. // Copy over important information.
newChild.copyInformationFrom(prevChild); newChild.copyInformationFrom(prevChild.next);


Node child = prevChild.next; Node childToReplace = prevChild.next;
newChild.next = child.next; newChild.next = childToReplace.next;
newChild.previous = prevChild;
newChild.parent = this; newChild.parent = this;
prevChild.next = newChild; prevChild.next = newChild;
if (child == last) { if (childToReplace == last) {
last = newChild; last = newChild;
} else {
childToReplace.next.previous = newChild;
} }
child.next = null; childToReplace.next = null;
child.parent = null; childToReplace.previous = null;
childToReplace.parent = null;
} }


/** Detaches the child after the given child, or the first child if prev is null. */ /** Detaches the child after the given child, or the first child if prev is null. */
Expand Down Expand Up @@ -1163,6 +1208,7 @@ private static void toStringTreeHelper(Node n, int level, Appendable sb)


Token token; // Type of the token of the node; NAME for example Token token; // Type of the token of the node; NAME for example
Node next; // next sibling Node next; // next sibling
Node previous; // previous sibling
private Node first; // first element of a linked list of children private Node first; // first element of a linked list of children
private Node last; // last element of a linked list of children private Node last; // last element of a linked list of children


Expand Down Expand Up @@ -1977,6 +2023,7 @@ public void detachChildren() {
Node nextChild = child.getNext(); Node nextChild = child.getNext();
child.parent = null; child.parent = null;
child.next = null; child.next = null;
child.previous = null;
child = nextChild; child = nextChild;
} }
first = null; first = null;
Expand All @@ -1989,14 +2036,18 @@ public Node removeChildAfter(Node prev) {
Preconditions.checkArgument(prev.next != null, Preconditions.checkArgument(prev.next != null,
"no next sibling."); "no next sibling.");


Node child = prev.next; Node childToRemove = prev.next;
prev.next = child.next; prev.next = childToRemove.next;
if (child == last) { if (childToRemove == last) {
last = prev; last = prev;
} }
child.next = null; if (childToRemove.next != null) {
child.parent = null; childToRemove.next.previous = prev;
return child; }
childToRemove.next = null;
childToRemove.previous = null;
childToRemove.parent = null;
return childToRemove;
} }


/** Remove the child after the given child, or the first child if given null. */ /** Remove the child after the given child, or the first child if given null. */
Expand Down Expand Up @@ -2051,6 +2102,7 @@ public Node cloneTree(boolean cloneTypeExprs) {
n2clone.parent = result; n2clone.parent = result;
if (result.last != null) { if (result.last != null) {
result.last.next = n2clone; result.last.next = n2clone;
n2clone.previous = result.last;
} }
if (result.first == null) { if (result.first == null) {
result.first = n2clone; result.first = n2clone;
Expand Down

0 comments on commit 90ac054

Please sign in to comment.