From 6cd7fca47186ccbb4abd0c0ecd66c181affd6e7c Mon Sep 17 00:00:00 2001 From: Vladislav Pavlov Date: Thu, 25 May 2023 04:02:14 +0300 Subject: [PATCH] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20?= =?UTF-8?q?=D0=B8=D1=81=D0=BA=D0=BB=D1=8E=D1=87=D0=B5=D0=BD=D0=B8=D1=8F,?= =?UTF-8?q?=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D1=8F=20in=20=D0=BC?= =?UTF-8?q?=D0=BE=D0=B6=D0=B5=D1=82=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20=D0=B1=D0=B5=D0=B7=20=D1=81=D0=BA=D0=BE=D0=B1?= =?UTF-8?q?=D0=BE=D0=BA,=20=D0=BF=D0=BE=D0=BF=D1=80=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B2=D0=BD=D0=B5=D1=88=D0=BD=D0=B8=D0=B9=20=D0=B2?= =?UTF-8?q?=D0=B8=D0=B4=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B9,=20?= =?UTF-8?q?=D1=80=D0=B0=D0=B7=D0=BB=D0=BE=D0=B6=D0=B8=D0=BB=20cpp=20=D0=B8?= =?UTF-8?q?=20hpp=20=D0=BF=D0=BE=20=D1=80=D0=B0=D0=B7=D0=BD=D1=8B=D0=BC=20?= =?UTF-8?q?=D0=BF=D0=B0=D0=BF=D0=BA=D0=B0=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/lib/query_language/CMakeLists.txt | 30 +- .../{classes.h => include/classes.hpp} | 24 +- .../lib/query_language/include/exception.hpp | 13 + .../query_language/include/include_libs.hpp | 8 + .../interpreter.hpp} | 11 +- .../{parcer.h => include/parcer.hpp} | 14 +- .../query_language/{ => include}/querying.hpp | 0 .../{scaner.h => include/scaner.hpp} | 19 +- .../lib/query_language/{ => src}/classes.cpp | 16 +- server/lib/query_language/src/exception.cpp | 8 + .../query_language/{ => src}/interpreter.cpp | 282 ++++++++++-------- server/lib/query_language/{ => src}/main.cpp | 36 +-- .../lib/query_language/{ => src}/parcer.cpp | 122 ++++---- .../lib/query_language/{ => src}/querying.cpp | 6 +- .../lib/query_language/{ => src}/scaner.cpp | 33 +- 15 files changed, 355 insertions(+), 267 deletions(-) rename server/lib/query_language/{classes.h => include/classes.hpp} (87%) create mode 100644 server/lib/query_language/include/exception.hpp create mode 100644 server/lib/query_language/include/include_libs.hpp rename server/lib/query_language/{interpreter.h => include/interpreter.hpp} (75%) rename server/lib/query_language/{parcer.h => include/parcer.hpp} (72%) rename server/lib/query_language/{ => include}/querying.hpp (100%) rename server/lib/query_language/{scaner.h => include/scaner.hpp} (92%) rename server/lib/query_language/{ => src}/classes.cpp (75%) create mode 100644 server/lib/query_language/src/exception.cpp rename server/lib/query_language/{ => src}/interpreter.cpp (63%) rename server/lib/query_language/{ => src}/main.cpp (67%) rename server/lib/query_language/{ => src}/parcer.cpp (55%) rename server/lib/query_language/{ => src}/querying.cpp (95%) rename server/lib/query_language/{ => src}/scaner.cpp (88%) diff --git a/server/lib/query_language/CMakeLists.txt b/server/lib/query_language/CMakeLists.txt index 306ceb3..864c578 100644 --- a/server/lib/query_language/CMakeLists.txt +++ b/server/lib/query_language/CMakeLists.txt @@ -1,16 +1,26 @@ +set(LANG_HEADERS + include/scaner.hpp + include/parcer.hpp + include/interpreter.hpp + include/classes.hpp + include/include_libs.hpp + include/exception.hpp +) + set(LANG_SOURCE - scaner.cpp - parcer.cpp - interpreter.cpp - classes.cpp + src/scaner.cpp + src/parcer.cpp + src/interpreter.cpp + src/classes.cpp + src/exception.cpp ) -add_library(query_lang ${LANG_SOURCE}) -target_include_directories(query_lang PUBLIC ./) +add_library(query_lang ${LANG_SOURCE} ${LANG_HEADERS}) +target_include_directories(query_lang PUBLIC ./include) -add_executable(query_lang_main main.cpp) +add_executable(query_lang_main src/main.cpp) target_link_libraries(query_lang_main query_lang) -add_library(querying querying.cpp) -target_include_directories(querying PUBLIC ./) -target_link_libraries(querying query_lang) +add_library(querying src/querying.cpp) +target_include_directories(querying PUBLIC ./include) +target_link_libraries(querying query_lang) \ No newline at end of file diff --git a/server/lib/query_language/classes.h b/server/lib/query_language/include/classes.hpp similarity index 87% rename from server/lib/query_language/classes.h rename to server/lib/query_language/include/classes.hpp index 4873761..f4759bb 100644 --- a/server/lib/query_language/classes.h +++ b/server/lib/query_language/include/classes.hpp @@ -1,5 +1,6 @@ #pragma once -#include "scaner.h" + +#include "scaner.hpp" class binary; class grouping; @@ -53,7 +54,7 @@ class expr { virtual void accept(expr_visitor *visitor) = 0; }; -// +// класс для переменной, считанной из запроса class literal : public expr { public: std::vector json_namevec; @@ -74,7 +75,7 @@ class binary : public expr { token op; std::unique_ptr right; - binary(std::unique_ptr l, token tok, std::unique_ptr r); + binary(std::unique_ptr left_, token tok, std::unique_ptr right_); virtual ~binary(){}; void accept(expr_visitor *visitor); }; @@ -84,22 +85,24 @@ class func_in : public expr { std::unique_ptr left; std::unique_ptr right; - func_in(std::unique_ptr l, std::unique_ptr r); + func_in(std::unique_ptr left_, std::unique_ptr right_); virtual ~func_in(){}; void accept(expr_visitor *visitor); }; + // элементарный класс унарных операций class unary : public expr { public: - std::unique_ptr ex; - token op; + std::unique_ptr expression; + token oper; - unary(std::unique_ptr e, token t); + unary(std::unique_ptr expression_, token tok); virtual ~unary(){}; void accept(expr_visitor *visitor); }; + class logical_expr : public expr { public: std::unique_ptr left; @@ -113,12 +116,17 @@ class logical_expr : public expr { void accept(expr_visitor *visitor); }; + // класс для выражений в скобках class grouping : public expr { public: std::unique_ptr expression; - grouping(std::unique_ptr e); + grouping(std::unique_ptr expression_); virtual ~grouping(){}; void accept(expr_visitor *visitor); }; + + + + diff --git a/server/lib/query_language/include/exception.hpp b/server/lib/query_language/include/exception.hpp new file mode 100644 index 0000000..7cfa65b --- /dev/null +++ b/server/lib/query_language/include/exception.hpp @@ -0,0 +1,13 @@ +#pragma once +#include "include_libs.hpp" + +// Базовый класс исключений для компонентов (сканер, парсер, интерпретатор) +class ComponentException : public std::exception { +public: + explicit ComponentException(const char* message); + + const char* what() const throw(); + +private: + std::string message_; +}; \ No newline at end of file diff --git a/server/lib/query_language/include/include_libs.hpp b/server/lib/query_language/include/include_libs.hpp new file mode 100644 index 0000000..8bef006 --- /dev/null +++ b/server/lib/query_language/include/include_libs.hpp @@ -0,0 +1,8 @@ +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/server/lib/query_language/interpreter.h b/server/lib/query_language/include/interpreter.hpp similarity index 75% rename from server/lib/query_language/interpreter.h rename to server/lib/query_language/include/interpreter.hpp index d3b191d..ab55f6a 100644 --- a/server/lib/query_language/interpreter.h +++ b/server/lib/query_language/include/interpreter.hpp @@ -1,5 +1,5 @@ #pragma once -#include "parcer.h" +#include "parcer.hpp" class interpreter : expr_visitor { public: @@ -19,7 +19,8 @@ class interpreter : expr_visitor { void visit(func_in *expr) override; void visit(logical_expr *ex) override; auto find_word_inJson(std::string word, nlohmann::json jsonValue) -> bool; - void check_number_operand(token oper, value operand); + void check_json_operand(value operand); + void check_number_operand(value operand); void check_number_operands(token oper, value left, value right); auto find_json_value(const nlohmann::json &card, std::vector) -> nlohmann::json; @@ -29,6 +30,10 @@ class interpreter : expr_visitor { auto upperJsonString(const nlohmann::json &data) -> nlohmann::json; auto lowerJsonString(const nlohmann::json &data) -> nlohmann::json; auto reduceJson(const nlohmann::json &jsonElem) -> nlohmann::json; - auto mergeJson(const nlohmann::json &json1, const nlohmann::json &json2) + auto getSelfKeys(const nlohmann::json& json_value) -> nlohmann::json; + auto handleAnyKey(const nlohmann::json& json_value, + const std::vector& levels_vec, + size_t current_index) -> nlohmann::json; + auto mergeJson(const nlohmann::json &jsonLeft, const nlohmann::json &jsonRight) -> nlohmann::json; }; diff --git a/server/lib/query_language/parcer.h b/server/lib/query_language/include/parcer.hpp similarity index 72% rename from server/lib/query_language/parcer.h rename to server/lib/query_language/include/parcer.hpp index 39b8cf6..9fd4451 100644 --- a/server/lib/query_language/parcer.h +++ b/server/lib/query_language/include/parcer.hpp @@ -1,5 +1,5 @@ #pragma once -#include "classes.h" +#include "classes.hpp" class parser { public: @@ -11,23 +11,19 @@ class parser { std::vector read_json_elem(); int current = 0; bool is_at_end(); + bool check(token_type type); + bool match(std::vector types); token peek(); token previous(); token advance(); - bool check(token_type type); - bool match(std::vector types); - token consume(token_type type, std::string message); std::unique_ptr primary(); - std::unique_ptr finish_call(expr *callee); std::unique_ptr func_in_class(); std::unique_ptr unar(); std::unique_ptr multiplication(); std::unique_ptr addition(); std::unique_ptr comparison(); std::unique_ptr equality(); - std::unique_ptr _and(); - std::unique_ptr _or(); - std::unique_ptr assignment(); + std::unique_ptr and_expr(); + std::unique_ptr or_expr(); std::unique_ptr expression(); - std::unique_ptr function(std::string kind); }; diff --git a/server/lib/query_language/querying.hpp b/server/lib/query_language/include/querying.hpp similarity index 100% rename from server/lib/query_language/querying.hpp rename to server/lib/query_language/include/querying.hpp diff --git a/server/lib/query_language/scaner.h b/server/lib/query_language/include/scaner.hpp similarity index 92% rename from server/lib/query_language/scaner.h rename to server/lib/query_language/include/scaner.hpp index 4a16d73..d954787 100644 --- a/server/lib/query_language/scaner.h +++ b/server/lib/query_language/include/scaner.hpp @@ -1,12 +1,7 @@ #pragma once -#include -#include -#include -#include -#include -#include +#include "include_libs.hpp" +#include "exception.hpp" -#include enum token_type { LEFT_PAREN, @@ -76,6 +71,12 @@ struct token { }; class scanner { +public: + + scanner(const std::string &s); + std::vector scan_tokens(); + +private: std::string source; std::vector tokens; std::map keywords; @@ -96,8 +97,4 @@ class scanner { void read_json_keyword(); void string(); void scan_token(); - - public: - scanner(const std::string &s); - std::vector scan_tokens(); }; diff --git a/server/lib/query_language/classes.cpp b/server/lib/query_language/src/classes.cpp similarity index 75% rename from server/lib/query_language/classes.cpp rename to server/lib/query_language/src/classes.cpp index 57a6d58..65ed342 100644 --- a/server/lib/query_language/classes.cpp +++ b/server/lib/query_language/src/classes.cpp @@ -1,4 +1,5 @@ -#include "classes.h" +#include "classes.hpp" + literal::literal(std::string v) : val(v){}; literal::literal(double d) : val(d){}; @@ -11,29 +12,30 @@ void literal::accept(expr_visitor *visitor) { visitor->visit(this); } -binary::binary(std::unique_ptr l, token tok, std::unique_ptr r) - : left(std::move(l)), op(tok), right(std::move(r)){}; +binary::binary(std::unique_ptr left_, token tok, std::unique_ptr right_) + : left(std::move(left_)), op(tok), right(std::move(right_)){}; void binary::accept(expr_visitor *visitor) { visitor->visit(this); } unary::unary(std::unique_ptr expr_, token t) - : ex(std::move(expr_)), op(t){}; + : expression(std::move(expr_)), oper(t){}; void unary::accept(expr_visitor *visitor) { visitor->visit(this); } logical_expr::logical_expr(std::unique_ptr left_, - token t, + token tok, std::unique_ptr right_) - : left(std::move(left_)), oper(t), right(std::move(right_)){}; + : left(std::move(left_)), oper(tok), right(std::move(right_)){}; void logical_expr::accept(expr_visitor *visitor) { visitor->visit(this); } + func_in::func_in(std::unique_ptr left_, std::unique_ptr right_) : left(std::move(left_)), right(std::move(right_)){}; @@ -41,6 +43,8 @@ void func_in::accept(expr_visitor *visitor) { visitor->visit(this); } + + grouping::grouping(std::unique_ptr expr_) : expression(std::move(expr_)){}; diff --git a/server/lib/query_language/src/exception.cpp b/server/lib/query_language/src/exception.cpp new file mode 100644 index 0000000..ae03e18 --- /dev/null +++ b/server/lib/query_language/src/exception.cpp @@ -0,0 +1,8 @@ +#include "exception.hpp" + + +ComponentException::ComponentException(const char* message) : message_(message) {} + +const char* ComponentException::what() const throw() { + return message_.c_str(); +} \ No newline at end of file diff --git a/server/lib/query_language/interpreter.cpp b/server/lib/query_language/src/interpreter.cpp similarity index 63% rename from server/lib/query_language/interpreter.cpp rename to server/lib/query_language/src/interpreter.cpp index cf6cd73..d0b54b6 100644 --- a/server/lib/query_language/interpreter.cpp +++ b/server/lib/query_language/src/interpreter.cpp @@ -1,4 +1,4 @@ -#include "interpreter.h" +#include "interpreter.hpp" interpreter::interpreter(){}; @@ -35,73 +35,81 @@ bool interpreter::is_equal(value left, value right) { return false; } -/*void interpreter::check_number_operand(token oper, value operand){ - if (operand.val_type == DOUBLE) - return; - // обработать ошибку -}*/ - -/*void interpreter::check_number_operands(token oper, value left, value right){ - if (left.val_type == DOUBLE && right.val_type == DOUBLE){ - if (right.doub_val == 0 && oper.type == SLASH) - // обработать ошибку - return; - } - // обработать ошибку -}*/ + +void interpreter::check_number_operand(value operand) { + if (operand.val_type != tt::DOUBLE) { + throw ComponentException("Invalid operand type"); + } +} + +void interpreter::check_json_operand( value operand) { + if (operand.val_type != tt::JSON) { + throw ComponentException("Expected JSON"); + } +} + +void interpreter::check_number_operands(token oper, value left, value right) { + if (left.val_type != tt::DOUBLE || right.val_type != tt::DOUBLE) { + throw ComponentException("Invalid operand type"); + } + if (right.doub_val == 0 && oper.type == tt::SLASH) { + throw ComponentException("Division by zero"); + } +} + + void interpreter::visit(binary *expr) { value left = evaluate(expr->left.get()); value right = evaluate(expr->right.get()); switch (expr->op.type) { case PLUS: - if (left.val_type == DOUBLE && right.val_type == DOUBLE) { + if (left.val_type == tt::DOUBLE && right.val_type == tt::DOUBLE) { result = value(left.doub_val + right.doub_val); - } else if (left.val_type == DOUBLE && right.val_type == DOUBLE) { + } else if (left.val_type == tt::JSON && right.val_type == tt::JSON) { result = value(mergeJson(left.json_val, right.json_val)); + } else { + throw ComponentException("Invalid operand type"); } - // обработать ошибку break; case MINUS: - // проверить типы - if (left.val_type == DOUBLE && right.val_type == DOUBLE) { - result = value(left.doub_val - right.doub_val); - } + check_number_operands(expr->op, left, right); + result = value(left.doub_val - right.doub_val); break; case STAR: - // check_number_operands(expr->op, left, right); - if (left.val_type == DOUBLE && right.val_type == DOUBLE) { - result = value(left.doub_val * right.doub_val); - } + check_number_operands(expr->op, left, right); + result = value(left.doub_val * right.doub_val); break; case SLASH: - // check_number_operands(expr->op, left, right); + check_number_operands(expr->op, left, right); result = value(left.doub_val / right.doub_val); break; case LESS: - // check_number_operands(expr->op, left, right); + check_number_operands(expr->op, left, right); result = value(left.doub_val < right.doub_val); break; case LESS_EQUAL: - // check_number_operands(expr->op, left, right); + check_number_operands(expr->op, left, right); result = value(left.doub_val <= right.doub_val); break; case GREATER: - // check_number_operands(expr->op, left, right); + check_number_operands(expr->op, left, right); result = value(left.doub_val > right.doub_val); break; case GREATER_EQUAL: - // check_number_operands(expr->op, left, right); + check_number_operands(expr->op, left, right); result = value(left.doub_val >= right.doub_val); break; case BANG_EQUAL: + check_number_operands(expr->op, left, right); result = value(!is_equal(left, right)); break; case EQUAL_EQUAL: + check_number_operands(expr->op, left, right); result = value(is_equal(left, right)); break; default: - result = value(); + throw ComponentException("Invalid operand type"); break; } } @@ -120,104 +128,84 @@ void interpreter::visit(func_in *expr) { } } -bool interpreter::find_word_inJson(std::string word, nlohmann::json jsonValue) { - if (jsonValue.is_string()) { - return jsonValue.get() == word; - } - - if (!jsonValue.is_array()) { - return false; - } - for (const auto &element : jsonValue) { - if (find_word_inJson(word, element)) { - return true; - } - } - return false; -} void interpreter::visit(unary *expr) { - value right = evaluate(expr->ex.get()); + value right = evaluate(expr->expression.get()); - switch (expr->op.type) { + switch (expr->oper.type) { case tt::MINUS: - // check_number_operand(expr->op, right); + check_number_operand(right); result = value(-right.doub_val); break; case tt::NOT: result = value(!is_truthy(right)); break; case tt::LEN: - if (right.val_type == tt::JSON) { - - result = value(json_length(right.json_val)); - } // обработать + check_json_operand(right); + result = value(json_length(right.json_val)); break; case tt::SPLIT: - if (right.val_type == tt::JSON) { - - result = value(splitJson(right.json_val)); - } // обработать + check_json_operand(right); + result = value(splitJson(right.json_val)); break; case tt::UPPER: - if (right.val_type == tt::JSON) { - - result = value(upperJsonString(right.json_val)); - } // обработать + check_json_operand(right); + result = value(upperJsonString(right.json_val)); break; case tt::LOWER: - if (right.val_type == tt::JSON) { - - result = value(lowerJsonString(right.json_val)); - } // обработать + check_json_operand(right); + result = value(lowerJsonString(right.json_val)); break; case tt::REDUCE: - if (right.val_type == tt::JSON) { - - result = value(reduceJson(right.json_val)); - } // обработать + check_json_operand(right); + result = value(reduceJson(right.json_val)); break; default: - result = value(); + ComponentException("Invalid operand type"); break; } } nlohmann::json interpreter::upperJsonString(const nlohmann::json &data) { + + if (data.is_string()) { + std::string str = data.get(); + std::transform(str.begin(), str.end(), str.begin(), ::toupper); + return str; + } + if (data.is_array()) { nlohmann::json result = nlohmann::json::array(); - for (const auto &item : data) { result.push_back(upperJsonString(item)); } - return result; - } else if (data.is_string()) { - std::string str = data.get(); - std::transform(str.begin(), str.end(), str.begin(), ::toupper); - return str; - } else { - return nlohmann::json(); } + + return nlohmann::json(); + // exeption? } + nlohmann::json interpreter::lowerJsonString(const nlohmann::json &data) { + + if (data.is_string()) { + std::string str = data.get(); + std::transform(str.begin(), str.end(), str.begin(), ::tolower); + return str; + } + if (data.is_array()) { nlohmann::json result = nlohmann::json::array(); - for (const auto &item : data) { result.push_back(lowerJsonString(item)); } - return result; - } else if (data.is_string()) { - std::string str = data.get(); - std::transform(str.begin(), str.end(), str.begin(), ::tolower); - return str; - } else { - return nlohmann::json(); } + + return nlohmann::json(); + } std::vector interpreter::splitString(const std::string &str) { @@ -234,10 +222,14 @@ std::vector interpreter::splitString(const std::string &str) { nlohmann::json interpreter::splitJson(const nlohmann::json &jsonValue) { if (jsonValue.is_null()) { return nlohmann::json::array(); - } else if (jsonValue.is_string()) { + } + + if (jsonValue.is_string()) { std::string str = jsonValue.get(); return splitString(str); - } else if (jsonValue.is_array()) { + } + + if (jsonValue.is_array()) { nlohmann::json result = nlohmann::json::array(); for (const auto &item : jsonValue) { if (item.is_string()) { @@ -246,28 +238,26 @@ nlohmann::json interpreter::splitJson(const nlohmann::json &jsonValue) { } } return result; - } else { - return nlohmann::json::array(); } + + return nlohmann::json::array(); } double interpreter::json_length(const nlohmann::json &jsonValue) { if (jsonValue.is_null()) { return 0; - } else if (jsonValue.is_array() || jsonValue.is_object()) { + } + + if (jsonValue.is_array() || jsonValue.is_object()) { return jsonValue.size(); - } else { - return 1; // объект неитерируемый } + + return 1; // неитерируемый объект, например число или строка } void interpreter::visit(literal *expr) { if (!expr->json_namevec.empty()) { - /* for (int i = 0; i < expr->json_namevec.size(); ++i ){ - std::cout << expr->json_namevec[i] <<" "<< i << std::endl; - }*/ - nlohmann::json json_val = find_json_value(card, expr->json_namevec); if (!json_val.empty()) { expr->val.val_type = JSON; @@ -277,10 +267,28 @@ void interpreter::visit(literal *expr) { result = expr->val; } -// разбить на мелкие функции -nlohmann::json -interpreter::find_json_value(const nlohmann::json &card, - std::vector levels_vec) { + +bool interpreter::find_word_inJson(std::string word, nlohmann::json jsonValue) { + if (jsonValue.is_string()) { + return jsonValue.get() == word; + } + + if (!jsonValue.is_array()) { + return false; + } + for (const auto &element : jsonValue) { + if (find_word_inJson(word, element)) { + return true; + } + } + return false; +} + + + + +nlohmann::json interpreter::find_json_value(const nlohmann::json& card, + std::vector levels_vec) { nlohmann::json current_json = card; for (size_t i = 0; i < levels_vec.size(); ++i) { @@ -290,31 +298,9 @@ interpreter::find_json_value(const nlohmann::json &card, if (current_json.contains(key)) { current_json = current_json[key]; } else if (key == "$ANY") { - nlohmann::json any_values; - for (auto it = current_json.begin(); it != current_json.end(); - ++it) { - const auto &result = find_json_value( - it.value(), - std::vector(levels_vec.begin() + i + 1, - levels_vec.end())); - if (!result.is_null()) { - any_values.push_back(result); - } - } - - if (any_values.size() == 1) { - return any_values[0]; - } else { - return any_values; - } - + return handleAnyKey(current_json, levels_vec, i); } else if (key == "$SELF") { - nlohmann::json self_keys; - for (auto it = current_json.begin(); it != current_json.end(); - ++it) { - self_keys.push_back(it.key()); - } - return self_keys; + return getSelfKeys(current_json); } else { return nlohmann::json(); } @@ -322,9 +308,45 @@ interpreter::find_json_value(const nlohmann::json &card, return nlohmann::json(); } } + return current_json; } +nlohmann::json interpreter::handleAnyKey(const nlohmann::json& json_value, + const std::vector& levels_vec, + size_t current_index) { + nlohmann::json any_values; + + for (auto it = json_value.begin(); it != json_value.end(); ++it) { + const auto& result = find_json_value( + it.value(), + std::vector(levels_vec.begin() + current_index + 1, levels_vec.end()) + ); + + if (!result.is_null()) { + any_values.push_back(result); + } + } + + if (any_values.size() == 1) { // возвращаем элемент, а не массив + return any_values[0]; + } else { + return any_values; + } +} + +nlohmann::json interpreter::getSelfKeys(const nlohmann::json& json_value) { + nlohmann::json self_keys; + + for (auto it = json_value.begin(); it != json_value.end(); ++it) { + self_keys.push_back(it.key()); + } + + return self_keys; +} + + + void interpreter::visit(logical_expr *ex) { value left = evaluate(ex->left.get()); if (ex->oper.type == OR) { @@ -361,15 +383,15 @@ nlohmann::json interpreter::reduceJson(const nlohmann::json &jsonElem) { return result; } -nlohmann::json interpreter::mergeJson(const nlohmann::json &json1, - const nlohmann::json &json2) { +nlohmann::json interpreter::mergeJson(const nlohmann::json &jsonLeft, + const nlohmann::json &jsonRight) { nlohmann::json mergedJson = nlohmann::json::object(); - for (nlohmann::json::const_iterator it = json1.begin(); it != json1.end(); + for (nlohmann::json::const_iterator it = jsonLeft.begin(); it != jsonLeft.end(); ++it) { mergedJson[it.key()] = it.value(); } - for (nlohmann::json::const_iterator it = json2.begin(); it != json2.end(); + for (nlohmann::json::const_iterator it = jsonRight.begin(); it != jsonRight.end(); ++it) { mergedJson[it.key()] = it.value(); } diff --git a/server/lib/query_language/main.cpp b/server/lib/query_language/src/main.cpp similarity index 67% rename from server/lib/query_language/main.cpp rename to server/lib/query_language/src/main.cpp index 9e9453b..cf857c5 100644 --- a/server/lib/query_language/main.cpp +++ b/server/lib/query_language/src/main.cpp @@ -1,4 +1,4 @@ -#include "interpreter.h" +#include "interpreter.hpp" using nlohmann::json; @@ -46,29 +46,31 @@ int main() { json jsonCard = card_to_json(card); - scanner scan("\"value2\" in(other[key4])"); + try { + scanner scan("\"value2\" in other[key2] or \"value2\" in other[key3]"); + //scanner scan("\"value2\" "); std::vector tokens = scan.scan_tokens(); - /*for (int i = 0; i < tokens.size(); ++i) { - std::cout << tokens[i].lexeme << " " << tokens[i].type << std::endl; - }*/ - - parser p(tokens); + parser p(tokens); std::unique_ptr exp = p.parse(); - interpreter inter; - value val = inter.interpret(exp.get(), jsonCard); + interpreter inter; + value val = inter.interpret(exp.get(), jsonCard); + if (val.val_type == DOUBLE) { - std::cout << "значение: " << val.doub_val << std::endl; + std::cout << "Значение: " << val.doub_val << std::endl; } else if (val.val_type == JSON) { - std::cout << "это json " << std::endl; - std::cout << "значение: " << val.json_val.dump() << std::endl; + std::cout << "Это JSON" << std::endl; + std::cout << "Значение: " << val.json_val.dump() << std::endl; } else if (val.val_type == BOOL) { - std::cout << "это bool " << std::endl; - std::cout << "значение: " << val.bool_val << std::endl; + std::cout << "Это логическое значение" << std::endl; + std::cout << "Значение: " << val.bool_val << std::endl; } else if (val.val_type == STRING) { - std::cout << "это string " << std::endl; - std::cout << "значение: " << val.str_val << std::endl; + std::cout << "Это строка" << std::endl; + std::cout << "Значение: " << val.str_val << std::endl; } else if (val.val_type == EMPTY) { - std::cout << "пусто" << std::endl; + std::cout << "Пусто" << std::endl; } +} catch (const ComponentException& e) { + std::cerr << "Ошибка: " << e.what() << std::endl; +} return 0; } diff --git a/server/lib/query_language/parcer.cpp b/server/lib/query_language/src/parcer.cpp similarity index 55% rename from server/lib/query_language/parcer.cpp rename to server/lib/query_language/src/parcer.cpp index 6930f49..eb027cf 100644 --- a/server/lib/query_language/parcer.cpp +++ b/server/lib/query_language/src/parcer.cpp @@ -1,4 +1,4 @@ -#include "parcer.h" +#include "parcer.hpp" parser::parser(std::vector &t) : tokens(t){}; @@ -34,29 +34,39 @@ bool parser::match(std::vector types) { return false; } -// потом заменить ifы + std::unique_ptr parser::primary() { - if (match({tt::FALSE})) - return std::make_unique(false); - if (match({tt::TRUE})) - return std::make_unique(true); - if (match({tt::NUMBER})) { - return std::make_unique(std::stod(previous().literal)); - } - if (match({tt::STRING})) - return std::make_unique(previous().literal); - if (match({tt::LEFT_PAREN})) { - std::unique_ptr expr = expression(); - // обработать, что нет правой скобки - return std::make_unique(std::move(expr)); - } - if (match({tt::IDENTIFIER})) { - std::vector json_fields = read_json_elem(); - if (!json_fields.empty()) { - return std::make_unique(json_fields); - } // обработать ошибку + token_type type = peek().type; + advance(); + + switch (type) { + case tt::FALSE: + return std::make_unique(false); + case tt::TRUE: + return std::make_unique(true); + case tt::NUMBER: + return std::make_unique(std::stod(previous().literal)); + case tt::STRING: + return std::make_unique(previous().literal); + case tt::LEFT_PAREN: { + std::unique_ptr expr = expression(); + if (match({tt::RIGHT_PAREN})) { + return std::make_unique(std::move(expr)); + } else { + throw ComponentException("Missing closing parenthesis for grouping."); + } + } + case tt::IDENTIFIER: { + std::vector json_fields = read_json_elem(); + if (!json_fields.empty()) { + return std::make_unique(json_fields); + } else { + throw ComponentException("Invalid JSON element."); + } + } + default: + throw ComponentException("Unexpected token encountered."); } - return nullptr; } std::vector parser::read_json_elem() { @@ -70,7 +80,7 @@ std::vector parser::read_json_elem() { } if (!match({tt::RIGHT_BRACKET})) { - return std::vector(); + throw ComponentException("Missing closing parenthesis for JSON."); } } return json_fields; @@ -78,14 +88,19 @@ std::vector parser::read_json_elem() { std::unique_ptr parser::func_in_class() { std::unique_ptr left = primary(); - if (match({tt::IN})) { - if (match({tt::LEFT_PAREN})) { - std::unique_ptr right = primary(); - if (match({tt::RIGHT_PAREN})) { - return std::make_unique(std::move(left), - std::move(right)); - } - } + if (match({tt::IN})){ + /*if(!match({tt::LEFT_PAREN})){ + throw ComponentException("Missing open parenthesis for function call."); + }*/ + + std::unique_ptr right = primary(); + + /*if (!match({tt::RIGHT_PAREN})) { + throw ComponentException("Missing closing parenthesis for function call."); + }*/ + + return std::make_unique(std::move(left), + std::move(right)); } return left; } @@ -106,51 +121,50 @@ std::unique_ptr parser::unar() { } std::unique_ptr parser::multiplication() { - std::unique_ptr expression = unar(); + std::unique_ptr left = unar(); while (match({tt::SLASH, tt::STAR})) { token oper = previous(); std::unique_ptr right = unar(); - expression = std::make_unique( - std::move(expression), oper, std::move(right)); + left = std::make_unique( + std::move(left), oper, std::move(right)); } - return expression; + return left; } std::unique_ptr parser::addition() { - std::unique_ptr expression = multiplication(); + std::unique_ptr left = multiplication(); while (match({tt::MINUS, tt::PLUS})) { - std::cout << "операция + -" << std::endl; token oper = previous(); std::unique_ptr right = multiplication(); - expression = std::make_unique( - std::move(expression), oper, std::move(right)); + left = std::make_unique( + std::move(left), oper, std::move(right)); } - return expression; + return left; } std::unique_ptr parser::comparison() { - std::unique_ptr expression = addition(); + std::unique_ptr left = addition(); while (match({tt::LESS, tt::LESS_EQUAL, tt::GREATER, tt::GREATER_EQUAL})) { token oper = previous(); std::unique_ptr right = addition(); - expression = std::make_unique( - std::move(expression), oper, std::move(right)); + left = std::make_unique( + std::move(left), oper, std::move(right)); } - return expression; + return left; } std::unique_ptr parser::equality() { - std::unique_ptr expression = comparison(); + std::unique_ptr left = comparison(); while (match({tt::BANG_EQUAL, tt::EQUAL_EQUAL})) { token oper = previous(); std::unique_ptr right = comparison(); - expression = std::make_unique( - std::move(expression), oper, std::move(right)); + left = std::make_unique( + std::move(left), oper, std::move(right)); } - return expression; + return left; } -std::unique_ptr parser::_and() { +std::unique_ptr parser::and_expr() { std::unique_ptr left = equality(); while (match({tt::AND})) { @@ -162,12 +176,12 @@ std::unique_ptr parser::_and() { return left; } -std::unique_ptr parser::_or() { - std::unique_ptr left = _and(); - // literal* l = reinterpret_cast(left); +std::unique_ptr parser::or_expr() { + std::unique_ptr left = and_expr(); + while (match({tt::OR})) { token oper = previous(); - std::unique_ptr right = _and(); + std::unique_ptr right = and_expr(); left = std::make_unique( std::move(left), oper, std::move(right)); } @@ -175,7 +189,7 @@ std::unique_ptr parser::_or() { } std::unique_ptr parser::expression() { - return _or(); + return or_expr(); } std::unique_ptr parser::parse() { diff --git a/server/lib/query_language/querying.cpp b/server/lib/query_language/src/querying.cpp similarity index 95% rename from server/lib/query_language/querying.cpp rename to server/lib/query_language/src/querying.cpp index 702f167..8f641ad 100644 --- a/server/lib/query_language/querying.cpp +++ b/server/lib/query_language/src/querying.cpp @@ -1,8 +1,8 @@ #include "querying.hpp" -#include "interpreter.h" -#include "parcer.h" -#include "scaner.h" +#include "interpreter.hpp" +#include "parcer.hpp" +#include "scaner.hpp" #include "spdlog/spdlog.h" #include #include diff --git a/server/lib/query_language/scaner.cpp b/server/lib/query_language/src/scaner.cpp similarity index 88% rename from server/lib/query_language/scaner.cpp rename to server/lib/query_language/src/scaner.cpp index c48fde2..b3c05a6 100644 --- a/server/lib/query_language/scaner.cpp +++ b/server/lib/query_language/src/scaner.cpp @@ -1,4 +1,4 @@ -#include "scaner.h" +#include "scaner.hpp" void scanner::init_keywords() { keywords["in"] = tt::IN; @@ -73,7 +73,7 @@ void scanner::number() { add_token(tt::NUMBER, source.substr(start, current - start)); } -// избавиться от дублирования кода + void scanner::read_json_keyword() { advance(); // считали $ while (isalnum(peek()[0]) || peek()[0] == '_') { @@ -83,10 +83,10 @@ void scanner::read_json_keyword() { if (text == "$ANY" || text == "$SELF") { add_token(tt::IDENTIFIER); } - // обработать ошибку, когда команды на $ нет + // } -// избавиться от дублирования кода + void scanner::read_json_level() { while (isalnum(peek()[0]) || peek()[0] == '_') { advance(); @@ -103,21 +103,21 @@ void scanner::string() { advance(); } - // Unterminated string + // нет вторых кавычек if (!has_next()) { - // тут вставить логгер - return; + + throw ComponentException("Missing closing quotation mark for string."); } - advance(); // за " - + advance(); // пропуск для кавычки + // добавляем слово без кавычек std::string value = source.substr(start + 1, current - start - 2); add_token(tt::STRING, value); } void scanner::scan_token() { - const char c = advance(); - switch (c) { + const char token = advance(); + switch (token) { case '(': add_token(tt::LEFT_PAREN); break; @@ -169,9 +169,10 @@ void scanner::scan_token() { case '>': add_token(match(std::string("=")) ? tt::GREATER_EQUAL : tt::GREATER); - break; + break; case ' ': case '\r': + case '\n': case '\t': break; case '"': @@ -179,14 +180,14 @@ void scanner::scan_token() { break; default: - if (is_digit(std::string(1, c))) + if (is_digit(std::string(1, token))) number(); - else if (c == '$') + else if (token == '$') read_json_keyword(); - else if (isalpha(c)) + else if (isalpha(token)) read_json_level(); else - std::cout << "Unexpected character "; + throw ComponentException("Unexpected character encountered."); break; } } -- GitLab