MLIR  20.0.0git
QueryParser.cpp
Go to the documentation of this file.
1 //===---- QueryParser.cpp - mlir-query command parser ---------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "QueryParser.h"
10 #include "llvm/ADT/StringSwitch.h"
11 
12 namespace mlir::query {
13 
14 // Lex any amount of whitespace followed by a "word" (any sequence of
15 // non-whitespace characters) from the start of region [begin,end). If no word
16 // is found before end, return StringRef(). begin is adjusted to exclude the
17 // lexed region.
18 llvm::StringRef QueryParser::lexWord() {
19  // Don't trim newlines.
20  line = line.ltrim(" \t\v\f\r");
21 
22  if (line.empty())
23  // Even though the line is empty, it contains a pointer and
24  // a (zero) length. The pointer is used in the LexOrCompleteWord
25  // code completion.
26  return line;
27 
28  llvm::StringRef word;
29  if (line.front() == '#') {
30  word = line.substr(0, 1);
31  } else {
32  word = line.take_until([](char c) {
33  // Don't trim newlines.
34  return llvm::StringRef(" \t\v\f\r").contains(c);
35  });
36  }
37 
38  line = line.drop_front(word.size());
39  return word;
40 }
41 
42 // This is the StringSwitch-alike used by LexOrCompleteWord below. See that
43 // function for details.
44 template <typename T>
46  llvm::StringRef word;
48 
50  // Set to the completion point offset in word, or StringRef::npos if
51  // completion point not in word.
53 
54  // Lexes a word and stores it in word. Returns a LexOrCompleteword<T> object
55  // that can be used like a llvm::StringSwitch<T>, but adds cases as possible
56  // completions if the lexed word contains the completion point.
57  LexOrCompleteWord(QueryParser *queryParser, llvm::StringRef &outWord)
58  : word(queryParser->lexWord()), stringSwitch(word),
59  queryParser(queryParser), wordCompletionPos(llvm::StringRef::npos) {
60  outWord = word;
61  if (queryParser->completionPos &&
62  queryParser->completionPos <= word.data() + word.size()) {
63  if (queryParser->completionPos < word.data())
65  else
66  wordCompletionPos = queryParser->completionPos - word.data();
67  }
68  }
69 
70  LexOrCompleteWord &Case(llvm::StringLiteral caseStr, const T &value,
71  bool isCompletion = true) {
72 
73  if (wordCompletionPos == llvm::StringRef::npos)
74  stringSwitch.Case(caseStr, value);
75  else if (!caseStr.empty() && isCompletion &&
76  wordCompletionPos <= caseStr.size() &&
77  caseStr.substr(0, wordCompletionPos) ==
78  word.substr(0, wordCompletionPos)) {
79 
80  queryParser->completions.emplace_back(
81  (caseStr.substr(wordCompletionPos) + " ").str(),
82  std::string(caseStr));
83  }
84  return *this;
85  }
86 
87  T Default(T value) { return stringSwitch.Default(value); }
88 };
89 
90 QueryRef QueryParser::endQuery(QueryRef queryRef) {
91  llvm::StringRef extra = line;
92  llvm::StringRef extraTrimmed = extra.ltrim(" \t\v\f\r");
93 
94  if (extraTrimmed.starts_with('\n') || extraTrimmed.starts_with("\r\n"))
95  queryRef->remainingContent = extra;
96  else {
97  llvm::StringRef trailingWord = lexWord();
98  if (trailingWord.starts_with('#')) {
99  line = line.drop_until([](char c) { return c == '\n'; });
100  line = line.drop_while([](char c) { return c == '\n'; });
101  return endQuery(queryRef);
102  }
103  if (!trailingWord.empty()) {
104  return new InvalidQuery("unexpected extra input: '" + extra + "'");
105  }
106  }
107  return queryRef;
108 }
109 
110 namespace {
111 
112 enum class ParsedQueryKind {
113  Invalid,
114  Comment,
115  NoOp,
116  Help,
117  Match,
118  Quit,
119 };
120 
121 QueryRef
122 makeInvalidQueryFromDiagnostics(const matcher::internal::Diagnostics &diag) {
123  std::string errStr;
124  llvm::raw_string_ostream os(errStr);
125  diag.print(os);
126  return new InvalidQuery(errStr);
127 }
128 } // namespace
129 
130 QueryRef QueryParser::completeMatcherExpression() {
131  std::vector<matcher::MatcherCompletion> comps =
133  line, completionPos - line.begin(), qs.getRegistryData(),
134  &qs.namedValues);
135  for (const auto &comp : comps) {
136  completions.emplace_back(comp.typedText, comp.matcherDecl);
137  }
138  return QueryRef();
139 }
140 
141 QueryRef QueryParser::doParse() {
142 
143  llvm::StringRef commandStr;
144  ParsedQueryKind qKind =
145  LexOrCompleteWord<ParsedQueryKind>(this, commandStr)
146  .Case("", ParsedQueryKind::NoOp)
147  .Case("#", ParsedQueryKind::Comment, /*isCompletion=*/false)
148  .Case("help", ParsedQueryKind::Help)
149  .Case("m", ParsedQueryKind::Match, /*isCompletion=*/false)
150  .Case("match", ParsedQueryKind::Match)
151  .Case("q", ParsedQueryKind::Quit, /*IsCompletion=*/false)
152  .Case("quit", ParsedQueryKind::Quit)
153  .Default(ParsedQueryKind::Invalid);
154 
155  switch (qKind) {
156  case ParsedQueryKind::Comment:
157  case ParsedQueryKind::NoOp:
158  line = line.drop_until([](char c) { return c == '\n'; });
159  line = line.drop_while([](char c) { return c == '\n'; });
160  if (line.empty())
161  return new NoOpQuery;
162  return doParse();
163 
164  case ParsedQueryKind::Help:
165  return endQuery(new HelpQuery);
166 
167  case ParsedQueryKind::Quit:
168  return endQuery(new QuitQuery);
169 
170  case ParsedQueryKind::Match: {
171  if (completionPos) {
172  return completeMatcherExpression();
173  }
174 
175  matcher::internal::Diagnostics diag;
176  auto matcherSource = line.ltrim();
177  auto origMatcherSource = matcherSource;
178  std::optional<matcher::DynMatcher> matcher =
180  matcherSource, qs.getRegistryData(), &qs.namedValues, &diag);
181  if (!matcher) {
182  return makeInvalidQueryFromDiagnostics(diag);
183  }
184  auto actualSource = origMatcherSource.substr(0, origMatcherSource.size() -
185  matcherSource.size());
186  QueryRef query = new MatchQuery(actualSource, *matcher);
187  query->remainingContent = matcherSource;
188  return query;
189  }
190 
191  case ParsedQueryKind::Invalid:
192  return new InvalidQuery("unknown command: " + commandStr);
193  }
194 
195  llvm_unreachable("Invalid query kind");
196 }
197 
198 QueryRef QueryParser::parse(llvm::StringRef line, const QuerySession &qs) {
199  return QueryParser(line, qs).doParse();
200 }
201 
202 std::vector<llvm::LineEditor::Completion>
203 QueryParser::complete(llvm::StringRef line, size_t pos,
204  const QuerySession &qs) {
205  QueryParser queryParser(line, qs);
206  queryParser.completionPos = line.data() + pos;
207 
208  queryParser.doParse();
209  return queryParser.completions;
210 }
211 
212 } // namespace mlir::query
static std::string diag(const llvm::Value &value)
static QueryRef parse(llvm::StringRef line, const QuerySession &qs)
static std::vector< llvm::LineEditor::Completion > complete(llvm::StringRef line, size_t pos, const QuerySession &qs)
const matcher::Registry & getRegistryData() const
Definition: QuerySession.h:31
llvm::StringMap< matcher::VariantValue > namedValues
Definition: QuerySession.h:33
static std::vector< MatcherCompletion > completeExpression(llvm::StringRef &code, unsigned completionOffset, const Registry &matcherRegistry, const NamedValueMap *namedValues)
Definition: Parser.cpp:564
static std::optional< DynMatcher > parseMatcherExpression(llvm::StringRef &matcherCode, const Registry &matcherRegistry, const NamedValueMap *namedValues, Diagnostics *error)
Definition: Parser.cpp:576
The OpAsmOpInterface, see OpAsmInterface.td for more details.
Definition: CallGraph.h:229
FailureOr< Attribute > query(Operation *op, ArrayRef< DataLayoutEntryKey > keys, bool emitError=false)
Perform a DLTI-query at op, recursively querying each key of keys on query interface-implementing att...
Definition: DLTI.cpp:510
llvm::IntrusiveRefCntPtr< Query > QueryRef
Definition: Query.h:36
LexOrCompleteWord(QueryParser *queryParser, llvm::StringRef &outWord)
Definition: QueryParser.cpp:57
LexOrCompleteWord & Case(llvm::StringLiteral caseStr, const T &value, bool isCompletion=true)
Definition: QueryParser.cpp:70