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()
.After error recovery, it only produces the values by
terminator()
.
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.After error recovery, it only produces the values by
terminator()
.
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()
. After error recovery, it only produces the values byterminator()
.
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()
. After error recovery, it only produces the values 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. |