2
0
mirror of https://github.com/boostorg/parser.git synced 2026-01-20 04:42:22 +00:00

6 Commits

Author SHA1 Message Date
Zach Laine
88abb615aa Add pre_- and post_parser members to parser_modifiers; these are used as
look-ahead/-behind positive or negative assertions.

When combining parsers using op>> and op>, if either side is an expect_parser
and the other side has an open pre_-/post_parser slot, take the subparser out
of the expect_parser, and use it directly in the pre_-/post_parser slot.

See #160.
2024-12-16 19:24:39 -06:00
Zach Laine
54f8eecfe6 Change the no_case[] directive to use the parser_modifiers struct, like omit[]
does; remove no_case_parser.

See #160.
2024-12-16 19:24:39 -06:00
Zach Laine
fcd257abca Generalize with_parser_mods(), so that some functions can be recursive, and
others can be non-recursive.

See #160.
2024-12-16 19:24:39 -06:00
Zach Laine
2f7e5964a6 Apply the same sort of change as the previous two commits, but to all the
parsers not already modified.  Generalize with_parser_mods().  Remove
omit_parser, since it is now moot.

See #160.
2024-12-16 19:24:39 -06:00
Zach Laine
2fff00b3e1 Change string_parser to support the use of parser_modifiers, and change lit()
to return a parameterized string_parser instead of string_parser wrapped in an
omit_parser.

See #160.
2024-12-16 19:24:39 -06:00
Zach Laine
28e9b61735 Add a new template, parser_modifiers, that will hold common modifications to
parsers, like turning off attribute generation (replacing omit_parser).
Change char_parser to support the use of parser_modifiers, and change lit() to
return a parameterized char_parser instead of char_parser wrapped in an
omit_parser.

See #160.
2024-12-16 19:24:39 -06:00
24 changed files with 3126 additions and 5107 deletions

View File

