]> git.sesse.net Git - casparcg/blob - dependencies/boost/boost/spirit/home/karma/char/char.hpp
Manually merged pull request #222
[casparcg] / dependencies / boost / boost / spirit / home / karma / char / char.hpp
1 //  Copyright (c) 2001-2011 Hartmut Kaiser
2 //  Copyright (c)      2010 Bryce Lelbach
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_KARMA_CHAR_FEB_21_2007_0543PM)
8 #define BOOST_SPIRIT_KARMA_CHAR_FEB_21_2007_0543PM
9
10 #if defined(_MSC_VER)
11 #pragma once
12 #endif
13
14 #include <boost/spirit/home/support/common_terminals.hpp>
15 #include <boost/spirit/home/support/string_traits.hpp>
16 #include <boost/spirit/home/support/info.hpp>
17 #include <boost/spirit/home/support/char_class.hpp>
18 #include <boost/spirit/home/support/detail/get_encoding.hpp>
19 #include <boost/spirit/home/support/char_set/basic_chset.hpp>
20 #include <boost/spirit/home/karma/domain.hpp>
21 #include <boost/spirit/home/karma/meta_compiler.hpp>
22 #include <boost/spirit/home/karma/delimit_out.hpp>
23 #include <boost/spirit/home/karma/char/char_generator.hpp>
24 #include <boost/spirit/home/karma/auxiliary/lazy.hpp>
25 #include <boost/spirit/home/karma/detail/get_casetag.hpp>
26 #include <boost/spirit/home/karma/detail/generate_to.hpp>
27 #include <boost/spirit/home/karma/detail/enable_lit.hpp>
28 #include <boost/fusion/include/at.hpp>
29 #include <boost/fusion/include/vector.hpp>
30 #include <boost/fusion/include/cons.hpp>
31 #include <boost/mpl/if.hpp>
32 #include <boost/mpl/assert.hpp>
33 #include <boost/mpl/bool.hpp>
34 #include <boost/utility/enable_if.hpp>
35 #include <string>
36
37 ///////////////////////////////////////////////////////////////////////////////
38 namespace boost { namespace spirit
39 {
40     ///////////////////////////////////////////////////////////////////////////
41     // Enablers
42     ///////////////////////////////////////////////////////////////////////////
43     template <typename CharEncoding>
44     struct use_terminal<karma::domain
45       , tag::char_code<tag::char_, CharEncoding>        // enables char_
46     > : mpl::true_ {};
47
48     template <typename CharEncoding, typename A0>
49     struct use_terminal<karma::domain
50       , terminal_ex<
51             tag::char_code<tag::char_, CharEncoding>    // enables char_('x'), char_("x")
52           , fusion::vector1<A0>
53         >
54     > : mpl::true_ {};
55
56     template <typename A0>
57     struct use_terminal<karma::domain
58           , terminal_ex<tag::lit, fusion::vector1<A0> > // enables lit('x')
59           , typename enable_if<traits::is_char<A0> >::type>
60       : mpl::true_ {};
61
62     template <typename CharEncoding, typename A0, typename A1>
63     struct use_terminal<karma::domain
64       , terminal_ex<
65             tag::char_code<tag::char_, CharEncoding>    // enables char_('a','z')
66           , fusion::vector2<A0, A1>
67         >
68     > : mpl::true_ {};
69
70     template <typename CharEncoding>                    // enables *lazy* char_('x'), char_("x")
71     struct use_lazy_terminal<
72         karma::domain
73       , tag::char_code<tag::char_, CharEncoding>
74       , 1 // arity
75     > : mpl::true_ {};
76
77     template <>
78     struct use_terminal<karma::domain, char>            // enables 'x'
79       : mpl::true_ {};
80
81     template <>
82     struct use_terminal<karma::domain, char[2]>         // enables "x"
83       : mpl::true_ {};
84
85     template <>
86     struct use_terminal<karma::domain, wchar_t>         // enables L'x'
87       : mpl::true_ {};
88
89     template <>
90     struct use_terminal<karma::domain, wchar_t[2]>      // enables L"x"
91       : mpl::true_ {};
92 }}
93
94 ///////////////////////////////////////////////////////////////////////////////
95 namespace boost { namespace spirit { namespace karma
96 {
97 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
98     using spirit::lit;    // lit('x') is equivalent to 'x'
99 #endif
100     using spirit::lit_type;
101
102     ///////////////////////////////////////////////////////////////////////////
103     //
104     //  any_char
105     //      generates a single character from the associated attribute
106     //
107     //      Note: this generator has to have an associated attribute
108     //
109     ///////////////////////////////////////////////////////////////////////////
110     template <typename CharEncoding, typename Tag>
111     struct any_char
112       : char_generator<any_char<CharEncoding, Tag>, CharEncoding, Tag>
113     {
114         typedef typename CharEncoding::char_type char_type;
115         typedef CharEncoding char_encoding;
116
117         template <typename Context, typename Unused>
118         struct attribute
119         {
120             typedef char_type type;
121         };
122
123         // any_char has an attached parameter
124         template <typename Attribute, typename CharParam, typename Context>
125         bool test(Attribute const& attr, CharParam& ch, Context&) const
126         {
127             ch = CharParam(attr);
128             return true;
129         }
130
131         // any_char has no attribute attached, it needs to have been
132         // initialized from a direct literal
133         template <typename CharParam, typename Context>
134         bool test(unused_type, CharParam&, Context&) const
135         {
136             // It is not possible (doesn't make sense) to use char_ without
137             // providing any attribute, as the generator doesn't 'know' what
138             // character to output. The following assertion fires if this
139             // situation is detected in your code.
140             BOOST_SPIRIT_ASSERT_MSG(false, char_not_usable_without_attribute, ());
141             return false;
142         }
143
144         template <typename Context>
145         static info what(Context const& /*context*/)
146         {
147             return info("any-char");
148         }
149     };
150
151     ///////////////////////////////////////////////////////////////////////////
152     //
153     //  literal_char
154     //      generates a single character given by a literal it was initialized
155     //      from
156     //
157     ///////////////////////////////////////////////////////////////////////////
158     template <typename CharEncoding, typename Tag, bool no_attribute>
159     struct literal_char
160       : char_generator<literal_char<CharEncoding, Tag, no_attribute>
161           , CharEncoding, Tag>
162     {
163         typedef typename CharEncoding::char_type char_type;
164         typedef CharEncoding char_encoding;
165
166         literal_char(char_type ch)
167           : ch (spirit::char_class::convert<char_encoding>::to(Tag(), ch)) 
168         {}
169
170         template <typename Context, typename Unused>
171         struct attribute
172           : mpl::if_c<no_attribute, unused_type, char_type>
173         {};
174
175         // A char_('x') which additionally has an associated attribute emits
176         // its immediate literal only if it matches the attribute, otherwise
177         // it fails.
178         // any_char has an attached parameter
179         template <typename Attribute, typename CharParam, typename Context>
180         bool test(Attribute const& attr, CharParam& ch_, Context&) const
181         {
182             // fail if attribute isn't matched my immediate literal
183             ch_ = attr;
184             return attr == ch;
185         }
186
187         // A char_('x') without any associated attribute just emits its 
188         // immediate literal
189         template <typename CharParam, typename Context>
190         bool test(unused_type, CharParam& ch_, Context&) const
191         {
192             ch_ = ch;
193             return true;
194         }
195
196         template <typename Context>
197         info what(Context const& /*context*/) const
198         {
199             return info("literal-char", char_encoding::toucs4(ch));
200         }
201
202         char_type ch;
203     };
204
205     ///////////////////////////////////////////////////////////////////////////
206     // char range generator
207     template <typename CharEncoding, typename Tag>
208     struct char_range
209       : char_generator<char_range<CharEncoding, Tag>, CharEncoding, Tag>
210     {
211         typedef typename CharEncoding::char_type char_type;
212         typedef CharEncoding char_encoding;
213
214         char_range(char_type from, char_type to)
215           : from(spirit::char_class::convert<char_encoding>::to(Tag(), from))
216           , to(spirit::char_class::convert<char_encoding>::to(Tag(), to)) 
217         {}
218
219         // A char_('a', 'z') which has an associated attribute emits it only if 
220         // it matches the character range, otherwise it fails.
221         template <typename Attribute, typename CharParam, typename Context>
222         bool test(Attribute const& attr, CharParam& ch, Context&) const
223         {
224             // fail if attribute doesn't belong to character range
225             ch = attr;
226             return (from <= char_type(attr)) && (char_type(attr) <= to);
227         }
228
229         // A char_('a', 'z') without any associated attribute fails compiling
230         template <typename CharParam, typename Context>
231         bool test(unused_type, CharParam&, Context&) const
232         {
233             // It is not possible (doesn't make sense) to use char_ generators 
234             // without providing any attribute, as the generator doesn't 'know' 
235             // what to output. The following assertion fires if this situation
236             // is detected in your code.
237             BOOST_SPIRIT_ASSERT_MSG(false
238               , char_range_not_usable_without_attribute, ());
239             return false;
240         }
241
242         template <typename Context>
243         info what(Context& /*context*/) const
244         {
245             info result("char-range", char_encoding::toucs4(from));
246             boost::get<std::string>(result.value) += '-';
247             boost::get<std::string>(result.value) += to_utf8(char_encoding::toucs4(to));
248             return result;
249         }
250
251         char_type from, to;
252     };
253
254     ///////////////////////////////////////////////////////////////////////////
255     // character set generator
256     template <typename CharEncoding, typename Tag, bool no_attribute>
257     struct char_set
258       : char_generator<char_set<CharEncoding, Tag, no_attribute>
259           , CharEncoding, Tag>
260     {
261         typedef typename CharEncoding::char_type char_type;
262         typedef CharEncoding char_encoding;
263
264         template <typename Context, typename Unused>
265         struct attribute
266           : mpl::if_c<no_attribute, unused_type, char_type>
267         {};
268
269         template <typename String>
270         char_set(String const& str)
271         {
272             typedef typename traits::char_type_of<String>::type in_type;
273
274             BOOST_SPIRIT_ASSERT_MSG((
275                 (sizeof(char_type) == sizeof(in_type))
276             ), cannot_convert_string, (String));
277
278             typedef spirit::char_class::convert<char_encoding> convert_type;
279
280             char_type const* definition =
281                 (char_type const*)traits::get_c_string(str);
282             char_type ch = convert_type::to(Tag(), *definition++);
283             while (ch)
284             {
285                 char_type next = convert_type::to(Tag(), *definition++);
286                 if (next == '-')
287                 {
288                     next = convert_type::to(Tag(), *definition++);
289                     if (next == 0)
290                     {
291                         chset.set(ch);
292                         chset.set('-');
293                         break;
294                     }
295                     chset.set(ch, next);
296                 }
297                 else
298                 {
299                     chset.set(ch);
300                 }
301                 ch = next;
302             }
303         }
304
305         // A char_("a-z") which has an associated attribute emits it only if 
306         // it matches the character set, otherwise it fails.
307         template <typename Attribute, typename CharParam, typename Context>
308         bool test(Attribute const& attr, CharParam& ch, Context&) const
309         {
310             // fail if attribute doesn't belong to character set
311             ch = attr;
312             return chset.test(char_type(attr));
313         }
314
315         // A char_("a-z") without any associated attribute fails compiling
316         template <typename CharParam, typename Context>
317         bool test(unused_type, CharParam&, Context&) const
318         {
319             // It is not possible (doesn't make sense) to use char_ generators 
320             // without providing any attribute, as the generator doesn't 'know' 
321             // what to output. The following assertion fires if this situation
322             // is detected in your code.
323             BOOST_SPIRIT_ASSERT_MSG(false
324                , char_set_not_usable_without_attribute, ());
325             return false;
326         }
327
328         template <typename Context>
329         info what(Context& /*context*/) const
330         {
331             return info("char-set");
332         }
333
334         support::detail::basic_chset<char_type> chset;
335     };
336
337     ///////////////////////////////////////////////////////////////////////////
338     // Generator generators: make_xxx function (objects)
339     ///////////////////////////////////////////////////////////////////////////
340     namespace detail
341     {
342         template <typename Modifiers, typename Encoding>
343         struct basic_literal
344         {
345             static bool const lower =
346                 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
347             static bool const upper =
348                 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
349
350             typedef literal_char<
351                 typename spirit::detail::get_encoding_with_case<
352                     Modifiers, Encoding, lower || upper>::type
353               , typename get_casetag<Modifiers, lower || upper>::type
354               , true>
355             result_type;
356
357             template <typename Char>
358             result_type operator()(Char ch, unused_type) const
359             {
360                 return result_type(ch);
361             }
362
363             template <typename Char>
364             result_type operator()(Char const* str, unused_type) const
365             {
366                 return result_type(str[0]);
367             }
368         };
369     }
370
371     // literals: 'x', "x"
372     template <typename Modifiers>
373     struct make_primitive<char, Modifiers>
374       : detail::basic_literal<Modifiers, char_encoding::standard> {};
375
376     template <typename Modifiers>
377     struct make_primitive<char const(&)[2], Modifiers>
378       : detail::basic_literal<Modifiers, char_encoding::standard> {};
379
380     // literals: L'x', L"x"
381     template <typename Modifiers>
382     struct make_primitive<wchar_t, Modifiers>
383       : detail::basic_literal<Modifiers, char_encoding::standard_wide> {};
384
385     template <typename Modifiers>
386     struct make_primitive<wchar_t const(&)[2], Modifiers>
387       : detail::basic_literal<Modifiers, char_encoding::standard_wide> {};
388
389     // char_
390     template <typename CharEncoding, typename Modifiers>
391     struct make_primitive<tag::char_code<tag::char_, CharEncoding>, Modifiers>
392     {
393         static bool const lower =
394             has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
395         static bool const upper =
396             has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
397
398         typedef any_char<
399             typename spirit::detail::get_encoding_with_case<
400                 Modifiers, CharEncoding, lower || upper>::type
401           , typename detail::get_casetag<Modifiers, lower || upper>::type
402         > result_type;
403
404         result_type operator()(unused_type, unused_type) const
405         {
406             return result_type();
407         }
408     };
409
410     ///////////////////////////////////////////////////////////////////////////
411     namespace detail
412     {
413         template <typename CharEncoding, typename Modifiers, typename A0
414           , bool no_attribute>
415         struct make_char_direct
416         {
417             static bool const lower =
418                 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
419             static bool const upper =
420                 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
421
422             typedef typename spirit::detail::get_encoding_with_case<
423                 Modifiers, CharEncoding, lower || upper>::type encoding;
424             typedef typename detail::get_casetag<
425                 Modifiers, lower || upper>::type tag;
426
427             typedef typename mpl::if_<
428                 traits::is_string<A0>
429               , char_set<encoding, tag, no_attribute>
430               , literal_char<encoding, tag, no_attribute>
431             >::type result_type;
432
433             template <typename Terminal>
434             result_type operator()(Terminal const& term, unused_type) const
435             {
436                 return result_type(fusion::at_c<0>(term.args));
437             }
438         };
439     }
440
441     // char_(...), lit(...)
442     template <typename CharEncoding, typename Modifiers, typename A0>
443     struct make_primitive<
444             terminal_ex<
445                 tag::char_code<tag::char_, CharEncoding>
446               , fusion::vector1<A0> >
447           , Modifiers>
448       : detail::make_char_direct<CharEncoding, Modifiers, A0, false>
449     {};
450
451     template <typename Modifiers, typename A0>
452     struct make_primitive<
453             terminal_ex<tag::lit, fusion::vector1<A0> >
454           , Modifiers
455           , typename enable_if<traits::is_char<A0> >::type>
456       : detail::make_char_direct<
457             typename traits::char_encoding_from_char<
458                 typename traits::char_type_of<A0>::type>::type
459           , Modifiers, A0, true>
460     {};
461
462     ///////////////////////////////////////////////////////////////////////////
463     // char_("x")
464     template <typename CharEncoding, typename Modifiers, typename Char>
465     struct make_primitive<
466         terminal_ex<
467             tag::char_code<tag::char_, CharEncoding>
468           , fusion::vector1<Char(&)[2]> > // For single char strings
469       , Modifiers>
470     {
471         static bool const lower =
472             has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
473         static bool const upper =
474             has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
475
476         typedef literal_char<
477             typename spirit::detail::get_encoding_with_case<
478                 Modifiers, CharEncoding, lower || upper>::type
479           , typename detail::get_casetag<Modifiers, lower || upper>::type
480           , false
481         > result_type;
482
483         template <typename Terminal>
484         result_type operator()(Terminal const& term, unused_type) const
485         {
486             return result_type(fusion::at_c<0>(term.args)[0]);
487         }
488     };
489
490     ///////////////////////////////////////////////////////////////////////////
491     // char_('a', 'z')
492     template <typename CharEncoding, typename Modifiers, typename A0, typename A1>
493     struct make_primitive<
494         terminal_ex<
495             tag::char_code<tag::char_, CharEncoding>
496           , fusion::vector2<A0, A1>
497         >
498       , Modifiers>
499     {
500         static bool const lower =
501             has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
502         static bool const upper =
503             has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
504
505         typedef char_range<
506             typename spirit::detail::get_encoding_with_case<
507                 Modifiers, CharEncoding, lower || upper>::type
508           , typename detail::get_casetag<Modifiers, lower || upper>::type
509         > result_type;
510
511         template <typename Terminal>
512         result_type operator()(Terminal const& term, unused_type) const
513         {
514             return result_type(fusion::at_c<0>(term.args)
515               , fusion::at_c<1>(term.args));
516         }
517     };
518
519     template <typename CharEncoding, typename Modifiers, typename Char>
520     struct make_primitive<
521         terminal_ex<
522             tag::char_code<tag::char_, CharEncoding>
523           , fusion::vector2<Char(&)[2], Char(&)[2]> // For single char strings
524         >
525       , Modifiers>
526     {
527         static bool const lower =
528             has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
529         static bool const upper =
530             has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
531
532         typedef char_range<
533             typename spirit::detail::get_encoding_with_case<
534                 Modifiers, CharEncoding, lower || upper>::type
535           , typename detail::get_casetag<Modifiers, lower || upper>::type
536         > result_type;
537
538         template <typename Terminal>
539         result_type operator()(Terminal const& term, unused_type) const
540         {
541             return result_type(fusion::at_c<0>(term.args)[0]
542               , fusion::at_c<1>(term.args)[0]);
543         }
544     };
545 }}}   // namespace boost::spirit::karma
546
547 #endif