2
0
mirror of https://github.com/boostorg/parser.git synced 2026-01-19 04:22:13 +00:00

Add support for parsing into attributes whose types are optionals or variants

other than the ones from std:: (e.g. boost::optional, boost::variant, and
boost::variant2::variant).

Fixes #53.
This commit is contained in:
Zach Laine
2024-01-07 19:51:35 -06:00
parent 4becbe34ad
commit cd284572c9
3 changed files with 628 additions and 20 deletions

View File

@@ -23,6 +23,23 @@
namespace boost { namespace parser {
/** A variable template that indicates that type `T` is an optional-like
type. */
template<typename T>
constexpr bool enable_optional = false;
/** A variable template that indicates that type `T` is an variant-like
type. */
template<typename T>
constexpr bool enable_variant = false;
#ifndef BOOST_PARSER_DOXYGEN
template<typename T>
constexpr bool enable_optional<std::optional<T>> = true;
template<typename... Ts>
constexpr bool enable_variant<std::variant<Ts...>> = 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<typename T>
struct is_optional : std::false_type
{};
template<typename T>
struct is_optional<std::optional<T>> : std::true_type
{};
constexpr bool is_optional_v = enable_optional<T>;
template<typename T>
struct is_variant : std::false_type
{};
template<typename... T>
struct is_variant<std::variant<T...>> : std::true_type
{};
constexpr bool is_variant_v = enable_variant<T>;
template<typename T>
struct is_utf8_view : std::false_type
@@ -1060,7 +1069,7 @@ namespace boost { namespace parser {
// for tuple<t> and on for tuple<optional<T>>, is because
// MSVC.
using type =
std::conditional_t<is_optional<T>::value, T, std::optional<T>>;
std::conditional_t<is_optional_v<T>, T, std::optional<T>>;
};
template<typename T>
@@ -2408,19 +2417,29 @@ namespace boost { namespace parser {
remove_cv_ref_t<decltype(parser::get(x, llong<1>{}))>;
if constexpr (!T::value) {
return std::false_type{};
} else if constexpr (
is_optional_v<struct_elem> && is_optional_v<tuple_elem>) {
using struct_opt_type = optional_type<struct_elem>;
using tuple_opt_type = optional_type<tuple_elem>;
using retval_t = decltype((*this)(
result,
detail::hl::make_tuple(
std::declval<struct_opt_type &>(),
std::declval<tuple_opt_type &>())));
return retval_t{};
} else if constexpr (std::is_convertible_v<
tuple_elem &&,
struct_elem>) {
return std::true_type{};
} else if constexpr (
container<struct_elem> && container<tuple_elem>) {
return detail::is_struct_compatible<
range_value_t<struct_elem>,
range_value_t<tuple_elem>>();
return detail::is_struct_compatible<
range_value_t<struct_elem>,
range_value_t<tuple_elem>>();
} else {
return std::bool_constant<detail::is_struct_compatible<
struct_elem,
tuple_elem>()>{};
return std::bool_constant<detail::is_struct_compatible<
struct_elem,
tuple_elem>()>{};
}
}
};
@@ -2665,7 +2684,7 @@ namespace boost { namespace parser {
: flags,
retval);
if constexpr (detail::is_optional<Attribute>{}) {
if constexpr (detail::is_optional_v<Attribute>) {
detail::optional_type<Attribute> attr;
detail::apply_parser(
*this,
@@ -3360,7 +3379,7 @@ namespace boost { namespace parser {
indices;
std::decay_t<decltype(parser::get(temp_result, llong<2>{}))>
merged;
if constexpr (detail::is_variant<Attribute>{}) {
if constexpr (detail::is_variant_v<Attribute>) {
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<Attribute>{}) {
} else if constexpr (detail::is_optional_v<Attribute>) {
typename Attribute::value_type attr;
call(
use_cbs, first_, last, context, skip, flags, success, attr);

View File

@@ -8,11 +8,23 @@
#include <boost/parser/parser.hpp>
#if __has_include(<boost/optional/optional.hpp>)
#define TEST_BOOST_OPTIONAL 1
#include <boost/optional/optional.hpp>
#include <boost/optional/optional_io.hpp>
#else
#define TEST_BOOST_OPTIONAL 0
#endif
#include <gtest/gtest.h>
using namespace boost::parser;
#if TEST_BOOST_OPTIONAL
template<typename T>
constexpr bool boost::parser::enable_optional<boost::optional<T>> = 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<char> c;
EXPECT_TRUE(parse(str, parser_5, c));
EXPECT_EQ(c, 'a');
}
{
std::string str = "z";
boost::optional<char> c;
EXPECT_FALSE(parse(str, parser_5, c));
}
{
std::string str = "z";
boost::optional<char> 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)

View File

@@ -8,11 +8,49 @@
#include <boost/parser/parser.hpp>
#if __has_include(<boost/optional/optional.hpp>)
#define TEST_BOOST_OPTIONAL 1
#include <boost/optional/optional.hpp>
#else
#define TEST_BOOST_OPTIONAL 0
#endif
#if __has_include(<boost/variant/variant.hpp>)
#define TEST_BOOST_VARIANT 1
#include <boost/variant/variant.hpp>
#include <boost/variant/get.hpp>
#else
#define TEST_BOOST_VARIANT 0
#endif
#if __has_include(<boost/variant2/variant.hpp>)
#define TEST_BOOST_VARIANT2 1
#include <boost/variant2/variant.hpp>
#else
#define TEST_BOOST_VARIANT2 0
#endif
#include <gtest/gtest.h>
using namespace boost::parser;
#if TEST_BOOST_OPTIONAL
template<typename T>
constexpr bool boost::parser::enable_optional<boost::optional<T>> = true;
#endif
#if TEST_BOOST_VARIANT
template<typename... Ts>
constexpr bool boost::parser::enable_optional<boost::variant<Ts...>> = true;
#endif
#if TEST_BOOST_VARIANT2
template<typename... Ts>
constexpr bool boost::parser::enable_optional<boost::variant2::variant<Ts...>> =
true;
#endif
struct s0_rule_tag
{};
@@ -46,6 +84,22 @@ struct s1
std::variant<std::string, double> str_;
std::vector<int> vec_;
};
#if TEST_BOOST_VARIANT
struct s1_boost_variant
{
int i_;
boost::variant<std::string, double> str_;
std::vector<int> vec_;
};
#endif
#if TEST_BOOST_VARIANT
struct s1_boost_variant2
{
int i_;
boost::variant2::variant<std::string, double> str_;
std::vector<int> vec_;
};
#endif
using s1_tuple =
tuple<int, std::variant<std::string, double>, std::vector<int>>;
@@ -57,6 +111,24 @@ callback_rule<s1_rule_a_tag, s1> s1_rule_a = "s1_rule_a";
callback_rule<s1_rule_b_tag, s1> 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<struct s1_bv_rule_a_tag, s1_boost_variant>
s1_boost_variant_rule_a = "s1_rule_a";
callback_rule<struct s1_bv_rule_b_tag, s1_boost_variant>
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<struct s1_bv2_rule_a_tag, s1_boost_variant2>
s1_boost_variant2_rule_a = "s1_rule_a";
callback_rule<struct s1_bv2_rule_b_tag, s1_boost_variant2>
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<std::vector<int>> vec_;
};
#if TEST_BOOST_OPTIONAL
struct s2_boost_optional
{
int i_;
std::string str_;
boost::optional<std::vector<int>> vec_;
};
#endif
using s2_tuple = tuple<int, std::string, std::optional<std::vector<int>>>;
@@ -74,6 +154,15 @@ callback_rule<s2_rule_a_tag, s2> s2_rule_a = "s2_rule_a";
callback_rule<s2_rule_b_tag, s2> 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<struct s2_bo_rule_a_tag, s2_boost_optional>
s2_boost_optional_rule_a = "s2_rule_a";
callback_rule<struct s2_bo_rule_b_tag, s2_boost_optional>
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<int>({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<std::string>(get(struct_, llong<1>{})), "text");
EXPECT_EQ(get(struct_, llong<2>{}), std::vector<int>({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<double>(get(struct_, llong<1>{})), 13.0);
EXPECT_EQ(get(struct_, llong<2>{}), std::vector<int>({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<int>({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<int>({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<int>({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<int>({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<int>({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<int>({1, 2, 3}));
}
#if TEST_BOOST_VARIANT
{
tuple<int, s1_boost_variant> 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<std::string>(get(struct_, llong<1>{})), "text");
EXPECT_EQ(get(struct_, llong<2>{}), std::vector<int>({1, 2, 3}));
}
{
tuple<int, s1_boost_variant> 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<double>(get(struct_, llong<1>{})), 13.0);
EXPECT_EQ(get(struct_, llong<2>{}), std::vector<int>({1, 2, 3}));
}
#endif
#if TEST_BOOST_VARIANT2
{
tuple<int, s1_boost_variant2> 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<int>({1, 2, 3}));
}
{
tuple<int, s1_boost_variant2> 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<int>({1, 2, 3}));
}
#endif
{
tuple<int, s2> 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<int>({1, 2, 3}));
}
#if TEST_BOOST_OPTIONAL
{
tuple<int, s2_boost_optional> 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<int>({1, 2, 3}));
}
{
tuple<int, s2_boost_optional> 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<int>({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<int>({1, 3, 2}));
}
#if TEST_BOOST_VARIANT
{
std::vector<s1_boost_variant> 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<std::string>(get(structs_[0], llong<1>{})), "text");
EXPECT_EQ(get(structs_[0], llong<2>{}), std::vector<int>({1, 2, 3}));
EXPECT_EQ(get(structs_[1], llong<0>{}), 41);
EXPECT_EQ(get(structs_[1], llong<1>{}).which(), 0u);
EXPECT_EQ(
boost::get<std::string>(get(structs_[1], llong<1>{})), "texty");
EXPECT_EQ(get(structs_[1], llong<2>{}), std::vector<int>({1, 3, 2}));
}
{
std::vector<s1_boost_variant> 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<double>(get(structs_[0], llong<1>{})), 13.0);
EXPECT_EQ(get(structs_[0], llong<2>{}), std::vector<int>({1, 2, 3}));
EXPECT_EQ(get(structs_[1], llong<0>{}), 41);
EXPECT_EQ(get(structs_[1], llong<1>{}).which(), 1u);
EXPECT_EQ(boost::get<double>(get(structs_[1], llong<1>{})), 12.0);
EXPECT_EQ(get(structs_[1], llong<2>{}), std::vector<int>({1, 3, 2}));
}
#endif
#if TEST_BOOST_VARIANT2
{
std::vector<s1_boost_variant2> 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<int>({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<int>({1, 3, 2}));
}
{
std::vector<s1_boost_variant2> 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<int>({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<int>({1, 3, 2}));
}
#endif
{
std::vector<s2> 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<int>({1, 3, 2}));
}
#if TEST_BOOST_OPTIONAL
{
std::vector<s2_boost_optional> 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<int>({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<int>({1, 3, 2}));
}
{
std::vector<s2_boost_optional> 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<int>({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<int>({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<int>({1, 3, 2}));
}
#if TEST_BOOST_VARIANT
{
tuple<int, std::vector<s1_boost_variant>> 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<std::string>(get(structs_[0], llong<1>{})), "text");
EXPECT_EQ(get(structs_[0], llong<2>{}), std::vector<int>({1, 2, 3}));
EXPECT_EQ(get(structs_[1], llong<0>{}), 41);
EXPECT_EQ(get(structs_[1], llong<1>{}).which(), 0u);
EXPECT_EQ(
boost::get<std::string>(get(structs_[1], llong<1>{})), "texty");
EXPECT_EQ(get(structs_[1], llong<2>{}), std::vector<int>({1, 3, 2}));
}
{
tuple<int, std::vector<s1_boost_variant>> 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<double>(get(structs_[0], llong<1>{})), 13.0);
EXPECT_EQ(get(structs_[0], llong<2>{}), std::vector<int>({1, 2, 3}));
EXPECT_EQ(get(structs_[1], llong<0>{}), 41);
EXPECT_EQ(get(structs_[1], llong<1>{}).which(), 1u);
EXPECT_EQ(boost::get<double>(get(structs_[1], llong<1>{})), 12.0);
EXPECT_EQ(get(structs_[1], llong<2>{}), std::vector<int>({1, 3, 2}));
}
#endif
#if TEST_BOOST_VARIANT2
{
tuple<int, std::vector<s1_boost_variant2>> 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<int>({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<int>({1, 3, 2}));
}
{
tuple<int, std::vector<s1_boost_variant2>> 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<int>({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<int>({1, 3, 2}));
}
#endif
{
tuple<int, std::vector<s2>> 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<int>({1, 3, 2}));
}
#if TEST_BOOST_OPTIONAL
{
tuple<int, std::vector<s2_boost_optional>> 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<int>({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<int>({1, 3, 2}));
}
{
tuple<int, std::vector<s2_boost_optional>> 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<int>({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<int>({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<std::vector<int>> in the trace logic.
namespace boost {
std::ostream &
operator<<(std::ostream & os, boost::optional<std::vector<int>> 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<int>({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<std::string>(get(struct_, llong<1>{})), "text");
EXPECT_EQ(get(struct_, llong<2>{}), std::vector<int>({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<double>(get(struct_, llong<1>{})), 13.0);
EXPECT_EQ(get(struct_, llong<2>{}), std::vector<int>({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<int>({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<int>({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<int>({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<int>({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<int>({1, 2, 3}));
}
#endif
}
TEST(struct_tuple, repeated_parse_into_struct)