// Copyright (c) 2001-2011 Hartmut Kaiser | |
// Copyright (c) 2001-2011 Joel de Guzman | |
// | |
// 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) | |
#if !defined(SPIRIT_QI_DETAIL_ATTRIBUTES_APR_18_2010_0458PM) | |
#define SPIRIT_QI_DETAIL_ATTRIBUTES_APR_18_2010_0458PM | |
#include <boost/spirit/home/qi/domain.hpp> | |
#include <boost/spirit/home/support/attributes_fwd.hpp> | |
#include <boost/spirit/home/support/attributes.hpp> | |
/////////////////////////////////////////////////////////////////////////////// | |
namespace boost { namespace spirit { namespace qi | |
{ | |
template <typename Exposed, typename Transformed> | |
struct default_transform_attribute | |
{ | |
typedef Transformed type; | |
static Transformed pre(Exposed& val) { return Transformed(); } | |
static void post(Exposed& val, Transformed const& attr) | |
{ | |
traits::assign_to(attr, val); | |
} | |
// fail() will be called by Qi rule's if the rhs failed parsing | |
static void fail(Exposed&) {} | |
}; | |
// handle case where no transformation is required as the types are the same | |
template <typename Attribute> | |
struct default_transform_attribute<Attribute, Attribute> | |
{ | |
typedef Attribute& type; | |
static Attribute& pre(Attribute& val) { return val; } | |
static void post(Attribute&, Attribute const&) {} | |
static void fail(Attribute&) {} | |
}; | |
template <typename Exposed, typename Transformed> | |
struct proxy_transform_attribute | |
{ | |
typedef Transformed type; | |
static Transformed pre(Exposed& val) { return Transformed(val); } | |
static void post(Exposed& val, Transformed const& attr) { /* no-op */ } | |
// fail() will be called by Qi rule's if the rhs failed parsing | |
static void fail(Exposed&) {} | |
}; | |
// handle case where no transformation is required as the types are the same | |
template <typename Attribute> | |
struct proxy_transform_attribute<Attribute, Attribute> | |
{ | |
typedef Attribute& type; | |
static Attribute& pre(Attribute& val) { return val; } | |
static void post(Attribute&, Attribute const&) {} | |
static void fail(Attribute&) {} | |
}; | |
// main specialization for Qi | |
template <typename Exposed, typename Transformed, typename Enable = void> | |
struct transform_attribute | |
: mpl::if_< | |
mpl::and_< | |
mpl::not_<is_const<Exposed> > | |
, mpl::not_<is_reference<Exposed> > | |
, traits::is_proxy<Transformed> > | |
, proxy_transform_attribute<Exposed, Transformed> | |
, default_transform_attribute<Exposed, Transformed> | |
>::type | |
{}; | |
template <typename Exposed, typename Transformed> | |
struct transform_attribute<optional<Exposed>, Transformed | |
, typename disable_if<is_same<optional<Exposed>, Transformed> >::type> | |
{ | |
typedef Transformed& type; | |
static Transformed& pre(optional<Exposed>& val) | |
{ | |
if (!val) | |
val = Transformed(); | |
return boost::get<Transformed>(val); | |
} | |
static void post(optional<Exposed>&, Transformed const&) {} | |
static void fail(optional<Exposed>& val) | |
{ | |
val = none_t(); // leave optional uninitialized if rhs failed | |
} | |
}; | |
// reference types need special handling | |
template <typename Attribute> | |
struct transform_attribute<Attribute&, Attribute> | |
{ | |
typedef Attribute& type; | |
static Attribute& pre(Attribute& val) { return val; } | |
static void post(Attribute&, Attribute const&) {} | |
static void fail(Attribute&) {} | |
}; | |
// unused_type needs some special handling as well | |
template <> | |
struct transform_attribute<unused_type, unused_type> | |
{ | |
typedef unused_type type; | |
static unused_type pre(unused_type) { return unused; } | |
static void post(unused_type, unused_type) {} | |
static void fail(unused_type) {} | |
}; | |
template <> | |
struct transform_attribute<unused_type const, unused_type> | |
: transform_attribute<unused_type, unused_type> | |
{}; | |
template <typename Attribute> | |
struct transform_attribute<unused_type, Attribute> | |
: transform_attribute<unused_type, unused_type> | |
{}; | |
template <typename Attribute> | |
struct transform_attribute<unused_type const, Attribute> | |
: transform_attribute<unused_type, unused_type> | |
{}; | |
template <typename Attribute> | |
struct transform_attribute<Attribute, unused_type> | |
: transform_attribute<unused_type, unused_type> | |
{}; | |
template <typename Attribute> | |
struct transform_attribute<Attribute const, unused_type> | |
: transform_attribute<unused_type, unused_type> | |
{}; | |
}}} | |
/////////////////////////////////////////////////////////////////////////////// | |
namespace boost { namespace spirit { namespace traits | |
{ | |
template <typename Exposed, typename Transformed> | |
struct transform_attribute<Exposed, Transformed, qi::domain> | |
: qi::transform_attribute<Exposed, Transformed> | |
{}; | |
template <typename Exposed, typename Transformed> | |
struct transform_attribute<Exposed&, Transformed, qi::domain> | |
: transform_attribute<Exposed, Transformed, qi::domain> | |
{}; | |
template <typename Attribute> | |
struct transform_attribute<Attribute&, Attribute, qi::domain> | |
: qi::transform_attribute<Attribute&, Attribute> | |
{}; | |
/////////////////////////////////////////////////////////////////////////// | |
template <typename Exposed, typename Transformed> | |
void post_transform(Exposed& dest, Transformed const& attr) | |
{ | |
return transform_attribute<Exposed, Transformed, qi::domain>::post(dest, attr); | |
} | |
/////////////////////////////////////////////////////////////////////////// | |
template <typename Exposed, typename Transformed> | |
void fail_transform(Exposed& dest, Transformed const&) | |
{ | |
return transform_attribute<Exposed, Transformed, qi::domain>::fail(dest); | |
} | |
}}} | |
#endif |