xref: /llvm-project/mlir/lib/AsmParser/Parser.h (revision 01e75646a5d4977a9e441e3db1042df0beccc4bb)
1 //===- Parser.h - MLIR Base Parser 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_PARSER_H
10 #define MLIR_LIB_ASMPARSER_PARSER_H
11 
12 #include "ParserState.h"
13 #include "mlir/IR/Builders.h"
14 #include "mlir/IR/OpImplementation.h"
15 #include <optional>
16 
17 namespace mlir {
18 namespace detail {
19 
20 //===----------------------------------------------------------------------===//
21 // Parser
22 //===----------------------------------------------------------------------===//
23 
24 /// This class implement support for parsing global entities like attributes and
25 /// types. It is intended to be subclassed by specialized subparsers that
26 /// include state.
27 class Parser {
28 public:
29   using Delimiter = OpAsmParser::Delimiter;
30 
31   Builder builder;
32 
33   Parser(ParserState &state)
34       : builder(state.config.getContext()), state(state) {}
35 
36   // Helper methods to get stuff from the parser-global state.
37   ParserState &getState() const { return state; }
38   MLIRContext *getContext() const { return state.config.getContext(); }
39   const llvm::SourceMgr &getSourceMgr() { return state.lex.getSourceMgr(); }
40 
41   /// Parse a comma-separated list of elements up until the specified end token.
42   ParseResult
43   parseCommaSeparatedListUntil(Token::Kind rightToken,
44                                function_ref<ParseResult()> parseElement,
45                                bool allowEmptyList = true);
46 
47   /// Parse a list of comma-separated items with an optional delimiter.  If a
48   /// delimiter is provided, then an empty list is allowed.  If not, then at
49   /// least one element will be parsed.
50   ParseResult
51   parseCommaSeparatedList(Delimiter delimiter,
52                           function_ref<ParseResult()> parseElementFn,
53                           StringRef contextMessage = StringRef());
54 
55   /// Parse a comma separated list of elements that must have at least one entry
56   /// in it.
57   ParseResult
58   parseCommaSeparatedList(function_ref<ParseResult()> parseElementFn) {
59     return parseCommaSeparatedList(Delimiter::None, parseElementFn);
60   }
61 
62   /// Parse the body of a dialect symbol, which starts and ends with <>'s, and
63   /// may be recursive. Return with the 'body' StringRef encompassing the entire
64   /// body. `isCodeCompletion` is set to true if the body contained a code
65   /// completion location, in which case the body is only populated up to the
66   /// completion.
67   ParseResult parseDialectSymbolBody(StringRef &body, bool &isCodeCompletion);
68   ParseResult parseDialectSymbolBody(StringRef &body) {
69     bool isCodeCompletion = false;
70     return parseDialectSymbolBody(body, isCodeCompletion);
71   }
72 
73   // We have two forms of parsing methods - those that return a non-null
74   // pointer on success, and those that return a ParseResult to indicate whether
75   // they returned a failure.  The second class fills in by-reference arguments
76   // as the results of their action.
77 
78   //===--------------------------------------------------------------------===//
79   // Error Handling
80   //===--------------------------------------------------------------------===//
81 
82   /// Emit an error and return failure.
83   InFlightDiagnostic emitError(const Twine &message = {});
84   InFlightDiagnostic emitError(SMLoc loc, const Twine &message = {});
85 
86   /// Emit an error about a "wrong token".  If the current token is at the
87   /// start of a source line, this will apply heuristics to back up and report
88   /// the error at the end of the previous line, which is where the expected
89   /// token is supposed to be.
90   InFlightDiagnostic emitWrongTokenError(const Twine &message = {});
91 
92   /// Encode the specified source location information into an attribute for
93   /// attachment to the IR.
94   Location getEncodedSourceLocation(SMLoc loc) {
95     return state.lex.getEncodedSourceLocation(loc);
96   }
97 
98   //===--------------------------------------------------------------------===//
99   // Token Parsing
100   //===--------------------------------------------------------------------===//
101 
102   /// Return the current token the parser is inspecting.
103   const Token &getToken() const { return state.curToken; }
104   StringRef getTokenSpelling() const { return state.curToken.getSpelling(); }
105 
106   /// Return the last parsed token.
107   const Token &getLastToken() const { return state.lastToken; }
108 
109   /// If the current token has the specified kind, consume it and return true.
110   /// If not, return false.
111   bool consumeIf(Token::Kind kind) {
112     if (state.curToken.isNot(kind))
113       return false;
114     consumeToken(kind);
115     return true;
116   }
117 
118   /// Advance the current lexer onto the next token.
119   void consumeToken() {
120     assert(state.curToken.isNot(Token::eof, Token::error) &&
121            "shouldn't advance past EOF or errors");
122     state.lastToken = state.curToken;
123     state.curToken = state.lex.lexToken();
124   }
125 
126   /// Advance the current lexer onto the next token, asserting what the expected
127   /// current token is.  This is preferred to the above method because it leads
128   /// to more self-documenting code with better checking.
129   void consumeToken(Token::Kind kind) {
130     assert(state.curToken.is(kind) && "consumed an unexpected token");
131     consumeToken();
132   }
133 
134   /// Reset the parser to the given lexer position. Resetting the parser/lexer
135   /// position does not update 'state.lastToken'. 'state.lastToken' is the
136   /// last parsed token, and is used to provide the scope end location for
137   /// OperationDefinitions. To ensure the correctness of the end location, the
138   /// last consumed token of an OperationDefinition needs to be the last token
139   /// belonging to it.
140   void resetToken(const char *tokPos) {
141     state.lex.resetPointer(tokPos);
142     state.curToken = state.lex.lexToken();
143   }
144 
145   /// Consume the specified token if present and return success.  On failure,
146   /// output a diagnostic and return failure.
147   ParseResult parseToken(Token::Kind expectedToken, const Twine &message);
148 
149   /// Parse an optional integer value from the stream.
150   OptionalParseResult parseOptionalInteger(APInt &result);
151 
152   /// Parse an optional integer value only in decimal format from the stream.
153   OptionalParseResult parseOptionalDecimalInteger(APInt &result);
154 
155   /// Parse a floating point value from a literal.
156   ParseResult parseFloatFromLiteral(std::optional<APFloat> &result,
157                                     const Token &tok, bool isNegative,
158                                     const llvm::fltSemantics &semantics);
159 
160   /// Parse a floating point value from an integer literal token.
161   ParseResult parseFloatFromIntegerLiteral(std::optional<APFloat> &result,
162                                            const Token &tok, bool isNegative,
163                                            const llvm::fltSemantics &semantics);
164 
165   /// Returns true if the current token corresponds to a keyword.
166   bool isCurrentTokenAKeyword() const {
167     return getToken().isAny(Token::bare_identifier, Token::inttype) ||
168            getToken().isKeyword();
169   }
170 
171   /// Parse a keyword, if present, into 'keyword'.
172   ParseResult parseOptionalKeyword(StringRef *keyword);
173 
174   //===--------------------------------------------------------------------===//
175   // Resource Parsing
176   //===--------------------------------------------------------------------===//
177 
178   /// Parse a handle to a dialect resource within the assembly format.
179   FailureOr<AsmDialectResourceHandle>
180   parseResourceHandle(const OpAsmDialectInterface *dialect, StringRef &name);
181   FailureOr<AsmDialectResourceHandle> parseResourceHandle(Dialect *dialect);
182 
183   //===--------------------------------------------------------------------===//
184   // Type Parsing
185   //===--------------------------------------------------------------------===//
186 
187   /// Invoke the `getChecked` method of the given Attribute or Type class, using
188   /// the provided location to emit errors in the case of failure. Note that
189   /// unlike `OpBuilder::getType`, this method does not implicitly insert a
190   /// context parameter.
191   template <typename T, typename... ParamsT>
192   T getChecked(SMLoc loc, ParamsT &&...params) {
193     return T::getChecked([&] { return emitError(loc); },
194                          std::forward<ParamsT>(params)...);
195   }
196 
197   ParseResult parseFunctionResultTypes(SmallVectorImpl<Type> &elements);
198   ParseResult parseTypeListNoParens(SmallVectorImpl<Type> &elements);
199   ParseResult parseTypeListParens(SmallVectorImpl<Type> &elements);
200 
201   /// Optionally parse a type.
202   OptionalParseResult parseOptionalType(Type &type);
203 
204   /// Parse an arbitrary type.
205   Type parseType();
206 
207   /// Parse a complex type.
208   Type parseComplexType();
209 
210   /// Parse an extended type.
211   Type parseExtendedType();
212 
213   /// Parse a function type.
214   Type parseFunctionType();
215 
216   /// Parse a memref type.
217   Type parseMemRefType();
218 
219   /// Parse a non function type.
220   Type parseNonFunctionType();
221 
222   /// Parse a tensor type.
223   Type parseTensorType();
224 
225   /// Parse a tuple type.
226   Type parseTupleType();
227 
228   /// Parse a vector type.
229   VectorType parseVectorType();
230   ParseResult parseVectorDimensionList(SmallVectorImpl<int64_t> &dimensions,
231                                        SmallVectorImpl<bool> &scalableDims);
232   ParseResult parseDimensionListRanked(SmallVectorImpl<int64_t> &dimensions,
233                                        bool allowDynamic = true,
234                                        bool withTrailingX = true);
235   ParseResult parseIntegerInDimensionList(int64_t &value);
236   ParseResult parseXInDimensionList();
237 
238   //===--------------------------------------------------------------------===//
239   // Attribute Parsing
240   //===--------------------------------------------------------------------===//
241 
242   /// Parse an arbitrary attribute with an optional type.
243   Attribute parseAttribute(Type type = {});
244 
245   /// Parse an optional attribute with the provided type.
246   OptionalParseResult parseOptionalAttribute(Attribute &attribute,
247                                              Type type = {});
248   OptionalParseResult parseOptionalAttribute(ArrayAttr &attribute, Type type);
249   OptionalParseResult parseOptionalAttribute(StringAttr &attribute, Type type);
250   OptionalParseResult parseOptionalAttribute(SymbolRefAttr &result, Type type);
251 
252   /// Parse an optional attribute that is demarcated by a specific token.
253   template <typename AttributeT>
254   OptionalParseResult parseOptionalAttributeWithToken(Token::Kind kind,
255                                                       AttributeT &attr,
256                                                       Type type = {}) {
257     if (getToken().isNot(kind))
258       return std::nullopt;
259 
260     if (Attribute parsedAttr = parseAttribute(type)) {
261       attr = cast<AttributeT>(parsedAttr);
262       return success();
263     }
264     return failure();
265   }
266 
267   /// Parse an attribute dictionary.
268   ParseResult parseAttributeDict(NamedAttrList &attributes);
269 
270   /// Parse a distinct attribute.
271   Attribute parseDistinctAttr(Type type);
272 
273   /// Parse an extended attribute.
274   Attribute parseExtendedAttr(Type type);
275 
276   /// Parse a float attribute.
277   Attribute parseFloatAttr(Type type, bool isNegative);
278 
279   /// Parse a decimal or a hexadecimal literal, which can be either an integer
280   /// or a float attribute.
281   Attribute parseDecOrHexAttr(Type type, bool isNegative);
282 
283   /// Parse a dense elements attribute.
284   Attribute parseDenseElementsAttr(Type attrType);
285   ShapedType parseElementsLiteralType(Type type);
286 
287   /// Parse a dense resource elements attribute.
288   Attribute parseDenseResourceElementsAttr(Type attrType);
289 
290   /// Parse a DenseArrayAttr.
291   Attribute parseDenseArrayAttr(Type type);
292 
293   /// Parse a sparse elements attribute.
294   Attribute parseSparseElementsAttr(Type attrType);
295 
296   /// Parse a strided layout attribute.
297   Attribute parseStridedLayoutAttr();
298 
299   //===--------------------------------------------------------------------===//
300   // Location Parsing
301   //===--------------------------------------------------------------------===//
302 
303   /// Parse a raw location instance.
304   ParseResult parseLocationInstance(LocationAttr &loc);
305 
306   /// Parse a callsite location instance.
307   ParseResult parseCallSiteLocation(LocationAttr &loc);
308 
309   /// Parse a fused location instance.
310   ParseResult parseFusedLocation(LocationAttr &loc);
311 
312   /// Parse a name or FileLineCol location instance.
313   ParseResult parseNameOrFileLineColRange(LocationAttr &loc);
314 
315   //===--------------------------------------------------------------------===//
316   // Affine Parsing
317   //===--------------------------------------------------------------------===//
318 
319   /// Parse a reference to either an affine map, expr, or an integer set.
320   ParseResult parseAffineMapOrIntegerSetReference(AffineMap &map,
321                                                   IntegerSet &set);
322   ParseResult parseAffineMapReference(AffineMap &map);
323   ParseResult
324   parseAffineExprReference(ArrayRef<std::pair<StringRef, AffineExpr>> symbolSet,
325                            AffineExpr &expr);
326   ParseResult parseIntegerSetReference(IntegerSet &set);
327 
328   /// Parse an AffineMap where the dim and symbol identifiers are SSA ids.
329   ParseResult
330   parseAffineMapOfSSAIds(AffineMap &map,
331                          function_ref<ParseResult(bool)> parseElement,
332                          Delimiter delimiter);
333 
334   /// Parse an AffineExpr where dim and symbol identifiers are SSA ids.
335   ParseResult
336   parseAffineExprOfSSAIds(AffineExpr &expr,
337                           function_ref<ParseResult(bool)> parseElement);
338 
339   //===--------------------------------------------------------------------===//
340   // Code Completion
341   //===--------------------------------------------------------------------===//
342 
343   /// The set of various code completion methods. Every completion method
344   /// returns `failure` to signal that parsing should abort after any desired
345   /// completions have been enqueued. Note that `failure` is does not mean
346   /// completion failed, it's just a signal to the parser to stop.
347 
348   ParseResult codeCompleteDialectName();
349   ParseResult codeCompleteOperationName(StringRef dialectName);
350   ParseResult codeCompleteDialectOrElidedOpName(SMLoc loc);
351   ParseResult codeCompleteStringDialectOrOperationName(StringRef name);
352   ParseResult codeCompleteExpectedTokens(ArrayRef<StringRef> tokens);
353   ParseResult codeCompleteOptionalTokens(ArrayRef<StringRef> tokens);
354 
355   Attribute codeCompleteAttribute();
356   Type codeCompleteType();
357   Attribute
358   codeCompleteDialectSymbol(const llvm::StringMap<Attribute> &aliases);
359   Type codeCompleteDialectSymbol(const llvm::StringMap<Type> &aliases);
360 
361 protected:
362   /// The Parser is subclassed and reinstantiated.  Do not add additional
363   /// non-trivial state here, add it to the ParserState class.
364   ParserState &state;
365 };
366 } // namespace detail
367 } // namespace mlir
368 
369 #endif // MLIR_LIB_ASMPARSER_PARSER_H
370