2
0
mirror of https://github.com/boostorg/parser.git synced 2026-01-19 16:32:13 +00:00

12 Commits

Author SHA1 Message Date
Zach Laine
6414f99e04 Remove space from declaration of UDLs, because apparently it matters?!
Fixes #216.
2025-03-13 19:03:14 -05:00
Zach Laine
78bc141d5f Add doc example of unexpected combining sequence parsers.
Example is based on #215.
2025-03-01 16:34:22 -06:00
necessarily-equal
b253d9ca53 Add unicode symbols parser (#213)
* Add symb parser to handle unicode symbols

* Add documentation for symb

* Add tests for symb

* Fix typo in the documentation

---------

Contributed by: Antoine Fontaine <antoinefontaine@posteo.net>
2025-02-20 23:51:17 -06:00
Zach Laine
0a34acc42a Add new macro BOOST_PARSER_GCC that is defined in config.hpp only for real
(non-Clang-emulated) GCC builds; replace relevant uses of the __GNUC__ macro
with BOOST_PARSER_GCC.

See discussion in PR #211.
2025-02-20 23:38:09 -06:00
Zach Laine
56c81c0b57 Use gross pointer dereference expression to implement detail::whatever
converions operator, since 2/3 of the big three compilers reject the use of
declval() there.
2025-02-20 23:38:09 -06:00
Zach Laine
821d1d4c08 Fix longstanding mysterious ill-formedness in
detail::static_assert_merge_attributes.  It was down to unavailabilty of a
default ctor for certain parser types.
2025-02-20 23:38:09 -06:00
Zach Laine
57cdd78210 Properly sort the code point values in detail::char_set<punct_chars>.
Fixes #209.
2024-12-23 17:28:07 -06:00
Zach Laine
3993efb692 Update MacOS badges in README.md. 2024-12-20 20:02:44 -06:00
Zach Laine
74bc8fc1bb Add the delimiter(p)[] directive proper (missing from previous commit).
Fixes #162.
2024-12-20 20:01:16 -06:00
Zach Laine
b42b052df4 Add the delimiter(p)[] directive, whic allows you to introduce a delimiter
into the parse of a permutation parser.

Fixes #162.
2024-12-19 22:26:08 -06:00
Zach Laine
42c9d82419 Add an optional char parser to quoted_string_parser, so that it can be made
fully general.

Fixes #196.
2024-12-17 00:17:54 -06:00
Zach Laine
958ac38256 Note for the user that they must be aware of nonobvious C++ operator
precedence impact of expression evaluation.

Fixes #205.
2024-12-16 22:33:55 -06:00
24 changed files with 5140 additions and 3159 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-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)
[![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)
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-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)
[![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)
[![License](https://img.shields.io/badge/license-boost-brightgreen.svg)](LICENSE_1_0.txt)

View File

@@ -110,6 +110,7 @@
[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>`]
@@ -201,6 +202,7 @@
[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`]]
@@ -211,11 +213,13 @@
[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`]]
@@ -239,6 +243,7 @@
[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]]

2145
doc/parser_reference.xml Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -132,6 +132,11 @@ 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_. ]
@@ -385,10 +390,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. ]]
[[`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>`. ]]
[[`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. ]]
[[`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>>`. ]]
[[`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. ]]
@@ -424,6 +429,15 @@ 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 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 the advantage of 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,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]
@@ -1442,6 +1450,24 @@ _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]
@@ -1590,6 +1616,71 @@ 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
@@ -2211,6 +2302,8 @@ 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);
@@ -2351,6 +2444,10 @@ 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,6 +73,12 @@
#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,118 +52,110 @@ namespace boost { namespace parser { namespace detail {
typename Parser,
typename DelimiterParser,
typename MinType,
typename MaxType,
typename ParserMods>
void print_parser_impl(
typename MaxType>
void print_parser(
Context const & context,
repeat_parser<
Parser,
DelimiterParser,
MinType,
MaxType,
ParserMods> const & parser,
repeat_parser<Parser, DelimiterParser, MinType, MaxType> const & parser,
std::ostream & os,
int components);
int components = 0);
template<typename Context, typename Parser, typename ParserMods>
void print_parser_impl(
template<typename Context, typename Parser>
void print_parser(
Context const & context,
opt_parser<Parser, ParserMods> const & parser,
opt_parser<Parser> const & parser,
std::ostream & os,
int components);
int components = 0);
template<typename Context, typename ParserTuple, typename ParserMods>
void print_parser_impl(
template<typename Context, typename ParserTuple>
void print_parser(
Context const & context,
or_parser<ParserTuple, ParserMods> const & parser,
or_parser<ParserTuple> const & parser,
std::ostream & os,
int components);
int components = 0);
template<typename Context, typename ParserTuple, typename ParserMods>
void print_parser_impl(
template<typename Context, typename ParserTuple, typename DelimiterParser>
void print_parser(
Context const & context,
perm_parser<ParserTuple, ParserMods> const & parser,
perm_parser<ParserTuple, DelimiterParser> const & parser,
std::ostream & os,
int components);
int components = 0);
template<
typename Context,
typename ParserTuple,
typename BacktrackingTuple,
typename CombiningGroups,
typename ParserMods>
void print_parser_impl(
typename CombiningGroups>
void print_parser(
Context const & context,
seq_parser<
ParserTuple,
BacktrackingTuple,
CombiningGroups,
ParserMods> const & parser,
seq_parser<ParserTuple, BacktrackingTuple, CombiningGroups> const &
parser,
std::ostream & os,
int components);
int components = 0);
template<
typename Context,
typename Parser,
typename Action,
typename ParserMods>
void print_parser_impl(
template<typename Context, typename Parser, typename Action>
void print_parser(
Context const & context,
action_parser<Parser, Action, ParserMods> const & parser,
action_parser<Parser, Action> const & parser,
std::ostream & os,
int components);
int components = 0);
template<typename Context, typename Parser, typename F, typename ParserMods>
void print_parser_impl(
template<typename Context, typename Parser, typename F>
void print_parser(
Context const & context,
transform_parser<Parser, F, ParserMods> const & parser,
transform_parser<Parser, F> const & parser,
std::ostream & os,
int components);
int components = 0);
template<typename Context, typename Parser, typename ParserMods>
void print_parser_impl(
template<typename Context, typename Parser>
void print_parser(
Context const & context,
raw_parser<Parser, ParserMods> const & parser,
omit_parser<Parser> const & parser,
std::ostream & os,
int components);
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);
#if defined(BOOST_PARSER_DOXYGEN) || BOOST_PARSER_USE_CONCEPTS
template<typename Context, typename Parser, typename ParserMods>
void print_parser_impl(
template<typename Context, typename Parser>
void print_parser(
Context const & context,
string_view_parser<Parser, ParserMods> const & parser,
string_view_parser<Parser> const & parser,
std::ostream & os,
int components);
int components = 0);
#endif
template<typename Context, typename Parser, typename ParserMods>
void print_parser_impl(
template<typename Context, typename Parser>
void print_parser(
Context const & context,
lexeme_parser<Parser, ParserMods> const & parser,
lexeme_parser<Parser> const & parser,
std::ostream & os,
int components);
int components = 0);
template<
typename Context,
typename Parser,
typename SkipParser,
typename ParserMods>
void print_parser_impl(
template<typename Context, typename Parser>
void print_parser(
Context const & context,
skip_parser<Parser, SkipParser, ParserMods> const & parser,
no_case_parser<Parser> const & parser,
std::ostream & os,
int components);
int components = 0);
template<
typename Context,
typename Parser,
expect_match_t ExpectMatch,
typename ParserMods>
void print_parser_impl(
template<typename Context, typename Parser, typename SkipParser>
void print_parser(
Context const & context,
expect_parser<Parser, ExpectMatch, ParserMods> const & parser,
skip_parser<Parser, SkipParser> const & parser,
std::ostream & os,
int components);
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);
template<
typename Context,
@@ -171,219 +163,206 @@ namespace boost { namespace parser { namespace detail {
typename Parser,
typename Attribute,
typename LocalState,
typename ParamsTuple,
typename ParserMods>
void print_parser_impl(
typename ParamsTuple>
void print_parser(
Context const & context,
rule_parser<
UseCallbacks,
Parser,
Attribute,
LocalState,
ParamsTuple,
ParserMods> const & parser,
ParamsTuple> const & parser,
std::ostream & os,
int components);
int components = 0);
template<typename Context, typename T, typename ParserMods>
void print_parser_impl(
template<typename Context, typename T>
void print_parser(
Context const & context,
symbol_parser<T, ParserMods> const & parser,
symbol_parser<T> const & parser,
std::ostream & os,
int components);
int components = 0);
template<typename Context, typename Predicate, typename ParserMods>
void print_parser_impl(
template<typename Context, typename Predicate>
void print_parser(
Context const & context,
eps_parser<Predicate, ParserMods> const & parser,
eps_parser<Predicate> const & parser,
std::ostream & os,
int components);
int components = 0);
template<typename Context, typename ParserMods>
void print_parser_impl(
template<typename Context>
void print_parser(
Context const & context,
eps_parser<nope, ParserMods> const & parser,
eps_parser<nope> const & parser,
std::ostream & os,
int components);
int components = 0);
template<typename Context, typename ParserMods>
void print_parser_impl(
template<typename Context>
void print_parser(
Context const & context,
eoi_parser<ParserMods> const & parser,
eoi_parser const & parser,
std::ostream & os,
int components);
int components = 0);
template<typename Context, typename Atribute, typename ParserMods>
void print_parser_impl(
template<typename Context, typename Atribute>
void print_parser(
Context const & context,
attr_parser<Atribute, ParserMods> const & parser,
attr_parser<Atribute> const & parser,
std::ostream & os,
int components);
int components = 0);
template<
typename Context,
typename Expected,
typename AttributeType,
typename ParserMods>
void print_parser_impl(
template<typename Context, typename Expected, typename AttributeType>
void print_parser(
Context const & context,
char_parser<Expected, AttributeType, ParserMods> const & parser,
char_parser<Expected, AttributeType> const & parser,
std::ostream & os,
int components);
int components = 0);
template<typename Context, typename ParserMods>
void print_parser_impl(
template<typename Context>
void print_parser(
Context const & context,
digit_parser<ParserMods> const & parser,
digit_parser const & parser,
std::ostream & os,
int components);
int components = 0);
template<typename Context, typename ParserMods>
void print_parser_impl(
template<typename Context>
void print_parser(
Context const & context,
char_subrange_parser<hex_digit_subranges, ParserMods> const & parser,
char_subrange_parser<hex_digit_subranges> const & parser,
std::ostream & os,
int components);
int components = 0);
template<typename Context, typename ParserMods>
void print_parser_impl(
template<typename Context>
void print_parser(
Context const & context,
char_subrange_parser<control_subranges, ParserMods> const & parser,
char_subrange_parser<control_subranges> const & parser,
std::ostream & os,
int components);
int components = 0);
template<typename Context, typename ParserMods>
void print_parser_impl(
template<typename Context>
void print_parser(
Context const & context,
char_set_parser<punct_chars, ParserMods> const & parser,
char_set_parser<punct_chars> const & parser,
std::ostream & os,
int components);
int components = 0);
template<typename Context, typename ParserMods>
void print_parser_impl(
template<typename Context>
void print_parser(
Context const & context,
char_set_parser<lower_case_chars, ParserMods> const & parser,
char_set_parser<symb_chars> const & parser,
std::ostream & os,
int components);
int components = 0);
template<typename Context, typename ParserMods>
void print_parser_impl(
template<typename Context>
void print_parser(
Context const & context,
char_set_parser<upper_case_chars, ParserMods> const & parser,
char_set_parser<lower_case_chars> const & parser,
std::ostream & os,
int components);
int components = 0);
template<
typename Context,
typename StrIter,
typename StrSentinel,
typename ParserMods>
void print_parser_impl(
template<typename Context>
void print_parser(
Context const & context,
string_parser<StrIter, StrSentinel, ParserMods> const & parser,
char_set_parser<upper_case_chars> const & parser,
std::ostream & os,
int components);
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);
template<
typename Context,
typename Quotes,
typename Escapes,
typename ParserMods>
void print_parser_impl(
Context const & context,
quoted_string_parser<Quotes, Escapes, ParserMods> const & parser,
std::ostream & os,
int components);
template<
typename Context,
bool NewlinesOnly,
bool NoNewlines,
typename ParserMods>
void print_parser_impl(
Context const & context,
ws_parser<NewlinesOnly, NoNewlines, ParserMods> const & parser,
std::ostream & os,
int components);
template<typename Context, typename ParserMods>
void print_parser_impl(
Context const & context,
bool_parser<ParserMods> const & parser,
std::ostream & os,
int components);
template<
typename Context,
typename T,
int Radix,
int MinDigits,
int MaxDigits,
typename Expected,
typename ParserMods>
void print_parser_impl(
Context const & context,
uint_parser<
T,
Radix,
MinDigits,
MaxDigits,
Expected,
ParserMods> const & parser,
std::ostream & os,
int components);
template<
typename Context,
typename T,
int Radix,
int MinDigits,
int MaxDigits,
typename Expected,
typename ParserMods>
void print_parser_impl(
Context const & context,
int_parser<T, Radix, MinDigits, MaxDigits, Expected, ParserMods> const &
parser,
std::ostream & os,
int components);
template<typename Context, typename T, typename ParserMods>
void print_parser_impl(
Context const & context,
float_parser<T, ParserMods> const & parser,
std::ostream & os,
int components);
template<typename Context, typename ParserMods>
void print_parser_impl(
Context const & context,
float_parser<float, ParserMods> const & parser,
std::ostream & os,
int components);
template<typename Context, typename ParserMods>
void print_parser_impl(
Context const & context,
float_parser<double, ParserMods> const & parser,
std::ostream & os,
int components);
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>
typename CharParser>
void print_parser(
Context const & context,
Parser const & parser,
quoted_string_parser<Quotes, Escapes, CharParser> const & parser,
std::ostream & os,
int components = 0);
template<typename Context, bool NewlinesOnly, bool NoNewlines>
void print_parser(
Context const & context,
ws_parser<NewlinesOnly, NoNewlines> const & parser,
std::ostream & os,
int components = 0);
template<typename Context>
void print_parser(
Context const & context,
bool_parser const & parser,
std::ostream & os,
int components = 0);
template<
typename Context,
typename T,
int Radix,
int MinDigits,
int MaxDigits,
typename Expected>
void print_parser(
Context const & context,
uint_parser<T, Radix, MinDigits, MaxDigits, Expected> const & parser,
std::ostream & os,
int components = 0);
template<
typename Context,
typename T,
int Radix,
int MinDigits,
int MaxDigits,
typename Expected>
void print_parser(
Context const & context,
int_parser<T, Radix, MinDigits, MaxDigits, Expected> const & parser,
std::ostream & os,
int components = 0);
template<typename Context, typename T>
void print_parser(
Context const & context,
float_parser<T> const & parser,
std::ostream & os,
int components = 0);
template<typename Context>
void print_parser(
Context const & context,
float_parser<float> const & parser,
std::ostream & os,
int components = 0);
template<typename Context>
void print_parser(
Context const & context,
float_parser<double> const & parser,
std::ostream & os,
int components = 0);
template<typename Context, typename SwitchValue, typename OrParser>
void print_parser(
Context const & context,
switch_parser<SwitchValue, OrParser> const & parser,
std::ostream & os,
int components = 0);

File diff suppressed because it is too large Load Diff

View File

@@ -24,8 +24,9 @@
#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(__GNUC__) && 12 <= __GNUC__
#if !BOOST_PARSER_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE && \
BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS && \
defined(BOOST_PARSER_GCC) && 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,7 +42,8 @@ namespace boost::parser::detail::text::detail {
template<typename R>
constexpr bool view =
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS || \
(defined(__cpp_lib_concepts) && (!defined(__GNUC__) || 12 <= __GNUC__))
(defined(__cpp_lib_concepts) && \
(!defined(BOOST_PARSER_GCC) || 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,41 +143,14 @@ 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`
@@ -188,21 +161,20 @@ namespace boost { namespace parser {
typename Parser,
typename DelimiterParser = detail::nope,
typename MinType = int64_t,
typename MaxType = int64_t,
typename ParserMods = parser_modifiers<>>
typename MaxType = int64_t>
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, typename ParserMods>
template<typename Parser>
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, typename ParserMods>
template<typename Parser>
struct one_plus_parser;
/** Repeats the application of another parser `p` of type `Parser`, `[1,
@@ -211,14 +183,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, typename ParserMods>
template<typename Parser, typename DelimiterParser>
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, typename ParserMods>
template<typename Parser>
struct opt_parser;
/** Applies each parser in `ParserTuple`, in order, stopping after the
@@ -226,7 +198,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, typename ParserMods>
template<typename ParserTuple>
struct or_parser;
/** Applies each parsers in `ParserTuple`, an any order, stopping after
@@ -237,7 +209,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 ParserMods>
template<typename ParserTuple, typename DelimiterParser>
struct perm_parser;
/** Applies each parser in `ParserTuple`, in order. The parse succeeds
@@ -250,15 +222,14 @@ namespace boost { namespace parser {
template<
typename ParserTuple,
typename BacktrackingTuple,
typename CombiningGroups,
typename ParserMods>
typename CombiningGroups>
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, typename ParserMods>
template<typename Parser, typename Action>
struct action_parser;
/** Applies the given parser `p` of type `Parser`. The attribute produced
@@ -266,14 +237,21 @@ 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, typename ParserMods>
template<typename Parser, typename F>
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, typename ParserMods>
template<typename Parser>
struct raw_parser;
#if defined(BOOST_PARSER_DOXYGEN) || BOOST_PARSER_USE_CONCEPTS
@@ -286,30 +264,34 @@ 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, typename ParserMods>
template<typename Parser>
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, typename ParserMods>
template<typename Parser>
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,
typename ParserMods = parser_modifiers<>>
template<typename Parser, typename SkipParser = detail::nope>
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 equal
to `ExpectMatch == expect_match_t::yes`. */
template<typename Parser, expect_match_t ExpectMatch, typename ParserMods>
and consuming no input. The parse succeeds iff `p`'s success is
unequal to `FailOnMatch`. */
template<typename Parser, bool FailOnMatch>
struct expect_parser;
/** Matches one of a set S of possible inputs, each of which is associated
@@ -318,7 +300,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, typename ParserMods>
template<typename T>
struct symbol_parser;
/** Applies another parser `p`, associated with this parser via `TagType`.
@@ -337,24 +319,22 @@ namespace boost { namespace parser {
typename TagType,
typename Attribute,
typename LocalState,
typename ParamsTuple,
typename ParserMods>
typename ParamsTuple>
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, typename ParserMods>
template<typename Predicate>
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, typename ParserMods>
template<typename Attribute>
struct attr_parser;
/** A tag type that can be passed as the first parameter to `char_()` when
@@ -371,10 +351,7 @@ 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,
typename ParserMods = parser_modifiers<>>
template<typename Expected, typename AttributeType = void>
struct char_parser;
/** Matches a single code point that is equal to one of the code points
@@ -382,7 +359,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, typename ParserMods>
template<typename Tag>
struct char_set_parser;
/** Matches a single code point that falls into one of the subranges of
@@ -390,18 +367,17 @@ 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, typename ParserMods>
template<typename Tag>
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, typename ParserMods>
template<typename StrIter, typename StrSentinel>
struct string_parser;
/** Matches a string delimited by quotation marks; produces a
@@ -409,7 +385,7 @@ namespace boost { namespace parser {
template<
typename Quotes = detail::nope,
typename Escapes = detail::nope,
typename ParserMods = parser_modifiers<>>
typename CharParser = char_parser<detail::nope>>
struct quoted_string_parser;
/** Matches an end-of-line (`NewlinesOnly == true`), whitespace
@@ -417,12 +393,11 @@ 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, typename ParserMods>
template<bool NewlinesOnly, bool NoNewlines>
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`
@@ -436,8 +411,7 @@ namespace boost { namespace parser {
int Radix = 10,
int MinDigits = 1,
int MaxDigits = -1,
typename Expected = detail::nope,
typename ParserMods = parser_modifiers<>>
typename Expected = detail::nope>
struct uint_parser;
/** Matches a signed number of radix `Radix`, of at least `MinDigits` and
@@ -451,13 +425,12 @@ namespace boost { namespace parser {
int Radix = 10,
int MinDigits = 1,
int MaxDigits = -1,
typename Expected = detail::nope,
typename ParserMods = parser_modifiers<>>
typename Expected = detail::nope>
struct int_parser;
/** Matches a floating point number, producing an attribute of type
`T`. */
template<typename T, typename ParserMods>
template<typename T>
struct float_parser;
/** Applies at most one of the parsers in `OrParser`. If `switch_value_`
@@ -465,10 +438,7 @@ 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,
typename ParserMods = parser_modifiers<>>
template<typename SwitchValue, typename OrParser = detail::nope>
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_modifiers<>>>>;
parser_interface<eps_parser<detail::phony>>>;
template<
typename V,
@@ -469,7 +469,7 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
parser_interface<eps_parser<detail::phony, parser_modifiers<>>>>;
parser_interface<eps_parser<detail::phony>>>;
namespace detail {
template<
@@ -571,8 +571,7 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
parser_interface<
eps_parser<detail::phony, parser_modifiers<>>>>
parser_interface<eps_parser<detail::phony>>>
[[nodiscard]] constexpr auto operator()(
R && r,
parser_interface<Parser, GlobalState, ErrorHandler> const &
@@ -583,8 +582,7 @@ namespace boost::parser {
return (*this)(
(R &&)r,
parser,
parser_interface<
eps_parser<detail::phony, parser_modifiers<>>>{},
parser_interface<eps_parser<detail::phony>>{},
(ReplacementR &&)replacement,
trace_mode);
}
@@ -625,11 +623,10 @@ 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, parser_modifiers<>>>{},
(SkipParser &&)skip,
parser_interface<eps_parser<detail::phony>>{},
(SkipParser &&) skip,
replacement);
} else {
static_assert(

View File

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

View File

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

View File

@@ -4,7 +4,8 @@
#include <boost/parser/replace.hpp>
#if (!defined(_MSC_VER) || BOOST_PARSER_USE_CONCEPTS) && \
(!defined(__GNUC__) || 12 <= __GNUC__ || !BOOST_PARSER_USE_CONCEPTS)
(!defined(BOOST_PARSER_GCC) || 12 <= __GNUC__ || \
!BOOST_PARSER_USE_CONCEPTS)
namespace boost::parser {
@@ -254,9 +255,7 @@ namespace boost::parser {
BOOST_PARSER_SUBRANGE(first, first), parse_result{});
}
if constexpr (std::is_same_v<
SkipParser,
eps_parser<phony, parser_modifiers<>>>) {
if constexpr (std::is_same_v<SkipParser, eps_parser<phony>>) {
auto result = parser::prefix_parse(
first, last, search_parser, trace_mode);
if (*result) {
@@ -580,7 +579,7 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
parser_interface<eps_parser<detail::phony, parser_modifiers<>>>>;
parser_interface<eps_parser<detail::phony>>>;
template<
typename V,
@@ -596,7 +595,7 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
parser_interface<eps_parser<detail::phony, parser_modifiers<>>>>;
parser_interface<eps_parser<detail::phony>>>;
namespace detail {
template<
@@ -699,8 +698,7 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
parser_interface<
eps_parser<detail::phony, parser_modifiers<>>>>
parser_interface<eps_parser<detail::phony>>>
[[nodiscard]] constexpr auto operator()(
R && r,
parser_interface<Parser, GlobalState, ErrorHandler> const &
@@ -711,8 +709,7 @@ namespace boost::parser {
return (*this)(
(R &&)r,
parser,
parser_interface<
eps_parser<detail::phony, parser_modifiers<>>>{},
parser_interface<eps_parser<detail::phony>>{},
(F &&)f,
trace_mode);
}
@@ -757,11 +754,10 @@ 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, parser_modifiers<>>>{},
(SkipParser &&)skip,
parser_interface<eps_parser<detail::phony>>{},
(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,14 +185,10 @@ 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,6 +237,27 @@ 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()
{
@@ -246,5 +267,6 @@ 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)
{
auto char_p = no_case[char_('a') | char_('B')];
constexpr 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<ignore_case_t::yes>(
mixed_sharp_s1,
detail::text::null_sentinel,
mixed_sharp_s2,
detail::text::null_sentinel);
auto const result = detail::no_case_aware_string_mismatch(
mixed_sharp_s1,
detail::text::null_sentinel,
mixed_sharp_s2,
detail::text::null_sentinel,
true);
BOOST_TEST(result.first == detail::text::null_sentinel);
BOOST_TEST(result.second == detail::text::null_sentinel);
}

View File

@@ -2753,6 +2753,16 @@ 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,5 +88,66 @@ int main()
}
}
return boost::report_errors();
{
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();
}

View File

@@ -49,7 +49,7 @@ int main()
}
}
// different_char
// different_quote
{
constexpr auto parser = bp::quoted_string('\'');
@@ -75,9 +75,18 @@ 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_char_with_escapes
// different_quote_with_escapes
{
{
auto parser = bp::quoted_string('\'', cu_escapes);
@@ -119,6 +128,58 @@ 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("'\"");
@@ -171,6 +232,15 @@ 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
@@ -233,6 +303,15 @@ 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
@@ -279,6 +358,16 @@ 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,8 +156,6 @@ int main()
<< "----------------------------------------\n";
PARSE(omit[char_]);
PARSE(omit[omit[char_]]);
PARSE(omit[*omit[char_]]);
std::cout << "\n\n"
<< "----------------------------------------\n"
@@ -190,15 +188,6 @@ 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"
@@ -229,16 +218,6 @@ 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"
@@ -247,16 +226,6 @@ 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"