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