1 // Copyright (c) 2001-2011 Hartmut Kaiser 2 // Copyright (c) 2001-2011 Joel de Guzman 3 // 4 // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 7 #ifndef BOOST_SPIRIT_QI_DETAIL_ATTRIBUTES_HPP 8 #define BOOST_SPIRIT_QI_DETAIL_ATTRIBUTES_HPP 9 10 #include <boost/spirit/home/qi/domain.hpp> 11 #include <boost/spirit/home/support/attributes_fwd.hpp> 12 #include <boost/spirit/home/support/attributes.hpp> 13 #include <boost/spirit/home/support/utree/utree_traits_fwd.hpp> 14 15 /////////////////////////////////////////////////////////////////////////////// 16 namespace boost { namespace spirit { namespace qi 17 { 18 template <typename Exposed, typename Transformed> 19 struct default_transform_attribute 20 { 21 typedef Transformed type; 22 preboost::spirit::qi::default_transform_attribute23 static Transformed pre(Exposed&) { return Transformed(); } 24 postboost::spirit::qi::default_transform_attribute25 static void post(Exposed& val, Transformed const& attr) 26 { 27 traits::assign_to(attr, val); 28 } 29 30 // fail() will be called by Qi rule's if the rhs failed parsing failboost::spirit::qi::default_transform_attribute31 static void fail(Exposed&) {} 32 }; 33 34 // handle case where no transformation is required as the types are the same 35 template <typename Attribute> 36 struct default_transform_attribute<Attribute, Attribute> 37 { 38 typedef Attribute& type; preboost::spirit::qi::default_transform_attribute39 static Attribute& pre(Attribute& val) { return val; } postboost::spirit::qi::default_transform_attribute40 static void post(Attribute&, Attribute const&) {} failboost::spirit::qi::default_transform_attribute41 static void fail(Attribute&) {} 42 }; 43 44 template <typename Exposed, typename Transformed> 45 struct proxy_transform_attribute 46 { 47 typedef Transformed type; 48 preboost::spirit::qi::proxy_transform_attribute49 static Transformed pre(Exposed& val) { return Transformed(val); } postboost::spirit::qi::proxy_transform_attribute50 static void post(Exposed&, Transformed const&) { /* no-op */ } 51 52 // fail() will be called by Qi rule's if the rhs failed parsing failboost::spirit::qi::proxy_transform_attribute53 static void fail(Exposed&) {} 54 }; 55 56 // handle case where no transformation is required as the types are the same 57 template <typename Attribute> 58 struct proxy_transform_attribute<Attribute, Attribute> 59 { 60 typedef Attribute& type; preboost::spirit::qi::proxy_transform_attribute61 static Attribute& pre(Attribute& val) { return val; } postboost::spirit::qi::proxy_transform_attribute62 static void post(Attribute&, Attribute const&) {} failboost::spirit::qi::proxy_transform_attribute63 static void fail(Attribute&) {} 64 }; 65 66 // main specialization for Qi 67 template <typename Exposed, typename Transformed, typename Enable = void> 68 struct transform_attribute 69 : mpl::if_< 70 mpl::and_< 71 mpl::not_<is_const<Exposed> > 72 , mpl::not_<is_reference<Exposed> > 73 , traits::is_proxy<Transformed> > 74 , proxy_transform_attribute<Exposed, Transformed> 75 , default_transform_attribute<Exposed, Transformed> 76 >::type 77 {}; 78 79 template <typename Exposed, typename Transformed> 80 struct transform_attribute<boost::optional<Exposed>, Transformed 81 , typename disable_if<is_same<boost::optional<Exposed>, Transformed> >::type> 82 { 83 typedef Transformed& type; preboost::spirit::qi::transform_attribute84 static Transformed& pre(boost::optional<Exposed>& val) 85 { 86 if (!val) 87 val = Transformed(); 88 return boost::get<Transformed>(val); 89 } postboost::spirit::qi::transform_attribute90 static void post(boost::optional<Exposed>&, Transformed const&) {} failboost::spirit::qi::transform_attribute91 static void fail(boost::optional<Exposed>& val) 92 { 93 val = none; // leave optional uninitialized if rhs failed 94 } 95 }; 96 97 // unused_type needs some special handling as well 98 template <> 99 struct transform_attribute<unused_type, unused_type> 100 { 101 typedef unused_type type; preboost::spirit::qi::transform_attribute102 static unused_type pre(unused_type) { return unused; } postboost::spirit::qi::transform_attribute103 static void post(unused_type, unused_type) {} failboost::spirit::qi::transform_attribute104 static void fail(unused_type) {} 105 }; 106 107 template <> 108 struct transform_attribute<unused_type const, unused_type> 109 : transform_attribute<unused_type, unused_type> 110 {}; 111 112 template <typename Attribute> 113 struct transform_attribute<Attribute, unused_type> 114 : transform_attribute<unused_type, unused_type> 115 {}; 116 117 template <typename Attribute> 118 struct transform_attribute<Attribute const, unused_type> 119 : transform_attribute<unused_type, unused_type> 120 {}; 121 }}} 122 123 /////////////////////////////////////////////////////////////////////////////// 124 namespace boost { namespace spirit { namespace traits 125 { 126 namespace detail { 127 template <typename Exposed, typename Transformed> 128 struct transform_attribute_base<Exposed, Transformed, qi::domain> 129 : qi::transform_attribute<Exposed, Transformed> 130 {}; 131 } 132 }}} 133 134 #endif 135