]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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> | |
92f5a8d4 | 15 | #include <boost/static_assert.hpp> |
7c673cae FG |
16 | #include <boost/config.hpp> |
17 | #include <boost/function.hpp> | |
18 | #include <boost/mpl/vector.hpp> | |
92f5a8d4 | 19 | #include <boost/type_traits/is_convertible.hpp> |
7c673cae FG |
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 | ||
f67539c2 TL |
42 | #include <boost/proto/extends.hpp> |
43 | #include <boost/proto/traits.hpp> | |
44 | #include <boost/type_traits/is_reference.hpp> | |
45 | ||
7c673cae FG |
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; | |
f67539c2 TL |
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; | |
7c673cae FG |
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 | ||
166 | explicit rule(std::string const& name = "unnamed-rule") | |
167 | : base_type(terminal::make(reference_(*this))) | |
168 | , name_(name) | |
169 | { | |
170 | } | |
171 | ||
172 | 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> | |
180 | 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> | |
189 | 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> | |
196 | 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 | ||
203 | 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 | ||
216 | std::string const& name() const | |
217 | { | |
218 | return name_; | |
219 | } | |
220 | ||
221 | void name(std::string const& str) | |
222 | { | |
223 | name_ = str; | |
224 | } | |
225 | ||
226 | template <typename Expr> | |
227 | 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> | |
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> | |
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> | |
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> | |
282 | bool parse(Iterator& first, Iterator const& last | |
283 | , Context& /*context*/, Skipper const& skipper | |
284 | , Attribute& attr_param) const | |
285 | { | |
92f5a8d4 TL |
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"); | |
7c673cae FG |
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 | ||
7c673cae FG |
300 | // do down-stream transformation, provides attribute for |
301 | // rhs parser | |
302 | typedef traits::transform_attribute< | |
92f5a8d4 | 303 | Attribute, attr_type, domain> |
7c673cae FG |
304 | transform; |
305 | ||
92f5a8d4 | 306 | typename transform::type attr_ = transform::pre(attr_param); |
7c673cae FG |
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 | |
92f5a8d4 | 321 | transform::post(attr_param, attr_); |
7c673cae FG |
322 | return true; |
323 | } | |
324 | ||
325 | // inform attribute transformation of failed rhs | |
92f5a8d4 | 326 | transform::fail(attr_param); |
7c673cae FG |
327 | } |
328 | return false; | |
329 | } | |
330 | ||
331 | template <typename Context, typename Skipper | |
332 | , typename Attribute, typename Params> | |
333 | bool parse(Iterator& first, Iterator const& last | |
334 | , Context& caller_context, Skipper const& skipper | |
335 | , Attribute& attr_param, Params const& params) const | |
336 | { | |
92f5a8d4 TL |
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"); | |
7c673cae FG |
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 | ||
7c673cae FG |
351 | // do down-stream transformation, provides attribute for |
352 | // rhs parser | |
353 | typedef traits::transform_attribute< | |
92f5a8d4 | 354 | Attribute, attr_type, domain> |
7c673cae FG |
355 | transform; |
356 | ||
92f5a8d4 | 357 | typename transform::type attr_ = transform::pre(attr_param); |
7c673cae FG |
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 | |
92f5a8d4 | 372 | transform::post(attr_param, attr_); |
7c673cae FG |
373 | return true; |
374 | } | |
375 | ||
376 | // inform attribute transformation of failed rhs | |
92f5a8d4 | 377 | transform::fail(attr_param); |
7c673cae FG |
378 | } |
379 | return false; | |
380 | } | |
381 | ||
382 | template <typename Context> | |
383 | info what(Context& /*context*/) const | |
384 | { | |
385 | return info(name_); | |
386 | } | |
387 | ||
388 | reference_ alias() const | |
389 | { | |
390 | return reference_(*this); | |
391 | } | |
392 | ||
393 | 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 | |
400 | 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> | |
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> | |
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 |