• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
subrule_group_generatorboost::spirit::repository::karma::subrule_group_generator75         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>
defboost::spirit::repository::karma::subrule_group_generator99         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>
generateboost::spirit::repository::karma::subrule_group_generator114         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>
generateboost::spirit::repository::karma::subrule_group_generator125         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>
generate_subrule_idboost::spirit::repository::karma::subrule_group_generator136         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>
generate_subrule_idboost::spirit::repository::karma::subrule_group_generator146         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>
generate_subruleboost::spirit::repository::karma::subrule_group_generator156         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>
generate_subruleboost::spirit::repository::karma::subrule_group_generator188         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>
whatboost::spirit::repository::karma::subrule_group_generator220         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 
subrule_groupboost::spirit::repository::karma::subrule_group258         explicit subrule_group(Defs const& defs)
259           : subrule_group::proto_extends(terminal::make(generator_type(defs)))
260         {
261         }
262 
generatorboost::spirit::repository::karma::subrule_group263         generator_type const& generator() const { return proto::value(*this); }
264 
defsboost::spirit::repository::karma::subrule_group265         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>
operator ,boost::spirit::repository::karma::subrule_group272         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
operator ,(subrule_group && left,subrule_group<Defs2> && other)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
get_parameterized_subjectboost::spirit::repository::karma::subrule_group298         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 
subrule_definitionboost::spirit::repository::karma::subrule_definition334         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 
subruleboost::spirit::repository::karma::subrule410         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
operator =boost::spirit::repository::karma::subrule461         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
BOOST_SPIRIT_SUBRULE_MODULUS_ASSIGN_OPERATORboost::spirit::repository::karma::subrule484         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 
nameboost::spirit::repository::karma::subrule504         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>
generateboost::spirit::repository::karma::subrule518         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>
generateboost::spirit::repository::karma::subrule528         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>
generateboost::spirit::repository::karma::subrule544         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>
generateboost::spirit::repository::karma::subrule556         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>
whatboost::spirit::repository::karma::subrule570         info what(Context& /*context*/) const
571         {
572             return info(name_);
573         }
574 
575         // bring in the operator() overloads
get_parameterized_subjectboost::spirit::repository::karma::subrule576         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
589