Header lexy/dsl/separator.hpp

The sep, trailing_sep and ignore_trailing_sep separators.

They are used with lexy::dsl::times  and lexy::dsl::list  (and variants thereof) and are not actually rules themselves.

Separator lexy::dsl::sep

lexy/dsl/separator.hpp
namespace lexy
{
    struct unexpected_trailing_separator {};
}

namespace lexy::dsl
{
    struct sep-dsl // models separator
    {
        template <typename Tag>
        static constexpr separator auto trailing_error;
    };

    constexpr sep-dsl auto sep(branch-rule rule);
}

sep indicates a separator between two items.

If specified as a separator, it will parse rule between two items, but it is an error if rule is after the last item. In that case, a generic error with tag lexy::unexpected_trailing_separator is raised at the position where the separator begins. This tag can be overridden by specifying a different tag via .trailing_error.

Example 1. Parse a list of letters separated by commas
struct production
{
    static constexpr auto rule = [] {
        auto item = dsl::capture(dsl::ascii::alpha);
        auto sep  = dsl::sep(dsl::comma);
        return dsl::list(item, sep);
    }();

    static constexpr auto value = lexy::as_string<std::string>;
};
Note
It is not always possible to check for the existence of a trailing separator. If it is not possible, parsing will continue as normal and (presumably) the next rule will fail due to the unexpected separator.

Separator lexy::dsl::trailing_sep

lexy/dsl/separator.hpp
namespace lexy::dsl
{
    constexpr separator auto trailing_sep(branch-rule rule);
}

trailing_sep indicates a separator between two items and optionally after the last item.

If specified as a separator, it will parse rule between two items, or after the last item. If no separator is present after the last item, it is not an error.

Example 2. Parse three integers separated by comma
struct production
{
    static constexpr auto rule = [] {
        auto item = dsl::integer<int>;
        auto sep  = dsl::trailing_sep(dsl::comma);
        return dsl::times<3>(item, sep);
    }();

    static constexpr auto value
        = lexy::callback<int>([](int a, int b, int c) { return a + b + c; });
};
Tip
To create a separator that must be present after every the last item (and every item before that), simply add the separator to the item itself.

Separator lexy::dsl::ignore_trailing_sep

lexy/dsl/separator.hpp
namespace lexy::dsl
{
    constexpr separator auto ignore_trailing_sep(branch-rule rule);
}

ignore_trailing_sep indicates a separator between two items and it can be ignored after the last item.

It can only be used with lexy::dsl::times . If specified as a separator, it will parse rule between two items, but makes no attempt to parse it after the last item.

Example 3. Parse three integers separated by comma, twice
struct three_ints
{
    static constexpr auto rule = [] {
        auto item = dsl::integer<int>;
        auto sep  = dsl::ignore_trailing_sep(dsl::comma);
        return dsl::times<3>(item, sep) + dsl::eof;
    }();

    static constexpr auto value
        = lexy::callback<int>([](int a, int b, int c) { return a + b + c; });
};

struct production
{
    static constexpr auto rule  = dsl::p<three_ints> + dsl::comma + dsl::p<three_ints>;
    static constexpr auto value = lexy::callback<int>([](int a, int b) { return a + b; });
};
Tip
Use it if the separator can also legally occur after the list.

See also