8#include "tokenizer.hpp"
9#include "generator.hpp"
18namespace hi::inline
v1 {
26 [[nodiscard]]
bool is_singular()
const noexcept
38 [[nodiscard]]
bool is_singular()
const noexcept
50 [[nodiscard]]
bool is_singular()
const noexcept
62 [[nodiscard]]
bool is_singular()
const noexcept
85 for (
hilet &name : names) {
104 [[nodiscard]]
std::string const &front()
const noexcept
106 return names.
front();
109 [[nodiscard]]
auto begin()
const noexcept
111 return names.
begin();
114 [[nodiscard]]
auto end()
const noexcept
124 [[nodiscard]]
bool is_singular()
const noexcept
126 return names.
size() == 1;
147 for (
hilet index : indices) {
161 hilet size_ = narrow_cast<ssize_t>(size);
163 for (
hilet index : indices) {
164 hilet index_ = index >= 0 ? index : size_ + index;
165 if (index_ >= 0 and index_ < size_) {
166 co_yield narrow_cast<std::size_t>(index_);
173 return indices.
size();
176 [[nodiscard]] ssize_t
const &front()
const noexcept
178 return indices.
front();
181 void push_back(ssize_t rhs)
noexcept
186 [[nodiscard]]
bool is_singular()
const noexcept
188 return indices.
size() == 1;
202 constexpr jsonpath_slice(ssize_t first, ssize_t last, ssize_t step) noexcept : first(first), last(last), step(step) {}
211 hilet size_ = narrow_cast<ssize_t>(size);
212 hilet begin = first >= 0 ? first : size_ + first;
213 return narrow_cast<std::size_t>(std::clamp(begin, 0_z, size_));
226 hilet size_ = narrow_cast<ssize_t>(size);
227 hilet last_ = std::clamp(
234 hilet first_ = begin(size);
235 hilet distance = last_ - first_;
236 hilet steps = distance / step;
237 return narrow_cast<std::size_t>(first_ + steps * step);
240 [[nodiscard]]
bool last_is_empty() const noexcept
247 if (last_is_empty()) {
248 return std::format(
"[{}:e:{}]", first, step);
250 return std::format(
"[{}:{}:{}]", first, last, step);
254 [[nodiscard]]
bool is_singular() const noexcept
261using jsonpath_node = std::variant<
262 jsonpath_root, jsonpath_current, jsonpath_wildcard, jsonpath_descend, jsonpath_names, jsonpath_indices, jsonpath_slice>;
265[[nodiscard]]
inline jsonpath_node parse_jsonpath_slicing_operator(
auto &it,
auto it_end, ssize_t first)
269 if (*it == tokenizer_name_t::IntegerLiteral) {
270 last =
static_cast<ssize_t>(*it);
275 if (*it == tokenizer_name_t::Operator and *it ==
":") {
277 hi_parse_check(*it == tokenizer_name_t::IntegerLiteral,
"Expect integer as third slice argument, got {}.", *it);
278 step =
static_cast<ssize_t>(*it);
282 hi_parse_check(*it == tokenizer_name_t::Operator and *it ==
"]",
"Expected end of slicing operator ']', got {}.", *it);
284 hi_parse_check(step != 0,
"Slicing operator's step must not be zero");
285 return jsonpath_slice{first, last, step};
288[[nodiscard]]
inline jsonpath_node parse_jsonpath_integer_indexing_operator(
auto &it,
auto it_end, ssize_t first)
290 auto tmp = jsonpath_indices(first);
292 while (*it == tokenizer_name_t::Operator and *it ==
",") {
294 hi_parse_check(*it == tokenizer_name_t::IntegerLiteral,
"Expect integer literal after comma ',', got {}.", *it);
295 tmp.push_back(
static_cast<ssize_t>(*it));
299 hi_parse_check(*it == tokenizer_name_t::Operator and *it ==
"]",
"Expected end of slicing operator ']', got {}.", *it);
303[[nodiscard]]
inline jsonpath_node parse_jsonpath_name_indexing_operator(
auto &it,
auto it_end,
std::string first)
305 auto tmp = jsonpath_names(
std::move(first));
307 while (*it == tokenizer_name_t::Operator and *it ==
",") {
309 hi_parse_check(*it == tokenizer_name_t::StringLiteral,
"Expect string literal after comma ',', got {}.", *it);
314 hi_parse_check(*it == tokenizer_name_t::Operator and *it ==
"]",
"Expected end of indexing operator ']', got {}.", *it);
318[[nodiscard]]
inline jsonpath_node parse_jsonpath_indexing_operator(
auto &it,
auto it_end)
322 if (*it == tokenizer_name_t::Operator and *it ==
"*") {
324 hi_parse_check(*it == tokenizer_name_t::Operator and *it ==
"]",
"Expected end of indexing operator ']', got {}.", *it);
325 return jsonpath_wildcard{};
327 }
else if (*it == tokenizer_name_t::Operator and *it ==
":") {
328 return parse_jsonpath_slicing_operator(it, it_end, 0);
330 }
else if (*it == tokenizer_name_t::IntegerLiteral) {
334 if (*it == tokenizer_name_t::Operator and *it ==
":") {
335 return parse_jsonpath_slicing_operator(it, it_end, first);
337 return parse_jsonpath_integer_indexing_operator(it, it_end, first);
340 }
else if (*it == tokenizer_name_t::StringLiteral) {
344 return parse_jsonpath_name_indexing_operator(it, it_end, first);
347 throw parse_error(std::format(
"Expected a integer index or child name after indexing operator '[', got token {}.", *it));
351[[nodiscard]]
inline jsonpath_node parse_jsonpath_child_operator(
auto &it,
auto it_end)
355 if (*it == tokenizer_name_t::Operator and *it ==
"*") {
356 return jsonpath_wildcard{};
358 }
else if (*it == tokenizer_name_t::Operator and *it ==
".") {
359 if (*(it + 1) == tokenizer_name_t::Operator and *(it + 1) ==
"[") {
362 return jsonpath_descend{};
369 return jsonpath_descend{};
372 }
else if (*it == tokenizer_name_t::Name) {
373 return jsonpath_names{
static_cast<std::string>(*it)};
376 throw parse_error(std::format(
"Expected a child name or wildcard, got token {}.", *it));
383 using value_type =
typename container_type::value_type;
384 using iterator =
typename container_type::iterator;
385 using const_iterator =
typename container_type::const_iterator;
387 [[nodiscard]]
jsonpath(std::string_view rhs) : _nodes()
390 hilet it_end = tokens.cend();
391 for (
auto it = tokens.cbegin(); it != it_end; ++it) {
392 if (*it == tokenizer_name_t::Operator and *it ==
".") {
393 _nodes.emplace_back(parse_jsonpath_child_operator(it, it_end));
395 }
else if (*it == tokenizer_name_t::Operator and *it ==
"[") {
396 _nodes.emplace_back(parse_jsonpath_indexing_operator(it, it_end));
398 }
else if (*it == tokenizer_name_t::Name and *it ==
"$") {
399 hi_parse_check(_nodes.empty(),
"Root node '$' not at start of path.");
402 }
else if (*it == tokenizer_name_t::Operator and *it ==
"@") {
403 hi_parse_check(_nodes.empty(),
"Current node '@' not at start of path.");
406 }
else if (*it == tokenizer_name_t::Name) {
407 hi_parse_check(_nodes.empty(),
"Unexpected child name {}.", *it);
410 }
else if (*it == tokenizer_name_t::End) {
414 throw parse_error(std::format(
"Unexpected token {}.", *it));
419 [[nodiscard]]
bool empty()
const noexcept
421 return _nodes.empty();
429 for (
hilet &node : _nodes) {
432 return node_.is_singular();
441 return _nodes.size();
444 [[nodiscard]] iterator begin() noexcept
446 return _nodes.begin();
449 [[nodiscard]] const_iterator
begin() const noexcept
451 return _nodes.begin();
454 [[nodiscard]] const_iterator cbegin() const noexcept
456 return _nodes.cbegin();
459 [[nodiscard]] iterator
end() noexcept
464 [[nodiscard]] const_iterator
end() const noexcept
469 [[nodiscard]] const_iterator cend() const noexcept
471 return _nodes.cend();
477 for (
hilet &node : path._nodes) {
480 return node_.string();
493template<
typename CharT>
494struct std::formatter<
hi::jsonpath, CharT> : std::formatter<char const *, CharT> {
495 auto format(hi::jsonpath
const &t,
auto &fc)
497 return std::formatter<std::string, CharT>{}.format(
to_string(t), fc);
Utilities used by the HikoGUI library itself.
#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:15
std::vector< token_t > parseTokens(std::string_view text) noexcept
The HikoGUI namespace.
Definition ascii.hpp:19
std::ptrdiff_t ssize_t
Signed size/index into an array.
Definition utility.hpp:162
A return value for a generator-function.
Definition generator.hpp:28
Definition jsonpath.hpp:20
Definition jsonpath.hpp:32
Definition jsonpath.hpp:44
Definition jsonpath.hpp:56
Definition jsonpath.hpp:68
Definition jsonpath.hpp:130
Definition jsonpath.hpp:192
std::size_t end(std::size_t size) const noexcept
Get the one-step beyond last offset.
Definition jsonpath.hpp:224
std::size_t begin(std::size_t size) const noexcept
Get the start offset.
Definition jsonpath.hpp:209
Definition jsonpath.hpp:380
bool is_singular() const noexcept
The json-path will result in zero or one match.
Definition jsonpath.hpp:426