2
0
mirror of https://github.com/boostorg/yap.git synced 2026-02-23 16:22:09 +00:00

Add customization points for plus and minus; sketch in placeholder support.

This commit is contained in:
Zach Laine
2016-11-03 21:08:39 -05:00
parent 30f12c154f
commit 31cb3b1716

View File

@@ -9,12 +9,13 @@
#include <iostream>
#include <cassert> // TODO: For testing.
#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 {
namespace boost::proto17 {
enum class expr_kind {
terminal,
@@ -32,6 +33,51 @@ namespace boost { namespace proto17 {
template <typename T>
using terminal = expression<expr_kind::terminal, T>;
#define BOOST_PROTO17_NOEXCEPT_DECLTYPE_RETURN(expr) \
noexcept(noexcept(expr)) -> decltype(expr) { return expr; }
namespace adl_detail {
template <typename T, typename U>
constexpr auto eval_plus (T && t, U && u) BOOST_PROTO17_NOEXCEPT_DECLTYPE_RETURN(
static_cast<T &&>(t) + static_cast<U &&>(u)
)
struct eval_plus_fn
{
template <typename T, typename U>
constexpr auto operator() (T && t, U && u) const BOOST_PROTO17_NOEXCEPT_DECLTYPE_RETURN(
eval_plus(static_cast<T &&>(t), static_cast<U &&>(u))
)
};
template <typename T, typename U>
constexpr auto eval_minus (T && t, U && u) BOOST_PROTO17_NOEXCEPT_DECLTYPE_RETURN(
static_cast<T &&>(t) - static_cast<U &&>(u)
)
struct eval_minus_fn
{
template <typename T, typename U>
constexpr auto operator() (T && t, U && u) const BOOST_PROTO17_NOEXCEPT_DECLTYPE_RETURN(
eval_minus(static_cast<T &&>(t), static_cast<U &&>(u))
)
};
}
#undef BOOST_PROTO17_NOEXCEPT_DECLTYPE_RETURN
using adl_detail::eval_plus_fn;
using adl_detail::eval_minus_fn;
inline namespace function_objects {
inline constexpr eval_plus_fn eval_plus{};
inline constexpr eval_minus_fn eval_minus{};
}
namespace detail {
template <typename T>
@@ -101,28 +147,53 @@ namespace boost { namespace proto17 {
constexpr bool is_hana_llong(hana::basic_type<hana::llong<I>>)
{ return true; };
// TODO: Fix.
template <typename Tuple, long long I>
auto get_tuple_element(Tuple && tuple, hana::tuple<hana::llong<I>>)
{ return hana::at_c<I>(tuple); };
template <typename Tuple, expr_kind Kind, typename ...T>
auto default_eval_expr (expression<Kind, T...> const & expr, Tuple && tuple)
{
using namespace hana::literals;
if constexpr (Kind == expr_kind::terminal) {
static_assert(sizeof...(T) == 1);
return expr.elements[0_c];
} else if constexpr (Kind == expr_kind::placeholder) {
static_assert(sizeof...(T) == 1);
// TODO: Fix.
return get_tuple_element(tuple, expr.elements);
} else if constexpr (Kind == expr_kind::plus) {
return
eval_plus(
default_eval_expr(expr.elements[0_c], static_cast<Tuple &&>(tuple)),
default_eval_expr(expr.elements[1_c], static_cast<Tuple &&>(tuple))
);
} else if constexpr (Kind == expr_kind::minus) {
return
eval_minus(
default_eval_expr(expr.elements[0_c], static_cast<Tuple &&>(tuple)),
default_eval_expr(expr.elements[1_c], static_cast<Tuple &&>(tuple))
);
} else {
assert(false && "Unhandled expr_kind in default_evaluate!");
return;
}
}
}
#if 0 // TODO
struct callable
{
auto operator() (TODO) const;
};
#endif
// TODO: Customization point.
// TODO: static assert/SFINAE std::is_callable<>
// TODO: static assert/SFINAE no placeholders
template <typename R, expr_kind Kind, typename ...T>
R evaluate_expression_as (expression<Kind, T...> const & expr)
{ return static_cast<R>(detail::default_eval_expr(expr, hana::tuple<>())); }
template <typename T>
constexpr bool is_terminal (hana::basic_type<T>)
{ return false; }
template <typename T>
constexpr bool is_terminal (hana::basic_type<expression<expr_kind::terminal, T>>)
{ return true; }
template <expr_kind Kind, typename T>
constexpr bool is_expression (hana::basic_type<T>)
{ return false; }
template <expr_kind Kind, typename ...T>
constexpr bool is_expression (hana::basic_type<expression<Kind, T...>>)
{ return true; }
// TODO: static assert/SFINAE std::is_callable<>
template <typename Expr, typename ...T>
auto evaluate (Expr const & expr, T && ...t)
{ return detail::default_eval_expr(expr, hana::make_tuple(static_cast<T &&>(t)...)); }
template <expr_kind Kind, typename ...T>
struct expression
@@ -152,6 +223,10 @@ namespace boost { namespace proto17 {
tuple_type elements;
template <typename R>
operator R ()
{ return evaluate_expression_as<R>(*this); }
template <typename U>
auto operator+ (U && rhs) const &
{
@@ -169,6 +244,24 @@ namespace boost { namespace proto17 {
hana::tuple<this_type, rhs_type>{std::move(*this), rhs_type{static_cast<U &&>(rhs)}}
};
}
template <typename U>
auto operator- (U && rhs) const &
{
using rhs_type = typename detail::rhs_type<U>::type;
return expression<expr_kind::minus, this_type, rhs_type>{
hana::tuple<this_type, rhs_type>{*this, rhs_type{static_cast<U &&>(rhs)}}
};
}
template <typename U>
auto operator- (U && rhs) &&
{
using rhs_type = typename detail::rhs_type<U>::type;
return expression<expr_kind::minus, this_type, rhs_type>{
hana::tuple<this_type, rhs_type>{std::move(*this), rhs_type{static_cast<U &&>(rhs)}}
};
}
};
template <long long I>
@@ -222,7 +315,7 @@ namespace boost { namespace proto17 {
switch (kind) {
case expr_kind::plus: return os << "+";
case expr_kind::minus: return os << "-";
// TODO
// TODO
default: return os << "** ERROR: UNKNOWN OPERATOR! **";
}
}
@@ -375,7 +468,7 @@ namespace boost { namespace proto17 {
}
} }
}
#include <string>
@@ -1223,6 +1316,163 @@ void print ()
#endif
}
void default_eval ()
{
term<double> unity{1.0};
int i_ = 42;
term<int &&> i{std::move(i_)};
bp17::expression<
bp17::expr_kind::minus,
term<double>,
term<int &&>
> expr = unity - std::move(i);
bp17::expression<
bp17::expr_kind::plus,
term<double>,
bp17::expression<
bp17::expr_kind::minus,
term<double>,
term<int &&>
>
> unevaluated_expr = unity + std::move(expr);
{
double result = unity;
std::cout << "unity=" << result << "\n"; // 1
}
{
double result = expr;
std::cout << "expr=" << result << "\n"; // -41
}
{
double result = unevaluated_expr;
std::cout << "unevaluated_expr=" << result << "\n"; // -40
}
{
double result = evaluate(unity, boost::hana::make_tuple(5, 6, 7));
std::cout << "evaluate(unity)=" << result << "\n"; // 1
}
{
double result = evaluate(expr, boost::hana::make_tuple());
std::cout << "evaluate(expr)=" << result << "\n"; // -41
}
{
double result = evaluate(unevaluated_expr, boost::hana::make_tuple(std::string("15")));
std::cout << "evaluate(unevaluated_expr)=" << result << "\n"; // -40
}
}
namespace test {
struct number
{
explicit operator double () const { return value; }
double value;
};
// User-defined binary-plus! With weird semantics!
inline auto eval_plus (number a, number b)
{ return number{a.value - b.value}; }
}
void eval ()
{
term<test::number> unity{{1.0}};
double d_ = 42.0;
term<test::number> i{{d_}};
bp17::expression<
bp17::expr_kind::plus,
term<test::number>,
term<test::number>
> expr = unity + std::move(i);
bp17::expression<
bp17::expr_kind::plus,
term<test::number>,
bp17::expression<
bp17::expr_kind::plus,
term<test::number>,
term<test::number>
>
> unevaluated_expr = unity + std::move(expr);
{
double result = unity;
std::cout << "unity=" << result << "\n"; // 1
}
{
double result = expr;
std::cout << "expr=" << result << "\n"; // -41
}
{
double result = unevaluated_expr;
std::cout << "unevaluated_expr=" << result << "\n"; // 42
}
{
double result = (double)evaluate(unity, boost::hana::make_tuple(5, 6, 7));
std::cout << "evaluate(unity)=" << result << "\n"; // 1
}
{
double result = (double)evaluate(expr, boost::hana::make_tuple());
std::cout << "evaluate(expr)=" << result << "\n"; // -41
}
{
double result = (double)evaluate(unevaluated_expr, boost::hana::make_tuple(std::string("15")));
std::cout << "evaluate(unevaluated_expr)=" << result << "\n"; // 42
}
}
#if 0
void placeholder_eval ()
{
using namespace boost::proto17::literals;
bp17::placeholder<2> p2 = 2_p;
int i_ = 42;
term<int> i{std::move(i_)};
bp17::expression<
bp17::expr_kind::plus,
bp17::placeholder<2>,
term<int>
> expr = p2 + std::move(i);
bp17::expression<
bp17::expr_kind::plus,
bp17::placeholder<2>,
bp17::expression<
bp17::expr_kind::plus,
bp17::placeholder<2>,
term<int>
>
> unevaluated_expr = p2 + std::move(expr);
{
double result = evaluate(p2, boost::hana::make_tuple(5, 6, 7));
std::cout << "evaluate(p2)=" << result << "\n"; // 7
}
{
double result = evaluate(expr, boost::hana::make_tuple(std::string("15"), 3, 1));
std::cout << "evaluate(expr)=" << result << "\n"; // 43
}
{
double result = evaluate(unevaluated_expr, boost::hana::make_tuple(std::string("15"), 2, 3));
std::cout << "evaluate(unevaluated_expr)=" << result << "\n"; // 48
}
}
#endif
int main ()
{
term_plus_x();
@@ -1235,6 +1485,13 @@ int main ()
print();
default_eval();
eval();
#if 0 // TODO: Fix.
placeholder_eval();
#endif
#if 0 // TODO
{
bp17::terminal<double> unity{1.0};