mirror of
https://github.com/boostorg/parser.git
synced 2026-02-23 03:52:14 +00:00
Compare commits
1 Commits
develop
...
introduce_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a200a4074 |
@@ -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)>` ]
|
[ `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). ]]
|
[ 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]` ]
|
[[ `_if_np_(pred)[p]` ]
|
||||||
[ Equivalent to `_e_(pred) >> p`. ]
|
[ Equivalent to `_e_(pred) >> p`. ]
|
||||||
[ `_ATTR_np_(p)` ]
|
[ `_ATTR_np_(p)` ]
|
||||||
|
|||||||
@@ -1514,10 +1514,9 @@ attribute, simply returns `bool`; this indicates the success or failure of the
|
|||||||
parse.]
|
parse.]
|
||||||
|
|
||||||
[warning _Parser_ assumes that all attributes are semi-regular (see
|
[warning _Parser_ assumes that all attributes are semi-regular (see
|
||||||
`std::semiregular`). Move-only types that are nearly `std::semiregular`,
|
`std::semiregular`). Within the _Parser_ code, attributes are assigned,
|
||||||
other than their copy operations, are also supported. Within the _Parser_
|
moved, copy, and default constructed. There is no support for move-only or
|
||||||
code, attributes are move assigned, moved, and default constructed. There is
|
non-default-constructible types.]
|
||||||
no support for non-default-constructible types.]
|
|
||||||
|
|
||||||
[heading The attribute type trait, _attr_]
|
[heading The attribute type trait, _attr_]
|
||||||
|
|
||||||
|
|||||||
@@ -3212,44 +3212,18 @@ namespace boost { namespace parser {
|
|||||||
|
|
||||||
int64_t count = 0;
|
int64_t count = 0;
|
||||||
|
|
||||||
auto const iteration = [&](auto prev_first, auto on_fail) {
|
for (int64_t end = detail::resolve(context, min_); count != end;
|
||||||
if constexpr (!detail::is_nope_v<DelimiterParser>) {
|
++count) {
|
||||||
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);
|
detail::skip(first, last, skip, flags);
|
||||||
attr_t attr{};
|
attr_t attr{};
|
||||||
parser_.call(
|
parser_.call(
|
||||||
first, last, context, skip, flags, success, attr);
|
first, last, context, skip, flags, success, attr);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
on_fail(prev_first);
|
detail::assign(retval, Attribute());
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
detail::move_back(
|
detail::move_back(
|
||||||
retval, std::move(attr), detail::gen_attrs(flags));
|
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_);
|
int64_t const end = detail::resolve(context, max_);
|
||||||
@@ -3260,13 +3234,38 @@ namespace boost { namespace parser {
|
|||||||
!detail::is_unconditional_eps<Parser>{} || end < Inf);
|
!detail::is_unconditional_eps<Parser>{} || end < Inf);
|
||||||
|
|
||||||
for (; count != end; ++count) {
|
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;
|
success = true;
|
||||||
first = prev_first;
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6589,24 +6588,20 @@ namespace boost { namespace parser {
|
|||||||
|
|
||||||
/** Represents a `repeat_parser` as a directive
|
/** Represents a `repeat_parser` as a directive
|
||||||
(e.g. `repeat[other_parser]`). */
|
(e.g. `repeat[other_parser]`). */
|
||||||
template<
|
template<typename MinType, typename MaxType>
|
||||||
typename MinType,
|
|
||||||
typename MaxType,
|
|
||||||
typename DelimiterParser = detail::nope>
|
|
||||||
struct repeat_directive
|
struct repeat_directive
|
||||||
{
|
{
|
||||||
template<typename Parser2>
|
template<typename Parser2>
|
||||||
constexpr auto operator[](parser_interface<Parser2> rhs) const noexcept
|
constexpr auto operator[](parser_interface<Parser2> rhs) const noexcept
|
||||||
{
|
{
|
||||||
using repeat_parser_type =
|
using repeat_parser_type =
|
||||||
repeat_parser<Parser2, DelimiterParser, MinType, MaxType>;
|
repeat_parser<Parser2, detail::nope, MinType, MaxType>;
|
||||||
return parser_interface{
|
return parser_interface{
|
||||||
repeat_parser_type{rhs.parser_, min_, max_, delimiter_}};
|
repeat_parser_type{rhs.parser_, min_, max_}};
|
||||||
}
|
}
|
||||||
|
|
||||||
MinType min_;
|
MinType min_;
|
||||||
MaxType max_;
|
MaxType max_;
|
||||||
DelimiterParser delimiter_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Returns a `repeat_directive` that repeats exactly `n` times, and whose
|
/** 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};
|
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_`
|
/** Returns a `repeat_directive` that repeats between `min_` and `max_`
|
||||||
times, inclusive, and whose `operator[]` returns a
|
times, inclusive, and whose `operator[]` returns a
|
||||||
`parser_interface<repeat_parser<P>>` from a given parser of type
|
`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_};
|
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
|
/** A directive that represents a `perm_parser`, where the items parsed
|
||||||
are delimited by `DelimiterParser`
|
are delimited by `DelimiterParser`
|
||||||
(e.g. `delimiter(delimter_parser)[some_perm_parser]`). This directive
|
(e.g. `delimiter(delimter_parser)[some_perm_parser]`). This directive
|
||||||
|
|||||||
288
test/parser.cpp
288
test/parser.cpp
@@ -1092,72 +1092,6 @@ int main()
|
|||||||
|
|
||||||
// repeat
|
// 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")];
|
constexpr auto parser = repeat(2, 3)[string("zs")];
|
||||||
|
|
||||||
@@ -1211,228 +1145,6 @@ int main()
|
|||||||
*chars == std::vector<std::string>({"zs", "zs"}));
|
*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");
|
constexpr auto parser = *char_ >> eps >> *string("str");
|
||||||
|
|||||||
Reference in New Issue
Block a user