Header lexy/dsl/loop.hpp

Rules that loop.

Rule lexy::dsl::loop

lexy/dsl/loop.hpp
namespace lexy::dsl
{
    constexpr rule auto loop(rule auto rule);
}

loop is a rule that matches rule repeatedly.

Requires

rule does not produce any values.

Parsing

Parses rule repeatedly until it either fails or break_ is parsed.

Errors

All errors raised by rule. It then fails if rule has failed.

Values

None.

Example 1. Repeatedly match a choice
constexpr auto id          = dsl::identifier(dsl::ascii::alpha);
constexpr auto kw_function = LEXY_KEYWORD("function", id);
constexpr auto kw_type     = LEXY_KEYWORD("type", id);

struct function_decl
{
    static constexpr auto rule = [] {
        auto arguments = dsl::parenthesized(LEXY_LIT("..."));
        auto body      = dsl::curly_bracketed(LEXY_LIT("..."));

        return kw_function >> id + arguments + body;
    }();
};

struct type_decl
{
    static constexpr auto rule //
        = kw_type >> id + dsl::lit_c<'='> + id + dsl::semicolon;
};

struct production
{
    static constexpr auto whitespace = dsl::ascii::space;
    static constexpr auto rule
        // Note: a real implementation couldn't use loop().
        // If the decls produce values, list() has to be used instead.
        = dsl::loop(dsl::p<function_decl> | dsl::p<type_decl> | dsl::break_);
};
Tip
Use lexy::dsl::while_  if there is a simple exit condition, lexy::dsl::list  if the rule should produce values.
Warning
You must not use lexy::dsl::return_  to exit from a loop.

Branch rule lexy::dsl::break_

lexy/dsl/loop.hpp
namespace lexy::dsl
{
    constexpr branch-rule auto break_;
}

break_ is a rule that exits from a loop.

Requires

It is used inside a loop rule.

(Branch) Parsing

Matches everything without consuming anything. Exits the loop.

Errors

None.

Values

None.

Rule lexy::dsl::while_

lexy/dsl/loop.hpp
namespace lexy::dsl
{
    constexpr rule auto while_(branch-rule auto rule)
    {
        return loop(rule | break_);
    }
}

while_ is a rule that parses the branch rule rule as often as possible.

It is entirely equivalent to loop(rule | break_). It can only fail, if rule can fail after it decided to select the branch. It can accept the empty string if rule backtracks on the first iteration.

Example 2. Parse a word, which can be empty
struct production
{
    static constexpr auto rule = dsl::while_(dsl::ascii::alpha);
};
Tip
Use lexy::dsl::opt  and lexy::dsl::list  if rule produces values.
Warning
If rule does not consume any characters, while_ will loop forever.
Caution
If whitespace  skipping is enabled, while_ will skip whitespace after every token of rule.

Rule lexy::dsl::while_one

lexy/dsl/loop.hpp
namespace lexy::dsl
{
    constexpr branch-rule auto while_one(branch-rule auto rule)
    {
        return rule >> while_(rule);
    }
}

while_one is a rule that parses rule repeatedly, but at least once.

It is entirely equivalent to rule >> while_(rule).

Example 3. Parse a word, which cannot be empty
struct production
{
    static constexpr auto rule = dsl::while_one(dsl::ascii::alpha);
};
Tip
Use lexy::dsl::list  if rule produces values.
Caution
If whitespace  skipping is enabled, while_one will skip whitespace after every token of rule. Consider lexy::dsl::identifier , which does not do that.

Rule lexy::dsl::do_while

lexy/dsl/loop.hpp
namespace lexy::dsl
{
    constexpr rule auto do_while(rule auto then, branch-rule auto condition)
    {
        return then + while_(condition >> then);
    }

    constexpr branch-rule auto do_while(branch-rule auto then,
                                        branch-rule auto condition)
    {
        return then >> while_(condition >> then);
    }
}

do_while is a rule that parses then while condition matches, but checks condition after then.

It is entirely equivalent to then + while_(condition >> then) if then is not a branch, and then >> while_(condition >> then) otherwise.

Example 4. Parse a list of non-empty words separated by spaces
struct production
{
    static constexpr auto rule = [] {
        auto word = dsl::while_one(dsl::ascii::alpha);
        return dsl::do_while(word, dsl::ascii::space);
    }();
};
Tip
Use lexy::dsl::list  if then produces values with condition as separator.

See also