1 //===- AsmParserImpl.h - MLIR AsmParserImpl Class ---------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef MLIR_LIB_ASMPARSER_ASMPARSERIMPL_H
10 #define MLIR_LIB_ASMPARSER_ASMPARSERIMPL_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"
21 //===----------------------------------------------------------------------===//
23 //===----------------------------------------------------------------------===//
25 /// This class provides the implementation of the generic parser methods within
27 template <typename BaseT
>
28 class AsmParserImpl
: public BaseT
{
30 AsmParserImpl(SMLoc nameLoc
, Parser
&parser
)
31 : nameLoc(nameLoc
), parser(parser
) {}
32 ~AsmParserImpl() override
= default;
34 /// Return the location of the original name token.
35 SMLoc
getNameLoc() const override
{ return nameLoc
; }
37 //===--------------------------------------------------------------------===//
39 //===--------------------------------------------------------------------===//
41 /// Return if any errors were emitted during parsing.
42 bool didEmitError() const { return emittedError
; }
44 /// Emit a diagnostic at the specified location and return failure.
45 InFlightDiagnostic
emitError(SMLoc loc
, const Twine
&message
) override
{
47 return parser
.emitError(loc
, message
);
50 /// Return a builder which provides useful access to MLIRContext, global
51 /// objects like types and attributes.
52 Builder
&getBuilder() const override
{ return parser
.builder
; }
54 /// Get the location of the next token and store it into the argument. This
56 SMLoc
getCurrentLocation() override
{ return parser
.getToken().getLoc(); }
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
);
63 //===--------------------------------------------------------------------===//
65 //===--------------------------------------------------------------------===//
67 using Delimiter
= AsmParser::Delimiter
;
69 /// Parse a `->` token.
70 ParseResult
parseArrow() override
{
71 return parser
.parseToken(Token::arrow
, "expected '->'");
74 /// Parses a `->` if present.
75 ParseResult
parseOptionalArrow() override
{
76 return success(parser
.consumeIf(Token::arrow
));
79 /// Parse a '{' token.
80 ParseResult
parseLBrace() override
{
81 return parser
.parseToken(Token::l_brace
, "expected '{'");
84 /// Parse a '{' token if present
85 ParseResult
parseOptionalLBrace() override
{
86 return success(parser
.consumeIf(Token::l_brace
));
89 /// Parse a `}` token.
90 ParseResult
parseRBrace() override
{
91 return parser
.parseToken(Token::r_brace
, "expected '}'");
94 /// Parse a `}` token if present
95 ParseResult
parseOptionalRBrace() override
{
96 return success(parser
.consumeIf(Token::r_brace
));
99 /// Parse a `:` token.
100 ParseResult
parseColon() override
{
101 return parser
.parseToken(Token::colon
, "expected ':'");
104 /// Parse a `:` token if present.
105 ParseResult
parseOptionalColon() override
{
106 return success(parser
.consumeIf(Token::colon
));
109 /// Parse a `,` token.
110 ParseResult
parseComma() override
{
111 return parser
.parseToken(Token::comma
, "expected ','");
114 /// Parse a `,` token if present.
115 ParseResult
parseOptionalComma() override
{
116 return success(parser
.consumeIf(Token::comma
));
120 ParseResult
parseEllipsis() override
{
121 return parser
.parseToken(Token::ellipsis
, "expected '...'");
124 /// Parses a `...` if present.
125 ParseResult
parseOptionalEllipsis() override
{
126 return success(parser
.consumeIf(Token::ellipsis
));
129 /// Parse a `=` token.
130 ParseResult
parseEqual() override
{
131 return parser
.parseToken(Token::equal
, "expected '='");
134 /// Parse a `=` token if present.
135 ParseResult
parseOptionalEqual() override
{
136 return success(parser
.consumeIf(Token::equal
));
139 /// Parse a '<' token.
140 ParseResult
parseLess() override
{
141 return parser
.parseToken(Token::less
, "expected '<'");
144 /// Parse a `<` token if present.
145 ParseResult
parseOptionalLess() override
{
146 return success(parser
.consumeIf(Token::less
));
149 /// Parse a '>' token.
150 ParseResult
parseGreater() override
{
151 return parser
.parseToken(Token::greater
, "expected '>'");
154 /// Parse a `>` token if present.
155 ParseResult
parseOptionalGreater() override
{
156 return success(parser
.consumeIf(Token::greater
));
159 /// Parse a `(` token.
160 ParseResult
parseLParen() override
{
161 return parser
.parseToken(Token::l_paren
, "expected '('");
164 /// Parses a '(' if present.
165 ParseResult
parseOptionalLParen() override
{
166 return success(parser
.consumeIf(Token::l_paren
));
169 /// Parse a `)` token.
170 ParseResult
parseRParen() override
{
171 return parser
.parseToken(Token::r_paren
, "expected ')'");
174 /// Parses a ')' if present.
175 ParseResult
parseOptionalRParen() override
{
176 return success(parser
.consumeIf(Token::r_paren
));
179 /// Parse a `[` token.
180 ParseResult
parseLSquare() override
{
181 return parser
.parseToken(Token::l_square
, "expected '['");
184 /// Parses a '[' if present.
185 ParseResult
parseOptionalLSquare() override
{
186 return success(parser
.consumeIf(Token::l_square
));
189 /// Parse a `]` token.
190 ParseResult
parseRSquare() override
{
191 return parser
.parseToken(Token::r_square
, "expected ']'");
194 /// Parses a ']' if present.
195 ParseResult
parseOptionalRSquare() override
{
196 return success(parser
.consumeIf(Token::r_square
));
199 /// Parses a '?' token.
200 ParseResult
parseQuestion() override
{
201 return parser
.parseToken(Token::question
, "expected '?'");
204 /// Parses a '?' if present.
205 ParseResult
parseOptionalQuestion() override
{
206 return success(parser
.consumeIf(Token::question
));
209 /// Parses a '*' token.
210 ParseResult
parseStar() override
{
211 return parser
.parseToken(Token::star
, "expected '*'");
214 /// Parses a '*' if present.
215 ParseResult
parseOptionalStar() override
{
216 return success(parser
.consumeIf(Token::star
));
219 /// Parses a '+' token.
220 ParseResult
parsePlus() override
{
221 return parser
.parseToken(Token::plus
, "expected '+'");
224 /// Parses a '+' token if present.
225 ParseResult
parseOptionalPlus() override
{
226 return success(parser
.consumeIf(Token::plus
));
229 /// Parses a '-' token.
230 ParseResult
parseMinus() override
{
231 return parser
.parseToken(Token::minus
, "expected '-'");
234 /// Parses a '-' token if present.
235 ParseResult
parseOptionalMinus() override
{
236 return success(parser
.consumeIf(Token::minus
));
239 /// Parse a '|' token.
240 ParseResult
parseVerticalBar() override
{
241 return parser
.parseToken(Token::vertical_bar
, "expected '|'");
244 /// Parse a '|' token if present.
245 ParseResult
parseOptionalVerticalBar() override
{
246 return success(parser
.consumeIf(Token::vertical_bar
));
249 /// Parses a quoted string token if present.
250 ParseResult
parseOptionalString(std::string
*string
) override
{
251 if (!parser
.getToken().is(Token::string
))
255 *string
= parser
.getToken().getStringValue();
256 parser
.consumeToken();
260 /// Parses a Base64 encoded string of bytes.
261 ParseResult
parseBase64Bytes(std::vector
<char> *bytes
) override
{
262 auto loc
= getCurrentLocation();
263 if (!parser
.getToken().is(Token::string
))
264 return emitError(loc
, "expected string");
267 // decodeBase64 doesn't modify its input so we can use the token spelling
268 // and just slice off the quotes/whitespaces if there are any. Whitespace
269 // and quotes cannot appear as part of a (standard) base64 encoded string,
270 // so this is safe to do.
271 StringRef b64QuotedString
= parser
.getTokenSpelling();
272 StringRef b64String
=
273 b64QuotedString
.ltrim("\" \t\n\v\f\r").rtrim("\" \t\n\v\f\r");
274 if (auto err
= llvm::decodeBase64(b64String
, *bytes
))
275 return emitError(loc
, toString(std::move(err
)));
278 parser
.consumeToken();
282 /// Parse a floating point value with given semantics from the stream. Since
283 /// this implementation parses the string as double precision and only
284 /// afterwards converts the value to the requested semantic, precision may be
286 ParseResult
parseFloat(const llvm::fltSemantics
&semantics
,
287 APFloat
&result
) override
{
288 bool isNegative
= parser
.consumeIf(Token::minus
);
289 Token curTok
= parser
.getToken();
290 std::optional
<APFloat
> apResult
;
291 if (failed(parser
.parseFloatFromLiteral(apResult
, curTok
, isNegative
,
294 parser
.consumeToken();
299 /// Parse a floating point value from the stream.
300 ParseResult
parseFloat(double &result
) override
{
301 llvm::APFloat
apResult(0.0);
302 if (parseFloat(APFloat::IEEEdouble(), apResult
))
305 result
= apResult
.convertToDouble();
309 /// Parse an optional integer value from the stream.
310 OptionalParseResult
parseOptionalInteger(APInt
&result
) override
{
311 return parser
.parseOptionalInteger(result
);
314 /// Parse an optional integer value from the stream.
315 OptionalParseResult
parseOptionalDecimalInteger(APInt
&result
) override
{
316 return parser
.parseOptionalDecimalInteger(result
);
319 /// Parse a list of comma-separated items with an optional delimiter. If a
320 /// delimiter is provided, then an empty list is allowed. If not, then at
321 /// least one element will be parsed.
322 ParseResult
parseCommaSeparatedList(Delimiter delimiter
,
323 function_ref
<ParseResult()> parseElt
,
324 StringRef contextMessage
) override
{
325 return parser
.parseCommaSeparatedList(delimiter
, parseElt
, contextMessage
);
328 //===--------------------------------------------------------------------===//
330 //===--------------------------------------------------------------------===//
332 ParseResult
parseKeyword(StringRef keyword
, const Twine
&msg
) override
{
333 if (parser
.getToken().isCodeCompletion())
334 return parser
.codeCompleteExpectedTokens(keyword
);
336 auto loc
= getCurrentLocation();
337 if (parseOptionalKeyword(keyword
))
338 return emitError(loc
, "expected '") << keyword
<< "'" << msg
;
341 using AsmParser::parseKeyword
;
343 /// Parse the given keyword if present.
344 ParseResult
parseOptionalKeyword(StringRef keyword
) override
{
345 if (parser
.getToken().isCodeCompletion())
346 return parser
.codeCompleteOptionalTokens(keyword
);
348 // Check that the current token has the same spelling.
349 if (!parser
.isCurrentTokenAKeyword() ||
350 parser
.getTokenSpelling() != keyword
)
352 parser
.consumeToken();
356 /// Parse a keyword, if present, into 'keyword'.
357 ParseResult
parseOptionalKeyword(StringRef
*keyword
) override
{
358 // Check that the current token is a keyword.
359 if (!parser
.isCurrentTokenAKeyword())
362 *keyword
= parser
.getTokenSpelling();
363 parser
.consumeToken();
367 /// Parse a keyword if it is one of the 'allowedKeywords'.
369 parseOptionalKeyword(StringRef
*keyword
,
370 ArrayRef
<StringRef
> allowedKeywords
) override
{
371 if (parser
.getToken().isCodeCompletion())
372 return parser
.codeCompleteOptionalTokens(allowedKeywords
);
374 // Check that the current token is a keyword.
375 if (!parser
.isCurrentTokenAKeyword())
378 StringRef currentKeyword
= parser
.getTokenSpelling();
379 if (llvm::is_contained(allowedKeywords
, currentKeyword
)) {
380 *keyword
= currentKeyword
;
381 parser
.consumeToken();
388 /// Parse an optional keyword or string and set instance into 'result'.`
389 ParseResult
parseOptionalKeywordOrString(std::string
*result
) override
{
391 if (succeeded(parseOptionalKeyword(&keyword
))) {
392 *result
= keyword
.str();
396 return parseOptionalString(result
);
399 //===--------------------------------------------------------------------===//
401 //===--------------------------------------------------------------------===//
403 /// Parse an arbitrary attribute and return it in result.
404 ParseResult
parseAttribute(Attribute
&result
, Type type
) override
{
405 result
= parser
.parseAttribute(type
);
406 return success(static_cast<bool>(result
));
409 /// Parse a custom attribute with the provided callback, unless the next
410 /// token is `#`, in which case the generic parser is invoked.
411 ParseResult
parseCustomAttributeWithFallback(
412 Attribute
&result
, Type type
,
413 function_ref
<ParseResult(Attribute
&result
, Type type
)> parseAttribute
)
415 if (parser
.getToken().isNot(Token::hash_identifier
))
416 return parseAttribute(result
, type
);
417 result
= parser
.parseAttribute(type
);
418 return success(static_cast<bool>(result
));
421 /// Parse a custom attribute with the provided callback, unless the next
422 /// token is `#`, in which case the generic parser is invoked.
423 ParseResult
parseCustomTypeWithFallback(
425 function_ref
<ParseResult(Type
&result
)> parseType
) override
{
426 if (parser
.getToken().isNot(Token::exclamation_identifier
))
427 return parseType(result
);
428 result
= parser
.parseType();
429 return success(static_cast<bool>(result
));
432 OptionalParseResult
parseOptionalAttribute(Attribute
&result
,
433 Type type
) override
{
434 return parser
.parseOptionalAttribute(result
, type
);
436 OptionalParseResult
parseOptionalAttribute(ArrayAttr
&result
,
437 Type type
) override
{
438 return parser
.parseOptionalAttribute(result
, type
);
440 OptionalParseResult
parseOptionalAttribute(StringAttr
&result
,
441 Type type
) override
{
442 return parser
.parseOptionalAttribute(result
, type
);
444 OptionalParseResult
parseOptionalAttribute(SymbolRefAttr
&result
,
445 Type type
) override
{
446 return parser
.parseOptionalAttribute(result
, type
);
449 /// Parse a named dictionary into 'result' if it is present.
450 ParseResult
parseOptionalAttrDict(NamedAttrList
&result
) override
{
451 if (parser
.getToken().isNot(Token::l_brace
))
453 return parser
.parseAttributeDict(result
);
456 /// Parse a named dictionary into 'result' if the `attributes` keyword is
458 ParseResult
parseOptionalAttrDictWithKeyword(NamedAttrList
&result
) override
{
459 if (failed(parseOptionalKeyword("attributes")))
461 return parser
.parseAttributeDict(result
);
464 /// Parse an affine map instance into 'map'.
465 ParseResult
parseAffineMap(AffineMap
&map
) override
{
466 return parser
.parseAffineMapReference(map
);
469 /// Parse an affine expr instance into 'expr' using the already computed
470 /// mapping from symbols to affine expressions in 'symbolSet'.
472 parseAffineExpr(ArrayRef
<std::pair
<StringRef
, AffineExpr
>> symbolSet
,
473 AffineExpr
&expr
) override
{
474 return parser
.parseAffineExprReference(symbolSet
, expr
);
477 /// Parse an integer set instance into 'set'.
478 ParseResult
parseIntegerSet(IntegerSet
&set
) override
{
479 return parser
.parseIntegerSetReference(set
);
482 //===--------------------------------------------------------------------===//
483 // Identifier Parsing
484 //===--------------------------------------------------------------------===//
486 /// Parse an optional @-identifier and store it (without the '@' symbol) in a
487 /// string attribute named 'attrName'.
488 ParseResult
parseOptionalSymbolName(StringAttr
&result
) override
{
489 Token atToken
= parser
.getToken();
490 if (atToken
.isNot(Token::at_identifier
))
493 result
= getBuilder().getStringAttr(atToken
.getSymbolReference());
494 parser
.consumeToken();
496 // If we are populating the assembly parser state, record this as a symbol
498 if (parser
.getState().asmState
) {
499 parser
.getState().asmState
->addUses(SymbolRefAttr::get(result
),
500 atToken
.getLocRange());
505 //===--------------------------------------------------------------------===//
507 //===--------------------------------------------------------------------===//
509 /// Parse a handle to a resource within the assembly format.
510 FailureOr
<AsmDialectResourceHandle
>
511 parseResourceHandle(Dialect
*dialect
) override
{
512 const auto *interface
= dyn_cast
<OpAsmDialectInterface
>(dialect
);
514 return parser
.emitError() << "dialect '" << dialect
->getNamespace()
515 << "' does not expect resource handles";
517 StringRef resourceName
;
518 return parser
.parseResourceHandle(interface
, resourceName
);
521 //===--------------------------------------------------------------------===//
523 //===--------------------------------------------------------------------===//
526 ParseResult
parseType(Type
&result
) override
{
527 return failure(!(result
= parser
.parseType()));
530 /// Parse an optional type.
531 OptionalParseResult
parseOptionalType(Type
&result
) override
{
532 return parser
.parseOptionalType(result
);
535 /// Parse an arrow followed by a type list.
536 ParseResult
parseArrowTypeList(SmallVectorImpl
<Type
> &result
) override
{
537 if (parseArrow() || parser
.parseFunctionResultTypes(result
))
542 /// Parse an optional arrow followed by a type list.
544 parseOptionalArrowTypeList(SmallVectorImpl
<Type
> &result
) override
{
545 if (!parser
.consumeIf(Token::arrow
))
547 return parser
.parseFunctionResultTypes(result
);
550 /// Parse a colon followed by a type.
551 ParseResult
parseColonType(Type
&result
) override
{
552 return failure(parser
.parseToken(Token::colon
, "expected ':'") ||
553 !(result
= parser
.parseType()));
556 /// Parse a colon followed by a type list, which must have at least one type.
557 ParseResult
parseColonTypeList(SmallVectorImpl
<Type
> &result
) override
{
558 if (parser
.parseToken(Token::colon
, "expected ':'"))
560 return parser
.parseTypeListNoParens(result
);
563 /// Parse an optional colon followed by a type list, which if present must
564 /// have at least one type.
566 parseOptionalColonTypeList(SmallVectorImpl
<Type
> &result
) override
{
567 if (!parser
.consumeIf(Token::colon
))
569 return parser
.parseTypeListNoParens(result
);
572 ParseResult
parseDimensionList(SmallVectorImpl
<int64_t> &dimensions
,
574 bool withTrailingX
) override
{
575 return parser
.parseDimensionListRanked(dimensions
, allowDynamic
,
579 ParseResult
parseXInDimensionList() override
{
580 return parser
.parseXInDimensionList();
583 LogicalResult
pushCyclicParsing(const void *opaquePointer
) override
{
584 return success(parser
.getState().cyclicParsingStack
.insert(opaquePointer
));
587 void popCyclicParsing() override
{
588 parser
.getState().cyclicParsingStack
.pop_back();
591 //===--------------------------------------------------------------------===//
593 //===--------------------------------------------------------------------===//
595 /// Parse a keyword, or an empty string if the current location signals a code
597 ParseResult
parseKeywordOrCompletion(StringRef
*keyword
) override
{
598 Token tok
= parser
.getToken();
599 if (tok
.isCodeCompletion() && tok
.getSpelling().empty()) {
603 return parseKeyword(keyword
);
606 /// Signal the code completion of a set of expected tokens.
607 void codeCompleteExpectedTokens(ArrayRef
<StringRef
> tokens
) override
{
608 Token tok
= parser
.getToken();
609 if (tok
.isCodeCompletion() && tok
.getSpelling().empty())
610 (void)parser
.codeCompleteExpectedTokens(tokens
);
614 /// The source location of the dialect symbol.
620 /// A flag that indicates if any errors were emitted during parsing.
621 bool emittedError
= false;
623 } // namespace detail
626 #endif // MLIR_LIB_ASMPARSER_ASMPARSERIMPL_H