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_PARSER_PARSER_H
10 #define MLIR_LIB_PARSER_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) : builder(state.context), state(state) {}
32 
33   // Helper methods to get stuff from the parser-global state.
getState()34   ParserState &getState() const { return state; }
getContext()35   MLIRContext *getContext() const { return state.context; }
getSourceMgr()36   const llvm::SourceMgr &getSourceMgr() { return state.lex.getSourceMgr(); }
37 
38   /// Parse a comma-separated list of elements up until the specified end token.
39   ParseResult
40   parseCommaSeparatedListUntil(Token::Kind rightToken,
41                                function_ref<ParseResult()> parseElement,
42                                bool allowEmptyList = true);
43 
44   /// Parse a list of comma-separated items with an optional delimiter.  If a
45   /// delimiter is provided, then an empty list is allowed.  If not, then at
46   /// least one element will be parsed.
47   ParseResult
48   parseCommaSeparatedList(Delimiter delimiter,
49                           function_ref<ParseResult()> parseElementFn,
50                           StringRef contextMessage = StringRef());
51 
52   /// Parse a comma separated list of elements that must have at least one entry
53   /// in it.
54   ParseResult
parseCommaSeparatedList(function_ref<ParseResult ()> parseElementFn)55   parseCommaSeparatedList(function_ref<ParseResult()> parseElementFn) {
56     return parseCommaSeparatedList(Delimiter::None, parseElementFn);
57   }
58 
59   ParseResult parsePrettyDialectSymbolName(StringRef &prettyName);
60 
61   // We have two forms of parsing methods - those that return a non-null
62   // pointer on success, and those that return a ParseResult to indicate whether
63   // they returned a failure.  The second class fills in by-reference arguments
64   // as the results of their action.
65 
66   //===--------------------------------------------------------------------===//
67   // Error Handling
68   //===--------------------------------------------------------------------===//
69 
70   /// Emit an error and return failure.
71   InFlightDiagnostic emitError(const Twine &message = {}) {
72     return emitError(state.curToken.getLoc(), message);
73   }
74   InFlightDiagnostic emitError(llvm::SMLoc loc, const Twine &message = {});
75 
76   /// Encode the specified source location information into an attribute for
77   /// attachment to the IR.
getEncodedSourceLocation(llvm::SMLoc loc)78   Location getEncodedSourceLocation(llvm::SMLoc loc) {
79     // If there are no active nested parsers, we can get the encoded source
80     // location directly.
81     if (state.parserDepth == 0)
82       return state.lex.getEncodedSourceLocation(loc);
83     // Otherwise, we need to re-encode it to point to the top level buffer.
84     return state.symbols.topLevelLexer->getEncodedSourceLocation(
85         remapLocationToTopLevelBuffer(loc));
86   }
87 
88   /// Remaps the given SMLoc to the top level lexer of the parser. This is used
89   /// to adjust locations of potentially nested parsers to ensure that they can
90   /// be emitted properly as diagnostics.
remapLocationToTopLevelBuffer(llvm::SMLoc loc)91   llvm::SMLoc remapLocationToTopLevelBuffer(llvm::SMLoc loc) {
92     // If there are no active nested parsers, we can return location directly.
93     SymbolState &symbols = state.symbols;
94     if (state.parserDepth == 0)
95       return loc;
96     assert(symbols.topLevelLexer && "expected valid top-level lexer");
97 
98     // Otherwise, we need to remap the location to the main parser. This is
99     // simply offseting the location onto the location of the last nested
100     // parser.
101     size_t offset = loc.getPointer() - state.lex.getBufferBegin();
102     auto *rawLoc =
103         symbols.nestedParserLocs[state.parserDepth - 1].getPointer() + offset;
104     return llvm::SMLoc::getFromPointer(rawLoc);
105   }
106 
107   //===--------------------------------------------------------------------===//
108   // Token Parsing
109   //===--------------------------------------------------------------------===//
110 
111   /// Return the current token the parser is inspecting.
getToken()112   const Token &getToken() const { return state.curToken; }
getTokenSpelling()113   StringRef getTokenSpelling() const { return state.curToken.getSpelling(); }
114 
115   /// If the current token has the specified kind, consume it and return true.
116   /// If not, return false.
consumeIf(Token::Kind kind)117   bool consumeIf(Token::Kind kind) {
118     if (state.curToken.isNot(kind))
119       return false;
120     consumeToken(kind);
121     return true;
122   }
123 
124   /// Advance the current lexer onto the next token.
consumeToken()125   void consumeToken() {
126     assert(state.curToken.isNot(Token::eof, Token::error) &&
127            "shouldn't advance past EOF or errors");
128     state.curToken = state.lex.lexToken();
129   }
130 
131   /// Advance the current lexer onto the next token, asserting what the expected
132   /// current token is.  This is preferred to the above method because it leads
133   /// to more self-documenting code with better checking.
consumeToken(Token::Kind kind)134   void consumeToken(Token::Kind kind) {
135     assert(state.curToken.is(kind) && "consumed an unexpected token");
136     consumeToken();
137   }
138 
139   /// Consume the specified token if present and return success.  On failure,
140   /// output a diagnostic and return failure.
141   ParseResult parseToken(Token::Kind expectedToken, const Twine &message);
142 
143   /// Parse an optional integer value from the stream.
144   OptionalParseResult parseOptionalInteger(APInt &result);
145 
146   /// Parse a floating point value from an integer literal token.
147   ParseResult parseFloatFromIntegerLiteral(Optional<APFloat> &result,
148                                            const Token &tok, bool isNegative,
149                                            const llvm::fltSemantics &semantics,
150                                            size_t typeSizeInBits);
151 
152   //===--------------------------------------------------------------------===//
153   // Type Parsing
154   //===--------------------------------------------------------------------===//
155 
156   /// Invoke the `getChecked` method of the given Attribute or Type class, using
157   /// the provided location to emit errors in the case of failure. Note that
158   /// unlike `OpBuilder::getType`, this method does not implicitly insert a
159   /// context parameter.
160   template <typename T, typename... ParamsT>
getChecked(llvm::SMLoc loc,ParamsT &&...params)161   T getChecked(llvm::SMLoc loc, ParamsT &&...params) {
162     return T::getChecked([&] { return emitError(loc); },
163                          std::forward<ParamsT>(params)...);
164   }
165 
166   ParseResult parseFunctionResultTypes(SmallVectorImpl<Type> &elements);
167   ParseResult parseTypeListNoParens(SmallVectorImpl<Type> &elements);
168   ParseResult parseTypeListParens(SmallVectorImpl<Type> &elements);
169 
170   /// Optionally parse a type.
171   OptionalParseResult parseOptionalType(Type &type);
172 
173   /// Parse an arbitrary type.
174   Type parseType();
175 
176   /// Parse a complex type.
177   Type parseComplexType();
178 
179   /// Parse an extended type.
180   Type parseExtendedType();
181 
182   /// Parse a function type.
183   Type parseFunctionType();
184 
185   /// Parse a memref type.
186   Type parseMemRefType();
187 
188   /// Parse a non function type.
189   Type parseNonFunctionType();
190 
191   /// Parse a tensor type.
192   Type parseTensorType();
193 
194   /// Parse a tuple type.
195   Type parseTupleType();
196 
197   /// Parse a vector type.
198   VectorType parseVectorType();
199   ParseResult parseDimensionListRanked(SmallVectorImpl<int64_t> &dimensions,
200                                        bool allowDynamic = true);
201   ParseResult parseXInDimensionList();
202 
203   /// Parse strided layout specification.
204   ParseResult parseStridedLayout(int64_t &offset,
205                                  SmallVectorImpl<int64_t> &strides);
206 
207   // Parse a brace-delimiter list of comma-separated integers with `?` as an
208   // unknown marker.
209   ParseResult parseStrideList(SmallVectorImpl<int64_t> &dimensions);
210 
211   //===--------------------------------------------------------------------===//
212   // Attribute Parsing
213   //===--------------------------------------------------------------------===//
214 
215   /// Parse an arbitrary attribute with an optional type.
216   Attribute parseAttribute(Type type = {});
217 
218   /// Parse an optional attribute with the provided type.
219   OptionalParseResult parseOptionalAttribute(Attribute &attribute,
220                                              Type type = {});
221   OptionalParseResult parseOptionalAttribute(ArrayAttr &attribute, Type type);
222   OptionalParseResult parseOptionalAttribute(StringAttr &attribute, Type type);
223 
224   /// Parse an optional attribute that is demarcated by a specific token.
225   template <typename AttributeT>
226   OptionalParseResult parseOptionalAttributeWithToken(Token::Kind kind,
227                                                       AttributeT &attr,
228                                                       Type type = {}) {
229     if (getToken().isNot(kind))
230       return llvm::None;
231 
232     if (Attribute parsedAttr = parseAttribute(type)) {
233       attr = parsedAttr.cast<AttributeT>();
234       return success();
235     }
236     return failure();
237   }
238 
239   /// Parse an attribute dictionary.
240   ParseResult parseAttributeDict(NamedAttrList &attributes);
241 
242   /// Parse an extended attribute.
243   Attribute parseExtendedAttr(Type type);
244 
245   /// Parse a float attribute.
246   Attribute parseFloatAttr(Type type, bool isNegative);
247 
248   /// Parse a decimal or a hexadecimal literal, which can be either an integer
249   /// or a float attribute.
250   Attribute parseDecOrHexAttr(Type type, bool isNegative);
251 
252   /// Parse an opaque elements attribute.
253   Attribute parseOpaqueElementsAttr(Type attrType);
254 
255   /// Parse a dense elements attribute.
256   Attribute parseDenseElementsAttr(Type attrType);
257   ShapedType parseElementsLiteralType(Type type);
258 
259   /// Parse a sparse elements attribute.
260   Attribute parseSparseElementsAttr(Type attrType);
261 
262   //===--------------------------------------------------------------------===//
263   // Location Parsing
264   //===--------------------------------------------------------------------===//
265 
266   /// Parse a raw location instance.
267   ParseResult parseLocationInstance(LocationAttr &loc);
268 
269   /// Parse a callsite location instance.
270   ParseResult parseCallSiteLocation(LocationAttr &loc);
271 
272   /// Parse a fused location instance.
273   ParseResult parseFusedLocation(LocationAttr &loc);
274 
275   /// Parse a name or FileLineCol location instance.
276   ParseResult parseNameOrFileLineColLocation(LocationAttr &loc);
277 
278   //===--------------------------------------------------------------------===//
279   // Affine Parsing
280   //===--------------------------------------------------------------------===//
281 
282   /// Parse a reference to either an affine map, or an integer set.
283   ParseResult parseAffineMapOrIntegerSetReference(AffineMap &map,
284                                                   IntegerSet &set);
285   ParseResult parseAffineMapReference(AffineMap &map);
286   ParseResult parseIntegerSetReference(IntegerSet &set);
287 
288   /// Parse an AffineMap where the dim and symbol identifiers are SSA ids.
289   ParseResult
290   parseAffineMapOfSSAIds(AffineMap &map,
291                          function_ref<ParseResult(bool)> parseElement,
292                          Delimiter delimiter);
293 
294   /// Parse an AffineExpr where dim and symbol identifiers are SSA ids.
295   ParseResult
296   parseAffineExprOfSSAIds(AffineExpr &expr,
297                           function_ref<ParseResult(bool)> parseElement);
298 
299 protected:
300   /// The Parser is subclassed and reinstantiated.  Do not add additional
301   /// non-trivial state here, add it to the ParserState class.
302   ParserState &state;
303 };
304 } // end namespace detail
305 } // end namespace mlir
306 
307 #endif // MLIR_LIB_PARSER_PARSER_H
308