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