File operator.hpp¶
File List > backends > cxx > include > zmbt > expr > operator.hpp
Go to the documentation of this file
#ifndef ZMBT_EXPR_SIGNAL_OPERATOR_HANDLER_HPP_
#define ZMBT_EXPR_SIGNAL_OPERATOR_HANDLER_HPP_
#include <limits>
#include "zmbt/core.hpp"
#include "zmbt/reflect.hpp"
#include "keyword.hpp"
#include "lazy_param.hpp"
#include <boost/current_function.hpp>
#define ZMBT_SOH_HANDLE_UNARY_TRANSFORM(OP, TRAIT) \
template <class T> \
static auto handle_##TRAIT(LV val) \
-> mp_if<has_##TRAIT<T>, V> \
try { \
return json_from(OP dejsonize<T>(val)); \
} \
catch(const std::exception& e) \
{ \
return detail::make_error_expr( \
e.what(), BOOST_CURRENT_FUNCTION); \
} \
template <class T> \
static auto handle_##TRAIT(LV) \
-> mp_if<mp_not<has_##TRAIT<T>>, V> \
try { \
return detail::make_error_expr( \
"invalid operand", BOOST_CURRENT_FUNCTION); \
} \
catch(const std::exception& e) \
{ \
return detail::make_error_expr( \
e.what(), BOOST_CURRENT_FUNCTION); \
}
#define ZMBT_SOH_HANDLE_BIN_TRANSFORM(OP, TRAIT) \
template <class T> \
static auto handle_##TRAIT(LV lhs, LV rhs) \
-> mp_if<has_##TRAIT<T>, V> \
try { \
return json_from(dejsonize<T>(lhs) OP dejsonize<T>(rhs)); \
} \
catch(const std::exception& e) \
{ \
return detail::make_error_expr( \
e.what(), BOOST_CURRENT_FUNCTION); \
} \
template <class T> \
static auto handle_##TRAIT(LV, LV) \
-> mp_if<mp_not<has_##TRAIT<T>>, V> \
try { \
return detail::make_error_expr( \
"invalid operands", BOOST_CURRENT_FUNCTION); \
} \
catch(const std::exception& e) \
{ \
return detail::make_error_expr( \
e.what(), BOOST_CURRENT_FUNCTION); \
}
namespace zmbt {
namespace lang {
namespace detail
{
ZMBT_HAS_TYPE(decorated_type)
boost::json::value make_error_expr(boost::json::string_view msg, boost::json::string_view ctx);
}
class Operator
{
public:
using V = boost::json::value;
using LV = LazyParam;
enum Config : std::uint32_t
{
Null,
Decor = 1U << 0,
Comparison = 1U << 1,
Arithmetics = 1U << 2,
Bitwise = 1U << 3,
Shift = 1U << 4,
Logic = 1U << 5,
Default = Decor|Comparison|Arithmetics|Bitwise|Shift,
Full = Default|Logic,
};
static V generic_is_truth (LV);
static V generic_decorate (LV);
static V generic_undecorate (LV);
static V generic_negate (LV);
static V generic_complement (LV);
static V generic_logical_not(LV);
static V generic_equal_to (LV, LV);
static V generic_less (LV, LV);
static V generic_less_equal (LV, LV);
static V generic_plus (LV, LV);
static V generic_minus (LV, LV);
static V generic_multiplies (LV, LV);
static V generic_divides (LV, LV);
static V generic_modulus (LV, LV);
static V generic_bit_and (LV, LV);
static V generic_bit_or (LV, LV);
static V generic_bit_xor (LV, LV);
static V generic_left_shift (LV, LV);
static V generic_right_shift(LV, LV);
static V generic_logical_and(LV, LV);
static V generic_logical_or (LV, LV);
static V generic_pow (LV, LV);
static V generic_log (LV, LV);
static V generic_quot(LV, LV);
private:
using unary_transform = std::function<V(LV)>;
using binary_transform = std::function<V(LV, LV)>;
ZMBT_SOH_HANDLE_UNARY_TRANSFORM(-, negate)
ZMBT_SOH_HANDLE_UNARY_TRANSFORM(~, complement)
ZMBT_SOH_HANDLE_UNARY_TRANSFORM(!, logical_not)
ZMBT_SOH_HANDLE_BIN_TRANSFORM(==, equal_to)
ZMBT_SOH_HANDLE_BIN_TRANSFORM(<, less)
ZMBT_SOH_HANDLE_BIN_TRANSFORM(<=, less_equal)
ZMBT_SOH_HANDLE_BIN_TRANSFORM(+, plus)
ZMBT_SOH_HANDLE_BIN_TRANSFORM(-, minus)
ZMBT_SOH_HANDLE_BIN_TRANSFORM(*, multiplies)
ZMBT_SOH_HANDLE_BIN_TRANSFORM(/, divides)
ZMBT_SOH_HANDLE_BIN_TRANSFORM(%, modulus)
ZMBT_SOH_HANDLE_BIN_TRANSFORM(&, bit_and)
ZMBT_SOH_HANDLE_BIN_TRANSFORM(|, bit_or)
ZMBT_SOH_HANDLE_BIN_TRANSFORM(^, bit_xor)
ZMBT_SOH_HANDLE_BIN_TRANSFORM(<<, left_shift)
ZMBT_SOH_HANDLE_BIN_TRANSFORM(>>, right_shift)
ZMBT_SOH_HANDLE_BIN_TRANSFORM(&&, logical_and)
ZMBT_SOH_HANDLE_BIN_TRANSFORM(||, logical_or)
#undef ZMBT_SOH_HANDLE_UNARY_TRANSFORM
#undef ZMBT_SOH_HANDLE_BIN_TRANSFORM
template <class T>
static auto handle_decorate(LV v)
-> mp_if<detail::has_type_decorated_type<T>, boost::json::value>
try
{
using Decorated = typename T::decorated_type;
return json_from(static_cast<Decorated>(dejsonize<T>(v)));
}
catch(const std::exception& e)
{
return detail::make_error_expr(e.what(), BOOST_CURRENT_FUNCTION);
}
template <class T>
static auto handle_decorate(boost::json::value const& a)
-> mp_if<mp_not<detail::has_type_decorated_type<T>>, boost::json::value>
try
{
return json_from(dejsonize<T>(a));
}
catch(const std::exception& e)
{
return detail::make_error_expr(e.what(), BOOST_CURRENT_FUNCTION);
}
template <class T>
static auto handle_undecorate(LV const& a)
-> mp_if<detail::has_type_decorated_type<T>, boost::json::value>
try
{
using Decorated = typename T::decorated_type;
return json_from(static_cast<T>(dejsonize<Decorated>(a)));
}
catch(const std::exception& e)
{
return detail::make_error_expr(e.what(), BOOST_CURRENT_FUNCTION);
}
template <class T>
static auto handle_undecorate(LV const& a)
-> mp_if<mp_not<detail::has_type_decorated_type<T>>, boost::json::value>
try
{
return json_from(dejsonize<T>(a));
}
catch(const std::exception& e)
{
return detail::make_error_expr(e.what(), BOOST_CURRENT_FUNCTION);
}
template <class T>
static auto handle_is_truth(LV const& val) -> mp_if<is_convertible<T, bool>, boost::json::value>
try
{
return static_cast<bool>(dejsonize<T>(val));
}
catch(const std::exception& e)
{
return detail::make_error_expr(e.what(), BOOST_CURRENT_FUNCTION);
}
template <class T>
static auto handle_is_truth(LV const&) -> mp_if<mp_not<is_convertible<T, bool>>, boost::json::value>
{
return detail::make_error_expr("invalid operand", BOOST_CURRENT_FUNCTION);
}
struct Handle {
boost::json::string annotation{""};
struct D {
unary_transform decorate{generic_decorate};
unary_transform undecorate{generic_undecorate};
} decor;
struct C {
binary_transform equal_to{generic_equal_to};
binary_transform less{generic_less};
binary_transform less_equal{generic_less_equal};
} comp;
struct A {
unary_transform neg{generic_negate};
binary_transform add{generic_plus};
binary_transform sub{generic_minus};
binary_transform mul{generic_multiplies};
binary_transform div{generic_divides};
binary_transform mod{generic_modulus};
} arithmetics;
struct B {
unary_transform compl_{generic_complement};
binary_transform and_{generic_bit_and};
binary_transform or_{generic_bit_or};
binary_transform xor_{generic_bit_xor};
} bitwise;
struct S {
binary_transform left{generic_left_shift};
binary_transform right{generic_right_shift};
} shift;
struct L {
unary_transform bool_{generic_is_truth};
binary_transform and_{generic_logical_and};
binary_transform or_{generic_logical_or};
} logic;
};
template <class T>
static Handle makeHandle(type_tag<T>, Config const cfg = Default) {
return {
format("%s#%d", type_name<T>(), cfg).c_str(),
Decor & cfg ? Handle::D{
handle_decorate<T>,
handle_undecorate<T>
} : Handle::D{},
Comparison & cfg ? Handle::C{
handle_equal_to<T>,
handle_less<T>,
handle_less_equal<T>
} : Handle::C{},
Arithmetics & cfg ? Handle::A{
handle_negate<T>,
handle_plus<T>,
handle_minus<T>,
handle_multiplies<T>,
handle_divides<T>,
handle_modulus<T>
} : Handle::A{},
Bitwise & cfg ? Handle::B{
handle_complement<T>,
handle_bit_and<T>,
handle_bit_or<T>,
handle_bit_xor<T>
} : Handle::B{},
Shift & cfg ? Handle::S{
handle_left_shift<T>,
handle_right_shift<T>
} : Handle::S{},
Logic & cfg ? Handle::L{
handle_is_truth<T>,
handle_logical_and<T>,
handle_logical_or<T>
} : Handle::L{},
};
}
Handle handle_;
explicit Operator(
Handle const handle
);
static bool exchangeHandle(Handle& handle, bool const retrieve);
public:
Operator();
template <class T>
Operator(type_tag<T> tag, Config const cfg)
: Operator{makeHandle(tag, cfg)}
{
}
template <class T>
Operator(type_tag<T> tag)
: Operator{tag, Config::Default}
{
}
Operator(boost::json::string_view annotation);
Operator(Operator const&) = default;
Operator(Operator &&) = default;
virtual ~Operator() = default;
Operator& operator=(Operator const&) = default;
Operator& operator=(Operator &&) = default;
bool is_generic() const
{
return annotation().empty();
}
boost::json::string annotation() const
{
return handle_.annotation;
}
boost::json::value decorate(boost::json::value const& a) const
{
return handle_.decor.decorate(a);
}
boost::json::value undecorate(boost::json::value const& a) const
{
return handle_.decor.undecorate(a);
}
boost::json::value apply(lang::Keyword const& keyword, LV lhs, LV rhs) const;
private:
V is_subset(LV const& lhs, LV const& rhs) const;
V contains(LV const& set, LV const& element) const;
};
} // namespace lang
} // namespace zmbt
#endif // ZMBT_EXPR_SIGNAL_OPERATOR_HANDLER_HPP_