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_CHAR_CLASS_AUG_10_2009_0720AM)
7 #define BOOST_SPIRIT_KARMA_CHAR_CLASS_AUG_10_2009_0720AM
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/string_traits.hpp>
15 #include <boost/spirit/home/support/info.hpp>
16 #include <boost/spirit/home/support/char_class.hpp>
17 #include <boost/spirit/home/support/detail/get_encoding.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/char/char_generator.hpp>
22 #include <boost/spirit/home/karma/auxiliary/lazy.hpp>
23 #include <boost/spirit/home/karma/detail/get_casetag.hpp>
24 #include <boost/spirit/home/karma/detail/generate_to.hpp>
25 
26 ///////////////////////////////////////////////////////////////////////////////
27 namespace boost { namespace spirit
28 {
29     ///////////////////////////////////////////////////////////////////////////
30     // Enablers
31     ///////////////////////////////////////////////////////////////////////////
32     // enables alnum, alpha, graph, etc.
33     template <typename CharClass, typename CharEncoding>
34     struct use_terminal<karma::domain
35         , tag::char_code<CharClass, CharEncoding> >
36       : mpl::true_ {};
37 
38 }}
39 
40 ///////////////////////////////////////////////////////////////////////////////
41 namespace boost { namespace spirit { namespace karma
42 {
43     // hoist the char classification namespaces into karma sub-namespaces of
44     // the same name
45     namespace ascii { using namespace boost::spirit::ascii; }
46     namespace iso8859_1 { using namespace boost::spirit::iso8859_1; }
47     namespace standard { using namespace boost::spirit::standard; }
48     namespace standard_wide { using namespace boost::spirit::standard_wide; }
49 #if defined(BOOST_SPIRIT_UNICODE)
50     namespace unicode { using namespace boost::spirit::unicode; }
51 #endif
52 
53     // Import the standard namespace into the karma namespace. This allows
54     // for default handling of all character/string related operations if not
55     // prefixed with a character set namespace.
56     using namespace boost::spirit::standard;
57 
58     // Import encoding
59     using spirit::encoding;
60 
61     ///////////////////////////////////////////////////////////////////////////
62     //
63     //  char_class
64     //      generates a single character if it matches the given character
65     //      class
66     //
67     ///////////////////////////////////////////////////////////////////////////
68     template <typename Tag, typename CharEncoding, typename CharClass>
69     struct char_class
70       : char_generator<
71             char_class<Tag, CharEncoding, CharClass>
72           , CharEncoding, CharClass>
73     {
74         typedef typename Tag::char_encoding char_encoding;
75         typedef typename char_encoding::char_type char_type;
76         typedef typename Tag::char_class classification;
77 
78         template <typename Context, typename Unused>
79         struct attribute
80         {
81             typedef char_type type;
82         };
83 
84         // char_class needs an attached attribute
85         template <typename Attribute, typename CharParam, typename Context>
testboost::spirit::karma::char_class86         bool test(Attribute const& attr, CharParam& ch, Context&) const
87         {
88             ch = attr;
89 
90             using spirit::char_class::classify;
91             return classify<char_encoding>::is(classification(), attr);
92         }
93 
94         // char_class shouldn't be used without any associated attribute
95         template <typename CharParam, typename Context>
testboost::spirit::karma::char_class96         bool test(unused_type, CharParam&, Context&) const
97         {
98             // It is not possible (doesn't make sense) to use char_ generators
99             // without providing any attribute, as the generator doesn't 'know'
100             // what to output. The following assertion fires if this situation
101             // is detected in your code.
102             BOOST_SPIRIT_ASSERT_FAIL(CharParam
103               , char_class_not_usable_without_attribute, ());
104             return false;
105         }
106 
107         template <typename Context>
whatboost::spirit::karma::char_class108         static info what(Context const& /*context*/)
109         {
110             typedef spirit::char_class::what<char_encoding> what_;
111             return info(what_::is(classification()));
112         }
113     };
114 
115     ///////////////////////////////////////////////////////////////////////////
116     //
117     //  space
118     //      generates a single character from the associated parameter
119     //
120     ///////////////////////////////////////////////////////////////////////////
121     template <typename CharEncoding>
122     struct any_space
123       : char_generator<any_space<CharEncoding>, CharEncoding, tag::space>
124     {
125         typedef typename CharEncoding::char_type char_type;
126         typedef CharEncoding char_encoding;
127 
128         template <typename Context, typename Unused>
129         struct attribute
130         {
131             typedef char_type type;
132         };
133 
134         // any_space has an attached parameter
135         template <typename Attribute, typename CharParam, typename Context>
testboost::spirit::karma::any_space136         bool test(Attribute const& attr, CharParam& ch, Context&) const
137         {
138             ch = CharParam(attr);
139 
140             using spirit::char_class::classify;
141             return classify<char_encoding>::is(tag::space(), attr);
142         }
143 
144         // any_space has no attribute attached, use single space character
145         template <typename CharParam, typename Context>
testboost::spirit::karma::any_space146         bool test(unused_type, CharParam& ch, Context&) const
147         {
148             ch = ' ';
149             return true;
150         }
151 
152         template <typename Context>
whatboost::spirit::karma::any_space153         static info what(Context const& /*context*/)
154         {
155             return info("space");
156         }
157     };
158 
159     ///////////////////////////////////////////////////////////////////////////
160     // Generator generators: make_xxx function (objects)
161     ///////////////////////////////////////////////////////////////////////////
162 
163     namespace detail
164     {
165         template <typename Tag, bool lower = false, bool upper = false>
166         struct make_char_class : mpl::identity<Tag> {};
167 
168         template <>
169         struct make_char_class<tag::alpha, true, false>
170           : mpl::identity<tag::lower> {};
171 
172         template <>
173         struct make_char_class<tag::alpha, false, true>
174           : mpl::identity<tag::upper> {};
175 
176         template <>
177         struct make_char_class<tag::alnum, true, false>
178           : mpl::identity<tag::lowernum> {};
179 
180         template <>
181         struct make_char_class<tag::alnum, false, true>
182           : mpl::identity<tag::uppernum> {};
183     }
184 
185     // enables alnum, alpha, graph, etc.
186     template <typename CharClass, typename CharEncoding, typename Modifiers>
187     struct make_primitive<tag::char_code<CharClass, CharEncoding>, Modifiers>
188     {
189         static bool const lower =
190             has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
191         static bool const upper =
192             has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
193 
194         typedef tag::char_code<
195             typename detail::make_char_class<CharClass, lower, upper>::type
196           , CharEncoding>
197         tag_type;
198 
199         typedef char_class<
200             tag_type
201           , typename spirit::detail::get_encoding_with_case<
202                 Modifiers, CharEncoding, lower || upper>::type
203           , typename detail::get_casetag<Modifiers, lower || upper>::type
204         > result_type;
205 
operator ()boost::spirit::karma::make_primitive206         result_type operator()(unused_type, unused_type) const
207         {
208             return result_type();
209         }
210     };
211 
212     // space is special
213     template <typename CharEncoding, typename Modifiers>
214     struct make_primitive<tag::char_code<tag::space, CharEncoding>, Modifiers>
215     {
216         typedef any_space<CharEncoding> result_type;
217 
operator ()boost::spirit::karma::make_primitive218         result_type operator()(unused_type, unused_type) const
219         {
220             return result_type();
221         }
222     };
223 
224 }}}  // namespace boost::spirit::karma
225 
226 #endif // !defined(BOOST_SPIRIT_KARMA_CHAR_FEB_21_2007_0543PM)
227