mpc
Haskell-like feature supports in C++
parser.hpp
Go to the documentation of this file.
1
2#pragma once
3#include <iostream>
4#include <string>
5#include <string_view>
6#include <mpc/control.hpp>
7#include <mpc/data.hpp>
8
9namespace mpc {
10#define MPC_FORWARD(x) std::forward<decltype(x)>(x)
11
12 template <class T>
13 T decay(T); // no definition
14
15 template <class T, class U>
16 concept similar_to = std::same_as<std::remove_cvref_t<T>, std::remove_cvref_t<U>>;
17
18 using String = std::list<char>;
19 using ParseError = std::string;
20 using ParseResult = either<ParseError, std::pair<char, String>>;
21 using Parser = StateT<String, ParseResult>;
22} // namespace mpc
23
24template <class T>
25struct mpc::alternative_traits<mpc::either<mpc::ParseError, std::pair<T, mpc::String>>> {
26 static constexpr auto combine = //
27 // TODO: m1, m2 を is_Parser<T> で制約
28 [](auto&& m1, auto&& m2) -> either<mpc::ParseError, std::pair<T, mpc::String>> {
29 if (m1.index() == 0) {
30 if (m2.index() == 0) {
31 return make_left(*fst(MPC_FORWARD(m1)) + " and " + *fst(MPC_FORWARD(m2)));
32 } else {
33 return MPC_FORWARD(m2);
34 }
35 } else {
36 return MPC_FORWARD(m1);
37 }
38 };
39};
40
41namespace mpc {
42 // Parsers
43 // https://hackage.haskell.org/package/parsec-3.1.15.1/docs/Text-Parsec.html#g:1
44
46 inline constexpr auto parse_test = //
47 // TODO: parser を is_Parser<T> で制約
48 partial([](auto&& parser, std::string_view sv) {
49 auto result = eval_StateT % MPC_FORWARD(parser) % String(sv.begin(), sv.end());
50 if (result.index() == 0) {
51 // fail
52 std::cout << mpc::quoted(sv) << ' ' << *fst(result) << std::endl;
53 } else {
54 // succeed
55 for (const auto& c : *snd(result))
56 std::cout << c;
57 std::cout << std::endl;
58 }
59 });
60
61 // Combinators
62 // https://hackage.haskell.org/package/parsec-3.1.15.1/docs/Text-Parsec.html#g:2
63
65 inline constexpr auto left = //
67 % lift<Parser> % partial([](similar_to<ParseError> auto&& str) -> eval_StateT_t<Parser> {
68 return make_left(MPC_FORWARD(str));
69 });
70
72 inline constexpr auto try1 = //
73 // TODO: parser を is_Parser<T> で制約
74 partial([](auto&& parser) {
75 return make_StateT<String>(partial(
76 [](auto&& parser2, similar_to<String> auto&& str) {
77 return run_StateT % MPC_FORWARD(parser2) % MPC_FORWARD(str);
78 },
79 MPC_FORWARD(parser)));
80 });
81
85 inline constexpr auto many1 = //
86 // TODO: p, sep を is_Parser<T> で制約
87 partial([](auto&& p) {
88 return make_StateT<String>(partial(
89 [](auto&& p2, similar_to<String> auto&& str)
90 -> decltype(run_StateT % (sequence % std::list{p2}) % str) {
91 const auto parse = run_StateT % MPC_FORWARD(p2);
92 auto result = parse % MPC_FORWARD(str);
93 if (result.index() == 0)
94 return make_left(*fst(std::move(result)));
95 auto [value, state] = *snd(std::move(result));
96 std::list<holding_t<decltype(p2)>> ret{std::move(value)};
97
98 for (result = parse % state; result.index() != 0; result = parse % state) {
99 std::tie(value, state) = *snd(std::move(result));
100 ret.push_back(std::move(value));
101 }
102 return make_right(std::make_pair(std::move(ret), std::move(state)));
103 },
104 MPC_FORWARD(p)));
105 });
106
110 inline constexpr auto many = //
111 // TODO: p を is_Parser<T> で制約
112 partial([](auto&& p) {
113 using namespace operators::alternatives;
114 return many1(MPC_FORWARD(p)) or pure<decltype(p)>(std::list<holding_t<decltype(p)>>{});
115 });
116
118 inline constexpr auto between = //
119 // TODO: open, p, close を is_Parser<T> で制約
120 partial([](auto&& open, auto&& p, auto&& close) {
121 return discard2nd(discard1st(MPC_FORWARD(open), MPC_FORWARD(p)), MPC_FORWARD(close));
122 });
123
125 inline constexpr auto sep_by1 = //
126 // TODO: p, sep を is_Parser<T> で制約
127 partial([](auto&& p, auto&& sep) {
128 auto p2 = p;
129 return liftA2(cons, MPC_FORWARD(p), many % discard1st(MPC_FORWARD(sep), std::move(p2)));
130 });
131
133 inline constexpr auto sep_by = //
134 // TODO: p, sep を is_Parser<T> で制約
135 partial([](auto&& p, auto&& sep) {
136 using namespace operators::alternatives;
137 return sep_by1(MPC_FORWARD(p), MPC_FORWARD(sep))
138 or pure<decltype(p)>(std::list<holding_t<decltype(p)>>{});
139 });
140
149 inline constexpr auto chainl1 = //
150 // TODO: p, op を is_Parser<T> で制約
151 partial([](auto&& p, auto&& op) {
152 return make_StateT<String>(partial(
153 [](auto&& p2, auto&& op2, similar_to<String> auto&& str)
154 -> decltype(run_StateT % p2 % str) {
155 const auto parse = run_StateT % MPC_FORWARD(p2);
156 const auto parse_op = run_StateT % MPC_FORWARD(op2);
157
158 auto result = parse % MPC_FORWARD(str);
159 if (result.index() == 0)
160 return make_left(*fst(std::move(result)));
161 auto [value, state] = *snd(std::move(result));
162
163 for (;;) {
164 auto result_op = parse_op % state;
165 if (result_op.index() == 0)
166 break;
167 auto [fn, state_op] = *snd(std::move(result_op));
168 auto result2 = parse % std::move(state_op);
169 if (result2.index() == 0)
170 break;
171 auto [value2, state2] = *snd(std::move(result2));
172 value = fn(std::move(value), std::move(value2));
173 state = std::move(state2);
174 }
175 return make_right(std::make_pair(std::move(value), std::move(state)));
176 },
177 MPC_FORWARD(p), MPC_FORWARD(op)));
178 });
179} // namespace mpc
180
181namespace mpc {
182 // Character Parsing
183 // https://hackage.haskell.org/package/parsec-3.1.15.1/docs/Text-Parsec-Char.html
184
186 inline constexpr auto satisfy = //
187 partial([](std::predicate<char> auto&& pred) {
188 return make_StateT<String>(partial(
189 [](auto&& pred2, similar_to<String> auto&& str) -> ParseResult {
190 using namespace std::string_literals;
191
192 if (auto m = uncons(MPC_FORWARD(str)); m.index() == 0) {
193 return make_left("unexpected end of input"s);
194 } else if (auto [x, xs] = *snd(std::move(m)); not std::invoke(MPC_FORWARD(pred2), x)) {
195 return make_left("unexpected "s + mpc::quoted(std::move(x)));
196 } else {
197 return make_right(std::make_pair(std::move(x), std::move(xs)));
198 }
199 },
200 MPC_FORWARD(pred)));
201 });
202
204 inline constexpr auto char1 = //
205 partial([](char c) {
206 using namespace operators::alternatives;
207 using namespace std::string_literals;
208 auto c2 = c;
209 return satisfy % (equal_to % std::move(c))
210 or left % ("expecting char "s + mpc::quoted(std::move(c2)));
211 });
212
214 inline constexpr auto string = //
215 partial([](std::string_view sv) {
216 return sequence
217 % fmap(partial([](char c) { return char1 % std::move(c); }),
218 std::list(sv.begin(), sv.end()));
219 });
220
221 namespace detail {
222 using namespace operators::alternatives;
223 using namespace std::string_literals;
224
225 inline const auto alnum = satisfy % mpc::isalnum or left % "expecting alnum"s;
226 inline const auto alpha = satisfy % mpc::isalpha or left % "expecting alpha"s;
227 inline const auto lower = satisfy % mpc::islower or left % "expecting lower"s;
228 inline const auto upper = satisfy % mpc::isupper or left % "expecting upper"s;
229 inline const auto digit = satisfy % mpc::isdigit or left % "expecting digit"s;
230 inline const auto xdigit = satisfy % mpc::isxdigit or left % "expecting xdigit"s;
231 inline const auto cntrl = satisfy % mpc::iscntrl or left % "expecting cntrl"s;
232 inline const auto graph = satisfy % mpc::isgraph or left % "expecting graph"s;
233 inline const auto space = satisfy % mpc::isspace or left % "expecting space"s;
234 inline const auto blank = satisfy % mpc::isblank or left % "expecting blank"s;
235 inline const auto print = satisfy % mpc::isprint or left % "expecting print"s;
236 inline const auto punct = satisfy % mpc::ispunct or left % "expecting punct"s;
237 inline const auto any_char = satisfy % (constant % true);
238 } // namespace detail
239
240 using detail::alnum, detail::alpha, detail::lower, detail::upper, detail::digit, detail::xdigit,
241 detail::cntrl, detail::graph, detail::space, detail::blank, detail::print, detail::punct,
242 detail::any_char;
243} // namespace mpc
std::basic_string< charT > quoted(charT s, charT delim=charT('\''))
Surrounds a string with delimiter.
Definition: char.hpp:115
std::variant< left_t< T >, right_t< U > > either
data Either a b = Left a | Right b
Definition: either.hpp:35
constexpr partial< detail::fmap_op > fmap
fmap :: (a -> b) -> f a -> f b
Definition: applicative.hpp:161
constexpr partial< detail::liftA2_op > liftA2
liftA2 :: (a -> b -> c) -> f a -> f b -> f c
Definition: applicative.hpp:102
constexpr partial< detail::_fst::get_op< 1 > > snd
Returns the second element of the given tuple-like object.
Definition: fst.hpp:34
constexpr partial< detail::compose_op > compose
Function composition.
Definition: compose.hpp:35
constexpr partial< detail::discard1st_op > discard1st
discard1st :: f a -> f b -> f b
Definition: applicative.hpp:108
constexpr partial< detail::combine_op > combine
combine :: f a -> f a -> f a
Definition: alternative.hpp:74
constexpr partial< detail::discard2nd_op > discard2nd
discard2nd :: f a -> f b -> f a
Definition: applicative.hpp:105
constexpr partial< std::ranges::equal_to > equal_to
Partially applicable std::ranges::equal_to.
Definition: operations.hpp:25
constexpr partial< detail::_fst::get_op< 0 > > fst
Returns the first element of the given tuple-like object.
Definition: fst.hpp:29
constexpr partial< detail::state_op< ST > > state
state :: (s -> (a, s)) -> m a
Definition: class.hpp:61
constexpr auto sep_by1
sepBy1 p sep = liftA2 (:) p (many (sep *> p))
Definition: parser.hpp:125
constexpr auto try1
パーサーを受け取り、パーサーを返す。このパーサーはパースに失敗しても直ちにエラーとならない。
Definition: parser.hpp:72
constexpr auto many1
Definition: parser.hpp:85
constexpr auto char1
文字を受け取り、パーサーを返す。このパーサーは、文字列の先頭が渡した文字に一致する場合にそれを返す。
Definition: parser.hpp:204
constexpr auto chainl1
Definition: parser.hpp:149
constexpr auto left
エラーメッセージを受け取り、必ず失敗するパーサーを返す。
Definition: parser.hpp:65
constexpr auto parse_test
パーサーと文字列を受け取り、パースする。パースに成功した場合、パース結果を表示する。失敗した場合、エラーメッセージを表示する。
Definition: parser.hpp:46
constexpr auto between
between open p close = open *> p <* close
Definition: parser.hpp:118
constexpr auto many
Definition: parser.hpp:110
constexpr auto satisfy
述語を受け取り、パーサーを返す。このパーサーは、文字列の先頭が述語を満たす場合にそれを返す。
Definition: parser.hpp:186
constexpr auto sep_by
sepBy p sep = sepBy1 p sep <|> pure []
Definition: parser.hpp:133
class Applicative f => Alternative f where
Definition: alternative.hpp:14
Implements a perfect-forwarding call wrapper.
Definition: partial.hpp:63