1 /*=============================================================================
2 Copyright (c) 2001-2011 Joel de Guzman
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
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>
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>
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>
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
49 namespace boost { namespace spirit { namespace qi
51 BOOST_PP_REPEAT(SPIRIT_ATTRIBUTES_LIMIT, SPIRIT_USING_ATTRIBUTE, _)
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;
66 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
87 typename Iterator, typename T1, typename T2, typename T3
91 typename proto::terminal<
92 reference<rule<Iterator, T1, T2, T3, T4> const>
94 , rule<Iterator, T1, T2, T3, T4>
96 , parser<rule<Iterator, T1, T2, T3, T4> >
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;
105 // The rule's locals_type: a sequence of types to be used as local variables
107 spirit::detail::extract_locals<template_params>::type
110 // The rule's skip-parser type
112 spirit::detail::extract_component<
113 qi::domain, template_params>::type
116 // The rule's encoding type
118 spirit::detail::extract_encoding<template_params>::type
121 // The rule's signature
123 spirit::detail::extract_sig<template_params, encoding_type, qi::domain>::type
126 // This is the rule's attribute type
128 spirit::detail::attr_from_sig<sig_type>::type
130 typedef typename add_reference<attr_type>::type attr_reference_type;
132 // parameter_types is a sequence of types passed as parameters to the rule
134 spirit::detail::params_from_sig<sig_type>::type
137 static size_t const params_size =
138 fusion::result_of::size<parameter_types>::type::value;
141 fusion::cons<attr_reference_type, parameter_types>
146 bool(Iterator& first, Iterator const& last
147 , context_type& context
148 , skipper_type const& skipper
154 is_same<encoding_type, unused_type>
156 , tag::char_code<tag::encoding, encoding_type>
158 encoding_modifier_type;
160 explicit rule(std::string const& name = "unnamed-rule")
161 : base_type(terminal::make(reference_(*this)))
166 rule(rule const& rhs)
167 : base_type(terminal::make(reference_(*this)))
173 template <typename Auto, typename Expr>
174 static void define(rule& /*lhs*/, Expr const& /*expr*/, mpl::false_)
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);
182 template <typename Auto, typename Expr>
183 static void define(rule& lhs, Expr const& expr, mpl::true_)
185 lhs.f = detail::bind_parser<Auto>(
186 compile<qi::domain>(expr, encoding_modifier_type()));
189 template <typename Expr>
190 rule(Expr const& expr, std::string const& name = "unnamed-rule")
191 : base_type(terminal::make(reference_(*this)))
194 define<mpl::false_>(*this, expr, traits::matches<qi::domain, Expr>());
197 rule& operator=(rule const& rhs)
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?");
210 std::string const& name() const
215 void name(std::string const& str)
220 template <typename Expr>
221 rule& operator=(Expr const& expr)
223 define<mpl::false_>(*this, expr, traits::matches<qi::domain, Expr>());
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)
233 define<mpl::true_>(r, expr, traits::matches<qi::domain, Expr>());
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)
242 return r %= static_cast<Expr const&>(expr);
245 // for rvalue references
246 template <typename Expr>
247 friend rule& operator%=(rule& r, Expr&& expr)
249 define<mpl::true_>(r, expr, traits::matches<qi::domain, Expr>());
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);
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);
269 template <typename Context, typename Iterator_>
272 typedef attr_type type;
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
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");
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);
294 // do down-stream transformation, provides attribute for
296 typedef traits::transform_attribute<
297 Attribute, attr_type, domain>
300 typename transform::type attr_ = transform::pre(attr_param);
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_);
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))
313 // do up-stream transformation, this integrates the results
314 // back into the original attribute value, if appropriate
315 transform::post(attr_param, attr_);
319 // inform attribute transformation of failed rhs
320 transform::fail(attr_param);
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
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");
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);
345 // do down-stream transformation, provides attribute for
347 typedef traits::transform_attribute<
348 Attribute, attr_type, domain>
351 typename transform::type attr_ = transform::pre(attr_param);
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);
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))
364 // do up-stream transformation, this integrates the results
365 // back into the original attribute value, if appropriate
366 transform::post(attr_param, attr_);
370 // inform attribute transformation of failed rhs
371 transform::fail(attr_param);
376 template <typename Context>
377 info what(Context& /*context*/) const
382 reference_ alias() const
384 return reference_(*this);
387 typename proto::terminal<this_type>::type copy() const
389 typename proto::terminal<this_type>::type result = {*this};
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>
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)
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);
414 rule<OutputIterator_, T1_, T2_, T3_, T4_>::encoding_modifier_type
415 encoding_modifier_type;
417 r.f = detail::bind_parser<mpl::true_>(
418 compile<qi::domain>(expr, encoding_modifier_type()));
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)
427 return r %= static_cast<Expr const&>(expr);
432 namespace boost { namespace spirit { namespace traits
434 ///////////////////////////////////////////////////////////////////////////
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
448 #if defined(BOOST_MSVC)
449 # pragma warning(pop)