• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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