diff --git a/include/boost/spirit/home/x3/core/skip_over.hpp b/include/boost/spirit/home/x3/core/skip_over.hpp index b3202b4e7..627c8096d 100644 --- a/include/boost/spirit/home/x3/core/skip_over.hpp +++ b/include/boost/spirit/home/x3/core/skip_over.hpp @@ -1,7 +1,7 @@ /*============================================================================= Copyright (c) 2001-2014 Joel de Guzman Copyright (c) 2017 wanghan02 - Copyright (c) 2024 Nana Sakisaka + Copyright (c) 2024-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) @@ -13,61 +13,86 @@ #include #include #include -#include -#include -#include -#include -#include -#include -namespace boost { namespace spirit { namespace x3 +#include + +#include +#include + +namespace boost::spirit::x3 { - /////////////////////////////////////////////////////////////////////////// + // Tag used to find the skipper from the context + struct skipper_tag; + // Move the /first/ iterator to the first non-matching position // given a skip-parser. The function is a no-op if unused_type or // unused_skipper is passed as the skip-parser. - /////////////////////////////////////////////////////////////////////////// - template - struct unused_skipper : unused_type + template + struct [[nodiscard]] unused_skipper { - unused_skipper(Skipper const& skipper) - : skipper(skipper) {} + constexpr unused_skipper(Skipper const& skipper) noexcept + : skipper(skipper) + {} + Skipper const& skipper; }; + template + using unused_skipper_t = unused_skipper(std::declval()))>>; + namespace detail { template - struct is_unused_skipper - : mpl::false_ {}; + struct is_unused_skipper : std::false_type + { + static_assert(X3Subject); + }; template - struct is_unused_skipper> - : mpl::true_ {}; + struct is_unused_skipper> : std::true_type {}; template <> - struct is_unused_skipper - : mpl::true_ {}; + struct is_unused_skipper : std::true_type {}; template - inline Skipper const& - get_unused_skipper(Skipper const& skipper) + [[nodiscard]] constexpr Skipper const& + get_unused_skipper(Skipper const& skipper) noexcept { + static_assert(X3Subject); return skipper; } + template - inline Skipper const& - get_unused_skipper(unused_skipper const& unused_skipper) + [[nodiscard]] constexpr Skipper const& + get_unused_skipper(unused_skipper const& unused_skipper) noexcept { + static_assert(X3Subject); return unused_skipper.skipper; } - template - inline void skip_over( - Iterator& first, Iterator const& last, Context& context, Skipper const& skipper) + template + struct skip_over_context + { + using type = unused_type; + }; + + template + requires (!std::is_same_v, unused_type>) + struct skip_over_context + { + using type = std::remove_cvref_t( + x3::get(std::declval()) + ))>; + }; + + template Se, typename Context, X3Subject Skipper> + constexpr void skip_over( + It& first, Se const& last, Context& context, Skipper const& skipper + ) + noexcept(is_nothrow_parsable_v::type, unused_type, unused_type>) { #if BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE - boost::ignore_unused(context); + (void)context; while (skipper.parse(first, last, unused, unused, unused)) /* loop */; #else @@ -117,7 +142,7 @@ namespace boost { namespace spirit { namespace x3 // For this reason we're going to cherry-pick the reference // and repack it into a brand new context. - auto const local_ctx = make_context( + auto const local_ctx = x3::make_context( x3::get(context)); while (skipper.parse(first, last, local_ctx, unused, unused)) @@ -126,35 +151,33 @@ namespace boost { namespace spirit { namespace x3 #endif } - template - inline void skip_over(Iterator&, Iterator const&, Context&, unused_type) + template Se, typename Context> + constexpr void skip_over(It&, Se const&, Context&, unused_type) noexcept { } - template - inline void skip_over( - Iterator&, Iterator const&, Context&, unused_skipper const&) + template Se, typename Context, typename Skipper> + constexpr void skip_over(It&, Se const&, Context&, unused_skipper const&) noexcept { } } - // this tag is used to find the skipper from the context - struct skipper_tag; - template struct has_skipper - : mpl::not_(boost::declval())) - >::type>::type - >> {}; + : std::bool_constant(std::declval()))> + >::value> + {}; - template - inline void skip_over( - Iterator& first, Iterator const& last, Context& context) + template + constexpr bool has_skipper_v = has_skipper::value; + + template Se, typename Context> + constexpr void skip_over(It& first, Se const& last, Context& context) + noexcept(noexcept(detail::skip_over(first, last, context, x3::get(context)))) { detail::skip_over(first, last, context, x3::get(context)); } -}}} +} // boost::spirit::x3 #endif diff --git a/include/boost/spirit/home/x3/directive/lexeme.hpp b/include/boost/spirit/home/x3/directive/lexeme.hpp index 942957b2c..47b1b3479 100644 --- a/include/boost/spirit/home/x3/directive/lexeme.hpp +++ b/include/boost/spirit/home/x3/directive/lexeme.hpp @@ -1,5 +1,6 @@ /*============================================================================= Copyright (c) 2001-2014 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) @@ -11,68 +12,85 @@ #include #include #include -#include -#include -namespace boost { namespace spirit { namespace x3 +#include +#include +#include + +namespace boost::spirit::x3 { template struct lexeme_directive : unary_parser> { - typedef unary_parser > base_type; - static bool const is_pass_through_unary = true; - static bool const handles_container = Subject::handles_container; + using base_type = unary_parser>; + static constexpr bool is_pass_through_unary = true; + static constexpr bool handles_container = Subject::handles_container; - constexpr lexeme_directive(Subject const& subject) - : base_type(subject) {} + template + requires std::is_constructible_v + constexpr lexeme_directive(SubjectT&& subject) + noexcept(std::is_nothrow_constructible_v) + : base_type(std::forward(subject)) + {} - template - typename enable_if, bool>::type - parse(Iterator& first, Iterator const& last - , Context const& context, RContext& rcontext, Attribute& attr) const + template + using pre_skip_context_t = std::remove_cvref_t(std::declval&>(), std::declval()) + )>; + + template Se, typename Context, typename RContext, typename Attribute> + requires has_skipper_v + [[nodiscard]] constexpr bool parse( + It& first, Se const& last, Context const& context, RContext& rcontext, Attribute& attr + ) const + noexcept( + noexcept(x3::skip_over(first, last, context)) && + is_nothrow_parsable_v, RContext, Attribute> + ) { x3::skip_over(first, last, context); - auto const& skipper = x3::get(context); - typedef unused_skipper< - typename remove_reference::type> - unused_skipper_type; - unused_skipper_type unused_skipper(skipper); + auto const& skipper = x3::get(context); + unused_skipper_t unused_skipper(skipper); return this->subject.parse( - first, last - , make_context(unused_skipper, context) - , rcontext - , attr); + first, last, + x3::make_context(unused_skipper, context), + rcontext, + attr + ); } - template - typename disable_if, bool>::type - parse(Iterator& first, Iterator const& last - , Context const& context, RContext& rcontext, Attribute& attr) const + template Se, typename Context, typename RContext, typename Attribute> + requires (!has_skipper_v) + [[nodiscard]] constexpr bool parse( + It& first, Se const& last, Context const& context, RContext& rcontext, Attribute& attr + ) const + noexcept(is_nothrow_parsable_v) { // no need to pre-skip if skipper is unused - return this->subject.parse( - first, last - , context - , rcontext - , attr); + return this->subject.parse(first, last, context, rcontext, attr); } }; - struct lexeme_gen + namespace detail { - template - constexpr lexeme_directive::value_type> - operator[](Subject const& subject) const + struct lexeme_gen { - return { as_parser(subject) }; - } - }; + template + [[nodiscard]] constexpr lexeme_directive> + operator[](Subject&& subject) const + noexcept(is_parser_nothrow_constructible_v>, Subject>) + { + return { as_parser(std::forward(subject)) }; + } + }; + } // detail - constexpr auto lexeme = lexeme_gen{}; -}}} + inline namespace cpos + { + inline constexpr detail::lexeme_gen lexeme{}; + } +} // boost::spirit::x3 #endif diff --git a/test/x3/lexeme.cpp b/test/x3/lexeme.cpp index 483196559..b816779ce 100644 --- a/test/x3/lexeme.cpp +++ b/test/x3/lexeme.cpp @@ -1,21 +1,22 @@ /*============================================================================= Copyright (c) 2001-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 "test.hpp" -int -main() +int main() { using spirit_test::test; - using boost::spirit::x3::ascii::space; - using boost::spirit::x3::ascii::space_type; - using boost::spirit::x3::ascii::digit; + using boost::spirit::x3::standard::space; + using boost::spirit::x3::standard::space_type; + using boost::spirit::x3::standard::digit; using boost::spirit::x3::lexeme; using boost::spirit::x3::rule;