]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/spirit/repository/home/karma/nonterminal/subrule.hpp
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / boost / boost / spirit / repository / home / karma / nonterminal / subrule.hpp
1 // Copyright (c) 2009 Francois Barel
2 // Copyright (c) 2001-2011 Joel de Guzman
3 // Copyright (c) 2001-2012 Hartmut Kaiser
4 //
5 // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7
8 #if !defined(BOOST_SPIRIT_REPOSITORY_KARMA_SUBRULE_AUGUST_12_2009_0813PM)
9 #define BOOST_SPIRIT_REPOSITORY_KARMA_SUBRULE_AUGUST_12_2009_0813PM
10
11 #if defined(_MSC_VER)
12 #pragma once
13 #endif
14
15 #include <boost/spirit/home/karma/domain.hpp>
16 #include <boost/spirit/home/karma/meta_compiler.hpp>
17 #include <boost/spirit/home/karma/generator.hpp>
18 #include <boost/spirit/home/karma/reference.hpp>
19 #include <boost/spirit/home/karma/nonterminal/detail/generator_binder.hpp>
20 #include <boost/spirit/home/karma/nonterminal/detail/parameterized.hpp>
21 #include <boost/spirit/home/support/argument.hpp>
22 #include <boost/spirit/home/support/assert_msg.hpp>
23 #include <boost/spirit/home/karma/detail/attributes.hpp>
24 #include <boost/spirit/home/support/info.hpp>
25 #include <boost/spirit/home/support/unused.hpp>
26 #include <boost/spirit/home/support/nonterminal/extract_param.hpp>
27 #include <boost/spirit/home/support/nonterminal/locals.hpp>
28 #include <boost/spirit/repository/home/support/subrule_context.hpp>
29
30 #include <boost/static_assert.hpp>
31 #include <boost/fusion/include/as_map.hpp>
32 #include <boost/fusion/include/at_key.hpp>
33 #include <boost/fusion/include/cons.hpp>
34 #include <boost/fusion/include/front.hpp>
35 #include <boost/fusion/include/has_key.hpp>
36 #include <boost/fusion/include/join.hpp>
37 #include <boost/fusion/include/make_map.hpp>
38 #include <boost/fusion/include/make_vector.hpp>
39 #include <boost/fusion/include/size.hpp>
40 #include <boost/fusion/include/vector.hpp>
41 #include <boost/mpl/bool.hpp>
42 #include <boost/mpl/identity.hpp>
43 #include <boost/mpl/int.hpp>
44 #include <boost/mpl/vector.hpp>
45 #include <boost/proto/extends.hpp>
46 #include <boost/proto/traits.hpp>
47 #include <boost/type_traits/is_const.hpp>
48 #include <boost/type_traits/is_reference.hpp>
49 #include <boost/type_traits/is_same.hpp>
50 #include <boost/type_traits/remove_reference.hpp>
51
52 #if defined(BOOST_MSVC)
53 # pragma warning(push)
54 # pragma warning(disable: 4355) // 'this' : used in base member initializer list warning
55 #endif
56
57 ///////////////////////////////////////////////////////////////////////////////
58 namespace boost { namespace spirit { namespace repository { namespace karma
59 {
60 ///////////////////////////////////////////////////////////////////////////
61 // subrule_group_generator:
62 // - generator representing a group of subrule definitions (one or more),
63 // invokes first subrule on entry,
64 ///////////////////////////////////////////////////////////////////////////
65 template <typename Defs>
66 struct subrule_group_generator
67 : spirit::karma::generator<subrule_group_generator<Defs> >
68 {
69 // Fusion associative sequence, associating each subrule ID in this
70 // group (as an MPL integral constant) with its definition
71 typedef Defs defs_type;
72
73 typedef subrule_group_generator<Defs> this_type;
74
75 explicit subrule_group_generator(Defs const& defs)
76 : defs(defs)
77 {
78 }
79 // from a subrule ID, get the type of a reference to its definition
80 template <int ID>
81 struct def_type
82 {
83 typedef mpl::int_<ID> id_type;
84
85 // If you are seeing a compilation error here, you are trying
86 // to use a subrule which was not defined in this group.
87 BOOST_SPIRIT_ASSERT_MSG(
88 (fusion::result_of::has_key<
89 defs_type const, id_type>::type::value)
90 , subrule_used_without_being_defined, (mpl::int_<ID>));
91
92 typedef typename
93 fusion::result_of::at_key<defs_type const, id_type>::type
94 type;
95 };
96
97 // from a subrule ID, get a reference to its definition
98 template <int ID>
99 typename def_type<ID>::type def() const
100 {
101 return fusion::at_key<mpl::int_<ID> >(defs);
102 }
103
104 template <typename Context, typename Iterator>
105 struct attribute
106 // Forward to first subrule.
107 : mpl::identity<
108 typename remove_reference<
109 typename fusion::result_of::front<Defs>::type
110 >::type::second_type::attr_type> {};
111
112 template <typename OutputIterator, typename Context
113 , typename Delimiter, typename Attribute>
114 bool generate(OutputIterator& sink, Context& context
115 , Delimiter const& delimiter, Attribute const& attr) const
116 {
117 // Forward to first subrule.
118 return generate_subrule(fusion::front(defs).second
119 , sink, context, delimiter, attr);
120 }
121
122 template <typename OutputIterator, typename Context
123 , typename Delimiter, typename Attribute
124 , typename Params>
125 bool generate(OutputIterator& sink, Context& context
126 , Delimiter const& delimiter, Attribute const& attr
127 , Params const& params) const
128 {
129 // Forward to first subrule.
130 return generate_subrule(fusion::front(defs).second
131 , sink, context, delimiter, attr, params);
132 }
133
134 template <int ID, typename OutputIterator, typename Context
135 , typename Delimiter, typename Attribute>
136 bool generate_subrule_id(OutputIterator& sink
137 , Context& context, Delimiter const& delimiter
138 , Attribute const& attr) const
139 {
140 return generate_subrule(def<ID>()
141 , sink, context, delimiter, attr);
142 }
143
144 template <int ID, typename OutputIterator, typename Context
145 , typename Delimiter, typename Attribute, typename Params>
146 bool generate_subrule_id(OutputIterator& sink
147 , Context& context, Delimiter const& delimiter
148 , Attribute const& attr, Params const& params) const
149 {
150 return generate_subrule(def<ID>()
151 , sink, context, delimiter, attr, params);
152 }
153
154 template <typename Def, typename OutputIterator, typename Context
155 , typename Delimiter, typename Attribute>
156 bool generate_subrule(Def const& def, OutputIterator& sink
157 , Context& /*caller_context*/, Delimiter const& delimiter
158 , Attribute const& attr) const
159 {
160 // compute context type for this subrule
161 typedef typename Def::locals_type subrule_locals_type;
162 typedef typename Def::attr_type subrule_attr_type;
163 typedef typename Def::attr_reference_type subrule_attr_reference_type;
164 typedef typename Def::parameter_types subrule_parameter_types;
165
166 typedef
167 subrule_context<
168 this_type
169 , fusion::cons<
170 subrule_attr_reference_type, subrule_parameter_types>
171 , subrule_locals_type
172 >
173 context_type;
174
175 typedef traits::transform_attribute<Attribute const
176 , subrule_attr_type, spirit::karma::domain> transform;
177
178 // If you are seeing a compilation error here, you are probably
179 // trying to use a subrule which has inherited attributes,
180 // without passing values for them.
181 context_type context(*this, transform::pre(attr));
182
183 return def.binder(sink, context, delimiter);
184 }
185
186 template <typename Def, typename OutputIterator, typename Context
187 , typename Delimiter, typename Attribute, typename Params>
188 bool generate_subrule(Def const& def, OutputIterator& sink
189 , Context& caller_context, Delimiter const& delimiter
190 , Attribute const& attr, Params const& params) const
191 {
192 // compute context type for this subrule
193 typedef typename Def::locals_type subrule_locals_type;
194 typedef typename Def::attr_type subrule_attr_type;
195 typedef typename Def::attr_reference_type subrule_attr_reference_type;
196 typedef typename Def::parameter_types subrule_parameter_types;
197
198 typedef
199 subrule_context<
200 this_type
201 , fusion::cons<
202 subrule_attr_reference_type, subrule_parameter_types>
203 , subrule_locals_type
204 >
205 context_type;
206
207 typedef traits::transform_attribute<Attribute const
208 , subrule_attr_type, spirit::karma::domain> transform;
209
210 // If you are seeing a compilation error here, you are probably
211 // trying to use a subrule which has inherited attributes,
212 // passing values of incompatible types for them.
213 context_type context(*this
214 , transform::pre(attr), params, caller_context);
215
216 return def.binder(sink, context, delimiter);
217 }
218
219 template <typename Context>
220 info what(Context& context) const
221 {
222 // Forward to first subrule.
223 return fusion::front(defs).second.binder.g.what(context);
224 }
225
226 Defs defs;
227 };
228
229 ///////////////////////////////////////////////////////////////////////////
230 // subrule_group:
231 // - a Proto terminal, so that a group behaves like any Spirit
232 // expression.
233 ///////////////////////////////////////////////////////////////////////////
234 template <typename Defs>
235 struct subrule_group
236 : proto::extends<
237 typename proto::terminal<
238 subrule_group_generator<Defs>
239 >::type
240 , subrule_group<Defs>
241 >
242 {
243 typedef subrule_group_generator<Defs> generator_type;
244 typedef typename proto::terminal<generator_type>::type terminal;
245
246 struct properties
247 // Forward to first subrule.
248 : remove_reference<
249 typename fusion::result_of::front<Defs>::type
250 >::type::second_type::subject_type::properties {};
251
252 static size_t const params_size =
253 // Forward to first subrule.
254 remove_reference<
255 typename fusion::result_of::front<Defs>::type
256 >::type::second_type::params_size;
257
258 explicit subrule_group(Defs const& defs)
259 : subrule_group::proto_extends(terminal::make(generator_type(defs)))
260 {
261 }
262
263 generator_type const& generator() const { return proto::value(*this); }
264
265 Defs const& defs() const { return generator().defs; }
266
267 template <typename Defs2>
268 subrule_group<
269 typename fusion::result_of::as_map<
270 typename fusion::result_of::join<
271 Defs const, Defs2 const>::type>::type>
272 operator,(subrule_group<Defs2> const& other) const
273 {
274 typedef subrule_group<
275 typename fusion::result_of::as_map<
276 typename fusion::result_of::join<
277 Defs const, Defs2 const>::type>::type> result_type;
278 return result_type(fusion::as_map(fusion::join(defs(), other.defs())));
279 }
280
281 // non-const versions needed to suppress proto's comma op kicking in
282 template <typename Defs2>
283 friend subrule_group<
284 typename fusion::result_of::as_map<
285 typename fusion::result_of::join<
286 Defs const, Defs2 const>::type>::type>
287 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
288 operator,(subrule_group&& left, subrule_group<Defs2>&& other)
289 #else
290 operator,(subrule_group& left, subrule_group<Defs2>& other)
291 #endif
292 {
293 return static_cast<subrule_group const&>(left)
294 .operator,(static_cast<subrule_group<Defs2> const&>(other));
295 }
296
297 // bring in the operator() overloads
298 generator_type const& get_parameterized_subject() const { return generator(); }
299 typedef generator_type parameterized_subject_type;
300 #include <boost/spirit/home/karma/nonterminal/detail/fcall.hpp>
301 };
302
303 ///////////////////////////////////////////////////////////////////////////
304 // subrule_definition: holds one particular definition of a subrule
305 ///////////////////////////////////////////////////////////////////////////
306 template <
307 int ID_
308 , typename Locals
309 , typename Attr
310 , typename AttrRef
311 , typename Parameters
312 , size_t ParamsSize
313 , typename Subject
314 , bool Auto_
315 >
316 struct subrule_definition
317 {
318 typedef mpl::int_<ID_> id_type;
319 BOOST_STATIC_CONSTANT(int, ID = ID_);
320
321 typedef Locals locals_type;
322 typedef Attr attr_type;
323 typedef AttrRef attr_reference_type;
324 typedef Parameters parameter_types;
325 static size_t const params_size = ParamsSize;
326
327 typedef Subject subject_type;
328 typedef mpl::bool_<Auto_> auto_type;
329 BOOST_STATIC_CONSTANT(bool, Auto = Auto_);
330
331 typedef spirit::karma::detail::generator_binder<
332 Subject, auto_type> binder_type;
333
334 subrule_definition(Subject const& subject, std::string const& name)
335 : binder(subject), name(name)
336 {
337 }
338
339 binder_type const binder;
340 std::string const name;
341 };
342
343 ///////////////////////////////////////////////////////////////////////////
344 // subrule placeholder:
345 // - on subrule definition: helper for creation of subrule_group,
346 // - on subrule invocation: Proto terminal and generator.
347 ///////////////////////////////////////////////////////////////////////////
348 template <
349 int ID_
350 , typename T1 = unused_type
351 , typename T2 = unused_type
352 >
353 struct subrule
354 : proto::extends<
355 typename proto::terminal<
356 spirit::karma::reference<subrule<ID_, T1, T2> const>
357 >::type
358 , subrule<ID_, T1, T2>
359 >
360 , spirit::karma::generator<subrule<ID_, T1, T2> >
361 {
362 //FIXME should go fetch the real properties of this subrule's definition in the current context, but we don't
363 // have the context here (properties would need to be 'template<typename Context> struct properties' instead)
364 typedef mpl::int_<
365 spirit::karma::generator_properties::all_properties> properties;
366
367 typedef mpl::int_<ID_> id_type;
368 BOOST_STATIC_CONSTANT(int, ID = ID_);
369
370 typedef subrule<ID_, T1, T2> this_type;
371 typedef spirit::karma::reference<this_type const> reference_;
372 typedef typename proto::terminal<reference_>::type terminal;
373 typedef proto::extends<terminal, this_type> base_type;
374
375 typedef mpl::vector<T1, T2> template_params;
376
377 // The subrule's locals_type: a sequence of types to be used as local variables
378 typedef typename
379 spirit::detail::extract_locals<template_params>::type
380 locals_type;
381
382 // The subrule's encoding type
383 typedef typename
384 spirit::detail::extract_encoding<template_params>::type
385 encoding_type;
386
387 // The subrule's signature
388 typedef typename
389 spirit::detail::extract_sig<template_params, encoding_type
390 , spirit::karma::domain>::type
391 sig_type;
392
393 // This is the subrule's attribute type
394 typedef typename
395 spirit::detail::attr_from_sig<sig_type>::type
396 attr_type;
397 BOOST_STATIC_ASSERT_MSG(
398 !is_reference<attr_type>::value && !is_const<attr_type>::value,
399 "Const/reference qualifiers on Karma subrule attribute are meaningless");
400 typedef attr_type const& attr_reference_type;
401
402 // parameter_types is a sequence of types passed as parameters to the subrule
403 typedef typename
404 spirit::detail::params_from_sig<sig_type>::type
405 parameter_types;
406
407 static size_t const params_size =
408 fusion::result_of::size<parameter_types>::type::value;
409
410 explicit subrule(std::string const& name_ = "unnamed-subrule")
411 : base_type(terminal::make(reference_(*this)))
412 , name_(name_)
413 {
414 }
415
416 // compute type of this subrule's definition for expr type Expr
417 template <typename Expr, bool Auto>
418 struct def_type_helper
419 {
420 // Report invalid expression error as early as possible.
421 // If you got an error_invalid_expression error message here,
422 // then the expression (Expr) is not a valid spirit karma expression.
423 BOOST_SPIRIT_ASSERT_MATCH(spirit::karma::domain, Expr);
424
425 typedef typename result_of::compile<
426 spirit::karma::domain, Expr>::type subject_type;
427
428 typedef subrule_definition<
429 ID_
430 , locals_type
431 , attr_type
432 , attr_reference_type
433 , parameter_types
434 , params_size
435 , subject_type
436 , Auto
437 > const type;
438 };
439
440 // compute type of subrule group containing only this
441 // subrule's definition for expr type Expr
442 template <typename Expr, bool Auto>
443 struct group_type_helper
444 {
445 typedef typename def_type_helper<Expr, Auto>::type def_type;
446
447 // create Defs map with only one entry: (ID -> def)
448 typedef typename
449 #ifndef BOOST_FUSION_HAS_VARIADIC_MAP
450 fusion::result_of::make_map<id_type, def_type>::type
451 #else
452 fusion::result_of::make_map<id_type>::template apply<def_type>::type
453 #endif
454 defs_type;
455
456 typedef subrule_group<defs_type> type;
457 };
458
459 template <typename Expr>
460 typename group_type_helper<Expr, false>::type
461 operator=(Expr const& expr) const
462 {
463 typedef group_type_helper<Expr, false> helper;
464 typedef typename helper::def_type def_type;
465 typedef typename helper::type result_type;
466 return result_type(fusion::make_map<id_type>(
467 def_type(compile<spirit::karma::domain>(expr), name_)));
468 }
469
470 #define BOOST_SPIRIT_SUBRULE_MODULUS_ASSIGN_OPERATOR(lhs_ref, rhs_ref) \
471 template <typename Expr> \
472 friend typename group_type_helper<Expr, true>::type \
473 operator%=(subrule lhs_ref sr, Expr rhs_ref expr) \
474 { \
475 typedef group_type_helper<Expr, true> helper; \
476 typedef typename helper::def_type def_type; \
477 typedef typename helper::type result_type; \
478 return result_type(fusion::make_map<id_type>( \
479 def_type(compile<spirit::karma::domain>(expr), sr.name_))); \
480 } \
481 /**/
482
483 // non-const versions needed to suppress proto's %= kicking in
484 BOOST_SPIRIT_SUBRULE_MODULUS_ASSIGN_OPERATOR(const&, const&)
485 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
486 BOOST_SPIRIT_SUBRULE_MODULUS_ASSIGN_OPERATOR(const&, &&)
487 #else
488 BOOST_SPIRIT_SUBRULE_MODULUS_ASSIGN_OPERATOR(const&, &)
489 #endif
490 BOOST_SPIRIT_SUBRULE_MODULUS_ASSIGN_OPERATOR(&, const&)
491 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
492 BOOST_SPIRIT_SUBRULE_MODULUS_ASSIGN_OPERATOR(&, &&)
493 #else
494 BOOST_SPIRIT_SUBRULE_MODULUS_ASSIGN_OPERATOR(&, &)
495 #endif
496
497 #undef BOOST_SPIRIT_SUBRULE_MODULUS_ASSIGN_OPERATOR
498
499 std::string const& name() const
500 {
501 return name_;
502 }
503
504 void name(std::string const& str)
505 {
506 name_ = str;
507 }
508
509 template <typename Context, typename Iterator>
510 struct attribute
511 {
512 typedef attr_type type;
513 };
514
515 template <typename OutputIterator, typename Group
516 , typename Attributes, typename Locals
517 , typename Delimiter, typename Attribute>
518 bool generate(OutputIterator& sink
519 , subrule_context<Group, Attributes, Locals>& context
520 , Delimiter const& delimiter, Attribute const& attr) const
521 {
522 return context.group.template generate_subrule_id<ID_>(
523 sink, context, delimiter, attr);
524 }
525
526 template <typename OutputIterator, typename Context
527 , typename Delimiter, typename Attribute>
528 bool generate(OutputIterator& /*sink*/
529 , Context& /*context*/
530 , Delimiter const& /*delimiter*/, Attribute const& /*attr*/) const
531 {
532 // If you are seeing a compilation error here, you are trying
533 // to use a subrule as a generator outside of a subrule group.
534 BOOST_SPIRIT_ASSERT_FAIL(OutputIterator
535 , subrule_used_outside_subrule_group, (id_type));
536
537 return false;
538 }
539
540 template <typename OutputIterator, typename Group
541 , typename Attributes, typename Locals
542 , typename Delimiter, typename Attribute
543 , typename Params>
544 bool generate(OutputIterator& sink
545 , subrule_context<Group, Attributes, Locals>& context
546 , Delimiter const& delimiter, Attribute const& attr
547 , Params const& params) const
548 {
549 return context.group.template generate_subrule_id<ID_>(
550 sink, context, delimiter, attr, params);
551 }
552
553 template <typename OutputIterator, typename Context
554 , typename Delimiter, typename Attribute
555 , typename Params>
556 bool generate(OutputIterator& /*sink*/
557 , Context& /*context*/
558 , Delimiter const& /*delimiter*/, Attribute const& /*attr*/
559 , Params const& /*params*/) const
560 {
561 // If you are seeing a compilation error here, you are trying
562 // to use a subrule as a generator outside of a subrule group.
563 BOOST_SPIRIT_ASSERT_FAIL(OutputIterator
564 , subrule_used_outside_subrule_group, (id_type));
565
566 return false;
567 }
568
569 template <typename Context>
570 info what(Context& /*context*/) const
571 {
572 return info(name_);
573 }
574
575 // bring in the operator() overloads
576 this_type const& get_parameterized_subject() const { return *this; }
577 typedef this_type parameterized_subject_type;
578 #include <boost/spirit/home/karma/nonterminal/detail/fcall.hpp>
579
580 std::string name_;
581 };
582 }}}}
583
584 #if defined(BOOST_MSVC)
585 # pragma warning(pop)
586 #endif
587
588 #endif