brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.6 KiB · 31aead7 Raw
213 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "QueryParser.h"10#include "llvm/ADT/StringSwitch.h"11 12namespace mlir::query {13 14// Lex any amount of whitespace followed by a "word" (any sequence of15// non-whitespace characters) from the start of region [begin,end).  If no word16// is found before end, return StringRef(). begin is adjusted to exclude the17// lexed region.18llvm::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 and24    // a (zero) length. The pointer is used in the LexOrCompleteWord25    // 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 that43// function for details.44template <typename T>45struct QueryParser::LexOrCompleteWord {46  llvm::StringRef word;47  llvm::StringSwitch<T> stringSwitch;48 49  QueryParser *queryParser;50  // Set to the completion point offset in word, or StringRef::npos if51  // completion point not in word.52  size_t wordCompletionPos;53 54  // Lexes a word and stores it in word. Returns a LexOrCompleteword<T> object55  // that can be used like a llvm::StringSwitch<T>, but adds cases as possible56  // 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      else66        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 90QueryRef 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 110namespace {111 112enum class ParsedQueryKind {113  Invalid,114  Comment,115  NoOp,116  Help,117  Match,118  Quit,119};120 121QueryRef122makeInvalidQueryFromDiagnostics(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} // namespace129 130QueryRef 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);137  }138  return QueryRef();139}140 141QueryRef 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 =179        matcher::internal::Parser::parseMatcherExpression(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 198QueryRef QueryParser::parse(llvm::StringRef line, const QuerySession &qs) {199  return QueryParser(line, qs).doParse();200}201 202std::vector<llvm::LineEditor::Completion>203QueryParser::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::query213