diff --git a/doc/tutorial.qbk b/doc/tutorial.qbk index cbdc14a7..ce6a6e46 100644 --- a/doc/tutorial.qbk +++ b/doc/tutorial.qbk @@ -1809,14 +1809,15 @@ for `p`. as `X >> Y -> Z`, where `X` is the type of the current attribute, `Y` is the type of the next attribute, and `Z` is the new current attribute type. In these rules, `C` is a container of `T`; `none` is a special type that -indicates that there is no attribute; `T` is a type; and `Ts...` is a -parameter pack of one or more types. Note that `T` may be the special type -`none`. The current attribute is always a tuple (call it `Tup`), so the -"current attribute `X`" refers to the last element of `Tup`, not `Tup` itself, -except for those rules that explicitly mention `_bp_tup_<>` as part of `X`'s -type. +indicates that there is no attribute; `T` is a type; `CHAR` is a character +type, either `char` or `char32_t`; and `Ts...` is a parameter pack of one or +more types. Note that `T` may be the special type `none`. The current +attribute is always a tuple (call it `Tup`), so the "current attribute `X`" +refers to the last element of `Tup`, not `Tup` itself, except for those rules +that explicitly mention `_bp_tup_<>` as part of `X`'s type. * `none >> T -> T` +* `CHAR` >> `CHAR` -> `std::string` * `T >> none -> T` * `C >> T -> C` * `T >> C -> C` diff --git a/include/boost/parser/parser.hpp b/include/boost/parser/parser.hpp index 6b108727..7ef884b7 100644 --- a/include/boost/parser/parser.hpp +++ b/include/boost/parser/parser.hpp @@ -1120,6 +1120,10 @@ namespace boost { namespace parser { } } + template + constexpr bool is_char_type_v = + std::is_same_v || std::is_same_v; + template struct optional_of_impl { @@ -3155,6 +3159,17 @@ namespace boost { namespace parser { result, detail::hl::append( indices, detail::hl::size_minus_one(result))); + } else if constexpr ( + detail::is_char_type_v && + (detail::is_char_type_v || + detail::is_char_type_v)) { + // CHAR >> CHAR -> string + return detail::hl::make_tuple( + detail::hl::append( + detail::hl::drop_back(result), + detail::wrapper{}), + detail::hl::append( + indices, detail::hl::size_minus_one(result))); } else if constexpr ( detail:: container_and_value_type || diff --git a/test/compile_seq_attribute.cpp b/test/compile_seq_attribute.cpp index d90a97ff..f78c5e3d 100644 --- a/test/compile_seq_attribute.cpp +++ b/test/compile_seq_attribute.cpp @@ -30,22 +30,22 @@ void compile_seq_attribute() { constexpr auto parser = char_ >> char_; using attr_t = decltype(prefix_parse(first, last, parser)); - static_assert(std::is_same_v>>); + static_assert(std::is_same_v>); } { constexpr auto parser = eps >> char_ >> char_; using attr_t = decltype(prefix_parse(first, last, parser)); - static_assert(std::is_same_v>>); + static_assert(std::is_same_v>); } { constexpr auto parser = char_ >> eps >> char_; using attr_t = decltype(prefix_parse(first, last, parser)); - static_assert(std::is_same_v>>); + static_assert(std::is_same_v>); } { constexpr auto parser = char_ >> char_ >> eps; using attr_t = decltype(prefix_parse(first, last, parser)); - static_assert(std::is_same_v>>); + static_assert(std::is_same_v>); } { constexpr auto parser = int_ >> char_; diff --git a/test/parser.cpp b/test/parser.cpp index 1d16d206..8f61662f 100644 --- a/test/parser.cpp +++ b/test/parser.cpp @@ -92,8 +92,8 @@ TEST(parser, basic) tuple result; EXPECT_TRUE(parse(str, parser_1, result)); using namespace boost::parser::literals; - EXPECT_EQ(get(result, 0_c), 'a'); - EXPECT_EQ(get(result, 1_c), 'b'); + EXPECT_EQ(get(result, 0_c), 'b'); + EXPECT_EQ(get(result, 1_c), '\0'); } { std::string str = "abc"; @@ -110,9 +110,9 @@ TEST(parser, basic) tuple result; EXPECT_TRUE(parse(str, parser_2, result)); using namespace boost::parser::literals; - EXPECT_EQ(get(result, 0_c), 'a'); - EXPECT_EQ(get(result, 1_c), 'b'); - EXPECT_EQ(get(result, 2_c), 'c'); + EXPECT_EQ(get(result, 0_c), 'c'); + EXPECT_EQ(get(result, 1_c), '\0'); + EXPECT_EQ(get(result, 2_c), '\0'); } { std::string str = "a"; @@ -1490,22 +1490,21 @@ TEST(parser, combined_seq_and_or) std::string str = "abc"; tuple chars; EXPECT_TRUE(parse(str, parser, chars)); - EXPECT_EQ(chars, tup('a', 'b', 'c')); + EXPECT_EQ(chars, tup('c', '\0', '\0')); // TODO: Document this behavior. } { std::string str = "abc"; - std::optional> const chars = - parse(str, parser); + std::optional const chars = parse(str, parser); EXPECT_TRUE(chars); - EXPECT_EQ(*chars, tup('a', 'b', 'c')); + EXPECT_EQ(*chars, "abc"); } { std::string str = "xyz"; tup chars; EXPECT_TRUE(parse(str, parser, chars)); - EXPECT_EQ(chars, tup('x', 'y', 'z')); + EXPECT_EQ(chars, tup('z', '\0', '\0')); } } @@ -1553,7 +1552,7 @@ TEST(parser, combined_seq_and_or) std::string str = "xyz"; tuple chars; EXPECT_TRUE(parse(str, parser, chars)); - EXPECT_EQ(chars, tup('x', 'y', 'z')); + EXPECT_EQ(chars, tup('z', '\0', '\0')); } } diff --git a/test/parser_api.cpp b/test/parser_api.cpp index b8359d78..c64e6a59 100644 --- a/test/parser_api.cpp +++ b/test/parser_api.cpp @@ -309,8 +309,8 @@ TEST(parser, basic) tuple result; EXPECT_TRUE(parse(str, parser_1, result)); using namespace boost::parser::literals; - EXPECT_EQ(get(result, 0_c), 'a'); - EXPECT_EQ(get(result, 1_c), 'b'); + EXPECT_EQ(get(result, 0_c), 'b'); + EXPECT_EQ(get(result, 1_c), '\0'); } { char const * str = "abc"; @@ -331,9 +331,9 @@ TEST(parser, basic) tuple result; EXPECT_TRUE(parse(str, parser_2, result)); using namespace boost::parser::literals; - EXPECT_EQ(get(result, 0_c), 'a'); - EXPECT_EQ(get(result, 1_c), 'b'); - EXPECT_EQ(get(result, 2_c), 'c'); + EXPECT_EQ(get(result, 0_c), 'c'); + EXPECT_EQ(get(result, 1_c), '\0'); + EXPECT_EQ(get(result, 2_c), '\0'); } { char const * str = "a"; @@ -1751,22 +1751,21 @@ TEST(parser, combined_seq_and_or) char const * str = "abc"; tuple chars; EXPECT_TRUE(parse(str, parser, chars)); - EXPECT_EQ(chars, tup('a', 'b', 'c')); + EXPECT_EQ(chars, tup('c', '\0', '\0')); } { char const * str = "abc"; - std::optional> const chars = - parse(str, parser); + std::optional const chars = parse(str, parser); EXPECT_TRUE(chars); - EXPECT_EQ(*chars, tup('a', 'b', 'c')); + EXPECT_EQ(*chars, "abc"); } { char const * str = "xyz"; tuple chars; EXPECT_TRUE(parse(str, parser, chars)); - EXPECT_EQ(chars, tup('x', 'y', 'z')); + EXPECT_EQ(chars, tup('z', '\0', '\0')); } } @@ -1814,7 +1813,7 @@ TEST(parser, combined_seq_and_or) char const * str = "xyz"; tuple chars; EXPECT_TRUE(parse(str, parser, chars)); - EXPECT_EQ(chars, tup('x', 'y', 'z')); + EXPECT_EQ(chars, tup('z', '\0', '\0')); } }