123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547 |
- // Copyright (c) 2001-2011 Hartmut Kaiser
- // Copyright (c) 2010 Bryce Lelbach
- //
- // 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/spirit/home/karma/detail/enable_lit.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 <boost/utility/enable_if.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 A0>
- struct use_terminal<karma::domain
- , terminal_ex<tag::lit, fusion::vector1<A0> > // enables lit('x')
- , typename enable_if<traits::is_char<A0> >::type>
- : 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
- {
- #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
- using spirit::lit; // lit('x') is equivalent to 'x'
- #endif
- using spirit::lit_type;
- ///////////////////////////////////////////////////////////////////////////
- //
- // 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_FAIL(CharParam, 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_ = static_cast<char_type>(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_FAIL(CharParam
- , 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, bool no_attribute>
- struct char_set
- : char_generator<char_set<CharEncoding, Tag, no_attribute>
- , CharEncoding, Tag>
- {
- typedef typename CharEncoding::char_type char_type;
- typedef CharEncoding char_encoding;
- template <typename Context, typename Unused>
- struct attribute
- : mpl::if_c<no_attribute, unused_type, char_type>
- {};
- 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_FAIL(CharParam
- , 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();
- }
- };
- ///////////////////////////////////////////////////////////////////////////
- namespace detail
- {
- template <typename CharEncoding, typename Modifiers, typename A0
- , bool no_attribute>
- struct make_char_direct
- {
- 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, no_attribute>
- , literal_char<encoding, tag, no_attribute>
- >::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_(...), lit(...)
- template <typename CharEncoding, typename Modifiers, typename A0>
- struct make_primitive<
- terminal_ex<
- tag::char_code<tag::char_, CharEncoding>
- , fusion::vector1<A0> >
- , Modifiers>
- : detail::make_char_direct<CharEncoding, Modifiers, A0, false>
- {};
- template <typename Modifiers, typename A0>
- struct make_primitive<
- terminal_ex<tag::lit, fusion::vector1<A0> >
- , Modifiers
- , typename enable_if<traits::is_char<A0> >::type>
- : detail::make_char_direct<
- typename traits::char_encoding_from_char<
- typename traits::char_type_of<A0>::type>::type
- , Modifiers, A0, true>
- {};
- ///////////////////////////////////////////////////////////////////////////
- // 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
|