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 or creates context variables that persist between loop iterations.

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