mergeSingletons static method

Merge two SingletonPredictionContext instances.

Stack tops equal, parents merge is same; return left graph.

Same stack top, parents differ; merge parents giving array node, then remainders of those graphs. A new root node is created to point to the merged parents.

Different stack tops pointing to same parent. Make array node for the root where both element in the root point to the same (original) parent.

Different stack tops pointing to different parents. Make array node for the root where each element points to the corresponding original parent.

@param a the first SingletonPredictionContext @param b the second SingletonPredictionContext @param rootIsWildcard true if this is a local-context merge, otherwise false to indicate a full-context merge @param mergeCache

Implementation

static PredictionContext mergeSingletons(
  SingletonPredictionContext a,
  SingletonPredictionContext b,
  bool rootIsWildcard,
  Map<Pair<PredictionContext, PredictionContext>, PredictionContext>?
      mergeCache,
) {
  if (mergeCache != null) {
    var previous = mergeCache[Pair(a, b)];
    if (previous != null) return previous;
    previous = mergeCache[Pair(b, a)];
    if (previous != null) return previous;
  }

  final rootMerge = mergeRoot(a, b, rootIsWildcard);
  if (rootMerge != null) {
    if (mergeCache != null) mergeCache[Pair(a, b)] = rootMerge;
    return rootMerge;
  }

  if (a.returnState == b.returnState) {
    assert(a.parent != null &&
        b.parent != null); // must be empty context, never null

    // a == b
    final parent = merge(a.parent!, b.parent!, rootIsWildcard, mergeCache);
    // if parent is same as existing a or b parent or reduced to a parent, return it
    if (parent == a.parent) return a; // ax + bx = ax, if a=b
    if (parent == b.parent) return b; // ax + bx = bx, if a=b
    // else: ax + ay = a'[x,y]
    // merge parents x and y, giving array node with x,y then remainders
    // of those graphs.  dup a, a' points at merged array
    // new joined parent so create new singleton pointing to it, a'
    PredictionContext a_ =
        SingletonPredictionContext.create(parent, a.returnState);
    if (mergeCache != null) mergeCache[Pair(a, b)] = a_;
    return a_;
  } else {
    // a != b payloads differ
    // see if we can collapse parents due to $+x parents if local ctx
    PredictionContext? singleParent;
    if (a == b || (a.parent != null && a.parent == b.parent)) {
      // ax + bx = [a,b]x
      singleParent = a.parent;
    }
    if (singleParent != null) {
      // parents are same
      // sort payloads and use same parent
      final payloads = <int>[a.returnState, b.returnState];
      if (a.returnState > b.returnState) {
        payloads[0] = b.returnState;
        payloads[1] = a.returnState;
      }
      final parents = <PredictionContext>[singleParent, singleParent];
      PredictionContext a_ = ArrayPredictionContext(parents, payloads);
      if (mergeCache != null) mergeCache[Pair(a, b)] = a_;
      return a_;
    }
    // parents differ and can't merge them. Just pack together
    // into array; can't merge.
    // ax + by = [ax,by]
    final payloads = <int>[a.returnState, b.returnState];
    var parents = <PredictionContext?>[a.parent, b.parent];
    if (a.returnState > b.returnState) {
      // sort by payload
      payloads[0] = b.returnState;
      payloads[1] = a.returnState;
      parents = [b.parent, a.parent];
    }
    PredictionContext a_ = ArrayPredictionContext(parents, payloads);
    if (mergeCache != null) mergeCache[Pair(a, b)] = a_;
    return a_;
  }
}