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

1 Commits

Author SHA1 Message Date
Zach Laine
390cd1dbe1 parser_config_WIP 2024-03-10 20:09:59 -05:00
18 changed files with 426 additions and 2524 deletions

View File

@@ -41,7 +41,6 @@
[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]
@@ -219,8 +218,6 @@
[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]]`()`]

View File

@@ -38,8 +38,6 @@ 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]
@@ -328,31 +326,6 @@ 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

View File

@@ -738,106 +738,6 @@ 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
@@ -1152,6 +1052,43 @@ 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

View File

@@ -51,16 +51,14 @@ 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 &>(),
std::declval<detail::nope &>()));
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 &>()));
template<typename T, typename I, typename S, typename GlobalState>
concept error_handler =

View File

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

View File

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

View File

@@ -148,10 +148,10 @@ namespace boost { namespace parser { namespace detail {
std::ostream & os,
int components = 0);
template<typename Context, typename Parser, bool FailOnMatch>
template<typename Context, typename Parser, typename ParserConfig>
void print_parser(
Context const & context,
expect_parser<Parser, FailOnMatch> const & parser,
expect_parser_t<Parser, ParserConfig> const & parser,
std::ostream & os,
int components = 0);
@@ -278,13 +278,6 @@ namespace boost { namespace parser { namespace detail {
std::ostream & os,
int components = 0);
template<typename Context, typename Quotes, typename Escapes>
void print_parser(
Context const & context,
quoted_string_parser<Quotes, Escapes> const & parser,
std::ostream & os,
int components = 0);
template<typename Context, bool NewlinesOnly, bool NoNewlines>
void print_parser(
Context const & context,

View File

@@ -378,14 +378,14 @@ namespace boost { namespace parser { namespace detail {
}
}
template<typename Context, typename Parser, bool FailOnMatch>
template<typename Context, typename Parser, typename ParserConfig>
void print_parser(
Context const & context,
expect_parser<Parser, FailOnMatch> const & parser,
expect_parser_t<Parser, ParserConfig> const & parser,
std::ostream & os,
int components)
{
if (FailOnMatch)
if (ParserConfig::fail_on_match)
os << "!";
else
os << "&";
@@ -482,7 +482,8 @@ namespace boost { namespace parser { namespace detail {
template<
typename Context,
typename ResolvedExpected,
bool Integral = std::is_integral<ResolvedExpected>{}>
bool Integral = std::is_integral<ResolvedExpected>{},
int SizeofExpected = sizeof(ResolvedExpected)>
struct print_expected_char_impl
{
static void call(
@@ -494,17 +495,13 @@ namespace boost { namespace parser { namespace detail {
}
};
template<typename Context>
struct print_expected_char_impl<Context, char32_t, true>
template<typename Context, typename Expected>
struct print_expected_char_impl<Context, Expected, true, 4>
{
static void
call(Context const & context, std::ostream & os, char32_t expected)
call(Context const & context, std::ostream & os, Expected expected)
{
if (expected == '\'') {
os << "'\\''";
return;
}
std::array<char32_t, 1> cps = {{expected}};
std::array<char32_t, 1> cps = {{(char32_t)expected}};
auto const r = cps | text::as_utf8;
os << "'";
for (auto c : r) {
@@ -692,27 +689,6 @@ namespace boost { namespace parser { namespace detail {
os << "\"";
}
template<typename Context, typename Quotes, typename Escapes>
void print_parser(
Context const & context,
quoted_string_parser<Quotes, Escapes> const & parser,
std::ostream & os,
int components)
{
os << "quoted_string(";
if constexpr (is_nope_v<Quotes>) {
detail::print_expected_char_impl<Context, char32_t>::call(
context, os, parser.ch_);
} else {
os << '"';
for (auto c : parser.chs_ | text::as_utf8) {
detail::print_char(os, c);
}
os << '"';
}
os << ')';
}
template<typename Context, bool NewlinesOnly, bool NoNewlines>
void print_parser(
Context const & context,

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,6 @@
#include <boost/parser/config.hpp>
#include <boost/parser/error_handling_fwd.hpp>
#include <boost/parser/detail/memos.hpp>
#include <any>
#include <cstdint>
@@ -71,6 +70,7 @@ 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,8 +80,7 @@ namespace boost { namespace parser {
bool UseCallbacks,
typename Iter,
typename Sentinel,
typename ErrorHandler,
typename Memos>
typename ErrorHandler>
inline auto make_context(
Iter first,
Sentinel last,
@@ -89,8 +88,7 @@ namespace boost { namespace parser {
int & indent,
ErrorHandler const & error_handler,
nope &,
symbol_table_tries_t & symbol_table_tries,
Memos & memos) noexcept;
symbol_table_tries_t & symbol_table_tries) noexcept;
struct skip_skipper;
@@ -119,6 +117,25 @@ 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`,
@@ -131,36 +148,15 @@ namespace boost { namespace parser {
typename Parser,
typename DelimiterParser = detail::nope,
typename MinType = int64_t,
typename MaxType = int64_t>
typename MaxType = int64_t,
typename ParserConfig = parser_config<>>
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>
template<typename Parser, typename ParserConfig = parser_config<>>
struct opt_parser;
/** Applies each parser in `ParserTuple`, in order, stopping after the
@@ -168,7 +164,7 @@ namespace boost { namespace parser {
one of the sub-parsers succeeds. The attribute produced is a
`std::variant` over the types of attribute produced by the parsers in
`ParserTuple`. */
template<typename ParserTuple>
template<typename ParserTuple, typename ParserConfig = parser_config<>>
struct or_parser;
/** Applies each parsers in `ParserTuple`, an any order, stopping after
@@ -179,7 +175,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>
template<typename ParserTuple, typename ParserConfig = parser_config<>>
struct perm_parser;
/** Applies each parser in `ParserTuple`, in order. The parse succeeds
@@ -192,14 +188,18 @@ namespace boost { namespace parser {
template<
typename ParserTuple,
typename BacktrackingTuple,
typename CombiningGroups>
typename CombiningGroups,
typename ParserConfig = parser_config<>>
struct seq_parser;
/** Applies the given parser `p` of type `Parser` and an invocable `a` of
type `Action`. `Action` shall model `semantic_action`, and `a` will
only be invoked if `p` succeeds. The parse succeeds iff `p` succeeds.
Produces no attribute. */
template<typename Parser, typename Action>
template<
typename Parser,
typename Action,
typename ParserConfig = parser_config<>>
struct action_parser;
/** Applies the given parser `p` of type `Parser`. The attribute produced
@@ -207,21 +207,24 @@ namespace boost { namespace parser {
only be invoked if `p` succeeds and sttributes are currently being
generated. The parse succeeds iff `p` succeeds. The attribute
produced is the the result of the call to `f`. */
template<typename Parser, typename F>
template<
typename Parser,
typename F,
typename ParserConfig = parser_config<>>
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>
template<typename Parser, typename ParserConfig = parser_config<>>
struct omit_parser;
/** Applies the given parser `p` of type `Parser`; regardless of the
attribute produced by `Parser`, this parser's attribute is equivalent
to `_where(ctx)` within a semantic action on `p`. The parse succeeds
iff `p` succeeds. */
template<typename Parser>
template<typename Parser, typename ParserConfig = parser_config<>>
struct raw_parser;
#if defined(BOOST_PARSER_DOXYGEN) || defined(__cpp_lib_concepts)
@@ -234,43 +237,49 @@ namespace boost { namespace parser {
non-contiguous, code using `string_view_parser` is ill-formed. The
parse succeeds iff `p` succeeds. This parser is only available in
C++20 and later. */
template<typename Parser>
template<typename Parser, typename ParserConfig = parser_config<>>
struct string_view_parser;
#endif
/** Applies the given parser `p` of type `Parser`, disabling the current
skipper in use, if any. The parse succeeds iff `p` succeeds. The
attribute produced is the type of attribute produced by `Parser`. */
template<typename Parser>
template<typename Parser, typename ParserConfig = parser_config<>>
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>
template<typename Parser, typename ParserConfig = parser_config<>>
struct no_case_parser;
/** Applies the given parser `p` of type `Parser`, using a parser of type
`SkipParser` as the skipper. The parse succeeds iff `p` succeeds.
The attribute produced is the type of attribute produced by
`Parser`. */
template<typename Parser, typename SkipParser = detail::nope>
template<
typename Parser,
typename SkipParser = detail::nope,
typename ParserConfig = parser_config<>>
struct skip_parser;
/** Applies the given parser `p` of type `Parser`, producing no attributes
and consuming no input. The parse succeeds iff `p`'s success is
unequal to `FailOnMatch`. */
template<typename Parser, bool FailOnMatch>
template<
typename Parser,
typename ParserConfig,
typename ParserConfig = parser_config<>>
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>
/** 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<>>
struct symbol_parser;
/** Applies another parser `p`, associated with this parser via `TagType`.
@@ -289,22 +298,24 @@ namespace boost { namespace parser {
typename TagType,
typename Attribute,
typename LocalState,
typename ParamsTuple>
typename ParamsTuple,
typename ParserConfig = parser_config<>>
struct rule_parser;
/** Matches anything, and consumes no input. If `Predicate` is anything
other than `detail::nope` (which it is by default), and `pred_(ctx)`
evaluates to false, where `ctx` is the parser context, the parse
fails. */
template<typename Predicate>
template<typename Predicate, typename ParserConfig = parser_config<>>
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>
template<typename Attribute, typename ParserConfig = parser_config<>>
struct attr_parser;
/** A tag type that can be passed as the first parameter to `char_()` when
@@ -345,17 +356,12 @@ namespace boost { namespace parser {
character being matched. */
struct digit_parser;
/** Matches a particular string, delimited by an iterator sentinel pair;
/** Maches a particular string, delimited by an iterator sentinel pair;
produces no attribute. */
template<typename StrIter, typename StrSentinel>
struct string_parser;
/** Matches a string delimited by quotation marks; produces a
`std::string` attribute. */
template<typename Quotes = detail::nope, typename Escapes = detail::nope>
struct quoted_string_parser;
/** Matches an end-of-line (`NewlinesOnly == true`), whitespace
/** Maches an end-of-line (`NewlinesOnly == true`), whitespace
(`NewlinesOnly == false`), or (`NoNewlines == true`) blank (whitespace
but not newline) code point, based on the Unicode definitions of each
(also matches the two code points `"\r\n"`). Produces no
@@ -363,7 +369,7 @@ namespace boost { namespace parser {
template<bool NewlinesOnly, bool NoNewlines>
struct ws_parser;
/** Matches the strings "true" and "false", producing an attribute of
/** Maches the strings "true" and "false", producing an attribute of
`true` or `false`, respectively, and fails on any other input. */
struct bool_parser;
@@ -420,8 +426,7 @@ namespace boost { namespace parser {
template<
typename Parser,
typename GlobalState = detail::nope,
typename ErrorHandler = default_error_handler,
bool Memoize = false>
typename ErrorHandler = default_error_handler>
struct parser_interface;
using no_attribute = detail::nope;

View File

@@ -210,7 +210,6 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser
#if !BOOST_PARSER_USE_CONCEPTS
,
@@ -232,14 +231,12 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize,
SkipParser>>
{
constexpr replace_view() = default;
constexpr replace_view(
V base,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser,
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
parser_interface<SkipParser> const & skip,
ReplacementV replacement,
trace trace_mode = trace::off) :
@@ -251,8 +248,7 @@ namespace boost::parser {
{}
constexpr replace_view(
V base,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser,
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
ReplacementV replacement,
trace trace_mode = trace::off) :
base_(std::move(base)),
@@ -399,7 +395,7 @@ namespace boost::parser {
private:
V base_;
ReplacementV replacement_;
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> parser_;
parser_interface<Parser, GlobalState, ErrorHandler> parser_;
parser_interface<SkipParser> skip_;
trace trace_mode_;
};
@@ -411,11 +407,10 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
replace_view(
V &&,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
parser_interface<Parser, GlobalState, ErrorHandler>,
parser_interface<SkipParser>,
ReplacementV &&,
trace)
@@ -425,7 +420,6 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize,
SkipParser>;
template<
@@ -434,11 +428,10 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
replace_view(
V &&,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
parser_interface<Parser, GlobalState, ErrorHandler>,
parser_interface<SkipParser>,
ReplacementV &&)
-> replace_view<
@@ -447,7 +440,6 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize,
SkipParser>;
template<
@@ -455,11 +447,10 @@ namespace boost::parser {
typename ReplacementV,
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize>
typename ErrorHandler>
replace_view(
V &&,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
parser_interface<Parser, GlobalState, ErrorHandler>,
ReplacementV &&,
trace)
-> replace_view<
@@ -468,7 +459,6 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize,
parser_interface<eps_parser<detail::phony>>>;
template<
@@ -476,11 +466,10 @@ namespace boost::parser {
typename ReplacementV,
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize>
typename ErrorHandler>
replace_view(
V &&,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
parser_interface<Parser, GlobalState, ErrorHandler>,
ReplacementV &&)
-> replace_view<
detail::text::detail::all_t<V>,
@@ -488,7 +477,6 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize,
parser_interface<eps_parser<detail::phony>>>;
namespace detail {
@@ -498,7 +486,6 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
typename Memoize,
typename SkipParser>
using replace_view_expr = decltype(replace_view<
V,
@@ -506,14 +493,10 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize::value,
SkipParser>(
std::declval<V>(),
std::declval<parser_interface<
Parser,
GlobalState,
ErrorHandler,
Memoize::value> const &>(),
std::declval<
parser_interface<Parser, GlobalState, ErrorHandler> const &>(),
std::declval<parser_interface<SkipParser> const &>(),
std::declval<ReplacementV>(),
trace::on));
@@ -524,7 +507,6 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
constexpr bool can_replace_view = is_detected_v<
replace_view_expr,
@@ -533,7 +515,6 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
std::bool_constant<Memoize>,
SkipParser>;
struct replace_impl
@@ -546,7 +527,6 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
requires
// clang-format off
@@ -565,12 +545,11 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize,
SkipParser>
// clang-format off
[[nodiscard]] constexpr auto operator()(
R && r,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser_interface<Parser, GlobalState, ErrorHandler> const &
parser,
parser_interface<SkipParser> const & skip,
ReplacementR && replacement,
@@ -594,8 +573,7 @@ namespace boost::parser {
range_like ReplacementR,
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize>
typename ErrorHandler>
requires
// clang-format off
(std::is_pointer_v<std::remove_cvref_t<R>> ||
@@ -613,12 +591,11 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize,
parser_interface<eps_parser<detail::phony>>>
// clang-format off
[[nodiscard]] constexpr auto operator()(
R && r,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser_interface<Parser, GlobalState, ErrorHandler> const &
parser,
ReplacementR && replacement,
trace trace_mode = trace::off) const
@@ -639,18 +616,14 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser,
typename ReplacementR = trace,
typename Trace = trace,
typename Enable = std::enable_if_t<is_parsable_range_like_v<R>>>
[[nodiscard]] constexpr auto operator()(
R && r,
parser_interface<
Parser,
GlobalState,
ErrorHandler,
Memoize> const & parser,
parser_interface<Parser, GlobalState, ErrorHandler> const &
parser,
SkipParser && skip,
ReplacementR && replacement = ReplacementR{},
Trace trace_mode = Trace{}) const
@@ -693,15 +666,11 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
[[nodiscard]] constexpr auto impl(
R && r,
parser_interface<
Parser,
GlobalState,
ErrorHandler,
Memoize> const & parser,
parser_interface<Parser, GlobalState, ErrorHandler> const &
parser,
parser_interface<SkipParser> const & skip,
ReplacementR && replacement,
trace trace_mode = trace::off) const
@@ -740,7 +709,6 @@ template<
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
constexpr bool std::ranges::enable_borrowed_range<boost::parser::replace_view<
V,
@@ -748,7 +716,6 @@ constexpr bool std::ranges::enable_borrowed_range<boost::parser::replace_view<
Parser,
GlobalState,
ErrorHandler,
Memoize,
SkipParser>> = std::ranges::enable_borrowed_range<V> &&
std::ranges::enable_borrowed_range<ReplacementV>;
#endif

View File

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

View File

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

View File

@@ -212,12 +212,10 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
auto attr_search_impl(
R && r,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser,
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
parser_interface<SkipParser> const & skip,
trace trace_mode)
{
@@ -284,12 +282,10 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
auto attr_search_repack_shim(
R && r,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser,
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
parser_interface<SkipParser> const & skip,
trace trace_mode)
{
@@ -338,7 +334,6 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser
#if !BOOST_PARSER_USE_CONCEPTS
,
@@ -356,7 +351,6 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize,
SkipParser>>
{
private:
@@ -367,8 +361,7 @@ namespace boost::parser {
constexpr transform_replace_view() = default;
constexpr transform_replace_view(
V base,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser,
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
parser_interface<SkipParser> const & skip,
F f,
trace trace_mode = trace::off) :
@@ -380,8 +373,7 @@ namespace boost::parser {
{}
constexpr transform_replace_view(
V base,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser,
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
F f,
trace trace_mode = trace::off) :
base_(std::move(base)),
@@ -526,7 +518,7 @@ namespace boost::parser {
private:
V base_;
F f_;
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> parser_;
parser_interface<Parser, GlobalState, ErrorHandler> parser_;
parser_interface<SkipParser> skip_;
trace trace_mode_;
};
@@ -538,11 +530,10 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
transform_replace_view(
V &&,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
parser_interface<Parser, GlobalState, ErrorHandler>,
parser_interface<SkipParser>,
F &&,
trace)
@@ -552,7 +543,6 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize,
SkipParser>;
template<
@@ -561,11 +551,10 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
transform_replace_view(
V &&,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
parser_interface<Parser, GlobalState, ErrorHandler>,
parser_interface<SkipParser>,
F &&)
-> transform_replace_view<
@@ -574,7 +563,6 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize,
SkipParser>;
template<
@@ -582,20 +570,15 @@ namespace boost::parser {
typename F,
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize>
typename ErrorHandler>
transform_replace_view(
V &&,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
F &&,
trace)
V &&, parser_interface<Parser, GlobalState, ErrorHandler>, F &&, trace)
-> transform_replace_view<
detail::text::detail::all_t<V>,
detail::remove_cv_ref_t<F>,
Parser,
GlobalState,
ErrorHandler,
Memoize,
parser_interface<eps_parser<detail::phony>>>;
template<
@@ -603,19 +586,15 @@ namespace boost::parser {
typename F,
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize>
typename ErrorHandler>
transform_replace_view(
V &&,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize>,
F &&)
V &&, parser_interface<Parser, GlobalState, ErrorHandler>, F &&)
-> transform_replace_view<
detail::text::detail::all_t<V>,
detail::remove_cv_ref_t<F>,
Parser,
GlobalState,
ErrorHandler,
Memoize,
parser_interface<eps_parser<detail::phony>>>;
namespace detail {
@@ -625,7 +604,6 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
typename Memoize,
typename SkipParser>
using transform_replace_view_expr = decltype(transform_replace_view<
V,
@@ -633,14 +611,10 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize::value,
SkipParser>(
std::declval<V>(),
std::declval<parser_interface<
Parser,
GlobalState,
ErrorHandler,
Memoize::value> const &>(),
std::declval<
parser_interface<Parser, GlobalState, ErrorHandler> const &>(),
std::declval<parser_interface<SkipParser> const &>(),
std::declval<F>(),
trace::on));
@@ -651,7 +625,6 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
constexpr bool can_transform_replace_view = is_detected_v<
transform_replace_view_expr,
@@ -660,7 +633,6 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
std::bool_constant<Memoize>,
SkipParser>;
struct transform_replace_impl
@@ -673,7 +645,6 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
requires
// clang-format off
@@ -692,12 +663,11 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize,
SkipParser>
// clang-format off
[[nodiscard]] constexpr auto operator()(
R && r,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser_interface<Parser, GlobalState, ErrorHandler> const &
parser,
parser_interface<SkipParser> const & skip,
F && f,
@@ -720,8 +690,7 @@ namespace boost::parser {
std::move_constructible F,
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize>
typename ErrorHandler>
requires
// clang-format off
(std::is_pointer_v<std::remove_cvref_t<R>> ||
@@ -739,12 +708,11 @@ namespace boost::parser {
Parser,
GlobalState,
ErrorHandler,
Memoize,
parser_interface<eps_parser<detail::phony>>>
// clang-format off
[[nodiscard]] constexpr auto operator()(
R && r,
parser_interface<Parser, GlobalState, ErrorHandler, Memoize> const &
parser_interface<Parser, GlobalState, ErrorHandler> const &
parser,
F && f,
trace trace_mode = trace::off) const
@@ -765,18 +733,14 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser,
typename F = trace,
typename Trace = trace,
typename Enable = std::enable_if_t<is_parsable_range_like_v<R>>>
[[nodiscard]] constexpr auto operator()(
R && r,
parser_interface<
Parser,
GlobalState,
ErrorHandler,
Memoize> const & parser,
parser_interface<Parser, GlobalState, ErrorHandler> const &
parser,
SkipParser && skip,
F && f = F{},
Trace trace_mode = Trace{}) const
@@ -823,15 +787,11 @@ namespace boost::parser {
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
[[nodiscard]] constexpr auto impl(
R && r,
parser_interface<
Parser,
GlobalState,
ErrorHandler,
Memoize> const & parser,
parser_interface<Parser, GlobalState, ErrorHandler> const &
parser,
parser_interface<SkipParser> const & skip,
F && f,
trace trace_mode = trace::off) const
@@ -870,7 +830,6 @@ template<
typename Parser,
typename GlobalState,
typename ErrorHandler,
bool Memoize,
typename SkipParser>
constexpr bool
std::ranges::enable_borrowed_range<boost::parser::transform_replace_view<
@@ -879,7 +838,6 @@ constexpr bool
Parser,
GlobalState,
ErrorHandler,
Memoize,
SkipParser>> = std::ranges::enable_borrowed_range<V> &&
(std::ranges::enable_borrowed_range<F> ||
boost::parser::detail::tidy_func<F>);

View File

@@ -46,7 +46,6 @@ macro(add_test_executable name)
add_test(NAME ${name} COMMAND ${name} --gtest_catch_exceptions=1)
endmacro()
add_test_executable(memos)
add_test_executable(all_t)
add_test_executable(search)
add_test_executable(split)
@@ -63,7 +62,6 @@ add_test_executable(parser_rule_with_params)
add_test_executable(parser_action)
add_test_executable(parser_action_with_params)
add_test_executable(parser_symbol_table)
add_test_executable(parser_quoted_string)
add_test_executable(tracing)
add_test_executable(parse_empty)
add_test_executable(tuple_aggregate)

View File

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

View File

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

View File

@@ -312,15 +312,6 @@ int main()
PARSE(string("h"));
std::cout << "\n\n"
<< "----------------------------------------\n"
<< "| quoted_string() |\n"
<< "----------------------------------------\n";
PARSE(quoted_string);
PARSE(quoted_string('\''));
PARSE(quoted_string("'\""));
std::cout << "\n\n"
<< "----------------------------------------\n"
<< "| eol |\n"