/*============================================================================= Copyright (c) 2001-2012 Joel de Guzman 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 #ifdef _MSC_VER // bogus https://developercommunity.visualstudio.com/t/buggy-warning-c4709/471956 # pragma warning(disable: 4709) // comma operator within array index expression #endif namespace check_stationary { x4::rule const a; x4::rule const b; auto const a_def = '{' >> x4::int_ >> '}'; auto const b_def = a; BOOST_SPIRIT_X4_DEFINE(a) BOOST_SPIRIT_X4_DEFINE(b) } // check_stationary namespace check_recursive { using node_t = boost::make_recursive_variant< int, std::vector >::type; x4::rule const grammar; auto const grammar_def = '[' >> grammar % ',' >> ']' | x4::int_; BOOST_SPIRIT_X4_DEFINE(grammar) } // check_recursive namespace check_recursive_scoped { using check_recursive::node_t; x4::rule const intvec; auto const grammar = intvec = '[' >> intvec % ',' >> ']' | x4::int_; } // check_recursive_scoped struct recursive_tuple { int value; std::vector children; }; BOOST_FUSION_ADAPT_STRUCT(recursive_tuple, value, children) // regression test for #461 namespace check_recursive_tuple { using iterator_type = std::string_view::const_iterator; x4::rule const grammar; auto const grammar_def = x4::int_ >> ('{' >> grammar % ',' >> '}' | x4::eps); BOOST_SPIRIT_X4_DEFINE(grammar) BOOST_SPIRIT_X4_INSTANTIATE(decltype(grammar), iterator_type, x4::parse_context_for) } // check_recursive_tuple TEST_CASE("rule3") { using namespace x4::standard; using x4::rule; using x4::lit; using x4::eps; using x4::_rule_var; using x4::_attr; // synth attribute value-init { std::string s; using rule_type = rule; auto rdef = rule_type{} = alpha[([](auto&& ctx) { x4::_rule_var(ctx) += x4::_attr(ctx); })]; REQUIRE(parse("abcdef", +rdef, s)); CHECK(s == "abcdef"); } // synth attribute value-init { std::string s; using rule_type = rule; auto rdef = rule_type() = alpha[([](auto&& ctx) { _rule_var(ctx) += _attr(ctx); })]; REQUIRE(parse("abcdef", +rdef, s)); CHECK(s == "abcdef"); } { auto r = rule{} = eps[([] ([[maybe_unused]] auto&& ctx) { static_assert( std::is_same_v, unused_type>, "Attr must not be synthesized" ); })]; CHECK(parse("", r)); } // ensure no unneeded synthesization, copying and moving occurred { spirit_test::stationary st { 0 }; REQUIRE(parse("{42}", check_stationary::b, st)); CHECK(st.val == 42); } { using namespace check_recursive; node_t v; REQUIRE(parse("[4,2]", grammar, v)); CHECK((node_t{std::vector{{4}, {2}}} == v)); } { using namespace check_recursive_scoped; node_t v; REQUIRE(parse("[4,2]", grammar, v)); CHECK((node_t{std::vector{{4}, {2}}} == v)); } }