@@ -57,7 +57,7 @@ Master status:
[![Windows MSVC](https://github.com/tzlaine/parser/actions/workflows/windows.yml/badge.svg?branch=master)](https://github.com/tzlaine/parser/actions/workflows/windows.yml)
[![macos-13 - Clang 14](https://github.com/tzlaine/parser/actions/workflows/macos-13.yml/badge.svg?branch=master)](https://github.com/tzlaine/parser/actions/workflows/macos-13.yml)
[![macos-12 - Clang 14](https://github.com/tzlaine/parser/actions/workflows/macos-12.yml/badge.svg?branch=master)](https://github.com/tzlaine/parser/actions/workflows/macos-12.yml)
Develop status:
@@ -67,6 +67,6 @@ Develop status:
[![Windows MSVC](https://github.com/tzlaine/parser/actions/workflows/windows.yml/badge.svg?branch=develop)](https://github.com/tzlaine/parser/actions/workflows/windows.yml)
[![macos-13 - Clang 14](https://github.com/tzlaine/parser/actions/workflows/macos-13.yml/badge.svg?branch=develop)](https://github.com/tzlaine/parser/actions/workflows/macos-13.yml)
[![macos-12 - Clang 14](https://github.com/tzlaine/parser/actions/workflows/macos-12.yml/badge.svg?branch=develop)](https://github.com/tzlaine/parser/actions/workflows/macos-12.yml)
[![License](https://img.shields.io/badge/license-boost-brightgreen.svg)](LICENSE_1_0.txt)

View File

@@ -110,7 +110,6 @@
[def _std_str_ `std::string`]
[def _std_strs_ `std::string`s]
[def _std_vec_char_ `std::vector<char>`]
[def _std_vec_char32_ `std::vector<char32_t>`]
@@ -202,7 +201,6 @@
[def _merge_ [globalref boost::parser::merge `merge[]`]]
[def _sep_ [globalref boost::parser::separate `separate[]`]]
[def _transform_ [globalref boost::parser::transform `transform(f)[]`]]
[def _delimiter_ [globalref boost::parser::delimiter `delimiter(p)[]`]]
[def _omit_np_ [globalref boost::parser::omit `omit`]]
[def _raw_np_ [globalref boost::parser::raw `raw`]]
@@ -213,13 +211,11 @@
[def _merge_np_ [globalref boost::parser::merge `merge`]]
[def _sep_np_ [globalref boost::parser::separate `separate`]]
[def _transform_np_ [globalref boost::parser::transform `transform`]]
[def _delimiter_np_ [globalref boost::parser::delimiter `delimiter`]]
[def _blank_ [globalref boost::parser::blank `blank`]]
[def _control_ [globalref boost::parser::control `control`]]
[def _digit_ [globalref boost::parser::digit `digit`]]
[def _punct_ [globalref boost::parser::punct `punct`]]
[def _symb_ [globalref boost::parser::symb `symb`]]
[def _hex_digit_ [globalref boost::parser::hex_digit `hex_digit`]]
[def _lower_ [globalref boost::parser::lower `lower`]]
[def _upper_ [globalref boost::parser::upper `upper`]]
@@ -243,7 +239,6 @@
[def _more_about_rules_ [link boost_parser.tutorial.more_about_rules More About Rules]]
[def _unicode_ [link boost_parser.tutorial.unicode_support Unicode Support]]
[def _concepts_ [link boost_parser.concepts Concepts]]
[def _seq_parser_example_ [link boost_parser.tutorial.attribute_generation.a_sequence_parser_attribute_example A sequence parser attribute example]]
[def _ex_json_ [link boost_parser.extended_examples.parsing_json Parsing JSON]]
[def _ex_cb_json_ [link boost_parser.extended_examples.parsing_json_with_callbacks Parsing JSON With Callbacks]]
[def _rationale_ [link boost_parser.rationale Rationale]]

File diff suppressed because it is too large Load Diff

View File

@@ -132,11 +132,6 @@ the input they match unless otherwise stated in the table below.]
[ The code point type in Unicode parsing, or `char` in non-Unicode parsing. See the entry for _ch_. ]
[]]
[[ `_symb_` ]
[ Matches a single symbol code point. ]
[ The code point type in Unicode parsing, or `char` in non-Unicode parsing. See the entry for _ch_. ]
[]]
[[ `_hex_digit_` ]
[ Matches a single hexidecimal digit code point. ]
[ The code point type in Unicode parsing, or `char` in non-Unicode parsing. See the entry for _ch_. ]
@@ -390,10 +385,10 @@ consume the input they match unless otherwise stated in the table below.]
[[`*p`] [ Parses using `p` repeatedly until `p` no longer matches; always matches. ] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`] [ 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 `*_e_` (this applies to unconditional _e_ only). ]]
[[`+p`] [ Parses using `p` repeatedly until `p` no longer matches; matches iff `p` matches at least once. ] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`] [ 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 `+_e_` (this applies to unconditional _e_ only). ]]
[[`-p`] [ Equivalent to `p | _e_`. ] [`std::optional<_ATTR_np_(p)>`] []]
[[`p1 >> p2`] [ Matches iff `p1` matches and then `p2` matches. ] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2)>` (See note.)] [ `>>` is associative; `p1 >> p2 >> p3`, `(p1 >> p2) >> p3`, and `p1 >> (p2 >> p3)` are all equivalent. This attribute type only applies to the case where `p1` and `p2` both generate attributes; see _attr_gen_ for the full rules. Differs in precedence from `operator>`. ]]
[[`p1 >> p2`] [ Matches iff `p1` matches and then `p2` matches. ] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2)>` (See note.)] [ `>>` is associative; `p1 >> p2 >> p3`, `(p1 >> p2) >> p3`, and `p1 >> (p2 >> p3)` are all equivalent. This attribute type only applies to the case where `p1` and `p2` both generate attributes; see _attr_gen_ for the full rules. ]]
[[`p >> c`] [ Equivalent to `p >> lit(c)`. ] [`_ATTR_np_(p)`] []]
[[`p >> r`] [ Equivalent to `p >> lit(r)`. ] [`_ATTR_np_(p)`] []]
[[`p1 > p2`] [ Matches iff `p1` matches and then `p2` matches. No back-tracking is allowed after `p1` matches; if `p1` matches but then `p2` does not, the top-level parse fails. ] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2)>` (See note.)] [ `>` is associative; `p1 > p2 > p3`, `(p1 > p2) > p3`, and `p1 > (p2 > p3)` are all equivalent. This attribute type only applies to the case where `p1` and `p2` both generate attributes; see _attr_gen_ for the full rules. Differs in precedence from `operator>>`. ]]
[[`p1 > p2`] [ Matches iff `p1` matches and then `p2` matches. No back-tracking is allowed after `p1` matches; if `p1` matches but then `p2` does not, the top-level parse fails. ] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2)>` (See note.)] [ `>` is associative; `p1 > p2 > p3`, `(p1 > p2) > p3`, and `p1 > (p2 > p3)` are all equivalent. This attribute type only applies to the case where `p1` and `p2` both generate attributes; see _attr_gen_ for the full rules. ]]
[[`p > c`] [ Equivalent to `p > lit(c)`. ] [`_ATTR_np_(p)`] []]
[[`p > r`] [ Equivalent to `p > lit(r)`. ] [`_ATTR_np_(p)`] []]
[[`p1 | p2`] [ Matches iff either `p1` matches or `p2` matches. ] [`std::variant<_ATTR_np_(p1), _ATTR_np_(p2)>` (See note.)] [ `|` is associative; `p1 | p2 | p3`, `(p1 | p2) | p3`, and `p1 | (p2 | p3)` are all equivalent. This attribute type only applies to the case where `p1` and `p2` both generate attributes, and where the attribute types are different; see _attr_gen_ for the full rules. ]]
@@ -429,15 +424,6 @@ because, for any parser `p`, `_e_ | p` is equivalent to _e_, since _e_ always
matches. This is not true for _e_ parameterized with a condition. For any
condition `cond`, `_e_(cond)` is allowed to appear anywhere within an
alternative parser.
[important The C++ operators `>` and `>>` have different precedences. This
will sometimes come up in warnings from your compiler. No matter how you do
or do not parenthesize chains of parsers separated by `>` and `>>`, the
resulting expression evaluates the same. Feel free to add parentheses if your
compiler complains. More broadly, keep the C++ operator precedence rules in
mind when writing your parsers _emdash_ the simplest thing to write may not
have your intended semantics. ]
]
[template table_attribute_generation

View File

@@ -65,7 +65,7 @@ subparsers does.
Finally, there is a /permutation parser/; it is created using `operator||`,
as in `p1 || p2 || p3`. A permutation parser tries to match all of its
subparsers to the input, in any order. So the parser `p1 || p2 || p3` is equivalent to `(p1 >> p2 >> p3) | (p1 >> p3 >> p2) | (p2 >> p1 >> p3) | (p2 >> p3 >> p1) | (p3 >> p1 >> p2) | (p3 >> p2 >> p1)`. Hopefully the advantage of its terseness is self-explanatory. It matches the
subparsers to the input, in any order. So the parser `p1 || p2 || p3` is equivalent to `(p1 >> p2 >> p3) | (p1 >> p3 >> p2) | (p2 >> p1 >> p3) | (p2 >> p3 >> p1) | (p3 >> p1 >> p2) | (p3 >> p2 >> p1)`. Hopefully its terseness is self-explanatory. It matches the
input iff all of its subparsers do, regardless of the order they match in.
_Parser_ parsers each have an /attribute/ associated with them, or explicitly
@@ -836,14 +836,6 @@ 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]
@@ -1450,24 +1442,6 @@ _merge_ and _sep_ create a copy of the given _seq_p_.
_transform_ creates a _xfm_p_.
[heading _delimiter_]
The _delimiter_np_ directive enables the use of a delimiter within a
permutation parser. It *only* applies to permutation parsers, just as _merge_
and _sep_ only apply to sequence parsers. Consider this permutation parser.
constexpr auto parser = bp::int_ || bp::string("foo") || bp::char_('g');
This will match all of: an integer, `"foo"`, and `'g'`, in any order (for
example, `"foo g 42"`). If you also want for those three elements to be
delimited by commas, you could write this parser instead.
constexpr auto delimited_parser =
bp::delimiter(bp::lit(','))[bp::int_ || bp::string("foo") || bp::char_('g')];
`delimited_parser` will parse the same elements as `parser`, but will also
require commas between the elements (as in `"foo, g, 42"`).
[endsect]
[section Combining Operations]
@@ -1616,71 +1590,6 @@ attribute becomes `T`.
[container_concept]
]
[heading A sequence parser attribute example]
Note that the application of `OP` is done in the style of a left-fold, and
is therefore greedy. This can lead to some non-obvious results. For example,
consider this program. Thanks to Duncan Paterson for this very nice example!
#include <boost/parser/parser.hpp>
#include <print>
namespace bp = boost::parser;
int main() {
const auto id_set_action = [](auto &ctx) {
const auto& [left, right] = _attr(ctx);
std::println("{} = {}", left, right);
};
const auto id_parser = bp::char_('a', 'z') > *bp::char_('a', 'z');
const auto id_set = (id_parser >> '=' >> id_parser)[id_set_action];
bp::parse("left=right", id_set);
return 0;
}
Perhaps surprisingly, this program prints `leftr = ight`! Why is this? This
happens because `id_parser` seems to impose structure, but does not. `id_set`
is exactly equivalent to this (comments added to clarify which parts are which
below).
const auto id_set = (
/*A*/ bp::char_('a', 'z') > /*B*/ *bp::char_('a', 'z') >>
/*C*/ '=' >>
/*D*/ bp::char_('a', 'z') > /*E*/ *bp::char_('a', 'z')
)[id_set_action];
As _Parser_ applies `OP` to this sequence parser, the individual steps are:
`A` and `B` get merged into a single _std_str_; `C` is ignored, since it
produces no attribute; and `D` gets merged into the _std_str_ formed earlier
by `A` and `B`; finally, we have `E`. `E` does not combine with `D`, as `D`
was already consumed. `E` also does not combine with the _std_str_ we formed
from `A`, `B`, and `D`, since we don't combine adjacent containers. In the
end, we have a 2-tuple of _std_strs_, in which the first element contains all
the characters parsed by `A`, `B`, and `D`, and in which the second element
contains all the characters parsed by `E`.
That's clearly not what we wanted here, though. How do we get a top-level
parser that would print `left = right`? We use a _r_. The parser used inside
a _r_ can never combine with any parser(s) outside the _r_. Instances of a
rule are inherently separate from all parsers with which they are used,
whether those parsers are _rs_ or non-_r_ parsers. So, consider a _r_
equivalent to the previous `id_parser` above.
namespace bp = boost::parser;
bp::rule<struct id_parser_tag, std::string> id_parser = "identifier";
auto const id_parser_def = bp::char_('a', 'z') > *bp::char_('a', 'z');
BOOST_PARSER_DEFINE_RULES(id_parser);
Later, we can use it just as we used the previous non-rule version.
const auto id_set = (id_parser >> '=' >> id_parser)[id_set_action];
This produces the results you might expect, since only the `bp::char_('a',
'z') > *bp::char_('a', 'z')` parser inside the `id_parser` _r_ is ever
eligible for combining via `OP`.
[heading Alternative parser attribute rules]
The rules for alternative parsers are much simpler. For an alternative parer
@@ -2302,8 +2211,6 @@ common use cases for _rs_. Use a _r_ if you want to:
* fix the attribute type produced by a parser to something other than the
default;
* control the attributes generated by adjacent sequence parsers;
* create a parser that produces useful diagnostic text;
* create a recursive rule (more on this below);
@@ -2444,10 +2351,6 @@ action if:
The notion of "compatible" is defined in _p_api_.
[heading Controlling the attributes generated]
See the _seq_parser_example_ in the _attr_gen_ section for details.
[heading Creating a parser for better diagnostics]
Each _r_ has associated diagnostic text that _Parser_ can use for failures of

View File

@@ -73,12 +73,6 @@
#endif
// Follows logic in boost/config/detail/select_compiler_config.hpp.
#if defined(__clang__) && !defined(__ibmxl__) && !defined(__CODEGEARC__)
#elif defined(__GNUC__) && !defined(__ibmxl__)
#define BOOST_PARSER_GCC
#endif
#if defined(__cpp_lib_constexpr_algorithms)
# define BOOST_PARSER_ALGO_CONSTEXPR constexpr
#else

View File

@@ -52,110 +52,118 @@ namespace boost { namespace parser { namespace detail {
typename Parser,
typename DelimiterParser,
typename MinType,
typename MaxType>
void print_parser(
typename MaxType,
typename ParserMods>
void print_parser_impl(
Context const & context,
repeat_parser<Parser, DelimiterParser, MinType, MaxType> const & parser,
repeat_parser<
Parser,
DelimiterParser,
MinType,
MaxType,
ParserMods> const & parser,
std::ostream & os,
int components = 0);
int components);
template<typename Context, typename Parser>
void print_parser(
template<typename Context, typename Parser, typename ParserMods>
void print_parser_impl(
Context const & context,
opt_parser<Parser> const & parser,
opt_parser<Parser, ParserMods> const & parser,
std::ostream & os,
int components = 0);
int components);
template<typename Context, typename ParserTuple>
void print_parser(
template<typename Context, typename ParserTuple, typename ParserMods>
void print_parser_impl(
Context const & context,
or_parser<ParserTuple> const & parser,
or_parser<ParserTuple, ParserMods> const & parser,
std::ostream & os,
int components = 0);
int components);
template<typename Context, typename ParserTuple, typename DelimiterParser>
void print_parser(
template<typename Context, typename ParserTuple, typename ParserMods>
void print_parser_impl(
Context const & context,
perm_parser<ParserTuple, DelimiterParser> const & parser,
perm_parser<ParserTuple, ParserMods> const & parser,
std::ostream & os,
int components = 0);
int components);
template<
typename Context,
typename ParserTuple,
typename BacktrackingTuple,
typename CombiningGroups>
void print_parser(
typename CombiningGroups,
typename ParserMods>
void print_parser_impl(
Context const & context,
seq_parser<ParserTuple, BacktrackingTuple, CombiningGroups> const &
parser,
seq_parser<
ParserTuple,
BacktrackingTuple,
CombiningGroups,
ParserMods> const & parser,
std::ostream & os,
int components = 0);
int components);
template<typename Context, typename Parser, typename Action>
void print_parser(
template<
typename Context,
typename Parser,
typename Action,
typename ParserMods>
void print_parser_impl(
Context const & context,
action_parser<Parser, Action> const & parser,
action_parser<Parser, Action, ParserMods> const & parser,
std::ostream & os,
int components = 0);
int components);
template<typename Context, typename Parser, typename F>
void print_parser(
template<typename Context, typename Parser, typename F, typename ParserMods>
void print_parser_impl(
Context const & context,
transform_parser<Parser, F> const & parser,
transform_parser<Parser, F, ParserMods> const & parser,
std::ostream & os,
int components = 0);
int components);
template<typename Context, typename Parser>
void print_parser(
template<typename Context, typename Parser, typename ParserMods>
void print_parser_impl(
Context const & context,
omit_parser<Parser> const & parser,
raw_parser<Parser, ParserMods> const & parser,
std::ostream & os,
int components = 0);
template<typename Context, typename Parser>
void print_parser(
Context const & context,
raw_parser<Parser> const & parser,
std::ostream & os,
int components = 0);
int components);
#if defined(BOOST_PARSER_DOXYGEN) || BOOST_PARSER_USE_CONCEPTS
template<typename Context, typename Parser>
void print_parser(
template<typename Context, typename Parser, typename ParserMods>
void print_parser_impl(
Context const & context,
string_view_parser<Parser> const & parser,
string_view_parser<Parser, ParserMods> const & parser,
std::ostream & os,
int components = 0);
int components);
#endif
template<typename Context, typename Parser>
void print_parser(
template<typename Context, typename Parser, typename ParserMods>
void print_parser_impl(
Context const & context,
lexeme_parser<Parser> const & parser,
lexeme_parser<Parser, ParserMods> const & parser,
std::ostream & os,
int components = 0);
int components);
template<typename Context, typename Parser>
void print_parser(
template<
typename Context,
typename Parser,
typename SkipParser,
typename ParserMods>
void print_parser_impl(
Context const & context,
no_case_parser<Parser> const & parser,
skip_parser<Parser, SkipParser, ParserMods> const & parser,
std::ostream & os,
int components = 0);
int components);
template<typename Context, typename Parser, typename SkipParser>
void print_parser(
template<
typename Context,
typename Parser,
expect_match_t ExpectMatch,
typename ParserMods>
void print_parser_impl(
Context const & context,
skip_parser<Parser, SkipParser> const & parser,
expect_parser<Parser, ExpectMatch, ParserMods> const & parser,
std::ostream & os,
int components = 0);
template<typename Context, typename Parser, bool FailOnMatch>
void print_parser(
Context const & context,
expect_parser<Parser, FailOnMatch> const & parser,
std::ostream & os,
int components = 0);
int components);
template<
typename Context,
@@ -163,154 +171,147 @@ namespace boost { namespace parser { namespace detail {
typename Parser,
typename Attribute,
typename LocalState,
typename ParamsTuple>
void print_parser(
typename ParamsTuple,
typename ParserMods>
void print_parser_impl(
Context const & context,
rule_parser<
UseCallbacks,
Parser,
Attribute,
LocalState,
ParamsTuple> const & parser,
ParamsTuple,
ParserMods> const & parser,
std::ostream & os,
int components = 0);
int components);
template<typename Context, typename T>
void print_parser(
template<typename Context, typename T, typename ParserMods>
void print_parser_impl(
Context const & context,
symbol_parser<T> const & parser,
symbol_parser<T, ParserMods> const & parser,
std::ostream & os,
int components = 0);
int components);
template<typename Context, typename Predicate>
void print_parser(
template<typename Context, typename Predicate, typename ParserMods>
void print_parser_impl(
Context const & context,
eps_parser<Predicate> const & parser,
eps_parser<Predicate, ParserMods> const & parser,
std::ostream & os,
int components = 0);
int components);
template<typename Context>
void print_parser(
template<typename Context, typename ParserMods>
void print_parser_impl(
Context const & context,
eps_parser<nope> const & parser,
eps_parser<nope, ParserMods> const & parser,
std::ostream & os,
int components = 0);
int components);
template<typename Context>
void print_parser(
template<typename Context, typename ParserMods>
void print_parser_impl(
Context const & context,
eoi_parser const & parser,
eoi_parser<ParserMods> const & parser,
std::ostream & os,
int components = 0);
int components);
template<typename Context, typename Atribute>
void print_parser(
template<typename Context, typename Atribute, typename ParserMods>
void print_parser_impl(
Context const & context,
attr_parser<Atribute> const & parser,
attr_parser<Atribute, ParserMods> const & parser,
std::ostream & os,
int components = 0);
int components);
template<typename Context, typename Expected, typename AttributeType>
void print_parser(
template<
typename Context,
typename Expected,
typename AttributeType,
typename ParserMods>
void print_parser_impl(
Context const & context,
char_parser<Expected, AttributeType> const & parser,
char_parser<Expected, AttributeType, ParserMods> const & parser,
std::ostream & os,
int components = 0);
int components);
template<typename Context>
void print_parser(
template<typename Context, typename ParserMods>
void print_parser_impl(
Context const & context,
digit_parser const & parser,
digit_parser<ParserMods> const & parser,
std::ostream & os,
int components = 0);
int components);
template<typename Context>
void print_parser(
template<typename Context, typename ParserMods>
void print_parser_impl(
Context const & context,
char_subrange_parser<hex_digit_subranges> const & parser,
char_subrange_parser<hex_digit_subranges, ParserMods> const & parser,
std::ostream & os,
int components = 0);
int components);
template<typename Context>
void print_parser(
template<typename Context, typename ParserMods>
void print_parser_impl(
Context const & context,
char_subrange_parser<control_subranges> const & parser,
char_subrange_parser<control_subranges, ParserMods> const & parser,
std::ostream & os,
int components = 0);
int components);
template<typename Context>
void print_parser(
template<typename Context, typename ParserMods>
void print_parser_impl(
Context const & context,
char_set_parser<punct_chars> const & parser,
char_set_parser<punct_chars, ParserMods> const & parser,
std::ostream & os,
int components = 0);
int components);
template<typename Context>
void print_parser(
template<typename Context, typename ParserMods>
void print_parser_impl(
Context const & context,
char_set_parser<symb_chars> const & parser,
char_set_parser<lower_case_chars, ParserMods> const & parser,
std::ostream & os,
int components = 0);
int components);
template<typename Context>
void print_parser(
template<typename Context, typename ParserMods>
void print_parser_impl(
Context const & context,
char_set_parser<lower_case_chars> const & parser,
char_set_parser<upper_case_chars, ParserMods> const & parser,
std::ostream & os,
int components = 0);
int components);
template<typename Context>
void print_parser(
template<
typename Context,
typename StrIter,
typename StrSentinel,
typename ParserMods>
void print_parser_impl(
Context const & context,
char_set_parser<upper_case_chars> const & parser,
string_parser<StrIter, StrSentinel, ParserMods> const & parser,
std::ostream & os,
int components = 0);
template<typename Context, typename Expected, typename AttributeType>
void print_parser(
Context const & context,
omit_parser<char_parser<Expected, AttributeType>> const & parser,
std::ostream & os,
int components = 0);
template<typename Context, typename StrIter, typename StrSentinel>
void print_parser(
Context const & context,
string_parser<StrIter, StrSentinel> const & parser,
std::ostream & os,
int components = 0);
template<typename Context, typename StrIter, typename StrSentinel>
void print_parser(
Context const & context,
omit_parser<string_parser<StrIter, StrSentinel>> const & parser,
std::ostream & os,
int components = 0);
int components);
template<
typename Context,
typename Quotes,
typename Escapes,
typename CharParser>
void print_parser(
typename ParserMods>
void print_parser_impl(
Context const & context,
quoted_string_parser<Quotes, Escapes, CharParser> const & parser,
quoted_string_parser<Quotes, Escapes, ParserMods> const & parser,
std::ostream & os,
int components = 0);
int components);
template<typename Context, bool NewlinesOnly, bool NoNewlines>
void print_parser(
template<
typename Context,
bool NewlinesOnly,
bool NoNewlines,
typename ParserMods>
void print_parser_impl(
Context const & context,
ws_parser<NewlinesOnly, NoNewlines> const & parser,
ws_parser<NewlinesOnly, NoNewlines, ParserMods> const & parser,
std::ostream & os,
int components = 0);
int components);
template<typename Context>
void print_parser(
template<typename Context, typename ParserMods>
void print_parser_impl(
Context const & context,
bool_parser const & parser,
bool_parser<ParserMods> const & parser,
std::ostream & os,
int components = 0);
int components);
template<
typename Context,
@@ -318,12 +319,19 @@ namespace boost { namespace parser { namespace detail {
int Radix,
int MinDigits,
int MaxDigits,
typename Expected>
void print_parser(
typename Expected,
typename ParserMods>
void print_parser_impl(
Context const & context,
uint_parser<T, Radix, MinDigits, MaxDigits, Expected> const & parser,
uint_parser<
T,
Radix,
MinDigits,
MaxDigits,
Expected,
ParserMods> const & parser,
std::ostream & os,
int components = 0);
int components);
template<
typename Context,
@@ -331,38 +339,51 @@ namespace boost { namespace parser { namespace detail {
int Radix,
int MinDigits,
int MaxDigits,
typename Expected>
void print_parser(
typename Expected,
typename ParserMods>
void print_parser_impl(
Context const & context,
int_parser<T, Radix, MinDigits, MaxDigits, Expected> const & parser,
int_parser<T, Radix, MinDigits, MaxDigits, Expected, ParserMods> const &
parser,
std::ostream & os,
int components = 0);
int components);
template<typename Context, typename T>
void print_parser(
template<typename Context, typename T, typename ParserMods>
void print_parser_impl(
Context const & context,
float_parser<T> const & parser,
float_parser<T, ParserMods> const & parser,
std::ostream & os,
int components = 0);
int components);
template<typename Context>
void print_parser(
template<typename Context, typename ParserMods>
void print_parser_impl(
Context const & context,
float_parser<float> const & parser,
float_parser<float, ParserMods> const & parser,
std::ostream & os,
int components = 0);
int components);
template<typename Context>
void print_parser(
template<typename Context, typename ParserMods>
void print_parser_impl(
Context const & context,
float_parser<double> const & parser,
float_parser<double, ParserMods> const & parser,
std::ostream & os,
int components = 0);
int components);
template<typename Context, typename SwitchValue, typename OrParser>
template<
typename Context,
typename SwitchValue,
typename OrParser,
typename ParserMods>
void print_parser_impl(
Context const & context,
switch_parser<SwitchValue, OrParser, ParserMods> const & parser,
std::ostream & os,
int components);
template<bool SuppressOmit = false, typename Context, typename Parser>
void print_parser(
Context const & context,
switch_parser<SwitchValue, OrParser> const & parser,
Parser const & parser,
std::ostream & os,
int components = 0);

File diff suppressed because it is too large Load Diff

View File

@@ -24,9 +24,8 @@
#define BOOST_PARSER_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE 0
#endif
#if !BOOST_PARSER_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE && \
BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS && \
defined(BOOST_PARSER_GCC) && 12 <= __GNUC__
#if !BOOST_PARSER_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE && \
BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS && defined(__GNUC__) && 12 <= __GNUC__
#define BOOST_PARSER_USE_LIBSTDCPP_GCC12_RANGE_ADAPTOR_CLOSURE 1
#else
#define BOOST_PARSER_USE_LIBSTDCPP_GCC12_RANGE_ADAPTOR_CLOSURE 0

View File

@@ -42,8 +42,7 @@ namespace boost::parser::detail::text::detail {
template<typename R>
constexpr bool view =
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS || \
(defined(__cpp_lib_concepts) && \
(!defined(BOOST_PARSER_GCC) || 12 <= __GNUC__))
(defined(__cpp_lib_concepts) && (!defined(__GNUC__) || 12 <= __GNUC__))
std::ranges::view<R>
#else
range_<R> && !container_<R> &&

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -143,14 +143,41 @@ namespace boost { namespace parser {
struct punct_chars
{};
struct symb_chars
{};
struct lower_case_chars
{};
struct upper_case_chars
{};
}
enum struct omit_attr_t { no, yes };
enum struct ignore_case_t { no, yes };
enum struct expect_match_t { no, yes };
template<typename Parser, expect_match_t ExpectMatch>
struct expected_parser
{
static constexpr expect_match_t expect_match = ExpectMatch;
Parser parser;
};
template<
omit_attr_t OmitAttr = omit_attr_t::no,
ignore_case_t IgnoreCase = ignore_case_t::no,
typename PreParser = detail::nope,
typename PostParser = detail::nope>
struct parser_modifiers
{
using pre_parser_type = PreParser;
using post_parser_type = PostParser;
static constexpr omit_attr_t omit_attr = OmitAttr;
static constexpr ignore_case_t ignore_case = IgnoreCase;
[[no_unique_address]] PreParser pre_parser;
[[no_unique_address]] PostParser post_parser;
};
/** Repeats the application of another parser `p` of type `Parser`,
optionally applying another parser `d` of type `DelimiterParser` in
between each pair of applications of `p`. The parse succeeds if `p`
@@ -161,20 +188,21 @@ namespace boost { namespace parser {
typename Parser,
typename DelimiterParser = detail::nope,
typename MinType = int64_t,
typename MaxType = int64_t>
typename MaxType = int64_t,
typename ParserMods = parser_modifiers<>>
struct repeat_parser;
/** Repeats the application of another parser `p` of type `Parser`, `[0,
Inf)` times. The parse always succeeds. The attribute produced is a
sequence of the type of attribute produced by `Parser`. */
template<typename Parser>
template<typename Parser, typename ParserMods>
struct zero_plus_parser;
/** Repeats the application of another parser `p` of type `Parser`, `[1,
Inf)` times. The parse succeeds iff `p` succeeds at least once. The
attribute produced is a sequence of the type of attribute produced by
`Parser`. */
template<typename Parser>
template<typename Parser, typename ParserMods>
struct one_plus_parser;
/** Repeats the application of another parser `p` of type `Parser`, `[1,
@@ -183,14 +211,14 @@ namespace boost { namespace parser {
succeeds at least once, and `d` succeeds each time it is applied. The
attribute produced is a sequence of the type of attribute produced by
`Parser`. */
template<typename Parser, typename DelimiterParser>
template<typename Parser, typename DelimiterParser, typename ParserMods>
struct delimited_seq_parser;
/** Repeats the application of another parser of type `Parser`, `[0, 1]`
times. The parse always succeeds. The attribute produced is a
`std::optional<T>`, where `T` is the type of attribute produced by
`Parser`. */
template<typename Parser>
template<typename Parser, typename ParserMods>
struct opt_parser;
/** Applies each parser in `ParserTuple`, in order, stopping after the
@@ -198,7 +226,7 @@ namespace boost { namespace parser {
one of the sub-parsers succeeds. The attribute produced is a
`std::variant` over the types of attribute produced by the parsers in
`ParserTuple`. */
template<typename ParserTuple>
template<typename ParserTuple, typename ParserMods>
struct or_parser;
/** Applies each parsers in `ParserTuple`, an any order, stopping after
@@ -209,7 +237,7 @@ namespace boost { namespace parser {
`ParserTuple`, not the order of the parsers' matches. It is an error
to specialize `perm_parser` with a `ParserTuple` template parameter
that includes an `eps_parser`. */
template<typename ParserTuple, typename DelimiterParser>
template<typename ParserTuple, typename ParserMods>
struct perm_parser;
/** Applies each parser in `ParserTuple`, in order. The parse succeeds
@@ -222,14 +250,15 @@ namespace boost { namespace parser {
template<
typename ParserTuple,
typename BacktrackingTuple,
typename CombiningGroups>
typename CombiningGroups,
typename ParserMods>
struct seq_parser;
/** Applies the given parser `p` of type `Parser` and an invocable `a` of
type `Action`. `Action` shall model `semantic_action`, and `a` will
only be invoked if `p` succeeds. The parse succeeds iff `p` succeeds.
Produces no attribute. */
template<typename Parser, typename Action>
template<typename Parser, typename Action, typename ParserMods>
struct action_parser;
/** Applies the given parser `p` of type `Parser`. The attribute produced
@@ -237,21 +266,14 @@ namespace boost { namespace parser {
only be invoked if `p` succeeds and sttributes are currently being
generated. The parse succeeds iff `p` succeeds. The attribute
produced is the the result of the call to `f`. */
template<typename Parser, typename F>
template<typename Parser, typename F, typename ParserMods>
struct transform_parser;
/** Applies the given parser `p` of type `Parser`. This parser produces
no attribute, and suppresses the production of any attributes that
would otherwise be produced by `p`. The parse succeeds iff `p`
succeeds. */
template<typename Parser>
struct omit_parser;
/** Applies the given parser `p` of type `Parser`; regardless of the
attribute produced by `Parser`, this parser's attribute is equivalent
to `_where(ctx)` within a semantic action on `p`. The parse succeeds
iff `p` succeeds. */
template<typename Parser>
template<typename Parser, typename ParserMods>
struct raw_parser;
#if defined(BOOST_PARSER_DOXYGEN) || BOOST_PARSER_USE_CONCEPTS
@@ -264,34 +286,30 @@ namespace boost { namespace parser {
non-contiguous, code using `string_view_parser` is ill-formed. The
parse succeeds iff `p` succeeds. This parser is only available in
C++20 and later. */
template<typename Parser>
template<typename Parser, typename ParserMods>
struct string_view_parser;
#endif
/** Applies the given parser `p` of type `Parser`, disabling the current
skipper in use, if any. The parse succeeds iff `p` succeeds. The
attribute produced is the type of attribute produced by `Parser`. */
template<typename Parser>
template<typename Parser, typename ParserMods>
struct lexeme_parser;
/** Applies the given parser `p` of type `Parser`, enabling
case-insensitive matching, based on Unicode case folding. The parse
succeeds iff `p` succeeds. The attribute produced is the type of
attribute produced by `Parser`. */
template<typename Parser>
struct no_case_parser;
/** Applies the given parser `p` of type `Parser`, using a parser of type
`SkipParser` as the skipper. The parse succeeds iff `p` succeeds.
The attribute produced is the type of attribute produced by
`Parser`. */
template<typename Parser, typename SkipParser = detail::nope>
template<
typename Parser,
typename SkipParser = detail::nope,
typename ParserMods = parser_modifiers<>>
struct skip_parser;
/** Applies the given parser `p` of type `Parser`, producing no attributes
and consuming no input. The parse succeeds iff `p`'s success is
unequal to `FailOnMatch`. */
template<typename Parser, bool FailOnMatch>
and consuming no input. The parse succeeds iff `p`'s success is equal
to `ExpectMatch == expect_match_t::yes`. */
template<typename Parser, expect_match_t ExpectMatch, typename ParserMods>
struct expect_parser;
/** Matches one of a set S of possible inputs, each of which is associated
@@ -300,7 +318,7 @@ namespace boost { namespace parser {
from S dynamically, during parsing; any such changes are reverted at
the end of parsing. The parse succeeds iff an element of S is
matched. \see `symbols` */
template<typename T>
template<typename T, typename ParserMods>
struct symbol_parser;
/** Applies another parser `p`, associated with this parser via `TagType`.
@@ -319,22 +337,24 @@ namespace boost { namespace parser {
typename TagType,
typename Attribute,
typename LocalState,
typename ParamsTuple>
typename ParamsTuple,
typename ParserMods>
struct rule_parser;
/** Matches anything, and consumes no input. If `Predicate` is anything
other than `detail::nope` (which it is by default), and `pred_(ctx)`
evaluates to false, where `ctx` is the parser context, the parse
fails. */
template<typename Predicate>
template<typename Predicate, typename ParserMods>
struct eps_parser;
/** Matches only the end of input. Produces no attribute. */
template<typename ParserMods>
struct eoi_parser;
/** Matches anything, consumes no input, and produces an attribute of type
`RESOLVE(Attribute)`. */
template<typename Attribute>
template<typename Attribute, typename ParserMods>
struct attr_parser;
/** A tag type that can be passed as the first parameter to `char_()` when
@@ -351,7 +371,10 @@ namespace boost { namespace parser {
parse fails only if the parser is constructed with a specific set of
expected code point values that does not include the matched code
point. */
template<typename Expected, typename AttributeType = void>
template<
typename Expected,
typename AttributeType = void,
typename ParserMods = parser_modifiers<>>
struct char_parser;
/** Matches a single code point that is equal to one of the code points
@@ -359,7 +382,7 @@ namespace boost { namespace parser {
characters for matching Unicode character classes like punctuation or
lower case. Attribute type is the attribute type of the character
being matched. */
template<typename Tag>
template<typename Tag, typename ParserMods>
struct char_set_parser;
/** Matches a single code point that falls into one of the subranges of
@@ -367,17 +390,18 @@ namespace boost { namespace parser {
sets of characters for matching Unicode character classes like hex
digits or control characters. Attribute type is the attribute type of
the character being matched. */
template<typename Tag>
template<typename Tag, typename ParserMods>
struct char_subrange_parser;
/** Matches a single decimal digit code point, using the Unicode character
class Hex_Digit. Attribute type is the attribute type of the
character being matched. */
template<typename ParserMods>
struct digit_parser;
/** Matches a particular string, delimited by an iterator sentinel pair;
produces no attribute. */
template<typename StrIter, typename StrSentinel>
template<typename StrIter, typename StrSentinel, typename ParserMods>
struct string_parser;
/** Matches a string delimited by quotation marks; produces a
@@ -385,7 +409,7 @@ namespace boost { namespace parser {
template<
typename Quotes = detail::nope,
typename Escapes = detail::nope,
typename CharParser = char_parser<detail::nope>>
typename ParserMods = parser_modifiers<>>
struct quoted_string_parser;
/** Matches an end-of-line (`NewlinesOnly == true`), whitespace
@@ -393,11 +417,12 @@ namespace boost { namespace parser {
but not newline) code point, based on the Unicode definitions of each
(also matches the two code points `"\r\n"`). Produces no
attribute. */
template<bool NewlinesOnly, bool NoNewlines>
template<bool NewlinesOnly, bool NoNewlines, typename ParserMods>
struct ws_parser;
/** Matches the strings "true" and "false", producing an attribute of
`true` or `false`, respectively, and fails on any other input. */
template<typename ParserMods>
struct bool_parser;
/** Matches an unsigned number of radix `Radix`, of at least `MinDigits`
@@ -411,7 +436,8 @@ namespace boost { namespace parser {
int Radix = 10,
int MinDigits = 1,
int MaxDigits = -1,
typename Expected = detail::nope>
typename Expected = detail::nope,
typename ParserMods = parser_modifiers<>>
struct uint_parser;
/** Matches a signed number of radix `Radix`, of at least `MinDigits` and
@@ -425,12 +451,13 @@ namespace boost { namespace parser {
int Radix = 10,
int MinDigits = 1,
int MaxDigits = -1,
typename Expected = detail::nope>
typename Expected = detail::nope,
typename ParserMods = parser_modifiers<>>
struct int_parser;
/** Matches a floating point number, producing an attribute of type
`T`. */
template<typename T>
template<typename T, typename ParserMods>
struct float_parser;
/** Applies at most one of the parsers in `OrParser`. If `switch_value_`
@@ -438,7 +465,10 @@ namespace boost { namespace parser {
first such parser is applied, and the success or failure and attribute
of the parse are those of the applied parser. Otherwise, the parse
fails. */
template<typename SwitchValue, typename OrParser = detail::nope>
template<
typename SwitchValue,
typename OrParser = detail::nope,
typename ParserMods = parser_modifiers<>>
struct switch_parser;
/** A wrapper for parsers that provides the operations that must be

View File

@@ -451,7 +451,7 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
parser_interface<eps_parser<detail::phony>>>;
parser_interface<eps_parser<detail::phony, parser_modifiers<>>>>;
template<
typename V,
@@ -469,7 +469,7 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
parser_interface<eps_parser<detail::phony>>>;
parser_interface<eps_parser<detail::phony, parser_modifiers<>>>>;
namespace detail {
template<
@@ -571,7 +571,8 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
parser_interface<eps_parser<detail::phony>>>
parser_interface<
eps_parser<detail::phony, parser_modifiers<>>>>
[[nodiscard]] constexpr auto operator()(
R && r,
parser_interface<Parser, GlobalState, ErrorHandler> const &
@@ -582,7 +583,8 @@ namespace boost::parser {
return (*this)(
(R &&)r,
parser,
parser_interface<eps_parser<detail::phony>>{},
parser_interface<
eps_parser<detail::phony, parser_modifiers<>>>{},
(ReplacementR &&)replacement,
trace_mode);
}
@@ -623,10 +625,11 @@ namespace boost::parser {
std::is_same_v<Trace, trace>) {
// (r, parser, replacement, trace) case
return impl(
(R &&) r,
(R &&)r,
parser,
parser_interface<eps_parser<detail::phony>>{},
(SkipParser &&) skip,
parser_interface<
eps_parser<detail::phony, parser_modifiers<>>>{},
(SkipParser &&)skip,
replacement);
} else {
static_assert(

View File

@@ -116,7 +116,9 @@ namespace boost::parser {
return BOOST_PARSER_SUBRANGE(first, first);
auto const search_parser = omit[*(char_ - parser)] >> -raw[parser];
if constexpr (std::is_same_v<SkipParser, eps_parser<phony>>) {
if constexpr (std::is_same_v<
SkipParser,
eps_parser<phony, parser_modifiers<>>>) {
auto result = parser::prefix_parse(
first, last, search_parser, trace_mode);
if (*result)
@@ -255,9 +257,9 @@ namespace boost::parser {
trace trace_mode = trace::off)
{
return parser::search(
(R &&) r,
(R &&)r,
parser,
parser_interface<eps_parser<detail::phony>>{},
parser_interface<eps_parser<detail::phony, parser_modifiers<>>>{},
trace_mode);
}
@@ -292,7 +294,7 @@ namespace boost::parser {
return parser::search(
BOOST_PARSER_SUBRANGE(first, last),
parser,
parser_interface<eps_parser<detail::phony>>{},
parser_interface<eps_parser<detail::phony, parser_modifiers<>>>{},
trace_mode);
}
@@ -483,7 +485,7 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
parser_interface<eps_parser<detail::phony>>>;
parser_interface<eps_parser<detail::phony, parser_modifiers<>>>>;
template<
typename V,
@@ -496,7 +498,7 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
parser_interface<eps_parser<detail::phony>>>;
parser_interface<eps_parser<detail::phony, parser_modifiers<>>>>;
namespace detail {
template<
@@ -569,7 +571,8 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
parser_interface<eps_parser<detail::phony>>>
parser_interface<
eps_parser<detail::phony, parser_modifiers<>>>>
[[nodiscard]] constexpr auto operator()(
R && r,
parser_interface<Parser, GlobalState, ErrorHandler> const &
@@ -579,7 +582,8 @@ namespace boost::parser {
return (*this)(
(R &&)r,
parser,
parser_interface<eps_parser<detail::phony>>{},
parser_interface<
eps_parser<detail::phony, parser_modifiers<>>>{},
trace_mode);
}
@@ -590,8 +594,8 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
typename SkipParser =
parser_interface<eps_parser<detail::phony>>,
typename SkipParser = parser_interface<
eps_parser<detail::phony, parser_modifiers<>>>,
typename Trace = trace,
typename Enable = std::enable_if_t<is_parsable_range_v<R>>>
[[nodiscard]] constexpr auto operator()(
@@ -607,9 +611,10 @@ namespace boost::parser {
std::is_same_v<Trace, trace>) {
// (r, parser, trace) case
return impl(
(R &&) r,
(R &&)r,
parser,
parser_interface<eps_parser<detail::phony>>{},
parser_interface<
eps_parser<detail::phony, parser_modifiers<>>>{},
skip);
} else if constexpr (
detail::is_parser_iface<SkipParser> &&

View File

@@ -193,14 +193,13 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler>
split_view(
V &&, parser_interface<Parser, GlobalState, ErrorHandler>, trace)
split_view(V &&, parser_interface<Parser, GlobalState, ErrorHandler>, trace)
-> split_view<
detail::text::detail::all_t<V>,
Parser,
GlobalState,
ErrorHandler,
parser_interface<eps_parser<detail::phony>>>;
parser_interface<eps_parser<detail::phony, parser_modifiers<>>>>;
template<
typename V,
@@ -213,7 +212,7 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
parser_interface<eps_parser<detail::phony>>>;
parser_interface<eps_parser<detail::phony, parser_modifiers<>>>>;
namespace detail {
template<
@@ -286,7 +285,8 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
parser_interface<eps_parser<detail::phony>>>
parser_interface<
eps_parser<detail::phony, parser_modifiers<>>>>
[[nodiscard]] constexpr auto operator()(
R && r,
parser_interface<Parser, GlobalState, ErrorHandler> const &
@@ -296,7 +296,8 @@ namespace boost::parser {
return (*this)(
(R &&)r,
parser,
parser_interface<eps_parser<detail::phony>>{},
parser_interface<
eps_parser<detail::phony, parser_modifiers<>>>{},
trace_mode);
}
@@ -307,8 +308,8 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
typename SkipParser =
parser_interface<eps_parser<detail::phony>>,
typename SkipParser = parser_interface<
eps_parser<detail::phony, parser_modifiers<>>>,
typename Trace = trace,
typename Enable = std::enable_if_t<is_parsable_range_v<R>>>
[[nodiscard]] constexpr auto operator()(
@@ -324,9 +325,10 @@ namespace boost::parser {
std::is_same_v<Trace, trace>) {
// (r, parser, trace) case
return impl(
(R &&) r,
(R &&)r,
parser,
parser_interface<eps_parser<detail::phony>>{},
parser_interface<
eps_parser<detail::phony, parser_modifiers<>>>{},
skip);
} else if constexpr (
detail::is_parser_iface<SkipParser> &&

View File

@@ -4,8 +4,7 @@
#include <boost/parser/replace.hpp>
#if (!defined(_MSC_VER) || BOOST_PARSER_USE_CONCEPTS) && \
(!defined(BOOST_PARSER_GCC) || 12 <= __GNUC__ || \
!BOOST_PARSER_USE_CONCEPTS)
(!defined(__GNUC__) || 12 <= __GNUC__ || !BOOST_PARSER_USE_CONCEPTS)
namespace boost::parser {
@@ -255,7 +254,9 @@ namespace boost::parser {
BOOST_PARSER_SUBRANGE(first, first), parse_result{});
}
if constexpr (std::is_same_v<SkipParser, eps_parser<phony>>) {
if constexpr (std::is_same_v<
SkipParser,
eps_parser<phony, parser_modifiers<>>>) {
auto result = parser::prefix_parse(
first, last, search_parser, trace_mode);
if (*result) {
@@ -579,7 +580,7 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
parser_interface<eps_parser<detail::phony>>>;
parser_interface<eps_parser<detail::phony, parser_modifiers<>>>>;
template<
typename V,
@@ -595,7 +596,7 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
parser_interface<eps_parser<detail::phony>>>;
parser_interface<eps_parser<detail::phony, parser_modifiers<>>>>;
namespace detail {
template<
@@ -698,7 +699,8 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
parser_interface<eps_parser<detail::phony>>>
parser_interface<
eps_parser<detail::phony, parser_modifiers<>>>>
[[nodiscard]] constexpr auto operator()(
R && r,
parser_interface<Parser, GlobalState, ErrorHandler> const &
@@ -709,7 +711,8 @@ namespace boost::parser {
return (*this)(
(R &&)r,
parser,
parser_interface<eps_parser<detail::phony>>{},
parser_interface<
eps_parser<detail::phony, parser_modifiers<>>>{},
(F &&)f,
trace_mode);
}
@@ -754,10 +757,11 @@ namespace boost::parser {
std::is_same_v<Trace, trace>) {
// (r, parser, f, trace) case
return impl(
to_range<R>::call((R &&) r),
to_range<R>::call((R &&)r),
parser,
parser_interface<eps_parser<detail::phony>>{},
(SkipParser &&) skip,
parser_interface<
eps_parser<detail::phony, parser_modifiers<>>>{},
(SkipParser &&)skip,
f);
} else {
static_assert(

View File

@@ -128,7 +128,7 @@ namespace boost { namespace parser {
/** A literal that can be used to concisely name `parser::llong`
integral constants. */
template<char... chars>
constexpr auto operator""_c()
constexpr auto operator"" _c()
{
constexpr long long n =
detail::parse_llong<sizeof...(chars)>({chars...});
@@ -185,10 +185,14 @@ namespace boost { namespace parser {
template<typename T>
operator T() const && noexcept
{
#if defined(__GNUC__) && __GNUC__ < 13
// Yuck.
std::remove_reference_t<T> * ptr = nullptr;
ptr += 1; // warning mitigation
return *ptr;
#else
return std::declval<T>();
#endif
}
};

View File

@@ -237,27 +237,6 @@ void github_issue_125()
}
}
void github_issue_209()
{
namespace bp = boost::parser;
BOOST_TEST(std::is_sorted(
std::begin(bp::detail::char_set<detail::punct_chars>::chars),
std::end(bp::detail::char_set<detail::punct_chars>::chars)));
BOOST_TEST(std::is_sorted(
std::begin(bp::detail::char_set<detail::symb_chars>::chars),
std::end(bp::detail::char_set<detail::symb_chars>::chars)));
BOOST_TEST(std::is_sorted(
std::begin(bp::detail::char_set<detail::lower_case_chars>::chars),
std::end(bp::detail::char_set<detail::lower_case_chars>::chars)));
BOOST_TEST(std::is_sorted(
std::begin(bp::detail::char_set<detail::upper_case_chars>::chars),
std::end(bp::detail::char_set<detail::upper_case_chars>::chars)));
}
int main()
{
@@ -267,6 +246,5 @@ int main()
github_issue_78();
github_issue_90();
github_issue_125();
github_issue_209();
return boost::report_errors();
}

View File

@@ -39,7 +39,7 @@ constexpr auto double_s = u8"sS"; // U+0073 U+0073
// basic)
{
constexpr auto char_p = no_case[char_('a') | char_('B')];
auto char_p = no_case[char_('a') | char_('B')];
{
auto const result = parse("a", char_p);
@@ -461,12 +461,12 @@ constexpr auto double_s = u8"sS"; // U+0073 U+0073
{
constexpr auto mixed_sharp_s1 = U"ẞs";
constexpr auto mixed_sharp_s2 = U"sẞ";
auto const result = detail::no_case_aware_string_mismatch(
mixed_sharp_s1,
detail::text::null_sentinel,
mixed_sharp_s2,
detail::text::null_sentinel,
true);
auto const result =
detail::no_case_aware_string_mismatch<ignore_case_t::yes>(
mixed_sharp_s1,
detail::text::null_sentinel,
mixed_sharp_s2,
detail::text::null_sentinel);
BOOST_TEST(result.first == detail::text::null_sentinel);
BOOST_TEST(result.second == detail::text::null_sentinel);
}

View File

@@ -2753,16 +2753,6 @@ int main()
BOOST_TEST(result == std::vector<uint32_t>({0x21, 0xfda}));
}
// symb_
{
auto parser = +symb;
std::u32string str = U"$^\u20AC!\u2194\u220F\U0001D7C6b\u2280\U0001FACE\U0001039F";
std::vector<uint32_t> result;
BOOST_TEST(parse(str, parser, char_ - symb, result));
BOOST_TEST(result == std::vector<uint32_t>({U'$', U'^', 0x20AC, 0x2194, 0x220F, 0x2280, 0x1FACE}));
}
// lower_
{
auto parser = +lower;

View File

@@ -88,66 +88,5 @@ int main()
}
}
{
using namespace bp::literals;
constexpr auto parser =
bp::delimiter(','_l)[bp::int_ || bp::string("foo") || bp::char_('g')];
{
auto result = bp::parse("42 foo g", parser, bp::ws);
BOOST_TEST(!result);
result = bp::parse("42, foo ,g", parser, bp::ws);
BOOST_TEST(result);
BOOST_TEST(
*result ==
(bp::tuple<int, std::string, double>(42, "foo"s, 'g')));
}
{
auto result = bp::parse(",42, g, foo", parser, bp::ws);
BOOST_TEST(!result);
result = bp::parse("42, g , foo", parser, bp::ws);
BOOST_TEST(result);
BOOST_TEST(
*result ==
(bp::tuple<int, std::string, double>(42, "foo"s, 'g')));
}
{
auto result = bp::parse("foo, 42, g,", parser, bp::ws);
BOOST_TEST(!result);
result = bp::parse("foo, 42, g", parser, bp::ws);
BOOST_TEST(result);
BOOST_TEST(
*result ==
(bp::tuple<int, std::string, double>(42, "foo"s, 'g')));
}
{
auto result = bp::parse("foo g 42", parser, bp::ws);
BOOST_TEST(!result);
result = bp::parse("foo, g, 42", parser, bp::ws);
BOOST_TEST(result);
BOOST_TEST(
*result ==
(bp::tuple<int, std::string, double>(42, "foo"s, 'g')));
}
{
auto result = bp::parse("g foo 42", parser, bp::ws);
BOOST_TEST(!result);
result = bp::parse("g ,foo ,42", parser, bp::ws);
BOOST_TEST(result);
BOOST_TEST(
*result ==
(bp::tuple<int, std::string, double>(42, "foo"s, 'g')));
}
{
auto result = bp::parse("g 42 foo", parser, bp::ws);
BOOST_TEST(!result);
result = bp::parse("g , 42 , foo", parser, bp::ws);
BOOST_TEST(result);
BOOST_TEST(
*result ==
(bp::tuple<int, std::string, double>(42, "foo"s, 'g')));
}
}
return boost::report_errors();
return boost::report_errors();
}

View File

@@ -49,7 +49,7 @@ int main()
}
}
// different_quote
// different_char
{
constexpr auto parser = bp::quoted_string('\'');
@@ -75,18 +75,9 @@ int main()
BOOST_TEST(result);
BOOST_TEST(*result == "'foo'");
}
{
constexpr auto parser = bp::quoted_string('\'', bp::char_("g\t"));
auto result = bp::parse(R"('\'ggg\'')", parser, bp::ws);
BOOST_TEST(result);
BOOST_TEST(*result == "'ggg'");
BOOST_TEST(!bp::parse(R"('\'fff\'')", parser, bp::ws));
}
}
// different_quote_with_escapes
// different_char_with_escapes
{
{
auto parser = bp::quoted_string('\'', cu_escapes);
@@ -128,58 +119,6 @@ int main()
}
}
// different_quote_with_escapes_and_char_p
{
{
auto parser = bp::quoted_string('\'', cu_escapes, bp::char_("g\t"));
{
auto result = bp::parse("", parser, bp::ws);
BOOST_TEST(!result);
}
{
auto result = bp::parse("'ggg'", parser, bp::ws);
BOOST_TEST(result);
}
{
auto result = bp::parse("'fff'", parser, bp::ws);
BOOST_TEST(!result);
}
{
auto result = bp::parse(R"('ggg\t')", parser, bp::ws);
BOOST_TEST(result);
BOOST_TEST(*result == "ggg\t");
}
{
auto result = bp::parse(R"('ggg\g')", parser, bp::ws);
BOOST_TEST(!result);
}
}
{
auto parser = bp::quoted_string('\'', cp_escapes);
{
auto result = bp::parse("", parser, bp::ws);
BOOST_TEST(!result);
}
{
auto result = bp::parse(R"('\tggg')", parser, bp::ws);
BOOST_TEST(result);
BOOST_TEST(*result == "\tggg");
}
{
auto result = bp::parse(R"('g\ggg')", parser, bp::ws);
BOOST_TEST(!result);
}
}
}
// char_set
{
constexpr auto parser = bp::quoted_string("'\"");
@@ -232,15 +171,6 @@ int main()
// character.
BOOST_TEST(!bp::parse(R"("\'foo")", parser, bp::ws));
}
{
constexpr auto parser = bp::quoted_string("'\"", bp::char_("g"));
auto result = bp::parse(R"('\'ggg\'')", parser, bp::ws);
BOOST_TEST(result);
BOOST_TEST(*result == "'ggg'");
BOOST_TEST(!bp::parse(R"('\'fff\'')", parser, bp::ws));
}
}
// char_set_with_escapes
@@ -303,15 +233,6 @@ int main()
BOOST_TEST(!result);
}
}
{
auto parser = bp::quoted_string("'\"", cu_escapes, bp::char_("g"));
auto result = bp::parse(R"('\'ggg\'')", parser, bp::ws);
BOOST_TEST(result);
BOOST_TEST(*result == "'ggg'");
BOOST_TEST(!bp::parse(R"('\'fff\'')", parser, bp::ws));
}
}
// doc_examples
@@ -358,16 +279,6 @@ int main()
assert(result5);
std::cout << *result5 << "\n"; // Prints (with a CRLF newline): some text
//]
//[ quoted_string_example_6
auto result6 = bp::parse(
"'some text'", bp::quoted_string("'\"", bp::char_('g')), bp::ws);
assert(!result6);
result6 =
bp::parse("'gggg'", bp::quoted_string("'\"", bp::char_('g')), bp::ws);
assert(result6);
std::cout << *result6 << "\n"; // Prints: gggg
//]
}
return boost::report_errors();

View File

@@ -144,7 +144,7 @@ int main()
std::cout << "\n\n"
<< "----------------------------------------\n"
<< "| transform)f_[] |\n"
<< "| transform(f)[] |\n"
<< "----------------------------------------\n";
auto f = [](auto x) { return x; };
@@ -156,6 +156,8 @@ int main()
<< "----------------------------------------\n";
PARSE(omit[char_]);
PARSE(omit[omit[char_]]);
PARSE(omit[*omit[char_]]);
std::cout << "\n\n"
<< "----------------------------------------\n"
@@ -188,6 +190,15 @@ int main()
PARSE(skip[char_]);
PARSE(skip(ws)[char_]);
std::cout << "\n\n"
<< "----------------------------------------\n"
<< "| no_case[] |\n"
<< "----------------------------------------\n";
PARSE(no_case[char_]);
PARSE(no_case[no_case[char_]]);
PARSE(no_case[*no_case[char_]]);
std::cout << "\n\n"
<< "----------------------------------------\n"
<< "| merge[] |\n"
@@ -218,6 +229,16 @@ int main()
PARSE(!char_);
PARSE(!(*char_ >> char_));
PARSE(!char_ >> char_);
PARSE(*char_ >> !char_);
PARSE(!char_ >> *char_ >> char_ >> !char_);
try {
PARSE((!char_) > char_);
} catch (...) {
}
PARSE(*char_ > !char_);
PARSE((!char_) > *char_ >> char_ > !char_);
std::cout << "\n\n"
<< "----------------------------------------\n"
<< "| operator& |\n"
@@ -226,6 +247,16 @@ int main()
PARSE(&char_);
PARSE(&(*char_ >> char_));
PARSE(&char_ >> char_);
PARSE(*char_ >> &char_);
PARSE(&char_ >> *char_ >> char_ >> &char_);
try {
PARSE(&char_ > char_);
} catch (...) {
}
PARSE(*char_ > &char_);
PARSE(&char_ >>*char_ >> char_ > &char_);
std::cout << "\n\n"
<< "----------------------------------------\n"
<< "| symbols<T> |\n"