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 #if !defined(SPIRIT_QI_DETAIL_ATTRIBUTES_APR_18_2010_0458PM) 8 #define SPIRIT_QI_DETAIL_ATTRIBUTES_APR_18_2010_0458PM 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 // reference types need special handling 98 template <typename Attribute> 99 struct transform_attribute<Attribute&, Attribute> 100 { 101 typedef Attribute& type; preboost::spirit::qi::transform_attribute102 static Attribute& pre(Attribute& val) { return val; } postboost::spirit::qi::transform_attribute103 static void post(Attribute&, Attribute const&) {} failboost::spirit::qi::transform_attribute104 static void fail(Attribute&) {} 105 }; 106 107 // unused_type needs some special handling as well 108 template <> 109 struct transform_attribute<unused_type, unused_type> 110 { 111 typedef unused_type type; preboost::spirit::qi::transform_attribute112 static unused_type pre(unused_type) { return unused; } postboost::spirit::qi::transform_attribute113 static void post(unused_type, unused_type) {} failboost::spirit::qi::transform_attribute114 static void fail(unused_type) {} 115 }; 116 117 template <> 118 struct transform_attribute<unused_type const, unused_type> 119 : transform_attribute<unused_type, unused_type> 120 {}; 121 122 template <typename Attribute> 123 struct transform_attribute<unused_type, Attribute> 124 : transform_attribute<unused_type, unused_type> 125 {}; 126 127 template <typename Attribute> 128 struct transform_attribute<unused_type const, Attribute> 129 : transform_attribute<unused_type, unused_type> 130 {}; 131 132 template <typename Attribute> 133 struct transform_attribute<Attribute, unused_type> 134 : transform_attribute<unused_type, unused_type> 135 {}; 136 137 template <typename Attribute> 138 struct transform_attribute<Attribute const, unused_type> 139 : transform_attribute<unused_type, unused_type> 140 {}; 141 }}} 142 143 /////////////////////////////////////////////////////////////////////////////// 144 namespace boost { namespace spirit { namespace traits 145 { 146 template <typename Exposed, typename Transformed> 147 struct transform_attribute<Exposed, Transformed, qi::domain> 148 : qi::transform_attribute<Exposed, Transformed> 149 {}; 150 151 template <typename Exposed, typename Transformed> 152 struct transform_attribute<Exposed&, Transformed, qi::domain> 153 : transform_attribute<Exposed, Transformed, qi::domain> 154 {}; 155 156 template <typename Attribute> 157 struct transform_attribute<Attribute&, Attribute, qi::domain> 158 : qi::transform_attribute<Attribute&, Attribute> 159 {}; 160 161 /////////////////////////////////////////////////////////////////////////// 162 template <typename Exposed, typename Transformed> post_transform(Exposed & dest,Transformed const & attr)163 void post_transform(Exposed& dest, Transformed const& attr) 164 { 165 return transform_attribute<Exposed, Transformed, qi::domain>::post(dest, attr); 166 } 167 168 /////////////////////////////////////////////////////////////////////////// 169 template <typename Exposed, typename Transformed> fail_transform(Exposed & dest,Transformed const &)170 void fail_transform(Exposed& dest, Transformed const&) 171 { 172 return transform_attribute<Exposed, Transformed, qi::domain>::fail(dest); 173 } 174 }}} 175 176 #endif 177