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 {
191 llvm::raw_string_ostream
OS(ErrStr);
192 Diag.printToStreamFull(
OS);
193 return new InvalidQuery(
OS.str());
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;
209 ParsedQueryKind QKind = LexOrCompleteWord<ParsedQueryKind>(
this, 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)
225 .Default(PQK_Invalid);
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(
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 =
285 LexOrCompleteWord<ParsedQueryVariable>(
this, VarStr)
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)
291 .Default(PQV_Invalid);
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 =
324 LexOrCompleteWord<ParsedQueryVariable>(
this, VarStr)
325 .Case(
"output", PQV_Output)
326 .Default(PQV_Invalid);
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");
366std::vector<LineEditor::Completion>
369 P.CompletionPos =
Line.data() +
Pos;
372 return P.Completions;
llvm::SmallString< 256U > Name
WantDiagnostics Diagnostics
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)