1 /*=============================================================================
2     Copyright (c) 2001-2011 Hartmut Kaiser
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_ALTERNATIVE_FUNCTION_APRIL_23_2007_1046AM)
8 #define SPIRIT_ALTERNATIVE_FUNCTION_APRIL_23_2007_1046AM
9 
10 #if defined(_MSC_VER)
11 #pragma once
12 #endif
13 
14 #include <boost/spirit/home/qi/domain.hpp>
15 #include <boost/spirit/home/qi/detail/assign_to.hpp>
16 #include <boost/spirit/home/support/unused.hpp>
17 #include <boost/spirit/home/qi/detail/attributes.hpp>
18 #include <boost/variant.hpp>
19 #include <boost/mpl/bool.hpp>
20 
21 namespace boost { namespace spirit { namespace qi { namespace detail
22 {
23     template <typename Variant, typename Expected>
24     struct find_substitute
25     {
26         // Get the type from the variant that can be a substitute for Expected.
27         // If none is found, just return Expected
28 
29         typedef Variant variant_type;
30         typedef typename variant_type::types types;
31         typedef typename mpl::end<types>::type end;
32 
33         typedef typename
34             mpl::find_if<types, is_same<mpl::_1, Expected> >::type
35         iter_1;
36 
37         typedef typename
38             mpl::eval_if<
39                 is_same<iter_1, end>,
40                 mpl::find_if<types, traits::is_substitute<mpl::_1, Expected> >,
41                 mpl::identity<iter_1>
42             >::type
43         iter;
44 
45         typedef typename
46             mpl::eval_if<
47                 is_same<iter, end>,
48                 mpl::identity<Expected>,
49                 mpl::deref<iter>
50             >::type
51         type;
52     };
53 
54     template <typename Iterator, typename Context, typename Skipper,
55         typename Attribute>
56     struct alternative_function
57     {
alternative_functionboost::spirit::qi::detail::alternative_function58         alternative_function(
59             Iterator& first_, Iterator const& last_, Context& context_,
60             Skipper const& skipper_, Attribute& attr_)
61           : first(first_), last(last_), context(context_), skipper(skipper_),
62             attr(attr_)
63         {
64         }
65 
66         template <typename Component>
callboost::spirit::qi::detail::alternative_function67         bool call(Component const& component, mpl::true_) const
68         {
69             // if Attribute is not a variant, then pass it as-is
70             return component.parse(first, last, context, skipper, attr);
71         }
72 
73         template <typename Component>
call_optional_or_variantboost::spirit::qi::detail::alternative_function74         bool call_optional_or_variant(Component const& component, mpl::true_) const
75         {
76             // If Attribute is an optional, then create an attribute for the Component
77             // with the type optional::value_type. If the expected attribute is unused type,
78             // use it instead.
79             typedef typename
80                 traits::attribute_of<Component, Context, Iterator>::type
81             expected_type;
82 
83             typename mpl::if_<
84                 is_same<expected_type, unused_type>,
85                 unused_type,
86                 typename Attribute::value_type>::type
87             val;
88 
89             if (component.parse(first, last, context, skipper, val))
90             {
91                 traits::assign_to(val, attr);
92                 return true;
93             }
94             return false;
95         }
96 
97         template <typename Component>
call_variantboost::spirit::qi::detail::alternative_function98         bool call_variant(Component const& component, mpl::false_) const
99         {
100             // If Attribute is a variant, then search the variant types for a
101             // suitable substitute type.
102 
103             typename
104                 find_substitute<Attribute,
105                     typename traits::attribute_of<Component, Context, Iterator>::type
106                 >::type
107             val;
108 
109             if (component.parse(first, last, context, skipper, val))
110             {
111                 traits::assign_to(val, attr);
112                 return true;
113             }
114             return false;
115         }
116 
117         template <typename Component>
call_variantboost::spirit::qi::detail::alternative_function118         bool call_variant(Component const& component, mpl::true_) const
119         {
120             // If Attribute is a variant and the expected attribute is
121             // the same type (pass the variant as-is).
122 
123             return component.parse(first, last, context, skipper, attr);
124         }
125 
126         template <typename Component>
call_optional_or_variantboost::spirit::qi::detail::alternative_function127         bool call_optional_or_variant(Component const& component, mpl::false_) const
128         {
129             // Attribute is a variant...
130 
131             typedef typename
132                 traits::attribute_of<Component, Context, Iterator>::type
133             expected;
134             return call_variant(component,
135                 is_same<Attribute, expected>());
136         }
137 
138         template <typename Component>
callboost::spirit::qi::detail::alternative_function139         bool call(Component const& component, mpl::false_) const
140         {
141             return call_optional_or_variant(
142                 component, spirit::traits::not_is_variant<Attribute, qi::domain>());
143         }
144 
145         template <typename Component>
call_unusedboost::spirit::qi::detail::alternative_function146         bool call_unused(Component const& component, mpl::true_) const
147         {
148             // return true if the parser succeeds
149             return call(component,
150                 mpl::and_<
151                     spirit::traits::not_is_variant<Attribute, qi::domain>,
152                     spirit::traits::not_is_optional<Attribute, qi::domain>
153                 >());
154         }
155 
156         template <typename Component>
call_unusedboost::spirit::qi::detail::alternative_function157         bool call_unused(Component const& component, mpl::false_) const
158         {
159             return component.parse(first, last, context, skipper, unused);
160         }
161 
162         template <typename Component>
operator ()boost::spirit::qi::detail::alternative_function163         bool operator()(Component const& component) const
164         {
165             // return true if the parser succeeds
166             typedef typename traits::not_is_unused<
167                 typename traits::attribute_of<Component, Context, Iterator>::type
168             >::type predicate;
169 
170             return call_unused(component, predicate());
171         }
172 
173         Iterator& first;
174         Iterator const& last;
175         Context& context;
176         Skipper const& skipper;
177         Attribute& attr;
178 
179     private:
180         // silence MSVC warning C4512: assignment operator could not be generated
181         alternative_function& operator= (alternative_function const&);
182     };
183 
184     template <typename Iterator, typename Context, typename Skipper>
185     struct alternative_function<Iterator, Context, Skipper, unused_type const>
186     {
alternative_functionboost::spirit::qi::detail::alternative_function187         alternative_function(
188             Iterator& first_, Iterator const& last_, Context& context_,
189             Skipper const& skipper_, unused_type)
190           : first(first_), last(last_), context(context_), skipper(skipper_)
191         {
192         }
193 
194         template <typename Component>
operator ()boost::spirit::qi::detail::alternative_function195         bool operator()(Component const& component) const
196         {
197             // return true if the parser succeeds
198             return component.parse(first, last, context, skipper,
199                 unused);
200         }
201 
202         Iterator& first;
203         Iterator const& last;
204         Context& context;
205         Skipper const& skipper;
206 
207     private:
208         // silence MSVC warning C4512: assignment operator could not be generated
209         alternative_function& operator= (alternative_function const&);
210     };
211 
212 }}}}
213 
214 #endif
215