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())
69 WordCompletionPos = 0;
71 WordCompletionPos = 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");
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 {
189QueryRef makeInvalidQueryFromDiagnostics(
const Diagnostics &Diag) {
191 llvm::raw_string_ostream OS(ErrStr);
192 Diag.printToStreamFull(OS);
198QueryRef QueryParser::completeMatcherExpression() {
199 std::vector<MatcherCompletion> Comps = Parser::completeExpression(
200 Line, CompletionPos - Line.begin(),
nullptr, &QS.NamedValues);
201 for (
auto I = Comps.begin(), E = Comps.end(); I != E; ++I) {
202 Completions.push_back(LineEditor::Completion(I->TypedText, I->MatcherDecl));
208 StringRef CommandStr;
211 .
Case(
"#", PQK_Comment,
false)
212 .
Case(
"help", PQK_Help)
213 .
Case(
"l", PQK_Let,
false)
214 .
Case(
"let", PQK_Let)
215 .
Case(
"m", PQK_Match,
false)
216 .
Case(
"match", PQK_Match)
217 .
Case(
"q", PQK_Quit,
false)
218 .
Case(
"quit", PQK_Quit)
219 .
Case(
"set", PQK_Set)
220 .
Case(
"enable", PQK_Enable)
221 .
Case(
"disable", PQK_Disable)
222 .
Case(
"unlet", PQK_Unlet)
223 .
Case(
"f", PQK_File,
false)
224 .
Case(
"file", PQK_File)
230 Line = Line.drop_until([](
char c) {
return c ==
'\n'; });
231 Line = Line.drop_while([](
char c) {
return c ==
'\n'; });
233 return new NoOpQuery;
237 return endQuery(
new HelpQuery);
240 return endQuery(
new QuitQuery);
243 StringRef Name = lexWord();
246 return new InvalidQuery(
"expected variable name");
249 return completeMatcherExpression();
252 ast_matchers::dynamic::VariantValue
Value;
253 if (!Parser::parseExpression(Line,
nullptr, &QS.NamedValues, &Value,
255 return makeInvalidQueryFromDiagnostics(Diag);
258 auto *Q =
new LetQuery(Name, Value);
259 Q->RemainingContent = Line;
265 return completeMatcherExpression();
268 auto MatcherSource = Line.ltrim();
269 auto OrigMatcherSource = MatcherSource;
270 std::optional<DynTypedMatcher> Matcher = Parser::parseMatcherExpression(
271 MatcherSource,
nullptr, &QS.NamedValues, &Diag);
273 return makeInvalidQueryFromDiagnostics(Diag);
275 auto ActualSource = OrigMatcherSource.slice(0, OrigMatcherSource.size() -
276 MatcherSource.size());
277 auto *Q =
new MatchQuery(ActualSource, *Matcher);
278 Q->RemainingContent = MatcherSource;
284 ParsedQueryVariable Var =
286 .
Case(
"output", PQV_Output)
287 .
Case(
"bind-root", PQV_BindRoot)
288 .
Case(
"print-matcher", PQV_PrintMatcher)
289 .
Case(
"enable-profile", PQV_EnableProfile)
290 .
Case(
"traversal", PQV_Traversal)
293 return new InvalidQuery(
"expected variable name");
294 if (Var == PQV_Invalid)
295 return new InvalidQuery(
"unknown variable: '" + VarStr +
"'");
300 Q = parseSetOutputKind<SetExclusiveOutputQuery>();
305 case PQV_PrintMatcher:
308 case PQV_EnableProfile:
315 llvm_unreachable(
"Invalid query kind");
323 ParsedQueryVariable Var =
325 .
Case(
"output", PQV_Output)
328 return new InvalidQuery(
"expected variable name");
329 if (Var == PQV_Invalid)
330 return new InvalidQuery(
"unknown variable: '" + VarStr +
"'");
334 if (QKind == PQK_Enable)
335 Q = parseSetOutputKind<EnableOutputQuery>();
336 else if (QKind == PQK_Disable)
337 Q = parseSetOutputKind<DisableOutputQuery>();
339 llvm_unreachable(
"Invalid query kind");
344 StringRef Name = lexWord();
347 return new InvalidQuery(
"expected variable name");
349 return endQuery(
new LetQuery(Name, VariantValue()));
353 return new FileQuery(Line);
356 return new InvalidQuery(
"unknown command: " + CommandStr);
359 llvm_unreachable(
"Invalid query kind");
363 return QueryParser(Line, QS).doParse();
366std::vector<LineEditor::Completion>
368 QueryParser P(Line, QS);
369 P.CompletionPos = Line.data() + Pos;
372 return P.Completions;
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::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)