diff options
author | Manoj Srivastava <srivasta@debian.org> | 2020-05-22 20:05:37 -0700 |
---|---|---|
committer | Manoj Srivastava <srivasta@debian.org> | 2020-05-22 21:39:31 -0700 |
commit | 035291b7f18974925f9a85a41e057bdc462c75f1 (patch) | |
tree | d69056be1a045aec185393b52dadb6fc2d5f50c9 /vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath | |
parent | 9714b44a37dfc03aa00187726beea7ed8257415e (diff) | |
parent | 4e9b9c402ed95bf9a17fd6d795bc49bb4128a6fa (diff) |
Merge branch 'upstream'
Diffstat (limited to 'vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath')
3 files changed, 2491 insertions, 0 deletions
diff --git a/vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/json_query.hpp b/vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/json_query.hpp new file mode 100644 index 00000000..7e530abd --- /dev/null +++ b/vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/json_query.hpp @@ -0,0 +1,921 @@ +// Copyright 2013 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_JSONPATH_JSONQUERY_HPP +#define JSONCONS_JSONPATH_JSONQUERY_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <memory> +#include "jsoncons/json.hpp" +#include "jsonpath_filter.hpp" +#include "jsonpath_error_category.hpp" + +namespace jsoncons { namespace jsonpath { + + template<typename CharT> + bool try_string_to_index(const CharT *s, size_t length, size_t* value) + { + static const size_t max_value = std::numeric_limits<size_t>::max JSONCONS_NO_MACRO_EXP(); + static const size_t max_value_div_10 = max_value / 10; + + size_t n = 0; + for (size_t i = 0; i < length; ++i) + { + CharT c = s[i]; + switch (c) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + { + size_t x = c - '0'; + if (n > max_value_div_10) + { + return false; + } + n = n * 10; + if (n > max_value - x) + { + return false; + } + + n += x; + } + break; + default: + return false; + break; + } + } + *value = n; + return true; + } + + template <typename CharT> + struct json_jsonpath_traits + { + }; + + template <> + struct json_jsonpath_traits<char> + { + static const std::string length_literal() {return "length";}; + }; + + template <> + struct json_jsonpath_traits<wchar_t> // assume utf16 + { + static const std::wstring length_literal() {return L"length";}; + }; + +// here + +template<class JsonT> +JsonT json_query(const JsonT& root, const typename JsonT::char_type* path, size_t length) +{ + jsonpath_evaluator<JsonT> evaluator; + evaluator.evaluate(root,path,length); + return evaluator.get_values(); +} + +template<class JsonT> +JsonT json_query(const JsonT& root, const typename JsonT::string_type& path) +{ + return json_query(root,path.data(),path.length()); +} + +template<class JsonT> +JsonT json_query(const JsonT& root, const typename JsonT::char_type* path) +{ + return json_query(root,path,std::char_traits<typename JsonT::char_type>::length(path)); +} + +enum class states +{ + start, + cr, + lf, + expect_separator, + expect_unquoted_name, + unquoted_name, + single_quoted_name, + double_quoted_name, + left_bracket, + left_bracket_start, + left_bracket_end, + left_bracket_end2, + left_bracket_step, + left_bracket_step2, + expect_right_bracket, + dot +}; + +template<class JsonT> +class jsonpath_evaluator : private basic_parsing_context<typename JsonT::char_type> +{ +private: + typedef typename JsonT::char_type char_type; + typedef typename JsonT::string_type string_type; + typedef const JsonT* cjson_ptr; + typedef std::vector<cjson_ptr> node_set; + + basic_parse_error_handler<char_type> *err_handler_; + states state_; + string_type buffer_; + size_t start_; + size_t end_; + size_t step_; + bool positive_start_; + bool positive_end_; + bool positive_step_; + bool end_undefined_; + std::vector<node_set> stack_; + bool recursive_descent_; + std::vector<cjson_ptr> nodes_; + std::vector<std::shared_ptr<JsonT>> temp_; + size_t line_; + size_t column_; + const char_type* begin_input_; + const char_type* end_input_; + const char_type* p_; + states pre_line_break_state_; + + void transfer_nodes() + { + stack_.push_back(nodes_); + nodes_.clear(); + } + +public: + jsonpath_evaluator() + : err_handler_(std::addressof(basic_default_parse_error_handler<char_type>::instance())) + { + } + + JsonT get_values() const + { + JsonT result = JsonT::make_array(); + + if (stack_.size() > 0) + { + for (size_t i = 0; i < stack_.back().size(); ++i) + { + cjson_ptr p = stack_.back()[i]; + result.add(*p); + } + } + return result; + } + + void evaluate(const JsonT& root, const string_type& path) + { + evaluate(root,path.data(),path.length()); + } + void evaluate(const JsonT& root, const char_type* path) + { + evaluate(root,path,std::char_traits<char_type>::length(path)); + } + + void evaluate(const JsonT& root, const char_type* path, size_t length) + { + begin_input_ = path; + end_input_ = path + length; + p_ = begin_input_; + + line_ = 1; + column_ = 1; + state_ = states::start; + buffer_.clear(); + start_ = 0; + end_ = 0; + step_ = 1; + recursive_descent_ = false; + positive_start_ = true; + positive_end_ = true; + positive_step_ = true; + end_undefined_ = false; + + while (p_ < end_input_) + { + switch (state_) + { + case states::cr: + ++line_; + column_ = 1; + switch (*p_) + { + case '\n': + state_ = pre_line_break_state_; + ++p_; + ++column_; + break; + default: + state_ = pre_line_break_state_; + break; + } + break; + case states::lf: + ++line_; + column_ = 1; + state_ = pre_line_break_state_; + break; + case states::start: + switch (*p_) + { + case '\r': + pre_line_break_state_ = state_; + state_ = states::cr; + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + break; + case ' ':case '\t': + ++p_; + ++column_; + break; + case '$': + case '@': + { + node_set v; + v.push_back(std::addressof(root)); + stack_.push_back(v); + state_ = states::expect_separator; + } + break; + default: + err_handler_->fatal_error(std::error_code(jsonpath_parser_errc::expected_root, jsonpath_error_category()), *this); + break; + }; + ++p_; + ++column_; + break; + case states::dot: + switch (*p_) + { + case '.': + recursive_descent_ = true; + ++p_; + ++column_; + state_ = states::expect_unquoted_name; + break; + default: + state_ = states::expect_unquoted_name; + break; + } + break; + case states::expect_unquoted_name: + switch (*p_) + { + case '\r': + pre_line_break_state_ = state_; + state_ = states::cr; + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + break; + case '.': + err_handler_->fatal_error(std::error_code(jsonpath_parser_errc::expected_name, jsonpath_error_category()), *this); + ++p_; + ++column_; + break; + case '*': + end_all(); + transfer_nodes(); + state_ = states::expect_separator; + ++p_; + ++column_; + break; + default: + state_ = states::unquoted_name; + break; + } + break; + case states::expect_separator: + switch (*p_) + { + case '\r': + pre_line_break_state_ = state_; + state_ = states::cr; + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + break; + case ' ':case '\t': + ++p_; + ++column_; + break; + case '.': + state_ = states::dot; + break; + case '[': + state_ = states::left_bracket; + break; + default: + err_handler_->fatal_error(std::error_code(jsonpath_parser_errc::expected_separator, jsonpath_error_category()), *this); + break; + }; + ++p_; + ++column_; + break; + case states::expect_right_bracket: + switch (*p_) + { + case '\r': + pre_line_break_state_ = state_; + state_ = states::cr; + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + break; + case ',': + state_ = states::left_bracket; + break; + case ']': + transfer_nodes(); + state_ = states::expect_separator; + break; + case ' ':case '\t': + break; + default: + err_handler_->fatal_error(std::error_code(jsonpath_parser_errc::expected_right_bracket, jsonpath_error_category()), *this); + break; + } + ++p_; + ++column_; + break; + case states::left_bracket_step: + switch (*p_) + { + case '\r': + pre_line_break_state_ = state_; + state_ = states::cr; + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + break; + case '-': + positive_step_ = false; + state_ = states::left_bracket_step2; + break; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + step_ = static_cast<size_t>(*p_-'0'); + state_ = states::left_bracket_step2; + break; + case ']': + end_array_slice(); + transfer_nodes(); + state_ = states::expect_separator; + break; + } + ++p_; + ++column_; + break; + case states::left_bracket_step2: + switch (*p_) + { + case '\r': + pre_line_break_state_ = state_; + state_ = states::cr; + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + break; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + step_ = step_*10 + static_cast<size_t>(*p_-'0'); + break; + case ']': + end_array_slice(); + transfer_nodes(); + state_ = states::expect_separator; + break; + } + ++p_; + ++column_; + break; + case states::left_bracket_end: + switch (*p_) + { + case '\r': + pre_line_break_state_ = state_; + state_ = states::cr; + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + break; + case '-': + positive_end_ = false; + state_ = states::left_bracket_end2; + break; + case ':': + step_ = 0; + state_ = states::left_bracket_step; + break; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + end_undefined_ = false; + end_ = static_cast<size_t>(*p_-'0'); + state_ = states::left_bracket_end2; + break; + case ']': + end_array_slice(); + transfer_nodes(); + state_ = states::expect_separator; + break; + } + ++p_; + ++column_; + break; + case states::left_bracket_end2: + switch (*p_) + { + case '\r': + pre_line_break_state_ = state_; + state_ = states::cr; + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + break; + case ':': + step_ = 0; + state_ = states::left_bracket_step; + break; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + end_undefined_ = false; + end_ = end_*10 + static_cast<size_t>(*p_-'0'); + break; + case ']': + end_array_slice(); + transfer_nodes(); + state_ = states::expect_separator; + break; + } + ++p_; + ++column_; + break; + case states::left_bracket_start: + switch (*p_) + { + case '\r': + pre_line_break_state_ = state_; + state_ = states::cr; + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + break; + case ':': + step_ = 1; + end_undefined_ = true; + state_ = states::left_bracket_end; + break; + case ',': + find_elements(); + break; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + start_ = start_*10 + static_cast<size_t>(*p_-'0'); + break; + case ']': + find_elements(); + transfer_nodes(); + state_ = states::expect_separator; + break; + } + ++p_; + ++column_; + break; + case states::left_bracket: + switch (*p_) + { + case '\r': + pre_line_break_state_ = state_; + state_ = states::cr; + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + break; + case ' ':case '\t': + ++p_; + ++column_; + break; + case '(': + { + if (stack_.back().size() == 1) + { + jsonpath_filter_parser<JsonT> parser(&p_,&line_,&column_); + parser.parse(p_,end_input_); + auto index = parser.eval(*(stack_.back()[0])); + if (index.template is<size_t>()) + { + start_ = index. template as<size_t>(); + find_elements(); + } + else if (index.is_string()) + { + find(index.as_string()); + } + } + else + { + ++p_; + ++column_; + } + } + break; + case '?': + { + jsonpath_filter_parser<JsonT> parser(&p_,&line_,&column_); + parser.parse(p_,end_input_); + nodes_.clear(); + for (size_t j = 0; j < stack_.back().size(); ++j) + { + accept(*(stack_.back()[j]),parser); + } + } + break; + + case ':': + step_ = 1; + end_undefined_ = true; + state_ = states::left_bracket_end; + ++p_; + ++column_; + break; + case ',': + find_elements(); + ++p_; + ++column_; + break; + case '-': + positive_start_ = false; + state_ = states::left_bracket_start; + ++p_; + ++column_; + break; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + start_ = static_cast<size_t>(*p_-'0'); + state_ = states::left_bracket_start; + ++p_; + ++column_; + break; + case ']': + //find_elements(); + transfer_nodes(); + state_ = states::expect_separator; + ++p_; + ++column_; + break; + case '*': + end_all(); + //transfer_nodes(); + state_ = states::expect_right_bracket; + ++p_; + ++column_; + break; + case '\'': + state_ = states::single_quoted_name; + ++p_; + ++column_; + break; + case '\"': + state_ = states::double_quoted_name; + ++p_; + ++column_; + break; + default: + ++p_; + ++column_; + break; + } + break; + case states::unquoted_name: + switch (*p_) + { + case '\r': + pre_line_break_state_ = state_; + state_ = states::cr; + break; + case '\n': + pre_line_break_state_ = state_; + state_ = states::lf; + break; + case '[': + find(buffer_); + buffer_.clear(); + transfer_nodes(); + start_ = 0; + state_ = states::left_bracket; + break; + case '.': + find(buffer_); + buffer_.clear(); + transfer_nodes(); + state_ = states::dot; + break; + case ' ':case '\t': + break; + default: + buffer_.push_back(*p_); + break; + }; + ++p_; + ++column_; + break; + case states::single_quoted_name: + switch (*p_) + { + case '\'': + find(buffer_); + buffer_.clear(); + state_ = states::expect_right_bracket; + break; + case '\\': + buffer_.push_back(*p_); + if (p_+1 < end_input_) + { + ++p_; + ++column_; + buffer_.push_back(*p_); + } + break; + default: + buffer_.push_back(*p_); + break; + }; + ++p_; + ++column_; + break; + case states::double_quoted_name: + switch (*p_) + { + case '\"': + find(buffer_); + buffer_.clear(); + state_ = states::expect_right_bracket; + break; + case '\\': + buffer_.push_back(*p_); + if (p_+1 < end_input_) + { + ++p_; + ++column_; + buffer_.push_back(*p_); + } + break; + default: + buffer_.push_back(*p_); + break; + }; + ++p_; + ++column_; + break; + default: + ++p_; + ++column_; + break; + } + } + switch (state_) + { + case states::unquoted_name: + { + find(buffer_); + buffer_.clear(); + transfer_nodes(); + } + break; + default: + break; + } + } + + void accept(const JsonT& val, + jsonpath_filter_parser<JsonT>& filter) + { + if (val.is_object()) + { + if (recursive_descent_ && val.is_object()) + { + for (auto it = val.members().begin(); it != val.members().end(); ++it) + { + accept(it->value(),filter); + } + } + if (filter.exists(val)) + { + nodes_.push_back(std::addressof(val)); + } + } + else if (val.is_array()) + { + for (auto it = val.elements().begin(); it != val.elements().end(); ++it) + { + accept(*it,filter); + } + } + } + + + + void end_all() + { + for (size_t i = 0; i < stack_.back().size(); ++i) + { + cjson_ptr p = stack_.back()[i]; + if (p->is_array()) + { + for (auto it = p->elements().begin(); it != p->elements().end(); ++it) + { + nodes_.push_back(std::addressof(*it)); + } + } + else if (p->is_object()) + { + for (auto it = p->members().begin(); it != p->members().end(); ++it) + { + nodes_.push_back(std::addressof(it->value())); + } + } + + } + start_ = 0; + } + + void find_elements() + { + for (size_t i = 0; i < stack_.back().size(); ++i) + { + cjson_ptr p = stack_.back()[i]; + if (p->is_array() && start_ < p->size()) + { + nodes_.push_back(std::addressof((*p)[start_])); + } + } + start_ = 0; + } + + void end_array_slice() + { + if (positive_step_) + { + end_array_slice1(); + } + else + { + end_array_slice2(); + } + start_ = 0; + end_ = 0; + step_ = 1; + positive_start_ = positive_end_ = positive_step_ = true; + end_undefined_ = true; + } + + void end_array_slice1() + { + for (size_t i = 0; i < stack_.back().size(); ++i) + { + cjson_ptr p = stack_.back()[i]; + if (p->is_array()) + { + size_t start = positive_start_ ? start_ : p->size() - start_; + size_t end; + if (!end_undefined_) + { + end = positive_end_ ? end_ : p->size() - end_; + } + else + { + end = p->size(); + } + for (size_t j = start; j < end; j += step_) + { + if (p->is_array() && j < p->size()) + { + nodes_.push_back(std::addressof((*p)[j])); + } + } + } + } + } + + void end_array_slice2() + { + for (size_t i = 0; i < stack_.back().size(); ++i) + { + cjson_ptr p = stack_.back()[i]; + size_t start = positive_start_ ? start_ : p->size() - start_; + size_t end; + if (!end_undefined_) + { + end = positive_end_ ? end_ : p->size() - end_; + } + else + { + end = p->size(); + } + + size_t j = end + step_ - 1; + while (j > (start+step_-1)) + { + j -= step_; + if (p->is_array() && j < p->size()) + { + nodes_.push_back(std::addressof((*p)[j])); + } + } + } + } + + void find(const string_type& name) + { + if (name.length() > 0) + { + for (size_t i = 0; i < stack_.back().size(); ++i) + { + find1(*(stack_.back()[i]), name); + } + recursive_descent_ = false; + } + } + + void find1(const JsonT& context_val, const string_type& name) + { + if (context_val.is_object()) + { + if (context_val.count(name) > 0) + { + nodes_.push_back(std::addressof(context_val.at(name))); + } + if (recursive_descent_) + { + for (auto it = context_val.members().begin(); it != context_val.members().end(); ++it) + { + if (it->value().is_object() || it->value().is_array()) + { + find1(it->value(), name); + } + } + } + } + else if (context_val.is_array()) + { + size_t index = 0; + if (try_string_to_index(name.data(),name.size(),&index)) + { + if (index < context_val.size()) + { + nodes_.push_back(std::addressof(context_val[index])); + } + } + else if (name == json_jsonpath_traits<char_type>::length_literal() && context_val.size() > 0) + { + auto q = std::make_shared<JsonT>(context_val.size()); + temp_.push_back(q); + nodes_.push_back(q.get()); + } + if (recursive_descent_) + { + for (auto it = context_val.elements().begin(); it != context_val.elements().end(); ++it) + { + if (it->is_object() || it->is_array()) + { + find1(*it, name); + } + } + } + } + } + + size_t do_line_number() const override + { + return line_; + } + + size_t do_column_number() const override + { + return column_; + } + + char_type do_current_char() const override + { + return 0; //p_ < end_input_? *p_ : 0; + } + +}; + +}} + +#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/jsonpath_error_category.hpp b/vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/jsonpath_error_category.hpp new file mode 100644 index 00000000..7f6b6a12 --- /dev/null +++ b/vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/jsonpath_error_category.hpp @@ -0,0 +1,75 @@ +/// Copyright 2013 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_JSONPATH_JSONPATH_ERROR_CATEGORY_HPP +#define JSONCONS_JSONPATH_JSONPATH_ERROR_CATEGORY_HPP + +#include "jsoncons/jsoncons.hpp" +#include <system_error> + +namespace jsoncons { namespace jsonpath { + +namespace jsonpath_parser_errc +{ + const int expected_root = 1; + const int expected_right_bracket = 2; + const int expected_name = 3; + const int expected_separator = 4; + const int invalid_filter = 5; + const int invalid_filter_expected_slash = 6; + const int invalid_filter_unbalanced_paren = 7; + const int invalid_filter_unsupported_operator = 8; + const int invalid_filter_expected_right_brace = 9; + const int invalid_filter_expected_primary = 10; +} + +class jsonpath_error_category_impl + : public std::error_category +{ +public: + virtual const char* name() const JSONCONS_NOEXCEPT + { + return "jsonpath"; + } + virtual std::string message(int ev) const + { + switch (ev) + { + case jsonpath_parser_errc::expected_root: + return "Expected $"; + case jsonpath_parser_errc::expected_right_bracket: + return "Expected ]"; + case jsonpath_parser_errc::expected_name: + return "Expected a name following a dot"; + case jsonpath_parser_errc::expected_separator: + return "Expected dot or left bracket separator"; + case jsonpath_parser_errc::invalid_filter: + return "Invalid path filter"; + case jsonpath_parser_errc::invalid_filter_expected_slash: + return "Invalid path filter, expected '/'"; + case jsonpath_parser_errc::invalid_filter_unbalanced_paren: + return "Invalid path filter, unbalanced parenthesis"; + case jsonpath_parser_errc::invalid_filter_unsupported_operator: + return "Unsupported operator"; + case jsonpath_parser_errc::invalid_filter_expected_right_brace: + return "Invalid path filter, expected right brace }"; + case jsonpath_parser_errc::invalid_filter_expected_primary: + return "Invalid path filter, expected primary expression."; + default: + return "Unknown jsonpath parser error"; + } + } +}; + +inline +const std::error_category& jsonpath_error_category() +{ + static jsonpath_error_category_impl instance; + return instance; +} + +}} +#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/jsonpath_filter.hpp b/vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/jsonpath_filter.hpp new file mode 100644 index 00000000..b0ac51c6 --- /dev/null +++ b/vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/jsonpath_filter.hpp @@ -0,0 +1,1495 @@ +// Copyright 2013 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_JSONPATH_FILTER_HPP +#define JSONCONS_JSONPATH_FILTER_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <memory> +#include <regex> +#include "jsoncons/json.hpp" +#include "jsonpath_error_category.hpp" + +namespace jsoncons { namespace jsonpath { + +template <class JsonT> +class jsonpath_evaluator; + +enum class filter_states +{ + start, + cr, + lf, + expect_right_round_bracket, + expect_oper_or_right_round_bracket, + expect_path_or_value, + expect_regex, + regex, + single_quoted_text, + double_quoted_text, + unquoted_text, + path, + value, + oper +}; + +enum class token_types +{ + left_paren, + right_paren, + term, + eq, + ne, + regex, + ampamp, + pipepipe, + lt, + gt, + lte, + gte, + plus, + minus, + exclaim, + done +}; + +template <class JsonT> +class term +{ +public: + typedef typename JsonT::string_type string_type; + typedef typename JsonT::char_type char_type; + + virtual void initialize(const JsonT& context_node) + { + } + virtual bool accept_single_node() const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual JsonT evaluate_single_node() const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual bool exclaim() const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual bool eq(const term& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual bool eq(const JsonT& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual bool ne(const term& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual bool ne(const JsonT& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual bool regex(const term& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual bool regex2(const string_type& subject) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual bool ampamp(const term& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual bool ampamp(const JsonT& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual bool pipepipe(const term& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual bool pipepipe(const JsonT& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual bool lt(const term& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual bool lt(const JsonT& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual bool gt(const term& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual bool gt(const JsonT& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual JsonT minus(const term& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual JsonT minus(const JsonT& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual JsonT unary_minus() const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual JsonT plus(const term& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } + virtual JsonT plus(const JsonT& rhs) const + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); + } +}; + +template <class JsonT> +class token +{ + token_types type_; + std::shared_ptr<term<JsonT>> term_ptr_; +public: + token(token_types type) + : type_(type) + { + } + token(token_types type, std::shared_ptr<term<JsonT>> term_ptr) + : type_(type), term_ptr_(term_ptr) + { + } + token(const token& t) + : type_(t.type_), term_ptr_(t.term_ptr_) + { + } + + token_types type() const + { + return type_; + } + + std::shared_ptr<term<JsonT>> term_ptr() + { + return term_ptr_; + } + + void initialize(const JsonT& context_node) + { + if (term_ptr_.get() != nullptr) + { + term_ptr_->initialize(context_node); + } + } +}; + +template <class JsonT> +class token_stream +{ + std::vector<token<JsonT>>& tokens_; + size_t index_; +public: + token_stream(std::vector<token<JsonT>>& tokens) + : tokens_(tokens), index_(0) + { + } + + token<JsonT> get() + { + static token<JsonT> done = token<JsonT>(token_types::done); + return index_ < tokens_.size() ? tokens_[index_++] : done; + } + void putback() + { + --index_; + } +}; + +template <class JsonT> +bool ampamp(const JsonT& lhs, const JsonT& rhs) +{ + return lhs.as_bool() && rhs.as_bool(); +} + +template <class JsonT> +bool pipepipe(const JsonT& lhs, const JsonT& rhs) +{ + return lhs.as_bool() || rhs.as_bool(); +} + +template <class JsonT> +bool lt(const JsonT& lhs, const JsonT& rhs) +{ + bool result = false; + if (lhs. template is<unsigned long long>() && rhs. template is<unsigned long long>()) + { + result = lhs. template as<unsigned long long>() < rhs. template as<unsigned long long>(); + } + else if (lhs. template is<long long>() && rhs. template is<long long>()) + { + result = lhs. template as<long long>() < rhs. template as<long long>(); + } + else if ((lhs.is_number() && rhs.is_double()) || (lhs.is_double() && rhs.is_number())) + { + result = lhs.as_double() < rhs.as_double(); + } + else if (lhs.is_string() && rhs.is_string()) + { + result = lhs.as_string() < rhs.as_string(); + } + return result; +} + +template <class JsonT> +bool gt(const JsonT& lhs, const JsonT& rhs) +{ + return lt(rhs,lhs); +} + +template <class JsonT> +JsonT plus(const JsonT& lhs, const JsonT& rhs) +{ + JsonT result = jsoncons::null_type(); + if (lhs.is_integer() && rhs.is_integer()) + { + result = ((lhs.as_integer() + rhs.as_integer())); + } + else if ((lhs.is_number() && rhs.is_double()) || (lhs.is_double() && rhs.is_number())) + { + result = (lhs.as_double() + rhs.as_double()); + } + else if (lhs.is_uinteger() && rhs.is_uinteger()) + { + result = (lhs.as_uinteger() + rhs.as_uinteger()); + } + return result; +} + +template <class JsonT> +JsonT unary_minus(const JsonT& lhs) +{ + JsonT result = jsoncons::null_type(); + if (lhs.is_integer()) + { + result = -lhs.as_integer(); + } + else if (lhs.is_double()) + { + result = -lhs.as_double(); + } + return result; +} + +template <class JsonT> +JsonT minus(const JsonT& lhs, const JsonT& rhs) +{ + JsonT result = jsoncons::null_type(); + if (lhs.is_integer() && rhs.is_integer()) + { + result = ((lhs.as_integer() - rhs.as_integer())); + } + else if ((lhs.is_number() && rhs.is_double()) || (lhs.is_double() && rhs.is_number())) + { + result = (lhs.as_double() - rhs.as_double()); + } + else if (lhs.is_uinteger() && rhs.is_uinteger() && lt(rhs,lhs)) + { + result = (lhs.as_uinteger() - rhs.as_uinteger()); + } + return result; +} + +template <class JsonT> +class value_term : public term<JsonT> +{ + JsonT value_; +public: + template <class T> + value_term(const T& value) + : value_(value) + { + } + + bool accept_single_node() const override + { + return value_.as_bool(); + } + + JsonT evaluate_single_node() const override + { + return value_; + } + + bool exclaim() const override + { + return !value_.as_bool(); + } + + bool eq(const term<JsonT>& rhs) const override + { + return rhs.eq(value_); + } + + bool eq(const JsonT& rhs) const override + { + return value_ == rhs; + } + + bool ne(const term<JsonT>& rhs) const override + { + return rhs.ne(value_); + } + bool ne(const JsonT& rhs) const override + { + return value_ != rhs; + } + bool regex(const term<JsonT>& rhs) const override + { + return rhs.regex2(value_.as_string()); + } + bool ampamp(const term<JsonT>& rhs) const override + { + return rhs.ampamp(value_); + } + bool ampamp(const JsonT& rhs) const override + { + return jsoncons::jsonpath::ampamp(value_,rhs); + } + bool pipepipe(const term<JsonT>& rhs) const override + { + return rhs.pipepipe(value_); + } + bool pipepipe(const JsonT& rhs) const override + { + return jsoncons::jsonpath::pipepipe(value_,rhs); + } + + bool lt(const term<JsonT>& rhs) const override + { + return rhs.gt(value_); + } + + bool lt(const JsonT& rhs) const override + { + return jsoncons::jsonpath::lt(value_,rhs); + } + + bool gt(const term<JsonT>& rhs) const override + { + return rhs.lt(value_); + } + + bool gt(const JsonT& rhs) const override + { + return jsoncons::jsonpath::gt(value_,rhs); + } + + JsonT minus(const term<JsonT>& rhs) const override + { + return jsoncons::jsonpath::plus(rhs.unary_minus(),value_); + } + + JsonT minus(const JsonT& rhs) const override + { + return jsoncons::jsonpath::minus(value_,rhs); + } + + JsonT unary_minus() const override + { + return jsoncons::jsonpath::unary_minus(value_); + } + + JsonT plus(const term<JsonT>& rhs) const override + { + return rhs.plus(value_); + } + + JsonT plus(const JsonT& rhs) const override + { + return jsoncons::jsonpath::plus(value_,rhs); + } +}; + +template <class JsonT> +class regex_term : public term<JsonT> +{ + typedef typename JsonT::char_type char_type; + typedef typename JsonT::string_type string_type; + string_type pattern_; + std::regex::flag_type flags_; +public: + regex_term(const string_type& pattern, std::regex::flag_type flags) + : pattern_(pattern), flags_(flags) + { + } + + bool regex2(const string_type& subject) const override + { + std::basic_regex<char_type> pattern(pattern_, + flags_); + return std::regex_match(subject, pattern); + } +}; + +template <class JsonT> +class path_term : public term<JsonT> +{ + typedef typename JsonT::string_type string_type; + + string_type path_; + JsonT nodes_; +public: + path_term(const string_type& path) + : path_(path) + { + } + + void initialize(const JsonT& context_node) override + { + jsonpath_evaluator<JsonT> evaluator; + evaluator.evaluate(context_node,path_); + nodes_ = evaluator.get_values(); + } + + bool accept_single_node() const override + { + return nodes_.size() != 0; + } + + JsonT evaluate_single_node() const override + { + return nodes_.size() == 1 ? nodes_[0] : nodes_; + } + + bool exclaim() const override + { + return nodes_.size() == 0; + } + + bool eq(const term<JsonT>& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.eq(nodes_[i]); + } + } + return result; + } + + bool eq(const JsonT& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = nodes_[i] == rhs; + } + } + return result; + } + + bool ne(const term<JsonT>& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.ne(nodes_[i]); + } + } + return result; + + } + bool ne(const JsonT& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = nodes_[i] != rhs; + } + } + return result; + } + bool regex(const term<JsonT>& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.regex2(nodes_[i].as_string()); + } + } + return result; + } + bool ampamp(const term<JsonT>& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.ampamp(nodes_[i]); + } + } + return result; + } + bool ampamp(const JsonT& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = jsoncons::jsonpath::ampamp(nodes_[i],rhs); + } + } + return result; + } + bool pipepipe(const term<JsonT>& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.pipepipe(nodes_[i]); + } + } + return result; + } + bool pipepipe(const JsonT& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = jsoncons::jsonpath::pipepipe(nodes_[i],rhs); + } + } + return result; + } + + bool lt(const JsonT& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = jsoncons::jsonpath::lt(nodes_[i],rhs); + } + } + return result; + } + + bool lt(const term<JsonT>& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.gt(nodes_[i]); + } + } + return result; + } + + bool gt(const JsonT& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = jsoncons::jsonpath::gt(nodes_[i],rhs); + } + } + return result; + } + + bool gt(const term<JsonT>& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.lt(nodes_[i]); + } + } + return result; + } + + JsonT minus(const JsonT& rhs) const override + { + return nodes_.size() == 1 ? jsoncons::jsonpath::minus(nodes_[0],rhs) : jsoncons::null_type(); + } + + JsonT minus(const term<JsonT>& rhs) const override + { + + return nodes_.size() == 1 ? jsoncons::jsonpath::plus(rhs.unary_minus(),nodes_[0]) : jsoncons::null_type(); + } + + JsonT unary_minus() const override + { + return nodes_.size() == 1 ? jsoncons::jsonpath::unary_minus(nodes_[0]) : jsoncons::null_type(); + } + + JsonT plus(const JsonT& rhs) const override + { + static auto a_null = jsoncons::null_type(); + return nodes_.size() == 1 ? jsoncons::jsonpath::plus(nodes_[0],rhs) : a_null; + } + + JsonT plus(const term<JsonT>& rhs) const override + { + static auto a_null = jsoncons::null_type(); + return nodes_.size() == 1 ? rhs.plus(nodes_[0]) : a_null; + } +}; + +template <class JsonT> +class jsonpath_filter_parser +{ + typedef typename JsonT::string_type string_type; + typedef typename JsonT::char_type char_type; + + size_t& line_; + size_t& column_; + filter_states state_; + string_type buffer_; + std::vector<token<JsonT>> tokens_; + int depth_; + const char_type* begin_input_; + const char_type* end_input_; + const char_type*& p_; + filter_states pre_line_break_state_; +public: + jsonpath_filter_parser(const char_type** expr, size_t* line,size_t* column) + : line_(*line), column_(*column),p_(*expr) + { + } + + bool exists(const JsonT& context_node) + { + for (auto it=tokens_.begin(); it != tokens_.end(); ++it) + { + it->initialize(context_node); + } + bool result = false; + + token_stream<JsonT> ts(tokens_); + auto e = expression(ts); + result = e->accept_single_node(); + + return result; + } + + JsonT eval(const JsonT& context_node) + { + try + { + for (auto it=tokens_.begin(); it != tokens_.end(); ++it) + { + it->initialize(context_node); + } + + token_stream<JsonT> ts(tokens_); + auto e = expression(ts); + JsonT result = e->evaluate_single_node(); + + return result; + } + catch (const parse_exception& e) + { + throw parse_exception(e.code(),line_,column_); + } + } + + std::shared_ptr<term<JsonT>> primary(token_stream<JsonT>& ts) + { + auto t = ts.get(); + + switch (t.type()) + { + case token_types::left_paren: + { + auto expr = expression(ts); + t = ts.get(); + if (t.type() != token_types::right_paren) + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_expected_right_brace, jsonpath_error_category()),line_,column_); + } + return expr; + } + case token_types::term: + return t.term_ptr(); + case token_types::exclaim: + { + JsonT val = primary(ts)->exclaim(); + auto expr = std::make_shared<value_term<JsonT>>(val); + return expr; + } + case token_types::minus: + { + JsonT val = primary(ts)->unary_minus(); + auto expr = std::make_shared<value_term<JsonT>>(val); + return expr; + } + default: + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_expected_primary, jsonpath_error_category()),line_,column_); + } + } + + std::shared_ptr<term<JsonT>> expression(token_stream<JsonT>& ts) + { + auto left = make_term(ts); + auto t = ts.get(); + while (true) + { + switch (t.type()) + { + case token_types::plus: + { + JsonT val = left->plus(*(make_term(ts))); + left = std::make_shared<value_term<JsonT>>(val); + t = ts.get(); + } + break; + case token_types::minus: + { + JsonT val = left->minus(*(make_term(ts))); + left = std::make_shared<value_term<JsonT>>(val); + t = ts.get(); + } + break; + default: + ts.putback(); + return left; + } + } + return left; + } + + std::shared_ptr<term<JsonT>> make_term(token_stream<JsonT>& ts) + { + auto left = primary(ts); + auto t = ts.get(); + while (true) + { + switch (t.type()) + { + case token_types::eq: + { + bool e = left->eq(*(primary(ts))); + JsonT val(e); + left = std::make_shared<value_term<JsonT>>(val); + t = ts.get(); + } + break; + case token_types::ne: + { + bool e = left->ne(*(primary(ts))); + JsonT val(e); + left = std::make_shared<value_term<JsonT>>(val); + t = ts.get(); + } + break; + case token_types::regex: + { + bool e = left->regex(*(primary(ts))); + JsonT val(e); + left = std::make_shared<value_term<JsonT>>(val); + t = ts.get(); + } + break; + case token_types::ampamp: + { + bool e = left->ampamp(*(primary(ts))); + JsonT val(e); + left = std::make_shared<value_term<JsonT>>(val); + t = ts.get(); + } + break; + case token_types::pipepipe: + { + bool e = left->pipepipe(*(primary(ts))); + JsonT val(e); + left = std::make_shared<value_term<JsonT>>(val); + t = ts.get(); + } + break; + case token_types::lt: + { + bool e = left->lt(*(primary(ts))); + JsonT val(e); + left = std::make_shared<value_term<JsonT>>(val); + t = ts.get(); + } + break; + case token_types::gt: + { + bool e = left->gt(*(primary(ts))); + JsonT val(e); + left = std::make_shared<value_term<JsonT>>(val); + t = ts.get(); + } + break; + case token_types::lte: + { + bool e = left->lt(*(primary(ts))) || left->eq(*(primary(ts))); + JsonT val(e); + left = std::make_shared<value_term<JsonT>>(val); + t = ts.get(); + } + break; + case token_types::gte: + { + bool e = left->gt(*(primary(ts))) || left->eq(*(primary(ts))); + JsonT val(e); + left = std::make_shared<value_term<JsonT>>(val); + t = ts.get(); + } + break; + default: + ts.putback(); + return left; + } + } + } + + void parse(const char_type* expr, size_t length) + { + parse(expr,expr+length); + } + + void parse(const char_type* expr, const char_type* end_expr) + { + p_ = expr; + end_input_ = end_expr; + depth_ = 0; + tokens_.clear(); + state_ = filter_states::start; + bool done = false; + while (!done && p_ < end_input_) + { + switch (state_) + { + case filter_states::cr: + ++line_; + column_ = 1; + switch (*p_) + { + case '\n': + state_ = pre_line_break_state_; + ++p_; + ++column_; + break; + default: + state_ = pre_line_break_state_; + break; + } + break; + case filter_states::lf: + ++line_; + column_ = 1; + state_ = pre_line_break_state_; + break; + case filter_states::start: + switch (*p_) + { + case '\r': + case '\n': + pre_line_break_state_ = state_; + state_ = filter_states::lf; + break; + case '(': + state_ = filter_states::expect_path_or_value; + ++depth_; + tokens_.push_back(token<JsonT>(token_types::left_paren)); + break; + case ')': + tokens_.push_back(token<JsonT>(token_types::right_paren)); + if (--depth_ == 0) + { + done = true; + } + break; + } + ++p_; + ++column_; + break; + case filter_states::oper: + switch (*p_) + { + case '\r': + case '\n': + ++line_; + column_ = 1; + state_ = pre_line_break_state_; + break; + case '!': + if (p_+1 < end_input_ && *(p_+1) == '=') + { + ++p_; + ++column_; + state_ = filter_states::expect_path_or_value; + tokens_.push_back(token<JsonT>(token_types::ne)); + } + else + { + state_ = filter_states::expect_path_or_value; + tokens_.push_back(token<JsonT>(token_types::exclaim)); + } + break; + case '&': + if (p_+1 < end_input_ && *(p_+1) == '&') + { + ++p_; + ++column_; + state_ = filter_states::expect_path_or_value; + tokens_.push_back(token<JsonT>(token_types::ampamp)); + } + break; + case '|': + if (p_+1 < end_input_ && *(p_+1) == '|') + { + ++p_; + ++column_; + state_ = filter_states::expect_path_or_value; + tokens_.push_back(token<JsonT>(token_types::pipepipe)); + } + break; + case '=': + if (p_+1 < end_input_ && *(p_+1) == '=') + { + ++p_; + ++column_; + state_ = filter_states::expect_path_or_value; + tokens_.push_back(token<JsonT>(token_types::eq)); + } + else if (p_+1 < end_input_ && *(p_+1) == '~') + { + ++p_; + ++column_; + state_ = filter_states::expect_regex; + tokens_.push_back(token<JsonT>(token_types::regex)); + } + break; + case '>': + if (p_+1 < end_input_ && *(p_+1) == '=') + { + ++p_; + ++column_; + state_ = filter_states::expect_path_or_value; + tokens_.push_back(token<JsonT>(token_types::gte)); + } + else + { + state_ = filter_states::expect_path_or_value; + tokens_.push_back(token<JsonT>(token_types::gt)); + } + break; + case '<': + if (p_+1 < end_input_ && *(p_+1) == '=') + { + ++p_; + ++column_; + state_ = filter_states::expect_path_or_value; + tokens_.push_back(token<JsonT>(token_types::lte)); + } + else + { + state_ = filter_states::expect_path_or_value; + tokens_.push_back(token<JsonT>(token_types::lt)); + } + break; + case '+': + state_ = filter_states::expect_path_or_value; + tokens_.push_back(token<JsonT>(token_types::plus)); + break; + case '-': + state_ = filter_states::expect_path_or_value; + tokens_.push_back(token<JsonT>(token_types::minus)); + break; + case ' ':case '\t': + break; + default: + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter, jsonpath_error_category()),line_,column_); + break; + + } + ++p_; + ++column_; + break; + case filter_states::unquoted_text: + { + switch (*p_) + { + case '\r': + case '\n': + ++line_; + column_ = 1; + state_ = pre_line_break_state_; + break; + case '<': + case '>': + case '!': + case '=': + case '&': + case '|': + case '+': + case '-': + { + if (buffer_.length() > 0) + { + try + { + auto val = JsonT::parse(buffer_); + tokens_.push_back(token<JsonT>(token_types::term,std::make_shared<value_term<JsonT>>(val))); + } + catch (const parse_exception& e) + { + throw parse_exception(e.code(),line_,column_); + } + buffer_.clear(); + } + state_ = filter_states::oper; + } + break; + case ')': + if (buffer_.length() > 0) + { + try + { + auto val = JsonT::parse(buffer_); + tokens_.push_back(token<JsonT>(token_types::term,std::make_shared<value_term<JsonT>>(val))); + } + catch (const parse_exception& e) + { + throw parse_exception(e.code(),line_,column_); + } + buffer_.clear(); + } + tokens_.push_back(token<JsonT>(token_types::right_paren)); + if (--depth_ == 0) + { + state_ = filter_states::start; + done = true; + } + else + { + state_ = filter_states::expect_path_or_value; + } + ++p_; + ++column_; + break; + case ' ':case '\t': + if (buffer_.length() > 0) + { + try + { + auto val = JsonT::parse(buffer_); + tokens_.push_back(token<JsonT>(token_types::term,std::make_shared<value_term<JsonT>>(val))); + } + catch (const parse_exception& e) + { + throw parse_exception(e.code(),line_,column_); + } + buffer_.clear(); + } + ++p_; + ++column_; + break; + default: + buffer_.push_back(*p_); + ++p_; + ++column_; + break; + } + } + break; + case filter_states::single_quoted_text: + { + switch (*p_) + { + case '\r': + case '\n': + ++line_; + column_ = 1; + state_ = pre_line_break_state_; + break; + case '\\': + buffer_.push_back(*p_); + if (p_+1 < end_input_) + { + ++p_; + ++column_; + buffer_.push_back(*p_); + } + break; + case '\'': + buffer_.push_back('\"'); + //if (buffer_.length() > 0) + { + try + { + auto val = JsonT::parse(buffer_); + tokens_.push_back(token<JsonT>(token_types::term,std::make_shared<value_term<JsonT>>(val))); + } + catch (const parse_exception& e) + { + throw parse_exception(e.code(),line_,column_); + } + buffer_.clear(); + } + state_ = filter_states::expect_path_or_value; + break; + + default: + buffer_.push_back(*p_); + break; + } + } + ++p_; + ++column_; + break; + case filter_states::double_quoted_text: + { + switch (*p_) + { + case '\r': + case '\n': + ++line_; + column_ = 1; + state_ = pre_line_break_state_; + break; + case '\\': + buffer_.push_back(*p_); + if (p_+1 < end_input_) + { + ++p_; + ++column_; + buffer_.push_back(*p_); + } + break; + case '\"': + buffer_.push_back(*p_); + //if (buffer_.length() > 0) + { + try + { + auto val = JsonT::parse(buffer_); + tokens_.push_back(token<JsonT>(token_types::term,std::make_shared<value_term<JsonT>>(val))); + } + catch (const parse_exception& e) + { + throw parse_exception(e.code(),line_,column_); + } + buffer_.clear(); + } + state_ = filter_states::expect_path_or_value; + break; + + default: + buffer_.push_back(*p_); + break; + } + } + ++p_; + ++column_; + break; + case filter_states::expect_path_or_value: + switch (*p_) + { + case '\r': + case '\n': + ++line_; + column_ = 1; + state_ = pre_line_break_state_; + break; + case '<': + case '>': + case '!': + case '=': + case '&': + case '|': + case '+': + case '-': + state_ = filter_states::oper; + // don't increment + break; + case '@': + buffer_.push_back(*p_); + state_ = filter_states::path; + ++p_; + ++column_; + break; + case ' ':case '\t': + ++p_; + ++column_; + break; + case '\'': + buffer_.push_back('\"'); + state_ = filter_states::single_quoted_text; + ++p_; + ++column_; + break; + case '\"': + buffer_.push_back(*p_); + state_ = filter_states::double_quoted_text; + ++p_; + ++column_; + break; + case '(': + ++depth_; + tokens_.push_back(token<JsonT>(token_types::left_paren)); + ++p_; + ++column_; + break; + case ')': + tokens_.push_back(token<JsonT>(token_types::right_paren)); + if (--depth_ == 0) + { + done = true; + state_ = filter_states::start; + } + ++p_; + ++column_; + break; + default: + // don't increment + state_ = filter_states::unquoted_text; + break; + }; + break; + case filter_states::expect_oper_or_right_round_bracket: + switch (*p_) + { + case '\r': + case '\n': + ++line_; + column_ = 1; + state_ = pre_line_break_state_; + break; + case ' ':case '\t': + break; + case ')': + tokens_.push_back(token<JsonT>(token_types::right_paren)); + if (--depth_ == 0) + { + done = true; + state_ = filter_states::start; + } + break; + case '<': + case '>': + case '!': + case '=': + case '&': + case '|': + case '+': + case '-': + { + state_ = filter_states::oper; + // don't increment p + } + break; + default: + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter, jsonpath_error_category()),line_,column_); + break; + }; + break; + case filter_states::expect_right_round_bracket: + switch (*p_) + { + case '\r': + case '\n': + ++line_; + column_ = 1; + state_ = pre_line_break_state_; + break; + case ' ':case '\t': + break; + case ')': + tokens_.push_back(token<JsonT>(token_types::right_paren)); + if (--depth_ == 0) + { + done = true; + state_ = filter_states::start; + } + else + { + state_ = filter_states::expect_oper_or_right_round_bracket; + } + break; + default: + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter, jsonpath_error_category()),line_,column_); + break; + }; + ++p_; + ++column_; + break; + case filter_states::path: + switch (*p_) + { + case '\r': + case '\n': + ++line_; + column_ = 1; + state_ = pre_line_break_state_; + break; + case '<': + case '>': + case '!': + case '=': + case '&': + case '|': + case '+': + case '-': + { + if (buffer_.length() > 0) + { + tokens_.push_back(token<JsonT>(token_types::term,std::make_shared<path_term<JsonT>>(buffer_))); + buffer_.clear(); + } + state_ = filter_states::oper; + // don't increment + } + break; + case ')': + if (buffer_.length() > 0) + { + tokens_.push_back(token<JsonT>(token_types::term,std::make_shared<path_term<JsonT>>(buffer_))); + tokens_.push_back(token<JsonT>(token_types::right_paren)); + buffer_.clear(); + } + if (--depth_ == 0) + { + state_ = filter_states::start; + done = true; + } + else + { + state_ = filter_states::expect_path_or_value; + } + ++p_; + ++column_; + break; + default: + buffer_.push_back(*p_); + ++p_; + ++column_; + break; + }; + break; + case filter_states::expect_regex: + switch (*p_) + { + case '\r': + case '\n': + ++line_; + column_ = 1; + state_ = pre_line_break_state_; + break; + case '/': + state_ = filter_states::regex; + break; + case ' ':case '\t': + break; + default: + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_expected_slash, jsonpath_error_category()),line_,column_); + break; + }; + ++p_; + ++column_; + break; + case filter_states::regex: + { + switch (*p_) + { + case '\r': + case '\n': + ++line_; + column_ = 1; + state_ = pre_line_break_state_; + break; + case '/': + //if (buffer_.length() > 0) + { + std::regex::flag_type flags = std::regex_constants::ECMAScript; + if (p_+1 < end_input_ && *(p_+1) == 'i') + { + ++p_; + ++column_; + flags |= std::regex_constants::icase; + } + tokens_.push_back(token<JsonT>(token_types::term,std::make_shared<regex_term<JsonT>>(buffer_,flags))); + buffer_.clear(); + } + state_ = filter_states::expect_path_or_value; + break; + + default: + buffer_.push_back(*p_); + break; + } + } + ++p_; + ++column_; + break; + default: + ++p_; + ++column_; + break; + } + } + if (depth_ != 0) + { + throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unbalanced_paren, jsonpath_error_category()),line_,column_); + } + } +}; + + +}} +#endif
\ No newline at end of file |