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.
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