Header lexy/error.hpp

Classes to store information about parse errors.

Class lexy::error

lexy/error.hpp
namespace lexy
{
    template <reader Reader, typename Tag>
    class error;

    struct expected_literal {};
    template <reader Reader>
    class error<Reader, expected_literal>;

    struct expected_keyword {};
    template <reader Reader>
    class error<Reader, expected_keyword>;

    struct expected_char_class {};
    template <reader Reader>
    class error<Reader, expected_char_class>;

    template <input Input, typename Tag>
    using error_for = error<input_reader<Input>, Tag>;
}

Represents a parse error.

Different kinds of errors are identified by the Tag, which is an empty tag type. The error type is specialized for three tags.

Generic error (primary template)

lexy/error.hpp
template <reader Reader, typename Tag>
class error
{
    using iterator = typename Reader::iterator;

public:
    constexpr explicit error(iterator begin, iterator end) noexcept;
    constexpr explicit error(iterator pos) noexcept
    : error(pos, pos)
    {}

    constexpr iterator position() const noexcept
    {
        return begin();
    }

    constexpr iterator begin() const noexcept;
    constexpr iterator end() const noexcept;

    constexpr const char* message() const noexcept;
};

A generic error without additional data.

position() is the position where the error occurred, while begin() and end() return the entire range. For some errors, this range is empty.

message() is determined by Tag. By default, it is the type name of Tag after removing the top-level namespace. This can be overridden by Tag::name() or Tag::name.

Example 1. Choice raises generic error at a single position
struct production
{
    static constexpr auto rule = LEXY_LIT("Hello") | LEXY_LIT("Hi");
};
Example 2. Identifier rules raise a generic error spanning a sub-range
struct production
{
    static constexpr auto rule = [] {
        // Define the general identifier syntax.
        auto head = dsl::ascii::alpha_underscore;
        auto tail = dsl::ascii::alpha_digit_underscore;
        auto id   = dsl::identifier(head, tail);

        // Define some keywords.
        auto kw_int    = LEXY_KEYWORD("int", id);
        auto kw_struct = LEXY_KEYWORD("struct", id);
        // ...

        // Parse an identifier
        return id
            // ... that is not a keyword,
            .reserve(kw_int, kw_struct)
            // ... doesn't start with an underscore,
            .reserve_prefix(dsl::lit_c<'_'>)
            // ... or contains a double underscore.
            .reserve_containing(LEXY_LIT("__"));
    }();
};

lexy::expected_literal error

lexy/error.hpp
struct expected_literal {};

template <reader Reader>
class error<Reader, expected_literal>
{
    using iterator  = typename Reader::iterator;
    using char_type = typename Reader::encoding::char_type;

public:
    constexpr explicit error(iterator pos,
                             const char_type string, std::size_t index) noexcept;

    constexpr iterator position() const noexcept;

    constexpr const char_type string() const noexcept;
    constexpr std::size_t index() const noexcept;

    constexpr char_type character() const noexcept
    {
        return string()[index()];
    }
};

An error where a given literal string was expected.

The error can be raised while trying to parse string() beginning at position(); the code unit at std::next(position(), index()) did not match character(). If the remaining input contained fewer code units than string(), index() indicates the first code unit that was missing.

It is raised by lexy::dsl::lit and related rules.

Example 3. LEXY_LIT() raises an expected literal error
struct production
{
    static constexpr auto rule = LEXY_LIT("Hello World!");
};

lexy::expected_keyword error

lexy/error.hpp
struct expected_keyword {};

template <reader Reader>
class error<Reader, expected_keyword>
{
    using iterator  = typename Reader::iterator;
    using char_type = typename Reader::encoding::char_type;

public:
    constexpr explicit error(iterator begin, iterator end,
                             const char_type string) noexcept;

    constexpr iterator position() const noexcept;

    constexpr iterator begin() const noexcept;
    constexpr iterator end() const noexcept;

    constexpr const char_type string() const noexcept;
};

An error where a given keyword was expected.

The error can be raised while trying to parse the keyword string() against the identifier [begin(), end()), but it was a different identifier. The position() is also begin().

It is raised by lexy::dsl::keyword.

Example 4. LEXY_KEYWORD() raises an expected keyword error
struct production
{
    static constexpr auto rule = [] {
        // Define the general identifier syntax.
        auto head = dsl::ascii::alpha_underscore;
        auto tail = dsl::ascii::alpha_digit_underscore;
        auto id   = dsl::identifier(head, tail);

        // Parse a keyword.
        return LEXY_KEYWORD("int", id);
    }();
};

lexy::expected_char_class error

lexy/error.hpp
struct expected_char_class {};

template <reader Reader>
class error<Reader, expected_keyword>
{
    using iterator  = typename Reader::iterator;

public:
    constexpr explicit error(iterator pos, const char name) noexcept;

    constexpr iterator position() const noexcept;

    constexpr const char character_class() const noexcept;
};

An error where one character from a character class was expected.

The error can be raised while trying to parse the character class with the human-readable name character_class() at position(). This happens in rules like lexy::dsl::ascii or lexy::dsl::digit.

Example 5. dsl::digit raises an expected char class error
struct production
{
    static constexpr auto rule = dsl::digit<dsl::octal>;
};

Class lexy::error_context

lexy/error.hpp
namespace lexy
{
    template <production Production, input Input>
    class error_context
    {
        using iterator  = typename input_reader<Reader>::iterator;

    public:
        constexpr explicit error_context(const Input& input,
                                         iterator pos) noexcept;
        constexpr explicit error_context(Production,
                                         const Input& input,
                                         iterator pos) noexcept;

        static consteval const char* production() noexcept;

        constexpr const Input& input() const noexcept;

        constexpr iterator position() const noexcept;
    };
}

Contains additional information about an error.

input()

The entire input where the error occurred; all positions are iterators into that input.

production()

The name of the production where the error occurred, i.e. lexy::production_name.

position()

The position where it started to parse Production.

See also