Echo Writes Code

errors.hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#ifndef CRUCIBLE_PARSING_ERRORS_HPP
#define CRUCIBLE_PARSING_ERRORS_HPP

#include "crucible/core/either.inl"
#include "crucible/core/errors.hpp"

#include <cstddef>
#include <functional>
#include <optional>
#include <string>
#include <variant>
#include <vector>

namespace crucible::parsing::errors {
  struct AmbiguousMatch final {
  };

  struct UnexpectedInput final {
  };

  struct UnexpectedEndOfInput final {
  };

  struct ExpectedExactBytes final {
    std::vector<std::byte> bytes {};
  };

  struct InsufficientInput final {
    std::size_t count { 0 };
  };

  class ParsingError final : public core::errors::AbstractError {
  public:
    explicit ParsingError(AmbiguousMatch const &variant);

    explicit ParsingError(UnexpectedInput const &variant);

    explicit ParsingError(UnexpectedEndOfInput const &variant);

    explicit ParsingError(ExpectedExactBytes const &variant);

    explicit ParsingError(InsufficientInput const &variant);

    ~ParsingError() override;

    template<typename T>
    [[nodiscard]]
    auto is() const -> bool {
      return std::holds_alternative<T>(my_variant);
    }

    [[nodiscard]]
    auto describe() const -> std::string override;

    [[nodiscard]]
    auto format() const -> std::string override;

    [[nodiscard]]
    auto source() const & -> std::optional<std::reference_wrapper<core::errors::AbstractError const>> override;

  private:
    std::variant<AmbiguousMatch, UnexpectedInput, UnexpectedEndOfInput, ExpectedExactBytes, InsufficientInput> my_variant;
  };

  template<typename STATE>
  class Reject final {
  public:
    Reject(STATE const &state, ParsingError const &error);

    [[nodiscard]]
    auto get_state() const -> STATE;

    [[nodiscard]]
    auto get_error() const -> ParsingError;

  private:
    STATE my_state;

    ParsingError my_error;
  };

  template<typename STATE, typename VALUE>
  class Accept final {
  public:
    Accept(STATE const &state, VALUE const &value);

    [[nodiscard]]
    auto get_state() const -> STATE;

    [[nodiscard]]
    auto get_value() const -> VALUE;

  private:
    STATE my_state;

    VALUE my_value;
  };

  template<typename STATE, typename ERROR>
  [[nodiscard]]
  auto make_reject(STATE const &state, ERROR const &error) -> core::either::Lhs<Reject<STATE>>;

  template<typename STATE, typename VALUE>
  [[nodiscard]]
  auto make_accept(STATE const &state, VALUE const &value) -> core::either::Rhs<Accept<STATE, VALUE>>;

  template<typename STATE, typename T>
  using ParsingResult = core::either::Either<Reject<STATE>, Accept<STATE, T>>;
}

#endif // CRUCIBLE_PARSING_ERRORS_HPP