1*c60b897dSRiver Riddle //===- DialectSymbolParser.cpp - MLIR Dialect Symbol Parser  --------------===//
2*c60b897dSRiver Riddle //
3*c60b897dSRiver Riddle // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*c60b897dSRiver Riddle // See https://llvm.org/LICENSE.txt for license information.
5*c60b897dSRiver Riddle // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*c60b897dSRiver Riddle //
7*c60b897dSRiver Riddle //===----------------------------------------------------------------------===//
8*c60b897dSRiver Riddle //
9*c60b897dSRiver Riddle // This file implements the parser for the dialect symbols, such as extended
10*c60b897dSRiver Riddle // attributes and types.
11*c60b897dSRiver Riddle //
12*c60b897dSRiver Riddle //===----------------------------------------------------------------------===//
13*c60b897dSRiver Riddle 
14*c60b897dSRiver Riddle #include "AsmParserImpl.h"
15*c60b897dSRiver Riddle #include "mlir/IR/BuiltinTypes.h"
16*c60b897dSRiver Riddle #include "mlir/IR/Dialect.h"
17*c60b897dSRiver Riddle #include "mlir/IR/DialectImplementation.h"
18*c60b897dSRiver Riddle #include "llvm/Support/SourceMgr.h"
19*c60b897dSRiver Riddle 
20*c60b897dSRiver Riddle using namespace mlir;
21*c60b897dSRiver Riddle using namespace mlir::detail;
22*c60b897dSRiver Riddle using llvm::MemoryBuffer;
23*c60b897dSRiver Riddle using llvm::SourceMgr;
24*c60b897dSRiver Riddle 
25*c60b897dSRiver Riddle namespace {
26*c60b897dSRiver Riddle /// This class provides the main implementation of the DialectAsmParser that
27*c60b897dSRiver Riddle /// allows for dialects to parse attributes and types. This allows for dialect
28*c60b897dSRiver Riddle /// hooking into the main MLIR parsing logic.
29*c60b897dSRiver Riddle class CustomDialectAsmParser : public AsmParserImpl<DialectAsmParser> {
30*c60b897dSRiver Riddle public:
CustomDialectAsmParser(StringRef fullSpec,Parser & parser)31*c60b897dSRiver Riddle   CustomDialectAsmParser(StringRef fullSpec, Parser &parser)
32*c60b897dSRiver Riddle       : AsmParserImpl<DialectAsmParser>(parser.getToken().getLoc(), parser),
33*c60b897dSRiver Riddle         fullSpec(fullSpec) {}
34*c60b897dSRiver Riddle   ~CustomDialectAsmParser() override = default;
35*c60b897dSRiver Riddle 
36*c60b897dSRiver Riddle   /// Returns the full specification of the symbol being parsed. This allows
37*c60b897dSRiver Riddle   /// for using a separate parser if necessary.
getFullSymbolSpec() const38*c60b897dSRiver Riddle   StringRef getFullSymbolSpec() const override { return fullSpec; }
39*c60b897dSRiver Riddle 
40*c60b897dSRiver Riddle private:
41*c60b897dSRiver Riddle   /// The full symbol specification.
42*c60b897dSRiver Riddle   StringRef fullSpec;
43*c60b897dSRiver Riddle };
44*c60b897dSRiver Riddle } // namespace
45*c60b897dSRiver Riddle 
46*c60b897dSRiver Riddle ///
47*c60b897dSRiver Riddle ///   pretty-dialect-sym-body ::= '<' pretty-dialect-sym-contents+ '>'
48*c60b897dSRiver Riddle ///   pretty-dialect-sym-contents ::= pretty-dialect-sym-body
49*c60b897dSRiver Riddle ///                                  | '(' pretty-dialect-sym-contents+ ')'
50*c60b897dSRiver Riddle ///                                  | '[' pretty-dialect-sym-contents+ ']'
51*c60b897dSRiver Riddle ///                                  | '{' pretty-dialect-sym-contents+ '}'
52*c60b897dSRiver Riddle ///                                  | '[^[<({>\])}\0]+'
53*c60b897dSRiver Riddle ///
parseDialectSymbolBody(StringRef & body,bool & isCodeCompletion)54*c60b897dSRiver Riddle ParseResult Parser::parseDialectSymbolBody(StringRef &body,
55*c60b897dSRiver Riddle                                            bool &isCodeCompletion) {
56*c60b897dSRiver Riddle   // Symbol bodies are a relatively unstructured format that contains a series
57*c60b897dSRiver Riddle   // of properly nested punctuation, with anything else in the middle. Scan
58*c60b897dSRiver Riddle   // ahead to find it and consume it if successful, otherwise emit an error.
59*c60b897dSRiver Riddle   const char *curPtr = getTokenSpelling().data();
60*c60b897dSRiver Riddle 
61*c60b897dSRiver Riddle   // Scan over the nested punctuation, bailing out on error and consuming until
62*c60b897dSRiver Riddle   // we find the end. We know that we're currently looking at the '<', so we can
63*c60b897dSRiver Riddle   // go until we find the matching '>' character.
64*c60b897dSRiver Riddle   assert(*curPtr == '<');
65*c60b897dSRiver Riddle   SmallVector<char, 8> nestedPunctuation;
66*c60b897dSRiver Riddle   const char *codeCompleteLoc = state.lex.getCodeCompleteLoc();
67*c60b897dSRiver Riddle   do {
68*c60b897dSRiver Riddle     // Handle code completions, which may appear in the middle of the symbol
69*c60b897dSRiver Riddle     // body.
70*c60b897dSRiver Riddle     if (curPtr == codeCompleteLoc) {
71*c60b897dSRiver Riddle       isCodeCompletion = true;
72*c60b897dSRiver Riddle       nestedPunctuation.clear();
73*c60b897dSRiver Riddle       break;
74*c60b897dSRiver Riddle     }
75*c60b897dSRiver Riddle 
76*c60b897dSRiver Riddle     char c = *curPtr++;
77*c60b897dSRiver Riddle     switch (c) {
78*c60b897dSRiver Riddle     case '\0':
79*c60b897dSRiver Riddle       // This also handles the EOF case.
80*c60b897dSRiver Riddle       if (!nestedPunctuation.empty()) {
81*c60b897dSRiver Riddle         return emitError() << "unbalanced '" << nestedPunctuation.back()
82*c60b897dSRiver Riddle                            << "' character in pretty dialect name";
83*c60b897dSRiver Riddle       }
84*c60b897dSRiver Riddle       return emitError("unexpected nul or EOF in pretty dialect name");
85*c60b897dSRiver Riddle     case '<':
86*c60b897dSRiver Riddle     case '[':
87*c60b897dSRiver Riddle     case '(':
88*c60b897dSRiver Riddle     case '{':
89*c60b897dSRiver Riddle       nestedPunctuation.push_back(c);
90*c60b897dSRiver Riddle       continue;
91*c60b897dSRiver Riddle 
92*c60b897dSRiver Riddle     case '-':
93*c60b897dSRiver Riddle       // The sequence `->` is treated as special token.
94*c60b897dSRiver Riddle       if (*curPtr == '>')
95*c60b897dSRiver Riddle         ++curPtr;
96*c60b897dSRiver Riddle       continue;
97*c60b897dSRiver Riddle 
98*c60b897dSRiver Riddle     case '>':
99*c60b897dSRiver Riddle       if (nestedPunctuation.pop_back_val() != '<')
100*c60b897dSRiver Riddle         return emitError("unbalanced '>' character in pretty dialect name");
101*c60b897dSRiver Riddle       break;
102*c60b897dSRiver Riddle     case ']':
103*c60b897dSRiver Riddle       if (nestedPunctuation.pop_back_val() != '[')
104*c60b897dSRiver Riddle         return emitError("unbalanced ']' character in pretty dialect name");
105*c60b897dSRiver Riddle       break;
106*c60b897dSRiver Riddle     case ')':
107*c60b897dSRiver Riddle       if (nestedPunctuation.pop_back_val() != '(')
108*c60b897dSRiver Riddle         return emitError("unbalanced ')' character in pretty dialect name");
109*c60b897dSRiver Riddle       break;
110*c60b897dSRiver Riddle     case '}':
111*c60b897dSRiver Riddle       if (nestedPunctuation.pop_back_val() != '{')
112*c60b897dSRiver Riddle         return emitError("unbalanced '}' character in pretty dialect name");
113*c60b897dSRiver Riddle       break;
114*c60b897dSRiver Riddle     case '"': {
115*c60b897dSRiver Riddle       // Dispatch to the lexer to lex past strings.
116*c60b897dSRiver Riddle       resetToken(curPtr - 1);
117*c60b897dSRiver Riddle       curPtr = state.curToken.getEndLoc().getPointer();
118*c60b897dSRiver Riddle 
119*c60b897dSRiver Riddle       // Handle code completions, which may appear in the middle of the symbol
120*c60b897dSRiver Riddle       // body.
121*c60b897dSRiver Riddle       if (state.curToken.isCodeCompletion()) {
122*c60b897dSRiver Riddle         isCodeCompletion = true;
123*c60b897dSRiver Riddle         nestedPunctuation.clear();
124*c60b897dSRiver Riddle         break;
125*c60b897dSRiver Riddle       }
126*c60b897dSRiver Riddle 
127*c60b897dSRiver Riddle       // Otherwise, ensure this token was actually a string.
128*c60b897dSRiver Riddle       if (state.curToken.isNot(Token::string))
129*c60b897dSRiver Riddle         return failure();
130*c60b897dSRiver Riddle       break;
131*c60b897dSRiver Riddle     }
132*c60b897dSRiver Riddle 
133*c60b897dSRiver Riddle     default:
134*c60b897dSRiver Riddle       continue;
135*c60b897dSRiver Riddle     }
136*c60b897dSRiver Riddle   } while (!nestedPunctuation.empty());
137*c60b897dSRiver Riddle 
138*c60b897dSRiver Riddle   // Ok, we succeeded, remember where we stopped, reset the lexer to know it is
139*c60b897dSRiver Riddle   // consuming all this stuff, and return.
140*c60b897dSRiver Riddle   resetToken(curPtr);
141*c60b897dSRiver Riddle 
142*c60b897dSRiver Riddle   unsigned length = curPtr - body.begin();
143*c60b897dSRiver Riddle   body = StringRef(body.data(), length);
144*c60b897dSRiver Riddle   return success();
145*c60b897dSRiver Riddle }
146*c60b897dSRiver Riddle 
147*c60b897dSRiver Riddle /// Parse an extended dialect symbol.
148*c60b897dSRiver Riddle template <typename Symbol, typename SymbolAliasMap, typename CreateFn>
parseExtendedSymbol(Parser & p,SymbolAliasMap & aliases,CreateFn && createSymbol)149*c60b897dSRiver Riddle static Symbol parseExtendedSymbol(Parser &p, SymbolAliasMap &aliases,
150*c60b897dSRiver Riddle                                   CreateFn &&createSymbol) {
151*c60b897dSRiver Riddle   Token tok = p.getToken();
152*c60b897dSRiver Riddle 
153*c60b897dSRiver Riddle   // Handle code completion of the extended symbol.
154*c60b897dSRiver Riddle   StringRef identifier = tok.getSpelling().drop_front();
155*c60b897dSRiver Riddle   if (tok.isCodeCompletion() && identifier.empty())
156*c60b897dSRiver Riddle     return p.codeCompleteDialectSymbol(aliases);
157*c60b897dSRiver Riddle 
158*c60b897dSRiver Riddle   // Parse the dialect namespace.
159*c60b897dSRiver Riddle   SMLoc loc = p.getToken().getLoc();
160*c60b897dSRiver Riddle   p.consumeToken();
161*c60b897dSRiver Riddle 
162*c60b897dSRiver Riddle   // Check to see if this is a pretty name.
163*c60b897dSRiver Riddle   StringRef dialectName;
164*c60b897dSRiver Riddle   StringRef symbolData;
165*c60b897dSRiver Riddle   std::tie(dialectName, symbolData) = identifier.split('.');
166*c60b897dSRiver Riddle   bool isPrettyName = !symbolData.empty() || identifier.back() == '.';
167*c60b897dSRiver Riddle 
168*c60b897dSRiver Riddle   // Check to see if the symbol has trailing data, i.e. has an immediately
169*c60b897dSRiver Riddle   // following '<'.
170*c60b897dSRiver Riddle   bool hasTrailingData =
171*c60b897dSRiver Riddle       p.getToken().is(Token::less) &&
172*c60b897dSRiver Riddle       identifier.bytes_end() == p.getTokenSpelling().bytes_begin();
173*c60b897dSRiver Riddle 
174*c60b897dSRiver Riddle   // If there is no '<' token following this, and if the typename contains no
175*c60b897dSRiver Riddle   // dot, then we are parsing a symbol alias.
176*c60b897dSRiver Riddle   if (!hasTrailingData && !isPrettyName) {
177*c60b897dSRiver Riddle     // Check for an alias for this type.
178*c60b897dSRiver Riddle     auto aliasIt = aliases.find(identifier);
179*c60b897dSRiver Riddle     if (aliasIt == aliases.end())
180*c60b897dSRiver Riddle       return (p.emitWrongTokenError("undefined symbol alias id '" + identifier +
181*c60b897dSRiver Riddle                                     "'"),
182*c60b897dSRiver Riddle               nullptr);
183*c60b897dSRiver Riddle     return aliasIt->second;
184*c60b897dSRiver Riddle   }
185*c60b897dSRiver Riddle 
186*c60b897dSRiver Riddle   // If this isn't an alias, we are parsing a dialect-specific symbol. If the
187*c60b897dSRiver Riddle   // name contains a dot, then this is the "pretty" form. If not, it is the
188*c60b897dSRiver Riddle   // verbose form that looks like <...>.
189*c60b897dSRiver Riddle   if (!isPrettyName) {
190*c60b897dSRiver Riddle     // Point the symbol data to the end of the dialect name to start.
191*c60b897dSRiver Riddle     symbolData = StringRef(dialectName.end(), 0);
192*c60b897dSRiver Riddle 
193*c60b897dSRiver Riddle     // Parse the body of the symbol.
194*c60b897dSRiver Riddle     bool isCodeCompletion = false;
195*c60b897dSRiver Riddle     if (p.parseDialectSymbolBody(symbolData, isCodeCompletion))
196*c60b897dSRiver Riddle       return nullptr;
197*c60b897dSRiver Riddle     symbolData = symbolData.drop_front();
198*c60b897dSRiver Riddle 
199*c60b897dSRiver Riddle     // If the body contained a code completion it won't have the trailing `>`
200*c60b897dSRiver Riddle     // token, so don't drop it.
201*c60b897dSRiver Riddle     if (!isCodeCompletion)
202*c60b897dSRiver Riddle       symbolData = symbolData.drop_back();
203*c60b897dSRiver Riddle   } else {
204*c60b897dSRiver Riddle     loc = SMLoc::getFromPointer(symbolData.data());
205*c60b897dSRiver Riddle 
206*c60b897dSRiver Riddle     // If the dialect's symbol is followed immediately by a <, then lex the body
207*c60b897dSRiver Riddle     // of it into prettyName.
208*c60b897dSRiver Riddle     if (hasTrailingData && p.parseDialectSymbolBody(symbolData))
209*c60b897dSRiver Riddle       return nullptr;
210*c60b897dSRiver Riddle   }
211*c60b897dSRiver Riddle 
212*c60b897dSRiver Riddle   return createSymbol(dialectName, symbolData, loc);
213*c60b897dSRiver Riddle }
214*c60b897dSRiver Riddle 
215*c60b897dSRiver Riddle /// Parse an extended attribute.
216*c60b897dSRiver Riddle ///
217*c60b897dSRiver Riddle ///   extended-attribute ::= (dialect-attribute | attribute-alias)
218*c60b897dSRiver Riddle ///   dialect-attribute  ::= `#` dialect-namespace `<` `"` attr-data `"` `>`
219*c60b897dSRiver Riddle ///   dialect-attribute  ::= `#` alias-name pretty-dialect-sym-body?
220*c60b897dSRiver Riddle ///   attribute-alias    ::= `#` alias-name
221*c60b897dSRiver Riddle ///
parseExtendedAttr(Type type)222*c60b897dSRiver Riddle Attribute Parser::parseExtendedAttr(Type type) {
223*c60b897dSRiver Riddle   MLIRContext *ctx = getContext();
224*c60b897dSRiver Riddle   Attribute attr = parseExtendedSymbol<Attribute>(
225*c60b897dSRiver Riddle       *this, state.symbols.attributeAliasDefinitions,
226*c60b897dSRiver Riddle       [&](StringRef dialectName, StringRef symbolData, SMLoc loc) -> Attribute {
227*c60b897dSRiver Riddle         // Parse an optional trailing colon type.
228*c60b897dSRiver Riddle         Type attrType = type;
229*c60b897dSRiver Riddle         if (consumeIf(Token::colon) && !(attrType = parseType()))
230*c60b897dSRiver Riddle           return Attribute();
231*c60b897dSRiver Riddle 
232*c60b897dSRiver Riddle         // If we found a registered dialect, then ask it to parse the attribute.
233*c60b897dSRiver Riddle         if (Dialect *dialect =
234*c60b897dSRiver Riddle                 builder.getContext()->getOrLoadDialect(dialectName)) {
235*c60b897dSRiver Riddle           // Temporarily reset the lexer to let the dialect parse the attribute.
236*c60b897dSRiver Riddle           const char *curLexerPos = getToken().getLoc().getPointer();
237*c60b897dSRiver Riddle           resetToken(symbolData.data());
238*c60b897dSRiver Riddle 
239*c60b897dSRiver Riddle           // Parse the attribute.
240*c60b897dSRiver Riddle           CustomDialectAsmParser customParser(symbolData, *this);
241*c60b897dSRiver Riddle           Attribute attr = dialect->parseAttribute(customParser, attrType);
242*c60b897dSRiver Riddle           resetToken(curLexerPos);
243*c60b897dSRiver Riddle           return attr;
244*c60b897dSRiver Riddle         }
245*c60b897dSRiver Riddle 
246*c60b897dSRiver Riddle         // Otherwise, form a new opaque attribute.
247*c60b897dSRiver Riddle         return OpaqueAttr::getChecked(
248*c60b897dSRiver Riddle             [&] { return emitError(loc); }, StringAttr::get(ctx, dialectName),
249*c60b897dSRiver Riddle             symbolData, attrType ? attrType : NoneType::get(ctx));
250*c60b897dSRiver Riddle       });
251*c60b897dSRiver Riddle 
252*c60b897dSRiver Riddle   // Ensure that the attribute has the same type as requested.
253*c60b897dSRiver Riddle   if (attr && type && attr.getType() != type) {
254*c60b897dSRiver Riddle     emitError("attribute type different than expected: expected ")
255*c60b897dSRiver Riddle         << type << ", but got " << attr.getType();
256*c60b897dSRiver Riddle     return nullptr;
257*c60b897dSRiver Riddle   }
258*c60b897dSRiver Riddle   return attr;
259*c60b897dSRiver Riddle }
260*c60b897dSRiver Riddle 
261*c60b897dSRiver Riddle /// Parse an extended type.
262*c60b897dSRiver Riddle ///
263*c60b897dSRiver Riddle ///   extended-type ::= (dialect-type | type-alias)
264*c60b897dSRiver Riddle ///   dialect-type  ::= `!` dialect-namespace `<` `"` type-data `"` `>`
265*c60b897dSRiver Riddle ///   dialect-type  ::= `!` alias-name pretty-dialect-attribute-body?
266*c60b897dSRiver Riddle ///   type-alias    ::= `!` alias-name
267*c60b897dSRiver Riddle ///
parseExtendedType()268*c60b897dSRiver Riddle Type Parser::parseExtendedType() {
269*c60b897dSRiver Riddle   MLIRContext *ctx = getContext();
270*c60b897dSRiver Riddle   return parseExtendedSymbol<Type>(
271*c60b897dSRiver Riddle       *this, state.symbols.typeAliasDefinitions,
272*c60b897dSRiver Riddle       [&](StringRef dialectName, StringRef symbolData, SMLoc loc) -> Type {
273*c60b897dSRiver Riddle         // If we found a registered dialect, then ask it to parse the type.
274*c60b897dSRiver Riddle         if (auto *dialect = ctx->getOrLoadDialect(dialectName)) {
275*c60b897dSRiver Riddle           // Temporarily reset the lexer to let the dialect parse the type.
276*c60b897dSRiver Riddle           const char *curLexerPos = getToken().getLoc().getPointer();
277*c60b897dSRiver Riddle           resetToken(symbolData.data());
278*c60b897dSRiver Riddle 
279*c60b897dSRiver Riddle           // Parse the type.
280*c60b897dSRiver Riddle           CustomDialectAsmParser customParser(symbolData, *this);
281*c60b897dSRiver Riddle           Type type = dialect->parseType(customParser);
282*c60b897dSRiver Riddle           resetToken(curLexerPos);
283*c60b897dSRiver Riddle           return type;
284*c60b897dSRiver Riddle         }
285*c60b897dSRiver Riddle 
286*c60b897dSRiver Riddle         // Otherwise, form a new opaque type.
287*c60b897dSRiver Riddle         return OpaqueType::getChecked([&] { return emitError(loc); },
288*c60b897dSRiver Riddle                                       StringAttr::get(ctx, dialectName),
289*c60b897dSRiver Riddle                                       symbolData);
290*c60b897dSRiver Riddle       });
291*c60b897dSRiver Riddle }
292*c60b897dSRiver Riddle 
293*c60b897dSRiver Riddle //===----------------------------------------------------------------------===//
294*c60b897dSRiver Riddle // mlir::parseAttribute/parseType
295*c60b897dSRiver Riddle //===----------------------------------------------------------------------===//
296*c60b897dSRiver Riddle 
297*c60b897dSRiver Riddle /// Parses a symbol, of type 'T', and returns it if parsing was successful. If
298*c60b897dSRiver Riddle /// parsing failed, nullptr is returned. The number of bytes read from the input
299*c60b897dSRiver Riddle /// string is returned in 'numRead'.
300*c60b897dSRiver Riddle template <typename T, typename ParserFn>
parseSymbol(StringRef inputStr,MLIRContext * context,size_t & numRead,ParserFn && parserFn)301*c60b897dSRiver Riddle static T parseSymbol(StringRef inputStr, MLIRContext *context, size_t &numRead,
302*c60b897dSRiver Riddle                      ParserFn &&parserFn) {
303*c60b897dSRiver Riddle   SourceMgr sourceMgr;
304*c60b897dSRiver Riddle   auto memBuffer = MemoryBuffer::getMemBuffer(
305*c60b897dSRiver Riddle       inputStr, /*BufferName=*/"<mlir_parser_buffer>",
306*c60b897dSRiver Riddle       /*RequiresNullTerminator=*/false);
307*c60b897dSRiver Riddle   sourceMgr.AddNewSourceBuffer(std::move(memBuffer), SMLoc());
308*c60b897dSRiver Riddle   SymbolState aliasState;
309*c60b897dSRiver Riddle   ParserConfig config(context);
310*c60b897dSRiver Riddle   ParserState state(sourceMgr, config, aliasState, /*asmState=*/nullptr,
311*c60b897dSRiver Riddle                     /*codeCompleteContext=*/nullptr);
312*c60b897dSRiver Riddle   Parser parser(state);
313*c60b897dSRiver Riddle 
314*c60b897dSRiver Riddle   SourceMgrDiagnosticHandler handler(
315*c60b897dSRiver Riddle       const_cast<llvm::SourceMgr &>(parser.getSourceMgr()),
316*c60b897dSRiver Riddle       parser.getContext());
317*c60b897dSRiver Riddle   Token startTok = parser.getToken();
318*c60b897dSRiver Riddle   T symbol = parserFn(parser);
319*c60b897dSRiver Riddle   if (!symbol)
320*c60b897dSRiver Riddle     return T();
321*c60b897dSRiver Riddle 
322*c60b897dSRiver Riddle   // Provide the number of bytes that were read.
323*c60b897dSRiver Riddle   Token endTok = parser.getToken();
324*c60b897dSRiver Riddle   numRead = static_cast<size_t>(endTok.getLoc().getPointer() -
325*c60b897dSRiver Riddle                                 startTok.getLoc().getPointer());
326*c60b897dSRiver Riddle   return symbol;
327*c60b897dSRiver Riddle }
328*c60b897dSRiver Riddle 
parseAttribute(StringRef attrStr,MLIRContext * context)329*c60b897dSRiver Riddle Attribute mlir::parseAttribute(StringRef attrStr, MLIRContext *context) {
330*c60b897dSRiver Riddle   size_t numRead = 0;
331*c60b897dSRiver Riddle   return parseAttribute(attrStr, context, numRead);
332*c60b897dSRiver Riddle }
parseAttribute(StringRef attrStr,Type type)333*c60b897dSRiver Riddle Attribute mlir::parseAttribute(StringRef attrStr, Type type) {
334*c60b897dSRiver Riddle   size_t numRead = 0;
335*c60b897dSRiver Riddle   return parseAttribute(attrStr, type, numRead);
336*c60b897dSRiver Riddle }
337*c60b897dSRiver Riddle 
parseAttribute(StringRef attrStr,MLIRContext * context,size_t & numRead)338*c60b897dSRiver Riddle Attribute mlir::parseAttribute(StringRef attrStr, MLIRContext *context,
339*c60b897dSRiver Riddle                                size_t &numRead) {
340*c60b897dSRiver Riddle   return parseSymbol<Attribute>(attrStr, context, numRead, [](Parser &parser) {
341*c60b897dSRiver Riddle     return parser.parseAttribute();
342*c60b897dSRiver Riddle   });
343*c60b897dSRiver Riddle }
parseAttribute(StringRef attrStr,Type type,size_t & numRead)344*c60b897dSRiver Riddle Attribute mlir::parseAttribute(StringRef attrStr, Type type, size_t &numRead) {
345*c60b897dSRiver Riddle   return parseSymbol<Attribute>(
346*c60b897dSRiver Riddle       attrStr, type.getContext(), numRead,
347*c60b897dSRiver Riddle       [type](Parser &parser) { return parser.parseAttribute(type); });
348*c60b897dSRiver Riddle }
349*c60b897dSRiver Riddle 
parseType(StringRef typeStr,MLIRContext * context)350*c60b897dSRiver Riddle Type mlir::parseType(StringRef typeStr, MLIRContext *context) {
351*c60b897dSRiver Riddle   size_t numRead = 0;
352*c60b897dSRiver Riddle   return parseType(typeStr, context, numRead);
353*c60b897dSRiver Riddle }
354*c60b897dSRiver Riddle 
parseType(StringRef typeStr,MLIRContext * context,size_t & numRead)355*c60b897dSRiver Riddle Type mlir::parseType(StringRef typeStr, MLIRContext *context, size_t &numRead) {
356*c60b897dSRiver Riddle   return parseSymbol<Type>(typeStr, context, numRead,
357*c60b897dSRiver Riddle                            [](Parser &parser) { return parser.parseType(); });
358*c60b897dSRiver Riddle }
359