token_kind_test.cpp 4.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  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/lexer/token_kind.h"
  5. #include <gmock/gmock.h>
  6. #include <gtest/gtest.h>
  7. #include <cstring>
  8. #include "llvm/ADT/StringRef.h"
  9. namespace Carbon::Testing {
  10. namespace {
  11. using ::testing::MatchesRegex;
  12. // We restrict symbols to punctuation characters that are expected to be widely
  13. // available on modern keyboards used for programming.
  14. constexpr llvm::StringLiteral SymbolRegex =
  15. R"([\[\]{}!@#%^&*()/?\\|;:.,<>=+~-]+)";
  16. // We restrict keywords to be lowercase ASCII letters and underscores.
  17. constexpr llvm::StringLiteral KeywordRegex = "[a-z_]+";
  18. #define CARBON_TOKEN(TokenName) \
  19. TEST(TokenKindTest, TokenName) { \
  20. EXPECT_EQ(#TokenName, TokenKind::TokenName().Name()); \
  21. EXPECT_FALSE(TokenKind::TokenName().IsSymbol()); \
  22. EXPECT_FALSE(TokenKind::TokenName().IsKeyword()); \
  23. EXPECT_EQ("", TokenKind::TokenName().GetFixedSpelling()); \
  24. }
  25. #define CARBON_SYMBOL_TOKEN(TokenName, Spelling) \
  26. TEST(TokenKindTest, TokenName) { \
  27. EXPECT_EQ(#TokenName, TokenKind::TokenName().Name()); \
  28. EXPECT_TRUE(TokenKind::TokenName().IsSymbol()); \
  29. EXPECT_FALSE(TokenKind::TokenName().IsGroupingSymbol()); \
  30. EXPECT_FALSE(TokenKind::TokenName().IsOpeningSymbol()); \
  31. EXPECT_FALSE(TokenKind::TokenName().IsClosingSymbol()); \
  32. EXPECT_FALSE(TokenKind::TokenName().IsKeyword()); \
  33. EXPECT_EQ(Spelling, TokenKind::TokenName().GetFixedSpelling()); \
  34. EXPECT_THAT(Spelling, MatchesRegex(SymbolRegex.str())); \
  35. }
  36. #define CARBON_OPENING_GROUP_SYMBOL_TOKEN(TokenName, Spelling, ClosingName) \
  37. TEST(TokenKindTest, TokenName) { \
  38. EXPECT_EQ(#TokenName, TokenKind::TokenName().Name()); \
  39. EXPECT_TRUE(TokenKind::TokenName().IsSymbol()); \
  40. EXPECT_TRUE(TokenKind::TokenName().IsGroupingSymbol()); \
  41. EXPECT_TRUE(TokenKind::TokenName().IsOpeningSymbol()); \
  42. EXPECT_EQ(TokenKind::ClosingName(), \
  43. TokenKind::TokenName().GetClosingSymbol()); \
  44. EXPECT_FALSE(TokenKind::TokenName().IsClosingSymbol()); \
  45. EXPECT_FALSE(TokenKind::TokenName().IsKeyword()); \
  46. EXPECT_EQ(Spelling, TokenKind::TokenName().GetFixedSpelling()); \
  47. EXPECT_THAT(Spelling, MatchesRegex(SymbolRegex.str())); \
  48. }
  49. #define CARBON_CLOSING_GROUP_SYMBOL_TOKEN(TokenName, Spelling, OpeningName) \
  50. TEST(TokenKindTest, TokenName) { \
  51. EXPECT_EQ(#TokenName, TokenKind::TokenName().Name()); \
  52. EXPECT_TRUE(TokenKind::TokenName().IsSymbol()); \
  53. EXPECT_TRUE(TokenKind::TokenName().IsGroupingSymbol()); \
  54. EXPECT_FALSE(TokenKind::TokenName().IsOpeningSymbol()); \
  55. EXPECT_TRUE(TokenKind::TokenName().IsClosingSymbol()); \
  56. EXPECT_EQ(TokenKind::OpeningName(), \
  57. TokenKind::TokenName().GetOpeningSymbol()); \
  58. EXPECT_FALSE(TokenKind::TokenName().IsKeyword()); \
  59. EXPECT_EQ(Spelling, TokenKind::TokenName().GetFixedSpelling()); \
  60. EXPECT_THAT(Spelling, MatchesRegex(SymbolRegex.str())); \
  61. }
  62. #define CARBON_KEYWORD_TOKEN(TokenName, Spelling) \
  63. TEST(TokenKindTest, TokenName) { \
  64. EXPECT_EQ(#TokenName, TokenKind::TokenName().Name()); \
  65. EXPECT_FALSE(TokenKind::TokenName().IsSymbol()); \
  66. EXPECT_TRUE(TokenKind::TokenName().IsKeyword()); \
  67. EXPECT_EQ(Spelling, TokenKind::TokenName().GetFixedSpelling()); \
  68. EXPECT_THAT(Spelling, MatchesRegex(KeywordRegex.str())); \
  69. }
  70. #include "toolchain/lexer/token_registry.def"
  71. // Verify that the symbol tokens are sorted from longest to shortest. This is
  72. // important to ensure that simply in-order testing will identify tokens
  73. // following the max-munch rule.
  74. TEST(TokenKindTest, SymbolsInDescendingLength) {
  75. int previous_length = INT_MAX;
  76. #define CARBON_SYMBOL_TOKEN(TokenName, Spelling) \
  77. EXPECT_LE(llvm::StringRef(Spelling).size(), previous_length) \
  78. << "Symbol token not in descending length order: " << #TokenName; \
  79. previous_length = llvm::StringRef(Spelling).size();
  80. #include "toolchain/lexer/token_registry.def"
  81. EXPECT_GT(previous_length, 0);
  82. }
  83. } // namespace
  84. } // namespace Carbon::Testing