private static Expression translateLeaf(PredicateLeaf leaf) {
    TransformSpec transformSpec = TransformSpec.fromStringWithColumnName(leaf.getColumnName());
    String columnName = transformSpec.getColumnName();
    UnboundTerm<Object> column =
        ObjectUtils.defaultIfNull(toTerm(columnName, transformSpec), Expressions.ref(columnName));

    switch (leaf.getOperator()) {
      case EQUALS:
        Object literal = leafToLiteral(leaf, transformSpec);
        return NaNUtil.isNaN(literal) ? isNaN(column) : equal(column, literal);
      case LESS_THAN:
        return lessThan(column, leafToLiteral(leaf, transformSpec));
      case LESS_THAN_EQUALS:
        return lessThanOrEqual(column, leafToLiteral(leaf, transformSpec));
      case IN:
        return in(column, leafToLiteralList(leaf));
      case BETWEEN:
        List<Object> icebergLiterals = leafToLiteralList(leaf);
        if (icebergLiterals.size() == 2) {
          return and(greaterThanOrEqual(column, icebergLiterals.get(0)),
              lessThanOrEqual(column, icebergLiterals.get(1)));
        } else {
          // In case semijoin reduction optimization was applied, there will be a BETWEEN( DynamicValue, DynamicValue)
          // clause, where DynamicValue is not evaluable in Tez AM, where Hive filter is translated into Iceberg filter.
          // Overwriting to constant true as the optimization will be utilized by Hive/Tez and no-op for Iceberg.
          // (Also: the original filter and Iceberg filter are both part of JobConf on the execution side.)
          return Expressions.alwaysTrue();
        }
      case IS_NULL:
        return isNull(column);
      default:
        throw new UnsupportedOperationException("Unknown operator: " + leaf.getOperator());
    }
  }
Translate leaf nodes from Hive operator to Iceberg operator.
@param leaf Leaf node
@return Expression fully translated from Hive PredicateLeaf
iceberg/iceberg-handler/src/main/java/org/apache/iceberg/mr/hive/HiveIcebergFilterFactory.java