All files / src/edits patchAst.js

94.87% Statements 37/39
91.67% Branches 11/12
100% Functions 6/6
94.87% Lines 37/39

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 651x       31x     31x         29x 29x 29x 29x 29x 51x 51x 51x 51x 51x           14x 14x 14x 31x   14x 31x     14x   14x 14x 40x 29x 29x 29x 29x 29x   11x     14x 31x   14x 11x 11x         14x 14x 14x    
import {assert} from '../utils';
 
// defaultdict with empty list
function addIndex(container, k, v) {
  Iif (container[k]) {
    container[k].push(v);
  } else {
    container[k] = [v];
  }
}
 
function copyAllIds(oldTree, newTree) {
  const oldIter = oldTree.descendants()[Symbol.iterator]();
  const newIter = newTree.descendants()[Symbol.iterator]();
  let oldPtr = oldIter.next();
  let newPtr = newIter.next();
  while (!oldPtr.done) {
    assert(!newPtr.done);
    newPtr.value.id = oldPtr.value.id;
    newPtr.value.element = oldPtr.value.element;
    oldPtr = oldIter.next();
    newPtr = newIter.next();
  }
}
 
export default function unify(oldTree, newTree) {
  function loop(oldTree, newTree) {
    newTree.id = oldTree.id;
    const index = {};
    for (const oldNode of oldTree.children()) {
      addIndex(index, oldNode.hash, oldNode);
    }
    for (const key in index) {
      index[key].reverse();
    }
 
    const processed = new Set();
 
    let partiallySuccess = false;
    const newLeftover = [...newTree.children()].filter(newNode => {
      if (index[newNode.hash]?.length > 0) {
        const oldNode = index[newNode.hash].pop();
        copyAllIds(oldNode, newNode);
        partiallySuccess = true;
        processed.add(oldNode.id);
        return false;
      } else {
        return true;
      }
    });
    const oldLeftover = [...oldTree.children()].filter(oldNode => {
      return !processed.has(oldNode.id);
    });
    if (partiallySuccess || newLeftover.length <= 1) {
      const commonLength = Math.min(oldLeftover.length, newLeftover.length);
      for (let i = 0; i < commonLength; i++) {
        loop(oldLeftover[i], newLeftover[i]);
      }
    }
  }
  loop(oldTree, newTree);
  newTree.annotateNodes();
  return newTree;
}