blob: 7e3076fca5be55678e91589094c71bc6662c949b [file] [log] [blame]
Chris Lattnere79379a2018-06-22 10:39:19 -07001//===- Parser.cpp - MLIR Parser Implementation ----------------------------===//
2//
3// Copyright 2019 The MLIR Authors.
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16// =============================================================================
17//
18// This file implements the parser for the MLIR textual form.
19//
20//===----------------------------------------------------------------------===//
21
22#include "mlir/Parser.h"
23#include "Lexer.h"
24#include "mlir/IR/Module.h"
Chris Lattnerf7e22732018-06-22 22:03:48 -070025#include "mlir/IR/Types.h"
Chris Lattnere79379a2018-06-22 10:39:19 -070026#include "llvm/Support/SourceMgr.h"
27using namespace mlir;
28using llvm::SourceMgr;
29
30namespace {
Chris Lattnerf7e22732018-06-22 22:03:48 -070031/// Simple enum to make code read better in cases that would otherwise return a
32/// bool value. Failure is "true" in a boolean context.
Chris Lattnere79379a2018-06-22 10:39:19 -070033enum ParseResult {
34 ParseSuccess,
35 ParseFailure
36};
37
38/// Main parser implementation.
39class Parser {
40 public:
Chris Lattnerf7e22732018-06-22 22:03:48 -070041 Parser(llvm::SourceMgr &sourceMgr, MLIRContext *context)
42 : context(context), lex(sourceMgr), curToken(lex.lexToken()){
Chris Lattnere79379a2018-06-22 10:39:19 -070043 module.reset(new Module());
44 }
45
46 Module *parseModule();
47private:
48 // State.
Chris Lattnerf7e22732018-06-22 22:03:48 -070049 MLIRContext *const context;
50
51 // The lexer for the source file we're parsing.
Chris Lattnere79379a2018-06-22 10:39:19 -070052 Lexer lex;
53
54 // This is the next token that hasn't been consumed yet.
55 Token curToken;
56
57 // This is the result module we are parsing into.
58 std::unique_ptr<Module> module;
59
60private:
61 // Helper methods.
62
63 /// Emit an error and return failure.
64 ParseResult emitError(const Twine &message);
65
66 /// Advance the current lexer onto the next token.
67 void consumeToken() {
68 assert(curToken.isNot(Token::eof, Token::error) &&
69 "shouldn't advance past EOF or errors");
70 curToken = lex.lexToken();
71 }
72
73 /// Advance the current lexer onto the next token, asserting what the expected
74 /// current token is. This is preferred to the above method because it leads
75 /// to more self-documenting code with better checking.
76 void consumeToken(Token::TokenKind kind) {
77 assert(curToken.is(kind) && "consumed an unexpected token");
78 consumeToken();
79 }
80
Chris Lattnerbb8fafc2018-06-22 15:52:02 -070081 /// If the current token has the specified kind, consume it and return true.
82 /// If not, return false.
83 bool consumeIf(Token::TokenKind kind) {
84 if (curToken.isNot(kind))
85 return false;
86 consumeToken(kind);
87 return true;
88 }
89
90 ParseResult parseCommaSeparatedList(Token::TokenKind rightToken,
91 const std::function<ParseResult()> &parseElement,
92 bool allowEmptyList = true);
93
Chris Lattnerf7e22732018-06-22 22:03:48 -070094 // We have two forms of parsing methods - those that return a non-null
95 // pointer on success, and those that return a ParseResult to indicate whether
96 // they returned a failure. The second class fills in by-reference arguments
97 // as the results of their action.
98
Chris Lattnere79379a2018-06-22 10:39:19 -070099 // Type parsing.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700100 PrimitiveType *parsePrimitiveType();
101 Type *parseElementType();
102 VectorType *parseVectorType();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700103 ParseResult parseDimensionListRanked(SmallVectorImpl<int> &dimensions);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700104 Type *parseTensorType();
105 Type *parseMemRefType();
106 Type *parseFunctionType();
107 Type *parseType();
108 ParseResult parseTypeList(SmallVectorImpl<Type*> &elements);
Chris Lattnere79379a2018-06-22 10:39:19 -0700109
110 // Top level entity parsing.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700111 ParseResult parseFunctionSignature(StringRef &name, FunctionType *&type);
Chris Lattnere79379a2018-06-22 10:39:19 -0700112 ParseResult parseExtFunc();
113};
114} // end anonymous namespace
115
116//===----------------------------------------------------------------------===//
117// Helper methods.
118//===----------------------------------------------------------------------===//
119
120ParseResult Parser::emitError(const Twine &message) {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700121 // If we hit a parse error in response to a lexer error, then the lexer
122 // already emitted an error.
123 if (curToken.is(Token::error))
124 return ParseFailure;
125
Chris Lattnere79379a2018-06-22 10:39:19 -0700126 // TODO(clattner): If/when we want to implement a -verify mode, this will need
127 // to package up errors into SMDiagnostic and report them.
128 lex.getSourceMgr().PrintMessage(curToken.getLoc(), SourceMgr::DK_Error,
129 message);
130 return ParseFailure;
131}
132
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700133/// Parse a comma-separated list of elements, terminated with an arbitrary
134/// token. This allows empty lists if allowEmptyList is true.
135///
136/// abstract-list ::= rightToken // if allowEmptyList == true
137/// abstract-list ::= element (',' element)* rightToken
138///
139ParseResult Parser::
140parseCommaSeparatedList(Token::TokenKind rightToken,
141 const std::function<ParseResult()> &parseElement,
142 bool allowEmptyList) {
143 // Handle the empty case.
144 if (curToken.is(rightToken)) {
145 if (!allowEmptyList)
146 return emitError("expected list element");
147 consumeToken(rightToken);
148 return ParseSuccess;
149 }
150
151 // Non-empty case starts with an element.
152 if (parseElement())
153 return ParseFailure;
154
155 // Otherwise we have a list of comma separated elements.
156 while (consumeIf(Token::comma)) {
157 if (parseElement())
158 return ParseFailure;
159 }
160
161 // Consume the end character.
162 if (!consumeIf(rightToken))
163 return emitError("expected ',' or ')'");
164
165 return ParseSuccess;
166}
Chris Lattnere79379a2018-06-22 10:39:19 -0700167
168//===----------------------------------------------------------------------===//
169// Type Parsing
170//===----------------------------------------------------------------------===//
171
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700172/// Parse the low-level fixed dtypes in the system.
173///
174/// primitive-type
175/// ::= `f16` | `bf16` | `f32` | `f64` // Floating point
176/// | `i1` | `i8` | `i16` | `i32` | `i64` // Sized integers
177/// | `int`
178///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700179PrimitiveType *Parser::parsePrimitiveType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700180 switch (curToken.getKind()) {
Chris Lattnerf7e22732018-06-22 22:03:48 -0700181 default:
182 return (emitError("expected type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700183 case Token::kw_bf16:
184 consumeToken(Token::kw_bf16);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700185 return Type::getBF16(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700186 case Token::kw_f16:
187 consumeToken(Token::kw_f16);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700188 return Type::getF16(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700189 case Token::kw_f32:
190 consumeToken(Token::kw_f32);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700191 return Type::getF32(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700192 case Token::kw_f64:
193 consumeToken(Token::kw_f64);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700194 return Type::getF64(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700195 case Token::kw_i1:
196 consumeToken(Token::kw_i1);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700197 return Type::getI1(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700198 case Token::kw_i8:
199 consumeToken(Token::kw_i8);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700200 return Type::getI8(context);
201 case Token::kw_i16:
202 consumeToken(Token::kw_i16);
203 return Type::getI16(context);
204 case Token::kw_i32:
205 consumeToken(Token::kw_i32);
206 return Type::getI32(context);
207 case Token::kw_i64:
208 consumeToken(Token::kw_i64);
209 return Type::getI64(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700210 case Token::kw_int:
211 consumeToken(Token::kw_int);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700212 return Type::getInt(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700213 }
214}
215
216/// Parse the element type of a tensor or memref type.
217///
218/// element-type ::= primitive-type | vector-type
219///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700220Type *Parser::parseElementType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700221 if (curToken.is(Token::kw_vector))
222 return parseVectorType();
223
224 return parsePrimitiveType();
225}
226
227/// Parse a vector type.
228///
229/// vector-type ::= `vector` `<` const-dimension-list primitive-type `>`
230/// const-dimension-list ::= (integer-literal `x`)+
231///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700232VectorType *Parser::parseVectorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700233 consumeToken(Token::kw_vector);
234
235 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700236 return (emitError("expected '<' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700237
238 if (curToken.isNot(Token::integer))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700239 return (emitError("expected dimension size in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700240
241 SmallVector<unsigned, 4> dimensions;
242 while (curToken.is(Token::integer)) {
243 // Make sure this integer value is in bound and valid.
244 auto dimension = curToken.getUnsignedIntegerValue();
245 if (!dimension.hasValue())
Chris Lattnerf7e22732018-06-22 22:03:48 -0700246 return (emitError("invalid dimension in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700247 dimensions.push_back(dimension.getValue());
248
249 consumeToken(Token::integer);
250
251 // Make sure we have an 'x' or something like 'xbf32'.
252 if (curToken.isNot(Token::bare_identifier) ||
253 curToken.getSpelling()[0] != 'x')
Chris Lattnerf7e22732018-06-22 22:03:48 -0700254 return (emitError("expected 'x' in vector dimension list"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700255
256 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
257 if (curToken.getSpelling().size() != 1)
258 lex.resetPointer(curToken.getSpelling().data()+1);
259
260 // Consume the 'x'.
261 consumeToken(Token::bare_identifier);
262 }
263
264 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700265 auto *elementType = parsePrimitiveType();
266 if (!elementType)
267 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700268
269 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700270 return (emitError("expected '>' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700271
Chris Lattnerf7e22732018-06-22 22:03:48 -0700272 return VectorType::get(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700273}
274
275/// Parse a dimension list of a tensor or memref type. This populates the
276/// dimension list, returning -1 for the '?' dimensions.
277///
278/// dimension-list-ranked ::= (dimension `x`)*
279/// dimension ::= `?` | integer-literal
280///
281ParseResult Parser::parseDimensionListRanked(SmallVectorImpl<int> &dimensions) {
282 while (curToken.isAny(Token::integer, Token::question)) {
283 if (consumeIf(Token::question)) {
284 dimensions.push_back(-1);
285 } else {
286 // Make sure this integer value is in bound and valid.
287 auto dimension = curToken.getUnsignedIntegerValue();
288 if (!dimension.hasValue() || (int)dimension.getValue() < 0)
289 return emitError("invalid dimension");
290 dimensions.push_back((int)dimension.getValue());
291 consumeToken(Token::integer);
292 }
293
294 // Make sure we have an 'x' or something like 'xbf32'.
295 if (curToken.isNot(Token::bare_identifier) ||
296 curToken.getSpelling()[0] != 'x')
297 return emitError("expected 'x' in dimension list");
298
299 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
300 if (curToken.getSpelling().size() != 1)
301 lex.resetPointer(curToken.getSpelling().data()+1);
302
303 // Consume the 'x'.
304 consumeToken(Token::bare_identifier);
305 }
306
307 return ParseSuccess;
308}
309
310/// Parse a tensor type.
311///
312/// tensor-type ::= `tensor` `<` dimension-list element-type `>`
313/// dimension-list ::= dimension-list-ranked | `??`
314///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700315Type *Parser::parseTensorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700316 consumeToken(Token::kw_tensor);
317
318 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700319 return (emitError("expected '<' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700320
321 bool isUnranked;
322 SmallVector<int, 4> dimensions;
323
324 if (consumeIf(Token::questionquestion)) {
325 isUnranked = true;
326 } else {
327 isUnranked = false;
328 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700329 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700330 }
331
332 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700333 auto elementType = parseElementType();
334 if (!elementType)
335 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700336
337 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700338 return (emitError("expected '>' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700339
Chris Lattnerf7e22732018-06-22 22:03:48 -0700340 // FIXME: Add an IR representation for tensor types.
341 return Type::getI1(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700342}
343
344/// Parse a memref type.
345///
346/// memref-type ::= `memref` `<` dimension-list-ranked element-type
347/// (`,` semi-affine-map-composition)? (`,` memory-space)? `>`
348///
349/// semi-affine-map-composition ::= (semi-affine-map `,` )* semi-affine-map
350/// memory-space ::= integer-literal /* | TODO: address-space-id */
351///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700352Type *Parser::parseMemRefType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700353 consumeToken(Token::kw_memref);
354
355 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700356 return (emitError("expected '<' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700357
358 SmallVector<int, 4> dimensions;
359 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700360 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700361
362 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700363 auto elementType = parseElementType();
364 if (!elementType)
365 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700366
367 // TODO: Parse semi-affine-map-composition.
368 // TODO: Parse memory-space.
369
370 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700371 return (emitError("expected '>' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700372
Chris Lattnerf7e22732018-06-22 22:03:48 -0700373 // FIXME: Add an IR representation for memref types.
374 return Type::getI1(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700375}
376
377
378
379/// Parse a function type.
380///
381/// function-type ::= type-list-parens `->` type-list
382///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700383Type *Parser::parseFunctionType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700384 assert(curToken.is(Token::l_paren));
385
Chris Lattnerf7e22732018-06-22 22:03:48 -0700386 SmallVector<Type*, 4> arguments;
387 if (parseTypeList(arguments))
388 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700389
390 if (!consumeIf(Token::arrow))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700391 return (emitError("expected '->' in function type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700392
Chris Lattnerf7e22732018-06-22 22:03:48 -0700393 SmallVector<Type*, 4> results;
394 if (parseTypeList(results))
395 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700396
Chris Lattnerf7e22732018-06-22 22:03:48 -0700397 return FunctionType::get(arguments, results, context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700398}
399
400
401/// Parse an arbitrary type.
402///
403/// type ::= primitive-type
404/// | vector-type
405/// | tensor-type
406/// | memref-type
407/// | function-type
408/// element-type ::= primitive-type | vector-type
409///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700410Type *Parser::parseType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700411 switch (curToken.getKind()) {
412 case Token::kw_memref: return parseMemRefType();
413 case Token::kw_tensor: return parseTensorType();
414 case Token::kw_vector: return parseVectorType();
415 case Token::l_paren: return parseFunctionType();
416 default:
417 return parsePrimitiveType();
418 }
419}
420
421/// Parse a "type list", which is a singular type, or a parenthesized list of
422/// types.
423///
424/// type-list ::= type-list-parens | type
425/// type-list-parens ::= `(` `)`
426/// | `(` type (`,` type)* `)`
427///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700428ParseResult Parser::parseTypeList(SmallVectorImpl<Type*> &elements) {
429 auto parseElt = [&]() -> ParseResult {
430 auto elt = parseType();
431 elements.push_back(elt);
432 return elt ? ParseSuccess : ParseFailure;
433 };
434
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700435 // If there is no parens, then it must be a singular type.
436 if (!consumeIf(Token::l_paren))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700437 return parseElt();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700438
Chris Lattnerf7e22732018-06-22 22:03:48 -0700439 if (parseCommaSeparatedList(Token::r_paren, parseElt))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700440 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700441
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700442 return ParseSuccess;
443}
444
Chris Lattnere79379a2018-06-22 10:39:19 -0700445
446//===----------------------------------------------------------------------===//
447// Top-level entity parsing.
448//===----------------------------------------------------------------------===//
449
450/// Parse a function signature, starting with a name and including the parameter
451/// list.
452///
453/// argument-list ::= type (`,` type)* | /*empty*/
454/// function-signature ::= function-id `(` argument-list `)` (`->` type-list)?
455///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700456ParseResult Parser::parseFunctionSignature(StringRef &name,
457 FunctionType *&type) {
Chris Lattnere79379a2018-06-22 10:39:19 -0700458 if (curToken.isNot(Token::at_identifier))
459 return emitError("expected a function identifier like '@foo'");
460
461 name = curToken.getSpelling().drop_front();
462 consumeToken(Token::at_identifier);
463
464 if (curToken.isNot(Token::l_paren))
465 return emitError("expected '(' in function signature");
Chris Lattnere79379a2018-06-22 10:39:19 -0700466
Chris Lattnerf7e22732018-06-22 22:03:48 -0700467 SmallVector<Type*, 4> arguments;
468 if (parseTypeList(arguments))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700469 return ParseFailure;
Chris Lattnere79379a2018-06-22 10:39:19 -0700470
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700471 // Parse the return type if present.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700472 SmallVector<Type*, 4> results;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700473 if (consumeIf(Token::arrow)) {
Chris Lattnerf7e22732018-06-22 22:03:48 -0700474 if (parseTypeList(results))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700475 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700476 }
Chris Lattnerf7e22732018-06-22 22:03:48 -0700477 type = FunctionType::get(arguments, results, context);
Chris Lattnere79379a2018-06-22 10:39:19 -0700478 return ParseSuccess;
479}
480
481
482/// External function declarations.
483///
484/// ext-func ::= `extfunc` function-signature
485///
486ParseResult Parser::parseExtFunc() {
487 consumeToken(Token::kw_extfunc);
488
489 StringRef name;
Chris Lattnerf7e22732018-06-22 22:03:48 -0700490 FunctionType *type = nullptr;
491 if (parseFunctionSignature(name, type))
Chris Lattnere79379a2018-06-22 10:39:19 -0700492 return ParseFailure;
493
494
495 // Okay, the external function definition was parsed correctly.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700496 module->functionList.push_back(new Function(name, type));
Chris Lattnere79379a2018-06-22 10:39:19 -0700497 return ParseSuccess;
498}
499
500
501/// This is the top-level module parser.
502Module *Parser::parseModule() {
503 while (1) {
504 switch (curToken.getKind()) {
505 default:
506 emitError("expected a top level entity");
507 return nullptr;
508
509 // If we got to the end of the file, then we're done.
510 case Token::eof:
511 return module.release();
512
513 // If we got an error token, then the lexer already emitted an error, just
514 // stop. Someday we could introduce error recovery if there was demand for
515 // it.
516 case Token::error:
517 return nullptr;
518
519 case Token::kw_extfunc:
520 if (parseExtFunc())
521 return nullptr;
522 break;
523
524 // TODO: cfgfunc, mlfunc, affine entity declarations, etc.
525 }
526 }
527}
528
529//===----------------------------------------------------------------------===//
530
531/// This parses the file specified by the indicated SourceMgr and returns an
532/// MLIR module if it was valid. If not, it emits diagnostics and returns null.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700533Module *mlir::parseSourceFile(llvm::SourceMgr &sourceMgr, MLIRContext *context){
534 return Parser(sourceMgr, context).parseModule();
Chris Lattnere79379a2018-06-22 10:39:19 -0700535}