brintos

brintos / llvm-project-archived public Read only

0
0
Text · 25.2 KiB · 4652c07 Raw
922 lines · cpp
1//=== JSON.cpp - JSON value, parsing and serialization - 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-exception6//7//===---------------------------------------------------------------------===//8 9#include "llvm/Support/JSON.h"10#include "llvm/ADT/STLExtras.h"11#include "llvm/ADT/StringExtras.h"12#include "llvm/Support/ConvertUTF.h"13#include "llvm/Support/Error.h"14#include "llvm/Support/Format.h"15#include "llvm/Support/NativeFormatting.h"16#include "llvm/Support/raw_ostream.h"17#include <cctype>18#include <cerrno>19#include <optional>20 21namespace llvm {22namespace json {23 24Value &Object::operator[](const ObjectKey &K) {25  return try_emplace(K, nullptr).first->getSecond();26}27Value &Object::operator[](ObjectKey &&K) {28  return try_emplace(std::move(K), nullptr).first->getSecond();29}30Value *Object::get(StringRef K) {31  auto I = find(K);32  if (I == end())33    return nullptr;34  return &I->second;35}36const Value *Object::get(StringRef K) const {37  auto I = find(K);38  if (I == end())39    return nullptr;40  return &I->second;41}42std::optional<std::nullptr_t> Object::getNull(StringRef K) const {43  if (auto *V = get(K))44    return V->getAsNull();45  return std::nullopt;46}47std::optional<bool> Object::getBoolean(StringRef K) const {48  if (auto *V = get(K))49    return V->getAsBoolean();50  return std::nullopt;51}52std::optional<double> Object::getNumber(StringRef K) const {53  if (auto *V = get(K))54    return V->getAsNumber();55  return std::nullopt;56}57std::optional<int64_t> Object::getInteger(StringRef K) const {58  if (auto *V = get(K))59    return V->getAsInteger();60  return std::nullopt;61}62std::optional<llvm::StringRef> Object::getString(StringRef K) const {63  if (auto *V = get(K))64    return V->getAsString();65  return std::nullopt;66}67const json::Object *Object::getObject(StringRef K) const {68  if (auto *V = get(K))69    return V->getAsObject();70  return nullptr;71}72json::Object *Object::getObject(StringRef K) {73  if (auto *V = get(K))74    return V->getAsObject();75  return nullptr;76}77const json::Array *Object::getArray(StringRef K) const {78  if (auto *V = get(K))79    return V->getAsArray();80  return nullptr;81}82json::Array *Object::getArray(StringRef K) {83  if (auto *V = get(K))84    return V->getAsArray();85  return nullptr;86}87bool operator==(const Object &LHS, const Object &RHS) { return LHS.M == RHS.M; }88 89Array::Array(std::initializer_list<Value> Elements) {90  V.reserve(Elements.size());91  for (const Value &V : Elements) {92    emplace_back(nullptr);93    back().moveFrom(std::move(V));94  }95}96 97Value::Value(std::initializer_list<Value> Elements)98    : Value(json::Array(Elements)) {}99 100void Value::copyFrom(const Value &M) {101  Type = M.Type;102  switch (Type) {103  case T_Null:104  case T_Boolean:105  case T_Double:106  case T_Integer:107  case T_UINT64:108    memcpy(&Union, &M.Union, sizeof(Union));109    break;110  case T_StringRef:111    create<StringRef>(M.as<StringRef>());112    break;113  case T_String:114    create<std::string>(M.as<std::string>());115    break;116  case T_Object:117    create<json::Object>(M.as<json::Object>());118    break;119  case T_Array:120    create<json::Array>(M.as<json::Array>());121    break;122  }123}124 125void Value::moveFrom(const Value &&M) {126  Type = M.Type;127  switch (Type) {128  case T_Null:129  case T_Boolean:130  case T_Double:131  case T_Integer:132  case T_UINT64:133    memcpy(&Union, &M.Union, sizeof(Union));134    break;135  case T_StringRef:136    create<StringRef>(M.as<StringRef>());137    break;138  case T_String:139    create<std::string>(std::move(M.as<std::string>()));140    M.Type = T_Null;141    break;142  case T_Object:143    create<json::Object>(std::move(M.as<json::Object>()));144    M.Type = T_Null;145    break;146  case T_Array:147    create<json::Array>(std::move(M.as<json::Array>()));148    M.Type = T_Null;149    break;150  }151}152 153void Value::destroy() {154  switch (Type) {155  case T_Null:156  case T_Boolean:157  case T_Double:158  case T_Integer:159  case T_UINT64:160    break;161  case T_StringRef:162    as<StringRef>().~StringRef();163    break;164  case T_String:165    as<std::string>().~basic_string();166    break;167  case T_Object:168    as<json::Object>().~Object();169    break;170  case T_Array:171    as<json::Array>().~Array();172    break;173  }174}175 176void Value::print(llvm::raw_ostream &OS) const { OS << *this; }177 178bool operator==(const Value &L, const Value &R) {179  if (L.kind() != R.kind())180    return false;181  switch (L.kind()) {182  case Value::Null:183    return *L.getAsNull() == *R.getAsNull();184  case Value::Boolean:185    return *L.getAsBoolean() == *R.getAsBoolean();186  case Value::Number:187    // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=323188    // The same integer must convert to the same double, per the standard.189    // However we see 64-vs-80-bit precision comparisons with gcc-7 -O3 -m32.190    // So we avoid floating point promotion for exact comparisons.191    if (L.Type == Value::T_Integer || R.Type == Value::T_Integer)192      return L.getAsInteger() == R.getAsInteger();193    return *L.getAsNumber() == *R.getAsNumber();194  case Value::String:195    return *L.getAsString() == *R.getAsString();196  case Value::Array:197    return *L.getAsArray() == *R.getAsArray();198  case Value::Object:199    return *L.getAsObject() == *R.getAsObject();200  }201  llvm_unreachable("Unknown value kind");202}203 204void Path::report(llvm::StringLiteral Msg) {205  // Walk up to the root context, and count the number of segments.206  unsigned Count = 0;207  const Path *P;208  for (P = this; P->Parent != nullptr; P = P->Parent)209    ++Count;210  Path::Root *R = P->Seg.root();211  // Fill in the error message and copy the path (in reverse order).212  R->ErrorMessage = Msg;213  R->ErrorPath.resize(Count);214  auto It = R->ErrorPath.begin();215  for (P = this; P->Parent != nullptr; P = P->Parent)216    *It++ = P->Seg;217}218 219Error Path::Root::getError() const {220  std::string S;221  raw_string_ostream OS(S);222  OS << (ErrorMessage.empty() ? "invalid JSON contents" : ErrorMessage);223  if (ErrorPath.empty()) {224    if (!Name.empty())225      OS << " when parsing " << Name;226  } else {227    OS << " at " << (Name.empty() ? "(root)" : Name);228    for (const Path::Segment &S : llvm::reverse(ErrorPath)) {229      if (S.isField())230        OS << '.' << S.field();231      else232        OS << '[' << S.index() << ']';233    }234  }235  return createStringError(llvm::inconvertibleErrorCode(), S);236}237 238std::vector<const Object::value_type *> sortedElements(const Object &O) {239  std::vector<const Object::value_type *> Elements;240  for (const auto &E : O)241    Elements.push_back(&E);242  llvm::sort(Elements,243             [](const Object::value_type *L, const Object::value_type *R) {244               return L->first < R->first;245             });246  return Elements;247}248 249// Prints a one-line version of a value that isn't our main focus.250// We interleave writes to OS and JOS, exploiting the lack of extra buffering.251// This is OK as we own the implementation.252static void abbreviate(const Value &V, OStream &JOS) {253  switch (V.kind()) {254  case Value::Array:255    JOS.rawValue(V.getAsArray()->empty() ? "[]" : "[ ... ]");256    break;257  case Value::Object:258    JOS.rawValue(V.getAsObject()->empty() ? "{}" : "{ ... }");259    break;260  case Value::String: {261    llvm::StringRef S = *V.getAsString();262    if (S.size() < 40) {263      JOS.value(V);264    } else {265      std::string Truncated = fixUTF8(S.take_front(37));266      Truncated.append("...");267      JOS.value(Truncated);268    }269    break;270  }271  default:272    JOS.value(V);273  }274}275 276// Prints a semi-expanded version of a value that is our main focus.277// Array/Object entries are printed, but not recursively as they may be huge.278static void abbreviateChildren(const Value &V, OStream &JOS) {279  switch (V.kind()) {280  case Value::Array:281    JOS.array([&] {282      for (const auto &I : *V.getAsArray())283        abbreviate(I, JOS);284    });285    break;286  case Value::Object:287    JOS.object([&] {288      for (const auto *KV : sortedElements(*V.getAsObject())) {289        JOS.attributeBegin(KV->first);290        abbreviate(KV->second, JOS);291        JOS.attributeEnd();292      }293    });294    break;295  default:296    JOS.value(V);297  }298}299 300void Path::Root::printErrorContext(const Value &R, raw_ostream &OS) const {301  OStream JOS(OS, /*IndentSize=*/2);302  // PrintValue recurses down the path, printing the ancestors of our target.303  // Siblings of nodes along the path are printed with abbreviate(), and the304  // target itself is printed with the somewhat richer abbreviateChildren().305  // 'Recurse' is the lambda itself, to allow recursive calls.306  auto PrintValue = [&](const Value &V, ArrayRef<Segment> Path, auto &Recurse) {307    // Print the target node itself, with the error as a comment.308    // Also used if we can't follow our path, e.g. it names a field that309    // *should* exist but doesn't.310    auto HighlightCurrent = [&] {311      std::string Comment = "error: ";312      Comment.append(ErrorMessage.data(), ErrorMessage.size());313      JOS.comment(Comment);314      abbreviateChildren(V, JOS);315    };316    if (Path.empty()) // We reached our target.317      return HighlightCurrent();318    const Segment &S = Path.back(); // Path is in reverse order.319    if (S.isField()) {320      // Current node is an object, path names a field.321      llvm::StringRef FieldName = S.field();322      const Object *O = V.getAsObject();323      if (!O || !O->get(FieldName))324        return HighlightCurrent();325      JOS.object([&] {326        for (const auto *KV : sortedElements(*O)) {327          JOS.attributeBegin(KV->first);328          if (FieldName == StringRef(KV->first))329            Recurse(KV->second, Path.drop_back(), Recurse);330          else331            abbreviate(KV->second, JOS);332          JOS.attributeEnd();333        }334      });335    } else {336      // Current node is an array, path names an element.337      const Array *A = V.getAsArray();338      if (!A || S.index() >= A->size())339        return HighlightCurrent();340      JOS.array([&] {341        unsigned Current = 0;342        for (const auto &V : *A) {343          if (Current++ == S.index())344            Recurse(V, Path.drop_back(), Recurse);345          else346            abbreviate(V, JOS);347        }348      });349    }350  };351  PrintValue(R, ErrorPath, PrintValue);352}353 354namespace {355// Simple recursive-descent JSON parser.356class Parser {357public:358  Parser(StringRef JSON)359      : Start(JSON.begin()), P(JSON.begin()), End(JSON.end()) {}360 361  bool checkUTF8() {362    size_t ErrOffset;363    if (isUTF8(StringRef(Start, End - Start), &ErrOffset))364      return true;365    P = Start + ErrOffset; // For line/column calculation.366    return parseError("Invalid UTF-8 sequence");367  }368 369  bool parseValue(Value &Out);370 371  bool assertEnd() {372    eatWhitespace();373    if (P == End)374      return true;375    return parseError("Text after end of document");376  }377 378  Error takeError() {379    assert(Err);380    return std::move(*Err);381  }382 383private:384  void eatWhitespace() {385    while (P != End && (*P == ' ' || *P == '\r' || *P == '\n' || *P == '\t'))386      ++P;387  }388 389  // On invalid syntax, parseX() functions return false and set Err.390  bool parseNumber(char First, Value &Out);391  bool parseString(std::string &Out);392  bool parseUnicode(std::string &Out);393  bool parseError(const char *Msg); // always returns false394 395  char next() { return P == End ? 0 : *P++; }396  char peek() { return P == End ? 0 : *P; }397  static bool isNumber(char C) {398    return C == '0' || C == '1' || C == '2' || C == '3' || C == '4' ||399           C == '5' || C == '6' || C == '7' || C == '8' || C == '9' ||400           C == 'e' || C == 'E' || C == '+' || C == '-' || C == '.';401  }402 403  std::optional<Error> Err;404  const char *Start, *P, *End;405};406} // namespace407 408bool Parser::parseValue(Value &Out) {409  eatWhitespace();410  if (P == End)411    return parseError("Unexpected EOF");412  switch (char C = next()) {413  // Bare null/true/false are easy - first char identifies them.414  case 'n':415    Out = nullptr;416    return (next() == 'u' && next() == 'l' && next() == 'l') ||417           parseError("Invalid JSON value (null?)");418  case 't':419    Out = true;420    return (next() == 'r' && next() == 'u' && next() == 'e') ||421           parseError("Invalid JSON value (true?)");422  case 'f':423    Out = false;424    return (next() == 'a' && next() == 'l' && next() == 's' && next() == 'e') ||425           parseError("Invalid JSON value (false?)");426  case '"': {427    std::string S;428    if (parseString(S)) {429      Out = std::move(S);430      return true;431    }432    return false;433  }434  case '[': {435    Out = Array{};436    Array &A = *Out.getAsArray();437    eatWhitespace();438    if (peek() == ']') {439      ++P;440      return true;441    }442    for (;;) {443      A.emplace_back(nullptr);444      if (!parseValue(A.back()))445        return false;446      eatWhitespace();447      switch (next()) {448      case ',':449        eatWhitespace();450        continue;451      case ']':452        return true;453      default:454        return parseError("Expected , or ] after array element");455      }456    }457  }458  case '{': {459    Out = Object{};460    Object &O = *Out.getAsObject();461    eatWhitespace();462    if (peek() == '}') {463      ++P;464      return true;465    }466    for (;;) {467      if (next() != '"')468        return parseError("Expected object key");469      std::string K;470      if (!parseString(K))471        return false;472      eatWhitespace();473      if (next() != ':')474        return parseError("Expected : after object key");475      eatWhitespace();476      if (!parseValue(O[std::move(K)]))477        return false;478      eatWhitespace();479      switch (next()) {480      case ',':481        eatWhitespace();482        continue;483      case '}':484        return true;485      default:486        return parseError("Expected , or } after object property");487      }488    }489  }490  default:491    if (isNumber(C))492      return parseNumber(C, Out);493    return parseError("Invalid JSON value");494  }495}496 497bool Parser::parseNumber(char First, Value &Out) {498  // Read the number into a string. (Must be null-terminated for strto*).499  SmallString<24> S;500  S.push_back(First);501  while (isNumber(peek()))502    S.push_back(next());503  char *End;504  // Try first to parse as integer, and if so preserve full 64 bits.505  // We check for errno for out of bounds errors and for End == S.end()506  // to make sure that the numeric string is not malformed.507  errno = 0;508  int64_t I = std::strtoll(S.c_str(), &End, 10);509  if (End == S.end() && errno != ERANGE) {510    Out = I;511    return true;512  }513  // strtroull has a special handling for negative numbers, but in this514  // case we don't want to do that because negative numbers were already515  // handled in the previous block.516  if (First != '-') {517    errno = 0;518    uint64_t UI = std::strtoull(S.c_str(), &End, 10);519    if (End == S.end() && errno != ERANGE) {520      Out = UI;521      return true;522    }523  }524  // If it's not an integer525  Out = std::strtod(S.c_str(), &End);526  return End == S.end() || parseError("Invalid JSON value (number?)");527}528 529bool Parser::parseString(std::string &Out) {530  // leading quote was already consumed.531  for (char C = next(); C != '"'; C = next()) {532    if (LLVM_UNLIKELY(P == End))533      return parseError("Unterminated string");534    if (LLVM_UNLIKELY((C & 0x1f) == C))535      return parseError("Control character in string");536    if (LLVM_LIKELY(C != '\\')) {537      Out.push_back(C);538      continue;539    }540    // Handle escape sequence.541    switch (C = next()) {542    case '"':543    case '\\':544    case '/':545      Out.push_back(C);546      break;547    case 'b':548      Out.push_back('\b');549      break;550    case 'f':551      Out.push_back('\f');552      break;553    case 'n':554      Out.push_back('\n');555      break;556    case 'r':557      Out.push_back('\r');558      break;559    case 't':560      Out.push_back('\t');561      break;562    case 'u':563      if (!parseUnicode(Out))564        return false;565      break;566    default:567      return parseError("Invalid escape sequence");568    }569  }570  return true;571}572 573static void encodeUtf8(uint32_t Rune, std::string &Out) {574  if (Rune < 0x80) {575    Out.push_back(Rune & 0x7F);576  } else if (Rune < 0x800) {577    uint8_t FirstByte = 0xC0 | ((Rune & 0x7C0) >> 6);578    uint8_t SecondByte = 0x80 | (Rune & 0x3F);579    Out.push_back(FirstByte);580    Out.push_back(SecondByte);581  } else if (Rune < 0x10000) {582    uint8_t FirstByte = 0xE0 | ((Rune & 0xF000) >> 12);583    uint8_t SecondByte = 0x80 | ((Rune & 0xFC0) >> 6);584    uint8_t ThirdByte = 0x80 | (Rune & 0x3F);585    Out.push_back(FirstByte);586    Out.push_back(SecondByte);587    Out.push_back(ThirdByte);588  } else if (Rune < 0x110000) {589    uint8_t FirstByte = 0xF0 | ((Rune & 0x1F0000) >> 18);590    uint8_t SecondByte = 0x80 | ((Rune & 0x3F000) >> 12);591    uint8_t ThirdByte = 0x80 | ((Rune & 0xFC0) >> 6);592    uint8_t FourthByte = 0x80 | (Rune & 0x3F);593    Out.push_back(FirstByte);594    Out.push_back(SecondByte);595    Out.push_back(ThirdByte);596    Out.push_back(FourthByte);597  } else {598    llvm_unreachable("Invalid codepoint");599  }600}601 602// Parse a UTF-16 \uNNNN escape sequence. "\u" has already been consumed.603// May parse several sequential escapes to ensure proper surrogate handling.604// We do not use ConvertUTF.h, it can't accept and replace unpaired surrogates.605// These are invalid Unicode but valid JSON (RFC 8259, section 8.2).606bool Parser::parseUnicode(std::string &Out) {607  // Invalid UTF is not a JSON error (RFC 8529§8.2). It gets replaced by U+FFFD.608  auto Invalid = [&] { Out.append(/* UTF-8 */ {'\xef', '\xbf', '\xbd'}); };609  // Decodes 4 hex digits from the stream into Out, returns false on error.610  auto Parse4Hex = [this](uint16_t &Out) -> bool {611    Out = 0;612    char Bytes[] = {next(), next(), next(), next()};613    for (unsigned char C : Bytes) {614      if (!std::isxdigit(C))615        return parseError("Invalid \\u escape sequence");616      Out <<= 4;617      Out |= (C > '9') ? (C & ~0x20) - 'A' + 10 : (C - '0');618    }619    return true;620  };621  uint16_t First; // UTF-16 code unit from the first \u escape.622  if (!Parse4Hex(First))623    return false;624 625  // We loop to allow proper surrogate-pair error handling.626  while (true) {627    // Case 1: the UTF-16 code unit is already a codepoint in the BMP.628    if (LLVM_LIKELY(First < 0xD800 || First >= 0xE000)) {629      encodeUtf8(First, Out);630      return true;631    }632 633    // Case 2: it's an (unpaired) trailing surrogate.634    if (LLVM_UNLIKELY(First >= 0xDC00)) {635      Invalid();636      return true;637    }638 639    // Case 3: it's a leading surrogate. We expect a trailing one next.640    // Case 3a: there's no trailing \u escape. Don't advance in the stream.641    if (LLVM_UNLIKELY(P + 2 > End || *P != '\\' || *(P + 1) != 'u')) {642      Invalid(); // Leading surrogate was unpaired.643      return true;644    }645    P += 2;646    uint16_t Second;647    if (!Parse4Hex(Second))648      return false;649    // Case 3b: there was another \u escape, but it wasn't a trailing surrogate.650    if (LLVM_UNLIKELY(Second < 0xDC00 || Second >= 0xE000)) {651      Invalid();      // Leading surrogate was unpaired.652      First = Second; // Second escape still needs to be processed.653      continue;654    }655    // Case 3c: a valid surrogate pair encoding an astral codepoint.656    encodeUtf8(0x10000 | ((First - 0xD800) << 10) | (Second - 0xDC00), Out);657    return true;658  }659}660 661bool Parser::parseError(const char *Msg) {662  int Line = 1;663  const char *StartOfLine = Start;664  for (const char *X = Start; X < P; ++X) {665    if (*X == 0x0A) {666      ++Line;667      StartOfLine = X + 1;668    }669  }670  Err.emplace(671      std::make_unique<ParseError>(Msg, Line, P - StartOfLine, P - Start));672  return false;673}674 675Expected<Value> parse(StringRef JSON) {676  Parser P(JSON);677  Value E = nullptr;678  if (P.checkUTF8())679    if (P.parseValue(E))680      if (P.assertEnd())681        return std::move(E);682  return P.takeError();683}684char ParseError::ID = 0;685 686bool isUTF8(llvm::StringRef S, size_t *ErrOffset) {687  // Fast-path for ASCII, which is valid UTF-8.688  if (LLVM_LIKELY(isASCII(S)))689    return true;690 691  const UTF8 *Data = reinterpret_cast<const UTF8 *>(S.data()), *Rest = Data;692  if (LLVM_LIKELY(isLegalUTF8String(&Rest, Data + S.size())))693    return true;694 695  if (ErrOffset)696    *ErrOffset = Rest - Data;697  return false;698}699 700std::string fixUTF8(llvm::StringRef S) {701  // This isn't particularly efficient, but is only for error-recovery.702  std::vector<UTF32> Codepoints(S.size()); // 1 codepoint per byte suffices.703  const UTF8 *In8 = reinterpret_cast<const UTF8 *>(S.data());704  UTF32 *Out32 = Codepoints.data();705  ConvertUTF8toUTF32(&In8, In8 + S.size(), &Out32, Out32 + Codepoints.size(),706                     lenientConversion);707  Codepoints.resize(Out32 - Codepoints.data());708  std::string Res(4 * Codepoints.size(), 0); // 4 bytes per codepoint suffice709  const UTF32 *In32 = Codepoints.data();710  UTF8 *Out8 = reinterpret_cast<UTF8 *>(&Res[0]);711  ConvertUTF32toUTF8(&In32, In32 + Codepoints.size(), &Out8, Out8 + Res.size(),712                     strictConversion);713  Res.resize(reinterpret_cast<char *>(Out8) - Res.data());714  return Res;715}716 717static void quote(llvm::raw_ostream &OS, llvm::StringRef S) {718  OS << '\"';719  for (unsigned char C : S) {720    if (C == 0x22 || C == 0x5C)721      OS << '\\';722    if (C >= 0x20) {723      OS << C;724      continue;725    }726    OS << '\\';727    switch (C) {728    // A few characters are common enough to make short escapes worthwhile.729    case '\t':730      OS << 't';731      break;732    case '\n':733      OS << 'n';734      break;735    case '\r':736      OS << 'r';737      break;738    default:739      OS << 'u';740      llvm::write_hex(OS, C, llvm::HexPrintStyle::Lower, 4);741      break;742    }743  }744  OS << '\"';745}746 747void llvm::json::OStream::value(const Value &V) {748  switch (V.kind()) {749  case Value::Null:750    valueBegin();751    OS << "null";752    return;753  case Value::Boolean:754    valueBegin();755    OS << (*V.getAsBoolean() ? "true" : "false");756    return;757  case Value::Number:758    valueBegin();759    if (V.Type == Value::T_Integer)760      OS << *V.getAsInteger();761    else if (V.Type == Value::T_UINT64)762      OS << *V.getAsUINT64();763    else764      OS << format("%.*g", std::numeric_limits<double>::max_digits10,765                   *V.getAsNumber());766    return;767  case Value::String:768    valueBegin();769    quote(OS, *V.getAsString());770    return;771  case Value::Array:772    return array([&] {773      for (const Value &E : *V.getAsArray())774        value(E);775    });776  case Value::Object:777    return object([&] {778      for (const Object::value_type *E : sortedElements(*V.getAsObject()))779        attribute(E->first, E->second);780    });781  }782}783 784void llvm::json::OStream::valueBegin() {785  assert(Stack.back().Ctx != Object && "Only attributes allowed here");786  if (Stack.back().HasValue) {787    assert(Stack.back().Ctx != Singleton && "Only one value allowed here");788    OS << ',';789  }790  if (Stack.back().Ctx == Array)791    newline();792  flushComment();793  Stack.back().HasValue = true;794}795 796void OStream::comment(llvm::StringRef Comment) {797  assert(PendingComment.empty() && "Only one comment per value!");798  PendingComment = Comment;799}800 801void OStream::flushComment() {802  if (PendingComment.empty())803    return;804  OS << (IndentSize ? "/* " : "/*");805  // Be sure not to accidentally emit "*/". Transform to "* /".806  while (!PendingComment.empty()) {807    auto Pos = PendingComment.find("*/");808    if (Pos == StringRef::npos) {809      OS << PendingComment;810      PendingComment = "";811    } else {812      OS << PendingComment.take_front(Pos) << "* /";813      PendingComment = PendingComment.drop_front(Pos + 2);814    }815  }816  OS << (IndentSize ? " */" : "*/");817  // Comments are on their own line unless attached to an attribute value.818  if (Stack.size() > 1 && Stack.back().Ctx == Singleton) {819    if (IndentSize)820      OS << ' ';821  } else {822    newline();823  }824}825 826void llvm::json::OStream::newline() {827  if (IndentSize) {828    OS.write('\n');829    OS.indent(Indent);830  }831}832 833void llvm::json::OStream::arrayBegin() {834  valueBegin();835  Stack.emplace_back();836  Stack.back().Ctx = Array;837  Indent += IndentSize;838  OS << '[';839}840 841void llvm::json::OStream::arrayEnd() {842  assert(Stack.back().Ctx == Array);843  Indent -= IndentSize;844  if (Stack.back().HasValue)845    newline();846  OS << ']';847  assert(PendingComment.empty());848  Stack.pop_back();849  assert(!Stack.empty());850}851 852void llvm::json::OStream::objectBegin() {853  valueBegin();854  Stack.emplace_back();855  Stack.back().Ctx = Object;856  Indent += IndentSize;857  OS << '{';858}859 860void llvm::json::OStream::objectEnd() {861  assert(Stack.back().Ctx == Object);862  Indent -= IndentSize;863  if (Stack.back().HasValue)864    newline();865  OS << '}';866  assert(PendingComment.empty());867  Stack.pop_back();868  assert(!Stack.empty());869}870 871void llvm::json::OStream::attributeBegin(llvm::StringRef Key) {872  assert(Stack.back().Ctx == Object);873  if (Stack.back().HasValue)874    OS << ',';875  newline();876  flushComment();877  Stack.back().HasValue = true;878  Stack.emplace_back();879  Stack.back().Ctx = Singleton;880  if (LLVM_LIKELY(isUTF8(Key))) {881    quote(OS, Key);882  } else {883    assert(false && "Invalid UTF-8 in attribute key");884    quote(OS, fixUTF8(Key));885  }886  OS.write(':');887  if (IndentSize)888    OS.write(' ');889}890 891void llvm::json::OStream::attributeEnd() {892  assert(Stack.back().Ctx == Singleton);893  assert(Stack.back().HasValue && "Attribute must have a value");894  assert(PendingComment.empty());895  Stack.pop_back();896  assert(Stack.back().Ctx == Object);897}898 899raw_ostream &llvm::json::OStream::rawValueBegin() {900  valueBegin();901  Stack.emplace_back();902  Stack.back().Ctx = RawValue;903  return OS;904}905 906void llvm::json::OStream::rawValueEnd() {907  assert(Stack.back().Ctx == RawValue);908  Stack.pop_back();909}910 911} // namespace json912} // namespace llvm913 914void llvm::format_provider<llvm::json::Value>::format(915    const llvm::json::Value &E, raw_ostream &OS, StringRef Options) {916  unsigned IndentAmount = 0;917  if (!Options.empty() && Options.getAsInteger(/*Radix=*/10, IndentAmount))918    llvm_unreachable("json::Value format options should be an integer");919  json::OStream(OS, IndentAmount).value(E);920}921 922