brintos

brintos / llvm-project-archived public Read only

0
0
Text · 20.6 KiB · eec2702 Raw
619 lines · c
1//===- AsmParserImpl.h - MLIR AsmParserImpl Class ---------------*- C++ -*-===//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#ifndef MLIR_LIB_ASMPARSER_ASMPARSERIMPL_H10#define MLIR_LIB_ASMPARSER_ASMPARSERIMPL_H11 12#include "Parser.h"13#include "mlir/AsmParser/AsmParserState.h"14#include "mlir/IR/Builders.h"15#include "mlir/IR/OpImplementation.h"16#include "llvm/Support/Base64.h"17#include <optional>18 19namespace mlir {20namespace detail {21//===----------------------------------------------------------------------===//22// AsmParserImpl23//===----------------------------------------------------------------------===//24 25/// This class provides the implementation of the generic parser methods within26/// AsmParser.27template <typename BaseT>28class AsmParserImpl : public BaseT {29public:30  AsmParserImpl(SMLoc nameLoc, Parser &parser)31      : nameLoc(nameLoc), parser(parser) {}32  ~AsmParserImpl() override = default;33 34  /// Return the location of the original name token.35  SMLoc getNameLoc() const override { return nameLoc; }36 37  //===--------------------------------------------------------------------===//38  // Utilities39  //===--------------------------------------------------------------------===//40 41  /// Return if any errors were emitted during parsing.42  bool didEmitError() const { return emittedError; }43 44  /// Emit a diagnostic at the specified location and return failure.45  InFlightDiagnostic emitError(SMLoc loc, const Twine &message) override {46    emittedError = true;47    return parser.emitError(loc, message);48  }49 50  /// Return a builder which provides useful access to MLIRContext, global51  /// objects like types and attributes.52  Builder &getBuilder() const override { return parser.builder; }53 54  /// Get the location of the next token and store it into the argument.  This55  /// always succeeds.56  SMLoc getCurrentLocation() override { return parser.getToken().getLoc(); }57 58  /// Re-encode the given source location as an MLIR location and return it.59  Location getEncodedSourceLoc(SMLoc loc) override {60    return parser.getEncodedSourceLocation(loc);61  }62 63  //===--------------------------------------------------------------------===//64  // Token Parsing65  //===--------------------------------------------------------------------===//66 67  using Delimiter = AsmParser::Delimiter;68 69  /// Parse a `->` token.70  ParseResult parseArrow() override {71    return parser.parseToken(Token::arrow, "expected '->'");72  }73 74  /// Parses a `->` if present.75  ParseResult parseOptionalArrow() override {76    return success(parser.consumeIf(Token::arrow));77  }78 79  /// Parse a '{' token.80  ParseResult parseLBrace() override {81    return parser.parseToken(Token::l_brace, "expected '{'");82  }83 84  /// Parse a '{' token if present85  ParseResult parseOptionalLBrace() override {86    return success(parser.consumeIf(Token::l_brace));87  }88 89  /// Parse a `}` token.90  ParseResult parseRBrace() override {91    return parser.parseToken(Token::r_brace, "expected '}'");92  }93 94  /// Parse a `}` token if present95  ParseResult parseOptionalRBrace() override {96    return success(parser.consumeIf(Token::r_brace));97  }98 99  /// Parse a `:` token.100  ParseResult parseColon() override {101    return parser.parseToken(Token::colon, "expected ':'");102  }103 104  /// Parse a `:` token if present.105  ParseResult parseOptionalColon() override {106    return success(parser.consumeIf(Token::colon));107  }108 109  /// Parse a `,` token.110  ParseResult parseComma() override {111    return parser.parseToken(Token::comma, "expected ','");112  }113 114  /// Parse a `,` token if present.115  ParseResult parseOptionalComma() override {116    return success(parser.consumeIf(Token::comma));117  }118 119  /// Parses a `...`.120  ParseResult parseEllipsis() override {121    return parser.parseToken(Token::ellipsis, "expected '...'");122  }123 124  /// Parses a `...` if present.125  ParseResult parseOptionalEllipsis() override {126    return success(parser.consumeIf(Token::ellipsis));127  }128 129  /// Parse a `=` token.130  ParseResult parseEqual() override {131    return parser.parseToken(Token::equal, "expected '='");132  }133 134  /// Parse a `=` token if present.135  ParseResult parseOptionalEqual() override {136    return success(parser.consumeIf(Token::equal));137  }138 139  /// Parse a '<' token.140  ParseResult parseLess() override {141    return parser.parseToken(Token::less, "expected '<'");142  }143 144  /// Parse a `<` token if present.145  ParseResult parseOptionalLess() override {146    return success(parser.consumeIf(Token::less));147  }148 149  /// Parse a '>' token.150  ParseResult parseGreater() override {151    return parser.parseToken(Token::greater, "expected '>'");152  }153 154  /// Parse a `>` token if present.155  ParseResult parseOptionalGreater() override {156    return success(parser.consumeIf(Token::greater));157  }158 159  /// Parse a `(` token.160  ParseResult parseLParen() override {161    return parser.parseToken(Token::l_paren, "expected '('");162  }163 164  /// Parses a '(' if present.165  ParseResult parseOptionalLParen() override {166    return success(parser.consumeIf(Token::l_paren));167  }168 169  /// Parse a `)` token.170  ParseResult parseRParen() override {171    return parser.parseToken(Token::r_paren, "expected ')'");172  }173 174  /// Parses a ')' if present.175  ParseResult parseOptionalRParen() override {176    return success(parser.consumeIf(Token::r_paren));177  }178 179  /// Parse a `[` token.180  ParseResult parseLSquare() override {181    return parser.parseToken(Token::l_square, "expected '['");182  }183 184  /// Parses a '[' if present.185  ParseResult parseOptionalLSquare() override {186    return success(parser.consumeIf(Token::l_square));187  }188 189  /// Parse a `]` token.190  ParseResult parseRSquare() override {191    return parser.parseToken(Token::r_square, "expected ']'");192  }193 194  /// Parses a ']' if present.195  ParseResult parseOptionalRSquare() override {196    return success(parser.consumeIf(Token::r_square));197  }198 199  /// Parses a '?' token.200  ParseResult parseQuestion() override {201    return parser.parseToken(Token::question, "expected '?'");202  }203 204  /// Parses a '?' if present.205  ParseResult parseOptionalQuestion() override {206    return success(parser.consumeIf(Token::question));207  }208 209  /// Parses a '/' token.210  ParseResult parseSlash() override {211    return parser.parseToken(Token::slash, "expected '/'");212  }213 214  /// Parses a '/' if present.215  ParseResult parseOptionalSlash() override {216    return success(parser.consumeIf(Token::slash));217  }218 219  /// Parses a '*' token.220  ParseResult parseStar() override {221    return parser.parseToken(Token::star, "expected '*'");222  }223 224  /// Parses a '*' if present.225  ParseResult parseOptionalStar() override {226    return success(parser.consumeIf(Token::star));227  }228 229  /// Parses a '+' token.230  ParseResult parsePlus() override {231    return parser.parseToken(Token::plus, "expected '+'");232  }233 234  /// Parses a '+' token if present.235  ParseResult parseOptionalPlus() override {236    return success(parser.consumeIf(Token::plus));237  }238 239  /// Parses a '-' token.240  ParseResult parseMinus() override {241    return parser.parseToken(Token::minus, "expected '-'");242  }243 244  /// Parses a '-' token if present.245  ParseResult parseOptionalMinus() override {246    return success(parser.consumeIf(Token::minus));247  }248 249  /// Parse a '|' token.250  ParseResult parseVerticalBar() override {251    return parser.parseToken(Token::vertical_bar, "expected '|'");252  }253 254  /// Parse a '|' token if present.255  ParseResult parseOptionalVerticalBar() override {256    return success(parser.consumeIf(Token::vertical_bar));257  }258 259  /// Parses a quoted string token if present.260  ParseResult parseOptionalString(std::string *string) override {261    return parser.parseOptionalString(string);262  }263 264  /// Parses a Base64 encoded string of bytes.265  ParseResult parseBase64Bytes(std::vector<char> *bytes) override {266    auto loc = getCurrentLocation();267    if (!parser.getToken().is(Token::string))268      return emitError(loc, "expected string");269 270    if (bytes) {271      // decodeBase64 doesn't modify its input so we can use the token spelling272      // and just slice off the quotes/whitespaces if there are any. Whitespace273      // and quotes cannot appear as part of a (standard) base64 encoded string,274      // so this is safe to do.275      StringRef b64QuotedString = parser.getTokenSpelling();276      StringRef b64String =277          b64QuotedString.ltrim("\"  \t\n\v\f\r").rtrim("\" \t\n\v\f\r");278      if (auto err = llvm::decodeBase64(b64String, *bytes))279        return emitError(loc, toString(std::move(err)));280    }281 282    parser.consumeToken();283    return success();284  }285 286  /// Parse a floating point value with given semantics from the stream. Since287  /// this implementation parses the string as double precision and only288  /// afterwards converts the value to the requested semantic, precision may be289  /// lost.290  ParseResult parseFloat(const llvm::fltSemantics &semantics,291                         APFloat &result) override {292    bool isNegative = parser.consumeIf(Token::minus);293    Token curTok = parser.getToken();294    std::optional<APFloat> apResult;295    if (failed(parser.parseFloatFromLiteral(apResult, curTok, isNegative,296                                            semantics)))297      return failure();298    parser.consumeToken();299    result = *apResult;300    return success();301  }302 303  /// Parse a floating point value from the stream.304  ParseResult parseFloat(double &result) override {305    llvm::APFloat apResult(0.0);306    if (parseFloat(APFloat::IEEEdouble(), apResult))307      return failure();308 309    result = apResult.convertToDouble();310    return success();311  }312 313  /// Parse an optional integer value from the stream.314  OptionalParseResult parseOptionalInteger(APInt &result) override {315    return parser.parseOptionalInteger(result);316  }317 318  /// Parse an optional integer value from the stream.319  OptionalParseResult parseOptionalDecimalInteger(APInt &result) override {320    return parser.parseOptionalDecimalInteger(result);321  }322 323  /// Parse a list of comma-separated items with an optional delimiter.  If a324  /// delimiter is provided, then an empty list is allowed.  If not, then at325  /// least one element will be parsed.326  ParseResult parseCommaSeparatedList(Delimiter delimiter,327                                      function_ref<ParseResult()> parseElt,328                                      StringRef contextMessage) override {329    return parser.parseCommaSeparatedList(delimiter, parseElt, contextMessage);330  }331 332  //===--------------------------------------------------------------------===//333  // Keyword Parsing334  //===--------------------------------------------------------------------===//335 336  ParseResult parseKeyword(StringRef keyword, const Twine &msg) override {337    if (parser.getToken().isCodeCompletion())338      return parser.codeCompleteExpectedTokens(keyword);339 340    auto loc = getCurrentLocation();341    if (parseOptionalKeyword(keyword))342      return emitError(loc, "expected '") << keyword << "'" << msg;343    return success();344  }345  using AsmParser::parseKeyword;346 347  /// Parse the given keyword if present.348  ParseResult parseOptionalKeyword(StringRef keyword) override {349    if (parser.getToken().isCodeCompletion())350      return parser.codeCompleteOptionalTokens(keyword);351 352    // Check that the current token has the same spelling.353    if (!parser.isCurrentTokenAKeyword() ||354        parser.getTokenSpelling() != keyword)355      return failure();356    parser.consumeToken();357    return success();358  }359 360  /// Parse a keyword, if present, into 'keyword'.361  ParseResult parseOptionalKeyword(StringRef *keyword) override {362    return parser.parseOptionalKeyword(keyword);363  }364 365  /// Parse a keyword if it is one of the 'allowedKeywords'.366  ParseResult367  parseOptionalKeyword(StringRef *keyword,368                       ArrayRef<StringRef> allowedKeywords) override {369    if (parser.getToken().isCodeCompletion())370      return parser.codeCompleteOptionalTokens(allowedKeywords);371 372    // Check that the current token is a keyword.373    if (!parser.isCurrentTokenAKeyword())374      return failure();375 376    StringRef currentKeyword = parser.getTokenSpelling();377    if (llvm::is_contained(allowedKeywords, currentKeyword)) {378      *keyword = currentKeyword;379      parser.consumeToken();380      return success();381    }382 383    return failure();384  }385 386  /// Parse an optional keyword or string and set instance into 'result'.`387  ParseResult parseOptionalKeywordOrString(std::string *result) override {388    return parser.parseOptionalKeywordOrString(result);389  }390 391  //===--------------------------------------------------------------------===//392  // Attribute Parsing393  //===--------------------------------------------------------------------===//394 395  /// Parse an arbitrary attribute and return it in result.396  ParseResult parseAttribute(Attribute &result, Type type) override {397    result = parser.parseAttribute(type);398    return success(static_cast<bool>(result));399  }400 401  /// Parse a custom attribute with the provided callback, unless the next402  /// token is `#`, in which case the generic parser is invoked.403  ParseResult parseCustomAttributeWithFallback(404      Attribute &result, Type type,405      function_ref<ParseResult(Attribute &result, Type type)> parseAttribute)406      override {407    if (parser.getToken().isNot(Token::hash_identifier))408      return parseAttribute(result, type);409    result = parser.parseAttribute(type);410    return success(static_cast<bool>(result));411  }412 413  /// Parse a custom attribute with the provided callback, unless the next414  /// token is `#`, in which case the generic parser is invoked.415  ParseResult parseCustomTypeWithFallback(416      Type &result,417      function_ref<ParseResult(Type &result)> parseType) override {418    if (parser.getToken().isNot(Token::exclamation_identifier))419      return parseType(result);420    result = parser.parseType();421    return success(static_cast<bool>(result));422  }423 424  OptionalParseResult parseOptionalAttribute(Attribute &result,425                                             Type type) override {426    return parser.parseOptionalAttribute(result, type);427  }428  OptionalParseResult parseOptionalAttribute(ArrayAttr &result,429                                             Type type) override {430    return parser.parseOptionalAttribute(result, type);431  }432  OptionalParseResult parseOptionalAttribute(StringAttr &result,433                                             Type type) override {434    return parser.parseOptionalAttribute(result, type);435  }436  OptionalParseResult parseOptionalAttribute(SymbolRefAttr &result,437                                             Type type) override {438    return parser.parseOptionalAttribute(result, type);439  }440 441  /// Parse a named dictionary into 'result' if it is present.442  ParseResult parseOptionalAttrDict(NamedAttrList &result) override {443    if (parser.getToken().isNot(Token::l_brace))444      return success();445    return parser.parseAttributeDict(result);446  }447 448  /// Parse a named dictionary into 'result' if the `attributes` keyword is449  /// present.450  ParseResult parseOptionalAttrDictWithKeyword(NamedAttrList &result) override {451    if (failed(parseOptionalKeyword("attributes")))452      return success();453    return parser.parseAttributeDict(result);454  }455 456  /// Parse an affine map instance into 'map'.457  ParseResult parseAffineMap(AffineMap &map) override {458    return parser.parseAffineMapReference(map);459  }460 461  /// Parse an affine expr instance into 'expr' using the already computed462  /// mapping from symbols to affine expressions in 'symbolSet'.463  ParseResult464  parseAffineExpr(ArrayRef<std::pair<StringRef, AffineExpr>> symbolSet,465                  AffineExpr &expr) override {466    return parser.parseAffineExprReference(symbolSet, expr);467  }468 469  /// Parse an integer set instance into 'set'.470  ParseResult parseIntegerSet(IntegerSet &set) override {471    return parser.parseIntegerSetReference(set);472  }473 474  //===--------------------------------------------------------------------===//475  // Identifier Parsing476  //===--------------------------------------------------------------------===//477 478  /// Parse an optional @-identifier and store it (without the '@' symbol) in a479  /// string attribute named 'attrName'.480  ParseResult parseOptionalSymbolName(StringAttr &result) override {481    Token atToken = parser.getToken();482    if (atToken.isNot(Token::at_identifier))483      return failure();484 485    result = getBuilder().getStringAttr(atToken.getSymbolReference());486    parser.consumeToken();487 488    // If we are populating the assembly parser state, record this as a symbol489    // reference.490    if (parser.getState().asmState) {491      parser.getState().asmState->addUses(SymbolRefAttr::get(result),492                                          atToken.getLocRange());493    }494    return success();495  }496 497  //===--------------------------------------------------------------------===//498  // Resource Parsing499  //===--------------------------------------------------------------------===//500 501  /// Parse a handle to a resource within the assembly format.502  FailureOr<AsmDialectResourceHandle>503  parseResourceHandle(Dialect *dialect) override {504    const auto *interface = dyn_cast<OpAsmDialectInterface>(dialect);505    if (!interface) {506      return parser.emitError() << "dialect '" << dialect->getNamespace()507                                << "' does not expect resource handles";508    }509    std::string resourceName;510    return parser.parseResourceHandle(interface, resourceName);511  }512 513  //===--------------------------------------------------------------------===//514  // Type Parsing515  //===--------------------------------------------------------------------===//516 517  /// Parse a type.518  ParseResult parseType(Type &result) override {519    return failure(!(result = parser.parseType()));520  }521 522  /// Parse an optional type.523  OptionalParseResult parseOptionalType(Type &result) override {524    return parser.parseOptionalType(result);525  }526 527  /// Parse an arrow followed by a type list.528  ParseResult parseArrowTypeList(SmallVectorImpl<Type> &result) override {529    if (parseArrow() || parser.parseFunctionResultTypes(result))530      return failure();531    return success();532  }533 534  /// Parse an optional arrow followed by a type list.535  ParseResult536  parseOptionalArrowTypeList(SmallVectorImpl<Type> &result) override {537    if (!parser.consumeIf(Token::arrow))538      return success();539    return parser.parseFunctionResultTypes(result);540  }541 542  /// Parse a colon followed by a type.543  ParseResult parseColonType(Type &result) override {544    return failure(parser.parseToken(Token::colon, "expected ':'") ||545                   !(result = parser.parseType()));546  }547 548  /// Parse a colon followed by a type list, which must have at least one type.549  ParseResult parseColonTypeList(SmallVectorImpl<Type> &result) override {550    if (parser.parseToken(Token::colon, "expected ':'"))551      return failure();552    return parser.parseTypeListNoParens(result);553  }554 555  /// Parse an optional colon followed by a type list, which if present must556  /// have at least one type.557  ParseResult558  parseOptionalColonTypeList(SmallVectorImpl<Type> &result) override {559    if (!parser.consumeIf(Token::colon))560      return success();561    return parser.parseTypeListNoParens(result);562  }563 564  ParseResult parseDimensionList(SmallVectorImpl<int64_t> &dimensions,565                                 bool allowDynamic,566                                 bool withTrailingX) override {567    return parser.parseDimensionListRanked(dimensions, allowDynamic,568                                           withTrailingX);569  }570 571  ParseResult parseXInDimensionList() override {572    return parser.parseXInDimensionList();573  }574 575  LogicalResult pushCyclicParsing(const void *opaquePointer) override {576    return success(parser.getState().cyclicParsingStack.insert(opaquePointer));577  }578 579  void popCyclicParsing() override {580    parser.getState().cyclicParsingStack.pop_back();581  }582 583  //===--------------------------------------------------------------------===//584  // Code Completion585  //===--------------------------------------------------------------------===//586 587  /// Parse a keyword, or an empty string if the current location signals a code588  /// completion.589  ParseResult parseKeywordOrCompletion(StringRef *keyword) override {590    Token tok = parser.getToken();591    if (tok.isCodeCompletion() && tok.getSpelling().empty()) {592      *keyword = "";593      return success();594    }595    return parseKeyword(keyword);596  }597 598  /// Signal the code completion of a set of expected tokens.599  void codeCompleteExpectedTokens(ArrayRef<StringRef> tokens) override {600    Token tok = parser.getToken();601    if (tok.isCodeCompletion() && tok.getSpelling().empty())602      (void)parser.codeCompleteExpectedTokens(tokens);603  }604 605protected:606  /// The source location of the dialect symbol.607  SMLoc nameLoc;608 609  /// The main parser.610  Parser &parser;611 612  /// A flag that indicates if any errors were emitted during parsing.613  bool emittedError = false;614};615} // namespace detail616} // namespace mlir617 618#endif // MLIR_LIB_ASMPARSER_ASMPARSERIMPL_H619