Header lexy/dsl/terminator.hpp
Rule DSL lexy::dsl::terminator
lexy/dsl/terminator.hpp
namespace lexy::dsl
{
struct terminator-dsl // note: not a rule itself
{
constexpr _branch-rule auto terminator() const;
constexpr terminator-dsl limit(auto ... limit);
constexpr rule auto recovery_rule() const;
//=== rules ===//
constexpr rule auto operator()(rule auto rule) const;
constexpr rule auto try_(rule auto rule) const;
constexpr rule auto opt(rule auto rule) const;
constexpr rule auto list(rule auto item) const;
constexpr rule auto list(rule auto item, separator auto sep) const;
constexpr rule auto opt_list(rule auto item) const;
constexpr rule auto opt_list(rule auto item, separator auto sep) const;
};
constexpr terminator-dsl terminator(branch-rule auto branch);
}
terminator
is not a rule, but a DSL for specifying rules that all parse something followed by a terminator.
Many rules require a branch rule as argument, like lexy::dsl::list
.
However, there isn’t always an easy way to check for a branch condition and sometimes the rule in question is always terminated by a given token (e.g. a semicolon).
Then you can use terminator
:
it specifies a branch rule as the terminator and provides ways of building rules where any branch condition is just "the terminator hasn’t been matched yet".
As such, you don’t need to provide a branch condition anymore.
Note | See lexy::dsl::brackets if you want to parse something that has not only a terminator but some prefix as well. |
Branch rule .terminator()
lexy/dsl/terminator.hpp
constexpr branch-rule auto terminator() const;
.terminator()
returns the rule that was passed to the top-level lexy::dsl::terminator()
.
.limit()
lexy/dsl/terminator.hpp
constexpr terminator-dsl limit(auto ... limit);
Provide a limit for error recovery.
terminator
can also do error recovery after an error by discarding input until the terminator is reached.
Similar to lexy::dsl::find
or lexy::dsl::recover
one can provide a limit, which is a literal rule or lexy::dsl::literal_set
.
If the limit is reached before the terminator, error recovery fails.
struct statement
{
static constexpr auto rule = [] {
// A statement is terminated by a semicolon.
// Error recovery fails when we've reached the } of the scope.
auto terminator = dsl::terminator(dsl::semicolon).limit(dsl::lit_c<'}'>);
return terminator.opt(LEXY_LIT("foo()") | LEXY_LIT("bar()"));
}();
};
struct production
{
static constexpr auto whitespace = dsl::ascii::space;
// Just a list of statements surrounded by {}.
static constexpr auto rule = dsl::curly_bracketed.list(dsl::p<statement>);
};
.recovery_rule()
lexy/dsl/terminator.hpp
constexpr rule auto recovery_rule() const;
.recovery_rule()
returns the rule that is used for the simple error recovery.
It is equivalent to lexy::dsl::recover
(terminator()).limit(tokens…)
,
where tokens
are all the tokens passed to every .limit()
call.
This simply discards input until it can match terminator()
.
Recovery fails when it reaches EOF or one of the limits, if any have been specified.
Rule .operator()
lexy/dsl/terminator.hpp
constexpr rule auto operator()(rule auto rule) const
{
return rule + terminator();
}
constexpr branch-rule auto operator()(branch-rule auto rule) const
{
return rule >> terminator();
}
.operator()
returns a rule that parses rule
, then parses the terminator.
It behaves entirely equivalent to rule + terminator()
.
Rule .try_()
lexy/dsl/terminator.hpp
constexpr rule auto try_(rule auto rule) const;
.try_()
returns a rule that parses rule
, then parses the terminator, but recovers on failure.
- Parsing
Parses
rule
andterminator()
insequence
.- Errors
All errors raised by
rule
andterminator()
. It can recover from a failedrule
by parsingrecovery_rule()
. It does not recover from a failedterminator()
.- Values
All values produced by
rule
followed by all values produced byterminator()
.
Rule .opt()
lexy/dsl/terminator.hpp
constexpr rule auto opt(rule auto rule) const;
.opt()
returns a rule that parses rule
if it is there, then parses the terminator.
- Parsing
Tries to parse
terminator()
and succeeds if that is the case. Otherwise, parsesrule
andterminator()
insequence
.- Errors
All errors raised by (branch) parsing of
terminator()
and parsing ofrule
. It can recover from a failedrule
by parsingrecovery_rule()
. It does not recover from a failedterminator()
.- Values
An object of type
lexy::nullopt
followed by all values produced byterminator()
in the first case.All values produced by
rule
followed by all values produced byterminator()
in the second case.
Note | .opt(rule) consumes the same input as lexy::dsl::opt ( lexy::dsl::peek_not (terminator()) >> rule ) + terminator() , but more efficiently. |
Rule .list()
lexy/dsl/terminator.hpp
constexpr rule auto list(rule auto item) const;
constexpr rule auto list(rule auto item, separator auto sep) const;
.list()
returns a rule that parses a non-empty list of item
, optionally separated by sep
, followed by the terminator.
- Parsing
It first parses
item
once, recovers if necessary. Then it enters the main loop of parsing the rest of the list.It first tries to parse
terminator()
. If that succeeds, finishes parsing. Otherwise, it continues with step 2.If no
separator
was specified, immediately continues with step 4. Otherwise, tries to parsesep
. On success, it continues with step 3. If the separator was missing, immediately recovers by going to step 4. Otherwise, recovers as described below.Tries to parse
terminator()
again. On success, handles a trailing separator by raising an error if necessary. It then immediately recovers and succeeds.Parses
item
. On success, repeats everything by going back to step 1. Otherwise, recovers as described below.
- Errors
All errors raised by branch parsing of
terminator()
. The rule then fails ifterminator()
has failed and never tries to recover.lexy::unexpected_trailing_separator
: if a trailing separator was parsed but is not allowed; at the position of the trailing separator. It then recovers without consuming additional input.All errors raised by branch parsing of
sep
and parsingitem
. It then recovers by discarding input until it either matchessep
, ifsep
was specified, or until it reachesitem
, if nosep
was specified. The latter is only possible ifitem
is a branch rule. Ifsep
/item
was matched, continues in the appropriate step from the parsing algorithm. If recovery reachesterminator()
, parses it and finishes. If recovery reaches the end of the input, or a limit, if one was specified, recovery fails.
- Values
It creates a sink of the current context. All items produced by
item
andsep
are forwarded to it; there are separate calls for every iteration and foritem
andsep
. The value of the finished sink is then produced followed by all values ofterminator()
.
Note | .list(rule, sep) consumes the same input as lexy::dsl::list ( lexy::dsl::peek_not (terminator()) >> rule, sep ) + terminator() , but more efficiently. |
Rule .opt_list()
lexy/dsl/terminator.hpp
constexpr rule auto opt_list(rule auto item) const;
constexpr rule auto opt_list(rule auto item, separator auto sep) const;
.opt_list()
returns a rule that parses a (possibly empty) list of item
, optionally separated by sep
, followed by the terminator.
- Parsing
Tries to parse
terminator()
and succeeds if that is the case. Otherwise, it parses the corresponding.list()
rule.- Errors
All errors raised by branch parsing of
terminator()
or parsing of.list()
. It never recovers from the terminator, and recovers from.list()
as described there.- Values
The first argument is:
a
lexy::nullopt
object in the first case,The result of the
.list()
rule in the second case. It is then followed by all values produced byterminator()
.
Note | This is different from term.opt(term.list(r)) as that would parse the terminator twice: once by .list() and once by .opt() .
Apart from that, it behaves identically. |