diff --git a/include/boost/parser/parser.hpp b/include/boost/parser/parser.hpp index ed0106a1..5d21a15b 100644 --- a/include/boost/parser/parser.hpp +++ b/include/boost/parser/parser.hpp @@ -23,6 +23,23 @@ namespace boost { namespace parser { + /** A variable template that indicates that type `T` is an optional-like + type. */ + template + constexpr bool enable_optional = false; + + /** A variable template that indicates that type `T` is an variant-like + type. */ + template + constexpr bool enable_variant = false; + +#ifndef BOOST_PARSER_DOXYGEN + template + constexpr bool enable_optional> = true; + template + constexpr bool enable_variant> = true; +#endif + /** A placeholder type used to represent the absence of information, value, etc., inside semantic actions. For instance, calling `_locals(ctx)` in a semantic action associated with a parser that has @@ -906,18 +923,10 @@ namespace boost { namespace parser { {}; template - struct is_optional : std::false_type - {}; - template - struct is_optional> : std::true_type - {}; + constexpr bool is_optional_v = enable_optional; template - struct is_variant : std::false_type - {}; - template - struct is_variant> : std::true_type - {}; + constexpr bool is_variant_v = enable_variant; template struct is_utf8_view : std::false_type @@ -1060,7 +1069,7 @@ namespace boost { namespace parser { // for tuple and on for tuple>, is because // MSVC. using type = - std::conditional_t::value, T, std::optional>; + std::conditional_t, T, std::optional>; }; template @@ -2408,19 +2417,29 @@ namespace boost { namespace parser { remove_cv_ref_t{}))>; if constexpr (!T::value) { return std::false_type{}; + } else if constexpr ( + is_optional_v && is_optional_v) { + using struct_opt_type = optional_type; + using tuple_opt_type = optional_type; + using retval_t = decltype((*this)( + result, + detail::hl::make_tuple( + std::declval(), + std::declval()))); + return retval_t{}; } else if constexpr (std::is_convertible_v< tuple_elem &&, struct_elem>) { return std::true_type{}; } else if constexpr ( container && container) { - return detail::is_struct_compatible< - range_value_t, - range_value_t>(); + return detail::is_struct_compatible< + range_value_t, + range_value_t>(); } else { - return std::bool_constant()>{}; + return std::bool_constant()>{}; } } }; @@ -2665,7 +2684,7 @@ namespace boost { namespace parser { : flags, retval); - if constexpr (detail::is_optional{}) { + if constexpr (detail::is_optional_v) { detail::optional_type attr; detail::apply_parser( *this, @@ -3360,7 +3379,7 @@ namespace boost { namespace parser { indices; std::decay_t{}))> merged; - if constexpr (detail::is_variant{}) { + if constexpr (detail::is_variant_v) { detail::apply_parser( *this, use_cbs, @@ -3371,7 +3390,7 @@ namespace boost { namespace parser { detail::set_in_apply_parser(flags), success, retval); - } else if constexpr (detail::is_optional{}) { + } else if constexpr (detail::is_optional_v) { typename Attribute::value_type attr; call( use_cbs, first_, last, context, skip, flags, success, attr); diff --git a/test/parser.cpp b/test/parser.cpp index 9f4bb80f..1d16d206 100644 --- a/test/parser.cpp +++ b/test/parser.cpp @@ -8,11 +8,23 @@ #include +#if __has_include() +#define TEST_BOOST_OPTIONAL 1 +#include +#include +#else +#define TEST_BOOST_OPTIONAL 0 +#endif + #include using namespace boost::parser; +#if TEST_BOOST_OPTIONAL +template +constexpr bool boost::parser::enable_optional> = true; +#endif TEST(parser, basic) { @@ -156,6 +168,27 @@ TEST(parser, basic) first, boost::parser::detail::text::null_sentinel, parser_5, c)); EXPECT_EQ(c, std::nullopt); } +#if TEST_BOOST_OPTIONAL + { + std::string str = "a"; + boost::optional c; + EXPECT_TRUE(parse(str, parser_5, c)); + EXPECT_EQ(c, 'a'); + } + { + std::string str = "z"; + boost::optional c; + EXPECT_FALSE(parse(str, parser_5, c)); + } + { + std::string str = "z"; + boost::optional c; + auto first = str.c_str(); + EXPECT_TRUE(prefix_parse( + first, boost::parser::detail::text::null_sentinel, parser_5, c)); + EXPECT_EQ(c, boost::none); + } +#endif } TEST(parser, int_uint) diff --git a/test/tuple_aggregate.cpp b/test/tuple_aggregate.cpp index 1d752c8f..51f0a25a 100644 --- a/test/tuple_aggregate.cpp +++ b/test/tuple_aggregate.cpp @@ -8,11 +8,49 @@ #include +#if __has_include() +#define TEST_BOOST_OPTIONAL 1 +#include +#else +#define TEST_BOOST_OPTIONAL 0 +#endif + +#if __has_include() +#define TEST_BOOST_VARIANT 1 +#include +#include +#else +#define TEST_BOOST_VARIANT 0 +#endif + +#if __has_include() +#define TEST_BOOST_VARIANT2 1 +#include +#else +#define TEST_BOOST_VARIANT2 0 +#endif + #include using namespace boost::parser; +#if TEST_BOOST_OPTIONAL +template +constexpr bool boost::parser::enable_optional> = true; +#endif + +#if TEST_BOOST_VARIANT +template +constexpr bool boost::parser::enable_optional> = true; +#endif + +#if TEST_BOOST_VARIANT2 +template +constexpr bool boost::parser::enable_optional> = + true; +#endif + struct s0_rule_tag {}; @@ -46,6 +84,22 @@ struct s1 std::variant str_; std::vector vec_; }; +#if TEST_BOOST_VARIANT +struct s1_boost_variant +{ + int i_; + boost::variant str_; + std::vector vec_; +}; +#endif +#if TEST_BOOST_VARIANT +struct s1_boost_variant2 +{ + int i_; + boost::variant2::variant str_; + std::vector vec_; +}; +#endif using s1_tuple = tuple, std::vector>; @@ -57,6 +111,24 @@ callback_rule s1_rule_a = "s1_rule_a"; callback_rule s1_rule_b = "s1_rule_b"; auto s1_rule_a_def = s1_parser_a; auto s1_rule_b_def = s1_parser_b; +#if TEST_BOOST_VARIANT +callback_rule + s1_boost_variant_rule_a = "s1_rule_a"; +callback_rule + s1_boost_variant_rule_b = "s1_rule_b"; +auto s1_boost_variant_rule_a_def = s1_parser_a; +auto s1_boost_variant_rule_b_def = s1_parser_b; +BOOST_PARSER_DEFINE_RULES(s1_boost_variant_rule_a, s1_boost_variant_rule_b); +#endif +#if TEST_BOOST_VARIANT2 +callback_rule + s1_boost_variant2_rule_a = "s1_rule_a"; +callback_rule + s1_boost_variant2_rule_b = "s1_rule_b"; +auto s1_boost_variant2_rule_a_def = s1_parser_a; +auto s1_boost_variant2_rule_b_def = s1_parser_b; +BOOST_PARSER_DEFINE_RULES(s1_boost_variant2_rule_a, s1_boost_variant2_rule_b); +#endif struct s2 { @@ -64,6 +136,14 @@ struct s2 std::string str_; std::optional> vec_; }; +#if TEST_BOOST_OPTIONAL +struct s2_boost_optional +{ + int i_; + std::string str_; + boost::optional> vec_; +}; +#endif using s2_tuple = tuple>>; @@ -74,6 +154,15 @@ callback_rule s2_rule_a = "s2_rule_a"; callback_rule s2_rule_b = "s2_rule_b"; auto s2_rule_a_def = s2_parser_a; auto s2_rule_b_def = s2_parser_b; +#if TEST_BOOST_OPTIONAL +callback_rule + s2_boost_optional_rule_a = "s2_rule_a"; +callback_rule + s2_boost_optional_rule_b = "s2_rule_b"; +auto s2_boost_optional_rule_a_def = s2_parser_a; +auto s2_boost_optional_rule_b_def = s2_parser_b; +BOOST_PARSER_DEFINE_RULES(s2_boost_optional_rule_a, s2_boost_optional_rule_b); +#endif BOOST_PARSER_DEFINE_RULES(s0_rule, s1_rule_a, s1_rule_b, s2_rule_a, s2_rule_b); @@ -231,6 +320,50 @@ TEST(struct_tuple, seq_parser_struct_rule) EXPECT_EQ(std::get<1>(get(struct_, llong<1>{})), 13.0); EXPECT_EQ(get(struct_, llong<2>{}), std::vector({1, 2, 3})); } +#if TEST_BOOST_VARIANT + { + s1_boost_variant struct_; + + EXPECT_TRUE( + parse("s1 42 text 1 2 3", s1_boost_variant_rule_a, ws, struct_)); + EXPECT_EQ(get(struct_, llong<0>{}), 42); + EXPECT_EQ(get(struct_, llong<1>{}).which(), 0u); + EXPECT_EQ(boost::get(get(struct_, llong<1>{})), "text"); + EXPECT_EQ(get(struct_, llong<2>{}), std::vector({1, 2, 3})); + } + { + s1_boost_variant struct_; + + EXPECT_TRUE( + parse("s1 42 13.0 1 2 3", s1_boost_variant_rule_b, ws, struct_)); + EXPECT_EQ(get(struct_, llong<0>{}), 42); + EXPECT_EQ(get(struct_, llong<1>{}).which(), 1u); + EXPECT_EQ(boost::get(get(struct_, llong<1>{})), 13.0); + EXPECT_EQ(get(struct_, llong<2>{}), std::vector({1, 2, 3})); + } +#endif +#if TEST_BOOST_VARIANT2 + { + s1_boost_variant2 struct_; + + EXPECT_TRUE( + parse("s1 42 text 1 2 3", s1_boost_variant2_rule_a, ws, struct_)); + EXPECT_EQ(get(struct_, llong<0>{}), 42); + EXPECT_EQ(get(struct_, llong<1>{}).index(), 0u); + EXPECT_EQ(boost::variant2::get<0>(get(struct_, llong<1>{})), "text"); + EXPECT_EQ(get(struct_, llong<2>{}), std::vector({1, 2, 3})); + } + { + s1_boost_variant2 struct_; + + EXPECT_TRUE( + parse("s1 42 13.0 1 2 3", s1_boost_variant2_rule_b, ws, struct_)); + EXPECT_EQ(get(struct_, llong<0>{}), 42); + EXPECT_EQ(get(struct_, llong<1>{}).index(), 1u); + EXPECT_EQ(boost::variant2::get<1>(get(struct_, llong<1>{})), 13.0); + EXPECT_EQ(get(struct_, llong<2>{}), std::vector({1, 2, 3})); + } +#endif { s2 struct_; @@ -247,6 +380,26 @@ TEST(struct_tuple, seq_parser_struct_rule) EXPECT_EQ(get(struct_, llong<1>{}), "text"); EXPECT_EQ(get(struct_, llong<2>{}), std::vector({1, 2, 3})); } +#if TEST_BOOST_OPTIONAL + { + s2_boost_optional struct_; + + EXPECT_TRUE( + parse("s2 42 text 1 2 3", s2_boost_optional_rule_a, ws, struct_)); + EXPECT_EQ(get(struct_, llong<0>{}), 42); + EXPECT_EQ(get(struct_, llong<1>{}), "text"); + EXPECT_EQ(get(struct_, llong<2>{}), std::vector({1, 2, 3})); + } + { + s2_boost_optional struct_; + + EXPECT_TRUE( + parse("s2 42 text 1 2 3", s2_boost_optional_rule_b, ws, struct_)); + EXPECT_EQ(get(struct_, llong<0>{}), 42); + EXPECT_EQ(get(struct_, llong<1>{}), "text"); + EXPECT_EQ(get(struct_, llong<2>{}), std::vector({1, 2, 3})); + } +#endif // Use the rule as part of a larger parse. { @@ -284,6 +437,74 @@ TEST(struct_tuple, seq_parser_struct_rule) EXPECT_EQ(std::get<1>(get(struct_, llong<1>{})), 13.0); EXPECT_EQ(get(struct_, llong<2>{}), std::vector({1, 2, 3})); } +#if TEST_BOOST_VARIANT + { + tuple result; + + EXPECT_TRUE(parse( + "99 s1 42 text 1 2 3", + int_ >> s1_boost_variant_rule_a, + ws, + result)); + auto i_ = get(result, llong<0>{}); + EXPECT_EQ(i_, 99); + auto struct_ = get(result, llong<1>{}); + EXPECT_EQ(get(struct_, llong<0>{}), 42); + EXPECT_EQ(get(struct_, llong<1>{}).which(), 0u); + EXPECT_EQ(boost::get(get(struct_, llong<1>{})), "text"); + EXPECT_EQ(get(struct_, llong<2>{}), std::vector({1, 2, 3})); + } + { + tuple result; + + EXPECT_TRUE(parse( + "99 s1 42 13.0 1 2 3", + int_ >> s1_boost_variant_rule_b, + ws, + result)); + auto i_ = get(result, llong<0>{}); + EXPECT_EQ(i_, 99); + auto struct_ = get(result, llong<1>{}); + EXPECT_EQ(get(struct_, llong<0>{}), 42); + EXPECT_EQ(get(struct_, llong<1>{}).which(), 1u); + EXPECT_EQ(boost::get(get(struct_, llong<1>{})), 13.0); + EXPECT_EQ(get(struct_, llong<2>{}), std::vector({1, 2, 3})); + } +#endif +#if TEST_BOOST_VARIANT2 + { + tuple result; + + EXPECT_TRUE(parse( + "99 s1 42 text 1 2 3", + int_ >> s1_boost_variant2_rule_a, + ws, + result)); + auto i_ = get(result, llong<0>{}); + EXPECT_EQ(i_, 99); + auto struct_ = get(result, llong<1>{}); + EXPECT_EQ(get(struct_, llong<0>{}), 42); + EXPECT_EQ(get(struct_, llong<1>{}).index(), 0u); + EXPECT_EQ(boost::variant2::get<0>(get(struct_, llong<1>{})), "text"); + EXPECT_EQ(get(struct_, llong<2>{}), std::vector({1, 2, 3})); + } + { + tuple result; + + EXPECT_TRUE(parse( + "99 s1 42 13.0 1 2 3", + int_ >> s1_boost_variant2_rule_b, + ws, + result)); + auto i_ = get(result, llong<0>{}); + EXPECT_EQ(i_, 99); + auto struct_ = get(result, llong<1>{}); + EXPECT_EQ(get(struct_, llong<0>{}), 42); + EXPECT_EQ(get(struct_, llong<1>{}).index(), 1u); + EXPECT_EQ(boost::variant2::get<1>(get(struct_, llong<1>{})), 13.0); + EXPECT_EQ(get(struct_, llong<2>{}), std::vector({1, 2, 3})); + } +#endif { tuple result; @@ -306,6 +527,38 @@ TEST(struct_tuple, seq_parser_struct_rule) EXPECT_EQ(get(struct_, llong<1>{}), "text"); EXPECT_EQ(get(struct_, llong<2>{}), std::vector({1, 2, 3})); } +#if TEST_BOOST_OPTIONAL + { + tuple result; + + EXPECT_TRUE(parse( + "99 s2 42 text 1 2 3", + int_ >> s2_boost_optional_rule_a, + ws, + result)); + auto i_ = get(result, llong<0>{}); + EXPECT_EQ(i_, 99); + auto struct_ = get(result, llong<1>{}); + EXPECT_EQ(get(struct_, llong<0>{}), 42); + EXPECT_EQ(get(struct_, llong<1>{}), "text"); + EXPECT_EQ(get(struct_, llong<2>{}), std::vector({1, 2, 3})); + } + { + tuple result; + + EXPECT_TRUE(parse( + "99 s2 42 text 1 2 3", + int_ >> s2_boost_optional_rule_b, + ws, + result)); + auto i_ = get(result, llong<0>{}); + EXPECT_EQ(i_, 99); + auto struct_ = get(result, llong<1>{}); + EXPECT_EQ(get(struct_, llong<0>{}), 42); + EXPECT_EQ(get(struct_, llong<1>{}), "text"); + EXPECT_EQ(get(struct_, llong<2>{}), std::vector({1, 2, 3})); + } +#endif } TEST(struct_tuple, repeated_seq_parser_struct_rule) @@ -492,6 +745,82 @@ TEST(struct_tuple, repeated_seq_parser_struct_rule) EXPECT_EQ(std::get<1>(get(structs_[1], llong<1>{})), 12.0); EXPECT_EQ(get(structs_[1], llong<2>{}), std::vector({1, 3, 2})); } +#if TEST_BOOST_VARIANT + { + std::vector structs_; + + EXPECT_TRUE(parse( + "s1 42 text 1 2 3 s1 41 texty 1 3 2", + *s1_boost_variant_rule_a, + ws, + structs_)); + EXPECT_EQ(get(structs_[0], llong<0>{}), 42); + EXPECT_EQ(get(structs_[0], llong<1>{}).which(), 0u); + EXPECT_EQ( + boost::get(get(structs_[0], llong<1>{})), "text"); + EXPECT_EQ(get(structs_[0], llong<2>{}), std::vector({1, 2, 3})); + EXPECT_EQ(get(structs_[1], llong<0>{}), 41); + EXPECT_EQ(get(structs_[1], llong<1>{}).which(), 0u); + EXPECT_EQ( + boost::get(get(structs_[1], llong<1>{})), "texty"); + EXPECT_EQ(get(structs_[1], llong<2>{}), std::vector({1, 3, 2})); + } + { + std::vector structs_; + + EXPECT_TRUE(parse( + "s1 42 13.0 1 2 3 s1 41 12.0 1 3 2", + *s1_boost_variant_rule_b, + ws, + structs_)); + EXPECT_EQ(get(structs_[0], llong<0>{}), 42); + EXPECT_EQ(get(structs_[0], llong<1>{}).which(), 1u); + EXPECT_EQ(boost::get(get(structs_[0], llong<1>{})), 13.0); + EXPECT_EQ(get(structs_[0], llong<2>{}), std::vector({1, 2, 3})); + EXPECT_EQ(get(structs_[1], llong<0>{}), 41); + EXPECT_EQ(get(structs_[1], llong<1>{}).which(), 1u); + EXPECT_EQ(boost::get(get(structs_[1], llong<1>{})), 12.0); + EXPECT_EQ(get(structs_[1], llong<2>{}), std::vector({1, 3, 2})); + } +#endif +#if TEST_BOOST_VARIANT2 + { + std::vector structs_; + + EXPECT_TRUE(parse( + "s1 42 text 1 2 3 s1 41 texty 1 3 2", + *s1_boost_variant2_rule_a, + ws, + structs_)); + EXPECT_EQ(get(structs_[0], llong<0>{}), 42); + EXPECT_EQ(get(structs_[0], llong<1>{}).index(), 0u); + EXPECT_EQ( + boost::variant2::get<0>(get(structs_[0], llong<1>{})), "text"); + EXPECT_EQ(get(structs_[0], llong<2>{}), std::vector({1, 2, 3})); + EXPECT_EQ(get(structs_[1], llong<0>{}), 41); + EXPECT_EQ(get(structs_[1], llong<1>{}).index(), 0u); + EXPECT_EQ( + boost::variant2::get<0>(get(structs_[1], llong<1>{})), "texty"); + EXPECT_EQ(get(structs_[1], llong<2>{}), std::vector({1, 3, 2})); + } + { + std::vector structs_; + + EXPECT_TRUE(parse( + "s1 42 13.0 1 2 3 s1 41 12.0 1 3 2", + *s1_boost_variant2_rule_b, + ws, + structs_)); + EXPECT_EQ(get(structs_[0], llong<0>{}), 42); + EXPECT_EQ(get(structs_[0], llong<1>{}).index(), 1u); + EXPECT_EQ(boost::variant2::get<1>(get(structs_[0], llong<1>{})), 13.0); + EXPECT_EQ(get(structs_[0], llong<2>{}), std::vector({1, 2, 3})); + EXPECT_EQ(get(structs_[1], llong<0>{}), 41); + EXPECT_EQ(get(structs_[1], llong<1>{}).index(), 1u); + EXPECT_EQ(boost::variant2::get<1>(get(structs_[1], llong<1>{})), 12.0); + EXPECT_EQ(get(structs_[1], llong<2>{}), std::vector({1, 3, 2})); + } +#endif { std::vector structs_; @@ -516,6 +845,38 @@ TEST(struct_tuple, repeated_seq_parser_struct_rule) EXPECT_EQ(get(structs_[1], llong<1>{}), "texty"); EXPECT_EQ(get(structs_[1], llong<2>{}), std::vector({1, 3, 2})); } +#if TEST_BOOST_OPTIONAL + { + std::vector structs_; + + EXPECT_TRUE(parse( + "s2 42 text 1 2 3 s2 41 texty 1 3 2", + *s2_boost_optional_rule_a, + ws, + structs_)); + EXPECT_EQ(get(structs_[0], llong<0>{}), 42); + EXPECT_EQ(get(structs_[0], llong<1>{}), "text"); + EXPECT_EQ(get(structs_[0], llong<2>{}), std::vector({1, 2, 3})); + EXPECT_EQ(get(structs_[1], llong<0>{}), 41); + EXPECT_EQ(get(structs_[1], llong<1>{}), "texty"); + EXPECT_EQ(get(structs_[1], llong<2>{}), std::vector({1, 3, 2})); + } + { + std::vector structs_; + + EXPECT_TRUE(parse( + "s2 42 text 1 2 3 s2 41 texty 1 3 2", + *s2_boost_optional_rule_b, + ws, + structs_)); + EXPECT_EQ(get(structs_[0], llong<0>{}), 42); + EXPECT_EQ(get(structs_[0], llong<1>{}), "text"); + EXPECT_EQ(get(structs_[0], llong<2>{}), std::vector({1, 2, 3})); + EXPECT_EQ(get(structs_[1], llong<0>{}), 41); + EXPECT_EQ(get(structs_[1], llong<1>{}), "texty"); + EXPECT_EQ(get(structs_[1], llong<2>{}), std::vector({1, 3, 2})); + } +#endif // Use the rule as part of a larger parse. { @@ -576,6 +937,94 @@ TEST(struct_tuple, repeated_seq_parser_struct_rule) EXPECT_EQ(std::get<1>(get(structs_[1], llong<1>{})), 12.0); EXPECT_EQ(get(structs_[1], llong<2>{}), std::vector({1, 3, 2})); } +#if TEST_BOOST_VARIANT + { + tuple> result; + + EXPECT_TRUE(parse( + "99 s1 42 text 1 2 3 s1 41 texty 1 3 2", + int_ >> *s1_boost_variant_rule_a, + ws, + result)); + auto i_ = get(result, llong<0>{}); + EXPECT_EQ(i_, 99); + auto structs_ = get(result, llong<1>{}); + EXPECT_EQ(get(structs_[0], llong<0>{}), 42); + EXPECT_EQ(get(structs_[0], llong<1>{}).which(), 0u); + EXPECT_EQ( + boost::get(get(structs_[0], llong<1>{})), "text"); + EXPECT_EQ(get(structs_[0], llong<2>{}), std::vector({1, 2, 3})); + EXPECT_EQ(get(structs_[1], llong<0>{}), 41); + EXPECT_EQ(get(structs_[1], llong<1>{}).which(), 0u); + EXPECT_EQ( + boost::get(get(structs_[1], llong<1>{})), "texty"); + EXPECT_EQ(get(structs_[1], llong<2>{}), std::vector({1, 3, 2})); + } + { + tuple> result; + + EXPECT_TRUE(parse( + "99 s1 42 13.0 1 2 3 s1 41 12.0 1 3 2", + int_ >> *s1_boost_variant_rule_b, + ws, + result)); + auto i_ = get(result, llong<0>{}); + EXPECT_EQ(i_, 99); + auto structs_ = get(result, llong<1>{}); + EXPECT_EQ(get(structs_[0], llong<0>{}), 42); + EXPECT_EQ(get(structs_[0], llong<1>{}).which(), 1u); + EXPECT_EQ(boost::get(get(structs_[0], llong<1>{})), 13.0); + EXPECT_EQ(get(structs_[0], llong<2>{}), std::vector({1, 2, 3})); + EXPECT_EQ(get(structs_[1], llong<0>{}), 41); + EXPECT_EQ(get(structs_[1], llong<1>{}).which(), 1u); + EXPECT_EQ(boost::get(get(structs_[1], llong<1>{})), 12.0); + EXPECT_EQ(get(structs_[1], llong<2>{}), std::vector({1, 3, 2})); + } +#endif +#if TEST_BOOST_VARIANT2 + { + tuple> result; + + EXPECT_TRUE(parse( + "99 s1 42 text 1 2 3 s1 41 texty 1 3 2", + int_ >> *s1_boost_variant2_rule_a, + ws, + result)); + auto i_ = get(result, llong<0>{}); + EXPECT_EQ(i_, 99); + auto structs_ = get(result, llong<1>{}); + EXPECT_EQ(get(structs_[0], llong<0>{}), 42); + EXPECT_EQ(get(structs_[0], llong<1>{}).index(), 0u); + EXPECT_EQ( + boost::variant2::get<0>(get(structs_[0], llong<1>{})), "text"); + EXPECT_EQ(get(structs_[0], llong<2>{}), std::vector({1, 2, 3})); + EXPECT_EQ(get(structs_[1], llong<0>{}), 41); + EXPECT_EQ(get(structs_[1], llong<1>{}).index(), 0u); + EXPECT_EQ( + boost::variant2::get<0>(get(structs_[1], llong<1>{})), "texty"); + EXPECT_EQ(get(structs_[1], llong<2>{}), std::vector({1, 3, 2})); + } + { + tuple> result; + + EXPECT_TRUE(parse( + "99 s1 42 13.0 1 2 3 s1 41 12.0 1 3 2", + int_ >> *s1_boost_variant2_rule_b, + ws, + result)); + auto i_ = get(result, llong<0>{}); + EXPECT_EQ(i_, 99); + auto structs_ = get(result, llong<1>{}); + EXPECT_EQ(get(structs_[0], llong<0>{}), 42); + EXPECT_EQ(get(structs_[0], llong<1>{}).index(), 1u); + EXPECT_EQ(boost::variant2::get<1>(get(structs_[0], llong<1>{})), 13.0); + EXPECT_EQ(get(structs_[0], llong<2>{}), std::vector({1, 2, 3})); + EXPECT_EQ(get(structs_[1], llong<0>{}), 41); + EXPECT_EQ(get(structs_[1], llong<1>{}).index(), 1u); + EXPECT_EQ(boost::variant2::get<1>(get(structs_[1], llong<1>{})), 12.0); + EXPECT_EQ(get(structs_[1], llong<2>{}), std::vector({1, 3, 2})); + } +#endif { tuple> result; @@ -612,6 +1061,44 @@ TEST(struct_tuple, repeated_seq_parser_struct_rule) EXPECT_EQ(get(structs_[1], llong<1>{}), "texty"); EXPECT_EQ(get(structs_[1], llong<2>{}), std::vector({1, 3, 2})); } +#if TEST_BOOST_OPTIONAL + { + tuple> result; + + EXPECT_TRUE(parse( + "99 s2 42 text 1 2 3 s2 41 texty 1 3 2", + int_ >> *s2_boost_optional_rule_a, + ws, + result)); + auto i_ = get(result, llong<0>{}); + EXPECT_EQ(i_, 99); + auto structs_ = get(result, llong<1>{}); + EXPECT_EQ(get(structs_[0], llong<0>{}), 42); + EXPECT_EQ(get(structs_[0], llong<1>{}), "text"); + EXPECT_EQ(get(structs_[0], llong<2>{}), std::vector({1, 2, 3})); + EXPECT_EQ(get(structs_[1], llong<0>{}), 41); + EXPECT_EQ(get(structs_[1], llong<1>{}), "texty"); + EXPECT_EQ(get(structs_[1], llong<2>{}), std::vector({1, 3, 2})); + } + { + tuple> result; + + EXPECT_TRUE(parse( + "99 s2 42 text 1 2 3 s2 41 texty 1 3 2", + int_ >> *s2_boost_optional_rule_b, + ws, + result)); + auto i_ = get(result, llong<0>{}); + EXPECT_EQ(i_, 99); + auto structs_ = get(result, llong<1>{}); + EXPECT_EQ(get(structs_[0], llong<0>{}), 42); + EXPECT_EQ(get(structs_[0], llong<1>{}), "text"); + EXPECT_EQ(get(structs_[0], llong<2>{}), std::vector({1, 2, 3})); + EXPECT_EQ(get(structs_[1], llong<0>{}), 41); + EXPECT_EQ(get(structs_[1], llong<1>{}), "texty"); + EXPECT_EQ(get(structs_[1], llong<2>{}), std::vector({1, 3, 2})); + } +#endif } struct callbacks_t @@ -732,6 +1219,17 @@ TEST(struct_tuple, seq_parser_struct_cb_rule) } } +// This only exists to unbreak the printing of +// boost::optional> in the trace logic. +namespace boost { + std::ostream & + operator<<(std::ostream & os, boost::optional> const & vec) + { + return os; + } +} +// TODO: Document that boost::optional badly breaks the tracing logic. + TEST(struct_tuple, parse_into_struct) { // tuples @@ -813,6 +1311,46 @@ TEST(struct_tuple, parse_into_struct) EXPECT_EQ(std::get<1>(get(struct_, llong<1>{})), 13.0); EXPECT_EQ(get(struct_, llong<2>{}), std::vector({1, 2, 3})); } +#if TEST_BOOST_VARIANT + { + s1_boost_variant struct_; + + EXPECT_TRUE(parse("s1 42 text 1 2 3", s1_parser_a, ws, struct_)); + EXPECT_EQ(get(struct_, llong<0>{}), 42); + EXPECT_EQ(get(struct_, llong<1>{}).which(), 0u); + EXPECT_EQ(boost::get(get(struct_, llong<1>{})), "text"); + EXPECT_EQ(get(struct_, llong<2>{}), std::vector({1, 2, 3})); + } + { + s1_boost_variant struct_; + + EXPECT_TRUE(parse("s1 42 13.0 1 2 3", s1_parser_b, ws, struct_)); + EXPECT_EQ(get(struct_, llong<0>{}), 42); + EXPECT_EQ(get(struct_, llong<1>{}).which(), 1u); + EXPECT_EQ(boost::get(get(struct_, llong<1>{})), 13.0); + EXPECT_EQ(get(struct_, llong<2>{}), std::vector({1, 2, 3})); + } +#endif +#if TEST_BOOST_VARIANT2 + { + s1_boost_variant2 struct_; + + EXPECT_TRUE(parse("s1 42 text 1 2 3", s1_parser_a, ws, struct_)); + EXPECT_EQ(get(struct_, llong<0>{}), 42); + EXPECT_EQ(get(struct_, llong<1>{}).index(), 0u); + EXPECT_EQ(boost::variant2::get<0>(get(struct_, llong<1>{})), "text"); + EXPECT_EQ(get(struct_, llong<2>{}), std::vector({1, 2, 3})); + } + { + s1_boost_variant2 struct_; + + EXPECT_TRUE(parse("s1 42 13.0 1 2 3", s1_parser_b, ws, struct_)); + EXPECT_EQ(get(struct_, llong<0>{}), 42); + EXPECT_EQ(get(struct_, llong<1>{}).index(), 1u); + EXPECT_EQ(boost::variant2::get<1>(get(struct_, llong<1>{})), 13.0); + EXPECT_EQ(get(struct_, llong<2>{}), std::vector({1, 2, 3})); + } +#endif { s2 struct_; @@ -829,6 +1367,24 @@ TEST(struct_tuple, parse_into_struct) EXPECT_EQ(get(struct_, llong<1>{}), "text"); EXPECT_EQ(get(struct_, llong<2>{}), std::vector({1, 2, 3})); } +#if TEST_BOOST_OPTIONAL + { + s2_boost_optional struct_; + + EXPECT_TRUE(parse("s2 42 text 1 2 3", s2_parser_a, ws, struct_)); + EXPECT_EQ(get(struct_, llong<0>{}), 42); + EXPECT_EQ(get(struct_, llong<1>{}), "text"); + EXPECT_EQ(*get(struct_, llong<2>{}), std::vector({1, 2, 3})); + } + { + s2_boost_optional struct_; + + EXPECT_TRUE(parse("s2 42 text 1 2 3", s2_parser_b, ws, struct_)); + EXPECT_EQ(get(struct_, llong<0>{}), 42); + EXPECT_EQ(get(struct_, llong<1>{}), "text"); + EXPECT_EQ(*get(struct_, llong<2>{}), std::vector({1, 2, 3})); + } +#endif } TEST(struct_tuple, repeated_parse_into_struct)