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