1 /*============================================================================= 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_ACTION_JANUARY_07_2007_1128AM) 8 #define SPIRIT_ACTION_JANUARY_07_2007_1128AM 9 10 #if defined(_MSC_VER) 11 #pragma once 12 #endif 13 14 #include <boost/spirit/home/qi/meta_compiler.hpp> 15 #include <boost/spirit/home/qi/parser.hpp> 16 #include <boost/spirit/home/qi/detail/attributes.hpp> 17 #include <boost/spirit/home/support/argument.hpp> 18 #include <boost/spirit/home/support/context.hpp> 19 #include <boost/spirit/home/support/unused.hpp> 20 #include <boost/spirit/home/support/info.hpp> 21 #include <boost/spirit/home/support/action_dispatch.hpp> 22 #include <boost/spirit/home/support/handles_container.hpp> 23 24 #include <boost/mpl/bool.hpp> 25 #include <boost/mpl/if.hpp> 26 #include <boost/type_traits/remove_const.hpp> 27 #include <boost/type_traits/is_same.hpp> 28 29 namespace boost { namespace spirit { namespace qi 30 { 31 BOOST_PP_REPEAT(SPIRIT_ARGUMENTS_LIMIT, SPIRIT_USING_ARGUMENT, _) 32 33 template <typename Subject, typename Action> 34 struct action : unary_parser<action<Subject, Action> > 35 { 36 typedef Subject subject_type; 37 typedef Action action_type; 38 39 template <typename Context, typename Iterator> 40 struct attribute 41 : traits::attribute_of<Subject, Context, Iterator> 42 {}; 43 actionboost::spirit::qi::action44 action(Subject const& subject_, Action f_) 45 : subject(subject_), f(f_) {} 46 47 #ifndef BOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT 48 template <typename Iterator, typename Context 49 , typename Skipper, typename Attribute> parseboost::spirit::qi::action50 bool parse(Iterator& first, Iterator const& last 51 , Context& context, Skipper const& skipper 52 , Attribute& attr_) const 53 { 54 typedef typename attribute<Context, Iterator>::type attr_type; 55 56 // create an attribute if one is not supplied 57 typedef traits::transform_attribute< 58 Attribute, attr_type, domain> transform; 59 60 typename transform::type attr = transform::pre(attr_); 61 62 Iterator save = first; 63 if (subject.parse(first, last, context, skipper, attr)) 64 { 65 // call the function, passing the attribute, the context. 66 // The client can return false to fail parsing. 67 if (traits::action_dispatch<Subject>()(f, attr, context)) 68 { 69 // Do up-stream transformation, this integrates the results 70 // back into the original attribute value, if appropriate. 71 transform::post(attr_, attr); 72 return true; 73 } 74 75 // reset iterators if semantic action failed the match 76 // retrospectively 77 first = save; 78 } 79 return false; 80 } 81 #else 82 template <typename Iterator, typename Context 83 , typename Skipper, typename Attribute> parseboost::spirit::qi::action84 bool parse(Iterator& first, Iterator const& last 85 , Context& context, Skipper const& skipper 86 , Attribute& attr) const 87 { 88 Iterator save = first; 89 if (subject.parse(first, last, context, skipper, attr)) // Use the attribute as-is 90 { 91 // call the function, passing the attribute, the context. 92 // The client can return false to fail parsing. 93 if (traits::action_dispatch<Subject>()(f, attr, context)) 94 return true; 95 96 // reset iterators if semantic action failed the match 97 // retrospectively 98 first = save; 99 } 100 return false; 101 } 102 103 template <typename Iterator, typename Context 104 , typename Skipper> parseboost::spirit::qi::action105 bool parse(Iterator& first, Iterator const& last 106 , Context& context, Skipper const& skipper 107 , unused_type) const 108 { 109 typedef typename attribute<Context, Iterator>::type attr_type; 110 111 // synthesize the attribute since one is not supplied 112 attr_type attr = attr_type(); 113 114 Iterator save = first; 115 if (subject.parse(first, last, context, skipper, attr)) 116 { 117 // call the function, passing the attribute, the context. 118 // The client can return false to fail parsing. 119 if (traits::action_dispatch<Subject>()(f, attr, context)) 120 return true; 121 122 // reset iterators if semantic action failed the match 123 // retrospectively 124 first = save; 125 } 126 return false; 127 } 128 #endif 129 130 template <typename Context> whatboost::spirit::qi::action131 info what(Context& context) const 132 { 133 // the action is transparent (does not add any info) 134 return subject.what(context); 135 } 136 137 Subject subject; 138 Action f; 139 140 // silence MSVC warning C4512: assignment operator could not be generated 141 BOOST_DELETED_FUNCTION(action& operator= (action const&)) 142 }; 143 }}} 144 145 namespace boost { namespace spirit 146 { 147 // Qi action meta-compiler 148 template <> 149 struct make_component<qi::domain, tag::action> 150 { 151 template <typename Sig> 152 struct result; 153 154 template <typename This, typename Elements, typename Modifiers> 155 struct result<This(Elements, Modifiers)> 156 { 157 typedef typename 158 remove_const<typename Elements::car_type>::type 159 subject_type; 160 161 typedef typename 162 remove_const<typename Elements::cdr_type::car_type>::type 163 action_type; 164 165 typedef qi::action<subject_type, action_type> type; 166 }; 167 168 template <typename Elements> 169 typename result<make_component(Elements, unused_type)>::type operator ()boost::spirit::make_component170 operator()(Elements const& elements, unused_type) const 171 { 172 typename result<make_component(Elements, unused_type)>::type 173 result(elements.car, elements.cdr.car); 174 return result; 175 } 176 }; 177 }} 178 179 namespace boost { namespace spirit { namespace traits 180 { 181 /////////////////////////////////////////////////////////////////////////// 182 template <typename Subject, typename Action> 183 struct has_semantic_action<qi::action<Subject, Action> > 184 : mpl::true_ {}; 185 186 /////////////////////////////////////////////////////////////////////////// 187 template <typename Subject, typename Action, typename Attribute 188 , typename Context, typename Iterator> 189 struct handles_container<qi::action<Subject, Action>, Attribute 190 , Context, Iterator> 191 : unary_handles_container<Subject, Attribute, Context, Iterator> {}; 192 }}} 193 194 #endif 195