mirror of
https://github.com/boostorg/parser.git
synced 2026-01-20 04:42:22 +00:00
Compare commits
2 Commits
parser_con
...
packrat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06fb60c78f | ||
|
|
24288a03a2 |
@@ -41,6 +41,7 @@
|
||||
[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]
|
||||
@@ -218,6 +219,8 @@
|
||||
[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]]`()`]
|
||||
|
||||
@@ -38,6 +38,8 @@ itself be used as a parser; it must be called. In the table below:
|
||||
|
||||
* `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]
|
||||
@@ -326,6 +328,31 @@ the input they match unless otherwise stated in the table below.]
|
||||
[ _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
|
||||
|
||||
137
doc/tutorial.qbk
137
doc/tutorial.qbk
@@ -738,6 +738,106 @@ no sense.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Alternative Parsers]
|
||||
|
||||
Frequently, you need to parse something that might have one of several forms.
|
||||
`operator|` is overloaded to form alternative parsers. For example:
|
||||
|
||||
namespace bp = boost::parser;
|
||||
auto const parser_1 = bp::int_ | bp::eps;
|
||||
|
||||
`parser_1` matches an integer, or if that fails, it matches /epsilon/, the
|
||||
empty string. This is equivalent to writing:
|
||||
|
||||
namespace bp = boost::parser;
|
||||
auto const parser_2 = -bp::int_;
|
||||
|
||||
However, neither `parser_1` nor `parser_2` is equivalent to writing this:
|
||||
|
||||
namespace bp = boost::parser;
|
||||
auto const parser_3 = bp::eps | bp::int_; // Does not do what you think.
|
||||
|
||||
The reason is that alternative parsers try each of their subparsers, one at a
|
||||
time, and stop on the first one that matches. /Epsilon/ matches anything,
|
||||
since it is zero length and consumes no input. It even matches the end of
|
||||
input. This means that `parser_3` is equivalent to _e_ by itself.
|
||||
|
||||
[note For this reason, writing `_e_ | p` for any parser p is considered a bug.
|
||||
Debug builds will assert when `_e_ | p` is encountered. ]
|
||||
|
||||
[warning This kind of error is very common when _e_ is involved, and also very
|
||||
easy to detect. However, it is possible to write `P1 >> P2`, where `P1` is a
|
||||
prefix of `P2`, such as `int_ | int >> int_`, or `repeat(4)[hex_digit] |
|
||||
repeat(8)[hex_digit]`. This is almost certainly an error, but is impossible
|
||||
to detect in the general case _emdash_ remember that _rs_ can be separately
|
||||
compiled, and consider a pair of rules whose associated `_def` parsers are
|
||||
`int_` and `int_ >> int_`, respectively.]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Parsing Quoted Strings]
|
||||
|
||||
It is very common to need to parse quoted strings. Quoted strings are
|
||||
slightly tricky, though, when using a skipper (and you should be using a
|
||||
skipper 99% of the time). You don't want to allow arbitrary whitespace in the
|
||||
middle of your strings, and you also don't want to remove all whitespace from
|
||||
your strings. Both of these things will happen with the typical skipper,
|
||||
_ws_.
|
||||
|
||||
So, here is how most people would write a quoted string parser:
|
||||
|
||||
namespace bp = boost::parser;
|
||||
const auto string = bp::lexeme['"' >> *(bp::char_ - '"') > '"'];
|
||||
|
||||
Some things to note:
|
||||
|
||||
* the result is a string;
|
||||
|
||||
* the quotes are not included in the result;
|
||||
|
||||
* there is an expectation point before the close-quote;
|
||||
|
||||
* the use of _lexeme_ disables skipping in the parser, and it must be written
|
||||
around the quotes, not around the `operator*` expression; and
|
||||
|
||||
* there's no way to write a quote in the middle of the string.
|
||||
|
||||
This is a very common pattern. I have written a quoted string parser like
|
||||
this dozens of times. The parser above is the quick-and-dirty version. A
|
||||
more robust version would be able to handle escaped quotes within the string,
|
||||
and then would immediately also need to support escaped escape characters.
|
||||
|
||||
_Parser_ provides _quot_str_ to use in place of this very common pattern. It
|
||||
supports quote- and escaped-character-escaping, using backslash as the escape
|
||||
character.
|
||||
|
||||
[quoted_string_example_1_2]
|
||||
|
||||
As common as this use case is, there are very similar use cases that it does
|
||||
not cover. So, _quot_str_ has some options. If you call it with a single
|
||||
character, it returns a _quot_str_ that uses that single character as the
|
||||
quote-character.
|
||||
|
||||
[quoted_string_example_3]
|
||||
|
||||
You can also supply a range of characters. One of the characters from the
|
||||
range must quote the whole string; mismatches are not allowed. Think of how
|
||||
Python allows you to quote a string with either `'"'` or `'\''`, but the same
|
||||
character must be used on both sides.
|
||||
|
||||
[quoted_string_example_4]
|
||||
|
||||
Another common thing to do in a quoted string parser is to recognize escape
|
||||
sequences. If you have simple escape sequencecs that do not require any real
|
||||
parsing, like say the simple escape sequences from C++, you can provide a
|
||||
_symbols_ object as well. The template parameter `T` to _symbols_t_ must be
|
||||
`char` or `char32_t`. You don't need to include the escaped backslash or the
|
||||
escaped quote character, since those always work.
|
||||
|
||||
[quoted_string_example_5]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Parsing In Detail]
|
||||
|
||||
Now that you've seen some examples, let's see how parsing works in a bit more
|
||||
@@ -1052,43 +1152,6 @@ for more information.]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Alternative Parsers]
|
||||
|
||||
Frequently, you need to parse something that might have one of several forms.
|
||||
`operator|` is overloaded to form alternative parsers. For example:
|
||||
|
||||
namespace bp = boost::parser;
|
||||
auto const parser_1 = bp::int_ | bp::eps;
|
||||
|
||||
`parser_1` matches an integer, or if that fails, it matches /epsilon/, the
|
||||
empty string. This is equivalent to writing:
|
||||
|
||||
namespace bp = boost::parser;
|
||||
auto const parser_2 = -bp::int_;
|
||||
|
||||
However, neither `parser_1` nor `parser_2` is equivalent to writing this:
|
||||
|
||||
namespace bp = boost::parser;
|
||||
auto const parser_3 = bp::eps | bp::int_; // Does not do what you think.
|
||||
|
||||
The reason is that alternative parsers try each of their subparsers, one at a
|
||||
time, and stop on the first one that matches. /Epsilon/ matches anything,
|
||||
since it is zero length and consumes no input. It even matches the end of
|
||||
input. This means that `parser_3` is equivalent to _e_ by itself.
|
||||
|
||||
[note For this reason, writing `_e_ | p` for any parser p is considered a bug.
|
||||
Debug builds will assert when `_e_ | p` is encountered. ]
|
||||
|
||||
[warning This kind of error is very common when _e_ is involved, and also very
|
||||
easy to detect. However, it is possible to write `P1 >> P2`, where `P1` is a
|
||||
prefix of `P2`, such as `int_ | int >> int_`, or `repeat(4)[hex_digit] |
|
||||
repeat(8)[hex_digit]`. This is almost certainly an error, but is impossible
|
||||
to detect in the general case _emdash_ remember that _rs_ can be separately
|
||||
compiled, and consider a pair of rules whose associated `_def` parsers are
|
||||
`int_` and `int_ >> int_`, respectively.]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section The Parsers And Their Uses]
|
||||
|
||||
_Parser_ comes with all the parsers most parsing tasks will ever need. Each
|
||||
|
||||
@@ -51,14 +51,16 @@ namespace boost { namespace parser {
|
||||
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 &>()));
|
||||
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 &>()));
|
||||
|
||||
template<typename T, typename I, typename S, typename GlobalState>
|
||||
concept error_handler =
|
||||
|
||||
44
include/boost/parser/detail/counted_iterator.hpp
Normal file
44
include/boost/parser/detail/counted_iterator.hpp
Normal file
@@ -0,0 +1,44 @@
|
||||
#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
|
||||
458
include/boost/parser/detail/memos.hpp
Normal file
458
include/boost/parser/detail/memos.hpp
Normal file
@@ -0,0 +1,458 @@
|
||||
#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
|
||||
@@ -148,10 +148,10 @@ namespace boost { namespace parser { namespace detail {
|
||||
std::ostream & os,
|
||||
int components = 0);
|
||||
|
||||
template<typename Context, typename Parser, typename ParserConfig>
|
||||
template<typename Context, typename Parser, bool FailOnMatch>
|
||||
void print_parser(
|
||||
Context const & context,
|
||||
expect_parser_t<Parser, ParserConfig> const & parser,
|
||||
expect_parser<Parser, FailOnMatch> const & parser,
|
||||
std::ostream & os,
|
||||
int components = 0);
|
||||
|
||||
@@ -278,6 +278,13 @@ 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,
|
||||
|
||||
@@ -378,14 +378,14 @@ namespace boost { namespace parser { namespace detail {
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Context, typename Parser, typename ParserConfig>
|
||||
template<typename Context, typename Parser, bool FailOnMatch>
|
||||
void print_parser(
|
||||
Context const & context,
|
||||
expect_parser_t<Parser, ParserConfig> const & parser,
|
||||
expect_parser<Parser, FailOnMatch> const & parser,
|
||||
std::ostream & os,
|
||||
int components)
|
||||
{
|
||||
if (ParserConfig::fail_on_match)
|
||||
if (FailOnMatch)
|
||||
os << "!";
|
||||
else
|
||||
os << "&";
|
||||
@@ -482,8 +482,7 @@ namespace boost { namespace parser { namespace detail {
|
||||
template<
|
||||
typename Context,
|
||||
typename ResolvedExpected,
|
||||
bool Integral = std::is_integral<ResolvedExpected>{},
|
||||
int SizeofExpected = sizeof(ResolvedExpected)>
|
||||
bool Integral = std::is_integral<ResolvedExpected>{}>
|
||||
struct print_expected_char_impl
|
||||
{
|
||||
static void call(
|
||||
@@ -495,13 +494,17 @@ namespace boost { namespace parser { namespace detail {
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Context, typename Expected>
|
||||
struct print_expected_char_impl<Context, Expected, true, 4>
|
||||
template<typename Context>
|
||||
struct print_expected_char_impl<Context, char32_t, true>
|
||||
{
|
||||
static void
|
||||
call(Context const & context, std::ostream & os, Expected expected)
|
||||
call(Context const & context, std::ostream & os, char32_t expected)
|
||||
{
|
||||
std::array<char32_t, 1> cps = {{(char32_t)expected}};
|
||||
if (expected == '\'') {
|
||||
os << "'\\''";
|
||||
return;
|
||||
}
|
||||
std::array<char32_t, 1> cps = {{expected}};
|
||||
auto const r = cps | text::as_utf8;
|
||||
os << "'";
|
||||
for (auto c : r) {
|
||||
@@ -689,6 +692,27 @@ 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,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <boost/parser/config.hpp>
|
||||
#include <boost/parser/error_handling_fwd.hpp>
|
||||
#include <boost/parser/detail/memos.hpp>
|
||||
|
||||
#include <any>
|
||||
#include <cstdint>
|
||||
@@ -70,7 +71,6 @@ namespace boost { namespace parser {
|
||||
trace = 1 << 2,
|
||||
in_apply_parser = 1 << 3
|
||||
};
|
||||
constexpr inline flags disable_attrs(flags f);
|
||||
|
||||
using symbol_table_tries_t =
|
||||
std::map<void *, std::pair<std::any, bool>, std::less<void *>>;
|
||||
@@ -80,7 +80,8 @@ namespace boost { namespace parser {
|
||||
bool UseCallbacks,
|
||||
typename Iter,
|
||||
typename Sentinel,
|
||||
typename ErrorHandler>
|
||||
typename ErrorHandler,
|
||||
typename Memos>
|
||||
inline auto make_context(
|
||||
Iter first,
|
||||
Sentinel last,
|
||||
@@ -88,7 +89,8 @@ namespace boost { namespace parser {
|
||||
int & indent,
|
||||
ErrorHandler const & error_handler,
|
||||
nope &,
|
||||
symbol_table_tries_t & symbol_table_tries) noexcept;
|
||||
symbol_table_tries_t & symbol_table_tries,
|
||||
Memos & memos) noexcept;
|
||||
|
||||
struct skip_skipper;
|
||||
|
||||
@@ -117,25 +119,6 @@ namespace boost { namespace parser {
|
||||
{};
|
||||
struct upper_case_chars
|
||||
{};
|
||||
|
||||
template<
|
||||
bool OmitAttr = false,
|
||||
bool DontConsumeInput = false,
|
||||
bool FailOnMatch = false,
|
||||
typename Action = nope>
|
||||
struct parser_config
|
||||
{
|
||||
static constexpr bool omit = OmitAttr;
|
||||
static constexpr bool dont_consume_input = DontConsumeInput;
|
||||
static constexpr bool fail_on_match = FailOnMatch;
|
||||
|
||||
static constexpr detail::flags flags(detail::flags f)
|
||||
{
|
||||
return omit ? detail::disable_attrs(f) : f;
|
||||
}
|
||||
|
||||
[[maybe_unused]] Action action_;
|
||||
};
|
||||
}
|
||||
|
||||
/** Repeats the application of another parser `p` of type `Parser`,
|
||||
@@ -148,15 +131,36 @@ namespace boost { namespace parser {
|
||||
typename Parser,
|
||||
typename DelimiterParser = detail::nope,
|
||||
typename MinType = int64_t,
|
||||
typename MaxType = int64_t,
|
||||
typename ParserConfig = parser_config<>>
|
||||
typename MaxType = int64_t>
|
||||
struct repeat_parser;
|
||||
|
||||
/** Repeats the application of another parser `p` of type `Parser`, `[0,
|
||||
Inf)` times. The parse always succeeds. The attribute produced is a
|
||||
sequence of the type of attribute produced by `Parser`. */
|
||||
template<typename Parser>
|
||||
struct zero_plus_parser;
|
||||
|
||||
/** Repeats the application of another parser `p` of type `Parser`, `[1,
|
||||
Inf)` times. The parse succeeds iff `p` succeeds at least once. The
|
||||
attribute produced is a sequence of the type of attribute produced by
|
||||
`Parser`. */
|
||||
template<typename Parser>
|
||||
struct one_plus_parser;
|
||||
|
||||
/** Repeats the application of another parser `p` of type `Parser`, `[1,
|
||||
Inf)` times, applying a parser `d` of type `DelimiterParser` in
|
||||
between each pair of applications of `p`. The parse succeeds iff `p`
|
||||
succeeds at least once, and `d` succeeds each time it is applied. The
|
||||
attribute produced is a sequence of the type of attribute produced by
|
||||
`Parser`. */
|
||||
template<typename Parser, typename DelimiterParser>
|
||||
struct delimited_seq_parser;
|
||||
|
||||
/** Repeats the application of another parser of type `Parser`, `[0, 1]`
|
||||
times. The parse always succeeds. The attribute produced is a
|
||||
`std::optional<T>`, where `T` is the type of attribute produced by
|
||||
`Parser`. */
|
||||
template<typename Parser, typename ParserConfig = parser_config<>>
|
||||
template<typename Parser>
|
||||
struct opt_parser;
|
||||
|
||||
/** Applies each parser in `ParserTuple`, in order, stopping after the
|
||||
@@ -164,7 +168,7 @@ namespace boost { namespace parser {
|
||||
one of the sub-parsers succeeds. The attribute produced is a
|
||||
`std::variant` over the types of attribute produced by the parsers in
|
||||
`ParserTuple`. */
|
||||
template<typename ParserTuple, typename ParserConfig = parser_config<>>
|
||||
template<typename ParserTuple>
|
||||
struct or_parser;
|
||||
|
||||
/** Applies each parsers in `ParserTuple`, an any order, stopping after
|
||||
@@ -175,7 +179,7 @@ namespace boost { namespace parser {
|
||||
`ParserTuple`, not the order of the parsers' matches. It is an error
|
||||
to specialize `perm_parser` with a `ParserTuple` template parameter
|
||||
that includes an `eps_parser`. */
|
||||
template<typename ParserTuple, typename ParserConfig = parser_config<>>
|
||||
template<typename ParserTuple>
|
||||
struct perm_parser;
|
||||
|
||||
/** Applies each parser in `ParserTuple`, in order. The parse succeeds
|
||||
@@ -188,18 +192,14 @@ namespace boost { namespace parser {
|
||||
template<
|
||||
typename ParserTuple,
|
||||
typename BacktrackingTuple,
|
||||
typename CombiningGroups,
|
||||
typename ParserConfig = parser_config<>>
|
||||
typename CombiningGroups>
|
||||
struct seq_parser;
|
||||
|
||||
/** Applies the given parser `p` of type `Parser` and an invocable `a` of
|
||||
type `Action`. `Action` shall model `semantic_action`, and `a` will
|
||||
only be invoked if `p` succeeds. The parse succeeds iff `p` succeeds.
|
||||
Produces no attribute. */
|
||||
template<
|
||||
typename Parser,
|
||||
typename Action,
|
||||
typename ParserConfig = parser_config<>>
|
||||
template<typename Parser, typename Action>
|
||||
struct action_parser;
|
||||
|
||||
/** Applies the given parser `p` of type `Parser`. The attribute produced
|
||||
@@ -207,24 +207,21 @@ namespace boost { namespace parser {
|
||||
only be invoked if `p` succeeds and sttributes are currently being
|
||||
generated. The parse succeeds iff `p` succeeds. The attribute
|
||||
produced is the the result of the call to `f`. */
|
||||
template<
|
||||
typename Parser,
|
||||
typename F,
|
||||
typename ParserConfig = parser_config<>>
|
||||
template<typename Parser, typename F>
|
||||
struct transform_parser;
|
||||
|
||||
/** Applies the given parser `p` of type `Parser`. This parser produces
|
||||
no attribute, and suppresses the production of any attributes that
|
||||
would otherwise be produced by `p`. The parse succeeds iff `p`
|
||||
succeeds. */
|
||||
template<typename Parser, typename ParserConfig = parser_config<>>
|
||||
template<typename Parser>
|
||||
struct omit_parser;
|
||||
|
||||
/** Applies the given parser `p` of type `Parser`; regardless of the
|
||||
attribute produced by `Parser`, this parser's attribute is equivalent
|
||||
to `_where(ctx)` within a semantic action on `p`. The parse succeeds
|
||||
iff `p` succeeds. */
|
||||
template<typename Parser, typename ParserConfig = parser_config<>>
|
||||
template<typename Parser>
|
||||
struct raw_parser;
|
||||
|
||||
#if defined(BOOST_PARSER_DOXYGEN) || defined(__cpp_lib_concepts)
|
||||
@@ -237,49 +234,43 @@ namespace boost { namespace parser {
|
||||
non-contiguous, code using `string_view_parser` is ill-formed. The
|
||||
parse succeeds iff `p` succeeds. This parser is only available in
|
||||
C++20 and later. */
|
||||
template<typename Parser, typename ParserConfig = parser_config<>>
|
||||
template<typename Parser>
|
||||
struct string_view_parser;
|
||||
#endif
|
||||
|
||||
/** Applies the given parser `p` of type `Parser`, disabling the current
|
||||
skipper in use, if any. The parse succeeds iff `p` succeeds. The
|
||||
attribute produced is the type of attribute produced by `Parser`. */
|
||||
template<typename Parser, typename ParserConfig = parser_config<>>
|
||||
template<typename Parser>
|
||||
struct lexeme_parser;
|
||||
|
||||
/** Applies the given parser `p` of type `Parser`, enabling
|
||||
case-insensitive matching, based on Unicode case folding. The parse
|
||||
succeeds iff `p` succeeds. The attribute produced is the type of
|
||||
attribute produced by `Parser`. */
|
||||
template<typename Parser, typename ParserConfig = parser_config<>>
|
||||
template<typename Parser>
|
||||
struct no_case_parser;
|
||||
|
||||
/** Applies the given parser `p` of type `Parser`, using a parser of type
|
||||
`SkipParser` as the skipper. The parse succeeds iff `p` succeeds.
|
||||
The attribute produced is the type of attribute produced by
|
||||
`Parser`. */
|
||||
template<
|
||||
typename Parser,
|
||||
typename SkipParser = detail::nope,
|
||||
typename ParserConfig = parser_config<>>
|
||||
template<typename Parser, typename SkipParser = detail::nope>
|
||||
struct skip_parser;
|
||||
|
||||
/** Applies the given parser `p` of type `Parser`, producing no attributes
|
||||
and consuming no input. The parse succeeds iff `p`'s success is
|
||||
unequal to `FailOnMatch`. */
|
||||
template<
|
||||
typename Parser,
|
||||
typename ParserConfig,
|
||||
typename ParserConfig = parser_config<>>
|
||||
template<typename Parser, bool FailOnMatch>
|
||||
struct expect_parser;
|
||||
|
||||
/** Matches one of a set S of possible inputs, each of which is
|
||||
associated with an attribute value of type `T`, forming a symbol
|
||||
table. New elements and their associated attributes may be added to
|
||||
or removed from S dynamically, during parsing; any such changes are
|
||||
reverted at the end of parsing. The parse succeeds iff an element of
|
||||
S is matched. \see `symbols` */
|
||||
template<typename T, typename ParserConfig = parser_config<>>
|
||||
/** Matches one of a set S of possible inputs, each of which is associated
|
||||
with an attribute value of type `T`, forming a symbol table. New
|
||||
elements and their associated attributes may be added to or removed
|
||||
from S dynamically, during parsing; any such changes are reverted at
|
||||
the end of parsing. The parse succeeds iff an element of S is
|
||||
matched. \see `symbols` */
|
||||
template<typename T>
|
||||
struct symbol_parser;
|
||||
|
||||
/** Applies another parser `p`, associated with this parser via `TagType`.
|
||||
@@ -298,24 +289,22 @@ namespace boost { namespace parser {
|
||||
typename TagType,
|
||||
typename Attribute,
|
||||
typename LocalState,
|
||||
typename ParamsTuple,
|
||||
typename ParserConfig = parser_config<>>
|
||||
typename ParamsTuple>
|
||||
struct rule_parser;
|
||||
|
||||
/** Matches anything, and consumes no input. If `Predicate` is anything
|
||||
other than `detail::nope` (which it is by default), and `pred_(ctx)`
|
||||
evaluates to false, where `ctx` is the parser context, the parse
|
||||
fails. */
|
||||
template<typename Predicate, typename ParserConfig = parser_config<>>
|
||||
template<typename Predicate>
|
||||
struct eps_parser;
|
||||
|
||||
/** Matches only the end of input. Produces no attribute. */
|
||||
template<typename ParserConfig = parser_config<>>
|
||||
struct eoi_parser;
|
||||
|
||||
/** Matches anything, consumes no input, and produces an attribute of type
|
||||
`RESOLVE(Attribute)`. */
|
||||
template<typename Attribute, typename ParserConfig = parser_config<>>
|
||||
template<typename Attribute>
|
||||
struct attr_parser;
|
||||
|
||||
/** A tag type that can be passed as the first parameter to `char_()` when
|
||||
@@ -356,12 +345,17 @@ namespace boost { namespace parser {
|
||||
character being matched. */
|
||||
struct digit_parser;
|
||||
|
||||
/** Maches a particular string, delimited by an iterator sentinel pair;
|
||||
/** Matches a particular string, delimited by an iterator sentinel pair;
|
||||
produces no attribute. */
|
||||
template<typename StrIter, typename StrSentinel>
|
||||
struct string_parser;
|
||||
|
||||
/** Maches an end-of-line (`NewlinesOnly == true`), whitespace
|
||||
/** 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
|
||||
(`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
|
||||
@@ -369,7 +363,7 @@ namespace boost { namespace parser {
|
||||
template<bool NewlinesOnly, bool NoNewlines>
|
||||
struct ws_parser;
|
||||
|
||||
/** Maches the strings "true" and "false", producing an attribute of
|
||||
/** Matches the strings "true" and "false", producing an attribute of
|
||||
`true` or `false`, respectively, and fails on any other input. */
|
||||
struct bool_parser;
|
||||
|
||||
@@ -426,7 +420,8 @@ namespace boost { namespace parser {
|
||||
template<
|
||||
typename Parser,
|
||||
typename GlobalState = detail::nope,
|
||||
typename ErrorHandler = default_error_handler>
|
||||
typename ErrorHandler = default_error_handler,
|
||||
bool Memoize = false>
|
||||
struct parser_interface;
|
||||
|
||||
using no_attribute = detail::nope;
|
||||
|
||||
@@ -210,6 +210,7 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser
|
||||
#if !BOOST_PARSER_USE_CONCEPTS
|
||||
,
|
||||
@@ -231,12 +232,14 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>>
|
||||
{
|
||||
constexpr replace_view() = default;
|
||||
constexpr replace_view(
|
||||
V base,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
ReplacementV replacement,
|
||||
trace trace_mode = trace::off) :
|
||||
@@ -248,7 +251,8 @@ namespace boost::parser {
|
||||
{}
|
||||
constexpr replace_view(
|
||||
V base,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
ReplacementV replacement,
|
||||
trace trace_mode = trace::off) :
|
||||
base_(std::move(base)),
|
||||
@@ -395,7 +399,7 @@ namespace boost::parser {
|
||||
private:
|
||||
V base_;
|
||||
ReplacementV replacement_;
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> parser_;
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> parser_;
|
||||
parser_interface<SkipParser> skip_;
|
||||
trace trace_mode_;
|
||||
};
|
||||
@@ -407,10 +411,11 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
replace_view(
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler>,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
|
||||
parser_interface<SkipParser>,
|
||||
ReplacementV &&,
|
||||
trace)
|
||||
@@ -420,6 +425,7 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>;
|
||||
|
||||
template<
|
||||
@@ -428,10 +434,11 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
replace_view(
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler>,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
|
||||
parser_interface<SkipParser>,
|
||||
ReplacementV &&)
|
||||
-> replace_view<
|
||||
@@ -440,6 +447,7 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>;
|
||||
|
||||
template<
|
||||
@@ -447,10 +455,11 @@ namespace boost::parser {
|
||||
typename ReplacementV,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
typename ErrorHandler,
|
||||
bool Memoize>
|
||||
replace_view(
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler>,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
|
||||
ReplacementV &&,
|
||||
trace)
|
||||
-> replace_view<
|
||||
@@ -459,6 +468,7 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
parser_interface<eps_parser<detail::phony>>>;
|
||||
|
||||
template<
|
||||
@@ -466,10 +476,11 @@ namespace boost::parser {
|
||||
typename ReplacementV,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
typename ErrorHandler,
|
||||
bool Memoize>
|
||||
replace_view(
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler>,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
|
||||
ReplacementV &&)
|
||||
-> replace_view<
|
||||
detail::text::detail::all_t<V>,
|
||||
@@ -477,6 +488,7 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
parser_interface<eps_parser<detail::phony>>>;
|
||||
|
||||
namespace detail {
|
||||
@@ -486,6 +498,7 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename Memoize,
|
||||
typename SkipParser>
|
||||
using replace_view_expr = decltype(replace_view<
|
||||
V,
|
||||
@@ -493,10 +506,14 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize::value,
|
||||
SkipParser>(
|
||||
std::declval<V>(),
|
||||
std::declval<
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &>(),
|
||||
std::declval<parser_interface<
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize::value> const &>(),
|
||||
std::declval<parser_interface<SkipParser> const &>(),
|
||||
std::declval<ReplacementV>(),
|
||||
trace::on));
|
||||
@@ -507,6 +524,7 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
constexpr bool can_replace_view = is_detected_v<
|
||||
replace_view_expr,
|
||||
@@ -515,6 +533,7 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
std::bool_constant<Memoize>,
|
||||
SkipParser>;
|
||||
|
||||
struct replace_impl
|
||||
@@ -527,6 +546,7 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
requires
|
||||
// clang-format off
|
||||
@@ -545,11 +565,12 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>
|
||||
// clang-format off
|
||||
[[nodiscard]] constexpr auto operator()(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
ReplacementR && replacement,
|
||||
@@ -573,7 +594,8 @@ namespace boost::parser {
|
||||
range_like ReplacementR,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
typename ErrorHandler,
|
||||
bool Memoize>
|
||||
requires
|
||||
// clang-format off
|
||||
(std::is_pointer_v<std::remove_cvref_t<R>> ||
|
||||
@@ -591,11 +613,12 @@ 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> const &
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
ReplacementR && replacement,
|
||||
trace trace_mode = trace::off) const
|
||||
@@ -616,14 +639,18 @@ 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> const &
|
||||
parser,
|
||||
parser_interface<
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize> const & parser,
|
||||
SkipParser && skip,
|
||||
ReplacementR && replacement = ReplacementR{},
|
||||
Trace trace_mode = Trace{}) const
|
||||
@@ -666,11 +693,15 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
[[nodiscard]] constexpr auto impl(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser,
|
||||
parser_interface<
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize> const & parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
ReplacementR && replacement,
|
||||
trace trace_mode = trace::off) const
|
||||
@@ -709,6 +740,7 @@ template<
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
constexpr bool std::ranges::enable_borrowed_range<boost::parser::replace_view<
|
||||
V,
|
||||
@@ -716,6 +748,7 @@ 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,10 +93,12 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
auto search_impl(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode)
|
||||
{
|
||||
@@ -127,6 +129,7 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
std::ranges::borrowed_subrange_t<R>
|
||||
@@ -135,7 +138,8 @@ namespace boost::parser {
|
||||
#endif
|
||||
search_repack_shim(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode)
|
||||
{
|
||||
@@ -172,6 +176,7 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser
|
||||
#if !BOOST_PARSER_USE_CONCEPTS
|
||||
,
|
||||
@@ -180,7 +185,8 @@ namespace boost::parser {
|
||||
>
|
||||
auto search(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode = trace::off)
|
||||
{
|
||||
@@ -210,11 +216,13 @@ 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> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode = trace::off)
|
||||
{
|
||||
@@ -234,7 +242,8 @@ namespace boost::parser {
|
||||
#endif
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler
|
||||
typename ErrorHandler,
|
||||
bool Memoize
|
||||
#if !BOOST_PARSER_USE_CONCEPTS
|
||||
,
|
||||
typename Enable = std::enable_if_t<detail::is_parsable_range_like_v<R>>
|
||||
@@ -242,7 +251,8 @@ namespace boost::parser {
|
||||
>
|
||||
auto search(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
trace trace_mode = trace::off)
|
||||
{
|
||||
return parser::search(
|
||||
@@ -273,11 +283,13 @@ 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> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
trace trace_mode = trace::off)
|
||||
{
|
||||
return parser::search(
|
||||
@@ -299,15 +311,22 @@ 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, SkipParser>>
|
||||
: detail::stl_interfaces::view_interface<search_all_view<
|
||||
V,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>>
|
||||
{
|
||||
constexpr search_all_view() = default;
|
||||
constexpr search_all_view(
|
||||
V base,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode = trace::off) :
|
||||
base_(std::move(base)),
|
||||
@@ -317,7 +336,8 @@ namespace boost::parser {
|
||||
{}
|
||||
constexpr search_all_view(
|
||||
V base,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
trace trace_mode = trace::off) :
|
||||
base_(std::move(base)),
|
||||
parser_(parser),
|
||||
@@ -421,7 +441,7 @@ namespace boost::parser {
|
||||
|
||||
private:
|
||||
V base_;
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> parser_;
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> parser_;
|
||||
parser_interface<SkipParser> skip_;
|
||||
trace trace_mode_;
|
||||
};
|
||||
@@ -432,10 +452,11 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
search_all_view(
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler>,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
|
||||
parser_interface<SkipParser>,
|
||||
trace)
|
||||
-> search_all_view<
|
||||
@@ -443,6 +464,7 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>;
|
||||
|
||||
template<
|
||||
@@ -450,43 +472,52 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
search_all_view(
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler>,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
|
||||
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>
|
||||
typename ErrorHandler,
|
||||
bool Memoize>
|
||||
search_all_view(
|
||||
V &&, parser_interface<Parser, GlobalState, ErrorHandler>, trace)
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
|
||||
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>
|
||||
search_all_view(V &&, parser_interface<Parser, GlobalState, ErrorHandler>)
|
||||
typename ErrorHandler,
|
||||
bool Memoize>
|
||||
search_all_view(
|
||||
V &&, parser_interface<Parser, GlobalState, ErrorHandler, Memoize>)
|
||||
-> search_all_view<
|
||||
detail::text::detail::all_t<V>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
parser_interface<eps_parser<detail::phony>>>;
|
||||
|
||||
namespace detail {
|
||||
@@ -495,16 +526,21 @@ 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> const &>(),
|
||||
std::declval<parser_interface<
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize::value> const &>(),
|
||||
std::declval<parser_interface<SkipParser> const &>(),
|
||||
trace::on));
|
||||
|
||||
@@ -513,6 +549,7 @@ 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,
|
||||
@@ -520,6 +557,7 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
std::bool_constant<Memoize>,
|
||||
SkipParser>;
|
||||
|
||||
struct search_all_impl
|
||||
@@ -530,7 +568,7 @@ namespace boost::parser {
|
||||
parsable_range_like R,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename ErrorHandler, bool Memoize,
|
||||
typename SkipParser>
|
||||
requires(
|
||||
std::is_pointer_v<std::remove_cvref_t<R>> ||
|
||||
@@ -540,11 +578,12 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>
|
||||
// clang-format off
|
||||
[[nodiscard]] constexpr auto operator()(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode = trace::off) const
|
||||
@@ -558,7 +597,7 @@ namespace boost::parser {
|
||||
parsable_range_like R,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
typename ErrorHandler, bool Memoize>
|
||||
requires(
|
||||
std::is_pointer_v<std::remove_cvref_t<R>> ||
|
||||
std::ranges::viewable_range<R>) &&
|
||||
@@ -567,11 +606,12 @@ 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> const &
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
trace trace_mode = trace::off) const
|
||||
// clang-format on
|
||||
@@ -590,14 +630,18 @@ 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> const &
|
||||
parser,
|
||||
parser_interface<
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize> const & parser,
|
||||
SkipParser const & skip = SkipParser{},
|
||||
Trace trace_mode = Trace{}) const
|
||||
{
|
||||
@@ -631,11 +675,15 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
[[nodiscard]] constexpr auto impl(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser,
|
||||
parser_interface<
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize> const & parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode = trace::off) const
|
||||
{
|
||||
@@ -663,11 +711,16 @@ 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, SkipParser>> =
|
||||
std::ranges::enable_borrowed_range<V>;
|
||||
constexpr bool
|
||||
std::ranges::enable_borrowed_range<boost::parser::search_all_view<
|
||||
V,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>> = std::ranges::enable_borrowed_range<V>;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -18,15 +18,21 @@ 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, SkipParser>>
|
||||
struct split_view : detail::stl_interfaces::view_interface<split_view<
|
||||
V,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>>
|
||||
{
|
||||
constexpr split_view() = default;
|
||||
constexpr split_view(
|
||||
V base,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode = trace::off) :
|
||||
base_(std::move(base)),
|
||||
@@ -36,7 +42,8 @@ namespace boost::parser {
|
||||
{}
|
||||
constexpr split_view(
|
||||
V base,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
trace trace_mode = trace::off) :
|
||||
base_(std::move(base)),
|
||||
parser_(parser),
|
||||
@@ -147,7 +154,7 @@ namespace boost::parser {
|
||||
|
||||
private:
|
||||
V base_;
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> parser_;
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> parser_;
|
||||
parser_interface<SkipParser> skip_;
|
||||
trace trace_mode_;
|
||||
};
|
||||
@@ -158,10 +165,11 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
split_view(
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler>,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
|
||||
parser_interface<SkipParser>,
|
||||
trace)
|
||||
-> split_view<
|
||||
@@ -169,6 +177,7 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>;
|
||||
|
||||
template<
|
||||
@@ -176,43 +185,52 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
split_view(
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler>,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
|
||||
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>
|
||||
typename ErrorHandler,
|
||||
bool Memoize>
|
||||
split_view(
|
||||
V &&, parser_interface<Parser, GlobalState, ErrorHandler>, trace)
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
|
||||
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>
|
||||
split_view(V &&, parser_interface<Parser, GlobalState, ErrorHandler>)
|
||||
typename ErrorHandler,
|
||||
bool Memoize>
|
||||
split_view(
|
||||
V &&, parser_interface<Parser, GlobalState, ErrorHandler, Memoize>)
|
||||
-> split_view<
|
||||
detail::text::detail::all_t<V>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
parser_interface<eps_parser<detail::phony>>>;
|
||||
|
||||
namespace detail {
|
||||
@@ -221,16 +239,21 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename Memoize,
|
||||
typename SkipParser>
|
||||
using split_view_expr = decltype(split_view<
|
||||
V,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
SkipParser>(
|
||||
V,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize::value,
|
||||
SkipParser>(
|
||||
std::declval<V>(),
|
||||
std::declval<
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &>(),
|
||||
std::declval<parser_interface<
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize::value> const &>(),
|
||||
std::declval<parser_interface<SkipParser> const &>(),
|
||||
trace::on));
|
||||
|
||||
@@ -239,6 +262,7 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
constexpr bool can_split_view = is_detected_v<
|
||||
split_view_expr,
|
||||
@@ -246,6 +270,7 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
std::bool_constant<Memoize>,
|
||||
SkipParser>;
|
||||
|
||||
struct split_impl
|
||||
@@ -257,6 +282,7 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
requires(
|
||||
std::is_pointer_v<std::remove_cvref_t<R>> ||
|
||||
@@ -266,11 +292,12 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>
|
||||
// clang-format off
|
||||
[[nodiscard]] constexpr auto operator()(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode = trace::off) const
|
||||
@@ -284,7 +311,8 @@ namespace boost::parser {
|
||||
parsable_range_like R,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
typename ErrorHandler,
|
||||
bool Memoize>
|
||||
requires(
|
||||
std::is_pointer_v<std::remove_cvref_t<R>> ||
|
||||
std::ranges::viewable_range<R>) &&
|
||||
@@ -293,11 +321,12 @@ 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> const &
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
trace trace_mode = trace::off) const
|
||||
// clang-format on
|
||||
@@ -316,14 +345,18 @@ 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> const &
|
||||
parser,
|
||||
parser_interface<
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize> const & parser,
|
||||
SkipParser const & skip = SkipParser{},
|
||||
Trace trace_mode = Trace{}) const
|
||||
{
|
||||
@@ -357,11 +390,15 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
[[nodiscard]] constexpr auto impl(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser,
|
||||
parser_interface<
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize> const & parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode = trace::off) const
|
||||
{
|
||||
@@ -389,10 +426,11 @@ 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, SkipParser>> =
|
||||
split_view<V, Parser, GlobalState, ErrorHandler, Memoize, SkipParser>> =
|
||||
std::ranges::enable_borrowed_range<V>;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -212,10 +212,12 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
auto attr_search_impl(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode)
|
||||
{
|
||||
@@ -282,10 +284,12 @@ 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> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode)
|
||||
{
|
||||
@@ -334,6 +338,7 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser
|
||||
#if !BOOST_PARSER_USE_CONCEPTS
|
||||
,
|
||||
@@ -351,6 +356,7 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>>
|
||||
{
|
||||
private:
|
||||
@@ -361,7 +367,8 @@ namespace boost::parser {
|
||||
constexpr transform_replace_view() = default;
|
||||
constexpr transform_replace_view(
|
||||
V base,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
F f,
|
||||
trace trace_mode = trace::off) :
|
||||
@@ -373,7 +380,8 @@ namespace boost::parser {
|
||||
{}
|
||||
constexpr transform_replace_view(
|
||||
V base,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
F f,
|
||||
trace trace_mode = trace::off) :
|
||||
base_(std::move(base)),
|
||||
@@ -518,7 +526,7 @@ namespace boost::parser {
|
||||
private:
|
||||
V base_;
|
||||
F f_;
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> parser_;
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> parser_;
|
||||
parser_interface<SkipParser> skip_;
|
||||
trace trace_mode_;
|
||||
};
|
||||
@@ -530,10 +538,11 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
transform_replace_view(
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler>,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
|
||||
parser_interface<SkipParser>,
|
||||
F &&,
|
||||
trace)
|
||||
@@ -543,6 +552,7 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>;
|
||||
|
||||
template<
|
||||
@@ -551,10 +561,11 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
transform_replace_view(
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler>,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
|
||||
parser_interface<SkipParser>,
|
||||
F &&)
|
||||
-> transform_replace_view<
|
||||
@@ -563,6 +574,7 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>;
|
||||
|
||||
template<
|
||||
@@ -570,15 +582,20 @@ namespace boost::parser {
|
||||
typename F,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
typename ErrorHandler,
|
||||
bool Memoize>
|
||||
transform_replace_view(
|
||||
V &&, parser_interface<Parser, GlobalState, ErrorHandler>, F &&, trace)
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
|
||||
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<
|
||||
@@ -586,15 +603,19 @@ namespace boost::parser {
|
||||
typename F,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
typename ErrorHandler,
|
||||
bool Memoize>
|
||||
transform_replace_view(
|
||||
V &&, parser_interface<Parser, GlobalState, ErrorHandler>, F &&)
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
|
||||
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 {
|
||||
@@ -604,6 +625,7 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename Memoize,
|
||||
typename SkipParser>
|
||||
using transform_replace_view_expr = decltype(transform_replace_view<
|
||||
V,
|
||||
@@ -611,10 +633,14 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize::value,
|
||||
SkipParser>(
|
||||
std::declval<V>(),
|
||||
std::declval<
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &>(),
|
||||
std::declval<parser_interface<
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize::value> const &>(),
|
||||
std::declval<parser_interface<SkipParser> const &>(),
|
||||
std::declval<F>(),
|
||||
trace::on));
|
||||
@@ -625,6 +651,7 @@ 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,
|
||||
@@ -633,6 +660,7 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
std::bool_constant<Memoize>,
|
||||
SkipParser>;
|
||||
|
||||
struct transform_replace_impl
|
||||
@@ -645,6 +673,7 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
requires
|
||||
// clang-format off
|
||||
@@ -663,11 +692,12 @@ namespace boost::parser {
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize,
|
||||
SkipParser>
|
||||
// clang-format off
|
||||
[[nodiscard]] constexpr auto operator()(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
F && f,
|
||||
@@ -690,7 +720,8 @@ namespace boost::parser {
|
||||
std::move_constructible F,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
typename ErrorHandler,
|
||||
bool Memoize>
|
||||
requires
|
||||
// clang-format off
|
||||
(std::is_pointer_v<std::remove_cvref_t<R>> ||
|
||||
@@ -708,11 +739,12 @@ 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> const &
|
||||
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
|
||||
parser,
|
||||
F && f,
|
||||
trace trace_mode = trace::off) const
|
||||
@@ -733,14 +765,18 @@ 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> const &
|
||||
parser,
|
||||
parser_interface<
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize> const & parser,
|
||||
SkipParser && skip,
|
||||
F && f = F{},
|
||||
Trace trace_mode = Trace{}) const
|
||||
@@ -787,11 +823,15 @@ namespace boost::parser {
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
[[nodiscard]] constexpr auto impl(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser,
|
||||
parser_interface<
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
Memoize> const & parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
F && f,
|
||||
trace trace_mode = trace::off) const
|
||||
@@ -830,6 +870,7 @@ template<
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
bool Memoize,
|
||||
typename SkipParser>
|
||||
constexpr bool
|
||||
std::ranges::enable_borrowed_range<boost::parser::transform_replace_view<
|
||||
@@ -838,6 +879,7 @@ 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>);
|
||||
|
||||
@@ -46,6 +46,7 @@ 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)
|
||||
@@ -62,6 +63,7 @@ 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)
|
||||
|
||||
452
test/memos.cpp
Normal file
452
test/memos.cpp
Normal file
@@ -0,0 +1,452 @@
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
279
test/parser_quoted_string.cpp
Normal file
279
test/parser_quoted_string.cpp
Normal file
@@ -0,0 +1,279 @@
|
||||
/**
|
||||
* 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
|
||||
//]
|
||||
}
|
||||
@@ -312,6 +312,15 @@ 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"
|
||||
|
||||
Reference in New Issue
Block a user