Mercurial > minori
comparison dep/toml11/toml/combinator.hpp @ 318:3b355fa948c7
config: use TOML instead of INI
unfortunately, INI is not enough, and causes some paths including
semicolons to break with our current storage of the library folders.
so, I decided to switch to TOML which does support real arrays...
author | Paper <paper@paper.us.eu.org> |
---|---|
date | Wed, 12 Jun 2024 05:25:41 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
317:b1f4d1867ab1 | 318:3b355fa948c7 |
---|---|
1 // Copyright Toru Niina 2017. | |
2 // Distributed under the MIT License. | |
3 #ifndef TOML11_COMBINATOR_HPP | |
4 #define TOML11_COMBINATOR_HPP | |
5 #include <cassert> | |
6 #include <cctype> | |
7 #include <cstdio> | |
8 | |
9 #include <array> | |
10 #include <iomanip> | |
11 #include <iterator> | |
12 #include <limits> | |
13 #include <type_traits> | |
14 | |
15 #include "region.hpp" | |
16 #include "result.hpp" | |
17 #include "traits.hpp" | |
18 #include "utility.hpp" | |
19 | |
20 // they scans characters and returns region if it matches to the condition. | |
21 // when they fail, it does not change the location. | |
22 // in lexer.hpp, these are used. | |
23 | |
24 namespace toml | |
25 { | |
26 namespace detail | |
27 { | |
28 | |
29 // to output character as an error message. | |
30 inline std::string show_char(const char c) | |
31 { | |
32 // It suppresses an error that occurs only in Debug mode of MSVC++ on Windows. | |
33 // I'm not completely sure but they check the value of char to be in the | |
34 // range [0, 256) and some of the COMPLETELY VALID utf-8 character sometimes | |
35 // has negative value (if char has sign). So here it re-interprets c as | |
36 // unsigned char through pointer. In general, converting pointer to a | |
37 // pointer that has different type cause UB, but `(signed|unsigned)?char` | |
38 // are one of the exceptions. Converting pointer only to char and std::byte | |
39 // (c++17) are valid. | |
40 if(std::isgraph(*reinterpret_cast<unsigned char const*>(std::addressof(c)))) | |
41 { | |
42 return std::string(1, c); | |
43 } | |
44 else | |
45 { | |
46 std::array<char, 5> buf; | |
47 buf.fill('\0'); | |
48 const auto r = std::snprintf( | |
49 buf.data(), buf.size(), "0x%02x", static_cast<int>(c) & 0xFF); | |
50 (void) r; // Unused variable warning | |
51 assert(r == static_cast<int>(buf.size()) - 1); | |
52 return std::string(buf.data()); | |
53 } | |
54 } | |
55 | |
56 template<char C> | |
57 struct character | |
58 { | |
59 static constexpr char target = C; | |
60 | |
61 static result<region, none_t> | |
62 invoke(location& loc) | |
63 { | |
64 if(loc.iter() == loc.end()) {return none();} | |
65 const auto first = loc.iter(); | |
66 | |
67 const char c = *(loc.iter()); | |
68 if(c != target) | |
69 { | |
70 return none(); | |
71 } | |
72 loc.advance(); // update location | |
73 | |
74 return ok(region(loc, first, loc.iter())); | |
75 } | |
76 }; | |
77 template<char C> | |
78 constexpr char character<C>::target; | |
79 | |
80 // closed interval [Low, Up]. both Low and Up are included. | |
81 template<char Low, char Up> | |
82 struct in_range | |
83 { | |
84 // assuming ascii part of UTF-8... | |
85 static_assert(Low <= Up, "lower bound should be less than upper bound."); | |
86 | |
87 static constexpr char upper = Up; | |
88 static constexpr char lower = Low; | |
89 | |
90 static result<region, none_t> | |
91 invoke(location& loc) | |
92 { | |
93 if(loc.iter() == loc.end()) {return none();} | |
94 const auto first = loc.iter(); | |
95 | |
96 const char c = *(loc.iter()); | |
97 if(c < lower || upper < c) | |
98 { | |
99 return none(); | |
100 } | |
101 | |
102 loc.advance(); | |
103 return ok(region(loc, first, loc.iter())); | |
104 } | |
105 }; | |
106 template<char L, char U> constexpr char in_range<L, U>::upper; | |
107 template<char L, char U> constexpr char in_range<L, U>::lower; | |
108 | |
109 // keep iterator if `Combinator` matches. otherwise, increment `iter` by 1 char. | |
110 // for detecting invalid characters, like control sequences in toml string. | |
111 template<typename Combinator> | |
112 struct exclude | |
113 { | |
114 static result<region, none_t> | |
115 invoke(location& loc) | |
116 { | |
117 if(loc.iter() == loc.end()) {return none();} | |
118 auto first = loc.iter(); | |
119 | |
120 auto rslt = Combinator::invoke(loc); | |
121 if(rslt.is_ok()) | |
122 { | |
123 loc.reset(first); | |
124 return none(); | |
125 } | |
126 loc.reset(std::next(first)); // XXX maybe loc.advance() is okay but... | |
127 return ok(region(loc, first, loc.iter())); | |
128 } | |
129 }; | |
130 | |
131 // increment `iter`, if matches. otherwise, just return empty string. | |
132 template<typename Combinator> | |
133 struct maybe | |
134 { | |
135 static result<region, none_t> | |
136 invoke(location& loc) | |
137 { | |
138 const auto rslt = Combinator::invoke(loc); | |
139 if(rslt.is_ok()) | |
140 { | |
141 return rslt; | |
142 } | |
143 return ok(region(loc)); | |
144 } | |
145 }; | |
146 | |
147 template<typename ... Ts> | |
148 struct sequence; | |
149 | |
150 template<typename Head, typename ... Tail> | |
151 struct sequence<Head, Tail...> | |
152 { | |
153 static result<region, none_t> | |
154 invoke(location& loc) | |
155 { | |
156 const auto first = loc.iter(); | |
157 auto rslt = Head::invoke(loc); | |
158 if(rslt.is_err()) | |
159 { | |
160 loc.reset(first); | |
161 return none(); | |
162 } | |
163 return sequence<Tail...>::invoke(loc, std::move(rslt.unwrap()), first); | |
164 } | |
165 | |
166 // called from the above function only, recursively. | |
167 template<typename Iterator> | |
168 static result<region, none_t> | |
169 invoke(location& loc, region reg, Iterator first) | |
170 { | |
171 const auto rslt = Head::invoke(loc); | |
172 if(rslt.is_err()) | |
173 { | |
174 loc.reset(first); | |
175 return none(); | |
176 } | |
177 reg += rslt.unwrap(); // concat regions | |
178 return sequence<Tail...>::invoke(loc, std::move(reg), first); | |
179 } | |
180 }; | |
181 | |
182 template<typename Head> | |
183 struct sequence<Head> | |
184 { | |
185 // would be called from sequence<T ...>::invoke only. | |
186 template<typename Iterator> | |
187 static result<region, none_t> | |
188 invoke(location& loc, region reg, Iterator first) | |
189 { | |
190 const auto rslt = Head::invoke(loc); | |
191 if(rslt.is_err()) | |
192 { | |
193 loc.reset(first); | |
194 return none(); | |
195 } | |
196 reg += rslt.unwrap(); // concat regions | |
197 return ok(reg); | |
198 } | |
199 }; | |
200 | |
201 template<typename ... Ts> | |
202 struct either; | |
203 | |
204 template<typename Head, typename ... Tail> | |
205 struct either<Head, Tail...> | |
206 { | |
207 static result<region, none_t> | |
208 invoke(location& loc) | |
209 { | |
210 const auto rslt = Head::invoke(loc); | |
211 if(rslt.is_ok()) {return rslt;} | |
212 return either<Tail...>::invoke(loc); | |
213 } | |
214 }; | |
215 template<typename Head> | |
216 struct either<Head> | |
217 { | |
218 static result<region, none_t> | |
219 invoke(location& loc) | |
220 { | |
221 return Head::invoke(loc); | |
222 } | |
223 }; | |
224 | |
225 template<typename T, typename N> | |
226 struct repeat; | |
227 | |
228 template<std::size_t N> struct exactly{}; | |
229 template<std::size_t N> struct at_least{}; | |
230 struct unlimited{}; | |
231 | |
232 template<typename T, std::size_t N> | |
233 struct repeat<T, exactly<N>> | |
234 { | |
235 static result<region, none_t> | |
236 invoke(location& loc) | |
237 { | |
238 region retval(loc); | |
239 const auto first = loc.iter(); | |
240 for(std::size_t i=0; i<N; ++i) | |
241 { | |
242 auto rslt = T::invoke(loc); | |
243 if(rslt.is_err()) | |
244 { | |
245 loc.reset(first); | |
246 return none(); | |
247 } | |
248 retval += rslt.unwrap(); | |
249 } | |
250 return ok(std::move(retval)); | |
251 } | |
252 }; | |
253 | |
254 template<typename T, std::size_t N> | |
255 struct repeat<T, at_least<N>> | |
256 { | |
257 static result<region, none_t> | |
258 invoke(location& loc) | |
259 { | |
260 region retval(loc); | |
261 | |
262 const auto first = loc.iter(); | |
263 for(std::size_t i=0; i<N; ++i) | |
264 { | |
265 auto rslt = T::invoke(loc); | |
266 if(rslt.is_err()) | |
267 { | |
268 loc.reset(first); | |
269 return none(); | |
270 } | |
271 retval += rslt.unwrap(); | |
272 } | |
273 while(true) | |
274 { | |
275 auto rslt = T::invoke(loc); | |
276 if(rslt.is_err()) | |
277 { | |
278 return ok(std::move(retval)); | |
279 } | |
280 retval += rslt.unwrap(); | |
281 } | |
282 } | |
283 }; | |
284 | |
285 template<typename T> | |
286 struct repeat<T, unlimited> | |
287 { | |
288 static result<region, none_t> | |
289 invoke(location& loc) | |
290 { | |
291 region retval(loc); | |
292 while(true) | |
293 { | |
294 auto rslt = T::invoke(loc); | |
295 if(rslt.is_err()) | |
296 { | |
297 return ok(std::move(retval)); | |
298 } | |
299 retval += rslt.unwrap(); | |
300 } | |
301 } | |
302 }; | |
303 | |
304 } // detail | |
305 } // toml | |
306 #endif// TOML11_COMBINATOR_HPP |