Header lexy/dsl/choice.hpp

Rule lexy::dsl::operator|

lexy/dsl/choice.hpp
namespace lexy
{
    struct exhausted_choice {};
}

namespace lexy::dsl
{
    struct choice {}; // models rule, and sometimes branch-rule

    constexpr choice operator|(branch-rule auto lhs, branch-rule auto rhs);

    constexpr choice operator|(choice lhs, branch-rule auto rhs);
    constexpr choice operator|(branch-rule auto lhs, choice rhs);
    constexpr choice operator|(choice lhs, choice rhs);
}

operator| (choice) is a rule that parses one of the specified branch rules.

Parsing

Tries to parse lhs, then tries to parse rhs.

Branch parsing

It is a branch rule if neither lhs nor rhs are unconditional branches (e.g. lexy::dsl::else_). Tries to parse lhs, then tries to parse rhs. Backtracks instead of failing for an exhausted choice.

Errors
  • lexy::exhausted_choice: if neither lhs nor rhs could be parsed, at the starting reader position. The rule then fails.

  • All errors raised by lhs or rhs during branch parsing. The rule then fails if they have failed.

Values

All values produced by the selected branch.

operator| can be chained: a | (b | c) is equivalent to a | lexy::dsl::else_ >> (b | c), and likewise for the other cases.

Example 1. Parse a greeting
struct production
{
    static constexpr auto rule = LEXY_LIT("Hello") | LEXY_LIT("Hi");
};
Example 2. Raise a different error if no greeting matches
struct production
{
    struct unknown_greeting
    {
        static constexpr auto name = "unknown greeting";
    };

    static constexpr auto rule
        // Generate a custom error for an unknown greeting.
        = LEXY_LIT("Hello") | LEXY_LIT("Hi") | dsl::error<unknown_greeting>;
};
Example 3. Do something differently if no greeting matches
struct production
{
    static constexpr auto rule
        // Input should be empty if greeting isn't known.
        = LEXY_LIT("Hello") | LEXY_LIT("Hi") | dsl::else_ >> dsl::eof;
};
Example 4. Branches can be arbitrarily complex
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       = dsl::p<function_decl> | dsl::p<type_decl>;
};
Example 5. Only the branch condition is checked
struct production
{
    static constexpr auto rule = LEXY_LIT("a") >> LEXY_LIT("bc")  // a, then bc
                                 | LEXY_LIT("a") >> LEXY_LIT("b") // a, then b
                                 | LEXY_LIT("bc") | LEXY_LIT("b");
};
Tip
Use lexy::dsl::operator>> to turn a rule into a branch by giving it a condition. Use lexy::dsl::peek or lexy::dsl::lookahead as conditions if there is no simple token rule to check the beginning of the branch.
Warning
Unlike alternative, order of branches in a choice matters.
Note
If one of the branches is always taken (e.g. because it uses lexy::dsl::else_), the lexy::exhausted_choice error is never raised.

See also