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_AUTO_NOV_29_2009_0339PM)
7 #define BOOST_SPIRIT_KARMA_AUTO_NOV_29_2009_0339PM
8 
9 #if defined(_MSC_VER)
10 #pragma once
11 #endif
12 
13 #include <boost/spirit/home/support/common_terminals.hpp>
14 #include <boost/spirit/home/support/info.hpp>
15 #include <boost/spirit/home/support/container.hpp>
16 #include <boost/spirit/home/support/assert_msg.hpp>
17 #include <boost/spirit/home/support/detail/hold_any.hpp>
18 #include <boost/spirit/home/karma/domain.hpp>
19 #include <boost/spirit/home/karma/meta_compiler.hpp>
20 #include <boost/spirit/home/karma/delimit_out.hpp>
21 #include <boost/spirit/home/karma/generator.hpp>
22 #include <boost/spirit/home/karma/auto/create_generator.hpp>
23 #include <boost/mpl/bool.hpp>
24 
25 ///////////////////////////////////////////////////////////////////////////////
26 namespace boost { namespace spirit
27 {
28     ///////////////////////////////////////////////////////////////////////////
29     // Enablers
30     ///////////////////////////////////////////////////////////////////////////
31     template <>
32     struct use_terminal<karma::domain, tag::auto_>     // enables auto_
33       : mpl::true_ {};
34 
35     template <typename A0>
36     struct use_terminal<karma::domain                   // enables auto_(...)
37       , terminal_ex<tag::auto_, fusion::vector1<A0> >
38     > : mpl::true_ {};
39 
40     template <>                                         // enables auto_(f)
41     struct use_lazy_terminal<
42         karma::domain, tag::auto_, 1   /*arity*/
43     > : mpl::true_ {};
44 
45 }}
46 
47 ///////////////////////////////////////////////////////////////////////////////
48 namespace boost { namespace spirit { namespace karma
49 {
50 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
51     using spirit::auto_;
52 #endif
53     using spirit::auto_type;
54 
55     ///////////////////////////////////////////////////////////////////////////
56     template <typename Modifiers>
57     struct auto_generator
58       : generator<auto_generator<Modifiers> >
59     {
60         typedef mpl::int_<generator_properties::all_properties> properties;
61 
62         template <typename Context, typename Unused>
63         struct attribute
64         {
65             typedef spirit::basic_hold_any<char> type;
66         };
67 
auto_generatorboost::spirit::karma::auto_generator68         auto_generator(Modifiers const& modifiers)
69           : modifiers_(modifiers) {}
70 
71         // auto_generator has an attached attribute
72         template <
73             typename OutputIterator, typename Context, typename Delimiter
74           , typename Attribute>
generateboost::spirit::karma::auto_generator75         bool generate(OutputIterator& sink, Context& context
76           , Delimiter const& d, Attribute const& attr) const
77         {
78             return compile<karma::domain>(create_generator<Attribute>(), modifiers_)
79                       .generate(sink, context, d, attr);
80         }
81 
82         // this auto_generator has no attribute attached, it needs to have been
83         // initialized from a value/variable
84         template <typename OutputIterator, typename Context
85           , typename Delimiter>
86         static bool
generateboost::spirit::karma::auto_generator87         generate(OutputIterator&, Context&, Delimiter const&, unused_type)
88         {
89             // It is not possible (doesn't make sense) to use auto_ generators
90             // without providing any attribute, as the generator doesn't 'know'
91             // what to output. The following assertion fires if this situation
92             // is detected in your code.
93             BOOST_SPIRIT_ASSERT_FAIL(OutputIterator, auto_not_usable_without_attribute, ());
94             return false;
95         }
96 
97         template <typename Context>
whatboost::spirit::karma::auto_generator98         info what(Context& /*context*/) const
99         {
100             return info("auto_");
101         }
102 
103         Modifiers modifiers_;
104     };
105 
106     ///////////////////////////////////////////////////////////////////////////
107     template <typename T, typename Modifiers>
108     struct lit_auto_generator
109       : generator<lit_auto_generator<T, Modifiers> >
110     {
111         typedef mpl::int_<generator_properties::all_properties> properties;
112 
113         template <typename Context, typename Unused>
114         struct attribute
115         {
116             typedef unused_type type;
117         };
118 
lit_auto_generatorboost::spirit::karma::lit_auto_generator119         lit_auto_generator(typename add_reference<T>::type t, Modifiers const& modifiers)
120           : t_(t)
121           , generator_(compile<karma::domain>(create_generator<T>(), modifiers))
122         {}
123 
124         // auto_generator has an attached attribute
125         template <
126             typename OutputIterator, typename Context, typename Delimiter
127           , typename Attribute>
generateboost::spirit::karma::lit_auto_generator128         bool generate(OutputIterator& sink, Context& context
129           , Delimiter const& d, Attribute const&) const
130         {
131             return generator_.generate(sink, context, d, t_);
132         }
133 
134         template <typename Context>
whatboost::spirit::karma::lit_auto_generator135         info what(Context& /*context*/) const
136         {
137             return info("auto_");
138         }
139 
140         typedef typename spirit::result_of::create_generator<T>::type
141             generator_type;
142 
143         typedef typename spirit::result_of::compile<
144             karma::domain, generator_type, Modifiers>::type generator_impl_type;
145 
146         T t_;
147         generator_impl_type generator_;
148 
149     private:
150         // silence MSVC warning C4512: assignment operator could not be generated
151         lit_auto_generator& operator= (lit_auto_generator const&);
152     };
153 
154     ///////////////////////////////////////////////////////////////////////////
155     // Generator generators: make_xxx function (objects)
156     ///////////////////////////////////////////////////////////////////////////
157 
158     // auto_
159     template <typename Modifiers>
160     struct make_primitive<tag::auto_, Modifiers>
161     {
162         typedef auto_generator<Modifiers> result_type;
163 
operator ()boost::spirit::karma::make_primitive164         result_type operator()(unused_type, Modifiers const& modifiers) const
165         {
166             return result_type(modifiers);
167         }
168     };
169 
170     // auto_(...)
171     template <typename Modifiers, typename A0>
172     struct make_primitive<
173             terminal_ex<tag::auto_, fusion::vector1<A0> >, Modifiers>
174     {
175         typedef typename add_const<A0>::type const_attribute;
176 
177         typedef lit_auto_generator<const_attribute, Modifiers> result_type;
178 
179         template <typename Terminal>
operator ()boost::spirit::karma::make_primitive180         result_type operator()(Terminal const& term, Modifiers const& modifiers) const
181         {
182             return result_type(fusion::at_c<0>(term.args), modifiers);
183         }
184     };
185 
186 }}}
187 
188 #endif
189