/*============================================================================= Copyright (c) 2015 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 namespace { struct my_tag; template struct match_counter_rule_id { template Se, class Failure, class Context> void on_error(It const&, Se const&, Context const& ctx, Failure const&) { STATIC_CHECK(x4::has_context_of_v); ++x4::get(ctx); } template Se, class Context, x4::X4Attribute Attr> void on_success(It const&, Se const&, Context const& ctx, Attr&) { STATIC_CHECK(x4::has_context_of_v); ++x4::get(ctx); } }; using x4::rule; using x4::int_; using x4::with; using x4::_attr; template constexpr auto value_equals = int_[([](auto&& ctx) { auto&& with_val = x4::get(ctx); static_assert(std::same_as); return with_val == _attr(ctx); })]; } // anonymous TEST_CASE("with") { BOOST_SPIRIT_X4_ASSERT_CONSTEXPR_CTORS(with(0)['x']); { constexpr int i = 0; BOOST_SPIRIT_X4_ASSERT_CONSTEXPR_CTORS(with(i)['x']); } // check various value categories { { int i = 42; CHECK(parse("42", with(i)[value_equals])); } { int const i = 42; CHECK(parse("42", with(i)[value_equals])); } { int i = 42; CHECK(parse("42", with(std::move(i))[value_equals])); } { int const i = 42; CHECK(parse("42", with(std::move(i))[value_equals])); } { int i = 42; auto with_gen = with(i); CHECK(parse("42", with_gen[value_equals])); } { int const i = 42; auto with_gen = with(i); CHECK(parse("42", with_gen[value_equals])); } { int i = 42; auto with_gen = with(std::move(i)); CHECK(parse("42", with_gen[value_equals])); } { int const i = 42; auto with_gen = with(std::move(i)); CHECK(parse("42", with_gen[value_equals])); } // lvalue `move_only` { spirit_test::move_only mo; (void)with(mo)[int_]; } { spirit_test::move_only mo; auto with_gen = with(mo); // passed-by-reference (void)with_gen[int_]; // permitted, never copies (void)std::move(with_gen)[int_]; } // rvalue `move_only` { (void)with(spirit_test::move_only{})[int_]; } { auto with_gen = with(spirit_test::move_only{}); // (void)with_gen[int_]; // requires copy-constructible (void)std::move(with_gen)[int_]; } } { // injecting data into the context in the grammar int matched_count = 0; auto r = rule>, std::vector>{} = '(' > int_ > ',' > int_ > ')'; // NOLINT(bugprone-chained-comparison) auto start = with(std::ref(matched_count))[r]; std::vector ints; REQUIRE(parse("(123,456)", start, ints)); REQUIRE(!parse("(abc,def)", start, ints)); CHECK(matched_count == 2); CHECK(ints == std::vector{123, 456}); } { // injecting non-const lvalue into the context int val = 0; auto const r = int_[([](auto&& ctx){ x4::get(ctx) += x4::_attr(ctx); })]; REQUIRE(parse("123,456", with(val)[r % ','])); CHECK(val == 579); } { // injecting rvalue into the context auto const r1 = int_[([](auto&& ctx){ x4::get(ctx) += x4::_attr(ctx); })]; auto const r2 = rule() = x4::lit('(') >> (r1 % ',') >> x4::lit(')')[([](auto&& ctx){ x4::_rule_var(ctx) = x4::get(ctx); })]; int attr = 0; REQUIRE(parse("(1,2,3)", with(100)[r2], attr)); CHECK(attr == 106); } { // injecting const/non-const lvalue and rvalue into the context struct functor { int operator()(int& val) { return val * 10; // non-const ref returns 10 * injected val } int operator()(int const& val) { return val; // const ref returns injected val } }; auto f = [](auto&& ctx){ x4::_rule_var(ctx) = x4::_attr(ctx) + functor()(x4::get(ctx)); }; auto const r = rule() = int_[f]; { int attr = 0; int const cval = 10; REQUIRE(parse("5", with(cval)[r], attr)); CHECK(attr == 15); // x4::get returns const ref to cval } { int attr = 0; int val = 10; REQUIRE(parse("5", with(val)[r], attr)); CHECK(attr == 105); // x4::get returns ref to val } { int attr = 0; REQUIRE(parse("5", with(10)[r], attr)); // x4::get returns ref to member variable of with_directive CHECK(attr == 105); } } }