FormatVariadic.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. //===- FormatVariadic.cpp - Format string parsing and analysis ----*-C++-*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //===----------------------------------------------------------------------===//
  7. #include "llvm/Support/FormatVariadic.h"
  8. #include <cassert>
  9. #include <optional>
  10. using namespace llvm;
  11. static std::optional<AlignStyle> translateLocChar(char C) {
  12. switch (C) {
  13. case '-':
  14. return AlignStyle::Left;
  15. case '=':
  16. return AlignStyle::Center;
  17. case '+':
  18. return AlignStyle::Right;
  19. default:
  20. return std::nullopt;
  21. }
  22. LLVM_BUILTIN_UNREACHABLE;
  23. }
  24. bool formatv_object_base::consumeFieldLayout(StringRef &Spec, AlignStyle &Where,
  25. size_t &Align, char &Pad) {
  26. Where = AlignStyle::Right;
  27. Align = 0;
  28. Pad = ' ';
  29. if (Spec.empty())
  30. return true;
  31. if (Spec.size() > 1) {
  32. // A maximum of 2 characters at the beginning can be used for something
  33. // other
  34. // than the width.
  35. // If Spec[1] is a loc char, then Spec[0] is a pad char and Spec[2:...]
  36. // contains the width.
  37. // Otherwise, if Spec[0] is a loc char, then Spec[1:...] contains the width.
  38. // Otherwise, Spec[0:...] contains the width.
  39. if (auto Loc = translateLocChar(Spec[1])) {
  40. Pad = Spec[0];
  41. Where = *Loc;
  42. Spec = Spec.drop_front(2);
  43. } else if (auto Loc = translateLocChar(Spec[0])) {
  44. Where = *Loc;
  45. Spec = Spec.drop_front(1);
  46. }
  47. }
  48. bool Failed = Spec.consumeInteger(0, Align);
  49. return !Failed;
  50. }
  51. std::optional<ReplacementItem>
  52. formatv_object_base::parseReplacementItem(StringRef Spec) {
  53. StringRef RepString = Spec.trim("{}");
  54. // If the replacement sequence does not start with a non-negative integer,
  55. // this is an error.
  56. char Pad = ' ';
  57. std::size_t Align = 0;
  58. AlignStyle Where = AlignStyle::Right;
  59. StringRef Options;
  60. size_t Index = 0;
  61. RepString = RepString.trim();
  62. if (RepString.consumeInteger(0, Index)) {
  63. assert(false && "Invalid replacement sequence index!");
  64. return ReplacementItem{};
  65. }
  66. RepString = RepString.trim();
  67. if (!RepString.empty() && RepString.front() == ',') {
  68. RepString = RepString.drop_front();
  69. if (!consumeFieldLayout(RepString, Where, Align, Pad))
  70. assert(false && "Invalid replacement field layout specification!");
  71. }
  72. RepString = RepString.trim();
  73. if (!RepString.empty() && RepString.front() == ':') {
  74. Options = RepString.drop_front().trim();
  75. RepString = StringRef();
  76. }
  77. RepString = RepString.trim();
  78. if (!RepString.empty()) {
  79. assert(false && "Unexpected characters found in replacement string!");
  80. }
  81. return ReplacementItem{Spec, Index, Align, Where, Pad, Options};
  82. }
  83. std::pair<ReplacementItem, StringRef>
  84. formatv_object_base::splitLiteralAndReplacement(StringRef Fmt) {
  85. while (!Fmt.empty()) {
  86. // Everything up until the first brace is a literal.
  87. if (Fmt.front() != '{') {
  88. std::size_t BO = Fmt.find_first_of('{');
  89. return std::make_pair(ReplacementItem{Fmt.substr(0, BO)}, Fmt.substr(BO));
  90. }
  91. StringRef Braces = Fmt.take_while([](char C) { return C == '{'; });
  92. // If there is more than one brace, then some of them are escaped. Treat
  93. // these as replacements.
  94. if (Braces.size() > 1) {
  95. size_t NumEscapedBraces = Braces.size() / 2;
  96. StringRef Middle = Fmt.take_front(NumEscapedBraces);
  97. StringRef Right = Fmt.drop_front(NumEscapedBraces * 2);
  98. return std::make_pair(ReplacementItem{Middle}, Right);
  99. }
  100. // An unterminated open brace is undefined. We treat the rest of the string
  101. // as a literal replacement, but we assert to indicate that this is
  102. // undefined and that we consider it an error.
  103. std::size_t BC = Fmt.find_first_of('}');
  104. if (BC == StringRef::npos) {
  105. assert(
  106. false &&
  107. "Unterminated brace sequence. Escape with {{ for a literal brace.");
  108. return std::make_pair(ReplacementItem{Fmt}, StringRef());
  109. }
  110. // Even if there is a closing brace, if there is another open brace before
  111. // this closing brace, treat this portion as literal, and try again with the
  112. // next one.
  113. std::size_t BO2 = Fmt.find_first_of('{', 1);
  114. if (BO2 < BC)
  115. return std::make_pair(ReplacementItem{Fmt.substr(0, BO2)},
  116. Fmt.substr(BO2));
  117. StringRef Spec = Fmt.slice(1, BC);
  118. StringRef Right = Fmt.substr(BC + 1);
  119. auto RI = parseReplacementItem(Spec);
  120. if (RI)
  121. return std::make_pair(*RI, Right);
  122. // If there was an error parsing the replacement item, treat it as an
  123. // invalid replacement spec, and just continue.
  124. Fmt = Fmt.drop_front(BC + 1);
  125. }
  126. return std::make_pair(ReplacementItem{Fmt}, StringRef());
  127. }
  128. SmallVector<ReplacementItem, 2>
  129. formatv_object_base::parseFormatString(StringRef Fmt) {
  130. SmallVector<ReplacementItem, 2> Replacements;
  131. ReplacementItem I;
  132. while (!Fmt.empty()) {
  133. std::tie(I, Fmt) = splitLiteralAndReplacement(Fmt);
  134. if (I.Type != ReplacementType::Empty)
  135. Replacements.push_back(I);
  136. }
  137. return Replacements;
  138. }
  139. void detail::format_adapter::anchor() { }