| // Copyright (c) 2001-2010 Hartmut Kaiser |
| // |
| // Distributed under the Boost Software License, Version 1.0. (See accompanying |
| // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| |
| #if !defined(BOOST_SPIRIT_KARMA_CHAR_FEB_21_2007_0543PM) |
| #define BOOST_SPIRIT_KARMA_CHAR_FEB_21_2007_0543PM |
| |
| #if defined(_MSC_VER) |
| #pragma once |
| #endif |
| |
| #include <boost/spirit/home/support/common_terminals.hpp> |
| #include <boost/spirit/home/support/string_traits.hpp> |
| #include <boost/spirit/home/support/info.hpp> |
| #include <boost/spirit/home/support/char_class.hpp> |
| #include <boost/spirit/home/support/detail/get_encoding.hpp> |
| #include <boost/spirit/home/support/char_set/basic_chset.hpp> |
| #include <boost/spirit/home/karma/domain.hpp> |
| #include <boost/spirit/home/karma/meta_compiler.hpp> |
| #include <boost/spirit/home/karma/delimit_out.hpp> |
| #include <boost/spirit/home/karma/char/char_generator.hpp> |
| #include <boost/spirit/home/karma/auxiliary/lazy.hpp> |
| #include <boost/spirit/home/karma/detail/get_casetag.hpp> |
| #include <boost/spirit/home/karma/detail/generate_to.hpp> |
| #include <boost/fusion/include/at.hpp> |
| #include <boost/fusion/include/vector.hpp> |
| #include <boost/fusion/include/cons.hpp> |
| #include <boost/mpl/if.hpp> |
| #include <boost/mpl/assert.hpp> |
| #include <boost/mpl/bool.hpp> |
| #include <string> |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| namespace boost { namespace spirit |
| { |
| /////////////////////////////////////////////////////////////////////////// |
| // Enablers |
| /////////////////////////////////////////////////////////////////////////// |
| template <typename CharEncoding> |
| struct use_terminal<karma::domain |
| , tag::char_code<tag::char_, CharEncoding> // enables char_ |
| > : mpl::true_ {}; |
| |
| template <typename CharEncoding, typename A0> |
| struct use_terminal<karma::domain |
| , terminal_ex< |
| tag::char_code<tag::char_, CharEncoding> // enables char_('x'), char_("x") |
| , fusion::vector1<A0> |
| > |
| > : mpl::true_ {}; |
| |
| template <typename CharEncoding, typename A0, typename A1> |
| struct use_terminal<karma::domain |
| , terminal_ex< |
| tag::char_code<tag::char_, CharEncoding> // enables char_('a','z') |
| , fusion::vector2<A0, A1> |
| > |
| > : mpl::true_ {}; |
| |
| template <typename CharEncoding> // enables *lazy* char_('x'), char_("x") |
| struct use_lazy_terminal< |
| karma::domain |
| , tag::char_code<tag::char_, CharEncoding> |
| , 1 // arity |
| > : mpl::true_ {}; |
| |
| template <> |
| struct use_terminal<karma::domain, char> // enables 'x' |
| : mpl::true_ {}; |
| |
| template <> |
| struct use_terminal<karma::domain, char[2]> // enables "x" |
| : mpl::true_ {}; |
| |
| template <> |
| struct use_terminal<karma::domain, wchar_t> // enables L'x' |
| : mpl::true_ {}; |
| |
| template <> |
| struct use_terminal<karma::domain, wchar_t[2]> // enables L"x" |
| : mpl::true_ {}; |
| |
| }} |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| namespace boost { namespace spirit { namespace karma |
| { |
| using spirit::lit; // lit('x') is equivalent to 'x' |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // |
| // any_char |
| // generates a single character from the associated attribute |
| // |
| // Note: this generator has to have an associated attribute |
| // |
| /////////////////////////////////////////////////////////////////////////// |
| template <typename CharEncoding, typename Tag> |
| struct any_char |
| : char_generator<any_char<CharEncoding, Tag>, CharEncoding, Tag> |
| { |
| typedef typename CharEncoding::char_type char_type; |
| typedef CharEncoding char_encoding; |
| |
| template <typename Context, typename Unused> |
| struct attribute |
| { |
| typedef char_type type; |
| }; |
| |
| // any_char has an attached parameter |
| template <typename Attribute, typename CharParam, typename Context> |
| bool test(Attribute const& attr, CharParam& ch, Context&) const |
| { |
| ch = CharParam(attr); |
| return true; |
| } |
| |
| // any_char has no attribute attached, it needs to have been |
| // initialized from a direct literal |
| template <typename CharParam, typename Context> |
| bool test(unused_type, CharParam&, Context&) const |
| { |
| // It is not possible (doesn't make sense) to use char_ without |
| // providing any attribute, as the generator doesn't 'know' what |
| // character to output. The following assertion fires if this |
| // situation is detected in your code. |
| BOOST_SPIRIT_ASSERT_MSG(false, char_not_usable_without_attribute, ()); |
| return false; |
| } |
| |
| template <typename Context> |
| static info what(Context const& /*context*/) |
| { |
| return info("any-char"); |
| } |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // |
| // literal_char |
| // generates a single character given by a literal it was initialized |
| // from |
| // |
| /////////////////////////////////////////////////////////////////////////// |
| template <typename CharEncoding, typename Tag, bool no_attribute> |
| struct literal_char |
| : char_generator<literal_char<CharEncoding, Tag, no_attribute> |
| , CharEncoding, Tag> |
| { |
| typedef typename CharEncoding::char_type char_type; |
| typedef CharEncoding char_encoding; |
| |
| literal_char(char_type ch) |
| : ch (spirit::char_class::convert<char_encoding>::to(Tag(), ch)) |
| {} |
| |
| template <typename Context, typename Unused> |
| struct attribute |
| : mpl::if_c<no_attribute, unused_type, char_type> |
| {}; |
| |
| // A char_('x') which additionally has an associated attribute emits |
| // its immediate literal only if it matches the attribute, otherwise |
| // it fails. |
| // any_char has an attached parameter |
| template <typename Attribute, typename CharParam, typename Context> |
| bool test(Attribute const& attr, CharParam& ch_, Context&) const |
| { |
| // fail if attribute isn't matched my immediate literal |
| ch_ = attr; |
| return attr == ch; |
| } |
| |
| // A char_('x') without any associated attribute just emits its |
| // immediate literal |
| template <typename CharParam, typename Context> |
| bool test(unused_type, CharParam& ch_, Context&) const |
| { |
| ch_ = ch; |
| return true; |
| } |
| |
| template <typename Context> |
| info what(Context const& /*context*/) const |
| { |
| return info("literal-char", char_encoding::toucs4(ch)); |
| } |
| |
| char_type ch; |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // char range generator |
| template <typename CharEncoding, typename Tag> |
| struct char_range |
| : char_generator<char_range<CharEncoding, Tag>, CharEncoding, Tag> |
| { |
| typedef typename CharEncoding::char_type char_type; |
| typedef CharEncoding char_encoding; |
| |
| char_range(char_type from, char_type to) |
| : from(spirit::char_class::convert<char_encoding>::to(Tag(), from)) |
| , to(spirit::char_class::convert<char_encoding>::to(Tag(), to)) |
| {} |
| |
| // A char_('a', 'z') which has an associated attribute emits it only if |
| // it matches the character range, otherwise it fails. |
| template <typename Attribute, typename CharParam, typename Context> |
| bool test(Attribute const& attr, CharParam& ch, Context&) const |
| { |
| // fail if attribute doesn't belong to character range |
| ch = attr; |
| return (from <= char_type(attr)) && (char_type(attr) <= to); |
| } |
| |
| // A char_('a', 'z') without any associated attribute fails compiling |
| template <typename CharParam, typename Context> |
| bool test(unused_type, CharParam&, Context&) const |
| { |
| // It is not possible (doesn't make sense) to use char_ generators |
| // without providing any attribute, as the generator doesn't 'know' |
| // what to output. The following assertion fires if this situation |
| // is detected in your code. |
| BOOST_SPIRIT_ASSERT_MSG(false |
| , char_range_not_usable_without_attribute, ()); |
| return false; |
| } |
| |
| template <typename Context> |
| info what(Context& /*context*/) const |
| { |
| info result("char-range", char_encoding::toucs4(from)); |
| boost::get<std::string>(result.value) += '-'; |
| boost::get<std::string>(result.value) += to_utf8(char_encoding::toucs4(to)); |
| return result; |
| } |
| |
| char_type from, to; |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // character set generator |
| template <typename CharEncoding, typename Tag> |
| struct char_set |
| : char_generator<char_set<CharEncoding, Tag>, CharEncoding, Tag> |
| { |
| typedef typename CharEncoding::char_type char_type; |
| typedef CharEncoding char_encoding; |
| |
| template <typename String> |
| char_set(String const& str) |
| { |
| typedef typename traits::char_type_of<String>::type in_type; |
| |
| BOOST_SPIRIT_ASSERT_MSG(( |
| (sizeof(char_type) == sizeof(in_type)) |
| ), cannot_convert_string, (String)); |
| |
| typedef spirit::char_class::convert<char_encoding> convert_type; |
| |
| char_type const* definition = |
| (char_type const*)traits::get_c_string(str); |
| char_type ch = convert_type::to(Tag(), *definition++); |
| while (ch) |
| { |
| char_type next = convert_type::to(Tag(), *definition++); |
| if (next == '-') |
| { |
| next = convert_type::to(Tag(), *definition++); |
| if (next == 0) |
| { |
| chset.set(ch); |
| chset.set('-'); |
| break; |
| } |
| chset.set(ch, next); |
| } |
| else |
| { |
| chset.set(ch); |
| } |
| ch = next; |
| } |
| } |
| |
| // A char_("a-z") which has an associated attribute emits it only if |
| // it matches the character set, otherwise it fails. |
| template <typename Attribute, typename CharParam, typename Context> |
| bool test(Attribute const& attr, CharParam& ch, Context&) const |
| { |
| // fail if attribute doesn't belong to character set |
| ch = attr; |
| return chset.test(char_type(attr)); |
| } |
| |
| // A char_("a-z") without any associated attribute fails compiling |
| template <typename CharParam, typename Context> |
| bool test(unused_type, CharParam&, Context&) const |
| { |
| // It is not possible (doesn't make sense) to use char_ generators |
| // without providing any attribute, as the generator doesn't 'know' |
| // what to output. The following assertion fires if this situation |
| // is detected in your code. |
| BOOST_SPIRIT_ASSERT_MSG(false |
| , char_set_not_usable_without_attribute, ()); |
| return false; |
| } |
| |
| template <typename Context> |
| info what(Context& /*context*/) const |
| { |
| return info("char-set"); |
| } |
| |
| support::detail::basic_chset<char_type> chset; |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // Generator generators: make_xxx function (objects) |
| /////////////////////////////////////////////////////////////////////////// |
| namespace detail |
| { |
| template <typename Modifiers, typename Encoding> |
| struct basic_literal |
| { |
| static bool const lower = |
| has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value; |
| static bool const upper = |
| has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value; |
| |
| typedef literal_char< |
| typename spirit::detail::get_encoding_with_case< |
| Modifiers, Encoding, lower || upper>::type |
| , typename get_casetag<Modifiers, lower || upper>::type |
| , true> |
| result_type; |
| |
| template <typename Char> |
| result_type operator()(Char ch, unused_type) const |
| { |
| return result_type(ch); |
| } |
| |
| template <typename Char> |
| result_type operator()(Char const* str, unused_type) const |
| { |
| return result_type(str[0]); |
| } |
| }; |
| } |
| |
| // literals: 'x', "x" |
| template <typename Modifiers> |
| struct make_primitive<char, Modifiers> |
| : detail::basic_literal<Modifiers, char_encoding::standard> {}; |
| |
| template <typename Modifiers> |
| struct make_primitive<char const(&)[2], Modifiers> |
| : detail::basic_literal<Modifiers, char_encoding::standard> {}; |
| |
| // literals: L'x', L"x" |
| template <typename Modifiers> |
| struct make_primitive<wchar_t, Modifiers> |
| : detail::basic_literal<Modifiers, char_encoding::standard_wide> {}; |
| |
| template <typename Modifiers> |
| struct make_primitive<wchar_t const(&)[2], Modifiers> |
| : detail::basic_literal<Modifiers, char_encoding::standard_wide> {}; |
| |
| // char_ |
| template <typename CharEncoding, typename Modifiers> |
| struct make_primitive<tag::char_code<tag::char_, CharEncoding>, Modifiers> |
| { |
| static bool const lower = |
| has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value; |
| static bool const upper = |
| has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value; |
| |
| typedef any_char< |
| typename spirit::detail::get_encoding_with_case< |
| Modifiers, CharEncoding, lower || upper>::type |
| , typename detail::get_casetag<Modifiers, lower || upper>::type |
| > result_type; |
| |
| result_type operator()(unused_type, unused_type) const |
| { |
| return result_type(); |
| } |
| }; |
| |
| // char_(...) |
| template <typename CharEncoding, typename Modifiers, typename A0> |
| struct make_primitive< |
| terminal_ex< |
| tag::char_code<tag::char_, CharEncoding> |
| , fusion::vector1<A0> |
| > |
| , Modifiers> |
| { |
| static bool const lower = |
| has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value; |
| static bool const upper = |
| has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value; |
| |
| typedef typename spirit::detail::get_encoding_with_case< |
| Modifiers, CharEncoding, lower || upper>::type encoding; |
| typedef typename detail::get_casetag< |
| Modifiers, lower || upper>::type tag; |
| |
| typedef typename mpl::if_< |
| traits::is_string<A0> |
| , char_set<encoding, tag> |
| , literal_char<encoding, tag, false> |
| >::type result_type; |
| |
| template <typename Terminal> |
| result_type operator()(Terminal const& term, unused_type) const |
| { |
| return result_type(fusion::at_c<0>(term.args)); |
| } |
| }; |
| |
| // char_("x") |
| template <typename CharEncoding, typename Modifiers, typename Char> |
| struct make_primitive< |
| terminal_ex< |
| tag::char_code<tag::char_, CharEncoding> |
| , fusion::vector1<Char(&)[2]> // For single char strings |
| > |
| , Modifiers> |
| { |
| static bool const lower = |
| has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value; |
| static bool const upper = |
| has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value; |
| |
| typedef literal_char< |
| typename spirit::detail::get_encoding_with_case< |
| Modifiers, CharEncoding, lower || upper>::type |
| , typename detail::get_casetag<Modifiers, lower || upper>::type |
| , false |
| > result_type; |
| |
| template <typename Terminal> |
| result_type operator()(Terminal const& term, unused_type) const |
| { |
| return result_type(fusion::at_c<0>(term.args)[0]); |
| } |
| }; |
| |
| // char_('a', 'z') |
| template <typename CharEncoding, typename Modifiers, typename A0, typename A1> |
| struct make_primitive< |
| terminal_ex< |
| tag::char_code<tag::char_, CharEncoding> |
| , fusion::vector2<A0, A1> |
| > |
| , Modifiers> |
| { |
| static bool const lower = |
| has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value; |
| static bool const upper = |
| has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value; |
| |
| typedef char_range< |
| typename spirit::detail::get_encoding_with_case< |
| Modifiers, CharEncoding, lower || upper>::type |
| , typename detail::get_casetag<Modifiers, lower || upper>::type |
| > result_type; |
| |
| template <typename Terminal> |
| result_type operator()(Terminal const& term, unused_type) const |
| { |
| return result_type(fusion::at_c<0>(term.args) |
| , fusion::at_c<1>(term.args)); |
| } |
| }; |
| |
| template <typename CharEncoding, typename Modifiers, typename Char> |
| struct make_primitive< |
| terminal_ex< |
| tag::char_code<tag::char_, CharEncoding> |
| , fusion::vector2<Char(&)[2], Char(&)[2]> // For single char strings |
| > |
| , Modifiers> |
| { |
| static bool const lower = |
| has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value; |
| static bool const upper = |
| has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value; |
| |
| typedef char_range< |
| typename spirit::detail::get_encoding_with_case< |
| Modifiers, CharEncoding, lower || upper>::type |
| , typename detail::get_casetag<Modifiers, lower || upper>::type |
| > result_type; |
| |
| template <typename Terminal> |
| result_type operator()(Terminal const& term, unused_type) const |
| { |
| return result_type(fusion::at_c<0>(term.args)[0] |
| , fusion::at_c<1>(term.args)[0]); |
| } |
| }; |
| }}} // namespace boost::spirit::karma |
| |
| #endif |