Select Git revision
BinaryExpressionProcessor.hpp
BinaryExpressionProcessor.hpp 8.71 KiB
#ifndef BINARY_EXPRESSION_PROCESSOR_HPP
#define BINARY_EXPRESSION_PROCESSOR_HPP
#include <language/PEGGrammar.hpp>
#include <language/ast/ASTNode.hpp>
#include <language/node_processor/INodeProcessor.hpp>
#include <language/utils/ParseError.hpp>
#include <type_traits>
template <typename DataType>
class DataHandler;
template <typename Op>
struct BinOp;
template <>
struct BinOp<language::and_op>
{
template <typename A, typename B>
PUGS_INLINE auto
eval(const A& a, const B& b) -> decltype(a and b)
{
return a and b;
}
};
template <>
struct BinOp<language::or_op>
{
template <typename A, typename B>
PUGS_INLINE auto
eval(const A& a, const B& b) -> decltype(a or b)
{
return a or b;
}
};
template <>
struct BinOp<language::xor_op>
{
// C++ xor returns bitwise xor integer. Here we want to just test if one and
// only one of {a,b} is true so we enforce a bool cast
template <typename A, typename B>
PUGS_INLINE auto
eval(const A& a, const B& b) -> bool
{
return a xor b;
}
};
template <>
struct BinOp<language::eqeq_op>
{
template <typename A, typename B>
PUGS_INLINE auto
eval(const A& a, const B& b) -> decltype(a == b)
{
return a == b;
}
};
template <>
struct BinOp<language::not_eq_op>
{
template <typename A, typename B>
PUGS_INLINE auto
eval(const A& a, const B& b) -> decltype(a != b)
{
return a != b;
}
};
template <>
struct BinOp<language::lesser_op>
{
template <typename A, typename B>
PUGS_INLINE auto
eval(const A& a, const B& b) -> decltype(a < b)
{
return a < b;
}
};
class OStream;
template <>
struct BinOp<language::shift_left_op>
{
template <typename A, typename B>
PUGS_INLINE auto
eval(const A& a, const B& b) -> decltype(a << b)
{
if constexpr (std::is_same_v<A, std::shared_ptr<const OStream>> and std::is_same_v<B, bool>) {
return a << std::boolalpha << b;
} else {
return a << b;
}
}
};
template <>
struct BinOp<language::shift_right_op>
{
template <typename A, typename B>
PUGS_INLINE auto
eval(const A& a, const B& b) -> decltype(a >> b)
{
return a >> b;
}
};
template <>
struct BinOp<language::lesser_or_eq_op>
{
template <typename A, typename B>
PUGS_INLINE auto
eval(const A& a, const B& b) -> decltype(a <= b)
{
return a <= b;
}
};
template <>
struct BinOp<language::greater_op>
{
template <typename A, typename B>
PUGS_INLINE auto
eval(const A& a, const B& b) -> decltype(a > b)
{
return a > b;
}
};
template <>
struct BinOp<language::greater_or_eq_op>
{
template <typename A, typename B>
PUGS_INLINE auto
eval(const A& a, const B& b) -> decltype(a >= b)
{
return a >= b;
}
};
template <>
struct BinOp<language::plus_op>
{
template <typename A, typename B>
PUGS_INLINE auto
eval(const A& a, const B& b) -> decltype(a + b)
{
return a + b;
}
};
template <>
struct BinOp<language::minus_op>
{
template <typename A, typename B>
PUGS_INLINE auto
eval(const A& a, const B& b) -> decltype(a - b)
{
return a - b;
}
};
template <>
struct BinOp<language::multiply_op>
{
template <typename A, typename B>
PUGS_INLINE auto
eval(const A& a, const B& b) -> decltype(a * b)
{
return a * b;
}
};
template <>
struct BinOp<language::divide_op>
{
template <typename A, typename B>
PUGS_INLINE auto
eval(const A& a, const B& b) -> decltype(a / b)
{
return a / b;
}
};
template <typename BinaryOpT, typename ValueT, typename A_DataT, typename B_DataT>
struct BinaryExpressionProcessor final : public INodeProcessor
{
private:
ASTNode& m_node;
PUGS_INLINE DataVariant
_eval(const DataVariant& a, const DataVariant& b)
{
if constexpr (std::is_arithmetic_v<A_DataT> and std::is_arithmetic_v<B_DataT>) {
if constexpr (std::is_signed_v<A_DataT> and not std::is_signed_v<B_DataT>) {
if constexpr (std::is_same_v<B_DataT, bool>) {
return static_cast<ValueT>(
BinOp<BinaryOpT>().eval(std::get<A_DataT>(a), static_cast<int64_t>(std::get<B_DataT>(b))));
} else {
return static_cast<ValueT>(
BinOp<BinaryOpT>().eval(std::get<A_DataT>(a), std::make_signed_t<B_DataT>(std::get<B_DataT>(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 {
return static_cast<ValueT>(
BinOp<BinaryOpT>().eval(std::make_signed_t<A_DataT>(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)));
}
} else {
return static_cast<ValueT>(BinOp<BinaryOpT>().eval(std::get<A_DataT>(a), std::get<B_DataT>(b)));
}
}
public:
DataVariant
execute(ExecutionPolicy& exec_policy)
{
return this->_eval(m_node.children[0]->execute(exec_policy), m_node.children[1]->execute(exec_policy));
}
BinaryExpressionProcessor(ASTNode& node) : m_node{node} {}
};
template <typename BinaryOpT, typename ValueT, typename A_DataT, typename B_DataT>
struct BinaryExpressionProcessor<BinaryOpT, std::shared_ptr<ValueT>, std::shared_ptr<A_DataT>, std::shared_ptr<B_DataT>>
final : public INodeProcessor
{
private:
ASTNode& m_node;
PUGS_INLINE DataVariant
_eval(const DataVariant& a, const DataVariant& b)
{
const auto& embedded_a = std::get<EmbeddedData>(a);
const auto& embedded_b = std::get<EmbeddedData>(b);
std::shared_ptr a_ptr = dynamic_cast<const DataHandler<A_DataT>&>(embedded_a.get()).data_ptr();
std::shared_ptr b_ptr = dynamic_cast<const DataHandler<B_DataT>&>(embedded_b.get()).data_ptr();
return EmbeddedData(std::make_shared<DataHandler<ValueT>>(BinOp<BinaryOpT>().eval(a_ptr, b_ptr)));
}
public:
DataVariant
execute(ExecutionPolicy& exec_policy)
{
try {
return this->_eval(m_node.children[0]->execute(exec_policy), m_node.children[1]->execute(exec_policy));
}
catch (const NormalError& error) {
throw ParseError(error.what(), m_node.begin());
}
}
BinaryExpressionProcessor(ASTNode& node) : m_node{node} {}
};
template <typename BinaryOpT, typename ValueT, typename A_DataT, typename B_DataT>
struct BinaryExpressionProcessor<BinaryOpT, std::shared_ptr<ValueT>, A_DataT, std::shared_ptr<B_DataT>> final
: public INodeProcessor
{
private:
ASTNode& m_node;
PUGS_INLINE DataVariant
_eval(const DataVariant& a, const DataVariant& b)
{
if constexpr ((std::is_arithmetic_v<A_DataT>) or (is_tiny_vector_v<A_DataT>) or (is_tiny_matrix_v<A_DataT>)) {
const auto& a_value = std::get<A_DataT>(a);
const auto& embedded_b = std::get<EmbeddedData>(b);
std::shared_ptr b_ptr = dynamic_cast<const DataHandler<B_DataT>&>(embedded_b.get()).data_ptr();
return EmbeddedData(std::make_shared<DataHandler<ValueT>>(BinOp<BinaryOpT>().eval(a_value, b_ptr)));
} else {
static_assert(std::is_arithmetic_v<A_DataT>, "invalid left hand side type");
}
}
public:
DataVariant
execute(ExecutionPolicy& exec_policy)
{
try {
return this->_eval(m_node.children[0]->execute(exec_policy), m_node.children[1]->execute(exec_policy));
}
catch (const NormalError& error) {
throw ParseError(error.what(), m_node.begin());
}
}
BinaryExpressionProcessor(ASTNode& node) : m_node{node} {}
};
template <typename BinaryOpT, typename ValueT, typename A_DataT, typename B_DataT>
struct BinaryExpressionProcessor<BinaryOpT, std::shared_ptr<ValueT>, std::shared_ptr<A_DataT>, B_DataT> final
: public INodeProcessor
{
private:
ASTNode& m_node;
PUGS_INLINE DataVariant
_eval(const DataVariant& a, const DataVariant& b)
{
if constexpr ((std::is_arithmetic_v<B_DataT>) or (is_tiny_matrix_v<B_DataT>) or (is_tiny_vector_v<B_DataT>) or
(std::is_same_v<std::string, B_DataT>)) {
const auto& embedded_a = std::get<EmbeddedData>(a);
const auto& b_value = std::get<B_DataT>(b);
std::shared_ptr a_ptr = dynamic_cast<const DataHandler<A_DataT>&>(embedded_a.get()).data_ptr();
return EmbeddedData(std::make_shared<DataHandler<ValueT>>(BinOp<BinaryOpT>().eval(a_ptr, b_value)));
} else {
static_assert(std::is_arithmetic_v<B_DataT>, "invalid right hand side type");
}
}
public:
DataVariant
execute(ExecutionPolicy& exec_policy)
{
try {
return this->_eval(m_node.children[0]->execute(exec_policy), m_node.children[1]->execute(exec_policy));
}
catch (const NormalError& error) {
throw ParseError(error.what(), m_node.begin());
}
}
BinaryExpressionProcessor(ASTNode& node) : m_node{node} {}
};
#endif // BINARY_EXPRESSION_PROCESSOR_HPP