diff --git a/detail/default_eval.hpp b/detail/default_eval.hpp index 26a791f..22f9cf7 100644 --- a/detail/default_eval.hpp +++ b/detail/default_eval.hpp @@ -156,7 +156,7 @@ namespace boost::proto17 { template auto transform_nonterminal (Expr const & expr, Tuple && tuple, Transform && transform); - template > + template > struct default_transform_expression { auto operator() (Expr && expr, Transform && transform) @@ -164,7 +164,11 @@ namespace boost::proto17 { constexpr expr_kind kind = remove_cv_ref_t::kind; if constexpr (kind == expr_kind::expr_ref) { decltype(auto) ref = ::boost::proto17::value(expr); - default_transform_expression transformer; + default_transform_expression< + decltype(ref), + Transform, + detail::arity_of() + > transformer; return transformer(ref, static_cast(transform)); } else if constexpr (kind == expr_kind::terminal || kind == expr_kind::placeholder) { return static_cast(expr); @@ -186,10 +190,11 @@ namespace boost::proto17 { } }; - template + template struct default_transform_expression< Expr, Transform, + Arity, std::void_t()(std::declval()))> > { @@ -213,7 +218,7 @@ namespace boost::proto17 { static_cast(tuple), [&transform](auto && element) { using element_t = decltype(element); - default_transform_expression transformer; + default_transform_expression()> transformer; return transformer( static_cast(element), static_cast(transform) diff --git a/detail/expression.hpp b/detail/expression.hpp index a7a020e..019ef48 100644 --- a/detail/expression.hpp +++ b/detail/expression.hpp @@ -4,6 +4,7 @@ #include "../expression_fwd.hpp" #include +#include #include @@ -191,6 +192,142 @@ namespace boost::proto17 { U >::type; + enum class expr_arity { + invalid, + one, + two, + n + }; + + template + constexpr expr_arity arity_of () + { + switch (Kind) { + case expr_kind::expr_ref: + + case expr_kind::terminal: + case expr_kind::placeholder: + + // unary + case expr_kind::unary_plus: // + + case expr_kind::negate: // - + case expr_kind::dereference: // * + case expr_kind::complement: // ~ + case expr_kind::address_of: // & + case expr_kind::logical_not: // ! + case expr_kind::pre_inc: // ++ + case expr_kind::pre_dec: // -- + case expr_kind::post_inc: // ++(int) + case expr_kind::post_dec: // --(int) + return expr_arity::one; + + // binary + case expr_kind::shift_left: // << + case expr_kind::shift_right: // >> + case expr_kind::multiplies: // * + case expr_kind::divides: // / + case expr_kind::modulus: // % + case expr_kind::plus: // + + case expr_kind::minus: // - + case expr_kind::less: // < + case expr_kind::greater: // > + case expr_kind::less_equal: // <= + case expr_kind::greater_equal: // >= + case expr_kind::equal_to: // == + case expr_kind::not_equal_to: // != + case expr_kind::logical_or: // || + case expr_kind::logical_and: // && + case expr_kind::bitwise_and: // & + case expr_kind::bitwise_or: // | + case expr_kind::bitwise_xor: // ^ + case expr_kind::comma: // : + case expr_kind::mem_ptr: // ->* + case expr_kind::assign: // = + case expr_kind::shift_left_assign: // <<= + case expr_kind::shift_right_assign: // >>= + case expr_kind::multiplies_assign: // *= + case expr_kind::divides_assign: // /= + case expr_kind::modulus_assign: // %= + case expr_kind::plus_assign: // += + case expr_kind::minus_assign: // -= + case expr_kind::bitwise_and_assign: // &= + case expr_kind::bitwise_or_assign: // |= + case expr_kind::bitwise_xor_assign: // ^= + case expr_kind::subscript: // [] + return expr_arity::two; + + // n-ary + case expr_kind::call: // () + return expr_arity::n; + + default: + return expr_arity::invalid; + } + } + + template + constexpr auto tag_for () + { +#define CASE(x) if constexpr (Kind == expr_kind::x) return x ## _tag{} + + CASE(expr_ref); + + CASE(terminal); + CASE(placeholder); + + // unary + CASE(unary_plus); // + + CASE(negate); // - + CASE(dereference); // * + CASE(complement); // ~ + CASE(address_of); // & + CASE(logical_not); // ! + CASE(pre_inc); // ++ + CASE(pre_dec); // -- + CASE(post_inc); // ++(int) + CASE(post_dec); // --(int) + + // binary + CASE(shift_left); // << + CASE(shift_right); // >> + CASE(multiplies); // * + CASE(divides); // / + CASE(modulus); // % + CASE(plus); // + + CASE(minus); // - + CASE(less); // < + CASE(greater); // > + CASE(less_equal); // <= + CASE(greater_equal); // >= + CASE(equal_to); // == + CASE(not_equal_to); // != + CASE(logical_or); // || + CASE(logical_and); // && + CASE(bitwise_and); // & + CASE(bitwise_or); // | + CASE(bitwise_xor); // ^ + CASE(comma); // ); + CASE(mem_ptr); // ->* + CASE(assign); // = + CASE(shift_left_assign); // <<= + CASE(shift_right_assign); // >>= + CASE(multiplies_assign); // *= + CASE(divides_assign); // /= + CASE(modulus_assign); // %= + CASE(plus_assign); // += + CASE(minus_assign); // -= + CASE(bitwise_and_assign); // &= + CASE(bitwise_or_assign); // |= + CASE(bitwise_xor_assign); // ^= + CASE(subscript); // [] + + // n-ary + CASE(call); // () + +#undef CASE + }; + + } } diff --git a/expression.hpp b/expression.hpp index dd7d322..e49cdeb 100644 --- a/expression.hpp +++ b/expression.hpp @@ -295,7 +295,7 @@ namespace boost::proto17 { { using namespace hana::literals; static_assert( - decltype(hana::size(expr.elements))::value == 1UL, + detail::arity_of() == detail::expr_arity::one, "value() is only defined for unary expressions." ); if constexpr (Expr::kind == expr_kind::expr_ref) { @@ -310,7 +310,7 @@ namespace boost::proto17 { { using namespace hana::literals; static_assert( - decltype(hana::size(expr.elements))::value == 1UL, + detail::arity_of() == detail::expr_arity::one, "value() is only defined for unary expressions." ); if constexpr (Expr::kind == expr_kind::expr_ref) { @@ -325,7 +325,7 @@ namespace boost::proto17 { { using namespace hana::literals; static_assert( - decltype(hana::size(expr.elements))::value == 1UL, + detail::arity_of() == detail::expr_arity::one, "value() is only defined for unary expressions." ); if constexpr (Expr::kind == expr_kind::expr_ref) { @@ -340,7 +340,7 @@ namespace boost::proto17 { { using namespace hana::literals; static_assert( - decltype(hana::size(expr.elements))::value == 2UL, + detail::arity_of() == detail::expr_arity::two, "left() and right() are only defined for binary expressions." ); return expr.elements[0_c]; @@ -351,7 +351,7 @@ namespace boost::proto17 { { using namespace hana::literals; static_assert( - decltype(hana::size(expr.elements))::value == 2UL, + detail::arity_of() == detail::expr_arity::two, "left() and right() are only defined for binary expressions." ); return expr.elements[0_c]; @@ -362,7 +362,7 @@ namespace boost::proto17 { { using namespace hana::literals; static_assert( - decltype(hana::size(expr.elements))::value == 2UL, + detail::arity_of() == detail::expr_arity::two, "left() and right() are only defined for binary expressions." ); return std::move(expr.elements)[0_c]; @@ -373,7 +373,7 @@ namespace boost::proto17 { { using namespace hana::literals; static_assert( - decltype(hana::size(expr.elements))::value == 2UL, + detail::arity_of() == detail::expr_arity::two, "left() and right() are only defined for binary expressions." ); return expr.elements[1_c]; @@ -384,7 +384,7 @@ namespace boost::proto17 { { using namespace hana::literals; static_assert( - decltype(hana::size(expr.elements))::value == 2UL, + detail::arity_of() == detail::expr_arity::two, "left() and right() are only defined for binary expressions." ); return expr.elements[1_c]; @@ -395,7 +395,7 @@ namespace boost::proto17 { { using namespace hana::literals; static_assert( - decltype(hana::size(expr.elements))::value == 2UL, + detail::arity_of() == detail::expr_arity::two, "left() and right() are only defined for binary expressions." ); return std::move(expr.elements)[1_c]; @@ -516,7 +516,8 @@ namespace boost::proto17 { template auto transform (Expr && expr, Transform && transform) { - return detail::default_transform_expression{}( + constexpr expr_kind kind = detail::remove_cv_ref_t::kind; + return detail::default_transform_expression()>{}( static_cast(expr), static_cast(transform) ); diff --git a/expression_fwd.hpp b/expression_fwd.hpp index 3eb3da1..1d1cbff 100644 --- a/expression_fwd.hpp +++ b/expression_fwd.hpp @@ -120,6 +120,62 @@ namespace boost::proto17 { } + // Tag types -- one per expr_kind: + + struct expr_ref_tag {}; // TODO: Needed? + + struct terminal_tag {}; + struct placeholder_tag {}; + + // unary + struct unary_plus_tag {}; // + + struct negate_tag {}; // - + struct dereference_tag {}; // * + struct complement_tag {}; // ~ + struct address_of_tag {}; // & + struct logical_not_tag {}; // ! + struct pre_inc_tag {}; // ++ + struct pre_dec_tag {}; // -- + struct post_inc_tag {}; // ++(int) + struct post_dec_tag {}; // --(int) + + // binary + struct shift_left_tag {}; // << + struct shift_right_tag {}; // >> + struct multiplies_tag {}; // * + struct divides_tag {}; // / + struct modulus_tag {}; // % + struct plus_tag {}; // + + struct minus_tag {}; // - + struct less_tag {}; // < + struct greater_tag {}; // > + struct less_equal_tag {}; // <= + struct greater_equal_tag {}; // >= + struct equal_to_tag {}; // == + struct not_equal_to_tag {}; // != + struct logical_or_tag {}; // || + struct logical_and_tag {}; // && + struct bitwise_and_tag {}; // & + struct bitwise_or_tag {}; // | + struct bitwise_xor_tag {}; // ^ + struct comma_tag {}; // _tag {}; + struct mem_ptr_tag {}; // ->* + struct assign_tag {}; // = + struct shift_left_assign_tag {}; // <<= + struct shift_right_assign_tag {}; // >>= + struct multiplies_assign_tag {}; // *= + struct divides_assign_tag {}; // /= + struct modulus_assign_tag {}; // %= + struct plus_assign_tag {}; // += + struct minus_assign_tag {}; // -= + struct bitwise_and_assign_tag {}; // &= + struct bitwise_or_assign_tag {}; // |= + struct bitwise_xor_assign_tag {}; // ^= + struct subscript_tag {}; // [] + + // n-ary + struct call_tag {}; // () + } #endif