public static void main(String[] args) {
    // String sA = "Select * { ?s ?p ?o . Filter((?s || ?p) && ?o) . }";
    // String sA = "Select * { ?s ?p ?o . Filter((?s || ?p) && !(?o || ?g)) . }";

    String sA =
        "Select * { ?s ?p ?o . Filter(?o != <http://Person>). Optional { { ?x ?y ?z . Filter(?x != <http://x> && ?x = ?y) . } Union { ?x a ?y . Filter(?x = <http://x>) . } } . }";

    // String sA = "Select * { ?s ?p ?o . Filter(!(?s = ?p || ?p = ?o && ?s = ?o || ?o = ?s)) . }";
    // String sA = "Select * { ?s ?p ?o . Filter(!(?s = ?p || ?j = <http://x>)) . }";
    Query qA = QueryFactory.create(sA);

    Op opA = Algebra.compile(qA);
    opA = Algebra.toQuadForm(opA);

    System.out.println(opA);

    // How to deal with union? variables appearing in them

    // System.out.println(opA.getClass());
    ExprList exprs = FilterUtils.collectExprs(opA, new ExprList());

    ExprList proc = eval(exprs);
    System.out.println(proc);

    List<ExprList> clauses = dnfToClauses(proc);

    System.out.println("Mentioned vars:" + proc.getVarsMentioned());

    System.out.println("Clauses: " + clauses);
  }
  public static ExprList eval(ExprList exprs) {
    System.out.println("ExprList.size = " + exprs.size());

    ExprList result = new ExprList();
    for (Expr expr : exprs) {
      result.add(eval(expr));
    }

    return result;
  }
  /** Place expressions around an Op */
  private static Op buildFilter(ExprList exprs, Op op) {
    if (exprs.isEmpty()) return op;

    for (Iterator<Expr> iter = exprs.iterator(); iter.hasNext(); ) {
      Expr expr = iter.next();
      if (op == null) op = OpTable.unit();
      op = OpFilter.filter(expr, op);
      iter.remove();
    }
    return op;
  }
  /**
   * Concatenates the sub exressions using Logical_And
   *
   * <p>and(and(and(0, 1), 2, 3)
   *
   * @param exprs
   * @return
   */
  public static Expr andifyLeftSided(ExprList exprs) {
    Expr result = null;

    for (Expr expr : exprs.getList()) {
      result = (result == null) ? expr : new E_LogicalAnd(result, expr);
    }

    return result;
  }
  public static void collectAnd(Expr expr, ExprList list) {
    if (expr instanceof E_LogicalAnd) {
      E_LogicalAnd e = (E_LogicalAnd) expr;

      collectAnd(e.getArg1(), list);
      collectAnd(e.getArg2(), list);
    } else {
      list.add(expr);
    }
  }
  public static ExprList collectExprs(Op op, ExprList result) {
    if (op instanceof OpLeftJoin) {
      OpLeftJoin x = (OpLeftJoin) op;

      if (x.getExprs() != null) {
        result.addAll(x.getExprs());
      }

      collectExprs(x.getLeft(), result);
      collectExprs(x.getRight(), result);
    } else if (op instanceof OpFilter) {
      OpFilter x = (OpFilter) op;
      result.addAll(x.getExprs());
      collectExprs(x.getSubOp(), result);
    } else if (op instanceof OpJoin) {
      OpJoin x = (OpJoin) op;

      collectExprs(x.getLeft(), result);
      collectExprs(x.getRight(), result);
    } else if (op instanceof OpUnion) {
      System.out.println(
          "Warning: Collecting expressions from unions. Since the same vars may appear within different (parts of) unions, it may be ambiguous to which part the expression refers.");

      OpUnion x = (OpUnion) op;

      collectExprs(x.getLeft(), result);
      collectExprs(x.getRight(), result);
    } else if (op instanceof OpQuadPattern) {

    } else if (op instanceof OpSequence) {
      OpSequence x = (OpSequence) op;
      for (Op element : x.getElements()) {
        collectExprs(element, result);
      }
    } else {
      throw new RuntimeException("Not implemented. Type: " + op.getClass());
    }

    return result;
  }
 /** For any expression now in scope, wrap the op with a filter */
 private static Op insertAnyFilter(ExprList exprs, Set<Var> patternVarsScope, Op op) {
   for (Iterator<Expr> iter = exprs.iterator(); iter.hasNext(); ) {
     Expr expr = iter.next();
     // Cache
     Set<Var> exprVars = expr.getVarsMentioned();
     if (patternVarsScope.containsAll(exprVars)) {
       if (op == null) op = OpTable.unit();
       op = OpFilter.filter(expr, op);
       iter.remove();
     }
   }
   return op;
 }
 @Override
 public void checkBuild(String uri, ExprList args) {
   if (args.size() != 0)
     throw new QueryBuildException("Function '" + Utils.className(this) + "' takes no arguments");
 }
 public static ExprList substitute(ExprList exprList, Binding binding) {
   if (isNotNeeded(binding)) return exprList;
   return exprList.copySubstitute(binding);
 }