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

1 Commits

Author SHA1 Message Date
Zach Laine
4287c9b7b3 Fix transform_replace* in C++20 mode on GCC < 12. 2024-02-11 18:56:59 -06:00
54 changed files with 2082 additions and 9435 deletions

View File

@@ -2,9 +2,9 @@ name: macos-12 - Clang 13
on:
push:
branches: [ master, develop, boost_review_changes ]
branches: [ master, develop ]
pull_request:
branches: [ master, develop, boost_review_changes ]
branches: [ master, develop ]
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)

View File

@@ -2,9 +2,9 @@ name: Ubuntu-20.04 - GCC 9,10
on:
push:
branches: [ master, develop, boost_review_changes ]
branches: [ master, develop ]
pull_request:
branches: [ master, develop, boost_review_changes ]
branches: [ master, develop ]
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)

View File

@@ -2,9 +2,9 @@ name: Ubuntu-22.04 - GCC 10,11
on:
push:
branches: [ master, develop, boost_review_changes ]
branches: [ master, develop ]
pull_request:
branches: [ master, develop, boost_review_changes ]
branches: [ master, develop ]
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)

View File

@@ -2,9 +2,9 @@ name: windows-2019 - Visual Studio 2019
on:
push:
branches: [ master, develop, boost_review_changes ]
branches: [ master, develop ]
pull_request:
branches: [ master, develop, boost_review_changes ]
branches: [ master, develop ]
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)

View File

@@ -2,9 +2,9 @@ name: windows-2022 - Visual Studio 2022
on:
push:
branches: [ master, develop, boost_review_changes ]
branches: [ master, develop ]
pull_request:
branches: [ master, develop, boost_review_changes ]
branches: [ master, develop ]
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)

View File

@@ -12,8 +12,6 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL Clang)
add_definitions(-g -Wall)
elseif (CMAKE_CXX_COMPILER_ID STREQUAL GNU)
add_definitions(-g -Wall)
elseif (CMAKE_CXX_COMPILER_ID STREQUAL MSVC)
add_definitions(/W3)
endif ()
##################################################

View File

