1 //  Copyright (c) 2001-2011 Hartmut Kaiser
2 //  Copyright (c) 2001-2011 Joel de Guzman
3 //
4 //  Distributed under the Boost Software License, Version 1.0. (See accompanying
5 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 
7 #if !defined(BOOST_SPIRIT_CHAR_GENERATOR_SEP_07_2009_0417PM)
8 #define BOOST_SPIRIT_CHAR_GENERATOR_SEP_07_2009_0417PM
9 
10 #if defined(_MSC_VER)
11 #pragma once
12 #endif
13 
14 #include <boost/spirit/home/karma/domain.hpp>
15 #include <boost/spirit/home/karma/generator.hpp>
16 #include <boost/spirit/home/karma/detail/generate_to.hpp>
17 #include <boost/spirit/home/karma/detail/extract_from.hpp>
18 #include <boost/spirit/home/karma/meta_compiler.hpp>
19 #include <boost/spirit/home/karma/delimit_out.hpp>
20 #include <boost/spirit/home/support/unused.hpp>
21 #include <boost/spirit/home/support/info.hpp>
22 #include <boost/spirit/home/support/container.hpp>
23 #include <boost/proto/operators.hpp>
24 #include <boost/proto/tags.hpp>
25 
26 namespace boost { namespace spirit
27 {
28     ///////////////////////////////////////////////////////////////////////////
29     // Enablers
30     ///////////////////////////////////////////////////////////////////////////
31     template <>
32     struct use_operator<karma::domain, proto::tag::complement> // enables ~
33       : mpl::true_ {};
34 
35 }}
36 
37 namespace boost { namespace spirit { namespace traits // classification
38 {
39     namespace detail
40     {
41         BOOST_MPL_HAS_XXX_TRAIT_DEF(char_generator_id)
42     }
43 
44     template <typename T>
45     struct is_char_generator : detail::has_char_generator_id<T> {};
46 }}}
47 
48 namespace boost { namespace spirit { namespace karma
49 {
50     ///////////////////////////////////////////////////////////////////////////
51     // The base char_parser
52     ///////////////////////////////////////////////////////////////////////////
53     template <typename Derived, typename CharEncoding, typename Tag
54       , typename Char = typename CharEncoding::char_type, typename Attr = Char>
55     struct char_generator : primitive_generator<Derived>
56     {
57         typedef CharEncoding char_encoding;
58         typedef Tag tag;
59         typedef Char char_type;
60         struct char_generator_id;
61 
62         // if Attr is unused_type, Derived must supply its own attribute
63         // metafunction
64         template <typename Context, typename Unused>
65         struct attribute
66         {
67             typedef Attr type;
68         };
69 
70         template <
71             typename OutputIterator, typename Context, typename Delimiter
72           , typename Attribute>
generateboost::spirit::karma::char_generator73         bool generate(OutputIterator& sink, Context& context, Delimiter const& d
74           , Attribute const& attr) const
75         {
76             if (!traits::has_optional_value(attr))
77                 return false;
78 
79             Attr ch = Attr();
80             if (!this->derived().test(traits::extract_from<Attr>(attr, context), ch, context))
81                 return false;
82 
83             return karma::detail::generate_to(sink, ch, char_encoding(), tag()) &&
84                    karma::delimit_out(sink, d);       // always do post-delimiting
85         }
86 
87         // Requirement: g.test(attr, ch, context) -> bool
88         //
89         //  attr:       associated attribute
90         //  ch:         character to be generated (set by test())
91         //  context:    enclosing rule context
92     };
93 
94     ///////////////////////////////////////////////////////////////////////////
95     // negated_char_generator handles ~cg expressions (cg is a char_generator)
96     ///////////////////////////////////////////////////////////////////////////
97     template <typename Positive>
98     struct negated_char_generator
99       : char_generator<negated_char_generator<Positive>
100           , typename Positive::char_encoding, typename Positive::tag>
101     {
negated_char_generatorboost::spirit::karma::negated_char_generator102         negated_char_generator(Positive const& positive)
103           : positive(positive) {}
104 
105         template <typename Attribute, typename CharParam, typename Context>
testboost::spirit::karma::negated_char_generator106         bool test(Attribute const& attr, CharParam& ch, Context& context) const
107         {
108             return !positive.test(attr, ch, context);
109         }
110 
111         template <typename Context>
whatboost::spirit::karma::negated_char_generator112         info what(Context& context) const
113         {
114             return info("not", positive.what(context));
115         }
116 
117         Positive positive;
118     };
119 
120     ///////////////////////////////////////////////////////////////////////////
121     // Generator generators: make_xxx function (objects)
122     ///////////////////////////////////////////////////////////////////////////
123     namespace detail
124     {
125         template <typename Positive>
126         struct make_negated_char_generator
127         {
128             typedef negated_char_generator<Positive> result_type;
operator ()boost::spirit::karma::detail::make_negated_char_generator129             result_type operator()(Positive const& positive) const
130             {
131                 return result_type(positive);
132             }
133         };
134 
135         template <typename Positive>
136         struct make_negated_char_generator<negated_char_generator<Positive> >
137         {
138             typedef Positive result_type;
operator ()boost::spirit::karma::detail::make_negated_char_generator139             result_type operator()(negated_char_generator<Positive> const& ncg) const
140             {
141                 return ncg.positive;
142             }
143         };
144     }
145 
146     template <typename Elements, typename Modifiers>
147     struct make_composite<proto::tag::complement, Elements, Modifiers>
148     {
149         typedef typename
150             fusion::result_of::value_at_c<Elements, 0>::type
151         subject;
152 
153         BOOST_SPIRIT_ASSERT_MSG((
154             traits::is_char_generator<subject>::value
155         ), subject_is_not_negatable, (subject));
156 
157         typedef typename
158             detail::make_negated_char_generator<subject>::result_type
159         result_type;
160 
operator ()boost::spirit::karma::make_composite161         result_type operator()(Elements const& elements, unused_type) const
162         {
163             return detail::make_negated_char_generator<subject>()(
164                 fusion::at_c<0>(elements));
165         }
166     };
167 
168 }}}
169 
170 #endif
171