/////////////////////////////////////////////////////////////////////////////// | |
/// \file domain.hpp | |
/// Contains definition of domain\<\> class template and helpers for | |
/// defining domains with a generator and a grammar for controlling | |
/// operator overloading. | |
// | |
// Copyright 2008 Eric Niebler. Distributed under the Boost | |
// Software License, Version 1.0. (See accompanying file | |
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
#ifndef BOOST_PROTO_DOMAIN_HPP_EAN_02_13_2007 | |
#define BOOST_PROTO_DOMAIN_HPP_EAN_02_13_2007 | |
#include <boost/ref.hpp> | |
#include <boost/type_traits/is_same.hpp> | |
#include <boost/proto/proto_fwd.hpp> | |
#include <boost/proto/generate.hpp> | |
#include <boost/proto/detail/as_expr.hpp> | |
#include <boost/proto/detail/deduce_domain.hpp> | |
namespace boost { namespace proto | |
{ | |
namespace detail | |
{ | |
struct not_a_generator | |
{}; | |
struct not_a_grammar | |
{}; | |
struct not_a_domain | |
{}; | |
} | |
namespace domainns_ | |
{ | |
/// \brief For use in defining domain tags to be used | |
/// with \c proto::extends\<\>. A \e Domain associates | |
/// an expression type with a \e Generator, and optionally | |
/// a \e Grammar. | |
/// | |
/// The Generator determines how new expressions in the | |
/// domain are constructed. Typically, a generator wraps | |
/// all new expressions in a wrapper that imparts | |
/// domain-specific behaviors to expressions within its | |
/// domain. (See \c proto::extends\<\>.) | |
/// | |
/// The Grammar determines whether a given expression is | |
/// valid within the domain, and automatically disables | |
/// any operator overloads which would cause an invalid | |
/// expression to be created. By default, the Grammar | |
/// parameter defaults to the wildcard, \c proto::_, which | |
/// makes all expressions valid within the domain. | |
/// | |
/// The Super declares the domain currently being defined | |
/// to be a sub-domain of Super. Expressions in sub-domains | |
/// can be freely combined with expressions in its super- | |
/// domain (and <I>its</I> super-domain, etc.). | |
/// | |
/// Example: | |
/// \code | |
/// template<typename Expr> | |
/// struct MyExpr; | |
/// | |
/// struct MyGrammar | |
/// : or_< terminal<_>, plus<MyGrammar, MyGrammar> > | |
/// {}; | |
/// | |
/// // Define MyDomain, in which all expressions are | |
/// // wrapped in MyExpr<> and only expressions that | |
/// // conform to MyGrammar are allowed. | |
/// struct MyDomain | |
/// : domain<generator<MyExpr>, MyGrammar> | |
/// {}; | |
/// | |
/// // Use MyDomain to define MyExpr | |
/// template<typename Expr> | |
/// struct MyExpr | |
/// : extends<Expr, MyExpr<Expr>, MyDomain> | |
/// { | |
/// // ... | |
/// }; | |
/// \endcode | |
/// | |
template< | |
typename Generator // = default_generator | |
, typename Grammar // = proto::_ | |
, typename Super // = no_super_domain | |
> | |
struct domain | |
: Generator | |
{ | |
typedef Generator proto_generator; | |
typedef Grammar proto_grammar; | |
typedef Super proto_super_domain; | |
typedef domain proto_base_domain; | |
/// INTERNAL ONLY | |
typedef void proto_is_domain_; | |
/// \brief A unary MonomorphicFunctionObject that turns objects into Proto | |
/// expression objects in this domain. | |
/// | |
/// The <tt>as_expr\<\></tt> function object turns objects into Proto expressions, if | |
/// they are not already, by making them Proto terminals held by value if | |
/// possible. Objects that are already Proto expressions are left alone. | |
/// | |
/// If <tt>wants_basic_expr\<Generator\>::value</tt> is true, then let \c E be \c basic_expr; | |
/// otherwise, let \t E be \c expr. Given an lvalue \c t of type \c T: | |
/// | |
/// If \c T is not a Proto expression type the resulting terminal is | |
/// calculated as follows: | |
/// | |
/// If \c T is a function type, an abstract type, or a type derived from | |
/// \c std::ios_base, let \c A be <tt>T &</tt>. | |
/// Otherwise, let \c A be the type \c T stripped of cv-qualifiers. | |
/// Then, the result of applying <tt>as_expr\<T\>()(t)</tt> is | |
/// <tt>Generator()(E\<tag::terminal, term\<A\> \>::make(t))</tt>. | |
/// | |
/// If \c T is a Proto expression type and its generator type is different from | |
/// \c Generator, the result is <tt>Generator()(t)</tt>. | |
/// | |
/// Otherwise, the result is \c t converted to an (un-const) rvalue. | |
/// | |
template<typename T, typename IsExpr = void, typename Callable = proto::callable> | |
struct as_expr | |
: detail::as_expr< | |
T | |
, typename detail::base_generator<Generator>::type | |
, wants_basic_expr<Generator>::value | |
> | |
{ | |
BOOST_PROTO_CALLABLE() | |
}; | |
/// INTERNAL ONLY | |
/// | |
template<typename T> | |
struct as_expr<T, typename T::proto_is_expr_, proto::callable> | |
{ | |
BOOST_PROTO_CALLABLE() | |
typedef typename remove_const<T>::type result_type; | |
result_type operator()(T &e) const | |
{ | |
return e; | |
} | |
}; | |
/// \brief A unary MonomorphicFunctionObject that turns objects into Proto | |
/// expression objects in this domain. | |
/// | |
/// The <tt>as_child\<\></tt> function object turns objects into Proto expressions, if | |
/// they are not already, by making them Proto terminals held by reference. | |
/// Objects that are already Proto expressions are simply returned by reference. | |
/// | |
/// If <tt>wants_basic_expr\<Generator\>::value</tt> is true, then let \c E be \c basic_expr; | |
/// otherwise, let \t E be \c expr. Given an lvalue \c t of type \c T: | |
/// | |
/// If \c T is not a Proto expression type the resulting terminal is | |
/// <tt>Generator()(E\<tag::terminal, term\<T &\> \>::make(t))</tt>. | |
/// | |
/// If \c T is a Proto expression type and its generator type is different from | |
/// \c Generator, the result is <tt>Generator()(t)</tt>. | |
/// | |
/// Otherwise, the result is the lvalue \c t. | |
/// | |
template<typename T, typename IsExpr = void, typename Callable = proto::callable> | |
struct as_child | |
: detail::as_child< | |
T | |
, typename detail::base_generator<Generator>::type | |
, wants_basic_expr<Generator>::value | |
> | |
{ | |
BOOST_PROTO_CALLABLE() | |
}; | |
/// INTERNAL ONLY | |
/// | |
template<typename T> | |
struct as_child<T, typename T::proto_is_expr_, proto::callable> | |
{ | |
BOOST_PROTO_CALLABLE() | |
typedef T &result_type; | |
result_type operator()(T &e) const | |
{ | |
return e; | |
} | |
}; | |
}; | |
/// \brief The domain expressions have by default, if | |
/// \c proto::extends\<\> has not been used to associate | |
/// a domain with an expression. | |
/// | |
struct default_domain | |
: domain<> | |
{}; | |
/// \brief A pseudo-domain for use in functions and | |
/// metafunctions that require a domain parameter. It | |
/// indicates that the domain of the parent node should | |
/// be inferred from the domains of the child nodes. | |
/// | |
/// \attention \c deduce_domain is not itself a valid domain. | |
/// | |
struct deduce_domain | |
: domain<detail::not_a_generator, detail::not_a_grammar, detail::not_a_domain> | |
{}; | |
/// \brief Given a domain, a tag type and an argument list, | |
/// compute the type of the expression to generate. This is | |
/// either an instance of \c proto::expr\<\> or | |
/// \c proto::basic_expr\<\>. | |
/// | |
template<typename Domain, typename Tag, typename Args, bool WantsBasicExpr> | |
struct base_expr | |
{ | |
typedef proto::expr<Tag, Args, Args::arity> type; | |
}; | |
/// INTERNAL ONLY | |
/// | |
template<typename Domain, typename Tag, typename Args> | |
struct base_expr<Domain, Tag, Args, true> | |
{ | |
typedef proto::basic_expr<Tag, Args, Args::arity> type; | |
}; | |
} | |
/// A metafunction that returns \c mpl::true_ | |
/// if the type \c T is the type of a Proto domain; | |
/// \c mpl::false_ otherwise. If \c T inherits from | |
/// \c proto::domain\<\>, \c is_domain\<T\> is | |
/// \c mpl::true_. | |
template<typename T, typename Void /* = void*/> | |
struct is_domain | |
: mpl::false_ | |
{}; | |
/// INTERNAL ONLY | |
/// | |
template<typename T> | |
struct is_domain<T, typename T::proto_is_domain_> | |
: mpl::true_ | |
{}; | |
/// A metafunction that returns the domain of | |
/// a given type. If \c T is a Proto expression | |
/// type, it returns that expression's associated | |
/// domain. If not, it returns | |
/// \c proto::default_domain. | |
template<typename T, typename Void /* = void*/> | |
struct domain_of | |
{ | |
typedef default_domain type; | |
}; | |
/// INTERNAL ONLY | |
/// | |
template<typename T> | |
struct domain_of<T, typename T::proto_is_expr_> | |
{ | |
typedef typename T::proto_domain type; | |
}; | |
/// INTERNAL ONLY | |
/// | |
template<typename T> | |
struct domain_of<T &, void> | |
{ | |
typedef typename domain_of<T>::type type; | |
}; | |
/// INTERNAL ONLY | |
/// | |
template<typename T> | |
struct domain_of<boost::reference_wrapper<T>, void> | |
{ | |
typedef typename domain_of<T>::type type; | |
}; | |
/// INTERNAL ONLY | |
/// | |
template<typename T> | |
struct domain_of<boost::reference_wrapper<T> const, void> | |
{ | |
typedef typename domain_of<T>::type type; | |
}; | |
/// A metafunction that returns \c mpl::true_ | |
/// if the type \c SubDomain is a sub-domain of | |
/// \c SuperDomain; \c mpl::false_ otherwise. | |
template<typename SubDomain, typename SuperDomain> | |
struct is_sub_domain_of | |
: is_sub_domain_of<typename SubDomain::proto_super_domain, SuperDomain> | |
{}; | |
/// INTERNAL ONLY | |
/// | |
template<typename SuperDomain> | |
struct is_sub_domain_of<proto::no_super_domain, SuperDomain> | |
: mpl::false_ | |
{}; | |
/// INTERNAL ONLY | |
/// | |
template<typename SuperDomain> | |
struct is_sub_domain_of<SuperDomain, SuperDomain> | |
: mpl::true_ | |
{}; | |
}} | |
#endif |