/*============================================================================= Copyright (c) 2001-2015 Joel de Guzman Copyright (c) 2001-2011 Hartmut Kaiser Copyright (c) 2025 Nana Sakisaka 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) =============================================================================*/ #include "test.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct di_ignore { std::string text; }; struct di_include { std::string FileName; }; BOOST_FUSION_ADAPT_STRUCT(di_ignore, text ) BOOST_FUSION_ADAPT_STRUCT(di_include, FileName ) struct undefined {}; TEST_CASE("alternative") { using x4::standard::char_; using x4::standard::lit; using x4::attr; using x4::int_; using x4::unused; using x4::omit; using x4::eps; BOOST_SPIRIT_X4_ASSERT_CONSTEXPR_CTORS(char_ | char_); { CHECK(parse("a", char_ | char_)); CHECK(parse("x", lit('x') | lit('i'))); CHECK(parse("i", lit('x') | lit('i'))); CHECK(!parse("z", lit('x') | lit('o'))); CHECK(parse("rock", lit("rock") | lit("roll"))); CHECK(parse("roll", lit("rock") | lit("roll"))); CHECK(parse("rock", lit("rock") | int_)); CHECK(parse("12345", lit("rock") | int_)); } { using attr_type = boost::variant; { attr_type v; REQUIRE(parse("12345", int_ | char_, v)); CHECK(boost::get(v) == 12345); } { attr_type v; REQUIRE(parse("12345", lit("rock") | int_ | char_, v)); CHECK(boost::get(v) == 12345); } { attr_type v; REQUIRE(parse("rock", lit("rock") | int_ | char_, v)); CHECK(v.which() == 0); } { attr_type v; REQUIRE(parse("x", lit("rock") | int_ | char_, v)); CHECK(boost::get(v) == 'x'); } } { // Make sure that we are using the actual supplied attribute types // from the variant and not the expected type. using attr_type = boost::variant; { attr_type v; REQUIRE(parse("12345", int_ | +char_, v)); CHECK(boost::get(v) == 12345); } { attr_type v; REQUIRE(parse("abc", int_ | +char_, v)); CHECK(boost::get(v) == "abc"); } { attr_type v; REQUIRE(parse("12345", +char_ | int_, v)); CHECK(boost::get(v) == "12345"); } } { unused_type x; CHECK(parse("rock", lit("rock") | lit('x'), x)); } { // test if alternatives with all components having unused // attributes have an unused attribute using boost::fusion::vector; using boost::fusion::at_c; vector v; REQUIRE((parse("abc", char_ >> (omit[char_] | omit[char_]) >> char_, v))); CHECK((at_c<0>(v) == 'a')); CHECK((at_c<1>(v) == 'c')); } { // Test that we can still pass a "compatible" attribute to // an alternate even if its "expected" attribute is unused type. std::string s; REQUIRE(parse("...", *(char_('.') | char_(',')), s)); CHECK(s == "..."); } { // make sure collapsing eps works as expected // (compile check only) using x4::rule; using x4::_attr; using x4::_rule_var; rule r1; rule r2; rule r3; constexpr auto f = [&](auto& ctx){ _rule_var(ctx) = _attr(ctx); }; (void)(r3 = (eps >> r1)[f]); (void)(r3 = (r1 | r2)[f]); (void)(r3 = eps >> r1 | r2); (void)r3; } { // test having a variant std::string s; REQUIRE(parse("a,b", char_ % ',' | eps, s)); CHECK(s == "ab"); } { { // testing a sequence taking a container as attribute std::string s; REQUIRE(parse("abc,a,b,c", char_ >> char_ >> (char_ % ','), s)); CHECK(s == "abcabc"); } { // test having an optional inside a sequence std::string s; REQUIRE(parse("ab", char_ >> char_ >> -(char_ % ','), s)); CHECK(s == "ab"); } { // test having a variant inside a sequence std::string s; CHECK(parse("ab", char_ >> char_ >> ((char_ % ',') | eps), s)); CHECK(s == "ab"); } { std::string s; CHECK(parse("abc", char_ >> char_ >> ((char_ % ',') | eps), s)); CHECK(s == "abc"); } } { //compile test only (bug_march_10_2011_8_35_am) using value_type = boost::variant; using x4::rule; rule r1; [[maybe_unused]] auto r1_ = r1 = r1 | eps; // left recursive! } { using x4::rule; using d_line = boost::variant; rule ignore; rule include; rule line; [[maybe_unused]] auto start = line = include | ignore; (void)line; } // single-element fusion vector tests { boost::fusion::vector> fv; REQUIRE(parse("12345", int_ | +char_, fv)); CHECK(boost::get(boost::fusion::at_c<0>(fv)) == 12345); } { boost::fusion::vector> fvi; REQUIRE(parse("12345", int_ | int_, fvi)); CHECK(boost::get(boost::fusion::at_c<0>(fvi)) == 12345); } // alternative over single element sequences as part of another sequence { constexpr auto key1 = lit("long") >> attr(long()); constexpr auto key2 = lit("char") >> attr(char()); constexpr auto keys = key1 | key2; constexpr auto pair = keys >> lit("=") >> +char_; boost::fusion::deque, std::string> attr_; REQUIRE(parse("long=ABC", pair, attr_)); CHECK(boost::get(&boost::fusion::front(attr_)) != nullptr); CHECK(boost::get(&boost::fusion::front(attr_)) == nullptr); } { // ensure no unneeded synthesization, copying and moving occurred constexpr auto p = '{' >> int_ >> '}'; spirit_test::stationary st { 0 }; REQUIRE(parse("{42}", p | eps | p, st)); CHECK(st.val == 42); } { // attributeless parsers must not insert values std::vector v; REQUIRE(parse("1 2 3 - 5 - - 7 -", (int_ | '-') % ' ', v)); REQUIRE(v.size() == 5); CHECK(v[0] == 1); CHECK(v[1] == 2); CHECK(v[2] == 3); CHECK(v[3] == 5); CHECK(v[4] == 7); } { // regressing test for #603 struct X {}; std::vector> v; REQUIRE(parse("xx42x9y", *(int_ | +char_('x') | 'y' >> attr(X{})), v)); CHECK(v.size() == 5); } { // sequence parser in alternative into container std::string s; REQUIRE(parse("abcbbcd", *(char_('a') >> *(*char_('b') >> char_('c')) | char_('d')), s)); CHECK(s == "abcbbcd"); } { // conversion between alternatives struct X {}; struct Y {}; struct Z {}; boost::variant v; boost::variant x{X{}}; v = x; // boost::variant supports that convertion auto const p = 'x' >> attr(x) | 'z' >> attr(Z{}); REQUIRE(parse("z", p, v)); CHECK(boost::get(&v) != nullptr); REQUIRE(parse("x", p, v)); CHECK(boost::get(&v) != nullptr); } { // regression test for #679 using Qaz = std::vector>; using Foo = std::vector>; using Bar = std::vector>; Bar x; CHECK(parse("abaabb", +('a' >> attr(Foo{}) | 'b' >> attr(int{})), x)); } }