Imported Upstream version 1.57.0
[platform/upstream/boost.git] / boost / spirit / repository / home / qi / nonterminal / subrule.hpp
1 /*=============================================================================
2     Copyright (c) 2009 Francois Barel
3     Copyright (c) 2001-2011 Joel de Guzman
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_QI_SUBRULE_AUGUST_06_2009_0239AM)
9 #define BOOST_SPIRIT_REPOSITORY_QI_SUBRULE_AUGUST_06_2009_0239AM
10
11 #if defined(_MSC_VER)
12 #pragma once
13 #endif
14
15 #include <boost/spirit/home/qi/domain.hpp>
16 #include <boost/spirit/home/qi/meta_compiler.hpp>
17 #include <boost/spirit/home/qi/parser.hpp>
18 #include <boost/spirit/home/qi/reference.hpp>
19 #include <boost/spirit/home/qi/nonterminal/detail/parameterized.hpp>
20 #include <boost/spirit/home/qi/nonterminal/detail/parser_binder.hpp>
21 #include <boost/spirit/home/support/argument.hpp>
22 #include <boost/spirit/home/support/assert_msg.hpp>
23 #include <boost/spirit/home/qi/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 qi
55 {
56     ///////////////////////////////////////////////////////////////////////////
57     // subrule_group:
58     // - parser 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::qi::reference<subrule_group<Defs> const>
68             >::type
69           , subrule_group<Defs>
70         >
71       , spirit::qi::parser<subrule_group<Defs> >
72     {
73         // Fusion associative sequence, associating each subrule ID in this
74         // group (as an MPL integral constant) with its definition
75         typedef Defs defs_type;
76
77         typedef subrule_group<Defs> this_type;
78         typedef spirit::qi::reference<this_type const> reference_;
79         typedef typename proto::terminal<reference_>::type terminal;
80         typedef proto::extends<terminal, this_type> base_type;
81
82         static size_t const params_size =
83             // Forward to first subrule.
84             remove_reference<
85                 typename fusion::result_of::front<Defs>::type
86             >::type::second_type::params_size;
87
88         subrule_group(subrule_group const& rhs)
89           : base_type(terminal::make(reference_(*this)))
90           , defs(rhs.defs)
91         {
92         }
93
94         explicit subrule_group(Defs const& defs)
95           : base_type(terminal::make(reference_(*this)))
96           , defs(defs)
97         {
98         }
99
100         // from a subrule ID, get the type of a reference to its definition
101         template <int ID>
102         struct def_type
103         {
104             typedef mpl::int_<ID> id_type;
105
106             // If you are seeing a compilation error here, you are trying
107             // to use a subrule which was not defined in this group.
108             BOOST_SPIRIT_ASSERT_MSG(
109                 (fusion::result_of::has_key<
110                     defs_type const, id_type>::type::value)
111               , subrule_used_without_being_defined, (mpl::int_<ID>));
112
113             typedef typename
114                 fusion::result_of::at_key<defs_type const, id_type>::type
115             type;
116         };
117
118         // from a subrule ID, get a reference to its definition
119         template <int ID>
120         typename def_type<ID>::type def() const
121         {
122             return fusion::at_key<mpl::int_<ID> >(defs);
123         }
124
125         template <typename Context, typename Iterator>
126         struct attribute
127             // Forward to first subrule.
128           : mpl::identity<
129                 typename remove_reference<
130                     typename fusion::result_of::front<Defs>::type
131                 >::type::second_type::attr_type> {};
132
133         template <typename Iterator, typename Context
134           , typename Skipper, typename Attribute>
135         bool parse(Iterator& first, Iterator const& last
136           , Context& context, Skipper const& skipper
137           , Attribute& attr) const
138         {
139             // Forward to first subrule.
140             return parse_subrule(fusion::front(defs).second
141               , first, last, context, skipper, attr);
142         }
143
144         template <typename Iterator, typename Context
145           , typename Skipper, typename Attribute, typename Params>
146         bool parse(Iterator& first, Iterator const& last
147           , Context& context, Skipper const& skipper
148           , Attribute& attr, Params const& params) const
149         {
150             // Forward to first subrule.
151             return parse_subrule(fusion::front(defs).second
152               , first, last, context, skipper, attr, params);
153         }
154
155         template <int ID, typename Iterator, typename Context
156           , typename Skipper, typename Attribute>
157         bool parse_subrule_id(Iterator& first, Iterator const& last
158           , Context& context, Skipper const& skipper
159           , Attribute& attr) const
160         {
161             return parse_subrule(def<ID>()
162               , first, last, context, skipper, attr);
163         }
164
165         template <int ID, typename Iterator, typename Context
166           , typename Skipper, typename Attribute, typename Params>
167         bool parse_subrule_id(Iterator& first, Iterator const& last
168           , Context& context, Skipper const& skipper
169           , Attribute& attr, Params const& params) const
170         {
171             return parse_subrule(def<ID>()
172               , first, last, context, skipper, attr, params);
173         }
174
175         template <typename Def
176           , typename Iterator, typename Context
177           , typename Skipper, typename Attribute>
178         bool parse_subrule(Def const& def
179           , Iterator& first, Iterator const& last
180           , Context& /*caller_context*/, Skipper const& skipper
181           , Attribute& attr) const
182         {
183             // compute context type for this subrule
184             typedef typename Def::locals_type subrule_locals_type;
185             typedef typename Def::attr_type subrule_attr_type;
186             typedef typename Def::attr_reference_type subrule_attr_reference_type;
187             typedef typename Def::parameter_types subrule_parameter_types;
188
189             typedef
190                 subrule_context<
191                     this_type
192                   , fusion::cons<
193                         subrule_attr_reference_type, subrule_parameter_types>
194                   , subrule_locals_type
195                 >
196             context_type;
197
198             // prepare attribute
199             typedef traits::make_attribute<
200                 subrule_attr_type, Attribute> make_attribute;
201
202             // do down-stream transformation, provides attribute for 
203             // rhs parser
204             typedef traits::transform_attribute<
205                 typename make_attribute::type, subrule_attr_type, spirit::qi::domain> 
206             transform;
207
208             typename make_attribute::type made_attr = make_attribute::call(attr);
209             typename transform::type attr_ = transform::pre(made_attr);
210
211             // If you are seeing a compilation error here, you are probably
212             // trying to use a subrule which has inherited attributes,
213             // without passing values for them.
214             context_type context(*this, attr_);
215
216             if (def.binder(first, last, context, skipper))
217             {
218                 // do up-stream transformation, this integrates the results 
219                 // back into the original attribute value, if appropriate
220                 traits::post_transform(attr, attr_);
221                 return true;
222             }
223
224             // inform attribute transformation of failed rhs
225             traits::fail_transform(attr, attr_);
226             return false;
227         }
228
229         template <typename Def
230           , typename Iterator, typename Context
231           , typename Skipper, typename Attribute, typename Params>
232         bool parse_subrule(Def const& def
233           , Iterator& first, Iterator const& last
234           , Context& caller_context, Skipper const& skipper
235           , Attribute& attr, Params const& params) const
236         {
237             // compute context type for this subrule
238             typedef typename Def::locals_type subrule_locals_type;
239             typedef typename Def::attr_type subrule_attr_type;
240             typedef typename Def::attr_reference_type subrule_attr_reference_type;
241             typedef typename Def::parameter_types subrule_parameter_types;
242
243             typedef
244                 subrule_context<
245                     this_type
246                   , fusion::cons<
247                         subrule_attr_reference_type, subrule_parameter_types>
248                   , subrule_locals_type
249                 >
250             context_type;
251
252             // prepare attribute
253             typedef traits::make_attribute<
254                 subrule_attr_type, Attribute> make_attribute;
255
256             // do down-stream transformation, provides attribute for 
257             // rhs parser
258             typedef traits::transform_attribute<
259                 typename make_attribute::type, subrule_attr_type, spirit::qi::domain> 
260             transform;
261
262             typename make_attribute::type made_attr = make_attribute::call(attr);
263             typename transform::type attr_ = transform::pre(made_attr);
264
265             // If you are seeing a compilation error here, you are probably
266             // trying to use a subrule which has inherited attributes,
267             // passing values of incompatible types for them.
268             context_type context(*this, attr_, params, caller_context);
269
270             if (def.binder(first, last, context, skipper))
271             {
272                 // do up-stream transformation, this integrates the results 
273                 // back into the original attribute value, if appropriate
274                 traits::post_transform(attr, attr_);
275                 return true;
276             }
277
278             // inform attribute transformation of failed rhs
279             traits::fail_transform(attr, attr_);
280             return false;
281         }
282
283         template <typename Context>
284         info what(Context& context) const
285         {
286             // Forward to first subrule.
287             return fusion::front(defs).second.binder.p.what(context);
288         }
289
290         template <typename Defs2>
291         subrule_group<
292             typename fusion::result_of::as_map<
293                 typename fusion::result_of::join<
294                     Defs const, Defs2 const>::type>::type>
295         operator,(subrule_group<Defs2> const& other) const
296         {
297             typedef subrule_group<
298                 typename fusion::result_of::as_map<
299                     typename fusion::result_of::join<
300                         Defs const, Defs2 const>::type>::type> result_type;
301             return result_type(fusion::as_map(fusion::join(defs, other.defs)));
302         }
303
304         // bring in the operator() overloads
305         this_type const& get_parameterized_subject() const { return *this; }
306         typedef this_type parameterized_subject_type;
307         #include <boost/spirit/home/qi/nonterminal/detail/fcall.hpp>
308
309         Defs defs;
310     };
311
312     ///////////////////////////////////////////////////////////////////////////
313     // subrule_definition: holds one particular definition of a subrule
314     ///////////////////////////////////////////////////////////////////////////
315     template <
316         int ID_
317       , typename Locals
318       , typename Attr
319       , typename AttrRef
320       , typename Parameters
321       , size_t ParamsSize
322       , typename Subject
323       , bool Auto_
324     >
325     struct subrule_definition
326     {
327         typedef mpl::int_<ID_> id_type;
328         BOOST_STATIC_CONSTANT(int, ID = ID_);
329
330         typedef Locals locals_type;
331         typedef Attr attr_type;
332         typedef AttrRef attr_reference_type;
333         typedef Parameters parameter_types;
334         static size_t const params_size = ParamsSize;
335
336         typedef Subject subject_type;
337         typedef mpl::bool_<Auto_> auto_type;
338         BOOST_STATIC_CONSTANT(bool, Auto = Auto_);
339
340         typedef spirit::qi::detail::parser_binder<
341             Subject, auto_type> binder_type;
342
343         subrule_definition(Subject const& subject, std::string const& name)
344           : binder(subject), name(name)
345         {
346         }
347
348         binder_type const binder;
349         std::string const name;
350     };
351
352     ///////////////////////////////////////////////////////////////////////////
353     // subrule placeholder:
354     // - on subrule definition: helper for creation of subrule_group,
355     // - on subrule invocation: Proto terminal and parser.
356     ///////////////////////////////////////////////////////////////////////////
357     template <
358         int ID_
359       , typename T1 = unused_type
360       , typename T2 = unused_type
361     >
362     struct subrule
363       : proto::extends<
364             typename proto::terminal<
365                 spirit::qi::reference<subrule<ID_, T1, T2> const>
366             >::type
367           , subrule<ID_, T1, T2>
368         >
369       , spirit::qi::parser<subrule<ID_, T1, T2> >
370     {
371         typedef mpl::int_<ID_> id_type;
372         BOOST_STATIC_CONSTANT(int, ID = ID_);
373
374         typedef subrule<ID_, T1, T2> this_type;
375         typedef spirit::qi::reference<this_type const> reference_;
376         typedef typename proto::terminal<reference_>::type terminal;
377         typedef proto::extends<terminal, this_type> base_type;
378
379         typedef mpl::vector<T1, T2> template_params;
380
381         // locals_type is a sequence of types to be used as local variables
382         typedef typename
383             spirit::detail::extract_locals<template_params>::type
384         locals_type;
385
386         typedef typename
387             spirit::detail::extract_sig<template_params>::type
388         sig_type;
389
390         // This is the subrule's attribute type
391         typedef typename
392             spirit::detail::attr_from_sig<sig_type>::type
393         attr_type;
394         typedef typename add_reference<attr_type>::type attr_reference_type;
395
396         // parameter_types is a sequence of types passed as parameters to the subrule
397         typedef typename
398             spirit::detail::params_from_sig<sig_type>::type
399         parameter_types;
400
401         static size_t const params_size =
402             fusion::result_of::size<parameter_types>::type::value;
403
404         explicit subrule(std::string const& name_ = "unnamed-subrule")
405           : base_type(terminal::make(reference_(*this)))
406           , name_(name_)
407         {
408         }
409
410         // compute type of this subrule's definition for expr type Expr
411         template <typename Expr, bool Auto>
412         struct def_type_helper
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(spirit::qi::domain, Expr);
418
419             typedef typename result_of::compile<
420                 spirit::qi::domain, Expr>::type subject_type;
421
422             typedef subrule_definition<
423                 ID_
424               , locals_type
425               , attr_type
426               , attr_reference_type
427               , parameter_types
428               , params_size
429               , subject_type
430               , Auto
431             > const type;
432         };
433
434         // compute type of subrule group containing only this
435         // subrule's definition for expr type Expr
436         template <typename Expr, bool Auto>
437         struct group_type_helper
438         {
439             typedef typename def_type_helper<Expr, Auto>::type def_type;
440
441             // create Defs map with only one entry: (ID -> def)
442             typedef typename
443                 fusion::result_of::make_map<id_type, def_type>::type
444             defs_type;
445
446             typedef subrule_group<defs_type> type;
447         };
448
449         template <typename Expr>
450         typename group_type_helper<Expr, false>::type
451         operator=(Expr const& expr) const
452         {
453             typedef group_type_helper<Expr, false> helper;
454             typedef typename helper::def_type def_type;
455             typedef typename helper::type result_type;
456             return result_type(fusion::make_map<id_type>(
457                 def_type(compile<spirit::qi::domain>(expr), name_)));
458         }
459
460         template <typename Expr>
461         friend typename group_type_helper<Expr, true>::type
462         operator%=(subrule const& sr, Expr const& expr)
463         {
464             typedef group_type_helper<Expr, true> helper;
465             typedef typename helper::def_type def_type;
466             typedef typename helper::type result_type;
467             return result_type(fusion::make_map<id_type>(
468                 def_type(compile<spirit::qi::domain>(expr), sr.name_)));
469         }
470
471         // non-const versions needed to suppress proto's %= kicking in
472         template <typename Expr>
473         friend typename group_type_helper<Expr, true>::type
474         operator%=(subrule const& sr, Expr& expr)
475         {
476             return operator%=(
477                 sr
478               , static_cast<Expr const&>(expr));
479         }
480         template <typename Expr>
481         friend typename group_type_helper<Expr, true>::type
482         operator%=(subrule& sr, Expr const& expr)
483         {
484             return operator%=(
485                 static_cast<subrule const&>(sr)
486               , expr);
487         }
488         template <typename Expr>
489         friend typename group_type_helper<Expr, true>::type
490         operator%=(subrule& sr, Expr& expr)
491         {
492             return operator%=(
493                 static_cast<subrule const&>(sr)
494               , static_cast<Expr const&>(expr));
495         }
496
497         std::string const& name() const
498         {
499             return name_;
500         }
501
502         void name(std::string const& str)
503         {
504             name_ = str;
505         }
506
507         template <typename Context, typename Iterator>
508         struct attribute
509         {
510             typedef attr_type type;
511         };
512
513         template <typename Iterator, typename Group
514           , typename Attributes, typename Locals
515           , typename Skipper, typename Attribute>
516         bool parse(Iterator& first, Iterator const& last
517           , subrule_context<Group, Attributes, Locals>& context
518           , Skipper const& skipper, Attribute& attr) const
519         {
520             return context.group.template parse_subrule_id<ID_>(
521                 first, last, context, skipper, attr);
522         }
523
524         template <typename Iterator, typename Context
525           , typename Skipper, typename Attribute>
526         bool parse(Iterator& /*first*/, Iterator const& /*last*/
527           , Context& /*context*/
528           , Skipper const& /*skipper*/, Attribute& /*attr*/) const
529         {
530             // If you are seeing a compilation error here, you are trying
531             // to use a subrule as a parser outside of a subrule group.
532             BOOST_SPIRIT_ASSERT_FAIL(Iterator
533               , subrule_used_outside_subrule_group, (id_type));
534
535             return false;
536         }
537
538         template <typename Iterator, typename Group
539           , typename Attributes, typename Locals
540           , typename Skipper, typename Attribute
541           , typename Params>
542         bool parse(Iterator& first, Iterator const& last
543           , subrule_context<Group, Attributes, Locals>& context
544           , Skipper const& skipper, Attribute& attr
545           , Params const& params) const
546         {
547             return context.group.template parse_subrule_id<ID_>(
548                 first, last, context, skipper, attr, params);
549         }
550
551         template <typename Iterator, typename Context
552           , typename Skipper, typename Attribute
553           , typename Params>
554         bool parse(Iterator& /*first*/, Iterator const& /*last*/
555           , Context& /*context*/
556           , Skipper const& /*skipper*/, Attribute& /*attr*/
557           , Params const& /*params*/) const
558         {
559             // If you are seeing a compilation error here, you are trying
560             // to use a subrule as a parser outside of a subrule group.
561             BOOST_SPIRIT_ASSERT_FAIL(Iterator
562               , subrule_used_outside_subrule_group, (id_type));
563
564             return false;
565         }
566
567         template <typename Context>
568         info what(Context& /*context*/) const
569         {
570             return info(name_);
571         }
572
573         // bring in the operator() overloads
574         this_type const& get_parameterized_subject() const { return *this; }
575         typedef this_type parameterized_subject_type;
576         #include <boost/spirit/home/qi/nonterminal/detail/fcall.hpp>
577
578         std::string name_;
579     };
580 }}}}
581
582 #if defined(BOOST_MSVC)
583 # pragma warning(pop)
584 #endif
585
586 #endif