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