aboutsummaryrefslogtreecommitdiffstats
path: root/yql/essentials/sql/v1/complete/syntax/cursor_token_context.cpp
diff options
context:
space:
mode:
authorvityaman <vityaman.dev@yandex.ru>2025-05-06 15:49:02 +0300
committerrobot-piglet <robot-piglet@yandex-team.com>2025-05-06 16:04:08 +0300
commit9c3fdca51d8ae892c5ad8f6ef92df73fafc09e28 (patch)
tree561c599fae4ea29b537a6958b65e1b052548edf2 /yql/essentials/sql/v1/complete/syntax/cursor_token_context.cpp
parentc131e959456f9f9a4adada5623ce3bae4097a8c1 (diff)
downloadydb-9c3fdca51d8ae892c5ad8f6ef92df73fafc09e28.tar.gz
YQL-19747 Complete folder, table and cluster names
--- - Related to `YQL-19747` - On top of https://github.com/ytsaurus/ytsaurus/pull/1253 - Related to https://github.com/ydb-platform/ydb/issues/9056 - Related to https://github.com/vityaman/ydb/issues/14 - Related to https://github.com/vityaman/ydb/issues/35 - Related to https://github.com/vityaman/ydb/issues/40 --- Pull Request resolved: https://github.com/ytsaurus/ytsaurus/pull/1257 commit_hash:0b842abb27184c88b8177beeea29fb1ea86b7a04
Diffstat (limited to 'yql/essentials/sql/v1/complete/syntax/cursor_token_context.cpp')
-rw-r--r--yql/essentials/sql/v1/complete/syntax/cursor_token_context.cpp160
1 files changed, 160 insertions, 0 deletions
diff --git a/yql/essentials/sql/v1/complete/syntax/cursor_token_context.cpp b/yql/essentials/sql/v1/complete/syntax/cursor_token_context.cpp
new file mode 100644
index 00000000000..33aef36847a
--- /dev/null
+++ b/yql/essentials/sql/v1/complete/syntax/cursor_token_context.cpp
@@ -0,0 +1,160 @@
+#include "cursor_token_context.h"
+
+#include <yql/essentials/core/issue/yql_issue.h>
+#include <yql/essentials/sql/v1/lexer/lexer.h>
+
+namespace NSQLComplete {
+
+ namespace {
+
+ bool Tokenize(ILexer::TPtr& lexer, TCompletionInput input, TParsedTokenList& tokens) {
+ NYql::TIssues issues;
+ if (!NSQLTranslation::Tokenize(
+ *lexer, TString(input.Text), /* queryName = */ "",
+ tokens, issues, /* maxErrors = */ 1)) {
+ return false;
+ }
+ return true;
+ }
+
+ TCursor GetCursor(const TParsedTokenList& tokens, size_t cursorPosition) {
+ size_t current = 0;
+ for (size_t i = 0; i < tokens.size() && current < cursorPosition; ++i) {
+ const auto& content = tokens[i].Content;
+
+ current += content.size();
+ if (current < cursorPosition) {
+ continue;
+ }
+
+ TCursor cursor = {
+ .PrevTokenIndex = i,
+ .NextTokenIndex = i,
+ .Position = cursorPosition,
+ };
+
+ if (current == cursorPosition) {
+ cursor.NextTokenIndex += 1;
+ }
+
+ return cursor;
+ }
+
+ return {
+ .PrevTokenIndex = Nothing(),
+ .NextTokenIndex = 0,
+ .Position = cursorPosition,
+ };
+ }
+
+ TVector<size_t> GetTokenPositions(const TParsedTokenList& tokens) {
+ TVector<size_t> positions;
+ positions.reserve(tokens.size());
+ size_t pos = 0;
+ for (const auto& token : tokens) {
+ positions.emplace_back(pos);
+ pos += token.Content.size();
+ }
+ return positions;
+ }
+
+ } // namespace
+
+ bool TRichParsedToken::IsLiteral() const {
+ return Base->Name == "STRING_VALUE" ||
+ Base->Name == "DIGIGTS" ||
+ Base->Name == "INTEGER_VALUE" ||
+ Base->Name == "REAL";
+ }
+
+ TRichParsedToken TokenAt(const TCursorTokenContext& context, size_t index) {
+ return {
+ .Base = &context.Tokens.at(index),
+ .Index = index,
+ .Position = context.TokenPositions.at(index),
+ };
+ }
+
+ TMaybe<TRichParsedToken> TCursorTokenContext::Enclosing() const {
+ if (Tokens.size() == 1) {
+ Y_ENSURE(Tokens[0].Name == "EOF");
+ return Nothing();
+ }
+
+ if (Cursor.PrevTokenIndex.Empty()) {
+ return Nothing();
+ }
+
+ auto token = TokenAt(*this, *Cursor.PrevTokenIndex);
+ if (Cursor.PrevTokenIndex == Cursor.NextTokenIndex ||
+ !IsWordBoundary(token.Base->Content.back())) {
+ return token;
+ }
+
+ return Nothing();
+ }
+
+ TMaybe<TRichParsedToken> TCursorTokenContext::MatchCursorPrefix(const TVector<TStringBuf>& pattern) const {
+ const auto prefix = std::span{Tokens.begin(), Cursor.NextTokenIndex};
+ if (prefix.size() < pattern.size()) {
+ return Nothing();
+ }
+
+ ssize_t i = static_cast<ssize_t>(prefix.size()) - 1;
+ ssize_t j = static_cast<ssize_t>(pattern.size()) - 1;
+ for (; 0 <= j; --i, --j) {
+ if (!pattern[j].empty() && prefix[i].Name != pattern[j]) {
+ return Nothing();
+ }
+ }
+ return TokenAt(*this, prefix.size() - pattern.size());
+ }
+
+ bool GetStatement(
+ ILexer::TPtr& lexer,
+ TCompletionInput input,
+ TCompletionInput& output,
+ size_t& output_position) {
+ TVector<TString> statements;
+ NYql::TIssues issues;
+ if (!NSQLTranslationV1::SplitQueryToStatements(
+ TString(input.Text) + ";", lexer,
+ statements, issues, /* file = */ "",
+ /* areBlankSkipped = */ false)) {
+ return false;
+ }
+
+ size_t& cursor = output_position;
+ cursor = 0;
+ for (const auto& statement : statements) {
+ if (input.CursorPosition < cursor + statement.size()) {
+ output = {
+ .Text = input.Text.SubStr(cursor, statement.size()),
+ .CursorPosition = input.CursorPosition - cursor,
+ };
+ return true;
+ }
+ cursor += statement.size();
+ }
+
+ output = input;
+ return true;
+ }
+
+ bool GetCursorTokenContext(ILexer::TPtr& lexer, TCompletionInput input, TCursorTokenContext& context) {
+ TParsedTokenList tokens;
+ if (!Tokenize(lexer, input, tokens)) {
+ return false;
+ }
+
+ TVector<size_t> positions = GetTokenPositions(tokens);
+ TCursor cursor = GetCursor(tokens, input.CursorPosition);
+ context = {
+ .Tokens = std::move(tokens),
+ .TokenPositions = std::move(positions),
+ .Cursor = cursor,
+ };
+ return true;
+ }
+
+} // namespace NSQLComplete