2
0
mirror of https://github.com/boostorg/parser.git synced 2026-01-24 18:12:32 +00:00

7 Commits

Author SHA1 Message Date
Zach Laine
88abb615aa Add pre_- and post_parser members to parser_modifiers; these are used as
look-ahead/-behind positive or negative assertions.

When combining parsers using op>> and op>, if either side is an expect_parser
and the other side has an open pre_-/post_parser slot, take the subparser out
of the expect_parser, and use it directly in the pre_-/post_parser slot.

See #160.
2024-12-16 19:24:39 -06:00
Zach Laine
54f8eecfe6 Change the no_case[] directive to use the parser_modifiers struct, like omit[]
does; remove no_case_parser.

See #160.
2024-12-16 19:24:39 -06:00
Zach Laine
fcd257abca Generalize with_parser_mods(), so that some functions can be recursive, and
others can be non-recursive.

See #160.
2024-12-16 19:24:39 -06:00
Zach Laine
2f7e5964a6 Apply the same sort of change as the previous two commits, but to all the
parsers not already modified.  Generalize with_parser_mods().  Remove
omit_parser, since it is now moot.

See #160.
2024-12-16 19:24:39 -06:00
Zach Laine
2fff00b3e1 Change string_parser to support the use of parser_modifiers, and change lit()
to return a parameterized string_parser instead of string_parser wrapped in an
omit_parser.

See #160.
2024-12-16 19:24:39 -06:00
Zach Laine
28e9b61735 Add a new template, parser_modifiers, that will hold common modifications to
parsers, like turning off attribute generation (replacing omit_parser).
Change char_parser to support the use of parser_modifiers, and change lit() to
return a parameterized char_parser instead of char_parser wrapped in an
omit_parser.

See #160.
2024-12-16 19:24:39 -06:00
Zach Laine
354586dd76 Github runner macos-12 -> macos-13. 2024-12-16 19:24:39 -06:00
7 changed files with 1264 additions and 484 deletions

View File

@@ -1,4 +1,4 @@
name: macos-12 - Clang 14
name: macos-13 - Clang 14
on:
push:
@@ -16,7 +16,7 @@ jobs:
matrix:
cxx_std: [17]
runs-on: macos-12
runs-on: macos-13
steps:
- uses: actions/checkout@v4

View File

