[Proto] Extracting types of sub-expression in transform

Hello, i have a DSL where terminal are defined like : terminal< simd<proto::_> > What I want is that any binary operator that apply on those terminal should be available only if both lhs and rhs parts have the same underlying type. E.G : simd<float> + simd<float> is ok while (simd<char> + simd<char>)*simd<float> is not ok. How I can enforce this check ? Is having a transform that take an expression and returns the underlying type OR mpl::void_ if an error occurs the good solution ? Thanks in advance -- ___________________________________________ Joel Falcou - Assistant Professor PARALL Team - LRI - Universite Paris Sud XI Tel : (+33)1 69 15 66 35

Joel Falcou wrote:
Hello,
i have a DSL where terminal are defined like : terminal< simd<proto::_> > What I want is that any binary operator that apply on those terminal should be available only if both lhs and rhs parts have the same underlying type. E.G :
simd<float> + simd<float> is ok while (simd<char> + simd<char>)*simd<float> is not ok.
How I can enforce this check ? Is having a transform that take an expression and returns the underlying type OR mpl::void_ if an error occurs the good solution ?
This question has come up a couple of times. The solution isn't very pretty ... write a grammar that allows expressions with incompatible terminals, and then write a separate transform that checks the terminals for compatibility. This issue came up during Proto's review and I posted some example code here (see the SameTerminals transform): http://lists.boost.org/Archives/boost/2008/03/135169.php I wish I knew of a better solution. -- Eric Niebler BoostPro Computing http://www.boostpro.com

Eric Niebler a écrit :
This question has come up a couple of times. The solution isn't very pretty ... write a grammar that allows expressions with incompatible terminals, and then write a separate transform that checks the terminals for compatibility. This issue came up during Proto's review and I posted some example code here (see the SameTerminals transform): Well I thought to have template grammar ;) aka :
template<class T> struct simd_grammar : terminal< simd<T> > .... {}; Then vec<T> extends a domain which is based on simd_grammar<T>. Not sure it's more elegant though. I'll dig this during the week. -- ___________________________________________ Joel Falcou - Assistant Professor PARALL Team - LRI - Universite Paris Sud XI Tel : (+33)1 69 15 66 35

Joel Falcou wrote:
Eric Niebler a écrit :
This question has come up a couple of times. The solution isn't very pretty ... write a grammar that allows expressions with incompatible terminals, and then write a separate transform that checks the terminals for compatibility. This issue came up during Proto's review and I posted some example code here (see the SameTerminals transform): Well I thought to have template grammar ;) aka :
template<class T> struct simd_grammar : terminal< simd<T> > .... {};
Then vec<T> extends a domain which is based on simd_grammar<T>. Not sure it's more elegant though. I'll dig this during the week.
Ah, well that's a clever thought. Here's some code to get you started ... #include <boost/proto/proto.hpp> namespace mpl = boost::mpl; namespace proto = boost::proto; using proto::_; template<typename T> struct simd {}; template<typename T> struct simd_grammar : proto::or_< proto::terminal<simd<T> > , proto::nary_expr<_, proto::vararg<simd_grammar<T> > > > {}; template<typename Expr, typename T> struct simd_expr; template<typename T> struct simd_generator { template<typename Sig> struct result; template<typename This, typename Expr> struct result<This(Expr)> { typedef simd_expr<Expr, T> type; }; template<typename Expr> simd_expr<Expr, T> const operator()(Expr const &expr) const { simd_expr<Expr, T> that = {expr}; return that; } }; template<typename T> struct simd_domain : proto::domain<simd_generator<T>, simd_grammar<T> > {}; template<typename Expr, typename T> struct simd_expr { BOOST_PROTO_EXTENDS(Expr, simd_expr, simd_domain<T>) }; simd_expr<proto::terminal<simd<char> >::type, char> const simd_char = {{{}}}; simd_expr<proto::terminal<simd<int> >::type, int> const simd_int = {{{}}}; int main() { (simd_char + simd_char) * simd_char; (simd_int + simd_int) * simd_int; // ERROR, these are in different domains // (simd_char + simd_char) * simd_int; } -- Eric Niebler BoostPro Computing http://www.boostpro.com

Neat code indeed. What's the simd_generator class ? a context or something I miss ?

Joel Falcou wrote:
Neat code indeed. What's the simd_generator class ? a context or something I miss ?
Used as the first parameter to the domain<> template. I would have used proto::pod_generator<simd_expr>, except that the pod_generator<> template accepts only class templates with one parameter, and simd_expr has two. See the section in the docs on generators ... they're just function objects that return wrapped Proto expression objects. -- Eric Niebler BoostPro Computing http://www.boostpro.com

Eric Niebler a écrit :
Used as the first parameter to the domain<> template. I would have used proto::pod_generator<simd_expr>, except that the pod_generator<> template accepts only class templates with one parameter, and simd_expr has two. See the section in the docs on generators ... they're just function objects that return wrapped Proto expression objects.
Was browsing the doc right now ;) And now I see the problem with the classic generator. Thansk for the head up. I'll flesh this up and see how it goes. Thanks again -- ___________________________________________ Joel Falcou - Assistant Professor PARALL Team - LRI - Universite Paris Sud XI Tel : (+33)1 69 15 66 35
participants (3)
-
Eric Niebler
-
Eric Niebler
-
Joel Falcou