mirror of
https://github.com/boostorg/parser.git
synced 2026-01-20 04:42:22 +00:00
Compare commits
1 Commits
packrat
...
xform_repl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4287c9b7b3 |
4
.github/workflows/macos-12.yml
vendored
4
.github/workflows/macos-12.yml
vendored
@@ -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.)
|
||||
|
||||
4
.github/workflows/ubuntu-20.04.yml
vendored
4
.github/workflows/ubuntu-20.04.yml
vendored
@@ -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.)
|
||||
|
||||
4
.github/workflows/ubuntu-22.04.yml
vendored
4
.github/workflows/ubuntu-22.04.yml
vendored
@@ -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.)
|
||||
|
||||
4
.github/workflows/windows-2019.yml
vendored
4
.github/workflows/windows-2019.yml
vendored
@@ -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.)
|
||||
|
||||
4
.github/workflows/windows-2022.yml
vendored
4
.github/workflows/windows-2022.yml
vendored
@@ -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.)
|
||||
|
||||
@@ -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 ()
|
||||
|
||||
##################################################
|
||||
|
||||
@@ -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
|
||||
:
|
||||
|
||||
103
doc/intro.qbk
103
doc/intro.qbk
@@ -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]
|
||||
|
||||
@@ -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]
|
||||
|
||||
599
doc/tables.qbk
599
doc/tables.qbk
@@ -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)>>`]]
|
||||
]
|
||||
]
|
||||
1332
doc/tutorial.qbk
1332
doc/tutorial.qbk
File diff suppressed because it is too large
Load Diff
@@ -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));
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 << ")";
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
@@ -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
@@ -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
@@ -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. */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>);
|
||||
|
||||
@@ -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
@@ -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>
|
||||
|
||||
452
test/memos.cpp
452
test/memos.cpp
@@ -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);
|
||||
}
|
||||
}
|
||||
100
test/no_case.cpp
100
test/no_case.cpp
@@ -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");
|
||||
|
||||
@@ -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
|
||||
274
test/parser.cpp
274
test/parser.cpp
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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')));
|
||||
}
|
||||
}
|
||||
@@ -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}));
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
}
|
||||
@@ -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')));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
//]
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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))));
|
||||
}
|
||||
}
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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_");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user