mirror of
https://github.com/boostorg/parser.git
synced 2026-02-23 16:02:08 +00:00
Compare commits
3 Commits
introduce_
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
293f5e1e3f | ||
|
|
85320bd6d7 | ||
|
|
e24163dd49 |
@@ -317,6 +317,16 @@ 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)` ]
|
||||
|
||||
@@ -1514,9 +1514,10 @@ 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`). Within the _Parser_ code, attributes are assigned,
|
||||
moved, copy, and default constructed. There is no support for move-only or
|
||||
non-default-constructible types.]
|
||||
`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.]
|
||||
|
||||
[heading The attribute type trait, _attr_]
|
||||
|
||||
|
||||
@@ -3212,18 +3212,44 @@ namespace boost { namespace parser {
|
||||
|
||||
int64_t count = 0;
|
||||
|
||||
for (int64_t end = detail::resolve(context, min_); count != end;
|
||||
++count) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
detail::skip(first, last, skip, flags);
|
||||
attr_t attr{};
|
||||
parser_.call(
|
||||
first, last, context, skip, flags, success, attr);
|
||||
if (!success) {
|
||||
detail::assign(retval, Attribute());
|
||||
return;
|
||||
on_fail(prev_first);
|
||||
return false;
|
||||
}
|
||||
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_);
|
||||
@@ -3234,37 +3260,12 @@ namespace boost { namespace parser {
|
||||
!detail::is_unconditional_eps<Parser>{} || end < Inf);
|
||||
|
||||
for (; count != end; ++count) {
|
||||
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) {
|
||||
if (!iteration(first, [&](auto prev_first) {
|
||||
success = true;
|
||||
first = prev_first;
|
||||
break;
|
||||
}
|
||||
})) {
|
||||
return;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6588,20 +6589,24 @@ namespace boost { namespace parser {
|
||||
|
||||
/** Represents a `repeat_parser` as a directive
|
||||
(e.g. `repeat[other_parser]`). */
|
||||
template<typename MinType, typename MaxType>
|
||||
template<
|
||||
typename MinType,
|
||||
typename MaxType,
|
||||
typename DelimiterParser = detail::nope>
|
||||
struct repeat_directive
|
||||
{
|
||||
template<typename Parser2>
|
||||
constexpr auto operator[](parser_interface<Parser2> rhs) const noexcept
|
||||
{
|
||||
using repeat_parser_type =
|
||||
repeat_parser<Parser2, detail::nope, MinType, MaxType>;
|
||||
repeat_parser<Parser2, DelimiterParser, MinType, MaxType>;
|
||||
return parser_interface{
|
||||
repeat_parser_type{rhs.parser_, min_, max_}};
|
||||
repeat_parser_type{rhs.parser_, min_, max_, delimiter_}};
|
||||
}
|
||||
|
||||
MinType min_;
|
||||
MaxType max_;
|
||||
DelimiterParser delimiter_;
|
||||
};
|
||||
|
||||
/** Returns a `repeat_directive` that repeats exactly `n` times, and whose
|
||||
@@ -6613,6 +6618,18 @@ 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
|
||||
@@ -6624,6 +6641,21 @@ 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
|
||||
|
||||
288
test/parser.cpp
288
test/parser.cpp
@@ -1092,6 +1092,72 @@ 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")];
|
||||
|
||||
@@ -1145,6 +1211,228 @@ 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");
|
||||
|
||||
Reference in New Issue
Block a user