diff --git a/expression.hpp b/expression.hpp index 2941bea..9f01097 100644 --- a/expression.hpp +++ b/expression.hpp @@ -50,11 +50,238 @@ namespace boost::proto17 { static const expr_kind kind = Kind; - expression (T && ... t) : - elements (static_cast(t)...) + expression (hana::tuple && rhs) : + elements (std::move(rhs)) {} - expression (hana::tuple && 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 & + { + using namespace hana::literals; + static_assert( + decltype(hana::size(elements))::value == 1UL, + "value() is only defined for unary expressions." + ); + return elements[0_c]; + } + + decltype(auto) value () & + { + using namespace hana::literals; + static_assert( + decltype(hana::size(elements))::value == 1UL, + "value() is only defined for unary expressions." + ); + return elements[0_c]; + } + + decltype(auto) value () && + { + using namespace hana::literals; + static_assert( + decltype(hana::size(elements))::value == 1UL, + "value() is only defined for unary expressions." + ); + return static_cast(elements)[0_c]; + } + + decltype(auto) left () const & + { + using namespace hana::literals; + static_assert( + decltype(hana::size(elements))::value == 2UL, + "left() and right() are only defined for binary expressions." + ); + return elements[0_c]; + } + + decltype(auto) left () & + { + using namespace hana::literals; + static_assert( + decltype(hana::size(elements))::value == 2UL, + "left() and right() are only defined for binary expressions." + ); + return elements[0_c]; + } + + decltype(auto) left () && + { + using namespace hana::literals; + static_assert( + decltype(hana::size(elements))::value == 2UL, + "left() and right() are only defined for binary expressions." + ); + return static_cast(elements)[0_c]; + } + + decltype(auto) right () const & + { + using namespace hana::literals; + static_assert( + decltype(hana::size(elements))::value == 2UL, + "left() and right() are only defined for binary expressions." + ); + return elements[1_c]; + } + + decltype(auto) right () & + { + using namespace hana::literals; + static_assert( + decltype(hana::size(elements))::value == 2UL, + "left() and right() are only defined for binary expressions." + ); + return elements[1_c]; + } + + decltype(auto) right () && + { + using namespace hana::literals; + static_assert( + decltype(hana::size(elements))::value == 2UL, + "left() and right() are only defined for binary expressions." + ); + return static_cast(elements)[1_c]; + } + +#define BOOST_PROTO17_UNARY_MEMBER_OPERATOR(op, op_name) \ + auto operator op const & \ + { \ + return expression{ \ + hana::tuple{*this} \ + }; \ + } \ + auto operator op && \ + { \ + return expression{ \ + hana::tuple{std::move(*this)} \ + }; \ + } + + 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(++(int), post_inc) // ++(int) + BOOST_PROTO17_UNARY_MEMBER_OPERATOR(--(int), post_dec) // --(int) + +#undef BOOST_PROTO17_UNARY_MEMBER_OPERATOR + +#define BOOST_PROTO17_BINARY_MEMBER_OPERATOR(op, op_name) \ + template \ + auto operator op (U && rhs) const & \ + { \ + using rhs_type = detail::operand_type_t; \ + return expression{ \ + hana::tuple{ \ + *this, \ + static_cast(rhs) \ + } \ + }; \ + } \ + template \ + auto operator op (U && rhs) && \ + { \ + using rhs_type = detail::operand_type_t; \ + return expression{ \ + hana::tuple{ \ + std::move(*this), \ + static_cast(rhs) \ + } \ + }; \ + } + + 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) // ^ + + template + auto operator, (U && rhs) const & + { + using rhs_type = detail::operand_type_t; + return expression{ + hana::tuple{*this, static_cast(rhs)} + }; + } + template + auto operator, (U && rhs) && + { + using rhs_type = detail::operand_type_t; + return expression{ + hana::tuple{std::move(*this), static_cast(rhs)} + }; + } + + 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 + + template + auto operator() (U && ...u) const & + { + using tuple_type = hana::tuple...>; + return detail::make_call_expression(*this, static_cast(u)...); + } + template + auto operator() (U && ...u) && + { + using tuple_type = hana::tuple...>; + return detail::make_call_expression(std::move(*this), static_cast(u)...); + } + }; + + template + struct expression + { + using this_type = expression; + using tuple_type = hana::tuple; + + static const expr_kind kind = expr_kind::terminal; + + expression (T && t) : + elements (static_cast(t)) + {} + + expression (hana::tuple && rhs) : elements (std::move(rhs)) {}