2
0
mirror of https://github.com/boostorg/parser.git synced 2026-02-23 16:02:08 +00:00

1 Commits

Author SHA1 Message Date
Andreas Buhr
4a200a4074 Add define BOOST_PARSER_DISABLE_TRACE to disable trace mode at compile time.
The trace feature doubles the compile time, even if never used.
This patch introduces the preprocessor define BOOST_PARSER_DISABLE_TRACE
to deactivate this feature at compile time.
2026-02-15 15:18:22 -06:00
4 changed files with 38 additions and 369 deletions

View File

@@ -317,16 +317,6 @@ the input they match unless otherwise stated in the table below.]
[ `std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>` ]
[ The special value _inf_ may be used for the upper bound; it indicates unlimited repetition. `decltype(_RES_np_(arg0))` and `decltype(_RES_np_(arg1))` each must be implicitly convertible to `int64_t`. Matching _e_ an unlimited number of times creates an infinite loop, which is undefined behavior in C++. _Parser_ will assert in debug mode when it encounters `_rpt_np_(n, _inf_)[_e_]` (this applies to unconditional _e_ only). ]]
[[ `_rpt_np_(arg0, p1)[p2]` ]
[ Matches iff `p2` matches exactly `_RES_np_(arg0)` times, matching `p1` in between each pair of consecutive matches of `p2`. Equivalent to: _e_ for `_RES_np_(arg0) <= 0`, and `_rpt_np_(_RES_np_(arg0) - 1)[p2 >> p1] >> p2` otherwise. ]
[ `std::string` if `_ATTR_np_(p2)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p2)>` ]
[ The special value _inf_ may be used; it indicates unlimited repetition. `decltype(_RES_np_(arg0))` must be implicitly convertible to `int64_t`. Matching _e_ an unlimited number of times creates an infinite loop, which is undefined behavior in C++. _Parser_ will assert in debug mode when it encounters `_rpt_np_(_inf_)[_e_]` (this applies to unconditional _e_ only). ]]
[[ `_rpt_np_(arg0, arg1, p1)[p2]` ]
[ Matches iff `p2` matches between `_RES_np_(arg0)` and `_RES_np_(arg1)` times, inclusively, matching `p1` in between each pair of consecutive matches of `p2`. Equivalent to: _e_ for `_RES_np_(arg1) <= 0`, and `_rpt_np_(_RES_np_(arg0) - 1, _RES_np_(arg1) - 1)[p2 >> p1] >> p2` otherwise. ]
[ `std::string` if `_ATTR_np_(p2)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p2)>` ]
[ The special value _inf_ may be used for the upper bound; it indicates unlimited repetition. `decltype(_RES_np_(arg0))` and `decltype(_RES_np_(arg1))` each must be implicitly convertible to `int64_t`. Matching _e_ an unlimited number of times creates an infinite loop, which is undefined behavior in C++. _Parser_ will assert in debug mode when it encounters `_rpt_np_(n, _inf_)[_e_]` (this applies to unconditional _e_ only). ]]
[[ `_if_np_(pred)[p]` ]
[ Equivalent to `_e_(pred) >> p`. ]
[ `_ATTR_np_(p)` ]

View File

@@ -1514,10 +1514,9 @@ attribute, simply returns `bool`; this indicates the success or failure of the
parse.]
[warning _Parser_ assumes that all attributes are semi-regular (see
`std::semiregular`). Move-only types that are nearly `std::semiregular`,
other than their copy operations, are also supported. Within the _Parser_
code, attributes are move assigned, moved, and default constructed. There is
no support for non-default-constructible types.]
`std::semiregular`). Within the _Parser_ code, attributes are assigned,
moved, copy, and default constructed. There is no support for move-only or
non-default-constructible types.]
[heading The attribute type trait, _attr_]

View File

