private static Op transformFilterQuadPattern(
      ExprList exprs, Set<Var> patternVarsScope, Node graphNode, BasicPattern pattern) {
    // Any filters that depend on no variables.
    Op op = insertAnyFilter(exprs, patternVarsScope, null);
    if (Var.isVar(graphNode)) {
      // Add in the graph node of the quad block.
      // It's picked up after the first triple is processed.
      VarUtils.addVar(patternVarsScope, Var.alloc(graphNode));
    }

    for (Triple triple : pattern) {
      OpQuadPattern opQuad = getQuads(op);
      if (opQuad == null) {
        opQuad = new OpQuadPattern(graphNode, new BasicPattern());
        op = OpSequence.create(op, opQuad);
      }

      opQuad.getBasicPattern().add(triple);
      // Update variables in scope.
      VarUtils.addVarsFromTriple(patternVarsScope, triple);

      // Attempt to place any filters
      op = insertAnyFilter(exprs, patternVarsScope, op);
    }

    return op;
  }
  private static Op transformFilterBGP(
      ExprList exprs, Set<Var> patternVarsScope, BasicPattern pattern) {
    // Any filters that depend on no variables.
    Op op = insertAnyFilter(exprs, patternVarsScope, null);

    for (Triple triple : pattern) {
      OpBGP opBGP = getBGP(op);
      if (opBGP == null) {
        // Last thing was not a BGP (so it likely to be a filter)
        // Need to pass the results from that into the next triple.
        // Which is a join and sequence is a special case of join
        // which always evaluates by passing results of the early
        // part into the next element of the sequence.

        opBGP = new OpBGP();
        op = OpSequence.create(op, opBGP);
      }

      opBGP.getPattern().add(triple);
      // Update variables in scope.
      VarUtils.addVarsFromTriple(patternVarsScope, triple);

      // Attempt to place any filters
      op = insertAnyFilter(exprs, patternVarsScope, op);
    }
    // Leave any remaining filter expressions - don't wrap up any as something else may take them.
    return op;
  }