| 1 | /*============================================================================= |
| 2 | Copyright (c) 2001-2011 Joel de Guzman |
| 3 | Copyright (c) 2001-2011 Hartmut Kaiser |
| 4 | Copyright (c) 2011 Thomas Heller |
| 5 | |
| 6 | Distributed under the Boost Software License, Version 1.0. (See accompanying |
| 7 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| 8 | ==============================================================================*/ |
| 9 | #if !defined(BOOST_SPIRIT_ARGUMENT_FEBRUARY_17_2007_0339PM) |
| 10 | #define BOOST_SPIRIT_ARGUMENT_FEBRUARY_17_2007_0339PM |
| 11 | |
| 12 | #if defined(_MSC_VER) |
| 13 | #pragma once |
| 14 | #endif |
| 15 | |
| 16 | #include <boost/preprocessor/repetition/repeat_from_to.hpp> |
| 17 | #include <boost/preprocessor/arithmetic/inc.hpp> |
| 18 | #include <boost/spirit/home/support/assert_msg.hpp> |
| 19 | #include <boost/spirit/home/support/limits.hpp> |
| 20 | #include <boost/fusion/include/at.hpp> |
| 21 | #include <boost/fusion/include/size.hpp> |
| 22 | #include <boost/mpl/size.hpp> |
| 23 | #include <boost/mpl/at.hpp> |
| 24 | #include <boost/phoenix/core/actor.hpp> |
| 25 | #include <boost/phoenix/core/argument.hpp> |
| 26 | #include <boost/phoenix/core/terminal.hpp> |
| 27 | #include <boost/phoenix/core/v2_eval.hpp> |
| 28 | #include <boost/proto/proto_fwd.hpp> // for transform placeholders |
| 29 | |
| 30 | #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS |
| 31 | |
| 32 | #define SPIRIT_DECLARE_ARG(z, n, data) \ |
| 33 | typedef phoenix::actor<argument<n> > \ |
| 34 | BOOST_PP_CAT(BOOST_PP_CAT(_, BOOST_PP_INC(n)), _type); \ |
| 35 | phoenix::actor<argument<n> > const \ |
| 36 | BOOST_PP_CAT(_, BOOST_PP_INC(n)) = \ |
| 37 | BOOST_PP_CAT(BOOST_PP_CAT(_, BOOST_PP_INC(n)), _type)(); \ |
| 38 | /***/ |
| 39 | |
| 40 | #define SPIRIT_USING_ARGUMENT(z, n, data) \ |
| 41 | using spirit::BOOST_PP_CAT(BOOST_PP_CAT(_, n), _type); \ |
| 42 | using spirit::BOOST_PP_CAT(_, n); \ |
| 43 | /***/ |
| 44 | |
| 45 | #else |
| 46 | |
| 47 | #define SPIRIT_DECLARE_ARG(z, n, data) \ |
| 48 | typedef phoenix::actor<argument<n> > \ |
| 49 | BOOST_PP_CAT(BOOST_PP_CAT(_, BOOST_PP_INC(n)), _type); \ |
| 50 | /***/ |
| 51 | |
| 52 | #define SPIRIT_USING_ARGUMENT(z, n, data) \ |
| 53 | using spirit::BOOST_PP_CAT(BOOST_PP_CAT(_, n), _type); \ |
| 54 | /***/ |
| 55 | |
| 56 | #endif |
| 57 | |
| 58 | namespace boost { namespace spirit |
| 59 | { |
| 60 | template <int N> |
| 61 | struct argument; |
| 62 | |
| 63 | template <typename Dummy> |
| 64 | struct attribute_context; |
| 65 | }} |
| 66 | |
| 67 | BOOST_PHOENIX_DEFINE_CUSTOM_TERMINAL( |
| 68 | template <int N> |
| 69 | , boost::spirit::argument<N> |
| 70 | , mpl::false_ // is not nullary |
| 71 | , v2_eval( |
| 72 | proto::make< |
| 73 | boost::spirit::argument<N>() |
| 74 | > |
| 75 | , proto::call< |
| 76 | functional::env(proto::_state) |
| 77 | > |
| 78 | ) |
| 79 | ) |
| 80 | |
| 81 | BOOST_PHOENIX_DEFINE_CUSTOM_TERMINAL( |
| 82 | template <typename Dummy> |
| 83 | , boost::spirit::attribute_context<Dummy> |
| 84 | , mpl::false_ // is not nullary |
| 85 | , v2_eval( |
| 86 | proto::make< |
| 87 | boost::spirit::attribute_context<Dummy>() |
| 88 | > |
| 89 | , proto::call< |
| 90 | functional::env(proto::_state) |
| 91 | > |
| 92 | ) |
| 93 | ) |
| 94 | |
| 95 | namespace boost { namespace spirit |
| 96 | { |
| 97 | namespace result_of |
| 98 | { |
| 99 | template <typename Sequence, int N> |
| 100 | struct get_arg |
| 101 | { |
| 102 | typedef typename |
| 103 | fusion::result_of::size<Sequence>::type |
| 104 | sequence_size; |
| 105 | |
| 106 | // report invalid argument not found (N is out of bounds) |
| 107 | BOOST_SPIRIT_ASSERT_MSG( |
| 108 | (N < sequence_size::value), |
| 109 | index_is_out_of_bounds, ()); |
| 110 | |
| 111 | typedef typename |
| 112 | fusion::result_of::at_c<Sequence, N>::type |
| 113 | type; |
| 114 | |
| 115 | static type call(Sequence& seq) |
| 116 | { |
| 117 | return fusion::at_c<N>(seq); |
| 118 | } |
| 119 | }; |
| 120 | |
| 121 | template <typename Sequence, int N> |
| 122 | struct get_arg<Sequence&, N> : get_arg<Sequence, N> |
| 123 | { |
| 124 | }; |
| 125 | } |
| 126 | |
| 127 | template <int N, typename T> |
| 128 | typename result_of::get_arg<T, N>::type |
| 129 | get_arg(T& val) |
| 130 | { |
| 131 | return result_of::get_arg<T, N>::call(val); |
| 132 | } |
| 133 | |
| 134 | template <typename> |
| 135 | struct attribute_context |
| 136 | { |
| 137 | typedef mpl::true_ no_nullary; |
| 138 | |
| 139 | template <typename Env> |
| 140 | struct result |
| 141 | { |
| 142 | // FIXME: is this remove_const really necessary? |
| 143 | typedef typename |
| 144 | remove_const< |
| 145 | typename mpl::at_c<typename Env::args_type, 0>::type |
| 146 | >::type |
| 147 | type; |
| 148 | }; |
| 149 | |
| 150 | template <typename Env> |
| 151 | typename result<Env>::type |
| 152 | eval(Env const& env) const |
| 153 | { |
| 154 | return fusion::at_c<0>(env.args()); |
| 155 | } |
| 156 | }; |
| 157 | |
| 158 | template <int N> |
| 159 | struct argument |
| 160 | { |
| 161 | typedef mpl::true_ no_nullary; |
| 162 | |
| 163 | template <typename Env> |
| 164 | struct result |
| 165 | { |
| 166 | typedef typename |
| 167 | mpl::at_c<typename Env::args_type, 0>::type |
| 168 | arg_type; |
| 169 | |
| 170 | typedef typename result_of::get_arg<arg_type, N>::type type; |
| 171 | }; |
| 172 | |
| 173 | template <typename Env> |
| 174 | typename result<Env>::type |
| 175 | eval(Env const& env) const |
| 176 | { |
| 177 | return get_arg<N>(fusion::at_c<0>(env.args())); |
| 178 | } |
| 179 | }; |
| 180 | |
| 181 | // _0 refers to the whole attribute as generated by the lhs parser |
| 182 | typedef phoenix::actor<attribute_context<void> > _0_type; |
| 183 | #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS |
| 184 | _0_type const _0 = _0_type(); |
| 185 | #endif |
| 186 | |
| 187 | // _1, _2, ... refer to the attributes of the single components the lhs |
| 188 | // parser is composed of |
| 189 | typedef phoenix::actor<argument<0> > _1_type; |
| 190 | typedef phoenix::actor<argument<1> > _2_type; |
| 191 | typedef phoenix::actor<argument<2> > _3_type; |
| 192 | |
| 193 | #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS |
| 194 | _1_type const _1 = _1_type(); |
| 195 | _2_type const _2 = _2_type(); |
| 196 | _3_type const _3 = _3_type(); |
| 197 | #endif |
| 198 | |
| 199 | // '_pass' may be used to make a match fail in retrospective |
| 200 | typedef phoenix::arg_names::_3_type _pass_type; |
| 201 | #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS |
| 202 | _pass_type const _pass = _pass_type(); |
| 203 | #endif |
| 204 | |
| 205 | // Bring in the rest of the arguments and attributes (_4 .. _N+1), using PP |
| 206 | BOOST_PP_REPEAT_FROM_TO( |
| 207 | 3, SPIRIT_ARGUMENTS_LIMIT, SPIRIT_DECLARE_ARG, _) |
| 208 | |
| 209 | #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS |
| 210 | // You can bring these in with the using directive |
| 211 | // without worrying about bringing in too much. |
| 212 | namespace labels |
| 213 | { |
| 214 | BOOST_PP_REPEAT(SPIRIT_ARGUMENTS_LIMIT, SPIRIT_USING_ARGUMENT, _) |
| 215 | } |
| 216 | #endif |
| 217 | |
| 218 | }} |
| 219 | |
| 220 | #undef SPIRIT_DECLARE_ARG |
| 221 | #endif |
| 222 | |