@@ -3212,44 +3212,18 @@ namespace boost { namespace parser {
int64_t count = 0;
auto const iteration = [&](auto prev_first, auto on_fail) {
if constexpr (!detail::is_nope_v<DelimiterParser>) {
if (count) {
detail::skip(first, last, skip, flags);
delimiter_parser_.call(
first,
last,
context,
skip,
detail::disable_attrs(flags),
success);
if (!success) {
on_fail(prev_first);
return false;
}
}
}
for (int64_t end = detail::resolve(context, min_); count != end;
++count) {
detail::skip(first, last, skip, flags);
attr_t attr{};
parser_.call(
first, last, context, skip, flags, success, attr);
if (!success) {
on_fail(prev_first);
return false;
detail::assign(retval, Attribute());
return;
}
detail::move_back(
retval, std::move(attr), detail::gen_attrs(flags));
return true;
};
for (int64_t end = detail::resolve(context, min_); count != end;
++count) {
if (!iteration(first, [&](auto prev_first) {
detail::assign(retval, Attribute());
})) {
return;
}
}
int64_t const end = detail::resolve(context, max_);
@@ -3260,12 +3234,37 @@ namespace boost { namespace parser {
!detail::is_unconditional_eps<Parser>{} || end < Inf);
for (; count != end; ++count) {
if (!iteration(first, [&](auto prev_first) {
auto const prev_first = first;
// This is only ever used in delimited_parser, which
// always has a min=1; we therefore know we're after a
// previous element when this executes.
if constexpr (!detail::is_nope_v<DelimiterParser>) {
detail::skip(first, last, skip, flags);
delimiter_parser_.call(
first,
last,
context,
skip,
detail::disable_attrs(flags),
success);
if (!success) {
success = true;
first = prev_first;
})) {
return;
break;
}
}
detail::skip(first, last, skip, flags);
attr_t attr{};
parser_.call(
first, last, context, skip, flags, success, attr);
if (!success) {
success = true;
first = prev_first;
break;
}
detail::move_back(
retval, std::move(attr), detail::gen_attrs(flags));
}
}
}
@@ -6589,24 +6588,20 @@ namespace boost { namespace parser {
/** Represents a `repeat_parser` as a directive
(e.g. `repeat[other_parser]`). */
template<
typename MinType,
typename MaxType,
typename DelimiterParser = detail::nope>
template<typename MinType, typename MaxType>
struct repeat_directive
{
template<typename Parser2>
constexpr auto operator[](parser_interface<Parser2> rhs) const noexcept
{
using repeat_parser_type =
repeat_parser<Parser2, DelimiterParser, MinType, MaxType>;
repeat_parser<Parser2, detail::nope, MinType, MaxType>;
return parser_interface{
repeat_parser_type{rhs.parser_, min_, max_, delimiter_}};
repeat_parser_type{rhs.parser_, min_, max_}};
}
MinType min_;
MaxType max_;
DelimiterParser delimiter_;
};
/** Returns a `repeat_directive` that repeats exactly `n` times, and whose
@@ -6618,18 +6613,6 @@ namespace boost { namespace parser {
return repeat_directive<T, T>{n, n};
}
/** Returns a `repeat_directive` that repeats exactly `n` times, where the
items parsed are delimited by `DelimiterParser`. The value returned
has an `operator[]` that returns a
`parser_interface<repeat_parser<P>>` from a given parser of type
`parser_interface<P>`. */
template<typename T, typename DelimiterParser>
inline repeat_directive<T, T, DelimiterParser>
repeat(T n, parser_interface<DelimiterParser> sep) noexcept
{
return repeat_directive<T, T, DelimiterParser>{n, n, sep.parser_};
}
/** Returns a `repeat_directive` that repeats between `min_` and `max_`
times, inclusive, and whose `operator[]` returns a
`parser_interface<repeat_parser<P>>` from a given parser of type
@@ -6641,21 +6624,6 @@ namespace boost { namespace parser {
return repeat_directive<MinType, MaxType>{min_, max_};
}
/** Returns a `repeat_directive` that repeats between `min_` and `max_`
times, inclusive, where the items parsed are delimited by
`DelimiterParser`. The value returned has an `operator[]` that
returns a `parser_interface<repeat_parser<P>>` from a given parser of
type `parser_interface<P>`. */
template<typename MinType, typename MaxType, typename DelimiterParser>
inline repeat_directive<MinType, MaxType, DelimiterParser> repeat(
MinType min_,
MaxType max_,
parser_interface<DelimiterParser> sep) noexcept
{
return repeat_directive<MinType, MaxType, DelimiterParser>{
min_, max_, sep.parser_};
}
/** A directive that represents a `perm_parser`, where the items parsed
are delimited by `DelimiterParser`
(e.g. `delimiter(delimter_parser)[some_perm_parser]`). This directive

View File

@@ -1092,72 +1092,6 @@ int main()
// repeat
{
{
constexpr auto parser = repeat(2)[string("zs")];
{
std::string str = "";
std::vector<std::string> chars;
BOOST_TEST(!parse(str, parser, chars));
BOOST_TEST(chars == std::vector<std::string>{});
{
std::optional<std::vector<std::string>> const chars =
parse(str, parser);
BOOST_TEST(!chars);
}
}
{
std::string str = "z";
std::vector<std::string> chars;
BOOST_TEST(!parse(str, parser, chars));
BOOST_TEST(chars == std::vector<std::string>{});
{
std::optional<std::vector<std::string>> const chars =
parse(str, parser);
BOOST_TEST(!chars);
}
}
{
std::string str = "zs";
std::vector<std::string> chars;
BOOST_TEST(!parse(str, parser, chars));
BOOST_TEST(chars == std::vector<std::string>{});
{
std::optional<std::vector<std::string>> const chars =
parse(str, parser);
BOOST_TEST(!chars);
}
}
{
std::string str = "zszs";
std::vector<std::string> chars;
BOOST_TEST(parse(str, parser, chars));
BOOST_TEST(chars == std::vector<std::string>({"zs", "zs"}));
{
std::optional<std::vector<std::string>> const chars =
parse(str, parser);
BOOST_TEST(chars);
BOOST_TEST(
*chars == std::vector<std::string>({"zs", "zs"}));
}
}
{
std::string str = "zszszs";
std::vector<std::string> chars;
BOOST_TEST(!parse(str, parser, chars));
BOOST_TEST(chars == std::vector<std::string>{});
{
std::optional<std::vector<std::string>> const chars =
parse(str, parser);
BOOST_TEST(!chars);
}
}
}
{
constexpr auto parser = repeat(2, 3)[string("zs")];
@@ -1211,228 +1145,6 @@ int main()
*chars == std::vector<std::string>({"zs", "zs"}));
}
}
{
std::string str = "zszszs";
std::vector<std::string> chars;
BOOST_TEST(parse(str, parser, chars));
BOOST_TEST(
chars == std::vector<std::string>({"zs", "zs", "zs"}));
{
std::optional<std::vector<std::string>> const chars =
parse(str, parser);
BOOST_TEST(chars);
BOOST_TEST(
*chars == std::vector<std::string>({"zs", "zs", "zs"}));
}
}
{
std::string str = "zszszszs";
std::vector<std::string> chars;
BOOST_TEST(!parse(str, parser, chars));
BOOST_TEST(chars == std::vector<std::string>{});
{
std::optional<std::vector<std::string>> const chars =
parse(str, parser);
BOOST_TEST(!chars);
}
}
}
{
auto parser = repeat(2, char_(','))[string("zs")];
{
std::string str = "";
std::vector<std::string> chars;
BOOST_TEST(!parse(str, parser, chars));
BOOST_TEST(chars == std::vector<std::string>{});
{
std::optional<std::vector<std::string>> const chars =
parse(str, parser);
BOOST_TEST(!chars);
}
}
{
std::string str = "z";
std::vector<std::string> chars;
BOOST_TEST(!parse(str, parser, chars));
BOOST_TEST(chars == std::vector<std::string>{});
{
std::optional<std::vector<std::string>> const chars =
parse(str, parser);
BOOST_TEST(!chars);
}
}
{
std::string str = "zs";
std::vector<std::string> chars;
BOOST_TEST(!parse(str, parser, chars));
BOOST_TEST(chars == std::vector<std::string>{});
{
std::optional<std::vector<std::string>> const chars =
parse(str, parser);
BOOST_TEST(!chars);
}
}
{
std::string str = "zszs";
std::vector<std::string> chars;
BOOST_TEST(!parse(str, parser, chars));
BOOST_TEST(chars == std::vector<std::string>());
{
std::optional<std::vector<std::string>> const chars =
parse(str, parser);
BOOST_TEST(!chars);
}
}
{
std::string str = "zs,zs";
std::vector<std::string> chars;
BOOST_TEST(parse(str, parser, chars));
BOOST_TEST(chars == std::vector<std::string>({"zs", "zs"}));
{
std::optional<std::vector<std::string>> const chars =
parse(str, parser);
BOOST_TEST(chars);
BOOST_TEST(
*chars == std::vector<std::string>({"zs", "zs"}));
}
}
{
std::string str = "zs,zs,";
std::vector<std::string> chars;
BOOST_TEST(!parse(str, parser, chars));
BOOST_TEST(chars == std::vector<std::string>());
{
std::optional<std::vector<std::string>> const chars =
parse(str, parser);
BOOST_TEST(!chars);
}
}
{
std::string str = "zs,zs,zs";
std::vector<std::string> chars;
BOOST_TEST(!parse(str, parser, chars));
BOOST_TEST(chars == std::vector<std::string>());
{
std::optional<std::vector<std::string>> const chars =
parse(str, parser);
BOOST_TEST(!chars);
}
}
}
{
auto parser = repeat(2, 3, char_(','))[string("zs")];
{
std::string str = "";
std::vector<std::string> chars;
BOOST_TEST(!parse(str, parser, chars));
BOOST_TEST(chars == std::vector<std::string>{});
{
std::optional<std::vector<std::string>> const chars =
parse(str, parser);
BOOST_TEST(!chars);
}
}
{
std::string str = "z";
std::vector<std::string> chars;
BOOST_TEST(!parse(str, parser, chars));
BOOST_TEST(chars == std::vector<std::string>{});
{
std::optional<std::vector<std::string>> const chars =
parse(str, parser);
BOOST_TEST(!chars);
}
}
{
std::string str = "zs";
std::vector<std::string> chars;
BOOST_TEST(!parse(str, parser, chars));
BOOST_TEST(chars == std::vector<std::string>{});
{
std::optional<std::vector<std::string>> const chars =
parse(str, parser);
BOOST_TEST(!chars);
}
}
{
std::string str = "zs,";
std::vector<std::string> chars;
BOOST_TEST(!parse(str, parser, chars));
BOOST_TEST(chars == std::vector<std::string>{});
{
std::optional<std::vector<std::string>> const chars =
parse(str, parser);
BOOST_TEST(!chars);
}
}
{
std::string str = "zs,zs,";
std::vector<std::string> chars;
BOOST_TEST(!parse(str, parser, chars));
BOOST_TEST(chars == std::vector<std::string>{});
{
std::optional<std::vector<std::string>> const chars =
parse(str, parser);
BOOST_TEST(!chars);
}
}
{
std::string str = "zs,zs";
std::vector<std::string> chars;
BOOST_TEST(parse(str, parser, chars));
BOOST_TEST(chars == std::vector<std::string>({"zs", "zs"}));
{
std::optional<std::vector<std::string>> const chars =
parse(str, parser);
BOOST_TEST(chars);
BOOST_TEST(
*chars == std::vector<std::string>({"zs", "zs"}));
}
}
{
std::string str = "zs,zs,zs";
std::vector<std::string> chars;
BOOST_TEST(parse(str, parser, chars));
BOOST_TEST(
chars == std::vector<std::string>({"zs", "zs", "zs"}));
{
std::optional<std::vector<std::string>> const chars =
parse(str, parser);
BOOST_TEST(chars);
BOOST_TEST(
*chars == std::vector<std::string>({"zs", "zs", "zs"}));
}
}
{
std::string str = "zs,zs,zs,zs";
std::vector<std::string> chars;
BOOST_TEST(!parse(str, parser, chars));
BOOST_TEST(chars == std::vector<std::string>{});
{
std::optional<std::vector<std::string>> const chars =
parse(str, parser);
BOOST_TEST(!chars);
}
}
}
{
constexpr auto parser = *char_ >> eps >> *string("str");