#include #include #include #include // For printing #include #include #include #define BOOST_PROTO17_STREAM_OPERATORS // TODO: For testing. // TODO: Verbose debugging mode for matching. // TODO: Proto-style "Fuzzy and Exact Matches of Terminals". namespace boost { namespace proto17 { enum class expr_kind { terminal, plus, minus, // etc... }; template struct expression; template struct terminal; namespace detail { template struct partial_decay { using type = T; }; template struct partial_decay { using type = T *; }; template struct partial_decay { using type = T *; }; template struct partial_decay { using type = T *; }; template struct partial_decay { using type = T *; }; template struct partial_decay { using type = R(*)(A...); }; template struct partial_decay { using type = R(*)(A..., ...); }; template ::type, bool AddRValueRef = std::is_same_v && !std::is_const_v> struct rhs_value_type_phase_1; template struct rhs_value_type_phase_1 { using type = U &&; }; template struct rhs_value_type_phase_1 { using type = U; }; template struct is_term { static bool const value = false; }; template struct is_term> { static bool const value = true; }; template struct is_expr { static bool const value = false; }; template struct is_expr> { static bool const value = true; }; template ::type, bool RemoveRefs = std::is_rvalue_reference_v, bool IsTermOrExpr = is_term>::value || is_expr>::value> struct rhs_type; template struct rhs_type { using type = T; }; template struct rhs_type { using type = terminal>; }; template struct rhs_type { using type = terminal; }; } #if 0 // TODO struct callable { auto operator() (TODO) const; }; #endif // TODO: May be a Callable. template struct terminal { T value; template auto operator+ (U && rhs) & { using rhs_type = typename detail::rhs_type::type; return expression &, rhs_type>{ hana::tuple &, rhs_type>{*this, rhs_type{static_cast(rhs)}} }; } template auto operator+ (U && rhs) const & { using rhs_type = typename detail::rhs_type::type; return expression const &, rhs_type>{ hana::tuple const &, rhs_type>{*this, rhs_type{static_cast(rhs)}} }; } template auto operator+ (U && rhs) && { using rhs_type = typename detail::rhs_type::type; return expression, rhs_type>{ hana::tuple, rhs_type>{ std::move(*this), rhs_type{static_cast(rhs)} } }; } }; template constexpr bool is_terminal (hana::basic_type) { return false; } template constexpr bool is_terminal (hana::basic_type>) { return true; } template constexpr bool is_expression (hana::basic_type) { return false; } template constexpr bool is_expression (hana::basic_type>) { return true; } template struct expression { static const expr_kind kind = Kind; hana::tuple elements; }; template struct placeholder : hana::llong {}; namespace literals { template constexpr auto operator"" _p () { return placeholder({c...})>{}; } } namespace match { template struct expression { KindMatches kind_matches; hana::tuple elements; }; // TODO: Use this to detect identical types within a match. template struct placeholder : hana::llong {}; } template constexpr bool is_match_expression (hana::basic_type) { return false; } template constexpr bool is_match_expression (hana::basic_type>) { return true; } namespace literals { template constexpr auto operator"" _T () { return match::placeholder({c...})>{}; } } namespace detail { inline std::ostream & print_impl (std::ostream & os, expr_kind kind) { switch (kind) { case expr_kind::plus: return os << "+"; case expr_kind::minus: return os << "-"; // TODO default: return os << "** ERROR: UNKNOWN OPERATOR! **"; } } template auto print_object (std::ostream & os, T const & x) -> decltype(os << x) { return os << x; } inline std::ostream & print_object (std::ostream & os, ...) { return os << "<>"; } template std::ostream & print_type (std::ostream & os) { os << typeindex::type_id().pretty_name(); if (std::is_const_v) os << " const"; if (std::is_volatile_v) os << " volatile"; using no_cv_t = std::remove_cv_t; if (std::is_lvalue_reference_v) os << " &"; if (std::is_rvalue_reference_v) os << " &&"; return os; } template std::ostream & print_impl ( std::ostream & os, terminal const & term, int indent, char const * indent_str) { for (int i = 0; i < indent; ++i) { os << indent_str; } os << "term<"; print_type(os); os << ">[="; print_object(os, term.value); os << "]\n"; return os; } template std::ostream & print_impl ( std::ostream & os, expression const & expr, int indent, char const * indent_str) { if constexpr (Kind == expr_kind::terminal) { using namespace hana::literals; static_assert(hana::size(expr.elements) == 1_c, ""); static_assert(is_terminal(hana::typeid_(expr.elements[0_c])), ""); print_impl(os, expr.elements[0_c]); } else { for (int i = 0; i < indent; ++i) { os << indent_str; } os << "expr<"; print_impl(os, Kind); os << ">\n"; hana::for_each(expr.elements, [&os, indent, indent_str](auto const & element) { print_impl(os, element, indent + 1, indent_str); }); } return os; } } template std::ostream & print (std::ostream & os, terminal const & term) { return detail::print_impl(os, term, 0, " "); } template std::ostream & print (std::ostream & os, expression const & expr) { return detail::print_impl(os, expr, 0, " "); } #if defined(BOOST_PROTO17_STREAM_OPERATORS) template std::ostream & operator<< (std::ostream & os, terminal const & term) { return detail::print_impl(os, term, 0, " "); } template std::ostream & operator<< (std::ostream & os, expression const & expr) { return detail::print_impl(os, expr, 0, " "); } #endif namespace detail { inline bool matches (...) { return false; } template bool matches (MatchExpr const & match_subtree, TreeExpr const & subtree); template void recursive_match_impl (MatchExpr const & match_subtree, TreeExpr const & subtree, bool & result) { if (!matches(match_subtree[hana::size_c], subtree[hana::size_c])) { result = false; } if constexpr (0 < I) { recursive_match_impl(match_subtree, subtree, result); } } template bool matches (MatchExpr const & match_subtree, TreeExpr const & subtree) { static_assert(is_match_expression(hana::typeid_(match_subtree)), "Attempted to use a non-tree as a match expression."); static_assert(is_expression(hana::typeid_(subtree)), "Attempted to use find a match in a non-tree."); // TODO: Verbose mode. if (!match_subtree.kind_matches(subtree)) { return false; } else { auto constexpr subtree_size = hana::size(subtree.elements); if constexpr (hana::size(match_subtree.elements) != subtree_size) { // TODO: Verbose mode. return false; } else { bool children_match = true; recursive_match_impl( match_subtree.elements, subtree.elements, children_match ); return children_match; } } } template auto mutate_subtrees_of ( Matcher const & match_subtree, expression & tree, Callable && mutation ) { // TODO: Process children first. if (matches(match_subtree, tree)) { return mutation(tree); } else if (Kind == expr_kind::terminal) { return tree; } else { auto mutate_child = [&match_subtree, &mutation] (auto & t) { return mutate_subtrees_of(match_subtree, t, static_cast(mutation)); }; auto return_elements = hana::transform(tree.elements, mutate_child); return make_expression(Kind, std::move(return_elements)); } } } } } #include template using term = boost::proto17::terminal; namespace bp17 = boost::proto17; using namespace std::string_literals; void term_plus_x () { // char const * string { term unity{1.0}; bp17::expression< bp17::expr_kind::plus, term &, term > unevaluated_expr = unity + "3"; } // std::string temporary { term unity{1.0}; bp17::expression< bp17::expr_kind::plus, term &, term > unevaluated_expr = unity + "3"s; } // arrays { term unity{1.0}; int ints[] = {1, 2}; bp17::expression< bp17::expr_kind::plus, term &, term > unevaluated_expr = unity + ints; } { term unity{1.0}; int const ints[] = {1, 2}; bp17::expression< bp17::expr_kind::plus, term &, term > unevaluated_expr = unity + ints; } { term unity{1.0}; int ints[] = {1, 2}; bp17::expression< bp17::expr_kind::plus, term &, term > unevaluated_expr = unity + std::move(ints); } // pointers { term unity{1.0}; int ints[] = {1, 2}; int * int_ptr = ints; bp17::expression< bp17::expr_kind::plus, term &, term > unevaluated_expr = unity + int_ptr; } { term unity{1.0}; int const ints[] = {1, 2}; int const * int_ptr = ints; bp17::expression< bp17::expr_kind::plus, term &, term > unevaluated_expr = unity + int_ptr; } { term unity{1.0}; int ints[] = {1, 2}; int * int_ptr = ints; bp17::expression< bp17::expr_kind::plus, term &, term > unevaluated_expr = unity + std::move(int_ptr); } // const pointers { term unity{1.0}; int ints[] = {1, 2}; int * const int_ptr = ints; bp17::expression< bp17::expr_kind::plus, term &, term > unevaluated_expr = unity + int_ptr; } { term unity{1.0}; int const ints[] = {1, 2}; int const * const int_ptr = ints; bp17::expression< bp17::expr_kind::plus, term &, term > unevaluated_expr = unity + int_ptr; } { term unity{1.0}; int ints[] = {1, 2}; int * const int_ptr = ints; bp17::expression< bp17::expr_kind::plus, term &, term > unevaluated_expr = unity + std::move(int_ptr); } // values { term unity{1.0}; int i = 1; bp17::expression< bp17::expr_kind::plus, term &, term > unevaluated_expr = unity + i; } { term unity{1.0}; int const i = 1; bp17::expression< bp17::expr_kind::plus, term &, term > unevaluated_expr = unity + i; } { term unity{1.0}; int i = 1; bp17::expression< bp17::expr_kind::plus, term &, term > unevaluated_expr = unity + std::move(i); } } void term_plus_x_this_ref_overloads() { { term unity{1.0}; int i = 1; bp17::expression< bp17::expr_kind::plus, term &, term > unevaluated_expr = unity + i; } { term const unity{1.0}; int i = 1; bp17::expression< bp17::expr_kind::plus, term const &, term > unevaluated_expr = unity + i; } { term unity{1.0}; int i = 1; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = std::move(unity) + i; } } void term_plus_term () { // char const * string { term unity{1.0}; bp17::expression< bp17::expr_kind::plus, term &, term > unevaluated_expr = unity + term{"3"}; } // std::string temporary { term unity{1.0}; bp17::expression< bp17::expr_kind::plus, term &, term > unevaluated_expr = unity + term{"3"s}; } // pointers { term unity{1.0}; int ints_[] = {1, 2}; term ints = {ints_}; bp17::expression< bp17::expr_kind::plus, term &, term & > unevaluated_expr = unity + ints; } { term unity{1.0}; int const ints_[] = {1, 2}; term ints = {ints_}; bp17::expression< bp17::expr_kind::plus, term &, term & > unevaluated_expr = unity + ints; } { term unity{1.0}; int ints_[] = {1, 2}; term ints = {ints_}; bp17::expression< bp17::expr_kind::plus, term &, term > unevaluated_expr = unity + std::move(ints); } // const pointers { term unity{1.0}; int ints[] = {1, 2}; term int_ptr = {ints}; bp17::expression< bp17::expr_kind::plus, term &, term & > unevaluated_expr = unity + int_ptr; } { term unity{1.0}; int const ints[] = {1, 2}; term int_ptr = {ints}; bp17::expression< bp17::expr_kind::plus, term &, term & > unevaluated_expr = unity + int_ptr; } { term unity{1.0}; int ints[] = {1, 2}; term int_ptr = {ints}; bp17::expression< bp17::expr_kind::plus, term &, term > unevaluated_expr = unity + std::move(int_ptr); } // values { term unity{1.0}; term i = {1}; bp17::expression< bp17::expr_kind::plus, term &, term & > unevaluated_expr = unity + i; } { term unity{1.0}; term i = {1}; bp17::expression< bp17::expr_kind::plus, term &, term & > unevaluated_expr = unity + i; } { term unity{1.0}; term i = {1}; bp17::expression< bp17::expr_kind::plus, term &, term > unevaluated_expr = unity + std::move(i); } // const value terminals { term unity{1.0}; term const i = {1}; bp17::expression< bp17::expr_kind::plus, term &, term const & > unevaluated_expr = unity + i; } { term unity{1.0}; term const i = {1}; bp17::expression< bp17::expr_kind::plus, term &, term const & > unevaluated_expr = unity + i; } // lvalue refs { term unity{1.0}; int i_ = 1; term i{i_}; bp17::expression< bp17::expr_kind::plus, term &, term & > unevaluated_expr = unity + i; } { term unity{1.0}; int i_ = 1; term i{i_}; bp17::expression< bp17::expr_kind::plus, term &, term & > unevaluated_expr = unity + i; } { term unity{1.0}; int i_ = 1; term i{i_}; bp17::expression< bp17::expr_kind::plus, term &, term > unevaluated_expr = unity + std::move(i); } // rvalue refs { term unity{1.0}; int i_ = 1; term i{std::move(i_)}; bp17::expression< bp17::expr_kind::plus, term &, term & > unevaluated_expr = unity + i; } { term unity{1.0}; int i_ = 1; term i{std::move(i_)}; bp17::expression< bp17::expr_kind::plus, term &, term > unevaluated_expr = unity + std::move(i); } } void term_plus_expr () { // values { term unity{1.0}; term i = {1}; bp17::expression< bp17::expr_kind::plus, term &, term & > expr = unity + i; bp17::expression< bp17::expr_kind::plus, term &, bp17::expression< bp17::expr_kind::plus, term &, term & > & > unevaluated_expr = unity + expr; } { term unity{1.0}; term i = {1}; bp17::expression< bp17::expr_kind::plus, term &, term & > expr = unity + i; bp17::expression< bp17::expr_kind::plus, term &, bp17::expression< bp17::expr_kind::plus, term &, term & > & > unevaluated_expr = unity + expr; } { term unity{1.0}; term i = {1}; bp17::expression< bp17::expr_kind::plus, term &, term > expr = unity + std::move(i); bp17::expression< bp17::expr_kind::plus, term &, bp17::expression< bp17::expr_kind::plus, term &, term > & > unevaluated_expr = unity + expr; } // const value terminals/expressions { term unity{1.0}; term const i = {1}; bp17::expression< bp17::expr_kind::plus, term &, term const & > const expr = unity + i; bp17::expression< bp17::expr_kind::plus, term &, bp17::expression< bp17::expr_kind::plus, term &, term const & > const & > unevaluated_expr = unity + expr; } { term unity{1.0}; term i = {1}; bp17::expression< bp17::expr_kind::plus, term &, term & > const expr = unity + i; bp17::expression< bp17::expr_kind::plus, term &, bp17::expression< bp17::expr_kind::plus, term &, term & > const & > unevaluated_expr = unity + expr; } // lvalue refs { term unity{1.0}; int i_ = 1; term i{i_}; bp17::expression< bp17::expr_kind::plus, term &, term & > expr = unity + i; bp17::expression< bp17::expr_kind::plus, term &, bp17::expression< bp17::expr_kind::plus, term &, term & > & > unevaluated_expr = unity + expr; } { term unity{1.0}; int i_ = 1; term i{i_}; bp17::expression< bp17::expr_kind::plus, term &, term & > expr = unity + i; bp17::expression< bp17::expr_kind::plus, term &, bp17::expression< bp17::expr_kind::plus, term &, term & > & > unevaluated_expr = unity + expr; } { term unity{1.0}; int i_ = 1; term i{i_}; bp17::expression< bp17::expr_kind::plus, term &, term > expr = unity + std::move(i); bp17::expression< bp17::expr_kind::plus, term &, bp17::expression< bp17::expr_kind::plus, term &, term > & > unevaluated_expr = unity + expr; } { term unity{1.0}; int i_ = 1; term i{i_}; bp17::expression< bp17::expr_kind::plus, term &, term & > expr = unity + i; bp17::expression< bp17::expr_kind::plus, term &, bp17::expression< bp17::expr_kind::plus, term &, term & > > unevaluated_expr = unity + std::move(expr); } { term unity{1.0}; int i_ = 1; term i{i_}; bp17::expression< bp17::expr_kind::plus, term &, term & > expr = unity + i; bp17::expression< bp17::expr_kind::plus, term &, bp17::expression< bp17::expr_kind::plus, term &, term & > > unevaluated_expr = unity + std::move(expr); } { term unity{1.0}; int i_ = 1; term i{i_}; bp17::expression< bp17::expr_kind::plus, term &, term > expr = unity + std::move(i); bp17::expression< bp17::expr_kind::plus, term &, bp17::expression< bp17::expr_kind::plus, term &, term > > unevaluated_expr = unity + std::move(expr); } // rvalue refs { term unity{1.0}; int i_ = 1; term i{std::move(i_)}; bp17::expression< bp17::expr_kind::plus, term &, term & > expr = unity + i; bp17::expression< bp17::expr_kind::plus, term &, bp17::expression< bp17::expr_kind::plus, term &, term & > & > unevaluated_expr = unity + expr; } { term unity{1.0}; int i_ = 1; term i{std::move(i_)}; bp17::expression< bp17::expr_kind::plus, term &, term > expr = unity + std::move(i); bp17::expression< bp17::expr_kind::plus, term &, bp17::expression< bp17::expr_kind::plus, term &, term > & > unevaluated_expr = unity + expr; } { term unity{1.0}; int i_ = 1; term i{std::move(i_)}; bp17::expression< bp17::expr_kind::plus, term &, term & > expr = unity + i; bp17::expression< bp17::expr_kind::plus, term &, bp17::expression< bp17::expr_kind::plus, term &, term & > > unevaluated_expr = unity + std::move(expr); } { term unity{1.0}; int i_ = 1; term i{std::move(i_)}; bp17::expression< bp17::expr_kind::plus, term &, term > expr = unity + std::move(i); bp17::expression< bp17::expr_kind::plus, term &, bp17::expression< bp17::expr_kind::plus, term &, term > > unevaluated_expr = unity + std::move(expr); } } void print () { term unity{1.0}; int i_ = 42; term i{std::move(i_)}; bp17::expression< bp17::expr_kind::plus, term &, term > expr = unity + std::move(i); bp17::expression< bp17::expr_kind::plus, term &, bp17::expression< bp17::expr_kind::plus, term &, term > > unevaluated_expr = unity + std::move(expr); bp17::print(std::cout, unity); bp17::print(std::cout, expr); bp17::print(std::cout, unevaluated_expr); struct thing {}; term a_thing{{}}; bp17::print(std::cout, a_thing); #if defined(BOOST_PROTO17_STREAM_OPERATORS) std::cout << unity; std::cout << expr; std::cout << unevaluated_expr; std::cout << a_thing; #endif } int main () { term_plus_x(); term_plus_x_this_ref_overloads(); term_plus_term(); term_plus_expr(); print(); #if 0 // TODO { bp17::terminal unity{1.0}; auto unevaluated_expr = unity + "3"; auto mutated_expr = mutate(unevaluated_expr, match_expr, mutation); auto result = bp17::eval(unevaluated_expr); } { bp17::terminal a{1.0}; bp17::terminal x{2.0}; bp17::terminal b{3}; auto unevaluated_expr = a * x + b; auto match_expr = 0_T * 0_T + 1_T; auto mutated_expr = mutate(unevaluated_expr, match_expr, mutation); auto result = bp17::eval(mutated_expr); } { bp17::terminal a{1.0}; bp17::terminal x{2.0}; bp17::terminal b{3}; auto match_double_2 = [] (auto && terminal) { if constexpr (hana::typeid_(terminal) == hana::type{}) return terminal == 2.0; else return false; }; auto unevaluated_expr = a * x + b; auto match_expr = bp17::match * match_double_2 + 0_T; auto mutated_expr = mutate(unevaluated_expr, match_expr, mutation); auto result = bp17::eval(mutated_expr); } #endif }