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