combinators.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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#ifndef CRUCIBLE_PARSING_COMBINATORS_HPP #define CRUCIBLE_PARSING_COMBINATORS_HPP #include "crucible/core/error_chain.inl" #include "crucible/parsing/result.inl" #include <type_traits> #include <utility> namespace crucible::parsing::combinators { template<typename LHS_PARSER, typename RHS_PARSER> class BothMatch final { static_assert(std::is_same_v<typename LHS_PARSER::StateType, typename RHS_PARSER::StateType>); public: using StateType = typename LHS_PARSER::StateType; BothMatch(StateType const &initial_state, StateType const &lhs_next_state, StateType const &rhs_next_state); [[nodiscard]] auto format() const -> std::string; private: StateType my_initial_state; StateType my_lhs_next_state; StateType my_rhs_next_state; }; template<typename LHS_PARSER, typename RHS_PARSER> class NeitherMatch final { public: using LHSError = typename LHS_PARSER::ErrorType; using RHSError = typename RHS_PARSER::ErrorType; NeitherMatch(LHSError const &lhs_error, RHSError const &rhs_error); [[nodiscard]] auto format() const -> std::string; private: LHSError my_lhs_error; RHSError my_rhs_error; }; template<typename LHS_PARSER, typename RHS_PARSER> struct OneOfError final : core::error_chain::ErrorChain<OneOfError<LHS_PARSER, RHS_PARSER>, BothMatch<LHS_PARSER, RHS_PARSER>, NeitherMatch<LHS_PARSER, RHS_PARSER>> { // As far as I know, this is the syntax that is _required_ to communicate "please make my // constructor be the same as the constructor of my parent class." // I tried `using ErrorChain::ErrorChain`, which works, but _only_ if `OneOfError` is _not_ a // template type. // As soon as this cursed syntax is fixed, PLEASE change this line. using core::error_chain::ErrorChain<OneOfError<LHS_PARSER, RHS_PARSER>, BothMatch<LHS_PARSER, RHS_PARSER>, NeitherMatch<LHS_PARSER, RHS_PARSER>>::ErrorChain; static constexpr char const message[] = "Expected exactly one match"; }; template<typename LHS_PARSER, typename RHS_PARSER> class OneOf final { static_assert(std::is_same_v<typename LHS_PARSER::AcceptType, typename RHS_PARSER::AcceptType>); public: using StateType = typename LHS_PARSER::StateType; using ErrorType = OneOfError<LHS_PARSER, RHS_PARSER>; using ValueType = typename LHS_PARSER::ValueType; using RejectType = result::Reject<StateType, ErrorType>; using AcceptType = result::Accept<StateType, ValueType>; using ResultType = core::result::Result<RejectType, AcceptType>; OneOf(LHS_PARSER const &lhs_parser, RHS_PARSER const &rhs_parser); [[nodiscard]] auto operator()(StateType const &state) const -> ResultType; private: LHS_PARSER my_lhs_parser; RHS_PARSER my_rhs_parser; }; template<typename LHS_PARSER, typename RHS_PARSER> class AndThen final { static_assert(std::is_same_v<typename LHS_PARSER::RejectType, typename RHS_PARSER::RejectType>); public: using StateType = typename LHS_PARSER::StateType; using ErrorType = typename LHS_PARSER::ErrorType; using ValueType = std::pair<typename LHS_PARSER::ValueType, typename RHS_PARSER::ValueType>; using RejectType = result::Reject<StateType, ErrorType>; using AcceptType = result::Accept<StateType, ValueType>; using ResultType = core::result::Result<RejectType, AcceptType>; AndThen(LHS_PARSER const &lhs_parser, RHS_PARSER const &rhs_parser); [[nodiscard]] auto operator()(StateType const &state) const -> ResultType; private: LHS_PARSER my_lhs_parser; RHS_PARSER my_rhs_parser; }; namespace operators { template<typename LHS_PARSER, typename RHS_PARSER> [[nodiscard]] auto operator^(LHS_PARSER const &lhs_parser, RHS_PARSER const &rhs_parser) -> OneOf<LHS_PARSER, RHS_PARSER>; template<typename LHS_PARSER, typename RHS_PARSER> [[nodiscard]] auto operator&(LHS_PARSER const &lhs_parser, RHS_PARSER const &rhs_parser) -> AndThen<LHS_PARSER, RHS_PARSER>; } } #endif // CRUCIBLE_PARSING_COMBINATORS_HPP