7#include "utility/module.hpp"
8#include "tokenizer.hpp"
9#include "generator.hpp"
17namespace hi::inline
v1 {
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 (
hilet &name : names) {
103 [[nodiscard]]
std::string const &front()
const noexcept
105 return names.
front();
108 [[nodiscard]]
auto begin()
const noexcept
110 return names.
begin();
113 [[nodiscard]]
auto end()
const noexcept
123 [[nodiscard]]
bool is_singular()
const noexcept
125 return names.
size() == 1;
146 for (
hilet index : indices) {
160 hilet size_ = narrow_cast<ssize_t>(size);
162 for (
hilet index : indices) {
163 hilet index_ = index >= 0 ? index : size_ + index;
164 if (index_ >= 0 and index_ < size_) {
165 co_yield narrow_cast<std::size_t>(index_);
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 indices.
size() == 1;
201 constexpr jsonpath_slice(ssize_t first, ssize_t last, ssize_t step) noexcept : first(first), last(last), step(step) {}
210 hilet size_ = narrow_cast<ssize_t>(size);
211 hilet begin = first >= 0 ? first : size_ + first;
212 return narrow_cast<std::size_t>(std::clamp(begin, 0_z, size_));
225 hilet size_ = narrow_cast<ssize_t>(size);
226 hilet last_ = std::clamp(
233 hilet first_ = begin(size);
234 hilet distance = last_ - first_;
235 hilet steps = distance / step;
236 return narrow_cast<std::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 hi_check(*it == tokenizer_name_t::IntegerLiteral,
"Expect integer as third slice argument, got {}.", *it);
277 step =
static_cast<ssize_t>(*it);
281 hi_check(*it == tokenizer_name_t::Operator and *it ==
"]",
"Expected end of slicing operator ']', got {}.", *it);
283 hi_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 hi_check(*it == tokenizer_name_t::IntegerLiteral,
"Expect integer literal after comma ',', got {}.", *it);
294 tmp.push_back(
static_cast<ssize_t>(*it));
298 hi_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 hi_check(*it == tokenizer_name_t::StringLiteral,
"Expect string literal after comma ',', got {}.", *it);
313 hi_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 hi_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) {
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(std::format(
"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(std::format(
"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()
389 hilet it_end = tokens.cend();
390 for (
auto it = tokens.cbegin(); 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 hi_check(_nodes.empty(),
"Root node '$' not at start of path.");
401 }
else if (*it == tokenizer_name_t::Operator and *it ==
"@") {
402 hi_check(_nodes.empty(),
"Current node '@' not at start of path.");
405 }
else if (*it == tokenizer_name_t::Name) {
406 hi_check(_nodes.empty(),
"Unexpected child name {}.", *it);
409 }
else if (*it == tokenizer_name_t::End) {
413 throw parse_error(std::format(
"Unexpected token {}.", *it));
418 [[nodiscard]]
bool empty()
const noexcept
420 return _nodes.empty();
428 for (
hilet &node : _nodes) {
431 return node_.is_singular();
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
455 return _nodes.cbegin();
458 [[nodiscard]] iterator
end() noexcept
463 [[nodiscard]] const_iterator
end() const noexcept
468 [[nodiscard]] const_iterator cend() const noexcept
470 return _nodes.cend();
476 for (
hilet &node : path._nodes) {
479 return node_.string();
492template<
typename CharT>
493struct std::formatter<
hi::jsonpath, CharT> : std::formatter<char const *, CharT> {
494 auto format(hi::jsonpath
const &t,
auto &fc)
496 return std::formatter<std::string, CharT>{}.format(
to_string(t), fc);
#define hi_check(expression, message,...)
Check if the expression is valid, or throw a parse_error.
Definition assert.hpp:110
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
constexpr std::string to_string(std::u32string_view rhs) noexcept
Conversion from UTF-32 to UTF-8.
Definition to_string.hpp:215
DOXYGEN BUG.
Definition algorithm.hpp:13
std::vector< token_t > parseTokens(std::string_view text) noexcept
geometry/margins.hpp
Definition cache.hpp:11
std::ptrdiff_t ssize_t
Signed size/index into an array.
Definition utility.hpp:189
A return value for a generator-function.
Definition generator.hpp:29
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
std::size_t end(std::size_t size) const noexcept
Get the one-step beyond last offset.
Definition jsonpath.hpp:223
std::size_t begin(std::size_t size) const noexcept
Get the start offset.
Definition jsonpath.hpp:208
Definition jsonpath.hpp:379
bool is_singular() const noexcept
The json-path will result in zero or one match.
Definition jsonpath.hpp:425