1 //===- Lexer.h - MLIR PDLL Frontend Lexer -----------------------*- 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 LIB_TOOLS_PDLL_PARSER_LEXER_H_
10 #define LIB_TOOLS_PDLL_PARSER_LEXER_H_
11 
12 #include "mlir/Support/LLVM.h"
13 #include "llvm/ADT/StringRef.h"
14 #include "llvm/Support/SMLoc.h"
15 
16 namespace llvm {
17 class SourceMgr;
18 } // namespace llvm
19 
20 namespace mlir {
21 struct LogicalResult;
22 
23 namespace pdll {
24 namespace ast {
25 class DiagnosticEngine;
26 } // namespace ast
27 
28 //===----------------------------------------------------------------------===//
29 // Token
30 //===----------------------------------------------------------------------===//
31 
32 class Token {
33 public:
34   enum Kind {
35     // Markers.
36     eof,
37     error,
38 
39     // Keywords.
40     KW_BEGIN,
41     // Dependent keywords, i.e. those that are treated as keywords depending on
42     // the current parser context.
43     KW_DEPENDENT_BEGIN,
44     kw_attr,
45     kw_op,
46     kw_type,
47     KW_DEPENDENT_END,
48 
49     // General keywords.
50     kw_Attr,
51     kw_erase,
52     kw_let,
53     kw_Constraint,
54     kw_Op,
55     kw_OpName,
56     kw_Pattern,
57     kw_replace,
58     kw_rewrite,
59     kw_Type,
60     kw_TypeRange,
61     kw_Value,
62     kw_ValueRange,
63     kw_with,
64     KW_END,
65 
66     // Punctuation.
67     arrow,
68     colon,
69     comma,
70     dot,
71     equal,
72     equal_arrow,
73     semicolon,
74     // Paired punctuation.
75     less,
76     greater,
77     l_brace,
78     r_brace,
79     l_paren,
80     r_paren,
81     l_square,
82     r_square,
83     underscore,
84 
85     // Tokens.
86     directive,
87     identifier,
88     integer,
89     string_block,
90     string
91   };
92   Token(Kind kind, StringRef spelling) : kind(kind), spelling(spelling) {}
93 
94   /// Given a token containing a string literal, return its value, including
95   /// removing the quote characters and unescaping the contents of the string.
96   std::string getStringValue() const;
97 
98   /// Returns true if the current token is a string literal.
99   bool isString() const { return isAny(Token::string, Token::string_block); }
100 
101   /// Returns true if the current token is a keyword.
102   bool isKeyword() const {
103     return kind > Token::KW_BEGIN && kind < Token::KW_END;
104   }
105 
106   /// Returns true if the current token is a keyword in a dependent context, and
107   /// in any other situation (e.g. variable names) may be treated as an
108   /// identifier.
109   bool isDependentKeyword() const {
110     return kind > Token::KW_DEPENDENT_BEGIN && kind < Token::KW_DEPENDENT_END;
111   }
112 
113   /// Return the bytes that make up this token.
114   StringRef getSpelling() const { return spelling; }
115 
116   /// Return the kind of this token.
117   Kind getKind() const { return kind; }
118 
119   /// Return true if this token is one of the specified kinds.
120   bool isAny(Kind k1, Kind k2) const { return is(k1) || is(k2); }
121   template <typename... T>
122   bool isAny(Kind k1, Kind k2, Kind k3, T... others) const {
123     return is(k1) || isAny(k2, k3, others...);
124   }
125 
126   /// Return if the token does not have the given kind.
127   bool isNot(Kind k) const { return k != kind; }
128   template <typename... T> bool isNot(Kind k1, Kind k2, T... others) const {
129     return !isAny(k1, k2, others...);
130   }
131 
132   /// Return if the token has the given kind.
133   bool is(Kind k) const { return kind == k; }
134 
135   /// Return a location for the start of this token.
136   llvm::SMLoc getStartLoc() const {
137     return llvm::SMLoc::getFromPointer(spelling.data());
138   }
139   /// Return a location at the end of this token.
140   llvm::SMLoc getEndLoc() const {
141     return llvm::SMLoc::getFromPointer(spelling.data() + spelling.size());
142   }
143   /// Return a location for the range of this token.
144   llvm::SMRange getLoc() const {
145     return llvm::SMRange(getStartLoc(), getEndLoc());
146   }
147 
148 private:
149   /// Discriminator that indicates the kind of token this is.
150   Kind kind;
151 
152   /// A reference to the entire token contents; this is always a pointer into
153   /// a memory buffer owned by the source manager.
154   StringRef spelling;
155 };
156 
157 //===----------------------------------------------------------------------===//
158 // Lexer
159 //===----------------------------------------------------------------------===//
160 
161 class Lexer {
162 public:
163   Lexer(llvm::SourceMgr &mgr, ast::DiagnosticEngine &diagEngine);
164   ~Lexer();
165 
166   /// Return a reference to the source manager used by the lexer.
167   llvm::SourceMgr &getSourceMgr() { return srcMgr; }
168 
169   /// Return a reference to the diagnostic engine used by the lexer.
170   ast::DiagnosticEngine &getDiagEngine() { return diagEngine; }
171 
172   /// Push an include of the given file. This will cause the lexer to start
173   /// processing the provided file. Returns failure if the file could not be
174   /// opened, success otherwise.
175   LogicalResult pushInclude(StringRef filename);
176 
177   /// Lex the next token and return it.
178   Token lexToken();
179 
180   /// Change the position of the lexer cursor. The next token we lex will start
181   /// at the designated point in the input.
182   void resetPointer(const char *newPointer) { curPtr = newPointer; }
183 
184   /// Emit an error to the lexer with the given location and message.
185   Token emitError(llvm::SMRange loc, const Twine &msg);
186   Token emitError(const char *loc, const Twine &msg);
187   Token emitErrorAndNote(llvm::SMRange loc, const Twine &msg,
188                          llvm::SMRange noteLoc, const Twine &note);
189 
190 private:
191   Token formToken(Token::Kind kind, const char *tokStart) {
192     return Token(kind, StringRef(tokStart, curPtr - tokStart));
193   }
194 
195   /// Return the next character in the stream.
196   int getNextChar();
197 
198   /// Lex methods.
199   void lexComment();
200   Token lexDirective(const char *tokStart);
201   Token lexIdentifier(const char *tokStart);
202   Token lexNumber(const char *tokStart);
203   Token lexString(const char *tokStart, bool isStringBlock);
204 
205   llvm::SourceMgr &srcMgr;
206   int curBufferID;
207   StringRef curBuffer;
208   const char *curPtr;
209 
210   /// The engine used to emit diagnostics during lexing/parsing.
211   ast::DiagnosticEngine &diagEngine;
212 
213   /// A flag indicating if we added a default diagnostic handler to the provided
214   /// diagEngine.
215   bool addedHandlerToDiagEngine;
216 };
217 } // namespace pdll
218 } // namespace mlir
219 
220 #endif // LIB_TOOLS_PDLL_PARSER_LEXER_H_
221