20#include "llvm/ADT/STLExtras.h"
21#include "llvm/ADT/StringExtras.h"
22#include "llvm/ADT/StringSwitch.h"
23#include "llvm/Support/ErrorHandling.h"
24#include "llvm/Support/SourceMgr.h"
33 return c ==
'$' || c ==
'.' || c ==
'_' || c ==
'-';
38 : sourceMgr(sourceMgr), context(context), codeCompleteLoc(
nullptr) {
39 auto bufferID = sourceMgr.getMainFileID();
43 if (sourceMgr.getNumBuffers() > 1) {
44 unsigned lastFileID = sourceMgr.getNumBuffers();
45 const llvm::MemoryBuffer *main = sourceMgr.getMemoryBuffer(bufferID);
46 const llvm::MemoryBuffer *last = sourceMgr.getMemoryBuffer(lastFileID);
47 if (main->getBufferStart() <= last->getBufferStart() &&
48 main->getBufferEnd() >= last->getBufferEnd()) {
49 bufferID = lastFileID;
52 curBuffer = sourceMgr.getMemoryBuffer(bufferID)->getBuffer();
53 curPtr = curBuffer.begin();
56 if (codeCompleteContext)
57 codeCompleteLoc = codeCompleteContext->getCodeCompleteLoc().getPointer();
64 unsigned mainFileID = sourceMgr.getMainFileID();
66 auto [lineNo, column] = sourceMgr.getLineAndColumn(loc);
67 auto *buffer = sourceMgr.getMemoryBuffer(mainFileID);
74Token Lexer::emitError(
const char *loc,
const Twine &message) {
77 return formToken(Token::error, loc);
81 const char *curBufferEnd = curBuffer.end();
83 const char *tokStart = curPtr;
86 if (tokStart == codeCompleteLoc)
87 return formToken(Token::code_complete, tokStart);
89 if (tokStart == curBufferEnd)
90 return formToken(Token::eof, tokStart);
96 if (isalpha(curPtr[-1]))
97 return lexBareIdentifierOrKeyword(tokStart);
100 return emitError(tokStart,
"unexpected character");
111 return lexBareIdentifierOrKeyword(tokStart);
118 return formToken(Token::colon, tokStart);
120 return formToken(Token::comma, tokStart);
122 return lexEllipsis(tokStart);
124 return formToken(Token::l_paren, tokStart);
126 return formToken(Token::r_paren, tokStart);
128 if (peek() ==
'-' && peek(1) ==
'#') {
130 return formToken(Token::file_metadata_begin, tokStart);
132 return formToken(Token::l_brace, tokStart);
134 return formToken(Token::r_brace, tokStart);
136 return formToken(Token::l_square, tokStart);
138 return formToken(Token::r_square, tokStart);
140 return formToken(Token::less, tokStart);
142 return formToken(Token::greater, tokStart);
144 return formToken(Token::equal, tokStart);
147 return formToken(Token::plus, tokStart);
149 return formToken(Token::star, tokStart);
153 return formToken(Token::arrow, tokStart);
155 return formToken(Token::minus, tokStart);
158 return formToken(Token::question, tokStart);
161 return formToken(Token::vertical_bar, tokStart);
168 return formToken(Token::slash, tokStart);
171 return lexAtIdentifier(tokStart);
174 if (peek() ==
'-' && peek(1) ==
'}') {
176 return formToken(Token::file_metadata_end, tokStart);
182 return lexPrefixedIdentifier(tokStart);
184 return lexString(tokStart);
196 return lexNumber(tokStart);
205Token Lexer::lexAtIdentifier(
const char *tokStart) {
211 Token stringIdentifier = lexString(curPtr);
212 if (stringIdentifier.
is(Token::error))
213 return stringIdentifier;
214 return formToken(Token::at_identifier, tokStart);
218 if (!isalpha(cur) && cur !=
'_')
220 "@ identifier expected to start with letter or '_'");
223 while (isalpha(peek()) || isdigit(peek()) || peek() ==
'_' || peek() ==
'$' ||
226 return formToken(Token::at_identifier, tokStart);
234Token Lexer::lexBareIdentifierOrKeyword(
const char *tokStart) {
236 while (isalpha(peek()) || isdigit(peek()) || peek() ==
'_' || peek() ==
'$' ||
241 StringRef spelling(tokStart, curPtr - tokStart);
243 auto isAllDigit = [](StringRef str) {
244 return llvm::all_of(str, llvm::isDigit);
248 if ((spelling.size() > 1 && tokStart[0] ==
'i' &&
249 isAllDigit(spelling.drop_front())) ||
250 ((spelling.size() > 2 && tokStart[1] ==
'i' &&
251 (tokStart[0] ==
's' || tokStart[0] ==
'u')) &&
252 isAllDigit(spelling.drop_front(2))))
253 return Token(Token::inttype, spelling);
256#define TOK_KEYWORD(SPELLING) .Case(#SPELLING, Token::kw_##SPELLING)
257#include "TokenKinds.def"
258 .Default(Token::bare_identifier);
260 return Token(kind, spelling);
267void Lexer::skipComment() {
269 assert(peek() ==
'/');
272 const char *curBufferEnd = curBuffer.end();
274 if (curPtr == curBufferEnd)
293Token Lexer::lexEllipsis(
const char *tokStart) {
294 assert(curPtr[-1] ==
'.');
296 if (peek() !=
'.' || peek(1) !=
'.')
297 return emitError(curPtr,
"expected three consecutive dots for an ellipsis");
300 return formToken(Token::ellipsis, tokStart);
308Token Lexer::lexNumber(
const char *tokStart) {
309 assert(isdigit(curPtr[-1]));
312 if (curPtr[-1] ==
'0' && peek() ==
'x') {
315 if (!isxdigit(peek(1)))
316 return formToken(Token::integer, tokStart);
319 while (isxdigit(peek()))
322 return formToken(Token::integer, tokStart);
326 while (isdigit(peek()))
330 return formToken(Token::integer, tokStart);
334 while (isdigit(peek()))
337 if (peek() ==
'e' || peek() ==
'E') {
338 if (isdigit(
static_cast<unsigned char>(peek(1))) ||
339 ((peek(1) ==
'-' || peek(1) ==
'+') &&
340 isdigit(
static_cast<unsigned char>(peek(2))))) {
342 while (isdigit(peek()))
346 return formToken(Token::floatliteral, tokStart);
358Token Lexer::lexPrefixedIdentifier(
const char *tokStart) {
363 kind = Token::hash_identifier;
364 errorKind =
"invalid attribute name";
367 kind = Token::percent_identifier;
368 errorKind =
"invalid SSA name";
371 kind = Token::caret_identifier;
372 errorKind =
"invalid block name";
375 kind = Token::exclamation_identifier;
376 errorKind =
"invalid type identifier";
379 llvm_unreachable(
"invalid caller");
383 if (isdigit(peek())) {
385 while (isdigit(peek()))
387 }
else if (isalpha(peek()) ||
isPunct(peek())) {
390 }
while (isalpha(peek()) || isdigit(peek()) ||
isPunct(peek()));
391 }
else if (curPtr == codeCompleteLoc) {
392 return formToken(Token::code_complete, tokStart);
394 return emitError(curPtr - 1, errorKind);
398 if (codeCompleteLoc && codeCompleteLoc >= tokStart &&
399 codeCompleteLoc <= curPtr) {
400 return Token(Token::code_complete,
401 StringRef(tokStart, codeCompleteLoc - tokStart));
404 return formToken(kind, tokStart);
412Token Lexer::lexString(
const char *tokStart) {
413 assert(curPtr[-1] ==
'"');
415 const char *curBufferEnd = curBuffer.end();
421 if (curPtr == codeCompleteLoc)
422 return formToken(Token::code_complete, tokStart);
424 if (curPtr == curBufferEnd)
425 return emitError(curPtr,
"expected '\"' in string literal");
430 return formToken(Token::string, tokStart);
434 return emitError(curPtr - 1,
"expected '\"' in string literal");
437 if (peek() ==
'"' || peek() ==
'\\' || peek() ==
'n' || peek() ==
't')
439 else if (llvm::isHexDigit(peek()) && llvm::isHexDigit(peek(1)))
443 return emitError(curPtr - 1,
"unknown escape in string literal");
static bool isPunct(char c)
This class provides an abstract interface into the parser for hooking in code completion events.
static FileLineColLoc get(StringAttr filename, unsigned line, unsigned column)
Location getEncodedSourceLocation(SMLoc loc)
Encode the specified source location information into a Location object for attachment to the IR or e...
const llvm::SourceMgr & getSourceMgr()
Lexer(const llvm::SourceMgr &sourceMgr, MLIRContext *context, AsmParserCodeCompleteContext *codeCompleteContext)
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
This represents a token in the MLIR syntax.
Include the generated interface declarations.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
llvm::StringSwitch< T, R > StringSwitch