text: // Licensed to the Apache Software Foundation (ASF) under one
  // or more contributor license agreements.  See the NOTICE file
  // distributed with this work for additional information
  // regarding copyright ownership.  The ASF licenses this file
  // to you under the Apache License, Version 2.0 (the
  // "License"); you may not use this file except in compliance
  // with the License.  You may obtain a copy of the License at
  //
  //   http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing,
  // software distributed under the License is distributed on an
  // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  // KIND, either express or implied.  See the License for the
  // specific language governing permissions and limitations
  // under the License.
  
  #include "gandiva/tree_expr_builder.h"
  
  #include <iostream>
  #include <utility>
  
  #include "gandiva/decimal_type_util.h"
  #include "gandiva/function_registry_common.h"
  #include "gandiva/gandiva_aliases.h"
  #include "gandiva/node.h"
  
  namespace gandiva {
  
  #define MAKE_LITERAL(atype, ctype)                                            \
    NodePtr TreeExprBuilder::MakeLiteral(ctype value) {                         \
      return std::make_shared<LiteralNode>(atype, LiteralHolder(value), false); \
    }
  
  MAKE_LITERAL(arrow::boolean(), bool)
  MAKE_LITERAL(arrow::int8(), int8_t)
  MAKE_LITERAL(arrow::int16(), int16_t)
  MAKE_LITERAL(arrow::int32(), int32_t)
  MAKE_LITERAL(arrow::int64(), int64_t)
  MAKE_LITERAL(arrow::uint8(), uint8_t)
  MAKE_LITERAL(arrow::uint16(), uint16_t)
  MAKE_LITERAL(arrow::uint32(), uint32_t)
  MAKE_LITERAL(arrow::uint64(), uint64_t)
  MAKE_LITERAL(arrow::float32(), float)
  MAKE_LITERAL(arrow::float64(), double)
  
  NodePtr TreeExprBuilder::MakeStringLiteral(const std::string& value) {
    return std::make_shared<LiteralNode>(arrow::utf8(), LiteralHolder(value), false);
  }
  
  NodePtr TreeExprBuilder::MakeBinaryLiteral(const std::string& value) {
    return std::make_shared<LiteralNode>(arrow::binary(), LiteralHolder(value), false);
  }
  
  NodePtr TreeExprBuilder::MakeDecimalLiteral(const DecimalScalar128& value) {
    return std::make_shared<LiteralNode>(arrow::decimal(value.precision(), value.scale()),
                                         LiteralHolder(value), false);
  }
  
  NodePtr TreeExprBuilder::MakeNull(DataTypePtr data_type) {
    static const std::string empty;
  
    if (data_type == nullptr) {
      return nullptr;
    }
  
    switch (data_type->id()) {
      case arrow::Type::BOOL:
        return std::make_shared<LiteralNode>(data_type, LiteralHolder(false), true);
      case arrow::Type::INT8:
        return std::make_shared<LiteralNode>(data_type, LiteralHolder((int8_t)0), true);
      case arrow::Type::INT16:
        return std::make_shared<LiteralNode>(data_type, LiteralHolder((int16_t)0), true);
        return std::make_shared<LiteralNode>(data_type, LiteralHolder((int32_t)0), true);
      case arrow::Type::UINT8:
        return std::make_shared<LiteralNode>(data_type, LiteralHolder((uint8_t)0), true);
      case arrow::Type::UINT16:
        return std::make_shared<LiteralNode>(data_type, LiteralHolder((uint16_t)0), true);
      case arrow::Type::UINT32:
        return std::make_shared<LiteralNode>(data_type, LiteralHolder((uint32_t)0), true);
      case arrow::Type::UINT64:
        return std::make_shared<LiteralNode>(data_type, LiteralHolder((uint64_t)0), true);
      case arrow::Type::FLOAT:
        return std::make_shared<LiteralNode>(data_type,
                                             LiteralHolder(static_cast<float>(0)), true);
      case arrow::Type::DOUBLE:
        return std::make_shared<LiteralNode>(data_type,
                                             LiteralHolder(static_cast<double>(0)), true);
      case arrow::Type::STRING:
      case arrow::Type::BINARY:
        return std::make_shared<LiteralNode>(data_type, LiteralHolder(empty), true);
      case arrow::Type::INT32:
      case arrow::Type::DATE32:
      case arrow::Type::TIME32:
      case arrow::Type::INTERVAL_MONTHS:
        return std::make_shared<LiteralNode>(data_type, LiteralHolder((int32_t)0), true);
      case arrow::Type::INT64:
      case arrow::Type::DATE64:
      case arrow::Type::TIME64:
      case arrow::Type::TIMESTAMP:
      case arrow::Type::INTERVAL_DAY_TIME:
        return std::make_shared<LiteralNode>(data_type, LiteralHolder((int64_t)0), true);
      case arrow::Type::DECIMAL: {
        std::shared_ptr<arrow::DecimalType> decimal_type =
            arrow::internal::checked_pointer_cast<arrow::DecimalType>(data_type);
        DecimalScalar128 literal(decimal_type->precision(), decimal_type->scale());
        return std::make_shared<LiteralNode>(data_type, LiteralHolder(literal), true);
      }
      default:
        return nullptr;
    }
  }
  
  NodePtr TreeExprBuilder::MakeField(FieldPtr field) {
    return NodePtr(new FieldNode(field));
  }
  
  NodePtr TreeExprBuilder::MakeFunction(const std::string& name, const NodeVector& params,
                                        DataTypePtr result_type) {
    if (result_type == nullptr) {
      return nullptr;
    }
    return std::make_shared<FunctionNode>(name, params, result_type);
  }
  
  NodePtr TreeExprBuilder::MakeIf(NodePtr condition, NodePtr then_node, NodePtr else_node,
                                  DataTypePtr result_type) {
    if (condition == nullptr || then_node == nullptr || else_node == nullptr ||
        result_type == nullptr) {
      return nullptr;
    }
    return std::make_shared<IfNode>(condition, then_node, else_node, result_type);
  }
  
  NodePtr TreeExprBuilder::MakeAnd(const NodeVector& children) {
    return std::make_shared<BooleanNode>(BooleanNode::AND, children);
  }
  
  NodePtr TreeExprBuilder::MakeOr(const NodeVector& children) {
    return std::make_shared<BooleanNode>(BooleanNode::OR, children);
  }
  
  // set this to true to print expressions for debugging purposes
  static bool print_expr = false;
  
  ExpressionPtr TreeExprBuilder::MakeExpression(NodePtr root_node, FieldPtr result_field) {
    if (result_field == nullptr) {
      return nullptr;
    }
    if (print_expr) {
      std::cout << "Expression: " << root_node->ToString() << "\n";
    }
    return ExpressionPtr(new Expression(root_node, result_field));
  }
  
  ExpressionPtr TreeExprBuilder::MakeExpression(const std::string& function,
                                                const FieldVector& in_fields,
                                                FieldPtr out_field) {
    if (out_field == nullptr) {
      return nullptr;
    }
    std::vector<NodePtr> field_nodes;
    for (auto& field : in_fields) {
      auto node = MakeField(field);
      field_nodes.push_back(node);
    }
    auto func_node = MakeFunction(function, field_nodes, out_field->type());
    return MakeExpression(func_node, out_field);
  }
  
  ConditionPtr TreeExprBuilder::MakeCondition(NodePtr root_node) {
    if (root_node == nullptr) {
      return nullptr;
    }
    if (print_expr) {
      std::cout << "Condition: " << root_node->ToString() << "\n";
    }
  
    return ConditionPtr(new Condition(root_node));
  }
  
  ConditionPtr TreeExprBuilder::MakeCondition(const std::string& function,
                                              const FieldVector& in_fields) {
    std::vector<NodePtr> field_nodes;
    for (auto& field : in_fields) {
      auto node = MakeField(field);
      field_nodes.push_back(node);
    }
  
    auto func_node = MakeFunction(function, field_nodes, arrow::boolean());
    return ConditionPtr(new Condition(func_node));
  }
  
  NodePtr TreeExprBuilder::MakeInExpressionDecimal(
      NodePtr node, std::unordered_set<gandiva::DecimalScalar128>& constants) {
    int32_t precision = 0;
    int32_t scale = 0;
    if (!constants.empty()) {
      precision = constants.begin()->precision();
      scale = constants.begin()->scale();
    }
    return std::make_shared<InExpressionNode<gandiva::DecimalScalar128>>(node, constants,
                                                                         precision, scale);
  }
  
  #define MAKE_IN(NAME, ctype, type)                                        \
    NodePtr TreeExprBuilder::MakeInExpression##NAME(                        \
        NodePtr node, const std::unordered_set<ctype>& values) {            \
      return std::make_shared<InExpressionNode<ctype>>(node, values, type); \
    }
  
  MAKE_IN(Int32, int32_t, int32());
  MAKE_IN(Int64, int64_t, int64());
  MAKE_IN(Date32, int32_t, date32());
  MAKE_IN(Date64, int64_t, date64());
  MAKE_IN(TimeStamp, int64_t, timestamp());
  MAKE_IN(Time32, int32_t, time32());
  MAKE_IN(Time64, int64_t, time64());
  MAKE_IN(Float, float, float32());
  MAKE_IN(Double, double, float64());
  MAKE_IN(String, std::string, utf8());
  MAKE_IN(Binary, std::string, binary());
  
  }  // namespace gandiva
  