summaryrefslogtreecommitdiffstats
path: root/yql/essentials/minikql/jsonpath/parser/parser.cpp
diff options
context:
space:
mode:
authorvvvv <[email protected]>2024-12-18 21:57:17 +0300
committervvvv <[email protected]>2024-12-18 22:58:34 +0300
commitf7f8a1dcd4b4b4a1af7acc6d8127d285c3850795 (patch)
treec22ca71d9eb197030fbd946452f4aadf613df95c /yql/essentials/minikql/jsonpath/parser/parser.cpp
parent9690d79e797ada85de4a648fbc1e386ea4621efe (diff)
Extracted parser from jsonpath lib
init commit_hash:8c6dd46ee72034f0480757612dcceb524d19a1d1
Diffstat (limited to 'yql/essentials/minikql/jsonpath/parser/parser.cpp')
-rw-r--r--yql/essentials/minikql/jsonpath/parser/parser.cpp104
1 files changed, 104 insertions, 0 deletions
diff --git a/yql/essentials/minikql/jsonpath/parser/parser.cpp b/yql/essentials/minikql/jsonpath/parser/parser.cpp
new file mode 100644
index 00000000000..105305ea3c5
--- /dev/null
+++ b/yql/essentials/minikql/jsonpath/parser/parser.cpp
@@ -0,0 +1,104 @@
+#include "parser.h"
+
+#include "ast_builder.h"
+#include "type_check.h"
+
+#include <yql/essentials/core/issue/protos/issue_id.pb.h>
+#include <yql/essentials/parser/proto_ast/gen/jsonpath/JsonPathLexer.h>
+#include <yql/essentials/parser/proto_ast/gen/jsonpath/JsonPathParser.h>
+#include <yql/essentials/parser/proto_ast/gen/jsonpath/JsonPathParser.pb.h>
+#include <yql/essentials/parser/proto_ast/antlr3/proto_ast_antlr3.h>
+
+#include <google/protobuf/message.h>
+
+#if defined(_tsan_enabled_)
+#include <util/system/mutex.h>
+#endif
+
+#include <util/string/strip.h>
+
+namespace {
+
+using namespace NYql;
+
+#if defined(_tsan_enabled_)
+TMutex SanitizerJsonPathTranslationMutex;
+#endif
+
+class TParseErrorsCollector : public NProtoAST::IErrorCollector {
+public:
+ TParseErrorsCollector(TIssues& issues, size_t maxErrors)
+ : IErrorCollector(maxErrors)
+ , Issues(issues)
+ {
+ }
+
+private:
+ void AddError(ui32 line, ui32 column, const TString& message) override {
+ Issues.AddIssue(TPosition(column, line, "jsonpath"), StripString(message));
+ Issues.back().SetCode(TIssuesIds::JSONPATH_PARSE_ERROR, TSeverityIds::S_ERROR);
+ }
+
+ TIssues& Issues;
+};
+
+}
+
+namespace NYql::NJsonPath {
+
+const TAstNodePtr ParseJsonPathAst(const TStringBuf path, TIssues& issues, size_t maxParseErrors) {
+ if (!IsUtf(path)) {
+ issues.AddIssue(TPosition(1, 1, "jsonpath"), "JsonPath must be UTF-8 encoded string");
+ issues.back().SetCode(TIssuesIds::JSONPATH_PARSE_ERROR, TSeverityIds::S_ERROR);
+ return {};
+ }
+
+ google::protobuf::Arena arena;
+ const google::protobuf::Message* rawAst = nullptr;
+ {
+ #if defined(_tsan_enabled_)
+ TGuard<TMutex> guard(SanitizerJsonPathTranslationMutex);
+ #endif
+ NProtoAST::TProtoASTBuilder3<NALP::JsonPathParser, NALP::JsonPathLexer> builder(path, "JsonPath", &arena);
+ TParseErrorsCollector collector(issues, maxParseErrors);
+ rawAst = builder.BuildAST(collector);
+ }
+
+ if (rawAst == nullptr) {
+ return nullptr;
+ }
+
+ const google::protobuf::Descriptor* descriptor = rawAst->GetDescriptor();
+ if (descriptor && descriptor->name() != "TJsonPathParserAST") {
+ return nullptr;
+ }
+
+ const auto* protoAst = static_cast<const NJsonPathGenerated::TJsonPathParserAST*>(rawAst);
+ TAstBuilder astBuilder(issues);
+ TAstNodePtr ast = astBuilder.Build(*protoAst);
+ if (!issues.Empty()) {
+ return nullptr;
+ }
+
+ // At this point AST is guaranteed to be valid. We return it even if
+ // type checker finds some logical errors.
+ TJsonPathTypeChecker checker(issues);
+ ast->Accept(checker);
+ return ast;
+}
+
+const TJsonPathPtr PackBinaryJsonPath(const TAstNodePtr ast) {
+ TJsonPathBuilder builder;
+ ast->Accept(builder);
+ return builder.ShrinkAndGetResult();
+}
+
+const TJsonPathPtr ParseJsonPath(const TStringBuf path, TIssues& issues, size_t maxParseErrors) {
+ const auto ast = ParseJsonPathAst(path, issues, maxParseErrors);
+ if (!issues.Empty()) {
+ return {};
+ }
+ return PackBinaryJsonPath(ast);
+}
+
+}