#ifndef BOOST_PROTO17_EXPRESSION_HPP_INCLUDED #define BOOST_PROTO17_EXPRESSION_HPP_INCLUDED #include "expression_fwd.hpp" #include "user_macros.hpp" #include "detail/expression.hpp" #include #include namespace boost::proto17 { namespace adl_detail { template constexpr decltype(auto) eval_expression_as (E const & expr, hana::basic_type, T &&... args); struct eval_expression_as_fn { template constexpr decltype(auto) operator() (E const & expr, hana::basic_type rtype, T &&... args) const { return eval_expression_as(expr, rtype, static_cast(args)...); } }; } using adl_detail::eval_expression_as_fn; inline namespace function_objects { inline constexpr eval_expression_as_fn eval_expression_as{}; } inline char const * op_string (expr_kind kind) { switch (kind) { case expr_kind::unary_plus: return "+"; case expr_kind::negate: return "-"; case expr_kind::dereference: return "*"; case expr_kind::complement: return "~"; case expr_kind::address_of: return "&"; case expr_kind::logical_not: return "!"; case expr_kind::pre_inc: return "++"; case expr_kind::pre_dec: return "--"; case expr_kind::post_inc: return "++(int)"; case expr_kind::post_dec: return "--(int)"; case expr_kind::shift_left: return "<<"; case expr_kind::shift_right: return ">>"; case expr_kind::multiplies: return "*"; case expr_kind::divides: return "/"; case expr_kind::modulus: return "%"; case expr_kind::plus: return "+"; case expr_kind::minus: return "-"; case expr_kind::less: return "<"; case expr_kind::greater: return ">"; case expr_kind::less_equal: return "<="; case expr_kind::greater_equal: return ">="; case expr_kind::equal_to: return "=="; case expr_kind::not_equal_to: return "!="; case expr_kind::logical_or: return "||"; case expr_kind::logical_and: return "&&"; case expr_kind::bitwise_and: return "&"; case expr_kind::bitwise_or: return "|"; case expr_kind::bitwise_xor: return "^"; case expr_kind::comma: return ","; case expr_kind::mem_ptr: return "->*"; case expr_kind::assign: return "="; case expr_kind::shift_left_assign: return "<<="; case expr_kind::shift_right_assign: return ">>="; case expr_kind::multiplies_assign: return "*="; case expr_kind::divides_assign: return "/="; case expr_kind::modulus_assign: return "%="; case expr_kind::plus_assign: return "+="; case expr_kind::minus_assign: return "-="; case expr_kind::bitwise_and_assign: return "&="; case expr_kind::bitwise_or_assign: return "|="; case expr_kind::bitwise_xor_assign: return "^="; case expr_kind::subscript: return "[]"; case expr_kind::call: return "()"; default: return "** ERROR: UNKNOWN OPERATOR! **"; } } template struct expression { using this_type = expression; using tuple_type = Tuple; static const expr_kind kind = Kind; expression () {} expression (tuple_type && rhs) : elements (std::move(rhs)) {} tuple_type elements; #ifdef BOOST_PROTO17_CONVERSION_OPERATOR_TEMPLATE template operator R () { return eval_expression_as(*this, hana::basic_type{}); } #endif decltype(auto) value () const & { return ::boost::proto17::value(*this); } decltype(auto) value () & { return ::boost::proto17::value(*this); } decltype(auto) value () && { return ::boost::proto17::value(std::move(*this)); } decltype(auto) left () const & { return ::boost::proto17::left(*this); } decltype(auto) left () & { return ::boost::proto17::left(*this); } decltype(auto) left () && { return ::boost::proto17::left(std::move(*this)); } decltype(auto) right () const & { return ::boost::proto17::right(*this); } decltype(auto) right () & { return ::boost::proto17::right(*this); } decltype(auto) right () && { return ::boost::proto17::right(std::move(*this)); } #define BOOST_PROTO17_UNARY_MEMBER_OPERATOR(op_name) \ BOOST_PROTO17_USER_UNARY_OPERATOR_MEMBER(op_name, this_type, ::boost::proto17::expression) BOOST_PROTO17_UNARY_MEMBER_OPERATOR(unary_plus) // + BOOST_PROTO17_UNARY_MEMBER_OPERATOR(negate) // - BOOST_PROTO17_UNARY_MEMBER_OPERATOR(dereference) // * BOOST_PROTO17_UNARY_MEMBER_OPERATOR(complement) // ~ BOOST_PROTO17_UNARY_MEMBER_OPERATOR(address_of) // & BOOST_PROTO17_UNARY_MEMBER_OPERATOR(logical_not) // ! BOOST_PROTO17_UNARY_MEMBER_OPERATOR(pre_inc) // ++ BOOST_PROTO17_UNARY_MEMBER_OPERATOR(pre_dec) // -- BOOST_PROTO17_UNARY_MEMBER_OPERATOR(post_inc) // ++(int) BOOST_PROTO17_UNARY_MEMBER_OPERATOR(post_dec) // --(int) #undef BOOST_PROTO17_UNARY_MEMBER_OPERATOR // TODO: Add test coverage for all the operators (with all three qual // types), for expression and terminal. Don't forget the free // operators. #define BOOST_PROTO17_BINARY_MEMBER_OPERATOR(op_name) \ BOOST_PROTO17_USER_BINARY_OPERATOR_MEMBER(op_name, this_type, ::boost::proto17::expression) BOOST_PROTO17_BINARY_MEMBER_OPERATOR(shift_left) // << BOOST_PROTO17_BINARY_MEMBER_OPERATOR(shift_right) // >> BOOST_PROTO17_BINARY_MEMBER_OPERATOR(multiplies) // * BOOST_PROTO17_BINARY_MEMBER_OPERATOR(divides) // / BOOST_PROTO17_BINARY_MEMBER_OPERATOR(modulus) // % BOOST_PROTO17_BINARY_MEMBER_OPERATOR(plus) // + BOOST_PROTO17_BINARY_MEMBER_OPERATOR(minus) // - BOOST_PROTO17_BINARY_MEMBER_OPERATOR(less) // < BOOST_PROTO17_BINARY_MEMBER_OPERATOR(greater) // > BOOST_PROTO17_BINARY_MEMBER_OPERATOR(less_equal) // <= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(greater_equal) // >= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(equal_to) // == BOOST_PROTO17_BINARY_MEMBER_OPERATOR(not_equal_to) // != BOOST_PROTO17_BINARY_MEMBER_OPERATOR(logical_or) // || BOOST_PROTO17_BINARY_MEMBER_OPERATOR(logical_and) // && BOOST_PROTO17_BINARY_MEMBER_OPERATOR(bitwise_and) // & BOOST_PROTO17_BINARY_MEMBER_OPERATOR(bitwise_or) // | BOOST_PROTO17_BINARY_MEMBER_OPERATOR(bitwise_xor) // ^ BOOST_PROTO17_BINARY_MEMBER_OPERATOR(comma) // , BOOST_PROTO17_BINARY_MEMBER_OPERATOR(mem_ptr) // ->* BOOST_PROTO17_BINARY_MEMBER_OPERATOR(assign) // = BOOST_PROTO17_BINARY_MEMBER_OPERATOR(shift_left_assign) // <<= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(shift_right_assign) // >>= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(multiplies_assign) // *= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(divides_assign) // /= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(modulus_assign) // %= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(plus_assign) // += BOOST_PROTO17_BINARY_MEMBER_OPERATOR(minus_assign) // -= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(bitwise_and_assign) // &= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(bitwise_or_assign) // |= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(bitwise_xor_assign) // ^= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(subscript) // [] #undef BOOST_PROTO17_BINARY_MEMBER_OPERATOR BOOST_PROTO17_USER_MEMBER_CALL_OPERATOR(this_type, ::boost::proto17::expression) }; template struct expression> { using this_type = expression>; using tuple_type = hana::tuple; static const expr_kind kind = expr_kind::terminal; expression () {} expression (T && t) : elements (static_cast(t)) {} expression (hana::tuple && rhs) : elements (std::move(rhs)) {} tuple_type elements; #ifdef BOOST_PROTO17_CONVERSION_OPERATOR_TEMPLATE template operator R () { return eval_expression_as(*this, hana::basic_type{}); } #endif decltype(auto) value () const & { return ::boost::proto17::value(*this); } decltype(auto) value () & { return ::boost::proto17::value(*this); } decltype(auto) value () && { return ::boost::proto17::value(std::move(*this)); } #define BOOST_PROTO17_UNARY_MEMBER_OPERATOR(op_name) \ BOOST_PROTO17_USER_UNARY_OPERATOR_MEMBER(op_name, this_type, ::boost::proto17::expression) BOOST_PROTO17_UNARY_MEMBER_OPERATOR(unary_plus) // + BOOST_PROTO17_UNARY_MEMBER_OPERATOR(negate) // - BOOST_PROTO17_UNARY_MEMBER_OPERATOR(dereference) // * BOOST_PROTO17_UNARY_MEMBER_OPERATOR(complement) // ~ BOOST_PROTO17_UNARY_MEMBER_OPERATOR(address_of) // & BOOST_PROTO17_UNARY_MEMBER_OPERATOR(logical_not) // ! BOOST_PROTO17_UNARY_MEMBER_OPERATOR(pre_inc) // ++ BOOST_PROTO17_UNARY_MEMBER_OPERATOR(pre_dec) // -- BOOST_PROTO17_UNARY_MEMBER_OPERATOR(post_inc) // ++(int) BOOST_PROTO17_UNARY_MEMBER_OPERATOR(post_dec) // --(int) #undef BOOST_PROTO17_UNARY_MEMBER_OPERATOR #define BOOST_PROTO17_BINARY_MEMBER_OPERATOR(op_name) \ BOOST_PROTO17_USER_BINARY_OPERATOR_MEMBER(op_name, this_type, ::boost::proto17::expression) BOOST_PROTO17_BINARY_MEMBER_OPERATOR(shift_left) // << BOOST_PROTO17_BINARY_MEMBER_OPERATOR(shift_right) // >> BOOST_PROTO17_BINARY_MEMBER_OPERATOR(multiplies) // * BOOST_PROTO17_BINARY_MEMBER_OPERATOR(divides) // / BOOST_PROTO17_BINARY_MEMBER_OPERATOR(modulus) // % BOOST_PROTO17_BINARY_MEMBER_OPERATOR(plus) // + BOOST_PROTO17_BINARY_MEMBER_OPERATOR(minus) // - BOOST_PROTO17_BINARY_MEMBER_OPERATOR(less) // < BOOST_PROTO17_BINARY_MEMBER_OPERATOR(greater) // > BOOST_PROTO17_BINARY_MEMBER_OPERATOR(less_equal) // <= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(greater_equal) // >= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(equal_to) // == BOOST_PROTO17_BINARY_MEMBER_OPERATOR(not_equal_to) // != BOOST_PROTO17_BINARY_MEMBER_OPERATOR(logical_or) // || BOOST_PROTO17_BINARY_MEMBER_OPERATOR(logical_and) // && BOOST_PROTO17_BINARY_MEMBER_OPERATOR(bitwise_and) // & BOOST_PROTO17_BINARY_MEMBER_OPERATOR(bitwise_or) // | BOOST_PROTO17_BINARY_MEMBER_OPERATOR(bitwise_xor) // ^ BOOST_PROTO17_BINARY_MEMBER_OPERATOR(comma) // , BOOST_PROTO17_BINARY_MEMBER_OPERATOR(mem_ptr) // ->* BOOST_PROTO17_BINARY_MEMBER_OPERATOR(assign) // = BOOST_PROTO17_BINARY_MEMBER_OPERATOR(shift_left_assign) // <<= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(shift_right_assign) // >>= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(multiplies_assign) // *= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(divides_assign) // /= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(modulus_assign) // %= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(plus_assign) // += BOOST_PROTO17_BINARY_MEMBER_OPERATOR(minus_assign) // -= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(bitwise_and_assign) // &= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(bitwise_or_assign) // |= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(bitwise_xor_assign) // ^= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(subscript) // [] #undef BOOST_PROTO17_BINARY_MEMBER_OPERATOR BOOST_PROTO17_USER_MEMBER_CALL_OPERATOR(this_type, ::boost::proto17::expression) }; template using placeholder = expression>>; template decltype(auto) deref (T && x) { if constexpr (detail::is_expr::value) { if constexpr (detail::remove_cv_ref_t::kind == expr_kind::expr_ref) { return ::boost::proto17::value(::boost::proto17::value(static_cast(x))); } else { return static_cast(x); } } else { return static_cast(x); } } template decltype(auto) value (Expr && expr) { static_assert( detail::is_expr::value, "value() is only defined for expression templates." ); using namespace hana::literals; constexpr expr_kind kind = detail::remove_cv_ref_t::kind; static_assert( detail::arity_of() == detail::expr_arity::one, "value() is only defined for unary expressions." ); if constexpr (kind == expr_kind::expr_ref) { if constexpr (std::is_rvalue_reference{} && !std::is_const>{}) { return std::move(*expr.elements[0_c]); } else { return *expr.elements[0_c]; } } else { if constexpr (std::is_lvalue_reference{}) { return expr.elements[0_c]; } else { return std::move(expr.elements[0_c]); } } } template decltype(auto) left (Expr && expr) { static_assert( detail::is_expr::value, "left() is only defined for expression templates." ); using namespace hana::literals; constexpr expr_kind kind = detail::remove_cv_ref_t::kind; if constexpr (kind == expr_kind::expr_ref) { return left(::boost::proto17::value(static_cast(expr))); } else { static_assert( detail::arity_of() == detail::expr_arity::two, "left() is only defined for binary expressions." ); if constexpr (std::is_lvalue_reference{}) { return expr.elements[0_c]; } else { return std::move(expr.elements[0_c]); } } } template decltype(auto) right (Expr && expr) { static_assert( detail::is_expr::value, "right() is only defined for expression templates." ); using namespace hana::literals; constexpr expr_kind kind = detail::remove_cv_ref_t::kind; if constexpr (kind == expr_kind::expr_ref) { return right(::boost::proto17::value(static_cast(expr))); } else { static_assert( detail::arity_of() == detail::expr_arity::two, "right() is only defined for binary expressions." ); if constexpr (std::is_lvalue_reference{}) { return expr.elements[1_c]; } else { return std::move(expr.elements[1_c]); } } } #define BOOST_PROTO17_BINARY_NON_MEMBER_OPERATOR(op_name) \ BOOST_PROTO17_USER_NON_MEMBER_BINARY_OPERATOR(op_name, expression) BOOST_PROTO17_BINARY_NON_MEMBER_OPERATOR(shift_left) // << BOOST_PROTO17_BINARY_NON_MEMBER_OPERATOR(shift_right) // >> BOOST_PROTO17_BINARY_NON_MEMBER_OPERATOR(multiplies) // * BOOST_PROTO17_BINARY_NON_MEMBER_OPERATOR(divides) // / BOOST_PROTO17_BINARY_NON_MEMBER_OPERATOR(modulus) // % BOOST_PROTO17_BINARY_NON_MEMBER_OPERATOR(plus) // + BOOST_PROTO17_BINARY_NON_MEMBER_OPERATOR(minus) // - BOOST_PROTO17_BINARY_NON_MEMBER_OPERATOR(less) // < BOOST_PROTO17_BINARY_NON_MEMBER_OPERATOR(greater) // > BOOST_PROTO17_BINARY_NON_MEMBER_OPERATOR(less_equal) // <= BOOST_PROTO17_BINARY_NON_MEMBER_OPERATOR(greater_equal) // >= BOOST_PROTO17_BINARY_NON_MEMBER_OPERATOR(equal_to) // == BOOST_PROTO17_BINARY_NON_MEMBER_OPERATOR(not_equal_to) // != BOOST_PROTO17_BINARY_NON_MEMBER_OPERATOR(logical_or) // || BOOST_PROTO17_BINARY_NON_MEMBER_OPERATOR(logical_and) // && BOOST_PROTO17_BINARY_NON_MEMBER_OPERATOR(bitwise_and) // & BOOST_PROTO17_BINARY_NON_MEMBER_OPERATOR(bitwise_or) // | BOOST_PROTO17_BINARY_NON_MEMBER_OPERATOR(bitwise_xor) // ^ #undef BOOST_PROTO17_BINARY_NON_MEMBER_OPERATOR template auto make_expression (T &&... t) { using tuple_type = hana::tuple...>; return expression{ tuple_type{ detail::make_operand>{}(static_cast(t))... } }; } template