Imported Upstream version 1.57.0
[platform/upstream/boost.git] / boost / spirit / home / qi / nonterminal / rule.hpp
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(BOOST_SPIRIT_RULE_FEBRUARY_12_2007_1020AM)
8 #define BOOST_SPIRIT_RULE_FEBRUARY_12_2007_1020AM
9
10 #if defined(_MSC_VER)
11 #pragma once
12 #endif
13
14 #include <boost/assert.hpp>
15 #include <boost/config.hpp>
16 #include <boost/function.hpp>
17 #include <boost/mpl/vector.hpp>
18 #include <boost/type_traits/add_reference.hpp>
19 #include <boost/type_traits/is_same.hpp>
20
21 #include <boost/fusion/include/vector.hpp>
22 #include <boost/fusion/include/size.hpp>
23 #include <boost/fusion/include/make_vector.hpp>
24 #include <boost/fusion/include/cons.hpp>
25 #include <boost/fusion/include/as_list.hpp>
26 #include <boost/fusion/include/as_vector.hpp>
27
28 #include <boost/spirit/home/support/unused.hpp>
29 #include <boost/spirit/home/support/argument.hpp>
30 #include <boost/spirit/home/support/context.hpp>
31 #include <boost/spirit/home/support/info.hpp>
32 #include <boost/spirit/home/qi/detail/attributes.hpp>
33 #include <boost/spirit/home/support/nonterminal/extract_param.hpp>
34 #include <boost/spirit/home/support/nonterminal/locals.hpp>
35 #include <boost/spirit/home/qi/reference.hpp>
36 #include <boost/spirit/home/qi/nonterminal/detail/parameterized.hpp>
37 #include <boost/spirit/home/qi/nonterminal/detail/parser_binder.hpp>
38 #include <boost/spirit/home/qi/nonterminal/nonterminal_fwd.hpp>
39 #include <boost/spirit/home/qi/skip_over.hpp>
40
41 #if defined(BOOST_MSVC)
42 # pragma warning(push)
43 # pragma warning(disable: 4355) // 'this' : used in base member initializer list warning
44 # pragma warning(disable: 4127) // conditional expression is constant
45 #endif
46
47 namespace boost { namespace spirit { namespace qi
48 {
49     BOOST_PP_REPEAT(SPIRIT_ATTRIBUTES_LIMIT, SPIRIT_USING_ATTRIBUTE, _)
50
51     using spirit::_pass_type;
52     using spirit::_val_type;
53     using spirit::_a_type;
54     using spirit::_b_type;
55     using spirit::_c_type;
56     using spirit::_d_type;
57     using spirit::_e_type;
58     using spirit::_f_type;
59     using spirit::_g_type;
60     using spirit::_h_type;
61     using spirit::_i_type;
62     using spirit::_j_type;
63
64 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
65
66     using spirit::_pass;
67     using spirit::_val;
68     using spirit::_a;
69     using spirit::_b;
70     using spirit::_c;
71     using spirit::_d;
72     using spirit::_e;
73     using spirit::_f;
74     using spirit::_g;
75     using spirit::_h;
76     using spirit::_i;
77     using spirit::_j;
78
79 #endif
80
81     using spirit::info;
82     using spirit::locals;
83
84     template <
85         typename Iterator, typename T1, typename T2, typename T3
86       , typename T4>
87     struct rule
88       : proto::extends<
89             typename proto::terminal<
90                 reference<rule<Iterator, T1, T2, T3, T4> const>
91             >::type
92           , rule<Iterator, T1, T2, T3, T4>
93         >
94       , parser<rule<Iterator, T1, T2, T3, T4> >
95     {
96         typedef Iterator iterator_type;
97         typedef rule<Iterator, T1, T2, T3, T4> this_type;
98         typedef reference<this_type const> reference_;
99         typedef typename proto::terminal<reference_>::type terminal;
100         typedef proto::extends<terminal, this_type> base_type;
101         typedef mpl::vector<T1, T2, T3, T4> template_params;
102
103         // The rule's locals_type: a sequence of types to be used as local variables
104         typedef typename
105             spirit::detail::extract_locals<template_params>::type
106         locals_type;
107
108         // The rule's skip-parser type
109         typedef typename
110             spirit::detail::extract_component<
111                 qi::domain, template_params>::type
112         skipper_type;
113
114         // The rule's signature
115         typedef typename
116             spirit::detail::extract_sig<template_params>::type
117         sig_type;
118
119         // The rule's encoding type
120         typedef typename
121             spirit::detail::extract_encoding<template_params>::type
122         encoding_type;
123
124         // This is the rule's attribute type
125         typedef typename
126             spirit::detail::attr_from_sig<sig_type>::type
127         attr_type;
128         typedef typename add_reference<attr_type>::type attr_reference_type;
129
130         // parameter_types is a sequence of types passed as parameters to the rule
131         typedef typename
132             spirit::detail::params_from_sig<sig_type>::type
133         parameter_types;
134
135         static size_t const params_size =
136             fusion::result_of::size<parameter_types>::type::value;
137
138         typedef context<
139             fusion::cons<attr_reference_type, parameter_types>
140           , locals_type>
141         context_type;
142
143         typedef function<
144             bool(Iterator& first, Iterator const& last
145               , context_type& context
146               , skipper_type const& skipper
147             )>
148         function_type;
149
150         typedef typename
151             mpl::if_<
152                 is_same<encoding_type, unused_type>
153               , unused_type
154               , tag::char_code<tag::encoding, encoding_type>
155             >::type
156         encoding_modifier_type;
157
158         explicit rule(std::string const& name = "unnamed-rule")
159           : base_type(terminal::make(reference_(*this)))
160           , name_(name)
161         {
162         }
163
164         rule(rule const& rhs)
165           : base_type(terminal::make(reference_(*this)))
166           , name_(rhs.name_)
167           , f(rhs.f)
168         {
169         }
170
171         template <typename Auto, typename Expr>
172         static void define(rule& /*lhs*/, Expr const& /*expr*/, mpl::false_)
173         {
174             // Report invalid expression error as early as possible.
175             // If you got an error_invalid_expression error message here,
176             // then the expression (expr) is not a valid spirit qi expression.
177             BOOST_SPIRIT_ASSERT_MATCH(qi::domain, Expr);
178         }
179
180         template <typename Auto, typename Expr>
181         static void define(rule& lhs, Expr const& expr, mpl::true_)
182         {
183             lhs.f = detail::bind_parser<Auto>(
184                 compile<qi::domain>(expr, encoding_modifier_type()));
185         }
186
187         template <typename Expr>
188         rule(Expr const& expr, std::string const& name = "unnamed-rule")
189           : base_type(terminal::make(reference_(*this)))
190           , name_(name)
191         {
192             define<mpl::false_>(*this, expr, traits::matches<qi::domain, Expr>());
193         }
194
195         rule& operator=(rule const& rhs)
196         {
197             // The following assertion fires when you try to initialize a rule
198             // from an uninitialized one. Did you mean to refer to the right
199             // hand side rule instead of assigning from it? In this case you
200             // should write lhs = rhs.alias();
201             BOOST_ASSERT(rhs.f && "Did you mean rhs.alias() instead of rhs?");
202
203             f = rhs.f;
204             name_ = rhs.name_;
205             return *this;
206         }
207
208         std::string const& name() const
209         {
210             return name_;
211         }
212
213         void name(std::string const& str)
214         {
215             name_ = str;
216         }
217
218         template <typename Expr>
219         rule& operator=(Expr const& expr)
220         {
221             define<mpl::false_>(*this, expr, traits::matches<qi::domain, Expr>());
222             return *this;
223         }
224
225 // VC7.1 has problems to resolve 'rule' without explicit template parameters
226 #if !BOOST_WORKAROUND(BOOST_MSVC, < 1400)
227         // g++ 3.3 barfs if this is a member function :(
228         template <typename Expr>
229         friend rule& operator%=(rule& r, Expr const& expr)
230         {
231             define<mpl::true_>(r, expr, traits::matches<qi::domain, Expr>());
232             return r;
233         }
234
235 #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
236         // non-const version needed to suppress proto's %= kicking in
237         template <typename Expr>
238         friend rule& operator%=(rule& r, Expr& expr)
239         {
240             return r %= static_cast<Expr const&>(expr);
241         }
242 #else
243         // for rvalue references
244         template <typename Expr>
245         friend rule& operator%=(rule& r, Expr&& expr)
246         {
247             define<mpl::true_>(r, expr, traits::matches<qi::domain, Expr>());
248             return r;
249         }
250 #endif
251
252 #else
253         // both friend functions have to be defined out of class as VC7.1
254         // will complain otherwise
255         template <typename OutputIterator_, typename T1_, typename T2_
256           , typename T3_, typename T4_, typename Expr>
257         friend rule<OutputIterator_, T1_, T2_, T3_, T4_>& operator%=(
258             rule<OutputIterator_, T1_, T2_, T3_, T4_>& r, Expr const& expr);
259
260         // non-const version needed to suppress proto's %= kicking in
261         template <typename OutputIterator_, typename T1_, typename T2_
262           , typename T3_, typename T4_, typename Expr>
263         friend rule<OutputIterator_, T1_, T2_, T3_, T4_>& operator%=(
264             rule<OutputIterator_, T1_, T2_, T3_, T4_>& r, Expr& expr);
265 #endif
266
267         template <typename Context, typename Iterator_>
268         struct attribute
269         {
270             typedef attr_type type;
271         };
272
273         template <typename Context, typename Skipper, typename Attribute>
274         bool parse(Iterator& first, Iterator const& last
275           , Context& /*context*/, Skipper const& skipper
276           , Attribute& attr_param) const
277         {
278             if (f)
279             {
280                 // do a preskip if this is an implied lexeme
281                 if (is_same<skipper_type, unused_type>::value)
282                     qi::skip_over(first, last, skipper);
283
284                 typedef traits::make_attribute<attr_type, Attribute> make_attribute;
285
286                 // do down-stream transformation, provides attribute for
287                 // rhs parser
288                 typedef traits::transform_attribute<
289                     typename make_attribute::type, attr_type, domain>
290                 transform;
291
292                 typename make_attribute::type made_attr = make_attribute::call(attr_param);
293                 typename transform::type attr_ = transform::pre(made_attr);
294
295                 // If you are seeing a compilation error here, you are probably
296                 // trying to use a rule or a grammar which has inherited
297                 // attributes, without passing values for them.
298                 context_type context(attr_);
299
300                 // If you are seeing a compilation error here stating that the
301                 // fourth parameter can't be converted to a required target type
302                 // then you are probably trying to use a rule or a grammar with
303                 // an incompatible skipper type.
304                 if (f(first, last, context, skipper))
305                 {
306                     // do up-stream transformation, this integrates the results
307                     // back into the original attribute value, if appropriate
308                     traits::post_transform(attr_param, attr_);
309                     return true;
310                 }
311
312                 // inform attribute transformation of failed rhs
313                 traits::fail_transform(attr_param, attr_);
314             }
315             return false;
316         }
317
318         template <typename Context, typename Skipper
319           , typename Attribute, typename Params>
320         bool parse(Iterator& first, Iterator const& last
321           , Context& caller_context, Skipper const& skipper
322           , Attribute& attr_param, Params const& params) const
323         {
324             if (f)
325             {
326                 // do a preskip if this is an implied lexeme
327                 if (is_same<skipper_type, unused_type>::value)
328                     qi::skip_over(first, last, skipper);
329
330                 typedef traits::make_attribute<attr_type, Attribute> make_attribute;
331
332                 // do down-stream transformation, provides attribute for
333                 // rhs parser
334                 typedef traits::transform_attribute<
335                     typename make_attribute::type, attr_type, domain>
336                 transform;
337
338                 typename make_attribute::type made_attr = make_attribute::call(attr_param);
339                 typename transform::type attr_ = transform::pre(made_attr);
340
341                 // If you are seeing a compilation error here, you are probably
342                 // trying to use a rule or a grammar which has inherited
343                 // attributes, passing values of incompatible types for them.
344                 context_type context(attr_, params, caller_context);
345
346                 // If you are seeing a compilation error here stating that the
347                 // fourth parameter can't be converted to a required target type
348                 // then you are probably trying to use a rule or a grammar with
349                 // an incompatible skipper type.
350                 if (f(first, last, context, skipper))
351                 {
352                     // do up-stream transformation, this integrates the results
353                     // back into the original attribute value, if appropriate
354                     traits::post_transform(attr_param, attr_);
355                     return true;
356                 }
357
358                 // inform attribute transformation of failed rhs
359                 traits::fail_transform(attr_param, attr_);
360             }
361             return false;
362         }
363
364         template <typename Context>
365         info what(Context& /*context*/) const
366         {
367             return info(name_);
368         }
369
370         reference_ alias() const
371         {
372             return reference_(*this);
373         }
374
375         typename proto::terminal<this_type>::type copy() const
376         {
377             typename proto::terminal<this_type>::type result = {*this};
378             return result;
379         }
380
381         // bring in the operator() overloads
382         rule const& get_parameterized_subject() const { return *this; }
383         typedef rule parameterized_subject_type;
384         #include <boost/spirit/home/qi/nonterminal/detail/fcall.hpp>
385
386         std::string name_;
387         function_type f;
388     };
389
390 #if BOOST_WORKAROUND(BOOST_MSVC, < 1400)
391     template <typename OutputIterator_, typename T1_, typename T2_
392       , typename T3_, typename T4_, typename Expr>
393     rule<OutputIterator_, T1_, T2_, T3_, T4_>& operator%=(
394         rule<OutputIterator_, T1_, T2_, T3_, T4_>& r, Expr const& expr)
395     {
396         // Report invalid expression error as early as possible.
397         // If you got an error_invalid_expression error message here,
398         // then the expression (expr) is not a valid spirit qi expression.
399         BOOST_SPIRIT_ASSERT_MATCH(qi::domain, Expr);
400
401         typedef typename
402             rule<OutputIterator_, T1_, T2_, T3_, T4_>::encoding_modifier_type
403         encoding_modifier_type;
404
405         r.f = detail::bind_parser<mpl::true_>(
406             compile<qi::domain>(expr, encoding_modifier_type()));
407         return r;
408     }
409
410     template <typename Iterator_, typename T1_, typename T2_
411       , typename T3_, typename T4_, typename Expr>
412     rule<Iterator_, T1_, T2_, T3_, T4_>& operator%=(
413         rule<Iterator_, T1_, T2_, T3_, T4_>& r, Expr& expr)
414     {
415         return r %= static_cast<Expr const&>(expr);
416     }
417 #endif
418 }}}
419
420 namespace boost { namespace spirit { namespace traits
421 {
422     ///////////////////////////////////////////////////////////////////////////
423     template <
424         typename IteratorA, typename IteratorB, typename Attribute
425       , typename Context, typename T1, typename T2, typename T3, typename T4>
426     struct handles_container<
427         qi::rule<IteratorA, T1, T2, T3, T4>, Attribute, Context, IteratorB>
428       : traits::is_container<
429           typename attribute_of<
430               qi::rule<IteratorA, T1, T2, T3, T4>, Context, IteratorB
431           >::type
432         >
433     {};
434 }}}
435
436 #if defined(BOOST_MSVC)
437 # pragma warning(pop)
438 #endif
439
440 #endif