MLIR  17.0.0git
TypeParser.cpp
Go to the documentation of this file.
1 //===- TypeParser.cpp - MLIR Type Parser Implementation -------------------===//
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 // This file implements the parser for the MLIR Types.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "Parser.h"
14 #include "mlir/IR/AffineMap.h"
15 #include "mlir/IR/BuiltinTypes.h"
16 #include "mlir/IR/OpDefinition.h"
17 #include "mlir/IR/TensorEncoding.h"
18 #include <optional>
19 
20 using namespace mlir;
21 using namespace mlir::detail;
22 
23 /// Optionally parse a type.
25  // There are many different starting tokens for a type, check them here.
26  switch (getToken().getKind()) {
27  case Token::l_paren:
28  case Token::kw_memref:
29  case Token::kw_tensor:
30  case Token::kw_complex:
31  case Token::kw_tuple:
32  case Token::kw_vector:
33  case Token::inttype:
34  case Token::kw_f8E5M2:
35  case Token::kw_f8E4M3FN:
36  case Token::kw_bf16:
37  case Token::kw_f16:
38  case Token::kw_f32:
39  case Token::kw_f64:
40  case Token::kw_f80:
41  case Token::kw_f128:
42  case Token::kw_index:
43  case Token::kw_none:
44  case Token::exclamation_identifier:
45  return failure(!(type = parseType()));
46 
47  default:
48  return std::nullopt;
49  }
50 }
51 
52 /// Parse an arbitrary type.
53 ///
54 /// type ::= function-type
55 /// | non-function-type
56 ///
58  if (getToken().is(Token::l_paren))
59  return parseFunctionType();
60  return parseNonFunctionType();
61 }
62 
63 /// Parse a function result type.
64 ///
65 /// function-result-type ::= type-list-parens
66 /// | non-function-type
67 ///
69  if (getToken().is(Token::l_paren))
70  return parseTypeListParens(elements);
71 
73  if (!t)
74  return failure();
75  elements.push_back(t);
76  return success();
77 }
78 
79 /// Parse a list of types without an enclosing parenthesis. The list must have
80 /// at least one member.
81 ///
82 /// type-list-no-parens ::= type (`,` type)*
83 ///
85  auto parseElt = [&]() -> ParseResult {
86  auto elt = parseType();
87  elements.push_back(elt);
88  return elt ? success() : failure();
89  };
90 
91  return parseCommaSeparatedList(parseElt);
92 }
93 
94 /// Parse a parenthesized list of types.
95 ///
96 /// type-list-parens ::= `(` `)`
97 /// | `(` type-list-no-parens `)`
98 ///
100  if (parseToken(Token::l_paren, "expected '('"))
101  return failure();
102 
103  // Handle empty lists.
104  if (getToken().is(Token::r_paren))
105  return consumeToken(), success();
106 
107  if (parseTypeListNoParens(elements) ||
108  parseToken(Token::r_paren, "expected ')'"))
109  return failure();
110  return success();
111 }
112 
113 /// Parse a complex type.
114 ///
115 /// complex-type ::= `complex` `<` type `>`
116 ///
118  consumeToken(Token::kw_complex);
119 
120  // Parse the '<'.
121  if (parseToken(Token::less, "expected '<' in complex type"))
122  return nullptr;
123 
124  SMLoc elementTypeLoc = getToken().getLoc();
125  auto elementType = parseType();
126  if (!elementType ||
127  parseToken(Token::greater, "expected '>' in complex type"))
128  return nullptr;
129  if (!elementType.isa<FloatType>() && !elementType.isa<IntegerType>())
130  return emitError(elementTypeLoc, "invalid element type for complex"),
131  nullptr;
132 
133  return ComplexType::get(elementType);
134 }
135 
136 /// Parse a function type.
137 ///
138 /// function-type ::= type-list-parens `->` function-result-type
139 ///
141  assert(getToken().is(Token::l_paren));
142 
143  SmallVector<Type, 4> arguments, results;
144  if (parseTypeListParens(arguments) ||
145  parseToken(Token::arrow, "expected '->' in function type") ||
146  parseFunctionResultTypes(results))
147  return nullptr;
148 
149  return builder.getFunctionType(arguments, results);
150 }
151 
152 /// Parse a memref type.
153 ///
154 /// memref-type ::= ranked-memref-type | unranked-memref-type
155 ///
156 /// ranked-memref-type ::= `memref` `<` dimension-list-ranked type
157 /// (`,` layout-specification)? (`,` memory-space)? `>`
158 ///
159 /// unranked-memref-type ::= `memref` `<*x` type (`,` memory-space)? `>`
160 ///
161 /// stride-list ::= `[` (dimension (`,` dimension)*)? `]`
162 /// strided-layout ::= `offset:` dimension `,` `strides: ` stride-list
163 /// layout-specification ::= semi-affine-map | strided-layout | attribute
164 /// memory-space ::= integer-literal | attribute
165 ///
167  SMLoc loc = getToken().getLoc();
168  consumeToken(Token::kw_memref);
169 
170  if (parseToken(Token::less, "expected '<' in memref type"))
171  return nullptr;
172 
173  bool isUnranked;
174  SmallVector<int64_t, 4> dimensions;
175 
176  if (consumeIf(Token::star)) {
177  // This is an unranked memref type.
178  isUnranked = true;
179  if (parseXInDimensionList())
180  return nullptr;
181 
182  } else {
183  isUnranked = false;
184  if (parseDimensionListRanked(dimensions))
185  return nullptr;
186  }
187 
188  // Parse the element type.
189  auto typeLoc = getToken().getLoc();
190  auto elementType = parseType();
191  if (!elementType)
192  return nullptr;
193 
194  // Check that memref is formed from allowed types.
195  if (!BaseMemRefType::isValidElementType(elementType))
196  return emitError(typeLoc, "invalid memref element type"), nullptr;
197 
198  MemRefLayoutAttrInterface layout;
199  Attribute memorySpace;
200 
201  auto parseElt = [&]() -> ParseResult {
202  // Either it is MemRefLayoutAttrInterface or memory space attribute.
203  Attribute attr = parseAttribute();
204  if (!attr)
205  return failure();
206 
207  if (attr.isa<MemRefLayoutAttrInterface>()) {
208  layout = attr.cast<MemRefLayoutAttrInterface>();
209  } else if (memorySpace) {
210  return emitError("multiple memory spaces specified in memref type");
211  } else {
212  memorySpace = attr;
213  return success();
214  }
215 
216  if (isUnranked)
217  return emitError("cannot have affine map for unranked memref type");
218  if (memorySpace)
219  return emitError("expected memory space to be last in memref type");
220 
221  return success();
222  };
223 
224  // Parse a list of mappings and address space if present.
225  if (!consumeIf(Token::greater)) {
226  // Parse comma separated list of affine maps, followed by memory space.
227  if (parseToken(Token::comma, "expected ',' or '>' in memref type") ||
228  parseCommaSeparatedListUntil(Token::greater, parseElt,
229  /*allowEmptyList=*/false)) {
230  return nullptr;
231  }
232  }
233 
234  if (isUnranked)
235  return getChecked<UnrankedMemRefType>(loc, elementType, memorySpace);
236 
237  return getChecked<MemRefType>(loc, dimensions, elementType, layout,
238  memorySpace);
239 }
240 
241 /// Parse any type except the function type.
242 ///
243 /// non-function-type ::= integer-type
244 /// | index-type
245 /// | float-type
246 /// | extended-type
247 /// | vector-type
248 /// | tensor-type
249 /// | memref-type
250 /// | complex-type
251 /// | tuple-type
252 /// | none-type
253 ///
254 /// index-type ::= `index`
255 /// float-type ::= `f16` | `bf16` | `f32` | `f64` | `f80` | `f128`
256 /// none-type ::= `none`
257 ///
259  switch (getToken().getKind()) {
260  default:
261  return (emitWrongTokenError("expected non-function type"), nullptr);
262  case Token::kw_memref:
263  return parseMemRefType();
264  case Token::kw_tensor:
265  return parseTensorType();
266  case Token::kw_complex:
267  return parseComplexType();
268  case Token::kw_tuple:
269  return parseTupleType();
270  case Token::kw_vector:
271  return parseVectorType();
272  // integer-type
273  case Token::inttype: {
274  auto width = getToken().getIntTypeBitwidth();
275  if (!width.has_value())
276  return (emitError("invalid integer width"), nullptr);
277  if (*width > IntegerType::kMaxWidth) {
278  emitError(getToken().getLoc(), "integer bitwidth is limited to ")
279  << IntegerType::kMaxWidth << " bits";
280  return nullptr;
281  }
282 
283  IntegerType::SignednessSemantics signSemantics = IntegerType::Signless;
284  if (std::optional<bool> signedness = getToken().getIntTypeSignedness())
285  signSemantics = *signedness ? IntegerType::Signed : IntegerType::Unsigned;
286 
287  consumeToken(Token::inttype);
288  return IntegerType::get(getContext(), *width, signSemantics);
289  }
290 
291  // float-type
292  case Token::kw_f8E5M2:
293  consumeToken(Token::kw_f8E5M2);
294  return builder.getFloat8E5M2Type();
295  case Token::kw_f8E4M3FN:
296  consumeToken(Token::kw_f8E4M3FN);
297  return builder.getFloat8E4M3FNType();
298  case Token::kw_bf16:
299  consumeToken(Token::kw_bf16);
300  return builder.getBF16Type();
301  case Token::kw_f16:
302  consumeToken(Token::kw_f16);
303  return builder.getF16Type();
304  case Token::kw_f32:
305  consumeToken(Token::kw_f32);
306  return builder.getF32Type();
307  case Token::kw_f64:
308  consumeToken(Token::kw_f64);
309  return builder.getF64Type();
310  case Token::kw_f80:
311  consumeToken(Token::kw_f80);
312  return builder.getF80Type();
313  case Token::kw_f128:
314  consumeToken(Token::kw_f128);
315  return builder.getF128Type();
316 
317  // index-type
318  case Token::kw_index:
319  consumeToken(Token::kw_index);
320  return builder.getIndexType();
321 
322  // none-type
323  case Token::kw_none:
324  consumeToken(Token::kw_none);
325  return builder.getNoneType();
326 
327  // extended type
328  case Token::exclamation_identifier:
329  return parseExtendedType();
330 
331  // Handle completion of a dialect type.
332  case Token::code_complete:
333  if (getToken().isCodeCompletionFor(Token::exclamation_identifier))
334  return parseExtendedType();
335  return codeCompleteType();
336  }
337 }
338 
339 /// Parse a tensor type.
340 ///
341 /// tensor-type ::= `tensor` `<` dimension-list type `>`
342 /// dimension-list ::= dimension-list-ranked | `*x`
343 ///
345  consumeToken(Token::kw_tensor);
346 
347  if (parseToken(Token::less, "expected '<' in tensor type"))
348  return nullptr;
349 
350  bool isUnranked;
351  SmallVector<int64_t, 4> dimensions;
352 
353  if (consumeIf(Token::star)) {
354  // This is an unranked tensor type.
355  isUnranked = true;
356 
357  if (parseXInDimensionList())
358  return nullptr;
359 
360  } else {
361  isUnranked = false;
362  if (parseDimensionListRanked(dimensions))
363  return nullptr;
364  }
365 
366  // Parse the element type.
367  auto elementTypeLoc = getToken().getLoc();
368  auto elementType = parseType();
369 
370  // Parse an optional encoding attribute.
371  Attribute encoding;
372  if (consumeIf(Token::comma)) {
373  encoding = parseAttribute();
374  if (auto v = encoding.dyn_cast_or_null<VerifiableTensorEncoding>()) {
375  if (failed(v.verifyEncoding(dimensions, elementType,
376  [&] { return emitError(); })))
377  return nullptr;
378  }
379  }
380 
381  if (!elementType || parseToken(Token::greater, "expected '>' in tensor type"))
382  return nullptr;
383  if (!TensorType::isValidElementType(elementType))
384  return emitError(elementTypeLoc, "invalid tensor element type"), nullptr;
385 
386  if (isUnranked) {
387  if (encoding)
388  return emitError("cannot apply encoding to unranked tensor"), nullptr;
389  return UnrankedTensorType::get(elementType);
390  }
391  return RankedTensorType::get(dimensions, elementType, encoding);
392 }
393 
394 /// Parse a tuple type.
395 ///
396 /// tuple-type ::= `tuple` `<` (type (`,` type)*)? `>`
397 ///
399  consumeToken(Token::kw_tuple);
400 
401  // Parse the '<'.
402  if (parseToken(Token::less, "expected '<' in tuple type"))
403  return nullptr;
404 
405  // Check for an empty tuple by directly parsing '>'.
406  if (consumeIf(Token::greater))
407  return TupleType::get(getContext());
408 
409  // Parse the element types and the '>'.
410  SmallVector<Type, 4> types;
411  if (parseTypeListNoParens(types) ||
412  parseToken(Token::greater, "expected '>' in tuple type"))
413  return nullptr;
414 
415  return TupleType::get(getContext(), types);
416 }
417 
418 /// Parse a vector type.
419 ///
420 /// vector-type ::= `vector` `<` vector-dim-list vector-element-type `>`
421 /// vector-dim-list := (static-dim-list `x`)? (`[` static-dim-list `]` `x`)?
422 /// static-dim-list ::= decimal-literal (`x` decimal-literal)*
423 ///
425  consumeToken(Token::kw_vector);
426 
427  if (parseToken(Token::less, "expected '<' in vector type"))
428  return nullptr;
429 
430  SmallVector<int64_t, 4> dimensions;
431  unsigned numScalableDims;
432  if (parseVectorDimensionList(dimensions, numScalableDims))
433  return nullptr;
434  if (any_of(dimensions, [](int64_t i) { return i <= 0; }))
435  return emitError(getToken().getLoc(),
436  "vector types must have positive constant sizes"),
437  nullptr;
438 
439  // Parse the element type.
440  auto typeLoc = getToken().getLoc();
441  auto elementType = parseType();
442  if (!elementType || parseToken(Token::greater, "expected '>' in vector type"))
443  return nullptr;
444 
445  if (!VectorType::isValidElementType(elementType))
446  return emitError(typeLoc, "vector elements must be int/index/float type"),
447  nullptr;
448 
449  return VectorType::get(dimensions, elementType, numScalableDims);
450 }
451 
452 /// Parse a dimension list in a vector type. This populates the dimension list,
453 /// and returns the number of scalable dimensions in `numScalableDims`.
454 ///
455 /// vector-dim-list := (static-dim-list `x`)? (`[` static-dim-list `]` `x`)?
456 /// static-dim-list ::= decimal-literal (`x` decimal-literal)*
457 ///
460  unsigned &numScalableDims) {
461  numScalableDims = 0;
462  // If there is a set of fixed-length dimensions, consume it
463  while (getToken().is(Token::integer)) {
464  int64_t value;
465  if (parseIntegerInDimensionList(value))
466  return failure();
467  dimensions.push_back(value);
468  // Make sure we have an 'x' or something like 'xbf32'.
469  if (parseXInDimensionList())
470  return failure();
471  }
472  // If there is a set of scalable dimensions, consume it
473  if (consumeIf(Token::l_square)) {
474  while (getToken().is(Token::integer)) {
475  int64_t value;
476  if (parseIntegerInDimensionList(value))
477  return failure();
478  dimensions.push_back(value);
479  numScalableDims++;
480  // Check if we have reached the end of the scalable dimension list
481  if (consumeIf(Token::r_square)) {
482  // Make sure we have something like 'xbf32'.
483  return parseXInDimensionList();
484  }
485  // Make sure we have an 'x'
486  if (parseXInDimensionList())
487  return failure();
488  }
489  // If we make it here, we've finished parsing the dimension list
490  // without finding ']' closing the set of scalable dimensions
491  return emitWrongTokenError(
492  "missing ']' closing set of scalable dimensions");
493  }
494 
495  return success();
496 }
497 
498 /// Parse a dimension list of a tensor or memref type. This populates the
499 /// dimension list, using ShapedType::kDynamic for the `?` dimensions if
500 /// `allowDynamic` is set and errors out on `?` otherwise. Parsing the trailing
501 /// `x` is configurable.
502 ///
503 /// dimension-list ::= eps | dimension (`x` dimension)*
504 /// dimension-list-with-trailing-x ::= (dimension `x`)*
505 /// dimension ::= `?` | decimal-literal
506 ///
507 /// When `allowDynamic` is not set, this is used to parse:
508 ///
509 /// static-dimension-list ::= eps | decimal-literal (`x` decimal-literal)*
510 /// static-dimension-list-with-trailing-x ::= (dimension `x`)*
513  bool allowDynamic, bool withTrailingX) {
514  auto parseDim = [&]() -> LogicalResult {
515  auto loc = getToken().getLoc();
516  if (consumeIf(Token::question)) {
517  if (!allowDynamic)
518  return emitError(loc, "expected static shape");
519  dimensions.push_back(ShapedType::kDynamic);
520  } else {
521  int64_t value;
523  return failure();
524  dimensions.push_back(value);
525  }
526  return success();
527  };
528 
529  if (withTrailingX) {
530  while (getToken().isAny(Token::integer, Token::question)) {
531  if (failed(parseDim()) || failed(parseXInDimensionList()))
532  return failure();
533  }
534  return success();
535  }
536 
537  if (getToken().isAny(Token::integer, Token::question)) {
538  if (failed(parseDim()))
539  return failure();
540  while (getToken().is(Token::bare_identifier) &&
541  getTokenSpelling()[0] == 'x') {
542  if (failed(parseXInDimensionList()) || failed(parseDim()))
543  return failure();
544  }
545  }
546  return success();
547 }
548 
550  // Hexadecimal integer literals (starting with `0x`) are not allowed in
551  // aggregate type declarations. Therefore, `0xf32` should be processed as
552  // a sequence of separate elements `0`, `x`, `f32`.
553  if (getTokenSpelling().size() > 1 && getTokenSpelling()[1] == 'x') {
554  // We can get here only if the token is an integer literal. Hexadecimal
555  // integer literals can only start with `0x` (`1x` wouldn't lex as a
556  // literal, just `1` would, at which point we don't get into this
557  // branch).
558  assert(getTokenSpelling()[0] == '0' && "invalid integer literal");
559  value = 0;
560  state.lex.resetPointer(getTokenSpelling().data() + 1);
561  consumeToken();
562  } else {
563  // Make sure this integer value is in bound and valid.
564  std::optional<uint64_t> dimension = getToken().getUInt64IntegerValue();
565  if (!dimension ||
566  *dimension > (uint64_t)std::numeric_limits<int64_t>::max())
567  return emitError("invalid dimension");
568  value = (int64_t)*dimension;
569  consumeToken(Token::integer);
570  }
571  return success();
572 }
573 
574 /// Parse an 'x' token in a dimension list, handling the case where the x is
575 /// juxtaposed with an element type, as in "xf32", leaving the "f32" as the next
576 /// token.
578  if (getToken().isNot(Token::bare_identifier) || getTokenSpelling()[0] != 'x')
579  return emitWrongTokenError("expected 'x' in dimension list");
580 
581  // If we had a prefix of 'x', lex the next token immediately after the 'x'.
582  if (getTokenSpelling().size() != 1)
583  state.lex.resetPointer(getTokenSpelling().data() + 1);
584 
585  // Consume the 'x'.
586  consumeToken(Token::bare_identifier);
587 
588  return success();
589 }
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
Attributes are known-constant values of operations.
Definition: Attributes.h:25
U dyn_cast_or_null() const
Definition: Attributes.h:174
U cast() const
Definition: Attributes.h:179
bool isa() const
Casting utility functions.
Definition: Attributes.h:159
static bool isValidElementType(Type type)
Return true if the specified element type is ok in a memref.
Definition: BuiltinTypes.h:370
FloatType getFloat8E5M2Type()
Definition: Builders.cpp:36
FloatType getF80Type()
Definition: Builders.cpp:52
FloatType getF128Type()
Definition: Builders.cpp:54
FloatType getF32Type()
Definition: Builders.cpp:48
FunctionType getFunctionType(TypeRange inputs, TypeRange results)
Definition: Builders.cpp:81
NoneType getNoneType()
Definition: Builders.cpp:89
FloatType getF16Type()
Definition: Builders.cpp:46
FloatType getBF16Type()
Definition: Builders.cpp:44
FloatType getFloat8E4M3FNType()
Definition: Builders.cpp:40
IndexType getIndexType()
Definition: Builders.cpp:56
FloatType getF64Type()
Definition: Builders.cpp:50
void resetPointer(const char *newPointer)
Change the position of the lexer cursor.
Definition: Lexer.h:38
This class implements Optional functionality for ParseResult.
Definition: OpDefinition.h:38
This class represents success/failure for parsing-like operations that find it important to chain tog...
static bool isValidElementType(Type type)
Return true if the specified element type is ok in a tensor.
SMLoc getLoc() const
Definition: Token.cpp:19
static std::optional< uint64_t > getUInt64IntegerValue(StringRef spelling)
For an integer token, return its value as an uint64_t.
Definition: Token.cpp:40
std::optional< unsigned > getIntTypeBitwidth() const
For an inttype token, return its bitwidth.
Definition: Token.cpp:59
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:74
bool isa() const
Definition: Types.h:301
ParseResult parseVectorDimensionList(SmallVectorImpl< int64_t > &dimensions, unsigned &numScalableDims)
Parse a dimension list in a vector type.
Definition: TypeParser.cpp:459
ParseResult parseXInDimensionList()
Parse an 'x' token in a dimension list, handling the case where the x is juxtaposed with an element t...
Definition: TypeParser.cpp:577
OptionalParseResult parseOptionalType(Type &type)
Optionally parse a type.
Definition: TypeParser.cpp:24
ParseResult parseToken(Token::Kind expectedToken, const Twine &message)
Consume the specified token if present and return success.
Definition: Parser.cpp:233
ParseResult parseCommaSeparatedListUntil(Token::Kind rightToken, function_ref< ParseResult()> parseElement, bool allowEmptyList=true)
Parse a comma-separated list of elements up until the specified end token.
Definition: Parser.cpp:139
Builder builder
Definition: Parser.h:30
Type parseType()
Parse an arbitrary type.
Definition: TypeParser.cpp:57
ParseResult parseTypeListParens(SmallVectorImpl< Type > &elements)
Parse a parenthesized list of types.
Definition: TypeParser.cpp:99
Type parseMemRefType()
Parse a memref type.
Definition: TypeParser.cpp:166
Type parseNonFunctionType()
Parse a non function type.
Definition: TypeParser.cpp:258
Type codeCompleteType()
Definition: Parser.cpp:433
Type parseExtendedType()
Parse an extended type.
Type parseTupleType()
Parse a tuple type.
Definition: TypeParser.cpp:398
InFlightDiagnostic emitError(const Twine &message={})
Emit an error and return failure.
Definition: Parser.cpp:158
ParserState & state
The Parser is subclassed and reinstantiated.
Definition: Parser.h:341
Attribute parseAttribute(Type type={})
Parse an arbitrary attribute with an optional type.
StringRef getTokenSpelling() const
Definition: Parser.h:103
void consumeToken()
Advance the current lexer onto the next token.
Definition: Parser.h:115
ParseResult parseIntegerInDimensionList(int64_t &value)
Definition: TypeParser.cpp:549
Type parseComplexType()
Parse a complex type.
Definition: TypeParser.cpp:117
ParseResult parseDimensionListRanked(SmallVectorImpl< int64_t > &dimensions, bool allowDynamic=true, bool withTrailingX=true)
Parse a dimension list of a tensor or memref type.
Definition: TypeParser.cpp:512
ParseResult parseFunctionResultTypes(SmallVectorImpl< Type > &elements)
Parse a function result type.
Definition: TypeParser.cpp:68
MLIRContext * getContext() const
Definition: Parser.h:37
InFlightDiagnostic emitWrongTokenError(const Twine &message={})
Emit an error about a "wrong token".
Definition: Parser.cpp:181
ParseResult parseCommaSeparatedList(Delimiter delimiter, function_ref< ParseResult()> parseElementFn, StringRef contextMessage=StringRef())
Parse a list of comma-separated items with an optional delimiter.
Definition: Parser.cpp:50
VectorType parseVectorType()
Parse a vector type.
Definition: TypeParser.cpp:424
Type parseFunctionType()
Parse a function type.
Definition: TypeParser.cpp:140
ParseResult parseTypeListNoParens(SmallVectorImpl< Type > &elements)
Parse a list of types without an enclosing parenthesis.
Definition: TypeParser.cpp:84
const Token & getToken() const
Return the current token the parser is inspecting.
Definition: Parser.h:102
Type parseTensorType()
Parse a tensor type.
Definition: TypeParser.cpp:344
bool consumeIf(Token::Kind kind)
If the current token has the specified kind, consume it and return true.
Definition: Parser.h:107
Detect if any of the given parameter types has a sub-element handler.
Include the generated interface declarations.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
Definition: LogicalResult.h:72
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26
Lexer lex
The lexer for the source file we're parsing.
Definition: ParserState.h:62