16be38247SSam McCall //=== JSON.cpp - JSON value, parsing and serialization - C++ -----------*-===//
26be38247SSam McCall //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66be38247SSam McCall //
76be38247SSam McCall //===---------------------------------------------------------------------===//
86be38247SSam McCall 
96be38247SSam McCall #include "llvm/Support/JSON.h"
1016619e71SSam McCall #include "llvm/ADT/STLExtras.h"
11e6057bc6SSam McCall #include "llvm/Support/ConvertUTF.h"
1216619e71SSam McCall #include "llvm/Support/Error.h"
136be38247SSam McCall #include "llvm/Support/Format.h"
14140b7b6fSSam McCall #include "llvm/Support/raw_ostream.h"
1575e164f6Sserge-sans-paille #include "llvm/Support/NativeFormatting.h"
166be38247SSam McCall #include <cctype>
176be38247SSam McCall 
186be38247SSam McCall namespace llvm {
196be38247SSam McCall namespace json {
206be38247SSam McCall 
operator [](const ObjectKey & K)216be38247SSam McCall Value &Object::operator[](const ObjectKey &K) {
226be38247SSam McCall   return try_emplace(K, nullptr).first->getSecond();
236be38247SSam McCall }
operator [](ObjectKey && K)246be38247SSam McCall Value &Object::operator[](ObjectKey &&K) {
256be38247SSam McCall   return try_emplace(std::move(K), nullptr).first->getSecond();
266be38247SSam McCall }
get(StringRef K)276be38247SSam McCall Value *Object::get(StringRef K) {
286be38247SSam McCall   auto I = find(K);
296be38247SSam McCall   if (I == end())
306be38247SSam McCall     return nullptr;
316be38247SSam McCall   return &I->second;
326be38247SSam McCall }
get(StringRef K) const336be38247SSam McCall const Value *Object::get(StringRef K) const {
346be38247SSam McCall   auto I = find(K);
356be38247SSam McCall   if (I == end())
366be38247SSam McCall     return nullptr;
376be38247SSam McCall   return &I->second;
386be38247SSam McCall }
getNull(StringRef K) const396be38247SSam McCall llvm::Optional<std::nullptr_t> Object::getNull(StringRef K) const {
406be38247SSam McCall   if (auto *V = get(K))
416be38247SSam McCall     return V->getAsNull();
426be38247SSam McCall   return llvm::None;
436be38247SSam McCall }
getBoolean(StringRef K) const446be38247SSam McCall llvm::Optional<bool> Object::getBoolean(StringRef K) const {
456be38247SSam McCall   if (auto *V = get(K))
466be38247SSam McCall     return V->getAsBoolean();
476be38247SSam McCall   return llvm::None;
486be38247SSam McCall }
getNumber(StringRef K) const496be38247SSam McCall llvm::Optional<double> Object::getNumber(StringRef K) const {
506be38247SSam McCall   if (auto *V = get(K))
516be38247SSam McCall     return V->getAsNumber();
526be38247SSam McCall   return llvm::None;
536be38247SSam McCall }
getInteger(StringRef K) const546be38247SSam McCall llvm::Optional<int64_t> Object::getInteger(StringRef K) const {
556be38247SSam McCall   if (auto *V = get(K))
566be38247SSam McCall     return V->getAsInteger();
576be38247SSam McCall   return llvm::None;
586be38247SSam McCall }
getString(StringRef K) const596be38247SSam McCall llvm::Optional<llvm::StringRef> Object::getString(StringRef K) const {
606be38247SSam McCall   if (auto *V = get(K))
616be38247SSam McCall     return V->getAsString();
626be38247SSam McCall   return llvm::None;
636be38247SSam McCall }
getObject(StringRef K) const646be38247SSam McCall const json::Object *Object::getObject(StringRef K) const {
656be38247SSam McCall   if (auto *V = get(K))
666be38247SSam McCall     return V->getAsObject();
676be38247SSam McCall   return nullptr;
686be38247SSam McCall }
getObject(StringRef K)696be38247SSam McCall json::Object *Object::getObject(StringRef K) {
706be38247SSam McCall   if (auto *V = get(K))
716be38247SSam McCall     return V->getAsObject();
726be38247SSam McCall   return nullptr;
736be38247SSam McCall }
getArray(StringRef K) const746be38247SSam McCall const json::Array *Object::getArray(StringRef K) const {
756be38247SSam McCall   if (auto *V = get(K))
766be38247SSam McCall     return V->getAsArray();
776be38247SSam McCall   return nullptr;
786be38247SSam McCall }
getArray(StringRef K)796be38247SSam McCall json::Array *Object::getArray(StringRef K) {
806be38247SSam McCall   if (auto *V = get(K))
816be38247SSam McCall     return V->getAsArray();
826be38247SSam McCall   return nullptr;
836be38247SSam McCall }
operator ==(const Object & LHS,const Object & RHS)846be38247SSam McCall bool operator==(const Object &LHS, const Object &RHS) {
856be38247SSam McCall   if (LHS.size() != RHS.size())
866be38247SSam McCall     return false;
876be38247SSam McCall   for (const auto &L : LHS) {
886be38247SSam McCall     auto R = RHS.find(L.first);
896be38247SSam McCall     if (R == RHS.end() || L.second != R->second)
906be38247SSam McCall       return false;
916be38247SSam McCall   }
926be38247SSam McCall   return true;
936be38247SSam McCall }
946be38247SSam McCall 
Array(std::initializer_list<Value> Elements)956be38247SSam McCall Array::Array(std::initializer_list<Value> Elements) {
966be38247SSam McCall   V.reserve(Elements.size());
976be38247SSam McCall   for (const Value &V : Elements) {
986be38247SSam McCall     emplace_back(nullptr);
996be38247SSam McCall     back().moveFrom(std::move(V));
1006be38247SSam McCall   }
1016be38247SSam McCall }
1026be38247SSam McCall 
Value(std::initializer_list<Value> Elements)1036be38247SSam McCall Value::Value(std::initializer_list<Value> Elements)
1046be38247SSam McCall     : Value(json::Array(Elements)) {}
1056be38247SSam McCall 
copyFrom(const Value & M)1066be38247SSam McCall void Value::copyFrom(const Value &M) {
1076be38247SSam McCall   Type = M.Type;
1086be38247SSam McCall   switch (Type) {
1096be38247SSam McCall   case T_Null:
1106be38247SSam McCall   case T_Boolean:
111d93eaeb7SSam McCall   case T_Double:
112d93eaeb7SSam McCall   case T_Integer:
1138c3adce8Sdjtodoro   case T_UINT64:
1145b267fb7SDuncan P. N. Exon Smith     memcpy(&Union, &M.Union, sizeof(Union));
1156be38247SSam McCall     break;
1166be38247SSam McCall   case T_StringRef:
1176be38247SSam McCall     create<StringRef>(M.as<StringRef>());
1186be38247SSam McCall     break;
1196be38247SSam McCall   case T_String:
1206be38247SSam McCall     create<std::string>(M.as<std::string>());
1216be38247SSam McCall     break;
1226be38247SSam McCall   case T_Object:
1236be38247SSam McCall     create<json::Object>(M.as<json::Object>());
1246be38247SSam McCall     break;
1256be38247SSam McCall   case T_Array:
1266be38247SSam McCall     create<json::Array>(M.as<json::Array>());
1276be38247SSam McCall     break;
1286be38247SSam McCall   }
1296be38247SSam McCall }
1306be38247SSam McCall 
moveFrom(const Value && M)1316be38247SSam McCall void Value::moveFrom(const Value &&M) {
1326be38247SSam McCall   Type = M.Type;
1336be38247SSam McCall   switch (Type) {
1346be38247SSam McCall   case T_Null:
1356be38247SSam McCall   case T_Boolean:
136d93eaeb7SSam McCall   case T_Double:
137d93eaeb7SSam McCall   case T_Integer:
1388c3adce8Sdjtodoro   case T_UINT64:
1395b267fb7SDuncan P. N. Exon Smith     memcpy(&Union, &M.Union, sizeof(Union));
1406be38247SSam McCall     break;
1416be38247SSam McCall   case T_StringRef:
1426be38247SSam McCall     create<StringRef>(M.as<StringRef>());
1436be38247SSam McCall     break;
1446be38247SSam McCall   case T_String:
1456be38247SSam McCall     create<std::string>(std::move(M.as<std::string>()));
1466be38247SSam McCall     M.Type = T_Null;
1476be38247SSam McCall     break;
1486be38247SSam McCall   case T_Object:
1496be38247SSam McCall     create<json::Object>(std::move(M.as<json::Object>()));
1506be38247SSam McCall     M.Type = T_Null;
1516be38247SSam McCall     break;
1526be38247SSam McCall   case T_Array:
1536be38247SSam McCall     create<json::Array>(std::move(M.as<json::Array>()));
1546be38247SSam McCall     M.Type = T_Null;
1556be38247SSam McCall     break;
1566be38247SSam McCall   }
1576be38247SSam McCall }
1586be38247SSam McCall 
destroy()1596be38247SSam McCall void Value::destroy() {
1606be38247SSam McCall   switch (Type) {
1616be38247SSam McCall   case T_Null:
1626be38247SSam McCall   case T_Boolean:
163d93eaeb7SSam McCall   case T_Double:
164d93eaeb7SSam McCall   case T_Integer:
1658c3adce8Sdjtodoro   case T_UINT64:
1666be38247SSam McCall     break;
1676be38247SSam McCall   case T_StringRef:
1686be38247SSam McCall     as<StringRef>().~StringRef();
1696be38247SSam McCall     break;
1706be38247SSam McCall   case T_String:
1716be38247SSam McCall     as<std::string>().~basic_string();
1726be38247SSam McCall     break;
1736be38247SSam McCall   case T_Object:
1746be38247SSam McCall     as<json::Object>().~Object();
1756be38247SSam McCall     break;
1766be38247SSam McCall   case T_Array:
1776be38247SSam McCall     as<json::Array>().~Array();
1786be38247SSam McCall     break;
1796be38247SSam McCall   }
1806be38247SSam McCall }
1816be38247SSam McCall 
operator ==(const Value & L,const Value & R)1826be38247SSam McCall bool operator==(const Value &L, const Value &R) {
1836be38247SSam McCall   if (L.kind() != R.kind())
1846be38247SSam McCall     return false;
1856be38247SSam McCall   switch (L.kind()) {
1866be38247SSam McCall   case Value::Null:
1876be38247SSam McCall     return *L.getAsNull() == *R.getAsNull();
1886be38247SSam McCall   case Value::Boolean:
1896be38247SSam McCall     return *L.getAsBoolean() == *R.getAsBoolean();
1906be38247SSam McCall   case Value::Number:
1911e7491eaSSam McCall     // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=323
1921e7491eaSSam McCall     // The same integer must convert to the same double, per the standard.
1931e7491eaSSam McCall     // However we see 64-vs-80-bit precision comparisons with gcc-7 -O3 -m32.
1941e7491eaSSam McCall     // So we avoid floating point promotion for exact comparisons.
1951e7491eaSSam McCall     if (L.Type == Value::T_Integer || R.Type == Value::T_Integer)
1961e7491eaSSam McCall       return L.getAsInteger() == R.getAsInteger();
1976be38247SSam McCall     return *L.getAsNumber() == *R.getAsNumber();
1986be38247SSam McCall   case Value::String:
1996be38247SSam McCall     return *L.getAsString() == *R.getAsString();
2006be38247SSam McCall   case Value::Array:
2016be38247SSam McCall     return *L.getAsArray() == *R.getAsArray();
2026be38247SSam McCall   case Value::Object:
2036be38247SSam McCall     return *L.getAsObject() == *R.getAsObject();
2046be38247SSam McCall   }
2056be38247SSam McCall   llvm_unreachable("Unknown value kind");
2066be38247SSam McCall }
2076be38247SSam McCall 
report(llvm::StringLiteral Msg)20816619e71SSam McCall void Path::report(llvm::StringLiteral Msg) {
20916619e71SSam McCall   // Walk up to the root context, and count the number of segments.
21016619e71SSam McCall   unsigned Count = 0;
21116619e71SSam McCall   const Path *P;
21216619e71SSam McCall   for (P = this; P->Parent != nullptr; P = P->Parent)
21316619e71SSam McCall     ++Count;
21416619e71SSam McCall   Path::Root *R = P->Seg.root();
21516619e71SSam McCall   // Fill in the error message and copy the path (in reverse order).
21616619e71SSam McCall   R->ErrorMessage = Msg;
21716619e71SSam McCall   R->ErrorPath.resize(Count);
21816619e71SSam McCall   auto It = R->ErrorPath.begin();
21916619e71SSam McCall   for (P = this; P->Parent != nullptr; P = P->Parent)
22016619e71SSam McCall     *It++ = P->Seg;
22116619e71SSam McCall }
22216619e71SSam McCall 
getError() const22316619e71SSam McCall Error Path::Root::getError() const {
22416619e71SSam McCall   std::string S;
22516619e71SSam McCall   raw_string_ostream OS(S);
22616619e71SSam McCall   OS << (ErrorMessage.empty() ? "invalid JSON contents" : ErrorMessage);
22716619e71SSam McCall   if (ErrorPath.empty()) {
22816619e71SSam McCall     if (!Name.empty())
22916619e71SSam McCall       OS << " when parsing " << Name;
23016619e71SSam McCall   } else {
23116619e71SSam McCall     OS << " at " << (Name.empty() ? "(root)" : Name);
23216619e71SSam McCall     for (const Path::Segment &S : llvm::reverse(ErrorPath)) {
23316619e71SSam McCall       if (S.isField())
23416619e71SSam McCall         OS << '.' << S.field();
23516619e71SSam McCall       else
23616619e71SSam McCall         OS << '[' << S.index() << ']';
23716619e71SSam McCall     }
23816619e71SSam McCall   }
23916619e71SSam McCall   return createStringError(llvm::inconvertibleErrorCode(), OS.str());
24016619e71SSam McCall }
24116619e71SSam McCall 
2426be38247SSam McCall namespace {
24338de1c33SSam McCall 
sortedElements(const Object & O)24438de1c33SSam McCall std::vector<const Object::value_type *> sortedElements(const Object &O) {
24538de1c33SSam McCall   std::vector<const Object::value_type *> Elements;
24638de1c33SSam McCall   for (const auto &E : O)
24738de1c33SSam McCall     Elements.push_back(&E);
24838de1c33SSam McCall   llvm::sort(Elements,
24938de1c33SSam McCall              [](const Object::value_type *L, const Object::value_type *R) {
25038de1c33SSam McCall                return L->first < R->first;
25138de1c33SSam McCall              });
25238de1c33SSam McCall   return Elements;
25338de1c33SSam McCall }
25438de1c33SSam McCall 
25538de1c33SSam McCall // Prints a one-line version of a value that isn't our main focus.
25638de1c33SSam McCall // We interleave writes to OS and JOS, exploiting the lack of extra buffering.
25738de1c33SSam McCall // This is OK as we own the implementation.
abbreviate(const Value & V,OStream & JOS)25891a98ec1SDaniel Sanders void abbreviate(const Value &V, OStream &JOS) {
25938de1c33SSam McCall   switch (V.kind()) {
26038de1c33SSam McCall   case Value::Array:
26191a98ec1SDaniel Sanders     JOS.rawValue(V.getAsArray()->empty() ? "[]" : "[ ... ]");
26238de1c33SSam McCall     break;
26338de1c33SSam McCall   case Value::Object:
26491a98ec1SDaniel Sanders     JOS.rawValue(V.getAsObject()->empty() ? "{}" : "{ ... }");
26538de1c33SSam McCall     break;
26638de1c33SSam McCall   case Value::String: {
26738de1c33SSam McCall     llvm::StringRef S = *V.getAsString();
26838de1c33SSam McCall     if (S.size() < 40) {
26938de1c33SSam McCall       JOS.value(V);
27038de1c33SSam McCall     } else {
27138de1c33SSam McCall       std::string Truncated = fixUTF8(S.take_front(37));
27238de1c33SSam McCall       Truncated.append("...");
27338de1c33SSam McCall       JOS.value(Truncated);
27438de1c33SSam McCall     }
27538de1c33SSam McCall     break;
27638de1c33SSam McCall   }
27738de1c33SSam McCall   default:
27838de1c33SSam McCall     JOS.value(V);
27938de1c33SSam McCall   }
28038de1c33SSam McCall }
28138de1c33SSam McCall 
28238de1c33SSam McCall // Prints a semi-expanded version of a value that is our main focus.
28338de1c33SSam McCall // Array/Object entries are printed, but not recursively as they may be huge.
abbreviateChildren(const Value & V,OStream & JOS)28491a98ec1SDaniel Sanders void abbreviateChildren(const Value &V, OStream &JOS) {
28538de1c33SSam McCall   switch (V.kind()) {
28638de1c33SSam McCall   case Value::Array:
28738de1c33SSam McCall     JOS.array([&] {
288590cc068SSerge Pavlov       for (const auto &I : *V.getAsArray())
28991a98ec1SDaniel Sanders         abbreviate(I, JOS);
29038de1c33SSam McCall     });
29138de1c33SSam McCall     break;
29238de1c33SSam McCall   case Value::Object:
29338de1c33SSam McCall     JOS.object([&] {
29438de1c33SSam McCall       for (const auto *KV : sortedElements(*V.getAsObject())) {
29538de1c33SSam McCall         JOS.attributeBegin(KV->first);
29691a98ec1SDaniel Sanders         abbreviate(KV->second, JOS);
29738de1c33SSam McCall         JOS.attributeEnd();
29838de1c33SSam McCall       }
29938de1c33SSam McCall     });
30038de1c33SSam McCall     break;
30138de1c33SSam McCall   default:
30238de1c33SSam McCall     JOS.value(V);
30338de1c33SSam McCall   }
30438de1c33SSam McCall }
30538de1c33SSam McCall 
30638de1c33SSam McCall } // namespace
30738de1c33SSam McCall 
printErrorContext(const Value & R,raw_ostream & OS) const30838de1c33SSam McCall void Path::Root::printErrorContext(const Value &R, raw_ostream &OS) const {
30938de1c33SSam McCall   OStream JOS(OS, /*IndentSize=*/2);
31038de1c33SSam McCall   // PrintValue recurses down the path, printing the ancestors of our target.
31138de1c33SSam McCall   // Siblings of nodes along the path are printed with abbreviate(), and the
31238de1c33SSam McCall   // target itself is printed with the somewhat richer abbreviateChildren().
31338de1c33SSam McCall   // 'Recurse' is the lambda itself, to allow recursive calls.
31438de1c33SSam McCall   auto PrintValue = [&](const Value &V, ArrayRef<Segment> Path, auto &Recurse) {
31538de1c33SSam McCall     // Print the target node itself, with the error as a comment.
31638de1c33SSam McCall     // Also used if we can't follow our path, e.g. it names a field that
31738de1c33SSam McCall     // *should* exist but doesn't.
31838de1c33SSam McCall     auto HighlightCurrent = [&] {
31938de1c33SSam McCall       std::string Comment = "error: ";
32038de1c33SSam McCall       Comment.append(ErrorMessage.data(), ErrorMessage.size());
32138de1c33SSam McCall       JOS.comment(Comment);
32291a98ec1SDaniel Sanders       abbreviateChildren(V, JOS);
32338de1c33SSam McCall     };
32438de1c33SSam McCall     if (Path.empty()) // We reached our target.
32538de1c33SSam McCall       return HighlightCurrent();
32638de1c33SSam McCall     const Segment &S = Path.back(); // Path is in reverse order.
32738de1c33SSam McCall     if (S.isField()) {
32838de1c33SSam McCall       // Current node is an object, path names a field.
32938de1c33SSam McCall       llvm::StringRef FieldName = S.field();
33038de1c33SSam McCall       const Object *O = V.getAsObject();
33138de1c33SSam McCall       if (!O || !O->get(FieldName))
33238de1c33SSam McCall         return HighlightCurrent();
33338de1c33SSam McCall       JOS.object([&] {
33438de1c33SSam McCall         for (const auto *KV : sortedElements(*O)) {
33538de1c33SSam McCall           JOS.attributeBegin(KV->first);
33638de1c33SSam McCall           if (FieldName.equals(KV->first))
33738de1c33SSam McCall             Recurse(KV->second, Path.drop_back(), Recurse);
33838de1c33SSam McCall           else
33991a98ec1SDaniel Sanders             abbreviate(KV->second, JOS);
34038de1c33SSam McCall           JOS.attributeEnd();
34138de1c33SSam McCall         }
34238de1c33SSam McCall       });
34338de1c33SSam McCall     } else {
34438de1c33SSam McCall       // Current node is an array, path names an element.
34538de1c33SSam McCall       const Array *A = V.getAsArray();
34638de1c33SSam McCall       if (!A || S.index() >= A->size())
34738de1c33SSam McCall         return HighlightCurrent();
34838de1c33SSam McCall       JOS.array([&] {
34938de1c33SSam McCall         unsigned Current = 0;
35038de1c33SSam McCall         for (const auto &V : *A) {
35138de1c33SSam McCall           if (Current++ == S.index())
35238de1c33SSam McCall             Recurse(V, Path.drop_back(), Recurse);
35338de1c33SSam McCall           else
35491a98ec1SDaniel Sanders             abbreviate(V, JOS);
35538de1c33SSam McCall         }
35638de1c33SSam McCall       });
35738de1c33SSam McCall     }
35838de1c33SSam McCall   };
35938de1c33SSam McCall   PrintValue(R, ErrorPath, PrintValue);
36038de1c33SSam McCall }
36138de1c33SSam McCall 
36238de1c33SSam McCall namespace {
3636be38247SSam McCall // Simple recursive-descent JSON parser.
3646be38247SSam McCall class Parser {
3656be38247SSam McCall public:
Parser(StringRef JSON)3666be38247SSam McCall   Parser(StringRef JSON)
3676be38247SSam McCall       : Start(JSON.begin()), P(JSON.begin()), End(JSON.end()) {}
3686be38247SSam McCall 
checkUTF8()369e6057bc6SSam McCall   bool checkUTF8() {
370e6057bc6SSam McCall     size_t ErrOffset;
371e6057bc6SSam McCall     if (isUTF8(StringRef(Start, End - Start), &ErrOffset))
372e6057bc6SSam McCall       return true;
373e6057bc6SSam McCall     P = Start + ErrOffset; // For line/column calculation.
374e6057bc6SSam McCall     return parseError("Invalid UTF-8 sequence");
375e6057bc6SSam McCall   }
376e6057bc6SSam McCall 
3776be38247SSam McCall   bool parseValue(Value &Out);
3786be38247SSam McCall 
assertEnd()3796be38247SSam McCall   bool assertEnd() {
3806be38247SSam McCall     eatWhitespace();
3816be38247SSam McCall     if (P == End)
3826be38247SSam McCall       return true;
3836be38247SSam McCall     return parseError("Text after end of document");
3846be38247SSam McCall   }
3856be38247SSam McCall 
takeError()3866be38247SSam McCall   Error takeError() {
3876be38247SSam McCall     assert(Err);
3886be38247SSam McCall     return std::move(*Err);
3896be38247SSam McCall   }
3906be38247SSam McCall 
3916be38247SSam McCall private:
eatWhitespace()3926be38247SSam McCall   void eatWhitespace() {
3936be38247SSam McCall     while (P != End && (*P == ' ' || *P == '\r' || *P == '\n' || *P == '\t'))
3946be38247SSam McCall       ++P;
3956be38247SSam McCall   }
3966be38247SSam McCall 
3976be38247SSam McCall   // On invalid syntax, parseX() functions return false and set Err.
398d93eaeb7SSam McCall   bool parseNumber(char First, Value &Out);
3996be38247SSam McCall   bool parseString(std::string &Out);
4006be38247SSam McCall   bool parseUnicode(std::string &Out);
4016be38247SSam McCall   bool parseError(const char *Msg); // always returns false
4026be38247SSam McCall 
next()4036be38247SSam McCall   char next() { return P == End ? 0 : *P++; }
peek()4046be38247SSam McCall   char peek() { return P == End ? 0 : *P; }
isNumber(char C)4056be38247SSam McCall   static bool isNumber(char C) {
4066be38247SSam McCall     return C == '0' || C == '1' || C == '2' || C == '3' || C == '4' ||
4076be38247SSam McCall            C == '5' || C == '6' || C == '7' || C == '8' || C == '9' ||
4086be38247SSam McCall            C == 'e' || C == 'E' || C == '+' || C == '-' || C == '.';
4096be38247SSam McCall   }
4106be38247SSam McCall 
4116be38247SSam McCall   Optional<Error> Err;
4126be38247SSam McCall   const char *Start, *P, *End;
4136be38247SSam McCall };
4146be38247SSam McCall 
parseValue(Value & Out)4156be38247SSam McCall bool Parser::parseValue(Value &Out) {
4166be38247SSam McCall   eatWhitespace();
4176be38247SSam McCall   if (P == End)
4186be38247SSam McCall     return parseError("Unexpected EOF");
4196be38247SSam McCall   switch (char C = next()) {
4206be38247SSam McCall   // Bare null/true/false are easy - first char identifies them.
4216be38247SSam McCall   case 'n':
4226be38247SSam McCall     Out = nullptr;
4236be38247SSam McCall     return (next() == 'u' && next() == 'l' && next() == 'l') ||
4246be38247SSam McCall            parseError("Invalid JSON value (null?)");
4256be38247SSam McCall   case 't':
4266be38247SSam McCall     Out = true;
4276be38247SSam McCall     return (next() == 'r' && next() == 'u' && next() == 'e') ||
4286be38247SSam McCall            parseError("Invalid JSON value (true?)");
4296be38247SSam McCall   case 'f':
4306be38247SSam McCall     Out = false;
4316be38247SSam McCall     return (next() == 'a' && next() == 'l' && next() == 's' && next() == 'e') ||
4326be38247SSam McCall            parseError("Invalid JSON value (false?)");
4336be38247SSam McCall   case '"': {
4346be38247SSam McCall     std::string S;
4356be38247SSam McCall     if (parseString(S)) {
4366be38247SSam McCall       Out = std::move(S);
4376be38247SSam McCall       return true;
4386be38247SSam McCall     }
4396be38247SSam McCall     return false;
4406be38247SSam McCall   }
4416be38247SSam McCall   case '[': {
4426be38247SSam McCall     Out = Array{};
4436be38247SSam McCall     Array &A = *Out.getAsArray();
4446be38247SSam McCall     eatWhitespace();
4456be38247SSam McCall     if (peek() == ']') {
4466be38247SSam McCall       ++P;
4476be38247SSam McCall       return true;
4486be38247SSam McCall     }
4496be38247SSam McCall     for (;;) {
4506be38247SSam McCall       A.emplace_back(nullptr);
4516be38247SSam McCall       if (!parseValue(A.back()))
4526be38247SSam McCall         return false;
4536be38247SSam McCall       eatWhitespace();
4546be38247SSam McCall       switch (next()) {
4556be38247SSam McCall       case ',':
4566be38247SSam McCall         eatWhitespace();
4576be38247SSam McCall         continue;
4586be38247SSam McCall       case ']':
4596be38247SSam McCall         return true;
4606be38247SSam McCall       default:
4616be38247SSam McCall         return parseError("Expected , or ] after array element");
4626be38247SSam McCall       }
4636be38247SSam McCall     }
4646be38247SSam McCall   }
4656be38247SSam McCall   case '{': {
4666be38247SSam McCall     Out = Object{};
4676be38247SSam McCall     Object &O = *Out.getAsObject();
4686be38247SSam McCall     eatWhitespace();
4696be38247SSam McCall     if (peek() == '}') {
4706be38247SSam McCall       ++P;
4716be38247SSam McCall       return true;
4726be38247SSam McCall     }
4736be38247SSam McCall     for (;;) {
4746be38247SSam McCall       if (next() != '"')
4756be38247SSam McCall         return parseError("Expected object key");
4766be38247SSam McCall       std::string K;
4776be38247SSam McCall       if (!parseString(K))
4786be38247SSam McCall         return false;
4796be38247SSam McCall       eatWhitespace();
4806be38247SSam McCall       if (next() != ':')
4816be38247SSam McCall         return parseError("Expected : after object key");
4826be38247SSam McCall       eatWhitespace();
4836be38247SSam McCall       if (!parseValue(O[std::move(K)]))
4846be38247SSam McCall         return false;
4856be38247SSam McCall       eatWhitespace();
4866be38247SSam McCall       switch (next()) {
4876be38247SSam McCall       case ',':
4886be38247SSam McCall         eatWhitespace();
4896be38247SSam McCall         continue;
4906be38247SSam McCall       case '}':
4916be38247SSam McCall         return true;
4926be38247SSam McCall       default:
4936be38247SSam McCall         return parseError("Expected , or } after object property");
4946be38247SSam McCall       }
4956be38247SSam McCall     }
4966be38247SSam McCall   }
4976be38247SSam McCall   default:
498d93eaeb7SSam McCall     if (isNumber(C))
499d93eaeb7SSam McCall       return parseNumber(C, Out);
5006be38247SSam McCall     return parseError("Invalid JSON value");
5016be38247SSam McCall   }
5026be38247SSam McCall }
5036be38247SSam McCall 
parseNumber(char First,Value & Out)504d93eaeb7SSam McCall bool Parser::parseNumber(char First, Value &Out) {
505d93eaeb7SSam McCall   // Read the number into a string. (Must be null-terminated for strto*).
5066be38247SSam McCall   SmallString<24> S;
5076be38247SSam McCall   S.push_back(First);
5086be38247SSam McCall   while (isNumber(peek()))
5096be38247SSam McCall     S.push_back(next());
5106be38247SSam McCall   char *End;
511d93eaeb7SSam McCall   // Try first to parse as integer, and if so preserve full 64 bits.
512*d8f4f102SWalter Erquinigo   // We check for errno for out of bounds errors and for End == S.end()
513*d8f4f102SWalter Erquinigo   // to make sure that the numeric string is not malformed.
514*d8f4f102SWalter Erquinigo   errno = 0;
515*d8f4f102SWalter Erquinigo   int64_t I = std::strtoll(S.c_str(), &End, 10);
516*d8f4f102SWalter Erquinigo   if (End == S.end() && errno != ERANGE) {
517d93eaeb7SSam McCall     Out = int64_t(I);
518d93eaeb7SSam McCall     return true;
519d93eaeb7SSam McCall   }
520*d8f4f102SWalter Erquinigo   // strtroull has a special handling for negative numbers, but in this
521*d8f4f102SWalter Erquinigo   // case we don't want to do that because negative numbers were already
522*d8f4f102SWalter Erquinigo   // handled in the previous block.
523*d8f4f102SWalter Erquinigo   if (First != '-') {
524*d8f4f102SWalter Erquinigo     errno = 0;
525*d8f4f102SWalter Erquinigo     uint64_t UI = std::strtoull(S.c_str(), &End, 10);
526*d8f4f102SWalter Erquinigo     if (End == S.end() && errno != ERANGE) {
527*d8f4f102SWalter Erquinigo       Out = UI;
528*d8f4f102SWalter Erquinigo       return true;
529*d8f4f102SWalter Erquinigo     }
530*d8f4f102SWalter Erquinigo   }
531d93eaeb7SSam McCall   // If it's not an integer
5326be38247SSam McCall   Out = std::strtod(S.c_str(), &End);
5336be38247SSam McCall   return End == S.end() || parseError("Invalid JSON value (number?)");
5346be38247SSam McCall }
5356be38247SSam McCall 
parseString(std::string & Out)5366be38247SSam McCall bool Parser::parseString(std::string &Out) {
5376be38247SSam McCall   // leading quote was already consumed.
5386be38247SSam McCall   for (char C = next(); C != '"'; C = next()) {
5396be38247SSam McCall     if (LLVM_UNLIKELY(P == End))
5406be38247SSam McCall       return parseError("Unterminated string");
5416be38247SSam McCall     if (LLVM_UNLIKELY((C & 0x1f) == C))
5426be38247SSam McCall       return parseError("Control character in string");
5436be38247SSam McCall     if (LLVM_LIKELY(C != '\\')) {
5446be38247SSam McCall       Out.push_back(C);
5456be38247SSam McCall       continue;
5466be38247SSam McCall     }
5476be38247SSam McCall     // Handle escape sequence.
5486be38247SSam McCall     switch (C = next()) {
5496be38247SSam McCall     case '"':
5506be38247SSam McCall     case '\\':
5516be38247SSam McCall     case '/':
5526be38247SSam McCall       Out.push_back(C);
5536be38247SSam McCall       break;
5546be38247SSam McCall     case 'b':
5556be38247SSam McCall       Out.push_back('\b');
5566be38247SSam McCall       break;
5576be38247SSam McCall     case 'f':
5586be38247SSam McCall       Out.push_back('\f');
5596be38247SSam McCall       break;
5606be38247SSam McCall     case 'n':
5616be38247SSam McCall       Out.push_back('\n');
5626be38247SSam McCall       break;
5636be38247SSam McCall     case 'r':
5646be38247SSam McCall       Out.push_back('\r');
5656be38247SSam McCall       break;
5666be38247SSam McCall     case 't':
5676be38247SSam McCall       Out.push_back('\t');
5686be38247SSam McCall       break;
5696be38247SSam McCall     case 'u':
5706be38247SSam McCall       if (!parseUnicode(Out))
5716be38247SSam McCall         return false;
5726be38247SSam McCall       break;
5736be38247SSam McCall     default:
5746be38247SSam McCall       return parseError("Invalid escape sequence");
5756be38247SSam McCall     }
5766be38247SSam McCall   }
5776be38247SSam McCall   return true;
5786be38247SSam McCall }
5796be38247SSam McCall 
encodeUtf8(uint32_t Rune,std::string & Out)5806be38247SSam McCall static void encodeUtf8(uint32_t Rune, std::string &Out) {
5816be38247SSam McCall   if (Rune < 0x80) {
5826be38247SSam McCall     Out.push_back(Rune & 0x7F);
5836be38247SSam McCall   } else if (Rune < 0x800) {
5846be38247SSam McCall     uint8_t FirstByte = 0xC0 | ((Rune & 0x7C0) >> 6);
5856be38247SSam McCall     uint8_t SecondByte = 0x80 | (Rune & 0x3F);
5866be38247SSam McCall     Out.push_back(FirstByte);
5876be38247SSam McCall     Out.push_back(SecondByte);
5886be38247SSam McCall   } else if (Rune < 0x10000) {
5896be38247SSam McCall     uint8_t FirstByte = 0xE0 | ((Rune & 0xF000) >> 12);
5906be38247SSam McCall     uint8_t SecondByte = 0x80 | ((Rune & 0xFC0) >> 6);
5916be38247SSam McCall     uint8_t ThirdByte = 0x80 | (Rune & 0x3F);
5926be38247SSam McCall     Out.push_back(FirstByte);
5936be38247SSam McCall     Out.push_back(SecondByte);
5946be38247SSam McCall     Out.push_back(ThirdByte);
5956be38247SSam McCall   } else if (Rune < 0x110000) {
5966be38247SSam McCall     uint8_t FirstByte = 0xF0 | ((Rune & 0x1F0000) >> 18);
5976be38247SSam McCall     uint8_t SecondByte = 0x80 | ((Rune & 0x3F000) >> 12);
5986be38247SSam McCall     uint8_t ThirdByte = 0x80 | ((Rune & 0xFC0) >> 6);
5996be38247SSam McCall     uint8_t FourthByte = 0x80 | (Rune & 0x3F);
6006be38247SSam McCall     Out.push_back(FirstByte);
6016be38247SSam McCall     Out.push_back(SecondByte);
6026be38247SSam McCall     Out.push_back(ThirdByte);
6036be38247SSam McCall     Out.push_back(FourthByte);
6046be38247SSam McCall   } else {
6056be38247SSam McCall     llvm_unreachable("Invalid codepoint");
6066be38247SSam McCall   }
6076be38247SSam McCall }
6086be38247SSam McCall 
6096be38247SSam McCall // Parse a UTF-16 \uNNNN escape sequence. "\u" has already been consumed.
6106be38247SSam McCall // May parse several sequential escapes to ensure proper surrogate handling.
6116be38247SSam McCall // We do not use ConvertUTF.h, it can't accept and replace unpaired surrogates.
6126be38247SSam McCall // These are invalid Unicode but valid JSON (RFC 8259, section 8.2).
parseUnicode(std::string & Out)6136be38247SSam McCall bool Parser::parseUnicode(std::string &Out) {
6146be38247SSam McCall   // Invalid UTF is not a JSON error (RFC 8529§8.2). It gets replaced by U+FFFD.
6156be38247SSam McCall   auto Invalid = [&] { Out.append(/* UTF-8 */ {'\xef', '\xbf', '\xbd'}); };
6166be38247SSam McCall   // Decodes 4 hex digits from the stream into Out, returns false on error.
6176be38247SSam McCall   auto Parse4Hex = [this](uint16_t &Out) -> bool {
6186be38247SSam McCall     Out = 0;
6196be38247SSam McCall     char Bytes[] = {next(), next(), next(), next()};
6206be38247SSam McCall     for (unsigned char C : Bytes) {
6216be38247SSam McCall       if (!std::isxdigit(C))
6226be38247SSam McCall         return parseError("Invalid \\u escape sequence");
6236be38247SSam McCall       Out <<= 4;
6246be38247SSam McCall       Out |= (C > '9') ? (C & ~0x20) - 'A' + 10 : (C - '0');
6256be38247SSam McCall     }
6266be38247SSam McCall     return true;
6276be38247SSam McCall   };
6286be38247SSam McCall   uint16_t First; // UTF-16 code unit from the first \u escape.
6296be38247SSam McCall   if (!Parse4Hex(First))
6306be38247SSam McCall     return false;
6316be38247SSam McCall 
6326be38247SSam McCall   // We loop to allow proper surrogate-pair error handling.
6336be38247SSam McCall   while (true) {
6346be38247SSam McCall     // Case 1: the UTF-16 code unit is already a codepoint in the BMP.
6356be38247SSam McCall     if (LLVM_LIKELY(First < 0xD800 || First >= 0xE000)) {
6366be38247SSam McCall       encodeUtf8(First, Out);
6376be38247SSam McCall       return true;
6386be38247SSam McCall     }
6396be38247SSam McCall 
6406be38247SSam McCall     // Case 2: it's an (unpaired) trailing surrogate.
6416be38247SSam McCall     if (LLVM_UNLIKELY(First >= 0xDC00)) {
6426be38247SSam McCall       Invalid();
6436be38247SSam McCall       return true;
6446be38247SSam McCall     }
6456be38247SSam McCall 
6466be38247SSam McCall     // Case 3: it's a leading surrogate. We expect a trailing one next.
6476be38247SSam McCall     // Case 3a: there's no trailing \u escape. Don't advance in the stream.
648e6057bc6SSam McCall     if (LLVM_UNLIKELY(P + 2 > End || *P != '\\' || *(P + 1) != 'u')) {
6496be38247SSam McCall       Invalid(); // Leading surrogate was unpaired.
6506be38247SSam McCall       return true;
6516be38247SSam McCall     }
6526be38247SSam McCall     P += 2;
6536be38247SSam McCall     uint16_t Second;
6546be38247SSam McCall     if (!Parse4Hex(Second))
6556be38247SSam McCall       return false;
6566be38247SSam McCall     // Case 3b: there was another \u escape, but it wasn't a trailing surrogate.
6576be38247SSam McCall     if (LLVM_UNLIKELY(Second < 0xDC00 || Second >= 0xE000)) {
6586be38247SSam McCall       Invalid();      // Leading surrogate was unpaired.
6596be38247SSam McCall       First = Second; // Second escape still needs to be processed.
6606be38247SSam McCall       continue;
6616be38247SSam McCall     }
6626be38247SSam McCall     // Case 3c: a valid surrogate pair encoding an astral codepoint.
6636be38247SSam McCall     encodeUtf8(0x10000 | ((First - 0xD800) << 10) | (Second - 0xDC00), Out);
6646be38247SSam McCall     return true;
6656be38247SSam McCall   }
6666be38247SSam McCall }
6676be38247SSam McCall 
parseError(const char * Msg)6686be38247SSam McCall bool Parser::parseError(const char *Msg) {
6696be38247SSam McCall   int Line = 1;
6706be38247SSam McCall   const char *StartOfLine = Start;
6716be38247SSam McCall   for (const char *X = Start; X < P; ++X) {
6726be38247SSam McCall     if (*X == 0x0A) {
6736be38247SSam McCall       ++Line;
6746be38247SSam McCall       StartOfLine = X + 1;
6756be38247SSam McCall     }
6766be38247SSam McCall   }
6776be38247SSam McCall   Err.emplace(
6780eaee545SJonas Devlieghere       std::make_unique<ParseError>(Msg, Line, P - StartOfLine, P - Start));
6796be38247SSam McCall   return false;
6806be38247SSam McCall }
6816be38247SSam McCall } // namespace
6826be38247SSam McCall 
parse(StringRef JSON)6836be38247SSam McCall Expected<Value> parse(StringRef JSON) {
6846be38247SSam McCall   Parser P(JSON);
6856be38247SSam McCall   Value E = nullptr;
686e6057bc6SSam McCall   if (P.checkUTF8())
6876be38247SSam McCall     if (P.parseValue(E))
6886be38247SSam McCall       if (P.assertEnd())
689c55cf4afSBill Wendling         return std::move(E);
6906be38247SSam McCall   return P.takeError();
6916be38247SSam McCall }
6926be38247SSam McCall char ParseError::ID = 0;
6936be38247SSam McCall 
isUTF8(llvm::StringRef S,size_t * ErrOffset)694e6057bc6SSam McCall bool isUTF8(llvm::StringRef S, size_t *ErrOffset) {
695e6057bc6SSam McCall   // Fast-path for ASCII, which is valid UTF-8.
696e6057bc6SSam McCall   if (LLVM_LIKELY(isASCII(S)))
697e6057bc6SSam McCall     return true;
698e6057bc6SSam McCall 
699e6057bc6SSam McCall   const UTF8 *Data = reinterpret_cast<const UTF8 *>(S.data()), *Rest = Data;
700e6057bc6SSam McCall   if (LLVM_LIKELY(isLegalUTF8String(&Rest, Data + S.size())))
701e6057bc6SSam McCall     return true;
702e6057bc6SSam McCall 
703e6057bc6SSam McCall   if (ErrOffset)
704e6057bc6SSam McCall     *ErrOffset = Rest - Data;
705e6057bc6SSam McCall   return false;
706e6057bc6SSam McCall }
707e6057bc6SSam McCall 
fixUTF8(llvm::StringRef S)708e6057bc6SSam McCall std::string fixUTF8(llvm::StringRef S) {
709e6057bc6SSam McCall   // This isn't particularly efficient, but is only for error-recovery.
710e6057bc6SSam McCall   std::vector<UTF32> Codepoints(S.size()); // 1 codepoint per byte suffices.
711e6057bc6SSam McCall   const UTF8 *In8 = reinterpret_cast<const UTF8 *>(S.data());
712e6057bc6SSam McCall   UTF32 *Out32 = Codepoints.data();
713e6057bc6SSam McCall   ConvertUTF8toUTF32(&In8, In8 + S.size(), &Out32, Out32 + Codepoints.size(),
714e6057bc6SSam McCall                      lenientConversion);
715e6057bc6SSam McCall   Codepoints.resize(Out32 - Codepoints.data());
716e6057bc6SSam McCall   std::string Res(4 * Codepoints.size(), 0); // 4 bytes per codepoint suffice
717e6057bc6SSam McCall   const UTF32 *In32 = Codepoints.data();
718e6057bc6SSam McCall   UTF8 *Out8 = reinterpret_cast<UTF8 *>(&Res[0]);
719e6057bc6SSam McCall   ConvertUTF32toUTF8(&In32, In32 + Codepoints.size(), &Out8, Out8 + Res.size(),
720e6057bc6SSam McCall                      strictConversion);
721e6057bc6SSam McCall   Res.resize(reinterpret_cast<char *>(Out8) - Res.data());
722e6057bc6SSam McCall   return Res;
723e6057bc6SSam McCall }
724e6057bc6SSam McCall 
quote(llvm::raw_ostream & OS,llvm::StringRef S)7256be38247SSam McCall static void quote(llvm::raw_ostream &OS, llvm::StringRef S) {
7266be38247SSam McCall   OS << '\"';
7276be38247SSam McCall   for (unsigned char C : S) {
7286be38247SSam McCall     if (C == 0x22 || C == 0x5C)
7296be38247SSam McCall       OS << '\\';
7306be38247SSam McCall     if (C >= 0x20) {
7316be38247SSam McCall       OS << C;
7326be38247SSam McCall       continue;
7336be38247SSam McCall     }
7346be38247SSam McCall     OS << '\\';
7356be38247SSam McCall     switch (C) {
7366be38247SSam McCall     // A few characters are common enough to make short escapes worthwhile.
7376be38247SSam McCall     case '\t':
7386be38247SSam McCall       OS << 't';
7396be38247SSam McCall       break;
7406be38247SSam McCall     case '\n':
7416be38247SSam McCall       OS << 'n';
7426be38247SSam McCall       break;
7436be38247SSam McCall     case '\r':
7446be38247SSam McCall       OS << 'r';
7456be38247SSam McCall       break;
7466be38247SSam McCall     default:
7476be38247SSam McCall       OS << 'u';
7486be38247SSam McCall       llvm::write_hex(OS, C, llvm::HexPrintStyle::Lower, 4);
7496be38247SSam McCall       break;
7506be38247SSam McCall     }
7516be38247SSam McCall   }
7526be38247SSam McCall   OS << '\"';
7536be38247SSam McCall }
7546be38247SSam McCall 
value(const Value & V)755a7edcfb5SSam McCall void llvm::json::OStream::value(const Value &V) {
756a7edcfb5SSam McCall   switch (V.kind()) {
757a7edcfb5SSam McCall   case Value::Null:
758a7edcfb5SSam McCall     valueBegin();
7596be38247SSam McCall     OS << "null";
760a7edcfb5SSam McCall     return;
761a7edcfb5SSam McCall   case Value::Boolean:
762a7edcfb5SSam McCall     valueBegin();
763a7edcfb5SSam McCall     OS << (*V.getAsBoolean() ? "true" : "false");
764a7edcfb5SSam McCall     return;
765a7edcfb5SSam McCall   case Value::Number:
766a7edcfb5SSam McCall     valueBegin();
767a7edcfb5SSam McCall     if (V.Type == Value::T_Integer)
768a7edcfb5SSam McCall       OS << *V.getAsInteger();
7698c3adce8Sdjtodoro     else if (V.Type == Value::T_UINT64)
7708c3adce8Sdjtodoro       OS << *V.getAsUINT64();
771a7edcfb5SSam McCall     else
772d93eaeb7SSam McCall       OS << format("%.*g", std::numeric_limits<double>::max_digits10,
773a7edcfb5SSam McCall                    *V.getAsNumber());
774a7edcfb5SSam McCall     return;
775a7edcfb5SSam McCall   case Value::String:
776a7edcfb5SSam McCall     valueBegin();
777a7edcfb5SSam McCall     quote(OS, *V.getAsString());
778a7edcfb5SSam McCall     return;
779a7edcfb5SSam McCall   case Value::Array:
780a7edcfb5SSam McCall     return array([&] {
781a7edcfb5SSam McCall       for (const Value &E : *V.getAsArray())
782a7edcfb5SSam McCall         value(E);
783a7edcfb5SSam McCall     });
784a7edcfb5SSam McCall   case Value::Object:
785a7edcfb5SSam McCall     return object([&] {
786a7edcfb5SSam McCall       for (const Object::value_type *E : sortedElements(*V.getAsObject()))
787a7edcfb5SSam McCall         attribute(E->first, E->second);
788a7edcfb5SSam McCall     });
789a7edcfb5SSam McCall   }
790a7edcfb5SSam McCall }
791a7edcfb5SSam McCall 
valueBegin()792a7edcfb5SSam McCall void llvm::json::OStream::valueBegin() {
793a7edcfb5SSam McCall   assert(Stack.back().Ctx != Object && "Only attributes allowed here");
794a7edcfb5SSam McCall   if (Stack.back().HasValue) {
795a7edcfb5SSam McCall     assert(Stack.back().Ctx != Singleton && "Only one value allowed here");
7966be38247SSam McCall     OS << ',';
7976be38247SSam McCall   }
798a7edcfb5SSam McCall   if (Stack.back().Ctx == Array)
799a7edcfb5SSam McCall     newline();
800140b7b6fSSam McCall   flushComment();
801a7edcfb5SSam McCall   Stack.back().HasValue = true;
8026be38247SSam McCall }
803a7edcfb5SSam McCall 
comment(llvm::StringRef Comment)804140b7b6fSSam McCall void OStream::comment(llvm::StringRef Comment) {
805140b7b6fSSam McCall   assert(PendingComment.empty() && "Only one comment per value!");
806140b7b6fSSam McCall   PendingComment = Comment;
807140b7b6fSSam McCall }
808140b7b6fSSam McCall 
flushComment()809140b7b6fSSam McCall void OStream::flushComment() {
810140b7b6fSSam McCall   if (PendingComment.empty())
811140b7b6fSSam McCall     return;
812140b7b6fSSam McCall   OS << (IndentSize ? "/* " : "/*");
813140b7b6fSSam McCall   // Be sure not to accidentally emit "*/". Transform to "* /".
814140b7b6fSSam McCall   while (!PendingComment.empty()) {
815140b7b6fSSam McCall     auto Pos = PendingComment.find("*/");
816140b7b6fSSam McCall     if (Pos == StringRef::npos) {
817140b7b6fSSam McCall       OS << PendingComment;
818140b7b6fSSam McCall       PendingComment = "";
819140b7b6fSSam McCall     } else {
820140b7b6fSSam McCall       OS << PendingComment.take_front(Pos) << "* /";
821140b7b6fSSam McCall       PendingComment = PendingComment.drop_front(Pos + 2);
822140b7b6fSSam McCall     }
823140b7b6fSSam McCall   }
824140b7b6fSSam McCall   OS << (IndentSize ? " */" : "*/");
825140b7b6fSSam McCall   // Comments are on their own line unless attached to an attribute value.
826140b7b6fSSam McCall   if (Stack.size() > 1 && Stack.back().Ctx == Singleton) {
827140b7b6fSSam McCall     if (IndentSize)
828140b7b6fSSam McCall       OS << ' ';
829140b7b6fSSam McCall   } else {
830140b7b6fSSam McCall     newline();
831140b7b6fSSam McCall   }
832140b7b6fSSam McCall }
833140b7b6fSSam McCall 
newline()834a7edcfb5SSam McCall void llvm::json::OStream::newline() {
835a7edcfb5SSam McCall   if (IndentSize) {
836a7edcfb5SSam McCall     OS.write('\n');
837a7edcfb5SSam McCall     OS.indent(Indent);
838a7edcfb5SSam McCall   }
839a7edcfb5SSam McCall }
840a7edcfb5SSam McCall 
arrayBegin()841a7edcfb5SSam McCall void llvm::json::OStream::arrayBegin() {
842a7edcfb5SSam McCall   valueBegin();
843a7edcfb5SSam McCall   Stack.emplace_back();
844a7edcfb5SSam McCall   Stack.back().Ctx = Array;
845a7edcfb5SSam McCall   Indent += IndentSize;
8466be38247SSam McCall   OS << '[';
8476be38247SSam McCall }
848a7edcfb5SSam McCall 
arrayEnd()849a7edcfb5SSam McCall void llvm::json::OStream::arrayEnd() {
850a7edcfb5SSam McCall   assert(Stack.back().Ctx == Array);
851a7edcfb5SSam McCall   Indent -= IndentSize;
852a7edcfb5SSam McCall   if (Stack.back().HasValue)
853a7edcfb5SSam McCall     newline();
8546be38247SSam McCall   OS << ']';
855140b7b6fSSam McCall   assert(PendingComment.empty());
856a7edcfb5SSam McCall   Stack.pop_back();
857a7edcfb5SSam McCall   assert(!Stack.empty());
8586be38247SSam McCall }
859a7edcfb5SSam McCall 
objectBegin()860a7edcfb5SSam McCall void llvm::json::OStream::objectBegin() {
861a7edcfb5SSam McCall   valueBegin();
862a7edcfb5SSam McCall   Stack.emplace_back();
863a7edcfb5SSam McCall   Stack.back().Ctx = Object;
864a7edcfb5SSam McCall   Indent += IndentSize;
865a7edcfb5SSam McCall   OS << '{';
8666be38247SSam McCall }
867a7edcfb5SSam McCall 
objectEnd()868a7edcfb5SSam McCall void llvm::json::OStream::objectEnd() {
869a7edcfb5SSam McCall   assert(Stack.back().Ctx == Object);
870a7edcfb5SSam McCall   Indent -= IndentSize;
871a7edcfb5SSam McCall   if (Stack.back().HasValue)
872a7edcfb5SSam McCall     newline();
873a7edcfb5SSam McCall   OS << '}';
874140b7b6fSSam McCall   assert(PendingComment.empty());
875a7edcfb5SSam McCall   Stack.pop_back();
876a7edcfb5SSam McCall   assert(!Stack.empty());
8776be38247SSam McCall }
8786be38247SSam McCall 
attributeBegin(llvm::StringRef Key)879a7edcfb5SSam McCall void llvm::json::OStream::attributeBegin(llvm::StringRef Key) {
880a7edcfb5SSam McCall   assert(Stack.back().Ctx == Object);
881a7edcfb5SSam McCall   if (Stack.back().HasValue)
882a7edcfb5SSam McCall     OS << ',';
883a7edcfb5SSam McCall   newline();
884140b7b6fSSam McCall   flushComment();
885a7edcfb5SSam McCall   Stack.back().HasValue = true;
886a7edcfb5SSam McCall   Stack.emplace_back();
887a7edcfb5SSam McCall   Stack.back().Ctx = Singleton;
888a7edcfb5SSam McCall   if (LLVM_LIKELY(isUTF8(Key))) {
889a7edcfb5SSam McCall     quote(OS, Key);
890a7edcfb5SSam McCall   } else {
891a7edcfb5SSam McCall     assert(false && "Invalid UTF-8 in attribute key");
892a7edcfb5SSam McCall     quote(OS, fixUTF8(Key));
893a7edcfb5SSam McCall   }
894a7edcfb5SSam McCall   OS.write(':');
895a7edcfb5SSam McCall   if (IndentSize)
896a7edcfb5SSam McCall     OS.write(' ');
897a7edcfb5SSam McCall }
898a7edcfb5SSam McCall 
attributeEnd()899a7edcfb5SSam McCall void llvm::json::OStream::attributeEnd() {
900a7edcfb5SSam McCall   assert(Stack.back().Ctx == Singleton);
901a7edcfb5SSam McCall   assert(Stack.back().HasValue && "Attribute must have a value");
902140b7b6fSSam McCall   assert(PendingComment.empty());
903a7edcfb5SSam McCall   Stack.pop_back();
904a7edcfb5SSam McCall   assert(Stack.back().Ctx == Object);
905a7edcfb5SSam McCall }
906a7edcfb5SSam McCall 
rawValueBegin()90791a98ec1SDaniel Sanders raw_ostream &llvm::json::OStream::rawValueBegin() {
90891a98ec1SDaniel Sanders   valueBegin();
90991a98ec1SDaniel Sanders   Stack.emplace_back();
91091a98ec1SDaniel Sanders   Stack.back().Ctx = RawValue;
91191a98ec1SDaniel Sanders   return OS;
91291a98ec1SDaniel Sanders }
91391a98ec1SDaniel Sanders 
rawValueEnd()91491a98ec1SDaniel Sanders void llvm::json::OStream::rawValueEnd() {
91591a98ec1SDaniel Sanders   assert(Stack.back().Ctx == RawValue);
91691a98ec1SDaniel Sanders   Stack.pop_back();
91791a98ec1SDaniel Sanders }
91891a98ec1SDaniel Sanders 
919a7edcfb5SSam McCall } // namespace json
920a7edcfb5SSam McCall } // namespace llvm
921a7edcfb5SSam McCall 
format(const llvm::json::Value & E,raw_ostream & OS,StringRef Options)9226be38247SSam McCall void llvm::format_provider<llvm::json::Value>::format(
9236be38247SSam McCall     const llvm::json::Value &E, raw_ostream &OS, StringRef Options) {
9246be38247SSam McCall   unsigned IndentAmount = 0;
925a7edcfb5SSam McCall   if (!Options.empty() && Options.getAsInteger(/*Radix=*/10, IndentAmount))
9266be38247SSam McCall     llvm_unreachable("json::Value format options should be an integer");
927a7edcfb5SSam McCall   json::OStream(OS, IndentAmount).value(E);
9286be38247SSam McCall }
9296be38247SSam McCall 
930