PageRenderTime 54ms CodeModel.GetById 17ms app.highlight 32ms RepoModel.GetById 1ms app.codeStats 0ms

/Src/Dependencies/Boost/boost/spirit/repository/home/karma/nonterminal/subrule.hpp

http://hadesmem.googlecode.com/
C++ Header | 560 lines | 424 code | 73 blank | 63 comment | 0 complexity | 4e384e22db7db17352b00fe3ad5272f7 MD5 | raw file
  1//  Copyright (c) 2009 Francois Barel
  2//  Copyright (c) 2001-2011 Joel de Guzman
  3//  Copyright (c) 2001-2011 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///////////////////////////////////////////////////////////////////////////////
 54namespace 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<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<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_MSG(false
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_MSG(false
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