8#include "tokenizer.hpp"
9#include "coroutine.hpp"
25 [[nodiscard]]
bool is_singular()
const noexcept
37 [[nodiscard]]
bool is_singular()
const noexcept
49 [[nodiscard]]
bool is_singular()
const noexcept
61 [[nodiscard]]
bool is_singular()
const noexcept
84 for (ttlet &name : names) {
98 [[nodiscard]]
size_t size()
const noexcept
103 [[nodiscard]]
std::string const &front()
const noexcept
105 return names.
front();
108 [[nodiscard]]
auto begin()
const noexcept
113 [[nodiscard]]
auto end()
const noexcept
123 [[nodiscard]]
bool is_singular()
const noexcept
125 return std::size(names) == 1;
146 for (ttlet index : indices) {
151 r += tt::to_string(index);
160 ttlet size_ =
static_cast<ssize_t>(size);
162 for (ttlet index : indices) {
163 ttlet index_ = index >= 0 ? index : size_ + index;
164 if (index_ >= 0 and index_ < size_) {
165 co_yield static_cast<size_t>(index_);
170 [[nodiscard]]
size_t size()
const noexcept
172 return indices.
size();
175 [[nodiscard]]
ssize_t const &front()
const noexcept
177 return indices.
front();
180 void push_back(
ssize_t rhs)
noexcept
185 [[nodiscard]]
bool is_singular()
const noexcept
187 return std::size(indices) == 1;
208 [[nodiscard]]
size_t begin(
size_t size)
const noexcept
210 ttlet size_ =
static_cast<ssize_t>(size);
211 ttlet
begin = first >= 0 ? first : size_ + first;
212 return static_cast<size_t>(std::clamp(begin, 0_z, size_));
223 [[nodiscard]]
size_t end(
size_t size)
const noexcept
225 ttlet size_ =
static_cast<ssize_t>(size);
226 ttlet last_ = std::clamp(
233 ttlet first_ =
begin(size);
234 ttlet distance = last_ - first_;
235 ttlet steps = distance / step;
236 return static_cast<size_t>(first_ + steps * step);
239 [[nodiscard]]
bool last_is_empty() const noexcept
246 if (last_is_empty()) {
247 return std::format(
"[{}:e:{}]", first, step);
249 return std::format(
"[{}:{}:{}]", first, last, step);
253 [[nodiscard]]
bool is_singular() const noexcept
260using jsonpath_node = std::variant<
261 jsonpath_root, jsonpath_current, jsonpath_wildcard, jsonpath_descend, jsonpath_names, jsonpath_indices, jsonpath_slice>;
264[[nodiscard]]
inline jsonpath_node parse_jsonpath_slicing_operator(
auto &it,
auto it_end, ssize_t first)
268 if (*it == tokenizer_name_t::IntegerLiteral) {
269 last =
static_cast<ssize_t
>(*it);
274 if (*it == tokenizer_name_t::Operator and *it ==
":") {
276 tt_parse_check(*it == tokenizer_name_t::IntegerLiteral,
"Expect integer as third slice argument, got {}.", *it);
277 step =
static_cast<ssize_t
>(*it);
281 tt_parse_check(*it == tokenizer_name_t::Operator and *it ==
"]",
"Expected end of slicing operator ']', got {}.", *it);
283 tt_parse_check(step != 0,
"Slicing operator's step must not be zero");
284 return jsonpath_slice{first, last, step};
287[[nodiscard]]
inline jsonpath_node parse_jsonpath_integer_indexing_operator(
auto &it,
auto it_end, ssize_t first)
289 auto tmp = jsonpath_indices(first);
291 while (*it == tokenizer_name_t::Operator and *it ==
",") {
293 tt_parse_check(*it == tokenizer_name_t::IntegerLiteral,
"Expect integer literal after comma ',', got {}.", *it);
294 tmp.push_back(
static_cast<ssize_t
>(*it));
298 tt_parse_check(*it == tokenizer_name_t::Operator and *it ==
"]",
"Expected end of slicing operator ']', got {}.", *it);
302[[nodiscard]]
inline jsonpath_node parse_jsonpath_name_indexing_operator(
auto &it,
auto it_end,
std::string first)
304 auto tmp = jsonpath_names(
std::move(first));
306 while (*it == tokenizer_name_t::Operator and *it ==
",") {
308 tt_parse_check(*it == tokenizer_name_t::StringLiteral,
"Expect string literal after comma ',', got {}.", *it);
313 tt_parse_check(*it == tokenizer_name_t::Operator and *it ==
"]",
"Expected end of indexing operator ']', got {}.", *it);
317[[nodiscard]]
inline jsonpath_node parse_jsonpath_indexing_operator(
auto &it,
auto it_end)
321 if (*it == tokenizer_name_t::Operator and *it ==
"*") {
323 tt_parse_check(*it == tokenizer_name_t::Operator and *it ==
"]",
"Expected end of indexing operator ']', got {}.", *it);
324 return jsonpath_wildcard{};
326 }
else if (*it == tokenizer_name_t::Operator and *it ==
":") {
327 return parse_jsonpath_slicing_operator(it, it_end, 0);
329 }
else if (*it == tokenizer_name_t::IntegerLiteral) {
330 auto first =
static_cast<ssize_t
>(*it);
333 if (*it == tokenizer_name_t::Operator and *it ==
":") {
334 return parse_jsonpath_slicing_operator(it, it_end, first);
336 return parse_jsonpath_integer_indexing_operator(it, it_end, first);
339 }
else if (*it == tokenizer_name_t::StringLiteral) {
343 return parse_jsonpath_name_indexing_operator(it, it_end, first);
346 throw parse_error(
"Expected a integer index or child name after indexing operator '[', got token {}.", *it);
350[[nodiscard]]
inline jsonpath_node parse_jsonpath_child_operator(
auto &it,
auto it_end)
354 if (*it == tokenizer_name_t::Operator and *it ==
"*") {
355 return jsonpath_wildcard{};
357 }
else if (*it == tokenizer_name_t::Operator and *it ==
".") {
358 if (*(it + 1) == tokenizer_name_t::Operator and *(it + 1) ==
"[") {
361 return jsonpath_descend{};
368 return jsonpath_descend{};
371 }
else if (*it == tokenizer_name_t::Name) {
372 return jsonpath_names{
static_cast<std::string>(*it)};
375 throw parse_error(
"Expected a child name or wildcard, got token {}.", *it);
382 using value_type =
typename container_type::value_type;
383 using iterator =
typename container_type::iterator;
384 using const_iterator =
typename container_type::const_iterator;
386 [[nodiscard]]
jsonpath(std::string_view rhs) : _nodes()
388 auto tokens = parseTokens(rhs);
389 ttlet it_end = std::cend(tokens);
390 for (
auto it = std::cbegin(tokens); it != it_end; ++it) {
391 if (*it == tokenizer_name_t::Operator and *it ==
".") {
392 _nodes.
emplace_back(parse_jsonpath_child_operator(it, it_end));
394 }
else if (*it == tokenizer_name_t::Operator and *it ==
"[") {
395 _nodes.
emplace_back(parse_jsonpath_indexing_operator(it, it_end));
397 }
else if (*it == tokenizer_name_t::Name and *it ==
"$") {
398 tt_parse_check(_nodes.
empty(),
"Root node '$' not at start of path.");
401 }
else if (*it == tokenizer_name_t::Operator and *it ==
"@") {
402 tt_parse_check(_nodes.
empty(),
"Current node '@' not at start of path.");
405 }
else if (*it == tokenizer_name_t::Name) {
406 tt_parse_check(_nodes.
empty(),
"Unexpected child name {}.", *it);
409 }
else if (*it == tokenizer_name_t::End) {
418 [[nodiscard]]
bool empty()
const noexcept
420 return _nodes.
empty();
428 for (ttlet &node : _nodes) {
431 return node_.is_singular();
438 [[nodiscard]]
size_t size() const noexcept
440 return _nodes.
size();
443 [[nodiscard]] iterator begin() noexcept
445 return _nodes.
begin();
448 [[nodiscard]] const_iterator begin() const noexcept
450 return _nodes.
begin();
453 [[nodiscard]] const_iterator cbegin() const noexcept
458 [[nodiscard]] iterator end() noexcept
463 [[nodiscard]] const_iterator end() const noexcept
468 [[nodiscard]] const_iterator cend() const noexcept
470 return _nodes.
cend();
473 [[nodiscard]]
friend std::string to_string(jsonpath
const &path)
noexcept
476 for (ttlet &node : path._nodes) {
479 return node_.string();
494template<
typename CharT>
495struct formatter<tt::jsonpath, CharT> : formatter<char const *, CharT> {
498 return formatter<std::string, CharT>{}.format(
to_string(t), fc);
A return value for a generator-function.
Definition coroutine.hpp:25
Exception thrown during parsing on an error.
Definition exception.hpp:26
Definition jsonpath.hpp:19
Definition jsonpath.hpp:31
Definition jsonpath.hpp:43
Definition jsonpath.hpp:55
Definition jsonpath.hpp:67
Definition jsonpath.hpp:129
Definition jsonpath.hpp:191
size_t begin(size_t size) const noexcept
Get the start offset.
Definition jsonpath.hpp:208
size_t end(size_t size) const noexcept
Get the one-step beyond last offset.
Definition jsonpath.hpp:223
Definition jsonpath.hpp:379
bool is_singular() const noexcept
The json-path will result in zero or one match.
Definition jsonpath.hpp:425
T emplace_back(T... args)