Branch data Line data Source code
1 : : #include "lex/Lexer.hpp"
2 : :
3 : : #include <cctype>
4 : :
5 : :
6 : : #define UNDO(CHR) { in.putback(c_); c_ = CHR; pos_.column--; }
7 : :
8 [ + - ]: 2149 :
9 [ + - ]: 2149 : using namespace m;
10 [ + - ]: 2149 : using namespace m::ast;
11 [ + - ]: 2149 :
12 [ + - ]: 2149 :
13 [ + - ]: 4298 : void Lexer::initialize_keywords()
14 [ + - ]: 2149 : {
15 [ + - ]: 2149 : #define M_KEYWORD(tok, text) keywords_.emplace(pool(#text), TK_##tok);
16 [ + - ]: 2149 : #include <mutable/tables/Keywords.tbl>
17 [ + - ]: 2149 : #undef M_KEYWORD
18 [ + - ]: 4298 : }
19 [ + - ]: 2149 :
20 [ + - ]: 29324 : Token Lexer::next()
21 [ + - ]: 2149 : {
22 [ + - ]: 2149 : /* skip whitespaces and comments */
23 [ + - ]: 29324 : for (;;) {
24 [ + - + + : 55805 : switch (c_) {
+ + ]
25 [ + - + - ]: 6146 : case EOF: return Token(pos_, pool("EOF"), TK_EOF);
26 [ + - ]: 28628 : case ' ': case '\t': case '\v': case '\f': case '\n': case '\r': step(); continue;
27 [ + - ]: 2149 :
28 [ + - ]: 2149 : case '-': {
29 [ + - ]: 2236 : step();
30 [ + - + + ]: 2236 : if (c_ == '-') {
31 [ + - ]: 2149 : /* read comment */
32 [ + - + + : 2201 : do step(); while (c_ != EOF and c_ != '\n');
+ + ]
33 [ + - ]: 2151 : continue;
34 [ + - ]: 2149 : } else {
35 [ + - ]: 2149 : /* TK_MINUS */
36 [ + - ]: 2234 : UNDO('-');
37 [ + - ]: 2234 : goto after;
38 [ + - ]: 2149 : }
39 [ + - ]: 2149 : }
40 [ + - ]: 2149 :
41 [ + - ]: 25242 : default: goto after;
42 [ + - ]: 2149 : }
43 [ + - ]: 2149 : }
44 [ + - ]: 2149 : after:
45 [ + - ]: 2149 :
46 [ + - ]: 25327 : start_ = pos_;
47 [ + - ]: 25327 : buf_.clear();
48 [ + - ]: 2149 :
49 [ + - + + : 25327 : switch (c_) {
+ + + + +
+ + + + +
+ + + + +
+ + + ]
50 [ + - ]: 2149 : case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
51 [ + - ]: 5688 : return read_number();
52 [ + - ]: 2149 :
53 [ + - ]: 2149 : case '"':
54 [ + - ]: 2312 : return read_string_literal();
55 [ + - ]: 2149 :
56 [ + - ]: 2149 : case 'd': {
57 [ + - ]: 2263 : step();
58 [ + - + + ]: 2263 : if (c_ == '\'') {
59 [ + - ]: 2215 : buf_.push_back('d'); // add prefix 'd'
60 [ + - ]: 2215 : return read_date_or_datetime();
61 [ + - ]: 2149 : } else {
62 [ + - ]: 2197 : UNDO('d');
63 [ + - ]: 2197 : return read_keyword_or_identifier();
64 [ + - ]: 2149 : }
65 [ + - ]: 2149 : }
66 [ + - ]: 2149 :
67 [ + - ]: 2149 : /* Punctuators */
68 [ - + ]: 2149 : #define LEX(chr, text, tt, SUB) case chr: step(); switch (c_) { SUB } return Token(start_, pool(text), tt);
69 : : #define GUESS(first, SUB) case first: step(); switch (c_) { SUB } UNDO(first); break;
70 [ + - ]: 1251 : LEX('(', "(", TK_LPAR, );
71 [ + - ]: 1231 : LEX(')', ")", TK_RPAR, );
72 [ + - ]: 7 : LEX('~', "~", TK_TILDE, );
73 [ + - ]: 80 : LEX('+', "+", TK_PLUS, );
74 [ + - ]: 86 : LEX('-', "-", TK_MINUS, );
75 [ + - ]: 360 : LEX('*', "*", TK_ASTERISK, );
76 [ + - ]: 15 : LEX('/', "/", TK_SLASH, );
77 [ + - ]: 6 : LEX('%', "%", TK_PERCENT, );
78 [ + - ]: 409 : LEX('=', "=", TK_EQUAL, );
79 [ + + + - ]: 29 : GUESS('!',
80 : : LEX('=', "!=", TK_BANG_EQUAL, ) );
81 [ + + + - : 54 : LEX('<', "<", TK_LESS,
+ - ]
82 : : LEX('=', "<=", TK_LESS_EQUAL, ) );
83 [ + + + - : 46 : LEX('>', ">", TK_GREATER,
+ - ]
84 : : LEX('=', ">=", TK_GREATER_EQUAL, ) );
85 [ + - ]: 3080 : LEX(',', ",", TK_COMMA, );
86 [ + - ]: 1364 : LEX(';', ";", TK_SEMICOL, );
87 [ + + + - : 845 : LEX('.', ".", TK_DOT,
+ - + ]
88 : : LEX('.', "..", TK_DOTDOT, )
89 : : case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
90 : : UNDO('.');
91 : : return read_number(););
92 : : case '\\':
93 : 22 : return read_instruction();
94 : :
95 : : #undef LEX
96 : : #undef GUESS
97 : :
98 : : default: /* fallthrough */;
99 : 10478 : }
100 : :
101 [ + + + + ]: 10480 : if ('_' == c_ or is_alpha(c_)) return read_keyword_or_identifier();
102 : :
103 : 41 : push();
104 : 41 : const auto str = internalize();
105 [ + - + - : 41 : diag.e(start_) << "illegal character '" << str << "'\n";
+ - + - ]
106 [ + - + - ]: 41 : return Token(start_, std::move(str), TK_ERROR);
107 : 27175 : }
108 : :
109 : :
110 : : /*====================================================================================================================*/
111 : : //
112 : : // Lexer functions
113 : : //
114 : : /*====================================================================================================================*/
115 : :
116 : 10487 : Token Lexer::read_keyword_or_identifier()
117 : : {
118 [ + + + + ]: 53156 : while ('_' == c_ or is_alnum(c_))
119 : 42669 : push();
120 : 10487 : const auto str = internalize();
121 [ + - ]: 10487 : auto it = keywords_.find(str);
122 [ + + + - : 10487 : if (it == keywords_.end()) return Token(start_, std::move(str), TK_IDENTIFIER);
+ - ]
123 [ + - + - ]: 5918 : else return Token(start_, std::move(str), it->second);
124 : 10487 : }
125 : :
126 : 3629 : Token Lexer::read_number()
127 : : {
128 : 3629 : bool is_float = false;
129 : 3629 : bool empty = true;
130 : : enum { Oct, Dec, Hex } is, has;
131 : :
132 : : /*-- Prefix ----------------------*/
133 : 3629 : is = Dec;
134 [ + + ]: 3629 : if ('0' == c_) { is = Oct; empty = false; push(); }
135 [ + + + + ]: 3629 : if ('x' == c_ || 'X' == c_) { is = Hex; empty = true; push(); }
136 : 3725 : has = is;
137 : :
138 : : /*-- sequence before dot ---------*/
139 : 10781 : for (;;) {
140 [ + + + + ]: 10781 : if (is == Oct && is_oct(c_)) /* OK */;
141 [ + + + + ]: 10725 : else if (is == Oct && is_dec(c_)) has = Dec;
142 [ + + + + ]: 10724 : else if (is == Dec && is_dec(c_)) /* OK */;
143 [ + + + + ]: 4036 : else if (is == Hex && is_hex(c_)) /* OK */;
144 : 3725 : else break;
145 : 7056 : empty = false;
146 : 7056 : push();
147 : : }
148 : :
149 : : /*-- the dot ---------------------*/
150 [ + + ]: 3725 : if ('.' == c_) {
151 : 100 : push();
152 : 100 : is_float = true;
153 [ + + ]: 100 : if (is == Oct) is = Dec; // there are no octal floating point constants
154 [ + + ]: 100 : if (has == Oct) has = Dec;
155 : :
156 : : /*-- sequence after dot ------*/
157 [ + + + + : 396 : if (is == Dec) { if (is_dec(c_)) empty = false; while (is_dec(c_)) push(); }
+ + ]
158 [ + + + + ]: 77 : else { M_insist(is == Hex); if (is_hex(c_)) empty = false; while (is_hex(c_)) push(); }
159 : 100 : }
160 : :
161 : : /*-- exponent part ---------------*/
162 [ + + + + : 3767 : if ((is == Oct && ('e' == c_ || 'E' == c_)) ||
+ + ]
163 [ + + + + ]: 6983 : (is == Dec && ('e' == c_ || 'E' == c_)) ||
164 [ + + + + ]: 3577 : (is == Hex && ('p' == c_ || 'P' == c_))) {
165 : 6894 : push();
166 : 6894 : is_float = true;
167 [ + + ]: 6894 : if (is == Oct) is = Dec; // there are no octal floating point constants
168 [ + + ]: 16 : if (has == Oct) has = Dec;
169 [ + + + + ]: 16 : if ('-' == c_ || '+' == c_) push();
170 : 16 : empty = true;
171 [ + + ]: 82 : while (is_dec(c_)) { empty = false; push(); }
172 : 16 : }
173 : :
174 [ + + + + ]: 3545 : if (empty or is != has) {
175 : 6 : const auto str = internalize();
176 [ + - + - : 6 : diag.e(start_) << "invalid number '" << str << "'\n";
+ - + - ]
177 [ + - + - ]: 6 : return Token(start_, std::move(str), TK_ERROR);
178 : 6 : }
179 : : TokenType tt;
180 [ - + + + ]: 3539 : switch (is) {
181 : 88 : case Oct: tt = TK_OCT_INT; break;
182 : 3406 : case Dec: tt = is_float ? TK_DEC_FLOAT : TK_DEC_INT; break;
183 : 45 : case Hex: tt = is_float ? TK_HEX_FLOAT : TK_HEX_INT; break;
184 : : }
185 [ + - ]: 3539 : return Token(start_, internalize(), tt);
186 : 3545 : }
187 : :
188 : 163 : Token Lexer::read_string_literal()
189 : : {
190 : 163 : push(); // initial '"'
191 : 163 : bool invalid = false;
192 [ + + + + ]: 1275 : while (EOF != c_ and '"' != c_) {
193 [ + + ]: 1112 : if (c_ == '\\') { // escape character
194 : 6 : push();
195 [ + + ]: 6 : switch (c_) {
196 : : default:
197 : : /* invalid escape sequence */
198 : 1 : invalid = true;
199 : : /* fallthrough */
200 : : case '"':
201 : : case '\\':
202 : : case 'n':
203 : : case 't':
204 : : /* valid escape sequence */
205 : 6 : push();
206 : 6 : }
207 : 6 : } else {
208 : 1106 : push();
209 : : }
210 : : }
211 : :
212 [ + + ]: 163 : if ('"' != c_) {
213 : 1 : const auto str = internalize();
214 [ + - + - : 1 : diag.e(start_) << "unterminated string literal '" << str << "'\n";
+ - + - ]
215 [ + - - + ]: 1 : return Token(start_, std::move(str), TK_ERROR);
216 : 1 : }
217 : :
218 : 162 : push(); // terminal '"'
219 : 162 : const auto str = internalize();
220 : :
221 [ + + ]: 162 : if (invalid) {
222 [ + - + - : 1 : diag.e(start_) << "invalid escape sequence in string literal '" << str << "'\n";
+ - + - ]
223 [ + - - + ]: 1 : return Token(start_, std::move(str), TK_ERROR);
224 : : }
225 : :
226 [ + - + - ]: 161 : return Token(start_, std::move(str), TK_STRING_LITERAL);
227 : 163 : }
228 : :
229 : 66 : Token Lexer::read_date_or_datetime()
230 : : {
231 : 66 : push(); // initial '''
232 : 66 : bool invalid = false;
233 : 66 : bool datetime = false;
234 : :
235 : : #define DIGITS(num) for (auto i = 0; i < num; ++i) if (is_dec(c_)) push(); else invalid = true;
236 : 66 : accept('-'); // for years BC
237 [ + + + + ]: 330 : DIGITS(4); // year
238 : 66 : invalid &= accept('-');
239 [ + + + + ]: 198 : DIGITS(2); // month
240 : 66 : invalid &= accept('-');
241 [ + + + + ]: 198 : DIGITS(2); // day
242 : :
243 [ + + ]: 66 : if (accept(' ')) {
244 : 33 : datetime = true;
245 [ + + + + ]: 99 : DIGITS(2) // hours
246 : 33 : invalid &= accept(':');
247 [ + + + + ]: 99 : DIGITS(2); // minutes
248 : 33 : invalid &= accept(':');
249 [ + + + + ]: 99 : DIGITS(2); // seconds
250 : 33 : }
251 : : #undef DIGITS
252 : :
253 [ + + ]: 66 : if ('\'' != c_) {
254 : 11 : const auto str = internalize();
255 [ + - + - : 11 : diag.e(start_) << "unterminated " << (datetime ? "datetime" : "date") << " '" << str << "'\n";
+ - + - +
- + - ]
256 [ + - - + ]: 11 : return Token(start_, std::move(str), TK_ERROR);
257 : 11 : }
258 : :
259 : 55 : push(); // terminal '''
260 : 55 : const auto str = internalize();
261 : :
262 [ + + ]: 55 : if (invalid) {
263 [ + - + - : 6 : diag.e(start_) << "invalid symbol in " << (datetime ? "datetime" : "date") << " '" << str << "'\n";
+ - + - +
- + - ]
264 [ + - - + ]: 6 : return Token(start_, std::move(str), TK_ERROR);
265 : : }
266 : :
267 [ + - + - ]: 49 : return Token(start_, std::move(str), datetime ? TK_DATE_TIME : TK_DATE);
268 : 66 : }
269 : :
270 : 22 : Token Lexer::read_instruction()
271 : : {
272 : 22 : push(); // initial '\'
273 [ + + + + ]: 319 : while (';' != c_ and EOF != c_)
274 : 297 : push();
275 [ + - ]: 22 : return Token(start_, internalize(), TK_INSTRUCTION);
276 : 0 : }
|