summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvityaman <[email protected]>2025-03-28 22:01:21 +0300
committerrobot-piglet <[email protected]>2025-03-28 22:36:16 +0300
commitb60cb8f5ce78ae5f63304a534278e124d31398b0 (patch)
tree033d726f561f37e4e258460159b3b379aa9c70f6
parentdf00f0d151a43de80f6e41291d9267afbbfb18a4 (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
-rw-r--r--yql/essentials/sql/v1/complete/antlr4/c3i.h41
-rw-r--r--yql/essentials/sql/v1/complete/antlr4/c3t.h (renamed from yql/essentials/sql/v1/complete/c3_engine.h)58
-rw-r--r--yql/essentials/sql/v1/complete/antlr4/defs.h18
-rw-r--r--yql/essentials/sql/v1/complete/antlr4/ya.make9
-rw-r--r--yql/essentials/sql/v1/complete/name/name_service.h10
-rw-r--r--yql/essentials/sql/v1/complete/name/static/default_name_set.cpp27
-rw-r--r--yql/essentials/sql/v1/complete/name/static/name_service.cpp13
-rw-r--r--yql/essentials/sql/v1/complete/name/static/name_service.h1
-rw-r--r--yql/essentials/sql/v1/complete/sql_antlr4.cpp126
-rw-r--r--yql/essentials/sql/v1/complete/sql_complete.cpp30
-rw-r--r--yql/essentials/sql/v1/complete/sql_complete.h1
-rw-r--r--yql/essentials/sql/v1/complete/sql_complete_ut.cpp41
-rw-r--r--yql/essentials/sql/v1/complete/sql_context.h26
-rw-r--r--yql/essentials/sql/v1/complete/string_util.h17
-rw-r--r--yql/essentials/sql/v1/complete/syntax/ansi.cpp (renamed from yql/essentials/sql/v1/complete/sql_syntax.cpp)2
-rw-r--r--yql/essentials/sql/v1/complete/syntax/ansi.h (renamed from yql/essentials/sql/v1/complete/sql_syntax.h)0
-rw-r--r--yql/essentials/sql/v1/complete/syntax/grammar.cpp68
-rw-r--r--yql/essentials/sql/v1/complete/syntax/grammar.h (renamed from yql/essentials/sql/v1/complete/sql_antlr4.h)20
-rw-r--r--yql/essentials/sql/v1/complete/syntax/grammar_ut.cpp37
-rw-r--r--yql/essentials/sql/v1/complete/syntax/local.cpp (renamed from yql/essentials/sql/v1/complete/sql_context.cpp)62
-rw-r--r--yql/essentials/sql/v1/complete/syntax/local.h28
-rw-r--r--yql/essentials/sql/v1/complete/syntax/parser_call_stack.cpp65
-rw-r--r--yql/essentials/sql/v1/complete/syntax/parser_call_stack.h13
-rw-r--r--yql/essentials/sql/v1/complete/syntax/ut/ya.make7
-rw-r--r--yql/essentials/sql/v1/complete/syntax/ya.make31
-rw-r--r--yql/essentials/sql/v1/complete/text/ut/ya.make7
-rw-r--r--yql/essentials/sql/v1/complete/text/word.cpp (renamed from yql/essentials/sql/v1/complete/string_util.cpp)2
-rw-r--r--yql/essentials/sql/v1/complete/text/word.h15
-rw-r--r--yql/essentials/sql/v1/complete/text/word_ut.cpp (renamed from yql/essentials/sql/v1/complete/string_util_ut.cpp)6
-rw-r--r--yql/essentials/sql/v1/complete/text/ya.make11
-rw-r--r--yql/essentials/sql/v1/complete/ut/ya.make1
-rw-r--r--yql/essentials/sql/v1/complete/ya.make15
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()