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 
callboost::spirit::result_of::get_arg115             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
get_arg(T & val)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
evalboost::spirit::attribute_context152         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
evalboost::spirit::argument175         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