blob: d2a875a29a86198a95aa0e94f54ea211497f9676 [file] [log] [blame]
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001// Copyright 2020 The Tint Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "src/tint/reader/wgsl/lexer.h"
16
17#include <limits>
Ben Clayton8b09bc92022-05-30 17:54:38 +000018#include <tuple>
19#include <vector>
Ryan Harrisondbc13af2022-02-21 15:19:07 +000020
21#include "gtest/gtest.h"
Zhaoming Jiang0fb4e2c2022-06-10 18:18:35 +000022#include "src/tint/number.h"
Ryan Harrisondbc13af2022-02-21 15:19:07 +000023
dan sinclair30a03d92022-04-07 17:55:04 +000024namespace tint::reader::wgsl {
Ryan Harrisondbc13af2022-02-21 15:19:07 +000025namespace {
26
27using LexerTest = testing::Test;
28
Antonio Maiorano25775302022-04-25 19:49:01 +000029// Blankspace constants. These are macros on purpose to be able to easily build
30// up string literals with them.
31//
32// Same line code points
33#define kSpace " "
34#define kHTab "\t"
35#define kL2R "\xE2\x80\x8E"
36#define kR2L "\xE2\x80\x8F"
37// Line break code points
38#define kCR "\r"
39#define kLF "\n"
40#define kVTab "\x0B"
41#define kFF "\x0C"
42#define kNL "\xC2\x85"
43#define kLS "\xE2\x80\xA8"
44#define kPS "\xE2\x80\xA9"
45
Ryan Harrisondbc13af2022-02-21 15:19:07 +000046TEST_F(LexerTest, Empty) {
dan sinclair41e4d9a2022-05-01 14:40:55 +000047 Source::File file("", "");
48 Lexer l(&file);
dan sinclair0cbf5a92022-07-25 16:43:08 +000049
50 auto list = l.Lex();
51 ASSERT_EQ(1u, list.size());
52 EXPECT_TRUE(list[0].IsEof());
Ryan Harrisondbc13af2022-02-21 15:19:07 +000053}
54
Antonio Maiorano25775302022-04-25 19:49:01 +000055TEST_F(LexerTest, Skips_Blankspace_Basic) {
dan sinclair41e4d9a2022-05-01 14:40:55 +000056 Source::File file("", "\t\r\n\t ident\t\n\t \r ");
57 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +000058
dan sinclair0cbf5a92022-07-25 16:43:08 +000059 auto list = l.Lex();
60 ASSERT_EQ(2u, list.size());
Ryan Harrisondbc13af2022-02-21 15:19:07 +000061
dan sinclair0cbf5a92022-07-25 16:43:08 +000062 {
63 auto& t = list[0];
64 EXPECT_TRUE(t.IsIdentifier());
65 EXPECT_EQ(t.source().range.begin.line, 2u);
66 EXPECT_EQ(t.source().range.begin.column, 6u);
67 EXPECT_EQ(t.source().range.end.line, 2u);
68 EXPECT_EQ(t.source().range.end.column, 11u);
69 EXPECT_EQ(t.to_str(), "ident");
70 }
71
72 {
73 auto& t = list[1];
74 EXPECT_TRUE(t.IsEof());
75 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +000076}
77
Antonio Maiorano25775302022-04-25 19:49:01 +000078TEST_F(LexerTest, Skips_Blankspace_Exotic) {
dan sinclair41e4d9a2022-05-01 14:40:55 +000079 Source::File file("", //
80 kVTab kFF kNL kLS kPS kL2R kR2L //
81 "ident" //
82 kVTab kFF kNL kLS kPS kL2R kR2L);
83 Lexer l(&file);
Antonio Maiorano25775302022-04-25 19:49:01 +000084
dan sinclair0cbf5a92022-07-25 16:43:08 +000085 auto list = l.Lex();
86 ASSERT_EQ(2u, list.size());
Antonio Maiorano25775302022-04-25 19:49:01 +000087
dan sinclair0cbf5a92022-07-25 16:43:08 +000088 {
89 auto& t = list[0];
90 EXPECT_TRUE(t.IsIdentifier());
91 EXPECT_EQ(t.source().range.begin.line, 6u);
92 EXPECT_EQ(t.source().range.begin.column, 7u);
93 EXPECT_EQ(t.source().range.end.line, 6u);
94 EXPECT_EQ(t.source().range.end.column, 12u);
95 EXPECT_EQ(t.to_str(), "ident");
96 }
97
98 {
99 auto& t = list[1];
100 EXPECT_TRUE(t.IsEof());
101 }
Antonio Maiorano25775302022-04-25 19:49:01 +0000102}
103
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000104TEST_F(LexerTest, Skips_Comments_Line) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000105 Source::File file("", R"(//starts with comment
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000106ident1 //ends with comment
107// blank line
108 ident2)");
dan sinclair41e4d9a2022-05-01 14:40:55 +0000109 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000110
dan sinclair0cbf5a92022-07-25 16:43:08 +0000111 auto list = l.Lex();
112 ASSERT_EQ(3u, list.size());
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000113
dan sinclair0cbf5a92022-07-25 16:43:08 +0000114 {
115 auto& t = list[0];
116 EXPECT_TRUE(t.IsIdentifier());
117 EXPECT_EQ(t.source().range.begin.line, 2u);
118 EXPECT_EQ(t.source().range.begin.column, 1u);
119 EXPECT_EQ(t.source().range.end.line, 2u);
120 EXPECT_EQ(t.source().range.end.column, 7u);
121 EXPECT_EQ(t.to_str(), "ident1");
122 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000123
dan sinclair0cbf5a92022-07-25 16:43:08 +0000124 {
125 auto& t = list[1];
126 EXPECT_TRUE(t.IsIdentifier());
127 EXPECT_EQ(t.source().range.begin.line, 4u);
128 EXPECT_EQ(t.source().range.begin.column, 2u);
129 EXPECT_EQ(t.source().range.end.line, 4u);
130 EXPECT_EQ(t.source().range.end.column, 8u);
131 EXPECT_EQ(t.to_str(), "ident2");
132 }
133
134 {
135 auto& t = list[2];
136 EXPECT_TRUE(t.IsEof());
137 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000138}
139
Antonio Maiorano25775302022-04-25 19:49:01 +0000140TEST_F(LexerTest, Skips_Comments_Unicode) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000141 Source::File file("", R"(// starts with 🙂🙂🙂
Antonio Maiorano25775302022-04-25 19:49:01 +0000142ident1 //ends with 🙂🙂🙂
143// blank line
144 ident2)");
dan sinclair41e4d9a2022-05-01 14:40:55 +0000145 Lexer l(&file);
Antonio Maiorano25775302022-04-25 19:49:01 +0000146
dan sinclair0cbf5a92022-07-25 16:43:08 +0000147 auto list = l.Lex();
148 ASSERT_EQ(3u, list.size());
Antonio Maiorano25775302022-04-25 19:49:01 +0000149
dan sinclair0cbf5a92022-07-25 16:43:08 +0000150 {
151 auto& t = list[0];
152 EXPECT_TRUE(t.IsIdentifier());
153 EXPECT_EQ(t.source().range.begin.line, 2u);
154 EXPECT_EQ(t.source().range.begin.column, 1u);
155 EXPECT_EQ(t.source().range.end.line, 2u);
156 EXPECT_EQ(t.source().range.end.column, 7u);
157 EXPECT_EQ(t.to_str(), "ident1");
158 }
Antonio Maiorano25775302022-04-25 19:49:01 +0000159
dan sinclair0cbf5a92022-07-25 16:43:08 +0000160 {
161 auto& t = list[1];
162 EXPECT_TRUE(t.IsIdentifier());
163 EXPECT_EQ(t.source().range.begin.line, 4u);
164 EXPECT_EQ(t.source().range.begin.column, 2u);
165 EXPECT_EQ(t.source().range.end.line, 4u);
166 EXPECT_EQ(t.source().range.end.column, 8u);
167 EXPECT_EQ(t.to_str(), "ident2");
168 }
169
170 {
171 auto& t = list[2];
172 EXPECT_TRUE(t.IsEof());
173 }
Antonio Maiorano25775302022-04-25 19:49:01 +0000174}
175
176using LineCommentTerminatorTest = testing::TestWithParam<const char*>;
James Price453d5ae2022-03-16 21:45:44 +0000177TEST_P(LineCommentTerminatorTest, Terminators) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000178 // Test that line comments are ended by blankspace characters other than
179 // space, horizontal tab, left-to-right mark, and right-to-left mark.
Ben Claytone55877d2022-05-04 13:58:49 +0000180 auto* c = GetParam();
Ben Claytone48ef8e2022-06-26 10:52:50 +0000181 std::string src = "const// This is a comment";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000182 src += c;
183 src += "ident";
184 Source::File file("", src);
185 Lexer l(&file);
James Price453d5ae2022-03-16 21:45:44 +0000186
dan sinclair41e4d9a2022-05-01 14:40:55 +0000187 auto is_same_line = [](std::string_view v) {
188 return v == kSpace || v == kHTab || v == kL2R || v == kR2L;
189 };
Antonio Maiorano25775302022-04-25 19:49:01 +0000190
dan sinclair0cbf5a92022-07-25 16:43:08 +0000191 auto list = l.Lex();
192 ASSERT_EQ(is_same_line(c) ? 2u : 3u, list.size());
193
194 size_t idx = 0;
195
196 {
197 auto& t = list[idx++];
198 EXPECT_TRUE(t.Is(Token::Type::kConst));
199 EXPECT_EQ(t.source().range.begin.line, 1u);
200 EXPECT_EQ(t.source().range.begin.column, 1u);
201 EXPECT_EQ(t.source().range.end.line, 1u);
202 EXPECT_EQ(t.source().range.end.column, 6u);
203 }
204
dan sinclair41e4d9a2022-05-01 14:40:55 +0000205 if (!is_same_line(c)) {
206 size_t line = is_same_line(c) ? 1u : 2u;
207 size_t col = is_same_line(c) ? 25u : 1u;
dan sinclair0cbf5a92022-07-25 16:43:08 +0000208
209 auto& t = list[idx++];
dan sinclair41e4d9a2022-05-01 14:40:55 +0000210 EXPECT_TRUE(t.IsIdentifier());
211 EXPECT_EQ(t.source().range.begin.line, line);
212 EXPECT_EQ(t.source().range.begin.column, col);
213 EXPECT_EQ(t.source().range.end.line, line);
214 EXPECT_EQ(t.source().range.end.column, col + 5);
215 EXPECT_EQ(t.to_str(), "ident");
216 }
217
dan sinclair0cbf5a92022-07-25 16:43:08 +0000218 {
219 auto& t = list[idx];
220 EXPECT_TRUE(t.IsEof());
221 }
James Price453d5ae2022-03-16 21:45:44 +0000222}
223INSTANTIATE_TEST_SUITE_P(LexerTest,
224 LineCommentTerminatorTest,
Antonio Maiorano25775302022-04-25 19:49:01 +0000225 testing::Values(
226 // same line
227 kSpace,
228 kHTab,
229 kCR,
230 kL2R,
231 kR2L,
232 // line break
233 kLF,
234 kVTab,
235 kFF,
236 kNL,
237 kLS,
238 kPS));
James Price453d5ae2022-03-16 21:45:44 +0000239
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000240TEST_F(LexerTest, Skips_Comments_Block) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000241 Source::File file("", R"(/* comment
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000242text */ident)");
dan sinclair41e4d9a2022-05-01 14:40:55 +0000243 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000244
dan sinclair0cbf5a92022-07-25 16:43:08 +0000245 auto list = l.Lex();
246 ASSERT_EQ(2u, list.size());
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000247
dan sinclair0cbf5a92022-07-25 16:43:08 +0000248 {
249 auto& t = list[0];
250 EXPECT_TRUE(t.IsIdentifier());
251 EXPECT_EQ(t.source().range.begin.line, 2u);
252 EXPECT_EQ(t.source().range.begin.column, 8u);
253 EXPECT_EQ(t.source().range.end.line, 2u);
254 EXPECT_EQ(t.source().range.end.column, 13u);
255 EXPECT_EQ(t.to_str(), "ident");
256 }
257
258 {
259 auto& t = list[1];
260 EXPECT_TRUE(t.IsEof());
261 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000262}
263
264TEST_F(LexerTest, Skips_Comments_Block_Nested) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000265 Source::File file("", R"(/* comment
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000266text // nested line comments are ignored /* more text
267/////**/ */*/ident)");
dan sinclair41e4d9a2022-05-01 14:40:55 +0000268 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000269
dan sinclair0cbf5a92022-07-25 16:43:08 +0000270 auto list = l.Lex();
271 ASSERT_EQ(2u, list.size());
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000272
dan sinclair0cbf5a92022-07-25 16:43:08 +0000273 {
274 auto& t = list[0];
275 EXPECT_TRUE(t.IsIdentifier());
276 EXPECT_EQ(t.source().range.begin.line, 3u);
277 EXPECT_EQ(t.source().range.begin.column, 14u);
278 EXPECT_EQ(t.source().range.end.line, 3u);
279 EXPECT_EQ(t.source().range.end.column, 19u);
280 EXPECT_EQ(t.to_str(), "ident");
281 }
282
283 {
284 auto& t = list[1];
285 EXPECT_TRUE(t.IsEof());
286 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000287}
288
289TEST_F(LexerTest, Skips_Comments_Block_Unterminated) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000290 // I had to break up the /* because otherwise the clang readability check
291 // errored out saying it could not find the end of a multi-line comment.
292 Source::File file("", R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000293 /)"
dan sinclair41e4d9a2022-05-01 14:40:55 +0000294 R"(*
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000295abcd)");
dan sinclair41e4d9a2022-05-01 14:40:55 +0000296 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000297
dan sinclair0cbf5a92022-07-25 16:43:08 +0000298 auto list = l.Lex();
299 ASSERT_EQ(1u, list.size());
300
301 auto& t = list[0];
dan sinclair41e4d9a2022-05-01 14:40:55 +0000302 ASSERT_TRUE(t.Is(Token::Type::kError));
303 EXPECT_EQ(t.to_str(), "unterminated block comment");
304 EXPECT_EQ(t.source().range.begin.line, 2u);
305 EXPECT_EQ(t.source().range.begin.column, 3u);
306 EXPECT_EQ(t.source().range.end.line, 2u);
307 EXPECT_EQ(t.source().range.end.column, 4u);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000308}
309
James Price453d5ae2022-03-16 21:45:44 +0000310TEST_F(LexerTest, Null_InBlankspace_IsError) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000311 Source::File file("", std::string{' ', 0, ' '});
312 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000313
dan sinclair0cbf5a92022-07-25 16:43:08 +0000314 auto list = l.Lex();
315 ASSERT_EQ(1u, list.size());
316
317 auto& t = list[0];
dan sinclair41e4d9a2022-05-01 14:40:55 +0000318 EXPECT_TRUE(t.IsError());
319 EXPECT_EQ(t.source().range.begin.line, 1u);
320 EXPECT_EQ(t.source().range.begin.column, 2u);
321 EXPECT_EQ(t.source().range.end.line, 1u);
322 EXPECT_EQ(t.source().range.end.column, 2u);
323 EXPECT_EQ(t.to_str(), "null character found");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000324}
325
326TEST_F(LexerTest, Null_InLineComment_IsError) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000327 Source::File file("", std::string{'/', '/', ' ', 0, ' '});
328 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000329
dan sinclair0cbf5a92022-07-25 16:43:08 +0000330 auto list = l.Lex();
331 ASSERT_EQ(1u, list.size());
332
333 auto& t = list[0];
dan sinclair41e4d9a2022-05-01 14:40:55 +0000334 EXPECT_TRUE(t.IsError());
335 EXPECT_EQ(t.source().range.begin.line, 1u);
336 EXPECT_EQ(t.source().range.begin.column, 4u);
337 EXPECT_EQ(t.source().range.end.line, 1u);
338 EXPECT_EQ(t.source().range.end.column, 4u);
339 EXPECT_EQ(t.to_str(), "null character found");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000340}
341
342TEST_F(LexerTest, Null_InBlockComment_IsError) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000343 Source::File file("", std::string{'/', '*', ' ', 0, '*', '/'});
344 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000345
dan sinclair0cbf5a92022-07-25 16:43:08 +0000346 auto list = l.Lex();
347 ASSERT_EQ(1u, list.size());
348
349 auto& t = list[0];
dan sinclair41e4d9a2022-05-01 14:40:55 +0000350 EXPECT_TRUE(t.IsError());
351 EXPECT_EQ(t.source().range.begin.line, 1u);
352 EXPECT_EQ(t.source().range.begin.column, 4u);
353 EXPECT_EQ(t.source().range.end.line, 1u);
354 EXPECT_EQ(t.source().range.end.column, 4u);
355 EXPECT_EQ(t.to_str(), "null character found");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000356}
357
358TEST_F(LexerTest, Null_InIdentifier_IsError) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000359 // Try inserting a null in an identifier. Other valid token
360 // kinds will behave similarly, so use the identifier case
361 // as a representative.
362 Source::File file("", std::string{'a', 0, 'c'});
363 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000364
dan sinclair0cbf5a92022-07-25 16:43:08 +0000365 auto list = l.Lex();
366 ASSERT_EQ(2u, list.size());
367
368 {
369 auto& t = list[0];
370 EXPECT_TRUE(t.IsIdentifier());
371 EXPECT_EQ(t.to_str(), "a");
372 }
373
374 {
375 auto& t = list[1];
376 EXPECT_TRUE(t.IsError());
377 EXPECT_EQ(t.source().range.begin.line, 1u);
378 EXPECT_EQ(t.source().range.begin.column, 2u);
379 EXPECT_EQ(t.source().range.end.line, 1u);
380 EXPECT_EQ(t.source().range.end.column, 2u);
381 EXPECT_EQ(t.to_str(), "null character found");
382 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000383}
384
385struct FloatData {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000386 const char* input;
Ben Clayton41285aa2022-05-10 14:55:34 +0000387 double result;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000388};
389inline std::ostream& operator<<(std::ostream& out, FloatData data) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000390 out << std::string(data.input);
391 return out;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000392}
393using FloatTest = testing::TestWithParam<FloatData>;
394TEST_P(FloatTest, Parse) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000395 auto params = GetParam();
396 Source::File file("", params.input);
397 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000398
dan sinclair0cbf5a92022-07-25 16:43:08 +0000399 auto list = l.Lex();
400 ASSERT_EQ(2u, list.size());
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000401
dan sinclair0cbf5a92022-07-25 16:43:08 +0000402 {
403 auto& t = list[0];
404 if (std::string(params.input).back() == 'f') {
405 EXPECT_TRUE(t.Is(Token::Type::kFloatLiteral_F));
406 } else if (std::string(params.input).back() == 'h') {
407 EXPECT_TRUE(t.Is(Token::Type::kFloatLiteral_H));
408 } else {
409 EXPECT_TRUE(t.Is(Token::Type::kFloatLiteral));
410 }
411 EXPECT_EQ(t.to_f64(), params.result);
412 EXPECT_EQ(t.source().range.begin.line, 1u);
413 EXPECT_EQ(t.source().range.begin.column, 1u);
414 EXPECT_EQ(t.source().range.end.line, 1u);
415 EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
416 }
417
418 {
419 auto& t = list[1];
420 EXPECT_TRUE(t.IsEof());
421 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000422}
423INSTANTIATE_TEST_SUITE_P(LexerTest,
424 FloatTest,
425 testing::Values(
426 // No decimal, with 'f' suffix
Ben Clayton41285aa2022-05-10 14:55:34 +0000427 FloatData{"0f", 0.0},
428 FloatData{"1f", 1.0},
Zhaoming Jiang0fb4e2c2022-06-10 18:18:35 +0000429 // No decimal, with 'h' suffix
430 FloatData{"0h", 0.0},
431 FloatData{"1h", 1.0},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000432
433 // Zero, with decimal.
Ben Clayton41285aa2022-05-10 14:55:34 +0000434 FloatData{"0.0", 0.0},
435 FloatData{"0.", 0.0},
436 FloatData{".0", 0.0},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000437 // Zero, with decimal and 'f' suffix
Ben Clayton41285aa2022-05-10 14:55:34 +0000438 FloatData{"0.0f", 0.0},
439 FloatData{"0.f", 0.0},
440 FloatData{".0f", 0.0},
Zhaoming Jiang0fb4e2c2022-06-10 18:18:35 +0000441 // Zero, with decimal and 'h' suffix
442 FloatData{"0.0h", 0.0},
443 FloatData{"0.h", 0.0},
444 FloatData{".0h", 0.0},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000445
446 // Non-zero with decimal
Ben Clayton41285aa2022-05-10 14:55:34 +0000447 FloatData{"5.7", 5.7},
448 FloatData{"5.", 5.},
449 FloatData{".7", .7},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000450 // Non-zero with decimal and 'f' suffix
Ben Claytone6c03a32022-05-26 19:39:05 +0000451 FloatData{"5.7f", static_cast<double>(5.7f)},
452 FloatData{"5.f", static_cast<double>(5.f)},
453 FloatData{".7f", static_cast<double>(.7f)},
Zhaoming Jiang0fb4e2c2022-06-10 18:18:35 +0000454 // Non-zero with decimal and 'h' suffix
455 FloatData{"5.7h", static_cast<double>(f16::Quantize(5.7f))},
456 FloatData{"5.h", static_cast<double>(f16::Quantize(5.f))},
457 FloatData{".7h", static_cast<double>(f16::Quantize(.7f))},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000458
459 // No decimal, with exponent
Ben Clayton41285aa2022-05-10 14:55:34 +0000460 FloatData{"1e5", 1e5},
461 FloatData{"1E5", 1e5},
462 FloatData{"1e-5", 1e-5},
463 FloatData{"1E-5", 1e-5},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000464 // No decimal, with exponent and 'f' suffix
Ben Claytone6c03a32022-05-26 19:39:05 +0000465 FloatData{"1e5f", static_cast<double>(1e5f)},
466 FloatData{"1E5f", static_cast<double>(1e5f)},
467 FloatData{"1e-5f", static_cast<double>(1e-5f)},
468 FloatData{"1E-5f", static_cast<double>(1e-5f)},
Zhaoming Jiang0fb4e2c2022-06-10 18:18:35 +0000469 // No decimal, with exponent and 'h' suffix
470 FloatData{"6e4h", static_cast<double>(f16::Quantize(6e4f))},
471 FloatData{"6E4h", static_cast<double>(f16::Quantize(6e4f))},
472 FloatData{"1e-5h", static_cast<double>(f16::Quantize(1e-5f))},
473 FloatData{"1E-5h", static_cast<double>(f16::Quantize(1e-5f))},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000474 // With decimal and exponents
Ben Clayton41285aa2022-05-10 14:55:34 +0000475 FloatData{"0.2e+12", 0.2e12},
476 FloatData{"1.2e-5", 1.2e-5},
477 FloatData{"2.57e23", 2.57e23},
478 FloatData{"2.5e+0", 2.5},
479 FloatData{"2.5e-0", 2.5},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000480 // With decimal and exponents and 'f' suffix
Ben Claytone6c03a32022-05-26 19:39:05 +0000481 FloatData{"0.2e+12f", static_cast<double>(0.2e12f)},
482 FloatData{"1.2e-5f", static_cast<double>(1.2e-5f)},
483 FloatData{"2.57e23f", static_cast<double>(2.57e23f)},
484 FloatData{"2.5e+0f", static_cast<double>(2.5f)},
485 FloatData{"2.5e-0f", static_cast<double>(2.5f)},
Zhaoming Jiang0fb4e2c2022-06-10 18:18:35 +0000486 // With decimal and exponents and 'h' suffix
487 FloatData{"0.2e+5h", static_cast<double>(f16::Quantize(0.2e5f))},
488 FloatData{"1.2e-5h", static_cast<double>(f16::Quantize(1.2e-5f))},
489 FloatData{"6.55e4h", static_cast<double>(f16::Quantize(6.55e4f))},
490 FloatData{"2.5e+0h", static_cast<double>(f16::Quantize(2.5f))},
491 FloatData{"2.5e-0h", static_cast<double>(f16::Quantize(2.5f))},
Ben Claytone6c03a32022-05-26 19:39:05 +0000492 // Quantization
Zhaoming Jiang0fb4e2c2022-06-10 18:18:35 +0000493 FloatData{"3.141592653589793", 3.141592653589793}, // no quantization
494 FloatData{"3.141592653589793f", 3.1415927410125732}, // f32 quantized
495 FloatData{"3.141592653589793h", 3.140625} // f16 quantized
Ben Claytone6c03a32022-05-26 19:39:05 +0000496 ));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000497
498using FloatTest_Invalid = testing::TestWithParam<const char*>;
499TEST_P(FloatTest_Invalid, Handles) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000500 Source::File file("", GetParam());
501 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000502
dan sinclair0cbf5a92022-07-25 16:43:08 +0000503 auto list = l.Lex();
504 ASSERT_FALSE(list.empty());
505
506 auto& t = list[0];
Zhaoming Jiang0fb4e2c2022-06-10 18:18:35 +0000507 EXPECT_FALSE(t.Is(Token::Type::kFloatLiteral) || t.Is(Token::Type::kFloatLiteral_F) ||
508 t.Is(Token::Type::kFloatLiteral_H));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000509}
dan sinclair41e4d9a2022-05-01 14:40:55 +0000510INSTANTIATE_TEST_SUITE_P(LexerTest,
511 FloatTest_Invalid,
512 testing::Values(".",
dan sinclair41e4d9a2022-05-01 14:40:55 +0000513 // Need a mantissa digit
514 ".e5",
515 ".E5",
516 // Need exponent digits
517 ".e",
518 ".e+",
519 ".e-",
520 ".E",
521 ".e+",
522 ".e-",
523 // Overflow
Ben Claytone6c03a32022-05-26 19:39:05 +0000524 "2.5e+256f",
Zhaoming Jiang0fb4e2c2022-06-10 18:18:35 +0000525 "6.5520e+4h",
dan sinclair41e4d9a2022-05-01 14:40:55 +0000526 // Decimal exponent must immediately
527 // follow the 'e'.
528 "2.5e 12",
529 "2.5e +12",
530 "2.5e -12",
531 "2.5e+ 123",
532 "2.5e- 123",
533 "2.5E 12",
534 "2.5E +12",
535 "2.5E -12",
536 "2.5E+ 123",
537 "2.5E- 123"));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000538
539using AsciiIdentifierTest = testing::TestWithParam<const char*>;
540TEST_P(AsciiIdentifierTest, Parse) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000541 Source::File file("", GetParam());
542 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000543
dan sinclair0cbf5a92022-07-25 16:43:08 +0000544 auto list = l.Lex();
545 ASSERT_EQ(2u, list.size());
546
547 {
548 auto& t = list[0];
549 EXPECT_TRUE(t.IsIdentifier());
550 EXPECT_EQ(t.source().range.begin.line, 1u);
551 EXPECT_EQ(t.source().range.begin.column, 1u);
552 EXPECT_EQ(t.source().range.end.line, 1u);
553 EXPECT_EQ(t.source().range.end.column, 1u + strlen(GetParam()));
554 EXPECT_EQ(t.to_str(), GetParam());
555 }
556
557 {
558 auto& t = list[1];
559 EXPECT_TRUE(t.IsEof());
560 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000561}
562INSTANTIATE_TEST_SUITE_P(LexerTest,
563 AsciiIdentifierTest,
564 testing::Values("a",
565 "test",
566 "test01",
567 "test_",
568 "_test",
569 "test_01",
570 "ALLCAPS",
571 "MiXeD_CaSe",
572 "abcdefghijklmnopqrstuvwxyz",
573 "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
574 "alldigits_0123456789"));
575
576struct UnicodeCase {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000577 const char* utf8;
578 size_t count;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000579};
580
Ben Clayton64b77542022-03-15 16:18:03 +0000581using ValidUnicodeIdentifierTest = testing::TestWithParam<UnicodeCase>;
582TEST_P(ValidUnicodeIdentifierTest, Parse) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000583 Source::File file("", GetParam().utf8);
584 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000585
dan sinclair0cbf5a92022-07-25 16:43:08 +0000586 auto list = l.Lex();
587 ASSERT_EQ(2u, list.size());
588
589 {
590 auto& t = list[0];
591 EXPECT_TRUE(t.IsIdentifier());
592 EXPECT_EQ(t.source().range.begin.line, 1u);
593 EXPECT_EQ(t.source().range.begin.column, 1u);
594 EXPECT_EQ(t.source().range.end.line, 1u);
595 EXPECT_EQ(t.source().range.end.column, 1u + GetParam().count);
596 EXPECT_EQ(t.to_str(), GetParam().utf8);
597 }
598
599 {
600 auto& t = list[1];
601 EXPECT_TRUE(t.IsEof());
602 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000603}
604INSTANTIATE_TEST_SUITE_P(
605 LexerTest,
Ben Clayton64b77542022-03-15 16:18:03 +0000606 ValidUnicodeIdentifierTest,
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000607 testing::ValuesIn({
608 UnicodeCase{// "𝐢𝐝𝐞𝐧𝐭𝐢𝐟𝐢𝐞𝐫"
609 "\xf0\x9d\x90\xa2\xf0\x9d\x90\x9d\xf0\x9d\x90\x9e\xf0\x9d"
610 "\x90\xa7\xf0\x9d\x90\xad\xf0\x9d\x90\xa2\xf0\x9d\x90\x9f"
611 "\xf0\x9d\x90\xa2\xf0\x9d\x90\x9e\xf0\x9d\x90\xab",
612 40},
613 UnicodeCase{// "𝑖𝑑𝑒𝑛𝑡𝑖𝑓𝑖𝑒𝑟"
614 "\xf0\x9d\x91\x96\xf0\x9d\x91\x91\xf0\x9d\x91\x92\xf0\x9d"
615 "\x91\x9b\xf0\x9d\x91\xa1\xf0\x9d\x91\x96\xf0\x9d\x91\x93"
616 "\xf0\x9d\x91\x96\xf0\x9d\x91\x92\xf0\x9d\x91\x9f",
617 40},
dan sinclair41e4d9a2022-05-01 14:40:55 +0000618 UnicodeCase{// "identifier"
619 "\xef\xbd\x89\xef\xbd\x84\xef\xbd\x85\xef\xbd\x8e\xef\xbd\x94\xef"
620 "\xbd\x89\xef\xbd\x86\xef\xbd\x89\xef\xbd\x85\xef\xbd\x92",
621 30},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000622 UnicodeCase{// "𝕚𝕕𝕖𝕟𝕥𝕚𝕗𝕚𝕖𝕣𝟙𝟚𝟛"
623 "\xf0\x9d\x95\x9a\xf0\x9d\x95\x95\xf0\x9d\x95\x96\xf0\x9d"
624 "\x95\x9f\xf0\x9d\x95\xa5\xf0\x9d\x95\x9a\xf0\x9d\x95\x97"
625 "\xf0\x9d\x95\x9a\xf0\x9d\x95\x96\xf0\x9d\x95\xa3\xf0\x9d"
626 "\x9f\x99\xf0\x9d\x9f\x9a\xf0\x9d\x9f\x9b",
627 52},
dan sinclair41e4d9a2022-05-01 14:40:55 +0000628 UnicodeCase{// "𝖎𝖉𝖊𝖓𝖙𝖎𝖋𝖎𝖊𝖗123"
629 "\xf0\x9d\x96\x8e\xf0\x9d\x96\x89\xf0\x9d\x96\x8a\xf0\x9d\x96\x93"
630 "\xf0\x9d\x96\x99\xf0\x9d\x96\x8e\xf0\x9d\x96\x8b\xf0\x9d\x96\x8e"
631 "\xf0\x9d\x96\x8a\xf0\x9d\x96\x97\x31\x32\x33",
632 43},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000633 }));
634
Ben Clayton64b77542022-03-15 16:18:03 +0000635using InvalidUnicodeIdentifierTest = testing::TestWithParam<const char*>;
636TEST_P(InvalidUnicodeIdentifierTest, Parse) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000637 Source::File file("", GetParam());
638 Lexer l(&file);
Ben Clayton64b77542022-03-15 16:18:03 +0000639
dan sinclair0cbf5a92022-07-25 16:43:08 +0000640 auto list = l.Lex();
641 ASSERT_FALSE(list.empty());
642
643 auto& t = list[0];
dan sinclair41e4d9a2022-05-01 14:40:55 +0000644 EXPECT_TRUE(t.IsError());
645 EXPECT_EQ(t.source().range.begin.line, 1u);
646 EXPECT_EQ(t.source().range.begin.column, 1u);
647 EXPECT_EQ(t.source().range.end.line, 1u);
648 EXPECT_EQ(t.source().range.end.column, 1u);
649 EXPECT_EQ(t.to_str(), "invalid UTF-8");
Ben Clayton64b77542022-03-15 16:18:03 +0000650}
dan sinclair41e4d9a2022-05-01 14:40:55 +0000651INSTANTIATE_TEST_SUITE_P(LexerTest,
652 InvalidUnicodeIdentifierTest,
653 testing::ValuesIn({
654 "\x80\x80\x80\x80", // 10000000
655 "\x81\x80\x80\x80", // 10000001
656 "\x8f\x80\x80\x80", // 10001111
657 "\x90\x80\x80\x80", // 10010000
658 "\x91\x80\x80\x80", // 10010001
659 "\x9f\x80\x80\x80", // 10011111
660 "\xa0\x80\x80\x80", // 10100000
661 "\xa1\x80\x80\x80", // 10100001
662 "\xaf\x80\x80\x80", // 10101111
663 "\xb0\x80\x80\x80", // 10110000
664 "\xb1\x80\x80\x80", // 10110001
665 "\xbf\x80\x80\x80", // 10111111
666 "\xc0\x80\x80\x80", // 11000000
667 "\xc1\x80\x80\x80", // 11000001
668 "\xf5\x80\x80\x80", // 11110101
669 "\xf6\x80\x80\x80", // 11110110
670 "\xf7\x80\x80\x80", // 11110111
671 "\xf8\x80\x80\x80", // 11111000
672 "\xfe\x80\x80\x80", // 11111110
673 "\xff\x80\x80\x80", // 11111111
Ben Clayton64b77542022-03-15 16:18:03 +0000674
dan sinclair41e4d9a2022-05-01 14:40:55 +0000675 "\xd0", // 2-bytes, missing second byte
676 "\xe8\x8f", // 3-bytes, missing third byte
677 "\xf4\x8f\x8f", // 4-bytes, missing fourth byte
Ben Clayton64b77542022-03-15 16:18:03 +0000678
dan sinclair41e4d9a2022-05-01 14:40:55 +0000679 "\xd0\x7f", // 2-bytes, second byte MSB unset
680 "\xe8\x7f\x8f", // 3-bytes, second byte MSB unset
681 "\xe8\x8f\x7f", // 3-bytes, third byte MSB unset
682 "\xf4\x7f\x8f\x8f", // 4-bytes, second byte MSB unset
683 "\xf4\x8f\x7f\x8f", // 4-bytes, third byte MSB unset
684 "\xf4\x8f\x8f\x7f", // 4-bytes, fourth byte MSB unset
685 }));
Ben Clayton64b77542022-03-15 16:18:03 +0000686
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000687TEST_F(LexerTest, IdentifierTest_SingleUnderscoreDoesNotMatch) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000688 Source::File file("", "_");
689 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000690
dan sinclair0cbf5a92022-07-25 16:43:08 +0000691 auto list = l.Lex();
692 ASSERT_FALSE(list.empty());
693
694 auto& t = list[0];
dan sinclair41e4d9a2022-05-01 14:40:55 +0000695 EXPECT_FALSE(t.IsIdentifier());
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000696}
697
698TEST_F(LexerTest, IdentifierTest_DoesNotStartWithDoubleUnderscore) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000699 Source::File file("", "__test");
700 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000701
dan sinclair0cbf5a92022-07-25 16:43:08 +0000702 auto list = l.Lex();
703 ASSERT_FALSE(list.empty());
704
705 auto& t = list[0];
dan sinclair41e4d9a2022-05-01 14:40:55 +0000706 EXPECT_FALSE(t.IsIdentifier());
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000707}
708
709TEST_F(LexerTest, IdentifierTest_DoesNotStartWithNumber) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000710 Source::File file("", "01test");
711 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000712
dan sinclair0cbf5a92022-07-25 16:43:08 +0000713 auto list = l.Lex();
714 EXPECT_FALSE(list.empty());
715
716 auto& t = list[0];
dan sinclair41e4d9a2022-05-01 14:40:55 +0000717 EXPECT_FALSE(t.IsIdentifier());
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000718}
719
Ben Clayton8b09bc92022-05-30 17:54:38 +0000720////////////////////////////////////////////////////////////////////////////////
721// ParseIntegerTest
722////////////////////////////////////////////////////////////////////////////////
723struct ParseIntegerCase {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000724 const char* input;
Ben Clayton8b09bc92022-05-30 17:54:38 +0000725 int64_t result;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000726};
Ben Clayton8b09bc92022-05-30 17:54:38 +0000727
728inline std::ostream& operator<<(std::ostream& out, ParseIntegerCase data) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000729 out << std::string(data.input);
730 return out;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000731}
732
Ben Clayton8b09bc92022-05-30 17:54:38 +0000733using ParseIntegerTest = testing::TestWithParam<std::tuple<char, ParseIntegerCase>>;
734TEST_P(ParseIntegerTest, Parse) {
735 auto suffix = std::get<0>(GetParam());
736 auto params = std::get<1>(GetParam());
dan sinclair41e4d9a2022-05-01 14:40:55 +0000737 Source::File file("", params.input);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000738
dan sinclair0cbf5a92022-07-25 16:43:08 +0000739 Lexer l(&file);
740
741 auto list = l.Lex();
742 ASSERT_FALSE(list.empty());
743
744 auto& t = list[0];
Ben Clayton8b09bc92022-05-30 17:54:38 +0000745 switch (suffix) {
746 case 'i':
747 EXPECT_TRUE(t.Is(Token::Type::kIntLiteral_I));
748 break;
749 case 'u':
750 EXPECT_TRUE(t.Is(Token::Type::kIntLiteral_U));
751 break;
752 case 0:
753 EXPECT_TRUE(t.Is(Token::Type::kIntLiteral));
754 break;
dan sinclair41e4d9a2022-05-01 14:40:55 +0000755 }
dan sinclair41e4d9a2022-05-01 14:40:55 +0000756 EXPECT_EQ(t.source().range.begin.line, 1u);
757 EXPECT_EQ(t.source().range.begin.column, 1u);
758 EXPECT_EQ(t.source().range.end.line, 1u);
759 EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
Ben Clayton8b09bc92022-05-30 17:54:38 +0000760 ASSERT_FALSE(t.IsError()) << t.to_str();
Ben Claytonf6934882022-05-04 21:01:12 +0000761 EXPECT_EQ(t.to_i64(), params.result);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000762}
763
Ben Clayton8b09bc92022-05-30 17:54:38 +0000764INSTANTIATE_TEST_SUITE_P(Dec_AInt,
765 ParseIntegerTest,
766 testing::Combine(testing::Values('\0'), // No suffix
767 testing::ValuesIn(std::vector<ParseIntegerCase>{
768 {"0", 0},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000769 {"2", 2},
770 {"123", 123},
771 {"2147483647", 2147483647},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000772 })));
773
774INSTANTIATE_TEST_SUITE_P(Dec_u32,
775 ParseIntegerTest,
776 testing::Combine(testing::Values('u'), // Suffix
777 testing::ValuesIn(std::vector<ParseIntegerCase>{
778 {"0u", 0},
779 {"123u", 123},
780 {"4294967295u", 4294967295ll},
781 })));
782
783INSTANTIATE_TEST_SUITE_P(Dec_i32,
784 ParseIntegerTest,
785 testing::Combine(testing::Values('i'), // Suffix
786 testing::ValuesIn(std::vector<ParseIntegerCase>{
787 {"0i", 0u},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000788 {"123i", 123},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000789 {"2147483647i", 2147483647},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000790 })));
791
792INSTANTIATE_TEST_SUITE_P(Hex_AInt,
793 ParseIntegerTest,
794 testing::Combine(testing::Values('\0'), // No suffix
795 testing::ValuesIn(std::vector<ParseIntegerCase>{
796 {"0x0", 0},
797 {"0X0", 0},
798 {"0x42", 66},
799 {"0X42", 66},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000800 {"0xeF1Abc9", 0xeF1Abc9},
801 {"0XeF1Abc9", 0xeF1Abc9},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000802 {"0x80000000", 0x80000000},
803 {"0X80000000", 0X80000000},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000804 {"0x7FFFFFFF", 0x7fffffff},
805 {"0X7FFFFFFF", 0x7fffffff},
806 {"0x7fffffff", 0x7fffffff},
807 {"0x7fffffff", 0x7fffffff},
808 {"0x7FfFfFfF", 0x7fffffff},
809 {"0X7FfFfFfF", 0x7fffffff},
810 {"0x7fffffffffffffff", 0x7fffffffffffffffll},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000811 })));
812
813INSTANTIATE_TEST_SUITE_P(Hex_u32,
814 ParseIntegerTest,
815 testing::Combine(testing::Values('u'), // Suffix
816 testing::ValuesIn(std::vector<ParseIntegerCase>{
817 {"0x0u", 0},
818 {"0x42u", 66},
819 {"0xeF1Abc9u", 250719177},
820 {"0xFFFFFFFFu", 0xffffffff},
821 {"0XFFFFFFFFu", 0xffffffff},
822 {"0xffffffffu", 0xffffffff},
823 {"0Xffffffffu", 0xffffffff},
824 {"0xfFfFfFfFu", 0xffffffff},
825 {"0XfFfFfFfFu", 0xffffffff},
826 })));
827
828INSTANTIATE_TEST_SUITE_P(Hex_i32,
829 ParseIntegerTest,
830 testing::Combine(testing::Values('i'), // Suffix
831 testing::ValuesIn(std::vector<ParseIntegerCase>{
832 {"0x0i", 0},
833 {"0x42i", 66},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000834 {"0xeF1Abc9i", 250719177},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000835 {"0x7FFFFFFFi", 0x7fffffff},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000836 {"0X7FFFFFFFi", 0x7fffffff},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000837 {"0x7fffffffi", 0x7fffffff},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000838 {"0X7fffffffi", 0x7fffffff},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000839 {"0x7FfFfFfFi", 0x7fffffff},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000840 {"0X7FfFfFfFi", 0x7fffffff},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000841 })));
842////////////////////////////////////////////////////////////////////////////////
843// ParseIntegerTest_CannotBeRepresented
844////////////////////////////////////////////////////////////////////////////////
845using ParseIntegerTest_CannotBeRepresented =
846 testing::TestWithParam<std::tuple<const char*, const char*>>;
847TEST_P(ParseIntegerTest_CannotBeRepresented, Parse) {
848 auto type = std::get<0>(GetParam());
849 auto source = std::get<1>(GetParam());
850 Source::File file("", source);
dan sinclair0cbf5a92022-07-25 16:43:08 +0000851
852 Lexer l(&file);
853 auto list = l.Lex();
854 ASSERT_FALSE(list.empty());
855
856 auto& t = list[0];
Ben Clayton8b09bc92022-05-30 17:54:38 +0000857 EXPECT_TRUE(t.Is(Token::Type::kError));
858 auto expect = "value cannot be represented as '" + std::string(type) + "'";
859 EXPECT_EQ(t.to_str(), expect);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000860}
Ben Clayton8b09bc92022-05-30 17:54:38 +0000861INSTANTIATE_TEST_SUITE_P(AbstractInt,
862 ParseIntegerTest_CannotBeRepresented,
863 testing::Combine(testing::Values("abstract-int"),
864 testing::Values("9223372036854775808",
865 "0xFFFFFFFFFFFFFFFF",
866 "0xffffffffffffffff",
867 "0x8000000000000000")));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000868
Ben Clayton8b09bc92022-05-30 17:54:38 +0000869INSTANTIATE_TEST_SUITE_P(i32,
870 ParseIntegerTest_CannotBeRepresented,
871 testing::Combine(testing::Values("i32"), // type
872 testing::Values("2147483648i")));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000873
Ben Clayton8b09bc92022-05-30 17:54:38 +0000874INSTANTIATE_TEST_SUITE_P(u32,
875 ParseIntegerTest_CannotBeRepresented,
dan sinclairb3b027d2022-10-26 15:20:47 +0000876 testing::Combine(testing::Values("u32"), // type
877 testing::Values("4294967296u")));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000878
Ben Clayton8b09bc92022-05-30 17:54:38 +0000879////////////////////////////////////////////////////////////////////////////////
880// ParseIntegerTest_LeadingZeros
881////////////////////////////////////////////////////////////////////////////////
882using ParseIntegerTest_LeadingZeros = testing::TestWithParam<const char*>;
883TEST_P(ParseIntegerTest_LeadingZeros, Parse) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000884 Source::File file("", GetParam());
dan sinclair0cbf5a92022-07-25 16:43:08 +0000885
886 Lexer l(&file);
887 auto list = l.Lex();
888 ASSERT_FALSE(list.empty());
889
890 auto& t = list[0];
Ben Clayton8b09bc92022-05-30 17:54:38 +0000891 EXPECT_TRUE(t.Is(Token::Type::kError));
892 EXPECT_EQ(t.to_str(), "integer literal cannot have leading 0s");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000893}
Ben Clayton8b09bc92022-05-30 17:54:38 +0000894
895INSTANTIATE_TEST_SUITE_P(LeadingZero,
896 ParseIntegerTest_LeadingZeros,
dan sinclairb3b027d2022-10-26 15:20:47 +0000897 testing::Values("01234", "0000", "00u"));
Ben Clayton8b09bc92022-05-30 17:54:38 +0000898
899////////////////////////////////////////////////////////////////////////////////
900// ParseIntegerTest_NoSignificantDigits
901////////////////////////////////////////////////////////////////////////////////
902using ParseIntegerTest_NoSignificantDigits = testing::TestWithParam<const char*>;
903TEST_P(ParseIntegerTest_NoSignificantDigits, Parse) {
904 Source::File file("", GetParam());
dan sinclair0cbf5a92022-07-25 16:43:08 +0000905
906 Lexer l(&file);
907 auto list = l.Lex();
908 ASSERT_FALSE(list.empty());
909
910 auto& t = list[0];
Ben Clayton8b09bc92022-05-30 17:54:38 +0000911 EXPECT_TRUE(t.Is(Token::Type::kError));
912 EXPECT_EQ(t.to_str(), "integer or float hex literal has no significant digits");
913}
914
915INSTANTIATE_TEST_SUITE_P(LeadingZero,
916 ParseIntegerTest_NoSignificantDigits,
dan sinclairb3b027d2022-10-26 15:20:47 +0000917 testing::Values("0x", "0X", "0xu", "0Xu", "0xi", "0Xi"));
dan sinclair41e4d9a2022-05-01 14:40:55 +0000918
919struct TokenData {
920 const char* input;
921 Token::Type type;
922};
923inline std::ostream& operator<<(std::ostream& out, TokenData data) {
924 out << std::string(data.input);
925 return out;
926}
927using PunctuationTest = testing::TestWithParam<TokenData>;
928TEST_P(PunctuationTest, Parses) {
929 auto params = GetParam();
930 Source::File file("", params.input);
931 Lexer l(&file);
932
dan sinclair0cbf5a92022-07-25 16:43:08 +0000933 auto list = l.Lex();
934 ASSERT_GE(list.size(), 2u);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000935
dan sinclair0cbf5a92022-07-25 16:43:08 +0000936 {
937 auto& t = list[0];
938 EXPECT_TRUE(t.Is(params.type));
939 EXPECT_EQ(t.source().range.begin.line, 1u);
940 EXPECT_EQ(t.source().range.begin.column, 1u);
941 EXPECT_EQ(t.source().range.end.line, 1u);
942 EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
943 }
944
945 {
946 auto& t = list[1];
947 EXPECT_EQ(t.source().range.begin.column, 1 + std::string(params.input).size());
948 }
dan sinclair41e4d9a2022-05-01 14:40:55 +0000949}
950INSTANTIATE_TEST_SUITE_P(LexerTest,
951 PunctuationTest,
952 testing::Values(TokenData{"&", Token::Type::kAnd},
dan sinclair41e4d9a2022-05-01 14:40:55 +0000953 TokenData{"->", Token::Type::kArrow},
954 TokenData{"@", Token::Type::kAttr},
955 TokenData{"/", Token::Type::kForwardSlash},
956 TokenData{"!", Token::Type::kBang},
957 TokenData{"[", Token::Type::kBracketLeft},
958 TokenData{"]", Token::Type::kBracketRight},
959 TokenData{"{", Token::Type::kBraceLeft},
960 TokenData{"}", Token::Type::kBraceRight},
961 TokenData{":", Token::Type::kColon},
962 TokenData{",", Token::Type::kComma},
963 TokenData{"=", Token::Type::kEqual},
964 TokenData{"==", Token::Type::kEqualEqual},
965 TokenData{">", Token::Type::kGreaterThan},
dan sinclair41e4d9a2022-05-01 14:40:55 +0000966 TokenData{"<", Token::Type::kLessThan},
967 TokenData{"<=", Token::Type::kLessThanEqual},
968 TokenData{"<<", Token::Type::kShiftLeft},
969 TokenData{"%", Token::Type::kMod},
970 TokenData{"!=", Token::Type::kNotEqual},
971 TokenData{"-", Token::Type::kMinus},
dan sinclair41e4d9a2022-05-01 14:40:55 +0000972 TokenData{".", Token::Type::kPeriod},
973 TokenData{"+", Token::Type::kPlus},
974 TokenData{"++", Token::Type::kPlusPlus},
975 TokenData{"|", Token::Type::kOr},
976 TokenData{"||", Token::Type::kOrOr},
977 TokenData{"(", Token::Type::kParenLeft},
978 TokenData{")", Token::Type::kParenRight},
979 TokenData{";", Token::Type::kSemicolon},
980 TokenData{"*", Token::Type::kStar},
981 TokenData{"~", Token::Type::kTilde},
982 TokenData{"_", Token::Type::kUnderscore},
983 TokenData{"^", Token::Type::kXor},
984 TokenData{"+=", Token::Type::kPlusEqual},
985 TokenData{"-=", Token::Type::kMinusEqual},
986 TokenData{"*=", Token::Type::kTimesEqual},
987 TokenData{"/=", Token::Type::kDivisionEqual},
988 TokenData{"%=", Token::Type::kModuloEqual},
989 TokenData{"&=", Token::Type::kAndEqual},
990 TokenData{"|=", Token::Type::kOrEqual},
dan sinclair73778d3b2022-08-02 18:18:05 +0000991 TokenData{"^=", Token::Type::kXorEqual},
dan sinclair73778d3b2022-08-02 18:18:05 +0000992 TokenData{"<<=", Token::Type::kShiftLeftEqual}));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000993
dan sinclair0cbf5a92022-07-25 16:43:08 +0000994using SplittablePunctuationTest = testing::TestWithParam<TokenData>;
995TEST_P(SplittablePunctuationTest, Parses) {
996 auto params = GetParam();
997 Source::File file("", params.input);
998 Lexer l(&file);
999
1000 auto list = l.Lex();
1001 ASSERT_GE(list.size(), 3u);
1002
1003 {
1004 auto& t = list[0];
1005 EXPECT_TRUE(t.Is(params.type));
1006 EXPECT_EQ(t.source().range.begin.line, 1u);
1007 EXPECT_EQ(t.source().range.begin.column, 1u);
1008 EXPECT_EQ(t.source().range.end.line, 1u);
1009 EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
1010 }
1011
Ben Clayton6fc130b2023-01-23 18:32:41 +00001012 const size_t num_placeholders = list[0].NumPlaceholders();
1013 EXPECT_GT(num_placeholders, 0u);
1014 ASSERT_EQ(list.size(), 2u + num_placeholders);
1015
1016 for (size_t i = 0; i < num_placeholders; i++) {
1017 auto& t = list[1 + i];
dan sinclair0cbf5a92022-07-25 16:43:08 +00001018 EXPECT_TRUE(t.Is(Token::Type::kPlaceholder));
1019 EXPECT_EQ(t.source().range.begin.line, 1u);
Ben Clayton6fc130b2023-01-23 18:32:41 +00001020 EXPECT_EQ(t.source().range.begin.column, 2u + i);
dan sinclair0cbf5a92022-07-25 16:43:08 +00001021 EXPECT_EQ(t.source().range.end.line, 1u);
1022 EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
1023 }
1024
1025 {
Ben Clayton6fc130b2023-01-23 18:32:41 +00001026 auto& t = list.back();
1027 EXPECT_TRUE(t.Is(Token::Type::kEOF));
1028 EXPECT_EQ(t.source().range.begin.column, 2u + num_placeholders);
dan sinclair0cbf5a92022-07-25 16:43:08 +00001029 }
1030}
1031INSTANTIATE_TEST_SUITE_P(LexerTest,
1032 SplittablePunctuationTest,
dan sinclair6c8dc152022-08-17 16:30:30 +00001033 testing::Values(TokenData{"&&", Token::Type::kAndAnd},
1034 TokenData{">=", Token::Type::kGreaterThanEqual},
dan sinclair2788bec2022-08-19 21:26:01 +00001035 TokenData{"--", Token::Type::kMinusMinus},
Ben Clayton6fc130b2023-01-23 18:32:41 +00001036 TokenData{">>", Token::Type::kShiftRight},
1037 TokenData{">>=", Token::Type::kShiftRightEqual}));
dan sinclair0cbf5a92022-07-25 16:43:08 +00001038
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001039using KeywordTest = testing::TestWithParam<TokenData>;
1040TEST_P(KeywordTest, Parses) {
dan sinclair41e4d9a2022-05-01 14:40:55 +00001041 auto params = GetParam();
1042 Source::File file("", params.input);
1043 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001044
dan sinclair0cbf5a92022-07-25 16:43:08 +00001045 auto list = l.Lex();
1046 ASSERT_GE(list.size(), 2u);
1047
1048 auto& t = list[0];
dan sinclair41e4d9a2022-05-01 14:40:55 +00001049 EXPECT_TRUE(t.Is(params.type)) << params.input;
1050 EXPECT_EQ(t.source().range.begin.line, 1u);
1051 EXPECT_EQ(t.source().range.begin.column, 1u);
1052 EXPECT_EQ(t.source().range.end.line, 1u);
1053 EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001054
dan sinclair0cbf5a92022-07-25 16:43:08 +00001055 EXPECT_EQ(list[1].source().range.begin.column, 1 + std::string(params.input).size());
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001056}
Ben Clayton643f2aa2023-02-18 08:36:01 +00001057INSTANTIATE_TEST_SUITE_P(LexerTest,
1058 KeywordTest,
1059 testing::Values(TokenData{"alias", Token::Type::kAlias},
1060 TokenData{"bitcast", Token::Type::kBitcast},
1061 TokenData{"break", Token::Type::kBreak},
1062 TokenData{"case", Token::Type::kCase},
1063 TokenData{"const", Token::Type::kConst},
1064 TokenData{"const_assert", Token::Type::kConstAssert},
1065 TokenData{"continue", Token::Type::kContinue},
1066 TokenData{"continuing", Token::Type::kContinuing},
1067 TokenData{"default", Token::Type::kDefault},
1068 TokenData{"diagnostic", Token::Type::kDiagnostic},
1069 TokenData{"discard", Token::Type::kDiscard},
1070 TokenData{"else", Token::Type::kElse},
1071 TokenData{"enable", Token::Type::kEnable},
1072 TokenData{"fallthrough", Token::Type::kFallthrough},
1073 TokenData{"false", Token::Type::kFalse},
1074 TokenData{"fn", Token::Type::kFn},
1075 TokenData{"for", Token::Type::kFor},
1076 TokenData{"if", Token::Type::kIf},
1077 TokenData{"let", Token::Type::kLet},
1078 TokenData{"loop", Token::Type::kLoop},
1079 TokenData{"override", Token::Type::kOverride},
1080 TokenData{"return", Token::Type::kReturn},
1081 TokenData{"static_assert", Token::Type::kStaticAssert},
1082 TokenData{"struct", Token::Type::kStruct},
1083 TokenData{"switch", Token::Type::kSwitch},
1084 TokenData{"true", Token::Type::kTrue},
1085 TokenData{"type", Token::Type::kType},
1086 TokenData{"var", Token::Type::kVar},
1087 TokenData{"while", Token::Type::kWhile}));
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001088
1089} // namespace
dan sinclair30a03d92022-04-07 17:55:04 +00001090} // namespace tint::reader::wgsl