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 |
