diff options
| author | vityaman <[email protected]> | 2025-03-28 22:01:21 +0300 |
|---|---|---|
| committer | robot-piglet <[email protected]> | 2025-03-28 22:36:16 +0300 |
| commit | b60cb8f5ce78ae5f63304a534278e124d31398b0 (patch) | |
| tree | 033d726f561f37e4e258460159b3b379aa9c70f6 | |
| parent | df00f0d151a43de80f6e41291d9267afbbfb18a4 (diff) | |
YQL-19747 Complete Function Names
- Function names are suggested now
- Changed the module structure
- Checking ruleIndex independence on mode (ansi | default) via unit tests
---
Pull Request resolved: https://github.com/ytsaurus/ytsaurus/pull/1163
commit_hash:1b1a27d2cff8db663c5c7e8efb57896476823315
32 files changed, 517 insertions, 291 deletions
diff --git a/yql/essentials/sql/v1/complete/antlr4/c3i.h b/yql/essentials/sql/v1/complete/antlr4/c3i.h new file mode 100644 index 00000000000..ca91649a547 --- /dev/null +++ b/yql/essentials/sql/v1/complete/antlr4/c3i.h @@ -0,0 +1,41 @@ +#pragma once + +#include "defs.h" + +#include <util/generic/fwd.h> +#include <util/generic/string.h> +#include <util/generic/vector.h> + +#include <unordered_set> + +namespace NSQLComplete { + + struct TSuggestedToken { + TTokenId Number; + }; + + struct TMatchedRule { + TRuleId Index; + TParserCallStack ParserCallStack; + }; + + struct TC3Candidates { + TVector<TSuggestedToken> Tokens; + TVector<TMatchedRule> Rules; + }; + + class IC3Engine { + public: + using TPtr = THolder<IC3Engine>; + + // std::unordered_set is used to prevent copying into c3 core + struct TConfig { + std::unordered_set<TTokenId> IgnoredTokens; + std::unordered_set<TRuleId> PreferredRules; + }; + + virtual TC3Candidates Complete(TStringBuf prefix) = 0; + virtual ~IC3Engine() = default; + }; + +} // namespace NSQLComplete diff --git a/yql/essentials/sql/v1/complete/c3_engine.h b/yql/essentials/sql/v1/complete/antlr4/c3t.h index 907339ab1f5..9042937678a 100644 --- a/yql/essentials/sql/v1/complete/c3_engine.h +++ b/yql/essentials/sql/v1/complete/antlr4/c3t.h @@ -1,13 +1,15 @@ #pragma once -#include "sql_antlr4.h" -#include "string_util.h" +#include "c3i.h" + +#include <yql/essentials/sql/v1/complete/text/word.h> #include <contrib/libs/antlr4_cpp_runtime/src/ANTLRInputStream.h> #include <contrib/libs/antlr4_cpp_runtime/src/BufferedTokenStream.h> #include <contrib/libs/antlr4_cpp_runtime/src/Vocabulary.h> #include <contrib/libs/antlr4-c3/src/CodeCompletionCore.hpp> +#include <util/generic/fwd.h> #include <util/generic/string.h> #include <util/generic/vector.h> @@ -15,34 +17,6 @@ namespace NSQLComplete { - struct TSuggestedToken { - TTokenId Number; - }; - - struct TMatchedRule { - TRuleId Index; - }; - - struct TC3Candidates { - TVector<TSuggestedToken> Tokens; - TVector<TMatchedRule> Rules; - }; - - class IC3Engine { - public: - using TPtr = THolder<IC3Engine>; - - // std::unordered_set is used to prevent copying into c3 core - struct TConfig { - std::unordered_set<TTokenId> IgnoredTokens; - std::unordered_set<TRuleId> PreferredRules; - }; - - virtual TC3Candidates Complete(TStringBuf queryPrefix) = 0; - virtual const antlr4::dfa::Vocabulary& GetVocabulary() const = 0; - virtual ~IC3Engine() = default; - }; - template <class Lexer, class Parser> struct TAntlrGrammar { using TLexer = Lexer; @@ -68,29 +42,24 @@ namespace NSQLComplete { CompletionCore.preferredRules = std::move(config.PreferredRules); } - TC3Candidates Complete(TStringBuf queryPrefix) override { - Assign(queryPrefix); - const auto caretTokenIndex = CaretTokenIndex(queryPrefix); + TC3Candidates Complete(TStringBuf prefix) override { + Assign(prefix); + const auto caretTokenIndex = CaretTokenIndex(prefix); auto candidates = CompletionCore.collectCandidates(caretTokenIndex); return Converted(std::move(candidates)); } - const antlr4::dfa::Vocabulary& GetVocabulary() const override { - return Lexer.getVocabulary(); - } - private: - void Assign(TStringBuf queryPrefix) { - Chars.load(queryPrefix.Data(), queryPrefix.Size(), /* lenient = */ false); + void Assign(TStringBuf prefix) { + Chars.load(prefix.Data(), prefix.Size(), /* lenient = */ false); Lexer.reset(); Tokens.setTokenSource(&Lexer); - Tokens.fill(); } - size_t CaretTokenIndex(TStringBuf queryPrefix) { + size_t CaretTokenIndex(TStringBuf prefix) { const auto tokensCount = Tokens.size(); - if (2 <= tokensCount && !LastWord(queryPrefix).Empty()) { + if (2 <= tokensCount && !LastWord(prefix).Empty()) { return tokensCount - 2; } return tokensCount - 1; @@ -101,8 +70,9 @@ namespace NSQLComplete { for (const auto& [token, _] : candidates.tokens) { converted.Tokens.emplace_back(token); } - for (const auto& [rule, _] : candidates.rules) { - converted.Rules.emplace_back(rule); + for (auto& [rule, data] : candidates.rules) { + converted.Rules.emplace_back(rule, std::move(data.ruleList)); + converted.Rules.back().ParserCallStack.emplace_back(rule); } return converted; } diff --git a/yql/essentials/sql/v1/complete/antlr4/defs.h b/yql/essentials/sql/v1/complete/antlr4/defs.h new file mode 100644 index 00000000000..7f2991a8a74 --- /dev/null +++ b/yql/essentials/sql/v1/complete/antlr4/defs.h @@ -0,0 +1,18 @@ +#pragma once + +#include <contrib/libs/antlr4_cpp_runtime/src/Token.h> + +#include <cstddef> +#include <vector> + +namespace NSQLComplete { + + using TTokenId = size_t; + using TRuleId = size_t; + + constexpr TTokenId TOKEN_EOF = antlr4::Token::EOF; + + // std::vector is used to prevent copying a C3 output + using TParserCallStack = std::vector<TRuleId>; + +} // namespace NSQLComplete diff --git a/yql/essentials/sql/v1/complete/antlr4/ya.make b/yql/essentials/sql/v1/complete/antlr4/ya.make new file mode 100644 index 00000000000..36145606177 --- /dev/null +++ b/yql/essentials/sql/v1/complete/antlr4/ya.make @@ -0,0 +1,9 @@ +LIBRARY() + +PEERDIR( + contrib/libs/antlr4_cpp_runtime + contrib/libs/antlr4-c3 + yql/essentials/sql/v1/complete/text +) + +END() diff --git a/yql/essentials/sql/v1/complete/name/name_service.h b/yql/essentials/sql/v1/complete/name/name_service.h index a4998fd8ff1..d3cf153341e 100644 --- a/yql/essentials/sql/v1/complete/name/name_service.h +++ b/yql/essentials/sql/v1/complete/name/name_service.h @@ -17,18 +17,24 @@ namespace NSQLComplete { using TConstraints = std::monostate; }; + struct TFunctionName: TIndentifier { + using TConstraints = std::monostate; + }; + using TGenericName = std::variant< - TTypeName>; + TTypeName, + TFunctionName>; struct TNameRequest { struct { std::optional<TTypeName::TConstraints> TypeName; + std::optional<TTypeName::TConstraints> Function; } Constraints; TString Prefix = ""; size_t Limit = 128; bool IsEmpty() const { - return !Constraints.TypeName; + return !Constraints.TypeName && !Constraints.Function; } }; diff --git a/yql/essentials/sql/v1/complete/name/static/default_name_set.cpp b/yql/essentials/sql/v1/complete/name/static/default_name_set.cpp index 06c55a1d27c..f04c9180a3c 100644 --- a/yql/essentials/sql/v1/complete/name/static/default_name_set.cpp +++ b/yql/essentials/sql/v1/complete/name/static/default_name_set.cpp @@ -40,6 +40,33 @@ namespace NSQLComplete { "Decimal", "DyNumber", }, + .Functions = { + "COALESCE", + "LENGTH", + "SUBSTRING", + "FIND", + "RFIND", + "StartsWith", + "EndsWith", + "IF", + "NANVL", + "Random", + "RandomNumber", + "RandomUuid", + "CurrentUtcDate", + "CurrentUtcDatetime", + "CurrentUtcTimestamp", + "CurrentTzDate", + "CurrentTzDatetime", + "CurrentTzTimestamp", + "AddTimezone", + "RemoveTimezone", + "Version", + "MAX_OF", + "MIN_OF", + "GREATEST", + "LEAST", + }, }; } diff --git a/yql/essentials/sql/v1/complete/name/static/name_service.cpp b/yql/essentials/sql/v1/complete/name/static/name_service.cpp index 4f0706a4eae..fa2bbfb360b 100644 --- a/yql/essentials/sql/v1/complete/name/static/name_service.cpp +++ b/yql/essentials/sql/v1/complete/name/static/name_service.cpp @@ -26,9 +26,12 @@ namespace NSQLComplete { size_t KindWeight(const TGenericName& name) { return std::visit([](const auto& name) { using T = std::decay_t<decltype(name)>; - if constexpr (std::is_same_v<T, TTypeName>) { + if constexpr (std::is_same_v<T, TFunctionName>) { return 1; } + if constexpr (std::is_same_v<T, TTypeName>) { + return 2; + } }, name); } @@ -60,6 +63,7 @@ namespace NSQLComplete { : NameSet_(std::move(names)) { Sort(NameSet_.Types); + Sort(NameSet_.Functions); } TFuture<TNameResponse> Lookup(TNameRequest request) override { @@ -70,10 +74,15 @@ namespace NSQLComplete { FilteredByPrefix(request.Prefix, NameSet_.Types)); } + if (request.Constraints.Function) { + AppendAs<TFunctionName>( + response.RankedNames, + FilteredByPrefix(request.Prefix, NameSet_.Functions)); + } + Sort(response.RankedNames); response.RankedNames.crop(request.Limit); - return NThreading::MakeFuture(std::move(response)); } diff --git a/yql/essentials/sql/v1/complete/name/static/name_service.h b/yql/essentials/sql/v1/complete/name/static/name_service.h index f9d8ec00003..79405598032 100644 --- a/yql/essentials/sql/v1/complete/name/static/name_service.h +++ b/yql/essentials/sql/v1/complete/name/static/name_service.h @@ -6,6 +6,7 @@ namespace NSQLComplete { struct NameSet { TVector<TString> Types; + TVector<TString> Functions; }; NameSet MakeDefaultNameSet(); diff --git a/yql/essentials/sql/v1/complete/sql_antlr4.cpp b/yql/essentials/sql/v1/complete/sql_antlr4.cpp deleted file mode 100644 index 724032d6124..00000000000 --- a/yql/essentials/sql/v1/complete/sql_antlr4.cpp +++ /dev/null @@ -1,126 +0,0 @@ -#include "sql_antlr4.h" - -#include <yql/essentials/sql/v1/format/sql_format.h> - -#include <yql/essentials/parser/antlr_ast/gen/v1_antlr4/SQLv1Antlr4Lexer.h> -#include <yql/essentials/parser/antlr_ast/gen/v1_antlr4/SQLv1Antlr4Parser.h> -#include <yql/essentials/parser/antlr_ast/gen/v1_ansi_antlr4/SQLv1Antlr4Lexer.h> -#include <yql/essentials/parser/antlr_ast/gen/v1_ansi_antlr4/SQLv1Antlr4Parser.h> - -#define RULE_(mode, name) NALA##mode##Antlr4::SQLv1Antlr4Parser::Rule##name - -#define RULE(name) RULE_(Default, name) - -#define STATIC_ASSERT_RULE_ID_MODE_INDEPENDENT(name) \ - static_assert(RULE_(Default, name) == RULE_(Ansi, name)) - -namespace NSQLComplete { - - class TSqlGrammar: public ISqlGrammar { - public: - TSqlGrammar(bool isAnsiLexer) - : Vocabulary(GetVocabulary(isAnsiLexer)) - , AllTokens(ComputeAllTokens()) - , KeywordTokens(ComputeKeywordTokens()) - { - } - - const antlr4::dfa::Vocabulary& GetVocabulary() const override { - return *Vocabulary; - } - - const std::unordered_set<TTokenId>& GetAllTokens() const override { - return AllTokens; - } - - const std::unordered_set<TTokenId>& GetKeywordTokens() const override { - return KeywordTokens; - } - - const TVector<TRuleId>& GetKeywordRules() const override { - static const TVector<TRuleId> KeywordRules = { - RULE(Keyword), - RULE(Keyword_expr_uncompat), - RULE(Keyword_table_uncompat), - RULE(Keyword_select_uncompat), - RULE(Keyword_alter_uncompat), - RULE(Keyword_in_uncompat), - RULE(Keyword_window_uncompat), - RULE(Keyword_hint_uncompat), - RULE(Keyword_as_compat), - RULE(Keyword_compat), - }; - - STATIC_ASSERT_RULE_ID_MODE_INDEPENDENT(Keyword); - STATIC_ASSERT_RULE_ID_MODE_INDEPENDENT(Keyword_expr_uncompat); - STATIC_ASSERT_RULE_ID_MODE_INDEPENDENT(Keyword_table_uncompat); - STATIC_ASSERT_RULE_ID_MODE_INDEPENDENT(Keyword_select_uncompat); - STATIC_ASSERT_RULE_ID_MODE_INDEPENDENT(Keyword_alter_uncompat); - STATIC_ASSERT_RULE_ID_MODE_INDEPENDENT(Keyword_in_uncompat); - STATIC_ASSERT_RULE_ID_MODE_INDEPENDENT(Keyword_window_uncompat); - STATIC_ASSERT_RULE_ID_MODE_INDEPENDENT(Keyword_hint_uncompat); - STATIC_ASSERT_RULE_ID_MODE_INDEPENDENT(Keyword_as_compat); - STATIC_ASSERT_RULE_ID_MODE_INDEPENDENT(Keyword_compat); - - return KeywordRules; - } - - const TVector<TRuleId>& GetTypeNameRules() const override { - static const TVector<TRuleId> TypeNameRules = { - RULE(Type_name_simple), - }; - - STATIC_ASSERT_RULE_ID_MODE_INDEPENDENT(Type_name_simple); - - return TypeNameRules; - } - - private: - static const antlr4::dfa::Vocabulary* GetVocabulary(bool isAnsiLexer) { - if (isAnsiLexer) { // Taking a reference is okay as vocabulary storage is static - return &NALAAnsiAntlr4::SQLv1Antlr4Parser(nullptr).getVocabulary(); - } - return &NALADefaultAntlr4::SQLv1Antlr4Parser(nullptr).getVocabulary(); - } - - std::unordered_set<TTokenId> ComputeAllTokens() { - const auto& vocabulary = GetVocabulary(); - - std::unordered_set<TTokenId> allTokens; - - for (size_t type = 1; type <= vocabulary.getMaxTokenType(); ++type) { - allTokens.emplace(type); - } - - return allTokens; - } - - std::unordered_set<TTokenId> ComputeKeywordTokens() { - const auto& vocabulary = GetVocabulary(); - const auto keywords = NSQLFormat::GetKeywords(); - - auto keywordTokens = GetAllTokens(); - std::erase_if(keywordTokens, [&](TTokenId token) { - return !keywords.contains(vocabulary.getSymbolicName(token)); - }); - keywordTokens.erase(TOKEN_EOF); - - return keywordTokens; - } - - const antlr4::dfa::Vocabulary* Vocabulary; - const std::unordered_set<TTokenId> AllTokens; - const std::unordered_set<TTokenId> KeywordTokens; - }; - - const ISqlGrammar& GetSqlGrammar(bool isAnsiLexer) { - const static TSqlGrammar DefaultSqlGrammar(/* isAnsiLexer = */ false); - const static TSqlGrammar AnsiSqlGrammar(/* isAnsiLexer = */ true); - - if (isAnsiLexer) { - return AnsiSqlGrammar; - } - return DefaultSqlGrammar; - } - -} // namespace NSQLComplete diff --git a/yql/essentials/sql/v1/complete/sql_complete.cpp b/yql/essentials/sql/v1/complete/sql_complete.cpp index 753d0a2835c..b3ddda2b23f 100644 --- a/yql/essentials/sql/v1/complete/sql_complete.cpp +++ b/yql/essentials/sql/v1/complete/sql_complete.cpp @@ -1,9 +1,8 @@ #include "sql_complete.h" -#include "sql_context.h" -#include "string_util.h" - +#include <yql/essentials/sql/v1/complete/text/word.h> #include <yql/essentials/sql/v1/complete/name/static/name_service.h> +#include <yql/essentials/sql/v1/complete/syntax/local.h> // FIXME(YQL-19747): unwanted dependency on a lexer implementation #include <yql/essentials/sql/v1/lexer/antlr4_pure/lexer.h> @@ -19,10 +18,9 @@ namespace NSQLComplete { explicit TSqlCompletionEngine( TLexerSupplier lexer, INameService::TPtr names, - ISqlCompletionEngine::TConfiguration configuration - ) + ISqlCompletionEngine::TConfiguration configuration) : Configuration(std::move(configuration)) - , ContextInference(MakeSqlContextInference(lexer)) + , SyntaxAnalysis(MakeLocalSyntaxAnalysis(lexer)) , Names(std::move(names)) { } @@ -31,7 +29,7 @@ namespace NSQLComplete { auto prefix = input.Text.Head(input.CursorPosition); auto completedToken = GetCompletedToken(prefix); - auto context = ContextInference->Analyze(input); + auto context = SyntaxAnalysis->Analyze(input); TVector<TCandidate> candidates; EnrichWithKeywords(candidates, std::move(context.Keywords), completedToken); @@ -67,7 +65,7 @@ namespace NSQLComplete { void EnrichWithNames( TVector<TCandidate>& candidates, - const TCompletionContext& context, + const TLocalSyntaxContext& context, const TCompletedToken& prefix) { if (candidates.size() == Configuration.Limit) { return; @@ -82,6 +80,10 @@ namespace NSQLComplete { request.Constraints.TypeName = TTypeName::TConstraints(); } + if (context.IsFunctionName) { + request.Constraints.Function = TFunctionName::TConstraints(); + } + if (request.IsEmpty()) { return; } @@ -96,9 +98,12 @@ namespace NSQLComplete { for (auto& name : names) { candidates.emplace_back(std::visit([](auto&& name) -> TCandidate { using T = std::decay_t<decltype(name)>; - if constexpr (std::is_base_of_v<TIndentifier, T>) { + if constexpr (std::is_base_of_v<TTypeName, T>) { return {ECandidateKind::TypeName, std::move(name.Indentifier)}; } + if constexpr (std::is_base_of_v<TFunctionName, T>) { + return {ECandidateKind::FunctionName, std::move(name.Indentifier)}; + } }, std::move(name))); } } @@ -112,7 +117,7 @@ namespace NSQLComplete { } TConfiguration Configuration; - ISqlContextInference::TPtr ContextInference; + ILocalSyntaxAnalysis::TPtr SyntaxAnalysis; INameService::TPtr Names; }; @@ -136,7 +141,7 @@ namespace NSQLComplete { INameService::TPtr names, ISqlCompletionEngine::TConfiguration configuration) { return ISqlCompletionEngine::TPtr( - new TSqlCompletionEngine(lexer, std::move(names), std::move(configuration))); + new TSqlCompletionEngine(lexer, std::move(names), std::move(configuration))); } } // namespace NSQLComplete @@ -150,6 +155,9 @@ void Out<NSQLComplete::ECandidateKind>(IOutputStream& out, NSQLComplete::ECandid case NSQLComplete::ECandidateKind::TypeName: out << "TypeName"; break; + case NSQLComplete::ECandidateKind::FunctionName: + out << "FunctionName"; + break; } } diff --git a/yql/essentials/sql/v1/complete/sql_complete.h b/yql/essentials/sql/v1/complete/sql_complete.h index feee2b47ddb..b8a970efd8f 100644 --- a/yql/essentials/sql/v1/complete/sql_complete.h +++ b/yql/essentials/sql/v1/complete/sql_complete.h @@ -21,6 +21,7 @@ namespace NSQLComplete { enum class ECandidateKind { Keyword, TypeName, + FunctionName, }; struct TCandidate { diff --git a/yql/essentials/sql/v1/complete/sql_complete_ut.cpp b/yql/essentials/sql/v1/complete/sql_complete_ut.cpp index aa242d313cb..5f07d5c3388 100644 --- a/yql/essentials/sql/v1/complete/sql_complete_ut.cpp +++ b/yql/essentials/sql/v1/complete/sql_complete_ut.cpp @@ -35,6 +35,7 @@ public: }; Y_UNIT_TEST_SUITE(SqlCompleteTests) { + using ECandidateKind::FunctionName; using ECandidateKind::Keyword; using ECandidateKind::TypeName; @@ -53,6 +54,7 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { TLexerSupplier lexer = MakePureLexerSupplier(); INameService::TPtr names = MakeStaticNameService({ .Types = {"Uint64"}, + .Functions = {"StartsWith"}, }); return MakeSqlCompletionEngine(std::move(lexer), std::move(names)); } @@ -263,27 +265,53 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { Y_UNIT_TEST(Pragma) { TVector<TCandidate> expected = { {Keyword, "ANSI"}, + }; + + auto engine = MakeSqlCompletionEngineUT(); + UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"PRAGMA "}), expected); + } + + Y_UNIT_TEST(Select) { + TVector<TCandidate> expected = { + {Keyword, "ALL"}, + {Keyword, "BITCAST"}, {Keyword, "CALLABLE"}, + {Keyword, "CASE"}, + {Keyword, "CAST"}, + {Keyword, "CURRENT_DATE"}, + {Keyword, "CURRENT_TIME"}, + {Keyword, "CURRENT_TIMESTAMP"}, {Keyword, "DICT"}, + {Keyword, "DISTINCT"}, + {Keyword, "EMPTY_ACTION"}, {Keyword, "ENUM"}, + {Keyword, "EXISTS"}, + {Keyword, "FALSE"}, {Keyword, "FLOW"}, + {Keyword, "JSON_EXISTS"}, + {Keyword, "JSON_QUERY"}, + {Keyword, "JSON_VALUE"}, {Keyword, "LIST"}, + {Keyword, "NOT"}, + {Keyword, "NULL"}, {Keyword, "OPTIONAL"}, {Keyword, "RESOURCE"}, {Keyword, "SET"}, + {Keyword, "STREAM"}, {Keyword, "STRUCT"}, {Keyword, "TAGGED"}, + {Keyword, "TRUE"}, {Keyword, "TUPLE"}, {Keyword, "VARIANT"}, + {FunctionName, "StartsWith"}, }; auto engine = MakeSqlCompletionEngineUT(); - UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"PRAGMA "}), expected); + UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"SELECT "}), expected); } - Y_UNIT_TEST(Select) { + Y_UNIT_TEST(SelectWhere) { TVector<TCandidate> expected = { - {Keyword, "ALL"}, {Keyword, "BITCAST"}, {Keyword, "CALLABLE"}, {Keyword, "CASE"}, @@ -292,7 +320,6 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { {Keyword, "CURRENT_TIME"}, {Keyword, "CURRENT_TIMESTAMP"}, {Keyword, "DICT"}, - {Keyword, "DISTINCT"}, {Keyword, "EMPTY_ACTION"}, {Keyword, "ENUM"}, {Keyword, "EXISTS"}, @@ -313,10 +340,11 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { {Keyword, "TRUE"}, {Keyword, "TUPLE"}, {Keyword, "VARIANT"}, + {FunctionName, "StartsWith"}, }; auto engine = MakeSqlCompletionEngineUT(); - UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"SELECT "}), expected); + UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"SELECT * FROM a WHERE "}), expected); } Y_UNIT_TEST(Upsert) { @@ -362,7 +390,7 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { Y_UNIT_TEST(WordBreak) { auto engine = MakeSqlCompletionEngineUT(); - UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"SELECT ("}).size(), 28); + UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"SELECT ("}).size(), 29); UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"SELECT (1)"}).size(), 30); UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"SELECT 1;"}).size(), 35); } @@ -448,6 +476,7 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { auto engine = MakeSqlCompletionEngine(MakePureLexerSupplier(), std::move(fallback)); UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"SELECT CAST (1 AS U"}).size(), 6); UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"SELECT CAST (1 AS "}).size(), 47); + UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"SELECT "}).size(), 55); } } // Y_UNIT_TEST_SUITE(SqlCompleteTests) diff --git a/yql/essentials/sql/v1/complete/sql_context.h b/yql/essentials/sql/v1/complete/sql_context.h deleted file mode 100644 index 5f370bafe3e..00000000000 --- a/yql/essentials/sql/v1/complete/sql_context.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include "sql_complete.h" - -#include <yql/essentials/sql/v1/lexer/lexer.h> - -#include <util/generic/string.h> - -namespace NSQLComplete { - - struct TCompletionContext { - TVector<TString> Keywords; - bool IsTypeName; - }; - - class ISqlContextInference { - public: - using TPtr = THolder<ISqlContextInference>; - - virtual TCompletionContext Analyze(TCompletionInput input) = 0; - virtual ~ISqlContextInference() = default; - }; - - ISqlContextInference::TPtr MakeSqlContextInference(TLexerSupplier lexer); - -} // namespace NSQLComplete diff --git a/yql/essentials/sql/v1/complete/string_util.h b/yql/essentials/sql/v1/complete/string_util.h index bafc578d82d..f0691764601 100644 --- a/yql/essentials/sql/v1/complete/string_util.h +++ b/yql/essentials/sql/v1/complete/string_util.h @@ -1,17 +1,4 @@ #pragma once -#include <util/charset/unidata.h> - -#include <string_view> - -namespace NSQLComplete { - - static const char WordBreakCharacters[] = " \t\v\f\a\b\r\n`~!@#$%^&*-=+[](){}\\|;:'\".,<>/?"; - - bool IsWordBoundary(char ch); - - size_t LastWordIndex(TStringBuf text); - - TStringBuf LastWord(TStringBuf text); - -} // namespace NSQLComplete +// TODO(YQL-19747): Migrate YDB CLI to yql/essentials/sql/v1/complete/text/word.h +#include <yql/essentials/sql/v1/complete/text/word.h> diff --git a/yql/essentials/sql/v1/complete/sql_syntax.cpp b/yql/essentials/sql/v1/complete/syntax/ansi.cpp index ba5a08d371a..7ca153e44ce 100644 --- a/yql/essentials/sql/v1/complete/sql_syntax.cpp +++ b/yql/essentials/sql/v1/complete/syntax/ansi.cpp @@ -1,4 +1,4 @@ -#include "sql_syntax.h" +#include "ansi.h" #include <yql/essentials/public/issue/yql_issue.h> #include <yql/essentials/sql/settings/translation_settings.h> diff --git a/yql/essentials/sql/v1/complete/sql_syntax.h b/yql/essentials/sql/v1/complete/syntax/ansi.h index f03cbc9fb99..f03cbc9fb99 100644 --- a/yql/essentials/sql/v1/complete/sql_syntax.h +++ b/yql/essentials/sql/v1/complete/syntax/ansi.h diff --git a/yql/essentials/sql/v1/complete/syntax/grammar.cpp b/yql/essentials/sql/v1/complete/syntax/grammar.cpp new file mode 100644 index 00000000000..4274d4bfb44 --- /dev/null +++ b/yql/essentials/sql/v1/complete/syntax/grammar.cpp @@ -0,0 +1,68 @@ +#include "grammar.h" + +#include <yql/essentials/sql/v1/format/sql_format.h> + +namespace NSQLComplete { + + class TSqlGrammar: public ISqlGrammar { + public: + TSqlGrammar() + : Vocabulary(GetVocabularyP()) + , AllTokens(ComputeAllTokens()) + , KeywordTokens(ComputeKeywordTokens()) + { + } + + const antlr4::dfa::Vocabulary& GetVocabulary() const override { + return *Vocabulary; + } + + const std::unordered_set<TTokenId>& GetAllTokens() const override { + return AllTokens; + } + + const std::unordered_set<TTokenId>& GetKeywordTokens() const override { + return KeywordTokens; + } + + private: + static const antlr4::dfa::Vocabulary* GetVocabularyP() { + return &NALADefaultAntlr4::SQLv1Antlr4Parser(nullptr).getVocabulary(); + } + + std::unordered_set<TTokenId> ComputeAllTokens() { + const auto& vocabulary = GetVocabulary(); + + std::unordered_set<TTokenId> allTokens; + + for (size_t type = 1; type <= vocabulary.getMaxTokenType(); ++type) { + allTokens.emplace(type); + } + + return allTokens; + } + + std::unordered_set<TTokenId> ComputeKeywordTokens() { + const auto& vocabulary = GetVocabulary(); + const auto keywords = NSQLFormat::GetKeywords(); + + auto keywordTokens = GetAllTokens(); + std::erase_if(keywordTokens, [&](TTokenId token) { + return !keywords.contains(vocabulary.getSymbolicName(token)); + }); + keywordTokens.erase(TOKEN_EOF); + + return keywordTokens; + } + + const antlr4::dfa::Vocabulary* Vocabulary; + const std::unordered_set<TTokenId> AllTokens; + const std::unordered_set<TTokenId> KeywordTokens; + }; + + const ISqlGrammar& GetSqlGrammar() { + const static TSqlGrammar DefaultSqlGrammar{}; + return DefaultSqlGrammar; + } + +} // namespace NSQLComplete diff --git a/yql/essentials/sql/v1/complete/sql_antlr4.h b/yql/essentials/sql/v1/complete/syntax/grammar.h index 1cf6424cc8e..b6449698ea5 100644 --- a/yql/essentials/sql/v1/complete/sql_antlr4.h +++ b/yql/essentials/sql/v1/complete/syntax/grammar.h @@ -1,29 +1,29 @@ #pragma once -#include <contrib/libs/antlr4_cpp_runtime/src/Token.h> -#include <contrib/libs/antlr4_cpp_runtime/src/Vocabulary.h> +#include <yql/essentials/sql/v1/complete/antlr4/defs.h> -#include <util/generic/vector.h> +#include <contrib/libs/antlr4_cpp_runtime/src/Vocabulary.h> #include <unordered_set> -namespace NSQLComplete { +#ifdef TOKEN_QUERY // Conflict with the winnt.h + #undef TOKEN_QUERY +#endif +#include <yql/essentials/parser/antlr_ast/gen/v1_antlr4/SQLv1Antlr4Parser.h> - using TTokenId = size_t; - using TRuleId = size_t; +#define RULE_(mode, name) NALA##mode##Antlr4::SQLv1Antlr4Parser::Rule##name +#define RULE(name) RULE_(Default, name) - constexpr TTokenId TOKEN_EOF = antlr4::Token::EOF; +namespace NSQLComplete { class ISqlGrammar { public: virtual const antlr4::dfa::Vocabulary& GetVocabulary() const = 0; virtual const std::unordered_set<TTokenId>& GetAllTokens() const = 0; virtual const std::unordered_set<TTokenId>& GetKeywordTokens() const = 0; - virtual const TVector<TRuleId>& GetKeywordRules() const = 0; - virtual const TVector<TRuleId>& GetTypeNameRules() const = 0; virtual ~ISqlGrammar() = default; }; - const ISqlGrammar& GetSqlGrammar(bool isAnsiLexer); + const ISqlGrammar& GetSqlGrammar(); } // namespace NSQLComplete diff --git a/yql/essentials/sql/v1/complete/syntax/grammar_ut.cpp b/yql/essentials/sql/v1/complete/syntax/grammar_ut.cpp new file mode 100644 index 00000000000..50fb6b43054 --- /dev/null +++ b/yql/essentials/sql/v1/complete/syntax/grammar_ut.cpp @@ -0,0 +1,37 @@ +#include <yql/essentials/parser/antlr_ast/gen/v1_antlr4/SQLv1Antlr4Parser.h> +#include <yql/essentials/parser/antlr_ast/gen/v1_ansi_antlr4/SQLv1Antlr4Parser.h> + +#include <library/cpp/testing/unittest/registar.h> + +Y_UNIT_TEST_SUITE(RuleTests) { + THolder<antlr4::Parser> GetDummyParser(bool ansi) { + if (ansi) { + return MakeHolder<NALAAnsiAntlr4::SQLv1Antlr4Parser>(nullptr); + } + return MakeHolder<NALADefaultAntlr4::SQLv1Antlr4Parser>(nullptr); + } + + Y_UNIT_TEST(RuleIndexModeIndependent) { + auto defaultRules = GetDummyParser(/* ansi = */ false)->getRuleIndexMap(); + auto ansiRules = GetDummyParser(/* ansi = */ true)->getRuleIndexMap(); + + UNIT_ASSERT_EQUAL(defaultRules, ansiRules); + } + + Y_UNIT_TEST(TokenTypeModeIndependent) { + auto defaultVocab = GetDummyParser(/* ansi = */ false)->getVocabulary(); + auto ansiVocab = GetDummyParser(/* ansi = */ true)->getVocabulary(); + + UNIT_ASSERT_VALUES_EQUAL(defaultVocab.getMaxTokenType(), ansiVocab.getMaxTokenType()); + + for (size_t type = 0; type <= defaultVocab.getMaxTokenType(); ++type) { + UNIT_ASSERT_VALUES_EQUAL( + defaultVocab.getSymbolicName(type), ansiVocab.getSymbolicName(type)); + UNIT_ASSERT_VALUES_EQUAL( + defaultVocab.getDisplayName(type), ansiVocab.getDisplayName(type)); + UNIT_ASSERT_VALUES_EQUAL( + defaultVocab.getLiteralName(type), ansiVocab.getLiteralName(type)); + } + } + +} // Y_UNIT_TEST_SUITE(RuleTests) diff --git a/yql/essentials/sql/v1/complete/sql_context.cpp b/yql/essentials/sql/v1/complete/syntax/local.cpp index 4cc809479b7..430718a56f1 100644 --- a/yql/essentials/sql/v1/complete/sql_context.cpp +++ b/yql/essentials/sql/v1/complete/syntax/local.cpp @@ -1,7 +1,11 @@ -#include "sql_context.h" +#include "local.h" -#include "c3_engine.h" -#include "sql_syntax.h" +#include "ansi.h" +#include "parser_call_stack.h" +#include "grammar.h" + +#include <yql/essentials/sql/v1/complete/antlr4/c3i.h> +#include <yql/essentials/sql/v1/complete/antlr4/c3t.h> #include <yql/essentials/core/issue/yql_issue.h> @@ -9,7 +13,7 @@ #include <util/stream/output.h> #ifdef TOKEN_QUERY // Conflict with the winnt.h -#undef TOKEN_QUERY + #undef TOKEN_QUERY #endif #include <yql/essentials/parser/antlr_ast/gen/v1_antlr4/SQLv1Antlr4Lexer.h> #include <yql/essentials/parser/antlr_ast/gen/v1_antlr4/SQLv1Antlr4Parser.h> @@ -19,7 +23,7 @@ namespace NSQLComplete { template <bool IsAnsiLexer> - class TSpecializedSqlContextInference: public ISqlContextInference { + class TSpecializedLocalSyntaxAnalysis: public ILocalSyntaxAnalysis { private: using TDefaultYQLGrammar = TAntlrGrammar< NALADefaultAntlr4::SQLv1Antlr4Lexer, @@ -35,14 +39,14 @@ namespace NSQLComplete { TDefaultYQLGrammar>; public: - explicit TSpecializedSqlContextInference(TLexerSupplier lexer) - : Grammar(&GetSqlGrammar(IsAnsiLexer)) + explicit TSpecializedLocalSyntaxAnalysis(TLexerSupplier lexer) + : Grammar(&GetSqlGrammar()) , Lexer_(lexer(/* ansi = */ IsAnsiLexer)) , C3(ComputeC3Config()) { } - TCompletionContext Analyze(TCompletionInput input) override { + TLocalSyntaxContext Analyze(TCompletionInput input) override { TStringBuf prefix; if (!GetC3Prefix(input, &prefix)) { return {}; @@ -52,6 +56,7 @@ namespace NSQLComplete { return { .Keywords = SiftedKeywords(candidates), .IsTypeName = IsTypeNameMatched(candidates), + .IsFunctionName = IsFunctionNameMatched(candidates), }; } @@ -72,17 +77,7 @@ namespace NSQLComplete { } std::unordered_set<TRuleId> ComputePreferredRules() { - const auto& keywordRules = Grammar->GetKeywordRules(); - const auto& typeNameRules = Grammar->GetTypeNameRules(); - - std::unordered_set<TRuleId> preferredRules; - - // Excludes tokens obtained from keyword rules - preferredRules.insert(std::begin(keywordRules), std::end(keywordRules)); - - preferredRules.insert(std::begin(typeNameRules), std::end(typeNameRules)); - - return preferredRules; + return GetC3PreferredRules(); } bool GetC3Prefix(TCompletionInput input, TStringBuf* prefix) { @@ -119,10 +114,15 @@ namespace NSQLComplete { } bool IsTypeNameMatched(const TC3Candidates& candidates) { - const auto& typeNameRules = Grammar->GetTypeNameRules(); - return FindIf(candidates.Rules, [&](const TMatchedRule& rule) { - return Find(typeNameRules, rule.Index) != std::end(typeNameRules); - }) != std::end(candidates.Rules); + return AnyOf(candidates.Rules, [&](const TMatchedRule& rule) { + return IsLikelyTypeStack(rule.ParserCallStack); + }); + } + + bool IsFunctionNameMatched(const TC3Candidates& candidates) { + return AnyOf(candidates.Rules, [&](const TMatchedRule& rule) { + return IsLikelyFunctionStack(rule.ParserCallStack); + }); } const ISqlGrammar* Grammar; @@ -130,34 +130,34 @@ namespace NSQLComplete { TC3Engine<G> C3; }; - class TSqlContextInference: public ISqlContextInference { + class TLocalSyntaxAnalysis: public ILocalSyntaxAnalysis { public: - explicit TSqlContextInference(TLexerSupplier lexer) + explicit TLocalSyntaxAnalysis(TLexerSupplier lexer) : DefaultEngine(lexer) , AnsiEngine(lexer) { } - TCompletionContext Analyze(TCompletionInput input) override { + TLocalSyntaxContext Analyze(TCompletionInput input) override { auto isAnsiLexer = IsAnsiQuery(TString(input.Text)); auto& engine = GetSpecializedEngine(isAnsiLexer); return engine.Analyze(std::move(input)); } private: - ISqlContextInference& GetSpecializedEngine(bool isAnsiLexer) { + ILocalSyntaxAnalysis& GetSpecializedEngine(bool isAnsiLexer) { if (isAnsiLexer) { return AnsiEngine; } return DefaultEngine; } - TSpecializedSqlContextInference</* IsAnsiLexer = */ false> DefaultEngine; - TSpecializedSqlContextInference</* IsAnsiLexer = */ true> AnsiEngine; + TSpecializedLocalSyntaxAnalysis</* IsAnsiLexer = */ false> DefaultEngine; + TSpecializedLocalSyntaxAnalysis</* IsAnsiLexer = */ true> AnsiEngine; }; - ISqlContextInference::TPtr MakeSqlContextInference(TLexerSupplier lexer) { - return TSqlContextInference::TPtr(new TSqlContextInference(lexer)); + ILocalSyntaxAnalysis::TPtr MakeLocalSyntaxAnalysis(TLexerSupplier lexer) { + return TLocalSyntaxAnalysis::TPtr(new TLocalSyntaxAnalysis(lexer)); } } // namespace NSQLComplete diff --git a/yql/essentials/sql/v1/complete/syntax/local.h b/yql/essentials/sql/v1/complete/syntax/local.h new file mode 100644 index 00000000000..79984d00e2b --- /dev/null +++ b/yql/essentials/sql/v1/complete/syntax/local.h @@ -0,0 +1,28 @@ +#pragma once + +#include <yql/essentials/sql/v1/complete/sql_complete.h> + +#include <yql/essentials/sql/v1/lexer/lexer.h> + +#include <util/generic/string.h> +#include <util/generic/vector.h> + +namespace NSQLComplete { + + struct TLocalSyntaxContext { + TVector<TString> Keywords; + bool IsTypeName; + bool IsFunctionName; + }; + + class ILocalSyntaxAnalysis { + public: + using TPtr = THolder<ILocalSyntaxAnalysis>; + + virtual TLocalSyntaxContext Analyze(TCompletionInput input) = 0; + virtual ~ILocalSyntaxAnalysis() = default; + }; + + ILocalSyntaxAnalysis::TPtr MakeLocalSyntaxAnalysis(TLexerSupplier lexer); + +} // namespace NSQLComplete diff --git a/yql/essentials/sql/v1/complete/syntax/parser_call_stack.cpp b/yql/essentials/sql/v1/complete/syntax/parser_call_stack.cpp new file mode 100644 index 00000000000..855d9af1601 --- /dev/null +++ b/yql/essentials/sql/v1/complete/syntax/parser_call_stack.cpp @@ -0,0 +1,65 @@ +#include "parser_call_stack.h" + +#include "grammar.h" + +#include <util/generic/vector.h> +#include <util/generic/algorithm.h> +#include <util/generic/yexception.h> + +namespace NSQLComplete { + + const TVector<TRuleId> KeywordRules = { + RULE(Keyword), + RULE(Keyword_expr_uncompat), + RULE(Keyword_table_uncompat), + RULE(Keyword_select_uncompat), + RULE(Keyword_alter_uncompat), + RULE(Keyword_in_uncompat), + RULE(Keyword_window_uncompat), + RULE(Keyword_hint_uncompat), + RULE(Keyword_as_compat), + RULE(Keyword_compat), + }; + + const TVector<TRuleId> TypeNameRules = { + RULE(Type_name_simple), + }; + + const TVector<TRuleId> FunctionNameRules = { + RULE(Id_expr), + RULE(An_id_or_type), + RULE(Id_or_type), + }; + + bool EndsWith(const TParserCallStack& suffix, const TParserCallStack& stack) { + if (stack.size() < suffix.size()) { + return false; + } + const size_t prefixSize = stack.size() - suffix.size(); + return Equal(std::begin(stack) + prefixSize, std::end(stack), std::begin(suffix)); + } + + bool ContainsRule(TRuleId rule, const TParserCallStack& stack) { + return Find(stack, rule) != std::end(stack); + } + + bool IsLikelyTypeStack(const TParserCallStack& stack) { + return EndsWith({RULE(Type_name_simple)}, stack); + } + + bool IsLikelyFunctionStack(const TParserCallStack& stack) { + return EndsWith({RULE(Unary_casual_subexpr), RULE(Id_expr)}, stack) || + EndsWith({RULE(Unary_casual_subexpr), + RULE(Atom_expr), + RULE(An_id_or_type)}, stack); + } + + std::unordered_set<TRuleId> GetC3PreferredRules() { + std::unordered_set<TRuleId> preferredRules; + preferredRules.insert(std::begin(KeywordRules), std::end(KeywordRules)); + preferredRules.insert(std::begin(TypeNameRules), std::end(TypeNameRules)); + preferredRules.insert(std::begin(FunctionNameRules), std::end(FunctionNameRules)); + return preferredRules; + } + +} // namespace NSQLComplete diff --git a/yql/essentials/sql/v1/complete/syntax/parser_call_stack.h b/yql/essentials/sql/v1/complete/syntax/parser_call_stack.h new file mode 100644 index 00000000000..756586988db --- /dev/null +++ b/yql/essentials/sql/v1/complete/syntax/parser_call_stack.h @@ -0,0 +1,13 @@ +#pragma once + +#include <yql/essentials/sql/v1/complete/antlr4/defs.h> + +namespace NSQLComplete { + + bool IsLikelyTypeStack(const TParserCallStack& stack); + + bool IsLikelyFunctionStack(const TParserCallStack& stack); + + std::unordered_set<TRuleId> GetC3PreferredRules(); + +} // namespace NSQLComplete diff --git a/yql/essentials/sql/v1/complete/syntax/ut/ya.make b/yql/essentials/sql/v1/complete/syntax/ut/ya.make new file mode 100644 index 00000000000..e070185af9f --- /dev/null +++ b/yql/essentials/sql/v1/complete/syntax/ut/ya.make @@ -0,0 +1,7 @@ +UNITTEST_FOR(yql/essentials/sql/v1/complete/syntax) + +SRCS( + grammar_ut.cpp +) + +END() diff --git a/yql/essentials/sql/v1/complete/syntax/ya.make b/yql/essentials/sql/v1/complete/syntax/ya.make new file mode 100644 index 00000000000..a3fe973e315 --- /dev/null +++ b/yql/essentials/sql/v1/complete/syntax/ya.make @@ -0,0 +1,31 @@ +LIBRARY() + +SRCS( + ansi.cpp + grammar.cpp + local.cpp + parser_call_stack.cpp +) + +ADDINCL( + yql/essentials/sql/v1/complete +) + +PEERDIR( + yql/essentials/core/issue + + yql/essentials/parser/antlr_ast/gen/v1_ansi_antlr4 + yql/essentials/parser/antlr_ast/gen/v1_antlr4 + + yql/essentials/sql/settings + yql/essentials/sql/v1/lexer + + # TODO(YQL-19747): Replace with the sql/v1/reflect to get keywords + yql/essentials/sql/v1/format +) + +END() + +RECURSE_FOR_TESTS( + ut +) diff --git a/yql/essentials/sql/v1/complete/text/ut/ya.make b/yql/essentials/sql/v1/complete/text/ut/ya.make new file mode 100644 index 00000000000..3c023ccfb47 --- /dev/null +++ b/yql/essentials/sql/v1/complete/text/ut/ya.make @@ -0,0 +1,7 @@ +UNITTEST_FOR(yql/essentials/sql/v1/complete/text) + +SRCS( + word_ut.cpp +) + +END() diff --git a/yql/essentials/sql/v1/complete/string_util.cpp b/yql/essentials/sql/v1/complete/text/word.cpp index 12a67010655..0468f62b031 100644 --- a/yql/essentials/sql/v1/complete/string_util.cpp +++ b/yql/essentials/sql/v1/complete/text/word.cpp @@ -1,4 +1,4 @@ -#include "string_util.h" +#include "word.h" #include <util/generic/strbuf.h> diff --git a/yql/essentials/sql/v1/complete/text/word.h b/yql/essentials/sql/v1/complete/text/word.h new file mode 100644 index 00000000000..e56f023940f --- /dev/null +++ b/yql/essentials/sql/v1/complete/text/word.h @@ -0,0 +1,15 @@ +#pragma once + +#include <util/charset/unidata.h> + +namespace NSQLComplete { + + static const char WordBreakCharacters[] = " \t\v\f\a\b\r\n`~!@#$%^&*-=+[](){}\\|;:'\".,<>/?"; + + bool IsWordBoundary(char ch); + + size_t LastWordIndex(TStringBuf text); + + TStringBuf LastWord(TStringBuf text); + +} // namespace NSQLComplete diff --git a/yql/essentials/sql/v1/complete/string_util_ut.cpp b/yql/essentials/sql/v1/complete/text/word_ut.cpp index ca3ed546a38..0eff931b1af 100644 --- a/yql/essentials/sql/v1/complete/string_util_ut.cpp +++ b/yql/essentials/sql/v1/complete/text/word_ut.cpp @@ -1,10 +1,10 @@ -#include "string_util.h" +#include "word.h" #include <library/cpp/testing/unittest/registar.h> using namespace NSQLComplete; -Y_UNIT_TEST_SUITE(StringUtilTest) { +Y_UNIT_TEST_SUITE(WordTest) { Y_UNIT_TEST(Blank) { UNIT_ASSERT_VALUES_EQUAL(LastWord(""), ""); UNIT_ASSERT_VALUES_EQUAL(LastWord(" "), ""); @@ -18,4 +18,4 @@ Y_UNIT_TEST_SUITE(StringUtilTest) { UNIT_ASSERT_VALUES_EQUAL(LastWord("two"), "two"); UNIT_ASSERT_VALUES_EQUAL(LastWord("one two"), "two"); } -} // Y_UNIT_TEST_SUITE(StringUtilTest) +} // Y_UNIT_TEST_SUITE(WordTest) diff --git a/yql/essentials/sql/v1/complete/text/ya.make b/yql/essentials/sql/v1/complete/text/ya.make new file mode 100644 index 00000000000..030e69172ab --- /dev/null +++ b/yql/essentials/sql/v1/complete/text/ya.make @@ -0,0 +1,11 @@ +LIBRARY() + +SRCS( + word.cpp +) + +END() + +RECURSE_FOR_TESTS( + ut +) diff --git a/yql/essentials/sql/v1/complete/ut/ya.make b/yql/essentials/sql/v1/complete/ut/ya.make index 7b1cde8bfb3..0a5d13dec46 100644 --- a/yql/essentials/sql/v1/complete/ut/ya.make +++ b/yql/essentials/sql/v1/complete/ut/ya.make @@ -2,7 +2,6 @@ UNITTEST_FOR(yql/essentials/sql/v1/complete) SRCS( sql_complete_ut.cpp - string_util_ut.cpp ) PEERDIR( diff --git a/yql/essentials/sql/v1/complete/ya.make b/yql/essentials/sql/v1/complete/ya.make index b401bcb3fa8..141b5c471d7 100644 --- a/yql/essentials/sql/v1/complete/ya.make +++ b/yql/essentials/sql/v1/complete/ya.make @@ -1,30 +1,21 @@ LIBRARY() SRCS( - sql_antlr4.cpp sql_complete.cpp - sql_context.cpp - sql_syntax.cpp - string_util.cpp ) PEERDIR( - contrib/libs/antlr4_cpp_runtime - contrib/libs/antlr4-c3 - yql/essentials/core/issue - yql/essentials/sql/settings - yql/essentials/sql/v1/format yql/essentials/sql/v1/lexer # FIXME(YQL-19747): unwanted dependency on a lexer implementation yql/essentials/sql/v1/lexer/antlr4_pure yql/essentials/sql/v1/lexer/antlr4_pure_ansi - yql/essentials/parser/antlr_ast/gen/v1_ansi_antlr4 - yql/essentials/parser/antlr_ast/gen/v1_antlr4 - + yql/essentials/sql/v1/complete/antlr4 yql/essentials/sql/v1/complete/name yql/essentials/sql/v1/complete/name/static + yql/essentials/sql/v1/complete/syntax + yql/essentials/sql/v1/complete/text ) END() |
