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             typedef traits::make_attribute<attr_type, Attribute> make_attribute;
57 
58             // create a attribute if none is supplied
59             // this creates a _copy_ of the attribute because the semantic
60             // action will likely change parts of this
61             typedef traits::transform_attribute<
62                 typename make_attribute::type, attr_type, domain> transform;
63 
64             typename transform::type attr =
65                 traits::pre_transform<domain, attr_type>(make_attribute::call(attr_));
66 
67             // call the function, passing the attribute, the context and a bool
68             // flag that the client can set to false to fail generating.
69             return traits::action_dispatch<Subject>()(f, attr, ctx) &&
70                    subject.generate(sink, ctx, d, attr);
71         }
72 
73         template <typename Context>
whatboost::spirit::karma::action74         info what(Context& context) const
75         {
76             // the action is transparent (does not add any info)
77             return subject.what(context);
78         }
79 
80         subject_type subject;
81         Action f;
82     };
83 
84 }}}
85 
86 ///////////////////////////////////////////////////////////////////////////////
87 namespace boost { namespace spirit
88 {
89     ///////////////////////////////////////////////////////////////////////////
90     // Karma action meta-compiler
91     template <>
92     struct make_component<karma::domain, tag::action>
93     {
94         template <typename Sig>
95         struct result;
96 
97         template <typename This, typename Elements, typename Modifiers>
98         struct result<This(Elements, Modifiers)>
99         {
100             typedef typename
101                 remove_const<typename Elements::car_type>::type
102             subject_type;
103 
104             typedef typename
105                 remove_const<typename Elements::cdr_type::car_type>::type
106             action_type;
107 
108             typedef karma::action<subject_type, action_type> type;
109         };
110 
111         template <typename Elements>
112         typename result<make_component(Elements, unused_type)>::type
operator ()boost::spirit::make_component113         operator()(Elements const& elements, unused_type) const
114         {
115             typename result<make_component(Elements, unused_type)>::type
116                 result(elements.car, elements.cdr.car);
117             return result;
118         }
119     };
120 }}
121 
122 namespace boost { namespace spirit { namespace traits
123 {
124     ///////////////////////////////////////////////////////////////////////////
125     template <typename Subject, typename Action>
126     struct has_semantic_action<karma::action<Subject, Action> >
127       : mpl::true_ {};
128 
129     ///////////////////////////////////////////////////////////////////////////
130     template <typename Subject, typename Action, typename Attribute
131       , typename Context, typename Iterator>
132     struct handles_container<karma::action<Subject, Action>, Attribute
133       , Context, Iterator>
134       : unary_handles_container<Subject, Attribute, Context, Iterator> {};
135 }}}
136 
137 #endif
138