aboutsummaryrefslogtreecommitdiff
path: root/include/jsoncons_ext/jmespath
diff options
context:
space:
mode:
authorRichard <q@1bpm.net>2022-09-04 00:32:56 +0100
committerRichard <q@1bpm.net>2022-09-04 00:32:56 +0100
commit1d055261b4144dbf86b2658437015b15d4dd9bff (patch)
tree6049b19d1bf953a650383de1a5e438b8b82679f6 /include/jsoncons_ext/jmespath
downloadcsound-json-1d055261b4144dbf86b2658437015b15d4dd9bff.tar.gz
csound-json-1d055261b4144dbf86b2658437015b15d4dd9bff.tar.bz2
csound-json-1d055261b4144dbf86b2658437015b15d4dd9bff.zip
initial
Diffstat (limited to 'include/jsoncons_ext/jmespath')
-rw-r--r--include/jsoncons_ext/jmespath/jmespath.hpp5215
-rw-r--r--include/jsoncons_ext/jmespath/jmespath_error.hpp215
2 files changed, 5430 insertions, 0 deletions
diff --git a/include/jsoncons_ext/jmespath/jmespath.hpp b/include/jsoncons_ext/jmespath/jmespath.hpp
new file mode 100644
index 0000000..69458cd
--- /dev/null
+++ b/include/jsoncons_ext/jmespath/jmespath.hpp
@@ -0,0 +1,5215 @@
+// Copyright 2020 Daniel Parker
+// Distributed under the Boost license, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+// See https://github.com/danielaparker/jsoncons for latest version
+
+#ifndef JSONCONS_JMESPATH_JMESPATH_HPP
+#define JSONCONS_JMESPATH_JMESPATH_HPP
+
+#include <string>
+#include <vector>
+#include <unordered_map> // std::unordered_map
+#include <memory>
+#include <type_traits> // std::is_const
+#include <limits> // std::numeric_limits
+#include <utility> // std::move
+#include <functional> //
+#include <algorithm> // std::stable_sort, std::reverse
+#include <cmath> // std::abs
+#include <jsoncons/json.hpp>
+#include <jsoncons_ext/jmespath/jmespath_error.hpp>
+
+namespace jsoncons {
+namespace jmespath {
+
+ enum class operator_kind
+ {
+ default_op, // Identifier, CurrentNode, Index, MultiSelectList, MultiSelectHash, FunctionExpression
+ projection_op,
+ flatten_projection_op, // FlattenProjection
+ or_op,
+ and_op,
+ eq_op,
+ ne_op,
+ lt_op,
+ lte_op,
+ gt_op,
+ gte_op,
+ not_op
+ };
+
+ struct operator_table final
+ {
+ static int precedence_level(operator_kind oper)
+ {
+ switch (oper)
+ {
+ case operator_kind::projection_op:
+ return 11;
+ case operator_kind::flatten_projection_op:
+ return 11;
+ case operator_kind::or_op:
+ return 9;
+ case operator_kind::and_op:
+ return 8;
+ case operator_kind::eq_op:
+ case operator_kind::ne_op:
+ return 6;
+ case operator_kind::lt_op:
+ case operator_kind::lte_op:
+ case operator_kind::gt_op:
+ case operator_kind::gte_op:
+ return 5;
+ case operator_kind::not_op:
+ return 1;
+ default:
+ return 1;
+ }
+ }
+
+ static bool is_right_associative(operator_kind oper)
+ {
+ switch (oper)
+ {
+ case operator_kind::not_op:
+ return true;
+ case operator_kind::projection_op:
+ return true;
+ case operator_kind::flatten_projection_op:
+ return false;
+ case operator_kind::or_op:
+ case operator_kind::and_op:
+ case operator_kind::eq_op:
+ case operator_kind::ne_op:
+ case operator_kind::lt_op:
+ case operator_kind::lte_op:
+ case operator_kind::gt_op:
+ case operator_kind::gte_op:
+ return false;
+ default:
+ return false;
+ }
+ }
+ };
+
+ enum class token_kind
+ {
+ current_node,
+ lparen,
+ rparen,
+ begin_multi_select_hash,
+ end_multi_select_hash,
+ begin_multi_select_list,
+ end_multi_select_list,
+ begin_filter,
+ end_filter,
+ pipe,
+ separator,
+ key,
+ literal,
+ expression,
+ binary_operator,
+ unary_operator,
+ function,
+ end_function,
+ argument,
+ begin_expression_type,
+ end_expression_type,
+ end_of_expression
+ };
+
+ struct literal_arg_t
+ {
+ explicit literal_arg_t() = default;
+ };
+ constexpr literal_arg_t literal_arg{};
+
+ struct begin_expression_type_arg_t
+ {
+ explicit begin_expression_type_arg_t() = default;
+ };
+ constexpr begin_expression_type_arg_t begin_expression_type_arg{};
+
+ struct end_expression_type_arg_t
+ {
+ explicit end_expression_type_arg_t() = default;
+ };
+ constexpr end_expression_type_arg_t end_expression_type_arg{};
+
+ struct end_of_expression_arg_t
+ {
+ explicit end_of_expression_arg_t() = default;
+ };
+ constexpr end_of_expression_arg_t end_of_expression_arg{};
+
+ struct separator_arg_t
+ {
+ explicit separator_arg_t() = default;
+ };
+ constexpr separator_arg_t separator_arg{};
+
+ struct key_arg_t
+ {
+ explicit key_arg_t() = default;
+ };
+ constexpr key_arg_t key_arg{};
+
+ struct lparen_arg_t
+ {
+ explicit lparen_arg_t() = default;
+ };
+ constexpr lparen_arg_t lparen_arg{};
+
+ struct rparen_arg_t
+ {
+ explicit rparen_arg_t() = default;
+ };
+ constexpr rparen_arg_t rparen_arg{};
+
+ struct begin_multi_select_hash_arg_t
+ {
+ explicit begin_multi_select_hash_arg_t() = default;
+ };
+ constexpr begin_multi_select_hash_arg_t begin_multi_select_hash_arg{};
+
+ struct end_multi_select_hash_arg_t
+ {
+ explicit end_multi_select_hash_arg_t() = default;
+ };
+ constexpr end_multi_select_hash_arg_t end_multi_select_hash_arg{};
+
+ struct begin_multi_select_list_arg_t
+ {
+ explicit begin_multi_select_list_arg_t() = default;
+ };
+ constexpr begin_multi_select_list_arg_t begin_multi_select_list_arg{};
+
+ struct end_multi_select_list_arg_t
+ {
+ explicit end_multi_select_list_arg_t() = default;
+ };
+ constexpr end_multi_select_list_arg_t end_multi_select_list_arg{};
+
+ struct begin_filter_arg_t
+ {
+ explicit begin_filter_arg_t() = default;
+ };
+ constexpr begin_filter_arg_t begin_filter_arg{};
+
+ struct end_filter_arg_t
+ {
+ explicit end_filter_arg_t() = default;
+ };
+ constexpr end_filter_arg_t end_filter_arg{};
+
+ struct pipe_arg_t
+ {
+ explicit pipe_arg_t() = default;
+ };
+ constexpr pipe_arg_t pipe_arg{};
+
+ struct current_node_arg_t
+ {
+ explicit current_node_arg_t() = default;
+ };
+ constexpr current_node_arg_t current_node_arg{};
+
+ struct end_function_arg_t
+ {
+ explicit end_function_arg_t() = default;
+ };
+ constexpr end_function_arg_t end_function_arg{};
+
+ struct argument_arg_t
+ {
+ explicit argument_arg_t() = default;
+ };
+ constexpr argument_arg_t argument_arg{};
+
+ struct slice
+ {
+ jsoncons::optional<int64_t> start_;
+ jsoncons::optional<int64_t> stop_;
+ int64_t step_;
+
+ slice()
+ : start_(), stop_(), step_(1)
+ {
+ }
+
+ slice(const jsoncons::optional<int64_t>& start, const jsoncons::optional<int64_t>& end, int64_t step)
+ : start_(start), stop_(end), step_(step)
+ {
+ }
+
+ slice(const slice& other)
+ : start_(other.start_), stop_(other.stop_), step_(other.step_)
+ {
+ }
+
+ slice& operator=(const slice& rhs)
+ {
+ if (this != &rhs)
+ {
+ if (rhs.start_)
+ {
+ start_ = rhs.start_;
+ }
+ else
+ {
+ start_.reset();
+ }
+ if (rhs.stop_)
+ {
+ stop_ = rhs.stop_;
+ }
+ else
+ {
+ stop_.reset();
+ }
+ step_ = rhs.step_;
+ }
+ return *this;
+ }
+
+ int64_t get_start(std::size_t size) const
+ {
+ if (start_)
+ {
+ auto len = *start_ >= 0 ? *start_ : (static_cast<int64_t>(size) + *start_);
+ return len <= static_cast<int64_t>(size) ? len : static_cast<int64_t>(size);
+ }
+ else
+ {
+ if (step_ >= 0)
+ {
+ return 0;
+ }
+ else
+ {
+ return static_cast<int64_t>(size);
+ }
+ }
+ }
+
+ int64_t get_stop(std::size_t size) const
+ {
+ if (stop_)
+ {
+ auto len = *stop_ >= 0 ? *stop_ : (static_cast<int64_t>(size) + *stop_);
+ return len <= static_cast<int64_t>(size) ? len : static_cast<int64_t>(size);
+ }
+ else
+ {
+ return step_ >= 0 ? static_cast<int64_t>(size) : -1;
+ }
+ }
+
+ int64_t step() const
+ {
+ return step_; // Allow negative
+ }
+ };
+
+ namespace detail {
+
+ enum class path_state
+ {
+ start,
+ lhs_expression,
+ rhs_expression,
+ sub_expression,
+ expression_type,
+ comparator_expression,
+ function_expression,
+ argument,
+ expression_or_expression_type,
+ quoted_string,
+ raw_string,
+ raw_string_escape_char,
+ quoted_string_escape_char,
+ escape_u1,
+ escape_u2,
+ escape_u3,
+ escape_u4,
+ escape_expect_surrogate_pair1,
+ escape_expect_surrogate_pair2,
+ escape_u5,
+ escape_u6,
+ escape_u7,
+ escape_u8,
+ literal,
+ key_expr,
+ val_expr,
+ identifier_or_function_expr,
+ unquoted_string,
+ key_val_expr,
+ number,
+ digit,
+ index_or_slice_expression,
+ bracket_specifier,
+ bracket_specifier_or_multi_select_list,
+ filter,
+ multi_select_list,
+ multi_select_hash,
+ rhs_slice_expression_stop,
+ rhs_slice_expression_step,
+ expect_rbracket,
+ expect_rparen,
+ expect_dot,
+ expect_rbrace,
+ expect_colon,
+ expect_multi_select_list,
+ cmp_lt_or_lte,
+ cmp_eq,
+ cmp_gt_or_gte,
+ cmp_ne,
+ expect_pipe_or_or,
+ expect_and
+ };
+
+ // dynamic_resources
+
+ template<class Json, class JsonReference>
+ class dynamic_resources
+ {
+ typedef typename Json::char_type char_type;
+ typedef typename Json::char_traits_type char_traits_type;
+ typedef std::basic_string<char_type,char_traits_type> string_type;
+ typedef typename Json::string_view_type string_view_type;
+ typedef JsonReference reference;
+ using pointer = typename std::conditional<std::is_const<typename std::remove_reference<JsonReference>::type>::value,typename Json::const_pointer,typename Json::pointer>::type;
+ typedef typename Json::const_pointer const_pointer;
+
+ std::vector<std::unique_ptr<Json>> temp_storage_;
+
+ public:
+ ~dynamic_resources()
+ {
+ }
+
+ reference number_type_name()
+ {
+ static Json number_type_name(JSONCONS_STRING_CONSTANT(char_type, "number"));
+
+ return number_type_name;
+ }
+
+ reference boolean_type_name()
+ {
+ static Json boolean_type_name(JSONCONS_STRING_CONSTANT(char_type, "boolean"));
+
+ return boolean_type_name;
+ }
+
+ reference string_type_name()
+ {
+ static Json string_type_name(JSONCONS_STRING_CONSTANT(char_type, "string"));
+
+ return string_type_name;
+ }
+
+ reference object_type_name()
+ {
+ static Json object_type_name(JSONCONS_STRING_CONSTANT(char_type, "object"));
+
+ return object_type_name;
+ }
+
+ reference array_type_name()
+ {
+ static Json array_type_name(JSONCONS_STRING_CONSTANT(char_type, "array"));
+
+ return array_type_name;
+ }
+
+ reference null_type_name()
+ {
+ static Json null_type_name(JSONCONS_STRING_CONSTANT(char_type, "null"));
+
+ return null_type_name;
+ }
+
+ reference true_value() const
+ {
+ static const Json true_value(true, semantic_tag::none);
+ return true_value;
+ }
+
+ reference false_value() const
+ {
+ static const Json false_value(false, semantic_tag::none);
+ return false_value;
+ }
+
+ reference null_value() const
+ {
+ static const Json null_value(null_type(), semantic_tag::none);
+ return null_value;
+ }
+
+ template <typename... Args>
+ Json* create_json(Args&& ... args)
+ {
+ auto temp = jsoncons::make_unique<Json>(std::forward<Args>(args)...);
+ Json* ptr = temp.get();
+ temp_storage_.emplace_back(std::move(temp));
+ return ptr;
+ }
+ };
+
+ template<class Json, class JsonReference>
+ class jmespath_evaluator
+ {
+ public:
+ typedef typename Json::char_type char_type;
+ typedef typename Json::char_traits_type char_traits_type;
+ typedef std::basic_string<char_type,char_traits_type> string_type;
+ typedef typename Json::string_view_type string_view_type;
+ typedef JsonReference reference;
+ using pointer = typename std::conditional<std::is_const<typename std::remove_reference<JsonReference>::type>::value,typename Json::const_pointer,typename Json::pointer>::type;
+ typedef typename Json::const_pointer const_pointer;
+
+ static bool is_false(reference ref)
+ {
+ return (ref.is_array() && ref.empty()) ||
+ (ref.is_object() && ref.empty()) ||
+ (ref.is_string() && ref.as_string_view().size() == 0) ||
+ (ref.is_bool() && !ref.as_bool()) ||
+ ref.is_null();
+ }
+
+ static bool is_true(reference ref)
+ {
+ return !is_false(ref);
+ }
+
+ class unary_operator
+ {
+ std::size_t precedence_level_;
+ bool is_right_associative_;
+
+ protected:
+ ~unary_operator() = default; // virtual destructor not needed
+ public:
+ unary_operator(operator_kind oper)
+ : precedence_level_(operator_table::precedence_level(oper)),
+ is_right_associative_(operator_table::is_right_associative(oper))
+ {
+ }
+
+ std::size_t precedence_level() const
+ {
+ return precedence_level_;
+ }
+ bool is_right_associative() const
+ {
+ return is_right_associative_;
+ }
+
+ virtual reference evaluate(reference val, dynamic_resources<Json,JsonReference>&, std::error_code& ec) const = 0;
+ };
+
+ class not_expression final : public unary_operator
+ {
+ public:
+ not_expression()
+ : unary_operator(operator_kind::not_op)
+ {}
+
+ reference evaluate(reference val, dynamic_resources<Json,JsonReference>& resources, std::error_code&) const override
+ {
+ return is_false(val) ? resources.true_value() : resources.false_value();
+ }
+ };
+
+ class binary_operator
+ {
+ std::size_t precedence_level_;
+ bool is_right_associative_;
+ protected:
+ ~binary_operator() = default; // virtual destructor not needed
+ public:
+ binary_operator(operator_kind oper)
+ : precedence_level_(operator_table::precedence_level(oper)),
+ is_right_associative_(operator_table::is_right_associative(oper))
+ {
+ }
+
+
+ std::size_t precedence_level() const
+ {
+ return precedence_level_;
+ }
+ bool is_right_associative() const
+ {
+ return is_right_associative_;
+ }
+
+ virtual reference evaluate(reference lhs, reference rhs, dynamic_resources<Json,JsonReference>&, std::error_code& ec) const = 0;
+
+ virtual std::string to_string(std::size_t indent = 0) const
+ {
+ std::string s;
+ for (std::size_t i = 0; i <= indent; ++i)
+ {
+ s.push_back(' ');
+ }
+ s.append("to_string not implemented\n");
+ return s;
+ }
+ };
+
+ // expression_base
+ class expression_base
+ {
+ std::size_t precedence_level_;
+ bool is_right_associative_;
+ bool is_projection_;
+ public:
+ expression_base(operator_kind oper, bool is_projection)
+ : precedence_level_(operator_table::precedence_level(oper)),
+ is_right_associative_(operator_table::is_right_associative(oper)),
+ is_projection_(is_projection)
+ {
+ }
+
+ std::size_t precedence_level() const
+ {
+ return precedence_level_;
+ }
+
+ bool is_right_associative() const
+ {
+ return is_right_associative_;
+ }
+
+ bool is_projection() const
+ {
+ return is_projection_;
+ }
+
+ virtual ~expression_base() = default;
+
+ virtual reference evaluate(reference val, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const = 0;
+
+ virtual void add_expression(std::unique_ptr<expression_base>&& expressions) = 0;
+
+ virtual std::string to_string(std::size_t = 0) const
+ {
+ return std::string("to_string not implemented");
+ }
+ };
+
+ // parameter
+
+ enum class parameter_kind{value, expression};
+
+ class parameter
+ {
+ parameter_kind type_;
+
+ union
+ {
+ expression_base* expression_;
+ pointer value_;
+ };
+
+ public:
+
+ parameter(const parameter& other) noexcept
+ : type_(other.type_)
+ {
+ switch (type_)
+ {
+ case parameter_kind::expression:
+ expression_ = other.expression_;
+ break;
+ case parameter_kind::value:
+ value_ = other.value_;
+ break;
+ default:
+ break;
+ }
+ }
+
+ parameter(reference value) noexcept
+ : type_(parameter_kind::value), value_(std::addressof(value))
+ {
+ }
+
+ parameter(expression_base* expression) noexcept
+ : type_(parameter_kind::expression), expression_(expression)
+ {
+ }
+
+ parameter& operator=(const parameter& other)
+ {
+ if (&other != this)
+ {
+ type_ = other.type_;
+ switch (type_)
+ {
+ case parameter_kind::expression:
+ expression_ = other.expression_;
+ break;
+ case parameter_kind::value:
+ value_ = other.value_;
+ break;
+ default:
+ break;
+ }
+ }
+ return *this;
+ }
+
+ bool is_value() const
+ {
+ return type_ == parameter_kind::value;
+ }
+
+ bool is_expression() const
+ {
+ return type_ == parameter_kind::expression;
+ }
+
+ const Json& value() const
+ {
+ return *value_;
+ }
+
+ const expression_base& expression() const
+ {
+ return *expression_;
+ }
+ };
+
+ // function_base
+ class function_base
+ {
+ jsoncons::optional<std::size_t> arg_count_;
+ public:
+ function_base(jsoncons::optional<std::size_t> arg_count)
+ : arg_count_(arg_count)
+ {
+ }
+
+ jsoncons::optional<std::size_t> arity() const
+ {
+ return arg_count_;
+ }
+
+ virtual ~function_base() = default;
+
+ virtual reference evaluate(std::vector<parameter>& args, dynamic_resources<Json,JsonReference>&, std::error_code& ec) const = 0;
+
+ virtual std::string to_string(std::size_t = 0) const
+ {
+ return std::string("to_string not implemented");
+ }
+ };
+
+ class abs_function : public function_base
+ {
+ public:
+ abs_function()
+ : function_base(1)
+ {
+ }
+
+ reference evaluate(std::vector<parameter>& args, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ JSONCONS_ASSERT(args.size() == *this->arity());
+
+ if (!args[0].is_value())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ reference arg0 = args[0].value();
+ switch (arg0.type())
+ {
+ case json_type::uint64_value:
+ return arg0;
+ case json_type::int64_value:
+ {
+ return arg0.template as<int64_t>() >= 0 ? arg0 : *resources.create_json(std::abs(arg0.template as<int64_t>()));
+ }
+ case json_type::double_value:
+ {
+ return arg0.template as<double>() >= 0 ? arg0 : *resources.create_json(std::abs(arg0.template as<double>()));
+ }
+ default:
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+ }
+ }
+ };
+
+ class avg_function : public function_base
+ {
+ public:
+ avg_function()
+ : function_base(1)
+ {
+ }
+
+ reference evaluate(std::vector<parameter>& args, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ JSONCONS_ASSERT(args.size() == *this->arity());
+
+ if (!args[0].is_value())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ reference arg0 = args[0].value();
+ if (!arg0.is_array())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+ if (arg0.empty())
+ {
+ return resources.null_value();
+ }
+
+ double sum = 0;
+ for (auto& j : arg0.array_range())
+ {
+ if (!j.is_number())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+ sum += j.template as<double>();
+ }
+
+ return sum == 0 ? resources.null_value() : *resources.create_json(sum/arg0.size());
+ }
+ };
+
+ class ceil_function : public function_base
+ {
+ public:
+ ceil_function()
+ : function_base(1)
+ {
+ }
+
+ reference evaluate(std::vector<parameter>& args, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ JSONCONS_ASSERT(args.size() == *this->arity());
+
+ if (!args[0].is_value())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ reference arg0 = args[0].value();
+ switch (arg0.type())
+ {
+ case json_type::uint64_value:
+ case json_type::int64_value:
+ {
+ return *resources.create_json(arg0.template as<double>());
+ }
+ case json_type::double_value:
+ {
+ return *resources.create_json(std::ceil(arg0.template as<double>()));
+ }
+ default:
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+ }
+ };
+
+ class contains_function : public function_base
+ {
+ public:
+ contains_function()
+ : function_base(2)
+ {
+ }
+
+ reference evaluate(std::vector<parameter>& args, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ JSONCONS_ASSERT(args.size() == *this->arity());
+
+ if (!(args[0].is_value() && args[1].is_value()))
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+
+ reference arg0 = args[0].value();
+ reference arg1 = args[1].value();
+
+ switch (arg0.type())
+ {
+ case json_type::array_value:
+ for (auto& j : arg0.array_range())
+ {
+ if (j == arg1)
+ {
+ return resources.true_value();
+ }
+ }
+ return resources.false_value();
+ case json_type::string_value:
+ {
+ if (!arg1.is_string())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+ auto sv0 = arg0.template as<string_view_type>();
+ auto sv1 = arg1.template as<string_view_type>();
+ return sv0.find(sv1) != string_view_type::npos ? resources.true_value() : resources.false_value();
+ }
+ default:
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+ }
+ }
+ };
+
+ class ends_with_function : public function_base
+ {
+ public:
+ ends_with_function()
+ : function_base(2)
+ {
+ }
+
+ reference evaluate(std::vector<parameter>& args, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ JSONCONS_ASSERT(args.size() == *this->arity());
+
+ if (!(args[0].is_value() && args[1].is_value()))
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ reference arg0 = args[0].value();
+ if (!arg0.is_string())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ reference arg1 = args[1].value();
+ if (!arg1.is_string())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ auto sv0 = arg0.template as<string_view_type>();
+ auto sv1 = arg1.template as<string_view_type>();
+
+ if (sv1.length() <= sv0.length() && sv1 == sv0.substr(sv0.length() - sv1.length()))
+ {
+ return resources.true_value();
+ }
+ else
+ {
+ return resources.false_value();
+ }
+ }
+ };
+
+ class floor_function : public function_base
+ {
+ public:
+ floor_function()
+ : function_base(1)
+ {
+ }
+
+ reference evaluate(std::vector<parameter>& args, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ JSONCONS_ASSERT(args.size() == *this->arity());
+
+ if (!args[0].is_value())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ reference arg0 = args[0].value();
+ switch (arg0.type())
+ {
+ case json_type::uint64_value:
+ case json_type::int64_value:
+ {
+ return *resources.create_json(arg0.template as<double>());
+ }
+ case json_type::double_value:
+ {
+ return *resources.create_json(std::floor(arg0.template as<double>()));
+ }
+ default:
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+ }
+ };
+
+ class join_function : public function_base
+ {
+ public:
+ join_function()
+ : function_base(2)
+ {
+ }
+
+ reference evaluate(std::vector<parameter>& args, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ JSONCONS_ASSERT(args.size() == *this->arity());
+
+ reference arg0 = args[0].value();
+ reference arg1 = args[1].value();
+
+ if (!(args[0].is_value() && args[1].is_value()))
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ if (!arg0.is_string())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+ if (!arg1.is_array())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ string_type sep = arg0.template as<string_type>();
+ string_type buf;
+ for (auto& j : arg1.array_range())
+ {
+ if (!j.is_string())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+ if (!buf.empty())
+ {
+ buf.append(sep);
+ }
+ auto sv = j.template as<string_view_type>();
+ buf.append(sv.begin(), sv.end());
+ }
+ return *resources.create_json(buf);
+ }
+ };
+
+ class length_function : public function_base
+ {
+ public:
+ length_function()
+ : function_base(1)
+ {
+ }
+
+ reference evaluate(std::vector<parameter>& args, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ JSONCONS_ASSERT(args.size() == *this->arity());
+
+ if (!args[0].is_value())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ reference arg0 = args[0].value();
+
+ switch (arg0.type())
+ {
+ case json_type::object_value:
+ case json_type::array_value:
+ return *resources.create_json(arg0.size());
+ case json_type::string_value:
+ {
+ auto sv0 = arg0.template as<string_view_type>();
+ auto length = unicode_traits::count_codepoints(sv0.data(), sv0.size());
+ return *resources.create_json(length);
+ }
+ default:
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+ }
+ }
+ };
+
+ class max_function : public function_base
+ {
+ public:
+ max_function()
+ : function_base(1)
+ {
+ }
+
+ reference evaluate(std::vector<parameter>& args, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ JSONCONS_ASSERT(args.size() == *this->arity());
+
+ if (!args[0].is_value())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ reference arg0 = args[0].value();
+ if (!arg0.is_array())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+ if (arg0.empty())
+ {
+ return resources.null_value();
+ }
+
+ bool is_number = arg0.at(0).is_number();
+ bool is_string = arg0.at(0).is_string();
+ if (!is_number && !is_string)
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ std::size_t index = 0;
+ for (std::size_t i = 1; i < arg0.size(); ++i)
+ {
+ if (!(arg0.at(i).is_number() == is_number && arg0.at(i).is_string() == is_string))
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+ if (arg0.at(i) > arg0.at(index))
+ {
+ index = i;
+ }
+ }
+
+ return arg0.at(index);
+ }
+ };
+
+ class max_by_function : public function_base
+ {
+ public:
+ max_by_function()
+ : function_base(2)
+ {
+ }
+
+ reference evaluate(std::vector<parameter>& args, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ JSONCONS_ASSERT(args.size() == *this->arity());
+
+ if (!(args[0].is_value() && args[1].is_expression()))
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ reference arg0 = args[0].value();
+ if (!arg0.is_array())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+ if (arg0.empty())
+ {
+ return resources.null_value();
+ }
+
+ const auto& expr = args[1].expression();
+
+ std::error_code ec2;
+ Json key1 = expr.evaluate(arg0.at(0), resources, ec2);
+
+ bool is_number = key1.is_number();
+ bool is_string = key1.is_string();
+ if (!(is_number || is_string))
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ std::size_t index = 0;
+ for (std::size_t i = 1; i < arg0.size(); ++i)
+ {
+ reference key2 = expr.evaluate(arg0.at(i), resources, ec2);
+ if (!(key2.is_number() == is_number && key2.is_string() == is_string))
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+ if (key2 > key1)
+ {
+ key1 = key2;
+ index = i;
+ }
+ }
+
+ return arg0.at(index);
+ }
+ };
+
+ class map_function : public function_base
+ {
+ public:
+ map_function()
+ : function_base(2)
+ {
+ }
+
+ reference evaluate(std::vector<parameter>& args, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ JSONCONS_ASSERT(args.size() == *this->arity());
+
+ if (!(args[0].is_expression() && args[1].is_value()))
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+ const auto& expr = args[0].expression();
+
+ reference arg0 = args[1].value();
+ if (!arg0.is_array())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ auto result = resources.create_json(json_array_arg);
+
+ for (auto& item : arg0.array_range())
+ {
+ auto& j = expr.evaluate(item, resources, ec);
+ if (ec)
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+ result->emplace_back(json_const_pointer_arg, std::addressof(j));
+ }
+
+ return *result;
+ }
+
+ std::string to_string(std::size_t = 0) const override
+ {
+ return std::string("map_function\n");
+ }
+ };
+
+ class min_function : public function_base
+ {
+ public:
+ min_function()
+ : function_base(1)
+ {
+ }
+
+ reference evaluate(std::vector<parameter>& args, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ JSONCONS_ASSERT(args.size() == *this->arity());
+
+ if (!args[0].is_value())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ reference arg0 = args[0].value();
+ if (!arg0.is_array())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+ if (arg0.empty())
+ {
+ return resources.null_value();
+ }
+
+ bool is_number = arg0.at(0).is_number();
+ bool is_string = arg0.at(0).is_string();
+ if (!is_number && !is_string)
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ std::size_t index = 0;
+ for (std::size_t i = 1; i < arg0.size(); ++i)
+ {
+ if (!(arg0.at(i).is_number() == is_number && arg0.at(i).is_string() == is_string))
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+ if (arg0.at(i) < arg0.at(index))
+ {
+ index = i;
+ }
+ }
+
+ return arg0.at(index);
+ }
+ };
+
+ class min_by_function : public function_base
+ {
+ public:
+ min_by_function()
+ : function_base(2)
+ {
+ }
+
+ reference evaluate(std::vector<parameter>& args, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ JSONCONS_ASSERT(args.size() == *this->arity());
+
+ if (!(args[0].is_value() && args[1].is_expression()))
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ reference arg0 = args[0].value();
+ if (!arg0.is_array())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+ if (arg0.empty())
+ {
+ return resources.null_value();
+ }
+
+ const auto& expr = args[1].expression();
+
+ std::error_code ec2;
+ Json key1 = expr.evaluate(arg0.at(0), resources, ec2);
+
+ bool is_number = key1.is_number();
+ bool is_string = key1.is_string();
+ if (!(is_number || is_string))
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ std::size_t index = 0;
+ for (std::size_t i = 1; i < arg0.size(); ++i)
+ {
+ reference key2 = expr.evaluate(arg0.at(i), resources, ec2);
+ if (!(key2.is_number() == is_number && key2.is_string() == is_string))
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+ if (key2 < key1)
+ {
+ key1 = key2;
+ index = i;
+ }
+ }
+
+ return arg0.at(index);
+ }
+ };
+
+ class merge_function : public function_base
+ {
+ public:
+ merge_function()
+ : function_base(jsoncons::optional<std::size_t>())
+ {
+ }
+
+ reference evaluate(std::vector<parameter>& args, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ if (args.empty())
+ {
+ ec = jmespath_errc::invalid_arity;
+ return resources.null_value();
+ }
+
+ for (auto& param : args)
+ {
+ if (!param.is_value())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+ }
+
+ reference arg0 = args[0].value();
+ if (!arg0.is_object())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+ if (args.size() == 1)
+ {
+ return arg0;
+ }
+
+ auto result = resources.create_json(arg0);
+ for (std::size_t i = 1; i < args.size(); ++i)
+ {
+ reference argi = args[i].value();
+ if (!argi.is_object())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+ for (auto& item : argi.object_range())
+ {
+ result->insert_or_assign(item.key(),item.value());
+ }
+ }
+
+ return *result;
+ }
+ };
+
+ class type_function : public function_base
+ {
+ public:
+ type_function()
+ : function_base(1)
+ {
+ }
+
+ reference evaluate(std::vector<parameter>& args, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ JSONCONS_ASSERT(args.size() == *this->arity());
+
+ if (!args[0].is_value())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ reference arg0 = args[0].value();
+
+ switch (arg0.type())
+ {
+ case json_type::int64_value:
+ case json_type::uint64_value:
+ case json_type::double_value:
+ return resources.number_type_name();
+ case json_type::bool_value:
+ return resources.boolean_type_name();
+ case json_type::string_value:
+ return resources.string_type_name();
+ case json_type::object_value:
+ return resources.object_type_name();
+ case json_type::array_value:
+ return resources.array_type_name();
+ default:
+ return resources.null_type_name();
+ break;
+
+ }
+ }
+ };
+
+ class sort_function : public function_base
+ {
+ public:
+ sort_function()
+ : function_base(1)
+ {
+ }
+
+ reference evaluate(std::vector<parameter>& args, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ JSONCONS_ASSERT(args.size() == *this->arity());
+
+ if (!args[0].is_value())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ reference arg0 = args[0].value();
+ if (!arg0.is_array())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+ if (arg0.size() <= 1)
+ {
+ return arg0;
+ }
+
+ bool is_number = arg0.at(0).is_number();
+ bool is_string = arg0.at(0).is_string();
+ if (!is_number && !is_string)
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ for (std::size_t i = 1; i < arg0.size(); ++i)
+ {
+ if (arg0.at(i).is_number() != is_number || arg0.at(i).is_string() != is_string)
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+ }
+
+ auto v = resources.create_json(arg0);
+ std::stable_sort((v->array_range()).begin(), (v->array_range()).end());
+ return *v;
+ }
+ };
+
+ class sort_by_function : public function_base
+ {
+ public:
+ sort_by_function()
+ : function_base(2)
+ {
+ }
+
+ reference evaluate(std::vector<parameter>& args, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ JSONCONS_ASSERT(args.size() == *this->arity());
+
+ if (!(args[0].is_value() && args[1].is_expression()))
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ reference arg0 = args[0].value();
+ if (!arg0.is_array())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+ if (arg0.size() <= 1)
+ {
+ return arg0;
+ }
+
+ const auto& expr = args[1].expression();
+
+ auto v = resources.create_json(arg0);
+ std::stable_sort((v->array_range()).begin(), (v->array_range()).end(),
+ [&expr,&resources,&ec](reference lhs, reference rhs) -> bool
+ {
+ std::error_code ec2;
+ reference key1 = expr.evaluate(lhs, resources, ec2);
+ bool is_number = key1.is_number();
+ bool is_string = key1.is_string();
+ if (!(is_number || is_string))
+ {
+ ec = jmespath_errc::invalid_type;
+ }
+
+ reference key2 = expr.evaluate(rhs, resources, ec2);
+ if (!(key2.is_number() == is_number && key2.is_string() == is_string))
+ {
+ ec = jmespath_errc::invalid_type;
+ }
+
+ return key1 < key2;
+ });
+ return ec ? resources.null_value() : *v;
+ }
+
+ std::string to_string(std::size_t = 0) const override
+ {
+ return std::string("sort_by_function\n");
+ }
+ };
+
+ class keys_function final : public function_base
+ {
+ public:
+ keys_function()
+ : function_base(1)
+ {
+ }
+
+ reference evaluate(std::vector<parameter>& args, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ JSONCONS_ASSERT(args.size() == *this->arity());
+
+ if (!args[0].is_value())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ reference arg0 = args[0].value();
+ if (!arg0.is_object())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ auto result = resources.create_json(json_array_arg);
+ result->reserve(args.size());
+
+ for (auto& item : arg0.object_range())
+ {
+ result->emplace_back(item.key());
+ }
+ return *result;
+ }
+ };
+
+ class values_function final : public function_base
+ {
+ public:
+ values_function()
+ : function_base(1)
+ {
+ }
+
+ reference evaluate(std::vector<parameter>& args, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ JSONCONS_ASSERT(args.size() == *this->arity());
+
+ if (!args[0].is_value())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ reference arg0 = args[0].value();
+ if (!arg0.is_object())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ auto result = resources.create_json(json_array_arg);
+ result->reserve(args.size());
+
+ for (auto& item : arg0.object_range())
+ {
+ result->emplace_back(item.value());
+ }
+ return *result;
+ }
+ };
+
+ class reverse_function final : public function_base
+ {
+ public:
+ reverse_function()
+ : function_base(1)
+ {
+ }
+
+ reference evaluate(std::vector<parameter>& args, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ JSONCONS_ASSERT(args.size() == *this->arity());
+
+ if (!args[0].is_value())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ reference arg0 = args[0].value();
+ switch (arg0.type())
+ {
+ case json_type::string_value:
+ {
+ string_view_type sv = arg0.as_string_view();
+ std::basic_string<char32_t> buf;
+ unicode_traits::convert(sv.data(), sv.size(), buf);
+ std::reverse(buf.begin(), buf.end());
+ string_type s;
+ unicode_traits::convert(buf.data(), buf.size(), s);
+ return *resources.create_json(s);
+ }
+ case json_type::array_value:
+ {
+ auto result = resources.create_json(arg0);
+ std::reverse(result->array_range().begin(),result->array_range().end());
+ return *result;
+ }
+ default:
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+ }
+ };
+
+ class starts_with_function : public function_base
+ {
+ public:
+ starts_with_function()
+ : function_base(2)
+ {
+ }
+
+ reference evaluate(std::vector<parameter>& args, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ JSONCONS_ASSERT(args.size() == *this->arity());
+
+ if (!(args[0].is_value() && args[1].is_value()))
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ reference arg0 = args[0].value();
+ if (!arg0.is_string())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ reference arg1 = args[1].value();
+ if (!arg1.is_string())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ auto sv0 = arg0.template as<string_view_type>();
+ auto sv1 = arg1.template as<string_view_type>();
+
+ if (sv1.length() <= sv0.length() && sv1 == sv0.substr(0, sv1.length()))
+ {
+ return resources.true_value();
+ }
+ else
+ {
+ return resources.false_value();
+ }
+ }
+ };
+
+ class sum_function : public function_base
+ {
+ public:
+ sum_function()
+ : function_base(1)
+ {
+ }
+
+ reference evaluate(std::vector<parameter>& args, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ JSONCONS_ASSERT(args.size() == *this->arity());
+
+ if (!args[0].is_value())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ reference arg0 = args[0].value();
+ if (!arg0.is_array())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+ double sum = 0;
+ for (auto& j : arg0.array_range())
+ {
+ if (!j.is_number())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+ sum += j.template as<double>();
+ }
+
+ return *resources.create_json(sum);
+ }
+ };
+
+ class to_array_function final : public function_base
+ {
+ public:
+ to_array_function()
+ : function_base(1)
+ {
+ }
+
+ reference evaluate(std::vector<parameter>& args, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ JSONCONS_ASSERT(args.size() == *this->arity());
+
+ if (!args[0].is_value())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ reference arg0 = args[0].value();
+ if (arg0.is_array())
+ {
+ return arg0;
+ }
+ else
+ {
+ auto result = resources.create_json(json_array_arg);
+ result->push_back(arg0);
+ return *result;
+ }
+ }
+
+ std::string to_string(std::size_t = 0) const override
+ {
+ return std::string("to_array_function\n");
+ }
+ };
+
+ class to_number_function final : public function_base
+ {
+ public:
+ to_number_function()
+ : function_base(1)
+ {
+ }
+
+ reference evaluate(std::vector<parameter>& args, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ JSONCONS_ASSERT(args.size() == *this->arity());
+
+ if (!args[0].is_value())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ reference arg0 = args[0].value();
+ switch (arg0.type())
+ {
+ case json_type::int64_value:
+ case json_type::uint64_value:
+ case json_type::double_value:
+ return arg0;
+ case json_type::string_value:
+ {
+ auto sv = arg0.as_string_view();
+ uint64_t uval{ 0 };
+ auto result1 = jsoncons::detail::to_integer(sv.data(), sv.length(), uval);
+ if (result1)
+ {
+ return *resources.create_json(uval);
+ }
+ int64_t sval{ 0 };
+ auto result2 = jsoncons::detail::to_integer(sv.data(), sv.length(), sval);
+ if (result2)
+ {
+ return *resources.create_json(sval);
+ }
+ jsoncons::detail::chars_to to_double;
+ try
+ {
+ auto s = arg0.as_string();
+ double d = to_double(s.c_str(), s.length());
+ return *resources.create_json(d);
+ }
+ catch (const std::exception&)
+ {
+ return resources.null_value();
+ }
+ }
+ default:
+ return resources.null_value();
+ }
+ }
+
+ std::string to_string(std::size_t = 0) const override
+ {
+ return std::string("to_number_function\n");
+ }
+ };
+
+ class to_string_function final : public function_base
+ {
+ public:
+ to_string_function()
+ : function_base(1)
+ {
+ }
+
+ reference evaluate(std::vector<parameter>& args, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ JSONCONS_ASSERT(args.size() == *this->arity());
+
+ if (!args[0].is_value())
+ {
+ ec = jmespath_errc::invalid_type;
+ return resources.null_value();
+ }
+
+ reference arg0 = args[0].value();
+ return *resources.create_json(arg0.template as<string_type>());
+ }
+
+ std::string to_string(std::size_t = 0) const override
+ {
+ return std::string("to_string_function\n");
+ }
+ };
+
+ class not_null_function final : public function_base
+ {
+ public:
+ not_null_function()
+ : function_base(jsoncons::optional<std::size_t>())
+ {
+ }
+
+ reference evaluate(std::vector<parameter>& args, dynamic_resources<Json,JsonReference>& resources, std::error_code&) const override
+ {
+ for (auto& param : args)
+ {
+ if (param.is_value() && !param.value().is_null())
+ {
+ return param.value();
+ }
+ }
+ return resources.null_value();
+ }
+
+ std::string to_string(std::size_t = 0) const override
+ {
+ return std::string("to_string_function\n");
+ }
+ };
+
+ // token
+
+ class token
+ {
+ public:
+ token_kind type_;
+
+ union
+ {
+ std::unique_ptr<expression_base> expression_;
+ const unary_operator* unary_operator_;
+ const binary_operator* binary_operator_;
+ const function_base* function_;
+ Json value_;
+ string_type key_;
+ };
+ public:
+
+ token(current_node_arg_t) noexcept
+ : type_(token_kind::current_node)
+ {
+ }
+
+ token(end_function_arg_t) noexcept
+ : type_(token_kind::end_function)
+ {
+ }
+
+ token(separator_arg_t) noexcept
+ : type_(token_kind::separator)
+ {
+ }
+
+ token(lparen_arg_t) noexcept
+ : type_(token_kind::lparen)
+ {
+ }
+
+ token(rparen_arg_t) noexcept
+ : type_(token_kind::rparen)
+ {
+ }
+
+ token(end_of_expression_arg_t) noexcept
+ : type_(token_kind::end_of_expression)
+ {
+ }
+
+ token(begin_multi_select_hash_arg_t) noexcept
+ : type_(token_kind::begin_multi_select_hash)
+ {
+ }
+
+ token(end_multi_select_hash_arg_t) noexcept
+ : type_(token_kind::end_multi_select_hash)
+ {
+ }
+
+ token(begin_multi_select_list_arg_t) noexcept
+ : type_(token_kind::begin_multi_select_list)
+ {
+ }
+
+ token(end_multi_select_list_arg_t) noexcept
+ : type_(token_kind::end_multi_select_list)
+ {
+ }
+
+ token(begin_filter_arg_t) noexcept
+ : type_(token_kind::begin_filter)
+ {
+ }
+
+ token(end_filter_arg_t) noexcept
+ : type_(token_kind::end_filter)
+ {
+ }
+
+ token(pipe_arg_t) noexcept
+ : type_(token_kind::pipe)
+ {
+ }
+
+ token(key_arg_t, const string_type& key)
+ : type_(token_kind::key)
+ {
+ new (&key_) string_type(key);
+ }
+
+ token(std::unique_ptr<expression_base>&& expression)
+ : type_(token_kind::expression)
+ {
+ new (&expression_) std::unique_ptr<expression_base>(std::move(expression));
+ }
+
+ token(const unary_operator* expression) noexcept
+ : type_(token_kind::unary_operator),
+ unary_operator_(expression)
+ {
+ }
+
+ token(const binary_operator* expression) noexcept
+ : type_(token_kind::binary_operator),
+ binary_operator_(expression)
+ {
+ }
+
+ token(const function_base* function) noexcept
+ : type_(token_kind::function),
+ function_(function)
+ {
+ }
+
+ token(argument_arg_t) noexcept
+ : type_(token_kind::argument)
+ {
+ }
+
+ token(begin_expression_type_arg_t) noexcept
+ : type_(token_kind::begin_expression_type)
+ {
+ }
+
+ token(end_expression_type_arg_t) noexcept
+ : type_(token_kind::end_expression_type)
+ {
+ }
+
+ token(literal_arg_t, Json&& value) noexcept
+ : type_(token_kind::literal), value_(std::move(value))
+ {
+ }
+
+ token(token&& other) noexcept
+ {
+ construct(std::forward<token>(other));
+ }
+
+ token& operator=(token&& other)
+ {
+ if (&other != this)
+ {
+ if (type_ == other.type_)
+ {
+ switch (type_)
+ {
+ case token_kind::expression:
+ expression_ = std::move(other.expression_);
+ break;
+ case token_kind::key:
+ key_ = std::move(other.key_);
+ break;
+ case token_kind::unary_operator:
+ unary_operator_ = other.unary_operator_;
+ break;
+ case token_kind::binary_operator:
+ binary_operator_ = other.binary_operator_;
+ break;
+ case token_kind::function:
+ function_ = other.function_;
+ break;
+ case token_kind::literal:
+ value_ = std::move(other.value_);
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ destroy();
+ construct(std::forward<token>(other));
+ }
+ }
+ return *this;
+ }
+
+ ~token() noexcept
+ {
+ destroy();
+ }
+
+ token_kind type() const
+ {
+ return type_;
+ }
+
+ bool is_lparen() const
+ {
+ return type_ == token_kind::lparen;
+ }
+
+ bool is_lbrace() const
+ {
+ return type_ == token_kind::begin_multi_select_hash;
+ }
+
+ bool is_key() const
+ {
+ return type_ == token_kind::key;
+ }
+
+ bool is_rparen() const
+ {
+ return type_ == token_kind::rparen;
+ }
+
+ bool is_current_node() const
+ {
+ return type_ == token_kind::current_node;
+ }
+
+ bool is_projection() const
+ {
+ return type_ == token_kind::expression && expression_->is_projection();
+ }
+
+ bool is_expression() const
+ {
+ return type_ == token_kind::expression;
+ }
+
+ bool is_operator() const
+ {
+ return type_ == token_kind::unary_operator ||
+ type_ == token_kind::binary_operator;
+ }
+
+ std::size_t precedence_level() const
+ {
+ switch(type_)
+ {
+ case token_kind::unary_operator:
+ return unary_operator_->precedence_level();
+ case token_kind::binary_operator:
+ return binary_operator_->precedence_level();
+ case token_kind::expression:
+ return expression_->precedence_level();
+ default:
+ return 0;
+ }
+ }
+
+ jsoncons::optional<std::size_t> arity() const
+ {
+ return type_ == token_kind::function ? function_->arity() : jsoncons::optional<std::size_t>();
+ }
+
+ bool is_right_associative() const
+ {
+ switch(type_)
+ {
+ case token_kind::unary_operator:
+ return unary_operator_->is_right_associative();
+ case token_kind::binary_operator:
+ return binary_operator_->is_right_associative();
+ case token_kind::expression:
+ return expression_->is_right_associative();
+ default:
+ return false;
+ }
+ }
+
+ void construct(token&& other)
+ {
+ type_ = other.type_;
+ switch (type_)
+ {
+ case token_kind::expression:
+ new (&expression_) std::unique_ptr<expression_base>(std::move(other.expression_));
+ break;
+ case token_kind::key:
+ new (&key_) string_type(std::move(other.key_));
+ break;
+ case token_kind::unary_operator:
+ unary_operator_ = other.unary_operator_;
+ break;
+ case token_kind::binary_operator:
+ binary_operator_ = other.binary_operator_;
+ break;
+ case token_kind::function:
+ function_ = other.function_;
+ break;
+ case token_kind::literal:
+ new (&value_) Json(std::move(other.value_));
+ break;
+ default:
+ break;
+ }
+ }
+
+ void destroy() noexcept
+ {
+ switch(type_)
+ {
+ case token_kind::expression:
+ expression_.~unique_ptr();
+ break;
+ case token_kind::key:
+ key_.~basic_string();
+ break;
+ case token_kind::literal:
+ value_.~Json();
+ break;
+ default:
+ break;
+ }
+ }
+
+ std::string to_string(std::size_t indent = 0) const
+ {
+ switch(type_)
+ {
+ case token_kind::expression:
+ return expression_->to_string(indent);
+ break;
+ case token_kind::unary_operator:
+ return std::string("unary_operator");
+ break;
+ case token_kind::binary_operator:
+ return binary_operator_->to_string(indent);
+ break;
+ case token_kind::current_node:
+ return std::string("current_node");
+ break;
+ case token_kind::end_function:
+ return std::string("end_function");
+ break;
+ case token_kind::separator:
+ return std::string("separator");
+ break;
+ case token_kind::literal:
+ return std::string("literal");
+ break;
+ case token_kind::key:
+ return std::string("key") + key_;
+ break;
+ case token_kind::begin_multi_select_hash:
+ return std::string("begin_multi_select_hash");
+ break;
+ case token_kind::begin_multi_select_list:
+ return std::string("begin_multi_select_list");
+ break;
+ case token_kind::begin_filter:
+ return std::string("begin_filter");
+ break;
+ case token_kind::pipe:
+ return std::string("pipe");
+ break;
+ case token_kind::lparen:
+ return std::string("lparen");
+ break;
+ case token_kind::function:
+ return function_->to_string();
+ case token_kind::argument:
+ return std::string("argument");
+ break;
+ case token_kind::begin_expression_type:
+ return std::string("begin_expression_type");
+ break;
+ case token_kind::end_expression_type:
+ return std::string("end_expression_type");
+ break;
+ default:
+ return std::string("default");
+ break;
+ }
+ }
+ };
+
+ static pointer evaluate_tokens(reference doc, const std::vector<token>& output_stack, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec)
+ {
+ pointer root_ptr = std::addressof(doc);
+ std::vector<parameter> stack;
+ std::vector<parameter> arg_stack;
+ for (std::size_t i = 0; i < output_stack.size(); ++i)
+ {
+ auto& t = output_stack[i];
+ switch (t.type())
+ {
+ case token_kind::literal:
+ {
+ stack.emplace_back(t.value_);
+ break;
+ }
+ case token_kind::begin_expression_type:
+ {
+ JSONCONS_ASSERT(i+1 < output_stack.size());
+ ++i;
+ JSONCONS_ASSERT(output_stack[i].is_expression());
+ JSONCONS_ASSERT(!stack.empty());
+ stack.pop_back();
+ stack.emplace_back(output_stack[i].expression_.get());
+ break;
+ }
+ case token_kind::pipe:
+ {
+ JSONCONS_ASSERT(!stack.empty());
+ root_ptr = std::addressof(stack.back().value());
+ break;
+ }
+ case token_kind::current_node:
+ stack.emplace_back(*root_ptr);
+ break;
+ case token_kind::expression:
+ {
+ JSONCONS_ASSERT(!stack.empty());
+ pointer ptr = std::addressof(stack.back().value());
+ stack.pop_back();
+ auto& ref = t.expression_->evaluate(*ptr, resources, ec);
+ stack.emplace_back(ref);
+ break;
+ }
+ case token_kind::unary_operator:
+ {
+ JSONCONS_ASSERT(stack.size() >= 1);
+ pointer ptr = std::addressof(stack.back().value());
+ stack.pop_back();
+ reference r = t.unary_operator_->evaluate(*ptr, resources, ec);
+ stack.emplace_back(r);
+ break;
+ }
+ case token_kind::binary_operator:
+ {
+ JSONCONS_ASSERT(stack.size() >= 2);
+ pointer rhs = std::addressof(stack.back().value());
+ stack.pop_back();
+ pointer lhs = std::addressof(stack.back().value());
+ stack.pop_back();
+ reference r = t.binary_operator_->evaluate(*lhs,*rhs, resources, ec);
+ stack.emplace_back(r);
+ break;
+ }
+ case token_kind::argument:
+ {
+ JSONCONS_ASSERT(!stack.empty());
+ arg_stack.push_back(std::move(stack.back()));
+ stack.pop_back();
+ break;
+ }
+ case token_kind::function:
+ {
+ if (t.function_->arity() && *(t.function_->arity()) != arg_stack.size())
+ {
+ ec = jmespath_errc::invalid_arity;
+ return std::addressof(resources.null_value());
+ }
+
+ reference r = t.function_->evaluate(arg_stack, resources, ec);
+ if (ec)
+ {
+ return std::addressof(resources.null_value());
+ }
+ arg_stack.clear();
+ stack.emplace_back(r);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ JSONCONS_ASSERT(stack.size() == 1);
+ return std::addressof(stack.back().value());
+ }
+
+ // Implementations
+
+ class or_operator final : public binary_operator
+ {
+ public:
+ or_operator()
+ : binary_operator(operator_kind::or_op)
+ {
+ }
+
+ reference evaluate(reference lhs, reference rhs, dynamic_resources<Json,JsonReference>& resources, std::error_code&) const override
+ {
+ if (lhs.is_null() && rhs.is_null())
+ {
+ return resources.null_value();
+ }
+ if (!is_false(lhs))
+ {
+ return lhs;
+ }
+ else
+ {
+ return rhs;
+ }
+ }
+
+ std::string to_string(std::size_t indent = 0) const override
+ {
+ std::string s;
+ for (std::size_t i = 0; i <= indent; ++i)
+ {
+ s.push_back(' ');
+ }
+ s.append("or_operator\n");
+ return s;
+ }
+ };
+
+ class and_operator final : public binary_operator
+ {
+ public:
+ and_operator()
+ : binary_operator(operator_kind::and_op)
+ {
+ }
+
+ reference evaluate(reference lhs, reference rhs, dynamic_resources<Json,JsonReference>&, std::error_code&) const override
+ {
+ if (is_true(lhs))
+ {
+ return rhs;
+ }
+ else
+ {
+ return lhs;
+ }
+ }
+
+ std::string to_string(std::size_t indent = 0) const override
+ {
+ std::string s;
+ for (std::size_t i = 0; i <= indent; ++i)
+ {
+ s.push_back(' ');
+ }
+ s.append("and_operator\n");
+ return s;
+ }
+ };
+
+ class eq_operator final : public binary_operator
+ {
+ public:
+ eq_operator()
+ : binary_operator(operator_kind::eq_op)
+ {
+ }
+
+ reference evaluate(reference lhs, reference rhs, dynamic_resources<Json,JsonReference>& resources, std::error_code&) const override
+ {
+ return lhs == rhs ? resources.true_value() : resources.false_value();
+ }
+
+ std::string to_string(std::size_t indent = 0) const override
+ {
+ std::string s;
+ for (std::size_t i = 0; i <= indent; ++i)
+ {
+ s.push_back(' ');
+ }
+ s.append("eq_operator\n");
+ return s;
+ }
+ };
+
+ class ne_operator final : public binary_operator
+ {
+ public:
+ ne_operator()
+ : binary_operator(operator_kind::ne_op)
+ {
+ }
+
+ reference evaluate(reference lhs, reference rhs, dynamic_resources<Json,JsonReference>& resources, std::error_code&) const override
+ {
+ return lhs != rhs ? resources.true_value() : resources.false_value();
+ }
+
+ std::string to_string(std::size_t indent = 0) const override
+ {
+ std::string s;
+ for (std::size_t i = 0; i <= indent; ++i)
+ {
+ s.push_back(' ');
+ }
+ s.append("ne_operator\n");
+ return s;
+ }
+ };
+
+ class lt_operator final : public binary_operator
+ {
+ public:
+ lt_operator()
+ : binary_operator(operator_kind::lt_op)
+ {
+ }
+
+ reference evaluate(reference lhs, reference rhs, dynamic_resources<Json,JsonReference>& resources, std::error_code&) const override
+ {
+ if (!(lhs.is_number() && rhs.is_number()))
+ {
+ return resources.null_value();
+ }
+ return lhs < rhs ? resources.true_value() : resources.false_value();
+ }
+
+ std::string to_string(std::size_t indent = 0) const override
+ {
+ std::string s;
+ for (std::size_t i = 0; i <= indent; ++i)
+ {
+ s.push_back(' ');
+ }
+ s.append("lt_operator\n");
+ return s;
+ }
+ };
+
+ class lte_operator final : public binary_operator
+ {
+ public:
+ lte_operator()
+ : binary_operator(operator_kind::lte_op)
+ {
+ }
+
+ reference evaluate(reference lhs, reference rhs, dynamic_resources<Json,JsonReference>& resources, std::error_code&) const override
+ {
+ if (!(lhs.is_number() && rhs.is_number()))
+ {
+ return resources.null_value();
+ }
+ return lhs <= rhs ? resources.true_value() : resources.false_value();
+ }
+
+ std::string to_string(std::size_t indent = 0) const override
+ {
+ std::string s;
+ for (std::size_t i = 0; i <= indent; ++i)
+ {
+ s.push_back(' ');
+ }
+ s.append("lte_operator\n");
+ return s;
+ }
+ };
+
+ class gt_operator final : public binary_operator
+ {
+ public:
+ gt_operator()
+ : binary_operator(operator_kind::gt_op)
+ {
+ }
+
+ reference evaluate(reference lhs, reference rhs, dynamic_resources<Json,JsonReference>& resources, std::error_code&) const override
+ {
+ if (!(lhs.is_number() && rhs.is_number()))
+ {
+ return resources.null_value();
+ }
+ return lhs > rhs ? resources.true_value() : resources.false_value();
+ }
+
+ std::string to_string(std::size_t indent = 0) const override
+ {
+ std::string s;
+ for (std::size_t i = 0; i <= indent; ++i)
+ {
+ s.push_back(' ');
+ }
+ s.append("gt_operator\n");
+ return s;
+ }
+ };
+
+ class gte_operator final : public binary_operator
+ {
+ public:
+ gte_operator()
+ : binary_operator(operator_kind::gte_op)
+ {
+ }
+
+ reference evaluate(reference lhs, reference rhs, dynamic_resources<Json,JsonReference>& resources, std::error_code&) const override
+ {
+ if (!(lhs.is_number() && rhs.is_number()))
+ {
+ return resources.null_value();
+ }
+ return lhs >= rhs ? resources.true_value() : resources.false_value();
+ }
+
+ std::string to_string(std::size_t indent = 0) const override
+ {
+ std::string s;
+ for (std::size_t i = 0; i <= indent; ++i)
+ {
+ s.push_back(' ');
+ }
+ s.append("gte_operator\n");
+ return s;
+ }
+ };
+
+ // basic_expression
+ class basic_expression : public expression_base
+ {
+ public:
+ basic_expression()
+ : expression_base(operator_kind::default_op, false)
+ {
+ }
+
+ void add_expression(std::unique_ptr<expression_base>&&) override
+ {
+ }
+ };
+
+ class identifier_selector final : public basic_expression
+ {
+ private:
+ string_type identifier_;
+ public:
+ identifier_selector(const string_view_type& name)
+ : identifier_(name)
+ {
+ }
+
+ reference evaluate(reference val, dynamic_resources<Json,JsonReference>& resources, std::error_code&) const override
+ {
+ //std::cout << "(identifier_selector " << identifier_ << " ) " << pretty_print(val) << "\n";
+ if (val.is_object() && val.contains(identifier_))
+ {
+ return val.at(identifier_);
+ }
+ else
+ {
+ return resources.null_value();
+ }
+ }
+
+ std::string to_string(std::size_t indent = 0) const override
+ {
+ std::string s;
+ for (std::size_t i = 0; i <= indent; ++i)
+ {
+ s.push_back(' ');
+ }
+ s.append("identifier_selector ");
+ s.append(identifier_);
+ return s;
+ }
+ };
+
+ class current_node final : public basic_expression
+ {
+ public:
+ current_node()
+ {
+ }
+
+ reference evaluate(reference val, dynamic_resources<Json,JsonReference>&, std::error_code&) const override
+ {
+ return val;
+ }
+
+ std::string to_string(std::size_t indent = 0) const override
+ {
+ std::string s;
+ for (std::size_t i = 0; i <= indent; ++i)
+ {
+ s.push_back(' ');
+ }
+ s.append("current_node ");
+ return s;
+ }
+ };
+
+ class index_selector final : public basic_expression
+ {
+ int64_t index_;
+ public:
+ index_selector(int64_t index)
+ : index_(index)
+ {
+ }
+
+ reference evaluate(reference val, dynamic_resources<Json,JsonReference>& resources, std::error_code&) const override
+ {
+ if (!val.is_array())
+ {
+ return resources.null_value();
+ }
+ int64_t slen = static_cast<int64_t>(val.size());
+ if (index_ >= 0 && index_ < slen)
+ {
+ std::size_t index = static_cast<std::size_t>(index_);
+ return val.at(index);
+ }
+ else if ((slen + index_) >= 0 && (slen+index_) < slen)
+ {
+ std::size_t index = static_cast<std::size_t>(slen + index_);
+ return val.at(index);
+ }
+ else
+ {
+ return resources.null_value();
+ }
+ }
+
+ std::string to_string(std::size_t indent = 0) const override
+ {
+ std::string s;
+ for (std::size_t i = 0; i <= indent; ++i)
+ {
+ s.push_back(' ');
+ }
+ s.append("index_selector ");
+ s.append(std::to_string(index_));
+ return s;
+ }
+ };
+
+ // projection_base
+ class projection_base : public expression_base
+ {
+ protected:
+ std::vector<std::unique_ptr<expression_base>> expressions_;
+ public:
+ projection_base(operator_kind oper)
+ : expression_base(oper, true)
+ {
+ }
+
+ void add_expression(std::unique_ptr<expression_base>&& expr) override
+ {
+ if (!expressions_.empty() && expressions_.back()->is_projection() &&
+ (expr->precedence_level() < expressions_.back()->precedence_level() ||
+ (expr->precedence_level() == expressions_.back()->precedence_level() && expr->is_right_associative())))
+ {
+ expressions_.back()->add_expression(std::move(expr));
+ }
+ else
+ {
+ expressions_.emplace_back(std::move(expr));
+ }
+ }
+
+ reference apply_expressions(reference val, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const
+ {
+ pointer ptr = std::addressof(val);
+ for (auto& expression : expressions_)
+ {
+ ptr = std::addressof(expression->evaluate(*ptr, resources, ec));
+ }
+ return *ptr;
+ }
+ };
+
+ class object_projection final : public projection_base
+ {
+ public:
+ object_projection()
+ : projection_base(operator_kind::projection_op)
+ {
+ }
+
+ reference evaluate(reference val, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ if (!val.is_object())
+ {
+ return resources.null_value();
+ }
+
+ auto result = resources.create_json(json_array_arg);
+ for (auto& item : val.object_range())
+ {
+ if (!item.value().is_null())
+ {
+ reference j = this->apply_expressions(item.value(), resources, ec);
+ if (!j.is_null())
+ {
+ result->emplace_back(json_const_pointer_arg, std::addressof(j));
+ }
+ }
+ }
+ return *result;
+ }
+
+ std::string to_string(std::size_t indent = 0) const override
+ {
+ std::string s;
+ for (std::size_t i = 0; i <= indent; ++i)
+ {
+ s.push_back(' ');
+ }
+ s.append("object_projection\n");
+ for (auto& expr : this->expressions_)
+ {
+ std::string sss = expr->to_string(indent+2);
+ s.insert(s.end(), sss.begin(), sss.end());
+ s.push_back('\n');
+ }
+ return s;
+ }
+ };
+
+ class list_projection final : public projection_base
+ {
+ public:
+ list_projection()
+ : projection_base(operator_kind::projection_op)
+ {
+ }
+
+ reference evaluate(reference val, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ if (!val.is_array())
+ {
+ return resources.null_value();
+ }
+
+ auto result = resources.create_json(json_array_arg);
+ for (reference item : val.array_range())
+ {
+ if (!item.is_null())
+ {
+ reference j = this->apply_expressions(item, resources, ec);
+ if (!j.is_null())
+ {
+ result->emplace_back(json_const_pointer_arg, std::addressof(j));
+ }
+ }
+ }
+ return *result;
+ }
+
+ std::string to_string(std::size_t indent = 0) const override
+ {
+ std::string s;
+ for (std::size_t i = 0; i <= indent; ++i)
+ {
+ s.push_back(' ');
+ }
+ s.append("list_projection\n");
+ for (auto& expr : this->expressions_)
+ {
+ std::string sss = expr->to_string(indent+2);
+ s.insert(s.end(), sss.begin(), sss.end());
+ s.push_back('\n');
+ }
+ return s;
+ }
+ };
+
+ class slice_projection final : public projection_base
+ {
+ slice slice_;
+ public:
+ slice_projection(const slice& s)
+ : projection_base(operator_kind::projection_op), slice_(s)
+ {
+ }
+
+ reference evaluate(reference val, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ if (!val.is_array())
+ {
+ return resources.null_value();
+ }
+
+ auto start = slice_.get_start(val.size());
+ auto end = slice_.get_stop(val.size());
+ auto step = slice_.step();
+
+ if (step == 0)
+ {
+ ec = jmespath_errc::step_cannot_be_zero;
+ return resources.null_value();
+ }
+
+ auto result = resources.create_json(json_array_arg);
+ if (step > 0)
+ {
+ if (start < 0)
+ {
+ start = 0;
+ }
+ if (end > static_cast<int64_t>(val.size()))
+ {
+ end = val.size();
+ }
+ for (int64_t i = start; i < end; i += step)
+ {
+ reference j = this->apply_expressions(val.at(static_cast<std::size_t>(i)), resources, ec);
+ if (!j.is_null())
+ {
+ result->emplace_back(json_const_pointer_arg, std::addressof(j));
+ }
+ }
+ }
+ else
+ {
+ if (start >= static_cast<int64_t>(val.size()))
+ {
+ start = static_cast<int64_t>(val.size()) - 1;
+ }
+ if (end < -1)
+ {
+ end = -1;
+ }
+ for (int64_t i = start; i > end; i += step)
+ {
+ reference j = this->apply_expressions(val.at(static_cast<std::size_t>(i)), resources, ec);
+ if (!j.is_null())
+ {
+ result->emplace_back(json_const_pointer_arg, std::addressof(j));
+ }
+ }
+ }
+
+ return *result;
+ }
+
+ std::string to_string(std::size_t indent = 0) const override
+ {
+ std::string s;
+ for (std::size_t i = 0; i <= indent; ++i)
+ {
+ s.push_back(' ');
+ }
+ s.append("slice_projection\n");
+ for (auto& expr : this->expressions_)
+ {
+ std::string sss = expr->to_string(indent+2);
+ s.insert(s.end(), sss.begin(), sss.end());
+ s.push_back('\n');
+ }
+ return s;
+ }
+ };
+
+ class filter_expression final : public projection_base
+ {
+ std::vector<token> token_list_;
+ public:
+ filter_expression(std::vector<token>&& token_list)
+ : projection_base(operator_kind::projection_op), token_list_(std::move(token_list))
+ {
+ }
+
+ reference evaluate(reference val, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ if (!val.is_array())
+ {
+ return resources.null_value();
+ }
+ auto result = resources.create_json(json_array_arg);
+
+ for (auto& item : val.array_range())
+ {
+ Json j(json_const_pointer_arg, evaluate_tokens(item, token_list_, resources, ec));
+ if (is_true(j))
+ {
+ reference jj = this->apply_expressions(item, resources, ec);
+ if (!jj.is_null())
+ {
+ result->emplace_back(json_const_pointer_arg, std::addressof(jj));
+ }
+ }
+ }
+ return *result;
+ }
+
+ std::string to_string(std::size_t indent = 0) const override
+ {
+ std::string s;
+ for (std::size_t i = 0; i <= indent; ++i)
+ {
+ s.push_back(' ');
+ }
+ s.append("filter_expression\n");
+ for (auto& item : token_list_)
+ {
+ std::string sss = item.to_string(indent+2);
+ s.insert(s.end(), sss.begin(), sss.end());
+ s.push_back('\n');
+ }
+ return s;
+ }
+ };
+
+ class flatten_projection final : public projection_base
+ {
+ public:
+ flatten_projection()
+ : projection_base(operator_kind::flatten_projection_op)
+ {
+ }
+
+ reference evaluate(reference val, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ if (!val.is_array())
+ {
+ return resources.null_value();
+ }
+
+ auto result = resources.create_json(json_array_arg);
+ for (reference current_elem : val.array_range())
+ {
+ if (current_elem.is_array())
+ {
+ for (reference elem : current_elem.array_range())
+ {
+ if (!elem.is_null())
+ {
+ reference j = this->apply_expressions(elem, resources, ec);
+ if (!j.is_null())
+ {
+ result->emplace_back(json_const_pointer_arg, std::addressof(j));
+ }
+ }
+ }
+ }
+ else
+ {
+ if (!current_elem.is_null())
+ {
+ reference j = this->apply_expressions(current_elem, resources, ec);
+ if (!j.is_null())
+ {
+ result->emplace_back(json_const_pointer_arg, std::addressof(j));
+ }
+ }
+ }
+ }
+ return *result;
+ }
+
+ std::string to_string(std::size_t indent = 0) const override
+ {
+ std::string s;
+ for (std::size_t i = 0; i <= indent; ++i)
+ {
+ s.push_back(' ');
+ }
+ s.append("flatten_projection\n");
+ for (auto& expr : this->expressions_)
+ {
+ std::string sss = expr->to_string(indent+2);
+ s.insert(s.end(), sss.begin(), sss.end());
+ s.push_back('\n');
+ }
+ return s;
+ }
+ };
+
+ class multi_select_list final : public basic_expression
+ {
+ std::vector<std::vector<token>> token_lists_;
+ public:
+ multi_select_list(std::vector<std::vector<token>>&& token_lists)
+ : token_lists_(std::move(token_lists))
+ {
+ }
+
+ reference evaluate(reference val, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ if (val.is_null())
+ {
+ return val;
+ }
+ auto result = resources.create_json(json_array_arg);
+ result->reserve(token_lists_.size());
+
+ for (auto& list : token_lists_)
+ {
+ result->emplace_back(json_const_pointer_arg, evaluate_tokens(val, list, resources, ec));
+ }
+ return *result;
+ }
+
+ std::string to_string(std::size_t indent = 0) const override
+ {
+ std::string s;
+ for (std::size_t i = 0; i <= indent; ++i)
+ {
+ s.push_back(' ');
+ }
+ s.append("multi_select_list\n");
+ for (auto& list : token_lists_)
+ {
+ for (auto& item : list)
+ {
+ std::string sss = item.to_string(indent+2);
+ s.insert(s.end(), sss.begin(), sss.end());
+ s.push_back('\n');
+ }
+ s.append("---\n");
+ }
+ return s;
+ }
+ };
+
+ struct key_tokens
+ {
+ string_type key;
+ std::vector<token> tokens;
+
+ key_tokens(string_type&& key, std::vector<token>&& tokens) noexcept
+ : key(std::move(key)), tokens(std::move(tokens))
+ {
+ }
+ };
+
+ class multi_select_hash final : public basic_expression
+ {
+ public:
+ std::vector<key_tokens> key_toks_;
+
+ multi_select_hash(std::vector<key_tokens>&& key_toks)
+ : key_toks_(std::move(key_toks))
+ {
+ }
+
+ reference evaluate(reference val, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ if (val.is_null())
+ {
+ return val;
+ }
+ auto resultp = resources.create_json(json_object_arg);
+ resultp->reserve(key_toks_.size());
+ for (auto& item : key_toks_)
+ {
+ resultp->try_emplace(item.key, json_const_pointer_arg, evaluate_tokens(val, item.tokens, resources, ec));
+ }
+
+ return *resultp;
+ }
+
+ std::string to_string(std::size_t indent = 0) const override
+ {
+ std::string s;
+ for (std::size_t i = 0; i <= indent; ++i)
+ {
+ s.push_back(' ');
+ }
+ s.append("multi_select_list\n");
+ return s;
+ }
+ };
+
+ class function_expression final : public basic_expression
+ {
+ public:
+ std::vector<token> toks_;
+
+ function_expression(std::vector<token>&& toks)
+ : toks_(std::move(toks))
+ {
+ }
+
+ reference evaluate(reference val, dynamic_resources<Json,JsonReference>& resources, std::error_code& ec) const override
+ {
+ return *evaluate_tokens(val, toks_, resources, ec);
+ }
+
+ std::string to_string(std::size_t indent = 0) const override
+ {
+ std::string s;
+ for (std::size_t i = 0; i <= indent; ++i)
+ {
+ s.push_back(' ');
+ }
+ s.append("function_expression\n");
+ for (auto& tok : toks_)
+ {
+ for (std::size_t i = 0; i <= indent+2; ++i)
+ {
+ s.push_back(' ');
+ }
+ std::string sss = tok.to_string(indent+2);
+ s.insert(s.end(), sss.begin(), sss.end());
+ s.push_back('\n');
+ }
+ return s;
+ }
+ };
+
+ class static_resources
+ {
+ std::vector<std::unique_ptr<Json>> temp_storage_;
+
+ public:
+
+ static_resources() = default;
+ static_resources(const static_resources& expr) = delete;
+ static_resources& operator=(const static_resources& expr) = delete;
+ static_resources(static_resources&& expr) = default;
+ static_resources& operator=(static_resources&& expr) = default;
+
+ const function_base* get_function(const string_type& name, std::error_code& ec) const
+ {
+ static abs_function abs_func;
+ static avg_function avg_func;
+ static ceil_function ceil_func;
+ static contains_function contains_func;
+ static ends_with_function ends_with_func;
+ static floor_function floor_func;
+ static join_function join_func;
+ static length_function length_func;
+ static max_function max_func;
+ static max_by_function max_by_func;
+ static map_function map_func;
+ static merge_function merge_func;
+ static min_function min_func;
+ static min_by_function min_by_func;
+ static type_function type_func;
+ static sort_function sort_func;
+ static sort_by_function sort_by_func;
+ static keys_function keys_func;
+ static values_function values_func;
+ static reverse_function reverse_func;
+ static starts_with_function starts_with_func;
+ static const sum_function sum_func;
+ static to_array_function to_array_func;
+ static to_number_function to_number_func;
+ static to_string_function to_string_func;
+ static not_null_function not_null_func;
+
+ using function_dictionary = std::unordered_map<string_type,const function_base*>;
+ static const function_dictionary functions_ =
+ {
+ {string_type{'a','b','s'}, &abs_func},
+ {string_type{'a','v','g'}, &avg_func},
+ {string_type{'c','e','i', 'l'}, &ceil_func},
+ {string_type{'c','o','n', 't', 'a', 'i', 'n', 's'}, &contains_func},
+ {string_type{'e','n','d', 's', '_', 'w', 'i', 't', 'h'}, &ends_with_func},
+ {string_type{'f','l','o', 'o', 'r'}, &floor_func},
+ {string_type{'j','o','i', 'n'}, &join_func},
+ {string_type{'l','e','n', 'g', 't', 'h'}, &length_func},
+ {string_type{'m','a','x'}, &max_func},
+ {string_type{'m','a','x','_','b','y'}, &max_by_func},
+ {string_type{'m','a','p'}, &map_func},
+ {string_type{'m','i','n'}, &min_func},
+ {string_type{'m','i','n','_','b','y'}, &min_by_func},
+ {string_type{'m','e','r', 'g', 'e'}, &merge_func},
+ {string_type{'t','y','p', 'e'}, &type_func},
+ {string_type{'s','o','r', 't'}, &sort_func},
+ {string_type{'s','o','r', 't','_','b','y'}, &sort_by_func},
+ {string_type{'k','e','y', 's'}, &keys_func},
+ {string_type{'v','a','l', 'u','e','s'}, &values_func},
+ {string_type{'r','e','v', 'e', 'r', 's','e'}, &reverse_func},
+ {string_type{'s','t','a', 'r','t','s','_','w','i','t','h'}, &starts_with_func},
+ {string_type{'s','u','m'}, &sum_func},
+ {string_type{'t','o','_','a','r','r','a','y',}, &to_array_func},
+ {string_type{'t','o','_', 'n', 'u', 'm','b','e','r'}, &to_number_func},
+ {string_type{'t','o','_', 's', 't', 'r','i','n','g'}, &to_string_func},
+ {string_type{'n','o','t', '_', 'n', 'u','l','l'}, &not_null_func}
+ };
+ auto it = functions_.find(name);
+ if (it == functions_.end())
+ {
+ ec = jmespath_errc::unknown_function;
+ return nullptr;
+ }
+ return it->second;
+ }
+
+ const unary_operator* get_not_operator() const
+ {
+ static const not_expression not_oper;
+
+ return &not_oper;
+ }
+
+ const binary_operator* get_or_operator() const
+ {
+ static const or_operator or_oper;
+
+ return &or_oper;
+ }
+
+ const binary_operator* get_and_operator() const
+ {
+ static const and_operator and_oper;
+
+ return &and_oper;
+ }
+
+ const binary_operator* get_eq_operator() const
+ {
+ static const eq_operator eq_oper;
+ return &eq_oper;
+ }
+
+ const binary_operator* get_ne_operator() const
+ {
+ static const ne_operator ne_oper;
+ return &ne_oper;
+ }
+
+ const binary_operator* get_lt_operator() const
+ {
+ static const lt_operator lt_oper;
+ return &lt_oper;
+ }
+
+ const binary_operator* get_lte_operator() const
+ {
+ static const lte_operator lte_oper;
+ return &lte_oper;
+ }
+
+ const binary_operator* get_gt_operator() const
+ {
+ static const gt_operator gt_oper;
+ return &gt_oper;
+ }
+
+ const binary_operator* get_gte_operator() const
+ {
+ static const gte_operator gte_oper;
+ return &gte_oper;
+ }
+ };
+
+ class jmespath_expression
+ {
+ static_resources resources_;
+ std::vector<token> output_stack_;
+ public:
+ jmespath_expression()
+ {
+ }
+
+ jmespath_expression(const jmespath_expression& expr) = delete;
+ jmespath_expression& operator=(const jmespath_expression& expr) = delete;
+
+ jmespath_expression(jmespath_expression&& expr)
+ : resources_(std::move(expr.resources_)),
+ output_stack_(std::move(expr.output_stack_))
+ {
+ }
+
+ jmespath_expression(static_resources&& resources,
+ std::vector<token>&& output_stack)
+ : resources_(std::move(resources)), output_stack_(std::move(output_stack))
+ {
+ }
+
+ Json evaluate(reference doc)
+ {
+ if (output_stack_.empty())
+ {
+ return Json::null();
+ }
+ std::error_code ec;
+ Json result = evaluate(doc, ec);
+ if (ec)
+ {
+ JSONCONS_THROW(jmespath_error(ec));
+ }
+ return result;
+ }
+
+ Json evaluate(reference doc, std::error_code& ec)
+ {
+ if (output_stack_.empty())
+ {
+ return Json::null();
+ }
+ dynamic_resources<Json,JsonReference> dynamic_storage;
+ return deep_copy(*evaluate_tokens(doc, output_stack_, dynamic_storage, ec));
+ }
+
+ static jmespath_expression compile(const string_view_type& expr)
+ {
+ jsoncons::jmespath::detail::jmespath_evaluator<Json,const Json&> evaluator;
+ std::error_code ec;
+ jmespath_expression result = evaluator.compile(expr.data(), expr.size(), ec);
+ if (ec)
+ {
+ JSONCONS_THROW(jmespath_error(ec, evaluator.line(), evaluator.column()));
+ }
+ return result;
+ }
+
+ static jmespath_expression compile(const string_view_type& expr,
+ std::error_code& ec)
+ {
+ jsoncons::jmespath::detail::jmespath_evaluator<Json,const Json&> evaluator;
+ return evaluator.compile(expr.data(), expr.size(), ec);
+ }
+ };
+ private:
+ std::size_t line_;
+ std::size_t column_;
+ const char_type* begin_input_;
+ const char_type* end_input_;
+ const char_type* p_;
+
+ static_resources resources_;
+ std::vector<path_state> state_stack_;
+
+ std::vector<token> output_stack_;
+ std::vector<token> operator_stack_;
+
+ public:
+ jmespath_evaluator()
+ : line_(1), column_(1),
+ begin_input_(nullptr), end_input_(nullptr),
+ p_(nullptr)
+ {
+ }
+
+ std::size_t line() const
+ {
+ return line_;
+ }
+
+ std::size_t column() const
+ {
+ return column_;
+ }
+
+ jmespath_expression compile(const char_type* path,
+ std::size_t length,
+ std::error_code& ec)
+ {
+ push_token(current_node_arg, ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.emplace_back(path_state::start);
+
+ string_type buffer;
+ uint32_t cp = 0;
+ uint32_t cp2 = 0;
+
+ begin_input_ = path;
+ end_input_ = path + length;
+ p_ = begin_input_;
+
+ slice slic{};
+
+ while (p_ < end_input_)
+ {
+ switch (state_stack_.back())
+ {
+ case path_state::start:
+ {
+ state_stack_.back() = path_state::rhs_expression;
+ state_stack_.emplace_back(path_state::lhs_expression);
+ break;
+ }
+ case path_state::rhs_expression:
+ switch(*p_)
+ {
+ case ' ':case '\t':case '\r':case '\n':
+ advance_past_space_character(ec);
+ break;
+ case '.':
+ ++p_;
+ ++column_;
+ state_stack_.emplace_back(path_state::sub_expression);
+ break;
+ case '|':
+ ++p_;
+ ++column_;
+ state_stack_.emplace_back(path_state::lhs_expression);
+ state_stack_.emplace_back(path_state::expect_pipe_or_or);
+ break;
+ case '&':
+ ++p_;
+ ++column_;
+ state_stack_.emplace_back(path_state::lhs_expression);
+ state_stack_.emplace_back(path_state::expect_and);
+ break;
+ case '<':
+ case '>':
+ case '=':
+ {
+ state_stack_.emplace_back(path_state::comparator_expression);
+ break;
+ }
+ case '!':
+ {
+ ++p_;
+ ++column_;
+ state_stack_.emplace_back(path_state::lhs_expression);
+ state_stack_.emplace_back(path_state::cmp_ne);
+ break;
+ }
+ case ')':
+ {
+ state_stack_.pop_back();
+ break;
+ }
+ case '[':
+ state_stack_.emplace_back(path_state::bracket_specifier);
+ ++p_;
+ ++column_;
+ break;
+ default:
+ if (state_stack_.size() > 1)
+ {
+ state_stack_.pop_back();
+ }
+ else
+ {
+ ec = jmespath_errc::syntax_error;
+ return jmespath_expression();
+ }
+ break;
+ }
+ break;
+ case path_state::comparator_expression:
+ switch(*p_)
+ {
+ case ' ':case '\t':case '\r':case '\n':
+ advance_past_space_character(ec);
+ break;
+ case '<':
+ ++p_;
+ ++column_;
+ state_stack_.back() = path_state::lhs_expression;
+ state_stack_.emplace_back(path_state::cmp_lt_or_lte);
+ break;
+ case '>':
+ ++p_;
+ ++column_;
+ state_stack_.back() = path_state::lhs_expression;
+ state_stack_.emplace_back(path_state::cmp_gt_or_gte);
+ break;
+ case '=':
+ {
+ ++p_;
+ ++column_;
+ state_stack_.back() = path_state::lhs_expression;
+ state_stack_.emplace_back(path_state::cmp_eq);
+ break;
+ }
+ default:
+ if (state_stack_.size() > 1)
+ {
+ state_stack_.pop_back();
+ }
+ else
+ {
+ ec = jmespath_errc::syntax_error;
+ return jmespath_expression();
+ }
+ break;
+ }
+ break;
+ case path_state::lhs_expression:
+ {
+ switch (*p_)
+ {
+ case ' ':case '\t':case '\r':case '\n':
+ advance_past_space_character(ec);
+ break;
+ case '\"':
+ state_stack_.back() = path_state::val_expr;
+ state_stack_.emplace_back(path_state::quoted_string);
+ ++p_;
+ ++column_;
+ break;
+ case '\'':
+ state_stack_.back() = path_state::raw_string;
+ ++p_;
+ ++column_;
+ break;
+ case '`':
+ state_stack_.back() = path_state::literal;
+ ++p_;
+ ++column_;
+ break;
+ case '{':
+ push_token(begin_multi_select_hash_arg, ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.back() = path_state::multi_select_hash;
+ ++p_;
+ ++column_;
+ break;
+ case '*': // wildcard
+ push_token(token(jsoncons::make_unique<object_projection>()), ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.pop_back();
+ ++p_;
+ ++column_;
+ break;
+ case '(':
+ {
+ ++p_;
+ ++column_;
+ push_token(lparen_arg, ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.back() = path_state::expect_rparen;
+ state_stack_.emplace_back(path_state::rhs_expression);
+ state_stack_.emplace_back(path_state::lhs_expression);
+ break;
+ }
+ case '!':
+ {
+ ++p_;
+ ++column_;
+ push_token(token(resources_.get_not_operator()), ec);
+ if (ec) {return jmespath_expression();}
+ break;
+ }
+ case '@':
+ ++p_;
+ ++column_;
+ push_token(token(jsoncons::make_unique<current_node>()), ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.pop_back();
+ break;
+ case '[':
+ state_stack_.back() = path_state::bracket_specifier_or_multi_select_list;
+ ++p_;
+ ++column_;
+ break;
+ default:
+ if ((*p_ >= 'A' && *p_ <= 'Z') || (*p_ >= 'a' && *p_ <= 'z') || (*p_ == '_'))
+ {
+ state_stack_.back() = path_state::identifier_or_function_expr;
+ state_stack_.emplace_back(path_state::unquoted_string);
+ buffer.push_back(*p_);
+ ++p_;
+ ++column_;
+ }
+ else
+ {
+ ec = jmespath_errc::expected_identifier;
+ return jmespath_expression();
+ }
+ break;
+ };
+ break;
+ }
+ case path_state::sub_expression:
+ {
+ switch (*p_)
+ {
+ case ' ':case '\t':case '\r':case '\n':
+ advance_past_space_character(ec);
+ break;
+ case '\"':
+ state_stack_.back() = path_state::val_expr;
+ state_stack_.emplace_back(path_state::quoted_string);
+ ++p_;
+ ++column_;
+ break;
+ case '{':
+ push_token(begin_multi_select_hash_arg, ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.back() = path_state::multi_select_hash;
+ ++p_;
+ ++column_;
+ break;
+ case '*':
+ push_token(token(jsoncons::make_unique<object_projection>()), ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.pop_back();
+ ++p_;
+ ++column_;
+ break;
+ case '[':
+ state_stack_.back() = path_state::expect_multi_select_list;
+ ++p_;
+ ++column_;
+ break;
+ default:
+ if ((*p_ >= 'A' && *p_ <= 'Z') || (*p_ >= 'a' && *p_ <= 'z') || (*p_ == '_'))
+ {
+ state_stack_.back() = path_state::identifier_or_function_expr;
+ state_stack_.emplace_back(path_state::unquoted_string);
+ buffer.push_back(*p_);
+ ++p_;
+ ++column_;
+ }
+ else
+ {
+ ec = jmespath_errc::expected_identifier;
+ return jmespath_expression();
+ }
+ break;
+ };
+ break;
+ }
+ case path_state::key_expr:
+ push_token(token(key_arg, buffer), ec);
+ if (ec) {return jmespath_expression();}
+ buffer.clear();
+ state_stack_.pop_back();
+ break;
+ case path_state::val_expr:
+ push_token(token(jsoncons::make_unique<identifier_selector>(buffer)), ec);
+ if (ec) {return jmespath_expression();}
+ buffer.clear();
+ state_stack_.pop_back();
+ break;
+ case path_state::expression_or_expression_type:
+ switch (*p_)
+ {
+ case ' ':case '\t':case '\r':case '\n':
+ advance_past_space_character(ec);
+ break;
+ case '&':
+ push_token(token(begin_expression_type_arg), ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.back() = path_state::expression_type;
+ state_stack_.emplace_back(path_state::rhs_expression);
+ state_stack_.emplace_back(path_state::lhs_expression);
+ ++p_;
+ ++column_;
+ break;
+ default:
+ state_stack_.back() = path_state::argument;
+ state_stack_.emplace_back(path_state::rhs_expression);
+ state_stack_.emplace_back(path_state::lhs_expression);
+ break;
+ }
+ break;
+ case path_state::identifier_or_function_expr:
+ switch(*p_)
+ {
+ case '(':
+ {
+ auto f = resources_.get_function(buffer, ec);
+ if (ec)
+ {
+ return jmespath_expression();
+ }
+ buffer.clear();
+ push_token(token(f), ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.back() = path_state::function_expression;
+ state_stack_.emplace_back(path_state::expression_or_expression_type);
+ ++p_;
+ ++column_;
+ break;
+ }
+ default:
+ {
+ push_token(token(jsoncons::make_unique<identifier_selector>(buffer)), ec);
+ if (ec) {return jmespath_expression();}
+ buffer.clear();
+ state_stack_.pop_back();
+ break;
+ }
+ }
+ break;
+
+ case path_state::function_expression:
+ switch (*p_)
+ {
+ case ' ':case '\t':case '\r':case '\n':
+ advance_past_space_character(ec);
+ break;
+ case ',':
+ push_token(token(current_node_arg), ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.emplace_back(path_state::expression_or_expression_type);
+ ++p_;
+ ++column_;
+ break;
+ case ')':
+ {
+ push_token(token(end_function_arg), ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.pop_back();
+ ++p_;
+ ++column_;
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+
+ case path_state::argument:
+ push_token(argument_arg, ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.pop_back();
+ break;
+
+ case path_state::expression_type:
+ push_token(end_expression_type_arg, ec);
+ push_token(argument_arg, ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.pop_back();
+ break;
+
+ case path_state::quoted_string:
+ switch (*p_)
+ {
+ case '\"':
+ state_stack_.pop_back(); // quoted_string
+ ++p_;
+ ++column_;
+ break;
+ case '\\':
+ state_stack_.emplace_back(path_state::quoted_string_escape_char);
+ ++p_;
+ ++column_;
+ break;
+ default:
+ buffer.push_back(*p_);
+ ++p_;
+ ++column_;
+ break;
+ };
+ break;
+
+ case path_state::unquoted_string:
+ switch (*p_)
+ {
+ case ' ':case '\t':case '\r':case '\n':
+ state_stack_.pop_back(); // unquoted_string
+ advance_past_space_character(ec);
+ break;
+ default:
+ if ((*p_ >= '0' && *p_ <= '9') || (*p_ >= 'A' && *p_ <= 'Z') || (*p_ >= 'a' && *p_ <= 'z') || (*p_ == '_'))
+ {
+ buffer.push_back(*p_);
+ ++p_;
+ ++column_;
+ }
+ else
+ {
+ state_stack_.pop_back(); // unquoted_string
+ }
+ break;
+ };
+ break;
+ case path_state::raw_string_escape_char:
+ switch (*p_)
+ {
+ case '\'':
+ buffer.push_back(*p_);
+ state_stack_.pop_back();
+ ++p_;
+ ++column_;
+ break;
+ default:
+ buffer.push_back('\\');
+ buffer.push_back(*p_);
+ state_stack_.pop_back();
+ ++p_;
+ ++column_;
+ break;
+ }
+ break;
+ case path_state::quoted_string_escape_char:
+ switch (*p_)
+ {
+ case '\"':
+ buffer.push_back('\"');
+ ++p_;
+ ++column_;
+ state_stack_.pop_back();
+ break;
+ case '\\':
+ buffer.push_back('\\');
+ ++p_;
+ ++column_;
+ state_stack_.pop_back();
+ break;
+ case '/':
+ buffer.push_back('/');
+ ++p_;
+ ++column_;
+ state_stack_.pop_back();
+ break;
+ case 'b':
+ buffer.push_back('\b');
+ ++p_;
+ ++column_;
+ state_stack_.pop_back();
+ break;
+ case 'f':
+ buffer.push_back('\f');
+ ++p_;
+ ++column_;
+ state_stack_.pop_back();
+ break;
+ case 'n':
+ buffer.push_back('\n');
+ ++p_;
+ ++column_;
+ state_stack_.pop_back();
+ break;
+ case 'r':
+ buffer.push_back('\r');
+ ++p_;
+ ++column_;
+ state_stack_.pop_back();
+ break;
+ case 't':
+ buffer.push_back('\t');
+ ++p_;
+ ++column_;
+ state_stack_.pop_back();
+ break;
+ case 'u':
+ ++p_;
+ ++column_;
+ state_stack_.back() = path_state::escape_u1;
+ break;
+ default:
+ ec = jmespath_errc::illegal_escaped_character;
+ return jmespath_expression();
+ }
+ break;
+ case path_state::escape_u1:
+ cp = append_to_codepoint(0, *p_, ec);
+ if (ec)
+ {
+ return jmespath_expression();
+ }
+ ++p_;
+ ++column_;
+ state_stack_.back() = path_state::escape_u2;
+ break;
+ case path_state::escape_u2:
+ cp = append_to_codepoint(cp, *p_, ec);
+ if (ec)
+ {
+ return jmespath_expression();
+ }
+ ++p_;
+ ++column_;
+ state_stack_.back() = path_state::escape_u3;
+ break;
+ case path_state::escape_u3:
+ cp = append_to_codepoint(cp, *p_, ec);
+ if (ec)
+ {
+ return jmespath_expression();
+ }
+ ++p_;
+ ++column_;
+ state_stack_.back() = path_state::escape_u4;
+ break;
+ case path_state::escape_u4:
+ cp = append_to_codepoint(cp, *p_, ec);
+ if (ec)
+ {
+ return jmespath_expression();
+ }
+ if (unicode_traits::is_high_surrogate(cp))
+ {
+ ++p_;
+ ++column_;
+ state_stack_.back() = path_state::escape_expect_surrogate_pair1;
+ }
+ else
+ {
+ unicode_traits::convert(&cp, 1, buffer);
+ ++p_;
+ ++column_;
+ state_stack_.pop_back();
+ }
+ break;
+ case path_state::escape_expect_surrogate_pair1:
+ switch (*p_)
+ {
+ case '\\':
+ ++p_;
+ ++column_;
+ state_stack_.back() = path_state::escape_expect_surrogate_pair2;
+ break;
+ default:
+ ec = jmespath_errc::invalid_codepoint;
+ return jmespath_expression();
+ }
+ break;
+ case path_state::escape_expect_surrogate_pair2:
+ switch (*p_)
+ {
+ case 'u':
+ ++p_;
+ ++column_;
+ state_stack_.back() = path_state::escape_u5;
+ break;
+ default:
+ ec = jmespath_errc::invalid_codepoint;
+ return jmespath_expression();
+ }
+ break;
+ case path_state::escape_u5:
+ cp2 = append_to_codepoint(0, *p_, ec);
+ if (ec)
+ {
+ return jmespath_expression();
+ }
+ ++p_;
+ ++column_;
+ state_stack_.back() = path_state::escape_u6;
+ break;
+ case path_state::escape_u6:
+ cp2 = append_to_codepoint(cp2, *p_, ec);
+ if (ec)
+ {
+ return jmespath_expression();
+ }
+ ++p_;
+ ++column_;
+ state_stack_.back() = path_state::escape_u7;
+ break;
+ case path_state::escape_u7:
+ cp2 = append_to_codepoint(cp2, *p_, ec);
+ if (ec)
+ {
+ return jmespath_expression();
+ }
+ ++p_;
+ ++column_;
+ state_stack_.back() = path_state::escape_u8;
+ break;
+ case path_state::escape_u8:
+ {
+ cp2 = append_to_codepoint(cp2, *p_, ec);
+ if (ec)
+ {
+ return jmespath_expression();
+ }
+ uint32_t codepoint = 0x10000 + ((cp & 0x3FF) << 10) + (cp2 & 0x3FF);
+ unicode_traits::convert(&codepoint, 1, buffer);
+ state_stack_.pop_back();
+ ++p_;
+ ++column_;
+ break;
+ }
+ case path_state::raw_string:
+ switch (*p_)
+ {
+ case '\'':
+ {
+ push_token(token(literal_arg, Json(buffer)), ec);
+ if (ec) {return jmespath_expression();}
+ buffer.clear();
+ state_stack_.pop_back(); // raw_string
+ ++p_;
+ ++column_;
+ break;
+ }
+ case '\\':
+ state_stack_.emplace_back(path_state::raw_string_escape_char);
+ ++p_;
+ ++column_;
+ break;
+ default:
+ buffer.push_back(*p_);
+ ++p_;
+ ++column_;
+ break;
+ };
+ break;
+ case path_state::literal:
+ switch (*p_)
+ {
+ case '`':
+ {
+ json_decoder<Json> decoder;
+ basic_json_reader<char_type,string_source<char_type>> reader(buffer, decoder);
+ std::error_code parse_ec;
+ reader.read(parse_ec);
+ if (parse_ec)
+ {
+ ec = jmespath_errc::invalid_literal;
+ return jmespath_expression();
+ }
+ auto j = decoder.get_result();
+
+ push_token(token(literal_arg, std::move(j)), ec);
+ if (ec) {return jmespath_expression();}
+ buffer.clear();
+ state_stack_.pop_back(); // json_value
+ ++p_;
+ ++column_;
+ break;
+ }
+ case '\\':
+ if (p_+1 < end_input_)
+ {
+ ++p_;
+ ++column_;
+ if (*p_ != '`')
+ {
+ buffer.push_back('\\');
+ }
+ buffer.push_back(*p_);
+ }
+ else
+ {
+ ec = jmespath_errc::unexpected_end_of_input;
+ return jmespath_expression();
+ }
+ ++p_;
+ ++column_;
+ break;
+ default:
+ buffer.push_back(*p_);
+ ++p_;
+ ++column_;
+ break;
+ };
+ break;
+ case path_state::number:
+ switch(*p_)
+ {
+ case '-':
+ buffer.push_back(*p_);
+ state_stack_.back() = path_state::digit;
+ ++p_;
+ ++column_;
+ break;
+ default:
+ state_stack_.back() = path_state::digit;
+ break;
+ }
+ break;
+ case path_state::digit:
+ switch(*p_)
+ {
+ case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':
+ buffer.push_back(*p_);
+ ++p_;
+ ++column_;
+ break;
+ default:
+ state_stack_.pop_back(); // digit
+ break;
+ }
+ break;
+
+ case path_state::bracket_specifier:
+ switch(*p_)
+ {
+ case '*':
+ push_token(token(jsoncons::make_unique<list_projection>()), ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.back() = path_state::expect_rbracket;
+ ++p_;
+ ++column_;
+ break;
+ case ']': // []
+ push_token(token(jsoncons::make_unique<flatten_projection>()), ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.pop_back(); // bracket_specifier
+ ++p_;
+ ++column_;
+ break;
+ case '?':
+ push_token(token(begin_filter_arg), ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.back() = path_state::filter;
+ state_stack_.emplace_back(path_state::rhs_expression);
+ state_stack_.emplace_back(path_state::lhs_expression);
+ ++p_;
+ ++column_;
+ break;
+ case ':': // slice_expression
+ state_stack_.back() = path_state::rhs_slice_expression_stop ;
+ state_stack_.emplace_back(path_state::number);
+ ++p_;
+ ++column_;
+ break;
+ // number
+ case '-':case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':
+ state_stack_.back() = path_state::index_or_slice_expression;
+ state_stack_.emplace_back(path_state::number);
+ break;
+ default:
+ ec = jmespath_errc::expected_index_expression;
+ return jmespath_expression();
+ }
+ break;
+ case path_state::bracket_specifier_or_multi_select_list:
+ switch(*p_)
+ {
+ case '*':
+ if (p_+1 >= end_input_)
+ {
+ ec = jmespath_errc::unexpected_end_of_input;
+ return jmespath_expression();
+ }
+ if (*(p_+1) == ']')
+ {
+ state_stack_.back() = path_state::bracket_specifier;
+ }
+ else
+ {
+ push_token(token(begin_multi_select_list_arg), ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.back() = path_state::multi_select_list;
+ state_stack_.emplace_back(path_state::lhs_expression);
+ }
+ break;
+ case ']': // []
+ case '?':
+ case ':': // slice_expression
+ case '-':case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':
+ state_stack_.back() = path_state::bracket_specifier;
+ break;
+ default:
+ push_token(token(begin_multi_select_list_arg), ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.back() = path_state::multi_select_list;
+ state_stack_.emplace_back(path_state::lhs_expression);
+ break;
+ }
+ break;
+
+ case path_state::expect_multi_select_list:
+ switch(*p_)
+ {
+ case ']':
+ case '?':
+ case ':':
+ case '-':case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':
+ ec = jmespath_errc::expected_multi_select_list;
+ return jmespath_expression();
+ case '*':
+ push_token(token(jsoncons::make_unique<list_projection>()), ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.back() = path_state::expect_rbracket;
+ ++p_;
+ ++column_;
+ break;
+ default:
+ push_token(token(begin_multi_select_list_arg), ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.back() = path_state::multi_select_list;
+ state_stack_.emplace_back(path_state::lhs_expression);
+ break;
+ }
+ break;
+
+ case path_state::multi_select_hash:
+ switch(*p_)
+ {
+ case '*':
+ case ']':
+ case '?':
+ case ':':
+ case '-':case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':
+ break;
+ default:
+ state_stack_.back() = path_state::key_val_expr;
+ break;
+ }
+ break;
+
+ case path_state::index_or_slice_expression:
+ switch(*p_)
+ {
+ case ']':
+ {
+ if (buffer.empty())
+ {
+ push_token(token(jsoncons::make_unique<flatten_projection>()), ec);
+ if (ec) {return jmespath_expression();}
+ }
+ else
+ {
+ int64_t val{ 0 };
+ auto r = jsoncons::detail::to_integer(buffer.data(), buffer.size(), val);
+ if (!r)
+ {
+ ec = jmespath_errc::invalid_number;
+ return jmespath_expression();
+ }
+ push_token(token(jsoncons::make_unique<index_selector>(val)), ec);
+ if (ec) {return jmespath_expression();}
+
+ buffer.clear();
+ }
+ state_stack_.pop_back(); // bracket_specifier
+ ++p_;
+ ++column_;
+ break;
+ }
+ case ':':
+ {
+ if (!buffer.empty())
+ {
+ int64_t val;
+ auto r = jsoncons::detail::to_integer(buffer.data(), buffer.size(), val);
+ if (!r)
+ {
+ ec = jmespath_errc::invalid_number;
+ return jmespath_expression();
+ }
+ slic.start_ = val;
+ buffer.clear();
+ }
+ state_stack_.back() = path_state::rhs_slice_expression_stop;
+ state_stack_.emplace_back(path_state::number);
+ ++p_;
+ ++column_;
+ break;
+ }
+ default:
+ ec = jmespath_errc::expected_rbracket;
+ return jmespath_expression();
+ }
+ break;
+ case path_state::rhs_slice_expression_stop :
+ {
+ if (!buffer.empty())
+ {
+ int64_t val{ 0 };
+ auto r = jsoncons::detail::to_integer(buffer.data(), buffer.size(), val);
+ if (!r)
+ {
+ ec = jmespath_errc::invalid_number;
+ return jmespath_expression();
+ }
+ slic.stop_ = jsoncons::optional<int64_t>(val);
+ buffer.clear();
+ }
+ switch(*p_)
+ {
+ case ']':
+ push_token(token(jsoncons::make_unique<slice_projection>(slic)), ec);
+ if (ec) {return jmespath_expression();}
+ slic = slice{};
+ state_stack_.pop_back(); // bracket_specifier2
+ ++p_;
+ ++column_;
+ break;
+ case ':':
+ state_stack_.back() = path_state::rhs_slice_expression_step;
+ state_stack_.emplace_back(path_state::number);
+ ++p_;
+ ++column_;
+ break;
+ default:
+ ec = jmespath_errc::expected_rbracket;
+ return jmespath_expression();
+ }
+ break;
+ }
+ case path_state::rhs_slice_expression_step:
+ {
+ if (!buffer.empty())
+ {
+ int64_t val{ 0 };
+ auto r = jsoncons::detail::to_integer(buffer.data(), buffer.size(), val);
+ if (!r)
+ {
+ ec = jmespath_errc::invalid_number;
+ return jmespath_expression();
+ }
+ if (val == 0)
+ {
+ ec = jmespath_errc::step_cannot_be_zero;
+ return jmespath_expression();
+ }
+ slic.step_ = val;
+ buffer.clear();
+ }
+ switch(*p_)
+ {
+ case ']':
+ push_token(token(jsoncons::make_unique<slice_projection>(slic)), ec);
+ if (ec) {return jmespath_expression();}
+ buffer.clear();
+ slic = slice{};
+ state_stack_.pop_back(); // rhs_slice_expression_step
+ ++p_;
+ ++column_;
+ break;
+ default:
+ ec = jmespath_errc::expected_rbracket;
+ return jmespath_expression();
+ }
+ break;
+ }
+ case path_state::expect_rbracket:
+ {
+ switch(*p_)
+ {
+ case ']':
+ state_stack_.pop_back(); // expect_rbracket
+ ++p_;
+ ++column_;
+ break;
+ default:
+ ec = jmespath_errc::expected_rbracket;
+ return jmespath_expression();
+ }
+ break;
+ }
+ case path_state::expect_rparen:
+ switch (*p_)
+ {
+ case ' ':case '\t':case '\r':case '\n':
+ advance_past_space_character(ec);
+ break;
+ case ')':
+ ++p_;
+ ++column_;
+ push_token(rparen_arg, ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.back() = path_state::rhs_expression;
+ break;
+ default:
+ ec = jmespath_errc::expected_rparen;
+ return jmespath_expression();
+ }
+ break;
+ case path_state::key_val_expr:
+ {
+ switch (*p_)
+ {
+ case ' ':case '\t':case '\r':case '\n':
+ advance_past_space_character(ec);
+ break;
+ case '\"':
+ state_stack_.back() = path_state::expect_colon;
+ state_stack_.emplace_back(path_state::key_expr);
+ state_stack_.emplace_back(path_state::quoted_string);
+ ++p_;
+ ++column_;
+ break;
+ case '\'':
+ state_stack_.back() = path_state::expect_colon;
+ state_stack_.emplace_back(path_state::raw_string);
+ ++p_;
+ ++column_;
+ break;
+ default:
+ if ((*p_ >= 'A' && *p_ <= 'Z') || (*p_ >= 'a' && *p_ <= 'z') || (*p_ == '_'))
+ {
+ state_stack_.back() = path_state::expect_colon;
+ state_stack_.emplace_back(path_state::key_expr);
+ state_stack_.emplace_back(path_state::unquoted_string);
+ buffer.push_back(*p_);
+ ++p_;
+ ++column_;
+ }
+ else
+ {
+ ec = jmespath_errc::expected_key;
+ return jmespath_expression();
+ }
+ break;
+ };
+ break;
+ }
+ case path_state::cmp_lt_or_lte:
+ {
+ switch(*p_)
+ {
+ case '=':
+ push_token(token(resources_.get_lte_operator()), ec);
+ push_token(token(current_node_arg), ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.pop_back();
+ ++p_;
+ ++column_;
+ break;
+ default:
+ push_token(token(resources_.get_lt_operator()), ec);
+ push_token(token(current_node_arg), ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.pop_back();
+ break;
+ }
+ break;
+ }
+ case path_state::cmp_gt_or_gte:
+ {
+ switch(*p_)
+ {
+ case '=':
+ push_token(token(resources_.get_gte_operator()), ec);
+ push_token(token(current_node_arg), ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.pop_back();
+ ++p_;
+ ++column_;
+ break;
+ default:
+ push_token(token(resources_.get_gt_operator()), ec);
+ push_token(token(current_node_arg), ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.pop_back();
+ break;
+ }
+ break;
+ }
+ case path_state::cmp_eq:
+ {
+ switch(*p_)
+ {
+ case '=':
+ push_token(token(resources_.get_eq_operator()), ec);
+ push_token(token(current_node_arg), ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.pop_back();
+ ++p_;
+ ++column_;
+ break;
+ default:
+ ec = jmespath_errc::expected_comparator;
+ return jmespath_expression();
+ }
+ break;
+ }
+ case path_state::cmp_ne:
+ {
+ switch(*p_)
+ {
+ case '=':
+ push_token(token(resources_.get_ne_operator()), ec);
+ push_token(token(current_node_arg), ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.pop_back();
+ ++p_;
+ ++column_;
+ break;
+ default:
+ ec = jmespath_errc::expected_comparator;
+ return jmespath_expression();
+ }
+ break;
+ }
+ case path_state::expect_dot:
+ {
+ switch(*p_)
+ {
+ case ' ':case '\t':case '\r':case '\n':
+ advance_past_space_character(ec);
+ break;
+ case '.':
+ state_stack_.pop_back(); // expect_dot
+ ++p_;
+ ++column_;
+ break;
+ default:
+ ec = jmespath_errc::expected_dot;
+ return jmespath_expression();
+ }
+ break;
+ }
+ case path_state::expect_pipe_or_or:
+ {
+ switch(*p_)
+ {
+ case '|':
+ push_token(token(resources_.get_or_operator()), ec);
+ push_token(token(current_node_arg), ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.pop_back();
+ ++p_;
+ ++column_;
+ break;
+ default:
+ push_token(token(pipe_arg), ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.pop_back();
+ break;
+ }
+ break;
+ }
+ case path_state::expect_and:
+ {
+ switch(*p_)
+ {
+ case '&':
+ push_token(token(resources_.get_and_operator()), ec);
+ push_token(token(current_node_arg), ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.pop_back(); // expect_and
+ ++p_;
+ ++column_;
+ break;
+ default:
+ ec = jmespath_errc::expected_and;
+ return jmespath_expression();
+ }
+ break;
+ }
+ case path_state::multi_select_list:
+ {
+ switch(*p_)
+ {
+ case ' ':case '\t':case '\r':case '\n':
+ advance_past_space_character(ec);
+ break;
+ case ',':
+ push_token(token(separator_arg), ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.emplace_back(path_state::lhs_expression);
+ ++p_;
+ ++column_;
+ break;
+ case '[':
+ state_stack_.emplace_back(path_state::lhs_expression);
+ break;
+ case '.':
+ state_stack_.emplace_back(path_state::sub_expression);
+ ++p_;
+ ++column_;
+ break;
+ case '|':
+ {
+ ++p_;
+ ++column_;
+ state_stack_.emplace_back(path_state::lhs_expression);
+ state_stack_.emplace_back(path_state::expect_pipe_or_or);
+ break;
+ }
+ case ']':
+ {
+ push_token(token(end_multi_select_list_arg), ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.pop_back();
+
+ ++p_;
+ ++column_;
+ break;
+ }
+ default:
+ ec = jmespath_errc::expected_rbracket;
+ return jmespath_expression();
+ }
+ break;
+ }
+ case path_state::filter:
+ {
+ switch(*p_)
+ {
+ case ' ':case '\t':case '\r':case '\n':
+ advance_past_space_character(ec);
+ break;
+ case ']':
+ {
+ push_token(token(end_filter_arg), ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.pop_back();
+ ++p_;
+ ++column_;
+ break;
+ }
+ default:
+ ec = jmespath_errc::expected_rbracket;
+ return jmespath_expression();
+ }
+ break;
+ }
+ case path_state::expect_rbrace:
+ {
+ switch(*p_)
+ {
+ case ' ':case '\t':case '\r':case '\n':
+ advance_past_space_character(ec);
+ break;
+ case ',':
+ push_token(token(separator_arg), ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.back() = path_state::key_val_expr;
+ ++p_;
+ ++column_;
+ break;
+ case '[':
+ case '{':
+ state_stack_.emplace_back(path_state::lhs_expression);
+ break;
+ case '.':
+ state_stack_.emplace_back(path_state::sub_expression);
+ ++p_;
+ ++column_;
+ break;
+ case '}':
+ {
+ state_stack_.pop_back();
+ push_token(end_multi_select_hash_arg, ec);
+ if (ec) {return jmespath_expression();}
+ ++p_;
+ ++column_;
+ break;
+ }
+ default:
+ ec = jmespath_errc::expected_rbrace;
+ return jmespath_expression();
+ }
+ break;
+ }
+ case path_state::expect_colon:
+ {
+ switch(*p_)
+ {
+ case ' ':case '\t':case '\r':case '\n':
+ advance_past_space_character(ec);
+ break;
+ case ':':
+ state_stack_.back() = path_state::expect_rbrace;
+ state_stack_.emplace_back(path_state::lhs_expression);
+ ++p_;
+ ++column_;
+ break;
+ default:
+ ec = jmespath_errc::expected_colon;
+ return jmespath_expression();
+ }
+ break;
+ }
+ }
+
+ }
+
+ if (state_stack_.empty())
+ {
+ ec = jmespath_errc::syntax_error;
+ return jmespath_expression();
+ }
+ while (state_stack_.size() > 1)
+ {
+ switch (state_stack_.back())
+ {
+ case path_state::rhs_expression:
+ if (state_stack_.size() > 1)
+ {
+ state_stack_.pop_back();
+ }
+ else
+ {
+ ec = jmespath_errc::syntax_error;
+ return jmespath_expression();
+ }
+ break;
+ case path_state::val_expr:
+ push_token(token(jsoncons::make_unique<identifier_selector>(buffer)), ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.pop_back();
+ break;
+ case path_state::identifier_or_function_expr:
+ push_token(token(jsoncons::make_unique<identifier_selector>(buffer)), ec);
+ if (ec) {return jmespath_expression();}
+ state_stack_.pop_back();
+ break;
+ case path_state::unquoted_string:
+ state_stack_.pop_back();
+ break;
+ default:
+ ec = jmespath_errc::syntax_error;
+ return jmespath_expression();
+ break;
+ }
+ }
+
+ if (!(state_stack_.size() == 1 && state_stack_.back() == path_state::rhs_expression))
+ {
+ ec = jmespath_errc::unexpected_end_of_input;
+ return jmespath_expression();
+ }
+
+ state_stack_.pop_back();
+
+ push_token(end_of_expression_arg, ec);
+ if (ec) {return jmespath_expression();}
+
+ //for (auto& t : output_stack_)
+ //{
+ // std::cout << t.to_string() << std::endl;
+ //}
+
+ return jmespath_expression(std::move(resources_), std::move(output_stack_));
+ }
+
+ void advance_past_space_character(std::error_code& ec)
+ {
+ switch (*p_)
+ {
+ case ' ':case '\t':
+ ++p_;
+ ++column_;
+ break;
+ case '\r':
+ if (p_+1 >= end_input_)
+ {
+ ec = jmespath_errc::unexpected_end_of_input;
+ return;
+ }
+ if (*(p_+1) == '\n')
+ ++p_;
+ ++line_;
+ column_ = 1;
+ ++p_;
+ break;
+ case '\n':
+ ++line_;
+ column_ = 1;
+ ++p_;
+ break;
+ default:
+ break;
+ }
+ }
+
+ void unwind_rparen(std::error_code& ec)
+ {
+ auto it = operator_stack_.rbegin();
+ while (it != operator_stack_.rend() && !it->is_lparen())
+ {
+ output_stack_.emplace_back(std::move(*it));
+ ++it;
+ }
+ if (it == operator_stack_.rend())
+ {
+ ec = jmespath_errc::unbalanced_parentheses;
+ return;
+ }
+ ++it;
+ operator_stack_.erase(it.base(),operator_stack_.end());
+ }
+
+ void push_token(token&& tok, std::error_code& ec)
+ {
+ switch (tok.type())
+ {
+ case token_kind::end_filter:
+ {
+ unwind_rparen(ec);
+ std::vector<token> toks;
+ auto it = output_stack_.rbegin();
+ while (it != output_stack_.rend() && it->type() != token_kind::begin_filter)
+ {
+ toks.emplace_back(std::move(*it));
+ ++it;
+ }
+ if (it == output_stack_.rend())
+ {
+ ec = jmespath_errc::unbalanced_braces;
+ return;
+ }
+ if (toks.back().type() != token_kind::literal)
+ {
+ toks.emplace_back(current_node_arg);
+ }
+ std::reverse(toks.begin(), toks.end());
+ ++it;
+ output_stack_.erase(it.base(),output_stack_.end());
+
+ if (!output_stack_.empty() && output_stack_.back().is_projection() &&
+ (tok.precedence_level() < output_stack_.back().precedence_level() ||
+ (tok.precedence_level() == output_stack_.back().precedence_level() && tok.is_right_associative())))
+ {
+ output_stack_.back().expression_->add_expression(jsoncons::make_unique<filter_expression>(std::move(toks)));
+ }
+ else
+ {
+ output_stack_.emplace_back(token(jsoncons::make_unique<filter_expression>(std::move(toks))));
+ }
+ break;
+ }
+ case token_kind::end_multi_select_list:
+ {
+ unwind_rparen(ec);
+ std::vector<std::vector<token>> vals;
+ auto it = output_stack_.rbegin();
+ while (it != output_stack_.rend() && it->type() != token_kind::begin_multi_select_list)
+ {
+ std::vector<token> toks;
+ do
+ {
+ toks.emplace_back(std::move(*it));
+ ++it;
+ } while (it != output_stack_.rend() && it->type() != token_kind::begin_multi_select_list && it->type() != token_kind::separator);
+ if (it->type() == token_kind::separator)
+ {
+ ++it;
+ }
+ if (toks.back().type() != token_kind::literal)
+ {
+ toks.emplace_back(current_node_arg);
+ }
+ std::reverse(toks.begin(), toks.end());
+ vals.emplace_back(std::move(toks));
+ }
+ if (it == output_stack_.rend())
+ {
+ ec = jmespath_errc::unbalanced_braces;
+ return;
+ }
+ ++it;
+ output_stack_.erase(it.base(),output_stack_.end());
+ std::reverse(vals.begin(), vals.end());
+ if (!output_stack_.empty() && output_stack_.back().is_projection() &&
+ (tok.precedence_level() < output_stack_.back().precedence_level() ||
+ (tok.precedence_level() == output_stack_.back().precedence_level() && tok.is_right_associative())))
+ {
+ output_stack_.back().expression_->add_expression(jsoncons::make_unique<multi_select_list>(std::move(vals)));
+ }
+ else
+ {
+ output_stack_.emplace_back(token(jsoncons::make_unique<multi_select_list>(std::move(vals))));
+ }
+ break;
+ }
+ case token_kind::end_multi_select_hash:
+ {
+ unwind_rparen(ec);
+ std::vector<key_tokens> key_toks;
+ auto it = output_stack_.rbegin();
+ while (it != output_stack_.rend() && it->type() != token_kind::begin_multi_select_hash)
+ {
+ std::vector<token> toks;
+ do
+ {
+ toks.emplace_back(std::move(*it));
+ ++it;
+ } while (it != output_stack_.rend() && it->type() != token_kind::key);
+ JSONCONS_ASSERT(it->is_key());
+ auto key = std::move(it->key_);
+ ++it;
+ if (it->type() == token_kind::separator)
+ {
+ ++it;
+ }
+ if (toks.back().type() != token_kind::literal)
+ {
+ toks.emplace_back(current_node_arg);
+ }
+ std::reverse(toks.begin(), toks.end());
+ key_toks.emplace_back(std::move(key), std::move(toks));
+ }
+ if (it == output_stack_.rend())
+ {
+ ec = jmespath_errc::unbalanced_braces;
+ return;
+ }
+ std::reverse(key_toks.begin(), key_toks.end());
+ ++it;
+ output_stack_.erase(it.base(),output_stack_.end());
+
+ if (!output_stack_.empty() && output_stack_.back().is_projection() &&
+ (tok.precedence_level() < output_stack_.back().precedence_level() ||
+ (tok.precedence_level() == output_stack_.back().precedence_level() && tok.is_right_associative())))
+ {
+ output_stack_.back().expression_->add_expression(jsoncons::make_unique<multi_select_hash>(std::move(key_toks)));
+ }
+ else
+ {
+ output_stack_.emplace_back(token(jsoncons::make_unique<multi_select_hash>(std::move(key_toks))));
+ }
+ break;
+ }
+ case token_kind::end_expression_type:
+ {
+ std::vector<token> toks;
+ auto it = output_stack_.rbegin();
+ while (it != output_stack_.rend() && it->type() != token_kind::begin_expression_type)
+ {
+ toks.emplace_back(std::move(*it));
+ ++it;
+ }
+ if (it == output_stack_.rend())
+ {
+ JSONCONS_THROW(json_runtime_error<std::runtime_error>("Unbalanced braces"));
+ }
+ if (toks.back().type() != token_kind::literal)
+ {
+ toks.emplace_back(current_node_arg);
+ }
+ std::reverse(toks.begin(), toks.end());
+ output_stack_.erase(it.base(),output_stack_.end());
+ output_stack_.emplace_back(token(jsoncons::make_unique<function_expression>(std::move(toks))));
+ break;
+ }
+ case token_kind::literal:
+ if (!output_stack_.empty() && output_stack_.back().type() == token_kind::current_node)
+ {
+ output_stack_.back() = std::move(tok);
+ }
+ else
+ {
+ output_stack_.emplace_back(std::move(tok));
+ }
+ break;
+ case token_kind::expression:
+ if (!output_stack_.empty() && output_stack_.back().is_projection() &&
+ (tok.precedence_level() < output_stack_.back().precedence_level() ||
+ (tok.precedence_level() == output_stack_.back().precedence_level() && tok.is_right_associative())))
+ {
+ output_stack_.back().expression_->add_expression(std::move(tok.expression_));
+ }
+ else
+ {
+ output_stack_.emplace_back(std::move(tok));
+ }
+ break;
+ case token_kind::rparen:
+ {
+ unwind_rparen(ec);
+ break;
+ }
+ case token_kind::end_function:
+ {
+ unwind_rparen(ec);
+ std::vector<token> toks;
+ auto it = output_stack_.rbegin();
+ std::size_t arg_count = 0;
+ while (it != output_stack_.rend() && it->type() != token_kind::function)
+ {
+ if (it->type() == token_kind::argument)
+ {
+ ++arg_count;
+ }
+ toks.emplace_back(std::move(*it));
+ ++it;
+ }
+ if (it == output_stack_.rend())
+ {
+ ec = jmespath_errc::unbalanced_parentheses;
+ return;
+ }
+ if (it->arity() && arg_count != *(it->arity()))
+ {
+ ec = jmespath_errc::invalid_arity;
+ return;
+ }
+ if (toks.back().type() != token_kind::literal)
+ {
+ toks.emplace_back(current_node_arg);
+ }
+ std::reverse(toks.begin(), toks.end());
+ toks.push_back(std::move(*it));
+ ++it;
+ output_stack_.erase(it.base(),output_stack_.end());
+
+ if (!output_stack_.empty() && output_stack_.back().is_projection() &&
+ (tok.precedence_level() < output_stack_.back().precedence_level() ||
+ (tok.precedence_level() == output_stack_.back().precedence_level() && tok.is_right_associative())))
+ {
+ output_stack_.back().expression_->add_expression(jsoncons::make_unique<function_expression>(std::move(toks)));
+ }
+ else
+ {
+ output_stack_.emplace_back(token(jsoncons::make_unique<function_expression>(std::move(toks))));
+ }
+ break;
+ }
+ case token_kind::end_of_expression:
+ {
+ auto it = operator_stack_.rbegin();
+ while (it != operator_stack_.rend())
+ {
+ output_stack_.emplace_back(std::move(*it));
+ ++it;
+ }
+ operator_stack_.clear();
+ break;
+ }
+ case token_kind::unary_operator:
+ case token_kind::binary_operator:
+ {
+ if (operator_stack_.empty() || operator_stack_.back().is_lparen())
+ {
+ operator_stack_.emplace_back(std::move(tok));
+ }
+ else if (tok.precedence_level() < operator_stack_.back().precedence_level()
+ || (tok.precedence_level() == operator_stack_.back().precedence_level() && tok.is_right_associative()))
+ {
+ operator_stack_.emplace_back(std::move(tok));
+ }
+ else
+ {
+ auto it = operator_stack_.rbegin();
+ while (it != operator_stack_.rend() && it->is_operator()
+ && (tok.precedence_level() > it->precedence_level()
+ || (tok.precedence_level() == it->precedence_level() && tok.is_right_associative())))
+ {
+ output_stack_.emplace_back(std::move(*it));
+ ++it;
+ }
+
+ operator_stack_.erase(it.base(),operator_stack_.end());
+ operator_stack_.emplace_back(std::move(tok));
+ }
+ break;
+ }
+ case token_kind::separator:
+ {
+ unwind_rparen(ec);
+ output_stack_.emplace_back(std::move(tok));
+ operator_stack_.emplace_back(token(lparen_arg));
+ break;
+ }
+ case token_kind::begin_filter:
+ output_stack_.emplace_back(std::move(tok));
+ operator_stack_.emplace_back(token(lparen_arg));
+ break;
+ case token_kind::begin_multi_select_list:
+ output_stack_.emplace_back(std::move(tok));
+ operator_stack_.emplace_back(token(lparen_arg));
+ break;
+ case token_kind::begin_multi_select_hash:
+ output_stack_.emplace_back(std::move(tok));
+ operator_stack_.emplace_back(token(lparen_arg));
+ break;
+ case token_kind::function:
+ output_stack_.emplace_back(std::move(tok));
+ operator_stack_.emplace_back(token(lparen_arg));
+ break;
+ case token_kind::current_node:
+ output_stack_.emplace_back(std::move(tok));
+ break;
+ case token_kind::key:
+ case token_kind::pipe:
+ case token_kind::argument:
+ case token_kind::begin_expression_type:
+ output_stack_.emplace_back(std::move(tok));
+ break;
+ case token_kind::lparen:
+ operator_stack_.emplace_back(std::move(tok));
+ break;
+ default:
+ break;
+ }
+ }
+
+ uint32_t append_to_codepoint(uint32_t cp, int c, std::error_code& ec)
+ {
+ cp *= 16;
+ if (c >= '0' && c <= '9')
+ {
+ cp += c - '0';
+ }
+ else if (c >= 'a' && c <= 'f')
+ {
+ cp += c - 'a' + 10;
+ }
+ else if (c >= 'A' && c <= 'F')
+ {
+ cp += c - 'A' + 10;
+ }
+ else
+ {
+ ec = jmespath_errc::invalid_codepoint;
+ }
+ return cp;
+ }
+ };
+
+ } // detail
+
+ template <class Json>
+ using jmespath_expression = typename jsoncons::jmespath::detail::jmespath_evaluator<Json,const Json&>::jmespath_expression;
+
+ template<class Json>
+ Json search(const Json& doc, const typename Json::string_view_type& path)
+ {
+ jsoncons::jmespath::detail::jmespath_evaluator<Json,const Json&> evaluator;
+ std::error_code ec;
+ auto expr = evaluator.compile(path.data(), path.size(), ec);
+ if (ec)
+ {
+ JSONCONS_THROW(jmespath_error(ec, evaluator.line(), evaluator.column()));
+ }
+ auto result = expr.evaluate(doc, ec);
+ if (ec)
+ {
+ JSONCONS_THROW(jmespath_error(ec));
+ }
+ return result;
+ }
+
+ template<class Json>
+ Json search(const Json& doc, const typename Json::string_view_type& path, std::error_code& ec)
+ {
+ jsoncons::jmespath::detail::jmespath_evaluator<Json,const Json&> evaluator;
+ auto expr = evaluator.compile(path.data(), path.size(), ec);
+ if (ec)
+ {
+ return Json::null();
+ }
+ auto result = expr.evaluate(doc, ec);
+ if (ec)
+ {
+ return Json::null();
+ }
+ return result;
+ }
+
+ template <class Json>
+ jmespath_expression<Json> make_expression(const typename json::string_view_type& expr)
+ {
+ return jmespath_expression<Json>::compile(expr);
+ }
+
+ template <class Json>
+ jmespath_expression<Json> make_expression(const typename json::string_view_type& expr,
+ std::error_code& ec)
+ {
+ return jmespath_expression<Json>::compile(expr, ec);
+ }
+
+
+} // namespace jmespath
+} // namespace jsoncons
+
+#endif
diff --git a/include/jsoncons_ext/jmespath/jmespath_error.hpp b/include/jsoncons_ext/jmespath/jmespath_error.hpp
new file mode 100644
index 0000000..6422c65
--- /dev/null
+++ b/include/jsoncons_ext/jmespath/jmespath_error.hpp
@@ -0,0 +1,215 @@
+/// Copyright 2020 Daniel Parker
+// Distributed under the Boost license, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+// See https://github.com/danielaparker/jsoncons for latest version
+
+#ifndef JSONCONS_JMESPATH_JMESPATH_ERROR_HPP
+#define JSONCONS_JMESPATH_JMESPATH_ERROR_HPP
+
+#include <jsoncons/json_exception.hpp>
+#include <system_error>
+
+namespace jsoncons { namespace jmespath {
+
+ class jmespath_error : public std::system_error, public virtual json_exception
+ {
+ std::size_t line_number_;
+ std::size_t column_number_;
+ mutable std::string what_;
+ public:
+ jmespath_error(std::error_code ec)
+ : std::system_error(ec), line_number_(0), column_number_(0)
+ {
+ }
+ jmespath_error(std::error_code ec, const std::string& what_arg)
+ : std::system_error(ec, what_arg), line_number_(0), column_number_(0)
+ {
+ }
+ jmespath_error(std::error_code ec, std::size_t position)
+ : std::system_error(ec), line_number_(0), column_number_(position)
+ {
+ }
+ jmespath_error(std::error_code ec, std::size_t line, std::size_t column)
+ : std::system_error(ec), line_number_(line), column_number_(column)
+ {
+ }
+ jmespath_error(const jmespath_error& other) = default;
+
+ jmespath_error(jmespath_error&& other) = default;
+
+ const char* what() const noexcept override
+ {
+ if (what_.empty())
+ {
+ JSONCONS_TRY
+ {
+ what_.append(std::system_error::what());
+ if (line_number_ != 0 && column_number_ != 0)
+ {
+ what_.append(" at line ");
+ what_.append(std::to_string(line_number_));
+ what_.append(" and column ");
+ what_.append(std::to_string(column_number_));
+ }
+ else if (column_number_ != 0)
+ {
+ what_.append(" at position ");
+ what_.append(std::to_string(column_number_));
+ }
+ return what_.c_str();
+ }
+ JSONCONS_CATCH(...)
+ {
+ return std::system_error::what();
+ }
+ }
+ else
+ {
+ return what_.c_str();
+ }
+ }
+
+ std::size_t line() const noexcept
+ {
+ return line_number_;
+ }
+
+ std::size_t column() const noexcept
+ {
+ return column_number_;
+ }
+ };
+
+enum class jmespath_errc
+{
+ success = 0,
+ expected_identifier,
+ expected_index,
+ expected_A_Za_Z_,
+ expected_rbracket,
+ expected_rparen,
+ expected_rbrace,
+ expected_colon,
+ expected_dot,
+ expected_or,
+ expected_and,
+ expected_multi_select_list,
+ invalid_number,
+ invalid_literal,
+ expected_comparator,
+ expected_key,
+ invalid_argument,
+ unknown_function,
+ invalid_type,
+ unexpected_end_of_input,
+ step_cannot_be_zero,
+ syntax_error,
+ invalid_codepoint,
+ illegal_escaped_character,
+ unbalanced_parentheses,
+ unbalanced_braces,
+ invalid_arity,
+ identifier_not_found,
+ expected_index_expression,
+ unknown_error
+};
+
+class jmespath_error_category_impl
+ : public std::error_category
+{
+public:
+ const char* name() const noexcept override
+ {
+ return "jsoncons/jmespath";
+ }
+ std::string message(int ev) const override
+ {
+ switch (static_cast<jmespath_errc>(ev))
+ {
+ case jmespath_errc::expected_identifier:
+ return "Expected identifier";
+ case jmespath_errc::expected_index:
+ return "Expected index";
+ case jmespath_errc::expected_A_Za_Z_:
+ return "Expected A-Z, a-z, or _";
+ case jmespath_errc::expected_rbracket:
+ return "Expected ]";
+ case jmespath_errc::expected_rparen:
+ return "Expected )";
+ case jmespath_errc::expected_rbrace:
+ return "Expected }";
+ case jmespath_errc::expected_colon:
+ return "Expected :";
+ case jmespath_errc::expected_dot:
+ return "Expected \".\"";
+ case jmespath_errc::expected_or:
+ return "Expected \"||\"";
+ case jmespath_errc::expected_and:
+ return "Expected \"&&\"";
+ case jmespath_errc::expected_multi_select_list:
+ return "Expected multi-select-list";
+ case jmespath_errc::invalid_number:
+ return "Invalid number";
+ case jmespath_errc::invalid_literal:
+ return "Invalid literal";
+ case jmespath_errc::expected_comparator:
+ return "Expected <, <=, ==, >=, > or !=";
+ case jmespath_errc::expected_key:
+ return "Expected key";
+ case jmespath_errc::invalid_argument:
+ return "Invalid argument type";
+ case jmespath_errc::unknown_function:
+ return "Unknown function";
+ case jmespath_errc::invalid_type:
+ return "Invalid type";
+ case jmespath_errc::unexpected_end_of_input:
+ return "Unexpected end of jmespath input";
+ case jmespath_errc::step_cannot_be_zero:
+ return "Slice step cannot be zero";
+ case jmespath_errc::syntax_error:
+ return "Syntax error";
+ case jmespath_errc::invalid_codepoint:
+ return "Invalid codepoint";
+ case jmespath_errc::illegal_escaped_character:
+ return "Illegal escaped character";
+ case jmespath_errc::unbalanced_parentheses:
+ return "Unbalanced parentheses";
+ case jmespath_errc::unbalanced_braces:
+ return "Unbalanced braces";
+ case jmespath_errc::invalid_arity:
+ return "Function called with wrong number of arguments";
+ case jmespath_errc::identifier_not_found:
+ return "Identifier not found";
+ case jmespath_errc::expected_index_expression:
+ return "Expected index expression";
+ case jmespath_errc::unknown_error:
+ default:
+ return "Unknown jmespath parser error";
+ }
+ }
+};
+
+inline
+const std::error_category& jmespath_error_category()
+{
+ static jmespath_error_category_impl instance;
+ return instance;
+}
+
+inline
+std::error_code make_error_code(jmespath_errc result)
+{
+ return std::error_code(static_cast<int>(result),jmespath_error_category());
+}
+
+}}
+
+namespace std {
+ template<>
+ struct is_error_code_enum<jsoncons::jmespath::jmespath_errc> : public true_type
+ {
+ };
+}
+
+#endif