#include "parser.h" #include "ast_builder.h" #include "type_check.h" #include #include #include #include #include #include #if defined(_tsan_enabled_) #include #endif #include 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 guard(SanitizerJsonPathTranslationMutex); #endif NProtoAST::TProtoASTBuilder3 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(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); } }