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