1 //  Copyright (c) 2001-2011 Hartmut Kaiser
2 //
3 //  Distributed under the Boost Software License, Version 1.0. (See accompanying
4 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 #if !defined(BOOST_SPIRIT_KARMA_ACTION_MAR_07_2007_0851AM)
7 #define BOOST_SPIRIT_KARMA_ACTION_MAR_07_2007_0851AM
8 
9 #if defined(_MSC_VER)
10 #pragma once
11 #endif
12 
13 #include <boost/spirit/home/karma/detail/attributes.hpp>
14 #include <boost/spirit/home/support/argument.hpp>
15 #include <boost/spirit/home/support/context.hpp>
16 #include <boost/spirit/home/support/unused.hpp>
17 #include <boost/spirit/home/support/info.hpp>
18 #include <boost/spirit/home/support/action_dispatch.hpp>
19 #include <boost/spirit/home/support/has_semantic_action.hpp>
20 #include <boost/spirit/home/support/handles_container.hpp>
21 #include <boost/spirit/home/karma/domain.hpp>
22 #include <boost/spirit/home/karma/meta_compiler.hpp>
23 #include <boost/spirit/home/karma/generator.hpp>
24 
25 #include <boost/mpl/bool.hpp>
26 #include <boost/mpl/if.hpp>
27 #include <boost/type_traits/remove_const.hpp>
28 #include <boost/type_traits/is_same.hpp>
29 
30 namespace boost { namespace spirit { namespace karma
31 {
32     ///////////////////////////////////////////////////////////////////////////
33     BOOST_PP_REPEAT(SPIRIT_ARGUMENTS_LIMIT, SPIRIT_USING_ARGUMENT, _)
34 
35     template <typename Subject, typename Action>
36     struct action : unary_generator<action<Subject, Action> >
37     {
38         typedef Subject subject_type;
39         typedef typename subject_type::properties properties;
40 
41         template <typename Context, typename Iterator>
42         struct attribute
43           : traits::attribute_of<Subject, Context, Iterator>
44         {};
45 
actionboost::spirit::karma::action46         action(Subject const& subject, Action f)
47           : subject(subject), f(f) {}
48 
49         template <
50             typename OutputIterator, typename Context, typename Delimiter
51           , typename Attribute>
generateboost::spirit::karma::action52         bool generate(OutputIterator& sink, Context& ctx, Delimiter const& d
53           , Attribute const& attr_) const
54         {
55             typedef typename attribute<Context, unused_type>::type attr_type;
56 
57             // create a attribute if none is supplied
58             // this creates a _copy_ of the attribute because the semantic
59             // action will likely change parts of this
60             typedef traits::transform_attribute<
61                 Attribute const, attr_type, domain> transform;
62 
63             attr_type attr = transform::pre(attr_);
64 
65             // call the function, passing the attribute, the context and a bool
66             // flag that the client can set to false to fail generating.
67             return traits::action_dispatch<Subject>()(f, attr, ctx) &&
68                    subject.generate(sink, ctx, d, attr);
69         }
70 
71         template <typename Context>
whatboost::spirit::karma::action72         info what(Context& context) const
73         {
74             // the action is transparent (does not add any info)
75             return subject.what(context);
76         }
77 
78         subject_type subject;
79         Action f;
80     };
81 
82 }}}
83 
84 ///////////////////////////////////////////////////////////////////////////////
85 namespace boost { namespace spirit
86 {
87     ///////////////////////////////////////////////////////////////////////////
88     // Karma action meta-compiler
89     template <>
90     struct make_component<karma::domain, tag::action>
91     {
92         template <typename Sig>
93         struct result;
94 
95         template <typename This, typename Elements, typename Modifiers>
96         struct result<This(Elements, Modifiers)>
97         {
98             typedef typename
99                 remove_const<typename Elements::car_type>::type
100             subject_type;
101 
102             typedef typename
103                 remove_const<typename Elements::cdr_type::car_type>::type
104             action_type;
105 
106             typedef karma::action<subject_type, action_type> type;
107         };
108 
109         template <typename Elements>
110         typename result<make_component(Elements, unused_type)>::type
operator ()boost::spirit::make_component111         operator()(Elements const& elements, unused_type) const
112         {
113             typename result<make_component(Elements, unused_type)>::type
114                 result(elements.car, elements.cdr.car);
115             return result;
116         }
117     };
118 }}
119 
120 namespace boost { namespace spirit { namespace traits
121 {
122     ///////////////////////////////////////////////////////////////////////////
123     template <typename Subject, typename Action>
124     struct has_semantic_action<karma::action<Subject, Action> >
125       : mpl::true_ {};
126 
127     ///////////////////////////////////////////////////////////////////////////
128     template <typename Subject, typename Action, typename Attribute
129       , typename Context, typename Iterator>
130     struct handles_container<karma::action<Subject, Action>, Attribute
131       , Context, Iterator>
132       : unary_handles_container<Subject, Attribute, Context, Iterator> {};
133 }}}
134 
135 #endif
136