diff options
Diffstat (limited to 'include/jsoncons_ext/jmespath')
| -rw-r--r-- | include/jsoncons_ext/jmespath/jmespath.hpp | 5215 | ||||
| -rw-r--r-- | include/jsoncons_ext/jmespath/jmespath_error.hpp | 215 | 
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'}, ¬_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 ¬_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 <_oper; +            } + +            const binary_operator* get_lte_operator() const +            { +                static const lte_operator lte_oper; +                return <e_oper; +            } + +            const binary_operator* get_gt_operator() const +            { +                static const gt_operator gt_oper; +                return >_oper; +            } + +            const binary_operator* get_gte_operator() const +            { +                static const gte_operator gte_oper; +                return >e_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 |