blob: abad611d84688efeffa6f5c8a0907e65c1454e8a [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"
25#include "llvm/Support/SourceMgr.h"
26using namespace mlir;
27using llvm::SourceMgr;
28
29namespace {
30/// Simple enum to make code read better. Failure is "true" in a boolean
31/// context.
32enum ParseResult {
33 ParseSuccess,
34 ParseFailure
35};
36
37/// Main parser implementation.
38class Parser {
39 public:
40 Parser(llvm::SourceMgr &sourceMgr) : lex(sourceMgr), curToken(lex.lexToken()){
41 module.reset(new Module());
42 }
43
44 Module *parseModule();
45private:
46 // State.
47 Lexer lex;
48
49 // This is the next token that hasn't been consumed yet.
50 Token curToken;
51
52 // This is the result module we are parsing into.
53 std::unique_ptr<Module> module;
54
55private:
56 // Helper methods.
57
58 /// Emit an error and return failure.
59 ParseResult emitError(const Twine &message);
60
61 /// Advance the current lexer onto the next token.
62 void consumeToken() {
63 assert(curToken.isNot(Token::eof, Token::error) &&
64 "shouldn't advance past EOF or errors");
65 curToken = lex.lexToken();
66 }
67
68 /// Advance the current lexer onto the next token, asserting what the expected
69 /// current token is. This is preferred to the above method because it leads
70 /// to more self-documenting code with better checking.
71 void consumeToken(Token::TokenKind kind) {
72 assert(curToken.is(kind) && "consumed an unexpected token");
73 consumeToken();
74 }
75
76 // Type parsing.
77
78 // Top level entity parsing.
79 ParseResult parseFunctionSignature(StringRef &name);
80 ParseResult parseExtFunc();
81};
82} // end anonymous namespace
83
84//===----------------------------------------------------------------------===//
85// Helper methods.
86//===----------------------------------------------------------------------===//
87
88ParseResult Parser::emitError(const Twine &message) {
89 // TODO(clattner): If/when we want to implement a -verify mode, this will need
90 // to package up errors into SMDiagnostic and report them.
91 lex.getSourceMgr().PrintMessage(curToken.getLoc(), SourceMgr::DK_Error,
92 message);
93 return ParseFailure;
94}
95
96
97//===----------------------------------------------------------------------===//
98// Type Parsing
99//===----------------------------------------------------------------------===//
100
101// ... TODO
102
103//===----------------------------------------------------------------------===//
104// Top-level entity parsing.
105//===----------------------------------------------------------------------===//
106
107/// Parse a function signature, starting with a name and including the parameter
108/// list.
109///
110/// argument-list ::= type (`,` type)* | /*empty*/
111/// function-signature ::= function-id `(` argument-list `)` (`->` type-list)?
112///
113ParseResult Parser::parseFunctionSignature(StringRef &name) {
114 if (curToken.isNot(Token::at_identifier))
115 return emitError("expected a function identifier like '@foo'");
116
117 name = curToken.getSpelling().drop_front();
118 consumeToken(Token::at_identifier);
119
120 if (curToken.isNot(Token::l_paren))
121 return emitError("expected '(' in function signature");
122 consumeToken(Token::l_paren);
123
124 // TODO: This should actually parse the full grammar here.
125
126 if (curToken.isNot(Token::r_paren))
127 return emitError("expected ')' in function signature");
128 consumeToken(Token::r_paren);
129
130 return ParseSuccess;
131}
132
133
134/// External function declarations.
135///
136/// ext-func ::= `extfunc` function-signature
137///
138ParseResult Parser::parseExtFunc() {
139 consumeToken(Token::kw_extfunc);
140
141 StringRef name;
142 if (parseFunctionSignature(name))
143 return ParseFailure;
144
145
146 // Okay, the external function definition was parsed correctly.
147 module->functionList.push_back(new Function(name));
148 return ParseSuccess;
149}
150
151
152/// This is the top-level module parser.
153Module *Parser::parseModule() {
154 while (1) {
155 switch (curToken.getKind()) {
156 default:
157 emitError("expected a top level entity");
158 return nullptr;
159
160 // If we got to the end of the file, then we're done.
161 case Token::eof:
162 return module.release();
163
164 // If we got an error token, then the lexer already emitted an error, just
165 // stop. Someday we could introduce error recovery if there was demand for
166 // it.
167 case Token::error:
168 return nullptr;
169
170 case Token::kw_extfunc:
171 if (parseExtFunc())
172 return nullptr;
173 break;
174
175 // TODO: cfgfunc, mlfunc, affine entity declarations, etc.
176 }
177 }
178}
179
180//===----------------------------------------------------------------------===//
181
182/// This parses the file specified by the indicated SourceMgr and returns an
183/// MLIR module if it was valid. If not, it emits diagnostics and returns null.
184Module *mlir::parseSourceFile(llvm::SourceMgr &sourceMgr) {
185 return Parser(sourceMgr).parseModule();
186}