summaryrefslogtreecommitdiffstats
blob: 0a66a655865a681dbf2a8388334758c50dec9b25 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
//  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>
#include <boost/spirit/home/support/utree/utree_traits_fwd.hpp>

///////////////////////////////////////////////////////////////////////////////
namespace boost { namespace spirit { namespace qi
{
    template <typename Exposed, typename Transformed>
    struct default_transform_attribute
    {
        typedef Transformed type;

        static Transformed pre(Exposed&) { 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&, Transformed const&) { /* 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<boost::optional<Exposed>, Transformed
      , typename disable_if<is_same<boost::optional<Exposed>, Transformed> >::type>
    {
        typedef Transformed& type;
        static Transformed& pre(boost::optional<Exposed>& val)
        {
            if (!val)
                val = Transformed();
            return boost::get<Transformed>(val);
        }
        static void post(boost::optional<Exposed>&, Transformed const&) {}
        static void fail(boost::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