Header lexy/dsl/operator.hpp

Define operators of an expression .

Branch rule lexy::dsl::op

lexy/dsl/operator.hpp
namespace lexy
{
    template <auto OperatorRule>
    using op = see-below;
}

namespace lexy::dsl
{
    constexpr operator-rule auto op(branch-rule auto r); (1)

    template <typename Tag>
    constexpr operator-rule auto op(branch-rule auto r); (2)

    template <auto Tag>
    constexpr operator-rule auto op(branch-rule auto r); (3)
}

op is a branch rule that parses an operator.

Requires

r is either a literal rule or a branch  whose condition is a literal rule.

(Branch) parsing

Parses r.

Errors

All errors raised by (branch) parsing r.

Values

A single value describing the operator that was just parsed (the tag), followed by all values produced by r. The type of the tag value is given by lexy::op, it is:

  • For overload 1, a unique type computed from the rule r.

  • For overload 2 and Tag != void, an object of the specified Tag type. If Tag is constructible from the iterator type of the input, it constructs it giving it the start position of the operator. Similarly, it is also possible to construct the Tag from the parse state and the iterator. Otherwise, it uses the default constructor.

  • For overload 2 and Tag == void, no tag value is produced.

  • For overload 3, an object of implementation-defined type that is implicitly convertible to the type of Tag, returning that value.

Example 1. By default, operators produce a unique tag type
struct production : lexy::expression_production
{
    static constexpr auto atom = dsl::integer<int>;

    struct operation : dsl::infix_op_left
    {
        static constexpr auto op = dsl::op(dsl::lit_c<'+'>);
        using operand            = dsl::atom;
    };

    static constexpr auto value
        = lexy::callback<int>([](int value) { return value; },
                              [](int lhs, lexy::op<operation::op>, int rhs) { return lhs + rhs; });
};
Example 2. Operator with custom type to get position information
struct plus
{
    const LEXY_CHAR8_T* pos;

    constexpr plus(const LEXY_CHAR8_T* pos) : pos(pos) {}
};

struct production : lexy::expression_production
{
    static constexpr auto atom = dsl::integer<int>;

    struct operation : dsl::infix_op_left
    {
        static constexpr auto op = dsl::op<plus>(dsl::lit_c<'+'>);
        using operand            = dsl::atom;
    };

    static constexpr auto value = lexy::callback<int>([](int value) { return value; },
                                                      [](int lhs, plus op, int rhs) {
                                                          LEXY_PRECONDITION(*op.pos == '+');
                                                          return lhs + rhs;
                                                      });
};
Tip
Use a branch rule as operators to parse a ternary operator, as seen in calculator.cpp .

Branch rule lexy::dsl::operator/ (operator)

lexy/dsl/operator.hpp
namespace lexy::dsl
{
    constexpr operator-rule auto operator/(operator-rule auto lhs,
                                           operator-rule auto rhs);
}

operator/ is a branch rule that parses one of multiple operators.

Branch parsing

Let lset be the lexy::dsl::literal_set  created by collecting all initial literal rules of lhs and rhs, possibly recursively if they themselves are created using operator/. Tries to match and consume lset, backtracks if that fails. Otherwise, it has selected the initial operator of a lexy::dsl::op  rule, parses the remainder of the rule without backtracking.

Parsing

Same as branch parsing, but fails instead of backtracking.

Errors
  • lexy::expected_literal_set: if no initial literal rule matched, at the initial position.

  • All errors raised by parsing the selected operator.

Values

All values produced by the selected operator, including the tag.

Example 3. Match plus or minus
constexpr auto op_plus  = dsl::op(dsl::lit_c<'+'>);
constexpr auto op_minus = dsl::op(dsl::lit_c<'-'>);

struct production : lexy::expression_production
{
    static constexpr auto atom = dsl::integer<int>;

    struct operation : dsl::infix_op_left
    {
        static constexpr auto op = op_plus / op_minus;
        using operand            = dsl::atom;
    };

    static constexpr auto value
        = lexy::callback<int>([](int value) { return value; },
                              [](int lhs, lexy::op<op_plus>, int rhs) { return lhs + rhs; },
                              [](int lhs, lexy::op<op_minus>, int rhs) { return lhs - rhs; });
};

See also