12#include "clang/ASTMatchers/Dynamic/Parser.h"
13#include "clang/Basic/CharInfo.h"
14#include "llvm/ADT/StringRef.h"
15#include "llvm/ADT/StringSwitch.h"
20using namespace clang::ast_matchers::dynamic;
29StringRef QueryParser::lexWord() {
31 Line = Line.ltrim(
" \t\v\f\r");
40 if (Line.front() ==
'#')
41 Word = Line.substr(0, 1);
43 Word = Line.take_until(isWhitespace);
45 Line = Line.drop_front(
Word.size());
67 if (
P->CompletionPos &&
P->CompletionPos <=
Word.data() +
Word.size()) {
68 if (
P->CompletionPos <
Word.data())
76 bool IsCompletion =
true) {
79 Switch.Case(CaseStr, Value);
80 else if (CaseStr.size() != 0 && IsCompletion &&
WordCompletionPos <= CaseStr.size() &&
83 P->Completions.push_back(LineEditor::Completion(
85 std::string(CaseStr)));
94 unsigned Value = LexOrCompleteWord<unsigned>(
this, ValStr)
99 return new InvalidQuery(
"expected 'true' or 'false', got '" + ValStr +
"'");
101 return new SetQuery<bool>(Var, Value);
104template <
typename QueryType>
QueryRef QueryParser::parseSetOutputKind() {
106 unsigned OutKind = LexOrCompleteWord<unsigned>(
this, ValStr)
112 if (OutKind == ~0u) {
113 return new InvalidQuery(
"expected 'diag', 'print', 'detailed-ast' or "
127 llvm_unreachable(
"Invalid output kind");
130QueryRef QueryParser::parseSetTraversalKind(TraversalKind QuerySession::*Var) {
133 LexOrCompleteWord<unsigned>(
this, ValStr)
134 .Case(
"AsIs", TK_AsIs)
135 .Case(
"IgnoreUnlessSpelledInSource", TK_IgnoreUnlessSpelledInSource)
138 return new InvalidQuery(
"expected traversal kind, got '" + ValStr +
"'");
140 return new SetQuery<TraversalKind>(Var,
static_cast<TraversalKind
>(Value));
144 StringRef Extra = Line;
145 StringRef ExtraTrimmed = Extra.ltrim(
" \t\v\f\r");
147 if (ExtraTrimmed.starts_with(
'\n') || ExtraTrimmed.starts_with(
"\r\n"))
148 Q->RemainingContent = Extra;
150 StringRef TrailingWord = lexWord();
151 if (TrailingWord.starts_with(
'#')) {
152 Line = Line.drop_until([](
char c) {
return c ==
'\n'; });
153 Line = Line.drop_while([](
char c) {
return c ==
'\n'; });
156 if (!TrailingWord.empty()) {
157 return new InvalidQuery(
"unexpected extra input: '" + Extra +
"'");
165enum ParsedQueryKind {
180enum ParsedQueryVariable {
190 llvm::raw_string_ostream
OS(ErrStr);
191 Diag.printToStreamFull(
OS);
192 return new InvalidQuery(
OS.str());
197QueryRef QueryParser::completeMatcherExpression() {
198 std::vector<MatcherCompletion> Comps = Parser::completeExpression(
199 Line, CompletionPos - Line.begin(),
nullptr, &QS.
NamedValues);
200 for (
auto I = Comps.begin(),
E = Comps.end(); I !=
E; ++I) {
201 Completions.push_back(LineEditor::Completion(I->TypedText, I->MatcherDecl));
207 StringRef CommandStr;
208 ParsedQueryKind QKind = LexOrCompleteWord<ParsedQueryKind>(
this, CommandStr)
210 .Case(
"#", PQK_Comment,
false)
211 .Case(
"help", PQK_Help)
212 .Case(
"l", PQK_Let,
false)
213 .Case(
"let", PQK_Let)
214 .Case(
"m", PQK_Match,
false)
215 .Case(
"match", PQK_Match)
216 .Case(
"q", PQK_Quit,
false)
217 .Case(
"quit", PQK_Quit)
218 .Case(
"set", PQK_Set)
219 .Case(
"enable", PQK_Enable)
220 .Case(
"disable", PQK_Disable)
221 .Case(
"unlet", PQK_Unlet)
222 .Case(
"f", PQK_File,
false)
223 .Case(
"file", PQK_File)
224 .Default(PQK_Invalid);
229 Line = Line.drop_until([](
char c) {
return c ==
'\n'; });
230 Line = Line.drop_while([](
char c) {
return c ==
'\n'; });
232 return new NoOpQuery;
236 return endQuery(
new HelpQuery);
239 return endQuery(
new QuitQuery);
242 StringRef
Name = lexWord();
245 return new InvalidQuery(
"expected variable name");
248 return completeMatcherExpression();
251 ast_matchers::dynamic::VariantValue Value;
252 if (!Parser::parseExpression(Line,
nullptr, &QS.
NamedValues, &Value,
254 return makeInvalidQueryFromDiagnostics(Diag);
257 auto *Q =
new LetQuery(
Name, Value);
258 Q->RemainingContent = Line;
264 return completeMatcherExpression();
267 auto MatcherSource = Line.ltrim();
268 auto OrigMatcherSource = MatcherSource;
269 std::optional<DynTypedMatcher> Matcher = Parser::parseMatcherExpression(
272 return makeInvalidQueryFromDiagnostics(Diag);
274 auto ActualSource = OrigMatcherSource.slice(0, OrigMatcherSource.size() -
275 MatcherSource.size());
276 auto *Q =
new MatchQuery(ActualSource, *Matcher);
277 Q->RemainingContent = MatcherSource;
283 ParsedQueryVariable Var =
284 LexOrCompleteWord<ParsedQueryVariable>(
this, VarStr)
285 .Case(
"output", PQV_Output)
286 .Case(
"bind-root", PQV_BindRoot)
287 .Case(
"print-matcher", PQV_PrintMatcher)
288 .Case(
"traversal", PQV_Traversal)
289 .Default(PQV_Invalid);
291 return new InvalidQuery(
"expected variable name");
292 if (Var == PQV_Invalid)
293 return new InvalidQuery(
"unknown variable: '" + VarStr +
"'");
298 Q = parseSetOutputKind<SetExclusiveOutputQuery>();
303 case PQV_PrintMatcher:
310 llvm_unreachable(
"Invalid query kind");
318 ParsedQueryVariable Var =
319 LexOrCompleteWord<ParsedQueryVariable>(
this, VarStr)
320 .Case(
"output", PQV_Output)
321 .Default(PQV_Invalid);
323 return new InvalidQuery(
"expected variable name");
324 if (Var == PQV_Invalid)
325 return new InvalidQuery(
"unknown variable: '" + VarStr +
"'");
329 if (QKind == PQK_Enable)
330 Q = parseSetOutputKind<EnableOutputQuery>();
331 else if (QKind == PQK_Disable)
332 Q = parseSetOutputKind<DisableOutputQuery>();
334 llvm_unreachable(
"Invalid query kind");
339 StringRef
Name = lexWord();
342 return new InvalidQuery(
"expected variable name");
344 return endQuery(
new LetQuery(
Name, VariantValue()));
348 return new FileQuery(Line);
351 return new InvalidQuery(
"unknown command: " + CommandStr);
354 llvm_unreachable(
"Invalid query kind");
361std::vector<LineEditor::Completion>
364 P.CompletionPos =
Line.data() +
Pos;
367 return P.Completions;
llvm::SmallString< 256U > Name
WantDiagnostics Diagnostics
llvm::raw_string_ostream OS
static QueryRef parse(StringRef Line, const QuerySession &QS)
Parse Line as a query.
static std::vector< llvm::LineEditor::Completion > complete(StringRef Line, size_t Pos, const QuerySession &QS)
Compute a list of completions for Line assuming a cursor at.
Represents the state for a particular clang-query session.
llvm::StringMap< ast_matchers::dynamic::VariantValue > NamedValues
llvm::IntrusiveRefCntPtr< Query > QueryRef
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Some operations such as code completion produce a set of candidates.
Any query which resulted in a parse error. The error message is in ErrStr.
LexOrCompleteWord & Case(llvm::StringLiteral CaseStr, const T &Value, bool IsCompletion=true)
LexOrCompleteWord(QueryParser *P, StringRef &OutWord)