//===----------------------------------------------------------------------===// // DuckDB // // matcher.hpp // // //===----------------------------------------------------------------------===// #pragma once #include "duckdb/common/string_util.hpp" #include "duckdb/common/vector.hpp" #include "duckdb/common/reference_map.hpp" #include "transformer/parse_result.hpp" namespace duckdb { class ParseResultAllocator; class Matcher; class MatcherAllocator; enum class SuggestionState : uint8_t { SUGGEST_KEYWORD, SUGGEST_CATALOG_NAME, SUGGEST_SCHEMA_NAME, SUGGEST_TABLE_NAME, SUGGEST_TYPE_NAME, SUGGEST_COLUMN_NAME, SUGGEST_FILE_NAME, SUGGEST_VARIABLE, SUGGEST_SCALAR_FUNCTION_NAME, SUGGEST_TABLE_FUNCTION_NAME, SUGGEST_PRAGMA_NAME, SUGGEST_SETTING_NAME, SUGGEST_RESERVED_VARIABLE }; enum class CandidateType { KEYWORD, IDENTIFIER, LITERAL }; struct AutoCompleteCandidate { // NOLINTNEXTLINE: allow implicit conversion from string AutoCompleteCandidate(string candidate_p, int32_t score_bonus = 0, CandidateType candidate_type = CandidateType::IDENTIFIER) : candidate(std::move(candidate_p)), score_bonus(score_bonus), candidate_type(candidate_type) { } // NOLINTNEXTLINE: allow implicit conversion from const char* AutoCompleteCandidate(const char *candidate_p, int32_t score_bonus = 0, CandidateType candidate_type = CandidateType::IDENTIFIER) : AutoCompleteCandidate(string(candidate_p), score_bonus, candidate_type) { } string candidate; //! The higher the score bonus, the more likely this candidate will be chosen int32_t score_bonus; //! The type of candidate we are suggesting - this modifies how we handle quoting/case sensitivity CandidateType candidate_type; //! Extra char to push at the back char extra_char = '\0'; //! Suggestion position idx_t suggestion_pos = 0; }; struct AutoCompleteSuggestion { AutoCompleteSuggestion(string text_p, idx_t pos) : text(std::move(text_p)), pos(pos) { } string text; idx_t pos; }; enum class MatchResultType { SUCCESS, FAIL }; enum class SuggestionType { OPTIONAL, MANDATORY }; enum class TokenType { WORD }; struct MatcherToken { // NOLINTNEXTLINE: allow implicit conversion from text MatcherToken(string text_p, idx_t offset_p) : text(std::move(text_p)), offset(offset_p) { length = text.length(); } TokenType type = TokenType::WORD; string text; idx_t offset = 0; idx_t length = 0; }; struct MatcherSuggestion { // NOLINTNEXTLINE: allow implicit conversion from auto-complete candidate MatcherSuggestion(AutoCompleteCandidate keyword_p) : keyword(std::move(keyword_p)), type(SuggestionState::SUGGEST_KEYWORD) { } // NOLINTNEXTLINE: allow implicit conversion from suggestion state MatcherSuggestion(SuggestionState type, char extra_char = '\0') : keyword(""), type(type), extra_char(extra_char) { } //! Literal suggestion AutoCompleteCandidate keyword; SuggestionState type; char extra_char = '\0'; }; struct MatchState { MatchState(vector &tokens, vector &suggestions, ParseResultAllocator &allocator) : tokens(tokens), suggestions(suggestions), token_index(0), allocator(allocator) { } MatchState(MatchState &state) : tokens(state.tokens), suggestions(state.suggestions), token_index(state.token_index), allocator(state.allocator) { } vector &tokens; vector &suggestions; reference_set_t added_suggestions; idx_t token_index; ParseResultAllocator &allocator; void AddSuggestion(MatcherSuggestion suggestion); }; enum class MatcherType { KEYWORD, LIST, OPTIONAL, CHOICE, REPEAT, VARIABLE, STRING_LITERAL, NUMBER_LITERAL, OPERATOR }; class Matcher { public: explicit Matcher(MatcherType type) : type(type) { } virtual ~Matcher() = default; //! Match virtual MatchResultType Match(MatchState &state) const = 0; virtual optional_ptr MatchParseResult(MatchState &state) const = 0; virtual SuggestionType AddSuggestion(MatchState &state) const; virtual SuggestionType AddSuggestionInternal(MatchState &state) const = 0; virtual string ToString() const = 0; void Print() const; static Matcher &RootMatcher(MatcherAllocator &allocator); MatcherType Type() const { return type; } void SetName(string name_p) { name = std::move(name_p); } string GetName() const; public: template TARGET &Cast() { if (type != TARGET::TYPE) { throw InternalException("Failed to cast matcher to type - matcher type mismatch"); } return reinterpret_cast(*this); } template const TARGET &Cast() const { if (type != TARGET::TYPE) { throw InternalException("Failed to cast matcher to type - matcher type mismatch"); } return reinterpret_cast(*this); } protected: MatcherType type; string name; }; class MatcherAllocator { public: Matcher &Allocate(unique_ptr matcher); private: vector> matchers; }; class ParseResultAllocator { public: optional_ptr Allocate(unique_ptr parse_result); private: vector> parse_results; }; } // namespace duckdb