]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Copyright (c) 2001-2011 Joel de Guzman |
2 | // Copyright (c) 2001-2011 Hartmut Kaiser | |
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_KARMA_RULE_MAR_05_2007_0455PM) | |
8 | #define BOOST_SPIRIT_KARMA_RULE_MAR_05_2007_0455PM | |
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_const.hpp> | |
19 | #include <boost/type_traits/add_reference.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/karma/delimit_out.hpp> | |
34 | #include <boost/spirit/home/karma/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/karma/reference.hpp> | |
38 | #include <boost/spirit/home/karma/detail/output_iterator.hpp> | |
39 | #include <boost/spirit/home/karma/nonterminal/nonterminal_fwd.hpp> | |
40 | #include <boost/spirit/home/karma/nonterminal/detail/generator_binder.hpp> | |
41 | #include <boost/spirit/home/karma/nonterminal/detail/parameterized.hpp> | |
42 | ||
43 | #if defined(BOOST_MSVC) | |
44 | # pragma warning(push) | |
45 | # pragma warning(disable: 4127) // conditional expression is constant | |
46 | # pragma warning(disable: 4355) // 'this' : used in base member initializer list warning | |
47 | #endif | |
48 | ||
49 | namespace boost { namespace spirit { namespace karma | |
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 OutputIterator, typename T1, typename T2, typename T3 | |
88 | , typename T4> | |
89 | struct rule | |
90 | : proto::extends< | |
91 | typename proto::terminal< | |
92 | reference<rule<OutputIterator, T1, T2, T3, T4> const> | |
93 | >::type | |
94 | , rule<OutputIterator, T1, T2, T3, T4> | |
95 | > | |
96 | , generator<rule<OutputIterator, T1, T2, T3, T4> > | |
97 | { | |
98 | typedef mpl::int_<generator_properties::all_properties> properties; | |
99 | ||
100 | typedef OutputIterator iterator_type; | |
101 | typedef rule<OutputIterator, T1, T2, T3, T4> this_type; | |
102 | typedef reference<this_type const> reference_; | |
103 | typedef typename proto::terminal<reference_>::type terminal; | |
104 | typedef proto::extends<terminal, this_type> base_type; | |
105 | typedef mpl::vector<T1, T2, T3, T4> template_params; | |
106 | ||
107 | // the output iterator is always wrapped by karma | |
108 | typedef detail::output_iterator<OutputIterator, properties> | |
109 | output_iterator; | |
110 | ||
111 | // locals_type is a sequence of types to be used as local variables | |
112 | typedef typename | |
113 | spirit::detail::extract_locals<template_params>::type | |
114 | locals_type; | |
115 | ||
116 | // The delimiter-generator type | |
117 | typedef typename | |
118 | spirit::detail::extract_component< | |
119 | karma::domain, template_params>::type | |
120 | delimiter_type; | |
121 | ||
122 | // The rule's encoding type | |
123 | typedef typename | |
124 | spirit::detail::extract_encoding<template_params>::type | |
125 | encoding_type; | |
126 | ||
127 | // The rule's signature | |
128 | typedef typename | |
129 | spirit::detail::extract_sig<template_params, encoding_type, karma::domain>::type | |
130 | sig_type; | |
131 | ||
132 | // This is the rule's attribute type | |
133 | typedef typename | |
134 | spirit::detail::attr_from_sig<sig_type>::type | |
135 | attr_type; | |
136 | typedef typename add_reference< | |
137 | typename add_const<attr_type>::type>::type | |
138 | attr_reference_type; | |
139 | ||
140 | // parameter_types is a sequence of types passed as parameters to the rule | |
141 | typedef typename | |
142 | spirit::detail::params_from_sig<sig_type>::type | |
143 | parameter_types; | |
144 | ||
145 | static size_t const params_size = | |
146 | fusion::result_of::size<parameter_types>::type::value; | |
147 | ||
148 | // the context passed to the right hand side of a rule contains | |
149 | // the attribute and the parameters for this particular rule invocation | |
150 | typedef context< | |
151 | fusion::cons<attr_reference_type, parameter_types> | |
152 | , locals_type> | |
153 | context_type; | |
154 | ||
155 | typedef function< | |
156 | bool(output_iterator&, context_type&, delimiter_type const&)> | |
157 | function_type; | |
158 | ||
159 | typedef typename | |
160 | mpl::if_< | |
161 | is_same<encoding_type, unused_type> | |
162 | , unused_type | |
163 | , tag::char_code<tag::encoding, encoding_type> | |
164 | >::type | |
165 | encoding_modifier_type; | |
166 | ||
167 | explicit rule(std::string const& name_ = "unnamed-rule") | |
168 | : base_type(terminal::make(reference_(*this))) | |
169 | , name_(name_) | |
170 | { | |
171 | } | |
172 | ||
173 | rule(rule const& rhs) | |
174 | : base_type(terminal::make(reference_(*this))) | |
175 | , name_(rhs.name_) | |
176 | , f(rhs.f) | |
177 | { | |
178 | } | |
179 | ||
180 | template <typename Auto, typename Expr> | |
181 | static void define(rule& lhs, Expr const& expr, mpl::false_) | |
182 | { | |
183 | // Report invalid expression error as early as possible. | |
184 | // If you got an error_invalid_expression error message here, | |
185 | // then the expression (expr) is not a valid spirit karma expression. | |
186 | BOOST_SPIRIT_ASSERT_MATCH(karma::domain, Expr); | |
187 | } | |
188 | ||
189 | template <typename Auto, typename Expr> | |
190 | static void define(rule& lhs, Expr const& expr, mpl::true_) | |
191 | { | |
192 | lhs.f = detail::bind_generator<Auto>( | |
193 | compile<karma::domain>(expr, encoding_modifier_type())); | |
194 | } | |
195 | ||
196 | template <typename Expr> | |
197 | rule (Expr const& expr, std::string const& name_ = "unnamed-rule") | |
198 | : base_type(terminal::make(reference_(*this))) | |
199 | , name_(name_) | |
200 | { | |
201 | define<mpl::false_>(*this, expr, traits::matches<karma::domain, Expr>()); | |
202 | } | |
203 | ||
204 | rule& operator=(rule const& rhs) | |
205 | { | |
206 | // The following assertion fires when you try to initialize a rule | |
207 | // from an uninitialized one. Did you mean to refer to the right | |
208 | // hand side rule instead of assigning from it? In this case you | |
209 | // should write lhs = rhs.alias(); | |
210 | BOOST_ASSERT(rhs.f && "Did you mean rhs.alias() instead of rhs?"); | |
211 | ||
212 | f = rhs.f; | |
213 | name_ = rhs.name_; | |
214 | return *this; | |
215 | } | |
216 | ||
217 | std::string const& name() const | |
218 | { | |
219 | return name_; | |
220 | } | |
221 | ||
222 | void name(std::string const& str) | |
223 | { | |
224 | name_ = str; | |
225 | } | |
226 | ||
227 | template <typename Expr> | |
228 | rule& operator=(Expr const& expr) | |
229 | { | |
230 | define<mpl::false_>(*this, expr, traits::matches<karma::domain, Expr>()); | |
231 | return *this; | |
232 | } | |
233 | ||
234 | // VC7.1 has problems to resolve 'rule' without explicit template parameters | |
235 | #if !BOOST_WORKAROUND(BOOST_MSVC, < 1400) | |
236 | // g++ 3.3 barfs if this is a member function :( | |
237 | template <typename Expr> | |
238 | friend rule& operator%=(rule& r, Expr const& expr) | |
239 | { | |
240 | define<mpl::true_>(r, expr, traits::matches<karma::domain, Expr>()); | |
241 | return r; | |
242 | } | |
243 | ||
244 | #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) | |
245 | // non-const version needed to suppress proto's %= kicking in | |
246 | template <typename Expr> | |
247 | friend rule& operator%=(rule& r, Expr& expr) | |
248 | { | |
249 | return r %= static_cast<Expr const&>(expr); | |
250 | } | |
251 | #else | |
252 | // for rvalue references | |
253 | template <typename Expr> | |
254 | friend rule& operator%=(rule& r, Expr&& expr) | |
255 | { | |
256 | define<mpl::true_>(r, expr, traits::matches<karma::domain, Expr>()); | |
257 | return r; | |
258 | } | |
259 | #endif | |
260 | ||
261 | #else | |
262 | // both friend functions have to be defined out of class as VC7.1 | |
263 | // will complain otherwise | |
264 | template <typename OutputIterator_, typename T1_, typename T2_ | |
265 | , typename T3_, typename T4_, typename Expr> | |
266 | friend rule<OutputIterator_, T1_, T2_, T3_, T4_>& operator%=( | |
267 | rule<OutputIterator_, T1_, T2_, T3_, T4_>&r, Expr const& expr); | |
268 | ||
269 | // non-const version needed to suppress proto's %= kicking in | |
270 | template <typename OutputIterator_, typename T1_, typename T2_ | |
271 | , typename T3_, typename T4_, typename Expr> | |
272 | friend rule<OutputIterator_, T1_, T2_, T3_, T4_>& operator%=( | |
273 | rule<OutputIterator_, T1_, T2_, T3_, T4_>& r, Expr& expr); | |
274 | #endif | |
275 | ||
276 | template <typename Context, typename Unused> | |
277 | struct attribute | |
278 | { | |
279 | typedef attr_type type; | |
280 | }; | |
281 | ||
282 | template <typename Context, typename Delimiter, typename Attribute> | |
283 | bool generate(output_iterator& sink, Context&, Delimiter const& delim | |
284 | , Attribute const& attr) const | |
285 | { | |
286 | if (f) | |
287 | { | |
288 | // Create an attribute if none is supplied. | |
289 | typedef traits::make_attribute<attr_type, Attribute> | |
290 | make_attribute; | |
291 | typedef traits::transform_attribute< | |
292 | typename make_attribute::type, attr_type, domain> | |
293 | transform; | |
294 | ||
295 | typename transform::type attr_ = | |
296 | traits::pre_transform<domain, attr_type>( | |
297 | make_attribute::call(attr)); | |
298 | ||
299 | // If you are seeing a compilation error here, you are probably | |
300 | // trying to use a rule or a grammar which has inherited | |
301 | // attributes, without passing values for them. | |
302 | context_type context(attr_); | |
303 | ||
304 | // If you are seeing a compilation error here stating that the | |
305 | // third parameter can't be converted to a karma::reference | |
306 | // then you are probably trying to use a rule or a grammar with | |
307 | // an incompatible delimiter type. | |
308 | if (f(sink, context, delim)) | |
309 | { | |
310 | // do a post-delimit if this is an implied verbatim | |
311 | if (is_same<delimiter_type, unused_type>::value) | |
312 | karma::delimit_out(sink, delim); | |
313 | ||
314 | return true; | |
315 | } | |
316 | } | |
317 | return false; | |
318 | } | |
319 | ||
320 | template <typename Context, typename Delimiter, typename Attribute | |
321 | , typename Params> | |
322 | bool generate(output_iterator& sink, Context& caller_context | |
323 | , Delimiter const& delim, Attribute const& attr | |
324 | , Params const& params) const | |
325 | { | |
326 | if (f) | |
327 | { | |
328 | // Create an attribute if none is supplied. | |
329 | typedef traits::make_attribute<attr_type, Attribute> | |
330 | make_attribute; | |
331 | typedef traits::transform_attribute< | |
332 | typename make_attribute::type, attr_type, domain> | |
333 | transform; | |
334 | ||
335 | typename transform::type attr_ = | |
336 | traits::pre_transform<domain, attr_type>( | |
337 | make_attribute::call(attr)); | |
338 | ||
339 | // If you are seeing a compilation error here, you are probably | |
340 | // trying to use a rule or a grammar which has inherited | |
341 | // attributes, passing values of incompatible types for them. | |
342 | context_type context(attr_, params, caller_context); | |
343 | ||
344 | // If you are seeing a compilation error here stating that the | |
345 | // third parameter can't be converted to a karma::reference | |
346 | // then you are probably trying to use a rule or a grammar with | |
347 | // an incompatible delimiter type. | |
348 | if (f(sink, context, delim)) | |
349 | { | |
350 | // do a post-delimit if this is an implied verbatim | |
351 | if (is_same<delimiter_type, unused_type>::value) | |
352 | karma::delimit_out(sink, delim); | |
353 | ||
354 | return true; | |
355 | } | |
356 | } | |
357 | return false; | |
358 | } | |
359 | ||
360 | template <typename Context> | |
361 | info what(Context& /*context*/) const | |
362 | { | |
363 | return info(name_); | |
364 | } | |
365 | ||
366 | reference_ alias() const | |
367 | { | |
368 | return reference_(*this); | |
369 | } | |
370 | ||
371 | typename proto::terminal<this_type>::type copy() const | |
372 | { | |
373 | typename proto::terminal<this_type>::type result = {*this}; | |
374 | return result; | |
375 | } | |
376 | ||
377 | // bring in the operator() overloads | |
378 | rule const& get_parameterized_subject() const { return *this; } | |
379 | typedef rule parameterized_subject_type; | |
380 | #include <boost/spirit/home/karma/nonterminal/detail/fcall.hpp> | |
381 | ||
382 | std::string name_; | |
383 | function_type f; | |
384 | }; | |
385 | ||
386 | #if BOOST_WORKAROUND(BOOST_MSVC, < 1400) | |
387 | template <typename OutputIterator_, typename T1_, typename T2_ | |
388 | , typename T3_, typename T4_, typename Expr> | |
389 | rule<OutputIterator_, T1_, T2_, T3_, T4_>& operator%=( | |
390 | rule<OutputIterator_, T1_, T2_, T3_, T4_>&r, Expr const& expr) | |
391 | { | |
392 | // Report invalid expression error as early as possible. | |
393 | // If you got an error_invalid_expression error message here, then | |
394 | // the expression (expr) is not a valid spirit karma expression. | |
395 | BOOST_SPIRIT_ASSERT_MATCH(karma::domain, Expr); | |
396 | ||
397 | typedef typename | |
398 | rule<OutputIterator_, T1_, T2_, T3_, T4_>::encoding_modifier_type | |
399 | encoding_modifier_type; | |
400 | ||
401 | r.f = detail::bind_generator<mpl::true_>( | |
402 | compile<karma::domain>(expr, encoding_modifier_type())); | |
403 | return r; | |
404 | } | |
405 | ||
406 | // non-const version needed to suppress proto's %= kicking in | |
407 | template <typename OutputIterator_, typename T1_, typename T2_ | |
408 | , typename T3_, typename T4_, typename Expr> | |
409 | rule<OutputIterator_, T1_, T2_, T3_, T4_>& operator%=( | |
410 | rule<OutputIterator_, T1_, T2_, T3_, T4_>& r, Expr& expr) | |
411 | { | |
412 | return r %= static_cast<Expr const&>(expr); | |
413 | } | |
414 | #endif | |
415 | }}} | |
416 | ||
417 | namespace boost { namespace spirit { namespace traits | |
418 | { | |
419 | namespace detail | |
420 | { | |
421 | template <typename RuleAttribute, typename Attribute> | |
422 | struct nonterminal_handles_container | |
423 | : mpl::and_< | |
424 | traits::is_container<RuleAttribute> | |
425 | , is_convertible<Attribute, RuleAttribute> > | |
426 | {}; | |
427 | } | |
428 | ||
429 | /////////////////////////////////////////////////////////////////////////// | |
430 | template < | |
431 | typename IteratorA, typename IteratorB, typename Attribute | |
432 | , typename Context, typename T1, typename T2, typename T3, typename T4> | |
433 | struct handles_container< | |
434 | karma::rule<IteratorA, T1, T2, T3, T4>, Attribute, Context | |
435 | , IteratorB> | |
436 | : detail::nonterminal_handles_container< | |
437 | typename attribute_of< | |
438 | karma::rule<IteratorA, T1, T2, T3, T4> | |
439 | , Context, IteratorB | |
440 | >::type, Attribute> | |
441 | {}; | |
442 | }}} | |
443 | ||
444 | #if defined(BOOST_MSVC) | |
445 | # pragma warning(pop) | |
446 | #endif | |
447 | ||
448 | #endif |