@@ -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,
@@ -164,11 +157,11 @@ namespace boost { namespace parser { namespace detail {
template<
typename Context,
typename Parser,
bool FailOnMatch,
expect_match_t ExpectMatch,
typename ParserMods>
void print_parser_impl(
Context const & context,
expect_parser<Parser, FailOnMatch, ParserMods> const & parser,
expect_parser<Parser, ExpectMatch, ParserMods> const & parser,
std::ostream & os,
int components);
@@ -387,7 +380,7 @@ namespace boost { namespace parser { namespace detail {
std::ostream & os,
int components);
template<typename Context, typename Parser>
template<bool SuppressOmit = false, typename Context, typename Parser>
void print_parser(
Context const & context,
Parser const & parser,

View File

@@ -273,7 +273,7 @@ namespace boost { namespace parser { namespace detail {
os << (backtrack ? " >> " : " > ");
if (group != prev_group && group)
os << (group == -1 ? "separate[" : "merge[");
detail::print_parser_impl(context, parser, os, components);
detail::print_parser(context, parser, os, components);
++components;
++i;
prev_group = (int)group;
@@ -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,
@@ -396,18 +385,18 @@ namespace boost { namespace parser { namespace detail {
template<
typename Context,
typename Parser,
bool FailOnMatch,
expect_match_t ExpectMatch,
typename ParserMods>
void print_parser_impl(
Context const & context,
expect_parser<Parser, FailOnMatch, ParserMods> const & parser,
expect_parser<Parser, ExpectMatch, ParserMods> const & parser,
std::ostream & os,
int components)
{
if (FailOnMatch)
os << "!";
else
if constexpr (ExpectMatch == expect_match_t::yes)
os << "&";
else
os << "!";
constexpr bool n_ary_child = n_aray_parser_v<Parser>;
if (n_ary_child)
os << "(";
@@ -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 << ")";
}
}
@@ -946,64 +935,120 @@ namespace boost { namespace parser { namespace detail {
context, parser.or_parser_, os, components);
}
template<typename ParserMods>
template<typename Context, typename Parser>
struct scoped_print_parser_mods
{
template<typename Parser>
scoped_print_parser_mods(std::ostream & os, Parser const & parser) :
os_(os), mods_(parser.mods_)
using parser_mods = decltype(std::declval<Parser>().mods_);
scoped_print_parser_mods(
Context const & context,
Parser const & parser,
std::ostream & os,
int & components,
bool suppress_omit) :
context_(context),
parser_(parser),
os_(os),
components_(components),
skip_omit_(suppress_omit)
{
if constexpr (ParserMods::omit_attr) {
skip_omit_ = skip_omit(parser);
if (!skip_omit_)
if constexpr (parser_mods::omit_attr == parser::omit_attr_t::yes) {
if (!skip_omit_ && !skip_omit(parser_))
os_ << "omit[";
}
if constexpr (
parser_mods::ignore_case == parser::ignore_case_t::yes) {
os_ << "no_case[";
}
if constexpr (!is_nope_v<typename parser_mods::pre_parser_type>) {
print_expected_operator<
typename parser_mods::pre_parser_type>();
detail::print_parser<true>(
context_,
parser_.mods_.pre_parser.parser,
os_,
components_);
os_ << " >> ";
}
}
~scoped_print_parser_mods()
{
if constexpr (ParserMods::omit_attr) {
if (!skip_omit_)
if constexpr (!is_nope_v<typename parser_mods::post_parser_type>) {
os_ << " >> ";
print_expected_operator<
typename parser_mods::post_parser_type>();
detail::print_parser<true>(
context_,
parser_.mods_.post_parser.parser,
os_,
components_);
}
if constexpr (
parser_mods::ignore_case == parser::ignore_case_t::yes) {
os_ << "]";
}
if constexpr (parser_mods::omit_attr == parser::omit_attr_t::yes) {
if (!skip_omit_ && !skip_omit(parser_))
os_ << "]";
}
}
template<typename ExpectedParser>
void print_expected_operator()
{
if constexpr (ExpectedParser::expect_match == expect_match_t::yes) {
os_ << "&";
} else {
os_ << "!";
}
}
template<typename T>
static bool skip_omit(T const &)
{
return false;
}
template<
typename Expected,
typename AttributeType,
typename ParserMods2>
template<typename Expected, typename AttributeType, typename ParserMods>
static bool
skip_omit(char_parser<Expected, AttributeType, ParserMods2> const &)
skip_omit(char_parser<Expected, AttributeType, ParserMods> const &)
{
return !std::is_same_v<Expected, detail::nope>;
}
template<typename StrIter, typename StrSentinel, typename ParserMods2>
template<typename StrIter, typename StrSentinel, typename ParserMods>
static bool
skip_omit(string_parser<StrIter, StrSentinel, ParserMods2> const &)
skip_omit(string_parser<StrIter, StrSentinel, ParserMods> const &)
{
return true;
}
template<
typename Parser2,
expect_match_t ExpectMatch,
typename ParserMods>
static bool
skip_omit(expect_parser<Parser2, ExpectMatch, ParserMods> const &)
{
return true;
}
Context const & context_;
Parser const & parser_;
std::ostream & os_;
ParserMods const & mods_;
bool skip_omit_ = false;
int & components_;
bool skip_omit_;
};
// TODO: Document how 'omit[]' will reappear for subparsers sometimes, as
// in omt[*omit[char_]] (see test/tracing.cpp).
template<typename Context, typename Parser>
// 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<bool SuppressOmit, typename Context, typename Parser>
void print_parser(
Context const & context,
Parser const & parser,
std::ostream & os,
int components)
{
scoped_print_parser_mods<std::decay_t<decltype(parser.mods_)>> _(
os, parser);
scoped_print_parser_mods _(
context, parser, os, components, SuppressOmit);
detail::print_parser_impl(context, parser, os, components);
}

File diff suppressed because it is too large Load Diff

View File

@@ -149,14 +149,33 @@ namespace boost { namespace parser {
{};
}
template<bool OmitAttr = false, typename Action = detail::nope>
enum struct omit_attr_t { no, yes };
enum struct ignore_case_t { no, yes };
enum struct expect_match_t { no, yes };
template<typename Parser, expect_match_t ExpectMatch>
struct expected_parser
{
static constexpr expect_match_t expect_match = ExpectMatch;
Parser parser;
};
template<
omit_attr_t OmitAttr = omit_attr_t::no,
ignore_case_t IgnoreCase = ignore_case_t::no,
typename PreParser = detail::nope,
typename PostParser = detail::nope>
struct parser_modifiers
{
using action_type = Action;
using pre_parser_type = PreParser;
using post_parser_type = PostParser;
static constexpr bool omit_attr = OmitAttr;
static constexpr omit_attr_t omit_attr = OmitAttr;
static constexpr ignore_case_t ignore_case = IgnoreCase;
[[no_unique_address]] Action action;
[[no_unique_address]] PreParser pre_parser;
[[no_unique_address]] PostParser post_parser;
};
/** Repeats the application of another parser `p` of type `Parser`,
@@ -277,13 +296,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
@@ -295,9 +307,9 @@ namespace boost { namespace parser {
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, typename ParserMods>
and consuming no input. The parse succeeds iff `p`'s success is equal
to `ExpectMatch == expect_match_t::yes`. */
template<typename Parser, expect_match_t ExpectMatch, typename ParserMods>
struct expect_parser;
/** Matches one of a set S of possible inputs, each of which is associated

View File

@@ -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);
}

View File

@@ -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"
@@ -220,6 +229,16 @@ int main()
PARSE(!char_);
PARSE(!(*char_ >> char_));
PARSE(!char_ >> char_);
PARSE(*char_ >> !char_);
PARSE(!char_ >> *char_ >> char_ >> !char_);
try {
PARSE((!char_) > char_);
} catch (...) {
}
PARSE(*char_ > !char_);
PARSE((!char_) > *char_ >> char_ > !char_);
std::cout << "\n\n"
<< "----------------------------------------\n"
<< "| operator& |\n"
@@ -228,6 +247,16 @@ int main()
PARSE(&char_);
PARSE(&(*char_ >> char_));
PARSE(&char_ >> char_);
PARSE(*char_ >> &char_);
PARSE(&char_ >> *char_ >> char_ >> &char_);
try {
PARSE(&char_ > char_);
} catch (...) {
}
PARSE(*char_ > &char_);
PARSE(&char_ >>*char_ >> char_ > &char_);
std::cout << "\n\n"
<< "----------------------------------------\n"
<< "| symbols<T> |\n"