// 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /////////////////////////////////////////////////////////////////////////////// namespace boost { namespace spirit { /////////////////////////////////////////////////////////////////////////// // Enablers /////////////////////////////////////////////////////////////////////////// template struct use_terminal // enables char_ > : mpl::true_ {}; template struct use_terminal // enables char_('x'), char_("x") , fusion::vector1 > > : mpl::true_ {}; template struct use_terminal // enables char_('a','z') , fusion::vector2 > > : mpl::true_ {}; template // enables *lazy* char_('x'), char_("x") struct use_lazy_terminal< karma::domain , tag::char_code , 1 // arity > : mpl::true_ {}; template <> struct use_terminal // enables 'x' : mpl::true_ {}; template <> struct use_terminal // enables "x" : mpl::true_ {}; template <> struct use_terminal // enables L'x' : mpl::true_ {}; template <> struct use_terminal // 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 struct any_char : char_generator, CharEncoding, Tag> { typedef typename CharEncoding::char_type char_type; typedef CharEncoding char_encoding; template struct attribute { typedef char_type type; }; // any_char has an attached parameter template 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 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 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 struct literal_char : char_generator , CharEncoding, Tag> { typedef typename CharEncoding::char_type char_type; typedef CharEncoding char_encoding; literal_char(char_type ch) : ch (spirit::char_class::convert::to(Tag(), ch)) {} template struct attribute : mpl::if_c {}; // 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 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 bool test(unused_type, CharParam& ch_, Context&) const { ch_ = ch; return true; } template info what(Context const& /*context*/) const { return info("literal-char", char_encoding::toucs4(ch)); } char_type ch; }; /////////////////////////////////////////////////////////////////////////// // char range generator template struct char_range : char_generator, 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::to(Tag(), from)) , to(spirit::char_class::convert::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 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 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 info what(Context& /*context*/) const { info result("char-range", char_encoding::toucs4(from)); boost::get(result.value) += '-'; boost::get(result.value) += to_utf8(char_encoding::toucs4(to)); return result; } char_type from, to; }; /////////////////////////////////////////////////////////////////////////// // character set generator template struct char_set : char_generator, CharEncoding, Tag> { typedef typename CharEncoding::char_type char_type; typedef CharEncoding char_encoding; template char_set(String const& str) { typedef typename traits::char_type_of::type in_type; BOOST_SPIRIT_ASSERT_MSG(( (sizeof(char_type) == sizeof(in_type)) ), cannot_convert_string, (String)); typedef spirit::char_class::convert 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 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 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 info what(Context& /*context*/) const { return info("char-set"); } support::detail::basic_chset chset; }; /////////////////////////////////////////////////////////////////////////// // Generator generators: make_xxx function (objects) /////////////////////////////////////////////////////////////////////////// namespace detail { template struct basic_literal { static bool const lower = has_modifier >::value; static bool const upper = has_modifier >::value; typedef literal_char< typename spirit::detail::get_encoding_with_case< Modifiers, Encoding, lower || upper>::type , typename get_casetag::type , true> result_type; template result_type operator()(Char ch, unused_type) const { return result_type(ch); } template result_type operator()(Char const* str, unused_type) const { return result_type(str[0]); } }; } // literals: 'x', "x" template struct make_primitive : detail::basic_literal {}; template struct make_primitive : detail::basic_literal {}; // literals: L'x', L"x" template struct make_primitive : detail::basic_literal {}; template struct make_primitive : detail::basic_literal {}; // char_ template struct make_primitive, Modifiers> { static bool const lower = has_modifier >::value; static bool const upper = has_modifier >::value; typedef any_char< typename spirit::detail::get_encoding_with_case< Modifiers, CharEncoding, lower || upper>::type , typename detail::get_casetag::type > result_type; result_type operator()(unused_type, unused_type) const { return result_type(); } }; // char_(...) template struct make_primitive< terminal_ex< tag::char_code , fusion::vector1 > , Modifiers> { static bool const lower = has_modifier >::value; static bool const upper = has_modifier >::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 , char_set , literal_char >::type result_type; template result_type operator()(Terminal const& term, unused_type) const { return result_type(fusion::at_c<0>(term.args)); } }; // char_("x") template struct make_primitive< terminal_ex< tag::char_code , fusion::vector1 // For single char strings > , Modifiers> { static bool const lower = has_modifier >::value; static bool const upper = has_modifier >::value; typedef literal_char< typename spirit::detail::get_encoding_with_case< Modifiers, CharEncoding, lower || upper>::type , typename detail::get_casetag::type , false > result_type; template result_type operator()(Terminal const& term, unused_type) const { return result_type(fusion::at_c<0>(term.args)[0]); } }; // char_('a', 'z') template struct make_primitive< terminal_ex< tag::char_code , fusion::vector2 > , Modifiers> { static bool const lower = has_modifier >::value; static bool const upper = has_modifier >::value; typedef char_range< typename spirit::detail::get_encoding_with_case< Modifiers, CharEncoding, lower || upper>::type , typename detail::get_casetag::type > result_type; template 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 struct make_primitive< terminal_ex< tag::char_code , fusion::vector2 // For single char strings > , Modifiers> { static bool const lower = has_modifier >::value; static bool const upper = has_modifier >::value; typedef char_range< typename spirit::detail::get_encoding_with_case< Modifiers, CharEncoding, lower || upper>::type , typename detail::get_casetag::type > result_type; template 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