mirror of
https://github.com/boostorg/parser.git
synced 2026-01-19 04:22:13 +00:00
Change the no_case[] directive to use the parser_modifiers struct, like omit[]
does; remove no_case_parser. See #160.
This commit is contained in:
@@ -143,13 +143,6 @@ namespace boost { namespace parser { namespace detail {
|
||||
std::ostream & os,
|
||||
int components);
|
||||
|
||||
template<typename Context, typename Parser, typename ParserMods>
|
||||
void print_parser_impl(
|
||||
Context const & context,
|
||||
no_case_parser<Parser, ParserMods> const & parser,
|
||||
std::ostream & os,
|
||||
int components);
|
||||
|
||||
template<
|
||||
typename Context,
|
||||
typename Parser,
|
||||
|
||||
@@ -358,17 +358,6 @@ namespace boost { namespace parser { namespace detail {
|
||||
context, "lexeme", parser.parser_, os, components);
|
||||
}
|
||||
|
||||
template<typename Context, typename Parser, typename ParserMods>
|
||||
void print_parser_impl(
|
||||
Context const & context,
|
||||
no_case_parser<Parser, ParserMods> const & parser,
|
||||
std::ostream & os,
|
||||
int components)
|
||||
{
|
||||
detail::print_directive(
|
||||
context, "no_case", parser.parser_, os, components);
|
||||
}
|
||||
|
||||
template<
|
||||
typename Context,
|
||||
typename Parser,
|
||||
@@ -598,7 +587,7 @@ namespace boost { namespace parser { namespace detail {
|
||||
std::ostream & os,
|
||||
int components)
|
||||
{
|
||||
if constexpr (parser.mods_.omit_attr) {
|
||||
if constexpr (parser.mods_.omit_attr == parser::omit_attr_t::yes) {
|
||||
if constexpr (is_nope_v<Expected>) {
|
||||
os << "char_";
|
||||
} else {
|
||||
@@ -692,7 +681,7 @@ namespace boost { namespace parser { namespace detail {
|
||||
std::ostream & os,
|
||||
int components)
|
||||
{
|
||||
if constexpr (!parser.mods_.omit_attr) {
|
||||
if constexpr (parser.mods_.omit_attr == parser::omit_attr_t::no) {
|
||||
os << "string(";
|
||||
}
|
||||
os << "\"";
|
||||
@@ -702,7 +691,7 @@ namespace boost { namespace parser { namespace detail {
|
||||
detail::print_char(os, c);
|
||||
}
|
||||
os << "\"";
|
||||
if constexpr (!parser.mods_.omit_attr) {
|
||||
if constexpr (parser.mods_.omit_attr == parser::omit_attr_t::no) {
|
||||
os << ")";
|
||||
}
|
||||
}
|
||||
@@ -953,15 +942,23 @@ namespace boost { namespace parser { namespace detail {
|
||||
scoped_print_parser_mods(std::ostream & os, Parser const & parser) :
|
||||
os_(os), mods_(parser.mods_)
|
||||
{
|
||||
if constexpr (ParserMods::omit_attr) {
|
||||
if constexpr (ParserMods::omit_attr == parser::omit_attr_t::yes) {
|
||||
skip_omit_ = skip_omit(parser);
|
||||
if (!skip_omit_)
|
||||
os_ << "omit[";
|
||||
}
|
||||
if constexpr (
|
||||
ParserMods::ignore_case == parser::ignore_case_t::yes) {
|
||||
os_ << "no_case[";
|
||||
}
|
||||
}
|
||||
~scoped_print_parser_mods()
|
||||
{
|
||||
if constexpr (ParserMods::omit_attr) {
|
||||
if constexpr (
|
||||
ParserMods::ignore_case == parser::ignore_case_t::yes) {
|
||||
os_ << "]";
|
||||
}
|
||||
if constexpr (ParserMods::omit_attr == parser::omit_attr_t::yes) {
|
||||
if (!skip_omit_)
|
||||
os_ << "]";
|
||||
}
|
||||
@@ -993,8 +990,9 @@ namespace boost { namespace parser { namespace detail {
|
||||
bool skip_omit_ = false;
|
||||
};
|
||||
|
||||
// TODO: Document how 'omit[]' will reappear for subparsers sometimes, as
|
||||
// in omt[*omit[char_]] (see test/tracing.cpp).
|
||||
// TODO: Document how recursive directives like 'omit[]' and
|
||||
// `no_case[]`will reappear for subparsers sometimes, as in
|
||||
// omt[*omit[char_]] (see test/tracing.cpp).
|
||||
template<typename Context, typename Parser>
|
||||
void print_parser(
|
||||
Context const & context,
|
||||
|
||||
@@ -1357,7 +1357,8 @@ namespace boost { namespace parser {
|
||||
template<typename ParserMods>
|
||||
constexpr auto gen_attrs()
|
||||
{
|
||||
return std::bool_constant<!ParserMods::omit_attr>{};
|
||||
return std::bool_constant<
|
||||
ParserMods::omit_attr == omit_attr_t::no>{};
|
||||
}
|
||||
|
||||
template<typename Container, typename T>
|
||||
@@ -1689,7 +1690,7 @@ namespace boost { namespace parser {
|
||||
pending_operations.clear();
|
||||
}
|
||||
|
||||
template<typename Context, typename T>
|
||||
template<parser::ignore_case_t IgnoreCase, typename Context, typename T>
|
||||
auto get_trie(
|
||||
Context const & context, symbol_parser_impl<T> const & sym_parser)
|
||||
{
|
||||
@@ -1701,7 +1702,8 @@ namespace boost { namespace parser {
|
||||
auto & [any, has_case_folded] =
|
||||
symbol_table_tries[(void *)&sym_parser.ref()];
|
||||
|
||||
bool const needs_case_folded = context.no_case_depth_;
|
||||
constexpr bool needs_case_folded =
|
||||
IgnoreCase == parser::ignore_case_t::yes;
|
||||
|
||||
if (!any.has_value()) {
|
||||
any = trie_t{};
|
||||
@@ -1805,52 +1807,6 @@ namespace boost { namespace parser {
|
||||
{}, std::nullopt, detail::symbol_table_op::clear});
|
||||
}
|
||||
|
||||
template<typename Context>
|
||||
parser::detail::text::optional_ref<T>
|
||||
find(Context const & context, std::string_view str) const
|
||||
{
|
||||
auto [trie, has_case_folded] = detail::get_trie(context, ref());
|
||||
if (context.no_case_depth_) {
|
||||
return trie[detail::case_fold_view(
|
||||
str | detail::text::as_utf32)];
|
||||
} else {
|
||||
return trie[str | detail::text::as_utf32];
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Context>
|
||||
void
|
||||
insert(Context const & context, std::string_view str, T && x) const
|
||||
{
|
||||
auto [trie, has_case_folded] = detail::get_trie(context, ref());
|
||||
if (context.no_case_depth_) {
|
||||
trie.insert(
|
||||
detail::case_fold_view(str | detail::text::as_utf32),
|
||||
std::move(x));
|
||||
} else {
|
||||
trie.insert(str | detail::text::as_utf32, std::move(x));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Context>
|
||||
void erase(Context const & context, std::string_view str) const
|
||||
{
|
||||
auto [trie, has_case_folded] = detail::get_trie(context, ref());
|
||||
if (context.no_case_depth_) {
|
||||
trie.erase(
|
||||
detail::case_fold_view(str | detail::text::as_utf32));
|
||||
} else {
|
||||
trie.erase(str | detail::text::as_utf32);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Context>
|
||||
void clear(Context const & context) const
|
||||
{
|
||||
auto [trie, _] = detail::get_trie(context, ref());
|
||||
trie.clear();
|
||||
}
|
||||
|
||||
mutable std::vector<std::pair<std::string, T>> initial_elements_;
|
||||
symbol_parser_impl const * copied_from_;
|
||||
|
||||
@@ -1891,14 +1847,14 @@ namespace boost { namespace parser {
|
||||
template<typename Iter, typename Sentinel, bool SortedUTF32>
|
||||
struct char_range
|
||||
{
|
||||
template<typename T, typename Context>
|
||||
bool contains(T c_, Context const & context) const
|
||||
template<parser::ignore_case_t IgnoreCase, typename T>
|
||||
bool contains(T c_) const
|
||||
{
|
||||
if constexpr (SortedUTF32) {
|
||||
return std::binary_search(chars_.begin(), chars_.end(), c_);
|
||||
}
|
||||
|
||||
if (context.no_case_depth_) {
|
||||
if constexpr (IgnoreCase == parser::ignore_case_t::yes) {
|
||||
case_fold_array_t folded;
|
||||
auto folded_last = detail::case_fold(c_, folded.begin());
|
||||
if constexpr (std::is_same_v<T, char32_t>) {
|
||||
@@ -1959,11 +1915,11 @@ namespace boost { namespace parser {
|
||||
}
|
||||
}
|
||||
|
||||
template<bool Equal, typename Context>
|
||||
auto no_case_aware_compare(Context const & context)
|
||||
template<parser::ignore_case_t IgnoreCase, bool Equal>
|
||||
auto no_case_aware_compare()
|
||||
{
|
||||
return [no_case = context.no_case_depth_](char32_t a, char32_t b) {
|
||||
if (no_case) {
|
||||
return [](char32_t a, char32_t b) {
|
||||
if (IgnoreCase == parser::ignore_case_t::yes) {
|
||||
case_fold_array_t folded_a = {0, 0, 0};
|
||||
detail::case_fold(a, folded_a.begin());
|
||||
case_fold_array_t folded_b = {0, 0, 0};
|
||||
@@ -1984,6 +1940,7 @@ namespace boost { namespace parser {
|
||||
decltype(std::declval<T &>() == std::declval<U &>());
|
||||
|
||||
template<
|
||||
parser::ignore_case_t IgnoreCase,
|
||||
typename Context,
|
||||
typename CharType,
|
||||
typename Expected,
|
||||
@@ -1999,34 +1956,43 @@ namespace boost { namespace parser {
|
||||
CharType,
|
||||
decltype(resolved)>) {
|
||||
auto const compare =
|
||||
detail::no_case_aware_compare<true>(context);
|
||||
detail::no_case_aware_compare<IgnoreCase, true>();
|
||||
return !compare(c, resolved);
|
||||
} else {
|
||||
return !resolved.contains(c, context);
|
||||
return !resolved.template contains<IgnoreCase>(c);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Context, typename CharType, typename Expected>
|
||||
struct unequal_impl<Context, CharType, Expected, true>
|
||||
template<
|
||||
parser::ignore_case_t IgnoreCase,
|
||||
typename Context,
|
||||
typename CharType,
|
||||
typename Expected>
|
||||
struct unequal_impl<IgnoreCase, Context, CharType, Expected, true>
|
||||
{
|
||||
static bool
|
||||
call(Context const & context, CharType c, Expected expected)
|
||||
{
|
||||
|
||||
return !detail::no_case_aware_compare<true>(context)(
|
||||
return !detail::no_case_aware_compare<IgnoreCase, true>()(
|
||||
c, expected);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Context, typename CharType, typename Expected>
|
||||
template<
|
||||
parser::ignore_case_t IgnoreCase,
|
||||
typename Context,
|
||||
typename CharType,
|
||||
typename Expected>
|
||||
bool unequal(Context const & context, CharType c, Expected expected)
|
||||
{
|
||||
return unequal_impl<Context, CharType, Expected>::call(
|
||||
return unequal_impl<IgnoreCase, Context, CharType, Expected>::call(
|
||||
context, c, expected);
|
||||
}
|
||||
|
||||
template<
|
||||
parser::ignore_case_t IgnoreCase,
|
||||
typename Context,
|
||||
typename CharType,
|
||||
typename LoType,
|
||||
@@ -2036,7 +2002,8 @@ namespace boost { namespace parser {
|
||||
CharType c,
|
||||
char_pair<LoType, HiType> const & expected)
|
||||
{
|
||||
auto const less = detail::no_case_aware_compare<false>(context);
|
||||
auto const less =
|
||||
detail::no_case_aware_compare<IgnoreCase, false>();
|
||||
{
|
||||
auto lo = detail::resolve(context, expected.lo_);
|
||||
if (less(c, lo))
|
||||
@@ -2050,7 +2017,10 @@ namespace boost { namespace parser {
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename Context, typename CharType>
|
||||
template<
|
||||
parser::ignore_case_t IgnoreCase,
|
||||
typename Context,
|
||||
typename CharType>
|
||||
bool unequal(Context const &, CharType, nope)
|
||||
{
|
||||
return false;
|
||||
@@ -2796,18 +2766,15 @@ namespace boost { namespace parser {
|
||||
}
|
||||
|
||||
template<
|
||||
parser::ignore_case_t IgnoreCase,
|
||||
typename Iter1,
|
||||
typename Sentinel1,
|
||||
typename Iter2,
|
||||
typename Sentinel2>
|
||||
std::pair<Iter1, Iter2> no_case_aware_string_mismatch(
|
||||
Iter1 first1,
|
||||
Sentinel1 last1,
|
||||
Iter2 first2,
|
||||
Sentinel2 last2,
|
||||
bool no_case)
|
||||
Iter1 first1, Sentinel1 last1, Iter2 first2, Sentinel2 last2)
|
||||
{
|
||||
if (no_case) {
|
||||
if (IgnoreCase == parser::ignore_case_t::yes) {
|
||||
auto it1 = no_case_iter(first1, last1);
|
||||
auto it2 = no_case_iter(first2, last2);
|
||||
auto const mismatch = detail::mismatch(
|
||||
@@ -2978,20 +2945,37 @@ namespace boost { namespace parser {
|
||||
inline constexpr struct omit_attr_t
|
||||
{
|
||||
static constexpr std::true_type recursive{};
|
||||
template<bool OmitAttr>
|
||||
constexpr auto operator()(parser_modifiers<OmitAttr> const &) const
|
||||
template<
|
||||
parser::omit_attr_t OmitAttr,
|
||||
parser::ignore_case_t IgnoreCase>
|
||||
constexpr auto
|
||||
operator()(parser_modifiers<OmitAttr, IgnoreCase> const &) const
|
||||
{
|
||||
return parser_modifiers<true>{};
|
||||
return parser_modifiers<parser::omit_attr_t::yes, IgnoreCase>{};
|
||||
}
|
||||
} omit_attr;
|
||||
|
||||
inline constexpr struct ignore_case_t
|
||||
{
|
||||
static constexpr std::true_type recursive{};
|
||||
template<
|
||||
parser::omit_attr_t OmitAttr,
|
||||
parser::ignore_case_t IgnoreCase>
|
||||
constexpr auto
|
||||
operator()(parser_modifiers<OmitAttr, IgnoreCase> const &) const
|
||||
{
|
||||
return parser_modifiers<OmitAttr, parser::ignore_case_t::yes>{};
|
||||
}
|
||||
} ignore_case;
|
||||
|
||||
template<typename Attribute, bool OmitAttr>
|
||||
using final_attribute_type_impl =
|
||||
std::conditional_t<OmitAttr, nope, Attribute>;
|
||||
|
||||
template<typename Attribute, typename ParserMods>
|
||||
using final_attribute_type =
|
||||
final_attribute_type_impl<Attribute, ParserMods::omit_attr>;
|
||||
using final_attribute_type = final_attribute_type_impl<
|
||||
Attribute,
|
||||
ParserMods::omit_attr == parser::omit_attr_t::yes>;
|
||||
}
|
||||
|
||||
#ifndef BOOST_PARSER_DOXYGEN
|
||||
@@ -3070,12 +3054,6 @@ namespace boost { namespace parser {
|
||||
return *context.globals_;
|
||||
}
|
||||
|
||||
template<typename Context>
|
||||
decltype(auto) _no_case(Context const & context)
|
||||
{
|
||||
return context.no_case_depth_;
|
||||
}
|
||||
|
||||
template<typename Context>
|
||||
decltype(auto) _error_handler(Context const & context)
|
||||
{
|
||||
@@ -5274,77 +5252,6 @@ namespace boost { namespace parser {
|
||||
[[no_unique_address]] ParserMods mods_;
|
||||
};
|
||||
|
||||
// TODO: -> mod
|
||||
template<typename Parser, typename ParserMods>
|
||||
struct no_case_parser
|
||||
{
|
||||
constexpr no_case_parser(Parser parser) : parser_(parser) {}
|
||||
constexpr no_case_parser(Parser parser, ParserMods mods) :
|
||||
parser_(parser), mods_(std::move(mods))
|
||||
{}
|
||||
|
||||
template<
|
||||
typename Iter,
|
||||
typename Sentinel,
|
||||
typename Context,
|
||||
typename SkipParser>
|
||||
auto call(
|
||||
Iter & first,
|
||||
Sentinel last,
|
||||
Context const & context_,
|
||||
SkipParser const & skip,
|
||||
detail::flags flags,
|
||||
bool & success) const
|
||||
{
|
||||
auto context = context_;
|
||||
++context.no_case_depth_;
|
||||
|
||||
using attr_t = decltype(parser_.call(
|
||||
first, last, context, skip, flags, success));
|
||||
detail::final_attribute_type<attr_t, ParserMods> retval{};
|
||||
call(first, last, context, skip, flags, success, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
template<
|
||||
typename Iter,
|
||||
typename Sentinel,
|
||||
typename Context,
|
||||
typename SkipParser,
|
||||
typename Attribute>
|
||||
void call(
|
||||
Iter & first,
|
||||
Sentinel last,
|
||||
Context const & context_,
|
||||
SkipParser const & skip,
|
||||
detail::flags flags,
|
||||
bool & success,
|
||||
Attribute & retval) const
|
||||
{
|
||||
auto context = context_;
|
||||
++context.no_case_depth_;
|
||||
|
||||
[[maybe_unused]] auto _ = detail::scoped_trace(
|
||||
*this, first, last, context, flags, retval);
|
||||
|
||||
parser_.call(first, last, context, skip, flags, success, retval);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
constexpr auto with_parser_mods(F f) const
|
||||
{
|
||||
if constexpr (f.recursive) {
|
||||
return parser::no_case_parser(
|
||||
parser_.with_parser_mods(f), f(mods_));
|
||||
} else {
|
||||
return parser::no_case_parser(parser_, f(mods_));
|
||||
}
|
||||
}
|
||||
|
||||
Parser parser_;
|
||||
[[no_unique_address]] ParserMods mods_;
|
||||
};
|
||||
|
||||
template<typename Parser, typename SkipParser, typename ParserMods>
|
||||
struct skip_parser
|
||||
{
|
||||
@@ -5558,31 +5465,70 @@ namespace boost { namespace parser {
|
||||
template<typename Context>
|
||||
void clear_for_next_parse(Context const & context);
|
||||
|
||||
#endif
|
||||
|
||||
/** Uses UTF-8 string `str` to look up an attribute in the table
|
||||
during parsing, returning it as an optional reference. The lookup
|
||||
is done on the copy of the symbol table inside the parse context
|
||||
`context`. */
|
||||
template<typename Context>
|
||||
parser::detail::text::optional_ref<T>
|
||||
find(Context const & context, std::string_view str) const;
|
||||
find(Context const & context, std::string_view str) const
|
||||
{
|
||||
auto [trie, has_case_folded] =
|
||||
detail::get_trie<ParserMods::ignore_case>(context, this->ref());
|
||||
if constexpr (
|
||||
ParserMods::ignore_case == parser::ignore_case_t::yes) {
|
||||
return trie[detail::case_fold_view(
|
||||
str | detail::text::as_utf32)];
|
||||
} else {
|
||||
return trie[str | detail::text::as_utf32];
|
||||
}
|
||||
}
|
||||
|
||||
/** Inserts an entry consisting of a UTF-8 string `str` to match, and
|
||||
an associtated attribute `x`, to the copy of the symbol table
|
||||
inside the parse context `context`. */
|
||||
template<typename Context>
|
||||
void insert(Context const & context, std::string_view str, T && x) const;
|
||||
void insert(Context const & context, std::string_view str, T && x) const
|
||||
{
|
||||
auto [trie, has_case_folded] =
|
||||
detail::get_trie<ParserMods::ignore_case>(context, this->ref());
|
||||
if constexpr (
|
||||
ParserMods::ignore_case == parser::ignore_case_t::yes) {
|
||||
trie.insert(
|
||||
detail::case_fold_view(str | detail::text::as_utf32),
|
||||
std::move(x));
|
||||
} else {
|
||||
trie.insert(str | detail::text::as_utf32, std::move(x));
|
||||
}
|
||||
}
|
||||
|
||||
/** Erases the entry whose UTF-8 match string is `str` from the copy
|
||||
of the symbol table inside the parse context `context`. */
|
||||
template<typename Context>
|
||||
void erase(Context const & context, std::string_view str) const;
|
||||
void erase(Context const & context, std::string_view str) const
|
||||
{
|
||||
auto [trie, has_case_folded] =
|
||||
detail::get_trie<ParserMods::ignore_case>(context, this->ref());
|
||||
if constexpr (
|
||||
ParserMods::ignore_case == parser::ignore_case_t::yes) {
|
||||
trie.erase(
|
||||
detail::case_fold_view(str | detail::text::as_utf32));
|
||||
} else {
|
||||
trie.erase(str | detail::text::as_utf32);
|
||||
}
|
||||
}
|
||||
|
||||
/** Erases the entry whose UTF-8 match string is `str` from the copy
|
||||
of the symbol table inside the parse context `context`. */
|
||||
template<typename Context>
|
||||
void clear(Context const & context) const;
|
||||
|
||||
#endif
|
||||
void clear(Context const & context) const
|
||||
{
|
||||
auto [trie, _] =
|
||||
detail::get_trie<ParserMods::ignore_case>(context, this->ref());
|
||||
trie.clear();
|
||||
}
|
||||
|
||||
template<
|
||||
typename Iter,
|
||||
@@ -5620,11 +5566,13 @@ namespace boost { namespace parser {
|
||||
[[maybe_unused]] auto _ = detail::scoped_trace(
|
||||
*this, first, last, context, flags, retval);
|
||||
|
||||
auto [trie, _0] = detail::get_trie(context, this->ref());
|
||||
auto const lookup = context.no_case_depth_
|
||||
? trie.longest_match(detail::case_fold_view(
|
||||
BOOST_PARSER_SUBRANGE(first, last)))
|
||||
: trie.longest_match(first, last);
|
||||
auto [trie, _0] =
|
||||
detail::get_trie<ParserMods::ignore_case>(context, this->ref());
|
||||
auto const lookup =
|
||||
ParserMods::ignore_case == parser::ignore_case_t::yes
|
||||
? trie.longest_match(detail::case_fold_view(
|
||||
BOOST_PARSER_SUBRANGE(first, last)))
|
||||
: trie.longest_match(first, last);
|
||||
if (lookup.match) {
|
||||
std::advance(first, lookup.size);
|
||||
if constexpr (detail::gen_attrs<ParserMods>())
|
||||
@@ -6735,10 +6683,22 @@ namespace boost { namespace parser {
|
||||
`parser_interface<P>`. */
|
||||
inline constexpr directive<lexeme_parser> lexeme;
|
||||
|
||||
/** The `no_case` directive, whose `operator[]` returns a
|
||||
`parser_interface<no_case_parser<P>>` from a given parser of type
|
||||
`parser_interface<P>`. */
|
||||
inline constexpr directive<no_case_parser> no_case;
|
||||
/** Transforms the attribute type of the given parser to `none`, as in
|
||||
(e.g. `no_case[other_parser]`). */
|
||||
struct no_case_directive
|
||||
{
|
||||
template<typename Parser>
|
||||
constexpr auto operator[](parser_interface<Parser> rhs) const noexcept
|
||||
{
|
||||
return parser_interface{
|
||||
rhs.parser_.with_parser_mods(detail::ignore_case)};
|
||||
}
|
||||
};
|
||||
|
||||
/** The global `no_case_directive` object, whose `operator[]` returns a
|
||||
new `parser_interface<P>` that ignores case, from a given parser of
|
||||
type `parser_interface<P>`. */
|
||||
inline constexpr no_case_directive no_case;
|
||||
|
||||
/** Represents a `repeat_parser` as a directive
|
||||
(e.g. `repeat[other_parser]`). */
|
||||
@@ -7209,11 +7169,12 @@ namespace boost { namespace parser {
|
||||
return;
|
||||
}
|
||||
char_type<decltype(*first)> const x = *first;
|
||||
if (detail::unequal(context, x, expected_)) {
|
||||
if (detail::unequal<ParserMods::ignore_case>(
|
||||
context, x, expected_)) {
|
||||
success = false;
|
||||
return;
|
||||
}
|
||||
if constexpr (!ParserMods::omit_attr)
|
||||
if constexpr (detail::gen_attrs<ParserMods>())
|
||||
detail::assign(retval, x);
|
||||
++first;
|
||||
}
|
||||
@@ -7710,24 +7671,30 @@ namespace boost { namespace parser {
|
||||
/** Returns a literal code point parser that produces no attribute. */
|
||||
inline constexpr auto lit(char c) noexcept
|
||||
{
|
||||
return parser_interface<
|
||||
char_parser<detail::nope, void, parser_modifiers<true>>>{}(c);
|
||||
return parser_interface<char_parser<
|
||||
detail::nope,
|
||||
void,
|
||||
parser_modifiers<omit_attr_t::yes>>>{}(c);
|
||||
}
|
||||
|
||||
#if defined(__cpp_char8_t) || defined(BOOST_PARSER_DOXYGEN)
|
||||
/** Returns a literal code point parser that produces no attribute. */
|
||||
inline constexpr auto lit(char8_t c) noexcept
|
||||
{
|
||||
return parser_interface<
|
||||
char_parser<detail::nope, void, parser_modifiers<true>>>{}(c);
|
||||
return parser_interface<char_parser<
|
||||
detail::nope,
|
||||
void,
|
||||
parser_modifiers<omit_attr_t::yes>>>{}(c);
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Returns a literal code point parser that produces no attribute. */
|
||||
inline constexpr auto lit(char32_t c) noexcept
|
||||
{
|
||||
return parser_interface<
|
||||
char_parser<detail::nope, void, parser_modifiers<true>>>{}(c);
|
||||
return parser_interface<char_parser<
|
||||
detail::nope,
|
||||
void,
|
||||
parser_modifiers<omit_attr_t::yes>>>{}(c);
|
||||
}
|
||||
|
||||
#ifndef BOOST_PARSER_DOXYGEN
|
||||
@@ -7805,12 +7772,9 @@ namespace boost { namespace parser {
|
||||
BOOST_PARSER_SUBRANGE(expected_first_, expected_last_) |
|
||||
detail::text::as_utf32;
|
||||
|
||||
auto const mismatch = detail::no_case_aware_string_mismatch(
|
||||
first,
|
||||
last,
|
||||
cps.begin(),
|
||||
cps.end(),
|
||||
context.no_case_depth_);
|
||||
auto const mismatch = detail::no_case_aware_string_mismatch<
|
||||
ParserMods::ignore_case>(
|
||||
first, last, cps.begin(), cps.end());
|
||||
if (mismatch.second != cps.end()) {
|
||||
success = false;
|
||||
return;
|
||||
@@ -7821,12 +7785,9 @@ namespace boost { namespace parser {
|
||||
|
||||
first = mismatch.first;
|
||||
} else {
|
||||
auto const mismatch = detail::no_case_aware_string_mismatch(
|
||||
first,
|
||||
last,
|
||||
expected_first_,
|
||||
expected_last_,
|
||||
context.no_case_depth_);
|
||||
auto const mismatch = detail::no_case_aware_string_mismatch<
|
||||
ParserMods::ignore_case>(
|
||||
first, last, expected_first_, expected_last_);
|
||||
if (mismatch.second != expected_last_) {
|
||||
success = false;
|
||||
return;
|
||||
@@ -8414,12 +8375,14 @@ namespace boost { namespace parser {
|
||||
[[maybe_unused]] auto _ = detail::scoped_trace(
|
||||
*this, first, last, context, flags, retval);
|
||||
|
||||
auto compare =
|
||||
[no_case = context.no_case_depth_](char32_t a, char32_t b) {
|
||||
if (no_case && 0x41 <= b && b < 0x5b)
|
||||
auto compare = [](char32_t a, char32_t b) {
|
||||
if constexpr (
|
||||
ParserMods::ignore_case == parser::ignore_case_t::yes) {
|
||||
if (0x41 <= b && b < 0x5b)
|
||||
b += 0x20;
|
||||
return a == b;
|
||||
};
|
||||
}
|
||||
return a == b;
|
||||
};
|
||||
|
||||
// The lambda quiets a signed/unsigned mismatch warning when
|
||||
// comparing the chars here to code points.
|
||||
|
||||
@@ -68,10 +68,16 @@ namespace boost { namespace parser {
|
||||
return BOOST_PARSER_SUBRANGE(ptr, detail::text::null_sentinel);
|
||||
}
|
||||
|
||||
template<bool OmitAttr = false>
|
||||
enum struct omit_attr_t { no, yes };
|
||||
enum struct ignore_case_t { no, yes };
|
||||
|
||||
template<
|
||||
omit_attr_t OmitAttr = omit_attr_t::no,
|
||||
ignore_case_t IgnoreCase = ignore_case_t::no>
|
||||
struct parser_modifiers
|
||||
{
|
||||
static constexpr bool omit_attr = OmitAttr;
|
||||
static constexpr omit_attr_t omit_attr = OmitAttr;
|
||||
static constexpr ignore_case_t ignore_case = IgnoreCase;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
@@ -273,13 +279,6 @@ namespace boost { namespace parser {
|
||||
template<typename Parser, typename ParserMods>
|
||||
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 ParserMods>
|
||||
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
|
||||
|
||||
@@ -39,7 +39,7 @@ constexpr auto double_s = u8"sS"; // U+0073 U+0073
|
||||
|
||||
// basic)
|
||||
{
|
||||
constexpr auto char_p = no_case[char_('a') | char_('B')];
|
||||
auto char_p = no_case[char_('a') | char_('B')];
|
||||
|
||||
{
|
||||
auto const result = parse("a", char_p);
|
||||
@@ -461,12 +461,12 @@ constexpr auto double_s = u8"sS"; // U+0073 U+0073
|
||||
{
|
||||
constexpr auto mixed_sharp_s1 = U"ẞs";
|
||||
constexpr auto mixed_sharp_s2 = U"sẞ";
|
||||
auto const result = detail::no_case_aware_string_mismatch(
|
||||
mixed_sharp_s1,
|
||||
detail::text::null_sentinel,
|
||||
mixed_sharp_s2,
|
||||
detail::text::null_sentinel,
|
||||
true);
|
||||
auto const result =
|
||||
detail::no_case_aware_string_mismatch<ignore_case_t::yes>(
|
||||
mixed_sharp_s1,
|
||||
detail::text::null_sentinel,
|
||||
mixed_sharp_s2,
|
||||
detail::text::null_sentinel);
|
||||
BOOST_TEST(result.first == detail::text::null_sentinel);
|
||||
BOOST_TEST(result.second == detail::text::null_sentinel);
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ int main()
|
||||
|
||||
std::cout << "\n\n"
|
||||
<< "----------------------------------------\n"
|
||||
<< "| transform)f_[] |\n"
|
||||
<< "| transform(f)[] |\n"
|
||||
<< "----------------------------------------\n";
|
||||
|
||||
auto f = [](auto x) { return x; };
|
||||
@@ -190,6 +190,15 @@ int main()
|
||||
PARSE(skip[char_]);
|
||||
PARSE(skip(ws)[char_]);
|
||||
|
||||
std::cout << "\n\n"
|
||||
<< "----------------------------------------\n"
|
||||
<< "| no_case[] |\n"
|
||||
<< "----------------------------------------\n";
|
||||
|
||||
PARSE(no_case[char_]);
|
||||
PARSE(no_case[no_case[char_]]);
|
||||
PARSE(no_case[*no_case[char_]]);
|
||||
|
||||
std::cout << "\n\n"
|
||||
<< "----------------------------------------\n"
|
||||
<< "| merge[] |\n"
|
||||
|
||||
Reference in New Issue
Block a user