@@ -24,7 +24,6 @@ doxygen parser_reference
# note that there is no detail::unspecified -- this is a hack to get all
# the SFINAE code out of the API docs.
<doxygen:param>"PREDEFINED=\"BOOST_PARSER_DOXYGEN=1\" \\
\"BOOST_PARSER_USE_CONCEPTS=1\" \\
\"enable_if=detail::unspecified\""
<doxygen:param>HIDE_UNDOC_MEMBERS=NO
<doxygen:param>EXTRACT_PRIVATE=NO
@@ -38,7 +37,7 @@ doxygen parser_reference
}
run_doxygen [ glob ../include/boost/parser/*.hpp : ../include/boost/parser/concepts.hpp ] : "Reference" ;
run_doxygen [ glob ../include/boost/parser/*.hpp ] : "Reference" ;
xml parser
:

View File

@@ -163,8 +163,7 @@ However, it does not suit user needs in some ways.
rule.
* Spirit X3 is missing many of the convenient interfaces to parsers that
Spirit 2 had. For instance, you cannot add parameters to a parser (see
description of _locals_ in _more_about_rules_).
Spirit 2 had. For instance, you cannot add parameters to a parser.
* All versions of Spirit have Unicode support, but it is quite difficult to
get working.
@@ -185,104 +184,10 @@ that have been retained in _Parser_. Both libraries:
* use approximately the same set of directives to influence the parse
(e.g. `lexeme[]`);
* provide loosely-coupled rules that are separately compilable (at least for
Spirit X3); and
* are built around a flexible parse context object that has state added to and
removed from it during the parse (again, comparing to Spirit X3).
[heading The Spirit X3 rule problem]
Some readers have wanted a concrete example of my claim that Spirit X3's rules
do not compose well. Consider this program.
#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <set>
#include <string>
#include <vector>
namespace x3 = boost::spirit::x3;
using ints_type = x3::rule<class ints, std::vector<int>>;
BOOST_SPIRIT_DECLARE(ints_type);
x3::rule<class ints, std::vector<int>> ints = "ints";
constexpr auto ints_def = x3::int_ % ',';
BOOST_SPIRIT_DEFINE(ints);
#define FIXED_ATTRIBUTE 0
int main()
{
std::string input = "43, 42";
auto first = input.begin();
auto const last = input.end();
#if FIXED_ATTRIBUTE
std::vector<int> result;
#else
std::set<int> result;
#endif
bool success = x3::phrase_parse(first, last, ints, x3::space, result);
if (success) {
// We want this to print "43 42\n".
for (auto x : result) {
std::cout << x << ' ';
}
std::cout << "\n";
}
return 0;
}
Defining `FIXED_ATTRIBUTE` to be `1` leads to a well-formed program that
prints `"42 43\n"` instead of the desired result. The problem here is that if
you feed an attribute out-param to `x3::phrase_parse()`, you get the
loose-match semantics that Spirit X3 and _Parser_ both do. This is a problem,
because the user explicitly asserted that the type of the `ints` rule's
attribute should be `std::vector<int>`. In my opinion, this code should be
ill-formed with `FIXED_ATTRIBUTE == 1`. To make it well-formed again, the
user could use `ints_def` directly, since it does not specify an attribute
type.
When the user explicitly states that a type is some fixed `T`, a library
should not ignore that. As a user of X3, I was bitten by this in such a way
that I considered X3 to be a nonviable option for my uses. I ran into a
problem that resulted from X3's ignoring one or more of my rules' attributes
so that it made the parse produce the wrong result, and I could see no way to
fix it.
When a library provides wider use cases via genericity, we generally consider
this a good thing. If it is too loose in its semantics, we generally say that
it is type-unsafe. Using _rs_ to nail down type flexibility is one way
_Parser_ tries to enable genericity where it is desired, and let the user turn
it off where it is not.
[endsect]
[section Cheat Sheet]
Here are all the tables containing the various _Parser_ parsers, examples,
etc., all in one place. These are repeated elsewhere in different sections of
the tutorial.
[heading The parsers]
[table_parsers_and_their_semantics]
[heading Operators defined on parsers]
[table_combining_operations]
[heading Attribute generation for certain parsers]
[table_attribute_generation]
[heading Attributes for operations on parsers]
[table_attribute_combinations]
[heading More attributes for operations on parsers]
[table_seq_or_attribute_combinations]
[endsect]

View File

@@ -39,9 +39,6 @@
[import ../example/parsing_into_a_class.cpp]
[import ../example/struct_rule.cpp]
[import ../example/user_error_handler.cpp]
[import ../test/parser.cpp]
[import ../test/parser_rule.cpp]
[import ../test/parser_quoted_string.cpp]
[import ../include/boost/parser/concepts.hpp]
[import ../include/boost/parser/error_handling_fwd.hpp]
@@ -70,17 +67,6 @@
[def _cb_r_ [classref boost::parser::callback_rule `callback_rule`]]
[def _cb_rs_ [classref boost::parser::callback_rules `callback_rule`s]]
[def _skp_p_ [classref boost::parser::skip_parser `skip_parser`]]
[def _xfm_p_ [classref boost::parser::transform_parser `tranform_parser`]]
[def _noc_p_ [classref boost::parser::no_case_parser `no_case_parser`]]
[def _sv_p_ [classref boost::parser::string_view_parser `string_view_parser`]]
[def _raw_p_ [classref boost::parser::raw_parser `raw_parser`]]
[def _omt_p_ [classref boost::parser::omit_parser `omit_parser`]]
[def _rpt_p_ [classref boost::parser::repeat_parser `repeat_parser`]]
[def _lex_p_ [classref boost::parser::lexeme_parser `lexeme_parser`]]
[def _seq_p_ [classref boost::parser::seq_parser `seq_parser`]]
[def _seq_ps_ [classref boost::parser::seq_parser `seq_parser`s]]
[def _bp_tup_ [classref boost::parser::tuple `boost::parser::tuple`]]
[def _bp_get_ [funcref boost::parser::get `boost::parser::get`]]
[def _bh_tup_ `boost::hana::tuple`]
@@ -119,9 +105,6 @@
[def _cbp_ [funcref boost::parser::callback_parse `callback_parse()`]]
[def _cbpp_ [funcref boost::parser::callback_prefix_parse `callback_prefix_parse()`]]
[def _attr_ [classref boost::parser::attribute `attribute`]]
[def _attr_t_ [classref boost::parser::attribute_t `attribute_t`]]
[def _w_glb_ [funcref boost::parser::with_globals `with_globals()`]]
[def _w_eh_ [funcref boost::parser::with_error_handler `with_error_handler()`]]
@@ -199,7 +182,6 @@
[def _skip_ [globalref boost::parser::skip `skip[]`]]
[def _merge_ [globalref boost::parser::merge `merge[]`]]
[def _sep_ [globalref boost::parser::separate `separate[]`]]
[def _transform_ [globalref boost::parser::transform `transform(f)[]`]]
[def _omit_np_ [globalref boost::parser::omit `omit`]]
[def _raw_np_ [globalref boost::parser::raw `raw`]]
@@ -209,7 +191,6 @@
[def _skip_np_ [globalref boost::parser::skip `skip`]]
[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 _blank_ [globalref boost::parser::blank `blank`]]
[def _control_ [globalref boost::parser::control `control`]]
@@ -219,19 +200,16 @@
[def _lower_ [globalref boost::parser::lower `lower`]]
[def _upper_ [globalref boost::parser::upper `upper`]]
[def _quot_str_ [globalref boost::parser::quoted_string `quoted_string`]]
[def _RES_ ['[^RESOLVE]]`()`]
[def _RES_np_ ['[^RESOLVE]]]
[def _ATTR_ ['[^ATTR]]`()`]
[def _ATTR_np_ ['[^ATTR]]]
[def _p_api_ [link boost_parser__proposed_.tutorial.the__parse____api The `parse()` API]]
[def _parsers_uses_ [link boost_parser__proposed_.tutorial.the_parsers_and_their_uses The Parsers And Their Uses]]
[def _parse_ctx_ [link boost_parser__proposed_.tutorial.the_parse_context The Parse Context]]
[def _rule_parsers_ [link boost_parser__proposed_.tutorial.rule_parsers Rule Parsers]]
[def _parsing_structs_ [link boost_parser__proposed_.tutorial.parsing_into__struct_s_and__class_es Parsing into `struct`s and `class`es]]
[def _expect_pts_ [link boost_parser__proposed_.tutorial.backtracking.expectation_points Expectation points]]
[def _expect_pts_ [link boost_parser__proposed_.tutorial.backtracking.html#boost_parser__proposed_.tutorial.backtracking.expectation_points Expectation points]]
[def _attr_gen_ [link boost_parser__proposed_.tutorial.attribute_generation Attribute Generation]]
[def _directives_ [link boost_parser__proposed_.tutorial.directives Directives]]
[def _eh_debugging_ [link boost_parser__proposed_.tutorial.error_handling_and_debugging Error Handling and Debugging]]
@@ -257,7 +235,6 @@
[def _emdash_ \u2014]
[include tables.qbk]
[include intro.qbk]
[include tutorial.qbk]
[include examples.qbk]

View File

@@ -1,599 +0,0 @@
[/
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/]
[template table_parsers_and_their_semantics
This table lists all the _Parser_ parsers. For the callable parsers, a
separate entry exists for each possible arity of arguments. For a parser `p`,
if there is no entry for `p` without arguments, `p` is a function, and cannot
itself be used as a parser; it must be called. In the table below:
* each entry is a global object usable directly in your parsers, unless
otherwise noted;
* "code point" is used to refer to the elements of the input range, which
assumes that the parse is being done in the Unicode-aware code path (if the
parse is being done in the non-Unicode code path, read "code point" as
"`char`");
* _RES_ is a notional macro that expands to the resolution of parse argument
or evaluation of a parse predicate (see _parsers_uses_);
* "`_RES_np_(pred) == true`" is a shorthand notation for "`_RES_np_(pred)` is
contextually convertible to `bool` and `true`"; likewise for `false`;
* `c` is a character of type `char`, `char8_t`, or `char32_t`;
* `str` is a string literal of type `char const[]`, `char8_t const []`, or
`char32_t const []`;
* `pred` is a parse predicate;
* `arg0`, `arg1`, `arg2`, ... are parse arguments;
* `a` is a semantic action;
* `r` is an object whose type models `parsable_range_like`; and
* `p`, `p1`, `p2`, ... are parsers.
* `escapes` is a _symbols_t_ object, where `T` is `char` or `char32_t`.
[note The definition of `parsable_range_like` is:
[parsable_range_like_concept]
It is intended to be a range-like thing; a null-terminated sequence of
characters is considered range-like, given that a pointer `T *` to a
null-terminated string is isomorphic with `subrange<T *, _null_sent_>`.]
[note Some of the parsers in this table consume no input. All parsers consume
the input they match unless otherwise stated in the table below.]
[table Parsers and Their Semantics
[[Parser] [Semantics] [Attribute Type] [Notes]]
[[ _e_ ]
[ Matches /epsilon/, the empty string. Always matches, and consumes no input. ]
[ None. ]
[ 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_`, `+_e_`, etc (this applies to unconditional _e_ only). ]]
[[ `_e_(pred)` ]
[ Fails to match the input if `_RES_np_(pred) == false`. Otherwise, the semantics are those of _e_. ]
[ None. ]
[]]
[[ _ws_ ]
[ Matches a single whitespace code point (see note), according to the Unicode White_Space property. ]
[ None. ]
[ For more info, see the [@https://www.unicode.org/Public/UCD/latest/ucd/PropList.txt Unicode properties]. _ws_ may consume one code point or two. It only consumes two code points when it matches `"\r\n"`. ]]
[[ _eol_ ]
[ Matches a single newline (see note), following the "hard" line breaks in the Unicode line breaking algorithm. ]
[ None. ]
[ For more info, see the [@https://unicode.org/reports/tr14 Unicode Line Breaking Algorithm]. _eol_ may consume one code point or two. It only consumes two code points when it matches `"\r\n"`. ]]
[[ _eoi_ ]
[ Matches only at the end of input, and consumes no input. ]
[ None. ]
[]]
[[ _attr_np_`(arg0)` ]
[ Always matches, and consumes no input. Generates the attribute `_RES_np_(arg0)`. ]
[ `decltype(_RES_np_(arg0))`. ]
[ An important use case for `_attr_` is to provide a default attribute value as a trailing alternative. For instance, an *optional* comma-delmited list is: `int_ % ',' | attr(std::vector<int>)`. Without the "`| attr(...)`", at least one `int_` match would be required. ]]
[[ _ch_ ]
[ Matches any single code point. ]
[ The code point type in Unicode parsing, or `char` in non-Unicode parsing. See _attr_gen_. ]
[]]
[[ `_ch_(arg0)` ]
[ Matches exactly the code point `_RES_np_(arg0)`. ]
[ The code point type in Unicode parsing, or `char` in non-Unicode parsing. See _attr_gen_. ]
[]]
[[ `_ch_(arg0, arg1)` ]
[ Matches the next code point `n` in the input, if `_RES_np_(arg0) <= n && n <= _RES_np_(arg1)`. ]
[ The code point type in Unicode parsing, or `char` in non-Unicode parsing. See _attr_gen_. ]
[]]
[[ `_ch_(r)` ]
[ Matches the next code point `n` in the input, if `n` is one of the code points in `r`. ]
[ The code point type in Unicode parsing, or `char` in non-Unicode parsing. See _attr_gen_. ]
[ `r` is taken to be in a UTF encoding. The exact UTF used depends on `r`'s element type. If you do not pass UTF encoded ranges for `r`, the behavior of _ch_ is undefined. Note that ASCII is a subset of UTF-8, so ASCII is fine. EBCDIC is not. `r` is not copied; a reference to it is taken. The lifetime of `_ch_(r)` must be within the lifetime of `r`. This overload of _ch_ does *not* take parse arguments. ]]
[[ _cp_ ]
[ Matches a single code point. ]
[ `char32_t` ]
[ Similar to _ch_, but with a fixed `char32_t` attribute type; _cp_ has all the same call operator overloads as _ch_, though they are not repeated here, for brevity. ]]
[[ _cu_ ]
[ Matches a single code point. ]
[ `char` ]
[ Similar to _ch_, but with a fixed `char` attribute type; _cu_ has all the same call operator overloads as _ch_, though they are not repeated here, for brevity. Even though the name "`cu`" suggests that this parser match at the code unit level, it does not. The name refers to the attribute type generated, much like the names _i_ versus _ui_. ]]
[[ `_blank_` ]
[ Equivalent to `_ws_ - _eol_`. ]
[ The code point type in Unicode parsing, or `char` in non-Unicode parsing. See the entry for _ch_. ]
[]]
[[ `_control_` ]
[ Matches a single control-character code point. ]
[ The code point type in Unicode parsing, or `char` in non-Unicode parsing. See the entry for _ch_. ]
[]]
[[ `_digit_` ]
[ Matches a single decimal digit code point. ]
[ The code point type in Unicode parsing, or `char` in non-Unicode parsing. See the entry for _ch_. ]
[]]
[[ `_punct_` ]
[ Matches a single punctuation 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_. ]
[]]
[[ `_lower_` ]
[ Matches a single lower-case code point. ]
[ The code point type in Unicode parsing, or `char` in non-Unicode parsing. See the entry for _ch_. ]
[]]
[[ `_upper_` ]
[ Matches a single upper-case code point. ]
[ The code point type in Unicode parsing, or `char` in non-Unicode parsing. See the entry for _ch_. ]
[]]
[[ _lit_np_`(c)`]
[ Matches exactly the given code point `c`. ]
[ None. ]
[_lit_ does *not* take parse arguments. ]]
[[ `c_l` ]
[ Matches exactly the given code point `c`. ]
[ None. ]
[ This is a _udl_ that represents `_lit_np_(c)`, for example `'F'_l`. ]]
[[ _lit_np_`(r)`]
[ Matches exactly the given string `r`. ]
[ None. ]
[ _lit_ does *not* take parse arguments. ]]
[[ `str_l` ]
[ Matches exactly the given string `str`. ]
[ None. ]
[ This is a _udl_ that represents `_lit_np_(s)`, for example `"a string"_l`. ]]
[[ `_str_np_(r)`]
[ Matches exactly `r`, and generates the match as an attribute. ]
[ _std_str_ ]
[ _str_ does *not* take parse arguments. ]]
[[ `str_p`]
[ Matches exactly `str`, and generates the match as an attribute. ]
[ _std_str_ ]
[ This is a _udl_ that represents `_str_np_(s)`, for example `"a string"_p`. ]]
[[ _b_ ]
[ Matches `"true"` or `"false"`. ]
[ `bool` ]
[]]
[[ _bin_ ]
[ Matches a binary unsigned integral value. ]
[ `unsigned int` ]
[ For example, _bin_ would match `"101"`, and generate an attribute of `5u`. ]]
[[ `_bin_(arg0)` ]
[ Matches exactly the binary unsigned integral value `_RES_np_(arg0)`. ]
[ `unsigned int` ]
[]]
[[ _oct_ ]
[ Matches an octal unsigned integral value. ]
[ `unsigned int` ]
[ For example, _oct_ would match `"31"`, and generate an attribute of `25u`. ]]
[[ `_oct_(arg0)` ]
[ Matches exactly the octal unsigned integral value `_RES_np_(arg0)`. ]
[ `unsigned int` ]
[]]
[[ _hex_ ]
[ Matches a hexadecimal unsigned integral value. ]
[ `unsigned int` ]
[ For example, _hex_ would match `"ff"`, and generate an attribute of `255u`. ]]
[[ `_hex_(arg0)` ]
[ Matches exactly the hexadecimal unsigned integral value `_RES_np_(arg0)`. ]
[ `unsigned int` ]
[]]
[[ _us_ ]
[ Matches an unsigned integral value. ]
[ `unsigned short` ]
[]]
[[ `_us_(arg0)` ]
[ Matches exactly the unsigned integral value `_RES_np_(arg0)`. ]
[ `unsigned short` ]
[]]
[[ _ui_ ]
[ Matches an unsigned integral value. ]
[ `unsigned int` ]
[]]
[[ `_ui_(arg0)` ]
[ Matches exactly the unsigned integral value `_RES_np_(arg0)`. ]
[ `unsigned int` ]
[]]
[[ _ul_ ]
[ Matches an unsigned integral value. ]
[ `unsigned long` ]
[]]
[[ `_ul_(arg0)` ]
[ Matches exactly the unsigned integral value `_RES_np_(arg0)`. ]
[ `unsigned long` ]
[]]
[[ _ull_ ]
[ Matches an unsigned integral value. ]
[ `unsigned long long` ]
[]]
[[ `_ull_(arg0)` ]
[ Matches exactly the unsigned integral value `_RES_np_(arg0)`. ]
[ `unsigned long long` ]
[]]
[[ _s_ ]
[ Matches a signed integral value. ]
[ `short` ]
[]]
[[ `_s_(arg0)` ]
[ Matches exactly the signed integral value `_RES_np_(arg0)`. ]
[ `short` ]
[]]
[[ _i_ ]
[ Matches a signed integral value. ]
[ `int` ]
[]]
[[ `_i_(arg0)` ]
[ Matches exactly the signed integral value `_RES_np_(arg0)`. ]
[ `int` ]
[]]
[[ _l_ ]
[ Matches a signed integral value. ]
[ `long` ]
[]]
[[ `_l_(arg0)` ]
[ Matches exactly the signed integral value `_RES_np_(arg0)`. ]
[ `long` ]
[]]
[[ _ll_ ]
[ Matches a signed integral value. ]
[ `long long` ]
[]]
[[ `_ll_(arg0)` ]
[ Matches exactly the signed integral value `_RES_np_(arg0)`. ]
[ `long long` ]
[]]
[[ _f_ ]
[ Matches a floating-point number. _f_ uses parsing implementation details from _Spirit_. The specifics of what formats are accepted can be found in their _spirit_reals_. Note that only the default `RealPolicies` is supported by _f_. ]
[ `float` ]
[]]
[[ _d_ ]
[ Matches a floating-point number. _d_ uses parsing implementation details from _Spirit_. The specifics of what formats are accepted can be found in their _spirit_reals_. Note that only the default `RealPolicies` is supported by _d_. ]
[ `double` ]
[]]
[[ `_rpt_np_(arg0)[p]` ]
[ Matches iff `p` matches exactly `_RES_np_(arg0)` times. ]
[ `std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>` ]
[ The special value _inf_ may be used; it indicates unlimited repetition. `decltype(_RES_np_(arg0))` must be implicitly convertible to `int64_t`. Matching _e_ an unlimited number of times creates an infinite loop, which is undefined behavior in C++. _Parser_ will assert in debug mode when it encounters `_rpt_np_(_inf_)[_e_]` (this applies to unconditional _e_ only). ]]
[[ `_rpt_np_(arg0, arg1)[p]` ]
[ Matches iff `p` matches between `_RES_np_(arg0)` and `_RES_np_(arg1)` times, inclusively. ]
[ `std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>` ]
[ The special value _inf_ may be used for the upper bound; it indicates unlimited repetition. `decltype(_RES_np_(arg0))` and `decltype(_RES_np_(arg1))` each must be implicitly convertible to `int64_t`. Matching _e_ an unlimited number of times creates an infinite loop, which is undefined behavior in C++. _Parser_ will assert in debug mode when it encounters `_rpt_np_(n, _inf_)[_e_]` (this applies to unconditional _e_ only). ]]
[[ `_if_np_(pred)[p]` ]
[ Equivalent to `_e_(pred) >> p`. ]
[ `std::optional<_ATTR_np_(p)>` ]
[ It is an error to write `_if_np_(pred)`. That is, it is an error to omit the conditionally matched parser `p`. ]]
[[ `_sw_np_(arg0)(arg1, p1)(arg2, p2) ...` ]
[ Equivalent to `p1` when `_RES_np_(arg0) == _RES_np_(arg1)`, `p2` when `_RES_np_(arg0) == _RES_np_(arg2)`, etc. If there is such no `argN`, the behavior of _sw_ is undefined. ]
[ `std::variant<_ATTR_np_(p1), _ATTR_np_(p2), ...>` ]
[ It is an error to write `_sw_np_(arg0)`. That is, it is an error to omit the conditionally matched parsers `p1`, `p2`, .... ]]
[[ _symbols_t_ ]
[ _symbols_ is an associative container of key, value pairs. Each key is a _std_str_ and each value has type `T`. In the Unicode parsing path, the strings are considered to be UTF-8 encoded; in the non-Unicode path, no encoding is assumed. _symbols_ Matches the longest prefix `pre` of the input that is equal to one of the keys `k`. If the length `len` of `pre` is zero, and there is no zero-length key, it does not match the input. If `len` is positive, the generated attribute is the value associated with `k`.]
[ `T` ]
[ Unlike the other entries in this table, _symbols_ is a type, not an object. ]]
[[ _quot_str_ ]
[ Matches `'"'`, followed by zero or more characters, followed by `'"'`. ]
[ _std_str_ ]
[ The result does not include the quotes. A quote within the string can be written by escaping it with a backslash. A backslash within the string can be written by writing two consecutive backslashes. Any other use of a backslash will fail the parse. Skipping is disabled while parsing the entire string, as if using _lexeme_. ]]
[[ `_quot_str_(c)` ]
[ Matches `c`, followed by zero or more characters, followed by `c`. ]
[ _std_str_ ]
[ The result does not include the `c` quotes. A `c` within the string can be written by escaping it with a backslash. A backslash within the string can be written by writing two consecutive backslashes. Any other use of a backslash will fail the parse. Skipping is disabled while parsing the entire string, as if using _lexeme_. ]]
[[ `_quot_str_(r)` ]
[ Matches some character `Q` in `r`, followed by zero or more characters, followed by `Q`. ]
[ _std_str_ ]
[ The result does not include the `Q` quotes. A `Q` within the string can be written by escaping it with a backslash. A backslash within the string can be written by writing two consecutive backslashes. Any other use of a backslash will fail the parse. Skipping is disabled while parsing the entire string, as if using _lexeme_. ]]
[[ `_quot_str_(c, symbols)` ]
[ Matches `c`, followed by zero or more characters, followed by `c`. ]
[ _std_str_ ]
[ The result does not include the `c` quotes. A `c` within the string can be written by escaping it with a backslash. A backslash within the string can be written by writing two consecutive backslashes. A backslash followed by a successful match using `symbols` will be interpreted as the corresponding value produced by `symbols`. Any other use of a backslash will fail the parse. Skipping is disabled while parsing the entire string, as if using _lexeme_. ]]
[[ `_quot_str_(r, symbols)` ]
[ Matches some character `Q` in `r`, followed by zero or more characters, followed by `Q`. ]
[ _std_str_ ]
[ The result does not include the `Q` quotes. A `Q` within the string can be written by escaping it with a backslash. A backslash within the string can be written by writing two consecutive backslashes. A backslash followed by a successful match using `symbols` will be interpreted as the corresponding value produced by `symbols`. Any other use of a backslash will fail the parse. Skipping is disabled while parsing the entire string, as if using _lexeme_. ]]
]
[important All the character parsers, like _ch_, _cp_ and _cu_ produce either
`char` or `char32_t` attributes. So when you see "`std::string` if
`_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`"
in the table above, that effectively means that every sequences of character
attributes get turned into a `std::string`. The only time this does not
happen is when you introduce your own rules with attributes using another
character type (or use _attr_ to do so).]
]
[template table_combining_operations
Here are all the operator overloaded for parsers. In the tables below:
* `c` is a character of type `char` or `char32_t`;
* `a` is a semantic action;
* `r` is an object whose type models `parsable_range_like` (see _concepts_);
and
* `p`, `p1`, `p2`, ... are parsers.
[note Some of the expressions in this table consume no input. All parsers
consume the input they match unless otherwise stated in the table below.]
[table Combining Operations and Their Semantics
[[Expression] [Semantics] [Attribute Type] [Notes]]
[[`!p`] [ Matches iff `p` does not match; consumes no input. ] [None.] []]
[[`&p`] [ Matches iff `p` matches; consumes no input. ] [None.] []]
[[`*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. ]]
[[`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. ]]
[[`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. ]]
[[`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 `p2` matches, regardless of the order they match in. ] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2)>`] [ `||` is associative; `p1 || p2 || p3`, `(p1 || p2) || p3`, and `p1 || (p2 || p3)` are all equivalent. It is an error to include a _e_ (conditional or non-conditional) in an `operator||` expression. Though the parsers are matched in any order, the attribute elements are always in the order written in the `operator||` expression. ]]
[[`p1 - p2`] [ Equivalent to `!p2 >> p1`. ] [`_ATTR_np_(p1)`] []]
[[`p - c`] [ Equivalent to `p - lit(c)`. ] [`_ATTR_np_(p)`] []]
[[`p - r`] [ Equivalent to `p - lit(r)`. ] [`_ATTR_np_(p)`] []]
[[`p1 % p2`] [ Equivalent to `p1 >> *(p2 >> p1)`. ] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p1)>`] []]
[[`p % c`] [ Equivalent to `p % lit(c)`. ] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`] []]
[[`p % r`] [ Equivalent to `p % lit(r)`. ] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`] []]
[[`p[a]`] [ Matches iff `p` matches. If `p` matches, the semantic action `a` is executed. ] [None.] []]
]
[important All the character parsers, like _ch_, _cp_ and _cu_ produce either
`char` or `char32_t` attributes. So when you see "`std::string` if
`_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`"
in the table above, that effectively means that every sequences of character
attributes get turned into a `std::string`. The only time this does not
happen is when you introduce your own rules with attributes using another
character type (or use _attr_ to do so).]
There are a couple of special rules not captured in the table above:
First, the zero-or-more and one-or-more repetitions (`operator*()` and
`operator+()`, respectively) may collapse when combined. For any parser `p`,
`+(+p)` collapses to `+p`; `**p`, `*+p`, and `+*p` each collapse to just `*p`.
Second, using _e_ in an alternative parser as any alternative *except* the
last one is a common source of errors; _Parser_ disallows it. This is true
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.
]
[template table_attribute_generation
This table summarizes the attributes generated for all _Parser_ parsers. In
the table below:
* _RES_ is a notional macro that expands to the resolution of parse argument
or evaluation of a parse predicate (see _parsers_uses_); and
* `x` and `y` represent arbitrary objects.
[table Parsers and Their Attributes
[[Parser] [Attribute Type] [Notes]]
[[ _e_ ] [ None. ] []]
[[ _eol_ ] [ None. ] []]
[[ _eoi_ ] [ None. ] []]
[[ `_attr_np_(x)` ] [ `decltype(_RES_np_(x))` ][]]
[[ _ch_ ] [ The code point type in Unicode parsing, or `char` in non-Unicode parsing; see below. ]
[Includes all the `_p` _udls_ that take a single character, and all character class parsers like `control` and `lower`.]]
[[ _cp_ ] [ `char32_t` ] []]
[[ _cu_ ] [ `char` ] []]
[[ `_lit_np_(x)`] [ None. ]
[Includes all the `_l` _udls_.]]
[[ `_str_np_(x)`] [ _std_str_ ]
[Includes all the `_p` _udls_ that take a string.]]
[[ _b_ ] [ `bool` ] []]
[[ _bin_ ] [ `unsigned int` ] []]
[[ _oct_ ] [ `unsigned int` ] []]
[[ _hex_ ] [ `unsigned int` ] []]
[[ _us_ ] [ `unsigned short` ] []]
[[ _ui_ ] [ `unsigned int` ] []]
[[ _ul_ ] [ `unsigned long` ] []]
[[ _ull_ ] [ `unsigned long long` ] []]
[[ _s_ ] [ `short` ] []]
[[ _i_ ] [ `int` ] []]
[[ _l_ ] [ `long` ] []]
[[ _ll_ ] [ `long long` ] []]
[[ _f_ ] [ `float` ] []]
[[ _d_ ] [ `double` ] []]
[[ _symbols_t_ ] [ `T` ] []]
]
_ch_ is a bit odd, since its attribute type is polymorphic. When you use _ch_
to parse text in the non-Unicode code path (i.e. a string of `char`), the
attribute is `char`. When you use the exact same _ch_ to parse in the
Unicode-aware code path, all matching is code point based, and so the
attribute type is the type used to represent code points, `char32_t`. All
parsing of UTF-8 falls under this case.
Here, we're parsing plain `char`s, meaning that the parsing is in the
non-Unicode code path, the attribute of _ch_ is `char`:
auto result = parse("some text", boost::parser::char_);
static_assert(std::is_same_v<decltype(result), std::optional<char>>));
When you parse UTF-8, the matching is done on a code point basis, so the
attribute type is `char32_t`:
auto result = parse("some text" | boost::parser::as_utf8, boost::parser::char_);
static_assert(std::is_same_v<decltype(result), std::optional<char32_t>>));
The good news is that usually you don't parse characters individually. When
you parse with _ch_, you usually parse repetition of then, which will produce
a _std_str_, regardless of whether you're in Unicode parsing mode or not. If
you do need to parse individual characters, and want to lock down their
attribute type, you can use _cp_ and/or _cu_ to enforce a non-polymorphic
attribute type.
]
[template table_attribute_combinations
Combining operations of course affect the generation of attributes. In the
tables below:
* `m` and `n` are parse arguments that resolve to integral values;
* `pred` is a parse predicate;
* `arg0`, `arg1`, `arg2`, ... are parse arguments;
* `a` is a semantic action; and
* `p`, `p1`, `p2`, ... are parsers that generate attributes.
[table Combining Operations and Their Attributes
[[Parser] [Attribute Type]]
[[`!p`] [None.]]
[[`&p`] [None.]]
[[`*p`] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`]]
[[`+p`] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`]]
[[`+*p`] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`]]
[[`*+p`] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`]]
[[`-p`] [`std::optional<_ATTR_np_(p)>`]]
[[`p1 >> p2`] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2)>`]]
[[`p1 > p2`] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2)>`]]
[[`p1 >> p2 >> p3`] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2), _ATTR_np_(p3)>`]]
[[`p1 > p2 >> p3`] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2), _ATTR_np_(p3)>`]]
[[`p1 >> p2 > p3`] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2), _ATTR_np_(p3)>`]]
[[`p1 > p2 > p3`] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2), _ATTR_np_(p3)>`]]
[[`p1 | p2`] [`std::variant<_ATTR_np_(p1), _ATTR_np_(p2)>`]]
[[`p1 | p2 | p3`] [`std::variant<_ATTR_np_(p1), _ATTR_np_(p2), _ATTR_np_(p3)>`]]
[[`p1 || p2`] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2)>`]]
[[`p1 || p2 || p3`] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2), _ATTR_np_(p3)>`]]
[[`p1 % p2`] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p1)>`]]
[[`p[a]`] [None.]]
[[`_rpt_np_(arg0)[p]`] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`]]
[[`_rpt_np_(arg0, arg1)[p]`] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`]]
[[`_if_np_(pred)[p]`] [`std::optional<_ATTR_np_(p)>`]]
[[`_sw_np_(arg0)(arg1, p1)(arg2, p2)...`]
[`std::variant<_ATTR_np_(p1), _ATTR_np_(p2), ...>`]]
]
[important All the character parsers, like _ch_, _cp_ and _cu_ produce either
`char` or `char32_t` attributes. So when you see "`std::string` if
`_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`"
in the table above, that effectively means that every sequences of character
attributes get turned into a `std::string`. The only time this does not
happen is when you introduce your own rules with attributes using another
character type (or use _attr_ to do so).]
[important In case you did not notice it above, adding a semantic action to a
parser erases the parser's attribute. The attribute is still available inside
the semantic action as `_attr(ctx)`.]
]
[template table_seq_or_attribute_combinations
In the table: `a` is a semantic action; and `p`, `p1`, `p2`, ... are parsers
that generate attributes. Note that only `>>` is used here; `>` has the exact
same attribute generation rules.
[table Sequence and Alternative Combining Operations and Their Attributes
[[Expression] [Attribute Type]]
[[`_e_ >> _e_`] [None.]]
[[`p >> _e_`] [`_ATTR_np_(p)`]]
[[`_e_ >> p`] [`_ATTR_np_(p)`]]
[[`_cu_ >> _str_np_("str")`] [_std_str_]]
[[`_str_np_("str") >> _cu_`] [_std_str_]]
[[`*_cu_ >> _str_np_("str")`] [`_bp_tup_<std::string, std::string>`]]
[[`_str_np_("str") >> *_cu_`] [`_bp_tup_<std::string, std::string>`]]
[[`p >> p`] [`_bp_tup_<_ATTR_np_(p), _ATTR_np_(p)>`]]
[[`*p >> p`] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`]]
[[`p >> *p`] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`]]
[[`*p >> -p`] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`]]
[[`-p >> *p`] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`]]
[[`_str_np_("str") >> -_cu_`] [_std_str_]]
[[`-_cu_ >> _str_np_("str")`] [_std_str_]]
[[`!p1 | p2[a]`] [None.]]
[[`p | p`] [`_ATTR_np_(p)`]]
[[`p1 | p2`] [`std::variant<_ATTR_np_(p1), _ATTR_np_(p2)>`]]
[[`p | `_e_] [`std::optional<_ATTR_np_(p)>`]]
[[`p1 | p2 | _e_`] [`std::optional<std::variant<_ATTR_np_(p1), _ATTR_np_(p2)>>`]]
[[`p1 | p2[a] | p3`] [`std::optional<std::variant<_ATTR_np_(p1), _ATTR_np_(p3)>>`]]
]
]

File diff suppressed because it is too large Load Diff

View File

@@ -35,7 +35,6 @@ int main()
auto const result = parse("X 9 X", parser, bp::ws);
assert(result && *result == 9);
//]
(void)result;
//[ self_filling_symbol_table_after_parse
assert(!parse("X", symbols));

View File

@@ -44,23 +44,25 @@ namespace boost { namespace parser {
//]
template<typename T>
concept range_like = std::ranges::range<T> || parsable_pointer<T>;
concept utf_pointer =
std::is_pointer_v<T> && code_unit<std::iter_value_t<T>>;
template<typename T>
concept range_like =
std::ranges::range<T> || utf_pointer<std::remove_cvref_t<T>>;
template<
typename I,
typename S,
typename ErrorHandler,
typename GlobalState>
using minimal_parse_context =
decltype(detail::make_context<false, false>(
std::declval<I>(),
std::declval<S>(),
std::declval<bool &>(),
std::declval<int &>(),
std::declval<ErrorHandler const &>(),
std::declval<detail::nope &>(),
std::declval<detail::symbol_table_tries_t &>(),
std::declval<detail::nope &>()));
using minimal_parse_context = decltype(detail::make_context(
std::declval<I>(),
std::declval<S>(),
std::declval<bool &>(),
std::declval<int &>(),
std::declval<ErrorHandler const &>(),
std::declval<detail::nope &>(),
std::declval<detail::symbol_table_tries_t &>()));
template<typename T, typename I, typename S, typename GlobalState>
concept error_handler =

View File

@@ -57,9 +57,11 @@ namespace boost::parser::detail {
return out;
} else {
// Skip [0x41, 0x5a), handled above.
auto const first = text::detail::begin(mapping_ranges) + 1;
auto const first =
detail::text::detail::begin(mapping_ranges) + 1;
// 7th entry starts with 0x100.
auto const last = text::detail::begin(mapping_ranges) + 7;
auto const last =
detail::text::detail::begin(mapping_ranges) + 7;
if (auto out_opt = do_short_mapping(first, last, cp, out))
return *out_opt;
}
@@ -69,8 +71,8 @@ namespace boost::parser::detail {
// Single-cp-mapping path (next most common case).
{
auto const first = text::detail::begin(mapping_ranges);
auto const last = text::detail::end(mapping_ranges);
auto const first = detail::text::detail::begin(mapping_ranges);
auto const last = detail::text::detail::end(mapping_ranges);
if (auto out_opt = do_short_mapping(first, last, cp, out))
return *out_opt;
}
@@ -93,8 +95,8 @@ namespace boost::parser::detail {
return std::copy(
it->mapping_,
std::find(
text::detail::begin(it->mapping_),
text::detail::end(it->mapping_),
detail::text::detail::begin(it->mapping_),
detail::text::detail::end(it->mapping_),
0),
out);
#endif
@@ -104,6 +106,7 @@ namespace boost::parser::detail {
*out++ = cp;
return out;
}
}
#endif

View File

@@ -1,44 +0,0 @@
#ifndef BOOST_PARSER_DETAIL_COUNTED_ITERATOR_HPP
#define BOOST_PARSER_DETAIL_COUNTED_ITERATOR_HPP
#include <boost/parser/detail/stl_interfaces/iterator_interface.hpp>
namespace boost::parser::detail {
template<typename I, typename S>
struct counted_iterator
: stl_interfaces::iterator_interface<
counted_iterator<I, S>,
std::forward_iterator_tag,
std::remove_cv_t<
std::remove_reference_t<decltype(*std::declval<I>())>>,
decltype(*std::declval<I>())>
{
constexpr counted_iterator() = default;
constexpr explicit counted_iterator(I & it) : it_(it) {}
constexpr size_t count() const { return count_; }
constexpr bool operator==(S last) const { return it_ == last; }
constexpr I base() const { return it_; }
constexpr counted_iterator & operator++()
{
++it_;
++count_;
return this;
}
private:
friend stl_interfaces::access;
constexpr I & base_reference() { return it_; }
constexpr I base_reference() const { return it_; }
I it_ = I();
size_t count_ = 0;
};
//
}
#endif

View File

@@ -58,32 +58,6 @@ namespace boost { namespace parser { namespace detail::hl {
}
// apply
template<typename F, typename Tuple, std::size_t... I>
constexpr auto
apply_impl(F && f, Tuple && t, std::integer_sequence<std::size_t, I...>)
-> decltype(((F &&) f)(parser::get((Tuple &&) t, llong<I>{})...))
{
return ((F &&) f)(parser::get((Tuple &&) t, llong<I>{})...);
}
template<
typename F,
typename Tuple,
typename Enable = std::enable_if_t<detail::is_tuple<
std::remove_cv_t<std::remove_reference_t<Tuple>>>{}>>
constexpr auto apply(F && f, Tuple && t) -> decltype(hl::apply_impl(
(F &&) f,
(Tuple &&) t,
std::make_integer_sequence<std::size_t, tuple_size_<Tuple>>{}))
{
return hl::apply_impl(
(F &&) f,
(Tuple &&) t,
std::make_integer_sequence<std::size_t, tuple_size_<Tuple>>{});
}
// for_each
template<typename F, typename Tuple, std::size_t... I>

View File

@@ -1,458 +0,0 @@
#ifndef BOOST_PARSER_DETAIL_MEMOS_HPP
#define BOOST_PARSER_DETAIL_MEMOS_HPP
#if __has_include(<boost/unordered/unordered_flat_map.hpp>)
#include <boost/unordered/unordered_flat_map.hpp>
#define BOOST_PARSER_HAVE_BOOST_UNORDERED_FLAT_MAP 1
#define BOOST_PARSER_MEMO_NS boost_unordered_flat_map
#else
#define BOOST_PARSER_HAVE_BOOST_UNORDERED_FLAT_MAP 0
#define BOOST_PARSER_MEMO_NS std_containers
#endif
#include <algorithm>
#include <type_traits>
#include <typeinfo>
#include <unordered_map>
#include <variant> // monostate
#include <vector>
namespace boost::parser::detail {
inline constexpr unsigned int next_pot(unsigned int i)
{
--i;
i |= i >> 1;
i |= i >> 2;
i |= i >> 4;
i |= i >> 8;
i |= i >> 16;
return ++i;
}
template<int Size, int Align>
struct trivial_type
{};
template<typename T>
using trivial_type_for = trivial_type<sizeof(T), alignof(T)>;
template<typename T, int N>
struct list_node
{
list_node() = default;
list_node(list_node * n) : next(n) {}
~list_node()
{
for (int i = 0; i < size; ++i) {
void * pos = buf + i * sizeof(T);
T * obj = static_cast<T *>(pos);
obj->~T();
}
}
void * push() { return buf + size++ * sizeof(T); }
void * get(int n) { return buf + n * sizeof(T); }
alignas(T[N]) std::byte buf[sizeof(T[N])];
list_node * next = nullptr;
int size = 0;
};
template<int Size, int Align, int N>
struct list_node<trivial_type<Size, Align>, N>
{
list_node() = default;
list_node(list_node * n) : next(n) {}
~list_node() {}
void * push() { return buf + size++ * Size; }
void * get(int n) { return buf + n * Size; }
alignas(Align) std::byte buf[Size * N];
list_node * next = nullptr;
int size = 0;
};
template<typename T, int N>
struct linked_list
{
using list_node_type = list_node<T, N>;
linked_list() = default;
linked_list(linked_list const &) = delete;
linked_list & operator=(linked_list const &) = delete;
~linked_list()
{
while (head_) {
auto * node = head_;
head_ = head_->next;
delete node;
}
}
// The bool indicates whether placement new is required.
std::pair<void *, bool> push()
{
if (next_.node) {
if (next_.idx == next_.node->size) {
next_.node = next_.node->next;
next_.idx = 0;
}
if (next_.node && next_.idx < next_.node->size)
return {next_.node->get(next_.idx++), false};
}
if (!head_)
head_ = new list_node_type();
else if (head_->size == N)
head_ = new list_node_type(head_);
return {head_->push(), true};
}
void reclaim() { next_ = {head_, 0}; }
private:
struct position
{
list_node_type * node = nullptr;
int idx = 0;
};
list_node_type * head_ = nullptr;
position next_{};
};
// http://jonkagstrom.com/mx3/mx3_rev2.html
inline size_t hash_mix(size_t x)
{
size_t const m = 0xe9846af9b1a615d;
x ^= x >> 32;
x *= m;
x ^= x >> 32;
x *= m;
x ^= x >> 28;
return x;
}
inline size_t hash_combine(size_t seed) { return seed; }
template<typename T, typename... Ts>
size_t hash_combine(size_t seed, T const & x, Ts const &... xs)
{
auto next_seed =
detail::hash_mix(seed + 0x9e3779b9 + std::hash<T>{}(x));
return detail::hash_combine(next_seed, xs...);
}
struct memo_items_base
{
memo_items_base(size_t id_token)
#if !BOOST_PARSER_HAVE_BOOST_UNORDERED_FLAT_MAP
:
id_token_(id_token)
#endif
{}
virtual ~memo_items_base() = 0;
virtual std::pair<void *, bool> new_item() = 0;
virtual void reclaim() = 0;
#if !BOOST_PARSER_HAVE_BOOST_UNORDERED_FLAT_MAP
size_t const id_token_ = 0;
#endif
};
inline memo_items_base::~memo_items_base() {}
inline constexpr size_t max_tidy_bytes = 16; // TODO: Tune.
template<typename T>
constexpr bool tidy = std::is_trivially_copyable_v<T> &&
std::is_trivially_destructible_v<T> &&
sizeof(T) < max_tidy_bytes;
template<typename T>
constexpr bool fat = 256 < sizeof(T);
template<typename T, bool Fat = fat<T>>
struct memo_items_impl : memo_items_base
{
memo_items_impl() : memo_items_base(typeid(T).hash_code()) {}
virtual ~memo_items_impl() = default;
virtual std::pair<void *, bool> new_item() { return list_.push(); }
virtual void reclaim() { list_.reclaim(); }
private:
linked_list<T, 16> list_; // TODO: Try with other values of N too.
};
template<int Size, int Align, bool Fat>
struct memo_items_impl<trivial_type<Size, Align>, Fat> : memo_items_base
{
memo_items_impl() :
memo_items_base(typeid(trivial_type<Size, Align>).hash_code())
{}
virtual ~memo_items_impl() = default;
virtual std::pair<void *, bool> new_item() { return list_.push(); }
virtual void reclaim() { list_.reclaim(); }
private:
linked_list<trivial_type<Size, Align>, 64> list_;
};
template<typename T>
struct memo_items_impl<T, true> : memo_items_base
{
memo_items_impl() : memo_items_base(typeid(T).hash_code()) {}
virtual ~memo_items_impl() = default;
virtual std::pair<void *, bool> new_item() { return list_.push(); }
virtual void reclaim() { list_.reclaim(); }
private:
linked_list<T, 1> list_;
};
struct identity
{
template<typename T>
constexpr decltype(auto) operator()(T && x) const
{
return (T &&) x;
}
};
inline namespace BOOST_PARSER_MEMO_NS {
template<
typename Key,
typename OtherDatum = std::monostate,
typename Proj = identity>
struct memos
{
memos() = default;
explicit memos(Proj proj) : proj_(std::move(proj)) {}
~memos()
{
#if BOOST_PARSER_HAVE_BOOST_UNORDERED_FLAT_MAP
for (auto [key, value] : memo_items_) {
delete value;
}
#else
for (auto value : memo_items_) {
delete value;
}
#endif
}
enum kind { success, failure };
template<typename A>
struct monostate_ptr_like
{
monostate_ptr_like() : valid(false) {}
explicit monostate_ptr_like(bool v) : valid(v) {}
explicit operator bool() const { return valid; }
bool operator==(nullptr_t) const { return !valid; }
A & operator*() { return value; }
A const & operator*() const { return value; }
A value = A();
bool valid = false;
static_assert(std::is_empty_v<A>);
};
template<typename A, bool Empty = std::is_empty_v<A>>
struct ref
{
ref() = default;
ref(A * v, OtherDatum * od) : valid(true), value(v), datum(od)
{}
explicit operator bool() const { return valid; }
kind get_kind() const
{
return value == nullptr ? failure : success;
}
bool valid = false;
A * value = nullptr;
OtherDatum * datum = 0;
};
template<typename A>
struct ref<A, true>
{
ref() = default;
ref(A *, OtherDatum * od) : valid(true), value(true), datum(od)
{}
explicit operator bool() const { return valid; }
kind get_kind() const
{
return value == nullptr ? failure : success;
}
bool valid = false;
monostate_ptr_like<A> value;
OtherDatum * datum = 0;
};
template<typename A, bool Empty = std::is_empty_v<A>>
struct const_ref
{
const_ref() = default;
const_ref(A const * v, OtherDatum const * od) :
valid(true), value(v), datum(od)
{}
explicit operator bool() const { return valid; }
kind get_kind() const
{
return value == nullptr ? failure : success;
}
bool valid = false;
A const * value = nullptr;
OtherDatum const * datum = 0;
};
template<typename A>
struct const_ref<A, true>
{
const_ref() = default;
const_ref(A const *, OtherDatum const * od) :
valid(true), value(true), datum(od)
{}
explicit operator bool() const { return valid; }
kind get_kind() const
{
return value == nullptr ? failure : success;
}
bool valid = false;
monostate_ptr_like<A> value;
OtherDatum const * datum = 0;
};
template<typename P, typename A, typename... Params>
ref<A> insert(kind k, Key key, Params const &... params)
{
if constexpr (!(std::is_constructible_v<std::hash<Params>> &&
...)) {
return {};
} else {
auto const hash = detail::hash_combine(
proj_(key),
typeid(P).hash_code(),
typeid(A).hash_code(),
std::hash<Params>{}(params)...);
entry & obj_and_other = table_[hash];
if (!obj_and_other.obj && k == success) {
auto const id =
tidy<A> ? typeid(trivial_type_for<A>).hash_code()
: typeid(A).hash_code();
if (std::is_empty_v<A>) {
obj_and_other = {nullptr, OtherDatum()};
} else {
#if BOOST_PARSER_HAVE_BOOST_UNORDERED_FLAT_MAP
memo_items_base *& items = memo_items_[id];
if (!items) {
if (tidy<A>) {
items = new memo_items_impl<
trivial_type_for<A>>;
} else {
items = new memo_items_impl<A>;
}
}
auto [pos, needs_construction] = items->new_item();
A * obj = needs_construction
? new (pos) A()
: static_cast<A *>(pos);
obj_and_other = {obj, OtherDatum()};
#else
auto it = std::lower_bound(
memo_items_.begin(),
memo_items_.end(),
id,
[](memo_items_base * base, size_t id) {
return base->id_token_ < id;
});
if (it == memo_items_.end() ||
(*it)->id_token_ != id) {
if (tidy<A>) {
it = memo_items_.insert(
it,
new memo_items_impl<
trivial_type_for<A>>);
} else {
it = memo_items_.insert(
it, new memo_items_impl<A>);
}
}
auto [pos, needs_construction] = (*it)->new_item();
A * obj = needs_construction
? new (pos) A()
: static_cast<A *>(pos);
obj_and_other = {obj, OtherDatum()};
#endif
}
}
return {
static_cast<A *>(obj_and_other.obj),
&obj_and_other.datum};
}
}
template<typename P, typename A, typename... Params>
const_ref<A> find(Key key, Params const &... params) const
{
if constexpr (!(std::is_constructible_v<std::hash<Params>> &&
...)) {
return {};
} else {
auto const hash = detail::hash_combine(
proj_(key),
typeid(P).hash_code(),
typeid(A).hash_code(),
std::hash<Params>{}(params)...);
auto it = table_.find(hash);
if (it == table_.end()) {
return {};
} else {
return {
static_cast<A const *>(it->second.obj),
&it->second.datum};
}
}
}
void reclaim()
{
#if BOOST_PARSER_HAVE_BOOST_UNORDERED_FLAT_MAP
for (auto [key, items] : memo_items_) {
items->reclaim();
}
#else
for (auto items : memo_items_) {
items->reclaim();
}
#endif
table_.clear();
}
// For testing.
size_t item_stores() const { return memo_items_.size(); }
size_t items() const { return table_.size(); }
private:
struct entry
{
void * obj;
[[maybe_unused]] OtherDatum datum;
};
#if BOOST_PARSER_HAVE_BOOST_UNORDERED_FLAT_MAP
boost::unordered_flat_map<size_t, memo_items_base *> memo_items_;
boost::unordered_flat_map<size_t, entry> table_;
#else
std::vector<memo_items_base *> memo_items_;
std::unordered_map<size_t, entry> table_;
#endif
Proj proj_;
};
}
}
#endif

View File

@@ -12,34 +12,12 @@
#ifndef BOOST_PARSER_DETAIL_NUMERIC_HPP
#define BOOST_PARSER_DETAIL_NUMERIC_HPP
#include <boost/parser/detail/text/unpack.hpp>
#include <version>
#if defined(__cpp_lib_to_chars)
#include <charconv>
#define BOOST_PARSER_HAVE_STD_CHARCONV
#define BOOST_PARSER_NUMERIC_NS std_charconv
#elif __has_include(<boost/charconv.hpp>)
#include <boost/charconv.hpp>
#define BOOST_PARSER_HAVE_BOOST_CHARCONV
#define BOOST_PARSER_NUMERIC_NS boost_charconv
#else
#define BOOST_PARSER_NUMERIC_NS spirit_parsers
#endif
#include <type_traits>
#include <cmath>
#if defined(BOOST_PARSER_HAVE_STD_CHARCONV) || \
defined(BOOST_PARSER_HAVE_BOOST_CHARCONV)
#define BOOST_PARSER_HAVE_CHARCONV
#endif
namespace boost { namespace parser { namespace detail_spirit_x3 {
namespace boost::parser::detail_spirit_x3 {
struct unused_type
{};
struct unused_type{};
// Copied from boost/spirit/home/support/char_class.hpp (Boost 1.71), and
// modified not to use Boost.TypeTraits.
@@ -985,106 +963,7 @@ namespace boost::parser::detail_spirit_x3 {
{
static bool const expect_dot = true;
};
}
namespace boost::parser::detail::numeric {
template<typename I, typename S>
constexpr bool common_range = std::is_same_v<I, S>;
template<typename I, typename S>
using unpacked_iter = decltype(text::unpack_iterator_and_sentinel(
std::declval<I>(), std::declval<S>())
.first);
template<typename I, typename S>
constexpr bool unpacks_to_chars =
std::is_pointer_v<unpacked_iter<I, S>> && std::is_same_v<
std::remove_cv_t<std::remove_reference_t<
std::remove_pointer_t<unpacked_iter<I, S>>>>,
char>;
inline namespace BOOST_PARSER_NUMERIC_NS {
template<int MinDigits, int MaxDigits, typename I, typename S>
#if defined(BOOST_PARSER_HAVE_CHARCONV)
constexpr bool use_charconv_int =
MinDigits == 1 && MaxDigits == -1 &&
common_range<I, S> && unpacks_to_chars<I, S>;
#else
constexpr bool use_charconv_int = false;
#endif
template<
bool Signed,
int Radix,
int MinDigits,
int MaxDigits,
typename I,
typename S,
typename T>
bool parse_int(I & first, S last, T & attr)
{
if constexpr (use_charconv_int<MinDigits, MaxDigits, I, S>) {
#if defined(BOOST_PARSER_HAVE_CHARCONV)
auto unpacked = text::unpack_iterator_and_sentinel(first, last);
#if defined(BOOST_PARSER_HAVE_STD_CHARCONV)
std::from_chars_result const result = std::from_chars(
#else
charconv::from_chars_result const result = charconv::from_chars(
#endif
unpacked.first, unpacked.last, attr, Radix);
if (result.ec == std::errc()) {
first = unpacked.repack(result.ptr);
return true;
}
return false;
#endif
} else if constexpr (Signed) {
using extract = detail_spirit_x3::
extract_int<T, Radix, MinDigits, MaxDigits>;
return extract::call(first, last, attr);
} else {
using extract = detail_spirit_x3::
extract_uint<T, Radix, MinDigits, MaxDigits>;
return extract::call(first, last, attr);
}
}
template<typename I, typename S>
#if defined(BOOST_PARSER_HAVE_CHARCONV)
constexpr bool use_charconv_real =
common_range<I, S> && unpacks_to_chars<I, S>;
#else
constexpr bool use_charconv_real = false;
#endif
template<typename I, typename S, typename T>
bool parse_real(I & first, S last, T & attr)
{
if constexpr (use_charconv_real<I, S>) {
#if defined(BOOST_PARSER_HAVE_CHARCONV)
auto unpacked = text::unpack_iterator_and_sentinel(first, last);
#if defined(BOOST_PARSER_HAVE_STD_CHARCONV)
std::from_chars_result const result = std::from_chars(
#else
charconv::from_chars_result const result = charconv::from_chars(
#endif
unpacked.first, unpacked.last, attr);
if (result.ec == std::errc()) {
first = unpacked.repack(result.ptr);
return true;
}
return false;
#endif
} else {
detail_spirit_x3::real_policies<T> policies;
using extract = detail_spirit_x3::
extract_real<T, detail_spirit_x3::real_policies<T>>;
return extract::parse(first, last, attr, policies);
}
}
}
}
}}}
#endif

View File

@@ -71,13 +71,6 @@ namespace boost { namespace parser { namespace detail {
std::ostream & os,
int components = 0);
template<typename Context, typename ParserTuple>
void print_parser(
Context const & context,
perm_parser<ParserTuple> const & parser,
std::ostream & os,
int components = 0);
template<
typename Context,
typename ParserTuple,
@@ -97,13 +90,6 @@ namespace boost { namespace parser { namespace detail {
std::ostream & os,
int components = 0);
template<typename Context, typename Parser, typename F>
void print_parser(
Context const & context,
transform_parser<Parser, F> const & parser,
std::ostream & os,
int components = 0);
template<typename Context, typename Parser>
void print_parser(
Context const & context,
@@ -278,13 +264,6 @@ namespace boost { namespace parser { namespace detail {
std::ostream & os,
int components = 0);
template<typename Context, typename Quotes, typename Escapes>
void print_parser(
Context const & context,
quoted_string_parser<Quotes, Escapes> const & parser,
std::ostream & os,
int components = 0);
template<typename Context, bool NewlinesOnly, bool NoNewlines>
void print_parser(
Context const & context,
@@ -575,7 +554,6 @@ namespace boost { namespace parser { namespace detail {
auto resolve(Context const &, nope n);
template<
bool DoTrace,
typename Iter,
typename Sentinel,
typename Context,
@@ -629,16 +607,6 @@ namespace boost { namespace parser { namespace detail {
std::string name_;
};
template<
typename Iter,
typename Sentinel,
typename Context,
typename Attribute>
struct scoped_trace_t<false, Iter, Sentinel, Context, Attribute>
{
scoped_trace_t() {}
};
template<
typename Parser,
typename Iter,
@@ -653,14 +621,11 @@ namespace boost { namespace parser { namespace detail {
flags f,
Attribute const & attr)
{
if constexpr (Context::do_trace) {
std::stringstream oss;
std::stringstream oss;
if (detail::do_trace(f))
detail::print_parser(context, parser, oss);
return scoped_trace_t<true, Iter, Sentinel, Context, Attribute>(
first, last, context, f, attr, oss.str());
} else {
return scoped_trace_t<false, Iter, Sentinel, Context, Attribute>{};
}
return scoped_trace_t<Iter, Sentinel, Context, Attribute>(
first, last, context, f, attr, oss.str());
}
template<typename Context, typename Attribute>

View File

@@ -10,29 +10,25 @@
#endif
#include <boost/type_index.hpp>
#define BOOST_PARSER_HAVE_BOOST_TYPEINDEX 1
#define BOOST_PARSER_TYPE_NAME_NS boost_type_index
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
#else
#include <typeinfo>
#define BOOST_PARSER_HAVE_BOOST_TYPEINDEX 0
#define BOOST_PARSER_TYPE_NAME_NS std_typeinfo
#endif
namespace boost { namespace parser { namespace detail {
inline namespace BOOST_PARSER_TYPE_NAME_NS {
template<typename T>
auto type_name()
{
template<typename T>
auto type_name()
{
#if BOOST_PARSER_HAVE_BOOST_TYPEINDEX
return typeindex::type_id<T>().pretty_name();
return typeindex::type_id<T>().pretty_name();
#else
return typeid(T).name();
return typeid(T).name();
#endif
}
}
template<typename Parser>
@@ -63,10 +59,6 @@ namespace boost { namespace parser { namespace detail {
struct n_aray_parser<or_parser<ParserTuple>> : std::true_type
{};
template<typename ParserTuple>
struct n_aray_parser<perm_parser<ParserTuple>> : std::true_type
{};
template<
typename ParserTuple,
typename BacktrackingTuple,
@@ -169,32 +161,6 @@ namespace boost { namespace parser { namespace detail {
os << ")";
}
template<typename Context, typename Parser>
void print_or_like_parser(
Context const & context,
Parser const & parser,
std::ostream & os,
int components,
std::string_view or_ellipsis,
std::string_view ws_or)
{
int i = 0;
bool printed_ellipsis = false;
hl::for_each(parser.parsers_, [&](auto const & parser) {
if (components == parser_component_limit) {
if (!printed_ellipsis)
os << or_ellipsis;
printed_ellipsis = true;
return;
}
if (i)
os << ws_or;
detail::print_parser(context, parser, os, components);
++components;
++i;
});
}
template<typename Context, typename ParserTuple>
void print_parser(
Context const & context,
@@ -202,19 +168,21 @@ namespace boost { namespace parser { namespace detail {
std::ostream & os,
int components)
{
detail::print_or_like_parser(
context, parser, os, components, " | ...", " | ");
}
template<typename Context, typename ParserTuple>
void print_parser(
Context const & context,
perm_parser<ParserTuple> const & parser,
std::ostream & os,
int components)
{
detail::print_or_like_parser(
context, parser, os, components, " || ...", " || ");
int i = 0;
bool printed_ellipsis = false;
hl::for_each(parser.parsers_, [&](auto const & parser) {
if (components == parser_component_limit) {
if (!printed_ellipsis)
os << " | ...";
printed_ellipsis = true;
return;
}
if (i)
os << " | ";
detail::print_parser(context, parser, os, components);
++components;
++i;
});
}
template<
@@ -258,7 +226,7 @@ namespace boost { namespace parser { namespace detail {
detail::print_parser(context, parser, os, components);
++components;
++i;
prev_group = (int)group;
prev_group = group;
});
if (prev_group && !printed_ellipsis)
os << ']';
@@ -291,17 +259,6 @@ namespace boost { namespace parser { namespace detail {
os << "]";
}
template<typename Context, typename Parser, typename F>
void print_parser(
Context const & context,
transform_parser<Parser, F> const & parser,
std::ostream & os,
int components)
{
detail::print_directive(
context, "transform(<<f>>)", parser.parser_, os, components);
}
template<typename Context, typename Parser>
void print_parser(
Context const & context,
@@ -482,7 +439,8 @@ namespace boost { namespace parser { namespace detail {
template<
typename Context,
typename ResolvedExpected,
bool Integral = std::is_integral<ResolvedExpected>{}>
bool Integral = std::is_integral<ResolvedExpected>{},
int SizeofExpected = sizeof(ResolvedExpected)>
struct print_expected_char_impl
{
static void call(
@@ -494,17 +452,13 @@ namespace boost { namespace parser { namespace detail {
}
};
template<typename Context>
struct print_expected_char_impl<Context, char32_t, true>
template<typename Context, typename Expected>
struct print_expected_char_impl<Context, Expected, true, 4>
{
static void
call(Context const & context, std::ostream & os, char32_t expected)
call(Context const & context, std::ostream & os, Expected expected)
{
if (expected == '\'') {
os << "'\\''";
return;
}
std::array<char32_t, 1> cps = {{expected}};
std::array<char32_t, 1> cps = {{(char32_t)expected}};
auto const r = cps | text::as_utf8;
os << "'";
for (auto c : r) {
@@ -692,27 +646,6 @@ namespace boost { namespace parser { namespace detail {
os << "\"";
}
template<typename Context, typename Quotes, typename Escapes>
void print_parser(
Context const & context,
quoted_string_parser<Quotes, Escapes> const & parser,
std::ostream & os,
int components)
{
os << "quoted_string(";
if constexpr (is_nope_v<Quotes>) {
detail::print_expected_char_impl<Context, char32_t>::call(
context, os, parser.ch_);
} else {
os << '"';
for (auto c : parser.chs_ | text::as_utf8) {
detail::print_char(os, c);
}
os << '"';
}
os << ')';
}
template<typename Context, bool NewlinesOnly, bool NoNewlines>
void print_parser(
Context const & context,
@@ -892,12 +825,11 @@ namespace boost { namespace parser { namespace detail {
int components)
{
using namespace literals;
os << "(";
detail::print(
os,
detail::resolve(
context, parser::get(parser.parsers_, 0_c).pred_.value_));
os << ", ";
os << "("
<< detail::resolve(
context, parser::get(parser.parsers_, 0_c).pred_.value_)
<< ", ";
detail::print_parser(
context, parser::get(parser.parsers_, 1_c), os, components);
os << ")";

View File

@@ -131,7 +131,8 @@ namespace boost::parser::detail::text::detail {
constexpr all_impl all;
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS && \
(!defined(__GNUC__) || 12 <= __GNUC__)
template<typename R>
using all_t = std::views::all_t<R>;
#else

View File

@@ -383,7 +383,7 @@ namespace boost::parser::detail { namespace text {
boost::parser::detail::text::continuation(*--retval)) {
++backup;
}
backup = (int)std::distance(retval, it);
backup = std::distance(retval, it);
if (boost::parser::detail::text::continuation(*retval)) {
if (it != first)
@@ -396,7 +396,7 @@ namespace boost::parser::detail { namespace text {
++*first_invalid;
while (first_invalid &&
std::distance(retval, *first_invalid) < backup) {
backup -= (int)std::distance(retval, *first_invalid);
backup -= std::distance(retval, *first_invalid);
retval = *first_invalid;
first_invalid = end_of_invalid_utf8(retval);
if (first_invalid == retval)
@@ -2568,42 +2568,6 @@ namespace boost::parser::detail { namespace text {
};
}
namespace detail {
struct iter_access
{
template<typename T>
static auto & buf(T & it)
{
return it.buf_;
}
template<typename T>
static auto & first_and_curr(T & it)
{
return it.first_and_curr_;
}
template<typename T>
static auto & buf_index(T & it)
{
return it.buf_index_;
}
template<typename T>
static auto & buf_last(T & it)
{
return it.buf_last_;
}
template<typename T>
static auto & to_increment(T & it)
{
return it.to_increment_;
}
template<typename T>
static auto & last(T & it)
{
return it.last_;
}
};
}
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<
format FromFormat,
@@ -2677,7 +2641,7 @@ namespace boost::parser::detail { namespace text {
#if !BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<
typename J = I,
typename Enable = std::enable_if_t<!is_bidirectional<J>>>
typename Enable = std::enable_if_t<is_bidirectional<J>>>
#endif
constexpr utf_iterator(I it, S last)
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
@@ -2705,12 +2669,11 @@ namespace boost::parser::detail { namespace text {
constexpr utf_iterator(
utf_iterator<FromFormat, ToFormat, I2, S2, ErrorHandler> const &
other) :
buf_(detail::iter_access::buf(other)),
first_and_curr_(detail::iter_access::first_and_curr(other)),
buf_index_(detail::iter_access::buf_index(other)),
buf_last_(detail::iter_access::buf_last(other)),
to_increment_(detail::iter_access::to_increment(other)),
last_(detail::iter_access::last(other))
buf_(other.buf_),
first_and_curr_(other.first_and_curr_),
buf_index_(other.buf_index_),
buf_last_(other.buf_last_),
last_(other.last_)
{}
#if !BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
@@ -3218,7 +3181,7 @@ namespace boost::parser::detail { namespace text {
auto it = encode_code_point(cp, buf_.begin());
buf_last_ = uint8_t(it - buf_.begin());
buf_index_ = buf_last_ - 1;
to_increment_ = (int)std::distance(curr(), initial);
to_increment_ = std::distance(curr(), initial);
} else {
auto buf = buf_;
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
@@ -3254,17 +3217,33 @@ namespace boost::parser::detail { namespace text {
constexpr I & curr() { return first_and_curr_.curr; }
constexpr I curr() const { return first_and_curr_.curr; }
std::array<value_type, 4 / static_cast<int>(ToFormat)> buf_ = {};
std::array<value_type, 4 / static_cast<int>(ToFormat)> buf_;
detail::first_and_curr<I> first_and_curr_ = {};
detail::first_and_curr<I> first_and_curr_;
uint8_t buf_index_ = 0;
uint8_t buf_last_ = 0;
uint8_t to_increment_ = 0;
[[no_unique_address]] S last_ = {};
[[no_unique_address]] S last_;
friend struct detail::iter_access;
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<
format FromFormat2,
format ToFormat2,
std::input_iterator I2,
std::sentinel_for<I2> S2,
transcoding_error_handler ErrorHandler2>
requires std::convertible_to<std::iter_value_t<I2>, detail::format_to_type_t<FromFormat2>>
#else
template<
format FromFormat2,
format ToFormat2,
typename I2,
typename S2,
typename ErrorHandler2>
#endif
friend class utf_iterator;
};
}}

View File

@@ -44,13 +44,27 @@ namespace boost::parser::detail { namespace text {
using iterator_to_tag_t = decltype(iterator_to_tag<I>());
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
#if defined(__GNUC__) && __GNUC__ < 12
// This uses the final version of viewable_range. Older GCCs use a
// different one that breaks, so we use this on instead of the one
// from std::ranges::. It's missing the !initializer_list part.
template<typename T>
concept viewable_range = std::ranges::range<T> &&
((std::ranges::view<std::remove_cvref_t<T>> &&
std::constructible_from<std::remove_cvref_t<T>, T>) ||
(!std::ranges::view<std::remove_cvref_t<T>> &&
(std::is_lvalue_reference_v<T> ||
std::movable<std::remove_reference_t<T>>)));
#else
template<typename T>
concept viewable_range = std::ranges::viewable_range<T>;
#endif
template<class T>
using with_reference = T &;
template<typename T>
concept can_reference = requires { typename with_reference<T>; };
#endif
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<class Char>
struct cast_to_charn {
constexpr Char operator()(Char c) const { return c; }
@@ -265,7 +279,7 @@ namespace boost::parser::detail { namespace text {
#if BOOST_PARSER_DETAIL_TEXT_USE_ALIAS_CTAD
template<class R, auto F>
project_view(R &&) -> project_view<std::views::all_t<R>, F>;
project_view(R &&) -> project_view<detail::all_t<R>, F>;
#endif
namespace detail {
@@ -281,7 +295,7 @@ namespace boost::parser::detail { namespace text {
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<class R>
requires std::ranges::viewable_range<R> &&
requires viewable_range<R> &&
std::ranges::input_range<R> &&
std::regular_invocable<decltype(F)&, std::ranges::range_reference_t<R>> &&
detail::can_reference<std::invoke_result_t<decltype(F)&, std::ranges::range_reference_t<R>>>
@@ -328,11 +342,7 @@ namespace boost::parser::detail { namespace text {
#endif
{
public:
constexpr char8_view()
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
requires std::default_initializable<V>
#endif
= default;
constexpr char8_view() requires std::default_initializable<V> = default;
constexpr char8_view(V base) :
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
project_view<V, detail::cast_to_charn<char8_t>{}>{std::move(base)}
@@ -406,7 +416,7 @@ namespace boost::parser::detail { namespace text {
{
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<class R>
requires (std::ranges::viewable_range<R> &&
requires (viewable_range<R> &&
std::ranges::input_range<R> &&
std::convertible_to<std::ranges::range_reference_t<R>, format_to_type_t<Format>>) ||
utf_pointer<std::remove_cvref_t<R>>
@@ -610,7 +620,7 @@ namespace boost::parser::detail { namespace text {
#if BOOST_PARSER_DETAIL_TEXT_USE_ALIAS_CTAD
template<format Format, class R>
utf_view(R &&) -> utf_view<Format, std::views::all_t<R>>;
utf_view(R &&) -> utf_view<Format, detail::all_t<R>>;
template<class V>
using utf8_view = utf_view<format::utf8, V>;
@@ -761,7 +771,7 @@ namespace boost::parser::detail { namespace text {
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<class R>
requires is_utf_view<std::remove_cvref_t<R>> ||
(std::ranges::viewable_range<R> &&
(viewable_range<R> &&
can_utf_view<unpacked_range<R>, View>) ||
utf_pointer<std::remove_cvref_t<R>>
#else

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,6 @@
#include <boost/parser/detail/text/algorithm.hpp>
#include <boost/parser/detail/text/transcode_iterator.hpp>
#include <algorithm>
#include <array>
#include <functional>
#include <iostream>

File diff suppressed because it is too large Load Diff

View File

@@ -8,9 +8,7 @@
#include <boost/parser/config.hpp>
#include <boost/parser/error_handling_fwd.hpp>
#include <boost/parser/detail/memos.hpp>
#include <any>
#include <cstdint>
#include <map>
#include <memory>
@@ -45,20 +43,6 @@ namespace boost { namespace parser {
constexpr bool enable_variant<std::variant<Ts...>> = true;
#endif
/** A type trait that evaluates to the attribute type for parser `Parser`
used to parse range `R`, as if by calling `parse(r, parser)`, using
some `R r` and `Parser parser`. Note that this implies that pointers
to null-terminated strings are supported types for `R`. The result is
not wrapped in a `std::optional` like the result of a call to
`parse()` would be. If `Parser` produces no attribute, the result is
the no-attribute sentinel type `none`. */
template<typename R, typename Parser>
struct attribute;
/** An alias for `typename attribute<R, Parser>::type`. */
template<typename R, typename Parser>
using attribute_t = typename attribute<R, Parser>::type;
namespace detail {
template<typename T>
constexpr bool is_optional_v = enable_optional<T>;
@@ -72,16 +56,71 @@ namespace boost { namespace parser {
in_apply_parser = 1 << 3
};
using symbol_table_tries_t =
std::map<void *, std::pair<std::any, bool>, std::less<void *>>;
struct any_copyable
{
template<
typename T,
typename Enable = std::enable_if_t<!std::is_reference_v<T>>>
any_copyable(T && v) :
impl_(new holder<std::decay_t<T>>(std::move(v)))
{}
template<typename T>
any_copyable(T const & v) : impl_(new holder<T>(v))
{}
template<
bool DoTrace,
bool UseCallbacks,
typename Iter,
typename Sentinel,
typename ErrorHandler,
typename Memos>
any_copyable() = default;
any_copyable(any_copyable const & other)
{
if (other.impl_)
impl_ = other.impl_->clone();
}
any_copyable & operator=(any_copyable const & other)
{
any_copyable temp(other);
swap(temp);
return *this;
}
any_copyable(any_copyable &&) = default;
any_copyable & operator=(any_copyable &&) = default;
bool empty() const { return impl_.get() == nullptr; }
template<typename T>
T & cast() const
{
BOOST_PARSER_DEBUG_ASSERT(impl_);
BOOST_PARSER_DEBUG_ASSERT(dynamic_cast<holder<T> *>(impl_.get()));
return static_cast<holder<T> *>(impl_.get())->value_;
}
void swap(any_copyable & other) { std::swap(impl_, other.impl_); }
private:
struct holder_base
{
virtual ~holder_base() {}
virtual std::unique_ptr<holder_base> clone() const = 0;
};
template<typename T>
struct holder : holder_base
{
holder(T && v) : value_(std::move(v)) {}
holder(T const & v) : value_(v) {}
virtual ~holder() {}
virtual std::unique_ptr<holder_base> clone() const
{
return std::unique_ptr<holder_base>(new holder<T>{value_});
}
T value_;
};
std::unique_ptr<holder_base> impl_;
};
using symbol_table_tries_t =
std::map<void *, any_copyable, std::less<void *>>;
template<typename Iter, typename Sentinel, typename ErrorHandler>
inline auto make_context(
Iter first,
Sentinel last,
@@ -89,8 +128,7 @@ namespace boost { namespace parser {
int & indent,
ErrorHandler const & error_handler,
nope &,
symbol_table_tries_t & symbol_table_tries,
Memos & memos) noexcept;
symbol_table_tries_t & symbol_table_tries) noexcept;
struct skip_skipper;
@@ -171,17 +209,6 @@ namespace boost { namespace parser {
template<typename ParserTuple>
struct or_parser;
/** Applies each parsers in `ParserTuple`, an any order, stopping after
all of them have matched the input. The parse succeeds iff all the
parsers match, regardless of the order in which they do. The
attribute produced is a `parser::tuple` containing the attributes of
the subparsers, in their order of the parsers' appearance in
`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>
struct perm_parser;
/** Applies each parser in `ParserTuple`, in order. The parse succeeds
iff all of the sub-parsers succeed. The attribute produced is a
`std::tuple` over the types of attribute produced by the parsers in
@@ -202,14 +229,6 @@ namespace boost { namespace parser {
template<typename Parser, typename Action>
struct action_parser;
/** Applies the given parser `p` of type `Parser`. The attribute produced
by `p` is passed to the fiven invocable `f` of type `F`. `f` will
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>
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`
@@ -345,17 +364,12 @@ namespace boost { namespace parser {
character being matched. */
struct digit_parser;
/** Matches a particular string, delimited by an iterator sentinel pair;
/** Maches a particular string, delimited by an iterator sentinel pair;
produces no attribute. */
template<typename StrIter, typename StrSentinel>
struct string_parser;
/** Matches a string delimited by quotation marks; produces a
`std::string` attribute. */
template<typename Quotes = detail::nope, typename Escapes = detail::nope>
struct quoted_string_parser;
/** Matches an end-of-line (`NewlinesOnly == true`), whitespace
/** Maches an end-of-line (`NewlinesOnly == true`), whitespace
(`NewlinesOnly == false`), or (`NoNewlines == true`) blank (whitespace
but not newline) code point, based on the Unicode definitions of each
(also matches the two code points `"\r\n"`). Produces no
@@ -363,7 +377,7 @@ namespace boost { namespace parser {
template<bool NewlinesOnly, bool NoNewlines>
struct ws_parser;
/** Matches the strings "true" and "false", producing an attribute of
/** Maches the strings "true" and "false", producing an attribute of
`true` or `false`, respectively, and fails on any other input. */
struct bool_parser;
@@ -420,8 +434,7 @@ namespace boost { namespace parser {
template<
typename Parser,
typename GlobalState = detail::nope,
typename ErrorHandler = default_error_handler,
bool Memoize = false>
typename ErrorHandler = default_error_handler>
struct parser_interface;
using no_attribute = detail::nope;
@@ -449,14 +462,13 @@ namespace boost { namespace parser {
typename ParamsTuple = no_params>
struct callback_rule;
#ifdef BOOST_PARSER_DOXYGEN
/** Returns a reference to the attribute(s) (i.e. return value) of the
bottommost parser; multiple attributes will be stored within a
`parser::tuple`. You may write to this value in a semantic action to
control what attribute value(s) the associated parser produces.
Returns `none` if the bottommost parser does produce an attribute. */
template<typename Context>
decltype(auto) _val(Context const & context);
#endif
/** Returns a reference to the attribute or attributes already produced by
the bottommost parser; multiple attributes will be stored within a
@@ -515,13 +527,9 @@ namespace boost { namespace parser {
/** Report that the error described in `message` occurred at `location`,
using the context's error handler. */
#if BOOST_PARSER_USE_CONCEPTS
template<std::forward_iterator I, typename Context>
#else
template<typename I, typename Context>
#endif
template<typename Iter, typename Context>
void _report_error(
Context const & context, std::string_view message, I location);
Context const & context, std::string_view message, Iter location);
/** Report that the error described in `message` occurred at
`_where(context).begin()`, using the context's error handler. */
@@ -530,13 +538,9 @@ namespace boost { namespace parser {
/** Report that the warning described in `message` occurred at `location`,
using the context's error handler. */
#if BOOST_PARSER_USE_CONCEPTS
template<std::forward_iterator I, typename Context>
#else
template<typename I, typename Context>
#endif
template<typename Iter, typename Context>
void _report_warning(
Context const & context, std::string_view message, I location);
Context const & context, std::string_view message, Iter location);
/** Report that the warning described in `message` occurred at
`_where(context).begin()`, using the context's error handler. */

View File

@@ -193,12 +193,7 @@ namespace boost::parser {
/** Produces a range of subranges of a given range `base`. Each subrange
is either a subrange of `base` that does not match the given parser
`parser`, or is the given replacement for a match, `replacement`.
In addition to the template parameter constraints, `V` and
`ReplacementV` must be ranges of `char`, or must have the same UTF
format, and `V` and `ReplacementV` must meet the same compatibility
requirements as described in `std::ranges::join_view`. */
`parser`, or is the given replacement for a match, `replacement`. */
template<
#if BOOST_PARSER_USE_CONCEPTS
std::ranges::viewable_range V,
@@ -210,7 +205,6 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser
#if !BOOST_PARSER_USE_CONCEPTS
,
@@ -232,14 +226,12 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize,
SkipParser>>
{
constexpr replace_view() = default;
constexpr replace_view(
V base,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser,
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
parser_interface<SkipParser> const & skip,
ReplacementV replacement,
trace trace_mode = trace::off) :
@@ -251,8 +243,7 @@ namespace boost::parser {
{}
constexpr replace_view(
V base,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser,
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
ReplacementV replacement,
trace trace_mode = trace::off) :
base_(std::move(base)),
@@ -399,7 +390,7 @@ namespace boost::parser {
private:
V base_;
ReplacementV replacement_;
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> parser_;
parser_interface<Parser, GlobalState, ErrorHandler> parser_;
parser_interface<SkipParser> skip_;
trace trace_mode_;
};
@@ -411,11 +402,10 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
replace_view(
V &&,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
parser_interface<Parser, GlobalState, ErrorHandler>,
parser_interface<SkipParser>,
ReplacementV &&,
trace)
@@ -425,7 +415,6 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize,
SkipParser>;
template<
@@ -434,11 +423,10 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
replace_view(
V &&,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
parser_interface<Parser, GlobalState, ErrorHandler>,
parser_interface<SkipParser>,
ReplacementV &&)
-> replace_view<
@@ -447,7 +435,6 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize,
SkipParser>;
template<
@@ -455,11 +442,10 @@ namespace boost::parser {
typename ReplacementV,
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize>
typename ErrorHandler>
replace_view(
V &&,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
parser_interface<Parser, GlobalState, ErrorHandler>,
ReplacementV &&,
trace)
-> replace_view<
@@ -468,7 +454,6 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize,
parser_interface<eps_parser<detail::phony>>>;
template<
@@ -476,11 +461,10 @@ namespace boost::parser {
typename ReplacementV,
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize>
typename ErrorHandler>
replace_view(
V &&,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
parser_interface<Parser, GlobalState, ErrorHandler>,
ReplacementV &&)
-> replace_view<
detail::text::detail::all_t<V>,
@@ -488,7 +472,6 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize,
parser_interface<eps_parser<detail::phony>>>;
namespace detail {
@@ -498,7 +481,6 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
typename Memoize,
typename SkipParser>
using replace_view_expr = decltype(replace_view<
V,
@@ -506,14 +488,10 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize::value,
SkipParser>(
std::declval<V>(),
std::declval<parser_interface<
Parser,
GlobalState,
ErrorHandler,
Memoize::value> const &>(),
std::declval<
parser_interface<Parser, GlobalState, ErrorHandler> const &>(),
std::declval<parser_interface<SkipParser> const &>(),
std::declval<ReplacementV>(),
trace::on));
@@ -524,7 +502,6 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
constexpr bool can_replace_view = is_detected_v<
replace_view_expr,
@@ -533,7 +510,6 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
std::bool_constant<Memoize>,
SkipParser>;
struct replace_impl
@@ -546,7 +522,6 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
requires
// clang-format off
@@ -565,12 +540,11 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize,
SkipParser>
// clang-format off
[[nodiscard]] constexpr auto operator()(
R && r,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser_interface<Parser, GlobalState, ErrorHandler> const &
parser,
parser_interface<SkipParser> const & skip,
ReplacementR && replacement,
@@ -594,8 +568,7 @@ namespace boost::parser {
range_like ReplacementR,
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize>
typename ErrorHandler>
requires
// clang-format off
(std::is_pointer_v<std::remove_cvref_t<R>> ||
@@ -613,12 +586,11 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize,
parser_interface<eps_parser<detail::phony>>>
// clang-format off
[[nodiscard]] constexpr auto operator()(
R && r,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser_interface<Parser, GlobalState, ErrorHandler> const &
parser,
ReplacementR && replacement,
trace trace_mode = trace::off) const
@@ -639,18 +611,14 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser,
typename ReplacementR = trace,
typename Trace = trace,
typename Enable = std::enable_if_t<is_parsable_range_like_v<R>>>
[[nodiscard]] constexpr auto operator()(
R && r,
parser_interface<
Parser,
GlobalState,
ErrorHandler,
Memoize> const & parser,
parser_interface<Parser, GlobalState, ErrorHandler> const &
parser,
SkipParser && skip,
ReplacementR && replacement = ReplacementR{},
Trace trace_mode = Trace{}) const
@@ -693,15 +661,11 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
[[nodiscard]] constexpr auto impl(
R && r,
parser_interface<
Parser,
GlobalState,
ErrorHandler,
Memoize> const & parser,
parser_interface<Parser, GlobalState, ErrorHandler> const &
parser,
parser_interface<SkipParser> const & skip,
ReplacementR && replacement,
trace trace_mode = trace::off) const
@@ -740,7 +704,6 @@ template<
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
constexpr bool std::ranges::enable_borrowed_range<boost::parser::replace_view<
V,
@@ -748,7 +711,6 @@ constexpr bool std::ranges::enable_borrowed_range<boost::parser::replace_view<
Parser,
GlobalState,
ErrorHandler,
Memoize,
SkipParser>> = std::ranges::enable_borrowed_range<V> &&
std::ranges::enable_borrowed_range<ReplacementV>;
#endif

View File

@@ -93,12 +93,10 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
auto search_impl(
R && r,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser,
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
parser_interface<SkipParser> const & skip,
trace trace_mode)
{
@@ -129,7 +127,6 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
#if BOOST_PARSER_USE_CONCEPTS
std::ranges::borrowed_subrange_t<R>
@@ -138,8 +135,7 @@ namespace boost::parser {
#endif
search_repack_shim(
R && r,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser,
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
parser_interface<SkipParser> const & skip,
trace trace_mode)
{
@@ -176,7 +172,6 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser
#if !BOOST_PARSER_USE_CONCEPTS
,
@@ -185,8 +180,7 @@ namespace boost::parser {
>
auto search(
R && r,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser,
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
parser_interface<SkipParser> const & skip,
trace trace_mode = trace::off)
{
@@ -216,13 +210,11 @@ namespace boost::parser {
detail::is_parsable_iter_v<I> &&
detail::is_equality_comparable_with_v<I, S>>
#endif
,
bool Memoize>
>
auto search(
I first,
S last,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser,
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
parser_interface<SkipParser> const & skip,
trace trace_mode = trace::off)
{
@@ -242,8 +234,7 @@ namespace boost::parser {
#endif
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize
typename ErrorHandler
#if !BOOST_PARSER_USE_CONCEPTS
,
typename Enable = std::enable_if_t<detail::is_parsable_range_like_v<R>>
@@ -251,8 +242,7 @@ namespace boost::parser {
>
auto search(
R && r,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser,
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
trace trace_mode = trace::off)
{
return parser::search(
@@ -283,13 +273,11 @@ namespace boost::parser {
detail::is_parsable_iter_v<I> &&
detail::is_equality_comparable_with_v<I, S>>
#endif
,
bool Memoize>
>
auto search(
I first,
S last,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser,
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
trace trace_mode = trace::off)
{
return parser::search(
@@ -301,7 +289,7 @@ namespace boost::parser {
/** Produces a sequence of subranges of the underlying sequence of type
`V`. Each subrange is a nonoverlapping match of the given parser,
using a skip-parser if provided. */
using a skip-parser if provided. */
template<
#if BOOST_PARSER_USE_CONCEPTS
std::ranges::viewable_range V,
@@ -311,22 +299,15 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
struct search_all_view
: detail::stl_interfaces::view_interface<search_all_view<
V,
Parser,
GlobalState,
ErrorHandler,
Memoize,
SkipParser>>
: detail::stl_interfaces::view_interface<
search_all_view<V, Parser, GlobalState, ErrorHandler, SkipParser>>
{
constexpr search_all_view() = default;
constexpr search_all_view(
V base,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser,
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
parser_interface<SkipParser> const & skip,
trace trace_mode = trace::off) :
base_(std::move(base)),
@@ -336,8 +317,7 @@ namespace boost::parser {
{}
constexpr search_all_view(
V base,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser,
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
trace trace_mode = trace::off) :
base_(std::move(base)),
parser_(parser),
@@ -441,7 +421,7 @@ namespace boost::parser {
private:
V base_;
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> parser_;
parser_interface<Parser, GlobalState, ErrorHandler> parser_;
parser_interface<SkipParser> skip_;
trace trace_mode_;
};
@@ -452,11 +432,10 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
search_all_view(
V &&,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
parser_interface<Parser, GlobalState, ErrorHandler>,
parser_interface<SkipParser>,
trace)
-> search_all_view<
@@ -464,7 +443,6 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize,
SkipParser>;
template<
@@ -472,52 +450,43 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
search_all_view(
V &&,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
parser_interface<Parser, GlobalState, ErrorHandler>,
parser_interface<SkipParser>)
-> search_all_view<
detail::text::detail::all_t<V>,
Parser,
GlobalState,
ErrorHandler,
Memoize,
SkipParser>;
template<
typename V,
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize>
typename ErrorHandler>
search_all_view(
V &&,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
trace)
V &&, parser_interface<Parser, GlobalState, ErrorHandler>, trace)
-> search_all_view<
detail::text::detail::all_t<V>,
Parser,
GlobalState,
ErrorHandler,
Memoize,
parser_interface<eps_parser<detail::phony>>>;
template<
typename V,
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize>
search_all_view(
V &&, parser_interface<Parser, GlobalState, ErrorHandler, Memoize>)
typename ErrorHandler>
search_all_view(V &&, parser_interface<Parser, GlobalState, ErrorHandler>)
-> search_all_view<
detail::text::detail::all_t<V>,
Parser,
GlobalState,
ErrorHandler,
Memoize,
parser_interface<eps_parser<detail::phony>>>;
namespace detail {
@@ -526,21 +495,16 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
typename Memoize,
typename SkipParser>
using search_all_view_expr = decltype(search_all_view<
V,
Parser,
GlobalState,
ErrorHandler,
Memoize::value,
SkipParser>(
std::declval<V>(),
std::declval<parser_interface<
Parser,
GlobalState,
ErrorHandler,
Memoize::value> const &>(),
std::declval<
parser_interface<Parser, GlobalState, ErrorHandler> const &>(),
std::declval<parser_interface<SkipParser> const &>(),
trace::on));
@@ -549,7 +513,6 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
constexpr bool can_search_all_view = is_detected_v<
search_all_view_expr,
@@ -557,7 +520,6 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
std::bool_constant<Memoize>,
SkipParser>;
struct search_all_impl
@@ -568,7 +530,7 @@ namespace boost::parser {
parsable_range_like R,
typename Parser,
typename GlobalState,
typename ErrorHandler, bool Memoize,
typename ErrorHandler,
typename SkipParser>
requires(
std::is_pointer_v<std::remove_cvref_t<R>> ||
@@ -578,12 +540,11 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize,
SkipParser>
// clang-format off
[[nodiscard]] constexpr auto operator()(
R && r,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser_interface<Parser, GlobalState, ErrorHandler> const &
parser,
parser_interface<SkipParser> const & skip,
trace trace_mode = trace::off) const
@@ -597,7 +558,7 @@ namespace boost::parser {
parsable_range_like R,
typename Parser,
typename GlobalState,
typename ErrorHandler, bool Memoize>
typename ErrorHandler>
requires(
std::is_pointer_v<std::remove_cvref_t<R>> ||
std::ranges::viewable_range<R>) &&
@@ -606,12 +567,11 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize,
parser_interface<eps_parser<detail::phony>>>
// clang-format off
[[nodiscard]] constexpr auto operator()(
R && r,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser_interface<Parser, GlobalState, ErrorHandler> const &
parser,
trace trace_mode = trace::off) const
// clang-format on
@@ -630,18 +590,14 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser =
parser_interface<eps_parser<detail::phony>>,
typename Trace = trace,
typename Enable = std::enable_if_t<is_parsable_range_like_v<R>>>
[[nodiscard]] constexpr auto operator()(
R && r,
parser_interface<
Parser,
GlobalState,
ErrorHandler,
Memoize> const & parser,
parser_interface<Parser, GlobalState, ErrorHandler> const &
parser,
SkipParser const & skip = SkipParser{},
Trace trace_mode = Trace{}) const
{
@@ -675,15 +631,11 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
[[nodiscard]] constexpr auto impl(
R && r,
parser_interface<
Parser,
GlobalState,
ErrorHandler,
Memoize> const & parser,
parser_interface<Parser, GlobalState, ErrorHandler> const &
parser,
parser_interface<SkipParser> const & skip,
trace trace_mode = trace::off) const
{
@@ -711,16 +663,11 @@ template<
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
constexpr bool
std::ranges::enable_borrowed_range<boost::parser::search_all_view<
V,
Parser,
GlobalState,
ErrorHandler,
Memoize,
SkipParser>> = std::ranges::enable_borrowed_range<V>;
constexpr bool std::ranges::enable_borrowed_range<
boost::parser::
search_all_view<V, Parser, GlobalState, ErrorHandler, SkipParser>> =
std::ranges::enable_borrowed_range<V>;
#endif
#endif

View File

@@ -8,7 +8,7 @@ namespace boost::parser {
/** Produces a sequence of subranges of the underlying sequence of type
`V`. the underlying sequence is split into subranges delimited by
matches of the given parser, possibly using a given skip-parser. */
matches of the given parser, possibly using a given skip-parser. */
template<
#if BOOST_PARSER_USE_CONCEPTS
std::ranges::viewable_range V,
@@ -18,21 +18,15 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
struct split_view : detail::stl_interfaces::view_interface<split_view<
V,
Parser,
GlobalState,
ErrorHandler,
Memoize,
SkipParser>>
struct split_view
: detail::stl_interfaces::view_interface<
split_view<V, Parser, GlobalState, ErrorHandler, SkipParser>>
{
constexpr split_view() = default;
constexpr split_view(
V base,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser,
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
parser_interface<SkipParser> const & skip,
trace trace_mode = trace::off) :
base_(std::move(base)),
@@ -42,8 +36,7 @@ namespace boost::parser {
{}
constexpr split_view(
V base,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser,
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
trace trace_mode = trace::off) :
base_(std::move(base)),
parser_(parser),
@@ -154,7 +147,7 @@ namespace boost::parser {
private:
V base_;
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> parser_;
parser_interface<Parser, GlobalState, ErrorHandler> parser_;
parser_interface<SkipParser> skip_;
trace trace_mode_;
};
@@ -165,11 +158,10 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
split_view(
V &&,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
parser_interface<Parser, GlobalState, ErrorHandler>,
parser_interface<SkipParser>,
trace)
-> split_view<
@@ -177,7 +169,6 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize,
SkipParser>;
template<
@@ -185,52 +176,43 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
split_view(
V &&,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
parser_interface<Parser, GlobalState, ErrorHandler>,
parser_interface<SkipParser>)
-> split_view<
detail::text::detail::all_t<V>,
Parser,
GlobalState,
ErrorHandler,
Memoize,
SkipParser>;
template<
typename V,
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize>
typename ErrorHandler>
split_view(
V &&,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
trace)
V &&, parser_interface<Parser, GlobalState, ErrorHandler>, trace)
-> split_view<
detail::text::detail::all_t<V>,
Parser,
GlobalState,
ErrorHandler,
Memoize,
parser_interface<eps_parser<detail::phony>>>;
template<
typename V,
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize>
split_view(
V &&, parser_interface<Parser, GlobalState, ErrorHandler, Memoize>)
typename ErrorHandler>
split_view(V &&, parser_interface<Parser, GlobalState, ErrorHandler>)
-> split_view<
detail::text::detail::all_t<V>,
Parser,
GlobalState,
ErrorHandler,
Memoize,
parser_interface<eps_parser<detail::phony>>>;
namespace detail {
@@ -239,21 +221,16 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
typename Memoize,
typename SkipParser>
using split_view_expr = decltype(split_view<
V,
Parser,
GlobalState,
ErrorHandler,
Memoize::value,
SkipParser>(
V,
Parser,
GlobalState,
ErrorHandler,
SkipParser>(
std::declval<V>(),
std::declval<parser_interface<
Parser,
GlobalState,
ErrorHandler,
Memoize::value> const &>(),
std::declval<
parser_interface<Parser, GlobalState, ErrorHandler> const &>(),
std::declval<parser_interface<SkipParser> const &>(),
trace::on));
@@ -262,7 +239,6 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
constexpr bool can_split_view = is_detected_v<
split_view_expr,
@@ -270,7 +246,6 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
std::bool_constant<Memoize>,
SkipParser>;
struct split_impl
@@ -282,7 +257,6 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
requires(
std::is_pointer_v<std::remove_cvref_t<R>> ||
@@ -292,12 +266,11 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize,
SkipParser>
// clang-format off
[[nodiscard]] constexpr auto operator()(
R && r,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser_interface<Parser, GlobalState, ErrorHandler> const &
parser,
parser_interface<SkipParser> const & skip,
trace trace_mode = trace::off) const
@@ -311,8 +284,7 @@ namespace boost::parser {
parsable_range_like R,
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize>
typename ErrorHandler>
requires(
std::is_pointer_v<std::remove_cvref_t<R>> ||
std::ranges::viewable_range<R>) &&
@@ -321,12 +293,11 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize,
parser_interface<eps_parser<detail::phony>>>
// clang-format off
[[nodiscard]] constexpr auto operator()(
R && r,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser_interface<Parser, GlobalState, ErrorHandler> const &
parser,
trace trace_mode = trace::off) const
// clang-format on
@@ -345,18 +316,14 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser =
parser_interface<eps_parser<detail::phony>>,
typename Trace = trace,
typename Enable = std::enable_if_t<is_parsable_range_like_v<R>>>
[[nodiscard]] constexpr auto operator()(
R && r,
parser_interface<
Parser,
GlobalState,
ErrorHandler,
Memoize> const & parser,
parser_interface<Parser, GlobalState, ErrorHandler> const &
parser,
SkipParser const & skip = SkipParser{},
Trace trace_mode = Trace{}) const
{
@@ -390,15 +357,11 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
[[nodiscard]] constexpr auto impl(
R && r,
parser_interface<
Parser,
GlobalState,
ErrorHandler,
Memoize> const & parser,
parser_interface<Parser, GlobalState, ErrorHandler> const &
parser,
parser_interface<SkipParser> const & skip,
trace trace_mode = trace::off) const
{
@@ -426,11 +389,10 @@ template<
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
constexpr bool std::ranges::enable_borrowed_range<
boost::parser::
split_view<V, Parser, GlobalState, ErrorHandler, Memoize, SkipParser>> =
split_view<V, Parser, GlobalState, ErrorHandler, SkipParser>> =
std::ranges::enable_borrowed_range<V>;
#endif

View File

@@ -24,11 +24,7 @@ namespace boost::parser {
#else
/** A view that produces UTF-8 from an given sequence of UTF.
\tparam V Constrained by `std::ranges::view<V>`. Additionally, the
value type of `V` must be `char`, `wchar_t`, `char8_t`, `char16_t`, or
`char32_t`. */
/** A view that produces UTF-8 from an given sequence of UTF. */
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS || defined(BOOST_PARSER_DOXYGEN)
template<detail::text::utf_range V>
requires std::ranges::view<V>
@@ -48,11 +44,7 @@ namespace boost::parser {
{}
};
/** A view that produces UTF-16 from an given sequence of UTF.
\tparam V Constrained by `std::ranges::view<V>`. Additionally, the
value type of `V` must be `char`, `wchar_t`, `char8_t`, `char16_t`, or
`char32_t`. */
/** A view that produces UTF-16 from an given sequence of UTF. */
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS || defined(BOOST_PARSER_DOXYGEN)
template<detail::text::utf_range V>
requires std::ranges::view<V>
@@ -72,11 +64,7 @@ namespace boost::parser {
{}
};
/** A view that produces UTF-32 from an given sequence of UTF.
\tparam V Constrained by `std::ranges::view<V>`. Additionally, the
value type of `V` must be `char`, `wchar_t`, `char8_t`, `char16_t`, or
`char32_t`. */
/** A view that produces UTF-32 from an given sequence of UTF. */
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS || defined(BOOST_PARSER_DOXYGEN)
template<detail::text::utf_range V>
requires std::ranges::view<V>

View File

@@ -3,8 +3,7 @@
#include <boost/parser/replace.hpp>
#if (!defined(_MSC_VER) || BOOST_PARSER_USE_CONCEPTS) && \
(!defined(__GNUC__) || 12 <= __GNUC__ || !BOOST_PARSER_USE_CONCEPTS)
#if (!defined(_MSC_VER) || BOOST_PARSER_USE_CONCEPTS)
namespace boost::parser {
@@ -17,10 +16,10 @@ namespace boost::parser {
template<typename I, typename S, typename Parser>
using attr_type = decltype(std::declval<Parser const &>().call(
std::bool_constant<false>{},
std::declval<I &>(),
std::declval<S>(),
std::declval<
parse_context<false, false, I, S, default_error_handler>>(),
std::declval<parse_context<I, S, default_error_handler>>(),
ws,
detail::default_flags(),
std::declval<bool &>()));
@@ -212,12 +211,10 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
auto attr_search_impl(
R && r,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser,
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
parser_interface<SkipParser> const & skip,
trace trace_mode)
{
@@ -284,12 +281,10 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
auto attr_search_repack_shim(
R && r,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser,
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
parser_interface<SkipParser> const & skip,
trace trace_mode)
{
@@ -320,13 +315,7 @@ namespace boost::parser {
/** Produces a range of subranges of a given range `base`. Each subrange
is either a subrange of `base` that does not match the given parser
`parser`, or is `f(*boost::parser::parse(match, parser))`, where `f`
is the given invocable and `match` is the matching subrange.
In addition to the template parameter constraints, `F` must be
invocable with the attribute type of `Parser`; `V` and the range type
produced by `F`, "`Rf`" must be ranges of `char`, or must have the
same UTF format; and `V` and `Rf` must meet the same compatibility
requirements as described in `std::ranges::join_view`. */
is the given invocable and `match` is the matching subrange. */
template<
#if BOOST_PARSER_USE_CONCEPTS
std::ranges::viewable_range V,
@@ -338,7 +327,6 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser
#if !BOOST_PARSER_USE_CONCEPTS
,
@@ -356,7 +344,6 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize,
SkipParser>>
{
private:
@@ -367,8 +354,7 @@ namespace boost::parser {
constexpr transform_replace_view() = default;
constexpr transform_replace_view(
V base,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser,
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
parser_interface<SkipParser> const & skip,
F f,
trace trace_mode = trace::off) :
@@ -380,8 +366,7 @@ namespace boost::parser {
{}
constexpr transform_replace_view(
V base,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser,
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
F f,
trace trace_mode = trace::off) :
base_(std::move(base)),
@@ -513,11 +498,11 @@ namespace boost::parser {
using base_type::operator++;
private:
detail::maybe_const<Const, transform_replace_view> * parent_ = {};
detail::maybe_const<Const, transform_replace_view> * parent_;
BOOST_PARSER_SUBRANGE<I, S> r_;
BOOST_PARSER_SUBRANGE<I> curr_;
I next_it_ = {};
bool in_match_ = {};
I next_it_;
bool in_match_;
};
template<bool Const>
@@ -526,7 +511,7 @@ namespace boost::parser {
private:
V base_;
F f_;
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> parser_;
parser_interface<Parser, GlobalState, ErrorHandler> parser_;
parser_interface<SkipParser> skip_;
trace trace_mode_;
};
@@ -538,11 +523,10 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
transform_replace_view(
V &&,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
parser_interface<Parser, GlobalState, ErrorHandler>,
parser_interface<SkipParser>,
F &&,
trace)
@@ -552,7 +536,6 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize,
SkipParser>;
template<
@@ -561,11 +544,10 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
transform_replace_view(
V &&,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
parser_interface<Parser, GlobalState, ErrorHandler>,
parser_interface<SkipParser>,
F &&)
-> transform_replace_view<
@@ -574,7 +556,6 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize,
SkipParser>;
template<
@@ -582,20 +563,15 @@ namespace boost::parser {
typename F,
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize>
typename ErrorHandler>
transform_replace_view(
V &&,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
F &&,
trace)
V &&, parser_interface<Parser, GlobalState, ErrorHandler>, F &&, trace)
-> transform_replace_view<
detail::text::detail::all_t<V>,
detail::remove_cv_ref_t<F>,
Parser,
GlobalState,
ErrorHandler,
Memoize,
parser_interface<eps_parser<detail::phony>>>;
template<
@@ -603,19 +579,15 @@ namespace boost::parser {
typename F,
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize>
typename ErrorHandler>
transform_replace_view(
V &&,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
F &&)
V &&, parser_interface<Parser, GlobalState, ErrorHandler>, F &&)
-> transform_replace_view<
detail::text::detail::all_t<V>,
detail::remove_cv_ref_t<F>,
Parser,
GlobalState,
ErrorHandler,
Memoize,
parser_interface<eps_parser<detail::phony>>>;
namespace detail {
@@ -625,7 +597,6 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
typename Memoize,
typename SkipParser>
using transform_replace_view_expr = decltype(transform_replace_view<
V,
@@ -633,14 +604,10 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize::value,
SkipParser>(
std::declval<V>(),
std::declval<parser_interface<
Parser,
GlobalState,
ErrorHandler,
Memoize::value> const &>(),
std::declval<
parser_interface<Parser, GlobalState, ErrorHandler> const &>(),
std::declval<parser_interface<SkipParser> const &>(),
std::declval<F>(),
trace::on));
@@ -651,7 +618,6 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
constexpr bool can_transform_replace_view = is_detected_v<
transform_replace_view_expr,
@@ -660,7 +626,6 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
std::bool_constant<Memoize>,
SkipParser>;
struct transform_replace_impl
@@ -673,7 +638,6 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
requires
// clang-format off
@@ -692,12 +656,11 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize,
SkipParser>
// clang-format off
[[nodiscard]] constexpr auto operator()(
R && r,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser_interface<Parser, GlobalState, ErrorHandler> const &
parser,
parser_interface<SkipParser> const & skip,
F && f,
@@ -720,8 +683,7 @@ namespace boost::parser {
std::move_constructible F,
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize>
typename ErrorHandler>
requires
// clang-format off
(std::is_pointer_v<std::remove_cvref_t<R>> ||
@@ -739,12 +701,11 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize,
parser_interface<eps_parser<detail::phony>>>
// clang-format off
[[nodiscard]] constexpr auto operator()(
R && r,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser_interface<Parser, GlobalState, ErrorHandler> const &
parser,
F && f,
trace trace_mode = trace::off) const
@@ -765,18 +726,14 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser,
typename F = trace,
typename Trace = trace,
typename Enable = std::enable_if_t<is_parsable_range_like_v<R>>>
[[nodiscard]] constexpr auto operator()(
R && r,
parser_interface<
Parser,
GlobalState,
ErrorHandler,
Memoize> const & parser,
parser_interface<Parser, GlobalState, ErrorHandler> const &
parser,
SkipParser && skip,
F && f = F{},
Trace trace_mode = Trace{}) const
@@ -823,15 +780,11 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
[[nodiscard]] constexpr auto impl(
R && r,
parser_interface<
Parser,
GlobalState,
ErrorHandler,
Memoize> const & parser,
parser_interface<Parser, GlobalState, ErrorHandler> const &
parser,
parser_interface<SkipParser> const & skip,
F && f,
trace trace_mode = trace::off) const
@@ -870,7 +823,6 @@ template<
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
constexpr bool
std::ranges::enable_borrowed_range<boost::parser::transform_replace_view<
@@ -879,7 +831,6 @@ constexpr bool
Parser,
GlobalState,
ErrorHandler,
Memoize,
SkipParser>> = std::ranges::enable_borrowed_range<V> &&
(std::ranges::enable_borrowed_range<F> ||
boost::parser::detail::tidy_func<F>);

View File

@@ -4,7 +4,7 @@ include(CTest)
enable_testing()
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -j4 -C ${CMAKE_CFG_INTDIR})
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} -j4 -C ${CMAKE_CFG_INTDIR})
##################################################
# Parser tests
@@ -46,7 +46,6 @@ macro(add_test_executable name)
add_test(NAME ${name} COMMAND ${name} --gtest_catch_exceptions=1)
endmacro()
add_test_executable(memos)
add_test_executable(all_t)
add_test_executable(search)
add_test_executable(split)
@@ -54,8 +53,6 @@ add_test_executable(replace)
add_test_executable(transform_replace)
add_test_executable(hl)
add_test_executable(aggr_tuple_assignment)
add_test_executable(parser_perm)
add_test_executable(parser_attributes)
add_test_executable(parser_lazy_params)
add_test_executable(parser_if_switch)
add_test_executable(parser_rule)
@@ -63,7 +60,6 @@ add_test_executable(parser_rule_with_params)
add_test_executable(parser_action)
add_test_executable(parser_action_with_params)
add_test_executable(parser_symbol_table)
add_test_executable(parser_quoted_string)
add_test_executable(tracing)
add_test_executable(parse_empty)
add_test_executable(tuple_aggregate)
@@ -71,8 +67,3 @@ add_test_executable(class_type)
add_test_executable(case_fold_generated)
add_test_executable(no_case)
add_test_executable(merge_separate)
add_test_executable(parse_coords_new)
add_test_executable(parser_seq_permutations_1)
add_test_executable(parser_seq_permutations_2)
add_test_executable(parser_or_permutations_1)
add_test_executable(parser_or_permutations_2)

File diff suppressed because it is too large Load Diff

View File

@@ -20,11 +20,6 @@ void compile_or_attribute()
using attr_t = decltype(prefix_parse(first, last, parser));
static_assert(
std::is_same_v<attr_t, std::optional<std::optional<int>>>);
static_assert(std::is_same_v<
attribute_t<
decltype(BOOST_PARSER_SUBRANGE(first, last)),
decltype(parser)>,
std::optional<int>>);
}
// scalar | scalar
@@ -32,33 +27,18 @@ void compile_or_attribute()
constexpr auto parser = char_ | char_;
using attr_t = decltype(prefix_parse(first, last, parser));
static_assert(std::is_same_v<attr_t, std::optional<char>>);
static_assert(std::is_same_v<
attribute_t<
decltype(BOOST_PARSER_SUBRANGE(first, last)),
decltype(parser)>,
char>);
}
{
constexpr auto parser = char_ | char_ | eps;
using attr_t = decltype(prefix_parse(first, last, parser));
static_assert(
std::is_same_v<attr_t, std::optional<std::optional<char>>>);
static_assert(std::is_same_v<
attribute_t<
decltype(BOOST_PARSER_SUBRANGE(first, last)),
decltype(parser)>,
std::optional<char>>);
}
{
constexpr auto parser = int_ | char_;
using attr_t = decltype(prefix_parse(first, last, parser));
static_assert(
std::is_same_v<attr_t, std::optional<std::variant<int, char>>>);
static_assert(std::is_same_v<
attribute_t<
decltype(BOOST_PARSER_SUBRANGE(first, last)),
decltype(parser)>,
std::variant<int, char>>);
}
{
constexpr auto parser = int_ | char_ | eps;
@@ -66,11 +46,6 @@ void compile_or_attribute()
static_assert(std::is_same_v<
attr_t,
std::optional<std::optional<std::variant<int, char>>>>);
static_assert(std::is_same_v<
attribute_t<
decltype(BOOST_PARSER_SUBRANGE(first, last)),
decltype(parser)>,
std::optional<std::variant<int, char>>>);
}
// -scalar | -scalar
@@ -79,22 +54,12 @@ void compile_or_attribute()
using attr_t = decltype(prefix_parse(first, last, parser));
static_assert(
std::is_same_v<attr_t, std::optional<std::optional<char>>>);
static_assert(std::is_same_v<
attribute_t<
decltype(BOOST_PARSER_SUBRANGE(first, last)),
decltype(parser)>,
std::optional<char>>);
}
{
constexpr auto parser = -char_ | -char_ | eps;
using attr_t = decltype(prefix_parse(first, last, parser));
static_assert(
std::is_same_v<attr_t, std::optional<std::optional<char>>>);
static_assert(std::is_same_v<
attribute_t<
decltype(BOOST_PARSER_SUBRANGE(first, last)),
decltype(parser)>,
std::optional<char>>);
}
{
constexpr auto parser = -int_ | -char_;
@@ -104,11 +69,6 @@ void compile_or_attribute()
attr_t,
std::optional<
std::variant<std::optional<int>, std::optional<char>>>>);
static_assert(std::is_same_v<
attribute_t<
decltype(BOOST_PARSER_SUBRANGE(first, last)),
decltype(parser)>,
std::variant<std::optional<int>, std::optional<char>>>);
}
{
constexpr auto parser = -int_ | -char_ | eps;
@@ -118,13 +78,6 @@ void compile_or_attribute()
attr_t,
std::optional<std::optional<
std::variant<std::optional<int>, std::optional<char>>>>>);
static_assert(
std::is_same_v<
attribute_t<
decltype(BOOST_PARSER_SUBRANGE(first, last)),
decltype(parser)>,
std::optional<
std::variant<std::optional<int>, std::optional<char>>>>);
}
// seq<T> | seq<T>
@@ -132,33 +85,18 @@ void compile_or_attribute()
constexpr auto parser = *char_ | *char_;
using attr_t = decltype(prefix_parse(first, last, parser));
static_assert(std::is_same_v<attr_t, std::optional<std::string>>);
static_assert(std::is_same_v<
attribute_t<
decltype(BOOST_PARSER_SUBRANGE(first, last)),
decltype(parser)>,
std::string>);
}
{
constexpr auto parser = *char_ | *char_ | eps;
using attr_t = decltype(prefix_parse(first, last, parser));
static_assert(
std::is_same_v<attr_t, std::optional<std::optional<std::string>>>);
static_assert(std::is_same_v<
attribute_t<
decltype(BOOST_PARSER_SUBRANGE(first, last)),
decltype(parser)>,
std::optional<std::string>>);
}
{
constexpr auto parser = *string("str") | *string("str");
using attr_t = decltype(prefix_parse(first, last, parser));
static_assert(
std::is_same_v<attr_t, std::optional<std::vector<std::string>>>);
static_assert(std::is_same_v<
attribute_t<
decltype(BOOST_PARSER_SUBRANGE(first, last)),
decltype(parser)>,
std::vector<std::string>>);
}
{
constexpr auto parser = *string("str") | *string("str") | eps;
@@ -166,11 +104,6 @@ void compile_or_attribute()
static_assert(std::is_same_v<
attr_t,
std::optional<std::optional<std::vector<std::string>>>>);
static_assert(std::is_same_v<
attribute_t<
decltype(BOOST_PARSER_SUBRANGE(first, last)),
decltype(parser)>,
std::optional<std::vector<std::string>>>);
}
// seq<T> | seq<U>

View File

@@ -1,452 +0,0 @@
/**
* Copyright (C) 2024 T. Zachary Laine
*
* Distributed under the Boost Software License, Version 1.0. (See
* accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
#include <boost/parser/detail/memos.hpp>
#include <variant> // for monostate
#include <gtest/gtest.h>
using namespace boost::parser;
TEST(memos, linked_list_1)
{
{
detail::linked_list<std::string, 1> list;
}
{
detail::linked_list<std::string, 1> list;
for (int i = 0; i < 16; ++i) {
auto [pos, needs_new] = list.push();
std::string * str = needs_new ? new (pos) std::string()
: static_cast<std::string *>(pos);
*str = 'a' + i;
}
}
{
detail::linked_list<int, 1> list;
}
{
detail::linked_list<int, 1> list;
for (int i = 0; i < 16; ++i) {
auto [pos, needs_new] = list.push();
int * j = needs_new ? new (pos) int() : static_cast<int *>(pos);
*j = i;
}
}
// reclaim, no reuse
{
detail::linked_list<std::string, 1> list;
for (int i = 0; i < 16; ++i) {
auto [pos, needs_new] = list.push();
std::string * str = needs_new ? new (pos) std::string()
: static_cast<std::string *>(pos);
*str = 'a' + i;
}
list.reclaim();
}
{
detail::linked_list<int, 1> list;
for (int i = 0; i < 16; ++i) {
auto [pos, needs_new] = list.push();
int * j = needs_new ? new (pos) int() : static_cast<int *>(pos);
*j = i;
}
list.reclaim();
}
// reclaim, partial reuse
{
detail::linked_list<std::string, 1> list;
for (int i = 0; i < 16; ++i) {
auto [pos, needs_new] = list.push();
std::string * str = needs_new ? new (pos) std::string()
: static_cast<std::string *>(pos);
*str = 'a' + i;
}
list.reclaim();
for (int i = 0; i < 9; ++i) {
auto [pos, needs_new] = list.push();
std::string * str = needs_new ? new (pos) std::string()
: static_cast<std::string *>(pos);
char const expected[] = {char('a' + (16 - 1) - i), 0};
EXPECT_EQ(*str, expected);
*str = "reused";
}
}
{
detail::linked_list<int, 1> list;
for (int i = 0; i < 16; ++i) {
auto [pos, needs_new] = list.push();
int * j = needs_new ? new (pos) int() : static_cast<int *>(pos);
*j = i;
}
list.reclaim();
for (int i = 0; i < 9; ++i) {
auto [pos, needs_new] = list.push();
int * j = needs_new ? new (pos) int() : static_cast<int *>(pos);
EXPECT_EQ(*j, (16 - 1) - i);
*j = -1;
}
}
// reclaim, full reuse
{
detail::linked_list<std::string, 1> list;
for (int i = 0; i < 16; ++i) {
auto [pos, needs_new] = list.push();
std::string * str = needs_new ? new (pos) std::string()
: static_cast<std::string *>(pos);
*str = 'a' + i;
}
list.reclaim();
for (int i = 0; i < 16; ++i) {
auto [pos, needs_new] = list.push();
std::string * str = needs_new ? new (pos) std::string()
: static_cast<std::string *>(pos);
char const expected[] = {char('a' + (16 - 1) - i), 0};
EXPECT_EQ(*str, expected);
*str = "reused";
}
}
{
detail::linked_list<int, 1> list;
for (int i = 0; i < 16; ++i) {
auto [pos, needs_new] = list.push();
int * j = needs_new ? new (pos) int() : static_cast<int *>(pos);
*j = i;
}
list.reclaim();
for (int i = 0; i < 16; ++i) {
auto [pos, needs_new] = list.push();
int * j = needs_new ? new (pos) int() : static_cast<int *>(pos);
EXPECT_EQ(*j, (16 - 1) - i);
*j = -1;
}
}
}
TEST(memos, linked_list_8)
{
{
detail::linked_list<std::string, 8> list;
}
{
detail::linked_list<std::string, 8> list;
for (int i = 0; i < 16; ++i) {
auto [pos, needs_new] = list.push();
std::string * str = needs_new ? new (pos) std::string()
: static_cast<std::string *>(pos);
*str = 'a' + i;
}
}
{
detail::linked_list<int, 8> list;
}
{
detail::linked_list<int, 8> list;
for (int i = 0; i < 16; ++i) {
auto [pos, needs_new] = list.push();
int * j = needs_new ? new (pos) int() : static_cast<int *>(pos);
*j = i;
}
}
// reclaim, no reuse
{
detail::linked_list<std::string, 8> list;
for (int i = 0; i < 16; ++i) {
auto [pos, needs_new] = list.push();
std::string * str = needs_new ? new (pos) std::string()
: static_cast<std::string *>(pos);
*str = 'a' + i;
}
list.reclaim();
}
{
detail::linked_list<int, 8> list;
for (int i = 0; i < 16; ++i) {
auto [pos, needs_new] = list.push();
int * j = needs_new ? new (pos) int() : static_cast<int *>(pos);
*j = i;
}
list.reclaim();
}
// reclaim, partial reuse
{
detail::linked_list<std::string, 8> list;
for (int i = 0; i < 16; ++i) {
auto [pos, needs_new] = list.push();
std::string * str = needs_new ? new (pos) std::string()
: static_cast<std::string *>(pos);
*str = 'a' + i;
}
list.reclaim();
for (int i = 0; i < 9; ++i) {
auto [pos, needs_new] = list.push();
std::string * str = needs_new ? new (pos) std::string()
: static_cast<std::string *>(pos);
char c = i < 8 ? char('a' + i + 8) : char('a' + i - 8);
char const expected[] = {c, 0};
EXPECT_EQ(*str, expected);
*str = "reused";
}
}
{
detail::linked_list<int, 8> list;
for (int i = 0; i < 16; ++i) {
auto [pos, needs_new] = list.push();
int * j = needs_new ? new (pos) int() : static_cast<int *>(pos);
*j = i;
}
list.reclaim();
for (int i = 0; i < 9; ++i) {
auto [pos, needs_new] = list.push();
int * j = needs_new ? new (pos) int() : static_cast<int *>(pos);
if (i < 8)
EXPECT_EQ(*j, i + 8);
else
EXPECT_EQ(*j, i - 8);
*j = -1;
}
}
// reclaim, full reuse
{
detail::linked_list<std::string, 8> list;
for (int i = 0; i < 16; ++i) {
auto [pos, needs_new] = list.push();
std::string * str = needs_new ? new (pos) std::string()
: static_cast<std::string *>(pos);
*str = 'a' + i;
}
list.reclaim();
for (int i = 0; i < 16; ++i) {
auto [pos, needs_new] = list.push();
std::string * str = needs_new ? new (pos) std::string()
: static_cast<std::string *>(pos);
char c = i < 8 ? char('a' + i + 8) : char('a' + i - 8);
char const expected[] = {c, 0};
EXPECT_EQ(*str, expected);
*str = "reused";
}
}
{
detail::linked_list<int, 8> list;
for (int i = 0; i < 16; ++i) {
auto [pos, needs_new] = list.push();
int * j = needs_new ? new (pos) int() : static_cast<int *>(pos);
*j = i;
}
list.reclaim();
for (int i = 0; i < 16; ++i) {
auto [pos, needs_new] = list.push();
int * j = needs_new ? new (pos) int() : static_cast<int *>(pos);
if (i < 8)
EXPECT_EQ(*j, i + 8);
else
EXPECT_EQ(*j, i - 8);
*j = -1;
}
}
}
struct one
{};
struct two
{};
TEST(memos, basic)
{
constexpr auto failure = detail::memos<size_t, size_t>::failure;
constexpr auto success = detail::memos<size_t, size_t>::success;
{
detail::memos<size_t, size_t> memos;
}
{
detail::memos<size_t, size_t> memos;
detail::memos<size_t, size_t>::const_ref<int> ref = memos.find<one, int>(13);
EXPECT_FALSE(ref);
EXPECT_EQ(ref.valid, false);
EXPECT_EQ(ref.value, nullptr);
EXPECT_EQ(ref.datum, nullptr);
}
{
detail::memos<size_t, size_t> memos;
detail::memos<size_t, size_t>::ref<int> ref =
memos.insert<one, int>(failure, 13);
EXPECT_TRUE(ref);
EXPECT_EQ(ref.get_kind(), failure);
EXPECT_EQ(ref.valid, true);
EXPECT_EQ(ref.value, nullptr);
EXPECT_NE(ref.datum, nullptr);
EXPECT_EQ(*ref.datum, 0);
EXPECT_FALSE((memos.find<one, int>(12)));
EXPECT_FALSE((memos.find<one, int>(13, 42)));
EXPECT_FALSE((memos.find<two, int>(13)));
EXPECT_FALSE((memos.find<one, double>(13)));
detail::memos<size_t, size_t>::const_ref<int> cref = memos.find<one, int>(13);
EXPECT_TRUE(cref);
EXPECT_EQ(cref.get_kind(), failure);
EXPECT_EQ(cref.valid, true);
EXPECT_EQ(cref.value, nullptr);
EXPECT_NE(cref.datum, nullptr);
EXPECT_EQ(*cref.datum, 0);
}
{
detail::memos<size_t, size_t> memos;
detail::memos<size_t, size_t>::ref<int> ref =
memos.insert<one, int>(success, 13);
EXPECT_TRUE(ref);
EXPECT_EQ(ref.get_kind(), success);
EXPECT_EQ(ref.valid, true);
EXPECT_NE(ref.value, nullptr);
EXPECT_NE(ref.datum, nullptr);
EXPECT_EQ(*ref.datum, 0);
EXPECT_FALSE((memos.find<one, int>(12)));
EXPECT_FALSE((memos.find<one, int>(13, 42)));
EXPECT_FALSE((memos.find<two, int>(13)));
EXPECT_FALSE((memos.find<one, double>(13)));
detail::memos<size_t, size_t>::const_ref<int> cref = memos.find<one, int>(13);
EXPECT_TRUE(cref);
EXPECT_EQ(cref.get_kind(), success);
EXPECT_EQ(cref.valid, true);
EXPECT_NE(cref.value, nullptr);
EXPECT_NE(cref.datum, nullptr);
EXPECT_EQ(*cref.datum, 0);
}
// types sharing the same trivial_type<size, align>
{
detail::memos<size_t, size_t> memos;
detail::memos<size_t, size_t>::ref<int> ref =
memos.insert<one, int>(success, 13);
EXPECT_TRUE(ref);
EXPECT_EQ(ref.get_kind(), success);
EXPECT_EQ(ref.valid, true);
EXPECT_NE(ref.value, nullptr);
EXPECT_NE(ref.datum, nullptr);
EXPECT_EQ(*ref.datum, 0);
*ref.value = 42;
EXPECT_FALSE((memos.find<one, int>(12)));
EXPECT_FALSE((memos.find<one, int>(13, 42)));
EXPECT_FALSE((memos.find<two, int>(13)));
EXPECT_FALSE((memos.find<one, float>(13)));
detail::memos<size_t, size_t>::const_ref<int> cref = memos.find<one, int>(13);
EXPECT_TRUE(cref);
EXPECT_EQ(cref.get_kind(), success);
EXPECT_EQ(cref.valid, true);
EXPECT_NE(cref.value, nullptr);
EXPECT_EQ(*cref.value, 42);
EXPECT_NE(cref.datum, nullptr);
EXPECT_EQ(*cref.datum, 0);
detail::memos<size_t, size_t>::ref<float> ref2 =
memos.insert<one, float>(success, 18);
EXPECT_TRUE(ref2);
EXPECT_EQ(ref2.get_kind(), success);
EXPECT_EQ(ref2.valid, true);
EXPECT_NE(ref2.value, nullptr);
EXPECT_NE(ref2.datum, nullptr);
EXPECT_EQ(*ref2.datum, 0);
*ref2.value = 13.0f;
EXPECT_FALSE((memos.find<one, float>(17)));
EXPECT_FALSE((memos.find<one, float>(18, 42)));
EXPECT_FALSE((memos.find<two, float>(18)));
EXPECT_FALSE((memos.find<one, char32_t>(18)));
detail::memos<size_t, size_t>::const_ref<float> cref2 = memos.find<one, float>(18);
EXPECT_TRUE(cref2);
EXPECT_EQ(cref2.get_kind(), success);
EXPECT_EQ(cref2.valid, true);
EXPECT_NE(cref2.value, nullptr);
EXPECT_EQ(*cref2.value, 13.0f);
EXPECT_NE(cref2.datum, nullptr);
EXPECT_EQ(*cref2.datum, 0);
detail::memos<size_t, size_t>::ref<char32_t> ref3 =
memos.insert<two, char32_t>(success, 21);
EXPECT_TRUE(ref3);
EXPECT_EQ(ref3.get_kind(), success);
EXPECT_EQ(ref3.valid, true);
EXPECT_TRUE(ref3.value);
EXPECT_NE(ref3.datum, nullptr);
EXPECT_EQ(*ref3.datum, 0);
*ref3.value = U'c';
EXPECT_FALSE((memos.find<two, char32_t>(20)));
EXPECT_FALSE((memos.find<two, char32_t>(21, 42)));
EXPECT_FALSE((memos.find<one, char32_t>(21)));
EXPECT_FALSE((memos.find<two, int>(21)));
detail::memos<size_t, size_t>::const_ref<char32_t> cref3 =
memos.find<two, char32_t>(21);
EXPECT_TRUE(cref3);
EXPECT_EQ(cref3.get_kind(), success);
EXPECT_EQ(cref3.valid, true);
EXPECT_TRUE(cref3.value);
EXPECT_EQ((unsigned int)*cref3.value, (unsigned int)U'c');
EXPECT_NE(cref3.datum, nullptr);
EXPECT_EQ(*cref3.datum, 0);
// three items
EXPECT_EQ(memos.items(), 3u);
// all three items use the same liked list for storage
EXPECT_EQ(memos.item_stores(), 1u);
}
// empty types
{
detail::memos<size_t, size_t> memos;
detail::memos<size_t, size_t>::ref<std::monostate> ref =
memos.insert<one, std::monostate>(success, 13);
EXPECT_TRUE(ref);
EXPECT_EQ(ref.get_kind(), success);
EXPECT_EQ(ref.valid, true);
EXPECT_EQ(*ref.value, std::monostate{});
*ref.value = std::monostate{};
EXPECT_NE(ref.datum, nullptr);
EXPECT_EQ(*ref.datum, 0);
EXPECT_FALSE((memos.find<one, std::monostate>(12)));
EXPECT_FALSE((memos.find<one, std::monostate>(13, 42)));
EXPECT_FALSE((memos.find<two, std::monostate>(13)));
EXPECT_FALSE((memos.find<one, double>(13)));
detail::memos<size_t, size_t>::const_ref<std::monostate> cref =
memos.find<one, std::monostate>(13);
EXPECT_TRUE(cref);
EXPECT_EQ(cref.get_kind(), success);
EXPECT_EQ(cref.valid, true);
EXPECT_EQ(*cref.value, std::monostate{});
EXPECT_NE(cref.datum, nullptr);
EXPECT_EQ(*cref.datum, 0);
}
}

View File

@@ -23,9 +23,6 @@ TEST(no_case, doc_example)
auto const alpha_parser = bp::no_case[bp::char_('a', 'z')];
assert(bp::parse("a" | bp::as_utf32, bp::no_case[alpha_parser])); // Match!
assert(bp::parse("B" | bp::as_utf32, bp::no_case[alpha_parser])); // Match!
(void)street_parser;
(void)alpha_parser;
}
@@ -168,97 +165,6 @@ TEST(no_case, match_any_within_string)
}
}
TEST(no_case, symbol_table)
{
// without mutation
{
symbols<int> const roman_numerals = {
{"I", 1}, {"V", 5}, {"X", 10}, {"L", 50}, {"C", 100}};
symbols<std::string> const named_strings = {
{"I", "1"}, {"V", "5"}, {"X", "10"}, {"L", "50"}, {"C", "100"}};
{
auto const result = parse("I", no_case[roman_numerals]);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 1);
}
{
auto const result = parse("i", no_case[roman_numerals]);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 1);
}
{
auto const result = parse("I", no_case[named_strings]);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "1");
}
{
auto const result = parse("i", no_case[named_strings]);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "1");
}
{
auto const result = parse("L", no_case[roman_numerals]);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 50);
}
{
auto const result = parse("l", no_case[roman_numerals]);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 50);
}
{
auto const result = parse("L", no_case[named_strings]);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "50");
}
{
auto const result = parse("l", no_case[named_strings]);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "50");
}
}
// with mutation
{
symbols<int> roman_numerals;
roman_numerals.insert_for_next_parse("I", 1)("V", 5)("X", 10);
auto const add_numeral = [&roman_numerals](auto & context) {
using namespace boost::parser::literals;
char chars[2] = {get(_attr(context), 0_c), 0};
roman_numerals.insert(context, chars, get(_attr(context), 1_c));
};
auto const numerals_parser = omit[roman_numerals] >>
(char_ >> int_)[add_numeral] >>
no_case[roman_numerals];
{
auto const result = parse("VL50L", numerals_parser);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 50);
EXPECT_FALSE(parse("L", roman_numerals));
}
{
auto const result = parse("VL50l", numerals_parser);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 50);
EXPECT_FALSE(parse("L", roman_numerals));
}
{
auto const result = parse("VC100C", numerals_parser);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 100);
EXPECT_FALSE(parse("C", roman_numerals));
}
{
auto const result = parse("Vc100C", numerals_parser);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 100);
EXPECT_FALSE(parse("C", roman_numerals));
}
}
}
constexpr auto capital_sharp_s = u8""; // U+1E9E
constexpr auto small_sharp_s = u8"ß"; // U+00DF
constexpr auto double_s = u8"sS"; // U+0073 U+0073
@@ -384,7 +290,7 @@ TEST(no_case, detail_no_case_iter)
auto first =
detail::no_case_iter(mixed_sharp_s1, detail::text::null_sentinel);
while (first != detail::text::null_sentinel) {
folded.push_back((char)*first);
folded.push_back(*first);
++first;
}
EXPECT_EQ(folded, "sss");
@@ -396,7 +302,7 @@ TEST(no_case, detail_no_case_iter)
auto first =
detail::no_case_iter(mixed_sharp_s2, detail::text::null_sentinel);
while (first != detail::text::null_sentinel) {
folded.push_back((char)*first);
folded.push_back(*first);
++first;
}
EXPECT_EQ(folded, "sss");
@@ -409,7 +315,7 @@ TEST(no_case, detail_no_case_iter)
detail::no_case_iter(street, detail::text::null_sentinel);
auto first = first_const;
while (first != detail::text::null_sentinel) {
folded.push_back((char)*first);
folded.push_back(*first);
++first;
}
EXPECT_EQ(folded, "strasse");

View File

@@ -1,199 +0,0 @@
/**
* Copyright (C) 2024 Phil Endecott
* Copyright (C) 2024 T. Zachary Laine
*
* Distributed under the Boost Software License, Version 1.0. (See
* accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
#include <boost/parser/config.hpp>
#if !BOOST_PARSER_USE_STD_TUPLE
#include <boost/parser/parser.hpp>
#include <cassert>
#include <iostream>
#include <optional>
#include <string>
#include <gtest/gtest.h>
namespace bp = boost::parser;
using namespace boost::hana::literals;
namespace g2d {
struct Vector
{
double x, y;
};
std::ostream & operator<<(std::ostream & os, Vector vec)
{
os << "vec{" << vec.x << ", " << vec.y << "}";
return os;
}
};
bp::rule<struct uint_0_60, unsigned int> uint_0_60 = "uint_0_60";
bp::rule<struct double_0_60, double> double_0_60 = "double_0_60";
bp::rule<struct degrees_decimal_minutes, double> degrees_decimal_minutes = "degrees_decimal_minutes";
bp::rule<struct degrees_minutes_seconds, double> degrees_minutes_seconds = "degrees_minutes_seconds";
bp::rule<struct degrees, double> degrees = "degrees";
bp::rule<struct latitude, double> latitude = "latitude";
bp::rule<struct longitude, double> longitude = "longitude";
bp::rule<struct signed_latitude, double> signed_latitude = "signed_latitude";
bp::rule<struct signed_longitude, double> signed_longitude = "signed_longitude";
bp::rule<struct latlon, g2d::Vector> latlon = "latlon";
const auto degrees_symbol = bp::no_case[ bp::lit("degrees") | bp::lit("deg") | bp::lit('d') ];
const auto minutes_symbol = bp::no_case[ bp::lit('\'') | bp::lit("minutes") | bp::lit("min") | bp::lit('m') ];
const auto seconds_symbol = bp::no_case[ bp::lit('"') | bp::lit("seconds") | bp::lit("sec") | bp::lit('s') ];
const auto uint_0_60_def = bp::uint_ [( [](auto & ctx) { _pass(ctx) = _attr(ctx) < 60U; _val(ctx) = _attr(ctx); } )];
const auto double_0_60_def = bp::double_ [( [](auto & ctx) { _pass(ctx) = _attr(ctx) < 60; _val(ctx) = _attr(ctx); } )];
const auto decimal_degrees = bp::double_ >> -degrees_symbol;
const auto degrees_decimal_minutes_def = (bp::uint_ >> -degrees_symbol
>> (double_0_60 - '.') >> -minutes_symbol) [( [](auto & ctx) {
auto d = _attr(ctx)[0_c];
auto m = _attr(ctx)[1_c];
_val(ctx) = d + m/60.0;
} )];
const auto degrees_minutes_seconds_def = (bp::uint_ >> -degrees_symbol
>> uint_0_60 >> -minutes_symbol
>> (double_0_60 - '.') >> -seconds_symbol) [( [](auto & ctx) {
auto d = _attr(ctx)[0_c];
auto m = _attr(ctx)[1_c];
auto s = _attr(ctx)[2_c];
_val(ctx) = d + m/60.0 + s/3600.0;
} )];
const auto degrees_def = degrees_minutes_seconds
| degrees_decimal_minutes
| decimal_degrees;
const auto northsouth = bp::no_case[ bp::char_("ns") ];
const auto eastwest = bp::no_case[ bp::char_("ew") ];
const auto latitude_def = (degrees >> northsouth) [( [](auto & ctx) {
auto d = _attr(ctx)[0_c];
auto ns = _attr(ctx)[1_c];
_pass(ctx) = d <= 90;
_val(ctx) = ns=='S' || ns=='s' ? -d : d;
} )];
const auto longitude_def = (degrees >> eastwest) [( [](auto & ctx) {
auto d = _attr(ctx)[0_c];
auto ew = _attr(ctx)[1_c];
_pass(ctx) = d <= 180;
_val(ctx) = ew=='W' || ew=='w' ? -d : d;
} )];
const auto signed_degrees = bp::double_ >> -degrees_symbol;
const auto signed_latitude_def = signed_degrees [( [](auto & ctx) { auto d = _attr(ctx); _pass(ctx) = -90 <= d && d <= 90; _val(ctx) = _attr(ctx); } )];
const auto signed_longitude_def = signed_degrees [( [](auto & ctx) { auto d = _attr(ctx); _pass(ctx) = -180 <= d && d <= 180; _val(ctx) = _attr(ctx); } )];
const auto latlon_def = ((latitude >> longitude) [( [](auto & ctx) { _val(ctx) = g2d::Vector{_attr(ctx)[1_c], _attr(ctx)[0_c]}; } )] )
| ((longitude >> latitude) [( [](auto & ctx) { _val(ctx) = g2d::Vector{_attr(ctx)[0_c], _attr(ctx)[1_c]}; } )] )
| ((signed_longitude >> signed_latitude)
[( [](auto & ctx) { _val(ctx) = g2d::Vector{_attr(ctx)[0_c], _attr(ctx)[1_c]}; } )] );
BOOST_PARSER_DEFINE_RULES(uint_0_60);
BOOST_PARSER_DEFINE_RULES(double_0_60);
BOOST_PARSER_DEFINE_RULES(degrees_decimal_minutes);
BOOST_PARSER_DEFINE_RULES(degrees_minutes_seconds);
BOOST_PARSER_DEFINE_RULES(degrees);
BOOST_PARSER_DEFINE_RULES(latitude);
BOOST_PARSER_DEFINE_RULES(longitude);
BOOST_PARSER_DEFINE_RULES(signed_latitude);
BOOST_PARSER_DEFINE_RULES(signed_longitude);
BOOST_PARSER_DEFINE_RULES(latlon);
#if 0
static std::optional<g2d::Vector> try_parse_latlon(std::string_view s)
{
auto input = latlon >> bp::eoi;
return parse(s,input, bp::ws|bp::lit(','));
}
int main(int argc, const char* argv[])
{
assert(argc==2);
auto opt_coords = try_parse_latlon(argv[1]);
if (!opt_coords) {
std::cerr << "parse error\n";
return 1;
} else {
std::cout << opt_coords->x << " " << opt_coords->y << "\n";
return 0;
}
}
#endif
TEST(parse_coords, all_examples)
{
std::vector<std::string> test_coords = {
"12.34 N, 56.78 E",
"56.78,-12.34",
"12d 30' n 45d 15' 7\" w",
"12 30 45 N, 45 15 7 W",
"12d 30m 15s S 50d 59m 59s W",
"50d 0.5m n 50d 59m 59s W"};
{
auto result = bp::parse(test_coords[0], latlon, bp::ws | bp::lit(','));
EXPECT_TRUE(result);
EXPECT_LT(std::abs(result->x - 56.78), 0.001);
EXPECT_LT(std::abs(result->y - 12.34), 0.001);
}
{
auto result = bp::parse(test_coords[1], latlon, bp::ws | bp::lit(','));
EXPECT_TRUE(result);
EXPECT_LT(std::abs(result->x - 56.78), 0.001);
EXPECT_LT(std::abs(result->y - -12.34), 0.001);
}
{
auto result = bp::parse(test_coords[2], latlon, bp::ws | bp::lit(','));
EXPECT_TRUE(result);
EXPECT_LT(std::abs(result->x - -45.2519), 0.001);
EXPECT_LT(std::abs(result->y - 12.5), 0.001);
}
{
auto result = bp::parse(test_coords[3], latlon, bp::ws | bp::lit(','));
EXPECT_TRUE(result);
EXPECT_LT(std::abs(result->x - -45.2519), 0.001);
EXPECT_LT(std::abs(result->y - 12.5125), 0.001);
}
{
auto result = bp::parse(test_coords[4], latlon, bp::ws | bp::lit(','));
EXPECT_TRUE(result);
EXPECT_LT(std::abs(result->x - -50.9997), 0.001);
EXPECT_LT(std::abs(result->y - -12.5042), 0.001);
}
{
auto result = bp::parse(test_coords[5], latlon, bp::ws | bp::lit(','));
EXPECT_TRUE(result);
EXPECT_LT(std::abs(result->x - -50.9997), 0.001);
EXPECT_LT(std::abs(result->y - 50.0083), 0.001);
}
}
#endif

View File

@@ -627,63 +627,61 @@ TEST(parser, star_and_plus_collapsing)
}
}
TEST(parser, action_)
TEST(parser, action)
{
{{std::string str = "";
std::stringstream ss;
auto action = [&ss](auto & context) { ss << _attr(context); };
auto parser = *char_('b')[action];
EXPECT_TRUE(parse(str, parser));
EXPECT_EQ(ss.str(), "");
}
{
std::string str = "b";
std::stringstream ss;
auto action = [&ss](auto & context) { ss << _attr(context); };
auto parser = *char_('b')[action];
EXPECT_TRUE(parse(str, parser));
EXPECT_EQ(ss.str(), "b");
}
{
std::string str = "bb";
std::stringstream ss;
auto action = [&ss](auto & context) { ss << _attr(context); };
auto parser = *char_('b')[action];
EXPECT_TRUE(parse(str, parser));
EXPECT_TRUE(parse(str, parser));
EXPECT_EQ(ss.str(), "bbbb");
}
}
{
{
std::string str = "";
{
std::stringstream ss;
auto action = [&ss](auto & ctx) { ss << _attr(ctx); };
auto parser = *char_('b')[action];
EXPECT_TRUE(parse(str, parser));
EXPECT_EQ(ss.str(), "");
}
{
str = "b";
std::stringstream ss;
auto action = [&ss](auto & ctx) { ss << _attr(ctx); };
auto parser = *char_('b')[action];
EXPECT_TRUE(parse(str, parser));
EXPECT_EQ(ss.str(), "b");
}
{
str = "bb";
std::stringstream ss;
auto action = [&ss](auto & ctx) { ss << _attr(ctx); };
auto parser = *char_('b')[action];
EXPECT_TRUE(parse(str, parser));
EXPECT_TRUE(parse(str, parser));
EXPECT_EQ(ss.str(), "bbbb");
}
std::stringstream ss;
auto action = [&ss](auto & context) { ss << _attr(context); };
auto parser = +char_('b')[action];
EXPECT_FALSE(parse(str, parser));
EXPECT_EQ(ss.str(), "");
}
{
{
std::string str = "";
std::stringstream ss;
auto action = [&ss](auto & ctx) { ss << _attr(ctx); };
auto parser = +char_('b')[action];
EXPECT_FALSE(parse(str, parser));
EXPECT_EQ(ss.str(), "");
}
{
std::string str = "b";
std::stringstream ss;
auto action = [&ss](auto & ctx) { ss << _attr(ctx); };
auto parser = +char_('b')[action];
EXPECT_TRUE(parse(str, parser));
EXPECT_EQ(ss.str(), "b");
}
{
std::string str = "bb";
std::stringstream ss;
auto action = [&ss](auto & ctx) { ss << _attr(ctx); };
auto parser = +char_('b')[action];
EXPECT_TRUE(parse(str, parser));
EXPECT_TRUE(parse(str, parser));
EXPECT_EQ(ss.str(), "bbbb");
}
std::string str = "b";
std::stringstream ss;
auto action = [&ss](auto & context) { ss << _attr(context); };
auto parser = +char_('b')[action];
EXPECT_TRUE(parse(str, parser));
EXPECT_EQ(ss.str(), "b");
}
{
std::string str = "bb";
std::stringstream ss;
auto action = [&ss](auto & context) { ss << _attr(context); };
auto parser = +char_('b')[action];
EXPECT_TRUE(parse(str, parser));
EXPECT_TRUE(parse(str, parser));
EXPECT_EQ(ss.str(), "bbbb");
}
}
}
TEST(parser, star_as_string_or_vector)
@@ -851,106 +849,6 @@ TEST(parser, star_as_string_or_vector)
}
}
TEST(parser, transform)
{
int calls = 0;
auto by_value_str_sum = [&](std::string s) {
++calls;
std::transform(
s.begin(), s.end(), s.begin(), [](auto ch) { return ch - '0'; });
return std::accumulate(s.begin(), s.end(), 0);
};
auto cref_str_sum = [&](std::string const & s) {
++calls;
int retval = 0;
for (auto ch : s) {
retval += ch - '0';
}
return retval;
};
auto rv_ref_str_sum = [&](std::string && s) {
++calls;
std::transform(
s.begin(), s.end(), s.begin(), [](auto ch) { return ch - '0'; });
return std::accumulate(s.begin(), s.end(), 0);
};
{
constexpr auto parser = +char_;
std::string str = "012345";
{
auto result = parse(str, parser);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "012345");
}
{
calls = 0;
auto result = parse(str, transform(by_value_str_sum)[parser]);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 15);
EXPECT_EQ(calls, 1);
}
{
calls = 0;
auto result = parse(str, transform(cref_str_sum)[parser]);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 15);
EXPECT_EQ(calls, 1);
}
{
calls = 0;
auto result = parse(str, transform(rv_ref_str_sum)[parser]);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 15);
EXPECT_EQ(calls, 1);
}
}
{
constexpr auto parser = +char_;
std::string str = "012345";
{
calls = 0;
auto result = parse(str, omit[transform(by_value_str_sum)[parser]]);
EXPECT_TRUE(result);
EXPECT_EQ(calls, 0);
}
{
calls = 0;
auto result = parse(str, omit[transform(cref_str_sum)[parser]]);
EXPECT_TRUE(result);
EXPECT_EQ(calls, 0);
}
{
calls = 0;
auto result = parse(str, omit[transform(rv_ref_str_sum)[parser]]);
EXPECT_TRUE(result);
EXPECT_EQ(calls, 0);
}
}
}
TEST(parser, transform_doc_example)
{
//[ transform_directive_example
auto str_sum = [&](std::string const & s) {
int retval = 0;
for (auto ch : s) {
retval += ch - '0';
}
return retval;
};
namespace bp = boost::parser;
constexpr auto parser = +bp::char_;
std::string str = "012345";
auto result = bp::parse(str, bp::transform(str_sum)[parser]);
assert(result);
assert(*result == 15);
static_assert(std::is_same_v<decltype(result), std::optional<int>>);
//]
(void)result;
}
TEST(parser, omit)
{
{
@@ -2144,7 +2042,11 @@ TEST(parser, combined_seq_and_or)
{
std::string str = "abc";
tuple<std::any, std::any, std::any> chars;
tuple<
boost::parser::detail::any_copyable,
boost::parser::detail::any_copyable,
boost::parser::detail::any_copyable>
chars;
EXPECT_TRUE(parse(str, parser, chars));
}
@@ -2265,13 +2167,6 @@ TEST(parser, combined_seq_and_or)
EXPECT_EQ(chars, "xyz");
}
}
{
constexpr auto parser = int_ >> -(lit('a') | 'b');
auto result = parse("34b", parser);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 34);
}
}
TEST(parser, eol_)
@@ -2954,64 +2849,3 @@ TEST(parser, rule_example)
using namespace rule_construction_example;
EXPECT_TRUE(bp::parse("3 4", type, bp::ws));
}
TEST(parser, utf_iterator_copy_ctor)
{
namespace bp = boost::parser;
char mut_chars[] = "foo";
char const const_chars[] = "bar";
auto mut_view = mut_chars | bp::as_utf8;
auto const_view = const_chars | bp::as_utf8;
auto mut_it = mut_view.begin();
auto mut_last = mut_view.end();
auto const_it = const_view.begin();
auto const_last = const_view.begin();
const_it = mut_it;
const_last = mut_last;
std::string copy;
copy.resize(3);
std::copy(const_it, const_last, copy.begin());
EXPECT_EQ(copy, "foo");
}
namespace github_issue_125_ {
namespace bp = boost::parser;
constexpr bp::
rule<struct replacement_field_rule, std::optional<unsigned short>>
replacement_field = "replacement_field";
constexpr auto replacement_field_def = bp::lit('{') >> -bp::ushort_;
BOOST_PARSER_DEFINE_RULES(replacement_field);
}
TEST(parser, github_issue_125)
{
namespace bp = boost::parser;
using namespace github_issue_125_;
unsigned short integer_found = 99;
auto print_repl_field = [&](auto & ctx) {
const std::optional<unsigned short> & val = bp::_attr(ctx);
if (val)
integer_found = *val;
else
integer_found = 77;
};
{
integer_found = 99;
auto result = bp::parse("{9", replacement_field[print_repl_field]);
EXPECT_TRUE(result);
EXPECT_EQ(integer_found, 9);
}
{
integer_found = 99;
auto result = bp::parse("{", replacement_field[print_repl_field]);
EXPECT_TRUE(result);
EXPECT_EQ(integer_found, 77);
}
}

View File

@@ -14,29 +14,31 @@ constexpr rule<struct abc_def_tag, std::string> abc_def = "abc or def";
constexpr auto abc_def_def = string("abc") | string("def");
BOOST_PARSER_DEFINE_RULES(abc_def);
auto const fail = [](auto & ctx) { _pass(ctx) = false; };
auto const fail = [](auto & context) { _pass(context) = false; };
constexpr rule<struct fail_abc_pass_def_tag, std::string> fail_abc_pass_def =
"abc";
constexpr auto fail_abc_pass_def_def = string("abc")[fail] | string("def");
BOOST_PARSER_DEFINE_RULES(fail_abc_pass_def);
auto const attr_to_val = [](auto & ctx) { _val(ctx) = _attr(ctx); };
auto const attr_to_val = [](auto & context) { _val(context) = _attr(context); };
constexpr rule<struct action_copy_abc_def_tag, std::string>
action_copy_abc_def = "abc or def";
constexpr auto action_copy_abc_def_def =
string("abc")[attr_to_val] | string("def")[attr_to_val];
BOOST_PARSER_DEFINE_RULES(action_copy_abc_def);
auto const abc_value = [](auto & ctx) { _val(ctx) = "abc"; };
auto const def_value = [](auto & ctx) { _val(ctx) = "def"; };
auto const abc_value = [](auto & context) { _val(context) = "abc"; };
auto const def_value = [](auto & context) { _val(context) = "def"; };
constexpr rule<struct rev_abc_def_tag, std::string> rev_abc_def = "abc or def";
constexpr auto rev_abc_def_def =
string("abc")[def_value] | string("def")[abc_value];
BOOST_PARSER_DEFINE_RULES(rev_abc_def);
auto const append_attr = [](auto & ctx) { _locals(ctx) += _attr(ctx); };
auto const locals_to_val = [](auto & ctx) {
_val(ctx) = std::move(_locals(ctx));
auto const append_attr = [](auto & context) {
_locals(context) += _attr(context);
};
auto const locals_to_val = [](auto & context) {
_val(context) = std::move(_locals(context));
};
rule<struct locals_abc_def_tag, std::string, std::string> const locals_abc_def =
"abc or def";
@@ -44,10 +46,10 @@ auto locals_abc_def_def = -string("abc")[append_attr] >>
-string("def")[append_attr] >> eps[locals_to_val];
BOOST_PARSER_DEFINE_RULES(locals_abc_def);
TEST(action, side_effects)
TEST(parser, side_effects)
{
int i = 0;
auto increment_i = [&i](auto & ctx) { ++i; };
auto increment_i = [&i](auto & context) { ++i; };
using no_attribute_return = decltype(parse("xyz", char_('a')[increment_i]));
static_assert(std::is_same_v<no_attribute_return, bool>);
@@ -73,7 +75,7 @@ TEST(action, side_effects)
}
}
TEST(action, pass)
TEST(parser, pass)
{
{
std::string const str = "xyz";
@@ -105,7 +107,7 @@ TEST(action, pass)
}
}
TEST(action, val_attr)
TEST(parser, val_attr)
{
{
std::string const str = "abc";
@@ -133,7 +135,7 @@ TEST(action, val_attr)
}
}
TEST(action, locals)
TEST(parser, locals)
{
{
std::string const str = "";
@@ -160,60 +162,3 @@ TEST(action, locals)
EXPECT_EQ(*result, "def");
}
}
auto drop_result = [](auto & ctx) {};
auto auto_assign = [](auto & ctx) { return _attr(ctx); };
auto auto_assign_multi_string_1 = [](std::string const & str1,
std::string const & str2) {
return str1 + str2;
};
auto auto_assign_multi_string_2 = [](std::string && str1, std::string && str2) {
return str1 + str2;
};
constexpr rule<struct str_rule_1_tag, std::string> str_rule_1 = "str_rule_1";
constexpr auto str_rule_1_def = +char_;
BOOST_PARSER_DEFINE_RULES(str_rule_1);
constexpr rule<struct str_rule_2_tag, std::string> str_rule_2 = "str_rule_2";
constexpr auto str_rule_2_def = (+char_)[drop_result];
BOOST_PARSER_DEFINE_RULES(str_rule_2);
constexpr rule<struct str_rule_3_tag, std::string> str_rule_3 = "str_rule_3";
constexpr auto str_rule_3_def = (+char_)[auto_assign];
BOOST_PARSER_DEFINE_RULES(str_rule_3);
constexpr rule<struct str_rule_6_tag, std::string> str_rule_6 = "str_rule_6";
constexpr auto str_rule_6_def =
(+(char_ - ' ') >> ' ' >> +char_)[auto_assign_multi_string_1];
BOOST_PARSER_DEFINE_RULES(str_rule_6);
constexpr rule<struct str_rule_7_tag, std::string> str_rule_7 = "str_rule_7";
constexpr auto str_rule_7_def =
(+(char_ - ' ') >> ' ' >> +char_)[auto_assign_multi_string_2];
BOOST_PARSER_DEFINE_RULES(str_rule_7);
TEST(action, alternate_invocables)
{
{
auto result_1 = parse("some text", str_rule_1);
EXPECT_TRUE(result_1);
EXPECT_EQ(*result_1, "some text");
auto result_2 = parse("some text", str_rule_2);
EXPECT_TRUE(result_2);
EXPECT_EQ(*result_2, "");
auto result_3 = parse("some text", str_rule_3);
EXPECT_TRUE(result_3);
EXPECT_EQ(*result_3, "some text");
auto result_6 = parse("some text", str_rule_6);
EXPECT_TRUE(result_6);
EXPECT_EQ(*result_6, "sometext");
auto result_7 = parse("some text", str_rule_7);
EXPECT_TRUE(result_7);
EXPECT_EQ(*result_7, "sometext");
}
}

View File

@@ -15,7 +15,7 @@ auto make_13 = [](auto & context) { return 13; };
auto const first_param_to_val = [](auto & context) {
using namespace boost::parser::literals;
_val(context) = (int)get(_params(context), 0_c);
_val(context) = get(_params(context), 0_c);
};
auto const second_param_to_val = [](auto & context) {
using namespace boost::parser::literals;

View File

@@ -115,12 +115,11 @@ TEST(parser, full_parse_api)
EXPECT_EQ(out, 'a');
out = 0;
first = str.c_str();
auto ws_copy = ws;
EXPECT_FALSE(prefix_parse(
first,
boost::parser::detail::text::null_sentinel,
char_('b'),
ws_copy,
ws,
out));
EXPECT_EQ(out, 0);
}
@@ -139,8 +138,7 @@ TEST(parser, full_parse_api)
EXPECT_TRUE(parse(str.c_str(), char_, ws, out));
EXPECT_EQ(out, 'a');
out = 0;
auto ws_copy = ws;
EXPECT_FALSE(parse(str.c_str(), char_('b'), ws_copy, out));
EXPECT_FALSE(parse(str.c_str(), char_('b'), ws, out));
EXPECT_EQ(out, 0);
}
@@ -158,12 +156,11 @@ TEST(parser, full_parse_api)
ws),
'a');
first = str.c_str();
auto ws_copy = ws;
EXPECT_TRUE(!prefix_parse(
first,
boost::parser::detail::text::null_sentinel,
char_('b'),
ws_copy));
ws));
}
// returned attr, using skipper, range
{
@@ -175,8 +172,7 @@ TEST(parser, full_parse_api)
{
EXPECT_TRUE(parse(str.c_str(), char_, ws));
EXPECT_EQ(*parse(str.c_str(), char_, ws), 'a');
auto ws_copy = ws;
EXPECT_FALSE(parse(str.c_str(), char_('b'), ws_copy));
EXPECT_FALSE(parse(str.c_str(), char_('b'), ws));
}
// callback, iter/sent
@@ -221,20 +217,6 @@ TEST(parser, full_parse_api)
first = str.c_str();
EXPECT_EQ(out, 'a');
}
{
char out = 0;
auto callbacks = [&out](auto tag, auto x) { out = x; };
auto first = str.c_str();
auto ws_copy = ws;
EXPECT_TRUE(callback_prefix_parse(
first,
boost::parser::detail::text::null_sentinel,
callback_char_rule,
ws_copy,
callbacks));
first = str.c_str();
EXPECT_EQ(out, 'a');
}
// callback, using skipper, range
{
char out = 0;
@@ -247,9 +229,8 @@ TEST(parser, full_parse_api)
{
char out = 0;
auto callbacks = [&out](auto tag, auto x) { out = x; };
auto ws_copy = ws;
EXPECT_TRUE(callback_parse(
str.c_str(), callback_char_rule, ws_copy, callbacks));
str.c_str(), callback_char_rule, ws, callbacks));
EXPECT_EQ(out, 'a');
}
}
@@ -1816,7 +1797,11 @@ TEST(parser, combined_seq_and_or)
{
char const * str = "abc";
tuple<std::any, std::any, std::any> chars;
tuple<
boost::parser::detail::any_copyable,
boost::parser::detail::any_copyable,
boost::parser::detail::any_copyable>
chars;
EXPECT_TRUE(parse(str, parser, chars));
}
@@ -1994,7 +1979,6 @@ TEST(parser, attr_out_param_compat)
using namespace bp::literals;
assert(success);
(void)success;
assert(bp::get(result, 0_c) == std::vector<int>({'r', U'ô', 'l', 'e'}));
assert(bp::get(result, 1_c) == "foo");
}
@@ -2012,7 +1996,6 @@ TEST(parser, attr_out_param_compat)
using namespace bp::literals;
assert(success);
(void)success;
// The 4 code points "rôle" get transcoded to 5 UTF-8 code points to fit in the std::string.
assert(bp::get(result, 0_c) == std::vector<char>({'r', (char)0xc3, (char)0xb4, 'l', 'e'}));
assert(bp::get(result, 1_c) == "foo");

View File

@@ -1,67 +0,0 @@
/**
* Copyright (C) 2024 T. Zachary Laine
*
* Distributed under the Boost Software License, Version 1.0. (See
* accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
#include <boost/parser/parser.hpp>
#include <gtest/gtest.h>
namespace bp = boost::parser;
bp::rule<struct seq1_tag, bp::tuple<int, char>> seq1 = "";
bp::rule<struct seq2_tag, bp::tuple<int, char>> seq2 = "";
auto const seq1_def = bp::int_ >> bp::char_('a');
auto const seq2_def = bp::int_ >> bp::char_('b');
BOOST_PARSER_DEFINE_RULES(seq1, seq2);
TEST(attributes, internal_errors_munging_attributes)
{
// These are just some assorted cases that have, or seemed likely to,
// cause problems when an internal failure in an alternative wipes out an
// existing result. This covers all the cases where "if (!success)"
// causes the attribute to be overwritten with a default-constructed
// value.
{
auto const parser =
bp::string("FOO") >> -(bp::string("bar") | bp::string("foo"));
auto result = bp::parse("FOOfoo", parser);
EXPECT_TRUE(result);
EXPECT_EQ(bp::get(*result, bp::llong<0>{}), std::string("FOO"));
EXPECT_EQ(bp::get(*result, bp::llong<1>{}), std::string("foo"));
}
{
auto const parser = bp::merge
[bp::string("FOO") >> (bp::string("bar") | bp::string("foo"))];
auto result = bp::parse("FOOfoo", parser);
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::string("FOOfoo"));
}
{
auto const parser = bp::merge
[(bp::attr(std::vector<std::string>({"FOO"})) | bp::eps) >>
(bp::repeat(1)[bp::string("foo")] | bp::eps)];
auto result = bp::parse("", parser);
EXPECT_TRUE(result);
EXPECT_TRUE(*result);
EXPECT_EQ(*result, std::vector<std::string>({"FOO"}));
}
{
auto const parser = bp::merge[seq1 >> (seq2 | seq1)];
auto result = bp::parse("7a9a", parser);
EXPECT_TRUE(result);
EXPECT_EQ(*result, (bp::tuple<int, char>(9, 'a')));
}
}

View File

@@ -1,338 +0,0 @@
/**
* Copyright (C) 2024 T. Zachary Laine
*
* Distributed under the Boost Software License, Version 1.0. (See
* accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
#include <boost/parser/parser.hpp>
#include <gtest/gtest.h>
namespace bp = boost::parser;
namespace make {
template<typename... Ts>
auto tuple(Ts &&... xs)
{
return bp::tuple<Ts...>((Ts &&) xs...);
}
}
/*
{P0, -P0, *P0, P1, P2, P3, eps}
<cartesian product>
{P0, P1, P2, P3, eps, *P0, -P0, (P0 |/>> P2), -(P0 |/>> P1), (-P0 |/>> P1)}
P0 = bp::string("foo");
P1 = bp::string("bar");
P2 = bp::int_;
P3 = bp::char_('c');
*/
using namespace std::literals;
TEST(attributes, or_parser_permutations_1)
{
[[maybe_unused]] int dummy = 0; // for clang-format(!)
// P0
{
auto result = bp::parse("foo", bp::string("foo") | bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, "foo"s);
}
{
auto result = bp::parse("bar", bp::string("foo") | bp::string("bar"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, "bar"s);
}
{
auto result = bp::parse("42", bp::string("foo") | bp::int_);
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(std::get<int>(*result), 42);
}
{
auto result = bp::parse("c", bp::string("foo") | bp::char_('c'));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(std::get<char>(*result), 'c');
}
{
auto result = bp::parse("foo", bp::string("foo") | bp::eps);
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::optional("foo"s));
}
{
auto result = bp::parse("foo", bp::string("foo") | *bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::string>(*result), "foo"s);
}
{
auto result = bp::parse("", bp::string("foo") | -bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(std::get<std::optional<std::string>>(*result), std::nullopt);
}
{
auto result = bp::parse(
"foo", bp::string("foo") | (bp::string("foo") | bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::string>(*result), "foo"s);
}
{
auto result = bp::parse(
"bar",
bp::string("foo") | -(bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1);
EXPECT_EQ(std::get<std::optional<std::string>>(*result), "bar"s);
}
{
auto result = bp::parse(
"", bp::string("foo") | (-bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1);
EXPECT_EQ(std::get<std::optional<std::string>>(*result), std::nullopt);
}
{
auto result = bp::parse(
"foo", bp::string("foo") | (bp::string("foo") >> bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::string>(*result), "foo"s);
}
{
auto result = bp::parse(
"", bp::string("foo") | -(bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(
(std::get<std::optional<bp::tuple<std::string, std::string>>>(
*result)),
std::nullopt);
}
{
auto result = bp::parse(
"bar",
bp::string("foo") | (-bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(
(std::get<bp::tuple<std::optional<std::string>, std::string>>(
*result)),
(make::tuple(std::optional<std::string>{}, "bar"s)));
}
// -P0
{
auto result = bp::parse("foo", -bp::string("foo") | bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(
std::get<std::optional<std::string>>(*result),
std::optional("foo"s));
}
{
auto result = bp::parse("", -bp::string("foo") | bp::string("bar"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::optional<std::string>>(*result), std::nullopt);
}
{
auto result = bp::parse("", -bp::string("foo") | bp::int_);
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::optional<std::string>>(*result), std::nullopt);
}
{
auto result = bp::parse("", -bp::string("foo") | bp::char_('c'));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::optional<std::string>>(*result), std::nullopt);
}
{
auto result = bp::parse("foo", -bp::string("foo") | bp::eps);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "foo"s);
}
{
auto result = bp::parse("foo", -bp::string("foo") | *bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::optional<std::string>>(*result), "foo"s);
}
{
auto result = bp::parse("foo", -bp::string("foo") | -bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, "foo"s);
}
{
auto result =
bp::parse("", -bp::string("foo") | (bp::string("foo") | bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::optional<std::string>>(*result), std::nullopt);
}
{
auto result = bp::parse(
"foo",
-bp::string("foo") | -(bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(*result, "foo"s);
}
{
auto result = bp::parse(
"", -bp::string("foo") | (-bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::optional<std::string>>(*result), std::nullopt);
}
{
auto result = bp::parse(
"foo", -bp::string("foo") | (bp::string("foo") >> bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::optional<std::string>>(*result), "foo"s);
}
{
auto result = bp::parse(
"foo",
-bp::string("foo") | -(bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::optional<std::string>>(*result), "foo"s);
}
{
auto result = bp::parse(
"foo",
-bp::string("foo") | (-bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::optional<std::string>>(*result), "foo"s);
}
// *P0
{
auto result = bp::parse(
"foo", bp::lexeme[*bp::string("foo")] | bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(
std::get<std::vector<std::string>>(*result), std::vector({"foo"s}));
}
{
auto result =
bp::parse("foofoo", *bp::string("foo") | bp::string("bar"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(
std::get<std::vector<std::string>>(*result),
std::vector({"foo"s, "foo"s}));
}
{
auto result = bp::parse("", *bp::string("foo") | bp::int_);
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(
std::get<std::vector<std::string>>(*result),
std::vector<std::string>{});
}
{
auto result = bp::parse("", *bp::string("foo") | bp::char_('c'));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(
std::get<std::vector<std::string>>(*result),
std::vector<std::string>{});
}
{
auto result = bp::parse("foofoo", *bp::string("foo") | bp::eps);
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::optional(std::vector({"foo"s, "foo"s})));
}
{
auto result = bp::parse(
"foofoo", bp::lexeme[*bp::string("foo")] | *bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::vector({"foo"s, "foo"s}));
}
{
auto result =
bp::parse("foofoo", *bp::string("foo") | -bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(
std::get<std::vector<std::string>>(*result),
std::vector({"foo"s, "foo"s}));
}
{
auto result = bp::parse(
"foofoo",
bp::lexeme[*bp::string("foo")] | (bp::string("foo") | bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(
std::get<std::vector<std::string>>(*result),
std::vector({"foo"s, "foo"s}));
}
{
auto result = bp::parse(
"foofoo",
bp::lexeme[*bp::string("foo")] |
-(bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(
std::get<std::vector<std::string>>(*result),
std::vector({"foo"s, "foo"s}));
}
{
auto result = bp::parse(
"foofoo",
bp::lexeme[*bp::string("foo")] |
(-bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(
std::get<std::vector<std::string>>(*result),
std::vector({"foo"s, "foo"s}));
}
{
auto result = bp::parse(
"foofoo",
bp::lexeme[*bp::string("foo")] | (bp::string("foo") >> bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(
std::get<std::vector<std::string>>(*result),
std::vector({"foo"s, "foo"s}));
}
{
auto result = bp::parse(
"foofoo",
bp::lexeme[*bp::string("foo")] |
-(bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(
std::get<std::vector<std::string>>(*result),
std::vector({"foo"s, "foo"s}));
}
{
auto result = bp::parse(
"foofoo",
bp::lexeme[*bp::string("foo")] |
(-bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(
std::get<std::vector<std::string>>(*result),
std::vector({"foo"s, "foo"s}));
}
}

View File

@@ -1,312 +0,0 @@
/**
* Copyright (C) 2024 T. Zachary Laine
*
* Distributed under the Boost Software License, Version 1.0. (See
* accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
#include <boost/parser/parser.hpp>
#include <gtest/gtest.h>
namespace bp = boost::parser;
namespace make {
template<typename... Ts>
auto tuple(Ts &&... xs)
{
return bp::tuple<Ts...>((Ts &&) xs...);
}
}
/*
{P0, -P0, *P0, P1, P2, P3, eps}
<cartesian product>
{P0, P1, P2, P3, eps, *P0, -P0, (P0 >>/| P2), -(P0 >>/| P1), (-P0 >>/| P1)}
P0 = bp::string("foo");
P1 = bp::string("bar");
P2 = bp::int_;
P3 = bp::char_('c');
*/
using namespace std::literals;
TEST(attributes, or_parser_permutations_2)
{
[[maybe_unused]] int dummy = 0; // for clang-format(!)
// P1
{
auto result = bp::parse("foo", bp::string("bar") | bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, "foo"s);
}
{
auto result = bp::parse("bar", bp::string("bar") | bp::string("bar"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, "bar"s);
}
{
auto result = bp::parse("42", bp::string("bar") | bp::int_);
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(std::get<int>(*result), 42);
}
{
auto result = bp::parse("bar", bp::string("bar") | bp::char_('c'));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::string>(*result), "bar"s);
}
{
auto result = bp::parse("", bp::string("bar") | bp::eps);
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::nullopt);
}
{
auto result =
bp::parse("foofoo", bp::string("bar") | *bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(
std::get<std::vector<std::string>>(*result),
std::vector({"foo"s, "foo"s}));
}
{
auto result = bp::parse("bar", bp::string("bar") | -bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::string>(*result), "bar"s);
}
{
auto result =
bp::parse("42", bp::string("bar") | (bp::string("foo") | bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(std::get<int>(*result), 42);
}
{
auto result = bp::parse(
"bar",
bp::string("foo") | -(bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(std::get<std::optional<std::string>>(*result), "bar"s);
}
{
auto result = bp::parse(
"foo",
bp::string("bar") | (-bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(std::get<std::optional<std::string>>(*result), "foo"s);
}
{
auto result = bp::parse(
"bar", bp::string("bar") | (bp::string("foo") >> bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::string>(*result), "bar"s);
}
{
auto result = bp::parse(
"bar",
bp::string("bar") | -(bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::string>(*result), "bar"s);
}
{
auto result = bp::parse(
"bar",
bp::string("bar") | (-bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::string>(*result), "bar"s);
}
// P2
{
auto result = bp::parse("42", bp::int_ | bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<int>(*result), 42);
}
{
auto result = bp::parse("bar", bp::int_ | bp::string("bar"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(std::get<std::string>(*result), "bar"s);
}
{
auto result = bp::parse("42", bp::int_ | bp::int_, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 42);
}
{
auto result = bp::parse("c", bp::int_ | bp::char_('c'));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(std::get<char>(*result), 'c');
}
{
auto result = bp::parse("", bp::int_ | bp::eps);
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::nullopt);
}
{
auto result = bp::parse("foofoo", bp::int_ | *bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(
std::get<std::vector<std::string>>(*result),
std::vector({"foo"s, "foo"s}));
}
{
auto result = bp::parse("42", bp::int_ | -bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<int>(*result), 42);
}
{
auto result =
bp::parse("42", bp::int_ | (bp::string("foo") | bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<int>(*result), 42);
}
{
auto result = bp::parse(
"bar", bp::int_ | -(bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(
std::get<std::optional<std::string>>(*result),
std::optional("bar"s));
}
{
auto result =
bp::parse("", bp::int_ | (-bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(std::get<std::optional<std::string>>(*result), std::nullopt);
}
{
auto result =
bp::parse("42", bp::int_ | (bp::string("foo") >> bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<int>(*result), 42);
}
{
auto result = bp::parse(
"42", bp::int_ | -(bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<int>(*result), 42);
}
{
auto result = bp::parse(
"42", bp::int_ | (-bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<int>(*result), 42);
}
// P3
{
auto result = bp::parse("c", bp::char_('c') | bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<char>(*result), 'c');
}
{
auto result = bp::parse("bar", bp::char_('c') | bp::string("bar"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(std::get<std::string>(*result), "bar"s);
}
{
auto result = bp::parse("42", bp::char_('c') | bp::int_);
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(std::get<int>(*result), 42);
}
{
auto result = bp::parse("c", bp::char_('c') | bp::char_('c'));
EXPECT_TRUE(result);
EXPECT_EQ(*result, 'c');
}
{
auto result = bp::parse("c", bp::char_('c') | bp::eps);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 'c');
}
{
auto result = bp::parse("foofoo", bp::char_('c') | *bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(
std::get<std::vector<std::string>>(*result),
std::vector({"foo"s, "foo"s}));
}
{
auto result = bp::parse("c", bp::char_('c') | -bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<char>(*result), 'c');
}
{
auto result =
bp::parse("42", bp::char_('c') | (bp::string("foo") | bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 2u);
EXPECT_EQ(std::get<int>(*result), 42);
}
{
auto result = bp::parse(
"bar", bp::char_('c') | -(bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(
std::get<std::optional<std::string>>(*result),
std::optional("bar"s));
}
{
auto result = bp::parse(
"foo", bp::char_('c') | (-bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(
std::get<std::optional<std::string>>(*result),
std::optional("foo"s));
}
{
auto result = bp::parse(
"foo42", bp::char_('c') | (bp::string("foo") >> bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(
(std::get<bp::tuple<std::string, int>>(*result)),
(make::tuple("foo"s, 42)));
}
{
auto result = bp::parse(
"c", bp::char_('c') | -(bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<char>(*result), 'c');
}
{
auto result = bp::parse(
"c", bp::char_('c') | (-bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<char>(*result), 'c');
}
// eps | ... prohibited.
}

View File

@@ -1,90 +0,0 @@
/**
* Copyright (C) 2024 T. Zachary Laine
*
* Distributed under the Boost Software License, Version 1.0. (See
* accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
#include <boost/parser/parser.hpp>
#include <gtest/gtest.h>
namespace bp = boost::parser;
using namespace std::literals;
TEST(permutation_parser, basic)
{
{
constexpr auto parser = bp::int_ || bp::string("foo");
{
auto result = bp::parse("42 foo", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, (bp::tuple<int, std::string>(42, "foo"s)));
}
{
auto result = bp::parse("42foo", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, (bp::tuple<int, std::string>(42, "foo"s)));
}
{
auto result = bp::parse("foo 42", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, (bp::tuple<int, std::string>(42, "foo"s)));
}
{
auto result = bp::parse("foo42", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, (bp::tuple<int, std::string>(42, "foo"s)));
}
}
{
constexpr auto parser = bp::int_ || bp::string("foo") || bp::char_('g');
{
auto result = bp::parse("42 foo g", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(bp::tuple<int, std::string, double>(42, "foo"s, 'g')));
}
{
auto result = bp::parse("42 g foo", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(bp::tuple<int, std::string, double>(42, "foo"s, 'g')));
}
{
auto result = bp::parse("foo 42 g", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(bp::tuple<int, std::string, double>(42, "foo"s, 'g')));
}
{
auto result = bp::parse("foo g 42", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(bp::tuple<int, std::string, double>(42, "foo"s, 'g')));
}
{
auto result = bp::parse("g foo 42", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(bp::tuple<int, std::string, double>(42, "foo"s, 'g')));
}
{
auto result = bp::parse("g 42 foo", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(bp::tuple<int, std::string, double>(42, "foo"s, 'g')));
}
}
}

View File

@@ -1,279 +0,0 @@
/**
* Copyright (C) 2024 T. Zachary Laine
*
* Distributed under the Boost Software License, Version 1.0. (See
* accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
#include <boost/parser/parser.hpp>
#include <boost/parser/transcode_view.hpp>
#include <gtest/gtest.h>
namespace bp = boost::parser;
bp::symbols<char> const cu_escapes = {{"t", '\t'}, {"r", '\r'}, {"n", '\n'}};
bp::symbols<char32_t> const cp_escapes = {
{"t", '\t'}, {"r", '\r'}, {"n", '\n'}};
TEST(quoted_string, basic)
{
constexpr auto parser = bp::quoted_string;
{
auto result = bp::parse("", parser, bp::ws);
EXPECT_FALSE(result);
}
{
auto result = bp::parse(R"("foo")", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "foo");
}
{
auto result = bp::parse(R"("foo\\")", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "foo\\");
}
{
auto result = bp::parse(R"("\"foo\"")", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "\"foo\"");
}
}
TEST(quoted_string, different_char)
{
constexpr auto parser = bp::quoted_string('\'');
{
auto result = bp::parse("", parser, bp::ws);
EXPECT_FALSE(result);
}
{
auto result = bp::parse(R"('foo')", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "foo");
}
{
auto result = bp::parse(R"('foo\\')", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "foo\\");
}
{
auto result = bp::parse(R"('\'foo\'')", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "'foo'");
}
}
TEST(quoted_string, different_char_with_escapes)
{
{
auto parser = bp::quoted_string('\'', cu_escapes);
{
auto result = bp::parse("", parser, bp::ws);
EXPECT_FALSE(result);
}
{
auto result = bp::parse(R"('foo\t')", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "foo\t");
}
{
auto result = bp::parse(R"('foo\x')", parser, bp::ws);
EXPECT_FALSE(result);
}
}
{
auto parser = bp::quoted_string('\'', cp_escapes);
{
auto result = bp::parse("", parser, bp::ws);
EXPECT_FALSE(result);
}
{
auto result = bp::parse(R"('\tfoo')", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "\tfoo");
}
{
auto result = bp::parse(R"('f\xoo')", parser, bp::ws);
EXPECT_FALSE(result);
}
}
}
TEST(quoted_string, char_set)
{
constexpr auto parser = bp::quoted_string("'\"");
{
auto result = bp::parse("", parser, bp::ws);
EXPECT_FALSE(result);
}
{
EXPECT_FALSE(bp::parse(R"('foo")", parser, bp::ws));
EXPECT_FALSE(bp::parse(R"("foo')", parser, bp::ws));
}
{
auto result = bp::parse(R"('foo')", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "foo");
}
{
auto result = bp::parse(R"("foo")", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "foo");
}
{
auto result = bp::parse(R"('foo\\')", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "foo\\");
}
{
auto result = bp::parse(R"("foo\\")", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "foo\\");
}
{
auto result = bp::parse(R"('\'foo\'')", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "'foo'");
}
{
auto result = bp::parse(R"("\"foo\"")", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "\"foo\"");
}
{
// Can't escape arbitrary characters, only backslash and the quote
// character.
EXPECT_FALSE(bp::parse(R"("\'foo")", parser, bp::ws));
}
}
TEST(quoted_string, char_set_with_escapes)
{
{
auto parser = bp::quoted_string("'\"", cu_escapes);
{
auto result = bp::parse("", parser, bp::ws);
EXPECT_FALSE(result);
}
{
EXPECT_FALSE(bp::parse(R"('foo")", parser, bp::ws));
EXPECT_FALSE(bp::parse(R"("foo')", parser, bp::ws));
}
{
auto result = bp::parse(R"('foo\t')", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "foo\t");
}
{
auto result = bp::parse(R"("\tfoo")", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "\tfoo");
}
{
auto result = bp::parse(R"('foo\x')", parser, bp::ws);
EXPECT_FALSE(result);
}
}
{
auto parser = bp::quoted_string("'\"", cp_escapes);
{
auto result = bp::parse("", parser, bp::ws);
EXPECT_FALSE(result);
}
{
EXPECT_FALSE(bp::parse(R"('foo")", parser, bp::ws));
EXPECT_FALSE(bp::parse(R"("foo')", parser, bp::ws));
}
{
auto result = bp::parse(R"('foo\t')", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "foo\t");
}
{
auto result = bp::parse(R"("\tfoo")", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "\tfoo");
}
{
auto result = bp::parse(R"('foo\x')", parser, bp::ws);
EXPECT_FALSE(result);
}
}
}
TEST(quoted_string, doc_examples)
{
//[ quoted_string_example_1_2
namespace bp = boost::parser;
auto result1 = bp::parse("\"some text\"", bp::quoted_string, bp::ws);
assert(result1);
std::cout << *result1 << "\n"; // Prints: some text
auto result2 =
bp::parse("\"some \\\"text\\\"\"", bp::quoted_string, bp::ws);
assert(result2);
std::cout << *result2 << "\n"; // Prints: some "text"
//]
//[ quoted_string_example_3
auto result3 = bp::parse("!some text!", bp::quoted_string('!'), bp::ws);
assert(result3);
std::cout << *result3 << "\n"; // Prints: some text
//]
//[ quoted_string_example_4
auto result4 = bp::parse("'some text'", bp::quoted_string("'\""), bp::ws);
assert(result4);
std::cout << *result4 << "\n"; // Prints: some text
//]
//[ quoted_string_example_5
// the c++ simple escapes
bp::symbols<char> const escapes = {
{"'", '\''},
{"?", '\?'},
{"a", '\a'},
{"b", '\b'},
{"f", '\f'},
{"n", '\n'},
{"r", '\r'},
{"t", '\t'},
{"v", '\v'}};
auto result5 =
bp::parse("\"some text\r\"", bp::quoted_string('"', escapes), bp::ws);
assert(result5);
std::cout << *result5 << "\n"; // Prints (with a CRLF newline): some text
//]
}

View File

@@ -557,85 +557,3 @@ namespace more_about_rules_4 {
return bp::parse(str, bp::omit[parens], bp::ws);
}
}
// clang-format off
namespace param_example {
//[ extended_param_yaml_example_rules
namespace bp = boost::parser;
// A type to represent the YAML parse context.
enum class context {
block_in,
block_out,
block_key,
flow_in,
flow_out,
flow_key
};
// A YAML value; no need to fill it in for this example.
struct value
{
// ...
};
// YAML [66], just stubbed in here.
auto const s_separate_in_line = bp::eps;
// YAML [137].
bp::rule<struct c_flow_seq_tag, value> c_flow_sequence = "c-flow-sequence";
// YAML [80].
bp::rule<struct s_separate_tag> s_separate = "s-separate";
// YAML [136].
bp::rule<struct in_flow_tag, value> in_flow = "in-flow";
// YAML [138]; just eps below.
bp::rule<struct ns_s_flow_seq_entries_tag, value> ns_s_flow_seq_entries =
"ns-s-flow-seq-entries";
// YAML [81]; just eps below.
bp::rule<struct s_separate_lines_tag> s_separate_lines = "s-separate-lines";
// Parser for YAML [137].
auto const c_flow_sequence_def =
'[' >>
-s_separate.with(bp::_p<0>, bp::_p<1>) >>
-in_flow.with(bp::_p<0>, bp::_p<1>) >>
']';
// Parser for YAML [80].
auto const s_separate_def = bp::switch_(bp::_p<1>)
(context::block_out, s_separate_lines.with(bp::_p<0>))
(context::block_in, s_separate_lines.with(bp::_p<0>))
(context::flow_out, s_separate_lines.with(bp::_p<0>))
(context::flow_in, s_separate_lines.with(bp::_p<0>))
(context::block_key, s_separate_in_line)
(context::flow_key, s_separate_in_line);
// Parser for YAML [136].
auto const in_flow_def = bp::switch_(bp::_p<1>)
(context::flow_out, ns_s_flow_seq_entries.with(bp::_p<0>, context::flow_in))
(context::flow_in, ns_s_flow_seq_entries.with(bp::_p<0>, context::flow_in))
(context::block_out, ns_s_flow_seq_entries.with(bp::_p<0>, context::flow_key))
(context::flow_key, ns_s_flow_seq_entries.with(bp::_p<0>, context::flow_key));
auto const ns_s_flow_seq_entries_def = bp::eps;
auto const s_separate_lines_def = bp::eps;
BOOST_PARSER_DEFINE_RULES(
c_flow_sequence,
s_separate,
in_flow,
ns_s_flow_seq_entries,
s_separate_lines);
//]
}
// clang-format on
TEST(parser, extended_param_example)
{
using namespace param_example;
//[ extended_param_yaml_example_use
auto const test_parser = c_flow_sequence.with(4, context::block_out);
auto result = bp::parse("[]", test_parser);
assert(result);
//]
(void)result;
}

View File

@@ -1,339 +0,0 @@
/**
* Copyright (C) 2024 T. Zachary Laine
*
* Distributed under the Boost Software License, Version 1.0. (See
* accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
#include <boost/parser/parser.hpp>
#include <gtest/gtest.h>
namespace bp = boost::parser;
namespace make {
template<typename... Ts>
auto tuple(Ts &&... xs)
{
return bp::tuple<Ts...>((Ts &&) xs...);
}
}
/*
{P0, -P0, *P0, P1, P2, P3, eps}
<cartesian product>
{P0, P1, P2, P3, eps, *P0, -P0, (P0 >>/| P2), -(P0 >>/| P1), (-P0 >>/| P1)}
P0 = bp::string("foo");
P1 = bp::string("bar");
P2 = bp::int_;
P3 = bp::char_('c');
*/
using namespace std::literals;
TEST(attributes, seq_parser_permutations_1)
{
[[maybe_unused]] int dummy = 0; // for clang-format(!)
// P0
{
auto result =
bp::parse("foofoo", bp::string("foo") >> bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple("foo"s, "foo"s)));
}
{
auto result =
bp::parse("foobar", bp::string("foo") >> bp::string("bar"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple("foo"s, "bar"s)));
}
{
auto result = bp::parse("foo42", bp::string("foo") >> bp::int_);
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple("foo"s, 42)));
}
{
auto result = bp::parse("fooc", bp::string("foo") >> bp::char_('c'));
EXPECT_TRUE(result);
EXPECT_EQ(*result, "fooc"s);
}
{
auto result = bp::parse("foo", bp::string("foo") >> bp::eps);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "foo"s);
}
{
auto result =
bp::parse("foofoofoo", bp::string("foo") >> *bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::vector({"foo"s, "foo"s, "foo"s}));
}
{
auto result = bp::parse("foo", bp::string("foo") >> -bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple("foo"s, std::optional<std::string>{})));
}
{
auto result = bp::parse(
"foofoo42", bp::string("foo") >> (bp::string("foo") >> bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple("foo"s, "foo"s, 42)));
}
{
auto result = bp::parse(
"foofoobar",
bp::string("foo") >> -(bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple("foo"s, std::optional(make::tuple("foo"s, "bar"s)))));
}
{
auto result = bp::parse(
"foofoobar",
bp::string("foo") >> (-bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(
*result, (make::tuple("foo"s, std::optional("foo"s), "bar"s)));
}
{
auto result = bp::parse(
"foo42", bp::string("foo") >> (bp::string("foo") | bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(
*result, (make::tuple("foo"s, std::variant<std::string, int>(42))));
}
{
auto result = bp::parse(
"foo",
bp::string("foo") >> -(bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple("foo"s, std::optional<std::string>{})));
}
{
auto result = bp::parse(
"foo",
bp::string("foo") >> (-bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple(
"foo"s,
std::variant<std::optional<std::string>, std::string>(
std::nullopt))));
}
// -P0
{
auto result =
bp::parse("foofoo", -bp::string("foo") >> bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(std::optional("foo"s), "foo"s)));
}
{
auto result = bp::parse("bar", -bp::string("foo") >> bp::string("bar"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(std::optional<std::string>{}, "bar"s)));
}
{
auto result = bp::parse("42", -bp::string("foo") >> bp::int_);
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(std::optional<std::string>{}, 42)));
}
{
auto result = bp::parse("c", -bp::string("foo") >> bp::char_('c'));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(std::optional<std::string>{}, 'c')));
}
{
auto result = bp::parse("foo", -bp::string("foo") >> bp::eps);
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::optional("foo"s));
}
{
auto result =
bp::parse("foofoo", -bp::string("foo") >> *bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::vector({"foo"s, "foo"s}));
}
{
auto result =
bp::parse("foofoo", -bp::string("foo") >> -bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple(std::optional("foo"s), std::optional("foo"s))));
}
{
auto result = bp::parse(
"foofoo42", -bp::string("foo") >> (bp::string("foo") >> bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(std::optional("foo"s), "foo"s, 42)));
}
{
auto result = bp::parse(
"foofoobar",
-bp::string("foo") >> -(bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple(
std::optional("foo"s),
std::optional((make::tuple("foo"s, "bar"s))))));
}
{
auto result = bp::parse(
"foofoobar",
-bp::string("foo") >> (-bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple(
std::optional("foo"s), std::optional("foo"s), "bar"s)));
}
{
auto result = bp::parse(
"foo42", -bp::string("foo") >> (bp::string("foo") | bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple(
std::optional("foo"s), std::variant<std::string, int>(42))));
}
{
auto result = bp::parse(
"foobar",
-bp::string("foo") >> -(bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple(std::optional("foo"s), std::optional("bar"s))));
}
{
auto result = bp::parse(
"foofoo",
-bp::string("foo") >> (-bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple(
"foo"s,
std::variant<std::optional<std::string>, std::string>(
std::optional("foo"s)))));
}
// *P0
{
auto result = bp::parse(
"foo foo",
bp::lexeme[*bp::string("foo")] >> bp::string("foo"),
bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::vector({"foo"s, "foo"s}));
}
{
auto result =
bp::parse("foobar", *bp::string("foo") >> bp::string("bar"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::vector({"foo"s, "bar"s}));
}
{
auto result = bp::parse("foo42", *bp::string("foo") >> bp::int_);
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(std::vector({"foo"s}), 42)));
}
{
auto result = bp::parse("fooc", *bp::string("foo") >> bp::char_('c'));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(std::vector({"foo"s}), 'c')));
}
{
auto result = bp::parse("foo", *bp::string("foo") >> bp::eps);
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::vector({"foo"s}));
}
{
auto result = bp::parse(
"foo foo",
bp::lexeme[*bp::string("foo")] >> *bp::string("foo"),
bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple(std::vector({"foo"s}), std::vector({"foo"s}))));
}
{
auto result =
bp::parse("foo", *bp::string("foo") >> -bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::vector({"foo"s}));
}
{
auto result = bp::parse(
"foo foo42",
bp::lexeme[*bp::string("foo")] >> (bp::string("foo") >> bp::int_),
bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(std::vector({"foo"s, "foo"s}), 42)));
}
{
auto result = bp::parse(
"foo foobar",
bp::lexeme[*bp::string("foo")] >>
-(bp::string("foo") >> bp::string("bar")),
bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple(
std::vector({"foo"s}),
std::optional((make::tuple("foo"s, "bar"s))))));
}
{
auto result = bp::parse(
"foo foobar",
bp::lexeme[*bp::string("foo")] >>
(-bp::string("foo") >> bp::string("bar")),
bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::vector({"foo"s, "foo"s, "bar"s}));
}
{
auto result = bp::parse(
"foo 42",
bp::lexeme[*bp::string("foo")] >> (bp::string("foo") | bp::int_),
bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple(
std::vector({"foo"s}), std::variant<std::string, int>(42))));
}
{
auto result = bp::parse(
"foo bar",
bp::lexeme[*bp::string("foo")] >>
-(bp::string("foo") | bp::string("bar")),
bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::vector({"foo"s, "bar"s}));
}
{
auto result = bp::parse(
"foo",
bp::lexeme[*bp::string("foo")] >>
(-bp::string("foo") | bp::string("bar")),
bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple(
std::vector({"foo"s}),
std::variant<std::optional<std::string>, std::string>(
std::nullopt))));
}
}

View File

@@ -1,370 +0,0 @@
/**
* Copyright (C) 2024 T. Zachary Laine
*
* Distributed under the Boost Software License, Version 1.0. (See
* accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
#include <boost/parser/parser.hpp>
#include <gtest/gtest.h>
namespace bp = boost::parser;
namespace make {
template<typename... Ts>
auto tuple(Ts &&... xs)
{
return bp::tuple<Ts...>((Ts &&) xs...);
}
}
/*
{P0, -P0, *P0, P1, P2, P3, eps}
<cartesian product>
{P0, P1, P2, P3, eps, *P0, -P0, (P0 >>/| P2), -(P0 >>/| P1), (-P0 >>/| P1)}
P0 = bp::string("foo");
P1 = bp::string("bar");
P2 = bp::int_;
P3 = bp::char_('c');
*/
using namespace std::literals;
TEST(attributes, seq_parser_permutations_2)
{
[[maybe_unused]] int dummy = 0; // for clang-format(!)
// P1
{
auto result =
bp::parse("barfoo", bp::string("bar") >> bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple("bar"s, "foo"s)));
}
{
auto result =
bp::parse("barbar", bp::string("bar") >> bp::string("bar"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple("bar"s, "bar"s)));
}
{
auto result = bp::parse("bar42", bp::string("bar") >> bp::int_);
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple("bar"s, 42)));
}
{
auto result = bp::parse("barc", bp::string("bar") >> bp::char_('c'));
EXPECT_TRUE(result);
EXPECT_EQ(*result, "barc"s);
}
{
auto result = bp::parse("bar", bp::string("bar") >> bp::eps);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "bar"s);
}
{
auto result =
bp::parse("barfoofoo", bp::string("bar") >> *bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::vector({"bar"s, "foo"s, "foo"s}));
}
{
auto result =
bp::parse("barfoo", bp::string("bar") >> -bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple("bar"s, std::optional("foo"s))));
}
{
auto result = bp::parse(
"barfoo42", bp::string("bar") >> (bp::string("foo") >> bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple("bar"s, "foo"s, 42)));
}
{
auto result = bp::parse(
"barfoobar",
bp::string("bar") >> -(bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple("bar"s, std::optional(make::tuple("foo"s, "bar"s)))));
}
{
auto result = bp::parse(
"barfoobar",
bp::string("bar") >> (-bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(
*result, (make::tuple("bar"s, std::optional("foo"s), "bar"s)));
}
{
auto result = bp::parse(
"bar42", bp::string("bar") >> (bp::string("foo") | bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(
*result, (make::tuple("bar"s, std::variant<std::string, int>(42))));
}
{
auto result = bp::parse(
"bar",
bp::string("bar") >> -(bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple("bar"s, std::optional<std::string>{})));
}
{
auto result = bp::parse(
"bar",
bp::string("bar") >> (-bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
make::tuple(
"bar"s,
std::variant<std::optional<std::string>, std::string>(
std::nullopt)));
}
// P2
{
auto result = bp::parse("42foo", bp::int_ >> bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(42, "foo"s)));
}
{
auto result = bp::parse("42bar", bp::int_ >> bp::string("bar"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(42, "bar"s)));
}
{
auto result = bp::parse("42 42", bp::int_ >> bp::int_, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(42, 42)));
}
{
auto result = bp::parse("42c", bp::int_ >> bp::char_('c'));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(42, 'c')));
}
{
auto result = bp::parse("42", bp::int_ >> bp::eps);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 42);
}
{
auto result = bp::parse("42foofoo", bp::int_ >> *bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(42, std::vector({"foo"s, "foo"s}))));
}
{
auto result = bp::parse("42foo", bp::int_ >> -bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(42, std::optional("foo"s))));
}
{
auto result =
bp::parse("42foo42", bp::int_ >> (bp::string("foo") >> bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(42, "foo"s, 42)));
}
{
auto result = bp::parse(
"42foobar", bp::int_ >> -(bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple(42, std::optional(make::tuple("foo"s, "bar"s)))));
}
{
auto result = bp::parse(
"42foobar", bp::int_ >> (-bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(42, std::optional("foo"s), "bar"s)));
}
{
auto result = bp::parse(
"42 42", bp::int_ >> (bp::string("foo") | bp::int_), bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(
*result, (make::tuple(42, std::variant<std::string, int>(42))));
}
{
auto result = bp::parse(
"42", bp::int_ >> -(bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(42, std::optional<std::string>{})));
}
{
auto result = bp::parse(
"42", bp::int_ >> (-bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
make::tuple(
42,
std::variant<std::optional<std::string>, std::string>(
std::nullopt)));
}
// P3
{
auto result = bp::parse("cfoo", bp::char_('c') >> bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, "cfoo"s);
}
{
auto result = bp::parse("cbar", bp::char_('c') >> bp::string("bar"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, "cbar"s);
}
{
auto result = bp::parse("c42", bp::char_('c') >> bp::int_);
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple('c', 42)));
}
{
auto result = bp::parse("cc", bp::char_('c') >> bp::char_('c'));
EXPECT_TRUE(result);
EXPECT_EQ(*result, "cc"s);
}
{
auto result = bp::parse("c", bp::char_('c') >> bp::eps);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 'c');
}
{
auto result =
bp::parse("cfoofoo", bp::char_('c') >> *bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple('c', std::vector({"foo"s, "foo"s}))));
}
{
auto result = bp::parse("cfoo", bp::char_('c') >> -bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple('c', std::optional("foo"s))));
}
{
auto result = bp::parse(
"cfoo42", bp::char_('c') >> (bp::string("foo") >> bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple("cfoo"s, 42)));
}
{
auto result = bp::parse(
"cfoobar",
bp::char_('c') >> -(bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple('c', std::optional(make::tuple("foo"s, "bar"s)))));
}
{
auto result = bp::parse(
"cfoobar",
bp::char_('c') >> (-bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple('c', std::optional("foo"s), "bar"s)));
}
{
auto result =
bp::parse("c42", bp::char_('c') >> (bp::string("foo") | bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(
*result, (make::tuple('c', std::variant<std::string, int>(42))));
}
{
auto result = bp::parse(
"c", bp::char_('c') >> -(bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple('c', std::optional<std::string>{})));
}
{
auto result = bp::parse(
"c", bp::char_('c') >> (-bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple(
'c',
std::variant<std::optional<std::string>, std::string>(
std::nullopt))));
}
// eps
{
auto result = bp::parse("foo", bp::eps >> bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, "foo"s);
}
{
auto result = bp::parse("bar", bp::eps >> bp::string("bar"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, "bar"s);
}
{
auto result = bp::parse("42", bp::eps >> bp::int_);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 42);
}
{
auto result = bp::parse("c", bp::eps >> bp::char_('c'));
EXPECT_TRUE(result);
EXPECT_EQ(*result, 'c');
}
{
auto result = bp::parse("", bp::eps >> bp::eps);
EXPECT_TRUE(result);
}
{
auto result = bp::parse("foofoo", bp::eps >> *bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::vector({"foo"s, "foo"s}));
}
{
auto result = bp::parse("foo", bp::eps >> -bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::optional("foo"s));
}
{
auto result =
bp::parse("foo42", bp::eps >> (bp::string("foo") >> bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple("foo"s, 42)));
}
{
auto result = bp::parse(
"foobar", bp::eps >> -(bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::optional((make::tuple("foo"s, "bar"s))));
}
{
auto result = bp::parse(
"foobar", bp::eps >> (-bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(std::optional("foo"s), "bar"s)));
}
{
auto result =
bp::parse("42", bp::eps >> (bp::string("foo") | bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (std::variant<std::string, int>(42)));
}
{
auto result =
bp::parse("", bp::eps >> -(bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::optional<std::string>{});
}
{
auto result =
bp::parse("", bp::eps >> (-bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(std::variant<std::optional<std::string>, std::string>(
std::nullopt)));
}
}

View File

@@ -258,8 +258,7 @@ TEST(replace, replace_unicode)
int count = 0;
std::string_view const strs[] = {"aa", "foo", "b"};
for (auto subrange : r) {
auto u8sub = subrange | bp::as_utf8;
std::string str(u8sub.begin(), u8sub.end());
std::string str(subrange.begin(), subrange.end());
EXPECT_EQ(str, strs[count]);
++count;
}
@@ -275,8 +274,7 @@ TEST(replace, replace_unicode)
int count = 0;
std::string_view const strs[] = {"aa", "foo", "baaba", "foo"};
for (auto subrange : r) {
auto u8sub = subrange | bp::as_utf8;
std::string str(u8sub.begin(), u8sub.end());
std::string str(subrange.begin(), subrange.end());
EXPECT_EQ(str, strs[count]);
++count;
}
@@ -303,8 +301,7 @@ TEST(replace, replace_unicode)
int count = 0;
std::string_view const strs[] = {"aa", "foo", "baaba", "foo"};
for (auto subrange : r) {
auto u8sub = subrange | bp::as_utf8;
std::string str(u8sub.begin(), u8sub.end());
std::string str(subrange.begin(), subrange.end());
EXPECT_EQ(str, strs[count]);
++count;
}
@@ -317,8 +314,7 @@ TEST(replace, replace_unicode)
int count = 0;
std::string_view const strs[] = {"aa", "foo", "baaba", "foo", "foo"};
for (auto subrange : r) {
auto u8sub = subrange | bp::as_utf8;
std::string str(u8sub.begin(), u8sub.end());
std::string str(subrange.begin(), subrange.end());
EXPECT_EQ(str, strs[count]);
++count;
}
@@ -346,8 +342,7 @@ TEST(replace, replace_unicode)
std::string_view const strs[] = {
"foo", "foo", "aa", "foo", "baaba", "foo", "foo"};
for (auto subrange : r) {
auto u8sub = subrange | bp::as_utf8;
std::string str(u8sub.begin(), u8sub.end());
std::string str(subrange.begin(), subrange.end());
EXPECT_EQ(str, strs[count]);
++count;
}
@@ -361,8 +356,7 @@ TEST(replace, replace_unicode)
std::string_view const strs[] = {
"foo", "foo", "aa", "foo", "baaba", "foo", "foo"};
for (auto subrange : r) {
auto u8sub = subrange | bp::as_utf8;
std::string str(u8sub.begin(), u8sub.end());
std::string str(subrange.begin(), subrange.end());
EXPECT_EQ(str, strs[count]);
++count;
}
@@ -376,8 +370,7 @@ TEST(replace, replace_unicode)
std::string_view const strs[] = {
"foo", "foo", "aa", "foo", "baaba", "foo", "foo"};
for (auto subrange : r) {
auto u8sub = subrange | bp::as_utf8;
std::string str(u8sub.begin(), u8sub.end());
std::string str(subrange.begin(), subrange.end());
EXPECT_EQ(str, strs[count]);
++count;
}
@@ -398,7 +391,7 @@ TEST(replace, join_compat)
std::string replace_result;
for (auto ch : rng) {
static_assert(std::is_same_v<decltype(ch), char32_t>);
replace_result.push_back((char)ch);
replace_result.push_back(ch);
}
EXPECT_EQ(replace_result, "foofooaafoobaabafoofoo");
}
@@ -444,35 +437,17 @@ TEST(replace, join_compat)
TEST(replace, doc_examples)
{
// clang-format off
{
namespace bp = boost::parser;
auto card_number = bp::int_ >> bp::repeat(3)['-' >> bp::int_];
auto rng = "My credit card number is 1234-5678-9012-3456." | bp::replace(card_number, "XXXX-XXXX-XXXX-XXXX");
auto rng = "XYZaaXYZbaabaXYZXYZ" | bp::replace(bp::lit("XYZ"), "foo");
int count = 0;
// Prints My credit card number is XXXX-XXXX-XXXX-XXXX.
// Prints foo aa foo baaba foo foo.
for (auto subrange : rng) {
std::cout << std::string_view(subrange.begin(), subrange.end() - subrange.begin());
std::cout << std::string_view(subrange.begin(), subrange.end() - subrange.begin()) << " ";
++count;
}
std::cout << "\n";
assert(count == 3);
assert(count == 6);
}
#if BOOST_PARSER_USE_CONCEPTS && (!defined(__GNUC__) || 12 <= __GNUC__)
{
namespace bp = boost::parser;
auto card_number = bp::int_ >> bp::repeat(3)['-' >> bp::int_];
auto rng = "My credit card number is 1234-5678-9012-3456." |
bp::replace(card_number, "XXXX-XXXX-XXXX-XXXX") |
std::views::join;
std::string replace_result;
for (auto ch : rng) {
replace_result.push_back(ch);
}
assert(replace_result == "My credit card number is XXXX-XXXX-XXXX-XXXX.");
}
#endif
// clang-format on
}
#endif

View File

@@ -739,7 +739,6 @@ TEST(search, doc_examples)
assert(
std::string_view(result.begin(), result.end() - result.begin()) ==
"XYZ");
(void)result;
}
{
auto r = "XYZaaXYZbaabaXYZXYZ" | bp::search_all(bp::lit("XYZ"));

View File

@@ -103,13 +103,6 @@ int main()
PARSE(char_ | int_ | float_);
std::cout << "\n\n"
<< "----------------------------------------\n"
<< "| operator|| |\n"
<< "----------------------------------------\n";
PARSE(char_ || int_ || float_);
std::cout << "\n\n"
<< "----------------------------------------\n"
<< "| operator- (binary) |\n"
@@ -138,14 +131,6 @@ int main()
PARSE(char_[a]);
std::cout << "\n\n"
<< "----------------------------------------\n"
<< "| transform)f_[] |\n"
<< "----------------------------------------\n";
auto f = [](auto x) { return x; };
PARSE(transform(f)[char_]);
std::cout << "\n\n"
<< "----------------------------------------\n"
<< "| omit[] |\n"
@@ -312,15 +297,6 @@ int main()
PARSE(string("h"));
std::cout << "\n\n"
<< "----------------------------------------\n"
<< "| quoted_string() |\n"
<< "----------------------------------------\n";
PARSE(quoted_string);
PARSE(quoted_string('\''));
PARSE(quoted_string("'\""));
std::cout << "\n\n"
<< "----------------------------------------\n"
<< "| eol |\n"

View File

@@ -14,8 +14,7 @@
#include <list>
#if (!defined(_MSC_VER) || BOOST_PARSER_USE_CONCEPTS) && \
(!defined(__GNUC__) || 12 <= __GNUC__ || !BOOST_PARSER_USE_CONCEPTS)
#if (!defined(_MSC_VER) || BOOST_PARSER_USE_CONCEPTS)
namespace bp = boost::parser;
@@ -681,8 +680,7 @@ TEST(transform_replace, transform_replace_unicode)
int count = 0;
std::string replace_result;
for (auto subrange : r) {
auto u8sub = subrange | bp::as_utf8;
std::string str(u8sub.begin(), u8sub.end());
std::string str(subrange.begin(), subrange.end());
replace_result += str;
++count;
}
@@ -697,8 +695,7 @@ TEST(transform_replace, transform_replace_unicode)
int count = 0;
std::string replace_result;
for (auto subrange : r) {
auto u8sub = subrange | bp::as_utf8;
std::string str(u8sub.begin(), u8sub.end());
std::string str(subrange.begin(), subrange.end());
replace_result += str;
++count;
}
@@ -727,8 +724,7 @@ TEST(transform_replace, transform_replace_unicode)
int count = 0;
std::string replace_result;
for (auto subrange : r) {
auto u8sub = subrange | bp::as_utf8;
std::string str(u8sub.begin(), u8sub.end());
std::string str(subrange.begin(), subrange.end());
replace_result += str;
++count;
}
@@ -742,8 +738,7 @@ TEST(transform_replace, transform_replace_unicode)
int count = 0;
std::string replace_result;
for (auto subrange : r) {
auto u8sub = subrange | bp::as_utf8;
std::string str(u8sub.begin(), u8sub.end());
std::string str(subrange.begin(), subrange.end());
replace_result += str;
++count;
}
@@ -779,7 +774,7 @@ TEST(transform_replace, join_compat)
std::string transform_replace_result;
for (auto ch : rng) {
static_assert(std::is_same_v<decltype(ch), char16_t>);
transform_replace_result.push_back((char)ch);
transform_replace_result.push_back(ch);
}
EXPECT_EQ(transform_replace_result, "1_aa88_99_baaba111_2222_ 3_4_");
}
@@ -791,7 +786,7 @@ TEST(transform_replace, join_compat)
std::string transform_replace_result;
for (auto ch : rng) {
static_assert(std::is_same_v<decltype(ch), char32_t>);
transform_replace_result.push_back((char)ch);
transform_replace_result.push_back(ch);
}
EXPECT_EQ(transform_replace_result, "1_aa88_99_baaba111_2222_ 3_4_");
}