@NotNull
 private List<String> getPaths(Value<Boolean> leftValue, Value<Boolean> rightValue) {
   List<String> paths = new ArrayList<>();
   paths.addAll(leftValue.getPaths());
   paths.addAll(rightValue.getPaths());
   return paths;
 }
 public ValueList checkAndHandleNull(ValueList leftValues, ValueList rightValues) {
   ValueList result = new ValueList();
   if (leftValues.isEmpty() && rightValues.isEmpty()) {
     // this solves part of the null-valued expression problem. But certainly not all.
     result.addValue(Value.createNull(Lists.newArrayList()));
   } else if (leftValues.isEmpty()) {
     for (Value value : rightValues.getValues()) {
       result.addValue(Value.createNull(value.getPaths()));
     }
   } else if (rightValues.isEmpty()) {
     for (Value value : leftValues.getValues()) {
       result.addValue(Value.createNull(value.getPaths()));
     }
   } else {
     return null;
   }
   return result;
 }
 private ValueList evaluateBooleanConstraint(RuleEvaluation evaluation, BinaryOperator statement) {
   ValueList leftValues = evaluation.evaluate(statement.getLeftOperand());
   if (!(statement.getRightOperand() instanceof Constraint)) {
     throw new IllegalArgumentException(
         "cannot evaluate matches statement, right operand not a constraint");
   }
   Constraint constraint = (Constraint) statement.getRightOperand();
   ValueList result = new ValueList();
   result.setType(PrimitiveType.Boolean);
   for (Value value : leftValues.getValues()) {
     result.addValue(constraint.getItem().isValidValue(value.getValue()), value.getPaths());
   }
   return result;
 }