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