private LanguageNode handleInFunction(FunctionCall fc) {
   ExpressionNode lhs = fc.getParameters().get(0);
   if (EngineConstant.COLUMN.has(lhs) && parent.isQualifyingColumn((ColumnInstance) lhs)) {
     // only matches if all the rhs are constant
     for (ExpressionNode en : fc.getParameters(1)) {
       if (!EngineConstant.CONSTANT.has(en)) return fc;
     }
     ColumnInstance ci = (ColumnInstance) lhs;
     if (!parent.isQualifyingColumn(ci.getPEColumn())) return fc;
     ArrayList<ExpressionNode> subexprs = new ArrayList<ExpressionNode>();
     ArrayList<Part> parts = new ArrayList<Part>();
     for (ExpressionNode en : fc.getParameters(1)) {
       ColumnInstance tci = (ColumnInstance) ci.copy(null);
       ConstantExpression litex = (ConstantExpression) en;
       ExpressionNode subeq = new FunctionCall(FunctionName.makeEquals(), tci, litex);
       Part p = buildPart(subeq, tci, litex);
       parts.add(p);
       subexprs.add((ExpressionNode) p.getParent());
     }
     if (subexprs.size() > 1) {
       FunctionCall orcall = new FunctionCall(FunctionName.makeOr(), subexprs);
       OredParts pc = parent.buildOredParts(orcall, parts);
       if (pc.isComplete()) setComplete(pc);
       orcall.setGrouped();
       state.put(orcall, pc);
       return orcall;
     } else {
       Part p = parts.get(0);
       return p.getParent();
     }
   }
   return fc;
 }
    private LanguageNode handleOrFunction(FunctionCall fc) {
      ArrayList<Part> subparts = new ArrayList<Part>();
      for (ExpressionNode en : fc.getParameters()) {
        Part p = state.get(en);
        if (p == null) {
          broadening();
          return fc;
        }
        subparts.add(p);
      }
      // now to figure out what we have.  we may have a a bunch of incomplete subexprs,
      // in which case we took a = 1 or a = 2 or a = 3 => a part collection of incompletes
      // or we may have (a = 1 and b = 2) or (a =3 and b =4) ... - likewise
      // or they maybe complete.  regardless, just build a partcollection and move on.
      // sort subparts by table key; if there's more than one let's just set broadening for now
      TableKey tk = null;
      for (Part p : subparts) {
        if (tk == null) tk = p.getTableKey();
        else if (!tk.equals(p.getTableKey())) {
          broadening();
          return fc;
        }
      }
      OredParts op = parent.buildOredParts(fc, subparts);
      if (op.isComplete()) setComplete(op);

      state.put(fc, op);
      return fc;
    }
 private Part buildNewMultiMultiPart(OredParts lp, OredParts rp) {
   ArrayList<Part> newParts = new ArrayList<Part>();
   for (Part lpc : lp.getParts()) {
     for (Part rpc : rp.getParts()) {
       newParts.add(combineParts(lpc.copy(), rpc.copy()));
     }
   }
   FunctionCall orcall =
       new FunctionCall(
           FunctionName.makeOr(), Functional.apply(newParts, Part.castToExpression));
   OredParts op = parent.buildOredParts(orcall, newParts);
   if (op.isComplete()) setComplete(op);
   return op;
 }
 private Part buildNewPartCollection(OredParts lp, Part rp) {
   // rp could be simple or complex, lp has either simple or complex elements.
   // the strategy here is to build a new complex part for each item in the collection, and
   // return a new collection.
   ArrayList<Part> newParts = new ArrayList<Part>();
   for (Part sp : lp.getParts()) {
     newParts.add(buildNewComplexPart(sp, rp.copy()));
   }
   FunctionCall orcall =
       new FunctionCall(
           FunctionName.makeOr(), Functional.apply(newParts, Part.castToExpression));
   OredParts op = parent.buildOredParts(orcall, newParts);
   if (op.isComplete()) setComplete(op);
   return op;
 }