string_helpers.cpp 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  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 "common/string_helpers.h"
  5. #include "common/check.h"
  6. #include "llvm/ADT/StringExtras.h"
  7. namespace Carbon {
  8. // Carbon only takes uppercase hex input.
  9. static auto FromHex(char c) -> std::optional<char> {
  10. if (c >= '0' && c <= '9') {
  11. return c - '0';
  12. }
  13. if (c >= 'A' && c <= 'F') {
  14. return 10 + c - 'A';
  15. }
  16. return std::nullopt;
  17. }
  18. auto UnescapeStringLiteral(llvm::StringRef source)
  19. -> std::optional<std::string> {
  20. std::string ret;
  21. ret.reserve(source.size());
  22. size_t i = 0;
  23. while (i < source.size()) {
  24. char c = source[i];
  25. if (c == '\\') {
  26. ++i;
  27. if (i == source.size()) {
  28. return std::nullopt;
  29. }
  30. switch (source[i]) {
  31. case 'n':
  32. ret.push_back('\n');
  33. break;
  34. case 'r':
  35. ret.push_back('\r');
  36. break;
  37. case 't':
  38. ret.push_back('\t');
  39. break;
  40. case '0':
  41. if (i + 1 < source.size() && llvm::isDigit(source[i + 1])) {
  42. // \0[0-9] is reserved.
  43. return std::nullopt;
  44. }
  45. ret.push_back('\0');
  46. break;
  47. case '"':
  48. ret.push_back('"');
  49. break;
  50. case '\'':
  51. ret.push_back('\'');
  52. break;
  53. case '\\':
  54. ret.push_back('\\');
  55. break;
  56. case 'x': {
  57. i += 2;
  58. if (i >= source.size()) {
  59. return std::nullopt;
  60. }
  61. std::optional<char> c1 = FromHex(source[i - 1]);
  62. std::optional<char> c2 = FromHex(source[i]);
  63. if (c1 == std::nullopt || c2 == std::nullopt) {
  64. return std::nullopt;
  65. }
  66. ret.push_back(16 * *c1 + *c2);
  67. break;
  68. }
  69. case 'u':
  70. FATAL() << "\\u is not yet supported in string literals";
  71. default:
  72. // Unsupported.
  73. return std::nullopt;
  74. }
  75. } else {
  76. ret.push_back(c);
  77. }
  78. ++i;
  79. }
  80. return ret;
  81. }
  82. } // namespace Carbon