blob: 5ddacc1c59516fd62da84cef3cda3e579f38f836 [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
dan sinclair61190452023-07-26 20:47:54 +000015#include "src/tint/lang/wgsl/reader/parser/lexer.h"
Ryan Harrisondbc13af2022-02-21 15:19:07 +000016
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"
dan sinclairce6dffe2023-08-14 21:01:40 +000022#include "src/tint/lang/core/fluent_types.h"
Ben Claytoncd52f382023-08-07 13:11:08 +000023#include "src/tint/lang/core/number.h"
Ryan Harrisondbc13af2022-02-21 15:19:07 +000024
dan sinclairce6dffe2023-08-14 21:01:40 +000025using namespace tint::core::fluent_types; // NOLINT
26
dan sinclair61190452023-07-26 20:47:54 +000027namespace tint::wgsl::reader {
Ryan Harrisondbc13af2022-02-21 15:19:07 +000028namespace {
29
30using LexerTest = testing::Test;
31
Antonio Maiorano25775302022-04-25 19:49:01 +000032// Blankspace constants. These are macros on purpose to be able to easily build
33// up string literals with them.
34//
35// Same line code points
36#define kSpace " "
37#define kHTab "\t"
38#define kL2R "\xE2\x80\x8E"
39#define kR2L "\xE2\x80\x8F"
40// Line break code points
41#define kCR "\r"
42#define kLF "\n"
43#define kVTab "\x0B"
44#define kFF "\x0C"
45#define kNL "\xC2\x85"
46#define kLS "\xE2\x80\xA8"
47#define kPS "\xE2\x80\xA9"
48
Ryan Harrisondbc13af2022-02-21 15:19:07 +000049TEST_F(LexerTest, Empty) {
dan sinclair41e4d9a2022-05-01 14:40:55 +000050 Source::File file("", "");
51 Lexer l(&file);
dan sinclair0cbf5a92022-07-25 16:43:08 +000052
53 auto list = l.Lex();
54 ASSERT_EQ(1u, list.size());
55 EXPECT_TRUE(list[0].IsEof());
Ryan Harrisondbc13af2022-02-21 15:19:07 +000056}
57
Antonio Maiorano25775302022-04-25 19:49:01 +000058TEST_F(LexerTest, Skips_Blankspace_Basic) {
dan sinclair41e4d9a2022-05-01 14:40:55 +000059 Source::File file("", "\t\r\n\t ident\t\n\t \r ");
60 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +000061
dan sinclair0cbf5a92022-07-25 16:43:08 +000062 auto list = l.Lex();
63 ASSERT_EQ(2u, list.size());
Ryan Harrisondbc13af2022-02-21 15:19:07 +000064
dan sinclair0cbf5a92022-07-25 16:43:08 +000065 {
66 auto& t = list[0];
67 EXPECT_TRUE(t.IsIdentifier());
68 EXPECT_EQ(t.source().range.begin.line, 2u);
69 EXPECT_EQ(t.source().range.begin.column, 6u);
70 EXPECT_EQ(t.source().range.end.line, 2u);
71 EXPECT_EQ(t.source().range.end.column, 11u);
72 EXPECT_EQ(t.to_str(), "ident");
73 }
74
75 {
76 auto& t = list[1];
77 EXPECT_TRUE(t.IsEof());
78 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +000079}
80
Antonio Maiorano25775302022-04-25 19:49:01 +000081TEST_F(LexerTest, Skips_Blankspace_Exotic) {
dan sinclair41e4d9a2022-05-01 14:40:55 +000082 Source::File file("", //
83 kVTab kFF kNL kLS kPS kL2R kR2L //
84 "ident" //
85 kVTab kFF kNL kLS kPS kL2R kR2L);
86 Lexer l(&file);
Antonio Maiorano25775302022-04-25 19:49:01 +000087
dan sinclair0cbf5a92022-07-25 16:43:08 +000088 auto list = l.Lex();
89 ASSERT_EQ(2u, list.size());
Antonio Maiorano25775302022-04-25 19:49:01 +000090
dan sinclair0cbf5a92022-07-25 16:43:08 +000091 {
92 auto& t = list[0];
93 EXPECT_TRUE(t.IsIdentifier());
94 EXPECT_EQ(t.source().range.begin.line, 6u);
95 EXPECT_EQ(t.source().range.begin.column, 7u);
96 EXPECT_EQ(t.source().range.end.line, 6u);
97 EXPECT_EQ(t.source().range.end.column, 12u);
98 EXPECT_EQ(t.to_str(), "ident");
99 }
100
101 {
102 auto& t = list[1];
103 EXPECT_TRUE(t.IsEof());
104 }
Antonio Maiorano25775302022-04-25 19:49:01 +0000105}
106
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000107TEST_F(LexerTest, Skips_Comments_Line) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000108 Source::File file("", R"(//starts with comment
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000109ident1 //ends with comment
110// blank line
111 ident2)");
dan sinclair41e4d9a2022-05-01 14:40:55 +0000112 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000113
dan sinclair0cbf5a92022-07-25 16:43:08 +0000114 auto list = l.Lex();
115 ASSERT_EQ(3u, list.size());
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000116
dan sinclair0cbf5a92022-07-25 16:43:08 +0000117 {
118 auto& t = list[0];
119 EXPECT_TRUE(t.IsIdentifier());
120 EXPECT_EQ(t.source().range.begin.line, 2u);
121 EXPECT_EQ(t.source().range.begin.column, 1u);
122 EXPECT_EQ(t.source().range.end.line, 2u);
123 EXPECT_EQ(t.source().range.end.column, 7u);
124 EXPECT_EQ(t.to_str(), "ident1");
125 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000126
dan sinclair0cbf5a92022-07-25 16:43:08 +0000127 {
128 auto& t = list[1];
129 EXPECT_TRUE(t.IsIdentifier());
130 EXPECT_EQ(t.source().range.begin.line, 4u);
131 EXPECT_EQ(t.source().range.begin.column, 2u);
132 EXPECT_EQ(t.source().range.end.line, 4u);
133 EXPECT_EQ(t.source().range.end.column, 8u);
134 EXPECT_EQ(t.to_str(), "ident2");
135 }
136
137 {
138 auto& t = list[2];
139 EXPECT_TRUE(t.IsEof());
140 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000141}
142
Antonio Maiorano25775302022-04-25 19:49:01 +0000143TEST_F(LexerTest, Skips_Comments_Unicode) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000144 Source::File file("", R"(// starts with 🙂🙂🙂
Antonio Maiorano25775302022-04-25 19:49:01 +0000145ident1 //ends with 🙂🙂🙂
146// blank line
147 ident2)");
dan sinclair41e4d9a2022-05-01 14:40:55 +0000148 Lexer l(&file);
Antonio Maiorano25775302022-04-25 19:49:01 +0000149
dan sinclair0cbf5a92022-07-25 16:43:08 +0000150 auto list = l.Lex();
151 ASSERT_EQ(3u, list.size());
Antonio Maiorano25775302022-04-25 19:49:01 +0000152
dan sinclair0cbf5a92022-07-25 16:43:08 +0000153 {
154 auto& t = list[0];
155 EXPECT_TRUE(t.IsIdentifier());
156 EXPECT_EQ(t.source().range.begin.line, 2u);
157 EXPECT_EQ(t.source().range.begin.column, 1u);
158 EXPECT_EQ(t.source().range.end.line, 2u);
159 EXPECT_EQ(t.source().range.end.column, 7u);
160 EXPECT_EQ(t.to_str(), "ident1");
161 }
Antonio Maiorano25775302022-04-25 19:49:01 +0000162
dan sinclair0cbf5a92022-07-25 16:43:08 +0000163 {
164 auto& t = list[1];
165 EXPECT_TRUE(t.IsIdentifier());
166 EXPECT_EQ(t.source().range.begin.line, 4u);
167 EXPECT_EQ(t.source().range.begin.column, 2u);
168 EXPECT_EQ(t.source().range.end.line, 4u);
169 EXPECT_EQ(t.source().range.end.column, 8u);
170 EXPECT_EQ(t.to_str(), "ident2");
171 }
172
173 {
174 auto& t = list[2];
175 EXPECT_TRUE(t.IsEof());
176 }
Antonio Maiorano25775302022-04-25 19:49:01 +0000177}
178
179using LineCommentTerminatorTest = testing::TestWithParam<const char*>;
James Price453d5ae2022-03-16 21:45:44 +0000180TEST_P(LineCommentTerminatorTest, Terminators) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000181 // Test that line comments are ended by blankspace characters other than
182 // space, horizontal tab, left-to-right mark, and right-to-left mark.
Ben Claytone55877d2022-05-04 13:58:49 +0000183 auto* c = GetParam();
Ben Claytone48ef8e2022-06-26 10:52:50 +0000184 std::string src = "const// This is a comment";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000185 src += c;
186 src += "ident";
187 Source::File file("", src);
188 Lexer l(&file);
James Price453d5ae2022-03-16 21:45:44 +0000189
dan sinclair41e4d9a2022-05-01 14:40:55 +0000190 auto is_same_line = [](std::string_view v) {
191 return v == kSpace || v == kHTab || v == kL2R || v == kR2L;
192 };
Antonio Maiorano25775302022-04-25 19:49:01 +0000193
dan sinclair0cbf5a92022-07-25 16:43:08 +0000194 auto list = l.Lex();
195 ASSERT_EQ(is_same_line(c) ? 2u : 3u, list.size());
196
197 size_t idx = 0;
198
199 {
200 auto& t = list[idx++];
201 EXPECT_TRUE(t.Is(Token::Type::kConst));
202 EXPECT_EQ(t.source().range.begin.line, 1u);
203 EXPECT_EQ(t.source().range.begin.column, 1u);
204 EXPECT_EQ(t.source().range.end.line, 1u);
205 EXPECT_EQ(t.source().range.end.column, 6u);
206 }
207
dan sinclair41e4d9a2022-05-01 14:40:55 +0000208 if (!is_same_line(c)) {
209 size_t line = is_same_line(c) ? 1u : 2u;
210 size_t col = is_same_line(c) ? 25u : 1u;
dan sinclair0cbf5a92022-07-25 16:43:08 +0000211
212 auto& t = list[idx++];
dan sinclair41e4d9a2022-05-01 14:40:55 +0000213 EXPECT_TRUE(t.IsIdentifier());
214 EXPECT_EQ(t.source().range.begin.line, line);
215 EXPECT_EQ(t.source().range.begin.column, col);
216 EXPECT_EQ(t.source().range.end.line, line);
217 EXPECT_EQ(t.source().range.end.column, col + 5);
218 EXPECT_EQ(t.to_str(), "ident");
219 }
220
dan sinclair0cbf5a92022-07-25 16:43:08 +0000221 {
222 auto& t = list[idx];
223 EXPECT_TRUE(t.IsEof());
224 }
James Price453d5ae2022-03-16 21:45:44 +0000225}
226INSTANTIATE_TEST_SUITE_P(LexerTest,
227 LineCommentTerminatorTest,
Antonio Maiorano25775302022-04-25 19:49:01 +0000228 testing::Values(
229 // same line
230 kSpace,
231 kHTab,
232 kCR,
233 kL2R,
234 kR2L,
235 // line break
236 kLF,
237 kVTab,
238 kFF,
239 kNL,
240 kLS,
241 kPS));
James Price453d5ae2022-03-16 21:45:44 +0000242
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000243TEST_F(LexerTest, Skips_Comments_Block) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000244 Source::File file("", R"(/* comment
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000245text */ident)");
dan sinclair41e4d9a2022-05-01 14:40:55 +0000246 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000247
dan sinclair0cbf5a92022-07-25 16:43:08 +0000248 auto list = l.Lex();
249 ASSERT_EQ(2u, list.size());
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000250
dan sinclair0cbf5a92022-07-25 16:43:08 +0000251 {
252 auto& t = list[0];
253 EXPECT_TRUE(t.IsIdentifier());
254 EXPECT_EQ(t.source().range.begin.line, 2u);
255 EXPECT_EQ(t.source().range.begin.column, 8u);
256 EXPECT_EQ(t.source().range.end.line, 2u);
257 EXPECT_EQ(t.source().range.end.column, 13u);
258 EXPECT_EQ(t.to_str(), "ident");
259 }
260
261 {
262 auto& t = list[1];
263 EXPECT_TRUE(t.IsEof());
264 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000265}
266
267TEST_F(LexerTest, Skips_Comments_Block_Nested) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000268 Source::File file("", R"(/* comment
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000269text // nested line comments are ignored /* more text
270/////**/ */*/ident)");
dan sinclair41e4d9a2022-05-01 14:40:55 +0000271 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000272
dan sinclair0cbf5a92022-07-25 16:43:08 +0000273 auto list = l.Lex();
274 ASSERT_EQ(2u, list.size());
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000275
dan sinclair0cbf5a92022-07-25 16:43:08 +0000276 {
277 auto& t = list[0];
278 EXPECT_TRUE(t.IsIdentifier());
279 EXPECT_EQ(t.source().range.begin.line, 3u);
280 EXPECT_EQ(t.source().range.begin.column, 14u);
281 EXPECT_EQ(t.source().range.end.line, 3u);
282 EXPECT_EQ(t.source().range.end.column, 19u);
283 EXPECT_EQ(t.to_str(), "ident");
284 }
285
286 {
287 auto& t = list[1];
288 EXPECT_TRUE(t.IsEof());
289 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000290}
291
292TEST_F(LexerTest, Skips_Comments_Block_Unterminated) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000293 // I had to break up the /* because otherwise the clang readability check
294 // errored out saying it could not find the end of a multi-line comment.
295 Source::File file("", R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000296 /)"
dan sinclair41e4d9a2022-05-01 14:40:55 +0000297 R"(*
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000298abcd)");
dan sinclair41e4d9a2022-05-01 14:40:55 +0000299 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000300
dan sinclair0cbf5a92022-07-25 16:43:08 +0000301 auto list = l.Lex();
302 ASSERT_EQ(1u, list.size());
303
304 auto& t = list[0];
dan sinclair41e4d9a2022-05-01 14:40:55 +0000305 ASSERT_TRUE(t.Is(Token::Type::kError));
306 EXPECT_EQ(t.to_str(), "unterminated block comment");
307 EXPECT_EQ(t.source().range.begin.line, 2u);
308 EXPECT_EQ(t.source().range.begin.column, 3u);
309 EXPECT_EQ(t.source().range.end.line, 2u);
310 EXPECT_EQ(t.source().range.end.column, 4u);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000311}
312
James Price453d5ae2022-03-16 21:45:44 +0000313TEST_F(LexerTest, Null_InBlankspace_IsError) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000314 Source::File file("", std::string{' ', 0, ' '});
315 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000316
dan sinclair0cbf5a92022-07-25 16:43:08 +0000317 auto list = l.Lex();
318 ASSERT_EQ(1u, list.size());
319
320 auto& t = list[0];
dan sinclair41e4d9a2022-05-01 14:40:55 +0000321 EXPECT_TRUE(t.IsError());
322 EXPECT_EQ(t.source().range.begin.line, 1u);
323 EXPECT_EQ(t.source().range.begin.column, 2u);
324 EXPECT_EQ(t.source().range.end.line, 1u);
325 EXPECT_EQ(t.source().range.end.column, 2u);
326 EXPECT_EQ(t.to_str(), "null character found");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000327}
328
329TEST_F(LexerTest, Null_InLineComment_IsError) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000330 Source::File file("", std::string{'/', '/', ' ', 0, ' '});
331 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000332
dan sinclair0cbf5a92022-07-25 16:43:08 +0000333 auto list = l.Lex();
334 ASSERT_EQ(1u, list.size());
335
336 auto& t = list[0];
dan sinclair41e4d9a2022-05-01 14:40:55 +0000337 EXPECT_TRUE(t.IsError());
338 EXPECT_EQ(t.source().range.begin.line, 1u);
339 EXPECT_EQ(t.source().range.begin.column, 4u);
340 EXPECT_EQ(t.source().range.end.line, 1u);
341 EXPECT_EQ(t.source().range.end.column, 4u);
342 EXPECT_EQ(t.to_str(), "null character found");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000343}
344
345TEST_F(LexerTest, Null_InBlockComment_IsError) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000346 Source::File file("", std::string{'/', '*', ' ', 0, '*', '/'});
347 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000348
dan sinclair0cbf5a92022-07-25 16:43:08 +0000349 auto list = l.Lex();
350 ASSERT_EQ(1u, list.size());
351
352 auto& t = list[0];
dan sinclair41e4d9a2022-05-01 14:40:55 +0000353 EXPECT_TRUE(t.IsError());
354 EXPECT_EQ(t.source().range.begin.line, 1u);
355 EXPECT_EQ(t.source().range.begin.column, 4u);
356 EXPECT_EQ(t.source().range.end.line, 1u);
357 EXPECT_EQ(t.source().range.end.column, 4u);
358 EXPECT_EQ(t.to_str(), "null character found");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000359}
360
361TEST_F(LexerTest, Null_InIdentifier_IsError) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000362 // Try inserting a null in an identifier. Other valid token
363 // kinds will behave similarly, so use the identifier case
364 // as a representative.
365 Source::File file("", std::string{'a', 0, 'c'});
366 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000367
dan sinclair0cbf5a92022-07-25 16:43:08 +0000368 auto list = l.Lex();
369 ASSERT_EQ(2u, list.size());
370
371 {
372 auto& t = list[0];
373 EXPECT_TRUE(t.IsIdentifier());
374 EXPECT_EQ(t.to_str(), "a");
375 }
376
377 {
378 auto& t = list[1];
379 EXPECT_TRUE(t.IsError());
380 EXPECT_EQ(t.source().range.begin.line, 1u);
381 EXPECT_EQ(t.source().range.begin.column, 2u);
382 EXPECT_EQ(t.source().range.end.line, 1u);
383 EXPECT_EQ(t.source().range.end.column, 2u);
384 EXPECT_EQ(t.to_str(), "null character found");
385 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000386}
387
388struct FloatData {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000389 const char* input;
Ben Clayton41285aa2022-05-10 14:55:34 +0000390 double result;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000391};
392inline std::ostream& operator<<(std::ostream& out, FloatData data) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000393 out << std::string(data.input);
394 return out;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000395}
396using FloatTest = testing::TestWithParam<FloatData>;
397TEST_P(FloatTest, Parse) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000398 auto params = GetParam();
399 Source::File file("", params.input);
400 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000401
dan sinclair0cbf5a92022-07-25 16:43:08 +0000402 auto list = l.Lex();
dan sinclair2fe7f192023-03-07 18:20:23 +0000403 ASSERT_EQ(2u, list.size()) << "Got: " << list[0].to_str();
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000404
dan sinclair0cbf5a92022-07-25 16:43:08 +0000405 {
406 auto& t = list[0];
407 if (std::string(params.input).back() == 'f') {
408 EXPECT_TRUE(t.Is(Token::Type::kFloatLiteral_F));
409 } else if (std::string(params.input).back() == 'h') {
410 EXPECT_TRUE(t.Is(Token::Type::kFloatLiteral_H));
411 } else {
412 EXPECT_TRUE(t.Is(Token::Type::kFloatLiteral));
413 }
414 EXPECT_EQ(t.to_f64(), params.result);
415 EXPECT_EQ(t.source().range.begin.line, 1u);
416 EXPECT_EQ(t.source().range.begin.column, 1u);
417 EXPECT_EQ(t.source().range.end.line, 1u);
418 EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
419 }
420
421 {
422 auto& t = list[1];
423 EXPECT_TRUE(t.IsEof());
424 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000425}
426INSTANTIATE_TEST_SUITE_P(LexerTest,
427 FloatTest,
428 testing::Values(
429 // No decimal, with 'f' suffix
Ben Clayton41285aa2022-05-10 14:55:34 +0000430 FloatData{"0f", 0.0},
431 FloatData{"1f", 1.0},
Zhaoming Jiang0fb4e2c2022-06-10 18:18:35 +0000432 // No decimal, with 'h' suffix
433 FloatData{"0h", 0.0},
434 FloatData{"1h", 1.0},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000435
436 // Zero, with decimal.
Ben Clayton41285aa2022-05-10 14:55:34 +0000437 FloatData{"0.0", 0.0},
438 FloatData{"0.", 0.0},
439 FloatData{".0", 0.0},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000440 // Zero, with decimal and 'f' suffix
Ben Clayton41285aa2022-05-10 14:55:34 +0000441 FloatData{"0.0f", 0.0},
442 FloatData{"0.f", 0.0},
443 FloatData{".0f", 0.0},
Zhaoming Jiang0fb4e2c2022-06-10 18:18:35 +0000444 // Zero, with decimal and 'h' suffix
445 FloatData{"0.0h", 0.0},
446 FloatData{"0.h", 0.0},
447 FloatData{".0h", 0.0},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000448
449 // Non-zero with decimal
Ben Clayton41285aa2022-05-10 14:55:34 +0000450 FloatData{"5.7", 5.7},
451 FloatData{"5.", 5.},
452 FloatData{".7", .7},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000453 // Non-zero with decimal and 'f' suffix
Ben Claytone6c03a32022-05-26 19:39:05 +0000454 FloatData{"5.7f", static_cast<double>(5.7f)},
455 FloatData{"5.f", static_cast<double>(5.f)},
456 FloatData{".7f", static_cast<double>(.7f)},
Zhaoming Jiang0fb4e2c2022-06-10 18:18:35 +0000457 // Non-zero with decimal and 'h' suffix
458 FloatData{"5.7h", static_cast<double>(f16::Quantize(5.7f))},
459 FloatData{"5.h", static_cast<double>(f16::Quantize(5.f))},
460 FloatData{".7h", static_cast<double>(f16::Quantize(.7f))},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000461
462 // No decimal, with exponent
Ben Clayton41285aa2022-05-10 14:55:34 +0000463 FloatData{"1e5", 1e5},
464 FloatData{"1E5", 1e5},
465 FloatData{"1e-5", 1e-5},
466 FloatData{"1E-5", 1e-5},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000467 // No decimal, with exponent and 'f' suffix
Ben Claytone6c03a32022-05-26 19:39:05 +0000468 FloatData{"1e5f", static_cast<double>(1e5f)},
469 FloatData{"1E5f", static_cast<double>(1e5f)},
470 FloatData{"1e-5f", static_cast<double>(1e-5f)},
471 FloatData{"1E-5f", static_cast<double>(1e-5f)},
Zhaoming Jiang0fb4e2c2022-06-10 18:18:35 +0000472 // No decimal, with exponent and 'h' suffix
473 FloatData{"6e4h", static_cast<double>(f16::Quantize(6e4f))},
474 FloatData{"6E4h", static_cast<double>(f16::Quantize(6e4f))},
475 FloatData{"1e-5h", static_cast<double>(f16::Quantize(1e-5f))},
476 FloatData{"1E-5h", static_cast<double>(f16::Quantize(1e-5f))},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000477 // With decimal and exponents
Ben Clayton41285aa2022-05-10 14:55:34 +0000478 FloatData{"0.2e+12", 0.2e12},
479 FloatData{"1.2e-5", 1.2e-5},
480 FloatData{"2.57e23", 2.57e23},
481 FloatData{"2.5e+0", 2.5},
482 FloatData{"2.5e-0", 2.5},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000483 // With decimal and exponents and 'f' suffix
Ben Claytone6c03a32022-05-26 19:39:05 +0000484 FloatData{"0.2e+12f", static_cast<double>(0.2e12f)},
485 FloatData{"1.2e-5f", static_cast<double>(1.2e-5f)},
486 FloatData{"2.57e23f", static_cast<double>(2.57e23f)},
487 FloatData{"2.5e+0f", static_cast<double>(2.5f)},
488 FloatData{"2.5e-0f", static_cast<double>(2.5f)},
Zhaoming Jiang0fb4e2c2022-06-10 18:18:35 +0000489 // With decimal and exponents and 'h' suffix
490 FloatData{"0.2e+5h", static_cast<double>(f16::Quantize(0.2e5f))},
491 FloatData{"1.2e-5h", static_cast<double>(f16::Quantize(1.2e-5f))},
492 FloatData{"6.55e4h", static_cast<double>(f16::Quantize(6.55e4f))},
493 FloatData{"2.5e+0h", static_cast<double>(f16::Quantize(2.5f))},
494 FloatData{"2.5e-0h", static_cast<double>(f16::Quantize(2.5f))},
Ben Claytone6c03a32022-05-26 19:39:05 +0000495 // Quantization
Zhaoming Jiang0fb4e2c2022-06-10 18:18:35 +0000496 FloatData{"3.141592653589793", 3.141592653589793}, // no quantization
497 FloatData{"3.141592653589793f", 3.1415927410125732}, // f32 quantized
dan sinclair6c34e112023-03-17 15:08:06 +0000498 FloatData{"3.141592653589793h", 3.140625}, // f16 quantized
499
500 // https://bugs.chromium.org/p/tint/issues/detail?id=1863
501 FloatData{"0."
502 "00000000000000000000000000000000000000000000000000" // 50
503 "00000000000000000000000000000000000000000000000000" // 100
504 "00000000000000000000000000000000000000000000000000" // 150
505 "00000000000000000000000000000000000000000000000000" // 200
506 "00000000000000000000000000000000000000000000000000" // 250
507 "00000000000000000000000000000000000000000000000000" // 300
508 "00000000000000000000000000000000000000000000000000" // 350
509 "1e+0",
510 0.0},
511 FloatData{"0."
512 "00000000000000000000000000000000000000000000000000" // 50
513 "00000000000000000000000000000000000000000000000000" // 100
514 "00000000000000000000000000000000000000000000000000" // 150
515 "00000000000000000000000000000000000000000000000000" // 200
516 "00000000000000000000000000000000000000000000000000" // 250
517 "00000000000000000000000000000000000000000000000000" // 300
518 "00000000000000000000000000000000000000000000000000" // 350
519 "1e+10",
520 0.0},
521 FloatData{"0."
522 "00000000000000000000000000000000000000000000000000" // 50
523 "00000000000000000000000000000000000000000000000000" // 100
524 "00000000000000000000000000000000000000000000000000" // 150
525 "00000000000000000000000000000000000000000000000000" // 200
526 "00000000000000000000000000000000000000000000000000" // 250
527 "00000000000000000000000000000000000000000000000000" // 300
528 "00000000000000000000000000000000000000000000000000" // 350
529 "1e+300",
530 1e-51},
531 FloatData{"0."
532 "00000000000000000000000000000000000000000000000000" // 50
533 "00000000000000000000000000000000000000000000000000" // 100
534 "00000000000000000000000000000000000000000000000000" // 150
535 "00000000000000000000000000000000000000000000000000" // 200
536 "00000000000000000000000000000000000000000000000000" // 250
537 "00000000000000000000000000000000000000000000000000" // 300
538 "00000000000000000000000000000000000000000000000000" // 350
539 "1",
540 0.0},
541
542 FloatData{"1"
543 "00000000000000000000000000000000000000000000000000" // 50
544 "00000000000000000000000000000000000000000000000000" // 100
545 ".0e-350",
546 1e-250}
547
Ben Claytone6c03a32022-05-26 19:39:05 +0000548 ));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000549
550using FloatTest_Invalid = testing::TestWithParam<const char*>;
551TEST_P(FloatTest_Invalid, Handles) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000552 Source::File file("", GetParam());
553 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000554
dan sinclair0cbf5a92022-07-25 16:43:08 +0000555 auto list = l.Lex();
556 ASSERT_FALSE(list.empty());
557
558 auto& t = list[0];
Zhaoming Jiang0fb4e2c2022-06-10 18:18:35 +0000559 EXPECT_FALSE(t.Is(Token::Type::kFloatLiteral) || t.Is(Token::Type::kFloatLiteral_F) ||
560 t.Is(Token::Type::kFloatLiteral_H));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000561}
dan sinclair41e4d9a2022-05-01 14:40:55 +0000562INSTANTIATE_TEST_SUITE_P(LexerTest,
563 FloatTest_Invalid,
564 testing::Values(".",
dan sinclair41e4d9a2022-05-01 14:40:55 +0000565 // Need a mantissa digit
566 ".e5",
567 ".E5",
568 // Need exponent digits
569 ".e",
570 ".e+",
571 ".e-",
572 ".E",
573 ".e+",
574 ".e-",
575 // Overflow
Ben Claytone6c03a32022-05-26 19:39:05 +0000576 "2.5e+256f",
Zhaoming Jiang0fb4e2c2022-06-10 18:18:35 +0000577 "6.5520e+4h",
dan sinclair41e4d9a2022-05-01 14:40:55 +0000578 // Decimal exponent must immediately
579 // follow the 'e'.
580 "2.5e 12",
581 "2.5e +12",
582 "2.5e -12",
583 "2.5e+ 123",
584 "2.5e- 123",
585 "2.5E 12",
586 "2.5E +12",
587 "2.5E -12",
588 "2.5E+ 123",
589 "2.5E- 123"));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000590
591using AsciiIdentifierTest = testing::TestWithParam<const char*>;
592TEST_P(AsciiIdentifierTest, Parse) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000593 Source::File file("", GetParam());
594 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000595
dan sinclair0cbf5a92022-07-25 16:43:08 +0000596 auto list = l.Lex();
597 ASSERT_EQ(2u, list.size());
598
599 {
600 auto& t = list[0];
601 EXPECT_TRUE(t.IsIdentifier());
602 EXPECT_EQ(t.source().range.begin.line, 1u);
603 EXPECT_EQ(t.source().range.begin.column, 1u);
604 EXPECT_EQ(t.source().range.end.line, 1u);
605 EXPECT_EQ(t.source().range.end.column, 1u + strlen(GetParam()));
606 EXPECT_EQ(t.to_str(), GetParam());
607 }
608
609 {
610 auto& t = list[1];
611 EXPECT_TRUE(t.IsEof());
612 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000613}
614INSTANTIATE_TEST_SUITE_P(LexerTest,
615 AsciiIdentifierTest,
616 testing::Values("a",
617 "test",
618 "test01",
619 "test_",
620 "_test",
621 "test_01",
622 "ALLCAPS",
623 "MiXeD_CaSe",
624 "abcdefghijklmnopqrstuvwxyz",
625 "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
626 "alldigits_0123456789"));
627
628struct UnicodeCase {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000629 const char* utf8;
630 size_t count;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000631};
632
Ben Clayton64b77542022-03-15 16:18:03 +0000633using ValidUnicodeIdentifierTest = testing::TestWithParam<UnicodeCase>;
634TEST_P(ValidUnicodeIdentifierTest, Parse) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000635 Source::File file("", GetParam().utf8);
636 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000637
dan sinclair0cbf5a92022-07-25 16:43:08 +0000638 auto list = l.Lex();
639 ASSERT_EQ(2u, list.size());
640
641 {
642 auto& t = list[0];
643 EXPECT_TRUE(t.IsIdentifier());
644 EXPECT_EQ(t.source().range.begin.line, 1u);
645 EXPECT_EQ(t.source().range.begin.column, 1u);
646 EXPECT_EQ(t.source().range.end.line, 1u);
647 EXPECT_EQ(t.source().range.end.column, 1u + GetParam().count);
648 EXPECT_EQ(t.to_str(), GetParam().utf8);
649 }
650
651 {
652 auto& t = list[1];
653 EXPECT_TRUE(t.IsEof());
654 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000655}
656INSTANTIATE_TEST_SUITE_P(
657 LexerTest,
Ben Clayton64b77542022-03-15 16:18:03 +0000658 ValidUnicodeIdentifierTest,
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000659 testing::ValuesIn({
660 UnicodeCase{// "𝐢𝐝𝐞𝐧𝐭𝐢𝐟𝐢𝐞𝐫"
661 "\xf0\x9d\x90\xa2\xf0\x9d\x90\x9d\xf0\x9d\x90\x9e\xf0\x9d"
662 "\x90\xa7\xf0\x9d\x90\xad\xf0\x9d\x90\xa2\xf0\x9d\x90\x9f"
663 "\xf0\x9d\x90\xa2\xf0\x9d\x90\x9e\xf0\x9d\x90\xab",
664 40},
665 UnicodeCase{// "𝑖𝑑𝑒𝑛𝑡𝑖𝑓𝑖𝑒𝑟"
666 "\xf0\x9d\x91\x96\xf0\x9d\x91\x91\xf0\x9d\x91\x92\xf0\x9d"
667 "\x91\x9b\xf0\x9d\x91\xa1\xf0\x9d\x91\x96\xf0\x9d\x91\x93"
668 "\xf0\x9d\x91\x96\xf0\x9d\x91\x92\xf0\x9d\x91\x9f",
669 40},
dan sinclair41e4d9a2022-05-01 14:40:55 +0000670 UnicodeCase{// "identifier"
671 "\xef\xbd\x89\xef\xbd\x84\xef\xbd\x85\xef\xbd\x8e\xef\xbd\x94\xef"
672 "\xbd\x89\xef\xbd\x86\xef\xbd\x89\xef\xbd\x85\xef\xbd\x92",
673 30},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000674 UnicodeCase{// "𝕚𝕕𝕖𝕟𝕥𝕚𝕗𝕚𝕖𝕣𝟙𝟚𝟛"
675 "\xf0\x9d\x95\x9a\xf0\x9d\x95\x95\xf0\x9d\x95\x96\xf0\x9d"
676 "\x95\x9f\xf0\x9d\x95\xa5\xf0\x9d\x95\x9a\xf0\x9d\x95\x97"
677 "\xf0\x9d\x95\x9a\xf0\x9d\x95\x96\xf0\x9d\x95\xa3\xf0\x9d"
678 "\x9f\x99\xf0\x9d\x9f\x9a\xf0\x9d\x9f\x9b",
679 52},
dan sinclair41e4d9a2022-05-01 14:40:55 +0000680 UnicodeCase{// "𝖎𝖉𝖊𝖓𝖙𝖎𝖋𝖎𝖊𝖗123"
681 "\xf0\x9d\x96\x8e\xf0\x9d\x96\x89\xf0\x9d\x96\x8a\xf0\x9d\x96\x93"
682 "\xf0\x9d\x96\x99\xf0\x9d\x96\x8e\xf0\x9d\x96\x8b\xf0\x9d\x96\x8e"
683 "\xf0\x9d\x96\x8a\xf0\x9d\x96\x97\x31\x32\x33",
684 43},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000685 }));
686
Ben Clayton64b77542022-03-15 16:18:03 +0000687using InvalidUnicodeIdentifierTest = testing::TestWithParam<const char*>;
688TEST_P(InvalidUnicodeIdentifierTest, Parse) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000689 Source::File file("", GetParam());
690 Lexer l(&file);
Ben Clayton64b77542022-03-15 16:18:03 +0000691
dan sinclair0cbf5a92022-07-25 16:43:08 +0000692 auto list = l.Lex();
693 ASSERT_FALSE(list.empty());
694
695 auto& t = list[0];
dan sinclair41e4d9a2022-05-01 14:40:55 +0000696 EXPECT_TRUE(t.IsError());
697 EXPECT_EQ(t.source().range.begin.line, 1u);
698 EXPECT_EQ(t.source().range.begin.column, 1u);
699 EXPECT_EQ(t.source().range.end.line, 1u);
700 EXPECT_EQ(t.source().range.end.column, 1u);
701 EXPECT_EQ(t.to_str(), "invalid UTF-8");
Ben Clayton64b77542022-03-15 16:18:03 +0000702}
dan sinclair41e4d9a2022-05-01 14:40:55 +0000703INSTANTIATE_TEST_SUITE_P(LexerTest,
704 InvalidUnicodeIdentifierTest,
705 testing::ValuesIn({
706 "\x80\x80\x80\x80", // 10000000
707 "\x81\x80\x80\x80", // 10000001
708 "\x8f\x80\x80\x80", // 10001111
709 "\x90\x80\x80\x80", // 10010000
710 "\x91\x80\x80\x80", // 10010001
711 "\x9f\x80\x80\x80", // 10011111
712 "\xa0\x80\x80\x80", // 10100000
713 "\xa1\x80\x80\x80", // 10100001
714 "\xaf\x80\x80\x80", // 10101111
715 "\xb0\x80\x80\x80", // 10110000
716 "\xb1\x80\x80\x80", // 10110001
717 "\xbf\x80\x80\x80", // 10111111
718 "\xc0\x80\x80\x80", // 11000000
719 "\xc1\x80\x80\x80", // 11000001
720 "\xf5\x80\x80\x80", // 11110101
721 "\xf6\x80\x80\x80", // 11110110
722 "\xf7\x80\x80\x80", // 11110111
723 "\xf8\x80\x80\x80", // 11111000
724 "\xfe\x80\x80\x80", // 11111110
725 "\xff\x80\x80\x80", // 11111111
Ben Clayton64b77542022-03-15 16:18:03 +0000726
dan sinclair41e4d9a2022-05-01 14:40:55 +0000727 "\xd0", // 2-bytes, missing second byte
728 "\xe8\x8f", // 3-bytes, missing third byte
729 "\xf4\x8f\x8f", // 4-bytes, missing fourth byte
Ben Clayton64b77542022-03-15 16:18:03 +0000730
dan sinclair41e4d9a2022-05-01 14:40:55 +0000731 "\xd0\x7f", // 2-bytes, second byte MSB unset
732 "\xe8\x7f\x8f", // 3-bytes, second byte MSB unset
733 "\xe8\x8f\x7f", // 3-bytes, third byte MSB unset
734 "\xf4\x7f\x8f\x8f", // 4-bytes, second byte MSB unset
735 "\xf4\x8f\x7f\x8f", // 4-bytes, third byte MSB unset
736 "\xf4\x8f\x8f\x7f", // 4-bytes, fourth byte MSB unset
737 }));
Ben Clayton64b77542022-03-15 16:18:03 +0000738
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000739TEST_F(LexerTest, IdentifierTest_SingleUnderscoreDoesNotMatch) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000740 Source::File file("", "_");
741 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000742
dan sinclair0cbf5a92022-07-25 16:43:08 +0000743 auto list = l.Lex();
744 ASSERT_FALSE(list.empty());
745
746 auto& t = list[0];
dan sinclair41e4d9a2022-05-01 14:40:55 +0000747 EXPECT_FALSE(t.IsIdentifier());
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000748}
749
750TEST_F(LexerTest, IdentifierTest_DoesNotStartWithDoubleUnderscore) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000751 Source::File file("", "__test");
752 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000753
dan sinclair0cbf5a92022-07-25 16:43:08 +0000754 auto list = l.Lex();
755 ASSERT_FALSE(list.empty());
756
757 auto& t = list[0];
dan sinclair41e4d9a2022-05-01 14:40:55 +0000758 EXPECT_FALSE(t.IsIdentifier());
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000759}
760
761TEST_F(LexerTest, IdentifierTest_DoesNotStartWithNumber) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000762 Source::File file("", "01test");
763 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000764
dan sinclair0cbf5a92022-07-25 16:43:08 +0000765 auto list = l.Lex();
766 EXPECT_FALSE(list.empty());
767
768 auto& t = list[0];
dan sinclair41e4d9a2022-05-01 14:40:55 +0000769 EXPECT_FALSE(t.IsIdentifier());
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000770}
771
Ben Clayton8b09bc92022-05-30 17:54:38 +0000772////////////////////////////////////////////////////////////////////////////////
773// ParseIntegerTest
774////////////////////////////////////////////////////////////////////////////////
775struct ParseIntegerCase {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000776 const char* input;
Ben Clayton8b09bc92022-05-30 17:54:38 +0000777 int64_t result;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000778};
Ben Clayton8b09bc92022-05-30 17:54:38 +0000779
780inline std::ostream& operator<<(std::ostream& out, ParseIntegerCase data) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000781 out << std::string(data.input);
782 return out;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000783}
784
Ben Clayton8b09bc92022-05-30 17:54:38 +0000785using ParseIntegerTest = testing::TestWithParam<std::tuple<char, ParseIntegerCase>>;
786TEST_P(ParseIntegerTest, Parse) {
787 auto suffix = std::get<0>(GetParam());
788 auto params = std::get<1>(GetParam());
dan sinclair41e4d9a2022-05-01 14:40:55 +0000789 Source::File file("", params.input);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000790
dan sinclair0cbf5a92022-07-25 16:43:08 +0000791 Lexer l(&file);
792
793 auto list = l.Lex();
794 ASSERT_FALSE(list.empty());
795
796 auto& t = list[0];
Ben Clayton8b09bc92022-05-30 17:54:38 +0000797 switch (suffix) {
798 case 'i':
799 EXPECT_TRUE(t.Is(Token::Type::kIntLiteral_I));
800 break;
801 case 'u':
802 EXPECT_TRUE(t.Is(Token::Type::kIntLiteral_U));
803 break;
804 case 0:
805 EXPECT_TRUE(t.Is(Token::Type::kIntLiteral));
806 break;
dan sinclair41e4d9a2022-05-01 14:40:55 +0000807 }
dan sinclair41e4d9a2022-05-01 14:40:55 +0000808 EXPECT_EQ(t.source().range.begin.line, 1u);
809 EXPECT_EQ(t.source().range.begin.column, 1u);
810 EXPECT_EQ(t.source().range.end.line, 1u);
811 EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
Ben Clayton8b09bc92022-05-30 17:54:38 +0000812 ASSERT_FALSE(t.IsError()) << t.to_str();
Ben Claytonf6934882022-05-04 21:01:12 +0000813 EXPECT_EQ(t.to_i64(), params.result);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000814}
815
Ben Clayton8b09bc92022-05-30 17:54:38 +0000816INSTANTIATE_TEST_SUITE_P(Dec_AInt,
817 ParseIntegerTest,
818 testing::Combine(testing::Values('\0'), // No suffix
819 testing::ValuesIn(std::vector<ParseIntegerCase>{
820 {"0", 0},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000821 {"2", 2},
822 {"123", 123},
823 {"2147483647", 2147483647},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000824 })));
825
826INSTANTIATE_TEST_SUITE_P(Dec_u32,
827 ParseIntegerTest,
828 testing::Combine(testing::Values('u'), // Suffix
829 testing::ValuesIn(std::vector<ParseIntegerCase>{
830 {"0u", 0},
831 {"123u", 123},
832 {"4294967295u", 4294967295ll},
833 })));
834
835INSTANTIATE_TEST_SUITE_P(Dec_i32,
836 ParseIntegerTest,
837 testing::Combine(testing::Values('i'), // Suffix
838 testing::ValuesIn(std::vector<ParseIntegerCase>{
839 {"0i", 0u},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000840 {"123i", 123},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000841 {"2147483647i", 2147483647},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000842 })));
843
844INSTANTIATE_TEST_SUITE_P(Hex_AInt,
845 ParseIntegerTest,
846 testing::Combine(testing::Values('\0'), // No suffix
847 testing::ValuesIn(std::vector<ParseIntegerCase>{
848 {"0x0", 0},
849 {"0X0", 0},
850 {"0x42", 66},
851 {"0X42", 66},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000852 {"0xeF1Abc9", 0xeF1Abc9},
853 {"0XeF1Abc9", 0xeF1Abc9},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000854 {"0x80000000", 0x80000000},
855 {"0X80000000", 0X80000000},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000856 {"0x7FFFFFFF", 0x7fffffff},
857 {"0X7FFFFFFF", 0x7fffffff},
858 {"0x7fffffff", 0x7fffffff},
859 {"0x7fffffff", 0x7fffffff},
860 {"0x7FfFfFfF", 0x7fffffff},
861 {"0X7FfFfFfF", 0x7fffffff},
862 {"0x7fffffffffffffff", 0x7fffffffffffffffll},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000863 })));
864
865INSTANTIATE_TEST_SUITE_P(Hex_u32,
866 ParseIntegerTest,
867 testing::Combine(testing::Values('u'), // Suffix
868 testing::ValuesIn(std::vector<ParseIntegerCase>{
869 {"0x0u", 0},
870 {"0x42u", 66},
871 {"0xeF1Abc9u", 250719177},
872 {"0xFFFFFFFFu", 0xffffffff},
873 {"0XFFFFFFFFu", 0xffffffff},
874 {"0xffffffffu", 0xffffffff},
875 {"0Xffffffffu", 0xffffffff},
876 {"0xfFfFfFfFu", 0xffffffff},
877 {"0XfFfFfFfFu", 0xffffffff},
878 })));
879
880INSTANTIATE_TEST_SUITE_P(Hex_i32,
881 ParseIntegerTest,
882 testing::Combine(testing::Values('i'), // Suffix
883 testing::ValuesIn(std::vector<ParseIntegerCase>{
884 {"0x0i", 0},
885 {"0x42i", 66},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000886 {"0xeF1Abc9i", 250719177},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000887 {"0x7FFFFFFFi", 0x7fffffff},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000888 {"0X7FFFFFFFi", 0x7fffffff},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000889 {"0x7fffffffi", 0x7fffffff},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000890 {"0X7fffffffi", 0x7fffffff},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000891 {"0x7FfFfFfFi", 0x7fffffff},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000892 {"0X7FfFfFfFi", 0x7fffffff},
Ben Clayton8b09bc92022-05-30 17:54:38 +0000893 })));
894////////////////////////////////////////////////////////////////////////////////
895// ParseIntegerTest_CannotBeRepresented
896////////////////////////////////////////////////////////////////////////////////
897using ParseIntegerTest_CannotBeRepresented =
898 testing::TestWithParam<std::tuple<const char*, const char*>>;
899TEST_P(ParseIntegerTest_CannotBeRepresented, Parse) {
900 auto type = std::get<0>(GetParam());
901 auto source = std::get<1>(GetParam());
902 Source::File file("", source);
dan sinclair0cbf5a92022-07-25 16:43:08 +0000903
904 Lexer l(&file);
905 auto list = l.Lex();
906 ASSERT_FALSE(list.empty());
907
908 auto& t = list[0];
Ben Clayton8b09bc92022-05-30 17:54:38 +0000909 EXPECT_TRUE(t.Is(Token::Type::kError));
910 auto expect = "value cannot be represented as '" + std::string(type) + "'";
911 EXPECT_EQ(t.to_str(), expect);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000912}
Ben Clayton8b09bc92022-05-30 17:54:38 +0000913INSTANTIATE_TEST_SUITE_P(AbstractInt,
914 ParseIntegerTest_CannotBeRepresented,
915 testing::Combine(testing::Values("abstract-int"),
916 testing::Values("9223372036854775808",
917 "0xFFFFFFFFFFFFFFFF",
918 "0xffffffffffffffff",
919 "0x8000000000000000")));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000920
Ben Clayton8b09bc92022-05-30 17:54:38 +0000921INSTANTIATE_TEST_SUITE_P(i32,
922 ParseIntegerTest_CannotBeRepresented,
923 testing::Combine(testing::Values("i32"), // type
924 testing::Values("2147483648i")));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000925
Ben Clayton8b09bc92022-05-30 17:54:38 +0000926INSTANTIATE_TEST_SUITE_P(u32,
927 ParseIntegerTest_CannotBeRepresented,
dan sinclairb3b027d2022-10-26 15:20:47 +0000928 testing::Combine(testing::Values("u32"), // type
929 testing::Values("4294967296u")));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000930
Ben Clayton8b09bc92022-05-30 17:54:38 +0000931////////////////////////////////////////////////////////////////////////////////
932// ParseIntegerTest_LeadingZeros
933////////////////////////////////////////////////////////////////////////////////
934using ParseIntegerTest_LeadingZeros = testing::TestWithParam<const char*>;
935TEST_P(ParseIntegerTest_LeadingZeros, Parse) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000936 Source::File file("", GetParam());
dan sinclair0cbf5a92022-07-25 16:43:08 +0000937
938 Lexer l(&file);
939 auto list = l.Lex();
940 ASSERT_FALSE(list.empty());
941
942 auto& t = list[0];
Ben Clayton8b09bc92022-05-30 17:54:38 +0000943 EXPECT_TRUE(t.Is(Token::Type::kError));
944 EXPECT_EQ(t.to_str(), "integer literal cannot have leading 0s");
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000945}
Ben Clayton8b09bc92022-05-30 17:54:38 +0000946
947INSTANTIATE_TEST_SUITE_P(LeadingZero,
948 ParseIntegerTest_LeadingZeros,
dan sinclairb3b027d2022-10-26 15:20:47 +0000949 testing::Values("01234", "0000", "00u"));
Ben Clayton8b09bc92022-05-30 17:54:38 +0000950
951////////////////////////////////////////////////////////////////////////////////
952// ParseIntegerTest_NoSignificantDigits
953////////////////////////////////////////////////////////////////////////////////
954using ParseIntegerTest_NoSignificantDigits = testing::TestWithParam<const char*>;
955TEST_P(ParseIntegerTest_NoSignificantDigits, Parse) {
956 Source::File file("", GetParam());
dan sinclair0cbf5a92022-07-25 16:43:08 +0000957
958 Lexer l(&file);
959 auto list = l.Lex();
960 ASSERT_FALSE(list.empty());
961
962 auto& t = list[0];
Ben Clayton8b09bc92022-05-30 17:54:38 +0000963 EXPECT_TRUE(t.Is(Token::Type::kError));
964 EXPECT_EQ(t.to_str(), "integer or float hex literal has no significant digits");
965}
966
967INSTANTIATE_TEST_SUITE_P(LeadingZero,
968 ParseIntegerTest_NoSignificantDigits,
dan sinclairb3b027d2022-10-26 15:20:47 +0000969 testing::Values("0x", "0X", "0xu", "0Xu", "0xi", "0Xi"));
dan sinclair41e4d9a2022-05-01 14:40:55 +0000970
971struct TokenData {
972 const char* input;
973 Token::Type type;
974};
975inline std::ostream& operator<<(std::ostream& out, TokenData data) {
976 out << std::string(data.input);
977 return out;
978}
979using PunctuationTest = testing::TestWithParam<TokenData>;
980TEST_P(PunctuationTest, Parses) {
981 auto params = GetParam();
982 Source::File file("", params.input);
983 Lexer l(&file);
984
dan sinclair0cbf5a92022-07-25 16:43:08 +0000985 auto list = l.Lex();
986 ASSERT_GE(list.size(), 2u);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000987
dan sinclair0cbf5a92022-07-25 16:43:08 +0000988 {
989 auto& t = list[0];
990 EXPECT_TRUE(t.Is(params.type));
991 EXPECT_EQ(t.source().range.begin.line, 1u);
992 EXPECT_EQ(t.source().range.begin.column, 1u);
993 EXPECT_EQ(t.source().range.end.line, 1u);
994 EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
995 }
996
997 {
998 auto& t = list[1];
999 EXPECT_EQ(t.source().range.begin.column, 1 + std::string(params.input).size());
1000 }
dan sinclair41e4d9a2022-05-01 14:40:55 +00001001}
1002INSTANTIATE_TEST_SUITE_P(LexerTest,
1003 PunctuationTest,
1004 testing::Values(TokenData{"&", Token::Type::kAnd},
dan sinclair41e4d9a2022-05-01 14:40:55 +00001005 TokenData{"->", Token::Type::kArrow},
1006 TokenData{"@", Token::Type::kAttr},
1007 TokenData{"/", Token::Type::kForwardSlash},
1008 TokenData{"!", Token::Type::kBang},
1009 TokenData{"[", Token::Type::kBracketLeft},
1010 TokenData{"]", Token::Type::kBracketRight},
1011 TokenData{"{", Token::Type::kBraceLeft},
1012 TokenData{"}", Token::Type::kBraceRight},
1013 TokenData{":", Token::Type::kColon},
1014 TokenData{",", Token::Type::kComma},
1015 TokenData{"=", Token::Type::kEqual},
1016 TokenData{"==", Token::Type::kEqualEqual},
1017 TokenData{">", Token::Type::kGreaterThan},
dan sinclair41e4d9a2022-05-01 14:40:55 +00001018 TokenData{"<", Token::Type::kLessThan},
1019 TokenData{"<=", Token::Type::kLessThanEqual},
1020 TokenData{"<<", Token::Type::kShiftLeft},
1021 TokenData{"%", Token::Type::kMod},
1022 TokenData{"!=", Token::Type::kNotEqual},
1023 TokenData{"-", Token::Type::kMinus},
dan sinclair41e4d9a2022-05-01 14:40:55 +00001024 TokenData{".", Token::Type::kPeriod},
1025 TokenData{"+", Token::Type::kPlus},
1026 TokenData{"++", Token::Type::kPlusPlus},
1027 TokenData{"|", Token::Type::kOr},
1028 TokenData{"||", Token::Type::kOrOr},
1029 TokenData{"(", Token::Type::kParenLeft},
1030 TokenData{")", Token::Type::kParenRight},
1031 TokenData{";", Token::Type::kSemicolon},
1032 TokenData{"*", Token::Type::kStar},
1033 TokenData{"~", Token::Type::kTilde},
1034 TokenData{"_", Token::Type::kUnderscore},
1035 TokenData{"^", Token::Type::kXor},
1036 TokenData{"+=", Token::Type::kPlusEqual},
1037 TokenData{"-=", Token::Type::kMinusEqual},
1038 TokenData{"*=", Token::Type::kTimesEqual},
1039 TokenData{"/=", Token::Type::kDivisionEqual},
1040 TokenData{"%=", Token::Type::kModuloEqual},
1041 TokenData{"&=", Token::Type::kAndEqual},
1042 TokenData{"|=", Token::Type::kOrEqual},
dan sinclair73778d3b2022-08-02 18:18:05 +00001043 TokenData{"^=", Token::Type::kXorEqual},
dan sinclair73778d3b2022-08-02 18:18:05 +00001044 TokenData{"<<=", Token::Type::kShiftLeftEqual}));
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001045
dan sinclair0cbf5a92022-07-25 16:43:08 +00001046using SplittablePunctuationTest = testing::TestWithParam<TokenData>;
1047TEST_P(SplittablePunctuationTest, Parses) {
1048 auto params = GetParam();
1049 Source::File file("", params.input);
1050 Lexer l(&file);
1051
1052 auto list = l.Lex();
1053 ASSERT_GE(list.size(), 3u);
1054
1055 {
1056 auto& t = list[0];
1057 EXPECT_TRUE(t.Is(params.type));
1058 EXPECT_EQ(t.source().range.begin.line, 1u);
1059 EXPECT_EQ(t.source().range.begin.column, 1u);
1060 EXPECT_EQ(t.source().range.end.line, 1u);
1061 EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
1062 }
1063
Ben Clayton6fc130b2023-01-23 18:32:41 +00001064 const size_t num_placeholders = list[0].NumPlaceholders();
1065 EXPECT_GT(num_placeholders, 0u);
1066 ASSERT_EQ(list.size(), 2u + num_placeholders);
1067
1068 for (size_t i = 0; i < num_placeholders; i++) {
1069 auto& t = list[1 + i];
dan sinclair0cbf5a92022-07-25 16:43:08 +00001070 EXPECT_TRUE(t.Is(Token::Type::kPlaceholder));
1071 EXPECT_EQ(t.source().range.begin.line, 1u);
Ben Clayton6fc130b2023-01-23 18:32:41 +00001072 EXPECT_EQ(t.source().range.begin.column, 2u + i);
dan sinclair0cbf5a92022-07-25 16:43:08 +00001073 EXPECT_EQ(t.source().range.end.line, 1u);
1074 EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
1075 }
1076
1077 {
Ben Clayton6fc130b2023-01-23 18:32:41 +00001078 auto& t = list.back();
1079 EXPECT_TRUE(t.Is(Token::Type::kEOF));
1080 EXPECT_EQ(t.source().range.begin.column, 2u + num_placeholders);
dan sinclair0cbf5a92022-07-25 16:43:08 +00001081 }
1082}
1083INSTANTIATE_TEST_SUITE_P(LexerTest,
1084 SplittablePunctuationTest,
dan sinclair6c8dc152022-08-17 16:30:30 +00001085 testing::Values(TokenData{"&&", Token::Type::kAndAnd},
1086 TokenData{">=", Token::Type::kGreaterThanEqual},
dan sinclair2788bec2022-08-19 21:26:01 +00001087 TokenData{"--", Token::Type::kMinusMinus},
Ben Clayton6fc130b2023-01-23 18:32:41 +00001088 TokenData{">>", Token::Type::kShiftRight},
1089 TokenData{">>=", Token::Type::kShiftRightEqual}));
dan sinclair0cbf5a92022-07-25 16:43:08 +00001090
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001091using KeywordTest = testing::TestWithParam<TokenData>;
1092TEST_P(KeywordTest, Parses) {
dan sinclair41e4d9a2022-05-01 14:40:55 +00001093 auto params = GetParam();
1094 Source::File file("", params.input);
1095 Lexer l(&file);
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001096
dan sinclair0cbf5a92022-07-25 16:43:08 +00001097 auto list = l.Lex();
1098 ASSERT_GE(list.size(), 2u);
1099
1100 auto& t = list[0];
dan sinclair41e4d9a2022-05-01 14:40:55 +00001101 EXPECT_TRUE(t.Is(params.type)) << params.input;
1102 EXPECT_EQ(t.source().range.begin.line, 1u);
1103 EXPECT_EQ(t.source().range.begin.column, 1u);
1104 EXPECT_EQ(t.source().range.end.line, 1u);
1105 EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001106
dan sinclair0cbf5a92022-07-25 16:43:08 +00001107 EXPECT_EQ(list[1].source().range.begin.column, 1 + std::string(params.input).size());
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001108}
Ben Clayton643f2aa2023-02-18 08:36:01 +00001109INSTANTIATE_TEST_SUITE_P(LexerTest,
1110 KeywordTest,
1111 testing::Values(TokenData{"alias", Token::Type::kAlias},
1112 TokenData{"bitcast", Token::Type::kBitcast},
1113 TokenData{"break", Token::Type::kBreak},
1114 TokenData{"case", Token::Type::kCase},
1115 TokenData{"const", Token::Type::kConst},
1116 TokenData{"const_assert", Token::Type::kConstAssert},
1117 TokenData{"continue", Token::Type::kContinue},
1118 TokenData{"continuing", Token::Type::kContinuing},
1119 TokenData{"default", Token::Type::kDefault},
1120 TokenData{"diagnostic", Token::Type::kDiagnostic},
1121 TokenData{"discard", Token::Type::kDiscard},
1122 TokenData{"else", Token::Type::kElse},
1123 TokenData{"enable", Token::Type::kEnable},
1124 TokenData{"fallthrough", Token::Type::kFallthrough},
1125 TokenData{"false", Token::Type::kFalse},
1126 TokenData{"fn", Token::Type::kFn},
1127 TokenData{"for", Token::Type::kFor},
1128 TokenData{"if", Token::Type::kIf},
1129 TokenData{"let", Token::Type::kLet},
1130 TokenData{"loop", Token::Type::kLoop},
1131 TokenData{"override", Token::Type::kOverride},
1132 TokenData{"return", Token::Type::kReturn},
dan sinclair187e0d52023-02-22 20:57:28 +00001133 TokenData{"requires", Token::Type::kRequires},
Ben Clayton643f2aa2023-02-18 08:36:01 +00001134 TokenData{"struct", Token::Type::kStruct},
1135 TokenData{"switch", Token::Type::kSwitch},
1136 TokenData{"true", Token::Type::kTrue},
Ben Clayton643f2aa2023-02-18 08:36:01 +00001137 TokenData{"var", Token::Type::kVar},
1138 TokenData{"while", Token::Type::kWhile}));
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001139
1140} // namespace
dan sinclair61190452023-07-26 20:47:54 +00001141} // namespace tint::wgsl::reader