Skip to content

Commit

Permalink
Add an optional char parser to quoted_string_parser, so that it can b…
Browse files Browse the repository at this point in the history
…e made

fully general.

Fixes #196.
  • Loading branch information
tzlaine committed Dec 17, 2024
1 parent 958ac38 commit 42c9d82
Show file tree
Hide file tree
Showing 6 changed files with 187 additions and 33 deletions.
8 changes: 8 additions & 0 deletions doc/tutorial.qbk
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,14 @@ escaped quote character, since those always work.

[quoted_string_example_5]

Additionally, with each of the forms shown above, you can optionally provide a
parser as a final argument, to will be used to parse each character inside the
quotes. You have to provide an actual full parser here; you cannot provide a
character or string literal. If you do not provide a character parser, _ch_
is used.

[quoted_string_example_6]

[endsect]

[section Parsing In Detail]
Expand Down
8 changes: 6 additions & 2 deletions include/boost/parser/detail/printing.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -280,10 +280,14 @@ namespace boost { namespace parser { namespace detail {
std::ostream & os,
int components = 0);

template<typename Context, typename Quotes, typename Escapes>
template<
typename Context,
typename Quotes,
typename Escapes,
typename CharParser>
void print_parser(
Context const & context,
quoted_string_parser<Quotes, Escapes> const & parser,
quoted_string_parser<Quotes, Escapes, CharParser> const & parser,
std::ostream & os,
int components = 0);

Expand Down
8 changes: 6 additions & 2 deletions include/boost/parser/detail/printing_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -695,10 +695,14 @@ namespace boost { namespace parser { namespace detail {
os << "\"";
}

template<typename Context, typename Quotes, typename Escapes>
template<
typename Context,
typename Quotes,
typename Escapes,
typename CharParser>
void print_parser(
Context const & context,
quoted_string_parser<Quotes, Escapes> const & parser,
quoted_string_parser<Quotes, Escapes, CharParser> const & parser,
std::ostream & os,
int components)
{
Expand Down
98 changes: 72 additions & 26 deletions include/boost/parser/parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7252,7 +7252,7 @@ namespace boost { namespace parser {
return parser_interface{string_parser(str)};
}

template<typename Quotes, typename Escapes>
template<typename Quotes, typename Escapes, typename CharParser>
struct quoted_string_parser
{
constexpr quoted_string_parser() : chs_(), ch_('"') {}
Expand All @@ -7265,7 +7265,11 @@ namespace boost { namespace parser {
typename Enable =
std::enable_if_t<detail::is_parsable_range_like_v<R>>>
#endif
constexpr quoted_string_parser(R && r) : chs_((R &&) r), ch_(0)
constexpr quoted_string_parser(
R && r,
parser_interface<CharParser> char_p =
parser_interface{CharParser()}) :
chs_((R &&)r), char_p_(char_p), ch_(0)
{
BOOST_PARSER_DEBUG_ASSERT(r.begin() != r.end());
}
Expand All @@ -7278,16 +7282,29 @@ namespace boost { namespace parser {
typename Enable =
std::enable_if_t<detail::is_parsable_range_like_v<R>>>
#endif
constexpr quoted_string_parser(R && r, Escapes escapes) :
chs_((R &&) r), escapes_(escapes), ch_(0)
constexpr quoted_string_parser(
R && r,
Escapes escapes,
parser_interface<CharParser> char_p =
parser_interface{CharParser()}) :
chs_((R &&)r), escapes_(escapes), char_p_(char_p), ch_(0)
{
BOOST_PARSER_DEBUG_ASSERT(r.begin() != r.end());
}

constexpr quoted_string_parser(char32_t cp) : chs_(), ch_(cp) {}
constexpr quoted_string_parser(
char32_t cp,
parser_interface<CharParser> char_p =
parser_interface{CharParser()}) :
chs_(), char_p_(char_p), ch_(cp)
{}

constexpr quoted_string_parser(char32_t cp, Escapes escapes) :
chs_(), escapes_(escapes), ch_(cp)
constexpr quoted_string_parser(
char32_t cp,
Escapes escapes,
parser_interface<CharParser> char_p =
parser_interface{CharParser()}) :
chs_(), escapes_(escapes), char_p_(char_p), ch_(cp)
{}

template<
Expand Down Expand Up @@ -7376,11 +7393,11 @@ namespace boost { namespace parser {
auto make_parser = [&]() {
if constexpr (detail::is_nope_v<Escapes>) {
return *((lit('\\') >> back_delim) |
(char_ - back_delim))[append] > ch;
(char_p_ - back_delim))[append] > ch;
} else {
return *((lit('\\') >> back_delim)[append] |
(lit('\\') >> parser_interface(escapes_))[append] |
(char_ - back_delim)[append]) > ch;
(char_p_ - back_delim)[append]) > ch;
}
};

Expand All @@ -7402,15 +7419,17 @@ namespace boost { namespace parser {
/** Returns a `parser_interface` containing a `quoted_string_parser`
that uses `x` as its quotation marks. */
#if BOOST_PARSER_USE_CONCEPTS
template<typename T>
template<typename T, typename Parser = char_parser<detail::nope>>
requires(!parsable_range_like<T>)
#else
template<
typename T,
typename Parser = char_parser<detail::nope>,
typename Enable =
std::enable_if_t<!detail::is_parsable_range_like_v<T>>>
#endif
constexpr auto operator()(T x) const noexcept
constexpr auto
operator()(T x, parser_interface<Parser> char_p = char_) const noexcept
{
if constexpr (!detail::is_nope_v<Quotes>) {
BOOST_PARSER_ASSERT(
Expand All @@ -7419,7 +7438,9 @@ namespace boost { namespace parser {
"quoted_string, like 'quoted_string('\"')('\\'')'. Quit "
"it!'"));
}
return parser_interface(quoted_string_parser(std::move(x)));
return parser_interface(
quoted_string_parser<detail::nope, detail::nope, Parser>(
std::move(x), char_p));
}

/** Returns a `parser_interface` containing a `quoted_string_parser`
Expand All @@ -7430,14 +7451,18 @@ namespace boost { namespace parser {
character begin matched is directly compared to the elements of
`r`. */
#if BOOST_PARSER_USE_CONCEPTS
template<parsable_range_like R>
template<
parsable_range_like R,
typename Parser = char_parser<detail::nope>>
#else
template<
typename R,
typename Parser = char_parser<detail::nope>,
typename Enable =
std::enable_if_t<detail::is_parsable_range_like_v<R>>>
#endif
constexpr auto operator()(R && r) const noexcept
constexpr auto operator()(
R && r, parser_interface<Parser> char_p = char_) const noexcept
{
BOOST_PARSER_ASSERT(((
!std::is_rvalue_reference_v<R &&> ||
Expand All @@ -7453,10 +7478,14 @@ namespace boost { namespace parser {
"'quoted_string(char-range)(char-range)'. Quit it!'"));
}
return parser_interface(
quoted_string_parser<decltype(BOOST_PARSER_SUBRANGE(
detail::make_view_begin(r), detail::make_view_end(r)))>(
quoted_string_parser<
decltype(BOOST_PARSER_SUBRANGE(
detail::make_view_begin(r), detail::make_view_end(r))),
detail::nope,
Parser>(
BOOST_PARSER_SUBRANGE(
detail::make_view_begin(r), detail::make_view_end(r))));
detail::make_view_begin(r), detail::make_view_end(r)),
char_p));
}

/** Returns a `parser_interface` containing a `quoted_string_parser`
Expand All @@ -7465,16 +7494,23 @@ namespace boost { namespace parser {
sequence, and what character(s) each escape sequence represents.
Note that `"\\"` and `"\ch"` are always valid escape sequences. */
#if BOOST_PARSER_USE_CONCEPTS
template<typename T, typename U>
template<
typename T,
typename U,
typename Parser = char_parser<detail::nope>>
requires(!parsable_range_like<T>)
#else
template<
typename T,
typename U,
typename Parser = char_parser<detail::nope>,
typename Enable =
std::enable_if_t<!detail::is_parsable_range_like_v<T>>>
#endif
auto operator()(T x, symbols<U> const & escapes) const noexcept
auto operator()(
T x,
symbols<U> const & escapes,
parser_interface<Parser> char_p = char_) const noexcept
{
if constexpr (!detail::is_nope_v<Quotes>) {
BOOST_PARSER_ASSERT(
Expand All @@ -7484,8 +7520,9 @@ namespace boost { namespace parser {
"it!'"));
}
auto symbols = symbol_parser(escapes.parser_);
auto parser = quoted_string_parser<detail::nope, decltype(symbols)>(
char32_t(x), symbols);
auto parser =
quoted_string_parser<detail::nope, decltype(symbols), Parser>(
char32_t(x), symbols, char_p);
return parser_interface(parser);
}

Expand All @@ -7500,15 +7537,22 @@ namespace boost { namespace parser {
escape sequence represents. Note that `"\\"` and `"\ch"` are
always valid escape sequences. */
#if BOOST_PARSER_USE_CONCEPTS
template<parsable_range_like R, typename T>
template<
parsable_range_like R,
typename T,
typename Parser = char_parser<detail::nope>>
#else
template<
typename R,
typename T,
typename Parser = char_parser<detail::nope>,
typename Enable =
std::enable_if_t<detail::is_parsable_range_like_v<R>>>
#endif
auto operator()(R && r, symbols<T> const & escapes) const noexcept
auto operator()(
R && r,
symbols<T> const & escapes,
parser_interface<Parser> char_p = char_) const noexcept
{
BOOST_PARSER_ASSERT(((
!std::is_rvalue_reference_v<R &&> ||
Expand All @@ -7526,14 +7570,16 @@ namespace boost { namespace parser {
auto symbols = symbol_parser(escapes.parser_);
auto quotes = BOOST_PARSER_SUBRANGE(
detail::make_view_begin(r), detail::make_view_end(r));
auto parser =
quoted_string_parser<decltype(quotes), decltype(symbols)>(
quotes, symbols);
auto parser = quoted_string_parser<
decltype(quotes),
decltype(symbols),
Parser>(quotes, symbols, char_p);
return parser_interface(parser);
}

Quotes chs_;
Escapes escapes_;
parser_interface<CharParser> char_p_;
char32_t ch_;
};

Expand Down
5 changes: 4 additions & 1 deletion include/boost/parser/parser_fwd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,10 @@ namespace boost { namespace parser {

/** Matches a string delimited by quotation marks; produces a
`std::string` attribute. */
template<typename Quotes = detail::nope, typename Escapes = detail::nope>
template<
typename Quotes = detail::nope,
typename Escapes = detail::nope,
typename CharParser = char_parser<detail::nope>>
struct quoted_string_parser;

/** Matches an end-of-line (`NewlinesOnly == true`), whitespace
Expand Down
Loading

0 comments on commit 42c9d82

Please sign in to comment.