@Override
    public Object visit(Call call) {
      final Operator op = call.operator();
      final List<Expression> args = call.arguments();


      if (op == Operators.NOT) {
        Preconditions.checkArgument(args.size() == 1, "Size should be 1 for %s but was %s", op, args.size());
        final Object value = args.get(0).accept(this);

        if (value == UNKNOWN) {
          return UNKNOWN;
        }

        if (value instanceof Boolean) {
          return !(Boolean) value;
        }

        throw new UnsupportedOperationException(String.format("Expected boolean for op %s but got %s", op, value.getClass().getName()));
      }

      if (op == IterableOperators.IS_EMPTY || op == IterableOperators.NOT_EMPTY) {
        Preconditions.checkArgument(args.size() == 1, "Size should be 1 for %s but was %s", op, args.size());
        final Object value = args.get(0).accept(this);
        if (value == UNKNOWN) {
          return UNKNOWN;
        }

        Preconditions.checkArgument(value instanceof Iterable, "%s not iterable", value.getClass().getName());
        final boolean empty = Iterables.isEmpty((Iterable<?>) value);
        return (op == IterableOperators.IS_EMPTY) == empty;
      }

      if (op == OptionalOperators.IS_ABSENT || op == OptionalOperators.IS_PRESENT) {
        Preconditions.checkArgument(args.size() == 1, "Size should be 1 for %s but was %s", op, args.size());
        final Object left = args.get(0).accept(this);

        if (left == UNKNOWN) {
         return (op == OptionalOperators.IS_ABSENT);
        }

        return (op == OptionalOperators.IS_ABSENT) ? Objects.isNull(left) : Objects.nonNull(left);
      }

      if (op == StringOperators.TO_UPPER_CASE || op == StringOperators.TO_LOWER_CASE) {
        Preconditions.checkArgument(args.size() == 1, "Size should be 1 but was %s", args.size());
        Object value = args.get(0).accept(this);
        if (value == null || value == UNKNOWN) {
          return UNKNOWN;
        }

        Preconditions.checkArgument(value instanceof CharSequence, "Expected %s got %s", CharSequence.class.getSimpleName(), value.getClass().getName());
        return op == StringOperators.TO_UPPER_CASE ? value.toString().toUpperCase() : value.toString().toLowerCase();
      }

      if (op == Operators.AND || op == Operators.OR) {
        Preconditions.checkArgument(!args.isEmpty(), "empty args for %s", op);
        final boolean shortCircuit = op == Operators.OR;
        boolean prev = !shortCircuit;
        for (Expression exp:args) {
          final Object result = exp.accept(this);
          if (result == null || result == UNKNOWN) {
            return UNKNOWN;
          } else if (prev == shortCircuit || Objects.equals(shortCircuit, result)) {
            return shortCircuit;
          } else {
            // continue evaluating
            prev = (Boolean) result;
          }
        }

        return prev;
      }
      
      if (op == IterableOperators.ANY) {
        Preconditions.checkArgument(call.arguments().size() == 2, "Expected two arguments for %s got %s", call, call.arguments().size());
        
        final Object left = call.arguments().get(0).accept(this);
        Preconditions.checkArgument(left instanceof Iterable, "%s is not iterable", left);
        @SuppressWarnings("unchecked")
        final Iterable<Object> leftIterable = (Iterable<Object>) left;
        Preconditions.checkArgument(call.arguments().get(1) instanceof Call, "%s is not a call", call.arguments().get(1));
        final Call rightCall = (Call) call.arguments().get(1);

        final Stream<Object> stream = StreamSupport.stream(leftIterable.spliterator(), false);
        return stream.anyMatch(r -> ExpressionInterpreter.of(rightCall).asPredicate().test(r));
      }

      if (op.arity() == Operator.Arity.BINARY) {
        Preconditions.checkArgument(call.arguments().size() == 2, "Expected two arguments for %s got %s", call, call.arguments().size());
        final Object left = call.arguments().get(0).accept(this);
        if (left == UNKNOWN) {
          return UNKNOWN;
        }

        final Object right = call.arguments().get(1).accept(this);
        if (right == UNKNOWN) {
          return UNKNOWN;
        }

        return binaryCall(call, left, right);
      }

      throw new UnsupportedOperationException("Don't know how to handle " + op);
    }
Predicate to check that current expression with given parameter evaluates to {@code true}
criteria/inmemory/src/org/immutables/criteria/inmemory/ExpressionInterpreter.java