Skip to content
Snippets Groups Projects
Commit 0d62634e authored by Stéphane Del Pino's avatar Stéphane Del Pino
Browse files

Change binary operators expression builders

parent 0756812b
No related branches found
No related tags found
1 merge request!70Feature/language reduce static
Showing
with 670 additions and 280 deletions
...@@ -3,205 +3,59 @@ ...@@ -3,205 +3,59 @@
#include <language/PEGGrammar.hpp> #include <language/PEGGrammar.hpp>
#include <language/node_processor/BinaryExpressionProcessor.hpp> #include <language/node_processor/BinaryExpressionProcessor.hpp>
#include <language/node_processor/ConcatExpressionProcessor.hpp> #include <language/node_processor/ConcatExpressionProcessor.hpp>
#include <language/utils/BinaryOperatorMangler.hpp>
#include <language/utils/OperatorRepository.hpp>
#include <language/utils/ParseError.hpp> #include <language/utils/ParseError.hpp>
ASTNodeBinaryOperatorExpressionBuilder::ASTNodeBinaryOperatorExpressionBuilder(ASTNode& n) ASTNodeBinaryOperatorExpressionBuilder::ASTNodeBinaryOperatorExpressionBuilder(ASTNode& n)
{ {
auto set_binary_operator_processor = [](ASTNode& n, const auto& operator_v) { const ASTNodeDataType& lhs_data_type = n.children[0]->m_data_type;
auto set_binary_operator_processor_for_data_b = [&](const auto data_a, const ASTNodeDataType& data_type_b) { const ASTNodeDataType& rhs_data_type = n.children[1]->m_data_type;
using OperatorT = std::decay_t<decltype(operator_v)>;
using DataTA = std::decay_t<decltype(data_a)>;
if constexpr (std::is_same_v<DataTA, std::string>) {
if constexpr (std::is_same_v<OperatorT, language::plus_op>) {
switch (data_type_b) {
case ASTNodeDataType::bool_t: {
n.m_node_processor = std::make_unique<ConcatExpressionProcessor<bool>>(n);
break;
}
case ASTNodeDataType::unsigned_int_t: {
n.m_node_processor = std::make_unique<ConcatExpressionProcessor<uint64_t>>(n);
break;
}
case ASTNodeDataType::int_t: {
n.m_node_processor = std::make_unique<ConcatExpressionProcessor<int64_t>>(n);
break;
}
case ASTNodeDataType::double_t: {
n.m_node_processor = std::make_unique<ConcatExpressionProcessor<double>>(n);
break;
}
case ASTNodeDataType::string_t: {
n.m_node_processor = std::make_unique<ConcatExpressionProcessor<std::string>>(n);
break;
}
default: {
throw ParseError("undefined operand type for binary operator", std::vector{n.children[1]->begin()});
}
}
} else if constexpr ((std::is_same_v<OperatorT, language::eqeq_op>) or
(std::is_same_v<OperatorT, language::not_eq_op>)) {
if (data_type_b == ASTNodeDataType::string_t) {
n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, DataTA, std::string>>(n);
} else {
throw ParseError("undefined operand type for binary operator", std::vector{n.begin()});
}
} else {
throw ParseError("undefined operand type for binary operator", std::vector{n.begin()});
}
} else if constexpr (std::is_same_v<DataTA, TinyVector<1>> or std::is_same_v<DataTA, TinyVector<2>> or
std::is_same_v<DataTA, TinyVector<3>>) {
if ((data_type_b == ASTNodeDataType::vector_t)) {
if constexpr (std::is_same_v<OperatorT, language::plus_op> or std::is_same_v<OperatorT, language::minus_op> or
std::is_same_v<OperatorT, language::eqeq_op> or
std::is_same_v<OperatorT, language::not_eq_op>) {
if (data_a.dimension() == data_type_b.dimension()) {
n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, DataTA, DataTA>>(n);
} else {
throw ParseError("incompatible dimensions of operands", std::vector{n.begin()});
}
} else {
throw ParseError("invalid binary operator", std::vector{n.begin()});
}
} else {
// LCOV_EXCL_START
throw ParseError("unexpected error: invalid operand type for binary operator",
std::vector{n.children[1]->begin()});
// LCOV_EXCL_STOP
}
} else {
switch (data_type_b) {
case ASTNodeDataType::bool_t: {
n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, DataTA, bool>>(n);
break;
}
case ASTNodeDataType::unsigned_int_t: {
n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, DataTA, uint64_t>>(n);
break;
}
case ASTNodeDataType::int_t: {
n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, DataTA, int64_t>>(n);
break;
}
case ASTNodeDataType::double_t: {
n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, DataTA, double>>(n);
break;
}
case ASTNodeDataType::vector_t: {
if constexpr (std::is_same_v<OperatorT, language::multiply_op>) {
switch (data_type_b.dimension()) {
case 1: {
n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, DataTA, TinyVector<1>>>(n);
break;
}
case 2: {
n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, DataTA, TinyVector<2>>>(n);
break;
}
case 3: {
n.m_node_processor = std::make_unique<BinaryExpressionProcessor<OperatorT, DataTA, TinyVector<3>>>(n);
break;
}
// LCOV_EXCL_START
default: {
throw ParseError("unexpected error: invalid dimension", std::vector{n.children[0]->begin()});
}
// LCOV_EXCL_STOP
}
break;
}
}
default: {
throw ParseError("undefined operand type for binary operator", std::vector{n.children[1]->begin()});
}
}
}
};
auto set_binary_operator_processor_for_data_a = [&](const ASTNodeDataType& data_type_a) {
const ASTNodeDataType data_type_b = n.children[1]->m_data_type;
switch (data_type_a) {
case ASTNodeDataType::bool_t: {
set_binary_operator_processor_for_data_b(bool{}, data_type_b);
break;
}
case ASTNodeDataType::unsigned_int_t: {
set_binary_operator_processor_for_data_b(uint64_t{}, data_type_b);
break;
}
case ASTNodeDataType::int_t: {
set_binary_operator_processor_for_data_b(int64_t{}, data_type_b);
break;
}
case ASTNodeDataType::double_t: {
set_binary_operator_processor_for_data_b(double{}, data_type_b);
break;
}
case ASTNodeDataType::string_t: {
set_binary_operator_processor_for_data_b(std::string{}, data_type_b);
break;
}
case ASTNodeDataType::vector_t: {
switch (data_type_a.dimension()) {
case 1: {
set_binary_operator_processor_for_data_b(TinyVector<1>{}, data_type_b);
break;
}
case 2: {
set_binary_operator_processor_for_data_b(TinyVector<2>{}, data_type_b);
break;
}
case 3: {
set_binary_operator_processor_for_data_b(TinyVector<3>{}, data_type_b);
break;
}
// LCOV_EXCL_START
default: {
throw ParseError("unexpected error: invalid dimension", std::vector{n.children[0]->begin()});
}
// LCOV_EXCL_STOP
}
break;
}
default: {
throw ParseError("undefined operand type for binary operator", std::vector{n.children[0]->begin()});
}
}
};
set_binary_operator_processor_for_data_a(n.children[0]->m_data_type);
};
const std::string binary_operator_name = [&]() -> std::string {
if (n.is_type<language::multiply_op>()) { if (n.is_type<language::multiply_op>()) {
set_binary_operator_processor(n, language::multiply_op{}); return binaryOperatorMangler<language::multiply_op>(lhs_data_type, rhs_data_type);
} else if (n.is_type<language::divide_op>()) { } else if (n.is_type<language::divide_op>()) {
set_binary_operator_processor(n, language::divide_op{}); return binaryOperatorMangler<language::divide_op>(lhs_data_type, rhs_data_type);
} else if (n.is_type<language::plus_op>()) { } else if (n.is_type<language::plus_op>()) {
set_binary_operator_processor(n, language::plus_op{}); return binaryOperatorMangler<language::plus_op>(lhs_data_type, rhs_data_type);
} else if (n.is_type<language::minus_op>()) { } else if (n.is_type<language::minus_op>()) {
set_binary_operator_processor(n, language::minus_op{}); return binaryOperatorMangler<language::minus_op>(lhs_data_type, rhs_data_type);
} else if (n.is_type<language::or_op>()) { } else if (n.is_type<language::or_op>()) {
set_binary_operator_processor(n, language::or_op{}); return binaryOperatorMangler<language::or_op>(lhs_data_type, rhs_data_type);
} else if (n.is_type<language::and_op>()) { } else if (n.is_type<language::and_op>()) {
set_binary_operator_processor(n, language::and_op{}); return binaryOperatorMangler<language::and_op>(lhs_data_type, rhs_data_type);
} else if (n.is_type<language::xor_op>()) { } else if (n.is_type<language::xor_op>()) {
set_binary_operator_processor(n, language::xor_op{}); return binaryOperatorMangler<language::xor_op>(lhs_data_type, rhs_data_type);
} else if (n.is_type<language::greater_op>()) { } else if (n.is_type<language::greater_op>()) {
set_binary_operator_processor(n, language::greater_op{}); return binaryOperatorMangler<language::greater_op>(lhs_data_type, rhs_data_type);
} else if (n.is_type<language::greater_or_eq_op>()) { } else if (n.is_type<language::greater_or_eq_op>()) {
set_binary_operator_processor(n, language::greater_or_eq_op{}); return binaryOperatorMangler<language::greater_or_eq_op>(lhs_data_type, rhs_data_type);
} else if (n.is_type<language::lesser_op>()) { } else if (n.is_type<language::lesser_op>()) {
set_binary_operator_processor(n, language::lesser_op{}); return binaryOperatorMangler<language::lesser_op>(lhs_data_type, rhs_data_type);
} else if (n.is_type<language::lesser_or_eq_op>()) { } else if (n.is_type<language::lesser_or_eq_op>()) {
set_binary_operator_processor(n, language::lesser_or_eq_op{}); return binaryOperatorMangler<language::lesser_or_eq_op>(lhs_data_type, rhs_data_type);
} else if (n.is_type<language::eqeq_op>()) { } else if (n.is_type<language::eqeq_op>()) {
set_binary_operator_processor(n, language::eqeq_op{}); return binaryOperatorMangler<language::eqeq_op>(lhs_data_type, rhs_data_type);
} else if (n.is_type<language::not_eq_op>()) { } else if (n.is_type<language::not_eq_op>()) {
set_binary_operator_processor(n, language::not_eq_op{}); return binaryOperatorMangler<language::not_eq_op>(lhs_data_type, rhs_data_type);
} else { } else {
throw ParseError("unexpected error: undefined binary operator", std::vector{n.begin()}); throw ParseError("unexpected error: undefined binary operator", std::vector{n.begin()});
} }
}();
const auto& optional_processor_builder =
OperatorRepository::instance().getBinaryProcessorBuilder(binary_operator_name);
if (optional_processor_builder.has_value()) {
n.m_node_processor = optional_processor_builder.value()->getNodeProcessor(n);
} else {
std::ostringstream error_message;
error_message << "undefined binary operator type: ";
error_message << rang::fgB::red << binary_operator_name << rang::fg::reset;
throw ParseError(error_message.str(), std::vector{n.children[0]->begin()});
}
} }
...@@ -352,40 +352,22 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const ...@@ -352,40 +352,22 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
const ASTNode& test_node = *n.children[1]; const ASTNode& test_node = *n.children[1];
ASTNodeNaturalConversionChecker{test_node, ASTNodeDataType::build<ASTNodeDataType::bool_t>()}; ASTNodeNaturalConversionChecker{test_node, ASTNodeDataType::build<ASTNodeDataType::bool_t>()};
} else if (n.is_type<language::unary_not>()) { } else if (n.is_type<language::unary_not>() or n.is_type<language::unary_minus>()) {
auto& operator_repository = OperatorRepository::instance(); auto& operator_repository = OperatorRepository::instance();
auto optional_value_type = operator_repository.getUnaryOperatorValueType( auto optional_value_type = [&] {
if (n.is_type<language::unary_not>()) {
return operator_repository.getUnaryOperatorValueType(
unaryOperatorMangler<language::unary_not>(n.children[0]->m_data_type)); unaryOperatorMangler<language::unary_not>(n.children[0]->m_data_type));
if (optional_value_type.has_value()) {
n.m_data_type = optional_value_type.value();
} else {
std::ostringstream message;
message << "undefined unary operator\n"
<< "note: unexpected operand type " << rang::fgB::red << dataTypeName(n.children[0]->m_data_type)
<< rang::style::reset;
throw ParseError(message.str(), n.begin());
}
} else if (n.is_type<language::lesser_op>() or n.is_type<language::lesser_or_eq_op>() or
n.is_type<language::greater_op>() or n.is_type<language::greater_or_eq_op>() or
n.is_type<language::eqeq_op>() or n.is_type<language::not_eq_op>()) {
n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::bool_t>();
} else if (n.is_type<language::and_op>() or n.is_type<language::or_op>() or n.is_type<language::xor_op>()) {
n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::bool_t>();
const ASTNode& lhs_node = *n.children[0];
ASTNodeNaturalConversionChecker{lhs_node, ASTNodeDataType::build<ASTNodeDataType::bool_t>()};
const ASTNode& rhs_node = *n.children[1];
ASTNodeNaturalConversionChecker{rhs_node, ASTNodeDataType::build<ASTNodeDataType::bool_t>()};
} else if (n.is_type<language::unary_minus>()) { } else if (n.is_type<language::unary_minus>()) {
auto& operator_repository = OperatorRepository::instance(); return operator_repository.getUnaryOperatorValueType(
auto optional_value_type = operator_repository.getUnaryOperatorValueType(
unaryOperatorMangler<language::unary_minus>(n.children[0]->m_data_type)); unaryOperatorMangler<language::unary_minus>(n.children[0]->m_data_type));
} else {
// LCOV_EXCL_START
throw UnexpectedError("invalid unary operator type");
// LCOV_EXCL_STOP
}
}();
if (optional_value_type.has_value()) { if (optional_value_type.has_value()) {
n.m_data_type = optional_value_type.value(); n.m_data_type = optional_value_type.value();
...@@ -396,6 +378,7 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const ...@@ -396,6 +378,7 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
<< rang::style::reset; << rang::style::reset;
throw ParseError(message.str(), n.begin()); throw ParseError(message.str(), n.begin());
} }
} else if (n.is_type<language::unary_plusplus>() or n.is_type<language::unary_minusminus>() or } else if (n.is_type<language::unary_plusplus>() or n.is_type<language::unary_minusminus>() or
n.is_type<language::post_plusplus>() or n.is_type<language::post_minusminus>()) { n.is_type<language::post_plusplus>() or n.is_type<language::post_minusminus>()) {
auto& operator_repository = OperatorRepository::instance(); auto& operator_repository = OperatorRepository::instance();
...@@ -424,28 +407,80 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const ...@@ -424,28 +407,80 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
n.m_data_type = optional_value_type.value(); n.m_data_type = optional_value_type.value();
} else { } else {
std::ostringstream message; std::ostringstream message;
message << "undefined unary operator\n" message << "undefined increment/decrement operator\n"
<< "note: unexpected operand type " << rang::fgB::red << dataTypeName(n.children[0]->m_data_type) << "note: unexpected operand type " << rang::fgB::red << dataTypeName(n.children[0]->m_data_type)
<< rang::style::reset; << rang::style::reset;
throw ParseError(message.str(), n.begin()); throw ParseError(message.str(), n.begin());
} }
n.m_data_type = n.children[0]->m_data_type;
} else if (n.is_type<language::plus_op>() or n.is_type<language::minus_op>() or } else if (n.is_type<language::plus_op>() or n.is_type<language::minus_op>() or
n.is_type<language::multiply_op>() or n.is_type<language::divide_op>()) { n.is_type<language::multiply_op>() or n.is_type<language::divide_op>() or
n.is_type<language::lesser_op>() or n.is_type<language::lesser_or_eq_op>() or
n.is_type<language::greater_op>() or n.is_type<language::greater_or_eq_op>() or
n.is_type<language::eqeq_op>() or n.is_type<language::not_eq_op>() or n.is_type<language::and_op>() or
n.is_type<language::or_op>() or n.is_type<language::xor_op>()) {
const ASTNodeDataType type_0 = n.children[0]->m_data_type; const ASTNodeDataType type_0 = n.children[0]->m_data_type;
const ASTNodeDataType type_1 = n.children[1]->m_data_type; const ASTNodeDataType type_1 = n.children[1]->m_data_type;
if ((type_0 == ASTNodeDataType::bool_t) and (type_1 == ASTNodeDataType::bool_t)) { auto& operator_repository = OperatorRepository::instance();
n.m_data_type = ASTNodeDataType::build<ASTNodeDataType::int_t>();
auto optional_value_type = [&] {
if (n.is_type<language::plus_op>()) {
return operator_repository.getBinaryOperatorValueType(
binaryOperatorMangler<language::plus_op>(type_0, type_1));
} else if (n.is_type<language::minus_op>()) {
return operator_repository.getBinaryOperatorValueType(
binaryOperatorMangler<language::minus_op>(type_0, type_1));
} else if (n.is_type<language::multiply_op>()) {
return operator_repository.getBinaryOperatorValueType(
binaryOperatorMangler<language::multiply_op>(type_0, type_1));
} else if (n.is_type<language::divide_op>()) {
return operator_repository.getBinaryOperatorValueType(
binaryOperatorMangler<language::divide_op>(type_0, type_1));
} else if (n.is_type<language::lesser_op>()) {
return operator_repository.getBinaryOperatorValueType(
binaryOperatorMangler<language::lesser_op>(type_0, type_1));
} else if (n.is_type<language::lesser_or_eq_op>()) {
return operator_repository.getBinaryOperatorValueType(
binaryOperatorMangler<language::lesser_or_eq_op>(type_0, type_1));
} else if (n.is_type<language::greater_op>()) {
return operator_repository.getBinaryOperatorValueType(
binaryOperatorMangler<language::greater_op>(type_0, type_1));
} else if (n.is_type<language::greater_or_eq_op>()) {
return operator_repository.getBinaryOperatorValueType(
binaryOperatorMangler<language::greater_or_eq_op>(type_0, type_1));
} else if (n.is_type<language::eqeq_op>()) {
return operator_repository.getBinaryOperatorValueType(
binaryOperatorMangler<language::eqeq_op>(type_0, type_1));
} else if (n.is_type<language::not_eq_op>()) {
return operator_repository.getBinaryOperatorValueType(
binaryOperatorMangler<language::not_eq_op>(type_0, type_1));
} else if (n.is_type<language::and_op>()) {
return operator_repository.getBinaryOperatorValueType(
binaryOperatorMangler<language::and_op>(type_0, type_1));
} else if (n.is_type<language::or_op>()) {
return operator_repository.getBinaryOperatorValueType(binaryOperatorMangler<language::or_op>(type_0, type_1));
} else if (n.is_type<language::xor_op>()) {
return operator_repository.getBinaryOperatorValueType(
binaryOperatorMangler<language::xor_op>(type_0, type_1));
} else { } else {
n.m_data_type = dataTypePromotion(type_0, type_1); // LCOV_EXCL_START
throw UnexpectedError("unexpected operator type");
// LCOV_EXCL_STOP
} }
if (n.m_data_type == ASTNodeDataType::undefined_t) { }();
if (optional_value_type.has_value()) {
n.m_data_type = optional_value_type.value();
} else {
std::ostringstream message; std::ostringstream message;
message << "undefined binary operator\n" message << "undefined binary operator\n"
<< "note: incompatible operand types " << dataTypeName(type_0) << " and " << dataTypeName(type_1); << "note: incompatible operand types " << dataTypeName(type_0) << " and " << dataTypeName(type_1);
throw ParseError(message.str(), n.begin()); throw ParseError(message.str(), n.begin());
} }
} else if (n.is_type<language::function_evaluation>()) { } else if (n.is_type<language::function_evaluation>()) {
if (n.children[0]->m_data_type == ASTNodeDataType::function_t) { if (n.children[0]->m_data_type == ASTNodeDataType::function_t) {
const std::string& function_name = n.children[0]->string(); const std::string& function_name = n.children[0]->string();
......
...@@ -26,7 +26,9 @@ ASTNodeIncDecExpressionBuilder::ASTNodeIncDecExpressionBuilder(ASTNode& n) ...@@ -26,7 +26,9 @@ ASTNodeIncDecExpressionBuilder::ASTNodeIncDecExpressionBuilder(ASTNode& n)
} else if (n.is_type<language::post_plusplus>()) { } else if (n.is_type<language::post_plusplus>()) {
return incDecOperatorMangler<language::post_plusplus>(data_type); return incDecOperatorMangler<language::post_plusplus>(data_type);
} else { } else {
// LCOV_EXCL_START
throw ParseError("unexpected error: undefined inc/dec operator", std::vector{n.begin()}); throw ParseError("unexpected error: undefined inc/dec operator", std::vector{n.begin()});
// LCOV_EXCL_STOP
} }
}(); }();
......
...@@ -15,7 +15,9 @@ ASTNodeUnaryOperatorExpressionBuilder::ASTNodeUnaryOperatorExpressionBuilder(AST ...@@ -15,7 +15,9 @@ ASTNodeUnaryOperatorExpressionBuilder::ASTNodeUnaryOperatorExpressionBuilder(AST
} else if (n.is_type<language::unary_not>()) { } else if (n.is_type<language::unary_not>()) {
return unaryOperatorMangler<language::unary_not>(data_type); return unaryOperatorMangler<language::unary_not>(data_type);
} else { } else {
// LCOV_EXCL_START
throw ParseError("unexpected error: undefined unary operator", std::vector{n.begin()}); throw ParseError("unexpected error: undefined unary operator", std::vector{n.begin()});
// LCOV_EXCL_STOP
} }
}(); }();
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
#include <language/node_processor/INodeProcessor.hpp> #include <language/node_processor/INodeProcessor.hpp>
#include <language/utils/ParseError.hpp> #include <language/utils/ParseError.hpp>
#include <type_traits>
template <typename Op> template <typename Op>
struct BinOp; struct BinOp;
...@@ -154,68 +156,49 @@ struct BinOp<language::divide_op> ...@@ -154,68 +156,49 @@ struct BinOp<language::divide_op>
} }
}; };
template <typename BinaryOpT, typename A_DataT, typename B_DataT> template <typename BinaryOpT, typename ValueT, typename A_DataT, typename B_DataT>
class BinaryExpressionProcessor final : public INodeProcessor struct BinaryExpressionProcessor final : public INodeProcessor
{ {
private:
ASTNode& m_node; ASTNode& m_node;
PUGS_INLINE DataVariant PUGS_INLINE DataVariant
_eval(const DataVariant& a, const DataVariant& b) _eval(const DataVariant& a, const DataVariant& b)
{ {
// Add 'signed' when necessary to avoid signed/unsigned comparison warnings if constexpr (std::is_arithmetic_v<A_DataT> and std::is_arithmetic_v<B_DataT>) {
if constexpr ((not(std::is_same_v<A_DataT, bool> or std::is_same_v<B_DataT, bool>)) and if constexpr (std::is_signed_v<A_DataT> and not std::is_signed_v<B_DataT>) {
(std::is_same_v<BinaryOpT, language::and_op> or std::is_same_v<BinaryOpT, language::or_op> or if constexpr (std::is_same_v<B_DataT, bool>) {
std::is_same_v<BinaryOpT, language::xor_op> or std::is_same_v<BinaryOpT, language::eqeq_op> or return static_cast<ValueT>(
std::is_same_v<BinaryOpT, language::not_eq_op> or std::is_same_v<BinaryOpT, language::lesser_op> or BinOp<BinaryOpT>().eval(std::get<A_DataT>(a), static_cast<int64_t>(std::get<B_DataT>(b))));
std::is_same_v<BinaryOpT, language::lesser_or_eq_op> or
std::is_same_v<BinaryOpT, language::greater_op> or
std::is_same_v<BinaryOpT, language::greater_or_eq_op>) and
(std::is_signed_v<A_DataT> xor std::is_signed_v<B_DataT>)) {
if constexpr (std::is_unsigned_v<A_DataT>) {
using signed_A_DataT = std::make_signed_t<A_DataT>;
const signed_A_DataT signed_a = static_cast<signed_A_DataT>(std::get<A_DataT>(a));
return BinOp<BinaryOpT>().eval(signed_a, std::get<B_DataT>(b));
} else { } else {
using signed_B_DataT = std::make_signed_t<B_DataT>; return static_cast<ValueT>(
const signed_B_DataT signed_b = static_cast<signed_B_DataT>(std::get<B_DataT>(b)); BinOp<BinaryOpT>().eval(std::get<A_DataT>(a), std::make_signed_t<B_DataT>(std::get<B_DataT>(b))));
return BinOp<BinaryOpT>().eval(std::get<A_DataT>(a), signed_b);
} }
} else if constexpr (not std::is_signed_v<A_DataT> and std::is_signed_v<B_DataT>) {
if constexpr (std::is_same_v<A_DataT, bool>) {
return static_cast<ValueT>(
BinOp<BinaryOpT>().eval(static_cast<int64_t>(std::get<A_DataT>(a)), std::get<B_DataT>(b)));
} else { } else {
auto result = BinOp<BinaryOpT>().eval(std::get<A_DataT>(a), std::get<B_DataT>(b)); return static_cast<ValueT>(
if constexpr (std::is_same_v<decltype(result), int>) { BinOp<BinaryOpT>().eval(std::make_signed_t<A_DataT>(std::get<A_DataT>(a)), std::get<B_DataT>(b)));
return static_cast<int64_t>(result);
} else {
return result;
} }
} else {
return static_cast<ValueT>(BinOp<BinaryOpT>().eval(std::get<A_DataT>(a), std::get<B_DataT>(b)));
} }
} else {
return static_cast<ValueT>(BinOp<BinaryOpT>().eval(std::get<A_DataT>(a), std::get<B_DataT>(b)));
} }
static inline const bool m_is_defined{[] {
if constexpr (std::is_same_v<BinaryOpT, language::xor_op>) {
return std::is_same_v<std::decay_t<A_DataT>, std::decay_t<B_DataT>> and std::is_integral_v<std::decay_t<A_DataT>>;
} }
return true;
}()};
public: public:
DataVariant DataVariant
execute(ExecutionPolicy& exec_policy) execute(ExecutionPolicy& exec_policy)
{ {
if constexpr (m_is_defined) {
return this->_eval(m_node.children[0]->execute(exec_policy), m_node.children[1]->execute(exec_policy)); return this->_eval(m_node.children[0]->execute(exec_policy), m_node.children[1]->execute(exec_policy));
} else {
return {}; // LCOV_EXCL_LINE
}
} }
BinaryExpressionProcessor(ASTNode& node) : m_node{node} BinaryExpressionProcessor(ASTNode& node) : m_node{node} {}
{
if constexpr (not m_is_defined) {
// LCOV_EXCL_START
throw ParseError("invalid operands to binary expression", std::vector{m_node.begin()});
// LCOV_EXCL_STOP
}
}
}; };
#endif // BINARY_EXPRESSION_PROCESSOR_HPP #endif // BINARY_EXPRESSION_PROCESSOR_HPP
...@@ -16,8 +16,12 @@ class ConcatExpressionProcessor final : public INodeProcessor ...@@ -16,8 +16,12 @@ class ConcatExpressionProcessor final : public INodeProcessor
{ {
if constexpr (std::is_same_v<B_DataT, std::string>) { if constexpr (std::is_same_v<B_DataT, std::string>) {
return a + std::get<B_DataT>(b); return a + std::get<B_DataT>(b);
} else { } else if constexpr (std::is_arithmetic_v<B_DataT>) {
return a + std::to_string(std::get<B_DataT>(b)); return a + std::to_string(std::get<B_DataT>(b));
} else {
std::ostringstream os;
os << a << b;
return os.str();
} }
} }
......
...@@ -8,8 +8,9 @@ ...@@ -8,8 +8,9 @@
#include <string> #include <string>
#include <typeinfo> #include <typeinfo>
struct INodeProcessor class INodeProcessor
{ {
public:
virtual DataVariant execute(ExecutionPolicy& exec_policy) = 0; virtual DataVariant execute(ExecutionPolicy& exec_policy) = 0;
std::string std::string
......
#ifndef BASIC_BINARY_OPERATOR_REGISTER_COMPARISON_OF_HPP
#define BASIC_BINARY_OPERATOR_REGISTER_COMPARISON_OF_HPP
#include <language/utils/BinaryOperatorProcessorBuilder.hpp>
#include <language/utils/OperatorRepository.hpp>
template <typename A_DataT, typename B_DataT>
struct BasicBinaryOperatorRegisterComparisonOf
{
BasicBinaryOperatorRegisterComparisonOf()
{
OperatorRepository& repository = OperatorRepository::instance();
repository.addBinaryOperator<language::eqeq_op>(
std::make_shared<BinaryOperatorProcessorBuilder<language::eqeq_op, bool, A_DataT, B_DataT>>());
repository.addBinaryOperator<language::not_eq_op>(
std::make_shared<BinaryOperatorProcessorBuilder<language::not_eq_op, bool, A_DataT, B_DataT>>());
repository.addBinaryOperator<language::greater_op>(
std::make_shared<BinaryOperatorProcessorBuilder<language::greater_op, bool, A_DataT, B_DataT>>());
repository.addBinaryOperator<language::greater_or_eq_op>(
std::make_shared<BinaryOperatorProcessorBuilder<language::greater_or_eq_op, bool, A_DataT, B_DataT>>());
repository.addBinaryOperator<language::lesser_op>(
std::make_shared<BinaryOperatorProcessorBuilder<language::lesser_op, bool, A_DataT, B_DataT>>());
repository.addBinaryOperator<language::lesser_or_eq_op>(
std::make_shared<BinaryOperatorProcessorBuilder<language::lesser_or_eq_op, bool, A_DataT, B_DataT>>());
}
};
#endif // BASIC_BINARY_OPERATOR_REGISTER_COMPARISON_OF_HPP
#ifndef BINARY_OPERATOR_MANGLER_HPP
#define BINARY_OPERATOR_MANGLER_HPP
#include <language/utils/ASTNodeDataType.hpp>
#include <utils/Exceptions.hpp>
#include <string>
namespace language
{
struct multiply_op;
struct divide_op;
struct plus_op;
struct minus_op;
struct or_op;
struct and_op;
struct xor_op;
struct greater_op;
struct greater_or_eq_op;
struct lesser_op;
struct lesser_or_eq_op;
struct eqeq_op;
struct not_eq_op;
} // namespace language
template <typename BinaryOperatorT>
std::string
binaryOperatorMangler(const ASTNodeDataType& lhs_data_type, const ASTNodeDataType& rhs_data_type)
{
const std::string operator_name = [] {
if constexpr (std::is_same_v<BinaryOperatorT, language::multiply_op>) {
return "*";
} else if constexpr (std::is_same_v<BinaryOperatorT, language::divide_op>) {
return "/";
} else if constexpr (std::is_same_v<BinaryOperatorT, language::plus_op>) {
return "+";
} else if constexpr (std::is_same_v<BinaryOperatorT, language::minus_op>) {
return "-";
} else if constexpr (std::is_same_v<BinaryOperatorT, language::or_op>) {
return "or";
} else if constexpr (std::is_same_v<BinaryOperatorT, language::and_op>) {
return "and";
} else if constexpr (std::is_same_v<BinaryOperatorT, language::xor_op>) {
return "xor";
} else if constexpr (std::is_same_v<BinaryOperatorT, language::greater_op>) {
return ">";
} else if constexpr (std::is_same_v<BinaryOperatorT, language::greater_or_eq_op>) {
return ">=";
} else if constexpr (std::is_same_v<BinaryOperatorT, language::lesser_op>) {
return "<";
} else if constexpr (std::is_same_v<BinaryOperatorT, language::lesser_or_eq_op>) {
return "<=";
} else if constexpr (std::is_same_v<BinaryOperatorT, language::eqeq_op>) {
return "==";
} else if constexpr (std::is_same_v<BinaryOperatorT, language::not_eq_op>) {
return "!=";
} else {
static_assert(std::is_same_v<language::multiply_op, BinaryOperatorT>, "undefined binary operator");
}
}();
return dataTypeName(lhs_data_type) + " " + operator_name + " " + dataTypeName(rhs_data_type);
}
#endif // BINARY_OPERATOR_MANGLER_HPP
#ifndef BINARY_OPERATOR_PROCESSOR_BUILDER_HPP
#define BINARY_OPERATOR_PROCESSOR_BUILDER_HPP
#include <algebra/TinyVector.hpp>
#include <language/PEGGrammar.hpp>
#include <language/node_processor/BinaryExpressionProcessor.hpp>
#include <language/utils/ASTNodeDataTypeTraits.hpp>
#include <language/utils/IBinaryOperatorProcessorBuilder.hpp>
#include <type_traits>
template <typename OperatorT, typename ValueT, typename A_DataT, typename B_DataT>
class BinaryOperatorProcessorBuilder final : public IBinaryOperatorProcessorBuilder
{
public:
BinaryOperatorProcessorBuilder() = default;
ASTNodeDataType
getDataTypeOfA() const
{
return ast_node_data_type_from<A_DataT>;
}
ASTNodeDataType
getDataTypeOfB() const
{
return ast_node_data_type_from<B_DataT>;
}
ASTNodeDataType
getReturnValueType() const
{
return ast_node_data_type_from<ValueT>;
}
std::unique_ptr<INodeProcessor>
getNodeProcessor(ASTNode& node) const
{
return std::make_unique<BinaryExpressionProcessor<OperatorT, ValueT, A_DataT, B_DataT>>(node);
}
};
#endif // BINARY_OPERATOR_PROCESSOR_BUILDER_HPP
#include <language/utils/BinaryOperatorRegisterForB.hpp>
#include <language/utils/BasicBinaryOperatorRegisterComparisonOf.hpp>
void
BinaryOperatorRegisterForB::_register_comparisons()
{
BasicBinaryOperatorRegisterComparisonOf<bool, bool>{};
}
void
BinaryOperatorRegisterForB::_register_logical_operators()
{
OperatorRepository& repository = OperatorRepository::instance();
repository.addBinaryOperator<language::and_op>(
std::make_shared<BinaryOperatorProcessorBuilder<language::and_op, bool, bool, bool>>());
repository.addBinaryOperator<language::or_op>(
std::make_shared<BinaryOperatorProcessorBuilder<language::or_op, bool, bool, bool>>());
repository.addBinaryOperator<language::xor_op>(
std::make_shared<BinaryOperatorProcessorBuilder<language::xor_op, bool, bool, bool>>());
}
void
BinaryOperatorRegisterForB::_register_plus()
{
OperatorRepository& repository = OperatorRepository::instance();
repository.addBinaryOperator<language::plus_op>(
std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, uint64_t, bool, bool>>());
}
void
BinaryOperatorRegisterForB::_register_minus()
{
OperatorRepository& repository = OperatorRepository::instance();
repository.addBinaryOperator<language::minus_op>(
std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, int64_t, bool, bool>>());
}
void
BinaryOperatorRegisterForB::_register_multiply()
{
OperatorRepository& repository = OperatorRepository::instance();
repository.addBinaryOperator<language::multiply_op>(
std::make_shared<BinaryOperatorProcessorBuilder<language::multiply_op, uint64_t, bool, bool>>());
}
void
BinaryOperatorRegisterForB::_register_divide()
{
OperatorRepository& repository = OperatorRepository::instance();
repository.addBinaryOperator<language::divide_op>(
std::make_shared<BinaryOperatorProcessorBuilder<language::divide_op, uint64_t, bool, bool>>());
}
BinaryOperatorRegisterForB::BinaryOperatorRegisterForB()
{
this->_register_comparisons();
this->_register_logical_operators();
this->_register_plus();
this->_register_minus();
this->_register_multiply();
this->_register_divide();
}
#ifndef BINARY_OPERATOR_REGISTER_FOR_B_HPP
#define BINARY_OPERATOR_REGISTER_FOR_B_HPP
class BinaryOperatorRegisterForB
{
private:
void _register_comparisons();
void _register_logical_operators();
void _register_plus();
void _register_minus();
void _register_multiply();
void _register_divide();
public:
BinaryOperatorRegisterForB();
};
#endif // BINARY_OPERATOR_REGISTER_FOR_B_HPP
#include <language/utils/BinaryOperatorRegisterForN.hpp>
#include <language/utils/BasicBinaryOperatorRegisterComparisonOf.hpp>
void
BinaryOperatorRegisterForN::_register_comparisons()
{
BasicBinaryOperatorRegisterComparisonOf<bool, uint64_t>{};
BasicBinaryOperatorRegisterComparisonOf<uint64_t, bool>{};
BasicBinaryOperatorRegisterComparisonOf<uint64_t, uint64_t>{};
}
template <typename OperatorT>
void
BinaryOperatorRegisterForN::_register_arithmetic()
{
OperatorRepository& repository = OperatorRepository::instance();
repository.addBinaryOperator<OperatorT>(
std::make_shared<BinaryOperatorProcessorBuilder<OperatorT, uint64_t, uint64_t, bool>>());
repository.addBinaryOperator<OperatorT>(
std::make_shared<BinaryOperatorProcessorBuilder<OperatorT, uint64_t, bool, uint64_t>>());
repository.addBinaryOperator<OperatorT>(
std::make_shared<BinaryOperatorProcessorBuilder<OperatorT, uint64_t, uint64_t, uint64_t>>());
}
void
BinaryOperatorRegisterForN::_register_minus()
{
OperatorRepository& repository = OperatorRepository::instance();
repository.addBinaryOperator<language::minus_op>(
std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, int64_t, uint64_t, bool>>());
repository.addBinaryOperator<language::minus_op>(
std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, int64_t, bool, uint64_t>>());
repository.addBinaryOperator<language::minus_op>(
std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, int64_t, uint64_t, uint64_t>>());
}
BinaryOperatorRegisterForN::BinaryOperatorRegisterForN()
{
this->_register_comparisons();
this->_register_arithmetic<language::plus_op>();
this->_register_minus();
this->_register_arithmetic<language::multiply_op>();
this->_register_arithmetic<language::divide_op>();
}
#ifndef BINARY_OPERATOR_REGISTER_FOR_N_HPP
#define BINARY_OPERATOR_REGISTER_FOR_N_HPP
class BinaryOperatorRegisterForN
{
private:
template <typename OperatorT>
void _register_arithmetic();
void _register_comparisons();
void _register_minus();
public:
BinaryOperatorRegisterForN();
};
#endif // BINARY_OPERATOR_REGISTER_FOR_N_HPP
#include <language/utils/BinaryOperatorRegisterForR.hpp>
#include <language/utils/BasicBinaryOperatorRegisterComparisonOf.hpp>
void
BinaryOperatorRegisterForR::_register_comparisons()
{
BasicBinaryOperatorRegisterComparisonOf<bool, double>{};
BasicBinaryOperatorRegisterComparisonOf<double, bool>{};
BasicBinaryOperatorRegisterComparisonOf<uint64_t, double>{};
BasicBinaryOperatorRegisterComparisonOf<double, uint64_t>{};
BasicBinaryOperatorRegisterComparisonOf<int64_t, double>{};
BasicBinaryOperatorRegisterComparisonOf<double, int64_t>{};
BasicBinaryOperatorRegisterComparisonOf<double, double>{};
}
template <typename OperatorT>
void
BinaryOperatorRegisterForR::_register_arithmetic()
{
OperatorRepository& repository = OperatorRepository::instance();
repository.addBinaryOperator<OperatorT>(
std::make_shared<BinaryOperatorProcessorBuilder<OperatorT, double, double, bool>>());
repository.addBinaryOperator<OperatorT>(
std::make_shared<BinaryOperatorProcessorBuilder<OperatorT, double, bool, double>>());
repository.addBinaryOperator<OperatorT>(
std::make_shared<BinaryOperatorProcessorBuilder<OperatorT, double, double, uint64_t>>());
repository.addBinaryOperator<OperatorT>(
std::make_shared<BinaryOperatorProcessorBuilder<OperatorT, double, uint64_t, double_t>>());
repository.addBinaryOperator<OperatorT>(
std::make_shared<BinaryOperatorProcessorBuilder<OperatorT, double, double, int64_t>>());
repository.addBinaryOperator<OperatorT>(
std::make_shared<BinaryOperatorProcessorBuilder<OperatorT, double, int64_t, double_t>>());
repository.addBinaryOperator<OperatorT>(
std::make_shared<BinaryOperatorProcessorBuilder<OperatorT, double, double, double>>());
}
BinaryOperatorRegisterForR::BinaryOperatorRegisterForR()
{
this->_register_comparisons();
this->_register_arithmetic<language::plus_op>();
this->_register_arithmetic<language::minus_op>();
this->_register_arithmetic<language::multiply_op>();
this->_register_arithmetic<language::divide_op>();
}
#ifndef BINARY_OPERATOR_REGISTER_FOR_R_HPP
#define BINARY_OPERATOR_REGISTER_FOR_R_HPP
class BinaryOperatorRegisterForR
{
private:
template <typename OperatorT>
void _register_arithmetic();
void _register_comparisons();
public:
BinaryOperatorRegisterForR();
};
#endif // BINARY_OPERATOR_REGISTER_FOR_R_HPP
#include <language/utils/BinaryOperatorRegisterForRn.hpp>
#include <language/utils/BinaryOperatorProcessorBuilder.hpp>
#include <language/utils/OperatorRepository.hpp>
template <size_t Dimension>
void
BinaryOperatorRegisterForRn<Dimension>::_register_comparisons()
{
OperatorRepository& repository = OperatorRepository::instance();
using Rn = TinyVector<Dimension>;
repository.addBinaryOperator<language::eqeq_op>(
std::make_shared<BinaryOperatorProcessorBuilder<language::eqeq_op, bool, Rn, Rn>>());
repository.addBinaryOperator<language::not_eq_op>(
std::make_shared<BinaryOperatorProcessorBuilder<language::not_eq_op, bool, Rn, Rn>>());
}
template <size_t Dimension>
void
BinaryOperatorRegisterForRn<Dimension>::_register_product_by_a_scalar()
{
OperatorRepository& repository = OperatorRepository::instance();
using Rn = TinyVector<Dimension>;
repository.addBinaryOperator<language::multiply_op>(
std::make_shared<BinaryOperatorProcessorBuilder<language::multiply_op, Rn, bool, Rn>>());
repository.addBinaryOperator<language::multiply_op>(
std::make_shared<BinaryOperatorProcessorBuilder<language::multiply_op, Rn, uint64_t, Rn>>());
repository.addBinaryOperator<language::multiply_op>(
std::make_shared<BinaryOperatorProcessorBuilder<language::multiply_op, Rn, int64_t, Rn>>());
repository.addBinaryOperator<language::multiply_op>(
std::make_shared<BinaryOperatorProcessorBuilder<language::multiply_op, Rn, double, Rn>>());
}
template <size_t Dimension>
template <typename OperatorT>
void
BinaryOperatorRegisterForRn<Dimension>::_register_arithmetic()
{
OperatorRepository& repository = OperatorRepository::instance();
using Rn = TinyVector<Dimension>;
repository.addBinaryOperator<OperatorT>(std::make_shared<BinaryOperatorProcessorBuilder<OperatorT, Rn, Rn, Rn>>());
}
template <size_t Dimension>
BinaryOperatorRegisterForRn<Dimension>::BinaryOperatorRegisterForRn()
{
this->_register_comparisons();
this->_register_product_by_a_scalar();
this->_register_arithmetic<language::plus_op>();
this->_register_arithmetic<language::minus_op>();
}
template class BinaryOperatorRegisterForRn<1>;
template class BinaryOperatorRegisterForRn<2>;
template class BinaryOperatorRegisterForRn<3>;
#ifndef BINARY_OPERATOR_REGISTER_FOR_RN_HPP
#define BINARY_OPERATOR_REGISTER_FOR_RN_HPP
#include <cstdlib>
template <size_t Dimension>
class BinaryOperatorRegisterForRn
{
private:
void _register_comparisons();
void _register_product_by_a_scalar();
template <typename OperatorT>
void _register_arithmetic();
public:
BinaryOperatorRegisterForRn();
};
#endif // BINARY_OPERATOR_REGISTER_FOR_RN_HPP
#include <language/utils/BinaryOperatorRegisterForString.hpp>
#include <language/utils/BinaryOperatorProcessorBuilder.hpp>
#include <language/utils/ConcatExpressionProcessorBuilder.hpp>
#include <language/utils/OperatorRepository.hpp>
void
BinaryOperatorRegisterForString::_register_comparisons()
{
OperatorRepository& repository = OperatorRepository::instance();
repository.addBinaryOperator<language::eqeq_op>(
std::make_shared<BinaryOperatorProcessorBuilder<language::eqeq_op, bool, std::string, std::string>>());
repository.addBinaryOperator<language::not_eq_op>(
std::make_shared<BinaryOperatorProcessorBuilder<language::not_eq_op, bool, std::string, std::string>>());
}
template <typename RHS_T>
void
BinaryOperatorRegisterForString::_register_concat()
{
OperatorRepository& repository = OperatorRepository::instance();
repository.addBinaryOperator<language::plus_op>(std::make_shared<ConcatExpressionProcessorBuilder<RHS_T>>());
}
BinaryOperatorRegisterForString::BinaryOperatorRegisterForString()
{
this->_register_comparisons();
this->_register_concat<bool>();
this->_register_concat<unsigned long>();
this->_register_concat<long>();
this->_register_concat<double>();
this->_register_concat<TinyVector<1>>();
this->_register_concat<TinyVector<2>>();
this->_register_concat<TinyVector<3>>();
this->_register_concat<std::string>();
}
#ifndef BINARY_OPERATOR_REGISTER_FOR_STRING_HPP
#define BINARY_OPERATOR_REGISTER_FOR_STRING_HPP
class BinaryOperatorRegisterForString
{
private:
void _register_comparisons();
template <typename RHS_T>
void _register_concat();
public:
BinaryOperatorRegisterForString();
};
#endif // BINARY_OPERATOR_REGISTER_FOR_STRING_HPP
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment