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