[rtsan] Remove mkfifoat interceptor (#116997)
[llvm-project.git] / mlir / lib / Query / QueryParser.cpp
blob31aead7d403d0dfebfef961a25746352282bd472
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 //===----------------------------------------------------------------------===//
9 #include "QueryParser.h"
10 #include "llvm/ADT/StringSwitch.h"
12 namespace mlir::query {
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");
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;
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 });
38 line = line.drop_front(word.size());
39 return word;
42 // This is the StringSwitch-alike used by LexOrCompleteWord below. See that
43 // function for details.
44 template <typename T>
45 struct QueryParser::LexOrCompleteWord {
46 llvm::StringRef word;
47 llvm::StringSwitch<T> stringSwitch;
49 QueryParser *queryParser;
50 // Set to the completion point offset in word, or StringRef::npos if
51 // completion point not in word.
52 size_t wordCompletionPos;
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())
64 wordCompletionPos = 0;
65 else
66 wordCompletionPos = queryParser->completionPos - word.data();
70 LexOrCompleteWord &Case(llvm::StringLiteral caseStr, const T &value,
71 bool isCompletion = true) {
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)) {
80 queryParser->completions.emplace_back(
81 (caseStr.substr(wordCompletionPos) + " ").str(),
82 std::string(caseStr));
84 return *this;
87 T Default(T value) { return stringSwitch.Default(value); }
90 QueryRef QueryParser::endQuery(QueryRef queryRef) {
91 llvm::StringRef extra = line;
92 llvm::StringRef extraTrimmed = extra.ltrim(" \t\v\f\r");
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);
103 if (!trailingWord.empty()) {
104 return new InvalidQuery("unexpected extra input: '" + extra + "'");
107 return queryRef;
110 namespace {
112 enum class ParsedQueryKind {
113 Invalid,
114 Comment,
115 NoOp,
116 Help,
117 Match,
118 Quit,
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);
128 } // namespace
130 QueryRef QueryParser::completeMatcherExpression() {
131 std::vector<matcher::MatcherCompletion> comps =
132 matcher::internal::Parser::completeExpression(
133 line, completionPos - line.begin(), qs.getRegistryData(),
134 &qs.namedValues);
135 for (const auto &comp : comps) {
136 completions.emplace_back(comp.typedText, comp.matcherDecl);
138 return QueryRef();
141 QueryRef QueryParser::doParse() {
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);
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();
164 case ParsedQueryKind::Help:
165 return endQuery(new HelpQuery);
167 case ParsedQueryKind::Quit:
168 return endQuery(new QuitQuery);
170 case ParsedQueryKind::Match: {
171 if (completionPos) {
172 return completeMatcherExpression();
175 matcher::internal::Diagnostics diag;
176 auto matcherSource = line.ltrim();
177 auto origMatcherSource = matcherSource;
178 std::optional<matcher::DynMatcher> matcher =
179 matcher::internal::Parser::parseMatcherExpression(
180 matcherSource, qs.getRegistryData(), &qs.namedValues, &diag);
181 if (!matcher) {
182 return makeInvalidQueryFromDiagnostics(diag);
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;
191 case ParsedQueryKind::Invalid:
192 return new InvalidQuery("unknown command: " + commandStr);
195 llvm_unreachable("Invalid query kind");
198 QueryRef QueryParser::parse(llvm::StringRef line, const QuerySession &qs) {
199 return QueryParser(line, qs).doParse();
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;
208 queryParser.doParse();
209 return queryParser.completions;
212 } // namespace mlir::query