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

source code of mlir/lib/AsmParser/AsmParserImpl.h