tokenized_buffer_test.cpp 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #include "toolchain/lex/tokenized_buffer.h"
  5. #include <gmock/gmock.h>
  6. #include <gtest/gtest.h>
  7. #include <forward_list>
  8. #include <iterator>
  9. #include "llvm/ADT/ArrayRef.h"
  10. #include "testing/base/test_raw_ostream.h"
  11. #include "toolchain/base/value_store.h"
  12. #include "toolchain/diagnostics/diagnostic_emitter.h"
  13. #include "toolchain/diagnostics/mocks.h"
  14. #include "toolchain/lex/tokenized_buffer_test_helpers.h"
  15. #include "toolchain/testing/yaml_test_helpers.h"
  16. namespace Carbon::Lex {
  17. namespace {
  18. using ::Carbon::Testing::ExpectedToken;
  19. using ::Carbon::Testing::IsDiagnostic;
  20. using ::Carbon::Testing::TestRawOstream;
  21. using ::testing::_;
  22. using ::testing::ElementsAre;
  23. using ::testing::Eq;
  24. using ::testing::HasSubstr;
  25. using ::testing::Pair;
  26. namespace Yaml = ::Carbon::Testing::Yaml;
  27. class LexerTest : public ::testing::Test {
  28. protected:
  29. auto GetSourceBuffer(llvm::StringRef text) -> SourceBuffer& {
  30. std::string filename = llvm::formatv("test{0}.carbon", ++file_index_);
  31. CARBON_CHECK(fs_.addFile(filename, /*ModificationTime=*/0,
  32. llvm::MemoryBuffer::getMemBuffer(text)));
  33. source_storage_.push_front(std::move(*SourceBuffer::CreateFromFile(
  34. fs_, filename, ConsoleDiagnosticConsumer())));
  35. return source_storage_.front();
  36. }
  37. auto Lex(llvm::StringRef text,
  38. DiagnosticConsumer& consumer = ConsoleDiagnosticConsumer())
  39. -> TokenizedBuffer {
  40. return TokenizedBuffer::Lex(value_stores_, GetSourceBuffer(text), consumer);
  41. }
  42. SharedValueStores value_stores_;
  43. llvm::vfs::InMemoryFileSystem fs_;
  44. int file_index_ = 0;
  45. std::forward_list<SourceBuffer> source_storage_;
  46. };
  47. TEST_F(LexerTest, HandlesEmptyBuffer) {
  48. auto buffer = Lex("");
  49. EXPECT_FALSE(buffer.has_errors());
  50. EXPECT_THAT(buffer, HasTokens(llvm::ArrayRef<ExpectedToken>{
  51. {TokenKind::StartOfFile}, {TokenKind::EndOfFile}}));
  52. }
  53. TEST_F(LexerTest, TracksLinesAndColumns) {
  54. auto buffer = Lex("\n ;;\n ;;;\n x\"foo\" '''baz\n a\n ''' y");
  55. EXPECT_FALSE(buffer.has_errors());
  56. EXPECT_THAT(
  57. buffer,
  58. HasTokens(llvm::ArrayRef<ExpectedToken>{
  59. {.kind = TokenKind::StartOfFile,
  60. .line = 1,
  61. .column = 1,
  62. .indent_column = 1},
  63. {.kind = TokenKind::Semi, .line = 2, .column = 3, .indent_column = 3},
  64. {.kind = TokenKind::Semi, .line = 2, .column = 4, .indent_column = 3},
  65. {.kind = TokenKind::Semi, .line = 3, .column = 4, .indent_column = 4},
  66. {.kind = TokenKind::Semi, .line = 3, .column = 5, .indent_column = 4},
  67. {.kind = TokenKind::Semi, .line = 3, .column = 6, .indent_column = 4},
  68. {.kind = TokenKind::Identifier,
  69. .line = 4,
  70. .column = 4,
  71. .indent_column = 4,
  72. .text = "x"},
  73. {.kind = TokenKind::StringLiteral,
  74. .line = 4,
  75. .column = 5,
  76. .indent_column = 4},
  77. {.kind = TokenKind::StringLiteral,
  78. .line = 4,
  79. .column = 11,
  80. .indent_column = 4},
  81. {.kind = TokenKind::Identifier,
  82. .line = 6,
  83. .column = 6,
  84. .indent_column = 11,
  85. .text = "y"},
  86. {.kind = TokenKind::EndOfFile, .line = 6, .column = 7},
  87. }));
  88. }
  89. TEST_F(LexerTest, HandlesNumericLiteral) {
  90. auto buffer = Lex("12-578\n 1 2\n0x12_3ABC\n0b10_10_11\n1_234_567\n1.5e9");
  91. EXPECT_FALSE(buffer.has_errors());
  92. ASSERT_THAT(buffer,
  93. HasTokens(llvm::ArrayRef<ExpectedToken>{
  94. {.kind = TokenKind::StartOfFile, .line = 1, .column = 1},
  95. {.kind = TokenKind::IntegerLiteral,
  96. .line = 1,
  97. .column = 1,
  98. .indent_column = 1,
  99. .text = "12"},
  100. {.kind = TokenKind::Minus,
  101. .line = 1,
  102. .column = 3,
  103. .indent_column = 1},
  104. {.kind = TokenKind::IntegerLiteral,
  105. .line = 1,
  106. .column = 4,
  107. .indent_column = 1,
  108. .text = "578"},
  109. {.kind = TokenKind::IntegerLiteral,
  110. .line = 2,
  111. .column = 3,
  112. .indent_column = 3,
  113. .text = "1"},
  114. {.kind = TokenKind::IntegerLiteral,
  115. .line = 2,
  116. .column = 6,
  117. .indent_column = 3,
  118. .text = "2"},
  119. {.kind = TokenKind::IntegerLiteral,
  120. .line = 3,
  121. .column = 1,
  122. .indent_column = 1,
  123. .text = "0x12_3ABC"},
  124. {.kind = TokenKind::IntegerLiteral,
  125. .line = 4,
  126. .column = 1,
  127. .indent_column = 1,
  128. .text = "0b10_10_11"},
  129. {.kind = TokenKind::IntegerLiteral,
  130. .line = 5,
  131. .column = 1,
  132. .indent_column = 1,
  133. .text = "1_234_567"},
  134. {.kind = TokenKind::RealLiteral,
  135. .line = 6,
  136. .column = 1,
  137. .indent_column = 1,
  138. .text = "1.5e9"},
  139. {.kind = TokenKind::EndOfFile, .line = 6, .column = 6},
  140. }));
  141. auto token_start = buffer.tokens().begin();
  142. auto token_12 = token_start + 1;
  143. EXPECT_EQ(buffer.GetIntegerLiteral(*token_12), 12);
  144. auto token_578 = token_12 + 2;
  145. EXPECT_EQ(buffer.GetIntegerLiteral(*token_578), 578);
  146. auto token_1 = token_578 + 1;
  147. EXPECT_EQ(buffer.GetIntegerLiteral(*token_1), 1);
  148. auto token_2 = token_1 + 1;
  149. EXPECT_EQ(buffer.GetIntegerLiteral(*token_2), 2);
  150. auto token_0x12_3abc = token_2 + 1;
  151. EXPECT_EQ(buffer.GetIntegerLiteral(*token_0x12_3abc), 0x12'3abc);
  152. auto token_0b10_10_11 = token_0x12_3abc + 1;
  153. EXPECT_EQ(buffer.GetIntegerLiteral(*token_0b10_10_11), 0b10'10'11);
  154. auto token_1_234_567 = token_0b10_10_11 + 1;
  155. EXPECT_EQ(buffer.GetIntegerLiteral(*token_1_234_567), 1'234'567);
  156. auto token_1_5e9 = token_1_234_567 + 1;
  157. auto value_1_5e9 = buffer.GetRealLiteral(*token_1_5e9);
  158. EXPECT_EQ(value_1_5e9.mantissa.getZExtValue(), 15);
  159. EXPECT_EQ(value_1_5e9.exponent.getSExtValue(), 8);
  160. EXPECT_EQ(value_1_5e9.is_decimal, true);
  161. }
  162. TEST_F(LexerTest, HandlesInvalidNumericLiterals) {
  163. auto buffer = Lex("14x 15_49 0x3.5q 0x3_4.5_6 0ops");
  164. EXPECT_TRUE(buffer.has_errors());
  165. ASSERT_THAT(buffer,
  166. HasTokens(llvm::ArrayRef<ExpectedToken>{
  167. {.kind = TokenKind::StartOfFile, .line = 1, .column = 1},
  168. {.kind = TokenKind::Error,
  169. .line = 1,
  170. .column = 1,
  171. .indent_column = 1,
  172. .text = "14x"},
  173. {.kind = TokenKind::IntegerLiteral,
  174. .line = 1,
  175. .column = 5,
  176. .indent_column = 1,
  177. .text = "15_49"},
  178. {.kind = TokenKind::Error,
  179. .line = 1,
  180. .column = 11,
  181. .indent_column = 1,
  182. .text = "0x3.5q"},
  183. {.kind = TokenKind::RealLiteral,
  184. .line = 1,
  185. .column = 18,
  186. .indent_column = 1,
  187. .text = "0x3_4.5_6"},
  188. {.kind = TokenKind::Error,
  189. .line = 1,
  190. .column = 28,
  191. .indent_column = 1,
  192. .text = "0ops"},
  193. {.kind = TokenKind::EndOfFile, .line = 1, .column = 32},
  194. }));
  195. }
  196. TEST_F(LexerTest, SplitsNumericLiteralsProperly) {
  197. llvm::StringLiteral source_text = R"(
  198. 1.
  199. .2
  200. 3.+foo
  201. 4.0-bar
  202. 5.0e+123+456
  203. 6.0e+1e+2
  204. 1e7
  205. 8..10
  206. 9.0.9.5
  207. 10.foo
  208. 11.0.foo
  209. 12e+1
  210. 13._
  211. )";
  212. auto buffer = Lex(source_text);
  213. EXPECT_TRUE(buffer.has_errors());
  214. EXPECT_THAT(buffer, HasTokens(llvm::ArrayRef<ExpectedToken>{
  215. {.kind = TokenKind::StartOfFile},
  216. {.kind = TokenKind::IntegerLiteral, .text = "1"},
  217. {.kind = TokenKind::Period},
  218. // newline
  219. {.kind = TokenKind::Period},
  220. {.kind = TokenKind::IntegerLiteral, .text = "2"},
  221. // newline
  222. {.kind = TokenKind::IntegerLiteral, .text = "3"},
  223. {.kind = TokenKind::Period},
  224. {.kind = TokenKind::Plus},
  225. {.kind = TokenKind::Identifier, .text = "foo"},
  226. // newline
  227. {.kind = TokenKind::RealLiteral, .text = "4.0"},
  228. {.kind = TokenKind::Minus},
  229. {.kind = TokenKind::Identifier, .text = "bar"},
  230. // newline
  231. {.kind = TokenKind::RealLiteral, .text = "5.0e+123"},
  232. {.kind = TokenKind::Plus},
  233. {.kind = TokenKind::IntegerLiteral, .text = "456"},
  234. // newline
  235. {.kind = TokenKind::Error, .text = "6.0e+1e"},
  236. {.kind = TokenKind::Plus},
  237. {.kind = TokenKind::IntegerLiteral, .text = "2"},
  238. // newline
  239. {.kind = TokenKind::Error, .text = "1e7"},
  240. // newline
  241. {.kind = TokenKind::IntegerLiteral, .text = "8"},
  242. {.kind = TokenKind::Period},
  243. {.kind = TokenKind::Period},
  244. {.kind = TokenKind::IntegerLiteral, .text = "10"},
  245. // newline
  246. {.kind = TokenKind::RealLiteral, .text = "9.0"},
  247. {.kind = TokenKind::Period},
  248. {.kind = TokenKind::RealLiteral, .text = "9.5"},
  249. // newline
  250. {.kind = TokenKind::Error, .text = "10.foo"},
  251. // newline
  252. {.kind = TokenKind::RealLiteral, .text = "11.0"},
  253. {.kind = TokenKind::Period},
  254. {.kind = TokenKind::Identifier, .text = "foo"},
  255. // newline
  256. {.kind = TokenKind::Error, .text = "12e"},
  257. {.kind = TokenKind::Plus},
  258. {.kind = TokenKind::IntegerLiteral, .text = "1"},
  259. // newline
  260. {.kind = TokenKind::IntegerLiteral, .text = "13"},
  261. {.kind = TokenKind::Period},
  262. {.kind = TokenKind::Underscore},
  263. // newline
  264. {.kind = TokenKind::EndOfFile},
  265. }));
  266. }
  267. TEST_F(LexerTest, HandlesGarbageCharacters) {
  268. constexpr char GarbageText[] = "$$💩-$\n$\0$12$\n\\\"\\\n\"x";
  269. auto buffer = Lex(llvm::StringRef(GarbageText, sizeof(GarbageText) - 1));
  270. EXPECT_TRUE(buffer.has_errors());
  271. EXPECT_THAT(
  272. buffer,
  273. HasTokens(llvm::ArrayRef<ExpectedToken>{
  274. {.kind = TokenKind::StartOfFile, .line = 1, .column = 1},
  275. {.kind = TokenKind::Error,
  276. .line = 1,
  277. .column = 1,
  278. // 💩 takes 4 bytes, and we count column as bytes offset.
  279. .text = llvm::StringRef("$$💩", 6)},
  280. {.kind = TokenKind::Minus, .line = 1, .column = 7},
  281. {.kind = TokenKind::Error, .line = 1, .column = 8, .text = "$"},
  282. // newline
  283. {.kind = TokenKind::Error,
  284. .line = 2,
  285. .column = 1,
  286. .text = llvm::StringRef("$\0$", 3)},
  287. {.kind = TokenKind::IntegerLiteral,
  288. .line = 2,
  289. .column = 4,
  290. .text = "12"},
  291. {.kind = TokenKind::Error, .line = 2, .column = 6, .text = "$"},
  292. // newline
  293. {.kind = TokenKind::Backslash, .line = 3, .column = 1, .text = "\\"},
  294. {.kind = TokenKind::Error, .line = 3, .column = 2, .text = "\"\\"},
  295. // newline
  296. {.kind = TokenKind::Error, .line = 4, .column = 1, .text = "\"x"},
  297. {.kind = TokenKind::EndOfFile, .line = 4, .column = 3},
  298. }));
  299. }
  300. TEST_F(LexerTest, Symbols) {
  301. // We don't need to exhaustively test symbols here as they're handled with
  302. // common code, but we want to check specific patterns to verify things like
  303. // max-munch rule and handling of interesting symbols.
  304. auto buffer = Lex("<<<");
  305. EXPECT_FALSE(buffer.has_errors());
  306. EXPECT_THAT(buffer, HasTokens(llvm::ArrayRef<ExpectedToken>{
  307. {TokenKind::StartOfFile},
  308. {TokenKind::LessLess},
  309. {TokenKind::Less},
  310. {TokenKind::EndOfFile},
  311. }));
  312. buffer = Lex("<<=>>");
  313. EXPECT_FALSE(buffer.has_errors());
  314. EXPECT_THAT(buffer, HasTokens(llvm::ArrayRef<ExpectedToken>{
  315. {TokenKind::StartOfFile},
  316. {TokenKind::LessLessEqual},
  317. {TokenKind::GreaterGreater},
  318. {TokenKind::EndOfFile},
  319. }));
  320. buffer = Lex("< <=> >");
  321. EXPECT_FALSE(buffer.has_errors());
  322. EXPECT_THAT(buffer, HasTokens(llvm::ArrayRef<ExpectedToken>{
  323. {TokenKind::StartOfFile},
  324. {TokenKind::Less},
  325. {TokenKind::LessEqualGreater},
  326. {TokenKind::Greater},
  327. {TokenKind::EndOfFile},
  328. }));
  329. buffer = Lex("\\/?@&^!");
  330. EXPECT_FALSE(buffer.has_errors());
  331. EXPECT_THAT(buffer, HasTokens(llvm::ArrayRef<ExpectedToken>{
  332. {TokenKind::StartOfFile},
  333. {TokenKind::Backslash},
  334. {TokenKind::Slash},
  335. {TokenKind::Question},
  336. {TokenKind::At},
  337. {TokenKind::Amp},
  338. {TokenKind::Caret},
  339. {TokenKind::Exclaim},
  340. {TokenKind::EndOfFile},
  341. }));
  342. }
  343. TEST_F(LexerTest, Parens) {
  344. auto buffer = Lex("()");
  345. EXPECT_FALSE(buffer.has_errors());
  346. EXPECT_THAT(buffer, HasTokens(llvm::ArrayRef<ExpectedToken>{
  347. {TokenKind::StartOfFile},
  348. {TokenKind::OpenParen},
  349. {TokenKind::CloseParen},
  350. {TokenKind::EndOfFile},
  351. }));
  352. buffer = Lex("((()()))");
  353. EXPECT_FALSE(buffer.has_errors());
  354. EXPECT_THAT(buffer, HasTokens(llvm::ArrayRef<ExpectedToken>{
  355. {TokenKind::StartOfFile},
  356. {TokenKind::OpenParen},
  357. {TokenKind::OpenParen},
  358. {TokenKind::OpenParen},
  359. {TokenKind::CloseParen},
  360. {TokenKind::OpenParen},
  361. {TokenKind::CloseParen},
  362. {TokenKind::CloseParen},
  363. {TokenKind::CloseParen},
  364. {TokenKind::EndOfFile},
  365. }));
  366. }
  367. TEST_F(LexerTest, CurlyBraces) {
  368. auto buffer = Lex("{}");
  369. EXPECT_FALSE(buffer.has_errors());
  370. EXPECT_THAT(buffer, HasTokens(llvm::ArrayRef<ExpectedToken>{
  371. {TokenKind::StartOfFile},
  372. {TokenKind::OpenCurlyBrace},
  373. {TokenKind::CloseCurlyBrace},
  374. {TokenKind::EndOfFile},
  375. }));
  376. buffer = Lex("{{{}{}}}");
  377. EXPECT_FALSE(buffer.has_errors());
  378. EXPECT_THAT(buffer, HasTokens(llvm::ArrayRef<ExpectedToken>{
  379. {TokenKind::StartOfFile},
  380. {TokenKind::OpenCurlyBrace},
  381. {TokenKind::OpenCurlyBrace},
  382. {TokenKind::OpenCurlyBrace},
  383. {TokenKind::CloseCurlyBrace},
  384. {TokenKind::OpenCurlyBrace},
  385. {TokenKind::CloseCurlyBrace},
  386. {TokenKind::CloseCurlyBrace},
  387. {TokenKind::CloseCurlyBrace},
  388. {TokenKind::EndOfFile},
  389. }));
  390. }
  391. TEST_F(LexerTest, MatchingGroups) {
  392. {
  393. TokenizedBuffer buffer = Lex("(){}");
  394. ASSERT_FALSE(buffer.has_errors());
  395. auto it = ++buffer.tokens().begin();
  396. auto open_paren_token = *it++;
  397. auto close_paren_token = *it++;
  398. EXPECT_EQ(close_paren_token,
  399. buffer.GetMatchedClosingToken(open_paren_token));
  400. EXPECT_EQ(open_paren_token,
  401. buffer.GetMatchedOpeningToken(close_paren_token));
  402. auto open_curly_token = *it++;
  403. auto close_curly_token = *it++;
  404. EXPECT_EQ(close_curly_token,
  405. buffer.GetMatchedClosingToken(open_curly_token));
  406. EXPECT_EQ(open_curly_token,
  407. buffer.GetMatchedOpeningToken(close_curly_token));
  408. auto eof_token = *it++;
  409. EXPECT_EQ(buffer.GetKind(eof_token), TokenKind::EndOfFile);
  410. EXPECT_EQ(buffer.tokens().end(), it);
  411. }
  412. {
  413. TokenizedBuffer buffer = Lex("({x}){(y)} {{((z))}}");
  414. ASSERT_FALSE(buffer.has_errors());
  415. auto it = ++buffer.tokens().begin();
  416. auto open_paren_token = *it++;
  417. auto open_curly_token = *it++;
  418. ASSERT_EQ("x", value_stores_.strings().Get(buffer.GetIdentifier(*it++)));
  419. auto close_curly_token = *it++;
  420. auto close_paren_token = *it++;
  421. EXPECT_EQ(close_paren_token,
  422. buffer.GetMatchedClosingToken(open_paren_token));
  423. EXPECT_EQ(open_paren_token,
  424. buffer.GetMatchedOpeningToken(close_paren_token));
  425. EXPECT_EQ(close_curly_token,
  426. buffer.GetMatchedClosingToken(open_curly_token));
  427. EXPECT_EQ(open_curly_token,
  428. buffer.GetMatchedOpeningToken(close_curly_token));
  429. open_curly_token = *it++;
  430. open_paren_token = *it++;
  431. ASSERT_EQ("y", value_stores_.strings().Get(buffer.GetIdentifier(*it++)));
  432. close_paren_token = *it++;
  433. close_curly_token = *it++;
  434. EXPECT_EQ(close_curly_token,
  435. buffer.GetMatchedClosingToken(open_curly_token));
  436. EXPECT_EQ(open_curly_token,
  437. buffer.GetMatchedOpeningToken(close_curly_token));
  438. EXPECT_EQ(close_paren_token,
  439. buffer.GetMatchedClosingToken(open_paren_token));
  440. EXPECT_EQ(open_paren_token,
  441. buffer.GetMatchedOpeningToken(close_paren_token));
  442. open_curly_token = *it++;
  443. auto inner_open_curly_token = *it++;
  444. open_paren_token = *it++;
  445. auto inner_open_paren_token = *it++;
  446. ASSERT_EQ("z", value_stores_.strings().Get(buffer.GetIdentifier(*it++)));
  447. auto inner_close_paren_token = *it++;
  448. close_paren_token = *it++;
  449. auto inner_close_curly_token = *it++;
  450. close_curly_token = *it++;
  451. EXPECT_EQ(close_curly_token,
  452. buffer.GetMatchedClosingToken(open_curly_token));
  453. EXPECT_EQ(open_curly_token,
  454. buffer.GetMatchedOpeningToken(close_curly_token));
  455. EXPECT_EQ(inner_close_curly_token,
  456. buffer.GetMatchedClosingToken(inner_open_curly_token));
  457. EXPECT_EQ(inner_open_curly_token,
  458. buffer.GetMatchedOpeningToken(inner_close_curly_token));
  459. EXPECT_EQ(close_paren_token,
  460. buffer.GetMatchedClosingToken(open_paren_token));
  461. EXPECT_EQ(open_paren_token,
  462. buffer.GetMatchedOpeningToken(close_paren_token));
  463. EXPECT_EQ(inner_close_paren_token,
  464. buffer.GetMatchedClosingToken(inner_open_paren_token));
  465. EXPECT_EQ(inner_open_paren_token,
  466. buffer.GetMatchedOpeningToken(inner_close_paren_token));
  467. auto eof_token = *it++;
  468. EXPECT_EQ(buffer.GetKind(eof_token), TokenKind::EndOfFile);
  469. EXPECT_EQ(buffer.tokens().end(), it);
  470. }
  471. }
  472. TEST_F(LexerTest, MismatchedGroups) {
  473. auto buffer = Lex("{");
  474. EXPECT_TRUE(buffer.has_errors());
  475. EXPECT_THAT(buffer,
  476. HasTokens(llvm::ArrayRef<ExpectedToken>{
  477. {TokenKind::StartOfFile},
  478. {TokenKind::OpenCurlyBrace},
  479. {.kind = TokenKind::CloseCurlyBrace, .recovery = true},
  480. {TokenKind::EndOfFile},
  481. }));
  482. buffer = Lex("}");
  483. EXPECT_TRUE(buffer.has_errors());
  484. EXPECT_THAT(buffer, HasTokens(llvm::ArrayRef<ExpectedToken>{
  485. {TokenKind::StartOfFile},
  486. {.kind = TokenKind::Error, .text = "}"},
  487. {TokenKind::EndOfFile},
  488. }));
  489. buffer = Lex("{(}");
  490. EXPECT_TRUE(buffer.has_errors());
  491. EXPECT_THAT(
  492. buffer,
  493. HasTokens(llvm::ArrayRef<ExpectedToken>{
  494. {TokenKind::StartOfFile},
  495. {.kind = TokenKind::OpenCurlyBrace, .column = 1},
  496. {.kind = TokenKind::OpenParen, .column = 2},
  497. {.kind = TokenKind::CloseParen, .column = 3, .recovery = true},
  498. {.kind = TokenKind::CloseCurlyBrace, .column = 3},
  499. {TokenKind::EndOfFile},
  500. }));
  501. buffer = Lex(")({)");
  502. EXPECT_TRUE(buffer.has_errors());
  503. EXPECT_THAT(
  504. buffer,
  505. HasTokens(llvm::ArrayRef<ExpectedToken>{
  506. {TokenKind::StartOfFile},
  507. {.kind = TokenKind::Error, .column = 1, .text = ")"},
  508. {.kind = TokenKind::OpenParen, .column = 2},
  509. {.kind = TokenKind::OpenCurlyBrace, .column = 3},
  510. {.kind = TokenKind::CloseCurlyBrace, .column = 4, .recovery = true},
  511. {.kind = TokenKind::CloseParen, .column = 4},
  512. {TokenKind::EndOfFile},
  513. }));
  514. }
  515. TEST_F(LexerTest, Whitespace) {
  516. auto buffer = Lex("{( } {(");
  517. // Whether there should be whitespace before/after each token.
  518. bool space[] = {true,
  519. // start-of-file
  520. true,
  521. // {
  522. false,
  523. // (
  524. true,
  525. // inserted )
  526. true,
  527. // }
  528. true,
  529. // {
  530. false,
  531. // (
  532. true,
  533. // inserted )
  534. true,
  535. // inserted }
  536. true,
  537. // EOF
  538. false};
  539. int pos = 0;
  540. for (Token token : buffer.tokens()) {
  541. SCOPED_TRACE(
  542. llvm::formatv("Token #{0}: '{1}'", token, buffer.GetTokenText(token)));
  543. ASSERT_LT(pos, std::size(space));
  544. EXPECT_THAT(buffer.HasLeadingWhitespace(token), Eq(space[pos]));
  545. ++pos;
  546. ASSERT_LT(pos, std::size(space));
  547. EXPECT_THAT(buffer.HasTrailingWhitespace(token), Eq(space[pos]));
  548. }
  549. ASSERT_EQ(pos + 1, std::size(space));
  550. }
  551. TEST_F(LexerTest, Keywords) {
  552. auto buffer = Lex(" fn");
  553. EXPECT_FALSE(buffer.has_errors());
  554. EXPECT_THAT(buffer,
  555. HasTokens(llvm::ArrayRef<ExpectedToken>{
  556. {TokenKind::StartOfFile},
  557. {.kind = TokenKind::Fn, .column = 4, .indent_column = 4},
  558. {TokenKind::EndOfFile},
  559. }));
  560. buffer = Lex("and or not if else for return var break continue _");
  561. EXPECT_FALSE(buffer.has_errors());
  562. EXPECT_THAT(buffer, HasTokens(llvm::ArrayRef<ExpectedToken>{
  563. {TokenKind::StartOfFile},
  564. {TokenKind::And},
  565. {TokenKind::Or},
  566. {TokenKind::Not},
  567. {TokenKind::If},
  568. {TokenKind::Else},
  569. {TokenKind::For},
  570. {TokenKind::Return},
  571. {TokenKind::Var},
  572. {TokenKind::Break},
  573. {TokenKind::Continue},
  574. {TokenKind::Underscore},
  575. {TokenKind::EndOfFile},
  576. }));
  577. }
  578. TEST_F(LexerTest, Comments) {
  579. auto buffer = Lex(" ;\n // foo\n ;\n");
  580. EXPECT_FALSE(buffer.has_errors());
  581. EXPECT_THAT(
  582. buffer,
  583. HasTokens(llvm::ArrayRef<ExpectedToken>{
  584. {.kind = TokenKind::StartOfFile, .line = 1, .column = 1},
  585. {.kind = TokenKind::Semi, .line = 1, .column = 2, .indent_column = 2},
  586. {.kind = TokenKind::Semi, .line = 3, .column = 3, .indent_column = 3},
  587. {.kind = TokenKind::EndOfFile, .line = 3, .column = 4},
  588. }));
  589. buffer = Lex("// foo\n//\n// bar");
  590. EXPECT_FALSE(buffer.has_errors());
  591. EXPECT_THAT(buffer, HasTokens(llvm::ArrayRef<ExpectedToken>{
  592. {TokenKind::StartOfFile}, {TokenKind::EndOfFile}}));
  593. // Make sure weird characters aren't a problem.
  594. buffer = Lex(" // foo#$!^?@-_💩🍫⃠ [̲̅$̲̅(̲̅ ͡° ͜ʖ ͡°̲̅)̲̅$̲̅]");
  595. EXPECT_FALSE(buffer.has_errors());
  596. EXPECT_THAT(buffer, HasTokens(llvm::ArrayRef<ExpectedToken>{
  597. {TokenKind::StartOfFile}, {TokenKind::EndOfFile}}));
  598. // Make sure we can lex a comment at the end of the input.
  599. buffer = Lex("//");
  600. EXPECT_FALSE(buffer.has_errors());
  601. EXPECT_THAT(buffer, HasTokens(llvm::ArrayRef<ExpectedToken>{
  602. {TokenKind::StartOfFile}, {TokenKind::EndOfFile}}));
  603. }
  604. TEST_F(LexerTest, InvalidComments) {
  605. llvm::StringLiteral testcases[] = {
  606. " /// foo\n",
  607. "foo // bar\n",
  608. "//! hello",
  609. " //world",
  610. };
  611. for (llvm::StringLiteral testcase : testcases) {
  612. auto buffer = Lex(testcase);
  613. EXPECT_TRUE(buffer.has_errors());
  614. }
  615. }
  616. TEST_F(LexerTest, Identifiers) {
  617. auto buffer = Lex(" foobar");
  618. EXPECT_FALSE(buffer.has_errors());
  619. EXPECT_THAT(buffer, HasTokens(llvm::ArrayRef<ExpectedToken>{
  620. {TokenKind::StartOfFile},
  621. {.kind = TokenKind::Identifier,
  622. .column = 4,
  623. .indent_column = 4,
  624. .text = "foobar"},
  625. {TokenKind::EndOfFile},
  626. }));
  627. // Check different kinds of identifier character sequences.
  628. buffer = Lex("_foo_bar");
  629. EXPECT_FALSE(buffer.has_errors());
  630. EXPECT_THAT(buffer, HasTokens(llvm::ArrayRef<ExpectedToken>{
  631. {TokenKind::StartOfFile},
  632. {.kind = TokenKind::Identifier, .text = "_foo_bar"},
  633. {TokenKind::EndOfFile},
  634. }));
  635. buffer = Lex("foo2bar00");
  636. EXPECT_FALSE(buffer.has_errors());
  637. EXPECT_THAT(buffer, HasTokens(llvm::ArrayRef<ExpectedToken>{
  638. {TokenKind::StartOfFile},
  639. {.kind = TokenKind::Identifier, .text = "foo2bar00"},
  640. {TokenKind::EndOfFile},
  641. }));
  642. // Check that we can parse identifiers that start with a keyword.
  643. buffer = Lex("fnord");
  644. EXPECT_FALSE(buffer.has_errors());
  645. EXPECT_THAT(buffer, HasTokens(llvm::ArrayRef<ExpectedToken>{
  646. {TokenKind::StartOfFile},
  647. {.kind = TokenKind::Identifier, .text = "fnord"},
  648. {TokenKind::EndOfFile},
  649. }));
  650. // Check multiple identifiers with indent and interning.
  651. buffer = Lex(" foo;bar\nbar \n foo\tfoo");
  652. EXPECT_FALSE(buffer.has_errors());
  653. EXPECT_THAT(buffer,
  654. HasTokens(llvm::ArrayRef<ExpectedToken>{
  655. {.kind = TokenKind::StartOfFile, .line = 1, .column = 1},
  656. {.kind = TokenKind::Identifier,
  657. .line = 1,
  658. .column = 4,
  659. .indent_column = 4,
  660. .text = "foo"},
  661. {.kind = TokenKind::Semi},
  662. {.kind = TokenKind::Identifier,
  663. .line = 1,
  664. .column = 8,
  665. .indent_column = 4,
  666. .text = "bar"},
  667. {.kind = TokenKind::Identifier,
  668. .line = 2,
  669. .column = 1,
  670. .indent_column = 1,
  671. .text = "bar"},
  672. {.kind = TokenKind::Identifier,
  673. .line = 3,
  674. .column = 3,
  675. .indent_column = 3,
  676. .text = "foo"},
  677. {.kind = TokenKind::Identifier,
  678. .line = 3,
  679. .column = 7,
  680. .indent_column = 3,
  681. .text = "foo"},
  682. {.kind = TokenKind::EndOfFile, .line = 3, .column = 10},
  683. }));
  684. }
  685. TEST_F(LexerTest, StringLiterals) {
  686. llvm::StringLiteral testcase = R"(
  687. "hello world\n"
  688. '''foo
  689. test \
  690. \xAB
  691. ''' trailing
  692. #"""#
  693. "\0"
  694. #"\0"foo"\1"#
  695. """x"""
  696. )";
  697. auto buffer = Lex(testcase);
  698. EXPECT_FALSE(buffer.has_errors());
  699. EXPECT_THAT(buffer,
  700. HasTokens(llvm::ArrayRef<ExpectedToken>{
  701. {.kind = TokenKind::StartOfFile, .line = 1, .column = 1},
  702. {.kind = TokenKind::StringLiteral,
  703. .line = 2,
  704. .column = 5,
  705. .indent_column = 5,
  706. .string_contents = {"hello world\n"}},
  707. {.kind = TokenKind::StringLiteral,
  708. .line = 4,
  709. .column = 5,
  710. .indent_column = 5,
  711. .string_contents = {" test \xAB\n"}},
  712. {.kind = TokenKind::Identifier,
  713. .line = 7,
  714. .column = 10,
  715. .indent_column = 5,
  716. .text = "trailing"},
  717. {.kind = TokenKind::StringLiteral,
  718. .line = 9,
  719. .column = 7,
  720. .indent_column = 7,
  721. .string_contents = {"\""}},
  722. {.kind = TokenKind::StringLiteral,
  723. .line = 11,
  724. .column = 5,
  725. .indent_column = 5,
  726. .string_contents = llvm::StringLiteral::withInnerNUL("\0")},
  727. {.kind = TokenKind::StringLiteral,
  728. .line = 13,
  729. .column = 5,
  730. .indent_column = 5,
  731. .string_contents = {"\\0\"foo\"\\1"}},
  732. // """x""" is three string literals, not one invalid
  733. // attempt at a block string literal.
  734. {.kind = TokenKind::StringLiteral,
  735. .line = 15,
  736. .column = 5,
  737. .indent_column = 5,
  738. .string_contents = {""}},
  739. {.kind = TokenKind::StringLiteral,
  740. .line = 15,
  741. .column = 7,
  742. .indent_column = 5,
  743. .string_contents = {"x"}},
  744. {.kind = TokenKind::StringLiteral,
  745. .line = 15,
  746. .column = 10,
  747. .indent_column = 5,
  748. .string_contents = {""}},
  749. {.kind = TokenKind::EndOfFile, .line = 16, .column = 3},
  750. }));
  751. }
  752. TEST_F(LexerTest, InvalidStringLiterals) {
  753. llvm::StringLiteral invalid[] = {
  754. // clang-format off
  755. R"(")",
  756. R"('''
  757. '')",
  758. R"("\)",
  759. R"("\")",
  760. R"("\\)",
  761. R"("\\\")",
  762. R"(''')",
  763. R"('''
  764. )",
  765. R"('''\)",
  766. R"(#'''
  767. ''')",
  768. // clang-format on
  769. };
  770. for (llvm::StringLiteral test : invalid) {
  771. SCOPED_TRACE(test);
  772. auto buffer = Lex(test);
  773. EXPECT_TRUE(buffer.has_errors());
  774. // We should have formed at least one error token.
  775. bool found_error = false;
  776. for (Token token : buffer.tokens()) {
  777. if (buffer.GetKind(token) == TokenKind::Error) {
  778. found_error = true;
  779. break;
  780. }
  781. }
  782. EXPECT_TRUE(found_error);
  783. }
  784. }
  785. TEST_F(LexerTest, TypeLiterals) {
  786. llvm::StringLiteral testcase = R"(
  787. i0 i1 i20 i999999999999 i0x1
  788. u0 u1 u64 u64b
  789. f32 f80 f1 fi
  790. s1
  791. )";
  792. auto buffer = Lex(testcase);
  793. EXPECT_FALSE(buffer.has_errors());
  794. ASSERT_THAT(buffer,
  795. HasTokens(llvm::ArrayRef<ExpectedToken>{
  796. {.kind = TokenKind::StartOfFile, .line = 1, .column = 1},
  797. {.kind = TokenKind::Identifier,
  798. .line = 2,
  799. .column = 5,
  800. .indent_column = 5,
  801. .text = {"i0"}},
  802. {.kind = TokenKind::IntegerTypeLiteral,
  803. .line = 2,
  804. .column = 8,
  805. .indent_column = 5,
  806. .text = {"i1"}},
  807. {.kind = TokenKind::IntegerTypeLiteral,
  808. .line = 2,
  809. .column = 11,
  810. .indent_column = 5,
  811. .text = {"i20"}},
  812. {.kind = TokenKind::IntegerTypeLiteral,
  813. .line = 2,
  814. .column = 15,
  815. .indent_column = 5,
  816. .text = {"i999999999999"}},
  817. {.kind = TokenKind::Identifier,
  818. .line = 2,
  819. .column = 29,
  820. .indent_column = 5,
  821. .text = {"i0x1"}},
  822. {.kind = TokenKind::Identifier,
  823. .line = 3,
  824. .column = 5,
  825. .indent_column = 5,
  826. .text = {"u0"}},
  827. {.kind = TokenKind::UnsignedIntegerTypeLiteral,
  828. .line = 3,
  829. .column = 8,
  830. .indent_column = 5,
  831. .text = {"u1"}},
  832. {.kind = TokenKind::UnsignedIntegerTypeLiteral,
  833. .line = 3,
  834. .column = 11,
  835. .indent_column = 5,
  836. .text = {"u64"}},
  837. {.kind = TokenKind::Identifier,
  838. .line = 3,
  839. .column = 15,
  840. .indent_column = 5,
  841. .text = {"u64b"}},
  842. {.kind = TokenKind::FloatingPointTypeLiteral,
  843. .line = 4,
  844. .column = 5,
  845. .indent_column = 5,
  846. .text = {"f32"}},
  847. {.kind = TokenKind::FloatingPointTypeLiteral,
  848. .line = 4,
  849. .column = 9,
  850. .indent_column = 5,
  851. .text = {"f80"}},
  852. {.kind = TokenKind::FloatingPointTypeLiteral,
  853. .line = 4,
  854. .column = 13,
  855. .indent_column = 5,
  856. .text = {"f1"}},
  857. {.kind = TokenKind::Identifier,
  858. .line = 4,
  859. .column = 16,
  860. .indent_column = 5,
  861. .text = {"fi"}},
  862. {.kind = TokenKind::Identifier,
  863. .line = 5,
  864. .column = 5,
  865. .indent_column = 5,
  866. .text = {"s1"}},
  867. {.kind = TokenKind::EndOfFile, .line = 6, .column = 3},
  868. }));
  869. auto token_i1 = buffer.tokens().begin() + 2;
  870. EXPECT_EQ(buffer.GetTypeLiteralSize(*token_i1), 1);
  871. auto token_i20 = buffer.tokens().begin() + 3;
  872. EXPECT_EQ(buffer.GetTypeLiteralSize(*token_i20), 20);
  873. auto token_i999999999999 = buffer.tokens().begin() + 4;
  874. EXPECT_EQ(buffer.GetTypeLiteralSize(*token_i999999999999), 999999999999ULL);
  875. auto token_u1 = buffer.tokens().begin() + 7;
  876. EXPECT_EQ(buffer.GetTypeLiteralSize(*token_u1), 1);
  877. auto token_u64 = buffer.tokens().begin() + 8;
  878. EXPECT_EQ(buffer.GetTypeLiteralSize(*token_u64), 64);
  879. auto token_f32 = buffer.tokens().begin() + 10;
  880. EXPECT_EQ(buffer.GetTypeLiteralSize(*token_f32), 32);
  881. auto token_f80 = buffer.tokens().begin() + 11;
  882. EXPECT_EQ(buffer.GetTypeLiteralSize(*token_f80), 80);
  883. auto token_f1 = buffer.tokens().begin() + 12;
  884. EXPECT_EQ(buffer.GetTypeLiteralSize(*token_f1), 1);
  885. }
  886. TEST_F(LexerTest, TypeLiteralTooManyDigits) {
  887. std::string code = "i";
  888. constexpr int Count = 10000;
  889. code.append(Count, '9');
  890. Testing::MockDiagnosticConsumer consumer;
  891. EXPECT_CALL(consumer,
  892. HandleDiagnostic(IsDiagnostic(
  893. DiagnosticKind::TooManyDigits, DiagnosticLevel::Error, 1, 2,
  894. HasSubstr(llvm::formatv(" {0} ", Count)))));
  895. auto buffer = Lex(code, consumer);
  896. EXPECT_TRUE(buffer.has_errors());
  897. ASSERT_THAT(
  898. buffer,
  899. HasTokens(llvm::ArrayRef<ExpectedToken>{
  900. {.kind = TokenKind::StartOfFile, .line = 1, .column = 1},
  901. {.kind = TokenKind::Error,
  902. .line = 1,
  903. .column = 1,
  904. .indent_column = 1,
  905. .text = {code}},
  906. {.kind = TokenKind::EndOfFile, .line = 1, .column = Count + 2},
  907. }));
  908. }
  909. TEST_F(LexerTest, DiagnosticTrailingComment) {
  910. llvm::StringLiteral testcase = R"(
  911. // Hello!
  912. var String x; // trailing comment
  913. )";
  914. Testing::MockDiagnosticConsumer consumer;
  915. EXPECT_CALL(consumer,
  916. HandleDiagnostic(IsDiagnostic(DiagnosticKind::TrailingComment,
  917. DiagnosticLevel::Error, 3, 19, _)));
  918. Lex(testcase, consumer);
  919. }
  920. TEST_F(LexerTest, DiagnosticWhitespace) {
  921. Testing::MockDiagnosticConsumer consumer;
  922. EXPECT_CALL(consumer, HandleDiagnostic(IsDiagnostic(
  923. DiagnosticKind::NoWhitespaceAfterCommentIntroducer,
  924. DiagnosticLevel::Error, 1, 3, _)));
  925. Lex("//no space after comment", consumer);
  926. }
  927. TEST_F(LexerTest, DiagnosticUnrecognizedEscape) {
  928. Testing::MockDiagnosticConsumer consumer;
  929. EXPECT_CALL(consumer, HandleDiagnostic(IsDiagnostic(
  930. DiagnosticKind::UnknownEscapeSequence,
  931. DiagnosticLevel::Error, 1, 8, HasSubstr("`b`"))));
  932. Lex(R"("hello\bworld")", consumer);
  933. }
  934. TEST_F(LexerTest, DiagnosticBadHex) {
  935. Testing::MockDiagnosticConsumer consumer;
  936. EXPECT_CALL(consumer, HandleDiagnostic(IsDiagnostic(
  937. DiagnosticKind::HexadecimalEscapeMissingDigits,
  938. DiagnosticLevel::Error, 1, 9, _)));
  939. Lex(R"("hello\xabworld")", consumer);
  940. }
  941. TEST_F(LexerTest, DiagnosticInvalidDigit) {
  942. Testing::MockDiagnosticConsumer consumer;
  943. EXPECT_CALL(consumer, HandleDiagnostic(IsDiagnostic(
  944. DiagnosticKind::InvalidDigit,
  945. DiagnosticLevel::Error, 1, 6, HasSubstr("'a'"))));
  946. Lex("0x123abc", consumer);
  947. }
  948. TEST_F(LexerTest, DiagnosticMissingTerminator) {
  949. Testing::MockDiagnosticConsumer consumer;
  950. EXPECT_CALL(consumer,
  951. HandleDiagnostic(IsDiagnostic(DiagnosticKind::UnterminatedString,
  952. DiagnosticLevel::Error, 1, 1, _)));
  953. Lex(R"(#" ")", consumer);
  954. }
  955. TEST_F(LexerTest, DiagnosticUnrecognizedChar) {
  956. Testing::MockDiagnosticConsumer consumer;
  957. EXPECT_CALL(consumer, HandleDiagnostic(
  958. IsDiagnostic(DiagnosticKind::UnrecognizedCharacters,
  959. DiagnosticLevel::Error, 1, 1, _)));
  960. Lex("\b", consumer);
  961. }
  962. TEST_F(LexerTest, PrintingAsYaml) {
  963. // Test that we can parse this into YAML and verify line and indent data.
  964. auto buffer = Lex("\n ;\n\n\n; ;\n\n\n\n\n\n\n\n\n\n\n");
  965. ASSERT_FALSE(buffer.has_errors());
  966. TestRawOstream print_stream;
  967. buffer.Print(print_stream);
  968. EXPECT_THAT(
  969. Yaml::Value::FromText(print_stream.TakeStr()),
  970. IsYaml(ElementsAre(Yaml::Sequence(ElementsAre(Yaml::Mapping(ElementsAre(
  971. Pair("filename", source_storage_.front().filename().str()),
  972. Pair("tokens",
  973. Yaml::Sequence(ElementsAre(
  974. Yaml::Mapping(ElementsAre(
  975. Pair("index", "0"), Pair("kind", "StartOfFile"),
  976. Pair("line", "1"), Pair("column", "1"),
  977. Pair("indent", "1"), Pair("spelling", ""),
  978. Pair("has_trailing_space", "true"))),
  979. Yaml::Mapping(
  980. ElementsAre(Pair("index", "1"), Pair("kind", "Semi"),
  981. Pair("line", "2"), Pair("column", "2"),
  982. Pair("indent", "2"), Pair("spelling", ";"),
  983. Pair("has_trailing_space", "true"))),
  984. Yaml::Mapping(
  985. ElementsAre(Pair("index", "2"), Pair("kind", "Semi"),
  986. Pair("line", "5"), Pair("column", "1"),
  987. Pair("indent", "1"), Pair("spelling", ";"),
  988. Pair("has_trailing_space", "true"))),
  989. Yaml::Mapping(
  990. ElementsAre(Pair("index", "3"), Pair("kind", "Semi"),
  991. Pair("line", "5"), Pair("column", "3"),
  992. Pair("indent", "1"), Pair("spelling", ";"),
  993. Pair("has_trailing_space", "true"))),
  994. Yaml::Mapping(ElementsAre(
  995. Pair("index", "4"), Pair("kind", "EndOfFile"),
  996. Pair("line", "15"), Pair("column", "1"),
  997. Pair("indent", "1"), Pair("spelling", "")))))))))))));
  998. }
  999. } // namespace
  1000. } // namespace Carbon::Lex