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